rsyntaxtree 0.9.1 → 1.0.4
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 +171 -0
- data/Gemfile +2 -0
- data/README.md +0 -1
- data/Rakefile +7 -0
- data/bin/rsyntaxtree +38 -31
- 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 +187 -204
- data/lib/rsyntaxtree/svg_graph.rb +446 -299
- data/lib/rsyntaxtree/utils.rb +49 -6
- data/lib/rsyntaxtree/version.rb +1 -1
- data/lib/rsyntaxtree.rb +143 -161
- data/rsyntaxtree.gemspec +2 -0
- data/syntree.png +0 -0
- data/syntree.svg +24 -0
- data/test/markup_parser_test.rb +207 -0
- metadata +39 -11
- 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 -312
- data/lib/rsyntaxtree/tree_graph.rb +0 -328
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rsyntaxtree
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Yoichiro Hasebe
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-02-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rmagick
|
@@ -50,6 +50,34 @@ dependencies:
|
|
50
50
|
- - ">="
|
51
51
|
- !ruby/object:Gem::Version
|
52
52
|
version: 3.0.1
|
53
|
+
- !ruby/object:Gem::Dependency
|
54
|
+
name: parslet
|
55
|
+
requirement: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - ">="
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: '0'
|
60
|
+
type: :runtime
|
61
|
+
prerelease: false
|
62
|
+
version_requirements: !ruby/object:Gem::Requirement
|
63
|
+
requirements:
|
64
|
+
- - ">="
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: '0'
|
67
|
+
- !ruby/object:Gem::Dependency
|
68
|
+
name: rsvg2
|
69
|
+
requirement: !ruby/object:Gem::Requirement
|
70
|
+
requirements:
|
71
|
+
- - ">="
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: '0'
|
74
|
+
type: :runtime
|
75
|
+
prerelease: false
|
76
|
+
version_requirements: !ruby/object:Gem::Requirement
|
77
|
+
requirements:
|
78
|
+
- - ">="
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: '0'
|
53
81
|
description: Yet another syntax tree generator made with Ruby and RMagick
|
54
82
|
email:
|
55
83
|
- yohasebe@gmail.com
|
@@ -59,6 +87,7 @@ extensions: []
|
|
59
87
|
extra_rdoc_files: []
|
60
88
|
files:
|
61
89
|
- ".gitignore"
|
90
|
+
- ".tags"
|
62
91
|
- Gemfile
|
63
92
|
- README.md
|
64
93
|
- Rakefile
|
@@ -76,23 +105,22 @@ files:
|
|
76
105
|
- fonts/NotoSerif-Regular.ttf
|
77
106
|
- fonts/NotoSerifJP-Bold.otf
|
78
107
|
- fonts/NotoSerifJP-Regular.otf
|
79
|
-
- fonts/
|
80
|
-
- fonts/
|
81
|
-
- fonts/lmroman10-bolditalic.otf
|
82
|
-
- fonts/lmroman10-italic.otf
|
83
|
-
- fonts/lmroman10-regular.otf
|
108
|
+
- fonts/OpenMoji-Black.ttf
|
109
|
+
- fonts/OpenMoji-Color.ttf
|
84
110
|
- fonts/wqy-zenhei.ttf
|
85
111
|
- lib/rsyntaxtree.rb
|
112
|
+
- lib/rsyntaxtree/base_graph.rb
|
86
113
|
- lib/rsyntaxtree/element.rb
|
87
114
|
- lib/rsyntaxtree/elementlist.rb
|
88
|
-
- lib/rsyntaxtree/
|
89
|
-
- lib/rsyntaxtree/graph.rb
|
115
|
+
- lib/rsyntaxtree/markup_parser.rb
|
90
116
|
- lib/rsyntaxtree/string_parser.rb
|
91
117
|
- lib/rsyntaxtree/svg_graph.rb
|
92
|
-
- lib/rsyntaxtree/tree_graph.rb
|
93
118
|
- lib/rsyntaxtree/utils.rb
|
94
119
|
- lib/rsyntaxtree/version.rb
|
95
120
|
- rsyntaxtree.gemspec
|
121
|
+
- syntree.png
|
122
|
+
- syntree.svg
|
123
|
+
- test/markup_parser_test.rb
|
96
124
|
homepage: http://github.com/yohasebe/rsyntaxtree
|
97
125
|
licenses:
|
98
126
|
- MIT
|
@@ -112,7 +140,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
112
140
|
- !ruby/object:Gem::Version
|
113
141
|
version: '0'
|
114
142
|
requirements: []
|
115
|
-
rubygems_version: 3.
|
143
|
+
rubygems_version: 3.3.3
|
116
144
|
signing_key:
|
117
145
|
specification_version: 4
|
118
146
|
summary: RSyntaxTree is a graphical syntax tree generator written in Ruby
|
data/fonts/latinmodern-math.otf
DELETED
Binary file
|
data/fonts/lmroman10-bold.otf
DELETED
Binary file
|
Binary file
|
data/fonts/lmroman10-italic.otf
DELETED
Binary file
|
data/fonts/lmroman10-regular.otf
DELETED
Binary file
|
@@ -1,68 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
# -*- coding: utf-8 -*-
|
3
|
-
|
4
|
-
#==========================
|
5
|
-
# error_message.rb
|
6
|
-
#==========================
|
7
|
-
#
|
8
|
-
# Takes an error message and drow an image file of the very message
|
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
|
-
class ErrorMessage
|
17
|
-
|
18
|
-
def initialize(text, font, font_size, filename, format)
|
19
|
-
|
20
|
-
@text = text
|
21
|
-
@font = font
|
22
|
-
@font_size = font_size
|
23
|
-
@filename = filename
|
24
|
-
@format = format
|
25
|
-
|
26
|
-
metrics = img_get_txt_metrics(text, font, font_size, NoDecoration, true)
|
27
|
-
|
28
|
-
@im = Image.new(metrics.width, metrics.height)
|
29
|
-
@gc = Draw.new
|
30
|
-
@gc.font = font
|
31
|
-
@gc.pointsize = font_size
|
32
|
-
@gc.stroke("transparent")
|
33
|
-
@gc.fill("black")
|
34
|
-
@gc.gravity(CenterGravity)
|
35
|
-
@gc.text(0, 0, text)
|
36
|
-
end
|
37
|
-
|
38
|
-
def img_get_txt_metrics(text, font, font_size, multiline)
|
39
|
-
|
40
|
-
background = Image.new(500, 250)
|
41
|
-
|
42
|
-
gc = Draw.new
|
43
|
-
gc.annotate(background, 0, 0, 0, 0, text) do |gc|
|
44
|
-
gc.font = font
|
45
|
-
gc.pointsize = font_size
|
46
|
-
gc.gravity = CenterGravity
|
47
|
-
gc.stroke = 'none'
|
48
|
-
end
|
49
|
-
|
50
|
-
if multiline
|
51
|
-
metrics = gc.get_multiline_type_metrics(background, text)
|
52
|
-
else
|
53
|
-
metrics = gc.get_type_metrics(background, text)
|
54
|
-
end
|
55
|
-
|
56
|
-
return metrics
|
57
|
-
end
|
58
|
-
|
59
|
-
def draw
|
60
|
-
@gc.draw(@im)
|
61
|
-
end
|
62
|
-
|
63
|
-
def save
|
64
|
-
@gc.draw(@im)
|
65
|
-
@im.write(@filename + "." + @format)
|
66
|
-
end
|
67
|
-
|
68
|
-
end
|
data/lib/rsyntaxtree/graph.rb
DELETED
@@ -1,312 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
# -*- coding: utf-8 -*-
|
3
|
-
|
4
|
-
#==========================
|
5
|
-
# graph.rb
|
6
|
-
#==========================
|
7
|
-
#
|
8
|
-
# Image utility functions to inspect text font metrics
|
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 'rmagick'
|
17
|
-
include Magick
|
18
|
-
|
19
|
-
class Graph
|
20
|
-
|
21
|
-
def initialize(e_list, metrics, symmetrize, color, leafstyle, multibyte, font, font_size)
|
22
|
-
|
23
|
-
# Set class-specific parameters beforehand in subclass
|
24
|
-
|
25
|
-
# Store parameters
|
26
|
-
@e_list = e_list
|
27
|
-
@m = metrics
|
28
|
-
@multibyte = multibyte
|
29
|
-
@leafstyle = leafstyle
|
30
|
-
@symmetrize = symmetrize
|
31
|
-
|
32
|
-
# Calculate image dimensions
|
33
|
-
@e_height = font_size + @m[:e_padd] * 2
|
34
|
-
h = @e_list.get_level_height
|
35
|
-
w = calc_level_width(0)
|
36
|
-
@width = w
|
37
|
-
@height = h * @e_height + (h-1) * (@m[:v_space] + font_size) + @m[:b_topbot] * 2
|
38
|
-
|
39
|
-
# Initialize the image and colors
|
40
|
-
@col_bg = "none"
|
41
|
-
@col_fg = "black"
|
42
|
-
@col_line = "black"
|
43
|
-
|
44
|
-
if color
|
45
|
-
@col_node = "blue"
|
46
|
-
@col_leaf = "green"
|
47
|
-
@col_trace = "red"
|
48
|
-
else
|
49
|
-
@col_node = "black"
|
50
|
-
@col_leaf = "black"
|
51
|
-
@col_trace = "black"
|
52
|
-
end
|
53
|
-
|
54
|
-
@main_height = img_get_txt_height("l", font, font_size)
|
55
|
-
@sub_size = (font_size * SUBSCRIPT_CONST)
|
56
|
-
@sub_space_width = img_get_txt_width("l", font, @sub_size)
|
57
|
-
end
|
58
|
-
|
59
|
-
def img_get_txt_metrics(text, font, font_size, multiline)
|
60
|
-
|
61
|
-
background = Image.new(1, 1)
|
62
|
-
|
63
|
-
gc = Draw.new
|
64
|
-
gc.annotate(background, 0, 0, 0, 0, text) do |gc|
|
65
|
-
gc.font = font
|
66
|
-
gc.pointsize = font_size
|
67
|
-
gc.gravity = CenterGravity
|
68
|
-
gc.stroke = 'none'
|
69
|
-
gc.kerning = 0
|
70
|
-
gc.interline_spacing = 0
|
71
|
-
gc.interword_spacing = 0
|
72
|
-
end
|
73
|
-
|
74
|
-
if multiline
|
75
|
-
metrics = gc.get_multiline_type_metrics(background, text)
|
76
|
-
else
|
77
|
-
metrics = gc.get_type_metrics(background, text)
|
78
|
-
end
|
79
|
-
return metrics
|
80
|
-
end
|
81
|
-
|
82
|
-
# Calculate the width of the element. If the element is
|
83
|
-
# a node, the calculation will be performed recursively
|
84
|
-
# for all child elements.
|
85
|
-
def calc_element_width(e)
|
86
|
-
w = 0
|
87
|
-
content = e.content.gsub("<>", " ")
|
88
|
-
|
89
|
-
children = @e_list.get_children(e.id)
|
90
|
-
|
91
|
-
if(children.length == 0)
|
92
|
-
w = img_get_txt_width(content, @font, @font_size) + @font_size
|
93
|
-
else
|
94
|
-
children.each do |child|
|
95
|
-
child_e = @e_list.get_id(child)
|
96
|
-
w += calc_element_width(child_e)
|
97
|
-
end
|
98
|
-
|
99
|
-
tw = img_get_txt_width(content, @font, @font_size) + @font_size
|
100
|
-
if(tw > w)
|
101
|
-
fix_child_size(e.id, w, tw)
|
102
|
-
w = tw
|
103
|
-
end
|
104
|
-
end
|
105
|
-
|
106
|
-
@e_list.set_element_width(e.id, w)
|
107
|
-
return w
|
108
|
-
end
|
109
|
-
|
110
|
-
# Calculate the width of all elements in a certain level
|
111
|
-
def calc_level_width(level)
|
112
|
-
w = 0
|
113
|
-
e = @e_list.get_first
|
114
|
-
while e
|
115
|
-
if(e.level == level)
|
116
|
-
x = calc_element_width(e)
|
117
|
-
w += x
|
118
|
-
end
|
119
|
-
e = @e_list.get_next
|
120
|
-
end
|
121
|
-
return w
|
122
|
-
end
|
123
|
-
|
124
|
-
def calc_children_width(id)
|
125
|
-
left = 0
|
126
|
-
right = 0
|
127
|
-
c_list = @e_list.get_children(id)
|
128
|
-
return nil if c_list.empty?
|
129
|
-
|
130
|
-
c_list.each do |c|
|
131
|
-
left = c.indent if indent == 0 or left > c.indent
|
132
|
-
end
|
133
|
-
c_list.each do |c|
|
134
|
-
right = c.indent + e.width if c.indent + c.width > right
|
135
|
-
end
|
136
|
-
return [left, right]
|
137
|
-
end
|
138
|
-
|
139
|
-
def get_children_indent(id)
|
140
|
-
calc_children_width(id)[0]
|
141
|
-
end
|
142
|
-
|
143
|
-
def get_children_width(id)
|
144
|
-
calc_children_width(id)[1] - get_children_indent(id)
|
145
|
-
end
|
146
|
-
|
147
|
-
# Parse the elements in the list top to bottom and
|
148
|
-
# draw the elements into the image.
|
149
|
-
# As we it iterate through the levels, the element
|
150
|
-
# indentation is calculated.
|
151
|
-
def parse_list
|
152
|
-
|
153
|
-
# Calc element list recursively....
|
154
|
-
e_arr = @e_list.get_elements
|
155
|
-
|
156
|
-
h = @e_list.get_level_height
|
157
|
-
|
158
|
-
h.times do |i|
|
159
|
-
x = 0
|
160
|
-
e_arr.each do |j|
|
161
|
-
|
162
|
-
if (j.level == i)
|
163
|
-
cw = @e_list.get_element_width(j.id)
|
164
|
-
parent_indent = @e_list.get_indent(j.parent)
|
165
|
-
if (x < parent_indent)
|
166
|
-
x = parent_indent
|
167
|
-
end
|
168
|
-
@e_list.set_indent(j.id, x)
|
169
|
-
|
170
|
-
if !@symmetrize
|
171
|
-
draw_element(x, i, cw, j.content, j.type)
|
172
|
-
if(j.parent != 0 )
|
173
|
-
words = j.content.split(" ")
|
174
|
-
unless @leafstyle == "nothing" && ETYPE_LEAF == j.type
|
175
|
-
if (@leafstyle == "auto" && ETYPE_LEAF == j.type && x == parent_indent)
|
176
|
-
if words.length > 1 || j.triangle
|
177
|
-
txt_width = img_get_txt_width(j.content, @font, @font_size)
|
178
|
-
triangle_to_parent(x, i, cw, txt_width, @symmetrize)
|
179
|
-
else
|
180
|
-
line_to_parent(x, i, cw, @e_list.get_indent(j.parent), @e_list.get_element_width(j.parent))
|
181
|
-
end
|
182
|
-
else
|
183
|
-
line_to_parent(x, i, cw, @e_list.get_indent(j.parent), @e_list.get_element_width(j.parent))
|
184
|
-
end
|
185
|
-
end
|
186
|
-
end
|
187
|
-
end
|
188
|
-
x += cw
|
189
|
-
end
|
190
|
-
end
|
191
|
-
end
|
192
|
-
return true if !@symmetrize
|
193
|
-
|
194
|
-
elements_to_draw = {}
|
195
|
-
triangles_to_draw = []
|
196
|
-
lines_to_draw = []
|
197
|
-
|
198
|
-
lmost = {:level => nil, :value => nil, :type => nil}
|
199
|
-
rmost = nil
|
200
|
-
h.times do |i|
|
201
|
-
curlevel = h - i - 1
|
202
|
-
e_arr.each_with_index do |j, idx|
|
203
|
-
if (j.level == curlevel)
|
204
|
-
# Draw a line to the parent element
|
205
|
-
children = @e_list.get_children(j.id)
|
206
|
-
|
207
|
-
tw = img_get_txt_width(j.content, @font, @font_size)
|
208
|
-
if children.length > 0
|
209
|
-
left, right = -1, -1
|
210
|
-
children.each do |child|
|
211
|
-
k = @e_list.get_id(child)
|
212
|
-
kw = img_get_txt_width(k.content, @font, @font_size)
|
213
|
-
left = k.indent + kw / 2 if k.indent + kw / 2 < left or left == -1
|
214
|
-
right = k.indent + kw / 2 if k.indent + kw / 2 > right
|
215
|
-
end
|
216
|
-
|
217
|
-
elements_to_draw[j.id] = {:left => left, :curlevel => curlevel, :width => right - left, :content => j.content, :type => j.type}
|
218
|
-
@e_list.set_indent(j.id, left + (right - left) / 2 - tw / 2)
|
219
|
-
|
220
|
-
children.each do |child|
|
221
|
-
k = @e_list.get_id(child)
|
222
|
-
words = k.content.split(" ")
|
223
|
-
dw = img_get_txt_width(k.content, @font, @font_size)
|
224
|
-
|
225
|
-
children2 = @e_list.get_children(k.id)
|
226
|
-
|
227
|
-
unless @leafstyle == "nothing" && ETYPE_LEAF == k.type
|
228
|
-
if (@leafstyle == "auto" && ETYPE_LEAF == k.type)
|
229
|
-
if words.length > 1 || k.triangle
|
230
|
-
txt_width = img_get_txt_width(k.content, @font, @font_size)
|
231
|
-
triangles_to_draw << {:indent => k.indent, :curlevel => curlevel + 1, :width1 => dw, :width2 => txt_width}
|
232
|
-
else
|
233
|
-
lines_to_draw << {:indent1 => k.indent, :curlevel => curlevel + 1, :width1 => dw, :indent2 => j.indent, :width2 => tw}
|
234
|
-
end
|
235
|
-
else
|
236
|
-
lines_to_draw << {:indent1 => k.indent, :curlevel => curlevel + 1, :width1 => dw, :indent2 => j.indent, :width2 => tw}
|
237
|
-
end
|
238
|
-
end
|
239
|
-
end
|
240
|
-
|
241
|
-
end
|
242
|
-
elements = e_arr.select do |l|
|
243
|
-
l.level == curlevel && @e_list.get_children(l.id).empty?
|
244
|
-
end
|
245
|
-
|
246
|
-
elements.each.with_index do |l, idx|
|
247
|
-
lw = img_get_txt_width(l.content, @font, @font_size)
|
248
|
-
left = l.indent
|
249
|
-
right = left + lw
|
250
|
-
unless elements_to_draw.include? l.id
|
251
|
-
elements_to_draw[l.id] = {:left => left, :curlevel => curlevel, :width => right - left, :content => l.content, :type => l.type}
|
252
|
-
end
|
253
|
-
end
|
254
|
-
end
|
255
|
-
end
|
256
|
-
|
257
|
-
e_arr.each do |e|
|
258
|
-
lpos = e.indent - img_get_txt_width(e.content, @font, @font_size) / 2
|
259
|
-
next if lpos > 0
|
260
|
-
if !lmost[:value] || lmost[:value] > lpos
|
261
|
-
lmost[:level] = e.level
|
262
|
-
lmost[:value] = lpos
|
263
|
-
lmost[:type] = e
|
264
|
-
end
|
265
|
-
rpos = e.indent + e.width
|
266
|
-
rmost = rpos if !rmost || rmost < rpos
|
267
|
-
end
|
268
|
-
end
|
269
|
-
|
270
|
-
offset = 0
|
271
|
-
if lmost[:level] != h - 1
|
272
|
-
offset = lmost[:value] / -2
|
273
|
-
new_width = rmost
|
274
|
-
@width = new_width + offset
|
275
|
-
end
|
276
|
-
|
277
|
-
elements_to_draw.each do |k, v|
|
278
|
-
draw_element(v[:left] + offset, v[:curlevel], v[:width], v[:content], v[:type])
|
279
|
-
end
|
280
|
-
triangles_to_draw.each do |v|
|
281
|
-
triangle_to_parent(v[:indent] + offset, v[:curlevel], v[:width1], v[:width2])
|
282
|
-
end
|
283
|
-
lines_to_draw.each do |v|
|
284
|
-
line_to_parent(v[:indent1] + offset, v[:curlevel], v[:width1], v[:indent2] + offset, v[:width2])
|
285
|
-
end
|
286
|
-
end
|
287
|
-
|
288
|
-
# Calculate top position from row (level)
|
289
|
-
def row2px(row)
|
290
|
-
@m[:b_topbot] + @e_height * row + (@m[:v_space] + @font_size) * row
|
291
|
-
end
|
292
|
-
|
293
|
-
def get_txt_only(text)
|
294
|
-
text = text.strip
|
295
|
-
if /\A([\+\-\=\*\#\~]+).+/ =~ text
|
296
|
-
prefix = $1
|
297
|
-
prefix_l = Regexp.escape(prefix)
|
298
|
-
prefix_r = Regexp.escape(prefix.reverse)
|
299
|
-
if /\A#{prefix_l}(.+)#{prefix_r}\z/ =~ text
|
300
|
-
return $1
|
301
|
-
end
|
302
|
-
end
|
303
|
-
return text
|
304
|
-
end
|
305
|
-
|
306
|
-
def img_get_txt_height(text, font, font_size, multiline = true)
|
307
|
-
metrics = img_get_txt_metrics(text, font, font_size, multiline)
|
308
|
-
# y = (metrics.bounds.y2 - metrics.bounds.y1).round
|
309
|
-
y = metrics.height
|
310
|
-
return y
|
311
|
-
end
|
312
|
-
end
|