```{r, child = "setup.Rmd", include = FALSE}
```

Condition formatting is a set of operations applied to raw inputs for error messages that includes:

- Transforming a character vector of lines to a width-wrapped list of error bullets. This makes it easy to write messages in a list format where each bullet conveys a single important point.

  ```{r, error = TRUE}
  abort(c(
    "The error header",
    "*" = "An error bullet",
    "i" = "An info bullet",
    "x" = "A cross bullet"
  ))
  ```

  See the [tidyverse error style guide](https://style.tidyverse.org/errors.html) for more about this style of error messaging.

- Applying style (emphasis, boldness, ...) and colours to message elements.

While the rlang package embeds rudimentary formatting routines, the main formatting engine is implemented in the [cli package](https://cli.r-lib.org/).


## Formatting messages with cli

By default, rlang uses an internal mechanism to format bullets. It is preferable to delegate formatting to the [cli package](https://cli.r-lib.org/) by using [cli::cli_abort()], [cli::cli_warn()], and [cli::cli_inform()] instead of the rlang versions. These wrappers enable cli formatting with sophisticated paragraph wrapping and bullet indenting that make long lines easier to read. In the following example, a long `!` bullet is broken with an indented newline:

```r
rlang::global_entrace(class = "errorr")
#> Error in `rlang::global_entrace()`:
#> ! `class` must be one of "error", "warning", or "message",
#>   not "errorr".
#> i Did you mean "error"?
```

The cli wrappers also add many features such as interpolation, semantic formatting of text elements, and pluralisation:

```r
inform_marbles <- function(n_marbles) {
  cli::cli_inform(c(
    "i" = "I have {n_marbles} shiny marble{?s} in my bag.",
    "v" = "Way to go {.code cli::cli_inform()}!"
  ))
}

inform_marbles(1)
#> i I have 1 shiny marble in my bag.
#> v Way to go `cli::cli_inform()`!

inform_marbles(2)
#> i I have 2 shiny marbles in my bag.
#> v Way to go `cli::cli_inform()`!
```


## Transitioning from `abort()` to `cli_abort()`

If you plan to mass-rename calls from `abort()` to `cli::cli_abort()`, be careful if you assemble error messages from user inputs. If these individual pieces contain cli or glue syntax, this will result in hard-to-debug errors and possibly [unexpected behaviour](https://xkcd.com/327/).

```{r, error = TRUE}
user_input <- "{base::stop('Wrong message.', call. = FALSE)}"
cli::cli_abort(sprintf("Can't handle input `%s`.", user_input))
```

To avoid this, protect your error messages by using cli to assemble the pieces:

```{r, error = TRUE}
user_input <- "{base::stop('Wrong message.', call. = FALSE)}"
cli::cli_abort("Can't handle input {.code {user_input}}.")
```


## Enabling cli formatting globally

To enable cli formatting for all `abort()` calls in your namespace, call [local_use_cli()] in the `onLoad` hook of your package. Using [on_load()] (make sure to call [run_on_load()] in your hook):

```r
on_load(local_use_cli())
```

Enabling cli formatting in `abort()` is useful for:

- Transitioning from `abort()` to `cli::cli_abort()` progressively.

- Using `abort()` when you'd like to disable interpolation syntax.

- Creating error conditions with `error_cnd()`. These condition messages will be automatically formatted with cli as well.
