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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d62cae7fca7f8ef2348b79ac2df27edfafbc5da7ada9523a2fad5b38de27e5a9
4
- data.tar.gz: 20fe942d398a0dd68e27a5cdc5b40d16d296e33399327494aaa608d847401e47
3
+ metadata.gz: df1c9b636fd924aa180e49679581afcb96338d18d854ab359046cbf91e048642
4
+ data.tar.gz: deb0a271ed914d69e8d4c7a138a83a1d7942c5a451de227b9c23d3637dea89f3
5
5
  SHA512:
6
- metadata.gz: 1d2ac9423eecd422db9ac518ba264ef56b3f9d17823950f648e56eff3de0dd08326daba18bfd8eeeba51d76e072a060f4be5c6542a50c709623adac370f080f0
7
- data.tar.gz: 198c5fa607c36cbc86808d42e3b0a806d83832ba5432827c871526d8ebaebaaa8cc3864f7a486e586b00ce2e983086e81184d08fe993f93ca2fa58fd7b0c9fd6
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: { open_file: ?o, cmd_history: ?c, dir_history: ?d, recurse: ?R, open_current: ?` },
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 File.join(Dir.tmpdir, "filecon_error.log"),
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 %name"
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 -hs %name | cut -wf1"
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
@@ -1,3 +1,3 @@
1
1
  module Filecon
2
- VERSION = "0.2.1"
2
+ VERSION = "0.3.0"
3
3
  end
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
- #switch_view
33
- def switch_to id=nil
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.gsub(/[\n\t]/, ?|)
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
- return unless cmd = Grid.new( left:left+1, top: pop, right: -1,
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, hints: "1234567890",
82
- colors: {columns: @colors[:commands] || [:green, :red] } ).pick( :row, column: 0 )
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
- return unless file = pick(:file)
122
- cmd += ?" + file + ?"
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
- n = popup(input: pairs, hints:"1234567890", format:[:min,:max],
218
+ picker = popup(input: pairs, format:[:min,:max],
175
219
  alternate: true, left: left, bottom: -2,
176
- colors: { columns: fc, fields: fields }).pick(:row, column: :all)
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, true ) if id.is_a? Integer
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, true) if id.is_a? Integer
401
+ open_file( id, !alt ) if id.is_a? Integer
343
402
  @user.reset
344
403
  end
345
404
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: filecon
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kilian Reitmayr