Skip to content

Commit ca60277

Browse files
authored
Allow setting span in custom/extern completers (nushell#15888)
# Description Closes nushell#15863. This PR allows custom and extern completers to set the `span` field for the `Suggestion`s they provide. The motivation for this is mainly making it easier to make completers for Zoxide. # Release notes summary Custom completers and external completers will be able to choose which part of the buffer to replace. This is useful if you also want to replace one of the previous arguments to a command, or if you only want to replace part of an expression. # Tests + Formatting Didn't add any tests, but did manually try the following: ``` > def comp [context, pos] { [{value: mwahahaha, description: bar, span: {start: 0, end: $pos}}] } > def foo [arg: string@comp] {} ``` After creating those definitions, `foo <TAB>` will replace the command line with `mwahahaha`. # After Submitting Needs to be mentioned in the completer docs.
1 parent a59ac4d commit ca60277

File tree

2 files changed

+52
-1
lines changed

2 files changed

+52
-1
lines changed

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

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -936,6 +936,24 @@ pub fn map_value_completions<'a>(
936936
_ => None,
937937
};
938938
}
939+
"span" => {
940+
if let Value::Record { val: span, .. } = value {
941+
let start = span
942+
.get("start")
943+
.and_then(|val| val.as_int().ok())
944+
.and_then(|x| usize::try_from(x).ok());
945+
let end = span
946+
.get("end")
947+
.and_then(|val| val.as_int().ok())
948+
.and_then(|x| usize::try_from(x).ok());
949+
if let (Some(start), Some(end)) = (start, end) {
950+
suggestion.span = reedline::Span {
951+
start: start.min(end),
952+
end,
953+
};
954+
}
955+
}
956+
}
939957
_ => (),
940958
}
941959
});

crates/nu-cli/tests/completions/mod.rs

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use nu_protocol::{
1515
};
1616
use nu_std::load_standard_library;
1717
use nu_test_support::fs;
18-
use reedline::{Completer, Suggestion};
18+
use reedline::{Completer, Span, Suggestion};
1919
use rstest::{fixture, rstest};
2020
use support::{
2121
completions_helpers::{
@@ -272,6 +272,25 @@ fn customcompletions_no_sort() {
272272
match_suggestions(&expected, &suggestions);
273273
}
274274

275+
#[test]
276+
fn custom_completions_override_span() {
277+
let (_, _, mut engine, mut stack) = new_engine();
278+
let command = r#"
279+
def comp [] { [{ value: blech, span: { start: 1, end: 10 } }] }
280+
def my-command [arg: string@comp] {}"#;
281+
assert!(support::merge_input(command.as_bytes(), &mut engine, &mut stack).is_ok());
282+
283+
let mut completer = NuCompleter::new(Arc::new(engine), Arc::new(stack));
284+
let completion_str = "my-command b";
285+
let suggestions = completer.complete(completion_str, completion_str.len());
286+
let expected = vec![Suggestion {
287+
value: "blech".to_string(),
288+
span: Span::new(1, 10),
289+
..Default::default()
290+
}];
291+
assert_eq!(expected, suggestions);
292+
}
293+
275294
#[rstest]
276295
/// Fallback to file completions if custom completer returns null
277296
#[case::fallback(r#"
@@ -797,6 +816,20 @@ fn external_completer_fallback() {
797816
match_suggestions(&expected, &suggestions);
798817
}
799818

819+
#[test]
820+
fn external_completer_override_span() {
821+
let block = "{|spans| [{ value: blech, span: { start: 1, end: 10 } }]}";
822+
let input = "foo b";
823+
824+
let suggestions = run_external_completion(block, input);
825+
let expected = vec![Suggestion {
826+
value: "blech".to_string(),
827+
span: Span::new(1, 10),
828+
..Default::default()
829+
}];
830+
assert_eq!(expected, suggestions);
831+
}
832+
800833
/// Fallback to external completions for flags of `sudo`
801834
#[test]
802835
fn external_completer_sudo() {

0 commit comments

Comments
 (0)