rtfm-filemanager 6.0.5 → 6.0.7
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 +293 -107
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 88ef15c96d6cd2e481ea3d0741da517dc256f7790673769457c9b78686721391
|
4
|
+
data.tar.gz: c1db40c673a60aa766fb3a79623e7ac912f0cf6898798db4d6731029cde8c7bb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7dd8b024cc288a1cb6b8fe2119dfaff80e657e16cbe34c0a0c3418943854f9a3bc9d2539031ab21b4fa1219a96fbd84e41bd24a1dff2eefd1db1b1504480e138
|
7
|
+
data.tar.gz: d4da7c1a24813ae78d768369e83decd456c4bde4e2b711d3b476bbbfd168db1e58632834a0db905bda1041cd44e63a6b8c3465b3758ae7620953dfea6e09000d
|
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 = '6.0.
|
21
|
+
@version = '6.0.7' # Fixed preview update after deletion + enhanced System Info with visual indicators
|
22
22
|
|
23
23
|
# SAVE & STORE TERMINAL {{{1
|
24
24
|
ORIG_STTY = `stty -g`.chomp
|
@@ -1413,9 +1413,25 @@ def follow_symlink # {{{3
|
|
1413
1413
|
elsif File.file?(target)
|
1414
1414
|
# If it's a file, change to the directory containing the file
|
1415
1415
|
target_dir = File.dirname(target)
|
1416
|
+
target_basename = File.basename(target)
|
1416
1417
|
Dir.chdir(target_dir)
|
1417
|
-
#
|
1418
|
-
@
|
1418
|
+
# Clear the index first to force a full refresh
|
1419
|
+
@index = 0
|
1420
|
+
@selected = nil
|
1421
|
+
# Refresh the directory listing
|
1422
|
+
dirlist
|
1423
|
+
# Find and select the target file in the new directory
|
1424
|
+
file_index = @files.index(target_basename)
|
1425
|
+
if file_index
|
1426
|
+
@index = file_index
|
1427
|
+
@selected = @files[@index]
|
1428
|
+
# Update the directory memory with the new index so it's not reset by the main loop
|
1429
|
+
@directory[Dir.pwd] = @index
|
1430
|
+
else
|
1431
|
+
# If file not found in listing (possibly filtered), still try to select it
|
1432
|
+
@selected = target_basename
|
1433
|
+
@directory[Dir.pwd] = 0
|
1434
|
+
end
|
1419
1435
|
else
|
1420
1436
|
@pB.say("Error: Symlink target does not exist or is not accessible".fg(196))
|
1421
1437
|
@symlink_history&.clear
|
@@ -3208,7 +3224,22 @@ def delete_items # {{{3
|
|
3208
3224
|
# Cannot undo permanent deletion, so don't add to undo history
|
3209
3225
|
end
|
3210
3226
|
@tagged.clear
|
3211
|
-
|
3227
|
+
|
3228
|
+
# Refresh the file list to reflect deletions
|
3229
|
+
@pL.update = true
|
3230
|
+
render # This will update @files and @selected
|
3231
|
+
|
3232
|
+
# After render, check if we still have files
|
3233
|
+
if @files.empty?
|
3234
|
+
# No files left in directory - clear the preview
|
3235
|
+
@pR.text = ""
|
3236
|
+
@pR.refresh
|
3237
|
+
else
|
3238
|
+
# Files exist - update preview for new selection
|
3239
|
+
@pR.update = true
|
3240
|
+
render # Update the preview pane
|
3241
|
+
end
|
3242
|
+
|
3212
3243
|
@pB.say("#{action} #{paths.size} items#{@trash ? " to #{TRASH_DIR}" : ''}".fg(204))
|
3213
3244
|
end
|
3214
3245
|
else
|
@@ -3617,7 +3648,6 @@ end
|
|
3617
3648
|
|
3618
3649
|
# RIGHT PANE CONTROLS {{{2
|
3619
3650
|
def refresh_right # {{{3
|
3620
|
-
render
|
3621
3651
|
@pR.full_refresh
|
3622
3652
|
@pR.update = @pB.update = true
|
3623
3653
|
end
|
@@ -3718,141 +3748,302 @@ end
|
|
3718
3748
|
|
3719
3749
|
# SYSTEM SHORTCUTS {{{2
|
3720
3750
|
def system_info # {{{3
|
3721
|
-
text = "
|
3751
|
+
text = "SYSTEM INFORMATION".b.fg(156) + " - " + Time.now.strftime("%Y-%m-%d %H:%M:%S").fg(249) + "\n"
|
3722
3752
|
text << "=" * 50 + "\n\n"
|
3723
3753
|
|
3724
3754
|
begin
|
3725
|
-
#
|
3726
|
-
text << "
|
3755
|
+
# System Overview
|
3756
|
+
text << "System Overview".fg(226).b + "\n"
|
3757
|
+
text << "─" * 20 + "\n"
|
3758
|
+
|
3759
|
+
# Hostname and uptime
|
3760
|
+
hostname = `hostname 2>/dev/null`.chomp
|
3761
|
+
uptime_raw = `uptime -p 2>/dev/null`.chomp.sub('up ', '')
|
3762
|
+
boot_time = `uptime -s 2>/dev/null`.chomp
|
3763
|
+
|
3764
|
+
text << sprintf(" %-15s %s\n", "Hostname:".fg(249), hostname.fg(156))
|
3765
|
+
text << sprintf(" %-15s %s\n", "Uptime:".fg(249), uptime_raw.fg(156))
|
3766
|
+
text << sprintf(" %-15s %s\n", "Boot time:".fg(249), boot_time.fg(156))
|
3767
|
+
|
3768
|
+
# OS Info
|
3727
3769
|
os_name = `awk -F '"' '/PRETTY/ {print $2}' /etc/os-release 2>/dev/null`.chomp
|
3728
3770
|
kernel_version = `uname -r 2>/dev/null`.chomp
|
3729
3771
|
architecture = `uname -m 2>/dev/null`.chomp
|
3730
|
-
|
3731
|
-
text << sprintf(" %-15s %s\n", "
|
3732
|
-
text << sprintf(" %-15s %s\n", "
|
3772
|
+
|
3773
|
+
text << sprintf(" %-15s %s\n", "OS:".fg(249), os_name.fg(156))
|
3774
|
+
text << sprintf(" %-15s %s\n", "Kernel:".fg(249), kernel_version.fg(156))
|
3775
|
+
text << sprintf(" %-15s %s\n", "Architecture:".fg(249), architecture.fg(156))
|
3733
3776
|
text << "\n"
|
3734
3777
|
rescue # rubocop:disable Lint/SuppressedException
|
3735
3778
|
end
|
3736
3779
|
|
3737
3780
|
begin
|
3738
|
-
# Hardware Information
|
3739
|
-
text << "Hardware
|
3781
|
+
# Hardware Information
|
3782
|
+
text << "Hardware".fg(226).b + "\n"
|
3783
|
+
text << "─" * 20 + "\n"
|
3784
|
+
|
3785
|
+
# CPU Info
|
3740
3786
|
cpu_count = `nproc 2>/dev/null`.chomp
|
3741
3787
|
cpuinfo = `lscpu 2>/dev/null`
|
3742
|
-
cpu_model = cpuinfo[/^.*Model name:\s*(.*)/, 1] || "Unknown"
|
3743
|
-
|
3744
|
-
|
3745
|
-
|
3746
|
-
|
3747
|
-
|
3748
|
-
|
3749
|
-
|
3788
|
+
cpu_model = cpuinfo[/^.*Model name:\s*(.*)/, 1]&.strip || "Unknown"
|
3789
|
+
cpu_model = cpu_model[0..45] + "..." if cpu_model.length > 48
|
3790
|
+
|
3791
|
+
# Current CPU frequency
|
3792
|
+
cpu_freq = `grep "cpu MHz" /proc/cpuinfo 2>/dev/null | head -1 | awk '{print $4}'`.chomp.to_f.round
|
3793
|
+
|
3794
|
+
# Load average
|
3795
|
+
loadavg = `cat /proc/loadavg 2>/dev/null`.chomp.split[0..2].join(' ')
|
3796
|
+
|
3797
|
+
text << sprintf(" %-15s %s\n", "CPU Model:".fg(249), cpu_model.fg(156))
|
3798
|
+
text << sprintf(" %-15s %s\n", "CPU Cores:".fg(249), "#{cpu_count} cores".fg(156))
|
3799
|
+
text << sprintf(" %-15s %s\n", "Current Freq:".fg(249), "#{cpu_freq} MHz".fg(156)) if cpu_freq > 0
|
3800
|
+
text << sprintf(" %-15s %s\n", "Load Average:".fg(249), loadavg.fg(156))
|
3801
|
+
|
3802
|
+
# Temperature if available
|
3803
|
+
if File.exist?("/sys/class/thermal/thermal_zone0/temp")
|
3804
|
+
temp = (File.read("/sys/class/thermal/thermal_zone0/temp").to_i / 1000.0).round(1)
|
3805
|
+
temp_color = temp > 80 ? 196 : temp > 60 ? 220 : 156
|
3806
|
+
text << sprintf(" %-15s %s\n", "CPU Temp:".fg(249), "#{temp}°C".fg(temp_color))
|
3750
3807
|
end
|
3808
|
+
|
3751
3809
|
text << "\n"
|
3752
3810
|
rescue # rubocop:disable Lint/SuppressedException
|
3753
3811
|
end
|
3754
3812
|
|
3755
3813
|
begin
|
3756
|
-
# Memory Information
|
3757
|
-
text << "Memory
|
3758
|
-
|
3759
|
-
|
3760
|
-
|
3761
|
-
|
3762
|
-
|
3763
|
-
|
3764
|
-
|
3765
|
-
|
3766
|
-
|
3767
|
-
|
3814
|
+
# Memory Information with visual bar
|
3815
|
+
text << "Memory".fg(226).b + "\n"
|
3816
|
+
text << "─" * 20 + "\n"
|
3817
|
+
|
3818
|
+
mem_info = `free -b 2>/dev/null | grep Mem:`
|
3819
|
+
if mem_info && !mem_info.empty?
|
3820
|
+
parts = mem_info.split
|
3821
|
+
total = parts[1].to_i
|
3822
|
+
used = parts[2].to_i
|
3823
|
+
available = parts[6].to_i
|
3824
|
+
|
3825
|
+
# Convert to human readable
|
3826
|
+
total_h = (total / 1024.0 / 1024.0 / 1024.0).round(1)
|
3827
|
+
used_h = (used / 1024.0 / 1024.0 / 1024.0).round(1)
|
3828
|
+
available_h = (available / 1024.0 / 1024.0 / 1024.0).round(1)
|
3829
|
+
percent = ((used.to_f / total) * 100).round
|
3830
|
+
|
3831
|
+
# Create visual bar (40 chars wide)
|
3832
|
+
bar_width = 40
|
3833
|
+
filled = (percent * bar_width / 100.0).round
|
3834
|
+
bar = "█" * filled + "░" * (bar_width - filled)
|
3835
|
+
|
3836
|
+
# Color based on usage
|
3837
|
+
bar_color = percent > 90 ? 196 : percent > 70 ? 220 : 156
|
3838
|
+
|
3839
|
+
# Bar first
|
3840
|
+
text << " " + bar.fg(bar_color) + " " + "#{percent}%".fg(bar_color) + "\n"
|
3841
|
+
text << sprintf(" %-15s %s\n", "Total:".fg(249), "#{total_h} GB".fg(156))
|
3842
|
+
text << sprintf(" %-15s %s\n", "Used:".fg(249), "#{used_h} GB".fg(bar_color))
|
3843
|
+
text << sprintf(" %-15s %s\n", "Available:".fg(249), "#{available_h} GB".fg(156))
|
3768
3844
|
end
|
3845
|
+
|
3846
|
+
# Swap info
|
3847
|
+
swap_info = `free -b 2>/dev/null | grep Swap:`
|
3848
|
+
if swap_info && !swap_info.empty? && swap_info.split[1].to_i > 0
|
3849
|
+
parts = swap_info.split
|
3850
|
+
swap_total = (parts[1].to_i / 1024.0 / 1024.0 / 1024.0).round(1)
|
3851
|
+
swap_used = (parts[2].to_i / 1024.0 / 1024.0 / 1024.0).round(1)
|
3852
|
+
text << sprintf(" %-15s %s\n", "Swap:".fg(249), "#{swap_used}/#{swap_total} GB".fg(156))
|
3853
|
+
end
|
3854
|
+
|
3769
3855
|
text << "\n"
|
3770
3856
|
rescue # rubocop:disable Lint/SuppressedException
|
3771
3857
|
end
|
3772
3858
|
|
3773
3859
|
begin
|
3774
|
-
#
|
3775
|
-
text << "
|
3776
|
-
|
3777
|
-
|
3778
|
-
|
3779
|
-
|
3780
|
-
|
3781
|
-
|
3782
|
-
|
3783
|
-
|
3784
|
-
|
3860
|
+
# Storage Information with visual bars
|
3861
|
+
text << "Storage".fg(226).b + "\n"
|
3862
|
+
text << "─" * 20 + "\n"
|
3863
|
+
|
3864
|
+
# Get disk usage for main filesystems only
|
3865
|
+
disk_output = `df -BG 2>/dev/null | grep -E '^/dev/' | grep -vE '/snap/|/tmp\\.| /run|/dev/loop'`
|
3866
|
+
if disk_output && !disk_output.empty?
|
3867
|
+
disk_output.lines.each do |line|
|
3868
|
+
parts = line.split
|
3869
|
+
next if parts.length < 6
|
3870
|
+
|
3871
|
+
filesystem = parts[0].sub('/dev/', '')
|
3872
|
+
size = parts[1].sub('G', '').to_i
|
3873
|
+
used = parts[2].sub('G', '').to_i
|
3874
|
+
avail = parts[3].sub('G', '').to_i
|
3875
|
+
percent = parts[4].sub('%', '').to_i
|
3876
|
+
mount = parts[5]
|
3877
|
+
|
3878
|
+
# Skip if too small
|
3879
|
+
next if size < 1
|
3880
|
+
|
3881
|
+
# Shorten mount point if needed
|
3882
|
+
mount_display = mount.length > 15 ? "...#{mount[-12..]}" : mount
|
3883
|
+
|
3884
|
+
# Mini bar (10 chars)
|
3885
|
+
bar_width = 10
|
3886
|
+
filled = (percent * bar_width / 100.0).round
|
3887
|
+
bar = "█" * filled + "░" * (bar_width - filled)
|
3888
|
+
|
3889
|
+
# Color based on usage
|
3890
|
+
color = percent > 90 ? 196 : percent > 80 ? 220 : 156
|
3891
|
+
|
3892
|
+
info = sprintf(" %-15s %3dG/%3dG %s %3d%%",
|
3893
|
+
mount_display, used, size, bar, percent)
|
3894
|
+
text << info.fg(color) + "\n"
|
3895
|
+
end
|
3896
|
+
end
|
3785
3897
|
text << "\n"
|
3786
3898
|
rescue # rubocop:disable Lint/SuppressedException
|
3787
3899
|
end
|
3788
3900
|
|
3789
3901
|
begin
|
3790
|
-
#
|
3791
|
-
text << "
|
3792
|
-
|
3793
|
-
|
3794
|
-
|
3795
|
-
|
3796
|
-
|
3797
|
-
|
3798
|
-
|
3799
|
-
|
3800
|
-
|
3801
|
-
|
3802
|
-
|
3803
|
-
|
3804
|
-
|
3805
|
-
|
3806
|
-
|
3902
|
+
# Network Information
|
3903
|
+
text << "Network".fg(226).b + "\n"
|
3904
|
+
text << "─" * 20 + "\n"
|
3905
|
+
|
3906
|
+
# Get active network interfaces
|
3907
|
+
interfaces = `ip -o link show 2>/dev/null | grep -E 'state UP|UNKNOWN' | awk '{print $2}' | sed 's/://'`.chomp.split("\n")
|
3908
|
+
|
3909
|
+
interfaces.each do |iface|
|
3910
|
+
next if iface.empty? || iface == "lo"
|
3911
|
+
|
3912
|
+
# Get IP address
|
3913
|
+
ip_addr = `ip -4 addr show #{iface} 2>/dev/null | grep -oP '(?<=inet\\s)\\d+(\\.\\d+){3}'`.chomp
|
3914
|
+
next if ip_addr.empty?
|
3915
|
+
|
3916
|
+
# Get RX/TX stats
|
3917
|
+
rx_bytes = File.read("/sys/class/net/#{iface}/statistics/rx_bytes").to_i rescue 0
|
3918
|
+
tx_bytes = File.read("/sys/class/net/#{iface}/statistics/tx_bytes").to_i rescue 0
|
3919
|
+
|
3920
|
+
rx_mb = (rx_bytes / 1024.0 / 1024.0).round(1)
|
3921
|
+
tx_mb = (tx_bytes / 1024.0 / 1024.0).round(1)
|
3922
|
+
|
3923
|
+
text << sprintf(" %-15s %s\n", "#{iface}:".fg(249), ip_addr.fg(156))
|
3924
|
+
text << sprintf(" %-15s %s\n", " Traffic:".fg(249), "↓#{rx_mb}MB ↑#{tx_mb}MB".fg(156))
|
3925
|
+
end
|
3926
|
+
|
3927
|
+
# Public IP if available (with timeout)
|
3928
|
+
begin
|
3929
|
+
require 'timeout'
|
3930
|
+
public_ip = Timeout.timeout(2) do
|
3931
|
+
`curl -s ifconfig.me 2>/dev/null`.chomp
|
3807
3932
|
end
|
3933
|
+
text << sprintf(" %-15s %s\n", "Public IP:".fg(249), public_ip.fg(156)) unless public_ip.empty?
|
3934
|
+
rescue
|
3935
|
+
# Skip public IP if timeout or error
|
3808
3936
|
end
|
3937
|
+
|
3809
3938
|
text << "\n"
|
3810
3939
|
rescue # rubocop:disable Lint/SuppressedException
|
3811
3940
|
end
|
3812
3941
|
|
3813
3942
|
begin
|
3814
|
-
#
|
3815
|
-
text << "
|
3816
|
-
|
3817
|
-
|
3818
|
-
|
3819
|
-
|
3820
|
-
|
3821
|
-
|
3822
|
-
|
3823
|
-
|
3824
|
-
|
3825
|
-
|
3943
|
+
# Environment Information
|
3944
|
+
text << "Environment".fg(226).b + "\n"
|
3945
|
+
text << "─" * 20 + "\n"
|
3946
|
+
|
3947
|
+
# Shell and terminal
|
3948
|
+
shell = ENV['SHELL']&.sub(%r{.*/}, '') || 'unknown'
|
3949
|
+
terminal = ENV['TERM'] || 'unknown'
|
3950
|
+
text << sprintf(" %-15s %s\n", "Shell:".fg(249), shell.fg(156))
|
3951
|
+
text << sprintf(" %-15s %s\n", "Terminal:".fg(249), terminal.fg(156))
|
3952
|
+
|
3953
|
+
# Package count
|
3954
|
+
if system("which dpkg >/dev/null 2>&1")
|
3955
|
+
packages = `dpkg-query -l 2>/dev/null | grep -c '^ii'`.chomp
|
3956
|
+
elsif system("which rpm >/dev/null 2>&1")
|
3957
|
+
packages = `rpm -qa 2>/dev/null | wc -l`.chomp
|
3958
|
+
elsif system("which pacman >/dev/null 2>&1")
|
3959
|
+
packages = `pacman -Q 2>/dev/null | wc -l`.chomp
|
3960
|
+
else
|
3961
|
+
packages = "unknown"
|
3962
|
+
end
|
3963
|
+
text << sprintf(" %-15s %s\n", "Packages:".fg(249), packages.fg(156))
|
3964
|
+
|
3965
|
+
# Desktop environment
|
3966
|
+
desktop = ENV['XDG_CURRENT_DESKTOP'] || ENV['DESKTOP_SESSION'] || 'none'
|
3967
|
+
text << sprintf(" %-15s %s\n", "Desktop:".fg(249), desktop.fg(156))
|
3968
|
+
|
3969
|
+
# GTK Theme if available
|
3970
|
+
if File.exist?("#{ENV['HOME']}/.config/gtk-3.0/settings.ini")
|
3971
|
+
gtk_theme = `grep gtk-theme-name ~/.config/gtk-3.0/settings.ini 2>/dev/null | cut -d= -f2`.chomp
|
3972
|
+
text << sprintf(" %-15s %s\n", "GTK Theme:".fg(249), gtk_theme.fg(156)) unless gtk_theme.empty?
|
3826
3973
|
end
|
3974
|
+
|
3827
3975
|
text << "\n"
|
3828
3976
|
rescue # rubocop:disable Lint/SuppressedException
|
3829
3977
|
end
|
3830
3978
|
|
3831
3979
|
begin
|
3832
|
-
#
|
3833
|
-
text << "
|
3834
|
-
|
3835
|
-
|
3836
|
-
|
3837
|
-
|
3838
|
-
|
3839
|
-
|
3840
|
-
|
3841
|
-
|
3842
|
-
|
3843
|
-
|
3844
|
-
|
3980
|
+
# Services & Processes
|
3981
|
+
text << "Services & Processes".fg(226).b + "\n"
|
3982
|
+
text << "─" * 20 + "\n"
|
3983
|
+
|
3984
|
+
# Running services count
|
3985
|
+
services_count = `systemctl list-units --type=service --state=running 2>/dev/null | grep -c '\.service'`.chomp
|
3986
|
+
text << sprintf(" %-15s %s\n", "Services:".fg(249), "#{services_count} running".fg(156)) unless services_count == "0"
|
3987
|
+
|
3988
|
+
# Failed services
|
3989
|
+
failed_count = `systemctl list-units --type=service --state=failed 2>/dev/null | grep -c '\.service'`.chomp
|
3990
|
+
if failed_count.to_i > 0
|
3991
|
+
text << sprintf(" %-15s %s\n", "Failed:".fg(249), "#{failed_count} service#{failed_count.to_i > 1 ? 's' : ''}".fg(196))
|
3992
|
+
# Get the actual failed services (need to parse the full output)
|
3993
|
+
failed_output = `systemctl list-units --type=service --state=failed --no-legend 2>/dev/null`.chomp
|
3994
|
+
unless failed_output.empty?
|
3995
|
+
failed_output.lines.each do |line|
|
3996
|
+
# Skip the bullet point and extract service name (second field)
|
3997
|
+
parts = line.strip.split(/\s+/)
|
3998
|
+
if parts.length >= 2
|
3999
|
+
service_name = parts[1]
|
4000
|
+
if service_name && service_name.include?('.service')
|
4001
|
+
# Shorten long service names if needed
|
4002
|
+
display_name = service_name.length > 40 ? service_name[0..37] + "..." : service_name
|
4003
|
+
text << " → #{display_name}".fg(196) + "\n"
|
4004
|
+
end
|
4005
|
+
end
|
4006
|
+
end
|
3845
4007
|
end
|
3846
|
-
else
|
3847
|
-
text << " " + "dmesg requires root access".fg(240) + "\n"
|
3848
|
-
text << " " + "Run: sudo sysctl kernel.dmesg_restrict=0".fg(240) + "\n"
|
3849
4008
|
end
|
4009
|
+
|
4010
|
+
# Process count
|
4011
|
+
proc_count = `ps aux | wc -l`.chomp.to_i - 1
|
4012
|
+
text << sprintf(" %-15s %s\n", "Processes:".fg(249), proc_count.to_s.fg(156))
|
4013
|
+
|
4014
|
+
# Users logged in
|
4015
|
+
users = `who | awk '{print $1}' | sort -u | wc -l`.chomp
|
4016
|
+
text << sprintf(" %-15s %s\n", "Users:".fg(249), "#{users} logged in".fg(156))
|
4017
|
+
|
4018
|
+
text << "\n"
|
3850
4019
|
rescue # rubocop:disable Lint/SuppressedException
|
3851
4020
|
end
|
3852
4021
|
|
4022
|
+
# Footer with system load average
|
4023
|
+
begin
|
4024
|
+
text << "─" * 50 + "\n"
|
4025
|
+
|
4026
|
+
# Get load average values
|
4027
|
+
loadavg = File.read("/proc/loadavg").split[0..2].map(&:to_f) rescue [0, 0, 0]
|
4028
|
+
cpu_count = `nproc 2>/dev/null`.chomp.to_i
|
4029
|
+
cpu_count = 1 if cpu_count == 0
|
4030
|
+
|
4031
|
+
# Format load values with color coding
|
4032
|
+
load_values = loadavg.map do |load|
|
4033
|
+
percent = (load / cpu_count * 100).round
|
4034
|
+
color = percent > 100 ? 196 : percent > 80 ? 220 : 156
|
4035
|
+
load.round(2).to_s.fg(color)
|
4036
|
+
end
|
4037
|
+
|
4038
|
+
text << "Load Average: " + load_values.join(" ") + " (1m 5m 15m)\n"
|
4039
|
+
text << "Updated: #{Time.now.strftime('%H:%M:%S')}".fg(240) + " - Press 'ENTER' to return".fg(249)
|
4040
|
+
rescue
|
4041
|
+
# Skip footer if error
|
4042
|
+
end
|
4043
|
+
|
3853
4044
|
@pR.say(text)
|
3854
|
-
rescue
|
3855
|
-
@pR.say(
|
4045
|
+
rescue => e
|
4046
|
+
@pR.say("Unable to show system info\n#{e.message}".fg(196))
|
3856
4047
|
end
|
3857
4048
|
|
3858
4049
|
def make_directory # {{{3
|
@@ -4855,26 +5046,21 @@ def open_selected(html = nil) # OPEN SELECTED FILE {{{2
|
|
4855
5046
|
end
|
4856
5047
|
# Don't try to read large files or PDFs as text for validation
|
4857
5048
|
if !@selected&.match(@pdffile) && File.size(@selected) < 1_000_000 && File.read(@selected).force_encoding('UTF-8').valid_encoding? # Pure text
|
4858
|
-
#
|
4859
|
-
|
4860
|
-
|
4861
|
-
$stdin.read_nonblock(4096)
|
4862
|
-
rescue IO::WaitReadable, EOFError
|
4863
|
-
break
|
4864
|
-
end
|
4865
|
-
end
|
4866
|
-
system("stty #{ORIG_STTY} < /dev/tty")
|
4867
|
-
# Clear to top-left
|
5049
|
+
# Save terminal state before launching editor
|
5050
|
+
system("stty -g < /dev/tty > /tmp/rtfm_stty_$$")
|
5051
|
+
# Clear and reset terminal for editor
|
4868
5052
|
system('clear < /dev/tty > /dev/tty')
|
4869
5053
|
Cursor.show
|
4870
|
-
|
5054
|
+
# Launch editor
|
5055
|
+
editor = ENV.fetch('EDITOR', 'vi')
|
4871
5056
|
system("#{editor} #{Shellwords.escape(@selected)}")
|
4872
|
-
|
4873
|
-
$
|
4874
|
-
|
4875
|
-
|
5057
|
+
# Restore terminal state
|
5058
|
+
system("stty $(cat /tmp/rtfm_stty_$$) < /dev/tty")
|
5059
|
+
system("rm -f /tmp/rtfm_stty_$$")
|
5060
|
+
# Reinitialize rcurses
|
5061
|
+
Rcurses.init!
|
4876
5062
|
Cursor.hide
|
4877
|
-
Rcurses.clear_screen
|
5063
|
+
Rcurses.clear_screen
|
4878
5064
|
refresh
|
4879
5065
|
render
|
4880
5066
|
return
|
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: 6.0.
|
4
|
+
version: 6.0.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Geir Isene
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-07-
|
11
|
+
date: 2025-07-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rcurses
|
@@ -53,8 +53,8 @@ dependencies:
|
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '7.4'
|
55
55
|
description: |-
|
56
|
-
|
57
|
-
A full featured terminal browser with syntax highlighted files, images shown in the terminal, videos thumbnailed, etc. You can bookmark and jump around easily, delete, rename, copy, symlink and move files. RTFM is one of the most feature-packed terminal file managers.
|
56
|
+
RTFM v6.0.7: Fixed preview updates after file deletion and significantly enhanced System Info display with visual indicators, environment details, and service monitoring.
|
57
|
+
A full featured terminal browser with syntax highlighted files, images shown in the terminal, videos thumbnailed, etc. Features include remote SSH/SFTP browsing, interactive SSH shell, comprehensive undo system, bookmarks, and much more. You can bookmark and jump around easily, delete, rename, copy, symlink and move files. RTFM is one of the most feature-packed terminal file managers.
|
58
58
|
email: g@isene.com
|
59
59
|
executables:
|
60
60
|
- rtfm
|