@@ -129,6 +129,7 @@ pub(super) struct State<'sess, 'ast> {
129
129
inline_config : InlineConfig < ( ) > ,
130
130
cursor : SourcePos ,
131
131
132
+ has_crlf : bool ,
132
133
contract : Option < & ' ast ast:: ItemContract < ' ast > > ,
133
134
single_line_stmt : Option < bool > ,
134
135
named_call_expr : bool ,
@@ -170,6 +171,10 @@ impl SourcePos {
170
171
self . enabled = enabled;
171
172
}
172
173
174
+ pub ( super ) fn next_line ( & mut self , is_at_crlf : bool ) {
175
+ self . pos += if is_at_crlf { 2 } else { 1 } ;
176
+ }
177
+
173
178
pub ( super ) fn span ( & self , to : BytePos ) -> Span {
174
179
Span :: new ( self . pos , to)
175
180
}
@@ -183,14 +188,15 @@ pub(super) enum Separator {
183
188
}
184
189
185
190
impl Separator {
186
- fn print ( & self , p : & mut pp:: Printer , cursor : & mut SourcePos ) {
191
+ fn print ( & self , p : & mut pp:: Printer , cursor : & mut SourcePos , is_at_crlf : bool ) {
187
192
match self {
188
193
Self :: Nbsp => p. nbsp ( ) ,
189
194
Self :: Space => p. space ( ) ,
190
195
Self :: Hardbreak => p. hardbreak ( ) ,
191
196
Self :: SpaceOrNbsp ( breaks) => p. space_or_nbsp ( * breaks) ,
192
197
}
193
- cursor. advance ( 1 ) ;
198
+
199
+ cursor. next_line ( is_at_crlf) ;
194
200
}
195
201
}
196
202
@@ -217,6 +223,7 @@ impl<'sess> State<'sess, '_> {
217
223
config,
218
224
inline_config,
219
225
cursor : SourcePos { pos : BytePos :: from_u32 ( 0 ) , enabled : true } ,
226
+ has_crlf : false ,
220
227
contract : None ,
221
228
single_line_stmt : None ,
222
229
named_call_expr : false ,
@@ -228,6 +235,25 @@ impl<'sess> State<'sess, '_> {
228
235
}
229
236
}
230
237
238
+ /// Checks a span of the source for a carriage return (`\r`) to determine if the file
239
+ /// uses CRLF line endings.
240
+ ///
241
+ /// If a `\r` is found, `self.has_crlf` is set to `true`. This is intended to be
242
+ /// called once at the beginning of the formatting process for efficiency.
243
+ fn check_crlf ( & mut self , span : Span ) {
244
+ if let Ok ( snip) = self . sm . span_to_snippet ( span)
245
+ && snip. contains ( '\r' )
246
+ {
247
+ self . has_crlf = true ;
248
+ }
249
+ }
250
+
251
+ /// Checks if the cursor is currently positioned at the start of a CRLF sequence (`\r\n`).
252
+ /// The check is only meaningful if `self.has_crlf` is true.
253
+ fn is_at_crlf ( & self ) -> bool {
254
+ self . has_crlf && self . char_at ( self . cursor . pos ) == Some ( '\r' )
255
+ }
256
+
231
257
fn space_left ( & self ) -> usize {
232
258
std:: cmp:: min (
233
259
self . s . space_left ( ) ,
@@ -272,9 +298,9 @@ impl<'sess> State<'sess, '_> {
272
298
273
299
/// Span to source.
274
300
impl State < ' _ , ' _ > {
275
- fn char_at ( & self , pos : BytePos ) -> char {
301
+ fn char_at ( & self , pos : BytePos ) -> Option < char > {
276
302
let res = self . sm . lookup_byte_offset ( pos) ;
277
- res. sf . src [ res. pos . to_usize ( ) ..] . chars ( ) . next ( ) . unwrap ( )
303
+ res. sf . src . get ( res. pos . to_usize ( ) ..) ? . chars ( ) . next ( )
278
304
}
279
305
280
306
fn print_span ( & mut self , span : Span ) {
@@ -340,11 +366,19 @@ impl State<'_, '_> {
340
366
}
341
367
342
368
fn print_sep ( & mut self , sep : Separator ) {
343
- if self . handle_span ( self . cursor . span ( self . cursor . pos + BytePos ( 1 ) ) , true ) {
369
+ if self . handle_span (
370
+ self . cursor . span ( self . cursor . pos + if self . is_at_crlf ( ) { 2 } else { 1 } ) ,
371
+ true ,
372
+ ) {
344
373
return ;
345
374
}
346
375
347
- sep. print ( & mut self . s , & mut self . cursor ) ;
376
+ self . print_sep_unhandled ( sep) ;
377
+ }
378
+
379
+ fn print_sep_unhandled ( & mut self , sep : Separator ) {
380
+ let is_at_crlf = self . is_at_crlf ( ) ;
381
+ sep. print ( & mut self . s , & mut self . cursor , is_at_crlf) ;
348
382
}
349
383
350
384
fn print_ident ( & mut self , ident : & ast:: Ident ) {
@@ -698,7 +732,7 @@ impl<'sess> State<'sess, '_> {
698
732
let hb = |this : & mut Self | {
699
733
this. hardbreak ( ) ;
700
734
if pos. is_last {
701
- this. cursor . advance ( 1 ) ;
735
+ this. cursor . next_line ( this . is_at_crlf ( ) ) ;
702
736
}
703
737
} ;
704
738
if line. is_empty ( ) {
@@ -732,7 +766,7 @@ impl<'sess> State<'sess, '_> {
732
766
let hb = |this : & mut Self | {
733
767
this. hardbreak ( ) ;
734
768
if pos. is_last {
735
- this. cursor . advance ( 1 ) ;
769
+ this. cursor . next_line ( this . is_at_crlf ( ) ) ;
736
770
}
737
771
} ;
738
772
if line. is_empty ( ) {
@@ -808,7 +842,7 @@ impl<'sess> State<'sess, '_> {
808
842
// Pre-requisite: ensure that blank links are printed at the beginning of new line.
809
843
if !self . last_token_is_break ( ) && !self . is_bol_or_only_ind ( ) {
810
844
config. hardbreak ( & mut self . s ) ;
811
- self . cursor . advance ( 1 ) ;
845
+ self . cursor . next_line ( self . is_at_crlf ( ) ) ;
812
846
}
813
847
814
848
// We need to do at least one, possibly two hardbreaks.
@@ -820,10 +854,10 @@ impl<'sess> State<'sess, '_> {
820
854
} ;
821
855
if twice {
822
856
config. hardbreak ( & mut self . s ) ;
823
- self . cursor . advance ( 1 ) ;
857
+ self . cursor . next_line ( self . is_at_crlf ( ) ) ;
824
858
}
825
859
config. hardbreak ( & mut self . s ) ;
826
- self . cursor . advance ( 1 ) ;
860
+ self . cursor . next_line ( self . is_at_crlf ( ) ) ;
827
861
}
828
862
}
829
863
}
0 commit comments