fm/modes/menu/
help.rs

1use anyhow::Result;
2use strfmt::strfmt;
3
4use crate::config::Bindings;
5use crate::event::ActionMap;
6use crate::io::Opener;
7
8const CUSTOM_HELP: &str = "
9- CUSTOM ACTIONS -
10%s: the selected file,
11%f: the flagged files,
12%e: the extension of the file,
13%n: the filename only,
14%d: the full path of the current directory,
15%t: execute the command in the same window,
16%c: the current clipboard as a string.
17";
18
19/// Creates the help `String` from keybindings.
20/// If multiple keybindings are bound to the same action, the last one
21/// is displayed.
22/// If an action displayed in help isn't bound to a key, the formating won't
23/// be possible. We use the default keybindings instead.
24/// If it doesn't work, we return an empty string.
25pub fn help_string(binds: &Bindings, opener: &Opener) -> String {
26    match make_help_with_config(binds, opener) {
27        Ok(help) => help,
28        Err(error) => {
29            crate::log_info!("Error parsing help: {error}");
30            let mut help = format!(
31                "Couldn't parse your keybindings: {error}.
32Using default keybindings.
33
34"
35            );
36            help.push_str(&make_help_with_config(&Bindings::new(), opener).unwrap_or_default());
37            help
38        }
39    }
40}
41
42macro_rules! action_descriptions {
43    ( $( $name:ident ),* $(,)? ) => {
44        format!(
45            concat!(
46                $(
47                    "{{", stringify!($name), ":<10}}:      {}\n",
48                )*
49            ),
50            $(
51                ActionMap::$name.description(),
52            )*
53        )
54    };
55}
56
57/// Help message to be displayed when help key is pressed.
58/// Default help key is `'h'`.
59fn format_help_message() -> String {
60    format!(
61        "
62{quit}
63
64- Navigation -
65{navigation}
66
67- Actions -
68{actions}
69    - default       {{Default}}
70    - audio         {{Audio}}
71    - images        {{Bitmap}}
72    - office        {{Office}}
73    - pdf, ebooks   {{Readable}}
74    - text          {{Text}}
75    - video         {{Video}}
76    - vectorials    {{Vectorial}}
77    - compressed files are decompressed
78    - iso images are mounted
79
80{more_actions}
81
82- Action on flagged files -
83{flagged_actions}
84
85- Trash -
86{trash_actions}
87
88- Tree -
89Navigate as usual. Most actions work as in 'normal' view.
90
91{tree_actions}
92
93    - DISPLAY MODES -
94Different modes for the main window
95{display_modes}
96
97    - EDIT MODES -
98Different modes for the bottom window
99{menu_modes}
100",
101        quit = action_descriptions!(Quit, Help),
102        navigation = action_descriptions!(
103            MoveLeft, MoveRight, MoveUp, MoveDown, KeyHome, End, PageUp, PageDown, Tab
104        ),
105        actions = action_descriptions!(
106            ToggleDualPane,
107            TogglePreviewSecond,
108            ToggleDisplayFull,
109            ToggleHidden,
110            Shell,
111            OpenFile,
112            NvimFilepicker,
113            NvimSetAddress,
114            Preview,
115            Back,
116            Home,
117            GoRoot,
118            GoStart,
119            MarksNew,
120            MarksJump,
121            TempMarksNew,
122            TempMarksJump,
123            SearchNext,
124            FuzzyFind,
125            FuzzyFindLine,
126            FuzzyFindHelp,
127            RefreshView,
128            CopyContent,
129            CopyFilename,
130            CopyFilepath,
131            OpenConfig,
132            CloudDrive,
133        ),
134        more_actions = action_descriptions!(Action),
135        flagged_actions = action_descriptions!(
136            ToggleFlag,
137            ToggleFlagChildren,
138            FlagAll,
139            ClearFlags,
140            ReverseFlags,
141            Symlink,
142            CopyPaste,
143            CutPaste,
144            Delete,
145            TrashMoveFile,
146            Compress,
147            FlaggedToClipboard,
148            FlaggedFromClipboard,
149            ToggleVisual,
150        ),
151        trash_actions = action_descriptions!(TrashOpen, TrashEmpty),
152        tree_actions = action_descriptions!(
153            Tree,
154            TreeFold,
155            TreeFoldAll,
156            TreeUnFoldAll,
157            TreeDepthIncr,
158            TreeDepthDecr
159        ),
160        display_modes = action_descriptions!(ResetMode, Tree, Preview),
161        menu_modes = action_descriptions!(
162            Chmod,
163            Exec,
164            NewDir,
165            NewFile,
166            Rename,
167            Cd,
168            RegexMatch,
169            Sort,
170            History,
171            Shortcut,
172            Mount,
173            Search,
174            Action,
175            Bulk,
176            TuiMenu,
177            CliMenu,
178            RemoteMount,
179            Filter,
180            DisplayFlagged,
181            Context,
182            Enter
183        ),
184    )
185}
186
187fn make_help_with_config(binds: &Bindings, opener: &Opener) -> Result<String> {
188    let mut keybind_reversed = binds.keybind_reversed();
189    keybind_reversed.extend(opener.association.as_map_of_strings());
190    let mut help = strfmt(&format_help_message(), &keybind_reversed)?;
191    help = complete_with_custom_binds(&binds.custom, help);
192    // std::fs::write("help.txt", &help)?; // keep here to save a new version of the help content
193    Ok(help)
194}
195
196fn complete_with_custom_binds(custom_binds: &Option<Vec<String>>, mut help: String) -> String {
197    if let Some(customs) = &custom_binds {
198        help.push_str(CUSTOM_HELP);
199        for custom in customs {
200            help.push_str(custom);
201        }
202    }
203    help
204}