rtfm-filemanager 8.0.2 → 8.1.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/CHANGELOG.md +10 -0
- data/README.md +8 -0
- data/bin/rtfm +87 -24
- metadata +4 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 65a65b423798385788eb367824c259a5c06afe6fdb758236c1251392d25a3a9c
|
|
4
|
+
data.tar.gz: 85ffe85ecc519a3ed161895a1c3acbb75abca292a406a91006867beb2094aca0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 42e385ba69a21ab5f4460c83033c1fa78f18fd0bbf2cbd9efb08288481ea3a11ea6cd79211e5299b2a09acf0c35b19c8d1ed661c354c3c28651e99063e5b66a7
|
|
7
|
+
data.tar.gz: e3d90244aa51ec34abbfabf044eb5cb51326ee3c264884dc9effbfbe4cc2d4ac99cc0f6174824600c55e02dc3173f2ec229c23889b5e39fd74578abd2a922399
|
data/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,16 @@ All notable changes to RTFM will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [8.1.1] - 2026-03-12
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
- **Right pane text not showing over images or file previews** - Fixed monkey-patched `say` method so pane refresh always draws, regardless of prior update state. Also added `clear_image` calls to marks, recent files, file properties, AI description, chat mode, command history, and SSH history
|
|
12
|
+
|
|
13
|
+
## [8.1.0] - 2026-03-12
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
- **File picker mode** (`--pick`) - Launch RTFM as a file picker for other applications. Tag files with `t`, quit with `q`, and the tagged file paths are written to the specified output file. Usage: `rtfm --pick=/path/to/output.txt [start_directory]`
|
|
17
|
+
|
|
8
18
|
## [8.0.1] - 2026-03-07
|
|
9
19
|
|
|
10
20
|
### Changed
|
data/README.md
CHANGED
|
@@ -22,6 +22,9 @@ rtfm
|
|
|
22
22
|
# Or start in specific directory
|
|
23
23
|
rtfm ~/Documents
|
|
24
24
|
|
|
25
|
+
# Use as file picker (tag files with t, quit with q)
|
|
26
|
+
rtfm --pick=/tmp/selected_files.txt
|
|
27
|
+
|
|
25
28
|
# Press ? for help
|
|
26
29
|
```
|
|
27
30
|
|
|
@@ -84,6 +87,7 @@ After first run, use `r` command to launch RTFM and exit into your current direc
|
|
|
84
87
|
- **Cryptographic hashing** - Directory tree verification
|
|
85
88
|
- **OpenAI integration** - File descriptions and interactive chat
|
|
86
89
|
- **Tab management** - Multiple tabs with duplication and renaming
|
|
90
|
+
- **File picker mode** - Use RTFM as a file selector for other applications (`--pick`)
|
|
87
91
|
- **Fuzzy search** - fzf integration
|
|
88
92
|
- **Navi integration** - Interactive command cheatsheets
|
|
89
93
|
|
|
@@ -646,6 +650,10 @@ Best image experience with: kitty, urxvt, xterm, mlterm, foot
|
|
|
646
650
|
|
|
647
651
|
## Latest Updates
|
|
648
652
|
|
|
653
|
+
### Version 8.1 Highlights
|
|
654
|
+
|
|
655
|
+
- **File picker mode** - `rtfm --pick=/path/to/output.txt` launches RTFM as a file selector. Browse and tag files normally with `t`, then quit with `q`. Tagged file paths are written one per line to the output file. Enables integration with email clients, upload tools, and other applications that need a file selection dialog.
|
|
656
|
+
|
|
649
657
|
### Version 7.3 Highlights
|
|
650
658
|
|
|
651
659
|
- **Modern image display** with termpix gem (Sixel + w3m protocols)
|
data/bin/rtfm
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
# get a great understanding of the code itself by simply sending
|
|
19
19
|
# or pasting this whole file into you favorite AI for coding with
|
|
20
20
|
# a prompt like this: "Help me understand every part of this code".
|
|
21
|
-
@version = '8.0
|
|
21
|
+
@version = '8.1.0' # File picker mode (--pick) for integration with other tools
|
|
22
22
|
|
|
23
23
|
# SAVE & STORE TERMINAL {{{1
|
|
24
24
|
ORIG_STTY = `stty -g`.chomp
|
|
@@ -134,6 +134,7 @@ module Rcurses
|
|
|
134
134
|
# Restore original say method override for compatibility
|
|
135
135
|
alias original_say say
|
|
136
136
|
def say(text)
|
|
137
|
+
self.update = true
|
|
137
138
|
original_say(text)
|
|
138
139
|
self.update = false
|
|
139
140
|
end
|
|
@@ -825,9 +826,22 @@ rescue StandardError => e
|
|
|
825
826
|
errormsg("⚠ Errors while loading #{CONFIG_FILE}\nCheck your config file or delete it to remake in a fresh RTFM start.", e)
|
|
826
827
|
end
|
|
827
828
|
load_config
|
|
829
|
+
# Load persisted width setting if it exists
|
|
830
|
+
width_file = File.join(RTFM_HOME, 'width')
|
|
831
|
+
if File.exist?(width_file)
|
|
832
|
+
saved_width = File.read(width_file).strip.to_i
|
|
833
|
+
@width = saved_width if saved_width >= 2 && saved_width <= 7
|
|
834
|
+
end
|
|
828
835
|
@marks['0'] = Dir.pwd # Original dir
|
|
829
836
|
@marks["'"] = Dir.pwd # Initial mark
|
|
830
837
|
|
|
838
|
+
# File picker mode: --pick=/path/to/output writes tagged files on quit
|
|
839
|
+
@pick_output = nil
|
|
840
|
+
if (pick_arg = ARGV.find { |a| a.start_with?('--pick=') })
|
|
841
|
+
@pick_output = pick_arg.split('=', 2).last
|
|
842
|
+
ARGV.delete(pick_arg)
|
|
843
|
+
end
|
|
844
|
+
|
|
831
845
|
# Handle start dir {{{2
|
|
832
846
|
Dir.chdir(ARGV.shift) if ARGV[0] && File.directory?(ARGV[0])
|
|
833
847
|
|
|
@@ -1203,7 +1217,10 @@ end
|
|
|
1203
1217
|
def change_width # {{{3
|
|
1204
1218
|
@width += 1
|
|
1205
1219
|
@width = 2 if @width == 8
|
|
1206
|
-
|
|
1220
|
+
|
|
1221
|
+
# Persist width setting
|
|
1222
|
+
File.write(File.join(RTFM_HOME, 'width'), @width.to_s) rescue nil
|
|
1223
|
+
|
|
1207
1224
|
if @dual_pane
|
|
1208
1225
|
# Show width setting info for dual-pane mode using the new ratio calculation
|
|
1209
1226
|
dir_panes_ratio = [0.5 - (@width - 2) * 0.034, 0.33].max
|
|
@@ -1212,7 +1229,7 @@ def change_width # {{{3
|
|
|
1212
1229
|
else
|
|
1213
1230
|
@pB.say("Width: #{@width}")
|
|
1214
1231
|
end
|
|
1215
|
-
|
|
1232
|
+
|
|
1216
1233
|
refresh
|
|
1217
1234
|
@pL.update = @pR.update = @pT.update = @pB.update = true
|
|
1218
1235
|
# Also update dual-pane objects if they exist
|
|
@@ -1886,6 +1903,7 @@ def track_directory_access(dir_path) # {{{3
|
|
|
1886
1903
|
end
|
|
1887
1904
|
|
|
1888
1905
|
def show_recent_files # {{{3
|
|
1906
|
+
clear_image
|
|
1889
1907
|
text = "Recently Accessed Files and Directories\n".b.fg(156)
|
|
1890
1908
|
text << "=" * 40 + "\n\n"
|
|
1891
1909
|
|
|
@@ -1959,8 +1977,9 @@ end
|
|
|
1959
1977
|
|
|
1960
1978
|
# FILE PROPERTIES {{{2
|
|
1961
1979
|
def show_file_properties # {{{3
|
|
1980
|
+
clear_image
|
|
1962
1981
|
return unless @selected && File.exist?(@selected)
|
|
1963
|
-
|
|
1982
|
+
|
|
1964
1983
|
begin
|
|
1965
1984
|
stat = File.stat(@selected)
|
|
1966
1985
|
text = "File Properties: #{File.basename(@selected)}\n".b.fg(156)
|
|
@@ -4502,6 +4521,7 @@ def hash_directory # {{{3
|
|
|
4502
4521
|
end
|
|
4503
4522
|
|
|
4504
4523
|
def openai_description # {{{3
|
|
4524
|
+
clear_image
|
|
4505
4525
|
begin
|
|
4506
4526
|
require 'ruby/openai'
|
|
4507
4527
|
rescue LoadError
|
|
@@ -4541,6 +4561,7 @@ def openai_description # {{{3
|
|
|
4541
4561
|
end
|
|
4542
4562
|
|
|
4543
4563
|
def chat_mode # {{{3
|
|
4564
|
+
clear_image
|
|
4544
4565
|
unless defined?(OpenAI) && @ai && !@ai.empty?
|
|
4545
4566
|
@pB.say("To make OpenAI work in RTFM, run `gem install ruby-openai` and add to ~/.rtfm/conf:\n @ai = 'your-secret-openai-key'")
|
|
4546
4567
|
return
|
|
@@ -5092,11 +5113,13 @@ def command_mode # {{{3
|
|
|
5092
5113
|
end
|
|
5093
5114
|
|
|
5094
5115
|
def show_history # {{{3
|
|
5116
|
+
clear_image
|
|
5095
5117
|
@pR.say("Command history:\n\n" + @pCmd.history.reverse.join("\n"))
|
|
5096
5118
|
@pB.update = true
|
|
5097
5119
|
end
|
|
5098
5120
|
|
|
5099
5121
|
def show_ssh_history # {{{3
|
|
5122
|
+
clear_image
|
|
5100
5123
|
history_text = "SSH Connection History\n".b.fg(156)
|
|
5101
5124
|
history_text << "=" * 50 + "\n\n"
|
|
5102
5125
|
|
|
@@ -6038,6 +6061,42 @@ def mark_latest # UPDATE MARKS LIST {{{2
|
|
|
6038
6061
|
@marks["'"] = Dir.pwd
|
|
6039
6062
|
end
|
|
6040
6063
|
|
|
6064
|
+
def mailcap_command(file_path) # FIND VIEWER VIA ~/.mailcap {{{2
|
|
6065
|
+
# Detect MIME type
|
|
6066
|
+
mime_type = IO.popen(['file', '--brief', '--mime-type', file_path]) { |f| f.read.strip }
|
|
6067
|
+
return nil if mime_type.nil? || mime_type.empty?
|
|
6068
|
+
|
|
6069
|
+
# Search mailcap files in order of preference
|
|
6070
|
+
mailcap_files = [File.join(Dir.home, '.mailcap'), '/etc/mailcap']
|
|
6071
|
+
mailcap_files.each do |mc_file|
|
|
6072
|
+
next unless File.exist?(mc_file)
|
|
6073
|
+
File.foreach(mc_file) do |line|
|
|
6074
|
+
line = line.strip
|
|
6075
|
+
next if line.empty? || line.start_with?('#')
|
|
6076
|
+
# Handle continuation lines (trailing backslash)
|
|
6077
|
+
# For simplicity, skip multi-line entries
|
|
6078
|
+
next if line.end_with?('\\')
|
|
6079
|
+
parts = line.split(';').map(&:strip)
|
|
6080
|
+
next if parts.length < 2
|
|
6081
|
+
pattern = parts[0]
|
|
6082
|
+
command = parts[1]
|
|
6083
|
+
flags = parts[2..].join(';')
|
|
6084
|
+
# Skip entries with copiousoutput (meant for text dump, not viewing)
|
|
6085
|
+
next if flags =~ /copiousoutput/i
|
|
6086
|
+
# Check if MIME type matches (supports wildcards like "image/*")
|
|
6087
|
+
pattern_re = Regexp.new('^' + Regexp.escape(pattern).gsub('\\*', '.*') + '$', Regexp::IGNORECASE)
|
|
6088
|
+
next unless mime_type.match?(pattern_re)
|
|
6089
|
+
# Replace %s with the file path in the command
|
|
6090
|
+
if command.include?('%s')
|
|
6091
|
+
return command.gsub('%s', Shellwords.escape(file_path))
|
|
6092
|
+
else
|
|
6093
|
+
return "#{command} #{Shellwords.escape(file_path)}"
|
|
6094
|
+
end
|
|
6095
|
+
end
|
|
6096
|
+
end
|
|
6097
|
+
nil # No mailcap match found
|
|
6098
|
+
end
|
|
6099
|
+
|
|
6041
6100
|
def get_interactive_program(file_path) # HELPER FOR OPEN_SELECTED TO USE @interactive {{{2
|
|
6042
6101
|
begin
|
|
6043
6102
|
inter_list = (@interactive || '').split(',').map(&:strip)
|
|
@@ -6146,16 +6205,11 @@ def open_selected(html = nil) # OPEN SELECTED FILE {{{2
|
|
|
6146
6205
|
# Use tagged items if any exist, otherwise use selected item
|
|
6147
6206
|
paths = @tagged.empty? ? [@selected] : @tagged
|
|
6148
6207
|
if html # html mode - open in HTML-browser
|
|
6149
|
-
|
|
6150
|
-
|
|
6151
|
-
|
|
6152
|
-
if File.exist?(tmpfile)
|
|
6153
|
-
sleep 0.5
|
|
6154
|
-
err = File.read(tmpfile)
|
|
6155
|
-
showimage('clear') if @image
|
|
6156
|
-
@pR.say(err.fg(196))
|
|
6157
|
-
File.delete(tmpfile)
|
|
6208
|
+
paths.each do |p|
|
|
6209
|
+
pid = Process.spawn('xdg-open', p, [:out, :err] => '/dev/null')
|
|
6210
|
+
Process.detach(pid)
|
|
6158
6211
|
end
|
|
6212
|
+
Rcurses.clear_screen; refresh; render
|
|
6159
6213
|
return
|
|
6160
6214
|
end
|
|
6161
6215
|
# Check if file is text (UTF-8, UTF-16, or other text encodings)
|
|
@@ -6209,21 +6263,22 @@ def open_selected(html = nil) # OPEN SELECTED FILE {{{2
|
|
|
6209
6263
|
render
|
|
6210
6264
|
return
|
|
6211
6265
|
end
|
|
6212
|
-
|
|
6213
|
-
|
|
6214
|
-
|
|
6266
|
+
# Try mailcap first, then fall back to run-mailcap or xdg-open
|
|
6267
|
+
mc_cmd = mailcap_command(@selected)
|
|
6268
|
+
if mc_cmd
|
|
6269
|
+
pid = Process.spawn(mc_cmd, :in => '/dev/null', [:out, :err] => '/dev/null')
|
|
6270
|
+
Process.detach(pid)
|
|
6271
|
+
elsif @runmailcap
|
|
6272
|
+
paths.each do |p|
|
|
6273
|
+
pid = Process.spawn('run-mailcap', p, :in => '/dev/null', [:out, :err] => '/dev/null')
|
|
6274
|
+
Process.detach(pid)
|
|
6275
|
+
end
|
|
6215
6276
|
else
|
|
6216
|
-
|
|
6277
|
+
pid = Process.spawn('xdg-open', @selected, :in => '/dev/null', [:out, :err] => '/dev/null')
|
|
6278
|
+
Process.detach(pid)
|
|
6217
6279
|
end
|
|
6218
6280
|
# Clean up
|
|
6219
6281
|
Rcurses.clear_screen; refresh; render
|
|
6220
|
-
if File.exist?(tmpfile)
|
|
6221
|
-
sleep 0.5
|
|
6222
|
-
err = File.read(tmpfile)
|
|
6223
|
-
showimage('clear') if @image
|
|
6224
|
-
@pR.say(err.fg(196))
|
|
6225
|
-
File.delete(tmpfile)
|
|
6226
|
-
end
|
|
6227
6282
|
end
|
|
6228
6283
|
|
|
6229
6284
|
def conf_write(all: false) # WRITE TO ~/.rtfm/conf {{{2
|
|
@@ -6264,6 +6319,13 @@ def conf_write(all: false) # WRITE TO ~/.rtfm/conf {{{2
|
|
|
6264
6319
|
end
|
|
6265
6320
|
|
|
6266
6321
|
def exit_rtfm # CLEAN EXIT {{{2
|
|
6322
|
+
# Pick mode: write tagged file paths to output file
|
|
6323
|
+
if @pick_output
|
|
6324
|
+
begin
|
|
6325
|
+
File.write(@pick_output, @tagged.join("\n") + "\n")
|
|
6326
|
+
rescue StandardError
|
|
6327
|
+
end
|
|
6328
|
+
end
|
|
6267
6329
|
# If invoked with a stub filename, write out our cwd
|
|
6268
6330
|
if ARGV[0]
|
|
6269
6331
|
begin
|
|
@@ -6574,6 +6636,7 @@ def showimage(image) # SHOW THE SELECTED IMAGE IN THE RIGHT WINDOW {{{2
|
|
|
6574
6636
|
end
|
|
6575
6637
|
|
|
6576
6638
|
def marks_info # SHOW MARKS IN RIGHT WINDOW {{{2
|
|
6639
|
+
clear_image
|
|
6577
6640
|
@marks = @marks.sort.to_h
|
|
6578
6641
|
info = "Directory Marks".b.fg(156) + "\n"
|
|
6579
6642
|
info << "=" * 50 + "\n\n"
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rtfm-filemanager
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 8.
|
|
4
|
+
version: 8.1.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Geir Isene
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-03-
|
|
11
|
+
date: 2026-03-12 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rcurses
|
|
@@ -71,7 +71,8 @@ description: 'RTFM v8.0: Browse and modify archives as virtual directories (extr
|
|
|
71
71
|
side-by-side mode. A full featured terminal browser with syntax highlighted files,
|
|
72
72
|
images shown in the terminal, videos thumbnailed, etc. Features include remote SSH/SFTP
|
|
73
73
|
browsing, interactive SSH shell, comprehensive undo system, OpenAI integration,
|
|
74
|
-
bookmarks, and much more. RTFM is one of the most feature-packed terminal file managers.
|
|
74
|
+
bookmarks, and much more. RTFM is one of the most feature-packed terminal file managers.
|
|
75
|
+
v8.1: File picker mode (--pick) for integration with other tools.'
|
|
75
76
|
email: g@isene.com
|
|
76
77
|
executables:
|
|
77
78
|
- rtfm
|