Skip to content

Commit f7659ac

Browse files
committed
refactor: move argument_completion_helper to ArgValueCompleter.fetch
1 parent 3d2b98e commit f7659ac

File tree

4 files changed

+243
-250
lines changed

4 files changed

+243
-250
lines changed
Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
use crate::{
2+
FileCompletion, NuCompleter,
3+
completions::{
4+
CommandCompletion, Completer, CompletionOptions, DirectoryCompletion, DotNuCompletion,
5+
ExportableCompletion, SemanticSuggestion, completer::Context,
6+
completion_options::NuMatcher,
7+
},
8+
};
9+
use nu_parser::parse_module_file_or_dir;
10+
use nu_protocol::{
11+
Span,
12+
ast::{Argument, Call, Expr, Expression, ListItem},
13+
engine::{ArgType, Stack, StateWorkingSet},
14+
};
15+
16+
pub struct ArgValueCompletion<'a> {
17+
pub call: &'a Call,
18+
pub arg_type: ArgType<'a>,
19+
pub need_fallback: &'a mut bool,
20+
pub completer: &'a NuCompleter,
21+
pub arg_idx: usize,
22+
pub pos: usize,
23+
}
24+
25+
impl<'a> Completer for ArgValueCompletion<'a> {
26+
fn fetch(
27+
&mut self,
28+
working_set: &StateWorkingSet,
29+
stack: &Stack,
30+
prefix: impl AsRef<str>,
31+
span: Span,
32+
offset: usize,
33+
options: &CompletionOptions,
34+
) -> Vec<SemanticSuggestion> {
35+
// if user input `--foo abc`, then the `prefix` here is abc.
36+
let mut matcher = NuMatcher::new(prefix.as_ref(), options, true);
37+
38+
let decl = working_set.get_decl(self.call.decl_id);
39+
let mut stack = stack.to_owned();
40+
41+
match decl.get_dynamic_completion(working_set.permanent_state, &mut stack, &self.arg_type) {
42+
Ok(Some(items)) => {
43+
for i in items {
44+
let suggestion = SemanticSuggestion::from_dynamic_suggestion(
45+
i,
46+
reedline::Span {
47+
start: span.start - offset,
48+
end: span.end - offset,
49+
},
50+
None,
51+
);
52+
matcher.add_semantic_suggestion(suggestion);
53+
}
54+
return matcher.suggestion_results();
55+
}
56+
Err(e) => {
57+
log::error!(
58+
"error on fetching dynamic suggestion on {} with {:?}: {e}",
59+
decl.name(),
60+
self.arg_type
61+
);
62+
}
63+
// fallback to type based completion, file completion, etc.
64+
Ok(None) => (),
65+
}
66+
67+
let command_head = decl.name();
68+
let ctx = Context::new(working_set, span, prefix.as_ref().as_bytes(), offset);
69+
let expr = self
70+
.call
71+
.arguments
72+
.get(self.arg_idx)
73+
.expect("Argument index out of range")
74+
.expr()
75+
.map(|e| &e.expr);
76+
77+
// TODO: Move command specific completion logic to its `get_dynamic_completion`
78+
if let ArgType::Positional(positional_arg_index) = self.arg_type {
79+
match command_head {
80+
// complete module file/directory
81+
"use" | "export use" | "overlay use" | "source-env"
82+
if positional_arg_index == 0 =>
83+
{
84+
*self.need_fallback = false;
85+
86+
return self.completer.process_completion(
87+
&mut DotNuCompletion {
88+
std_virtual_path: command_head != "source-env",
89+
},
90+
&ctx,
91+
);
92+
}
93+
// NOTE: if module file already specified,
94+
// should parse it to get modules/commands/consts to complete
95+
"use" | "export use" => {
96+
*self.need_fallback = false;
97+
98+
let Some((module_name, span)) = self.call.arguments.iter().find_map(|arg| {
99+
if let Argument::Positional(Expression {
100+
expr: Expr::String(module_name),
101+
span,
102+
..
103+
}) = arg
104+
{
105+
Some((module_name.as_bytes(), span))
106+
} else {
107+
None
108+
}
109+
}) else {
110+
return vec![];
111+
};
112+
113+
let (module_id, temp_working_set) = match working_set.find_module(module_name) {
114+
Some(module_id) => (module_id, None),
115+
None => {
116+
let mut temp_working_set =
117+
StateWorkingSet::new(working_set.permanent_state);
118+
let Some(module_id) = parse_module_file_or_dir(
119+
&mut temp_working_set,
120+
module_name,
121+
*span,
122+
None,
123+
) else {
124+
return vec![];
125+
};
126+
(module_id, Some(temp_working_set))
127+
}
128+
};
129+
let mut exportable_completion = ExportableCompletion {
130+
module_id,
131+
temp_working_set,
132+
};
133+
let mut complete_on_list_items =
134+
|items: &[ListItem]| -> Vec<SemanticSuggestion> {
135+
for item in items {
136+
let span = item.expr().span;
137+
if span.contains(self.pos) {
138+
let offset = span.start.saturating_sub(ctx.span.start);
139+
let end_offset = ctx
140+
.prefix
141+
.len()
142+
.min(self.pos.min(span.end) - ctx.span.start + 1);
143+
let new_ctx = Context::new(
144+
ctx.working_set,
145+
Span::new(span.start, ctx.span.end.min(span.end)),
146+
ctx.prefix.get(offset..end_offset).unwrap_or_default(),
147+
ctx.offset,
148+
);
149+
return self
150+
.completer
151+
.process_completion(&mut exportable_completion, &new_ctx);
152+
}
153+
}
154+
vec![]
155+
};
156+
157+
return match expr {
158+
Some(Expr::String(_)) => self
159+
.completer
160+
.process_completion(&mut exportable_completion, &ctx),
161+
Some(Expr::FullCellPath(fcp)) => match &fcp.head.expr {
162+
Expr::List(items) => complete_on_list_items(items),
163+
_ => vec![],
164+
},
165+
_ => vec![],
166+
};
167+
}
168+
"which" => {
169+
*self.need_fallback = false;
170+
171+
let mut completer = CommandCompletion {
172+
internals: true,
173+
externals: true,
174+
};
175+
return self.completer.process_completion(&mut completer, &ctx);
176+
}
177+
"attr complete" => {
178+
*self.need_fallback = false;
179+
180+
let mut completer = CommandCompletion {
181+
internals: true,
182+
externals: false,
183+
};
184+
return self.completer.process_completion(&mut completer, &ctx);
185+
}
186+
_ => (),
187+
}
188+
};
189+
190+
// general positional arguments
191+
let file_completion_helper =
192+
|| self.completer.process_completion(&mut FileCompletion, &ctx);
193+
match expr {
194+
Some(Expr::Directory(_, _)) => {
195+
*self.need_fallback = false;
196+
self.completer
197+
.process_completion(&mut DirectoryCompletion, &ctx)
198+
}
199+
Some(Expr::Filepath(_, _)) | Some(Expr::GlobPattern(_, _)) => file_completion_helper(),
200+
// fallback to file completion if necessary
201+
_ if *self.need_fallback => file_completion_helper(),
202+
_ => vec![],
203+
}
204+
}
205+
}

crates/nu-cli/src/completions/arg_value_dynamic_completion.rs

Lines changed: 0 additions & 58 deletions
This file was deleted.

0 commit comments

Comments
 (0)