terminal_rb 0.12.0 → 0.12.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/terminal/input/as_key_event.rb +44 -46
- data/lib/terminal/input.rb +17 -13
- data/lib/terminal/text.rb +14 -17
- data/lib/terminal/version.rb +1 -1
- data/lib/terminal.rb +12 -10
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 834587f3bf9e66077d0ad33b8391100863ec8932e4eafd31077684c8a982d03c
|
4
|
+
data.tar.gz: fd95fac927978b7bdbc39d71797d165b42a787a6a35139418c6a445192258e83
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7f5284ff90de5ee142d3e11414df40148eef0dca7bb216e000f4f7a3474c416bba644cdb2a44656612eae33bb7e0933424ef34161a7cd247b89054ab99538bbe
|
7
|
+
data.tar.gz: 979db236870e067f58d25e18ca4bc5ce088c1558b8db8c59e95017656c28cf6e762593849fa4e9d44a2d716654b81e02d643ca43d2ba83528410070c8a8e70c7
|
@@ -11,28 +11,21 @@ module Terminal
|
|
11
11
|
when "\e" # ESC ESC ...
|
12
12
|
return esc_esc(raw)
|
13
13
|
when 'O'
|
14
|
-
if raw.size == 3
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
when '[' # ESC [ ...
|
19
|
-
if raw.size == 3
|
20
|
-
# ESC [ ?
|
21
|
-
return KeyEvent.new(raw, *@ss3[raw[2].ord])
|
22
|
-
end
|
23
|
-
if raw.size == 6 && raw[2] == 'M'
|
24
|
-
# ESC [ M b c r
|
14
|
+
return KeyEvent.new(raw, *@ss3[raw[2].ord]) if raw.size == 3 # ESC O ?
|
15
|
+
when '['
|
16
|
+
return KeyEvent.new(raw, *@ss3[raw[2].ord]) if raw.size == 3 # ESC [ ?
|
17
|
+
if raw.size == 6 && raw[2] == 'M' # ESC [ M b c r
|
25
18
|
return mouse_vt200(raw)
|
26
19
|
end
|
27
20
|
return csi1(raw) if raw.start_with?("\e[1;") # ESC [ 1 ; ...
|
28
21
|
case raw[-1]
|
29
|
-
when '~'
|
22
|
+
when '~' # ESC [ ... ~
|
30
23
|
return legacy(raw)
|
31
|
-
when 'u'
|
24
|
+
when 'u' # ESC [ ... u
|
32
25
|
return csi_u(raw)
|
33
|
-
when 'M'
|
26
|
+
when 'M' # ESC [ ... M
|
34
27
|
return raw[2] == '<' ? mouse_sgr(raw) : mouse_urxvt(raw)
|
35
|
-
when 'm'
|
28
|
+
when 'm' # ESC [ ... m
|
36
29
|
return mouse_sgr(raw) if raw[2] == '<'
|
37
30
|
end
|
38
31
|
end
|
@@ -41,37 +34,6 @@ module Terminal
|
|
41
34
|
|
42
35
|
private
|
43
36
|
|
44
|
-
def mouse_vt200(raw)
|
45
|
-
# ESC [ M b c r
|
46
|
-
mouse_event(raw, *raw[3..].chars.map! { _1.ord - 32 })
|
47
|
-
end
|
48
|
-
|
49
|
-
def mouse_sgr(raw)
|
50
|
-
# ESC [ < <code> ; <col> ; <row> M
|
51
|
-
# ESC [ < <code> ; <col> ; <row> m
|
52
|
-
return KeyEvent.unknown(raw) if raw.size < 8
|
53
|
-
bcr = raw[3..-2].split(';', 3).map!(&:to_i)
|
54
|
-
bcr.size == 3 ? mouse_event(raw, *bcr) : KeyEvent.unknown(raw)
|
55
|
-
end
|
56
|
-
|
57
|
-
def mouse_urxvt(raw)
|
58
|
-
# ESC [ <code> ; <col> ; <row> M
|
59
|
-
return KeyEvent.unknown(raw) if raw.size < 8
|
60
|
-
bcr = raw[2..-2].split(';', 3).map!(&:to_i)
|
61
|
-
bcr.size == 3 ? mouse_event(raw, *bcr) : KeyEvent.unknown(raw)
|
62
|
-
end
|
63
|
-
|
64
|
-
def mouse_event(raw, btn, col, row)
|
65
|
-
return KeyEvent.unknown(raw) if btn < 0 || col < 1 || row < 1
|
66
|
-
kind = btn & 3
|
67
|
-
ka = btn >= 64 ? @mouse_wheel_kind : @mouse_kind
|
68
|
-
btn -= kind
|
69
|
-
modifier = btn.allbits?(4) ? 1 : 0
|
70
|
-
modifier += 2 if btn.allbits?(8)
|
71
|
-
modifier += 4 if btn.allbits?(16)
|
72
|
-
KeyEvent.new(raw, ka[kind], modifier, [col, row])
|
73
|
-
end
|
74
|
-
|
75
37
|
def csi_u(raw)
|
76
38
|
# ESC [ <code> u
|
77
39
|
# ESC [ <code> ; <modifier> u
|
@@ -118,6 +80,42 @@ module Terminal
|
|
118
80
|
key, modifier = @esc1[char.ord]
|
119
81
|
KeyEvent.new(raw, key || char, modifier || 2)
|
120
82
|
end
|
83
|
+
|
84
|
+
def mouse_vt200(raw)
|
85
|
+
# ESC [ M b c r
|
86
|
+
mouse_event(raw, *raw[3..].chars.map! { _1.ord - 32 })
|
87
|
+
end
|
88
|
+
|
89
|
+
def mouse_sgr(raw)
|
90
|
+
# ESC [ < <code> ; <col> ; <row> M
|
91
|
+
# ESC [ < <code> ; <col> ; <row> m
|
92
|
+
return KeyEvent.unknown(raw) if raw.size < 8
|
93
|
+
bcr = raw[3..-2].split(';', 3).map!(&:to_i)
|
94
|
+
bcr.size == 3 ? mouse_event(raw, *bcr) : KeyEvent.unknown(raw)
|
95
|
+
end
|
96
|
+
|
97
|
+
def mouse_urxvt(raw)
|
98
|
+
# ESC [ <code> ; <col> ; <row> M
|
99
|
+
return KeyEvent.unknown(raw) if raw.size < 8
|
100
|
+
bcr = raw[2..-2].split(';', 3).map!(&:to_i)
|
101
|
+
bcr.size == 3 ? mouse_event(raw, *bcr) : KeyEvent.unknown(raw)
|
102
|
+
end
|
103
|
+
|
104
|
+
def mouse_event(raw, btn, col, row)
|
105
|
+
return KeyEvent.unknown(raw) if btn < 0 || col < 1 || row < 1
|
106
|
+
key, btn = kind_of_mouse_event(btn)
|
107
|
+
modifier = btn.allbits?(4) ? 1 : 0
|
108
|
+
modifier += 2 if btn.allbits?(8)
|
109
|
+
modifier += 4 if btn.allbits?(16)
|
110
|
+
KeyEvent.new(raw, key, modifier, [col, row])
|
111
|
+
end
|
112
|
+
|
113
|
+
def mouse_event_key(btn)
|
114
|
+
kind = btn & 3
|
115
|
+
key = (btn >= 64 ? @mouse_wheel_kind : @mouse_kind)[kind]
|
116
|
+
# TODO: what about btn >= 128 for more mouse wheel events?
|
117
|
+
[btn - kind, key]
|
118
|
+
end
|
121
119
|
end
|
122
120
|
|
123
121
|
@mouse_kind = %i[
|
data/lib/terminal/input.rb
CHANGED
@@ -9,7 +9,8 @@ module Terminal
|
|
9
9
|
# @attribute [r] input_mode
|
10
10
|
#
|
11
11
|
# @return [:csi_u]
|
12
|
-
# when CSIu protocol
|
12
|
+
# when [CSIu protocol](https://sw.kovidgoyal.net/kitty/keyboard-protocol)
|
13
|
+
# supported
|
13
14
|
# @return [:legacy]
|
14
15
|
# for standard terminal
|
15
16
|
# @return [:dumb]
|
@@ -51,8 +52,7 @@ module Terminal
|
|
51
52
|
KeyEvent.new(raw, *opts)
|
52
53
|
when :csi_u, :legacy
|
53
54
|
# raw = with_mouse ? read_tty_with_mouse : read_tty
|
54
|
-
raw = read_tty
|
55
|
-
AsKeyEvent[raw] if raw
|
55
|
+
AsKeyEvent[raw] if (raw = read_tty)
|
56
56
|
end
|
57
57
|
end
|
58
58
|
|
@@ -69,7 +69,7 @@ module Terminal
|
|
69
69
|
else
|
70
70
|
:legacy
|
71
71
|
end
|
72
|
-
rescue
|
72
|
+
rescue Interrupt
|
73
73
|
:legacy
|
74
74
|
rescue IOError, SystemCallError
|
75
75
|
:error
|
@@ -90,7 +90,7 @@ module Terminal
|
|
90
90
|
nil
|
91
91
|
end
|
92
92
|
|
93
|
-
def read_tty_with_mouse(
|
93
|
+
def read_tty_with_mouse(each_move: false)
|
94
94
|
# highlight: '1001'
|
95
95
|
# drag: '1002'
|
96
96
|
# move: '1003'
|
@@ -98,7 +98,7 @@ module Terminal
|
|
98
98
|
# sgr: '1006'
|
99
99
|
# urxvt: '1015'
|
100
100
|
# pixel: '1016'
|
101
|
-
opts =
|
101
|
+
opts = each_move ? '1000;1003;1006;1015' : '1000;1006;1015'
|
102
102
|
opts = _write("\e[?#{opts}h") ? "\e[?#{opts}l" : nil
|
103
103
|
read_tty
|
104
104
|
ensure
|
@@ -106,13 +106,13 @@ module Terminal
|
|
106
106
|
end
|
107
107
|
|
108
108
|
def read_tty
|
109
|
-
key = STDIN.getch
|
110
|
-
|
111
|
-
|
112
|
-
|
109
|
+
if (key = STDIN.getch) == "\e"
|
110
|
+
while (nc = STDIN.read_nonblock(1, exception: false))
|
111
|
+
String === nc ? key << nc : break
|
112
|
+
end
|
113
113
|
end
|
114
114
|
key
|
115
|
-
rescue
|
115
|
+
rescue Interrupt
|
116
116
|
nil
|
117
117
|
rescue IOError, SystemCallError
|
118
118
|
@input_mode = :error
|
@@ -148,10 +148,12 @@ module Terminal
|
|
148
148
|
end
|
149
149
|
end
|
150
150
|
|
151
|
+
# @!visibility private
|
151
152
|
def new(raw, key = raw, modifier = 0, extra = nil)
|
152
|
-
@cache ?
|
153
|
+
@cache ? (@cache[raw] ||= super.freeze) : super.freeze
|
153
154
|
end
|
154
155
|
|
156
|
+
# @!visibility private
|
155
157
|
def unknown(raw) = new(raw, nil)
|
156
158
|
end
|
157
159
|
|
@@ -172,7 +174,9 @@ module Terminal
|
|
172
174
|
# @return [Integer] modifier key code
|
173
175
|
attr_reader :modifier
|
174
176
|
|
175
|
-
# @comment for mouse events
|
177
|
+
# @comment for mouse events
|
178
|
+
# @!visibility private
|
179
|
+
attr_reader :extra
|
176
180
|
|
177
181
|
# Name of the key event.
|
178
182
|
# This can be a simple name like `"a"` or `"Shift+Ctrl+F12"` for combined
|
data/lib/terminal/text.rb
CHANGED
@@ -30,7 +30,7 @@ module Terminal
|
|
30
30
|
def width(str, bbcode: true)
|
31
31
|
str = bbcode ? Ansi.unbbcode(str) : str.to_s
|
32
32
|
return 0 if str.empty?
|
33
|
-
str = str.encode(
|
33
|
+
str = str.encode(@encoding) if str.encoding != @encoding
|
34
34
|
width = 0
|
35
35
|
str.scan(WIDTH_SCANNER) do |sp, gc|
|
36
36
|
next width += char_width(gc) if gc
|
@@ -113,7 +113,7 @@ module Terminal
|
|
113
113
|
|
114
114
|
def char_width(char)
|
115
115
|
ord = char.ord
|
116
|
-
return
|
116
|
+
return @ctrlchar_width[ord] || 2 if ord < 0x20
|
117
117
|
return 1 if char.size < 2 && ord < 0xa1
|
118
118
|
width = CharWidth[ord]
|
119
119
|
return @ambiguous_char_width if width == -1
|
@@ -124,7 +124,7 @@ module Terminal
|
|
124
124
|
end
|
125
125
|
|
126
126
|
def lim_pairs(snippeds, limit)
|
127
|
-
line =
|
127
|
+
line = @empty.dup
|
128
128
|
size = 0
|
129
129
|
csi = nil
|
130
130
|
snippeds.each do |snipped|
|
@@ -144,7 +144,7 @@ module Terminal
|
|
144
144
|
|
145
145
|
if snipped == :hard_nl
|
146
146
|
line[-1] == ' ' ? yield(line.chop, size - 1) : yield(line, size)
|
147
|
-
line =
|
147
|
+
line = @empty.dup
|
148
148
|
csi = nil
|
149
149
|
next size = 0
|
150
150
|
end
|
@@ -190,7 +190,7 @@ module Terminal
|
|
190
190
|
end
|
191
191
|
|
192
192
|
def pairs(snippeds)
|
193
|
-
line =
|
193
|
+
line = @empty.dup
|
194
194
|
size = 0
|
195
195
|
csi = nil
|
196
196
|
snippeds.each do |snipped|
|
@@ -208,7 +208,7 @@ module Terminal
|
|
208
208
|
|
209
209
|
if snipped == :hard_nl
|
210
210
|
line[-1] == ' ' ? yield(line.chop, size - 1) : yield(line, size)
|
211
|
-
line =
|
211
|
+
line = @empty.dup
|
212
212
|
csi = nil
|
213
213
|
next size = 0
|
214
214
|
end
|
@@ -229,7 +229,7 @@ module Terminal
|
|
229
229
|
end
|
230
230
|
|
231
231
|
def lim_lines(snippeds, limit)
|
232
|
-
line =
|
232
|
+
line = @empty.dup
|
233
233
|
size = 0
|
234
234
|
csi = nil
|
235
235
|
snippeds.each do |snipped|
|
@@ -249,7 +249,7 @@ module Terminal
|
|
249
249
|
|
250
250
|
if snipped == :hard_nl
|
251
251
|
yield(line[-1] == ' ' ? line.chop : line)
|
252
|
-
line =
|
252
|
+
line = @empty.dup
|
253
253
|
csi = nil
|
254
254
|
next size = 0
|
255
255
|
end
|
@@ -295,7 +295,7 @@ module Terminal
|
|
295
295
|
end
|
296
296
|
|
297
297
|
def lines(snippeds)
|
298
|
-
line =
|
298
|
+
line = @empty.dup
|
299
299
|
size = 0
|
300
300
|
csi = nil
|
301
301
|
snippeds.each do |snipped|
|
@@ -313,7 +313,7 @@ module Terminal
|
|
313
313
|
|
314
314
|
if snipped == :hard_nl
|
315
315
|
yield(line[-1] == ' ' ? line.chop : line)
|
316
|
-
line =
|
316
|
+
line = @empty.dup
|
317
317
|
csi = nil
|
318
318
|
next size = 0
|
319
319
|
end
|
@@ -342,7 +342,7 @@ module Terminal
|
|
342
342
|
next ret << (last = :hard_nl)
|
343
343
|
end
|
344
344
|
|
345
|
-
txt = txt.encode(
|
345
|
+
txt = txt.encode(@encoding) if txt.encoding != @encoding
|
346
346
|
|
347
347
|
txt.scan(SCAN_EXPR) do |nl, csi, osc, space, gc|
|
348
348
|
if gc
|
@@ -445,10 +445,8 @@ module Terminal
|
|
445
445
|
private_constant :Osc, :CsiEnd, :Csi, :Word, :WordEx
|
446
446
|
|
447
447
|
@ambiguous_char_width = 1
|
448
|
-
|
449
|
-
|
450
|
-
EMPTY = String.new(encoding: ENC).freeze
|
451
|
-
private_constant :ENC, :EMPTY
|
448
|
+
@encoding = Encoding::UTF_8
|
449
|
+
@empty = String.new(encoding: @encoding).freeze
|
452
450
|
|
453
451
|
SCAN_EXPR =
|
454
452
|
/\G(?:
|
@@ -468,7 +466,7 @@ module Terminal
|
|
468
466
|
)/x
|
469
467
|
private_constant :SCAN_EXPR, :WIDTH_SCANNER
|
470
468
|
|
471
|
-
|
469
|
+
@ctrlchar_width = {
|
472
470
|
0x00 => 0,
|
473
471
|
0x01 => 1,
|
474
472
|
0x02 => 1,
|
@@ -502,7 +500,6 @@ module Terminal
|
|
502
500
|
0x1e => 1,
|
503
501
|
0x1f => 1
|
504
502
|
}.compare_by_identity.freeze
|
505
|
-
private_constant :CONTROL_CHAR_WIDTH
|
506
503
|
|
507
504
|
autoload :CharWidth, "#{__dir__}/text/char_width.rb"
|
508
505
|
private_constant :CharWidth
|
data/lib/terminal/version.rb
CHANGED
data/lib/terminal.rb
CHANGED
@@ -11,16 +11,16 @@ require_relative 'terminal/input'
|
|
11
11
|
# It automagically detects whether your terminal supports ANSI features, like
|
12
12
|
# coloring (see {colors}) or the
|
13
13
|
# [CSIu protocol](https://sw.kovidgoyal.net/kitty/keyboard-protocol) support
|
14
|
-
# (see {
|
15
|
-
# chars (see {Text.width}) and help
|
16
|
-
# (see {Text.each_line}).
|
14
|
+
# (see {read_key_event} and {input_mode}).
|
15
|
+
# It calculates the display width for Unicode chars (see {Text.width}) and help
|
16
|
+
# you to display text with line formatting (see {Text.each_line}).
|
17
17
|
#
|
18
18
|
module Terminal
|
19
19
|
class << self
|
20
|
-
# Return true
|
21
|
-
# When the terminal does not support it, {colors} will return `2`
|
22
|
-
#
|
23
|
-
#
|
20
|
+
# Return true if the current terminal supports ANSI control codes.
|
21
|
+
# When the terminal does not support it, {colors} will return `2` and all
|
22
|
+
# output methods ({<<}, {print}, {puts}) will not forward ANSI control
|
23
|
+
# codes to the terminal, {read_key_event} will not support CSIu.
|
24
24
|
#
|
25
25
|
# @attribute [r] ansi?
|
26
26
|
# @return [Boolean] whether ANSI control codes are supported
|
@@ -123,8 +123,9 @@ module Terminal
|
|
123
123
|
|
124
124
|
# Screen size as a tuple of {rows} and {columns}.
|
125
125
|
#
|
126
|
-
# If the terminal does not support the report
|
127
|
-
# is not supported in general then environment variables
|
126
|
+
# If the terminal does not support the report of it's dimension or ANSI
|
127
|
+
# is not supported in general then environment variables `COLUMNS` and
|
128
|
+
# `LINES` will be used.
|
128
129
|
# If this failed `[25, 80]` will be returned as default.
|
129
130
|
#
|
130
131
|
# Setting the terminal size is not widely supported.
|
@@ -156,7 +157,8 @@ module Terminal
|
|
156
157
|
# Hide the cursor.
|
157
158
|
# Will not send the control code if the cursor is already hidden.
|
158
159
|
#
|
159
|
-
#
|
160
|
+
# When you called {hide_cursor} n-times you need to call {show_cursor}
|
161
|
+
# n-times to show the cursor again.
|
160
162
|
#
|
161
163
|
# @return [Terminal] itself
|
162
164
|
def hide_cursor
|
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.12.
|
4
|
+
version: 0.12.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mike Blumtritt
|
@@ -44,11 +44,11 @@ homepage: https://codeberg.org/mblumtritt/Terminal.rb
|
|
44
44
|
licenses:
|
45
45
|
- MIT
|
46
46
|
metadata:
|
47
|
-
rubygems_mfa_required: 'true'
|
48
|
-
yard.run: yard
|
49
47
|
source_code_uri: https://codeberg.org/mblumtritt/Terminal.rb
|
50
48
|
bug_tracker_uri: https://codeberg.org/mblumtritt/Terminal.rb/issues
|
51
|
-
documentation_uri: https://rubydoc.info/gems/terminal_rb
|
49
|
+
documentation_uri: https://rubydoc.info/gems/terminal_rb
|
50
|
+
rubygems_mfa_required: 'true'
|
51
|
+
yard.run: yard
|
52
52
|
rdoc_options: []
|
53
53
|
require_paths:
|
54
54
|
- lib
|