@@ -10,7 +10,8 @@ use crate::rewrite::RewriteContext;
10
10
use crate :: shape:: { Indent , Shape } ;
11
11
use crate :: string:: { rewrite_string, StringFormat } ;
12
12
use crate :: utils:: {
13
- count_newlines, first_line_width, last_line_width, trim_left_preserve_layout, unicode_str_width,
13
+ count_newlines, first_line_width, last_line_width, tab_to_spaces, trim_left_preserve_layout,
14
+ unicode_str_width,
14
15
} ;
15
16
use crate :: { ErrorKind , FormattingError } ;
16
17
@@ -1162,14 +1163,6 @@ impl FullCodeCharKind {
1162
1163
self == FullCodeCharKind :: InStringCommented
1163
1164
|| self == FullCodeCharKind :: StartStringCommented
1164
1165
}
1165
-
1166
- fn to_codecharkind ( self ) -> CodeCharKind {
1167
- if self . is_comment ( ) {
1168
- CodeCharKind :: Comment
1169
- } else {
1170
- CodeCharKind :: Normal
1171
- }
1172
- }
1173
1166
}
1174
1167
1175
1168
impl < T > CharClasses < T >
@@ -1484,16 +1477,31 @@ impl<'a> Iterator for UngroupedCommentCodeSlices<'a> {
1484
1477
/// functional text. Line style comments contain their ending newlines.
1485
1478
pub ( crate ) struct CommentCodeSlices < ' a > {
1486
1479
slice : & ' a str ,
1487
- last_slice_kind : CodeCharKind ,
1488
- last_slice_end : usize ,
1480
+ ungrouped_code_slices : MultiPeek < UngroupedCommentCodeSlices < ' a > > ,
1481
+ offset : Option < usize > ,
1482
+ tab_spaces : usize ,
1489
1483
}
1490
1484
1491
1485
impl < ' a > CommentCodeSlices < ' a > {
1492
1486
pub ( crate ) fn new ( slice : & ' a str ) -> CommentCodeSlices < ' a > {
1493
1487
CommentCodeSlices {
1494
1488
slice,
1495
- last_slice_kind : CodeCharKind :: Comment ,
1496
- last_slice_end : 0 ,
1489
+ tab_spaces : 4 ,
1490
+ ungrouped_code_slices : multipeek ( UngroupedCommentCodeSlices :: new ( slice) ) ,
1491
+ offset : None ,
1492
+ }
1493
+ }
1494
+
1495
+ pub ( crate ) fn with_offset (
1496
+ slice : & ' a str ,
1497
+ offset : usize ,
1498
+ tab_spaces : usize ,
1499
+ ) -> CommentCodeSlices < ' a > {
1500
+ CommentCodeSlices {
1501
+ slice,
1502
+ tab_spaces,
1503
+ ungrouped_code_slices : multipeek ( UngroupedCommentCodeSlices :: new ( slice) ) ,
1504
+ offset : Some ( offset) . filter ( |o| * o != 0 ) ,
1497
1505
}
1498
1506
}
1499
1507
}
@@ -1502,59 +1510,50 @@ impl<'a> Iterator for CommentCodeSlices<'a> {
1502
1510
type Item = ( CodeCharKind , usize , & ' a str ) ;
1503
1511
1504
1512
fn next ( & mut self ) -> Option < Self :: Item > {
1505
- if self . last_slice_end == self . slice . len ( ) {
1506
- return None ;
1507
- }
1508
-
1509
- let mut sub_slice_end = self . last_slice_end ;
1510
- let mut first_whitespace = None ;
1511
- let subslice = & self . slice [ self . last_slice_end ..] ;
1512
- let mut iter = CharClasses :: new ( subslice. char_indices ( ) ) ;
1513
-
1514
- for ( kind, ( i, c) ) in & mut iter {
1515
- let is_comment_connector = self . last_slice_kind == CodeCharKind :: Normal
1516
- && & subslice[ ..2 ] == "//"
1517
- && [ ' ' , '\t' ] . contains ( & c) ;
1518
-
1519
- if is_comment_connector && first_whitespace. is_none ( ) {
1520
- first_whitespace = Some ( i) ;
1513
+ let first_chunk = self . ungrouped_code_slices . next ( ) ?;
1514
+ if first_chunk. 0 == CodeCharKind :: Normal {
1515
+ if !first_chunk. 2 . trim ( ) . is_empty ( ) {
1516
+ self . offset = Some ( last_line_width ( first_chunk. 2 ) ) . filter ( |o| * o != 0 ) ;
1521
1517
}
1518
+ return Some ( first_chunk) ;
1519
+ }
1522
1520
1523
- if kind. to_codecharkind ( ) == self . last_slice_kind && !is_comment_connector {
1524
- let last_index = match first_whitespace {
1525
- Some ( j) => j,
1526
- None => i,
1527
- } ;
1528
- sub_slice_end = self . last_slice_end + last_index;
1529
- break ;
1530
- }
1521
+ let mut comment_end_index = first_chunk. 1 + first_chunk. 2 . len ( ) ;
1522
+ while let Some ( & ( k, i, s) ) = self . ungrouped_code_slices . peek ( ) {
1523
+ match k {
1524
+ CodeCharKind :: Comment if self . offset . is_none ( ) => {
1525
+ comment_end_index = i + s. len ( ) ;
1526
+ self . ungrouped_code_slices . next ( ) ?;
1527
+ }
1528
+ CodeCharKind :: Comment => break ,
1529
+ CodeCharKind :: Normal if s. trim ( ) . is_empty ( ) && count_newlines ( s) == 0 => {
1530
+ let indent_width = tab_to_spaces ( s, self . tab_spaces ) ;
1531
+ if self . offset . map_or ( false , |comment_offset| {
1532
+ !( indent_width < comment_offset + 2 && comment_offset < indent_width + 2 )
1533
+ } ) {
1534
+ break ;
1535
+ }
1531
1536
1532
- if !is_comment_connector {
1533
- first_whitespace = None ;
1537
+ match self . ungrouped_code_slices . peek ( ) {
1538
+ Some ( ( CodeCharKind :: Comment , index, s) ) => {
1539
+ comment_end_index = index + s. len ( ) ;
1540
+ // Advance twice.
1541
+ self . ungrouped_code_slices . next ( ) ?;
1542
+ self . ungrouped_code_slices . next ( ) ?;
1543
+ }
1544
+ _ => break ,
1545
+ }
1546
+ }
1547
+ CodeCharKind :: Normal => break ,
1534
1548
}
1535
1549
}
1536
1550
1537
- if let ( None , true ) = ( iter. next ( ) , sub_slice_end == self . last_slice_end ) {
1538
- // This was the last subslice.
1539
- sub_slice_end = match first_whitespace {
1540
- Some ( i) => self . last_slice_end + i,
1541
- None => self . slice . len ( ) ,
1542
- } ;
1543
- }
1544
-
1545
- let kind = match self . last_slice_kind {
1546
- CodeCharKind :: Comment => CodeCharKind :: Normal ,
1547
- CodeCharKind :: Normal => CodeCharKind :: Comment ,
1548
- } ;
1549
- let res = (
1550
- kind,
1551
- self . last_slice_end ,
1552
- & self . slice [ self . last_slice_end ..sub_slice_end] ,
1553
- ) ;
1554
- self . last_slice_end = sub_slice_end;
1555
- self . last_slice_kind = kind;
1556
-
1557
- Some ( res)
1551
+ let comment_start_index = first_chunk. 1 ;
1552
+ Some ( (
1553
+ CodeCharKind :: Comment ,
1554
+ comment_start_index,
1555
+ & self . slice [ comment_start_index..comment_end_index] ,
1556
+ ) )
1558
1557
}
1559
1558
}
1560
1559
@@ -1728,7 +1727,6 @@ mod test {
1728
1727
let input = "// comment\n test();" ;
1729
1728
let mut iter = CommentCodeSlices :: new ( input) ;
1730
1729
1731
- assert_eq ! ( ( CodeCharKind :: Normal , 0 , "" ) , iter. next( ) . unwrap( ) ) ;
1732
1730
assert_eq ! (
1733
1731
( CodeCharKind :: Comment , 0 , "// comment\n " ) ,
1734
1732
iter. next( ) . unwrap( )
@@ -1742,18 +1740,67 @@ mod test {
1742
1740
1743
1741
#[ test]
1744
1742
fn comment_code_slices_three ( ) {
1745
- let input = "1 // comment\n // comment2\n \n " ;
1743
+ let input = "1 // comment\n // comment2\n \n " ;
1746
1744
let mut iter = CommentCodeSlices :: new ( input) ;
1747
1745
1748
1746
assert_eq ! ( ( CodeCharKind :: Normal , 0 , "1 " ) , iter. next( ) . unwrap( ) ) ;
1749
1747
assert_eq ! (
1750
- ( CodeCharKind :: Comment , 2 , "// comment\n // comment2\n " ) ,
1748
+ ( CodeCharKind :: Comment , 2 , "// comment\n // comment2\n " ) ,
1749
+ iter. next( ) . unwrap( )
1750
+ ) ;
1751
+ assert_eq ! ( ( CodeCharKind :: Normal , 27 , "\n " ) , iter. next( ) . unwrap( ) ) ;
1752
+ assert_eq ! ( None , iter. next( ) ) ;
1753
+ }
1754
+
1755
+ #[ test]
1756
+ fn comment_code_slices_four ( ) {
1757
+ let input = r#"
1758
+ if x == 3 {
1759
+ x = 4;
1760
+ } // if x == 3
1761
+ // end of block
1762
+ "# ;
1763
+ let mut iter = CommentCodeSlices :: new ( input) ;
1764
+
1765
+ assert_eq ! (
1766
+ (
1767
+ CodeCharKind :: Normal ,
1768
+ 0 ,
1769
+ r#"
1770
+ if x == 3 {
1771
+ x = 4;
1772
+ } "#
1773
+ ) ,
1774
+ iter. next( ) . unwrap( )
1775
+ ) ;
1776
+ assert_eq ! (
1777
+ ( CodeCharKind :: Comment , 26 , "// if x == 3\n " , ) ,
1778
+ iter. next( ) . unwrap( )
1779
+ ) ;
1780
+ assert_eq ! (
1781
+ ( CodeCharKind :: Comment , 39 , "// end of block\n " ) ,
1751
1782
iter. next( ) . unwrap( )
1752
1783
) ;
1753
- assert_eq ! ( ( CodeCharKind :: Normal , 29 , "\n " ) , iter. next( ) . unwrap( ) ) ;
1754
1784
assert_eq ! ( None , iter. next( ) ) ;
1755
1785
}
1756
1786
1787
+ #[ test]
1788
+ fn comment_code_slices_five ( ) {
1789
+ let input = "1 // comment\r \n \r \n // comment2\r \n " ;
1790
+ let mut iter = CommentCodeSlices :: new ( input) ;
1791
+
1792
+ assert_eq ! ( ( CodeCharKind :: Normal , 0 , "1 " ) , iter. next( ) . unwrap( ) ) ;
1793
+ assert_eq ! (
1794
+ ( CodeCharKind :: Comment , 2 , "// comment\r \n " ) ,
1795
+ iter. next( ) . unwrap( )
1796
+ ) ;
1797
+ assert_eq ! ( ( CodeCharKind :: Normal , 14 , "\r \n " , ) , iter. next( ) . unwrap( ) ) ;
1798
+ assert_eq ! (
1799
+ ( CodeCharKind :: Comment , 18 , "// comment2\r \n " ) ,
1800
+ iter. next( ) . unwrap( )
1801
+ ) ;
1802
+ assert_eq ! ( None , iter. next( ) ) ;
1803
+ }
1757
1804
#[ test]
1758
1805
#[ rustfmt:: skip]
1759
1806
fn format_doc_comments ( ) {
0 commit comments