1 2#' A simple CLI theme 3#' 4#' To use this theme, you can set it as the `cli.theme` option. 5#' Note that this is in addition to the builtin theme, which is still in 6#' effect. 7#' 8#' ```r 9#' options(cli.theme = cli::simple_theme()) 10#' ``` 11#' 12#' and then CLI apps started after this will use it as the default theme. 13#' You can also use it temporarily, in a div element: 14#' 15#' ```r 16#' cli_div(theme = cli::simple_theme()) 17#' ``` 18#' 19#' # Showcase 20#' 21#' ```{asciicast simple-theme} 22#' show <- cli_div(theme = cli::simple_theme()) 23#' 24#' cli_h1("Heading 1") 25#' cli_h2("Heading 2") 26#' cli_h3("Heading 3") 27#' 28#' cli_par() 29#' cli_alert_danger("Danger alert") 30#' cli_alert_warning("Warning alert") 31#' cli_alert_info("Info alert") 32#' cli_alert_success("Success alert") 33#' cli_alert("Alert for starting a process or computation", 34#' class = "alert-start") 35#' cli_end() 36#' 37#' cli_text("Packages and versions: {.pkg cli} {.version 1.0.0}.") 38#' cli_text("Time intervals: {.timestamp 3.4s}") 39#' 40#' cli_text("{.emph Emphasis} and {.strong strong emphasis}") 41#' 42#' cli_text("This is a piece of code: {.code sum(x) / length(x)}") 43#' cli_text("Function names: {.fn cli::simple_theme}") 44#' 45#' cli_text("Files: {.file /usr/bin/env}") 46#' cli_text("URLs: {.url https://r-project.org}") 47#' 48#' cli_h2("Longer code chunk") 49#' cli_par(class = "code R") 50#' cli_verbatim( 51#' '# window functions are useful for grouped mutates', 52#' 'mtcars %>%', 53#' ' group_by(cyl) %>%', 54#' ' mutate(rank = min_rank(desc(mpg)))') 55#' 56#' cli_end(show) 57#' ``` 58#' 59#' @param dark Whether the theme should be optimized for a dark 60#' background. If `"auto"`, then cli will try to detect this. 61#' Detection usually works in recent RStudio versions, and in iTerm 62#' on macOS, but not on other platforms. 63#' 64#' @seealso [themes], [builtin_theme()]. 65#' @export 66 67simple_theme <- function(dark = getOption("cli_theme_dark", "auto")) { 68 69 dark <- detect_dark_theme(dark) 70 71 list( 72 h1 = list( 73 "margin-top" = 1, 74 "margin-bottom" = 0, 75 color = "cyan", 76 fmt = function(x) cli::rule(x, line_col = "cyan")), 77 78 h2 = list( 79 "margin-top" = 1, 80 "margin-bottom" = 0, 81 color = "cyan", 82 fmt = function(x) paste0(symbol$line, " ", x, " ", symbol$line, symbol$line)), 83 84 h3 = list( 85 "margin-top" = 1, 86 "margin-bottom" = 0, 87 color = "cyan"), 88 89 par = list("margin-top" = 0, "margin-bottom" = 1), 90 91 ".alert-danger" = list( 92 "background-color" = "red", 93 color = "white", 94 before = function() paste0(symbol$cross, " ") 95 ), 96 97 ".alert-warning" = list( 98 color = "orange", 99 "font-weight" = "bold", 100 before = paste0("!", " ") 101 ), 102 103 ".alert-success" = list( 104 before = function() paste0(col_green(symbol$tick), " ") 105 ), 106 ".alert-info" = list( 107 before = function() paste0(col_cyan(symbol$info), " ") 108 ), 109 110 ".alert-start" = list( 111 before = function() paste0(symbol$arrow_right, " ")), 112 113 span.pkg = list( 114 color = "blue", 115 "font-weight" = "bold"), 116 span.version = list(color = "blue"), 117 118 span.emph = simple_theme_emph(), 119 span.strong = list("font-weight" = "bold", "font-style" = "italic"), 120 121 span.fun = utils::modifyList(simple_theme_code(dark), list(after = "()")), 122 span.fn = utils::modifyList(simple_theme_code(dark), list(after = "()")), 123 span.arg = simple_theme_code(dark), 124 span.kbd = utils::modifyList(simple_theme_code(dark), 125 list(before = "<", after = ">")), 126 span.key = utils::modifyList(simple_theme_code(dark), 127 list(before = "<", after = ">")), 128 span.file = simple_theme_file(), 129 span.path = simple_theme_file(), 130 span.email = simple_theme_url(), 131 span.url = utils::modifyList(simple_theme_url(), 132 list(before = "<", after = ">")), 133 span.var = simple_theme_code(dark), 134 span.envvar = simple_theme_code(dark), 135 136 span.timestamp = list(before = "[", after = "]", color = "grey") 137 ) 138} 139 140simple_theme_emph <- function() { 141 list("font-style" = "italic") 142} 143 144simple_theme_url <- function() { 145 list(color = "blue") 146} 147 148simple_theme_code <- function(dark) { 149 if (dark) { 150 list("background-color" = "#232323", color = "#f0f0f0") 151 } else{ 152 list("background-color" = "#f8f8f8", color = "#202020") 153 } 154} 155 156simple_theme_file <- function() { 157 list(color = "blue") 158} 159 160simple_theme_r_code <- function(dark) { 161 dark <- dark 162 style <- if (dark) { 163 make_ansi_style("#f0f0f0") 164 } else { 165 make_ansi_style("#202020") 166 } 167 function(x) { 168 x <- ansi_strip(x) 169 lines <- strsplit(x, "\n", fixed = TRUE)[[1]] 170 fmd <- code_highlight(lines) 171 style(fmd) 172 } 173} 174 175is_iterm <- function() { 176 isatty(stdout()) && Sys.getenv("TERM_PROGRAM", "") == "iTerm.app" 177} 178 179is_iterm_dark <- function() { 180 if (is.null(clienv[["is_iterm_dark"]])) { 181 clienv$is_iterm_dark <- 182 tryCatch( 183 error = function(x) FALSE, { 184 osa <- ' 185 tell application "iTerm2" 186 tell current session of current window 187 get background color 188 end tell 189 end tell 190 ' 191 out <- system2("osascript", c("-e", shQuote(osa)), stdout = TRUE) 192 nums <- scan(text = gsub(",", "", out), quiet = TRUE) 193 mean(nums) < 20000 194 }) 195 } 196 clienv[["is_iterm_dark"]] 197} 198