rsyntaxtree 1.6.0 → 1.6.1

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: b1ba1c70fd18704ea011d4edb62af9cb18b0109852731faf08a0f8a24360acab
4
- data.tar.gz: da6e7c971afc3e5b1b1dbea1f9e0955a511a71702c3869673a363106f45d9459
3
+ metadata.gz: 867e51aad2f9b73b3aeecc016592ed9329a28269266d1caafb2ae42dac9555d0
4
+ data.tar.gz: 70c17e7f8aeacd3ad398c81152ad924faa23def26768dca1babce71e6ef867a0
5
5
  SHA512:
6
- metadata.gz: b5f0a68402ced555dd3ab07c1a3540225b6afe880f56385c2e9c419974bddbde31330cc78a9a2c8306c1692e7810a6bf57c1b35812af62135305241083daf011
7
- data.tar.gz: 16268685b95ca4e98d566275b0f82d4f265b88c665ac6fee796837bfa8ceee36df45e708ec057e3dc0e62270e6bfcc9f4f599177608e7a9d7c76f314d67b1b08
6
+ metadata.gz: cf0c02890fcb35834cbb29b4bad13c764e2e3ec005ffe5207fe9c33f432f406a630abcd9bef0ce05d8e5349ee6b7dc5e1f6c78afdd9411c101015cada35bd58f
7
+ data.tar.gz: 9906029477a7d286b98412f462d323060c6e12a79e7a0fb67e6207673f3db23d8a6f02cf771b6d6dc7ad56d6b5bb2c2903e9ac9cefd203de845129374b942e5a
data/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.6.1] - 2026-06
4
+
5
+ ### Improved
6
+ - Region shade rendering wraps the subtree more cleanly: wider, balanced
7
+ padding; bracket/rectangle enclosures are kept inside the plane; the incoming
8
+ parent connector stops just short of the plane (no overlap or touching); and
9
+ the margin is consistent between root and non-root regions. Works in both
10
+ top-to-bottom and left-to-right layouts (the connector-facing edge is the top
11
+ in TTB and the left in LTR, with symmetric padding on the other sides).
12
+
13
+ ### Added
14
+ - Example 065: nested (overlapping) region shades, shown as progressively
15
+ darker gray.
16
+
3
17
  ## [1.6.0] - 2026-06
4
18
 
5
19
  ### Added
@@ -0,0 +1,22 @@
1
+ ---
2
+ name: "065"
3
+ caption: "Nested region shades (overlapping domains)"
4
+ category: "Generative Grammar"
5
+ color: "off"
6
+ polyline: "off"
7
+ symmetrization: "off"
8
+ connector: "auto"
9
+ connector_height: "2.0"
10
+ linewidth: "1"
11
+ hide_default_connectors: "off"
12
+ font: "Noto Serif"
13
+ ---
14
+ ```
15
+ [%S
16
+ [DP everyone]
17
+ [%VP
18
+ [V loves]
19
+ [%NP Mary]
20
+ ]
21
+ ]
22
+ ```
Binary file
Binary file
@@ -25,7 +25,7 @@
25
25
  </pattern>
26
26
  </defs>
27
27
  <rect x="-17.6" y="0" width="761.2000000000002" height="779.625" stroke="none" fill="white" />"
28
- <rect x='222.2' y='162.2' width='477.4000000000001' height='603.725' rx='8.8' ry='8.8' fill='lightblue' fill-opacity='0.2' stroke='lightblue' stroke-opacity='0.55' stroke-width='2' />
28
+ <rect x='213.4' y='193.5' width='495.0000000000001' height='581.225' rx='11.25' ry='11.25' fill='lightblue' fill-opacity='0.2' stroke='lightblue' stroke-opacity='0.55' stroke-width='2' />
29
29
  <text white-space='pre' alignment-baseline='text-top' style='fill: #0072B2; storoke-width: 0; font-size: 32px;' x='216.76250000000002' y='67.5'><tspan x='216.76250000000002' y='67.5' style="" text-decoration="" font-family="'Noto Serif', 'Noto Serif JP', OpenMoji, 'OpenMoji Color', 'OpenMoji Black', serif">TP</tspan>
30
30
  </text>
31
31
  <text white-space='pre' alignment-baseline='text-top' style='fill: #0072B2; storoke-width: 0; font-size: 32px;' x='67.6' y='238.5'><tspan x='67.6' y='238.5' style="" text-decoration="" font-family="'Noto Serif', 'Noto Serif JP', OpenMoji, 'OpenMoji Color', 'OpenMoji Black', serif">DP</tspan>
@@ -0,0 +1,54 @@
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="515.2" height="597.375" viewBox="-17.6, 0, 532.8000000000001, 608.625" 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="17.6" markerHeight="17.6" orient="auto">
6
+ <path d="M 0 0 L 10 5 L 0 10" fill="black"/>
7
+ </marker>
8
+ <marker id="arrowBackward" markerUnits="userSpaceOnUse" viewBox="0 0 10 10" refX="5" refY="5" markerWidth="17.6" markerHeight="17.6" orient="auto">
9
+ <path d="M 0 0 L 10 5 L 0 10 z" fill="black"/>
10
+ </marker>
11
+ <marker id="arrowForward" markerUnits="userSpaceOnUse" viewBox="0 0 10 10" refX="5" refY="5" markerWidth="17.6" markerHeight="17.6" orient="auto">
12
+ <path d="M 10 0 L 0 5 L 10 10 z" fill="black"/>
13
+ </marker>
14
+ <marker id="arrowBothways" markerUnits="userSpaceOnUse" viewBox="0 0 30 10" refX="15" refY="5" markerWidth="52.800000000000004" markerHeight="17.6" 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="black"/>
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="black" 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="black" stroke-width="4"></line>
25
+ </pattern>
26
+ </defs>
27
+ <rect x="-17.6" y="0" width="532.8000000000001" height="608.625" stroke="none" fill="white" />"
28
+ <rect x='-7.105427357601002e-15' y='22.5' width='480.0' height='581.225' rx='11.25' ry='11.25' fill='#888888' fill-opacity='0.2' stroke='#888888' stroke-opacity='0.55' stroke-width='2' />
29
+ <rect x='213.4' y='193.5' width='266.6' height='410.225' rx='11.25' ry='11.25' fill='#888888' fill-opacity='0.2' stroke='#888888' stroke-opacity='0.55' stroke-width='2' />
30
+ <rect x='362.79999999999995' y='364.5' width='117.20000000000005' height='239.22500000000002' rx='11.25' ry='11.25' fill='#888888' fill-opacity='0.2' stroke='#888888' stroke-opacity='0.55' stroke-width='2' />
31
+ <text white-space='pre' alignment-baseline='text-top' style='fill: black; storoke-width: 0; font-size: 32px;' x='208.525' y='67.5'><tspan x='208.525' y='67.5' style="" text-decoration="" font-family="'Noto Serif', 'Noto Serif JP', OpenMoji, 'OpenMoji Color', 'OpenMoji Black', serif">S</tspan>
32
+ </text>
33
+ <text white-space='pre' alignment-baseline='text-top' style='fill: black; storoke-width: 0; font-size: 32px;' x='67.6' y='238.5'><tspan x='67.6' y='238.5' style="" text-decoration="" font-family="'Noto Serif', 'Noto Serif JP', OpenMoji, 'OpenMoji Color', 'OpenMoji Black', serif">DP</tspan>
34
+ </text>
35
+ <text white-space='pre' alignment-baseline='text-top' style='fill: black; storoke-width: 0; font-size: 32px;' x='17.599999999999994' y='409.5'><tspan x='17.599999999999994' y='409.5' style="" text-decoration="" font-family="'Noto Serif', 'Noto Serif JP', OpenMoji, 'OpenMoji Color', 'OpenMoji Black', serif">everyone</tspan>
36
+ </text>
37
+ <text white-space='pre' alignment-baseline='text-top' style='fill: black; storoke-width: 0; font-size: 32px;' x='325.45' y='238.5'><tspan x='325.45' y='238.5' style="" text-decoration="" font-family="'Noto Serif', 'Noto Serif JP', OpenMoji, 'OpenMoji Color', 'OpenMoji Black', serif">VP</tspan>
38
+ </text>
39
+ <text white-space='pre' alignment-baseline='text-top' style='fill: black; storoke-width: 0; font-size: 32px;' x='259.5' y='409.5'><tspan x='259.5' y='409.5' style="" text-decoration="" font-family="'Noto Serif', 'Noto Serif JP', OpenMoji, 'OpenMoji Color', 'OpenMoji Black', serif">V</tspan>
40
+ </text>
41
+ <text white-space='pre' alignment-baseline='text-top' style='fill: black; storoke-width: 0; font-size: 32px;' x='231.0' y='580.5'><tspan x='231.0' y='580.5' style="" text-decoration="" font-family="'Noto Serif', 'Noto Serif JP', OpenMoji, 'OpenMoji Color', 'OpenMoji Black', serif">loves</tspan>
42
+ </text>
43
+ <text white-space='pre' alignment-baseline='text-top' style='fill: black; storoke-width: 0; font-size: 32px;' x='399.4' y='409.5'><tspan x='399.4' y='409.5' style="" text-decoration="" font-family="'Noto Serif', 'Noto Serif JP', OpenMoji, 'OpenMoji Color', 'OpenMoji Black', serif">NP</tspan>
44
+ </text>
45
+ <text white-space='pre' alignment-baseline='text-top' style='fill: black; storoke-width: 0; font-size: 32px;' x='380.4' y='580.5'><tspan x='380.4' y='580.5' style="" text-decoration="" font-family="'Noto Serif', 'Noto Serif JP', OpenMoji, 'OpenMoji Color', 'OpenMoji Black', serif">Mary</tspan>
46
+ </text>
47
+ <line style='fill: none; stroke:black; stroke-width:2; stroke-linejoin:round; stroke-linecap:round;' x1='89.1' y1='182.25' x2='217.525' y2='95.625' />
48
+ <line style='fill: none; stroke:black; stroke-width:2; stroke-linejoin:round; stroke-linecap:round;' x1='345.95' y1='182.25' x2='217.525' y2='95.625' />
49
+ <line style='fill: none; stroke:black; stroke-width:2; stroke-linejoin:round; stroke-linecap:round;' x1='89.1' y1='353.25' x2='89.1' y2='266.625' />
50
+ <line style='fill: none; stroke:black; stroke-width:2; stroke-linejoin:round; stroke-linecap:round;' x1='270.5' y1='353.25' x2='345.95' y2='266.625' />
51
+ <line style='fill: none; stroke:black; stroke-width:2; stroke-linejoin:round; stroke-linecap:round;' x1='421.4' y1='353.25' x2='345.95' y2='266.625' />
52
+ <line style='fill: none; stroke:black; stroke-width:2; stroke-linejoin:round; stroke-linecap:round;' x1='270.5' y1='524.25' x2='270.5' y2='437.625' />
53
+ <line style='fill: none; stroke:black; stroke-width:2; stroke-linejoin:round; stroke-linecap:round;' x1='421.4' y1='524.25' x2='421.4' y2='437.625' />
54
+ </svg>
@@ -236,26 +236,6 @@ module RSyntaxTree
236
236
  end
237
237
  end
238
238
 
239
- # Bounding box of the subtree rooted at +id+, expressed in final drawing
240
- # coordinates (horizontal_indent / vertical_indent / content_*). Works for
241
- # both TTB and LTR because it runs after layout (and finalize_ltr) has
242
- # placed every element. Used to draw whole-subtree region shades.
243
- def subtree_bounds(id = 1)
244
- el = @element_list.get_id(id)
245
- left = el.horizontal_indent
246
- right = el.horizontal_indent + el.content_width
247
- top = el.vertical_indent
248
- bottom = el.vertical_indent + el.content_height
249
- el.children.each do |c|
250
- cb = subtree_bounds(c)
251
- left = cb[:left] if cb[:left] < left
252
- right = cb[:right] if cb[:right] > right
253
- top = cb[:top] if cb[:top] < top
254
- bottom = cb[:bottom] if cb[:bottom] > bottom
255
- end
256
- { left: left, right: right, top: top, bottom: bottom }
257
- end
258
-
259
239
  def get_leftmost(id = 1)
260
240
  target = @element_list.get_id(id)
261
241
  target_indent = target.horizontal_indent
@@ -142,21 +142,57 @@ module RSyntaxTree
142
142
  # Outer (shallower) regions are emitted first so deeper ones layer on
143
143
  # top; with low opacity the overlap reads as a darker nesting.
144
144
  def collect_region_shades
145
- pad = @global[:h_gap_between_nodes] / 2
145
+ hctt = @global[:height_connector_to_text]
146
+ pad = @global[:h_gap_between_nodes] # generous padding for the non-parent-facing edges
147
+ pad_parent = hctt / 2.0 # tighter margin on the parent-facing edge of the root
148
+ radius = hctt / 2.0
146
149
  stroke_width = @linewidth + LINE_SCALING
147
150
  half = stroke_width / 2.0
148
151
  @element_list.get_elements.each do |element|
149
152
  next unless element.region
150
153
 
151
- b = subtree_bounds(element.id)
152
- x = b[:left] - pad
153
- y = b[:top] - pad
154
- w = (b[:right] - b[:left]) + pad * 2
155
- h = (b[:bottom] - b[:top]) + pad * 2
154
+ b = region_subtree_bounds(element.id)
155
+ left = b[:left] - pad
156
+ right = b[:right] + pad
157
+ top = b[:top] - pad
158
+ bottom = b[:bottom] + pad
159
+
160
+ # The edge facing the parent is handled specially so the incoming
161
+ # connector neither overlaps nor touches the plane. That edge is the
162
+ # TOP in top-to-bottom layout and the LEFT in left-to-right layout; the
163
+ # other edges keep the generous padding. For a non-root node the edge
164
+ # is placed midway between the connector anchor and the content edge
165
+ # (even gap on both sides); the tree root has no incoming connector, so
166
+ # it just gets a tighter-but-consistent margin there.
167
+ is_root = element.parent.zero?
168
+ if @direction == "ltr"
169
+ anchor = element.horizontal_indent - hctt
170
+ left = if is_root
171
+ b[:left] - pad_parent
172
+ elsif anchor < b[:left]
173
+ (b[:left] + anchor) / 2.0
174
+ else
175
+ left
176
+ end
177
+ else
178
+ anchor = element.vertical_indent + hctt / 2.0
179
+ top = if is_root
180
+ b[:top] - pad_parent
181
+ elsif anchor < b[:top]
182
+ (b[:top] + anchor) / 2.0
183
+ else
184
+ top
185
+ end
186
+ end
187
+
188
+ x = left
189
+ y = top
190
+ w = right - left
191
+ h = bottom - top
156
192
  # An explicit shade color is always honored (consistent with the
157
193
  # @color: node-text color); bare '%' falls back to gray.
158
194
  color = element.region_color || REGION_DEFAULT_COLOR
159
- @region_shades << "<rect x='#{x}' y='#{y}' width='#{w}' height='#{h}' rx='#{pad}' ry='#{pad}' " \
195
+ @region_shades << "<rect x='#{x}' y='#{y}' width='#{w}' height='#{h}' rx='#{radius}' ry='#{radius}' " \
160
196
  "fill='#{color}' fill-opacity='#{REGION_FILL_OPACITY}' " \
161
197
  "stroke='#{color}' stroke-opacity='#{REGION_STROKE_OPACITY}' stroke-width='#{stroke_width}' />\n"
162
198
 
@@ -170,6 +206,49 @@ module RSyntaxTree
170
206
  end
171
207
  end
172
208
 
209
+ # Visual bounding box of a single element as actually drawn: the label /
210
+ # enclosure box (which starts hctt*3/4 below vertical_indent, i.e. below the
211
+ # connector gap) widened to include any enclosure bracket/rectangle that is
212
+ # painted beyond the content width.
213
+ def element_visual_box(el)
214
+ hctt = @global[:height_connector_to_text]
215
+ box_top = el.vertical_indent + hctt * 3 / 4 # bc[:y]: line-height / enclosure box top
216
+ box_bottom = box_top + el.content_height
217
+ left = el.horizontal_indent
218
+ right = el.horizontal_indent + el.content_width
219
+ if [:brackets, :rectangle, :brectangle].include?(el.enclosure)
220
+ ext = @global[:h_gap_between_nodes] / 2 + (@linewidth + BLINE_SCALING)
221
+ left -= ext
222
+ right += ext
223
+ sw = @linewidth + BLINE_SCALING
224
+ top = box_top - sw
225
+ bottom = box_bottom + sw
226
+ else
227
+ # No enclosure box is painted, so hug the actual glyphs rather than the
228
+ # taller line-height box: the line box carries ~hctt*3/4 of leading both
229
+ # above the cap top and below the baseline, which would otherwise leave
230
+ # too much empty space above and below a plain label.
231
+ top = el.vertical_indent + hctt * 3 / 2
232
+ bottom = box_bottom - hctt * 3 / 4
233
+ end
234
+ { left: left, top: top, right: right, bottom: bottom }
235
+ end
236
+
237
+ # Union of element_visual_box over the subtree rooted at +id+, in final
238
+ # drawing coordinates. Used to size region shades so the whole subtree
239
+ # (labels, enclosures, brackets) sits inside the plane.
240
+ def region_subtree_bounds(id)
241
+ b = element_visual_box(@element_list.get_id(id))
242
+ @element_list.get_id(id).children.each do |c|
243
+ cb = region_subtree_bounds(c)
244
+ b[:left] = cb[:left] if cb[:left] < b[:left]
245
+ b[:right] = cb[:right] if cb[:right] > b[:right]
246
+ b[:top] = cb[:top] if cb[:top] < b[:top]
247
+ b[:bottom] = cb[:bottom] if cb[:bottom] > b[:bottom]
248
+ end
249
+ b
250
+ end
251
+
173
252
  def draw_a_path(s_x, s_y, t_x, t_y, target_arrow = :none)
174
253
  spacing = @global[:h_gap_between_nodes] * 1.25
175
254
  min_bulge = @global[:height_connector_to_text]
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RSyntaxTree
4
- VERSION = "1.6.0"
4
+ VERSION = "1.6.1"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rsyntaxtree
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.6.0
4
+ version: 1.6.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yoichiro Hasebe
@@ -210,6 +210,7 @@ files:
210
210
  - docs/_examples/062.md
211
211
  - docs/_examples/063.md
212
212
  - docs/_examples/064.md
213
+ - docs/_examples/065.md
213
214
  - docs/_includes/box_and_circle_table.html
214
215
  - docs/_includes/escape_char_table.html
215
216
  - docs/_includes/social_media_links.html
@@ -280,6 +281,7 @@ files:
280
281
  - docs/assets/img/062.png
281
282
  - docs/assets/img/063.png
282
283
  - docs/assets/img/064.png
284
+ - docs/assets/img/065.png
283
285
  - docs/assets/img/elements/arrow_both.png
284
286
  - docs/assets/img/elements/arrow_both_bold.png
285
287
  - docs/assets/img/elements/arrow_left.png
@@ -367,6 +369,7 @@ files:
367
369
  - docs/assets/svg/062.svg
368
370
  - docs/assets/svg/063.svg
369
371
  - docs/assets/svg/064.svg
372
+ - docs/assets/svg/065.svg
370
373
  - docs/documentation.md
371
374
  - docs/documentation_ja.md
372
375
  - docs/examples.html