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: 0x55baa1df0c08> <environment: 0x55baa28418a0>

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         43.9µs     47µs    20649.    99.2KB     18.9
#> 2 plain          44µs   47.2µs    20573.        0B     19.6
#> 3 base         11.1µs   12.2µs    79453.    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           45µs   48.2µs    19967.        0B     20.9
#> 2 plain        44.8µs   47.3µs    20393.        0B     23.3
#> 3 base           13µs     14µs    69281.        0B     20.8

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       105.74µs 112.07µs     8667.   75.02KB     16.7
#> 2 plain        83.8µs  88.66µs    10922.    8.73KB     14.6
#> 3 base         1.84µs   1.96µs   491077.        0B      0

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          322µs    344µs     2872.   33.15KB     18.8
#> 2 plain         322µs    342µs     2891.    1.09KB     21.1

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.62µs   6.12µs   156958.    9.19KB     31.4
#>  2 fansi_ansi       29.61µs  32.08µs    30259.    4.18KB     24.2
#>  3 cli_plain         5.64µs   6.13µs   158520.        0B     31.7
#>  4 fansi_plain      29.21µs   31.5µs    30641.      688B     24.5
#>  5 cli_vec_ansi      6.98µs   7.35µs   132766.      448B     13.3
#>  6 fansi_vec_ansi   38.53µs  40.23µs    24093.    5.02KB     19.3
#>  7 cli_vec_plain     7.55µs   7.97µs   122718.      448B     24.5
#>  8 fansi_vec_plain  36.89µs  38.59µs    25263.    5.02KB     20.2
#>  9 cli_txt_ansi      5.63µs   5.93µs   163943.        0B     32.8
#> 10 fansi_txt_ansi   29.34µs  30.82µs    30388.      688B     24.3
#> 11 cli_txt_plain     6.46µs   6.79µs   143495.        0B     14.4
#> 12 fansi_txt_plain  37.02µs  38.75µs    25143.    5.02KB     20.1

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.8µs   61.8µs    15306.    22.6KB     8.15
#> 2 fansi       111.6µs  114.5µs     8553.    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.49µs   7.07µs   136627.        0B    27.3 
#>  2 fansi_ansi       88.06µs  91.48µs    10607.   38.84KB    16.6 
#>  3 base_ansi       911.07ns 942.15ns  1007532.        0B   101.  
#>  4 cli_plain         6.49µs   6.98µs   138855.        0B    13.9 
#>  5 fansi_plain      87.78µs  92.06µs    10430.      688B    16.7 
#>  6 base_plain      820.96ns 942.15ns   790763.        0B    79.1 
#>  7 cli_vec_ansi     29.25µs  30.14µs    32578.      448B     3.26
#>  8 fansi_vec_ansi  107.53µs 112.71µs     8630.    5.02KB    14.6 
#>  9 base_vec_ansi    18.48µs  18.57µs    53139.      448B     0   
#> 10 cli_vec_plain    28.05µs  28.79µs    34125.      448B     6.83
#> 11 fansi_vec_plain  99.53µs 104.39µs     9303.    5.02KB    14.7 
#> 12 base_vec_plain   10.85µs  10.93µs    90202.      448B     0   
#> 13 cli_txt_ansi     29.16µs  29.86µs    32913.        0B     6.58
#> 14 fansi_txt_ansi   101.2µs 106.32µs     9101.      688B    14.6 
#> 15 base_txt_ansi     18.2µs  18.25µs    53783.        0B     0   
#> 16 cli_txt_plain    27.37µs  28.04µs    35021.        0B     7.01
#> 17 fansi_txt_plain  90.93µs  95.74µs    10121.      688B    16.8 
#> 18 base_txt_plain   10.59µs  11.09µs    84023.        0B     0
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.27µs   8.92µs   108575.        0B    32.6 
#>  2 fansi_ansi       88.77µs  93.09µs    10419.      688B    16.6 
#>  3 base_ansi         1.22µs   1.26µs   761886.        0B     0   
#>  4 cli_plain         8.19µs   8.72µs   111611.        0B    22.3 
#>  5 fansi_plain      88.71µs  92.48µs    10420.      688B    16.6 
#>  6 base_plain           1µs   1.05µs   909690.        0B    91.0 
#>  7 cli_vec_ansi      34.1µs  35.17µs    27764.      448B     5.55
#>  8 fansi_vec_ansi  117.23µs 120.89µs     8042.    5.02KB    12.4 
#>  9 base_vec_ansi    42.99µs  44.15µs    22448.      448B     0   
#> 10 cli_vec_plain     33.3µs  33.97µs    28934.      448B     5.79
#> 11 fansi_vec_plain 107.35µs 111.44µs     8680.    5.02KB    14.5 
#> 12 base_vec_plain   22.96µs   23.3µs    42425.      448B     0   
#> 13 cli_txt_ansi     34.73µs   35.6µs    27637.        0B     8.29
#> 14 fansi_txt_ansi  107.25µs 111.72µs     8731.      688B    12.4 
#> 15 base_txt_ansi    45.55µs  46.73µs    21163.        0B     2.12
#> 16 cli_txt_plain    32.64µs  33.32µs    29144.        0B     5.83
#> 17 fansi_txt_plain  98.67µs 103.75µs     8587.      688B    12.4 
#> 18 base_txt_plain   24.78µs   25.3µs    39016.        0B     3.90

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.38µs   6.97µs   139387.        0B    27.9 
#> 2 cli_plain       6.04µs   6.48µs   150344.        0B    15.0 
#> 3 cli_vec_ansi   31.48µs  32.65µs    28910.      848B     5.78
#> 4 cli_vec_plain  10.01µs  10.62µs    92084.      848B     9.21
#> 5 cli_txt_ansi   30.67µs  31.46µs    31367.        0B     6.27
#> 6 cli_txt_plain   6.84µs   7.37µs   128483.        0B    25.7

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          11.6µs   12.2µs    80004.        0B     24.0
#>  2 fansi_ansi        27.3µs   28.7µs    33956.    7.24KB     27.2
#>  3 cli_plain         11.4µs   12.1µs    80587.        0B     24.2
#>  4 fansi_plain       26.9µs   28.5µs    34061.      688B     27.3
#>  5 cli_vec_ansi      20.5µs   21.3µs    45811.      848B     13.7
#>  6 fansi_vec_ansi    52.3µs   54.3µs    18012.    5.41KB     12.5
#>  7 cli_vec_plain     14.1µs   14.8µs    65913.      848B     26.4
#>  8 fansi_vec_plain   35.6µs   37.5µs    25994.    4.59KB     18.2
#>  9 cli_txt_ansi      20.1µs   20.8µs    47118.        0B     14.1
#> 10 fansi_txt_ansi    43.5µs   45.2µs    21613.    5.12KB     17.3
#> 11 cli_txt_plain     12.4µs   13.1µs    73893.        0B     22.2
#> 12 fansi_txt_plain   28.5µs   30.4µs    31736.      688B     25.4

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         142.8µs 149.42µs     6524.  104.31KB    18.9 
#>  2 fansi_ansi      123.99µs 129.67µs     7518.  106.35KB    19.2 
#>  3 base_ansi         3.98µs   4.28µs   229047.      224B    22.9 
#>  4 cli_plain       141.37µs 148.54µs     6408.    8.09KB    16.7 
#>  5 fansi_plain     124.32µs 129.97µs     7465.    9.62KB    21.3 
#>  6 base_plain        3.61µs   3.81µs   257024.        0B     0   
#>  7 cli_vec_ansi      7.26ms   7.37ms      135.  823.77KB    27.5 
#>  8 fansi_vec_ansi    1.04ms   1.07ms      895.  846.81KB    17.2 
#>  9 base_vec_ansi   153.95µs 160.47µs     6104.    22.7KB     2.03
#> 10 cli_vec_plain     7.23ms   7.38ms      134.  823.77KB    28.9 
#> 11 fansi_vec_plain 968.31µs      1ms      988.  845.98KB    19.5 
#> 12 base_vec_plain  107.13µs 110.19µs     8901.      848B     2.01
#> 13 cli_txt_ansi      3.35ms   3.38ms      295.    63.6KB     2.02
#> 14 fansi_txt_ansi    1.54ms   1.57ms      627.   35.05KB     2.02
#> 15 base_txt_ansi   134.89µs  143.7µs     6910.   18.47KB     2.02
#> 16 cli_txt_plain     2.47ms    2.5ms      397.    63.6KB     0   
#> 17 fansi_txt_plain 518.38µs 536.93µs     1851.    30.6KB     6.15
#> 18 base_txt_plain   86.63µs  88.93µs    10903.   11.05KB     2.02

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         95.96µs 101.62µs     9258.   33.81KB     21.2
#>  2 fansi_ansi       53.25µs  56.91µs    16877.   31.43KB     21.3
#>  3 base_ansi         1.06µs   1.15µs   793788.     4.2KB     79.4
#>  4 cli_plain        95.13µs 100.57µs     9553.        0B     21.2
#>  5 fansi_plain      52.43µs  56.58µs    16873.      872B     21.5
#>  6 base_plain           1µs    1.1µs   871448.        0B      0  
#>  7 cli_vec_ansi    222.09µs 230.13µs     4250.   16.73KB     10.4
#>  8 fansi_vec_ansi  120.29µs 125.91µs     7508.    5.59KB     10.4
#>  9 base_vec_ansi    44.69µs   48.1µs    20567.      848B      0  
#> 10 cli_vec_plain   176.56µs 183.42µs     5240.   16.73KB     12.0
#> 11 fansi_vec_plain 116.62µs 119.81µs     8145.    5.59KB     12.5
#> 12 base_vec_plain   38.87µs  43.77µs    22632.      848B      0  
#> 13 cli_txt_ansi    103.45µs 107.25µs     9017.        0B     21.1
#> 14 fansi_txt_ansi   52.13µs  55.33µs    17378.      872B     21.2
#> 15 base_txt_ansi      1.1µs   1.18µs   810735.        0B     81.1
#> 16 cli_txt_plain    93.35µs  99.11µs     9825.        0B     21.1
#> 17 fansi_txt_plain  52.44µs  55.72µs    17410.      872B     23.5
#> 18 base_txt_plain    1.02µs   1.12µs   855682.        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        317.52µs 335.31µs    2937.         0B    19.1 
#>  2 fansi_ansi        94.9µs 100.69µs    9576.    97.33KB    21.1 
#>  3 base_ansi         37.4µs  39.29µs   24472.         0B    19.6 
#>  4 cli_plain       195.27µs 206.95µs    4649.         0B    18.8 
#>  5 fansi_plain      93.33µs  99.14µs    9802.       872B    21.0 
#>  6 base_plain       30.25µs  32.06µs   29971.         0B    21.0 
#>  7 cli_vec_ansi     33.98ms  34.29ms      29.2    2.48KB    52.5 
#>  8 fansi_vec_ansi  237.92µs 246.55µs    3987.     7.25KB    10.3 
#>  9 base_vec_ansi     2.18ms   2.24ms     441.    48.18KB    25.8 
#> 10 cli_vec_plain    20.33ms  20.45ms      48.7    2.48KB    29.2 
#> 11 fansi_vec_plain 197.84µs 205.13µs    4778.     6.42KB    12.5 
#> 12 base_vec_plain    1.61ms   1.66ms     597.     47.4KB    22.0 
#> 13 cli_txt_ansi     26.44ms  26.74ms      37.4  507.59KB    14.4 
#> 14 fansi_txt_ansi  228.19µs 236.51µs    4164.     6.77KB     8.21
#> 15 base_txt_ansi     1.24ms   1.29ms     763.   582.06KB    20.7 
#> 16 cli_txt_plain     1.22ms   1.26ms     783.   369.84KB    15.4 
#> 17 fansi_txt_plain 180.29µs 187.12µs    5194.     2.51KB    10.3 
#> 18 base_txt_plain  870.46µs 905.43µs    1086.   367.31KB    18.1

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.56µs    7.1µs   136059.   24.81KB    27.2 
#>  2 fansi_ansi       77.26µs  82.52µs    11561.   28.48KB    21.4 
#>  3 base_ansi       982.08ns   1.03µs   916176.        0B     0   
#>  4 cli_plain         6.52µs   7.14µs   136280.        0B    27.3 
#>  5 fansi_plain      77.89µs  81.97µs    11828.    1.98KB    21.3 
#>  6 base_plain      952.04ns      1µs   933592.        0B     0   
#>  7 cli_vec_ansi     27.14µs   28.5µs    34441.     1.7KB     6.89
#>  8 fansi_vec_ansi  112.86µs  118.2µs     8247.    8.86KB    14.9 
#>  9 base_vec_ansi      6.2µs    6.4µs   151953.      848B    15.2 
#> 10 cli_vec_plain    22.81µs  23.89µs    41093.     1.7KB     8.22
#> 11 fansi_vec_plain 106.89µs 113.22µs     8615.    8.86KB    14.9 
#> 12 base_vec_plain    5.99µs   6.07µs   161311.      848B     0   
#> 13 cli_txt_ansi      6.57µs   7.17µs   135125.        0B    40.5 
#> 14 fansi_txt_ansi   77.69µs  82.14µs    11840.    1.98KB    19.1 
#> 15 base_txt_ansi     6.39µs   6.46µs   151843.        0B    15.2 
#> 16 cli_txt_plain     7.31µs   7.78µs   125755.        0B    25.2 
#> 17 fansi_txt_plain  76.13µs  79.85µs    12144.    1.98KB    21.3 
#> 18 base_txt_plain    4.06µs   4.11µs   237452.        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       100.01µs 104.77µs    9252.    11.85KB    16.8 
#>  2 base_ansi        1.33µs   1.39µs  697864.         0B     0   
#>  3 cli_plain       80.82µs  84.97µs   11330.     8.73KB    14.6 
#>  4 base_plain       1.01µs   1.05µs  908132.         0B     0   
#>  5 cli_vec_ansi     3.95ms   4.03ms     248.   838.77KB    31.6 
#>  6 base_vec_ansi   79.27µs  79.64µs   12142.       848B     0   
#>  7 cli_vec_plain    2.23ms   2.31ms     427.    816.9KB    27.7 
#>  8 base_vec_plain  46.39µs   47.2µs   20919.       848B     0   
#>  9 cli_txt_ansi    14.66ms  14.79ms      67.5  114.42KB     6.53
#> 10 base_txt_ansi   78.98µs  80.36µs   12326.         0B     0   
#> 11 cli_txt_plain   264.3µs 271.77µs    3614.    18.16KB     4.05
#> 12 base_txt_plain  43.99µs  45.66µs   21736.         0B     2.17

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         71.9µs   75.7µs    12802.        0B    21.1 
#>  2 base_ansi          16µs     17µs    57024.        0B    22.8 
#>  3 cli_plain        71.6µs   75.4µs    12775.        0B    21.1 
#>  4 base_plain       15.9µs   16.9µs    57631.        0B    17.3 
#>  5 cli_vec_ansi    170.8µs  177.3µs     5514.     7.2KB    10.3 
#>  6 base_vec_ansi    56.2µs   61.2µs    15943.    1.66KB     6.11
#>  7 cli_vec_plain   157.2µs  163.2µs     5994.     7.2KB     8.21
#>  8 base_vec_plain   50.3µs   55.4µs    17693.    1.66KB     8.19
#>  9 cli_txt_ansi    147.6µs  152.3µs     6430.        0B    10.3 
#> 10 base_txt_ansi    40.2µs   41.4µs    23684.        0B     9.48
#> 11 cli_txt_plain   131.2µs  135.7µs     7218.        0B    10.2 
#> 12 base_txt_plain   34.7µs   35.7µs    27403.        0B    11.0

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          7.95µs   8.55µs   113462.        0B    34.0 
#> 2 base       852.04ns  902.1ns   818099.        0B     0   
#> 3 cli_vec     23.59µs  24.21µs    40491.      448B     8.10
#> 4 base_vec    11.53µs  11.71µs    84360.      448B     0   
#> 5 cli_txt     23.63µs  24.11µs    40774.        0B     8.16
#> 6 base_txt    12.49µs  12.56µs    78578.        0B     7.86
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          7.89µs   8.36µs   116963.        0B    23.4 
#> 2 base         1.27µs   1.34µs   722050.        0B     0   
#> 3 cli_vec     28.73µs  29.64µs    33076.      448B     9.93
#> 4 base_vec    50.95µs  51.44µs    19241.      448B     0   
#> 5 cli_txt     29.32µs  29.96µs    32849.        0B     6.57
#> 6 base_txt    86.64µs  87.22µs    11348.        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.27µs   8.77µs   111549.        0B    22.3 
#> 2 base       851.11ns  902.1ns  1054218.        0B     0   
#> 3 cli_vec     19.34µs  19.92µs    49303.      448B    14.8 
#> 4 base_vec    11.51µs   11.7µs    83927.      448B     0   
#> 5 cli_txt     19.93µs  20.59µs    46363.        0B     9.27
#> 6 base_txt    12.49µs  12.57µs    78064.        0B     7.81

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.11µs   6.48µs   150343.    22.1KB    30.1 
#> 2 base       991.04ns   1.04µs   913225.        0B     0   
#> 3 cli_vec     29.06µs  29.91µs    32897.     1.7KB     9.87
#> 4 base_vec     7.79µs   7.97µs   123124.      848B     0   
#> 5 cli_txt      6.09µs   6.54µs   147923.        0B    29.6 
#> 6 base_txt     5.39µs   5.45µs   178993.        0B    17.9

Session info

sessioninfo::session_info()
#> ─ Session info ──────────────────────────────────────────────────────
#>  setting  value
#>  version  R version 4.4.2 (2024-10-31)
#>  os       Ubuntu 24.04.1 LTS
#>  system   x86_64, linux-gnu
#>  ui       X11
#>  language en
#>  collate  C.UTF-8
#>  ctype    C.UTF-8
#>  tz       UTC
#>  date     2025-02-13
#>  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.4   2025-02-13 [1] local
#>  codetools     0.2-20  2024-03-31 [3] CRAN (R 4.4.2)
#>  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.5   2024-10-30 [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      1.8.9   2024-09-20 [1] RSPM
#>  knitr         1.49    2024-11-08 [1] RSPM
#>  lifecycle     1.0.4   2023-11-07 [1] RSPM
#>  magrittr      2.0.3   2022-03-30 [1] RSPM
#>  pillar        1.10.1  2025-01-07 [1] RSPM
#>  pkgconfig     2.0.3   2019-09-22 [1] RSPM
#>  pkgdown       2.1.1   2024-09-17 [1] any (@2.1.1)
#>  profmem       0.6.0   2020-12-13 [1] RSPM
#>  R6            2.6.0   2025-02-12 [1] RSPM
#>  ragg          1.3.3   2024-09-11 [1] RSPM
#>  rlang         1.1.5   2025-01-17 [1] RSPM
#>  rmarkdown     2.29    2024-11-04 [1] RSPM
#>  sass          0.4.9   2024-03-15 [1] RSPM
#>  sessioninfo   1.2.3   2025-02-05 [1] any (@1.2.3)
#>  systemfonts   1.2.1   2025-01-20 [1] RSPM
#>  textshaping   1.0.0   2025-01-20 [1] RSPM
#>  tibble        3.2.1   2023-03-20 [1] RSPM
#>  utf8          1.2.4   2023-10-22 [1] RSPM
#>  vctrs         0.6.5   2023-12-01 [1] RSPM
#>  xfun          0.50    2025-01-07 [1] RSPM
#>  yaml          2.3.10  2024-07-26 [1] RSPM
#> 
#>  [1] /home/runner/work/_temp/Library
#>  [2] /opt/R/4.4.2/lib/R/site-library
#>  [3] /opt/R/4.4.2/lib/R/library
#>  * ── Packages attached to the search path.
#> 
#> ─────────────────────────────────────────────────────────────────────