@@ -144,6 +144,7 @@ import { lines } from "../text.ts";
144144import { readYamlFromMarkdown } from "../yaml.ts" ;
145145import { languagesInMarkdown } from "../../execute/engine-shared.ts" ;
146146import { pathWithForwardSlashes } from "../path.ts" ;
147+ import { convertToHtmlSpans , hasAnsiEscapeCodes } from "../ansi-colors.ts" ;
147148
148149export const kJupyterNotebookExtensions = [
149150 ".ipynb" ,
@@ -581,10 +582,10 @@ export function jupyterAssets(input: string, to?: string) {
581582 } ;
582583}
583584
584- export function jupyterToMarkdown (
585+ export async function jupyterToMarkdown (
585586 nb : JupyterNotebook ,
586587 options : JupyterToMarkdownOptions ,
587- ) : JupyterToMarkdownResult {
588+ ) : Promise < JupyterToMarkdownResult > {
588589 // optional content injection / html preservation for html output
589590 // that isn't an ipynb
590591 const isHtml = options . toHtml && ! options . toIpynb ;
@@ -638,7 +639,7 @@ export function jupyterToMarkdown(
638639 md . push ( ...mdFromRawCell ( cell ) ) ;
639640 break ;
640641 case "code" :
641- md . push ( ...mdFromCodeCell ( cell , ++ codeCellIndex , options ) ) ;
642+ md . push ( ...( await mdFromCodeCell ( cell , ++ codeCellIndex , options ) ) ) ;
642643 break ;
643644 default :
644645 throw new Error ( "Unexpected cell type " + cell . cell_type ) ;
@@ -881,7 +882,7 @@ const kLangCommentChars: Record<string, string | string[]> = {
881882 dot : "//" ,
882883} ;
883884
884- function mdFromCodeCell (
885+ async function mdFromCodeCell (
885886 cell : JupyterCellWithOptions ,
886887 cellIndex : number ,
887888 options : JupyterToMarkdownOptions ,
@@ -1200,14 +1201,16 @@ function mdFromCodeCell(
12001201 const caption = isCaptionableData ( output )
12011202 ? ( outputCaptions . shift ( ) || null )
12021203 : null ;
1203- md . push ( mdOutputDisplayData (
1204- outputLabel ,
1205- caption ,
1206- outputName + "-" + ( index + 1 ) ,
1207- output as JupyterOutputDisplayData ,
1208- options ,
1209- figureOptions ,
1210- ) ) ;
1204+ md . push (
1205+ await mdOutputDisplayData (
1206+ outputLabel ,
1207+ caption ,
1208+ outputName + "-" + ( index + 1 ) ,
1209+ output as JupyterOutputDisplayData ,
1210+ options ,
1211+ figureOptions ,
1212+ ) ,
1213+ ) ;
12111214 // if this isn't an image and we have a caption, place it at the bottom of the div
12121215 if ( caption && ! isImage ( output , options ) ) {
12131216 md . push ( `\n${ caption } \n` ) ;
@@ -1322,7 +1325,7 @@ function mdOutputError(output: JupyterOutputError) {
13221325 return mdCodeOutput ( [ output . ename + ": " + output . evalue ] ) ;
13231326}
13241327
1325- function mdOutputDisplayData (
1328+ async function mdOutputDisplayData (
13261329 label : string | null ,
13271330 caption : string | null ,
13281331 filename : string ,
@@ -1367,7 +1370,24 @@ function mdOutputDisplayData(
13671370 lines [ 0 ] = lines [ 0 ] . slice ( 1 , - 1 ) ;
13681371 return mdMarkdownOutput ( lines ) ;
13691372 } else {
1370- return mdCodeOutput ( lines . map ( colors . stripColor ) ) ;
1373+ if ( options . toHtml ) {
1374+ if ( lines . some ( hasAnsiEscapeCodes ) ) {
1375+ const html = ( await Promise . all (
1376+ lines . map ( convertToHtmlSpans ) ,
1377+ ) ) ;
1378+ return mdMarkdownOutput (
1379+ [
1380+ "\n::: {.ansi-escaped-output}\n```{=html}\n<pre>" ,
1381+ ...html ,
1382+ "</pre>\n```\n:::\n" ,
1383+ ] ,
1384+ ) ;
1385+ } else {
1386+ return mdCodeOutput ( lines ) ;
1387+ }
1388+ } else {
1389+ return mdCodeOutput ( lines . map ( colors . stripColor ) ) ;
1390+ }
13711391 }
13721392 }
13731393 }
0 commit comments