unixcmd 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ OTdhMmZkYzFhNGI4YWY4MTFiZDA3MjM3NWY3ZmU3ZDEzZTk0OTI2OQ==
5
+ data.tar.gz: !binary |-
6
+ NTcwNDMzOWZmMDMxNGMyNDlkNWM5ZGVhYTE2MDVlOTBmZjY0MjRjNA==
7
+ !binary "U0hBNTEy":
8
+ metadata.gz: !binary |-
9
+ YjNmOTcyYmEzYjUwMWU2ZTRiNWYyZDMzNmJlMTUyYzEyYTkxNTQ3MDA3ZTBk
10
+ MTNiZGY4ZWMyNGYyZTFlN2NlMTQxNTIyMmI4NGVlMjQzYjNiMDFlY2RlYzJl
11
+ YTJjZTIwZWYwNmNhMjhkYzIzNzQ0MGI1MGZlN2NlMjk1ZDU4YzY=
12
+ data.tar.gz: !binary |-
13
+ Mjg4YzE0YjFlZjlkYWE0Nzk0ZWMwOGNiMWVkMjhhZGEwMWIzN2JiMTYxOWUz
14
+ MDBjM2Y0YTZmOTgyMjQ0MDBmNmU5NmJkMmFmZDY5ZWQxOTI2OGZmZTk2MTBh
15
+ MzExMDMxZGQ1MjcwNGIwYTI2YTg0Y2U4NmUwMzIyYjNkNzU2ZDA=
data/bin/unixcmd ADDED
@@ -0,0 +1,96 @@
1
+ #!/usr/bin/ruby19
2
+
3
+ require 'gtk2'
4
+ require 'open3'
5
+
6
+ require 'unixcmd/panel'
7
+ require 'unixcmd/version'
8
+ require 'unixcmd/config'
9
+
10
+
11
+ class CmdWnd < Gtk::Window
12
+ @vbox
13
+ @btnpanel
14
+ @panes
15
+ @left
16
+ @right
17
+
18
+ def left() @left end
19
+ def right() @right end
20
+
21
+ def initialize
22
+ super
23
+
24
+ set_title APP_NAME + ' ' + APP_VERSION
25
+
26
+ set_border_width 5
27
+
28
+ @vbox = Gtk::VBox.new
29
+ @panes = Gtk::HPaned.new
30
+ @left = CmdPanelWidget.new
31
+ @right = CmdPanelWidget.new
32
+
33
+ @panes.pack1 @left, true, true
34
+ @panes.pack2 @right, true, true
35
+
36
+ @vbox.pack_start @panes, true
37
+
38
+ add @vbox
39
+
40
+ signal_connect('destroy') { destroy }
41
+
42
+ self.focus_chain = [@left, @right]
43
+
44
+ set_default_size 1024, 768
45
+ show_all
46
+ end
47
+
48
+ def curpanel
49
+ return @left if self.focus.parent.parent.parent == @left
50
+ @right
51
+ end
52
+
53
+ def otherpanel
54
+ return @left if self.focus.parent.parent.parent == @right
55
+ @right
56
+ end
57
+
58
+ def selected_file
59
+ curpanel().path + curpanel().selection[0]
60
+ end
61
+
62
+ def destroy
63
+ Gtk.main_quit
64
+ end
65
+ end
66
+
67
+
68
+ GLib::Thread.init
69
+ Gdk::Threads.init
70
+ Gdk::Threads.enter
71
+
72
+ Gtk::AccelMap.add_entry '<unixcmd>/panel/reload', Gdk::Keyval::GDK_F2, nil
73
+
74
+ Gtk::AccelMap.add_entry '<unixcmd>/file/view', Gdk::Keyval::GDK_F3, nil
75
+ Gtk::AccelMap.add_entry '<unixcmd>/file/edit', Gdk::Keyval::GDK_F4, nil
76
+ Gtk::AccelMap.add_entry '<unixcmd>/file/copy', Gdk::Keyval::GDK_F5, nil
77
+ Gtk::AccelMap.add_entry '<unixcmd>/file/move', Gdk::Keyval::GDK_F6, nil
78
+ Gtk::AccelMap.add_entry '<unixcmd>/file/mkdir', Gdk::Keyval::GDK_F7, nil
79
+ Gtk::AccelMap.add_entry '<unixcmd>/file/remove', Gdk::Keyval::GDK_F8, Gdk::Window::SHIFT_MASK
80
+
81
+ Gtk::AccelMap.add_entry '<unixcmd>/test/print_selection', Gdk::Keyval::GDK_F11, nil
82
+
83
+ Gtk::AccelMap.add_entry '<unixcmd>/file/info', Gdk::Keyval::GDK_Return, Gdk::Window::MOD1_MASK
84
+
85
+ Gtk::AccelMap.add_entry '<unixcmd>/app/quit', Gdk::Keyval::GDK_F4, Gdk::Window::MOD1_MASK
86
+
87
+
88
+ require 'unixcmd/cmd'
89
+
90
+
91
+ $wnd = CmdWnd.new
92
+ $wnd.add_accel_group $accels
93
+
94
+ Gtk.main
95
+
96
+ Gdk::Threads.leave
@@ -0,0 +1,157 @@
1
+ # TODO: find more elegance solution
2
+ class Fixnum
3
+ def to_rwx
4
+ res = '----------'
5
+
6
+ if self&(1<<0) > 0 then res[res.size-1] = 'x' end
7
+ if self&(1<<1) > 0 then res[res.size-2] = 'w' end
8
+ if self&(1<<2) > 0 then res[res.size-3] = 'r' end
9
+
10
+ if self&(1<<3) > 0 then res[res.size-4] = 'x' end
11
+ if self&(1<<4) > 0 then res[res.size-5] = 'w' end
12
+ if self&(1<<5) > 0 then res[res.size-6] = 'r' end
13
+
14
+ if self&(1<<6) > 0 then res[res.size-7] = 'x' end
15
+ if self&(1<<7) > 0 then res[res.size-8] = 'w' end
16
+ if self&(1<<8) > 0 then res[res.size-9] = 'r' end
17
+
18
+ if (self>>9) == 040 then res[res.size-10] = 'd' end
19
+
20
+ res
21
+ end
22
+ end
23
+
24
+ # TODO: Bug in Pathname
25
+ class Pathname
26
+ alias_method :old_plus, :+
27
+ alias_method :old_exist, :exist?
28
+ alias_method :old_directory, :directory?
29
+ alias_method :old_entries, :entries
30
+ alias_method :old_readable_real, :readable_real?
31
+ alias_method :old_writable_real, :writable_real?
32
+ alias_method :old_mkdir, :mkdir
33
+
34
+ def + (pathname)
35
+ return old_plus pathname if pathname.class != Pathname || to_s != '~' || pathname.to_s != '..'
36
+
37
+ expand_path.old_plus pathname
38
+ end
39
+
40
+ def exist?() expand_path.old_exist end
41
+ def directory?() expand_path.old_directory end
42
+ def entries() expand_path.old_entries end
43
+ def readable_real?() expand_path.old_readable_real end
44
+ def writable_real?() expand_path.old_writable_real end
45
+ def mkdir() expand_path.old_mkdir end
46
+ end
47
+
48
+ # TODO: find another way
49
+ UNITS = %W(k M G T).freeze
50
+
51
+ class Integer
52
+ def to_szstr
53
+ number = self
54
+ if number < 1024
55
+ exponent = 0
56
+ else
57
+ max_exp = UNITS.size - 1
58
+
59
+ exponent = ( Math.log(number) / Math.log(1024) ).to_i # convert to base
60
+ exponent = max_exp if exponent > max_exp # we need this to avoid overflow for the highest unit
61
+
62
+ number /= 1024 ** exponent
63
+ end
64
+
65
+ "#{number}" + (exponent > 0 ? " #{UNITS[exponent-1]}" : '')
66
+ end
67
+ end
68
+
69
+ # TODO: bug in Time::strftime
70
+ class Time
71
+ alias_method :old_strftime, :strftime
72
+
73
+ def strftime(format)
74
+ if ENV['LANG'] == 'ru_RU.UTF-8' then
75
+ format = format.sub '%x', '%d.%m.%Y'
76
+ end
77
+
78
+ return old_strftime(format)
79
+ end
80
+ end
81
+
82
+ class MIME::Types
83
+ def self.get_icon_names(filepath)
84
+ types = MIME::Types.of filepath
85
+ return nil if types == nil || types.count == 0
86
+ script_path = Pathname.new(__FILE__).expand_path.dirname.to_s
87
+ res = `#{script_path}/gnome-get-filetype-icon #{types[0]}`
88
+ return (res.strip.split ' ').drop(2) if $? == 0
89
+ nil
90
+ end
91
+
92
+ def self.get_icon_path(filepath)
93
+ icons_path = Pathname.new '/usr/share/icons/gnome/16x16'
94
+
95
+ return icons_path + Pathname.new('places/folder.png') if filepath.directory?
96
+
97
+ icon_names = MIME::Types.get_icon_names(filepath.to_s)
98
+
99
+ return icons_path + Pathname.new('mimetypes/text-x-generic.png') if icon_names == nil
100
+
101
+ icon_names.each do |icon|
102
+ icon_path = icons_path + Pathname.new('mimetypes') + Pathname.new(icon.to_s + '.png')
103
+
104
+ return icon_path.to_s if icon_path.exist?
105
+ end
106
+
107
+ icons_path + Pathname.new('mimetypes/text-x-generic.png')
108
+ end
109
+ end
110
+
111
+ class Gtk::Widget
112
+ def connect_bypath(path)
113
+ signal_connect('clicked') { $actMap[path].call }
114
+ self
115
+ end
116
+ end
117
+
118
+ # continue from exception
119
+ require 'continuation'
120
+
121
+ class Exception
122
+ class NoContinuation < StandardError
123
+ end
124
+
125
+ attr_accessor :continuation
126
+
127
+ def continue
128
+ raise NoContinuation unless continuation.respond_to?(:call)
129
+ continuation.call
130
+ end
131
+ end
132
+
133
+ module NeverGonnaLetYouDown
134
+ def raise(exception = RuntimeError, string = nil, array = caller)
135
+ # With a single String argument, raises a
136
+ # RuntimeError with the string as a message.
137
+ if exception.is_a?(String)
138
+ string = exception
139
+ exception = RuntimeError
140
+ end
141
+
142
+ callcc do |cc|
143
+ obj = exception.exception(string)
144
+ obj.set_backtrace(array)
145
+ obj.continuation = cc
146
+ super obj
147
+ end
148
+ end
149
+
150
+ def fail(exception = RuntimeError, string = nil, array = caller)
151
+ raise(exception, string, array)
152
+ end
153
+ end
154
+
155
+ class Object
156
+ include NeverGonnaLetYouDown
157
+ end
@@ -0,0 +1,217 @@
1
+ $accels = Gtk::AccelGroup.new
2
+
3
+ $actMap = Hash.new
4
+
5
+ require 'thread'
6
+
7
+ #require_relative './copier.rb'
8
+ #require_relative './copyctrl.rb'
9
+ #require_relative './fileinfodlg.rb'
10
+
11
+ $actMap['<unixcmd>/panel/reload'] = Proc.new { $wnd.curpanel.reload }
12
+
13
+ $actMap['<unixcmd>/file/copy'] = Proc.new { cmd_file_copy $wnd.curpanel.selection, $wnd.curpanel.path, $wnd.otherpanel.path }
14
+ $actMap['<unixcmd>/file/remove'] = Proc.new { cmd_file_remove $wnd.curpanel.selection }
15
+
16
+ $actMap['<unixcmd>/file/view'] = Proc.new { cmd_file_view $wnd.selected_file }
17
+ $actMap['<unixcmd>/file/edit'] = Proc.new { cmd_file_edit $wnd.selected_file }
18
+
19
+ $actMap['<unixcmd>/file/info'] = Proc.new { cmd_file_info $wnd.selected_file }
20
+
21
+ $actMap['<unixcmd>/app/quit'] = Proc.new { $wnd.destroy }
22
+
23
+ $actMap['<unixcmd>/test/print_selection'] = Proc.new { p $wnd.curpanel.selection }
24
+
25
+ $actMap.each_key do |key|
26
+ $accels.connect(key, &$actMap[key])
27
+ end
28
+
29
+ #module MyCopyModel
30
+ # include CopyModel
31
+ #
32
+ # def cp(src, dst)
33
+ # return if src == dst
34
+ #
35
+ # p [:cp, [src, dst]]
36
+ #
37
+ # srcfile = File.new src.expand_path, 'rb'
38
+ # dstfile = File.new dst.expand_path, 'wb'
39
+ # copied_sum = 0
40
+ # size = srcfile.stat.size
41
+ # block_size = $cfg['copy']['block_size']
42
+ # time_start = Time::now.to_f
43
+ # elapsed = 0.0
44
+ #
45
+ # begin
46
+ # copied = IO::copy_stream srcfile, dstfile, block_size
47
+ # copied_sum += copied
48
+ #
49
+ # view.file_progress copied_sum.to_f/size.to_f
50
+ #
51
+ # elapsed = Time::now.to_f - time_start
52
+ # view.file_speed (copied_sum/elapsed).to_i if elapsed > 0
53
+ # end while copied > 0
54
+ #
55
+ # nil
56
+ # end
57
+ #
58
+ # def mkdir(path)
59
+ # p [:mkdir, [path]]
60
+ # path.mkdir
61
+ # end
62
+ #end
63
+
64
+ #module MyCopyView
65
+ # include CopyView
66
+ #
67
+ # class << View
68
+ # @queue
69
+ #
70
+ # def queue=(queue) @queue = queue end
71
+ #
72
+ # def start() end
73
+ # def end() @queue.push [:end] end
74
+ #
75
+ # def file_start(src, dst) @queue.push [:file_start, [src, dst]] end
76
+ #
77
+ # def file_end() end
78
+ #
79
+ # def file_progress(percent) @queue.push [:file_progress, [percent]] end
80
+ # def progress(percent) @queue.push [:progress, [percent]] end
81
+ # def dir_create(path) @queue.push [:dir_create, [path]] end
82
+ #
83
+ # def file_speed(speed) @queue.push [:file_speed, [speed]] end
84
+ # end
85
+ #end
86
+
87
+ def cmd_file_copy(files, srcdir, dstdir)
88
+ # (dlg = CopyOptionsDlg.new files, srcdir, dstdir).run do |res|
89
+ # case res
90
+ # when Gtk::Dialog::RESPONSE_CANCEL, Gtk::Dialog::RESPONSE_DELETE_EVENT
91
+ # dlg.destroy
92
+ # return
93
+ # when Gtk::Dialog::RESPONSE_OK then dlg.destroy
94
+ # else
95
+ # raise ArgumentError, res.to_s
96
+ # end
97
+ # end
98
+ #
99
+ # queue = Queue.new
100
+ #
101
+ # copier = Copier.new dlg.files, dlg.src, dlg.dst, false, false
102
+ # copier.view = MyCopyView
103
+ # copier.model = MyCopyModel
104
+ # copier.view.queue = queue
105
+ #
106
+ # dlg = CopyDlg.new
107
+ #
108
+ # cpthread = Thread.new do
109
+ # begin
110
+ # copier.run
111
+ # rescue => err
112
+ # print 'error: '
113
+ # p err.hash[:type]
114
+ #
115
+ # if err.hash[:type] == :not_exist
116
+ # p err.hash[:path]
117
+ # #err.hash[:stop] = true
118
+ # end
119
+ #
120
+ # if err.hash[:type] == :srcdstdifftype
121
+ # p err.hash[:src]
122
+ # p err.hash[:dst]
123
+ # #err.hash[:stop] = true
124
+ # end
125
+ #
126
+ # if err.hash[:type] == :access_denied
127
+ # p err.hash[:path]
128
+ # #err.hash[:stop] = true
129
+ # end
130
+ #
131
+ # if err.hash[:type] == :exist
132
+ # p err.hash[:path]
133
+ # err.hash[:overwrite] = true if err.hash[:path].basename.to_s == '6'
134
+ # #err.hash[:stop] = true
135
+ # end
136
+ #
137
+ # err.continue
138
+ # end
139
+ # end
140
+ #
141
+ # cpthread.abort_on_exception = true
142
+ #
143
+ # idle = Gtk.idle_add do
144
+ # if !queue.empty?
145
+ # call = queue.pop
146
+ # args = call[1]
147
+ #
148
+ # dlg.dispatch_model_call call[0], args
149
+ # end
150
+ #
151
+ # true
152
+ # end
153
+ #
154
+ # dlg.run do |res|
155
+ # case res
156
+ # when Gtk::Dialog::RESPONSE_CANCEL then copy.stop
157
+ # end
158
+ # end
159
+ #
160
+ # Gtk.idle_remove idle
161
+ # cpthread.join
162
+ # cpthread.exit
163
+ end
164
+
165
+ def cmd_file_remove(files)
166
+ files.each do |file|
167
+ end
168
+ end
169
+
170
+ def cmd_file_view(file)
171
+ fullpath = file.expand_path
172
+
173
+ return if fullpath.directory?
174
+
175
+ if file.expand_path.directory?
176
+ filetype = 'directory'
177
+ else
178
+ filetype = MIME::Types.of fullpath.to_s
179
+ filetype = 'binary (undefined)' if filetype == nil || filetype.count == 0
180
+ filetype = filetype[0].to_s if filetype.class == Array
181
+ end
182
+
183
+ viewer = 'xdg-open'
184
+
185
+ viewer = $cfg['viewers'][filetype] if $cfg['viewers'].has_key? filetype
186
+
187
+ Open3.popen3 viewer, fullpath.to_s
188
+ end
189
+
190
+ def cmd_file_edit(file)
191
+ fullpath = file.expand_path
192
+
193
+ return if fullpath.directory?
194
+
195
+ if file.expand_path.directory?
196
+ filetype = 'directory'
197
+ else
198
+ filetype = MIME::Types.of fullpath.to_s
199
+ filetype = 'binary (undefined)' if filetype == nil || filetype.count == 0
200
+ filetype = filetype[0].to_s if filetype.class == Array
201
+ end
202
+
203
+ editor = 'xdg-open'
204
+
205
+ editor = $cfg['editors'][filetype] if $cfg['editors'].has_key? filetype
206
+
207
+ Open3.popen3 editor, fullpath.to_s
208
+ end
209
+
210
+ def cmd_file_info(file)
211
+ dlg = FileInfoDlg.new file
212
+ dlg.run
213
+ dlg.destroy
214
+ end
215
+
216
+ # vim: sw=2 sts=2 ts=8:
217
+
@@ -0,0 +1,10 @@
1
+ $cfg = Hash.new
2
+
3
+ $cfg['viewers'] = Hash.new
4
+ $cfg['viewers']['text/plain'] = 'gview'
5
+
6
+ $cfg['editors'] = Hash.new
7
+ $cfg['editors']['text/plain'] = 'gvim'
8
+
9
+ $cfg['copy'] = Hash.new
10
+ $cfg['copy']['block_size'] = 128*1024
@@ -0,0 +1,187 @@
1
+ require 'launchy'
2
+ require 'mime/types'
3
+ require 'unixcmd/aux'
4
+
5
+
6
+ class CmdDirWidget < Gtk::Frame
7
+ @path
8
+ @view
9
+
10
+ def view() @view end
11
+
12
+ def initialize
13
+ super
14
+
15
+ model = Gtk::ListStore.new String, String, String, String, String, String, Gdk::Pixbuf, Integer
16
+ @view = Gtk::TreeView.new model
17
+
18
+ Gtk::VScrollbar.new @view.vadjustment
19
+
20
+ @view.signal_connect('row-activated') { |view, path, column| open(path) }
21
+
22
+ scrollwnd = Gtk::ScrolledWindow.new
23
+ scrollwnd.set_policy Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC
24
+
25
+ scrollwnd.add @view
26
+
27
+ add_child Gtk::Builder.new, scrollwnd
28
+
29
+ checker = Gtk::CellRendererToggle.new
30
+ checker.signal_connect('toggled') { |s, path| iter = @view.model.get_iter(path); iter[7] = ~iter[7]; }
31
+
32
+ @view.signal_connect('key-press-event') { |s, event| key_pressed(event) }
33
+
34
+ cols = [ Gtk::TreeViewColumn.new('', checker, :active => 7 ),
35
+ Gtk::TreeViewColumn.new('Name'),
36
+ Gtk::TreeViewColumn.new('Ext', Gtk::CellRendererText.new, :text => 2),
37
+ Gtk::TreeViewColumn.new('Size', Gtk::CellRendererText.new, :text => 3),
38
+ Gtk::TreeViewColumn.new('Date', Gtk::CellRendererText.new, :text => 4),
39
+ Gtk::TreeViewColumn.new('Attr', Gtk::CellRendererText.new, :text => 5) ]
40
+
41
+ renderer = Gtk::CellRendererPixbuf.new
42
+ cols[1].pack_start renderer, false
43
+ cols[1].add_attribute renderer, 'pixbuf', 6
44
+
45
+ renderer = Gtk::CellRendererText.new
46
+ cols[1].pack_start renderer, false
47
+ cols[1].add_attribute renderer, 'text', 1
48
+
49
+ (1..cols.count).each do |i|
50
+ cols[i-1].sort_column_id = i
51
+ end
52
+
53
+ cols.drop(2).each { |col| col.expand = false }
54
+ cols[0].expand = false
55
+ cols[1].expand = true
56
+
57
+ cols.each { |col| @view.append_column col }
58
+
59
+ @view.selection.mode = Gtk::SELECTION_MULTIPLE
60
+
61
+ model.set_sort_column_id 2
62
+
63
+ self.focus_chain = [ @view ]
64
+
65
+ grab_focus
66
+
67
+ chdir Pathname.new '~'
68
+ end
69
+
70
+ def path() @path end
71
+ def expanded_path() @path.expand_path end
72
+
73
+ def back() chdir(@path + Pathname.new('..')) end
74
+
75
+ def reload
76
+ model = @view.model
77
+
78
+ model.clear
79
+
80
+ @view.columns[0].set_visible(false)
81
+
82
+ files = expanded_path.entries.sort
83
+
84
+ first_row = nil
85
+
86
+ files.each do |file|
87
+ full_path = expanded_path + file
88
+ file_icon_path = MIME::Types.get_icon_path full_path
89
+
90
+ next if file.to_s == '.'
91
+ next if file.to_s == '..' && expanded_path.root?
92
+ next if file.to_s[0] == '.' && file.to_s != '..'
93
+
94
+ row = model.append
95
+
96
+ first_row = row if first_row.nil?
97
+
98
+ row[0] = file.to_s
99
+
100
+ if full_path.directory? then
101
+ row[1] = file.to_s + '/'
102
+ row[3] = '<DIR>'
103
+ else
104
+ row[1] = file.basename('.*').to_s
105
+ row[3] = full_path.stat.size.to_i.to_szstr
106
+ end
107
+
108
+ row[2] = file.extname
109
+ row[4] = Time.at(full_path.stat.mtime).strftime '%x %R'
110
+ row[5] = full_path.stat.mode.to_rwx
111
+ row[6] = Gdk::Pixbuf.new file_icon_path.to_s
112
+ row[7] = 0
113
+ end
114
+
115
+ @view.selection.select_iter first_row
116
+ @view.scroll_to_cell first_row.path, @view.columns[1], false, 0.0, 0.0
117
+ end
118
+
119
+ def open(path)
120
+ iter = @view.model.get_iter(path)
121
+
122
+ file = iter.get_value 0
123
+
124
+ if (expanded_path + Pathname.new(file)).directory? then
125
+ chdir @path + Pathname.new(file)
126
+ else
127
+ Launchy.open (expanded_path + Pathname.new(file)).to_s
128
+ end
129
+ end
130
+
131
+ def chdir(path)
132
+ old_path = @path == nil ? Pathname.new('') : @path
133
+ @path = path
134
+
135
+ set_label @path.to_s
136
+
137
+ reload
138
+
139
+ if path == old_path.parent then
140
+ dirname = old_path.basename
141
+
142
+ @view.model.each do |model, path, iter|
143
+ if iter.get_value(0) == dirname.to_s then
144
+ @view.selection.select_path path
145
+ @view.set_cursor path, nil, false
146
+ break
147
+ end
148
+ end
149
+
150
+ end
151
+
152
+ if @view.selection.count_selected_rows == 0 then
153
+ @view.selection.select_iter @view.model.iter_first
154
+ @view.set_cursor @view.model.iter_first.path, nil, false
155
+ end
156
+
157
+ grab_focus
158
+
159
+ signal_emit 'dir-changed'
160
+ end
161
+
162
+ def key_pressed(event)
163
+ if event.keyval == Gdk::Keyval::GDK_Insert
164
+ @view.columns[0].visible = true
165
+
166
+ last = nil
167
+
168
+ @view.selection.selected_each do |model, path, iter|
169
+ @view.selection.unselect_iter iter
170
+ iter[7] = ~iter[7] if iter[0] != '..'
171
+ last = iter
172
+ end
173
+
174
+ @view.selection.select_iter last if last && last.next!
175
+
176
+ return true
177
+ elsif event.keyval == Gdk::Keyval::GDK_space
178
+ return true
179
+ end
180
+ end
181
+
182
+ type_register
183
+
184
+ signal_new('dir_changed', GLib::Signal::RUN_FIRST, nil, nil)
185
+
186
+ def signal_do_dir_changed() nil end
187
+ end
@@ -0,0 +1,159 @@
1
+ require 'sys/filesystem'
2
+ require 'unixcmd/dirview'
3
+
4
+ class CmdPanelCaptionWidget < Gtk::HBox
5
+ @mounts
6
+ @mounts_handler
7
+ @text
8
+
9
+ type_register
10
+
11
+ signal_new('go_root', GLib::Signal::RUN_FIRST, nil, nil)
12
+ signal_new('go_home', GLib::Signal::RUN_FIRST, nil, nil)
13
+ signal_new('go_back', GLib::Signal::RUN_FIRST, nil, nil)
14
+ signal_new('go_mountpoint', GLib::Signal::RUN_FIRST, nil, nil, String)
15
+
16
+ def signal_do_go_root() nil end
17
+ def signal_do_go_home() nil end
18
+ def signal_do_go_back() nil end
19
+ def signal_do_go_mountpoint(point) nil end
20
+
21
+ def initialize
22
+ super
23
+
24
+ @text = Gtk::Label.new 'Caption'
25
+ @mounts = Gtk::ComboBox.new
26
+
27
+ btn_root = Gtk::Button.new '/'
28
+ btn_home = Gtk::Button.new '~'
29
+ btn_back = Gtk::Button.new '..'
30
+
31
+ btn_root.relief = Gtk::RELIEF_NONE
32
+ btn_home.relief = Gtk::RELIEF_NONE
33
+ btn_back.relief = Gtk::RELIEF_NONE
34
+
35
+ btn_root.signal_connect('clicked') { signal_emit 'go-root' }
36
+ btn_home.signal_connect('clicked') { signal_emit 'go-home' }
37
+ btn_back.signal_connect('clicked') { signal_emit 'go-back' }
38
+
39
+ @mounts_handler = @mounts.signal_connect('changed') { signal_emit 'go-mountpoint', @mounts.active_text }
40
+
41
+ @mounts.focus_on_click = false
42
+
43
+ self.focus_chain = []
44
+
45
+ reload_mounts
46
+
47
+ pack_start @mounts, false
48
+ pack_start @text, true
49
+ pack_start Gtk::VSeparator.new, false
50
+ pack_start btn_root, false
51
+ pack_start Gtk::VSeparator.new, false
52
+ pack_start btn_home, false
53
+ pack_start Gtk::VSeparator.new, false
54
+ pack_start btn_back, false
55
+ end
56
+
57
+ def reload_mounts
58
+ cur_mounts = Array.new
59
+ new_mounts = Array.new
60
+
61
+ Sys::Filesystem.mounts do |mount|
62
+ # TODO: make correct mounts filter
63
+ next if mount.mount_type != 'vfat' && mount.mount_type != 'ntfs' && mount.mount_type != 'ext3' && mount.mount_type != 'ext2' && mount.mount_type != 'ext4'
64
+ new_mounts << Pathname.new(mount.mount_point).to_s
65
+ end
66
+
67
+ @mounts.model.each do |model, path, iter|
68
+ cur_mounts << model.get_value(iter, 0)
69
+ end
70
+
71
+ if new_mounts != cur_mounts
72
+ @mounts.signal_handler_block @mounts_handler
73
+ @mounts.model.clear
74
+ @mounts.active = -1
75
+ new_mounts.each { |point| @mounts.append_text point }
76
+ @mounts.signal_handler_unblock @mounts_handler
77
+ end
78
+ end
79
+
80
+ def update_mount_point(point)
81
+ new_active = nil
82
+
83
+ @mounts.model.each do |model, path, iter|
84
+ new_active = model.get_iter(path) if point == model.get_iter(path).get_value(0)
85
+ end
86
+
87
+ @mounts.signal_handler_block @mounts_handler
88
+ @mounts.active_iter = new_active if @mounts.active_iter != new_active
89
+ @mounts.signal_handler_unblock @mounts_handler
90
+ end
91
+
92
+ def set_text(text)
93
+ @text.text = text
94
+ end
95
+ end
96
+
97
+ class CmdPanelWidget < Gtk::VBox
98
+ @dir
99
+ @caption
100
+
101
+ def initialize
102
+ super
103
+
104
+ @caption = CmdPanelCaptionWidget.new
105
+
106
+ @dir = CmdDirWidget.new
107
+
108
+ pack_start @caption, false
109
+ pack_end @dir
110
+
111
+ @dir.signal_connect('dir-changed') { update_caption }
112
+ @caption.signal_connect('go-root') { @dir.chdir Pathname.new '/' }
113
+ @caption.signal_connect('go-home') { @dir.chdir Pathname.new '~' }
114
+ @caption.signal_connect('go-back') { @dir.back }
115
+ @caption.signal_connect('go-mountpoint') { |widget, point| @dir.chdir Pathname.new point if point != nil }
116
+
117
+ self.focus_chain = [ @dir ]
118
+
119
+ @dir.chdir Pathname.new '~'
120
+ end
121
+
122
+ def update_caption
123
+ path = @dir.path.expand_path.to_s
124
+ mount_point = Sys::Filesystem.mount_point path
125
+
126
+ stat = Sys::Filesystem.stat mount_point
127
+
128
+ capacity = stat.blocks*stat.block_size
129
+ free = stat.blocks_free*stat.block_size
130
+
131
+ @caption.set_text(sprintf("%s of %s free", free.to_i.to_szstr, capacity.to_i.to_szstr))
132
+ @caption.reload_mounts
133
+ @caption.update_mount_point mount_point
134
+ end
135
+
136
+ def path
137
+ @dir.path
138
+ end
139
+
140
+ def selection
141
+ res = Array.new
142
+
143
+ @dir.view().model.each { |model, path, iter|
144
+ res << Pathname.new(iter[0]) if(iter[7] != 0)
145
+ }
146
+
147
+ if res.empty? then
148
+ @dir.view.selection.selected_each do |model, path, iter|
149
+ res << Pathname.new(model.get_value(iter, 0))
150
+ end
151
+ end
152
+
153
+ res.count > 0 ? res : nil
154
+ end
155
+
156
+ def reload
157
+ @dir.reload
158
+ end
159
+ end
@@ -0,0 +1,2 @@
1
+ APP_NAME = 'UNIX Commander'
2
+ APP_VERSION = '0.1'
metadata ADDED
@@ -0,0 +1,51 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: unixcmd
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Levenkov Artem
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-09-05 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Orthodox file manager
14
+ email: artem@levenkov.org
15
+ executables:
16
+ - unixcmd
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - lib/unixcmd/panel.rb
21
+ - lib/unixcmd/dirview.rb
22
+ - lib/unixcmd/config.rb
23
+ - lib/unixcmd/cmd.rb
24
+ - lib/unixcmd/version.rb
25
+ - lib/unixcmd/aux.rb
26
+ - bin/unixcmd
27
+ homepage: http://github.com/levenkov/unixcmd
28
+ licenses:
29
+ - MIT
30
+ metadata: {}
31
+ post_install_message:
32
+ rdoc_options: []
33
+ require_paths:
34
+ - lib
35
+ required_ruby_version: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ! '>='
38
+ - !ruby/object:Gem::Version
39
+ version: '0'
40
+ required_rubygems_version: !ruby/object:Gem::Requirement
41
+ requirements:
42
+ - - ! '>='
43
+ - !ruby/object:Gem::Version
44
+ version: '0'
45
+ requirements: []
46
+ rubyforge_project:
47
+ rubygems_version: 2.0.14
48
+ signing_key:
49
+ specification_version: 4
50
+ summary: UNIX Commander
51
+ test_files: []