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
use clap::{Parser, Subcommand, ValueEnum};
use regex::Regex;
use std::path::PathBuf;
/// Fly through your shell history
#[derive(Parser)]
#[command(author, version)]
pub struct Cli {
#[command(subcommand)]
pub command: SubCommand,
/// Debug
#[arg(short, long)]
pub debug: bool,
/// Session ID to record or search under (defaults to $`MCFLY_SESSION_ID`)
#[arg(long = "session_id")]
pub session_id: Option<String>,
/// Shell history file to read from when adding or searching (defaults to $`MCFLY_HISTORY`)
#[arg(long = "mcfly_history")]
pub mcfly_history: Option<PathBuf>,
/// Shell history file format
#[arg(
value_name = "FORMAT",
value_enum,
long = "history_format",
default_value_t
)]
pub history_format: HistoryFormat,
}
#[derive(Subcommand)]
pub enum SubCommand {
/// Add commands to the history
#[command(alias = "a")]
Add {
/// The command that was run (default last line of $`MCFLY_HISTORY` file)
command: Vec<String>,
/// Exit code of command
#[arg(value_name = "EXIT_CODE", short, long)]
exit: Option<i32>,
/// Also append command to the given file (e.q., .`bash_history`)
#[arg(value_name = "HISTFILE", short, long)]
append_to_histfile: Option<String>,
/// The time that the command was run (default now)
#[arg(value_name = "UNIX_EPOCH", short, long)]
when: Option<i64>,
/// Directory where command was run (default $PWD)
#[arg(value_name = "PATH", short, long = "dir")]
directory: Option<String>,
/// The previous directory the user was in before running the command (default $OLDPWD)
#[arg(value_name = "PATH", short, long = "old-dir")]
old_directory: Option<String>,
},
/// Search the history
#[command(alias = "s")]
Search {
/// The command search term(s)
command: Vec<String>,
/// Directory where command was run (default $PWD)
#[arg(value_name = "PATH", short, long = "dir")]
directory: Option<String>,
/// Number of results to return
#[arg(value_name = "NUMBER", short, long)]
results: Option<u16>,
/// Fuzzy-find results. 0 is off; higher numbers weight shorter/earlier matches more. Try 2
#[arg(short, long)]
fuzzy: Option<i16>,
/// Delete entry without confirm
#[arg(long = "delete_without_confirm")]
delete_without_confirm: bool,
/// Write results to file, including selection mode, new commandline, and any shell-specific requests
#[arg(value_name = "PATH", short, long)]
output_selection: Option<String>,
},
/// Record a directory having been moved; moves command records from the old path to the new one
Move {
/// The old directory path
old_dir_path: String,
/// The new directory path
new_dir_path: String,
},
/// Train the suggestion engine (developer tool)
Train {
/// Directory where command was run
#[arg(short, long = "refresh_cache")]
refresh_cache: bool,
},
/// Prints the shell code used to execute mcfly
Init {
/// Shell to init
#[arg(value_enum)]
shell: InitMode,
},
/// Dump history into stdout; the results are sorted by timestamp
Dump {
/// Select all commands ran since the point
#[arg(long)]
since: Option<String>,
/// Select all commands ran before the point
#[arg(long)]
before: Option<String>,
/// Sort order [case ignored]
#[arg(
long,
short,
value_name = "ORDER",
value_enum,
default_value_t,
ignore_case = true
)]
sort: SortOrder,
/// Require commands to match the pattern
#[arg(long, short)]
regex: Option<Regex>,
/// The format to dump in
#[arg(long, short, value_enum, default_value_t)]
format: DumpFormat,
},
/// Prints stats
Stats {
/// The minimum command length to be listed in the "top-n" commands
#[arg(
value_name = "MIN_CMD_LENGTH",
short,
long,
value_name = "min_cmd_length",
default_value_t = 0
)]
min_cmd_length: i16,
/// The number of "top-n" commands
#[arg(
value_name = "CMDS",
short,
long,
value_name = "cmds",
default_value_t = 10
)]
cmds: i16,
/// Break down by top directories - defaults to 0, which doesn't limit by directory
#[arg(
value_name = "DIRS",
short,
long,
value_name = "dirs",
default_value_t = 0
)]
dirs: i16,
// Skip the top n commands when breaking down by directory
#[arg(
value_name = "GLOBAL_CMDS_TO_IGNORE",
short,
long,
value_name = "global_cmds_to_ignore",
default_value_t = 10
)]
global_commands_to_ignore: i16,
/// Only show commands from a given directory
#[arg(value_name = "ONLY_DIR", short, long)]
only_dir: Option<String>,
},
}
#[derive(Clone, Copy, ValueEnum, Default)]
pub enum HistoryFormat {
#[default]
Bash,
Zsh,
ZshExtended,
Fish,
}
#[derive(Clone, Copy, ValueEnum)]
pub enum InitMode {
Bash,
Zsh,
Fish,
Powershell,
}
#[derive(Debug, Clone, Copy, ValueEnum, Default)]
#[value(rename_all = "UPPER")]
pub enum SortOrder {
#[default]
#[value(alias = "asc")]
Asc,
#[value(alias = "desc")]
Desc,
}
#[derive(Debug, Clone, Copy, ValueEnum, Default)]
pub enum DumpFormat {
#[default]
Json,
Csv,
}
impl Cli {
#[must_use]
pub fn is_init(&self) -> bool {
matches!(self.command, SubCommand::Init { .. })
}
}
impl SortOrder {
#[inline]
#[must_use]
pub fn to_str(&self) -> &'static str {
match self {
Self::Asc => "ASC",
Self::Desc => "DESC",
}
}
}