@@ -212,8 +212,6 @@ fn process_diagnostics(
212212 . filter_map ( |( i, c) | if c == b'\n' { Some ( i) } else { None } )
213213 . collect :: < Vec < usize > > ( ) ;
214214
215- let diag_copy = diags. clone ( ) ;
216-
217215 let mut expected = extract_expected_diags ( source) ;
218216 let captures: Vec < _ > =
219217 expected. iter ( ) . map ( |expected| & expected. comment_range ) . cloned ( ) . collect ( ) ;
@@ -305,7 +303,7 @@ fn process_diagnostics(
305303
306304 if !success && update {
307305 let mut source = source. to_string ( ) ;
308- self :: update ( diag_copy , & mut source, lines, & captures) ;
306+ self :: update ( & diags , & mut source, lines, & captures) ;
309307 std:: fs:: write ( path, source) . unwrap ( ) ;
310308 }
311309
@@ -314,7 +312,7 @@ fn process_diagnostics(
314312
315313/// Rewrite the source to remove the old comments and add accurate error comments
316314fn update (
317- mut diags : Vec < & Diagnostic > ,
315+ diags : & [ & Diagnostic ] ,
318316 source : & mut String ,
319317 mut lines : Vec < usize > ,
320318 to_remove : & [ std:: ops:: Range < usize > ] ,
@@ -328,42 +326,57 @@ fn update(
328326 }
329327 }
330328
331- diags. sort_by_key ( |d| {
332- let ( l, c) = d. line_column ( ) ;
333- ( usize:: MAX - l, c)
334- } ) ;
335-
336- let mut last_line = 0 ;
337- let mut last_line_adjust = 0 ;
329+ let mut last_line_adjust = Vec :: from_iter ( std:: iter:: repeat_n ( 0 , lines. len ( ) ) ) ;
338330
339331 for d in diags {
340- let ( l, c) = d. line_column ( ) ;
341- if c < 3 {
342- panic ! ( "Error message cannot be on the column < 3: {d:?}" )
343- }
332+ let mut insert_range_at = |range : & str , l, c : usize | {
333+ let column_adjust = if c < 3 { "<" . repeat ( 3 - c) } else { "" . to_string ( ) } ;
334+ let byte_offset = lines[ l - 1 ] + 1 ;
335+ let to_insert = format ! (
336+ "//{indent}{range}{adjust}{column_adjust}{error_or_warning}{{{message}}}\n " ,
337+ indent = " " . repeat( c. max( 3 ) - 3 ) ,
338+ adjust = "^" . repeat( last_line_adjust[ l - 1 ] ) ,
339+ error_or_warning =
340+ if d. level( ) == DiagnosticLevel :: Error { "error" } else { "warning" } ,
341+ message = d. message( ) . replace( '\n' , "↵" ) . replace( env!( "CARGO_MANIFEST_DIR" ) , "📂" )
342+ ) ;
343+ if byte_offset > source. len ( ) {
344+ source. push ( '\n' ) ;
345+ }
346+ source. insert_str ( byte_offset, & to_insert) ;
347+ for line in ( l - 1 ) ..lines. len ( ) {
348+ lines[ line] += to_insert. len ( ) ;
349+ }
350+ last_line_adjust[ l - 1 ] += 1 ;
351+ } ;
344352
345- if last_line == l {
346- last_line_adjust += 1 ;
353+ let ( line_start, column_start) = d. line_column ( ) ;
354+ let ( line_end, column_end) = d. end_line_column ( ) ;
355+
356+ // The end column is exclusive, therefore use - 1 here
357+ let range = if d. length ( ) <= 1 {
358+ // Single-character diagnostic, use "^" for the marker
359+ "^" . to_owned ( )
347360 } else {
348- last_line = l;
349- last_line_adjust = 0 ;
350- }
361+ let end = if line_start == line_end {
362+ // Same line, we can insert the closing "<"
363+ " " . repeat ( column_end - column_start - 2 ) + "<"
364+ } else {
365+ // End is on a different line, we'll emit it later
366+ "" . to_owned ( )
367+ } ;
368+ format ! ( ">{end}" )
369+ } ;
351370
352- let byte_offset = lines [ l - 1 ] + 1 ;
371+ insert_range_at ( & range , line_start , column_start ) ;
353372
354- let to_insert = format ! (
355- "//{indent}^{adjust}{error_or_warning}{{{message}}}\n " ,
356- indent = " " . repeat( c - 3 ) ,
357- adjust = "^" . repeat( last_line_adjust) ,
358- error_or_warning =
359- if d. level( ) == DiagnosticLevel :: Error { "error" } else { "warning" } ,
360- message = d. message( ) . replace( '\n' , "↵" ) . replace( env!( "CARGO_MANIFEST_DIR" ) , "📂" )
361- ) ;
362- if byte_offset > source. len ( ) {
363- source. push ( '\n' ) ;
373+ // Insert the closing `<` at another line if necessary
374+ // Edge-case: If a single-character diagnostic is on a newline character (\n), its
375+ // end_line_column is technically on a new line, but the single ^ marker is enough, so no
376+ // closing character is needed.
377+ if line_start != line_end && d. length ( ) > 1 {
378+ insert_range_at ( "<" , line_end, column_end - 1 ) ;
364379 }
365- source. insert_str ( byte_offset, & to_insert) ;
366- lines[ l - 1 ] += to_insert. len ( ) ;
367380 }
368381}
369382
0 commit comments