rtfm-filemanager 8.2.1 → 8.2.3
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/bin/rtfm +86 -71
- data/img/rtfm-kb.svg +341 -0
- metadata +3 -3
- data/img/rtfm-kb.png +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4ca25cd86bf46067b73bf66b33635f6e220d937ba528ab25434da99655a04e52
|
|
4
|
+
data.tar.gz: 58418e13253d8063d73114f361764cf20e04f62649ddea41ec0163abbf224af4
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 70397c9a79033585cdd6dcb7ff1bd99d5fc6f973a223e3f91cbd7c23f2534ed0c738f9ed2be6432a37e993fe115d872c36617c444844bb9f09e84510541afade
|
|
7
|
+
data.tar.gz: b346e1b4d9cadd7657eb0649e0111a83b0f2e5332c5195b13b9e82afb3a34703b293c74b934e3e1876f916780b25d085daed25306c18c23a692c4e2bb526c488
|
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.2.
|
|
21
|
+
@version = '8.2.3' # Replace bare rescues with typed exceptions
|
|
22
22
|
|
|
23
23
|
# SAVE & STORE TERMINAL {{{1
|
|
24
24
|
ORIG_STTY = `stty -g`.chomp
|
|
@@ -61,7 +61,7 @@ def check_image_redraw # {{{2
|
|
|
61
61
|
end
|
|
62
62
|
end
|
|
63
63
|
# Kitty and Sixel protocols don't need redraw checks - images persist
|
|
64
|
-
rescue
|
|
64
|
+
rescue StandardError # non-fatal image redraw check
|
|
65
65
|
# Silently fail - we don't want focus checking to break anything
|
|
66
66
|
end
|
|
67
67
|
end
|
|
@@ -682,7 +682,7 @@ def restore_tab_state # {{{2
|
|
|
682
682
|
|
|
683
683
|
begin
|
|
684
684
|
Dir.chdir(tab[:directory]) if Dir.exist?(tab[:directory])
|
|
685
|
-
rescue
|
|
685
|
+
rescue Errno::ENOENT, Errno::EACCES # permission denied or missing dir
|
|
686
686
|
# If directory doesn't exist, go to home
|
|
687
687
|
Dir.chdir
|
|
688
688
|
tab[:directory] = Dir.pwd
|
|
@@ -910,7 +910,7 @@ if File.exist?(PREVIEW_FILE)
|
|
|
910
910
|
@plugin_errors << "Invalid preview.rb line #{idx + 1}: #{line}"
|
|
911
911
|
end
|
|
912
912
|
end
|
|
913
|
-
rescue => e
|
|
913
|
+
rescue StandardError => e # malformed preview config
|
|
914
914
|
@plugin_errors << "Error loading preview.rb: #{e.class}: #{e.message}"
|
|
915
915
|
end
|
|
916
916
|
end
|
|
@@ -1075,7 +1075,7 @@ KEYMAP = { # {{{2
|
|
|
1075
1075
|
if File.exist?(KEYS_FILE)
|
|
1076
1076
|
begin
|
|
1077
1077
|
load KEYS_FILE
|
|
1078
|
-
rescue => e
|
|
1078
|
+
rescue StandardError => e # broken key binding config
|
|
1079
1079
|
@plugin_errors << "Error loading keys.rb: #{e.class}: #{e.message}"
|
|
1080
1080
|
end
|
|
1081
1081
|
end
|
|
@@ -1114,7 +1114,7 @@ def load_plugin(name)
|
|
|
1114
1114
|
snapshot.each { |k, v| changed[k] = v unless KEYMAP.key?(k) }
|
|
1115
1115
|
p[:saved_keys] = changed
|
|
1116
1116
|
p[:enabled] = true
|
|
1117
|
-
rescue => e
|
|
1117
|
+
rescue StandardError => e # plugin load failure
|
|
1118
1118
|
@plugin_errors << "Error loading plugin #{name}: #{e.class}: #{e.message}"
|
|
1119
1119
|
end
|
|
1120
1120
|
end
|
|
@@ -1248,7 +1248,7 @@ def refresh_all # {{{3
|
|
|
1248
1248
|
if new_h && new_w && new_h >= 10 && new_w >= 20
|
|
1249
1249
|
@h, @w = new_h, new_w
|
|
1250
1250
|
end
|
|
1251
|
-
rescue
|
|
1251
|
+
rescue StandardError # terminal size query failed
|
|
1252
1252
|
# Keep current size if we can't read new size
|
|
1253
1253
|
end
|
|
1254
1254
|
|
|
@@ -1346,7 +1346,7 @@ def change_width # {{{3
|
|
|
1346
1346
|
@width = 2 if @width == 8
|
|
1347
1347
|
|
|
1348
1348
|
# Persist width setting
|
|
1349
|
-
File.write(File.join(RTFM_HOME, 'width'), @width.to_s) rescue nil
|
|
1349
|
+
File.write(File.join(RTFM_HOME, 'width'), @width.to_s) rescue nil # ignore write error
|
|
1350
1350
|
|
|
1351
1351
|
if @dual_pane
|
|
1352
1352
|
# Show width setting info for dual-pane mode using the new ratio calculation
|
|
@@ -1589,7 +1589,7 @@ def jump_to_mark # {{{3
|
|
|
1589
1589
|
if m =~ /[\w']/ && @marks[m]
|
|
1590
1590
|
@directory[Dir.pwd] = @index
|
|
1591
1591
|
dir_before = Dir.pwd
|
|
1592
|
-
begin; Dir.chdir(@marks[m]); track_directory_access(@marks[m]); rescue; @pB.say(' No such directory'); end
|
|
1592
|
+
begin; Dir.chdir(@marks[m]); track_directory_access(@marks[m]); rescue Errno::ENOENT, Errno::EACCES; @pB.say(' No such directory'); end
|
|
1593
1593
|
mark_latest
|
|
1594
1594
|
@marks["'"] = dir_before
|
|
1595
1595
|
end
|
|
@@ -1692,7 +1692,7 @@ def follow_symlink # {{{3
|
|
|
1692
1692
|
|
|
1693
1693
|
# Clear history after successful navigation
|
|
1694
1694
|
@symlink_history.clear
|
|
1695
|
-
rescue => e
|
|
1695
|
+
rescue StandardError => e # symlink resolution failure
|
|
1696
1696
|
@pB.say("Error following symlink: #{e}")
|
|
1697
1697
|
@symlink_history&.clear
|
|
1698
1698
|
end
|
|
@@ -1755,7 +1755,7 @@ def tag_current # {{{3
|
|
|
1755
1755
|
else
|
|
1756
1756
|
@tagged.push(item); @tagsize += File.size(item) rescue 0
|
|
1757
1757
|
end
|
|
1758
|
-
|
|
1758
|
+
|
|
1759
1759
|
# Advance to next item in the active pane
|
|
1760
1760
|
max_index = current_files.size - 1
|
|
1761
1761
|
if @active_pane == :left
|
|
@@ -2124,7 +2124,7 @@ def show_file_properties # {{{3
|
|
|
2124
2124
|
mime_output = `file --mime-type #{Shellwords.escape(@selected)} 2>/dev/null`.strip
|
|
2125
2125
|
mime_type = mime_output.split(':')[1]&.strip || "Unknown"
|
|
2126
2126
|
text << sprintf(" %-20s %s\n", "MIME Type:", mime_type.fg(156))
|
|
2127
|
-
rescue
|
|
2127
|
+
rescue StandardError # file command failed
|
|
2128
2128
|
text << sprintf(" %-20s %s\n", "MIME Type:", "Unknown".fg(240))
|
|
2129
2129
|
end
|
|
2130
2130
|
|
|
@@ -2143,7 +2143,7 @@ def show_file_properties # {{{3
|
|
|
2143
2143
|
owner = Etc.getpwuid(stat.uid).name rescue stat.uid.to_s
|
|
2144
2144
|
group = Etc.getgrgid(stat.gid).name rescue stat.gid.to_s
|
|
2145
2145
|
text << sprintf(" %-20s %s\n", "Owner:Group:", "#{owner}:#{group}".fg(156))
|
|
2146
|
-
rescue
|
|
2146
|
+
rescue StandardError # uid/gid lookup failed
|
|
2147
2147
|
text << sprintf(" %-20s %s\n", "Owner:Group:", "#{stat.uid}:#{stat.gid}".fg(156))
|
|
2148
2148
|
end
|
|
2149
2149
|
|
|
@@ -2163,7 +2163,7 @@ def show_file_properties # {{{3
|
|
|
2163
2163
|
target = File.readlink(@selected)
|
|
2164
2164
|
text << sprintf(" %-20s %s\n", "Points to:", target.fg(156))
|
|
2165
2165
|
text << sprintf(" %-20s %s\n", "Target exists:", File.exist?(target) ? "Yes".fg(156) : "No".fg(196))
|
|
2166
|
-
rescue
|
|
2166
|
+
rescue Errno::ENOENT, Errno::EACCES # permission denied or missing symlink target
|
|
2167
2167
|
text << sprintf(" %-20s %s\n", "Target:", "Cannot read link".fg(196))
|
|
2168
2168
|
end
|
|
2169
2169
|
end
|
|
@@ -2178,7 +2178,7 @@ def show_file_properties # {{{3
|
|
|
2178
2178
|
dirs = entries.select { |e| File.directory?(File.join(@selected, e)) }
|
|
2179
2179
|
files = entries.select { |e| File.file?(File.join(@selected, e)) }
|
|
2180
2180
|
text << sprintf(" %-20s %s\n", "Breakdown:", "#{dirs.length} directories, #{files.length} files")
|
|
2181
|
-
rescue
|
|
2181
|
+
rescue Errno::EACCES, Errno::ENOENT # permission denied or missing dir
|
|
2182
2182
|
text << sprintf(" %-20s %s\n", "Contents:", "Cannot read directory".fg(196))
|
|
2183
2183
|
end
|
|
2184
2184
|
end
|
|
@@ -2194,7 +2194,7 @@ def show_file_properties # {{{3
|
|
|
2194
2194
|
require 'digest'
|
|
2195
2195
|
checksum = Digest::SHA256.file(@selected).hexdigest[0, 16]
|
|
2196
2196
|
text << sprintf(" %-20s %s...\n", "SHA256 (partial):", checksum.fg(156))
|
|
2197
|
-
rescue
|
|
2197
|
+
rescue Errno::EACCES, Errno::ENOENT # permission denied or missing file
|
|
2198
2198
|
text << sprintf(" %-20s %s\n", "Checksum:", "Cannot calculate".fg(240))
|
|
2199
2199
|
end
|
|
2200
2200
|
else
|
|
@@ -2209,7 +2209,7 @@ def show_file_properties # {{{3
|
|
|
2209
2209
|
(chunk.bytes.any? { |b| b < 32 && ![9, 10, 13].include?(b) })
|
|
2210
2210
|
text << sprintf(" %-20s %s\n", "Content type:", is_binary ? "Binary".fg(196) : "Text".fg(156))
|
|
2211
2211
|
end
|
|
2212
|
-
rescue
|
|
2212
|
+
rescue Errno::EACCES, Errno::ENOENT # permission denied or missing file
|
|
2213
2213
|
text << sprintf(" %-20s %s\n", "Content type:", "Unknown".fg(240))
|
|
2214
2214
|
end
|
|
2215
2215
|
end
|
|
@@ -2578,7 +2578,7 @@ def show_binary_comparison(file1, file2, stat1, stat2) # {{{3
|
|
|
2578
2578
|
text << "\n File types:\n".fg(226)
|
|
2579
2579
|
text << " #{File.basename(file1)}: #{type1.split(':')[1]&.strip || 'Unknown'}\n".fg(240)
|
|
2580
2580
|
text << " #{File.basename(file2)}: #{type2.split(':')[1]&.strip || 'Unknown'}\n".fg(240)
|
|
2581
|
-
rescue
|
|
2581
|
+
rescue StandardError # file type detection failed
|
|
2582
2582
|
# Ignore file type detection errors
|
|
2583
2583
|
end
|
|
2584
2584
|
|
|
@@ -2792,7 +2792,7 @@ def files_identical?(file1, file2) # {{{3
|
|
|
2792
2792
|
end
|
|
2793
2793
|
|
|
2794
2794
|
true
|
|
2795
|
-
rescue
|
|
2795
|
+
rescue Errno::EACCES, Errno::ENOENT, Errno::EISDIR # permission denied or missing file
|
|
2796
2796
|
false
|
|
2797
2797
|
end
|
|
2798
2798
|
|
|
@@ -2808,7 +2808,7 @@ def binary_file?(file) # {{{3
|
|
|
2808
2808
|
|
|
2809
2809
|
null_count > 0 || (non_printable.to_f / chunk.length) > 0.3
|
|
2810
2810
|
end
|
|
2811
|
-
rescue
|
|
2811
|
+
rescue Errno::EACCES, Errno::ENOENT, Errno::EISDIR # permission denied or missing file
|
|
2812
2812
|
true # Assume binary if we can't read it
|
|
2813
2813
|
end
|
|
2814
2814
|
|
|
@@ -2924,7 +2924,7 @@ def parse_archive_listing(archive_path) # {{{3
|
|
|
2924
2924
|
else
|
|
2925
2925
|
parse_tar_listing(raw, entries)
|
|
2926
2926
|
end
|
|
2927
|
-
rescue => e
|
|
2927
|
+
rescue StandardError => e # archive format or read error
|
|
2928
2928
|
@pB.say("Error reading archive: #{e.message}".fg(196))
|
|
2929
2929
|
end
|
|
2930
2930
|
entries
|
|
@@ -3064,6 +3064,7 @@ end
|
|
|
3064
3064
|
def enter_archive_mode(archive_path) # {{{3
|
|
3065
3065
|
@archive_origin_dir = Dir.pwd
|
|
3066
3066
|
@archive_origin_tagged = @tagged.dup
|
|
3067
|
+
@archive_origin_index = @index
|
|
3067
3068
|
@archive_mode = true
|
|
3068
3069
|
@archive_path = archive_path
|
|
3069
3070
|
@archive_current_dir = ''
|
|
@@ -3093,7 +3094,8 @@ def exit_archive_mode # {{{3
|
|
|
3093
3094
|
@tagged = @archive_origin_tagged || []
|
|
3094
3095
|
@archive_origin_tagged = []
|
|
3095
3096
|
@archive_origin_dir = nil
|
|
3096
|
-
@index = 0
|
|
3097
|
+
@index = @archive_origin_index || 0
|
|
3098
|
+
@archive_origin_index = nil
|
|
3097
3099
|
@pB.say("Returned to local browsing".fg(156))
|
|
3098
3100
|
@pL.update = @pR.update = @pT.update = @pB.update = true
|
|
3099
3101
|
dirlist
|
|
@@ -3645,7 +3647,7 @@ def upload_tagged_files # {{{3
|
|
|
3645
3647
|
failed_count += 1
|
|
3646
3648
|
@pB.say("✗ Failed to upload #{File.basename(local_file)}".fg(196))
|
|
3647
3649
|
end
|
|
3648
|
-
rescue => e
|
|
3650
|
+
rescue StandardError => e # upload failure
|
|
3649
3651
|
failed_count += 1
|
|
3650
3652
|
@pB.say("✗ Error uploading #{File.basename(local_file)}: #{e.message}".fg(196))
|
|
3651
3653
|
end
|
|
@@ -4229,7 +4231,7 @@ def trash_browser # TRASH BROWSER {{{3
|
|
|
4229
4231
|
begin
|
|
4230
4232
|
size = File.directory?(f) ? (command("du -sb #{Shellwords.escape(f)} 2>/dev/null").split.first.to_i rescue 0) : File.size(f)
|
|
4231
4233
|
mtime = File.mtime(f)
|
|
4232
|
-
rescue
|
|
4234
|
+
rescue Errno::EACCES, Errno::ENOENT # permission denied or missing file
|
|
4233
4235
|
size = 0
|
|
4234
4236
|
mtime = Time.at(0)
|
|
4235
4237
|
end
|
|
@@ -4300,7 +4302,7 @@ def trash_browser # TRASH BROWSER {{{3
|
|
|
4300
4302
|
end
|
|
4301
4303
|
@pB.say("Restored: #{File.basename(dest)}".fg(156))
|
|
4302
4304
|
sel = [sel - 1, 0].max
|
|
4303
|
-
rescue => e
|
|
4305
|
+
rescue StandardError => e # restore from trash failed
|
|
4304
4306
|
@pB.say("Restore failed: #{e.message}".fg(196))
|
|
4305
4307
|
end
|
|
4306
4308
|
when 'd'
|
|
@@ -4880,7 +4882,8 @@ def copy_path_primary # {{{3
|
|
|
4880
4882
|
path = get_selected_full_path
|
|
4881
4883
|
if path
|
|
4882
4884
|
copy_to_clipboard(path, 'primary')
|
|
4883
|
-
|
|
4885
|
+
copy_to_clipboard(path, 'clipboard')
|
|
4886
|
+
@pB.say(' Path copied')
|
|
4884
4887
|
else
|
|
4885
4888
|
@pB.say(' No selected item path to copy')
|
|
4886
4889
|
end
|
|
@@ -4895,7 +4898,8 @@ def copy_path_clipboard # {{{3
|
|
|
4895
4898
|
path = get_selected_full_path
|
|
4896
4899
|
if path
|
|
4897
4900
|
copy_to_clipboard(path, 'clipboard')
|
|
4898
|
-
|
|
4901
|
+
copy_to_clipboard(path, 'primary')
|
|
4902
|
+
@pB.say(' Path copied')
|
|
4899
4903
|
else
|
|
4900
4904
|
@pB.say(' No selected item path to copy')
|
|
4901
4905
|
end
|
|
@@ -4966,10 +4970,11 @@ def copy_right # {{{3
|
|
|
4966
4970
|
@pB.say(' Failed to copy image - xclip may not be installed')
|
|
4967
4971
|
end
|
|
4968
4972
|
else
|
|
4969
|
-
# Copy right pane text content
|
|
4970
|
-
|
|
4971
|
-
|
|
4972
|
-
shell("echo -n #{
|
|
4973
|
+
# Copy right pane text content to both selections
|
|
4974
|
+
escaped = Shellwords.escape(@pR.text.pure)
|
|
4975
|
+
shell("echo -n #{escaped} | xclip -selection clipboard > /dev/null 2>&1", background: true)
|
|
4976
|
+
shell("echo -n #{escaped} | xclip -selection primary > /dev/null 2>&1", background: true)
|
|
4977
|
+
@pB.say(' Right pane text copied')
|
|
4973
4978
|
end
|
|
4974
4979
|
end
|
|
4975
4980
|
|
|
@@ -5002,9 +5007,9 @@ def system_info # {{{3
|
|
|
5002
5007
|
text << sprintf(" %-15s %s\n", "Kernel:".fg(249), kernel_version.fg(156))
|
|
5003
5008
|
text << sprintf(" %-15s %s\n", "Architecture:".fg(249), architecture.fg(156))
|
|
5004
5009
|
text << "\n"
|
|
5005
|
-
rescue #
|
|
5010
|
+
rescue StandardError # OS info unavailable
|
|
5006
5011
|
end
|
|
5007
|
-
|
|
5012
|
+
|
|
5008
5013
|
begin
|
|
5009
5014
|
# Hardware Information
|
|
5010
5015
|
text << "Hardware".fg(226).b + "\n"
|
|
@@ -5033,11 +5038,11 @@ def system_info # {{{3
|
|
|
5033
5038
|
temp_color = temp > 80 ? 196 : temp > 60 ? 220 : 156
|
|
5034
5039
|
text << sprintf(" %-15s %s\n", "CPU Temp:".fg(249), "#{temp}°C".fg(temp_color))
|
|
5035
5040
|
end
|
|
5036
|
-
|
|
5041
|
+
|
|
5037
5042
|
text << "\n"
|
|
5038
|
-
rescue #
|
|
5043
|
+
rescue StandardError # hardware info unavailable
|
|
5039
5044
|
end
|
|
5040
|
-
|
|
5045
|
+
|
|
5041
5046
|
begin
|
|
5042
5047
|
# Memory Information with visual bar
|
|
5043
5048
|
text << "Memory".fg(226).b + "\n"
|
|
@@ -5079,11 +5084,11 @@ def system_info # {{{3
|
|
|
5079
5084
|
swap_used = (parts[2].to_i / 1024.0 / 1024.0 / 1024.0).round(1)
|
|
5080
5085
|
text << sprintf(" %-15s %s\n", "Swap:".fg(249), "#{swap_used}/#{swap_total} GB".fg(156))
|
|
5081
5086
|
end
|
|
5082
|
-
|
|
5087
|
+
|
|
5083
5088
|
text << "\n"
|
|
5084
|
-
rescue #
|
|
5089
|
+
rescue StandardError # memory info unavailable
|
|
5085
5090
|
end
|
|
5086
|
-
|
|
5091
|
+
|
|
5087
5092
|
begin
|
|
5088
5093
|
# Storage Information with visual bars
|
|
5089
5094
|
text << "Storage".fg(226).b + "\n"
|
|
@@ -5123,9 +5128,9 @@ def system_info # {{{3
|
|
|
5123
5128
|
end
|
|
5124
5129
|
end
|
|
5125
5130
|
text << "\n"
|
|
5126
|
-
rescue #
|
|
5131
|
+
rescue StandardError # storage info unavailable
|
|
5127
5132
|
end
|
|
5128
|
-
|
|
5133
|
+
|
|
5129
5134
|
begin
|
|
5130
5135
|
# Network Information
|
|
5131
5136
|
text << "Network".fg(226).b + "\n"
|
|
@@ -5159,14 +5164,14 @@ def system_info # {{{3
|
|
|
5159
5164
|
`curl -s ifconfig.me 2>/dev/null`.chomp
|
|
5160
5165
|
end
|
|
5161
5166
|
text << sprintf(" %-15s %s\n", "Public IP:".fg(249), public_ip.fg(156)) unless public_ip.empty?
|
|
5162
|
-
rescue
|
|
5167
|
+
rescue StandardError # timeout or network error
|
|
5163
5168
|
# Skip public IP if timeout or error
|
|
5164
5169
|
end
|
|
5165
5170
|
|
|
5166
5171
|
text << "\n"
|
|
5167
|
-
rescue #
|
|
5172
|
+
rescue StandardError # network info unavailable
|
|
5168
5173
|
end
|
|
5169
|
-
|
|
5174
|
+
|
|
5170
5175
|
begin
|
|
5171
5176
|
# Environment Information
|
|
5172
5177
|
text << "Environment".fg(226).b + "\n"
|
|
@@ -5201,9 +5206,9 @@ def system_info # {{{3
|
|
|
5201
5206
|
end
|
|
5202
5207
|
|
|
5203
5208
|
text << "\n"
|
|
5204
|
-
rescue #
|
|
5209
|
+
rescue StandardError # environment info unavailable
|
|
5205
5210
|
end
|
|
5206
|
-
|
|
5211
|
+
|
|
5207
5212
|
begin
|
|
5208
5213
|
# Services & Processes
|
|
5209
5214
|
text << "Services & Processes".fg(226).b + "\n"
|
|
@@ -5244,11 +5249,11 @@ def system_info # {{{3
|
|
|
5244
5249
|
text << sprintf(" %-15s %s\n", "Users:".fg(249), "#{users} logged in".fg(156))
|
|
5245
5250
|
|
|
5246
5251
|
text << "\n"
|
|
5247
|
-
rescue #
|
|
5252
|
+
rescue StandardError # services info unavailable
|
|
5248
5253
|
end
|
|
5249
|
-
|
|
5254
|
+
|
|
5250
5255
|
@pR.say(text)
|
|
5251
|
-
rescue => e
|
|
5256
|
+
rescue StandardError => e # system info display failed
|
|
5252
5257
|
@pR.say("Unable to show system info\n#{e.message}".fg(196))
|
|
5253
5258
|
end
|
|
5254
5259
|
|
|
@@ -5261,7 +5266,7 @@ end
|
|
|
5261
5266
|
|
|
5262
5267
|
def navi_invoke # {{{3
|
|
5263
5268
|
@navi = `navi`
|
|
5264
|
-
rescue
|
|
5269
|
+
rescue StandardError # navi command not found
|
|
5265
5270
|
@pB.say(' navi not installed - see https://github.com/junegunn/fzf')
|
|
5266
5271
|
end
|
|
5267
5272
|
|
|
@@ -5460,7 +5465,7 @@ def get_cached_dirlist(dir, ls_options, ls_options_with_long = nil) # {{{2
|
|
|
5460
5465
|
dir_mtime = File.mtime(dir).to_i
|
|
5461
5466
|
file_count = Dir.entries(dir).size
|
|
5462
5467
|
cache_key = "#{dir}:#{ls_options_with_long}:#{dir_mtime}:#{file_count}"
|
|
5463
|
-
rescue
|
|
5468
|
+
rescue Errno::EACCES, Errno::ENOENT # permission denied or missing dir
|
|
5464
5469
|
return nil # Can't cache if we can't get mtime or file count
|
|
5465
5470
|
end
|
|
5466
5471
|
|
|
@@ -5488,7 +5493,7 @@ def get_cached_dirlist(dir, ls_options, ls_options_with_long = nil) # {{{2
|
|
|
5488
5493
|
@dir_cache.delete_if { |key, _| key.start_with?("#{dir}:") && key != cache_key }
|
|
5489
5494
|
|
|
5490
5495
|
result
|
|
5491
|
-
rescue => e
|
|
5496
|
+
rescue StandardError => e # ls command failed
|
|
5492
5497
|
# Return empty result on error
|
|
5493
5498
|
{ purels: [], colorls: [] }
|
|
5494
5499
|
end
|
|
@@ -5500,7 +5505,7 @@ def get_cached_file_metadata(file_path) # {{{2
|
|
|
5500
5505
|
begin
|
|
5501
5506
|
file_stat = File.stat(file_path)
|
|
5502
5507
|
cache_key = "#{file_path}:#{file_stat.mtime.to_i}:#{file_stat.size}"
|
|
5503
|
-
rescue
|
|
5508
|
+
rescue Errno::EACCES, Errno::ENOENT # permission denied or missing file
|
|
5504
5509
|
return nil
|
|
5505
5510
|
end
|
|
5506
5511
|
|
|
@@ -5536,7 +5541,7 @@ def get_cached_file_metadata(file_path) # {{{2
|
|
|
5536
5541
|
@metadata_cache.delete_if { |key, _| key.start_with?("#{file_path}:") && key != cache_key }
|
|
5537
5542
|
|
|
5538
5543
|
metadata
|
|
5539
|
-
rescue
|
|
5544
|
+
rescue StandardError # metadata extraction failed
|
|
5540
5545
|
nil
|
|
5541
5546
|
end
|
|
5542
5547
|
end
|
|
@@ -5701,7 +5706,7 @@ def dirlist(left: true, directory: nil) # LIST DIRECTORIES {{{2
|
|
|
5701
5706
|
pure_output = command("ls #{Shellwords.escape(dir)} #{ls_options}")
|
|
5702
5707
|
purels = pure_output.pure.split("\n")
|
|
5703
5708
|
colorls = color_output.split("\n")
|
|
5704
|
-
rescue => e
|
|
5709
|
+
rescue StandardError => e # ls command failed
|
|
5705
5710
|
purels = []
|
|
5706
5711
|
colorls = []
|
|
5707
5712
|
end
|
|
@@ -5732,7 +5737,7 @@ def dirlist(left: true, directory: nil) # LIST DIRECTORIES {{{2
|
|
|
5732
5737
|
@files = purels
|
|
5733
5738
|
# Update @selected & @fileattr for left pane
|
|
5734
5739
|
if purels[@index]
|
|
5735
|
-
@selected = Dir.pwd
|
|
5740
|
+
@selected = File.join(Dir.pwd, purels[@index])
|
|
5736
5741
|
sfile = @selected.dup
|
|
5737
5742
|
sfile += '/' if File.directory?(@selected)
|
|
5738
5743
|
time_opt = @is_macos_bsd ? '-T' : '--time-style=long-iso'
|
|
@@ -6165,7 +6170,7 @@ def command(cmd, timeout: 5, return_both: false) # {{{2
|
|
|
6165
6170
|
@pR.say(msg.fg(196))
|
|
6166
6171
|
''
|
|
6167
6172
|
end
|
|
6168
|
-
rescue => e
|
|
6173
|
+
rescue StandardError => e # command execution failed
|
|
6169
6174
|
msg = "Error: #{e.message}\n#{e.backtrace.join("\n")}\n"
|
|
6170
6175
|
if return_both
|
|
6171
6176
|
['', msg]
|
|
@@ -6241,7 +6246,7 @@ def copy_move_link(type) # COPY OR MOVE TAGGED ITEMS {{{2
|
|
|
6241
6246
|
end
|
|
6242
6247
|
|
|
6243
6248
|
@file_op_result = " #{type.capitalize} complete: #{operations.size} item(s)".fg(156)
|
|
6244
|
-
rescue => e
|
|
6249
|
+
rescue StandardError => e # file operation failed
|
|
6245
6250
|
@file_op_result = " #{type.capitalize} error: #{e.message}".fg(196)
|
|
6246
6251
|
ensure
|
|
6247
6252
|
@file_op_progress = nil
|
|
@@ -6274,7 +6279,7 @@ def copy_move_link_sync(type, items, dest_dir) # {{{3
|
|
|
6274
6279
|
operations << { source_path: item, dest_path: dest }
|
|
6275
6280
|
@pB.say(' Item(s) symlinked here.')
|
|
6276
6281
|
end
|
|
6277
|
-
rescue => e
|
|
6282
|
+
rescue StandardError => e # file operation failed
|
|
6278
6283
|
@pB.say(e.to_s)
|
|
6279
6284
|
end
|
|
6280
6285
|
end
|
|
@@ -6403,7 +6408,7 @@ def get_interactive_program(file_path) # HELPER FOR OPEN_SELECTED TO USE @intera
|
|
|
6403
6408
|
end
|
|
6404
6409
|
end
|
|
6405
6410
|
end
|
|
6406
|
-
rescue
|
|
6411
|
+
rescue StandardError # desktop file detection failed
|
|
6407
6412
|
# If detection fails, fall back to normal behavior
|
|
6408
6413
|
end
|
|
6409
6414
|
nil
|
|
@@ -6723,7 +6728,7 @@ def showcontent # SHOW CONTENTS IN THE RIGHT WINDOW {{{2
|
|
|
6723
6728
|
end
|
|
6724
6729
|
end
|
|
6725
6730
|
end
|
|
6726
|
-
rescue => e
|
|
6731
|
+
rescue StandardError => e # SVG render failed
|
|
6727
6732
|
@pR.say("Error processing SVG: #{e}")
|
|
6728
6733
|
end
|
|
6729
6734
|
when /\.(?:png|jpe?g|bmp|gif|webp|tiff?)$/i
|
|
@@ -6736,7 +6741,7 @@ def showcontent # SHOW CONTENTS IN THE RIGHT WINDOW {{{2
|
|
|
6736
6741
|
showimage(@selected)
|
|
6737
6742
|
@image = true
|
|
6738
6743
|
end
|
|
6739
|
-
rescue => e
|
|
6744
|
+
rescue Errno::EACCES, Errno::ENOENT => e # permission denied or missing image
|
|
6740
6745
|
@pR.say("Error checking image size: #{e}")
|
|
6741
6746
|
end
|
|
6742
6747
|
when /\.(?:mpg|mpeg|avi|mov|mkv|mp4|webm|flv|wmv|m4v)$/i
|
|
@@ -6765,6 +6770,7 @@ def showcontent # SHOW CONTENTS IN THE RIGHT WINDOW {{{2
|
|
|
6765
6770
|
else
|
|
6766
6771
|
# Enhanced text file preview with partial loading for large files
|
|
6767
6772
|
begin
|
|
6773
|
+
Timeout.timeout(5) do # Prevent preview from hanging
|
|
6768
6774
|
file_size = File.size(@selected)
|
|
6769
6775
|
|
|
6770
6776
|
# For text files, we can preview them partially even if large
|
|
@@ -6779,6 +6785,7 @@ def showcontent # SHOW CONTENTS IN THE RIGHT WINDOW {{{2
|
|
|
6779
6785
|
line_count = 0
|
|
6780
6786
|
|
|
6781
6787
|
file.each_line do |line|
|
|
6788
|
+
line = line[0, 10_000] + "...\n" if line.length > 10_000
|
|
6782
6789
|
lines << line
|
|
6783
6790
|
line_count += 1
|
|
6784
6791
|
break if line_count >= preview_lines
|
|
@@ -6819,25 +6826,33 @@ def showcontent # SHOW CONTENTS IN THE RIGHT WINDOW {{{2
|
|
|
6819
6826
|
else
|
|
6820
6827
|
# Small files - read entirely as before
|
|
6821
6828
|
text = File.read(@selected).force_encoding('UTF-8') rescue ''
|
|
6829
|
+
# Truncate extremely long lines to prevent UI hang
|
|
6830
|
+
has_long_lines = text.lines.any? { |l| l.length > 2_000 }
|
|
6831
|
+
if has_long_lines
|
|
6832
|
+
text = text.lines.map { |l| l.length > 2_000 ? l[0, 10_000] + "...\n" : l }.join
|
|
6833
|
+
end
|
|
6822
6834
|
if text.valid_encoding?
|
|
6823
|
-
if @batuse
|
|
6824
|
-
# Try bat
|
|
6835
|
+
if @batuse && !has_long_lines
|
|
6836
|
+
# Try bat on original file (safe, no long lines)
|
|
6825
6837
|
bat_cmd = "#{@bat} -n --color=always #{Shellwords.escape(@selected)}"
|
|
6826
|
-
bat_output = command(bat_cmd, timeout:
|
|
6838
|
+
bat_output = command(bat_cmd, timeout: 5)
|
|
6827
6839
|
if bat_output.empty?
|
|
6828
|
-
# Bat failed or returned empty - try plain cat
|
|
6829
6840
|
showcommand("cat #{Shellwords.escape(@selected)}")
|
|
6830
6841
|
else
|
|
6831
6842
|
@pR.say(bat_output)
|
|
6832
6843
|
end
|
|
6833
6844
|
else
|
|
6834
|
-
|
|
6845
|
+
# Use truncated text directly (long lines or no bat)
|
|
6846
|
+
@pR.say(text)
|
|
6835
6847
|
end
|
|
6836
6848
|
else
|
|
6837
6849
|
@pR.say("No preview available for #{@selected}")
|
|
6838
6850
|
end
|
|
6839
6851
|
end
|
|
6840
|
-
|
|
6852
|
+
end # Timeout.timeout
|
|
6853
|
+
rescue Timeout::Error
|
|
6854
|
+
@pR.say("Preview timed out (file too large or complex)")
|
|
6855
|
+
rescue StandardError => e # file preview failed
|
|
6841
6856
|
@pR.say("Error previewing file: #{e}")
|
|
6842
6857
|
end
|
|
6843
6858
|
end
|
|
@@ -6894,7 +6909,7 @@ def showimage(image) # SHOW THE SELECTED IMAGE IN THE RIGHT WINDOW {{{2
|
|
|
6894
6909
|
max_height: @pR.h - 1)
|
|
6895
6910
|
@current_image_path = img_path
|
|
6896
6911
|
end
|
|
6897
|
-
rescue => e
|
|
6912
|
+
rescue StandardError => e # image display failed
|
|
6898
6913
|
@pR.text = "Error showing image: #{e.message}"
|
|
6899
6914
|
end
|
|
6900
6915
|
end
|
|
@@ -7075,7 +7090,7 @@ loop do
|
|
|
7075
7090
|
@pT.update = @pL.update = @pR.update = @pB.update = true
|
|
7076
7091
|
refresh
|
|
7077
7092
|
end
|
|
7078
|
-
rescue; end
|
|
7093
|
+
rescue StandardError; end # terminal size query failed
|
|
7079
7094
|
end
|
|
7080
7095
|
|
|
7081
7096
|
# redraw, but ignore TTY‐focus errors
|
|
@@ -7093,7 +7108,7 @@ loop do
|
|
|
7093
7108
|
# If cwd was deleted externally, jump home
|
|
7094
7109
|
begin
|
|
7095
7110
|
Dir.pwd
|
|
7096
|
-
rescue
|
|
7111
|
+
rescue Errno::ENOENT, Errno::EACCES # cwd was deleted or became inaccessible
|
|
7097
7112
|
Dir.chdir
|
|
7098
7113
|
end
|
|
7099
7114
|
# If selected file was removed externally, force pane refresh (skip in archive/remote mode)
|
data/img/rtfm-kb.svg
ADDED
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1500 560" width="1500" height="560" font-family="monospace, Courier New, Courier">
|
|
2
|
+
<defs>
|
|
3
|
+
<style>
|
|
4
|
+
.key { fill: #333; stroke: #555; stroke-width: 1; rx: 5; ry: 5; }
|
|
5
|
+
.kw { fill: #2a2a2a; stroke: #555; stroke-width: 1; rx: 5; ry: 5; }
|
|
6
|
+
.kl { font-size: 12px; fill: #bbb; font-weight: bold; text-anchor: middle; }
|
|
7
|
+
.lo { font-size: 8.5px; fill: #FF8888; text-anchor: middle; }
|
|
8
|
+
.up { font-size: 8.5px; fill: #88BBFF; text-anchor: middle; }
|
|
9
|
+
.ct { font-size: 10px; fill: #88FF88; }
|
|
10
|
+
.sp { font-size: 8.5px; fill: #DDAAFF; text-anchor: middle; }
|
|
11
|
+
.nv { font-size: 8.5px; fill: #bbb; text-anchor: middle; }
|
|
12
|
+
</style>
|
|
13
|
+
</defs>
|
|
14
|
+
<rect width="1500" height="560" fill="#1a1a1a" rx="8"/>
|
|
15
|
+
<text x="470" y="22" text-anchor="middle" font-size="15" font-weight="bold" fill="#fff">RTFM Keyboard Reference</text>
|
|
16
|
+
|
|
17
|
+
<!-- Row 0: Esc -->
|
|
18
|
+
<rect x="10" y="34" width="58" height="55" class="key"/>
|
|
19
|
+
<text x="39" y="54" class="kl">Esc</text>
|
|
20
|
+
<text x="39" y="80" class="lo">quit</text>
|
|
21
|
+
|
|
22
|
+
<!-- Row 1: Number row kw=62 gap=4 -->
|
|
23
|
+
<rect x="10" y="97" width="58" height="55" class="key"/>
|
|
24
|
+
<text x="39" y="117" class="kl">` ~</text>
|
|
25
|
+
<text x="39" y="143" class="lo">~ home</text>
|
|
26
|
+
|
|
27
|
+
<rect x="72" y="97" width="62" height="55" class="key"/>
|
|
28
|
+
<text x="103" y="117" class="kl">1</text>
|
|
29
|
+
<text x="103" y="143" class="lo">tab 1</text>
|
|
30
|
+
|
|
31
|
+
<rect x="138" y="97" width="62" height="55" class="key"/>
|
|
32
|
+
<text x="169" y="117" class="kl">2</text>
|
|
33
|
+
<text x="169" y="143" class="lo">tab 2</text>
|
|
34
|
+
|
|
35
|
+
<rect x="204" y="97" width="62" height="55" class="key"/>
|
|
36
|
+
<text x="235" y="117" class="kl">3</text>
|
|
37
|
+
<text x="235" y="143" class="lo">tab 3</text>
|
|
38
|
+
|
|
39
|
+
<rect x="270" y="97" width="62" height="55" class="key"/>
|
|
40
|
+
<text x="301" y="117" class="kl">4</text>
|
|
41
|
+
<text x="301" y="143" class="lo">tab 4</text>
|
|
42
|
+
|
|
43
|
+
<rect x="336" y="97" width="62" height="55" class="key"/>
|
|
44
|
+
<text x="367" y="117" class="kl">5</text>
|
|
45
|
+
<text x="367" y="143" class="lo">tab 5</text>
|
|
46
|
+
|
|
47
|
+
<rect x="402" y="97" width="62" height="55" class="key"/>
|
|
48
|
+
<text x="433" y="117" class="kl">6</text>
|
|
49
|
+
<text x="433" y="143" class="lo">tab 6</text>
|
|
50
|
+
|
|
51
|
+
<rect x="468" y="97" width="62" height="55" class="key"/>
|
|
52
|
+
<text x="499" y="117" class="kl">7</text>
|
|
53
|
+
<text x="499" y="143" class="lo">tab 7</text>
|
|
54
|
+
|
|
55
|
+
<rect x="534" y="97" width="62" height="55" class="key"/>
|
|
56
|
+
<text x="565" y="117" class="kl">8</text>
|
|
57
|
+
<text x="565" y="143" class="lo">tab 8</text>
|
|
58
|
+
|
|
59
|
+
<rect x="600" y="97" width="62" height="55" class="key"/>
|
|
60
|
+
<text x="631" y="117" class="kl">9</text>
|
|
61
|
+
<text x="631" y="143" class="lo">tab 9</text>
|
|
62
|
+
|
|
63
|
+
<rect x="666" y="97" width="62" height="55" class="key"/>
|
|
64
|
+
<text x="697" y="127" class="kl">0</text>
|
|
65
|
+
|
|
66
|
+
<rect x="732" y="97" width="62" height="55" class="key"/>
|
|
67
|
+
<text x="763" y="115" class="kl">- _</text>
|
|
68
|
+
<text x="763" y="133" class="sp">_ image</text>
|
|
69
|
+
<text x="763" y="146" class="lo">- preview</text>
|
|
70
|
+
|
|
71
|
+
<rect x="798" y="97" width="62" height="55" class="key"/>
|
|
72
|
+
<text x="829" y="115" class="kl">= +</text>
|
|
73
|
+
<text x="829" y="133" class="sp">+ interact</text>
|
|
74
|
+
<text x="829" y="146" class="lo">= mkdir</text>
|
|
75
|
+
|
|
76
|
+
<rect x="864" y="97" width="76" height="55" class="kw"/>
|
|
77
|
+
<text x="902" y="130" class="nv">Bksp</text>
|
|
78
|
+
|
|
79
|
+
<!-- Row 2: QWERTY start x=10+80=90 offset, kw=62 -->
|
|
80
|
+
<rect x="10" y="160" width="76" height="55" class="kw"/>
|
|
81
|
+
<text x="48" y="183" class="nv">Tab</text>
|
|
82
|
+
<text x="48" y="206" class="nv">pgdn R</text>
|
|
83
|
+
|
|
84
|
+
<rect x="90" y="160" width="62" height="55" class="key"/>
|
|
85
|
+
<text x="121" y="176" class="kl">Q</text>
|
|
86
|
+
<text x="121" y="194" class="up">Q nosave</text>
|
|
87
|
+
<text x="121" y="207" class="lo">q save</text>
|
|
88
|
+
|
|
89
|
+
<rect x="156" y="160" width="62" height="55" class="key"/>
|
|
90
|
+
<text x="187" y="176" class="kl">W</text>
|
|
91
|
+
<text x="187" y="194" class="up">Write cfg</text>
|
|
92
|
+
<text x="187" y="207" class="lo">width</text>
|
|
93
|
+
|
|
94
|
+
<rect x="222" y="160" width="62" height="55" class="key"/>
|
|
95
|
+
<text x="253" y="176" class="kl">E</text>
|
|
96
|
+
<text x="253" y="194" class="up">Bulk ren</text>
|
|
97
|
+
<text x="253" y="207" class="lo">props</text>
|
|
98
|
+
|
|
99
|
+
<rect x="288" y="160" width="62" height="55" class="key"/>
|
|
100
|
+
<text x="319" y="176" class="kl">R</text>
|
|
101
|
+
<text x="319" y="194" class="up">Load cfg</text>
|
|
102
|
+
<text x="319" y="207" class="lo">refresh</text>
|
|
103
|
+
|
|
104
|
+
<rect x="354" y="160" width="62" height="55" class="key"/>
|
|
105
|
+
<text x="385" y="176" class="kl">T</text>
|
|
106
|
+
<text x="385" y="194" class="up">Tag list</text>
|
|
107
|
+
<text x="385" y="207" class="lo">tag</text>
|
|
108
|
+
|
|
109
|
+
<rect x="420" y="160" width="62" height="55" class="key"/>
|
|
110
|
+
<text x="451" y="176" class="kl">Y</text>
|
|
111
|
+
<text x="451" y="194" class="up">Cp clipbd</text>
|
|
112
|
+
<text x="451" y="207" class="lo">cp primary</text>
|
|
113
|
+
|
|
114
|
+
<rect x="486" y="160" width="62" height="55" class="key"/>
|
|
115
|
+
<text x="517" y="176" class="kl">U</text>
|
|
116
|
+
<text x="517" y="194" class="up">Undo</text>
|
|
117
|
+
<text x="517" y="207" class="lo">untag all</text>
|
|
118
|
+
|
|
119
|
+
<rect x="552" y="160" width="62" height="55" class="key"/>
|
|
120
|
+
<text x="583" y="176" class="kl">I</text>
|
|
121
|
+
<text x="583" y="194" class="up">AI descr</text>
|
|
122
|
+
<text x="583" y="207" class="lo">invert</text>
|
|
123
|
+
|
|
124
|
+
<rect x="618" y="160" width="62" height="55" class="key"/>
|
|
125
|
+
<text x="649" y="176" class="kl">O</text>
|
|
126
|
+
<text x="649" y="194" class="up">ls cmd</text>
|
|
127
|
+
<text x="649" y="207" class="lo">order</text>
|
|
128
|
+
|
|
129
|
+
<rect x="684" y="160" width="62" height="55" class="key"/>
|
|
130
|
+
<text x="715" y="176" class="kl">P</text>
|
|
131
|
+
<text x="715" y="194" class="up">Move here</text>
|
|
132
|
+
<text x="715" y="207" class="lo">copy here</text>
|
|
133
|
+
|
|
134
|
+
<rect x="750" y="160" width="62" height="55" class="key"/>
|
|
135
|
+
<text x="781" y="176" class="kl">[ {</text>
|
|
136
|
+
<text x="781" y="194" class="sp">{ ren tab</text>
|
|
137
|
+
<text x="781" y="207" class="sp">[ cls tab</text>
|
|
138
|
+
|
|
139
|
+
<rect x="816" y="160" width="62" height="55" class="key"/>
|
|
140
|
+
<text x="847" y="176" class="kl">] }</text>
|
|
141
|
+
<text x="847" y="194" class="sp">} dup tab</text>
|
|
142
|
+
<text x="847" y="207" class="sp">] new tab</text>
|
|
143
|
+
|
|
144
|
+
<rect x="882" y="160" width="58" height="55" class="key"/>
|
|
145
|
+
<text x="911" y="176" class="kl">\</text>
|
|
146
|
+
<text x="911" y="200" class="sp">clr srch</text>
|
|
147
|
+
|
|
148
|
+
<!-- Row 3: ASDF start x=10+90=100 offset -->
|
|
149
|
+
<rect x="10" y="223" width="86" height="55" class="kw"/>
|
|
150
|
+
<text x="53" y="255" class="nv">Ctrl</text>
|
|
151
|
+
|
|
152
|
+
<rect x="100" y="223" width="62" height="55" class="key"/>
|
|
153
|
+
<text x="131" y="239" class="kl">A</text>
|
|
154
|
+
<text x="131" y="257" class="up">Long list</text>
|
|
155
|
+
<text x="131" y="270" class="lo">all/none</text>
|
|
156
|
+
|
|
157
|
+
<rect x="166" y="223" width="62" height="55" class="key"/>
|
|
158
|
+
<text x="197" y="239" class="kl">S</text>
|
|
159
|
+
<text x="197" y="257" class="up">Sys info</text>
|
|
160
|
+
<text x="197" y="270" class="lo">symlink</text>
|
|
161
|
+
|
|
162
|
+
<rect x="232" y="223" width="62" height="55" class="key"/>
|
|
163
|
+
<text x="263" y="239" class="kl">D</text>
|
|
164
|
+
<text x="263" y="257" class="up">Emp trash</text>
|
|
165
|
+
<text x="263" y="270" class="lo">delete</text>
|
|
166
|
+
|
|
167
|
+
<rect x="298" y="223" width="62" height="55" class="key"/>
|
|
168
|
+
<text x="329" y="239" class="kl">F</text>
|
|
169
|
+
<text x="329" y="257" class="up">Filt regex</text>
|
|
170
|
+
<text x="329" y="270" class="lo">filt type</text>
|
|
171
|
+
|
|
172
|
+
<rect x="364" y="223" width="62" height="55" class="key"/>
|
|
173
|
+
<text x="395" y="239" class="kl">G</text>
|
|
174
|
+
<text x="395" y="257" class="up">Git status</text>
|
|
175
|
+
<text x="395" y="270" class="lo">grep</text>
|
|
176
|
+
|
|
177
|
+
<rect x="430" y="223" width="62" height="55" class="key"/>
|
|
178
|
+
<text x="461" y="239" class="kl">H</text>
|
|
179
|
+
<text x="461" y="257" class="up">Hash dir</text>
|
|
180
|
+
<text x="461" y="270" class="nv">h = LEFT</text>
|
|
181
|
+
|
|
182
|
+
<rect x="496" y="223" width="62" height="55" class="key"/>
|
|
183
|
+
<text x="527" y="239" class="kl">J</text>
|
|
184
|
+
<text x="527" y="257" class="up">Prev tab</text>
|
|
185
|
+
<text x="527" y="270" class="nv">j = DOWN</text>
|
|
186
|
+
|
|
187
|
+
<rect x="562" y="223" width="62" height="55" class="key"/>
|
|
188
|
+
<text x="593" y="239" class="kl">K</text>
|
|
189
|
+
<text x="593" y="257" class="up">Next tab</text>
|
|
190
|
+
<text x="593" y="270" class="nv">k = UP</text>
|
|
191
|
+
|
|
192
|
+
<rect x="628" y="223" width="62" height="55" class="key"/>
|
|
193
|
+
<text x="659" y="239" class="kl">L</text>
|
|
194
|
+
<text x="659" y="257" class="up">Locate</text>
|
|
195
|
+
<text x="659" y="270" class="nv">l = RIGHT</text>
|
|
196
|
+
|
|
197
|
+
<rect x="694" y="223" width="62" height="55" class="key"/>
|
|
198
|
+
<text x="725" y="239" class="kl">; :</text>
|
|
199
|
+
<text x="725" y="257" class="sp">: command</text>
|
|
200
|
+
<text x="725" y="270" class="sp">; history</text>
|
|
201
|
+
|
|
202
|
+
<rect x="760" y="223" width="62" height="55" class="key"/>
|
|
203
|
+
<text x="791" y="239" class="kl">'</text>
|
|
204
|
+
<text x="791" y="262" class="sp">jump mark</text>
|
|
205
|
+
|
|
206
|
+
<rect x="826" y="223" width="114" height="55" class="kw"/>
|
|
207
|
+
<text x="883" y="248" class="nv">Enter</text>
|
|
208
|
+
<text x="883" y="268" class="nv">open/refresh</text>
|
|
209
|
+
|
|
210
|
+
<!-- Row 4: ZXCV start x=10+100=110 offset -->
|
|
211
|
+
<rect x="10" y="286" width="96" height="55" class="kw"/>
|
|
212
|
+
<text x="58" y="318" class="nv">Shift</text>
|
|
213
|
+
|
|
214
|
+
<rect x="110" y="286" width="62" height="55" class="key"/>
|
|
215
|
+
<text x="141" y="302" class="kl">Z</text>
|
|
216
|
+
<text x="141" y="320" class="up">Zip</text>
|
|
217
|
+
<text x="141" y="333" class="lo">unzip</text>
|
|
218
|
+
|
|
219
|
+
<rect x="176" y="286" width="62" height="55" class="key"/>
|
|
220
|
+
<text x="207" y="302" class="kl">X</text>
|
|
221
|
+
<text x="207" y="320" class="up">Compare</text>
|
|
222
|
+
<text x="207" y="333" class="lo">open force</text>
|
|
223
|
+
|
|
224
|
+
<rect x="242" y="286" width="62" height="55" class="key"/>
|
|
225
|
+
<text x="273" y="302" class="kl">C</text>
|
|
226
|
+
<text x="273" y="320" class="up">Config</text>
|
|
227
|
+
<text x="273" y="333" class="lo">rename</text>
|
|
228
|
+
|
|
229
|
+
<rect x="308" y="286" width="62" height="55" class="key"/>
|
|
230
|
+
<text x="339" y="302" class="kl">V</text>
|
|
231
|
+
<text x="339" y="320" class="up">Plugins</text>
|
|
232
|
+
<text x="339" y="333" class="lo">version</text>
|
|
233
|
+
|
|
234
|
+
<rect x="374" y="286" width="62" height="55" class="key"/>
|
|
235
|
+
<text x="405" y="302" class="kl">B</text>
|
|
236
|
+
<text x="405" y="320" class="up">Border</text>
|
|
237
|
+
<text x="405" y="333" class="lo">syntax hl</text>
|
|
238
|
+
|
|
239
|
+
<rect x="440" y="286" width="62" height="55" class="key"/>
|
|
240
|
+
<text x="471" y="302" class="kl">N</text>
|
|
241
|
+
<text x="471" y="320" class="up">Srch prev</text>
|
|
242
|
+
<text x="471" y="333" class="lo">srch next</text>
|
|
243
|
+
|
|
244
|
+
<rect x="506" y="286" width="62" height="55" class="key"/>
|
|
245
|
+
<text x="537" y="302" class="kl">M</text>
|
|
246
|
+
<text x="537" y="320" class="up">Show mrks</text>
|
|
247
|
+
<text x="537" y="333" class="lo">set mark</text>
|
|
248
|
+
|
|
249
|
+
<rect x="572" y="286" width="62" height="55" class="key"/>
|
|
250
|
+
<text x="603" y="315" class="kl">, <</text>
|
|
251
|
+
|
|
252
|
+
<rect x="638" y="286" width="62" height="55" class="key"/>
|
|
253
|
+
<text x="669" y="302" class="kl">. ></text>
|
|
254
|
+
<text x="669" y="333" class="sp">> follow lnk</text>
|
|
255
|
+
|
|
256
|
+
<rect x="704" y="286" width="62" height="55" class="key"/>
|
|
257
|
+
<text x="735" y="302" class="kl">/ ?</text>
|
|
258
|
+
<text x="735" y="320" class="sp">? help</text>
|
|
259
|
+
<text x="735" y="333" class="sp">/ search</text>
|
|
260
|
+
|
|
261
|
+
<rect x="770" y="286" width="170" height="55" class="kw"/>
|
|
262
|
+
<text x="855" y="318" class="nv">Shift</text>
|
|
263
|
+
|
|
264
|
+
<!-- Row 5: Bottom -->
|
|
265
|
+
<rect x="10" y="349" width="70" height="50" class="kw"/>
|
|
266
|
+
<text x="45" y="378" class="nv">Ctrl</text>
|
|
267
|
+
|
|
268
|
+
<rect x="84" y="349" width="58" height="50" class="kw"/>
|
|
269
|
+
<text x="113" y="378" class="nv">Alt</text>
|
|
270
|
+
|
|
271
|
+
<rect x="146" y="349" width="330" height="50" class="key"/>
|
|
272
|
+
<text x="311" y="378" class="nv">Space</text>
|
|
273
|
+
|
|
274
|
+
<rect x="480" y="349" width="62" height="50" class="key"/>
|
|
275
|
+
<text x="511" y="366" class="kl"># @</text>
|
|
276
|
+
<text x="511" y="382" class="sp"># locate</text>
|
|
277
|
+
<text x="511" y="394" class="sp">@ ruby dbg</text>
|
|
278
|
+
|
|
279
|
+
<!-- Nav cluster -->
|
|
280
|
+
<rect x="990" y="97" width="64" height="55" class="key"/>
|
|
281
|
+
<text x="1022" y="120" class="nv">Home</text>
|
|
282
|
+
<text x="1022" y="143" class="nv">g first</text>
|
|
283
|
+
|
|
284
|
+
<rect x="1058" y="97" width="64" height="55" class="key"/>
|
|
285
|
+
<text x="1090" y="120" class="nv">End</text>
|
|
286
|
+
<text x="1090" y="143" class="nv">G last</text>
|
|
287
|
+
|
|
288
|
+
<rect x="990" y="160" width="64" height="55" class="key"/>
|
|
289
|
+
<text x="1022" y="183" class="nv">PgUp</text>
|
|
290
|
+
<text x="1022" y="206" class="nv">page up</text>
|
|
291
|
+
|
|
292
|
+
<rect x="1058" y="160" width="64" height="55" class="key"/>
|
|
293
|
+
<text x="1090" y="183" class="nv">PgDn</text>
|
|
294
|
+
<text x="1090" y="206" class="nv">page dn</text>
|
|
295
|
+
|
|
296
|
+
<rect x="1022" y="286" width="60" height="55" class="key"/>
|
|
297
|
+
<text x="1052" y="310" class="nv">UP</text>
|
|
298
|
+
<text x="1052" y="333" class="nv">k</text>
|
|
299
|
+
|
|
300
|
+
<rect x="958" y="349" width="60" height="50" class="key"/>
|
|
301
|
+
<text x="988" y="370" class="nv">LEFT</text>
|
|
302
|
+
<text x="988" y="390" class="nv">h</text>
|
|
303
|
+
|
|
304
|
+
<rect x="1022" y="349" width="60" height="50" class="key"/>
|
|
305
|
+
<text x="1052" y="370" class="nv">DOWN</text>
|
|
306
|
+
<text x="1052" y="390" class="nv">j</text>
|
|
307
|
+
|
|
308
|
+
<rect x="1086" y="349" width="60" height="50" class="key"/>
|
|
309
|
+
<text x="1116" y="370" class="nv">RIGHT</text>
|
|
310
|
+
<text x="1116" y="390" class="nv">l/enter</text>
|
|
311
|
+
|
|
312
|
+
<!-- Right panel: Ctrl combos -->
|
|
313
|
+
<rect x="1180" y="34" width="300" height="340" rx="6" fill="#1a2a1a" stroke="#4a6a4a" stroke-width="1"/>
|
|
314
|
+
<text x="1330" y="56" text-anchor="middle" font-size="13" font-weight="bold" fill="#88FF88">Ctrl Combos</text>
|
|
315
|
+
<text x="1194" y="80" class="ct">C-A AI chat mode</text>
|
|
316
|
+
<text x="1194" y="100" class="ct">C-D Toggle trash view</text>
|
|
317
|
+
<text x="1194" y="120" class="ct">C-E Browse remote</text>
|
|
318
|
+
<text x="1194" y="140" class="ct">C-F Clear filter</text>
|
|
319
|
+
<text x="1194" y="160" class="ct">C-L fzf jump</text>
|
|
320
|
+
<text x="1194" y="180" class="ct">C-N Navi cheatsheet</text>
|
|
321
|
+
<text x="1194" y="200" class="ct">C-O Change ownership</text>
|
|
322
|
+
<text x="1194" y="220" class="ct">C-P Change permissions</text>
|
|
323
|
+
<text x="1194" y="240" class="ct">C-R Recent files</text>
|
|
324
|
+
<text x="1194" y="260" class="ct">C-T Tag by pattern</text>
|
|
325
|
+
<text x="1194" y="280" class="ct">C-Y Copy pane to clipboard</text>
|
|
326
|
+
<text x="1194" y="300" class="ct">C-; SSH history</text>
|
|
327
|
+
<text x="1194" y="328" class="ct">C-Arrows Move/copy items</text>
|
|
328
|
+
<text x="1194" y="348" class="ct">S-Arrows Scroll right pane</text>
|
|
329
|
+
<text x="1194" y="368" class="ct">S-Tab Page up right pane</text>
|
|
330
|
+
|
|
331
|
+
<!-- Legend -->
|
|
332
|
+
<rect x="20" y="470" width="14" height="14" fill="#442222" rx="2" stroke="#663333" stroke-width="0.5"/>
|
|
333
|
+
<text x="40" y="482" font-size="10" fill="#FF8888">lowercase</text>
|
|
334
|
+
<rect x="120" y="470" width="14" height="14" fill="#222244" rx="2" stroke="#333366" stroke-width="0.5"/>
|
|
335
|
+
<text x="140" y="482" font-size="10" fill="#88BBFF">UPPERCASE</text>
|
|
336
|
+
<rect x="240" y="470" width="14" height="14" fill="#224422" rx="2" stroke="#336633" stroke-width="0.5"/>
|
|
337
|
+
<text x="260" y="482" font-size="10" fill="#88FF88">Ctrl+key</text>
|
|
338
|
+
<rect x="350" y="470" width="14" height="14" fill="#332244" rx="2" stroke="#553366" stroke-width="0.5"/>
|
|
339
|
+
<text x="370" y="482" font-size="10" fill="#DDAAFF">special</text>
|
|
340
|
+
<text x="460" y="482" font-size="10" fill="#bbb">gray = navigation</text>
|
|
341
|
+
</svg>
|
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.2.
|
|
4
|
+
version: 8.2.3
|
|
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-25 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rcurses
|
|
@@ -97,7 +97,7 @@ files:
|
|
|
97
97
|
- examples/rtfm.conf
|
|
98
98
|
- examples/settings.rb
|
|
99
99
|
- img/logo.png
|
|
100
|
-
- img/rtfm-kb.
|
|
100
|
+
- img/rtfm-kb.svg
|
|
101
101
|
- man/rtfm.1
|
|
102
102
|
homepage: https://isene.com/
|
|
103
103
|
licenses:
|
data/img/rtfm-kb.png
DELETED
|
Binary file
|