'How do I get capture.output functionality while capturing ANSI color codes from crayon?

What ways are there to capture output à la capture.output but which will retain the ANSI color encoding which comes out of crayon?

> crayon::green("green")
[1] "\033[32mgreen\033[39m"
> capture.output(crayon::green("green"))
[1] "[1] \"green\""

Edit: Another example

> green <- function() {
+   print(crayon::green("green"))
+   cat(crayon::green("green"))
+   
+   invisible()
+ }
> green()
[1] "\033[32mgreen\033[39m"
green
> capture.output(green())
[1] "[1] \"green\"" "green"        
> 
r


Solution 1:[1]

Ultimately, I believe the issue arises with the crayon::has_color() function which is called when any of the crayon functions are run. This function calls https://github.com/r-lib/crayon/blob/4a44bb262615ab5c4e30cb80437d9f2e24ccb006/R/aab-num-ansi-colors.R#L36-L267

Looking at what the function does: when called within capture.output crayon:::num_ansi_colors() will typically return 1L because it detects the presence of the sink. This can be worked around by setting options(crayon.enabled = TRUE).

green <- function() {
  print(crayon::green("green"))
  cat(crayon::green("green"))
  invisible()
}
capture.output(green())
#> [1] "[1] \"green\"" "green"
withr::with_options(list(crayon.enabled = TRUE), capture.output(green()))
#> [1] "[1] \"\\033[32mgreen\\033[39m\"" "\033[32mgreen\033[39m"

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Tyler Smith