rbcurse-extras 0.0.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/README.md +75 -0
- data/VERSION +1 -0
- data/examples/data/list.txt +300 -0
- data/examples/data/lotr.txt +12 -0
- data/examples/data/table.txt +36 -0
- data/examples/data/tasks.txt +27 -0
- data/examples/data/unix1.txt +21 -0
- data/examples/inc/qdfilechooser.rb +70 -0
- data/examples/inc/rfe_renderer.rb +121 -0
- data/examples/newtabbedwindow.rb +100 -0
- data/examples/rfe.rb +1236 -0
- data/examples/test2.rb +670 -0
- data/examples/testeditlist.rb +78 -0
- data/examples/testtable.rb +270 -0
- data/examples/testvimsplit.rb +141 -0
- data/lib/rbcurse/extras/include/celleditor.rb +112 -0
- data/lib/rbcurse/extras/include/checkboxcellrenderer.rb +57 -0
- data/lib/rbcurse/extras/include/comboboxcellrenderer.rb +30 -0
- data/lib/rbcurse/extras/include/defaultlistselectionmodel.rb +79 -0
- data/lib/rbcurse/extras/include/listkeys.rb +37 -0
- data/lib/rbcurse/extras/include/listselectable.rb +144 -0
- data/lib/rbcurse/extras/include/tableextended.rb +40 -0
- data/lib/rbcurse/extras/widgets/horizlist.rb +203 -0
- data/lib/rbcurse/extras/widgets/menutree.rb +63 -0
- data/lib/rbcurse/extras/widgets/multilinelabel.rb +142 -0
- data/lib/rbcurse/extras/widgets/rcomboedit.rb +256 -0
- data/lib/rbcurse/extras/widgets/rlink.rb.moved +27 -0
- data/lib/rbcurse/extras/widgets/rlistbox.rb +1247 -0
- data/lib/rbcurse/extras/widgets/rmenulink.rb.moved +21 -0
- data/lib/rbcurse/extras/widgets/rmulticontainer.rb +304 -0
- data/lib/rbcurse/extras/widgets/rmultisplit.rb +722 -0
- data/lib/rbcurse/extras/widgets/rmultitextview.rb +306 -0
- data/lib/rbcurse/extras/widgets/rpopupmenu.rb +755 -0
- data/lib/rbcurse/extras/widgets/rtable.rb +1758 -0
- data/lib/rbcurse/extras/widgets/rvimsplit.rb +800 -0
- data/lib/rbcurse/extras/widgets/table/tablecellrenderer.rb +86 -0
- data/lib/rbcurse/extras/widgets/table/tabledatecellrenderer.rb +98 -0
- metadata +94 -0
@@ -0,0 +1,21 @@
|
|
1
|
+
Eric S. Raymond, in his book The Art of Unix Programming,[2] summarizes the Unix philosophy as the widely-used KISS Principle of "Keep it Simple, Stupid."[3] He also provides a series of design rules:
|
2
|
+
|
3
|
+
* Rule of Modularity: Write simple parts connected by clean interfaces.
|
4
|
+
* Rule of Clarity: Clarity is better than cleverness.
|
5
|
+
* Rule of Composition: Design programs to be connected to other programs.
|
6
|
+
* Rule of Separation: Separate policy from mechanism; separate interfaces from engines.
|
7
|
+
* Rule of Simplicity: Design for simplicity; add complexity only where you must.
|
8
|
+
* Rule of Parsimony: Write a big program only when it is clear by demonstration that nothing else will do.
|
9
|
+
* Rule of Transparency: Design for visibility to make inspection and debugging easier.
|
10
|
+
* Rule of Robustness: Robustness is the child of transparency and simplicity.
|
11
|
+
* Rule of Representation: Fold knowledge into data so program logic can be stupid and robust.[4]
|
12
|
+
* Rule of Least Surprise: In interface design, always do the least surprising thing.
|
13
|
+
* Rule of Silence: When a program has nothing surprising to say, it should say nothing.
|
14
|
+
* Rule of Repair: When you must fail, fail noisily and as soon as possible.
|
15
|
+
* Rule of Economy: Programmer time is expensive; conserve it in preference to machine time.
|
16
|
+
* Rule of Generation: Avoid hand-hacking; write programs to write programs when you can.
|
17
|
+
* Rule of Optimization: Prototype before polishing. Get it working before you optimize it.
|
18
|
+
* Rule of Diversity: Distrust all claims for "one true way".
|
19
|
+
* Rule of Extensibility: Design for the future, because it will be here sooner than you think.
|
20
|
+
|
21
|
+
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# NOTE this no longer works after the changes in Messagebox,
|
2
|
+
# needs to be redone.
|
3
|
+
# this is a test program, tests out messageboxes. type F1 to exit
|
4
|
+
# a quick dirty file chooser in 2 lines of code.
|
5
|
+
require 'logger'
|
6
|
+
require 'rbcurse/core/system/ncurses'
|
7
|
+
require 'rbcurse/core/system/window'
|
8
|
+
require 'rbcurse/core/widgets/rwidget'
|
9
|
+
|
10
|
+
##
|
11
|
+
# a quick dirty file chooser - only temporary till we make something better.
|
12
|
+
class QDFileChooser
|
13
|
+
attr_accessor :show_folders # bool
|
14
|
+
attr_accessor :traverse_folders # bool
|
15
|
+
attr_accessor :default_pattern # e.g. "*.*"
|
16
|
+
attr_accessor :dialog_title # File Chooser
|
17
|
+
def initialize
|
18
|
+
|
19
|
+
end
|
20
|
+
def show_open_dialog
|
21
|
+
@form = RubyCurses::Form.new nil
|
22
|
+
label = RubyCurses::Label.new @form, {'text' => 'File', 'row'=>3, 'col'=>4, 'color'=>'black', 'bgcolor'=>'white', 'mnemonic'=>'F'}
|
23
|
+
field = RubyCurses::Field.new @form do
|
24
|
+
name "file"
|
25
|
+
row 3
|
26
|
+
col 10
|
27
|
+
display_length 40
|
28
|
+
set_label label
|
29
|
+
end
|
30
|
+
default_pattern ||= "*.*"
|
31
|
+
flist = Dir.glob(default_pattern)
|
32
|
+
@listb = RubyCurses::Listbox.new @form do
|
33
|
+
name "mylist"
|
34
|
+
row 5
|
35
|
+
col 10
|
36
|
+
width 40
|
37
|
+
height 10
|
38
|
+
list flist
|
39
|
+
title "File list"
|
40
|
+
title_attrib 'bold'
|
41
|
+
end
|
42
|
+
#@listb.list.bind(:ENTER_ROW) { field.set_buffer @listb.selected_item }
|
43
|
+
listb = @listb
|
44
|
+
field.bind(:CHANGE) do |f|
|
45
|
+
flist = Dir.glob(f.getvalue+"*")
|
46
|
+
l = listb.list
|
47
|
+
l.remove_all
|
48
|
+
l.insert 0, *flist
|
49
|
+
end
|
50
|
+
atitle = @dialog_title || "Quick Dirty(TM) File Chooser"
|
51
|
+
@mb = RubyCurses::MessageBox.new @form do
|
52
|
+
title atitle
|
53
|
+
type :override
|
54
|
+
height 20
|
55
|
+
width 60
|
56
|
+
top 5
|
57
|
+
left 20
|
58
|
+
default_button 0
|
59
|
+
button_type :ok_cancel
|
60
|
+
end
|
61
|
+
#$log.debug "MBOX :selected #{@listb.selected_item}, #{@listb[@listb.getvalue[0]]} "
|
62
|
+
return @mb.selected_index == 0 ? :OK : :CANCEL
|
63
|
+
end
|
64
|
+
def get_selected_file
|
65
|
+
#return @mb.selected_index == 0 ? @listb.selected_item : nil
|
66
|
+
#return @mb.selected_index == 0 ? @listb[@listb.getvalue[0]] : nil
|
67
|
+
# return either the selected_value or if user pressed okay, then focussed item
|
68
|
+
return @mb.selected_index == 0 ? @listb.selected_value || @listb.selected_item : nil
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
module RubyCurses
|
2
|
+
|
3
|
+
##
|
4
|
+
# This is a basic list cell renderer that will render the to_s value of anything.
|
5
|
+
# Using alignment one can use for numbers too.
|
6
|
+
# However, for booleans it will print true and false. If editing, you may want checkboxes
|
7
|
+
class RfeRenderer < ListCellRenderer
|
8
|
+
def initialize text="", config={}, &block
|
9
|
+
super
|
10
|
+
@orig_bgcolor = @bgcolor
|
11
|
+
@orig_color = @color
|
12
|
+
@orig_attr = @attr
|
13
|
+
# we need to refer to file types, executable, dir, link, otherwise we'll go crazy
|
14
|
+
@color_hash = {
|
15
|
+
'.rb' => [get_color($datacolor, 'red', 'black'), 0],
|
16
|
+
'.txt' => [get_color($datacolor, 'white', 'black'), 0],
|
17
|
+
'.gemspec' => [get_color($datacolor, 'yellow', 'black'), 0],
|
18
|
+
'.gem' => [get_color($datacolor, 'yellow', 'black'), 0],
|
19
|
+
'.c' => [get_color($datacolor, 'green', 'black'), 0],
|
20
|
+
'.py' => [get_color($datacolor, 'green', 'black'), 0],
|
21
|
+
'.tgz' => [get_color($datacolor, 'red', 'black'), get_attrib('bold')],
|
22
|
+
'.gz' => [get_color($datacolor, 'red', 'black'), 0],
|
23
|
+
'.zip' => [get_color($datacolor, 'red', 'black'), 0],
|
24
|
+
'.jar' => [get_color($datacolor, 'red', 'black'), 0],
|
25
|
+
'.html' => [get_color($datacolor, 'green', 'black'), get_attrib('reverse')],
|
26
|
+
"" => [get_color($datacolor, 'yellow', 'black'), get_attrib('bold')],
|
27
|
+
'.jpg' => [get_color($datacolor, 'magenta', 'black'), 0],
|
28
|
+
'.png' => [get_color($datacolor, 'magenta', 'black'), 0],
|
29
|
+
'.sh' => [get_color($datacolor, 'red', 'black'), 0],
|
30
|
+
'.mp3' => [get_color($datacolor, 'cyan', 'blue'), 0],
|
31
|
+
'.bak' => [get_color($datacolor, 'magenta', 'black'), 0],
|
32
|
+
'.tmp' => [get_color($datacolor, 'black', 'blue'), 0],
|
33
|
+
'.pl' => [get_color($datacolor, 'green', 'black'), 0],
|
34
|
+
'.java' => [get_color($datacolor, 'cyan', 'blue'), 0],
|
35
|
+
'.class' => [get_color($datacolor, 'magenta', 'black'), 0],
|
36
|
+
'.pyc' => [get_color($datacolor, 'magenta', 'black'), 0],
|
37
|
+
'.o' => [get_color($datacolor, 'magenta', 'black'), 0],
|
38
|
+
'.a' => [get_color($datacolor, 'magenta', 'black'), 0],
|
39
|
+
'.lib' => [get_color($datacolor, 'magenta', 'black'), 0]
|
40
|
+
}
|
41
|
+
end
|
42
|
+
|
43
|
+
# override parent method to set color_pair and attr for different kind of files
|
44
|
+
def select_colors focussed, selected
|
45
|
+
ext = File.extname(@path)
|
46
|
+
c = @color_hash[ext]
|
47
|
+
c = [$datacolor, FFI::NCurses::A_NORMAL] unless c
|
48
|
+
if File.directory? @path
|
49
|
+
c = [get_color($datacolor, 'blue', 'black'), FFI::NCurses::A_BOLD]
|
50
|
+
end
|
51
|
+
@color_pair, @attr = *c
|
52
|
+
if selected
|
53
|
+
#@attr = FFI::NCurses::A_UNDERLINE | FFI::NCurses::A_BOLD # UL not avaible on screen
|
54
|
+
@attr = FFI::NCurses::A_REVERSE | FFI::NCurses::A_BOLD
|
55
|
+
@color_pair = $datacolor
|
56
|
+
end
|
57
|
+
if focussed
|
58
|
+
@attr = FFI::NCurses::A_REVERSE # | FFI::NCurses::A_BOLD
|
59
|
+
end
|
60
|
+
end
|
61
|
+
#
|
62
|
+
def repaint graphic, r=@row,c=@col, row_index=-1, value=@text, focussed=false, selected=false
|
63
|
+
|
64
|
+
@bgcolor = @orig_bgcolor
|
65
|
+
@color = @orig_color
|
66
|
+
@row_attr = @orig_attr
|
67
|
+
# XXX ouch, when we delete from list, must delete from here too.
|
68
|
+
value = @parent.entries[row_index]
|
69
|
+
if value[0,1]=="/"
|
70
|
+
path = value.dup
|
71
|
+
else
|
72
|
+
path = @parent.cur_dir()+"/"+value
|
73
|
+
end
|
74
|
+
@path = path # i need it in select_color
|
75
|
+
begin
|
76
|
+
stat = File.stat(path)
|
77
|
+
if File.directory? path
|
78
|
+
@row_attr = Ncurses::A_BOLD
|
79
|
+
#@color = 'yellow'
|
80
|
+
end
|
81
|
+
value = format_string(value, path, stat)
|
82
|
+
super
|
83
|
+
|
84
|
+
rescue => err
|
85
|
+
$log.debug " rfe_renderer: #{err}"
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
89
|
+
GIGA_SIZE = 1073741824.0
|
90
|
+
MEGA_SIZE = 1048576.0
|
91
|
+
KILO_SIZE = 1024.0
|
92
|
+
|
93
|
+
# Return the file size with a readable style.
|
94
|
+
def readable_file_size(size, precision)
|
95
|
+
case
|
96
|
+
#when size == 1 then "1 B"
|
97
|
+
when size < KILO_SIZE then "%d B" % size
|
98
|
+
when size < MEGA_SIZE then "%.#{precision}f K" % (size / KILO_SIZE)
|
99
|
+
when size < GIGA_SIZE then "%.#{precision}f M" % (size / MEGA_SIZE)
|
100
|
+
else "%.#{precision}f G" % (size / GIGA_SIZE)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
def date_format t
|
104
|
+
t.strftime "%Y/%m/%d"
|
105
|
+
end
|
106
|
+
def format_string fn, path,stat
|
107
|
+
max_len = 30
|
108
|
+
f = fn.dup
|
109
|
+
if File.directory? path
|
110
|
+
#"%-*s\t(dir)" % [max_len,f]
|
111
|
+
#f = "/"+f # disallows search on keypress
|
112
|
+
f = "/"+f
|
113
|
+
end
|
114
|
+
if f.size > max_len
|
115
|
+
f = f[0..max_len-1]
|
116
|
+
end
|
117
|
+
"%-*s %10s %s" % [max_len,f, readable_file_size(stat.size,1), date_format(stat.mtime)]
|
118
|
+
end
|
119
|
+
# ADD HERE
|
120
|
+
end
|
121
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
# this is a test program, tests out tabbed panes. type F1 to exit
|
2
|
+
#
|
3
|
+
require 'logger'
|
4
|
+
require 'rbcurse'
|
5
|
+
require 'rbcurse/core/widgets/rtabbedpane'
|
6
|
+
require 'rbcurse/core/widgets/rcontainer'
|
7
|
+
require 'rbcurse/core/widgets/rcombo'
|
8
|
+
require 'rbcurse/core/widgets/rtabbedwindow'
|
9
|
+
|
10
|
+
include RubyCurses
|
11
|
+
class SetupTabbedPane
|
12
|
+
def run
|
13
|
+
$config_hash ||= Variable.new Hash.new
|
14
|
+
#configvar.update_command(){ |v| $config_hash[v.source()] = v.value }
|
15
|
+
|
16
|
+
r = Container.new nil, :suppress_borders => true
|
17
|
+
l1 = Label.new nil, :name => "profile", :attr => 'bold', :text => "Profile"
|
18
|
+
f1 = Field.new nil, :name => "name", :maxlen => 20, :display_length => 20, :bgcolor => :white,
|
19
|
+
:color => :black, :text => "abc", :label => ' Name: '
|
20
|
+
f2 = Field.new nil, :name => "email", :display_length => 20, :bgcolor => :white,
|
21
|
+
:color => :blue, :text => "me@google.com", :label => 'Email: '
|
22
|
+
f3 = RadioButton.new nil, :variable => $config_hash, :text => "red", :value => "RED", :color => :red
|
23
|
+
f4 = RadioButton.new nil, :variable => $config_hash, :text => "blue", :value => "BLUE", :color => :blue
|
24
|
+
f5 = RadioButton.new nil, :variable => $config_hash, :text => "green", :value => "GREEN", :color => :green
|
25
|
+
r.add(l1,f1)
|
26
|
+
r.add(f2)
|
27
|
+
r.add(f3,f4,f5)
|
28
|
+
|
29
|
+
tp = TabbedWindow.new :row => 3, :col => 7, :width => 60, :height => 20 do
|
30
|
+
title "User Setup"
|
31
|
+
button_type :ok_apply_cancel
|
32
|
+
tab "&Profile" do
|
33
|
+
item Field.new nil, :row => 2, :col => 2, :text => "enter your name", :label => ' Name: '
|
34
|
+
item Field.new nil, :row => 3, :col => 2, :text => "enter your email", :label => 'Email: '
|
35
|
+
end
|
36
|
+
tab "&Settings" do
|
37
|
+
item Label.new nil, :text => "Text", :row => 1, :col => 2, :attr => 'bold'
|
38
|
+
item CheckBox.new nil, :row => 2, :col => 2, :text => "Antialias text"
|
39
|
+
item CheckBox.new nil, :row => 3, :col => 2, :text => "Use bold fonts"
|
40
|
+
item CheckBox.new nil, :row => 4, :col => 2, :text => "Allow blinking text"
|
41
|
+
item CheckBox.new nil, :row => 5, :col => 2, :text => "Display ANSI Colors"
|
42
|
+
item Label.new nil, :text => "Cursor", :row => 7, :col => 2, :attr => 'bold'
|
43
|
+
$config_hash.set_value Variable.new, :cursor
|
44
|
+
item RadioButton.new nil, :row => 8, :col => 2, :text => "Block", :value => "block", :variable => $config_hash[:cursor]
|
45
|
+
item RadioButton.new nil, :row => 9, :col => 2, :text => "Blink", :value => "blink", :variable => $config_hash[:cursor]
|
46
|
+
item RadioButton.new nil, :row => 10, :col => 2, :text => "Underline", :value => "underline", :variable => $config_hash[:cursor]
|
47
|
+
end
|
48
|
+
tab "&Term" do
|
49
|
+
|
50
|
+
item Label.new nil, :text => "Arrow Key in Combos", :row => 2, :col => 2, :attr => 'bold'
|
51
|
+
x = Variable.new
|
52
|
+
$config_hash.set_value x, :term
|
53
|
+
item RadioButton.new nil, :row => 3, :col => 2, :text => "ignore", :value => "ignore", :variable => $config_hash[:term]
|
54
|
+
item RadioButton.new nil, :row => 4, :col => 2, :text => "popup", :value => "popup", :variable => $config_hash[:term]
|
55
|
+
item RadioButton.new nil, :row => 5, :col => 2, :text => "next", :value => "next", :variable => $config_hash[:term]
|
56
|
+
cb = ComboBox.new nil, :row => 7, :col => 2, :display_length => 15,
|
57
|
+
:list => %w[xterm xterm-color xterm-256color screen vt100 vt102],
|
58
|
+
:label => "Declare terminal as: "
|
59
|
+
#radio.update_command() {|rb| ENV['TERM']=rb.value }
|
60
|
+
item cb
|
61
|
+
x.update_command do |rb|
|
62
|
+
cb.arrow_key_policy=rb.value.to_sym
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
tab "Conta&iner" do
|
67
|
+
item r
|
68
|
+
end
|
69
|
+
# tell tabbedpane what to do if a button is pressed (ok/apply/cancel)
|
70
|
+
command do |eve|
|
71
|
+
alert "user pressed button index:#{eve.event} , Name: #{eve.action_command}, Tab: #{eve.source.current_tab} "
|
72
|
+
case eve.event
|
73
|
+
when 0,2 # ok cancel
|
74
|
+
throw :close, eve.event
|
75
|
+
when 1 # apply
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
tp.run
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
if $0 == __FILE__
|
84
|
+
# Initialize curses
|
85
|
+
begin
|
86
|
+
# XXX update with new color and kb
|
87
|
+
VER::start_ncurses # this is initializing colors via ColorMap.setup
|
88
|
+
$log = Logger.new((File.join(ENV["LOGDIR"] || "./" ,"rbc13.log")))
|
89
|
+
$log.level = Logger::DEBUG
|
90
|
+
tp = SetupTabbedPane.new()
|
91
|
+
buttonindex = tp.run
|
92
|
+
rescue => ex
|
93
|
+
ensure
|
94
|
+
VER::stop_ncurses
|
95
|
+
p ex if ex
|
96
|
+
p(ex.backtrace.join("\n")) if ex
|
97
|
+
$log.debug( ex) if ex
|
98
|
+
$log.debug(ex.backtrace.join("\n")) if ex
|
99
|
+
end
|
100
|
+
end
|
data/examples/rfe.rb
ADDED
@@ -0,0 +1,1236 @@
|
|
1
|
+
#####################################################
|
2
|
+
# This is a sample program demonstrating a 2 pane file explorer using
|
3
|
+
# rbcurse's widgets.
|
4
|
+
# I have used a listbox here, perhaps a Table would be more configurable
|
5
|
+
# than a listbox.
|
6
|
+
#
|
7
|
+
# FIXME many popups use the old Messagebox which will crash. i've updated
|
8
|
+
# grep not the others.
|
9
|
+
# Copyright rkumar 2009, 2010 under Ruby License.
|
10
|
+
#
|
11
|
+
####################################################
|
12
|
+
require 'rbcurse'
|
13
|
+
require 'rbcurse/core/widgets/rcombo'
|
14
|
+
require 'rbcurse/extras/widgets/rlistbox'
|
15
|
+
require './inc/rfe_renderer'
|
16
|
+
require 'rbcurse/core/widgets/keylabelprinter'
|
17
|
+
require 'rbcurse/core/widgets/applicationheader'
|
18
|
+
require 'rbcurse/core/include/action'
|
19
|
+
require 'fileutils'
|
20
|
+
require 'yaml' ## added for 1.9
|
21
|
+
#$LOAD_PATH << "/Users/rahul/work/projects/rbcurse/"
|
22
|
+
|
23
|
+
# TODO
|
24
|
+
# operations on selected files: move, delete, zip, copy
|
25
|
+
# - delete should move to Trash if exists - DONE
|
26
|
+
# global - don't ask confirm
|
27
|
+
# Select based on pattern.
|
28
|
+
# This class represents the finder pane. There are 2
|
29
|
+
# on this sample app
|
30
|
+
# NOTE: rfe_renderer uses entries so you may need to sync it with list_data_model
|
31
|
+
# actually, renderer should refer back to list data model!
|
32
|
+
class FileExplorer
|
33
|
+
include FileUtils
|
34
|
+
attr_reader :wdir
|
35
|
+
attr_reader :list # listbox
|
36
|
+
attr_reader :dir
|
37
|
+
attr_reader :prev_dirs
|
38
|
+
attr_reader :other_list # the opposite list
|
39
|
+
attr_reader :entries # avoid, can be outdated
|
40
|
+
attr_accessor :filter_pattern
|
41
|
+
|
42
|
+
def initialize form, rfe, row, col, height, width
|
43
|
+
@form = form
|
44
|
+
@rfe = rfe
|
45
|
+
@row, @col, @ht, @wid = row, col, height, width
|
46
|
+
@dir = Dir.new(Dir.getwd)
|
47
|
+
@wdir = @dir.path
|
48
|
+
@filter_pattern = '*'
|
49
|
+
@prev_dirs=[]
|
50
|
+
@inside_block = false
|
51
|
+
$entry_count = 0 # just for show... may not be accurate after deletes etc
|
52
|
+
|
53
|
+
end
|
54
|
+
def title str
|
55
|
+
@list.title = str
|
56
|
+
end
|
57
|
+
def selected_color
|
58
|
+
@list.selected_color
|
59
|
+
end
|
60
|
+
def selected_bgcolor
|
61
|
+
@list.selected_bgcolor
|
62
|
+
end
|
63
|
+
|
64
|
+
# changes to given dir
|
65
|
+
# ensure that path is provided since other list
|
66
|
+
# may have cd'd elsewhere
|
67
|
+
def change_dir adir
|
68
|
+
list = @list
|
69
|
+
begin
|
70
|
+
#dir = File.expand_path dir
|
71
|
+
#cd "#{@dir.path}/#{adir}"
|
72
|
+
cd adir
|
73
|
+
list.title = pwd()
|
74
|
+
@dir = Dir.new(Dir.getwd)
|
75
|
+
@wdir = @dir.path
|
76
|
+
@prev_dirs << @wdir
|
77
|
+
rescan
|
78
|
+
rescue => err
|
79
|
+
@rfe.status_row.text = err.to_s
|
80
|
+
end
|
81
|
+
end
|
82
|
+
def goto_previous_dir
|
83
|
+
#alert "Previous dirs contain #{@prev_dirs} "
|
84
|
+
d = @prev_dirs.pop
|
85
|
+
if !d.nil? && d == @wdir
|
86
|
+
d = @prev_dirs.pop
|
87
|
+
end
|
88
|
+
d = @wdir unless d # for those cases where we are showing some result and user doesn't know how t get back
|
89
|
+
change_dir d unless d.nil?
|
90
|
+
end
|
91
|
+
def filter list
|
92
|
+
list.delete_if { |f|
|
93
|
+
!File.directory? @wdir +"/"+ f and !File.fnmatch?(@filter_pattern, f)
|
94
|
+
}
|
95
|
+
#$log.debug " FILTER CALLED AFTER #{list.size}, #{list.entries}"
|
96
|
+
end
|
97
|
+
def rescan
|
98
|
+
flist = @dir.entries
|
99
|
+
$entry_count = flist.size # just for show... may not be accurate after deletes etc
|
100
|
+
flist.shift
|
101
|
+
#populate @entries
|
102
|
+
populate flist
|
103
|
+
end
|
104
|
+
def populate flist
|
105
|
+
#fl << format_string("..", nil)
|
106
|
+
#fl = []
|
107
|
+
#flist.each {|f| ff = "#{@wdir}/#{f}"; stat = File.stat(ff)
|
108
|
+
# fl << format_string(f, stat)
|
109
|
+
#}
|
110
|
+
filter(flist) if @filter_pattern != '*'
|
111
|
+
@entries = flist
|
112
|
+
list.list_data_model.remove_all
|
113
|
+
#list.list_data_model.insert 0, *fl
|
114
|
+
list.list_data_model.insert 0, *flist
|
115
|
+
list.set_form_row
|
116
|
+
#$entry_count = list.size # just for show... may not be accurate after deletes etc
|
117
|
+
end
|
118
|
+
def sort key, reverse=false
|
119
|
+
# remove parent before sorting, keep at top
|
120
|
+
first = @entries.delete_at(0) if @entries[0]==".."
|
121
|
+
key ||= @sort_key
|
122
|
+
cdir=cur_dir()+"/"
|
123
|
+
case key
|
124
|
+
when :size
|
125
|
+
@entries.sort! {|x,y| xs = File.stat(cdir+x); ys = File.stat(cdir+y);
|
126
|
+
if reverse
|
127
|
+
xs.size <=> ys.size
|
128
|
+
else
|
129
|
+
ys.size <=> xs.size
|
130
|
+
end
|
131
|
+
}
|
132
|
+
when :mtime
|
133
|
+
@entries.sort! {|x,y| xs = File.stat(cdir+x); ys = File.stat(cdir+y);
|
134
|
+
if reverse
|
135
|
+
xs.mtime <=> ys.mtime
|
136
|
+
else
|
137
|
+
ys.mtime <=> xs.mtime
|
138
|
+
end
|
139
|
+
}
|
140
|
+
when :atime
|
141
|
+
@entries.sort! {|x,y| xs = File.stat(cdir+x); ys = File.stat(cdir+y);
|
142
|
+
if reverse
|
143
|
+
xs.atime <=> ys.atime
|
144
|
+
else
|
145
|
+
ys.atime <=> xs.atime
|
146
|
+
end
|
147
|
+
}
|
148
|
+
when :name
|
149
|
+
@entries.sort! {|x,y| x <=> y
|
150
|
+
if reverse
|
151
|
+
x <=> y
|
152
|
+
else
|
153
|
+
y <=> x
|
154
|
+
end
|
155
|
+
}
|
156
|
+
when :ext
|
157
|
+
@entries.sort! {|x,y|
|
158
|
+
if reverse
|
159
|
+
File.extname(cdir+x) <=> File.extname(cdir+y)
|
160
|
+
else
|
161
|
+
File.extname(cdir+y) <=> File.extname(cdir+x)
|
162
|
+
end
|
163
|
+
}
|
164
|
+
end
|
165
|
+
@sort_key = key
|
166
|
+
@entries.insert 0, first unless first.nil? # keep parent on top
|
167
|
+
populate @entries
|
168
|
+
end
|
169
|
+
GIGA_SIZE = 1073741824.0
|
170
|
+
MEGA_SIZE = 1048576.0
|
171
|
+
KILO_SIZE = 1024.0
|
172
|
+
|
173
|
+
# Return the file size with a readable style.
|
174
|
+
def readable_file_size(size, precision)
|
175
|
+
case
|
176
|
+
#when size == 1 : "1 B"
|
177
|
+
when size < KILO_SIZE then "%d B" % size
|
178
|
+
when size < MEGA_SIZE then "%.#{precision}f K" % (size / KILO_SIZE)
|
179
|
+
when size < GIGA_SIZE then "%.#{precision}f M" % (size / MEGA_SIZE)
|
180
|
+
else "%.#{precision}f G" % (size / GIGA_SIZE)
|
181
|
+
end
|
182
|
+
end
|
183
|
+
def date_format t
|
184
|
+
t.strftime "%Y/%m/%d"
|
185
|
+
end
|
186
|
+
def oldformat_string fn, stat
|
187
|
+
max_len = 30
|
188
|
+
f = fn.dup
|
189
|
+
if File.directory? f
|
190
|
+
#"%-*s\t(dir)" % [max_len,f]
|
191
|
+
#f = "/"+f # disallows search on keypress
|
192
|
+
f = f + "/ "
|
193
|
+
end
|
194
|
+
if f.size > max_len
|
195
|
+
f = f[0..max_len-1]
|
196
|
+
end
|
197
|
+
"%-*s\t%10s\t%s" % [max_len,f, readable_file_size(stat.size,1), date_format(stat.mtime)]
|
198
|
+
end
|
199
|
+
def cur_dir
|
200
|
+
@dir.path
|
201
|
+
end
|
202
|
+
alias :current_dir :cur_dir
|
203
|
+
def draw_screen dir=nil
|
204
|
+
# I get an error here if dir in yaml file is non-existent, like deleted or copied from another machine
|
205
|
+
# 2010-08-22 19:25
|
206
|
+
if dir
|
207
|
+
if File.exists?(dir) && File.directory?(dir)
|
208
|
+
cd dir unless dir.nil?
|
209
|
+
else
|
210
|
+
dir = nil
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
wdir = FileUtils.pwd
|
215
|
+
@prev_dirs << wdir
|
216
|
+
@dir = Dir.new(Dir.getwd)
|
217
|
+
@wdir = @dir.path
|
218
|
+
r = @row
|
219
|
+
c = @col
|
220
|
+
#cola = 1
|
221
|
+
#colb = Ncurses.COLS/2
|
222
|
+
ht = @ht
|
223
|
+
wid = @wid
|
224
|
+
#fl = Dir.glob(default_pattern)
|
225
|
+
#flist << format_string("..", nil)
|
226
|
+
fl = @dir.entries
|
227
|
+
fl.shift
|
228
|
+
filter(fl)
|
229
|
+
#flist = []
|
230
|
+
#fl.each {|f| stat = File.stat(f)
|
231
|
+
# flist << format_string(f, stat)
|
232
|
+
#}
|
233
|
+
@entries = fl
|
234
|
+
$entry_count = @entries.size
|
235
|
+
title = pwd()
|
236
|
+
@wdir = title
|
237
|
+
rfe = self
|
238
|
+
|
239
|
+
lista = Listbox.new @form do
|
240
|
+
name "lista"
|
241
|
+
row r
|
242
|
+
col c
|
243
|
+
width wid
|
244
|
+
height ht
|
245
|
+
#list flist
|
246
|
+
list fl
|
247
|
+
title wdir
|
248
|
+
#title_attrib 'reverse'
|
249
|
+
cell_renderer RfeRenderer.new "", {"color"=>@color, "bgcolor"=>@bgcolor, "parent" => rfe, "display_length"=> wid-2}
|
250
|
+
KEY_ROW_SELECTOR 0 # C-space since space used for preview
|
251
|
+
end
|
252
|
+
@list = lista
|
253
|
+
lista.bind(:ENTER) {|l| @rfe.current_list(self); l.title_attrib 'reverse'; }
|
254
|
+
lista.bind(:LEAVE) {|l| l.title_attrib 'normal'; }
|
255
|
+
|
256
|
+
|
257
|
+
#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 }
|
258
|
+
row_cmd = lambda {|lb, list| file = list.entries[lb.current_index]; @rfe.status_row.text = file; # File.stat("#{cur_dir()}/#{file}").inspect
|
259
|
+
}
|
260
|
+
lista.bind(:ENTER_ROW, self) {|lb,list| row_cmd.call(lb,list) }
|
261
|
+
|
262
|
+
end
|
263
|
+
def list_data
|
264
|
+
@list.list_data_model
|
265
|
+
end
|
266
|
+
def current_index
|
267
|
+
@list.current_index
|
268
|
+
end
|
269
|
+
def filename ix=current_index()
|
270
|
+
#@entries[@list.current_index]
|
271
|
+
list_data()[ix]
|
272
|
+
end
|
273
|
+
def filepath ix=current_index()
|
274
|
+
f = filename(ix)
|
275
|
+
return unless f
|
276
|
+
if f[0,1]=='/'
|
277
|
+
f
|
278
|
+
else
|
279
|
+
cur_dir() + "/" + f
|
280
|
+
end
|
281
|
+
end
|
282
|
+
# delete the item at position i
|
283
|
+
def delete_at i=@list.current_index
|
284
|
+
ret = @list.list_data_model.delete_at i
|
285
|
+
ret = @entries.delete_at i
|
286
|
+
end
|
287
|
+
def delete obj
|
288
|
+
ret = @list.list_data_model.delete obj
|
289
|
+
ret = @entries.delete_at obj
|
290
|
+
end
|
291
|
+
def insert_at obj, ix = @list.current_index
|
292
|
+
@list.list_data_model.insert ix, f
|
293
|
+
@entries.insert ix, obj
|
294
|
+
end
|
295
|
+
def remove_selected_rows
|
296
|
+
rows = @list.selected_rows
|
297
|
+
rows=rows.sort! {|x,y| y <=> x }
|
298
|
+
rows.each do |i|
|
299
|
+
ret = @list.list_data_model.delete_at i
|
300
|
+
ret = @entries.delete_at i
|
301
|
+
end
|
302
|
+
end
|
303
|
+
|
304
|
+
# ADD
|
305
|
+
end
|
306
|
+
class RFe
|
307
|
+
attr_reader :status_row
|
308
|
+
def initialize
|
309
|
+
@window = VER::Window.root_window
|
310
|
+
@form = Form.new @window
|
311
|
+
# made in invisible since i am using chunks to print. however, we do set this variable
|
312
|
+
status_row = RubyCurses::Label.new @form, {'text' => "", :row => Ncurses.LINES-4, :col => 0, :display_length=>Ncurses.COLS-2, :visible => false}
|
313
|
+
@status_row = status_row
|
314
|
+
colb = Ncurses.COLS/2
|
315
|
+
ht = Ncurses.LINES - 4
|
316
|
+
wid = Ncurses.COLS/2 - 0
|
317
|
+
@trash_path = File.expand_path("~/.Trash")
|
318
|
+
@trash_exists = File.directory? @trash_path
|
319
|
+
$log.debug " trash_path #{@trash_path}, #{@trash_exists}"
|
320
|
+
@lista = FileExplorer.new @form, self, row=1, col=1, ht, wid
|
321
|
+
@listb = FileExplorer.new @form, self, row=1, col=colb, ht, wid
|
322
|
+
|
323
|
+
init_vars
|
324
|
+
end
|
325
|
+
def init_vars
|
326
|
+
@bookmarks=[]
|
327
|
+
@config_name = File.expand_path("~/.rfe.yml")
|
328
|
+
if File.exist? @config_name
|
329
|
+
@config = YAML::load( File.open(@config_name));
|
330
|
+
if !@config.nil?
|
331
|
+
@bookmarks = @config["bookmarks"]||[]
|
332
|
+
@last_dirs = @config["last_dirs"]
|
333
|
+
end
|
334
|
+
end
|
335
|
+
@config ||={}
|
336
|
+
@stopping = false
|
337
|
+
end
|
338
|
+
def save_config
|
339
|
+
@config["last_dirs"]=[@lista.current_dir(),@listb.current_dir()]
|
340
|
+
File.open(@config_name, "w") { | f | YAML.dump( @config, f )}
|
341
|
+
end
|
342
|
+
def move
|
343
|
+
fp = @current_list.filepath #.gsub(' ',"\ ")
|
344
|
+
fn = @current_list.filename
|
345
|
+
$log.debug " FP #{fp}"
|
346
|
+
other_list = [@lista, @listb].index(@current_list)==0 ? @listb : @lista
|
347
|
+
other_dir = other_list.cur_dir
|
348
|
+
$log.debug " OL #{other_list.cur_dir}"
|
349
|
+
if @current_list.list.selected_row_count == 0
|
350
|
+
str= "#{fn}"
|
351
|
+
else
|
352
|
+
str= "#{@current_list.list.selected_row_count} files "
|
353
|
+
end
|
354
|
+
|
355
|
+
mb = RubyCurses::MessageBox.new :width => 80 do
|
356
|
+
title "Move"
|
357
|
+
message "Move #{str} to"
|
358
|
+
add Field.new :default => other_dir, :bgcolor => :cyan, :name => "name"
|
359
|
+
button_type :ok_cancel
|
360
|
+
default_button 0
|
361
|
+
end
|
362
|
+
index = mb.run
|
363
|
+
fld = mb.widget("name")
|
364
|
+
|
365
|
+
#mb = RubyCurses::MessageBox.new do
|
366
|
+
#title "Move"
|
367
|
+
#message "Move #{str} to"
|
368
|
+
#type :input
|
369
|
+
#width 80
|
370
|
+
#default_value other_dir
|
371
|
+
#button_type :ok_cancel
|
372
|
+
#default_button 0
|
373
|
+
#end
|
374
|
+
#confirm "selected :#{mb.input_value}, #{mb.selected_index}"
|
375
|
+
if index == 0
|
376
|
+
begin
|
377
|
+
if @current_list.list.selected_row_count == 0
|
378
|
+
FileUtils.move(fp, fld.text)
|
379
|
+
#ret = @current_list.list.list().delete_at @current_list.list.current_index # ???
|
380
|
+
# @current_list.entries.delete_at @current_list.current_index
|
381
|
+
@current_list.delete_at
|
382
|
+
else
|
383
|
+
each_selected_row do |f|
|
384
|
+
FileUtils.move(f, fld.text)
|
385
|
+
end
|
386
|
+
@current_list.remove_selected_rows
|
387
|
+
@current_list.list.clear_selection
|
388
|
+
end
|
389
|
+
rescue => err
|
390
|
+
textdialog err
|
391
|
+
$log.debug "XXX: Exception in rfe, move #{err.to_s} "
|
392
|
+
end
|
393
|
+
other_list.rescan
|
394
|
+
end
|
395
|
+
end
|
396
|
+
def each_selected_row #title, message, default_value
|
397
|
+
rows = @current_list.list.selected_rows
|
398
|
+
rows = rows.dup
|
399
|
+
rows.each do |i|
|
400
|
+
fp = @current_list.filepath i
|
401
|
+
#$log.debug " moving #{i}: #{fp}"
|
402
|
+
#FileUtils.move(fp, mb.input_value)
|
403
|
+
yield fp
|
404
|
+
end
|
405
|
+
end
|
406
|
+
def copy
|
407
|
+
fp = @current_list.filepath #.gsub(' ',"\ ")
|
408
|
+
fn = @current_list.filename
|
409
|
+
$log.debug " FP #{fp}"
|
410
|
+
other_list = [@lista, @listb].index(@current_list)==0 ? @listb : @lista
|
411
|
+
other_dir = other_list.cur_dir
|
412
|
+
$log.debug " OL #{other_list.cur_dir}"
|
413
|
+
if @current_list.list.selected_row_count == 0
|
414
|
+
str= "#{fn}"
|
415
|
+
else
|
416
|
+
str= "#{@current_list.list.selected_row_count} files "
|
417
|
+
end
|
418
|
+
mb = RubyCurses::MessageBox.new do
|
419
|
+
title "Copy"
|
420
|
+
message "Copy #{str} to"
|
421
|
+
type :input
|
422
|
+
width 80
|
423
|
+
default_value other_dir
|
424
|
+
button_type :ok_cancel
|
425
|
+
default_button 0
|
426
|
+
end
|
427
|
+
if mb.selected_index == 0
|
428
|
+
if @current_list.list.selected_row_count == 0
|
429
|
+
FileUtils.copy(fp, mb.input_value)
|
430
|
+
else
|
431
|
+
each_selected_row do |f|
|
432
|
+
FileUtils.copy(f, mb.input_value)
|
433
|
+
end
|
434
|
+
@current_list.list.clear_selection
|
435
|
+
end
|
436
|
+
other_list.rescan
|
437
|
+
end
|
438
|
+
end
|
439
|
+
def delete
|
440
|
+
fp = @current_list.filepath #.gsub(' ',"\ ")
|
441
|
+
fn = @current_list.filename
|
442
|
+
if @current_list.list.selected_row_count == 0
|
443
|
+
str= "#{fn}"
|
444
|
+
else
|
445
|
+
str= "#{@current_list.list.selected_row_count} files "
|
446
|
+
end
|
447
|
+
if confirm("delete #{str}")
|
448
|
+
if @current_list.list.selected_row_count == 0
|
449
|
+
if @trash_exists
|
450
|
+
FileUtils.mv fp, @trash_path
|
451
|
+
else
|
452
|
+
FileUtils.rm fp
|
453
|
+
end
|
454
|
+
ret=@current_list.delete_at
|
455
|
+
else
|
456
|
+
each_selected_row do |f|
|
457
|
+
if @trash_exists
|
458
|
+
FileUtils.mv f, @trash_path
|
459
|
+
else
|
460
|
+
FileUtils.rm f
|
461
|
+
end
|
462
|
+
end
|
463
|
+
@current_list.remove_selected_rows
|
464
|
+
@current_list.list.clear_selection
|
465
|
+
end
|
466
|
+
end
|
467
|
+
end
|
468
|
+
def copy1
|
469
|
+
fp = @current_list.filepath
|
470
|
+
fn = @current_list.filename
|
471
|
+
$log.debug " FP #{fp}"
|
472
|
+
other_list = [@lista, @listb].index(@current_list)==0 ? @listb : @lista
|
473
|
+
other_dir = other_list.cur_dir
|
474
|
+
$log.debug " OL #{other_list.cur_dir}"
|
475
|
+
str= "copy #{fn} to #{other_list.cur_dir}"
|
476
|
+
$log.debug " copy #{fp}"
|
477
|
+
#confirm "#{str}"
|
478
|
+
mb = RubyCurses::MessageBox.new do
|
479
|
+
title "Copy"
|
480
|
+
message "Copy #{fn} to"
|
481
|
+
type :input
|
482
|
+
width 60
|
483
|
+
default_value other_dir
|
484
|
+
button_type :ok_cancel
|
485
|
+
default_button 0
|
486
|
+
end
|
487
|
+
#confirm "selected :#{mb.input_value}, #{mb.selected_index}"
|
488
|
+
if mb.selected_index == 0
|
489
|
+
# need to redraw directories
|
490
|
+
FileUtils.copy(fp, mb.input_value)
|
491
|
+
other_list.rescan
|
492
|
+
end
|
493
|
+
end
|
494
|
+
## TODO : make this separate and callable with its own keylabels
|
495
|
+
# Now you can just use viewer() instead of having to write this. See Utils in rwidget.rb
|
496
|
+
def view content=nil # can throw IO errors
|
497
|
+
require 'rbcurse/core/widgets/rtextview'
|
498
|
+
wt = 0
|
499
|
+
wl = 0
|
500
|
+
wh = Ncurses.LINES-wt
|
501
|
+
ww = Ncurses.COLS-wl
|
502
|
+
if content.nil?
|
503
|
+
begin
|
504
|
+
fp = @current_list.filepath
|
505
|
+
content = get_contents(fp)
|
506
|
+
rescue => err
|
507
|
+
$log.debug err.to_s
|
508
|
+
$log.debug(err.backtrace.join("\n"))
|
509
|
+
alert err.to_s
|
510
|
+
return
|
511
|
+
end
|
512
|
+
else
|
513
|
+
fp=""
|
514
|
+
end
|
515
|
+
@layout = { :height => wh, :width => ww, :top => wt, :left => wl }
|
516
|
+
@v_window = VER::Window.new(@layout)
|
517
|
+
@v_form = RubyCurses::Form.new @v_window
|
518
|
+
@textview = TextView.new @v_form do
|
519
|
+
name "myView"
|
520
|
+
row 0
|
521
|
+
col 0
|
522
|
+
width ww
|
523
|
+
height wh-0
|
524
|
+
title fp
|
525
|
+
title_attrib 'bold'
|
526
|
+
print_footer true
|
527
|
+
footer_attrib 'bold'
|
528
|
+
end
|
529
|
+
#content = File.open(fp,"r").readlines
|
530
|
+
begin
|
531
|
+
@textview.set_content content #, :WRAP_WORD
|
532
|
+
@v_form.repaint
|
533
|
+
@v_window.wrefresh
|
534
|
+
Ncurses::Panel.update_panels
|
535
|
+
while((ch = @v_window.getchar()) != ?\C-q.getbyte(0) )
|
536
|
+
break if [ FFI::NCurses::KEY_F3 , KEY_F10 , ?q.getbyte(0) , 27, 2727].include? ch
|
537
|
+
@v_form.handle_key ch
|
538
|
+
@v_form.repaint
|
539
|
+
##@v_window.wrefresh
|
540
|
+
end
|
541
|
+
rescue => err
|
542
|
+
alert err.to_s
|
543
|
+
ensure
|
544
|
+
@v_window.destroy if !@v_window.nil?
|
545
|
+
end
|
546
|
+
end
|
547
|
+
def get_contents fp
|
548
|
+
return nil unless File.readable? fp
|
549
|
+
return Dir.new(fp).entries if File.directory? fp
|
550
|
+
case File.extname(fp)
|
551
|
+
when '.tgz','.gz'
|
552
|
+
cmd = "tar -ztvf #{fp}"
|
553
|
+
content = %x[#{cmd}]
|
554
|
+
when '.zip'
|
555
|
+
cmd = "unzip -l #{fp}"
|
556
|
+
content = %x[#{cmd}]
|
557
|
+
else
|
558
|
+
content = File.open(fp,"r").readlines
|
559
|
+
end
|
560
|
+
end
|
561
|
+
def opt_file c
|
562
|
+
fp = @current_list.filepath
|
563
|
+
fn = @current_list.filename
|
564
|
+
other_list = [@lista, @listb].index(@current_list)==0 ? @listb : @lista
|
565
|
+
case c
|
566
|
+
when 'c'
|
567
|
+
copy
|
568
|
+
when 'm'
|
569
|
+
move
|
570
|
+
when 'd'
|
571
|
+
delete
|
572
|
+
when 'u'
|
573
|
+
str= "move #{fn} to #{other_list.cur_dir}"
|
574
|
+
if confirm("#{str}")
|
575
|
+
$log.debug " MOVE #{str}"
|
576
|
+
end
|
577
|
+
when 'v'
|
578
|
+
str= "view #{fp}"
|
579
|
+
#if confirm("#{str}")==:YES
|
580
|
+
$log.debug " VIEW #{fp}"
|
581
|
+
view
|
582
|
+
#end
|
583
|
+
when 'r'
|
584
|
+
str= "ruby #{fn}"
|
585
|
+
if confirm("#{str}")
|
586
|
+
$log.debug " #{str} "
|
587
|
+
end
|
588
|
+
when 'e'
|
589
|
+
str= "edit #{fp}"
|
590
|
+
#if confirm("#{str}")==:YES
|
591
|
+
edit fp
|
592
|
+
when 'x'
|
593
|
+
str= "exec #{fp}"
|
594
|
+
exec_popup fp
|
595
|
+
when 'p'
|
596
|
+
page fp
|
597
|
+
when 'q'
|
598
|
+
qlmanage fp
|
599
|
+
end
|
600
|
+
end
|
601
|
+
def opt_dir c
|
602
|
+
fp = @current_list.filepath
|
603
|
+
fn = @current_list.filename
|
604
|
+
case c
|
605
|
+
when 'O'
|
606
|
+
# str= "copy #{fn} to #{other_list.cur_dir}"
|
607
|
+
if File.directory? @current_list.filepath
|
608
|
+
@current_list.change_dir fp
|
609
|
+
end
|
610
|
+
when 'o'
|
611
|
+
if File.directory? @current_list.filepath
|
612
|
+
@other_list.change_dir fp
|
613
|
+
end
|
614
|
+
@open_in_other = true # ???basically keep opening in other
|
615
|
+
when 'd'
|
616
|
+
str= "delete #{fn} "
|
617
|
+
if confirm("#{str}")
|
618
|
+
$log.debug " delete #{fp}"
|
619
|
+
FileUtils.rm fp
|
620
|
+
ret=@current_list.list.list_data_model.delete_at @current_list.list.current_index # ???
|
621
|
+
$log.debug " DEL RET #{ret},#{@current_list.list.current_index}"
|
622
|
+
end
|
623
|
+
when 'u'
|
624
|
+
str= "move #{fn} to #{other_list.cur_dir}"
|
625
|
+
if confirm("#{str}")
|
626
|
+
$log.debug " MOVE #{str}"
|
627
|
+
end
|
628
|
+
when 'b'
|
629
|
+
dd = @current_list.wdir
|
630
|
+
@bookmarks << dd unless @bookmarks.include? dd
|
631
|
+
when 'u'
|
632
|
+
dd = @current_list.wdir
|
633
|
+
@bookmarks.delete dd
|
634
|
+
when 'l'
|
635
|
+
@current_list.populate @bookmarks
|
636
|
+
when 's'
|
637
|
+
@config["bookmarks"] = @bookmarks
|
638
|
+
save_config
|
639
|
+
when 'e'
|
640
|
+
str= "edit #{fp}"
|
641
|
+
#if confirm("#{str}")==:YES
|
642
|
+
edit fp
|
643
|
+
when 'm'
|
644
|
+
f = get_string("Enter a directory to create", 20 )
|
645
|
+
if f != ""
|
646
|
+
FileUtils.mkdir f
|
647
|
+
@current_list.list.list_data_model.insert @current_list.list.current_index, f # ???
|
648
|
+
@current_list.entries.insert @current_list.list.current_index, f # ???
|
649
|
+
end
|
650
|
+
|
651
|
+
when 'x'
|
652
|
+
str= "exec #{fp}"
|
653
|
+
exec_popup fp
|
654
|
+
end
|
655
|
+
end
|
656
|
+
def exec_popup fp
|
657
|
+
last_exec_def1 = @last_exec_def1 || ""
|
658
|
+
last_exec_def2 = @last_exec_def2 || false
|
659
|
+
|
660
|
+
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]})
|
661
|
+
if sel == 0
|
662
|
+
@last_exec_def1 = inp
|
663
|
+
@last_exec_def2 = hash["view result"]
|
664
|
+
cmd = "#{inp} #{fp}"
|
665
|
+
filestr = %x[ #{cmd} 2>/dev/null ]
|
666
|
+
if hash["view result"]==true
|
667
|
+
view filestr
|
668
|
+
end
|
669
|
+
end
|
670
|
+
end
|
671
|
+
def edit fp=@current_list.filepath
|
672
|
+
$log.debug " edit #{fp}"
|
673
|
+
editor = ENV['EDITOR'] || 'vi'
|
674
|
+
vimp = %x[which #{editor}].chomp
|
675
|
+
shell_out "#{vimp} #{fp}"
|
676
|
+
end
|
677
|
+
|
678
|
+
# TODO we need to move these to some common file so differnt programs and demos
|
679
|
+
# can use them on pressing space or enter.
|
680
|
+
def page fp=@current_list.filepath
|
681
|
+
ft=%x[file #{fp}]
|
682
|
+
if ft.index("text")
|
683
|
+
pager = ENV['PAGER'] || 'less'
|
684
|
+
vimp = %x[which #{pager}].chomp
|
685
|
+
shell_out "#{vimp} #{fp}"
|
686
|
+
elsif ft.index(/zip/i)
|
687
|
+
shell_out "tar tvf #{fp} | less"
|
688
|
+
elsif ft.index(/directory/i)
|
689
|
+
shell_out "ls -lh #{fp} | less"
|
690
|
+
else
|
691
|
+
alert "#{fp} is not text, not paging "
|
692
|
+
#use_on_file "als", fp # only zip or archive
|
693
|
+
end
|
694
|
+
end
|
695
|
+
def qlmanage fp=@current_list.filepath
|
696
|
+
begin
|
697
|
+
a=%x[which qlmanage]
|
698
|
+
if a != ""
|
699
|
+
cmd="qlmanage -p #{@current_list.filepath} 2>/dev/null"
|
700
|
+
%x[#{cmd}]
|
701
|
+
else
|
702
|
+
alert "qlmanage not present on your system. Trying pager"
|
703
|
+
page fp
|
704
|
+
end
|
705
|
+
rescue Interrupt
|
706
|
+
rescue => err
|
707
|
+
alert err.to_s
|
708
|
+
end
|
709
|
+
end
|
710
|
+
# also if calling program gives output but does not stop
|
711
|
+
# or take control, then nothing will show up
|
712
|
+
def use_on_file prog, args, fp=@current_list.filepath
|
713
|
+
vimp = %x[which #{prog}].chomp
|
714
|
+
if vimp != ""
|
715
|
+
alert "using #{prog} "
|
716
|
+
shell_out "#{vimp} #{args } #{fp}"
|
717
|
+
else
|
718
|
+
alert "could not locate #{prog} "
|
719
|
+
end
|
720
|
+
end
|
721
|
+
def stopping?
|
722
|
+
@stopping
|
723
|
+
end
|
724
|
+
def draw_screens
|
725
|
+
lasta = lastb = nil
|
726
|
+
if !@config["last_dirs"].nil?
|
727
|
+
lasta = @config["last_dirs"][0]
|
728
|
+
lastb = @config["last_dirs"][1]
|
729
|
+
end
|
730
|
+
@lista.draw_screen lasta
|
731
|
+
@listb.draw_screen lastb
|
732
|
+
|
733
|
+
# bind dd to delete file
|
734
|
+
# actually this should be in listbox, and we should listen for row delete and then call opt_file
|
735
|
+
@form.bind_key([?d,?d], 'delete'){
|
736
|
+
opt_file 'd'
|
737
|
+
}
|
738
|
+
# list traps 'q' so this won't work
|
739
|
+
@form.bind_key([?q,?q], 'quit'){
|
740
|
+
@stopping = true
|
741
|
+
}
|
742
|
+
# this won't work since the listbox will consume the d first
|
743
|
+
@form.bind_key(?@, 'home'){
|
744
|
+
@current_list.change_dir File.expand_path("~/")
|
745
|
+
}
|
746
|
+
@form.bind_key(?^, 'previous dir'){
|
747
|
+
@current_list.change_dir @current_list.prev_dirs[0] unless @current_list.prev_dirs.empty?
|
748
|
+
}
|
749
|
+
@form.bind_key(?\C-f, 'file menu'){
|
750
|
+
@klp.mode :file
|
751
|
+
@klp.repaint
|
752
|
+
while((ch = @window.getchar()) != ?\C-c.getbyte(0) )
|
753
|
+
if ch < 33 || ch > 126
|
754
|
+
Ncurses.beep
|
755
|
+
elsif "cmdsuvrexpq".index(ch.chr) == nil
|
756
|
+
Ncurses.beep
|
757
|
+
else
|
758
|
+
opt_file ch.chr
|
759
|
+
break
|
760
|
+
end
|
761
|
+
end
|
762
|
+
@klp.mode :normal
|
763
|
+
}
|
764
|
+
# C-d has been bound to scroll-down
|
765
|
+
@form.bind_key(?\C-w, 'dir menu'){
|
766
|
+
@klp.mode :dir
|
767
|
+
@klp.repaint
|
768
|
+
keys = @klp.get_current_keys
|
769
|
+
while((ch = @window.getchar()) != ?\C-c.getbyte(0) )
|
770
|
+
if ch < 33 || ch > 126
|
771
|
+
Ncurses.beep
|
772
|
+
elsif !keys.include?(ch.chr)
|
773
|
+
Ncurses.beep
|
774
|
+
else
|
775
|
+
opt_dir ch.chr
|
776
|
+
break
|
777
|
+
end
|
778
|
+
end
|
779
|
+
@klp.mode :normal
|
780
|
+
}
|
781
|
+
# backspace KEY_BS
|
782
|
+
@form.bind_key(127, 'previous dir'){
|
783
|
+
@current_list.goto_previous_dir
|
784
|
+
}
|
785
|
+
# form gives this to list which consumes it for selection.
|
786
|
+
# need to bind to list's LIST_SELECTION_EVENT
|
787
|
+
@form.bind_key(32, 'pager'){
|
788
|
+
fp = @current_list.filepath
|
789
|
+
page fp
|
790
|
+
}
|
791
|
+
@form.bind_key(FFI::NCurses::KEY_F3, 'view'){
|
792
|
+
begin
|
793
|
+
view()
|
794
|
+
rescue => err
|
795
|
+
alert err.to_s
|
796
|
+
end
|
797
|
+
}
|
798
|
+
@form.bind_key(FFI::NCurses::KEY_F1, 'help'){
|
799
|
+
#Io.view(["this is some help text","hello there"])
|
800
|
+
color0 = get_color($promptcolor, 'black','green')
|
801
|
+
color1 = get_color($reversecolor, 'green','black')
|
802
|
+
color2 = get_color($reversecolor, 'magenta','black')
|
803
|
+
arr = []
|
804
|
+
#arr << " FILE BROWSER HELP "
|
805
|
+
arr << [color0," FILE BROWSER HELP ", FFI::NCurses::A_NORMAL]
|
806
|
+
arr << " "
|
807
|
+
arr << [[color1," <tab> ",nil],[color2, "- switch between windows", nil]]
|
808
|
+
arr << [[color1," <enter> ",nil],[color2, "- open dir", nil]]
|
809
|
+
arr << [[color1," F3 ",nil],[color2, "- view file/dir/zip contents (toggle) ", nil]]
|
810
|
+
arr << [[color1," F4 ",nil],[color2, "- edit file content", nil]]
|
811
|
+
arr << [[color1," <char> ", nil],[color2, "first file starting with <char>",nil]]
|
812
|
+
#arr << " VIM MODE "
|
813
|
+
arr << [color0," VIM MODE ", FFI::NCurses::A_NORMAL]
|
814
|
+
arr << [[color1," M",nil],[color2, "-v - Vim like bindings for navigation (toggle)", nil]]
|
815
|
+
arr << " jk gg G up down motion, C-n C-p, Alt-0, Alt-9 "
|
816
|
+
arr << [[color1," p or Space ",nil],[color2, "- use pager on current file", nil]]
|
817
|
+
arr << [[color1," q ",nil],[color2, "- use qlmanage on file ",nil],[$promptcolor, " (OSX)", nil]]
|
818
|
+
arr << [[color1," f<char> ",nil],[color2, "- first file starting with <char>", nil]]
|
819
|
+
|
820
|
+
arr << " "
|
821
|
+
arr << " < > ^ V - move help window "
|
822
|
+
arr << " "
|
823
|
+
# next line does not work due to chunks
|
824
|
+
w = arr.max_by(&:length).length
|
825
|
+
#arr = ["this is some help text","hello there"]
|
826
|
+
|
827
|
+
require 'rbcurse/core/util/viewer'
|
828
|
+
RubyCurses::Viewer.view(arr, :layout => [10,10, 4+arr.size, w+2],:close_key => KEY_RETURN, :title => "<Enter> to close", :print_footer => false) do |t|
|
829
|
+
# you may configure textview further here.
|
830
|
+
#t.suppress_borders true
|
831
|
+
#t.color = :black
|
832
|
+
#t.bgcolor = :white
|
833
|
+
# or
|
834
|
+
#t.attr = :reverse
|
835
|
+
t.attr = :normal
|
836
|
+
#t.bind_key(KEY_F1){ alert "closing up!"; throw :close }
|
837
|
+
# just for kicks move window around
|
838
|
+
t.bind_key('<'){ f = t.form.window; c = f.left - 1; f.hide; f.mvwin(f.top, c); f.show;
|
839
|
+
f.reset_layout([f.height, f.width, f.top, c]);
|
840
|
+
}
|
841
|
+
t.bind_key('>'){ f = t.form.window; c = f.left + 1; f.hide; f.mvwin(f.top, c);
|
842
|
+
f.reset_layout([f.height, f.width, f.top, c]); f.show;
|
843
|
+
}
|
844
|
+
t.bind_key('^'){ f = t.form.window; c = f.top - 1 ; f.hide; f.mvwin(c, f.left);
|
845
|
+
f.reset_layout([f.height, f.width, c, f.left]) ; f.show;
|
846
|
+
}
|
847
|
+
t.bind_key('V'){ f = t.form.window; c = f.top + 1 ; f.hide; f.mvwin(c, f.left);
|
848
|
+
f.reset_layout([f.height, f.width, c, f.left]); f.show;
|
849
|
+
}
|
850
|
+
end
|
851
|
+
}
|
852
|
+
@form.bind_key(FFI::NCurses::KEY_F4, 'edit'){
|
853
|
+
edit()
|
854
|
+
}
|
855
|
+
@form.bind_key(FFI::NCurses::KEY_F6, 'sort'){
|
856
|
+
selected_index, sort_key, reverse, case_sensitive = sort_popup
|
857
|
+
if selected_index == 0
|
858
|
+
@current_list.sort(sort_key, reverse)
|
859
|
+
end
|
860
|
+
}
|
861
|
+
@form.bind_key(FFI::NCurses::KEY_F5, 'filter'){
|
862
|
+
filter()
|
863
|
+
}
|
864
|
+
@form.bind_key(FFI::NCurses::KEY_F7, 'grep'){
|
865
|
+
grep_popup()
|
866
|
+
}
|
867
|
+
@form.bind_key(FFI::NCurses::KEY_F8, 'system'){
|
868
|
+
system_popup()
|
869
|
+
}
|
870
|
+
# will work if you are in vim mode
|
871
|
+
@form.bind_key(?p, 'pager'){
|
872
|
+
page
|
873
|
+
}
|
874
|
+
@form.bind_key(?z, 'qlmanage OSX'){
|
875
|
+
qlmanage
|
876
|
+
}
|
877
|
+
# will no longer come here. list event has to be used
|
878
|
+
#@form.bind_key(?\C-m){ # listbox has eaten it up
|
879
|
+
@lista.list.bind(:PRESS){
|
880
|
+
dir = @current_list.filepath
|
881
|
+
if File.directory? @current_list.filepath
|
882
|
+
@current_list.change_dir dir
|
883
|
+
end
|
884
|
+
}
|
885
|
+
@listb.list.bind(:PRESS){
|
886
|
+
dir = @current_list.filepath
|
887
|
+
if File.directory? @current_list.filepath
|
888
|
+
@current_list.change_dir dir
|
889
|
+
end
|
890
|
+
}
|
891
|
+
gw = get_color($reversecolor, 'green', 'black')
|
892
|
+
bw = get_color($datacolor, 'blue', 'black')
|
893
|
+
@klp = RubyCurses::KeyLabelPrinter.new @form, get_key_labels
|
894
|
+
@klp.footer_color_pair = bw
|
895
|
+
@klp.footer_mnemonic_color_pair = gw
|
896
|
+
@klp.set_key_labels get_key_labels(:file), :file
|
897
|
+
@klp.set_key_labels get_key_labels(:view), :view
|
898
|
+
@klp.set_key_labels get_key_labels(:dir), :dir
|
899
|
+
@form.repaint
|
900
|
+
@window.wrefresh
|
901
|
+
Ncurses::Panel.update_panels
|
902
|
+
begin
|
903
|
+
chunks=["File","Key"]
|
904
|
+
color0 = get_color($promptcolor, 'white','blue')
|
905
|
+
color1 = get_color($datacolor, 'black','green')
|
906
|
+
|
907
|
+
## qq stops program, but only if M-v (vim mode)
|
908
|
+
while(!stopping? && (ch = @window.getchar()) != ?\C-q.getbyte(0) )
|
909
|
+
break if ch == KEY_F10
|
910
|
+
s = keycode_tos ch
|
911
|
+
#status_row.text = "| Pressed #{ch} , #{s}"
|
912
|
+
@form.handle_key(ch)
|
913
|
+
|
914
|
+
# the following is just a test of show_colored_chunks
|
915
|
+
# Please use status_line introduced in 1.4.x
|
916
|
+
#count = @current_list.list.size
|
917
|
+
count1 = @lista.list.size
|
918
|
+
count2 = @listb.list.size
|
919
|
+
x, y = FFI::NCurses::getyx @window.get_window
|
920
|
+
chunks[0]=[color0, "%-30s" % status_row.text, FFI::NCurses::A_BOLD]
|
921
|
+
chunks[1]=[color1, "%-18s" % " | #{ch}, #{s} |", FFI::NCurses::A_NORMAL]
|
922
|
+
chunks[2]=[color0, " Total: #{count1}, #{count2}"]
|
923
|
+
@window.wmove(Ncurses.LINES-3,0)
|
924
|
+
@window.color_set(color0, nil)
|
925
|
+
@window.print_empty_line
|
926
|
+
@window.wmove(Ncurses.LINES-3,0)
|
927
|
+
@window.show_colored_chunks chunks
|
928
|
+
@window.wmove(x,y)
|
929
|
+
|
930
|
+
#@form.repaint
|
931
|
+
@window.wrefresh
|
932
|
+
end
|
933
|
+
ensure
|
934
|
+
@window.destroy if !@window.nil?
|
935
|
+
save_config
|
936
|
+
end
|
937
|
+
|
938
|
+
end
|
939
|
+
# TODO
|
940
|
+
#
|
941
|
+
#
|
942
|
+
#
|
943
|
+
|
944
|
+
# current_list
|
945
|
+
##
|
946
|
+
# getter and setter for current_list
|
947
|
+
def current_list(*val)
|
948
|
+
if val.empty?
|
949
|
+
@current_list
|
950
|
+
else
|
951
|
+
@current_list = val[0]
|
952
|
+
@other_list = [@lista, @listb].index(@current_list)==0 ? @listb : @lista
|
953
|
+
end
|
954
|
+
end
|
955
|
+
def get_key_labels categ=nil
|
956
|
+
if categ.nil?
|
957
|
+
key_labels = [
|
958
|
+
['C-q', 'Exit'], ['C-v', 'View'],
|
959
|
+
['C-f', 'File'], ['C-w', 'Dir'],
|
960
|
+
['C-Sp','Select'], ['Spc', "Preview"],
|
961
|
+
['F3', 'View'], ['F4', 'Edit'],
|
962
|
+
['F5', 'Filter'], ['F6', 'Sort'],
|
963
|
+
['F7', 'Grep'], ['F8', 'System'],
|
964
|
+
['M-0', 'Top'], ['M-9', 'End'],
|
965
|
+
['C-p', 'PgUp'], ['C-n', 'PgDn'],
|
966
|
+
['M-v', 'Vim Mode'], ['BSpc', 'PrevDir']
|
967
|
+
]
|
968
|
+
elsif categ == :file
|
969
|
+
key_labels = [
|
970
|
+
['c', 'Copy'], ['m', 'Move'],
|
971
|
+
['d', 'Delete'], ['v', 'View'],
|
972
|
+
['s', 'Select'], ['u', 'Unselect'],
|
973
|
+
['p', 'Page'], ['x', 'Exec Cmd'],
|
974
|
+
['r', 'ruby'], ['e', "Edit"],
|
975
|
+
['C-c', 'Cancel']
|
976
|
+
]
|
977
|
+
elsif categ == :view
|
978
|
+
key_labels = [
|
979
|
+
['c', 'Date'], ['m', 'Size'],
|
980
|
+
['d', 'Delete'], ['v', 'View'],
|
981
|
+
['C-c', 'Cancel']
|
982
|
+
]
|
983
|
+
elsif categ == :dir
|
984
|
+
key_labels = [
|
985
|
+
['o', 'open'], ['O', 'Open in right'],
|
986
|
+
['d', 'Delete'], ['R', 'Del Recurse'],
|
987
|
+
['t', 'tree'], ['p', 'Previous'],
|
988
|
+
['b', 'Bookmark'], ['u', 'Unbookmark'],
|
989
|
+
['l', 'List'], ['s', 'Save'],
|
990
|
+
['m', 'mkdir'], nil,
|
991
|
+
['C-c', 'Cancel']
|
992
|
+
]
|
993
|
+
end
|
994
|
+
return key_labels
|
995
|
+
end
|
996
|
+
def get_key_labels_table
|
997
|
+
key_labels = [
|
998
|
+
['M-n','NewRow'], ['M-d','DelRow'],
|
999
|
+
['C-x','Select'], nil,
|
1000
|
+
['M-0', 'Top'], ['M-9', 'End'],
|
1001
|
+
['C-p', 'PgUp'], ['C-n', 'PgDn'],
|
1002
|
+
['M-Tab','Nxt Fld'], ['Tab','Nxt Col'],
|
1003
|
+
['+','Widen'], ['-','Narrow']
|
1004
|
+
]
|
1005
|
+
return key_labels
|
1006
|
+
end
|
1007
|
+
def sort_popup
|
1008
|
+
#mform = RubyCurses::Form.new nil
|
1009
|
+
mform = nil
|
1010
|
+
field_list = []
|
1011
|
+
r = 4
|
1012
|
+
$radio = RubyCurses::Variable.new
|
1013
|
+
rtextvalue = [:name, :ext, :size, :mtime, :atime]
|
1014
|
+
["Name", "Extension", "Size", "Modify Time", "Access Time" ].each_with_index do |rtext,ix|
|
1015
|
+
field = RubyCurses::RadioButton.new mform do
|
1016
|
+
variable $radio
|
1017
|
+
text rtext
|
1018
|
+
value rtextvalue[ix]
|
1019
|
+
color 'black'
|
1020
|
+
bgcolor 'white'
|
1021
|
+
#row r
|
1022
|
+
#col 5
|
1023
|
+
end
|
1024
|
+
field_list << field
|
1025
|
+
r += 1
|
1026
|
+
end
|
1027
|
+
r = 4
|
1028
|
+
["Reverse", "case sensitive"].each do |cbtext|
|
1029
|
+
field = RubyCurses::CheckBox.new mform do
|
1030
|
+
text cbtext
|
1031
|
+
name cbtext
|
1032
|
+
color 'black'
|
1033
|
+
bgcolor 'white'
|
1034
|
+
#row r
|
1035
|
+
#col 30
|
1036
|
+
end
|
1037
|
+
field_list << field
|
1038
|
+
r += 1
|
1039
|
+
end
|
1040
|
+
mb = RubyCurses::MessageBox.new :width => 50 do
|
1041
|
+
title "Sort Options"
|
1042
|
+
button_type :ok_cancel
|
1043
|
+
default_button 0
|
1044
|
+
end
|
1045
|
+
field_list.each { |e| mb.add(e) }
|
1046
|
+
index = mb.run
|
1047
|
+
if index == 0
|
1048
|
+
$log.debug " SORT POPUP #{$radio.value}"
|
1049
|
+
#$log.debug " SORT POPUP #{mb.inspect}"
|
1050
|
+
$log.debug " SORT POPUP #{mb.widget("Reverse").value}"
|
1051
|
+
$log.debug " SORT POPUP #{mb.widget("case sensitive").value}"
|
1052
|
+
end
|
1053
|
+
return index, $radio.value, mb.widget("Reverse").value, mb.widget("case sensitive").value
|
1054
|
+
end
|
1055
|
+
def filter
|
1056
|
+
f = get_string("Enter a filter pattern", :maxlen => 20, :default => "*")
|
1057
|
+
f = "*" if f.nil? or f == ""
|
1058
|
+
@current_list.filter_pattern = f
|
1059
|
+
@current_list.rescan
|
1060
|
+
end
|
1061
|
+
|
1062
|
+
# ask user for pattern to grep through files
|
1063
|
+
# and display file names in same list
|
1064
|
+
# Please see testmessagebox.rb for cleaner ways of creating messageboxes.
|
1065
|
+
|
1066
|
+
def grep_popup
|
1067
|
+
last_regex = @last_regex || ""
|
1068
|
+
last_pattern = @last_pattern || "*"
|
1069
|
+
r = 4
|
1070
|
+
mform = nil
|
1071
|
+
field = RubyCurses::Field.new mform do
|
1072
|
+
name "regex"
|
1073
|
+
#row r
|
1074
|
+
#col 30
|
1075
|
+
set_buffer last_regex
|
1076
|
+
label 'Regex'
|
1077
|
+
#set_label Label.new @form, {'text' => 'Regex', 'col'=>5, 'mnemonic'=> 'R'}
|
1078
|
+
end
|
1079
|
+
r += 1
|
1080
|
+
field1 = RubyCurses::Field.new mform do
|
1081
|
+
name "filepattern"
|
1082
|
+
#row r
|
1083
|
+
#col 30
|
1084
|
+
set_buffer last_pattern
|
1085
|
+
label 'File Pattern'
|
1086
|
+
#set_label Label.new @form, {'text' => 'File Pattern','col'=>5, :color=>'black',:bgcolor=>'white','mnemonic'=> 'F'}
|
1087
|
+
end
|
1088
|
+
r += 1
|
1089
|
+
fields = []
|
1090
|
+
["Recurse", "case insensitive"].each do |cbtext|
|
1091
|
+
fields.push(RubyCurses::CheckBox.new(mform) do
|
1092
|
+
text cbtext
|
1093
|
+
name cbtext
|
1094
|
+
#color 'black'
|
1095
|
+
#bgcolor 'white'
|
1096
|
+
#row r
|
1097
|
+
#col 5
|
1098
|
+
end
|
1099
|
+
)
|
1100
|
+
r += 1
|
1101
|
+
end
|
1102
|
+
mb = RubyCurses::MessageBox.new :width => 50 do
|
1103
|
+
title "Grep Options"
|
1104
|
+
button_type :ok_cancel
|
1105
|
+
default_button 0
|
1106
|
+
item field
|
1107
|
+
item field1
|
1108
|
+
item fields.first
|
1109
|
+
item fields.last
|
1110
|
+
end
|
1111
|
+
selected_index = mb.run
|
1112
|
+
if selected_index == 0
|
1113
|
+
return if mb.form.by_name["regex"].getvalue()==""
|
1114
|
+
@last_regex = mb.form.by_name["regex"].getvalue
|
1115
|
+
inp = mb.form.by_name["regex"].getvalue
|
1116
|
+
fp = mb.form.by_name["filepattern"].getvalue
|
1117
|
+
@last_pattern = fp
|
1118
|
+
flags=""
|
1119
|
+
#flags << " -i " if mb.form.by_name["case insensitive"].value==true
|
1120
|
+
#flags << " -R " if mb.form.by_name["Recurse"].value==true
|
1121
|
+
flags << " -i " if fields[0].value==true
|
1122
|
+
flags << " -R " if fields[1].value==true
|
1123
|
+
# sometimes grep pukes "No such file or directory if you specify some
|
1124
|
+
# filespec that is not present. I don't want it to come in filestr
|
1125
|
+
# so i am not piping stderr to stdout
|
1126
|
+
cmd = "cd #{@current_list.cur_dir()};grep -l #{flags} #{inp} #{fp}"
|
1127
|
+
filestr = %x[ #{cmd} ]
|
1128
|
+
files = nil
|
1129
|
+
files = filestr.split(/\n/) unless filestr.nil?
|
1130
|
+
#view filestr
|
1131
|
+
if !files || files.empty?
|
1132
|
+
alert "Sorry! No files for regex #{inp}"
|
1133
|
+
return
|
1134
|
+
end
|
1135
|
+
@current_list.title "grep #{inp}"
|
1136
|
+
@current_list.populate files
|
1137
|
+
# Use backspace to go back
|
1138
|
+
end
|
1139
|
+
return selected_index, mb.form.by_name["regex"].getvalue, mb.form.by_name["filepattern"].getvalue, fields[1].value, fields[0].value
|
1140
|
+
end
|
1141
|
+
|
1142
|
+
def system_popup
|
1143
|
+
deflt = @last_system || ""
|
1144
|
+
options=["run in shell","view output","file explorer"]
|
1145
|
+
#inp = get_string("Enter a system command", 30, deflt)
|
1146
|
+
|
1147
|
+
mb = MessageBox.new :title => "System Command" , :width => 80 do
|
1148
|
+
add Field.new :label => 'Enter command', :name => "cmd", :display_length => 50, :bgcolor => :cyan,
|
1149
|
+
:text => deflt
|
1150
|
+
$radio = RubyCurses::Variable.new
|
1151
|
+
add RadioButton.new :text => "run in shell", :color => :blue, :variable => $radio
|
1152
|
+
add RadioButton.new :text => "view output", :color => :red, :variable => $radio
|
1153
|
+
add RadioButton.new :text => "file explorer", :color => :red, :variable => $radio
|
1154
|
+
button_type :ok_cancel
|
1155
|
+
end
|
1156
|
+
sel = mb.run
|
1157
|
+
inp = mb.widget("cmd").text
|
1158
|
+
$log.debug "XXX: value of radio is #{$radio.value}, inp : #{inp} "
|
1159
|
+
#sel, inp, hash = get_string_with_options("Enter a system command", 40, deflt, {"radiobuttons" => options, "radio_default"=>@last_system_radio || options[0]})
|
1160
|
+
if sel == 0
|
1161
|
+
if !inp.nil?
|
1162
|
+
@last_system = inp
|
1163
|
+
@last_system_radio = $radio.value
|
1164
|
+
case $radio.value
|
1165
|
+
when options[0]
|
1166
|
+
shell_out inp
|
1167
|
+
when options[1]
|
1168
|
+
filestr = %x[ #{inp} ]
|
1169
|
+
view filestr
|
1170
|
+
when options[2]
|
1171
|
+
filestr = %x[ #{inp} ]
|
1172
|
+
files = nil
|
1173
|
+
files = filestr.split(/\n/) unless filestr.nil?
|
1174
|
+
@current_list.title inp
|
1175
|
+
@current_list.populate files
|
1176
|
+
$log.debug " SYSTEM got #{files.size}, #{files.inspect}"
|
1177
|
+
else
|
1178
|
+
shell_out inp
|
1179
|
+
end
|
1180
|
+
end
|
1181
|
+
end
|
1182
|
+
end
|
1183
|
+
# This will notwork, dunno if its being called
|
1184
|
+
def popup
|
1185
|
+
deflt = @last_regexp || ""
|
1186
|
+
#sel, inp, hash = get_string_with_options("Enter a filter pattern", 20, "*", {"checkboxes" => ["case sensitive","reverse"], "checkbox_defaults"=>[true, false]})
|
1187
|
+
sel, inp, hash = get_string_with_options("Enter a grep pattern", 20, deflt, {"checkboxes" => ["case insensitive","not-including"]})
|
1188
|
+
if sel == 0
|
1189
|
+
@last_regexp = inp
|
1190
|
+
flags=""
|
1191
|
+
flags << " -i " if hash["case insensitive"]==true
|
1192
|
+
flags << " -v " if hash["not-including"]==true
|
1193
|
+
cmd = "grep -l #{flags} #{inp} *"
|
1194
|
+
filestr = %x[ #{cmd} ]
|
1195
|
+
files = nil
|
1196
|
+
files = filestr.split(/\n/) unless filestr.nil?
|
1197
|
+
view filestr
|
1198
|
+
end
|
1199
|
+
$log.debug " POPUP: #{sel}: #{inp}, #{hash['case sensitive']}, #{hash['reverse']}"
|
1200
|
+
end
|
1201
|
+
# This won't work if you do something like 'ls -l', you will need to do 'ls -l | less'
|
1202
|
+
def shell_out command
|
1203
|
+
@window.hide
|
1204
|
+
Ncurses.endwin
|
1205
|
+
ret = system command
|
1206
|
+
Ncurses.refresh
|
1207
|
+
#Ncurses.curs_set 0 # why ?
|
1208
|
+
@window.show
|
1209
|
+
ret
|
1210
|
+
end
|
1211
|
+
end
|
1212
|
+
if $0 == __FILE__
|
1213
|
+
include RubyCurses
|
1214
|
+
include RubyCurses::Utils
|
1215
|
+
|
1216
|
+
begin
|
1217
|
+
# Initialize curses
|
1218
|
+
VER::start_ncurses # this is initializing colors via ColorMap.setup
|
1219
|
+
#$log = Logger.new("rbc13.log")
|
1220
|
+
$log = Logger.new(ENV['LOGDIR'] || "" + "rbc13.log")
|
1221
|
+
|
1222
|
+
$log.level = Logger::DEBUG
|
1223
|
+
|
1224
|
+
catch(:close) do
|
1225
|
+
t = RFe.new
|
1226
|
+
t.draw_screens
|
1227
|
+
end
|
1228
|
+
rescue => ex
|
1229
|
+
ensure
|
1230
|
+
VER::stop_ncurses
|
1231
|
+
p ex if ex
|
1232
|
+
p(ex.backtrace.join("\n")) if ex
|
1233
|
+
$log.debug( ex) if ex
|
1234
|
+
$log.debug(ex.backtrace.join("\n")) if ex
|
1235
|
+
end
|
1236
|
+
end
|