rbcurse 0.1.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.
- data/CHANGELOG +1570 -0
- data/History.txt +6 -0
- data/Manifest.txt +54 -0
- data/README.txt +304 -0
- data/Rakefile +28 -0
- data/examples/qdfilechooser.rb +68 -0
- data/examples/rfe.rb +853 -0
- data/examples/rfe_renderer.rb +69 -0
- data/examples/test1.rb +242 -0
- data/examples/test2.rb +498 -0
- data/examples/testcombo.rb +95 -0
- data/examples/testkeypress.rb +61 -0
- data/examples/testmenu.rb +105 -0
- data/examples/testtable.rb +266 -0
- data/examples/testtabp.rb +106 -0
- data/examples/testtodo.rb +532 -0
- data/examples/viewtodo.rb +512 -0
- data/lib/rbcurse/action.rb +31 -0
- data/lib/rbcurse/applicationheader.rb +57 -0
- data/lib/rbcurse/celleditor.rb +120 -0
- data/lib/rbcurse/checkboxcellrenderer.rb +69 -0
- data/lib/rbcurse/colormap.rb +133 -0
- data/lib/rbcurse/comboboxcellrenderer.rb +45 -0
- data/lib/rbcurse/defaultlistselectionmodel.rb +49 -0
- data/lib/rbcurse/keylabelprinter.rb +143 -0
- data/lib/rbcurse/listcellrenderer.rb +99 -0
- data/lib/rbcurse/listkeys.rb +33 -0
- data/lib/rbcurse/listscrollable.rb +216 -0
- data/lib/rbcurse/listselectable.rb +67 -0
- data/lib/rbcurse/mapper.rb +108 -0
- data/lib/rbcurse/orderedhash.rb +77 -0
- data/lib/rbcurse/rcombo.rb +243 -0
- data/lib/rbcurse/rdialogs.rb +183 -0
- data/lib/rbcurse/rform.rb +845 -0
- data/lib/rbcurse/rinputdataevent.rb +36 -0
- data/lib/rbcurse/rlistbox.rb +804 -0
- data/lib/rbcurse/rmenu.rb +666 -0
- data/lib/rbcurse/rmessagebox.rb +325 -0
- data/lib/rbcurse/rpopupmenu.rb +754 -0
- data/lib/rbcurse/rtabbedpane.rb +259 -0
- data/lib/rbcurse/rtable.rb +1296 -0
- data/lib/rbcurse/rtextarea.rb +673 -0
- data/lib/rbcurse/rtextview.rb +335 -0
- data/lib/rbcurse/rwidget.rb +1731 -0
- data/lib/rbcurse/scrollable.rb +301 -0
- data/lib/rbcurse/selectable.rb +94 -0
- data/lib/rbcurse/table/tablecellrenderer.rb +85 -0
- data/lib/rbcurse/table/tabledatecellrenderer.rb +102 -0
- data/lib/rbcurse.rb +7 -0
- data/lib/ver/keyboard.rb +150 -0
- data/lib/ver/keyboard2.rb +170 -0
- data/lib/ver/ncurses.rb +102 -0
- data/lib/ver/window.rb +369 -0
- data/test/test_rbcurse.rb +0 -0
- metadata +118 -0
data/examples/rfe.rb
ADDED
@@ -0,0 +1,853 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'ncurses'
|
3
|
+
require 'logger'
|
4
|
+
require 'rbcurse'
|
5
|
+
require 'rbcurse/rcombo'
|
6
|
+
require 'rbcurse/rlistbox'
|
7
|
+
require 'rfe_renderer'
|
8
|
+
#require 'lib/rbcurse/table/tablecellrenderer'
|
9
|
+
require 'rbcurse/keylabelprinter'
|
10
|
+
require 'rbcurse/applicationheader'
|
11
|
+
require 'rbcurse/action'
|
12
|
+
require 'fileutils'
|
13
|
+
#$LOAD_PATH << "/Users/rahul/work/projects/rbcurse/"
|
14
|
+
|
15
|
+
# TODO
|
16
|
+
# operations on selected files: move, delete, zip
|
17
|
+
# This class represents the finder pane. There are 2
|
18
|
+
# on this sample app
|
19
|
+
class FileExplorer
|
20
|
+
include FileUtils
|
21
|
+
attr_reader :wdir
|
22
|
+
attr_reader :list # listbox
|
23
|
+
attr_reader :dir
|
24
|
+
attr_reader :prev_dirs
|
25
|
+
attr_reader :other_list # the opposite list
|
26
|
+
attr_reader :entries # avoid, can be outdated
|
27
|
+
attr_accessor :filter_pattern
|
28
|
+
|
29
|
+
def initialize form, rfe, row, col, height, width
|
30
|
+
@form = form
|
31
|
+
@rfe = rfe
|
32
|
+
@row, @col, @ht, @wid = row, col, height, width
|
33
|
+
@dir = Dir.new(Dir.getwd)
|
34
|
+
@wdir = @dir.path
|
35
|
+
@filter_pattern = '*'
|
36
|
+
@prev_dirs=[]
|
37
|
+
end
|
38
|
+
def title str
|
39
|
+
@list.title = str
|
40
|
+
end
|
41
|
+
def selected_color
|
42
|
+
@list.selected_color
|
43
|
+
end
|
44
|
+
def selected_bgcolor
|
45
|
+
@list.selected_bgcolor
|
46
|
+
end
|
47
|
+
|
48
|
+
# changes to given dir
|
49
|
+
# ensure that path is provided since other list
|
50
|
+
# may have cd'd elsewhere
|
51
|
+
def change_dir adir
|
52
|
+
list = @list
|
53
|
+
begin
|
54
|
+
#dir = File.expand_path dir
|
55
|
+
#cd "#{@dir.path}/#{adir}"
|
56
|
+
cd adir
|
57
|
+
list.title = pwd()
|
58
|
+
@dir = Dir.new(Dir.getwd)
|
59
|
+
@wdir = @dir.path
|
60
|
+
@prev_dirs << @wdir
|
61
|
+
rescan
|
62
|
+
rescue => err
|
63
|
+
@rfe.status_row.text = err.to_s
|
64
|
+
end
|
65
|
+
end
|
66
|
+
def goto_previous_dir
|
67
|
+
d = @prev_dirs.pop
|
68
|
+
if !d.nil? and d == @wdir
|
69
|
+
d = @prev_dirs.pop
|
70
|
+
end
|
71
|
+
change_dir d unless d.nil?
|
72
|
+
end
|
73
|
+
def filter list
|
74
|
+
list.delete_if { |f|
|
75
|
+
!File.directory? @wdir +"/"+ f and !File.fnmatch?(@filter_pattern, f)
|
76
|
+
}
|
77
|
+
#$log.debug " FILTER CALLED AFTER #{list.size}, #{list.entries}"
|
78
|
+
end
|
79
|
+
def rescan
|
80
|
+
flist = @dir.entries
|
81
|
+
flist.shift
|
82
|
+
#populate @entries
|
83
|
+
populate flist
|
84
|
+
end
|
85
|
+
def populate flist
|
86
|
+
#fl << format_string("..", nil)
|
87
|
+
#fl = []
|
88
|
+
#flist.each {|f| ff = "#{@wdir}/#{f}"; stat = File.stat(ff)
|
89
|
+
# fl << format_string(f, stat)
|
90
|
+
#}
|
91
|
+
filter(flist) if @filter_pattern != '*'
|
92
|
+
@entries = flist
|
93
|
+
list.list_data_model.remove_all
|
94
|
+
#list.list_data_model.insert 0, *fl
|
95
|
+
list.list_data_model.insert 0, *flist
|
96
|
+
end
|
97
|
+
def sort key, reverse=false
|
98
|
+
# remove parent before sorting, keep at top
|
99
|
+
first = @entries.delete_at(0) if @entries[0]==".."
|
100
|
+
key ||= @sort_key
|
101
|
+
cdir=cur_dir()+"/"
|
102
|
+
case key
|
103
|
+
when :size
|
104
|
+
@entries.sort! {|x,y| xs = File.stat(cdir+x); ys = File.stat(cdir+y);
|
105
|
+
if reverse
|
106
|
+
xs.size <=> ys.size
|
107
|
+
else
|
108
|
+
ys.size <=> xs.size
|
109
|
+
end
|
110
|
+
}
|
111
|
+
when :mtime
|
112
|
+
@entries.sort! {|x,y| xs = File.stat(cdir+x); ys = File.stat(cdir+y);
|
113
|
+
if reverse
|
114
|
+
xs.mtime <=> ys.mtime
|
115
|
+
else
|
116
|
+
ys.mtime <=> xs.mtime
|
117
|
+
end
|
118
|
+
}
|
119
|
+
when :atime
|
120
|
+
@entries.sort! {|x,y| xs = File.stat(cdir+x); ys = File.stat(cdir+y);
|
121
|
+
if reverse
|
122
|
+
xs.atime <=> ys.atime
|
123
|
+
else
|
124
|
+
ys.atime <=> xs.atime
|
125
|
+
end
|
126
|
+
}
|
127
|
+
when :name
|
128
|
+
@entries.sort! {|x,y| x <=> y
|
129
|
+
if reverse
|
130
|
+
x <=> y
|
131
|
+
else
|
132
|
+
y <=> x
|
133
|
+
end
|
134
|
+
}
|
135
|
+
when :ext
|
136
|
+
@entries.sort! {|x,y|
|
137
|
+
if reverse
|
138
|
+
File.extname(cdir+x) <=> File.extname(cdir+y)
|
139
|
+
else
|
140
|
+
File.extname(cdir+y) <=> File.extname(cdir+x)
|
141
|
+
end
|
142
|
+
}
|
143
|
+
end
|
144
|
+
@sort_key = key
|
145
|
+
@entries.insert 0, first unless first.nil? # keep parent on top
|
146
|
+
populate @entries
|
147
|
+
end
|
148
|
+
GIGA_SIZE = 1073741824.0
|
149
|
+
MEGA_SIZE = 1048576.0
|
150
|
+
KILO_SIZE = 1024.0
|
151
|
+
|
152
|
+
# Return the file size with a readable style.
|
153
|
+
def readable_file_size(size, precision)
|
154
|
+
case
|
155
|
+
#when size == 1 : "1 B"
|
156
|
+
when size < KILO_SIZE : "%d B" % size
|
157
|
+
when size < MEGA_SIZE : "%.#{precision}f K" % (size / KILO_SIZE)
|
158
|
+
when size < GIGA_SIZE : "%.#{precision}f M" % (size / MEGA_SIZE)
|
159
|
+
else "%.#{precision}f G" % (size / GIGA_SIZE)
|
160
|
+
end
|
161
|
+
end
|
162
|
+
def date_format t
|
163
|
+
t.strftime "%Y/%m/%d"
|
164
|
+
end
|
165
|
+
def oldformat_string fn, stat
|
166
|
+
max_len = 30
|
167
|
+
f = fn.dup
|
168
|
+
if File.directory? f
|
169
|
+
#"%-*s\t(dir)" % [max_len,f]
|
170
|
+
#f = "/"+f # disallows search on keypress
|
171
|
+
f = f + "/ "
|
172
|
+
end
|
173
|
+
if f.size > max_len
|
174
|
+
f = f[0..max_len-1]
|
175
|
+
end
|
176
|
+
"%-*s\t%10s\t%s" % [max_len,f, readable_file_size(stat.size,1), date_format(stat.mtime)]
|
177
|
+
end
|
178
|
+
def cur_dir
|
179
|
+
@dir.path
|
180
|
+
end
|
181
|
+
alias :current_dir :cur_dir
|
182
|
+
def draw_screen dir=nil
|
183
|
+
cd dir unless dir.nil?
|
184
|
+
wdir = FileUtils.pwd
|
185
|
+
@prev_dirs << wdir
|
186
|
+
@dir = Dir.new(Dir.getwd)
|
187
|
+
@wdir = @dir.path
|
188
|
+
r = @row
|
189
|
+
c = @col
|
190
|
+
#cola = 1
|
191
|
+
#colb = Ncurses.COLS/2
|
192
|
+
ht = @ht
|
193
|
+
wid = @wid
|
194
|
+
#fl = Dir.glob(default_pattern)
|
195
|
+
#flist << format_string("..", nil)
|
196
|
+
fl = @dir.entries
|
197
|
+
fl.shift
|
198
|
+
filter(fl)
|
199
|
+
#flist = []
|
200
|
+
#fl.each {|f| stat = File.stat(f)
|
201
|
+
# flist << format_string(f, stat)
|
202
|
+
#}
|
203
|
+
@entries = fl
|
204
|
+
title = pwd()
|
205
|
+
@wdir = title
|
206
|
+
rfe = self
|
207
|
+
|
208
|
+
lista = Listbox.new @form do
|
209
|
+
name "lista"
|
210
|
+
row r
|
211
|
+
col c
|
212
|
+
width wid
|
213
|
+
height ht
|
214
|
+
#list flist
|
215
|
+
list fl
|
216
|
+
title wdir
|
217
|
+
#title_attrib 'reverse'
|
218
|
+
cell_renderer RfeRenderer.new "", {"color"=>@color, "bgcolor"=>@bgcolor, "parent" => rfe, "display_length"=> wid-2}
|
219
|
+
end
|
220
|
+
@list = lista
|
221
|
+
lista.bind(:ENTER) {|l| @rfe.current_list(self); l.title_attrib 'reverse'; }
|
222
|
+
lista.bind(:LEAVE) {|l| l.title_attrib 'normal'; }
|
223
|
+
|
224
|
+
|
225
|
+
#row_cmd = lambda {|list| file = list.list_data_model[list.current_index].split(/\t/)[0].strip; @rfe.status_row.text = File.stat("#{cur_dir()}/#{file}").inspect }
|
226
|
+
row_cmd = lambda {|lb, list| file = list.entries[lb.current_index]; @rfe.status_row.text = file; # File.stat("#{cur_dir()}/#{file}").inspect
|
227
|
+
}
|
228
|
+
lista.bind(:ENTER_ROW, self) {|lb,list| row_cmd.call(lb,list) }
|
229
|
+
|
230
|
+
end
|
231
|
+
def list_data
|
232
|
+
@list.list_data_model
|
233
|
+
end
|
234
|
+
def current_index
|
235
|
+
@list.current_index
|
236
|
+
end
|
237
|
+
def filename
|
238
|
+
#@entries[@list.current_index]
|
239
|
+
list_data()[current_index()]
|
240
|
+
end
|
241
|
+
def filepath
|
242
|
+
f = filename()
|
243
|
+
if f[0,1]=='/'
|
244
|
+
f
|
245
|
+
else
|
246
|
+
cur_dir() + "/" + filename()
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
end
|
251
|
+
class RFe
|
252
|
+
attr_reader :status_row
|
253
|
+
def initialize
|
254
|
+
@window = VER::Window.root_window
|
255
|
+
@form = Form.new @window
|
256
|
+
status_row = RubyCurses::Label.new @form, {'text' => "", :row => Ncurses.LINES-4, :col => 0, :display_length=>Ncurses.COLS-2}
|
257
|
+
@status_row = status_row
|
258
|
+
colb = Ncurses.COLS/2
|
259
|
+
ht = Ncurses.LINES - 7
|
260
|
+
wid = Ncurses.COLS/2 - 0
|
261
|
+
@lista = FileExplorer.new @form, self, row=2, col=1, ht, wid
|
262
|
+
@listb = FileExplorer.new @form, self, row=2, col=colb, ht, wid
|
263
|
+
|
264
|
+
init_vars
|
265
|
+
end
|
266
|
+
def init_vars
|
267
|
+
@bookmarks=[]
|
268
|
+
@config_name = File.expand_path("~/.rfe.yml")
|
269
|
+
if File.exist? @config_name
|
270
|
+
@config = YAML::load( File.open(@config_name));
|
271
|
+
if !@config.nil?
|
272
|
+
@bookmarks = @config["bookmarks"]||[]
|
273
|
+
@last_dirs = @config["last_dirs"]
|
274
|
+
end
|
275
|
+
end
|
276
|
+
@config ||={}
|
277
|
+
end
|
278
|
+
def save_config
|
279
|
+
@config["last_dirs"]=[@lista.current_dir(),@listb.current_dir()]
|
280
|
+
File.open(@config_name, "w") { | f | YAML.dump( @config, f )}
|
281
|
+
end
|
282
|
+
def move
|
283
|
+
fp = @current_list.filepath
|
284
|
+
fn = @current_list.filename
|
285
|
+
$log.debug " FP #{fp}"
|
286
|
+
other_list = [@lista, @listb].index(@current_list)==0 ? @listb : @lista
|
287
|
+
other_dir = other_list.cur_dir
|
288
|
+
$log.debug " OL #{other_list.cur_dir}"
|
289
|
+
str= "move #{fn} to #{other_list.cur_dir}"
|
290
|
+
$log.debug " MOVE #{fp}"
|
291
|
+
#confirm "#{str}"
|
292
|
+
mb = RubyCurses::MessageBox.new do
|
293
|
+
title "Move"
|
294
|
+
message "Move #{fn} to"
|
295
|
+
type :input
|
296
|
+
width 60
|
297
|
+
default_value other_dir
|
298
|
+
button_type :ok_cancel
|
299
|
+
default_button 0
|
300
|
+
end
|
301
|
+
#confirm "selected :#{mb.input_value}, #{mb.selected_index}"
|
302
|
+
if mb.selected_index == 0
|
303
|
+
# need to redraw directories
|
304
|
+
FileUtils.move(fp, mb.input_value)
|
305
|
+
@current_list.list.list_data_model.delete_at @current_list.list.current_index # ???
|
306
|
+
other_list.rescan
|
307
|
+
end
|
308
|
+
end
|
309
|
+
def copy
|
310
|
+
fp = @current_list.filepath
|
311
|
+
fn = @current_list.filename
|
312
|
+
$log.debug " FP #{fp}"
|
313
|
+
other_list = [@lista, @listb].index(@current_list)==0 ? @listb : @lista
|
314
|
+
other_dir = other_list.cur_dir
|
315
|
+
$log.debug " OL #{other_list.cur_dir}"
|
316
|
+
str= "copy #{fn} to #{other_list.cur_dir}"
|
317
|
+
$log.debug " copy #{fp}"
|
318
|
+
#confirm "#{str}"
|
319
|
+
mb = RubyCurses::MessageBox.new do
|
320
|
+
title "Copy"
|
321
|
+
message "Copy #{fn} to"
|
322
|
+
type :input
|
323
|
+
width 60
|
324
|
+
default_value other_dir
|
325
|
+
button_type :ok_cancel
|
326
|
+
default_button 0
|
327
|
+
end
|
328
|
+
#confirm "selected :#{mb.input_value}, #{mb.selected_index}"
|
329
|
+
if mb.selected_index == 0
|
330
|
+
# need to redraw directories
|
331
|
+
FileUtils.copy(fp, mb.input_value)
|
332
|
+
other_list.rescan
|
333
|
+
end
|
334
|
+
end
|
335
|
+
## TODO : make this separate and callable with its own keylabels
|
336
|
+
def view content=nil
|
337
|
+
require 'rbcurse/rtextview'
|
338
|
+
wt = 0
|
339
|
+
wl = 0
|
340
|
+
wh = Ncurses.LINES-wt
|
341
|
+
ww = Ncurses.COLS-wl
|
342
|
+
if content.nil?
|
343
|
+
fp = @current_list.filepath
|
344
|
+
content = get_contents(fp)
|
345
|
+
else
|
346
|
+
fp=""
|
347
|
+
end
|
348
|
+
@layout = { :height => wh, :width => ww, :top => wt, :left => wl }
|
349
|
+
@v_window = VER::Window.new(@layout)
|
350
|
+
@v_form = RubyCurses::Form.new @v_window
|
351
|
+
@textview = TextView.new @v_form do
|
352
|
+
name "myView"
|
353
|
+
row 0
|
354
|
+
col 0
|
355
|
+
width ww
|
356
|
+
height wh-2
|
357
|
+
title fp
|
358
|
+
title_attrib 'bold'
|
359
|
+
print_footer true
|
360
|
+
footer_attrib 'bold'
|
361
|
+
end
|
362
|
+
#content = File.open(fp,"r").readlines
|
363
|
+
@textview.set_content content #, :WRAP_WORD
|
364
|
+
@v_form.repaint
|
365
|
+
@v_window.wrefresh
|
366
|
+
Ncurses::Panel.update_panels
|
367
|
+
begin
|
368
|
+
while((ch = @v_window.getchar()) != ?\C-q )
|
369
|
+
break if ch == KEY_F3
|
370
|
+
@v_form.handle_key ch
|
371
|
+
@v_form.repaint
|
372
|
+
##@v_window.wrefresh
|
373
|
+
end
|
374
|
+
ensure
|
375
|
+
@v_window.destroy if !@v_window.nil?
|
376
|
+
end
|
377
|
+
end
|
378
|
+
def get_contents fp
|
379
|
+
return nil unless File.readable? fp
|
380
|
+
return Dir.new(fp).entries if File.directory? fp
|
381
|
+
case File.extname(fp)
|
382
|
+
when '.tgz','.gz'
|
383
|
+
cmd = "tar -ztvf #{fp}"
|
384
|
+
content = %x[#{cmd}]
|
385
|
+
else
|
386
|
+
content = File.open(fp,"r").readlines
|
387
|
+
end
|
388
|
+
end
|
389
|
+
def opt_file c
|
390
|
+
fp = @current_list.filepath
|
391
|
+
fn = @current_list.filename
|
392
|
+
other_list = [@lista, @listb].index(@current_list)==0 ? @listb : @lista
|
393
|
+
case c
|
394
|
+
when 'c'
|
395
|
+
# str= "copy #{fn} to #{other_list.cur_dir}"
|
396
|
+
copy
|
397
|
+
when 'm'
|
398
|
+
str= "move #{fn} to #{other_list.cur_dir}"
|
399
|
+
move
|
400
|
+
#if confirm("#{str}")==:YES
|
401
|
+
#$log.debug " MOVE #{str}"
|
402
|
+
#end
|
403
|
+
when 'd'
|
404
|
+
str= "delete #{fn} "
|
405
|
+
if confirm("#{str}")==:YES
|
406
|
+
$log.debug " delete #{fp}"
|
407
|
+
FileUtils.rm fp
|
408
|
+
ret=@current_list.list.list_data_model.delete_at @current_list.list.current_index # ???
|
409
|
+
$log.debug " DEL RET #{ret},#{@current_list.list.current_index}"
|
410
|
+
end
|
411
|
+
when 'u'
|
412
|
+
str= "move #{fn} to #{other_list.cur_dir}"
|
413
|
+
if confirm("#{str}")==:YES
|
414
|
+
$log.debug " MOVE #{str}"
|
415
|
+
end
|
416
|
+
when 'v'
|
417
|
+
str= "view #{fp}"
|
418
|
+
#if confirm("#{str}")==:YES
|
419
|
+
$log.debug " VIEW #{fp}"
|
420
|
+
view
|
421
|
+
#end
|
422
|
+
when 'r'
|
423
|
+
str= "ruby #{fn}"
|
424
|
+
if confirm("#{str}")=='y'
|
425
|
+
$log.debug " #{str} "
|
426
|
+
end
|
427
|
+
when 'e'
|
428
|
+
str= "edit #{fp}"
|
429
|
+
#if confirm("#{str}")==:YES
|
430
|
+
edit fp
|
431
|
+
when 'x'
|
432
|
+
str= "exec #{fp}"
|
433
|
+
exec_popup fp
|
434
|
+
end
|
435
|
+
end
|
436
|
+
def opt_dir c
|
437
|
+
fp = @current_list.filepath
|
438
|
+
fn = @current_list.filename
|
439
|
+
case c
|
440
|
+
when 'O'
|
441
|
+
# str= "copy #{fn} to #{other_list.cur_dir}"
|
442
|
+
if File.directory? @current_list.filepath
|
443
|
+
@current_list.change_dir fp
|
444
|
+
end
|
445
|
+
when 'o'
|
446
|
+
if File.directory? @current_list.filepath
|
447
|
+
@other_list.change_dir fp
|
448
|
+
end
|
449
|
+
@open_in_other = true # ???basically keep opening in other
|
450
|
+
when 'd'
|
451
|
+
str= "delete #{fn} "
|
452
|
+
if confirm("#{str}")==:YES
|
453
|
+
$log.debug " delete #{fp}"
|
454
|
+
FileUtils.rm fp
|
455
|
+
ret=@current_list.list.list_data_model.delete_at @current_list.list.current_index # ???
|
456
|
+
$log.debug " DEL RET #{ret},#{@current_list.list.current_index}"
|
457
|
+
end
|
458
|
+
when 'u'
|
459
|
+
str= "move #{fn} to #{other_list.cur_dir}"
|
460
|
+
if confirm("#{str}")==:YES
|
461
|
+
$log.debug " MOVE #{str}"
|
462
|
+
end
|
463
|
+
when 'b'
|
464
|
+
dd = @current_list.wdir
|
465
|
+
@bookmarks << dd unless @bookmarks.include? dd
|
466
|
+
when 'u'
|
467
|
+
dd = @current_list.wdir
|
468
|
+
@bookmarks.delete dd
|
469
|
+
when 'l'
|
470
|
+
@current_list.populate @bookmarks
|
471
|
+
when 's'
|
472
|
+
@config["bookmarks"] = @bookmarks
|
473
|
+
save_config
|
474
|
+
when 'e'
|
475
|
+
str= "edit #{fp}"
|
476
|
+
#if confirm("#{str}")==:YES
|
477
|
+
edit fp
|
478
|
+
when 'x'
|
479
|
+
str= "exec #{fp}"
|
480
|
+
exec_popup fp
|
481
|
+
end
|
482
|
+
end
|
483
|
+
def exec_popup fp
|
484
|
+
last_exec_def1 = @last_exec_def1 || ""
|
485
|
+
last_exec_def2 = @last_exec_def2 || false
|
486
|
+
|
487
|
+
sel, inp, hash = get_string_with_options("Enter a command to execute on #{fp}", 30, last_exec_def1, {"checkboxes" => ["view result"], "checkbox_defaults"=>[last_exec_def2]})
|
488
|
+
if sel == 0
|
489
|
+
@last_exec_def1 = inp
|
490
|
+
@last_exec_def2 = hash["view result"]
|
491
|
+
cmd = "#{inp} #{fp}"
|
492
|
+
filestr = %x[ #{cmd} 2>/dev/null ]
|
493
|
+
if hash["view result"]==true
|
494
|
+
view filestr
|
495
|
+
end
|
496
|
+
end
|
497
|
+
end
|
498
|
+
def edit fp=@current_list.filepath
|
499
|
+
$log.debug " edit #{fp}"
|
500
|
+
shell_out "/opt/local/bin/vim #{fp}"
|
501
|
+
end
|
502
|
+
def draw_screens
|
503
|
+
lasta = lastb = nil
|
504
|
+
if !@config["last_dirs"].nil?
|
505
|
+
lasta = @config["last_dirs"][0]
|
506
|
+
lastb = @config["last_dirs"][1]
|
507
|
+
end
|
508
|
+
@lista.draw_screen lasta
|
509
|
+
@listb.draw_screen lastb
|
510
|
+
|
511
|
+
@form.bind_key(?@){
|
512
|
+
@current_list.change_dir File.expand_path("~/")
|
513
|
+
}
|
514
|
+
@form.bind_key(?^){
|
515
|
+
@current_list.change_dir @current_list.prev_dirs[0] unless @current_list.prev_dirs.empty?
|
516
|
+
}
|
517
|
+
@form.bind_key(?\C-f){
|
518
|
+
@klp.mode :file
|
519
|
+
@klp.repaint
|
520
|
+
## FIXME chr could fail !!
|
521
|
+
while((ch = @window.getchar()) != ?\C-c )
|
522
|
+
if "cmdsuvrex".index(ch.chr) == nil
|
523
|
+
Ncurses.beep
|
524
|
+
else
|
525
|
+
opt_file ch.chr
|
526
|
+
break
|
527
|
+
end
|
528
|
+
end
|
529
|
+
@klp.mode :normal
|
530
|
+
}
|
531
|
+
@form.bind_key(?\C-d){
|
532
|
+
@klp.mode :dir
|
533
|
+
@klp.repaint
|
534
|
+
keys = @klp.get_current_keys
|
535
|
+
## FIXME chr could fail !!
|
536
|
+
while((ch = @window.getchar()) != ?\C-c )
|
537
|
+
if !keys.include?(ch.chr)
|
538
|
+
Ncurses.beep
|
539
|
+
else
|
540
|
+
opt_dir ch.chr
|
541
|
+
break
|
542
|
+
end
|
543
|
+
end
|
544
|
+
@klp.mode :normal
|
545
|
+
}
|
546
|
+
# backspace
|
547
|
+
@form.bind_key(127){
|
548
|
+
@current_list.goto_previous_dir
|
549
|
+
}
|
550
|
+
@form.bind_key(32){
|
551
|
+
begin
|
552
|
+
cmd="qlmanage -p #{@current_list.filepath} 2>/dev/null"
|
553
|
+
%x[#{cmd}]
|
554
|
+
rescue Interrupt
|
555
|
+
end
|
556
|
+
}
|
557
|
+
@form.bind_key(KEY_F3){
|
558
|
+
view()
|
559
|
+
}
|
560
|
+
@form.bind_key(KEY_F4){
|
561
|
+
edit()
|
562
|
+
}
|
563
|
+
@form.bind_key(KEY_F6){
|
564
|
+
selected_index, sort_key, reverse, case_sensitive = sort_popup
|
565
|
+
if selected_index == 0
|
566
|
+
@current_list.sort(sort_key, reverse)
|
567
|
+
end
|
568
|
+
}
|
569
|
+
@form.bind_key(KEY_F5){
|
570
|
+
filter()
|
571
|
+
}
|
572
|
+
@form.bind_key(KEY_F7){
|
573
|
+
grep_popup()
|
574
|
+
}
|
575
|
+
@form.bind_key(KEY_F8){
|
576
|
+
system_popup()
|
577
|
+
}
|
578
|
+
@form.bind_key(?\C-m){
|
579
|
+
dir = @current_list.filepath
|
580
|
+
if File.directory? @current_list.filepath
|
581
|
+
@current_list.change_dir dir
|
582
|
+
end
|
583
|
+
}
|
584
|
+
@klp = RubyCurses::KeyLabelPrinter.new @form, get_key_labels
|
585
|
+
@klp.set_key_labels get_key_labels(:file), :file
|
586
|
+
@klp.set_key_labels get_key_labels(:view), :view
|
587
|
+
@klp.set_key_labels get_key_labels(:dir), :dir
|
588
|
+
@form.repaint
|
589
|
+
@window.wrefresh
|
590
|
+
Ncurses::Panel.update_panels
|
591
|
+
begin
|
592
|
+
while((ch = @window.getchar()) != ?\C-q )
|
593
|
+
s = keycode_tos ch
|
594
|
+
status_row.text = "Pressed #{ch} , #{s}"
|
595
|
+
@form.handle_key(ch)
|
596
|
+
|
597
|
+
@form.repaint
|
598
|
+
@window.wrefresh
|
599
|
+
end
|
600
|
+
ensure
|
601
|
+
@window.destroy if !@window.nil?
|
602
|
+
save_config
|
603
|
+
end
|
604
|
+
|
605
|
+
end
|
606
|
+
# TODO
|
607
|
+
#
|
608
|
+
#
|
609
|
+
#
|
610
|
+
|
611
|
+
# current_list
|
612
|
+
##
|
613
|
+
# getter and setter for current_list
|
614
|
+
def current_list(*val)
|
615
|
+
if val.empty?
|
616
|
+
@current_list
|
617
|
+
else
|
618
|
+
@current_list = val[0]
|
619
|
+
@other_list = [@lista, @listb].index(@current_list)==0 ? @listb : @lista
|
620
|
+
end
|
621
|
+
end
|
622
|
+
def get_key_labels categ=nil
|
623
|
+
if categ.nil?
|
624
|
+
key_labels = [
|
625
|
+
['C-q', 'Exit'], ['C-v', 'View'],
|
626
|
+
['C-f', 'File'], ['C-d', 'Dir'],
|
627
|
+
['C-x','Select'], nil,
|
628
|
+
['F3', 'View'], ['F4', 'Edit'],
|
629
|
+
['F5', 'Filter'], ['F6', 'Sort'],
|
630
|
+
['F7', 'Grep'], ['F8', 'System'],
|
631
|
+
['M-0', 'Top'], ['M-9', 'End'],
|
632
|
+
['C-p', 'PgUp'], ['C-n', 'PgDn']
|
633
|
+
]
|
634
|
+
elsif categ == :file
|
635
|
+
key_labels = [
|
636
|
+
['c', 'Copy'], ['m', 'Move'],
|
637
|
+
['d', 'Delete'], ['v', 'View'],
|
638
|
+
['s', 'Select'], ['u', 'Unselect'],
|
639
|
+
['p', 'Page'], ['x', 'Exec Cmd'],
|
640
|
+
['r', 'ruby'], ['e', "Edit"],
|
641
|
+
['C-c', 'Cancel']
|
642
|
+
]
|
643
|
+
elsif categ == :view
|
644
|
+
key_labels = [
|
645
|
+
['c', 'Date'], ['m', 'Size'],
|
646
|
+
['d', 'Delete'], ['v', 'View'],
|
647
|
+
['C-c', 'Cancel']
|
648
|
+
]
|
649
|
+
elsif categ == :dir
|
650
|
+
key_labels = [
|
651
|
+
['o', 'open'], ['O', 'Open in right'],
|
652
|
+
['d', 'Delete'], ['R', 'Del Recurse'],
|
653
|
+
['t', 'tree'], ['p', 'Previous'],
|
654
|
+
['b', 'Bookmark'], ['u', 'Unbookmark'],
|
655
|
+
['l', 'List'], ['s', 'Save'],
|
656
|
+
['C-c', 'Cancel']
|
657
|
+
]
|
658
|
+
end
|
659
|
+
return key_labels
|
660
|
+
end
|
661
|
+
def get_key_labels_table
|
662
|
+
key_labels = [
|
663
|
+
['M-n','NewRow'], ['M-d','DelRow'],
|
664
|
+
['C-x','Select'], nil,
|
665
|
+
['M-0', 'Top'], ['M-9', 'End'],
|
666
|
+
['C-p', 'PgUp'], ['C-n', 'PgDn'],
|
667
|
+
['M-Tab','Nxt Fld'], ['Tab','Nxt Col'],
|
668
|
+
['+','Widen'], ['-','Narrow']
|
669
|
+
]
|
670
|
+
return key_labels
|
671
|
+
end
|
672
|
+
def sort_popup
|
673
|
+
mform = RubyCurses::Form.new nil
|
674
|
+
field_list = []
|
675
|
+
r = 4
|
676
|
+
$radio = RubyCurses::Variable.new
|
677
|
+
rtextvalue = [:name, :ext, :size, :mtime, :atime]
|
678
|
+
["Name", "Extension", "Size", "Modify Time", "Access Time" ].each_with_index do |rtext,ix|
|
679
|
+
field = RubyCurses::RadioButton.new mform do
|
680
|
+
variable $radio
|
681
|
+
text rtext
|
682
|
+
value rtextvalue[ix]
|
683
|
+
color 'black'
|
684
|
+
bgcolor 'white'
|
685
|
+
row r
|
686
|
+
col 5
|
687
|
+
end
|
688
|
+
field_list << field
|
689
|
+
r += 1
|
690
|
+
end
|
691
|
+
r = 4
|
692
|
+
["Reverse", "case sensitive"].each do |cbtext|
|
693
|
+
field = RubyCurses::CheckBox.new mform do
|
694
|
+
text cbtext
|
695
|
+
name cbtext
|
696
|
+
color 'black'
|
697
|
+
bgcolor 'white'
|
698
|
+
row r
|
699
|
+
col 30
|
700
|
+
end
|
701
|
+
field_list << field
|
702
|
+
r += 1
|
703
|
+
end
|
704
|
+
mb = RubyCurses::MessageBox.new mform do
|
705
|
+
title "Sort Options"
|
706
|
+
button_type :ok_cancel
|
707
|
+
default_button 0
|
708
|
+
end
|
709
|
+
if mb.selected_index == 0
|
710
|
+
$log.debug " SORT POPUP #{$radio.value}"
|
711
|
+
#$log.debug " SORT POPUP #{mb.inspect}"
|
712
|
+
$log.debug " SORT POPUP #{mform.by_name["Reverse"].value}"
|
713
|
+
$log.debug " SORT POPUP #{mform.by_name["case sensitive"].value}"
|
714
|
+
end
|
715
|
+
return mb.selected_index, $radio.value, mform.by_name["Reverse"].value, mform.by_name["case sensitive"].value
|
716
|
+
end
|
717
|
+
def filter
|
718
|
+
f = get_string("Enter a filter pattern", 20, "*")
|
719
|
+
f = "*" if f.nil? or f == ""
|
720
|
+
@current_list.filter_pattern = f
|
721
|
+
@current_list.rescan
|
722
|
+
end
|
723
|
+
def grep_popup
|
724
|
+
last_regex = @last_regex || ""
|
725
|
+
last_pattern = @last_pattern || "*"
|
726
|
+
mform = RubyCurses::Form.new nil
|
727
|
+
r = 4
|
728
|
+
field = RubyCurses::Field.new mform do
|
729
|
+
name "regex"
|
730
|
+
row r
|
731
|
+
col 30
|
732
|
+
set_buffer last_regex
|
733
|
+
set_label Label.new @form, {'text' => 'Regex', 'col'=>5, :color=>'black',:bgcolor=>'white','mnemonic'=> 'R'}
|
734
|
+
end
|
735
|
+
r += 1
|
736
|
+
field = RubyCurses::Field.new mform do
|
737
|
+
name "filepattern"
|
738
|
+
row r
|
739
|
+
col 30
|
740
|
+
set_buffer last_pattern
|
741
|
+
set_label Label.new @form, {'text' => 'File Pattern','col'=>5, :color=>'black',:bgcolor=>'white','mnemonic'=> 'F'}
|
742
|
+
end
|
743
|
+
r += 1
|
744
|
+
["Recurse", "case insensitive"].each do |cbtext|
|
745
|
+
field = RubyCurses::CheckBox.new mform do
|
746
|
+
text cbtext
|
747
|
+
name cbtext
|
748
|
+
color 'black'
|
749
|
+
bgcolor 'white'
|
750
|
+
row r
|
751
|
+
col 5
|
752
|
+
end
|
753
|
+
r += 1
|
754
|
+
end
|
755
|
+
mb = RubyCurses::MessageBox.new mform do
|
756
|
+
title "Grep Options"
|
757
|
+
button_type :ok_cancel
|
758
|
+
default_button 0
|
759
|
+
end
|
760
|
+
if mb.selected_index == 0
|
761
|
+
return if mform.by_name["regex"].getvalue()==""
|
762
|
+
@last_regex = mform.by_name["regex"].getvalue
|
763
|
+
inp = mform.by_name["regex"].getvalue
|
764
|
+
fp = mform.by_name["filepattern"].getvalue
|
765
|
+
@last_pattern = fp
|
766
|
+
flags=""
|
767
|
+
flags << " -i " if mform.by_name["case insensitive"].value==true
|
768
|
+
flags << " -R " if mform.by_name["Recurse"].value==true
|
769
|
+
cmd = "cd #{@current_list.cur_dir()};grep -l #{flags} #{inp} #{fp}"
|
770
|
+
filestr = %x[ #{cmd} ]
|
771
|
+
files = nil
|
772
|
+
files = filestr.split(/\n/) unless filestr.nil?
|
773
|
+
#view filestr
|
774
|
+
@current_list.title "grep #{inp}"
|
775
|
+
@current_list.populate files
|
776
|
+
end
|
777
|
+
return mb.selected_index, mform.by_name["regex"].getvalue, mform.by_name["filepattern"].getvalue, mform.by_name["Recurse"].value, mform.by_name["case insensitive"].value
|
778
|
+
end
|
779
|
+
def system_popup
|
780
|
+
deflt = @last_system || ""
|
781
|
+
options=["run in shell","view output","file explorer"]
|
782
|
+
#inp = get_string("Enter a system command", 30, deflt)
|
783
|
+
sel, inp, hash = get_string_with_options("Enter a system command", 40, deflt, {"radiobuttons" => options, "radio_default"=>@last_system_radio || options[0]})
|
784
|
+
if sel == 0
|
785
|
+
if !inp.nil?
|
786
|
+
@last_system = inp
|
787
|
+
@last_system_radio = hash["radio"]
|
788
|
+
case hash["radio"]
|
789
|
+
when options[0]
|
790
|
+
shell_out inp
|
791
|
+
when options[1]
|
792
|
+
filestr = %x[ #{inp} ]
|
793
|
+
view filestr
|
794
|
+
when options[2]
|
795
|
+
filestr = %x[ #{inp} ]
|
796
|
+
files = nil
|
797
|
+
files = filestr.split(/\n/) unless filestr.nil?
|
798
|
+
@current_list.title inp
|
799
|
+
@current_list.populate files
|
800
|
+
$log.debug " SYSTEM got #{files.size}, #{files.inspect}"
|
801
|
+
end
|
802
|
+
end
|
803
|
+
end
|
804
|
+
end
|
805
|
+
def popup
|
806
|
+
deflt = @last_regexp || ""
|
807
|
+
#sel, inp, hash = get_string_with_options("Enter a filter pattern", 20, "*", {"checkboxes" => ["case sensitive","reverse"], "checkbox_defaults"=>[true, false]})
|
808
|
+
sel, inp, hash = get_string_with_options("Enter a grep pattern", 20, deflt, {"checkboxes" => ["case insensitive","not-including"]})
|
809
|
+
if sel == 0
|
810
|
+
@last_regexp = inp
|
811
|
+
flags=""
|
812
|
+
flags << " -i " if hash["case insensitive"]==true
|
813
|
+
flags << " -v " if hash["not-including"]==true
|
814
|
+
cmd = "grep -l #{flags} #{inp} *"
|
815
|
+
filestr = %x[ #{cmd} ]
|
816
|
+
files = nil
|
817
|
+
files = filestr.split(/\n/) unless filestr.nil?
|
818
|
+
view filestr
|
819
|
+
end
|
820
|
+
$log.debug " POPUP: #{sel}: #{inp}, #{hash['case sensitive']}, #{hash['reverse']}"
|
821
|
+
end
|
822
|
+
def shell_out command
|
823
|
+
@window.hide
|
824
|
+
Ncurses.endwin
|
825
|
+
system command
|
826
|
+
Ncurses.refresh
|
827
|
+
#Ncurses.curs_set 0 # why ?
|
828
|
+
@window.show
|
829
|
+
end
|
830
|
+
end
|
831
|
+
if $0 == __FILE__
|
832
|
+
include RubyCurses
|
833
|
+
include RubyCurses::Utils
|
834
|
+
|
835
|
+
begin
|
836
|
+
# Initialize curses
|
837
|
+
VER::start_ncurses # this is initializing colors via ColorMap.setup
|
838
|
+
$log = Logger.new("view.log")
|
839
|
+
$log.level = Logger::DEBUG
|
840
|
+
|
841
|
+
catch(:close) do
|
842
|
+
t = RFe.new
|
843
|
+
t.draw_screens
|
844
|
+
end
|
845
|
+
rescue => ex
|
846
|
+
ensure
|
847
|
+
VER::stop_ncurses
|
848
|
+
p ex if ex
|
849
|
+
p(ex.backtrace.join("\n")) if ex
|
850
|
+
$log.debug( ex) if ex
|
851
|
+
$log.debug(ex.backtrace.join("\n")) if ex
|
852
|
+
end
|
853
|
+
end
|