filecon 0.1.2 → 0.2.1
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 +50 -21
- data/bin/filecon +30 -17
- data/config.yaml +72 -31
- data/filecon.1 +6 -0
- data/lib/filecon/version.rb +1 -1
- data/lib/filecon.rb +241 -50
- data/logo_alpha_small.png +0 -0
- metadata +6 -8
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d62cae7fca7f8ef2348b79ac2df27edfafbc5da7ada9523a2fad5b38de27e5a9
|
|
4
|
+
data.tar.gz: 20fe942d398a0dd68e27a5cdc5b40d16d296e33399327494aaa608d847401e47
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1d2ac9423eecd422db9ac518ba264ef56b3f9d17823950f648e56eff3de0dd08326daba18bfd8eeeba51d76e072a060f4be5c6542a50c709623adac370f080f0
|
|
7
|
+
data.tar.gz: 198c5fa607c36cbc86808d42e3b0a806d83832ba5432827c871526d8ebaebaaa8cc3864f7a486e586b00ce2e983086e81184d08fe993f93ca2fa58fd7b0c9fd6
|
data/README.md
CHANGED
|
@@ -1,14 +1,33 @@
|
|
|
1
|
+

|
|
2
|
+
|
|
1
3
|
# Filecon
|
|
2
4
|
|
|
3
|
-
|
|
5
|
+
## Description
|
|
6
|
+
|
|
7
|
+
Filecon is a terminal-based file manager built on the [Typr](https://codeberg.org/typr/typr) terminal UI toolkit. It packs everything a file manager should do into a keyboard-driven terminal program: every file, command, and directory is reachable in a few keystrokes, and the most common operations take the fewest key presses.
|
|
8
|
+
|
|
9
|
+
Filecon is designed to be **intuitive**, **complete**, **powerful**, and the **fastest possible** file manager. The whole interface is built around that principle:
|
|
10
|
+
|
|
11
|
+
- **Hint navigation** — every visible row carries a number hint (1–9, 0); pressing it acts on that row immediately, no cursor movement needed.
|
|
12
|
+
- **Live search in popups** — command and history popups open in `/` search mode; type to distill the list, then pick one of the few remaining results with a number.
|
|
13
|
+
- **Frequency-ordered history** — directory and command history are ranked by use count, so the most likely choice is always near the top.
|
|
14
|
+
|
|
15
|
+
Filecon's long-term goal is to become an **interactive shell**: a separate companion program will handle command building, and combined with Filecon the two will form a full interactive shell that competes with interactive CLI shells.
|
|
16
|
+
|
|
17
|
+
Filecon runs on Typr, whose self-contained terminal layer ships its own precompiled terminfo key table and MIME-type database in the gem — no ncurses or external tooling required — so Filecon works on any raw, ANSI-capable terminal (including Termux).
|
|
4
18
|
|
|
5
19
|
## Features
|
|
6
20
|
|
|
7
|
-
- Directory browsing with MIME-type detection
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
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
|
+
- **Fastest possible navigation** — hint numbers (1–9, 0) open rows directly; TAB pages hints beyond the first ten
|
|
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
|
|
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
|
+
- **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
|
+
- **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
|
|
29
|
+
- **Power browsing** — recursive directory listing, `execute` ($PATH browser), marking, filtering, sorting, and switchable column views
|
|
30
|
+
- **Fully documented configuration** — a self-documenting `config.yaml` covers colors, commands, views, history, and terminal settings
|
|
12
31
|
|
|
13
32
|
## Installation
|
|
14
33
|
|
|
@@ -16,12 +35,6 @@ A terminal-based file manager built on the [Typr](https://codeberg.org/typr/typr
|
|
|
16
35
|
gem install filecon
|
|
17
36
|
```
|
|
18
37
|
|
|
19
|
-
Or add to your Gemfile:
|
|
20
|
-
|
|
21
|
-
```ruby
|
|
22
|
-
gem "filecon", "~> 0.1"
|
|
23
|
-
```
|
|
24
|
-
|
|
25
38
|
## Usage
|
|
26
39
|
|
|
27
40
|
```bash
|
|
@@ -39,12 +52,14 @@ filecon [directory]
|
|
|
39
52
|
**Actions**
|
|
40
53
|
- `o` — Open list of all commands for selected file
|
|
41
54
|
- `c` — Command history
|
|
55
|
+
- `x` — List all executables from $PATH directories
|
|
42
56
|
- `h` — Help
|
|
43
57
|
- `v` — Views
|
|
44
58
|
- `s` — Sort view
|
|
45
59
|
- `f` — Filter view
|
|
46
60
|
- `r` — Reset view
|
|
47
|
-
- `R` —
|
|
61
|
+
- `R` — Recursive file listing
|
|
62
|
+
- `/` — Search the listing by name
|
|
48
63
|
|
|
49
64
|
**Marking**
|
|
50
65
|
- `m` — Mark file
|
|
@@ -61,32 +76,46 @@ filecon [directory]
|
|
|
61
76
|
- Enter — Select / confirm
|
|
62
77
|
- Esc — Quit
|
|
63
78
|
|
|
79
|
+
### Mouse
|
|
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.
|
|
82
|
+
|
|
83
|
+
### Popups and search
|
|
84
|
+
|
|
85
|
+
Command and history popups open in `/` search mode. Type a few characters to **distill** the list down to the matching entries; when only a handful remain, press the number hint of the one you want. Large lists can be narrowed in a keystroke or two. The main listing searches the same way when you press `/`.
|
|
86
|
+
|
|
64
87
|
### Configuration
|
|
65
88
|
|
|
66
|
-
Config is stored at `~/.config/filecon/config.yaml` (YAML
|
|
89
|
+
Config is stored at `~/.config/filecon/config.yaml` (YAML). On first run the bundled, fully documented `config.yaml` is copied there. It includes:
|
|
67
90
|
|
|
68
|
-
- Color settings (named colors, 8-bit palette, RGB triplets)
|
|
69
|
-
- Command definitions per MIME type
|
|
70
|
-
- View configurations
|
|
91
|
+
- Color settings (named colors, 8-bit palette, RGB triplets) — including the `colors.commands` pair used by the command picker and status line
|
|
92
|
+
- Command definitions per MIME type, with execution-mode prefixes
|
|
93
|
+
- View configurations (columns that run shell commands)
|
|
71
94
|
- History limits and terminal settings
|
|
72
95
|
|
|
73
|
-
|
|
96
|
+
State and history files live under `~/.local/share/filecon/`.
|
|
97
|
+
|
|
98
|
+
**Command execution modes:**
|
|
74
99
|
|
|
75
|
-
- `|` — pipe output to status line
|
|
100
|
+
- `|` — pipe output to the status line
|
|
76
101
|
- `+` — run in a new terminal window
|
|
77
102
|
- `=` — display output in the text viewer
|
|
78
103
|
- `!` — evaluate as Ruby code
|
|
79
104
|
|
|
80
105
|
**Substitution variables:** `%name` (file path), `%dir` (directory picker), `%file` (file picker), `%str` (text input)
|
|
81
106
|
|
|
82
|
-
See `filecon(1)`
|
|
107
|
+
See `filecon(1)` for the full manual.
|
|
108
|
+
|
|
109
|
+
## Roadmap
|
|
110
|
+
|
|
111
|
+
- **Pointer-only mode** — full mouse-driven operation of the entire interface, building on the click/wheel mouse support already present
|
|
112
|
+
- **Interactive shell** — a separate command-building program that combines with Filecon into an interactive shell competing with interactive CLI shells
|
|
83
113
|
|
|
84
114
|
## Development
|
|
85
115
|
|
|
86
116
|
```bash
|
|
87
117
|
git clone https://codeberg.org/typr/filecon
|
|
88
118
|
cd filecon
|
|
89
|
-
bundle install
|
|
90
119
|
rake test
|
|
91
120
|
```
|
|
92
121
|
|
data/bin/filecon
CHANGED
|
@@ -1,39 +1,52 @@
|
|
|
1
1
|
#!/usr/bin/ruby
|
|
2
2
|
|
|
3
|
+
require "fileutils"
|
|
4
|
+
require "yaml"
|
|
3
5
|
require_relative "../lib/filecon"
|
|
4
6
|
|
|
5
7
|
begin
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
8
|
+
config_dir = File.expand_path("~/.config/filecon")
|
|
9
|
+
config_path = File.join(config_dir, "config.yaml")
|
|
10
|
+
unless File.exist?(config_path)
|
|
11
|
+
FileUtils.mkpath config_dir
|
|
12
|
+
FileUtils.cp File.join(__dir__, "../config.yaml"), config_path
|
|
13
|
+
end
|
|
14
|
+
state_dir = File.expand_path("~/.local/share/filecon")
|
|
15
|
+
FileUtils.mkpath state_dir
|
|
13
16
|
|
|
14
|
-
|
|
17
|
+
dh_path = File.join(state_dir, "dir_history")
|
|
18
|
+
ch_path = File.join(state_dir, "cmd_history")
|
|
19
|
+
|
|
20
|
+
[dh_path, ch_path].each { |f| FileUtils.touch f }
|
|
21
|
+
|
|
22
|
+
parse = ->(p) { File.readlines(p).map { |l| s = l.chomp.split(",", 2); [s[0].to_i, s[1]] } rescue [] }
|
|
23
|
+
|
|
24
|
+
config = YAML.safe_load(File.read(config_path), permitted_classes: [Symbol]) || {}
|
|
15
25
|
|
|
16
26
|
term = config["term"] || ENV["TERM"] || ""
|
|
17
|
-
|
|
27
|
+
term += config["term_hold"] if config["term_hold"]
|
|
18
28
|
|
|
19
29
|
Typr.init config["colors"]["default"]
|
|
20
30
|
Typr.clear
|
|
21
31
|
|
|
22
32
|
app = Filecon::App.new( right: -1, bottom: -1,
|
|
23
|
-
dir_history:
|
|
24
|
-
cmd_history:
|
|
25
|
-
|
|
26
|
-
|
|
33
|
+
dir_history: parse[dh_path],
|
|
34
|
+
cmd_history: parse[ch_path],
|
|
35
|
+
path: { config: config_path, state: state_dir, dir_history: dh_path,
|
|
36
|
+
cmd_history: ch_path },
|
|
37
|
+
directory: ARGV.first || ?., keymap: { open_file: ?o, cmd_history: ?c, dir_history: ?d, recurse: ?R, open_current: ?` },
|
|
38
|
+
colors: config["colors"] || {},
|
|
27
39
|
views: config["views"] || {},
|
|
28
40
|
commands: config["commands"] || {},
|
|
29
41
|
term: term,
|
|
30
|
-
term_hold: term_hold,
|
|
31
42
|
max_history: config["max_history"] || 100,
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
Typr.on_resize { app.
|
|
43
|
+
frequency_limit: config["frequency_limit"] || 10,
|
|
44
|
+
filter_dirs: config["filter_dirs"] )
|
|
45
|
+
Typr.on_resize { app.show }
|
|
46
|
+
app.import_shell_history
|
|
35
47
|
app.fly
|
|
36
48
|
rescue => e
|
|
49
|
+
$stderr.puts "#{e.class}: #{e.message}\n#{e.backtrace.first(10).join("\n")}"
|
|
37
50
|
File.write File.join(Dir.tmpdir, "filecon_error.log"),
|
|
38
51
|
"#{e.class}: #{e.message}\n#{e.backtrace.first(10).join("\n")}"
|
|
39
52
|
ensure
|
data/config.yaml
CHANGED
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
# =============================================================================
|
|
4
4
|
#
|
|
5
5
|
# This is the default configuration file for Filecon, a terminal file manager.
|
|
6
|
-
# Copy this file to ~/.config/filecon/config.yaml and customize as needed.
|
|
7
6
|
#
|
|
8
7
|
# All settings are optional. Filecon will use sensible defaults if values
|
|
9
8
|
# are not specified.
|
|
@@ -22,7 +21,11 @@ term_hold: " --hold"
|
|
|
22
21
|
|
|
23
22
|
# Maximum number of history entries to retain.
|
|
24
23
|
# Older entries beyond this limit are automatically pruned.
|
|
25
|
-
max_history:
|
|
24
|
+
max_history: 10000
|
|
25
|
+
|
|
26
|
+
frequency_limit: 10
|
|
27
|
+
# When true, active filters also hide directories that don't match.
|
|
28
|
+
filter_dirs: true
|
|
26
29
|
|
|
27
30
|
|
|
28
31
|
# =============================================================================
|
|
@@ -32,11 +35,28 @@ max_history: 100
|
|
|
32
35
|
# Customize the color scheme for different file types in the browser view.
|
|
33
36
|
#
|
|
34
37
|
# Color values can be:
|
|
35
|
-
# - Named colors:
|
|
38
|
+
# - Named colors:
|
|
39
|
+
# Basic: black, red, green, yellow, blue, magenta, cyan, white, grey
|
|
40
|
+
# Shades: brown, orange, lime, pink, maroon, navy, teal, olive, coral, tan
|
|
41
|
+
# Dark: dark_red, dark_green, dark_yellow, dark_blue,
|
|
42
|
+
# dark_magenta, dark_cyan
|
|
36
43
|
# - Grey shades: grey0 through grey100 (e.g., grey62 for 62% grey)
|
|
37
44
|
# - 8-bit palette: 0 - 255 (maps to terminal's 256-color palette)
|
|
38
45
|
# - RGB triplets: [0-255, 0-255, 0-255] (true color terminals)
|
|
39
46
|
#
|
|
47
|
+
# Color settings passed to Typr spaces:
|
|
48
|
+
# default global default foreground/background [fg, bg]
|
|
49
|
+
# border widget borders
|
|
50
|
+
# header column/panel headers
|
|
51
|
+
# question prompt question text
|
|
52
|
+
# answer typed input text
|
|
53
|
+
# selected highlighted / selected row background
|
|
54
|
+
# alternate alternating row background in lists
|
|
55
|
+
# hints hint numbers/digits
|
|
56
|
+
# actions named action colors: "[f]ilter", "[s]ort", "[v]iews"
|
|
57
|
+
# commands command picker and status line: [name, args] colors
|
|
58
|
+
# search search-match highlight (text viewer)
|
|
59
|
+
#
|
|
40
60
|
# Usage:
|
|
41
61
|
# Foreground color only: "blue"
|
|
42
62
|
# Foreground + background: ["white", "black"]
|
|
@@ -45,12 +65,16 @@ max_history: 100
|
|
|
45
65
|
|
|
46
66
|
colors:
|
|
47
67
|
default: ["white", "black"]
|
|
68
|
+
# [name, args] colors for the command picker and the status line
|
|
69
|
+
# shown while building/running a command
|
|
70
|
+
commands: ["green", "red"]
|
|
48
71
|
types:
|
|
49
72
|
image: "blue"
|
|
50
73
|
audio: "green"
|
|
51
74
|
video: "cyan"
|
|
52
75
|
directory: "yellow"
|
|
53
76
|
"x-pie-executable": "red"
|
|
77
|
+
# executable: "red"
|
|
54
78
|
|
|
55
79
|
|
|
56
80
|
# =============================================================================
|
|
@@ -91,39 +115,59 @@ colors:
|
|
|
91
115
|
#
|
|
92
116
|
# %str - Prompts for text input, inserts the string
|
|
93
117
|
#
|
|
118
|
+
# SPECIAL CATEGORIES:
|
|
119
|
+
#
|
|
120
|
+
# executable - Added to the command picker for any file whose
|
|
121
|
+
# executable bit is set for the current user, regardless
|
|
122
|
+
# of its MIME type (e.g. shell scripts with shebangs).
|
|
123
|
+
#
|
|
94
124
|
# =============================================================================
|
|
95
125
|
|
|
96
126
|
commands:
|
|
97
127
|
default:
|
|
98
|
-
|
|
99
|
-
disk_use: "|du -hs %name"
|
|
128
|
+
# copy: "|rsync --progress %name %dir"
|
|
100
129
|
info: "=file %name"
|
|
101
|
-
copy: "|
|
|
130
|
+
copy: "|cp -R %name %dir"
|
|
102
131
|
move: "|mv %name %dir"
|
|
103
|
-
|
|
132
|
+
rename: "|mv %name %str"
|
|
133
|
+
delete: "|rm -rf %name"
|
|
134
|
+
open_with: "|%file %name %str"
|
|
135
|
+
open_with_terminal: "+%file %name %str"
|
|
136
|
+
xdg_open: "|xdg-open %name"
|
|
137
|
+
|
|
138
|
+
executable:
|
|
139
|
+
run: "|%name %str"
|
|
140
|
+
run_terminal: "+%name %str"
|
|
141
|
+
help: "=%name --help"
|
|
142
|
+
manual: "+man %name"
|
|
104
143
|
|
|
105
144
|
directory:
|
|
106
145
|
cd: "!cd %name"
|
|
107
|
-
new_file: "|
|
|
108
|
-
new_dir: "|mkdir %str"
|
|
109
|
-
|
|
146
|
+
new_file: "|touch %name/%str"
|
|
147
|
+
new_dir: "|mkdir %name/%str"
|
|
148
|
+
shell: "+$SHELL -c 'cd %name && exec $SHELL'"
|
|
149
|
+
# zsh: "+zsh -c 'cd %name && exec zsh'"
|
|
150
|
+
disk_use: "|du -hs %name | cut -wf1"
|
|
151
|
+
play: "+mpv %name"
|
|
152
|
+
|
|
110
153
|
text:
|
|
111
154
|
view: "+moor %name"
|
|
112
155
|
edit: "+micro %name"
|
|
113
|
-
count: "|wc -l %name"
|
|
156
|
+
count: "|wc -l %name | cut -wf1"
|
|
114
157
|
|
|
115
158
|
troff:
|
|
116
159
|
manual: "+man %name"
|
|
117
160
|
|
|
118
161
|
"x-ruby":
|
|
119
|
-
run: "
|
|
162
|
+
run: "|ruby %name"
|
|
163
|
+
run_terminal: "+ruby %name"
|
|
120
164
|
|
|
121
165
|
html:
|
|
122
166
|
terminal: "+cha %name"
|
|
123
167
|
graphics: "|vimb %name"
|
|
124
168
|
|
|
125
169
|
image:
|
|
126
|
-
|
|
170
|
+
view: "|pqiv %name"
|
|
127
171
|
|
|
128
172
|
video:
|
|
129
173
|
play: "|mpv %name"
|
|
@@ -134,12 +178,6 @@ commands:
|
|
|
134
178
|
pdf:
|
|
135
179
|
view: "|mupdf %name"
|
|
136
180
|
|
|
137
|
-
"x-pie-executable":
|
|
138
|
-
run: "|%name"
|
|
139
|
-
run_terminal: "+%name"
|
|
140
|
-
help: "=%name --help"
|
|
141
|
-
manual: "+man %name"
|
|
142
|
-
|
|
143
181
|
"x-python":
|
|
144
182
|
run: "+python3 %name"
|
|
145
183
|
|
|
@@ -178,23 +216,23 @@ commands:
|
|
|
178
216
|
view: "=cat %name | jq ."
|
|
179
217
|
|
|
180
218
|
"zip":
|
|
181
|
-
list: "
|
|
219
|
+
list: "=unzip -l %name"
|
|
182
220
|
extract: "|unzip %name -d %dir"
|
|
183
221
|
|
|
184
222
|
"x-gzip":
|
|
185
|
-
list: "
|
|
223
|
+
list: "=tar -tzf %name"
|
|
186
224
|
extract: "|tar -xzf %name -C %dir"
|
|
187
225
|
|
|
188
226
|
"x-bzip2":
|
|
189
|
-
list: "
|
|
227
|
+
list: "=tar -tjf %name"
|
|
190
228
|
extract: "|tar -xjf %name -C %dir"
|
|
191
229
|
|
|
192
230
|
"x-xz":
|
|
193
|
-
list: "
|
|
231
|
+
list: "=tar -tJf %name"
|
|
194
232
|
extract: "|tar -xJf %name -C %dir"
|
|
195
233
|
|
|
196
234
|
"x-tar":
|
|
197
|
-
list: "
|
|
235
|
+
list: "=tar -tf %name"
|
|
198
236
|
extract: "|tar -xf %name -C %dir"
|
|
199
237
|
|
|
200
238
|
"epub+zip":
|
|
@@ -219,10 +257,10 @@ commands:
|
|
|
219
257
|
# - A string Command to execute (with %name substitution)
|
|
220
258
|
# - A symbol Reference to a system field (e.g., :size, :type, :subtype)
|
|
221
259
|
#
|
|
222
|
-
# Prefix ! to evaluate as Ruby
|
|
260
|
+
# Prefix ! to evaluate as Ruby
|
|
223
261
|
#
|
|
224
262
|
# Available system fields:
|
|
225
|
-
# target, permissions, owner, group, size,
|
|
263
|
+
# target, permissions, executable, owner, group, size,
|
|
226
264
|
# accessed, modified, created, type, subtype
|
|
227
265
|
#
|
|
228
266
|
# When a view is activated, its columns are appended to the default file
|
|
@@ -234,15 +272,18 @@ views:
|
|
|
234
272
|
content:
|
|
235
273
|
content: "head -n 50 %name"
|
|
236
274
|
|
|
237
|
-
|
|
275
|
+
types:
|
|
238
276
|
type: true
|
|
239
277
|
subtype: true
|
|
240
278
|
description: "file -b %name"
|
|
241
279
|
|
|
280
|
+
disk_use:
|
|
281
|
+
du: "du -hs %name | cut -wf1"
|
|
282
|
+
|
|
242
283
|
count:
|
|
243
|
-
chars: "wc -m %name"
|
|
244
|
-
words: "wc -w %name"
|
|
245
|
-
lines: "wc -l %name"
|
|
284
|
+
chars: "wc -m %name | cut -wf1"
|
|
285
|
+
words: "wc -w %name | cut -wf1"
|
|
286
|
+
lines: "wc -l %name | cut -wf1"
|
|
246
287
|
|
|
247
288
|
whatis:
|
|
248
|
-
whatis: "
|
|
289
|
+
whatis: "whatis $(basename %name) 2>&1 | sed 's/.* - //'"
|
data/filecon.1
CHANGED
|
@@ -77,6 +77,12 @@ Open list of all commands for selected file
|
|
|
77
77
|
.TP
|
|
78
78
|
.B c
|
|
79
79
|
Browse command history
|
|
80
|
+
.PP
|
|
81
|
+
Directory and command history popups list the most frequently used entries
|
|
82
|
+
first, then the remaining entries in most-recent order. The
|
|
83
|
+
.B frequency_limit
|
|
84
|
+
setting in config.yaml (default 10) controls how many frequent entries lead
|
|
85
|
+
the list.
|
|
80
86
|
.SH CONFIGURATION
|
|
81
87
|
On first run, the default
|
|
82
88
|
.B config.yaml
|
data/lib/filecon/version.rb
CHANGED
data/lib/filecon.rb
CHANGED
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
require "fileutils"
|
|
2
|
-
require "yaml"
|
|
3
|
-
|
|
4
1
|
begin
|
|
5
2
|
require_relative "../../typr/lib/typr"
|
|
6
3
|
rescue LoadError
|
|
@@ -9,19 +6,30 @@ end
|
|
|
9
6
|
|
|
10
7
|
require_relative "filecon/version"
|
|
11
8
|
|
|
12
|
-
module Filecon
|
|
13
|
-
PATH = File.join(ENV["HOME"], ".config/filecon/")
|
|
14
|
-
end
|
|
15
|
-
|
|
16
9
|
class Filecon::App < Typr::Browser
|
|
17
10
|
include Typr
|
|
18
11
|
|
|
19
|
-
def cd dir, append=false
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
12
|
+
def cd dir, append=false
|
|
13
|
+
if dir.is_a? Array
|
|
14
|
+
dirs = dir.filter_map { |d| d = File.expand_path(d.to_s); Dir.exist?(d) ? d : nil }
|
|
15
|
+
dirs.each_with_index { |d, i|
|
|
16
|
+
@directory = d if i.positive?
|
|
17
|
+
Dir.chdir(d) if i.positive?
|
|
18
|
+
super d, i.positive?
|
|
19
|
+
}
|
|
20
|
+
@directory = dirs
|
|
21
|
+
nil
|
|
22
|
+
else
|
|
23
|
+
dir = @dir_history[dir+1][1] if dir.is_a? Integer
|
|
24
|
+
record :dir, File.expand_path(dir) unless append || [?/, ENV["HOME"]].include?(dir)
|
|
25
|
+
super dir, append
|
|
26
|
+
nil
|
|
27
|
+
end
|
|
23
28
|
end
|
|
24
29
|
|
|
30
|
+
def execute; cd ENV["PATH"].split(":"); add_path_column end
|
|
31
|
+
|
|
32
|
+
#switch_view
|
|
25
33
|
def switch_to id=nil
|
|
26
34
|
return unless id
|
|
27
35
|
id = @views.keys[id] if id.is_a? Integer
|
|
@@ -30,9 +38,13 @@ class Filecon::App < Typr::Browser
|
|
|
30
38
|
data = @data.map.with_index{ |row, id| row + view.values.map{ |cmd|
|
|
31
39
|
next unless cmd.is_a?(String)
|
|
32
40
|
built = build cmd, id
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
41
|
+
next unless built
|
|
42
|
+
io = if built[0] == ?!
|
|
43
|
+
StringIO.new eval( built[1..-1] ).to_s
|
|
44
|
+
else
|
|
45
|
+
cmd = built[0] == ?| ? built : ?| + built
|
|
46
|
+
open cmd + " 2>&1"
|
|
47
|
+
end
|
|
36
48
|
io.read(width).to_s.scrub.gsub(/[\n\t]/, ?|)
|
|
37
49
|
}.compact }
|
|
38
50
|
@sequence = [ NAME ] + view.keys.map{ |head|
|
|
@@ -40,55 +52,79 @@ class Filecon::App < Typr::Browser
|
|
|
40
52
|
clear
|
|
41
53
|
self << data
|
|
42
54
|
@current = id
|
|
55
|
+
@view = id
|
|
43
56
|
end
|
|
44
57
|
|
|
45
58
|
def open_file id=nil, default=false, types=nil
|
|
46
59
|
unless id || types
|
|
47
60
|
return unless id ||= @selected[:rows].empty? ?
|
|
48
|
-
@user.ask( open:[self, :row] ) : @selected[:rows]
|
|
61
|
+
@user.ask( open:[self, :row, NAME] ) : @selected[:rows]
|
|
49
62
|
end
|
|
50
63
|
types ||= if id.is_a? Array
|
|
51
64
|
eval id.map{ |id| @data[id].values_at(SUBTYPE,TYPE).to_s }.join(?&)
|
|
52
65
|
else @data[id].values_at(SUBTYPE, TYPE)
|
|
53
66
|
end - [??] + ["default"]
|
|
67
|
+
if id && (id.is_a?(Array) ? id.all?{ |i| @data[i][EXECUTABLE] } : @data[id][EXECUTABLE])
|
|
68
|
+
types.insert(types.index("default") || types.size, "executable")
|
|
69
|
+
end
|
|
54
70
|
|
|
55
|
-
commands = @commands.values_at( *types ).map(&:to_a).flatten 1
|
|
56
|
-
|
|
71
|
+
commands = @commands.values_at( *types ).map(&:to_a).flatten( 1 ).uniq
|
|
72
|
+
pair = if default; commands.first
|
|
57
73
|
else move left+1,top+1
|
|
58
|
-
if id.is_a?(Array);
|
|
74
|
+
if id.is_a?(Array); draw "#{id.count.to_s} files: (#{
|
|
59
75
|
types.join ?, })".ljust width
|
|
60
76
|
else print id end
|
|
61
|
-
|
|
77
|
+
pop = id ? top+2 : top
|
|
78
|
+
return unless cmd = Grid.new( left:left+1, top: pop, right: -1,
|
|
79
|
+
bottom: [ pop + commands.count - 1, Typr.height ].min,
|
|
62
80
|
input:commands, border: :light, format: [:min, :max],
|
|
63
|
-
borders: { top: nil }, alternate: false,
|
|
64
|
-
colors: {columns: [:green, :red] } ).pick( :row )
|
|
65
|
-
commands[ cmd ]
|
|
81
|
+
borders: { top: nil }, alternate: false, hints: "1234567890",
|
|
82
|
+
colors: {columns: @colors[:commands] || [:green, :red] } ).pick( :row, column: 0 )
|
|
83
|
+
commands[ cmd ]
|
|
66
84
|
end
|
|
67
|
-
cmd = build
|
|
85
|
+
cmd = build pair.last, id, pair.first
|
|
86
|
+
return unless cmd
|
|
68
87
|
if cmd[0] == ?|
|
|
69
88
|
display = cmd[1..-1]
|
|
70
|
-
|
|
89
|
+
record :cmd, cmd
|
|
90
|
+
io = run( cmd )
|
|
71
91
|
output = io.read.to_s.scrub.strip
|
|
72
|
-
@
|
|
73
|
-
|
|
92
|
+
nc, ac = @colors[:commands] || [:green, :red]
|
|
93
|
+
@user.show "> #{color_code(nc)}#{pair.first}#{color_code(ac)}:#{display}" \
|
|
94
|
+
"#{color_code(@colors[:default])} : #{output.lines.last}"
|
|
95
|
+
Typr.read_key
|
|
74
96
|
else
|
|
75
|
-
|
|
76
|
-
|
|
97
|
+
record :cmd, cmd unless cmd[0..2] == '!cd'
|
|
98
|
+
run( cmd )
|
|
99
|
+
show
|
|
77
100
|
end
|
|
78
101
|
end
|
|
79
102
|
|
|
80
|
-
def build str, id
|
|
103
|
+
def build str, id, name=nil
|
|
104
|
+
nc, ac = @colors[:commands] || [:green, :red]
|
|
105
|
+
reset = color_code( @colors[:default] )
|
|
106
|
+
prefix = name ? "#{color_code(nc)}#{name}#{color_code(ac)}:" : ""
|
|
81
107
|
cmd = ""
|
|
82
108
|
while str[/\%(name|dir|file|str)/]
|
|
83
109
|
cmd += $`
|
|
84
110
|
case $&
|
|
85
111
|
when '%name'; cmd += ?"+( id.nil? ? @directory :
|
|
86
112
|
id.is_a?( Array ) ? id.map{ |id|
|
|
87
|
-
@
|
|
88
|
-
@
|
|
89
|
-
when '%dir'
|
|
90
|
-
|
|
91
|
-
|
|
113
|
+
@data[id][NAME] }.join('" "') :
|
|
114
|
+
@data[id][NAME] )+?"
|
|
115
|
+
when '%dir'
|
|
116
|
+
@user.show "> #{prefix}#{cmd}#{$&}#{$'}#{reset}"
|
|
117
|
+
return unless dir = pick(:directory)
|
|
118
|
+
cmd += ?" + dir + ?"
|
|
119
|
+
when '%file'
|
|
120
|
+
@user.show "> #{prefix}#{cmd}#{$&}#{$'}#{reset}"
|
|
121
|
+
return unless file = pick(:file)
|
|
122
|
+
cmd += ?" + file + ?"
|
|
123
|
+
when '%str'
|
|
124
|
+
prompt = cmd.empty? || cmd.end_with?(' ') ? cmd : "#{cmd} "
|
|
125
|
+
query = Typr.read_line "> #{prefix}#{prompt}", left: left, top: @user.top
|
|
126
|
+
return unless query
|
|
127
|
+
cmd += query
|
|
92
128
|
end
|
|
93
129
|
str = str[($`+$&).size..-1]
|
|
94
130
|
end
|
|
@@ -96,32 +132,168 @@ class Filecon::App < Typr::Browser
|
|
|
96
132
|
return cmd
|
|
97
133
|
end
|
|
98
134
|
|
|
99
|
-
def run cmd=nil
|
|
135
|
+
def run cmd=nil
|
|
100
136
|
return unless cmd
|
|
101
|
-
cmd = @cmd_history[cmd] if cmd.is_a? Integer
|
|
137
|
+
cmd = @cmd_history[cmd][1] if cmd.is_a? Integer
|
|
102
138
|
case cmd[0]
|
|
103
139
|
when ?! then io = StringIO.new eval( cmd[1..-1] ).to_s
|
|
104
140
|
when ?| then io = open( cmd + " 2>&1" )
|
|
105
141
|
when ?+ then io = open( ?| + @term +' '+ cmd[1..-1] + " 2>&1" )
|
|
106
142
|
when ?= then Text.new(top: 2, right:-1, bottom:-2, border: :light,
|
|
107
143
|
input:open( ?|+cmd[1..-1]+" 2>&1" ) ).pick :none
|
|
108
|
-
|
|
109
|
-
if store
|
|
110
|
-
@cmd_history.unshift cmd
|
|
111
|
-
@cmd_history.uniq!
|
|
112
|
-
File.write @cmd_history_path, @cmd_history[0..@max_history].join($/)
|
|
144
|
+
else io = open( ?| + @term +' '+ cmd + " 2>&1" )
|
|
113
145
|
end
|
|
114
146
|
return io
|
|
115
147
|
end
|
|
116
148
|
|
|
117
|
-
def cmd_history;
|
|
118
|
-
|
|
149
|
+
def cmd_history; history @cmd_history, :cmd end
|
|
150
|
+
def dir_history; history @dir_history, :dir end
|
|
151
|
+
|
|
152
|
+
def history data, type
|
|
153
|
+
is_cmd = type == :cmd
|
|
154
|
+
data = data.drop 1 unless is_cmd
|
|
155
|
+
return unless data.any?
|
|
156
|
+
|
|
157
|
+
top = data.max_by(@frequency_limit) { |cnt, _| cnt }
|
|
158
|
+
top_set = top.filter_map { |_, e| e }.to_h { |e| [e, true] }
|
|
159
|
+
ordered = top + data.reject { |_, e| top_set[e] }
|
|
160
|
+
|
|
161
|
+
pairs = ordered.map { |_, e|
|
|
162
|
+
is_cmd ? [e.split(' ', 2)[0], e.split(' ', 2)[1] || ""] :
|
|
163
|
+
[File.basename(e), e]
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
fc = is_cmd ? [:red, :blue] : [:yellow, :brown]
|
|
167
|
+
fields = {}
|
|
168
|
+
ordered.each_with_index { |(cnt, e), i|
|
|
169
|
+
next unless top_set[e]
|
|
170
|
+
fields[[i,0]] = [fc[0], :grey20]
|
|
171
|
+
fields[[i,1]] = [fc[1], :grey20]
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
n = popup(input: pairs, hints:"1234567890", format:[:min,:max],
|
|
175
|
+
alternate: true, left: left, bottom: -2,
|
|
176
|
+
colors: { columns: fc, fields: fields }).pick(:row, column: :all)
|
|
177
|
+
return unless n
|
|
178
|
+
|
|
179
|
+
entry = ordered[n][1]
|
|
180
|
+
record type, entry
|
|
181
|
+
|
|
182
|
+
if is_cmd
|
|
183
|
+
begin; run entry; rescue => e; Text.new(top: 2, right:-1, bottom:-2, border: :light,
|
|
184
|
+
input: StringIO.new(e.message + "\n" + e.backtrace.first(3).join("\n"))).pick :none; end
|
|
185
|
+
else
|
|
186
|
+
unless Dir.exist? entry
|
|
187
|
+
@user.show "no such directory: #{entry}"; Typr.read_key; return
|
|
188
|
+
end
|
|
189
|
+
cd entry
|
|
190
|
+
nil
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
def import_shell_history
|
|
195
|
+
sync = File.join(@path[:state], "shell_sync"); return if File.exist?(sync)
|
|
196
|
+
|
|
197
|
+
@user.show "importing shell history..."
|
|
198
|
+
valid = ENV["PATH"].split(":").each_with_object({}) { |d, v|
|
|
199
|
+
Dir.entries(d).each { |e| v[e] = true } rescue nil }
|
|
200
|
+
|
|
201
|
+
builtins = %w[cd . alias bg break builtin command continue declare dirs echo
|
|
202
|
+
eval exec exit export false fc fg getopts hash history jobs kill let limit
|
|
203
|
+
local logoff logout mapfile popd printf pushd pwd read readonly return set
|
|
204
|
+
shift shopt source suspend test times trap true type typeset ulimit umask
|
|
205
|
+
unalias unset wait whence which]
|
|
206
|
+
|
|
207
|
+
aliases = {}
|
|
208
|
+
[".zshrc", ".bashrc"].each { |rc|
|
|
209
|
+
File.readlines(File.join(ENV["HOME"], rc)).each { |l|
|
|
210
|
+
l =~ /\A\s*alias\s+(\w+)=(?:'([^']*)'|"([^"]*)"|(\S+))/ &&
|
|
211
|
+
aliases[$1] = ($2 || $3 || $4 || "").split.first } rescue nil }
|
|
212
|
+
|
|
213
|
+
last = 0
|
|
214
|
+
lines = 0
|
|
215
|
+
[File.expand_path("~/.bash_history"), File.expand_path("~/.zsh_history")].each { |p|
|
|
216
|
+
next unless File.exist?(p)
|
|
217
|
+
@user.show "importing shell history: #{File.basename(p)}..."
|
|
218
|
+
File.readlines(p).each { |l|
|
|
219
|
+
c = l.chomp.scrub(''); next if c.empty? || c[0] == '#'
|
|
220
|
+
if p.end_with?('zsh_history')
|
|
221
|
+
ts = c[/\A: (\d+):\d+;(.*)/, 1]&.to_i
|
|
222
|
+
c = c[/\A: \d+:\d+;(.*)/, 1] || c
|
|
223
|
+
last = ts if ts && ts > last
|
|
224
|
+
end
|
|
225
|
+
next if c.empty?
|
|
226
|
+
first = c.split.first; next unless first
|
|
227
|
+
r = first; 10.times { break unless aliases[r]; r = aliases[r] }
|
|
228
|
+
c = r + c[first.size..] if r != first
|
|
229
|
+
next unless valid[r] || builtins.include?(r)
|
|
230
|
+
record :cmd, c, write: false unless %w[cd pushd].include?(r)
|
|
231
|
+
c.split.each { |t|
|
|
232
|
+
t = t.delete_prefix('"').delete_prefix("'").delete_suffix('"').delete_suffix("'")
|
|
233
|
+
next unless t.start_with?('/', '~')
|
|
234
|
+
t = File.expand_path(t) rescue nil
|
|
235
|
+
record :dir, t, write: false if t && Dir.exist?(t)
|
|
236
|
+
}
|
|
237
|
+
lines += 1
|
|
238
|
+
@user.show "importing shell history: #{lines} lines..." if lines % 500 == 0
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
File.write(@path[:cmd_history], @cmd_history.map { |c, e| "#{c},#{e}" }.join($/))
|
|
242
|
+
File.write(@path[:dir_history], @dir_history.map { |c, e| "#{c},#{e}" }.join($/))
|
|
243
|
+
File.write(sync, last.to_s)
|
|
244
|
+
@user.reset
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
def record type, entry, write: true
|
|
248
|
+
h = type == :cmd ? @cmd_history : @dir_history
|
|
249
|
+
idx = h.index { |_, e| e == entry }
|
|
250
|
+
cnt = idx ? (h.delete_at(idx)[0] + 1) : 1
|
|
251
|
+
h.unshift [cnt, entry]
|
|
252
|
+
h.slice!(@max_history..) if h.size > @max_history
|
|
253
|
+
File.write @path[:"#{type}_history"], h.map { |c, e| "#{c},#{e}" }.join($/) if write
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
def recurse
|
|
257
|
+
return if @directory.is_a?(Array)
|
|
258
|
+
root = File.expand_path(@directory)
|
|
259
|
+
clear
|
|
260
|
+
cd root
|
|
261
|
+
Dir.glob("**/*", File::FNM_DOTMATCH, base: root).sort.each { |p|
|
|
262
|
+
next if !@show_hidden && p.split(?/).any? { |c| c.start_with?(?.) }
|
|
263
|
+
next unless File.directory?(File.join(root, p))
|
|
264
|
+
d = File.expand_path(p, root)
|
|
265
|
+
@directory = d
|
|
266
|
+
Dir.chdir d
|
|
267
|
+
cd d, true
|
|
268
|
+
}
|
|
269
|
+
Dir.chdir root
|
|
270
|
+
@directory = root
|
|
271
|
+
add_path_column
|
|
272
|
+
@current = 0
|
|
273
|
+
nil
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
def add_path_column
|
|
277
|
+
Typr.const_set :PATH, @header.size unless Typr.const_defined?(:PATH)
|
|
278
|
+
@header << "path" unless @header.include?("path")
|
|
279
|
+
@data.each { |row| row[PATH] = File.dirname(row[NAME]) }
|
|
280
|
+
@sequence.insert(@sequence.index(NAME) || 0, PATH) unless @sequence.include?(PATH)
|
|
281
|
+
# @align[@header.size-1] = :right
|
|
119
282
|
end
|
|
120
283
|
|
|
121
284
|
def help
|
|
122
285
|
info = "\nFILECON - a terminal file manager\n\n" \
|
|
123
286
|
"HINTS: press a number (1-9,0) to open that file with its default action.\n" \
|
|
124
287
|
" TAB cycles pages of hints.\n\n" \
|
|
288
|
+
"COMMANDS:\n" \
|
|
289
|
+
" e[x]ecute browse all executables on your PATH\n" \
|
|
290
|
+
" [R]ecurse expand the current directory tree (subdirectories listed inline)\n" \
|
|
291
|
+
" [d]irectories jump to a recently visited directory\n" \
|
|
292
|
+
" [c]ommands re-run a recent command\n\n" \
|
|
293
|
+
" Directory and command history popups list the most frequently used\n" \
|
|
294
|
+
" entries first, then the rest in most-recent order. The frequency_limit\n" \
|
|
295
|
+
" setting in config.yaml (default 10) controls how many frequent entries\n" \
|
|
296
|
+
" lead the list.\n\n" \
|
|
125
297
|
"CONFIG: ~/.config/filecon/config.yaml\n\n" \
|
|
126
298
|
"KEYBINDINGS:\n\n" + @user.bindings.join(?\n)
|
|
127
299
|
Text.new( input: info, top:2, left:3, right: -3, bottom: -3, header: "HELP",
|
|
@@ -131,24 +303,43 @@ class Filecon::App < Typr::Browser
|
|
|
131
303
|
|
|
132
304
|
def initialize args={}
|
|
133
305
|
super
|
|
306
|
+
@rawsort[NAME] = false
|
|
307
|
+
@cmd_history ||= []
|
|
308
|
+
@dir_history ||= []
|
|
309
|
+
@path ||= {}
|
|
310
|
+
@frequency_limit = args[:frequency_limit] || 10
|
|
311
|
+
@keymap[:open_current] = ?`
|
|
312
|
+
@keymap[:execute] = ?x
|
|
313
|
+
@keymap[:recurse] = ?R
|
|
134
314
|
@user.bindings.insert 1, "[o]pen"
|
|
135
|
-
@user.bindings.insert 7, "[
|
|
136
|
-
@user.
|
|
137
|
-
|
|
315
|
+
@user.bindings.insert 7, "[R]ecurse"
|
|
316
|
+
@user.bindings.insert 8, "[c]ommands"
|
|
317
|
+
@user.bindings.insert 9, "e[x]ecute"
|
|
318
|
+
@user.bindings.insert 11, "[`]:open_current"
|
|
319
|
+
@user.reset
|
|
138
320
|
end
|
|
139
321
|
|
|
322
|
+
def open_current; open_file nil, false, ["directory", "inode"] - [??] + ["default"] end
|
|
323
|
+
|
|
140
324
|
def fly
|
|
141
325
|
loop do
|
|
142
|
-
|
|
326
|
+
show
|
|
143
327
|
draw_hints :rows
|
|
144
|
-
key = Typr.
|
|
328
|
+
key = Typr.read_key
|
|
145
329
|
next unless key
|
|
146
330
|
case key
|
|
147
331
|
when KEY_ESCAPE; exit
|
|
148
|
-
when
|
|
332
|
+
when Typr::Mouse
|
|
333
|
+
if key.wheel? and key.press?
|
|
334
|
+
send( key.wheel_up? ? @keymap[:up] : @keymap[:down] )
|
|
335
|
+
elsif key.press? and key.left?
|
|
336
|
+
id = hit( key.y, key.x )
|
|
337
|
+
open_file( id, true ) if id.is_a? Integer
|
|
338
|
+
end
|
|
339
|
+
@user.reset
|
|
149
340
|
else
|
|
150
341
|
id = send( key )
|
|
151
|
-
open_file id, true if id.is_a? Integer
|
|
342
|
+
open_file( id, true) if id.is_a? Integer
|
|
152
343
|
@user.reset
|
|
153
344
|
end
|
|
154
345
|
end
|
|
Binary file
|
metadata
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: filecon
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1
|
|
4
|
+
version: 0.2.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Kilian Reitmayr
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: typr
|
|
@@ -16,14 +15,14 @@ dependencies:
|
|
|
16
15
|
requirements:
|
|
17
16
|
- - "~>"
|
|
18
17
|
- !ruby/object:Gem::Version
|
|
19
|
-
version: '1.
|
|
18
|
+
version: '1.3'
|
|
20
19
|
type: :runtime
|
|
21
20
|
prerelease: false
|
|
22
21
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
22
|
requirements:
|
|
24
23
|
- - "~>"
|
|
25
24
|
- !ruby/object:Gem::Version
|
|
26
|
-
version: '1.
|
|
25
|
+
version: '1.3'
|
|
27
26
|
- !ruby/object:Gem::Dependency
|
|
28
27
|
name: unicode-display_width
|
|
29
28
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -82,11 +81,11 @@ files:
|
|
|
82
81
|
- filecon.1
|
|
83
82
|
- lib/filecon.rb
|
|
84
83
|
- lib/filecon/version.rb
|
|
84
|
+
- logo_alpha_small.png
|
|
85
85
|
homepage: https://codeberg.org/typr/filecon
|
|
86
86
|
licenses:
|
|
87
87
|
- GPL-2.0-only
|
|
88
88
|
metadata: {}
|
|
89
|
-
post_install_message:
|
|
90
89
|
rdoc_options: []
|
|
91
90
|
require_paths:
|
|
92
91
|
- lib
|
|
@@ -101,8 +100,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
101
100
|
- !ruby/object:Gem::Version
|
|
102
101
|
version: '0'
|
|
103
102
|
requirements: []
|
|
104
|
-
rubygems_version: 3.
|
|
105
|
-
signing_key:
|
|
103
|
+
rubygems_version: 3.6.9
|
|
106
104
|
specification_version: 4
|
|
107
105
|
summary: Terminal file manager built on Typr
|
|
108
106
|
test_files: []
|