Skip to content

Native support for R cli package ANSI-styled output in knitr engine #13815

@coatless

Description

@coatless

Summary

R code using the cli package produces unstyled, plain text output in Quarto HTML documents. The ANSI escape sequences are stripped, losing all formatting (colors, bold, emphasis). While Quarto 1.7+ added ANSI support for Jupyter/Julia, R/knitr documents still lack native handling.

Background

The cli package is widely used in the R ecosystem (tidyverse, devtools, usethis, etc.). Many custom print methods leverage cli for informative output. Without native support, Quarto users see degraded output quality compared to RStudio console or terminal rendering.

Minimal Reproducible Example

Save as cli-demo.qmd and render with quarto render cli-demo.qmd:

---
title: "CLI Output Demo"
format: html
---

```{r}
#| echo: false
library(cli)

demo_behavior <- function() {
  cli_h1("Status Report")
  cli_alert_success("All tests passed")
  cli_alert_warning("Memory usage high")
  cli_alert_danger("Connection failed")
}

demo_behavior()
```

Output Comparison

Console Output (Expected) Quarto Rendered Output (Actual)
Terminal Output with R's `cli` package Image

Desired Output

Mirror RStudio with a light grey background for CLI output:

Print method created using the `cli` R package being displayed in Quarto with colors using a light grey shade to match RStudio's print background

Or, just the regular CLI output:

Print method created using the `cli` R package being displayed in Quarto with colors but no background grey shade

Expected vs Actual Behavior

Aspect Expected Actual
Colors Styled with appropriate colors (green ✔, yellow ⚠, red ✖) Plain monochrome text
Formatting Bold headers, styled alerts No text styling
Icons Unicode symbols rendered with color context Symbols appear but lack styling
Background Terminal-style grey background White/default background

Current Workaround

Users must manually configure custom knitr hooks using fansi in every document:

```{r}
#| include: false
options(crayon.enabled = TRUE, cli.num_colors = 256)

ansi_aware_handler <- function(x, options) {
  paste0(
    '<pre class="r-output"><code>',
    fansi::sgr_to_html(x = htmltools::htmlEscape(x), warn = FALSE, term.cap = "256"),
    '</code></pre>'
  )
}

knitr::knit_hooks$set(
  output = ansi_aware_handler,
  message = ansi_aware_handler,
  warning = ansi_aware_handler,
  error = ansi_aware_handler
)
```

This is non-obvious, requires additional dependencies (fansi, htmltools), and must be repeated in every document.

Note

The workaround produces separate <pre> blocks for each cli statement, which may result in extra vertical spacing. This is normal knitr behavior (one output block per cat()/message() call). If desired, CSS can be used to collapse consecutive output blocks:

```{=html}
<style>
pre.r-output {
  margin: 0;
  padding: 0;
}
pre.r-output + pre.r-output {
  border-top: none;
}
</style>
```

Proposed Solution

Add native ANSI processing for R/knitr output, similar to the fix in PR #7813. Also consider adding a feature flag or three for the new behavior:

  1. Add a chunk option like ansi: true to enable ANSI-to-HTML conversion
  2. Document-level YAML option such as execute: ansi-colors: true
  3. Terminal-style background for ANSI output blocks (grey background to visually distinguish from regular output)

Related Issues

Issue Title Status
#5746 knitr: process ANSI color codes Open
#3730 Support ANSI colour output with downlit Open
#4204 ASCII escape codes should be stripped or processed to HTML Closed (Jupyter only)
Discussion #3957 {cli} output not captured by quarto slides Active

Environment

  • Quarto version: 1.8.26
  • R version: 4.5.2
  • cli package version: 3.6.5
  • OS: macOS 26.2

Metadata

Metadata

Assignees

Labels

engines-knitrAnything regarding knitr enginesenhancementNew feature or request

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions