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.
- checksums.yaml +7 -0
- data/Dockerfile +26 -0
- data/Gemfile +15 -0
- data/Gemfile.lock +91 -0
- data/LICENSE +21 -0
- data/README.md +28 -0
- data/ast/genheader +3 -0
- data/ast/include/hashmap.c +1151 -0
- data/ast/include/hashmap.c.license +20 -0
- data/ast/include/hashmap.h +54 -0
- data/ast/src/core/ast.c +448 -0
- data/ast/src/core/ast.h +259 -0
- data/ast/src/core/common.h +24 -0
- data/ast/src/core/component.c +85 -0
- data/ast/src/core/component.h +35 -0
- data/ast/src/core/hml.c +665 -0
- data/ast/src/core/hml.h +11 -0
- data/ast/src/core/input.c +458 -0
- data/ast/src/core/input.h +118 -0
- data/ast/src/core/style.c +101 -0
- data/ast/src/core/style.h +41 -0
- data/ast/src/core/text.c +784 -0
- data/ast/src/core/text.h +93 -0
- data/ast/src/core/util.c +140 -0
- data/ast/src/core/util.h +48 -0
- data/ast/src/hokusai.c +6 -0
- data/ast/src/hokusai.h +6 -0
- data/ast/test/fixtures/test.ui +13 -0
- data/ast/test/greatest.h +1266 -0
- data/ast/test/hokusai.c +14 -0
- data/ast/test/parser.c +234 -0
- data/ast/test/text.c +116 -0
- data/ext/extconf.rb +27 -0
- data/grammar/Cargo.lock +80 -0
- data/grammar/Cargo.toml +26 -0
- data/grammar/binding.gyp +20 -0
- data/grammar/bindings/node/binding.cc +28 -0
- data/grammar/bindings/node/index.js +19 -0
- data/grammar/bindings/rust/build.rs +40 -0
- data/grammar/bindings/rust/lib.rs +52 -0
- data/grammar/corpus/1_document.txt +131 -0
- data/grammar/corpus/2_selectors.txt +58 -0
- data/grammar/corpus/3_spaces.txt +69 -0
- data/grammar/corpus/4_errors.txt +10 -0
- data/grammar/corpus/5_macros.txt +175 -0
- data/grammar/corpus/6_styles.txt +81 -0
- data/grammar/grammar.js +275 -0
- data/grammar/package-lock.json +34 -0
- data/grammar/package.json +33 -0
- data/grammar/src/grammar.json +1269 -0
- data/grammar/src/node-types.json +474 -0
- data/grammar/src/parser.c +5772 -0
- data/grammar/src/scanner.c +258 -0
- data/grammar/src/tree_sitter/parser.h +230 -0
- data/grammar/src/tree_sitter/scanner.h +12 -0
- data/grammar/test.nml +10 -0
- data/hokusai.gemspec +19 -0
- data/ui/examples/assets/DigitalDisplay.ttf +0 -0
- data/ui/examples/assets/OpenSans-Regular.ttf +0 -0
- data/ui/examples/assets/addy.png +0 -0
- data/ui/examples/assets/baby_sean.png +0 -0
- data/ui/examples/assets/football-troll.png +0 -0
- data/ui/examples/assets/gear.png +0 -0
- data/ui/examples/assets/icecold.ttf +0 -0
- data/ui/examples/assets/science-troll.png +0 -0
- data/ui/examples/buddy.rb +31 -0
- data/ui/examples/clock.rb +58 -0
- data/ui/examples/counter.rb +123 -0
- data/ui/examples/dynamic.rb +147 -0
- data/ui/examples/foobar.rb +236 -0
- data/ui/examples/stock.rb +115 -0
- data/ui/examples/stock_decider/option.rb +74 -0
- data/ui/examples/tic_tac_toe.rb +246 -0
- data/ui/lib/lib_hokusai.rb +425 -0
- data/ui/spec/hokusai/ast_spec.rb +88 -0
- data/ui/spec/hokusai/automation/keys_transcoder_spec.rb +50 -0
- data/ui/spec/hokusai/automation/selector_spec.rb +68 -0
- data/ui/spec/hokusai/block_spec.rb +126 -0
- data/ui/spec/hokusai/directives_spec.rb +327 -0
- data/ui/spec/hokusai/e2e/client_spec.rb +58 -0
- data/ui/spec/hokusai/e2e/meta_spec.rb +42 -0
- data/ui/spec/hokusai/publisher_spec.rb +38 -0
- data/ui/spec/hokusai/slots_spec.rb +150 -0
- data/ui/spec/hokusai/util/piece_table_spec.rb +90 -0
- data/ui/spec/hokusai_spec.rb +0 -0
- data/ui/spec/spec_helper.rb +30 -0
- data/ui/src/hokusai/ast.rb +446 -0
- data/ui/src/hokusai/automation/client.rb +167 -0
- data/ui/src/hokusai/automation/constants.rb +98 -0
- data/ui/src/hokusai/automation/converters/selector_converter.rb +61 -0
- data/ui/src/hokusai/automation/driver.rb +54 -0
- data/ui/src/hokusai/automation/driver_command_queue.rb +50 -0
- data/ui/src/hokusai/automation/driver_commands/base.rb +79 -0
- data/ui/src/hokusai/automation/driver_commands/get_attribute.rb +41 -0
- data/ui/src/hokusai/automation/driver_commands/invoke.rb +33 -0
- data/ui/src/hokusai/automation/driver_commands/locate.rb +48 -0
- data/ui/src/hokusai/automation/driver_commands/trigger_keyboard.rb +94 -0
- data/ui/src/hokusai/automation/driver_commands/trigger_mouse.rb +213 -0
- data/ui/src/hokusai/automation/keys_transcoder.rb +128 -0
- data/ui/src/hokusai/automation/selector.rb +39 -0
- data/ui/src/hokusai/automation/server.rb +114 -0
- data/ui/src/hokusai/automation.rb +3 -0
- data/ui/src/hokusai/backends/raylib/config.rb +47 -0
- data/ui/src/hokusai/backends/raylib/font.rb +113 -0
- data/ui/src/hokusai/backends/raylib/keys.rb +124 -0
- data/ui/src/hokusai/backends/raylib.rb +449 -0
- data/ui/src/hokusai/backends/sdl2/Monaco.ttf +0 -0
- data/ui/src/hokusai/backends/sdl2/color.rb +12 -0
- data/ui/src/hokusai/backends/sdl2/config.rb +31 -0
- data/ui/src/hokusai/backends/sdl2/font.rb +127 -0
- data/ui/src/hokusai/backends/sdl2/keys.rb +119 -0
- data/ui/src/hokusai/backends/sdl2.rb +529 -0
- data/ui/src/hokusai/block.rb +237 -0
- data/ui/src/hokusai/blocks/button.rb +100 -0
- data/ui/src/hokusai/blocks/checkbox.rb +51 -0
- data/ui/src/hokusai/blocks/circle.rb +28 -0
- data/ui/src/hokusai/blocks/clipped.rb +23 -0
- data/ui/src/hokusai/blocks/cursor.rb +49 -0
- data/ui/src/hokusai/blocks/dynamic.rb +37 -0
- data/ui/src/hokusai/blocks/empty.rb +10 -0
- data/ui/src/hokusai/blocks/hblock.rb +35 -0
- data/ui/src/hokusai/blocks/image.rb +18 -0
- data/ui/src/hokusai/blocks/input.rb +200 -0
- data/ui/src/hokusai/blocks/label.rb +39 -0
- data/ui/src/hokusai/blocks/panel.rb +126 -0
- data/ui/src/hokusai/blocks/rect.rb +24 -0
- data/ui/src/hokusai/blocks/scissor_begin.rb +18 -0
- data/ui/src/hokusai/blocks/scissor_end.rb +12 -0
- data/ui/src/hokusai/blocks/scrollbar.rb +103 -0
- data/ui/src/hokusai/blocks/selectable.rb +77 -0
- data/ui/src/hokusai/blocks/svg.rb +20 -0
- data/ui/src/hokusai/blocks/text.rb +214 -0
- data/ui/src/hokusai/blocks/titlebar/osx.rb +145 -0
- data/ui/src/hokusai/blocks/toggle.rb +55 -0
- data/ui/src/hokusai/blocks/vblock.rb +35 -0
- data/ui/src/hokusai/commands/base.rb +22 -0
- data/ui/src/hokusai/commands/circle.rb +47 -0
- data/ui/src/hokusai/commands/image.rb +45 -0
- data/ui/src/hokusai/commands/rect.rb +158 -0
- data/ui/src/hokusai/commands/scissor.rb +22 -0
- data/ui/src/hokusai/commands/text.rb +92 -0
- data/ui/src/hokusai/commands.rb +87 -0
- data/ui/src/hokusai/diff.rb +124 -0
- data/ui/src/hokusai/error.rb +3 -0
- data/ui/src/hokusai/event.rb +54 -0
- data/ui/src/hokusai/events/keyboard.rb +84 -0
- data/ui/src/hokusai/events/mouse.rb +172 -0
- data/ui/src/hokusai/font.rb +280 -0
- data/ui/src/hokusai/meta.rb +152 -0
- data/ui/src/hokusai/mounting/loop_entry.rb +230 -0
- data/ui/src/hokusai/mounting/mount_entry.rb +74 -0
- data/ui/src/hokusai/mounting/update_entry.rb +101 -0
- data/ui/src/hokusai/node.rb +98 -0
- data/ui/src/hokusai/node_mounter.rb +102 -0
- data/ui/src/hokusai/painter.rb +214 -0
- data/ui/src/hokusai/publisher.rb +32 -0
- data/ui/src/hokusai/style.rb +72 -0
- data/ui/src/hokusai/types.rb +266 -0
- data/ui/src/hokusai/util/clamping_iterator.rb +202 -0
- data/ui/src/hokusai/util/piece_table.rb +111 -0
- data/ui/src/hokusai/util/selection.rb +145 -0
- data/ui/src/hokusai.rb +120 -0
- data/ui/vendor/.gitkeep +0 -0
- data/vendor/.gitkeep +0 -0
- data/xmake.lua +192 -0
- metadata +222 -0
@@ -0,0 +1,158 @@
|
|
1
|
+
module Hokusai
|
2
|
+
class Commands::Rect < Commands::Base
|
3
|
+
attr_reader :x, :y, :width, :height,
|
4
|
+
:rounding, :color, :outline,
|
5
|
+
:outline_color, :padding
|
6
|
+
|
7
|
+
def initialize(x, y, width, height)
|
8
|
+
@x = x.to_f
|
9
|
+
@y = y.to_f
|
10
|
+
@width = width.to_f
|
11
|
+
@height = height.to_f
|
12
|
+
@outline = Outline.default
|
13
|
+
@rounding = 0.0
|
14
|
+
@color = Color.new(0, 0, 0, 0)
|
15
|
+
@outline_color = Color.new(0, 0, 0, 255)
|
16
|
+
@padding = Padding.new(0.0, 0.0, 0.0, 0.0)
|
17
|
+
end
|
18
|
+
|
19
|
+
def hash
|
20
|
+
[self.class, x, y, width, height, rounding, color.hash, outline.hash, outline_color.hash, padding.hash].hash
|
21
|
+
end
|
22
|
+
|
23
|
+
# Modifies the parameter *Canvas*
|
24
|
+
# to offset the boundary with
|
25
|
+
# this rectangle's computed geometry
|
26
|
+
def trim_canvas(canvas)
|
27
|
+
x, y, w, h = background_boundary
|
28
|
+
|
29
|
+
canvas.x = x + padding.left
|
30
|
+
canvas.y = y + padding.top
|
31
|
+
canvas.width = w - (padding.left + padding.right)
|
32
|
+
canvas.height = h - (padding.top + padding.bottom)
|
33
|
+
|
34
|
+
canvas
|
35
|
+
end
|
36
|
+
|
37
|
+
# Shorthand for #width
|
38
|
+
def w
|
39
|
+
width
|
40
|
+
end
|
41
|
+
|
42
|
+
# Shorthand for #height
|
43
|
+
def h
|
44
|
+
height
|
45
|
+
end
|
46
|
+
|
47
|
+
# Sets padding for the rectangle
|
48
|
+
# `value` is an array with padding declarations
|
49
|
+
# at [top, right, bottom, left]
|
50
|
+
def padding=(value)
|
51
|
+
case value
|
52
|
+
when Padding
|
53
|
+
@padding = value
|
54
|
+
else
|
55
|
+
@padding = Padding.convert(value)
|
56
|
+
end
|
57
|
+
|
58
|
+
self
|
59
|
+
end
|
60
|
+
|
61
|
+
# Sets an outline at `weight`
|
62
|
+
def outline=(outline)
|
63
|
+
@outline = outline
|
64
|
+
|
65
|
+
self
|
66
|
+
end
|
67
|
+
|
68
|
+
# Sets the outline color to `value`
|
69
|
+
def outline_color=(value)
|
70
|
+
case value
|
71
|
+
when Color
|
72
|
+
@outline_color = value
|
73
|
+
when Array
|
74
|
+
@outline_color = Color.new(value[0], value[1], value[2], value[3] || 255)
|
75
|
+
else
|
76
|
+
raise "Basd color"
|
77
|
+
end
|
78
|
+
|
79
|
+
self
|
80
|
+
end
|
81
|
+
|
82
|
+
|
83
|
+
# Sets the color of the rectangle
|
84
|
+
# from an array of rgba values
|
85
|
+
def color=(value)
|
86
|
+
case value
|
87
|
+
when Color
|
88
|
+
@color = value
|
89
|
+
when Array
|
90
|
+
@color = Color.new(value[0], value[1], value[2], value[3] || 255)
|
91
|
+
end
|
92
|
+
|
93
|
+
self
|
94
|
+
end
|
95
|
+
|
96
|
+
# Rounding amount for this rect
|
97
|
+
def round=(amount)
|
98
|
+
@rounding = amount
|
99
|
+
|
100
|
+
self
|
101
|
+
end
|
102
|
+
|
103
|
+
# Returns true if the rectangle has any padding
|
104
|
+
def padding?
|
105
|
+
[padding.t, padding.r, padding.b, padding.l].any? do |p|
|
106
|
+
p != 0.0
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
# Returns a tuple with the
|
111
|
+
# geometric boundary for this rectangle
|
112
|
+
def boundary
|
113
|
+
[x, y, width, height]
|
114
|
+
end
|
115
|
+
|
116
|
+
# Returns a tuple with the
|
117
|
+
# computed geometric **inner** boundary for this rectangle
|
118
|
+
# with outlines subtracted
|
119
|
+
def background_boundary
|
120
|
+
nx = x.dup
|
121
|
+
ny = y.dup
|
122
|
+
nw = width.dup
|
123
|
+
nh = height.dup
|
124
|
+
|
125
|
+
if outline.top > 0.0
|
126
|
+
ny += outline.top
|
127
|
+
nh -= outline.top
|
128
|
+
end
|
129
|
+
|
130
|
+
if outline.left > 0.0
|
131
|
+
nx += outline.left
|
132
|
+
nw -= outline.left
|
133
|
+
end
|
134
|
+
|
135
|
+
if outline.bottom > 0.0
|
136
|
+
nh -= outline.bottom
|
137
|
+
end
|
138
|
+
|
139
|
+
if outline.right > 0.0
|
140
|
+
nw -= outline.right
|
141
|
+
end
|
142
|
+
|
143
|
+
[nx, ny, nw, nh]
|
144
|
+
end
|
145
|
+
|
146
|
+
# Returns true if this rectangle
|
147
|
+
# has an outline
|
148
|
+
def outline?
|
149
|
+
outline.present?
|
150
|
+
end
|
151
|
+
|
152
|
+
# Returns true if this rectangle's
|
153
|
+
# outline is uniform
|
154
|
+
def outline_uniform?
|
155
|
+
outline.uniform?
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Hokusai
|
2
|
+
class Commands::ScissorBegin < Commands::Base
|
3
|
+
attr_reader :x, :y, :width, :height
|
4
|
+
|
5
|
+
def initialize(x, y, width, height)
|
6
|
+
@x = x
|
7
|
+
@y = y
|
8
|
+
@width = width
|
9
|
+
@height = height
|
10
|
+
end
|
11
|
+
|
12
|
+
def hash
|
13
|
+
[self.class, x, y, width, height].hash
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class Commands::ScissorEnd < Commands::Base;
|
18
|
+
def hash
|
19
|
+
[self.class].hash
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
module Hokusai
|
2
|
+
class Commands::Text < Commands::Base
|
3
|
+
attr_reader :x, :y, :size, :color,
|
4
|
+
:padding, :wrap, :content,
|
5
|
+
:font, :static, :line_height,
|
6
|
+
:bold, :italic
|
7
|
+
|
8
|
+
def initialize(content, x, y)
|
9
|
+
@content = content
|
10
|
+
@x = x.to_f
|
11
|
+
@y = y.to_f
|
12
|
+
@color = Color.new(0, 0, 0, 255)
|
13
|
+
@padding = Padding.new(0.0, 0.0, 0.0, 0.0)
|
14
|
+
@size = 17
|
15
|
+
@wrap = false
|
16
|
+
@font = nil
|
17
|
+
@static = true
|
18
|
+
@bold = false
|
19
|
+
@italic = false
|
20
|
+
@line_height = 0.0
|
21
|
+
end
|
22
|
+
|
23
|
+
def hash
|
24
|
+
[self.class, content, color.hash, padding.hash, size, font, wrap].hash
|
25
|
+
end
|
26
|
+
|
27
|
+
def bold=(value)
|
28
|
+
@bold = value
|
29
|
+
end
|
30
|
+
|
31
|
+
def italic=(value)
|
32
|
+
@italic = value
|
33
|
+
end
|
34
|
+
|
35
|
+
def static=(value)
|
36
|
+
@static = !!value
|
37
|
+
end
|
38
|
+
|
39
|
+
def line_height=(value)
|
40
|
+
@line_height = value
|
41
|
+
end
|
42
|
+
|
43
|
+
def dynamic=(value)
|
44
|
+
@static = !value
|
45
|
+
end
|
46
|
+
|
47
|
+
def font=(value)
|
48
|
+
@font = value
|
49
|
+
end
|
50
|
+
|
51
|
+
def content=(value)
|
52
|
+
@content = value
|
53
|
+
end
|
54
|
+
|
55
|
+
def size=(height)
|
56
|
+
@size = height.to_f
|
57
|
+
end
|
58
|
+
|
59
|
+
# Sets padding for the text
|
60
|
+
# `value` is an array with padding declarations
|
61
|
+
# at [top, right, bottom, left]
|
62
|
+
def padding=(value)
|
63
|
+
case value
|
64
|
+
when Array
|
65
|
+
@padding = Padding.new(value[0], value[1], value[2], value[3])
|
66
|
+
when Integer
|
67
|
+
@padding = Padding.new(value, value, value, value)
|
68
|
+
when Padding
|
69
|
+
@padding = value
|
70
|
+
end
|
71
|
+
|
72
|
+
self
|
73
|
+
end
|
74
|
+
|
75
|
+
# Sets the color of the text
|
76
|
+
# from an array of rgba values
|
77
|
+
def color=(value)
|
78
|
+
case value
|
79
|
+
when Color
|
80
|
+
@color = value
|
81
|
+
when Array
|
82
|
+
@color = Color.new(value[0], value[1], value[2], value[3] || 255)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def padding?
|
87
|
+
[padding.t, padding.r, padding.b, padding.l].any? do |p|
|
88
|
+
p != 0.0
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require_relative "./commands/base"
|
2
|
+
require_relative "./commands/circle"
|
3
|
+
require_relative "./commands/image"
|
4
|
+
require_relative "./commands/rect"
|
5
|
+
require_relative "./commands/scissor"
|
6
|
+
require_relative "./commands/text"
|
7
|
+
|
8
|
+
module Hokusai
|
9
|
+
class Commands
|
10
|
+
attr_reader :queue
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
# @queue = []
|
14
|
+
end
|
15
|
+
|
16
|
+
# def hash
|
17
|
+
# [self.class, *@queue.map(&:hash)].hash
|
18
|
+
# end
|
19
|
+
|
20
|
+
def rect(x, y, w, h)
|
21
|
+
command = Commands::Rect.new(x, y, w, h)
|
22
|
+
yield(command)
|
23
|
+
|
24
|
+
command.draw
|
25
|
+
# add(command)
|
26
|
+
end
|
27
|
+
|
28
|
+
def circle(x, y, radius)
|
29
|
+
command = Commands::Circle.new(x, y, radius)
|
30
|
+
yield(command)
|
31
|
+
|
32
|
+
command.draw
|
33
|
+
# add(command)
|
34
|
+
end
|
35
|
+
|
36
|
+
def svg(source, x, y, w, h)
|
37
|
+
command = Commands::SVG.new(source, x, y, w, h)
|
38
|
+
yield(command)
|
39
|
+
|
40
|
+
# add(command)
|
41
|
+
end
|
42
|
+
|
43
|
+
# Invokes an image command
|
44
|
+
# from a filename, at position {x,y} with `w`x`h` dimensions
|
45
|
+
def image(source, x, y, w, h)
|
46
|
+
Commands::Image.new(source, x, y, w, h).draw
|
47
|
+
# add(Commands::Image.new(source, x, y, w, h))
|
48
|
+
end
|
49
|
+
|
50
|
+
# Invokes a scissor begin command
|
51
|
+
# at position {x,y} with `w`x`h` dimensions
|
52
|
+
def scissor_begin(x, y, w, h)
|
53
|
+
Commands::ScissorBegin.new(x, y, w, h).draw
|
54
|
+
# add(Commands::ScissorBegin.new(x, y, w, h))
|
55
|
+
end
|
56
|
+
|
57
|
+
# Invokes a scissor stop command
|
58
|
+
def scissor_end
|
59
|
+
Commands::ScissorEnd.new.draw
|
60
|
+
# add(Commands::ScissorEnd.new)
|
61
|
+
end
|
62
|
+
|
63
|
+
def text(content, x, y)
|
64
|
+
command = Commands::Text.new(content, x, y)
|
65
|
+
yield command
|
66
|
+
|
67
|
+
command.draw
|
68
|
+
# add(command)
|
69
|
+
end
|
70
|
+
|
71
|
+
def each
|
72
|
+
queue.each do |cmd|
|
73
|
+
yield(cmd)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def clear!
|
78
|
+
# @queue = []
|
79
|
+
end
|
80
|
+
|
81
|
+
def add(command)
|
82
|
+
# @queue << command
|
83
|
+
|
84
|
+
self
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,124 @@
|
|
1
|
+
module Hokusai
|
2
|
+
class MovePatch
|
3
|
+
attr_accessor :from, :to, :delete
|
4
|
+
|
5
|
+
def initialize(from:, to:, delete: false)
|
6
|
+
@from = from
|
7
|
+
@to = to
|
8
|
+
@delete = delete
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class InsertPatch
|
13
|
+
attr_accessor :target, :value, :delete
|
14
|
+
|
15
|
+
def initialize(target:, value:, delete: false)
|
16
|
+
@target = target
|
17
|
+
@value = value
|
18
|
+
@delete = delete
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class UpdatePatch
|
23
|
+
attr_accessor :target, :value
|
24
|
+
|
25
|
+
def initialize(target:, value:)
|
26
|
+
@target = target
|
27
|
+
@value = value
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class DeletePatch
|
32
|
+
attr_accessor :target
|
33
|
+
|
34
|
+
def initialize(target)
|
35
|
+
@target = target
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
class Diff
|
40
|
+
attr_reader :before, :after, :insertions
|
41
|
+
|
42
|
+
def initialize(before, after)
|
43
|
+
@before = before
|
44
|
+
@after = after
|
45
|
+
@insertions = {}
|
46
|
+
end
|
47
|
+
|
48
|
+
def map(list)
|
49
|
+
memo = {}
|
50
|
+
list.each_with_index do |(key, value), index|
|
51
|
+
memo[key] = { value: value, index: index }
|
52
|
+
end
|
53
|
+
|
54
|
+
memo
|
55
|
+
end
|
56
|
+
|
57
|
+
def patch
|
58
|
+
i = 0
|
59
|
+
deletions = 0
|
60
|
+
mapbefore = map(before)
|
61
|
+
mapafter = map(after)
|
62
|
+
|
63
|
+
while i < after.size
|
64
|
+
# left right
|
65
|
+
# [d, a, c] [(c), e, a, b]
|
66
|
+
#
|
67
|
+
# 1. [c, a] [c, (e), a]
|
68
|
+
#
|
69
|
+
# 2. [c, e, a] [c, e, b, (a),]
|
70
|
+
#
|
71
|
+
# 3. [c, e, b, a]
|
72
|
+
#
|
73
|
+
# is value (c) in left?
|
74
|
+
# yes ->
|
75
|
+
# is left[0] (a) in right?
|
76
|
+
# yes -> move c to 0, move a to 2
|
77
|
+
# no -> delete a, move c to 0
|
78
|
+
#
|
79
|
+
akey, value = after[i] # b
|
80
|
+
ckey, current = before[i] || nil # a
|
81
|
+
|
82
|
+
if bi = mapbefore.delete(akey) # 2
|
83
|
+
if bi[:index] != i # true (2 != 0)
|
84
|
+
if mapafter[ckey] # true
|
85
|
+
# move a to 2
|
86
|
+
before[bi[:index]] = [ckey, current] # before[2] = a
|
87
|
+
# update index
|
88
|
+
mapbefore[ckey] = { index: bi, value: current }
|
89
|
+
|
90
|
+
# move c to 0
|
91
|
+
yield MovePatch.new(from: bi, to: i)
|
92
|
+
else
|
93
|
+
yield MovePatch.new(from: bi, to: i, delete: true)
|
94
|
+
mapbefore[ckey] = nil
|
95
|
+
deletions += 1
|
96
|
+
# next
|
97
|
+
end
|
98
|
+
elsif value != current
|
99
|
+
yield UpdatePatch.new(target: i, value: value)
|
100
|
+
end
|
101
|
+
else # insert logic
|
102
|
+
if mapafter[ckey]
|
103
|
+
before[i + 1] = [ckey, current]
|
104
|
+
mapbefore[ckey] = { index: i + 1, value: current }
|
105
|
+
|
106
|
+
yield InsertPatch.new(target: i, value: value)
|
107
|
+
else
|
108
|
+
yield InsertPatch.new(target: i, value: value, delete: true)
|
109
|
+
mapbefore[ckey] = nil
|
110
|
+
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
i += 1
|
115
|
+
end
|
116
|
+
|
117
|
+
mapbefore.values.each do |value|
|
118
|
+
next if value.nil?
|
119
|
+
|
120
|
+
yield DeletePatch.new(value[:index]) unless value[:index].nil?
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Hokusai
|
4
|
+
class Event
|
5
|
+
attr_reader :captures, :bubbles
|
6
|
+
attr_accessor :stopped
|
7
|
+
|
8
|
+
def self.name(name)
|
9
|
+
@name = name
|
10
|
+
end
|
11
|
+
|
12
|
+
def name
|
13
|
+
self.class.instance_variable_get("@name")
|
14
|
+
end
|
15
|
+
|
16
|
+
def stopped
|
17
|
+
@stopped ||= false
|
18
|
+
end
|
19
|
+
|
20
|
+
def stop
|
21
|
+
self.stopped = true
|
22
|
+
end
|
23
|
+
|
24
|
+
def captures
|
25
|
+
@captures ||= []
|
26
|
+
end
|
27
|
+
|
28
|
+
def bubbles
|
29
|
+
@bubbles ||= []
|
30
|
+
end
|
31
|
+
|
32
|
+
def to_json
|
33
|
+
raise Hokusai::Error.new("#{self.class} must implement to_json")
|
34
|
+
end
|
35
|
+
|
36
|
+
def matches(block)
|
37
|
+
return false if block.node.portal.nil?
|
38
|
+
|
39
|
+
val = block.node.portal.ast.event(name)
|
40
|
+
!!val
|
41
|
+
end
|
42
|
+
|
43
|
+
def bubble
|
44
|
+
while block = captures.pop
|
45
|
+
block.emit(name, self)
|
46
|
+
|
47
|
+
break if stopped
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
require_relative './events/keyboard'
|
54
|
+
require_relative './events/mouse'
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module Hokusai
|
2
|
+
class KeyboardEvent < Event
|
3
|
+
extend Forwardable
|
4
|
+
|
5
|
+
def_delegators :@keyboard, :shift, :super, :ctrl,
|
6
|
+
:alt, :pressed, :pressed_len, :released,
|
7
|
+
:released_len
|
8
|
+
|
9
|
+
attr_reader :input
|
10
|
+
|
11
|
+
def initialize(input, state)
|
12
|
+
@input = input
|
13
|
+
@state = state
|
14
|
+
@keyboard = input.keyboard
|
15
|
+
end
|
16
|
+
|
17
|
+
def hovered(canvas)
|
18
|
+
input.hovered?(canvas)
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_json
|
22
|
+
{
|
23
|
+
keypress: {
|
24
|
+
keycode: code,
|
25
|
+
char: char.to_s,
|
26
|
+
super: self.super,
|
27
|
+
control: ctrl,
|
28
|
+
shift: shift,
|
29
|
+
alt: alt
|
30
|
+
}
|
31
|
+
}.to_json
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class KeyUpEvent < KeyboardEvent
|
36
|
+
name "keyup"
|
37
|
+
|
38
|
+
def keyboard_key
|
39
|
+
input.raw[:keyboard][:released]
|
40
|
+
end
|
41
|
+
|
42
|
+
def key
|
43
|
+
keyboard_key[:key][:key]
|
44
|
+
end
|
45
|
+
|
46
|
+
def code
|
47
|
+
keyboard_key[:char_code]
|
48
|
+
end
|
49
|
+
|
50
|
+
def char
|
51
|
+
code.chr
|
52
|
+
end
|
53
|
+
|
54
|
+
def capture(block, _)
|
55
|
+
captures << block if matches(block) && released_len > 0
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
class KeyPressEvent < KeyboardEvent
|
60
|
+
name "keypress"
|
61
|
+
|
62
|
+
def keyboard_key
|
63
|
+
input.raw[:keyboard][:pressed]
|
64
|
+
end
|
65
|
+
|
66
|
+
def key
|
67
|
+
keyboard_key[:key][:key]
|
68
|
+
end
|
69
|
+
|
70
|
+
def code
|
71
|
+
keyboard_key[:char_code]
|
72
|
+
end
|
73
|
+
|
74
|
+
def char
|
75
|
+
code.chr
|
76
|
+
end
|
77
|
+
|
78
|
+
def capture(block, _)
|
79
|
+
return unless matches(block) && pressed_len > 0
|
80
|
+
|
81
|
+
captures << block
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|