echoes 0.3.0 → 0.4.0
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/README.md +178 -11
- data/lib/echoes/gui.rb +24 -9
- data/lib/echoes/iterm2_images.rb +56 -1
- data/lib/echoes/kitty_graphics.rb +47 -2
- data/lib/echoes/kitty_graphics_appkit.rb +14 -5
- data/lib/echoes/objc.rb +47 -0
- data/lib/echoes/screen.rb +2 -1
- data/lib/echoes/svg_cg_renderer.rb +689 -0
- data/lib/echoes/svg_color.rb +120 -0
- data/lib/echoes/svg_path_parser.rb +120 -0
- data/lib/echoes/svg_renderer.rb +272 -0
- data/lib/echoes/svg_sniffer.rb +81 -0
- data/lib/echoes/svg_transform.rb +54 -0
- data/lib/echoes/svg_walker.rb +107 -0
- data/lib/echoes/version.rb +1 -1
- metadata +8 -1
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Echoes
|
|
4
|
+
# Minimal SVG element scanner. Yields one event per element to
|
|
5
|
+
# the block (or returns an Enumerator):
|
|
6
|
+
#
|
|
7
|
+
# [:open, tag, {attr => value, …}]
|
|
8
|
+
# [:close, tag, {}]
|
|
9
|
+
# [:self_close, tag, {attr => value, …}]
|
|
10
|
+
#
|
|
11
|
+
# Skips comments, processing instructions (`<?xml…?>`), DOCTYPE
|
|
12
|
+
# declarations, and CDATA sections. Text content between tags is
|
|
13
|
+
# ignored (the fast-path SVG renderer doesn't render text — any
|
|
14
|
+
# SVG that uses <text> is rejected before we walk it).
|
|
15
|
+
#
|
|
16
|
+
# Stops yielding on malformed input (no matching `>`, unbalanced
|
|
17
|
+
# comment, etc.). The caller treats early termination as "can't
|
|
18
|
+
# render — bail to WKWebView."
|
|
19
|
+
module SvgWalker
|
|
20
|
+
TAG_NAME_RE = /[a-zA-Z][\w:.-]*/
|
|
21
|
+
# `\G` anchors the match to the scan offset passed to Regexp#match,
|
|
22
|
+
# so we can reuse the same regex from any position. `\A` would
|
|
23
|
+
# only match at string-position 0, which is wrong once we're past
|
|
24
|
+
# the first tag.
|
|
25
|
+
CLOSE_TAG_RE = /\G<\/(#{TAG_NAME_RE})\s*>/m
|
|
26
|
+
OPEN_TAG_RE = /\G<(#{TAG_NAME_RE})([^>]*)>/m
|
|
27
|
+
ATTR_RE = /(#{TAG_NAME_RE})\s*=\s*(?:"([^"]*)"|'([^']*)')/
|
|
28
|
+
|
|
29
|
+
module_function
|
|
30
|
+
|
|
31
|
+
def events(bytes)
|
|
32
|
+
return enum_for(:events, bytes) unless block_given?
|
|
33
|
+
return if bytes.nil?
|
|
34
|
+
|
|
35
|
+
s = bytes.b
|
|
36
|
+
pos = 0
|
|
37
|
+
len = s.length
|
|
38
|
+
while pos < len
|
|
39
|
+
lt = s.index('<', pos)
|
|
40
|
+
break unless lt
|
|
41
|
+
pos = lt
|
|
42
|
+
|
|
43
|
+
# Comment: <!-- … -->
|
|
44
|
+
if s[pos, 4] == '<!--'
|
|
45
|
+
close = s.index('-->', pos + 4)
|
|
46
|
+
break unless close
|
|
47
|
+
pos = close + 3
|
|
48
|
+
next
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# CDATA: <![CDATA[ … ]]>
|
|
52
|
+
if s[pos, 9] == '<![CDATA['
|
|
53
|
+
close = s.index(']]>', pos + 9)
|
|
54
|
+
break unless close
|
|
55
|
+
pos = close + 3
|
|
56
|
+
next
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Other declarations: <!DOCTYPE …>, <!ENTITY …>, etc.
|
|
60
|
+
if s[pos, 2] == '<!'
|
|
61
|
+
close = s.index('>', pos + 2)
|
|
62
|
+
break unless close
|
|
63
|
+
pos = close + 1
|
|
64
|
+
next
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Processing instruction: <?xml …?>
|
|
68
|
+
if s[pos, 2] == '<?'
|
|
69
|
+
close = s.index('?>', pos + 2)
|
|
70
|
+
break unless close
|
|
71
|
+
pos = close + 2
|
|
72
|
+
next
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Closing tag: </tag>
|
|
76
|
+
if s[pos, 2] == '</'
|
|
77
|
+
m = CLOSE_TAG_RE.match(s, pos)
|
|
78
|
+
break unless m && m.begin(0) == pos
|
|
79
|
+
yield [:close, m[1], {}]
|
|
80
|
+
pos = m.end(0)
|
|
81
|
+
next
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# Opening or self-closing tag.
|
|
85
|
+
m = OPEN_TAG_RE.match(s, pos)
|
|
86
|
+
break unless m && m.begin(0) == pos
|
|
87
|
+
tag = m[1]
|
|
88
|
+
body = m[2]
|
|
89
|
+
if body.rstrip.end_with?('/')
|
|
90
|
+
attrs_str = body.rstrip.chomp('/')
|
|
91
|
+
yield [:self_close, tag, parse_attrs(attrs_str)]
|
|
92
|
+
else
|
|
93
|
+
yield [:open, tag, parse_attrs(body)]
|
|
94
|
+
end
|
|
95
|
+
pos = m.end(0)
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def parse_attrs(str)
|
|
100
|
+
out = {}
|
|
101
|
+
str.scan(ATTR_RE) do |name, dq, sq|
|
|
102
|
+
out[name] = dq || sq || ''
|
|
103
|
+
end
|
|
104
|
+
out
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
data/lib/echoes/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: echoes
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.4.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Akira Matsuda
|
|
@@ -86,6 +86,13 @@ files:
|
|
|
86
86
|
- lib/echoes/profile.rb
|
|
87
87
|
- lib/echoes/screen.rb
|
|
88
88
|
- lib/echoes/sixel_decoder.rb
|
|
89
|
+
- lib/echoes/svg_cg_renderer.rb
|
|
90
|
+
- lib/echoes/svg_color.rb
|
|
91
|
+
- lib/echoes/svg_path_parser.rb
|
|
92
|
+
- lib/echoes/svg_renderer.rb
|
|
93
|
+
- lib/echoes/svg_sniffer.rb
|
|
94
|
+
- lib/echoes/svg_transform.rb
|
|
95
|
+
- lib/echoes/svg_walker.rb
|
|
89
96
|
- lib/echoes/tab.rb
|
|
90
97
|
- lib/echoes/terminal.rb
|
|
91
98
|
- lib/echoes/version.rb
|