typr 1.8.0 → 1.9.2
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/CHANGELOG.md +24 -0
- data/README.md +4 -4
- data/lib/browser.rb +98 -19
- data/lib/grid.rb +120 -31
- data/lib/line.rb +50 -8
- data/lib/space.rb +113 -8
- data/lib/stack.rb +106 -34
- data/lib/terminal.rb +393 -55
- data/lib/text.rb +57 -11
- data/lib/typr.rb +5 -3
- data/typr.gemspec +2 -2
- metadata +2 -2
data/lib/line.rb
CHANGED
|
@@ -12,6 +12,17 @@ module Typr
|
|
|
12
12
|
# line.ask([ ["Name?", :line], ["Age?", :line] ])
|
|
13
13
|
|
|
14
14
|
class Line < Space
|
|
15
|
+
##
|
|
16
|
+
# Line state: +default+ (a String, Proc, or Space) restored by {#reset},
|
|
17
|
+
# +prompt+ (a single char, +>?+ by default) shown before answers,
|
|
18
|
+
# +bindings+ the clickable keybinding labels, +data+ the currently
|
|
19
|
+
# rendered text, +align+ (:left/:right) horizontal alignment,
|
|
20
|
+
# +trim+ (:left/:right) the side clipped on overflow.
|
|
21
|
+
#
|
|
22
|
+
# line.default = "status: ok"
|
|
23
|
+
# line.prompt = "?"
|
|
24
|
+
# line.align = :left
|
|
25
|
+
|
|
15
26
|
attr_accessor :default, :prompt, :bindings, :data, :align, :trim
|
|
16
27
|
|
|
17
28
|
# Render +msg+ (String, Proc, or Space) on this line.
|
|
@@ -36,7 +47,7 @@ class Line < Space
|
|
|
36
47
|
# line.append " world" #=> "hello world"
|
|
37
48
|
# line << "!" #=> "hello world!"
|
|
38
49
|
|
|
39
|
-
def append(str); show @data+str end
|
|
50
|
+
def append(str); show @data+str; @data end
|
|
40
51
|
alias :<< :append
|
|
41
52
|
|
|
42
53
|
# The keybinding list as a clickable grid of the line's own bindings. It
|
|
@@ -92,16 +103,26 @@ class Line < Space
|
|
|
92
103
|
# Array - interactive pick via <widget>.pick(<type>); an optional third
|
|
93
104
|
# element renders the chosen row's field into the line, and an
|
|
94
105
|
# optional fourth element is passed as pick keyword arguments
|
|
95
|
-
# (e.g. { column: 0 } to open the pick in / search mode)
|
|
106
|
+
# (e.g. { column: 0 } to open the pick in / search mode).
|
|
107
|
+
# Special case: [:line, { initial: "text" }] opens the inline
|
|
108
|
+
# editor via Typr.read_line prefilled with +initial+ instead
|
|
109
|
+
# of a widget pick.
|
|
96
110
|
# :key - a single keypress via Typr.read_key
|
|
97
111
|
# :line - interactive line editor via Typr.read_line at the cursor
|
|
98
112
|
#
|
|
113
|
+
# Every entry — including a trailing +with:+ — is simply another
|
|
114
|
+
# question in order (a +with:+ entry is labeled "with" when drawn), so
|
|
115
|
+
# +ask(pick: [grid, :row], with: :line)+ first picks, then reads
|
|
116
|
+
# free text. Hash order is insertion order.
|
|
117
|
+
#
|
|
99
118
|
# Pressing the exit key (@keymap[:exit], Escape by default) aborts the
|
|
100
119
|
# remaining questions and returns nil.
|
|
101
120
|
#
|
|
102
121
|
# line.ask(name: :line) #=> "Alice"
|
|
103
122
|
# line.ask(keys: :key) #=> "a"
|
|
104
123
|
# line.ask(open: [grid, :row, :name]) #=> 2 (picked row id)
|
|
124
|
+
# line.ask(nick: [:line, { initial: "bob" }]) #=> edited string
|
|
125
|
+
# line.ask(pick: [grid, :row], with: :line) #=> [2, "typed text"]
|
|
105
126
|
# line.ask([ ["Name?", :line], ["Ok?", :key] ]) #=> ["Alice", "a"]
|
|
106
127
|
|
|
107
128
|
def ask sentence
|
|
@@ -149,15 +170,26 @@ class Line < Space
|
|
|
149
170
|
return ( answer.one? ? answer.first : answer )
|
|
150
171
|
end
|
|
151
172
|
|
|
152
|
-
|
|
153
|
-
#
|
|
154
|
-
#
|
|
155
|
-
#
|
|
156
|
-
#
|
|
157
|
-
#
|
|
173
|
+
##
|
|
174
|
+
# Prompt for a single command line at the cursor: +prompt+ rendered in
|
|
175
|
+
# the line's default color, typed input in the answer color. TAB
|
|
176
|
+
# matches the current word against the shell (commands, options, files)
|
|
177
|
+
# and replaces it through the pick grid. Regions of the typed input
|
|
178
|
+
# matching @colors[:regex] are colored as they are typed (with the
|
|
179
|
+
# :shell scheme: the first word red, double-dash options blue).
|
|
180
|
+
#
|
|
181
|
+
# +history+ is an Array whose entries Up/Down walk; +prefixes+ lists
|
|
182
|
+
# command-start characters stripped before completion matching;
|
|
183
|
+
# +redraw+ repaints the caller's screen after a completion pick;
|
|
184
|
+
# +regex+ overrides @colors[:regex] for this prompt.
|
|
158
185
|
#
|
|
159
186
|
# line.cli "> ", initial: "cp %name"
|
|
160
187
|
# #=> "cp source.txt" (or nil on Escape)
|
|
188
|
+
# line.cli "> ", history: @recent, prefixes: "$>"
|
|
189
|
+
#
|
|
190
|
+
# @param prompt [String] rendered before the typed input
|
|
191
|
+
# @param initial [String] prefilled input
|
|
192
|
+
# @return [String, nil] the accepted command, or nil on Escape
|
|
161
193
|
|
|
162
194
|
def cli prompt, initial: '', redraw: nil, history: nil, prefixes: nil, regex: nil
|
|
163
195
|
re = /\A[#{Regexp.escape(prefixes || '|+=!')}]/
|
|
@@ -197,6 +229,16 @@ class Line < Space
|
|
|
197
229
|
|
|
198
230
|
public
|
|
199
231
|
|
|
232
|
+
##
|
|
233
|
+
# Construct a Line. Position via the {Space} boundaries; +default+ sets
|
|
234
|
+
# the text shown after {#reset}, +bindings+ the keybinding labels.
|
|
235
|
+
#
|
|
236
|
+
# line = Typr::Line.new(top: -1, left: 0,
|
|
237
|
+
# default: "(f)ilter, (s)ort, [esc] quit")
|
|
238
|
+
#
|
|
239
|
+
# @param args [Hash] boundary and display options (see {Space#initialize})
|
|
240
|
+
# @return [Line]
|
|
241
|
+
|
|
200
242
|
def initialize args
|
|
201
243
|
@right= -1
|
|
202
244
|
@align = :left
|
data/lib/space.rb
CHANGED
|
@@ -16,7 +16,21 @@ class Space
|
|
|
16
16
|
include Typr
|
|
17
17
|
|
|
18
18
|
%w[left top right bottom].each{ |name| method = <<STR
|
|
19
|
-
|
|
19
|
+
##
|
|
20
|
+
# Raw +%s+ value as passed to the constructor, before resolution
|
|
21
|
+
# (nil, Integer, Float, or Proc). Useful for introspection.
|
|
22
|
+
#
|
|
23
|
+
# space.%s_setting #=> 0
|
|
24
|
+
#
|
|
25
|
+
def %s_setting; @%s; end
|
|
26
|
+
##
|
|
27
|
+
# Resolved +%s+ edge: Integer (absolute position), Float (fraction of
|
|
28
|
+
# the terminal), Proc (evaluated each layout pass), or a negative
|
|
29
|
+
# Integer (offset from the opposite edge, -1 = last). Defaults to the
|
|
30
|
+
# widget's natural extent when unset.
|
|
31
|
+
#
|
|
32
|
+
# space.%s #=> 4
|
|
33
|
+
#
|
|
20
34
|
def %s
|
|
21
35
|
max=Typr.#{ name[/left|right/] ? 'width' : 'height' }
|
|
22
36
|
if !@%s;[max, #{ case name
|
|
@@ -30,9 +44,18 @@ else 'top+[(respond_to?(:rows) ? rows : 0), 1].max-1+(respond_to?(:headspace) ?
|
|
|
30
44
|
else @%s end
|
|
31
45
|
end
|
|
32
46
|
STR
|
|
33
|
-
eval( method % ([name]*
|
|
47
|
+
eval( method % ([name]*15) ) }
|
|
48
|
+
|
|
49
|
+
##
|
|
50
|
+
# Deep-convert String keys to Symbols so string-keyed config (e.g. YAML)
|
|
51
|
+
# is honored. Non-Hash values pass through untouched.
|
|
52
|
+
#
|
|
53
|
+
# space.symbolize "colors" => { "border" => :red }
|
|
54
|
+
# #=> {colors: {border: :red}}
|
|
55
|
+
#
|
|
56
|
+
# @param obj [Object] hash or value to convert
|
|
57
|
+
# @return [Object] converted copy, or the value itself when not a Hash
|
|
34
58
|
|
|
35
|
-
# Deep-convert String keys to Symbols so string-keyed config (e.g. YAML) is honored.
|
|
36
59
|
def symbolize obj
|
|
37
60
|
case obj
|
|
38
61
|
when Hash
|
|
@@ -41,12 +64,44 @@ eval( method % ([name]*11) ) }
|
|
|
41
64
|
else obj end
|
|
42
65
|
end
|
|
43
66
|
|
|
67
|
+
##
|
|
68
|
+
# Viewport edges, readable and assignable. Each accepts an Integer
|
|
69
|
+
# (absolute position), a Float (fraction of the terminal), a Proc
|
|
70
|
+
# (evaluated each layout pass), or a negative Integer (offset from the
|
|
71
|
+
# opposite edge, -1 = last row/column); unset edges fall back to the
|
|
72
|
+
# widget's natural extent. +left_setting+ and friends return the raw
|
|
73
|
+
# constructor value before resolution.
|
|
74
|
+
#
|
|
75
|
+
# space.left = 0
|
|
76
|
+
# space.right = 0.5
|
|
77
|
+
# space.bottom = -1
|
|
78
|
+
# space.right_setting #=> 0.5
|
|
44
79
|
attr_writer :left, :top, :right, :bottom
|
|
80
|
+
##
|
|
81
|
+
# +margin+ is the left-edge padding string, +colors+ the per-part color
|
|
82
|
+
# hash, +interval+ the redraw period in seconds for {#start}, and
|
|
83
|
+
# +borders+ the raw edge characters (prefer {#border=}).
|
|
84
|
+
#
|
|
85
|
+
# space.margin = " "
|
|
86
|
+
# space.interval = 2
|
|
45
87
|
attr_accessor :margin, :colors, :interval, :borders
|
|
46
88
|
|
|
89
|
+
##
|
|
47
90
|
# Viewport width in cells (right - left + 1).
|
|
91
|
+
#
|
|
92
|
+
# space.width #=> 80
|
|
93
|
+
#
|
|
94
|
+
# @return [Integer]
|
|
95
|
+
|
|
48
96
|
def width; right - left + 1 end
|
|
97
|
+
|
|
98
|
+
##
|
|
49
99
|
# Viewport height in cells (bottom - top + 1).
|
|
100
|
+
#
|
|
101
|
+
# space.height #=> 24
|
|
102
|
+
#
|
|
103
|
+
# @return [Integer]
|
|
104
|
+
|
|
50
105
|
def height; bottom - top + 1 end
|
|
51
106
|
|
|
52
107
|
##
|
|
@@ -60,7 +115,7 @@ eval( method % ([name]*11) ) }
|
|
|
60
115
|
def data_at x, y; nil end
|
|
61
116
|
|
|
62
117
|
##
|
|
63
|
-
# The trigger key for a binding label like "[h]elp" or "[/]:
|
|
118
|
+
# The trigger key for a binding label like "[h]elp" or "[/]:narrow", or nil
|
|
64
119
|
# for named keys ("[up]", "[esc]") which stay keyboard-only.
|
|
65
120
|
#
|
|
66
121
|
# line.extract_key "[R]ecurse" # => "R"
|
|
@@ -70,18 +125,48 @@ eval( method % ([name]*11) ) }
|
|
|
70
125
|
key if key and key.size == 1
|
|
71
126
|
end
|
|
72
127
|
|
|
128
|
+
##
|
|
73
129
|
# Redraw every +interval+ seconds from a background thread.
|
|
130
|
+
#
|
|
131
|
+
# space.interval = 1
|
|
132
|
+
# space.start #=> #<Thread>
|
|
133
|
+
# space.stop # terminates it
|
|
134
|
+
#
|
|
135
|
+
# @return [Thread]
|
|
136
|
+
|
|
74
137
|
def start; @updater = Thread.new{ loop{show; sleep @interval }} end
|
|
75
|
-
|
|
138
|
+
|
|
139
|
+
##
|
|
140
|
+
# Stop the background refresh thread started by {#start}.
|
|
141
|
+
#
|
|
142
|
+
# space.stop #=> #<Thread> (terminated)
|
|
143
|
+
#
|
|
144
|
+
# @return [Thread]
|
|
145
|
+
|
|
76
146
|
def stop; @updater.terminate end
|
|
77
147
|
|
|
148
|
+
##
|
|
78
149
|
# Draw a border char at screen (x, y); skips nil and off-screen positions.
|
|
150
|
+
#
|
|
151
|
+
# space.draw_border 0, 0, "┌" #=> nil
|
|
152
|
+
#
|
|
153
|
+
# @param x [Integer] column (0-based)
|
|
154
|
+
# @param y [Integer] row (0-based)
|
|
155
|
+
# @param char [String, nil] character to draw
|
|
156
|
+
# @return [nil]
|
|
157
|
+
|
|
79
158
|
def draw_border x,y,char
|
|
80
159
|
draw move_code(x, y) + char unless not char or
|
|
81
160
|
x < 0 or x > Typr.width or y < 0 or y > Typr.height
|
|
82
161
|
end
|
|
83
162
|
|
|
163
|
+
##
|
|
84
164
|
# Draw the widget's border box (no-op when no borders are set).
|
|
165
|
+
#
|
|
166
|
+
# space.show #=> nil
|
|
167
|
+
#
|
|
168
|
+
# @return [nil]
|
|
169
|
+
|
|
85
170
|
def show
|
|
86
171
|
return if @borders.empty?
|
|
87
172
|
color @colors[:border]
|
|
@@ -97,8 +182,19 @@ eval( method % ([name]*11) ) }
|
|
|
97
182
|
draw_border(right + 1, bottom + 1, @borders[:bottom_right])
|
|
98
183
|
end
|
|
99
184
|
|
|
100
|
-
|
|
101
|
-
#
|
|
185
|
+
##
|
|
186
|
+
# Set border style: +:light+/:heavy+/:double+/:round+, a single char
|
|
187
|
+
# repeated across the box, an 8-char string (top, bottom, left, right,
|
|
188
|
+
# top-left, top-right, bottom-left, bottom-right), or nil for none.
|
|
189
|
+
#
|
|
190
|
+
# space.border = :round
|
|
191
|
+
# space.border = "─" # one char for every edge
|
|
192
|
+
# space.border = "──││┌┐└┘" # explicit edges, same as :light
|
|
193
|
+
# space.border = nil # remove the border
|
|
194
|
+
#
|
|
195
|
+
# @param border [Symbol, String, nil]
|
|
196
|
+
# @return [void]
|
|
197
|
+
|
|
102
198
|
def border=(border)
|
|
103
199
|
chars = case border
|
|
104
200
|
when Symbol
|
|
@@ -111,8 +207,17 @@ eval( method % ([name]*11) ) }
|
|
|
111
207
|
bottom_right ].map.with_index{ |part,id| [part.to_sym, chars[id]] }.to_h if chars
|
|
112
208
|
end
|
|
113
209
|
|
|
210
|
+
##
|
|
114
211
|
# Build a widget from boundary (left/top/right/bottom), border, margin,
|
|
115
|
-
# colors, interval, and keymap.
|
|
212
|
+
# colors, interval, and keymap. Every keyword becomes an instance
|
|
213
|
+
# variable (+border:+ is applied through {#border=}).
|
|
214
|
+
#
|
|
215
|
+
# box = Typr::Space.new(left: 0, top: 2, right: 0.5, bottom: -4,
|
|
216
|
+
# border: :round, colors: { border: :grey50 }, interval: 2)
|
|
217
|
+
#
|
|
218
|
+
# @param args [Hash] boundary and visual options (see the class example)
|
|
219
|
+
# @return [Space]
|
|
220
|
+
|
|
116
221
|
def initialize args={}
|
|
117
222
|
@max, @keymap, @colors, @margin = 0, {}, {}, ' '
|
|
118
223
|
@left, @top, @interval, @borders = 0, 0, 1, {}
|
data/lib/stack.rb
CHANGED
|
@@ -17,10 +17,25 @@ module Typr
|
|
|
17
17
|
# KEY_HOME / KEY_END (jump to first or last pageable row)
|
|
18
18
|
|
|
19
19
|
class Stack < Space
|
|
20
|
-
##
|
|
21
|
-
|
|
20
|
+
##
|
|
21
|
+
# Widget configuration and state: +left+/+top+/+right+/+bottom+ set
|
|
22
|
+
# the viewport (see {Space}), +alternate+ toggles striped rows
|
|
23
|
+
# (+:grey10+ against the default bg), +start+ is the scroll offset,
|
|
24
|
+
# +keymap+ maps key sequences to methods, +selected+ holds picked ids
|
|
25
|
+
# per type, and +header+ is the top-bar label.
|
|
26
|
+
#
|
|
27
|
+
# stack.start = 3
|
|
28
|
+
# stack.header = "Title"
|
|
22
29
|
|
|
23
30
|
attr_accessor :start, :keymap, :selected, :header
|
|
31
|
+
##
|
|
32
|
+
# +separator+ is the gap between columns, +hints+ the hint characters,
|
|
33
|
+
# +hints_start+ the offset of the current hint chunk ({#cycle}), and
|
|
34
|
+
# +modifier+ is +:alt+ after an Alt-digit hint press, +nil+ otherwise.
|
|
35
|
+
#
|
|
36
|
+
# stack.hints = "1234567890"
|
|
37
|
+
# stack.modifier #=> :alt (after picking with Alt+digit)
|
|
38
|
+
|
|
24
39
|
attr_accessor :separator, :hints, :hints_start, :modifier
|
|
25
40
|
|
|
26
41
|
##
|
|
@@ -80,7 +95,9 @@ module Typr
|
|
|
80
95
|
# stack.reset # resets position and selection
|
|
81
96
|
# stack.reset :position # only scrolls back to top
|
|
82
97
|
# stack.reset :selection # clears all selected rows/columns/fields
|
|
83
|
-
# stack.reset [:
|
|
98
|
+
# stack.reset [:position, :selection]
|
|
99
|
+
#
|
|
100
|
+
# @param type [:all, :position, :selection, Array<Symbol>] anything else is ignored
|
|
84
101
|
|
|
85
102
|
def reset type=:all
|
|
86
103
|
case type
|
|
@@ -150,10 +167,16 @@ module Typr
|
|
|
150
167
|
|
|
151
168
|
##
|
|
152
169
|
# Dispatches a key from the terminal to its semantic action and clamps the current page
|
|
153
|
-
# offset.
|
|
170
|
+
# offset. Unknown keys only clamp. +confirm+ dispatches to a +confirm+
|
|
171
|
+
# method, which only Browser defines.
|
|
172
|
+
#
|
|
173
|
+
# stack.send Typr::KEY_DOWN # scrolls down one row
|
|
154
174
|
#
|
|
155
|
-
#
|
|
156
|
-
#
|
|
175
|
+
# Mouse: wheel scrolls (+:scroll+), a click that misses is +:outside+,
|
|
176
|
+
# a left/right press on a row returns its id.
|
|
177
|
+
#
|
|
178
|
+
# @param key [String, Typr::Mouse] key sequence or mouse event
|
|
179
|
+
# @return [Object] the keymap action's result; +:scroll+/:outside+/row id for mouse
|
|
157
180
|
|
|
158
181
|
def send key#, map=nil
|
|
159
182
|
if key.is_a?(Typr::Mouse)
|
|
@@ -174,63 +197,100 @@ module Typr
|
|
|
174
197
|
return response
|
|
175
198
|
end
|
|
176
199
|
|
|
177
|
-
##
|
|
200
|
+
##
|
|
201
|
+
# Scroll to the top of the dataset.
|
|
178
202
|
#
|
|
179
|
-
# stack.to_top
|
|
203
|
+
# stack.to_top # @start => 0
|
|
204
|
+
#
|
|
205
|
+
# @return [nil]
|
|
180
206
|
|
|
181
207
|
def to_top; @start = 0; return end
|
|
182
208
|
|
|
183
|
-
##
|
|
209
|
+
##
|
|
210
|
+
# Scroll to the bottom pageable position (last row minus viewport height).
|
|
184
211
|
#
|
|
185
|
-
# stack.to_bottom
|
|
212
|
+
# stack.to_bottom # @start => rows - height
|
|
213
|
+
#
|
|
214
|
+
# @return [nil]
|
|
186
215
|
|
|
187
216
|
def to_bottom; @start = rows - height; return end
|
|
188
217
|
|
|
189
|
-
##
|
|
218
|
+
##
|
|
219
|
+
# Step down by one row.
|
|
220
|
+
#
|
|
221
|
+
# stack.down # @start += 1
|
|
190
222
|
#
|
|
191
|
-
#
|
|
223
|
+
# @return [nil]
|
|
192
224
|
|
|
193
225
|
def down; @start += 1; return end
|
|
194
226
|
|
|
195
|
-
##
|
|
227
|
+
##
|
|
228
|
+
# Step up by one row.
|
|
229
|
+
#
|
|
230
|
+
# stack.up # @start -= 1
|
|
196
231
|
#
|
|
197
|
-
#
|
|
232
|
+
# @return [nil]
|
|
198
233
|
|
|
199
234
|
def up; @start -= 1; return end
|
|
200
235
|
|
|
201
|
-
##
|
|
236
|
+
##
|
|
237
|
+
# Jump down by one viewport of rows.
|
|
238
|
+
#
|
|
239
|
+
# stack.page_down # @start += height
|
|
202
240
|
#
|
|
203
|
-
#
|
|
241
|
+
# @return [nil]
|
|
204
242
|
|
|
205
243
|
def page_down; @start += height; return end
|
|
206
244
|
|
|
207
|
-
##
|
|
245
|
+
##
|
|
246
|
+
# Jump up by one viewport of rows.
|
|
247
|
+
#
|
|
248
|
+
# stack.page_up # @start -= height
|
|
208
249
|
#
|
|
209
|
-
#
|
|
250
|
+
# @return [nil]
|
|
210
251
|
|
|
211
252
|
def page_up; @start -= height; return end
|
|
212
253
|
|
|
213
254
|
##
|
|
214
|
-
# Blocks the calling thread
|
|
215
|
-
# page
|
|
216
|
-
#
|
|
255
|
+
# Blocks the calling thread for an interactive pick from the current
|
|
256
|
+
# page with hint characters or arrow keys. Single picks return the
|
|
257
|
+
# moment they're made; multi (+...+s+) picks toggle until Return
|
|
258
|
+
# confirms the selection (Escape aborts, and confirming an empty
|
|
259
|
+
# selection returns nil).
|
|
217
260
|
#
|
|
218
261
|
# The +type+ argument controls what kind of picker is shown:
|
|
219
262
|
#
|
|
220
|
-
#
|
|
221
|
-
#
|
|
222
|
-
# +:row
|
|
223
|
-
#
|
|
224
|
-
# +:column
|
|
225
|
-
# +:
|
|
226
|
-
# +:
|
|
227
|
-
#
|
|
263
|
+
# Type | Picks
|
|
264
|
+
# -------------------|------------------------------------------------
|
|
265
|
+
# +:row+ | Single row id
|
|
266
|
+
# +:rows+ | Multi-select row ids (Return confirms)
|
|
267
|
+
# +:column+ | One column of the given row (Grid: real index, Text: word offset)
|
|
268
|
+
# +:columns+ | Multi-select columns (Return confirms)
|
|
269
|
+
# +:field+ | One [row, column] pair, picked row-then-column
|
|
270
|
+
# +:fields+ | Multi-select [row, column] pairs
|
|
271
|
+
# +:relative_row+ | Viewport-absolute row index (0-based)
|
|
272
|
+
# +:none+ | Navigation only; always returns nil
|
|
273
|
+
#
|
|
274
|
+
# +:column+, +:columns+, +:field+ (+:fields+) and +:none+ need row
|
|
275
|
+
# positions, so they only work on Grid and Text — a bare Stack
|
|
276
|
+
# supports +:row+ and +:rows+. (The +"file"+ type belongs to
|
|
277
|
+
# {Browser#pick}.)
|
|
228
278
|
#
|
|
229
279
|
# stack.pick # single row picker
|
|
230
|
-
# stack.pick :column, 3 #
|
|
231
|
-
# stack.pick
|
|
280
|
+
# stack.pick :column, 3 # column of the 4th visible row (page index, not id)
|
|
281
|
+
# stack.pick :rows # multi-select rows
|
|
282
|
+
# stack.pick :relative_row # 0-based index into the viewport
|
|
232
283
|
#
|
|
233
|
-
#
|
|
284
|
+
# Pressing Alt with a hint digit (ESC + digit) picks that hint row and
|
|
285
|
+
# sets +modifier+ to +:alt+ for the caller. The Return and Escape keys
|
|
286
|
+
# come from +@keymap+ (+confirm+/+exit+, Return/Escape by default).
|
|
287
|
+
#
|
|
288
|
+
# Mouse: left-click a row to pick it (row pickers only); wheel up/down
|
|
289
|
+
# scrolls the page; clicking outside cancels like Escape.
|
|
290
|
+
#
|
|
291
|
+
# @param type [Symbol, String] picker type (table above; symbols documented)
|
|
292
|
+
# @param row [Integer] page-relative row for +:column+ hints (ignored otherwise)
|
|
293
|
+
# @return [Integer, Array, nil] row id, [row, column], confirmed selection, or nil
|
|
234
294
|
|
|
235
295
|
def pick type = :row, row=0 #, key=nil
|
|
236
296
|
type = type.to_s
|
|
@@ -298,6 +358,14 @@ module Typr
|
|
|
298
358
|
return
|
|
299
359
|
end
|
|
300
360
|
|
|
361
|
+
##
|
|
362
|
+
# Walk the hint characters backwards by one chunk (mirror of {#cycle}),
|
|
363
|
+
# wrapping to the last full chunk before the start of the list.
|
|
364
|
+
#
|
|
365
|
+
# stack.cycle_back # hints_start -= hints.size (wraps at 0)
|
|
366
|
+
#
|
|
367
|
+
# @return [nil]
|
|
368
|
+
|
|
301
369
|
def cycle_back
|
|
302
370
|
max = [height-1, rows-1+headspace].min
|
|
303
371
|
@hints_start -= @hints.size
|
|
@@ -312,11 +380,15 @@ module Typr
|
|
|
312
380
|
#
|
|
313
381
|
# Option | Default | Description
|
|
314
382
|
# ----------------|---------|-------------------------------------------
|
|
315
|
-
# +
|
|
316
|
-
# +hints+ | +"
|
|
383
|
+
# +keymap+ | {} | Custom name-to-key mappings (override navigation defaults)
|
|
384
|
+
# +hints+ | +"1234567890"+ | Characters used in the hint overlay
|
|
317
385
|
# +alternate+ | true | Striped row backgrounds
|
|
318
386
|
# +header+ | nil | Label shown in a header bar
|
|
319
387
|
# +separator+ | +" "+ | String drawn between columns (used by Grid)
|
|
388
|
+
# +colors+ | {} | Per-part colors (+hints+, +header+, +selected+, +alternate+, +rows+)
|
|
389
|
+
# +selected+ | {} | Pre-picked ids per type (+rows+, +columns+, +fields+)
|
|
390
|
+
#
|
|
391
|
+
# stack = Typr::Stack.new(keymap: { exit: "q" }) # quit on q instead
|
|
320
392
|
|
|
321
393
|
def initialize args={}
|
|
322
394
|
@keymap, @separator, @selected = {}, " ", {}
|