terminal_rb 1.0.4 → 1.0.6

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: cafc2d55ed2812b89586adb37fbe22d9c1a46bec4c7ab87f7ba326792254ff5f
4
- data.tar.gz: 1cf7e56b768478dbafa982fe555693cb110c1825476f155af52214853527b9c5
3
+ metadata.gz: 8f2f93f672f13936c9415cf3a474533df0f5785da3272f3482a02842a0607917
4
+ data.tar.gz: 52a1498c80085ea7667b7641416f406ae8694e02505a0c3201efd5f150f8d986
5
5
  SHA512:
6
- metadata.gz: 80820ee91b7ae9db787cdbeb0d28fc0bfeafae944ea5106008286b693e13dfed8fa718794cc5c2f656d47d0a1a84918b0708b92206e6e00ec180a75b4ab406d3
7
- data.tar.gz: 1fe8c92a73d3469cb356c924919dc2d4639e74706606f13b6cf7d06c299637ab193e4d6722d061dcfd59b854231d55c23c538dc4593ca21a5cfd600620bebc55
6
+ metadata.gz: 41cfbe3e34fa3db0af51674dc0f70f32dd08fb20d2b3a1040eff2834c65440f917f2ecea021500037658fbcf613373148c8399fdb29b7ea987916e71c570a65d
7
+ data.tar.gz: b6485ac5e2a9ba17ec72ffadc94cad6f5348ab846f885d12e9a68a338c15baeaa0d564ce1e1a4d2f946505887782e02dfd7221fc03e60bd3e7bb40afb88b47a1
data/README.md CHANGED
@@ -1,10 +1,10 @@
1
- # Terminal.rb v1.0.4
1
+ # Terminal.rb v1.0.6
2
2
 
3
3
  Terminal.rb supports you with input and output on your terminal. Simple [BBCode](https://en.wikipedia.org/wiki/BBCode)-like markup for attributes and coloring, word-wise line breaks, correct special key recognition and mouse event reporting enable you to implement your CLI app quickly and easily.
4
4
 
5
5
  - Gem: [rubygems.org](https://rubygems.org/gems/terminal_rb)
6
6
  - Source: [codeberg.org](https://codeberg.org/mblumtritt/Terminal.rb)
7
- - Help: [rubydoc.info](https://rubydoc.info/gems/terminal_rb/1.0.4/Terminal)
7
+ - Help: [rubydoc.info](https://rubydoc.info/gems/terminal_rb/1.0.6/Terminal)
8
8
 
9
9
  ## Features
10
10
 
@@ -0,0 +1,39 @@
1
+ [b red]Lorem ipsum[/] dolor sit amet, [yellow]consectetur[/] adipiscing elit. Praesent odio orci, [black on_bright_yellow]congue[/] sit amet turpis a, posuere [inv]congue[/] purus. Proin et lectus eget mi vehicula [i green uu]pellentesque[/] nec eu sem. Quisque nunc lectus, [uu]pharetra[/] non justo nec, porttitor mollis enim. Aenean dapibus massa tortor. Curabitur iaculis consequat sapien, eget [i green uu]pellentesque[/] turpis tempor bibendum. Nam cursus at quam vel [yellow]sollicitudin[/]. Etiam luctus nisl nisl, at eleifend tortor blandit non. Duis non suscipit quam. Vestibulum commodo molestie [u]fermentum[/]. Vivamus gravida dui sed nisl ornare, in eleifend leo tristique. Pellentesque eget eleifend [i]augue[/].
2
+
3
+ Vestibulum ultrices, ipsum ut volutpat aliquet, lectus mauris varius ante, non faucibus massa nisi et magna. Nullam id lacus sit amet nisi luctus gravida ut ac odio. Suspendisse ligula erat, vehicula sit amet nulla eget, porta semper neque. Fusce eget ultrices massa. Sed quis mauris tempor, [black on_bright_yellow]congue[/] nibh sed, lacinia mauris. Pellentesque convallis viverra ultrices. Ut sit amet massa [yellow]sollicitudin[/] lectus [uu]pharetra[/] vehicula. Ut hendrerit risus sit amet consequat maximus. Aliquam at ligula at nulla bibendum laoreet ac vitae [i]augue[/]. Sed ullamcorper, orci vel fringilla imperdiet, nisl leo [yellow]consectetur[/] nunc, sit amet pulvinar tortor nulla quis ex.
4
+
5
+ Morbi vitae [i]augue[/] eu neque laoreet [black on_bright_yellow]congue[/]. Integer eu est libero. Quisque consequat felis ipsum, quis consequat dui eleifend eu. Quisque malesuada ipsum vel arcu [yellow]consectetur[/] fringilla. Integer eu eleifend enim. Nam feugiat rutrum justo, consequat ornare massa molestie quis. Aenean eget malesuada ex. Morbi [yellow]sollicitudin[/] commodo nisi, nec auctor ante porta vitae. Aenean tristique ligula sit amet purus ultricies auctor. Nam [cu]finibus[/], libero at vestibulum mattis, diam ipsum placerat massa, sit amet porta ligula libero et lorem. Nullam est tellus, elementum venenatis justo aliquam, pulvinar rutrum nulla. Phasellus nec nisl sem. Sed [i green uu]sagittis[/] nulla sed aliquet auctor. Quisque sit amet [yellow]sollicitudin[/] massa, ut porttitor lacus. Aliquam at sem nec lacus varius pretium rhoncus vel mi. Praesent et lacus sed nunc lacinia porttitor.
6
+
7
+ Nulla mauris [i]augue[/], lacinia sit amet porta et, efficitur in ex. Fusce a fringilla ex. Phasellus ut sem justo. Sed nec sapien orci. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Maecenas lectus dui, pretium quis massa vel, gravida commodo mi. Proin feugiat, felis eget bibendum dictum, urna velit cursus odio, ut accumsan ligula orci eu nibh. Donec cursus placerat est ac euismod.
8
+
9
+ Aliquam erat volutpat. Suspendisse iaculis leo porttitor quam pretium lacinia. Morbi euismod sit amet enim in condimentum. Morbi sed [uu]pharetra[/] purus. Vivamus quis libero sed neque [inv]congue[/] egestas. Mauris ullamcorper ipsum vel justo eleifend fringilla. Mauris facilisis quam convallis mauris [inv]congue[/] tempor. Fusce tortor purus, ultrices ut molestie sit amet, [u]fermentum[/] vel quam.
10
+
11
+ Duis placerat ultricies [i green uu]pellentesque[/]. Nam nec efficitur orci, in [yellow]sollicitudin[/] sapien. Nunc condimentum aliquet enim id efficitur. Nulla tempus urna ex. Ut sed dolor eget sapien faucibus imperdiet et tincidunt ex. Vestibulum feugiat vel quam id eleifend. Sed tristique a mauris eget [white on_red]lobortis[/]. Nulla mollis est ipsum, in [black on_bright_yellow]congue[/] nisi maximus eget. Phasellus laoreet rutrum facilisis. In suscipit elementum lorem, a blandit turpis.
12
+
13
+ Suspendisse suscipit in odio quis facilisis. Aliquam nec eros ultrices, hendrerit lacus sit amet, bibendum turpis. Duis ligula ligula, efficitur non tortor quis, ornare dictum urna. Nam blandit lorem blandit turpis laoreet malesuada. Duis et magna ut lorem tempus dignissim. Phasellus dui turpis, ultrices et aliquam nec, pulvinar sed [i]augue[/]. Morbi [uu]pharetra[/] laoreet ipsum non laoreet. Pellentesque a felis vitae sapien condimentum [yellow]sollicitudin[/]. Etiam in nisl eget odio luctus gravida. Donec [yellow]sollicitudin[/] risus porta, scelerisque est ut, pulvinar odio. Nulla at suscipit tortor. Curabitur euismod [inv]congue[/] rhoncus. Cras imperdiet enim arcu, non vehicula tortor tincidunt non. Vivamus tincidunt [u]fermentum[/] quam et dignissim. In lacinia venenatis nunc, non [inv]congue[/] ipsum [inv]congue[/] ut.
14
+
15
+ Donec vitae nulla id elit efficitur facilisis ut sit amet enim. Nam sed magna lorem. Sed scelerisque vel urna sed porta. Donec a orci vel est interdum ultricies ac eu mi. Quisque condimentum luctus venenatis. Proin laoreet [yellow]sollicitudin[/] magna. Proin at nisl a sem condimentum vehicula. Fusce interdum ipsum ac lectus [u]fermentum[/] rutrum. Fusce aliquam, eros at interdum semper, purus urna vulputate lacus, eu [u]fermentum[/] felis sem ut nisl. Pellentesque at viverra libero. Integer [u]fermentum[/] vestibulum tortor, eu aliquam tortor [black on_bright_yellow]congue[/] at. Vestibulum vel fringilla velit. Proin ultricies magna ac ipsum bibendum porttitor. Duis nec leo urna. Morbi rhoncus fringilla [cu]finibus[/].
16
+
17
+ Praesent metus mi, laoreet vel enim in, luctus aliquam odio. Maecenas ultrices metus quam, eget auctor ante [cu]finibus[/] ac. Etiam venenatis et tellus nec suscipit. Sed a nunc libero. In hac habitasse platea dictumst. Ut cursus efficitur dolor, at fringilla risus. Etiam id placerat tellus. Cras sit amet [white on_red]lobortis[/] turpis. Sed bibendum dolor tortor, a elementum nunc molestie cursus. Nullam nec lectus in [i]augue[/] commodo [i green uu]sagittis[/] sed eu tellus. Nam vitae mollis eros. Vivamus ut rhoncus risus. Phasellus [i]augue[/] risus, ultrices ac aliquet quis, suscipit at ipsum. Ut eu odio in felis facilisis [uu]pharetra[/] vitae ut neque. Nunc eget risus [white on_red]lobortis[/], placerat neque id, aliquet arcu. Etiam est tortor, ultricies sit amet eleifend eget, maximus nec ipsum.
18
+
19
+ Proin ex turpis, viverra a convallis at, tincidunt et mi. Ut venenatis tincidunt nisl ac rhoncus. Sed dapibus, metus sit amet [yellow]consectetur[/] mattis, nunc lectus [black on_bright_yellow]congue[/] metus, vitae ornare [i]augue[/] diam eu [i]augue[/]. Proin eget sapien a lorem laoreet [yellow]consectetur[/]. Morbi [i green uu]sagittis[/], dui at egestas malesuada, felis lectus aliquet ante, nec euismod tellus elit semper ante. Nulla vehicula non nibh a aliquet. Donec a massa eget justo tincidunt ullamcorper. Praesent elementum dictum orci et convallis. Sed non dui a [i]augue[/] accumsan vestibulum. Vestibulum id lacus [black on_bright_yellow]congue[/], hendrerit justo sit amet, suscipit magna. Mauris ultrices mattis diam a [white on_red]lobortis[/]. Ut interdum et sapien in [white on_red]lobortis[/].
20
+
21
+ Suspendisse placerat in ex et auctor. Nunc maximus metus quis [black on_bright_yellow]congue[/] suscipit. Vivamus lectus mi, efficitur vel turpis id, suscipit fringilla nunc. Fusce malesuada massa turpis. Aliquam dolor orci, facilisis eu lorem id, elementum placerat ipsum. Proin ac sem sem. Cras [cu]finibus[/] varius fringilla. Fusce non feugiat risus, ut egestas massa. Suspendisse vestibulum [i]augue[/] eu dapibus egestas. Nulla facilisi. Sed ut nulla eu massa fringilla commodo nec vitae neque.
22
+
23
+ Curabitur gravida posuere nunc ut placerat. Phasellus aliquam interdum [u]fermentum[/]. Ut ac mi erat. Morbi [yellow]consectetur[/] odio non nibh ultricies [u]fermentum[/]. Nam dolor enim, mollis at purus a, euismod facilisis ex. Pellentesque dui massa, [yellow]sollicitudin[/] vitae [white on_red]lobortis[/] nec, malesuada a eros. Donec [yellow]sollicitudin[/] tempor volutpat. Cras ac dignissim velit. Cras nec blandit lorem.
24
+
25
+ Phasellus [black on_bright_yellow]congue[/] eu urna non mollis. Suspendisse magna turpis, maximus eget ornare vel, [inv]congue[/] id nisl. Proin feugiat molestie odio quis semper. Pellentesque convallis viverra euismod. Mauris porttitor rhoncus eros, at egestas urna. Nam eget condimentum mi. Fusce ut purus metus. Sed sed ipsum nibh. Vestibulum vehicula tempor turpis, at rhoncus tellus porttitor sed.
26
+
27
+ Donec id dictum sem, ut vulputate nisl. Donec [black on_bright_yellow]congue[/] eleifend purus, eu pretium eros laoreet non. Duis commodo justo a quam laoreet egestas. Donec eu mauris ac metus pulvinar venenatis. Praesent dictum urna ac iaculis vehicula. Ut non felis viverra, semper odio ornare, [yellow]sollicitudin[/] purus. Sed nec metus vehicula, elementum sapien eu, ultrices massa. Quisque tristique semper luctus. Vestibulum sit amet diam sed purus [black on_bright_yellow]congue[/] efficitur et non justo. In massa magna, accumsan at condimentum sit amet, pretium ut orci. Nulla [uu]pharetra[/] magna a metus vehicula varius. Integer et lacus semper, suscipit [i]augue[/] non, [yellow]consectetur[/] nisi. In id tellus vel turpis tristique dignissim nec vel lectus. Sed interdum diam felis, at bibendum arcu feugiat sed.
28
+
29
+ Morbi tortor urna, suscipit non nulla nec, cursus interdum nisl. Nam ante nisi, suscipit a felis eu, faucibus tincidunt metus. Mauris gravida tellus in ipsum porttitor lacinia eu et ante. Maecenas blandit eleifend dui, eu viverra leo. Ut eu [i green uu]pellentesque[/] est. Cras id [cu]finibus[/] ipsum. Vestibulum eget mi ac ante dictum dictum scelerisque at nibh. Ut accumsan aliquam eros eget tincidunt. Nunc sit amet dignissim mauris. Praesent id [i]augue[/] consequat lectus [u]fermentum[/] accumsan quis ut elit. Proin venenatis eros lacus, non ullamcorper purus [u]fermentum[/] vitae. Fusce dolor libero, pretium ac mi nec, porta elementum mauris. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Sed viverra cursus ultricies.
30
+
31
+ Nam egestas ante a dui mollis rutrum. Phasellus a dapibus arcu. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Suspendisse ac tortor in urna tristique bibendum. Aliquam ultrices, sem sit amet semper vehicula, [i]augue[/] erat porttitor [i]augue[/], a pretium nisi magna [i green uu]pellentesque[/] enim. Vestibulum nec nibh vitae nulla interdum [cu]finibus[/] ut viverra dolor. Pellentesque quis lacus enim. Donec et auctor mi. Curabitur eu [i green uu]pellentesque[/] risus. Aliquam [cu]finibus[/] dolor nec velit placerat [inv]congue[/]. Duis eget porttitor dolor. Vestibulum turpis nisi, porttitor ac pulvinar ac, vehicula viverra quam. In mollis, ante sit amet dictum [inv]congue[/], turpis dui luctus sem, eget convallis risus velit eget lorem.
32
+
33
+ Nam quis accumsan tellus, vitae dictum lectus. Donec varius porta metus et iaculis. Ut et consequat est, nec tincidunt neque. Sed ullamcorper lectus eu enim suscipit, sed tincidunt massa dictum. Sed venenatis elit metus, [inv]congue[/] aliquam lectus [i green uu]sagittis[/] at. Pellentesque ante arcu, pulvinar ut commodo at, consequat id sapien. Nunc mollis dolor eu ultricies mattis.
34
+
35
+ Phasellus et elementum lectus, vitae convallis nunc. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Sed dictum arcu [white on_red]lobortis[/] erat vulputate rhoncus. Ut id imperdiet justo. Donec vehicula in eros at lacinia. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Nam iaculis [black on_bright_yellow]congue[/] dignissim. Duis vel quam feugiat, gravida quam non, volutpat nisi. Integer eget auctor mauris, consequat dignissim nunc. Ut scelerisque [i]augue[/] aliquam erat rutrum, vitae aliquet est semper. Etiam nec velit lorem. Ut malesuada auctor metus sit amet posuere. Vivamus quis ipsum magna. Vivamus libero erat, dictum ut lorem auctor, tincidunt ultricies tortor. Suspendisse faucibus, ligula id auctor tincidunt, odio ligula tristique [i]augue[/], ac interdum ligula justo dictum magna.
36
+
37
+ Aliquam eros sapien, [inv]congue[/] ut metus eget, blandit iaculis ex. Donec id condimentum leo. Nunc [white on_red]lobortis[/] [yellow]consectetur[/] nunc nec posuere. Curabitur id iaculis diam. Nullam elementum luctus odio, et vehicula velit scelerisque at. Sed lorem nisl, malesuada quis massa sed, hendrerit [uu]pharetra[/] eros. Pellentesque leo mi, placerat id maximus ut, consequat sed turpis. Nulla nunc mi, convallis at iaculis non, ultricies vel tortor. Donec purus velit, molestie in [u]fermentum[/] ut, [black on_bright_yellow]congue[/] in dui. Morbi molestie, enim tempus malesuada consequat, orci lacus bibendum velit, non porta nisi ante a ipsum. Donec vitae nulla nulla.
38
+
39
+ Nulla varius dignissim turpis ac consequat. Fusce ut varius sapien. Cras [yellow]consectetur[/] est eleifend, imperdiet nibh a, dapibus justo. Etiam vehicula, est ac aliquam consequat, ante nibh porta ex, dictum suscipit diam justo et sapien. Sed porttitor ipsum nec diam [u]fermentum[/], vitae mattis diam gravida. Vivamus ac elementum ex, vitae maximus est. Maecenas tempor elementum pretium. Cras aliquam magna sit amet ipsum rutrum commodo. Aliquam cursus tincidunt sapien, et imperdiet sem [black on_bright_yellow]congue[/].
@@ -52,7 +52,7 @@ module Terminal
52
52
  # Total number of lines.
53
53
  #
54
54
  # @attribute [r] line_count
55
- # @return [Integer, nil] +nil+ when not already calculated
55
+ # @return [Integer, nil] `nil` when not already calculated
56
56
  def line_count = @buf&.size
57
57
 
58
58
  # Index of the topmost visible line.
@@ -68,7 +68,7 @@ module Terminal
68
68
 
69
69
  # Resize to the current terminal dimensions and redraw.
70
70
  #
71
- # @return [self, nil] +nil+ when resize is not required
71
+ # @return [self, nil] `nil` when resize is not required
72
72
  def resize_to_screen = _resize(*Terminal.size)
73
73
 
74
74
  # Resize to specific dimensions (clamped to terminal bounds)
@@ -76,7 +76,7 @@ module Terminal
76
76
  #
77
77
  # @param rows [Integer] new row count
78
78
  # @param columns [Integer] new column count
79
- # @return [self, nil] +nil+ when resize is not required
79
+ # @return [self, nil] `nil` when resize is not required
80
80
  def resize(rows, columns)
81
81
  _resize(
82
82
  rows.clamp(1, Terminal.rows),
@@ -99,7 +99,7 @@ module Terminal
99
99
 
100
100
  # Scroll to the beginning of the content.
101
101
  #
102
- # @return [self, nil] +nil+ when already on begin
102
+ # @return [self, nil] `nil` when already on begin
103
103
  def begin
104
104
  return draw unless @buf
105
105
  return if @line_top == 0
@@ -109,7 +109,7 @@ module Terminal
109
109
 
110
110
  # Scroll to the end of the content.
111
111
  #
112
- # @return [self, nil] +nil+ when already on end
112
+ # @return [self, nil] `nil` when already on end
113
113
  def end
114
114
  return draw unless @buf
115
115
  idx = @buf.size - @rows_visible
data/lib/terminal/ansi.rb CHANGED
@@ -45,7 +45,7 @@ module Terminal
45
45
  # Generate an ANSI escape sequence from attribute names or color
46
46
  # indices.
47
47
  #
48
- # Accepts symbols (`:bold`, +:red+), strings (`"bold"`, +"#ff0000"+),
48
+ # Accepts symbols (`:bold`, `:red`), strings (`"bold"`, `"#ff0000"`),
49
49
  # or integers for 256-color palette (0-255 foreground, 256-511
50
50
  # background, 512-767 underline color).
51
51
  #
@@ -122,11 +122,11 @@ module Terminal
122
122
  #
123
123
  # @example
124
124
  # Terminal::Ansi.try_convert('bold red') # => "\e[1;31m"
125
- # Terminal::Ansi.try_convert('invalid') # => nil
125
+ # Terminal::Ansi.try_convert('invalid') # => nil
126
126
  #
127
127
  # @param attributes [#to_s] space-separated attribute names
128
128
  # @param separator [String] delimiter for splitting
129
- # @return [String, nil] ANSI escape sequence, or +nil+ if any
129
+ # @return [String, nil] ANSI escape sequence, or `nil` if any
130
130
  # attribute is invalid
131
131
  def try_convert(attributes, separator: ' ')
132
132
  return unless attributes
@@ -168,9 +168,9 @@ module Terminal
168
168
 
169
169
  # Convert BBCode markup to ANSI escape codes.
170
170
  #
171
- # Tags like +[bold]+ are converted to their ANSI equivalents;
172
- # +[/bold]+ or +[/]+ resets. Unknown tags are left unchanged.
173
- # Escape a tag with a backslash: +[\\bold]+ renders as +[bold]+.
171
+ # Tags like `[bold]` are converted to their ANSI equivalents;
172
+ # `[/bold]` or `[/]` resets. Unknown tags are left unchanged.
173
+ # Escape a tag with a backslash: `[\\bold]` renders as `[bold]`.
174
174
  #
175
175
  # @see .unbbcode
176
176
  # @see .plain
@@ -361,7 +361,7 @@ module Terminal
361
361
  # Terminal::Ansi.cursor_pos(1, 1) # home position
362
362
  # Terminal::Ansi.cursor_pos(10, 5) # row 10, column 5
363
363
  #
364
- # @param row [Integer, nil] row number; +nil+ moves to home
364
+ # @param row [Integer, nil] row number; `nil` moves to home
365
365
  # @param column [Integer, nil] column number
366
366
  # @return (see .[])
367
367
  def cursor_pos(row, column = nil)
@@ -396,7 +396,7 @@ module Terminal
396
396
  # Erase part of the screen.
397
397
  #
398
398
  # @param part [Symbol] area to erase:
399
- # +:all+, +:below+, +:above+, or +:scrollback+
399
+ # `:all`, `:below`, `:above`, or `:scrollback`
400
400
  # @return (see .[])
401
401
  def screen_erase(part = :all) = "\e[#{@screen_erase[part]}J"
402
402
 
@@ -449,7 +449,7 @@ module Terminal
449
449
  # Erase part of the current line.
450
450
  #
451
451
  # @param part [Symbol] area to erase:
452
- # +:all+, +:to_end+, or +:to_start+
452
+ # `:all`, `:to_end`, or `:to_start`
453
453
  # @return (see .[])
454
454
  def line_erase(part = :all) = "\e[#{@line_erase[part]}K"
455
455
 
@@ -472,7 +472,7 @@ module Terminal
472
472
  # @see .link_end
473
473
  #
474
474
  # @param url [#to_s] the link URL
475
- # @param params [Hash] optional link parameters (e.g., +id:+)
475
+ # @param params [Hash] optional link parameters (e.g., `id:`)
476
476
  # @return (see .[])
477
477
  def link_start(url, **params)
478
478
  "\e]8;#{params.map { it.join('=') }.join(':')};#{url}\a"
@@ -520,12 +520,12 @@ module Terminal
520
520
  # Terminal.raw_write(Terminal::Ansi.progress(:error)) # error state
521
521
  # Terminal.raw_write(Terminal::Ansi.progress(nil)) # hide
522
522
  #
523
- # @param state [Symbol, Numeric, Boolean] progress state:
524
- # - +:show+ or +true+ to show, `:err`/`:error`, `:warn`/`:warning`,
525
- # +:indeterminate+, a +Numeric+ (0-100) to set percentage, or
523
+ # @param state [Symbol, Numeric, true, false] progress state:
524
+ # - `:show` or `true` to show, `:err`/`:error`, `:warn`/`:warning`,
525
+ # `:indeterminate`, a `Numeric` (0-100) to set percentage, or
526
526
  # any other value to hide
527
- # @param percent [Integer] progress percentage (0-100, used with
528
- # +:show+ state)
527
+ # @param percent [#to_i] progress percentage (0-100, used with
528
+ # `:show` state)
529
529
  # @return (see .[])
530
530
  def progress(state, percent = 0)
531
531
  case state
@@ -563,9 +563,9 @@ module Terminal
563
563
  # @param fracd [Integer, nil] fractional denominator
564
564
  # (must be > fracn, max 15)
565
565
  # @param vertical [Symbol, Integer, nil] vertical alignment:
566
- # +:top+, +:bottom+, +:middle+
566
+ # `:top`, `:bottom`, `:middle`
567
567
  # @param horizontal [Symbol, Integer, nil] horizontal alignment:
568
- # +:left+, +:right+, +:center+
568
+ # `:left`, `:right`, `:center`
569
569
  # @return (see .[])
570
570
  def scale(
571
571
  text,
@@ -6,14 +6,13 @@ module Terminal
6
6
  attr_reader :input_mode
7
7
 
8
8
  def on_key_event(mouse: false, mouse_move: false, focus: false)
9
- raise('already reading key events') if (@in_recursion += 1) != 1
10
9
  return unless block_given?
11
- opts = __input_option(mouse, mouse_move, focus)
10
+ opts = nil
12
11
  STDIN.noecho do
13
- opts &&= @in.syswrite("#{opts}h") ? "#{opts}l" : nil
12
+ opts = __input_options(mouse, mouse_move, focus)
14
13
  while (raw = @in.getch)
15
14
  next yield(KeyEvent[raw]) if raw != "\e"
16
- while String === (nc = @in.read_nonblock(1, exception: false))
15
+ while (nc = @in.read_nonblock(1, exception: false)).is_a?(String)
17
16
  raw << nc
18
17
  end
19
18
  next yield(KeyEvent[raw]) if raw.rindex("\e") < 2
@@ -25,13 +24,15 @@ module Terminal
25
24
  __input_error
26
25
  false
27
26
  ensure
28
- @in_recursion -= 1
29
- @in.syswrite(opts) if opts && @in
27
+ if opts
28
+ @in_opts.pop
29
+ @in&.syswrite(opts)
30
+ end
30
31
  end
31
32
 
32
33
  private
33
34
 
34
- def __input_option(mouse, mouse_move, focus)
35
+ def __input_options(mouse, mouse_move, focus)
35
36
  opts = (mouse ? ['1000'] : [])
36
37
  # highlight: '1001'
37
38
  # drag: '1002'
@@ -41,7 +42,19 @@ module Terminal
41
42
  # sgr: '1006'
42
43
  # urxvt: '1015'
43
44
  # pixel: '1016'
44
- "\e[?#{opts.join(';')};1006" unless opts.empty?
45
+ if (last = @in_opts[-1])
46
+ if opts.empty?
47
+ @in.syswrite("#{last}l")
48
+ return "#{last}h"
49
+ end
50
+ @in_opts << (opts = "\e[?#{opts.join(';')};1006")
51
+ @in.syswrite("#{last}l#{opts}h")
52
+ return "#{opts}l#{last}h"
53
+ end
54
+ return if opts.empty?
55
+ @in_opts << (opts = "\e[?#{opts.join(';')};1006")
56
+ @in.syswrite("#{opts}h")
57
+ "#{opts}l"
45
58
  end
46
59
  end
47
60
 
@@ -5,8 +5,7 @@ module Terminal
5
5
  module DumpInput
6
6
  def input_mode = :dumb
7
7
 
8
- def on_key_event(*_)
9
- raise('already reading key events') if (@in_recursion += 1) != 1
8
+ def on_key_event(*)
10
9
  return unless block_given?
11
10
  while (raw = STDIN.getc)
12
11
  opts = dumb_keys[raw.ord] if raw.size == 1
@@ -17,8 +16,6 @@ module Terminal
17
16
  rescue IOError, SystemCallError
18
17
  __input_error
19
18
  false
20
- ensure
21
- @in_recursion -= 1
22
19
  end
23
20
 
24
21
  private
@@ -23,8 +23,8 @@ module Terminal
23
23
  class KeyEvent
24
24
  # The key identifier.
25
25
  #
26
- # @return [Symbol, String, nil] a named key like +:Enter+, +:Tab+,
27
- # +:MBLeft+ (mouse), or a character string like +"a"+; +nil+ for
26
+ # @return [Symbol, String, nil] a named key like `:Enter`, `:Tab`,
27
+ # `:MBLeft` (mouse), or a character string like `"a"`; `nil` for
28
28
  # unknown sequences
29
29
  attr_reader :key
30
30
 
@@ -61,8 +61,8 @@ module Terminal
61
61
 
62
62
  # Mouse position when this is a mouse event.
63
63
  #
64
- # @return [Array<Integer, Integer>, nil] +[row, column]+ for mouse
65
- # events, +nil+ for keyboard events
64
+ # @return [Array<Integer, Integer>, nil] `[row, column]` for mouse
65
+ # events, `nil` for keyboard events
66
66
  attr_reader :position
67
67
 
68
68
  # The raw input sequence as received from the terminal.
@@ -85,8 +85,8 @@ module Terminal
85
85
  # @private
86
86
  # Destructuring-friendly array representation.
87
87
  #
88
- # @return [Array<String>] +[raw]+ if {#simple?}
89
- # @return [Array<String, String>] +[raw, name]+ otherwise
88
+ # @return [Array<String>] `[raw]` if {#simple?}
89
+ # @return [Array<String, String>] `[raw, name]` otherwise
90
90
  def to_ary = simple? ? [@raw] : [@raw, @name]
91
91
 
92
92
  # @return [String] the event {#name}
@@ -140,7 +140,7 @@ module Terminal
140
140
  @names ||=
141
141
  (@csiu.values + @csi.values + @ss3.values)
142
142
  .uniq
143
- .keep_if { Symbol === it }
143
+ .keep_if { it.is_a?(Symbol) }
144
144
  .sort!
145
145
  ).dup
146
146
  end
@@ -15,7 +15,7 @@ module Terminal
15
15
  # Terminal.input_mode # => :csi_u
16
16
  #
17
17
  # @attribute [r] input_mode
18
- # @return [Symbol] +:csi_u+, +:legacy+, +:dumb+, or +:error+
18
+ # @return [Symbol] `:csi_u`, `:legacy`, `:dumb`, or `:error`
19
19
 
20
20
  #
21
21
  # @!endgroup
@@ -42,8 +42,7 @@ module Terminal
42
42
  # @param focus [true, false] enable terminal focus/unfocus events
43
43
  # @yield [event] called for each input event
44
44
  # @yieldparam event [KeyEvent] the parsed key event
45
- # @return [nil, false] +false+ on I/O error
46
- # @raise [RuntimeError] if already inside a key event loop
45
+ # @return [nil, false] `false` on I/O error
47
46
 
48
47
  # @!method self.read_key_event
49
48
  #
@@ -53,7 +52,7 @@ module Terminal
53
52
  # event = Terminal.read_key_event
54
53
  # puts "You pressed: #{event.name}"
55
54
  #
56
- # @return [KeyEvent, false] the next key event, or +false+ on error
55
+ # @return [KeyEvent, false] the next key event, or `false` on error
57
56
 
58
57
  #
59
58
  # @!endgroup
@@ -62,10 +61,10 @@ module Terminal
62
61
  # @private
63
62
  module Input
64
63
  def input_mode
65
- @in_recursion = 0
66
64
  case @input_mode = __find_input_mode
67
65
  when :legacy, :csi_u
68
66
  @in = IO.console
67
+ @in_opts = []
69
68
  require_relative('input/ansi')
70
69
  extend AnsiInput
71
70
  when :dumb
@@ -105,7 +104,7 @@ module Terminal
105
104
  con = IO.console
106
105
  STDIN.noecho do
107
106
  return :legacy if con.syswrite("\e[>1u\e[?u\e[c") != 12
108
- inp = +''
107
+ inp = ''.b
109
108
  inp << con.getch until inp.rindex('c')
110
109
  return :legacy unless inp.include?("\e[?1u")
111
110
  end
@@ -56,8 +56,8 @@ module Terminal
56
56
 
57
57
  def print(*objects, bbcode: true)
58
58
  return if objects.empty?
59
- return @out.print(*objects) unless bbcode
60
- @out.print(*objects.map! { Ansi.bbcode(it) })
59
+ objects.map! { Ansi.bbcode(it) } if bbcode
60
+ @out.print(*objects)
61
61
  rescue IOError, SystemCallError
62
62
  __output_error(nil)
63
63
  end
@@ -65,8 +65,8 @@ module Terminal
65
65
  def puts(*objects, bbcode: true)
66
66
  objects.flatten!
67
67
  return @out.puts if objects.empty?
68
- return @out.puts(objects) unless bbcode
69
- @out.puts(objects.map! { Ansi.bbcode(it) })
68
+ objects.map! { Ansi.bbcode(it) } if bbcode
69
+ @out.puts(*objects)
70
70
  rescue IOError, SystemCallError
71
71
  __output_error(nil)
72
72
  end
@@ -84,6 +84,7 @@ module Terminal
84
84
  suffix: nil
85
85
  )
86
86
  objects.flatten!
87
+ return @out.puts if objects.empty?
87
88
  @out.puts(
88
89
  Text::Formatter.format(
89
90
  *objects,
@@ -145,6 +146,7 @@ module Terminal
145
146
  private_class_method def self.extended(mod)
146
147
  mod.instance_variable_set(:@cc, 0)
147
148
  mod.instance_variable_set(:@as, 0)
149
+ # at_exit { raw_write("#{Ansi::CURSOR_SHOW}#{Ansi::SCREEN_ALTERNATE_OFF}") }
148
150
  end
149
151
  end
150
152
 
@@ -67,13 +67,14 @@ module Terminal
67
67
  suffix: nil
68
68
  )
69
69
  objects.flatten!
70
+ return @out.puts if objects.empty?
70
71
  @out.puts(
71
72
  Text::Formatter.format(
72
73
  *objects,
73
74
  ansi: false,
74
75
  bbcode:,
75
76
  spaces:,
76
- eol: eol,
77
+ eol:,
77
78
  align:,
78
79
  width:,
79
80
  height:,
@@ -66,7 +66,7 @@ module Terminal
66
66
  #
67
67
  # The terminal size.
68
68
  #
69
- # @return [Array<Integer, Integer>] +[rows, columns]+
69
+ # @return [Array<Integer, Integer>] `[rows, columns]`
70
70
 
71
71
  # Terminal width in columns.
72
72
  #
@@ -89,7 +89,7 @@ module Terminal
89
89
  # Current cursor position.
90
90
  # This is only available when ANSI is supported ({ansi?} return true).
91
91
  #
92
- # @return [Array<Integer, Integer>, nil] +[row, column]+ or +nil+ if
92
+ # @return [Array<Integer, Integer>, nil] `[row, column]` or `nil` if
93
93
  # unavailable
94
94
 
95
95
  # Whether the terminal has been resized since the last size query.
@@ -113,7 +113,7 @@ module Terminal
113
113
  # @example
114
114
  # Terminal << '[bold]Hello[/bold] World'
115
115
  #
116
- # @param object [#to_s, nil] the object to output; +nil+ is ignored
116
+ # @param object [#to_s, nil] the object to output; `nil` is ignored
117
117
  # @return [self]
118
118
 
119
119
  # @!method print(*objects, bbcode: true)
@@ -162,7 +162,7 @@ module Terminal
162
162
  # processing.
163
163
  #
164
164
  # @param object [#to_s] object to write
165
- # @return [Integer, nil] bytes written, or +nil+ on error
165
+ # @return [Integer, nil] bytes written, or `nil` on error
166
166
 
167
167
  # @!method hide_cursor
168
168
  #
@@ -1,10 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'stringio'
4
+
3
5
  # RSpec shared context for testing code that uses Terminal.rb.
4
6
  #
5
- # Stubs all Terminal I/O methods and provides +stdout+, +stdin+, and
6
- # +stdoutstr+ test helpers. Output is captured into the +stdout+ array;
7
- # input is read from the +stdin+ array.
7
+ # Stubs all Terminal I/O methods and provides `stdout`, `stdin`, and
8
+ # `stdoutstr` test helpers. Output is captured into the `stdout` array;
9
+ # input is read from the `stdin` array.
8
10
  #
9
11
  # @example Basic usage
10
12
  # RSpec.describe MyClass do
@@ -20,19 +22,19 @@
20
22
  # include_context 'with Terminal.rb', ansi: false, colors: 8,
21
23
  # size: [40, 120]
22
24
  #
23
- # @param ansi [true, false] mock ANSI support (default: +true+)
25
+ # @param ansi [true, false] mock ANSI support (default: `true`)
24
26
  # @param application [Symbol] mock terminal application
25
- # (default: +:kitty+)
26
- # @param colors [Integer, Symbol] mock color depth; use +:true_color+
27
- # for 16777216 (default: +256+)
27
+ # (default: `:kitty`)
28
+ # @param colors [Integer, Symbol] mock color depth; use `:true_color`
29
+ # for 16777216 (default: `256`)
28
30
  # @param size [Array<Integer, Integer>] mock terminal size as
29
- # +[rows, columns]+ (default: +[25, 80]+)
31
+ # `[rows, columns]` (default: `[25, 80]`)
30
32
  # @param pos [Array<Integer, Integer>] mock cursor position as
31
- # +[row, column]+ (default: +[1, 1]+)
33
+ # `[row, column]` (default: `[1, 1]`)
32
34
  RSpec.shared_context 'with Terminal.rb' do |ansi: true, application: :kitty, colors: 256, size: [25, 80], pos: [1, 1]|
33
- let(:stdout) { [] }
35
+ let(:stdout) { StringIO.new }
36
+ let(:stdout_lines) { stdout.string.lines(chomp: true) }
34
37
  let(:stdin) { [] }
35
- let(:stdoutstr) { stdout.join }
36
38
 
37
39
  before do
38
40
  allow(Terminal).to receive(:ansi?).with(no_args).and_return(ansi)
@@ -48,46 +50,48 @@ RSpec.shared_context 'with Terminal.rb' do |ansi: true, application: :kitty, col
48
50
  allow(Terminal).to receive(:size).with(no_args).and_return(size)
49
51
  allow(Terminal).to receive(:pos).with(no_args).and_return(pos)
50
52
 
51
- bbcode_ = {
52
- true =>
53
- ansi ?
54
- ->(s) { Terminal::Ansi.bbcode(s) } :
55
- ->(s) { Terminal::Ansi.plain(s) },
56
- false => ansi ? lambda(&:to_s) : ->(s) { Terminal::Ansi.undecorate(s) }
57
- }.compare_by_identity
53
+ if ansi
54
+ bbcode_ = ->(s) { Terminal::Ansi.bbcode(s) }
58
55
 
59
- allow(Terminal).to receive(:<<) do |object|
60
- stdout.push(bbcode[object]) unless object.nil?
61
- Terminal
62
- end
56
+ allow(Terminal).to receive(:<<) do |object|
57
+ stdout.write(bbcode_[object]) if object != nil
58
+ Terminal
59
+ end
63
60
 
64
- allow(Terminal).to receive(:print) do |*objects, bbcode: true|
65
- bbcode = bbcode_[bbcode]
66
- objects.flatten.each { stdout.push(bbcode[it]) unless it.nil? }
67
- nil
68
- end
61
+ allow(Terminal).to receive(:print) do |*objects, bbcode: true|
62
+ next if objects.empty?
63
+ objects.map! { Ansi.bbcode(it) } if bbcode
64
+ stdout.print(*objects)
65
+ end
69
66
 
70
- allow(Terminal).to receive(:puts) do |*objects, bbcode: true|
71
- objects.flatten!
72
- if objects.empty?
73
- stdout.push("\n")
74
- next
67
+ allow(Terminal).to receive(:puts) do |*objects, bbcode: true|
68
+ objects.flatten!
69
+ next @out.puts if objects.empty?
70
+ objects.map! { Ansi.bbcode(it) } if bbcode
71
+ stdout.puts(*objects)
75
72
  end
76
- bbcode = bbcode_[bbcode]
77
- objects.each do |s|
78
- next stdout.push("\n") if s.nil?
79
- stdout.push(s = bbcode[s])
80
- stdout.push("\n") if s[-1] != "\n"
73
+
74
+ allow(Terminal).to receive(:raw_write) { stdout.syswrite(it) }
75
+ else
76
+ plain_ = ->(s) { Terminal::Ansi.plain(s) }
77
+ undecorate_ = ->(s) { Terminal::Ansi.undecorate(s) }
78
+
79
+ allow(Terminal).to receive(:<<) do |object|
80
+ stdout.write(Terminal::Ansi.plain(object)) if object != nil
81
+ Terminal
81
82
  end
82
- nil
83
- end
84
83
 
85
- if ansi
86
- allow(Terminal).to receive(:raw_write) do |object|
87
- stdout.push(object = object.to_s)
88
- object.bytesize
84
+ allow(Terminal).to receive(:print) do |*objects, bbcode: true|
85
+ next if objects.empty?
86
+ stdout.print(*objects.map!(&(bbcode ? plain_ : undecorate_)))
89
87
  end
90
- else
88
+
89
+ allow(Terminal).to receive(:puts) do |*objects, bbcode: true|
90
+ objects.flatten!
91
+ next stdout.puts if objects.empty?
92
+ stdout.puts(*objects.map!(&(bbcode ? plain_ : undecorate_)))
93
+ end
94
+
91
95
  allow(Terminal).to receive(:raw_write).and_return(nil)
92
96
  end
93
97
 
@@ -77,7 +77,7 @@ module Terminal
77
77
  return unless obj
78
78
  return copy_writer(obj) if obj.respond_to?(:readpartial)
79
79
  return copy_writer(obj.to_io) if obj.respond_to?(:to_io)
80
- return array_writer(obj) if Array === obj
80
+ return array_writer(obj) if obj.is_a?(Array)
81
81
  if obj.respond_to?(:each)
82
82
  return enum_writer(obj.enum_for(:each)) if obj.respond_to?(:enum_for)
83
83
  return enum_writer(Enumerator.new { |y| obj.each { y << it } })
@@ -32,8 +32,8 @@ module Terminal
32
32
  # # => [["Hello", 5]]
33
33
  #
34
34
  # @param (see #initialize)
35
- # @param with_size [true, false] when +true+,
36
- # return +[line, width]+ pairs instead of plain strings
35
+ # @param with_size [true, false] when `true`,
36
+ # return `[line, width]` pairs instead of plain strings
37
37
  # @param (see #lines_with_size)
38
38
  # @return (see #lines_with_size)
39
39
  def self.[](
@@ -86,17 +86,23 @@ module Terminal
86
86
  # @param ansi [true, false] recognize ANSI escape codes
87
87
  # @param bbcode [true, false] process BBCode markup
88
88
  # @param spaces [true, false] preserve whitespace;
89
- # when +false+ leading/trailing spaces and multiple spaces are
89
+ # when `false` leading/trailing spaces and multiple spaces are
90
90
  # collapsed
91
91
  # @param eol [true, false] preserve line endings;
92
- # when +false+ newlines are treated as spaces
92
+ # when `false` newlines are treated as spaces
93
93
  def initialize(*str, ansi: true, bbcode: true, spaces: true, eol: true)
94
94
  @lex = []
95
95
  return if str.empty?
96
96
  ansi ? _generate_ansi(str, bbcode) : _generate(str, bbcode)
97
97
  return if @lex.empty?
98
+ @keep_paragraph = true
98
99
  @lex = _ignore_whitespace unless spaces
99
- @lex = _ignore_newline unless eol
100
+ case eol
101
+ when false, nil
102
+ @lex = _ignore_newline
103
+ when :no_paragraph
104
+ @keep_paragraph = false
105
+ end
100
106
  end
101
107
 
102
108
  # Word-wrap and return lines with their display widths.
@@ -106,10 +112,10 @@ module Terminal
106
112
  # fmt.lines_with_size(width: 5)
107
113
  # # => [["Hello", 5], ["World", 5]]
108
114
  #
109
- # @param width [Integer, nil] maximum line width in columns;
110
- # +nil+ returns unwrapped lines
115
+ # @param width [#to_i, nil] maximum line width in columns;
116
+ # `nil` returns unwrapped lines
111
117
  # @return [Array<String, Integer>] pairs of
112
- # +[line_text, display_width]+
118
+ # `[line_text, display_width]`
113
119
  # @raise (see #format)
114
120
  def lines_with_size(width: nil)
115
121
  return [] if @lex.empty?
@@ -125,9 +131,9 @@ module Terminal
125
131
  # fmt.lines(width: 5)
126
132
  # # => ["Hello", "World"]
127
133
  #
128
- # @param width [Integer, nil] maximum line width in columns
134
+ # @param width [#to_i, nil] maximum line width in columns
129
135
  # @return [Array<String>]
130
- # @raise [ArgumentError] if +width+ is zero or negative
136
+ # @raise [ArgumentError] if `width` is zero or negative
131
137
  def lines(width: nil) = lines_with_size(width:).map(&:first)
132
138
 
133
139
  # Format lines with alignment, padding, and decorations.
@@ -138,11 +144,11 @@ module Terminal
138
144
  # # => [" Hi "]
139
145
  #
140
146
  # @param align [Symbol, nil] text alignment:
141
- # +:left+, +:right+, +:center+, or +nil+ (no fill)
142
- # @param width [Integer, nil] output line width in columns
143
- # @param height [Integer, nil] number of output lines;
147
+ # `:left`, `:right`, `:center`, or `nil` (no fill)
148
+ # @param width [#to_i, nil] output line width in columns
149
+ # @param height [#to_i, nil] number of output lines;
144
150
  # negative values take lines from the end
145
- # @param padding [Integer, Array, nil] CSS-style padding
151
+ # @param padding [#to_i, Array, nil] CSS-style padding
146
152
  # - 1 value: all sides;
147
153
  # - 2 values: [vertical, horizontal];
148
154
  # - 3 values: [top, horizontal, bottom];
@@ -150,7 +156,7 @@ module Terminal
150
156
  # @param prefix [#to_s, nil] string prepended to each line
151
157
  # @param suffix [#to_s, nil] string appended to each line
152
158
  # @return [Array<String>] formatted output lines
153
- # @raise [ArgumentError] if +width+ is zero or negative
159
+ # @raise [ArgumentError] if `width` is zero or negative
154
160
  def format(
155
161
  align: nil,
156
162
  width: nil,
@@ -172,27 +178,29 @@ module Terminal
172
178
  return [] if height < 1
173
179
  end
174
180
 
181
+ space = SPACE_CACHE.dup
182
+
175
183
  if width
176
184
  w = (width = width.to_i) - left - right
177
185
  raise(ArgumentError, "invalid width - #{width.inspect}") if w < 1
178
186
  lws = _limited(w)
179
187
  lws = tail ? lws.last(height) : lws.take(height) if height
180
- empty = "#{prefix}#{' ' * width}#{suffix}" if top + bottom > 0
188
+ empty = "#{prefix}#{space[width]}#{suffix}" if top + bottom > 0
181
189
  else
182
190
  lws = @unlimited || _unlimited
183
191
  lws = tail ? lws.last(height) : lws.take(height) if height
184
192
  w = lws.empty? ? 0 : lws.max_by(&:last)[-1]
185
193
  if top + bottom > 0
186
- empty = "#{prefix}#{' ' * (w + left + right)}#{suffix}"
194
+ empty = "#{prefix}#{space[w + left + right]}#{suffix}"
187
195
  end
188
196
  end
189
197
 
190
198
  ret = []
191
199
  ret.fill(empty, 0, top) if top > 0
192
- left = left < 1 ? prefix.to_s : "#{prefix}#{' ' * left}"
193
- right = right < 1 ? suffix.to_s : "#{' ' * right}#{suffix}"
200
+ left = left < 1 ? prefix.to_s : "#{prefix}#{space[left]}"
201
+ right = right < 1 ? suffix.to_s : "#{space[right]}#{suffix}"
194
202
 
195
- space = SPACE_CACHE.dup
203
+ # TODO: styling
196
204
 
197
205
  case align
198
206
  when :left
@@ -201,9 +209,9 @@ module Terminal
201
209
  lws.each { |l, s| ret << "#{left}#{space[w - s]}#{l}#{right}" }
202
210
  when :center
203
211
  lws.each do |l, s|
204
- ls = (s = w - s) / 2
205
- next ret << "#{left}#{l}#{right}" if ls < 1
206
- ret << "#{left}#{space[ls]}#{l}#{space[s - ls]}#{right}"
212
+ rs = ((s = w - s) / 2.0).round
213
+ next ret << "#{left}#{l}#{right}" if rs < 1
214
+ ret << "#{left}#{space[s - rs]}#{l}#{space[rs]}#{right}"
207
215
  end
208
216
  else
209
217
  lws.each { |l, _| ret << "#{left}#{l}#{right}" }
@@ -224,7 +232,7 @@ module Terminal
224
232
  # fmt = Terminal::Text::Formatter.new("short\na longer line")
225
233
  # fmt.max_line_width # => 13
226
234
  #
227
- # @return [Integer] widest line in columns, +0+ when empty
235
+ # @return [Integer] widest line in columns, `0` when empty
228
236
  def max_line_width
229
237
  @max_line_width ||=
230
238
  (@lex.empty? ? 0 : (@unlimited || _unlimited).max_by(&:last)[-1])
@@ -237,7 +245,7 @@ module Terminal
237
245
  # Terminal::Text::Formatter.new('Hello World').to_s(width: 5)
238
246
  # # => "Hello\nWorld"
239
247
  #
240
- # @param width [Integer, nil] maximum line width in columns
248
+ # @param width [#to_i, nil] maximum line width in columns
241
249
  # @return [String]
242
250
  def to_s(width: nil) = lines(width:).join("\n")
243
251
 
@@ -294,8 +302,9 @@ module Terminal
294
302
  if (last = line[-1]).is_a?(Space) # ignore trailing space
295
303
  line.pop
296
304
  size -= last.size
305
+ next add_line.call
297
306
  end
298
- add_line.call # if size > 0
307
+ add_line.call if (current != EOP) || (@keep_paragraph || size > 0)
299
308
  next
300
309
  end
301
310
 
@@ -507,7 +516,7 @@ module Terminal
507
516
  # @private
508
517
  class Space
509
518
  attr_accessor :size
510
- def to_str = (' ' * @size)
519
+ def to_str = (@size == 1 ? ' ' : ' ' * @size)
511
520
  def initialize = (@size = 1)
512
521
  def inc = (@size += 1)
513
522
  def inspect = @size == 1 ? '<Space>' : "<Space #{@size}>"
@@ -565,7 +574,7 @@ module Terminal
565
574
  class << self
566
575
  attr_reader :to_str, :size, :inspect
567
576
  end
568
- @to_str = "\e[m"
577
+ @to_str = Ansi::RESET
569
578
  @size = 0
570
579
  @inspect = '<CsiEnd>'
571
580
  end
@@ -581,11 +590,12 @@ module Terminal
581
590
 
582
591
  ENCODING = Encoding::UTF_8
583
592
 
584
- SPACE_CACHE =
585
- Hash
586
- .new { |h, s| h[s] = s < 1 ? '' : ' ' * s }
587
- .compare_by_identity
588
- .freeze
593
+ space_cache =
594
+ Hash.new { |h, s| h[s] = s < 1 ? '' : ' ' * s }.compare_by_identity
595
+ space_cache[0]
596
+ space_cache[1]
597
+ space_cache[2]
598
+ SPACE_CACHE = space_cache.freeze
589
599
 
590
600
  SCAN_REGEX =
591
601
  /\G(?:
data/lib/terminal/text.rb CHANGED
@@ -28,7 +28,7 @@ module Terminal
28
28
  # Terminal::Text.ambiguous_char_width # => 1
29
29
  # Terminal::Text.ambiguous_char_width = 2 # for CJK terminals
30
30
  #
31
- # @return [Integer] default: +1+
31
+ # @return [Integer] default: `1`
32
32
  attr_accessor :ambiguous_char_width
33
33
 
34
34
  # Calculate the display width of a string in terminal columns.
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Terminal
4
4
  # The version number of the gem.
5
- VERSION = '1.0.4'
5
+ VERSION = '1.0.6'
6
6
  end
data/lib/terminal.rb CHANGED
@@ -30,32 +30,32 @@ module Terminal
30
30
  # Detect the terminal emulator application.
31
31
  #
32
32
  # Known applications:
33
- # +:alacritty+,
34
- # +:amiga+,
35
- # +:code_edit+,
36
- # +:dg_unix+,
37
- # +:docker+,
38
- # +:fluent+,
39
- # +:hpterm+,
40
- # +:hyper+,
41
- # +:iterm+,
42
- # +:kitty+,
43
- # +:macos+,
44
- # +:mintty+,
45
- # +:ms_terminal+,
46
- # +:ncr260+,
47
- # +:nsterm+,
48
- # +:terminator+,
49
- # +:terminology+,
50
- # +:termite+,
51
- # +:vscode+,
52
- # +:vt100+,
53
- # +:warp+,
54
- # +:wyse+,
55
- # +:xnuppc+
33
+ # `:alacritty`,
34
+ # `:amiga`,
35
+ # `:code_edit`,
36
+ # `:dg_unix`,
37
+ # `:docker`,
38
+ # `:fluent`,
39
+ # `:hpterm`,
40
+ # `:hyper`,
41
+ # `:iterm`,
42
+ # `:kitty`,
43
+ # `:macos`,
44
+ # `:mintty`,
45
+ # `:ms_terminal`,
46
+ # `:ncr260`,
47
+ # `:nsterm`,
48
+ # `:terminator`,
49
+ # `:terminology`,
50
+ # `:termite`,
51
+ # `:vscode`,
52
+ # `:vt100`,
53
+ # `:warp`,
54
+ # `:wyse`,
55
+ # `:xnuppc`
56
56
  #
57
- # Any unrecognized +TERM_PROGRAM+ value is converted to a sanitized
58
- # symbol. Returns +nil+ when no terminal can be identified.
57
+ # Any unrecognized `TERM_PROGRAM` value is converted to a sanitized
58
+ # symbol. Returns `nil` when no terminal can be identified.
59
59
  #
60
60
  # @example
61
61
  # Terminal.application # => :kitty
@@ -77,7 +77,7 @@ module Terminal
77
77
  # @param cmd [Array<String>] command and arguments
78
78
  # @param options [Hash] options passed to the shell runner
79
79
  # @return [Array<Process::Status, Array<String>, Array<String>>]
80
- # +[status, stdout_lines, stderr_lines]+
80
+ # `[status, stdout_lines, stderr_lines]`
81
81
  # @example
82
82
  # status, output, error = Terminal.sh('echo', 'hello')
83
83
  # output # => ["hello\n"]
@@ -88,7 +88,7 @@ module Terminal
88
88
  # @param options [Hash] options passed to the shell runner
89
89
  # @yield [line, type] called for each output line
90
90
  # @yieldparam line [String] the output line
91
- # @yieldparam type [Symbol] +:output+ or +:error+
91
+ # @yieldparam type [Symbol] `:output` or `:error`
92
92
  # @return [Process::Status] the exit status
93
93
  # @example
94
94
  # Terminal.sh('make') do |line, type|
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: 1.0.4
4
+ version: 1.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mike Blumtritt
@@ -29,6 +29,7 @@ files:
29
29
  - examples/bbcode.rb
30
30
  - examples/info.rb
31
31
  - examples/key-codes.rb
32
+ - examples/lorem_ipsum.ansi
32
33
  - examples/screen_viewer.rb
33
34
  - examples/text.rb
34
35
  - lib/terminal.rb
@@ -59,13 +60,13 @@ metadata:
59
60
  yard.run: yard
60
61
  source_code_uri: https://codeberg.org/mblumtritt/Terminal.rb
61
62
  bug_tracker_uri: https://codeberg.org/mblumtritt/Terminal.rb/issues
62
- documentation_uri: https://rubydoc.info/gems/terminal_rb/1.0.4
63
+ documentation_uri: https://rubydoc.info/gems/terminal_rb/1.0.6
63
64
  rdoc_options: []
64
65
  require_paths:
65
66
  - lib
66
67
  required_ruby_version: !ruby/object:Gem::Requirement
67
68
  requirements:
68
- - - ">"
69
+ - - ">="
69
70
  - !ruby/object:Gem::Version
70
71
  version: '3.4'
71
72
  required_rubygems_version: !ruby/object:Gem::Requirement
@@ -74,7 +75,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
74
75
  - !ruby/object:Gem::Version
75
76
  version: '0'
76
77
  requirements: []
77
- rubygems_version: 4.0.11
78
+ rubygems_version: 4.0.15
78
79
  specification_version: 4
79
80
  summary: Fast terminal access with ANSI, CSIu, mouse events, BBCode, word-wise line
80
81
  break support and much more.