hokusai-zero 0.1.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.
Files changed (166) hide show
  1. checksums.yaml +7 -0
  2. data/Dockerfile +26 -0
  3. data/Gemfile +15 -0
  4. data/Gemfile.lock +91 -0
  5. data/LICENSE +21 -0
  6. data/README.md +28 -0
  7. data/ast/genheader +3 -0
  8. data/ast/include/hashmap.c +1151 -0
  9. data/ast/include/hashmap.c.license +20 -0
  10. data/ast/include/hashmap.h +54 -0
  11. data/ast/src/core/ast.c +448 -0
  12. data/ast/src/core/ast.h +259 -0
  13. data/ast/src/core/common.h +24 -0
  14. data/ast/src/core/component.c +85 -0
  15. data/ast/src/core/component.h +35 -0
  16. data/ast/src/core/hml.c +665 -0
  17. data/ast/src/core/hml.h +11 -0
  18. data/ast/src/core/input.c +458 -0
  19. data/ast/src/core/input.h +118 -0
  20. data/ast/src/core/style.c +101 -0
  21. data/ast/src/core/style.h +41 -0
  22. data/ast/src/core/text.c +784 -0
  23. data/ast/src/core/text.h +93 -0
  24. data/ast/src/core/util.c +140 -0
  25. data/ast/src/core/util.h +48 -0
  26. data/ast/src/hokusai.c +6 -0
  27. data/ast/src/hokusai.h +6 -0
  28. data/ast/test/fixtures/test.ui +13 -0
  29. data/ast/test/greatest.h +1266 -0
  30. data/ast/test/hokusai.c +14 -0
  31. data/ast/test/parser.c +234 -0
  32. data/ast/test/text.c +116 -0
  33. data/ext/extconf.rb +27 -0
  34. data/grammar/Cargo.lock +80 -0
  35. data/grammar/Cargo.toml +26 -0
  36. data/grammar/binding.gyp +20 -0
  37. data/grammar/bindings/node/binding.cc +28 -0
  38. data/grammar/bindings/node/index.js +19 -0
  39. data/grammar/bindings/rust/build.rs +40 -0
  40. data/grammar/bindings/rust/lib.rs +52 -0
  41. data/grammar/corpus/1_document.txt +131 -0
  42. data/grammar/corpus/2_selectors.txt +58 -0
  43. data/grammar/corpus/3_spaces.txt +69 -0
  44. data/grammar/corpus/4_errors.txt +10 -0
  45. data/grammar/corpus/5_macros.txt +175 -0
  46. data/grammar/corpus/6_styles.txt +81 -0
  47. data/grammar/grammar.js +275 -0
  48. data/grammar/package-lock.json +34 -0
  49. data/grammar/package.json +33 -0
  50. data/grammar/src/grammar.json +1269 -0
  51. data/grammar/src/node-types.json +474 -0
  52. data/grammar/src/parser.c +5772 -0
  53. data/grammar/src/scanner.c +258 -0
  54. data/grammar/src/tree_sitter/parser.h +230 -0
  55. data/grammar/src/tree_sitter/scanner.h +12 -0
  56. data/grammar/test.nml +10 -0
  57. data/hokusai.gemspec +19 -0
  58. data/ui/examples/assets/DigitalDisplay.ttf +0 -0
  59. data/ui/examples/assets/OpenSans-Regular.ttf +0 -0
  60. data/ui/examples/assets/addy.png +0 -0
  61. data/ui/examples/assets/baby_sean.png +0 -0
  62. data/ui/examples/assets/football-troll.png +0 -0
  63. data/ui/examples/assets/gear.png +0 -0
  64. data/ui/examples/assets/icecold.ttf +0 -0
  65. data/ui/examples/assets/science-troll.png +0 -0
  66. data/ui/examples/buddy.rb +31 -0
  67. data/ui/examples/clock.rb +58 -0
  68. data/ui/examples/counter.rb +123 -0
  69. data/ui/examples/dynamic.rb +147 -0
  70. data/ui/examples/foobar.rb +236 -0
  71. data/ui/examples/stock.rb +115 -0
  72. data/ui/examples/stock_decider/option.rb +74 -0
  73. data/ui/examples/tic_tac_toe.rb +246 -0
  74. data/ui/lib/lib_hokusai.rb +425 -0
  75. data/ui/spec/hokusai/ast_spec.rb +88 -0
  76. data/ui/spec/hokusai/automation/keys_transcoder_spec.rb +50 -0
  77. data/ui/spec/hokusai/automation/selector_spec.rb +68 -0
  78. data/ui/spec/hokusai/block_spec.rb +126 -0
  79. data/ui/spec/hokusai/directives_spec.rb +327 -0
  80. data/ui/spec/hokusai/e2e/client_spec.rb +58 -0
  81. data/ui/spec/hokusai/e2e/meta_spec.rb +42 -0
  82. data/ui/spec/hokusai/publisher_spec.rb +38 -0
  83. data/ui/spec/hokusai/slots_spec.rb +150 -0
  84. data/ui/spec/hokusai/util/piece_table_spec.rb +90 -0
  85. data/ui/spec/hokusai_spec.rb +0 -0
  86. data/ui/spec/spec_helper.rb +30 -0
  87. data/ui/src/hokusai/ast.rb +446 -0
  88. data/ui/src/hokusai/automation/client.rb +167 -0
  89. data/ui/src/hokusai/automation/constants.rb +98 -0
  90. data/ui/src/hokusai/automation/converters/selector_converter.rb +61 -0
  91. data/ui/src/hokusai/automation/driver.rb +54 -0
  92. data/ui/src/hokusai/automation/driver_command_queue.rb +50 -0
  93. data/ui/src/hokusai/automation/driver_commands/base.rb +79 -0
  94. data/ui/src/hokusai/automation/driver_commands/get_attribute.rb +41 -0
  95. data/ui/src/hokusai/automation/driver_commands/invoke.rb +33 -0
  96. data/ui/src/hokusai/automation/driver_commands/locate.rb +48 -0
  97. data/ui/src/hokusai/automation/driver_commands/trigger_keyboard.rb +94 -0
  98. data/ui/src/hokusai/automation/driver_commands/trigger_mouse.rb +213 -0
  99. data/ui/src/hokusai/automation/keys_transcoder.rb +128 -0
  100. data/ui/src/hokusai/automation/selector.rb +39 -0
  101. data/ui/src/hokusai/automation/server.rb +114 -0
  102. data/ui/src/hokusai/automation.rb +3 -0
  103. data/ui/src/hokusai/backends/raylib/config.rb +47 -0
  104. data/ui/src/hokusai/backends/raylib/font.rb +113 -0
  105. data/ui/src/hokusai/backends/raylib/keys.rb +124 -0
  106. data/ui/src/hokusai/backends/raylib.rb +449 -0
  107. data/ui/src/hokusai/backends/sdl2/Monaco.ttf +0 -0
  108. data/ui/src/hokusai/backends/sdl2/color.rb +12 -0
  109. data/ui/src/hokusai/backends/sdl2/config.rb +31 -0
  110. data/ui/src/hokusai/backends/sdl2/font.rb +127 -0
  111. data/ui/src/hokusai/backends/sdl2/keys.rb +119 -0
  112. data/ui/src/hokusai/backends/sdl2.rb +529 -0
  113. data/ui/src/hokusai/block.rb +237 -0
  114. data/ui/src/hokusai/blocks/button.rb +100 -0
  115. data/ui/src/hokusai/blocks/checkbox.rb +51 -0
  116. data/ui/src/hokusai/blocks/circle.rb +28 -0
  117. data/ui/src/hokusai/blocks/clipped.rb +23 -0
  118. data/ui/src/hokusai/blocks/cursor.rb +49 -0
  119. data/ui/src/hokusai/blocks/dynamic.rb +37 -0
  120. data/ui/src/hokusai/blocks/empty.rb +10 -0
  121. data/ui/src/hokusai/blocks/hblock.rb +35 -0
  122. data/ui/src/hokusai/blocks/image.rb +18 -0
  123. data/ui/src/hokusai/blocks/input.rb +200 -0
  124. data/ui/src/hokusai/blocks/label.rb +39 -0
  125. data/ui/src/hokusai/blocks/panel.rb +126 -0
  126. data/ui/src/hokusai/blocks/rect.rb +24 -0
  127. data/ui/src/hokusai/blocks/scissor_begin.rb +18 -0
  128. data/ui/src/hokusai/blocks/scissor_end.rb +12 -0
  129. data/ui/src/hokusai/blocks/scrollbar.rb +103 -0
  130. data/ui/src/hokusai/blocks/selectable.rb +77 -0
  131. data/ui/src/hokusai/blocks/svg.rb +20 -0
  132. data/ui/src/hokusai/blocks/text.rb +214 -0
  133. data/ui/src/hokusai/blocks/titlebar/osx.rb +145 -0
  134. data/ui/src/hokusai/blocks/toggle.rb +55 -0
  135. data/ui/src/hokusai/blocks/vblock.rb +35 -0
  136. data/ui/src/hokusai/commands/base.rb +22 -0
  137. data/ui/src/hokusai/commands/circle.rb +47 -0
  138. data/ui/src/hokusai/commands/image.rb +45 -0
  139. data/ui/src/hokusai/commands/rect.rb +158 -0
  140. data/ui/src/hokusai/commands/scissor.rb +22 -0
  141. data/ui/src/hokusai/commands/text.rb +92 -0
  142. data/ui/src/hokusai/commands.rb +87 -0
  143. data/ui/src/hokusai/diff.rb +124 -0
  144. data/ui/src/hokusai/error.rb +3 -0
  145. data/ui/src/hokusai/event.rb +54 -0
  146. data/ui/src/hokusai/events/keyboard.rb +84 -0
  147. data/ui/src/hokusai/events/mouse.rb +172 -0
  148. data/ui/src/hokusai/font.rb +280 -0
  149. data/ui/src/hokusai/meta.rb +152 -0
  150. data/ui/src/hokusai/mounting/loop_entry.rb +230 -0
  151. data/ui/src/hokusai/mounting/mount_entry.rb +74 -0
  152. data/ui/src/hokusai/mounting/update_entry.rb +101 -0
  153. data/ui/src/hokusai/node.rb +98 -0
  154. data/ui/src/hokusai/node_mounter.rb +102 -0
  155. data/ui/src/hokusai/painter.rb +214 -0
  156. data/ui/src/hokusai/publisher.rb +32 -0
  157. data/ui/src/hokusai/style.rb +72 -0
  158. data/ui/src/hokusai/types.rb +266 -0
  159. data/ui/src/hokusai/util/clamping_iterator.rb +202 -0
  160. data/ui/src/hokusai/util/piece_table.rb +111 -0
  161. data/ui/src/hokusai/util/selection.rb +145 -0
  162. data/ui/src/hokusai.rb +120 -0
  163. data/ui/vendor/.gitkeep +0 -0
  164. data/vendor/.gitkeep +0 -0
  165. data/xmake.lua +192 -0
  166. metadata +222 -0
@@ -0,0 +1,172 @@
1
+ module Hokusai
2
+ class MouseEvent < Event
3
+ extend Forwardable
4
+
5
+ attr_reader :input, :state
6
+
7
+ def initialize(input, state)
8
+ @input = input
9
+ @mouse = input.mouse
10
+ @left = @mouse.left
11
+ @right = @mouse.right
12
+ @middle = @mouse.middle
13
+ @state = state
14
+ end
15
+
16
+ def mouse
17
+ @mouse
18
+ end
19
+
20
+ def pos
21
+ mouse.pos
22
+ end
23
+
24
+ def delta
25
+ mouse.delta
26
+ end
27
+
28
+ def scroll
29
+ mouse.scroll
30
+ end
31
+
32
+ def scroll_delta
33
+ mouse.scroll_delta
34
+ end
35
+
36
+ def left
37
+ @left
38
+ end
39
+
40
+ def right
41
+ @right
42
+ end
43
+
44
+ def middle
45
+ @middle
46
+ end
47
+
48
+ def to_json
49
+ hash = {}
50
+ hash[:pos] = { x: pos.x, y: pos.y }
51
+
52
+ [:left, :right, :middle].each do |button|
53
+ hash[button] = {
54
+ down: send(button).down,
55
+ up: send(button).up,
56
+ clicked: send(button).clicked,
57
+ released: send(button).released
58
+ }
59
+ end
60
+
61
+ hash[:scroll] = scroll
62
+ hash[:scroll_delta] = scroll_delta
63
+
64
+ hash.to_json
65
+ end
66
+
67
+ protected
68
+
69
+ def hovered(canvas)
70
+ LibHokusai.hoku_input_is_hovered(input.raw, canvas.to_hoku_rect)
71
+ end
72
+ end
73
+
74
+ class MouseMoveEvent < MouseEvent
75
+ name "mousemove"
76
+
77
+ def capture(block, _)
78
+ if matches(block) #&& (delta.y != 0.0000000000 && delta.x != 0.0000000000)
79
+ captures << block
80
+ end
81
+ end
82
+ end
83
+
84
+ class ClickEvent < MouseEvent
85
+ name "click"
86
+
87
+ def capture(block, canvas)
88
+ if left[:clicked] && clicked(canvas)
89
+ block.node.meta.focus
90
+
91
+ if matches(block)
92
+ captures << block
93
+ end
94
+ elsif left[:clicked]
95
+ block.node.meta.blur
96
+ end
97
+ end
98
+
99
+ def clicked(canvas)
100
+ LibHokusai.hoku_input_is_clicked(input.raw, canvas.to_hoku_rect)
101
+ end
102
+ end
103
+
104
+ class MouseUpEvent < MouseEvent
105
+ name "mouseup"
106
+
107
+ def capture(block, _)
108
+ if left[:up] && matches(block)
109
+ captures << block
110
+ end
111
+ end
112
+ end
113
+
114
+ class MouseDownEvent < MouseEvent
115
+ name "mousedown"
116
+
117
+ def capture(block, _)
118
+ if left[:down] && matches(block)
119
+ captures << block
120
+ end
121
+ end
122
+ end
123
+
124
+ class WheelEvent < MouseEvent
125
+ name "wheel"
126
+
127
+ def capture(block, _)
128
+ if matches(block) && scroll_delta != 0.0
129
+ captures << block
130
+ end
131
+ end
132
+ end
133
+
134
+ class HoverEvent < MouseEvent
135
+ name "hover"
136
+
137
+ def capture(block, _)
138
+ captures << block
139
+ end
140
+
141
+ def bubble
142
+ while block = captures.pop
143
+ block.emit(name, self)
144
+
145
+ cursor = block.node.meta.get_prop(:cursor)&.to_sym
146
+
147
+ if !state.set && cursor == :manual
148
+ state.set = true
149
+ end
150
+
151
+ if !state.set && cursor && cursor != :manual
152
+ Hokusai.set_mouse_cursor(cursor)
153
+ state.set = true
154
+ end
155
+
156
+ break if stopped
157
+ end
158
+
159
+ if !state.nil? && !state.set
160
+ Hokusai.set_mouse_cursor(:default)
161
+ end
162
+ end
163
+ end
164
+
165
+ class MouseOutEvent < MouseEvent
166
+ name "mouseout"
167
+
168
+ def capture(block, _)
169
+ captures << block if matches(block)
170
+ end
171
+ end
172
+ end
@@ -0,0 +1,280 @@
1
+ module Hokusai
2
+ class Font
3
+ def clamp(text, size, width, initial_offset = 0.0)
4
+ raise Hokusai::Error.new("Font #clamp not implemented")
5
+ end
6
+
7
+ def clamp_markdown(text, size, width, initial_offset = 0.0)
8
+ raise Hokusai::Error.new("Font #clamp not implemented")
9
+ end
10
+
11
+ def height
12
+ raise Hokusai::Error.new("Font #height not implemented")
13
+ end
14
+ end
15
+
16
+ class Clamping
17
+ class Char
18
+ attr_reader :raw
19
+ def initialize(raw)
20
+ @raw = raw
21
+ end
22
+
23
+ def width
24
+ raw[:width]
25
+ end
26
+
27
+ def offset
28
+ raw[:offset]
29
+ end
30
+ end
31
+
32
+ class Group
33
+ attr_reader :raw
34
+
35
+ def initialize(raw)
36
+ @raw = raw
37
+ end
38
+
39
+ def offset
40
+ @offset ||= raw[:offset]
41
+ end
42
+
43
+ def size
44
+ @size ||= raw[:size]
45
+ end
46
+
47
+ def width
48
+ chars.sum(&:width)
49
+ end
50
+
51
+ def type
52
+ @type ||= raw[:type]
53
+ end
54
+
55
+ def normal?
56
+ @normal ||= type == LibHokusai::GROUP_NORMAL
57
+ end
58
+
59
+ def bold?
60
+ @bold ||= ((type & LibHokusai::GROUP_BOLD) != 0)
61
+ end
62
+
63
+ def italics?
64
+ @italics ||= ((type & LibHokusai::GROUP_ITALICS) != 0)
65
+ end
66
+
67
+ def link?
68
+ @link ||= ((type & LibHokusai::GROUP_LINK) != 0)
69
+ end
70
+
71
+ def code?
72
+ @code ||= type & LibHokusai::GROUP_CODE
73
+ end
74
+
75
+ def link
76
+ @href ||= raw[:payload].read_string
77
+ end
78
+
79
+ def chars
80
+ return @chars unless @chars.nil?
81
+
82
+ @chars = []
83
+ each_char do |char|
84
+ @chars << char
85
+ end
86
+
87
+ @chars
88
+ end
89
+
90
+ def each_char
91
+ char = raw[:chars]
92
+ i = 0
93
+
94
+ while !char.null?
95
+ yield Char.new(char), i
96
+ i += 1
97
+ char = char[:next_char]
98
+ end
99
+ end
100
+ end
101
+
102
+ class Segment
103
+ attr_reader :raw
104
+
105
+ def initialize(raw)
106
+ @raw = raw
107
+ end
108
+
109
+ def width(range = (offset...offset + size))
110
+ chars[range]&.sum(&:width) || 0.0
111
+ end
112
+
113
+ def offset
114
+ raw[:offset]
115
+ end
116
+
117
+ def size
118
+ raw[:size]
119
+ end
120
+
121
+ def chars
122
+ return @chars unless @chars.nil?
123
+
124
+ @chars = []
125
+ each_char do |char|
126
+ @chars << char
127
+ end
128
+
129
+ @chars
130
+ end
131
+
132
+ def each_char
133
+ char = raw[:chars]
134
+ i = 0
135
+
136
+ while !char.null?
137
+ yield Char.new(char), i
138
+ i += 1
139
+ char = char[:next_char]
140
+ end
141
+ end
142
+
143
+ def groups
144
+ return @groups unless @groups.nil?
145
+
146
+ @groups = []
147
+ each_group do |group|
148
+ @groups << group
149
+ end
150
+
151
+ @groups
152
+ end
153
+
154
+ def each_group
155
+ group = raw[:groups]
156
+ i = 0
157
+ until group.null?
158
+ yield Group.new(group), i
159
+ i.succ
160
+ group = group[:next_group]
161
+ end
162
+ end
163
+
164
+ def select_end
165
+ raw[:select_end]
166
+ end
167
+
168
+ def select_begin
169
+ raw[:select_begin]
170
+ end
171
+
172
+ def select_begin=(val)
173
+ raw[:select_begin] = val
174
+ end
175
+
176
+ def select_end=(val)
177
+ raw[:select_end] = val.nil? ? select_begin : val
178
+ end
179
+
180
+ def has_selection?
181
+ !select_end.nil? && !select_begin.nil?
182
+ end
183
+
184
+ def char_is_selected(char)
185
+ return false if select_begin.nil? || select_end.nil?
186
+
187
+ (select_begin..select_end).include?(char.offset)
188
+ end
189
+
190
+ def make_selection(start, stop)
191
+ self.select_begin = start
192
+ self.select_end = stop
193
+ end
194
+ end
195
+
196
+ attr_reader :raw, :markdown
197
+
198
+ def initialize(raw, markdown: false)
199
+ @markdown = markdown
200
+ @raw = raw
201
+ end
202
+
203
+ def segments
204
+ return @segments unless @segments.nil?
205
+
206
+ @segments = []
207
+ each_segment do |segment|
208
+ @segments << segment
209
+ end
210
+
211
+ @segments
212
+ end
213
+
214
+ def debug
215
+ LibHokusai.hoku_text_clamp_debug(raw)
216
+ end
217
+
218
+ def each_segment
219
+ segment = raw[:segments]
220
+ i = 0
221
+
222
+ until segment.null?
223
+ yield Segment.new(segment), i
224
+ i += 1
225
+
226
+
227
+ segment = segment[:next_segment]
228
+ end
229
+ end
230
+
231
+ def text(segment)
232
+ raw[:text][segment.offset, segment.size]
233
+ end
234
+
235
+ def [](offset, size)
236
+ raw[:text][offset, size]
237
+ end
238
+
239
+ def to_a
240
+ segments.map do |segment|
241
+ text(segment)
242
+ end
243
+ end
244
+ end
245
+
246
+ class FontRegistry
247
+ attr_reader :fonts, :active_font
248
+
249
+ def initialize
250
+ @fonts = {}
251
+ @active_font = nil
252
+ end
253
+
254
+ def register(name, font)
255
+ raise Hokusai::Error.new("Font #{name} already registered") if fonts[name]
256
+
257
+ fonts[name] = font
258
+ end
259
+
260
+ def active_font_name
261
+ raise Hokusai::Error.new("No active font") if active_font.nil?
262
+
263
+ active_font
264
+ end
265
+
266
+ def activate(name)
267
+ raise Hokusai::Error.new("Font #{name} is not registered") unless fonts[name]
268
+
269
+ @active_font = name
270
+ end
271
+
272
+ def get(name)
273
+ fonts[name]
274
+ end
275
+
276
+ def active
277
+ fonts[active_font]
278
+ end
279
+ end
280
+ end
@@ -0,0 +1,152 @@
1
+ require_relative "./publisher"
2
+
3
+ module Hokusai
4
+ class Meta
5
+ attr_reader :focused, :parent, :target, :updater,
6
+ :props, :publisher
7
+
8
+ def self.commands
9
+ @commands ||= Commands.new
10
+ end
11
+
12
+ def initialize
13
+ @focused = false
14
+ @parent = nil
15
+ @target = nil
16
+ @updater = nil
17
+ @props = nil
18
+ @publisher = Publisher.new
19
+ @children = nil
20
+ end
21
+
22
+ def node_count
23
+ count = children?&.size || 0
24
+
25
+ children?&.each do |child|
26
+ count += child.node.meta.node_count
27
+ end
28
+
29
+ count
30
+ end
31
+
32
+ def get_child?(index)
33
+ return nil if @children.nil?
34
+
35
+ get_child(index)
36
+ end
37
+
38
+ def children=(values)
39
+ @children = values
40
+ end
41
+
42
+ def children?
43
+ return nil if @children.nil?
44
+
45
+ @children
46
+ end
47
+
48
+ def <<(child)
49
+ children! << child
50
+ end
51
+
52
+ def get_child(index)
53
+ children![index]
54
+ end
55
+
56
+ def set_child(index, value)
57
+ children![index] = value
58
+ end
59
+
60
+ def children!
61
+ @children ||= []
62
+ end
63
+
64
+ def props!
65
+ @props ||= {}
66
+ end
67
+
68
+ def get_prop?(name)
69
+ return nil if @props.nil?
70
+
71
+ get_prop(name)
72
+ end
73
+
74
+ def set_prop(name, value)
75
+ @props ||= {}
76
+
77
+ @props[name] = value
78
+ end
79
+
80
+ def get_prop(name)
81
+ @props ||= {}
82
+
83
+ @props[name]
84
+ end
85
+
86
+ def focus
87
+ @focused = true
88
+
89
+ children?&.each do |child|
90
+ child.node.meta.focus
91
+ end
92
+ end
93
+
94
+ def blur
95
+ @focused = false
96
+
97
+ children?&.each do |child|
98
+ child.node.meta.blur
99
+ end
100
+ end
101
+
102
+ def on_update(target, &block)
103
+ @target = target
104
+ @updater = block
105
+ end
106
+
107
+ def update(block)
108
+ # pp props
109
+ # if parent_block = parent
110
+ if target_block = target
111
+ if updater_block = updater
112
+ # Hokusai::Pool.post do
113
+ block.public_send(:before_updated) if block.respond_to?(:before_updated)
114
+
115
+ updater_block.call(block, target_block, target_block)
116
+ block.public_send(:after_updated) if block.respond_to?(:after_updated)
117
+
118
+ # end
119
+ end
120
+ end
121
+ # end
122
+
123
+ children?&.each do |child|
124
+ child.update
125
+ end
126
+ end
127
+
128
+ def has_ast?(ast, index)
129
+ if portal = children![index]&.node&.portal
130
+ return portal.ast.object_id == ast.object_id
131
+ end
132
+
133
+ false
134
+ end
135
+ #
136
+ # def destroy
137
+ # children.each do |child|
138
+ # child.before_destroy if child.respond_to?(:before_destroy)
139
+ # child.node.destroy
140
+ # end
141
+ # end
142
+
143
+ def child_delete(index)
144
+ if child = children![index]
145
+ child.before_destroy if child.respond_to?(:before_destroy)
146
+ child.node.destroy
147
+
148
+ children!.delete_at(index)
149
+ end
150
+ end
151
+ end
152
+ end