r-lib / cli
1

2
#' CLI text
3
#'
4
#' It is wrapped to the screen width automatically. It may contain inline
5
#' markup. (See [inline-markup].)
6
#'
7
#' @param ... The text to show, in character vectors. They will be
8
#'   concatenated into a single string. Newlines are _not_ preserved.
9
#' @param .envir Environment to evaluate the glue expressions in.
10
#'
11
#' @export
12
#' @examples
13
#' cli_text("Hello world!")
14
#' cli_text(packageDescription("cli")$Description)
15
#'
16
#' ## Arguments are concatenated
17
#' cli_text("this", "that")
18
#'
19
#' ## Command substitution
20
#' greeting <- "Hello"
21
#' subject <- "world"
22
#' cli_text("{greeting} {subject}!")
23
#'
24
#' ## Inline theming
25
#' cli_text("The {.fn cli_text} function in the {.pkg cli} package")
26
#'
27
#' ## Use within container elements
28
#' ul <- cli_ul()
29
#' cli_li()
30
#' cli_text("{.emph First} item")
31
#' cli_li()
32
#' cli_text("{.emph Second} item")
33
#' cli_end(ul)
34

35
cli_text <- function(..., .envir = parent.frame()) {
36 1
  cli__message("text", list(text = glue_cmd(..., .envir = .envir)))
37
}
38

39
#' CLI verbatim text
40
#'
41
#' It is not wrapped, but printed as is.
42
#'
43
#' @param ... The text to show, in character vectors. Each element is
44
#'   printed on a new line.
45
#' @param .envir Environment to evaluate the glue expressions in.
46
#'
47
#' @export
48
#' @examples
49
#' cli_verbatim("This has\nthree", "lines")
50

51
cli_verbatim <- function(..., .envir = parent.frame()) {
52 1
  cli__message("verbatim", c(list(...), list(.envir = .envir)))
53
}
54

55
#' CLI headings
56
#'
57
#' @param text Text of the heading. It can contain inline markup.
58
#' @param id Id of the heading element, string. It can be used in themes.
59
#' @param class Class of the heading element, string. It can be used in
60
#'   themes.
61
#' @param .envir Environment to evaluate the glue expressions in.
62
#'
63
#' @export
64
#' @examples
65
#' cli_h1("Main title")
66
#' cli_h2("Subtitle")
67
#' cli_text("And some regular text....")
68

69
cli_h1 <- function(text, id = NULL, class = NULL, .envir = parent.frame()) {
70 1
  cli__message("h1", list(text = glue_cmd(text, .envir = .envir), id = id,
71 1
                          class = class))
72
}
73

74
#' @rdname cli_h1
75
#' @export
76

77
cli_h2 <- function(text, id = NULL, class = NULL, .envir = parent.frame()) {
78 1
  cli__message("h2", list(text = glue_cmd(text, .envir = .envir), id = id,
79 1
                          class = class))
80
}
81

82
#' @rdname cli_h1
83
#' @export
84

85
cli_h3 <- function(text, id = NULL, class = NULL, .envir = parent.frame()) {
86 1
  cli__message("h3", list(text = glue_cmd(text, .envir = .envir), id = id,
87 1
                          class = class))
88
}
89

90
#' Generic CLI container
91
#'
92
#' See [containers]. A `cli_div` container is special, because it may
93
#' add new themes, that are valid within the container.
94
#'
95
#' @param id Element id, a string. If `NULL`, then a new id is generated
96
#'   and returned.
97
#' @param class Class name, sting. Can be used in themes.
98
#' @param theme A custom theme for the container. See [themes].
99
#' @param .auto_close Whether to close the container, when the calling
100
#'   function finishes (or `.envir` is removed, if specified).
101
#' @param .envir Environment to evaluate the glue expressions in. It is
102
#'   also used to auto-close the container if `.auto_close` is `TRUE`.
103
#' @return The id of the new container element, invisibly.
104
#'
105
#' @export
106
#' @examples
107
#' ## div with custom theme
108
#' d <- cli_div(theme = list(h1 = list(color = "blue",
109
#'                                     "font-weight" = "bold")))
110
#' cli_h1("Custom title")
111
#' cli_end(d)
112
#'
113
#' ## Close automatically
114
#' div <- function() {
115
#'   cli_div(class = "tmp", theme = list(.tmp = list(color = "yellow")))
116
#'   cli_text("This is yellow")
117
#' }
118
#' div()
119
#' cli_text("This is not yellow any more")
120

121
cli_div <- function(id = NULL, class = NULL, theme = NULL,
122
                    .auto_close = TRUE, .envir = parent.frame()) {
123 1
  cli__message("div", list(id = id, class = class, theme = theme),
124 1
               .auto_close = .auto_close, .envir = .envir)
125
}
126

127
#' CLI paragraph
128
#'
129
#' See [containers].
130
#'
131
#' @param id Element id, a string. If `NULL`, then a new id is generated
132
#'   and returned.
133
#' @param class Class name, sting. Can be used in themes.
134
#' @inheritParams cli_div
135
#' @return The id of the new container element, invisibly.
136
#'
137
#' @export
138
#' @examples
139
#' id <- cli_par()
140
#' cli_text("First paragraph")
141
#' cli_end(id)
142
#' id <- cli_par()
143
#' cli_text("Second paragraph")
144
#' cli_end(id)
145

146
cli_par <- function(id = NULL, class = NULL, .auto_close = TRUE,
147
                    .envir = parent.frame()) {
148 1
  cli__message("par", list(id = id, class = class),
149 1
               .auto_close = .auto_close, .envir = .envir)
150
}
151

152
#' Close a CLI container
153
#'
154
#' @param id Id of the container to close. If missing, the current
155
#' container is closed, if any.
156
#'
157
#' @export
158
#' @examples
159
#' ## If id is omitted
160
#' cli_par()
161
#' cli_text("First paragraph")
162
#' cli_end()
163
#' cli_par()
164
#' cli_text("Second paragraph")
165
#' cli_end()
166

167
cli_end <- function(id = NULL) {
168 1
  cli__message("end", list(id = id %||% NA_character_))
169
}
170

171
#' Unordered CLI list
172
#'
173
#' An unordered list is a container, see [containers].
174
#'
175
#' @param items If not `NULL`, then a character vector. Each element of
176
#'   the vector will be one list item, and the list container will be
177
#'   closed by default (see the `.close` argument).
178
#' @param id Id of the list container. Can be used for closing it with
179
#'   [cli_end()] or in themes. If `NULL`, then an id is generated and
180
#'   retuned invisibly.
181
#' @param class Class of the list container. Can be used in themes.
182
#' @param .close Whether to close the list container if the `items` were
183
#'   specified. If `FALSE` then new items can be added to the list.
184
#' @inheritParams cli_div
185
#' @return The id of the new container element, invisibly.
186
#'
187
#' @export
188
#' @examples
189
#' ## Specifying the items at the beginning
190
#' cli_ul(c("one", "two", "three"))
191
#'
192
#' ## Adding items one by one
193
#' cli_ul()
194
#' cli_li("one")
195
#' cli_li("two")
196
#' cli_li("three")
197
#' cli_end()
198
#'
199
#' ## Complex item, added gradually.
200
#' cli_ul()
201
#' cli_li()
202
#' cli_verbatim("Beginning of the {.emph first} item")
203
#' cli_text("Still the first item")
204
#' cli_end()
205
#' cli_li("Second item")
206
#' cli_end()
207

208
cli_ul <- function(items = NULL, id = NULL, class = NULL,
209
                   .close = TRUE, .auto_close = TRUE,
210
                   .envir = parent.frame()) {
211 1
  cli__message(
212 1
    "ul",
213 1
    list(
214 1
      items = lapply(items, glue_cmd, .envir = .envir), id = id,
215 1
      class = class, .close = .close),
216 1
    .auto_close = .auto_close, .envir = .envir)
217
}
218

219
#' Ordered CLI list
220
#'
221
#' An ordered list is a container, see [containers].
222
#'
223
#' @inheritParams cli_ul
224
#' @return The id of the new container element, invisibly.
225
#'
226
#' @export
227
#' @examples
228
#' ## Specifying the items at the beginning
229
#' cli_ol(c("one", "two", "three"))
230
#'
231
#' ## Adding items one by one
232
#' cli_ol()
233
#' cli_li("one")
234
#' cli_li("two")
235
#' cli_li("three")
236
#' cli_end()
237
#'
238
#' ## Nested lists
239
#' cli_div(theme = list(ol = list("margin-left" = 2)))
240
#' cli_ul()
241
#' cli_li("one")
242
#' cli_ol(c("foo", "bar", "foobar"))
243
#' cli_li("two")
244
#' cli_end()
245
#' cli_end()
246

247
cli_ol <- function(items = NULL, id = NULL, class = NULL,
248
                   .close = TRUE, .auto_close = TRUE,
249
                   .envir = parent.frame()) {
250 1
  cli__message(
251 1
    "ol",
252 1
    list(
253 1
      items = lapply(items, glue_cmd, .envir = .envir), id = id,
254 1
      class = class, .close = .close),
255 1
    .auto_close = .auto_close, .envir = .envir)
256
}
257

258
#' Definition list
259
#'
260
#' A definition list is a container, see [containers].
261
#'
262
#' @param items Named character vector, or `NULL`. If not `NULL`, they
263
#'   are used as list items.
264
#' @inheritParams cli_ul
265
#' @return The id of the new container element, invisibly.
266
#'
267
#' @export
268
#' @examples
269
#' ## Specifying the items at the beginning
270
#' cli_dl(c(foo = "one", bar = "two", baz = "three"))
271
#'
272
#' ## Adding items one by one
273
#' cli_dl()
274
#' cli_li(c(foo = "one"))
275
#' cli_li(c(bar = "two"))
276
#' cli_li(c(baz = "three"))
277
#' cli_end()
278

279
cli_dl <- function(items = NULL, id = NULL, class = NULL,
280
                   .close = TRUE, .auto_close = TRUE,
281
                   .envir = parent.frame()) {
282 1
  cli__message(
283 1
    "dl",
284 1
    list(
285 1
      items = lapply(items, glue_cmd, .envir = .envir), id = id,
286 1
      class = class, .close = .close),
287 1
    .auto_close = .auto_close, .envir = .envir)
288
}
289

290
#' CLI list item(s)
291
#'
292
#' A list item is a container, see [containers].
293
#'
294
#' @param items Character vector of items, or `NULL`.
295
#' @param id Id of the new container. Can be used for closing it with
296
#'   [cli_end()] or in themes. If `NULL`, then an id is generated and
297
#'   retuned invisibly.
298
#' @param class Class of the item container. Can be used in themes.
299
#' @inheritParams cli_div
300
#' @return The id of the new container element, invisibly.
301
#'
302
#' @export
303
#' @examples
304
#' ## Adding items one by one
305
#' cli_ul()
306
#' cli_li("one")
307
#' cli_li("two")
308
#' cli_li("three")
309
#' cli_end()
310
#'
311
#' ## Complex item, added gradually.
312
#' cli_ul()
313
#' cli_li()
314
#' cli_verbatim("Beginning of the {.emph first} item")
315
#' cli_text("Still the first item")
316
#' cli_end()
317
#' cli_li("Second item")
318
#' cli_end()
319

320
cli_li <- function(items = NULL, id = NULL, class = NULL,
321
                   .auto_close = TRUE, .envir = parent.frame()) {
322 1
  cli__message(
323 1
    "li",
324 1
    list(
325 1
      items = lapply(items, glue_cmd, .envir = .envir), id = id,
326 1
      class = class),
327 1
    .auto_close = .auto_close, .envir = .envir)
328
}
329

330
#' CLI alerts
331
#'
332
#' Alerts are typically short status messages.
333
#'
334
#' @param text Text of the alert.
335
#' @param id Id of the alert element. Can be used in themes.
336
#' @param class Class of the alert element. Can be used in themes.
337
#' @param wrap Whether to auto-wrap the text of the alert.
338
#' @param .envir Environment to evaluate the glue expressions in.
339
#'
340
#' @export
341
#' @examples
342
#'
343
#' cli_alert("Cannot lock package library.")
344
#' cli_alert_success("Package {.pkg cli} installed successfully.")
345
#' cli_alert_danger("Could not download {.pkg cli}.")
346
#' cli_alert_warning("Internet seems to be unreacheable.")
347
#' cli_alert_info("Downloaded 1.45MiB of data")
348

349
cli_alert <- function(text, id = NULL, class = NULL, wrap = FALSE,
350
                       .envir = parent.frame()) {
351 1
  cli__message("alert", list(text = glue_cmd(text, .envir = .envir), id = id,
352 1
                             class = class, wrap = wrap))
353
}
354

355
#' @rdname cli_alert
356
#' @export
357

358
cli_alert_success <- function(text, id = NULL, class = NULL, wrap = FALSE,
359
                              .envir = parent.frame()) {
360 1
  cli__message("alert_success", list(text = glue_cmd(text, .envir = .envir),
361 1
                                     id = id, class = class, wrap = wrap))
362
}
363

364
#' @rdname cli_alert
365
#' @export
366

367
cli_alert_danger <- function(text, id = NULL, class = NULL, wrap = FALSE,
368
                              .envir = parent.frame()) {
369 1
  cli__message("alert_danger", list(text = glue_cmd(text, .envir = .envir),
370 1
                                    id = id, class = class, wrap = wrap))
371
}
372

373
#' @rdname cli_alert
374
#' @export
375

376
cli_alert_warning <- function(text, id = NULL, class = NULL, wrap = FALSE,
377
                               .envir = parent.frame()) {
378 1
  cli__message("alert_warning", list(text = glue_cmd(text, .envir = .envir),
379 1
                                     id = id, class = class, wrap = wrap))
380
}
381

382
#' @rdname cli_alert
383
#' @export
384

385
cli_alert_info <- function(text, id = NULL, class = NULL, wrap = FALSE,
386
                            .envir = parent.frame()) {
387 1
  cli__message("alert_info", list(text = glue_cmd(text, .envir = .envir),
388 1
                                  id = id, class = class, wrap = wrap))
389
}
390

391
#' CLI horizontal rule
392
#'
393
#' It can be used to separate parts of the output. The line style of the
394
#' rule can be changed via the the `line-type` property. Possible values
395
#' are:
396
#'
397
#' * `"single"`: (same as `1`), a single line,
398
#' * `"double"`: (same as `2`), a double line,
399
#' * `"bar1"`, `"bar2"`, `"bar3"`, etc., `"bar8"` uses varying height bars.
400
#'
401
#' Colors and background colors can similarly changed via a theme, see
402
#' examples below.
403
#'
404
#' @param .envir Environment to evaluate the glue expressions in.
405
#' @inheritParams rule
406
#' @inheritParams cli_div
407
#'
408
#' @export
409
#' @examples
410
#' cli_rule()
411
#' cli_text(packageDescription("cli")$Description)
412
#' cli_rule()
413
#'
414
#' # Theming
415
#' d <- cli_div(theme = list(rule = list(
416
#'   color = "blue",
417
#'   "background-color" = "darkgrey",
418
#'   "line-type" = "double")))
419
#' cli_rule("Left", right = "Right")
420
#' cli_end(d)
421
#'
422
#' # Interpolation
423
#' cli_rule(left = "One plus one is {1+1}")
424
#' cli_rule(left = "Package {.pkg mypackage}")
425

426
cli_rule <- function(left = "", center = "", right = "", id = NULL,
427
                     .envir = parent.frame()) {
428 0
  cli__message("rule", list(left = glue_cmd(left, .envir = .envir),
429 0
                            center = glue_cmd(center, .envir = .envir),
430 0
                            right = glue_cmd(right, .envir = .envir),
431 0
                            id = id))
432
}
433

434
#' CLI block quote
435
#'
436
#' A section that is quoted from another source. It is typically indented.
437
#'
438
#' @export
439
#' @param quote Text of the quotation.
440
#' @param citation Source of the quotation, typically a link or the name
441
#'   of a person.
442
#' @inheritParams cli_div
443
#' @examples
444
#' cli_blockquote(cli:::lorem_ipsum(), citation = "Nobody, ever")
445

446
cli_blockquote <- function(quote, citation = NULL, id = NULL,
447
                           class = NULL, .envir = parent.frame()) {
448 0
  cli__message(
449 0
    "blockquote",
450 0
    list(
451 0
      quote = glue_cmd(quote, .envir = .envir),
452 0
      citation = glue_cmd(citation, .envir = .envir),
453 0
      id = id,
454 0
      class = class
455
    )
456
  )
457
}
458

459
#' A block of code
460
#'
461
#' A helper function that creates a `div` with class `code` and then calls
462
#' `cli_verbatim()` to output code lines. The builtin theme formats these
463
#' containers specially. In particular, it adds syntax highlighting to
464
#' valid R code.
465
#'
466
#' @param lines Chracter vector, each line will be a line of code, and
467
#'   newline charactes also create new lines. Note that _no_ glue
468
#'   substitution is performed on the code.
469
#' @param ... More character vectors, they are appended to `lines`.
470
#' @param language Programming language. This is also added as a class,
471
#'   in addition to `code`.
472
#' @param .auto_close Passed to `cli_div()` when creating the container of
473
#'   the code. By default the code container is closed after emitting
474
#'   `lines` and `...` via `cli_verbatim()`. You can keep that container
475
#'   open with `.auto_close` and/or `.envir`, and then calling
476
#'   `cli_verbatim()` to add (more) code. Note that the code will be
477
#'   formatted and syntax highlighted separately for each `cli_verbatim()`
478
#'   call.
479
#' @param .envir Passed to `cli_div()` when creating the container of the
480
#'   code.
481
#' @return The id of the container that contains the code.
482
#'
483
#' @export
484
#' @examples
485
#' cli_code(format(cli::cli_blockquote))
486

487
cli_code <- function(lines = NULL, ..., language = "R",
488
                     .auto_close = TRUE, .envir = environment()) {
489 1
  lines <- c(lines, unlist(list(...)))
490 1
  id <- cli_div(
491 1
    class = paste("code", language),
492 1
    .auto_close = .auto_close,
493 1
    .envir = .envir
494
  )
495 1
  cli_verbatim(lines)
496 1
  invisible(id)
497
}
498

499
cli__message <- function(type, args, .auto_close = TRUE, .envir = NULL) {
500

501 1
  if ("id" %in% names(args) && is.null(args$id)) args$id <- new_uuid()
502

503 1
  if (.auto_close && !is.null(.envir) && !identical(.envir, .GlobalEnv)) {
504 1
    if (type == "status") {
505 1
      defer(cli_status_clear(id = args$id, result = args$auto_result),
506 1
            envir = .envir, priority = "first")
507
    } else {
508 1
      defer(cli_end(id = args$id), envir = .envir, priority = "first")
509
    }
510
  }
511

512 1
  cond <- list(message = paste("cli message", type),
513 1
               type = type, args = args, pid = clienv$pid)
514 1
  class(cond) <- c("cli_message", "callr_message", "condition")
515

516 1
  withRestarts(
517
  {
518 1
    signalCondition(cond)
519 1
    cli__default_handler(cond)
520
  },
521 1
  callr_message_handled = function() NULL,
522 1
  cli_message_handled = function() NULL)
523

524 1
  invisible(args$id)
525
}
526

527
cli__default_handler <- function(msg) {
528 1
  custom_handler <- getOption("cli.default_handler")
529

530 1
  if (is.function(custom_handler)) {
531 1
    custom_handler(msg)
532
  } else {
533 1
    cli_server_default(msg)
534
  }
535
}

Read our documentation on viewing source code .

Loading