diff --git a/crates/nu-parser/src/hir/syntax_shape.rs b/crates/nu-parser/src/hir/syntax_shape.rs index 98483eb1ad..04d89e93aa 100644 --- a/crates/nu-parser/src/hir/syntax_shape.rs +++ b/crates/nu-parser/src/hir/syntax_shape.rs @@ -182,10 +182,10 @@ pub trait SignatureRegistry { #[derive(Getters, new)] pub struct ExpandContext<'context> { #[get = "pub(crate)"] - registry: Box, + pub registry: Box, #[get = "pub(crate)"] - source: &'context Text, - homedir: Option, + pub source: &'context Text, + pub homedir: Option, } impl<'context> ExpandContext<'context> { diff --git a/crates/nu-parser/src/lib.rs b/crates/nu-parser/src/lib.rs index 41c7cde5f5..05194a67eb 100644 --- a/crates/nu-parser/src/lib.rs +++ b/crates/nu-parser/src/lib.rs @@ -6,7 +6,9 @@ pub mod parse_command; pub use crate::commands::classified::{ClassifiedCommand, ClassifiedPipeline, InternalCommand}; pub use crate::commands::ExternalCommand; pub use crate::hir::syntax_shape::flat_shape::FlatShape; -pub use crate::hir::syntax_shape::{expand_syntax, ExpandSyntax, PipelineShape, SignatureRegistry}; +pub use crate::hir::syntax_shape::{ + expand_syntax, ExpandContext, ExpandSyntax, PipelineShape, SignatureRegistry, +}; pub use crate::hir::tokens_iterator::TokensIterator; pub use crate::parse::files::Files; pub use crate::parse::flag::Flag; diff --git a/src/cli.rs b/src/cli.rs index dbfd8641d0..4e0bcfc0e3 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -587,7 +587,7 @@ async fn process_line(readline: Result, ctx: &mut Context } } -fn classify_pipeline( +pub fn classify_pipeline( pipeline: &TokenNode, context: &Context, source: &Text, diff --git a/src/shell/completer.rs b/src/shell/completer.rs index 27aeaed155..ca038f7236 100644 --- a/src/shell/completer.rs +++ b/src/shell/completer.rs @@ -16,28 +16,10 @@ impl NuCompleter { pos: usize, context: &rustyline::Context, ) -> rustyline::Result<(usize, Vec)> { + use nu_source::{HasSpan, Text}; + let commands: Vec = self.commands.names(); - let mut completions = self.file_completer.complete(line, pos, context)?.1; - - for completion in &mut completions { - if completion.replacement.contains("\\ ") { - completion.replacement = completion.replacement.replace("\\ ", " "); - } - if completion.replacement.contains("\\(") { - completion.replacement = completion.replacement.replace("\\(", "("); - } - - if completion.replacement.contains(' ') || completion.replacement.contains('(') { - if !completion.replacement.starts_with('\"') { - completion.replacement = format!("\"{}", completion.replacement); - } - if !completion.replacement.ends_with('\"') { - completion.replacement = format!("{}\"", completion.replacement); - } - } - } - let line_chars: Vec<_> = line[..pos].chars().collect(); let mut replace_pos = line_chars.len(); while replace_pos > 0 { @@ -47,6 +29,80 @@ impl NuCompleter { replace_pos -= 1; } + // See if we're a flag + let mut completions = vec![]; + + if pos > 0 && line_chars[pos - 1] == '-' { + let mut line_copy = line.to_string(); + let replace_string = (replace_pos..pos).map(|_| " ").collect::(); + line_copy.replace_range(replace_pos..pos, &replace_string); + match nu_parser::parse(&line_copy) { + Ok(val) => { + let source = Text::from(line); + let pipeline_list = vec![val.clone()]; + let mut iterator = + nu_parser::TokensIterator::all(&pipeline_list, source.clone(), val.span()); + + let expand_context = nu_parser::ExpandContext { + homedir: None, + registry: Box::new(self.commands.clone()), + source: &source, + }; + + let result = nu_parser::expand_syntax( + &nu_parser::PipelineShape, + &mut iterator, + &expand_context, + ); + + if let Ok(result) = result { + for command in result.commands.list { + match command { + nu_parser::ClassifiedCommand::Internal( + nu_parser::InternalCommand { args, .. }, + ) => { + if replace_pos >= args.span.start() + && replace_pos <= args.span.end() + { + if let Some(named) = args.named { + for (name, _) in named.iter() { + completions.push(rustyline::completion::Pair { + display: format!("--{}", name), + replacement: format!("--{}", name), + }); + } + } + } + } + _ => {} + } + } + } + } + _ => {} + } + } else { + completions = self.file_completer.complete(line, pos, context)?.1; + + for completion in &mut completions { + if completion.replacement.contains("\\ ") { + completion.replacement = completion.replacement.replace("\\ ", " "); + } + if completion.replacement.contains("\\(") { + completion.replacement = completion.replacement.replace("\\(", "("); + } + + if completion.replacement.contains(' ') || completion.replacement.contains('(') { + if !completion.replacement.starts_with('\"') { + completion.replacement = format!("\"{}", completion.replacement); + } + if !completion.replacement.ends_with('\"') { + completion.replacement = format!("{}\"", completion.replacement); + } + } + } + }; + for command in commands.iter() { let mut pos = replace_pos; let mut matched = true;