@@ -4,14 +4,16 @@ use once_cell::sync::Lazy;
4
4
5
5
use crate :: indent:: IndentStyle ;
6
6
use crate :: regex:: Regex ;
7
+ use crate :: syntax:: ModelineConfig ;
7
8
use crate :: { LineEnding , RopeSlice } ;
8
9
9
10
// 5 is the vim default
10
11
const LINES_TO_CHECK : usize = 5 ;
11
12
const LENGTH_TO_CHECK : usize = 256 ;
12
13
13
- static MODELINE_REGEX : Lazy < Regex > =
14
+ static VIM_MODELINE_REGEX : Lazy < Regex > =
14
15
Lazy :: new ( || Regex :: new ( r"^(\S*\s+)?(vi|[vV]im[<=>]?\d*|ex):\s*(set?\s+)?" ) . unwrap ( ) ) ;
16
+ static HELIX_MODELINE_REGEX : Lazy < Regex > = Lazy :: new ( || Regex :: new ( r"^(\S*\s+)?helix:" ) . unwrap ( ) ) ;
15
17
16
18
#[ derive( Default , Debug , Eq , PartialEq ) ]
17
19
pub struct Modeline {
@@ -65,7 +67,8 @@ impl Modeline {
65
67
} ;
66
68
c == ' ' || c == '\t'
67
69
} ;
68
- if let Some ( pos) = MODELINE_REGEX . find ( line) {
70
+
71
+ if let Some ( pos) = VIM_MODELINE_REGEX . find ( line) {
69
72
for option in line[ pos. end ( ) ..] . split ( split_modeline) {
70
73
let parts: Vec < _ > = option. split ( '=' ) . collect ( ) ;
71
74
match parts[ 0 ] {
@@ -93,6 +96,27 @@ impl Modeline {
93
96
}
94
97
}
95
98
}
99
+
100
+ if let Some ( pos) = HELIX_MODELINE_REGEX . find ( line) {
101
+ let config = & line[ pos. end ( ) ..] ;
102
+ match toml:: from_str :: < ModelineConfig > ( config) {
103
+ Ok ( modeline) => {
104
+ if let Some ( language) = modeline. language {
105
+ self . language = Some ( language) ;
106
+ }
107
+ if let Some ( indent) = modeline. indent {
108
+ self . indent_style = Some ( IndentStyle :: from_str ( & indent. unit ) ) ;
109
+ }
110
+ if let Some ( line_ending) = modeline. line_ending {
111
+ self . line_ending = LineEnding :: from_str ( & line_ending) ;
112
+ if self . line_ending . is_none ( ) {
113
+ log:: warn!( "could not interpret line ending {line_ending:?}" ) ;
114
+ }
115
+ }
116
+ }
117
+ Err ( e) => log:: warn!( "{e}" ) ,
118
+ }
119
+ }
96
120
}
97
121
}
98
122
@@ -223,6 +247,41 @@ mod test {
223
247
..Default :: default ( )
224
248
} ,
225
249
) ,
250
+ (
251
+ "# helix: language = 'perl'" ,
252
+ Modeline {
253
+ language : Some ( "perl" . to_string ( ) ) ,
254
+ ..Default :: default ( )
255
+ } ,
256
+ ) ,
257
+ (
258
+ "# helix: indent = { unit = ' ' }" ,
259
+ Modeline {
260
+ indent_style : Some ( IndentStyle :: Spaces ( 3 ) ) ,
261
+ ..Default :: default ( )
262
+ } ,
263
+ ) ,
264
+ (
265
+ "# helix: indent = { unit = \" \t \" }" ,
266
+ Modeline {
267
+ indent_style : Some ( IndentStyle :: Tabs ) ,
268
+ ..Default :: default ( )
269
+ } ,
270
+ ) ,
271
+ (
272
+ "# helix: indent = { unit = \" \\ t\" }" ,
273
+ Modeline {
274
+ indent_style : Some ( IndentStyle :: Tabs ) ,
275
+ ..Default :: default ( )
276
+ } ,
277
+ ) ,
278
+ (
279
+ "# helix: line-ending = \" \\ r\\ n\" " ,
280
+ Modeline {
281
+ line_ending : Some ( LineEnding :: Crlf ) ,
282
+ ..Default :: default ( )
283
+ } ,
284
+ ) ,
226
285
] ;
227
286
for ( line, expected) in tests {
228
287
let mut got = Modeline :: default ( ) ;
0 commit comments