Skip to content

$output function (x, options) { if (class == “output” && output_asis(x, options)) return(x) hook.t(x, options[[paste0(“attr.”, class)]], options[[paste0(“class.”, class)]]) } <bytecode: 0x55c2e28dad60> <environment: 0x55c2e333a2d0>

Introduction

Often we can use the corresponding base R function as a baseline. We also compare to the fansi package, where it is possible.

Data

In cli the typical use case is short string scalars, but we run some benchmarks longer strings and string vectors as well.

library(cli)
library(fansi)
options(cli.unicode = TRUE)
options(cli.num_colors = 256)
ansi <- format_inline(
  "{col_green(symbol$tick)} {.code print(x)} {.emph emphasised}"
)
plain <- ansi_strip(ansi)
vec_plain <- rep(plain, 100)
vec_ansi <- rep(ansi, 100)
vec_plain6 <- rep(plain, 6)
vec_ansi6 <- rep(plain, 6)
txt_plain <- paste(vec_plain, collapse = " ")
txt_ansi <- paste(vec_ansi, collapse = " ")
uni <- paste(
  "\U0001f477\u200d\u2640\ufe0f",
  "\U0001f477\U0001f3fb",
  "\U0001f477\u200d\u2640\ufe0f",
  "\U0001f477\U0001f3fb",
  "\U0001f477\U0001f3ff\u200d\u2640\ufe0f"
)
vec_uni <- rep(uni, 100)
txt_uni <- paste(vec_uni, collapse = " ")

ANSI functions

ansi_align()

bench::mark(
  ansi  = ansi_align(ansi, width = 20),
  plain = ansi_align(plain, width = 20), 
  base  = format(plain, width = 20),
  check = FALSE
)
#> # A tibble: 3 × 6
#>   expression      min   median `itr/sec` mem_alloc `gc/sec`
#>   <bch:expr> <bch:tm> <bch:tm>     <dbl> <bch:byt>    <dbl>
#> 1 ansi         46.9µs   50.2µs    19448.    99.3KB     18.8
#> 2 plain        46.1µs   49.5µs    19753.        0B     19.4
#> 3 base         11.4µs   12.3µs    79592.    48.4KB     15.9
bench::mark(
  ansi  = ansi_align(ansi, width = 20, align = "right"),
  plain = ansi_align(plain, width = 20, align = "right"), 
  base  = format(plain, width = 20, justify = "right"),
  check = FALSE
)
#> # A tibble: 3 × 6
#>   expression      min   median `itr/sec` mem_alloc `gc/sec`
#>   <bch:expr> <bch:tm> <bch:tm>     <dbl> <bch:byt>    <dbl>
#> 1 ansi         47.5µs   50.9µs    19162.        0B     20.9
#> 2 plain        47.9µs   51.1µs    18957.        0B     21.1
#> 3 base         13.2µs   14.3µs    68076.        0B     20.4

ansi_chartr()

bench::mark(
  ansi  = ansi_chartr("abc", "XYZ", ansi),
  plain = ansi_chartr("abc", "XYZ", plain),
  base  = chartr("abc", "XYZ", plain),
  check = FALSE
)
#> # A tibble: 3 × 6
#>   expression      min   median `itr/sec` mem_alloc `gc/sec`
#>   <bch:expr> <bch:tm> <bch:tm>     <dbl> <bch:byt>    <dbl>
#> 1 ansi       110.88µs 117.23µs     8339.   75.07KB     14.5
#> 2 plain       88.31µs  92.93µs    10491.    8.73KB     14.5
#> 3 base         1.85µs   1.97µs   492654.        0B     49.3

ansi_columns()

bench::mark(
  ansi  = ansi_columns(vec_ansi6, width = 120),
  plain = ansi_columns(vec_plain6, width = 120),
  check = FALSE
)
#> # A tibble: 2 × 6
#>   expression      min   median `itr/sec` mem_alloc `gc/sec`
#>   <bch:expr> <bch:tm> <bch:tm>     <dbl> <bch:byt>    <dbl>
#> 1 ansi          330µs    355µs     2793.   33.17KB     18.9
#> 2 plain         329µs    350µs     2834.    1.09KB     19.0

ansi_has_any()

bench::mark(
  cli_ansi        = ansi_has_any(ansi),
  fansi_ansi      = has_sgr(ansi),
  cli_plain       = ansi_has_any(plain),
  fansi_plain     = has_sgr(plain),
  cli_vec_ansi    = ansi_has_any(vec_ansi),
  fansi_vec_ansi  = has_sgr(vec_ansi),
  cli_vec_plain   = ansi_has_any(vec_plain),
  fansi_vec_plain = has_sgr(vec_plain),
  cli_txt_ansi    = ansi_has_any(txt_ansi),
  fansi_txt_ansi  = has_sgr(txt_ansi),
  cli_txt_plain   = ansi_has_any(txt_plain),
  fansi_txt_plain = has_sgr(vec_plain),
  check = FALSE
)
#> # A tibble: 12 × 6
#>    expression           min   median `itr/sec` mem_alloc `gc/sec`
#>    <bch:expr>      <bch:tm> <bch:tm>     <dbl> <bch:byt>    <dbl>
#>  1 cli_ansi           5.9µs    6.4µs   151592.     9.2KB     30.3
#>  2 fansi_ansi       30.87µs  33.01µs    29580.    4.18KB     23.7
#>  3 cli_plain         5.95µs   6.37µs   152900.        0B     30.6
#>  4 fansi_plain      30.24µs  32.44µs    30069.      688B     24.1
#>  5 cli_vec_ansi      7.35µs   7.64µs   127876.      448B     25.6
#>  6 fansi_vec_ansi   39.27µs  41.11µs    23766.    5.02KB     19.0
#>  7 cli_vec_plain     7.95µs   8.29µs   118138.      448B     11.8
#>  8 fansi_vec_plain  37.87µs  39.84µs    24477.    5.02KB     22.0
#>  9 cli_txt_ansi      5.78µs   6.19µs   158224.        0B     15.8
#> 10 fansi_txt_ansi   30.41µs  31.96µs    30498.      688B     27.5
#> 11 cli_txt_plain     6.76µs   7.06µs   135245.        0B     13.5
#> 12 fansi_txt_plain  37.55µs  39.82µs    24523.    5.02KB     19.6

ansi_html()

This is typically used with longer text.

bench::mark(
  cli   = ansi_html(txt_ansi),
  fansi = sgr_to_html(txt_ansi, classes = TRUE),
  check = FALSE
)
#> # A tibble: 2 × 6
#>   expression      min   median `itr/sec` mem_alloc `gc/sec`
#>   <bch:expr> <bch:tm> <bch:tm>     <dbl> <bch:byt>    <dbl>
#> 1 cli            59µs   60.5µs    16175.    22.7KB     8.15
#> 2 fansi         115µs  118.3µs     8296.    55.3KB     8.16

ansi_nchar()

bench::mark(
  cli_ansi        = ansi_nchar(ansi),
  fansi_ansi      = nchar_sgr(ansi),
  base_ansi       = nchar(ansi),
  cli_plain       = ansi_nchar(plain),
  fansi_plain     = nchar_sgr(plain),
  base_plain      = nchar(plain),
  cli_vec_ansi    = ansi_nchar(vec_ansi),
  fansi_vec_ansi  = nchar_sgr(vec_ansi),
  base_vec_ansi   = nchar(vec_ansi),
  cli_vec_plain   = ansi_nchar(vec_plain),
  fansi_vec_plain = nchar_sgr(vec_plain),
  base_vec_plain  = nchar(vec_plain),
  cli_txt_ansi    = ansi_nchar(txt_ansi),
  fansi_txt_ansi  = nchar_sgr(txt_ansi),
  base_txt_ansi   = nchar(txt_ansi),
  cli_txt_plain   = ansi_nchar(txt_plain),
  fansi_txt_plain = nchar_sgr(txt_plain),
  base_txt_plain  = nchar(txt_plain),
  check = FALSE
)
#> # A tibble: 18 × 6
#>    expression           min   median `itr/sec` mem_alloc `gc/sec`
#>    <bch:expr>      <bch:tm> <bch:tm>     <dbl> <bch:byt>    <dbl>
#>  1 cli_ansi           6.7µs   7.26µs   134029.        0B    26.8 
#>  2 fansi_ansi        91.7µs   96.2µs    10148.   38.83KB    16.6 
#>  3 base_ansi       901.05ns 942.15ns  1016317.        0B     0   
#>  4 cli_plain         6.63µs   7.08µs   136870.        0B    27.4 
#>  5 fansi_plain      91.25µs  95.64µs    10203.      688B    16.6 
#>  6 base_plain      831.09ns 872.07ns  1096695.        0B     0   
#>  7 cli_vec_ansi     28.59µs   29.3µs    33601.      448B     6.72
#>  8 fansi_vec_ansi  111.57µs    116µs     8419.    5.02KB    12.4 
#>  9 base_vec_ansi    16.02µs  16.09µs    61339.      448B     6.13
#> 10 cli_vec_plain    26.69µs   27.3µs    36053.      448B     3.61
#> 11 fansi_vec_plain 102.54µs 106.49µs     9160.    5.02KB    16.7 
#> 12 base_vec_plain    9.52µs   9.58µs   102696.      448B     0   
#> 13 cli_txt_ansi        28µs  28.71µs    34300.        0B     6.86
#> 14 fansi_txt_ansi  103.91µs 108.34µs     9016.      688B    14.5 
#> 15 base_txt_ansi    15.65µs   15.7µs    62775.        0B     0   
#> 16 cli_txt_plain    26.15µs  26.82µs    36376.        0B     7.28
#> 17 fansi_txt_plain  94.11µs  98.92µs     9844.      688B    14.5 
#> 18 base_txt_plain    9.19µs   9.25µs   105947.        0B    10.6
bench::mark(
  cli_ansi        = ansi_nchar(ansi, type = "width"),
  fansi_ansi      = nchar_sgr(ansi, type = "width"),
  base_ansi       = nchar(ansi, "width"),
  cli_plain       = ansi_nchar(plain, type = "width"),
  fansi_plain     = nchar_sgr(plain, type = "width"),
  base_plain      = nchar(plain, "width"),
  cli_vec_ansi    = ansi_nchar(vec_ansi, type = "width"),
  fansi_vec_ansi  = nchar_sgr(vec_ansi, type = "width"),
  base_vec_ansi   = nchar(vec_ansi, "width"),
  cli_vec_plain   = ansi_nchar(vec_plain, type = "width"),
  fansi_vec_plain = nchar_sgr(vec_plain, type = "width"),
  base_vec_plain  = nchar(vec_plain, "width"),
  cli_txt_ansi    = ansi_nchar(txt_ansi, type = "width"),
  fansi_txt_ansi  = nchar_sgr(txt_ansi, type = "width"),
  base_txt_ansi   = nchar(txt_ansi, "width"),
  cli_txt_plain   = ansi_nchar(txt_plain, type = "width"),
  fansi_txt_plain = nchar_sgr(txt_plain, type = "width"),
  base_txt_plain  = nchar(txt_plain, type = "width"),
  check = FALSE
)
#> # A tibble: 18 × 6
#>    expression           min   median `itr/sec` mem_alloc `gc/sec`
#>    <bch:expr>      <bch:tm> <bch:tm>     <dbl> <bch:byt>    <dbl>
#>  1 cli_ansi          8.46µs   9.01µs   108232.        0B    32.5 
#>  2 fansi_ansi       92.69µs  96.74µs    10068.      688B    16.5 
#>  3 base_ansi         1.21µs   1.26µs   757889.        0B     0   
#>  4 cli_plain         8.32µs   8.89µs   109960.        0B    22.0 
#>  5 fansi_plain      92.15µs  95.82µs    10180.      688B    16.5 
#>  6 base_plain      971.02ns   1.02µs   931423.        0B     0   
#>  7 cli_vec_ansi     34.84µs  35.54µs    27628.      448B     8.29
#>  8 fansi_vec_ansi  120.01µs 123.66µs     7894.    5.02KB    12.4 
#>  9 base_vec_ansi    41.37µs  41.52µs    23829.      448B     0   
#> 10 cli_vec_plain    33.28µs  34.02µs    28792.      448B     5.76
#> 11 fansi_vec_plain 110.25µs 114.35µs     8536.    5.02KB    12.4 
#> 12 base_vec_plain   21.75µs  21.94µs    45011.      448B     0   
#> 13 cli_txt_ansi     34.91µs  35.55µs    27702.        0B     8.31
#> 14 fansi_txt_ansi  111.24µs 115.25µs     8489.      688B    12.3 
#> 15 base_txt_ansi    44.15µs  44.45µs    22157.        0B     2.22
#> 16 cli_txt_plain    32.94µs  33.59µs    29310.        0B     5.86
#> 17 fansi_txt_plain 101.11µs 105.51µs     9255.      688B    14.5 
#> 18 base_txt_plain   23.22µs  23.95µs    41311.        0B     4.13

ansi_simplify()

Nothing to compare here.

bench::mark(
  cli_ansi      = ansi_simplify(ansi),
  cli_plain     = ansi_simplify(plain),
  cli_vec_ansi  = ansi_simplify(vec_ansi),
  cli_vec_plain = ansi_simplify(vec_plain),
  cli_txt_ansi  = ansi_simplify(txt_ansi),
  cli_txt_plain = ansi_simplify(txt_plain),
  check = FALSE
)
#> # A tibble: 6 × 6
#>   expression         min   median `itr/sec` mem_alloc `gc/sec`
#>   <bch:expr>    <bch:tm> <bch:tm>     <dbl> <bch:byt>    <dbl>
#> 1 cli_ansi        6.78µs   7.28µs   133824.        0B    26.8 
#> 2 cli_plain       6.36µs    6.7µs   145672.        0B    14.6 
#> 3 cli_vec_ansi   33.02µs  33.97µs    29021.      848B     5.81
#> 4 cli_vec_plain  10.26µs  10.87µs    90063.      848B     9.01
#> 5 cli_txt_ansi   31.93µs  32.61µs    30185.        0B     6.04
#> 6 cli_txt_plain   7.22µs   7.67µs   127437.        0B    25.5

ansi_strip()

bench::mark(
  cli_ansi        = ansi_strip(ansi),
  fansi_ansi      = strip_sgr(ansi),
  cli_plain       = ansi_strip(plain),
  fansi_plain     = strip_sgr(plain),
  cli_vec_ansi    = ansi_strip(vec_ansi),
  fansi_vec_ansi  = strip_sgr(vec_ansi),
  cli_vec_plain   = ansi_strip(vec_plain),
  fansi_vec_plain = strip_sgr(vec_plain),
  cli_txt_ansi    = ansi_strip(txt_ansi),
  fansi_txt_ansi  = strip_sgr(txt_ansi),
  cli_txt_plain   = ansi_strip(txt_plain),
  fansi_txt_plain = strip_sgr(txt_plain),
  check = FALSE
)
#> # A tibble: 12 × 6
#>    expression           min   median `itr/sec` mem_alloc `gc/sec`
#>    <bch:expr>      <bch:tm> <bch:tm>     <dbl> <bch:byt>    <dbl>
#>  1 cli_ansi          25.8µs   27.2µs    35979.        0B     28.8
#>  2 fansi_ansi        28.5µs   30.1µs    32382.    7.24KB     25.9
#>  3 cli_plain         25.3µs   26.4µs    37018.        0B     29.6
#>  4 fansi_plain         28µs   29.6µs    33044.      688B     23.1
#>  5 cli_vec_ansi        35µs   36.4µs    26887.      848B     21.5
#>  6 fansi_vec_ansi    53.7µs   55.9µs    17493.    5.41KB     14.6
#>  7 cli_vec_plain     28.3µs     30µs    32525.      848B     26.0
#>  8 fansi_vec_plain   36.3µs   38.1µs    25629.    4.59KB     18.0
#>  9 cli_txt_ansi      34.7µs   36.4µs    26921.        0B     21.6
#> 10 fansi_txt_ansi    44.6µs   46.7µs    20929.    5.12KB     16.9
#> 11 cli_txt_plain     26.5µs   27.9µs    34981.        0B     28.0
#> 12 fansi_txt_plain   28.9µs   30.3µs    32241.      688B     25.8

ansi_strsplit()

bench::mark(
  cli_ansi        = ansi_strsplit(ansi, "i"),
  fansi_ansi      = strsplit_sgr(ansi, "i"),
  base_ansi       = strsplit(ansi, "i"),
  cli_plain       = ansi_strsplit(plain, "i"),
  fansi_plain     = strsplit_sgr(plain, "i"),
  base_plain      = strsplit(plain, "i"),
  cli_vec_ansi    = ansi_strsplit(vec_ansi, "i"),
  fansi_vec_ansi  = strsplit_sgr(vec_ansi, "i"),
  base_vec_ansi   = strsplit(vec_ansi, "i"),
  cli_vec_plain   = ansi_strsplit(vec_plain, "i"),
  fansi_vec_plain = strsplit_sgr(vec_plain, "i"),
  base_vec_plain  = strsplit(vec_plain, "i"),
  cli_txt_ansi    = ansi_strsplit(txt_ansi, "i"),
  fansi_txt_ansi  = strsplit_sgr(txt_ansi, "i"),
  base_txt_ansi   = strsplit(txt_ansi, "i"),
  cli_txt_plain   = ansi_strsplit(txt_plain, "i"),
  fansi_txt_plain = strsplit_sgr(txt_plain, "i"),
  base_txt_plain  = strsplit(txt_plain, "i"),
  check = FALSE
)
#> # A tibble: 18 × 6
#>    expression           min   median `itr/sec` mem_alloc `gc/sec`
#>    <bch:expr>      <bch:tm> <bch:tm>     <dbl> <bch:byt>    <dbl>
#>  1 cli_ansi        162.99µs  169.8µs     5754.  104.34KB    18.9 
#>  2 fansi_ansi      125.75µs 131.58µs     7425.  106.35KB    21.1 
#>  3 base_ansi         4.16µs   4.51µs   217102.      224B     0   
#>  4 cli_plain       161.38µs 168.33µs     5798.    8.09KB    18.8 
#>  5 fansi_plain     123.89µs 129.49µs     7543.    9.62KB    21.0 
#>  6 base_plain        3.65µs    3.9µs   250033.        0B    25.0 
#>  7 cli_vec_ansi      7.43ms   7.54ms      132.  823.77KB    24.9 
#>  8 fansi_vec_ansi    1.02ms   1.06ms      911.  846.81KB    19.3 
#>  9 base_vec_ansi   156.41µs 161.36µs     6098.    22.7KB     2.03
#> 10 cli_vec_plain     7.42ms   7.53ms      132.  823.77KB    28.6 
#> 11 fansi_vec_plain 965.81µs      1ms      983.  845.98KB    19.5 
#> 12 base_vec_plain  105.45µs 110.86µs     8837.      848B     4.05
#> 13 cli_txt_ansi      3.41ms   3.44ms      290.    63.6KB     0   
#> 14 fansi_txt_ansi    1.54ms   1.56ms      638.   35.05KB     2.02
#> 15 base_txt_ansi   136.77µs 146.13µs     6626.   18.47KB     2.03
#> 16 cli_txt_plain     2.38ms    2.4ms      414.    63.6KB     0   
#> 17 fansi_txt_plain 516.98µs 545.34µs     1824.    30.6KB     6.72
#> 18 base_txt_plain    86.9µs  89.43µs    10972.   11.05KB     2.01

ansi_strtrim()

bench::mark(
  cli_ansi        = ansi_strtrim(ansi, 10),
  fansi_ansi      = strtrim_sgr(ansi, 10),
  base_ansi       = strtrim(ansi, 10),
  cli_plain       = ansi_strtrim(plain, 10),
  fansi_plain     = strtrim_sgr(plain, 10),
  base_plain      = strtrim(plain, 10),
  cli_vec_ansi    = ansi_strtrim(vec_ansi, 10),
  fansi_vec_ansi  = strtrim_sgr(vec_ansi, 10),
  base_vec_ansi   = strtrim(vec_ansi, 10),
  cli_vec_plain   = ansi_strtrim(vec_plain, 10),
  fansi_vec_plain = strtrim_sgr(vec_plain, 10),
  base_vec_plain  = strtrim(vec_plain, 10),
  cli_txt_ansi    = ansi_strtrim(txt_ansi, 10),
  fansi_txt_ansi  = strtrim_sgr(txt_ansi, 10),
  base_txt_ansi   = strtrim(txt_ansi, 10),
  cli_txt_plain   = ansi_strtrim(txt_plain, 10),
  fansi_txt_plain = strtrim_sgr(txt_plain, 10),
  base_txt_plain  = strtrim(txt_plain, 10),
  check = FALSE
)
#> # A tibble: 18 × 6
#>    expression           min   median `itr/sec` mem_alloc `gc/sec`
#>    <bch:expr>      <bch:tm> <bch:tm>     <dbl> <bch:byt>    <dbl>
#>  1 cli_ansi        145.63µs 152.59µs     6414.   33.84KB     23.0
#>  2 fansi_ansi       53.75µs  56.73µs    17173.   31.43KB     23.5
#>  3 base_ansi         1.09µs   1.14µs   835431.     4.2KB      0  
#>  4 cli_plain       143.43µs 149.76µs     6529.        0B     25.3
#>  5 fansi_plain      52.84µs  55.93µs    17462.      872B     23.1
#>  6 base_plain           1µs   1.05µs   902903.        0B      0  
#>  7 cli_vec_ansi     273.8µs 284.97µs     3360.   16.73KB     12.4
#>  8 fansi_vec_ansi  122.72µs  126.8µs     7693.    5.59KB     12.4
#>  9 base_vec_ansi    35.94µs  36.28µs    27245.      848B      0  
#> 10 cli_vec_plain   229.24µs 237.44µs     4138.   16.73KB     14.7
#> 11 fansi_vec_plain 119.97µs 123.58µs     7930.    5.59KB     12.4
#> 12 base_vec_plain   30.05µs  30.77µs    31898.      848B      0  
#> 13 cli_txt_ansi    154.61µs 161.56µs     6069.        0B     23.1
#> 14 fansi_txt_ansi   52.94µs  56.24µs    17354.      872B     23.1
#> 15 base_txt_ansi     1.13µs   1.17µs   814429.        0B      0  
#> 16 cli_txt_plain   145.92µs 151.59µs     6463.        0B     25.3
#> 17 fansi_txt_plain  53.39µs  56.45µs    17299.      872B     23.2
#> 18 base_txt_plain    1.04µs   1.08µs   885174.        0B      0

ansi_strwrap()

This function is most useful for longer text, but it is often called for short text in cli, so it makes sense to benchmark that as well.

bench::mark(
  cli_ansi        = ansi_strwrap(ansi, 30),
  fansi_ansi      = strwrap_sgr(ansi, 30),
  base_ansi       = strwrap(ansi, 30),
  cli_plain       = ansi_strwrap(plain, 30),
  fansi_plain     = strwrap_sgr(plain, 30),
  base_plain      = strwrap(plain, 30),
  cli_vec_ansi    = ansi_strwrap(vec_ansi, 30),
  fansi_vec_ansi  = strwrap_sgr(vec_ansi, 30),
  base_vec_ansi   = strwrap(vec_ansi, 30),
  cli_vec_plain   = ansi_strwrap(vec_plain, 30),
  fansi_vec_plain = strwrap_sgr(vec_plain, 30),
  base_vec_plain  = strwrap(vec_plain, 30),
  cli_txt_ansi    = ansi_strwrap(txt_ansi, 30),
  fansi_txt_ansi  = strwrap_sgr(txt_ansi, 30),
  base_txt_ansi   = strwrap(txt_ansi, 30),
  cli_txt_plain   = ansi_strwrap(txt_plain, 30),
  fansi_txt_plain = strwrap_sgr(txt_plain, 30),
  base_txt_plain  = strwrap(txt_plain, 30),
  check = FALSE
)
#> # A tibble: 18 × 6
#>    expression           min   median `itr/sec` mem_alloc `gc/sec`
#>    <bch:expr>      <bch:tm> <bch:tm>     <dbl> <bch:byt>    <dbl>
#>  1 cli_ansi        401.09µs 422.35µs    2351.         0B     21.6
#>  2 fansi_ansi       96.31µs 101.31µs    9667.    97.33KB     20.9
#>  3 base_ansi        38.51µs  40.58µs   23828.         0B     21.5
#>  4 cli_plain       272.59µs 285.33µs    3452.         0B     18.8
#>  5 fansi_plain      95.49µs  100.4µs    9745.       872B     23.1
#>  6 base_plain       32.09µs  33.66µs   28952.         0B     20.3
#>  7 cli_vec_ansi     42.17ms  42.46ms      23.5    2.48KB    118. 
#>  8 fansi_vec_ansi  242.05µs 251.06µs    3931.     7.25KB     10.3
#>  9 base_vec_ansi     2.22ms   2.27ms     440.    48.18KB     26.5
#> 10 cli_vec_plain    28.68ms  28.88ms      34.6    2.48KB     38.9
#> 11 fansi_vec_plain 201.55µs 209.89µs    4677.     6.42KB     14.6
#> 12 base_vec_plain    1.61ms   1.66ms     599.     47.4KB     21.8
#> 13 cli_txt_ansi     23.88ms  23.99ms      41.7  507.59KB     13.0
#> 14 fansi_txt_ansi  232.61µs 241.12µs    4084.     6.77KB     10.3
#> 15 base_txt_ansi     1.25ms   1.28ms     766.   582.06KB     20.3
#> 16 cli_txt_plain     1.26ms   1.29ms     767.   369.84KB     17.5
#> 17 fansi_txt_plain  183.5µs 188.58µs    5219.     2.51KB     12.3
#> 18 base_txt_plain  839.46µs 863.89µs    1149.   367.31KB     17.6

ansi_substr()

bench::mark(
  cli_ansi        = ansi_substr(ansi, 2, 10),
  fansi_ansi      = substr_sgr(ansi, 2, 10),
  base_ansi       = substr(ansi, 2, 10),
  cli_plain       = ansi_substr(plain, 2, 10),
  fansi_plain     = substr_sgr(plain, 2, 10),
  base_plain      = substr(plain, 2, 10),
  cli_vec_ansi    = ansi_substr(vec_ansi, 2, 10),
  fansi_vec_ansi  = substr_sgr(vec_ansi, 2, 10),
  base_vec_ansi   = substr(vec_ansi, 2, 10),
  cli_vec_plain   = ansi_substr(vec_plain, 2, 10),
  fansi_vec_plain = substr_sgr(vec_plain, 2, 10),
  base_vec_plain  = substr(vec_plain, 2, 10),
  cli_txt_ansi    = ansi_substr(txt_ansi, 2, 10),
  fansi_txt_ansi  = substr_sgr(txt_ansi, 2, 10),
  base_txt_ansi   = substr(txt_ansi, 2, 10),
  cli_txt_plain   = ansi_substr(txt_plain, 2, 10),
  fansi_txt_plain = substr_sgr(txt_plain, 2, 10),
  base_txt_plain  = substr(txt_plain, 2, 10),
  check = FALSE
)
#> # A tibble: 18 × 6
#>    expression           min   median `itr/sec` mem_alloc `gc/sec`
#>    <bch:expr>      <bch:tm> <bch:tm>     <dbl> <bch:byt>    <dbl>
#>  1 cli_ansi          6.87µs   7.26µs   134712.   24.83KB    26.9 
#>  2 fansi_ansi        77.2µs  81.09µs    12045.   28.48KB    21.1 
#>  3 base_ansi         1.04µs   1.08µs   878667.        0B    87.9 
#>  4 cli_plain         6.85µs   7.29µs   133544.        0B    26.7 
#>  5 fansi_plain      76.12µs   80.2µs    12162.    1.98KB    21.0 
#>  6 base_plain      972.07ns   1.05µs   906806.        0B    90.7 
#>  7 cli_vec_ansi     27.09µs  27.91µs    35285.     1.7KB     7.06
#>  8 fansi_vec_ansi  112.75µs  116.7µs     8330.    8.86KB    14.6 
#>  9 base_vec_ansi     6.02µs   6.14µs   159418.      848B     0   
#> 10 cli_vec_plain    22.94µs     24µs    40922.     1.7KB    12.3 
#> 11 fansi_vec_plain 106.49µs  111.1µs     8798.    8.86KB    14.7 
#> 12 base_vec_plain     5.8µs   5.91µs   163992.      848B    16.4 
#> 13 cli_txt_ansi       6.9µs   7.35µs   132558.        0B    26.5 
#> 14 fansi_txt_ansi   75.98µs  79.96µs    12203.    1.98KB    21.0 
#> 15 base_txt_ansi     5.17µs   5.25µs   186772.        0B    18.7 
#> 16 cli_txt_plain     7.45µs   7.93µs   123014.        0B    24.6 
#> 17 fansi_txt_plain  76.15µs  80.02µs    12131.    1.98KB    21.0 
#> 18 base_txt_plain    3.38µs   3.45µs   282767.        0B     0

ansi_tolower() , ansi_toupper()

bench::mark(
  cli_ansi        = ansi_tolower(ansi),
  base_ansi       = tolower(ansi),
  cli_plain       = ansi_tolower(plain),
  base_plain      = tolower(plain),
  cli_vec_ansi    = ansi_tolower(vec_ansi),
  base_vec_ansi   = tolower(vec_ansi),
  cli_vec_plain   = ansi_tolower(vec_plain),
  base_vec_plain  = tolower(vec_plain),
  cli_txt_ansi    = ansi_tolower(txt_ansi),
  base_txt_ansi   = tolower(txt_ansi),
  cli_txt_plain   = ansi_tolower(txt_plain),
  base_txt_plain  = tolower(txt_plain),
  check = FALSE
)
#> # A tibble: 12 × 6
#>    expression          min   median `itr/sec` mem_alloc `gc/sec`
#>    <bch:expr>     <bch:tm> <bch:tm>     <dbl> <bch:byt>    <dbl>
#>  1 cli_ansi       105.41µs 109.97µs    8851.    11.88KB    16.6 
#>  2 base_ansi        1.33µs   1.38µs  705647.         0B     0   
#>  3 cli_plain        84.8µs  88.71µs   10964.     8.73KB    14.5 
#>  4 base_plain       1.02µs   1.06µs  918151.         0B     0   
#>  5 cli_vec_ansi     4.02ms   4.11ms     243.   838.77KB    31.0 
#>  6 base_vec_ansi   74.41µs   74.8µs   13234.       848B     0   
#>  7 cli_vec_plain    2.26ms   2.32ms     429.    816.9KB    28.4 
#>  8 base_vec_plain  43.91µs  44.27µs   22336.       848B     0   
#>  9 cli_txt_ansi    13.47ms   13.6ms      73.5  114.42KB     6.49
#> 10 base_txt_ansi   75.91µs  76.19µs   12990.         0B     0   
#> 11 cli_txt_plain  269.38µs  277.5µs    3550.    18.16KB     6.10
#> 12 base_txt_plain  42.25µs  43.71µs   22848.         0B     0

ansi_trimws()

bench::mark(
  cli_ansi        = ansi_trimws(ansi),
  base_ansi       = trimws(ansi),
  cli_plain       = ansi_trimws(plain),
  base_plain      = trimws(plain),
  cli_vec_ansi    = ansi_trimws(vec_ansi),
  base_vec_ansi   = trimws(vec_ansi),
  cli_vec_plain   = ansi_trimws(vec_plain),
  base_vec_plain  = trimws(vec_plain),
  cli_txt_ansi    = ansi_trimws(txt_ansi),
  base_txt_ansi   = trimws(txt_ansi),
  cli_txt_plain   = ansi_trimws(txt_plain),
  base_txt_plain  = trimws(txt_plain),
  check = FALSE
)
#> # A tibble: 12 × 6
#>    expression          min   median `itr/sec` mem_alloc `gc/sec`
#>    <bch:expr>     <bch:tm> <bch:tm>     <dbl> <bch:byt>    <dbl>
#>  1 cli_ansi        107.2µs  112.5µs     8637.        0B    23.0 
#>  2 base_ansi        16.4µs   17.4µs    56109.        0B    22.5 
#>  3 cli_plain         106µs  111.1µs     8785.        0B    23.0 
#>  4 base_plain       16.3µs   17.3µs    56524.        0B    22.6 
#>  5 cli_vec_ansi    202.8µs  211.9µs     4634.     7.2KB    12.4 
#>  6 base_vec_ansi    55.1µs   63.5µs    15492.    1.66KB     6.10
#>  7 cli_vec_plain   189.9µs  199.3µs     4928.     7.2KB    12.4 
#>  8 base_vec_plain   49.4µs   56.6µs    17342.    1.66KB     6.10
#>  9 cli_txt_ansi      177µs  183.4µs     5344.        0B    14.5 
#> 10 base_txt_ansi    37.9µs   39.1µs    25018.        0B     7.51
#> 11 cli_txt_plain   158.9µs  166.7µs     5866.        0B    16.7 
#> 12 base_txt_plain   33.4µs   34.5µs    28320.        0B    11.3

UTF-8 functions

utf8_nchar()

bench::mark(
  cli        = utf8_nchar(uni, type = "chars"),
  base       = nchar(uni, "chars"),
  cli_vec    = utf8_nchar(vec_uni, type = "chars"),
  base_vec   = nchar(vec_uni, "chars"),
  cli_txt    = utf8_nchar(txt_uni, type = "chars"),
  base_txt   = nchar(txt_uni, "chars"),
  check = FALSE
)
#> # A tibble: 6 × 6
#>   expression      min   median `itr/sec` mem_alloc `gc/sec`
#>   <bch:expr> <bch:tm> <bch:tm>     <dbl> <bch:byt>    <dbl>
#> 1 cli          8.14µs   8.69µs   112230.        0B    22.5 
#> 2 base       881.03ns 932.02ns  1003496.        0B     0   
#> 3 cli_vec     23.01µs  23.69µs    41394.      448B    12.4 
#> 4 base_vec    11.59µs  11.89µs    82949.      448B     0   
#> 5 cli_txt     23.17µs  23.81µs    41131.        0B     8.23
#> 6 base_txt    12.41µs  12.71µs    76942.        0B     7.69
bench::mark(
  cli        = utf8_nchar(uni, type = "width"),
  base       = nchar(uni, "width"),
  cli_vec    = utf8_nchar(vec_uni, type = "width"),
  base_vec   = nchar(vec_uni, "width"),
  cli_txt    = utf8_nchar(txt_uni, type = "width"),
  base_txt   = nchar(txt_uni, "width"),
  check = FALSE
)
#> # A tibble: 6 × 6
#>   expression      min   median `itr/sec` mem_alloc `gc/sec`
#>   <bch:expr> <bch:tm> <bch:tm>     <dbl> <bch:byt>    <dbl>
#> 1 cli          8.07µs   8.72µs   111419.        0B    22.3 
#> 2 base         1.33µs   1.38µs   692855.        0B     0   
#> 3 cli_vec     28.52µs   29.3µs    33501.      448B    10.1 
#> 4 base_vec    51.05µs  51.65µs    19135.      448B     0   
#> 5 cli_txt     28.91µs  29.68µs    33104.        0B     6.62
#> 6 base_txt    87.75µs  88.62µs    11170.        0B     0
bench::mark(
  cli        = utf8_nchar(uni, type = "codepoints"),
  base       = nchar(uni, "chars"),
  cli_vec    = utf8_nchar(vec_uni, type = "codepoints"),
  base_vec   = nchar(vec_uni, "chars"),
  cli_txt    = utf8_nchar(txt_uni, type = "codepoints"),
  base_txt   = nchar(txt_uni, "chars"),
  check = FALSE
)
#> # A tibble: 6 × 6
#>   expression      min   median `itr/sec` mem_alloc `gc/sec`
#>   <bch:expr> <bch:tm> <bch:tm>     <dbl> <bch:byt>    <dbl>
#> 1 cli          8.63µs   9.18µs   106147.        0B     21.2
#> 2 base       891.04ns 932.02ns  1017290.        0B      0  
#> 3 cli_vec     19.58µs  20.27µs    48376.      448B     14.5
#> 4 base_vec     11.6µs  11.92µs    82715.      448B      0  
#> 5 cli_txt     20.11µs  20.87µs    46945.        0B     14.1
#> 6 base_txt    12.41µs  12.71µs    77904.        0B      0

utf8_substr()

bench::mark(
  cli        = utf8_substr(uni, 2, 10),
  base       = substr(uni, 2, 10),
  cli_vec    = utf8_substr(vec_uni, 2, 10),
  base_vec   = substr(vec_uni, 2, 10),
  cli_txt    = utf8_substr(txt_uni, 2, 10),
  base_txt   = substr(txt_uni, 2, 10),
  check = FALSE
)
#> # A tibble: 6 × 6
#>   expression      min   median `itr/sec` mem_alloc `gc/sec`
#>   <bch:expr> <bch:tm> <bch:tm>     <dbl> <bch:byt>    <dbl>
#> 1 cli          6.31µs   6.82µs   142010.    22.1KB    28.4 
#> 2 base         1.07µs   1.12µs   845319.        0B    84.5 
#> 3 cli_vec     28.87µs  29.66µs    33182.     1.7KB     6.64
#> 4 base_vec     7.91µs   8.39µs   117686.      848B     0   
#> 5 cli_txt      6.27µs   6.73µs   144030.        0B    43.2 
#> 6 base_txt     5.48µs   5.54µs   176832.        0B     0

Session info

sessioninfo::session_info()
#> ─ Session info ──────────────────────────────────────────────────────
#>  setting  value
#>  version  R version 4.5.0 (2025-04-11)
#>  os       Ubuntu 24.04.2 LTS
#>  system   x86_64, linux-gnu
#>  ui       X11
#>  language en
#>  collate  C.UTF-8
#>  ctype    C.UTF-8
#>  tz       UTC
#>  date     2025-06-01
#>  pandoc   3.1.11 @ /opt/hostedtoolcache/pandoc/3.1.11/x64/ (via rmarkdown)
#>  quarto   NA
#> 
#> ─ Packages ──────────────────────────────────────────────────────────
#>  package     * version    date (UTC) lib source
#>  bench         1.1.4      2025-01-16 [1] RSPM
#>  bslib         0.9.0      2025-01-30 [1] RSPM
#>  cachem        1.1.0      2024-05-16 [1] RSPM
#>  cli         * 3.6.5.9000 2025-06-01 [1] local
#>  codetools     0.2-20     2024-03-31 [3] CRAN (R 4.5.0)
#>  desc          1.4.3      2023-12-10 [1] RSPM
#>  digest        0.6.37     2024-08-19 [1] RSPM
#>  evaluate      1.0.3      2025-01-10 [1] RSPM
#>  fansi       * 1.0.6      2023-12-08 [1] RSPM
#>  fastmap       1.2.0      2024-05-15 [1] RSPM
#>  fs            1.6.6      2025-04-12 [1] RSPM
#>  glue          1.8.0      2024-09-30 [1] RSPM
#>  htmltools     0.5.8.1    2024-04-04 [1] RSPM
#>  htmlwidgets   1.6.4      2023-12-06 [1] RSPM
#>  jquerylib     0.1.4      2021-04-26 [1] RSPM
#>  jsonlite      2.0.0      2025-03-27 [1] RSPM
#>  knitr         1.50       2025-03-16 [1] RSPM
#>  lifecycle     1.0.4      2023-11-07 [1] RSPM
#>  magrittr      2.0.3      2022-03-30 [1] RSPM
#>  pillar        1.10.2     2025-04-05 [1] RSPM
#>  pkgconfig     2.0.3      2019-09-22 [1] RSPM
#>  pkgdown       2.1.3      2025-05-25 [1] any (@2.1.3)
#>  profmem       0.7.0      2025-05-02 [1] RSPM
#>  R6            2.6.1      2025-02-15 [1] RSPM
#>  ragg          1.4.0      2025-04-10 [1] RSPM
#>  rlang         1.1.6      2025-04-11 [1] RSPM
#>  rmarkdown     2.29       2024-11-04 [1] RSPM
#>  sass          0.4.10     2025-04-11 [1] RSPM
#>  sessioninfo   1.2.3      2025-02-05 [1] RSPM
#>  systemfonts   1.2.3      2025-04-30 [1] RSPM
#>  textshaping   1.0.1      2025-05-01 [1] RSPM
#>  tibble        3.2.1      2023-03-20 [1] RSPM
#>  utf8          1.2.5      2025-05-01 [1] RSPM
#>  vctrs         0.6.5      2023-12-01 [1] RSPM
#>  xfun          0.52       2025-04-02 [1] RSPM
#>  yaml          2.3.10     2024-07-26 [1] RSPM
#> 
#>  [1] /home/runner/work/_temp/Library
#>  [2] /opt/R/4.5.0/lib/R/site-library
#>  [3] /opt/R/4.5.0/lib/R/library
#>  * ── Packages attached to the search path.
#> 
#> ─────────────────────────────────────────────────────────────────────