rtfm-filemanager 8.2.1 → 8.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/bin/rtfm +77 -65
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 70a9b068989497362fa5d26c2a31cc1f839af5364ccf978b0f99f68707159255
|
|
4
|
+
data.tar.gz: f7e15cbab0c75bef8fc163eb179b60559ed08fc2f87244eb0e7ed703758c4581
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 664d2c0a068716ff76cd10bd525dbc6383b5e8073d696db8d268a2927eaf6050affdcd0c359fbb0be8544612c3591804975a9847594af09392f12de389c76b5b
|
|
7
|
+
data.tar.gz: c02dce8c6556406b65b0ff87b9062f4f45256d4feccc0fbcf1c8fc2404c84708acdaae8f87b2ddd929377494691accd61d519ca8b964481ed7d686d08ee7d6e1
|
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.2' # 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'
|
|
@@ -5002,9 +5004,9 @@ def system_info # {{{3
|
|
|
5002
5004
|
text << sprintf(" %-15s %s\n", "Kernel:".fg(249), kernel_version.fg(156))
|
|
5003
5005
|
text << sprintf(" %-15s %s\n", "Architecture:".fg(249), architecture.fg(156))
|
|
5004
5006
|
text << "\n"
|
|
5005
|
-
rescue #
|
|
5007
|
+
rescue StandardError # OS info unavailable
|
|
5006
5008
|
end
|
|
5007
|
-
|
|
5009
|
+
|
|
5008
5010
|
begin
|
|
5009
5011
|
# Hardware Information
|
|
5010
5012
|
text << "Hardware".fg(226).b + "\n"
|
|
@@ -5033,11 +5035,11 @@ def system_info # {{{3
|
|
|
5033
5035
|
temp_color = temp > 80 ? 196 : temp > 60 ? 220 : 156
|
|
5034
5036
|
text << sprintf(" %-15s %s\n", "CPU Temp:".fg(249), "#{temp}°C".fg(temp_color))
|
|
5035
5037
|
end
|
|
5036
|
-
|
|
5038
|
+
|
|
5037
5039
|
text << "\n"
|
|
5038
|
-
rescue #
|
|
5040
|
+
rescue StandardError # hardware info unavailable
|
|
5039
5041
|
end
|
|
5040
|
-
|
|
5042
|
+
|
|
5041
5043
|
begin
|
|
5042
5044
|
# Memory Information with visual bar
|
|
5043
5045
|
text << "Memory".fg(226).b + "\n"
|
|
@@ -5079,11 +5081,11 @@ def system_info # {{{3
|
|
|
5079
5081
|
swap_used = (parts[2].to_i / 1024.0 / 1024.0 / 1024.0).round(1)
|
|
5080
5082
|
text << sprintf(" %-15s %s\n", "Swap:".fg(249), "#{swap_used}/#{swap_total} GB".fg(156))
|
|
5081
5083
|
end
|
|
5082
|
-
|
|
5084
|
+
|
|
5083
5085
|
text << "\n"
|
|
5084
|
-
rescue #
|
|
5086
|
+
rescue StandardError # memory info unavailable
|
|
5085
5087
|
end
|
|
5086
|
-
|
|
5088
|
+
|
|
5087
5089
|
begin
|
|
5088
5090
|
# Storage Information with visual bars
|
|
5089
5091
|
text << "Storage".fg(226).b + "\n"
|
|
@@ -5123,9 +5125,9 @@ def system_info # {{{3
|
|
|
5123
5125
|
end
|
|
5124
5126
|
end
|
|
5125
5127
|
text << "\n"
|
|
5126
|
-
rescue #
|
|
5128
|
+
rescue StandardError # storage info unavailable
|
|
5127
5129
|
end
|
|
5128
|
-
|
|
5130
|
+
|
|
5129
5131
|
begin
|
|
5130
5132
|
# Network Information
|
|
5131
5133
|
text << "Network".fg(226).b + "\n"
|
|
@@ -5159,14 +5161,14 @@ def system_info # {{{3
|
|
|
5159
5161
|
`curl -s ifconfig.me 2>/dev/null`.chomp
|
|
5160
5162
|
end
|
|
5161
5163
|
text << sprintf(" %-15s %s\n", "Public IP:".fg(249), public_ip.fg(156)) unless public_ip.empty?
|
|
5162
|
-
rescue
|
|
5164
|
+
rescue StandardError # timeout or network error
|
|
5163
5165
|
# Skip public IP if timeout or error
|
|
5164
5166
|
end
|
|
5165
5167
|
|
|
5166
5168
|
text << "\n"
|
|
5167
|
-
rescue #
|
|
5169
|
+
rescue StandardError # network info unavailable
|
|
5168
5170
|
end
|
|
5169
|
-
|
|
5171
|
+
|
|
5170
5172
|
begin
|
|
5171
5173
|
# Environment Information
|
|
5172
5174
|
text << "Environment".fg(226).b + "\n"
|
|
@@ -5201,9 +5203,9 @@ def system_info # {{{3
|
|
|
5201
5203
|
end
|
|
5202
5204
|
|
|
5203
5205
|
text << "\n"
|
|
5204
|
-
rescue #
|
|
5206
|
+
rescue StandardError # environment info unavailable
|
|
5205
5207
|
end
|
|
5206
|
-
|
|
5208
|
+
|
|
5207
5209
|
begin
|
|
5208
5210
|
# Services & Processes
|
|
5209
5211
|
text << "Services & Processes".fg(226).b + "\n"
|
|
@@ -5244,11 +5246,11 @@ def system_info # {{{3
|
|
|
5244
5246
|
text << sprintf(" %-15s %s\n", "Users:".fg(249), "#{users} logged in".fg(156))
|
|
5245
5247
|
|
|
5246
5248
|
text << "\n"
|
|
5247
|
-
rescue #
|
|
5249
|
+
rescue StandardError # services info unavailable
|
|
5248
5250
|
end
|
|
5249
|
-
|
|
5251
|
+
|
|
5250
5252
|
@pR.say(text)
|
|
5251
|
-
rescue => e
|
|
5253
|
+
rescue StandardError => e # system info display failed
|
|
5252
5254
|
@pR.say("Unable to show system info\n#{e.message}".fg(196))
|
|
5253
5255
|
end
|
|
5254
5256
|
|
|
@@ -5261,7 +5263,7 @@ end
|
|
|
5261
5263
|
|
|
5262
5264
|
def navi_invoke # {{{3
|
|
5263
5265
|
@navi = `navi`
|
|
5264
|
-
rescue
|
|
5266
|
+
rescue StandardError # navi command not found
|
|
5265
5267
|
@pB.say(' navi not installed - see https://github.com/junegunn/fzf')
|
|
5266
5268
|
end
|
|
5267
5269
|
|
|
@@ -5460,7 +5462,7 @@ def get_cached_dirlist(dir, ls_options, ls_options_with_long = nil) # {{{2
|
|
|
5460
5462
|
dir_mtime = File.mtime(dir).to_i
|
|
5461
5463
|
file_count = Dir.entries(dir).size
|
|
5462
5464
|
cache_key = "#{dir}:#{ls_options_with_long}:#{dir_mtime}:#{file_count}"
|
|
5463
|
-
rescue
|
|
5465
|
+
rescue Errno::EACCES, Errno::ENOENT # permission denied or missing dir
|
|
5464
5466
|
return nil # Can't cache if we can't get mtime or file count
|
|
5465
5467
|
end
|
|
5466
5468
|
|
|
@@ -5488,7 +5490,7 @@ def get_cached_dirlist(dir, ls_options, ls_options_with_long = nil) # {{{2
|
|
|
5488
5490
|
@dir_cache.delete_if { |key, _| key.start_with?("#{dir}:") && key != cache_key }
|
|
5489
5491
|
|
|
5490
5492
|
result
|
|
5491
|
-
rescue => e
|
|
5493
|
+
rescue StandardError => e # ls command failed
|
|
5492
5494
|
# Return empty result on error
|
|
5493
5495
|
{ purels: [], colorls: [] }
|
|
5494
5496
|
end
|
|
@@ -5500,7 +5502,7 @@ def get_cached_file_metadata(file_path) # {{{2
|
|
|
5500
5502
|
begin
|
|
5501
5503
|
file_stat = File.stat(file_path)
|
|
5502
5504
|
cache_key = "#{file_path}:#{file_stat.mtime.to_i}:#{file_stat.size}"
|
|
5503
|
-
rescue
|
|
5505
|
+
rescue Errno::EACCES, Errno::ENOENT # permission denied or missing file
|
|
5504
5506
|
return nil
|
|
5505
5507
|
end
|
|
5506
5508
|
|
|
@@ -5536,7 +5538,7 @@ def get_cached_file_metadata(file_path) # {{{2
|
|
|
5536
5538
|
@metadata_cache.delete_if { |key, _| key.start_with?("#{file_path}:") && key != cache_key }
|
|
5537
5539
|
|
|
5538
5540
|
metadata
|
|
5539
|
-
rescue
|
|
5541
|
+
rescue StandardError # metadata extraction failed
|
|
5540
5542
|
nil
|
|
5541
5543
|
end
|
|
5542
5544
|
end
|
|
@@ -5701,7 +5703,7 @@ def dirlist(left: true, directory: nil) # LIST DIRECTORIES {{{2
|
|
|
5701
5703
|
pure_output = command("ls #{Shellwords.escape(dir)} #{ls_options}")
|
|
5702
5704
|
purels = pure_output.pure.split("\n")
|
|
5703
5705
|
colorls = color_output.split("\n")
|
|
5704
|
-
rescue => e
|
|
5706
|
+
rescue StandardError => e # ls command failed
|
|
5705
5707
|
purels = []
|
|
5706
5708
|
colorls = []
|
|
5707
5709
|
end
|
|
@@ -5732,7 +5734,7 @@ def dirlist(left: true, directory: nil) # LIST DIRECTORIES {{{2
|
|
|
5732
5734
|
@files = purels
|
|
5733
5735
|
# Update @selected & @fileattr for left pane
|
|
5734
5736
|
if purels[@index]
|
|
5735
|
-
@selected = Dir.pwd
|
|
5737
|
+
@selected = File.join(Dir.pwd, purels[@index])
|
|
5736
5738
|
sfile = @selected.dup
|
|
5737
5739
|
sfile += '/' if File.directory?(@selected)
|
|
5738
5740
|
time_opt = @is_macos_bsd ? '-T' : '--time-style=long-iso'
|
|
@@ -6165,7 +6167,7 @@ def command(cmd, timeout: 5, return_both: false) # {{{2
|
|
|
6165
6167
|
@pR.say(msg.fg(196))
|
|
6166
6168
|
''
|
|
6167
6169
|
end
|
|
6168
|
-
rescue => e
|
|
6170
|
+
rescue StandardError => e # command execution failed
|
|
6169
6171
|
msg = "Error: #{e.message}\n#{e.backtrace.join("\n")}\n"
|
|
6170
6172
|
if return_both
|
|
6171
6173
|
['', msg]
|
|
@@ -6241,7 +6243,7 @@ def copy_move_link(type) # COPY OR MOVE TAGGED ITEMS {{{2
|
|
|
6241
6243
|
end
|
|
6242
6244
|
|
|
6243
6245
|
@file_op_result = " #{type.capitalize} complete: #{operations.size} item(s)".fg(156)
|
|
6244
|
-
rescue => e
|
|
6246
|
+
rescue StandardError => e # file operation failed
|
|
6245
6247
|
@file_op_result = " #{type.capitalize} error: #{e.message}".fg(196)
|
|
6246
6248
|
ensure
|
|
6247
6249
|
@file_op_progress = nil
|
|
@@ -6274,7 +6276,7 @@ def copy_move_link_sync(type, items, dest_dir) # {{{3
|
|
|
6274
6276
|
operations << { source_path: item, dest_path: dest }
|
|
6275
6277
|
@pB.say(' Item(s) symlinked here.')
|
|
6276
6278
|
end
|
|
6277
|
-
rescue => e
|
|
6279
|
+
rescue StandardError => e # file operation failed
|
|
6278
6280
|
@pB.say(e.to_s)
|
|
6279
6281
|
end
|
|
6280
6282
|
end
|
|
@@ -6403,7 +6405,7 @@ def get_interactive_program(file_path) # HELPER FOR OPEN_SELECTED TO USE @intera
|
|
|
6403
6405
|
end
|
|
6404
6406
|
end
|
|
6405
6407
|
end
|
|
6406
|
-
rescue
|
|
6408
|
+
rescue StandardError # desktop file detection failed
|
|
6407
6409
|
# If detection fails, fall back to normal behavior
|
|
6408
6410
|
end
|
|
6409
6411
|
nil
|
|
@@ -6723,7 +6725,7 @@ def showcontent # SHOW CONTENTS IN THE RIGHT WINDOW {{{2
|
|
|
6723
6725
|
end
|
|
6724
6726
|
end
|
|
6725
6727
|
end
|
|
6726
|
-
rescue => e
|
|
6728
|
+
rescue StandardError => e # SVG render failed
|
|
6727
6729
|
@pR.say("Error processing SVG: #{e}")
|
|
6728
6730
|
end
|
|
6729
6731
|
when /\.(?:png|jpe?g|bmp|gif|webp|tiff?)$/i
|
|
@@ -6736,7 +6738,7 @@ def showcontent # SHOW CONTENTS IN THE RIGHT WINDOW {{{2
|
|
|
6736
6738
|
showimage(@selected)
|
|
6737
6739
|
@image = true
|
|
6738
6740
|
end
|
|
6739
|
-
rescue => e
|
|
6741
|
+
rescue Errno::EACCES, Errno::ENOENT => e # permission denied or missing image
|
|
6740
6742
|
@pR.say("Error checking image size: #{e}")
|
|
6741
6743
|
end
|
|
6742
6744
|
when /\.(?:mpg|mpeg|avi|mov|mkv|mp4|webm|flv|wmv|m4v)$/i
|
|
@@ -6765,6 +6767,7 @@ def showcontent # SHOW CONTENTS IN THE RIGHT WINDOW {{{2
|
|
|
6765
6767
|
else
|
|
6766
6768
|
# Enhanced text file preview with partial loading for large files
|
|
6767
6769
|
begin
|
|
6770
|
+
Timeout.timeout(5) do # Prevent preview from hanging
|
|
6768
6771
|
file_size = File.size(@selected)
|
|
6769
6772
|
|
|
6770
6773
|
# For text files, we can preview them partially even if large
|
|
@@ -6779,6 +6782,7 @@ def showcontent # SHOW CONTENTS IN THE RIGHT WINDOW {{{2
|
|
|
6779
6782
|
line_count = 0
|
|
6780
6783
|
|
|
6781
6784
|
file.each_line do |line|
|
|
6785
|
+
line = line[0, 10_000] + "...\n" if line.length > 10_000
|
|
6782
6786
|
lines << line
|
|
6783
6787
|
line_count += 1
|
|
6784
6788
|
break if line_count >= preview_lines
|
|
@@ -6819,25 +6823,33 @@ def showcontent # SHOW CONTENTS IN THE RIGHT WINDOW {{{2
|
|
|
6819
6823
|
else
|
|
6820
6824
|
# Small files - read entirely as before
|
|
6821
6825
|
text = File.read(@selected).force_encoding('UTF-8') rescue ''
|
|
6826
|
+
# Truncate extremely long lines to prevent UI hang
|
|
6827
|
+
has_long_lines = text.lines.any? { |l| l.length > 2_000 }
|
|
6828
|
+
if has_long_lines
|
|
6829
|
+
text = text.lines.map { |l| l.length > 2_000 ? l[0, 10_000] + "...\n" : l }.join
|
|
6830
|
+
end
|
|
6822
6831
|
if text.valid_encoding?
|
|
6823
|
-
if @batuse
|
|
6824
|
-
# Try bat
|
|
6832
|
+
if @batuse && !has_long_lines
|
|
6833
|
+
# Try bat on original file (safe, no long lines)
|
|
6825
6834
|
bat_cmd = "#{@bat} -n --color=always #{Shellwords.escape(@selected)}"
|
|
6826
|
-
bat_output = command(bat_cmd, timeout:
|
|
6835
|
+
bat_output = command(bat_cmd, timeout: 5)
|
|
6827
6836
|
if bat_output.empty?
|
|
6828
|
-
# Bat failed or returned empty - try plain cat
|
|
6829
6837
|
showcommand("cat #{Shellwords.escape(@selected)}")
|
|
6830
6838
|
else
|
|
6831
6839
|
@pR.say(bat_output)
|
|
6832
6840
|
end
|
|
6833
6841
|
else
|
|
6834
|
-
|
|
6842
|
+
# Use truncated text directly (long lines or no bat)
|
|
6843
|
+
@pR.say(text)
|
|
6835
6844
|
end
|
|
6836
6845
|
else
|
|
6837
6846
|
@pR.say("No preview available for #{@selected}")
|
|
6838
6847
|
end
|
|
6839
6848
|
end
|
|
6840
|
-
|
|
6849
|
+
end # Timeout.timeout
|
|
6850
|
+
rescue Timeout::Error
|
|
6851
|
+
@pR.say("Preview timed out (file too large or complex)")
|
|
6852
|
+
rescue StandardError => e # file preview failed
|
|
6841
6853
|
@pR.say("Error previewing file: #{e}")
|
|
6842
6854
|
end
|
|
6843
6855
|
end
|
|
@@ -6894,7 +6906,7 @@ def showimage(image) # SHOW THE SELECTED IMAGE IN THE RIGHT WINDOW {{{2
|
|
|
6894
6906
|
max_height: @pR.h - 1)
|
|
6895
6907
|
@current_image_path = img_path
|
|
6896
6908
|
end
|
|
6897
|
-
rescue => e
|
|
6909
|
+
rescue StandardError => e # image display failed
|
|
6898
6910
|
@pR.text = "Error showing image: #{e.message}"
|
|
6899
6911
|
end
|
|
6900
6912
|
end
|
|
@@ -7075,7 +7087,7 @@ loop do
|
|
|
7075
7087
|
@pT.update = @pL.update = @pR.update = @pB.update = true
|
|
7076
7088
|
refresh
|
|
7077
7089
|
end
|
|
7078
|
-
rescue; end
|
|
7090
|
+
rescue StandardError; end # terminal size query failed
|
|
7079
7091
|
end
|
|
7080
7092
|
|
|
7081
7093
|
# redraw, but ignore TTY‐focus errors
|
|
@@ -7093,7 +7105,7 @@ loop do
|
|
|
7093
7105
|
# If cwd was deleted externally, jump home
|
|
7094
7106
|
begin
|
|
7095
7107
|
Dir.pwd
|
|
7096
|
-
rescue
|
|
7108
|
+
rescue Errno::ENOENT, Errno::EACCES # cwd was deleted or became inaccessible
|
|
7097
7109
|
Dir.chdir
|
|
7098
7110
|
end
|
|
7099
7111
|
# If selected file was removed externally, force pane refresh (skip in archive/remote mode)
|
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.2
|
|
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-21 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rcurses
|