Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 952176d

Browse files
committed
Add special contexts for top level, fixes #58
1 parent 1a50ae5 commit 952176d

File tree

5 files changed

+73
-11
lines changed

5 files changed

+73
-11
lines changed

assets/default_newlines.packdump

982 Bytes
Binary file not shown.

assets/default_nonewlines.packdump

798 Bytes
Binary file not shown.

src/parsing/parser.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,8 @@ impl ParseState {
5252
/// pointer to the main context of the syntax.
5353
pub fn new(syntax: &SyntaxDefinition) -> ParseState {
5454
let start_state = StateLevel {
55-
context: syntax.contexts["main"].clone(),
55+
// __start is a special context we add in yaml_load.rs
56+
context: syntax.contexts["__start"].clone(),
5657
prototype: None,
5758
captures: None,
5859
};

src/parsing/yaml_load.rs

Lines changed: 58 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,17 @@ struct ParserState<'a> {
5151
variable_regex: Regex,
5252
backref_regex: Regex,
5353
short_multibyte_regex: Regex,
54-
top_level_scope: Scope,
5554
lines_include_newline: bool,
5655
}
5756

57+
static START_CONTEXTS: &'static str = "
58+
__start:
59+
- match: ''
60+
push: __main
61+
__main:
62+
- include: main
63+
";
64+
5865
impl SyntaxDefinition {
5966
/// In case you want to create your own SyntaxDefinition's in memory from strings.
6067
/// Generally you should use a `SyntaxSet`
@@ -96,15 +103,16 @@ impl SyntaxDefinition {
96103
variable_regex: Regex::new(r"\{\{([A-Za-z0-9_]+)\}\}").unwrap(),
97104
backref_regex: Regex::new(r"\\\d").unwrap(),
98105
short_multibyte_regex: Regex::new(r"\\x([a-fA-F][a-fA-F0-9])").unwrap(),
99-
top_level_scope: top_level_scope,
100106
lines_include_newline: lines_include_newline,
101107
};
102108

103-
let contexts = try!(SyntaxDefinition::parse_contexts(contexts_hash, &mut state));
109+
let mut contexts = try!(SyntaxDefinition::parse_contexts(contexts_hash, &mut state));
104110
if !contexts.contains_key("main") {
105111
return Err(ParseSyntaxError::MainMissing);
106112
}
107113

114+
SyntaxDefinition::add_initial_contexts(&mut contexts, &mut state, top_level_scope);
115+
108116
let defn = SyntaxDefinition {
109117
name: try!(get_key(h, "name", |x| x.as_str())).to_owned(),
110118
scope: top_level_scope,
@@ -135,12 +143,6 @@ impl SyntaxDefinition {
135143
let is_prototype = name == "prototype";
136144
let context_ptr =
137145
try!(SyntaxDefinition::parse_context(val_vec, state, is_prototype));
138-
if name == "main" {
139-
let mut context = context_ptr.borrow_mut();
140-
if context.meta_content_scope.is_empty() {
141-
context.meta_content_scope.push(state.top_level_scope)
142-
}
143-
}
144146
contexts.insert(name.to_owned(), context_ptr);
145147
}
146148
}
@@ -335,6 +337,46 @@ impl SyntaxDefinition {
335337
Ok(vec![try!(SyntaxDefinition::parse_reference(y, state))])
336338
}
337339
}
340+
341+
/// Sublime treats the top level context slightly differently from
342+
/// including the main context from other syntaxes. When main is popped
343+
/// it is immediately re-added and when it is `set` over the file level
344+
/// scope remains. This behaviour is emulated through some added contexts
345+
/// that are the actual top level contexts used in parsing.
346+
/// See https://github.com/trishume/syntect/issues/58 for more.
347+
fn add_initial_contexts(contexts: &mut HashMap<String, ContextPtr>,
348+
state: &mut ParserState,
349+
top_level_scope: Scope) {
350+
let yaml_docs = YamlLoader::load_from_str(START_CONTEXTS).unwrap();
351+
let yaml = &yaml_docs[0];
352+
353+
let start_yaml : &[Yaml] = yaml["__start"].as_vec().unwrap();
354+
let start = SyntaxDefinition::parse_context(start_yaml, state, false).unwrap();
355+
{
356+
let mut start_b = start.borrow_mut();
357+
start_b.meta_content_scope = vec![top_level_scope];
358+
}
359+
contexts.insert("__start".to_owned(), start);
360+
361+
let main_yaml : &[Yaml] = yaml["__main"].as_vec().unwrap();
362+
let main = SyntaxDefinition::parse_context(main_yaml, state, false).unwrap();
363+
{
364+
let real_main = contexts["main"].borrow();
365+
let mut main_b = main.borrow_mut();
366+
main_b.meta_include_prototype = real_main.meta_include_prototype;
367+
main_b.meta_scope = real_main.meta_scope.clone();
368+
main_b.meta_content_scope = real_main.meta_content_scope.clone();
369+
}
370+
contexts.insert("__main".to_owned(), main);
371+
372+
// add the top_level_scope as a meta_content_scope to main so
373+
// pushes from other syntaxes add the file scope
374+
// TODO: this order is not quite correct if main also has a meta_scope
375+
{
376+
let mut real_main = contexts["main"].borrow_mut();
377+
real_main.meta_content_scope.insert(0,top_level_scope);
378+
}
379+
}
338380
}
339381

340382
#[cfg(test)]
@@ -388,7 +430,8 @@ mod tests {
388430
false)
389431
.unwrap();
390432
assert_eq!(defn2.name, "C");
391-
assert_eq!(defn2.scope, Scope::new("source.c").unwrap());
433+
let top_level_scope = Scope::new("source.c").unwrap();
434+
assert_eq!(defn2.scope, top_level_scope);
392435
let exts: Vec<String> = vec![String::from("c"), String::from("h")];
393436
assert_eq!(defn2.file_extensions, exts);
394437
assert_eq!(defn2.hidden, true);
@@ -397,8 +440,13 @@ mod tests {
397440
let n: Vec<Scope> = Vec::new();
398441
println!("{:?}", defn2);
399442
// assert!(false);
443+
assert_eq!(defn2.contexts["main"].borrow().meta_content_scope, vec![top_level_scope]);
400444
assert_eq!(defn2.contexts["main"].borrow().meta_scope, n);
401445
assert_eq!(defn2.contexts["main"].borrow().meta_include_prototype, true);
446+
447+
assert_eq!(defn2.contexts["__main"].borrow().meta_content_scope, n);
448+
assert_eq!(defn2.contexts["__start"].borrow().meta_content_scope, vec![top_level_scope]);
449+
402450
assert_eq!(defn2.contexts["string"].borrow().meta_scope,
403451
vec![Scope::new("string.quoted.double.c").unwrap()]);
404452
let first_pattern: &Pattern = &defn2.contexts["main"].borrow().patterns[0];

testdata/Testing.sublime-syntax

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ contexts:
1212
- include: zoom
1313
main:
1414
- meta_include_prototype: false
15+
- match: =testset
16+
push: testset
1517
- match: hi
1618
scope: comment
1719
- match: troll
@@ -52,3 +54,14 @@ contexts:
5254
- meta_scope: bamf
5355
- match: bamf
5456
scope: keyword
57+
testset:
58+
- meta_scope: constant.testset.meta
59+
- meta_content_scope: string.testset.content
60+
- match: =doset
61+
set: setto
62+
setto:
63+
- clear_scopes: 1
64+
- meta_scope: constant.setto.meta
65+
- meta_content_scope: comment.setto.content
66+
- match: =endset
67+
pop: true

0 commit comments

Comments
 (0)