terminal_rb 0.11.1 → 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/examples/key-codes.rb +5 -5
- data/lib/terminal/ansi/attributes.rb +4 -7
- data/lib/terminal/ansi.rb +31 -42
- data/lib/terminal/detect.rb +21 -21
- data/lib/terminal/input/as_key_event.rb +315 -0
- data/lib/terminal/input.rb +181 -38
- data/lib/terminal/rspec/helper.rb +7 -8
- data/lib/terminal/text/char_width.rb +4 -3
- data/lib/terminal/text.rb +14 -17
- data/lib/terminal/version.rb +1 -1
- data/lib/terminal.rb +12 -10
- metadata +5 -6
- data/lib/terminal/input/csiu_keys.rb +0 -198
- data/lib/terminal/input/dumb_keys.rb +0 -19
- data/lib/terminal/input/legacy_keys.rb +0 -149
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]
|
@@ -25,40 +26,43 @@ module Terminal
|
|
25
26
|
# The input will be returned as named key codes like "Ctrl+c" by default.
|
26
27
|
# This can be changed by `mode`.
|
27
28
|
#
|
29
|
+
# @deprecated Use arther {read_key_event} for better input handling.
|
30
|
+
#
|
28
31
|
# @param [:named, :raw, :both] mode modifies the result
|
29
32
|
# @return [String] key code ("as is") in `:raw` mode
|
30
33
|
# @return [String] key name in `:named` mode
|
31
34
|
# @return [[String, String]] key code and key name in `:both` mode
|
35
|
+
# @return [nil] in any error case
|
32
36
|
def read_key(mode: :named)
|
33
|
-
|
34
|
-
return
|
35
|
-
|
36
|
-
key, name = read_tty_with(@input_mode == :csi_u ? CSIuKeys : LegacyKeys)
|
37
|
-
return unless key
|
37
|
+
event = read_key_event or return
|
38
|
+
return event.raw if mode == :raw
|
39
|
+
key, name = event
|
38
40
|
mode == :both ? [key, name] : name || key
|
39
41
|
end
|
40
42
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
43
|
+
# Read next {KeyEvent} from standard input.
|
44
|
+
#
|
45
|
+
# @return [KeyEvent] next event
|
46
|
+
# @return [nil] on any error
|
47
|
+
def read_key_event
|
48
|
+
case input_mode
|
49
|
+
when :dumb
|
50
|
+
raw = read_dumb or return
|
51
|
+
opts = DUMB_KEYS[raw.ord] if raw.size == 1
|
52
|
+
KeyEvent.new(raw, *opts)
|
53
|
+
when :csi_u, :legacy
|
54
|
+
# raw = with_mouse ? read_tty_with_mouse : read_tty
|
55
|
+
AsKeyEvent[raw] if (raw = read_tty)
|
56
|
+
end
|
49
57
|
end
|
50
58
|
|
51
|
-
|
52
|
-
key, *esc = read_tty
|
53
|
-
return unless key
|
54
|
-
return key, trans.key_name(key) if esc.empty?
|
55
|
-
[key + esc.join, trans.translate(esc)]
|
56
|
-
end
|
59
|
+
private
|
57
60
|
|
58
61
|
def find_input_mode
|
59
62
|
im = ENV['INPUT_MODE']
|
60
|
-
return :dumb if im == 'dumb'
|
63
|
+
return :dumb if im == 'dumb'
|
61
64
|
return :legacy if im == 'legacy'
|
65
|
+
return :dumb unless STDIN.tty?
|
62
66
|
if ansi? && _write("\e[>1u\e[?u\e[c") && csi_u?
|
63
67
|
at_exit { _write("\e[<u") }
|
64
68
|
:csi_u
|
@@ -72,35 +76,174 @@ module Terminal
|
|
72
76
|
end
|
73
77
|
|
74
78
|
def csi_u?
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
79
|
+
inp = +''
|
80
|
+
STDIN.raw { inp << _1.getch until inp.rindex('c') }
|
81
|
+
inp.include?("\e[?1u")
|
82
|
+
end
|
83
|
+
|
84
|
+
def read_dumb
|
85
|
+
STDIN.getc
|
86
|
+
rescue Interrupt
|
87
|
+
"\x05"
|
88
|
+
rescue IOError, SystemCallError
|
89
|
+
@input_mode = :error
|
90
|
+
nil
|
91
|
+
end
|
92
|
+
|
93
|
+
def read_tty_with_mouse(each_move: false)
|
94
|
+
# highlight: '1001'
|
95
|
+
# drag: '1002'
|
96
|
+
# move: '1003'
|
97
|
+
# ext: '1005'
|
98
|
+
# sgr: '1006'
|
99
|
+
# urxvt: '1015'
|
100
|
+
# pixel: '1016'
|
101
|
+
opts = each_move ? '1000;1003;1006;1015' : '1000;1006;1015'
|
102
|
+
opts = _write("\e[?#{opts}h") ? "\e[?#{opts}l" : nil
|
103
|
+
read_tty
|
104
|
+
ensure
|
105
|
+
_write(opts) if opts
|
82
106
|
end
|
83
107
|
|
84
108
|
def read_tty
|
85
|
-
STDIN.
|
86
|
-
|
87
|
-
return key if key[0] != "\e"
|
88
|
-
while (nc = raw.read_nonblock(1, exception: false))
|
109
|
+
if (key = STDIN.getch) == "\e"
|
110
|
+
while (nc = STDIN.read_nonblock(1, exception: false))
|
89
111
|
String === nc ? key << nc : break
|
90
112
|
end
|
91
|
-
key
|
92
113
|
end
|
114
|
+
key
|
93
115
|
rescue Interrupt
|
94
116
|
nil
|
95
117
|
rescue IOError, SystemCallError
|
96
118
|
@input_mode = :error
|
97
119
|
nil
|
98
120
|
end
|
121
|
+
|
122
|
+
DUMB_KEYS = {
|
123
|
+
0x05 => ['c', 4],
|
124
|
+
0x08 => :Back,
|
125
|
+
0x09 => :Tab,
|
126
|
+
0x0a => :Enter,
|
127
|
+
0x0d => :Return,
|
128
|
+
0x1b => :Esc
|
129
|
+
}.compare_by_identity.freeze
|
130
|
+
private_constant :DUMB_KEYS
|
131
|
+
end
|
132
|
+
|
133
|
+
#
|
134
|
+
# Key event reported from {read_key_event}.
|
135
|
+
#
|
136
|
+
class KeyEvent
|
137
|
+
class << self
|
138
|
+
# @attribute [w] caching
|
139
|
+
# @return [true, false] whether KeyCodes should be cached
|
140
|
+
def caching = !!@cache
|
141
|
+
|
142
|
+
# @attribute [w] caching
|
143
|
+
def caching=(value)
|
144
|
+
if value
|
145
|
+
@cache ||= {}
|
146
|
+
else
|
147
|
+
@cache = nil
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
# @!visibility private
|
152
|
+
def new(raw, key = raw, modifier = 0, extra = nil)
|
153
|
+
@cache ? (@cache[raw] ||= super.freeze) : super.freeze
|
154
|
+
end
|
155
|
+
|
156
|
+
# @!visibility private
|
157
|
+
def unknown(raw) = new(raw, nil)
|
158
|
+
end
|
159
|
+
|
160
|
+
# Event string received from standard input.
|
161
|
+
# This can be a simple value like `"a"`or `"\e[24;6~"` (for Shift+Ctrl+F12).
|
162
|
+
#
|
163
|
+
# @return [String] received event string
|
164
|
+
attr_reader :raw
|
165
|
+
|
166
|
+
# Pressed key without any modifiers.
|
167
|
+
# This can be a string for simple keys like `"a"` or a Symbol like `:F12`.
|
168
|
+
# @return [String, Symbol] key without modifiers
|
169
|
+
attr_reader :key
|
170
|
+
|
171
|
+
# Modifier key code. This represents the encoded key modifier like `Shift`
|
172
|
+
# or `Alt`.
|
173
|
+
#
|
174
|
+
# @return [Integer] modifier key code
|
175
|
+
attr_reader :modifier
|
176
|
+
|
177
|
+
# @comment for mouse events
|
178
|
+
# @!visibility private
|
179
|
+
attr_reader :extra
|
180
|
+
|
181
|
+
# Name of the key event.
|
182
|
+
# This can be a simple name like `"a"` or `"Shift+Ctrl+F12"` for combined
|
183
|
+
# keys.
|
184
|
+
#
|
185
|
+
# @return [String] key name
|
186
|
+
attr_reader :name
|
187
|
+
|
188
|
+
# @attribute [r] modifier?
|
189
|
+
# @return [true, false] whether a key modifier was pressed
|
190
|
+
def modifier? = @modifier != 0
|
191
|
+
|
192
|
+
# @attribute [r] simple?
|
193
|
+
# @return [true, false] whether a simple char was pressed
|
194
|
+
def simple? = @raw == @name
|
195
|
+
|
196
|
+
# All pressed keys.
|
197
|
+
# This is composed by all {modifier} and the {key}.
|
198
|
+
#
|
199
|
+
# @return [Array<Symbol, String>] all pressed keys
|
200
|
+
def to_a = @ary.dup
|
201
|
+
|
202
|
+
# @!visibility private
|
203
|
+
def to_ary = simple? ? [@raw] : [@raw, @name]
|
204
|
+
|
205
|
+
# @!visibility private
|
206
|
+
def to_s = @name.dup
|
207
|
+
|
208
|
+
# @!visibility private
|
209
|
+
def inspect = "<#{self.class.name} #{to_ary.map(&:inspect).join(' ')}>"
|
210
|
+
|
211
|
+
# @!visibility private
|
212
|
+
def freeze
|
213
|
+
@raw.freeze
|
214
|
+
@key.freeze
|
215
|
+
@extra.freeze
|
216
|
+
@name.freeze
|
217
|
+
super
|
218
|
+
end
|
219
|
+
|
220
|
+
private
|
221
|
+
|
222
|
+
def initialize(raw, key, modifier, extra)
|
223
|
+
@raw = raw
|
224
|
+
@key = key
|
225
|
+
@modifier = modifier
|
226
|
+
@extra = extra
|
227
|
+
@ary = MODIFIERS.filter_map { |b, n| n if modifier.allbits?(b) }
|
228
|
+
@ary << key if key
|
229
|
+
@name = @ary.join('+').encode(Encoding::UTF_8)
|
230
|
+
end
|
231
|
+
|
232
|
+
@cache = {}
|
233
|
+
|
234
|
+
MODIFIERS = {
|
235
|
+
1 => :Shift,
|
236
|
+
2 => :Alt,
|
237
|
+
4 => :Ctrl,
|
238
|
+
8 => :Super,
|
239
|
+
16 => :Hyper,
|
240
|
+
32 => :Meta,
|
241
|
+
64 => :Caps,
|
242
|
+
128 => :Num
|
243
|
+
}.freeze
|
244
|
+
private_constant :MODIFIERS
|
99
245
|
end
|
100
246
|
|
101
|
-
|
102
|
-
|
103
|
-
autoload :DumbKeys, "#{dir}/input/dumb_keys.rb"
|
104
|
-
autoload :LegacyKeys, "#{dir}/input/legacy_keys.rb"
|
105
|
-
private_constant :CSIuKeys, :DumbKeys, :LegacyKeys
|
247
|
+
autoload :AsKeyEvent, "#{__dir__}/input/as_key_event.rb"
|
248
|
+
private_constant :AsKeyEvent
|
106
249
|
end
|
@@ -17,14 +17,13 @@ RSpec.shared_context 'with Terminal.rb' do |ansi: true, application: :kitty, col
|
|
17
17
|
allow(Terminal).to receive(:hide_cursor).with(no_args).and_return(Terminal)
|
18
18
|
allow(Terminal).to receive(:show_cursor).with(no_args).and_return(Terminal)
|
19
19
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
nobbc = ansi ? lambda(&:to_s) : ->(s) { Terminal::Ansi.undecorate(s) }
|
20
|
+
if ansi
|
21
|
+
bbc = ->(s) { Terminal::Ansi.bbcode(s) }
|
22
|
+
nobbc = lambda(&:to_s)
|
23
|
+
else
|
24
|
+
bbc = ->(s) { Terminal::Ansi.plain(s) }
|
25
|
+
nobbc = ->(s) { Terminal::Ansi.undecorate(s) }
|
26
|
+
end
|
28
27
|
|
29
28
|
allow(Terminal).to receive(:<<) do |object|
|
30
29
|
stdout.push(bbcode[object]) unless object.nil?
|
@@ -6,9 +6,9 @@ module Terminal
|
|
6
6
|
# Generated file; based on Unicode v16.0.0
|
7
7
|
#
|
8
8
|
module CharWidth
|
9
|
-
def self.[](ord) =
|
9
|
+
def self.[](ord) = @width[@last.bsearch_index { ord <= _1 }]
|
10
10
|
|
11
|
-
|
11
|
+
@last = [
|
12
12
|
0xa0,
|
13
13
|
0xa1,
|
14
14
|
0xa3,
|
@@ -1293,7 +1293,7 @@ module Terminal
|
|
1293
1293
|
0x7fffffff
|
1294
1294
|
].freeze
|
1295
1295
|
|
1296
|
-
|
1296
|
+
@width = [
|
1297
1297
|
1,
|
1298
1298
|
-1,
|
1299
1299
|
1,
|
@@ -2578,6 +2578,7 @@ module Terminal
|
|
2578
2578
|
1
|
2579
2579
|
].freeze
|
2580
2580
|
end
|
2581
|
+
|
2581
2582
|
private_constant :CharWidth
|
2582
2583
|
end
|
2583
2584
|
end
|
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.
|
4
|
+
version: 0.12.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mike Blumtritt
|
@@ -34,9 +34,7 @@ files:
|
|
34
34
|
- lib/terminal/ansi/named_colors.rb
|
35
35
|
- lib/terminal/detect.rb
|
36
36
|
- lib/terminal/input.rb
|
37
|
-
- lib/terminal/input/
|
38
|
-
- lib/terminal/input/dumb_keys.rb
|
39
|
-
- lib/terminal/input/legacy_keys.rb
|
37
|
+
- lib/terminal/input/as_key_event.rb
|
40
38
|
- lib/terminal/rspec/helper.rb
|
41
39
|
- lib/terminal/text.rb
|
42
40
|
- lib/terminal/text/char_width.rb
|
@@ -46,10 +44,11 @@ homepage: https://codeberg.org/mblumtritt/Terminal.rb
|
|
46
44
|
licenses:
|
47
45
|
- MIT
|
48
46
|
metadata:
|
49
|
-
rubygems_mfa_required: 'true'
|
50
47
|
source_code_uri: https://codeberg.org/mblumtritt/Terminal.rb
|
51
48
|
bug_tracker_uri: https://codeberg.org/mblumtritt/Terminal.rb/issues
|
52
|
-
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
|
53
52
|
rdoc_options: []
|
54
53
|
require_paths:
|
55
54
|
- lib
|