@@ -51,10 +51,17 @@ struct ParserState<'a> {
51
51
variable_regex : Regex ,
52
52
backref_regex : Regex ,
53
53
short_multibyte_regex : Regex ,
54
- top_level_scope : Scope ,
55
54
lines_include_newline : bool ,
56
55
}
57
56
57
+ static START_CONTEXTS : & ' static str = "
58
+ __start:
59
+ - match: ''
60
+ push: __main
61
+ __main:
62
+ - include: main
63
+ " ;
64
+
58
65
impl SyntaxDefinition {
59
66
/// In case you want to create your own SyntaxDefinition's in memory from strings.
60
67
/// Generally you should use a `SyntaxSet`
@@ -96,15 +103,16 @@ impl SyntaxDefinition {
96
103
variable_regex : Regex :: new ( r"\{\{([A-Za-z0-9_]+)\}\}" ) . unwrap ( ) ,
97
104
backref_regex : Regex :: new ( r"\\\d" ) . unwrap ( ) ,
98
105
short_multibyte_regex : Regex :: new ( r"\\x([a-fA-F][a-fA-F0-9])" ) . unwrap ( ) ,
99
- top_level_scope : top_level_scope,
100
106
lines_include_newline : lines_include_newline,
101
107
} ;
102
108
103
- let contexts = try!( SyntaxDefinition :: parse_contexts ( contexts_hash, & mut state) ) ;
109
+ let mut contexts = try!( SyntaxDefinition :: parse_contexts ( contexts_hash, & mut state) ) ;
104
110
if !contexts. contains_key ( "main" ) {
105
111
return Err ( ParseSyntaxError :: MainMissing ) ;
106
112
}
107
113
114
+ SyntaxDefinition :: add_initial_contexts ( & mut contexts, & mut state, top_level_scope) ;
115
+
108
116
let defn = SyntaxDefinition {
109
117
name : try!( get_key ( h, "name" , |x| x. as_str ( ) ) ) . to_owned ( ) ,
110
118
scope : top_level_scope,
@@ -135,12 +143,6 @@ impl SyntaxDefinition {
135
143
let is_prototype = name == "prototype" ;
136
144
let context_ptr =
137
145
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
- }
144
146
contexts. insert ( name. to_owned ( ) , context_ptr) ;
145
147
}
146
148
}
@@ -335,6 +337,46 @@ impl SyntaxDefinition {
335
337
Ok ( vec ! [ try!( SyntaxDefinition :: parse_reference( y, state) ) ] )
336
338
}
337
339
}
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
+ }
338
380
}
339
381
340
382
#[ cfg( test) ]
@@ -388,7 +430,8 @@ mod tests {
388
430
false )
389
431
. unwrap ( ) ;
390
432
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) ;
392
435
let exts: Vec < String > = vec ! [ String :: from( "c" ) , String :: from( "h" ) ] ;
393
436
assert_eq ! ( defn2. file_extensions, exts) ;
394
437
assert_eq ! ( defn2. hidden, true ) ;
@@ -397,8 +440,13 @@ mod tests {
397
440
let n: Vec < Scope > = Vec :: new ( ) ;
398
441
println ! ( "{:?}" , defn2) ;
399
442
// assert!(false);
443
+ assert_eq ! ( defn2. contexts[ "main" ] . borrow( ) . meta_content_scope, vec![ top_level_scope] ) ;
400
444
assert_eq ! ( defn2. contexts[ "main" ] . borrow( ) . meta_scope, n) ;
401
445
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
+
402
450
assert_eq ! ( defn2. contexts[ "string" ] . borrow( ) . meta_scope,
403
451
vec![ Scope :: new( "string.quoted.double.c" ) . unwrap( ) ] ) ;
404
452
let first_pattern: & Pattern = & defn2. contexts [ "main" ] . borrow ( ) . patterns [ 0 ] ;
0 commit comments