@@ -30,42 +30,86 @@ impl HeredocKind {
3030 }
3131}
3232
33+ /// A segment of heredoc content. Used to distinguish between content that should
34+ /// receive squiggly indentation and content from nested non-squiggly heredocs
35+ /// that should not be indented.
36+ #[ derive( Debug , Clone ) ]
37+ pub enum HeredocSegment {
38+ Normal ( String ) ,
39+ /// Content from nested non-squiggly heredocs, should never receive squiggly indentation.
40+ /// This includes both the heredoc content and the closing identifier.
41+ Raw ( String ) ,
42+ }
43+
3344#[ derive( Debug , Clone ) ]
3445pub struct HeredocString < ' src > {
3546 symbol : Cow < ' src , str > ,
3647 pub kind : HeredocKind ,
37- pub buf : Vec < u8 > ,
48+ pub segments : Vec < HeredocSegment > ,
3849 pub indent : ColNumber ,
3950}
4051
4152impl < ' src > HeredocString < ' src > {
42- pub fn new ( symbol : Cow < ' src , str > , kind : HeredocKind , buf : Vec < u8 > , indent : ColNumber ) -> Self {
53+ pub fn new (
54+ symbol : Cow < ' src , str > ,
55+ kind : HeredocKind ,
56+ segments : Vec < HeredocSegment > ,
57+ indent : ColNumber ,
58+ ) -> Self {
4359 HeredocString {
4460 symbol,
4561 kind,
46- buf ,
62+ segments ,
4763 indent,
4864 }
4965 }
5066
5167 pub fn render_as_string ( self ) -> String {
5268 let indent = self . indent ;
53- let string = String :: from_utf8 ( self . buf ) . expect ( "heredoc is utf8" ) ;
5469
5570 if self . kind . is_squiggly ( ) {
56- string
57- . split ( '\n' )
58- . map ( |l| {
59- String :: from ( format ! ( "{}{}" , get_indent( indent as usize + 2 ) , l) . trim_end ( ) )
60- } )
61- . collect :: < Vec < String > > ( )
62- . join ( "\n " )
71+ // For squiggly heredocs, we need to apply indentation to Normal segments
72+ // but not to Raw segments (which come from nested non-squiggly heredocs).
73+ let mut result = String :: new ( ) ;
74+ for segment in self . segments {
75+ match segment {
76+ HeredocSegment :: Normal ( content) => {
77+ // Apply squiggly indentation to each line
78+ for ( i, line) in content. split ( '\n' ) . enumerate ( ) {
79+ if i > 0 {
80+ result. push ( '\n' ) ;
81+ }
82+ let indented = format ! ( "{}{}" , get_indent( indent as usize + 2 ) , line) ;
83+ result. push_str ( indented. trim_end ( ) ) ;
84+ }
85+ }
86+ HeredocSegment :: Raw ( content) => {
87+ // No indentation for raw content (nested non-squiggly heredocs)
88+ for ( i, line) in content. split ( '\n' ) . enumerate ( ) {
89+ if i > 0 {
90+ result. push ( '\n' ) ;
91+ }
92+ result. push_str ( line. trim_end ( ) ) ;
93+ }
94+ }
95+ }
96+ }
97+ result
6398 } else {
64- string
65- . split ( '\n' )
66- . map ( |l| l. trim_end ( ) )
67- . collect :: < Vec < & str > > ( )
68- . join ( "\n " )
99+ // For non-squiggly heredocs, just join segments and trim line endings
100+ let mut result = String :: new ( ) ;
101+ for segment in self . segments {
102+ let content = match segment {
103+ HeredocSegment :: Normal ( s) | HeredocSegment :: Raw ( s) => s,
104+ } ;
105+ for ( i, line) in content. split ( '\n' ) . enumerate ( ) {
106+ if i > 0 {
107+ result. push ( '\n' ) ;
108+ }
109+ result. push_str ( line. trim_end ( ) ) ;
110+ }
111+ }
112+ result
69113 }
70114 }
71115
0 commit comments