From b6ba7f97fd692d5fb2fe2e028425fa6aea560684 Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Sun, 8 Dec 2019 18:58:53 +1300 Subject: [PATCH 1/5] WIP param completions --- crates/nu-parser/src/hir/syntax_shape.rs | 6 +- crates/nu-parser/src/lib.rs | 4 +- src/cli.rs | 2 +- src/shell/completer.rs | 96 +++++++++++++++++++----- 4 files changed, 83 insertions(+), 25 deletions(-) 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; From f9a46ce1e7980f425b1a0a98c0de649d4317ba40 Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Sun, 8 Dec 2019 19:04:23 +1300 Subject: [PATCH 2/5] WIP param completions --- src/shell/completer.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shell/completer.rs b/src/shell/completer.rs index ca038f7236..dffb337df9 100644 --- a/src/shell/completer.rs +++ b/src/shell/completer.rs @@ -32,7 +32,7 @@ impl NuCompleter { // See if we're a flag let mut completions = vec![]; - if pos > 0 && line_chars[pos - 1] == '-' { + if pos > 0 && line_chars[replace_pos] == '-' { let mut line_copy = line.to_string(); let replace_string = (replace_pos..pos).map(|_| " ").collect::(); line_copy.replace_range(replace_pos..pos, &replace_string); From b5f8c1cc50e41c274322b73c3bc5b0a0cef89d29 Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Sun, 8 Dec 2019 19:23:31 +1300 Subject: [PATCH 3/5] param completions work now --- src/shell/completer.rs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/shell/completer.rs b/src/shell/completer.rs index dffb337df9..fc089a3abd 100644 --- a/src/shell/completer.rs +++ b/src/shell/completer.rs @@ -21,6 +21,7 @@ impl NuCompleter { let commands: Vec = self.commands.names(); let line_chars: Vec<_> = line[..pos].chars().collect(); + let mut replace_pos = line_chars.len(); while replace_pos > 0 { if line_chars[replace_pos - 1] == ' ' { @@ -29,9 +30,11 @@ impl NuCompleter { replace_pos -= 1; } - // See if we're a flag + let substring = line_chars[replace_pos..pos].iter().collect::(); + let mut completions = vec![]; + // See if we're a flag if pos > 0 && line_chars[replace_pos] == '-' { let mut line_copy = line.to_string(); let replace_string = (replace_pos..pos).map(|_| " ").collect::(); @@ -66,10 +69,14 @@ impl NuCompleter { { if let Some(named) = args.named { for (name, _) in named.iter() { - completions.push(rustyline::completion::Pair { - display: format!("--{}", name), - replacement: format!("--{}", name), - }); + let full_flag = format!("--{}", name); + + if full_flag.starts_with(&substring) { + completions.push(rustyline::completion::Pair { + display: full_flag.clone(), + replacement: full_flag, + }); + } } } } From f653992b4a4f52f5d3e9c16ab1855137d7bb824a Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Sun, 8 Dec 2019 19:42:43 +1300 Subject: [PATCH 4/5] A little cleanup --- src/shell/completer.rs | 129 +++++++++++++++++++++++------------------ 1 file changed, 72 insertions(+), 57 deletions(-) diff --git a/src/shell/completer.rs b/src/shell/completer.rs index fc089a3abd..c40b67d863 100644 --- a/src/shell/completer.rs +++ b/src/shell/completer.rs @@ -1,6 +1,7 @@ use crate::context::CommandRegistry; use derive_new::new; +use nu_source::{HasSpan, Text}; use rustyline::completion::{Completer, FilenameCompleter}; #[derive(new)] @@ -16,8 +17,6 @@ impl NuCompleter { pos: usize, context: &rustyline::Context, ) -> rustyline::Result<(usize, Vec)> { - use nu_source::{HasSpan, Text}; - let commands: Vec = self.commands.names(); let line_chars: Vec<_> = line[..pos].chars().collect(); @@ -30,64 +29,11 @@ impl NuCompleter { replace_pos -= 1; } - let substring = line_chars[replace_pos..pos].iter().collect::(); - - let mut completions = vec![]; + let mut completions; // See if we're a flag if pos > 0 && line_chars[replace_pos] == '-' { - 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() { - let full_flag = format!("--{}", name); - - if full_flag.starts_with(&substring) { - completions.push(rustyline::completion::Pair { - display: full_flag.clone(), - replacement: full_flag, - }); - } - } - } - } - } - _ => {} - } - } - } - } - _ => {} - } + completions = self.get_matching_arguments(&line_chars, line, replace_pos, pos); } else { completions = self.file_completer.complete(line, pos, context)?.1; @@ -136,4 +82,73 @@ impl NuCompleter { Ok((replace_pos, completions)) } + + fn get_matching_arguments( + &self, + line_chars: &[char], + line: &str, + replace_pos: usize, + pos: usize, + ) -> Vec { + let mut matching_arguments = vec![]; + + let mut line_copy = line.to_string(); + let substring = line_chars[replace_pos..pos].iter().collect::(); + 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() { + let full_flag = format!("--{}", name); + + if full_flag.starts_with(&substring) { + matching_arguments.push( + rustyline::completion::Pair { + display: full_flag.clone(), + replacement: full_flag, + }, + ); + } + } + } + } + } + _ => {} + } + } + } + } + _ => {} + } + + matching_arguments + } } From 0515ed976cb36e24b845d5897c16c602fc8ea813 Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Mon, 9 Dec 2019 05:36:24 +1300 Subject: [PATCH 5/5] Fix panic --- src/shell/completer.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shell/completer.rs b/src/shell/completer.rs index c40b67d863..fac2af1c4a 100644 --- a/src/shell/completer.rs +++ b/src/shell/completer.rs @@ -32,7 +32,7 @@ impl NuCompleter { let mut completions; // See if we're a flag - if pos > 0 && line_chars[replace_pos] == '-' { + if pos > 0 && replace_pos < line_chars.len() && line_chars[replace_pos] == '-' { completions = self.get_matching_arguments(&line_chars, line, replace_pos, pos); } else { completions = self.file_completer.complete(line, pos, context)?.1;