rfd 0.3.0 → 0.4.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 +4 -4
- data/README.md +67 -50
- data/lib/rfd.rb +44 -15
- data/lib/rfd/commands.rb +16 -1
- data/rfd.gemspec +1 -1
- data/spec/controller_spec.rb +41 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d75fe5bcaf9a3f7a14ba0f23fb6fc475c4aaea68
|
4
|
+
data.tar.gz: 19fad896ea6eec39e417bdfee2bb0bac28d37e96
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 778f65ab177d37b688ea9f7dbe678ab3fa5b656cba93096387689cf7521c305f29b6de971a2e1de8f1cdd90918fba0776763df7573c41542adba52f8c4806ff7
|
7
|
+
data.tar.gz: e3d23535bdc25262fa98c802c8a526a76dd25d585722dac423b601ce5c60f7dbab738d20307e76becb7e9133637bdae00004ee524885c305391182c80577161f
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# rfd (Ruby on Files & Directories)
|
2
2
|
|
3
|
-
rfd is a terminal
|
3
|
+
rfd is a terminal-based filesystem explorer, inpsired by the legendary freesoft MS-DOS filer, "FD".
|
4
4
|
|
5
5
|
## Installation
|
6
6
|
|
@@ -12,42 +12,43 @@ rfd is a terminal based File explorer, inpsired by the legendary freesoft MS-DOS
|
|
12
12
|
* NCurses
|
13
13
|
* (FFI)
|
14
14
|
|
15
|
-
## Tested
|
15
|
+
## Tested environments
|
16
16
|
|
17
|
-
Mac OS X Mountain Lion, Mac OS X Lion
|
17
|
+
Mac OS X Mountain Lion, Mac OS X Lion, Ubuntu 13.04
|
18
18
|
|
19
19
|
## Screenshot
|
20
20
|
|
21
|
-

|
22
22
|
|
23
23
|
## Start Me Up
|
24
24
|
|
25
|
-
Open up your terminal and type
|
25
|
+
Open up your terminal and type:
|
26
26
|
|
27
27
|
% rfd
|
28
28
|
|
29
|
-
You can also pass in a starting directory name, which
|
29
|
+
You can also pass in a starting directory name, which defaults to `.`.
|
30
30
|
|
31
31
|
% rfd ~/src/rails
|
32
32
|
|
33
33
|
## Commands
|
34
34
|
|
35
|
-
You can
|
35
|
+
You can send commands to rfd by pressing some chars on your keyboard, just like Vim.
|
36
|
+
If you're unfamiliar with this sort of command system, I recommend you to play with `vimtutor` before you go any further.
|
36
37
|
|
37
38
|
All available commands in rfd are defined as Ruby methods here. https://github.com/amatsuda/rfd/tree/master/lib/rfd/commands.rb
|
38
39
|
|
39
40
|
### Changing the current directory
|
40
41
|
|
41
|
-
*
|
42
|
-
*
|
43
|
-
*
|
42
|
+
* `<Enter>`: cd into the directory where the cursor is on.
|
43
|
+
* `<Delete>` (or \<Backspace\> on your keyboard, probably?): Go up to the upper directory (cd ..).
|
44
|
+
* `-`: Get back to where you once belonged (popd).
|
44
45
|
|
45
46
|
### Moving the cursor
|
46
47
|
|
47
|
-
*
|
48
|
-
*
|
49
|
-
*
|
50
|
-
*
|
48
|
+
* `j`: Move down.
|
49
|
+
* `k`: Move up.
|
50
|
+
* `h`: Move left. At the leftmost column, move to the right end column at the previous page.
|
51
|
+
* `l`: Move right. At the rightmost column, move to the left end column at the next page.
|
51
52
|
|
52
53
|
### The {count} parameter
|
53
54
|
|
@@ -56,31 +57,31 @@ For example, `3j` moves the cursor to 3 lines below, and `999k` will take your c
|
|
56
57
|
|
57
58
|
### Jumping the cursor
|
58
59
|
|
59
|
-
*
|
60
|
-
*
|
61
|
-
*
|
60
|
+
* `H`: Move to the top of the current page.
|
61
|
+
* `M`: Move to the middle of the current page.
|
62
|
+
* `L`: Move to the bottom of the current page.
|
62
63
|
|
63
64
|
### Switching the page
|
64
65
|
|
65
|
-
*
|
66
|
-
*
|
67
|
-
*
|
68
|
-
*
|
66
|
+
* `ctrl-n, ctrl-f`: Move to the top of the next page.
|
67
|
+
* `ctrl-p, ctrl-b`: Move to the top of the previous page.
|
68
|
+
* `g`: Move to the top of the first page.
|
69
|
+
* `G`: Move to the bottom of the last page.
|
69
70
|
|
70
71
|
### Finding a file / directory
|
71
72
|
|
72
73
|
You can find a file by typing the first letter of it immediately after the find commands.
|
73
74
|
|
74
|
-
*
|
75
|
-
*
|
76
|
-
*
|
75
|
+
* `f{char}`: Move to the next file / directory of which name starts with the given char.
|
76
|
+
* `F{char}`: Move to the previous file / directory of which name starts with the given char.
|
77
|
+
* `n`: Repeat the last `f` or `F`.
|
77
78
|
|
78
79
|
### Searching, sorting
|
79
80
|
|
80
81
|
For commands like these that require a parameter string, type the parameter in the command line at the bottom of the screen, and press \<Enter\>.
|
81
82
|
|
82
|
-
*
|
83
|
-
*
|
83
|
+
* `/`: Grep the current directory with the given parameter. The parameter will be interpreted as Ruby Regexp (e.g. `.*\.rb$`).
|
84
|
+
* `s`: Sort files / directories in the current directory in the given order.
|
84
85
|
* (none): by name
|
85
86
|
* r : reverse order by name
|
86
87
|
* s, S : order by file size
|
@@ -99,41 +100,48 @@ For commands like these that require a parameter string, type the parameter in t
|
|
99
100
|
You can send a command to the file / directory on which the cursor is on. Or, you can send a command to multiple files / directories at once by marking them first.
|
100
101
|
The mark is drawn as a `*` char on the left of each file / directory name.
|
101
102
|
|
102
|
-
*
|
103
|
-
*
|
103
|
+
* `<Space>`: Mark / unmark current file / directory.
|
104
|
+
* `ctrl-a`: Mark / unmark all file / directories in the current directory.
|
104
105
|
|
105
106
|
### Manipulating files / directories
|
106
107
|
|
107
108
|
As stated above, you can send a command to one or more files / directories. In this document, the term "selected items" means "(the marked files / directories) || (the file / directory on which the cursor is on)".
|
108
109
|
|
109
|
-
*
|
110
|
-
*
|
111
|
-
*
|
112
|
-
*
|
113
|
-
*
|
110
|
+
* `c`: Copy selected items (cp).
|
111
|
+
* `m`: Move selected items (mv).
|
112
|
+
* `d`: Move selected items into the Trash.
|
113
|
+
* `D`: Delete selected items.
|
114
|
+
* `r`: Rename selected items. This command takes a sed-like argument separated by a `/`. For example, changing all .html files' extention to .html.erb could be done by `\.html$/.html.erb`.
|
115
|
+
|
116
|
+
### Yank and Paste
|
117
|
+
|
118
|
+
`y` & `p` works just like Windows-c & Windows-v on explorer.exe.
|
119
|
+
|
120
|
+
* `y`: Yank selected items.
|
121
|
+
* `p`: Paste yanked items into the directory on which the cursor is, or into the current directory.
|
114
122
|
|
115
123
|
### Creating files / directories
|
116
124
|
|
117
|
-
*
|
118
|
-
*
|
119
|
-
*
|
125
|
+
* `t`: Create a new file (touch).
|
126
|
+
* `K`: Creat a new directory (mkdir).
|
127
|
+
* `S`: Create new symlink to the current file / directory (ln -s).
|
120
128
|
|
121
129
|
### Attributes
|
122
130
|
|
123
|
-
*
|
124
|
-
*
|
131
|
+
* `a`: Change permission of selected items (chmod). Takes chmod-like argument such as `g+w`, `755`.
|
132
|
+
* `w`: Change the owner of of selected items (chown). Takes chown-like argument such as `alice`, `nobody:nobody`.
|
125
133
|
|
126
134
|
### Viewing, Editing, Opening
|
127
135
|
|
128
|
-
*
|
129
|
-
*
|
130
|
-
*
|
131
|
-
*
|
136
|
+
* `<Enter>`: View current file with the system $VIEWER such as `less`.
|
137
|
+
* `v`: View current file with the system $VIEWER such as `less`.
|
138
|
+
* `e`: Edit current file with the system $EDITOR such as `vim`.
|
139
|
+
* `o`: Send the `open` command.
|
132
140
|
|
133
141
|
### Manipulating archives
|
134
142
|
|
135
|
-
*
|
136
|
-
*
|
143
|
+
* `u`: Unarchive .zip, .gz, or .tar.gz file into the current directory.
|
144
|
+
* `z`: Archive selected items into a .zip file with the given name.
|
137
145
|
|
138
146
|
### Handling .zip files
|
139
147
|
|
@@ -141,15 +149,24 @@ You can `cd` into a .zip file as if it's just a directory, then unarchive select
|
|
141
149
|
|
142
150
|
### Splitting columns
|
143
151
|
|
144
|
-
*
|
152
|
+
* `ctrl-w`: Change the window split size to the {count} value (e.g. `4<C-w>` to split the window into 4 columns). The default number of columns is 2.
|
153
|
+
|
154
|
+
### Using mouse
|
155
|
+
|
156
|
+
Mouse is available if your terminal supports it. You can move the cursor by clicking on a file / directory. Double clicking on a file / directory is equivalent to pressing \<Enter\> on it.
|
145
157
|
|
146
158
|
### Misc
|
147
159
|
|
148
|
-
*
|
149
|
-
*
|
150
|
-
*
|
151
|
-
*
|
152
|
-
*
|
160
|
+
* `ctrl-l`: Refresh the whole screen.
|
161
|
+
* `C`: Copy selected items' paths to the clipboard.
|
162
|
+
* `O`: Open a new terminal window at the current directory.
|
163
|
+
* `!`: Execute a shell command.
|
164
|
+
* `q`: Quit the app.
|
165
|
+
|
166
|
+
## How to manually execute a command, or how the commands are executed
|
167
|
+
|
168
|
+
By pressing `:`, you can enter the command-line mode. Any string given in the command line after `:` will be executed as Ruby method call in the `Controller` instance.
|
169
|
+
For instance, `:j` brings your cursor down, `:mkdir foo` makes a directory named "foo". And `:q!` of course works as you might expect, since `q!` method is implemented so.
|
153
170
|
|
154
171
|
## Contributing
|
155
172
|
|
data/lib/rfd.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
require 'ffi-ncurses'
|
2
|
-
require 'ffi-ncurses/mouse'
|
3
2
|
Curses = FFI::NCurses
|
4
3
|
require 'fileutils'
|
5
4
|
require 'tmpdir'
|
@@ -53,7 +52,7 @@ module Rfd
|
|
53
52
|
@header_l = HeaderLeftWindow.new
|
54
53
|
@header_r = HeaderRightWindow.new
|
55
54
|
@command_line = CommandLineWindow.new
|
56
|
-
@direction, @dir_history, @last_command, @times = nil, [], nil, nil
|
55
|
+
@direction, @dir_history, @last_command, @times, @yanked_items = nil, [], nil, nil, nil
|
57
56
|
end
|
58
57
|
|
59
58
|
# The main loop.
|
@@ -308,31 +307,33 @@ module Rfd
|
|
308
307
|
|
309
308
|
# Sort the loaded files and directories in already given sort order.
|
310
309
|
def sort_items_according_to_current_direction
|
311
|
-
|
310
|
+
@items, unsorted = items.partition {|i| %w(. ..).include? i.name}
|
311
|
+
@items.sort!
|
312
|
+
@items += case @direction
|
312
313
|
when nil
|
313
|
-
|
314
|
+
unsorted.partition(&:directory?).flat_map(&:sort)
|
314
315
|
when 'r'
|
315
|
-
|
316
|
+
unsorted.partition(&:directory?).flat_map {|arr| arr.sort.reverse}
|
316
317
|
when 'S', 's'
|
317
|
-
|
318
|
+
unsorted.partition(&:directory?).flat_map {|arr| arr.sort_by {|i| -i.size}}
|
318
319
|
when 'Sr', 'sr'
|
319
|
-
|
320
|
+
unsorted.partition(&:directory?).flat_map {|arr| arr.sort_by(&:size)}
|
320
321
|
when 't'
|
321
|
-
|
322
|
+
unsorted.partition(&:directory?).flat_map {|arr| arr.sort {|x, y| y.mtime <=> x.mtime}}
|
322
323
|
when 'tr'
|
323
|
-
|
324
|
+
unsorted.partition(&:directory?).flat_map {|arr| arr.sort_by(&:mtime)}
|
324
325
|
when 'c'
|
325
|
-
|
326
|
+
unsorted.partition(&:directory?).flat_map {|arr| arr.sort {|x, y| y.ctime <=> x.ctime}}
|
326
327
|
when 'cr'
|
327
|
-
|
328
|
+
unsorted.partition(&:directory?).flat_map {|arr| arr.sort_by(&:ctime)}
|
328
329
|
when 'u'
|
329
|
-
|
330
|
+
unsorted.partition(&:directory?).flat_map {|arr| arr.sort {|x, y| y.atime <=> x.atime}}
|
330
331
|
when 'ur'
|
331
|
-
|
332
|
+
unsorted.partition(&:directory?).flat_map {|arr| arr.sort_by(&:atime)}
|
332
333
|
when 'e'
|
333
|
-
|
334
|
+
unsorted.partition(&:directory?).flat_map {|arr| arr.sort {|x, y| y.extname <=> x.extname}}
|
334
335
|
when 'er'
|
335
|
-
|
336
|
+
unsorted.partition(&:directory?).flat_map {|arr| arr.sort_by(&:extname)}
|
336
337
|
end
|
337
338
|
items.each.with_index {|item, index| item.index = index}
|
338
339
|
end
|
@@ -476,6 +477,34 @@ module Rfd
|
|
476
477
|
ls
|
477
478
|
end
|
478
479
|
|
480
|
+
# Yank selected file / directory names.
|
481
|
+
def yank
|
482
|
+
@yanked_items = selected_items
|
483
|
+
end
|
484
|
+
|
485
|
+
# Paste yanked files / directories here.
|
486
|
+
def paste
|
487
|
+
if @yanked_items
|
488
|
+
if current_item.directory?
|
489
|
+
FileUtils.cp_r @yanked_items.map(&:path), current_item
|
490
|
+
else
|
491
|
+
@yanked_items.each do |item|
|
492
|
+
if items.include? item
|
493
|
+
i = 1
|
494
|
+
while i += 1
|
495
|
+
new_item = Item.new dir: current_dir, name: "#{item.basename}_#{i}#{item.extname}", stat: item.stat, window_width: maxx
|
496
|
+
break unless File.exist? new_item.path
|
497
|
+
end
|
498
|
+
FileUtils.cp_r item, new_item
|
499
|
+
else
|
500
|
+
FileUtils.cp_r item, current_dir
|
501
|
+
end
|
502
|
+
end
|
503
|
+
end
|
504
|
+
ls
|
505
|
+
end
|
506
|
+
end
|
507
|
+
|
479
508
|
# Copy selected files and directories' path into clipboard on OSX.
|
480
509
|
def clipboard
|
481
510
|
IO.popen('pbcopy', 'w') {|f| f << selected_items.map(&:path).join(' ')} if osx?
|
data/lib/rfd/commands.rb
CHANGED
@@ -73,11 +73,21 @@ module Rfd
|
|
73
73
|
end
|
74
74
|
end
|
75
75
|
|
76
|
+
# Paste yanked files / directories into the directory on which the cursor is, or into the current directory.
|
77
|
+
def p
|
78
|
+
paste
|
79
|
+
end
|
80
|
+
|
76
81
|
# "q"uit the app.
|
77
82
|
def q
|
78
83
|
raise StopIteration if ask 'Are you sure want to exit? (y/n)'
|
79
84
|
end
|
80
85
|
|
86
|
+
# "q"uit the app!
|
87
|
+
def q!
|
88
|
+
raise StopIteration
|
89
|
+
end
|
90
|
+
|
81
91
|
# "r"ename selected files and directories.
|
82
92
|
def r
|
83
93
|
process_command_line preset_command: 'rename'
|
@@ -108,6 +118,11 @@ module Rfd
|
|
108
118
|
process_command_line preset_command: 'chown'
|
109
119
|
end
|
110
120
|
|
121
|
+
# "y"ank selected file / directory names.
|
122
|
+
def y
|
123
|
+
yank
|
124
|
+
end
|
125
|
+
|
111
126
|
# Archive selected files and directories into a "z"ip file.
|
112
127
|
def z
|
113
128
|
process_command_line preset_command: 'zip'
|
@@ -159,7 +174,7 @@ module Rfd
|
|
159
174
|
|
160
175
|
# "O"pen terminal here.
|
161
176
|
def O
|
162
|
-
dir = current_item.directory? ? current_item.path : current_dir
|
177
|
+
dir = current_item.directory? ? current_item.path : current_dir.path
|
163
178
|
system %Q[osascript -e 'tell app "Terminal"
|
164
179
|
do script "cd #{dir}"
|
165
180
|
end tell'] if osx?
|
data/rfd.gemspec
CHANGED
@@ -4,7 +4,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
4
|
|
5
5
|
Gem::Specification.new do |spec|
|
6
6
|
spec.name = "rfd"
|
7
|
-
spec.version = '0.
|
7
|
+
spec.version = '0.4.0'
|
8
8
|
spec.authors = ["Akira Matsuda"]
|
9
9
|
spec.email = ["ronnie@dio.jp"]
|
10
10
|
spec.description = 'Ruby on Files & Directories'
|
data/spec/controller_spec.rb
CHANGED
@@ -305,6 +305,47 @@ describe Rfd::Controller do
|
|
305
305
|
it { should be_symlink File.join(tmpdir, 'aaa') }
|
306
306
|
end
|
307
307
|
|
308
|
+
describe '#yank' do
|
309
|
+
before do
|
310
|
+
controller.find '.file1'
|
311
|
+
controller.toggle_mark
|
312
|
+
controller.find 'dir3'
|
313
|
+
controller.toggle_mark
|
314
|
+
controller.yank
|
315
|
+
end
|
316
|
+
it 'should be yanked' do
|
317
|
+
controller.instance_variable_get(:@yanked_items).map(&:name).should =~ %w(.file1 dir3)
|
318
|
+
end
|
319
|
+
end
|
320
|
+
|
321
|
+
describe '#paste' do
|
322
|
+
before do
|
323
|
+
controller.find '.file1'
|
324
|
+
controller.toggle_mark
|
325
|
+
controller.find 'dir3'
|
326
|
+
controller.toggle_mark
|
327
|
+
controller.yank
|
328
|
+
end
|
329
|
+
context 'when the cursor is on a directory' do
|
330
|
+
before do
|
331
|
+
controller.find 'dir1'
|
332
|
+
controller.paste
|
333
|
+
end
|
334
|
+
subject { File }
|
335
|
+
it { should be_exist File.join(tmpdir, 'dir1', '.file1') }
|
336
|
+
it { should be_exist File.join(tmpdir, 'dir1', 'dir3') }
|
337
|
+
end
|
338
|
+
context 'when the cursor is on a file' do
|
339
|
+
before do
|
340
|
+
controller.find 'file2'
|
341
|
+
controller.paste
|
342
|
+
end
|
343
|
+
subject { File }
|
344
|
+
it { should be_exist File.join(tmpdir, '.file1_2') }
|
345
|
+
it { should be_exist File.join(tmpdir, 'dir3_2') }
|
346
|
+
end
|
347
|
+
end
|
348
|
+
|
308
349
|
describe '#pbcopy' do
|
309
350
|
before do
|
310
351
|
controller.find '.file1'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rfd
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Akira Matsuda
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-10-
|
11
|
+
date: 2013-10-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ffi-ncurses
|