@@ -6,6 +6,7 @@ use crate::renderer::{RenderContext, Renderer};
6
6
use crate :: theme:: { self , playpen_editor, Theme } ;
7
7
use crate :: utils;
8
8
9
+ use std:: borrow:: Cow ;
9
10
use std:: collections:: BTreeMap ;
10
11
use std:: collections:: HashMap ;
11
12
use std:: fs;
@@ -584,6 +585,7 @@ fn fix_code_blocks(html: &str) -> String {
584
585
}
585
586
586
587
fn add_playpen_pre ( html : & str , playpen_config : & Playpen ) -> String {
588
+ let boring_line_regex = Regex :: new ( r"^(\s*)#(#|.)(.*)$" ) . unwrap ( ) ;
587
589
let regex = Regex :: new ( r##"((?s)<code[^>]?class="([^"]+)".*?>(.*?)</code>)"## ) . unwrap ( ) ;
588
590
regex
589
591
. replace_all ( html, |caps : & Captures < ' _ > | {
@@ -597,21 +599,45 @@ fn add_playpen_pre(html: &str, playpen_config: &Playpen) -> String {
597
599
|| classes. contains ( "mdbook-runnable" )
598
600
{
599
601
// wrap the contents in an external pre block
600
- if playpen_config. editable && classes. contains ( "editable" )
601
- || text. contains ( "fn main" )
602
- || text. contains ( "quick_main!" )
603
- {
604
- format ! ( "<pre class=\" playpen\" >{}</pre>" , text)
605
- } else {
606
- // we need to inject our own main
607
- let ( attrs, code) = partition_source ( code) ;
608
-
609
- format ! (
610
- "<pre class=\" playpen\" ><code class=\" {}\" >\n # \
611
- #![allow(unused_variables)]\n {}#fn main() {{\n {}#}}</code></pre>",
612
- classes, attrs, code
613
- )
614
- }
602
+ format ! ( "<pre class=\" playpen\" ><code class=\" {}\" >{}</code></pre>" ,
603
+ classes,
604
+ {
605
+ let content: Cow <str > = if playpen_config. editable && classes. contains( "editable" )
606
+ || text. contains( "fn main" )
607
+ || text. contains( "quick_main!" )
608
+ {
609
+ code. into( )
610
+ } else {
611
+ // we need to inject our own main
612
+ let ( attrs, code) = partition_source( code) ;
613
+
614
+ format!( "\n # #![allow(unused_variables)]\n {}#fn main() {{\n {}#}}" ,
615
+ attrs, code
616
+ ) . into( )
617
+ } ;
618
+ let mut prev_line_hidden = false ;
619
+ let mut result = String :: with_capacity( content. len( ) ) ;
620
+ for line in content. lines( ) {
621
+ if let Some ( caps) = boring_line_regex. captures( line) {
622
+ if !prev_line_hidden && & caps[ 2 ] != "#" {
623
+ result += "<span class=\" boring\" >" ;
624
+ prev_line_hidden = true ;
625
+ }
626
+ result += & caps[ 1 ] ;
627
+ if & caps[ 2 ] != " " { result += & caps[ 2 ] ; }
628
+ result += & caps[ 3 ] ;
629
+ } else {
630
+ if prev_line_hidden {
631
+ result += "</span>" ;
632
+ prev_line_hidden = false ;
633
+ }
634
+ result += line;
635
+ }
636
+ result += "\n " ;
637
+ }
638
+ result
639
+ }
640
+ )
615
641
} else {
616
642
// not language-rust, so no-op
617
643
text. to_owned ( )
@@ -687,4 +713,22 @@ mod tests {
687
713
assert_eq ! ( got, should_be) ;
688
714
}
689
715
}
716
+
717
+ #[ test]
718
+ fn add_playpen ( ) {
719
+ let inputs = [
720
+ ( "<code class=\" language-rust\" >x()</code>" ,
721
+ "<pre class=\" playpen\" ><code class=\" language-rust\" >\n <span class=\" boring\" >#![allow(unused_variables)]\n fn main() {\n </span>x()\n <span class=\" boring\" >}\n </code></pre>" ) ,
722
+ ( "<code class=\" language-rust\" >fn main() {}</code>" ,
723
+ "<pre class=\" playpen\" ><code class=\" language-rust\" >fn main() {}\n </code></pre>" ) ,
724
+ ( "<code class=\" language-rust editable\" >let s = \" foo\n # bar\n \" ;</code>" ,
725
+ "<pre class=\" playpen\" ><code class=\" language-rust editable\" >let s = \" foo\n <span class=\" boring\" > bar\n </span>\" ;\n </code></pre>" ) ,
726
+ ( "<code class=\" language-rust editable\" >let s = \" foo\n ## bar\n \" ;</code>" ,
727
+ "<pre class=\" playpen\" ><code class=\" language-rust editable\" >let s = \" foo\n # bar\n \" ;\n </code></pre>" ) ,
728
+ ] ;
729
+ for ( src, should_be) in & inputs {
730
+ let got = add_playpen_pre ( src, & Playpen { editable : true , ..Playpen :: default ( ) } ) ;
731
+ assert_eq ! ( & * got, * should_be) ;
732
+ }
733
+ }
690
734
}
0 commit comments