fix(completion): prefix_str should be trimmed to element_expression (#15171)

# Description
Hot fix of  a newly introduced bug by #15086.
Forgot to trim the line str according to the expression span, which will
disable external command completions in many cases.

Also adds the suggestion kind to external commands, for lsp
visualization.

# User-Facing Changes

Before:
<img width="246" alt="image"
src="https://github.com/user-attachments/assets/c62904f6-0dd7-4368-8f0b-aacd6fe590f0"
/>

After:
<img width="291" alt="image"
src="https://github.com/user-attachments/assets/76316649-956f-4828-94cb-41f79d5f94f7"
/>

I find it better to visually distinguish externals from internals, so
`function` for internals and `interface` for externals.
But it's arguably not the best option.

# Tests + Formatting

test case adjusted

# After Submitting
This commit is contained in:
zc he 2025-02-25 18:47:10 +08:00 committed by GitHub
parent 1d0d91d5e5
commit 938fa6ee55
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 12 additions and 6 deletions

View File

@ -5,7 +5,7 @@ use crate::{
SuggestionKind,
};
use nu_protocol::{
engine::{Stack, StateWorkingSet},
engine::{CommandType, Stack, StateWorkingSet},
Span,
};
use reedline::Suggestion;
@ -75,8 +75,7 @@ impl CommandCompletion {
append_whitespace: true,
..Default::default()
},
// TODO: is there a way to create a test?
kind: None,
kind: Some(SuggestionKind::Command(CommandType::External)),
},
);
}

View File

@ -164,7 +164,13 @@ impl NuCompleter {
return vec![];
};
self.complete_by_expression(&working_set, element_expression, offset, pos, line)
// line of element_expression
let start_offset = element_expression.span.start - offset;
if let Some(line) = line.get(start_offset..) {
self.complete_by_expression(&working_set, element_expression, offset, pos, line)
} else {
vec![]
}
}
/// Complete given the expression of interest
@ -173,7 +179,7 @@ impl NuCompleter {
/// # Arguments
/// * `offset` - start offset of current working_set span
/// * `pos` - cursor position, should be > offset
/// * `prefix_str` - all the text before the cursor
/// * `prefix_str` - all the text before the cursor, within the `element_expression`
pub fn complete_by_expression(
&self,
working_set: &StateWorkingSet,

View File

@ -353,7 +353,7 @@ fn external_commands_only() {
Arc::new(engine),
Arc::new(nu_protocol::engine::Stack::new()),
);
let completion_str = "^sleep";
let completion_str = "ls; ^sleep";
let suggestions = completer.complete(completion_str, completion_str.len());
#[cfg(windows)]
let expected: Vec<String> = vec!["sleep.exe".into()];

View File

@ -727,6 +727,7 @@ impl LanguageServer {
SuggestionKind::Command(c) => match c {
nu_protocol::engine::CommandType::Keyword => Some(CompletionItemKind::KEYWORD),
nu_protocol::engine::CommandType::Builtin => Some(CompletionItemKind::FUNCTION),
nu_protocol::engine::CommandType::External => Some(CompletionItemKind::INTERFACE),
_ => None,
},
SuggestionKind::Module => Some(CompletionItemKind::MODULE),