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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 977c06e8d495f8c0e73cff49642e812234cc5861d7495fc44f4dcef4f3b253ee
4
- data.tar.gz: 863d24475a32ef39f8f1298876f55d112f4443384ddab9f3fe6fda7228db828c
3
+ metadata.gz: 6b6f4c3e8cfa6ca602f831ef011a146ff0f70d77d9a0da4a7a37a9768e52da39
4
+ data.tar.gz: 73f1ce0355077b7803c7c03924aaa764e8dac2f05e2534a653f37ba4b7d32b27
5
5
  SHA512:
6
- metadata.gz: 2ad9fa7a857903776fddde3b4c4b00963f977c26f8e74662175234fe798615105f4a71c47a5d5cd02c944ed5090cc9c6892d164e1d2c7de9d013b0643d816115
7
- data.tar.gz: ef31547f441d1833ef53d79b0e04c70451573f97966410247d83d883f392da0917fab3f0008a8419925e6d7e261d02b43f011bdc7fc2ab2b2519c21648aff1e7
6
+ metadata.gz: 2e65c5d198050d41671d57fb5a60c67efd0d4f22c4da71cb4253e8260481fa5c0bc32713be85bf4d1c14a3e5eb7ad886f088ff78418059197b89bf685615a152
7
+ data.tar.gz: 9376328d7d488c039ce14411061ee41f4f46efa9ee244c33481f03a855bd6861e871248f3e5faee2b07826b09646e3789a09fd3e2398784c801d527d784114bf
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Terminal.rb ![version](https://img.shields.io/gem/v/terminal_rb?label=)
2
2
 
3
- Terminal access with support for ANSI control codes and [BBCode-like](https://en.wikipedia.org/wiki/BBCode) embedded text attribute syntax.
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
- next match_str if (match = Regexp.last_match[1]).empty?
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
- next match_str if (match = Regexp.last_match[1]).empty?
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
- next match_str if (match = Regexp.last_match[1]).empty?
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.to_i};" \
301
- "#{(Math.sin(i + PI2_THIRD) * 255).abs.to_i};" \
302
- "#{(Math.sin(i + PI4_THIRD) * 255).abs.to_i}m#{char}"
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
@@ -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
- app_from_term_program || app_from_term
9
+ app_by_tp || app_by_term
10
10
  end
11
11
 
12
12
  def colors
13
- if KNOW_APP_WITH_TRUE_COLOR.include?(app_from_term_program) ||
14
- (ENV['COLORTERM'] == 'truecolor')
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 = color_by_name[term] and return 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 app_from_term_program
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
- value
51
+ ENV['TERM_PROGRAM']
53
52
  ]
54
53
  end
55
54
 
56
- def app_from_term
57
- value = ENV['TERM'] or return
58
- {
59
- 'alacritty' => :alacritty,
60
- 'amiga' => :amiga,
61
- 'd430' => :dg_unix,
62
- 'd470' => :dg_unix,
63
- 'dg+' => :dg_unix,
64
- 'dgunix' => :dg_unix,
65
- 'hp+' => :hpterm,
66
- 'hpterm' => :hpterm,
67
- 'mintty' => :mintty,
68
- 'ms-terminal' => :ms_terminal,
69
- 'ncr260' => :ncr260,
70
- 'nsterm' => :nsterm,
71
- 'terminator' => :terminator,
72
- 'terminology' => :terminology,
73
- 'termite' => :termite,
74
- 'vt100' => :vt100,
75
- 'wy350' => :wyse,
76
- 'wy370' => :wyse,
77
- 'xnuppc' => :xnuppc
78
- }.each_pair { |str, type| return type if value.start_with?(str) }
79
- nil
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 color_by_name
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
 
@@ -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
- if limit
71
- limit = limit.to_i
72
- raise(ArgumentError, "invalid limit - #{limit}") if limit < 1
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
- if limit
105
- limit = limit.to_i
106
- raise(ArgumentError, "invalid limit - #{limit}") if limit < 1
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(text, bbcode, ansi, ignore_newline, limit)
125
+ def lim_pairs(snippeds, limit)
134
126
  line = EMPTY.dup
135
127
  size = 0
136
128
  csi = nil
137
- as_snippeds(
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 < limit
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 < limit
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 lim_lines(text, bbcode, ansi, ignore_newline, limit)
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
- as_snippeds(
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 < limit
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 < limit
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 pairs(text, bbcode, ansi, ignore_newline)
296
+ def lines(snippeds)
278
297
  line = EMPTY.dup
279
298
  size = 0
280
299
  csi = nil
281
- as_snippeds(text, bbcode, ansi, ignore_newline, Word).each do |snipped|
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, size)
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, size)
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 ret[-1] == :space
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
- next ret << (last = CsiEnd) if csi == "\e[m" || csi == "\e[0m"
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
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Terminal
4
4
  # The version number of the gem.
5
- VERSION = '0.9.6'
5
+ VERSION = '0.10.0'
6
6
  end
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&.write(@bbcode[object]) unless object.nil?
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.flatten!
201
- return if (line = objects.join).empty?
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 objects that does not already end with a
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
- if objects.empty?
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
- (@out = STDOUT).sync = true unless tty.nil?
265
-
266
- if tty
267
- @inf = STDOUT
268
- @con = IO.console
269
- Signal.trap('WINCH') { @size = nil } if Signal.list.key?('WINCH')
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
- if @ansi
273
- @bbcode = ->(s) { Ansi.bbcode(s) }
274
- @nobbcode = lambda(&:to_s)
275
- else
276
- @bbcode = ->(s) { Ansi.plain(s) }
277
- @nobbcode = ->(s) { Ansi.undecorate(s) }
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.9.6
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 support for ANSI control codes and
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.9.6/Terminal
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.6.9
67
+ rubygems_version: 3.7.0
68
68
  specification_version: 4
69
- summary: Easy terminal access with ANSI and BBCode support.
69
+ summary: Fast terminal access with ANSI and BBCode support.
70
70
  test_files: []