filecon 0.2.1 → 0.3.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 +7 -7
- data/bin/filecon +8 -3
- data/config.yaml +5 -3
- data/filecon.1 +6 -5
- data/lib/filecon/version.rb +1 -1
- data/lib/filecon.rb +80 -21
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: df1c9b636fd924aa180e49679581afcb96338d18d854ab359046cbf91e048642
|
|
4
|
+
data.tar.gz: deb0a271ed914d69e8d4c7a138a83a1d7942c5a451de227b9c23d3637dea89f3
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: cdd7f22ae47392a10f1485dad5fdebd98860604e28bac74e214a13ca9b3d9b4f0b838878e8e523f827c91d724246c620fb8c526dcfbe97fb67817c4d3253bc40
|
|
7
|
+
data.tar.gz: 75e4a171320400619c0923ed985c9b93f598c454477cec23adad90b78adad58e2f8533e7ff535ac428c595cf39f26c212b7a709c173fc4802b4a405ab54cd6c0
|
data/README.md
CHANGED
|
@@ -21,8 +21,8 @@ Filecon runs on Typr, whose self-contained terminal layer ships its own precompi
|
|
|
21
21
|
- **Directory browsing with MIME-type detection** — files are typed from a packaged MIME database and colored accordingly, with optional `file --mime-type` magic detection for unknowns
|
|
22
22
|
- **Fastest possible navigation** — hint numbers (1–9, 0) open rows directly; TAB pages hints beyond the first ten
|
|
23
23
|
- **Default `[/]:search` in popups** — command and history popups open in search mode: start typing to distill the list down to the matches, then press a number hint to pick from the few remaining results. The listing itself searches the same way
|
|
24
|
-
- **Mouse support** — click a row to open it with its default action; the mouse wheel scrolls the listing (pointer-only mode is planned)
|
|
25
|
-
- **Command execution modes** — commands run in one of four ways, chosen by prefix: `|` status line, `=` text viewer, `+` new terminal window, `!` Ruby eval; per-MIME-type command sets with `%name`, `%dir`, `%file`, `%str` substitution
|
|
24
|
+
- **Mouse support** — click a row to open it with its default action, right-click to open its command list; the mouse wheel scrolls the listing (pointer-only mode is planned)
|
|
25
|
+
- **Command execution modes** — commands run in one of four ways, chosen by prefix: `|` status line, `=` text viewer, `+` new terminal window, `!` Ruby eval; per-MIME-type command sets with `%name`, `%dir`, `%file`, `%cmd`, `%str` substitution
|
|
26
26
|
- **Customizable column views** — view columns run shell commands with `%name` substitution (content preview, char/word/line counts, type info, disk usage, man-page descriptions)
|
|
27
27
|
- **Directory and command history with a frequency counter** — entries stored as `[count, entry]` pairs, most-used first then most-recent; `frequency_limit` controls how many frequent entries lead the list
|
|
28
28
|
- **Shell history import** — on first run, `~/.bash_history` and `~/.zsh_history` are validated, alias-resolved, and merged into the command history; directory paths referenced by those commands are collected into the directory history
|
|
@@ -46,11 +46,10 @@ filecon [directory]
|
|
|
46
46
|
**Navigation**
|
|
47
47
|
- Arrow keys / Page Up/Down / Home / End — Navigate files
|
|
48
48
|
- Backspace — Go to parent directory
|
|
49
|
-
- Number keys — Open file with default command
|
|
49
|
+
- Number keys — Open file with default command; Alt+number — Open command list for the file
|
|
50
50
|
- Tab — Cycle hint numbers for rows beyond the first 10
|
|
51
51
|
|
|
52
52
|
**Actions**
|
|
53
|
-
- `o` — Open list of all commands for selected file
|
|
54
53
|
- `c` — Command history
|
|
55
54
|
- `x` — List all executables from $PATH directories
|
|
56
55
|
- `h` — Help
|
|
@@ -66,6 +65,7 @@ filecon [directory]
|
|
|
66
65
|
- `M` — Mark range
|
|
67
66
|
- `a` — Mark all
|
|
68
67
|
- `i` — Invert mark
|
|
68
|
+
- `Enter` — Open the command list for marked files
|
|
69
69
|
|
|
70
70
|
**Directory**
|
|
71
71
|
- `~` — Go to home directory
|
|
@@ -73,12 +73,12 @@ filecon [directory]
|
|
|
73
73
|
- `d` — Directory history
|
|
74
74
|
|
|
75
75
|
**Other**
|
|
76
|
-
- Enter — Select / confirm
|
|
76
|
+
- Enter — Select / confirm (also: open the command list for marked files)
|
|
77
77
|
- Esc — Quit
|
|
78
78
|
|
|
79
79
|
### Mouse
|
|
80
80
|
|
|
81
|
-
Click a row to open it with its default action; the mouse wheel scrolls the listing. Mouse reporting is enabled automatically when Filecon starts.
|
|
81
|
+
Click a row to open it with its default action, right-click to open its command list; the mouse wheel scrolls the listing. Mouse reporting is enabled automatically when Filecon starts.
|
|
82
82
|
|
|
83
83
|
### Popups and search
|
|
84
84
|
|
|
@@ -102,7 +102,7 @@ State and history files live under `~/.local/share/filecon/`.
|
|
|
102
102
|
- `=` — display output in the text viewer
|
|
103
103
|
- `!` — evaluate as Ruby code
|
|
104
104
|
|
|
105
|
-
**Substitution variables:** `%name` (file path), `%dir` (directory picker), `%file` (file picker), `%str` (text input)
|
|
105
|
+
**Substitution variables:** `%name` (file path), `%dir` (directory picker), `%file` (file picker), `%cmd` (PATH executable picker), `%str` (text input)
|
|
106
106
|
|
|
107
107
|
See `filecon(1)` for the full manual.
|
|
108
108
|
|
data/bin/filecon
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/ruby
|
|
2
2
|
|
|
3
3
|
require "fileutils"
|
|
4
|
+
require "tmpdir"
|
|
4
5
|
require "yaml"
|
|
5
6
|
require_relative "../lib/filecon"
|
|
6
7
|
|
|
8
|
+
log = nil
|
|
7
9
|
begin
|
|
8
10
|
config_dir = File.expand_path("~/.config/filecon")
|
|
9
11
|
config_path = File.join(config_dir, "config.yaml")
|
|
@@ -34,7 +36,7 @@ begin
|
|
|
34
36
|
cmd_history: parse[ch_path],
|
|
35
37
|
path: { config: config_path, state: state_dir, dir_history: dh_path,
|
|
36
38
|
cmd_history: ch_path },
|
|
37
|
-
directory: ARGV.first || ?., keymap: {
|
|
39
|
+
directory: ARGV.first || ?., keymap: { cmd_history: ?c, dir_history: ?d, recurse: ?R, open_current: ?` },
|
|
38
40
|
colors: config["colors"] || {},
|
|
39
41
|
views: config["views"] || {},
|
|
40
42
|
commands: config["commands"] || {},
|
|
@@ -46,9 +48,12 @@ begin
|
|
|
46
48
|
app.import_shell_history
|
|
47
49
|
app.fly
|
|
48
50
|
rescue => e
|
|
51
|
+
log = File.join(Dir.tmpdir, "filecon_error.log")
|
|
49
52
|
$stderr.puts "#{e.class}: #{e.message}\n#{e.backtrace.first(10).join("\n")}"
|
|
50
|
-
File.write
|
|
51
|
-
"#{e.class}: #{e.message}\n#{e.backtrace.first(10).join("\n")}"
|
|
53
|
+
File.write log, "#{e.class}: #{e.message}\n#{e.backtrace.first(10).join("\n")}"
|
|
52
54
|
ensure
|
|
53
55
|
Typr.exit
|
|
56
|
+
if log
|
|
57
|
+
$stderr.puts "filecon crashed: details in #{log}"
|
|
58
|
+
end
|
|
54
59
|
end
|
data/config.yaml
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
|
|
18
18
|
# Suffix appended to term for opening files in a new window.
|
|
19
19
|
# Example: if term is "foot", term_hold becomes "foot --hold"
|
|
20
|
-
term_hold: " --hold"
|
|
20
|
+
# term_hold: " --hold"
|
|
21
21
|
|
|
22
22
|
# Maximum number of history entries to retain.
|
|
23
23
|
# Older entries beyond this limit are automatically pruned.
|
|
@@ -113,6 +113,8 @@ colors:
|
|
|
113
113
|
#
|
|
114
114
|
# %file - Opens file picker, inserts chosen path
|
|
115
115
|
#
|
|
116
|
+
# %cmd - Lists the PATH, picks an executable, inserts its path
|
|
117
|
+
#
|
|
116
118
|
# %str - Prompts for text input, inserts the string
|
|
117
119
|
#
|
|
118
120
|
# SPECIAL CATEGORIES:
|
|
@@ -270,7 +272,7 @@ commands:
|
|
|
270
272
|
|
|
271
273
|
views:
|
|
272
274
|
content:
|
|
273
|
-
content: "head -n 50
|
|
275
|
+
content: "cat %name | strings | head -n 50 "
|
|
274
276
|
|
|
275
277
|
types:
|
|
276
278
|
type: true
|
|
@@ -278,7 +280,7 @@ views:
|
|
|
278
280
|
description: "file -b %name"
|
|
279
281
|
|
|
280
282
|
disk_use:
|
|
281
|
-
du: "du -
|
|
283
|
+
du: "du -s %name | cut -wf1"
|
|
282
284
|
|
|
283
285
|
count:
|
|
284
286
|
chars: "wc -m %name | cut -wf1"
|
data/filecon.1
CHANGED
|
@@ -27,7 +27,7 @@ Navigate files
|
|
|
27
27
|
Go to parent directory
|
|
28
28
|
.TP
|
|
29
29
|
.B Number keys
|
|
30
|
-
Open file with default command
|
|
30
|
+
Open file with default command; Alt+number opens the command list for the file
|
|
31
31
|
.TP
|
|
32
32
|
.B Tab
|
|
33
33
|
Cycle hint numbers for rows beyond the first 10
|
|
@@ -66,15 +66,13 @@ Open commands for current directory
|
|
|
66
66
|
Navigate to home directory
|
|
67
67
|
.TP
|
|
68
68
|
.B Return
|
|
69
|
-
Confirm: cd into directories or open files
|
|
69
|
+
Confirm: cd into directories or open files; with marked files,
|
|
70
|
+
open the command list for them
|
|
70
71
|
.TP
|
|
71
72
|
.B Escape
|
|
72
73
|
Quit
|
|
73
74
|
.SH FILECON KEYS
|
|
74
75
|
.TP
|
|
75
|
-
.B o
|
|
76
|
-
Open list of all commands for selected file
|
|
77
|
-
.TP
|
|
78
76
|
.B c
|
|
79
77
|
Browse command history
|
|
80
78
|
.PP
|
|
@@ -122,6 +120,9 @@ Prompt to pick a directory
|
|
|
122
120
|
.B %file
|
|
123
121
|
Prompt to pick a file
|
|
124
122
|
.TP
|
|
123
|
+
.B %cmd
|
|
124
|
+
Prompt to pick a PATH executable
|
|
125
|
+
.TP
|
|
125
126
|
.B %str
|
|
126
127
|
Prompt for a text string (line input)
|
|
127
128
|
.SH VIEWS
|
data/lib/filecon/version.rb
CHANGED
data/lib/filecon.rb
CHANGED
|
@@ -10,6 +10,7 @@ class Filecon::App < Typr::Browser
|
|
|
10
10
|
include Typr
|
|
11
11
|
|
|
12
12
|
def cd dir, append=false
|
|
13
|
+
@selected[:rows] = [] unless append
|
|
13
14
|
if dir.is_a? Array
|
|
14
15
|
dirs = dir.filter_map { |d| d = File.expand_path(d.to_s); Dir.exist?(d) ? d : nil }
|
|
15
16
|
dirs.each_with_index { |d, i|
|
|
@@ -29,8 +30,16 @@ class Filecon::App < Typr::Browser
|
|
|
29
30
|
|
|
30
31
|
def execute; cd ENV["PATH"].split(":"); add_path_column end
|
|
31
32
|
|
|
32
|
-
|
|
33
|
-
|
|
33
|
+
def pick type='file', **kw
|
|
34
|
+
return super unless type == :cmd
|
|
35
|
+
dir = @directory
|
|
36
|
+
execute
|
|
37
|
+
result = super
|
|
38
|
+
cd dir
|
|
39
|
+
result
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def change_view id=nil
|
|
34
43
|
return unless id
|
|
35
44
|
id = @views.keys[id] if id.is_a? Integer
|
|
36
45
|
view = @views[id]
|
|
@@ -45,7 +54,9 @@ class Filecon::App < Typr::Browser
|
|
|
45
54
|
cmd = built[0] == ?| ? built : ?| + built
|
|
46
55
|
open cmd + " 2>&1"
|
|
47
56
|
end
|
|
48
|
-
io.read(width).to_s.scrub.
|
|
57
|
+
cell = io.read(width).to_s.scrub.strip
|
|
58
|
+
value = coerce_type cell
|
|
59
|
+
value.is_a?(String) || cell.empty? ? cell.gsub(/[\n\t]/, ?|) : value
|
|
49
60
|
}.compact }
|
|
50
61
|
@sequence = [ NAME ] + view.keys.map{ |head|
|
|
51
62
|
@header.index(head.to_s) || (@header += [head.to_s]; @header.count-1) }
|
|
@@ -69,21 +80,30 @@ class Filecon::App < Typr::Browser
|
|
|
69
80
|
end
|
|
70
81
|
|
|
71
82
|
commands = @commands.values_at( *types ).map(&:to_a).flatten( 1 ).uniq
|
|
83
|
+
alt = false
|
|
72
84
|
pair = if default; commands.first
|
|
73
85
|
else move left+1,top+1
|
|
74
86
|
if id.is_a?(Array); draw "#{id.count.to_s} files: (#{
|
|
75
87
|
types.join ?, })".ljust width
|
|
76
88
|
else print id end
|
|
77
89
|
pop = id ? top+2 : top
|
|
78
|
-
|
|
90
|
+
picker = Grid.new( left:left+1, top: pop, right: -1,
|
|
79
91
|
bottom: [ pop + commands.count - 1, Typr.height ].min,
|
|
80
92
|
input:commands, border: :light, format: [:min, :max],
|
|
81
|
-
borders: { top: nil }, alternate: false,
|
|
82
|
-
colors: {columns: @colors[:commands] || [:green, :red] }
|
|
93
|
+
borders: { top: nil }, alternate: false,
|
|
94
|
+
colors: {columns: @colors[:commands] || [:green, :red] } )
|
|
95
|
+
return unless cmd = picker.pick( :row, column: 0 )
|
|
96
|
+
alt = picker.modifier == :alt
|
|
83
97
|
commands[ cmd ]
|
|
84
98
|
end
|
|
99
|
+
dir = @directory
|
|
85
100
|
cmd = build pair.last, id, pair.first
|
|
86
101
|
return unless cmd
|
|
102
|
+
if alt
|
|
103
|
+
edited = Typr.read_line "> ", left: left, top: @user.top, initial: cmd
|
|
104
|
+
return unless edited
|
|
105
|
+
cmd = edited
|
|
106
|
+
end
|
|
87
107
|
if cmd[0] == ?|
|
|
88
108
|
display = cmd[1..-1]
|
|
89
109
|
record :cmd, cmd
|
|
@@ -92,12 +112,39 @@ class Filecon::App < Typr::Browser
|
|
|
92
112
|
nc, ac = @colors[:commands] || [:green, :red]
|
|
93
113
|
@user.show "> #{color_code(nc)}#{pair.first}#{color_code(ac)}:#{display}" \
|
|
94
114
|
"#{color_code(@colors[:default])} : #{output.lines.last}"
|
|
115
|
+
show
|
|
95
116
|
Typr.read_key
|
|
96
117
|
else
|
|
97
118
|
record :cmd, cmd unless cmd[0..2] == '!cd'
|
|
98
119
|
run( cmd )
|
|
99
|
-
show
|
|
100
120
|
end
|
|
121
|
+
Array(id).sort.reverse.each { |i| refresh_row i } if id && cmd[0..2] != '!cd' && @directory == dir
|
|
122
|
+
@selected[:rows] = [] if id && @directory != dir
|
|
123
|
+
show #unless cmd[0] == ?|
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def refresh_row id
|
|
127
|
+
return unless row = @data[id]
|
|
128
|
+
name = row[NAME]
|
|
129
|
+
return delete_row id unless File.symlink?(name) || File.exist?(name)
|
|
130
|
+
updated = scan_file name
|
|
131
|
+
updated[-2,2] = row[-2,2]
|
|
132
|
+
@data[id] = updated
|
|
133
|
+
process id
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def delete_row id
|
|
137
|
+
@data.delete_at id
|
|
138
|
+
@layer.delete_at id if @layer
|
|
139
|
+
if @map
|
|
140
|
+
@map.delete id
|
|
141
|
+
@map.map!{ |i| i > id ? i - 1 : i }
|
|
142
|
+
end
|
|
143
|
+
@colors[:fields] = @colors[:fields].map { |(row,col),color|
|
|
144
|
+
row == id ? nil : row > id ? [[row - 1, col], color] : [[row, col], color] }.compact.to_h
|
|
145
|
+
@start = rows - height if @start > rows - height
|
|
146
|
+
@start = 0 if @start < 0
|
|
147
|
+
@selected[:rows] = []
|
|
101
148
|
end
|
|
102
149
|
|
|
103
150
|
def build str, id, name=nil
|
|
@@ -105,21 +152,18 @@ class Filecon::App < Typr::Browser
|
|
|
105
152
|
reset = color_code( @colors[:default] )
|
|
106
153
|
prefix = name ? "#{color_code(nc)}#{name}#{color_code(ac)}:" : ""
|
|
107
154
|
cmd = ""
|
|
108
|
-
while str[/\%(name|dir|file|str)/]
|
|
155
|
+
while str[/\%(name|cmd|dir|file|str)/]
|
|
109
156
|
cmd += $`
|
|
110
157
|
case $&
|
|
111
158
|
when '%name'; cmd += ?"+( id.nil? ? @directory :
|
|
112
159
|
id.is_a?( Array ) ? id.map{ |id|
|
|
113
160
|
@data[id][NAME] }.join('" "') :
|
|
114
161
|
@data[id][NAME] )+?"
|
|
115
|
-
when '%dir'
|
|
116
|
-
@user.show "> #{prefix}#{cmd}#{$&}#{$'}#{reset}"
|
|
117
|
-
return unless dir = pick(:directory)
|
|
118
|
-
cmd += ?" + dir + ?"
|
|
119
|
-
when '%file'
|
|
162
|
+
when '%dir', '%file', '%cmd'
|
|
120
163
|
@user.show "> #{prefix}#{cmd}#{$&}#{$'}#{reset}"
|
|
121
|
-
|
|
122
|
-
|
|
164
|
+
result = pick( { '%dir' => :directory, '%file' => :file, '%cmd' => :cmd }[$&] )
|
|
165
|
+
return unless result
|
|
166
|
+
cmd += ?" + result + ?"
|
|
123
167
|
when '%str'
|
|
124
168
|
prompt = cmd.empty? || cmd.end_with?(' ') ? cmd : "#{cmd} "
|
|
125
169
|
query = Typr.read_line "> #{prefix}#{prompt}", left: left, top: @user.top
|
|
@@ -171,12 +215,18 @@ class Filecon::App < Typr::Browser
|
|
|
171
215
|
fields[[i,1]] = [fc[1], :grey20]
|
|
172
216
|
}
|
|
173
217
|
|
|
174
|
-
|
|
218
|
+
picker = popup(input: pairs, format:[:min,:max],
|
|
175
219
|
alternate: true, left: left, bottom: -2,
|
|
176
|
-
colors: { columns: fc, fields: fields })
|
|
220
|
+
colors: { columns: fc, fields: fields })
|
|
221
|
+
n = picker.pick(:row, column: :all)
|
|
177
222
|
return unless n
|
|
178
223
|
|
|
179
224
|
entry = ordered[n][1]
|
|
225
|
+
if is_cmd and picker.modifier == :alt
|
|
226
|
+
edited = Typr.read_line "> ", left: left, top: @user.top, initial: entry
|
|
227
|
+
return unless edited
|
|
228
|
+
entry = edited
|
|
229
|
+
end
|
|
180
230
|
record type, entry
|
|
181
231
|
|
|
182
232
|
if is_cmd
|
|
@@ -284,6 +334,9 @@ class Filecon::App < Typr::Browser
|
|
|
284
334
|
def help
|
|
285
335
|
info = "\nFILECON - a terminal file manager\n\n" \
|
|
286
336
|
"HINTS: press a number (1-9,0) to open that file with its default action.\n" \
|
|
337
|
+
" Alt+number opens the command list for that file instead.\n" \
|
|
338
|
+
" Right-click a file to open its command list.\n" \
|
|
339
|
+
" Mark files with m, then Return opens their command list.\n" \
|
|
287
340
|
" TAB cycles pages of hints.\n\n" \
|
|
288
341
|
"COMMANDS:\n" \
|
|
289
342
|
" e[x]ecute browse all executables on your PATH\n" \
|
|
@@ -311,7 +364,6 @@ class Filecon::App < Typr::Browser
|
|
|
311
364
|
@keymap[:open_current] = ?`
|
|
312
365
|
@keymap[:execute] = ?x
|
|
313
366
|
@keymap[:recurse] = ?R
|
|
314
|
-
@user.bindings.insert 1, "[o]pen"
|
|
315
367
|
@user.bindings.insert 7, "[R]ecurse"
|
|
316
368
|
@user.bindings.insert 8, "[c]ommands"
|
|
317
369
|
@user.bindings.insert 9, "e[x]ecute"
|
|
@@ -319,6 +371,11 @@ class Filecon::App < Typr::Browser
|
|
|
319
371
|
@user.reset
|
|
320
372
|
end
|
|
321
373
|
|
|
374
|
+
def confirm
|
|
375
|
+
return unless @selected[:rows].any?
|
|
376
|
+
open_file @selected[:rows], false
|
|
377
|
+
end
|
|
378
|
+
|
|
322
379
|
def open_current; open_file nil, false, ["directory", "inode"] - [??] + ["default"] end
|
|
323
380
|
|
|
324
381
|
def fly
|
|
@@ -332,14 +389,16 @@ class Filecon::App < Typr::Browser
|
|
|
332
389
|
when Typr::Mouse
|
|
333
390
|
if key.wheel? and key.press?
|
|
334
391
|
send( key.wheel_up? ? @keymap[:up] : @keymap[:down] )
|
|
335
|
-
elsif key.press? and key.left?
|
|
392
|
+
elsif key.press? and ( key.left? or key.right? )
|
|
336
393
|
id = hit( key.y, key.x )
|
|
337
|
-
open_file( id,
|
|
394
|
+
open_file( id, !key.right? ) if id.is_a? Integer
|
|
338
395
|
end
|
|
339
396
|
@user.reset
|
|
340
397
|
else
|
|
398
|
+
alt = key.is_a?(String) && key[/\A\e(\d)\z/]
|
|
399
|
+
key = key[1] if alt
|
|
341
400
|
id = send( key )
|
|
342
|
-
open_file( id,
|
|
401
|
+
open_file( id, !alt ) if id.is_a? Integer
|
|
343
402
|
@user.reset
|
|
344
403
|
end
|
|
345
404
|
end
|