typr 1.1.2 → 1.2.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 +70 -0
- data/README.md +9 -9
- data/example/grid +4 -4
- data/example/text +7 -4
- data/example/top500.csv +1 -0
- data/lib/browser.rb +104 -74
- data/lib/curses.rb +48 -77
- data/lib/frontend.rb +10 -20
- data/lib/graphical.rb +39 -92
- data/lib/grid.rb +76 -29
- data/lib/line.rb +57 -27
- data/lib/space.rb +14 -5
- data/lib/stack.rb +18 -19
- data/lib/terminal.rb +249 -169
- data/lib/text.rb +118 -14
- data/lib/typr.rb +5 -6
- data/share/mimetypes +1298 -1
- data/typr.gemspec +2 -2
- metadata +2 -7
- data/Gemfile +0 -10
data/lib/curses.rb
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
#!/usr/bin/ruby
|
|
2
|
-
|
|
3
1
|
require 'ncursesw'
|
|
4
2
|
require_relative 'frontend'
|
|
5
|
-
|
|
3
|
+
|
|
6
4
|
module Visuals
|
|
7
5
|
|
|
8
6
|
include Ncurses
|
|
@@ -11,142 +9,115 @@ module Visuals
|
|
|
11
9
|
KEY_TAB = 9
|
|
12
10
|
KEY_PAGEDOWN = KEY_NPAGE
|
|
13
11
|
KEY_PAGEUP = KEY_PPAGE
|
|
14
|
-
|
|
15
|
-
KEY_DELETE = KEY_DC
|
|
16
|
-
|
|
12
|
+
|
|
17
13
|
$colors = COLORS.keys
|
|
18
14
|
$pairs = []
|
|
19
|
-
# COLORS = %w[ black red green yellow blue magenta cyan white grey]
|
|
20
|
-
# KEY_TAB = 9
|
|
21
|
-
# HEIGHT,WIDTH = IO.console.winsize
|
|
22
15
|
|
|
23
|
-
%w[color pair].each{ |name| method = <<STR
|
|
24
|
-
def %s_for obj;
|
|
16
|
+
%w[color pair].each{ |name| method = <<STR
|
|
17
|
+
def %s_for obj;
|
|
25
18
|
if id = $%ss.index( obj ) then return id
|
|
26
19
|
else last = ( $%ss << obj.dup ).count - 1
|
|
27
|
-
Ncurses.init_%s( last, *obj )
|
|
20
|
+
Ncurses.init_%s( last, *obj )
|
|
28
21
|
return last
|
|
29
22
|
end
|
|
30
23
|
end
|
|
31
24
|
STR
|
|
32
25
|
eval( method % ([name]*4) )
|
|
33
26
|
}
|
|
34
|
-
|
|
27
|
+
|
|
35
28
|
def self.width; Ncurses.COLS end
|
|
36
29
|
def self.height; Ncurses.LINES end
|
|
37
|
-
def self.row; Ncurses.getcury $
|
|
38
|
-
def self.column; Ncurses.getcurx $
|
|
39
|
-
|
|
30
|
+
def self.row; Ncurses.getcury $screen end
|
|
31
|
+
def self.column; Ncurses.getcurx $screen end
|
|
32
|
+
|
|
40
33
|
def self.exit
|
|
41
34
|
Ncurses.echo
|
|
42
35
|
Ncurses.nocbreak
|
|
43
36
|
Ncurses.nl
|
|
44
37
|
Ncurses.endwin
|
|
45
|
-
# system "reset"
|
|
46
38
|
end
|
|
47
39
|
|
|
48
|
-
def read input
|
|
40
|
+
def read input
|
|
49
41
|
case input
|
|
50
42
|
when :key
|
|
51
|
-
key = Ncurses.getch
|
|
52
|
-
key = key.chr if key.between? 32, 126
|
|
43
|
+
key = Ncurses.getch
|
|
44
|
+
key = key.chr if key.between? 32, 126
|
|
53
45
|
return key
|
|
54
|
-
when :line
|
|
55
|
-
|
|
56
|
-
Ncurses.
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
46
|
+
when :line
|
|
47
|
+
str = ''
|
|
48
|
+
until (key = Ncurses.getch) == KEY_RETURN
|
|
49
|
+
return nil if key == KEY_ESCAPE
|
|
50
|
+
if [KEY_BACKSPACE, 127, 8].include? key
|
|
51
|
+
str.chop!
|
|
52
|
+
else
|
|
53
|
+
str << key.chr if key.between? 32, 126
|
|
54
|
+
end
|
|
55
|
+
end
|
|
61
56
|
return str
|
|
62
57
|
end
|
|
63
58
|
end
|
|
64
59
|
|
|
65
60
|
def move x=0,y=0; Ncurses.move y, x end
|
|
66
61
|
def refresh; Ncurses.refresh end
|
|
67
|
-
def
|
|
68
|
-
|
|
69
|
-
def clear type=:screen;
|
|
70
|
-
case type
|
|
62
|
+
def clear type=:screen;
|
|
63
|
+
case type
|
|
71
64
|
when :screen; Ncurses.erase
|
|
72
65
|
when :line; Ncurses.clrtoeol
|
|
73
66
|
when :down; Ncurses.clrtobot
|
|
74
|
-
end
|
|
67
|
+
end
|
|
75
68
|
end
|
|
76
69
|
def change; Ncurses.color_set pair_for( $color ), 0 end
|
|
77
|
-
def
|
|
70
|
+
def draw string; Ncurses.addstr string.to_s end
|
|
78
71
|
|
|
79
72
|
def get_background; $color[1] end
|
|
80
73
|
def get_foreground; $color[0] end
|
|
81
|
-
def background color;
|
|
82
|
-
$color[1] = (color ? color_for( color ) : $default[1]); change
|
|
74
|
+
def background color;
|
|
75
|
+
$color[1] = (color ? color_for( color ) : $default[1]); change
|
|
83
76
|
end
|
|
84
|
-
def foreground color;
|
|
85
|
-
$color[0] = (color ? color_for( color ) : $default[0]); change
|
|
77
|
+
def foreground color;
|
|
78
|
+
$color[0] = (color ? color_for( color ) : $default[0]); change
|
|
86
79
|
end
|
|
87
80
|
|
|
88
81
|
def color c
|
|
89
82
|
c = [c] unless c.is_a? Array and c.count == 2
|
|
90
|
-
foreground c[0] if c[0]
|
|
91
|
-
background c[1] if c[1]
|
|
83
|
+
foreground c[0] if c[0]
|
|
84
|
+
background c[1] if c[1]
|
|
92
85
|
end
|
|
93
86
|
|
|
94
|
-
|
|
95
|
-
# if id = $color_pairs.index( pair ) return id
|
|
96
|
-
# else last = ( $color_pairs << c ).count - 1
|
|
97
|
-
# Ncurses.init_pair( last, *pair )
|
|
98
|
-
# return last
|
|
99
|
-
# end
|
|
100
|
-
# pair = p.map{ |col|
|
|
101
|
-
# unless id = $colors.index( col )
|
|
102
|
-
# id = ($colors << col).count - 1
|
|
103
|
-
# Ncurses.init_color id, *col
|
|
104
|
-
# end
|
|
105
|
-
# id
|
|
106
|
-
# }
|
|
107
|
-
# unless ( id = $color_pairs.index( pair ) )
|
|
108
|
-
# id = ( $color_pairs << pair ).count - 1
|
|
109
|
-
# Ncurses.init_pair id, *pair
|
|
110
|
-
# end
|
|
111
|
-
# id
|
|
112
|
-
# end
|
|
113
|
-
|
|
114
|
-
def self.init args={}
|
|
115
|
-
# SCREEN = Ncurses.initscr
|
|
87
|
+
def self.init args={}
|
|
116
88
|
$creen = Ncurses.initscr
|
|
117
|
-
Ncurses.cbreak
|
|
118
|
-
Ncurses.noecho
|
|
119
|
-
Ncurses.nl
|
|
120
|
-
# Ncurses.nonl # turn off newline translation
|
|
89
|
+
Ncurses.cbreak
|
|
90
|
+
Ncurses.noecho
|
|
91
|
+
Ncurses.nl
|
|
121
92
|
Ncurses.curs_set 0
|
|
122
93
|
Ncurses.start_color
|
|
123
|
-
Ncurses.stdscr.intrflush(false)
|
|
124
|
-
Ncurses.stdscr.keypad(true)
|
|
94
|
+
Ncurses.stdscr.intrflush(false)
|
|
95
|
+
Ncurses.stdscr.keypad(true)
|
|
125
96
|
|
|
126
|
-
$default = [
|
|
127
|
-
color_for( args[:foreground] || :grey80 ),
|
|
97
|
+
$default = [
|
|
98
|
+
color_for( args[:foreground] || :grey80 ),
|
|
128
99
|
color_for( args[:background] || :grey10 ) ]
|
|
129
100
|
$color = $default.dup
|
|
130
101
|
|
|
131
|
-
COLORS.each_with_index{ |c,i|
|
|
132
|
-
$pairs << [ i, $default[1] ]
|
|
133
|
-
Ncurses.init_color i, *c[1]
|
|
102
|
+
COLORS.each_with_index{ |c,i|
|
|
103
|
+
$pairs << [ i, $default[1] ]
|
|
104
|
+
Ncurses.init_color i, *c[1]
|
|
134
105
|
Ncurses.init_pair i, i, $default[1] }
|
|
135
|
-
|
|
106
|
+
|
|
136
107
|
Ncurses.bkgd Ncurses::COLOR_PAIR( pair_for $default )
|
|
137
108
|
|
|
138
|
-
end
|
|
109
|
+
end
|
|
139
110
|
|
|
140
111
|
end
|
|
141
112
|
|
|
142
113
|
if __FILE__ == $0
|
|
143
114
|
include Visuals
|
|
144
|
-
Visuals.init
|
|
115
|
+
Visuals.init
|
|
145
116
|
characters = (32..126).map(&:chr).join
|
|
146
117
|
loop do
|
|
147
118
|
clear
|
|
148
|
-
$colors.each_with_index{ |c,i|
|
|
149
|
-
foreground c; move 0,i;
|
|
119
|
+
$colors.each_with_index{ |c,i|
|
|
120
|
+
foreground c; move 0,i; draw characters }
|
|
150
121
|
refresh
|
|
151
122
|
exit if read(:key) == KEY_ESCAPE
|
|
152
123
|
end
|
data/lib/frontend.rb
CHANGED
|
@@ -1,19 +1,6 @@
|
|
|
1
|
-
require 'readline'
|
|
2
|
-
|
|
3
1
|
module Visuals
|
|
4
2
|
|
|
5
|
-
|
|
6
|
-
# black: [ 0, 0, 0],
|
|
7
|
-
# red: [ 700, 400, 400],
|
|
8
|
-
# green: [ 400, 700, 400],
|
|
9
|
-
# yellow: [ 700, 700, 400],
|
|
10
|
-
# blue: [ 400, 400, 700],
|
|
11
|
-
# magenta: [ 700, 400, 700],
|
|
12
|
-
# cyan: [ 400, 700, 700],
|
|
13
|
-
# white: [ 999, 999, 999],
|
|
14
|
-
# grey: [ 618, 618, 618] }
|
|
15
|
-
|
|
16
|
-
COLORS = {
|
|
3
|
+
COLORS = {
|
|
17
4
|
black: [ 0, 0, 0],
|
|
18
5
|
red: [ 180, 100, 100],
|
|
19
6
|
green: [ 100, 180, 100],
|
|
@@ -22,12 +9,15 @@ module Visuals
|
|
|
22
9
|
magenta: [ 180, 100, 180],
|
|
23
10
|
cyan: [ 100, 180, 180],
|
|
24
11
|
white: [ 255, 255, 255],
|
|
25
|
-
grey: [ 158, 158, 158]
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
[
|
|
12
|
+
grey: [ 158, 158, 158],
|
|
13
|
+
dark_red: [ 90, 30, 30],
|
|
14
|
+
dark_green: [ 30, 90, 30],
|
|
15
|
+
dark_yellow: [ 90, 80, 30],
|
|
16
|
+
dark_blue: [ 30, 30, 90],
|
|
17
|
+
dark_magenta: [ 90, 30, 90],
|
|
18
|
+
dark_cyan: [ 30, 80, 80] }
|
|
29
19
|
|
|
30
|
-
|
|
31
|
-
|
|
20
|
+
COLORS.merge! 1.upto(9).map{ |i|
|
|
21
|
+
["grey#{ i*10 }".to_sym, [i*25]*3 ] }.to_h
|
|
32
22
|
|
|
33
23
|
end
|
data/lib/graphical.rb
CHANGED
|
@@ -1,22 +1,16 @@
|
|
|
1
|
-
#!/usr/bin/ruby
|
|
2
1
|
require 'sdl2'
|
|
3
|
-
#require 'io/console'
|
|
4
|
-
#require 'readline'
|
|
5
2
|
require_relative 'frontend'
|
|
6
|
-
|
|
3
|
+
|
|
7
4
|
module Visuals
|
|
8
5
|
include SDL2
|
|
9
6
|
|
|
10
|
-
public
|
|
11
|
-
i=-1
|
|
12
|
-
# SDL2.init(SDL2::INIT_EVERYTHING)
|
|
13
7
|
SDL2.init(SDL2::INIT_VIDEO)
|
|
14
8
|
TTF.init
|
|
15
|
-
WINDOW = Window.create("visuals",
|
|
16
|
-
Window::POS_CENTERED,
|
|
17
|
-
Window::POS_CENTERED,
|
|
9
|
+
WINDOW = Window.create("visuals",
|
|
10
|
+
Window::POS_CENTERED,
|
|
11
|
+
Window::POS_CENTERED,
|
|
18
12
|
1324, 768, 0)
|
|
19
|
-
GO = WINDOW.create_renderer(-1,
|
|
13
|
+
GO = WINDOW.create_renderer(-1,
|
|
20
14
|
Renderer::Flags::ACCELERATED|Renderer::Flags::TARGETTEXTURE)
|
|
21
15
|
Key.constants.each{ |c| c = c.to_s
|
|
22
16
|
eval 'KEY_'+c.upcase+'=Key::'+c }
|
|
@@ -27,8 +21,7 @@ public
|
|
|
27
21
|
def self.column; $col end
|
|
28
22
|
def self.x; $x end
|
|
29
23
|
def self.y; $y end
|
|
30
|
-
|
|
31
|
-
|
|
24
|
+
|
|
32
25
|
def color_for c
|
|
33
26
|
return unless c
|
|
34
27
|
c = COLORS[c] if c.is_a?( Symbol )
|
|
@@ -39,136 +32,90 @@ public
|
|
|
39
32
|
def get_foreground; $color[0] end
|
|
40
33
|
def background color; return unless color
|
|
41
34
|
$color[1] = color_for( color ) end
|
|
42
|
-
def foreground color;
|
|
35
|
+
def foreground color;
|
|
43
36
|
$color[0] = (color ? color_for( color ) : $default[0]) end
|
|
44
37
|
|
|
45
|
-
def color c
|
|
46
|
-
c = [c] unless c.is_a? Array and c.count == 2
|
|
38
|
+
def color c
|
|
39
|
+
c = [c] unless c.is_a? Array and c.count == 2
|
|
47
40
|
foreground c[0]
|
|
48
41
|
background c[1]
|
|
49
|
-
# $letters[c] = (32.upto 126).map{ |n| n = n.chr
|
|
50
|
-
# [n, $font.render_blended( n, c )] }.to_h unless $letters[c]
|
|
51
42
|
end
|
|
52
43
|
|
|
53
44
|
def move col, row
|
|
54
|
-
$x = ($col = col) * $charsize[1]
|
|
55
|
-
$y = ($row = row) * $charsize[0]
|
|
45
|
+
$x = ($col = col) * $charsize[1]
|
|
46
|
+
$y = ($row = row) * $charsize[0]
|
|
56
47
|
end
|
|
57
48
|
|
|
58
|
-
def clear type = :screen
|
|
59
|
-
GO.draw_color = $default[1]
|
|
60
|
-
case type
|
|
61
|
-
|
|
62
|
-
when :screen; GO.fill_rect Rect.new(0, 0, *WINDOW.size)
|
|
49
|
+
def clear type = :screen
|
|
50
|
+
GO.draw_color = $default[1]
|
|
51
|
+
case type
|
|
52
|
+
when :screen; GO.fill_rect Rect.new(0, 0, *WINDOW.size)
|
|
63
53
|
when :line; GO.fill_rect Rect.new(
|
|
64
54
|
Visuals.x, Visuals.y, WINDOW.size[0], Visuals.y+$charsize[0])
|
|
65
55
|
when :down; GO.fill_rect Rect.new(
|
|
66
56
|
0, Visuals.y, *WINDOW.size)
|
|
67
57
|
end
|
|
68
58
|
end
|
|
69
|
-
|
|
70
|
-
def
|
|
59
|
+
|
|
60
|
+
def draw( str )
|
|
71
61
|
return unless str
|
|
72
|
-
# chars = str.chars.map{ |char| $letters[foreground][char] }
|
|
73
|
-
# width = chars.map( &:w ).sum
|
|
74
|
-
# if $color[1] != $default[1] #get_background
|
|
75
62
|
if get_background
|
|
76
63
|
GO.draw_color = get_background
|
|
77
|
-
GO.fill_rect Rect.new($x, $y, str.size*$charsize[1], $charsize[0])
|
|
64
|
+
GO.fill_rect Rect.new($x, $y, str.size*$charsize[1], $charsize[0])
|
|
78
65
|
end
|
|
79
|
-
# GO.fill_rect Rect.new($x, $y, width, $charsize[0])
|
|
80
|
-
# text = Surface.new( width, $charsize[0], 32, 0, 0, 0, 0 )
|
|
81
|
-
# x=0
|
|
82
|
-
# for char in chars #.each{|c|
|
|
83
|
-
# Surface.blit char, nil, text, Rect.new( x, 0, char.w, char.h )
|
|
84
|
-
# x += char.w
|
|
85
|
-
# end
|
|
86
|
-
# GO.copy GO.create_texture_from(text),nil,Rect.new($x, $y, width, $charsize[0])
|
|
87
66
|
text = str.rstrip
|
|
88
67
|
unless text.empty?
|
|
89
68
|
image = $font.render_blended( text, get_foreground )
|
|
90
69
|
GO.copy GO.create_texture_from( image ), nil,
|
|
91
|
-
Rect.new($x, $y, image.w, $charsize[0])
|
|
92
|
-
end
|
|
70
|
+
Rect.new($x, $y, image.w, $charsize[0])
|
|
71
|
+
end
|
|
93
72
|
move $col+str.size, $row
|
|
94
73
|
end
|
|
95
74
|
|
|
96
75
|
def refresh; GO.present end
|
|
97
76
|
|
|
98
|
-
def read input
|
|
77
|
+
def read input
|
|
99
78
|
case input
|
|
100
79
|
when :event then e = Event.poll until e
|
|
101
|
-
when :key then
|
|
80
|
+
when :key then
|
|
102
81
|
e = Event.poll until e.is_a? Event::KeyDown
|
|
103
|
-
return e.sym.between?(32, 126) ? e.sym.chr : e.sym
|
|
104
|
-
when :line
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
loop do
|
|
114
|
-
move x, y
|
|
115
|
-
show line
|
|
116
|
-
sleep 0.1
|
|
117
|
-
end
|
|
118
|
-
}
|
|
119
|
-
line = Readline.readline
|
|
120
|
-
listen.terminate
|
|
121
|
-
# until input.string[-1]==$/
|
|
122
|
-
return line
|
|
123
|
-
# until (key = read :key) == KEY_RETURN
|
|
124
|
-
# str << key if key.is_a? String
|
|
125
|
-
# end
|
|
126
|
-
#
|
|
127
|
-
# text = ""
|
|
128
|
-
# TextInput.start
|
|
129
|
-
# loop do
|
|
130
|
-
## ev = Event.poll
|
|
131
|
-
# case ev = read( :event )
|
|
132
|
-
# when Event::KeyDown
|
|
133
|
-
# if ev.sym == KEY_RETURN
|
|
134
|
-
# TextInput.stop
|
|
135
|
-
# return text
|
|
136
|
-
# end
|
|
137
|
-
# when Event::TextInput
|
|
138
|
-
# text += ev.text
|
|
139
|
-
# show ev.text
|
|
140
|
-
# p ev.text
|
|
141
|
-
# end
|
|
142
|
-
# end
|
|
82
|
+
return e.sym.between?(32, 126) ? e.sym.chr : e.sym
|
|
83
|
+
when :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
|
|
143
92
|
end
|
|
144
93
|
end
|
|
145
94
|
|
|
146
95
|
def self.exit
|
|
147
96
|
end
|
|
148
97
|
|
|
149
|
-
def self.init args={}
|
|
150
|
-
$default = [
|
|
151
|
-
color_for( args[:foreground] || :grey80 ),
|
|
98
|
+
def self.init args={}
|
|
99
|
+
$default = [
|
|
100
|
+
color_for( args[:foreground] || :grey80 ),
|
|
152
101
|
color_for( args[:background] || :grey10 ) ]
|
|
153
102
|
$color = $default.dup
|
|
154
103
|
$charsize = args[:charsize] || [18,11]
|
|
155
104
|
$font = TTF.open( args[:font] || "/usr/share/fonts/X11/TTF/VeraMono.ttf", $charsize[0] )
|
|
156
105
|
move 0, 0
|
|
157
106
|
end
|
|
158
|
-
|
|
107
|
+
|
|
159
108
|
end
|
|
160
109
|
|
|
161
110
|
if __FILE__ == $0
|
|
162
|
-
# require_relative 'base'
|
|
163
111
|
include Visuals
|
|
164
|
-
Visuals.init font:ARGV[0]
|
|
112
|
+
Visuals.init font:ARGV[0]
|
|
165
113
|
characters = (32..126).map(&:chr).join
|
|
166
114
|
loop do
|
|
167
115
|
clear
|
|
168
|
-
COLORS.keys.each_with_index{ |c,i|
|
|
169
|
-
foreground c; move 0,i;
|
|
116
|
+
COLORS.keys.each_with_index{ |c,i|
|
|
117
|
+
foreground c; move 0,i; draw characters }
|
|
170
118
|
refresh
|
|
171
|
-
# GO.present
|
|
172
119
|
exit if read(:key) == KEY_ESCAPE
|
|
173
120
|
end
|
|
174
121
|
end
|
data/lib/grid.rb
CHANGED
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
|
-
# coding: utf-8
|
|
3
|
-
# frozen_string_literal: true
|
|
4
|
-
|
|
5
1
|
require_relative 'space.rb'
|
|
6
2
|
|
|
7
3
|
module Typr
|
|
@@ -13,16 +9,16 @@ module Typr
|
|
|
13
9
|
# input: [ ["Alice", 30], ["Bob", 25] ],
|
|
14
10
|
# header: [:name, :age],
|
|
15
11
|
# format: [:max, :right]
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
12
|
+
# )
|
|
13
|
+
# grid.show
|
|
14
|
+
#
|
|
19
15
|
# Column format tokens: +Integer+ (fixed width), +:min+ (auto), +:max+ (fill remaining).
|
|
20
16
|
#
|
|
21
17
|
# Built-in procs: +:filetree+, +:datetime+, +:magnitudes+, +:convert+.
|
|
22
18
|
|
|
23
19
|
class Grid < Stack # Table
|
|
24
20
|
attr_accessor :format, :procs, :filters, :data, :map
|
|
25
|
-
attr_accessor :align, :rawsort, :rawfilter
|
|
21
|
+
attr_accessor :align, :rawsort, :rawfilter, :reverse
|
|
26
22
|
attr_writer :sequence
|
|
27
23
|
|
|
28
24
|
##
|
|
@@ -127,8 +123,9 @@ module Typr
|
|
|
127
123
|
# @param h [Array<String, Symbol>]
|
|
128
124
|
|
|
129
125
|
def header=( h ); super
|
|
130
|
-
h.each_with_index{ |h,i|
|
|
131
|
-
h.
|
|
126
|
+
h.each_with_index{ |h,i|
|
|
127
|
+
Typr.const_set(h.upcase, i) unless Typr.const_defined?(h.upcase)
|
|
128
|
+
} if h.is_a? Array
|
|
132
129
|
end
|
|
133
130
|
|
|
134
131
|
##
|
|
@@ -143,7 +140,7 @@ module Typr
|
|
|
143
140
|
def reset type=:all
|
|
144
141
|
case type
|
|
145
142
|
when :display; @map = nil; @sort = nil; @filters.clear
|
|
146
|
-
when :format; @widths.clear
|
|
143
|
+
when :format; @widths.clear
|
|
147
144
|
when :all; reset [:display, :format]
|
|
148
145
|
end
|
|
149
146
|
super
|
|
@@ -180,10 +177,11 @@ module Typr
|
|
|
180
177
|
end
|
|
181
178
|
|
|
182
179
|
##
|
|
183
|
-
# Add a column filter (substring or regex).
|
|
180
|
+
# Add a column filter (substring or regex). +:all+ matches any column.
|
|
184
181
|
#
|
|
185
182
|
# grid.add_filter(0, "Ali") # name contains "Ali"
|
|
186
183
|
# grid.add_filter(1, /^\d{2}$/) # age matches regex
|
|
184
|
+
# grid.add_filter(:all, "ip") # any column contains "ip"
|
|
187
185
|
#
|
|
188
186
|
# @param column [Integer, Symbol]
|
|
189
187
|
# @param query [String, Regexp]
|
|
@@ -205,8 +203,10 @@ module Typr
|
|
|
205
203
|
|
|
206
204
|
def check row
|
|
207
205
|
@filters.reject{ |column,query|
|
|
208
|
-
|
|
209
|
-
|
|
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?
|
|
210
210
|
end
|
|
211
211
|
|
|
212
212
|
##
|
|
@@ -240,6 +240,57 @@ module Typr
|
|
|
240
240
|
|
|
241
241
|
def sorted_by name=false; (name and @sort) ? @header[@sort] : @sort end
|
|
242
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
|
+
|
|
243
294
|
##
|
|
244
295
|
# Sort by column (toggle direction on repeat).
|
|
245
296
|
#
|
|
@@ -263,8 +314,9 @@ module Typr
|
|
|
263
314
|
def sort
|
|
264
315
|
return false unless @sort
|
|
265
316
|
data = (@procs[@sort] and not @rawsort[@sort]) ? @layer : @data
|
|
266
|
-
@map =
|
|
317
|
+
@map = (0...@data.size).to_a.sort{ |a,b| (data[a][@sort] <=> data[b][@sort]) || 0 }
|
|
267
318
|
@map.reverse! if @reverse
|
|
319
|
+
@map = @map.select{ |id| check id } unless @filters.empty?
|
|
268
320
|
return
|
|
269
321
|
end
|
|
270
322
|
|
|
@@ -296,11 +348,11 @@ module Typr
|
|
|
296
348
|
##
|
|
297
349
|
# Compute column widths from visible data and render the grid.
|
|
298
350
|
#
|
|
299
|
-
# grid.
|
|
351
|
+
# grid.show
|
|
300
352
|
#
|
|
301
353
|
# @return [void]
|
|
302
354
|
|
|
303
|
-
def
|
|
355
|
+
def show
|
|
304
356
|
if not @data or @data.empty? or ( @map and @map.empty? )
|
|
305
357
|
@widths = [ width/columns ] * columns if @widths.count < columns
|
|
306
358
|
@rest = 0
|
|
@@ -352,20 +404,20 @@ module Typr
|
|
|
352
404
|
def print row=nil
|
|
353
405
|
return super unless row
|
|
354
406
|
header = ( row == :header )
|
|
355
|
-
return
|
|
407
|
+
return draw @header[0..width-1].ljust(width) if
|
|
356
408
|
header and @header.is_a? String
|
|
357
409
|
fields = (header ? @header : @data[row] ).dup
|
|
358
410
|
@layer[row].each{ |col,value| fields[col] = value } if
|
|
359
411
|
@layer[row] if @layer unless header
|
|
360
412
|
for col,id in sequence.each_with_index
|
|
361
|
-
|
|
413
|
+
draw @separator unless id == 0
|
|
362
414
|
select = ( @selected[:columns].include? col or
|
|
363
415
|
@selected[:fields].include? [row,col] ) unless
|
|
364
416
|
@selected[:rows].include?(row) or header
|
|
365
417
|
color( @colors[:fields][[row,col]] ||
|
|
366
418
|
@colors[:columns][col] || @colors[:default] ) unless header
|
|
367
419
|
background @colors[:selected] if select
|
|
368
|
-
|
|
420
|
+
draw prepare( fields[col].to_s, width_for( id ), @align[col] )
|
|
369
421
|
background @colors[:default][1] if select
|
|
370
422
|
end
|
|
371
423
|
end
|
|
@@ -404,22 +456,17 @@ module Typr
|
|
|
404
456
|
@columns,@functions = 0,{}
|
|
405
457
|
@ignore,@rawfilter,@rawsort,@reverse = [],[],[],false
|
|
406
458
|
@filters,@procs = [],{}
|
|
407
|
-
@align,@format,@widths
|
|
408
|
-
super
|
|
459
|
+
@align,@format,@widths = [],[],[]
|
|
460
|
+
super
|
|
409
461
|
@colors = { columns: [], fields: {} }.merge ( @colors )
|
|
410
462
|
@selected = { fields:[], columns:[] }.merge @selected
|
|
411
463
|
@functions = {
|
|
412
|
-
filetree: Proc.new{ |f| f.
|
|
464
|
+
filetree: Proc.new{ |f| ' ' * [(d = f.count('/') - 1), 0].max + '└' + File.basename(f) },
|
|
413
465
|
datetime: Proc.new{|sec|Time.at(sec).strftime"%y-%m-%d %H:%M" rescue ??},
|
|
414
466
|
magnitudes: Proc.new{ |size| mag = (size.to_s.length-1) / 3
|
|
415
467
|
mag>0 ? (size.to_s.insert -(mag*3+1), ?.)[0..4] + %w[B K M G T][mag] :
|
|
416
468
|
size rescue size },
|
|
417
|
-
convert: Proc.new{ |value|
|
|
418
|
-
case value.to_s
|
|
419
|
-
when /^[\d]+$/ then value.to_s.to_i
|
|
420
|
-
when /^\d*[\.\,]\d+$/ then value.to_s.to_f
|
|
421
|
-
else value
|
|
422
|
-
end } }
|
|
469
|
+
convert: Proc.new{ |value| coerce_type value } }
|
|
423
470
|
|
|
424
471
|
if @input
|
|
425
472
|
self << @input
|