@@ -10,7 +10,8 @@ use crate::rewrite::RewriteContext;
1010use crate :: shape:: { Indent , Shape } ;
1111use crate :: string:: { rewrite_string, StringFormat } ;
1212use 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,
1415} ;
1516use crate :: { ErrorKind , FormattingError } ;
1617
@@ -1162,14 +1163,6 @@ impl FullCodeCharKind {
11621163 self == FullCodeCharKind :: InStringCommented
11631164 || self == FullCodeCharKind :: StartStringCommented
11641165 }
1165-
1166- fn to_codecharkind ( self ) -> CodeCharKind {
1167- if self . is_comment ( ) {
1168- CodeCharKind :: Comment
1169- } else {
1170- CodeCharKind :: Normal
1171- }
1172- }
11731166}
11741167
11751168impl < T > CharClasses < T >
@@ -1484,16 +1477,31 @@ impl<'a> Iterator for UngroupedCommentCodeSlices<'a> {
14841477/// functional text. Line style comments contain their ending newlines.
14851478pub ( crate ) struct CommentCodeSlices < ' a > {
14861479 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 ,
14891483}
14901484
14911485impl < ' a > CommentCodeSlices < ' a > {
14921486 pub ( crate ) fn new ( slice : & ' a str ) -> CommentCodeSlices < ' a > {
14931487 CommentCodeSlices {
14941488 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 ) ,
14971505 }
14981506 }
14991507}
@@ -1502,59 +1510,50 @@ impl<'a> Iterator for CommentCodeSlices<'a> {
15021510 type Item = ( CodeCharKind , usize , & ' a str ) ;
15031511
15041512 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 ) ;
15211517 }
1518+ return Some ( first_chunk) ;
1519+ }
15221520
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+ }
15311536
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 ,
15341548 }
15351549 }
15361550
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+ ) )
15581557 }
15591558}
15601559
@@ -1728,7 +1727,6 @@ mod test {
17281727 let input = "// comment\n test();" ;
17291728 let mut iter = CommentCodeSlices :: new ( input) ;
17301729
1731- assert_eq ! ( ( CodeCharKind :: Normal , 0 , "" ) , iter. next( ) . unwrap( ) ) ;
17321730 assert_eq ! (
17331731 ( CodeCharKind :: Comment , 0 , "// comment\n " ) ,
17341732 iter. next( ) . unwrap( )
@@ -1742,18 +1740,67 @@ mod test {
17421740
17431741 #[ test]
17441742 fn comment_code_slices_three ( ) {
1745- let input = "1 // comment\n // comment2\n \n " ;
1743+ let input = "1 // comment\n // comment2\n \n " ;
17461744 let mut iter = CommentCodeSlices :: new ( input) ;
17471745
17481746 assert_eq ! ( ( CodeCharKind :: Normal , 0 , "1 " ) , iter. next( ) . unwrap( ) ) ;
17491747 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 " ) ,
17511782 iter. next( ) . unwrap( )
17521783 ) ;
1753- assert_eq ! ( ( CodeCharKind :: Normal , 29 , "\n " ) , iter. next( ) . unwrap( ) ) ;
17541784 assert_eq ! ( None , iter. next( ) ) ;
17551785 }
17561786
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+ }
17571804 #[ test]
17581805 #[ rustfmt:: skip]
17591806 fn format_doc_comments ( ) {
0 commit comments