rcmd-egui 4.30.8

rcmd in a window: the orthodox dual-pane file manager, its ratatui drawing painted by egui instead of a terminal.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
# rcmd

A Midnight Commander replacement in Rust: orthodox dual-pane file manager
with MC keybindings, built on ratatui. All four roadmaps are complete -
1.0 ([docs/PLAN.md](docs/PLAN.md)), 2.0
([docs/PLAN2.md](docs/PLAN2.md)), 3.0
([docs/PLAN3.md](docs/PLAN3.md)) and now **4.0, the parity release**
([docs/PLAN4.md](docs/PLAN4.md)), whose scope came from a
decision-by-decision comparison against mc
([docs/MC-DIFF.md](docs/MC-DIFF.md)). Every row that comparison marked
**Adopt** is closed, and the places where rcmd still differs on purpose
are written down there rather than left to be discovered.

**4.11 onwards** is a second comparison, against the rest of the
orthodox family - Far Manager, DOS Navigator, Volkov Commander, Total
Commander, and the modern TUI managers - written down the same way in
[docs/ORTHODOX-DIFF.md](docs/ORTHODOX-DIFF.md). Those rows are not
parity work and nothing is owed to anybody, which is why `Skip` appears
there as often as `Adopt`.

![rcmd demo: browsing, the syntax-highlighted viewer, marking and
copying, the persistent subshell](docs/demo.gif)

*(recorded by [tests/e2e/record_demo.py](tests/e2e/record_demo.py) -
the same pty harness that runs the test suite - and rendered with
[agg](https://github.com/asciinema/agg))*

**4.28** adds a second front end: `rcmd-egui` is the same file
manager drawn by [egui](https://github.com/emilk/egui) in a window
instead of by a terminal - see [In a window](#in-a-window).

![rcmd-egui: the same two panels, the same keys, in a
window](docs/rcmd-egui.png)

## Status

**2.0** - complete MC-workflow parity and beyond: marking and F5–F8
operations with MC-style dialogs (mtimes preserved, F8 goes to trash),
command line + shell integration with real job control, F3 chunked
viewer with wrap and hex modes, F9 menu, F1 help, config file with
keymap presets/custom bindings, quick search, filter, hotlist, themes,
archive browsing (zip, tar, tar.{gz,xz,bz2}) with extraction and
copy-into-zip; find file / panelize / directory compare, non-blocking
listings with filesystem watching, **SFTP remote panels**, a **built-in
editor** with syntax highlighting, mouse support, per-panel directory
history, quick view, info panel, listing formats, git status in the
panels, **openers and an F2 user menu**, and MC's ESC-prefix - see
below.

**3.0** - the live commander: the persistent **subshell**
(Ctrl+O), SFTP auth depth (passphrase keys, keyboard-interactive),
bulk rename via the editor, viewer follow mode (tail -f) with
syntax highlighting and precise search-match highlighting, `[[view]]`
filters (F3 through `pdftotext` & co.), Tab path completion,
gitignore-aware find, recent directories in the hotlist, a **job
queue** with background transfers, chmod/chown/symlink dialogs, editor
soft-wrap + `$1` capture groups + block ops, copy *into* tar, **rar and
7z browsing** (via 7z/unrar), click-to-sort headers, and an MC alias
batch (S-F4/S-F5/S-F6, C-x t/p, M-c quick cd…).

**3.8** - toward parity with mc: `config.toml` is now yours alone, with
everything rcmd changes itself moved to a state file; F9 > Options >
Panel options is one grouped dialog covering mc's whole setting
surface; `[keys.viewer]` and `[keys.editor]` rebind inside the viewer
and the editor; `rcmd --import-mc` converts an existing mc
configuration; the command line gained mc's keys, macros and a
persistent history; and the panels gained the **Layout** settings
(horizontal split, adjustable ratio, optional bars), a **per-panel mini
status** and the **multi-column brief listing**.

**3.10** - the panels themselves: mc's **directory tree**, both as the
Command-menu dialog (Enter moves this panel) and as a panel listing mode
(Enter moves the other one and the tree stays), scanned on demand so
there is no tree cache to go stale; and the **user-defined listing
format**, where `listing = "user"` draws whatever `listing_format` names
in mc's own format language - `half type name | size | mtime` and the
other fifteen fields, with widths that grow.

**3.11** - `[[highlight]]` colour rules: entries are painted by glob or
by kind, which is mc's filehighlight without the second file.

**3.12** - mc's menu bar: **Left, File, Command, Options, Right**, where
the two panel menus act on their own panel whichever one has the focus.

**3.51** - the wider world (4.0 S7): `-e` and `-v` and the
**rcedit / rcview / rcdiff** aliases, mc's startup flags
(`-b -c -C -S -d -u -U -l`), the shipped shell wrappers, **skins** -
rcmd's own theme files and mc's skin files read where they lie - and
**macOS builds back** in CI and in the releases.

**4.28** - **a second front end**: `rcmd-egui` draws the same screen
with egui, in a window, sharing every crate with the terminal build and
calling the same `ui::draw`. `rcmd-tui` became a library as well as a
binary to allow it, and `App::run`'s body became `App::tick` so a front
end that does not own its event loop can drive the same state machine.
`Ctrl+O` opens a real terminal pane in it: `vt100` interprets what the
existing subshell's pty produces, so `less` and `vim` work there. See
[In a window](#in-a-window).

**4.11-4.27** - the orthodox pass, from
[docs/ORTHODOX-DIFF.md](docs/ORTHODOX-DIFF.md): **directory
synchronize** (compare, then a plan that says which way each difference
goes), **Alt+F5 packs** into a new archive, **Ctrl+X u undoes** a move
or a bulk rename, mask lists (`*.c,*.h|*_test.*`) everywhere a glob is
typed, **named filter sets**, select and filter **by size and age**,
five more **sort orders** including *unsorted*, the hotlist ranked by
**frecency** and searchable, `rcmd --remote` **driving a running
instance** (and with it a plugin story that needs no runtime), **rclone
panels**, what is **mounted** in the `C-x a` list, **checksum files**
and a **Verify** box on the copy form, **wipe**, **apply a command per
file**, the **numbered places**, **recent files**, and the small keys
the others always had - restore marks, size every directory, names to
the clipboard, hide a panel.

**4.0** - the parity release, and the leftovers that finished it: mc's
**quick search** with an input field of its own, **Learn keys**,
`[keys.dialog]`, a **hotlist with groups** and a label prompt and
editing, **user-menu conditions and submenus** plus the per-directory
`.mc.menu`, mc's full **macro set**, dialog **input history**, **mouse**
and **underlined hotkeys**, the mc **clipboard file**, and **user syntax
files**. What is left in [docs/MC-DIFF.md](docs/MC-DIFF.md) is the
divergences - Tab completing rather than switching panels, F8 to the
trash, one grouped options dialog instead of five - each of them a
decision with a reason next to it.

## Install & run

```sh
cargo install rcmd-tui                 # from crates.io; installs the `rcmd` binary
# or straight from git:
cargo install --git https://github.com/jaroslavpachola/rcmd rcmd-tui
# from a checkout:
cargo install --path crates/rcmd-tui   # installs the `rcmd` binary
# or during development:
cargo run -p rcmd-tui                  # or: just run

cargo install rcmd-egui                # the window build
cargo install --path crates/rcmd-egui  # the same, from a checkout
cargo run -p rcmd-egui
just install-desktop                   # and a menu entry for the window
```

`just install-desktop` writes
`~/.local/share/applications/rcmd-egui.desktop` from
[crates/rcmd-egui/dist](crates/rcmd-egui/dist), pinning `Exec` to the
installed binary because a desktop session rarely carries
`~/.cargo/bin` on its `PATH`; a packager installs the file as it
stands. The entry claims no `inode/directory` handler on purpose - it
starts the window where a launcher starts anything, and which program
a folder opens in is the desktop's own setting, not this file's to
take.

Release binaries are attached to GitHub releases (built by
`.github/workflows/release.yml` on `v*` tags): the glibc Linux build, a
**static musl build** (`x86_64-unknown-linux-musl`, C dependencies
vendored) that runs on any distro with no shared-library requirements,
and macOS on both architectures (`x86_64-apple-darwin`,
`aarch64-apple-darwin`, OpenSSL vendored so nothing has to be installed
alongside).

```
usage: rcmd [OPTIONS] [DIR1 [DIR2]]
       rcedit FILE...    rcview FILE    rcdiff FILE1 FILE2
       rcmd --import-mc [MC_CONFIG_DIR]

  -e, --edit FILE     start in the editor on FILE (repeatable)
  -v, --view FILE     start in the viewer on FILE
  -P, --printwd FILE  write the last active directory to FILE on exit
  -S, --skin NAME     theme: mc, dark, bw
  -b, --nocolor       black and white
  -c, --color         colour (the default)
  -C, --colors SPEC   mc colour spec: keyword=fg,bg:keyword=fg,bg
  -d, --nomouse       no mouse
  -u / -U             subshell off / on for this run
  -l, --ftplog FILE   log the FTP/fish dialogue to FILE
      --remote LINE   hand LINE to a running rcmd and exit
      --to PID        which one, when several are running
```

`-e` and `-v` bring rcmd up on **one screen instead of the panels**, and
closing it ends the session - that is mc's `mcedit` / `mcview`, and the
same thing happens when the binary is reached through a link named
`rcedit`, `rcview` or `rcdiff` (mc's names work too, if that is what
your fingers type):

```sh
ln -s "$(command -v rcmd)" ~/.local/bin/rcedit    # and rcview, rcdiff
rcedit notes.txt draft.txt   # two editor screens; Alt+` lists them
rcdiff old.rs new.rs         # the two files side by side
```

`-b` is the one to reach for when the colours are not arriving - it
drops to the terminal's own foreground and background, with reverse
video where something has to stand out, and it overrides `-S`. `-C`
takes mc's colour spec (`normal=brightgreen,black:directory=white`) and
lays it over whatever theme is loaded; keywords rcmd has nowhere to put
are named on the status line rather than dropped in silence. `-l` writes
every line of FTP and `fish://` dialogue to a file - the transcript is
what a server that will not list looks like from outside - with the
password redacted.

Coming from mc? `rcmd --import-mc` reads your `menu`, `mc.ext` and
`mc.keymap` and prints the equivalent rcmd config on stdout - user menu
entries, openers, view filters and panel key bindings. It never touches
your `config.toml`; review what it prints and paste what you want.
Anything with no rcmd equivalent (`type/` matchers, `%cd` commands,
unsupported macros) is reported on stderr rather than guessed at.

To make your shell follow rcmd's last directory on exit (the mc-wrapper
trick), source one of the shipped wrappers - [`contrib/rc.sh`](contrib/rc.sh)
for bash/zsh, [`contrib/rc.fish`](contrib/rc.fish) for fish. They come
with the release tarballs, and are one function each if you would rather
copy it into your shell config than source a file:

```sh
. /path/to/rc.sh                              # bash/zsh: in ~/.bashrc
cp rc.fish ~/.config/fish/functions/rc.fish   # fish
rc                                            # rcmd, and cd where it ended
```

Both are the same idea: rcmd writes its last active directory to a file
on exit (`-P`), the function reads it and `cd`s there. A run that ends
in a crash, or in a directory that has since gone away, leaves the shell
exactly where it was.

## In a window

`rcmd-egui` is rcmd drawn by egui instead of by a terminal. Same
panels, same keys, same `config.toml`, same themes, same viewer and
editor - it is a front end and nothing more. The whole of `rcmd-core`, `rcmd-edit` and
`rcmd-tui` is shared with the terminal build rather than reimplemented,
and the drawing code (`ui.rs`) is called unchanged: what the window
contributes is a ratatui `Backend` that paints a monospace cell grid, a
translation from egui input into the crossterm events the state machine
already dispatches on, and an answer to "run this command" that does not
assume a tty.

```
usage: rcmd-egui [OPTIONS] [DIR1 [DIR2]]

  -e, --edit FILE     start in the editor on FILE (repeatable)
  -v, --view FILE     start in the viewer on FILE
  -D, --diff A B      start in the diff viewer on A and B
  -S, --skin NAME     theme: mc, dark, bw
  -b, --nocolor       black and white
  -C, --colors SPEC   mc colour spec: keyword=fg,bg:keyword=fg,bg
      --font-size N   point size of the grid font, for this session
```

`$TERMINAL` names the emulator to fall back on when there is no
subshell; `$RCMD_EGUI_FONT` a `.ttf`/`.otf` to draw the grid in for
the one session; `$RCMD_EGUI_KEYS` keys to play in at startup, for
driving the window from a script.

**The font is yours to choose** - the one setting a terminal cannot
have. **Options > Font...** in the window's menu bar lists the
monospaced families the system has, with a size slider beside them,
and the grid behind the dialog changes as you pick; OK keeps the
choice, Cancel puts back what you had. **Ctrl+= / Ctrl+- / Ctrl+0**
step the size and put it back, as in any windowed terminal. Both are
written to `window.toml` beside rcmd's `state.toml`. By hand, the same
two go under a `[window]` table in `config.toml`, which the terminal
build ignores:

```toml
[window]
font = "DejaVu Sans Mono"   # a family name, or a path to a .ttf/.otf
font_size = 14
```

Without any of that the grid is drawn in a system monospace face -
DejaVu, Liberation, Menlo or Consolas, whichever is there - because
egui's bundled font is missing most of the box-drawing block and rcmd
frames every panel and every dialog in it. egui's own font is the
fallback beneath whatever is chosen, so a glyph the chosen face lacks
is still drawn.

**Ctrl+O opens a terminal pane**, the same as it opens the output
screen in a terminal. `subshell.rs` already owned the pty, spawned the
shell, tracked its working directory through the prompt hooks and
buffered every byte it wrote; the window only had to add the
interpreting half, which is [`vt100`](https://crates.io/crates/vt100) -
bytes in, a grid of cells out - and painting a grid of cells is what
this front end does anyway.

![rcmd-egui: git status and ls in the embedded terminal
pane](docs/rcmd-egui-shell.png)

Colour, bold, the alternate screen and application-cursor mode all
work, so `less`, `vim` and anything built on ncurses behave as they do
anywhere else. A second `Ctrl+O` brings the panels back, and the active
panel has followed the shell's `cd` - and the shell follows the panel's,
the same sync the terminal build does. A command typed on rcmd's own
command line opens the pane, runs there, and closes it again when it
finishes.

The protocol behind that - wait for a prompt, sync the directory in,
feed the command, know when it finished, sync back out - is not written
twice. It is `App::begin_subshell` / `step_subshell` / `end_subshell`,
and the terminal build loops over the same three calls while passing
keys through raw.

**The menu bar is the window's own**, above the grid, rather than mc's
row of titles drawn inside it: real dropdowns, the pointer's, with the
key shown beside each entry and the hotkey letter underlined and
working - `F9` opens the leftmost menu as it does in a terminal, the
arrow keys and Enter walk it, `f` then `q` is still File > Quit. The
entries are the same tables the terminal build draws (`MENUS` and, in
the editor, `EDIT_MENUS`), and choosing one makes the same call its
dropdown makes on Enter, so Left and Right act on their own panel here
too. The editor on top swaps in its own bar; a dialog, a job, the help
or the viewer greys it, since what is on top has the keys. The
`show_menubar` row is the terminal build's and is not drawn here.

**What is still different.** Openers and `[[open]]` rules are spawned
detached, which is what an opener always wanted - a GUI program no
longer needs its trailing `&`. And with no subshell at all (`subshell =
false`, or a shell that would not spawn) commands fall back to a
terminal emulator: `$TERMINAL` if it is set, else the usual ones, with a
"press Enter" pause so a command that only prints an error can be read.

Everything else is shared, including the state file - the directory a
window was left in is where the next terminal session starts.

## Keys

| Key | Action |
|-----|--------|
| Tab | Switch panel |
| ↑ ↓ PgUp PgDn Home End | Move cursor |
| Enter | Enter directory or archive (zip, tar, tar.{gz,xz,bz2}) |
| Backspace | Parent directory / leave archive |
| F1 | Help |
| F2 | User menu (`[[commands]]` from the config) |
| F3 | View file (internal viewer) |
| F4 | Edit file (built-in editor; `editor = "external"` for $EDITOR) |
| F9 | Pulldown menu (highlighted letters are hotkeys: `F9 o p` = Panel options) |
| Insert, Ctrl+T | Mark entry and advance |
| `+` / `-` (or `\`) | Select / unselect by glob |
| `*` | Invert marks |
| Ctrl+X l / s / v | Hard link / absolute symlink / relative symlink to the cursor entry |
| Ctrl+X Ctrl+S | Change where an existing symlink points |
| F5 | Copy marked (or cursor) entry - opens MC's form: source mask, destination, preserve attributes / follow links / dive into subdirs / stable symlinks, and OK / Background / Cancel |
| F6 | Move / rename |
| F7 | Make directory |
| Alt+F5 | Pack the marked entries into a new archive (the name says the format) |
| F8 | Delete to trash |
| Shift+F8 | Delete permanently |
| Alt+Del | Wipe: overwrite every byte, then delete |
| Ctrl+G | Apply a command to each marked file, one at a time |
| Ctrl+X u | Undo the last move (asks first; a second time is the redo) |
| Alt+N | Sort by name (again = reverse; extension, size, the three times, owner, group and *unsorted* live in the panel's own F9 → Left/Right menu) |
| Alt+T | Cycle listing format: brief (names in columns) / full / long (active long panel = full-width one-panel view) |
| Ctrl+U | Swap panels |
| Alt+. | Toggle hidden files |
| Ctrl+S, Alt+S | Quick search: matches anywhere in the name, `*`/`?` glob, smartcase; Ctrl+S or ↓/↑ walks the matches |
| Ctrl+F | Filter shown files by glob (`*` or empty clears) |
| Alt+letter | In a dialog: press the button whose underlined letter it is |
| Ctrl+\ | Directory hotlist: Enter goes (or walks into a group), `Ctrl+S` narrows the list by what you type, `a` adds this directory, `g` makes a group, `e` renames, `m` moves an entry into another group, `d` drops, Alt+↑/↓ reorders |
| Alt+F7 | Find file (glob + optional content); results panelized |
| Alt+← / Alt+→ | Directory history back / forward (per panel) |
| Alt+Shift+H | Directory history as a list; Enter goes there |
| Alt+↑ | Directory hotlist |
| Ctrl+X d | Compare directories (marks differences in both panels) |
| Ctrl+X m | Put back the marks the last operation spent |
| Ctrl+X Space | Size every directory in the panel, one after the other |
| Ctrl+X 0…9 | The ten numbered places: go there, or set an empty one here |
| Ctrl+Ins / Ctrl+Alt+Ins | Copy the marked names / full paths to the clipboard |
| Ctrl+F1 / Ctrl+F2 | Hide the left / right panel, and give the other the screen |
| Ctrl+X ! | Panelize a command's output |
| Alt+H | Command history (kept across sessions); Alt+P / Alt+N walk it |
| Alt+A | Insert the panel's path on the command line |
| Ctrl+X q | Quick view: other panel previews the cursor file |
| Ctrl+X i | Info panel: other panel shows the cursor file's full stat |
| Alt+i / Alt+o | Other panel: same directory / directory under cursor |
| Ctrl+Space | Directory size (background scan into the Size column) |
| Ctrl+R | Reload panel (also restores listing after find/panelize) |
| Esc | Cancel dialog / running operation / clear command line |
| Esc *key* | MC meta prefix: Esc 1…0 = F1…F10, Esc x = Alt+X, Esc Esc = Esc |
| F10 | Quit |

Typing goes to the **command line** at the bottom; Enter runs it in the
active panel's directory (`cd` changes the panel instead, and `cd -`
goes back to where the panel came from; a relative `cd` that misses
locally also tries `$CDPATH`). Dialog fields remember what was typed
into them before - Alt+P and Alt+N walk a field's own history, kept per
kind of question (destinations, `mkdir`, `cd`, `chown`…) and saved
between sessions. MC's macros expand there too (the same
set the user menu gets, below - so `%%s` is how you type a literal
`%s`). Alt+Enter
inserts the selected filename, Ctrl+P/Ctrl+N walk history, Ctrl+A/E are
readline-style and Esc clears the line (Ctrl+U swaps panels, like MC).
The `+`/`-`/`*`/`\` selection keys apply only while the command line is
empty.

**The subshell** (Ctrl+O): a persistent `$SHELL` runs on its own pty for
the whole session, exactly like MC's. Ctrl+O flips between the panels
and its screen - the last command's output is still there - and typed
commands run *inside* it, so aliases, functions, history and `$?`
survive between commands. cd sync goes both ways: the panels follow a
`cd` typed in the subshell, and the subshell is moved to the active
panel's directory before running anything. `exit` respawns it. bash,
zsh and fish get a prompt hook for precise tracking; plain POSIX `sh`
works with a `/proc`-based fallback. `subshell = false` in the config
restores the old one-shot execution (also the automatic fallback if the
shell cannot be spawned).

In dialogs: arrows/Tab move between buttons, Enter confirms, Esc cancels;
overwrite and error prompts also take hotkeys (o/a/s/S, r/s/S). The
The copy/move form takes MC's **source mask**: `*.tar.gz` with a
destination of `dir/*.tgz` copies `foo.tar.gz` to `dir/foo.tgz`, and
files the mask does not match stay where they are. The mask's wildcards
are numbered left to right - `*` in the destination is the first,
`\1`..`\9` any of them, `\0` the whole name - and `\u \l \U \L \E`
change case. (Regex renaming with capture groups lives in F9 > File >
Bulk rename, which is a better place for it than a one-line field.)

The overwrite prompt is MC's: both files' size and date on screen, then
**Overwrite / Append / Reget** for this file and **All / Update / Size
differs / None** for every remaining one (Up/Down switch rows). Append
and Reget - MC's resume - need a local file on both sides.

**Checksums**: F9 → File → *Checksum file (sha256)* writes a
`sha256sum`-format file for what is marked - `hash  name` lines, the
names relative to the file's own directory, so `sha256sum -c` reads it
and so does *Check the checksum file*, which hashes each named file
again and says how many matched and how many did **not**. That is the
checksum you hand to someone else; the **Verify** box on the copy form
is the one you keep to yourself - it reads every copy back and compares
it with the source, which is the only thing that turns "the write
returned no error" into "the bytes are there".

**Alt+Del wipes**: every byte of each file is overwritten once and
flushed to the device before it is unlinked. What that is worth is on
the confirm dialog, because the difference matters: the bytes that were
in those blocks are written over, but a copy-on-write filesystem writes
the zeroes somewhere else, an SSD's controller may do the same, and a
snapshot or a backup was never this file's to overwrite. It is a better
delete, not an erasure.

**Ctrl+G applies a command to each marked file**, one at a time:
`[[commands]]` hands every marked file to a single invocation, which is
the right shape for `tar` and the wrong one for `convert`. The command
is a template like any other (`%f` is the file, `%d` the directory) and
what runs is one line per file, in the terminal, where the output and
Ctrl+C are as they always are. A `%{question}` is refused here rather
than asked two hundred times.

**Ctrl+X u undoes the last move.** Every move F6 makes onto a name that
was free is recorded as it happens - and so is every rename a **bulk
rename** made, which used to be final the moment it finished - and `Ctrl+X u` asks before putting
the items back where they came from. It is an ordinary job - the same
progress, the same error prompts, the same Esc - and because the undo
is itself a move, a second `Ctrl+X u` is the redo. A move that landed
on a name that was already taken is not recorded: putting the source
back would not bring back what it overwrote, and an undo that quietly
destroyed something would be a second accident rather than the end of
the first. A pair whose file has since moved on, or whose old name is
occupied again, is left alone and counted as skipped. A copy leaves no
record either - undoing one means deleting what it wrote, which is a
deletion and should be asked for as one - and F8 has always gone to the
trash, which is where a deletion is undone.

Esc doubles as MC's meta prefix everywhere: after a lone Esc, a digit is
an F-key (Esc 1 = F1 … Esc 0 = F10) and any other key gets Alt added -
handy on terminals without working F-keys or Alt. Esc Esc is a real
Escape; an unanswered Esc acts as one after a second.

**Viewer** (F3): arrows/PgUp/PgDn/Home/End scroll, ←→ horizontal scroll,
F2 toggles soft-wrap, F4 toggles hex mode, F3/F10/Esc/q quit. Lines are
indexed lazily, so huge files open instantly; very long lines are broken
at 4096 columns. A file that never declares its length - anything under
`/proc` or `/sys`, or a block device - is read for it rather than shown
as empty. The bottom bar names what each key does *now*, as mc's
does: F2 says Unwrap once wrapping is on.

**F5**, `Alt+L` or `:` opens **goto**, which takes all three of mc's
destinations in one field, told apart by how the number is written: a
bare `201` is a line, `0x3e8` or `1000b` a byte offset, and `50%` a
share of the file. **`m`** followed by a digit sets one of ten marks at
the current position and **`r`** followed by the same digit returns to
it. `Alt+R` toggles a column ruler under the title, which counts from
the leftmost column on screen rather than from the start of the line,
so it keeps telling the truth when the view is scrolled sideways.

F7 or `/` opens mc's **search dialog**: the pattern, and the four
answers that change what it means. The pattern is read as **Normal**
(a literal), a **Regular expression**, or **Hexadecimal** bytes -
`7f454c46`, `7f 45 4c 46` and `0x7f 0x45 0x4c 0x46` are the same four,
and it is the only way to look for something that is not text. Alongside
it: **Case sensitive**, **Whole words** and **Backwards**. Tab and the
arrows move between rows, Space ticks, Enter searches; `n` repeats the
search with its options intact. Matches are highlighted in the line and
the found line is marked.

**F8** turns nroff formatting on: `_^Ht` and `t^Ht` - a character, a
backspace and another character, which is how a formatted man page has
said "underline" and "bold" since printers could only move forward -
are read as the attributes they stand for instead of showing up as
control bytes. The search follows the mode, so with formatting on the
word you can see is the word you can look for.

**F6** swaps the `[[view]]` filter in and out under the same file: the
parsed text from `pdftotext`, `tr`, `unzip -l` or whatever the rule
runs, or the file as it actually is. It is the in-viewer form of the
choice Shift+F3 makes when opening.

**Alt+!** (F9 > File > Filtered view) is the same thing for a command
typed on the spot: the field starts as the file name, the command goes
in front of it (`head -50 `, `strings `, `xxd | less`-style pipes are
fine, `%f` works too), and the output opens in the viewer as a filter
would, so F6 swaps the file itself back in.

**Ctrl+F** and **Ctrl+B** move to the next and previous file of the
panel without leaving the viewer, keeping wrap, hex, the ruler, the
formatting mode and the search - so reading through a directory is one
key per file. The panel cursor follows, which is where you land when
you quit.

In **hex mode** (F4), **F2** puts a cursor on the bytes. Hex digits type
over the byte it is on, two halves to a byte; Tab switches to the text
column, where a character stands for itself; arrows, PgUp/PgDn and
Home/End move it; **F6** writes the changed bytes into the file and Esc
stops editing. Nothing reaches the file until F6, changed bytes are
marked until then, and leaving with any still unwritten asks first.
Bytes are replaced, never inserted or deleted, so the file's length
never moves - which is what makes writing a handful of bytes into a
multi-GB file instant. Editing needs the file itself: on an archive
member, a remote file or a `[[view]]` filter's output the viewer is on a
copy, and it says so rather than writing to something about to be
deleted.

**Responsiveness**: directory listings that take longer than ~100 ms
(huge directories, cold network mounts) load in the background - the old
listing stays up with a spinner, typing never blocks, Esc cancels.
Panels also auto-reload when their directory changes on disk (debounced;
`watch = false` in the config disables it).

**Selecting and filtering**: `+` and `-` select and unselect by
pattern, and `Ctrl+F` filters what the panel shows at all. All three
are mc's one dialog: the pattern, then **Files only** (directories are
left alone, so a filter can never strand you), **Case sensitive**, and
**Shell patterns** - unticked, the pattern is a regular expression
instead of a glob. A regex that will not compile is quoted back at you
rather than silently matching nothing. The panel names the filter it is
under along its bottom edge, options included.

**Named filter sets** (`Ctrl+X f`) are Far's filter menu: `[[filter]]`
entries in the config, each a name and a mask list, and a list of
switches saying which of them this panel is under. Several can be on at
once, and what the panel then shows is **what any of them shows, minus
what any of them hides** - so a "sources" set of `*.c,*.h|*_test.*`
and a "notes" set of `*.md` switched on together show the sources and
the notes and still no tests. `Space` ticks a row, `a` switches them
all off (or all on again), Enter applies, and with nothing ticked the
panel is unfiltered. `Ctrl+F` stays what it always was: one glob, typed
on the spot.

```toml
[[filter]]
name = "sources"
mask = "*.c,*.h|*_test.*"

[[filter]]
name = "no build output"
mask = "|*.o,*.d,target/*"
```

Beside the pattern the same dialog asks DN's other two questions:
**Size** (`>1M`, `<=100k`, `1M-2G` - k/M/G/T, 1024-based as the panel
counts) and **Newer than** (`30m`, `24h`, `7d`, `2w`). Both are empty
by default and ask nothing; filled in, an entry has to satisfy all
three. Directories are never held to a size or an age - the number
beside a directory is not its own - so `+` with a size still leaves the
tree navigable. "Everything over a hundred megabytes" and "everything I
touched this week" were a trip through find and panelize before.

A shell pattern is a **list**, which is Far Manager's mask language and
what mc's single glob grows into: `*.c,*.h` is either of them, and a
`|` takes a second list back out again, so `*.c,*.h|*_test.*` is the
sources without the tests and `|*.o` is everything except objects.
Whitespace around a mask is not part of it, one mask is still one mask,
and the same list works in the find dialog's filename field. It is the
shell-pattern switch's language alone: with the switch unticked the
pattern is a regular expression, where `|` is the alternation it has
always been.

**Power tools**: Alt+F7 opens **find file** - where to start, a
filename pattern, and the text to look for inside the files, with mc's
answers beside them: **whole words**, **case sensitive**, **regular
expression** (matched line by line), **all charsets** (the same word as
another machine spelled it - KOI8-R, CP1251, Shift_JIS and the rest),
**skip hidden**, **follow symlinks**, and rcmd's own **skip
gitignored**. Matches arrive in a **results window** of their own as
they are found, with mc's six buttons: **Chdir** (Enter on a row) takes
the panel to the file and puts the cursor on it, **Again** reopens the
dialog on the same question, **Panelize** turns the list into the panel
listing, **View** and **Edit** open the match, and **Quit** closes.
`find_window = false` restores the pre-4.0 shape, where matches stream
straight into the panel as a *panelized* listing (paths relative to the
search root), where marking and F5/F6/F8 work as usual. *Panelize command…*
(F9 → Left/Right) turns any command's stdout lines into such a listing
(`git ls-files -m`, `rg -l TODO`, …). Its output **streams in as it
arrives**, so a slow command fills the panel while it runs and Esc
stops it. Commands worth keeping sit above the field as a saved list:
Tab moves between the list and the field, Ctrl+S saves what you typed
under a name, F8 drops one. They live in `[[panelize]]` entries in the
config, and the ones you save while running go to the state file. *Compare directories* (Ctrl+X d) asks
mc's question first - **Quick** (size and date), **Size only**, or
**Thorough** - and marks what differs on both sides, so a plain F5
copies the differences across. Thorough reads the files, which is the
only way to tell two files with the same size and date apart; it runs
in the background, marks each pair as it finds it, and Esc stops it.
Size only is for a tree whose timestamps were never going to survive
the trip.

**Synchronize directories** (F9 → Command) is what a comparison is for.
It asks the same Quick / Size only / Thorough question, runs the same
comparison, and then shows the **plan** instead of stopping at marks:
one row per difference, an arrow saying which way it would be copied -
the newer side wins, and a file only one side has crosses over - and a
note saying why the row is there. **Space** skips a row, **←/→** turn
one round, **a** switches them all off and on, **Enter** runs it as
ordinary copy jobs, one per direction. What it copies replaces what it
lands on *without* asking, because that is the question the plan
answered; a row left switched off is not copied at all. Marking the
differences and leaving F5 to guess the direction is where mc stops,
and that guess is wrong exactly when the differences run both ways.
Both sides have to be local, and directories are left alone - the
comparison has always been about the files in one directory, not the
tree under it.

**Compare files** (F9 → Command) puts the cursor file of each panel
side by side, lined up by a Myers diff: changed lines are highlighted
on both sides, a line only one file has shows opposite a `~~~` gap, and
`n` and `p` walk from one difference to the next (it opens on the first
one). `q` closes it. It is a screen like the viewer and the editor, so
``Alt+` `` lists it and you can leave it open while you do something
else.

**Mouse**: click focuses a panel and moves the cursor, double-click
enters, the wheel scrolls whatever it hovers (panels, viewer, editor,
quick view), the bottom keybar and the F9 menu are clickable, and a
click in the editor places the cursor. All additive - every feature
stays keyboard-reachable. Hold Shift to select terminal text as usual;
`mouse = false` in the config turns capture off entirely.

**Panel history**: each panel remembers where it has been -
Alt+←/Alt+→ walk back and forward browser-style (sftp:// locations
reconnect through the connection cache), Alt+Shift+H lists the whole
history with `*` on where the panel is now and Enter moving the cursor
there, Alt+↑ opens the hotlist.

**Ctrl+X 0…9 are Far's folder shortcuts**, and they are hotlist
entries whose label is that digit: `Ctrl+X 3` goes to the one labelled
`3`, and if there is no such entry it makes one here and says so. There
is nothing new to store or forget - the hotlist already persists,
reorders and renames, and a shortcut is a hotlist entry with a very
short name.

**Recent files** (F9 → File) is what the viewer and the editor have
opened, newest first, kept between sessions - the one history you want
right after closing a screen. Enter puts the panel on the file, cursor
and all.

**The hotlist remembers where you go.** Under your own entries it lists
everywhere rcmd has been, ranked the way zoxide ranks directories -
how often you went there, weighted by how recently, so three visits
this morning beat ten last year and neither is forgotten - and the log
is kept in the state file, so it is still there next session. **Ctrl+S**
narrows the whole list by what you type (Backspace edits it, Esc drops
it), which on a list already sorted by where you actually work is one
key and three letters to anywhere.

**Quick view** (Ctrl+X q): the other panel becomes a live preview of
the file under the cursor, updating as you move. It uses the viewer's
chunked reader, so previewing a multi-GB log is instant. Tab focuses
the preview for scrolling (arrows/PgUp/PgDn); Ctrl+X q turns it off.

**Openers & user commands**: `[[open]]` rules in the config make Enter
open files by type - the first matching rule wins:

```toml
[[open]]
match = "*.pdf"              # a mask list, case-insensitive
run = "zathura %f >/dev/null 2>&1 &"

[[open]]
type = "^ELF"                # a regex over what `file -b` says of it
run = "objdump -d %f | less"

[[open]]
regex = "^[a-z]+[0-9]+\\.log$"  # a regex on the name ((?i) folds case)
directory = "^/var/log/"       # ...and one on the panel's path
run = "less %f"
```

Those are mc.ext's four matchers (`match`, `regex`, `type`,
`directory`); every one a rule gives must hold. `match` takes the same
**mask list** the select and filter dialogs do, so
`match = "*.jpg,*.png|thumb_*"` is one rule rather than two and an
exception; so does `[[highlight]]`'s. `file` is only asked
when a rule has `type =`, and `[[view]]` rules take the same keys.

A file no rule claims goes to the **desktop** - `xdg-open`, or `open`
on macOS - as long as there is a display (`$DISPLAY` or
`$WAYLAND_DISPLAY`) to open it on; over a bare ssh Enter stays quiet,
since the browser would open on the wrong machine. `desktop_open =
false` switches the fallback off; a `[[open]]` rule always wins.

Openers run without a "press Enter" pause, so terminal programs (mpv,
less) feel native and GUI programs just need a trailing `&`. With
lynx-like motion on, Right still only enters directories - Enter opens.
`[[commands]]` are named shell templates listed in the **F2 user menu**
(first nine get digit hotkeys) and optionally bound directly:

```toml
[[commands]]
name = "git status"
run = "git status | less"
key = "ctrl+g"

[[commands]]                     # only offered where it makes sense
name = "extract here"
run = "tar xf %f"
when = "f *.tar.gz | f *.tgz"

[[commands]]                     # a submenu: Enter walks in, ← walks out
name = "Tools"
entries = [
  { name = "line count", run = "wc -l %s" },
]
```

`when` is **mc's user-menu condition language**: `f`/`F` the cursor file
here or in the other panel, `d`/`D` the directory, `t`/`T` the file's
type (`r` regular, `d` directory, `l` link, `x` executable, `n` not a
directory, `t` something is marked), `x` a program that must exist,
`!` to negate, `|` and `&` to join - evaluated left to right, as mc
evaluates them. Patterns are globs.

A **`.mc.menu` in the panel's directory** is read too, in mc's own
format (`shell_patterns=0` files have their regexes converted). Its
entries come first and the configured ones stay after them: a project's
menu is an addition to yours, where mc's would have replaced it.

Both expand **mc's macros** before running in the active panel's
directory, everything shell-quoted:

| Macro | This panel | Other panel |
|---|---|---|
| cursor file | `%f` | `%F` |
| directory | `%d` | `%D` |
| marked files | `%t` | `%T` |
| marked files, and drop the marks | `%u` | `%U` |
| marked files, or the cursor file if none | `%s` | `%S` |

`%q` is the clipboard file (`~/.cache/mc/mcedit/mcedit.clip`, shared
with mcedit - rcmd's editor writes it too), `%%` a literal percent, and
`%{Some question}` **asks** before the command runs, putting the answer
in unquoted, which is how options get passed. Anything else is left
alone, so `printf '%%s'` needs its percent doubled like everywhere else.

**File properties**: the info panel (Ctrl+X i) turns the other panel
into a live stat display of the file under the cursor - type, size,
permissions, owner and group (resolved locally, numeric on SFTP),
hard links, inode, and all three timestamps - plus the filesystem's
free space, which also shows in every local panel's footer. Listing
formats are switchable per panel from F9 → Left/Right: *brief* (names only,
full width), *full* (the classic name/size/mtime), and *long*
(ls-style perms/owner/group/size/name). A long listing needs room, so
while the *active* panel is long it takes the whole width and the
other panel is hidden - MC's one-panel view; Tab to the other panel
(or cycle the format back) and the split returns. The choice persists
in the config (`listing`).

**Git awareness**: inside a git work tree the panel title shows the
branch (`[main]`) and each entry gets a one-cell status column -
`M` modified, `A` added, `?` untracked, `!` ignored (ignored entries
are dimmed); changes deep inside a subdirectory mark the subdirectory.
Statuses are computed on a background thread so huge repositories never
block the UI. Built behind the default-on `git` cargo feature;
`git = false` in the config disables it at runtime.

**Archives**: Enter on a `.zip`, `.tar` or `.cpio` - plain or wrapped in
`.gz`, `.xz`, `.bz2` or `.zst`, with the usual short spellings
(`.tgz`, `.txz`, `.tbz2`, `.tzst`) - browses it like a directory (the
panel title shows `archive://path`). cpio is read in all three of its
header shapes - `newc`/`crc`, the portable octal `odc`, and the old
binary one in either byte order - and a hard link inside one lists and
opens as the file it shares its bytes with.

`ar` archives open too, which is how a `.a` static library lists its
members, and a **Debian package** (`.deb`, `.udeb`) opens as one tree
rather than three: `debian-binary` at the root, the metadata and
maintainer scripts under `CONTROL/`, and everything the package
installs under `CONTENTS/`.

**FISH**: `cd fish://[user@]host[:port][/path]` puts a panel on a
server that has a shell but no SFTP subsystem. It is the same SSH
connection, the same authentication and the same host-key dialog; what
differs is what happens after login. Every operation is one small
command, and the listing comes back as NUL-separated records rather than
`ls -l` output, so a filename containing a space, a newline or a `->`
survives - which `ls -l` cannot promise. `stat(1)` is used where the
server has it and an `ls`-based fallback where it does not.

**FTP**: `cd ftp://[user[:password]@]host[:port][/path]` connects a
panel to an FTP server - no user means the anonymous login. Listings
prefer `MLSD`, which says what everything is, and fall back to `LIST`
where the server is too old for it. Browsing, F3, F5 in both directions,
F6, F7 and F8 all work; FTP has no symlinks and no way to change
ownership, so those report that rather than pretending. Every transfer
needs a connection of its own, so a small pool of logged-in ones is kept
and reused: one login covers a whole session of listing and copying.

**rclone**: `cd rclone://<remote>[/path]` puts a panel on anything
rclone reaches - S3, Google Drive, Dropbox, B2, WebDAV, Swift and the
forty-odd others - using the config rclone already has on that machine.
Listing, F3 and F5 **out** work; the panel is read-only, because
writing back is rclone's `copyto` and belongs with the progress
reporting rather than with the listing. One integration instead of
forty protocols is the whole argument: `rclone lsf` and `rclone cat`
are a smaller thing to depend on, and a much smaller thing to get
wrong. Without rclone installed, opening one says so.

**Ctrl+X A** lists everywhere a panel can go: the open archives and
live SFTP connections, with the panel each one belongs to, and under
them **what the machine has mounted** - every mount point `df` knows,
with what it is and how much room is left. Enter goes there (a
connection is reused, so no second login), `f` frees a connection or an
archive - the panel returns to a local directory and an idle connection
is forgotten - and a mount point says it is not rcmd's to free.
**Alt+F1** and **Alt+F2** open the same list for the **left** and
**right** panel by name rather than for the active one, which is where
Far keeps its drive menu.

**rar, 7z, lha/lzh, arj and cab** browse through an installed `7z`
(p7zip - rar needs its nonfree codec) or `unrar`, read-only and streamed
one member at a time. Without one of those tools installed, opening one
says which tool it wants rather than failing silently.

An **mbox** (`.mbox`, `.mbx`, plain or compressed) browses as the
messages in it, each numbered so name order is arrival order and named
by its subject - decoded, since real mail writes subjects as
`=?UTF-8?B?...?=`. Opening one gives an ordinary RFC 822 message,
without the `From ` separator line the mbox format puts between them.

A **patch** (`.patch`, `.diff`, plain or compressed) browses as the tree
it would apply to: one entry per file it touches, holding that file's
hunks and nothing else, filed under the directories its paths name.
Unified, git, context and Subversion headers all start a section.
Nothing is applied or reversed - this is a way of reading a patch, not
of using one.

An **ISO 9660 image** (`.iso`) browses in place. **Rock Ridge** names,
modes and symlinks are used where the disc carries them, **Joliet**'s
UTF-16 names where it does not, and the base format's shouted 8.3 names
(minus the `;1` version suffix) where it has neither.

An **RPM package** (`.rpm`, source packages included) takes the same
shape. `CONTROL/header` is the package's tags rendered as text - name,
version, license, summary, description, what the payload is wrapped in -
and any install scriptlets sit beside it as `prein`, `postin`, `preun`,
`postun`. `CONTENTS/` is the payload, which is a cpio stream under gzip,
xz, lzma, bzip2 or zstd. Signatures are stepped over, not checked: a
listing is not a claim that a package is authentic. F5 copies members out with the
usual progress/overwrite dialogs, F3 views them; move, delete, and mkdir
are disabled inside. Copying **into** an archive works for zip and tar: F5 with the
destination panel inside one, or any destination written as
`path/to/archive.zip://dir`. A member with the same name is **replaced**,
not shadowed by a second copy of the name. The archive index loads once
at open; each member read decodes only that member.

**Alt+F5 packs**: the marked entries (or the one under the cursor) go
into an archive of their own. The **name decides the container** -
`.zip`, `.tar`, `.tar.gz`/`.tgz`, `.tar.xz`/`.txz`, `.tar.bz2`/`.tbz2` -
and it is offered in the other panel's directory, named after the single
entry or after the directory holding several, the way either would have
been named by hand. One entry or a whole tree goes in; a name that is
already an archive is added to rather than replaced, which is the same
thing F5 into an open one does. Anything rcmd cannot write itself says
so rather than producing an empty file.

Inside a `.zip` or `.tar`, **F8 deletes**, **F6 renames** (type a bare
name - an absolute one would mean leaving the archive, which is a copy)
and **F7 makes a directory**. Each batch rewrites the container once, so
deleting five members costs one rewrite rather than five, and the
original is only replaced when the new one is complete. The other
formats - deb, rpm, iso, cpio and the 7z-backed ones - stay read-only.

**Editor** (F4): a built-in mcedit-style editor. F2 saves (atomically,
preserving permissions and CRLF line endings), F3 starts marking
(Shift+arrows also select), Ctrl+C/X/V copy/cut/paste, Ctrl+Z/Ctrl+Y
undo/redo (unlimited, with typing bursts grouped), F7 searches with a
smartcase regex and Shift+F7 repeats, F4 replaces interactively
(Replace / Skip / All / Quit), F8 deletes the selection or line, Enter
auto-indents, Ctrl+arrows hop words, and F10/Esc quits (asking
Save/Discard/Cancel when modified). Known file types get syntect syntax
colors (skipped for files over 2 MB - a 50 MB log still opens in about
0.2 s). On an SFTP panel F4 edits a local scratch copy and uploads it
back when you close the editor. Set `editor = "external"` in the config
to keep using $VISUAL/$EDITOR.

**F9 in the editor** opens its own menu bar - File, Edit, Search,
Options - over the title row, with every entry naming the key that
already does it: the menu is how you find the key, not a second way of
working. **Options > General** is mc's editor options dialog: **tab
size**, **fill tabs with spaces** (Tab inserts spaces up to the next
stop, so the file has no tabs in it), **return does autoindent**,
**backspace through tabs** (inside an indent one Backspace takes the
whole stop rather than one space of it) and the **wrap column** the
soft wrap folds at - `window` means the window's width, which is mc's
dynamic wrapping. Left/Right nudge the numbers, Space ticks the
switches, and OK applies them to the open editor and remembers them for
the next session. They are `edit_tab_size`, `edit_fill_tabs`,
`edit_auto_indent`, `edit_backspace_tabs`, `edit_wrap_column`,
`edit_line_numbers`, `edit_backups` and `edit_clipboard` in the config
file. **Options > Syntax** picks the highlighting by hand - every
syntax syntect knows, or plain text - for a file whose name does not
say what it is.

**Getting around, and bookmarks**: `Alt+L` goes to a line by number,
`Alt+K` bookmarks the line the cursor is on, `Alt+J` and `Alt+I` walk
to the next and previous bookmark, and `Alt+O` drops them all. A
bookmark follows its text: inserting or deleting lines above one moves
it with what it marked, rather than leaving it pointing at whatever
slid into that line number. `Alt+N` draws mc's line-number gutter, with
a `*` beside a bookmarked line so the bookmarks can be seen and not
only jumped to. `Ctrl+U` undoes, as it does in mc, beside rcmd's
`Ctrl+Z`.

**The desktop clipboard**: Ctrl+C and Ctrl+X also put the text on the
system clipboard and Ctrl+V reads it, through `wl-copy`, `xclip`,
`xsel` or `pbcopy` - whichever is installed. With none of them there,
or with nothing in the clipboard, the editor's own clipboard stands, so
copy and paste inside rcmd work either way. `edit_clipboard = false`
keeps it to the editor.

**Backups**: with `edit_backups` on, every save first copies what is on
disk to `file~` - mc's "Do backups", one step back rather than a
history.

**Codepages** (`Alt+E`): a file is bytes, and nothing in it says what
they mean - so `Alt+E` in the viewer, the editor **or a panel** picks
the codepage to read it in: UTF-8, the Latin and Cyrillic and Greek and Baltic
single-byte sets, KOI8-R/U, CP866, and Shift_JIS, EUC-JP, GBK, Big5 and
EUC-KR. The viewer re-reads at once (and the search follows, because it
reads what you can see); the editor re-reads and **writes back in the
same codepage**, so editing a KOI8-R file leaves a KOI8-R file. Since
changing it means re-reading, the editor asks you to save first rather
than dropping an edit. The title bar names the codepage whenever it is
not UTF-8.

On a **panel** (`Alt+E`, or Left/Right → Character set) the codepage is
what the *filenames* are read in. Unix names are bytes, so a directory
written on a CP1251 or KOI8-R machine shows as replacement characters
until the panel is told - and then it reads, sorts, filters and quick-
searches as text. Names typed into a dialog on that panel are written
back in the same codepage, so the file you make is the file the panel
then shows. The panel title names the codepage while one is set.

**Screens** (``Alt+` ``): several editors and viewers can be open at
once. ``Alt+` `` lists them - the panels are the first row, then every
open screen with what it is on and whether it has unsaved changes - and
Enter switches. Closing a screen (F10 in the editor, q in the viewer)
lands back on the panels, which is where mc puts you too. Quitting rcmd
with an editor still holding unsaved changes says how many and asks,
whether or not the ordinary exit question is switched on.

**Remote filesystems (SFTP)**: `cd sftp://[user@]host[:port][/path]`
(or F9 → Left/Right → SFTP link) connects a panel to a server - user
defaults to your login, path to the remote home. Authentication tries
your ssh-agent, then the default `~/.ssh/id_*` keys, then asks for a
password; host keys are checked against `~/.ssh/known_hosts`, and
unknown hosts show a fingerprint dialog before being saved. The panel
title shows the URL. Everything works panel-normally: F5/F6 transfer
between local and remote (or between two remote directories) with the
usual progress/overwrite dialogs, F7 creates server directories, F8
deletes on the server (permanently - there is no remote trash), F3
views, and F4 edits a local scratch copy that is uploaded back when the
editor saved it. `cd path` stays on the server; plain `cd` (or any `~`
path) returns the panel to the local filesystem, and closing the last
remote panel closes the connection. Both panels can share one
connection - put the same host on both sides, or compare a local tree
against a remote one with Ctrl+X d and F5 the differences across. The
hotlist stores sftp:// entries, so `Ctrl+\` + Enter reconnects.

## Driving rcmd from outside

Every instance listens on a unix socket of its own, and `rcmd --remote`
hands it one line:

```sh
rcmd --remote 'cd /var/log'        # move the active panel
rcmd --remote 'select *.log'       # mark by mask (prints how many)
rcmd --remote 'action sort-size'   # any action, by the name a key would bind
rcmd --remote pwd                  # ...and the questions a script asks
rcmd --remote cursor               # the file under the cursor
rcmd --remote marked               # what is marked, space separated
```

The vocabulary is small on purpose, because `action` is the whole
keymap: anything rcmd can be told to do by a key can be asked for by
name (`rcmd --remote 'action listing-brief'`). `status TEXT` puts a
line on the status row, which is how a script says it finished.

With several instances running, name one with `--to PID`; a command
**rcmd itself started** - a `[[commands]]` entry, anything typed in the
subshell - needs no such thing, because it is handed `RCMD_SOCKET` in
its environment and `--remote` follows it. That is the whole plugin
story: a shell script that can cd the panel, mark files and run any
action is a plugin, and it needs no ABI, no embedded runtime and no
versioned interface to be one.

```toml
[[commands]]
name = "jump to the newest log"
run = 'rcmd --remote "cd /var/log" && rcmd --remote "select *.log"'
```

The socket lives in `$XDG_RUNTIME_DIR/rcmd/<pid>.sock` (or
`/tmp/rcmd-<uid>/` where there is no runtime directory), the directory
0700 and the socket 0600: anyone who can reach it can already run
commands as you. It goes when the instance does, and a socket left
behind by a crash is cleaned up the next time something looks for one.

## Configuration

`~/.config/rcmd/config.toml` is **yours** - rcmd only ever reads it, so
comments and hand formatting survive. Everything rcmd changes itself
(panel sort mode, hidden files, listing format, the hotlist, and every
options-form toggle) goes to `$XDG_STATE_HOME/rcmd/state.toml`
(`~/.local/state/rcmd/state.toml` by default) and takes precedence over
the config file. State is sparse - only keys you actually changed in the
UI are stored, so a config edit keeps working for everything else - and
writes merge into the on-disk file, so several rcmd instances never
clobber each other. The state keys (`show_hidden`, `sort_key`,
`sort_reverse`, `listing`, `[[hotlist]]`) are still read from
`config.toml` as your defaults; what the UI changes goes to the state
file on top of them.

The settings live in one sectioned checkbox form under **F9 → Options →
Panel options**, applied live: *Layout* (split direction and size, the
per-panel mini status, and which of the menu bar / status line /
command line / key bar are drawn), *Panel* (hidden files, lynx-like motion,
mouse, auto-reload, git), *Confirmation* (ask before deleting /
overwriting / quitting) and *Shell and editor* (persistent subshell,
internal or external editor). The theme has a list of its own under
**F9 → Options → Appearance**, because a skin is one of however many
files are installed rather than a two-way switch:

```toml
theme = "mc"        # "dark", "bw", or the name of a theme file
keymap = "mc"       # or "modern" (= lynx-like motion on by default)
lynx = false        # Left/Right = parent/enter; in the options form
watch = true        # auto-reload panels on external changes
restore_other_dir = true  # the other panel starts where it was left
mouse = true        # click/double-click/wheel support
git = false         # git status column + branch in panel titles (off by
                    # default since 4.10: it is a column on every row)
editor = "internal" # or "external" ($VISUAL/$EDITOR for F4)
subshell = true     # persistent $SHELL behind Ctrl+O (false = one-shot exec)
brief_columns = 2          # name columns in the brief listing (1..6)
split = "vertical"         # or "horizontal" (panels stacked)
split_ratio = 50           # percent for the left/top panel, 20..80
show_menubar = false       # MC's permanent menu bar (F9 works either way; the window has its own)
show_mini_status = false   # a status row inside each panel (MC's)
show_free_space = true     # free space in each local panel's footer
show_status = true         # the cursor-entry row inside the active panel
                           # (messages and job progress show there too)
show_cmdline = true        # the command line
show_keybar = true         # the F1..F10 bar along the bottom
confirm_delete = true      # ask before F8 / Shift+F8
confirm_overwrite = true   # ask before overwriting during copy/move
confirm_exit = false       # ask before F10 quits (MC asks; rcmd does not)
confirm_hotlist_delete = true   # ask before dropping a hotlist entry
confirm_execute = false    # ask before Enter runs an [[open]] command
esc_timeout_ms = 250 # how long a lone Esc waits for its meta follow-up
                     # (1000 = MC's roomier window for typing Esc 1..0)
edit_tab_size = 8          # the built-in editor, F9 > Options > General
edit_fill_tabs = false     # Tab inserts spaces up to the next stop
edit_auto_indent = true    # Enter copies the line's leading whitespace
edit_backspace_tabs = false  # in an indent, Backspace takes a whole stop
edit_wrap_column = 0       # column the soft wrap folds at; 0 = the window
find_window = true         # find file: matches in a window of their own
desktop_open = true        # Enter on a file no [[open]] rule claims: xdg-open
                           # (open on macOS) when there is a display
                           # (false = straight into the panel listing)
edit_line_numbers = false  # the line-number gutter (Alt+N toggles it)
edit_backups = false       # keep the previous contents as file~ on save
edit_clipboard = true      # share the desktop clipboard (wl-copy/xclip/...)
show_hidden = true
sort_key = "name"   # name | ext | size | mtime | atime | ctime
                    # | owner | group | unsorted
sort_reverse = false
listing = "full"    # brief | full | long | tree | user
# "user" draws listing_format: a panel size (half/full), an optional
# repeat count 1-9, then fields with optional :width (:width+ grows) -
# name size bsize type mark mtime atime ctime perm mode nlink ngid nuid
# owner group inode, plus "space" and "|". MC's Full listing written out:
listing_format = "half type name | size | mtime"

[window]            # the window build only; see "In a window"
font = "DejaVu Sans Mono"   # family name or a .ttf/.otf path
font_size = 14

[keys]              # custom bindings on top of the preset
"ctrl+y" = "swap-panels"     # bare entries bind in the panel
[keys.viewer]                # ...and these inside the F3 viewer
"ctrl+w" = "wrap"            # quit wrap hex search search-next follow
                             # goto set-mark go-mark ruler nroff raw
                             # next-file prev-file hex-edit hex-save
[keys.dialog]                # ...and these wherever a dialog is open
"ctrl+j" = "ok"              # ok cancel next prev - a bound key stands
                             # in for Enter / Esc / Tab / Shift+Tab
[keys.editor]                # ...and these inside the F4 editor
"ctrl+q" = "quit"            # save quit mark replace search search-next
                             # block-copy block-move delete-line undo
                             # redo copy cut paste select-all wrap menu
                             # goto bookmark bookmark-next bookmark-prev
                             # bookmark-clear line-numbers
# key syntax:  [ctrl+][alt+][shift+]<key>  (f1..f20, letters, +, -, etc.)
# actions: help view edit copy move mkdir delete delete-perm select-group
#   unselect-group invert-selection quit shell reload swap-panels
#   toggle-hidden sort-name sort-ext sort-size sort-mtime sort-reverse
#   menu mark quick-search hotlist filter up-dir enter history-back
#   history-forward quick-view info-view user-menu listing-brief
#   listing-full listing-long listing-tree listing-user listing-cycle
#   other-same-dir other-open-dir sftp-link find-file panelize
#   compare-dirs dir-size dir-tree appearance learn-keys edit-config

[[highlight]]          # MC's filehighlight, as rules: first match wins
match = "*.tar.gz"     # a mask list on the name (*.c,*.h|*_test.*)...
color = "brightred"    # ...mc's colour names, #rrggbb or "default"

[[highlight]]
type = "exe"           # ...or what the entry is: dir linkdir exe link
color = "magenta"      #    broken file
bold = true            # optional; left out, the kind's own weight stands

[[hotlist]]                 # Ctrl+\ - a tree, as in mc
label = "projects"
path = "/home/you/git"

[[hotlist]]                 # an entry with `entries` is a group to
label = "Work"              # walk into rather than a place to go
entries = [
  { label = "api", path = "/srv/api" },
]

[[open]]                    # Enter on a matching file runs this
match = "*.pdf"             # match (glob) / regex (name) / type (file -b)
run = "zathura %f >/dev/null 2>&1 &"   # / directory (path): all given must hold

[[panelize]]                # saved panelize commands (Ctrl+S adds one)
name = "modified"
run = "git ls-files -m"

[[commands]]                # F2 user menu; key = "..." binds directly
name = "git status"
run = "git status | less"
```

### Syntax files

The editor highlights with syntect, which speaks **`.sublime-syntax`**.
Drop your own into `~/.config/rcmd/syntax/` and they join the built-in
list - by extension, and in F9 > Options > Syntax inside the editor.
A file that will not parse costs itself and a note on the editor's
status line, never the highlighting of everything else. (mc's own
syntax format is a different language and is not read.)

### Skins

A theme that is not one of the three built in (`mc`, `dark`, `bw`) is a
file, looked up by name in `~/.config/rcmd/themes/` and then in mc's
skin directories - `~/.local/share/mc/skins`, `/usr/local/share/mc/skins`,
`/usr/share/mc/skins`. rcmd's own format is TOML naming the fields it
sets, over an optional base, so a skin can be three lines:

```toml
base = "dark"            # mc | dark | bw - the palette to patch (default mc)
dir_fg = "brightblue"
panel_bg = "#1e222a"
header_fg = "color214"
```

The fields are `panel_fg` `panel_bg` `dir_fg` `exec_fg` `broken_fg`
`header_fg` `mark_fg` `select_fg` `select_bg` `dialog_fg` `dialog_bg`
`error_fg` `error_bg` `help_fg` `help_bg` `help_header_fg` `prompt_fg`
`key_fg` `key_bg` `label_fg` `label_bg` `menu_fg` `menu_bg`
`menu_hot_fg` `menu_sel_fg` `menu_sel_bg` `dialog_hot_fg`. A colour is
one of mc's names
(`black`, `brightgreen`, `brown`, `lightgray`, ...), `#rrggbb`,
`colorN` (0-255), `rgbRGB` (three digits 0-5), `grayN` (0-23), or
`default` for the terminal's own.

**mc's skins work as they are**: `-S julia256` reads
`/usr/share/mc/skins/julia256.ini` and maps its `[core]`, `[dialog]`,
`[error]`, `[help]`, `[filehighlight]` and `[buttonbar]` sections onto
those fields. What rcmd draws for itself - the frames, the menus - is
not taken from the skin, so a skin is read for its colours and nothing
else. **F9 → Options → Appearance** lists everything found and switches
on Enter, and the choice outlives the session.

## Development

```sh
cargo test --workspace                              # unit tests (rcmd-core is TUI-free)
cargo clippy --workspace --all-targets -- -D warnings
python3 tests/e2e/run.py                            # drives the real binary in a pty
just check                                          # all of the above
just gui                                            # the window build
```

The e2e suite drives `rcmd` through a pty and so covers only the
terminal front end; what the two share is covered by the unit tests
either way. `rcmd-egui` can render a frame and exit without a pair of
eyes on it, which is how `docs/rcmd-egui.png` is made:

```sh
cargo run -p rcmd-egui --features screenshot   # writes $EFRAME_SCREENSHOT_TO
RCMD_EGUI_KEYS='ctrl+o,l,s,enter' cargo run -p rcmd-egui  # keys, as if typed
```

`$RCMD_EGUI_KEYS` plays keys in one per frame, spelled the way
`config.toml` spells them, which is how the pictures above of screens
that need a keystroke were taken. (A literal comma cannot be spelled: it separates.)

The e2e suite includes an SFTP scenario that spins up a local paramiko
server (`pip install paramiko`; skipped when unavailable).

Workspace layout: `crates/rcmd-core` (panel/fs logic, no TUI deps),
`crates/rcmd-edit` (editor buffer/undo/search, TUI-free; syntect behind
the `syntax` feature), `crates/rcmd-tui` (the file manager itself, as a
library, plus the terminal binary `rcmd`), and `crates/rcmd-egui` (the
window front end, the binary of the same name, ~3,100 lines on top of
that library). CI runs fmt, clippy and the unit tests on Linux and macOS, and
the pty e2e suite on Linux - it drives the binary through `/dev/pts`
and installs shells to test them, which is a Linux job. Licensed MIT.