Skip to main content

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