diff --git a/src/main.rs b/src/main.rs index 7ffc02885..bd907a7b8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -63,6 +63,16 @@ fn main() -> std::io::Result<()> { .required("block", SyntaxShape::Block, "body of the definition"); working_set.add_decl(sig.into()); + let sig = Signature::build("add"); + working_set.add_decl(sig.into()); + let sig = Signature::build("add it"); + working_set.add_decl(sig.into()); + + let sig = Signature::build("add it together") + .required("x", SyntaxShape::Int, "x value") + .required("y", SyntaxShape::Int, "y value"); + working_set.add_decl(sig.into()); + ParserState::merge_working_set(&mut parser_state, working_set); // let file = std::fs::read(&path)?; diff --git a/src/parser.rs b/src/parser.rs index 0e30d6e29..aa7645681 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -643,15 +643,36 @@ impl ParserWorkingSet { // assume spans.len() > 0? let name = self.get_span_contents(spans[0]); - if let Some(decl_id) = self.find_decl(name) { - let (call, span, err) = self.parse_internal_call(spans, decl_id); - ( - Expression { - expr: Expr::Call(call), - span, - }, - err, - ) + if self.contains_decl_partial_match(name) { + // potentially subcommand + let mut name = name.to_vec(); + let mut pos = 1; + let mut decl_id = None; + while pos < spans.len() { + let mut new_name = name.to_vec(); + new_name.push(b' '); + new_name.extend(self.get_span_contents(spans[pos])); + if let Some(did) = self.find_decl(&new_name) { + decl_id = Some(did); + } else { + break; + } + name = new_name; + pos += 1; + } + // parse internal command + if let Some(decl_id) = decl_id { + let (call, span, err) = self.parse_internal_call(&spans[(pos - 1)..], decl_id); + ( + Expression { + expr: Expr::Call(call), + span, + }, + err, + ) + } else { + self.parse_external_call(spans) + } } else { self.parse_external_call(spans) } diff --git a/src/parser_state.rs b/src/parser_state.rs index 3e4e315a1..be6bc1475 100644 --- a/src/parser_state.rs +++ b/src/parser_state.rs @@ -256,6 +256,28 @@ impl ParserWorkingSet { None } + pub fn contains_decl_partial_match(&self, name: &[u8]) -> bool { + for scope in self.scope.iter().rev() { + for decl in &scope.decls { + if decl.0.starts_with(name) { + return true; + } + } + } + + if let Some(permanent_state) = &self.permanent_state { + for scope in permanent_state.scope.iter().rev() { + for decl in &scope.decls { + if decl.0.starts_with(name) { + return true; + } + } + } + } + + false + } + pub fn next_var_id(&self) -> VarId { if let Some(permanent_state) = &self.permanent_state { let num_permanent_vars = permanent_state.num_vars();