rsyntaxtree 0.8.8 → 1.0.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 +4 -4
- data/.gitignore +2 -0
- data/.tags +203 -0
- data/Gemfile +2 -0
- data/README.md +0 -1
- data/Rakefile +7 -0
- data/bin/rsyntaxtree +38 -31
- data/fonts/NotoSansJP-Bold.otf +0 -0
- data/fonts/NotoSansJP-Regular.otf +0 -0
- data/fonts/NotoSansMath-Regular.ttf +0 -0
- data/fonts/NotoSerifJP-Bold.otf +0 -0
- data/fonts/NotoSerifJP-Regular.otf +0 -0
- data/fonts/OpenMoji-Black.ttf +0 -0
- data/fonts/OpenMoji-Color.ttf +0 -0
- data/lib/rsyntaxtree/base_graph.rb +262 -0
- data/lib/rsyntaxtree/element.rb +155 -25
- data/lib/rsyntaxtree/elementlist.rb +16 -13
- data/lib/rsyntaxtree/markup_parser.rb +208 -0
- data/lib/rsyntaxtree/string_parser.rb +190 -197
- data/lib/rsyntaxtree/svg_graph.rb +450 -260
- data/lib/rsyntaxtree/utils.rb +49 -6
- data/lib/rsyntaxtree/version.rb +1 -1
- data/lib/rsyntaxtree.rb +143 -154
- data/rsyntaxtree.gemspec +2 -0
- data/test/markup_parser_test.rb +207 -0
- metadata +41 -13
- data/fonts/NotoSansCJKjp-Regular.otf +0 -0
- data/fonts/NotoSerifCJKjp-Regular.otf +0 -0
- data/fonts/latinmodern-math.otf +0 -0
- data/fonts/lmroman10-bold.otf +0 -0
- data/fonts/lmroman10-bolditalic.otf +0 -0
- data/fonts/lmroman10-italic.otf +0 -0
- data/fonts/lmroman10-regular.otf +0 -0
- data/lib/rsyntaxtree/error_message.rb +0 -68
- data/lib/rsyntaxtree/graph.rb +0 -307
- data/lib/rsyntaxtree/tree_graph.rb +0 -309
@@ -1,309 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
# -*- coding: utf-8 -*-
|
3
|
-
|
4
|
-
#==========================
|
5
|
-
# tree_graph.rb
|
6
|
-
#==========================
|
7
|
-
#
|
8
|
-
# Parses an element list into a (non-SVG) graphical tree.
|
9
|
-
#
|
10
|
-
# This file is part of RSyntaxTree, which is a ruby port of Andre Eisenbach's
|
11
|
-
# excellent program phpSyntaxTree.
|
12
|
-
#
|
13
|
-
# Copyright (c) 2007-2021 Yoichiro Hasebe <yohasebe@gmail.com>
|
14
|
-
# Copyright (c) 2003-2004 Andre Eisenbach <andre@ironcreek.net>
|
15
|
-
|
16
|
-
require 'graph'
|
17
|
-
require 'rmagick'
|
18
|
-
include Magick
|
19
|
-
|
20
|
-
class TreeGraph < Graph
|
21
|
-
|
22
|
-
def initialize(e_list, metrics, symmetrize, color, leafstyle, multibyte,
|
23
|
-
fontstyle, font, font_it, font_bd, font_itbd, font_math, font_cjk, font_size,
|
24
|
-
margin, transparent)
|
25
|
-
|
26
|
-
# Store class-specific parameters
|
27
|
-
@fontstyle = fontstyle
|
28
|
-
@font = multibyte ? font_cjk : font
|
29
|
-
@font_size = font_size
|
30
|
-
@font_it = font_it
|
31
|
-
@font_bd = font_bd
|
32
|
-
@font_itbd = font_itbd
|
33
|
-
@font_math = font_math
|
34
|
-
@font_cjk = font_cjk
|
35
|
-
@margin = margin
|
36
|
-
@transparent = transparent
|
37
|
-
|
38
|
-
super(e_list, metrics, symmetrize, color, leafstyle, multibyte, @font, @font_size)
|
39
|
-
|
40
|
-
# Initialize the image and colors
|
41
|
-
@gc = Draw.new
|
42
|
-
@gc.font = @font
|
43
|
-
@gc.pointsize(@font_size)
|
44
|
-
end
|
45
|
-
|
46
|
-
def destroy
|
47
|
-
@im.destroy!
|
48
|
-
end
|
49
|
-
|
50
|
-
def draw
|
51
|
-
parse_list
|
52
|
-
@im = Image.new(@width, @height)
|
53
|
-
if @transparent
|
54
|
-
@im.matte_reset!
|
55
|
-
end
|
56
|
-
@im.interlace = PlaneInterlace
|
57
|
-
@gc.draw(@im)
|
58
|
-
end
|
59
|
-
|
60
|
-
def save(filename)
|
61
|
-
draw
|
62
|
-
@im.write(filename)
|
63
|
-
end
|
64
|
-
|
65
|
-
# inspired by the implementation of Gruff
|
66
|
-
# by Geoffrey Grosenbach
|
67
|
-
def to_blob(fileformat='PNG')
|
68
|
-
draw
|
69
|
-
@im.trim!
|
70
|
-
if @transparent
|
71
|
-
@im.border!(@margin, @margin, "transparent")
|
72
|
-
else
|
73
|
-
@im.border!(@margin, @margin, "white")
|
74
|
-
end
|
75
|
-
@im.format = fileformat
|
76
|
-
@im.interlace = PlaneInterlace
|
77
|
-
return @im.to_blob
|
78
|
-
end
|
79
|
-
|
80
|
-
:private
|
81
|
-
|
82
|
-
# Add the element into the tree (draw it)
|
83
|
-
def draw_element(x, y, w, string, type)
|
84
|
-
numlines = string.count("\n")
|
85
|
-
string = string.sub(/\^\z/){""}
|
86
|
-
# Calculate element dimensions and position
|
87
|
-
if (type == ETYPE_LEAF) and @leafstyle == "nothing"
|
88
|
-
top = row2px(y - 1) + (@font_size * 1.5)
|
89
|
-
else
|
90
|
-
top = row2px(y)
|
91
|
-
end
|
92
|
-
left = x + @m[:b_side]
|
93
|
-
bottom = top + @e_height * numlines
|
94
|
-
right = left + w
|
95
|
-
|
96
|
-
# Split the string into the main part and the
|
97
|
-
# subscript part of the element (if any)
|
98
|
-
parts = string.split("_", 2)
|
99
|
-
if(parts.length > 1 )
|
100
|
-
main = parts[0].strip
|
101
|
-
sub = parts[1].gsub(/_/, " ").strip
|
102
|
-
else
|
103
|
-
main = parts[0].strip
|
104
|
-
sub = ""
|
105
|
-
end
|
106
|
-
|
107
|
-
if /\A\=(.+)\=\z/ =~ main
|
108
|
-
main = $1
|
109
|
-
main_decoration = OverlineDecoration
|
110
|
-
elsif /\A\-(.+)\-\z/ =~ main
|
111
|
-
main = $1
|
112
|
-
main_decoration = UnderlineDecoration
|
113
|
-
elsif /\A\~(.+)\~\z/ =~ main
|
114
|
-
main = $1
|
115
|
-
main_decoration = LineThroughDecoration
|
116
|
-
else
|
117
|
-
main_decoration = NoDecoration
|
118
|
-
end
|
119
|
-
|
120
|
-
main_font = @font
|
121
|
-
|
122
|
-
if /\A\*\*\*(.+)\*\*\*\z/ =~ main
|
123
|
-
main = $1
|
124
|
-
if !@multibyte
|
125
|
-
main_font = @font_itbd
|
126
|
-
end
|
127
|
-
elsif /\A\*\*(.+)\*\*\z/ =~ main
|
128
|
-
main = $1
|
129
|
-
if !@multibyte
|
130
|
-
main_font = @font_bd
|
131
|
-
end
|
132
|
-
elsif /\A\*(.+)\*\z/ =~ main
|
133
|
-
main = $1
|
134
|
-
if !@multibyte
|
135
|
-
main_font = @font_it
|
136
|
-
end
|
137
|
-
end
|
138
|
-
|
139
|
-
if /\A#(.+)#\z/ =~ main
|
140
|
-
main = $1
|
141
|
-
main_font = @font_math
|
142
|
-
end
|
143
|
-
|
144
|
-
# Calculate text size for the main and the
|
145
|
-
# subscript part of the element
|
146
|
-
|
147
|
-
main_width = img_get_txt_width(main, main_font, @font_size)
|
148
|
-
|
149
|
-
if /\A\=(.+)\=\z/ =~ sub
|
150
|
-
sub = $1
|
151
|
-
sub_decoration = OverlineDecoration
|
152
|
-
elsif /\A\-(.+)\-\z/ =~ sub
|
153
|
-
sub = $1
|
154
|
-
sub_decoration = UnderlineDecoration
|
155
|
-
elsif /\A\~(.+)\~z/ =~ sub
|
156
|
-
sub = $1
|
157
|
-
sub_decoration = LineThroughDecoration
|
158
|
-
else
|
159
|
-
sub_decoration = NoDecoration
|
160
|
-
end
|
161
|
-
|
162
|
-
sub_font = @font
|
163
|
-
if /\A\*\*\*(.+)\*\*\*\z/ =~ sub
|
164
|
-
sub = $1
|
165
|
-
if !@multibyte
|
166
|
-
sub_font = @font_itbd
|
167
|
-
end
|
168
|
-
elsif /\A\*\*(.+)\*\*\z/ =~ sub
|
169
|
-
sub = $1
|
170
|
-
if !@multibyte
|
171
|
-
sub_font = @font_bd
|
172
|
-
end
|
173
|
-
elsif /\A\*(.+)\*\z/ =~ sub
|
174
|
-
sub = $1
|
175
|
-
if !@multibyte
|
176
|
-
sub_font = @font_it
|
177
|
-
end
|
178
|
-
end
|
179
|
-
|
180
|
-
if /\A#(.+)#\z/ =~ sub
|
181
|
-
sub = $1
|
182
|
-
sub_font = @font_math
|
183
|
-
end
|
184
|
-
|
185
|
-
if sub != ""
|
186
|
-
sub_width = img_get_txt_width(sub.to_s, sub_font, @sub_size)
|
187
|
-
else
|
188
|
-
sub_width = 0
|
189
|
-
end
|
190
|
-
|
191
|
-
# Center text in the element
|
192
|
-
txt_width = main_width + sub_width
|
193
|
-
|
194
|
-
txt_pos = left + (right - left) / 2 - txt_width / 2
|
195
|
-
|
196
|
-
# Select apropriate color
|
197
|
-
if(type == ETYPE_LEAF)
|
198
|
-
col = @col_leaf
|
199
|
-
else
|
200
|
-
col = @col_node
|
201
|
-
end
|
202
|
-
|
203
|
-
if(main[0].chr == "<" && main[-1].chr == ">")
|
204
|
-
col = @col_trace
|
205
|
-
end
|
206
|
-
|
207
|
-
@gc.stroke("none")
|
208
|
-
@gc.fill(col)
|
209
|
-
|
210
|
-
# Draw main text
|
211
|
-
@gc.pointsize(@font_size)
|
212
|
-
main_x = txt_pos
|
213
|
-
main_y = top + @e_height - @m[:e_padd]
|
214
|
-
|
215
|
-
@gc.interline_spacing = -(@main_height / 3)
|
216
|
-
@gc.font(main_font)
|
217
|
-
@gc.decorate(main_decoration)
|
218
|
-
@gc.text(main_x.ceil, main_y.ceil, main)
|
219
|
-
|
220
|
-
# Draw subscript text
|
221
|
-
if (sub.length > 0 )
|
222
|
-
@gc.pointsize(@sub_size)
|
223
|
-
sub_x = txt_pos + main_width + @sub_space_width
|
224
|
-
sub_y = top + (@e_height - @m[:e_padd] + @sub_size / 2)
|
225
|
-
@gc.font(sub_font)
|
226
|
-
@gc.decorate(sub_decoration)
|
227
|
-
@gc.text(sub_x.ceil, sub_y.ceil, sub)
|
228
|
-
end
|
229
|
-
end
|
230
|
-
|
231
|
-
# Draw a line between child/parent elements
|
232
|
-
def line_to_parent(fromX, fromY, fromW, toX, toW)
|
233
|
-
|
234
|
-
if (fromY == 0 )
|
235
|
-
return
|
236
|
-
end
|
237
|
-
|
238
|
-
fromTop = row2px(fromY)
|
239
|
-
fromLeft = (fromX + fromW / 2 + @m[:b_side])
|
240
|
-
toBot = (row2px(fromY - 1 ) + @e_height)
|
241
|
-
toLeft = (toX + toW / 2 + @m[:b_side])
|
242
|
-
|
243
|
-
@gc.fill("none")
|
244
|
-
@gc.stroke @col_line
|
245
|
-
@gc.stroke_width 1 * FONT_SCALING
|
246
|
-
@gc.line(fromLeft.ceil, fromTop.ceil, toLeft.ceil, toBot.ceil)
|
247
|
-
end
|
248
|
-
|
249
|
-
# Draw a triangle between child/parent elements
|
250
|
-
def triangle_to_parent(fromX, fromY, fromW, textW, symmetrize = true)
|
251
|
-
if (fromY == 0)
|
252
|
-
return
|
253
|
-
end
|
254
|
-
|
255
|
-
toX = fromX
|
256
|
-
fromCenter = (fromX + fromW / 2 + @m[:b_side])
|
257
|
-
|
258
|
-
fromTop = row2px(fromY).ceil
|
259
|
-
fromLeft1 = (fromCenter + textW / 2).ceil
|
260
|
-
fromLeft2 = (fromCenter - textW / 2).ceil
|
261
|
-
toBot = (row2px(fromY - 1) + @e_height)
|
262
|
-
if symmetrize
|
263
|
-
toLeft = (toX + textW / 2 + @m[:b_side])
|
264
|
-
else
|
265
|
-
toLeft = (toX + textW / 2 + @m[:b_side] * 3)
|
266
|
-
end
|
267
|
-
|
268
|
-
@gc.fill("none")
|
269
|
-
@gc.stroke @col_line
|
270
|
-
@gc.stroke_width 1 * 2
|
271
|
-
@gc.line(fromLeft1, fromTop, toLeft, toBot)
|
272
|
-
@gc.line(fromLeft2, fromTop, toLeft, toBot)
|
273
|
-
@gc.line(fromLeft1, fromTop, fromLeft2, fromTop)
|
274
|
-
end
|
275
|
-
|
276
|
-
# If a node element text is wider than the sum of it's
|
277
|
-
# child elements, then the child elements need to
|
278
|
-
# be resized to even out the space. This function
|
279
|
-
# recurses down the a child tree and sizes the
|
280
|
-
# children appropriately.
|
281
|
-
def fix_child_size(id, current, target)
|
282
|
-
children = @e_list.get_children(id)
|
283
|
-
@e_list.set_element_width(id, target)
|
284
|
-
|
285
|
-
if(children.length > 0 )
|
286
|
-
delta = target - current
|
287
|
-
target_delta = delta / children.length
|
288
|
-
|
289
|
-
children.each do |child|
|
290
|
-
child_width = @e_list.get_element_width(child)
|
291
|
-
fix_child_size(child, child_width, child_width + target_delta)
|
292
|
-
end
|
293
|
-
end
|
294
|
-
end
|
295
|
-
|
296
|
-
def img_get_txt_width(text, font, font_size, multiline = true)
|
297
|
-
parts = text.split("_", 2)
|
298
|
-
main_before = parts[0].strip
|
299
|
-
sub = parts[1]
|
300
|
-
main = get_txt_only(main_before)
|
301
|
-
main_metrics = img_get_txt_metrics(main, font, font_size, multiline)
|
302
|
-
width = main_metrics.width
|
303
|
-
if sub
|
304
|
-
sub_metrics = img_get_txt_metrics(sub.strip, font, font_size * SUBSCRIPT_CONST, multiline)
|
305
|
-
width += sub_metrics.width
|
306
|
-
end
|
307
|
-
return width
|
308
|
-
end
|
309
|
-
end
|