rtfm-filemanager 7.3.6 → 7.4.0
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/CHANGELOG.md +174 -0
- data/README.md +633 -628
- data/bin/rtfm +1 -1
- data/docs/configuration.md +397 -0
- data/docs/faq.md +436 -0
- data/docs/getting-started.md +276 -0
- data/docs/keyboard-reference.md +387 -0
- data/docs/plugins.md +649 -0
- data/docs/remote-browsing.md +425 -0
- data/docs/troubleshooting.md +639 -0
- data/examples/rtfm.conf +280 -0
- data/man/rtfm.1 +361 -0
- metadata +13 -3
data/docs/plugins.md
ADDED
|
@@ -0,0 +1,649 @@
|
|
|
1
|
+
# RTFM Plugin Development Guide
|
|
2
|
+
|
|
3
|
+
Extend RTFM with custom preview handlers and key bindings.
|
|
4
|
+
|
|
5
|
+
## Plugin System Overview
|
|
6
|
+
|
|
7
|
+
RTFM supports two types of plugins:
|
|
8
|
+
|
|
9
|
+
1. **Preview Handlers** (`~/.rtfm/plugins/preview.rb`) - Custom file type previews
|
|
10
|
+
2. **Key Bindings** (`~/.rtfm/plugins/keys.rb`) - Custom commands and key mappings
|
|
11
|
+
|
|
12
|
+
Both are Ruby files evaluated in RTFM's context, giving you full access to RTFM's internals.
|
|
13
|
+
|
|
14
|
+
## Preview Handlers
|
|
15
|
+
|
|
16
|
+
### Location
|
|
17
|
+
|
|
18
|
+
`~/.rtfm/plugins/preview.rb`
|
|
19
|
+
|
|
20
|
+
### Syntax
|
|
21
|
+
|
|
22
|
+
```ruby
|
|
23
|
+
# extension1, extension2, extension3 = command with @s placeholder
|
|
24
|
+
#
|
|
25
|
+
# @s is replaced with shell-escaped filename
|
|
26
|
+
|
|
27
|
+
# Examples:
|
|
28
|
+
txt, log = bat -n --color=always @s
|
|
29
|
+
md = pandoc @s -t plain
|
|
30
|
+
pdf = pdftotext -f 1 -l 4 @s -
|
|
31
|
+
json = jq . @s
|
|
32
|
+
xml = xmllint --format @s
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### How It Works
|
|
36
|
+
|
|
37
|
+
1. RTFM matches file extension
|
|
38
|
+
2. Replaces `@s` with escaped filename
|
|
39
|
+
3. Executes command
|
|
40
|
+
4. Displays output in right pane
|
|
41
|
+
|
|
42
|
+
### Examples
|
|
43
|
+
|
|
44
|
+
#### Syntax Highlighting
|
|
45
|
+
|
|
46
|
+
```ruby
|
|
47
|
+
# Programming languages
|
|
48
|
+
rb, py, js = bat -n --color=always @s
|
|
49
|
+
c, cpp, h = highlight -O ansi --force --line-numbers @s
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
#### Document Formats
|
|
53
|
+
|
|
54
|
+
```ruby
|
|
55
|
+
# Markdown
|
|
56
|
+
md, markdown = pandoc @s -t plain
|
|
57
|
+
|
|
58
|
+
# PDF
|
|
59
|
+
pdf = pdftotext -f 1 -l 10 @s -
|
|
60
|
+
|
|
61
|
+
# LibreOffice
|
|
62
|
+
odt = odt2txt @s
|
|
63
|
+
ods = ssconvert --export-type=Gnumeric_stf:stf_csv @s fd://1
|
|
64
|
+
|
|
65
|
+
# MS Office
|
|
66
|
+
docx = docx2txt @s
|
|
67
|
+
xlsx = ssconvert --export-type=Gnumeric_stf:stf_csv @s fd://1
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
#### Data Formats
|
|
71
|
+
|
|
72
|
+
```ruby
|
|
73
|
+
# JSON with syntax highlighting
|
|
74
|
+
json = jq -C . @s
|
|
75
|
+
|
|
76
|
+
# YAML
|
|
77
|
+
yaml, yml = bat -l yaml @s
|
|
78
|
+
|
|
79
|
+
# XML
|
|
80
|
+
xml = xmllint --format @s | bat -l xml
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
#### Media Info
|
|
84
|
+
|
|
85
|
+
```ruby
|
|
86
|
+
# Video metadata
|
|
87
|
+
mp4, mkv, avi = ffprobe -hide_banner @s 2>&1
|
|
88
|
+
|
|
89
|
+
# Audio metadata
|
|
90
|
+
mp3, flac = mediainfo @s
|
|
91
|
+
|
|
92
|
+
# Image metadata (already built-in, but you can override)
|
|
93
|
+
# png, jpg = identify -verbose @s
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
#### Archives (Preview Contents)
|
|
97
|
+
|
|
98
|
+
Built-in support for: zip, tar, gz, bz2, xz, rar, 7z
|
|
99
|
+
|
|
100
|
+
Override if needed:
|
|
101
|
+
```ruby
|
|
102
|
+
zip = unzip -l @s
|
|
103
|
+
tar = tar -tvf @s
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Complex Preview Handlers
|
|
107
|
+
|
|
108
|
+
For more complex logic, use Ruby in preview.rb:
|
|
109
|
+
|
|
110
|
+
```ruby
|
|
111
|
+
# Define handler as Ruby code instead of shell command
|
|
112
|
+
PREVIEW_HANDLERS << [/\.log$/i, -> {
|
|
113
|
+
# Custom Ruby handler
|
|
114
|
+
content = File.read(@selected).lines.last(50).join
|
|
115
|
+
@pR.say("Last 50 lines:\n" + content)
|
|
116
|
+
}]
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Key Bindings
|
|
120
|
+
|
|
121
|
+
### Location
|
|
122
|
+
|
|
123
|
+
`~/.rtfm/plugins/keys.rb`
|
|
124
|
+
|
|
125
|
+
### Basic Syntax
|
|
126
|
+
|
|
127
|
+
```ruby
|
|
128
|
+
# Add or override key binding
|
|
129
|
+
KEYMAP['X'] = :my_handler
|
|
130
|
+
|
|
131
|
+
# Define handler method
|
|
132
|
+
def my_handler(_chr)
|
|
133
|
+
@pB.say("You pressed X!")
|
|
134
|
+
end
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### Available Panes
|
|
138
|
+
|
|
139
|
+
| Variable | Description |
|
|
140
|
+
|----------|-------------|
|
|
141
|
+
| `@pT` | Top pane (path/metadata) |
|
|
142
|
+
| `@pL` | Left pane (file list) |
|
|
143
|
+
| `@pR` | Right pane (preview) |
|
|
144
|
+
| `@pB` | Bottom pane (status) |
|
|
145
|
+
| `@pCmd` | Command prompt pane |
|
|
146
|
+
| `@pSearch` | Search prompt pane |
|
|
147
|
+
| `@pAI` | AI chat pane |
|
|
148
|
+
| `@pRuby` | Ruby debug pane |
|
|
149
|
+
|
|
150
|
+
### Pane Methods
|
|
151
|
+
|
|
152
|
+
```ruby
|
|
153
|
+
# Display text
|
|
154
|
+
@pR.say("Hello world")
|
|
155
|
+
@pB.say("Status message")
|
|
156
|
+
|
|
157
|
+
# Ask for input
|
|
158
|
+
answer = @pCmd.ask('Enter value: ', 'default')
|
|
159
|
+
|
|
160
|
+
# Clear pane
|
|
161
|
+
@pR.clear
|
|
162
|
+
|
|
163
|
+
# Update pane (mark for refresh)
|
|
164
|
+
@pR.update = true
|
|
165
|
+
|
|
166
|
+
# Force immediate refresh
|
|
167
|
+
@pR.refresh
|
|
168
|
+
@pR.full_refresh # Complete redraw
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### Available Variables
|
|
172
|
+
|
|
173
|
+
| Variable | Type | Description |
|
|
174
|
+
|----------|------|-------------|
|
|
175
|
+
| `@selected` | String | Currently selected file/dir path |
|
|
176
|
+
| `@tagged` | Array | Paths of tagged items |
|
|
177
|
+
| `@marks` | Hash | Bookmarks {'a' => '/path', ...} |
|
|
178
|
+
| `@files` | Array | Current directory file list |
|
|
179
|
+
| `@index` | Integer | Selected item index |
|
|
180
|
+
| `@w` / `@h` | Integer | Terminal width/height |
|
|
181
|
+
| `@preview` | Boolean | Preview enabled? |
|
|
182
|
+
| `@showimage` | Boolean | Image preview enabled? |
|
|
183
|
+
| `@trash` | Boolean | Trash bin enabled? |
|
|
184
|
+
|
|
185
|
+
### Helper Functions
|
|
186
|
+
|
|
187
|
+
#### Execute Commands
|
|
188
|
+
|
|
189
|
+
```ruby
|
|
190
|
+
# Capture output (auto-shows errors in right pane)
|
|
191
|
+
output = command("ls -la", timeout: 5)
|
|
192
|
+
@pR.say(output)
|
|
193
|
+
|
|
194
|
+
# Fire-and-forget (shows errors if any)
|
|
195
|
+
shell("mv file1 file2", background: false)
|
|
196
|
+
|
|
197
|
+
# Show both stdout and stderr in right pane
|
|
198
|
+
shellexec("grep -r pattern .")
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
#### File Operations
|
|
202
|
+
|
|
203
|
+
```ruby
|
|
204
|
+
# Check if file exists
|
|
205
|
+
File.exist?(@selected)
|
|
206
|
+
|
|
207
|
+
# Get file size
|
|
208
|
+
File.size(@selected)
|
|
209
|
+
|
|
210
|
+
# Read file
|
|
211
|
+
content = File.read(@selected)
|
|
212
|
+
|
|
213
|
+
# Write file
|
|
214
|
+
File.write('/tmp/output.txt', content)
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
## Example Plugins
|
|
218
|
+
|
|
219
|
+
### Example 1: Git Commit Shortcut
|
|
220
|
+
|
|
221
|
+
```ruby
|
|
222
|
+
# ~/.rtfm/plugins/keys.rb
|
|
223
|
+
|
|
224
|
+
KEYMAP['C-G'] = :git_quick_commit
|
|
225
|
+
|
|
226
|
+
def git_quick_commit
|
|
227
|
+
message = @pCmd.ask('Commit message: ', '')
|
|
228
|
+
return if message.strip.empty?
|
|
229
|
+
|
|
230
|
+
shellexec("git add . && git commit -m '#{message}' && git push")
|
|
231
|
+
@pB.say("Git commit and push completed")
|
|
232
|
+
end
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
**Usage:** Press `Ctrl-g`, enter message, done!
|
|
236
|
+
|
|
237
|
+
### Example 2: Quick Note Taker
|
|
238
|
+
|
|
239
|
+
```ruby
|
|
240
|
+
KEYMAP['C-N'] = :quick_note
|
|
241
|
+
|
|
242
|
+
def quick_note
|
|
243
|
+
note = @pCmd.ask('Note: ', '')
|
|
244
|
+
return if note.strip.empty?
|
|
245
|
+
|
|
246
|
+
File.open("#{Dir.home}/notes.txt", 'a') do |f|
|
|
247
|
+
f.puts "[#{Time.now}] #{note}"
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
@pB.say("Note saved to ~/notes.txt")
|
|
251
|
+
end
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
### Example 3: Batch File Converter
|
|
255
|
+
|
|
256
|
+
```ruby
|
|
257
|
+
KEYMAP['C-C'] = :convert_images
|
|
258
|
+
|
|
259
|
+
def convert_images
|
|
260
|
+
return @pB.say("Tag images first!") if @tagged.empty?
|
|
261
|
+
|
|
262
|
+
format = @pCmd.ask('Convert to (png/jpg/webp): ', 'png')
|
|
263
|
+
|
|
264
|
+
@tagged.each do |file|
|
|
265
|
+
next unless file.match(/\.(jpg|png|gif|bmp)$/i)
|
|
266
|
+
|
|
267
|
+
output = file.sub(/\.\w+$/, ".#{format}")
|
|
268
|
+
command("convert #{Shellwords.escape(file)} #{Shellwords.escape(output)}")
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
@pB.say("Converted #{@tagged.size} images to #{format}")
|
|
272
|
+
@tagged.clear
|
|
273
|
+
@pL.update = true
|
|
274
|
+
end
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
### Example 4: Custom File Opener
|
|
278
|
+
|
|
279
|
+
```ruby
|
|
280
|
+
KEYMAP['O'] = :open_with
|
|
281
|
+
|
|
282
|
+
def open_with
|
|
283
|
+
program = @pCmd.ask('Open with: ', 'vim')
|
|
284
|
+
return if program.strip.empty?
|
|
285
|
+
|
|
286
|
+
escaped = Shellwords.escape(@selected)
|
|
287
|
+
|
|
288
|
+
# Set flag to prevent SIGWINCH redrawing over program
|
|
289
|
+
@external_program_running = true
|
|
290
|
+
|
|
291
|
+
system("stty sane < /dev/tty")
|
|
292
|
+
system("clear < /dev/tty > /dev/tty")
|
|
293
|
+
Cursor.show
|
|
294
|
+
|
|
295
|
+
system("#{program} #{escaped}")
|
|
296
|
+
|
|
297
|
+
@external_program_running = false
|
|
298
|
+
|
|
299
|
+
# Restore terminal for RTFM
|
|
300
|
+
system('stty raw -echo isig < /dev/tty')
|
|
301
|
+
$stdin.raw!
|
|
302
|
+
$stdin.echo = false
|
|
303
|
+
Cursor.hide
|
|
304
|
+
Rcurses.clear_screen
|
|
305
|
+
refresh
|
|
306
|
+
render
|
|
307
|
+
end
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
### Example 5: Directory Size Calculator
|
|
311
|
+
|
|
312
|
+
```ruby
|
|
313
|
+
KEYMAP['#'] = :calc_dir_size
|
|
314
|
+
|
|
315
|
+
def calc_dir_size
|
|
316
|
+
return @pB.say("Select a directory") unless File.directory?(@selected)
|
|
317
|
+
|
|
318
|
+
@pR.say("Calculating size...")
|
|
319
|
+
|
|
320
|
+
output = command("du -sh #{Shellwords.escape(@selected)}")
|
|
321
|
+
size = output.split("\t").first
|
|
322
|
+
|
|
323
|
+
@pR.say("Directory Size\n\n#{@selected}\n\n#{size}")
|
|
324
|
+
end
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
## Advanced Techniques
|
|
328
|
+
|
|
329
|
+
### Launching External TUI Programs
|
|
330
|
+
|
|
331
|
+
For full-screen terminal programs (vim, htop, etc.):
|
|
332
|
+
|
|
333
|
+
```ruby
|
|
334
|
+
def launch_external_program(cmd)
|
|
335
|
+
@external_program_running = true
|
|
336
|
+
|
|
337
|
+
# Save and restore terminal state
|
|
338
|
+
system("stty -g < /dev/tty > /tmp/rtfm_stty_$$")
|
|
339
|
+
system('stty sane < /dev/tty')
|
|
340
|
+
system('clear < /dev/tty > /dev/tty')
|
|
341
|
+
Cursor.show
|
|
342
|
+
|
|
343
|
+
# Spawn on real tty
|
|
344
|
+
pid = Process.spawn(cmd,
|
|
345
|
+
in: '/dev/tty',
|
|
346
|
+
out: '/dev/tty',
|
|
347
|
+
err: '/dev/tty')
|
|
348
|
+
|
|
349
|
+
begin
|
|
350
|
+
Process.wait(pid)
|
|
351
|
+
rescue Interrupt
|
|
352
|
+
Process.kill('TERM', pid) rescue nil
|
|
353
|
+
retry
|
|
354
|
+
ensure
|
|
355
|
+
@external_program_running = false
|
|
356
|
+
end
|
|
357
|
+
|
|
358
|
+
# Restore RTFM terminal state
|
|
359
|
+
system('stty raw -echo isig < /dev/tty')
|
|
360
|
+
$stdin.raw!
|
|
361
|
+
$stdin.echo = false
|
|
362
|
+
Cursor.hide
|
|
363
|
+
Rcurses.clear_screen
|
|
364
|
+
refresh
|
|
365
|
+
render
|
|
366
|
+
end
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
### Working with Tagged Items
|
|
370
|
+
|
|
371
|
+
```ruby
|
|
372
|
+
def process_tagged_items
|
|
373
|
+
if @tagged.empty?
|
|
374
|
+
@pB.say("No items tagged")
|
|
375
|
+
return
|
|
376
|
+
end
|
|
377
|
+
|
|
378
|
+
@tagged.each do |item|
|
|
379
|
+
# Process each item
|
|
380
|
+
if File.file?(item)
|
|
381
|
+
# Handle file
|
|
382
|
+
elsif File.directory?(item)
|
|
383
|
+
# Handle directory
|
|
384
|
+
end
|
|
385
|
+
end
|
|
386
|
+
|
|
387
|
+
# Clear tags after processing
|
|
388
|
+
@tagged.clear
|
|
389
|
+
@pL.update = true
|
|
390
|
+
end
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
### Interactive Prompts
|
|
394
|
+
|
|
395
|
+
```ruby
|
|
396
|
+
def interactive_handler
|
|
397
|
+
# Text input
|
|
398
|
+
text = @pCmd.ask('Enter text: ', 'default value')
|
|
399
|
+
|
|
400
|
+
# Number input
|
|
401
|
+
num = @pCmd.ask('Enter number: ', '10').to_i
|
|
402
|
+
|
|
403
|
+
# Yes/no confirmation
|
|
404
|
+
confirm = @pCmd.ask('Proceed? (y/n): ', 'y')
|
|
405
|
+
return unless confirm =~ /^y/i
|
|
406
|
+
|
|
407
|
+
# Process...
|
|
408
|
+
end
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
### Updating Display
|
|
412
|
+
|
|
413
|
+
```ruby
|
|
414
|
+
def custom_display
|
|
415
|
+
# Update right pane
|
|
416
|
+
@pR.clear
|
|
417
|
+
@pR.say("Custom content here")
|
|
418
|
+
@pR.update = true
|
|
419
|
+
|
|
420
|
+
# Update bottom status
|
|
421
|
+
@pB.say("Operation complete")
|
|
422
|
+
@pB.update = true
|
|
423
|
+
|
|
424
|
+
# Trigger render
|
|
425
|
+
render
|
|
426
|
+
end
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
## Plugin Best Practices
|
|
430
|
+
|
|
431
|
+
### 1. Check Prerequisites
|
|
432
|
+
|
|
433
|
+
```ruby
|
|
434
|
+
def my_handler
|
|
435
|
+
unless cmd?('required-program')
|
|
436
|
+
@pB.say("Error: required-program not installed")
|
|
437
|
+
return
|
|
438
|
+
end
|
|
439
|
+
|
|
440
|
+
# Continue...
|
|
441
|
+
end
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
### 2. Handle Errors Gracefully
|
|
445
|
+
|
|
446
|
+
```ruby
|
|
447
|
+
def safe_handler
|
|
448
|
+
begin
|
|
449
|
+
# Your code
|
|
450
|
+
rescue => e
|
|
451
|
+
@pB.say("Error: #{e.message}")
|
|
452
|
+
end
|
|
453
|
+
end
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
### 3. Provide Feedback
|
|
457
|
+
|
|
458
|
+
```ruby
|
|
459
|
+
def verbose_handler
|
|
460
|
+
@pB.say("Processing...")
|
|
461
|
+
|
|
462
|
+
# Long operation
|
|
463
|
+
result = command("slow-command")
|
|
464
|
+
|
|
465
|
+
@pB.say("Completed!")
|
|
466
|
+
@pR.say(result)
|
|
467
|
+
end
|
|
468
|
+
```
|
|
469
|
+
|
|
470
|
+
### 4. Use Shellwords for Safety
|
|
471
|
+
|
|
472
|
+
```ruby
|
|
473
|
+
require 'shellwords'
|
|
474
|
+
|
|
475
|
+
escaped = Shellwords.escape(@selected)
|
|
476
|
+
command("program #{escaped}")
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
### 5. Respect Image Display
|
|
480
|
+
|
|
481
|
+
```ruby
|
|
482
|
+
def text_display_handler
|
|
483
|
+
# Clear image before showing text
|
|
484
|
+
clear_image
|
|
485
|
+
|
|
486
|
+
@pR.say("Your text content")
|
|
487
|
+
end
|
|
488
|
+
```
|
|
489
|
+
|
|
490
|
+
## Debugging Plugins
|
|
491
|
+
|
|
492
|
+
### Test in Ruby Mode
|
|
493
|
+
|
|
494
|
+
1. Press `@` to enter Ruby mode
|
|
495
|
+
2. Test your code:
|
|
496
|
+
```ruby
|
|
497
|
+
my_handler(nil)
|
|
498
|
+
```
|
|
499
|
+
3. Check for errors in right pane
|
|
500
|
+
|
|
501
|
+
### Reload Plugins
|
|
502
|
+
|
|
503
|
+
```ruby
|
|
504
|
+
# In Ruby mode
|
|
505
|
+
load '~/.rtfm/plugins/keys.rb'
|
|
506
|
+
```
|
|
507
|
+
|
|
508
|
+
Or restart RTFM.
|
|
509
|
+
|
|
510
|
+
### Check Variables
|
|
511
|
+
|
|
512
|
+
```ruby
|
|
513
|
+
# In Ruby mode
|
|
514
|
+
puts KEYMAP.keys.sort
|
|
515
|
+
puts @selected
|
|
516
|
+
puts defined?(my_handler)
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
## Plugin Ideas
|
|
520
|
+
|
|
521
|
+
### Workflow Automation
|
|
522
|
+
|
|
523
|
+
- Git workflow shortcuts
|
|
524
|
+
- Deployment scripts
|
|
525
|
+
- Backup automation
|
|
526
|
+
- File organization rules
|
|
527
|
+
|
|
528
|
+
### File Processing
|
|
529
|
+
|
|
530
|
+
- Batch image conversion
|
|
531
|
+
- Document generation
|
|
532
|
+
- Log analysis
|
|
533
|
+
- Data extraction
|
|
534
|
+
|
|
535
|
+
### Integration
|
|
536
|
+
|
|
537
|
+
- Integration with other tools
|
|
538
|
+
- API calls
|
|
539
|
+
- Database queries
|
|
540
|
+
- Cloud storage sync
|
|
541
|
+
|
|
542
|
+
### Information Display
|
|
543
|
+
|
|
544
|
+
- Custom file info
|
|
545
|
+
- Directory statistics
|
|
546
|
+
- Metadata extraction
|
|
547
|
+
- Health checks
|
|
548
|
+
|
|
549
|
+
## Sharing Plugins
|
|
550
|
+
|
|
551
|
+
Consider sharing useful plugins:
|
|
552
|
+
1. Post as GitHub gist
|
|
553
|
+
2. Share in RTFM issues/discussions
|
|
554
|
+
3. Create plugin collection repository
|
|
555
|
+
|
|
556
|
+
## Plugin Template
|
|
557
|
+
|
|
558
|
+
```ruby
|
|
559
|
+
# ~/.rtfm/plugins/keys.rb
|
|
560
|
+
#
|
|
561
|
+
# Plugin: [Name]
|
|
562
|
+
# Description: [What it does]
|
|
563
|
+
# Author: [Your name]
|
|
564
|
+
# Dependencies: [Required programs]
|
|
565
|
+
|
|
566
|
+
KEYMAP['[KEY]'] = :plugin_name
|
|
567
|
+
|
|
568
|
+
def plugin_name(_chr)
|
|
569
|
+
# Check prerequisites
|
|
570
|
+
return @pB.say("Error: dependency missing") unless cmd?('program')
|
|
571
|
+
|
|
572
|
+
# Get input if needed
|
|
573
|
+
input = @pCmd.ask('Prompt: ', 'default')
|
|
574
|
+
return if input.strip.empty?
|
|
575
|
+
|
|
576
|
+
# Show progress
|
|
577
|
+
@pB.say("Processing...")
|
|
578
|
+
|
|
579
|
+
# Do work
|
|
580
|
+
begin
|
|
581
|
+
result = command("your-command #{Shellwords.escape(input)}")
|
|
582
|
+
|
|
583
|
+
# Display result
|
|
584
|
+
@pR.say(result)
|
|
585
|
+
@pB.say("Completed!")
|
|
586
|
+
|
|
587
|
+
rescue => e
|
|
588
|
+
@pB.say("Error: #{e.message}")
|
|
589
|
+
end
|
|
590
|
+
end
|
|
591
|
+
```
|
|
592
|
+
|
|
593
|
+
## Reference
|
|
594
|
+
|
|
595
|
+
### All Available Methods
|
|
596
|
+
|
|
597
|
+
```ruby
|
|
598
|
+
# Command execution
|
|
599
|
+
command(cmd, timeout: 5, return_both: false)
|
|
600
|
+
shell(cmd, background: false, err: nil)
|
|
601
|
+
shellexec(cmd, timeout: 10)
|
|
602
|
+
|
|
603
|
+
# Utilities
|
|
604
|
+
cmd?(program) # Check if program exists
|
|
605
|
+
dirlist(left: false) # Get directory listing
|
|
606
|
+
mark_latest # Update directory marks
|
|
607
|
+
track_file_access(path) # Track file access
|
|
608
|
+
track_directory_access(path) # Track directory access
|
|
609
|
+
|
|
610
|
+
# Display
|
|
611
|
+
refresh # Refresh layout
|
|
612
|
+
render # Render all panes
|
|
613
|
+
clear_image # Clear displayed image
|
|
614
|
+
showimage(path) # Display image
|
|
615
|
+
|
|
616
|
+
# Operations
|
|
617
|
+
add_undo_operation(info) # Add to undo history
|
|
618
|
+
copy_to_clipboard(text, 'primary' or 'clipboard')
|
|
619
|
+
```
|
|
620
|
+
|
|
621
|
+
### Global Variables
|
|
622
|
+
|
|
623
|
+
```ruby
|
|
624
|
+
# File system
|
|
625
|
+
Dir.pwd # Current directory
|
|
626
|
+
@selected # Selected item path
|
|
627
|
+
@files # Current dir file list
|
|
628
|
+
@tagged # Tagged items array
|
|
629
|
+
|
|
630
|
+
# Configuration
|
|
631
|
+
@preview # Preview enabled?
|
|
632
|
+
@showimage # Images enabled?
|
|
633
|
+
@trash # Trash enabled?
|
|
634
|
+
@lsall / @lslong / @lsorder / @lsinvert
|
|
635
|
+
|
|
636
|
+
# State
|
|
637
|
+
@index # Selected item index
|
|
638
|
+
@marks # Bookmarks hash
|
|
639
|
+
@history # Command history array
|
|
640
|
+
@remote_mode # In SSH mode?
|
|
641
|
+
|
|
642
|
+
# Display
|
|
643
|
+
@w / @h # Terminal dimensions
|
|
644
|
+
@pL / @pR / @pT / @pB # Panes
|
|
645
|
+
```
|
|
646
|
+
|
|
647
|
+
---
|
|
648
|
+
|
|
649
|
+
[← Keyboard Reference](keyboard-reference.md) | [Back to README](../README.md)
|