Skip to content

Commit 932ca13

Browse files
committed
refactor(clap_complete): Replace parameters in complete_arg with ParseState
1 parent e142795 commit 932ca13

File tree

1 file changed

+96
-70
lines changed

1 file changed

+96
-70
lines changed

clap_complete/src/dynamic/completer.rs

Lines changed: 96 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,10 @@ pub fn complete(
5353
let mut current_cmd = &*cmd;
5454
let mut pos_index = 1;
5555
let mut is_escaped = false;
56+
let mut state = ParseState::ValueDone;
5657
while let Some(arg) = raw_args.next(&mut cursor) {
5758
if cursor == target_cursor {
58-
return complete_arg(&arg, current_cmd, current_dir, pos_index, is_escaped);
59+
return complete_arg(&arg, current_cmd, current_dir, pos_index, state);
5960
}
6061

6162
debug!("complete::next: Begin parsing '{:?}'", arg.to_value_os(),);
@@ -64,18 +65,22 @@ pub fn complete(
6465
if let Some(next_cmd) = current_cmd.find_subcommand(value) {
6566
current_cmd = next_cmd;
6667
pos_index = 1;
68+
state = ParseState::ValueDone;
6769
continue;
6870
}
6971
}
7072

7173
if is_escaped {
7274
pos_index += 1;
75+
state = ParseState::Pos(pos_index);
7376
} else if arg.is_escape() {
7477
is_escaped = true;
78+
state = ParseState::ValueDone;
7579
} else if let Some(_long) = arg.to_long() {
7680
} else if let Some(_short) = arg.to_short() {
7781
} else {
7882
pos_index += 1;
83+
state = ParseState::ValueDone;
7984
}
8085
}
8186

@@ -85,96 +90,117 @@ pub fn complete(
8590
))
8691
}
8792

93+
#[derive(Debug, PartialEq, Eq, Clone)]
94+
enum ParseState {
95+
/// Parsing a value done, there is no state to record.
96+
ValueDone,
97+
98+
/// Parsing a positional argument after `--`
99+
Pos(usize),
100+
}
101+
88102
fn complete_arg(
89103
arg: &clap_lex::ParsedArg<'_>,
90104
cmd: &clap::Command,
91105
current_dir: Option<&std::path::Path>,
92106
pos_index: usize,
93-
is_escaped: bool,
107+
state: ParseState,
94108
) -> Result<Vec<CompletionCandidate>, std::io::Error> {
95109
debug!(
96-
"complete_arg: arg={:?}, cmd={:?}, current_dir={:?}, pos_index={}, is_escaped={}",
110+
"complete_arg: arg={:?}, cmd={:?}, current_dir={:?}, pos_index={:?}, state={:?}",
97111
arg,
98112
cmd.get_name(),
99113
current_dir,
100114
pos_index,
101-
is_escaped
115+
state
102116
);
103117
let mut completions = Vec::<CompletionCandidate>::new();
104118

105-
if !is_escaped {
106-
if let Some((flag, value)) = arg.to_long() {
107-
if let Ok(flag) = flag {
108-
if let Some(value) = value {
109-
if let Some(arg) = cmd.get_arguments().find(|a| a.get_long() == Some(flag)) {
110-
completions.extend(
111-
complete_arg_value(value.to_str().ok_or(value), arg, current_dir)
112-
.into_iter()
113-
.map(|comp| {
114-
CompletionCandidate::new(format!(
115-
"--{}={}",
116-
flag,
117-
comp.get_content().to_string_lossy()
118-
))
119-
.help(comp.get_help().cloned())
120-
.visible(comp.is_visible())
121-
}),
122-
);
119+
match state {
120+
ParseState::ValueDone => {
121+
if let Some((flag, value)) = arg.to_long() {
122+
if let Ok(flag) = flag {
123+
if let Some(value) = value {
124+
if let Some(arg) = cmd.get_arguments().find(|a| a.get_long() == Some(flag))
125+
{
126+
completions.extend(
127+
complete_arg_value(value.to_str().ok_or(value), arg, current_dir)
128+
.into_iter()
129+
.map(|comp| {
130+
CompletionCandidate::new(format!(
131+
"--{}={}",
132+
flag,
133+
comp.get_content().to_string_lossy()
134+
))
135+
.help(comp.get_help().cloned())
136+
.visible(comp.is_visible())
137+
}),
138+
);
139+
}
140+
} else {
141+
completions.extend(longs_and_visible_aliases(cmd).into_iter().filter(
142+
|comp| {
143+
comp.get_content()
144+
.starts_with(format!("--{}", flag).as_str())
145+
},
146+
));
147+
148+
completions.extend(hidden_longs_aliases(cmd).into_iter().filter(|comp| {
149+
comp.get_content()
150+
.starts_with(format!("--{}", flag).as_str())
151+
}))
123152
}
124-
} else {
125-
completions.extend(longs_and_visible_aliases(cmd).into_iter().filter(|comp| {
126-
comp.get_content()
127-
.starts_with(format!("--{}", flag).as_str())
128-
}));
129-
130-
completions.extend(hidden_longs_aliases(cmd).into_iter().filter(|comp| {
131-
comp.get_content()
132-
.starts_with(format!("--{}", flag).as_str())
133-
}))
134153
}
135-
}
136-
} else if arg.is_escape() || arg.is_stdio() || arg.is_empty() {
137-
// HACK: Assuming knowledge of is_escape / is_stdio
138-
completions.extend(longs_and_visible_aliases(cmd));
154+
} else if arg.is_escape() || arg.is_stdio() || arg.is_empty() {
155+
// HACK: Assuming knowledge of is_escape / is_stdio
156+
completions.extend(longs_and_visible_aliases(cmd));
139157

140-
completions.extend(hidden_longs_aliases(cmd));
141-
}
158+
completions.extend(hidden_longs_aliases(cmd));
159+
}
142160

143-
if arg.is_empty() || arg.is_stdio() || arg.is_short() {
144-
let dash_or_arg = if arg.is_empty() {
145-
"-".into()
146-
} else {
147-
arg.to_value_os().to_string_lossy()
148-
};
149-
// HACK: Assuming knowledge of is_stdio
150-
completions.extend(
151-
shorts_and_visible_aliases(cmd)
152-
.into_iter()
153-
// HACK: Need better `OsStr` manipulation
154-
.map(|comp| {
155-
CompletionCandidate::new(format!(
156-
"{}{}",
157-
dash_or_arg,
158-
comp.get_content().to_string_lossy()
159-
))
160-
.help(comp.get_help().cloned())
161-
.visible(true)
162-
}),
163-
);
164-
}
165-
}
161+
if arg.is_empty() || arg.is_stdio() || arg.is_short() {
162+
let dash_or_arg = if arg.is_empty() {
163+
"-".into()
164+
} else {
165+
arg.to_value_os().to_string_lossy()
166+
};
167+
// HACK: Assuming knowledge of is_stdio
168+
completions.extend(
169+
shorts_and_visible_aliases(cmd)
170+
.into_iter()
171+
// HACK: Need better `OsStr` manipulation
172+
.map(|comp| {
173+
CompletionCandidate::new(format!(
174+
"{}{}",
175+
dash_or_arg,
176+
comp.get_content().to_string_lossy()
177+
))
178+
.help(comp.get_help().cloned())
179+
.visible(true)
180+
}),
181+
);
182+
}
166183

167-
if let Some(positional) = cmd
168-
.get_positionals()
169-
.find(|p| p.get_index() == Some(pos_index))
170-
{
171-
completions.extend(complete_arg_value(arg.to_value(), positional, current_dir).into_iter());
172-
}
184+
if let Some(positional) = cmd
185+
.get_positionals()
186+
.find(|p| p.get_index() == Some(pos_index))
187+
{
188+
completions.extend(complete_arg_value(arg.to_value(), positional, current_dir));
189+
}
173190

174-
if let Ok(value) = arg.to_value() {
175-
completions.extend(complete_subcommand(value, cmd));
191+
if let Ok(value) = arg.to_value() {
192+
completions.extend(complete_subcommand(value, cmd));
193+
}
194+
}
195+
ParseState::Pos(_) => {
196+
if let Some(positional) = cmd
197+
.get_positionals()
198+
.find(|p| p.get_index() == Some(pos_index))
199+
{
200+
completions.extend(complete_arg_value(arg.to_value(), positional, current_dir));
201+
}
202+
}
176203
}
177-
178204
if completions.iter().any(|a| a.is_visible()) {
179205
completions.retain(|a| a.is_visible())
180206
}

0 commit comments

Comments
 (0)