typr 1.1.4 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +41 -0
- data/README.md +68 -37
- data/example/grid +4 -4
- data/example/text +7 -4
- data/lib/browser.rb +106 -78
- data/lib/frontend.rb +7 -3
- data/lib/graphical.rb +10 -13
- data/lib/grid.rb +69 -14
- data/lib/line.rb +57 -27
- data/lib/space.rb +25 -5
- data/lib/stack.rb +34 -10
- data/lib/terminal.rb +280 -27
- data/lib/text.rb +129 -7
- data/lib/typr.rb +8 -9
- data/share/mimetypes +1298 -1
- data/share/terminfo +691 -0
- data/typr.gemspec +4 -3
- metadata +3 -8
- data/Gemfile +0 -10
- data/lib/curses.rb +0 -120
data/lib/graphical.rb
CHANGED
|
@@ -57,7 +57,7 @@ module Visuals
|
|
|
57
57
|
end
|
|
58
58
|
end
|
|
59
59
|
|
|
60
|
-
def
|
|
60
|
+
def draw( str )
|
|
61
61
|
return unless str
|
|
62
62
|
if get_background
|
|
63
63
|
GO.draw_color = get_background
|
|
@@ -81,17 +81,14 @@ module Visuals
|
|
|
81
81
|
e = Event.poll until e.is_a? Event::KeyDown
|
|
82
82
|
return e.sym.between?(32, 126) ? e.sym.chr : e.sym
|
|
83
83
|
when :line
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
line = Readline.readline
|
|
93
|
-
listen.terminate
|
|
94
|
-
return line
|
|
84
|
+
str = ''
|
|
85
|
+
loop do
|
|
86
|
+
e = Event.poll
|
|
87
|
+
next unless e.is_a? Event::KeyDown
|
|
88
|
+
return nil if e.sym == KEY_ESCAPE
|
|
89
|
+
return str if e.sym == KEY_RETURN
|
|
90
|
+
str << e.sym.chr if e.sym.between? 32, 126
|
|
91
|
+
end
|
|
95
92
|
end
|
|
96
93
|
end
|
|
97
94
|
|
|
@@ -117,7 +114,7 @@ if __FILE__ == $0
|
|
|
117
114
|
loop do
|
|
118
115
|
clear
|
|
119
116
|
COLORS.keys.each_with_index{ |c,i|
|
|
120
|
-
foreground c; move 0,i;
|
|
117
|
+
foreground c; move 0,i; draw characters }
|
|
121
118
|
refresh
|
|
122
119
|
exit if read(:key) == KEY_ESCAPE
|
|
123
120
|
end
|
data/lib/grid.rb
CHANGED
|
@@ -9,16 +9,16 @@ module Typr
|
|
|
9
9
|
# input: [ ["Alice", 30], ["Bob", 25] ],
|
|
10
10
|
# header: [:name, :age],
|
|
11
11
|
# format: [:max, :right]
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
# )
|
|
13
|
+
# grid.show
|
|
14
|
+
#
|
|
15
15
|
# Column format tokens: +Integer+ (fixed width), +:min+ (auto), +:max+ (fill remaining).
|
|
16
16
|
#
|
|
17
17
|
# Built-in procs: +:filetree+, +:datetime+, +:magnitudes+, +:convert+.
|
|
18
18
|
|
|
19
19
|
class Grid < Stack # Table
|
|
20
20
|
attr_accessor :format, :procs, :filters, :data, :map
|
|
21
|
-
attr_accessor :align, :rawsort, :rawfilter
|
|
21
|
+
attr_accessor :align, :rawsort, :rawfilter, :reverse
|
|
22
22
|
attr_writer :sequence
|
|
23
23
|
|
|
24
24
|
##
|
|
@@ -177,10 +177,11 @@ module Typr
|
|
|
177
177
|
end
|
|
178
178
|
|
|
179
179
|
##
|
|
180
|
-
# Add a column filter (substring or regex).
|
|
180
|
+
# Add a column filter (substring or regex). +:all+ matches any column.
|
|
181
181
|
#
|
|
182
182
|
# grid.add_filter(0, "Ali") # name contains "Ali"
|
|
183
183
|
# grid.add_filter(1, /^\d{2}$/) # age matches regex
|
|
184
|
+
# grid.add_filter(:all, "ip") # any column contains "ip"
|
|
184
185
|
#
|
|
185
186
|
# @param column [Integer, Symbol]
|
|
186
187
|
# @param query [String, Regexp]
|
|
@@ -202,8 +203,10 @@ module Typr
|
|
|
202
203
|
|
|
203
204
|
def check row
|
|
204
205
|
@filters.reject{ |column,query|
|
|
205
|
-
|
|
206
|
-
|
|
206
|
+
cols = column == :all ? @data[row].each_index.to_a : [column]
|
|
207
|
+
cols.any?{ |col|
|
|
208
|
+
( (@procs[col] and not @rawfilter[col]) ?
|
|
209
|
+
@layer : @data )[row][col].to_s[query] } }.empty?
|
|
207
210
|
end
|
|
208
211
|
|
|
209
212
|
##
|
|
@@ -237,6 +240,57 @@ module Typr
|
|
|
237
240
|
|
|
238
241
|
def sorted_by name=false; (name and @sort) ? @header[@sort] : @sort end
|
|
239
242
|
|
|
243
|
+
##
|
|
244
|
+
# Pick a row with live-filtering.
|
|
245
|
+
#
|
|
246
|
+
# When column is given, `Grid` overrides `Stack#pick` to add interactive
|
|
247
|
+
# text filtering of rows by the given column. Filter text is shown at the
|
|
248
|
+
# bottom of the grid. Passes through to `super` for all other types or
|
|
249
|
+
# when no column is given.
|
|
250
|
+
#
|
|
251
|
+
# grid.pick :row, 0, column: :name
|
|
252
|
+
# grid.pick :row, 0, column: :all # match any column
|
|
253
|
+
#
|
|
254
|
+
# @param type [Symbol] type is ignored (always :row); passed to super otherwise
|
|
255
|
+
# @param column [Symbol, String] column name to filter on, or :all (default nil)
|
|
256
|
+
|
|
257
|
+
def pick type = :row, row=0, column: nil
|
|
258
|
+
return super(type, row) unless column
|
|
259
|
+
|
|
260
|
+
saved = [@filters.dup, @map, @start]
|
|
261
|
+
base = @map || ids
|
|
262
|
+
@filters = [[column, '']]
|
|
263
|
+
@map = base.select{ |id| check id }
|
|
264
|
+
@start = 0
|
|
265
|
+
show
|
|
266
|
+
draw_hints
|
|
267
|
+
result = Typr.read_line '/', left: left, top: self.bottom + 1,
|
|
268
|
+
&->(key, query, _) {
|
|
269
|
+
if key.is_a?(String) and idx = @hints[0..height-@hints_start-1].index(key)
|
|
270
|
+
return page.to_a[idx + @hints_start]
|
|
271
|
+
end
|
|
272
|
+
if key.is_a?(String) and !key.each_char.all?{ |c| c.ord.between?(32, 126) } and
|
|
273
|
+
@keymap.values.include?(key) and ![KEY_BACKSPACE, "\b"].include?(key)
|
|
274
|
+
send key
|
|
275
|
+
else
|
|
276
|
+
@filters = [[column, query]]
|
|
277
|
+
@map = base.select{ |id| check id }
|
|
278
|
+
@start = 0
|
|
279
|
+
end
|
|
280
|
+
show
|
|
281
|
+
draw_hints
|
|
282
|
+
nil
|
|
283
|
+
}
|
|
284
|
+
case result
|
|
285
|
+
when nil; @filters, @map, @start = saved
|
|
286
|
+
when Integer; return result
|
|
287
|
+
else
|
|
288
|
+
@filters = result.empty? ? saved[0] : saved[0] + [[column, result]]
|
|
289
|
+
filter :all
|
|
290
|
+
end
|
|
291
|
+
return
|
|
292
|
+
end
|
|
293
|
+
|
|
240
294
|
##
|
|
241
295
|
# Sort by column (toggle direction on repeat).
|
|
242
296
|
#
|
|
@@ -260,8 +314,9 @@ module Typr
|
|
|
260
314
|
def sort
|
|
261
315
|
return false unless @sort
|
|
262
316
|
data = (@procs[@sort] and not @rawsort[@sort]) ? @layer : @data
|
|
263
|
-
@map =
|
|
317
|
+
@map = (0...@data.size).to_a.sort{ |a,b| (data[a][@sort] <=> data[b][@sort]) || 0 }
|
|
264
318
|
@map.reverse! if @reverse
|
|
319
|
+
@map = @map.select{ |id| check id } unless @filters.empty?
|
|
265
320
|
return
|
|
266
321
|
end
|
|
267
322
|
|
|
@@ -293,11 +348,11 @@ module Typr
|
|
|
293
348
|
##
|
|
294
349
|
# Compute column widths from visible data and render the grid.
|
|
295
350
|
#
|
|
296
|
-
# grid.
|
|
351
|
+
# grid.show
|
|
297
352
|
#
|
|
298
353
|
# @return [void]
|
|
299
354
|
|
|
300
|
-
def
|
|
355
|
+
def show
|
|
301
356
|
if not @data or @data.empty? or ( @map and @map.empty? )
|
|
302
357
|
@widths = [ width/columns ] * columns if @widths.count < columns
|
|
303
358
|
@rest = 0
|
|
@@ -349,20 +404,20 @@ module Typr
|
|
|
349
404
|
def print row=nil
|
|
350
405
|
return super unless row
|
|
351
406
|
header = ( row == :header )
|
|
352
|
-
return
|
|
407
|
+
return draw @header[0..width-1].ljust(width) if
|
|
353
408
|
header and @header.is_a? String
|
|
354
409
|
fields = (header ? @header : @data[row] ).dup
|
|
355
410
|
@layer[row].each{ |col,value| fields[col] = value } if
|
|
356
411
|
@layer[row] if @layer unless header
|
|
357
412
|
for col,id in sequence.each_with_index
|
|
358
|
-
|
|
413
|
+
draw @separator unless id == 0
|
|
359
414
|
select = ( @selected[:columns].include? col or
|
|
360
415
|
@selected[:fields].include? [row,col] ) unless
|
|
361
416
|
@selected[:rows].include?(row) or header
|
|
362
417
|
color( @colors[:fields][[row,col]] ||
|
|
363
418
|
@colors[:columns][col] || @colors[:default] ) unless header
|
|
364
419
|
background @colors[:selected] if select
|
|
365
|
-
|
|
420
|
+
draw prepare( fields[col].to_s, width_for( id ), @align[col] )
|
|
366
421
|
background @colors[:default][1] if select
|
|
367
422
|
end
|
|
368
423
|
end
|
|
@@ -406,7 +461,7 @@ module Typr
|
|
|
406
461
|
@colors = { columns: [], fields: {} }.merge ( @colors )
|
|
407
462
|
@selected = { fields:[], columns:[] }.merge @selected
|
|
408
463
|
@functions = {
|
|
409
|
-
filetree: Proc.new{ |f| f.
|
|
464
|
+
filetree: Proc.new{ |f| ' ' * [(d = f.count('/') - 1), 0].max + '└' + File.basename(f) },
|
|
410
465
|
datetime: Proc.new{|sec|Time.at(sec).strftime"%y-%m-%d %H:%M" rescue ??},
|
|
411
466
|
magnitudes: Proc.new{ |size| mag = (size.to_s.length-1) / 3
|
|
412
467
|
mag>0 ? (size.to_s.insert -(mag*3+1), ?.)[0..4] + %w[B K M G T][mag] :
|
data/lib/line.rb
CHANGED
|
@@ -7,36 +7,36 @@ module Typr
|
|
|
7
7
|
# == Example
|
|
8
8
|
#
|
|
9
9
|
# line = Line.new( top: 5, left: 10, width: 40 )
|
|
10
|
-
# line.
|
|
10
|
+
# line.show "Hello world"
|
|
11
11
|
# line.append " more"
|
|
12
|
-
# line.ask([ ["Name?", :
|
|
12
|
+
# line.ask([ ["Name?", :line], ["Age?", :line] ])
|
|
13
13
|
|
|
14
14
|
class Line < Space
|
|
15
|
-
attr_accessor :default, :prompt, :bindings, :data
|
|
15
|
+
attr_accessor :default, :prompt, :bindings, :data, :align, :trim
|
|
16
16
|
|
|
17
17
|
# Render +msg+ (String, Proc, or Space) on this line.
|
|
18
18
|
#
|
|
19
|
-
# line.
|
|
20
|
-
# line.
|
|
19
|
+
# line.show "status: ok"
|
|
20
|
+
# line.show Proc.new { show_time }
|
|
21
21
|
|
|
22
|
-
def
|
|
22
|
+
def show msg=@data, align=@align
|
|
23
23
|
@data = msg
|
|
24
24
|
move left, top
|
|
25
25
|
color @colors[:default]
|
|
26
26
|
case msg
|
|
27
27
|
when Proc; msg.call
|
|
28
|
-
when Space; msg.
|
|
29
|
-
when String;
|
|
28
|
+
when Space; msg.show
|
|
29
|
+
when String; draw( prepare msg, width, align, @trim )
|
|
30
30
|
end
|
|
31
31
|
end
|
|
32
32
|
|
|
33
33
|
# Append +str+ to the current content and redraw.
|
|
34
34
|
#
|
|
35
|
-
# line.
|
|
35
|
+
# line.show "hello"
|
|
36
36
|
# line.append " world" #=> "hello world"
|
|
37
37
|
# line << "!" #=> "hello world!"
|
|
38
38
|
|
|
39
|
-
def append(str);
|
|
39
|
+
def append(str); show @data+str end
|
|
40
40
|
alias :<< :append
|
|
41
41
|
|
|
42
42
|
# Display keybinding help in a floating grid.
|
|
@@ -56,38 +56,68 @@ class Line < Space
|
|
|
56
56
|
#
|
|
57
57
|
# line.reset
|
|
58
58
|
|
|
59
|
-
def reset;
|
|
59
|
+
def reset; show( @default || ( @bindings || [@prompt] ).join(' ') ) end
|
|
60
60
|
|
|
61
61
|
# Prompt the user with a sequence of questions.
|
|
62
|
-
# +sentence+ is an array of [question, type] pairs.
|
|
63
|
-
# Returns a single answer or an array when multiple questions.
|
|
62
|
+
# +sentence+ is an array of [question, type] pairs (or a hash of them).
|
|
63
|
+
# Returns a single answer, or an array when there are multiple questions.
|
|
64
64
|
#
|
|
65
|
-
#
|
|
66
|
-
#
|
|
65
|
+
# The +type+ selects how the answer is collected:
|
|
66
|
+
# Array - interactive pick via <widget>.pick(<type>); an optional third
|
|
67
|
+
# element renders the chosen row's field into the line
|
|
68
|
+
# :key - a single keypress via Typr.read_key
|
|
69
|
+
# :line - interactive line editor via Typr.read_line at the cursor
|
|
70
|
+
#
|
|
71
|
+
# Pressing the exit key (@keymap[:exit], Escape by default) aborts the
|
|
72
|
+
# remaining questions and returns nil.
|
|
73
|
+
#
|
|
74
|
+
# line.ask(name: :line) #=> "Alice"
|
|
75
|
+
# line.ask(keys: :key) #=> "a"
|
|
76
|
+
# line.ask(open: [grid, :row, :name]) #=> 2 (picked row id)
|
|
77
|
+
# line.ask([ ["Name?", :line], ["Ok?", :key] ]) #=> ["Alice", "a"]
|
|
67
78
|
|
|
68
79
|
def ask sentence
|
|
69
80
|
answer = []
|
|
70
81
|
move left, top
|
|
71
82
|
Typr.clear :line
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
83
|
+
saved = @trim
|
|
84
|
+
@trim = :left
|
|
85
|
+
begin
|
|
86
|
+
@data = @prompt.to_s
|
|
87
|
+
colored = color_code( @colors[:default] ).to_s + @data
|
|
88
|
+
move left, top
|
|
89
|
+
draw prepare( colored, width, @align, @trim )
|
|
90
|
+
for question, object in sentence
|
|
91
|
+
text = " " + question.to_s + " "
|
|
92
|
+
@data += text
|
|
93
|
+
colored += color_code( @colors[:question] ).to_s + text
|
|
94
|
+
move left, top
|
|
95
|
+
draw prepare( colored, width, @align, @trim )
|
|
96
|
+
color( @colors[:answer] )
|
|
97
|
+
case object
|
|
98
|
+
when Array then answer << object.first.pick( object[1] )
|
|
99
|
+
when :key then answer << Typr.read_key
|
|
100
|
+
when :line then answer << Typr.read_line( colored + color_code( @colors[:answer] ),
|
|
101
|
+
left: left, top: top )
|
|
102
|
+
end
|
|
103
|
+
return if !answer.last or answer.last == @keymap[:exit]
|
|
104
|
+
text = ( object.is_a?(Array) and object[2] ) ?
|
|
105
|
+
object.first.data[answer.last][object[2]].to_s : answer.last.to_s
|
|
106
|
+
@data += text
|
|
107
|
+
colored += color_code( @colors[:answer] ).to_s + text
|
|
108
|
+
move left, top
|
|
109
|
+
draw prepare( colored, width, @align, @trim )
|
|
81
110
|
end
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
append answer.last.to_s
|
|
111
|
+
ensure
|
|
112
|
+
@trim = saved
|
|
85
113
|
end
|
|
86
114
|
return ( answer.one? ? answer.first : answer )
|
|
87
115
|
end
|
|
88
116
|
|
|
89
117
|
def initialize args
|
|
90
118
|
@right= -1
|
|
119
|
+
@align = :left
|
|
120
|
+
@trim = :right
|
|
91
121
|
@prompt = ?>
|
|
92
122
|
super
|
|
93
123
|
@bottom = @top
|
data/lib/space.rb
CHANGED
|
@@ -10,7 +10,7 @@ module Typr
|
|
|
10
10
|
#
|
|
11
11
|
# @example
|
|
12
12
|
# box = Space.new(left: 0, top: 2, right: 0.5, bottom: -4, border: :round)
|
|
13
|
-
# box.
|
|
13
|
+
# box.show
|
|
14
14
|
|
|
15
15
|
class Space
|
|
16
16
|
include Typr
|
|
@@ -29,21 +29,36 @@ include Typr
|
|
|
29
29
|
STR
|
|
30
30
|
eval( method % ([name]*11) ) }
|
|
31
31
|
|
|
32
|
+
# Deep-convert String keys to Symbols so string-keyed config (e.g. YAML) is honored.
|
|
33
|
+
def symbolize obj
|
|
34
|
+
case obj
|
|
35
|
+
when Hash
|
|
36
|
+
obj.each_with_object({}) { |(k, v), h|
|
|
37
|
+
h[k.is_a?(String) ? k.to_sym : k] = symbolize(v) }
|
|
38
|
+
else obj end
|
|
39
|
+
end
|
|
40
|
+
|
|
32
41
|
attr_writer :left, :top, :right, :bottom
|
|
33
42
|
attr_accessor :margin, :colors, :interval, :borders
|
|
34
43
|
|
|
44
|
+
# Viewport width in cells (right - left + 1).
|
|
35
45
|
def width; right - left + 1 end
|
|
46
|
+
# Viewport height in cells (bottom - top + 1).
|
|
36
47
|
def height; bottom - top + 1 end
|
|
37
48
|
|
|
38
|
-
|
|
49
|
+
# Redraw every +interval+ seconds from a background thread.
|
|
50
|
+
def start; @updater = Thread.new{ loop{show; sleep @interval }} end
|
|
51
|
+
# Stop the background refresh thread.
|
|
39
52
|
def stop; @updater.terminate end
|
|
40
53
|
|
|
54
|
+
# Draw a border char at screen (x, y); skips nil and off-screen positions.
|
|
41
55
|
def draw_border x,y,char
|
|
42
|
-
|
|
56
|
+
draw move_code(x, y) + char unless not char or
|
|
43
57
|
x < 0 or x > Typr.width or y < 0 or y > Typr.height
|
|
44
58
|
end
|
|
45
59
|
|
|
46
|
-
|
|
60
|
+
# Draw the widget's border box (no-op when no borders are set).
|
|
61
|
+
def show
|
|
47
62
|
return if @borders.empty?
|
|
48
63
|
color @colors[:border]
|
|
49
64
|
draw_border(left - 1, top - 1, @borders[:top_left])
|
|
@@ -58,6 +73,8 @@ eval( method % ([name]*11) ) }
|
|
|
58
73
|
draw_border(right + 1, bottom + 1, @borders[:bottom_right])
|
|
59
74
|
end
|
|
60
75
|
|
|
76
|
+
# Set border style: :light/:heavy/:double/:round, a char repeated across
|
|
77
|
+
# the box, or nil for none.
|
|
61
78
|
def border=(border)
|
|
62
79
|
chars = case border
|
|
63
80
|
when Symbol
|
|
@@ -70,11 +87,14 @@ eval( method % ([name]*11) ) }
|
|
|
70
87
|
bottom_right ].map.with_index{ |part,id| [part.to_sym, chars[id]] }.to_h if chars
|
|
71
88
|
end
|
|
72
89
|
|
|
90
|
+
# Build a widget from boundary (left/top/right/bottom), border, margin,
|
|
91
|
+
# colors, interval, and keymap.
|
|
73
92
|
def initialize args={}
|
|
74
|
-
@max, @keymap, @colors, @margin = 0, {}, {}, '
|
|
93
|
+
@max, @keymap, @colors, @margin = 0, {}, {}, ' '
|
|
75
94
|
@left, @top, @interval, @borders = 0, 0, 1, {}
|
|
76
95
|
args.each{ |name, value|
|
|
77
96
|
instance_variable_set ?@ + name.to_s, value }
|
|
97
|
+
@colors = symbolize( @colors ) if @colors.is_a? Hash
|
|
78
98
|
@keymap = { exit: KEY_ESCAPE }.merge @keymap
|
|
79
99
|
@colors = { default: [:white, :black], border: [:white, :black] }.merge(@colors)
|
|
80
100
|
borders = @borders.dup
|
data/lib/stack.rb
CHANGED
|
@@ -38,6 +38,20 @@ module Typr
|
|
|
38
38
|
|
|
39
39
|
def headspace; @header ? 1 : 0 end
|
|
40
40
|
|
|
41
|
+
##
|
|
42
|
+
# Map a mouse click at 1-based terminal (row, col) to a data row id on
|
|
43
|
+
# the current page, or nil when the click lands outside the widget (border,
|
|
44
|
+
# header, margins). Row ids match what hint presses return from `pick`.
|
|
45
|
+
#
|
|
46
|
+
# stack.hit 3, 5 # => 0 (row 3, col 5 hits data row 0)
|
|
47
|
+
|
|
48
|
+
def hit row, col
|
|
49
|
+
return unless row and col
|
|
50
|
+
rel = row - 1 - top - headspace
|
|
51
|
+
return unless rel.between?(0, height - 1) and col.between?(left, right)
|
|
52
|
+
page.to_a[rel]
|
|
53
|
+
end
|
|
54
|
+
|
|
41
55
|
##
|
|
42
56
|
# The usable height after subtracting any header space.
|
|
43
57
|
#
|
|
@@ -50,7 +64,7 @@ module Typr
|
|
|
50
64
|
#
|
|
51
65
|
# stack.print 42 # renders a blank row
|
|
52
66
|
|
|
53
|
-
def print id;
|
|
67
|
+
def print id; draw " " * (width-@margin.size) end
|
|
54
68
|
|
|
55
69
|
##
|
|
56
70
|
# Resets widget state by one or more categories.
|
|
@@ -80,16 +94,16 @@ module Typr
|
|
|
80
94
|
if type.to_s[ /column/ ]
|
|
81
95
|
positions( row_id )[ @hints_start..-1 ].each_with_index{ |pos, idx|
|
|
82
96
|
move( left + pos, top + row_id )
|
|
83
|
-
|
|
97
|
+
draw @hints[idx] }
|
|
84
98
|
else
|
|
85
99
|
bottom = top + headspace + [height, rows].min - 1
|
|
86
100
|
(top + headspace..bottom).each{ |pos|
|
|
87
|
-
move( left, pos );
|
|
101
|
+
move( left, pos ); draw ' ' }
|
|
88
102
|
@hints.chars.each_with_index{ |char, idx|
|
|
89
103
|
pos = idx + @hints_start + headspace
|
|
90
104
|
break if top + pos > bottom
|
|
91
105
|
move( left, top + pos )
|
|
92
|
-
|
|
106
|
+
draw char }
|
|
93
107
|
end
|
|
94
108
|
end
|
|
95
109
|
|
|
@@ -100,11 +114,11 @@ module Typr
|
|
|
100
114
|
# This method is called by your application's main loop each frame; it does not handle
|
|
101
115
|
# events itself (see {#send}).
|
|
102
116
|
|
|
103
|
-
def
|
|
117
|
+
def show
|
|
104
118
|
if @header
|
|
105
119
|
color @colors[ :header ]
|
|
106
120
|
move left,top
|
|
107
|
-
|
|
121
|
+
draw @margin
|
|
108
122
|
print :header
|
|
109
123
|
end
|
|
110
124
|
list = page.to_a
|
|
@@ -116,7 +130,7 @@ module Typr
|
|
|
116
130
|
dark=!dark if @alternate
|
|
117
131
|
background ( select ? @colors[:selected] :
|
|
118
132
|
(@alternate and dark) ? @colors[:alternate] : @colors[:default][1] )
|
|
119
|
-
|
|
133
|
+
draw @margin
|
|
120
134
|
print id
|
|
121
135
|
background if select
|
|
122
136
|
end
|
|
@@ -193,6 +207,8 @@ module Typr
|
|
|
193
207
|
# stack.pick # single row picker
|
|
194
208
|
# stack.pick :column, 3 # pick a column in row 3
|
|
195
209
|
# stack.pick "rows" # multi-select rows
|
|
210
|
+
#
|
|
211
|
+
# Mouse: left-click a row to pick it; wheel up/down scrolls the page.
|
|
196
212
|
|
|
197
213
|
def pick type = :row, row=0 #, key=nil
|
|
198
214
|
type = type.to_s
|
|
@@ -203,11 +219,19 @@ module Typr
|
|
|
203
219
|
column = pick( :column, page.to_a.index( row + headspace)) or return
|
|
204
220
|
value = [ row , column ]
|
|
205
221
|
else
|
|
206
|
-
|
|
222
|
+
show
|
|
207
223
|
draw_hints type, row unless type['none']
|
|
208
224
|
limit = type['row'] ? height : positions(row).count
|
|
209
|
-
key = Typr.
|
|
210
|
-
if key.is_a?(
|
|
225
|
+
key = Typr.read_key
|
|
226
|
+
if key.is_a?(Typr::Mouse)
|
|
227
|
+
if key.wheel? and key.press?
|
|
228
|
+
send( key.wheel_up? ? @keymap[:up] : @keymap[:down] )
|
|
229
|
+
next
|
|
230
|
+
elsif key.press? and key.left? and type['row'] and
|
|
231
|
+
value = hit( key.y, key.x )
|
|
232
|
+
relative = value if type['relative_']
|
|
233
|
+
end
|
|
234
|
+
elsif key.is_a?(String) and value =
|
|
211
235
|
@hints[0..limit-@hints_start-1].index(key)
|
|
212
236
|
value += @hints_start
|
|
213
237
|
relative = value + @start if type['relative_']
|