rsyntaxtree 0.9.3 → 1.0.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -0
  3. data/.tags +179 -0
  4. data/Gemfile +2 -0
  5. data/README.md +35 -29
  6. data/Rakefile +7 -0
  7. data/bin/rsyntaxtree +42 -31
  8. data/fonts/OpenMoji-Black.ttf +0 -0
  9. data/fonts/OpenMoji-Color.ttf +0 -0
  10. data/img/elements/circle.png +0 -0
  11. data/img/elements/circle_abc.png +0 -0
  12. data/img/elements/circle_bold.png +0 -0
  13. data/img/elements/circle_hatched.png +0 -0
  14. data/img/elements/circle_one.png +0 -0
  15. data/img/elements/connector.png +0 -0
  16. data/img/elements/connector_bold.png +0 -0
  17. data/img/elements/square.png +0 -0
  18. data/img/elements/square_abc.png +0 -0
  19. data/img/elements/square_bold.png +0 -0
  20. data/img/elements/square_hatched.png +0 -0
  21. data/img/elements/square_one.png +0 -0
  22. data/img/rsyntaxtree.png +0 -0
  23. data/img/sample.png +0 -0
  24. data/img/sample.svg +38 -0
  25. data/lib/rsyntaxtree/base_graph.rb +262 -0
  26. data/lib/rsyntaxtree/element.rb +156 -25
  27. data/lib/rsyntaxtree/elementlist.rb +16 -13
  28. data/lib/rsyntaxtree/markup_parser.rb +208 -0
  29. data/lib/rsyntaxtree/string_parser.rb +187 -204
  30. data/lib/rsyntaxtree/svg_graph.rb +471 -298
  31. data/lib/rsyntaxtree/utils.rb +49 -6
  32. data/lib/rsyntaxtree/version.rb +1 -1
  33. data/lib/rsyntaxtree.rb +144 -161
  34. data/rsyntaxtree.gemspec +2 -0
  35. data/test/markup_parser_test.rb +207 -0
  36. metadata +52 -11
  37. data/fonts/latinmodern-math.otf +0 -0
  38. data/fonts/lmroman10-bold.otf +0 -0
  39. data/fonts/lmroman10-bolditalic.otf +0 -0
  40. data/fonts/lmroman10-italic.otf +0 -0
  41. data/fonts/lmroman10-regular.otf +0 -0
  42. data/lib/rsyntaxtree/error_message.rb +0 -68
  43. data/lib/rsyntaxtree/graph.rb +0 -312
  44. data/lib/rsyntaxtree/tree_graph.rb +0 -327
@@ -1,327 +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
- @im.interlace = LineInterlace
58
- @gc.draw(@im)
59
- end
60
-
61
- def save(filename)
62
- draw
63
- @im.write(filename)
64
- end
65
-
66
- # inspired by the implementation of Gruff
67
- # by Geoffrey Grosenbach
68
- def to_blob(fileformat='PNG')
69
- draw
70
- @im.trim!
71
- if @transparent
72
- @im.border!(@margin, @margin, "transparent")
73
- else
74
- @im.border!(@margin, @margin, "white")
75
- end
76
- @im.format = fileformat
77
- @im.interlace = PlaneInterlace
78
- return @im.to_blob
79
- end
80
-
81
- :private
82
-
83
- # Add the element into the tree (draw it)
84
- def draw_element(x, y, w, string, type)
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
- right = left + w
94
-
95
- # Split the string into the main part and the
96
- # subscript part of the element (if any)
97
- parts = string.split("_", 2)
98
- if(parts.length > 1 )
99
- main = parts[0].strip
100
- sub = parts[1].gsub(/_/, " ").strip
101
- else
102
- main = parts[0].strip
103
- sub = ""
104
- end
105
-
106
- if /\A\=(.+)\=\z/ =~ main
107
- main = $1
108
- main_decoration = OverlineDecoration
109
- elsif /\A\-(.+)\-\z/ =~ main
110
- main = $1
111
- main_decoration = UnderlineDecoration
112
- elsif /\A\~(.+)\~\z/ =~ main
113
- main = $1
114
- main_decoration = LineThroughDecoration
115
- else
116
- main_decoration = NoDecoration
117
- end
118
-
119
- main_font = @font
120
-
121
- if /\A\*\*\*(.+)\*\*\*\z/ =~ main
122
- main = $1
123
- if !@multibyte
124
- main_font = @font_itbd
125
- end
126
- elsif /\A\*\*(.+)\*\*\z/ =~ main
127
- main = $1
128
- if !@multibyte
129
- main_font = @font_bd
130
- end
131
- elsif /\A\*(.+)\*\z/ =~ main
132
- main = $1
133
- if !@multibyte
134
- main_font = @font_it
135
- end
136
- end
137
-
138
- if /\A#(.+)#\z/ =~ main
139
- main = $1
140
- main_font = @font_math
141
- end
142
-
143
- # Calculate text size for the main and the
144
- # subscript part of the element
145
-
146
-
147
- main_width = 0
148
- main_height = 0
149
- main.split(/\\n/).each do |l|
150
- l_width = img_get_txt_width(l, main_font, @font_size)
151
- main_width = l_width if main_width < l_width
152
- main_height += img_get_txt_height(l, @font, @font_size)
153
- end
154
-
155
- if /\A\=(.+)\=\z/ =~ sub
156
- sub = $1
157
- sub_decoration = OverlineDecoration
158
- elsif /\A\-(.+)\-\z/ =~ sub
159
- sub = $1
160
- sub_decoration = UnderlineDecoration
161
- elsif /\A\~(.+)\~z/ =~ sub
162
- sub = $1
163
- sub_decoration = LineThroughDecoration
164
- else
165
- sub_decoration = NoDecoration
166
- end
167
-
168
- sub_font = @font
169
- if /\A\*\*\*(.+)\*\*\*\z/ =~ sub
170
- sub = $1
171
- if !@multibyte
172
- sub_font = @font_itbd
173
- end
174
- elsif /\A\*\*(.+)\*\*\z/ =~ sub
175
- sub = $1
176
- if !@multibyte
177
- sub_font = @font_bd
178
- end
179
- elsif /\A\*(.+)\*\z/ =~ sub
180
- sub = $1
181
- if !@multibyte
182
- sub_font = @font_it
183
- end
184
- end
185
-
186
- if /\A#(.+)#\z/ =~ sub
187
- sub = $1
188
- sub_font = @font_math
189
- end
190
-
191
- if sub != ""
192
- sub_width = img_get_txt_width(sub.to_s, sub_font, @sub_size)
193
- sub_height = img_get_txt_height(sub.to_s, sub_font, @sub_size)
194
- else
195
- sub_width = 0
196
- sub_height = 0
197
- end
198
-
199
- # Center text in the element
200
- txt_pos = left + (right - left) / 2
201
-
202
- # Select apropriate color
203
- if(type == ETYPE_LEAF)
204
- col = @col_leaf
205
- else
206
- col = @col_node
207
- end
208
-
209
- if(main[0].chr == "<" && main[-1].chr == ">")
210
- col = @col_trace
211
- end
212
-
213
- @gc.stroke("none")
214
- @gc.fill(col)
215
-
216
- # Draw main text
217
- @gc.pointsize(@font_size)
218
- @gc.kerning = 0
219
- @gc.interline_spacing = 0
220
- @gc.interword_spacing = 0
221
-
222
- main_x = txt_pos - sub_width / 2
223
- main_y = top + @e_height - @m[:e_padd]
224
-
225
- # @gc.interline_spacing = -(@main_height / 3)
226
- @gc.font(main_font)
227
- @gc.decorate(main_decoration)
228
- numlines = main.count("\\n")
229
- if numlines > 1
230
- @height = @height + @main_height * numlines
231
- end
232
- @gc.text_align(CenterAlign)
233
- @gc.text(main_x.ceil, main_y.ceil, main.gsub("\\n", "\n"))
234
-
235
- # Draw subscript text
236
- if (sub != "" )
237
- @gc.pointsize(@sub_size)
238
- sub_x = main_x + (main_width / 2) + (sub_width / 2)
239
- sub_y = top + main_height + sub_height / 4
240
- @height += sub_height / 4
241
- @gc.font(sub_font)
242
- @gc.decorate(sub_decoration)
243
- @gc.text_align(CenterAlign)
244
- @gc.text(sub_x.ceil, sub_y.ceil, " " + sub.gsub("\\n", "\n"))
245
- end
246
- end
247
-
248
- # Draw a line between child/parent elements
249
- def line_to_parent(fromX, fromY, fromW, toX, toW)
250
-
251
- if (fromY == 0 )
252
- return
253
- end
254
-
255
- fromTop = row2px(fromY)
256
- fromLeft = (fromX + fromW / 2 + @m[:b_side])
257
- toBot = (row2px(fromY - 1 ) + @e_height)
258
- toLeft = (toX + toW / 2 + @m[:b_side])
259
-
260
- @gc.fill("none")
261
- @gc.stroke @col_line
262
- @gc.stroke_width 1 * FONT_SCALING
263
- @gc.line(fromLeft.ceil, fromTop.ceil, toLeft.ceil, toBot.ceil)
264
- end
265
-
266
- # Draw a triangle between child/parent elements
267
- def triangle_to_parent(fromX, fromY, fromW, textW, symmetrize = true)
268
- if (fromY == 0)
269
- return
270
- end
271
-
272
- toX = fromX
273
- fromCenter = (fromX + fromW / 2 + @m[:b_side])
274
-
275
- fromTop = row2px(fromY).ceil
276
- fromLeft1 = (fromCenter + textW / 2).ceil
277
- fromLeft2 = (fromCenter - textW / 2).ceil
278
- toBot = (row2px(fromY - 1) + @e_height)
279
-
280
- if symmetrize
281
- toLeft = (toX + textW / 2 + @m[:b_side])
282
- else
283
- toLeft = (toX + textW / 2 + @m[:b_side] * 3)
284
- end
285
-
286
- @gc.fill("none")
287
- @gc.stroke @col_line
288
- @gc.stroke_width 1 * 2
289
- @gc.line(fromLeft1, fromTop, toLeft, toBot)
290
- @gc.line(fromLeft2, fromTop, toLeft, toBot)
291
- @gc.line(fromLeft1, fromTop, fromLeft2, fromTop)
292
- end
293
-
294
- # If a node element text is wider than the sum of it's
295
- # child elements, then the child elements need to
296
- # be resized to even out the space. This function
297
- # recurses down the a child tree and sizes the
298
- # children appropriately.
299
- def fix_child_size(id, current, target)
300
- children = @e_list.get_children(id)
301
- @e_list.set_element_width(id, target)
302
-
303
- if(children.length > 0 )
304
- delta = target - current
305
- target_delta = delta / children.length
306
-
307
- children.each do |child|
308
- child_width = @e_list.get_element_width(child)
309
- fix_child_size(child, child_width, child_width + target_delta)
310
- end
311
- end
312
- end
313
-
314
- def img_get_txt_width(text, font, font_size, multiline = true)
315
- parts = text.split("_", 2)
316
- main_before = parts[0].strip
317
- sub = parts[1]
318
- main = get_txt_only(main_before)
319
- main_metrics = img_get_txt_metrics(main, font, font_size, multiline)
320
- width = main_metrics.width
321
- if sub
322
- sub_metrics = img_get_txt_metrics(sub.strip, font, font_size * SUBSCRIPT_CONST, multiline)
323
- width += sub_metrics.width
324
- end
325
- return width
326
- end
327
- end