unixcmd 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.
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: []