rsyntaxtree 1.3.2 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,53 @@
1
+ <?xml version="1.0" standalone="no"?>
2
+ <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
3
+ <svg width="359.2" height="605.25" viewBox="-15.200000000000001, 0, 374.4, 616.5" version="1.1" xmlns="http://www.w3.org/2000/svg">
4
+ <defs>
5
+ <marker id="arrow" markerUnits="userSpaceOnUse" viewBox="0 0 10 10" refX="10" refY="5" markerWidth="15.200000000000001" markerHeight="15.200000000000001" orient="auto">
6
+ <path d="M 0 0 L 10 5 L 0 10" fill="#CC79A7"/>
7
+ </marker>
8
+ <marker id="arrowBackward" markerUnits="userSpaceOnUse" viewBox="0 0 10 10" refX="5" refY="5" markerWidth="15.200000000000001" markerHeight="15.200000000000001" orient="auto">
9
+ <path d="M 0 0 L 10 5 L 0 10 z" fill="#CC79A7"/>
10
+ </marker>
11
+ <marker id="arrowForward" markerUnits="userSpaceOnUse" viewBox="0 0 10 10" refX="5" refY="5" markerWidth="15.200000000000001" markerHeight="15.200000000000001" orient="auto">
12
+ <path d="M 10 0 L 0 5 L 10 10 z" fill="#CC79A7"/>
13
+ </marker>
14
+ <marker id="arrowBothways" markerUnits="userSpaceOnUse" viewBox="0 0 30 10" refX="15" refY="5" markerWidth="45.6" markerHeight="15.200000000000001" orient="auto">
15
+ <path d="M 0 5 L 10 0 L 10 5 L 20 5 L 20 0 L 30 5 L 20 10 L 20 5 L 10 5 L 10 10 z" fill="#CC79A7"/>
16
+ </marker>
17
+ <pattern id="hatchBlack" x="10" y="10" width="10" height="10" patternUnits="userSpaceOnUse" patternTransform="rotate(45)">
18
+ <line x1="0" y="0" x2="0" y2="10" stroke="black" stroke-width="4"></line>
19
+ </pattern>
20
+ <pattern id="hatchForNode" x="10" y="10" width="10" height="10" patternUnits="userSpaceOnUse" patternTransform="rotate(45)">
21
+ <line x1="0" y="0" x2="0" y2="10" stroke="#0072B2" stroke-width="4"></line>
22
+ </pattern>
23
+ <pattern id="hatchForLeaf" x="10" y="10" width="10" height="10" patternUnits="userSpaceOnUse" patternTransform="rotate(45)">
24
+ <line x1="0" y="0" x2="0" y2="10" stroke="#009E73" stroke-width="4"></line>
25
+ </pattern>
26
+ </defs>
27
+ <text white-space='pre' alignment-baseline='text-top' style='fill: #0072B2; storoke-width: 0; font-size: 32px;' x='180.2' y='67.5'><tspan x='180.2' y='67.5' style="" text-decoration="" font-family="'Noto Sans', 'Noto Sans JP', OpenMoji, 'OpenMoji Color', 'OpenMoji Black', sans-serif">S</tspan>
28
+ </text>
29
+ <text white-space='pre' alignment-baseline='text-top' style='fill: #0072B2; storoke-width: 0; font-size: 32px;' x='75.09999999999998' y='238.5'><tspan x='75.09999999999998' y='238.5' style="" text-decoration="" font-family="'Noto Sans', 'Noto Sans JP', OpenMoji, 'OpenMoji Color', 'OpenMoji Black', sans-serif">NP</tspan>
30
+ </text>
31
+ <text white-space='pre' alignment-baseline='text-top' style='fill: #0072B2; storoke-width: 0; font-size: 32px;' x='15.199999999999989' y='409.5'><tspan x='15.199999999999989' y='409.5' style="" text-decoration="" font-family="'Noto Sans', 'Noto Sans JP', OpenMoji, 'OpenMoji Color', 'OpenMoji Black', sans-serif">Det</tspan>
32
+ </text>
33
+ <text white-space='pre' alignment-baseline='text-top' style='fill: #E63946; storoke-width: 0; font-size: 32px;' x='16.69999999999999' y='580.5'><tspan x='16.69999999999999' y='580.5' style="" text-decoration="" font-family="'Noto Sans', 'Noto Sans JP', OpenMoji, 'OpenMoji Color', 'OpenMoji Black', sans-serif">the</tspan>
34
+ </text>
35
+ <text white-space='pre' alignment-baseline='text-top' style='fill: #0072B2; storoke-width: 0; font-size: 32px;' x='139.5' y='409.5'><tspan x='139.5' y='409.5' style="" text-decoration="" font-family="'Noto Sans', 'Noto Sans JP', OpenMoji, 'OpenMoji Color', 'OpenMoji Black', sans-serif">N</tspan>
36
+ </text>
37
+ <text white-space='pre' alignment-baseline='text-top' style='fill: #457B9D; storoke-width: 0; font-size: 32px;' x='129.0' y='580.5'><tspan x='129.0' y='580.5' style="" text-decoration="" font-family="'Noto Sans', 'Noto Sans JP', OpenMoji, 'OpenMoji Color', 'OpenMoji Black', sans-serif">cat</tspan>
38
+ </text>
39
+ <text white-space='pre' alignment-baseline='text-top' style='fill: #0072B2; storoke-width: 0; font-size: 32px;' x='262.8' y='238.5'><tspan x='262.8' y='238.5' style="" text-decoration="" font-family="'Noto Sans', 'Noto Sans JP', OpenMoji, 'OpenMoji Color', 'OpenMoji Black', sans-serif">VP</tspan>
40
+ </text>
41
+ <text white-space='pre' alignment-baseline='text-top' style='fill: #0072B2; storoke-width: 0; font-size: 32px;' x='271.8' y='409.5'><tspan x='271.8' y='409.5' style="" text-decoration="" font-family="'Noto Sans', 'Noto Sans JP', OpenMoji, 'OpenMoji Color', 'OpenMoji Black', sans-serif">V</tspan>
42
+ </text>
43
+ <text white-space='pre' alignment-baseline='text-top' style='fill: #2A9D8F; storoke-width: 0; font-size: 32px;' x='234.8' y='580.5'><tspan x='234.8' y='580.5' style="" text-decoration="" font-family="'Noto Sans', 'Noto Sans JP', OpenMoji, 'OpenMoji Color', 'OpenMoji Black', sans-serif">sleeps</tspan>
44
+ </text>
45
+ <line style='fill: none; stroke:black; stroke-width:2; stroke-linejoin:round; stroke-linecap:round;' x1='96.59999999999998' y1='182.25' x2='189.2' y2='95.625' />
46
+ <line style='fill: none; stroke:black; stroke-width:2; stroke-linejoin:round; stroke-linecap:round;' x1='281.8' y1='182.25' x2='189.2' y2='95.625' />
47
+ <line style='fill: none; stroke:black; stroke-width:2; stroke-linejoin:round; stroke-linecap:round;' x1='41.69999999999999' y1='353.25' x2='96.59999999999998' y2='266.625' />
48
+ <line style='fill: none; stroke:black; stroke-width:2; stroke-linejoin:round; stroke-linecap:round;' x1='151.5' y1='353.25' x2='96.59999999999998' y2='266.625' />
49
+ <line style='fill: none; stroke:black; stroke-width:2; stroke-linejoin:round; stroke-linecap:round;' x1='41.69999999999999' y1='524.25' x2='41.69999999999999' y2='437.625' />
50
+ <line style='fill: none; stroke:black; stroke-width:2; stroke-linejoin:round; stroke-linecap:round;' x1='151.5' y1='524.25' x2='151.5' y2='437.625' />
51
+ <line style='fill: none; stroke:black; stroke-width:2; stroke-linejoin:round; stroke-linecap:round;' x1='281.8' y1='353.25' x2='281.8' y2='266.625' />
52
+ <line style='fill: none; stroke:black; stroke-width:2; stroke-linejoin:round; stroke-linecap:round;' x1='281.8' y1='524.25' x2='281.8' y2='437.625' />
53
+ </svg>
@@ -0,0 +1,73 @@
1
+ <?xml version="1.0" standalone="no"?>
2
+ <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
3
+ <svg width="912.0000000000001" height="776.25" viewBox="-15.200000000000001, 0, 927.2000000000002, 787.5" version="1.1" xmlns="http://www.w3.org/2000/svg">
4
+ <defs>
5
+ <marker id="arrow" markerUnits="userSpaceOnUse" viewBox="0 0 10 10" refX="10" refY="5" markerWidth="15.200000000000001" markerHeight="15.200000000000001" orient="auto">
6
+ <path d="M 0 0 L 10 5 L 0 10" fill="#CC79A7"/>
7
+ </marker>
8
+ <marker id="arrowBackward" markerUnits="userSpaceOnUse" viewBox="0 0 10 10" refX="5" refY="5" markerWidth="15.200000000000001" markerHeight="15.200000000000001" orient="auto">
9
+ <path d="M 0 0 L 10 5 L 0 10 z" fill="#CC79A7"/>
10
+ </marker>
11
+ <marker id="arrowForward" markerUnits="userSpaceOnUse" viewBox="0 0 10 10" refX="5" refY="5" markerWidth="15.200000000000001" markerHeight="15.200000000000001" orient="auto">
12
+ <path d="M 10 0 L 0 5 L 10 10 z" fill="#CC79A7"/>
13
+ </marker>
14
+ <marker id="arrowBothways" markerUnits="userSpaceOnUse" viewBox="0 0 30 10" refX="15" refY="5" markerWidth="45.6" markerHeight="15.200000000000001" orient="auto">
15
+ <path d="M 0 5 L 10 0 L 10 5 L 20 5 L 20 0 L 30 5 L 20 10 L 20 5 L 10 5 L 10 10 z" fill="#CC79A7"/>
16
+ </marker>
17
+ <pattern id="hatchBlack" x="10" y="10" width="10" height="10" patternUnits="userSpaceOnUse" patternTransform="rotate(45)">
18
+ <line x1="0" y="0" x2="0" y2="10" stroke="black" stroke-width="4"></line>
19
+ </pattern>
20
+ <pattern id="hatchForNode" x="10" y="10" width="10" height="10" patternUnits="userSpaceOnUse" patternTransform="rotate(45)">
21
+ <line x1="0" y="0" x2="0" y2="10" stroke="#0072B2" stroke-width="4"></line>
22
+ </pattern>
23
+ <pattern id="hatchForLeaf" x="10" y="10" width="10" height="10" patternUnits="userSpaceOnUse" patternTransform="rotate(45)">
24
+ <line x1="0" y="0" x2="0" y2="10" stroke="#009E73" stroke-width="4"></line>
25
+ </pattern>
26
+ </defs>
27
+ <text white-space='pre' alignment-baseline='text-top' style='fill: #0072B2; storoke-width: 0; font-size: 32px;' x='362.90000000000003' y='67.5'><tspan x='362.90000000000003' y='67.5' style="" text-decoration="" font-family="'Noto Sans', 'Noto Sans JP', OpenMoji, 'OpenMoji Color', 'OpenMoji Black', sans-serif">S</tspan>
28
+ </text>
29
+ <text white-space='pre' alignment-baseline='text-top' style='fill: red; storoke-width: 0; font-size: 32px;' x='156.20000000000002' y='238.5'><tspan x='156.20000000000002' y='238.5' style="" text-decoration="" font-family="'Noto Sans', 'Noto Sans JP', OpenMoji, 'OpenMoji Color', 'OpenMoji Black', sans-serif">NP</tspan>
30
+ </text>
31
+ <text white-space='pre' alignment-baseline='text-top' style='fill: blue; storoke-width: 0; font-size: 32px;' x='165.70000000000002' y='409.5'><tspan x='165.70000000000002' y='409.5' style="" text-decoration="" font-family="'Noto Sans', 'Noto Sans JP', OpenMoji, 'OpenMoji Color', 'OpenMoji Black', sans-serif">N</tspan>
32
+ </text>
33
+ <text white-space='pre' alignment-baseline='text-top' style='fill: #009E73; storoke-width: 0; font-size: 32px;' x='15.199999999999989' y='580.5'><tspan x='15.199999999999989' y='580.5' style="" text-decoration="" font-family="'Noto Sans', 'Noto Sans JP', OpenMoji, 'OpenMoji Color', 'OpenMoji Black', sans-serif">the<tspan style='fill:none;'>■</tspan>quick<tspan style='fill:none;'>■</tspan>brown<tspan style='fill:none;'>■</tspan>fox</tspan>
34
+ </text>
35
+ <text white-space='pre' alignment-baseline='text-top' style='fill: green; storoke-width: 0; font-size: 32px;' x='547.1000000000001' y='238.5'><tspan x='547.1000000000001' y='238.5' style="" text-decoration="" font-family="'Noto Sans', 'Noto Sans JP', OpenMoji, 'OpenMoji Color', 'OpenMoji Black', sans-serif">VP</tspan>
36
+ </text>
37
+ <text white-space='pre' alignment-baseline='text-top' style='fill: #0072B2; storoke-width: 0; font-size: 32px;' x='437.50000000000006' y='409.5'><tspan x='437.50000000000006' y='409.5' style="" text-decoration="" font-family="'Noto Sans', 'Noto Sans JP', OpenMoji, 'OpenMoji Color', 'OpenMoji Black', sans-serif">V</tspan>
38
+ </text>
39
+ <text white-space='pre' alignment-baseline='text-top' style='fill: #009E73; storoke-width: 0; font-size: 32px;' x='401.00000000000006' y='580.5'><tspan x='401.00000000000006' y='580.5' style="" text-decoration="" font-family="'Noto Sans', 'Noto Sans JP', OpenMoji, 'OpenMoji Color', 'OpenMoji Black', sans-serif">jumps</tspan>
40
+ </text>
41
+ <text white-space='pre' alignment-baseline='text-top' style='fill: #0072B2; storoke-width: 0; font-size: 32px;' x='665.7' y='409.5'><tspan x='665.7' y='409.5' style="" text-decoration="" font-family="'Noto Sans', 'Noto Sans JP', OpenMoji, 'OpenMoji Color', 'OpenMoji Black', sans-serif">PP</tspan>
42
+ </text>
43
+ <text white-space='pre' alignment-baseline='text-top' style='fill: #0072B2; storoke-width: 0; font-size: 32px;' x='578.3000000000001' y='580.5'><tspan x='578.3000000000001' y='580.5' style="" text-decoration="" font-family="'Noto Sans', 'Noto Sans JP', OpenMoji, 'OpenMoji Color', 'OpenMoji Black', sans-serif">P</tspan>
44
+ </text>
45
+ <text white-space='pre' alignment-baseline='text-top' style='fill: #009E73; storoke-width: 0; font-size: 32px;' x='554.8000000000001' y='751.5'><tspan x='554.8000000000001' y='751.5' style="" text-decoration="" font-family="'Noto Sans', 'Noto Sans JP', OpenMoji, 'OpenMoji Color', 'OpenMoji Black', sans-serif">over</tspan>
46
+ </text>
47
+ <text white-space='pre' alignment-baseline='text-top' style='fill: purple; storoke-width: 0; font-size: 32px;' x='760.1000000000001' y='580.5'><tspan x='760.1000000000001' y='580.5' style="" text-decoration="" font-family="'Noto Sans', 'Noto Sans JP', OpenMoji, 'OpenMoji Color', 'OpenMoji Black', sans-serif">NP</tspan>
48
+ </text>
49
+ <text white-space='pre' alignment-baseline='text-top' style='fill: #009E73; storoke-width: 0; font-size: 32px;' x='681.6000000000001' y='751.5'><tspan x='681.6000000000001' y='751.5' style="" text-decoration="" font-family="'Noto Sans', 'Noto Sans JP', OpenMoji, 'OpenMoji Color', 'OpenMoji Black', sans-serif">the<tspan style='fill:none;'>■</tspan>lazy<tspan style='fill:none;'>■</tspan>dog</tspan>
50
+ </text>
51
+ <line style='fill: none; stroke:black; stroke-width:2; stroke-linejoin:round; stroke-linecap:round;' x1='177.70000000000002' y1='182.25' x2='371.90000000000003' y2='95.625' />
52
+ <line style='fill: none; stroke:black; stroke-width:2; stroke-linejoin:round; stroke-linecap:round;' x1='566.1000000000001' y1='182.25' x2='371.90000000000003' y2='95.625' />
53
+ <line style='fill: none; stroke:black; stroke-width:2; stroke-linejoin:round; stroke-linecap:round;' x1='177.70000000000002' y1='353.25' x2='177.70000000000002' y2='266.625' />
54
+ <polygon style='fill: none; stroke: black; stroke-width:2; stroke-linejoin:round;stroke-linecap:round;' points='15.199999999999989 524.25 340.2 524.25 177.70000000000002 437.625' />
55
+ <line style='fill: none; stroke:black; stroke-width:2; stroke-linejoin:round; stroke-linecap:round;' x1='447.50000000000006' y1='353.25' x2='566.1000000000001' y2='266.625' />
56
+ <line style='fill: none; stroke:black; stroke-width:2; stroke-linejoin:round; stroke-linecap:round;' x1='684.7' y1='353.25' x2='566.1000000000001' y2='266.625' />
57
+ <line style='fill: none; stroke:black; stroke-width:2; stroke-linejoin:round; stroke-linecap:round;' x1='447.50000000000006' y1='524.25' x2='447.50000000000006' y2='437.625' />
58
+ <line style='fill: none; stroke:black; stroke-width:2; stroke-linejoin:round; stroke-linecap:round;' x1='587.8000000000001' y1='524.25' x2='684.7' y2='437.625' />
59
+ <line style='fill: none; stroke:black; stroke-width:2; stroke-linejoin:round; stroke-linecap:round;' x1='781.6000000000001' y1='524.25' x2='684.7' y2='437.625' />
60
+ <line style='fill: none; stroke:black; stroke-width:2; stroke-linejoin:round; stroke-linecap:round;' x1='587.8000000000001' y1='695.25' x2='587.8000000000001' y2='608.625' />
61
+ <polygon style='fill: none; stroke: black; stroke-width:2; stroke-linejoin:round;stroke-linecap:round;' points='681.6000000000001 695.25 881.6000000000001 695.25 781.6000000000001 608.625' />
62
+ <polyline style='stroke:red; stroke-width:2; fill:none; stroke-linejoin:round; stroke-linecap:round;'
63
+ points='156.20000000000002,187.875 148.60000000000002,187.875 148.60000000000002,261.0 156.20000000000002,261.0' />
64
+
65
+ <polyline style='stroke:red; stroke-width:2; fill:none; stroke-linejoin:round; stroke-linecap:round;'
66
+ points='199.20000000000002,187.875 206.8,187.875 206.8,261.0 199.20000000000002,261.0' />
67
+
68
+ <polyline style='stroke:green; stroke-width:2; fill:none; stroke-linejoin:round; stroke-linecap:round;'
69
+ points='547.1000000000001,187.875 539.5000000000001,187.875 539.5000000000001,261.0 547.1000000000001,261.0' />
70
+
71
+ <polyline style='stroke:green; stroke-width:2; fill:none; stroke-linejoin:round; stroke-linecap:round;'
72
+ points='585.1000000000001,187.875 592.7000000000002,187.875 592.7000000000002,261.0 585.1000000000001,261.0' />
73
+ </svg>
@@ -121,6 +121,25 @@ If `##` is placed at the beginning of the leaf text, a rectangle is drawn instea
121
121
 
122
122
  If `###` is placed at the beginning of the leaf text, a rectangle with thicker lines is drawn.
123
123
 
124
+ ### Per-Node Styling (Color)
125
+
126
+ You can specify a custom color for individual nodes using the `@color:` prefix. Both named colors and hex color codes are supported.
127
+
128
+ |Sample Input|Description|
129
+ |------------|-----------|
130
+ |`@red:NP`|Named color (red)|
131
+ |`@blue:VP`|Named color (blue)|
132
+ |`@#FF5500:NP`|Hex color code|
133
+ |`@#0A0:VP`|Short hex color code|
134
+
135
+ **Markup Order**: When combining with other prefixes, use this order: `^` (triangle) → `#` (enclosure) → `@color:` (color)
136
+
137
+ |Sample Input|Description|
138
+ |------------|-----------|
139
+ |`^@blue:NP`|Triangle connector + blue color|
140
+ |`#@red:NP`|Square brackets + red color|
141
+ |`^#@green:NP`|Triangle + brackets + green color|
142
+
124
143
  ### Escape Special Characters
125
144
 
126
145
  The backslash character `\` must be used to print certain characters used in the markup. If you do not have the `\` key on your keyboard, you can also use the yen/yuan character `¥` to escape.
@@ -153,6 +172,76 @@ Each additional connectors is distinguished by an ID number. The ID is specified
153
172
 
154
173
  A node can have any number of IDs. The same ID must appear in the text of the *two* nodes between which the additional connector is rendered. The same ID number cannot appear in more than two places.
155
174
 
175
+ ### Command Line Interface Features
176
+
177
+ The following features are available only in the command-line interface.
178
+
179
+ #### Penn Treebank Format
180
+
181
+ RSyntaxTree automatically detects and converts Penn Treebank format to bracket notation:
182
+
183
+ ```
184
+ # Penn Treebank format
185
+ (S (NP the dog) (VP runs))
186
+
187
+ # Equivalent bracket notation
188
+ [S [NP the dog] [VP runs]]
189
+ ```
190
+
191
+ **Escaping special characters in Penn Treebank format:**
192
+
193
+ | Input | Displayed as |
194
+ |-------|--------------|
195
+ | `\(` `\)` | Parentheses `()` as literal text |
196
+ | `\[` `\]` | Square brackets `[]` as literal text |
197
+
198
+ Example:
199
+ ```
200
+ (S (NP hello\(world\)) (VP test))
201
+ → [S [NP hello(world)] [VP test]]
202
+ ```
203
+
204
+ #### Standard Input Support
205
+
206
+ You can pipe tree data via standard input:
207
+
208
+ ```bash
209
+ echo "[S [NP hello] [VP world]]" | rsyntaxtree -f svg -o ./
210
+ cat tree.txt | rsyntaxtree -f png -o ./
211
+ ```
212
+
213
+ #### Configuration File
214
+
215
+ Create a `.rsyntaxtreerc` file in your home directory or current directory to set default options:
216
+
217
+ ```yaml
218
+ # ~/.rsyntaxtreerc
219
+ format: svg
220
+ color: modern
221
+ fontsize: 18
222
+ leafstyle: auto
223
+ symmetrize: off
224
+ ```
225
+
226
+ CLI arguments override configuration file settings. Unknown options in the config file will generate warnings, and invalid values will cause errors with helpful messages.
227
+
228
+ #### TikZ Output
229
+
230
+ RSyntaxTree can generate TikZ/forest code for LaTeX documents using the `-f tikz` option. The output can be used directly in LaTeX with the `forest` package.
231
+
232
+ **Limitations:** The TikZ output focuses on tree structure and does not support the following visual features:
233
+
234
+ | Feature | TikZ Support |
235
+ |---------|--------------|
236
+ | Per-node coloring (`@color:`) | Not supported |
237
+ | Enclosures (`#`, `##`) | Not supported |
238
+ | Triangle connectors (`^`) | Not supported |
239
+ | Text decoration (bold, italic) | Not supported |
240
+ | Subscript/superscript (`_x_`, `__x__`) | Not supported |
241
+ | Path drawing (`+1`, `+>1`) | Not supported |
242
+
243
+ Users familiar with LaTeX can manually add these features to the generated TikZ code using standard LaTeX commands (e.g., `\textcolor{red}{NP}`, `\textbf{...}`).
244
+
156
245
  <script src="https://cdn.jsdelivr.net/npm/jquery@3.5.0/dist/jquery.min.js"></script>
157
246
  <script src="https://cdn.jsdelivr.net/npm/lightbox2@2.11.3/src/js/lightbox.js"></script>
158
247
 
@@ -123,12 +123,31 @@ SVG形式を用いる場合,期待通りの表示を得るためには,ご
123
123
 
124
124
  ### リーフを囲む括弧と矩形の描画
125
125
 
126
- ラベルまたはリーフとなるテキストの最初に(`^` が存在する場合はその直後に) `#` を付けると,そのテキスト全体を角括弧([ ])で囲みます(例:`[#NP text]`, `[NP #text]`, `[NP ^#text]`).
126
+ ラベルまたはリーフとなるテキストの最初に(`^` が存在する場合はその直後に) `#` を付けると,そのテキスト全体を角括弧([ ])で囲みます(例:`[#NP text]`, `[NP #text]`, `[NP ^#text]`).
127
127
 
128
128
  テキストの最初に `##` を付けると,テキスト全体を矩形(ボックス)で囲みます.
129
129
 
130
130
  テキストの最初に `###` を付けると,テキスト全体を太い線の矩形(ボックス)で囲みます.
131
131
 
132
+ ### ノードごとの色指定
133
+
134
+ `@color:` プレフィックスを使用して,個々のノードにカスタムカラーを指定できます.色名とHEXカラーコードの両方がサポートされています.
135
+
136
+ |入力例|説明|
137
+ |------------|-----------|
138
+ |`@red:NP`|色名(赤)|
139
+ |`@blue:VP`|色名(青)|
140
+ |`@#FF5500:NP`|HEXカラーコード|
141
+ |`@#0A0:VP`|短縮形HEXカラーコード|
142
+
143
+ **マークアップの順序**:他のプレフィックスと組み合わせる場合は,次の順序を使用してください:`^`(三角形)→ `#`(囲み)→ `@color:`(色)
144
+
145
+ |入力例|説明|
146
+ |------------|-----------|
147
+ |`^@blue:NP`|三角形コネクター+青色|
148
+ |`#@red:NP`|角括弧+赤色|
149
+ |`^#@green:NP`|三角形+角括弧+緑色|
150
+
132
151
  ### 一部の文字を表示するためのエスケープ
133
152
 
134
153
  文字装飾などのマークアップに使用される一部の文字をテキストとして表示するためには `\` によってエスケープする必要があります.使用している環境で `\` が使えない場合は `¥` で代用することができます.
@@ -164,6 +183,76 @@ IDにはどのような数字を用いても構いませんが,必ず **2箇
164
183
 
165
184
  IDにはどのような数字を用いても構いませんが,必ず **2箇所** で同じIDを指定することが必要です.同じIDを3箇所以上で指定することはできません.
166
185
 
186
+ ### コマンドラインインターフェースの機能
187
+
188
+ 以下の機能はコマンドラインインターフェースでのみ利用可能です.
189
+
190
+ #### Penn Treebank形式
191
+
192
+ RSyntaxTreeはPenn Treebank形式を自動的に検出し,括弧表記に変換します:
193
+
194
+ ```
195
+ # Penn Treebank形式
196
+ (S (NP the dog) (VP runs))
197
+
198
+ # 同等の括弧表記
199
+ [S [NP the dog] [VP runs]]
200
+ ```
201
+
202
+ **Penn Treebank形式での特殊文字のエスケープ:**
203
+
204
+ | 入力 | 表示 |
205
+ |------|------|
206
+ | `\(` `\)` | 丸括弧 `()` をそのまま表示 |
207
+ | `\[` `\]` | 角括弧 `[]` をそのまま表示 |
208
+
209
+ 例:
210
+ ```
211
+ (S (NP hello\(world\)) (VP test))
212
+ → [S [NP hello(world)] [VP test]]
213
+ ```
214
+
215
+ #### 標準入力のサポート
216
+
217
+ パイプを使って標準入力からツリーデータを渡すことができます:
218
+
219
+ ```bash
220
+ echo "[S [NP hello] [VP world]]" | rsyntaxtree -f svg -o ./
221
+ cat tree.txt | rsyntaxtree -f png -o ./
222
+ ```
223
+
224
+ #### 設定ファイル
225
+
226
+ ホームディレクトリまたはカレントディレクトリに `.rsyntaxtreerc` ファイルを作成して,デフォルトオプションを設定できます:
227
+
228
+ ```yaml
229
+ # ~/.rsyntaxtreerc
230
+ format: svg
231
+ color: modern
232
+ fontsize: 18
233
+ leafstyle: auto
234
+ symmetrize: off
235
+ ```
236
+
237
+ コマンドライン引数は設定ファイルの設定を上書きします.設定ファイル内の不明なオプションは警告を生成し,無効な値はエラーメッセージを表示します.
238
+
239
+ #### TikZ出力
240
+
241
+ RSyntaxTreeは`-f tikz`オプションを使用してLaTeXドキュメント用のTikZ/forestコードを生成できます.出力は`forest`パッケージを使用してLaTeXで直接使用できます.
242
+
243
+ **制限事項:** TikZ出力はツリー構造に焦点を当てており,以下の視覚的機能はサポートされていません:
244
+
245
+ | 機能 | TikZサポート |
246
+ |------|--------------|
247
+ | ノード別カラー指定(`@color:`) | 非対応 |
248
+ | 囲み(`#`,`##`) | 非対応 |
249
+ | 三角形コネクタ(`^`) | 非対応 |
250
+ | テキスト装飾(太字,斜体) | 非対応 |
251
+ | 下付き・上付き文字(`_x_`,`__x__`) | 非対応 |
252
+ | パス描画(`+1`,`+>1`) | 非対応 |
253
+
254
+ LaTeXに精通しているユーザーは,標準的なLaTeXコマンド(例:`\textcolor{red}{NP}`,`\textbf{...}`)を使用して,生成されたTikZコードにこれらの機能を手動で追加できます.
255
+
167
256
  <script src="https://cdn.jsdelivr.net/npm/jquery@3.5.0/dist/jquery.min.js"></script>
168
257
  <script src="https://cdn.jsdelivr.net/npm/lightbox2@2.11.3/src/js/lightbox.js"></script>
169
258
 
@@ -5,7 +5,7 @@
5
5
  #==========================
6
6
  #
7
7
  # Image utility functions to inspect text font metrics
8
- # Copyright (c) 2007-2024 Yoichiro Hasebe <yohasebe@gmail.com>
8
+ # Copyright (c) 2007-2026 Yoichiro Hasebe <yohasebe@gmail.com>
9
9
 
10
10
  require_relative 'utils'
11
11
 
@@ -44,7 +44,7 @@ module RSyntaxTree
44
44
  @col_bg = "none"
45
45
  @col_fg = "black"
46
46
 
47
- @col_line = if params[:hide_default_connectors]
47
+ @col_line = if params[:hide_default_connectors] == true
48
48
  "none"
49
49
  else
50
50
  "black"
@@ -188,19 +188,19 @@ module RSyntaxTree
188
188
  child = children[0]
189
189
  case @leafstyle
190
190
  when "auto"
191
- if child.contains_phrase || child.triangle
191
+ if parent.triangle || child.contains_phrase
192
192
  triangle_to_parent(parent, child)
193
193
  else
194
194
  line_to_parent(parent, child)
195
195
  end
196
196
  when "bar"
197
- if child.triangle
197
+ if parent.triangle
198
198
  triangle_to_parent(parent, child)
199
199
  else
200
200
  line_to_parent(parent, child)
201
201
  end
202
202
  when "nothing", "none"
203
- if child.triangle
203
+ if parent.triangle
204
204
  triangle_to_parent(parent, child)
205
205
  elsif ETYPE_LEAF != child.type
206
206
  line_to_parent(parent, child)
@@ -5,14 +5,14 @@
5
5
  #==========================
6
6
  #
7
7
  # Aa class that represents a basic tree element, either node or leaf.
8
- # Copyright (c) 2007-2024 Yoichiro Hasebe <yohasebe@gmail.com>
8
+ # Copyright (c) 2007-2026 Yoichiro Hasebe <yohasebe@gmail.com>
9
9
 
10
10
  require_relative "markup_parser"
11
11
  require_relative "utils"
12
12
 
13
13
  module RSyntaxTree
14
14
  class Element
15
- attr_accessor :id, :parent, :type, :level, :width, :height, :content, :content_width, :content_height, :horizontal_indent, :vertical_indent, :triangle, :enclosure, :children, :font, :fontsize, :contains_phrase, :path
15
+ attr_accessor :id, :parent, :type, :level, :width, :height, :content, :content_width, :content_height, :horizontal_indent, :vertical_indent, :triangle, :enclosure, :children, :font, :fontsize, :contains_phrase, :path, :color
16
16
 
17
17
  def initialize(id, parent, content, level, fontset, fontsize, global)
18
18
  @global = global
@@ -49,6 +49,7 @@ module RSyntaxTree
49
49
  @paths = results[:paths]
50
50
  @enclosure = results[:enclosure]
51
51
  @triangle = results[:triangle]
52
+ @color = results[:color]
52
53
 
53
54
  @contains_phrase = false
54
55
  setup
@@ -5,7 +5,7 @@
5
5
  #==========================
6
6
  #
7
7
  # Contains a list of unordered tree elements with a defined parent
8
- # Copyright (c) 2007-2024 Yoichiro Hasebe <yohasebe@gmail.com>
8
+ # Copyright (c) 2007-2026 Yoichiro Hasebe <yohasebe@gmail.com>
9
9
 
10
10
  require_relative "element"
11
11
 
@@ -33,7 +33,7 @@ module RSyntaxTree
33
33
  end
34
34
 
35
35
  def get_first
36
- return nil if @elements.length.empty?
36
+ return nil if @elements.empty?
37
37
 
38
38
  @iterator = 0
39
39
  @elements[@iterator]
@@ -41,9 +41,7 @@ module RSyntaxTree
41
41
 
42
42
  def get_next
43
43
  @iterator += 1
44
- return @elements[@iterator] if @elements[@iterator]
45
-
46
- nil
44
+ @elements[@iterator]
47
45
  end
48
46
 
49
47
  def get_id(id)
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ #==========================
4
+ # format_converter.rb
5
+ #==========================
6
+ #
7
+ # Converts various tree notation formats to RSyntaxTree's bracket notation
8
+ # Copyright (c) 2007-2026 Yoichiro Hasebe <yohasebe@gmail.com>
9
+
10
+ module RSyntaxTree
11
+ module FormatConverter
12
+ module_function
13
+
14
+ # Detect the format of the input string
15
+ # @param text [String] the input tree notation
16
+ # @return [Symbol] :penn or :bracket
17
+ def detect_format(text)
18
+ stripped = text.strip
19
+ if stripped.start_with?('(') && !stripped.start_with?('([')
20
+ :penn
21
+ else
22
+ :bracket
23
+ end
24
+ end
25
+
26
+ # Convert any supported format to bracket notation
27
+ # @param text [String] the input tree notation
28
+ # @return [String] bracket notation
29
+ def to_bracket(text)
30
+ case detect_format(text)
31
+ when :penn
32
+ penn_to_bracket(text)
33
+ else
34
+ text
35
+ end
36
+ end
37
+
38
+ # Convert Penn TreeBank format to bracket notation
39
+ # Penn: (S (NP hello) (VP world))
40
+ # Bracket: [S [NP hello] [VP world]]
41
+ # Use \( and \) to include literal parentheses in text
42
+ # @param text [String] Penn TreeBank notation
43
+ # @return [String] bracket notation
44
+ def penn_to_bracket(text)
45
+ # Normalize whitespace (collapse multiple spaces/newlines to single space)
46
+ normalized = text.gsub(/\s+/, ' ').strip
47
+
48
+ # Protect escaped parentheses with placeholders
49
+ result = normalized.gsub('\(', "\x00LPAREN\x00").gsub('\)', "\x00RPAREN\x00")
50
+
51
+ # Replace structural parentheses with brackets
52
+ result = result.gsub('(', '[').gsub(')', ']')
53
+
54
+ # Restore escaped parentheses as literal parentheses
55
+ result = result.gsub("\x00LPAREN\x00", '(').gsub("\x00RPAREN\x00", ')')
56
+
57
+ # Clean up extra spaces after opening brackets
58
+ result = result.gsub(/\[\s+/, '[')
59
+ # Clean up extra spaces before closing brackets
60
+ result = result.gsub(/\s+\]/, ']')
61
+
62
+ result
63
+ end
64
+ end
65
+ end
@@ -13,6 +13,11 @@ class MarkupParser < Parslet::Parser
13
13
  rule(:brackets) { str('#') }
14
14
  rule(:triangle) { str('^') }
15
15
 
16
+ # Color specification: @colorname: or @#hexcode:
17
+ rule(:color_name) { match('[a-zA-Z]').repeat(1) }
18
+ rule(:color_hex) { str('#') >> match('[0-9a-fA-F]').repeat(3, 6) }
19
+ rule(:color_spec) { str('@') >> (color_hex | color_name).as(:color_value) >> str(':') }
20
+
16
21
  rule(:path) { (str('+') >> str('-').maybe >> (str('>') | str('<')).maybe >> match('\d').repeat(1)).as(:path) }
17
22
  # rule(:escaped) { str('\\') >> match('[#<>{}\\^+*_=~\|\n\-]').as(:chr) }
18
23
  rule(:escaped) { str('\\') >> match('[#<>{}\\\\^+*_=~\\|\\n\\-\\[\\]]').as(:chr) }
@@ -51,7 +56,7 @@ class MarkupParser < Parslet::Parser
51
56
  rule(:markup) { (text | decoration | shape | bstroke) }
52
57
 
53
58
  rule(:line) { (cr.as(:extracr) | border | bborder | markup.repeat(1).as(:line) >> (cr | eof | str('+').present?)) }
54
- rule(:lines) { triangle.maybe.as(:triangle) >> (brectangle | rectangle | brackets).maybe.as(:enclosure) >> line.repeat(1) >> path.repeat(0).as(:paths) >> (cr | eof) }
59
+ rule(:lines) { triangle.maybe.as(:triangle) >> (brectangle | rectangle | brackets).maybe.as(:enclosure) >> color_spec.maybe.as(:color) >> line.repeat(1) >> path.repeat(0).as(:paths) >> (cr | eof) }
55
60
  root :lines
56
61
  end
57
62
 
@@ -171,7 +176,7 @@ module Markup
171
176
 
172
177
  applied = @evaluator.apply(parsed)
173
178
 
174
- results = { enclosure: :none, triangle: false, paths: [], contents: [] }
179
+ results = { enclosure: :none, triangle: false, paths: [], contents: [], color: nil }
175
180
  applied.each do |h|
176
181
  if h[:enclosure]
177
182
  results[:enclosure] = case h[:enclosure].to_s
@@ -187,6 +192,12 @@ module Markup
187
192
  end
188
193
  results[:triangle] = h[:triangle].to_s == '^' if h[:triangle]
189
194
  results[:paths] = h[:paths] if h[:paths]
195
+ # Handle color specification
196
+ if h[:color] && h[:color][:color_value]
197
+ color_value = h[:color][:color_value].to_s
198
+ # Prepend # if it's a hex color without it (parser captures just the hex part after #)
199
+ results[:color] = color_value
200
+ end
190
201
  results[:contents] << h if h[:type] == :text || h[:type] == :border || h[:type] == :bborder
191
202
  end
192
203
  { status: :success, results: results }
@@ -6,7 +6,7 @@
6
6
  #
7
7
  # Parses a phrase into leafs and nodes and store the result in an element list
8
8
  # (see element_list.rb)
9
- # Copyright (c) 2007-2024 Yoichiro Hasebe <yohasebe@gmail.com>
9
+ # Copyright (c) 2007-2026 Yoichiro Hasebe <yohasebe@gmail.com>
10
10
 
11
11
  require_relative 'elementlist'
12
12
  require_relative 'element'
@@ -5,7 +5,7 @@
5
5
  #==========================
6
6
  #
7
7
  # Parses an element list into an SVG tree.
8
- # Copyright (c) 2007-2024 Yoichiro Hasebe <yohasebe@gmail.com>
8
+ # Copyright (c) 2007-2026 Yoichiro Hasebe <yohasebe@gmail.com>
9
9
 
10
10
  # No tempfile usage in this file
11
11
  require_relative 'base_graph'
@@ -149,7 +149,10 @@ module RSyntaxTree
149
149
  right = left + element.content_width
150
150
  txt_pos = left + (right - left) / 2
151
151
 
152
- col = if element.type == ETYPE_LEAF
152
+ # Use element's custom color if specified, otherwise use default based on type
153
+ col = if element.color
154
+ element.color
155
+ elsif element.type == ETYPE_LEAF
153
156
  @col_leaf
154
157
  else
155
158
  @col_node
@@ -444,7 +447,11 @@ module RSyntaxTree
444
447
 
445
448
  path_flags.uniq.each do |k|
446
449
  targets = path_pool_target[k]
450
+ next if targets.nil? || targets.empty?
451
+
447
452
  fst = targets.shift
453
+ next if fst.nil?
454
+
448
455
  targets.each do |t|
449
456
  paths << { x1: fst[0], y1: fst[1], x2: t[0], y2: t[1], arrow: :double }
450
457
  end