rsyntaxtree 1.14.0 → 2.0.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +145 -3
- data/README.md +15 -7
- data/bin/rsyntaxtree +10 -11
- data/lib/rsyntaxtree/base_graph.rb +17 -8
- data/lib/rsyntaxtree/element.rb +25 -2
- data/lib/rsyntaxtree/lsif_graph.rb +9 -3
- data/lib/rsyntaxtree/markup_parser.rb +8 -3
- data/lib/rsyntaxtree/notation_core.md +17 -4
- data/lib/rsyntaxtree/notation_examples.md +97 -5
- data/lib/rsyntaxtree/svg_graph.rb +266 -13
- data/lib/rsyntaxtree/tikz_generator.rb +9 -0
- data/lib/rsyntaxtree/version.rb +1 -1
- data/lib/rsyntaxtree.rb +93 -68
- data/rsyntaxtree.gemspec +4 -3
- metadata +1 -29
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9ccd433053f296c9189c9eceb87f61c91ed815ff6b1be77f1cd2115a73eaf1cd
|
|
4
|
+
data.tar.gz: f769d68efb73c1aafc9dc9af9f0e4e7cbd7a0c741caf253905ebe11dc3c454be
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0e6218bc0ddf1f4c49e8fac2c8972cbd3e0eb251fe7087150ea73f63b054fe546483588e582a0f01e52ab26c20fd883ab2c67da07adf1f3120755447a7956945
|
|
7
|
+
data.tar.gz: b0810c0df9ede2cd1c36100ae9a3c055ece2d59261f8278ef8de8b79e07921702c7b8db83fa43f81810184c363b860bae3d9a9c1f45b4a02307f5f8220354fa8
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,119 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [2.0.0] - 2026-08-28
|
|
4
|
+
|
|
5
|
+
The removals announced in 1.10.0 and 1.12.0, and the fixes that came out of
|
|
6
|
+
looking at what was left. Every figure in the gallery draws exactly as it did.
|
|
7
|
+
|
|
8
|
+
### Removed
|
|
9
|
+
- JPG and GIF output. JPEG blurs line art and GIF has nothing to offer that
|
|
10
|
+
PNG does not do better, and they were the only reason for the RMagick
|
|
11
|
+
dependency. `-f jpg` and `-f gif` are now refused the way any unknown
|
|
12
|
+
format is. Use `-f png`.
|
|
13
|
+
- The RMagick dependency, and with it ImageMagick. A machine that installs
|
|
14
|
+
this gem no longer needs ImageMagick's headers to build one, and the gem
|
|
15
|
+
now asks for four libraries instead of five.
|
|
16
|
+
- The deprecated aliases, which a major release is the moment to drop:
|
|
17
|
+
`symmetrize` and its `-y` flag (say `tidy: symmetric`), `tidy_spacing`
|
|
18
|
+
(say `hspacing`), the undocumented `tidy_nest`, and `nothing`'s
|
|
19
|
+
undocumented spelling `none` in `leafstyle`. Each is refused by name and
|
|
20
|
+
told what replaced it. An unknown option is passed over in silence, since
|
|
21
|
+
a caller may hand its own parameters through, and a removed one read that
|
|
22
|
+
way would have handed back a different figure without a word.
|
|
23
|
+
- `symmetrize` from the LSIF `meta.source.params` block. The layout scale it
|
|
24
|
+
duplicated, `tidy`, is written there already.
|
|
25
|
+
|
|
26
|
+
### Fixed
|
|
27
|
+
- A triangle drawn bottom to top pointed the wrong way. The shape spans the
|
|
28
|
+
child's text and points at the parent, and which way that is depends on
|
|
29
|
+
which of the two sits higher — the question the connectors ask and the
|
|
30
|
+
triangle did not. Bottom to top the figure folded through itself: the base
|
|
31
|
+
struck through the leaf and the apex through the node. No gallery figure
|
|
32
|
+
carries one, because every bottom-to-top example is a derivation, which
|
|
33
|
+
draws rules instead of connectors.
|
|
34
|
+
- Every label now keeps the same air above it as below it. The connector
|
|
35
|
+
endpoints were measured from the layout box, whose edges sit unevenly
|
|
36
|
+
around the ink, so every figure carried a little more space under each
|
|
37
|
+
label than over it — visibly once a figure was tilted. The enclosures
|
|
38
|
+
were built with symmetric clearances all along; the plain labels now get
|
|
39
|
+
what the boxes always had. Nearly every gallery figure changes by a few
|
|
40
|
+
pixels of line length; no label, no position and no size moves.
|
|
41
|
+
- A movement rail could reach past the right edge of a left-to-right
|
|
42
|
+
canvas and be cut off at it: the rail grows the canvas as it routes, and
|
|
43
|
+
the width it grew — unlike the height — was then recomputed from the
|
|
44
|
+
elements alone. Four pixels at the default spacing, twenty-four at
|
|
45
|
+
hspacing 0.5.
|
|
46
|
+
- A rule written `---` (or `===` for a double rule) was refused inside a
|
|
47
|
+
`#( … #)` matrix, though it was drawn in every other kind of label. Two
|
|
48
|
+
hyphens and four were accepted there and three were not — a distinction
|
|
49
|
+
nothing could explain. The matrix grammar had no rule for it and the
|
|
50
|
+
matrix renderer dropped every row that was not text.
|
|
51
|
+
- The bracket of a matrix that followed something in the same cell was drawn
|
|
52
|
+
on top of it: `AGR |1| [ … ]`, which is how a shared value is written, put
|
|
53
|
+
the right edge of the tag and the left edge of the bracket on the same
|
|
54
|
+
coordinate exactly. A block now keeps as much room in front of it as the
|
|
55
|
+
bracket keeps inside it.
|
|
56
|
+
- In a left-to-right tree, `hspacing` and `vheight` both moved the width and
|
|
57
|
+
nothing moved the height. The layout replaces the gap that separates
|
|
58
|
+
sisters with one of its own and was not scaling it by `hspacing`, so a
|
|
59
|
+
left-to-right figure could be made wider but never shorter.
|
|
60
|
+
- `storoke-width` in the style of every text element of every SVG. Renderers
|
|
61
|
+
ignored the misspelling, so nothing ever looked wrong.
|
|
62
|
+
|
|
63
|
+
### Added
|
|
64
|
+
- `shear`: the drawn figure tilts by the given angle (degrees, positive
|
|
65
|
+
leaning the top to the right) and lies on a plane drawn behind it, so the
|
|
66
|
+
lean reads as a surface seen at an angle rather than as a mistake. The
|
|
67
|
+
whole picture shears as one affine piece — layout untouched, region
|
|
68
|
+
shades coming out parallelograms on their own, and nothing able to newly
|
|
69
|
+
touch or cross. The plane is fill without an edge — a region shade is
|
|
70
|
+
bounded because it marks one part of a figure off from the rest, and a
|
|
71
|
+
line round the whole drawing would read as a frame. `shear_plane` turns
|
|
72
|
+
it off or gives it a colour, and a transparent background takes it away
|
|
73
|
+
for you: a clear background is asked for in order to lay the figure over
|
|
74
|
+
something else, and a sheet under it is what would defeat that.
|
|
75
|
+
TikZ refuses a sheared figure the way it refuses a derivation.
|
|
76
|
+
- `vmargin`: the clearance between a label and its connectors, the same
|
|
77
|
+
above and below, measured from the ink its row actually contains — a row
|
|
78
|
+
of capitals pays nothing for descenders nobody wrote, and the ends of a
|
|
79
|
+
row's connectors stay level. From 0.1 to 1.0; at nothing at all a node's
|
|
80
|
+
box stops holding a label that draws its own shape.
|
|
81
|
+
- Three gallery examples, in two new categories: the Indo-European family
|
|
82
|
+
tree (Historical Linguistics), where the region shade groups branches
|
|
83
|
+
rather than marking a c-command domain; type-driven semantic composition
|
|
84
|
+
(Formal Semantics); and a tree of typed feature structures with structure
|
|
85
|
+
sharing (Formal Grammar), which is the figure the matrix rule was missing.
|
|
86
|
+
|
|
87
|
+
### Changed
|
|
88
|
+
- The documents name every option. Four were missing from the one-page
|
|
89
|
+
reference and one from the README, because the test that reads the
|
|
90
|
+
documents built its roll-call from the tables of listed and numeric
|
|
91
|
+
values — and so never asked after the options that take on or off. It
|
|
92
|
+
reads the roll-call from the defaults now, and the README is one of the
|
|
93
|
+
documents it reads.
|
|
94
|
+
- Three tests were added for the shapes of defect this release fixed: one
|
|
95
|
+
asks every feature in the index to read the same in a label, in a matrix
|
|
96
|
+
and in a matrix inside a matrix; one reads the drawn shapes back out of
|
|
97
|
+
the SVG and asks whether any two of them touch; and one asks a
|
|
98
|
+
left-to-right tree to answer to `hspacing` in its height.
|
|
99
|
+
- The sweep draws two more figures — one with a triangle, one with a
|
|
100
|
+
movement rail — and moves the direction, `vmargin` and `shear` among its
|
|
101
|
+
settings, and asks of every triangle that it have an area. Each of the two
|
|
102
|
+
defects above lived in a figure the sweep did not draw, at a direction it
|
|
103
|
+
did not set: the settings alone could not have found either, and a
|
|
104
|
+
triangle folded flat passes every other check there is.
|
|
105
|
+
- The manuals say what TikZ output does with what it cannot draw: it drops
|
|
106
|
+
it rather than refusing, so a label that is a matrix arrives with its
|
|
107
|
+
cells run together on one line.
|
|
108
|
+
|
|
109
|
+
### Migration
|
|
110
|
+
- `format: "jpg"` / `"gif"` → `"png"`.
|
|
111
|
+
- `symmetrize: "on"` → `tidy: "symmetric"`; `tidy_spacing: n` → `hspacing: n`;
|
|
112
|
+
`leafstyle: "none"` → `"nothing"`. Each has been the documented spelling
|
|
113
|
+
since 1.12.0.
|
|
114
|
+
- Everything else — every other option, and every piece of notation — is
|
|
115
|
+
unchanged.
|
|
116
|
+
|
|
3
117
|
## [1.14.0] - 2026-08-27
|
|
4
118
|
|
|
5
119
|
### Added
|
|
@@ -513,12 +627,40 @@ RMagick dependency.
|
|
|
513
627
|
|
|
514
628
|
## [1.3.1] - 2024-10-24
|
|
515
629
|
|
|
630
|
+
- Square brackets can be escaped with `\[` and `\]`
|
|
516
631
|
- Bug fixes and improvements
|
|
517
632
|
|
|
518
633
|
## [1.3.0] - 2024-08-27
|
|
519
634
|
|
|
520
635
|
- TikZ/forest LaTeX output support
|
|
521
636
|
|
|
522
|
-
##
|
|
523
|
-
|
|
524
|
-
|
|
637
|
+
## Earlier releases (2018–2023)
|
|
638
|
+
|
|
639
|
+
Before this file was kept, the web interface carried the release notes. Moved
|
|
640
|
+
here so the history has one home.
|
|
641
|
+
|
|
642
|
+
- 2023-09 — Cross-hatch rendering issue fixed
|
|
643
|
+
- 2023-02 — PDF download; improved line edges; `Line width` option;
|
|
644
|
+
`Traditional` colour option; `Hide connectors` option; extra connectors
|
|
645
|
+
between nodes
|
|
646
|
+
- 2023-01 — `Noto Sans Mono` font option
|
|
647
|
+
- 2022-11 — `¥` accepted in place of the backslash for escapes; documentation
|
|
648
|
+
in Japanese
|
|
649
|
+
- 2022-06 — RSyntaxTree on the Web: the UI as a source package, runnable
|
|
650
|
+
locally with Docker
|
|
651
|
+
- 2022-02 — `Polyline connector` option
|
|
652
|
+
- 2022-01 — comprehensive rewrite; path drawing (non-directional, directional,
|
|
653
|
+
bidirectional); more flexible text markup; new markup patterns (newlines,
|
|
654
|
+
brackets, horizontal lines, boxed text); triangles in every connector mode;
|
|
655
|
+
improved error display and image zoom in the UI
|
|
656
|
+
- 2021-12 — subscript `_text_` and superscript `__text__`; `\n` inside
|
|
657
|
+
terminal nodes
|
|
658
|
+
- 2021-11 — label-less terminal nodes (`[A [B] [C]]`); auto bracket close;
|
|
659
|
+
math symbol rendering; better image quality; some decoration symbols altered
|
|
660
|
+
- 2019-11 — SVG download error fixed
|
|
661
|
+
- 2019-04 — SVG colour on/off fixed
|
|
662
|
+
- 2018-06 — whitespace in labels with `<>` (`Modal<>AUX`)
|
|
663
|
+
- 2018-03 — `V spacing` option (then called Connector height); syntax
|
|
664
|
+
highlighting of the input; text styles (italic, bold) and decoration
|
|
665
|
+
(underline, overline, line-through); refined site design
|
|
666
|
+
- 2018-02 — margins around the image; better editor (Ace)
|
data/README.md
CHANGED
|
@@ -69,7 +69,7 @@ Connect nodes with lines or arrows:
|
|
|
69
69
|
|
|
70
70
|
### Multiple Output Formats
|
|
71
71
|
|
|
72
|
-
Generate trees in PNG, SVG, PDF, or LSIF (JSON) format.
|
|
72
|
+
Generate trees in PNG, SVG, PDF, TikZ, or LSIF (JSON) format.
|
|
73
73
|
|
|
74
74
|
## Web Interface
|
|
75
75
|
|
|
@@ -170,18 +170,25 @@ Usage:
|
|
|
170
170
|
| Option | Description | Default |
|
|
171
171
|
|--------|-------------|---------|
|
|
172
172
|
| `-o, --outdir` | Output directory | `./` |
|
|
173
|
-
| `-f, --format` | Output format: png, svg, pdf, lsif, tikz
|
|
173
|
+
| `-f, --format` | Output format: png, svg, pdf, lsif, tikz | `png` |
|
|
174
174
|
| `-l, --leafstyle` | Leaf style: auto, triangle, bar, nothing | `auto` |
|
|
175
175
|
| `-n, --fontstyle` | Font style: sans, serif, cjk, mono | `sans` |
|
|
176
176
|
| `-s, --fontsize` | Font size: 6-26 | `16` |
|
|
177
177
|
| `-i, --linewidth` | Line width relative to the font size: 0.5-3.0 (`1` = 5% of the font size) | `1.0` |
|
|
178
178
|
| `-c, --color` | Color mode: modern, traditional, gray (black text, grey lines), off | `modern` |
|
|
179
179
|
| `-p, --polyline` | Polyline connectors: on, off | `off` |
|
|
180
|
-
|
|
|
180
|
+
| `--hide-default-connectors` | Draw no parent-to-child lines, leaving only the ones written with `+-n`: on, off | `off` |
|
|
181
|
+
| `-d, --direction` | Tree layout direction: ttb, ltr, btt | `ttb` |
|
|
181
182
|
| `--tidy` | Layout scale: off, symmetric, low, medium, high | `off` |
|
|
182
|
-
| `--hspacing` |
|
|
183
|
+
| `--hspacing` | How far apart sisters sit, all layout modes (0.5-3.0) | `1.0` |
|
|
184
|
+
| `-v, --vheight` | How far apart levels sit (0.5-5.0) | `2.0` |
|
|
185
|
+
| `--derivation` | Join each node to its daughters with one rule drawn across them: on, off | `off` |
|
|
183
186
|
| `--hyphen` | How a hyphen reads: markup (`-underline-`) or literal | `markup` |
|
|
184
187
|
| `-m, --mirror` | Flip the tree horizontally (RTL convention): on, off | `off` |
|
|
188
|
+
| `--shear` | Tilt the drawn figure, in degrees (-45 to 45, positive leans the top right) | `0` |
|
|
189
|
+
| `--shear-plane` | The plane behind a sheared figure: on, off, or a colour | `on` |
|
|
190
|
+
| `--vmargin` | Clearance between a label and its connectors (0.1-1.0, same above and below) | `0.4` |
|
|
191
|
+
| `-r, --transparent` | Leave the background clear instead of painting it white: on, off | `off` |
|
|
185
192
|
| `--validate` | Check the input without drawing: a JSON diagnosis on stdout, the verdict in the exit code | |
|
|
186
193
|
| `--notation` | Print a short reference for the notation | |
|
|
187
194
|
|
|
@@ -215,10 +222,11 @@ a model writing it does better with the reference in front of it than without.
|
|
|
215
222
|
[web interface](https://yohasebe.com/rsyntaxtree) or on your own machine —
|
|
216
223
|
nothing needs installing. Give the model one of these to read:
|
|
217
224
|
|
|
218
|
-
- [The
|
|
219
|
-
|
|
225
|
+
- [The reference, on one page](https://yohasebe.github.io/rsyntaxtree/notation.txt):
|
|
226
|
+
the characters that already mean something, then every feature at a line
|
|
227
|
+
each, then the options. About 6 KB.
|
|
220
228
|
- [Everything in one file](https://yohasebe.github.io/rsyntaxtree/llms-full.txt):
|
|
221
|
-
the reference, the manual and all the gallery examples,
|
|
229
|
+
the reference, the manual and all the gallery examples, about 85 KB.
|
|
222
230
|
|
|
223
231
|
**If the model can run a shell**, it can draw and then look at what it drew,
|
|
224
232
|
which is the part that lets it correct itself:
|
data/bin/rsyntaxtree
CHANGED
|
@@ -9,7 +9,7 @@ require_relative '../lib/rsyntaxtree'
|
|
|
9
9
|
require_relative '../lib/rsyntaxtree/utils'
|
|
10
10
|
require_relative '../lib/rsyntaxtree/format_converter'
|
|
11
11
|
|
|
12
|
-
# "png,
|
|
12
|
+
# "png, pdf, svg, lsif, or tikz" — built once from the library's
|
|
13
13
|
# own list so the three places that name the formats cannot drift apart.
|
|
14
14
|
FORMAT_LIST_MESSAGE = FORMATS.join(", ").sub(/, ([^,]+)\z/, ', or \1')
|
|
15
15
|
|
|
@@ -24,14 +24,15 @@ CONFIG_VALIDATORS = {
|
|
|
24
24
|
linewidth: ->(v) { v.is_a?(Numeric) && v >= 0.5 && v <= 3.0 ? nil : "must be in the range of 0.5-3.0" },
|
|
25
25
|
vheight: ->(v) { v.is_a?(Numeric) && v >= 0.5 && v <= 5.0 ? nil : "must be in the range of 0.5-5.0" },
|
|
26
26
|
color: ->(v) { OPTION_VALUES[:color].include?(v.to_s) ? nil : "must be modern, traditional, gray, or off" },
|
|
27
|
-
symmetrize: ->(v) { /\A(on|off|true|false)\z/ =~ v.to_s ? nil : "must be on or off" },
|
|
28
27
|
transparent: ->(v) { /\A(on|off|true|false)\z/ =~ v.to_s ? nil : "must be on or off" },
|
|
29
28
|
polyline: ->(v) { /\A(on|off|true|false)\z/ =~ v.to_s ? nil : "must be on or off" },
|
|
30
29
|
hide_default_connectors: ->(v) { /\A(on|off|true|false)\z/ =~ v.to_s ? nil : "must be on or off" },
|
|
31
30
|
mirror: ->(v) { /\A(on|off|true|false)\z/ =~ v.to_s ? nil : "must be on or off" },
|
|
31
|
+
shear: ->(v) { v.is_a?(Numeric) && v >= -45 && v <= 45 ? nil : "must be in the range of -45-45" },
|
|
32
|
+
vmargin: ->(v) { v.is_a?(Numeric) && v >= 0.1 && v <= 1.0 ? nil : "must be in the range of 0.1-1.0" },
|
|
33
|
+
shear_plane: ->(v) { v.to_s =~ /\A(on|off)\z/ || RSyntaxTree::COLOR_NAMES.include?(v.to_s.downcase) || v.to_s =~ /\A#(\h{3}|\h{6})\z/ ? nil : "must be on, off, or a colour" },
|
|
32
34
|
tidy: ->(v) { OPTION_VALUES[:tidy].include?(v.to_s) ? nil : "must be off, symmetric, low, medium, or high" },
|
|
33
35
|
hspacing: ->(v) { v.is_a?(Numeric) && v >= 0.5 && v <= 3.0 ? nil : "must be in the range of 0.5-3.0" },
|
|
34
|
-
tidy_spacing: ->(v) { v.is_a?(Numeric) && v >= 0.5 && v <= 3.0 ? nil : "must be in the range of 0.5-3.0" },
|
|
35
36
|
direction: ->(v) { OPTION_VALUES[:direction].include?(v.to_s) ? nil : "must be one of: #{OPTION_VALUES[:direction].join(', ')}" },
|
|
36
37
|
hyphen: ->(v) { OPTION_VALUES[:hyphen].include?(v.to_s) ? nil : "must be markup or literal" }
|
|
37
38
|
}.freeze
|
|
@@ -114,14 +115,15 @@ opts = Optimist.options do
|
|
|
114
115
|
opt :linewidth, "Size: 0.5-3.0", default: 1.0, short: :i
|
|
115
116
|
opt :vheight, "Connector Height: 0.5-5.0", default: 2.0, short: :v
|
|
116
117
|
opt :color, "Color text and bars: modern, traditional, gray, or off", default: "modern", short: :c
|
|
117
|
-
opt :symmetrize, "DEPRECATED alias of --tidy symmetric: on or off", default: "off", short: :y
|
|
118
118
|
opt :transparent, "Make background transparent: on or off", default: "off", short: :r
|
|
119
119
|
opt :polyline, "draw polyline connectors: on or off", default: "off", short: :p
|
|
120
120
|
opt :hide_default_connectors, "make default connectors transparent: on or off", default: "off", short: :none
|
|
121
121
|
opt :mirror, "flip the tree horizontally (RTL linguistics convention: first word at the right edge): on or off", default: "off"
|
|
122
|
+
opt :shear, "Tilt the drawn figure, in degrees: -45 to 45, positive leaning the top to the right", default: 0.0, short: :none
|
|
123
|
+
opt :shear_plane, "The plane behind a sheared figure: on, off, a colour name, or a hex colour", default: "on", short: :none
|
|
124
|
+
opt :vmargin, "Clearance between a label and its connectors, 0.1-1.0", default: 0.4, short: :none
|
|
122
125
|
opt :tidy, "tidy tree layout: off, symmetric (radical symmetrization), low (packed, strict leaf positions), medium (packed; leaves may overlap but never swap order), or high (packed; leaf order kept per row only)", default: "off", short: :none
|
|
123
126
|
opt :hspacing, "Horizontal spacing factor (counterpart of vheight): 0.5-3.0", default: 1.0, short: :none
|
|
124
|
-
opt :tidy_spacing, "DEPRECATED alias of --hspacing: 0.5-3.0", default: 1.0, short: :none
|
|
125
127
|
opt :direction, "Tree layout direction: ttb (top-to-bottom), ltr (left-to-right) or btt (bottom-to-top, the root last)", default: "ttb", short: :d
|
|
126
128
|
opt :derivation, "Join each node to its daughters with one rule drawn across them, as a derivation is written, rather than with a line to each: on, off", default: "off", short: :none
|
|
127
129
|
opt :hyphen, "How a hyphen in a label reads: markup (-underline-) or literal (a hyphen; \-underline\- then underlines)", default: "markup", short: :none
|
|
@@ -140,8 +142,10 @@ Optimist.die :leafstyle, "must be auto, triangle, bar, or nothing" unless OPTION
|
|
|
140
142
|
Optimist.die :fontstyle, "must be sans, serif, cjk, or mono" unless OPTION_VALUES[:fontstyle].include?(opts[:fontstyle])
|
|
141
143
|
Optimist.die :fontsize, "must be in the range of 6-26" unless opts[:fontsize] >= 6 && opts[:fontsize] <= 26
|
|
142
144
|
Optimist.die :linewidth, "must be in the range of 0.5-3.0" unless opts[:linewidth] >= 0.5 && opts[:linewidth] <= 3.0
|
|
145
|
+
Optimist.die :shear, "must be in the range of -45-45" unless opts[:shear] >= -45 && opts[:shear] <= 45
|
|
146
|
+
Optimist.die :vmargin, "must be in the range of 0.1-1.0" unless opts[:vmargin] >= 0.1 && opts[:vmargin] <= 1.0
|
|
147
|
+
Optimist.die :shear_plane, "must be on, off, or a colour" unless /\A(on|off)\z/ =~ opts[:shear_plane] || RSyntaxTree::COLOR_NAMES.include?(opts[:shear_plane].downcase) || /\A#(\h{3}|\h{6})\z/ =~ opts[:shear_plane]
|
|
143
148
|
Optimist.die :color, "must be either modern, traditional, gray, or off" unless OPTION_VALUES[:color].include?(opts[:color])
|
|
144
|
-
Optimist.die :symmetrize, "must be either on or off" unless /\A(on|off|true|false)\z/ =~ opts[:symmetrize]
|
|
145
149
|
Optimist.die :vheight, "must be in the range of 0.5-5.0" if opts[:vheight] < 0.5 || opts[:vheight] > 5.0
|
|
146
150
|
Optimist.die :transparent, "must be either on or off" unless /\A(on|off|true|false)\z/ =~ opts[:transparent]
|
|
147
151
|
Optimist.die :polyline, "must be either on or off" unless /\A(on|off|true|false)\z/ =~ opts[:polyline]
|
|
@@ -149,7 +153,6 @@ Optimist.die :hide_default_connectors, "must be either on or off" unless /\A(on|
|
|
|
149
153
|
Optimist.die :mirror, "must be either on or off" unless /\A(on|off|true|false)\z/ =~ opts[:mirror]
|
|
150
154
|
Optimist.die :tidy, "must be off, symmetric, low, medium, or high" unless OPTION_VALUES[:tidy].include?(opts[:tidy])
|
|
151
155
|
Optimist.die :hspacing, "must be in the range of 0.5-3.0" if opts[:hspacing] < 0.5 || opts[:hspacing] > 3.0
|
|
152
|
-
Optimist.die :tidy_spacing, "must be in the range of 0.5-3.0" if opts[:tidy_spacing] < 0.5 || opts[:tidy_spacing] > 3.0
|
|
153
156
|
|
|
154
157
|
# Merge config file options with CLI options (CLI takes precedence)
|
|
155
158
|
string_opts = {}
|
|
@@ -170,10 +173,6 @@ opts.each do |key, value|
|
|
|
170
173
|
end
|
|
171
174
|
end
|
|
172
175
|
|
|
173
|
-
if %w[jpg gif].include?(string_opts[:format])
|
|
174
|
-
warn "Warning: #{string_opts[:format].upcase} output is deprecated and will be removed in RSyntaxTree 2.0. Use PNG instead."
|
|
175
|
-
end
|
|
176
|
-
|
|
177
176
|
# These print and exit, so they answer before the input is read. Reading
|
|
178
177
|
# first meant waiting on a pipe that never closes when stdin is not a
|
|
179
178
|
# terminal, which is how they are reached from a script.
|
|
@@ -14,7 +14,6 @@ module RSyntaxTree
|
|
|
14
14
|
def initialize(element_list, params, global)
|
|
15
15
|
@global = global
|
|
16
16
|
@element_list = element_list
|
|
17
|
-
@symmetrize = params[:symmetrize] == true
|
|
18
17
|
@direction = params[:direction] || "ttb"
|
|
19
18
|
|
|
20
19
|
case params[:color]
|
|
@@ -72,13 +71,10 @@ module RSyntaxTree
|
|
|
72
71
|
# "off" | "low" (packing, strict leaf positions) | "medium" (packing
|
|
73
72
|
# with cross-row tucking as long as no two leaves swap left-right
|
|
74
73
|
# order) | "high" (free tucking; leaf order kept per row only).
|
|
75
|
-
#
|
|
76
|
-
#
|
|
77
|
-
#
|
|
78
|
-
# meaningless, so packing wins over a legacy symmetrize flag.
|
|
74
|
+
# One scale, and nothing beside it: the standalone symmetrize and
|
|
75
|
+
# tidy_nest flags that used to lift a mode into another were removed
|
|
76
|
+
# in 2.0, so what is asked for is what is drawn.
|
|
79
77
|
tidy_mode = params[:tidy].to_s
|
|
80
|
-
tidy_mode = "high" if tidy_mode == "low" && params[:tidy_nest] == true
|
|
81
|
-
tidy_mode = "symmetric" if tidy_mode == "off" && @symmetrize
|
|
82
78
|
@tidy = %w[low medium high].include?(tidy_mode)
|
|
83
79
|
# :none — leaf spans may not overlap at all (strict positions)
|
|
84
80
|
# :ordered — spans may overlap, but leaf centers keep their order
|
|
@@ -966,7 +962,13 @@ module RSyntaxTree
|
|
|
966
962
|
# is disproportionately large relative to the swapped content dimensions.
|
|
967
963
|
# Use height_connector_to_text / 2 (= font_height / 4) for tight
|
|
968
964
|
# vertical packing proportional to the font size.
|
|
969
|
-
|
|
965
|
+
#
|
|
966
|
+
# Scaled by hspacing, like the gap it replaces. Without it the two
|
|
967
|
+
# spacing options both pushed the width in this direction — hspacing
|
|
968
|
+
# only through the margins it is left in — and nothing at all decided
|
|
969
|
+
# how far apart siblings sat, so a left-to-right tree could be made
|
|
970
|
+
# wider but never shorter.
|
|
971
|
+
@global[:h_gap_between_nodes] = @global[:height_connector_to_text] / 2 * @global[:hspacing]
|
|
970
972
|
|
|
971
973
|
# In LTR, height_connector becomes horizontal depth between levels.
|
|
972
974
|
# After content swap, content_height = original content_width (small),
|
|
@@ -1090,7 +1092,14 @@ module RSyntaxTree
|
|
|
1090
1092
|
max_x = @rule_name_edge if @rule_name_edge.to_f > max_x
|
|
1091
1093
|
width = max_x + @global[:h_gap_between_nodes]
|
|
1092
1094
|
height = max_y
|
|
1095
|
+
# A movement path routes outside the tree — below it top-to-bottom,
|
|
1096
|
+
# beyond it to the right left-to-right — and grows @height or @width as
|
|
1097
|
+
# it goes. The height has always been read back here; the width was
|
|
1098
|
+
# computed from the elements alone and then overwrote what the path had
|
|
1099
|
+
# grown, so a left-to-right path could reach past the canvas and be cut
|
|
1100
|
+
# off at its edge.
|
|
1093
1101
|
height = @height if @height > height
|
|
1102
|
+
width = @width if @width > width
|
|
1094
1103
|
{ height: height, width: width }
|
|
1095
1104
|
end
|
|
1096
1105
|
end
|
data/lib/rsyntaxtree/element.rb
CHANGED
|
@@ -13,7 +13,7 @@ require_relative "color_names"
|
|
|
13
13
|
|
|
14
14
|
module RSyntaxTree
|
|
15
15
|
class Element
|
|
16
|
-
attr_accessor :rule_name, :label_with_rule_name, :id, :parent, :type, :level, :width, :height, :content, :content_width, :text_width, :content_height, :horizontal_indent, :vertical_indent, :triangle, :enclosure, :children, :font, :fontsize, :contains_phrase, :path, :color, :raw_content, :region, :region_color
|
|
16
|
+
attr_accessor :ink_top, :ink_bottom, :rule_name, :label_with_rule_name, :id, :parent, :type, :level, :width, :height, :content, :content_width, :text_width, :content_height, :horizontal_indent, :vertical_indent, :triangle, :enclosure, :children, :font, :fontsize, :contains_phrase, :path, :color, :raw_content, :region, :region_color
|
|
17
17
|
|
|
18
18
|
# names_a_rule says the content is a mother's label rather than a leaf's
|
|
19
19
|
# text. Only a mother has a step under it for a name to sit beside, and a
|
|
@@ -309,6 +309,10 @@ module RSyntaxTree
|
|
|
309
309
|
row_holds_text = content[:elements].any? do |e|
|
|
310
310
|
(e[:decoration] & [:box, :circle, :bar]).empty? && !e[:text].to_s.strip.empty?
|
|
311
311
|
end
|
|
312
|
+
# True until something is drawn in the current column. A tabstop
|
|
313
|
+
# opens the next one, so a block that starts a column is at the
|
|
314
|
+
# start of a cell however many columns came before it.
|
|
315
|
+
cell_start = true
|
|
312
316
|
content[:elements].each do |e|
|
|
313
317
|
# A nested matrix is measured by the same code one level down, and
|
|
314
318
|
# reports the size of the block it will occupy in this row: its own
|
|
@@ -317,7 +321,18 @@ module RSyntaxTree
|
|
|
317
321
|
inner = measure_lines(e[:matrix], nested: true)
|
|
318
322
|
e[:matrix_width] = inner[:width]
|
|
319
323
|
e[:matrix_height] = inner[:height]
|
|
320
|
-
|
|
324
|
+
# A block that opens a cell needs nothing in front of it: the
|
|
325
|
+
# column it starts is already held clear. One that follows
|
|
326
|
+
# something in the same cell — the tag on a shared value, as in
|
|
327
|
+
# AGR |1| [ ... ] — was drawn with its bracket on the ink before
|
|
328
|
+
# it, because a run is spaced for the glyph that comes next and
|
|
329
|
+
# a bracket is not a glyph.
|
|
330
|
+
# As much room in front of the bracket as the bracket keeps
|
|
331
|
+
# inside it, so the two sides of it look alike. Half as much
|
|
332
|
+
# left it looking crowded from the outside.
|
|
333
|
+
e[:matrix_lead] = cell_start ? 0 : matrix_bracket_room
|
|
334
|
+
cell_start = false
|
|
335
|
+
e[:width] = inner[:width] + matrix_bracket_room * 2 + e[:matrix_lead]
|
|
321
336
|
# Two separate allowances. The block is padded inside its own
|
|
322
337
|
# brackets, above and below, and that padding is part of the row.
|
|
323
338
|
# The gap that keeps the block clear of the rows either side is
|
|
@@ -335,6 +350,14 @@ module RSyntaxTree
|
|
|
335
350
|
next
|
|
336
351
|
end
|
|
337
352
|
|
|
353
|
+
# A tabstop opens the next column; anything else puts ink in the
|
|
354
|
+
# one being filled.
|
|
355
|
+
if e[:decoration].to_a.include?(:tabstop)
|
|
356
|
+
cell_start = true
|
|
357
|
+
elsif !e[:text].to_s.empty?
|
|
358
|
+
cell_start = false
|
|
359
|
+
end
|
|
360
|
+
|
|
338
361
|
text = e[:text]
|
|
339
362
|
# Handle escaped square brackets
|
|
340
363
|
text = text.gsub('\\[', '[')
|
|
@@ -291,12 +291,18 @@ module RSyntaxTree
|
|
|
291
291
|
connector_height: @params[:vheight],
|
|
292
292
|
horizontal_spacing: @params[:hspacing] || 1.0,
|
|
293
293
|
line_width: @params[:linewidth],
|
|
294
|
-
# The layout scale the figure was drawn on.
|
|
295
|
-
#
|
|
294
|
+
# The layout scale the figure was drawn on. Files written
|
|
295
|
+
# before 2.0 carry a separate symmetrize flag beside it; the
|
|
296
|
+
# scale is what it meant, and it is all that is written now.
|
|
296
297
|
tidy: @params[:tidy] || "off",
|
|
297
|
-
symmetrize: @params[:symmetrize],
|
|
298
298
|
mirror: @params[:mirror] == true,
|
|
299
299
|
direction: @params[:direction] || "ttb",
|
|
300
|
+
# Degrees, positive leaning the top right. The geometry below
|
|
301
|
+
# is the unsheared layout — the shear is applied at render — so
|
|
302
|
+
# a reader who wants the drawn look applies it, and one who
|
|
303
|
+
# wants the layout ignores it.
|
|
304
|
+
shear: (@params[:shear] || 0).to_f,
|
|
305
|
+
vmargin: (@params[:vmargin] || 0.4).to_f,
|
|
300
306
|
# Which of the two readings of a hyphen the input was parsed
|
|
301
307
|
# under. The input is recorded verbatim above, and the same
|
|
302
308
|
# string means different things under the two, so a reader
|
|
@@ -5,8 +5,13 @@ require 'parslet'
|
|
|
5
5
|
class MarkupParser < Parslet::Parser
|
|
6
6
|
rule(:cr) { str('\\n') }
|
|
7
7
|
rule(:eof) { any.absent? }
|
|
8
|
-
rule(:border) {
|
|
9
|
-
rule(:bborder) {
|
|
8
|
+
rule(:border) { rule_line >> (eof | cr) }
|
|
9
|
+
rule(:bborder) { double_rule_line >> (eof | cr) }
|
|
10
|
+
# The rule itself, without what ends the line. A matrix ends its rows on
|
|
11
|
+
# its own closing delimiter as well as on a line break, so it supplies its
|
|
12
|
+
# own terminator; folding one in here would have the two consume it twice.
|
|
13
|
+
rule(:rule_line) { match('[^\-]').absent? >> str('-').repeat(3).as(:border) }
|
|
14
|
+
rule(:double_rule_line) { match('[^=]').absent? >> str('=').repeat(3).as(:bborder) }
|
|
10
15
|
|
|
11
16
|
rule(:brectangle) { str('###') }
|
|
12
17
|
rule(:rectangle) { str('##') }
|
|
@@ -79,7 +84,7 @@ class MarkupParser < Parslet::Parser
|
|
|
79
84
|
# bare brackets would be read as tree structure and bare parentheses appear
|
|
80
85
|
# in labels too often to claim.
|
|
81
86
|
rule(:matrix) { str('#(') >> matrix_line.repeat(1).as(:matrix) >> str('#)') }
|
|
82
|
-
rule(:matrix_line) { matrix_markup.repeat(1).as(:line) >> (cr | str('#)').present?) }
|
|
87
|
+
rule(:matrix_line) { (rule_line | double_rule_line | matrix_markup.repeat(1).as(:line)) >> (cr | str('#)').present?) }
|
|
83
88
|
rule(:matrix_markup) { (matrix | tabstop | matrix_text | decoration | shape | bstroke) }
|
|
84
89
|
# Text inside a matrix stops at the closing delimiter as well.
|
|
85
90
|
rule(:matrix_text) { (escaped | (str('#)').absent? >> non_escaped)).repeat(1).as(:text) }
|
|
@@ -13,7 +13,10 @@ figure that was meant.
|
|
|
13
13
|
- `<>` is one space and `<3>` is three, everywhere — never angle brackets.
|
|
14
14
|
Where linguistics wants the brackets themselves, write ⟨ and ⟩ (U+27E8/9):
|
|
15
15
|
SPR\t⟨<>NP<>⟩, 'hand⟨SUBJ,OBJ⟩'. A label written <NP> is refused with this
|
|
16
|
-
advice; a stray <3> simply draws three spaces.
|
|
16
|
+
advice; a stray <3> simply draws three spaces. No text face carries these
|
|
17
|
+
two characters, so whatever the machine falls back to draws them — they
|
|
18
|
+
will not quite match the letters beside them, and how far off they look
|
|
19
|
+
depends on the fonts installed.
|
|
17
20
|
- A pair of hyphens underlines what stands between them: well-made-word draws
|
|
18
21
|
"made" underlined. (A lone hyphen is refused with a hint.) Write `\-` for a
|
|
19
22
|
hyphen — V\-bar, HEAD\-DTR — or set the hyphen option to literal.
|
|
@@ -84,7 +87,7 @@ Options (the command line spells them --like-this):
|
|
|
84
87
|
|
|
85
88
|
| option | what it decides |
|
|
86
89
|
|------------|-----------------|
|
|
87
|
-
| format | png, svg, pdf,
|
|
90
|
+
| format | png, svg, pdf, tikz, lsif |
|
|
88
91
|
| fontstyle | sans, serif, mono, cjk |
|
|
89
92
|
| fontsize | 6–26 |
|
|
90
93
|
| color | modern, traditional, off, gray |
|
|
@@ -93,10 +96,20 @@ Options (the command line spells them --like-this):
|
|
|
93
96
|
| direction | ttb, ltr, btt |
|
|
94
97
|
| mirror | flip the finished layout, for RTL scripts |
|
|
95
98
|
| tidy | off, symmetric, low, medium, high — how tightly subtrees pack |
|
|
96
|
-
| hspacing |
|
|
97
|
-
| vheight |
|
|
99
|
+
| hspacing | how far apart sisters sit, 0.5–3.0 |
|
|
100
|
+
| vheight | how far apart levels sit, 0.5–5.0 |
|
|
101
|
+
| polyline | draw each connector as two right angles rather than a slanted line |
|
|
102
|
+
| hide_default_connectors | draw no parent-to-child lines, leaving only the ones written with +-n — how a lattice or a network is drawn |
|
|
103
|
+
| transparent | leave the background clear instead of painting it white |
|
|
98
104
|
| derivation | one rule across the daughters, categorial-grammar style |
|
|
99
105
|
| hyphen | markup (hyphens underline) or literal (hyphens are hyphens) |
|
|
106
|
+
| shear | tilt the drawn figure: degrees, −45 to 45, positive leans the top right |
|
|
107
|
+
| shear_plane | the plane behind a sheared figure: on (grey), off, or a colour; never drawn on a transparent background |
|
|
108
|
+
| vmargin | clearance between a label and its connectors, 0.1–1.0, the same above and below |
|
|
109
|
+
|
|
110
|
+
hspacing and vheight are named for the top-to-bottom layout, and follow the
|
|
111
|
+
tree rather than the page: with direction ltr, sisters stack downwards and
|
|
112
|
+
hspacing is what separates them, while vheight runs across.
|
|
100
113
|
|
|
101
114
|
The full manual explains each of these with figures, and every example in the
|
|
102
115
|
gallery is written out beside the figure it draws:
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
RSyntaxTree examples:
|
|
1
|
+
RSyntaxTree examples: 80 trees, every one verified to draw.
|
|
2
2
|
|
|
3
3
|
Each is the input behind a figure in the gallery at https://yohasebe.github.io/rsyntaxtree/examples.
|
|
4
4
|
The settings line names the options the gallery records for that figure;
|
|
@@ -8,10 +8,10 @@ here through the same parser that draws it, so each one is accepted.
|
|
|
8
8
|
Notation reference: rsyntaxtree --notation
|
|
9
9
|
Check an input without drawing: rsyntaxtree --validate "[S [NP a] [VP b]]"
|
|
10
10
|
|
|
11
|
-
What the option names on a settings line mean
|
|
12
|
-
the reference
|
|
13
|
-
|
|
14
|
-
|
|
11
|
+
What the option names on a settings line mean: one line each at the end
|
|
12
|
+
of the reference (`rsyntaxtree --notation`), the full story in the manual
|
|
13
|
+
at https://yohasebe.github.io/rsyntaxtree/documentation. Everything at once, this file and the manual
|
|
14
|
+
together: https://yohasebe.github.io/rsyntaxtree/llms-full.txt
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
## 000 — RSyntaxTree basic example
|
|
@@ -2521,3 +2521,95 @@ Source: Steedman 2000
|
|
|
2521
2521
|
[(S\\NP)/NP hates]]]
|
|
2522
2522
|
[NP London]]
|
|
2523
2523
|
```
|
|
2524
|
+
|
|
2525
|
+
## 082 — Indo-European language family
|
|
2526
|
+
|
|
2527
|
+
Category: Historical Linguistics
|
|
2528
|
+
Settings: direction=ltr fontstyle=noto-serif hspacing=0.5 polyline=on vheight=5.0
|
|
2529
|
+
|
|
2530
|
+
```
|
|
2531
|
+
[Proto\-Indo\-European
|
|
2532
|
+
[%@#4a7c59:Italic
|
|
2533
|
+
[Latin
|
|
2534
|
+
[Western [*Spanish*] [*Portuguese*] [*French*]]
|
|
2535
|
+
[Eastern [*Italian*] [*Romanian*]]]]
|
|
2536
|
+
[%@#3d6b9e:Germanic
|
|
2537
|
+
[West [*English*] [*German*] [*Dutch*]]
|
|
2538
|
+
[North [*Swedish*] [*Icelandic*]]]
|
|
2539
|
+
[%@#b5651d:Balto\-Slavic
|
|
2540
|
+
[Slavic [*Russian*] [*Polish*] [*Czech*]]
|
|
2541
|
+
[Baltic [*Lithuanian*] [*Latvian*]]]
|
|
2542
|
+
[%@#8e4585:Indo\-Iranian
|
|
2543
|
+
[Indo\-Aryan [*Hindi*] [*Bengali*]]
|
|
2544
|
+
[Iranian [*Persian*] [*Pashto*]]]
|
|
2545
|
+
[%@#7a6a9b:Hellenic [Ancient<>Greek [*Greek*]]]
|
|
2546
|
+
[%@#2f7d7d:Celtic [*Irish*] [*Welsh*]]]
|
|
2547
|
+
```
|
|
2548
|
+
|
|
2549
|
+
## 083 — Type-driven semantic composition
|
|
2550
|
+
|
|
2551
|
+
Category: Formal Semantics
|
|
2552
|
+
Settings: color=none fontstyle=noto-serif leafstyle=nothing
|
|
2553
|
+
|
|
2554
|
+
```
|
|
2555
|
+
[S\n*t*\n**love**(**m**)(**j**)
|
|
2556
|
+
[DP\n*e*\n**j** [*John*]]
|
|
2557
|
+
[VP\n⟨*e*,*t*⟩\nλ*x*.**love**(**m**)(*x*)
|
|
2558
|
+
[V\n⟨*e*,⟨*e*,*t*⟩⟩\nλ*y*λ*x*.**love**(*y*)(*x*) [*loves*]]
|
|
2559
|
+
[DP\n*e*\n**m** [*Mary*]]]]
|
|
2560
|
+
```
|
|
2561
|
+
|
|
2562
|
+
## 084 — Typed feature structures with structure sharing
|
|
2563
|
+
|
|
2564
|
+
Category: Formal Grammar
|
|
2565
|
+
Settings: color=none fontstyle=noto-serif leafstyle=nothing
|
|
2566
|
+
|
|
2567
|
+
```
|
|
2568
|
+
[#(*phrase*\
|
|
2569
|
+
---\
|
|
2570
|
+
SYN\t#(HEAD\t|1|\
|
|
2571
|
+
VAL\t#(SPR\t⟨<>⟩#)#)#)
|
|
2572
|
+
[#(*phrase*\
|
|
2573
|
+
---\
|
|
2574
|
+
SYN\t#(HEAD\t#(*noun*\
|
|
2575
|
+
---\
|
|
2576
|
+
AGR\t|2|#(*3sing*\
|
|
2577
|
+
---\
|
|
2578
|
+
PER\t3\
|
|
2579
|
+
NUM\t*sg*#)#)\
|
|
2580
|
+
VAL\t#(SPR\t⟨<>⟩#)#)#) [the<>dog]]
|
|
2581
|
+
[#(*word*\
|
|
2582
|
+
---\
|
|
2583
|
+
SYN\t#(HEAD\t|1|#(*verb*\
|
|
2584
|
+
---\
|
|
2585
|
+
AGR\t|2|#)\
|
|
2586
|
+
VAL\t#(SPR\t⟨<>*NP*<>⟩#)#)#) [barks]]]
|
|
2587
|
+
```
|
|
2588
|
+
|
|
2589
|
+
## 085 — A tree on a tilted plane
|
|
2590
|
+
|
|
2591
|
+
Category: General
|
|
2592
|
+
Settings: fontstyle=noto-serif shear=20 vheight=1.0
|
|
2593
|
+
|
|
2594
|
+
```
|
|
2595
|
+
[S
|
|
2596
|
+
[NP
|
|
2597
|
+
[D the]
|
|
2598
|
+
[N man]
|
|
2599
|
+
]
|
|
2600
|
+
[VP
|
|
2601
|
+
[V put]
|
|
2602
|
+
[NP
|
|
2603
|
+
[D the]
|
|
2604
|
+
[N book]
|
|
2605
|
+
]
|
|
2606
|
+
[PP
|
|
2607
|
+
[P on]
|
|
2608
|
+
[NP
|
|
2609
|
+
[D the]
|
|
2610
|
+
[N table]
|
|
2611
|
+
]
|
|
2612
|
+
]
|
|
2613
|
+
]
|
|
2614
|
+
]
|
|
2615
|
+
```
|