rsyntaxtree 1.13.2 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: aa35ea4c535165dcf70b1a1b6375ff32666ce42294219a9b3d59ba6cb614ee85
4
- data.tar.gz: 23d80a1781dd85a41d349b670b7610981bba30a87fa90cd0847d91dc65356fe4
3
+ metadata.gz: 9ccd433053f296c9189c9eceb87f61c91ed815ff6b1be77f1cd2115a73eaf1cd
4
+ data.tar.gz: f769d68efb73c1aafc9dc9af9f0e4e7cbd7a0c741caf253905ebe11dc3c454be
5
5
  SHA512:
6
- metadata.gz: baa9e98752ce86da774ededc1228b6f588e69da5b381bc94112190f7198f8a2128d64760cc49114b9e3a8815d24e0984714cf562ebdb0e86572dc4c3790e0bab
7
- data.tar.gz: ada76c5d30433a0652be01242c8da0225f63e84c3717accb0eeb3628567df9744b67c408405acc94e52dbd38288fe5352f3ceb2c789b41974184dd2443322f6b
6
+ metadata.gz: 0e6218bc0ddf1f4c49e8fac2c8972cbd3e0eb251fe7087150ea73f63b054fe546483588e582a0f01e52ab26c20fd883ab2c67da07adf1f3120755447a7956945
7
+ data.tar.gz: b0810c0df9ede2cd1c36100ae9a3c055ece2d59261f8278ef8de8b79e07921702c7b8db83fa43f81810184c363b860bae3d9a9c1f45b4a02307f5f8220354fa8
data/CHANGELOG.md CHANGED
@@ -1,6 +1,166 @@
1
1
  # Changelog
2
2
 
3
- ## [1.13.2] - 2026-08
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
+
117
+ ## [1.14.0] - 2026-08-27
118
+
119
+ ### Added
120
+ - The notation has a map. The reference the gem ships (`--notation`) is one
121
+ page: the characters that already mean something, then every feature at a
122
+ line each with the notation beside it, then the options. Both manuals open
123
+ with the same list, each row pointing at the section that explains it. A test
124
+ reads the feature set out of the grammar itself and draws every sample, so a
125
+ feature the grammar gains with no row in the documents fails the build, and a
126
+ sample that stops meaning what it says fails with it.
127
+ - The changelog is on the documentation site, at /changelog, built from
128
+ CHANGELOG.md and linked from the manuals and the README.
129
+
130
+ ### Changed
131
+ - Every release in the changelog is dated to the day, from the git tags. Two of
132
+ the old month-only dates were wrong.
133
+ - What the trap section warns about is now, by definition, what the tool
134
+ accepts and draws as something other than what was meant. A mistake the tool
135
+ refuses is the error message's job, and its card has come down; the warning
136
+ about parentheses, which the Penn Treebank conversion had made false, tells
137
+ the truth again.
138
+ - The arrow markers' dimensions are rounded; the defs of every SVG carried
139
+ float dust in an attribute.
140
+
141
+ ### Fixed
142
+ - Turning `derivation` on no longer deletes a column from a node that has no
143
+ daughters. A rule name is written after a column break and names the step
144
+ that produced a node from its daughters, so a node with none names no rule —
145
+ but the label is read before the tree is built, and the name was taken out
146
+ anyway and then had no rule to be drawn beside. `[A\tfoo]` drew "A foo" with
147
+ the option off and "A" with it on. The label is put back once the tree is
148
+ known.
149
+ - A mistake inside a node's label keeps the name of what is wrong with it. The
150
+ first raw space splits a token into a label and its children, and when the
151
+ label would not parse, every cause but one was relabelled "a raw space split
152
+ this" — so the message named an unknown colour while the code and the hint
153
+ talked about spaces, and a caller acting on the code was sent to fix what was
154
+ not wrong. Which story is right is now asked of the parser rather than
155
+ guessed: the token is put back together with its spaces written as the
156
+ notation writes them, and if it reads, the space was the cause.
157
+ - A hex colour is three digits or six, which is what every message about colour
158
+ here already said. The grammar asked for three to six, so four and five
159
+ parsed, passed the validator — which does not look at a value beginning with
160
+ `#` — and reached librsvg, which cannot read them and draws the label black
161
+ without reporting it.
162
+
163
+ ## [1.13.2] - 2026-08-27
4
164
 
5
165
  ### Fixed
6
166
  - A movement path is drawn as one stroke with its corners eased, in place of
@@ -25,7 +185,7 @@
25
185
  the gallery is unchanged to the pixel — every raster figure is byte-identical
26
186
  and the SVGs differ only in the family list they carry.
27
187
 
28
- ## [1.13.1] - 2026-08
188
+ ## [1.13.1] - 2026-08-27
29
189
 
30
190
  ### Fixed
31
191
  - `^` at the head of a leaf draws the triangle it asks for. The mark may be
@@ -44,7 +204,7 @@
44
204
  every input, because the form still read a `format` select the page no longer
45
205
  had. A value that is actually wrong is still rejected.
46
206
 
47
- ## [1.13.0] - 2026-08
207
+ ## [1.13.0] - 2026-08-24
48
208
 
49
209
  ### Added
50
210
  - Derivations. A derivation puts the words first and the result last, and
@@ -63,7 +223,7 @@
63
223
  have when the root is at the top, so every line ran from above the daughter,
64
224
  through its label and the mother's, to below the mother.
65
225
 
66
- ## [1.12.0] - 2026-08
226
+ ## [1.12.0] - 2026-08-22
67
227
 
68
228
  Everything needed to write this notation is now available as text, built from
69
229
  the files the tool itself reads, and a refusal says where that text is.
@@ -93,7 +253,7 @@ the files the tool itself reads, and a refusal says where that text is.
93
253
  meant waiting on a pipe that never closes when stdin is not a terminal,
94
254
  which is how a script reaches them.
95
255
 
96
- ## [1.11.0] - 2026-08
256
+ ## [1.11.0] - 2026-08-21
97
257
 
98
258
  Every input the tool accepts now draws, and every input it refuses says why.
99
259
  Line thickness follows the type size, so figures drawn at any font size keep
@@ -152,7 +312,7 @@ fifth lighter than before.
152
312
  read as a path to the current directory.
153
313
  - Overline was documented as missing from PNG output. It has been there.
154
314
 
155
- ## [1.10.0] - 2026-08
315
+ ## [1.10.0] - 2026-08-19
156
316
 
157
317
  A transitional release ahead of 2.0, which drops JPG/GIF output and the
158
318
  RMagick dependency.
@@ -175,7 +335,7 @@ RMagick dependency.
175
335
  file here carries `frozen_string_literal`, which made the working form the
176
336
  unobvious one.
177
337
 
178
- ## [1.9.0] - 2026-08
338
+ ## [1.9.0] - 2026-08-19
179
339
 
180
340
  ### Added
181
341
  - `hyphen: literal`, which trades the two readings of a hyphen: a bare one is
@@ -243,7 +403,7 @@ RMagick dependency.
243
403
  the arrow was drawn small to fit; now the pair is spread and the arrow keeps
244
404
  its size. Only pairs that carry a link move, and only when they need to.
245
405
 
246
- ## [1.8.2] - 2026-08
406
+ ## [1.8.2] - 2026-08-17
247
407
 
248
408
  ### Changed
249
409
  - `tidy: high` now compresses as far as its name promises. The level-balance
@@ -271,7 +431,7 @@ RMagick dependency.
271
431
  resolved nowhere on macOS, Debian/Ubuntu or Alpine; the chain fell through
272
432
  to `Noto Sans Mono`, which it now names directly.
273
433
 
274
- ## [1.8.1] - 2026-08
434
+ ## [1.8.1] - 2026-08-15
275
435
 
276
436
  ### Fixed
277
437
  - Arabic rendered as isolated, unjoined letterforms in some environments.
@@ -300,7 +460,7 @@ RMagick dependency.
300
460
  - Documentation records how to override any of the named families with a
301
461
  fontconfig alias, for users who prefer their own script fonts.
302
462
 
303
- ## [1.8.0] - 2026-08
463
+ ## [1.8.0] - 2026-08-15
304
464
 
305
465
  ### Added
306
466
  - `tidy` layout scale, one option covering every layout mode from the most
@@ -349,7 +509,7 @@ RMagick dependency.
349
509
  when the caller passes only a partial parameter set (e.g. `tidy: off`
350
510
  rendered as `symmetric` in the web UI).
351
511
 
352
- ## [1.7.0] - 2026-08
512
+ ## [1.7.0] - 2026-08-13
353
513
 
354
514
  ### Changed
355
515
  - Text measurement now uses Pango, the same engine (and the same fontconfig
@@ -369,7 +529,7 @@ RMagick dependency.
369
529
  - Runtime dependency on the `pango` gem (ruby-gnome). No new system
370
530
  requirements: librsvg already depends on Pango.
371
531
 
372
- ## [1.6.3] - 2026-07
532
+ ## [1.6.3] - 2026-07-19
373
533
 
374
534
  ### Fixed
375
535
  - Packaged files no longer carry owner-only permissions. `gem build` preserves
@@ -381,14 +541,14 @@ RMagick dependency.
381
541
  tree had picked up on data files (images, fonts, Markdown, CSS, library
382
542
  sources).
383
543
 
384
- ## [1.6.2] - 2026-06
544
+ ## [1.6.2] - 2026-06-26
385
545
 
386
546
  ### Fixed
387
547
  - Region shade no longer touches the image edge when its padded bounds reach
388
548
  past the tree's natural extent (e.g. a deep enclosed/multi-line node): the
389
549
  canvas now grows with a margin around the shaded plane.
390
550
 
391
- ## [1.6.1] - 2026-06
551
+ ## [1.6.1] - 2026-06-26
392
552
 
393
553
  ### Improved
394
554
  - Region shade rendering wraps the subtree more cleanly: wider, balanced
@@ -402,7 +562,7 @@ RMagick dependency.
402
562
  - Example 065: nested (overlapping) region shades, shown as progressively
403
563
  darker gray.
404
564
 
405
- ## [1.6.0] - 2026-06
565
+ ## [1.6.0] - 2026-06-25
406
566
 
407
567
  ### Added
408
568
  - Region shade (`%` prefix): paints a semi-transparent plane behind the whole
@@ -430,7 +590,7 @@ RMagick dependency.
430
590
  - Region shade on the root/topmost node no longer clipped by the canvas: the
431
591
  SVG viewBox now grows to include region planes that extend past the tree.
432
592
 
433
- ## [1.5.0] - 2026-04
593
+ ## [1.5.0] - 2026-04-06
434
594
 
435
595
  ### Added
436
596
  - Left-to-right tree layout (`-d ltr` / `--direction ltr`)
@@ -445,7 +605,7 @@ RMagick dependency.
445
605
  ### Improved
446
606
  - TTB path bulge proportional to endpoint distance (reduced excess)
447
607
 
448
- ## [1.4.0] - 2026-01
608
+ ## [1.4.0] - 2026-01-06
449
609
 
450
610
  ### Added
451
611
  - LSIF (Linguistic Structure Interchange Format) JSON output (`-f lsif`)
@@ -461,18 +621,46 @@ RMagick dependency.
461
621
  - Added examples for per-node coloring (054, 055, 056)
462
622
  - Added example 057: Subscript and superscript demo
463
623
 
464
- ## [1.3.2] - 2024
624
+ ## [1.3.2] - 2025-03-03
465
625
 
466
626
  - Garbage collection friendly implementation
467
627
 
468
- ## [1.3.1] - 2024
628
+ ## [1.3.1] - 2024-10-24
469
629
 
630
+ - Square brackets can be escaped with `\[` and `\]`
470
631
  - Bug fixes and improvements
471
632
 
472
- ## [1.3.0] - 2024
633
+ ## [1.3.0] - 2024-08-27
473
634
 
474
635
  - TikZ/forest LaTeX output support
475
636
 
476
- ## Previous versions
477
-
478
- See commit history for earlier changes.
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. (JPG and GIF are deprecated and will be removed in 2.0.)
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 (jpg and gif are deprecated) | `png` |
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
- | `-d, --direction` | Tree layout direction: ttb, ltr | `ttb` |
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` | Horizontal spacing factor, all layout modes (0.5-3.0) | `1.0` |
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
 
@@ -206,6 +213,51 @@ fontsize: 18
206
213
 
207
214
  CLI options override config file settings.
208
215
 
216
+ ## Using RSyntaxTree with an AI Model
217
+
218
+ The notation is small, but several characters in it already mean something, so
219
+ a model writing it does better with the reference in front of it than without.
220
+
221
+ **If the model only writes the notation** and you draw it yourself — in the
222
+ [web interface](https://yohasebe.com/rsyntaxtree) or on your own machine —
223
+ nothing needs installing. Give the model one of these to read:
224
+
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.
228
+ - [Everything in one file](https://yohasebe.github.io/rsyntaxtree/llms-full.txt):
229
+ the reference, the manual and all the gallery examples, about 85 KB.
230
+
231
+ **If the model can run a shell**, it can draw and then look at what it drew,
232
+ which is the part that lets it correct itself:
233
+
234
+ ```bash
235
+ docker run --rm -v "$PWD:/work" -w /work ghcr.io/yohasebe/rsyntaxtree \
236
+ rsyntaxtree --notation # the reference, on stdout
237
+ docker run --rm -v "$PWD:/work" -w /work ghcr.io/yohasebe/rsyntaxtree \
238
+ rsyntaxtree -f png -o . "[S [NP a tree] [VP appears]]"
239
+ ```
240
+
241
+ Then read `syntree.png` back. `--examples` prints every gallery example with
242
+ the settings it was drawn at, and `--validate` reports what is wrong with an
243
+ input as JSON — including whether rewriting it is worth trying — without
244
+ drawing anything:
245
+
246
+ ```json
247
+ { "schema": "rsyntaxtree.error/1", "ok": false,
248
+ "errors": [ { "code": "unbalanced_brackets",
249
+ "message": "Error: open and close brackets do not match",
250
+ "hint": "Count the brackets: every '[' needs one ']'.",
251
+ "retryable": true } ],
252
+ "reference": "rsyntaxtree --notation, or https://yohasebe.github.io/rsyntaxtree/llms-full.txt" }
253
+ ```
254
+
255
+ The exit code carries the verdict too, so a script can branch on it without
256
+ reading the JSON. The Docker image is used above because this tool draws
257
+ through Pango and librsvg, and a figure depends on which versions of those —
258
+ and which fonts — are installed; the image fixes all of them. Installed as a
259
+ gem it works the same, once those libraries are on the machine.
260
+
209
261
  ## Documentation
210
262
 
211
263
  For detailed documentation on syntax and markup:
@@ -213,6 +265,7 @@ For detailed documentation on syntax and markup:
213
265
  - [Documentation in English](https://yohasebe.github.io/rsyntaxtree/documentation)
214
266
  - [日本語ドキュメント](https://yohasebe.github.io/rsyntaxtree/documentation_ja)
215
267
  - [Example Gallery](https://yohasebe.github.io/rsyntaxtree/examples)
268
+ - [Changelog](https://yohasebe.github.io/rsyntaxtree/changelog)
216
269
 
217
270
  ## How to Cite
218
271
 
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, jpg, gif, pdf, svg, lsif, or tikz" — built once from the library's
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
- # Legacy inputs upgrade into the scale: tidy_nest: on lifts "low" to
76
- # "high", and the old standalone symmetrize: on lifts "off" to
77
- # "symmetric". When tidy packing is active the symmetric layout is
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
- @global[:h_gap_between_nodes] = @global[:height_connector_to_text] / 2
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