rtfm-filemanager 3.3 → 3.5
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/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: []
|