terminal_rb 0.9.6 → 0.10.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 +1 -1
- data/lib/terminal/ansi.rb +24 -9
- data/lib/terminal/detect.rb +37 -35
- data/lib/terminal/input.rb +2 -1
- data/lib/terminal/text.rb +89 -91
- data/lib/terminal/version.rb +1 -1
- data/lib/terminal.rb +47 -29
- metadata +5 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6b6f4c3e8cfa6ca602f831ef011a146ff0f70d77d9a0da4a7a37a9768e52da39
|
4
|
+
data.tar.gz: 73f1ce0355077b7803c7c03924aaa764e8dac2f05e2534a653f37ba4b7d32b27
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2e65c5d198050d41671d57fb5a60c67efd0d4f22c4da71cb4253e8260481fa5c0bc32713be85bf4d1c14a3e5eb7ad886f088ff78418059197b89bf685615a152
|
7
|
+
data.tar.gz: 9376328d7d488c039ce14411061ee41f4f46efa9ee244c33481f03a855bd6861e871248f3e5faee2b07826b09646e3789a09fd3e2398784c801d527d784114bf
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# Terminal.rb 
|
2
2
|
|
3
|
-
Terminal access with
|
3
|
+
Terminal access with super fast ANSI control codes support and [BBCode-like](https://en.wikipedia.org/wiki/BBCode) embedded text attribute syntax.
|
4
4
|
|
5
5
|
- Gem: [rubygems.org](https://rubygems.org/gems/terminal_rb)
|
6
6
|
- Source: [codeberg.org](https://codeberg.org/mblumtritt/Terminal.rb)
|
data/lib/terminal/ansi.rb
CHANGED
@@ -226,7 +226,7 @@ module Terminal
|
|
226
226
|
str = str.to_s
|
227
227
|
return str.dup unless str.index('[')
|
228
228
|
str.gsub(BBCODE) do |match_str|
|
229
|
-
|
229
|
+
match = Regexp.last_match(1) or next match_str
|
230
230
|
next "[#{match[1..]}]" if match[0] == '\\'
|
231
231
|
try_convert(match) || match_str
|
232
232
|
end
|
@@ -246,7 +246,7 @@ module Terminal
|
|
246
246
|
str = str.to_s
|
247
247
|
return str.dup unless str.index('[')
|
248
248
|
str.gsub(BBCODE) do |match_str|
|
249
|
-
|
249
|
+
match = Regexp.last_match(1) or next match_str
|
250
250
|
next "[#{match[1..]}]" if match[0] == '\\'
|
251
251
|
next match_str if (match = match.split).empty?
|
252
252
|
next if match.all? { ATTRIBUTES[_1] || COLORS[_1] || _color(_1) }
|
@@ -274,7 +274,7 @@ module Terminal
|
|
274
274
|
end
|
275
275
|
str =
|
276
276
|
str.gsub(BBCODE) do |match_str|
|
277
|
-
|
277
|
+
match = Regexp.last_match(1) or next match_str
|
278
278
|
next "[#{match[1..]}]" if match[0] == '\\'
|
279
279
|
next match_str if (match = match.split).empty?
|
280
280
|
next if match.all? { ATTRIBUTES[_1] || COLORS[_1] || _color(_1) }
|
@@ -297,9 +297,9 @@ module Terminal
|
|
297
297
|
.chars
|
298
298
|
.map! do |char|
|
299
299
|
i = (seed + ((pos += 1) / spread)) * frequency
|
300
|
-
"\e[38;2;#{(Math.sin(i) * 255).abs
|
301
|
-
"#{(Math.sin(i + PI2_THIRD) * 255).abs
|
302
|
-
"#{(Math.sin(i + PI4_THIRD) * 255).abs
|
300
|
+
"\e[38;2;#{(Math.sin(i) * 255).to_i.abs};" \
|
301
|
+
"#{(Math.sin(i + PI2_THIRD) * 255).to_i.abs};" \
|
302
|
+
"#{(Math.sin(i + PI4_THIRD) * 255).to_i.abs}m#{char}"
|
303
303
|
end
|
304
304
|
.join << RESET
|
305
305
|
end
|
@@ -390,6 +390,7 @@ module Terminal
|
|
390
390
|
|
391
391
|
# Erase screen part.
|
392
392
|
#
|
393
|
+
# @param [:below, :above, :all, :scrollback] part screen part to erase
|
393
394
|
# @return (see cursor_up)
|
394
395
|
def screen_erase(part = :all)
|
395
396
|
"\e[#{
|
@@ -446,6 +447,7 @@ module Terminal
|
|
446
447
|
|
447
448
|
# Erase part of line.
|
448
449
|
#
|
450
|
+
# @param [:to_end, :to_start, :all] part line part to erase
|
449
451
|
# @return (see cursor_up)
|
450
452
|
def line_erase(part = :all)
|
451
453
|
"\e[#{
|
@@ -468,14 +470,26 @@ module Terminal
|
|
468
470
|
def title(title) = "\e]2;#{title}\a"
|
469
471
|
|
470
472
|
# Set tab title.
|
471
|
-
# This is not widely supported
|
473
|
+
# This is not widely supported; works for
|
474
|
+
# Hyper,
|
475
|
+
# iTerm2,
|
476
|
+
# Kitty,
|
477
|
+
# MacOS Terminal,
|
478
|
+
# Tabby,
|
479
|
+
# WezTerm.
|
472
480
|
#
|
473
481
|
# @param (see title)
|
474
482
|
# @return (see cursor_up)
|
475
483
|
def tab_title(title) = "\e]0;#{title}\a"
|
476
484
|
|
477
485
|
# Create a hyperlink.
|
478
|
-
# This is not widely supported
|
486
|
+
# This is not widely supported; works for
|
487
|
+
# Ghosty,
|
488
|
+
# iTerm2,
|
489
|
+
# Kitty,
|
490
|
+
# Rio,
|
491
|
+
# Tabby,
|
492
|
+
# WezTerm.
|
479
493
|
#
|
480
494
|
# @param [#to_s] url URL to link to
|
481
495
|
# @param [#to_s] text text to display for the link
|
@@ -485,7 +499,7 @@ module Terminal
|
|
485
499
|
# Create scaled text.
|
486
500
|
# It uses the
|
487
501
|
# [text sizing protocol](https://sw.kovidgoyal.net/kitty/text-sizing-protocol).
|
488
|
-
# This is not widely supported.
|
502
|
+
# This is not widely supported; works for Kitty.
|
489
503
|
#
|
490
504
|
# @example Double-height Greeting
|
491
505
|
# Terminal::Ansi.scale('Hello Ruby!', scale: 2)
|
@@ -672,6 +686,7 @@ module Terminal
|
|
672
686
|
# def chars_delete(count = 1) = "\e[#{count}P"
|
673
687
|
# def chars_erase(count = 1) = "\e[#{count}X"
|
674
688
|
# def notify(title) = "\e]9;#{title}\a"
|
689
|
+
# def set_scroll_region(top = nil, bottom = nil) = "\e[#{top};#{bottom}r"
|
675
690
|
|
676
691
|
# @comment TODO:
|
677
692
|
# https://sw.kovidgoyal.net/kitty/desktop-notifications
|
data/lib/terminal/detect.rb
CHANGED
@@ -6,19 +6,19 @@ module Terminal
|
|
6
6
|
def application
|
7
7
|
return :kitty if ENV.key?('KITTY_PID')
|
8
8
|
return :alacritty if ENV.key?('ALACRITTY_WINDOW_ID')
|
9
|
-
|
9
|
+
app_by_tp || app_by_term
|
10
10
|
end
|
11
11
|
|
12
12
|
def colors
|
13
|
-
if
|
14
|
-
|
13
|
+
return 16_777_216 if ENV['COLORTERM'] == 'truecolor'
|
14
|
+
if %i[ghostty iterm kitty rio vscode wezterm tabby].include?(app_by_tp)
|
15
15
|
return 16_777_216
|
16
16
|
end
|
17
17
|
term = ENV['TERM'] or return 8
|
18
18
|
return 16_777_216 if /[+-]direct/.match?(term)
|
19
19
|
match = /[-+](\d+)color/.match(term) and return match[1].to_i
|
20
20
|
match = /[-+](\d+)bit/.match(term) and return 2**match[1].to_i
|
21
|
-
ret =
|
21
|
+
ret = color_by[term] and return ret
|
22
22
|
case term
|
23
23
|
when /^(?:iTerm\s?\d*\.app|nsterm-build\d+|terminology(-[0-9.]+)?)$/
|
24
24
|
256
|
@@ -31,8 +31,7 @@ module Terminal
|
|
31
31
|
|
32
32
|
private
|
33
33
|
|
34
|
-
def
|
35
|
-
value = ENV['TERM_PROGRAM'] or return
|
34
|
+
def app_by_tp
|
36
35
|
{
|
37
36
|
'Apple_Terminal' => :macos,
|
38
37
|
'CodeEditApp_Terminal' => :code_edit,
|
@@ -49,37 +48,43 @@ module Terminal
|
|
49
48
|
'WarpTerminal' => :warp,
|
50
49
|
'WezTerm' => :wezterm
|
51
50
|
}[
|
52
|
-
|
51
|
+
ENV['TERM_PROGRAM']
|
53
52
|
]
|
54
53
|
end
|
55
54
|
|
56
|
-
def
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
'
|
61
|
-
'
|
62
|
-
|
63
|
-
'dg+'
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
'
|
69
|
-
|
70
|
-
'
|
71
|
-
'
|
72
|
-
|
73
|
-
'
|
74
|
-
'
|
75
|
-
|
76
|
-
'
|
77
|
-
'
|
78
|
-
|
79
|
-
|
55
|
+
def app_by_term
|
56
|
+
term = ENV['TERM'] or return
|
57
|
+
case term[0]
|
58
|
+
when 'a'
|
59
|
+
return :alacritty if term.start_with?('alacritty')
|
60
|
+
:amiga if term.start_with?('amiga')
|
61
|
+
when 'd'
|
62
|
+
if term.start_with?('dg+') || term.start_with?('dgunix') ||
|
63
|
+
/\Ad4[37]0/.match?(term)
|
64
|
+
:dg_unix
|
65
|
+
end
|
66
|
+
when 'h'
|
67
|
+
:hpterm if term.start_with?('hp+') || term.start_with?('hpterm')
|
68
|
+
when 'm'
|
69
|
+
return :mintty if term.start_with?('mintty')
|
70
|
+
:ms_terminal if term.start_with?('ms-terminal')
|
71
|
+
when 'n'
|
72
|
+
return :ncr260 if term.start_with?('ncr260')
|
73
|
+
:nsterm if term.start_with?('nsterm')
|
74
|
+
when 't'
|
75
|
+
return :terminator if term.start_with?('terminator')
|
76
|
+
return :terminology if term.start_with?('terminology')
|
77
|
+
:termite if term.start_with?('termite')
|
78
|
+
when 'v'
|
79
|
+
:vt100 if term.start_with?('vt100')
|
80
|
+
when 'w'
|
81
|
+
:wyse if /\Awy3\d\d/.match?(term)
|
82
|
+
when 'x'
|
83
|
+
:xnuppc if term.start_with?('xnuppc')
|
84
|
+
end
|
80
85
|
end
|
81
86
|
|
82
|
-
def
|
87
|
+
def color_by
|
83
88
|
{
|
84
89
|
'alacritty' => 256,
|
85
90
|
'kitty' => 256,
|
@@ -142,9 +147,6 @@ module Terminal
|
|
142
147
|
'dummy' => 2
|
143
148
|
}
|
144
149
|
end
|
145
|
-
|
146
|
-
KNOW_APP_WITH_TRUE_COLOR = %i[kitty ghostty vscode iterm].freeze
|
147
|
-
private_constant :KNOW_APP_WITH_TRUE_COLOR
|
148
150
|
end
|
149
151
|
end
|
150
152
|
|
data/lib/terminal/input.rb
CHANGED
@@ -95,6 +95,7 @@ module Terminal
|
|
95
95
|
end
|
96
96
|
|
97
97
|
def csi_u?
|
98
|
+
# iTerm2 returns result in two chunks :/
|
98
99
|
ret = false
|
99
100
|
while true
|
100
101
|
result = read_tty or return false
|
@@ -109,5 +110,5 @@ module Terminal
|
|
109
110
|
autoload :CSIuKeys, "#{dir}/input/csiu_keys.rb"
|
110
111
|
autoload :DumbKeys, "#{dir}/input/dumb_keys.rb"
|
111
112
|
autoload :LegacyKeys, "#{dir}/input/legacy_keys.rb"
|
112
|
-
private_constant :CSIuKeys, :LegacyKeys
|
113
|
+
private_constant :CSIuKeys, :DumbKeys, :LegacyKeys
|
113
114
|
end
|
data/lib/terminal/text.rb
CHANGED
@@ -67,19 +67,15 @@ module Terminal
|
|
67
67
|
ignore_newline: false,
|
68
68
|
&block
|
69
69
|
)
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
if block
|
74
|
-
lim_lines(text, bbcode, ansi, ignore_newline, limit, &block)
|
75
|
-
else
|
76
|
-
to_enum(:lim_lines, text, bbcode, ansi, ignore_newline, limit)
|
77
|
-
end
|
78
|
-
elsif block
|
79
|
-
lines(text, bbcode, ansi, ignore_newline, &block)
|
80
|
-
else
|
81
|
-
to_enum(:lines, text, bbcode, ansi, ignore_newline)
|
70
|
+
unless limit
|
71
|
+
snippeds = as_snippeds(text, bbcode, ansi, ignore_newline, Word)
|
72
|
+
return block ? lines(snippeds, &block) : to_enum(:lines, snippeds)
|
82
73
|
end
|
74
|
+
limit = limit.to_i
|
75
|
+
raise(ArgumentError, "invalid limit - #{limit}") if limit < 1
|
76
|
+
snippeds = as_snippeds(text, bbcode, ansi, ignore_newline, WordEx)
|
77
|
+
return lim_lines(snippeds, limit, &block) if block
|
78
|
+
to_enum(:lim_lines, snippeds, limit)
|
83
79
|
end
|
84
80
|
alias each each_line
|
85
81
|
|
@@ -101,19 +97,15 @@ module Terminal
|
|
101
97
|
ignore_newline: false,
|
102
98
|
&block
|
103
99
|
)
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
if block
|
108
|
-
lim_pairs(text, bbcode, ansi, ignore_newline, limit, &block)
|
109
|
-
else
|
110
|
-
to_enum(:lim_pairs, text, bbcode, ansi, ignore_newline, limit)
|
111
|
-
end
|
112
|
-
elsif block
|
113
|
-
pairs(text, bbcode, ansi, ignore_newline, &block)
|
114
|
-
else
|
115
|
-
to_enum(:pairs, text, bbcode, ansi, ignore_newline)
|
100
|
+
unless limit
|
101
|
+
snippeds = as_snippeds(text, bbcode, ansi, ignore_newline, Word)
|
102
|
+
return block ? pairs(snippeds, &block) : to_enum(:pairs, snippeds)
|
116
103
|
end
|
104
|
+
limit = limit.to_i
|
105
|
+
raise(ArgumentError, "invalid limit - #{limit}") if limit < 1
|
106
|
+
snippeds = as_snippeds(text, bbcode, ansi, ignore_newline, WordEx)
|
107
|
+
return lim_pairs(snippeds, limit, &block) if block
|
108
|
+
to_enum(:lim_pairs, snippeds, limit)
|
117
109
|
end
|
118
110
|
alias each_with_size each_line_with_size
|
119
111
|
|
@@ -130,17 +122,11 @@ module Terminal
|
|
130
122
|
sco == 0xff9e || sco == 0xff9f ? 2 : 1
|
131
123
|
end
|
132
124
|
|
133
|
-
def lim_pairs(
|
125
|
+
def lim_pairs(snippeds, limit)
|
134
126
|
line = EMPTY.dup
|
135
127
|
size = 0
|
136
128
|
csi = nil
|
137
|
-
|
138
|
-
text,
|
139
|
-
bbcode,
|
140
|
-
ansi,
|
141
|
-
ignore_newline,
|
142
|
-
WordEx
|
143
|
-
).each do |snipped|
|
129
|
+
snippeds.each do |snipped|
|
144
130
|
if snipped == :space
|
145
131
|
next if size == 0
|
146
132
|
next line << ' ' if (size += 1) <= limit
|
@@ -150,13 +136,13 @@ module Terminal
|
|
150
136
|
end
|
151
137
|
|
152
138
|
if snipped == :nl
|
153
|
-
yield(line, size)
|
139
|
+
line[-1] == ' ' ? yield(line.chop, size - 1) : yield(line, size)
|
154
140
|
line = "#{csi}"
|
155
141
|
next size = 0
|
156
142
|
end
|
157
143
|
|
158
144
|
if snipped == :hard_nl
|
159
|
-
yield(line, size)
|
145
|
+
line[-1] == ' ' ? yield(line.chop, size - 1) : yield(line, size)
|
160
146
|
line = EMPTY.dup
|
161
147
|
csi = nil
|
162
148
|
next size = 0
|
@@ -183,13 +169,13 @@ module Terminal
|
|
183
169
|
end
|
184
170
|
yield(line, size) if size != 0
|
185
171
|
|
186
|
-
if snipped.size
|
172
|
+
if snipped.size <= limit
|
187
173
|
line = "#{csi}#{snipped}"
|
188
174
|
next size = snipped.size
|
189
175
|
end
|
190
176
|
|
191
177
|
words = snipped.split(limit)
|
192
|
-
if words[-1].size
|
178
|
+
if words[-1].size <= limit
|
193
179
|
snipped = words.pop
|
194
180
|
line = "#{csi}#{snipped}"
|
195
181
|
size = snipped.size
|
@@ -202,17 +188,50 @@ module Terminal
|
|
202
188
|
nil
|
203
189
|
end
|
204
190
|
|
205
|
-
def
|
191
|
+
def pairs(snippeds)
|
192
|
+
line = EMPTY.dup
|
193
|
+
size = 0
|
194
|
+
csi = nil
|
195
|
+
snippeds.each do |snipped|
|
196
|
+
if snipped == :space
|
197
|
+
next if size == 0
|
198
|
+
line << ' '
|
199
|
+
next size += 1
|
200
|
+
end
|
201
|
+
|
202
|
+
if snipped == :nl
|
203
|
+
line[-1] == ' ' ? yield(line.chop, size - 1) : yield(line, size)
|
204
|
+
line = "#{csi}"
|
205
|
+
next size = 0
|
206
|
+
end
|
207
|
+
|
208
|
+
if snipped == :hard_nl
|
209
|
+
line[-1] == ' ' ? yield(line.chop, size - 1) : yield(line, size)
|
210
|
+
line = EMPTY.dup
|
211
|
+
csi = nil
|
212
|
+
next size = 0
|
213
|
+
end
|
214
|
+
|
215
|
+
if snipped == CsiEnd
|
216
|
+
line << CsiEnd if csi
|
217
|
+
next csi = nil
|
218
|
+
end
|
219
|
+
|
220
|
+
next line << (csi = snipped) if snipped.is_a?(Csi)
|
221
|
+
next line << snipped if snipped.is_a?(Osc)
|
222
|
+
|
223
|
+
# Word:
|
224
|
+
line << snipped
|
225
|
+
size += snipped.size
|
226
|
+
end
|
227
|
+
nil
|
228
|
+
end
|
229
|
+
|
230
|
+
def lim_lines(snippeds, limit)
|
206
231
|
line = EMPTY.dup
|
207
232
|
size = 0
|
208
233
|
csi = nil
|
209
|
-
|
210
|
-
text,
|
211
|
-
bbcode,
|
212
|
-
ansi,
|
213
|
-
ignore_newline,
|
214
|
-
WordEx
|
215
|
-
).each do |snipped|
|
234
|
+
snippeds.each do |snipped|
|
216
235
|
if snipped == :space
|
217
236
|
next if size == 0
|
218
237
|
next line << ' ' if (size += 1) <= limit
|
@@ -222,13 +241,13 @@ module Terminal
|
|
222
241
|
end
|
223
242
|
|
224
243
|
if snipped == :nl
|
225
|
-
yield(line)
|
244
|
+
yield(line[-1] == ' ' ? line.chop : line)
|
226
245
|
line = "#{csi}"
|
227
246
|
next size = 0
|
228
247
|
end
|
229
248
|
|
230
249
|
if snipped == :hard_nl
|
231
|
-
yield(line)
|
250
|
+
yield(line[-1] == ' ' ? line.chop : line)
|
232
251
|
line = EMPTY.dup
|
233
252
|
csi = nil
|
234
253
|
next size = 0
|
@@ -255,13 +274,13 @@ module Terminal
|
|
255
274
|
end
|
256
275
|
yield(line) if size != 0
|
257
276
|
|
258
|
-
if snipped.size
|
277
|
+
if snipped.size <= limit
|
259
278
|
line = "#{csi}#{snipped}"
|
260
279
|
next size = snipped.size
|
261
280
|
end
|
262
281
|
|
263
282
|
words = snipped.split(limit)
|
264
|
-
if words[-1].size
|
283
|
+
if words[-1].size <= limit
|
265
284
|
snipped = words.pop
|
266
285
|
line = "#{csi}#{snipped}"
|
267
286
|
size = snipped.size
|
@@ -274,11 +293,11 @@ module Terminal
|
|
274
293
|
nil
|
275
294
|
end
|
276
295
|
|
277
|
-
def
|
296
|
+
def lines(snippeds)
|
278
297
|
line = EMPTY.dup
|
279
298
|
size = 0
|
280
299
|
csi = nil
|
281
|
-
|
300
|
+
snippeds.each do |snipped|
|
282
301
|
if snipped == :space
|
283
302
|
next if size == 0
|
284
303
|
line << ' '
|
@@ -286,13 +305,13 @@ module Terminal
|
|
286
305
|
end
|
287
306
|
|
288
307
|
if snipped == :nl
|
289
|
-
yield(line
|
308
|
+
yield(line[-1] == ' ' ? line.chop : line)
|
290
309
|
line = "#{csi}"
|
291
310
|
next size = 0
|
292
311
|
end
|
293
312
|
|
294
313
|
if snipped == :hard_nl
|
295
|
-
yield(line
|
314
|
+
yield(line[-1] == ' ' ? line.chop : line)
|
296
315
|
line = EMPTY.dup
|
297
316
|
csi = nil
|
298
317
|
next size = 0
|
@@ -313,62 +332,43 @@ module Terminal
|
|
313
332
|
nil
|
314
333
|
end
|
315
334
|
|
316
|
-
def lines(text, bbcode, ansi, ignore_newline)
|
317
|
-
line = EMPTY.dup
|
318
|
-
csi = nil
|
319
|
-
as_snippeds(text, bbcode, ansi, ignore_newline, Word).each do |snipped|
|
320
|
-
next line << ' ' if snipped == :space
|
321
|
-
|
322
|
-
if snipped == :nl
|
323
|
-
next if line.empty?
|
324
|
-
yield(line)
|
325
|
-
next line = "#{csi}"
|
326
|
-
end
|
327
|
-
|
328
|
-
if snipped == :hard_nl
|
329
|
-
yield(line)
|
330
|
-
line = EMPTY.dup
|
331
|
-
next csi = nil
|
332
|
-
end
|
333
|
-
|
334
|
-
if snipped == CsiEnd
|
335
|
-
line << CsiEnd if csi
|
336
|
-
next csi = nil
|
337
|
-
end
|
338
|
-
|
339
|
-
csi = snipped if snipped.is_a?(Csi)
|
340
|
-
# Csi, Osc, Word:
|
341
|
-
line << snipped
|
342
|
-
end
|
343
|
-
nil
|
344
|
-
end
|
345
|
-
|
346
335
|
def as_snippeds(text, bbcode, ansi, ignore_newline, word_class)
|
347
336
|
ret = []
|
348
337
|
last = nil
|
349
338
|
text.each do |txt|
|
350
339
|
if (txt = bbcode ? Ansi.bbcode(txt) : txt.to_s).empty?
|
351
|
-
next ret[-1] = last = :hard_nl if
|
340
|
+
next ret[-1] = last = :hard_nl if last.is_a?(Symbol)
|
352
341
|
next ret << (last = :hard_nl)
|
353
342
|
end
|
343
|
+
|
354
344
|
txt = txt.encode(ENC) if txt.encoding != ENC
|
345
|
+
|
355
346
|
txt.scan(SCAN_EXPR) do |nl, csi, osc, space, gc|
|
356
347
|
if gc
|
357
348
|
next last.add(gc, char_width(gc)) if last.is_a?(word_class)
|
358
349
|
next ret << (last = word_class.new(gc, char_width(gc)))
|
359
350
|
end
|
351
|
+
|
360
352
|
next last.is_a?(Symbol) ? nil : ret << (last = :space) if space
|
353
|
+
|
361
354
|
if nl
|
362
|
-
if ignore_newline
|
355
|
+
if ignore_newline # handle nl like space
|
363
356
|
next last.is_a?(Symbol) ? nil : ret << (last = :space)
|
364
357
|
end
|
365
358
|
next last == :space ? ret[-1] = last = :nl : ret << (last = :nl)
|
366
359
|
end
|
360
|
+
|
367
361
|
next unless ansi
|
362
|
+
|
368
363
|
next ret << (last = Osc.new(osc)) if osc
|
369
|
-
|
364
|
+
|
365
|
+
if csi == "\e[m" || csi == "\e[0m"
|
366
|
+
next last == CsiEnd ? nil : ret << (last = CsiEnd)
|
367
|
+
end
|
368
|
+
|
370
369
|
last.is_a?(Csi) ? last.add(csi) : ret << (last = Csi.new(csi))
|
371
370
|
end
|
371
|
+
|
372
372
|
next ret[-1] = last = :hard_nl if last.is_a?(Symbol)
|
373
373
|
ret << (last = :hard_nl)
|
374
374
|
end
|
@@ -378,15 +378,14 @@ module Terminal
|
|
378
378
|
|
379
379
|
class Osc
|
380
380
|
attr_reader :to_str, :size
|
381
|
-
|
381
|
+
alias _to_s to_s
|
382
382
|
alias to_s to_str
|
383
|
+
def inspect = "#{_to_s.chop} #{@to_str.inspect}>"
|
383
384
|
|
384
385
|
def initialize(str)
|
385
386
|
@to_str = str
|
386
387
|
@size = 0
|
387
388
|
end
|
388
|
-
|
389
|
-
def inspect = "#{to_s.chop} #{@to_str.inspect}>"
|
390
389
|
end
|
391
390
|
|
392
391
|
class Csi < Osc
|
@@ -403,8 +402,9 @@ module Terminal
|
|
403
402
|
|
404
403
|
class Word
|
405
404
|
attr_reader :to_str, :size
|
406
|
-
|
405
|
+
alias _to_s to_s
|
407
406
|
alias to_s to_str
|
407
|
+
def inspect = "#{_to_s.chop} #{@size}:#{@to_str.inspect}>"
|
408
408
|
|
409
409
|
def initialize(char, size)
|
410
410
|
@to_str = char.dup
|
@@ -415,8 +415,6 @@ module Terminal
|
|
415
415
|
@to_str << char
|
416
416
|
@size += size
|
417
417
|
end
|
418
|
-
|
419
|
-
def inspect = "#{to_s.chop} #{@size}:#{@to_str.inspect}>"
|
420
418
|
end
|
421
419
|
|
422
420
|
class WordEx < Word
|
data/lib/terminal/version.rb
CHANGED
data/lib/terminal.rb
CHANGED
@@ -182,7 +182,7 @@ module Terminal
|
|
182
182
|
# @param [#to_s] object object to write
|
183
183
|
# @return [Terminal] itself
|
184
184
|
def <<(object)
|
185
|
-
@out
|
185
|
+
@out.write(Ansi.bbcode(object)) if @out && object != nil
|
186
186
|
self
|
187
187
|
rescue IOError
|
188
188
|
@out = nil
|
@@ -197,17 +197,15 @@ module Terminal
|
|
197
197
|
# @return [nil]
|
198
198
|
def print(*objects, bbcode: true)
|
199
199
|
return unless @out
|
200
|
-
objects
|
201
|
-
|
202
|
-
return if (line = (bbcode ? @bbcode : @nobbcode)[line]).empty?
|
203
|
-
@out.write(line)
|
200
|
+
return @out.print(*objects) unless bbcode
|
201
|
+
objects.each { @out.write(Ansi.bbcode(_1)) }
|
204
202
|
nil
|
205
203
|
rescue IOError
|
206
204
|
@out = nil
|
207
205
|
end
|
208
206
|
|
209
207
|
# Writes the given objects to the terminal.
|
210
|
-
# Writes a newline after each
|
208
|
+
# Writes a newline after each object that does not already end with a
|
211
209
|
# newline sequence in it's String represenation.
|
212
210
|
# If called without any arguments, writes a newline only.
|
213
211
|
#
|
@@ -217,18 +215,10 @@ module Terminal
|
|
217
215
|
# @return (see print)
|
218
216
|
def puts(*objects, bbcode: true)
|
219
217
|
return unless @out
|
218
|
+
return @out.puts if objects.empty?
|
219
|
+
return @out.puts(objects) unless bbcode
|
220
220
|
objects.flatten!
|
221
|
-
|
222
|
-
@out.write("\n")
|
223
|
-
return
|
224
|
-
end
|
225
|
-
bbcode = bbcode ? @bbcode : @nobbcode
|
226
|
-
objects.each do |s|
|
227
|
-
next @out.write("\n") if s.nil?
|
228
|
-
@out.write(s = bbcode[s])
|
229
|
-
@out.write("\n") if s[-1] != "\n"
|
230
|
-
end
|
231
|
-
nil
|
221
|
+
objects.empty? ? @out.puts : @out.puts(objects.map! { Ansi.bbcode(_1) })
|
232
222
|
rescue IOError
|
233
223
|
@out = nil
|
234
224
|
end
|
@@ -261,20 +251,48 @@ module Terminal
|
|
261
251
|
@cc = 0
|
262
252
|
tty, @ansi = _determine_modes
|
263
253
|
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
254
|
+
unless tty.nil?
|
255
|
+
@out = STDOUT
|
256
|
+
@out.sync = true
|
257
|
+
if tty
|
258
|
+
@inf = STDOUT
|
259
|
+
@con = IO.console
|
260
|
+
Signal.trap('WINCH') { @size = nil } if Signal.list.key?('WINCH')
|
261
|
+
end
|
270
262
|
end
|
271
263
|
|
272
|
-
|
273
|
-
@
|
274
|
-
@
|
275
|
-
|
276
|
-
|
277
|
-
|
264
|
+
unless @ansi
|
265
|
+
@plain = ->(s) { Ansi.plain(s) }
|
266
|
+
@undecorate = ->(s) { Ansi.undecorate(s) }
|
267
|
+
|
268
|
+
class << self
|
269
|
+
alias << <<
|
270
|
+
def <<(object)
|
271
|
+
@out.write(Ansi.plain(object)) if @out && object != nil
|
272
|
+
self
|
273
|
+
rescue IOError
|
274
|
+
@out = nil
|
275
|
+
self
|
276
|
+
end
|
277
|
+
|
278
|
+
alias print print
|
279
|
+
def print(*objects, bbcode: true)
|
280
|
+
return if @out.nil? || objects.empty?
|
281
|
+
@out.print(*objects.map!(&(bbcode ? @plain : @undecorate)))
|
282
|
+
rescue IOError
|
283
|
+
@out = nil
|
284
|
+
end
|
285
|
+
|
286
|
+
alias puts puts
|
287
|
+
def puts(*objects, bbcode: true)
|
288
|
+
return unless @out
|
289
|
+
objects.flatten!
|
290
|
+
return @out.puts if objects.empty?
|
291
|
+
@out.puts(objects.map!(&(bbcode ? @plain : @undecorate)))
|
292
|
+
rescue IOError
|
293
|
+
@out = nil
|
294
|
+
end
|
295
|
+
end
|
278
296
|
end
|
279
297
|
|
280
298
|
dir = "#{__dir__}/terminal"
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: terminal_rb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.10.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mike Blumtritt
|
@@ -10,7 +10,7 @@ cert_chain: []
|
|
10
10
|
date: 1980-01-02 00:00:00.000000000 Z
|
11
11
|
dependencies: []
|
12
12
|
description: |
|
13
|
-
Terminal access with
|
13
|
+
Terminal access with super fast ANSI control codes support and
|
14
14
|
BBCode-like embedded text attribute syntax.
|
15
15
|
executables:
|
16
16
|
- bbcode
|
@@ -49,7 +49,7 @@ metadata:
|
|
49
49
|
rubygems_mfa_required: 'true'
|
50
50
|
source_code_uri: https://codeberg.org/mblumtritt/Terminal.rb
|
51
51
|
bug_tracker_uri: https://codeberg.org/mblumtritt/Terminal.rb/issues
|
52
|
-
documentation_uri: https://rubydoc.info/gems/terminal_rb/0.
|
52
|
+
documentation_uri: https://rubydoc.info/gems/terminal_rb/0.10.0/Terminal
|
53
53
|
rdoc_options: []
|
54
54
|
require_paths:
|
55
55
|
- lib
|
@@ -64,7 +64,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
64
64
|
- !ruby/object:Gem::Version
|
65
65
|
version: '0'
|
66
66
|
requirements: []
|
67
|
-
rubygems_version: 3.
|
67
|
+
rubygems_version: 3.7.0
|
68
68
|
specification_version: 4
|
69
|
-
summary:
|
69
|
+
summary: Fast terminal access with ANSI and BBCode support.
|
70
70
|
test_files: []
|