rfd 0.0.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 +7 -0
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/MIT-LICENSE +22 -0
- data/README.md +31 -0
- data/Rakefile +1 -0
- data/bin/rfd +5 -0
- data/lib/rfd.rb +456 -0
- data/lib/rfd/commands.rb +234 -0
- data/lib/rfd/item.rb +176 -0
- data/lib/rfd/windows.rb +227 -0
- data/rfd.gemspec +24 -0
- data/spec/controller_spec.rb +277 -0
- data/spec/spec_helper.rb +9 -0
- data/spec/support/capture_helper.rb +21 -0
- data/spec/testdir/.file1 +0 -0
- data/spec/testdir/.file2 +0 -0
- data/spec/testdir/.file3 +0 -0
- data/spec/testdir/.link1 +0 -0
- data/spec/testdir/file1 +1 -0
- data/spec/testdir/file2 +0 -0
- data/spec/testdir/file3 +0 -0
- data/spec/testdir/link1 +1 -0
- data/spec/testdir/link2 +0 -0
- metadata +137 -0
data/lib/rfd/commands.rb
ADDED
@@ -0,0 +1,234 @@
|
|
1
|
+
module Rfd
|
2
|
+
module Commands
|
3
|
+
# Change permission ("A"ttributes) of selected files and directories.
|
4
|
+
def a
|
5
|
+
process_command_line preset_command: 'chmod'
|
6
|
+
end
|
7
|
+
|
8
|
+
# "c"opy selected files and directories.
|
9
|
+
def c
|
10
|
+
process_command_line preset_command: 'cp'
|
11
|
+
end
|
12
|
+
|
13
|
+
# Soft "d"elete (actually mv to the trash folder) selected files and directories.
|
14
|
+
def d
|
15
|
+
if selected_items.any?
|
16
|
+
if ask %Q[Are your sure want to trash #{selected_items.one? ? selected_items.first.name : "these #{selected_items.size} files"}? (y/n)]
|
17
|
+
FileUtils.mv selected_items.map(&:path), File.expand_path('~/.Trash/')
|
18
|
+
@current_row -= selected_items.count {|i| i.index <= current_row}
|
19
|
+
ls
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# Open current file or directory with the "e"ditor
|
25
|
+
def e
|
26
|
+
edit
|
27
|
+
end
|
28
|
+
|
29
|
+
# "f"ind the first flie or directory of which name starts with the given String.
|
30
|
+
def f
|
31
|
+
process_command_line preset_command: 'find'
|
32
|
+
end
|
33
|
+
|
34
|
+
# Move the cursor to the left pane.
|
35
|
+
def h
|
36
|
+
(y = current_row - maxy) >= 0 and move_cursor y
|
37
|
+
end
|
38
|
+
|
39
|
+
# Move the cursor down.
|
40
|
+
def j
|
41
|
+
if current_row + 1 >= items.size
|
42
|
+
move_cursor 0
|
43
|
+
else
|
44
|
+
move_cursor current_row + 1
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# Move the cursor up.
|
49
|
+
def k
|
50
|
+
if current_row == 0
|
51
|
+
move_cursor items.size - 1
|
52
|
+
else
|
53
|
+
move_cursor current_row - 1
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# Move the cursor to the right pane.
|
58
|
+
def l
|
59
|
+
(y = current_row + maxy) < items.size and move_cursor y
|
60
|
+
end
|
61
|
+
|
62
|
+
# "m"ove selected files and directories.
|
63
|
+
def m
|
64
|
+
process_command_line preset_command: 'mv'
|
65
|
+
end
|
66
|
+
|
67
|
+
# "o"pen selected files and directories with the OS "open" command.
|
68
|
+
def o
|
69
|
+
system "open #{selected_items.map {|i| %Q["#{i.path}"]}.join(' ')}"
|
70
|
+
end
|
71
|
+
|
72
|
+
# "q"uit the app.
|
73
|
+
def q
|
74
|
+
raise StopIteration if ask 'Are your sure want to exit? (y/n)'
|
75
|
+
end
|
76
|
+
|
77
|
+
# "r"ename selected files and directories.
|
78
|
+
def r
|
79
|
+
process_command_line preset_command: 'rename'
|
80
|
+
end
|
81
|
+
|
82
|
+
# "s"ort displayed files and directories in the given order.
|
83
|
+
def s
|
84
|
+
process_command_line preset_command: 'sort'
|
85
|
+
end
|
86
|
+
|
87
|
+
# Create a new file, or update its timestamp if the file already exists ("t"ouch).
|
88
|
+
def t
|
89
|
+
process_command_line preset_command: 'touch'
|
90
|
+
end
|
91
|
+
|
92
|
+
# "o"pen selected files and directories with the viewer.
|
93
|
+
def v
|
94
|
+
view
|
95
|
+
end
|
96
|
+
|
97
|
+
# Hard "d"elete selected files and directories.
|
98
|
+
def D
|
99
|
+
if selected_items.any?
|
100
|
+
if ask %Q[Are your sure want to delete #{selected_items.one? ? selected_items.first.name : "these #{selected_items.size} files"}? (y/n)]
|
101
|
+
FileUtils.rm_rf selected_items.map(&:path)
|
102
|
+
@current_row -= selected_items.count {|i| i.index <= current_row}
|
103
|
+
ls
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
# "f"ind the last flie or directory of which name starts with the given String.
|
109
|
+
def F
|
110
|
+
process_command_line preset_command: 'find_reverse'
|
111
|
+
end
|
112
|
+
|
113
|
+
# Move the cursor to the top.
|
114
|
+
def H
|
115
|
+
move_cursor current_page * max_items
|
116
|
+
end
|
117
|
+
|
118
|
+
# Ma"K"e a directory.
|
119
|
+
def K
|
120
|
+
process_command_line preset_command: 'mkdir'
|
121
|
+
end
|
122
|
+
|
123
|
+
# Move the cursor to the bottom.
|
124
|
+
def L
|
125
|
+
move_cursor current_page * max_items + displayed_items.size - 1
|
126
|
+
end
|
127
|
+
|
128
|
+
# Move the cursor to the "M"iddle.
|
129
|
+
def M
|
130
|
+
move_cursor current_page * max_items + displayed_items.size / 2
|
131
|
+
end
|
132
|
+
|
133
|
+
# Mark or unmark "a"ll files and directories.
|
134
|
+
def ctrl_a
|
135
|
+
mark = marked_items.size != (items.size - 2) # exclude . and ..
|
136
|
+
items.each {|i| i.toggle_mark unless i.marked? == mark}
|
137
|
+
draw_items
|
138
|
+
move_cursor current_row
|
139
|
+
draw_marked_items
|
140
|
+
header_r.wrefresh
|
141
|
+
end
|
142
|
+
|
143
|
+
# "b"ack to the previous page.
|
144
|
+
def ctrl_b
|
145
|
+
ctrl_p
|
146
|
+
end
|
147
|
+
|
148
|
+
# "f"orward to the next page.
|
149
|
+
def ctrl_f
|
150
|
+
ctrl_n
|
151
|
+
end
|
152
|
+
|
153
|
+
# Refresh the screen.
|
154
|
+
def ctrl_l
|
155
|
+
ls
|
156
|
+
end
|
157
|
+
|
158
|
+
# Forward to the "n"ext page.
|
159
|
+
def ctrl_n
|
160
|
+
if total_pages > 1
|
161
|
+
if last_page?
|
162
|
+
move_cursor 0
|
163
|
+
else
|
164
|
+
move_cursor (current_page + 1) * max_items
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
# Back to the "p"revious page.
|
170
|
+
def ctrl_p
|
171
|
+
if total_pages > 1
|
172
|
+
if first_page?
|
173
|
+
move_cursor (total_pages - 1) * max_items
|
174
|
+
else
|
175
|
+
move_cursor (current_page - 1) * max_items
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
# Change the number of columns in the main window.
|
181
|
+
(?1..?9).each do |n|
|
182
|
+
define_method(n) do
|
183
|
+
spawn_panes n.to_i
|
184
|
+
ls
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
# Return to the previous directory (popd).
|
189
|
+
def -
|
190
|
+
popd
|
191
|
+
end
|
192
|
+
|
193
|
+
# Search files and directories from the current directory.
|
194
|
+
def /
|
195
|
+
process_command_line preset_command: 'grep'
|
196
|
+
end
|
197
|
+
|
198
|
+
# Execute a shell command in an external shell.
|
199
|
+
define_method('!') do
|
200
|
+
process_shell_command
|
201
|
+
end
|
202
|
+
|
203
|
+
# Execute a command in the controller context.
|
204
|
+
define_method(':') do
|
205
|
+
process_command_line
|
206
|
+
end
|
207
|
+
|
208
|
+
# cd into a directory, or view a file.
|
209
|
+
def enter
|
210
|
+
if current_item.directory?
|
211
|
+
cd current_item
|
212
|
+
ls
|
213
|
+
else
|
214
|
+
v
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
# Toggle mark, and move down.
|
219
|
+
def space
|
220
|
+
toggle_mark
|
221
|
+
j
|
222
|
+
draw_marked_items
|
223
|
+
header_r.wrefresh
|
224
|
+
end
|
225
|
+
|
226
|
+
# cd to the upper hierarchy.
|
227
|
+
def del
|
228
|
+
if current_dir != '/'
|
229
|
+
cd '..'
|
230
|
+
ls
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|
234
|
+
end
|
data/lib/rfd/item.rb
ADDED
@@ -0,0 +1,176 @@
|
|
1
|
+
module Rfd
|
2
|
+
class Item
|
3
|
+
include Comparable
|
4
|
+
attr_reader :name
|
5
|
+
attr_accessor :index
|
6
|
+
|
7
|
+
def initialize(dir: nil, name: nil, window_width: nil)
|
8
|
+
@dir, @name, @window_width, @marked = dir, name, window_width, false
|
9
|
+
end
|
10
|
+
|
11
|
+
def path
|
12
|
+
@path ||= File.join @dir, @name
|
13
|
+
end
|
14
|
+
|
15
|
+
def basename
|
16
|
+
@basename ||= File.basename name, extname
|
17
|
+
end
|
18
|
+
|
19
|
+
def extname
|
20
|
+
@extname ||= File.extname name
|
21
|
+
end
|
22
|
+
|
23
|
+
def full_display_name
|
24
|
+
n = @name.dup
|
25
|
+
n << " -> #{target}" if symlink?
|
26
|
+
n
|
27
|
+
end
|
28
|
+
|
29
|
+
def display_name
|
30
|
+
@display_name ||= begin
|
31
|
+
n = full_display_name
|
32
|
+
if mb_size(n) <= @window_width - 15
|
33
|
+
n
|
34
|
+
else
|
35
|
+
if symlink?
|
36
|
+
mb_left n, @window_width - 16
|
37
|
+
else
|
38
|
+
"#{mb_left(basename, @window_width - 16 - extname.length)}…#{extname}"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def lstat
|
45
|
+
@lstat ||= File.lstat path
|
46
|
+
end
|
47
|
+
|
48
|
+
def stat
|
49
|
+
@stat ||= File.stat path
|
50
|
+
end
|
51
|
+
|
52
|
+
def color
|
53
|
+
if symlink?
|
54
|
+
Curses::COLOR_MAGENTA
|
55
|
+
elsif hidden?
|
56
|
+
Curses::COLOR_GREEN
|
57
|
+
elsif directory?
|
58
|
+
Curses::COLOR_CYAN
|
59
|
+
elsif executable?
|
60
|
+
Curses::COLOR_RED
|
61
|
+
else
|
62
|
+
Curses::COLOR_WHITE
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def size
|
67
|
+
directory? ? 0 : lstat.size
|
68
|
+
end
|
69
|
+
|
70
|
+
def size_or_dir
|
71
|
+
directory? ? '<DIR>' : size.to_s
|
72
|
+
end
|
73
|
+
|
74
|
+
def atime
|
75
|
+
lstat.atime.strftime('%Y-%m-%d %H:%M:%S')
|
76
|
+
end
|
77
|
+
|
78
|
+
def ctime
|
79
|
+
lstat.ctime.strftime('%Y-%m-%d %H:%M:%S')
|
80
|
+
end
|
81
|
+
|
82
|
+
def mtime
|
83
|
+
lstat.mtime.strftime('%Y-%m-%d %H:%M:%S')
|
84
|
+
end
|
85
|
+
|
86
|
+
def mode
|
87
|
+
@mode ||= begin
|
88
|
+
m = lstat.mode
|
89
|
+
ret = directory? ? 'd' : symlink? ? 'l' : '-'
|
90
|
+
[(m & 0700) / 64, (m & 070) / 8, m & 07].inject(ret) do |str, s|
|
91
|
+
str << "#{s & 4 == 4 ? 'r' : '-'}#{s & 2 == 2 ? 'w' : '-'}#{s & 1 == 1 ? 'x' : '-'}"
|
92
|
+
end
|
93
|
+
if m & 04000 != 0
|
94
|
+
ret[3] = directory? ? 's' : 'S'
|
95
|
+
end
|
96
|
+
if m & 02000 != 0
|
97
|
+
ret[6] = directory? ? 's' : 'S'
|
98
|
+
end
|
99
|
+
if m & 01000 == 512
|
100
|
+
ret[-1] = directory? ? 't' : 'T'
|
101
|
+
end
|
102
|
+
ret
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def directory?
|
107
|
+
stat.directory?
|
108
|
+
end
|
109
|
+
|
110
|
+
def symlink?
|
111
|
+
lstat.symlink?
|
112
|
+
end
|
113
|
+
|
114
|
+
def hidden?
|
115
|
+
name.start_with?('.') && (name != '.') && (name != '..')
|
116
|
+
end
|
117
|
+
|
118
|
+
def executable?
|
119
|
+
lstat.executable?
|
120
|
+
end
|
121
|
+
|
122
|
+
def target
|
123
|
+
File.readlink path if symlink?
|
124
|
+
end
|
125
|
+
|
126
|
+
def toggle_mark
|
127
|
+
unless %w(. ..).include? name
|
128
|
+
@marked = !@marked
|
129
|
+
true
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
def marked?
|
134
|
+
@marked
|
135
|
+
end
|
136
|
+
|
137
|
+
def current_mark
|
138
|
+
marked? ? '*' : ' '
|
139
|
+
end
|
140
|
+
|
141
|
+
def mb_left(str, size)
|
142
|
+
len = 0
|
143
|
+
index = str.each_char.with_index do |c, i|
|
144
|
+
break i if len + mb_char_size(c) > size
|
145
|
+
len += mb_size c
|
146
|
+
end
|
147
|
+
str[0, index]
|
148
|
+
end
|
149
|
+
|
150
|
+
def mb_char_size(c)
|
151
|
+
c == '…' ? 1 : c.bytesize == 1 ? 1 : 2
|
152
|
+
end
|
153
|
+
|
154
|
+
def mb_size(str)
|
155
|
+
str.each_char.inject(0) {|l, c| l += mb_char_size(c)}
|
156
|
+
end
|
157
|
+
|
158
|
+
def mb_ljust(str, size)
|
159
|
+
"#{str}#{' ' * [0, size - mb_size(str)].max}"
|
160
|
+
end
|
161
|
+
|
162
|
+
def to_s
|
163
|
+
"#{current_mark}#{mb_ljust(display_name, @window_width - 15)}#{size_or_dir.rjust(13)}"
|
164
|
+
end
|
165
|
+
|
166
|
+
def <=>(o)
|
167
|
+
if directory? && !o.directory?
|
168
|
+
1
|
169
|
+
elsif !directory? && o.directory?
|
170
|
+
-1
|
171
|
+
else
|
172
|
+
name <=> o.name
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
data/lib/rfd/windows.rb
ADDED
@@ -0,0 +1,227 @@
|
|
1
|
+
module Rfd
|
2
|
+
class Window
|
3
|
+
attr_reader :window
|
4
|
+
|
5
|
+
def wmove(y, x = 0)
|
6
|
+
Curses.wmove window, y, x
|
7
|
+
end
|
8
|
+
|
9
|
+
def waddstr(str, clear_to_eol_before_add: false)
|
10
|
+
wclrtoeol if clear_to_eol_before_add
|
11
|
+
Curses.waddstr window, str
|
12
|
+
end
|
13
|
+
|
14
|
+
def mvwaddstr(y, x, str)
|
15
|
+
Curses.mvwaddstr window, y, x, str
|
16
|
+
end
|
17
|
+
|
18
|
+
def wclear
|
19
|
+
Curses.wclear window
|
20
|
+
end
|
21
|
+
|
22
|
+
def wrefresh
|
23
|
+
Curses.wrefresh window
|
24
|
+
end
|
25
|
+
|
26
|
+
def maxx
|
27
|
+
Curses.getmaxx window
|
28
|
+
end
|
29
|
+
|
30
|
+
def maxy
|
31
|
+
Curses.getmaxy window
|
32
|
+
end
|
33
|
+
|
34
|
+
def begx
|
35
|
+
Curses.getbegx window
|
36
|
+
end
|
37
|
+
|
38
|
+
def begy
|
39
|
+
Curses.getbegy window
|
40
|
+
end
|
41
|
+
|
42
|
+
def subwin(height, width, top, left)
|
43
|
+
Curses.derwin Curses.stdscr, height, width, top, left
|
44
|
+
end
|
45
|
+
|
46
|
+
def wclrtoeol
|
47
|
+
Curses.wclrtoeol window
|
48
|
+
end
|
49
|
+
|
50
|
+
def draw_border(*border_param)
|
51
|
+
border_window = subwin maxy + 2, maxx + 2, begy - 1, begx - 1
|
52
|
+
Curses.wbkgd border_window, Curses.COLOR_PAIR(Curses::COLOR_CYAN)
|
53
|
+
Curses.wborder border_window, *border_param
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
class HeaderLeftWindow < Window
|
58
|
+
def initialize
|
59
|
+
@window = subwin 3, Curses.COLS - 32, 1, 1
|
60
|
+
draw_border 0, 0, 0, 0, 0, 0, Curses::ACS_LTEE, 0
|
61
|
+
end
|
62
|
+
|
63
|
+
def draw_path_and_page_number(path: nil, current: 1, total: nil)
|
64
|
+
@path_and_page_number = %Q[Page: #{"#{current}/ #{total}".ljust(11)} Path: #{path}]
|
65
|
+
wmove 0
|
66
|
+
waddstr @path_and_page_number, clear_to_eol_before_add: true
|
67
|
+
wrefresh
|
68
|
+
end
|
69
|
+
|
70
|
+
def draw_current_file_info(current_file)
|
71
|
+
draw_current_filename current_file.full_display_name
|
72
|
+
draw_stat current_file
|
73
|
+
end
|
74
|
+
|
75
|
+
def draw_current_filename(current_file_name)
|
76
|
+
@current_file_name = "File: #{current_file_name}"
|
77
|
+
wmove 1
|
78
|
+
waddstr @current_file_name, clear_to_eol_before_add: true
|
79
|
+
end
|
80
|
+
|
81
|
+
def draw_stat(item)
|
82
|
+
@stat = " #{item.size_or_dir.ljust(13)}#{item.mtime} #{item.mode}"
|
83
|
+
wmove 2
|
84
|
+
waddstr @stat, clear_to_eol_before_add: true
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
class HeaderRightWindow < Window
|
89
|
+
def initialize
|
90
|
+
@window = subwin 3, 29, 1, Curses.COLS - 30
|
91
|
+
draw_border 0, 0, 0, 0, Curses::ACS_TTEE, 0, Curses::ACS_BTEE, Curses::ACS_RTEE
|
92
|
+
end
|
93
|
+
|
94
|
+
def draw_marked_items(count: 0, size: 0)
|
95
|
+
wmove 1
|
96
|
+
waddstr %Q[#{"#{count}Marked".rjust(11)} #{size.to_s.reverse.gsub( /(\d{3})(?=\d)/, '\1,').reverse.rjust(16)}], clear_to_eol_before_add: true
|
97
|
+
end
|
98
|
+
|
99
|
+
def draw_total_items(count: 0, size: 0)
|
100
|
+
wmove 2
|
101
|
+
waddstr %Q[#{"#{count}Files".rjust(10)} #{size.to_s.reverse.gsub( /(\d{3})(?=\d)/, '\1,').reverse.rjust(17)}], clear_to_eol_before_add: true
|
102
|
+
wrefresh
|
103
|
+
end
|
104
|
+
|
105
|
+
def debug(s)
|
106
|
+
wmove 0, 0
|
107
|
+
wclrtoeol
|
108
|
+
waddstr s.to_s
|
109
|
+
wrefresh
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
class MainWindow < Window
|
114
|
+
class Panes
|
115
|
+
attr_reader :current_index
|
116
|
+
|
117
|
+
def initialize(panes)
|
118
|
+
@panes, @current_index = panes, 0
|
119
|
+
end
|
120
|
+
|
121
|
+
def active
|
122
|
+
@panes[@current_index]
|
123
|
+
end
|
124
|
+
|
125
|
+
def activate(index)
|
126
|
+
@current_index = index if index < @panes.size
|
127
|
+
end
|
128
|
+
|
129
|
+
def size
|
130
|
+
@panes.size
|
131
|
+
end
|
132
|
+
|
133
|
+
def close_all
|
134
|
+
@panes.each {|p| Curses.delwin p}
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
def initialize(dir = '.')
|
139
|
+
border_window = subwin Curses.LINES - 5, Curses.COLS, 4, 0
|
140
|
+
Curses.wbkgd border_window, Curses::COLOR_PAIR(Curses::COLOR_CYAN)
|
141
|
+
Curses.box border_window, 0, 0
|
142
|
+
|
143
|
+
spawn_panes 2
|
144
|
+
end
|
145
|
+
|
146
|
+
def spawn_panes(num)
|
147
|
+
@panes.close_all if defined? @panes
|
148
|
+
width = (Curses.COLS - 2) / num
|
149
|
+
windows = 0.upto(num - 1).inject([]) {|arr, i| arr << subwin(Curses.LINES - 7, width - 1, 5, width * i + 1)}
|
150
|
+
@panes = Panes.new windows
|
151
|
+
activate_pane 0
|
152
|
+
end
|
153
|
+
|
154
|
+
def activate_pane(num)
|
155
|
+
@panes.activate num
|
156
|
+
end
|
157
|
+
|
158
|
+
def window
|
159
|
+
@panes.active
|
160
|
+
end
|
161
|
+
|
162
|
+
def max_items
|
163
|
+
maxy * @panes.size
|
164
|
+
end
|
165
|
+
|
166
|
+
def draw_item(item, current: false)
|
167
|
+
Curses.wattr_set window, current ? Curses::A_UNDERLINE : Curses::A_NORMAL, item.color, nil
|
168
|
+
mvwaddstr item.index % maxy, 0, "#{item.to_s}\n"
|
169
|
+
Curses.wstandend window
|
170
|
+
wrefresh
|
171
|
+
end
|
172
|
+
|
173
|
+
def draw_items_to_each_pane(items)
|
174
|
+
original_active_pane_index = @panes.current_index
|
175
|
+
|
176
|
+
0.upto(@panes.size - 1) do |index|
|
177
|
+
activate_pane index
|
178
|
+
wclear
|
179
|
+
wmove 0
|
180
|
+
items[maxy * index, maxy * (index + 1)].each do |item|
|
181
|
+
Curses.wattr_set window, Curses::A_NORMAL, item.color, nil
|
182
|
+
waddstr "#{item.to_s}\n"
|
183
|
+
end if items[maxy * index, maxy * (index + 1)]
|
184
|
+
Curses.wstandend window
|
185
|
+
wrefresh
|
186
|
+
end
|
187
|
+
activate_pane original_active_pane_index
|
188
|
+
end
|
189
|
+
|
190
|
+
def toggle_mark(item)
|
191
|
+
mvwaddstr item.index % maxy, 0, item.current_mark if item.toggle_mark
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
class CommandLineWindow < Window
|
196
|
+
def initialize
|
197
|
+
@window = subwin 1, Curses.COLS, Curses.LINES - 1, 0
|
198
|
+
end
|
199
|
+
|
200
|
+
def set_prompt(str)
|
201
|
+
Curses.wattr_set window, Curses::A_BOLD, Curses::COLOR_WHITE, nil
|
202
|
+
wmove 0
|
203
|
+
wclrtoeol
|
204
|
+
waddstr str
|
205
|
+
Curses.wstandend window
|
206
|
+
end
|
207
|
+
|
208
|
+
def get_command(prompt: nil)
|
209
|
+
Curses.echo
|
210
|
+
startx = prompt ? prompt.length : 1
|
211
|
+
s = ' ' * 100
|
212
|
+
Curses.mvwgetstr window, 0, startx, s
|
213
|
+
"#{prompt[1..-1] if prompt}#{s.strip}"
|
214
|
+
ensure
|
215
|
+
Curses.noecho
|
216
|
+
end
|
217
|
+
|
218
|
+
def show_error(str)
|
219
|
+
Curses.wattr_set window, Curses::A_BOLD, Curses::COLOR_RED, nil
|
220
|
+
wmove 0
|
221
|
+
wclrtoeol
|
222
|
+
waddstr str
|
223
|
+
wrefresh
|
224
|
+
Curses.wstandend window
|
225
|
+
end
|
226
|
+
end
|
227
|
+
end
|