Skip to content

Commit d314a19

Browse files
authored
Merge pull request #12132 from MichaelHatherly/mh/stdout-colour-html
Support colour output in stdout for `jupyter` and `julia` engines
2 parents 7f8cfd0 + 7ba0fd4 commit d314a19

File tree

3 files changed

+43
-14
lines changed

3 files changed

+43
-14
lines changed

news/changelog-1.7.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,3 +94,4 @@ All changes included in 1.7:
9494
- ([#10532](https://github.com/quarto-dev/quarto-cli/issues/10532)): Quarto changed default of `--headless=old` to `--headless` as [Chrome 132 has removed old headless mode](https://developer.chrome.com/blog/removing-headless-old-from-chrome) and only support new mode. For using old mode, `QUARTO_CHROMIUM` could be set to a [new `chrome-headless-shell` binary](https://developer.chrome.com/blog/chrome-headless-shell) or too an older chrome version (between 128 and 132) and `QUARTO_CHROMIUM_HEADLESS_MODE` set to `old` for using old headless mode with that compatabitle version.
9595
- ([#10961](https://github.com/quarto-dev/quarto-cli/issues/10961)): Add more information on which Chrome Headless will be used in `quarto check install`. This is helpful to help debug mermaid issues.
9696
- ([#11951](https://github.com/quarto-dev/quarto-cli/issues/11951)): Raw LaTeX table without `tbl-` prefix label for using Quarto crossref are now correctly passed through unmodified.
97+
- ([#12117](https://github.com/quarto-dev/quarto-cli/issues/12117)): Color output to stdout and stderr is now correctly rendered for `html` format in the Jupyter and Julia engines.

src/core/jupyter/jupyter.ts

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1629,7 +1629,7 @@ async function mdFromCodeCell(
16291629
}
16301630
md.push(text.join(""));
16311631
} else {
1632-
md.push(mdOutputStream(stream));
1632+
md.push(await mdOutputStream(stream, options));
16331633
}
16341634
} else if (output.output_type === "error") {
16351635
md.push(await mdOutputError(output as JupyterOutputError, options));
@@ -1766,7 +1766,7 @@ function isMarkdown(output: JupyterOutput, options: JupyterToMarkdownOptions) {
17661766
return isDisplayDataType(output, options, displayDataIsMarkdown);
17671767
}
17681768

1769-
function mdOutputStream(output: JupyterOutputStream) {
1769+
async function mdOutputStream(output: JupyterOutputStream, options: JupyterToMarkdownOptions) {
17701770
let text: string[] = [];
17711771
if (typeof output.text === "string") {
17721772
text = [output.text];
@@ -1781,14 +1781,23 @@ function mdOutputStream(output: JupyterOutputStream) {
17811781
/<ipython-input.*?>:\d+:\s+/,
17821782
"",
17831783
);
1784-
return mdCodeOutput(
1785-
[firstLine, ...text.slice(1)].map(colors.stripColor),
1786-
);
1784+
text = [firstLine, ...text.slice(1)];
17871785
}
17881786
}
17891787

1790-
// normal default handling
1791-
return mdCodeOutput(text.map(colors.stripColor));
1788+
if (options.toHtml && text.some(hasAnsiEscapeCodes)) {
1789+
const linesHTML = await convertToHtmlSpans(text.join("\n"));
1790+
return mdMarkdownOutput(
1791+
[
1792+
"\n::: {.ansi-escaped-output}\n```{=html}\n<pre>",
1793+
linesHTML,
1794+
"</pre>\n```\n:::\n",
1795+
],
1796+
);
1797+
} else {
1798+
// normal default behavior
1799+
return mdCodeOutput(text.map(colors.stripColor));
1800+
}
17921801
}
17931802

17941803
async function mdOutputError(
@@ -1864,8 +1873,8 @@ async function mdOutputDisplayData(
18641873
// if output is invalid, warn and emit empty
18651874
const data = output.data[mimeType] as unknown;
18661875
if (!Array.isArray(data) || data.some((s) => typeof s !== "string")) {
1867-
return mdWarningOutput(`Unable to process text plain output data
1868-
which does not appear to be plain text: ${JSON.stringify(data)}`);
1876+
return await mdWarningOutput(`Unable to process text plain output data
1877+
which does not appear to be plain text: ${JSON.stringify(data)}`, options);
18691878
}
18701879
const lines = data as string[];
18711880
// pandas inexplicably outputs html tables as text/plain with an enclosing single-quote
@@ -1900,9 +1909,10 @@ which does not appear to be plain text: ${JSON.stringify(data)}`);
19001909
}
19011910

19021911
// no type match found
1903-
return mdWarningOutput(
1912+
return await mdWarningOutput(
19041913
"Unable to display output for mime type(s): " +
1905-
Object.keys(output.data).join(", "),
1914+
Object.keys(output.data).join(", "),
1915+
options,
19061916
);
19071917
}
19081918

@@ -2061,12 +2071,12 @@ function mdEnclosedOutput(begin: string, text: string[], end: string) {
20612071
return md.join("");
20622072
}
20632073

2064-
function mdWarningOutput(msg: string) {
2065-
return mdOutputStream({
2074+
async function mdWarningOutput(msg: string, options: JupyterToMarkdownOptions) {
2075+
return await mdOutputStream({
20662076
output_type: "stream",
20672077
name: "stderr",
20682078
text: [msg],
2069-
});
2079+
}, options);
20702080
}
20712081

20722082
function isWarningOutput(output: JupyterOutput) {
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
---
2+
engine: julia
3+
format: html
4+
_quarto:
5+
tests:
6+
html:
7+
ensureHtmlElements:
8+
- ["div.cell-output-stdout div.ansi-escaped-output pre span.ansi-red-fg.ansi-bold"]
9+
- ["div.cell-output-stdout div.ansi-escaped-output pre span.ansi-red-cyan-bold"]
10+
---
11+
12+
```{julia}
13+
printstyled("red"; color = :red, bold = true)
14+
```
15+
16+
```{julia}
17+
@info "logging"
18+
```

0 commit comments

Comments
 (0)