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
19pub 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
57fn 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 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}