rtfm-filemanager 3.3 → 3.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +2 -6
- data/bin/rtfm +159 -214
- data/rtfm-kb.png +0 -0
- metadata +7 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fe11017b37608ece785d04b740e858ee400a3518f7ec6e2e90d318c36069d431
|
4
|
+
data.tar.gz: c1f526b4b1a347c106915e6c4e03486e1adf1464c8050e153b625f1510fa6aa7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8cb52b1a6b0d7bd0db5f76486cde99416a1a3fcb9ceee3d1e5e0cc912c6c79c567e104982e9fa32f6a8f53a7cbbe34481f72d30980e24c9a2ffc31ac544db96e
|
7
|
+
data.tar.gz: 8376fb44256d84321f755842daa76009c5e116a86024977bd1af5bc01c24915198b51c0c082f2e609cd6181ee5dfef36484a6394a376da8f08f1816ad76c5567
|
data/README.md
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# RTFM - Ruby Terminal File Manager
|
2
|
-
|
2
|
+
|
3
3
|
 [](https://badge.fury.io/rb/rtfm-filemanager)  
|
4
4
|
|
5
5
|
What other features can I cram into this file manager?
|
@@ -64,9 +64,6 @@ of the selected item (directory or file) is shown in the right pane. The right
|
|
64
64
|
pane is also used to show information such as the currently tagged items, your
|
65
65
|
(book)marks, output from commands, etc.
|
66
66
|
|
67
|
-
When you start RTFM, you can supply a directory path as an argument to let
|
68
|
-
RTFM start up in that directory.
|
69
|
-
|
70
67
|
You can run any command in the bottom "command bar" and have the output
|
71
68
|
presented in the right pane. Use LEFT and RIGHT keys to go back and forth on
|
72
69
|
the command line, HOME to beginning of line, END to end of line, Backspace or
|
@@ -263,9 +260,8 @@ B | Toggle border
|
|
263
260
|
y | Copy path of selected item to primary selection (for pasting with middle mouse button)
|
264
261
|
Y | Copy path of selected item to clipboard
|
265
262
|
Ctrl-y | Copy content of right pane to clipboard
|
266
|
-
Ctrl-d | Create a new directory (a shortcut for ":mkdir ")
|
267
|
-
Ctrl-n | Invoke navi (see https://github.com/denisidoro/navi) with any output in right pane
|
268
263
|
S | Show comprehensive system info (system, CPU, filesystem, latest dmesg messages)
|
264
|
+
Ctrl-n | Invoke navi (see https://github.com/denisidoro/navi) with any output in right pane
|
269
265
|
|
270
266
|
## Keyboard cheat sheet
|
271
267
|

|
data/bin/rtfm
CHANGED
@@ -14,7 +14,7 @@
|
|
14
14
|
# for any damages resulting from its use. Further, I am under no
|
15
15
|
# obligation to maintain or extend this software. It is provided
|
16
16
|
# on an 'as is' basis without any expressed or implied warranty.
|
17
|
-
@version = "3.
|
17
|
+
@version = "3.5"
|
18
18
|
|
19
19
|
# PRELIMINARIES
|
20
20
|
@help = <<HELPTEXT
|
@@ -111,11 +111,10 @@ ADDITIONAL COMMANDS
|
|
111
111
|
y = Copy path of selected item to primary selection (for pasting with middle mouse button)
|
112
112
|
Y = Copy path of selected item to clipboard
|
113
113
|
Ctrl-y = Copy content of right pane to clipboard
|
114
|
-
Ctrl-d = Create a new directory (a shortcut for ":mkdir ")
|
115
|
-
Ctrl-n = Invoke navi (see https://github.com/denisidoro/navi) with any output in right window
|
116
114
|
S = Show comprehensive System info (system, CPU, filesystem, latest dmesg messages)
|
115
|
+
Ctrl-n = Invoke navi (see https://github.com/denisidoro/navi) with any output in right window
|
117
116
|
|
118
|
-
COPYRIGHT: Geir Isene, 2020-
|
117
|
+
COPYRIGHT: Geir Isene, 2020-3. No rights reserved. See http://isene.com for more.
|
119
118
|
HELPTEXT
|
120
119
|
def firstrun
|
121
120
|
@firstrun = <<~FIRSTRUN
|
@@ -143,38 +142,9 @@ def firstrun
|
|
143
142
|
|
144
143
|
FIRSTRUN
|
145
144
|
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
@rtfmlaunch = <<RTFMFISHLAUNCH
|
150
|
-
# This is the RTFM launcher (https://github.com/isene/RTFM) for fish
|
151
|
-
function r {
|
152
|
-
f=$(mktemp)
|
153
|
-
(
|
154
|
-
set +e
|
155
|
-
rtfm "$f"
|
156
|
-
code=$?
|
157
|
-
if [ "$code" != 0 ]; then
|
158
|
-
rm -f "$f"
|
159
|
-
exit "$code"
|
160
|
-
fi
|
161
|
-
)
|
162
|
-
code=$?
|
163
|
-
if [ "$code" != 0 ]; then
|
164
|
-
return "$code"
|
165
|
-
fi
|
166
|
-
d=$(<"$f")
|
167
|
-
rm -f "$f"
|
168
|
-
cd "$d"
|
169
|
-
}
|
170
|
-
RTFMFISHLAUNCH
|
171
|
-
File.write(Dir.home+'/.config/fish/config.fish', @rtfmlaunch)
|
172
|
-
`echo "source ~/.config/fish/config.fish" >> .#{@shell}rc`
|
173
|
-
end
|
174
|
-
else
|
175
|
-
if not File.exist?(Dir.home+'/.rtfm.launch')
|
176
|
-
@rtfmlaunch = <<RTFMLAUNCH
|
177
|
-
# This is the RTFM launcher (https://github.com/isene/RTFM) for bash/zsh
|
145
|
+
if not File.exist?(Dir.home+'/.rtfm.launch')
|
146
|
+
@rtfmlaunch = <<RTFMLAUNCH
|
147
|
+
# This is the RTFM launcher (https://github.com/isene/RTFM)
|
178
148
|
function r {
|
179
149
|
f=$(mktemp)
|
180
150
|
(
|
@@ -195,19 +165,18 @@ function r {
|
|
195
165
|
cd "$d"
|
196
166
|
}
|
197
167
|
RTFMLAUNCH
|
198
|
-
|
199
|
-
|
200
|
-
|
168
|
+
File.write(Dir.home+'/.rtfm.launch', @rtfmlaunch)
|
169
|
+
@shell = File.basename(`echo "$SHELL"`.chomp)
|
170
|
+
`echo "source ~/.rtfm.launch" >> .#{@shell}rc`
|
201
171
|
end
|
202
172
|
|
203
173
|
puts @firstrun
|
204
174
|
puts "\n... hit ENTER to start RTFM. Hit ? inside RTFM to show the help text. Enjoy :-)"
|
205
|
-
|
175
|
+
STDIN.gets
|
206
176
|
end
|
207
177
|
begin # BASIC SETUP
|
208
178
|
require 'fileutils'
|
209
179
|
require 'io/console'
|
210
|
-
require 'io/wait'
|
211
180
|
require 'date'
|
212
181
|
require 'timeout'
|
213
182
|
require 'curses'
|
@@ -229,7 +198,8 @@ begin # BASIC SETUP
|
|
229
198
|
|
230
199
|
cmd?('bat') ? @bat = "bat" : @bat = "batcat"
|
231
200
|
|
232
|
-
|
201
|
+
STDIN.set_encoding(Encoding::UTF_8) # Set encoding for STDIN
|
202
|
+
LScolors = `echo $LS_COLORS` # Import LS_COLORS
|
233
203
|
|
234
204
|
## Curses setup
|
235
205
|
Curses.init_screen
|
@@ -241,52 +211,48 @@ begin # BASIC SETUP
|
|
241
211
|
|
242
212
|
# INITIALIZE VARIABLES
|
243
213
|
## These can be set by user in .rtfm.conf
|
244
|
-
@lsbase
|
245
|
-
@lslong
|
246
|
-
@lsall
|
247
|
-
@lsorder
|
248
|
-
@lsinvert
|
249
|
-
@lsuser
|
250
|
-
@width
|
251
|
-
@history
|
252
|
-
@
|
253
|
-
@
|
254
|
-
@
|
255
|
-
@
|
256
|
-
@batuse = true # Use batcat for syntax highlighting
|
257
|
-
@aimodel = "gpt-3.5-turbo-instruct" # The default OpenAI model, set another in .rtfm.conf if you like
|
214
|
+
@lsbase = "--group-directories-first" # Basic ls setup
|
215
|
+
@lslong = false # Set short form ls (toggled by pressing "l")
|
216
|
+
@lsall = "" # Set "ls -a" to false (toggled by pressing "a" - sets it to "-a")
|
217
|
+
@lsorder = "" # Change the order/sorting by pressing 'o' (circular toggle)
|
218
|
+
@lsinvert = "" # Set to "-r" to reverse/invert sorting order
|
219
|
+
@lsuser = "" # Set this variable in .rtfm.conf to any 'ls' switch you want to customize directory listings
|
220
|
+
@width = 4 # Set width of the left pane to the default ⅓ of the terminal width
|
221
|
+
@history = [] # Initialize the command line history array
|
222
|
+
@border = false
|
223
|
+
@preview = true
|
224
|
+
@runmailcap = false # Set to 'true' in .rtfm.conf if you want to use run-mailcap instead of xdg-open
|
225
|
+
@batuse = true # Use batcat for syntax highlighting
|
258
226
|
## These are automatically written on exit
|
259
|
-
@marks
|
260
|
-
@hash
|
261
|
-
@tagged
|
227
|
+
@marks = {} # Initialize (book)marks hash
|
228
|
+
@hash = {} # Initialize the sha directory hashing
|
229
|
+
@tagged = [] # Initialize the tagged array - for collecting all tagged items
|
262
230
|
## These should not be set by user in .rtfm.conf
|
263
|
-
@directory
|
264
|
-
@searched
|
265
|
-
@lsfiles
|
266
|
-
@lsmatch
|
267
|
-
@index
|
268
|
-
@cont
|
269
|
-
@tagsize
|
270
|
-
@navi
|
271
|
-
@marks["'"]
|
231
|
+
@directory = {} # Initialize the directory hash for remembering directories visited
|
232
|
+
@searched = "" # Initialize the active searched for items
|
233
|
+
@lsfiles = "" # File types to show (initially set to all file types) - not saved on exit
|
234
|
+
@lsmatch = "" # Files to match (initially set to matching all files) - not saved on exit
|
235
|
+
@index = 0 # Set chosen item to first on startup
|
236
|
+
@cont = ""
|
237
|
+
@tagsize = 0
|
238
|
+
@navi = ""
|
239
|
+
@marks["'"] = Dir.pwd
|
272
240
|
## File type recognizers
|
273
|
-
@imagefile
|
274
|
-
@pptfile
|
275
|
-
@xlsfile
|
276
|
-
@docfile
|
277
|
-
@docxfile
|
278
|
-
@xlsxfile
|
279
|
-
@pptxfile
|
280
|
-
@oolofile
|
281
|
-
@pdffile
|
241
|
+
@imagefile = /\.jpg$|\.JPG$|\.jpeg$|\.png$|\.bmp$|\.gif$|\.tif$|\.tiff$/
|
242
|
+
@pptfile = /\.ppt$/
|
243
|
+
@xlsfile = /\.xls$/
|
244
|
+
@docfile = /\.doc$/
|
245
|
+
@docxfile = /\.docx$/
|
246
|
+
@xlsxfile = /\.xlsx$/
|
247
|
+
@pptxfile = /\.pptx$/
|
248
|
+
@oolofile = /\.odt$|\.odc$|\.odp$|\.odg$/
|
249
|
+
@pdffile = /\.pdf$|\.ps$/
|
282
250
|
## Get variables from config file (written back to .rtf.conf upon exit via 'q')
|
283
251
|
if File.exist?(Dir.home+'/.rtfm.conf')
|
284
252
|
load(Dir.home+'/.rtfm.conf')
|
285
253
|
end
|
286
|
-
Dir.chdir(ARGV[0]) if ARGV[0] and Dir.exist?(ARGV[0]) and ARGV[0] !~ /\/tmp/
|
287
254
|
end
|
288
|
-
# CLASS
|
289
|
-
class Curses::Window
|
255
|
+
class Curses::Window # CLASS EXTENSION
|
290
256
|
attr_accessor :fg, :bg, :attr, :text, :update, :pager, :pager_more, :pager_cmd, :locate, :nohistory
|
291
257
|
# General extensions (see https://github.com/isene/Ruby-Curses-Class-Extension)
|
292
258
|
def clr
|
@@ -316,6 +282,16 @@ class Curses::Window
|
|
316
282
|
# RTFM specific extensions
|
317
283
|
end
|
318
284
|
# GENERIC FUNCTIONS
|
285
|
+
def get_ls_color(type) # GET THE COLOR FOR THE FILETYPE FROM IMPORTED LS_COLORS
|
286
|
+
bold = 0
|
287
|
+
begin
|
288
|
+
color = LScolors.match(/#{type}=\d*;\d*;(\d*)/)[1]
|
289
|
+
bold = 1 if LScolors.match(/#{type}=\d*;\d*;\d*;1/)
|
290
|
+
rescue
|
291
|
+
color = 7 # Default color
|
292
|
+
end
|
293
|
+
return color.to_i, bold
|
294
|
+
end
|
319
295
|
def syntax_highlight(input) # SYNTAX HIGHLIGHTING FROM ANSI COLOR CODES
|
320
296
|
color_ary = color_parse(input)
|
321
297
|
color_ary.each do | pair |
|
@@ -332,15 +308,13 @@ def syntax_highlight(input) # SYNTAX HIGHLIGHTING FROM ANSI COLOR CODES
|
|
332
308
|
end
|
333
309
|
end
|
334
310
|
def color_parse(input) # PARSE ANSI COLOR SEQUENCES
|
335
|
-
input.gsub!(/\e\[\d;38;5;(\d+);*(\d*)m/, '¤¤\1¤¤\2¤¤')
|
336
|
-
input.gsub!(/\e\[38;5;(\d+);*(\d*)m/, '¤¤\1¤¤\2¤¤')
|
337
|
-
input.gsub!(/\e\[\d;38;2;(\d+);*(\d*);\d*m/, '¤¤\1¤¤\2¤¤')
|
338
|
-
input.gsub!(/\e\[38;2;(\d+);*(\d*);\d*m/, '¤¤\1¤¤\2¤¤')
|
339
|
-
input.gsub!(/\e\[
|
340
|
-
input.gsub!(/\e\[0m/, "")
|
311
|
+
input.gsub!( /\e\[\d;38;5;(\d+);*(\d*)m/, '¤¤\1¤¤\2¤¤')
|
312
|
+
input.gsub!( /\e\[38;5;(\d+);*(\d*)m/, '¤¤\1¤¤\2¤¤')
|
313
|
+
input.gsub!( /\e\[\d;38;2;(\d+);*(\d*);\d*m/, '¤¤\1¤¤\2¤¤')
|
314
|
+
input.gsub!( /\e\[38;2;(\d+);*(\d*);\d*m/, '¤¤\1¤¤\2¤¤')
|
315
|
+
input.gsub!( /\e\[0m/, "\t")
|
341
316
|
color_array = input.split("¤¤")
|
342
317
|
color_array = color_array.drop(1)
|
343
|
-
#color_array.map! { |x| x || 0 }
|
344
318
|
output = color_array.each_slice(3).to_a
|
345
319
|
return output
|
346
320
|
end
|
@@ -348,10 +322,9 @@ def getchr # PROCESS KEY PRESSES
|
|
348
322
|
# Note: Curses.getch blanks out @w_t
|
349
323
|
# @w_l.getch makes Curses::KEY_DOWN etc not work
|
350
324
|
# Therefore resorting to the generic method
|
351
|
-
c =
|
325
|
+
c = STDIN.getch(min: 0, time: 3)
|
352
326
|
case c
|
353
327
|
when "\e" # ANSI escape sequences
|
354
|
-
return "ESC" if $stdin.ready? == nil
|
355
328
|
case $stdin.getc
|
356
329
|
when '[' # CSI
|
357
330
|
case $stdin.getc
|
@@ -360,13 +333,12 @@ def getchr # PROCESS KEY PRESSES
|
|
360
333
|
when 'C' then chr = "RIGHT"
|
361
334
|
when 'D' then chr = "LEFT"
|
362
335
|
when 'Z' then chr = "S-TAB"
|
363
|
-
when '2' then chr = "INS" ; chr = "C-INS" if
|
364
|
-
when '3' then chr = "DEL" ; chr = "C-DEL" if
|
365
|
-
when '5' then chr = "PgUP" ; chr = "C-PgUP" if
|
366
|
-
when '6' then chr = "PgDOWN" ; chr = "C-PgDOWN" if
|
367
|
-
when '7' then chr = "HOME" ; chr = "C-HOME" if
|
368
|
-
when '8' then chr = "END" ; chr = "C-END" if
|
369
|
-
else chr = ""
|
336
|
+
when '2' then chr = "INS" ; chr = "C-INS" if STDIN.getc == "^"
|
337
|
+
when '3' then chr = "DEL" ; chr = "C-DEL" if STDIN.getc == "^"
|
338
|
+
when '5' then chr = "PgUP" ; chr = "C-PgUP" if STDIN.getc == "^"
|
339
|
+
when '6' then chr = "PgDOWN" ; chr = "C-PgDOWN" if STDIN.getc == "^"
|
340
|
+
when '7' then chr = "HOME" ; chr = "C-HOME" if STDIN.getc == "^"
|
341
|
+
when '8' then chr = "END" ; chr = "C-END" if STDIN.getc == "^"
|
370
342
|
end
|
371
343
|
when 'O' # Set Ctrl+ArrowKey equal to ArrowKey; May be used for other purposes in the future
|
372
344
|
case $stdin.getc
|
@@ -374,29 +346,22 @@ def getchr # PROCESS KEY PRESSES
|
|
374
346
|
when 'b' then chr = "C-DOWN"
|
375
347
|
when 'c' then chr = "C-RIGHT"
|
376
348
|
when 'd' then chr = "C-LEFT"
|
377
|
-
else chr = ""
|
378
349
|
end
|
379
350
|
end
|
380
351
|
when "", "" then chr = "BACK"
|
381
|
-
when "
|
382
|
-
when "
|
383
|
-
when "" then chr = "C-E"
|
352
|
+
when "" then chr = "WBACK"
|
353
|
+
when "" then chr = "LDEL"
|
384
354
|
when "" then chr = "C-G"
|
385
|
-
when "" then chr = "C-K"
|
386
355
|
when "" then chr = "C-L"
|
387
356
|
when "" then chr = "C-N"
|
388
357
|
when "" then chr = "C-O"
|
389
358
|
when "" then chr = "C-P"
|
390
359
|
when "" then chr = "C-T"
|
391
360
|
when "" then chr = "C-Y"
|
392
|
-
when "" then chr = "WBACK"
|
393
|
-
when "" then chr = "LDEL"
|
394
361
|
when "\r" then chr = "ENTER"
|
395
362
|
when "\t" then chr = "TAB"
|
396
|
-
when
|
397
|
-
else chr = ""
|
363
|
+
when /./ then chr = c
|
398
364
|
end
|
399
|
-
#stdin_clear
|
400
365
|
return chr
|
401
366
|
end
|
402
367
|
def main_getkey # GET KEY FROM USER
|
@@ -489,11 +454,11 @@ def main_getkey # GET KEY FROM USER
|
|
489
454
|
# JUMPING AND MARKS
|
490
455
|
when 'm' # Set mark
|
491
456
|
marks_info
|
492
|
-
m =
|
457
|
+
m = STDIN.getc
|
493
458
|
if m.match(/[\w']/)
|
494
459
|
@marks[m] = Dir.pwd
|
495
460
|
elsif m == "-"
|
496
|
-
r =
|
461
|
+
r = STDIN.getc
|
497
462
|
@marks.delete(r)
|
498
463
|
end
|
499
464
|
marks_info
|
@@ -648,7 +613,7 @@ def main_getkey # GET KEY FROM USER
|
|
648
613
|
@tagged.push("\"#{Dir.pwd}/#{@selected}\"")
|
649
614
|
@tagged.uniq!
|
650
615
|
deletes = @tagged.join(" ")
|
651
|
-
if
|
616
|
+
if STDIN.getc == 'y'
|
652
617
|
`rm -rf #{deletes} 2>/dev/null`
|
653
618
|
items_number = @tagged.length
|
654
619
|
@tagged = []
|
@@ -907,9 +872,6 @@ def main_getkey # GET KEY FROM USER
|
|
907
872
|
system("echo -n '#{@cont}' | #{clip}")
|
908
873
|
when 'S' # Show comprehensive system info
|
909
874
|
sysinfo
|
910
|
-
when 'C-D' # Create new directory (shortcut for ":mkdir ")
|
911
|
-
cmd = w_b_getstr(": ", "mkdir ")
|
912
|
-
w_b_exec(cmd + " -p")
|
913
875
|
when 'C-N' # navi integration (https://github.com/denisidoro/navi)
|
914
876
|
begin
|
915
877
|
@navi = `navi`
|
@@ -919,7 +881,7 @@ def main_getkey # GET KEY FROM USER
|
|
919
881
|
@break = true
|
920
882
|
when '@' # Enter "Ruby debug"
|
921
883
|
@w_b.nohistory = false
|
922
|
-
cmd = w_b_getstr("◆ ", ""
|
884
|
+
cmd = w_b_getstr("◆ ", "")
|
923
885
|
@w_b.clr
|
924
886
|
@w_b.refresh
|
925
887
|
@w_b.update = true
|
@@ -927,8 +889,8 @@ def main_getkey # GET KEY FROM USER
|
|
927
889
|
info = "Command: #{cmd}\n\n"
|
928
890
|
begin
|
929
891
|
info += eval(cmd).to_s
|
930
|
-
rescue
|
931
|
-
info += "Error: #{
|
892
|
+
rescue StandardError => e
|
893
|
+
info += "Error: #{e.inspect}"
|
932
894
|
end
|
933
895
|
w_r_info(info)
|
934
896
|
@w_r.update = false
|
@@ -943,12 +905,6 @@ def main_getkey # GET KEY FROM USER
|
|
943
905
|
rescue
|
944
906
|
end
|
945
907
|
end
|
946
|
-
def stdin_clear
|
947
|
-
begin
|
948
|
-
$stdin.getc while $stdin.ready?
|
949
|
-
rescue
|
950
|
-
end
|
951
|
-
end
|
952
908
|
def conf_write
|
953
909
|
if File.exist?(Dir.home+'/.rtfm.conf')
|
954
910
|
conf = File.read(Dir.home+'/.rtfm.conf')
|
@@ -961,10 +917,6 @@ def conf_write
|
|
961
917
|
conf += "@hash = #{@hash}\n"
|
962
918
|
conf.sub!(/^@tagged.*\[.*\]\n/, "")
|
963
919
|
conf += "@tagged = #{@tagged}\n"
|
964
|
-
conf.sub!(/^@history.*\[.*\]\n/, "")
|
965
|
-
conf += "@history = #{@history}\n"
|
966
|
-
conf.sub!(/^@rubyhistory.*\[.*\]\n/, "")
|
967
|
-
conf += "@rubyhistory = #{@rubyhistory}\n"
|
968
920
|
if @write_conf_all
|
969
921
|
conf.sub!(/^@lslong.*\n/, "")
|
970
922
|
conf += "@lslong = #{@lslong}\n"
|
@@ -1008,8 +960,7 @@ end
|
|
1008
960
|
def get_files(win) # The core of the directory listings
|
1009
961
|
ls_cmd = "ls 2>/dev/null #{@lsbase} #{@lsall} #{@lsorder} #{@lsinvert} #{@lsuser}" # Get files in current directory
|
1010
962
|
ls_cmd += @selected_safe if win == "right"
|
1011
|
-
@
|
1012
|
-
@files = @cfiles.map {|f| f.sub(/^.*\d+m(.+)\e\[0m/, '\1')}
|
963
|
+
@files = `#{ls_cmd}`.split("\n")
|
1013
964
|
ls_cmd += " -H " if win == "right"
|
1014
965
|
ls_cmd += %q[ -lh --time-style="long-iso" | awk '{printf "%s%s%s%11s%6s%6s", $1, " " $3, ":" $4,$6,$7,$5"\n"}']
|
1015
966
|
@fspes = `#{ls_cmd}`.split("\n").drop(1)
|
@@ -1076,8 +1027,7 @@ def list_dir(active) # LIST CONTENT OF A DIRECTORY (BOTH active AND RIGHT WINDOW
|
|
1076
1027
|
@cont = ""
|
1077
1028
|
end
|
1078
1029
|
while ix < @files.size and t < win.maxy do
|
1079
|
-
str
|
1080
|
-
cstr = @cfiles[ix]
|
1030
|
+
str = @files[ix]
|
1081
1031
|
active ? str_path = str : str_path = "#{@selected}/#{str}"
|
1082
1032
|
begin # Add items matching @tag to @tagged
|
1083
1033
|
if str.match(/#{@tag}/) and @tag != false
|
@@ -1086,9 +1036,25 @@ def list_dir(active) # LIST CONTENT OF A DIRECTORY (BOTH active AND RIGHT WINDOW
|
|
1086
1036
|
end
|
1087
1037
|
rescue
|
1088
1038
|
end
|
1039
|
+
# Determine the filetype of the item
|
1040
|
+
ftype = ""
|
1041
|
+
ftype = str.match(/\.([^.]*$)/)[1] if str.match?(/\.([^.]*$)/)
|
1042
|
+
# Set special filetypes (sequence matters)
|
1043
|
+
ftype = "bd" if File.blockdev?(str_path)
|
1044
|
+
ftype = "cd" if File.chardev?(str_path)
|
1045
|
+
ftype = "pi" if File.pipe?(str_path)
|
1046
|
+
ftype = "st" if File.sticky?(str_path)
|
1047
|
+
ftype = "so" if File.socket?(str_path)
|
1048
|
+
ftype = "ex" if File.executable?(str_path)
|
1049
|
+
ftype = "di" if File.directory?(str_path)
|
1050
|
+
ftype = "ln" if File.symlink?(str_path)
|
1051
|
+
begin
|
1052
|
+
File.stat(str_path) # Checking if not an orphaned link
|
1053
|
+
rescue
|
1054
|
+
ftype = "or" # Set to orphant if no link target
|
1055
|
+
end
|
1089
1056
|
fg = 7; bold = 0; bg = 0 # Set default color
|
1090
|
-
|
1091
|
-
fg, bold = fl[0][0].to_i, fl[0][1].to_i unless fl[0] == nil
|
1057
|
+
fg, bold = get_ls_color(ftype) unless ftype == "" # Color from LS_COLORS
|
1092
1058
|
init_pair(fg, fg, bg)
|
1093
1059
|
file_marker = color_pair(fg)
|
1094
1060
|
file_marker = file_marker | Curses::A_BOLD if bold == 1
|
@@ -1110,8 +1076,6 @@ def list_dir(active) # LIST CONTENT OF A DIRECTORY (BOTH active AND RIGHT WINDOW
|
|
1110
1076
|
ext_name = File.extname(str)
|
1111
1077
|
ext_length = ext_name.length
|
1112
1078
|
nbl = win.maxx - 5 - ext_length # nbl: new_base_length
|
1113
|
-
nbl -= 1 if dir != "" # Account for one extra character
|
1114
|
-
nbl -= 1 if link != "" # Account for one extra character
|
1115
1079
|
str = base_name[0..nbl] + "…" + ext_name
|
1116
1080
|
end
|
1117
1081
|
if !active and ix == win.maxy - 1 # Add indicator of more at bottom @w_r list
|
@@ -1123,7 +1087,7 @@ def list_dir(active) # LIST CONTENT OF A DIRECTORY (BOTH active AND RIGHT WINDOW
|
|
1123
1087
|
win.attron(file_marker) { win << str } # Implement color/bold to the item
|
1124
1088
|
win.clrtoeol
|
1125
1089
|
win << "\n"
|
1126
|
-
ix += 1; t
|
1090
|
+
ix += 1; t += 1
|
1127
1091
|
end
|
1128
1092
|
(win.maxy - win.cury).times {win.deleteln()} # Clear to bottom of window
|
1129
1093
|
if active
|
@@ -1150,14 +1114,12 @@ def open_selected(html = nil) # OPEN SELECTED ITEM (when pressing RIGHT)
|
|
1150
1114
|
if File.read(@selected).force_encoding("UTF-8").valid_encoding? and not html
|
1151
1115
|
system("exec $EDITOR #{@selected_safe}")
|
1152
1116
|
else
|
1153
|
-
|
1154
|
-
|
1155
|
-
|
1156
|
-
|
1157
|
-
|
1158
|
-
system("xdg-open #{@selected_safe} 2>/dev/null")
|
1117
|
+
if @runmailcap
|
1118
|
+
Thread.new { system("run-mailcap #{@selected_safe} 2>/dev/null") }
|
1119
|
+
else
|
1120
|
+
Thread.new { system("xdg-open #{@selected_safe} 2>/dev/null") }
|
1121
|
+
end
|
1159
1122
|
end
|
1160
|
-
end
|
1161
1123
|
@break = true
|
1162
1124
|
rescue
|
1163
1125
|
end
|
@@ -1185,7 +1147,7 @@ def copy_move_link(type) # COPY OR MOVE TAGGED ITEMS (COPY IF "keep == true")
|
|
1185
1147
|
FileUtils.ln_s(item, dest)
|
1186
1148
|
w_b_info(" Item(s) symlinked here.")
|
1187
1149
|
end
|
1188
|
-
rescue
|
1150
|
+
rescue StandardError => err
|
1189
1151
|
w_b_info(err.to_s)
|
1190
1152
|
end
|
1191
1153
|
end
|
@@ -1279,19 +1241,16 @@ def w_r_doc # GET FULL CONTENT TO PAGE
|
|
1279
1241
|
@w_r << @w_r.text
|
1280
1242
|
end
|
1281
1243
|
def w_r_info(info) # SHOW INFO IN THE RIGHT WINDOW
|
1282
|
-
|
1283
|
-
|
1284
|
-
|
1285
|
-
|
1286
|
-
|
1287
|
-
|
1288
|
-
|
1289
|
-
|
1290
|
-
|
1291
|
-
|
1292
|
-
@w_r.update = false
|
1293
|
-
rescue
|
1294
|
-
end
|
1244
|
+
image_show("clear") if @image; @image = false
|
1245
|
+
@w_r.clr
|
1246
|
+
@w_r.refresh
|
1247
|
+
w_r_width = Curses.cols - (Curses.cols * @width / 10) - 2
|
1248
|
+
info.gsub!(/(.{1,#{w_r_width}})( +|$\n?)|(.{1,#{w_r_width}})/, "\\1\\3\n")
|
1249
|
+
@w_r.text = info
|
1250
|
+
@w_r.pager_cmd = ""
|
1251
|
+
pager_start
|
1252
|
+
pager_show
|
1253
|
+
@w_r.update = false
|
1295
1254
|
end
|
1296
1255
|
def marks_info # SHOW MARKS IN RIGHT WINDOW
|
1297
1256
|
@w_r.fg = 183
|
@@ -1415,13 +1374,11 @@ def openai # INTERFACE TO OPENAI
|
|
1415
1374
|
p += "#{f}? "
|
1416
1375
|
p += "Give a brief summary of its content: " + c unless File.directory?(@selected) and c == ""
|
1417
1376
|
|
1418
|
-
|
1419
|
-
|
1377
|
+
response = client.completions( parameters: { model: "text-davinci-003", prompt: p, max_tokens: 200 })
|
1378
|
+
if response["error"]["message"] == ""
|
1420
1379
|
text = "OpenAI description:\n" + response["choices"][0]["text"]
|
1421
|
-
|
1422
|
-
text
|
1423
|
-
text += "Check your connection and @ai secret key (in .rtfm.conf).\n\n"
|
1424
|
-
text += response.to_s
|
1380
|
+
else
|
1381
|
+
text = response["error"]["message"]
|
1425
1382
|
end
|
1426
1383
|
|
1427
1384
|
@w_r.fg = 229
|
@@ -1450,8 +1407,8 @@ def sysinfo
|
|
1450
1407
|
cpu = "CPUs = " + `nproc`.chop + " "
|
1451
1408
|
cpuinfo = `lscpu`
|
1452
1409
|
cpu += cpuinfo[/^.*Model name:\s*(.*)/, 1] + " "
|
1453
|
-
cpu += "Max: " + cpuinfo[/^.*CPU max MHz:\s*(.*)/, 1]
|
1454
|
-
cpu += "Min: " + cpuinfo[/^.*CPU min MHz:\s*(.*)/, 1]
|
1410
|
+
cpu += "Max: " + cpuinfo[/^.*CPU max MHz:\s*(.*)/, 1][/(.*),.*/, 1] + "MHz "
|
1411
|
+
cpu += "Min: " + cpuinfo[/^.*CPU min MHz:\s*(.*)/, 1][/(.*),.*/, 1] + "MHz\n\n"
|
1455
1412
|
text += [[154, 0, cpu]]
|
1456
1413
|
mem = `free -h` + "\n"
|
1457
1414
|
text += [[229, 0, mem]]
|
@@ -1460,8 +1417,7 @@ def sysinfo
|
|
1460
1417
|
disk = `df -H | head -8`
|
1461
1418
|
text += [[172, 0, disk]]
|
1462
1419
|
dmesg = "\nDMESG (latest first):\n"
|
1463
|
-
|
1464
|
-
dcmd != "" ? dmesg += dcmd : dmesg += "dmesg requires root, run 'sudo sysctl kernel.dmesg_restrict=0' if you need permission\n"
|
1420
|
+
dmesg += `dmesg | tail -6`.split("\n").sort.reverse.join("\n")
|
1465
1421
|
text += [[219, 0, dmesg]]
|
1466
1422
|
w_r_info(ansifix(text))
|
1467
1423
|
rescue
|
@@ -1489,29 +1445,23 @@ def w_b_info(info) # SHOW INFO IN @W_B
|
|
1489
1445
|
@w_b.write
|
1490
1446
|
@w_b.update = false
|
1491
1447
|
end
|
1492
|
-
def w_b_getstr(pretext, text
|
1448
|
+
def w_b_getstr(pretext, text) # A SIMPLE READLINE-LIKE ROUTINE
|
1493
1449
|
Curses.curs_set(1)
|
1494
1450
|
Curses.echo
|
1495
1451
|
stk = 0
|
1452
|
+
@history.insert(stk, text)
|
1453
|
+
pos = @history[stk].length
|
1496
1454
|
chr = ""
|
1497
|
-
if ruby
|
1498
|
-
@rubyhistory.insert(stk, text)
|
1499
|
-
@history_copy = @rubyhistory.map(&:clone)
|
1500
|
-
else
|
1501
|
-
@history.insert(stk, text)
|
1502
|
-
@history_copy = @history.map(&:clone)
|
1503
|
-
end
|
1504
|
-
pos = @history_copy[stk].length
|
1505
1455
|
while chr != "ENTER"
|
1506
1456
|
@w_b.setpos(0,0)
|
1507
1457
|
init_pair(250, 250, 238)
|
1508
|
-
text = pretext + @
|
1458
|
+
text = pretext + @history[stk]
|
1509
1459
|
text += " " * (@w_b.maxx - text.length) if text.length < @w_b.maxx
|
1510
1460
|
@w_b.attron(color_pair(250)) { @w_b << text }
|
1511
1461
|
@w_b.setpos(0,pretext.length + pos)
|
1512
1462
|
@w_b.refresh
|
1513
1463
|
chr = getchr
|
1514
|
-
if chr ==
|
1464
|
+
if chr == "C-G"
|
1515
1465
|
Curses.curs_set(0)
|
1516
1466
|
Curses.noecho
|
1517
1467
|
@w_b.update = true
|
@@ -1520,50 +1470,50 @@ def w_b_getstr(pretext, text, ruby=false) # A SIMPLE READLINE-LIKE ROUTINE
|
|
1520
1470
|
case chr
|
1521
1471
|
when 'UP'
|
1522
1472
|
unless @w_b.nohistory
|
1523
|
-
unless stk == @
|
1473
|
+
unless stk == @history.length - 1
|
1524
1474
|
stk += 1
|
1525
|
-
pos = @
|
1475
|
+
pos = @history[stk].length
|
1526
1476
|
end
|
1527
1477
|
end
|
1528
1478
|
when 'DOWN'
|
1529
1479
|
unless @w_b.nohistory
|
1530
1480
|
unless stk == 0
|
1531
1481
|
stk -= 1
|
1532
|
-
pos = @
|
1482
|
+
pos = @history[stk].length
|
1533
1483
|
end
|
1534
1484
|
end
|
1535
1485
|
when 'RIGHT'
|
1536
|
-
pos += 1 unless pos > @
|
1486
|
+
pos += 1 unless pos > @history[stk].length
|
1537
1487
|
when 'LEFT'
|
1538
1488
|
pos -= 1 unless pos == 0
|
1539
1489
|
when 'HOME'
|
1540
1490
|
pos = 0
|
1541
1491
|
when 'END'
|
1542
|
-
pos = @
|
1492
|
+
pos = @history[stk].length
|
1543
1493
|
when 'DEL'
|
1544
|
-
@
|
1494
|
+
@history[stk][pos] = ""
|
1545
1495
|
when 'BACK'
|
1546
1496
|
unless pos == 0
|
1547
1497
|
pos -= 1
|
1548
|
-
@
|
1498
|
+
@history[stk][pos] = ""
|
1549
1499
|
end
|
1550
1500
|
when 'WBACK'
|
1551
1501
|
unless pos == 0
|
1552
|
-
until @
|
1502
|
+
until @history[stk][pos - 1] == " " or pos == 0
|
1553
1503
|
pos -= 1
|
1554
|
-
@
|
1504
|
+
@history[stk][pos] = ""
|
1555
1505
|
end
|
1556
|
-
if @
|
1506
|
+
if @history[stk][pos - 1] == " "
|
1557
1507
|
pos -= 1
|
1558
|
-
@
|
1508
|
+
@history[stk][pos] = ""
|
1559
1509
|
end
|
1560
1510
|
end
|
1561
1511
|
when 'LDEL'
|
1562
|
-
@
|
1512
|
+
@history[stk] = ""
|
1563
1513
|
pos = 0
|
1564
1514
|
when 'TAB' # Tab completion of dirs and files
|
1565
1515
|
p1 = pos - 1
|
1566
|
-
c = @
|
1516
|
+
c = @history[stk][0..(p1)].sub(/^.* /, '')
|
1567
1517
|
p0 = p1 - c.length
|
1568
1518
|
compl = File.expand_path(c)
|
1569
1519
|
compl += "/" if Dir.exist?(compl)
|
@@ -1598,28 +1548,19 @@ def w_b_getstr(pretext, text, ruby=false) # A SIMPLE READLINE-LIKE ROUTINE
|
|
1598
1548
|
Curses.echo
|
1599
1549
|
end
|
1600
1550
|
end
|
1601
|
-
@
|
1551
|
+
@history[stk].sub!(c,compl)
|
1602
1552
|
pos = pos - c.length + compl.length
|
1603
1553
|
when /^.$/
|
1604
|
-
@
|
1605
|
-
pos += 1
|
1606
|
-
end
|
1607
|
-
while $stdin.ready?
|
1608
|
-
chr = $stdin.getc
|
1609
|
-
@history_copy[stk].insert(pos,chr)
|
1554
|
+
@history[stk].insert(pos,chr)
|
1610
1555
|
pos += 1
|
1611
1556
|
end
|
1612
1557
|
end
|
1613
|
-
curstr = @
|
1614
|
-
@
|
1615
|
-
ruby ? @rubyhistory.insert(0, @history_copy[stk]) : @history.insert(0, @history_copy[stk])
|
1558
|
+
curstr = @history[stk]
|
1559
|
+
@history.shift if @w_b.nohistory
|
1616
1560
|
unless @w_b.nohistory
|
1617
1561
|
@history.uniq!
|
1618
1562
|
@history.compact!
|
1619
1563
|
@history.delete("")
|
1620
|
-
@rubyhistory.uniq!
|
1621
|
-
@rubyhistory.compact!
|
1622
|
-
@rubyhistory.delete("")
|
1623
1564
|
end
|
1624
1565
|
Curses.curs_set(0)
|
1625
1566
|
Curses.noecho
|
@@ -1642,11 +1583,11 @@ def w_b_exec(cmd) # EXECUTE COMMAND FROM @W_B
|
|
1642
1583
|
status = Timeout::timeout(15) {
|
1643
1584
|
@w_r.clr
|
1644
1585
|
begin
|
1645
|
-
@w_r.pager_cmd = "#{cmd}
|
1646
|
-
@w_r.text =
|
1586
|
+
@w_r.pager_cmd = "#{cmd} | #{@bat} -n --color=always 2>/dev/null"
|
1587
|
+
@w_r.text = `#{@w_r.pager_cmd}`
|
1647
1588
|
rescue
|
1648
|
-
@w_r.pager_cmd = "#{cmd} 2
|
1649
|
-
@w_r.text =
|
1589
|
+
@w_r.pager_cmd = "#{cmd} 2>/dev/null"
|
1590
|
+
@w_r.text = `#{@w_r.pager_cmd}`
|
1650
1591
|
end
|
1651
1592
|
unless @w_r.text == "" or @w_r.text == nil
|
1652
1593
|
pager_start
|
@@ -1678,8 +1619,8 @@ loop do # OUTER LOOP - CATCHING REFRESHES VIA 'r'
|
|
1678
1619
|
maxx = Curses.cols
|
1679
1620
|
maxy = Curses.lines
|
1680
1621
|
# Curses::Window.new(h,w,y,x)
|
1681
|
-
@w_t = Curses::Window.new(1,
|
1682
|
-
@w_b = Curses::Window.new(1,
|
1622
|
+
@w_t = Curses::Window.new(1, 0, 0, 0)
|
1623
|
+
@w_b = Curses::Window.new(1, 0, maxy - 1, 0)
|
1683
1624
|
@w_l = Curses::Window.new(maxy - 3, (maxx * @width / 10) - 1, 2, 0)
|
1684
1625
|
@w_r = Curses::Window.new(maxy - 4, maxx - (maxx * @width / 10), 2, maxx * @width / 10)
|
1685
1626
|
@w_p = Curses::Window.new(1, maxx - (maxx * @width / 10), maxy - 2, maxx * @width / 10)
|
@@ -1698,6 +1639,8 @@ loop do # OUTER LOOP - CATCHING REFRESHES VIA 'r'
|
|
1698
1639
|
tagged_info
|
1699
1640
|
@w_r.update = false
|
1700
1641
|
end
|
1642
|
+
@change = true
|
1643
|
+
@change_tag = true # For future need to force @change
|
1701
1644
|
loop do # INNER, CORE LOOP
|
1702
1645
|
begin # Jump to home dir if current dir is externally removed
|
1703
1646
|
Dir.pwd
|
@@ -1729,8 +1672,13 @@ loop do # OUTER LOOP - CATCHING REFRESHES VIA 'r'
|
|
1729
1672
|
@selected = @files[@index] # Get text of selected item
|
1730
1673
|
sel_old = @selected_safe
|
1731
1674
|
@selected_safe = "\"#{@selected}\"" # Make it safe for commands
|
1732
|
-
|
1733
|
-
|
1675
|
+
@selected_safe == sel_old ? @change = false : @change = true
|
1676
|
+
@change = true if @change_tag; @change_tag = false
|
1677
|
+
if @change
|
1678
|
+
system("printf \"\033]0;RTFM: #{Dir.pwd}\007\"") # Set Window title to path
|
1679
|
+
# Top window (info line)
|
1680
|
+
w_t_info
|
1681
|
+
end
|
1734
1682
|
@w_l.setpos(0,0)
|
1735
1683
|
list_dir(true)
|
1736
1684
|
@w_l.refresh
|
@@ -1753,9 +1701,6 @@ loop do # OUTER LOOP - CATCHING REFRESHES VIA 'r'
|
|
1753
1701
|
break if Curses.cols != maxx or Curses.lines != maxy # break on terminal resize
|
1754
1702
|
break if @break # Break to outer loop, redrawing windows, if user hit 'r'
|
1755
1703
|
end
|
1756
|
-
rescue StandardError => err # Throw error nicely
|
1757
|
-
w_r_info(err)
|
1758
|
-
@w_r.update = false
|
1759
1704
|
ensure # On exit: close curses, clear terminal
|
1760
1705
|
@write_conf_all = false
|
1761
1706
|
conf_write if @write_conf # Write marks to config file
|
@@ -1763,7 +1708,7 @@ loop do # OUTER LOOP - CATCHING REFRESHES VIA 'r'
|
|
1763
1708
|
close_screen
|
1764
1709
|
# If launched via the script "r", return current dir and "r" will cd to that
|
1765
1710
|
begin
|
1766
|
-
File.write(ARGV[0], Dir.pwd) if ARGV[0] and ARGV[0].match(/\/tmp/)
|
1711
|
+
File.write(ARGV[0], Dir.pwd) if ARGV[0] and ARGV[0].match(/\/tmp\/tmp/)
|
1767
1712
|
rescue
|
1768
1713
|
end
|
1769
1714
|
end
|
data/rtfm-kb.png
CHANGED
Binary file
|
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: '3.
|
4
|
+
version: '3.5'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Geir Isene
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-05-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: curses
|
@@ -47,8 +47,7 @@ dependencies:
|
|
47
47
|
description: 'A full featured terminal browser with syntax highlighted files, images
|
48
48
|
shown in the terminal, videos thumbnailed, etc. You can bookmark and jump around
|
49
49
|
easily, delete, rename, copy, symlink and move files. RTFM has a a wide range of
|
50
|
-
other features. New in 3.
|
51
|
-
add own by setting @aimodel in .rtfm.conf.'
|
50
|
+
other features. New in 3.5: Simplified install :-)'
|
52
51
|
email: g@isene.com
|
53
52
|
executables:
|
54
53
|
- rtfm
|
@@ -63,7 +62,7 @@ licenses:
|
|
63
62
|
- Unlicense
|
64
63
|
metadata:
|
65
64
|
source_code_uri: https://github.com/isene/RTFM
|
66
|
-
post_install_message:
|
65
|
+
post_install_message:
|
67
66
|
rdoc_options: []
|
68
67
|
require_paths:
|
69
68
|
- lib
|
@@ -78,8 +77,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
78
77
|
- !ruby/object:Gem::Version
|
79
78
|
version: '0'
|
80
79
|
requirements: []
|
81
|
-
rubygems_version: 3.
|
82
|
-
signing_key:
|
80
|
+
rubygems_version: 3.3.5
|
81
|
+
signing_key:
|
83
82
|
specification_version: 4
|
84
83
|
summary: RTFM - Ruby Terminal File Manager
|
85
84
|
test_files: []
|