@@ -67,19 +67,27 @@ impl PresentationBuilder<'_, '_> {
6767 let block_length = self . push_code_lines ( & snippet) ;
6868 match snippet. attributes . execution . clone ( ) {
6969 SnippetExec :: None => Ok ( ( ) ) ,
70- SnippetExec :: Exec ( _) | SnippetExec :: AcquireTerminal ( _) if !execution_allowed => {
71- let exec_type = match snippet. attributes . representation {
70+ SnippetExec :: Exec ( _) | SnippetExec :: AutoExec ( _ ) | SnippetExec :: AcquireTerminal ( _) if !execution_allowed => {
71+ let mut exec_type = match snippet. attributes . representation {
7272 SnippetRepr :: Image => ExecutionType :: Image ,
7373 SnippetRepr :: ExecReplace => ExecutionType :: ExecReplace ,
7474 SnippetRepr :: Render | SnippetRepr :: Snippet => ExecutionType :: Execute ,
7575 } ;
76+ if matches ! ( snippet. attributes. execution, SnippetExec :: AutoExec ( _) ) {
77+ exec_type = ExecutionType :: ExecReplace ;
78+ }
7679 self . push_execution_disabled_operation ( exec_type) ;
7780 Ok ( ( ) )
7881 }
79- SnippetExec :: Exec ( spec) => {
82+ SnippetExec :: Exec ( spec) | SnippetExec :: AutoExec ( spec) => {
83+ let policy = if matches ! ( snippet. attributes. execution, SnippetExec :: AutoExec ( _) ) {
84+ RenderAsyncStartPolicy :: Automatic
85+ } else {
86+ RenderAsyncStartPolicy :: OnDemand
87+ } ;
8088 let executor = self . snippet_executor . language_executor ( & snippet. language , & spec) ?;
8189 let alignment = self . code_style ( & snippet) . alignment ;
82- let handle = SnippetHandle :: new ( snippet. clone ( ) , executor, RenderAsyncStartPolicy :: OnDemand ) ;
90+ let handle = SnippetHandle :: new ( snippet. clone ( ) , executor, policy ) ;
8391 self . chunk_operations
8492 . push ( RenderOperation :: RenderAsync ( Rc :: new ( RunSnippetTrigger :: new ( handle. clone ( ) ) ) ) ) ;
8593 self . push_indicator ( handle. clone ( ) , block_length, alignment) ;
@@ -113,7 +121,10 @@ impl PresentationBuilder<'_, '_> {
113121
114122 fn is_execution_allowed ( & self , snippet : & Snippet ) -> bool {
115123 match snippet. attributes . representation {
116- SnippetRepr :: Snippet => self . options . enable_snippet_execution ,
124+ SnippetRepr :: Snippet => match snippet. attributes . execution {
125+ SnippetExec :: AutoExec ( _) => self . options . enable_snippet_execution_replace ,
126+ _ => self . options . enable_snippet_execution ,
127+ } ,
117128 SnippetRepr :: Image | SnippetRepr :: ExecReplace => self . options . enable_snippet_execution_replace ,
118129 SnippetRepr :: Render => true ,
119130 }
@@ -361,7 +372,11 @@ impl AsRenderOperations for Differ {
361372#[ cfg( all( test, target_os = "linux" ) ) ]
362373mod tests {
363374 use super :: * ;
364- use crate :: { markdown:: text_style:: Color , presentation:: builder:: utils:: Test , theme:: raw} ;
375+ use crate :: {
376+ markdown:: text_style:: Color ,
377+ presentation:: builder:: utils:: { RunAsyncRendersPolicy , Test } ,
378+ theme:: raw,
379+ } ;
365380 use rstest:: rstest;
366381 use std:: fs;
367382
@@ -436,7 +451,16 @@ echo hi
436451```
437452---" ;
438453 let lines = Test :: new ( input) . render ( ) . rows ( 7 ) . columns ( 7 ) . into_lines ( ) ;
439- let expected = & [ " " , "———————" , " " , "echo hi" , " " , "———————" , " " ] ;
454+ let expected = & [
455+ //
456+ " " ,
457+ "———————" ,
458+ " " ,
459+ "echo hi" ,
460+ " " ,
461+ "———————" ,
462+ " " ,
463+ ] ;
440464 assert_eq ! ( lines, expected) ;
441465 }
442466
@@ -454,7 +478,14 @@ echo hi
454478 ..Default :: default ( )
455479 } ;
456480 let lines = Test :: new ( input) . theme ( theme) . render ( ) . rows ( 5 ) . columns ( 13 ) . into_lines ( ) ;
457- let expected = & [ " " , " " , " echo hi " , " " , " " ] ;
481+ let expected = & [
482+ //
483+ " " ,
484+ " " ,
485+ " echo hi " ,
486+ " " ,
487+ " " ,
488+ ] ;
458489 assert_eq ! ( lines, expected) ;
459490 }
460491
@@ -464,8 +495,39 @@ echo hi
464495```bash +exec
465496echo hi
466497```" ;
467- let lines = Test :: new ( input) . render ( ) . rows ( 4 ) . columns ( 19 ) . run_async_renders ( false ) . into_lines ( ) ;
468- let expected = & [ " " , "echo hi " , " " , "—— [not started] ——" ] ;
498+ let lines =
499+ Test :: new ( input) . render ( ) . rows ( 4 ) . columns ( 19 ) . run_async_renders ( RunAsyncRendersPolicy :: None ) . into_lines ( ) ;
500+ let expected = & [
501+ //
502+ " " ,
503+ "echo hi " ,
504+ " " ,
505+ "—— [not started] ——" ,
506+ ] ;
507+ assert_eq ! ( lines, expected) ;
508+ }
509+
510+ #[ test]
511+ fn exec_auto ( ) {
512+ let input = "
513+ ```bash +auto_exec
514+ echo hi
515+ ```" ;
516+ let lines = Test :: new ( input)
517+ . render ( )
518+ . rows ( 6 )
519+ . columns ( 19 )
520+ . run_async_renders ( RunAsyncRendersPolicy :: OnlyAutomatic )
521+ . into_lines ( ) ;
522+ let expected = & [
523+ //
524+ " " ,
525+ "echo hi " ,
526+ " " ,
527+ "——— [finished] ————" ,
528+ " " ,
529+ "hi " ,
530+ ] ;
469531 assert_eq ! ( lines, expected) ;
470532 }
471533
@@ -475,7 +537,8 @@ echo hi
475537```bash +validate
476538echo hi
477539```" ;
478- let lines = Test :: new ( input) . render ( ) . rows ( 4 ) . columns ( 19 ) . run_async_renders ( false ) . into_lines ( ) ;
540+ let lines =
541+ Test :: new ( input) . render ( ) . rows ( 4 ) . columns ( 19 ) . run_async_renders ( RunAsyncRendersPolicy :: None ) . into_lines ( ) ;
479542 let expected = & [ " " , "echo hi " , " " , " " ] ;
480543 assert_eq ! ( lines, expected) ;
481544 }
@@ -649,9 +712,16 @@ echo hi
649712echo hi
650713```
651714<!-- snippet_output: foo -->" ;
652- let lines = Test :: new ( input) . render ( ) . rows ( 4 ) . columns ( 19 ) . run_async_renders ( false ) . into_lines ( ) ;
715+ let lines =
716+ Test :: new ( input) . render ( ) . rows ( 4 ) . columns ( 19 ) . run_async_renders ( RunAsyncRendersPolicy :: None ) . into_lines ( ) ;
653717 // this should look exactly the same as if we hadn't detached the output
654- let expected = & [ " " , "echo hi " , " " , "—— [not started] ——" ] ;
718+ let expected = & [
719+ //
720+ " " ,
721+ "echo hi " ,
722+ " " ,
723+ "—— [not started] ——" ,
724+ ] ;
655725 assert_eq ! ( lines, expected) ;
656726 }
657727
0 commit comments