diff --git a/src/parsing/parser.rs b/src/parsing/parser.rs index 62d6abfb..53eb8114 100644 --- a/src/parsing/parser.rs +++ b/src/parsing/parser.rs @@ -1260,6 +1260,34 @@ contexts: expect_scope_stacks_with_syntax("/** * */", &[", ", ", , ", ", "], syntax); } + #[test] + fn can_parse_context_included_in_prototype_via_named_reference() { + let syntax = r#" +scope: source.test +contexts: + prototype: + - match: a + push: a + - match: b + scope: test.bad + main: + - match: unused + # This context is included in the prototype (see `push: a`). + # Because of that, ST doesn't apply the prototype to this context, so if + # we're in here the "b" shouldn't match. + a: + - match: a + scope: test.good +"#; + + let stack_states = stack_states(parse("aa b", syntax)); + assert_eq!(stack_states, vec![ + "", + ", ", + "", + ], "Expected test.bad to not match"); + } + #[test] fn can_parse_with_prototype_set() { let syntax = r#"%YAML 1.2 @@ -1341,14 +1369,13 @@ contexts: syntax_set.link_syntaxes(); let mut state = ParseState::new(&syntax_set.syntaxes()[0]); - - let mut stack = ScopeStack::new(); let ops = ops(line, &mut state); + expect_scope_stacks_for_ops(ops, expect); + } + fn expect_scope_stacks_for_ops(ops: Vec<(usize, ScopeStackOp)>, expect: &[&str]) { let mut criteria_met = Vec::new(); - for &(_, ref op) in ops.iter() { - stack.apply(op); - let stack_str = format!("{:?}", stack); + for stack_str in stack_states(ops) { println!("{}", stack_str); for expectation in expect.iter() { if stack_str.contains(expectation) { @@ -1361,9 +1388,31 @@ contexts: } } + fn parse(line: &str, syntax: &str) -> Vec<(usize, ScopeStackOp)> { + let syntax = SyntaxDefinition::load_from_str(syntax, true, None).unwrap(); + let mut syntax_set = SyntaxSet::new(); + syntax_set.add_syntax(syntax); + syntax_set.link_syntaxes(); + + let mut state = ParseState::new(&syntax_set.syntaxes()[0]); + ops(line, &mut state) + } + fn ops(line: &str, state: &mut ParseState) -> Vec<(usize, ScopeStackOp)> { let ops = state.parse_line(line); debug_print_ops(line, &ops); ops } + + fn stack_states(ops: Vec<(usize, ScopeStackOp)>) -> Vec { + let mut states = Vec::new(); + let mut stack = ScopeStack::new(); + for &(_, ref op) in ops.iter() { + stack.apply(op); + let scopes: Vec = stack.as_slice().iter().map(|s| format!("{:?}", s)).collect(); + let stack_str = scopes.join(", "); + states.push(stack_str); + } + states + } } diff --git a/src/parsing/syntax_set.rs b/src/parsing/syntax_set.rs index 9c2f7c30..86628039 100644 --- a/src/parsing/syntax_set.rs +++ b/src/parsing/syntax_set.rs @@ -282,8 +282,16 @@ impl SyntaxSet { }; if let Some(context_refs) = maybe_context_refs { for context_ref in context_refs.iter() { - if let ContextReference::Inline(ref context_ptr) = *context_ref { - Self::recursively_mark_no_prototype(syntax, context_ptr.clone()); + match context_ref { + ContextReference::Inline(ref context_ptr) => { + Self::recursively_mark_no_prototype(syntax, context_ptr.clone()); + }, + ContextReference::Named(ref s) => { + if let Some(context_ptr) = syntax.contexts.get(s) { + Self::recursively_mark_no_prototype(syntax, context_ptr.clone()); + } + }, + _ => (), } } }