@@ -16,6 +16,7 @@ pub struct Shortcode {
16
16
// In practice, span.len() is always equal to SHORTCODE_PLACEHOLDER.len()
17
17
pub ( crate ) span : Range < usize > ,
18
18
pub ( crate ) body : Option < String > ,
19
+ pub ( crate ) indent : String ,
19
20
pub ( crate ) nth : usize ,
20
21
pub ( crate ) inner : Vec < Shortcode > ,
21
22
// set later down the line, for quick access without needing the definitions
@@ -88,9 +89,18 @@ impl Shortcode {
88
89
new_context. insert ( "nth" , & self . nth ) ;
89
90
new_context. extend ( context. clone ( ) ) ;
90
91
91
- let res = utils:: templates:: render_template ( & tpl_name, tera, new_context, & None )
92
- . with_context ( || format ! ( "Failed to render {} shortcode" , name) ) ?
93
- . replace ( "\r \n " , "\n " ) ;
92
+ let rendered = utils:: templates:: render_template ( & tpl_name, tera, new_context, & None )
93
+ . with_context ( || format ! ( "Failed to render {} shortcode" , name) ) ?;
94
+ // Append the rendered text, but indenting each line after the first one as much as the line in which the shortcode was called.
95
+ let mut res = String :: with_capacity ( rendered. len ( ) ) ;
96
+ let mut lines = rendered. split_terminator ( '\n' ) ;
97
+ if let Some ( first_line) = lines. next ( ) {
98
+ res. push_str ( first_line. trim_end_matches ( '\r' ) ) ;
99
+ for line in lines {
100
+ res. push_str ( & self . indent ) ;
101
+ res. push_str ( line. trim_end_matches ( '\r' ) ) ;
102
+ }
103
+ }
94
104
95
105
Ok ( res)
96
106
}
@@ -246,17 +256,31 @@ pub fn parse_for_shortcodes(
246
256
247
257
// We have at least a `page` pair
248
258
for p in pairs. next ( ) . unwrap ( ) . into_inner ( ) {
259
+ fn current_indent ( text : & str ) -> & str {
260
+ let current_line = match text. rsplit_once ( '\n' ) {
261
+ Some ( ( _, line) ) => line,
262
+ None => text,
263
+ } ;
264
+ // Stop at the first character that is not considered indentation by the CommonMark spec.
265
+ match current_line. split_once ( |ch| ch != ' ' && ch != '\t' ) {
266
+ Some ( ( whitespace, _) ) => whitespace,
267
+ None => current_line,
268
+ }
269
+ }
270
+
249
271
match p. as_rule ( ) {
250
272
Rule :: text => output. push_str ( p. as_span ( ) . as_str ( ) ) ,
251
273
Rule :: inline_shortcode => {
252
274
let start = output. len ( ) ;
275
+ let indent = current_indent ( & output) . into ( ) ;
253
276
let ( name, args) = parse_shortcode_call ( p) ;
254
277
let nth = invocation_counter. get ( & name) ;
255
278
shortcodes. push ( Shortcode {
256
279
name,
257
280
args,
258
281
span : start..( start + SHORTCODE_PLACEHOLDER . len ( ) ) ,
259
282
body : None ,
283
+ indent,
260
284
nth,
261
285
inner : Vec :: new ( ) ,
262
286
tera_name : String :: new ( ) ,
@@ -265,6 +289,7 @@ pub fn parse_for_shortcodes(
265
289
}
266
290
Rule :: shortcode_with_body => {
267
291
let start = output. len ( ) ;
292
+ let indent = current_indent ( & output) . into ( ) ;
268
293
let mut inner = p. into_inner ( ) ;
269
294
// 3 items in inner: call, body, end
270
295
// we don't care about the closing tag
@@ -279,6 +304,7 @@ pub fn parse_for_shortcodes(
279
304
args,
280
305
span : start..( start + SHORTCODE_PLACEHOLDER . len ( ) ) ,
281
306
body : Some ( body) ,
307
+ indent,
282
308
nth,
283
309
inner,
284
310
tera_name : String :: new ( ) ,
@@ -422,6 +448,7 @@ mod tests {
422
448
args : Value :: Null ,
423
449
span : 10 ..20 ,
424
450
body : None ,
451
+ indent : String :: new ( ) ,
425
452
nth : 0 ,
426
453
inner : Vec :: new ( ) ,
427
454
tera_name : String :: new ( ) ,
@@ -442,6 +469,7 @@ mod tests {
442
469
args : Value :: Null ,
443
470
span : 42 ..65 ,
444
471
body : None ,
472
+ indent : String :: new ( ) ,
445
473
nth : 0 ,
446
474
inner : Vec :: new ( ) ,
447
475
tera_name : String :: new ( ) ,
0 commit comments