From 938fa6ee559a2d9d65c20f009cbb6abbfe48325c Mon Sep 17 00:00:00 2001 From: zc he Date: Tue, 25 Feb 2025 18:47:10 +0800 Subject: [PATCH] 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: image After: image 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 --- crates/nu-cli/src/completions/command_completions.rs | 5 ++--- crates/nu-cli/src/completions/completer.rs | 10 ++++++++-- crates/nu-cli/tests/completions/mod.rs | 2 +- crates/nu-lsp/src/lib.rs | 1 + 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/crates/nu-cli/src/completions/command_completions.rs b/crates/nu-cli/src/completions/command_completions.rs index 2f384840a1..2af199d1d9 100644 --- a/crates/nu-cli/src/completions/command_completions.rs +++ b/crates/nu-cli/src/completions/command_completions.rs @@ -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)), }, ); } diff --git a/crates/nu-cli/src/completions/completer.rs b/crates/nu-cli/src/completions/completer.rs index 457c19554f..3a8fc07298 100644 --- a/crates/nu-cli/src/completions/completer.rs +++ b/crates/nu-cli/src/completions/completer.rs @@ -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, diff --git a/crates/nu-cli/tests/completions/mod.rs b/crates/nu-cli/tests/completions/mod.rs index 27fba186ea..48d5f940c5 100644 --- a/crates/nu-cli/tests/completions/mod.rs +++ b/crates/nu-cli/tests/completions/mod.rs @@ -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 = vec!["sleep.exe".into()]; diff --git a/crates/nu-lsp/src/lib.rs b/crates/nu-lsp/src/lib.rs index 4e1f4d37ff..95fac87f83 100644 --- a/crates/nu-lsp/src/lib.rs +++ b/crates/nu-lsp/src/lib.rs @@ -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),