filecon 0.1.1 → 0.1.2
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 +16 -5
- data/bin/filecon +27 -17
- data/config.yaml +8 -4
- data/filecon.1 +16 -3
- data/lib/filecon/version.rb +1 -1
- data/lib/filecon.rb +39 -57
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7999c20dbb6c7d75ff85343c955bb07794853b9bab8859132cf368b8f48735dd
|
|
4
|
+
data.tar.gz: 41bcfea5119ff2ebe534305a3eda418e825d9980dd329fb2dbf51cf783b35e29
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e0e7cb9f038a8f91adabda6258643dd9e2a11557b471740b2adb7fa42a9f93a0a027a62a659719e5370de463974083d4e5f5f3ee509ae782def11620624b2936
|
|
7
|
+
data.tar.gz: bcdc1bb5b7dfb36fe9bb43c4d8a50db175081d45aa548796e5482204056d4ae3e0d41fae0401ec547f32bd25ed840921c221e2c485d98a108285e5d21c0b5b81
|
data/README.md
CHANGED
|
@@ -54,7 +54,7 @@ filecon [directory]
|
|
|
54
54
|
|
|
55
55
|
**Directory**
|
|
56
56
|
- `~` — Go to home directory
|
|
57
|
-
- `` ` `` —
|
|
57
|
+
- `` ` `` — Open commands for current directory
|
|
58
58
|
- `d` — Directory history
|
|
59
59
|
|
|
60
60
|
**Other**
|
|
@@ -63,12 +63,23 @@ filecon [directory]
|
|
|
63
63
|
|
|
64
64
|
### Configuration
|
|
65
65
|
|
|
66
|
-
Config is stored at `~/.config/filecon/config.yaml` and includes:
|
|
66
|
+
Config is stored at `~/.config/filecon/config.yaml` (YAML format) and includes:
|
|
67
67
|
|
|
68
|
-
- Color settings
|
|
69
|
-
- Command definitions per
|
|
68
|
+
- Color settings (named colors, 8-bit palette, RGB triplets)
|
|
69
|
+
- Command definitions per MIME type
|
|
70
70
|
- View configurations
|
|
71
|
-
- History limits
|
|
71
|
+
- History limits and terminal settings
|
|
72
|
+
|
|
73
|
+
**Command prefixes:**
|
|
74
|
+
|
|
75
|
+
- `|` — pipe output to status line
|
|
76
|
+
- `+` — run in a new terminal window
|
|
77
|
+
- `=` — display output in the text viewer
|
|
78
|
+
- `!` — evaluate as Ruby code
|
|
79
|
+
|
|
80
|
+
**Substitution variables:** `%name` (file path), `%dir` (directory picker), `%file` (file picker), `%str` (text input)
|
|
81
|
+
|
|
82
|
+
See `filecon(1)` or the installed `config.yaml` for full details.
|
|
72
83
|
|
|
73
84
|
## Development
|
|
74
85
|
|
data/bin/filecon
CHANGED
|
@@ -1,28 +1,38 @@
|
|
|
1
1
|
#!/usr/bin/ruby
|
|
2
2
|
|
|
3
|
+
require_relative "../lib/filecon"
|
|
4
|
+
|
|
3
5
|
begin
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
path = Filecon::PATH
|
|
7
|
+
FileUtils.mkpath path unless File.exist? path
|
|
8
|
+
FileUtils.cp File.join(__dir__, "../config.yaml"), path unless File.exist? File.join(path, "config.yaml")
|
|
9
|
+
dir_history_path = File.join(path, "dir_history")
|
|
10
|
+
cmd_history_path = File.join(path, "cmd_history")
|
|
11
|
+
FileUtils.touch dir_history_path
|
|
12
|
+
FileUtils.touch cmd_history_path
|
|
8
13
|
|
|
9
|
-
|
|
14
|
+
config = YAML.safe_load(File.read(File.join(path, "config.yaml")), permitted_classes: [Symbol]) || {}
|
|
10
15
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
Typr.init( color: config[:colors][:default] )
|
|
16
|
+
term = config["term"] || ENV["TERM"] || ""
|
|
17
|
+
term_hold = term + (config["term_hold"] || " --hold")
|
|
18
|
+
|
|
19
|
+
Typr.init config["colors"]["default"]
|
|
16
20
|
Typr.clear
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
21
|
+
|
|
22
|
+
app = Filecon::App.new( right: -1, bottom: -1,
|
|
23
|
+
dir_history: File.read(dir_history_path).split($/),
|
|
24
|
+
cmd_history: File.read(cmd_history_path).split($/),
|
|
20
25
|
directory: ARGV.first, keymap: { open_file: ?o, cmd_history: ?c },
|
|
21
|
-
colors: { cmd_history: :red }.merge( config[
|
|
22
|
-
views: config[
|
|
23
|
-
commands: config[
|
|
26
|
+
colors: { cmd_history: :red }.merge( config["colors"] || {} ),
|
|
27
|
+
views: config["views"] || {},
|
|
28
|
+
commands: config["commands"] || {},
|
|
24
29
|
term: term,
|
|
25
|
-
term_hold: term_hold
|
|
30
|
+
term_hold: term_hold,
|
|
31
|
+
max_history: config["max_history"] || 100,
|
|
32
|
+
dir_history_path: dir_history_path,
|
|
33
|
+
cmd_history_path: cmd_history_path )
|
|
34
|
+
Typr.on_resize { app.draw }
|
|
35
|
+
app.fly
|
|
26
36
|
rescue => e
|
|
27
37
|
File.write File.join(Dir.tmpdir, "filecon_error.log"),
|
|
28
38
|
"#{e.class}: #{e.message}\n#{e.backtrace.first(10).join("\n")}"
|
data/config.yaml
CHANGED
|
@@ -96,15 +96,17 @@ colors:
|
|
|
96
96
|
commands:
|
|
97
97
|
default:
|
|
98
98
|
open: "|xdg-open %name"
|
|
99
|
-
|
|
99
|
+
disk_use: "|du -hs %name"
|
|
100
100
|
info: "=file %name"
|
|
101
|
-
copy: "
|
|
101
|
+
copy: "|rsync --progress %name %dir"
|
|
102
102
|
move: "|mv %name %dir"
|
|
103
103
|
delete: "|rm %name"
|
|
104
104
|
|
|
105
105
|
directory:
|
|
106
106
|
cd: "!cd %name"
|
|
107
|
-
|
|
107
|
+
new_file: "|micro %str"
|
|
108
|
+
new_dir: "|mkdir %str"
|
|
109
|
+
|
|
108
110
|
text:
|
|
109
111
|
view: "+moor %name"
|
|
110
112
|
edit: "+micro %name"
|
|
@@ -237,7 +239,9 @@ views:
|
|
|
237
239
|
subtype: true
|
|
238
240
|
description: "file -b %name"
|
|
239
241
|
|
|
240
|
-
|
|
242
|
+
count:
|
|
243
|
+
chars: "wc -m %name"
|
|
244
|
+
words: "wc -w %name"
|
|
241
245
|
lines: "wc -l %name"
|
|
242
246
|
|
|
243
247
|
whatis:
|
data/filecon.1
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
.TH FILECON 1 "2026-07-
|
|
1
|
+
.TH FILECON 1 "2026-07-27" "filecon 0.1.1" "User Commands"
|
|
2
2
|
.SH NAME
|
|
3
3
|
filecon \- interactive terminal file manager with hint-based navigation
|
|
4
4
|
.SH SYNOPSIS
|
|
@@ -60,7 +60,7 @@ Filter rows
|
|
|
60
60
|
Recurse directory tree
|
|
61
61
|
.TP
|
|
62
62
|
.B `
|
|
63
|
-
|
|
63
|
+
Open commands for current directory
|
|
64
64
|
.TP
|
|
65
65
|
.B ~
|
|
66
66
|
Navigate to home directory
|
|
@@ -80,7 +80,7 @@ Browse command history
|
|
|
80
80
|
.SH CONFIGURATION
|
|
81
81
|
On first run, the default
|
|
82
82
|
.B config.yaml
|
|
83
|
-
is copied from the installation directory to
|
|
83
|
+
(YAML format) is copied from the installation directory to
|
|
84
84
|
.BR ~/.config/filecon/ .
|
|
85
85
|
.SS Config File Locations
|
|
86
86
|
.TP
|
|
@@ -92,6 +92,19 @@ Directory navigation history
|
|
|
92
92
|
.TP
|
|
93
93
|
.B ~/.config/filecon/cmd_history
|
|
94
94
|
Command execution history
|
|
95
|
+
.SS Command Prefixes
|
|
96
|
+
.TP
|
|
97
|
+
.B |
|
|
98
|
+
Pipe output to status line
|
|
99
|
+
.TP
|
|
100
|
+
.B +
|
|
101
|
+
Run in a new terminal window
|
|
102
|
+
.TP
|
|
103
|
+
.B =
|
|
104
|
+
Display output in the text viewer
|
|
105
|
+
.TP
|
|
106
|
+
.B !
|
|
107
|
+
Evaluate as Ruby code
|
|
95
108
|
.SS Command Substitutions
|
|
96
109
|
.TP
|
|
97
110
|
.B %name
|
data/lib/filecon/version.rb
CHANGED
data/lib/filecon.rb
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
require "fileutils"
|
|
2
|
-
require "open3"
|
|
3
2
|
require "yaml"
|
|
4
3
|
|
|
5
4
|
begin
|
|
@@ -12,49 +11,14 @@ require_relative "filecon/version"
|
|
|
12
11
|
|
|
13
12
|
module Filecon
|
|
14
13
|
PATH = File.join(ENV["HOME"], ".config/filecon/")
|
|
15
|
-
|
|
16
|
-
def self.dir_history_path
|
|
17
|
-
File.join(PATH, "dir_history")
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
def self.cmd_history_path
|
|
21
|
-
File.join(PATH, "cmd_history")
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
def self.setup_config
|
|
25
|
-
FileUtils.mkpath PATH unless File.exist? PATH
|
|
26
|
-
FileUtils.cp File.join(__dir__, "../config.yaml"), PATH unless File.exist? File.join(PATH, "config.yaml")
|
|
27
|
-
FileUtils.touch dir_history_path
|
|
28
|
-
FileUtils.touch cmd_history_path
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
def self.deep_symbolize_keys(obj)
|
|
32
|
-
case obj
|
|
33
|
-
when Hash
|
|
34
|
-
obj.each_with_object({}) { |(k, v), h| h[k.to_sym] = deep_symbolize_keys(v) }
|
|
35
|
-
when Array
|
|
36
|
-
obj.map { |v| deep_symbolize_keys(v) }
|
|
37
|
-
else
|
|
38
|
-
obj
|
|
39
|
-
end
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
def self.config
|
|
43
|
-
config_path = File.join(PATH, "config.yaml")
|
|
44
|
-
if File.exist?(config_path)
|
|
45
|
-
deep_symbolize_keys(YAML.safe_load(File.read(config_path), permitted_classes: [Symbol]))
|
|
46
|
-
else
|
|
47
|
-
{}
|
|
48
|
-
end
|
|
49
|
-
end
|
|
50
14
|
end
|
|
51
15
|
|
|
52
16
|
class Filecon::App < Typr::Browser
|
|
53
17
|
include Typr
|
|
54
18
|
|
|
55
19
|
def cd dir, append=false; super
|
|
56
|
-
File.write
|
|
57
|
-
@dir_history[0
|
|
20
|
+
File.write @dir_history_path,
|
|
21
|
+
@dir_history[0..@max_history].join($/)
|
|
58
22
|
return
|
|
59
23
|
end
|
|
60
24
|
|
|
@@ -78,15 +42,17 @@ class Filecon::App < Typr::Browser
|
|
|
78
42
|
@current = id
|
|
79
43
|
end
|
|
80
44
|
|
|
81
|
-
def open_file id=nil, default=false
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
45
|
+
def open_file id=nil, default=false, types=nil
|
|
46
|
+
unless id || types
|
|
47
|
+
return unless id ||= @selected[:rows].empty? ?
|
|
48
|
+
@user.ask( open:[self, :row] ) : @selected[:rows]
|
|
49
|
+
end
|
|
50
|
+
types ||= if id.is_a? Array
|
|
85
51
|
eval id.map{ |id| @data[id].values_at(SUBTYPE,TYPE).to_s }.join(?&)
|
|
86
52
|
else @data[id].values_at(SUBTYPE, TYPE)
|
|
87
|
-
end - [??] + [
|
|
53
|
+
end - [??] + ["default"]
|
|
88
54
|
|
|
89
|
-
commands = @commands.values_at( *types
|
|
55
|
+
commands = @commands.values_at( *types ).map(&:to_a).flatten 1
|
|
90
56
|
cmd = if default; commands.first.last
|
|
91
57
|
else move left+1,top+1
|
|
92
58
|
if id.is_a?(Array); show "#{id.count.to_s} files: (#{
|
|
@@ -99,23 +65,25 @@ class Filecon::App < Typr::Browser
|
|
|
99
65
|
commands[ cmd ].last
|
|
100
66
|
end
|
|
101
67
|
cmd = build cmd, id
|
|
102
|
-
if cmd
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
68
|
+
if cmd[0] == ?|
|
|
69
|
+
display = cmd[1..-1]
|
|
70
|
+
io = run( cmd, true )
|
|
71
|
+
output = io.read.to_s.scrub.strip
|
|
72
|
+
@user.draw "> #{display} : #{output.lines.last}"
|
|
73
|
+
Typr.read :key
|
|
74
|
+
else
|
|
75
|
+
run( cmd, cmd[0..2] != '!cd' )
|
|
76
|
+
draw
|
|
77
|
+
end
|
|
111
78
|
end
|
|
112
79
|
|
|
113
80
|
def build str, id
|
|
114
81
|
cmd = ""
|
|
115
82
|
while str[/\%(name|dir|file|str)/]
|
|
116
|
-
|
|
83
|
+
cmd += $`
|
|
117
84
|
case $&
|
|
118
|
-
when '%name'; cmd += ?"+( id.
|
|
85
|
+
when '%name'; cmd += ?"+( id.nil? ? @directory :
|
|
86
|
+
id.is_a?( Array ) ? id.map{ |id|
|
|
119
87
|
@directory + @data[id][NAME] }.join('" "') :
|
|
120
88
|
@directory + @data[id][NAME] )+?"
|
|
121
89
|
when '%dir'; cmd += ?"+(pick :directory)+?"
|
|
@@ -141,7 +109,7 @@ class Filecon::App < Typr::Browser
|
|
|
141
109
|
if store
|
|
142
110
|
@cmd_history.unshift cmd
|
|
143
111
|
@cmd_history.uniq!
|
|
144
|
-
File.write
|
|
112
|
+
File.write @cmd_history_path, @cmd_history[0..@max_history].join($/)
|
|
145
113
|
end
|
|
146
114
|
return io
|
|
147
115
|
end
|
|
@@ -150,11 +118,23 @@ class Filecon::App < Typr::Browser
|
|
|
150
118
|
colors: { columns: [ @colors[:cmd_history] ] } } ).pick(:row), true
|
|
151
119
|
end
|
|
152
120
|
|
|
121
|
+
def help
|
|
122
|
+
info = "\nFILECON - a terminal file manager\n\n" \
|
|
123
|
+
"HINTS: press a number (1-9,0) to open that file with its default action.\n" \
|
|
124
|
+
" TAB cycles pages of hints.\n\n" \
|
|
125
|
+
"CONFIG: ~/.config/filecon/config.yaml\n\n" \
|
|
126
|
+
"KEYBINDINGS:\n\n" + @user.bindings.join(?\n)
|
|
127
|
+
Text.new( input: info, top:2, left:3, right: -3, bottom: -3, header: "HELP",
|
|
128
|
+
colors: { header: [:black,:white], border:[:white,:grey10] },
|
|
129
|
+
border: :light ).pick :none
|
|
130
|
+
end
|
|
131
|
+
|
|
153
132
|
def initialize args={}
|
|
154
133
|
super
|
|
155
134
|
@user.bindings.insert 1, "[o]pen"
|
|
156
135
|
@user.bindings.insert 7, "[c]ommands"
|
|
157
136
|
@user.draw
|
|
137
|
+
|
|
158
138
|
end
|
|
159
139
|
|
|
160
140
|
def fly
|
|
@@ -162,12 +142,14 @@ class Filecon::App < Typr::Browser
|
|
|
162
142
|
draw
|
|
163
143
|
draw_hints :rows
|
|
164
144
|
key = Typr.read :key
|
|
165
|
-
|
|
145
|
+
next unless key
|
|
166
146
|
case key
|
|
167
147
|
when KEY_ESCAPE; exit
|
|
148
|
+
when ?`; open_file nil, false, ["directory", "inode"] - [??] + ["default"]
|
|
168
149
|
else
|
|
169
150
|
id = send( key )
|
|
170
151
|
open_file id, true if id.is_a? Integer
|
|
152
|
+
@user.reset
|
|
171
153
|
end
|
|
172
154
|
end
|
|
173
155
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: filecon
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Kilian Reitmayr
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-07-
|
|
11
|
+
date: 2026-07-28 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: typr
|