cli/0000755000176200001440000000000014753300402011017 5ustar liggesuserscli/tests/0000755000176200001440000000000014752736636012206 5ustar liggesuserscli/tests/testthat/0000755000176200001440000000000014753300402014021 5ustar liggesuserscli/tests/testthat/test-collapsing.R0000644000176200001440000001476114752735214017301 0ustar liggesusers start_app() on.exit(stop_app(), add = TRUE) test_that("collapsing without formatting, n>3", { expect_snapshot({ pkgs <- paste0("pkg", 1:5) cli_text("Packages: {pkgs}.") }) }) test_that("collapsing without formatting, n<3", { expect_snapshot({ pkgs <- paste0("pkg", 1:2) cli_text("Packages: {pkgs}.") }) }) test_that("collapsing with formatting", { expect_snapshot(local({ cli_div(theme = list(".pkg" = list(fmt = function(x) paste0(x, " (P)")))) pkgs <- paste0("pkg", 1:5) cli_text("Packages: {.pkg {pkgs}}.") })) }) test_that("collapsing with formatting, custom seps", { expect_snapshot(local({ cli_div(theme = list(div = list("vec-sep" = " ... "))) pkgs <- paste0("pkg", 1:5) cli_text("Packages: {.pkg {pkgs}}.") })) }) test_that("collapsing a cli_vec", { expect_snapshot({ pkgs <- cli_vec( paste0("pkg", 1:5), style = list("vec-sep" = " & ", "vec-last" = " & ") ) cli_text("Packages: {pkgs}.") }) }) test_that_cli(configs = c("plain", "ansi"), "collapsing a cli_vec with styling", { expect_snapshot(local({ cli_div(theme = list(body = list("vec-sep" = " ... "))) pkgs <- cli_vec( paste0("pkg", 1:5), style = list("vec-sep" = " & ", "vec-last" = " & ", color = "blue") ) cli_text("Packages: {pkgs}.") })) }) test_that("head", { v <- function(n, t = 5) { cli_vec( seq_len(n), style = list("vec-trunc-style" = "head", "vec-trunc" = t) ) } expect_snapshot({ cli_text("{v(0,1)}") cli_text("{v(1,1)}") cli_text("{v(2,1)}") cli_text("{v(3,1)}") cli_text("{v(4,1)}") cli_text("{v(0,2)}") cli_text("{v(1,2)}") cli_text("{v(2,2)}") cli_text("{v(3,2)}") cli_text("{v(4,2)}") cli_text("{v(0,3)}") cli_text("{v(1,3)}") cli_text("{v(2,3)}") cli_text("{v(3,3)}") cli_text("{v(4,3)}") cli_text("{v(0,4)}") cli_text("{v(1,4)}") cli_text("{v(2,4)}") cli_text("{v(3,4)}") cli_text("{v(4,4)}") cli_text("{v(0,5)}") cli_text("{v(1,5)}") cli_text("{v(2,5)}") cli_text("{v(3,5)}") cli_text("{v(4,5)}") cli_text("{v(10,5)}") }) }) test_that("both-ends", { v <- function(n, t = 5) { cli_vec( seq_len(n), style = list("vec-trunc-style" = "both-ends", "vec-trunc" = t) ) } expect_snapshot({ cli_text("{v(0,1)}") cli_text("{v(1,1)}") cli_text("{v(2,1)}") cli_text("{v(3,1)}") cli_text("{v(4,1)}") cli_text("{v(5,1)}") cli_text("{v(6,1)}") cli_text("{v(7,1)}") cli_text("{v(10,1)}") }) }) test_that_cli(configs = c("plain", "ansi"), "both-ends with formatting", { v <- function(n, t = 5) { cli_vec( seq_len(n), style = list("vec-trunc-style" = "both-ends", "vec-trunc" = t) ) } expect_snapshot({ cli_text("{.val {v(0,1)}}") cli_text("{.val {v(1,1)}}") cli_text("{.val {v(2,1)}}") cli_text("{.val {v(3,1)}}") cli_text("{.val {v(4,1)}}") cli_text("{.val {v(5,1)}}") cli_text("{.val {v(6,1)}}") cli_text("{.val {v(7,1)}}") cli_text("{.val {v(10,1)}}") cli_text("{.val {v(10,6)}}") cli_text("{.val {v(10,10)}}") cli_text("{.val {v(11,10)}}") }) }) test_that("ansi_collapse", { l10 <- letters[1:10] expect_snapshot({ ansi_collapse(l10) ansi_collapse(l10, trunc = 6) ansi_collapse(l10, trunc = 5) ansi_collapse(l10, trunc = 4) ansi_collapse(l10, trunc = 1) ansi_collapse(l10, sep = "; ") ansi_collapse(l10, sep = "; ", last = "; or ") ansi_collapse(l10, sep = "; ") ansi_collapse(l10, sep = "; ", last = "; or ", trunc = 6) ansi_collapse(l10, style = "head") ansi_collapse(l10, trunc = 6, style = "head") ansi_collapse(l10, trunc = 5, style = "head") ansi_collapse(l10, trunc = 4, style = "head") ansi_collapse(l10, trunc = 1, style = "head") ansi_collapse(l10, sep = "; ", style = "head") ansi_collapse(l10, sep = "; ", last = "; or ", style = "head") ansi_collapse(l10, sep = "; ", last = "; or ", trunc = 6, style = "head") }) }) test_that("ansi_collapse with width trimming", { l10 <- letters[1:10] expect_snapshot({ ansi_collapse(l10, width = 1, style = "head") ansi_collapse(l10, width = 2, style = "head") ansi_collapse(l10, width = 3, style = "head") ansi_collapse(l10, width = 4, style = "head") ansi_collapse(l10, width = 5, style = "head") ansi_collapse(l10, width = 6, style = "head") ansi_collapse(l10, width = 7, style = "head") ansi_collapse(l10, width = 8, style = "head") ansi_collapse(l10, width = 9, style = "head") ansi_collapse(l10, width = 30, style = "head") ansi_collapse(l10, width = 31, style = "head") ansi_collapse(l10, width = 32, style = "head") ansi_collapse(l10, width = 40, style = "head") }) expect_snapshot({ ansi_collapse(l10, width = 10, style = "both-ends") }) }) test_that("ansi_collapse produces consistent truncation results", { expect_equal(ansi_collapse(1:2, trunc = 1, style = "head"), ansi_collapse(1:2, trunc = 0, style = "head")) }) test_that("ansi_collapse uses `sep2` for length-two inputs", { expect_equal(ansi_collapse(1:2), "1 and 2") expect_equal(ansi_collapse(1:2, trunc = 2, style = "head"), "1 and 2") }) test_that("Avoid duplication of length 1 vecs when width set (#590)", { expect_equal(ansi_collapse(1), "1") expect_equal(ansi_collapse(1, style = "head"), "1") expect_equal(ansi_collapse(1, style = "head", width = 70), "1") expect_equal(ansi_collapse(1, style = "head", last = " and again "), "1") expect_equal(ansi_collapse(1, style = "head", width = 70, last = " and again "), "1") }) test_that("Issue #681", { # sep2 takes precedence expect_equal(ansi_collapse(1:2, sep2 = " and ", last = " or "), "1 and 2") expect_equal(ansi_collapse(1:2, sep2 = " xor ", last = " or "), "1 xor 2") # default for sep2 is last without the Oxford comma expect_equal(ansi_collapse(1:3, last = ", or "), "1, 2, or 3") expect_equal(ansi_collapse(1:2, last = ", or "), "1 or 2") expect_equal(ansi_collapse(1:2, last = " or "), "1 or 2") expect_snapshot({ v <- cli::cli_vec( c("foo", "bar", "foobar"), style = list("vec-last" = ", or ") ) cli::cli_text("Must be one of: {v}.") v <- cli::cli_vec( c("foo", "bar"), style = list("vec-last" = " or ") ) cli::cli_text("Must be one of: {v}.") v <- cli::cli_vec( c("foo", "bar"), style = list("vec-last" = " or ", "vec-sep2" = " xor ") ) cli::cli_text("Must be one of: {v}.") }) }) cli/tests/testthat/test-utils.R0000644000176200001440000001265714752735214016310 0ustar liggesusers test_that("is_windows", { expect_equal(is_windows(), .Platform$OS.type == "windows") }) test_that("make_space", { expect_equal(make_space(0), "") expect_equal(make_space(1), " ") expect_equal(make_space(5), " ") }) test_that("apply_style", { expect_error( apply_style("text", raw(0)), "must be a color name or an ANSI style function" ) expect_equal( apply_style("foo", function(x) toupper(x)), "FOO" ) withr::local_options(cli.num_ansi_colors = truecolor) expect_equal( apply_style("foo", "red"), col_red("foo") ) }) test_that("viapply", { expect_equal( viapply(c("foo", "foobar"), length), vapply(c("foo", "foobar"), length, integer(1)) ) expect_equal( viapply(character(), length), vapply(character(), length, integer(1)) ) }) test_that("ruler", { expect_snapshot( ruler(20) ) }) test_that("rpad", { expect_equal(rpad(character()), character()) expect_equal(rpad("foo"), "foo") expect_equal(rpad(c("foo", "foobar")), c("foo ", "foobar")) }) test_that("lpad", { expect_equal(lpad(character()), character()) expect_equal(lpad("foo"), "foo") expect_equal(lpad(c("foo", "foobar")), c(" foo", "foobar")) }) test_that("is_utf8_output", { local_mocked_bindings( l10n_info = function() list(MBCS = TRUE, `UTF-8` = TRUE, `Latin-1` = FALSE) ) withr::with_options( list(cli.unicode = NULL), expect_true(is_utf8_output()) ) local_mocked_bindings( l10n_info = function() list(MBCS = FALSE, `UTF-8` = FALSE, `Latin-1` = TRUE) ) withr::with_options( list(cli.unicode = NULL), expect_false(is_utf8_output()) ) }) test_that("is_latex_output", { local_mocked_bindings(loadedNamespaces = function() "foobar") expect_false(is_latex_output()) local_mocked_bindings( loadedNamespaces = function() "knitr", get = function(x, ...) { if (x == "is_latex_output") { function() TRUE } else { base::get(x, ...) } } ) expect_true(is_latex_output()) }) test_that("dedent", { cases <- list( list("", 0, ""), list("", 1, ""), list("", 2, ""), list("x", 0, "x"), list("x", 1, "x"), list("x", 2, "x"), list("xx", 0, "xx"), list("xx", 1, "xx"), list("xx", 2, "xx"), list("foobar", 0, "foobar"), list("foobar", 1, "foobar"), list("foobar", 2, "foobar"), list(" ", 0, " "), list(" ", 1, ""), list(" ", 2, ""), list(" ", 0, " "), list(" ", 1, " "), list(" ", 2, ""), list(" x", 0, " x"), list(" x", 1, "x"), list(" x", 2, "x"), list(" x", 0, " x"), list(" x", 1, " x"), list(" x", 2, "x"), list(" x y", 3, "x y"), list(" x y", 4, "x y"), list(" x y", 5, "x y"), list(" x ", 3, "x "), list(" x ", 4, "x "), list(" x ", 5, "x ") ) for (c in cases) expect_identical(dedent(c[[1]], c[[2]]), ansi_string(c[[3]])) }) test_that("tail_na", { cases <- list( list(1:4, 4L), list(1, 1), list(double(), NA_real_), list(character(), NA_character_) ) for (i in seq_along(cases)) { c <- cases[[i]] expect_identical(tail_na(c[[1]]), c[[2]], info = i) } cases2 <- list( list(1:4, 2, 3:4), list(1, 2, c(NA_real_, 1)), list(double(), 2, c(NA_real_, NA_real_)), list(character(), 2, c(NA_character_, NA_character_)) ) for (i in seq_along(cases2)) { c <- cases2[[i]] expect_identical(tail_na(c[[1]], c[[2]]), c[[3]], info = i) } }) test_that("get_ppid", { expect_equal( ps::ps_ppid(), get_ppid() ) }) test_that("na.omit", { expect_snapshot({ na.omit(character()) na.omit(integer()) na.omit(1:5) na.omit(c(1,NA,2,NA)) na.omit(c(NA_integer_, NA_integer_)) na.omit(list(1,2,3)) }) }) test_that("get_rstudio_theme", { local_mocked_bindings( getThemeInfo = function() function(...) warning("just a word"), .package = "rstudioapi" ) expect_silent(get_rstudio_theme()) }) test_that("try_silently", { expect_silent( try_silently(1:10) ) expect_s3_class( try_silently(stop("not this")), "error" ) }) test_that("str_trim", { expect_snapshot({ str_trim("foo") str_trim(character()) str_trim(" foo") str_trim("foo ") str_trim(" foo ") str_trim(c(NA_character_, " foo ", NA_character_, " bar ")) }) }) test_that("leading_space", { testthat::local_reproducible_output(unicode = TRUE) expect_snapshot({ paste0("-", leading_space("foo"), "-") paste0("-", leading_space(" foo"), "-") paste0("-", leading_space(" foo "), "-") paste0("-", leading_space(" \t foo "), "-") paste0("-", leading_space("\u00a0foo "), "-") paste0("-", leading_space(" \u00a0 foo "), "-") }) }) test_that("trailing_space", { testthat::local_reproducible_output(unicode = TRUE) expect_snapshot({ paste0("-", trailing_space("foo"), "-") paste0("-", trailing_space("foo "), "-") paste0("-", trailing_space(" foo "), "-") paste0("-", trailing_space(" foo \t "), "-") paste0("-", trailing_space(" foo\u00a0"), "-") paste0("-", trailing_space(" \u00a0 foo \u00a0 "), "-") }) }) test_that("abbrev", { expect_snapshot({ abbrev("123456789012345") abbrev("12345678901") abbrev("1234567890") abbrev("123456789") abbrev("12345") abbrev("1") abbrev("") abbrev("\033[31m1234567890\033[39m") abbrev(c("\033[31m1234567890\033[39m", "", "1234567890123"), 5) abbrev(rep("\033[31m1234567890\033[39m", 5), 5) }) }) cli/tests/testthat/test-text.R0000644000176200001440000000113714557444176016132 0ustar liggesusers start_app() on.exit(stop_app(), add = TRUE) test_that("text is wrapped", { withr::local_options(cli.width = 60) withr::local_rng_version("3.3.0") set.seed(42) expect_snapshot(local({ cli_div(class = "testcli", theme = test_style()) cli_h1("Header") cli_text(lorem_ipsum()) })) }) test_that("verbatim text is not wrapped", { cli_div(class = "testcli", theme = test_style()) withr::local_options(cli.width = 60) suppressMessages(cli_h1("Header")) txt <- strrep("1234567890 ", 20) out <- capt0(cli_verbatim(txt), strip_style = TRUE) expect_equal(out, paste0(txt, "\n")) }) cli/tests/testthat/progress-1.c0000644000176200001440000000414514557444176016216 0ustar liggesusers #include #include SEXP clitest__progress_crud(SEXP config) { SEXP bar = PROTECT(cli_progress_bar(10, config)); int i; for (i = 0; i < 10; i++) { if (CLI_SHOULD_TICK) cli_progress_set(bar, i + 1); } cli_progress_done(bar); UNPROTECT(1); return ScalarLogical(!Rf_isNull(bar)); } SEXP clitest__progress_sets() { SEXP bar = PROTECT(cli_progress_bar(10, NULL)); cli_progress_set_name(bar, "new name"); cli_progress_set_status(bar, "stats"); cli_progress_set_type(bar, "tasks"); cli_progress_set_format(bar, "{cli::pb_name}{cli::pb_status}{cli::pb_current}"); cli_progress_set_clear(bar, FALSE); int i; for (i = 0; i < 10; i++) { if (CLI_SHOULD_TICK) cli_progress_set(bar, i + 1); } cli_progress_done(bar); UNPROTECT(1); return ScalarLogical(!Rf_isNull(bar)); } SEXP clitest__progress_add() { SEXP bar = PROTECT(cli_progress_bar(10, NULL)); int i; for (i = 0; i < 10; i++) { cli_progress_add(bar, 1); } cli_progress_done(bar); UNPROTECT(1); return ScalarLogical(!Rf_isNull(bar)); } SEXP clitest__progress_num() { return ScalarInteger(cli_progress_num()); } SEXP clitest__progress_sleep(SEXP s, SEXP ns) { cli_progress_sleep(INTEGER(s)[0], INTEGER(ns)[0]); return R_NilValue; } SEXP clitest__progress_update() { SEXP bar = PROTECT(cli_progress_bar(10, NULL)); int i; for (i = 0; i < 10; i++) { cli_progress_update(bar, /* set= */ -1, /* inc= */ 1, /* force= */ 1); } cli_progress_done(bar); UNPROTECT(1); return ScalarLogical(!Rf_isNull(bar)); } SEXP clitest__progress_update2() { SEXP bar = PROTECT(cli_progress_bar(10, NULL)); int i; for (i = 0; i < 10; i++) { cli_progress_update(bar, /* set= */ i + 1, /* inc= */ 0, /* force= */ 1); } cli_progress_done(bar); UNPROTECT(1); return ScalarLogical(!Rf_isNull(bar)); } SEXP clitest__progress_update3() { SEXP bar = PROTECT(cli_progress_bar(10, NULL)); int i; for (i = 0; i < 10; i++) { cli_progress_update(bar, /* set= */ i + 1, /* inc= */ 0, /* force= */ 0); } cli_progress_done(bar); UNPROTECT(1); return ScalarLogical(!Rf_isNull(bar)); } cli/tests/testthat/test-suppress.R0000644000176200001440000000076314557444176017036 0ustar liggesusers test_that("suppress output", { if (getRversion() >= "4.0.0") { cnd <- NULL tryCatch( suppressMessages(cli_text("foo"), "cliMessage"), message = function(cnd2) cnd <<- cnd2 ) expect_null(cnd) } mysuppress <- function(expr) { withCallingHandlers( expr, cliMessage = function(msg) invokeRestart("muffleMessage") ) } cnd <- NULL tryCatch( mysuppress(cli_text("foo")), message = function(cnd2) cnd <<- cnd2 ) expect_null(cnd) }) cli/tests/testthat/test-type.R0000644000176200001440000000410514557444176016125 0ustar liggesusers test_that("type style", { expect_snapshot({ # objects cli_text("{.obj_type_friendly {mtcars}}") cli_text("{.obj_type_friendly {tibble::as_tibble(mtcars)}}") cli_text("{.obj_type_friendly {rlang::quo(1)}}") # matrices and arrays cli_text("{.obj_type_friendly {list()}}") cli_text("{.obj_type_friendly {matrix(list(1, 2))}}") cli_text("{.obj_type_friendly {array(list(1, 2, 3))}}") cli_text("{.obj_type_friendly {integer()}}") cli_text("{.obj_type_friendly {matrix(1:3)}}") cli_text("{.obj_type_friendly {array(1:3, dim = 1:3)}}") cli_text("{.obj_type_friendly {character()}}") cli_text("{.obj_type_friendly {matrix(letters)}}") cli_text("{.obj_type_friendly {array(letters[1:3], dim = 1:3)}}") # missing arguments # this does not actually work in {.obj_type_friendly} because of the eval rounds typename(quote(expr = )) # scalars cli_text("{.obj_type_friendly {NA}}") cli_text("{.obj_type_friendly {NA_integer_}}") cli_text("{.obj_type_friendly {NA_real_}}") cli_text("{.obj_type_friendly {NA_complex_}}") cli_text("{.obj_type_friendly {NA_character_}}") cli_text("{.obj_type_friendly {TRUE}}") cli_text("{.obj_type_friendly {FALSE}}") cli_text("{.obj_type_friendly {1L}}") cli_text("{.obj_type_friendly {1.0}}") cli_text("{.obj_type_friendly {1i}}") cli_text("{.obj_type_friendly {as.raw(1L)}}") cli_text("{.obj_type_friendly {'foo'}}") cli_text("{.obj_type_friendly {''}}") cli_text("{.obj_type_friendly {list(1)}}") cli_text("{.obj_type_friendly {matrix(NA)}}") cli_text("{.obj_type_friendly {matrix(1)}}") # empty vectors cli_text("{.obj_type_friendly {logical()}}") cli_text("{.obj_type_friendly {integer()}}") cli_text("{.obj_type_friendly {double()}}") cli_text("{.obj_type_friendly {complex()}}") cli_text("{.obj_type_friendly {character()}}") cli_text("{.obj_type_friendly {raw()}}") cli_text("{.obj_type_friendly {list()}}") # correct article cli_text("{.obj_type_friendly {structure(1, class = 'igraph')}}") }) }) cli/tests/testthat/test-spinners.R0000644000176200001440000000046714557444176017014 0ustar liggesusers test_that("get_spinner", { if (is_utf8_output()) { expect_equal(get_spinner()$name, "dots") } else { expect_equal(get_spinner()$name, "line") } }) test_that("list_spinners", { ls <- list_spinners() expect_true(is.character(ls)) expect_true("dots" %in% ls) expect_true("line" %in% ls) }) cli/tests/testthat/test-meta.R0000644000176200001440000000306214557444176016073 0ustar liggesusers start_app() on.exit(stop_app(), add = TRUE) test_that_cli("meta basics", { expect_snapshot( cli::cli({ message("This is before") cli_alert_info("First message") message("This as well") cli_alert_success("Success!") }) ) }) test_that_cli("meta is single cli_message", { msgs <- list() withCallingHandlers( cli::cli({ cli_alert_info("First message") cli_alert_success("Success!") }), cli_message = function(msg) { msgs <<- c(msgs, list(msg)) invokeRestart("cli_message_handled") } ) expect_equal(length(msgs), 1L) expect_snapshot(cli_server_default(msgs[[1]])) }) test_that_cli("meta is single cliMessage", { msgs <- list() expect_snapshot( withCallingHandlers( cli::cli({ cli_alert_info("First message") cli_alert_success("Success!") }), cliMessage = function(msg) { msgs <<- c(msgs, list(msg)) } ) ) expect_equal(length(msgs), 1L) }) test_that_cli("substitution", { expect_snapshot(local({ x <- 1:3 cli({ title <- "My title" cli_h1("Title: {.emph {title}}") cli_text("And {.emph some} more: {.val {x}}") }) })) }) test_that("return values are ok when recording (#496)", { expect_snapshot( cli::cli({ lid <- cli::cli_ul() cli::cli_li("a bullet") cli::cli_end(lid) }) ) }) test_that("nested cli() (#497)", { expect_snapshot( cli::cli({ cli::cli_h1("Header") cli::cli(cli::cli_text("Some text")) cli::cli_text("Some more text") }) ) }) cli/tests/testthat/test-progress-types.R0000644000176200001440000001030314752735214020140 0ustar liggesusers start_app() on.exit(stop_app(), add = TRUE) test_that("iterator", { withr::local_options( cli.dynamic = TRUE, cli.ansi = TRUE, cli.spinner = NULL, cli.spinner_unicode = NULL, cli.progress_format_iterator = NULL, cli.progress_format_iterator_nototal= NULL, cli.width = Inf ) fun <- function() { cli_progress_bar(type = "iterator", total = 100) cli_progress_update(set = 50, force = TRUE) } out <- fix_times(capture_cli_messages(fun())) expect_snapshot(out) fun <- function() { cli_progress_bar(type = "iterator", total = NA) cli_progress_update(set = 50, force = TRUE) } out <- fix_times(capture_cli_messages(fun())) expect_snapshot(out) }) test_that("tasks", { skip_on_cran() withr::local_options( cli.dynamic = TRUE, cli.ansi = TRUE, cli.spinner = NULL, cli.spinner_unicode = NULL, cli.progress_format_tasks = NULL, cli.progress_format_tasks_nototal= NULL, cli.width = Inf ) fun <- function() { cli_progress_bar(type = "tasks", total = 100) cli_progress_update(set = 50, force = TRUE) } out <- fix_times(capture_cli_messages(fun())) expect_snapshot(out) fun <- function() { cli_progress_bar(type = "tasks", total = NA) cli_progress_update(set = 50, force = TRUE) } out <- fix_times(capture_cli_messages(fun())) expect_snapshot(out) }) test_that("download", { withr::local_options( cli.dynamic = TRUE, cli.ansi = TRUE, cli.spinner = NULL, cli.spinner_unicode = NULL, cli.progress_format_download = NULL, cli.progress_format_download_nototal= NULL ) fun <- function() { cli_progress_bar(type = "download", total = 1024 * 1024) cli_progress_update(set = 52 * 1024, force = TRUE) } out <- fix_times(capture_cli_messages(fun())) expect_snapshot(out) fun <- function() { cli_progress_bar(type = "download", total = NA) cli_progress_update(set = 52 * 1024, force = TRUE) } out <- fix_times(capture_cli_messages(fun())) expect_snapshot(out) }) test_that("customize with options, iterator", { withr::local_options( cli.dynamic = TRUE, cli.ansi = TRUE, cli.progress_format_iterator = "new format {cli::pb_current}", cli.progress_format_iterator_nototal = NULL ) fun <- function(type, total, set = 50) { cli_progress_bar(type = type, total = total) cli_progress_update(set = set, force = TRUE) } expect_snapshot(capture_cli_messages(fun("iterator", 100))) expect_snapshot(capture_cli_messages(fun("iterator", NA))) withr::local_options( cli.progress_format_iterator_nototal = "new too {cli::pb_current}" ) expect_snapshot(capture_cli_messages(fun("iterator", 100))) expect_snapshot(capture_cli_messages(fun("iterator", NA))) }) test_that("customize with options, tasks", { withr::local_options( cli.dynamic = TRUE, cli.ansi = TRUE, cli.progress_format_tasks = "new format {cli::pb_current}", cli.progress_format_tasks_nototal = NULL ) fun <- function(type, total, set = 50) { cli_progress_bar(type = type, total = total) cli_progress_update(set = set, force = TRUE) } expect_snapshot(capture_cli_messages(fun("tasks", 100))) expect_snapshot(capture_cli_messages(fun("tasks", NA))) withr::local_options( cli.progress_format_tasks_nototal = "new too {cli::pb_current}" ) expect_snapshot(capture_cli_messages(fun("tasks", 100))) expect_snapshot(capture_cli_messages(fun("tasks", NA))) }) test_that("customize with options, download", { withr::local_options( cli.dynamic = TRUE, cli.ansi = TRUE, cli.progress_format_download = "new format {cli::pb_current_bytes}", cli.progress_format_download_nototal = NULL ) fun <- function(type, total, set = 50) { cli_progress_bar(type = type, total = total) cli_progress_update(set = set, force = TRUE) } expect_snapshot(capture_cli_messages(fun("download", 1024 * 1024, 512 * 1024))) expect_snapshot(capture_cli_messages(fun("download", NA, 512 * 1024))) withr::local_options( cli.progress_format_download_nototal = "new too {cli::pb_current_bytes}" ) expect_snapshot(capture_cli_messages(fun("download", 1024 * 1024, 512 * 1024))) expect_snapshot(capture_cli_messages(fun("download", NA, 512 * 1024))) }) cli/tests/testthat/test-progress-c.R0000644000176200001440000001025214557444176017230 0ustar liggesusers test_that("c api #1", { skip_on_cran() withr::local_options(cli.ansi = TRUE, cli.dynamic = TRUE) withr::local_options(cli.progress_handlers_only = "cli") dll <- make_c_function(test_path("progress-1.c"), linkingto = "cli") on.exit(dyn.unload(dll[["path"]]), add = TRUE) # simple crud out <- capture_cli_messages(cli_with_ticks( ret <- .Call(dll$clitest__progress_crud, NULL) )) out <- fix_times(out) expect_snapshot(out) # config can be FALSE out <- capture_cli_messages(cli_with_ticks( ret <- .Call(dll$clitest__progress_crud, FALSE) )) expect_false(ret) expect_equal(out, character()) # config can override defaults out <- capture_cli_messages(cli_with_ticks( ret <- .Call( dll$clitest__progress_crud, list(format = "{cli::pb_current}/{cli::pb_total}") ) )) expect_snapshot(out) # config must be a named list expect_error( .Call(dll$clitest__progress_crud, list(123)), "list elements must be named" ) expect_error( .Call(dll$clitest__progress_crud, 100L), "Unknown cli progress bar configuation" ) # config can be a progress bar name withr::local_options( cli.progress_format_iterator = "{cli::pb_name}{cli::pb_current}" ) out <- capture_cli_messages(cli_with_ticks( ret <- .Call(dll$clitest__progress_crud, "me llama") )) expect_snapshot(out) # set various options out <- capture_cli_messages(cli_with_ticks( ret <- .Call(dll$clitest__progress_sets) )) expect_snapshot(out) # cli_progress_add out <- capture_cli_messages(cli_with_ticks( ret <- .Call(dll$clitest__progress_add) )) expect_snapshot(out) # cli_progress_num before <- .Call(dll$clitest__progress_num) bar <- cli_progress_bar() after <- .Call(dll$clitest__progress_num) cli_progress_done() expect_true(before + 1 == after) # cli_progress_update out <- capture_cli_messages(cli_without_ticks( ret <- .Call(dll$clitest__progress_update) )) expect_snapshot(out) out <- capture_cli_messages(cli_without_ticks( ret <- .Call(dll$clitest__progress_update2) )) expect_snapshot(out) out <- capture_cli_messages(cli_with_ticks( ret <- .Call(dll$clitest__progress_update3) )) expect_snapshot(out) # C progress bars have ids withr::local_options(cli.progress_handlers_only = "logger") out <- capture.output(cli_with_ticks( ret <- .Call(dll$clitest__progress_crud, NULL) )) out <- fix_logger_output(out) expect_snapshot(out) # cli_progress_sleep tic <- .Call(clic_get_time) .Call(dll$clitest__progress_sleep, 0L, 100L * 1000L * 1000L) toc <- .Call(clic_get_time) expect_true(toc - tic > 0.05) # progress vars in format_done withr::local_options(cli.progress_handlers_only = "cli") out <- capture_cli_messages(cli_with_ticks( ret <- .Call( dll$clitest__progress_crud, list( format = "{cli::pb_current}/{cli::pb_total}", format_done = "Just did {cli::pb_current} step{?s}.", clear = FALSE ) ) )) expect_snapshot(out) }) test_that("c api #2", { skip_on_cran() dll <- make_c_function(test_path("progress-2.c"), linkingto = "cli") ret <- cli_with_ticks(.Call(dll$clitest__init_timer)) expect_equal(ret, c(0L, 1L)) }) test_that("clic__find_var", { x <- 10 expect_equal(.Call(clic__find_var, environment(), as.symbol("x")), 10) # not inherit env <- new.env(parent = environment()) expect_error( .Call(clic__find_var, env, as.symbol("x")), "Cannot find variable" ) expect_error( .Call(clic__find_var, environment(), as.symbol(basename(tempfile()))), "Cannot find variable" ) }) test_that("unloading stops the thread", { # It is important to skip this on CRAN, because in ASAN we do not # kill the tick thread on unload, because it triggers an ASAN crash, # which is similar to https://github.com/google/sanitizers/issues/1152 skip_on_cran() fun <- function() { before <- ps::ps_num_threads() library(cli) between <- ps::ps_num_threads() unloadNamespace("cli") after <- ps::ps_num_threads() list(before = before, between = between, after = after) } out <- callr::r(fun) expect_equal(out$between, out$before + 1L) expect_equal(out$after, out$between - 1L) }) cli/tests/testthat/test-inline.R0000644000176200001440000000336014557444176016424 0ustar liggesusers withr::local_envvar(CLI_NO_BUILTIN_THEME = "true") withr::local_options(cli.theme = NULL, cli.user_theme = NULL) start_app() on.exit(stop_app(), add = TRUE) test_that_cli(configs = c("plain", "ansi"), "inline classes", { classes <- c( "emph", "strong", "code", "pkg", "fun", "arg", "key", "file", "path", "email", "url", "var", "envvar", "cls") do <- function(class) { special_style <- structure( list( list(color = "cyan"), list(before = "<<<"), list(after =">>>")), names = c( paste0("span.", class), paste0("span.", class), paste0("span.", class) ) ) cli_div(theme = special_style) txt <- glue::glue("This is {. it} really", .open = "<", .close = ">") cli_text(txt) } expect_snapshot( invisible(lapply(classes, do)) ) }) test_that("{{ and }} can be used for comments", { expect_snapshot(local({ cli_text("Escaping {{ works") cli_text("Escaping }} works") cli_text("Escaping {{ and }} works") cli_text("Escaping {{{{ works") cli_text("Escaping }}}} works") cli_text("Escaping {{{{ and }} works") cli_text("Escaping {{{{ and }}}} works") cli_text("Escaping {{ and }}}} works") })) }) test_that("no glue substitution in expressions that evaluate to a string", { expect_snapshot(local({ msg <- "Message with special characters like } { }} {{" cli_text("{msg}") cli_text("{.emph {msg}}") })) }) test_that("S3 class is used for styling", { expect_snapshot(local({ cli_div( theme = list( div = list("class-map" = list("foo" = "bar")), ".bar" = list(before = "::")) ) obj <- structure("yep", class = "foo") cli_text("This is {obj}.") })) }) cli/tests/testthat/test-pluralization.R0000644000176200001440000001025014752735214020030 0ustar liggesusers start_app() on.exit(stop_app(), add = TRUE) test_that("simplest", { expect_snapshot({ for (n in 0:2) cli_text("{n} package{?s}") for (n in 0:2) print(pluralize("{n} package{?s}")) }) }) test_that("irregular", { expect_snapshot({ for (n in 0:2) cli_text("{n} dictionar{?y/ies}") for (n in 0:2) print(pluralize("{n} dictionar{?y/ies}")) }) }) test_that("multiple substitutions", { expect_snapshot({ for (n in 0:2) cli_text("{n} package{?s} {?is/are} ...") for (n in 0:2) print(pluralize("{n} package{?s} {?is/are} ...")) }) }) test_that("multiple quantities", { expect_snapshot({ for (m in 0:2) for (n in 0:2) cli_text("{m} package{?s} and {n} folder{?s}") for (m in 0:2) for (n in 0:2) print(pluralize("{m} package{?s} and {n} folder{?s}")) }) }) test_that("no()", { expect_snapshot({ for (n in 0:2) cli_text("{no(n)} package{?s}") for (n in 0:2) print(pluralize("{no(n)} package{?s}")) }) }) test_that("set qty() explicitly", { expect_snapshot({ for (n in 0:2) cli_text("{qty(n)}There {?is/are} {n} package{?s}") for (n in 0:2) print(pluralize("{qty(n)}There {?is/are} {n} package{?s}")) }) }) test_that("collapsing vectors", { expect_snapshot({ pkgs <- function(n) glue::glue("pkg{seq_len(n)}") for (n in 1:3) cli_text("The {pkgs(n)} package{?s}") for (n in 1:3) print(pluralize("The {pkgs(n)} package{?s}")) }) }) test_that("pluralization and style", { expect_snapshot({ special_style <- list(span.foo = list(before = "<", after = ">")) cli_div(theme = special_style) for (n in 0:2) cli_text("{n} {.foo package{?s}}") }) expect_snapshot({ pkgs <- function(n) glue::glue("pkg{seq_len(n)}") for (n in 1:3) cli_text("The {.foo {pkgs(n)}} package{?s}") }) }) test_that("post-processing", { expect_snapshot({ for (n in 0:2) cli_text("Package{?s}: {n}") }) expect_snapshot({ pkgs <- function(n) glue::glue("pkg{seq_len(n)}") for (n in 1:2) cli_text("Package{?s}: {pkgs(n)}") for (n in 1:2) print(pluralize("Package{?s}: {pkgs(n)}")) }) }) test_that("post-processing errors", { expect_error( cli_text("package{?s}"), "Cannot pluralize without a quantity" ) expect_error( pluralize("package{?s}"), "Cannot pluralize without a quantity" ) expect_error( cli_text("package{?s} {5} {10}"), "Multiple quantities for pluralization" ) expect_error( pluralize("package{?s} {5} {10}"), "Multiple quantities for pluralization" ) }) test_that("issue 158", { expect_snapshot({ print(pluralize("{0} word{?A/B/}")) print(pluralize("{1} word{?A/B/}")) print(pluralize("{9} word{?A/B/}")) }) }) test_that("Edge cases for pluralize() (#701)", { expect_snapshot({ # Should not be pluralized print(pluralize("{NA} file{?s} expected")) print(pluralize("{NA_character_} file{?s} expected")) # Should be pluralized print(pluralize("{NA_real_} file{?s} expected")) print(pluralize("{NA_integer_} file{?s} expected")) print(pluralize("{NaN} file{?s} expected")) print(pluralize("{Inf} file{?s} expected")) print(pluralize("{-Inf} file{?s} expected")) }) expect_snapshot({ # Should not be pluralized print(pluralize("Found {NA} director{?y/ies}.")) print(pluralize("Found {NA_character_} director{?y/ies}.")) # Should be pluralized print(pluralize("Found {NA_real_} director{?y/ies}.")) print(pluralize("Found {NA_integer_} director{?y/ies}.")) print(pluralize("Found {NaN} director{?y/ies}.")) print(pluralize("Found {Inf} director{?y/ies}.")) print(pluralize("Found {-Inf} director{?y/ies}.")) }) expect_snapshot({ # Should not be pluralized print(pluralize("Will remove {?no/the/the} {NA} package{?s}.")) print(pluralize("Will remove {?no/the/the} {NA_character_} package{?s}.")) # Should be pluralized print(pluralize("Will remove {?no/the/the} {NA_real_} package{?s}.")) print(pluralize("Will remove {?no/the/the} {NA_integer_} package{?s}.")) print(pluralize("Will remove {?no/the/the} {NaN} package{?s}.")) print(pluralize("Will remove {?no/the/the} {Inf} package{?s}.")) print(pluralize("Will remove {?no/the/the} {-Inf} package{?s}.")) }) }) cli/tests/testthat/test-code.R0000644000176200001440000000020014602231453016025 0ustar liggesusers start_app() on.exit(stop_app(), add = TRUE) test_that_cli("issue #154", { expect_snapshot({ cli_code("a\nb\nc") }) }) cli/tests/testthat/test-utf8.R0000644000176200001440000000466214557444176016042 0ustar liggesusers # We need an UTF-8 platform or a recent R version on Windows utf8 <- l10n_info()$`UTF-8` newwin <- .Platform$OS.type == "windows" && getRversion() >= "4.0.0" if (!utf8 && !newwin) return() test_that("UTF-8 output on Windows", { skip_on_cran() skip_on_covr() out <- r_utf8(function() { library(cli) options(cli.unicode = TRUE) options(cli.num_colors = 1) options(cli.width = 70) options(cli.dynamic = FALSE) Sys.setenv(RSTUDIO = NA) s1 <- "\u30DE\u30EB\u30C1\u30D0\u30A4\u30C8\u306E\u30BF\u30A4\u30C8\u30EB" s2 <- "\u00e1rv\u00edzt\u0171r\u0151 t\u00fck\u00f6rf\u00far\u00f3g\u00e9p" cli_h1("Alerts") cli_alert(s1) cli_alert_danger(s2) cli_alert_info(s1) cli_alert_success(s1) cli_alert_warning(s1) cli_h1("Block quote") cli_blockquote(s1, s2) cli_h1("Bullets") cli_bullets(c("*" = s1, "!" = s2)) cli_h1("Code") cli_code(c(s1, s2)) cli_h1("Lists") cli_dl(c(s1 = s1, s2 = s2)) cli_ol(c(s1, s2)) cli_ul(c(s1, s2)) cli_h1("Headers") cli_h1(s1) cli_h2(s2) cli_h3(s1) cli_h1("Progress bars") cli_progress_step(s1) cli_progress_step(s2) cli_progress_done() cli_h1("Text") idx <- c(1L, 2L, 1L, 2L, 1L, 1L, 1L, 1L, 2L, 1L, 2L, 1L, 1L, 1L, 1L) cli_text(paste(c(s1, s2)[idx], collapse = " ")) cli_h1("Verbatim") cli_verbatim(c(s1, s2)) }) out$stdout <- gsub("\\[[.0-9]+m?s\\]", "[1s]", out$stdout) tmp <- tempfile(fileext = ".txt") writeBin(charToRaw(out$stdout), tmp) expect_snapshot_file(tmp, name = "utf8-output.txt") }) test_that("utf8_graphemes", { expect_equal(utf8_graphemes(character()), list()) expect_equal(utf8_graphemes(""), list(character())) str <- c( NA, "", "alpha", "\U0001f477\U0001f3ff\u200d\u2640\ufe0f", "\U0001f477\U0001f3ff", "\U0001f477\u200d\u2640\ufe0f", "\U0001f477\U0001f3fb", "\U0001f477\U0001f3ff" ) exp <- list( NA_character_, character(), c("a", "l", "p", "h", "a"), "\U0001f477\U0001f3ff\u200d\u2640\ufe0f", "\U0001f477\U0001f3ff", "\U0001f477\u200d\u2640\ufe0f", "\U0001f477\U0001f3fb", "\U0001f477\U0001f3ff" ) expect_equal(utf8_graphemes(str), exp) str2 <- paste0(na.omit(str), collapse = "") exp2 <- list(na.omit(unlist(exp))) expect_equal(utf8_graphemes(str2), exp2) }) test_that("errors", { expect_snapshot_error( fix_r_utf8_output("\x02\xff\xfe \x03\xff\xfe \x03\xff\xfe") ) }) cli/tests/testthat/test-cliapp-output.R0000644000176200001440000001032314557444176017751 0ustar liggesusers start_app() on.exit(stop_app(), add = TRUE) test_that("cliapp output auto", { skip_on_cran() txt <- "Stay calm. This is a test." script <- tempfile(fileext = ".R") on.exit(unlink(script, recursive = TRUE), add = TRUE) # stderr if not interactive ---------------- code <- substitute(env = list(txt = txt), { options(rlib_interactive = FALSE, cli.num_colors = 1L) cli::cli_text(txt) }) cat(deparse(code), file = script, sep = "\n") out <- callr::rscript(script, show = FALSE, fail_on_status = FALSE) expect_true(out$stderr %in% paste0(txt, c("\n", "\r\n"))) expect_equal(out$stdout, "") # stdout if interactive -------------------- code <- substitute(env = list(txt = txt), { options(rlib_interactive = TRUE, cli.num_colors = 1L) cli::cli_text(txt) }) cat(deparse(code), file = script, sep = "\n") out <- callr::rscript(script, show = FALSE, fail_on_status = FALSE) expect_true(out$stdout %in% paste0(txt, c("\n", "\r\n"))) expect_equal(out$stderr, "") # choose explicitly ----------------------- txt2 <- "Don't move" code <- substitute(env = list(txt = txt, txt2 = txt2), { options(rlib_interactive = FALSE, cli_num_colors = 1L) cli::start_app(output = "stderr") cli::cli_text(txt) cli::stop_app() options(rlib_interactive = TRUE) cli::start_app(output = "stdout") cli::cli_text(txt2) cli::stop_app() }) cat(deparse(code), file = script, sep = "\n") out <- callr::rscript(script, show = FALSE, fail_on_status = FALSE) expect_true(out$stderr %in% paste0(txt, c("\n", "\r\n"))) expect_true(out$stdout %in% paste0(txt2, c("\n", "\r\n"))) }) test_that("can also use a connection", { skip_on_cran() txt <- "Stay calm. This is a test." script <- tempfile(fileext = ".R") on.exit(unlink(script, recursive = TRUE), add = TRUE) code <- substitute(env = list(txt = txt), { options(cli.num_colors = 1L) con <- textConnection(NULL, open = "w", local = TRUE) cli::start_app(output = con) cli::cli_text(txt) cli::stop_app() flush(con) cat("output:", textConnectionValue(con), "\n", sep = "") }) cat(deparse(code), file = script, sep = "\n") out <- callr::rscript(script, show = FALSE, fail_on_status = FALSE) expect_true(out$stdout %in% paste0("output:", txt, c("\n", "\r\n"))) expect_equal(out$stderr, "") }) test_that("message if there is a sink", { # if there is an output sink, non-interactive msgs <- NULL tmp <- NULL fun <- function() { sink(tmp <<- tempfile()) on.exit(sink(NULL), add = TRUE) cli_text("Hola") } withCallingHandlers( fun(), cliMessage = function(m) { msgs <<- c(msgs, list(m)) invokeRestart("muffleMessage") } ) expect_equal(msgs[[1]]$message, "Hola\n") expect_equal(length(readLines(tmp)), 0) # if there is a message sink, non-interactive msgs <- NULL tmp <- tempfile() con <- file(tmp, open = "w+") fun <- function() { sink(con, type = "message") on.exit(sink(NULL, type = "message"), add = TRUE) cat("this\n", file = stderr()) cli_text("Hola") } withCallingHandlers( fun(), cliMessage = function(m) { msgs <<- c(msgs, list(m)) invokeRestart("muffleMessage") } ) expect_equal(msgs[[1]]$message, "Hola\n") expect_equal(readLines(tmp), "this") withr::local_options(rlib_interactive = TRUE) # if there is an output sink, interactive msgs <- NULL tmp <- NULL fun <- function() { sink(tmp <<- tempfile()) on.exit(sink(NULL), add = TRUE) cli_text("Hola") } withCallingHandlers( fun(), cliMessage = function(m) { msgs <<- c(msgs, list(m)) invokeRestart("muffleMessage") } ) expect_equal(msgs[[1]]$message, "Hola\n") expect_equal(length(readLines(tmp)), 0) # if there is a message sink, interactive msgs <- NULL tmp <- tempfile() con <- file(tmp, open = "w+") fun <- function() { sink(con, type = "message") on.exit(sink(NULL, type = "message"), add = TRUE) cat("this\n", file = stderr()) cli_text("Hola") } withCallingHandlers( fun(), cliMessage = function(m) { msgs <<- c(msgs, list(m)) invokeRestart("muffleMessage") } ) expect_equal(msgs[[1]]$message, "Hola\n") expect_equal(readLines(tmp), "this") }) cli/tests/testthat/test-tree.R0000644000176200001440000000610314557444176016103 0ustar liggesusers test_that_cli("tree", { data <- data.frame( stringsAsFactors = FALSE, package = c("processx", "backports", "assertthat", "Matrix", "magrittr", "rprojroot", "clisymbols", "prettyunits", "withr", "desc", "igraph", "R6", "crayon", "debugme", "digest", "irlba", "rcmdcheck", "callr", "pkgconfig", "lattice"), dependencies = I(list( c("assertthat", "crayon", "debugme", "R6"), character(0), character(0), "lattice", character(0), "backports", character(0), c("magrittr", "assertthat"), character(0), c("assertthat", "R6", "crayon", "rprojroot"), c("irlba", "magrittr", "Matrix", "pkgconfig"), character(0), character(0), "crayon", character(0), "Matrix", c("callr", "clisymbols", "crayon", "desc", "digest", "prettyunits", "R6", "rprojroot", "withr"), c("processx", "R6"), character(0), character(0) )) ) expect_snapshot(tree(data)) expect_snapshot(tree(data, root = "desc")) # Check that trees with apparent circularity error nicely data <- data.frame( stringsAsFactors = FALSE, X = c("a", "b", "c","d", "e", "f", "g", "h", "j"), Y = I(list( c("b", "e", "f"), c("d", "g"), character(0), c("a", "h"), character(0), character(0), character(0), c("j"), character(0) )) ) expect_warning(tree(data), "Endless loop found in tree: a -> b -> d -> a") }) test_that_cli("trimming", { pkgdeps <- list( "dplyr@0.8.3" = c("assertthat@0.2.1", "glue@1.3.1", "magrittr@1.5", "R6@2.4.0", "Rcpp@1.0.2", "rlang@0.4.0", "tibble@2.1.3", "tidyselect@0.2.5"), "assertthat@0.2.1" = character(), "glue@1.3.1" = character(), "magrittr@1.5" = character(), "pkgconfig@2.0.3" = character(), "R6@2.4.0" = character(), "Rcpp@1.0.2" = character(), "rlang@0.4.0" = character(), "tibble@2.1.3" = c("cli@1.1.0", "crayon@1.3.4", "fansi@0.4.0", "pillar@1.4.2", "pkgconfig@2.0.3", "rlang@0.4.0"), "cli@1.1.0" = c("assertthat@0.2.1", "crayon@1.3.4"), "crayon@1.3.4" = character(), "fansi@0.4.0" = character(), "pillar@1.4.2" = c("cli@1.1.0", "crayon@1.3.4", "fansi@0.4.0", "rlang@0.4.0", "utf8@1.1.4", "vctrs@0.2.0"), "utf8@1.1.4" = character(), "vctrs@0.2.0" = c("backports@1.1.5", "ellipsis@0.3.0", "digest@0.6.21", "glue@1.3.1", "rlang@0.4.0", "zeallot@0.1.0"), "backports@1.1.5" = character(), "ellipsis@0.3.0" = c("rlang@0.4.0"), "digest@0.6.21" = character(), "glue@1.3.1" = character(), "zeallot@0.1.0" = character(), "tidyselect@0.2.5" = c("glue@1.3.1", "purrr@1.3.1", "rlang@0.4.0", "Rcpp@1.0.2"), "purrr@0.3.3" = c("magrittr@1.5", "rlang@0.4.0") ) pkgs <- data.frame( stringsAsFactors = FALSE, name = names(pkgdeps), deps = I(unname(pkgdeps)) ) pkgs$label <- pkgs$name pkgs$trimmed <- paste(pkgs$name, " (trimmed)") expect_snapshot(tree(pkgs, trim = TRUE)) }) test_that("no warning for tibbles", { data <- tibble::tibble( package = c("A", "B", "C"), dependencies = c("B", "C", "") ) expect_silent(cli::tree(data)) }) cli/tests/testthat/test-cat-helpers.R0000644000176200001440000000226214557444176017355 0ustar liggesusers test_that("cat_line", { expect_snapshot( cat_line("This is ", "a ", "line of text.") ) tmp <- tempfile() on.exit(unlink(tmp), add = TRUE) cat_line("This is ", "a ", "line of text.", file = tmp) exp <- "This is a line of text." expect_equal(readLines(tmp, warn = FALSE), exp) local_reproducible_output(crayon = TRUE) expect_snapshot({ cat_line("This is ", "a ", "line of text.", col = "red") cat_line("This is ", "a ", "line of text.", background_col = "green") }) }) test_that_cli(configs = c("plain", "unicode"), "cat_bullet", { expect_snapshot({ cat_bullet(letters[1:5]) }) }) test_that_cli(configs = c("plain", "unicode"), "cat_boxx", { expect_snapshot({ cat_boxx("foo") }) }) test_that_cli(configs = c("plain", "unicode"), "cat_rule", { expect_snapshot(local({ withr::local_options(cli.width = 20) cat_rule("title") })) }) test_that_cli(configs = c("plain", "unicode"), "cat_print", { expect_snapshot({ cat_print(boxx("")) }) expect_snapshot(local({ tmp <- tempfile() on.exit(unlink(tmp), add = TRUE) expect_silent(cat_print(boxx(""), file = tmp)) cat(readLines(tmp, warn = FALSE), sep = "\n") })) }) cli/tests/testthat/test-lists.R0000644000176200001440000001247314557444176016311 0ustar liggesusers start_app() on.exit(stop_app(), add = TRUE) test_that_cli(configs = c("plain", "unicode"), "ul", { expect_snapshot(local({ lid <- cli_ul() cli_li("foo") cli_li(c("bar", "foobar")) cli_end(lid) })) }) test_that_cli(configs = c("plain", "unicode"), "ol", { expect_snapshot(local({ cli_div(theme = list(ol = list())) lid <- cli_ol() cli_li("foo") cli_li(c("bar", "foobar")) cli_end(lid) })) }) test_that_cli(configs = c("plain", "unicode"), "ul ul", { expect_snapshot(local({ cli_div( theme = list( "ul ul" = list("list-style-type" = "-", "margin-left" = 2) ) ) lid <- cli_ul() cli_li("1") lid2 <- cli_ul() cli_li("1 1") cli_li(c("1 2", "1 3")) cli_end(lid2) cli_li("2") cli_end(lid) })) }) test_that_cli(configs = c("plain", "unicode"), "ul ol", { expect_snapshot(local({ cli_div( theme = list( li = list("margin-left" = 2) ) ) lid <- cli_ul() cli_li("1") lid2 <- cli_ol() cli_li("1 1") cli_li(c("1 2", "1 3")) cli_end(lid2) cli_li("2") cli_end(lid) })) }) test_that_cli(configs = c("plain", "unicode"), "ol ol", { expect_snapshot(local({ cli_div( theme = list( "li" = list("margin-left" = 2), "li li" = list("margin-left" = 2) ) ) lid <- cli_ol() cli_li("1") lid2 <- cli_ol() cli_li("1 1") cli_li(c("1 2", "1 3")) cli_end(lid2) cli_li("2") cli_end(lid) })) }) test_that_cli(configs = c("plain", "unicode"), "ol ul", { expect_snapshot(local({ cli_div( theme = list( ul = list("margin-left" = 2) ) ) lid <- cli_ol() cli_li("1") lid2 <- cli_ul() cli_li("1 1") cli_li(c("1 2", "1 3")) cli_end(lid2) cli_li("2") cli_end(lid) })) }) test_that_cli(configs = c("plain", "unicode"), "starting with an item", { expect_snapshot(local({ cli_li("foo") cli_li(c("bar", "foobar")) cli_end() cli_end() })) }) test_that_cli(configs = c("plain", "unicode"), "ol, with first item", { expect_snapshot(local({ cli_div(theme = list(ol = list())) lid <- cli_ol("foo", .close = FALSE) cli_li(c("bar", "foobar")) cli_end(lid) })) }) test_that_cli(configs = c("plain", "unicode"), "ul, with first item", { expect_snapshot(local({ lid <- cli_ul("foo", .close = FALSE) cli_li(c("bar", "foobar")) cli_end(lid) })) }) test_that_cli(configs = c("plain", "unicode"), "dl", { expect_snapshot(local({ cli_div(theme = list(ul = list())) lid <- cli_dl() cli_li(c(this = "foo")) cli_li(c(that = "bar", other = "foobar")) cli_end(lid) })) }) test_that_cli(configs = c("plain", "unicode"), "dl dl", { expect_snapshot(local({ cli_div( theme = list( li = list("margin-left" = 2) ) ) lid <- cli_dl() cli_li(c(a = "1")) lid2 <- cli_dl() cli_li(c("a-a" = "1 1")) cli_li(c("a-b" = "1 2", "a-c" = "1 3")) cli_end(lid2) cli_li(c(b = "2")) cli_end(lid) })) }) test_that_cli(configs = c("plain", "unicode"), "dl ol", { expect_snapshot(local({ cli_div( theme = list( li = list("margin-left" = 2) ) ) lid <- cli_dl() cli_li(c(a = "1")) lid2 <- cli_ol() cli_li(c("1 1")) cli_li(c("1 2", "1 3")) cli_end(lid2) cli_li(c(b = "2")) cli_end(lid) })) }) test_that_cli(configs = c("plain", "unicode"), "dl ul", { expect_snapshot(local({ cli_div( theme = list( li = list("margin-left" = 2) ) ) lid <- cli_dl() cli_li(c(a = "1")) lid2 <- cli_ul() cli_li(c("1 1")) cli_li(c("1 2", "1 3")) cli_end(lid2) cli_li(c(b = "2")) cli_end(lid) })) }) test_that_cli(configs = c("plain", "unicode"), "ol dl", { expect_snapshot(local({ cli_div( theme = list( li = list("margin-left" = 2) ) ) lid <- cli_ol() cli_li("1") lid2 <- cli_dl() cli_li(c("a-a" = "1 1")) cli_li(c("a-b" = "1 2", "a-c" = "1 3")) cli_end(lid2) cli_li("2") cli_end(lid) })) }) test_that_cli(configs = c("plain", "unicode"), "ul dl", { expect_snapshot(local({ cli_div( theme = list( li = list("margin-left" = 2) ) ) lid <- cli_ul() cli_li("1") lid2 <- cli_dl() cli_li(c("a-a" = "1 1")) cli_li(c("a-b" = "1 2", "a-c" = "1 3")) cli_end(lid2) cli_li("2") cli_end(lid) })) }) test_that_cli(configs = c("plain", "unicode"), "dl, with first item", { expect_snapshot(local({ cli_div(theme = list(ul = list())) lid <- cli_dl(c(this = "foo"), .close = FALSE) cli_li(c(that = "bar", other = "foobar")) cli_end(lid) })) }) test_that_cli(configs = "ansi", "styling pieces of a dl", { expect_snapshot(local({ cli_div( theme = list( .dt = list(postfix = " -> "), .dd = list(color = "blue") ) ) cli_dl(c(foo = "bar", bar = "baz")) })) }) test_that("cli_dl edge cases", { # invalid input expect_snapshot( error = TRUE, cli_dl("foo", "must be a named character vector") ) # empty dd expect_snapshot( cli_dl(c(abc = "foo", empty = "", def = "bar")) ) }) test_that("cli_dl label style", { expect_snapshot(local({ cli_dl(c( "{.code code}" = "{.code this is code too}", "{.str strin}" = "{.url https://x.com}" )) })) }) cli/tests/testthat/test-spark.R0000644000176200001440000000045714752735214016263 0ustar liggesusers test_that_cli(configs = c("plain", "unicode"), "spark_bar", { expect_snapshot({ spark_bar(seq(0, 1, length.out = 8)) spark_bar(c(0, NA, 0.5, NA, 1)) }) }) test_that_cli(configs = c("plain", "unicode"), "spark_line", { expect_snapshot({ spark_line(seq(0, 1, length.out = 10)) }) }) cli/tests/testthat/test-ansi-hyperlink.R0000644000176200001440000004007214752735214020075 0ustar liggesusers test_that("ansi_align", { txt0 <- "\033]8;;https://ex.com\007te\033]8;;\007" txt1 <- st_from_bel(txt0) txt <- paste0(txt0, txt1) space3 <- strrep(" ", 3) space6 <- strrep(" ", 6) expect_equal( ansi_align(txt, 10), ansi_string(paste0(txt, space6)) ) expect_equal( ansi_align(txt, 10, "center"), ansi_string(paste0(space3, txt, space3)) ) expect_equal( ansi_align(txt, 10, "right"), ansi_string(paste0(space6, txt)) ) }) test_that("ansi_chartr", { txt0 <- "1\033]8;;https://ex.com\007text\033]8;;\0072" txt1 <- st_from_bel(txt0) txt <- paste0(txt0, txt1) expect_equal( ansi_chartr("12x0", "34yo", txt), ansi_string(paste0( "3\033]8;;https://ex.com\007teyt\033]8;;\0074", st_from_bel("3\033]8;;https://ex.com\007teyt\033]8;;\0074") )) ) }) test_that("ansi_columns", { txt <- "\033]8;;https://ex.com\007text\033]8;;\007" expect_equal( ansi_strip(ansi_columns(rep(txt, 4), 10)), c("text text ", "text text ") ) }) test_that("ansi_has_any", { txt <- "1\033]8;;https://ex.com\007text\033]8;;\0072" expect_true(ansi_has_any(txt)) expect_true(ansi_has_any(txt, sgr = FALSE, csi = FALSE)) expect_false(ansi_has_any(txt, link = FALSE)) }) test_that("ansi_html", { txt <- paste0( "1", "\033[1m\033]8;;https://ex.com\007", "text", "\033]8;;\007", "\033[22m", "2" ) expect_equal( ansi_html(txt), paste0( "1", "", "", "text", "", "", "2" ) ) }) test_that("ansi_nchar", { cases <- list( list("\033]8;;https://ex.com\007text\033]8;;\007", 4), list("\033]8;x=1:y=2;https://ex.com\007text\033]8;;\007", 4), list("\033]8;;https://ex.com\007text\033]8;;\007", 4), list("\033[1m\033]8;;https://ex.com\007text\033]8;;\007\033[22m", 4) ) for (c in cases) { expect_equal(ansi_nchar(c[[1]]), c[[2]]) } }) test_that("ansi_regex", { cases <- c( "1\033]8;;https://ex.com\007text\033]8;;\0072", "1\033]8;x=1:y=2;https://ex.com\007text\033]8;;\0072", "1\033]8;;https://ex.com\007text\033]8;;\0072", "1\033[1m\033]8;;https://ex.com\007text\033]8;;\007\033[22m2" ) for (case in cases) { expect_equal(gsub(ansi_regex(), "", case, perl = TRUE), "1text2") } }) test_that("ansi_simplify", { txt <- "1\033[1m\033]8;;https://ex.com\007text\033]8;;\007\033[22m2" expect_equal( ansi_simplify(txt), ansi_string( "1\033]8;;https://ex.com\007\033[1mtext\033[22m\033]8;;\0072" ) ) }) test_that("ansi_strip", { cases <- c( "1\033]8;;https://ex.com\007text\033]8;;\0072", "1\033]8;x=1:y=2;https://ex.com\007text\033]8;;\0072", "1\033]8;;https://ex.com\007text\033]8;;\0072", "1\033[1m\033]8;;https://ex.com\007text\033]8;;\007\033[22m2" ) for (case in cases) { expect_equal(ansi_strip(case), "1text2") } txt <- "1\033[1m\033]8;;https://ex.com\007text\033]8;;\007\033[22m2" expect_equal( ansi_strip(txt, link = FALSE), "1\033]8;;https://ex.com\007text\033]8;;\0072" ) expect_equal( ansi_strip(txt, sgr = FALSE), "1\033[1mtext\033[22m2" ) }) test_that("ansi_strsplit", { txt <- "1\033]8;;https://ex.com\007te;xt\033]8;;\0072" expect_equal( ansi_strsplit(txt, ";"), list(ansi_string(c( "1\033]8;;https://ex.com\007te\033]8;;\007", "\033]8;;https://ex.com\007xt\033]8;;\0072" ))) ) }) test_that("ansi_strtrim", { txt <- "1\033]8;;https://ex.com\007text\033]8;;\0072" expect_equal( ansi_strtrim(txt, 6), ansi_string(txt) ) expect_equal( ansi_strtrim(txt, 4), ansi_string(paste0(ansi_substr(txt, 1, 1), "...")) ) }) test_that("ansi_strwrap", { txt <- "1\033]8;;https://ex.com\007text\033]8;;\0072" wrp <- ansi_strwrap(strrep(paste0(txt, " "), 10), 15) expect_equal( wrp, ansi_string(rep(paste0(txt, " ", txt), 5)) ) }) test_that("ansi_substr", { txt <- "1\033[1m\033]8;;https://ex.com\007text\033]8;;\007\033[22m2" cases <- list( list(1, 3, "1\033]8;;https://ex.com\007\033[1mte\033[22m\033]8;;\007"), list(4, 6, "\033]8;;https://ex.com\007\033[1mxt\033[22m\033]8;;\0072"), list(3, 4, "\033]8;;https://ex.com\007\033[1mex\033[22m\033]8;;\007"), list(1, 10, "1\033]8;;https://ex.com\007\033[1mtext\033[22m\033]8;;\0072") ) for (c in cases) { expect_equal(ansi_substr(txt, c[[1]], c[[2]]), ansi_string(c[[3]])) } }) test_that("ansi_substring", { txt <- "1\033[1m\033]8;;https://ex.com\007text\033]8;;\007\033[22m2" cases <- list( list(1, 3, "1\033]8;;https://ex.com\007\033[1mte\033[22m\033]8;;\007"), list(4, 6, "\033]8;;https://ex.com\007\033[1mxt\033[22m\033]8;;\0072"), list(3, 4, "\033]8;;https://ex.com\007\033[1mex\033[22m\033]8;;\007"), list(1, 10, "1\033]8;;https://ex.com\007\033[1mtext\033[22m\033]8;;\0072") ) for (c in cases) { expect_equal(ansi_substring(txt, c[[1]], c[[2]]), ansi_string(c[[3]])) } }) test_that("ansi_tolower", { txt <- "Pre\033]8;;https://ex.com\007tEXt\033]8;;\007PoST" expect_equal( ansi_tolower(txt), ansi_string("pre\033]8;;https://ex.com\007text\033]8;;\007post") ) }) test_that("ansi_toupper", { txt <- "Pre\033]8;;https://ex.com\007tEXt\033]8;;\007PoST" expect_equal( ansi_toupper(txt), ansi_string("PRE\033]8;;https://ex.com\007TEXT\033]8;;\007POST") ) }) test_that("ansi_trimws", { txt <- "1\033[1m\033]8;;https://ex.com\007text\033]8;;\007\033[22m2" expect_equal( ansi_trimws(paste0(" ", txt, " ")), ansi_simplify(txt) ) expect_equal( ansi_trimws(txt), ansi_string(txt) ) }) test_that("unknown hyperlink type", { expect_snapshot( error = TRUE, make_link("this", "foobar") ) }) test_that("iterm file links", { withr::local_envvar(R_CLI_HYPERLINK_STYLE = "iterm") withr::local_envvar(R_CLI_HYPERLINK_FILE_URL_FORMAT = NA_character_) withr::local_options(cli.hyperlink = TRUE) expect_snapshot({ cli::cli_text("{.file /path/to/file:10}") cli::cli_text("{.file /path/to/file:10:20}") }) }) test_that("rstudio links", { local_clean_cli_context() withr::local_envvar( RSTUDIO = "1", RSTUDIO_SESSION_PID = Sys.getpid(), RSTUDIO_CHILD_PROCESS_PANE = "build", RSTUDIO_CLI_HYPERLINKS = "1" ) withr::local_options( cli.hyperlink = TRUE, cli.hyperlink_help = TRUE, cli.hyperlink_run = TRUE, cli.hyperlink_vignette = TRUE ) expect_snapshot( cli::cli_text("{.fun pkg::fun}") ) expect_snapshot( cli::cli_text("{.help fun}") ) expect_snapshot( cli::cli_text("{.run package::func()}") ) expect_snapshot( cli::cli_text("{.vignette package::title}") ) expect_snapshot( cli::cli_text("{.topic pkg::topic}") ) }) test_that("ST hyperlinks", { withr::local_envvar(R_CLI_HYPERLINK_MODE = "posix") withr::local_options(cli.hyperlink = TRUE) expect_snapshot( cat(style_hyperlink("text", "https://example.com")) ) }) test_that("ansi_has_hyperlink_support", { local_clean_cli_context() # force with env var withr::with_envvar(list(R_CLI_HYPERLINKS = "true"), expect_true(ansi_has_hyperlink_support()) ) # if no ansi support, then no local_mocked_bindings(num_ansi_colors = function() 256L) expect_false(ansi_has_hyperlink_support()) # are we in rstudio with support? local_mocked_bindings( num_ansi_colors = function() 257L, rstudio_detect = function() list(type = "rstudio_console", hyperlink = TRUE) ) expect_true(ansi_has_hyperlink_support()) }) test_that("ansi_has_hyperlink_support 2", { local_clean_cli_context() local_mocked_bindings( num_ansi_colors = function() 256L, isatty = function(...) FALSE ) expect_false(ansi_has_hyperlink_support()) }) test_that("ansi_has_hyperlink_support 3", { local_clean_cli_context() local_mocked_bindings( num_ansi_colors = function() 256L, isatty = function(...) TRUE, is_windows = function() TRUE ) withr::local_envvar(WT_SESSION = "4c464723-f51f-4612-83f7-31e1c75abd83") expect_true(ansi_has_hyperlink_support()) }) test_that("ansi_has_hyperlink_support 4", { local_clean_cli_context() local_mocked_bindings( num_ansi_colors = function() 256L, isatty = function(...) TRUE ) withr::local_envvar("CI" = "true") expect_false(ansi_has_hyperlink_support()) withr::local_envvar("CI" = NA_character_, TEAMCITY_VERSION = "1") expect_false(ansi_has_hyperlink_support()) }) test_that("ansi_has_hyperlink_support 5", { local_clean_cli_context() local_mocked_bindings( num_ansi_colors = function() 256L, isatty = function(...) TRUE ) withr::local_envvar( TERM_PROGRAM = "iTerm.app", TERM_PROGRAM_VERSION = "3.4.16" ) expect_true(ansi_has_hyperlink_support()) }) test_that("ansi_has_hyperlink_support 5", { local_clean_cli_context() local_mocked_bindings( num_ansi_colors = function() 256L, isatty = function(...) TRUE ) withr::local_envvar(VTE_VERSION = "0.51.1") expect_true(ansi_has_hyperlink_support()) withr::local_envvar(VTE_VERSION = "5110") expect_true(ansi_has_hyperlink_support()) withr::local_envvar(VTE_VERSION = "foo") expect_false(ansi_has_hyperlink_support()) }) test_that("ansi_hyperlink_types", { local_clean_cli_context() withr::local_envvar( R_CLI_HYPERLINKS = "true", R_CLI_HYPERLINK_RUN = "true" ) expect_true(ansi_hyperlink_types()[["run"]]) }) test_that("get_config_chr() consults option, env var, then its default", { local_clean_cli_context() key <- "hyperlink_TYPE_url_format" expect_null(get_config_chr(key)) withr::local_envvar(R_CLI_HYPERLINK_TYPE_URL_FORMAT = "envvar") expect_equal(get_config_chr(key), "envvar") withr::local_options(cli.hyperlink_type_url_format = "option") expect_equal(get_config_chr(key), "option") }) test_that("get_config_chr() errors if option is not NULL or string", { withr::local_options(cli.something = FALSE) expect_error(get_config_chr("something"), "is_string") }) test_that("get_hyperlink_format() delivers custom format", { local_clean_cli_context() withr::local_options( cli.hyperlink_run = TRUE, cli.hyperlink_help = TRUE, cli.hyperlink_vignette = TRUE ) # env var is consulted after option, so start with env var withr::local_envvar( R_CLI_HYPERLINK_RUN_URL_FORMAT = "envvar{code}", R_CLI_HYPERLINK_HELP_URL_FORMAT = "envvar{topic}", R_CLI_HYPERLINK_VIGNETTE_URL_FORMAT = "envvar{vignette}" ) expect_equal(get_hyperlink_format("run"), "envvar{code}") expect_equal(get_hyperlink_format("help"), "envvar{topic}") expect_equal(get_hyperlink_format("vignette"), "envvar{vignette}") withr::local_options( cli.hyperlink_run_url_format = "option{code}", cli.hyperlink_help_url_format = "option{topic}", cli.hyperlink_vignette_url_format = "option{vignette}" ) expect_equal(get_hyperlink_format("run"), "option{code}") expect_equal(get_hyperlink_format("help"), "option{topic}") expect_equal(get_hyperlink_format("vignette"), "option{vignette}") }) test_that("parse_file_link_params(), typical input", { expect_equal( parse_file_link_params("some/path.ext"), list( path = "some/path.ext", line = NULL, column = NULL ) ) expect_equal( parse_file_link_params("some/path.ext:14"), list( path = "some/path.ext", line = "14", column = NULL ) ) expect_equal( parse_file_link_params("some/path.ext:14:23"), list( path = "some/path.ext", line = "14", column = "23" ) ) }) test_that("parse_file_link_params(), weird trailing colons", { expect_equal( parse_file_link_params("some/path.ext:"), list( path = "some/path.ext", line = NULL, column = NULL ) ) expect_equal( parse_file_link_params("some/path.ext::"), list( path = "some/path.ext", line = NULL, column = NULL ) ) expect_equal( parse_file_link_params("some/path.ext:14:"), list( path = "some/path.ext", line = "14", column = NULL ) ) }) test_that("interpolate_parts(), more or less data in `params`", { fmt <- "whatever/{path}#@${line}^&*{column}" params <- list(path = "some/path.ext", line = "14", column = "23") expect_equal( interpolate_parts(fmt, params), "whatever/some/path.ext#@$14^&*23" ) params <- list(path = "some/path.ext", line = "14", column = NULL) expect_equal( interpolate_parts(fmt, params), "whatever/some/path.ext#@$14" ) params <- list(path = "some/path.ext", line = NULL, column = NULL) expect_equal( interpolate_parts(fmt, params), "whatever/some/path.ext" ) }) test_that("interpolate_parts(), format only has `path`", { fmt <- "whatever/{path}" params <- list(path = "some/path.ext", line = "14", column = "23") expect_equal( interpolate_parts(fmt, params), "whatever/some/path.ext" ) }) test_that("construct_file_link() works with custom format and an absolute path", { withr::local_options( "cli.hyperlink_file_url_format" = "positron://file{path}:{line}:{column}" ) expect_equal( construct_file_link(list(path = "/absolute/path")), list(url = "positron://file/absolute/path") ) expect_equal( construct_file_link(list(path = "/absolute/path", line = "12")), list(url = "positron://file/absolute/path:12") ) expect_equal( construct_file_link(list(path = "/absolute/path", line = "12", column = "5")), list(url = "positron://file/absolute/path:12:5") ) local_mocked_bindings(is_windows = function() TRUE) expect_equal( construct_file_link(list(path = "c:/absolute/path")), list(url = "positron://file/c:/absolute/path") ) }) test_that("construct_file_link() works with custom format and a relative path", { withr::local_options( "cli.hyperlink_file_url_format" = "positron://file{path}:{line}:{column}" ) # inspired by test helpers `sanitize_wd()` and `sanitize_home()`, but these # don't prefix the pattern-to-replace with `file://` sanitize_dir <- function(x, what = c("wd", "home")) { what <- match.arg(what) pattern <- switch(what, wd = getwd(), home = path.expand("~")) if (is_windows()) { pattern <- paste0("/", pattern) } replacement <- switch(what, wd = "/working/directory", home = "/my/home") sub(pattern, replacement, x$url, fixed = TRUE) } expect_equal( sanitize_dir(construct_file_link(list(path = "relative/path")), what = "wd"), "positron://file/working/directory/relative/path" ) expect_equal( sanitize_dir(construct_file_link(list(path = "relative/path:12")), what = "wd"), "positron://file/working/directory/relative/path:12" ) expect_equal( sanitize_dir(construct_file_link(list(path = "relative/path:12:5")), what = "wd"), "positron://file/working/directory/relative/path:12:5" ) expect_equal( sanitize_dir(construct_file_link(list(path = "./relative/path")), what = "wd"), "positron://file/working/directory/./relative/path" ) expect_equal( sanitize_dir(construct_file_link(list(path = "./relative/path:12")), what = "wd"), "positron://file/working/directory/./relative/path:12" ) expect_equal( sanitize_dir(construct_file_link(list(path = "./relative/path:12:5")), what = "wd"), "positron://file/working/directory/./relative/path:12:5" ) expect_equal( sanitize_dir(construct_file_link(list(path = "~/relative/path")), what = "home"), "positron://file/my/home/relative/path" ) expect_equal( sanitize_dir(construct_file_link(list(path = "~/relative/path:17")), what = "home"), "positron://file/my/home/relative/path:17" ) expect_equal( sanitize_dir(construct_file_link(list(path = "~/relative/path:17:22")), what = "home"), "positron://file/my/home/relative/path:17:22" ) }) test_that("construct_file_link() works with custom format and input starting with 'file://'", { withr::local_options( "cli.hyperlink_file_url_format" = "positron://file{path}:{line}:{column}" ) expect_equal( construct_file_link(list(path = "file:///absolute/path")), list(url = "positron://file/absolute/path") ) expect_equal( construct_file_link(list(path = "file:///absolute/path", line = "12", column = "5")), list(url = "positron://file/absolute/path:12:5") ) }) cli/tests/testthat/test-prettycode.R0000644000176200001440000001401314752735214017316 0ustar liggesusers col_seq <- list(function(x) paste0("1", x), function(x) paste0("2", x), function(x) paste0("3", x)) test_that("bracket highlighting", { # [](){} expect_equal(color_brackets(c("[", "]", "(", ")", "{", "}"), col_seq), c("1[", "1]", "1(", "1)", "1{", "1}")) # [({[({})]})] expect_equal( color_brackets(c( "[", "(", "{", "[", "(", "{", "}", ")", "]", "}", ")", "]" ), col_seq), c( "1[", "2(", "3{", "1[", "2(", "3{", "3}", "2)", "1]", "3}", "2)", "1]" ) ) # [[ [] ]][[ ()() ]] expect_equal( color_brackets( c("[[", "[", "]", "]", "]", "[[", "(", ")", "(", ")", "]", "]"), col_seq ), c( "1[[", "2[", "2]", "1]", "1]", "1[[", "2(", "2)", "2(", "2)", "1]", "1]" ) ) }) test_that_cli(configs = c("plain", "ansi"), "reserved", { expect_snapshot({ cat(code_highlight("function () { }", list(reserved = "bold"))) cat(code_highlight("if (1) NULL else NULL", list(reserved = "bold"))) cat(code_highlight("repeat {}", list(reserved = "bold"))) cat(code_highlight("while (1) {}", list(reserved = "bold"))) cat(code_highlight("for (i in x) next", list(reserved = "bold"))) cat(code_highlight("for (i in x) break", list(reserved = "bold"))) }) }) test_that_cli(configs = c("plain", "ansi"), "number", { expect_snapshot({ cat(code_highlight("1 + 1.0 + -1 + 2L + Inf", list(number = "bold"))) cat(code_highlight( "NA + NA_real_ + NA_integer_ + NA_character_", list(number = "bold") )) cat(code_highlight("TRUE + FALSE", list(number = "bold"))) }) }) test_that_cli(configs = c("plain", "ansi"), "null", { expect_snapshot({ cat(code_highlight("NULL", list(null = "bold"))) }) }) test_that_cli(configs = c("plain", "ansi"), "operator", { expect_snapshot({ cat(code_highlight("~ ! 1 - 2 + 3:4 * 5 / 6 ^ 7", list(operator = "bold"))) cat(code_highlight( "? 1 %% 2 %+% 2 < 3 & 4 > 5 && 6 == 7 | 8 <= 9 || 10 >= 11", list(operator = "bold") )) cat(code_highlight( "a <- 10; 20 -> b; c = 30; a$b; a@b", list(operator = "bold") )) }) }) test_that_cli(configs = c("plain", "ansi"), "call", { expect_snapshot({ cat(code_highlight("ls(2)", list(call = "bold"))) }) }) test_that_cli(configs = c("plain", "ansi"), "string", { expect_snapshot({ cat(code_highlight("'s' + \"s\"", list(string = "bold"))) }) }) test_that_cli(configs = c("plain", "ansi"), "comment", { expect_snapshot({ cat(code_highlight(c("# COM", " ls() ## ANOT"), list(comment = "bold"))) }) }) test_that_cli(configs = c("plain", "ansi"), "bracket", { expect_snapshot({ cat(code_highlight("foo <- function(x){x}", list(bracket = list("bold")))) }) }) test_that("replace_in_place", { expect_equal( replace_in_place("1234567890", c(2, 6), c(5, 8), c("foobar", "xxx")), "1foobarxxx90" ) expect_equal( replace_in_place("1234567890", c(1, 5), c(6, 10), c("A", "B")), "AB" ) }) test_that("replace_in_place corner cases", { expect_equal( replace_in_place("foobar", integer(), integer(), character()), "foobar" ) expect_equal( replace_in_place("12345", 1L, 5L, "no!"), "no!" ) expect_equal( replace_in_place("12345", 1:5, 1:5, letters[1:5]), "abcde" ) }) test_that_cli(configs = c("plain", "ansi"), "parse errors", { expect_equal( code_highlight("not good!!!"), "not good!!!" ) cnd <- NULL withCallingHandlers( expect_equal( code_highlight("not good!!!"), "not good!!!" ), cli_parse_failure = function(e) cnd <<- e ) expect_s3_class(cnd, "cli_parse_failure") expect_s3_class(cnd, "condition") expect_equal(cnd$code, "not good!!!") }) test_that("code themes", { withr::local_options(cli.code_theme = "solarized_dark") expect_equal(code_theme_default()$reserved, "#859900") withr::local_options(cli.code_theme = NULL) withr::local_envvar(RSTUDIO = "0") withr::local_options(cli.code_theme_terminal = "solarized_light") expect_equal(code_theme_default()$reserved, "#859900") local_mocked_bindings( rstudio_detect = function() list(type = "rstudio_console") ) withr::local_options(cli.code_theme_rstudio = "Xcode") expect_equal(code_theme_default()$reserved, "#C800A4") withr::local_options(cli.code_theme_rstudio = NULL) skip_if_not_installed("rstudioapi") local_mocked_bindings(code_theme_default_rstudio = function() "foo") expect_equal(code_theme_default(), "foo") }) test_that("code themes 2", { withr::local_options(cli.code_theme = "nope!!") expect_warning(code_theme_default(), "Unknown cli code theme") withr::local_options(cli.code_theme = 111) expect_warning(code_theme_default(), "Invalid cli code theme") }) test_that("code_theme_default_rstudio", { local_mocked_bindings( get_rstudio_theme = function() list(editor = "Solarized Dark") ) expect_equal(code_theme_default_rstudio()$reserved, "#859900") local_mocked_bindings( get_rstudio_theme = function() list(editor = "Not really") ) expect_warning( cth <- code_theme_default_rstudio(), "cli does not know this RStudio theme" ) expect_equal(cth, code_theme_default_term()) }) test_that("code_theme_list", { expect_snapshot(code_theme_list()) }) test_that_cli(configs = "ansi", "new language features, raw strings", { if (getRversion() < "4.0.1") { expect_true(TRUE); return() } expect_snapshot( cat(code_highlight( '"old" + r"("new""")"', list(string = "bold", reserved = "italic") )) ) }) test_that_cli(configs = "ansi", "new language features, pipe", { if (getRversion() < "4.1.0") { expect_true(TRUE); return() } expect_snapshot( cat(code_highlight('dir() |> toupper()', list(operator = "bold"))) ) }) test_that_cli(configs = "ansi", "new language features, lambda functions", { if (getRversion() < "4.1.0") { expect_true(TRUE); return() } expect_snapshot( cat(code_highlight('\\(x) x * 2', list(reserved = "bold"))) ) }) cli/tests/testthat/test-rlang-errors.R0000644000176200001440000001031214752735214017547 0ustar liggesuserstest_that_cli("cli_abort", { withr::local_options(cli.theme_dark = FALSE) expect_snapshot(error = TRUE, local({ n <- "boo" cli_abort(c( "{.var n} must be a numeric vector", "x" = "You've supplied a {.cls {class(n)}} vector." )) })) expect_snapshot(error = TRUE, local({ len <- 26 idx <- 100 cli_abort(c( "Must index an existing element:", "i" = "There {?is/are} {len} element{?s}.", "x" = "You've tried to subset element {idx}." )) })) n <- "boo" err <- tryCatch( cli_abort(c( "{.var n} must be a numeric vector", "x" = "You've supplied a {.cls {class(n)}} vector." )), error = function(e) e ) expect_snapshot(c(err$message, err$body)) }) test_that_cli("cli_warn", { skip_if_not_installed("rlang", "1.0.0") withr::local_options(cli.theme_dark = FALSE) expect_snapshot({ n <- "boo" cli_warn(c( "{.var n} must be a numeric vector", "x" = "You've supplied a {.cls {class(n)}} vector." )) }) expect_snapshot(local({ len <- 26 idx <- 100 cli_warn(c( "Must index an existing element:", "i" = "There {?is/are} {len} element{?s}.", "x" = "You've tried to subset element {idx}." )) })) }) test_that_cli("cli_inform", { skip_if_not_installed("rlang", "1.0.0") withr::local_options(cli.ansi = FALSE) expect_snapshot({ n <- "boo" cli_inform(c( "{.var n} must be a numeric vector", "x" = "You've supplied a {.cls {class(n)}} vector." )) }) expect_snapshot(local({ len <- 26 idx <- 100 cli_inform(c( "Must index an existing element:", "i" = "There {?is/are} {len} element{?s}.", "x" = "You've tried to subset element {idx}." )) })) }) test_that("cli_abort width in RStudio", { # this is to fix breakage with new testthat withr::local_options(cli.condition_width = getOption("cli.width")) local_mocked_bindings(rstudio_detect = function() list(type = "rstudio_console")) withr::local_rng_version("3.5.0") set.seed(42) expect_snapshot(error = TRUE, local({ len <- 26 idx <- 100 cli_abort(c( lorem_ipsum(1, 3), "i" = lorem_ipsum(1, 3), "x" = lorem_ipsum(1, 3) )) })) }) test_that_cli(configs = "ansi", "color in RStudio", { local_mocked_bindings( rstudio_detect = function() list(type = "rstudio_console", num_colors = 256), get_rstudio_theme = function() list(foreground = "rgb(0, 0, 0)") ) expect_snapshot({ col <- get_rstudio_fg_color0() cat(col("this is the new color")) }) local_mocked_bindings(get_rstudio_theme = function() list()) expect_null(get_rstudio_fg_color0()) local_mocked_bindings( rstudio_detect = function() list(type = "rstudio_console", num_colors = 1) ) expect_null(get_rstudio_fg_color0()) }) test_that_cli(configs = "ansi", "update_rstudio_color", { local_mocked_bindings( get_rstudio_fg_color = function() make_ansi_style("#008800") ) expect_snapshot(cat(update_rstudio_color("color me interested"))) }) test_that("cli_abort() captures correct call and backtrace", { skip_on_cran() rlang::local_options( rlang_trace_top_env = environment(), rlang_trace_format_srcrefs = FALSE ) f <- function() g() g <- function() h() h <- function() cli::cli_abort("foo") expect_snapshot({ print(expect_error(f())) }, variant = paste0("rlang-", packageVersion("rlang"))) classed_stop <- function(message, env = parent.frame()) { cli::cli_abort( message, .envir = env, class = "cli_my_class" ) } h <- function(x) { if (!length(x)) { classed_stop("{.arg x} can't be empty.") } } f <- function(x) g(x) g <- function(x) h(x) expect_snapshot({ print(expect_error(f(list()))) }, variant = paste0("rlang-", packageVersion("rlang"))) }) test_that("cli_abort(.internal = TRUE) reports the correct function (r-lib/rlang#1386)", { skip_on_cran() fn <- function() { cli::cli_abort("Message.", .internal = TRUE) } environment(fn) <- rlang::ns_env("base") # Should mention an internal error in the `base` package expect_snapshot({ (expect_error(fn())) }, variant = paste0("rlang-", packageVersion("rlang"))) }) cli/tests/testthat/test-vt.R0000644000176200001440000000677314557444176015612 0ustar liggesusers test_that("empty input", { expect_snapshot( vt_output("", width = 20, height = 2)$segment ) }) test_that("raw input", { expect_snapshot( vt_output(charToRaw("foobar"), width = 20, height = 2)$segment ) }) test_that("overflow", { expect_snapshot( vt_output(strrep("1234567890", 2), width = 19, height = 2)$segment ) }) test_that("control characters", { expect_snapshot( vt_output("foo\nbar", width = 20, height = 2)$segment ) expect_snapshot( vt_output("foobar\rbaz", width = 20, height = 2)$segment ) }) test_that("scroll up", { expect_snapshot( vt_output(strrep("1234567890", 5), width = 20, height = 2)$segment ) expect_snapshot( vt_output(paste0(1:10, "\n"), width = 10, height = 5)$segment ) }) test_that_cli(configs = "ansi", "ANSI SGR", { expect_snapshot( vt_output("12\033[31m34\033[1m56\033[39m78\033[21m90", width = 20, height = 2) ) expect_snapshot( vt_output(style_bold("I'm bold"), width = 20, height = 2) ) expect_snapshot( vt_output(style_italic("I'm italic"), width = 20, height = 2) ) expect_snapshot( vt_output(style_underline("I'm underlined"), width = 20, height = 2) ) expect_snapshot( vt_output(style_strikethrough("I'm strikethrough"), width = 20, height = 2) ) expect_snapshot( vt_output(style_inverse("I'm inverse"), width = 20, height = 2) ) }) test_that("hyperlinks", { withr::local_options(cli.hyperlink = TRUE) expect_snapshot({ link <- style_hyperlink("text", "url") vt_output(c("pre ", st_from_bel(link), " post"), width = 20, height = 2) }) expect_snapshot({ link <- style_hyperlink("text", "url", params = c("f" = "x", "g" = "y")) vt_output(c("pre ", st_from_bel(link), " post"), width = 20, height = 2) }) }) test_that("erase in line", { expect_snapshot({ vt_output("foobar\033[3D\033[K", width = 10, height = 2)$segment vt_output("foobar\033[3D\033[0K", width = 10, height = 2)$segment vt_output("foobar\033[3D\033[1K", width = 10, height = 2)$segment vt_output("foobar\033[3D\033[2K", width = 10, height = 2)$segment }) }) test_that("erase in screen", { expect_snapshot({ vt_output("foo\nfoobar\nfoobar2\033[A\033[4D\033[J", width = 10, height = 4)$segment vt_output("foo\nfoobar\nfoobar2\033[A\033[4D\033[0J", width = 10, height = 4)$segment vt_output("foo\nfoobar\nfoobar2\033[A\033[4D\033[1J", width = 10, height = 4)$segment vt_output("foo\nfoobar\nfoobar2\033[A\033[4D\033[2Jx", width = 10, height = 4)$segment vt_output("foo\nfoobar\nfoobar2\033[A\033[4D\033[3Jx", width = 10, height = 4)$segment }) }) test_that("colors", { expect_equal(vt_output("\033[30mcolored\033[39m")$color[1], "0") expect_equal(vt_output("\033[37mcolored\033[39m")$color[1], "7") expect_equal(vt_output("\033[90mcolored\033[39m")$color[1], "8") expect_equal(vt_output("\033[97mcolored\033[39m")$color[1], "15") expect_equal(vt_output("\033[40mcolored\033[39m")$background_color[1], "0") expect_equal(vt_output("\033[47mcolored\033[39m")$background_color[1], "7") expect_equal(vt_output("\033[100mcolored\033[39m")$background_color[1], "8") expect_equal(vt_output("\033[107mcolored\033[39m")$background_color[1], "15") expect_equal(vt_output("\033[38;5;100mcolored\033[39m")$color[1], "100") expect_equal(vt_output("\033[48;5;110mcolored\033[39m")$background_color[1], "110") expect_equal(vt_output("\033[38;2;1;2;3mcolored\033[39m")$color[1], "#010203") expect_equal(vt_output("\033[48;2;4;5;6mcolored\033[39m")$background_color[1], "#040506") }) cli/tests/testthat/test-ansi-make.R0000644000176200001440000000415514557444176017016 0ustar liggesusers test_that("make_style without name", { pink <- make_ansi_style("pink") expect_true(inherits(pink, "cli_ansi_style")) }) test_that("hexa color regex works", { positive <- c("#000000", "#ffffff", "#0f0f0f", "#f0f0f0", "#00000000", "#ffffffff", "#0f0f0f00", "#f0f0f055") negative <- c("", "#12345", "123456", "1234567", "12345678", "#1234567", "#1234ffg", "#gggggx", "foo#123456", "foo#123456bar") for (color in positive) { expect_true(grepl(hash_color_regex, color)) expect_true(grepl(hash_color_regex, toupper(color))) } for (color in negative) { expect_false(grepl(hash_color_regex, color)) expect_false(grepl(hash_color_regex, toupper(color))) } }) test_that("we fall back for ANSI 8 if needed", { yellow3 <- make_ansi_style("yellow3", colors = 8) expect_equal(yellow3("foobar"), col_yellow("foobar")) }) test_that("we can create a style from an R color", { red4 <- make_ansi_style("red4") red_text <- red4("text") expect_true(num_ansi_colors() == 1 || ansi_has_any(red_text)) }) test_that("errors", { expect_snapshot( error = TRUE, make_ansi_style(1:10) ) }) test_that("make_ansi_style", { withr::local_options(cli.num_colors = 256) cf <- crayon::red expect_equal( make_ansi_style(cf)("foo"), col_red("foo") ) expect_equal( make_ansi_style("dim")("foo"), style_blurred("foo") ) expect_equal( make_ansi_style("red", bg = TRUE)("red"), bg_red("red") ) expect_equal( make_ansi_style(cbind(c(200, 200, 100)), grey = TRUE)("200-200-100"), ansi_string("\033[38;5;250m200-200-100\033[39m") ) withr::local_options(cli.num_colors = truecolor) expect_equal( make_ansi_style(cbind(c(200, 200, 100)))("200-200-100"), ansi_string("\033[38;2;200;200;100m200-200-100\033[39m") ) expect_equal( make_ansi_style(cbind(c(200, 200, 100)), bg = TRUE)("200-200-100"), ansi_string("\033[48;2;200;200;100m200-200-100\033[49m") ) # errors expect_snapshot( error = TRUE, make_ansi_style(1:10) ) expect_snapshot( error = TRUE, make_ansi_style("foobar") ) }) cli/tests/testthat/test-ansi-combine.R0000644000176200001440000000175014557444176017513 0ustar liggesusers test_that("one style", { testthat::skip_on_covr() # because we are comparing functions expect_equal( combine_ansi_styles(col_red), col_red, ignore_function_env = TRUE ) expect_equal( combine_ansi_styles(style_bold), style_bold, ignore_function_env = TRUE ) }) test_that_cli(configs = c("plain", "ansi"), "style objects", { expect_equal( combine_ansi_styles(col_red, style_bold)("blah"), col_red(style_bold("blah")) ) expect_equal( combine_ansi_styles(col_red, style_bold, style_underline)("foo"), col_red(style_bold(style_underline("foo"))) ) }) test_that_cli(configs = c("plain", "ansi"), "create styles on the fly", { expect_equal( combine_ansi_styles("darkolivegreen", style_bold)("blah"), make_ansi_style("darkolivegreen")((style_bold("blah"))) ) expect_equal( combine_ansi_styles(style_bold, "darkolivegreen", style_underline)("foo"), style_bold(make_ansi_style("darkolivegreen")(style_underline("foo"))) ) }) cli/tests/testthat/test-progress-ticking.R0000644000176200001440000000064614557444176020444 0ustar liggesusers test_that("ticking", { withr::local_options( cli.ansi = TRUE, cli.dynamic = TRUE, cli.progress_show_after = 0, cli.progress_handlers_only = "cli" ) fun <- function() { i <- 0L while (ticking(i < 10L, total = 10L, name = "ticking", format = "{cli::pb_current}/{cli::pb_total}")) { i <- i + 1L } } out <- capture_cli_messages(cli_with_ticks(fun())) expect_snapshot(out) }) cli/tests/testthat/test-progress-handler-logger.R0000644000176200001440000000037314752735214021674 0ustar liggesusers test_that("loggerr_out", { bar <- new.env(parent = emptyenv()) bar$id <- "id" bar$current <- 13 bar$total <- 113 local_mocked_bindings(Sys.time = function() .POSIXct(1623325865, tz = "CET")) expect_snapshot(logger_out(bar, "updated")) }) cli/tests/testthat/test-headers.R0000644000176200001440000000106514557444176016561 0ustar liggesusers start_app() on.exit(stop_app(), add = TRUE) test_that_cli("headers", { expect_snapshot(local({ cli_div(class = "testcli", theme = test_style()) cli_h1("HEADER") cli_h2("Header") cli_h3("Header") x <- "foobar" xx <- 100 cli_h2("{xx}. header: {x}") }), variant = if (packageVersion("testthat") <= "3.1.4") "old" else "new") }) test_that("issue #218", { expect_snapshot({ cli_h1("one {1} two {2} three {3}") cli_h2("one {1} two {2} three {3}") }, variant = if (packageVersion("testthat") <= "3.1.4") "old" else "new") }) cli/tests/testthat/test-subprocess.R0000644000176200001440000000774114557444176017345 0ustar liggesusers test_that("events are properly generated", { ## This needs callr >= 3.0.0.90001, which is not yet on CRAN if (packageVersion("callr") < "3.0.0.9001") skip("Need newer callr") do <- function() { options(cli.message_class = "callr_message") cli::cli_div() cli::cli_h1("title") cli::cli_text("text") } rs <- callr::r_session$new() on.exit(rs$kill(), add = TRUE) msgs <- list() handler <- function(msg) { msgs <<- c(msgs, list(msg)) if (!is.null(findRestart("cli_message_handled"))) { invokeRestart("cli_message_handled") } if (!is.null(findRestart("callr_r_session_muffle"))) { invokeRestart("callr_r_session_muffle") } } withCallingHandlers( rs$run(do), cli_message = handler) expect_equal(length(msgs), 4) lapply(msgs, expect_s3_class, "cli_message") expect_equal(msgs[[1]]$type, "div") expect_equal(msgs[[2]]$type, "h1") expect_equal(msgs[[3]]$type, "text") expect_equal(msgs[[4]]$type, "end") rs$close() }) test_that("subprocess with default handler", { ## This needs callr >= 3.0.0.90001, which is not yet on CRAN if (packageVersion("callr") < "3.0.0.9001") skip("Need newer callr") do <- function() { options(cli.message_class = "callr_message") cli::cli_div() cli::cli_h1("title") cli::cli_text("text") } rs <- callr::r_session$new() on.exit(rs$kill(), add = TRUE) msgs <- list() withr::with_options(list( cli.default_handler = function(msg) { msgs <<- c(msgs, list(msg)) if (!is.null(findRestart("cli_message_handled"))) { invokeRestart("cli_message_handled") } }), rs$run(do) ) expect_equal(length(msgs), 4) lapply(msgs, expect_s3_class, "cli_message") expect_equal(msgs[[1]]$type, "div") expect_equal(msgs[[2]]$type, "h1") expect_equal(msgs[[3]]$type, "text") expect_equal(msgs[[4]]$type, "end") rs$close() }) test_that("output in child process", { ## This needs callr >= 3.0.0.90001, which is not yet on CRAN if (packageVersion("callr") < "3.0.0.9001") skip("Need newer callr") # We need to do our own condition handling, otherwise callr will # handle `cli_message` and copy it to the main process. # So on `cli_message` we just call the default handler, which will # call `message()`, and on `message` we'll copy the formatted message # to the main process. do <- function() { options(cli.num_colors = 256) withCallingHandlers({ cli::start_app(theme = cli::simple_theme()) cli::cli_h1("Title") cli::cli_text("This is generated in the {.emph subprocess}.") "foobar" }, cli_message = function(msg) { withCallingHandlers({ cli:::cli_server_default(msg) invokeRestart("cli_message_handled") }, message = function(mmsg) { class(mmsg) <- c("callr_message", "message", "condition") signalCondition(mmsg) }) } ) } rs <- callr::r_session$new() on.exit(rs$kill(), add = TRUE) # Store the formatted messages from callr # We also need to muffle the default handler here msgs <- list() result <- withCallingHandlers( rs$run_with_output(do), callr_message = function(msg) { msgs <<- c(msgs, list(msg)) if (!is.null(msg$muffle) && !is.null(findRestart(msg$muffle))) { invokeRestart(msg$muffle) } } ) expect_equal(result$stdout, "") expect_equal(result$stderr, "") expect_identical(result$result, "foobar") expect_null(result$error) str <- paste(vcapply(msgs, "[[", "message"), collapse = "") expect_true(ansi_has_any(str)) expect_match(str, "Title") expect_match(str, "This is generated") rs$close() }) test_that("substitution in child process", { do <- function() { options(cli.message_class = "callr_message") cli::cli_text("This is process {Sys.getpid()}.") } rs <- callr::r_session$new() on.exit(rs$kill(), add = TRUE) out <- capt0(rs$run(do)) expect_match(out, glue::glue("This is process {rs$get_pid()}")) rs$close() }) cli/tests/testthat/test-sitrep.R0000644000176200001440000000077314557444176016461 0ustar liggesusers test_that("sitrep runs", { expect_true(is.list(cli_sitrep())) expect_true(is.character(format(cli_sitrep()))) out <- capture_output(print(cli_sitrep())) expect_true(all(grepl("^- ", out))) }) test_that("get_active_symbol_set", { withr::with_options(list(cli.unicode = TRUE), { expect_true(get_active_symbol_set() %in% c("UTF-8", "RStudio (UTF-8)")) }) withr::with_options(list(cli.unicode = FALSE), { set <- get_active_symbol_set() expect_equal(set, "ASCII (non UTF-8)") }) }) cli/tests/testthat/helper.R0000644000176200001440000001246214557444176015453 0ustar liggesusers rule_class <- function(x) { structure(x, class = c("cli_rule", "rule", "cli_ansi_string", "ansi_string", "character")) } capture_msgs <- function(expr) { msgs <- character() i <- 0 suppressMessages(withCallingHandlers( expr, message = function(e) msgs[[i <<- i + 1]] <<- conditionMessage(e))) paste0(msgs, collapse = "") } capture_cli_messages <- function(expr) { msgs <- character() withCallingHandlers( expr, cliMessage = function(e) { msgs <<- c(msgs, conditionMessage(e)) invokeRestart("muffleMessage") } ) msgs } capt <- function(expr, print_it = TRUE) { pr <- if (print_it) print else identity paste(capture.output(pr(expr)), collapse = "\n") } capt0 <- function(expr, strip_style = FALSE) { out <- capture_msgs(expr) if (strip_style) ansi_strip(out) else out } local_cli_config <- function(unicode = FALSE, dynamic = FALSE, ansi = FALSE, num_colors = 1, .local_envir = parent.frame()) { withr::local_options( cli.dynamic = dynamic, cli.ansi = ansi, cli.unicode = unicode, crayon.enabled = num_colors > 1, crayon.colors = num_colors, .local_envir = .local_envir ) withr::local_envvar( PKG_OMIT_TIMES = "true", PKG_OMIT_SIZES = "true", .local_envir = .local_envir ) } test_style <- function() { list( ".testcli h1" = list( "font-weight" = "bold", "font-style" = "italic", "margin-top" = 1, "margin-bottom" = 1), ".testcli h2" = list( "font-weight" = "bold", "margin-top" = 1, "margin-bottom" = 1), ".testcli h3" = list( "text-decoration" = "underline", "margin-top" = 1) ) } fix_times <- function(out) { out <- sub("[(][ ]*[.0-9]+ [Mk]B/s[)]", "(8.5 MB/s)", out) out <- sub("[(][.0-9]+/s[)]", "(100/s)", out) out <- sub(" [.0-9]+(ms|s|m)", " 3ms", out) out <- sub("ETA:[ ]*[.0-9]+m?s", "ETA: 1s", out) out <- gsub("\\[[.0-9]+m?s\\]", "[1s]", out) out } fix_logger_output <- function(lines) { sub( paste0( "^[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]T", "[0-9][0-9]:[0-9][0-9]:[0-9][0-9]\\+00:00 ", "cli-[0-9]+-[0-9]+ " ), "2021-06-18T00:09:14+00:00 cli-36434-1 ", lines ) } make_c_function <- function(file = NULL, code = NULL, args = character(), type = c(".c", ".cpp"), header = NULL, linkingto = packageName(), quiet = Sys.getenv("TESTTHAT") == "true") { type <- match.arg(type) # Create source file dir.create(dir <- tempfile()) if (is.null(file)) { lines <- create_c_function_call(code, args, header = header) } else { lines <- readLines(file) } src <- basename(tempfile(fileext = type)) writeLines(lines, file.path(dir, src)) # Compile cflags <- "" for (pkg in linkingto) { pkgdir <- file.path(find.package(pkg), "include") lcldir <- file.path(find.package(pkg), "inst", "include") cflags <- paste(cflags, "-I", pkgdir, "-I", lcldir) } env <- c(PKG_CFLAGS = cflags) callr::rcmd( "SHLIB", src, wd = file.path(dir), env = env, echo = !quiet, show = !quiet ) # Load DLL dllfile <- file.path(dir, sub("[.]c(pp)?$", .Platform$dynlib.ext, src)) dll <- dyn.load(dllfile, local = TRUE, now = TRUE) # TODO: finalizer to unload/delete dll } create_c_function_call <- function(code, args, header = NULL) { c( "#include ", header, "SEXP tmp_c_function(", if (length(args) > 0) paste0("SEXP ", args, collapse = ", "), ") {", code, "}\n" ) } win2unix <- function (str) { gsub("\r\n", "\n", str, fixed = TRUE, useBytes = TRUE) } st_from_bel <- function(x) { gsub("\007", "\033\\", x, fixed = TRUE) } st_to_bel <- function(x) { gsub("\033\\", "\007", x, fixed = TRUE) } test_package_root <- function() { x <- tryCatch( rprojroot::find_package_root_file(), error = function(e) NULL) if (!is.null(x)) return(x) pkg <- testthat::testing_package() x <- tryCatch( rprojroot::find_package_root_file( path = file.path("..", "..", "00_pkg_src", pkg)), error = function(e) NULL) if (!is.null(x)) return(x) stop("Cannot find package root") } sanitize_wd <- function(x) { wd <- paste0("file://", getwd()) gsub(wd, "file:///testthat/home", x, fixed = TRUE) } sanitize_home <- function(x) { home <- paste0("file://", path.expand("~")) gsub(home, "file:///my/home", x, fixed = TRUE) } sanitize_srcref <- function(x) { gsub(" at .*.R:[0-9]+:[0-9]+", "", x) } sanitize_call <- function(x) { gsub(" in `.*`", "", x) } r_pty <- function(.envir = parent.frame()) { skip_on_cran() # TODO: why does this fail on the CI, in covr if (Sys.getenv("R_COVR") == "true" && isTRUE(as.logical(Sys.getenv("CI")))) { skip("fails on CI in covr") } if (!Sys.info()[["sysname"]] %in% c("Darwin", "Linux")) skip("Needs Linux or macOS") r <- file.path(R.home("bin"), "R") p <- processx::process$new( r, c("-q", "--slave", "--vanilla"), pty = TRUE, env = c("current", R_CLI_HIDE_CURSOR = "false", R_LIBS = .libPaths()[1]) ) defer({ close(p$get_input_connection()) p$wait(1000) p$kill() }, envir = .envir) p$poll_io(1000) p$read_output() p } cli/tests/testthat/test-custom-handler.R0000644000176200001440000000064514557444176020076 0ustar liggesusers test_that("custom handler works", { conds <- list() withr::with_options( list(cli.default_handler = function(msg) conds <<- c(conds, list(msg))), { cli_h1("title"); cli_h2("subtitle"); cli_text("text") } ) expect_equal(length(conds), 3) lapply(conds, expect_s3_class, "cli_message") expect_equal(conds[[1]]$type, "h1") expect_equal(conds[[2]]$type, "h2") expect_equal(conds[[3]]$type, "text") }) cli/tests/testthat/test-box-styles.R0000644000176200001440000000025214557444176017254 0ustar liggesusers test_that_cli(configs = c("plain", "unicode"), "list_border_styles", { expect_snapshot( for (st in list_border_styles()) print(boxx("", border_style = st)) ) }) cli/tests/testthat/test-ansi-html.R0000644000176200001440000000354214557444176017044 0ustar liggesusers test_that("ansi_html", { str <- c( "\033[1mbold\033[22m", "\033[2mfaint", "\033[3mitalic\033[0m", "\033[4munderline", "\033[5mblink", "\033[7minverse", "\033[8mhide", "\033[9mcrossedout", "\033[30mblack", "\033[31mred", "\033[32mgreen", "\033[33myellow", "\033[34mblue", "\033[35mmagenta", "\033[36mcyan", "\033[37mwhite", "\033[90mbblack", "\033[91mbred", "\033[92mbgreen", "\033[93mbyellow", "\033[94mbblue", "\033[95mbmagenta", "\033[96mbcyan", "\033[97mbwhite", "\033[38;5;156mcolor-156", "\033[38;2;1;22;255mcolor-1-22-255", "\033[40mbg-black", "\033[41mbg-red", "\033[42mbg-green", "\033[43mbg-yellow", "\033[44mbg-blue", "\033[45mbg-magenta", "\033[46mbg-cyan", "\033[47mbg-white", "\033[100mbg-bblack", "\033[101mbg-bred", "\033[102mbg-bgreen", "\033[103mbg-byellow", "\033[104mbg-bblue", "\033[105mbg-bmagenta", "\033[106mbg-bcyan", "\033[107mbg-bwhite", "\033[48;5;156mbg-color-156", "\033[48;2;1;22;255mbg-color-1-22-255" ) expect_snapshot( ansi_html(str) ) }) test_that("multiple styles", { expect_snapshot( ansi_html("\033[1;2;35;45mmultiple") ) }) test_that("CSI", { expect_equal( ansi_html("foo\033[10Abar", csi = "drop"), "foobar" ) expect_equal( ansi_html("\033[1mfoo\033[0m\033[10Abar", csi = "drop"), "foobar" ) expect_equal( ansi_html("foo\033[10Abar", csi = "keep"), "foo\033[10Abar" ) expect_equal( ansi_html("\033[1mfoo\033[0m\033[10Abar", csi = "keep"), "foo\033[10Abar" ) }) test_that("ansi_html_style", { expect_snapshot( ansi_html_style(colors = 8) ) expect_snapshot( ansi_html_style(colors = 256, palette = "ubuntu") ) }) cli/tests/testthat/test-alerts.R0000644000176200001440000000137414557444176016443 0ustar liggesusers start_app() on.exit(stop_app(), add = TRUE) test_that("generic", { expect_snapshot(local({ cli_div(theme = list(".alert" = list(before = "GENERIC! "))) cli_alert("wow") })) }) test_that_cli("success", { expect_snapshot(local({ cli_alert_success("wow") })) }) test_that_cli("danger", { expect_snapshot(local({ cli_alert_danger("wow") })) }) test_that_cli("warning", { expect_snapshot(local({ cli_alert_warning("wow") })) }) test_that_cli("info", { expect_snapshot(local({ cli_alert_info("wow") })) }) test_that("before and after can have spaces", { expect_snapshot(local({ cli_div(theme = list(.alert = list(before = "x ", after = " x"))) cli_alert("continuing that first alert", wrap = TRUE) })) }) cli/tests/testthat/test-links.R0000644000176200001440000001750014752735214016260 0ustar liggesusers # -- {.email} ------------------------------------------------------------- test_that_cli(configs = c("plain", "fancy"), links = c("all", "none"), "{.email}", { expect_snapshot({ cli_text("{.email bugs.bunny@acme.com}") }) }) test_that_cli(configs = c("plain", "fancy"), links = c("all", "none"), "{.email} vectors", { expect_snapshot({ emails <- paste0("bugs.bunny-", 1:3, "@acme.com") cli_text("{.email {emails}}") }) }) # -- {.file} and {.path} -------------------------------------------------- test_that_cli(configs = c("plain", "fancy"), links = c("all", "none"), "{.file} and {.path}", { withr::local_envvar(R_CLI_HYPERLINK_STYLE = NA_character_) # absolute path expect_snapshot({ cli_text("{.file /absolute/path}") cli_text("{.file file:///absolute/path}") cli_text("{.path /absolute/path}") cli_text("{.path file:///absolute/path}") }) # relative path expect_snapshot({ cli_text("{.file relative/path}") cli_text("{.file ./relative/path}") cli_text("{.path relative/path}") cli_text("{.path ./relative/path}") }, transform = sanitize_wd) # ~ expect_snapshot({ cli_text("{.file ~/relative/path}") cli_text("{.path ~/relative/path}") }, transform = sanitize_home) # vectorized expect_snapshot({ paths <- c("~/foo", "bar", "file:///abs") cli_text("{.file {paths}}") }, transform = function(x) sanitize_home(sanitize_wd(x))) # weird names expect_snapshot({ paths <- c("foo ", " bar ", "file:///a bs ") cli_text("{.file {paths}}") }, transform = sanitize_wd) # hand created hyperlink is skipped expect_snapshot({ name <- cli::style_hyperlink("/foo/bar", "/foo/bar") cli_text("{.file {name}}") }) # line numbers expect_snapshot({ cli_text("{.file /absolute/path:12}") cli_text("{.file file:///absolute/path:5}") cli_text("{.path /absolute/path:123}") cli_text("{.path file:///absolute/path:51}") }) expect_snapshot({ cli_text("{.file relative/path:12}") cli_text("{.file ./relative/path:5}") cli_text("{.path relative/path:123}") cli_text("{.path ./relative/path:51}") }, transform = sanitize_wd) expect_snapshot({ cli_text("{.file ~/relative/path:12}") cli_text("{.path ~/relative/path:5}") }, transform = sanitize_home) # line and column numbers expect_snapshot({ cli_text("{.file /absolute/path:12:5}") cli_text("{.file file:///absolute/path:5:100}") cli_text("{.path /absolute/path:123:1}") cli_text("{.path file:///absolute/path:51:6}") }) expect_snapshot({ cli_text("{.file relative/path:12:13}") cli_text("{.file ./relative/path:5:20}") cli_text("{.path relative/path:123:21}") cli_text("{.path ./relative/path:51:2}") }, transform = sanitize_wd) expect_snapshot({ cli_text("{.file ~/relative/path:12:23}") cli_text("{.path ~/relative/path:5:2}") }, transform = sanitize_home) expect_snapshot({ paths <- c("~/foo", "bar:10", "file:///abs:10:20") cli_text("{.file {paths}}") }, transform = function(x) sanitize_home(sanitize_wd(x))) local_mocked_bindings(is_windows = function() TRUE) expect_equal( abs_path1("c:/foo/bar"), "file://c:/foo/bar" ) }) # -- {.fun} --------------------------------------------------------------- test_that_cli(configs = "plain", links = c("all", "none"), "{.fun}", { expect_snapshot({ cli_text("{.fun myfun}") cli_text("{.fun mypackage::myfun}") }) expect_snapshot({ funs <- paste0("mypkg::myfun", 1:3) cli_text("{.fun {funs}}") }) }) test_that_cli(configs = "plain", links = "all", "turning off help", { withr::local_options(cli.hyperlink_help = FALSE) expect_snapshot({ cli_text("{.fun pkg::func}") }) }) test_that_cli(configs = "plain", links = "all", ".fun with custom format", { withr::local_options(cli.hyperlink_help_url_format = "aaa-{topic}-zzz") expect_snapshot({ cli_text("{.fun pkg::func}") }) }) # -- {.help} -------------------------------------------------------------- test_that_cli(configs = "plain", links = c("all", "none"), "{.help}", { expect_snapshot({ cli_text("{.help pkg::fun}") cli_text("{.help [link text](pkg::fun)}") }) expect_snapshot({ funcs <- paste0("pkg::fun", 1:3) cli_text("{.help {funcs}}") }) }) test_that_cli(configs = "plain", links = "all", ".help with custom format", { withr::local_options(cli.hyperlink_help_url_format = "aaa-{topic}-zzz") expect_snapshot({ cli_text("{.help pkg::fun}") }) }) # -- {.href} -------------------------------------------------------------- test_that_cli(configs = "plain", links = c("all", "none"), "{.href}", { expect_snapshot({ cli_text("{.href https://cli.r-lib.org}") cli_text("{.href [linktext](https://cli.r-lib.org)}") cli_text("{.href [link text](https://cli.r-lib.org)}") }) }) test_that_cli(configs = "plain", links = c("all", "none"), "{.href} vectors", { expect_snapshot({ url <- paste0("https://cli.r-lib.org/", 1:3) cli_text("{.href {url}}") }) }) # -- {.run} --------------------------------------------------------------- test_that_cli(configs = "plain", links = c("all", "none"), "{.run}", { expect_snapshot({ cli_text("{.run pkg::fun(param)}") cli_text("{.run [run(p1, p2)](pkg::fun(p1, p2, other = 'foo'))}") }) }) test_that_cli(configs = "plain", links = c("all", "none"), "{.run} vectors", { expect_snapshot({ codes <- paste0("pkg::fun", 1:3, "()") cli_text("{.run {codes}}") }) }) test_that_cli(configs = "plain", links = "all", ".run with custom format", { withr::local_options(cli.hyperlink_run_url_format = "aaa-{code}-zzz") expect_snapshot({ cli_text("{.run devtools::document()}") }) }) # -- {.topic} ------------------------------------------------------------- test_that_cli(configs = "plain", links = c("all", "none"), "{.topic}", { expect_snapshot({ cli_text("{.topic pkg::topic}") cli_text("{.topic [link text](pkg::topic)}") }) expect_snapshot({ topics <- paste0("pkg::topic", 1:3) cli_text("{.topic {topics}}") }) }) test_that_cli(configs = "plain", links = "all", ".topic with custom format", { withr::local_options(cli.hyperlink_help_url_format = "aaa-{topic}-zzz") expect_snapshot({ cli_text("{.topic pkg::fun}") }) }) # -- {.url} --------------------------------------------------------------- test_that_cli(configs = c("plain", "fancy"), links = c("all", "none"), "{.url}", { expect_snapshot({ cli_text("{.url https://cli.r-lib.org}") }) }) test_that_cli(configs = c("plain", "fancy"), links = c("all", "none"), "{.url} vector", { expect_snapshot({ urls <- paste0("https://cli.r-lib.org/", 1:3) cli_text("{.url {urls}}") }) }) test_that_cli(configs = "plain", links = "all", "linked {.url}", { expect_snapshot({ link <- c( "https://cli.r-lib.org", style_hyperlink("text", "https://cli.r-lib.org") ) cli_text("{.url {link}}") }) }) test_that("make_link_url", { withr::local_options(cli.hyperlink = TRUE) x <- style_hyperlink(paste0("foo", 1:3), paste0("https://foo.bar/", 1:3)) expect_equal(make_link_url(x), x) }) # -- {.vignette} ---------------------------------------------------------- test_that_cli(configs = "plain", links = c("all", "none"), "{.vignette}", { expect_snapshot({ cli_text("{.vignette pkg::name}") cli_text("{.vignette [link text](pkg::name)}") }) expect_snapshot({ vignettes <- paste0("pkg::topic", 1:3) cli_text("{.vignette {vignettes}}") }) }) test_that_cli(configs = "plain", links = "all", ".vignette with custom format", { withr::local_options(cli.hyperlink_vignette_url_format = "aaa-{vignette}-zzz") expect_snapshot({ cli_text("{.vignette pkgdown::accessibility}") }) }) cli/tests/testthat/progresstestcpp/0000755000176200001440000000000014557444176017313 5ustar liggesuserscli/tests/testthat/progresstestcpp/R/0000755000176200001440000000000014557444176017514 5ustar liggesuserscli/tests/testthat/progresstestcpp/R/cpp11.R0000644000176200001440000000040714557444176020564 0ustar liggesusers# Generated by cpp11: do not edit by hand test_baseline_ <- function() { .Call(`_progresstestcpp_test_baseline_`) } test_cli_ <- function() { .Call(`_progresstestcpp_test_cli_`) } test_template_ <- function() { .Call(`_progresstestcpp_test_template_`) } cli/tests/testthat/progresstestcpp/R/testcpp.R0000644000176200001440000000036014557444176021320 0ustar liggesusers #' @useDynLib progresstestcpp, .registration = TRUE NULL #' @export test_baseline <- function() { test_baseline_() } #' @export test_cli <- function() { test_cli_() } #' @export test_template <- function() { test_template_() } cli/tests/testthat/progresstestcpp/src/0000755000176200001440000000000014557444176020102 5ustar liggesuserscli/tests/testthat/progresstestcpp/src/testcpp.cpp0000644000176200001440000000150614557444176022272 0ustar liggesusers #include #include #include #include [[cpp11::register]] int test_baseline_() { int res = 0; for (int i = 0; i < 2000000000; i++) { res += i % 2; } return res; } [[cpp11::register]] int test_cli_() { int res = 0; cpp11::sexp bar = cli_progress_bar(2000000000, NULL); for (int i = 0; i < 2000000000; i++) { if (CLI_SHOULD_TICK) cli_progress_set(bar, i); res += i % 2; } return res; } [[cpp11::register]] int test_template_() { int res = 0; cpp11::sexp bar = cli_progress_bar(2000000000, NULL); cli_progress_set_format( bar, "{%d} package{?s} {cli::pb_bar} | {cli::pb_elapsed}", 4 ); for (int i = 0; i < 2000000000; i++) { if (CLI_SHOULD_TICK) cli_progress_set(bar, i); res += i % 2; } return res; } cli/tests/testthat/progresstestcpp/src/cpp11.cpp0000644000176200001440000000234714557444176021540 0ustar liggesusers// Generated by cpp11: do not edit by hand // clang-format off #include "cpp11/declarations.hpp" // testcpp.cpp int test_baseline_(); extern "C" SEXP _progresstestcpp_test_baseline_() { BEGIN_CPP11 return cpp11::as_sexp(test_baseline_()); END_CPP11 } // testcpp.cpp int test_cli_(); extern "C" SEXP _progresstestcpp_test_cli_() { BEGIN_CPP11 return cpp11::as_sexp(test_cli_()); END_CPP11 } // testcpp.cpp int test_template_(); extern "C" SEXP _progresstestcpp_test_template_() { BEGIN_CPP11 return cpp11::as_sexp(test_template_()); END_CPP11 } extern "C" { /* .Call calls */ extern SEXP _progresstestcpp_test_baseline_(); extern SEXP _progresstestcpp_test_cli_(); extern SEXP _progresstestcpp_test_template_(); static const R_CallMethodDef CallEntries[] = { {"_progresstestcpp_test_baseline_", (DL_FUNC) &_progresstestcpp_test_baseline_, 0}, {"_progresstestcpp_test_cli_", (DL_FUNC) &_progresstestcpp_test_cli_, 0}, {"_progresstestcpp_test_template_", (DL_FUNC) &_progresstestcpp_test_template_, 0}, {NULL, NULL, 0} }; } extern "C" void R_init_progresstestcpp(DllInfo* dll){ R_registerRoutines(dll, NULL, CallEntries, NULL, NULL); R_useDynamicSymbols(dll, FALSE); R_forceSymbols(dll, TRUE); } cli/tests/testthat/progresstestcpp/NAMESPACE0000644000176200001440000000023414557444176020531 0ustar liggesusers# Generated by roxygen2: do not edit by hand export(test_baseline) export(test_cli) export(test_template) useDynLib(progresstestcpp, .registration = TRUE) cli/tests/testthat/progresstestcpp/DESCRIPTION0000644000176200001440000000053514557444176021024 0ustar liggesusersPackage: progresstestcpp Title: Testing Terminal Progress Bars Version: 1.0.0 Authors@R: person("Gabor", "Csardi", , "csardi.gabor@gmail.com", role = c("aut", "cre")) Description: Test progress bars from the cli package, C++ version. License: MIT + file LICENSE Imports: cli LinkingTo: cli, cpp11 RoxygenNote: 7.1.1.9001 Encoding: UTF-8 cli/tests/testthat/test-progress-variables.R0000644000176200001440000002064014752735214020751 0ustar liggesusers test_that("cli_progress_demo", { withr::local_options(cli.ansi = TRUE) out <- cli_progress_demo(live = FALSE, at = 50) out$lines <- fix_times(out$lines) expect_snapshot(out) out <- cli_progress_demo(live = FALSE, at = NULL, total = 3) out$lines <- fix_times(out$lines) expect_snapshot(out) out <- cli_progress_demo(live = FALSE, at = NULL, total = NA, delay = 0.001) out$lines <- fix_times(out$lines) expect_snapshot(out) fun <- function() { options(cli.progress_handlers_only = "cli") cli_progress_demo(live = TRUE, at = NULL, total = 3) } msgs <- capture_cli_messages(out <- fun()) expect_snapshot(out) expect_snapshot(msgs) }) test_that("pb_bar", { expect_equal(cli__pb_bar(NULL), "") withr::local_options(cli__pb = list(current = 15, total = NA)) expect_snapshot(cli_text("-{cli::pb_bar}-")) withr::local_options(cli__pb = list(current = 15, total = 30)) expect_snapshot(cli_text("-{cli::pb_bar}-")) }) test_that("pb_current", { expect_equal(cli__pb_current(NULL), "") withr::local_options(cli__pb = list(current = 15)) expect_equal(cli::pb_current, 15) }) test_that("pb_current_bytes", { expect_equal(cli__pb_current_bytes(NULL), "") expect_snapshot({ cli__pb_current_bytes(list(current = 0)) cli__pb_current_bytes(list(current = 1)) cli__pb_current_bytes(list(current = 1000)) cli__pb_current_bytes(list(current = 1000 * 23)) cli__pb_current_bytes(list(current = 1000 * 1000 * 23)) }) }) test_that("pb_elapsed", { expect_equal(cli__pb_elapsed(NULL), "") withr::local_options(cli__pb = list(start = 0, speed_time = 1)) local_mocked_bindings(.Call = function(...) 1) expect_snapshot(cli__pb_elapsed()) local_mocked_bindings(.Call = function(...) 21) expect_snapshot(cli__pb_elapsed()) local_mocked_bindings(.Call = function(...) 58) expect_snapshot(cli__pb_elapsed()) local_mocked_bindings(.Call = function(...) 60 * 65) expect_snapshot(cli__pb_elapsed()) }) test_that("pb_elapsed_clock", { expect_equal(cli__pb_elapsed_clock(NULL), "") withr::local_options(cli__pb = list(start = 0, speed_time = 1)) local_mocked_bindings(.Call = function(...) 1) expect_snapshot(cli__pb_elapsed_clock()) local_mocked_bindings(.Call = function(...) 21) expect_snapshot(cli__pb_elapsed_clock()) local_mocked_bindings(.Call = function(...) 58) expect_snapshot(cli__pb_elapsed_clock()) local_mocked_bindings(.Call = function(...) 60 * 65) expect_snapshot(cli__pb_elapsed_clock()) }) test_that("pb_elapsed_raw", { expect_equal(cli__pb_elapsed_raw(NULL), "") withr::local_options(cli__pb = list(start = 0, speed_time = 1)) local_mocked_bindings(.Call = function(...) 1) expect_snapshot(cli__pb_elapsed_raw()) local_mocked_bindings(.Call = function(...) 21) expect_snapshot(cli__pb_elapsed_raw()) local_mocked_bindings(.Call = function(...) 58) expect_snapshot(cli__pb_elapsed_raw()) local_mocked_bindings(.Call = function(...) 60 * 65) expect_snapshot(cli__pb_elapsed_raw()) }) test_that("pb_eta", { expect_equal(cli__pb_eta(NULL), "") local_mocked_bindings(cli__pb_eta_raw = function(...) NA_real_) expect_snapshot(cli__pb_eta(list())) local_mocked_bindings(cli__pb_eta_raw = function(...) as.difftime(12, units = "secs")) expect_snapshot(cli__pb_eta(list())) }) test_that("pb_eta_raw", { expect_equal(cli__pb_eta_raw(NULL), "") withr::local_options(cli__pb = list(total = NA)) expect_identical(cli__pb_eta_raw(), NA_real_) local_mocked_bindings(.Call = function(...) 0) withr::local_options(cli__pb = list(start = -10, total = 100, current = 0)) expect_snapshot(cli__pb_eta_raw()) withr::local_options(cli__pb = list(start = -10, total = 100, current = 20)) expect_snapshot(cli__pb_eta_raw()) withr::local_options(cli__pb = list(start = -40, total = 100, current = 80)) expect_snapshot(cli__pb_eta_raw()) withr::local_options(cli__pb = list(start = -50, total = 100, current = 100)) expect_snapshot(cli__pb_eta_raw()) }) test_that("pb_eta_str", { expect_equal(cli__pb_eta_str(NULL), "") withr::local_options(cli__pb = list(total = NA)) expect_identical(cli__pb_eta_str(), "") local_mocked_bindings(cli__pb_eta = function(...) "?") expect_snapshot(cli__pb_eta_str(list())) local_mocked_bindings(cli__pb_eta = function(...) " 1s") expect_snapshot(cli__pb_eta_str(list())) }) test_that("pb_extra", { expect_equal(cli__pb_extra(NULL), "") expect_equal(cli__pb_extra(list(extra = list(a = 1))), list(a = 1)) }) test_that("pb_id", { expect_equal(cli__pb_id(NULL), "") expect_equal(cli__pb_id(list(id = 123)), 123) }) test_that("pb_name", { expect_equal(cli__pb_name(NULL), "") expect_equal(cli__pb_name(list(name = NULL)), "") expect_equal(cli__pb_name(list(name = "foo")), "foo ") }) test_that("pb_percent", { expect_equal(cli__pb_percent(NULL), "") expect_snapshot({ cli__pb_percent(list(current = 0, total = 99)) cli__pb_percent(list(current = 5, total = 99)) cli__pb_percent(list(current = 10, total = 99)) cli__pb_percent(list(current = 25, total = 99)) cli__pb_percent(list(current = 99, total = 99)) cli__pb_percent(list(current = 100, total = 99)) }) }) test_that("pb_pid", { expect_equal(cli__pb_pid(NULL), "") expect_equal(cli__pb_pid(list()), Sys.getpid()) expect_equal(cli__pb_pid(list(pid = 100)), 100) }) test_that("pb_rate", { expect_equal(cli__pb_rate(NULL), "") local_mocked_bindings(cli__pb_rate_raw = function(...) NaN) expect_snapshot(cli__pb_rate(list())) local_mocked_bindings(cli__pb_rate_raw = function(...) Inf) expect_snapshot(cli__pb_rate(list())) local_mocked_bindings(cli__pb_rate_raw = function(...) 1 / 10) expect_snapshot(cli__pb_rate(list())) local_mocked_bindings(cli__pb_rate_raw = function(...) 12.4) expect_snapshot(cli__pb_rate(list())) }) test_that("pb_rate_raw", { expect_equal(cli__pb_rate_raw(NULL), "") local_mocked_bindings(cli__pb_elapsed_raw = function(...) this) this <- 0 expect_equal(cli__pb_rate_raw(list(current = 0)), NaN) expect_equal(cli__pb_rate_raw(list(current = 23)), Inf) this <- 1 expect_equal(cli__pb_rate_raw(list(current = 23)), 23) this <- 10 expect_equal(cli__pb_rate_raw(list(current = 1)), 1/10) }) test_that("pb_rate_bytes", { expect_equal(cli__pb_rate_bytes(NULL), "") local_mocked_bindings(cli__pb_rate_raw = function(...) NaN) expect_snapshot(cli__pb_rate_bytes(list())) local_mocked_bindings(cli__pb_rate_raw = function(...) Inf) expect_snapshot(cli__pb_rate_bytes(list())) local_mocked_bindings(cli__pb_rate_raw = function(...) 0) expect_snapshot(cli__pb_rate_bytes(list())) local_mocked_bindings(cli__pb_rate_raw = function(...) 1024) expect_snapshot(cli__pb_rate_bytes(list())) local_mocked_bindings(cli__pb_rate_raw = function(...) 1024 * 23) expect_snapshot(cli__pb_rate_bytes(list())) local_mocked_bindings(cli__pb_rate_raw = function(...) 1024 * 1024 * 23) expect_snapshot(cli__pb_rate_bytes(list())) }) test_that("pb_spin", { expect_equal(cli__pb_spin(NULL), "") withr::local_options(cli.spinner = "line") withr::local_options(cli__pb = list(tick = 1)) expect_snapshot(cli_text("-{cli::pb_spin}-{cli::pb_spin}-")) withr::local_options(cli__pb = list(tick = 2)) expect_snapshot(cli_text("-{cli::pb_spin}-{cli::pb_spin}-")) withr::local_options(cli__pb = list(tick = 10)) expect_snapshot(cli_text("-{cli::pb_spin}-{cli::pb_spin}-")) }) test_that("pb_status", { expect_equal(cli__pb_status(NULL), "") expect_equal(cli__pb_status(NULL), "") expect_equal(cli__pb_status(list(status = NULL)), "") expect_equal(cli__pb_status(list(status = "foo")), "foo ") }) test_that("pb_timestamp", { expect_equal(cli__pb_timestamp(NULL), "") fake <- .POSIXct(1623974954, tz = "GMT") local_mocked_bindings(Sys.time = function() fake) expect_snapshot(cli__pb_timestamp(list())) backup <- mget(c("load_time", "speed_time"), clienv) on.exit({ clienv$load_time <- backup$load_time clienv$speed_time <- backup$speed_time }, add = TRUE) clienv$load_time <- fake - 10 clienv$speed_time <- 3.0 expect_snapshot(cli__pb_timestamp(list())) }) test_that("pb_total", { expect_equal(cli__pb_total(NULL), "") expect_equal(cli__pb_total(list(total = 101)), 101) }) test_that("pb_total_bytes", { expect_equal(cli__pb_total_bytes(NULL), "") expect_snapshot({ cli__pb_total_bytes(list(total = 0)) cli__pb_total_bytes(list(total = 1)) cli__pb_total_bytes(list(total = 1000)) cli__pb_total_bytes(list(total = 1000 * 23)) cli__pb_total_bytes(list(total = 1000 * 1000 * 23)) }) }) cli/tests/testthat/test-glue.R0000644000176200001440000000203114557444176016074 0ustar liggesusers # https://github.com/r-lib/cli/issues/370 test_that("glue quotes and comments", { expect_snapshot({ cli_dl( c( "test_1" = "all good", "test_2" = "not #good" ) ) cli::cli_dl(c("test_3" = "no' good either")) cli::cli_dl(c("test_4" = "no\" good also")) cli::cli_text("{.url https://example.com/#section}") cli::cli_alert_success("Qapla'") }) }) test_that("quotes, etc. within expressions are still OK", { expect_snapshot({ cli::cli_text("{.url URL} {x <- 'foo'; nchar(x)}") cli::cli_text("{.url URL} {x <- \"foo\"; nchar(x)}") cli::cli_text("{.url URL} {1 + 1 # + 1} {1 + 1}") }) }) test_that("{. } is always a style", { cmd <- paste0("{.", basename(tempfile()), " }") expect_silent(glue_cmd(cmd, .envir = environment())) .foo <- 100 vals <- glue_cmd("{.foo }", .envir = environment())$values expect_false(any(grepl("^v[0-9]+$", names(vals)))) }) test_that("{ } is parsed with literal = FALSE", { expect_snapshot( format_message("{.emph {'{foo {}'}}") ) }) cli/tests/testthat/test-progress-handler-say.R0000644000176200001440000000136614752735214021214 0ustar liggesusers test_that("say_out", { px <- asNamespace("processx")$get_tool("px") tmp <- tempfile("cli-test-") on.exit(unlink(tmp), add = TRUE) withr::local_options( cli.progress_say_command = px, cli.progress_say_args = c("writefile", tmp) ) p <- say_out(" 70%") expect_s3_class(p, "process") p$wait(3000) expect_false(p$is_alive()) p$kill() expect_equal(readLines(tmp, warn = FALSE), " 70%") }) test_that("say_update", { withr::local_options(cli.progress_say_frequency = 1e-9) local_mocked_bindings(say_out = function(text) text) bar <- new.env(parent = emptyenv()) bar$current <- 10 bar$total <- NA say_update(bar) expect_equal(bar$say_proc, 10) bar$total <- 50 say_update(bar) expect_equal(bar$say_proc, " 20%") }) cli/tests/testthat/test-rules.R0000644000176200001440000000753214557444176016305 0ustar liggesusers test_that_cli("make_line", { expect_equal(make_line(1, "-"), "-") expect_equal(make_line(0, "-"), "") expect_equal(make_line(2, "-"), "--") expect_equal(make_line(10, "-"), "----------") expect_equal(make_line(2, "12"), "12") expect_equal(make_line(0, "12"), "") expect_equal(make_line(1, "12"), "1") expect_equal(make_line(9, "12"), "121212121") expect_equal(make_line(10, "12"), "1212121212") }) test_that("width option", { expect_equal( rule(width = 11, line = "-"), rule_class("-----------") ) }) test_that("left label", { expect_equal( rule("label", width = 12, line = "-"), rule_class("-- label ---") ) expect_equal( rule("l", width = 12, line = "-"), rule_class("-- l -------") ) expect_equal( rule("label", width = 9, line = "-"), rule_class("-- label ") ) expect_equal( rule("label", width = 8, line = "-"), rule_class("-- label") ) expect_equal( rule("label", width = 6, line = "-"), rule_class("-- lab") ) }) test_that("centered label", { expect_error( rule(left = "label", center = "label"), "cannot be specified" ) expect_error( rule(center = "label", right = "label"), "cannot be specified" ) expect_equal( rule(center = "label", width = 13, line = "-"), rule_class("--- label ---") ) expect_equal( rule(center = "label", width = 14, line = "-"), rule_class("---- label ---") ) expect_equal( rule(center = "label", width = 9, line = "-"), rule_class("- label -") ) expect_equal( rule(center = "label", width = 8, line = "-"), rule_class("- labe -") ) expect_equal( rule(center = "label", width = 7, line = "-"), rule_class("- lab -") ) }) test_that("right label", { expect_equal( rule(right = "label", width = 12, line = "-"), rule_class("--- label --") ) expect_equal( rule(right = "l", width = 12, line = "-"), rule_class("------- l --") ) expect_equal( rule(right = "label", width = 9, line = "-"), rule_class(" label --") ) expect_equal( rule(right = "label", width = 8, line = "-"), rule_class(" label -") ) expect_equal( rule(right = "label", width = 6, line = "-"), rule_class(" label") ) expect_equal( rule(right = "label", width = 5, line = "-"), rule_class(" labe") ) expect_equal( rule(right = "label", width = 4, line = "-"), rule_class(" lab") ) }) test_that("line_col", { withr::with_options( list(cli.num_colors = 256L), { expect_true(ansi_has_any( rule(line_col = "red") )) expect_true(ansi_has_any( rule(left = "left", line_col = "red") )) expect_true(ansi_has_any( rule(left = "left", right = "right", line_col = "red") )) expect_true(ansi_has_any( rule(center = "center", line_col = "red") )) expect_true(ansi_has_any( rule(right = "right", line_col = "red") )) expect_true(ansi_has_any( rule(line_col = col_red) )) } ) }) test_that_cli("get_line_char", { expect_equal(get_line_char(1), cli::symbol$line) expect_equal(get_line_char(2), cli::symbol$double_line) expect_equal(get_line_char("bar1"), cli::symbol$lower_block_1) expect_equal(get_line_char("bar2"), cli::symbol$lower_block_2) expect_equal(get_line_char("bar3"), cli::symbol$lower_block_3) expect_equal(get_line_char("bar4"), cli::symbol$lower_block_4) expect_equal(get_line_char("bar5"), cli::symbol$lower_block_5) expect_equal(get_line_char("bar6"), cli::symbol$lower_block_6) expect_equal(get_line_char("bar7"), cli::symbol$lower_block_7) expect_equal(get_line_char("bar8"), cli::symbol$lower_block_8) expect_equal(get_line_char("xxx"), "xxx") expect_equal(get_line_char(c("x", "y", "z")), "xyz") }) test_that("print.cli_rule", { withr::local_options(cli.width = 20) expect_snapshot(rule("foo")) }) cli/tests/testthat/test-ansiex-2.R0000644000176200001440000003140614557444176016576 0ustar liggesusers test_that("very long strings", { withr::local_options(cli.num_colors = 256) str <- strrep("1234 ", 1000) expect_equal( ansi_simplify(col_red(col_red(str))), col_red(str) ) str2 <- paste0(col_green(str), col_red(str)) expect_equal( ansi_simplify(col_green(str2)), ansi_string(str2) ) }) test_that("RGB colors", { cases <- list( list("\033[38;5;123mfoo\033[39m", "\033[38;5;123mfoo\033[39m"), list("\033[38;2;1;2;3mfoo\033[39m", "\033[38;2;1;2;3mfoo\033[39m"), list("\033[38;2;mfoo\033[39m", "\033[38;2;0;0;0mfoo\033[39m"), list("\033[48;5;123mfoo\033[49m", "\033[48;5;123mfoo\033[49m"), list("\033[48;2;1;2;3mfoo\033[49m", "\033[48;2;1;2;3mfoo\033[49m"), list("\033[48;2;mfoo\033[49m", "\033[48;2;0;0;0mfoo\033[49m"), ## bad tags are skipped completely list("\033[48;4;12mfoo\033[49m", "foo") ) for (c in cases) { expect_equal(ansi_simplify(c[[1]]), ansi_string(c[[2]])) } }) test_that("0m closing tag", { cases <- list( list("\033[1mfoo\033[0m", "\033[1mfoo\033[22m"), list("\033[1mfoo\033[m", "\033[1mfoo\033[22m") ) for (c in cases) { expect_equal(ansi_simplify(c[[1]]), ansi_string(c[[2]])) } }) test_that("various tags", { cases <- list( list("\033[1m\033[22m\033[1mfoo", "\033[1mfoo\033[22m"), list("\033[2m\033[22m\033[2mfoo", "\033[2mfoo\033[22m"), list("\033[3m\033[23m\033[3mfoo", "\033[3mfoo\033[23m"), list("\033[4m\033[24m\033[4mfoo", "\033[4mfoo\033[24m"), list("\033[5m\033[25m\033[5mfoo", "\033[5mfoo\033[25m"), list("\033[7m\033[27m\033[7mfoo", "\033[7mfoo\033[27m"), list("\033[8m\033[28m\033[8mfoo", "\033[8mfoo\033[28m"), list("\033[9m\033[29m\033[9mfoo", "\033[9mfoo\033[29m"), list("\033[30m\033[39m\033[30mfoo", "\033[30mfoo\033[39m"), list("\033[31m\033[39m\033[31mfoo", "\033[31mfoo\033[39m"), list("\033[32m\033[39m\033[32mfoo", "\033[32mfoo\033[39m"), list("\033[33m\033[39m\033[33mfoo", "\033[33mfoo\033[39m"), list("\033[34m\033[39m\033[34mfoo", "\033[34mfoo\033[39m"), list("\033[35m\033[39m\033[35mfoo", "\033[35mfoo\033[39m"), list("\033[36m\033[39m\033[36mfoo", "\033[36mfoo\033[39m"), list("\033[37m\033[39m\033[37mfoo", "\033[37mfoo\033[39m"), list("\033[90m\033[39m\033[90mfoo", "\033[90mfoo\033[39m"), list("\033[91m\033[39m\033[91mfoo", "\033[91mfoo\033[39m"), list("\033[92m\033[39m\033[92mfoo", "\033[92mfoo\033[39m"), list("\033[93m\033[39m\033[93mfoo", "\033[93mfoo\033[39m"), list("\033[94m\033[39m\033[94mfoo", "\033[94mfoo\033[39m"), list("\033[95m\033[39m\033[95mfoo", "\033[95mfoo\033[39m"), list("\033[96m\033[39m\033[96mfoo", "\033[96mfoo\033[39m"), list("\033[97m\033[39m\033[97mfoo", "\033[97mfoo\033[39m"), list("\033[40m\033[49m\033[40mfoo", "\033[40mfoo\033[49m"), list("\033[41m\033[49m\033[41mfoo", "\033[41mfoo\033[49m"), list("\033[42m\033[49m\033[42mfoo", "\033[42mfoo\033[49m"), list("\033[43m\033[49m\033[43mfoo", "\033[43mfoo\033[49m"), list("\033[44m\033[49m\033[44mfoo", "\033[44mfoo\033[49m"), list("\033[45m\033[49m\033[45mfoo", "\033[45mfoo\033[49m"), list("\033[46m\033[49m\033[46mfoo", "\033[46mfoo\033[49m"), list("\033[47m\033[49m\033[47mfoo", "\033[47mfoo\033[49m"), list("\033[100m\033[49m\033[100mfoo", "\033[100mfoo\033[49m"), list("\033[101m\033[49m\033[101mfoo", "\033[101mfoo\033[49m"), list("\033[102m\033[49m\033[102mfoo", "\033[102mfoo\033[49m"), list("\033[103m\033[49m\033[103mfoo", "\033[103mfoo\033[49m"), list("\033[104m\033[49m\033[104mfoo", "\033[104mfoo\033[49m"), list("\033[105m\033[49m\033[105mfoo", "\033[105mfoo\033[49m"), list("\033[106m\033[49m\033[106mfoo", "\033[106mfoo\033[49m"), list("\033[107m\033[49m\033[107mfoo", "\033[107mfoo\033[49m") ) for (c in cases) { expect_equal(ansi_simplify(c[[1]]), ansi_string(c[[2]])) } }) test_that("unknown tags are kept as is, and [0m is also kept for then", { cases <- list( list("\033[11mfoo\033[0m", "\033[11mfoo\033[0m") ) for (c in cases) { expect_equal(ansi_simplify(c[[1]]), ansi_string(c[[2]])) } }) test_that("simplify w/o tags", { cases <- list( list(c("", "foo", "\033[1mbold"), c("", "foo", "\033[1mbold\033[22m")) ) for (c in cases) { expect_equal(ansi_simplify(c[[1]]), ansi_string(c[[2]])) } }) test_that("CSI sequences", { expect_equal( ansi_simplify("foo\033[10Abar", csi = "drop"), ansi_string("foobar") ) expect_equal( ansi_simplify("\033[1mfoo\033[0m\033[10Abar", csi = "drop"), ansi_string("\033[1mfoo\033[22mbar") ) expect_equal( ansi_simplify("foo\033[10Abar", csi = "keep"), ansi_string("foo\033[10Abar") ) expect_equal( ansi_simplify("\033[1mfoo\033[0m\033[10Abar", csi = "keep"), ansi_string("\033[1mfoo\033[10A\033[22mbar") ) expect_equal( ansi_strip("\033[1mfoo\033[10Abar\033[0m", csi = TRUE, sgr = FALSE), "\033[1mfoobar\033[0m" ) expect_equal( ansi_strip("\033[1mfoo\033[10Abar\033[0m", csi = FALSE, sgr = TRUE), "foo\033[10Abar" ) }) test_that("ansi_has_any", { T <- TRUE F <- FALSE expect_false(ansi_has_any("foobar", sgr = T, csi = T)) expect_true (ansi_has_any("\033[1mfoobar", sgr = T, csi = T)) expect_true (ansi_has_any("\033[10Afoobar", sgr = T, csi = T)) expect_true (ansi_has_any("\033[10A\033[1mfoobar", sgr = T, csi = T)) expect_false(ansi_has_any("foobar", sgr = T, csi = F)) expect_true (ansi_has_any("\033[1mfoobar", sgr = T, csi = F)) expect_false(ansi_has_any("\033[10Afoobar", sgr = T, csi = F)) expect_true (ansi_has_any("\033[10A\033[1mfoobar", sgr = T, csi = F)) expect_false(ansi_has_any("foobar", sgr = F, csi = T)) expect_false(ansi_has_any("\033[1mfoobar", sgr = F, csi = T)) expect_true (ansi_has_any("\033[10Afoobar", sgr = F, csi = T)) expect_true (ansi_has_any("\033[10A\033[1mfoobar", sgr = F, csi = T)) expect_false(ansi_has_any("foobar", sgr = F, csi = F)) expect_false(ansi_has_any("\033[1mfoobar", sgr = F, csi = F)) expect_false(ansi_has_any("\033[10Afoobar", sgr = F, csi = F)) expect_false(ansi_has_any("\033[10A\033[1mfoobar", sgr = F, csi = F)) }) test_that("NA", { T <- TRUE F <- FALSE s <- c("foo", NA, "bar", "\033[1mfoobar") expect_equal( ansi_simplify(s), ansi_string(c("foo", NA, "bar", "\033[1mfoobar\033[22m")) ) expect_equal(is.na(ansi_simplify(s)), c(F, T, F, F)) expect_equal( ansi_substr(s, 1, 2), ansi_string(c("fo", NA, "ba", "\033[1mfo\033[22m")) ) expect_equal(is.na(ansi_substr(s, 1, 2)), c(F, T, F, F)) expect_snapshot(ansi_html(s)) expect_equal(is.na(ansi_html(s)), c(F, T, F, F)) expect_equal(ansi_has_any(s), c(F, NA, F, T)) expect_equal(ansi_strip(s), c("foo", NA, "bar", "foobar")) expect_equal(is.na(ansi_strip(s)), c(F, T, F, F)) }) test_that("strrep", { expect_equal(strrep(character(), 5), character()) expect_equal(strrep("a", 5), "aaaaa") }) test_that("convert to character", { expect_false(ansi_has_any(123)) expect_equal(ansi_strip(123), "123") expect_equal(ansi_substr(1234, 2, 3), ansi_string("23")) expect_equal(ansi_substring(1234, 2, 3), ansi_string("23")) expect_equal(ansi_strsplit(1234, 2), list(ansi_string(c("1", "34")))) expect_equal(ansi_trimws(123), ansi_string("123")) expect_equal(ansi_strwrap(123), ansi_string("123")) expect_equal(ansi_simplify(123), ansi_string("123")) expect_equal(ansi_html(123), "123") expect_equal(ansi_nchar(123), 3) }) test_that("ansi_nchar", { b <- col_red(c( "\U0001f477\U0001f3fb", "\U0001f477\U0001f3fc\u200d\u2642\ufe0f", "\U0001f477\U0001f3fd\u200d\u2640\ufe0f", "\U0001f477", "\U0001f477\U0001f3fe\u200d\u2640\ufe0f" )) expect_equal(ansi_nchar(b), rep(1L, 5)) expect_equal(ansi_nchar(b, "chars"), rep(1L, 5)) expect_equal(ansi_nchar(b, "bytes"), c(8L, 17L, 17L, 4L, 17L)) expect_equal(ansi_nchar(b, "width"), rep(2L, 5)) expect_equal(ansi_nchar(b, "graphemes"), rep(1L, 5)) expect_equal(ansi_nchar(b, "codepoints"), c(2L, 5L, 5L, 1L, 5L)) bb <- paste0(b, collapse = "") expect_equal(ansi_nchar(bb), sum(rep(1L, 5))) expect_equal(ansi_nchar(bb, "chars"), sum(rep(1L, 5))) expect_equal(ansi_nchar(bb, "bytes"), sum(c(8L, 17L, 17L, 4L, 17L))) expect_equal(ansi_nchar(bb, "width"), sum(rep(2L, 5))) expect_equal(ansi_nchar(bb, "graphemes"), sum(rep(1L, 5))) expect_equal(ansi_nchar(bb, "codepoints"), sum(c(2L, 5L, 5L, 1L, 5L))) expect_equal(ansi_nchar(character(), "chars"), integer()) expect_equal(ansi_nchar(character(), "bytes"), integer()) expect_equal(ansi_nchar(character(), "width"), integer()) expect_equal(ansi_nchar(character(), "graphemes"), integer()) expect_equal(ansi_nchar(character(), "codepoints"), integer()) expect_equal(ansi_nchar("", "chars"), 0L) expect_equal(ansi_nchar("", "bytes"), 0L) expect_equal(ansi_nchar("", "width"), 0L) expect_equal(ansi_nchar("", "graphemes"), 0L) expect_equal(ansi_nchar("", "codepoints"), 0L) }) test_that("ansi_align with graphemes", { withr::local_options(cli.num_colors = 256) b <- col_red(c( "\U0001f477\U0001f3fb", "\U0001f477\U0001f3fc\u200d\u2642\ufe0f", "\U0001f477\U0001f3fd\u200d\u2640\ufe0f", "\U0001f477", "\U0001f477\U0001f3fe\u200d\u2640\ufe0f" )) expect_equal( ansi_align(b, width = 10, align = "left"), ansi_string(paste0(b, strrep(" ", 8))) ) expect_equal( ansi_align(b, width = 10, align = "center"), ansi_string(paste0(strrep(" ", 4), b, strrep(" ", 4))) ) expect_equal( ansi_align(b, width = 10, align = "right"), ansi_string(paste0(strrep(" ", 8), b)) ) }) test_that("ansi_columns with graphemes", { withr::local_options(cli.num_colors = 256) b <- col_red(c( "\U0001f477\U0001f3fb", "\U0001f477\U0001f3fc\u200d\u2642\ufe0f", "\U0001f477\U0001f3fd\u200d\u2640\ufe0f", "\U0001f477", "\U0001f477\U0001f3fe\u200d\u2640\ufe0f" )) expect_equal( ansi_columns(b, width = 6), ansi_string(c( paste0(b[1], " ", b[2], " "), paste0(b[3], " ", b[4], " "), paste0(b[5], " ") )) ) }) test_that("ansi_substr with graphemes", { withr::local_options(cli.num_colors = 256) b <- col_red(c( "\U0001f477\U0001f3fb", "\U0001f477\U0001f3fc\u200d\u2642\ufe0f", "\U0001f477\U0001f3fd\u200d\u2640\ufe0f", "\U0001f477", "\U0001f477\U0001f3fe\u200d\u2640\ufe0f" )) bb <- paste0(b, collapse = "") expect_equal( ansi_substr(bb, 2, 4), col_red(paste0( "\U0001f477\U0001f3fc\u200d\u2642\ufe0f", "\U0001f477\U0001f3fd\u200d\u2640\ufe0f", "\U0001f477" )) ) }) test_that("ansi_grep", { withr::local_options(cli.num_colors = 256, cli.hyperlink = TRUE) red_needle <- col_red("needle") haystack <- c("foo", "needle", "foo") green_haystack <- col_green(haystack) expect_equal( ansi_grep(red_needle, green_haystack), 2L ) expect_equal( ansi_grep(red_needle, haystack), 2L ) expect_equal( ansi_grep(red_needle, green_haystack, value = TRUE), ansi_string(green_haystack[2]) ) expect_equal( ansi_grep("nope", haystack), integer() ) expect_equal( ansi_grep("nope", haystack, value = TRUE), ansi_string(character()) ) expect_equal( ansi_grep("nope", character()), integer() ) expect_equal( ansi_grep("nope", character(), value = TRUE), ansi_string(character()) ) }) test_that("ansi_grepl", { withr::local_options(cli.num_colors = 256, cli.hyperlink = TRUE) red_needle <- col_red("needle") haystack <- c("foo", "needle", "foo") green_haystack <- col_green(haystack) expect_equal( ansi_grepl(red_needle, green_haystack), c(FALSE, TRUE, FALSE) ) expect_equal( ansi_grepl(red_needle, haystack), c(FALSE, TRUE, FALSE) ) expect_equal( ansi_grepl("nope", haystack), c(FALSE, FALSE, FALSE) ) expect_equal( ansi_grepl("nope", character()), logical() ) }) test_that("ansi_nzchar", { withr::local_options(cli.num_colors = 256, cli.hyperlink = TRUE) expect_equal(ansi_nzchar(""), FALSE) expect_equal(ansi_nzchar(c("", "")), c(FALSE, FALSE)) expect_equal(ansi_nzchar(c("", "yes")), c(FALSE, TRUE)) expect_equal(ansi_nzchar(c("yes", "")), c(TRUE, FALSE)) expect_equal(ansi_nzchar(c("yes", "yes")), c(TRUE, TRUE)) expect_equal(ansi_nzchar(col_red("")), FALSE) expect_equal(ansi_nzchar(col_red(c("", ""))), c(FALSE, FALSE)) expect_equal(ansi_nzchar(col_red(c("", "yes"))), c(FALSE, TRUE)) expect_equal(ansi_nzchar(col_red(c("yes", ""))), c(TRUE, FALSE)) expect_equal(ansi_nzchar(col_red(c("yes", "yes"))), c(TRUE, TRUE)) expect_equal(ansi_nzchar(style_hyperlink("text", "https://x.xom")), TRUE) expect_equal(ansi_nzchar(style_hyperlink("", "https://x.xom")), FALSE) expect_equal(ansi_nzchar(NA), nzchar(NA)) expect_equal(ansi_nzchar(NA, keepNA = TRUE), nzchar(NA, keepNA = TRUE)) }) cli/tests/testthat/test-themes.R0000644000176200001440000000665614602234603016425 0ustar liggesusers start_app(.auto_close = TRUE) test_that_cli("add/remove/list themes", { withr::local_rng_version("3.3.0") set.seed(24) start_app(.auto_close = TRUE) id <- default_app()$add_theme(list(".green" = list(color = "green"))) expect_true(id %in% names(default_app()$list_themes())) expect_snapshot({ cli_par(class = "green") cli_text(lorem_ipsum()) cli_end() }) default_app()$remove_theme(id) expect_false(id %in% names(default_app()$list_themes())) }) test_that("default theme is valid", { expect_error({ id <- default_app()$add_theme(builtin_theme()) default_app()$remove_theme(id) }, NA) }) test_that("explicit formatter is used, and combined", { id <- default_app()$add_theme(list( "span.emph" = list( fmt = function(x) paste0("(((", x, ")))"), before = "<<", after = ">>") )) on.exit(default_app()$remove_theme(id), add = TRUE) expect_snapshot( cli_text("this is {.emph it}, really") ) }) test_that("simple theme", { def <- simple_theme() expect_true(is.list(def)) expect_false(is.null(names(def))) expect_true(all(names(def) != "")) expect_true(all(vlapply(def, is.list))) }) test_that("user's override", { custom <- list(".alert" = list(before = "custom:")) override <- list(".alert" = list(after = "override:")) expect_snapshot(local({ start_app(theme = custom, .auto_close = FALSE) cli_alert("Alert!") stop_app() withr::local_options(cli.user_theme = override) start_app(theme = custom, .auto_close = FALSE) cli_alert("Alert!") stop_app() })) }) test_that("theme does not precompute Unicode symbols", { withr::local_options(cli.unicode = TRUE, cli.num_colors = 256L) start_app() msg <- NULL withCallingHandlers( cli_alert_success("ok"), cliMessage = function(m) { msg <<- m invokeRestart("muffleMessage") } ) expect_true(ansi_has_any(msg$message)) msg2 <- NULL withr::local_options(cli.unicode = FALSE, cli.num_colors = 1L) withCallingHandlers( cli_alert_success("ok2"), cliMessage = function(m) { msg2 <<- m invokeRestart("muffleMessage") } ) expect_equal(msg2$message, "v ok2\n") }) test_that("NULL will undo a style property", { expect_snapshot(local({ cli_alert("this has an arrow") cli_div(theme = list(.alert = list(before = NULL))) cli_alert("this does not") })) }) test_that_cli(configs = "ansi", "NULL will undo color", { expect_snapshot(local({ cli_alert("{.emph {.val this is blue}}") cli_div(theme = list(span.val = list(color = NULL))) cli_alert("{.emph {.val this is not}}") })) expect_snapshot(local({ cli_alert("{.emph {.val this is blue}}") cli_div(theme = list(span.val = list(color = "none"))) cli_alert("{.emph {.val this is not}}") })) }) withr::local_options(cli.theme = NULL, cli.user_theme = NULL) withr::local_options(cli.theme_dark = FALSE, cli.num_colors = 256) start_app() on.exit(stop_app(), add = TRUE) test_that_cli(configs = "ansi", "NULL will undo background color", { skip_if_not_installed("testthat", "3.1.2") expect_snapshot(local({ cli_alert("{.emph {.code this has bg color}}") cli_div(theme = list(span = list("background-color" = NULL))) cli_alert("{.emph {.code this does not}}") })) expect_snapshot(local({ cli_alert("{.emph {.code this has bg color}}") cli_div(theme = list(span = list("background-color" = "none"))) cli_alert("{.emph {.code this does not}}") })) }) cli/tests/testthat/test-package.R0000644000176200001440000000151314557444176016537 0ustar liggesusers test_that("No leftover SVG figures", { skip_on_cran() skip_on_covr() pkg_dir <- test_package_root() figs <- dir(file.path(pkg_dir, "man", "figures"), pattern = "[.]svg$") rd <- dir(file.path(pkg_dir, "man"), pattern = "[.]Rd$", full.names = TRUE) rd_figs <- unlist(lapply(rd, function(x) { grep("\\\\figure\\{", readLines(x), value = TRUE) })) rd_figs <- sub("^.*\\\\figure\\{(.*[.]svg).*$", "\\1", rd_figs) expect_equal( sort(figs), sort(unique(rd_figs)) ) figs2 <- dir(file.path(pkg_dir, "man", "figures", "README"), pattern = "[.]svg$") readme <- file.path(pkg_dir, "README.md") readme_figs <- grep("man/figures/", readLines(readme), value = TRUE) readme_figs <- sub("^.*man/figures/README/(.*[.]svg).*$", "\\1", readme_figs) expect_equal( sort(figs2), sort(unique(readme_figs)) ) }) cli/tests/testthat/progresstest/0000755000176200001440000000000014752736636016612 5ustar liggesuserscli/tests/testthat/progresstest/R/0000755000176200001440000000000014557444176017011 5ustar liggesuserscli/tests/testthat/progresstest/R/test.R0000644000176200001440000000122614557444176020114 0ustar liggesusers #' @useDynLib progresstest, .registration = TRUE, .fixes = "c_" NULL #' @export test_baseline <- function() { .Call(c_test0) } #' @export test_modulo <- function(progress = FALSE) { .Call(c_test00, progress) } #' @export test_cli <- function() { .Call(c_test1) } #' @export test_cli_unroll <- function() { this <- "test2" .Call(c_test2) } #' @export testx <- function() { this <- "testx" .Call(c_testx) } test3 <- function() { this <- "test3" test2() } call_with_cleanup <- function(ptr, ...) { .Call(c_cleancall_call, pairlist(ptr, ...), parent.frame()) } testc <- function() { this <- "testc" call_with_cleanup(c_testc) } cli/tests/testthat/progresstest/src/0000755000176200001440000000000014557444176017377 5ustar liggesuserscli/tests/testthat/progresstest/src/test.c0000644000176200001440000000454114557444176020526 0ustar liggesusers #include #include "cleancall.h" #include SEXP test0() { int i; int res = 0; for (i = 0; i < 2000000000; i++) { res += i % 2; } return ScalarInteger(res); } SEXP test00(SEXP progress) { int i; int res = 0; int progress_ = LOGICAL(progress)[0]; for (i = 0; i < 2000000000; i++) { if (i % 10000 == 0 && progress_) cli_progress_set(R_NilValue, i); res += i % 2; } return ScalarInteger(res); } SEXP test1() { int i; int res = 0; SEXP bar = PROTECT(cli_progress_bar(2000000000, NULL)); for (i = 0; i < 2000000000; i++) { if (CLI_SHOULD_TICK) cli_progress_set(bar, i); res += i % 2; } cli_progress_done(bar); UNPROTECT(1); return ScalarInteger(res); } SEXP testx() { int i; int res = 0; SEXP bar = PROTECT(cli_progress_bar(2000000000, NULL)); cli_progress_set_format( bar, "{%d} package{?s} {cli::pb_bar} | {cli::pb_elapsed}", 4 ); for (i = 0; i < 2000000000; i++) { if (CLI_SHOULD_TICK) cli_progress_set(bar, i); res += i % 2; } cli_progress_done(bar); UNPROTECT(1); return ScalarInteger(res); } SEXP test2() { int i = 0; int res = 0; SEXP bar = PROTECT(cli_progress_bar(2000000000, NULL)); int s, final, step = 2000000000 / 100000; for (s = 0; s < 100000; s++) { if (CLI_SHOULD_TICK) cli_progress_set(bar, i); final = (s + 1) * step; for (i = s * step; i < final; i++) { res += i % 2; } } cli_progress_done(bar); UNPROTECT(1); return ScalarInteger(res); } SEXP testc() { int i; int res = 0; SEXP bar = PROTECT(cli_progress_bar(2000000000, NULL)); for (i = 0; i < 2000000000; i++) { if (CLI_SHOULD_TICK) cli_progress_set(bar, i); res += i % 2; } error("sorry, can't do this any more"); cli_progress_done(bar); UNPROTECT(1); return ScalarInteger(res); } static const R_CallMethodDef CallEntries[] = { CLEANCALL_METHOD_RECORD, { "test0", (DL_FUNC) test0, 0 }, { "test00", (DL_FUNC) test00, 1 }, { "test1", (DL_FUNC) test1, 0 }, { "test2", (DL_FUNC) test2, 0 }, { "testx", (DL_FUNC) testx, 0 }, { "testc", (DL_FUNC) testc, 0 }, { NULL, NULL, 0 } }; void R_init_progresstest(DllInfo *dll) { R_registerRoutines(dll, NULL, CallEntries, NULL, NULL); R_useDynamicSymbols(dll, FALSE); R_forceSymbols(dll, TRUE); cleancall_fns_dot_call = Rf_findVar(Rf_install(".Call"), R_BaseEnv); } cli/tests/testthat/progresstest/src/cleancall.h0000644000176200001440000000274314557444176021474 0ustar liggesusers#ifndef CLEANCALL_H #define CLEANCALL_H #include #include #ifdef __cplusplus extern "C" { #endif // -------------------------------------------------------------------- // Internals // -------------------------------------------------------------------- typedef union {void* p; DL_FUNC fn;} fn_ptr; #if (defined(R_VERSION) && R_VERSION < R_Version(3, 4, 0)) SEXP R_MakeExternalPtrFn(DL_FUNC p, SEXP tag, SEXP prot); DL_FUNC R_ExternalPtrAddrFn(SEXP s); #endif // -------------------------------------------------------------------- // API for packages that embed cleancall // -------------------------------------------------------------------- // The R API does not have a setter for external function pointers SEXP cleancall_MakeExternalPtrFn(DL_FUNC p, SEXP tag, SEXP prot); void cleancall_SetExternalPtrAddrFn(SEXP s, DL_FUNC p); #define CLEANCALL_METHOD_RECORD \ {"cleancall_call", (DL_FUNC) &cleancall_call, 2} SEXP cleancall_call(SEXP args, SEXP env); extern SEXP cleancall_fns_dot_call; void cleancall_init(); // -------------------------------------------------------------------- // Public API // -------------------------------------------------------------------- #define R_CLEANCALL_SUPPORT 1 SEXP r_with_cleanup_context(SEXP (*fn)(void* data), void* data); void r_call_on_exit(void (*fn)(void* data), void* data); void r_call_on_early_exit(void (*fn)(void* data), void* data); int r_cleancall_is_active(); #ifdef __cplusplus } #endif #endif cli/tests/testthat/progresstest/src/cleancall.c0000644000176200001440000001026314557444176021463 0ustar liggesusers#define R_NO_REMAP #include #include "cleancall.h" #if (defined(R_VERSION) && R_VERSION < R_Version(3, 4, 0)) SEXP R_MakeExternalPtrFn(DL_FUNC p, SEXP tag, SEXP prot) { fn_ptr ptr; ptr.fn = p; return R_MakeExternalPtr(ptr.p, tag, prot); } DL_FUNC R_ExternalPtrAddrFn(SEXP s) { fn_ptr ptr; ptr.p = R_ExternalPtrAddr(s); return ptr.fn; } #endif // The R API does not have a setter for function pointers SEXP cleancall_MakeExternalPtrFn(DL_FUNC p, SEXP tag, SEXP prot) { fn_ptr tmp; tmp.fn = p; return R_MakeExternalPtr(tmp.p, tag, prot); } void cleancall_SetExternalPtrAddrFn(SEXP s, DL_FUNC p) { fn_ptr ptr; ptr.fn = p; R_SetExternalPtrAddr(s, ptr.p); } // Initialised at load time with the `.Call` primitive SEXP cleancall_fns_dot_call = NULL; void cleancall_init() { cleancall_fns_dot_call = Rf_findVar(Rf_install(".Call"), R_BaseEnv); } struct eval_args { SEXP call; SEXP env; }; static SEXP eval_wrap(void* data) { struct eval_args* args = (struct eval_args*) data; return Rf_eval(args->call, args->env); } SEXP cleancall_call(SEXP args, SEXP env) { SEXP call = PROTECT(Rf_lcons(cleancall_fns_dot_call, args)); struct eval_args data = { call, env }; SEXP out = r_with_cleanup_context(&eval_wrap, &data); UNPROTECT(1); return out; } static SEXP callbacks = NULL; // Preallocate a callback static void push_callback(SEXP stack) { SEXP top = CDR(stack); SEXP early_handler = PROTECT(Rf_allocVector(LGLSXP, 1)); SEXP fn_extptr = PROTECT(cleancall_MakeExternalPtrFn(NULL, R_NilValue, R_NilValue)); SEXP data_extptr = PROTECT(R_MakeExternalPtr(NULL, early_handler, R_NilValue)); SEXP cb = Rf_cons(Rf_cons(fn_extptr, data_extptr), top); SETCDR(stack, cb); UNPROTECT(3); } struct data_wrapper { SEXP (*fn)(void* data); void *data; SEXP callbacks; int success; }; static void call_exits(void* data) { // Remove protecting node. Don't remove the preallocated callback on // the top as it might contain a handler when something went wrong. SEXP top = CDR(callbacks); // Restore old stack struct data_wrapper* state = data; callbacks = (SEXP) state->callbacks; // Handlers should not jump while (top != R_NilValue) { SEXP cb = CAR(top); top = CDR(top); void (*fn)(void*) = (void (*)(void*)) R_ExternalPtrAddrFn(CAR(cb)); void *data = (void*) R_ExternalPtrAddr(CDR(cb)); int early_handler = LOGICAL(R_ExternalPtrTag(CDR(cb)))[0]; // Check for empty pointer in preallocated callbacks if (fn) { if (!early_handler || !state->success) fn(data); } } } static SEXP with_cleanup_context_wrap(void *data) { struct data_wrapper* cdata = data; SEXP ret = cdata->fn(cdata->data); cdata->success = 1; return ret; } SEXP r_with_cleanup_context(SEXP (*fn)(void* data), void* data) { // Preallocate new stack before changing `callbacks` to avoid // leaving the global variable in a bad state if alloc fails SEXP new = PROTECT(Rf_cons(R_NilValue, R_NilValue)); push_callback(new); if (!callbacks) callbacks = R_NilValue; SEXP old = callbacks; callbacks = new; struct data_wrapper state = { fn, data, old, 0 }; SEXP out = R_ExecWithCleanup(with_cleanup_context_wrap, &state, &call_exits, &state); UNPROTECT(1); return out; } int r_cleancall_is_active() { return callbacks != NULL; } static void call_save_handler(void (*fn)(void *data), void* data, int early) { if (!callbacks) { fn(data); Rf_error("Internal error: Exit handler pushed outside " "of an exit context"); } SEXP cb = CADR(callbacks); // Update pointers cleancall_SetExternalPtrAddrFn(CAR(cb), (DL_FUNC) fn); R_SetExternalPtrAddr(CDR(cb), data); LOGICAL(R_ExternalPtrTag(CDR(cb)))[0] = early; // Preallocate the next callback in case the allocator jumps push_callback(callbacks); } void r_call_on_exit(void (*fn)(void* data), void* data) { call_save_handler(fn, data, /* early = */ 0); } void r_call_on_early_exit(void (*fn)(void* data), void* data) { call_save_handler(fn, data, /* early = */ 1); } cli/tests/testthat/progresstest/NAMESPACE0000644000176200001440000000031414557444176020025 0ustar liggesusers# Generated by roxygen2: do not edit by hand export(test_baseline) export(test_cli) export(test_cli_unroll) export(test_modulo) export(testx) useDynLib(progresstest, .registration = TRUE, .fixes = "c_") cli/tests/testthat/progresstest/DESCRIPTION0000644000176200001440000000050214557444176020313 0ustar liggesusersPackage: progresstest Title: Testing Terminal Progress Bars Version: 1.0.0 Authors@R: person("Gabor", "Csardi", , "csardi.gabor@gmail.com", role = c("aut", "cre")) Description: Test progress bars from the cli package. License: MIT + file LICENSE Imports: cli LinkingTo: cli RoxygenNote: 7.1.1.9001 Encoding: UTF-8 cli/tests/testthat/test-bullets.R0000644000176200001440000000155414557444176016623 0ustar liggesusers start_app() on.exit(stop_app(), add = TRUE) test_that_cli("bullets", { expect_snapshot(cli_bullets(c( "noindent", " " = "space", "v" = "success", "x" = "danger", "!" = "warning", "i" = "info", "*" = "bullet", ">" = "arrow" ))) }) test_that_cli("bullets glue", { expect_snapshot(cli_bullets(c( "noindent {.key {1:3}}", " " = "space {.key {1:3}}", "v" = "success {.key {1:3}}", "x" = "danger {.key {1:3}}", "!" = "warning {.key {1:3}}", "i" = "info {.key {1:3}}", "*" = "bullet {.key {1:3}}", ">" = "arrow {.key {1:3}}" ))) }) test_that_cli("bullets wrapping", { txt <- strrep("This is some text that is longer than the width. ", 3) expect_snapshot(cli_bullets(c( txt, " " = txt, "v" = txt, "x" = txt, "!" = txt, "i" = txt, "*" = txt, ">" = txt ))) }) cli/tests/testthat/test-assertions.R0000644000176200001440000000542214557444176017341 0ustar liggesusers test_that("is_string", { strings <- list("foo", "", "111", "1", "-", "NA") not_strings <- list(1, character(), NA_character_, NA, c("foo", NA), c("1", "2"), NULL) for (p in strings) { expect_true(is_string(p)) expect_silent(stopifnot(is_string(p))) } for (n in not_strings) { expect_false(is_string(n)) expect_error( stopifnot(is_string(n)), "is_string(n) is not TRUE", fixed = TRUE ) } }) test_that("is_border_style", { expect_true(is_border_style(rownames(box_styles())[1])) expect_false(is_border_style("blahblahxxx")) expect_silent(stopifnot(is_border_style(rownames(box_styles())[1]))) expect_error( stopifnot(is_border_style("blahblahxxx")), "is_border_style(\"blahblahxxx\") is not TRUE", fixed = TRUE ) }) test_that("is_padding_or_margin", { good <- list(1, 0, 0L, 1L, 237, c(1,2,3,4), c(0,0,0,0), rep(1L, 4)) bad <- list(numeric(), integer(), c(1,2), c(1L, 2L, 3L), 1:5, "1", c("1", "2", "3", "1"), NA, NA_real_, NA_integer_, c(1,2,NA,1), c(1L,NA,3L)) for (g in good) { expect_true(is_padding_or_margin(g)) expect_silent(stopifnot(is_padding_or_margin(g))) } for (b in bad) { expect_false(is_padding_or_margin(b)) expect_error( stopifnot(is_padding_or_margin(b)), "is_padding_or_margin(b) is not TRUE", fixed = TRUE ) } }) test_that("is_col", { good <- list("red", "orange", NULL, col_red) bad <- list(c("red", "orange"), character(), NA_character_) for (g in good) { expect_true(is_col(g)) expect_silent(stopifnot(is_col(g))) } for (b in bad) { expect_false(is_col(b)) expect_error( stopifnot(is_col(b)), "is_col(b) is not TRUE", fixed = TRUE ) } }) test_that("is_count", { counts <- list(1, 1L, 0, 0L, 42, 42L) not_counts <- list(c(1, 2), numeric(), NA_integer_, NA_real_, NA, 1.1, NULL, "1") for (c in counts) { expect_true(is_count(c)) expect_silent(stopifnot(is_count(c))) } for (n in not_counts) { expect_false(is_count(n)) expect_error( stopifnot(is_count(n)), "is_count(n) is not TRUE", fixed = TRUE ) } }) test_that("is_tree_style", { good <- list( list(h = "1", v = "2", l = "3", j = "4"), list(j = "4", v = "2", h = "1", l = "3") ) bad <- list( NULL, 1:4, c(h = "1", v = "2", l = "3", j = "4"), list(h = "1", v = "2", l = "3", j = "4", x = "10"), list(h = "1", v = c("2", "3"), l = "3", j = "4"), list(h = "1", v = "2", l = character(), j = "4"), list(h = "1", v = "2", l = 3, j = "4"), list("1", v = "2", l = "3", j = "4"), list("1", "2", "3", "4") ) for (x in good) expect_true (is_tree_style(x)) for (x in bad ) expect_false(is_tree_style(x)) }) cli/tests/testthat/test-progress-handlers.R0000644000176200001440000000322414752735214020600 0ustar liggesusers test_that("cli_progress_builtin_handlers", { expect_true(is.character(cli_progress_builtin_handlers())) expect_true(all( c("cli", "shiny", "rstudio") %in% cli_progress_builtin_handlers() )) }) test_that("cli_progress_select_handlers #1", { # only handlers withr::local_options( "cli.progress_handlers" = c("foo", "bar"), "cli.progress_handlers_force" = c("forced"), "cli.progress_handlers_only" = "logger" ) expect_equal( names(cli_progress_select_handlers(list(), environment())), "logger" ) }) test_that("cli_progress_select_handlers #2", { # auto-select withr::local_options( "cli.progress_handlers" = c("foo", "bar", "baz"), "cli.progress_handlers_force" = NULL, "cli.progress_handlers_only" = NULL ) fake <- list( foo = list(able = function(...) FALSE), bar = list(), baz = list(), forced = list() ) local_mocked_bindings(builtin_handlers = function() fake) expect_equal(cli_progress_select_handlers(), fake["bar"]) }) test_that("cli_progress_select_handlers #3", { # auto-select withr::local_options( "cli.progress_handlers" = c("foo", "bar", "baz"), "cli.progress_handlers_force" = c("forced"), "cli.progress_handlers_only" = NULL ) fake <- list( foo = list(able = function(...) FALSE), bar = list(able = function(...) TRUE), baz = list(), forced = list() ) local_mocked_bindings(builtin_handlers = function() fake) expect_equal(cli_progress_select_handlers(), fake[c("bar", "forced")]) }) test_that("builtin_handlers", { expect_true(is.list(builtin_handlers())) expect_true(all(c("cli", "shiny", "rstudio") %in% names(builtin_handlers()))) }) cli/tests/testthat/test-ansiex.R0000644000176200001440000004324214557444176016440 0ustar liggesusers test_that("cli_ansi_string", { right <- c("cli_ansi_string", "ansi_string", "character") expect_equal(class(ansi_string("foobar")), right) expect_equal(class(ansi_string(133)), right) expect_equal(class(ansi_string(ansi_string(134))), right) }) test_that("ansi_regex", { # somewhat special sequences cases <- list( list("foo\033[39;49mbar", "foobar"), list("foo\033[1;3;4mbar", "foobar"), list("foo\033[1;;4mbar", "foobar"), list("foo\033[mbar", "foobar") ) for (case in cases) { expect_equal(gsub(ansi_regex(), "", case[[1]], perl = TRUE), case[[2]]) } }) test_that("ansi_has_any works", { withr::local_options(list( cli.num_colors = 256L, cli.hyperlink = TRUE )) expect_false(ansi_has_any("foobar")) funcs <- ls(asNamespace("cli"), pattern = "^col_|^bg_|^style_") for (sym in setdiff(funcs, "style_hyperlink")) { fun <- get(sym, envir = asNamespace("cli")) expect_true(ansi_has_any(fun("foo", "bar")), label = sym) } }) test_that("ansi_strip works", { withr::local_options(list( cli.num_colors = 256L, cli.hyperlink = TRUE )) expect_equal("", ansi_strip("")) expect_equal("foobar", ansi_strip("foobar")) expect_equal( "foobar", ansi_strip(col_red(style_underline(style_bold("foobar")))) ) funcs <- ls(asNamespace("cli"), pattern = "^col_|^bg_|^style_") for (sym in setdiff(funcs, "style_hyperlink")) { fun <- get(sym, envir = asNamespace("cli")) ans <- if (sym == "style_hyperlink") "foo" else "foobar" expect_equal(ans, ansi_strip(fun("foo", "bar"))) } }) str <- c("", "plain", "\033[31m", "\033[39m", "\033[31mred\033[39m", "\033[31mred\033[39m\033[31mred\033[39m", "foo\033[31mred\033[39m", "\033[31mred\033[39mfoo") test_that("ansi_nchar", { withr::local_options(list(cli.num_colors = 256L)) for (s in str) { expect_equal(ansi_nchar(s), nchar(ansi_strip(s)), info = s) } }) test_that("ansi_nchar wide characters", { expect_equal(ansi_nchar("\u231a", "width"), 2L) }) test_that("ansi_substr bad input", { expect_snapshot( error = TRUE, ansi_substr("foobar", NULL, 10) ) expect_snapshot( error = TRUE, ansi_substr("foobar", 10, NULL) ) expect_snapshot( error = TRUE, ansi_substr("foobar", "bad", "bad") ) }) test_that("ansi_substr", { withr::local_options(list(cli.num_colors = 256L)) for (s in str) { for (i in 1 %:% ansi_nchar(s)) { for (j in i %:% ansi_nchar(s)) { expect_equal(ansi_strip(ansi_substr(s, i, j)), substr(ansi_strip(s), i, j), info = paste(s, i, j)) } } } }) test_that("ansi_substr keeps color", { withr::local_options(list(cli.num_colors = 256L)) expect_equal( ansi_substr("\033[31mred\033[39m", 1, 1), ansi_string("\033[31mr\033[39m") ) expect_equal( ansi_substr("foo\033[31mred\033[39m", 4, 4), ansi_string("\033[31mr\033[39m") ) expect_equal( ansi_substr("foo\033[31mred\033[39mbar", 4, 4), ansi_string("\033[31mr\033[39m") ) expect_equal( ansi_substr("\033[31mred\033[39mfoo\033[31mred\033[39mbar", 7, 7), ansi_string("\033[31mr\033[39m") ) }) test_that("ansi_substr, start after string end", { withr::local_options(list(cli.num_colors = 256L)) expect_equal(ansi_substr("red", 4, 4), ansi_string("")) expect_equal(ansi_substr("red", 4, 5), ansi_string("")) expect_equal(ansi_strip(ansi_substr("\033[31mred\033[39m", 4, 4)), "") expect_equal(ansi_strip(ansi_substr("\033[31mred\033[39m", 4, 5)), "") expect_equal(ansi_substr("red", 3, 4), ansi_string("d")) expect_equal(ansi_substr("red", 3, 5), ansi_string("d")) expect_equal(ansi_strip(ansi_substr("\033[31mred\033[39m", 3, 4)), "d") expect_equal(ansi_strip(ansi_substr("\033[31mred\033[39m", 3, 5)), "d") }) test_that("ansi_substr, multiple strings", { withr::local_options(list(cli.num_colors = 256L)) set.seed(42) for (i in 1:100) { strs <- sample(str, 4) num_starts <- sample(1:5, 1) num_stops <- sample(1:5, 1) starts <- sample(1:5, num_starts, replace = TRUE) stops <- sample(1:5, num_stops, replace = TRUE) r1 <- ansi_strip(ansi_substr(strs, starts, stops)) r2 <- substr(ansi_strip(strs), starts, stops) expect_equal(r1, r2) } }) test_that("ansi_substr corner cases", { withr::local_options(list(cli.num_colors = 256L)) # Zero length input c0 <- character(0L) o0 <- structure(list(), class="abc") co0 <- structure(character(0L), class="abc") expect_identical(ansi_substr(c0, 1, 1), ansi_string(substr(c0, 1, 1))) expect_identical(ansi_substr(o0, 1, 1), ansi_string(substr(o0, 1, 1))) expect_identical(ansi_substr(co0, 1, 1), ansi_string(substr(co0, 1, 1))) expect_identical( ansi_substring(c0, 1, 1), ansi_string(substring(c0, 1, 1)) ) expect_identical( ansi_substring(o0, 1, 1), ansi_string(substring(o0, 1, 1)) ) expect_identical( ansi_substring(co0, 1, 1), ansi_string(substring(co0, 1, 1)) ) # Character start/stop expect_identical( ansi_substr("abc", "1", 1), ansi_string(substr("abc", "1", 1)) ) expect_identical( ansi_substr("abc", 1, "1"), ansi_string(substr("abc", 1, "1")) ) # non-numeric arguments cause errors; NOTE: this actually "works" # with 'substr' but not implemented in 'ansi_substr' expect_snapshot( error = TRUE, ansi_substr("abc", "hello", 1) ) }) test_that("ansi_substring", { withr::local_options(list(cli.num_colors = 256L)) for (s in str) { for (i in 1 %:% ansi_nchar(s)) { for (j in i %:% ansi_nchar(s)) { expect_equal(ansi_strip(ansi_substring(s, i, j)), substring(ansi_strip(s), i, j), info = paste(s, i, j)) } } } }) test_that("ansi_substring, multiple strings", { withr::local_options(list(cli.num_colors = 256L)) set.seed(42) for (i in 1:100) { strs <- sample(str, 4) num_starts <- sample(1:5, 1) num_stops <- sample(1:5, 1) starts <- sample(1:5, num_starts, replace = TRUE) stops <- sample(1:5, num_stops, replace = TRUE) r1 <- ansi_strip(ansi_substring(strs, starts, stops)) r2 <- substring(ansi_strip(strs), starts, stops) expect_equal(r1, r2) } }) test_that("ansi_substring corner cases", { withr::local_options(list(cli.num_colors = 256L)) # Zero length input c0 <- character(0L) o0 <- structure(list(), class="abc") co0 <- structure(character(0L), class="abc") expect_identical( ansi_substring(c0, 1, 1), ansi_string(substring(c0, 1, 1)) ) expect_identical( ansi_substring(o0, 1, 1), ansi_string(substring(o0, 1, 1)) ) expect_identical( ansi_substring(co0, 1, 1), ansi_string(substring(co0, 1, 1)) ) }) test_that("ansi_strsplit", { withr::local_options(list(cli.num_colors = 256L)) red <- "\033[31mred\033[39m" str <- "plain-plain" expect_equal( ansi_strsplit(str, "-"), lapply(strsplit(str, "-"), ansi_string) ) str <- paste0(red, "-plain") expect_equal( ansi_strip(ansi_strsplit(str, "-")[[1]]), strsplit(ansi_strip(str), "-")[[1]] ) expect_equal( ansi_strsplit(str, "e"), list(ansi_string(c("\033[31mr\033[39m", "\033[31md\033[39m-plain"))) ) str <- paste0(red, "-", red, "-", red) expect_equal( ansi_strip(ansi_strsplit(str, "-")[[1]]), strsplit(ansi_strip(str), "-")[[1]] ) # with leading and trailing separators str.2 <- paste0("-", red, "-", red, "-", red, "-") expect_equal(ansi_strip(ansi_strsplit(str.2, "-")[[1]]), strsplit(ansi_strip(str.2), "-")[[1]]) # greater than length 1 str.3 <- paste0("-", c(col_green("hello"), col_red("goodbye")), "-world-") expect_equal(ansi_strip(unlist(ansi_strsplit(str.3, "-"))), unlist(strsplit(ansi_strip(str.3), "-"))) }) test_that("ansi_strsplit multiple strings", { withr::local_options(list(cli.num_colors = 256L)) red <- "\033[31mred\033[39m" str <- c( paste0("plain-plain-", red, "-plain-", red), paste0(red, "-", red), red ) r1 <- lapply(ansi_strsplit(str, "-"), ansi_strip) r2 <- strsplit(ansi_strip(str), "-") expect_equal(r1, r2) }) test_that("ansi_strsplit edge cases", { withr::local_options(list(cli.num_colors = 256L)) expect_equal(ansi_strsplit("", "-"), list(ansi_string(character(0L)))) expect_equal( ansi_strip(ansi_strsplit("\033[31m\033[39m", "-")[[1]]), character(0L) ) # special cases expect_equal(ansi_strsplit("", ""), lapply(strsplit("", ""), ansi_string)) expect_equal( ansi_strsplit("a", "a"), lapply(strsplit("a", "a"), ansi_string) ) # this following test isn't working yet expect_equal( ansi_strsplit("a", ""), lapply(strsplit("a", ""), ansi_string) ) expect_equal( ansi_strsplit("", "a"), lapply(strsplit("", "a"), ansi_string) ) # Longer strings expect_identical( ansi_strsplit(c("", "a", "aa"), "a"), lapply(strsplit(c("", "a", "aa"), "a"), ansi_string) ) expect_identical( ansi_strsplit(c("abaa", "ababza"), "b."), lapply(strsplit(c("abaa", "ababza"), "b."), ansi_string) ) }) test_that("Weird length 'split'", { withr::local_options(list(cli.num_colors = 256L)) expect_snapshot( error = TRUE, ansi_strsplit(c("ab", "bd"), c("b", "d")) ) expect_identical( ansi_strsplit("ab", NULL), lapply(strsplit("ab", NULL), ansi_string) ) expect_identical( ansi_strsplit("ab", character(0L)), lapply(strsplit("ab", character(0L)), ansi_string) ) }) test_that("ansi_align", { withr::local_options(list(cli.num_colors = 256L)) expect_equal(ansi_align(character()), ansi_string(character())) expect_equal(ansi_align("", 0), ansi_string("")) expect_equal(ansi_align(" ", 0), ansi_string(" ")) expect_equal(ansi_align(" ", 1), ansi_string(" ")) expect_equal(ansi_align(" ", 2), ansi_string(" ")) expect_equal(ansi_align("a", 1), ansi_string("a")) expect_equal(ansi_align(letters, 1), ansi_string(letters)) expect_equal(ansi_align(letters, 0), ansi_string(letters)) expect_equal(ansi_align(letters, -1), ansi_string(letters)) expect_equal(ansi_align(letters, 2), ansi_string(paste0(letters, " "))) expect_equal( ansi_align(letters, 3, "center"), ansi_string(paste0(" ", letters, " ")) ) expect_equal( ansi_align(letters, 2, "right"), ansi_string(paste0(" ", letters)) ) expect_equal( ansi_align(c("foo", "foobar", "", "a"), 6, "left"), ansi_string(c("foo ", "foobar", " ", "a "))) expect_equal( ansi_align(c("foo", "foobar", "", "a"), 6, "center"), ansi_string(c(" foo ", "foobar", " ", " a "))) expect_equal( ansi_align(c("foo", "foobar", "", "a"), 6, "right"), ansi_string(c(" foo", "foobar", " ", " a"))) # #54: alignment of wide characters expect_equal( ansi_align(c("foo", "\u6210\u4ea4\u65e5", "", "a"), 6, "left"), ansi_string(c("foo ", "\u6210\u4ea4\u65e5", " ", "a "))) expect_equal( ansi_align(c("foo", "\u6210\u4ea4\u65e5", "", "a"), 6, "center"), ansi_string(c(" foo ", "\u6210\u4ea4\u65e5", " ", " a "))) expect_equal( ansi_align(c("foo", "\u6210\u4ea4\u65e5", "", "a"), 6, "right"), ansi_string(c(" foo", "\u6210\u4ea4\u65e5", " ", " a"))) }) test_that("stripping hyperlinks", { withr::local_options(list(cli.hyperlink = TRUE)) x <- unclass(style_hyperlink("foo", "https://r-pkg.org")) expect_equal( ansi_strip(paste0("1111-", x, "-2222-", x, "-333")), "1111-foo-2222-foo-333" ) }) test_that("ansi_trimws", { cases <- list( list(character(), ansi_string(character())), list(1, ansi_string(1)), list("", ansi_string("")), list("foo", ansi_string("foo")), list(" foo ", ansi_string("foo")), list(c("foo", "bar"), ansi_string(c("foo", "bar"))), list(col_red(c(" colored ")), ansi_string(col_red("colored"))), list( paste0(" ", col_red(c(" colored ")), " "), ansi_string(col_red("colored"))) ) for (case in cases) expect_equal(ansi_trimws(case[[1]]), case[[2]]) cases_left <- list( list(character(), ansi_string(character())), list(1, ansi_string(1)), list("", ansi_string("")), list("foo", ansi_string("foo")), list(" foo ", ansi_string("foo ")), list(c("foo", "bar"), ansi_string(c("foo", "bar"))), list(col_red(c(" colored ")), ansi_string(col_red("colored "))), list( paste0(" ", col_red(c(" colored ")), " "), ansi_string(paste0(col_red("colored "), " "))) ) for (case in cases_left) { expect_equal(ansi_trimws(case[[1]], "left"), case[[2]]) } cases_right <- list( list(character(), ansi_string(character())), list(1, ansi_string(1)), list("", ansi_string("")), list("foo", ansi_string("foo")), list(" foo ", ansi_string(" foo")), list(c(" foo ", " bar "), ansi_string(c(" foo", " bar"))), list(c("foo", "bar"), ansi_string(c("foo", "bar"))), list(col_red(c(" colored ")), ansi_string(col_red(" colored"))), list( paste0(" ", col_red(c(" colored ")), " "), ansi_string(paste0(" ", col_red(" colored")))) ) for (case in cases_right) { expect_equal(ansi_trimws(case[[1]], "right"), case[[2]]) } }) test_that("ansi_strwrap simple", { cases = list( list(character(), character()), list("", ""), list("foo", "foo"), list(1, "1"), list(c("foo", "bar"), c("foo", "bar")) ) for (case in cases) { expect_equal(ansi_strwrap(case[[1]], 20), ansi_string(case[[2]])) } }) test_that("ansi_strwrap simple styled", { cases = list( list(col_red("foo"), col_red("foo")), list(col_red(c("foo", "bar")), col_red(c("foo", "bar"))), list( paste0("foo", bg_red(" "), "bar"), paste0("foo", bg_red(" "), "bar") ) ) for (case in cases) { expect_equal(ansi_strwrap(case[[1]], 20), ansi_string(case[[2]])) } }) test_that("ansi_strwrap", { txt0 <- glue::glue_col(" {col_red Velit occaecat} quis culpa occaecat. {col_green Pariatur} \\ ad veniam pariatur {bg_blue consectetur}. Dolore aliquip et \\ {style_underline consequat Lorem consectetur} dolor. Irure id velit \\ proident elit veniam eu exercitation nisi laboris officia. Qui \\ {col_red sunt occaecat} cillum {col_red sit commodo sit. \\ Culpa} aliquip et consectetur ullamco aliqua Lorem laborum dolore. ") txt <- paste0(txt0, "\n\t \n", txt0) expect_equal( ansi_strip(ansi_strwrap(txt0, 40)), strwrap(ansi_strip(txt0), 40) ) expect_equal( ansi_strip(ansi_strwrap(txt, 40)), strwrap(ansi_strip(txt), 40) ) expect_equal( ansi_strip(ansi_strwrap(txt, 40, indent = 2)), strwrap(ansi_strip(txt), 40, indent = 2) ) expect_equal( ansi_strip(ansi_strwrap(txt, 40, exdent = 2)), strwrap(ansi_strip(txt), 40, exdent = 2) ) expect_equal( ansi_strip(ansi_strwrap(txt, 40, indent = 2, exdent = 4)), strwrap(ansi_strip(txt), 40, indent = 2, exdent = 4) ) }) test_that("ansi_strwrap double width", { expect_equal( ansi_strwrap("\U0001F477 1 2 3", 4), ansi_string(c("\U0001f477", "1 2", "3")) ) }) test_that("ansi_strwrap newlines", { expect_equal( ansi_strwrap("\033[32mv\033[39m hello world.\nxxx"), ansi_string("\033[32mv\033[39m hello world. xxx") ) }) test_that("ansi_strwrap and \f edge cases", { expect_equal( ansi_strwrap("\033[32mfoo\fbar\033[39m"), ansi_string(c("\033[32mfoo\033[39m", "\033[32mbar\033[39m")) ) expect_equal( ansi_strwrap("\033[32m\ffoo\f\033[39m"), ansi_string(c("", "\033[32mfoo\033[39m", "")) ) }) test_that_cli(configs = c("plain", "ansi"), "ansi_strtrim", { withr::local_options(c(cli.unicode = FALSE)) setup_unicode_width_fix() cases <- list( list("", ansi_string("")), list("1", ansi_string("1")), list("123456789", ansi_string("123456789")), list("1234567890", ansi_string("1234567890")), list("12345678901", ansi_string("1234567...")), list( strrep("\u231A", 6), ansi_string(paste0(strrep("\u231A", 3), "..."))), list(col_red("1"), col_red("1")), list(c("foo", NA, col_red("bar")), ansi_string(c("foo", NA, col_red("bar")))) ) for (case in cases) expect_equal(ansi_strtrim(case[[1]], 10), case[[2]]) }) test_that("ansi_strtrim with zero-length ellipsis", { expect_snapshot({ ansi_strtrim("12345", 1, ellipsis = "") ansi_strtrim("12345", 3, ellipsis = "") ansi_strtrim("12345", 5, ellipsis = "") }) }) test_that("ansi_strtrim errors", { expect_snapshot( error = TRUE, ansi_strtrim("foobar", -1) ) }) test_that("ansi_strtrim edge cases", { expect_snapshot({ ansi_strtrim("foobar", width = 3, ellipsis = "...") ansi_strtrim("foobar", width = 2, ellipsis = "...") ansi_strtrim("foobar", width = 1, ellipsis = "...") ansi_strtrim("foobar", width = 0, ellipsis = "...") }) }) test_that("ansi_columns", { withr::local_options(c(cli.unicode = FALSE)) local_edition(3) expect_equal(ansi_columns(character()), ansi_string(character())) expect_snapshot_output( cat(ansi_columns(paste("foo", 1:10), width = 40), sep = "\n") ) txt60 <- strrep("1234567890", 6) expect_snapshot_output( cat(ansi_columns(txt60, width = 15), sep = "\n") ) }) test_that_cli(configs = c("plain", "ansi"), "ansi_toupper", { x <- paste0( col_red("Red "), "normal ", style_bold(col_green("green")) ) expect_snapshot(local({ cat_line(x) cat_line(ansi_toupper(x)) })) }) test_that_cli(configs = c("plain", "ansi"), "ansi_tolower", { x <- paste0( col_red("Red "), "NORMAL ", style_bold(col_green("grEeN")) ) expect_snapshot(local({ cat_line(x) cat_line(ansi_tolower(x)) })) }) test_that_cli(configs = c("plain", "ansi"), "ansi_chartr", { x <- paste0( col_red("Red "), "normal ", style_bold(col_green("green")) ) expect_snapshot(local({ cat_line(x) cat_line(ansi_chartr(" R_", "-r*", x)) })) }) cli/tests/testthat/test-boxes.R0000644000176200001440000000357614557444176016277 0ustar liggesusers test_that_cli(configs = c("plain", "unicode"), "empty label", { expect_snapshot(boxx("")) }) test_that_cli(configs = c("plain", "unicode"), "empty label 2", { expect_snapshot(boxx(character())) }) test_that_cli(configs = c("plain", "unicode"), "label", { expect_snapshot(boxx("label")) }) test_that_cli(configs = c("plain", "unicode"), "label vector", { expect_snapshot(boxx(c("label", "l2"))) }) test_that_cli(configs = c("plain", "unicode"), "border style", { expect_snapshot(boxx("label", border_style = "classic")) }) test_that_cli(configs = c("plain", "unicode"), "padding", { expect_snapshot(boxx("label", padding = 2)) expect_snapshot(boxx("label", padding = c(1,2,1,2))) expect_snapshot(boxx("label", padding = c(1,2,0,2))) expect_snapshot(boxx("label", padding = c(1,2,0,0))) }) test_that_cli(configs = c("plain", "unicode"), "margin", { expect_snapshot(boxx("label", margin = 1)) expect_snapshot(boxx("label", margin = c(1,2,3,4))) expect_snapshot(boxx("label", margin = c(0,1,2,0))) }) test_that_cli(configs = c("plain", "unicode"), "float", { expect_snapshot(boxx("label", float = "center", width = 20)) expect_snapshot(boxx("label", float = "right", width = 20)) }) test_that_cli("background_col", { expect_snapshot(boxx("label", background_col = "red")) expect_snapshot(boxx("label", background_col = col_red)) }) test_that_cli("border_col", { expect_snapshot(boxx("label", border_col = "red")) expect_snapshot(boxx("label", border_col = col_red)) }) test_that_cli(configs = c("plain", "unicode"), "align", { expect_snapshot(boxx(c("label", "l2"), align = "center")) expect_snapshot(boxx(c("label", "l2"), align = "right")) }) test_that_cli(configs = c("plain", "unicode"), "header", { expect_snapshot(boxx("foobar", header = "foo")) }) test_that_cli(configs = c("plain", "unicode"), "footer", { expect_snapshot(boxx("foobar", footer = "foo")) }) cli/tests/testthat/test-progress-bar.R0000644000176200001440000000231014557444176017546 0ustar liggesusers test_that_cli("make_progress_bar", { withr::local_options( cli.progress_bar_style = NULL, cli.progress_bar_style_unicode = NULL, cli.progress_bar_style_ascii = NULL ) expect_snapshot(make_progress_bar(.5)) }) test_that_cli(configs = "fancy", "cli_progress_styles", { withr::local_options( cli.progress_bar_style_unicode = NULL, cli.progress_bar_style_ascii = NULL ) withr::local_options(cli.progress_bar_style = "classic") expect_snapshot(make_progress_bar(.5)) withr::local_options(cli.progress_bar_style = "squares") expect_snapshot(make_progress_bar(.5)) withr::local_options(cli.progress_bar_style = "dot") expect_snapshot(make_progress_bar(.5)) withr::local_options(cli.progress_bar_style = "fillsquares") expect_snapshot(make_progress_bar(.5)) withr::local_options(cli.progress_bar_style = "bar") expect_snapshot(make_progress_bar(.5)) }) test_that_cli(configs = c("plain", "unicode"), "custom style", { mybar <- list(complete = "X", incomplete = "O", current = ">") withr::local_options( cli.progress_bar_style = mybar, cli.progress_bar_style_unicode = NULL, cli.progress_bar_style_ascii = NULL ) expect_snapshot(make_progress_bar(.5)) }) cli/tests/testthat/test-containers.R0000644000176200001440000000461114557444176017313 0ustar liggesusers start_app() on.exit(stop_app(), add = TRUE) test_that("auto closing", { expect_snapshot(local({ cli_div(theme = list(".xx .emph" = list(before = "itsu:"))) f <- function() { cli_par(class = "xx") cli_text("foo {.emph blah} bar") } # this has the marker f() # but this does not, because the .xx par was closed cli_text("foo {.emph blah} bar") })) }) test_that("opt out of auto closing", { expect_snapshot(local({ cli_div(theme = list(".xx .emph" = list(before = "itsu:"))) id <- NULL f <- function() { id <<- cli_par(class = "xx", .auto_close = FALSE) cli_text("foo {.emph blah} bar") } f() # Still active cli_text("foo {.emph blah} bar") ## close explicitly expect_false(is.null(id)) cli_end(id) cli_text("foo {.emph blah} bar") })) }) test_that("auto closing with special env", { expect_snapshot(local({ cli_div(theme = list(".xx .emph" = list(before = "itsu:"))) f <- function() { g() # Still active cli_text("foo {.emph blah} bar") } g <- function() { cli_par(class = "xx", .auto_close = TRUE, .envir = parent.frame()) cli_text("foo {.emph blah} bar") } f() # Not active any more cli_text("foo {.emph blah} bar") })) }) test_that("div with special style", { expect_snapshot({ f <- function() { cli_div(theme = list(".xx .emph" = list(before = "itsu:"))) cli_par(class = "xx") cli_text("foo {.emph blah} bar") } f() # Not active any more cli_text("foo {.emph blah} bar") }) }) test_that("margin is squashed", { skip_if_not_installed("testthat", "3.1.2") # expect_snapshot cuts off the trailing newline from the message it # seems, so instead of 4 empty lines, there will be only three expect_snapshot(local({ cli_div(theme = list(par = list("margin-top" = 4, "margin-bottom" = 4))) cli_text("three lines") cli_par() cli_par() cli_par() cli_text("until here") cli_end() cli_end() cli_end() cli_par() cli_par() cli_par() cli_text("no space, still") cli_end() cli_end() cli_end() cli_text("three lines again") })) }) test_that("before and after work properly", { expect_snapshot(local({ cli_div( theme = list( "div.alert-success" = list(before ="!!!") )) cli_alert_success("{.pkg foobar} is good") })) }) cli/tests/testthat/test-deep-lists.R0000644000176200001440000000201514557444176017213 0ustar liggesusers start_app() on.exit(stop_app(), add = TRUE) test_that("deep lists ul", { test_ul = function(n = 2) { for(i in seq_len(n)) { cli::cli_ul() cli::cli_li(paste0("Level ",i)) } } expect_snapshot( for (i in 1:4) test_ul(i) ) }) test_that("deep lists ol", { test_ol = function(n = 2) { for(i in seq_len(n)) { cli::cli_ol() cli::cli_li(paste0("Level ",i)) } } expect_snapshot( for (i in 1:4) test_ol(i) ) }) test_that("deep lists ol ul", { test_ol_ul = function(n = 2) { for(i in seq_len(n)) { cli::cli_ol() cli::cli_li(paste0("Level ",2*i-1)) cli::cli_ul() cli::cli_li(paste0("Level ",2*i)) } } expect_snapshot( for (i in 1:4) test_ol_ul(i) ) }) test_that("deep lists ul ol", { test_ul_ol = function(n = 2) { for(i in seq_len(n)) { cli::cli_ul() cli::cli_li(paste0("Level ",2*i-1)) cli::cli_ol() cli::cli_li(paste0("Level ",2*i)) } } expect_snapshot( for (i in 1:4) test_ul_ol(i) ) }) cli/tests/testthat/test-progress-message.R0000644000176200001440000000502614557444176020435 0ustar liggesusers test_that("cli_progress_message", { withr::local_options(cli.dynamic = FALSE, cli.ansi = FALSE) fun <- function() { cli_progress_message("Simplest progress 'bar', {.fun fn} {2} two{?s}") } expect_snapshot(capture_cli_messages(fun())) }) test_that("cli_progress_message error", { # we need the env var as well, because the on.exit handler of the progress # bar might run after the on.exit handler that removes the `cli.dynamic` # option. withr::local_envvar(R_CLI_DYNAMIC = "false") fun <- function() { suppressWarnings(testthat::local_reproducible_output()) options(cli.dynamic = FALSE, cli.ansi = FALSE) cli::cli_progress_message("Simplest progress 'bar', {.fun fn} {2} two{?s}") stop("oopsie") } outfile <- tempfile() on.exit(unlink(outfile), add = TRUE) expect_error(callr::r(fun, stdout = outfile, stderr = outfile), "oopsie") expect_snapshot(readLines(outfile)) # we need the env var as well, because the on.exit handler of the progress # bar might run after the on.exit handler that removes the `cli.dynamic` # option. withr::local_envvar(R_CLI_DYNAMIC = "true") fun2 <- function() { suppressWarnings(testthat::local_reproducible_output()) options(cli.dynamic = TRUE, cli.ansi = TRUE) cli::cli_progress_message("Simplest progress 'bar', {.fun fn} {2} two{?s}") stop("oopsie") } outfile <- tempfile() on.exit(unlink(outfile), add = TRUE) expect_error(callr::r(fun2, stdout = outfile, stderr = outfile), "oopsie") out <- rawToChar(readBin(outfile, "raw", 1000)) expect_snapshot(win2unix(out)) }) start_app() on.exit(stop_app(), add = TRUE) test_that("cli_progress_step", { withr::local_options(cli.dynamic = TRUE, cli.ansi = TRUE) suppressWarnings(testthat::local_reproducible_output()) fun <- function() { cli_progress_step("First step") cli_progress_step("Second step") } msgs <- fix_times(capture_cli_messages(fun())) expect_snapshot(msgs) }) test_that("cli_progress_step error", { if (getRversion() < "3.5.0") skip("Needs R 3.5.0") fun <- function() { options( cli.dynamic = FALSE, cli.ansi = FALSE, cli.unicode = FALSE, cli.width = 80, width = 80, cli.num_colors = 1 ) cli::cli_progress_step("First step") cli::cli_progress_step("Second step") stop("oopsie") } outfile <- tempfile() on.exit(unlink(outfile), add = TRUE) expect_error(callr::r(fun, stdout = outfile, stderr = "2>&1"), "oopsie") out <- fix_times(rawToChar(readBin(outfile, "raw", 1000))) expect_snapshot(win2unix(out)) }) cli/tests/testthat/test-css.R0000644000176200001440000000676214557444176015747 0ustar liggesusers test_that("parse_selector_node", { empty <- list(tag = character(), class = character(), id = character()) cases <- list( list("", empty), list("tag", list(tag = "tag")), list(".class", list(class = "class")), list("#id", list(id = "id")), list("tag.class", list(tag = "tag", class = "class")), list("tag.c1.c2.c3", list(tag = "tag", class = c("c1", "c2", "c3"))), list("tag#id", list(tag = "tag", id = "id")), list("tag#id.class", list(tag = "tag", class = "class", id = "id")), list("tag.class#id", list(tag = "tag", class = "class", id = "id")), list("#id.class", list(class = "class", id = "id")), list("#id.c1.c2", list(class = c("c1", "c2"), id = "id")), list("#id1#id2", list(id = c("id1", "id2"))) ) for (c in cases) { exp <- modifyList(empty, c[[2]]) expect_identical(parse_selector_node(c[[1]]), exp, info = c[[1]]) } }) test_that("parse_selector", { empty <- list(tag = character(), class = character(), id = character()) cases <- list( list("", list()), list("foo", list(list(tag = "foo"))), list("foo bar", list(list(tag = "foo"), list(tag = "bar"))), list("foo.c1 bar.c2", list(list(tag = "foo", class = "c1"), list(tag = "bar", class = "c2"))), list("#i1 tag #i2 .cl", list(list(id = "i1"), list(tag = "tag"), list(id = "i2"), list(class = "cl"))) ) for (c in cases) { exp <- lapply(c[[2]], function(x) modifyList(empty, x)) expect_identical(parse_selector(c[[1]]), exp, info = c[[1]]) } }) test_that("match_selector_node", { default <- list(tag = "mytag", class = character(), id = "myid") pos <- list( list("foo", list(tag = "foo", class = "class"), id = "id"), list(".class", list(tag = "foo", class = "class"), id = "id"), list("foo.class", list(tag = "foo", class = "class", id = "id")), list("#id", list(tag = "foo", class = "class", id = "id")), list(".c", list(class = c("c", "d", "e"))) ) for (c in pos) { sel <- parse_selector_node(c[[1]]) cnt <- modifyList(default, c[[2]]) expect_true(match_selector_node(sel, cnt), info = c[[1]]) } neg <- list( list("foo", list()), list(".class", list()), list("#id", list()), list("foo.class", list()), list("foo.c1.c2", list(tag = "foo", class = c("c1", "c3"))) ) for (c in neg) { sel <- parse_selector_node(c[[1]]) cnt <- modifyList(default, c[[2]]) expect_false(match_selector_node(sel, cnt), info = c[[1]]) } }) test_that("match_selector", { default <- list(tag = "mytag", class = character(), id = "myid") pos <- list( list("foo bar", list(list(tag = "foo"), list(tag = "bar"))), list("bar", list(list(tag = "foo"), list(tag = "bar"))), list(".class", list(list(tag = "x"), list(class = "class"))), list(".c1", list(list(tag = "x"), list(class = "c"), list(class = "c1"))) ) for (c in pos) { sels <- parse_selector(c[[1]]) cnts <- lapply(c[[2]], function(x) modifyList(default, x)) expect_true(match_selector(sels, cnts), info = c[[1]]) } neg <- list( list("foo bar", list(list(tag = "foo"), list(tag = "ba"))), list("foo bar", list(list(tag = "foo"), list(class = "bar"))), list(".class", list(list(tag = "x"), list(class = "class1"))), list(".c1", list(list(tag = "x"), list(class = "c"))) ) for (c in neg) { sels <- parse_selector(c[[1]]) cnts <- lapply(c[[2]], function(x) modifyList(default, x)) expect_false(match_selector(sels, cnts), info = c[[1]]) } }) cli/tests/testthat/test-format-conditions.R0000644000176200001440000000750514752735214020603 0ustar liggesusers test_that_cli("format_error", { expect_snapshot(error = TRUE, local({ n <- "boo" stop(format_error(c( "{.var n} must be a numeric vector", "x" = "You've supplied a {.cls {class(n)}} vector." ))) })) expect_snapshot(error = TRUE, local({ len <- 26 idx <- 100 stop(format_error(c( "Must index an existing element:", "i" = "There {?is/are} {len} element{?s}.", "x" = "You've tried to subset element {idx}." ))) })) }) test_that_cli("format_warning", { expect_snapshot({ n <- "boo" warning(format_warning(c( "{.var n} must be a numeric vector", "x" = "You've supplied a {.cls {class(n)}} vector." ))) }) expect_snapshot(local({ len <- 26 idx <- 100 warning(format_warning(c( "Must index an existing element:", "i" = "There {?is/are} {len} element{?s}.", "x" = "You've tried to subset element {idx}." ))) })) }) test_that_cli("format_message", { expect_snapshot({ n <- "boo" message(format_message(c( "{.var n} must be a numeric vector", "x" = "You've supplied a {.cls {class(n)}} vector." ))) }) expect_snapshot(local({ len <- 26 idx <- 100 message(format_message(c( "Must index an existing element:", "i" = "There {?is/are} {len} element{?s}.", "x" = "You've tried to subset element {idx}." ))) })) }) test_that_cli(configs = "ansi", "color in RStudio", { local_mocked_bindings( rstudio_detect = function() list(type = "rstudio_console", num_colors = 256), get_rstudio_theme = function() list(foreground = "rgb(0, 0, 0)") ) expect_snapshot({ col <- get_rstudio_fg_color0() cat(col("this is the new color")) }) local_mocked_bindings(get_rstudio_theme = function() list()) expect_null(get_rstudio_fg_color0()) local_mocked_bindings( rstudio_detect = function() list(type = "rstudio_console", num_colors = 1) ) expect_null(get_rstudio_fg_color0()) }) test_that_cli(configs = "ansi", "update_rstudio_color", { local_mocked_bindings( get_rstudio_fg_color = function() make_ansi_style("#008800") ) expect_snapshot(cat(update_rstudio_color("color me interested"))) }) test_that("named first element", { expect_snapshot( format_error(c("*" = "foo", "*" = "bar")) ) expect_snapshot( format_warning(c("*" = "foo", "*" = "bar")) ) }) test_that("no cli conditions are thrown", { cnd <- NULL withCallingHandlers({ format_error("error") format_warning("warning") format_message("message") }, cli_message = function(cnd_) cnd <<- cnd_) expect_null(cnd) }) test_that("cli.condition_width", { withr::local_options(cli.condition_width = 40, cli.num_colors = 1) msg <- strrep("1234567890 ", 8) expect_snapshot({ format_error(msg) format_warning(msg) format_message(msg) }) withr::local_options(cli.condition_width = Inf) expect_snapshot({ format_error(msg) format_warning(msg) format_message(msg) }) }) test_that_cli("suppressing Unicode bullets", { withr::local_options(cli.condition_unicode_bullets = FALSE) expect_snapshot(error = TRUE, local({ n <- "boo" stop(format_error(c( "{.var n} must be a numeric vector", "x" = "You've supplied a {.cls {class(n)}} vector.", "v" = "Success.", "i" = "Info.", "*" = "Bullet", ">" = "Arrow" ))) })) }) test_that("edge cases", { expect_equal(cli::format_error(""), "") expect_equal(cli::format_error(NULL), "") expect_equal(cli::format_error(character()), "") expect_equal(cli::format_warning(""), "") expect_equal(cli::format_warning(NULL), "") expect_equal(cli::format_warning(character()), "") expect_equal(cli::format_message(""), "") expect_equal(cli::format_message(NULL), "") expect_equal(cli::format_message(character()), "") }) cli/tests/testthat/test-inline-2.R0000644000176200001440000001230114752735214016547 0ustar liggesusers start_app() on.exit(stop_app(), add = TRUE) test_that_cli( configs = c("plain", "ansi"), "quoting phrases that don't start or end with letter or number", { expect_snapshot(local({ x0 <- "good-name" cli_text("The name is {.file {x0}}.") x <- "weird-name " cli_text("The name is {.file {x}}.") cli_text("The name is {.path {x}}.") cli_text("The name is {.email {x}}.") })) } ) test_that_cli(configs = c("plain", "ansi"), "quoting weird names, still", { nb <- function(x) gsub("\u00a0", " ", x, fixed = TRUE) expect_snapshot(local({ cat_line(nb(quote_weird_name("good"))) cat_line(nb(quote_weird_name(" bad"))) cat_line(nb(quote_weird_name("bad "))) cat_line(nb(quote_weird_name(" bad "))) })) }) test_that_cli(configs = c("ansi"), "~/ files are not weird", { nb <- function(x) gsub("\u00a0", " ", x, fixed = TRUE) expect_snapshot(local({ cat_line(nb(quote_weird_name("~/good"))) cat_line(nb(quote_weird_name("~~bad"))) cat_line(nb(quote_weird_name("bad~ "))) cat_line(nb(quote_weird_name(" ~ bad ~ "))) })) }) test_that_cli("custom truncation", { expect_snapshot({ x <- cli_vec(1:100, list("vec-trunc" = 5)) cli_text("Some numbers: {x}.") cli_text("Some numbers: {.val {x}}.") }) }) test_that_cli(configs = c("plain", "ansi"), "collapsing class names", { expect_snapshot(local({ cc <- c("one", "two") cli_text("this is a class: {.cls myclass}") cli_text("multiple classes: {.cls {cc}}") })) }) test_that_cli(configs = c("plain", "ansi"), "transform", { expect_snapshot(local({ cli_text("This is a {.field field} (before)") foo <- function(x) toupper(x) cli_div(theme = list(span.field = list(transform = foo))) cli_text("This is a {.field field} (during)") cli_end() cli_text("This is a {.field field} (after)") })) }) test_that("cli_format", { expect_snapshot( cli_format(1:4/7, list(digits = 2)) ) }) test_that("cli_format() is used for .val", { withr::local_options(cli.width = 60) withr::local_rng_version("3.3.0") set.seed(42) expect_snapshot(local({ cli_div(theme = list(.val = list(digits = 2))) cli_text("Some random numbers: {.val {runif(4)}}.") })) }) test_that(".q always double quotes", { expect_snapshot( cli_text("just a {.q string}, nothing more") ) }) test_that(".or", { expect_snapshot( cli_text("{.or {letters[1:5]}}") ) expect_snapshot( cli_text("{.or {letters[1:2]}}") ) }) test_that("line breaks", { txt <- paste( "Cupidatat deserunt culpa enim deserunt minim aliqua tempor fugiat", "cupidatat laboris officia esse ex aliqua. Ullamco mollit adipisicing", "anim." ) txt2 <- paste0(txt, "\f", txt) expect_snapshot(ansi_strwrap(txt2, width = 60)) }) test_that_cli(configs = "ansi", "double ticks", { x <- c("a", "`x`", "b") cli_div(theme = list( .code = list(color = "red"), .fun = list(color = "red") )) expect_snapshot(format_inline("{.code {x}}")) expect_snapshot(format_inline("{.fun {x}}")) }) test_that("do not inherit 'transform' issue #422", { expect_snapshot({ d <- deparse(c("cli", "glue")) cli::cli_alert_info("To install, run {.code install.packages({d})}") }) expect_snapshot({ cli::cli_text("{.code foo({1+1})}") }) }) test_that_cli(configs = c("ansi", "plain"), "no inherit color, issue #474", { expect_snapshot({ cli::cli_text("pre {.val x {'foo'} y} post") }) }) test_that_cli(configs = c("ansi", "plain"), "\\f at the end, issue #491", { expect_snapshot({ cli_fmt(cli::cli_text("{.val a}{.val b}")) cli_fmt(cli::cli_text("\f{.val a}{.val b}")) cli_fmt(cli::cli_text("\f\f{.val a}{.val b}")) cli_fmt(cli::cli_text("{.val a}\f{.val b}")) cli_fmt(cli::cli_text("{.val a}\f\f{.val b}")) cli_fmt(cli::cli_text("{.val a}{.val b}\f")) cli_fmt(cli::cli_text("{.val a}{.val b}\f\f")) cli_fmt(cli::cli_text("\f\f\f{.val a}\f\f\f{.val b}\f\f\f")) }) }) test_that("truncate vectors at 20", { expect_snapshot( cli::cli_text("Some letters: {letters}") ) }) test_that_cli(configs = "ansi", "brace expresssion edge cases", { foo <- "foo" bar <- "bar" expect_snapshot({ cli_text("{.code {foo} and {bar}}") cli_text("{.emph {foo} and {bar}}") cli_text("{.q {foo} and {bar}}") }) }) test_that("various errors", { expect_snapshot_error( cli_text("xx {.foobar} yy") ) expect_snapshot_error( cli_text("xx {.someverylong+expression} yy") ) expect_snapshot( error = TRUE, cli_text("xx {__cannot-parse-this__} yy"), transform = sanitize_srcref, variant = if (getRversion() < "4.2.0") "old-r" else "new-r" ) expect_snapshot( error = TRUE, cli_text("xx {1 + 'a'} yy"), transform = function(x) sanitize_call(sanitize_srcref(x)) ) }) test_that("format_inline and newlines", { expect_snapshot({ format_inline("foo\nbar") format_inline("\nfoo\n\nbar\n") format_inline("foo\fbar") format_inline("\ffoo\f\fbar\f") }) expect_snapshot({ format_inline("foo\nbar", keep_whitespace = FALSE) format_inline("\nfoo\n\nbar\n", keep_whitespace = FALSE) format_inline("foo\fbar", keep_whitespace = FALSE) format_inline("\ffoo\f\fbar\f", keep_whitespace = FALSE) }) }) cli/tests/testthat/test-progress-along.R0000644000176200001440000000730414752735214020103 0ustar liggesusers test_that("cli_progress_along crud", { fun <- function() { sapply(cli_progress_along(letters), function(i) i) } capture_cli_messages(ret <- fun()) expect_identical(ret, seq_along(letters)) }) test_that("progress bar terminated at mapping function exit", { fun <- function() { snap <- as.character(names(clienv$progress)) sapply(cli_progress_along(letters), function(i) i) expect_identical(as.character(names(clienv$progress)), snap) } capture_cli_messages(fun()) }) test_that("interpolation uses the right env", { if (getRversion() < "3.5.0") skip("Needs ALTREP") fun <- function() { withr::local_options( cli.ansi = TRUE, cli.dynamic = TRUE, cli.progress_show_after = 0, cli.progress_handlers_only = "cli" ) x <- 10 sapply(cli_progress_along(1:5, format = "x: {x}"), function(i) i) } out <- capture_cli_messages(cli_with_ticks(fun())) expect_snapshot(out) }) test_that("cli_progress_along", { if (getRversion() < "3.5.0") skip("Needs ALTREP") withr::local_envvar(CLI_NO_THREAD = "1") fun <- function() { withr::local_options( cli.ansi = TRUE, cli.dynamic = TRUE, cli.progress_show_after = 0, cli.progress_handlers_only = "logger" ) vapply(cli::cli_progress_along(1:10), function(i) i, integer(1)) } lines <- fix_logger_output(capture.output(cli_with_ticks(fun()))) expect_snapshot(lines) }) test_that("cli_progress_along error", { if (getRversion() < "3.5.0") skip("Needs ALTREP") withr::local_envvar(CLI_NO_THREAD = "1") fun <- function() { withr::local_options( cli.ansi = TRUE, cli.dynamic = TRUE, cli.progress_show_after = 0, cli.progress_handlers_only = "logger" ) suppressWarnings(testthat::local_reproducible_output()) lapply( cli::cli_progress_along(1:10, clear = FALSE), function(i) { if (i == 5) stop("oops") } ) } outfile <- tempfile() expect_error(callr::r(fun, stdout = outfile, stderr = outfile)) lines <- fix_logger_output(readLines(outfile)) expect_snapshot(lines) }) test_that("old R is just seq_along", { # It is tricky to check that we get seq_along(), because # identical(cli_progress_along(1:10), seq_along(1:10)) holds, # so we just check that no progress bar is created. local_mocked_bindings(getRversion = function() package_version("3.4.0")) snapshot <- names(clienv$progress) it <- cli_progress_along(1:10) expect_identical(snapshot, names(clienv$progress)) expect_identical(it, seq_along(1:10)) }) test_that("error in handler is a single warning", { if (getRversion() < "3.5.0") skip("Needs ALTREP") fun <- function() { withr::local_options( cli.ansi = TRUE, cli.dynamic = TRUE, cli.progress_show_after = 0, cli.progress_handlers_only = "cli" ) x <- 10 sapply(cli_progress_along(1:5, format = "{1+''}"), function(i) i) } expect_snapshot( cli_with_ticks(fun()), transform = sanitize_srcref ) }) test_that("length 1 seq", { fun <- function() { sapply(cli_progress_along(1L), function(i) i) } capture_cli_messages(ret <- cli_with_ticks(fun())) expect_identical(ret, 1L) }) test_that("ALTREP methods", { if (getRversion() < "3.5.0") skip("Needs ALTREP") seq <- cli_progress_along(1:10) expect_output(.Internal(inspect(seq)), "progress_along") expect_equal(is.unsorted(seq), FALSE) expect_equal(sum(seq), sum(1:10)) seq <- cli_progress_along(letters) expect_equal(min(seq), 1L) expect_equal(max(seq), length(letters)) z <- cli_progress_along(character()) expect_equal(min(z), Inf) seq <- cli_progress_along(letters) expect_equal(.Call(clic_dataptr, seq), seq_along(letters) * 2) seq2 <- seq expect_silent(seq2[1] <- 100) }) cli/tests/testthat/progress-2.c0000644000176200001440000000046514557444176016220 0ustar liggesusers #include #include SEXP clitest__init_timer() { int before = CLI_SHOULD_TICK; cli_progress_init_timer(); int after = CLI_SHOULD_TICK; SEXP ret = PROTECT(Rf_allocVector(INTSXP, 2)); INTEGER(ret)[0] = before; INTEGER(ret)[1] = after; UNPROTECT(1); return ret; } cli/tests/testthat/test-non-breaking-space.R0000644000176200001440000000041514752735214020600 0ustar liggesusers test_that("does not break", { testthat::local_reproducible_output(unicode = TRUE) expect_snapshot(local({ withr::local_options(cli.width = 40) str30 <- "123456789 123456789 1234567890" cli_text(c(str30, "this\u00a0is\u00a0not\u00a0breaking")) })) }) cli/tests/testthat/test-defer.R0000644000176200001440000000017214557444176016231 0ustar liggesusers test_that("errors", { fun <- function() { defer(1 + "") } expect_snapshot( error = TRUE, fun() ) }) cli/tests/testthat/test-progress-utils.R0000644000176200001440000000203514752735214020137 0ustar liggesusers test_that("cli_progress_num", { withr::local_options(cli.progress_handlers_only = "cli") fun <- function() { before <- cli_progress_num() cli_progress_bar() after <- cli_progress_num() expect_equal(before + 1, after) } capture_cli_messages(fun()) }) test_that("cli_progress_cleanup", { fun <- function() { num <- NULL cli::cli_progress_bar() fun2 <- function() { cli::cli_progress_bar() cli::cli_progress_cleanup() num <<- cli::cli_progress_num() } fun2() } out <- callr::r(fun) expect_equal(out, 0L) }) test_that("should_run_progress_examples", { withr::local_envvar(NOT_CRAN = "true") expect_true(should_run_progress_examples()) local_mocked_bindings(is_rcmd_check = function() TRUE) expect_false(should_run_progress_examples()) }) test_that("is_rcmd_check", { withr::local_envvar(NOT_CRAN = NA, "_R_CHECK_PACKAGE_NAME_" = NA) expect_false(is_rcmd_check()) withr::local_envvar(NOT_CRAN = NA, "_R_CHECK_PACKAGE_NAME_" = "cli") expect_true(is_rcmd_check()) }) cli/tests/testthat/_snaps/0000755000176200001440000000000014752736636015331 5ustar liggesuserscli/tests/testthat/_snaps/spark.md0000644000176200001440000000110014752735214016752 0ustar liggesusers# spark_bar [plain] Code spark_bar(seq(0, 1, length.out = 8)) Output __,,**## Code spark_bar(c(0, NA, 0.5, NA, 1)) Output _ , # # spark_bar [unicode] Code spark_bar(seq(0, 1, length.out = 8)) Output ▁▂▃▄▅▆▇█ Code spark_bar(c(0, NA, 0.5, NA, 1)) Output ▁ ▄ █ # spark_line [plain] Code spark_line(seq(0, 1, length.out = 10)) Output _,,-^ # spark_line [unicode] Code spark_line(seq(0, 1, length.out = 10)) Output ⣀⡠⠔⠊⠉ cli/tests/testthat/_snaps/progress-types.md0000644000176200001440000000516014752734132020650 0ustar liggesusers# iterator Code out Output [1] "\r===============>--------------- 50% | ETA: 1s\033[K\r" [2] "\r\033[K" --- Code out Output [1] "\r\\ 50 done (100/s) | 3ms\033[K\r" "\r\033[K" # tasks Code out Output [1] "\r\\ 50/100 ETA: 1s | \033[K\r" "\r\033[K" --- Code out Output [1] "\r\\ 50 done (100/s) | 3ms\033[K\r" "\r\033[K" # download Code out Output [1] "\r==>---------------------------- | 53 kB/1.0 MB ETA: 1s\033[K\r" [2] "\r\033[K" --- Code out Output [1] "\r\\ 53 kB (8.5 MB/s) | 3ms\033[K\r" [2] "\r\033[K" # customize with options, iterator Code capture_cli_messages(fun("iterator", 100)) Output [1] "\rnew format 50\033[K\r" "\r\033[K" --- Code capture_cli_messages(fun("iterator", NA)) Output [1] "\rnew format 50\033[K\r" "\r\033[K" --- Code capture_cli_messages(fun("iterator", 100)) Output [1] "\rnew format 50\033[K\r" "\r\033[K" --- Code capture_cli_messages(fun("iterator", NA)) Output [1] "\rnew too 50\033[K\r" "\r\033[K" # customize with options, tasks Code capture_cli_messages(fun("tasks", 100)) Output [1] "\rnew format 50\033[K\r" "\r\033[K" --- Code capture_cli_messages(fun("tasks", NA)) Output [1] "\rnew format 50\033[K\r" "\r\033[K" --- Code capture_cli_messages(fun("tasks", 100)) Output [1] "\rnew format 50\033[K\r" "\r\033[K" --- Code capture_cli_messages(fun("tasks", NA)) Output [1] "\rnew too 50\033[K\r" "\r\033[K" # customize with options, download Code capture_cli_messages(fun("download", 1024 * 1024, 512 * 1024)) Output [1] "\rnew format 524 kB\033[K\r" "\r\033[K" --- Code capture_cli_messages(fun("download", NA, 512 * 1024)) Output [1] "\rnew format 524 kB\033[K\r" "\r\033[K" --- Code capture_cli_messages(fun("download", 1024 * 1024, 512 * 1024)) Output [1] "\rnew format 524 kB\033[K\r" "\r\033[K" --- Code capture_cli_messages(fun("download", NA, 512 * 1024)) Output [1] "\rnew too 524 kB\033[K\r" "\r\033[K" cli/tests/testthat/_snaps/ansiex.md0000644000176200001440000000663014752734103017132 0ustar liggesusers# ansi_substr bad input Code ansi_substr("foobar", NULL, 10) Condition Error: ! `ansi_substr()` must have non-empty `start` and `stop` arguments i `start` has length 0 --- Code ansi_substr("foobar", 10, NULL) Condition Error: ! `ansi_substr()` must have non-empty `start` and `stop` arguments i `stop` has length 0 --- Code ansi_substr("foobar", "bad", "bad") Condition Error: ! `start` and `stop` must not have `NA` values i `start` has 1 `NA` value, after coercion to integer i `stop` has 1 `NA` value, after coercion to integer # ansi_substr corner cases Code ansi_substr("abc", "hello", 1) Condition Error: ! `start` and `stop` must not have `NA` values i `start` has 1 `NA` value, after coercion to integer # Weird length 'split' Code ansi_strsplit(c("ab", "bd"), c("b", "d")) Condition Error: ! `split` must be character of length <= 1, or must coerce to that i `split` is (or was coerced to) a character vector # ansi_strtrim with zero-length ellipsis Code ansi_strtrim("12345", 1, ellipsis = "") Output [1] 1 Code ansi_strtrim("12345", 3, ellipsis = "") Output [1] 123 Code ansi_strtrim("12345", 5, ellipsis = "") Output [1] 12345 # ansi_strtrim errors Code ansi_strtrim("foobar", -1) Condition Error: ! `width` must be non-negative in `cli::ansi_strtrim()`. # ansi_strtrim edge cases Code ansi_strtrim("foobar", width = 3, ellipsis = "...") Output [1] "..." Code ansi_strtrim("foobar", width = 2, ellipsis = "...") Output [1] ".." Code ansi_strtrim("foobar", width = 1, ellipsis = "...") Output [1] "." Code ansi_strtrim("foobar", width = 0, ellipsis = "...") Output [1] "" # ansi_columns foo 1 foo 2 foo 3 foo 4 foo 5 foo 6 foo 7 foo 8 foo 9 foo 10 --- 123456789012... # ansi_toupper [plain] Code local({ cat_line(x) cat_line(ansi_toupper(x)) }) Output Red normal green RED NORMAL GREEN # ansi_toupper [ansi] Code local({ cat_line(x) cat_line(ansi_toupper(x)) }) Output Red normal green RED NORMAL GREEN # ansi_tolower [plain] Code local({ cat_line(x) cat_line(ansi_tolower(x)) }) Output Red NORMAL grEeN red normal green # ansi_tolower [ansi] Code local({ cat_line(x) cat_line(ansi_tolower(x)) }) Output Red NORMAL grEeN red normal green # ansi_chartr [plain] Code local({ cat_line(x) cat_line(ansi_chartr(" R_", "-r*", x)) }) Output Red normal green red-normal-green # ansi_chartr [ansi] Code local({ cat_line(x) cat_line(ansi_chartr(" R_", "-r*", x)) }) Output Red normal green red-normal-green cli/tests/testthat/_snaps/ansi-utils.md0000644000176200001440000000520614752734100017726 0ustar liggesusers# re_table Code tbl2 Output start end length text1 "19" "23" "5" "\033[31m" text2 "27" "31" "5" "\033[39m" text3 "48" "52" "5" "\033[32m" text4 "58" "62" "5" "\033[39m" text5 "74" "98" "25" "\033]8;;https://example.com\a" text6 "103" "108" "6" "\033]8;;\a" --- Code non_matching(list(tbl), txt) Output [[1]] start end length [1,] 1 18 18 [2,] 24 26 3 [3,] 32 47 16 [4,] 53 57 5 [5,] 63 73 11 [6,] 99 102 4 # re_table special cases Code tbl Output start end length --- Code non_matching(list(tbl), txt) Output [[1]] start end length [1,] 1 6 6 --- Code non_matching(list(tbl), txt, empty = TRUE) Output [[1]] start end length [1,] 1 6 6 --- Code tbl Output start end length [1,] 1 5 5 [2,] 12 16 5 --- Code non_matching(list(tbl), txt) Output [[1]] start end length [1,] 6 11 6 --- Code non_matching(list(tbl), txt, empty = TRUE) Output [[1]] start end length [1,] 1 0 0 [2,] 6 11 6 [3,] 17 16 0 --- Code tbl Output start end length [1,] 5 9 5 [2,] 10 14 5 --- Code non_matching(list(tbl), txt) Output [[1]] start end length [1,] 1 4 4 [2,] 15 18 4 --- Code non_matching(list(tbl), txt, empty = TRUE) Output [[1]] start end length [1,] 1 4 4 [2,] 10 9 0 [3,] 15 18 4 # myseq Code myseq(1, 5) Output [1] 1 2 3 4 5 Code myseq(1, 1) Output [1] 1 Code myseq(1, 0) Output integer(0) Code myseq(1, 5, 2) Output [1] 1 3 5 Code myseq(1, 6, 2) Output [1] 1 3 5 Code myseq(1, 1, 2) Output [1] 1 Code myseq(1, 2, -1) Output integer(0) Code myseq(10, 1, -1) Output [1] 10 9 8 7 6 5 4 3 2 1 Code myseq(10, 1, -2) Output [1] 10 8 6 4 2 Code myseq(1, 5, -2) Output integer(0) cli/tests/testthat/_snaps/rules.md0000644000176200001440000000012414752734135016772 0ustar liggesusers# print.cli_rule Code rule("foo") Output -- foo ------------- cli/tests/testthat/_snaps/ansi-make.md0000644000176200001440000000176614752734100017512 0ustar liggesusers# errors Code make_ansi_style(1:10) Condition Error: ! `style` must be an ANSI style i an ANSI style is a character scalar (cli style name, RGB or R color name), or a [3x1] or [4x1] numeric RGB matrix i `style` is an integer vector # make_ansi_style Code make_ansi_style(1:10) Condition Error: ! `style` must be an ANSI style i an ANSI style is a character scalar (cli style name, RGB or R color name), or a [3x1] or [4x1] numeric RGB matrix i `style` is an integer vector --- Code make_ansi_style("foobar") Condition Error: ! Unknown style specification: "style", it must be one of * a builtin cli style, e.g. "bold" or "red", * an R color name, see `?grDevices::colors()`. * a [3x1] or [4x1] numeric RGB matrix with, range 0-255. cli/tests/testthat/_snaps/defer.md0000644000176200001440000000026114752734110016720 0ustar liggesusers# errors Code fun() Condition Error: ! Error in a deferred `on.exit()` clause Caused by error: ! non-numeric argument to binary operator cli/tests/testthat/_snaps/old-r/0000755000176200001440000000000014557444176016344 5ustar liggesuserscli/tests/testthat/_snaps/old-r/inline-2.md0000644000176200001440000000037714557444176020312 0ustar liggesusers# various errors Code cli_text("xx {__cannot-parse-this__} yy") Condition Error: ! Could not parse cli `{}` expression: `__cannot-parse-th...`. Caused by error: ! :1:1: unexpected input 1: _ ^ cli/tests/testthat/_snaps/meta.md0000644000176200001440000001263114752734123016571 0ustar liggesusers# meta basics [plain] Code cli::cli({ message("This is before") cli_alert_info("First message") message("This as well") cli_alert_success("Success!") }) Message This is before This as well i First message v Success! # meta basics [ansi] Code cli::cli({ message("This is before") cli_alert_info("First message") message("This as well") cli_alert_success("Success!") }) Message This is before This as well i First message v Success! # meta basics [unicode] Code cli::cli({ message("This is before") cli_alert_info("First message") message("This as well") cli_alert_success("Success!") }) Message This is before This as well ℹ First message ✔ Success! # meta basics [fancy] Code cli::cli({ message("This is before") cli_alert_info("First message") message("This as well") cli_alert_success("Success!") }) Message This is before This as well ℹ First message ✔ Success! # meta is single cli_message [plain] Code cli_server_default(msgs[[1]]) Message i First message v Success! Output NULL # meta is single cli_message [ansi] Code cli_server_default(msgs[[1]]) Message i First message v Success! Output NULL # meta is single cli_message [unicode] Code cli_server_default(msgs[[1]]) Message ℹ First message ✔ Success! Output NULL # meta is single cli_message [fancy] Code cli_server_default(msgs[[1]]) Message ℹ First message ✔ Success! Output NULL # meta is single cliMessage [plain] Code withCallingHandlers(cli::cli({ cli_alert_info("First message") cli_alert_success("Success!") }), cliMessage = function(msg) { msgs <<- c(msgs, list(msg)) }) Message i First message v Success! # meta is single cliMessage [ansi] Code withCallingHandlers(cli::cli({ cli_alert_info("First message") cli_alert_success("Success!") }), cliMessage = function(msg) { msgs <<- c(msgs, list(msg)) }) Message i First message v Success! # meta is single cliMessage [unicode] Code withCallingHandlers(cli::cli({ cli_alert_info("First message") cli_alert_success("Success!") }), cliMessage = function(msg) { msgs <<- c(msgs, list(msg)) }) Message ℹ First message ✔ Success! # meta is single cliMessage [fancy] Code withCallingHandlers(cli::cli({ cli_alert_info("First message") cli_alert_success("Success!") }), cliMessage = function(msg) { msgs <<- c(msgs, list(msg)) }) Message ℹ First message ✔ Success! # substitution [plain] Code local({ x <- 1:3 cli({ title <- "My title" cli_h1("Title: {.emph {title}}") cli_text("And {.emph some} more: {.val {x}}") }) }) Message -- Title: My title ------------------------------------------------------------- And some more: 1, 2, and 3 # substitution [ansi] Code local({ x <- 1:3 cli({ title <- "My title" cli_h1("Title: {.emph {title}}") cli_text("And {.emph some} more: {.val {x}}") }) }) Message -- Title: My title ------------------------------------------------------------- And some more: 1, 2, and 3 # substitution [unicode] Code local({ x <- 1:3 cli({ title <- "My title" cli_h1("Title: {.emph {title}}") cli_text("And {.emph some} more: {.val {x}}") }) }) Message ── Title: My title ───────────────────────────────────────────────────────────── And some more: 1, 2, and 3 # substitution [fancy] Code local({ x <- 1:3 cli({ title <- "My title" cli_h1("Title: {.emph {title}}") cli_text("And {.emph some} more: {.val {x}}") }) }) Message ── Title: My title ───────────────────────────────────────────────────────────── And some more: 1, 2, and 3 # return values are ok when recording (#496) Code cli::cli({ lid <- cli::cli_ul() cli::cli_li("a bullet") cli::cli_end(lid) }) Message * a bullet # nested cli() (#497) Code cli::cli({ cli::cli_h1("Header") cli::cli(cli::cli_text("Some text")) cli::cli_text("Some more text") }) Message -- Header ---------------------------------------------------------------------- Some text Some more text cli/tests/testthat/_snaps/new/0000755000176200001440000000000014753300402016075 5ustar liggesuserscli/tests/testthat/_snaps/new/headers.md0000644000176200001440000000366414752734112020053 0ustar liggesusers# headers [plain] Code local({ cli_div(class = "testcli", theme = test_style()) cli_h1("HEADER") cli_h2("Header") cli_h3("Header") x <- "foobar" xx <- 100 cli_h2("{xx}. header: {x}") }) Message HEADER Header Header 100. header: foobar # headers [ansi] Code local({ cli_div(class = "testcli", theme = test_style()) cli_h1("HEADER") cli_h2("Header") cli_h3("Header") x <- "foobar" xx <- 100 cli_h2("{xx}. header: {x}") }) Message HEADER Header Header 100. header: foobar # headers [unicode] Code local({ cli_div(class = "testcli", theme = test_style()) cli_h1("HEADER") cli_h2("Header") cli_h3("Header") x <- "foobar" xx <- 100 cli_h2("{xx}. header: {x}") }) Message HEADER Header Header 100. header: foobar # headers [fancy] Code local({ cli_div(class = "testcli", theme = test_style()) cli_h1("HEADER") cli_h2("Header") cli_h3("Header") x <- "foobar" xx <- 100 cli_h2("{xx}. header: {x}") }) Message HEADER Header Header 100. header: foobar # issue #218 Code cli_h1("one {1} two {2} three {3}") Message -- one 1 two 2 three 3 --------------------------------------------------------- Code cli_h2("one {1} two {2} three {3}") Message -- one 1 two 2 three 3 -- cli/tests/testthat/_snaps/boxes.md0000644000176200001440000002623214752734104016764 0ustar liggesusers# empty label [plain] Code boxx("") Output +------+ | | | | | | +------+ # empty label [unicode] Code boxx("") Output ┌──────┐ │ │ │ │ │ │ └──────┘ # empty label 2 [plain] Code boxx(character()) Output +------+ | | | | +------+ # empty label 2 [unicode] Code boxx(character()) Output ┌──────┐ │ │ │ │ └──────┘ # label [plain] Code boxx("label") Output +-----------+ | | | label | | | +-----------+ # label [unicode] Code boxx("label") Output ┌───────────┐ │ │ │ label │ │ │ └───────────┘ # label vector [plain] Code boxx(c("label", "l2")) Output +-----------+ | | | label | | l2 | | | +-----------+ # label vector [unicode] Code boxx(c("label", "l2")) Output ┌───────────┐ │ │ │ label │ │ l2 │ │ │ └───────────┘ # border style [plain] Code boxx("label", border_style = "classic") Output +-----------+ | | | label | | | +-----------+ # border style [unicode] Code boxx("label", border_style = "classic") Output +-----------+ | | | label | | | +-----------+ # padding [plain] Code boxx("label", padding = 2) Output +-----------------+ | | | | | label | | | | | +-----------------+ --- Code boxx("label", padding = c(1, 2, 1, 2)) Output +---------+ | | | label | | | +---------+ --- Code boxx("label", padding = c(1, 2, 0, 2)) Output +---------+ | label | | | +---------+ --- Code boxx("label", padding = c(1, 2, 0, 0)) Output +-------+ | label| | | +-------+ # padding [unicode] Code boxx("label", padding = 2) Output ┌─────────────────┐ │ │ │ │ │ label │ │ │ │ │ └─────────────────┘ --- Code boxx("label", padding = c(1, 2, 1, 2)) Output ┌─────────┐ │ │ │ label │ │ │ └─────────┘ --- Code boxx("label", padding = c(1, 2, 0, 2)) Output ┌─────────┐ │ label │ │ │ └─────────┘ --- Code boxx("label", padding = c(1, 2, 0, 0)) Output ┌───────┐ │ label│ │ │ └───────┘ # margin [plain] Code boxx("label", margin = 1) Output +-----------+ | | | label | | | +-----------+ --- Code boxx("label", margin = c(1, 2, 3, 4)) Output +-----------+ | | | label | | | +-----------+ --- Code boxx("label", margin = c(0, 1, 2, 0)) Output +-----------+ | | | label | | | +-----------+ # margin [unicode] Code boxx("label", margin = 1) Output ┌───────────┐ │ │ │ label │ │ │ └───────────┘ --- Code boxx("label", margin = c(1, 2, 3, 4)) Output ┌───────────┐ │ │ │ label │ │ │ └───────────┘ --- Code boxx("label", margin = c(0, 1, 2, 0)) Output ┌───────────┐ │ │ │ label │ │ │ └───────────┘ # float [plain] Code boxx("label", float = "center", width = 20) Output +-----------+ | | | label | | | +-----------+ --- Code boxx("label", float = "right", width = 20) Output +-----------+ | | | label | | | +-----------+ # float [unicode] Code boxx("label", float = "center", width = 20) Output ┌───────────┐ │ │ │ label │ │ │ └───────────┘ --- Code boxx("label", float = "right", width = 20) Output ┌───────────┐ │ │ │ label │ │ │ └───────────┘ # background_col [plain] Code boxx("label", background_col = "red") Output +-----------+ | | | label | | | +-----------+ --- Code boxx("label", background_col = col_red) Output +-----------+ | | | label | | | +-----------+ # background_col [ansi] Code boxx("label", background_col = "red") Output +-----------+ | | | label | | | +-----------+ --- Code boxx("label", background_col = col_red) Output +-----------+ | | | label | | | +-----------+ # background_col [unicode] Code boxx("label", background_col = "red") Output ┌───────────┐ │ │ │ label │ │ │ └───────────┘ --- Code boxx("label", background_col = col_red) Output ┌───────────┐ │ │ │ label │ │ │ └───────────┘ # background_col [fancy] Code boxx("label", background_col = "red") Output ┌───────────┐ │ │ │ label │ │ │ └───────────┘ --- Code boxx("label", background_col = col_red) Output ┌───────────┐ │ │ │ label │ │ │ └───────────┘ # border_col [plain] Code boxx("label", border_col = "red") Output +-----------+ | | | label | | | +-----------+ --- Code boxx("label", border_col = col_red) Output +-----------+ | | | label | | | +-----------+ # border_col [ansi] Code boxx("label", border_col = "red") Output +-----------+ | | | label | | | +-----------+ --- Code boxx("label", border_col = col_red) Output +-----------+ | | | label | | | +-----------+ # border_col [unicode] Code boxx("label", border_col = "red") Output ┌───────────┐ │ │ │ label │ │ │ └───────────┘ --- Code boxx("label", border_col = col_red) Output ┌───────────┐ │ │ │ label │ │ │ └───────────┘ # border_col [fancy] Code boxx("label", border_col = "red") Output ┌───────────┐ │ │ │ label │ │ │ └───────────┘ --- Code boxx("label", border_col = col_red) Output ┌───────────┐ │ │ │ label │ │ │ └───────────┘ # align [plain] Code boxx(c("label", "l2"), align = "center") Output +-----------+ | | | label | | l2 | | | +-----------+ --- Code boxx(c("label", "l2"), align = "right") Output +-----------+ | | | label | | l2 | | | +-----------+ # align [unicode] Code boxx(c("label", "l2"), align = "center") Output ┌───────────┐ │ │ │ label │ │ l2 │ │ │ └───────────┘ --- Code boxx(c("label", "l2"), align = "right") Output ┌───────────┐ │ │ │ label │ │ l2 │ │ │ └───────────┘ # header [plain] Code boxx("foobar", header = "foo") Output + foo -------+ | | | foobar | | | +------------+ # header [unicode] Code boxx("foobar", header = "foo") Output ┌ foo ───────┐ │ │ │ foobar │ │ │ └────────────┘ # footer [plain] Code boxx("foobar", footer = "foo") Output +------------+ | | | foobar | | | +------- foo + # footer [unicode] Code boxx("foobar", footer = "foo") Output ┌────────────┐ │ │ │ foobar │ │ │ └─────── foo ┘ cli/tests/testthat/_snaps/box-styles.md0000644000176200001440000000276214752734103017756 0ustar liggesusers# list_border_styles [plain] Code for (st in list_border_styles()) print(boxx("", border_style = st)) Output +------+ | | | | | | +------+ +------+ | | | | | | +------+ +------+ | | | | | | +------+ +------+ | | | | | | +------+ +------+ | | | | | | +------+ +------+ | | | | | | +------+ # list_border_styles [unicode] Code for (st in list_border_styles()) print(boxx("", border_style = st)) Output ┌──────┐ │ │ │ │ │ │ └──────┘ ╔══════╗ ║ ║ ║ ║ ║ ║ ╚══════╝ ╭──────╮ │ │ │ │ │ │ ╰──────╯ ╓──────╖ ║ ║ ║ ║ ║ ║ ╙──────╜ ╒══════╕ │ │ │ │ │ │ ╘══════╛ +------+ | | | | | | +------+ cli/tests/testthat/_snaps/progress-message.md0000644000176200001440000000164314752734132021132 0ustar liggesusers# cli_progress_message Code capture_cli_messages(fun()) Output [1] "Simplest progress 'bar', `fn()` 2 twos\n" # cli_progress_message error Code readLines(outfile) Output [1] "Simplest progress 'bar', `fn()` 2 twos" [2] "Error in (function () : oopsie" --- Code win2unix(out) Output [1] "\033[?25l\rSimplest progress 'bar', `fn()` 2 twos\033[K\r\r\033[K\033[?25hError in (function () : oopsie\n" # cli_progress_step Code msgs Output [1] "\ri First step\033[K\r" "\rv First step [1s]\033[K\r" [3] "\n" "\ri Second step\033[K\r" [5] "\rv Second step [1s]\033[K\r" "\n" # cli_progress_step error Code win2unix(out) Output [1] "i First step\nv First step [1s]\n\ni Second step\nx Second step [1s]\n\nError in (function () : oopsie\n" cli/tests/testthat/_snaps/rlang-1.1.0/0000755000176200001440000000000014557444176017065 5ustar liggesuserscli/tests/testthat/_snaps/rlang-1.1.0/rlang-errors.md0000644000176200001440000000306314557444176022026 0ustar liggesusers# cli_abort() captures correct call and backtrace Code print(expect_error(f())) Output Error in `h()`: ! foo --- Backtrace: x 1. +-base::print(expect_error(f())) 2. +-testthat::expect_error(f()) 3. | \-testthat:::expect_condition_matching(...) 4. | \-testthat:::quasi_capture(...) 5. | +-testthat (local) .capture(...) 6. | | \-base::withCallingHandlers(...) 7. | \-rlang::eval_bare(quo_get_expr(.quo), quo_get_env(.quo)) 8. \-cli (local) f() 9. \-cli (local) g() 10. \-cli (local) h() --- Code print(expect_error(f(list()))) Output Error in `h()`: ! `x` can't be empty. --- Backtrace: x 1. +-base::print(expect_error(f(list()))) 2. +-testthat::expect_error(f(list())) 3. | \-testthat:::expect_condition_matching(...) 4. | \-testthat:::quasi_capture(...) 5. | +-testthat (local) .capture(...) 6. | | \-base::withCallingHandlers(...) 7. | \-rlang::eval_bare(quo_get_expr(.quo), quo_get_env(.quo)) 8. \-cli (local) f(list()) 9. \-cli (local) g(x) 10. \-cli (local) h(x) # cli_abort(.internal = TRUE) reports the correct function (r-lib/rlang#1386) Code (expect_error(fn())) Output Error in `fn()`: ! Message. i This is an internal error that was detected in the base package. cli/tests/testthat/_snaps/ansi-html.md0000644000176200001440000007576214752734077017565 0ustar liggesusers# ansi_html Code ansi_html(str) Output [1] "bold" [2] "faint" [3] "italic" [4] "underline" [5] "blink" [6] "inverse" [7] "hide" [8] "crossedout" [9] "black" [10] "red" [11] "green" [12] "yellow" [13] "blue" [14] "magenta" [15] "cyan" [16] "white" [17] "bblack" [18] "bred" [19] "bgreen" [20] "byellow" [21] "bblue" [22] "bmagenta" [23] "bcyan" [24] "bwhite" [25] "color-156" [26] "color-1-22-255" [27] "bg-black" [28] "bg-red" [29] "bg-green" [30] "bg-yellow" [31] "bg-blue" [32] "bg-magenta" [33] "bg-cyan" [34] "bg-white" [35] "bg-bblack" [36] "bg-bred" [37] "bg-bgreen" [38] "bg-byellow" [39] "bg-bblue" [40] "bg-bmagenta" [41] "bg-bcyan" [42] "bg-bwhite" [43] "bg-color-156" [44] "bg-color-1-22-255" # multiple styles Code ansi_html("\033[1;2;35;45mmultiple") Output [1] "multiple" # ansi_html_style Code ansi_html_style(colors = 8) Output .ansi-bold { font-weight: bold; } .ansi-italic { font-style: italic; } .ansi-underline { text-decoration: underline; } .ansi-blink { text-decoration: blink; } .ansi-hide { visibility: hidden; } .ansi-crossedout { text-decoration: line-through; } .ansi-link:hover { text-decoration: underline; } .ansi-color-0 { color: #000000 } .ansi-color-1 { color: #cd3131 } .ansi-color-2 { color: #0dbc79 } .ansi-color-3 { color: #e5e510 } .ansi-color-4 { color: #2472c8 } .ansi-color-5 { color: #bc3fbc } .ansi-color-6 { color: #11a8cd } .ansi-color-7 { color: #e5e5e5 } .ansi-color-8 { color: #666666 } .ansi-color-9 { color: #f14c4c } .ansi-color-10 { color: #23d18b } .ansi-color-11 { color: #f5f543 } .ansi-color-12 { color: #3b8eea } .ansi-color-13 { color: #d670d6 } .ansi-color-14 { color: #29b8db } .ansi-color-15 { color: #e5e5e5 } .ansi-bg-color-0 { background-color: #000000 } .ansi-bg-color-1 { background-color: #cd3131 } .ansi-bg-color-2 { background-color: #0dbc79 } .ansi-bg-color-3 { background-color: #e5e510 } .ansi-bg-color-4 { background-color: #2472c8 } .ansi-bg-color-5 { background-color: #bc3fbc } .ansi-bg-color-6 { background-color: #11a8cd } .ansi-bg-color-7 { background-color: #e5e5e5 } .ansi-bg-color-8 { background-color: #666666 } .ansi-bg-color-9 { background-color: #f14c4c } .ansi-bg-color-10 { background-color: #23d18b } .ansi-bg-color-11 { background-color: #f5f543 } .ansi-bg-color-12 { background-color: #3b8eea } .ansi-bg-color-13 { background-color: #d670d6 } .ansi-bg-color-14 { background-color: #29b8db } .ansi-bg-color-15 { background-color: #e5e5e5 } --- Code ansi_html_style(colors = 256, palette = "ubuntu") Output .ansi-bold { font-weight: bold; } .ansi-italic { font-style: italic; } .ansi-underline { text-decoration: underline; } .ansi-blink { text-decoration: blink; } .ansi-hide { visibility: hidden; } .ansi-crossedout { text-decoration: line-through; } .ansi-link:hover { text-decoration: underline; } .ansi-color-0 { color: #010101 } .ansi-color-1 { color: #de382b } .ansi-color-2 { color: #39b54a } .ansi-color-3 { color: #ffc706 } .ansi-color-4 { color: #006fb8 } .ansi-color-5 { color: #762671 } .ansi-color-6 { color: #2cb5e9 } .ansi-color-7 { color: #cccccc } .ansi-color-8 { color: #808080 } .ansi-color-9 { color: #ff0000 } .ansi-color-10 { color: #00ff00 } .ansi-color-11 { color: #ffff00 } .ansi-color-12 { color: #0000ff } .ansi-color-13 { color: #ff00ff } .ansi-color-14 { color: #00ffff } .ansi-color-15 { color: #ffffff } .ansi-bg-color-0 { background-color: #010101 } .ansi-bg-color-1 { background-color: #de382b } .ansi-bg-color-2 { background-color: #39b54a } .ansi-bg-color-3 { background-color: #ffc706 } .ansi-bg-color-4 { background-color: #006fb8 } .ansi-bg-color-5 { background-color: #762671 } .ansi-bg-color-6 { background-color: #2cb5e9 } .ansi-bg-color-7 { background-color: #cccccc } .ansi-bg-color-8 { background-color: #808080 } .ansi-bg-color-9 { background-color: #ff0000 } .ansi-bg-color-10 { background-color: #00ff00 } .ansi-bg-color-11 { background-color: #ffff00 } .ansi-bg-color-12 { background-color: #0000ff } .ansi-bg-color-13 { background-color: #ff00ff } .ansi-bg-color-14 { background-color: #00ffff } .ansi-bg-color-15 { background-color: #ffffff } .ansi-color-16 { color: #000000 } .ansi-color-52 { color: #330000 } .ansi-color-88 { color: #660000 } .ansi-color-124 { color: #990000 } .ansi-color-160 { color: #cc0000 } .ansi-color-196 { color: #ff0000 } .ansi-color-22 { color: #003300 } .ansi-color-58 { color: #333300 } .ansi-color-94 { color: #663300 } .ansi-color-130 { color: #993300 } .ansi-color-166 { color: #cc3300 } .ansi-color-202 { color: #ff3300 } .ansi-color-28 { color: #006600 } .ansi-color-64 { color: #336600 } .ansi-color-100 { color: #666600 } .ansi-color-136 { color: #996600 } .ansi-color-172 { color: #cc6600 } .ansi-color-208 { color: #ff6600 } .ansi-color-34 { color: #009900 } .ansi-color-70 { color: #339900 } .ansi-color-106 { color: #669900 } .ansi-color-142 { color: #999900 } .ansi-color-178 { color: #cc9900 } .ansi-color-214 { color: #ff9900 } .ansi-color-40 { color: #00cc00 } .ansi-color-76 { color: #33cc00 } .ansi-color-112 { color: #66cc00 } .ansi-color-148 { color: #99cc00 } .ansi-color-184 { color: #cccc00 } .ansi-color-220 { color: #ffcc00 } .ansi-color-46 { color: #00ff00 } .ansi-color-82 { color: #33ff00 } .ansi-color-118 { color: #66ff00 } .ansi-color-154 { color: #99ff00 } .ansi-color-190 { color: #ccff00 } .ansi-color-226 { color: #ffff00 } .ansi-color-17 { color: #000033 } .ansi-color-53 { color: #330033 } .ansi-color-89 { color: #660033 } .ansi-color-125 { color: #990033 } .ansi-color-161 { color: #cc0033 } .ansi-color-197 { color: #ff0033 } .ansi-color-23 { color: #003333 } .ansi-color-59 { color: #333333 } .ansi-color-95 { color: #663333 } .ansi-color-131 { color: #993333 } .ansi-color-167 { color: #cc3333 } .ansi-color-203 { color: #ff3333 } .ansi-color-29 { color: #006633 } .ansi-color-65 { color: #336633 } .ansi-color-101 { color: #666633 } .ansi-color-137 { color: #996633 } .ansi-color-173 { color: #cc6633 } .ansi-color-209 { color: #ff6633 } .ansi-color-35 { color: #009933 } .ansi-color-71 { color: #339933 } .ansi-color-107 { color: #669933 } .ansi-color-143 { color: #999933 } .ansi-color-179 { color: #cc9933 } .ansi-color-215 { color: #ff9933 } .ansi-color-41 { color: #00cc33 } .ansi-color-77 { color: #33cc33 } .ansi-color-113 { color: #66cc33 } .ansi-color-149 { color: #99cc33 } .ansi-color-185 { color: #cccc33 } .ansi-color-221 { color: #ffcc33 } .ansi-color-47 { color: #00ff33 } .ansi-color-83 { color: #33ff33 } .ansi-color-119 { color: #66ff33 } .ansi-color-155 { color: #99ff33 } .ansi-color-191 { color: #ccff33 } .ansi-color-227 { color: #ffff33 } .ansi-color-18 { color: #000066 } .ansi-color-54 { color: #330066 } .ansi-color-90 { color: #660066 } .ansi-color-126 { color: #990066 } .ansi-color-162 { color: #cc0066 } .ansi-color-198 { color: #ff0066 } .ansi-color-24 { color: #003366 } .ansi-color-60 { color: #333366 } .ansi-color-96 { color: #663366 } .ansi-color-132 { color: #993366 } .ansi-color-168 { color: #cc3366 } .ansi-color-204 { color: #ff3366 } .ansi-color-30 { color: #006666 } .ansi-color-66 { color: #336666 } .ansi-color-102 { color: #666666 } .ansi-color-138 { color: #996666 } .ansi-color-174 { color: #cc6666 } .ansi-color-210 { color: #ff6666 } .ansi-color-36 { color: #009966 } .ansi-color-72 { color: #339966 } .ansi-color-108 { color: #669966 } .ansi-color-144 { color: #999966 } .ansi-color-180 { color: #cc9966 } .ansi-color-216 { color: #ff9966 } .ansi-color-42 { color: #00cc66 } .ansi-color-78 { color: #33cc66 } .ansi-color-114 { color: #66cc66 } .ansi-color-150 { color: #99cc66 } .ansi-color-186 { color: #cccc66 } .ansi-color-222 { color: #ffcc66 } .ansi-color-48 { color: #00ff66 } .ansi-color-84 { color: #33ff66 } .ansi-color-120 { color: #66ff66 } .ansi-color-156 { color: #99ff66 } .ansi-color-192 { color: #ccff66 } .ansi-color-228 { color: #ffff66 } .ansi-color-19 { color: #000099 } .ansi-color-55 { color: #330099 } .ansi-color-91 { color: #660099 } .ansi-color-127 { color: #990099 } .ansi-color-163 { color: #cc0099 } .ansi-color-199 { color: #ff0099 } .ansi-color-25 { color: #003399 } .ansi-color-61 { color: #333399 } .ansi-color-97 { color: #663399 } .ansi-color-133 { color: #993399 } .ansi-color-169 { color: #cc3399 } .ansi-color-205 { color: #ff3399 } .ansi-color-31 { color: #006699 } .ansi-color-67 { color: #336699 } .ansi-color-103 { color: #666699 } .ansi-color-139 { color: #996699 } .ansi-color-175 { color: #cc6699 } .ansi-color-211 { color: #ff6699 } .ansi-color-37 { color: #009999 } .ansi-color-73 { color: #339999 } .ansi-color-109 { color: #669999 } .ansi-color-145 { color: #999999 } .ansi-color-181 { color: #cc9999 } .ansi-color-217 { color: #ff9999 } .ansi-color-43 { color: #00cc99 } .ansi-color-79 { color: #33cc99 } .ansi-color-115 { color: #66cc99 } .ansi-color-151 { color: #99cc99 } .ansi-color-187 { color: #cccc99 } .ansi-color-223 { color: #ffcc99 } .ansi-color-49 { color: #00ff99 } .ansi-color-85 { color: #33ff99 } .ansi-color-121 { color: #66ff99 } .ansi-color-157 { color: #99ff99 } .ansi-color-193 { color: #ccff99 } .ansi-color-229 { color: #ffff99 } .ansi-color-20 { color: #0000cc } .ansi-color-56 { color: #3300cc } .ansi-color-92 { color: #6600cc } .ansi-color-128 { color: #9900cc } .ansi-color-164 { color: #cc00cc } .ansi-color-200 { color: #ff00cc } .ansi-color-26 { color: #0033cc } .ansi-color-62 { color: #3333cc } .ansi-color-98 { color: #6633cc } .ansi-color-134 { color: #9933cc } .ansi-color-170 { color: #cc33cc } .ansi-color-206 { color: #ff33cc } .ansi-color-32 { color: #0066cc } .ansi-color-68 { color: #3366cc } .ansi-color-104 { color: #6666cc } .ansi-color-140 { color: #9966cc } .ansi-color-176 { color: #cc66cc } .ansi-color-212 { color: #ff66cc } .ansi-color-38 { color: #0099cc } .ansi-color-74 { color: #3399cc } .ansi-color-110 { color: #6699cc } .ansi-color-146 { color: #9999cc } .ansi-color-182 { color: #cc99cc } .ansi-color-218 { color: #ff99cc } .ansi-color-44 { color: #00cccc } .ansi-color-80 { color: #33cccc } .ansi-color-116 { color: #66cccc } .ansi-color-152 { color: #99cccc } .ansi-color-188 { color: #cccccc } .ansi-color-224 { color: #ffcccc } .ansi-color-50 { color: #00ffcc } .ansi-color-86 { color: #33ffcc } .ansi-color-122 { color: #66ffcc } .ansi-color-158 { color: #99ffcc } .ansi-color-194 { color: #ccffcc } .ansi-color-230 { color: #ffffcc } .ansi-color-21 { color: #0000ff } .ansi-color-57 { color: #3300ff } .ansi-color-93 { color: #6600ff } .ansi-color-129 { color: #9900ff } .ansi-color-165 { color: #cc00ff } .ansi-color-201 { color: #ff00ff } .ansi-color-27 { color: #0033ff } .ansi-color-63 { color: #3333ff } .ansi-color-99 { color: #6633ff } .ansi-color-135 { color: #9933ff } .ansi-color-171 { color: #cc33ff } .ansi-color-207 { color: #ff33ff } .ansi-color-33 { color: #0066ff } .ansi-color-69 { color: #3366ff } .ansi-color-105 { color: #6666ff } .ansi-color-141 { color: #9966ff } .ansi-color-177 { color: #cc66ff } .ansi-color-213 { color: #ff66ff } .ansi-color-39 { color: #0099ff } .ansi-color-75 { color: #3399ff } .ansi-color-111 { color: #6699ff } .ansi-color-147 { color: #9999ff } .ansi-color-183 { color: #cc99ff } .ansi-color-219 { color: #ff99ff } .ansi-color-45 { color: #00ccff } .ansi-color-81 { color: #33ccff } .ansi-color-117 { color: #66ccff } .ansi-color-153 { color: #99ccff } .ansi-color-189 { color: #ccccff } .ansi-color-225 { color: #ffccff } .ansi-color-51 { color: #00ffff } .ansi-color-87 { color: #33ffff } .ansi-color-123 { color: #66ffff } .ansi-color-159 { color: #99ffff } .ansi-color-195 { color: #ccffff } .ansi-color-231 { color: #ffffff } .ansi-color-232 { color: #0a0a0a } .ansi-color-233 { color: #141414 } .ansi-color-234 { color: #1f1f1f } .ansi-color-235 { color: #292929 } .ansi-color-236 { color: #333333 } .ansi-color-237 { color: #3d3d3d } .ansi-color-238 { color: #474747 } .ansi-color-239 { color: #525252 } .ansi-color-240 { color: #5c5c5c } .ansi-color-241 { color: #666666 } .ansi-color-242 { color: #707070 } .ansi-color-243 { color: #7a7a7a } .ansi-color-244 { color: #858585 } .ansi-color-245 { color: #8f8f8f } .ansi-color-246 { color: #999999 } .ansi-color-247 { color: #a3a3a3 } .ansi-color-248 { color: #adadad } .ansi-color-249 { color: #b8b8b8 } .ansi-color-250 { color: #c2c2c2 } .ansi-color-251 { color: #cccccc } .ansi-color-252 { color: #d6d6d6 } .ansi-color-253 { color: #e0e0e0 } .ansi-color-254 { color: #ebebeb } .ansi-color-255 { color: #f5f5f5 } .ansi-bg-color-16 { background-color: #000000 } .ansi-bg-color-52 { background-color: #330000 } .ansi-bg-color-88 { background-color: #660000 } .ansi-bg-color-124 { background-color: #990000 } .ansi-bg-color-160 { background-color: #cc0000 } .ansi-bg-color-196 { background-color: #ff0000 } .ansi-bg-color-22 { background-color: #003300 } .ansi-bg-color-58 { background-color: #333300 } .ansi-bg-color-94 { background-color: #663300 } .ansi-bg-color-130 { background-color: #993300 } .ansi-bg-color-166 { background-color: #cc3300 } .ansi-bg-color-202 { background-color: #ff3300 } .ansi-bg-color-28 { background-color: #006600 } .ansi-bg-color-64 { background-color: #336600 } .ansi-bg-color-100 { background-color: #666600 } .ansi-bg-color-136 { background-color: #996600 } .ansi-bg-color-172 { background-color: #cc6600 } .ansi-bg-color-208 { background-color: #ff6600 } .ansi-bg-color-34 { background-color: #009900 } .ansi-bg-color-70 { background-color: #339900 } .ansi-bg-color-106 { background-color: #669900 } .ansi-bg-color-142 { background-color: #999900 } .ansi-bg-color-178 { background-color: #cc9900 } .ansi-bg-color-214 { background-color: #ff9900 } .ansi-bg-color-40 { background-color: #00cc00 } .ansi-bg-color-76 { background-color: #33cc00 } .ansi-bg-color-112 { background-color: #66cc00 } .ansi-bg-color-148 { background-color: #99cc00 } .ansi-bg-color-184 { background-color: #cccc00 } .ansi-bg-color-220 { background-color: #ffcc00 } .ansi-bg-color-46 { background-color: #00ff00 } .ansi-bg-color-82 { background-color: #33ff00 } .ansi-bg-color-118 { background-color: #66ff00 } .ansi-bg-color-154 { background-color: #99ff00 } .ansi-bg-color-190 { background-color: #ccff00 } .ansi-bg-color-226 { background-color: #ffff00 } .ansi-bg-color-17 { background-color: #000033 } .ansi-bg-color-53 { background-color: #330033 } .ansi-bg-color-89 { background-color: #660033 } .ansi-bg-color-125 { background-color: #990033 } .ansi-bg-color-161 { background-color: #cc0033 } .ansi-bg-color-197 { background-color: #ff0033 } .ansi-bg-color-23 { background-color: #003333 } .ansi-bg-color-59 { background-color: #333333 } .ansi-bg-color-95 { background-color: #663333 } .ansi-bg-color-131 { background-color: #993333 } .ansi-bg-color-167 { background-color: #cc3333 } .ansi-bg-color-203 { background-color: #ff3333 } .ansi-bg-color-29 { background-color: #006633 } .ansi-bg-color-65 { background-color: #336633 } .ansi-bg-color-101 { background-color: #666633 } .ansi-bg-color-137 { background-color: #996633 } .ansi-bg-color-173 { background-color: #cc6633 } .ansi-bg-color-209 { background-color: #ff6633 } .ansi-bg-color-35 { background-color: #009933 } .ansi-bg-color-71 { background-color: #339933 } .ansi-bg-color-107 { background-color: #669933 } .ansi-bg-color-143 { background-color: #999933 } .ansi-bg-color-179 { background-color: #cc9933 } .ansi-bg-color-215 { background-color: #ff9933 } .ansi-bg-color-41 { background-color: #00cc33 } .ansi-bg-color-77 { background-color: #33cc33 } .ansi-bg-color-113 { background-color: #66cc33 } .ansi-bg-color-149 { background-color: #99cc33 } .ansi-bg-color-185 { background-color: #cccc33 } .ansi-bg-color-221 { background-color: #ffcc33 } .ansi-bg-color-47 { background-color: #00ff33 } .ansi-bg-color-83 { background-color: #33ff33 } .ansi-bg-color-119 { background-color: #66ff33 } .ansi-bg-color-155 { background-color: #99ff33 } .ansi-bg-color-191 { background-color: #ccff33 } .ansi-bg-color-227 { background-color: #ffff33 } .ansi-bg-color-18 { background-color: #000066 } .ansi-bg-color-54 { background-color: #330066 } .ansi-bg-color-90 { background-color: #660066 } .ansi-bg-color-126 { background-color: #990066 } .ansi-bg-color-162 { background-color: #cc0066 } .ansi-bg-color-198 { background-color: #ff0066 } .ansi-bg-color-24 { background-color: #003366 } .ansi-bg-color-60 { background-color: #333366 } .ansi-bg-color-96 { background-color: #663366 } .ansi-bg-color-132 { background-color: #993366 } .ansi-bg-color-168 { background-color: #cc3366 } .ansi-bg-color-204 { background-color: #ff3366 } .ansi-bg-color-30 { background-color: #006666 } .ansi-bg-color-66 { background-color: #336666 } .ansi-bg-color-102 { background-color: #666666 } .ansi-bg-color-138 { background-color: #996666 } .ansi-bg-color-174 { background-color: #cc6666 } .ansi-bg-color-210 { background-color: #ff6666 } .ansi-bg-color-36 { background-color: #009966 } .ansi-bg-color-72 { background-color: #339966 } .ansi-bg-color-108 { background-color: #669966 } .ansi-bg-color-144 { background-color: #999966 } .ansi-bg-color-180 { background-color: #cc9966 } .ansi-bg-color-216 { background-color: #ff9966 } .ansi-bg-color-42 { background-color: #00cc66 } .ansi-bg-color-78 { background-color: #33cc66 } .ansi-bg-color-114 { background-color: #66cc66 } .ansi-bg-color-150 { background-color: #99cc66 } .ansi-bg-color-186 { background-color: #cccc66 } .ansi-bg-color-222 { background-color: #ffcc66 } .ansi-bg-color-48 { background-color: #00ff66 } .ansi-bg-color-84 { background-color: #33ff66 } .ansi-bg-color-120 { background-color: #66ff66 } .ansi-bg-color-156 { background-color: #99ff66 } .ansi-bg-color-192 { background-color: #ccff66 } .ansi-bg-color-228 { background-color: #ffff66 } .ansi-bg-color-19 { background-color: #000099 } .ansi-bg-color-55 { background-color: #330099 } .ansi-bg-color-91 { background-color: #660099 } .ansi-bg-color-127 { background-color: #990099 } .ansi-bg-color-163 { background-color: #cc0099 } .ansi-bg-color-199 { background-color: #ff0099 } .ansi-bg-color-25 { background-color: #003399 } .ansi-bg-color-61 { background-color: #333399 } .ansi-bg-color-97 { background-color: #663399 } .ansi-bg-color-133 { background-color: #993399 } .ansi-bg-color-169 { background-color: #cc3399 } .ansi-bg-color-205 { background-color: #ff3399 } .ansi-bg-color-31 { background-color: #006699 } .ansi-bg-color-67 { background-color: #336699 } .ansi-bg-color-103 { background-color: #666699 } .ansi-bg-color-139 { background-color: #996699 } .ansi-bg-color-175 { background-color: #cc6699 } .ansi-bg-color-211 { background-color: #ff6699 } .ansi-bg-color-37 { background-color: #009999 } .ansi-bg-color-73 { background-color: #339999 } .ansi-bg-color-109 { background-color: #669999 } .ansi-bg-color-145 { background-color: #999999 } .ansi-bg-color-181 { background-color: #cc9999 } .ansi-bg-color-217 { background-color: #ff9999 } .ansi-bg-color-43 { background-color: #00cc99 } .ansi-bg-color-79 { background-color: #33cc99 } .ansi-bg-color-115 { background-color: #66cc99 } .ansi-bg-color-151 { background-color: #99cc99 } .ansi-bg-color-187 { background-color: #cccc99 } .ansi-bg-color-223 { background-color: #ffcc99 } .ansi-bg-color-49 { background-color: #00ff99 } .ansi-bg-color-85 { background-color: #33ff99 } .ansi-bg-color-121 { background-color: #66ff99 } .ansi-bg-color-157 { background-color: #99ff99 } .ansi-bg-color-193 { background-color: #ccff99 } .ansi-bg-color-229 { background-color: #ffff99 } .ansi-bg-color-20 { background-color: #0000cc } .ansi-bg-color-56 { background-color: #3300cc } .ansi-bg-color-92 { background-color: #6600cc } .ansi-bg-color-128 { background-color: #9900cc } .ansi-bg-color-164 { background-color: #cc00cc } .ansi-bg-color-200 { background-color: #ff00cc } .ansi-bg-color-26 { background-color: #0033cc } .ansi-bg-color-62 { background-color: #3333cc } .ansi-bg-color-98 { background-color: #6633cc } .ansi-bg-color-134 { background-color: #9933cc } .ansi-bg-color-170 { background-color: #cc33cc } .ansi-bg-color-206 { background-color: #ff33cc } .ansi-bg-color-32 { background-color: #0066cc } .ansi-bg-color-68 { background-color: #3366cc } .ansi-bg-color-104 { background-color: #6666cc } .ansi-bg-color-140 { background-color: #9966cc } .ansi-bg-color-176 { background-color: #cc66cc } .ansi-bg-color-212 { background-color: #ff66cc } .ansi-bg-color-38 { background-color: #0099cc } .ansi-bg-color-74 { background-color: #3399cc } .ansi-bg-color-110 { background-color: #6699cc } .ansi-bg-color-146 { background-color: #9999cc } .ansi-bg-color-182 { background-color: #cc99cc } .ansi-bg-color-218 { background-color: #ff99cc } .ansi-bg-color-44 { background-color: #00cccc } .ansi-bg-color-80 { background-color: #33cccc } .ansi-bg-color-116 { background-color: #66cccc } .ansi-bg-color-152 { background-color: #99cccc } .ansi-bg-color-188 { background-color: #cccccc } .ansi-bg-color-224 { background-color: #ffcccc } .ansi-bg-color-50 { background-color: #00ffcc } .ansi-bg-color-86 { background-color: #33ffcc } .ansi-bg-color-122 { background-color: #66ffcc } .ansi-bg-color-158 { background-color: #99ffcc } .ansi-bg-color-194 { background-color: #ccffcc } .ansi-bg-color-230 { background-color: #ffffcc } .ansi-bg-color-21 { background-color: #0000ff } .ansi-bg-color-57 { background-color: #3300ff } .ansi-bg-color-93 { background-color: #6600ff } .ansi-bg-color-129 { background-color: #9900ff } .ansi-bg-color-165 { background-color: #cc00ff } .ansi-bg-color-201 { background-color: #ff00ff } .ansi-bg-color-27 { background-color: #0033ff } .ansi-bg-color-63 { background-color: #3333ff } .ansi-bg-color-99 { background-color: #6633ff } .ansi-bg-color-135 { background-color: #9933ff } .ansi-bg-color-171 { background-color: #cc33ff } .ansi-bg-color-207 { background-color: #ff33ff } .ansi-bg-color-33 { background-color: #0066ff } .ansi-bg-color-69 { background-color: #3366ff } .ansi-bg-color-105 { background-color: #6666ff } .ansi-bg-color-141 { background-color: #9966ff } .ansi-bg-color-177 { background-color: #cc66ff } .ansi-bg-color-213 { background-color: #ff66ff } .ansi-bg-color-39 { background-color: #0099ff } .ansi-bg-color-75 { background-color: #3399ff } .ansi-bg-color-111 { background-color: #6699ff } .ansi-bg-color-147 { background-color: #9999ff } .ansi-bg-color-183 { background-color: #cc99ff } .ansi-bg-color-219 { background-color: #ff99ff } .ansi-bg-color-45 { background-color: #00ccff } .ansi-bg-color-81 { background-color: #33ccff } .ansi-bg-color-117 { background-color: #66ccff } .ansi-bg-color-153 { background-color: #99ccff } .ansi-bg-color-189 { background-color: #ccccff } .ansi-bg-color-225 { background-color: #ffccff } .ansi-bg-color-51 { background-color: #00ffff } .ansi-bg-color-87 { background-color: #33ffff } .ansi-bg-color-123 { background-color: #66ffff } .ansi-bg-color-159 { background-color: #99ffff } .ansi-bg-color-195 { background-color: #ccffff } .ansi-bg-color-231 { background-color: #ffffff } .ansi-bg-color-232 { background-color: #0a0a0a } .ansi-bg-color-233 { background-color: #141414 } .ansi-bg-color-234 { background-color: #1f1f1f } .ansi-bg-color-235 { background-color: #292929 } .ansi-bg-color-236 { background-color: #333333 } .ansi-bg-color-237 { background-color: #3d3d3d } .ansi-bg-color-238 { background-color: #474747 } .ansi-bg-color-239 { background-color: #525252 } .ansi-bg-color-240 { background-color: #5c5c5c } .ansi-bg-color-241 { background-color: #666666 } .ansi-bg-color-242 { background-color: #707070 } .ansi-bg-color-243 { background-color: #7a7a7a } .ansi-bg-color-244 { background-color: #858585 } .ansi-bg-color-245 { background-color: #8f8f8f } .ansi-bg-color-246 { background-color: #999999 } .ansi-bg-color-247 { background-color: #a3a3a3 } .ansi-bg-color-248 { background-color: #adadad } .ansi-bg-color-249 { background-color: #b8b8b8 } .ansi-bg-color-250 { background-color: #c2c2c2 } .ansi-bg-color-251 { background-color: #cccccc } .ansi-bg-color-252 { background-color: #d6d6d6 } .ansi-bg-color-253 { background-color: #e0e0e0 } .ansi-bg-color-254 { background-color: #ebebeb } .ansi-bg-color-255 { background-color: #f5f5f5 } cli/tests/testthat/_snaps/keypress.md0000644000176200001440000000435014752734117017512 0ustar liggesusers# control characaters Code for (code in c(1:2, 4:6, 8:14, 16L, 20L, 21L, 23L, 27L, 127L)) { p$write_input("cli::keypress()\n") Sys.sleep(0.1) p$write_input(as.raw(code)) p$poll_io(1000) cat(p$read_output()) } Output [1] "ctrl-a" [1] "ctrl-b" [1] "ctrl-d" [1] "ctrl-e" [1] "ctrl-f" [1] "ctrl-h" [1] "tab" [1] "enter" [1] "ctrl-k" [1] "ctrl-l" [1] "enter" [1] "ctrl-n" [1] "ctrl-p" [1] "ctrl-t" [1] "ctrl-u" [1] "ctrl-w" [1] "escape" [1] "backspace" # write ahead Code p$write_input("{ Sys.sleep(0.5); cli::keypress() }\nX") p$poll_io(1000) Output output error process "ready" "nopipe" "silent" Code cat(p$read_output()) Output [1] "X" # arrows, etc Code for (key in keys) { p$write_input("cli::keypress()\n") p$write_input(key) p$poll_io(1000) cat(p$read_output()) } Output [1] "up" [1] "right" [1] "left" [1] "end" [1] "home" [1] "-" [1] "up" [1] "down" [1] "right" [1] "left" [1] "end" [1] "home" [1] "-" [1] "home" [1] "insert" [1] "delete" [1] "end" [1] "pageup" [1] "pagedown" [1] "-" [1] "pageup" [1] "pagedown" [1] "-" [1] "home" [1] "end" [1] "-" [1] "f1" [1] "f2" [1] "f3" [1] "f4" [1] "-" [1] "f5" [1] "f6" [1] "f7" [1] "f8" [1] "f9" [1] "f10" [1] "f11" [1] "f12" [1] "-" [1] "f1" [1] "f2" [1] "f3" [1] "f4" [1] "-" [1] "escape" # nonblocking Code p$write_input("cli::keypress(block = FALSE)\n") p$poll_io(1000) Output output error process "ready" "nopipe" "silent" Code cat(p$read_output()) Output [1] NA --- Code p$write_input("{ Sys.sleep(0.5); cli::keypress() }\nX") p$poll_io(1000) Output output error process "ready" "nopipe" "silent" Code cat(p$read_output()) Output [1] "X" cli/tests/testthat/_snaps/links.md0000644000176200001440000007104514752735214016771 0ustar liggesusers# {.email} [plain-none] Code cli_text("{.email bugs.bunny@acme.com}") Message 'bugs.bunny@acme.com' # {.email} [fancy-none] Code cli_text("{.email bugs.bunny@acme.com}") Message bugs.bunny@acme.com # {.email} [plain-all] Code cli_text("{.email bugs.bunny@acme.com}") Message ']8;;mailto:bugs.bunny@acme.combugs.bunny@acme.com]8;;' # {.email} [fancy-all] Code cli_text("{.email bugs.bunny@acme.com}") Message ]8;;mailto:bugs.bunny@acme.combugs.bunny@acme.com]8;; # {.email} vectors [plain-none] Code emails <- paste0("bugs.bunny-", 1:3, "@acme.com") cli_text("{.email {emails}}") Message 'bugs.bunny-1@acme.com', 'bugs.bunny-2@acme.com', and 'bugs.bunny-3@acme.com' # {.email} vectors [fancy-none] Code emails <- paste0("bugs.bunny-", 1:3, "@acme.com") cli_text("{.email {emails}}") Message bugs.bunny-1@acme.com, bugs.bunny-2@acme.com, and bugs.bunny-3@acme.com # {.email} vectors [plain-all] Code emails <- paste0("bugs.bunny-", 1:3, "@acme.com") cli_text("{.email {emails}}") Message ']8;;mailto:bugs.bunny-1@acme.combugs.bunny-1@acme.com]8;;', ']8;;mailto:bugs.bunny-2@acme.combugs.bunny-2@acme.com]8;;', and ']8;;mailto:bugs.bunny-3@acme.combugs.bunny-3@acme.com]8;;' # {.email} vectors [fancy-all] Code emails <- paste0("bugs.bunny-", 1:3, "@acme.com") cli_text("{.email {emails}}") Message ]8;;mailto:bugs.bunny-1@acme.combugs.bunny-1@acme.com]8;;, ]8;;mailto:bugs.bunny-2@acme.combugs.bunny-2@acme.com]8;;, and ]8;;mailto:bugs.bunny-3@acme.combugs.bunny-3@acme.com]8;; # {.file} and {.path} [plain-none] Code cli_text("{.file /absolute/path}") Message '/absolute/path' Code cli_text("{.file file:///absolute/path}") Message 'file:///absolute/path' Code cli_text("{.path /absolute/path}") Message '/absolute/path' Code cli_text("{.path file:///absolute/path}") Message 'file:///absolute/path' --- Code cli_text("{.file relative/path}") Message 'relative/path' Code cli_text("{.file ./relative/path}") Message './relative/path' Code cli_text("{.path relative/path}") Message 'relative/path' Code cli_text("{.path ./relative/path}") Message './relative/path' --- Code cli_text("{.file ~/relative/path}") Message '~/relative/path' Code cli_text("{.path ~/relative/path}") Message '~/relative/path' --- Code paths <- c("~/foo", "bar", "file:///abs") cli_text("{.file {paths}}") Message '~/foo', 'bar', and 'file:///abs' --- Code paths <- c("foo ", " bar ", "file:///a bs ") cli_text("{.file {paths}}") Message 'foo ', ' bar ', and 'file:///a bs ' --- Code name <- cli::style_hyperlink("/foo/bar", "/foo/bar") cli_text("{.file {name}}") Message '/foo/bar' --- Code cli_text("{.file /absolute/path:12}") Message '/absolute/path:12' Code cli_text("{.file file:///absolute/path:5}") Message 'file:///absolute/path:5' Code cli_text("{.path /absolute/path:123}") Message '/absolute/path:123' Code cli_text("{.path file:///absolute/path:51}") Message 'file:///absolute/path:51' --- Code cli_text("{.file relative/path:12}") Message 'relative/path:12' Code cli_text("{.file ./relative/path:5}") Message './relative/path:5' Code cli_text("{.path relative/path:123}") Message 'relative/path:123' Code cli_text("{.path ./relative/path:51}") Message './relative/path:51' --- Code cli_text("{.file ~/relative/path:12}") Message '~/relative/path:12' Code cli_text("{.path ~/relative/path:5}") Message '~/relative/path:5' --- Code cli_text("{.file /absolute/path:12:5}") Message '/absolute/path:12:5' Code cli_text("{.file file:///absolute/path:5:100}") Message 'file:///absolute/path:5:100' Code cli_text("{.path /absolute/path:123:1}") Message '/absolute/path:123:1' Code cli_text("{.path file:///absolute/path:51:6}") Message 'file:///absolute/path:51:6' --- Code cli_text("{.file relative/path:12:13}") Message 'relative/path:12:13' Code cli_text("{.file ./relative/path:5:20}") Message './relative/path:5:20' Code cli_text("{.path relative/path:123:21}") Message 'relative/path:123:21' Code cli_text("{.path ./relative/path:51:2}") Message './relative/path:51:2' --- Code cli_text("{.file ~/relative/path:12:23}") Message '~/relative/path:12:23' Code cli_text("{.path ~/relative/path:5:2}") Message '~/relative/path:5:2' --- Code paths <- c("~/foo", "bar:10", "file:///abs:10:20") cli_text("{.file {paths}}") Message '~/foo', 'bar:10', and 'file:///abs:10:20' # {.file} and {.path} [fancy-none] Code cli_text("{.file /absolute/path}") Message /absolute/path Code cli_text("{.file file:///absolute/path}") Message file:///absolute/path Code cli_text("{.path /absolute/path}") Message /absolute/path Code cli_text("{.path file:///absolute/path}") Message file:///absolute/path --- Code cli_text("{.file relative/path}") Message relative/path Code cli_text("{.file ./relative/path}") Message ./relative/path Code cli_text("{.path relative/path}") Message relative/path Code cli_text("{.path ./relative/path}") Message ./relative/path --- Code cli_text("{.file ~/relative/path}") Message ~/relative/path Code cli_text("{.path ~/relative/path}") Message ~/relative/path --- Code paths <- c("~/foo", "bar", "file:///abs") cli_text("{.file {paths}}") Message ~/foo, bar, and file:///abs --- Code paths <- c("foo ", " bar ", "file:///a bs ") cli_text("{.file {paths}}") Message 'foo ', ' bar ', and 'file:///a bs ' --- Code name <- cli::style_hyperlink("/foo/bar", "/foo/bar") cli_text("{.file {name}}") Message /foo/bar --- Code cli_text("{.file /absolute/path:12}") Message /absolute/path:12 Code cli_text("{.file file:///absolute/path:5}") Message file:///absolute/path:5 Code cli_text("{.path /absolute/path:123}") Message /absolute/path:123 Code cli_text("{.path file:///absolute/path:51}") Message file:///absolute/path:51 --- Code cli_text("{.file relative/path:12}") Message relative/path:12 Code cli_text("{.file ./relative/path:5}") Message ./relative/path:5 Code cli_text("{.path relative/path:123}") Message relative/path:123 Code cli_text("{.path ./relative/path:51}") Message ./relative/path:51 --- Code cli_text("{.file ~/relative/path:12}") Message ~/relative/path:12 Code cli_text("{.path ~/relative/path:5}") Message ~/relative/path:5 --- Code cli_text("{.file /absolute/path:12:5}") Message /absolute/path:12:5 Code cli_text("{.file file:///absolute/path:5:100}") Message file:///absolute/path:5:100 Code cli_text("{.path /absolute/path:123:1}") Message /absolute/path:123:1 Code cli_text("{.path file:///absolute/path:51:6}") Message file:///absolute/path:51:6 --- Code cli_text("{.file relative/path:12:13}") Message relative/path:12:13 Code cli_text("{.file ./relative/path:5:20}") Message ./relative/path:5:20 Code cli_text("{.path relative/path:123:21}") Message relative/path:123:21 Code cli_text("{.path ./relative/path:51:2}") Message ./relative/path:51:2 --- Code cli_text("{.file ~/relative/path:12:23}") Message ~/relative/path:12:23 Code cli_text("{.path ~/relative/path:5:2}") Message ~/relative/path:5:2 --- Code paths <- c("~/foo", "bar:10", "file:///abs:10:20") cli_text("{.file {paths}}") Message ~/foo, bar:10, and file:///abs:10:20 # {.file} and {.path} [plain-all] Code cli_text("{.file /absolute/path}") Message ']8;;file:///absolute/path/absolute/path]8;;' Code cli_text("{.file file:///absolute/path}") Message ']8;;file:///absolute/pathfile:///absolute/path]8;;' Code cli_text("{.path /absolute/path}") Message ']8;;file:///absolute/path/absolute/path]8;;' Code cli_text("{.path file:///absolute/path}") Message ']8;;file:///absolute/pathfile:///absolute/path]8;;' --- Code cli_text("{.file relative/path}") Message ']8;;file:///testthat/home/relative/pathrelative/path]8;;' Code cli_text("{.file ./relative/path}") Message ']8;;file:///testthat/home/./relative/path./relative/path]8;;' Code cli_text("{.path relative/path}") Message ']8;;file:///testthat/home/relative/pathrelative/path]8;;' Code cli_text("{.path ./relative/path}") Message ']8;;file:///testthat/home/./relative/path./relative/path]8;;' --- Code cli_text("{.file ~/relative/path}") Message ']8;;file:///my/home/relative/path~/relative/path]8;;' Code cli_text("{.path ~/relative/path}") Message ']8;;file:///my/home/relative/path~/relative/path]8;;' --- Code paths <- c("~/foo", "bar", "file:///abs") cli_text("{.file {paths}}") Message ']8;;file:///my/home/foo~/foo]8;;', ']8;;file:///testthat/home/barbar]8;;', and ']8;;file:///absfile:///abs]8;;' --- Code paths <- c("foo ", " bar ", "file:///a bs ") cli_text("{.file {paths}}") Message ']8;;file:///testthat/home/foo foo]8;; ', ' ]8;;file:///testthat/home/ bar bar]8;; ', and ']8;;file:///a bs file:///a bs]8;; ' --- Code name <- cli::style_hyperlink("/foo/bar", "/foo/bar") cli_text("{.file {name}}") Message ']8;;/foo/bar/foo/bar]8;;' --- Code cli_text("{.file /absolute/path:12}") Message ']8;line = 12:col = 1;file:///absolute/path/absolute/path:12]8;;' Code cli_text("{.file file:///absolute/path:5}") Message ']8;line = 5:col = 1;file:///absolute/pathfile:///absolute/path:5]8;;' Code cli_text("{.path /absolute/path:123}") Message ']8;line = 123:col = 1;file:///absolute/path/absolute/path:123]8;;' Code cli_text("{.path file:///absolute/path:51}") Message ']8;line = 51:col = 1;file:///absolute/pathfile:///absolute/path:51]8;;' --- Code cli_text("{.file relative/path:12}") Message ']8;line = 12:col = 1;file:///testthat/home/relative/pathrelative/path:12]8;;' Code cli_text("{.file ./relative/path:5}") Message ']8;line = 5:col = 1;file:///testthat/home/./relative/path./relative/path:5]8;;' Code cli_text("{.path relative/path:123}") Message ']8;line = 123:col = 1;file:///testthat/home/relative/pathrelative/path:123]8;;' Code cli_text("{.path ./relative/path:51}") Message ']8;line = 51:col = 1;file:///testthat/home/./relative/path./relative/path:51]8;;' --- Code cli_text("{.file ~/relative/path:12}") Message ']8;line = 12:col = 1;file:///my/home/relative/path~/relative/path:12]8;;' Code cli_text("{.path ~/relative/path:5}") Message ']8;line = 5:col = 1;file:///my/home/relative/path~/relative/path:5]8;;' --- Code cli_text("{.file /absolute/path:12:5}") Message ']8;line = 12:col = 5;file:///absolute/path/absolute/path:12:5]8;;' Code cli_text("{.file file:///absolute/path:5:100}") Message ']8;line = 5:col = 100;file:///absolute/pathfile:///absolute/path:5:100]8;;' Code cli_text("{.path /absolute/path:123:1}") Message ']8;line = 123:col = 1;file:///absolute/path/absolute/path:123:1]8;;' Code cli_text("{.path file:///absolute/path:51:6}") Message ']8;line = 51:col = 6;file:///absolute/pathfile:///absolute/path:51:6]8;;' --- Code cli_text("{.file relative/path:12:13}") Message ']8;line = 12:col = 13;file:///testthat/home/relative/pathrelative/path:12:13]8;;' Code cli_text("{.file ./relative/path:5:20}") Message ']8;line = 5:col = 20;file:///testthat/home/./relative/path./relative/path:5:20]8;;' Code cli_text("{.path relative/path:123:21}") Message ']8;line = 123:col = 21;file:///testthat/home/relative/pathrelative/path:123:21]8;;' Code cli_text("{.path ./relative/path:51:2}") Message ']8;line = 51:col = 2;file:///testthat/home/./relative/path./relative/path:51:2]8;;' --- Code cli_text("{.file ~/relative/path:12:23}") Message ']8;line = 12:col = 23;file:///my/home/relative/path~/relative/path:12:23]8;;' Code cli_text("{.path ~/relative/path:5:2}") Message ']8;line = 5:col = 2;file:///my/home/relative/path~/relative/path:5:2]8;;' --- Code paths <- c("~/foo", "bar:10", "file:///abs:10:20") cli_text("{.file {paths}}") Message ']8;;file:///my/home/foo~/foo]8;;', ']8;line = 10:col = 1;file:///testthat/home/barbar:10]8;;', and ']8;line = 10:col = 20;file:///absfile:///abs:10:20]8;;' # {.file} and {.path} [fancy-all] Code cli_text("{.file /absolute/path}") Message ]8;;file:///absolute/path/absolute/path]8;; Code cli_text("{.file file:///absolute/path}") Message ]8;;file:///absolute/pathfile:///absolute/path]8;; Code cli_text("{.path /absolute/path}") Message ]8;;file:///absolute/path/absolute/path]8;; Code cli_text("{.path file:///absolute/path}") Message ]8;;file:///absolute/pathfile:///absolute/path]8;; --- Code cli_text("{.file relative/path}") Message ]8;;file:///testthat/home/relative/pathrelative/path]8;; Code cli_text("{.file ./relative/path}") Message ]8;;file:///testthat/home/./relative/path./relative/path]8;; Code cli_text("{.path relative/path}") Message ]8;;file:///testthat/home/relative/pathrelative/path]8;; Code cli_text("{.path ./relative/path}") Message ]8;;file:///testthat/home/./relative/path./relative/path]8;; --- Code cli_text("{.file ~/relative/path}") Message ]8;;file:///my/home/relative/path~/relative/path]8;; Code cli_text("{.path ~/relative/path}") Message ]8;;file:///my/home/relative/path~/relative/path]8;; --- Code paths <- c("~/foo", "bar", "file:///abs") cli_text("{.file {paths}}") Message ]8;;file:///my/home/foo~/foo]8;;, ]8;;file:///testthat/home/barbar]8;;, and ]8;;file:///absfile:///abs]8;; --- Code paths <- c("foo ", " bar ", "file:///a bs ") cli_text("{.file {paths}}") Message ']8;;file:///testthat/home/foo foo]8;; ', ' ]8;;file:///testthat/home/ bar bar]8;; ', and ']8;;file:///a bs file:///a bs]8;; ' --- Code name <- cli::style_hyperlink("/foo/bar", "/foo/bar") cli_text("{.file {name}}") Message ]8;;/foo/bar/foo/bar]8;; --- Code cli_text("{.file /absolute/path:12}") Message ]8;line = 12:col = 1;file:///absolute/path/absolute/path:12]8;; Code cli_text("{.file file:///absolute/path:5}") Message ]8;line = 5:col = 1;file:///absolute/pathfile:///absolute/path:5]8;; Code cli_text("{.path /absolute/path:123}") Message ]8;line = 123:col = 1;file:///absolute/path/absolute/path:123]8;; Code cli_text("{.path file:///absolute/path:51}") Message ]8;line = 51:col = 1;file:///absolute/pathfile:///absolute/path:51]8;; --- Code cli_text("{.file relative/path:12}") Message ]8;line = 12:col = 1;file:///testthat/home/relative/pathrelative/path:12]8;; Code cli_text("{.file ./relative/path:5}") Message ]8;line = 5:col = 1;file:///testthat/home/./relative/path./relative/path:5]8;; Code cli_text("{.path relative/path:123}") Message ]8;line = 123:col = 1;file:///testthat/home/relative/pathrelative/path:123]8;; Code cli_text("{.path ./relative/path:51}") Message ]8;line = 51:col = 1;file:///testthat/home/./relative/path./relative/path:51]8;; --- Code cli_text("{.file ~/relative/path:12}") Message ]8;line = 12:col = 1;file:///my/home/relative/path~/relative/path:12]8;; Code cli_text("{.path ~/relative/path:5}") Message ]8;line = 5:col = 1;file:///my/home/relative/path~/relative/path:5]8;; --- Code cli_text("{.file /absolute/path:12:5}") Message ]8;line = 12:col = 5;file:///absolute/path/absolute/path:12:5]8;; Code cli_text("{.file file:///absolute/path:5:100}") Message ]8;line = 5:col = 100;file:///absolute/pathfile:///absolute/path:5:100]8;; Code cli_text("{.path /absolute/path:123:1}") Message ]8;line = 123:col = 1;file:///absolute/path/absolute/path:123:1]8;; Code cli_text("{.path file:///absolute/path:51:6}") Message ]8;line = 51:col = 6;file:///absolute/pathfile:///absolute/path:51:6]8;; --- Code cli_text("{.file relative/path:12:13}") Message ]8;line = 12:col = 13;file:///testthat/home/relative/pathrelative/path:12:13]8;; Code cli_text("{.file ./relative/path:5:20}") Message ]8;line = 5:col = 20;file:///testthat/home/./relative/path./relative/path:5:20]8;; Code cli_text("{.path relative/path:123:21}") Message ]8;line = 123:col = 21;file:///testthat/home/relative/pathrelative/path:123:21]8;; Code cli_text("{.path ./relative/path:51:2}") Message ]8;line = 51:col = 2;file:///testthat/home/./relative/path./relative/path:51:2]8;; --- Code cli_text("{.file ~/relative/path:12:23}") Message ]8;line = 12:col = 23;file:///my/home/relative/path~/relative/path:12:23]8;; Code cli_text("{.path ~/relative/path:5:2}") Message ]8;line = 5:col = 2;file:///my/home/relative/path~/relative/path:5:2]8;; --- Code paths <- c("~/foo", "bar:10", "file:///abs:10:20") cli_text("{.file {paths}}") Message ]8;;file:///my/home/foo~/foo]8;;, ]8;line = 10:col = 1;file:///testthat/home/barbar:10]8;;, and ]8;line = 10:col = 20;file:///absfile:///abs:10:20]8;; # {.fun} [plain-none] Code cli_text("{.fun myfun}") Message `myfun()` Code cli_text("{.fun mypackage::myfun}") Message `mypackage::myfun()` --- Code funs <- paste0("mypkg::myfun", 1:3) cli_text("{.fun {funs}}") Message `mypkg::myfun1()`, `mypkg::myfun2()`, and `mypkg::myfun3()` # {.fun} [plain-all] Code cli_text("{.fun myfun}") Message `myfun()` Code cli_text("{.fun mypackage::myfun}") Message `]8;;x-r-help:mypackage::myfunmypackage::myfun]8;;()` --- Code funs <- paste0("mypkg::myfun", 1:3) cli_text("{.fun {funs}}") Message `]8;;x-r-help:mypkg::myfun1mypkg::myfun1]8;;()`, `]8;;x-r-help:mypkg::myfun2mypkg::myfun2]8;;()`, and `]8;;x-r-help:mypkg::myfun3mypkg::myfun3]8;;()` # turning off help [plain-all] Code cli_text("{.fun pkg::func}") Message `pkg::func()` # .fun with custom format [plain-all] Code cli_text("{.fun pkg::func}") Message `]8;;aaa-pkg::func-zzzpkg::func]8;;()` # {.help} [plain-none] Code cli_text("{.help pkg::fun}") Message `?pkg::fun()` Code cli_text("{.help [link text](pkg::fun)}") Message link text (`?pkg::fun()`) --- Code funcs <- paste0("pkg::fun", 1:3) cli_text("{.help {funcs}}") Message `?pkg::fun1()`, `?pkg::fun2()`, and `?pkg::fun3()` # {.help} [plain-all] Code cli_text("{.help pkg::fun}") Message ]8;;x-r-help:pkg::funpkg::fun]8;; Code cli_text("{.help [link text](pkg::fun)}") Message ]8;;x-r-help:pkg::funlink text]8;; --- Code funcs <- paste0("pkg::fun", 1:3) cli_text("{.help {funcs}}") Message ]8;;x-r-help:pkg::fun1pkg::fun1]8;;, ]8;;x-r-help:pkg::fun2pkg::fun2]8;;, and ]8;;x-r-help:pkg::fun3pkg::fun3]8;; # .help with custom format [plain-all] Code cli_text("{.help pkg::fun}") Message ]8;;aaa-pkg::fun-zzzpkg::fun]8;; # {.href} [plain-none] Code cli_text("{.href https://cli.r-lib.org}") Message Code cli_text("{.href [linktext](https://cli.r-lib.org)}") Message linktext () Code cli_text("{.href [link text](https://cli.r-lib.org)}") Message link text () # {.href} [plain-all] Code cli_text("{.href https://cli.r-lib.org}") Message <]8;;https://cli.r-lib.orghttps://cli.r-lib.org]8;;> Code cli_text("{.href [linktext](https://cli.r-lib.org)}") Message ]8;;https://cli.r-lib.orglinktext]8;; Code cli_text("{.href [link text](https://cli.r-lib.org)}") Message ]8;;https://cli.r-lib.orglink text]8;; # {.href} vectors [plain-none] Code url <- paste0("https://cli.r-lib.org/", 1:3) cli_text("{.href {url}}") Message , , and # {.href} vectors [plain-all] Code url <- paste0("https://cli.r-lib.org/", 1:3) cli_text("{.href {url}}") Message <]8;;https://cli.r-lib.org/1https://cli.r-lib.org/1]8;;>, <]8;;https://cli.r-lib.org/2https://cli.r-lib.org/2]8;;>, and <]8;;https://cli.r-lib.org/3https://cli.r-lib.org/3]8;;> # {.run} [plain-none] Code cli_text("{.run pkg::fun(param)}") Message `pkg::fun(param)` Code cli_text("{.run [run(p1, p2)](pkg::fun(p1, p2, other = 'foo'))}") Message `run(p1, p2)` # {.run} [plain-all] Code cli_text("{.run pkg::fun(param)}") Message ]8;;x-r-run:pkg::fun(param)pkg::fun(param)]8;; Code cli_text("{.run [run(p1, p2)](pkg::fun(p1, p2, other = 'foo'))}") Message ]8;;x-r-run:pkg::fun(p1, p2, other = 'foo')run(p1, p2)]8;; # {.run} vectors [plain-none] Code codes <- paste0("pkg::fun", 1:3, "()") cli_text("{.run {codes}}") Message `pkg::fun1()`, `pkg::fun2()`, and `pkg::fun3()` # {.run} vectors [plain-all] Code codes <- paste0("pkg::fun", 1:3, "()") cli_text("{.run {codes}}") Message ]8;;x-r-run:pkg::fun1()pkg::fun1()]8;;, ]8;;x-r-run:pkg::fun2()pkg::fun2()]8;;, and ]8;;x-r-run:pkg::fun3()pkg::fun3()]8;; # .run with custom format [plain-all] Code cli_text("{.run devtools::document()}") Message ]8;;aaa-devtools::document()-zzzdevtools::document()]8;; # {.topic} [plain-none] Code cli_text("{.topic pkg::topic}") Message `?pkg::topic` Code cli_text("{.topic [link text](pkg::topic)}") Message link text (`?pkg::topic`) --- Code topics <- paste0("pkg::topic", 1:3) cli_text("{.topic {topics}}") Message `?pkg::topic1`, `?pkg::topic2`, and `?pkg::topic3` # {.topic} [plain-all] Code cli_text("{.topic pkg::topic}") Message ]8;;x-r-help:pkg::topicpkg::topic]8;; Code cli_text("{.topic [link text](pkg::topic)}") Message ]8;;x-r-help:pkg::topiclink text]8;; --- Code topics <- paste0("pkg::topic", 1:3) cli_text("{.topic {topics}}") Message ]8;;x-r-help:pkg::topic1pkg::topic1]8;;, ]8;;x-r-help:pkg::topic2pkg::topic2]8;;, and ]8;;x-r-help:pkg::topic3pkg::topic3]8;; # .topic with custom format [plain-all] Code cli_text("{.topic pkg::fun}") Message ]8;;aaa-pkg::fun-zzzpkg::fun]8;; # {.url} [plain-none] Code cli_text("{.url https://cli.r-lib.org}") Message # {.url} [fancy-none] Code cli_text("{.url https://cli.r-lib.org}") Message  # {.url} [plain-all] Code cli_text("{.url https://cli.r-lib.org}") Message <]8;;https://cli.r-lib.orghttps://cli.r-lib.org]8;;> # {.url} [fancy-all] Code cli_text("{.url https://cli.r-lib.org}") Message <]8;;https://cli.r-lib.orghttps://cli.r-lib.org]8;;> # {.url} vector [plain-none] Code urls <- paste0("https://cli.r-lib.org/", 1:3) cli_text("{.url {urls}}") Message , , and # {.url} vector [fancy-none] Code urls <- paste0("https://cli.r-lib.org/", 1:3) cli_text("{.url {urls}}") Message , , and  # {.url} vector [plain-all] Code urls <- paste0("https://cli.r-lib.org/", 1:3) cli_text("{.url {urls}}") Message <]8;;https://cli.r-lib.org/1https://cli.r-lib.org/1]8;;>, <]8;;https://cli.r-lib.org/2https://cli.r-lib.org/2]8;;>, and <]8;;https://cli.r-lib.org/3https://cli.r-lib.org/3]8;;> # {.url} vector [fancy-all] Code urls <- paste0("https://cli.r-lib.org/", 1:3) cli_text("{.url {urls}}") Message <]8;;https://cli.r-lib.org/1https://cli.r-lib.org/1]8;;>, <]8;;https://cli.r-lib.org/2https://cli.r-lib.org/2]8;;>, and <]8;;https://cli.r-lib.org/3https://cli.r-lib.org/3]8;;> # linked {.url} [plain-all] Code link <- c("https://cli.r-lib.org", style_hyperlink("text", "https://cli.r-lib.org")) cli_text("{.url {link}}") Message <]8;;https://cli.r-lib.orghttps://cli.r-lib.org]8;;> and <]8;;https://cli.r-lib.orgtext]8;;> # {.vignette} [plain-none] Code cli_text("{.vignette pkg::name}") Message `vignette(pkg::name)` Code cli_text("{.vignette [link text](pkg::name)}") Message link text (`vignette(pkg::name)`) --- Code vignettes <- paste0("pkg::topic", 1:3) cli_text("{.vignette {vignettes}}") Message `vignette(pkg::topic1)`, `vignette(pkg::topic2)`, and `vignette(pkg::topic3)` # {.vignette} [plain-all] Code cli_text("{.vignette pkg::name}") Message ]8;;x-r-vignette:pkg::namepkg::name]8;; Code cli_text("{.vignette [link text](pkg::name)}") Message ]8;;x-r-vignette:pkg::namelink text]8;; --- Code vignettes <- paste0("pkg::topic", 1:3) cli_text("{.vignette {vignettes}}") Message ]8;;x-r-vignette:pkg::topic1pkg::topic1]8;;, ]8;;x-r-vignette:pkg::topic2pkg::topic2]8;;, and ]8;;x-r-vignette:pkg::topic3pkg::topic3]8;; # .vignette with custom format [plain-all] Code cli_text("{.vignette pkgdown::accessibility}") Message ]8;;aaa-pkgdown::accessibility-zzzpkgdown::accessibility]8;; cli/tests/testthat/_snaps/glue.md0000644000176200001440000000174414752734111016577 0ustar liggesusers# glue quotes and comments Code cli_dl(c(test_1 = "all good", test_2 = "not #good")) Message test_1: all good test_2: not #good Code cli::cli_dl(c(test_3 = "no' good either")) Message test_3: no' good either Code cli::cli_dl(c(test_4 = "no\" good also")) Message test_4: no" good also Code cli::cli_text("{.url https://example.com/#section}") Message Code cli::cli_alert_success("Qapla'") Message v Qapla' # quotes, etc. within expressions are still OK Code cli::cli_text("{.url URL} {x <- 'foo'; nchar(x)}") Message 3 Code cli::cli_text("{.url URL} {x <- \"foo\"; nchar(x)}") Message 3 Code cli::cli_text("{.url URL} {1 + 1 # + 1} {1 + 1}") Message 2 2 # { } is parsed with literal = FALSE Code format_message("{.emph {'{foo {}'}}") Output [1] "{foo {}" cli/tests/testthat/_snaps/inline-2.md0000644000176200001440000002634414752734113017265 0ustar liggesusers# quoting phrases that don't start or end with letter or number [plain] Code local({ x0 <- "good-name" cli_text("The name is {.file {x0}}.") x <- "weird-name " cli_text("The name is {.file {x}}.") cli_text("The name is {.path {x}}.") cli_text("The name is {.email {x}}.") }) Message The name is 'good-name'. The name is 'weird-name '. The name is 'weird-name '. The name is 'weird-name '. # quoting phrases that don't start or end with letter or number [ansi] Code local({ x0 <- "good-name" cli_text("The name is {.file {x0}}.") x <- "weird-name " cli_text("The name is {.file {x}}.") cli_text("The name is {.path {x}}.") cli_text("The name is {.email {x}}.") }) Message The name is good-name. The name is 'weird-name '. The name is 'weird-name '. The name is 'weird-name '. # quoting weird names, still [plain] Code local({ cat_line(nb(quote_weird_name("good"))) cat_line(nb(quote_weird_name(" bad"))) cat_line(nb(quote_weird_name("bad "))) cat_line(nb(quote_weird_name(" bad "))) }) Output 'good' ' bad' 'bad ' ' bad ' # quoting weird names, still [ansi] Code local({ cat_line(nb(quote_weird_name("good"))) cat_line(nb(quote_weird_name(" bad"))) cat_line(nb(quote_weird_name("bad "))) cat_line(nb(quote_weird_name(" bad "))) }) Output good ' bad' 'bad ' ' bad ' # ~/ files are not weird [ansi] Code local({ cat_line(nb(quote_weird_name("~/good"))) cat_line(nb(quote_weird_name("~~bad"))) cat_line(nb(quote_weird_name("bad~ "))) cat_line(nb(quote_weird_name(" ~ bad ~ "))) }) Output ~/good '~~bad' 'bad~ ' ' ~ bad ~ ' # custom truncation [plain] Code x <- cli_vec(1:100, list(`vec-trunc` = 5)) cli_text("Some numbers: {x}.") Message Some numbers: 1, 2, 3, ..., 99, and 100. Code cli_text("Some numbers: {.val {x}}.") Message Some numbers: 1, 2, 3, ..., 99, and 100. # custom truncation [ansi] Code x <- cli_vec(1:100, list(`vec-trunc` = 5)) cli_text("Some numbers: {x}.") Message Some numbers: 1, 2, 3, ..., 99, and 100. Code cli_text("Some numbers: {.val {x}}.") Message Some numbers: 1, 2, 3, ..., 99, and 100. # custom truncation [unicode] Code x <- cli_vec(1:100, list(`vec-trunc` = 5)) cli_text("Some numbers: {x}.") Message Some numbers: 1, 2, 3, …, 99, and 100. Code cli_text("Some numbers: {.val {x}}.") Message Some numbers: 1, 2, 3, …, 99, and 100. # custom truncation [fancy] Code x <- cli_vec(1:100, list(`vec-trunc` = 5)) cli_text("Some numbers: {x}.") Message Some numbers: 1, 2, 3, …, 99, and 100. Code cli_text("Some numbers: {.val {x}}.") Message Some numbers: 1, 2, 3, …, 99, and 100. # collapsing class names [plain] Code local({ cc <- c("one", "two") cli_text("this is a class: {.cls myclass}") cli_text("multiple classes: {.cls {cc}}") }) Message this is a class: multiple classes: # collapsing class names [ansi] Code local({ cc <- c("one", "two") cli_text("this is a class: {.cls myclass}") cli_text("multiple classes: {.cls {cc}}") }) Message this is a class:  multiple classes:  # transform [plain] Code local({ cli_text("This is a {.field field} (before)") foo <- (function(x) toupper(x)) cli_div(theme = list(span.field = list(transform = foo))) cli_text("This is a {.field field} (during)") cli_end() cli_text("This is a {.field field} (after)") }) Message This is a field (before) This is a FIELD (during) This is a field (after) # transform [ansi] Code local({ cli_text("This is a {.field field} (before)") foo <- (function(x) toupper(x)) cli_div(theme = list(span.field = list(transform = foo))) cli_text("This is a {.field field} (during)") cli_end() cli_text("This is a {.field field} (after)") }) Message This is a field (before) This is a FIELD (during) This is a field (after) # cli_format Code cli_format(1:4 / 7, list(digits = 2)) Output [1] 0.14 0.29 0.43 0.57 # cli_format() is used for .val Code local({ cli_div(theme = list(.val = list(digits = 2))) cli_text("Some random numbers: {.val {runif(4)}}.") }) Message Some random numbers: 0.91, 0.94, 0.29, and 0.83. # .q always double quotes Code cli_text("just a {.q string}, nothing more") Message just a "string", nothing more # .or Code cli_text("{.or {letters[1:5]}}") Message a, b, c, d, or e --- Code cli_text("{.or {letters[1:2]}}") Message a or b # line breaks Code ansi_strwrap(txt2, width = 60) Output [1] Cupidatat deserunt culpa enim deserunt minim aliqua tempor [2] fugiat cupidatat laboris officia esse ex aliqua. Ullamco [3] mollit adipisicing anim. [4] Cupidatat deserunt culpa enim deserunt minim aliqua tempor [5] fugiat cupidatat laboris officia esse ex aliqua. Ullamco [6] mollit adipisicing anim. # double ticks [ansi] Code format_inline("{.code {x}}") Output [1] "\033[31m`a`\033[39m, \033[31m`` `x` ``\033[39m, and \033[31m`b`\033[39m" --- Code format_inline("{.fun {x}}") Output [1] "\033[31m`a()`\033[39m, \033[31m`` `x` ()``\033[39m, and \033[31m`b()`\033[39m" # do not inherit 'transform' issue #422 Code d <- deparse(c("cli", "glue")) cli::cli_alert_info("To install, run {.code install.packages({d})}") Message i To install, run `install.packages(c("cli", "glue"))` --- Code cli::cli_text("{.code foo({1+1})}") Message `foo(2)` # no inherit color, issue #474 [plain] Code cli::cli_text("pre {.val x {'foo'} y} post") Message pre "x foo y" post # no inherit color, issue #474 [ansi] Code cli::cli_text("pre {.val x {'foo'} y} post") Message pre "x foo y" post # \f at the end, issue #491 [plain] Code cli_fmt(cli::cli_text("{.val a}{.val b}")) Output [1] "\"a\"\"b\"" Code cli_fmt(cli::cli_text("\f{.val a}{.val b}")) Output [1] "" "\"a\"\"b\"" Code cli_fmt(cli::cli_text("\f\f{.val a}{.val b}")) Output [1] "" "" "\"a\"\"b\"" Code cli_fmt(cli::cli_text("{.val a}\f{.val b}")) Output [1] "\"a\"" "\"b\"" Code cli_fmt(cli::cli_text("{.val a}\f\f{.val b}")) Output [1] "\"a\"" "" "\"b\"" Code cli_fmt(cli::cli_text("{.val a}{.val b}\f")) Output [1] "\"a\"\"b\"" "" Code cli_fmt(cli::cli_text("{.val a}{.val b}\f\f")) Output [1] "\"a\"\"b\"" "" "" Code cli_fmt(cli::cli_text("\f\f\f{.val a}\f\f\f{.val b}\f\f\f")) Output [1] "" "" "" "\"a\"" "" "" "\"b\"" "" "" [10] "" # \f at the end, issue #491 [ansi] Code cli_fmt(cli::cli_text("{.val a}{.val b}")) Output [1] "\033[34m\"a\"\"b\"\033[39m" Code cli_fmt(cli::cli_text("\f{.val a}{.val b}")) Output [1] "" "\033[34m\"a\"\"b\"\033[39m" Code cli_fmt(cli::cli_text("\f\f{.val a}{.val b}")) Output [1] "" "" [3] "\033[34m\"a\"\"b\"\033[39m" Code cli_fmt(cli::cli_text("{.val a}\f{.val b}")) Output [1] "\033[34m\"a\"\033[39m" "\033[34m\"b\"\033[39m" Code cli_fmt(cli::cli_text("{.val a}\f\f{.val b}")) Output [1] "\033[34m\"a\"\033[39m" "" "\033[34m\"b\"\033[39m" Code cli_fmt(cli::cli_text("{.val a}{.val b}\f")) Output [1] "\033[34m\"a\"\"b\"\033[39m" "" Code cli_fmt(cli::cli_text("{.val a}{.val b}\f\f")) Output [1] "\033[34m\"a\"\"b\"\033[39m" "" [3] "" Code cli_fmt(cli::cli_text("\f\f\f{.val a}\f\f\f{.val b}\f\f\f")) Output [1] "" "" "" [4] "\033[34m\"a\"\033[39m" "" "" [7] "\033[34m\"b\"\033[39m" "" "" [10] "" # truncate vectors at 20 Code cli::cli_text("Some letters: {letters}") Message Some letters: a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, ..., y, and z # brace expresssion edge cases [ansi] Code cli_text("{.code {foo} and {bar}}") Message `foo and bar` Code cli_text("{.emph {foo} and {bar}}") Message foo and bar Code cli_text("{.q {foo} and {bar}}") Message "foo and bar" # various errors ! Invalid cli literal: `{.foobar}` starts with a dot. i Interpreted literals must not start with a dot in cli >= 3.4.0. i `{}` expressions starting with a dot are now only used for cli styles. i To avoid this error, put a space character after the starting `{` or use parentheses: `{(.foobar)}`. --- ! Invalid cli literal: `{.someve...}` starts with a dot. i Interpreted literals must not start with a dot in cli >= 3.4.0. i `{}` expressions starting with a dot are now only used for cli styles. i To avoid this error, put a space character after the starting `{` or use parentheses: `{(.someve...)}`. --- Code cli_text("xx {1 + 'a'} yy") Condition Error: ! Could not evaluate cli `{}` expression: `1 + 'a'`. Caused by error: ! non-numeric argument to binary operator # format_inline and newlines Code format_inline("foo\nbar") Output [1] "foo\nbar" Code format_inline("\nfoo\n\nbar\n") Output [1] "\nfoo\n\nbar\n" Code format_inline("foo\fbar") Output [1] "foo\fbar" Code format_inline("\ffoo\f\fbar\f") Output [1] "\ffoo\f\fbar\f" --- Code format_inline("foo\nbar", keep_whitespace = FALSE) Output [1] "foo bar" Code format_inline("\nfoo\n\nbar\n", keep_whitespace = FALSE) Output [1] "foo\n\nbar" Code format_inline("foo\fbar", keep_whitespace = FALSE) Output [1] "foo\nbar" Code format_inline("\ffoo\f\fbar\f", keep_whitespace = FALSE) Output [1] "\nfoo\n\nbar\n" cli/tests/testthat/_snaps/type.md0000644000176200001440000000666014752734137016636 0ustar liggesusers# type style Code cli_text("{.obj_type_friendly {mtcars}}") Message a data frame Code cli_text("{.obj_type_friendly {tibble::as_tibble(mtcars)}}") Message a tibble Code cli_text("{.obj_type_friendly {rlang::quo(1)}}") Message a object Code cli_text("{.obj_type_friendly {list()}}") Message an empty list Code cli_text("{.obj_type_friendly {matrix(list(1, 2))}}") Message a list matrix Code cli_text("{.obj_type_friendly {array(list(1, 2, 3))}}") Message a list Code cli_text("{.obj_type_friendly {integer()}}") Message an empty integer vector Code cli_text("{.obj_type_friendly {matrix(1:3)}}") Message an integer matrix Code cli_text("{.obj_type_friendly {array(1:3, dim = 1:3)}}") Message an integer array Code cli_text("{.obj_type_friendly {character()}}") Message an empty character vector Code cli_text("{.obj_type_friendly {matrix(letters)}}") Message a character matrix Code cli_text("{.obj_type_friendly {array(letters[1:3], dim = 1:3)}}") Message a character array Code typename(quote(expr = )) Output [1] "absent" Code cli_text("{.obj_type_friendly {NA}}") Message `NA` Code cli_text("{.obj_type_friendly {NA_integer_}}") Message an integer `NA` Code cli_text("{.obj_type_friendly {NA_real_}}") Message a numeric `NA` Code cli_text("{.obj_type_friendly {NA_complex_}}") Message a complex `NA` Code cli_text("{.obj_type_friendly {NA_character_}}") Message a character `NA` Code cli_text("{.obj_type_friendly {TRUE}}") Message `TRUE` Code cli_text("{.obj_type_friendly {FALSE}}") Message `FALSE` Code cli_text("{.obj_type_friendly {1L}}") Message an integer Code cli_text("{.obj_type_friendly {1.0}}") Message a number Code cli_text("{.obj_type_friendly {1i}}") Message a complex number Code cli_text("{.obj_type_friendly {as.raw(1L)}}") Message a raw value Code cli_text("{.obj_type_friendly {'foo'}}") Message a string Code cli_text("{.obj_type_friendly {''}}") Message `""` Code cli_text("{.obj_type_friendly {list(1)}}") Message a list Code cli_text("{.obj_type_friendly {matrix(NA)}}") Message a logical matrix Code cli_text("{.obj_type_friendly {matrix(1)}}") Message a double matrix Code cli_text("{.obj_type_friendly {logical()}}") Message an empty logical vector Code cli_text("{.obj_type_friendly {integer()}}") Message an empty integer vector Code cli_text("{.obj_type_friendly {double()}}") Message an empty numeric vector Code cli_text("{.obj_type_friendly {complex()}}") Message an empty complex vector Code cli_text("{.obj_type_friendly {character()}}") Message an empty character vector Code cli_text("{.obj_type_friendly {raw()}}") Message an empty raw vector Code cli_text("{.obj_type_friendly {list()}}") Message an empty list Code cli_text("{.obj_type_friendly {structure(1, class = 'igraph')}}") Message an object cli/tests/testthat/_snaps/diff.md0000644000176200001440000000765314752734110016557 0ustar liggesusers# diff_chr Code d$lcs Output operation offset length old_offset new_offset 1 match 0 8 8 8 2 delete 8 1 9 8 3 insert 8 1 9 9 4 match 9 7 16 16 5 insert 16 2 16 18 6 match 16 1 17 19 --- Code d$lcs Output operation offset length old_offset new_offset 1 match 0 8 8 8 2 delete 8 1 9 8 3 insert 8 1 9 9 4 match 9 7 16 16 5 delete 16 2 18 16 6 match 18 1 19 17 # diff_chr [plain] Code d Output @@ -6,7 +6,7 @@ 1 1 2 -3 +10 4 4 4 @@ -14,4 +14,6 @@ 4 4 4 +6 +7 5 --- Code d$lcs Output operation offset length old_offset new_offset 1 match 0 8 8 8 2 delete 8 1 9 8 3 insert 8 1 9 9 4 match 9 7 16 16 5 insert 16 2 16 18 6 match 16 1 17 19 # diff_chr [ansi] Code d Output @@ -6,7 +6,7 @@ 1 1 2 -3 +10 4 4 4 @@ -14,4 +14,6 @@ 4 4 4 +6 +7 5 --- Code d$lcs Output operation offset length old_offset new_offset 1 match 0 8 8 8 2 delete 8 1 9 8 3 insert 8 1 9 9 4 match 9 7 16 16 5 insert 16 2 16 18 6 match 16 1 17 19 # diff_chr edge cases Code diff_chr(character(), character()) --- Code diff_chr(character(), character())$lcs Output [1] operation offset length old_offset new_offset <0 rows> (or 0-length row.names) --- Code diff_chr("a", character()) Output @@ -1 +0 @@ -a --- Code diff_chr(character(), "b") Output @@ -0 +1 @@ +b --- Code diff_chr("a", "a") --- Code diff_chr(letters, letters) --- Code diff_chr(c("a", NA, "a2"), "b") Output @@ -1,3 +1 @@ -a -NA -a2 +b --- Code diff_chr(NA_character_, "NA") Output @@ -1 +1 @@ -NA +NA # format.cli_diff_chr context Code print(d, context = 1) Output @@ -8,3 +8,3 @@ 2 -3 +10 4 @@ -16,2 +16,4 @@ 4 +6 +7 5 --- Code print(d, context = 0) Output @@ -9 +9 @@ -3 +10 @@ -17,0 +17,2 @@ +6 +7 --- Code print(d, context = Inf) Output 1 1 1 1 1 1 1 2 -3 +10 4 4 4 4 4 4 4 +6 +7 5 --- Code print(d2, context = Inf) Output foo bar # diff_str [plain] Code d Output {+PRE+}abcdefg[-hijklm-]{+MIDDLE+}nopqrstuvwxyz{+POST+} # diff_str [ansi] Code d Output PREabcdefghijklmMIDDLEnopqrstuvwxyzPOST # max_diff ! Diff edit distance is larger than the limit. i The edit distance limit is 0. --- ! Diff edit distance is larger than the limit. i The edit distance limit is 1. cli/tests/testthat/_snaps/ansi-hyperlink.md0000644000176200001440000000234614752734100020575 0ustar liggesusers# unknown hyperlink type Code make_link("this", "foobar") Condition Error in `match.arg()`: ! 'arg' should be one of "email", "file", "fun", "help", "href", "run", "topic", "url", "vignette" # iterm file links Code cli::cli_text("{.file /path/to/file:10}") Message ']8;;file:///path/to/file#10/path/to/file:10]8;;' Code cli::cli_text("{.file /path/to/file:10:20}") Message ']8;;file:///path/to/file#10:20/path/to/file:10:20]8;;' # rstudio links Code cli::cli_text("{.fun pkg::fun}") Message `]8;;ide:help:pkg::funpkg::fun]8;;()` --- Code cli::cli_text("{.help fun}") Message ]8;;ide:help:funfun]8;; --- Code cli::cli_text("{.run package::func()}") Message ]8;;ide:run:package::func()package::func()]8;; --- Code cli::cli_text("{.vignette package::title}") Message ]8;;ide:vignette:package::titlepackage::title]8;; --- Code cli::cli_text("{.topic pkg::topic}") Message ]8;;ide:help:pkg::topicpkg::topic]8;; # ST hyperlinks Code cat(style_hyperlink("text", "https://example.com")) Output ]8;;https://example.com\text]8;;\ cli/tests/testthat/_snaps/containers.md0000644000176200001440000000510414752734107020007 0ustar liggesusers# auto closing Code local({ cli_div(theme = list(`.xx .emph` = list(before = "itsu:"))) f <- (function() { cli_par(class = "xx") cli_text("foo {.emph blah} bar") }) f() cli_text("foo {.emph blah} bar") }) Message foo itsu:blah bar foo blah bar # opt out of auto closing Code local({ cli_div(theme = list(`.xx .emph` = list(before = "itsu:"))) id <- NULL f <- (function() { id <<- cli_par(class = "xx", .auto_close = FALSE) cli_text("foo {.emph blah} bar") }) f() cli_text("foo {.emph blah} bar") expect_false(is.null(id)) cli_end(id) cli_text("foo {.emph blah} bar") }) Message foo itsu:blah bar foo itsu:blah bar foo blah bar # auto closing with special env Code local({ cli_div(theme = list(`.xx .emph` = list(before = "itsu:"))) f <- (function() { g() cli_text("foo {.emph blah} bar") }) g <- (function() { cli_par(class = "xx", .auto_close = TRUE, .envir = parent.frame()) cli_text("foo {.emph blah} bar") }) f() cli_text("foo {.emph blah} bar") }) Message foo itsu:blah bar foo itsu:blah bar foo blah bar # div with special style Code f <- (function() { cli_div(theme = list(`.xx .emph` = list(before = "itsu:"))) cli_par(class = "xx") cli_text("foo {.emph blah} bar") }) f() Message foo itsu:blah bar Code cli_text("foo {.emph blah} bar") Message foo blah bar # margin is squashed Code local({ cli_div(theme = list(par = list(`margin-top` = 4, `margin-bottom` = 4))) cli_text("three lines") cli_par() cli_par() cli_par() cli_text("until here") cli_end() cli_end() cli_end() cli_par() cli_par() cli_par() cli_text("no space, still") cli_end() cli_end() cli_end() cli_text("three lines again") }) Message three lines until here no space, still three lines again # before and after work properly Code local({ cli_div(theme = list(`div.alert-success` = list(before = "!!!"))) cli_alert_success("{.pkg foobar} is good") }) Message !!!foobar is good cli/tests/testthat/_snaps/text.md0000644000176200001440000000163514752734136016635 0ustar liggesusers# text is wrapped Code local({ cli_div(class = "testcli", theme = test_style()) cli_h1("Header") cli_text(lorem_ipsum()) }) Message Header Duis quis magna incididunt nulla commodo minim non exercitation nostrud ullamco dolor exercitation ut veniam. Fugiat irure tempor commodo voluptate ut. In et tempor excepteur quis. Qui et nisi ad quis ad cupidatat tempor laborum est excepteur aliqua veniam. Velit sunt magna veniam Lorem elit enim et pariatur. Occaecat mollit consequat dolore in. Veniam officia labore reprehenderit culpa dolore quis nisi do aliqua commodo deserunt. Cupidatat nostrud ad est in ad laboris consectetur esse minim. Irure do anim anim ea mollit ad cupidatat ullamco ullamco nulla elit in. Lorem Lorem deserunt deserunt et ut velit nulla nulla ipsum ad laborum quis. cli/tests/testthat/_snaps/non-breaking-space.md0000644000176200001440000000042314752734123021302 0ustar liggesusers# does not break Code local({ withr::local_options(cli.width = 40) str30 <- "123456789 123456789 1234567890" cli_text(c(str30, "this is not breaking")) }) Message 123456789 123456789 1234567890this is not breaking cli/tests/testthat/_snaps/pluralization.md0000644000176200001440000001437114752735214020545 0ustar liggesusers# simplest Code for (n in 0:2) cli_text("{n} package{?s}") Message 0 packages 1 package 2 packages Code for (n in 0:2) print(pluralize("{n} package{?s}")) Output 0 packages 1 package 2 packages # irregular Code for (n in 0:2) cli_text("{n} dictionar{?y/ies}") Message 0 dictionaries 1 dictionary 2 dictionaries Code for (n in 0:2) print(pluralize("{n} dictionar{?y/ies}")) Output 0 dictionaries 1 dictionary 2 dictionaries # multiple substitutions Code for (n in 0:2) cli_text("{n} package{?s} {?is/are} ...") Message 0 packages are ... 1 package is ... 2 packages are ... Code for (n in 0:2) print(pluralize("{n} package{?s} {?is/are} ...")) Output 0 packages are ... 1 package is ... 2 packages are ... # multiple quantities Code for (m in 0:2) for (n in 0:2) cli_text("{m} package{?s} and {n} folder{?s}") Message 0 packages and 0 folders 0 packages and 1 folder 0 packages and 2 folders 1 package and 0 folders 1 package and 1 folder 1 package and 2 folders 2 packages and 0 folders 2 packages and 1 folder 2 packages and 2 folders Code for (m in 0:2) for (n in 0:2) print(pluralize( "{m} package{?s} and {n} folder{?s}")) Output 0 packages and 0 folders 0 packages and 1 folder 0 packages and 2 folders 1 package and 0 folders 1 package and 1 folder 1 package and 2 folders 2 packages and 0 folders 2 packages and 1 folder 2 packages and 2 folders # no() Code for (n in 0:2) cli_text("{no(n)} package{?s}") Message no packages 1 package 2 packages Code for (n in 0:2) print(pluralize("{no(n)} package{?s}")) Output no packages 1 package 2 packages # set qty() explicitly Code for (n in 0:2) cli_text("{qty(n)}There {?is/are} {n} package{?s}") Message There are 0 packages There is 1 package There are 2 packages Code for (n in 0:2) print(pluralize("{qty(n)}There {?is/are} {n} package{?s}")) Output There are 0 packages There is 1 package There are 2 packages # collapsing vectors Code pkgs <- (function(n) glue::glue("pkg{seq_len(n)}")) for (n in 1:3) cli_text("The {pkgs(n)} package{?s}") Message The pkg1 package The pkg1 and pkg2 packages The pkg1, pkg2, and pkg3 packages Code for (n in 1:3) print(pluralize("The {pkgs(n)} package{?s}")) Output The pkg1 package The pkg1 and pkg2 packages The pkg1, pkg2, and pkg3 packages # pluralization and style Code special_style <- list(span.foo = list(before = "<", after = ">")) cli_div(theme = special_style) for (n in 0:2) cli_text("{n} {.foo package{?s}}") Message 0 packages 1 package 2 packages --- Code pkgs <- (function(n) glue::glue("pkg{seq_len(n)}")) for (n in 1:3) cli_text("The {.foo {pkgs(n)}} package{?s}") Message The pkg1 package The pkg1 and pkg2 packages The pkg1, pkg2, and pkg3 packages # post-processing Code for (n in 0:2) cli_text("Package{?s}: {n}") Message Packages: 0 Package: 1 Packages: 2 --- Code pkgs <- (function(n) glue::glue("pkg{seq_len(n)}")) for (n in 1:2) cli_text("Package{?s}: {pkgs(n)}") Message Package: pkg1 Packages: pkg1 and pkg2 Code for (n in 1:2) print(pluralize("Package{?s}: {pkgs(n)}")) Output Package: pkg1 Packages: pkg1 and pkg2 # issue 158 Code print(pluralize("{0} word{?A/B/}")) Output 0 wordA Code print(pluralize("{1} word{?A/B/}")) Output 1 wordB Code print(pluralize("{9} word{?A/B/}")) Output 9 word # Edge cases for pluralize() (#701) Code print(pluralize("{NA} file{?s} expected")) Output NA file expected Code print(pluralize("{NA_character_} file{?s} expected")) Output NA file expected Code print(pluralize("{NA_real_} file{?s} expected")) Output NA files expected Code print(pluralize("{NA_integer_} file{?s} expected")) Output NA files expected Code print(pluralize("{NaN} file{?s} expected")) Output NaN files expected Code print(pluralize("{Inf} file{?s} expected")) Output Inf files expected Code print(pluralize("{-Inf} file{?s} expected")) Output -Inf files expected --- Code print(pluralize("Found {NA} director{?y/ies}.")) Output Found NA directory. Code print(pluralize("Found {NA_character_} director{?y/ies}.")) Output Found NA directory. Code print(pluralize("Found {NA_real_} director{?y/ies}.")) Output Found NA directories. Code print(pluralize("Found {NA_integer_} director{?y/ies}.")) Output Found NA directories. Code print(pluralize("Found {NaN} director{?y/ies}.")) Output Found NaN directories. Code print(pluralize("Found {Inf} director{?y/ies}.")) Output Found Inf directories. Code print(pluralize("Found {-Inf} director{?y/ies}.")) Output Found -Inf directories. --- Code print(pluralize("Will remove {?no/the/the} {NA} package{?s}.")) Output Will remove the NA package. Code print(pluralize("Will remove {?no/the/the} {NA_character_} package{?s}.")) Output Will remove the NA package. Code print(pluralize("Will remove {?no/the/the} {NA_real_} package{?s}.")) Output Will remove the NA packages. Code print(pluralize("Will remove {?no/the/the} {NA_integer_} package{?s}.")) Output Will remove the NA packages. Code print(pluralize("Will remove {?no/the/the} {NaN} package{?s}.")) Output Will remove the NaN packages. Code print(pluralize("Will remove {?no/the/the} {Inf} package{?s}.")) Output Will remove the Inf packages. Code print(pluralize("Will remove {?no/the/the} {-Inf} package{?s}.")) Output Will remove the -Inf packages. cli/tests/testthat/_snaps/bullets.md0000644000176200001440000002363314752734105017321 0ustar liggesusers# bullets [plain] Code cli_bullets(c("noindent", ` ` = "space", v = "success", x = "danger", `!` = "warning", i = "info", `*` = "bullet", `>` = "arrow")) Message noindent space v success x danger ! warning i info * bullet > arrow # bullets [ansi] Code cli_bullets(c("noindent", ` ` = "space", v = "success", x = "danger", `!` = "warning", i = "info", `*` = "bullet", `>` = "arrow")) Message noindent space v success x danger ! warning i info * bullet > arrow # bullets [unicode] Code cli_bullets(c("noindent", ` ` = "space", v = "success", x = "danger", `!` = "warning", i = "info", `*` = "bullet", `>` = "arrow")) Message noindent space ✔ success ✖ danger ! warning ℹ info • bullet → arrow # bullets [fancy] Code cli_bullets(c("noindent", ` ` = "space", v = "success", x = "danger", `!` = "warning", i = "info", `*` = "bullet", `>` = "arrow")) Message noindent space ✔ success ✖ danger ! warning ℹ info • bullet → arrow # bullets glue [plain] Code cli_bullets(c("noindent {.key {1:3}}", ` ` = "space {.key {1:3}}", v = "success {.key {1:3}}", x = "danger {.key {1:3}}", `!` = "warning {.key {1:3}}", i = "info {.key {1:3}}", `*` = "bullet {.key {1:3}}", `>` = "arrow {.key {1:3}}")) Message noindent [1], [2], and [3] space [1], [2], and [3] v success [1], [2], and [3] x danger [1], [2], and [3] ! warning [1], [2], and [3] i info [1], [2], and [3] * bullet [1], [2], and [3] > arrow [1], [2], and [3] # bullets glue [ansi] Code cli_bullets(c("noindent {.key {1:3}}", ` ` = "space {.key {1:3}}", v = "success {.key {1:3}}", x = "danger {.key {1:3}}", `!` = "warning {.key {1:3}}", i = "info {.key {1:3}}", `*` = "bullet {.key {1:3}}", `>` = "arrow {.key {1:3}}")) Message noindent [1], [2], and [3] space [1], [2], and [3] v success [1], [2], and [3] x danger [1], [2], and [3] ! warning [1], [2], and [3] i info [1], [2], and [3] * bullet [1], [2], and [3] > arrow [1], [2], and [3] # bullets glue [unicode] Code cli_bullets(c("noindent {.key {1:3}}", ` ` = "space {.key {1:3}}", v = "success {.key {1:3}}", x = "danger {.key {1:3}}", `!` = "warning {.key {1:3}}", i = "info {.key {1:3}}", `*` = "bullet {.key {1:3}}", `>` = "arrow {.key {1:3}}")) Message noindent [1], [2], and [3] space [1], [2], and [3] ✔ success [1], [2], and [3] ✖ danger [1], [2], and [3] ! warning [1], [2], and [3] ℹ info [1], [2], and [3] • bullet [1], [2], and [3] → arrow [1], [2], and [3] # bullets glue [fancy] Code cli_bullets(c("noindent {.key {1:3}}", ` ` = "space {.key {1:3}}", v = "success {.key {1:3}}", x = "danger {.key {1:3}}", `!` = "warning {.key {1:3}}", i = "info {.key {1:3}}", `*` = "bullet {.key {1:3}}", `>` = "arrow {.key {1:3}}")) Message noindent [1], [2], and [3] space [1], [2], and [3] ✔ success [1], [2], and [3] ✖ danger [1], [2], and [3] ! warning [1], [2], and [3] ℹ info [1], [2], and [3] • bullet [1], [2], and [3] → arrow [1], [2], and [3] # bullets wrapping [plain] Code cli_bullets(c(txt, ` ` = txt, v = txt, x = txt, `!` = txt, i = txt, `*` = txt, `>` = txt)) Message This is some text that is longer than the width. This is some text that is longer than the width. This is some text that is longer than the width. This is some text that is longer than the width. This is some text that is longer than the width. This is some text that is longer than the width. v This is some text that is longer than the width. This is some text that is longer than the width. This is some text that is longer than the width. x This is some text that is longer than the width. This is some text that is longer than the width. This is some text that is longer than the width. ! This is some text that is longer than the width. This is some text that is longer than the width. This is some text that is longer than the width. i This is some text that is longer than the width. This is some text that is longer than the width. This is some text that is longer than the width. * This is some text that is longer than the width. This is some text that is longer than the width. This is some text that is longer than the width. > This is some text that is longer than the width. This is some text that is longer than the width. This is some text that is longer than the width. # bullets wrapping [ansi] Code cli_bullets(c(txt, ` ` = txt, v = txt, x = txt, `!` = txt, i = txt, `*` = txt, `>` = txt)) Message This is some text that is longer than the width. This is some text that is longer than the width. This is some text that is longer than the width. This is some text that is longer than the width. This is some text that is longer than the width. This is some text that is longer than the width. v This is some text that is longer than the width. This is some text that is longer than the width. This is some text that is longer than the width. x This is some text that is longer than the width. This is some text that is longer than the width. This is some text that is longer than the width. ! This is some text that is longer than the width. This is some text that is longer than the width. This is some text that is longer than the width. i This is some text that is longer than the width. This is some text that is longer than the width. This is some text that is longer than the width. * This is some text that is longer than the width. This is some text that is longer than the width. This is some text that is longer than the width. > This is some text that is longer than the width. This is some text that is longer than the width. This is some text that is longer than the width. # bullets wrapping [unicode] Code cli_bullets(c(txt, ` ` = txt, v = txt, x = txt, `!` = txt, i = txt, `*` = txt, `>` = txt)) Message This is some text that is longer than the width. This is some text that is longer than the width. This is some text that is longer than the width. This is some text that is longer than the width. This is some text that is longer than the width. This is some text that is longer than the width. ✔ This is some text that is longer than the width. This is some text that is longer than the width. This is some text that is longer than the width. ✖ This is some text that is longer than the width. This is some text that is longer than the width. This is some text that is longer than the width. ! This is some text that is longer than the width. This is some text that is longer than the width. This is some text that is longer than the width. ℹ This is some text that is longer than the width. This is some text that is longer than the width. This is some text that is longer than the width. • This is some text that is longer than the width. This is some text that is longer than the width. This is some text that is longer than the width. → This is some text that is longer than the width. This is some text that is longer than the width. This is some text that is longer than the width. # bullets wrapping [fancy] Code cli_bullets(c(txt, ` ` = txt, v = txt, x = txt, `!` = txt, i = txt, `*` = txt, `>` = txt)) Message This is some text that is longer than the width. This is some text that is longer than the width. This is some text that is longer than the width. This is some text that is longer than the width. This is some text that is longer than the width. This is some text that is longer than the width. ✔ This is some text that is longer than the width. This is some text that is longer than the width. This is some text that is longer than the width. ✖ This is some text that is longer than the width. This is some text that is longer than the width. This is some text that is longer than the width. ! This is some text that is longer than the width. This is some text that is longer than the width. This is some text that is longer than the width. ℹ This is some text that is longer than the width. This is some text that is longer than the width. This is some text that is longer than the width. • This is some text that is longer than the width. This is some text that is longer than the width. This is some text that is longer than the width. → This is some text that is longer than the width. This is some text that is longer than the width. This is some text that is longer than the width. cli/tests/testthat/_snaps/progress-variables.md0000644000176200001440000001253314752734133021457 0ustar liggesusers# cli_progress_demo Code out Output \ 50 done (100/s) | 3ms --- Code out Output ==========>-------------------- 33% | ETA: 1s ====================>---------- 67% | ETA: 1s ==============================> 100% | ETA: 1s  --- Code out Output \ 1 done (100/s) | 3ms | 2 done (100/s) | 3ms / 3 done (100/s) | 3ms - 4 done (100/s) | 3ms \ 5 done (100/s) | 3ms  --- Code out Output ==========>-------------------- 33% | ETA: 10s ====================>---------- 67% | ETA: 3s ==============================> 100% | ETA: 0s  --- Code msgs Output [1] "\r==========>-------------------- 33% | ETA: 10s\033[K\r" [2] "\r====================>---------- 67% | ETA: 3s\033[K\r" [3] "\r==============================> 100% | ETA: 0s\033[K\r" [4] "\r\033[K" # pb_bar Code cli_text("-{cli::pb_bar}-") Message -- --- Code cli_text("-{cli::pb_bar}-") Message -===============>--------------- - # pb_current_bytes Code cli__pb_current_bytes(list(current = 0)) Output [1] "0.0 kB" Code cli__pb_current_bytes(list(current = 1)) Output [1] "0.0 kB" Code cli__pb_current_bytes(list(current = 1000)) Output [1] "1.0 kB" Code cli__pb_current_bytes(list(current = 1000 * 23)) Output [1] " 23 kB" Code cli__pb_current_bytes(list(current = 1000 * 1000 * 23)) Output [1] " 23 MB" # pb_elapsed Code cli__pb_elapsed() Output [1] "1s" --- Code cli__pb_elapsed() Output [1] "21s" --- Code cli__pb_elapsed() Output [1] "58s" --- Code cli__pb_elapsed() Output [1] "1h 5m" # pb_elapsed_clock Code cli__pb_elapsed_clock() Output [1] "00:00:01" --- Code cli__pb_elapsed_clock() Output [1] "00:00:21" --- Code cli__pb_elapsed_clock() Output [1] "00:00:58" --- Code cli__pb_elapsed_clock() Output [1] "01:05:00" # pb_elapsed_raw Code cli__pb_elapsed_raw() Output [1] 1 --- Code cli__pb_elapsed_raw() Output [1] 21 --- Code cli__pb_elapsed_raw() Output [1] 58 --- Code cli__pb_elapsed_raw() Output [1] 3900 # pb_eta Code cli__pb_eta(list()) Output [1] "?" --- Code cli__pb_eta(list()) Output [1] "12s" # pb_eta_raw Code cli__pb_eta_raw() Output [1] NA --- Code cli__pb_eta_raw() Output Time difference of 40 secs --- Code cli__pb_eta_raw() Output Time difference of 10 secs --- Code cli__pb_eta_raw() Output Time difference of 0 secs # pb_eta_str Code cli__pb_eta_str(list()) Output [1] "" --- Code cli__pb_eta_str(list()) Output [1] "ETA: 1s" # pb_percent Code cli__pb_percent(list(current = 0, total = 99)) Output [1] " 0%" Code cli__pb_percent(list(current = 5, total = 99)) Output [1] " 5%" Code cli__pb_percent(list(current = 10, total = 99)) Output [1] " 10%" Code cli__pb_percent(list(current = 25, total = 99)) Output [1] " 25%" Code cli__pb_percent(list(current = 99, total = 99)) Output [1] "100%" Code cli__pb_percent(list(current = 100, total = 99)) Output [1] "101%" # pb_rate Code cli__pb_rate(list()) Output [1] "?/s" --- Code cli__pb_rate(list()) Output [1] "?/s" --- Code cli__pb_rate(list()) Output [1] "0.1/s" --- Code cli__pb_rate(list()) Output [1] "12/s" # pb_rate_bytes Code cli__pb_rate_bytes(list()) Output [1] "NaN kB/s" --- Code cli__pb_rate_bytes(list()) Output [1] "Inf YB/s" --- Code cli__pb_rate_bytes(list()) Output [1] "0.0 kB/s" --- Code cli__pb_rate_bytes(list()) Output [1] "1.0 kB/s" --- Code cli__pb_rate_bytes(list()) Output [1] " 24 kB/s" --- Code cli__pb_rate_bytes(list()) Output [1] " 24 MB/s" # pb_spin Code cli_text("-{cli::pb_spin}-{cli::pb_spin}-") Message -\-\- --- Code cli_text("-{cli::pb_spin}-{cli::pb_spin}-") Message -|-|- --- Code cli_text("-{cli::pb_spin}-{cli::pb_spin}-") Message -|-|- # pb_timestamp Code cli__pb_timestamp(list()) Output [1] "2021-06-18T00:09:14+00:00" --- Code cli__pb_timestamp(list()) Output [1] "2021-06-18T00:09:34+00:00" # pb_total_bytes Code cli__pb_total_bytes(list(total = 0)) Output [1] "0.0 kB" Code cli__pb_total_bytes(list(total = 1)) Output [1] "0.0 kB" Code cli__pb_total_bytes(list(total = 1000)) Output [1] "1.0 kB" Code cli__pb_total_bytes(list(total = 1000 * 23)) Output [1] " 23 kB" Code cli__pb_total_bytes(list(total = 1000 * 1000 * 23)) Output [1] " 23 MB" cli/tests/testthat/_snaps/lists.md0000644000176200001440000002657314752734123017013 0ustar liggesusers# ul [plain] Code local({ lid <- cli_ul() cli_li("foo") cli_li(c("bar", "foobar")) cli_end(lid) }) Message * foo * bar * foobar # ul [unicode] Code local({ lid <- cli_ul() cli_li("foo") cli_li(c("bar", "foobar")) cli_end(lid) }) Message • foo • bar • foobar # ol [plain] Code local({ cli_div(theme = list(ol = list())) lid <- cli_ol() cli_li("foo") cli_li(c("bar", "foobar")) cli_end(lid) }) Message 1. foo 2. bar 3. foobar # ol [unicode] Code local({ cli_div(theme = list(ol = list())) lid <- cli_ol() cli_li("foo") cli_li(c("bar", "foobar")) cli_end(lid) }) Message 1. foo 2. bar 3. foobar # ul ul [plain] Code local({ cli_div(theme = list(`ul ul` = list(`list-style-type` = "-", `margin-left` = 2))) lid <- cli_ul() cli_li("1") lid2 <- cli_ul() cli_li("1 1") cli_li(c("1 2", "1 3")) cli_end(lid2) cli_li("2") cli_end(lid) }) Message * 1 - 1 1 - 1 2 - 1 3 * 2 # ul ul [unicode] Code local({ cli_div(theme = list(`ul ul` = list(`list-style-type` = "-", `margin-left` = 2))) lid <- cli_ul() cli_li("1") lid2 <- cli_ul() cli_li("1 1") cli_li(c("1 2", "1 3")) cli_end(lid2) cli_li("2") cli_end(lid) }) Message • 1 - 1 1 - 1 2 - 1 3 • 2 # ul ol [plain] Code local({ cli_div(theme = list(li = list(`margin-left` = 2))) lid <- cli_ul() cli_li("1") lid2 <- cli_ol() cli_li("1 1") cli_li(c("1 2", "1 3")) cli_end(lid2) cli_li("2") cli_end(lid) }) Message * 1 1. 1 1 2. 1 2 3. 1 3 * 2 # ul ol [unicode] Code local({ cli_div(theme = list(li = list(`margin-left` = 2))) lid <- cli_ul() cli_li("1") lid2 <- cli_ol() cli_li("1 1") cli_li(c("1 2", "1 3")) cli_end(lid2) cli_li("2") cli_end(lid) }) Message • 1 1. 1 1 2. 1 2 3. 1 3 • 2 # ol ol [plain] Code local({ cli_div(theme = list(li = list(`margin-left` = 2), `li li` = list( `margin-left` = 2))) lid <- cli_ol() cli_li("1") lid2 <- cli_ol() cli_li("1 1") cli_li(c("1 2", "1 3")) cli_end(lid2) cli_li("2") cli_end(lid) }) Message 1. 1 1. 1 1 2. 1 2 3. 1 3 2. 2 # ol ol [unicode] Code local({ cli_div(theme = list(li = list(`margin-left` = 2), `li li` = list( `margin-left` = 2))) lid <- cli_ol() cli_li("1") lid2 <- cli_ol() cli_li("1 1") cli_li(c("1 2", "1 3")) cli_end(lid2) cli_li("2") cli_end(lid) }) Message 1. 1 1. 1 1 2. 1 2 3. 1 3 2. 2 # ol ul [plain] Code local({ cli_div(theme = list(ul = list(`margin-left` = 2))) lid <- cli_ol() cli_li("1") lid2 <- cli_ul() cli_li("1 1") cli_li(c("1 2", "1 3")) cli_end(lid2) cli_li("2") cli_end(lid) }) Message 1. 1 * 1 1 * 1 2 * 1 3 2. 2 # ol ul [unicode] Code local({ cli_div(theme = list(ul = list(`margin-left` = 2))) lid <- cli_ol() cli_li("1") lid2 <- cli_ul() cli_li("1 1") cli_li(c("1 2", "1 3")) cli_end(lid2) cli_li("2") cli_end(lid) }) Message 1. 1 • 1 1 • 1 2 • 1 3 2. 2 # starting with an item [plain] Code local({ cli_li("foo") cli_li(c("bar", "foobar")) cli_end() cli_end() }) Message * foo * bar * foobar # starting with an item [unicode] Code local({ cli_li("foo") cli_li(c("bar", "foobar")) cli_end() cli_end() }) Message • foo • bar • foobar # ol, with first item [plain] Code local({ cli_div(theme = list(ol = list())) lid <- cli_ol("foo", .close = FALSE) cli_li(c("bar", "foobar")) cli_end(lid) }) Message 1. foo 2. bar 3. foobar # ol, with first item [unicode] Code local({ cli_div(theme = list(ol = list())) lid <- cli_ol("foo", .close = FALSE) cli_li(c("bar", "foobar")) cli_end(lid) }) Message 1. foo 2. bar 3. foobar # ul, with first item [plain] Code local({ lid <- cli_ul("foo", .close = FALSE) cli_li(c("bar", "foobar")) cli_end(lid) }) Message * foo * bar * foobar # ul, with first item [unicode] Code local({ lid <- cli_ul("foo", .close = FALSE) cli_li(c("bar", "foobar")) cli_end(lid) }) Message • foo • bar • foobar # dl [plain] Code local({ cli_div(theme = list(ul = list())) lid <- cli_dl() cli_li(c(this = "foo")) cli_li(c(that = "bar", other = "foobar")) cli_end(lid) }) Message this: foo that: bar other: foobar # dl [unicode] Code local({ cli_div(theme = list(ul = list())) lid <- cli_dl() cli_li(c(this = "foo")) cli_li(c(that = "bar", other = "foobar")) cli_end(lid) }) Message this: foo that: bar other: foobar # dl dl [plain] Code local({ cli_div(theme = list(li = list(`margin-left` = 2))) lid <- cli_dl() cli_li(c(a = "1")) lid2 <- cli_dl() cli_li(c(`a-a` = "1 1")) cli_li(c(`a-b` = "1 2", `a-c` = "1 3")) cli_end(lid2) cli_li(c(b = "2")) cli_end(lid) }) Message a: 1 a-a: 1 1 a-b: 1 2 a-c: 1 3 b: 2 # dl dl [unicode] Code local({ cli_div(theme = list(li = list(`margin-left` = 2))) lid <- cli_dl() cli_li(c(a = "1")) lid2 <- cli_dl() cli_li(c(`a-a` = "1 1")) cli_li(c(`a-b` = "1 2", `a-c` = "1 3")) cli_end(lid2) cli_li(c(b = "2")) cli_end(lid) }) Message a: 1 a-a: 1 1 a-b: 1 2 a-c: 1 3 b: 2 # dl ol [plain] Code local({ cli_div(theme = list(li = list(`margin-left` = 2))) lid <- cli_dl() cli_li(c(a = "1")) lid2 <- cli_ol() cli_li(c("1 1")) cli_li(c("1 2", "1 3")) cli_end(lid2) cli_li(c(b = "2")) cli_end(lid) }) Message a: 1 1. 1 1 2. 1 2 3. 1 3 b: 2 # dl ol [unicode] Code local({ cli_div(theme = list(li = list(`margin-left` = 2))) lid <- cli_dl() cli_li(c(a = "1")) lid2 <- cli_ol() cli_li(c("1 1")) cli_li(c("1 2", "1 3")) cli_end(lid2) cli_li(c(b = "2")) cli_end(lid) }) Message a: 1 1. 1 1 2. 1 2 3. 1 3 b: 2 # dl ul [plain] Code local({ cli_div(theme = list(li = list(`margin-left` = 2))) lid <- cli_dl() cli_li(c(a = "1")) lid2 <- cli_ul() cli_li(c("1 1")) cli_li(c("1 2", "1 3")) cli_end(lid2) cli_li(c(b = "2")) cli_end(lid) }) Message a: 1 * 1 1 * 1 2 * 1 3 b: 2 # dl ul [unicode] Code local({ cli_div(theme = list(li = list(`margin-left` = 2))) lid <- cli_dl() cli_li(c(a = "1")) lid2 <- cli_ul() cli_li(c("1 1")) cli_li(c("1 2", "1 3")) cli_end(lid2) cli_li(c(b = "2")) cli_end(lid) }) Message a: 1 • 1 1 • 1 2 • 1 3 b: 2 # ol dl [plain] Code local({ cli_div(theme = list(li = list(`margin-left` = 2))) lid <- cli_ol() cli_li("1") lid2 <- cli_dl() cli_li(c(`a-a` = "1 1")) cli_li(c(`a-b` = "1 2", `a-c` = "1 3")) cli_end(lid2) cli_li("2") cli_end(lid) }) Message 1. 1 a-a: 1 1 a-b: 1 2 a-c: 1 3 2. 2 # ol dl [unicode] Code local({ cli_div(theme = list(li = list(`margin-left` = 2))) lid <- cli_ol() cli_li("1") lid2 <- cli_dl() cli_li(c(`a-a` = "1 1")) cli_li(c(`a-b` = "1 2", `a-c` = "1 3")) cli_end(lid2) cli_li("2") cli_end(lid) }) Message 1. 1 a-a: 1 1 a-b: 1 2 a-c: 1 3 2. 2 # ul dl [plain] Code local({ cli_div(theme = list(li = list(`margin-left` = 2))) lid <- cli_ul() cli_li("1") lid2 <- cli_dl() cli_li(c(`a-a` = "1 1")) cli_li(c(`a-b` = "1 2", `a-c` = "1 3")) cli_end(lid2) cli_li("2") cli_end(lid) }) Message * 1 a-a: 1 1 a-b: 1 2 a-c: 1 3 * 2 # ul dl [unicode] Code local({ cli_div(theme = list(li = list(`margin-left` = 2))) lid <- cli_ul() cli_li("1") lid2 <- cli_dl() cli_li(c(`a-a` = "1 1")) cli_li(c(`a-b` = "1 2", `a-c` = "1 3")) cli_end(lid2) cli_li("2") cli_end(lid) }) Message • 1 a-a: 1 1 a-b: 1 2 a-c: 1 3 • 2 # dl, with first item [plain] Code local({ cli_div(theme = list(ul = list())) lid <- cli_dl(c(this = "foo"), .close = FALSE) cli_li(c(that = "bar", other = "foobar")) cli_end(lid) }) Message this: foo that: bar other: foobar # dl, with first item [unicode] Code local({ cli_div(theme = list(ul = list())) lid <- cli_dl(c(this = "foo"), .close = FALSE) cli_li(c(that = "bar", other = "foobar")) cli_end(lid) }) Message this: foo that: bar other: foobar # styling pieces of a dl [ansi] Code local({ cli_div(theme = list(.dt = list(postfix = " -> "), .dd = list(color = "blue"))) cli_dl(c(foo = "bar", bar = "baz")) }) Message foo -> bar bar -> baz # cli_dl edge cases Code cli_dl("foo", "must be a named character vector") Condition Error: ! `items` must be a named character vector i `items` is not named --- Code cli_dl(c(abc = "foo", empty = "", def = "bar")) Message abc: foo empty: def: bar # cli_dl label style Code local({ cli_dl(c(`{.code code}` = "{.code this is code too}", `{.str strin}` = "{.url https://x.com}")) }) Message `code`: `this is code too` "strin": cli/tests/testthat/_snaps/themes.md0000644000176200001440000001111114752734136017124 0ustar liggesusers# add/remove/list themes [plain] Code cli_par(class = "green") cli_text(lorem_ipsum()) Message Non incididunt mollit ullamco duis officia proident. Laborum esse mollit mollit eiusmod tempor cupidatat. In commodo anim irure nostrud. Deserunt nisi amet laborum magna aliqua. Do esse consectetur ut deserunt nulla Lorem non. Fugiat est dolore deserunt aliqua amet et esse dolore elit exercitation sint exercitation non ipsum. Code cli_end() Message # add/remove/list themes [ansi] Code cli_par(class = "green") cli_text(lorem_ipsum()) Message Non incididunt mollit ullamco duis officia proident. Laborum esse mollit mollit eiusmod tempor cupidatat. In commodo anim irure nostrud. Deserunt nisi amet laborum magna aliqua. Do esse consectetur ut deserunt nulla Lorem non. Fugiat est dolore deserunt aliqua amet et esse dolore elit exercitation sint exercitation non ipsum. Code cli_end() Message # add/remove/list themes [unicode] Code cli_par(class = "green") cli_text(lorem_ipsum()) Message Non incididunt mollit ullamco duis officia proident. Laborum esse mollit mollit eiusmod tempor cupidatat. In commodo anim irure nostrud. Deserunt nisi amet laborum magna aliqua. Do esse consectetur ut deserunt nulla Lorem non. Fugiat est dolore deserunt aliqua amet et esse dolore elit exercitation sint exercitation non ipsum. Code cli_end() Message # add/remove/list themes [fancy] Code cli_par(class = "green") cli_text(lorem_ipsum()) Message Non incididunt mollit ullamco duis officia proident. Laborum esse mollit mollit eiusmod tempor cupidatat. In commodo anim irure nostrud. Deserunt nisi amet laborum magna aliqua. Do esse consectetur ut deserunt nulla Lorem non. Fugiat est dolore deserunt aliqua amet et esse dolore elit exercitation sint exercitation non ipsum. Code cli_end() Message # explicit formatter is used, and combined Code cli_text("this is {.emph it}, really") Message this is (((<>))), really # user's override Code local({ start_app(theme = custom, .auto_close = FALSE) cli_alert("Alert!") stop_app() withr::local_options(cli.user_theme = override) start_app(theme = custom, .auto_close = FALSE) cli_alert("Alert!") stop_app() }) Message custom:Alert! custom:Alert!override: # NULL will undo a style property Code local({ cli_alert("this has an arrow") cli_div(theme = list(.alert = list(before = NULL))) cli_alert("this does not") }) Message > this has an arrow this does not # NULL will undo color [ansi] Code local({ cli_alert("{.emph {.val this is blue}}") cli_div(theme = list(span.val = list(color = NULL))) cli_alert("{.emph {.val this is not}}") }) Message > "this is blue" > "this is not" --- Code local({ cli_alert("{.emph {.val this is blue}}") cli_div(theme = list(span.val = list(color = "none"))) cli_alert("{.emph {.val this is not}}") }) Message > "this is blue" > "this is not" # NULL will undo background color [ansi] Code local({ cli_alert("{.emph {.code this has bg color}}") cli_div(theme = list(span = list(`background-color` = NULL))) cli_alert("{.emph {.code this does not}}") }) Message > `this has bg color` > `this does not` --- Code local({ cli_alert("{.emph {.code this has bg color}}") cli_div(theme = list(span = list(`background-color` = "none"))) cli_alert("{.emph {.code this does not}}") }) Message > `this has bg color` > `this does not` cli/tests/testthat/_snaps/console-width.md0000644000176200001440000000036614752734107020426 0ustar liggesusers# errors ! `options("cli.width")` must be an integer scalar. i `options("cli.width")` is a character vector. --- ! `options("cli.width")` cannot be `NA`. --- ! `options("cli.width")` must be a positive integer and not -100. cli/tests/testthat/_snaps/progress-along.md0000644000176200001440000000420714752734125020607 0ustar liggesusers# interpolation uses the right env Code out Output [1] "\rx: 10\033[K\r" "\rx: 10\033[K\r" "\rx: 10\033[K\r" "\rx: 10\033[K\r" [5] "\r\033[K" # cli_progress_along Code lines Output [1] "2021-06-18T00:09:14+00:00 cli-36434-1 0/10 created" [2] "2021-06-18T00:09:14+00:00 cli-36434-1 0/10 added" [3] "2021-06-18T00:09:14+00:00 cli-36434-1 1/10 updated" [4] "2021-06-18T00:09:14+00:00 cli-36434-1 2/10 updated" [5] "2021-06-18T00:09:14+00:00 cli-36434-1 3/10 updated" [6] "2021-06-18T00:09:14+00:00 cli-36434-1 4/10 updated" [7] "2021-06-18T00:09:14+00:00 cli-36434-1 5/10 updated" [8] "2021-06-18T00:09:14+00:00 cli-36434-1 6/10 updated" [9] "2021-06-18T00:09:14+00:00 cli-36434-1 7/10 updated" [10] "2021-06-18T00:09:14+00:00 cli-36434-1 8/10 updated" [11] "2021-06-18T00:09:14+00:00 cli-36434-1 9/10 updated" [12] "2021-06-18T00:09:14+00:00 cli-36434-1 9/10 terminated (done)" [13] " [1] 1 2 3 4 5 6 7 8 9 10" # cli_progress_along error Code lines Output [1] "2021-06-18T00:09:14+00:00 cli-36434-1 0/10 created" [2] "2021-06-18T00:09:14+00:00 cli-36434-1 0/10 added" [3] "2021-06-18T00:09:14+00:00 cli-36434-1 1/10 updated" [4] "2021-06-18T00:09:14+00:00 cli-36434-1 2/10 updated" [5] "2021-06-18T00:09:14+00:00 cli-36434-1 3/10 updated" [6] "2021-06-18T00:09:14+00:00 cli-36434-1 4/10 updated" [7] "2021-06-18T00:09:14+00:00 cli-36434-1 4/10 terminated (failed)" [8] "Error in FUN(X[[i]], ...) : oops" # error in handler is a single warning Code cli_with_ticks(fun()) Condition Warning in `value[[3L]]()`: cli progress bar update failed: ! Could not evaluate cli `{}` expression: `1+''`. Caused by error in `1 + ""`: ! non-numeric argument to binary operator Output [1] 1 2 3 4 5 cli/tests/testthat/_snaps/alerts.md0000644000176200001440000000427214752734077017147 0ustar liggesusers# generic Code local({ cli_div(theme = list(.alert = list(before = "GENERIC! "))) cli_alert("wow") }) Message GENERIC! wow # success [plain] Code local({ cli_alert_success("wow") }) Message v wow # success [ansi] Code local({ cli_alert_success("wow") }) Message v wow # success [unicode] Code local({ cli_alert_success("wow") }) Message ✔ wow # success [fancy] Code local({ cli_alert_success("wow") }) Message ✔ wow # danger [plain] Code local({ cli_alert_danger("wow") }) Message x wow # danger [ansi] Code local({ cli_alert_danger("wow") }) Message x wow # danger [unicode] Code local({ cli_alert_danger("wow") }) Message ✖ wow # danger [fancy] Code local({ cli_alert_danger("wow") }) Message ✖ wow # warning [plain] Code local({ cli_alert_warning("wow") }) Message ! wow # warning [ansi] Code local({ cli_alert_warning("wow") }) Message ! wow # warning [unicode] Code local({ cli_alert_warning("wow") }) Message ! wow # warning [fancy] Code local({ cli_alert_warning("wow") }) Message ! wow # info [plain] Code local({ cli_alert_info("wow") }) Message i wow # info [ansi] Code local({ cli_alert_info("wow") }) Message i wow # info [unicode] Code local({ cli_alert_info("wow") }) Message ℹ wow # info [fancy] Code local({ cli_alert_info("wow") }) Message ℹ wow # before and after can have spaces Code local({ cli_div(theme = list(.alert = list(before = "x ", after = " x"))) cli_alert("continuing that first alert", wrap = TRUE) }) Message x continuing that first alert x cli/tests/testthat/_snaps/deep-lists.md0000644000176200001440000000276614752734110017720 0ustar liggesusers# deep lists ul Code for (i in 1:4) test_ul(i) Message * Level 1 * Level 1 * Level 2 * Level 1 * Level 2 * Level 3 * Level 1 * Level 2 * Level 3 * Level 4 # deep lists ol Code for (i in 1:4) test_ol(i) Message 1. Level 1 1. Level 1 1. Level 2 1. Level 1 1. Level 2 1. Level 3 1. Level 1 1. Level 2 1. Level 3 1. Level 4 # deep lists ol ul Code for (i in 1:4) test_ol_ul(i) Message 1. Level 1 * Level 2 1. Level 1 * Level 2 1. Level 3 * Level 4 1. Level 1 * Level 2 1. Level 3 * Level 4 1. Level 5 * Level 6 1. Level 1 * Level 2 1. Level 3 * Level 4 1. Level 5 * Level 6 1. Level 7 * Level 8 # deep lists ul ol Code for (i in 1:4) test_ul_ol(i) Message * Level 1 1. Level 2 * Level 1 1. Level 2 * Level 3 1. Level 4 * Level 1 1. Level 2 * Level 3 1. Level 4 * Level 5 1. Level 6 * Level 1 1. Level 2 * Level 3 1. Level 4 * Level 5 1. Level 6 * Level 7 1. Level 8 cli/tests/testthat/_snaps/format-conditions.md0000644000176200001440000002722414752734111021303 0ustar liggesusers# format_error [plain] Code local({ n <- "boo" stop(format_error(c("{.var n} must be a numeric vector", x = "You've supplied a {.cls {class(n)}} vector."))) }) Condition Error: ! `n` must be a numeric vector x You've supplied a vector. --- Code local({ len <- 26 idx <- 100 stop(format_error(c("Must index an existing element:", i = "There {?is/are} {len} element{?s}.", x = "You've tried to subset element {idx}."))) }) Condition Error: ! Must index an existing element: i There are 26 elements. x You've tried to subset element 100. # format_error [ansi] Code local({ n <- "boo" stop(format_error(c("{.var n} must be a numeric vector", x = "You've supplied a {.cls {class(n)}} vector."))) }) Condition Error: ! `n` must be a numeric vector x You've supplied a  vector. --- Code local({ len <- 26 idx <- 100 stop(format_error(c("Must index an existing element:", i = "There {?is/are} {len} element{?s}.", x = "You've tried to subset element {idx}."))) }) Condition Error: ! Must index an existing element: i There are 26 elements. x You've tried to subset element 100. # format_error [unicode] Code local({ n <- "boo" stop(format_error(c("{.var n} must be a numeric vector", x = "You've supplied a {.cls {class(n)}} vector."))) }) Condition Error: ! `n` must be a numeric vector ✖ You've supplied a vector. --- Code local({ len <- 26 idx <- 100 stop(format_error(c("Must index an existing element:", i = "There {?is/are} {len} element{?s}.", x = "You've tried to subset element {idx}."))) }) Condition Error: ! Must index an existing element: ℹ There are 26 elements. ✖ You've tried to subset element 100. # format_error [fancy] Code local({ n <- "boo" stop(format_error(c("{.var n} must be a numeric vector", x = "You've supplied a {.cls {class(n)}} vector."))) }) Condition Error: ! `n` must be a numeric vector ✖ You've supplied a  vector. --- Code local({ len <- 26 idx <- 100 stop(format_error(c("Must index an existing element:", i = "There {?is/are} {len} element{?s}.", x = "You've tried to subset element {idx}."))) }) Condition Error: ! Must index an existing element: ℹ There are 26 elements. ✖ You've tried to subset element 100. # format_warning [plain] Code n <- "boo" warning(format_warning(c("{.var n} must be a numeric vector", x = "You've supplied a {.cls {class(n)}} vector."))) Condition Warning: `n` must be a numeric vector x You've supplied a vector. --- Code local({ len <- 26 idx <- 100 warning(format_warning(c("Must index an existing element:", i = "There {?is/are} {len} element{?s}.", x = "You've tried to subset element {idx}."))) }) Condition Warning: Must index an existing element: i There are 26 elements. x You've tried to subset element 100. # format_warning [ansi] Code n <- "boo" warning(format_warning(c("{.var n} must be a numeric vector", x = "You've supplied a {.cls {class(n)}} vector."))) Condition Warning: `n` must be a numeric vector x You've supplied a  vector. --- Code local({ len <- 26 idx <- 100 warning(format_warning(c("Must index an existing element:", i = "There {?is/are} {len} element{?s}.", x = "You've tried to subset element {idx}."))) }) Condition Warning: Must index an existing element: i There are 26 elements. x You've tried to subset element 100. # format_warning [unicode] Code n <- "boo" warning(format_warning(c("{.var n} must be a numeric vector", x = "You've supplied a {.cls {class(n)}} vector."))) Condition Warning: `n` must be a numeric vector ✖ You've supplied a vector. --- Code local({ len <- 26 idx <- 100 warning(format_warning(c("Must index an existing element:", i = "There {?is/are} {len} element{?s}.", x = "You've tried to subset element {idx}."))) }) Condition Warning: Must index an existing element: ℹ There are 26 elements. ✖ You've tried to subset element 100. # format_warning [fancy] Code n <- "boo" warning(format_warning(c("{.var n} must be a numeric vector", x = "You've supplied a {.cls {class(n)}} vector."))) Condition Warning: `n` must be a numeric vector ✖ You've supplied a  vector. --- Code local({ len <- 26 idx <- 100 warning(format_warning(c("Must index an existing element:", i = "There {?is/are} {len} element{?s}.", x = "You've tried to subset element {idx}."))) }) Condition Warning: Must index an existing element: ℹ There are 26 elements. ✖ You've tried to subset element 100. # format_message [plain] Code n <- "boo" message(format_message(c("{.var n} must be a numeric vector", x = "You've supplied a {.cls {class(n)}} vector."))) Message `n` must be a numeric vector x You've supplied a vector. --- Code local({ len <- 26 idx <- 100 message(format_message(c("Must index an existing element:", i = "There {?is/are} {len} element{?s}.", x = "You've tried to subset element {idx}."))) }) Message Must index an existing element: i There are 26 elements. x You've tried to subset element 100. # format_message [ansi] Code n <- "boo" message(format_message(c("{.var n} must be a numeric vector", x = "You've supplied a {.cls {class(n)}} vector."))) Message `n` must be a numeric vector x You've supplied a  vector. --- Code local({ len <- 26 idx <- 100 message(format_message(c("Must index an existing element:", i = "There {?is/are} {len} element{?s}.", x = "You've tried to subset element {idx}."))) }) Message Must index an existing element: i There are 26 elements. x You've tried to subset element 100. # format_message [unicode] Code n <- "boo" message(format_message(c("{.var n} must be a numeric vector", x = "You've supplied a {.cls {class(n)}} vector."))) Message `n` must be a numeric vector ✖ You've supplied a vector. --- Code local({ len <- 26 idx <- 100 message(format_message(c("Must index an existing element:", i = "There {?is/are} {len} element{?s}.", x = "You've tried to subset element {idx}."))) }) Message Must index an existing element: ℹ There are 26 elements. ✖ You've tried to subset element 100. # format_message [fancy] Code n <- "boo" message(format_message(c("{.var n} must be a numeric vector", x = "You've supplied a {.cls {class(n)}} vector."))) Message `n` must be a numeric vector ✖ You've supplied a  vector. --- Code local({ len <- 26 idx <- 100 message(format_message(c("Must index an existing element:", i = "There {?is/are} {len} element{?s}.", x = "You've tried to subset element {idx}."))) }) Message Must index an existing element: ℹ There are 26 elements. ✖ You've tried to subset element 100. # color in RStudio [ansi] Code col <- get_rstudio_fg_color0() cat(col("this is the new color")) Output this is the new color # update_rstudio_color [ansi] Code cat(update_rstudio_color("color me interested")) Output color me interested # named first element Code format_error(c(`*` = "foo", `*` = "bar")) Output [1] "* foo\n* bar" --- Code format_warning(c(`*` = "foo", `*` = "bar")) Output [1] "* foo\n* bar" # cli.condition_width Code format_error(msg) Output [1] "1234567890 1234567890 1234567890\n1234567890 1234567890 1234567890\n1234567890 1234567890" Code format_warning(msg) Output [1] "1234567890 1234567890 1234567890\n1234567890 1234567890 1234567890\n1234567890 1234567890" Code format_message(msg) Output [1] "1234567890 1234567890 1234567890\n1234567890 1234567890 1234567890\n1234567890 1234567890" --- Code format_error(msg) Output [1] "1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890" Code format_warning(msg) Output [1] "1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890" Code format_message(msg) Output [1] "1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890" # suppressing Unicode bullets [plain] Code local({ n <- "boo" stop(format_error(c("{.var n} must be a numeric vector", x = "You've supplied a {.cls {class(n)}} vector.", v = "Success.", i = "Info.", `*` = "Bullet", `>` = "Arrow"))) }) Condition Error: ! `n` must be a numeric vector x You've supplied a vector. v Success. i Info. * Bullet > Arrow # suppressing Unicode bullets [ansi] Code local({ n <- "boo" stop(format_error(c("{.var n} must be a numeric vector", x = "You've supplied a {.cls {class(n)}} vector.", v = "Success.", i = "Info.", `*` = "Bullet", `>` = "Arrow"))) }) Condition Error: ! `n` must be a numeric vector x You've supplied a  vector. v Success. i Info. * Bullet > Arrow # suppressing Unicode bullets [unicode] Code local({ n <- "boo" stop(format_error(c("{.var n} must be a numeric vector", x = "You've supplied a {.cls {class(n)}} vector.", v = "Success.", i = "Info.", `*` = "Bullet", `>` = "Arrow"))) }) Condition Error: ! `n` must be a numeric vector x You've supplied a vector. v Success. i Info. * Bullet > Arrow # suppressing Unicode bullets [fancy] Code local({ n <- "boo" stop(format_error(c("{.var n} must be a numeric vector", x = "You've supplied a {.cls {class(n)}} vector.", v = "Success.", i = "Info.", `*` = "Bullet", `>` = "Arrow"))) }) Condition Error: ! `n` must be a numeric vector x You've supplied a  vector. v Success. i Info. * Bullet > Arrow cli/tests/testthat/_snaps/progress-bar.md0000644000176200001440000000502514752734126020253 0ustar liggesusers# make_progress_bar [plain] Code make_progress_bar(0.5) Output [1] "===============>--------------- " # make_progress_bar [ansi] Code make_progress_bar(0.5) Output [1] "===============>--------------- " # make_progress_bar [unicode] Code make_progress_bar(0.5) Output [1] "■■■■■■■■■■■■■■■■                " # make_progress_bar [fancy] Code make_progress_bar(0.5) Output [1] "■■■■■■■■■■■■■■■■                " # cli_progress_styles [fancy] Code make_progress_bar(0.5) Output [1] "################                " --- Code make_progress_bar(0.5) Output [1] "■■■■■■■■■■■■■■■■                " --- Code make_progress_bar(0.5) Output [1] "\033[90m─\033[39m\033[90m─\033[39m\033[90m─\033[39m\033[90m─\033[39m\033[90m─\033[39m\033[90m─\033[39m\033[90m─\033[39m\033[90m─\033[39m\033[90m─\033[39m\033[90m─\033[39m\033[90m─\033[39m\033[90m─\033[39m\033[90m─\033[39m\033[90m─\033[39m\033[90m─\033[39m\033[31m●\033[39m\033[90m─\033[39m\033[90m─\033[39m\033[90m─\033[39m\033[90m─\033[39m\033[90m─\033[39m\033[90m─\033[39m\033[90m─\033[39m\033[90m─\033[39m\033[90m─\033[39m\033[90m─\033[39m\033[90m─\033[39m\033[90m─\033[39m\033[90m─\033[39m\033[90m─\033[39m\033[90m─\033[39m " --- Code make_progress_bar(0.5) Output [1] "■■■■■■■■■■■■■■■■\033[90m□\033[39m\033[90m□\033[39m\033[90m□\033[39m\033[90m□\033[39m\033[90m□\033[39m\033[90m□\033[39m\033[90m□\033[39m\033[90m□\033[39m\033[90m□\033[39m\033[90m□\033[39m\033[90m□\033[39m\033[90m□\033[39m\033[90m□\033[39m\033[90m□\033[39m\033[90m□\033[39m " --- Code make_progress_bar(0.5) Output [1] "████████████████\033[90m█\033[39m\033[90m█\033[39m\033[90m█\033[39m\033[90m█\033[39m\033[90m█\033[39m\033[90m█\033[39m\033[90m█\033[39m\033[90m█\033[39m\033[90m█\033[39m\033[90m█\033[39m\033[90m█\033[39m\033[90m█\033[39m\033[90m█\033[39m\033[90m█\033[39m\033[90m█\033[39m " # custom style [plain] Code make_progress_bar(0.5) Output [1] "XXXXXXXXXXXXXXX>OOOOOOOOOOOOOOO " # custom style [unicode] Code make_progress_bar(0.5) Output [1] "XXXXXXXXXXXXXXX>OOOOOOOOOOOOOOO " cli/tests/testthat/_snaps/progress-client.md0000644000176200001440000000320314752734130020754 0ustar liggesusers# cli_progress_bar Code capture_cli_messages(fun()) Output [1] "\\ name status 1\n" # removes previous progress bar Code capture_cli_messages(fun()) Output [1] "first\n" "first done\n" "\n" "second\n" [5] "second done\n" "\n" # cli_progress_update can update status Code capture_cli_messages(fun()) Output [1] "\\ name status 1\n" "| name new status 2\n" # cli_progress_update can update extra data Code capture_cli_messages(fun()) Output [1] "Extra: bar\n" "Extra: baz\n" # update set Code capture_cli_messages(fun()) Output [1] "name 1/100\n" "name 50/100\n" # format changes if we (un)learn total Code out Output [1] "\\ name 1 done (100/s) | 3ms\n" [2] "name ===============>--------------- 50% | ETA: 1s\n" [3] "/ name 75 done (100/s) | 3ms\n" # auto-terminate Code capture_cli_messages(fun()) Output [1] "first\n" "first done\n" [3] "\n" "First is done by now.\n" [5] "second\n" "second done\n" [7] "\n" # cli_progress_output Code capture_cli_messages(fun()) Output [1] "\rfirst\033[K\r" "\r\033[K" "just 1 text\n" "first\r" [5] "\rfirst\033[K\r" "\r\033[K" --- Code capture_cli_messages(fun()) Output [1] "\rfirst\r" "\r \r" "just 1 text\n" "first\r" [5] "\rfirst\r" "\r \r" cli/tests/testthat/_snaps/progress-ticking.md0000644000176200001440000000036514752734132021136 0ustar liggesusers# ticking Code out Output [1] "\r1/10\033[K\r" "\r2/10\033[K\r" "\r3/10\033[K\r" "\r4/10\033[K\r" [5] "\r5/10\033[K\r" "\r6/10\033[K\r" "\r7/10\033[K\r" "\r8/10\033[K\r" [9] "\r9/10\033[K\r" "\r\033[K" cli/tests/testthat/_snaps/collapsing.md0000644000176200001440000002503414752735214020001 0ustar liggesusers# collapsing without formatting, n>3 Code pkgs <- paste0("pkg", 1:5) cli_text("Packages: {pkgs}.") Message Packages: pkg1, pkg2, pkg3, pkg4, and pkg5. # collapsing without formatting, n<3 Code pkgs <- paste0("pkg", 1:2) cli_text("Packages: {pkgs}.") Message Packages: pkg1 and pkg2. # collapsing with formatting Code local({ cli_div(theme = list(.pkg = list(fmt = function(x) paste0(x, " (P)")))) pkgs <- paste0("pkg", 1:5) cli_text("Packages: {.pkg {pkgs}}.") }) Message Packages: pkg1 (P), pkg2 (P), pkg3 (P), pkg4 (P), and pkg5 (P). # collapsing with formatting, custom seps Code local({ cli_div(theme = list(div = list(`vec-sep` = " ... "))) pkgs <- paste0("pkg", 1:5) cli_text("Packages: {.pkg {pkgs}}.") }) Message Packages: pkg1 ... pkg2 ... pkg3 ... pkg4, and pkg5. # collapsing a cli_vec Code pkgs <- cli_vec(paste0("pkg", 1:5), style = list(`vec-sep` = " & ", `vec-last` = " & ")) cli_text("Packages: {pkgs}.") Message Packages: pkg1 & pkg2 & pkg3 & pkg4 & pkg5. # collapsing a cli_vec with styling [plain] Code local({ cli_div(theme = list(body = list(`vec-sep` = " ... "))) pkgs <- cli_vec(paste0("pkg", 1:5), style = list(`vec-sep` = " & ", `vec-last` = " & ", color = "blue")) cli_text("Packages: {pkgs}.") }) Message Packages: pkg1 & pkg2 & pkg3 & pkg4 & pkg5. # collapsing a cli_vec with styling [ansi] Code local({ cli_div(theme = list(body = list(`vec-sep` = " ... "))) pkgs <- cli_vec(paste0("pkg", 1:5), style = list(`vec-sep` = " & ", `vec-last` = " & ", color = "blue")) cli_text("Packages: {pkgs}.") }) Message Packages: pkg1 & pkg2 & pkg3 & pkg4 & pkg5. # head Code cli_text("{v(0,1)}") Message Code cli_text("{v(1,1)}") Message 1 Code cli_text("{v(2,1)}") Message 1 and 2 Code cli_text("{v(3,1)}") Message 1, ... Code cli_text("{v(4,1)}") Message 1, ... Code cli_text("{v(0,2)}") Message Code cli_text("{v(1,2)}") Message 1 Code cli_text("{v(2,2)}") Message 1 and 2 Code cli_text("{v(3,2)}") Message 1, 2, ... Code cli_text("{v(4,2)}") Message 1, 2, ... Code cli_text("{v(0,3)}") Message Code cli_text("{v(1,3)}") Message 1 Code cli_text("{v(2,3)}") Message 1 and 2 Code cli_text("{v(3,3)}") Message 1, 2, and 3 Code cli_text("{v(4,3)}") Message 1, 2, 3, ... Code cli_text("{v(0,4)}") Message Code cli_text("{v(1,4)}") Message 1 Code cli_text("{v(2,4)}") Message 1 and 2 Code cli_text("{v(3,4)}") Message 1, 2, and 3 Code cli_text("{v(4,4)}") Message 1, 2, 3, and 4 Code cli_text("{v(0,5)}") Message Code cli_text("{v(1,5)}") Message 1 Code cli_text("{v(2,5)}") Message 1 and 2 Code cli_text("{v(3,5)}") Message 1, 2, and 3 Code cli_text("{v(4,5)}") Message 1, 2, 3, and 4 Code cli_text("{v(10,5)}") Message 1, 2, 3, 4, 5, ... # both-ends Code cli_text("{v(0,1)}") Message Code cli_text("{v(1,1)}") Message 1 Code cli_text("{v(2,1)}") Message 1 and 2 Code cli_text("{v(3,1)}") Message 1, 2, and 3 Code cli_text("{v(4,1)}") Message 1, 2, 3, and 4 Code cli_text("{v(5,1)}") Message 1, 2, 3, 4, and 5 Code cli_text("{v(6,1)}") Message 1, 2, 3, ..., 5, and 6 Code cli_text("{v(7,1)}") Message 1, 2, 3, ..., 6, and 7 Code cli_text("{v(10,1)}") Message 1, 2, 3, ..., 9, and 10 # both-ends with formatting [plain] Code cli_text("{.val {v(0,1)}}") Message Code cli_text("{.val {v(1,1)}}") Message 1 Code cli_text("{.val {v(2,1)}}") Message 1 and 2 Code cli_text("{.val {v(3,1)}}") Message 1, 2, and 3 Code cli_text("{.val {v(4,1)}}") Message 1, 2, 3, and 4 Code cli_text("{.val {v(5,1)}}") Message 1, 2, 3, 4, and 5 Code cli_text("{.val {v(6,1)}}") Message 1, 2, 3, ..., 5, and 6 Code cli_text("{.val {v(7,1)}}") Message 1, 2, 3, ..., 6, and 7 Code cli_text("{.val {v(10,1)}}") Message 1, 2, 3, ..., 9, and 10 Code cli_text("{.val {v(10,6)}}") Message 1, 2, 3, 4, ..., 9, and 10 Code cli_text("{.val {v(10,10)}}") Message 1, 2, 3, 4, 5, 6, 7, 8, 9, and 10 Code cli_text("{.val {v(11,10)}}") Message 1, 2, 3, 4, 5, 6, 7, 8, ..., 10, and 11 # both-ends with formatting [ansi] Code cli_text("{.val {v(0,1)}}") Message Code cli_text("{.val {v(1,1)}}") Message 1 Code cli_text("{.val {v(2,1)}}") Message 1 and 2 Code cli_text("{.val {v(3,1)}}") Message 1, 2, and 3 Code cli_text("{.val {v(4,1)}}") Message 1, 2, 3, and 4 Code cli_text("{.val {v(5,1)}}") Message 1, 2, 3, 4, and 5 Code cli_text("{.val {v(6,1)}}") Message 1, 2, 3, ..., 5, and 6 Code cli_text("{.val {v(7,1)}}") Message 1, 2, 3, ..., 6, and 7 Code cli_text("{.val {v(10,1)}}") Message 1, 2, 3, ..., 9, and 10 Code cli_text("{.val {v(10,6)}}") Message 1, 2, 3, 4, ..., 9, and 10 Code cli_text("{.val {v(10,10)}}") Message 1, 2, 3, 4, 5, 6, 7, 8, 9, and 10 Code cli_text("{.val {v(11,10)}}") Message 1, 2, 3, 4, 5, 6, 7, 8, ..., 10, and 11 # ansi_collapse Code ansi_collapse(l10) Output [1] "a, b, c, d, e, f, g, h, i, and j" Code ansi_collapse(l10, trunc = 6) Output [1] "a, b, c, d, ..., i, and j" Code ansi_collapse(l10, trunc = 5) Output [1] "a, b, c, ..., i, and j" Code ansi_collapse(l10, trunc = 4) Output [1] "a, b, c, ..., i, and j" Code ansi_collapse(l10, trunc = 1) Output [1] "a, b, c, ..., i, and j" Code ansi_collapse(l10, sep = "; ") Output [1] "a; b; c; d; e; f; g; h; i, and j" Code ansi_collapse(l10, sep = "; ", last = "; or ") Output [1] "a; b; c; d; e; f; g; h; i; or j" Code ansi_collapse(l10, sep = "; ") Output [1] "a; b; c; d; e; f; g; h; i, and j" Code ansi_collapse(l10, sep = "; ", last = "; or ", trunc = 6) Output [1] "a; b; c; d; ...; i; or j" Code ansi_collapse(l10, style = "head") Output [1] "a, b, c, d, e, f, g, h, i, and j" Code ansi_collapse(l10, trunc = 6, style = "head") Output [1] "a, b, c, d, e, f, ..." Code ansi_collapse(l10, trunc = 5, style = "head") Output [1] "a, b, c, d, e, ..." Code ansi_collapse(l10, trunc = 4, style = "head") Output [1] "a, b, c, d, ..." Code ansi_collapse(l10, trunc = 1, style = "head") Output [1] "a, ..." Code ansi_collapse(l10, sep = "; ", style = "head") Output [1] "a; b; c; d; e; f; g; h; i, and j" Code ansi_collapse(l10, sep = "; ", last = "; or ", style = "head") Output [1] "a; b; c; d; e; f; g; h; i; or j" Code ansi_collapse(l10, sep = "; ", last = "; or ", trunc = 6, style = "head") Output [1] "a; b; c; d; e; f; ..." # ansi_collapse with width trimming Code ansi_collapse(l10, width = 1, style = "head") Output [1] . Code ansi_collapse(l10, width = 2, style = "head") Output [1] .. Code ansi_collapse(l10, width = 3, style = "head") Output [1] "..." Code ansi_collapse(l10, width = 4, style = "head") Output [1] "a..." Code ansi_collapse(l10, width = 5, style = "head") Output [1] "a..." Code ansi_collapse(l10, width = 6, style = "head") Output [1] "a, ..." Code ansi_collapse(l10, width = 7, style = "head") Output [1] "a, ..." Code ansi_collapse(l10, width = 8, style = "head") Output [1] "a, ..." Code ansi_collapse(l10, width = 9, style = "head") Output [1] "a, b, ..." Code ansi_collapse(l10, width = 30, style = "head") Output [1] "a, b, c, d, e, f, g, h, i, ..." Code ansi_collapse(l10, width = 31, style = "head") Output [1] "a, b, c, d, e, f, g, h, i, ..." Code ansi_collapse(l10, width = 32, style = "head") Output [1] "a, b, c, d, e, f, g, h, i, and j" Code ansi_collapse(l10, width = 40, style = "head") Output [1] "a, b, c, d, e, f, g, h, i, and j" --- Code ansi_collapse(l10, width = 10, style = "both-ends") Condition Warning in `collapse_both_ends()`: ! finite `width` is not implemented in `cli::ansi_collapse()`. i `width = Inf` is used instead. Output [1] "a, b, c, d, e, f, g, h, i, and j" # Issue #681 Code v <- cli::cli_vec(c("foo", "bar", "foobar"), style = list(`vec-last` = ", or ")) cli::cli_text("Must be one of: {v}.") Message Must be one of: foo, bar, or foobar. Code v <- cli::cli_vec(c("foo", "bar"), style = list(`vec-last` = " or ")) cli::cli_text("Must be one of: {v}.") Message Must be one of: foo or bar. Code v <- cli::cli_vec(c("foo", "bar"), style = list(`vec-last` = " or ", `vec-sep2` = " xor ")) cli::cli_text("Must be one of: {v}.") Message Must be one of: foo xor bar. cli/tests/testthat/_snaps/new-r/0000755000176200001440000000000014557444176016357 5ustar liggesuserscli/tests/testthat/_snaps/new-r/inline-2.md0000644000176200001440000000040114752734113020277 0ustar liggesusers# various errors Code cli_text("xx {__cannot-parse-this__} yy") Condition Error: ! Could not parse cli `{}` expression: `__cannot-parse-th...`. Caused by error: ! :1:2: unexpected input 1: __ ^ cli/tests/testthat/_snaps/app.md0000644000176200001440000000044214752734103016416 0ustar liggesusers# stop_app() errors Code stop_app(1:10) Condition Error: ! `app` must be a CLI app i `app` is an integer vector # warning if inactive app Code stop_app(app) Condition Warning in `stop_app()`: No app to end Output NULL cli/tests/testthat/_snaps/inline.md0000644000176200001440000000457014752734113017123 0ustar liggesusers# inline classes [plain] Code invisible(lapply(classes, do)) Message This is <<>> really This is <<>> really This is <<>> really This is <<>> really This is <<>> really This is <<>> really This is <<>> really This is <<>> really This is <<>> really This is <<>> really This is <<>> really This is <<>> really This is <<>> really This is <<>> really # inline classes [ansi] Code invisible(lapply(classes, do)) Message This is <<>> really This is <<>> really This is <<>> really This is <<>> really This is <<>> really This is <<>> really This is <<>> really This is <<>> really This is <<>> really This is <<>> really This is <<>> really This is <<>> really This is <<>> really This is <<>> really # {{ and }} can be used for comments Code local({ cli_text("Escaping {{ works") cli_text("Escaping }} works") cli_text("Escaping {{ and }} works") cli_text("Escaping {{{{ works") cli_text("Escaping }}}} works") cli_text("Escaping {{{{ and }} works") cli_text("Escaping {{{{ and }}}} works") cli_text("Escaping {{ and }}}} works") }) Message Escaping { works Escaping } works Escaping { and } works Escaping {{ works Escaping }} works Escaping {{ and } works Escaping {{ and }} works Escaping { and }} works # no glue substitution in expressions that evaluate to a string Code local({ msg <- "Message with special characters like } { }} {{" cli_text("{msg}") cli_text("{.emph {msg}}") }) Message Message with special characters like } { }} {{ Message with special characters like } { }} {{ # S3 class is used for styling Code local({ cli_div(theme = list(div = list(`class-map` = list(foo = "bar")), .bar = list( before = "::"))) obj <- structure("yep", class = "foo") cli_text("This is {obj}.") }) Message This is ::yep. cli/tests/testthat/_snaps/ansiex-2.md0000644000176200001440000000042214752734101017260 0ustar liggesusers# NA Code ansi_html(s) Output [1] "foo" [2] NA [3] "bar" [4] "foobar" cli/tests/testthat/_snaps/progress-handler-logger.md0000644000176200001440000000016714752734130022376 0ustar liggesusers# loggerr_out Code logger_out(bar, "updated") Output 2021-06-10T13:51:05+00:00 id 13/113 updated cli/tests/testthat/_snaps/rlang-1.1.4/0000755000176200001440000000000014752735214017062 5ustar liggesuserscli/tests/testthat/_snaps/rlang-1.1.4/rlang-errors.md0000644000176200001440000000306314752735214022023 0ustar liggesusers# cli_abort() captures correct call and backtrace Code print(expect_error(f())) Output Error in `h()`: ! foo --- Backtrace: x 1. +-base::print(expect_error(f())) 2. +-testthat::expect_error(f()) 3. | \-testthat:::expect_condition_matching(...) 4. | \-testthat:::quasi_capture(...) 5. | +-testthat (local) .capture(...) 6. | | \-base::withCallingHandlers(...) 7. | \-rlang::eval_bare(quo_get_expr(.quo), quo_get_env(.quo)) 8. \-cli (local) f() 9. \-cli (local) g() 10. \-cli (local) h() --- Code print(expect_error(f(list()))) Output Error in `h()`: ! `x` can't be empty. --- Backtrace: x 1. +-base::print(expect_error(f(list()))) 2. +-testthat::expect_error(f(list())) 3. | \-testthat:::expect_condition_matching(...) 4. | \-testthat:::quasi_capture(...) 5. | +-testthat (local) .capture(...) 6. | | \-base::withCallingHandlers(...) 7. | \-rlang::eval_bare(quo_get_expr(.quo), quo_get_env(.quo)) 8. \-cli (local) f(list()) 9. \-cli (local) g(x) 10. \-cli (local) h(x) # cli_abort(.internal = TRUE) reports the correct function (r-lib/rlang#1386) Code (expect_error(fn())) Output Error in `fn()`: ! Message. i This is an internal error that was detected in the base package. cli/tests/testthat/_snaps/ansi-palette.md0000644000176200001440000001306414752734100020225 0ustar liggesusers# ansi_palette_show Code ansi_palette_show(colors = truecolor) Output bright variants blck red grn yllw blue mgnt cyan whte blck red grn yllw blue mgnt cyan whte #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### --- Code ansi_palette_show(colors = truecolor) Output bright variants blck red grn yllw blue mgnt cyan whte blck red grn yllw blue mgnt cyan whte #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### # error Code withr::with_options(list(cli.palette = "foobar12"), ansi_palette_show(colors = 256)) Condition Error: ! Cannot find cli ANSI palette "foobar12" i Know palettes are "dichro", "vga", "winxp", "vscode", "win10", "macos", "putty", "mirc", "xterm", "ubuntu", "eclipse", "iterm", "iterm-pastel", "iterm-smoooooth", "iterm-snazzy", "iterm-solarized", and "iterm-tango". i Maybe the `cli.palette` option is incorrect? # custom palettes Code col_black("black") Output [1] black Code col_red("red") Output [1] red Code col_green("green") Output [1] green Code col_yellow("yellow") Output [1] yellow Code col_blue("blue") Output [1] blue Code col_magenta("magenta") Output [1] magenta Code col_cyan("cyan") Output [1] cyan Code col_white("white") Output [1] white Code col_br_black("br_black") Output [1] br_black Code col_br_red("br_red") Output [1] br_red Code col_br_green("br_green") Output [1] br_green Code col_br_yellow("br_yellow") Output [1] br_yellow Code col_br_blue("br_blue") Output [1] br_blue Code col_br_magenta("br_magenta") Output [1] br_magenta Code col_br_cyan("br_cyan") Output [1] br_cyan Code col_br_white("br_white") Output [1] br_white cli/tests/testthat/_snaps/ansi.md0000644000176200001440000000074614752734101016575 0ustar liggesusers# print.cli_ansi_style Code print(col_red) Output Example output # print.cli_ansi_string Code print(col_red("red")) Output [1] red # ansi-scale Code ansi_scale(c(0, 0, 0)) Output [1] 0 0 0 Code ansi_scale(c(255, 100, 0)) Output [1] 5 2 0 Code ansi_scale(c(255, 100, 0), round = FALSE) Output [1] 5.000000 1.960784 0.000000 cli/tests/testthat/_snaps/utf8.md0000644000176200001440000000014114752734137016527 0ustar liggesusers# errors ! Invalid output from UTF-8 R i Found 1 UTF-8 begin marker and 2 end markers. cli/tests/testthat/_snaps/progress-c.md0000644000176200001440000000747414752734130017736 0ustar liggesusers# c api #1 Code out Output [1] "\r ===>--------------------------- 10% | ETA: 1s\033[K\r" [2] "\r ======>------------------------ 20% | ETA: 1s\033[K\r" [3] "\r =========>--------------------- 30% | ETA: 1s\033[K\r" [4] "\r ============>------------------ 40% | ETA: 1s\033[K\r" [5] "\r ===============>--------------- 50% | ETA: 1s\033[K\r" [6] "\r ==================>------------ 60% | ETA: 1s\033[K\r" [7] "\r =====================>--------- 70% | ETA: 1s\033[K\r" [8] "\r ========================>------ 80% | ETA: 1s\033[K\r" [9] "\r ===========================>--- 90% | ETA: 1s\033[K\r" [10] "\r\033[K" --- Code out Output [1] "\r1/10\033[K\r" "\r2/10\033[K\r" "\r3/10\033[K\r" "\r4/10\033[K\r" [5] "\r5/10\033[K\r" "\r6/10\033[K\r" "\r7/10\033[K\r" "\r8/10\033[K\r" [9] "\r9/10\033[K\r" "\r\033[K" --- Code out Output [1] "\rme llama 1\033[K\r" "\rme llama 2\033[K\r" "\rme llama 3\033[K\r" [4] "\rme llama 4\033[K\r" "\rme llama 5\033[K\r" "\rme llama 6\033[K\r" [7] "\rme llama 7\033[K\r" "\rme llama 8\033[K\r" "\rme llama 9\033[K\r" [10] "\r\033[K" --- Code out Output [1] "\rnew name stats 1\033[K\r" "\rnew name stats 2\033[K\r" [3] "\rnew name stats 3\033[K\r" "\rnew name stats 4\033[K\r" [5] "\rnew name stats 5\033[K\r" "\rnew name stats 6\033[K\r" [7] "\rnew name stats 7\033[K\r" "\rnew name stats 8\033[K\r" [9] "\rnew name stats 9\033[K\r" "\rnew name stats 10\033[K\r" [11] "\n" --- Code out Output [1] "\r 1\033[K\r" "\r 2\033[K\r" "\r 3\033[K\r" "\r 4\033[K\r" "\r 5\033[K\r" [6] "\r 6\033[K\r" "\r 7\033[K\r" "\r 8\033[K\r" "\r 9\033[K\r" "\r\033[K" --- Code out Output [1] "\r 1\033[K\r" "\r 2\033[K\r" "\r 3\033[K\r" "\r 4\033[K\r" "\r 5\033[K\r" [6] "\r 6\033[K\r" "\r 7\033[K\r" "\r 8\033[K\r" "\r 9\033[K\r" "\r\033[K" --- Code out Output [1] "\r 1\033[K\r" "\r 2\033[K\r" "\r 3\033[K\r" "\r 4\033[K\r" "\r 5\033[K\r" [6] "\r 6\033[K\r" "\r 7\033[K\r" "\r 8\033[K\r" "\r 9\033[K\r" "\r\033[K" --- Code out Output [1] "\r 1\033[K\r" "\r 2\033[K\r" "\r 3\033[K\r" "\r 4\033[K\r" "\r 5\033[K\r" [6] "\r 6\033[K\r" "\r 7\033[K\r" "\r 8\033[K\r" "\r 9\033[K\r" "\r\033[K" --- Code out Output [1] "2021-06-18T00:09:14+00:00 cli-36434-1 1/10 added" [2] "2021-06-18T00:09:14+00:00 cli-36434-1 1/10 updated" [3] "2021-06-18T00:09:14+00:00 cli-36434-1 2/10 updated" [4] "2021-06-18T00:09:14+00:00 cli-36434-1 3/10 updated" [5] "2021-06-18T00:09:14+00:00 cli-36434-1 4/10 updated" [6] "2021-06-18T00:09:14+00:00 cli-36434-1 5/10 updated" [7] "2021-06-18T00:09:14+00:00 cli-36434-1 6/10 updated" [8] "2021-06-18T00:09:14+00:00 cli-36434-1 7/10 updated" [9] "2021-06-18T00:09:14+00:00 cli-36434-1 8/10 updated" [10] "2021-06-18T00:09:14+00:00 cli-36434-1 9/10 updated" [11] "2021-06-18T00:09:14+00:00 cli-36434-1 10/10 terminated (done)" --- Code out Output [1] "\r1/10\033[K\r" "\r2/10\033[K\r" [3] "\r3/10\033[K\r" "\r4/10\033[K\r" [5] "\r5/10\033[K\r" "\r6/10\033[K\r" [7] "\r7/10\033[K\r" "\r8/10\033[K\r" [9] "\r9/10\033[K\r" "\rJust did 10 steps.\033[K\r" [11] "\n" cli/tests/testthat/_snaps/utf8/0000755000176200001440000000000014753300402016172 5ustar liggesuserscli/tests/testthat/_snaps/utf8/utf8-output.txt0000644000176200001440000000644414557444176021212 0ustar liggesusers ── Alerts ──────────────────────────────────────────────────────────── → マルチバイトのタイトル ✖ árvíztűrő tükörfúrógép ℹ マルチバイトのタイトル ✔ マルチバイトのタイトル ! マルチバイトのタイトル ── Block quote ─────────────────────────────────────────────────────── “マルチバイトのタイトル” — árvíztűrő tükörfúrógép ── Bullets ─────────────────────────────────────────────────────────── • マルチバイトのタイトル ! árvíztűrő tükörfúrógép ── Code ────────────────────────────────────────────────────────────── マルチバイトのタイトル árvíztűrő tükörfúrógép ── Lists ───────────────────────────────────────────────────────────── s1: マルチバイトのタイトル s2: árvíztűrő tükörfúrógép 1. マルチバイトのタイトル 2. árvíztűrő tükörfúrógép • マルチバイトのタイトル • árvíztűrő tükörfúrógép ── Headers ─────────────────────────────────────────────────────────── ── マルチバイトのタイトル ──────────────────────────────────────────── ── árvíztűrő tükörfúrógép ── ── マルチバイトのタイトル ── Progress bars ───────────────────────────────────────────────────── ℹ マルチバイトのタイトル ✔ マルチバイトのタイトル [1s] ℹ árvíztűrő tükörfúrógép ✔ árvíztűrő tükörfúrógép [1s] ── Text ────────────────────────────────────────────────────────────── マルチバイトのタイトル árvíztűrő tükörfúrógép マルチバイトのタイトル árvíztűrő tükörfúrógép マルチバイトのタイトル マルチバイトのタイトル マルチバイトのタイトル マルチバイトのタイトル árvíztűrő tükörfúrógép マルチバイトのタイトル árvíztűrő tükörfúrógép マルチバイトのタイトル マルチバイトのタイトル マルチバイトのタイトル マルチバイトのタイトル ── Verbatim ────────────────────────────────────────────────────────── マルチバイトのタイトル árvíztűrő tükörfúrógép cli/tests/testthat/_snaps/rlang-errors.md0000644000176200001440000002426214752734134020265 0ustar liggesusers# cli_abort [plain] Code local({ n <- "boo" cli_abort(c("{.var n} must be a numeric vector", x = "You've supplied a {.cls {class(n)}} vector.")) }) Condition Error: ! `n` must be a numeric vector x You've supplied a vector. --- Code local({ len <- 26 idx <- 100 cli_abort(c("Must index an existing element:", i = "There {?is/are} {len} element{?s}.", x = "You've tried to subset element {idx}.")) }) Condition Error: ! Must index an existing element: i There are 26 elements. x You've tried to subset element 100. --- Code c(err$message, err$body) Output x "`n` must be a numeric vector" "You've supplied a vector." # cli_abort [ansi] Code local({ n <- "boo" cli_abort(c("{.var n} must be a numeric vector", x = "You've supplied a {.cls {class(n)}} vector.")) }) Condition Error: ! `n` must be a numeric vector x You've supplied a  vector. --- Code local({ len <- 26 idx <- 100 cli_abort(c("Must index an existing element:", i = "There {?is/are} {len} element{?s}.", x = "You've tried to subset element {idx}.")) }) Condition Error: ! Must index an existing element: i There are 26 elements. x You've tried to subset element 100. --- Code c(err$message, err$body) Output "`n` must be a numeric vector" x "You've supplied a \033[34m\033[39m vector." # cli_abort [unicode] Code local({ n <- "boo" cli_abort(c("{.var n} must be a numeric vector", x = "You've supplied a {.cls {class(n)}} vector.")) }) Condition Error: ! `n` must be a numeric vector ✖ You've supplied a vector. --- Code local({ len <- 26 idx <- 100 cli_abort(c("Must index an existing element:", i = "There {?is/are} {len} element{?s}.", x = "You've tried to subset element {idx}.")) }) Condition Error: ! Must index an existing element: ℹ There are 26 elements. ✖ You've tried to subset element 100. --- Code c(err$message, err$body) Output x "`n` must be a numeric vector" "You've supplied a vector." # cli_abort [fancy] Code local({ n <- "boo" cli_abort(c("{.var n} must be a numeric vector", x = "You've supplied a {.cls {class(n)}} vector.")) }) Condition Error: ! `n` must be a numeric vector ✖ You've supplied a  vector. --- Code local({ len <- 26 idx <- 100 cli_abort(c("Must index an existing element:", i = "There {?is/are} {len} element{?s}.", x = "You've tried to subset element {idx}.")) }) Condition Error: ! Must index an existing element: ℹ There are 26 elements. ✖ You've tried to subset element 100. --- Code c(err$message, err$body) Output "`n` must be a numeric vector" x "You've supplied a \033[34m\033[39m vector." # cli_warn [plain] Code n <- "boo" cli_warn(c("{.var n} must be a numeric vector", x = "You've supplied a {.cls {class(n)}} vector.")) Condition Warning: `n` must be a numeric vector x You've supplied a vector. --- Code local({ len <- 26 idx <- 100 cli_warn(c("Must index an existing element:", i = "There {?is/are} {len} element{?s}.", x = "You've tried to subset element {idx}.")) }) Condition Warning: Must index an existing element: i There are 26 elements. x You've tried to subset element 100. # cli_warn [ansi] Code n <- "boo" cli_warn(c("{.var n} must be a numeric vector", x = "You've supplied a {.cls {class(n)}} vector.")) Condition Warning: `n` must be a numeric vector x You've supplied a  vector. --- Code local({ len <- 26 idx <- 100 cli_warn(c("Must index an existing element:", i = "There {?is/are} {len} element{?s}.", x = "You've tried to subset element {idx}.")) }) Condition Warning: Must index an existing element: i There are 26 elements. x You've tried to subset element 100. # cli_warn [unicode] Code n <- "boo" cli_warn(c("{.var n} must be a numeric vector", x = "You've supplied a {.cls {class(n)}} vector.")) Condition Warning: `n` must be a numeric vector ✖ You've supplied a vector. --- Code local({ len <- 26 idx <- 100 cli_warn(c("Must index an existing element:", i = "There {?is/are} {len} element{?s}.", x = "You've tried to subset element {idx}.")) }) Condition Warning: Must index an existing element: ℹ There are 26 elements. ✖ You've tried to subset element 100. # cli_warn [fancy] Code n <- "boo" cli_warn(c("{.var n} must be a numeric vector", x = "You've supplied a {.cls {class(n)}} vector.")) Condition Warning: `n` must be a numeric vector ✖ You've supplied a  vector. --- Code local({ len <- 26 idx <- 100 cli_warn(c("Must index an existing element:", i = "There {?is/are} {len} element{?s}.", x = "You've tried to subset element {idx}.")) }) Condition Warning: Must index an existing element: ℹ There are 26 elements. ✖ You've tried to subset element 100. # cli_inform [plain] Code n <- "boo" cli_inform(c("{.var n} must be a numeric vector", x = "You've supplied a {.cls {class(n)}} vector.")) Message `n` must be a numeric vector x You've supplied a vector. --- Code local({ len <- 26 idx <- 100 cli_inform(c("Must index an existing element:", i = "There {?is/are} {len} element{?s}.", x = "You've tried to subset element {idx}.")) }) Message Must index an existing element: i There are 26 elements. x You've tried to subset element 100. # cli_inform [ansi] Code n <- "boo" cli_inform(c("{.var n} must be a numeric vector", x = "You've supplied a {.cls {class(n)}} vector.")) Message `n` must be a numeric vector x You've supplied a  vector. --- Code local({ len <- 26 idx <- 100 cli_inform(c("Must index an existing element:", i = "There {?is/are} {len} element{?s}.", x = "You've tried to subset element {idx}.")) }) Message Must index an existing element: i There are 26 elements. x You've tried to subset element 100. # cli_inform [unicode] Code n <- "boo" cli_inform(c("{.var n} must be a numeric vector", x = "You've supplied a {.cls {class(n)}} vector.")) Message `n` must be a numeric vector ✖ You've supplied a vector. --- Code local({ len <- 26 idx <- 100 cli_inform(c("Must index an existing element:", i = "There {?is/are} {len} element{?s}.", x = "You've tried to subset element {idx}.")) }) Message Must index an existing element: ℹ There are 26 elements. ✖ You've tried to subset element 100. # cli_inform [fancy] Code n <- "boo" cli_inform(c("{.var n} must be a numeric vector", x = "You've supplied a {.cls {class(n)}} vector.")) Message `n` must be a numeric vector ✖ You've supplied a  vector. --- Code local({ len <- 26 idx <- 100 cli_inform(c("Must index an existing element:", i = "There {?is/are} {len} element{?s}.", x = "You've tried to subset element {idx}.")) }) Message Must index an existing element: ℹ There are 26 elements. ✖ You've tried to subset element 100. # cli_abort width in RStudio Code local({ len <- 26 idx <- 100 cli_abort(c(lorem_ipsum(1, 3), i = lorem_ipsum(1, 3), x = lorem_ipsum(1, 3))) }) Condition Error: ! Duis quis magna incididunt nulla commodo minim non exercitation nostrud ullamco dolor exercitation ut veniam. Fugiat irure tempor commodo voluptate ut. In et tempor excepteur quis. i Et nisi ad quis ad cupidatat tempor laborum est excepteur aliqua veniam ex. Sunt magna veniam Lorem elit enim et pariatur aliqua occaecat mollit consequat dolore in mollit. Officia labore reprehenderit culpa dolore quis nisi do aliqua commodo deserunt fugiat cupidatat nostrud ad. x Ad laboris consectetur esse minim pariatur irure do anim anim. Mollit ad cupidatat ullamco ullamco nulla elit in. # color in RStudio [ansi] Code col <- get_rstudio_fg_color0() cat(col("this is the new color")) Output this is the new color # update_rstudio_color [ansi] Code cat(update_rstudio_color("color me interested")) Output color me interested cli/tests/testthat/_snaps/prettycode.md0000644000176200001440000001452114752734125020027 0ustar liggesusers# reserved [plain] Code cat(code_highlight("function () { }", list(reserved = "bold"))) Output function () { } Code cat(code_highlight("if (1) NULL else NULL", list(reserved = "bold"))) Output if (1) NULL else NULL Code cat(code_highlight("repeat {}", list(reserved = "bold"))) Output repeat {} Code cat(code_highlight("while (1) {}", list(reserved = "bold"))) Output while (1) {} Code cat(code_highlight("for (i in x) next", list(reserved = "bold"))) Output for (i in x) next Code cat(code_highlight("for (i in x) break", list(reserved = "bold"))) Output for (i in x) break # reserved [ansi] Code cat(code_highlight("function () { }", list(reserved = "bold"))) Output function () { } Code cat(code_highlight("if (1) NULL else NULL", list(reserved = "bold"))) Output if (1) NULL else NULL Code cat(code_highlight("repeat {}", list(reserved = "bold"))) Output repeat {} Code cat(code_highlight("while (1) {}", list(reserved = "bold"))) Output while (1) {} Code cat(code_highlight("for (i in x) next", list(reserved = "bold"))) Output for (i in x) next Code cat(code_highlight("for (i in x) break", list(reserved = "bold"))) Output for (i in x) break # number [plain] Code cat(code_highlight("1 + 1.0 + -1 + 2L + Inf", list(number = "bold"))) Output 1 + 1.0 + -1 + 2L + Inf Code cat(code_highlight("NA + NA_real_ + NA_integer_ + NA_character_", list(number = "bold"))) Output NA + NA_real_ + NA_integer_ + NA_character_ Code cat(code_highlight("TRUE + FALSE", list(number = "bold"))) Output TRUE + FALSE # number [ansi] Code cat(code_highlight("1 + 1.0 + -1 + 2L + Inf", list(number = "bold"))) Output 1 + 1.0 + -1 + 2L + Inf Code cat(code_highlight("NA + NA_real_ + NA_integer_ + NA_character_", list(number = "bold"))) Output NA + NA_real_ + NA_integer_ + NA_character_ Code cat(code_highlight("TRUE + FALSE", list(number = "bold"))) Output TRUE + FALSE # null [plain] Code cat(code_highlight("NULL", list(null = "bold"))) Output NULL # null [ansi] Code cat(code_highlight("NULL", list(null = "bold"))) Output NULL # operator [plain] Code cat(code_highlight("~ ! 1 - 2 + 3:4 * 5 / 6 ^ 7", list(operator = "bold"))) Output ~ ! 1 - 2 + 3:4 * 5 / 6 ^ 7 Code cat(code_highlight("? 1 %% 2 %+% 2 < 3 & 4 > 5 && 6 == 7 | 8 <= 9 || 10 >= 11", list(operator = "bold"))) Output ? 1 %% 2 %+% 2 < 3 & 4 > 5 && 6 == 7 | 8 <= 9 || 10 >= 11 Code cat(code_highlight("a <- 10; 20 -> b; c = 30; a$b; a@b", list(operator = "bold"))) Output a <- 10; 20 -> b; c = 30; a$b; a@b # operator [ansi] Code cat(code_highlight("~ ! 1 - 2 + 3:4 * 5 / 6 ^ 7", list(operator = "bold"))) Output ~ ! 1 - 2 + 3:4 * 5 / 6 ^ 7 Code cat(code_highlight("? 1 %% 2 %+% 2 < 3 & 4 > 5 && 6 == 7 | 8 <= 9 || 10 >= 11", list(operator = "bold"))) Output ? 1 %% 2 %+% 2 < 3 & 4 > 5 && 6 == 7 | 8 <= 9 || 10 >= 11 Code cat(code_highlight("a <- 10; 20 -> b; c = 30; a$b; a@b", list(operator = "bold"))) Output a <- 10; 20 -> b; c = 30; a$b; a@b # call [plain] Code cat(code_highlight("ls(2)", list(call = "bold"))) Output ls(2) # call [ansi] Code cat(code_highlight("ls(2)", list(call = "bold"))) Output ls(2) # string [plain] Code cat(code_highlight("'s' + \"s\"", list(string = "bold"))) Output 's' + "s" # string [ansi] Code cat(code_highlight("'s' + \"s\"", list(string = "bold"))) Output 's' + "s" # comment [plain] Code cat(code_highlight(c("# COM", " ls() ## ANOT"), list(comment = "bold"))) Output # COM ls() ## ANOT # comment [ansi] Code cat(code_highlight(c("# COM", " ls() ## ANOT"), list(comment = "bold"))) Output # COM ls() ## ANOT # bracket [plain] Code cat(code_highlight("foo <- function(x){x}", list(bracket = list("bold")))) Output foo <- function(x){x} # bracket [ansi] Code cat(code_highlight("foo <- function(x){x}", list(bracket = list("bold")))) Output foo <- function(x){x} # code_theme_list Code code_theme_list() Output [1] "Ambiance" "Chaos" "Chrome" [4] "Clouds" "Clouds Midnight" "Cobalt" [7] "Crimson Editor" "Dawn" "Dracula" [10] "Dreamweaver" "Eclipse" "Idle Fingers" [13] "Katzenmilch" "Kr Theme" "Material" [16] "Merbivore" "Merbivore Soft" "Mono Industrial" [19] "Monokai" "Pastel On Dark" "Solarized Dark" [22] "Solarized Light" "Textmate (default)" "Tomorrow" [25] "Tomorrow Night" "Tomorrow Night Blue" "Tomorrow Night Bright" [28] "Tomorrow Night 80s" "Twilight" "Vibrant Ink" [31] "Xcode" # new language features, raw strings [ansi] Code cat(code_highlight("\"old\" + r\"(\"new\"\"\")\"", list(string = "bold", reserved = "italic"))) Output "old" + r"("new""")" # new language features, pipe [ansi] Code cat(code_highlight("dir() |> toupper()", list(operator = "bold"))) Output dir() |> toupper() # new language features, lambda functions [ansi] Code cat(code_highlight("\\(x) x * 2", list(reserved = "bold"))) Output \(x) x * 2 cli/tests/testthat/_snaps/verbatim.md0000644000176200001440000000063614752734140017455 0ustar liggesusers# verbatim text is correctly styled Code local({ theme <- list(.padded = list(`margin-left` = 4)) cli_div(class = "padded", theme = theme) lines <- c("first", "second", "third") cli_verbatim(lines) cli_verbatim(paste0(lines, collapse = "\n")) }) Message first second third first second third cli/tests/testthat/_snaps/tree.md0000644000176200001440000001301214752734137016601 0ustar liggesusers# tree [plain] Code tree(data) Output processx +-assertthat +-crayon +-debugme | \-crayon \-R6 --- Code tree(data, root = "desc") Output desc +-assertthat +-R6 +-crayon \-rprojroot \-backports # tree [ansi] Code tree(data) Output processx +-assertthat +-crayon +-debugme | \-crayon \-R6 --- Code tree(data, root = "desc") Output desc +-assertthat +-R6 +-crayon \-rprojroot \-backports # tree [unicode] Code tree(data) Output processx ├─assertthat ├─crayon ├─debugme │ └─crayon └─R6 --- Code tree(data, root = "desc") Output desc ├─assertthat ├─R6 ├─crayon └─rprojroot └─backports # tree [fancy] Code tree(data) Output processx ├─assertthat ├─crayon ├─debugme │ └─crayon └─R6 --- Code tree(data, root = "desc") Output desc ├─assertthat ├─R6 ├─crayon └─rprojroot └─backports # trimming [plain] Code tree(pkgs, trim = TRUE) Output dplyr@0.8.3 +-assertthat@0.2.1 +-glue@1.3.1 +-magrittr@1.5 +-R6@2.4.0 +-Rcpp@1.0.2 +-rlang@0.4.0 +-tibble@2.1.3 | +-cli@1.1.0 | | +-assertthat@0.2.1 (trimmed) | | \-crayon@1.3.4 | +-crayon@1.3.4 (trimmed) | +-fansi@0.4.0 | +-pillar@1.4.2 | | +-cli@1.1.0 (trimmed) | | +-crayon@1.3.4 (trimmed) | | +-fansi@0.4.0 (trimmed) | | +-rlang@0.4.0 (trimmed) | | +-utf8@1.1.4 | | \-vctrs@0.2.0 | | +-backports@1.1.5 | | +-ellipsis@0.3.0 | | | \-rlang@0.4.0 (trimmed) | | +-digest@0.6.21 | | +-glue@1.3.1 (trimmed) | | +-rlang@0.4.0 (trimmed) | | \-zeallot@0.1.0 | +-pkgconfig@2.0.3 | \-rlang@0.4.0 (trimmed) \-tidyselect@0.2.5 +-glue@1.3.1 (trimmed) +-rlang@0.4.0 (trimmed) \-Rcpp@1.0.2 (trimmed) # trimming [ansi] Code tree(pkgs, trim = TRUE) Output dplyr@0.8.3 +-assertthat@0.2.1 +-glue@1.3.1 +-magrittr@1.5 +-R6@2.4.0 +-Rcpp@1.0.2 +-rlang@0.4.0 +-tibble@2.1.3 | +-cli@1.1.0 | | +-assertthat@0.2.1 (trimmed) | | \-crayon@1.3.4 | +-crayon@1.3.4 (trimmed) | +-fansi@0.4.0 | +-pillar@1.4.2 | | +-cli@1.1.0 (trimmed) | | +-crayon@1.3.4 (trimmed) | | +-fansi@0.4.0 (trimmed) | | +-rlang@0.4.0 (trimmed) | | +-utf8@1.1.4 | | \-vctrs@0.2.0 | | +-backports@1.1.5 | | +-ellipsis@0.3.0 | | | \-rlang@0.4.0 (trimmed) | | +-digest@0.6.21 | | +-glue@1.3.1 (trimmed) | | +-rlang@0.4.0 (trimmed) | | \-zeallot@0.1.0 | +-pkgconfig@2.0.3 | \-rlang@0.4.0 (trimmed) \-tidyselect@0.2.5 +-glue@1.3.1 (trimmed) +-rlang@0.4.0 (trimmed) \-Rcpp@1.0.2 (trimmed) # trimming [unicode] Code tree(pkgs, trim = TRUE) Output dplyr@0.8.3 ├─assertthat@0.2.1 ├─glue@1.3.1 ├─magrittr@1.5 ├─R6@2.4.0 ├─Rcpp@1.0.2 ├─rlang@0.4.0 ├─tibble@2.1.3 │ ├─cli@1.1.0 │ │ ├─assertthat@0.2.1 (trimmed) │ │ └─crayon@1.3.4 │ ├─crayon@1.3.4 (trimmed) │ ├─fansi@0.4.0 │ ├─pillar@1.4.2 │ │ ├─cli@1.1.0 (trimmed) │ │ ├─crayon@1.3.4 (trimmed) │ │ ├─fansi@0.4.0 (trimmed) │ │ ├─rlang@0.4.0 (trimmed) │ │ ├─utf8@1.1.4 │ │ └─vctrs@0.2.0 │ │ ├─backports@1.1.5 │ │ ├─ellipsis@0.3.0 │ │ │ └─rlang@0.4.0 (trimmed) │ │ ├─digest@0.6.21 │ │ ├─glue@1.3.1 (trimmed) │ │ ├─rlang@0.4.0 (trimmed) │ │ └─zeallot@0.1.0 │ ├─pkgconfig@2.0.3 │ └─rlang@0.4.0 (trimmed) └─tidyselect@0.2.5 ├─glue@1.3.1 (trimmed) ├─rlang@0.4.0 (trimmed) └─Rcpp@1.0.2 (trimmed) # trimming [fancy] Code tree(pkgs, trim = TRUE) Output dplyr@0.8.3 ├─assertthat@0.2.1 ├─glue@1.3.1 ├─magrittr@1.5 ├─R6@2.4.0 ├─Rcpp@1.0.2 ├─rlang@0.4.0 ├─tibble@2.1.3 │ ├─cli@1.1.0 │ │ ├─assertthat@0.2.1 (trimmed) │ │ └─crayon@1.3.4 │ ├─crayon@1.3.4 (trimmed) │ ├─fansi@0.4.0 │ ├─pillar@1.4.2 │ │ ├─cli@1.1.0 (trimmed) │ │ ├─crayon@1.3.4 (trimmed) │ │ ├─fansi@0.4.0 (trimmed) │ │ ├─rlang@0.4.0 (trimmed) │ │ ├─utf8@1.1.4 │ │ └─vctrs@0.2.0 │ │ ├─backports@1.1.5 │ │ ├─ellipsis@0.3.0 │ │ │ └─rlang@0.4.0 (trimmed) │ │ ├─digest@0.6.21 │ │ ├─glue@1.3.1 (trimmed) │ │ ├─rlang@0.4.0 (trimmed) │ │ └─zeallot@0.1.0 │ ├─pkgconfig@2.0.3 │ └─rlang@0.4.0 (trimmed) └─tidyselect@0.2.5 ├─glue@1.3.1 (trimmed) ├─rlang@0.4.0 (trimmed) └─Rcpp@1.0.2 (trimmed) cli/tests/testthat/_snaps/hash.md0000644000176200001440000001156614752735214016576 0ustar liggesusers# hash_emoji Code hash_emoji(character())$names Output list() Code hash_emoji("")$names Output [[1]] [1] "teacup without handle" "rhinoceros" "flushed face" Code hash_emoji("x")$names Output [[1]] [1] "mage: dark skin tone" "spoon" "fuel pump" Code hash_emoji(NA_character_)$names Output [[1]] [1] NA NA NA Code hash_emoji(NA)$names Output [[1]] [1] NA NA NA Code hash_emoji(c(NA, "", "foo", NA))$names Output [[1]] [1] NA NA NA [[2]] [1] "teacup without handle" "rhinoceros" "flushed face" [[3]] [1] "sun behind cloud" "raised back of hand: dark skin tone" [3] "children crossing" [[4]] [1] NA NA NA # hash_raw_emoji Code hash_raw_emoji(raw())$names Output [1] "teacup without handle" "rhinoceros" "flushed face" Code hash_raw_emoji(as.raw(0))$names Output [1] "diamond with a dot" "raised fist" "face with thermometer" Code hash_raw_emoji(charToRaw("foobar"))$names Output [1] "fishing pole" "money with wings" "eagle" # hash_obj_emoji Code hash_obj_emoji("")$names Output [1] "woman pilot: medium skin tone" "cat with wry smile" [3] "couple with heart" Code hash_obj_emoji(raw(0))$names Output [1] "fire" "man teacher: medium-light skin tone" [3] "carp streamer" Code hash_obj_emoji(1:10)$names Output [1] "backhand index pointing right: medium-light skin tone" [2] "woman office worker: medium skin tone" [3] "tiger face" Code hash_obj_emoji(mtcars)$names Output [1] "woman judge: medium skin tone" "pause button" [3] "flag: North Korea" # hash_animal Code hash_animal(character())$words Output list() Code hash_animal("")$words Output [[1]] [1] "dogtired" "conventional" "olingo" Code hash_animal("x")$words Output [[1]] [1] "goodhearted" "lovelorn" "amphiuma" Code hash_animal(NA_character_)$words Output [[1]] [1] NA NA NA Code hash_animal(NA)$words Output [[1]] [1] NA NA NA Code hash_animal(c(NA, "", "foo", NA))$words Output [[1]] [1] NA NA NA [[2]] [1] "dogtired" "conventional" "olingo" [[3]] [1] "sacrilegious" "diet" "lion" [[4]] [1] NA NA NA # hash_raw_animal Code hash_raw_animal(raw())$words Output [1] "dogtired" "conventional" "olingo" Code hash_raw_animal(as.raw(0))$words Output [1] "scarabaeiform" "surly" "goldfish" Code hash_raw_animal(charToRaw("foobar"))$words Output [1] "unevolving" "degrading" "harrier" # hash_obj_animal Code hash_obj_animal("")$words Output [1] "pathworky" "wondrous" "minibeast" Code hash_obj_animal(raw(0))$words Output [1] "undestructive" "unequal" "indianglassfish" Code hash_obj_animal(1:10)$words Output [1] "benignant" "profound" "ambushbug" Code hash_obj_animal(mtcars)$words Output [1] "novice" "flushed" "australianshelduck" # hash_xxhash Code hash_xxhash(letters[1:5]) Output [1] "a96faf705af16834e6c632b61e964e1f" "4b2212e31ac97fd4575a0b1c44d8843f" [3] "12d8bdd17f74de858c40219a46b9f81b" "56a841f9102d5ff745f80274c9c7a7ca" [5] "2d97a8f9e2edaaefe5e72e5e3bec4a78" Code hash_xxhash(c("a", NA, "b")) Output [1] "a96faf705af16834e6c632b61e964e1f" NA [3] "4b2212e31ac97fd4575a0b1c44d8843f" Code hash_xxhash64(letters[1:5]) Output [1] "e6c632b61e964e1f" "575a0b1c44d8843f" "8c40219a46b9f81b" "45f80274c9c7a7ca" [5] "e5e72e5e3bec4a78" Code hash_raw_xxhash(charToRaw("a")) Output [1] "a96faf705af16834e6c632b61e964e1f" Code hash_raw_xxhash64(charToRaw("a")) Output [1] "e6c632b61e964e1f" Code hash_obj_xxhash(raw(0)) Output [1] "64f55f347c3e13113cde6a6f033766e3" Code hash_obj_xxhash64(raw(0)) Output [1] "0c9b74982308d8fd" --- Code hash_file_xxhash(tmp) Output [1] "a96faf705af16834e6c632b61e964e1f" Code hash_file_xxhash64(tmp) Output [1] "e6c632b61e964e1f" cli/tests/testthat/_snaps/code.md0000644000176200001440000000057114752734106016556 0ustar liggesusers# issue #154 [plain] Code cli_code("a\nb\nc") Message a b c # issue #154 [ansi] Code cli_code("a\nb\nc") Message a b c # issue #154 [unicode] Code cli_code("a\nb\nc") Message a b c # issue #154 [fancy] Code cli_code("a\nb\nc") Message a b c cli/tests/testthat/_snaps/utils.md0000644000176200001440000000630514752734140017003 0ustar liggesusers# ruler Code ruler(20) Output ----+----1----+----2 12345678901234567890 # na.omit Code na.omit(character()) Output character(0) Code na.omit(integer()) Output integer(0) Code na.omit(1:5) Output [1] 1 2 3 4 5 Code na.omit(c(1, NA, 2, NA)) Output [1] 1 2 Code na.omit(c(NA_integer_, NA_integer_)) Output integer(0) Code na.omit(list(1, 2, 3)) Output [[1]] [1] 1 [[2]] [1] 2 [[3]] [1] 3 # str_trim Code str_trim("foo") Output [1] "foo" Code str_trim(character()) Output character(0) Code str_trim(" foo") Output [1] "foo" Code str_trim("foo ") Output [1] "foo" Code str_trim(" foo ") Output [1] "foo" Code str_trim(c(NA_character_, " foo ", NA_character_, " bar ")) Output [1] NA "foo" NA "bar" # leading_space Code paste0("-", leading_space("foo"), "-") Output [1] "--" Code paste0("-", leading_space(" foo"), "-") Output [1] "- -" Code paste0("-", leading_space(" foo "), "-") Output [1] "- -" Code paste0("-", leading_space(" \t foo "), "-") Output [1] "- \t -" Code paste0("-", leading_space(" foo "), "-") Output [1] "- -" Code paste0("-", leading_space("   foo "), "-") Output [1] "-   -" # trailing_space Code paste0("-", trailing_space("foo"), "-") Output [1] "--" Code paste0("-", trailing_space("foo "), "-") Output [1] "- -" Code paste0("-", trailing_space(" foo "), "-") Output [1] "- -" Code paste0("-", trailing_space(" foo \t "), "-") Output [1] "- \t -" Code paste0("-", trailing_space(" foo "), "-") Output [1] "- -" Code paste0("-", trailing_space("   foo   "), "-") Output [1] "-   -" # abbrev Code abbrev("123456789012345") Output [1] 1234567... Code abbrev("12345678901") Output [1] 1234567... Code abbrev("1234567890") Output [1] 1234567890 Code abbrev("123456789") Output [1] 123456789 Code abbrev("12345") Output [1] 12345 Code abbrev("1") Output [1] 1 Code abbrev("") Output [1] Code abbrev("\033[31m1234567890\033[39m") Output [1] 1234567890 Code abbrev(c("\033[31m1234567890\033[39m", "", "1234567890123"), 5) Output [1] 12... [2] [3] 12... Code abbrev(rep("\033[31m1234567890\033[39m", 5), 5) Output [1] 12... [2] 12... [3] 12... [4] 12... [5] 12... cli/tests/testthat/_snaps/cat-helpers.md0000644000176200001440000000443214752734105020052 0ustar liggesusers# cat_line Code cat_line("This is ", "a ", "line of text.") Output This is a line of text. --- Code cat_line("This is ", "a ", "line of text.", col = "red") Output This is a line of text. Code cat_line("This is ", "a ", "line of text.", background_col = "green") Output This is a line of text. # cat_bullet [plain] Code cat_bullet(letters[1:5]) Output * a * b * c * d * e # cat_bullet [unicode] Code cat_bullet(letters[1:5]) Output • a • b • c • d • e # cat_boxx [plain] Code cat_boxx("foo") Output +---------+ | | | foo | | | +---------+ # cat_boxx [unicode] Code cat_boxx("foo") Output ┌─────────┐ │ │ │ foo │ │ │ └─────────┘ # cat_rule [plain] Code local({ withr::local_options(cli.width = 20) cat_rule("title") }) Output -- title ----------- # cat_rule [unicode] Code local({ withr::local_options(cli.width = 20) cat_rule("title") }) Output ── title ─────────── # cat_print [plain] Code cat_print(boxx("")) Output +------+ | | | | | | +------+ --- Code local({ tmp <- tempfile() on.exit(unlink(tmp), add = TRUE) expect_silent(cat_print(boxx(""), file = tmp)) cat(readLines(tmp, warn = FALSE), sep = "\n") }) Output +------+ | | | | | | +------+ # cat_print [unicode] Code cat_print(boxx("")) Output ┌──────┐ │ │ │ │ │ │ └──────┘ --- Code local({ tmp <- tempfile() on.exit(unlink(tmp), add = TRUE) expect_silent(cat_print(boxx(""), file = tmp)) cat(readLines(tmp, warn = FALSE), sep = "\n") }) Output ┌──────┐ │ │ │ │ │ │ └──────┘ cli/tests/testthat/_snaps/vt.md0000644000176200001440000002126214752734140016273 0ustar liggesusers# empty input Code vt_output("", width = 20, height = 2)$segment Output [1] " " " " # raw input Code vt_output(charToRaw("foobar"), width = 20, height = 2)$segment Output [1] "foobar " " " # overflow Code vt_output(strrep("1234567890", 2), width = 19, height = 2)$segment Output [1] "1234567890123456789" "0 " # control characters Code vt_output("foo\nbar", width = 20, height = 2)$segment Output [1] "foo " "bar " --- Code vt_output("foobar\rbaz", width = 20, height = 2)$segment Output [1] "bazbar " " " # scroll up Code vt_output(strrep("1234567890", 5), width = 20, height = 2)$segment Output [1] "12345678901234567890" "1234567890 " --- Code vt_output(paste0(1:10, "\n"), width = 10, height = 5)$segment Output [1] "7 " "8 " "9 " "10 " " " # ANSI SGR [ansi] Code vt_output("12\033[31m34\033[1m56\033[39m78\033[21m90", width = 20, height = 2) Output lineno segmentno segment bold italic underline strikethrough 1 1 1 12 FALSE FALSE FALSE FALSE 2 1 1 34 FALSE FALSE FALSE FALSE 3 1 1 56 TRUE FALSE FALSE FALSE 4 1 1 78 TRUE FALSE FALSE FALSE 5 1 1 90 FALSE FALSE FALSE FALSE 6 2 1 FALSE FALSE FALSE FALSE blink inverse color background_color link link_params 1 FALSE FALSE 2 FALSE FALSE 1 3 FALSE FALSE 1 4 FALSE FALSE 5 FALSE FALSE 6 FALSE FALSE --- Code vt_output(style_bold("I'm bold"), width = 20, height = 2) Output lineno segmentno segment bold italic underline strikethrough 1 1 1 I'm bold TRUE FALSE FALSE FALSE 2 1 1 FALSE FALSE FALSE FALSE 3 2 1 FALSE FALSE FALSE FALSE blink inverse color background_color link link_params 1 FALSE FALSE 2 FALSE FALSE 3 FALSE FALSE --- Code vt_output(style_italic("I'm italic"), width = 20, height = 2) Output lineno segmentno segment bold italic underline strikethrough 1 1 1 I'm italic FALSE TRUE FALSE FALSE 2 1 1 FALSE FALSE FALSE FALSE 3 2 1 FALSE FALSE FALSE FALSE blink inverse color background_color link link_params 1 FALSE FALSE 2 FALSE FALSE 3 FALSE FALSE --- Code vt_output(style_underline("I'm underlined"), width = 20, height = 2) Output lineno segmentno segment bold italic underline strikethrough 1 1 1 I'm underlined FALSE FALSE TRUE FALSE 2 1 1 FALSE FALSE FALSE FALSE 3 2 1 FALSE FALSE FALSE FALSE blink inverse color background_color link link_params 1 FALSE FALSE 2 FALSE FALSE 3 FALSE FALSE --- Code vt_output(style_strikethrough("I'm strikethrough"), width = 20, height = 2) Output lineno segmentno segment bold italic underline strikethrough 1 1 1 I'm strikethrough FALSE FALSE FALSE TRUE 2 1 1 FALSE FALSE FALSE FALSE 3 2 1 FALSE FALSE FALSE FALSE blink inverse color background_color link link_params 1 FALSE FALSE 2 FALSE FALSE 3 FALSE FALSE --- Code vt_output(style_inverse("I'm inverse"), width = 20, height = 2) Output lineno segmentno segment bold italic underline strikethrough 1 1 1 I'm inverse FALSE FALSE FALSE FALSE 2 1 1 FALSE FALSE FALSE FALSE 3 2 1 FALSE FALSE FALSE FALSE blink inverse color background_color link link_params 1 FALSE TRUE 2 FALSE FALSE 3 FALSE FALSE # hyperlinks Code link <- style_hyperlink("text", "url") vt_output(c("pre ", st_from_bel(link), " post"), width = 20, height = 2) Output lineno segmentno segment bold italic underline strikethrough 1 1 1 pre FALSE FALSE FALSE FALSE 2 1 1 text FALSE FALSE FALSE FALSE 3 1 1 post FALSE FALSE FALSE FALSE 4 2 1 FALSE FALSE FALSE FALSE blink inverse color background_color link link_params 1 FALSE FALSE 2 FALSE FALSE url 3 FALSE FALSE 4 FALSE FALSE --- Code link <- style_hyperlink("text", "url", params = c(f = "x", g = "y")) vt_output(c("pre ", st_from_bel(link), " post"), width = 20, height = 2) Output lineno segmentno segment bold italic underline strikethrough 1 1 1 pre FALSE FALSE FALSE FALSE 2 1 1 text FALSE FALSE FALSE FALSE 3 1 1 post FALSE FALSE FALSE FALSE 4 2 1 FALSE FALSE FALSE FALSE blink inverse color background_color link link_params 1 FALSE FALSE 2 FALSE FALSE url f = x:g = y 3 FALSE FALSE 4 FALSE FALSE # erase in line Code vt_output("foobar\033[3D\033[K", width = 10, height = 2)$segment Output [1] "foo " " " Code vt_output("foobar\033[3D\033[0K", width = 10, height = 2)$segment Output [1] "foo " " " Code vt_output("foobar\033[3D\033[1K", width = 10, height = 2)$segment Output [1] " ar " " " Code vt_output("foobar\033[3D\033[2K", width = 10, height = 2)$segment Output [1] " " " " # erase in screen Code vt_output("foo\nfoobar\nfoobar2\033[A\033[4D\033[J", width = 10, height = 4)$ segment Output [1] "foo " "foo " " " " " Code vt_output("foo\nfoobar\nfoobar2\033[A\033[4D\033[0J", width = 10, height = 4)$ segment Output [1] "foo " "foo " " " " " Code vt_output("foo\nfoobar\nfoobar2\033[A\033[4D\033[1J", width = 10, height = 4)$ segment Output [1] " " " ar " "foobar2 " " " Code vt_output("foo\nfoobar\nfoobar2\033[A\033[4D\033[2Jx", width = 10, height = 4)$ segment Output [1] " " " x " " " " " Code vt_output("foo\nfoobar\nfoobar2\033[A\033[4D\033[3Jx", width = 10, height = 4)$ segment Output [1] " " " x " " " " " cli/tests/testthat/test-status-bar.R0000644000176200001440000002135214557444176017234 0ustar liggesusersstart_app() on.exit(stop_app(), add = TRUE) # We can't easily use snapshot tests here, because they don't capture \r test_that("create and clear", { f <- function() { cli_status("* This is the current status") cli_status_clear() } out <- ansi_strip(capt0(f())) expect_match(out, "* This is the current status", fixed = TRUE) out <- ansi_strip(capt0(f())) expect_match(out, "* This is the current status", fixed = TRUE) }) test_that("output while status bar is active", { withr::local_options(list(cli.ansi = FALSE, cli.dynamic = TRUE)) f <- function() { cli_text("out1") sb <- cli_status("status1") cli_text("out2") cli_status_update("status2", id = sb) } out <- ansi_strip(capt0(f())) expect_equal(out, paste0( "out1\n", "\rstatus1\r", "\r \rout2\nstatus1\r", "\rstatus2\r", "\r \r")) }) test_that("interpolation", { withr::local_options(list(cli.ansi = FALSE, cli.dynamic = TRUE)) f <- function() { cli_div(theme = list("span.pkg" = list("before" = "{", after = "}"))) cli_status("You see 1+1={1+1}, this is {.pkg cli}") cli_status_clear() } out <- ansi_strip(capt0(f())) expect_equal(out, paste0( "\rYou see 1+1=2, this is {cli}\r", "\r \r")) }) test_that("update", { withr::local_options(list(cli.ansi = FALSE, cli.dynamic = TRUE)) f <- function() { cli_text("out1") sb <- cli_status("status1") cli_status_update("status2", id = sb) } out <- ansi_strip(capt0(f())) expect_equal(out, paste0( "out1\n", "\rstatus1\r", "\rstatus2\r", "\r \r")) }) test_that("keep", { withr::local_options(list(cli.ansi = FALSE, cli.dynamic = TRUE)) f <- function() { cli_status("* This is the current status", .keep = TRUE) cli_status_clear() } out <- ansi_strip(capt0(f())) expect_equal(out, "\r* This is the current status\r\n") }) test_that("multiple status bars", { withr::local_options(list(cli.ansi = FALSE, cli.dynamic = TRUE)) f <- function() { sb1 <- cli_status("status1") cli_text("text1") sb2 <- cli_status("status2") cli_text("text2") cli_status_clear(sb2) cli_text("text3") } out <- ansi_strip(capt0(f())) expect_equal(out, paste0( "\rstatus1\r", "\r \rtext1\nstatus1\r", # emit text1, restore status1 "\rstatus2\r", # show status2 "\r \rtext2\nstatus2\r", # emit text2, restore status2 "\r \rstatus1\r", # clear status2, restore status1 "\r \rtext3\nstatus1\r", # emit text3, restore status1 "\r \r")) # (auto)clear status1 }) test_that("truncating", { withr::local_options(list( cli.ansi = FALSE, cli.dynamic = TRUE, cli.unicode = FALSE )) f <- function() { withr::local_options(list(cli.width = 40)) txt <- "Eiusmod enim mollit aute aliquip Lorem sunt cupidatat." cli_status(c(txt, txt)) } out <- ansi_strip(capt0(f())) expect_equal(out, paste0( "\rEiusmod enim mollit aute aliquip Lore...\r", "\r \r")) }) test_that("ansi colors and clearing", { withr::local_options(list( cli.num_colors = 256L, cli.ansi = FALSE, cli.dynamic = TRUE )) f <- function() { withr::local_options(list(num_ansi_colors = 256L)) cli_status(col_red("This is red")) cli_status_clear() } out <- capt0(f()) expect_match(out, "\033[31m", fixed = TRUE) expect_match(out, "\r \r", fixed = TRUE) }) test_that("theming status bar", { f <- function() { cli_text("out1") sb <- cli_status("{.alert-info status1}") cli_text("out2") cli_status_update("status2", id = sb) } out <- ansi_strip(capt0(f())) out2 <- ansi_strip(capt0(cli_alert_info("status1"))) expect_match(out, str_trim(out2), fixed = TRUE) }) test_that("successful termination", { withr::local_options(list(cli.ansi = FALSE, cli.dynamic = TRUE)) f <- function() { cli_text("out1") sb <- cli_status("status1") cli_text("out2") cli_status_clear(result = "done") } out <- ansi_strip(capt0(f())) expect_equal(out, paste0( "out1\n", "\rstatus1\r", "\r \rout2\nstatus1\r", "\rstatus1 ... done\r\n" )) }) test_that("terminate with failed", { withr::local_options(list(cli.ansi = FALSE, cli.dynamic = TRUE)) f <- function() { cli_text("out1") sb <- cli_status("status1") cli_text("out2") cli_status_clear(result = "failed") } out <- ansi_strip(capt0(f())) expect_equal(out, paste0( "out1\n", "\rstatus1\r", "\r \rout2\nstatus1\r", "\rstatus1 ... failed\r\n" )) }) test_that("auto close with success", { withr::local_options(list(cli.ansi = FALSE, cli.dynamic = TRUE)) f <- function() { cli_text("out1") sb <- cli_status("status1", .auto_result = "done") cli_text("out2") } out <- ansi_strip(capt0(f())) expect_equal(out, paste0( "out1\n", "\rstatus1\r", "\r \rout2\nstatus1\r", "\rstatus1 ... done\r\n" )) }) test_that("auto close wtih failure", { withr::local_options(list(cli.ansi = FALSE, cli.dynamic = TRUE)) f <- function() { cli_text("out1") sb <- cli_status("status1", .auto_result = "failed") if (is_interactive()) Sys.sleep(2) cli_text("out2") if (is_interactive()) Sys.sleep(2) } out <- ansi_strip(capt0(f())) expect_equal(out, paste0( "out1\n", "\rstatus1\r", "\r \rout2\nstatus1\r", "\rstatus1 ... failed\r\n" )) }) test_that("auto close with styling", { f <- function() { cli_text("out1") sb <- cli_status( msg = "{.alert-info status1}", msg_done = "{.alert-success status1 ... done}", msg_failed = "{.alert-danger status1 ... failed}", .auto_result = "failed" ) if (is_interactive()) Sys.sleep(1) cli_text("out2") if (is_interactive()) Sys.sleep(1) } out <- ansi_strip(capt0(f())) expect_match(out, "status1 ... failed", fixed = TRUE) f2 <- function() { cli_text("out1") sb <- cli_status( msg = "{.alert-info status1}", msg_done = "{.alert-success status1 ... done}", msg_failed = "{.alert-danger status1 ... failed}", .auto_result = "done" ) if (is_interactive()) Sys.sleep(1) cli_text("out2") if (is_interactive()) Sys.sleep(1) } out2 <- ansi_strip(capt0(f2())) expect_match(out2, "status1 ... done", fixed = TRUE) }) test_that("process auto close with success", { f <- function() { cli_text("out1") sb <- cli_process_start("status1", on_exit = "done") cli_text("out2") } out <- ansi_strip(capt0(f())) expect_match(out, "status1 ... done") }) test_that("process auto close with failure", { f <- function() { cli_text("out1") sb <- cli_process_start("status1", on_exit = "failed") if (is_interactive()) Sys.sleep(2) cli_text("out2") if (is_interactive()) Sys.sleep(2) } out <- ansi_strip(capt0(f())) expect_match(out, "status1 ... failed") }) test_that("Multiple spaces are no condensed in a status bar", { f <- function() { cli_status("* This is the current status") cli_status_clear() } out <- ansi_strip(capt0(f())) expect_match(out, "* This is the current status", fixed = TRUE) out <- ansi_strip(capt0(f())) expect_match(out, "* This is the current status", fixed = TRUE) }) test_that("Emojis are cleaned up properly", { skip_on_os("windows") withr::local_options(list(cli.ansi = FALSE, cli.dynamic = TRUE)) f <- function() { cli_text("out1") sb <- cli_status("\U0001F477") cli_text("out2") cli_status_update("\u2728", id = sb) } out <- ansi_strip(capt0(f())) exps <- c( paste0( "out1\n", "\r\U0001F477\r", "\r \rout2\n\U0001F477\r", "\r\u2728\r", "\r \r"), paste0( "out1\n", "\r\r", "\r \rout2\n\r", "\r\r", "\r \r") ) expect_true(out %in% exps) }) test_that("auto-close with done or failure", { withr::local_options(list( cli.ansi = FALSE, cli.dynamic = TRUE, cli.unicode = FALSE )) f <- function() { cli_text("out1") sb <- cli_process_start("status1") cli_text("out2") } out <- ansi_strip(capt0(f())) expect_match(out, "status1 ... done") out <- ansi_strip(capt0(f())) expect_match(out, "status1 ... done") # This fails on older R versions, only if f2() is tryCatch()-ed. if (getRversion() < "3.5.0") skip("Needs R 3.5.0") f2 <- function() { cli_text("out1") sb <- cli_process_start("status1") cli_text("out2") stop("oops") } out2 <- ansi_strip(capt0(tryCatch(f2(), error = function(err) NULL))) expect_match(out2, fixed = TRUE, paste0( "out1\n", "\ri status1\r", "\r \r", "out2\n", "i status1\r", "\rx status1 ... failed\r\n" )) }) cli/tests/testthat/test-hash.R0000644000176200001440000001033614752735214016063 0ustar liggesusers test_that("hash_sha256", { dig <- function(x) { digest::digest(x, serialize = FALSE, algo = "sha256") } cases <- list( list(character(), character()), list("", dig("")), list("x", dig("x")), list(NA_character_, NA_character_), list(NA, NA_character_), list( c(NA, "", "foo", NA), c(NA, dig(""), dig("foo"), NA) ) ) for (case in cases) { expect_equal(hash_sha256(case[[1]]), case[[2]]) } }) test_that("hash_raw_sha256", { dig <- function(x) { digest::digest(x, serialize = FALSE, algo = "sha256") } cases <- list( list(raw(), dig(raw())), list(as.raw(0), dig(as.raw(0))), list(charToRaw("foobar"), dig("foobar")) ) for (case in cases) { expect_equal(hash_raw_sha256(case[[1]]), case[[2]]) } }) test_that("hash_obj_sha256", { dig <- function(x) { digest::digest(x, serializeVersion = 2, algo = "sha256") } cases <- list( "", raw(0), 1:10, mtcars ) for (case in cases) { expect_equal(hash_obj_sha256(case), dig(case)) } }) test_that("hash_file_sha256", { dig <- function(x) { digest::digest(file = x, algo = "sha256") } f <- test_path("test-hash.R") expect_equal( hash_file_sha256(character()), character() ) expect_equal(hash_file_sha256(f), dig(f)) }) test_that("hash_md5", { dig <- function(x) { digest::digest(x, serialize = FALSE, algo = "md5") } cases <- list( list(character(), character()), list("", dig("")), list("x", dig("x")), list(NA_character_, NA_character_), list(NA, NA_character_), list( c(NA, "", "foo", NA), c(NA, dig(""), dig("foo"), NA) ) ) for (case in cases) { expect_equal(hash_md5(case[[1]]), case[[2]]) } }) test_that("hash_raw_md5", { dig <- function(x) { digest::digest(x, serialize = FALSE, algo = "md5") } cases <- list( list(raw(), dig(raw())), list(as.raw(0), dig(as.raw(0))), list(charToRaw("foobar"), dig("foobar")) ) for (case in cases) { expect_equal(hash_raw_md5(case[[1]]), case[[2]]) } }) test_that("hash_obj_md5", { dig <- function(x) { digest::digest(x, serializeVersion = 2, algo = "md5") } cases <- list( "", raw(0), 1:10, mtcars ) for (case in cases) { expect_equal(hash_obj_md5(case), dig(case)) } }) test_that("hash_file_md5", { dig <- function(x) { digest::digest(file = x, algo = "md5") } f <- test_path("test-hash.R") expect_equal( hash_file_md5(character()), character() ) expect_equal(hash_file_md5(f), dig(f)) expect_equal(hash_file_md5(c(f, f)), c(dig(f), dig(f))) }) test_that("hash_emoji", { expect_snapshot({ hash_emoji(character())$names hash_emoji("")$names hash_emoji("x")$names hash_emoji(NA_character_)$names hash_emoji(NA)$names hash_emoji(c(NA, "", "foo", NA))$names }) }) test_that("hash_raw_emoji", { expect_snapshot({ hash_raw_emoji(raw())$names hash_raw_emoji(as.raw(0))$names hash_raw_emoji(charToRaw("foobar"))$names }) }) test_that("hash_obj_emoji", { expect_snapshot({ hash_obj_emoji("")$names hash_obj_emoji(raw(0))$names hash_obj_emoji(1:10)$names hash_obj_emoji(mtcars)$names }) }) test_that("hash_animal", { expect_snapshot({ hash_animal(character())$words hash_animal("")$words hash_animal("x")$words hash_animal(NA_character_)$words hash_animal(NA)$words hash_animal(c(NA, "", "foo", NA))$words }) }) test_that("hash_raw_animal", { expect_snapshot({ hash_raw_animal(raw())$words hash_raw_animal(as.raw(0))$words hash_raw_animal(charToRaw("foobar"))$words }) }) test_that("hash_obj_animal", { expect_snapshot({ hash_obj_animal("")$words hash_obj_animal(raw(0))$words hash_obj_animal(1:10)$words hash_obj_animal(mtcars)$words }) }) test_that("hash_xxhash", { expect_snapshot({ hash_xxhash(letters[1:5]) hash_xxhash(c("a", NA, "b")) hash_xxhash64(letters[1:5]) hash_raw_xxhash(charToRaw("a")) hash_raw_xxhash64(charToRaw("a")) hash_obj_xxhash(raw(0)) hash_obj_xxhash64(raw(0)) }) tmp <- tempfile() on.exit(unlink(tmp), add = TRUE) writeBin(charToRaw("a"), tmp) expect_snapshot({ hash_file_xxhash(tmp) hash_file_xxhash64(tmp) }) }) cli/tests/testthat/test-console-width.R0000644000176200001440000000046514557444176017730 0ustar liggesusers test_that("errors", { withr::local_options(cli.width = letters) expect_snapshot_error( console_width() ) withr::local_options(cli.width = NA_integer_) expect_snapshot_error( console_width() ) withr::local_options(cli.width = -100L) expect_snapshot_error( console_width() ) }) cli/tests/testthat/test-cat.R0000644000176200001440000000024414557444176015713 0ustar liggesusers test_that("cat_line appends to file", { tmp <- tempfile() cat_line("a", file = tmp) cat_line("b", file = tmp) expect_equal(readLines(tmp), c("a", "b")) }) cli/tests/testthat/test-num-ansi-colors.R0000644000176200001440000001216314752735214020166 0ustar liggesuserstest_that("win10_build works for different osVersion", { local_mocked_bindings( sessionInfo = function() list(running = NULL), .package = "utils" ) expect_identical(win10_build(), 0L) local_mocked_bindings( sessionInfo = function() list(running = "Debian GNU/Linux 11 (bullseye)"), .package = "utils" ) expect_identical(win10_build(), 0L) local_mocked_bindings( sessionInfo = function() list(running = "Windows 10 x64 (build 16299)"), .package = "utils" ) expect_identical(win10_build(), 16299L) }) test_that("cli.default_num_colors #1", { # crayon.enabled withr::local_envvar(R_CLI_NUM_COLORS = NA_character_) withr::local_options( cli.num_colors = NULL, crayon.enabled = TRUE, crayon.colors = NULL, cli.default_num_colors = NULL ) expect_equal(num_ansi_colors(), 8L) withr::local_options(cli.default_num_colors = 123L) expect_equal(num_ansi_colors(), 123L) }) test_that("cli.default_num_colors #2", { # Windows emacs withr::local_envvar( R_CLI_NUM_COLORS = NA_character_, RSTUDIO = NA_character_ ) withr::local_options( cli.num_colors = NULL, crayon.enabled = NULL, crayon.colors = NULL, cli.default_num_colors = NULL ) local_mocked_bindings( os_type = function() "windows", commandArgs = function() "--ess", is_emacs_with_color = function() TRUE ) expect_equal(num_ansi_colors(), 8L) withr::local_options(cli.default_num_colors = 123L) expect_equal(num_ansi_colors(), 123L) }) test_that("cli.default_num_colors #3", { # non-truecolor COLORMAP withr::local_envvar(COLORTERM = "other") withr::local_options(cli.default_num_colors = NULL) expect_equal(detect_tty_colors(), 8L) withr::local_options(cli.default_num_colors = 123L) expect_equal(detect_tty_colors(), 123L) }) test_that("cli.default_num_colors #4", { # Unix emacs with color withr::local_envvar(COLORTERM = NA_character_) local_mocked_bindings( os_type = function() "unix", is_emacs_with_color = function() TRUE ) withr::local_options(cli.default_num_colors = NULL) expect_equal(detect_tty_colors(), 8L) withr::local_options(cli.default_num_colors = 123L) expect_equal(detect_tty_colors(), 123L) }) test_that("cli.default_num_colors #5", { # rstudio terminal on Windows withr::local_envvar(COLORTERM = NA_character_) local_mocked_bindings( os_type = function() "windows", win10_build = function() 10586, rstudio_detect = function() list(type = "rstudio_terminal"), system2 = function(...) TRUE ) withr::local_options(cli.default_num_colors = NULL) expect_equal(detect_tty_colors(), 8L) withr::local_options(cli.default_num_colors = 123L) expect_equal(detect_tty_colors(), 123L) }) test_that("cli.default_num_colors #6", { # Windows 10 terminal withr::local_envvar(COLORTERM = NA_character_) withr::local_options(cli.default_num_colors = NULL) local_mocked_bindings( os_type = function() "windows", win10_build = function() 10586, rstudio_detect = function() list(type = "not_rstudio"), system2 = function(...) TRUE ) expect_equal(detect_tty_colors(), 256L) local_mocked_bindings(win10_build = function() 14931) expect_equal(detect_tty_colors(), truecolor) withr::local_options(cli.default_num_colors = 123L) expect_equal(detect_tty_colors(), 123L) }) test_that("cli.default_num_colors #7", { # conemu or cmder withr::local_envvar( COLORTERM = NA_character_, ConEmuANSI = "ON" ) withr::local_options(cli.default_num_colors = NULL) local_mocked_bindings( os_type = function() "windows", win10_build = function() 1 ) expect_equal(detect_tty_colors(), 8L) withr::local_options(cli.default_num_colors = 123L) expect_equal(detect_tty_colors(), 123L) }) test_that("cli.default_num_colors #8", { # unix terminal, xterm withr::local_envvar( COLORTERM = NA_character_, TERM = "xterm" ) local_mocked_bindings( os_type = function() "unix", is_emacs_with_color = function() FALSE, system = function(...) "8" ) withr::local_options(cli.default_num_colors = NULL) expect_equal(detect_tty_colors(), 256L) withr::local_options(cli.default_num_colors = 123L) expect_equal(detect_tty_colors(), 123L) }) test_that("ESS_BACKGROUND_MODE", { withr::local_envvar( RSTUDIO = NA_character_, ESS_BACKGROUND_MODE = NA_character_ ) local_mocked_bindings( is_iterm = function() FALSE, is_emacs = function() TRUE ) expect_false(detect_dark_theme("auto")) withr::local_envvar(ESS_BACKGROUND_MODE = "dark") expect_true(detect_dark_theme("auto")) }) test_that("emacs_version", { withr::local_envvar(INSIDE_EMACS = "") expect_true(is.na(emacs_version())) withr::local_envvar(INSIDE_EMACS = "foobar") expect_true(is.na(emacs_version())) withr::local_envvar(INSIDE_EMACS = "23.2.3") expect_equal(emacs_version(), c(23, 2, 3)) withr::local_envvar(INSIDE_EMACS = "23.2.3,foobar") expect_equal(emacs_version(), c(23, 2, 3)) withr::local_envvar(INSIDE_EMACS = "'23.2.3'") expect_equal(emacs_version(), c(23, 2, 3)) withr::local_envvar(INSIDE_EMACS = "'23.2.3',foobar") expect_equal(emacs_version(), c(23, 2, 3)) }) cli/tests/testthat/test-substitution.R0000644000176200001440000000026014557444176017716 0ustar liggesusers start_app() on.exit(stop_app(), add = TRUE) test_that("glue errors", { expect_error(cli_h1("foo { asdfasdfasdf } bar")) expect_error(cli_text("foo {cmd {dsfsdf()}}")) }) cli/tests/testthat/test-keypress.R0000644000176200001440000000266314635006371017004 0ustar liggesusers test_that("control characaters", { skip_on_cran() p <- r_pty() expect_snapshot( for (code in c(1:2, 4:6, 8:14, 16L, 20L, 21L, 23L, 27L, 127L)) { p$write_input("cli::keypress()\n") Sys.sleep(0.1) p$write_input(as.raw(code)) p$poll_io(1000) cat(p$read_output()) } ) }) test_that("write ahead", { skip_on_cran() p <- r_pty() expect_snapshot({ p$write_input("{ Sys.sleep(0.5); cli::keypress() }\nX") p$poll_io(1000) cat(p$read_output()) }) }) test_that("arrows, etc", { skip_on_cran() p <- r_pty() keys <- paste0("\033", c( "[A", "[C", "[D", "[F", "[H", "-", "OA", "OB", "OC", "OD", "OF", "OH", "-", "[1~", "[2~", "[3~", "[4~", "[5~", "[6~", "-", "[[5~", "[[6~", "-", "[[7~", "[[8~", "-", "OP", "OQ", "OR", "OS", "-", "[15~", "[17~", "[18~", "[19~", "[20~", "[21~", "[23~", "[24~", "-", "[11~", "[12~", "[13~", "[14~", "-", "" )) keys[keys == "\033-"] <- "-" expect_snapshot({ for (key in keys) { p$write_input("cli::keypress()\n") p$write_input(key) p$poll_io(1000) cat(p$read_output()) } }) }) test_that("nonblocking", { skip_on_cran() p <- r_pty() expect_snapshot({ p$write_input("cli::keypress(block = FALSE)\n") p$poll_io(1000) cat(p$read_output()) }) expect_snapshot({ p$write_input("{ Sys.sleep(0.5); cli::keypress() }\nX") p$poll_io(1000) cat(p$read_output()) }) }) cli/tests/testthat/test-progress-client.R0000644000176200001440000001252614752735214020263 0ustar liggesusers test_that("cli_progress_bar", { withr::local_options(cli.dynamic = FALSE, cli.ansi = FALSE) fun <- function() { bar <- cli_progress_bar( name = "name", status = "status", format = "{cli::pb_spin} {cli::pb_name}{cli::pb_status}{cli::pb_current}" ) cli_progress_update(force = TRUE) cli_progress_done(id = bar) } expect_snapshot(capture_cli_messages(fun())) }) test_that("custom format needs a format string", { expect_error(cli_progress_bar(type = "custom"), "Need to specify format") }) test_that("removes previous progress bar", { withr::local_options(cli.dynamic = FALSE, cli.ansi = FALSE) fun <- function() { bar <- cli_progress_bar(format = "first", format_done = "first done", clear = FALSE) cli_progress_update(force = TRUE) bar2 <- cli_progress_bar(format = "second", format_done = "second done", clear = FALSE) cli_progress_update(force = TRUE) } expect_snapshot(capture_cli_messages(fun())) }) test_that("backend methods are called", { withr::local_options(cli.progress_handlers_only = "logger") fun <- function() { cli_progress_bar() cli_progress_update(force = TRUE) cli_progress_done() } out <- capture_output(fun()) expect_match(out, "created.*added.*updated.*terminated") }) test_that("update errors if no progress bar", { fun <- function() { cli_progress_update() } expect_error(fun(), "Cannot find current progress bar") fun <- function() { cli_progress_output("boo") } expect_error(fun(), "Cannot find current progress bar") envkey <- NULL fun <- function() { envkey <<- format(environment()) clienv$progress_ids[[envkey]] <- "foobar" cli_progress_update() } expect_error(fun(), "Cannot find progress bar") envkey <- NULL fun <- function() { envkey <<- format(environment()) clienv$progress_ids[[envkey]] <- "foobar" cli_progress_output("booboo") } expect_error(fun(), "Cannot find progress bar") clienv$progress_ids[[envkey]] <- NULL }) test_that("cli_progress_update can update status", { withr::local_options(cli.dynamic = FALSE, cli.ansi = FALSE) fun <- function() { bar <- cli_progress_bar( name = "name", status = "status", format = "{cli::pb_spin} {cli::pb_name}{cli::pb_status}{cli::pb_current}" ) cli_progress_update(force = TRUE) cli_progress_update(status = "new status", force = TRUE) cli_progress_done(id = bar) } expect_snapshot(capture_cli_messages(fun())) }) test_that("cli_progress_update can update extra data", { withr::local_options(cli.dynamic = FALSE, cli.ansi = FALSE) fun <- function() { bar <- cli_progress_bar( format = "Extra: {cli::pb_extra$foo}", extra = list(foo = "bar") ) cli_progress_update(force = TRUE) cli_progress_update(extra = list(foo = "baz"), force = TRUE) cli_progress_done(id = bar) } expect_snapshot(capture_cli_messages(fun())) }) test_that("update set", { withr::local_options(cli.dynamic = FALSE, cli.ansi = FALSE) fun <- function() { bar <- cli_progress_bar( name = "name", total = 100, format = "{cli::pb_name}{cli::pb_status}{cli::pb_current}/{cli::pb_total}" ) cli_progress_update(force = TRUE) cli_progress_update(force = TRUE, set = 50) cli_progress_done(id = bar) } expect_snapshot(capture_cli_messages(fun())) }) test_that("format changes if we (un)learn total", { withr::local_options(cli.dynamic = FALSE, cli.ansi = FALSE) fun <- function() { bar <- cli_progress_bar( name = "name", total = NA, ) cli_progress_update(force = TRUE) cli_progress_update(force = TRUE, set = 50, total = 100) cli_progress_update(force = TRUE, set = 75, total = NA) cli_progress_done(id = bar) } out <- fix_times(capture_cli_messages(fun())) expect_snapshot(out) }) test_that("auto-terminate", { withr::local_options(cli.dynamic = FALSE, cli.ansi = FALSE) fun <- function() { bar <- cli_progress_bar(total = 10, format = "first", format_done = "first done", clear = FALSE) cli_progress_update(force = TRUE) cli_progress_update(force = TRUE, set = 10) cli_text("First is done by now.\n") bar2 <- cli_progress_bar(format = "second", format_done = "second done", clear = FALSE) cli_progress_update(force = TRUE) } expect_snapshot(capture_cli_messages(fun())) }) test_that("done does nothing if no progress bar", { fun <- function() { cli_progress_done() } expect_true(fun()) }) test_that("cli_progress_output", { skip_if_not_installed("testthat", "3.1.2") withr::local_options(cli.dynamic = TRUE, cli.ansi = TRUE) fun <- function() { bar <- cli_progress_bar(total = 10, format = "first") cli_progress_update(force = TRUE) cli_progress_output("just {1} text{?s}") cli_progress_update(force = TRUE) } expect_snapshot(capture_cli_messages(fun())) withr::local_options(cli.dynamic = TRUE, cli.ansi = FALSE) expect_snapshot(capture_cli_messages(fun())) }) test_that("cli_progress_bar handles Inf like NA", { withr::local_options(cli.dynamic = FALSE, cli.ansi = FALSE) fun <- function(total) { bar <- cli_progress_bar( name = "name", format = "{cli::pb_name}{cli::pb_current}", total = total ) cli_progress_update(force = TRUE) cli_progress_done(id = bar) } expect_equal(capture_cli_messages(fun(total = NA)), capture_cli_messages(fun(total = Inf))) }) cli/tests/testthat/test-ansi-utils.R0000644000176200001440000000266214557444176017242 0ustar liggesusers test_that("re_table", { withr::local_options( cli.num_colors = 256, cli.hyperlink = TRUE ) txt <- paste0( "this is some text ", col_red("red"), " some more text ", col_green("green"), " then some ", style_hyperlink("text", "https://example.com") ) tbl <- re_table(ansi_regex(), txt)[[1]] tbl2 <- cbind(tbl, c(text = substring(txt, tbl[, "start"], tbl[, "end"]))) expect_snapshot(tbl2) expect_snapshot(non_matching(list(tbl), txt)) }) test_that("re_table special cases", { withr::local_options( cli.num_colors = 256, cli.hyperlink = TRUE ) txt <- "foobar" tbl <- re_table(ansi_regex(), txt)[[1]] expect_snapshot(tbl) expect_snapshot(non_matching(list(tbl), txt)) expect_snapshot(non_matching(list(tbl), txt, empty = TRUE)) txt <- col_red("foobar") tbl <- re_table(ansi_regex(), txt)[[1]] expect_snapshot(tbl) expect_snapshot(non_matching(list(tbl), txt)) expect_snapshot(non_matching(list(tbl), txt, empty = TRUE)) txt <- paste0("foo ", col_red(""), " bar") tbl <- re_table(ansi_regex(), txt)[[1]] expect_snapshot(tbl) expect_snapshot(non_matching(list(tbl), txt)) expect_snapshot(non_matching(list(tbl), txt, empty = TRUE)) }) test_that("myseq", { expect_snapshot({ myseq(1, 5) myseq(1, 1) myseq(1, 0) myseq(1, 5, 2) myseq(1, 6, 2) myseq(1, 1, 2) myseq(1, 2, -1) myseq(10, 1, -1) myseq(10, 1, -2) myseq(1, 5, -2) }) }) cli/tests/testthat/test-verbatim.R0000644000176200001440000000053214557444176016755 0ustar liggesusers start_app() on.exit(stop_app(), add = TRUE) test_that("verbatim text is correctly styled", { expect_snapshot(local({ theme <- list(.padded = list("margin-left" = 4)) cli_div(class = "padded", theme = theme) lines <- c("first", "second", "third") cli_verbatim(lines) cli_verbatim(paste0(lines, collapse = "\n")) })) }) cli/tests/testthat/test-ansi-palette.R0000644000176200001440000000172614557444176017540 0ustar liggesusers test_that("ansi_palette_show", { local_clean_cli_context() expect_snapshot( ansi_palette_show(colors = truecolor) ) withr::local_options(cli.palette = "iterm-snazzy") expect_snapshot( ansi_palette_show(colors = truecolor) ) }) test_that("error", { expect_snapshot( error = TRUE, withr::with_options( list(cli.palette = "foobar12"), ansi_palette_show(colors = 256) ) ) }) test_that("custom palettes", { withr::local_options( cli.num_colors = 256, cli.palette = "iterm-snazzy" ) expect_snapshot({ col_black("black") col_red("red") col_green("green") col_yellow("yellow") col_blue("blue") col_magenta("magenta") col_cyan("cyan") col_white("white") col_br_black("br_black") col_br_red("br_red") col_br_green("br_green") col_br_yellow("br_yellow") col_br_blue("br_blue") col_br_magenta("br_magenta") col_br_cyan("br_cyan") col_br_white("br_white") }) }) cli/tests/testthat/test-app.R0000644000176200001440000000035514557444176015727 0ustar liggesusers test_that("stop_app() errors", { expect_snapshot( error = TRUE, stop_app(1:10) ) }) test_that("warning if inactive app", { app <- start_app(.auto_close = FALSE) stop_app(app) expect_snapshot( stop_app(app) ) }) cli/tests/testthat/test-diff.R0000644000176200001440000000435614557444176016064 0ustar liggesusers test_that("diff_chr", { # Something simple first a <- as.character(c(1,1,1,1,1,1,1,2,3,4,4,4,4,4,4,4,5)) b <- as.character(c(1,1,1,1,1,1,1,2,10,4,4,4,4,4,4,4,6,7,5)) d <- diff_chr(a, b) expect_snapshot(d$lcs) d <- diff_chr(b, a) expect_snapshot(d$lcs) }) test_that_cli(configs = c("plain", "ansi"), "diff_chr", { # Something simple first a <- as.character(c(1,1,1,1,1,1,1,2,3,4,4,4,4,4,4,4,5)) b <- as.character(c(1,1,1,1,1,1,1,2,10,4,4,4,4,4,4,4,6,7,5)) d <- diff_chr(a, b) expect_snapshot(d) expect_snapshot(d$lcs) }) test_that("diff_chr edge cases", { expect_snapshot(diff_chr(character(), character())) expect_snapshot(diff_chr(character(), character())$lcs) expect_snapshot(diff_chr("a", character())) expect_snapshot(diff_chr(character(), "b")) expect_snapshot(diff_chr("a", "a")) expect_snapshot(diff_chr(letters, letters)) expect_snapshot(diff_chr(c("a", NA, "a2"), "b")) expect_snapshot(diff_chr(NA_character_, "NA")) }) test_that("format.cli_diff_chr context", { # Something simple first a <- as.character(c(1,1,1,1,1,1,1,2,3,4,4,4,4,4,4,4,5)) b <- as.character(c(1,1,1,1,1,1,1,2,10,4,4,4,4,4,4,4,6,7,5)) d <- diff_chr(a, b) expect_snapshot(print(d, context = 1)) expect_snapshot(print(d, context = 0)) expect_snapshot(print(d, context = Inf)) d2 <- diff_chr(c("foo", "bar"), c("foo", "bar")) expect_snapshot(print(d2, context = Inf)) }) test_that_cli(configs = c("plain", "ansi"), "diff_str", { str1 <- "abcdefghijklmnopqrstuvwxyz" str2 <- "PREabcdefgMIDDLEnopqrstuvwxyzPOST" d <- diff_str(str1, str2) expect_snapshot(d) }) test_that("warnings and errors", { expect_error(diff_chr(1:10, 1:10), "is.character") expect_error( format(diff_chr("foo", "bar"), context = -1), "is_count" ) expect_warning( format(diff_chr("foo", "bar"), what = 1, is = 2, this = 3), "Extra arguments" ) expect_warning( format(diff_str("foo", "bar"), what = 1, is = 2, this = 3), "Extra arguments" ) }) test_that("max_diff", { expect_snapshot_error( class = "cli_diff_max_dist", diff_chr("a", c("a", "b"), 0) ) expect_silent(diff_chr(c("a", "c"), c("a", "b"), 2)) expect_snapshot_error( class = "cli_diff_max_dist", diff_chr(c("a", "c"), c("a", "b"), 1) ) }) cli/tests/testthat/setup.R0000644000176200001440000000026414557444176015331 0ustar liggesusers unlink(dir( file.path(dirname(dirname(normalizePath(test_path()))), "src"), pattern = "[.]gcda$", full.names = TRUE )) withr::defer(.Call(clic__gcov_flush), teardown_env()) cli/tests/testthat/test-timer.R0000644000176200001440000000043614557444176016267 0ustar liggesusers test_that("ALTREP methods", { expect_equal(length(`__cli_update_due`), 1L) expect_silent({ tim <- `__cli_update_due` tim[1] <- FALSE }) expect_silent({ `__cli_update_due`[1] }) }) test_that("cli_tick_set", { skip_on_cran() expect_silent(cli_tick_set()) }) cli/tests/testthat/test-ansi.R0000644000176200001440000000653014557444176016102 0ustar liggesusers test_that("Classes", { expect_equal(class(style_underline("foo")), c("cli_ansi_string", "ansi_string", "character")) }) test_that("Coloring and highlighting works", { local_reproducible_output(crayon = TRUE) expect_equal(c(style_underline("foo")), "\u001b[4mfoo\u001b[24m") expect_equal(c(col_red("foo")), "\u001b[31mfoo\u001b[39m") expect_equal(c(bg_red("foo")), "\u001b[41mfoo\u001b[49m") }) test_that("Applying multiple styles at once works", { local_reproducible_output(crayon = TRUE) st <- combine_ansi_styles(col_red, bg_green, "underline") expect_equal( c(st("foo")), "\u001b[31m\u001b[42m\u001b[4mfoo\u001b[24m\u001b[49m\u001b[39m") st <- combine_ansi_styles(style_underline, "red", bg_green) expect_equal( c(st("foo")), "\u001b[4m\u001b[31m\u001b[42mfoo\u001b[49m\u001b[39m\u001b[24m") }) test_that("Nested styles are supported", { local_reproducible_output(crayon = TRUE) st <- combine_ansi_styles(style_underline, bg_blue) expect_equal( c(col_red("foo", st("bar"), "!")), "\u001b[31mfoo\u001b[4m\u001b[44mbar\u001b[49m\u001b[24m!\u001b[39m") }) test_that("Nested styles of the same type are supported", { local_reproducible_output(crayon = TRUE) expect_equal( c(col_red("a", col_blue("b", col_green("c"), "b"), "c")), "\u001b[31ma\u001b[34mb\u001b[32mc\u001b[34mb\u001b[31mc\u001b[39m") }) test_that("Reset all styles", { local_reproducible_output(crayon = TRUE) st <- combine_ansi_styles("red", bg_green, "underline") ok <- c( paste0( "\033[0m\033[31m\033[42m\033[4mfoo\033[24m\033[49m\033[39m", "foo\033[0m\033[22m\033[23m\033[24m\033[27m\033[28m", "\033[29m\033[39m\033[49m"), paste0("\u001b[0m\u001b[31m\u001b[42m\u001b[4mfoo\u001b[24m\u001b[49m", "\u001b[39mfoo\u001b[0m") ) expect_true(style_reset(st("foo"), "foo") %in% ok) }) test_that("Variable number of arguments", { local_reproducible_output(crayon = TRUE) expect_equal(c(col_red("foo", "bar")), "\u001b[31mfoobar\u001b[39m") }) test_that("print.cli_ansi_style", { expect_snapshot( print(col_red) ) }) test_that("print.cli_ansi_string", { withr::local_options(cli.num_colors = 256) expect_snapshot( print(col_red("red")) ) }) test_that("ansi-scale", { expect_snapshot({ ansi_scale(c(0,0,0)) ansi_scale(c(255,100,0)) ansi_scale(c(255,100,0), round = FALSE) }) }) test_that("zero length vectors", { withr::local_options(cli.num_colors = 1) expect_equal(length(col_cyan(character())), 0) expect_equal(length(bg_cyan(character())), 0) expect_equal(length(col_br_cyan(character())), 0) expect_equal(length(bg_br_cyan(character())), 0) withr::local_options(cli.num_colors = 8) expect_equal(length(col_cyan(character())), 0) expect_equal(length(bg_cyan(character())), 0) expect_equal(length(col_br_cyan(character())), 0) expect_equal(length(bg_br_cyan(character())), 0) withr::local_options(cli.num_colors = 256) expect_equal(length(col_cyan(character())), 0) expect_equal(length(bg_cyan(character())), 0) expect_equal(length(col_br_cyan(character())), 0) expect_equal(length(bg_br_cyan(character())), 0) withr::local_options(cli.num_colors = truecolor) expect_equal(length(col_cyan(character())), 0) expect_equal(length(bg_cyan(character())), 0) expect_equal(length(col_br_cyan(character())), 0) expect_equal(length(bg_br_cyan(character())), 0) }) cli/tests/testthat.R0000644000176200001440000000006214557444176014165 0ustar liggesuserslibrary(testthat) library(cli) test_check("cli") cli/MD50000644000176200001440000006515314753300402011341 0ustar liggesusers5c51481e0974246272381a797ec14d9f *DESCRIPTION 6f22fdde441ec9cbaddb626d704887aa *LICENSE 178772a56e7476d2074a8431a4660c38 *LICENSE.note 67bf9da24d70edfab77849bce5a9dcd1 *NAMESPACE c7ab16e8aa3e1ad4373ea95e613c3513 *NEWS.md 25c9f9e1468860541dad28b4bae30731 *R/aaa-utils.R 6cfe3eeba4629affff58e35ff9f99cad *R/aab-rstudio-detect.R a721ee6472f4d2a3490dd01b2ea930d8 *R/ansi-hyperlink.R 9c30bc56555d4b4075fded1a2a18753a *R/ansi-palette.R cd9a096faf39d45ff9084969533b5ec3 *R/ansi-utils.R cff4a01d1bf281ca18b6cd37150bb65b *R/ansi.R d49b0bb09dfb8780c20ae7ed4550e8ec *R/ansiex.R b6f38d1f5d0fadb472fa28e22def9b17 *R/app.R 2017cf06cdfba8e61920d34521a27443 *R/assertions.R f70df326a4e14bbdc143d1c984663303 *R/box-styles.R 347f09c3281a10bcdc0d2be40bf7e25a *R/boxes.R 55c0d7461b7e3324c1ba01019783d818 *R/bullets.R 516839eb767f2f32445cd6ec1e64c34e *R/cat.R 69713c927ab70be64c2d4bd39d10a6bf *R/cli-errors.R 036450882ab5669f3459e55894d34317 *R/cli-package.R ffefe94dcaa1c107881f9f480ced6f2a *R/cli.R 81d72f031bf0360703a7c5c9e6aba1a3 *R/cliapp-docs.R 895262e99c7984ab213bfbdaf5c3d80d *R/cliapp.R 53fe0d04585b70532bac3069a3d2a5a2 *R/containers.R 87d9b64fa630b7a669d4e51cede01854 *R/debug.R 2f63f85d446715d0dd509fee3b2d35c6 *R/defer.R db10c08e18d82c6f5d211f8bbf31fe93 *R/diff.R 3b776cb5d6a93f08073c0f40ddab4778 *R/docs.R c9d952971dfe1e28aea75308dcf670f9 *R/enc-utils.R 4f9626f9d682428a8d21b5965452f008 *R/errors.R 3b751116872d38ad76ad4b3f1e174a71 *R/format-conditions.R a9a5198c5f0209e6230a8641e16faf94 *R/format.R 08012448106846fa3a3848dc6c8b417a *R/friendly-type.R 9b1a7dc9293185547032c1388fda35cd *R/glue.R ecfd41bfb1acbaa2ef5fa6d96b98e524 *R/hash.R a3aeeca404ffea17fa14a023d79c7535 *R/inline.R 5a7ef0cdf45eb56061729099784c3a2b *R/internals.R a9b3f6f15c34370258194e1c518b260a *R/keypress.R ff681a26e738a802bd685bd2961a5039 *R/lorem.R f2c5aa8c7582742573eadf502fa04754 *R/mocks.R c9112d968bab24abe06fd6938e81e2c7 *R/num-ansi-colors.R 652144408a87dd191039b45a542e3e3f *R/onload.R cfd8bdec8fd612f8d4fb3361780c5988 *R/pluralize.R 47d680d0327705761cae99c6c63ce411 *R/prettycode.R 0684c80487792c973578cff43389a0c7 *R/print.R 50cae8bff401023070aba7d12c5d7108 *R/progress-along.R c22944245d1253723fdd3d9e7ebd0703 *R/progress-bar.R 52a904d067ccd88ab3d0b04d210197c4 *R/progress-c.R ed90153597098337cf262cc84ee555c8 *R/progress-client.R 39f09009dbee1a9a599069fa8470a6c9 *R/progress-server.R 55a2556795e8cc0d29f874900b1a51d4 *R/progress-ticking.R 68ad576593bf21d5c8be5be99296f7f3 *R/progress-utils.R da4f83ce401f356646ae58698e89a11e *R/progress-variables.R 6d32216035fb4ac46d9401e1bdde9596 *R/rematch2.R c2ff24dc09ae661f3cd337ef9a7bced6 *R/rlang.R 02973c8e5edd0acad617c03f82ce894e *R/ruler.R 01e86ed0edf7d0f67104adab8958d2de *R/rules.R 6314e0be26278524847b03e0eaa82536 *R/server.R b08ce1ca8f5ec3c48822668b0e33e0f7 *R/simple-theme.R 782d72952cf8982df5c21aedf119c815 *R/sitrep.R fe5d0e7464286dd1e07746d3da593ad9 *R/sizes.R 7e5bcdbc0128dfa42cef67542fc76013 *R/spark.R 4fc4855ca0231186268c3dceb6177ad7 *R/spinner.R 5276ffce0d82412d9944553d7fac08a5 *R/status-bar.R 537925f62ea66c1fec76ac95b58b6a77 *R/symbol.R a0a0a19c474ac3b68b331d14b1a86ea3 *R/sysdata.rda 5b99cc0feab32255a4fb4d486e479bfe *R/test.R 3c6f93aeafcad0ed15f1414bb4bd31ef *R/themes.R dd7f5ddd6a39f483fe1606a1f80b3e0c *R/time-ago.R 5b1c514866de7bd0ca2a88a6c0889cd8 *R/time.R 57c041c648b8e5d4cf17e5e8b0a43ccb *R/timer.R 6e671b6ff7561f2782e0f6a657a4ec00 *R/tree.R 7fd2537048736697be29ad4d387d9c11 *R/tty.R 50794dc6d843381ccd68d7bc8fa424cb *R/unicode.R 492880f712bc5550da424f50b8773231 *R/utf8.R 589cb3bdb6f41a9dc57afd31257bc51a *R/utils.R 7656100084d56a42e27e615d69b8dbe5 *R/vt.R 198da767fa7a1b18d3dd3c5aca77afb1 *R/width.R b056fe999c5d25b825486db469e83d34 *R/zzz.R c2529ca0252e40cd71254cd9ccddc164 *README.md b92af83cdf1863d79ba5db78caed49f5 *exec/news.R b6a34628690fc7587a54c6f271956f3c *exec/outdated.R 7b3b382306a00ed2ed4751dc20684556 *exec/search.R c43a681bd9ce1d951d7e066a79505658 *exec/up.R b92af83cdf1863d79ba5db78caed49f5 *inst/examples/apps/news.R d71030204ac721b2b6fb9dd1f013066b *inst/examples/apps/outdated.R e3540d59292af42b3b1570c25cb55260 *inst/examples/apps/search.R 234ede852bac1dc638fc0d774a764ee8 *inst/examples/apps/up.R f07e6e168985b8a6dd63dafd2894d514 *inst/include/cli/progress.h aaffd10fd0246bb9d2333d0d2c920093 *inst/logo.txt a8a10e10ed0b9a9cc92cda3e58e487af *inst/shiny/along/app.R 5590d85218e87a0c1d1071c37db6d382 *inst/shiny/format/app.R 23a60b6905cfc334e4b021f04113b043 *inst/shiny/nested/app.R 8020185d6a15e38bc931667419f6c4c7 *inst/shiny/output/app.R bcc9a5722e9728e99017db12f690f194 *inst/shiny/simple/app.R 8af86d0ec79df75967a53e64662cbbfa *man/ansi-styles.Rd feb924ef040f5a0c0a179848b2e0291c *man/ansi_align.Rd 8ff28b95e615f245f2c615fde6d1b5cc *man/ansi_collapse.Rd 7a3a2a5d499baf7d738745e37cc5f4bc *man/ansi_columns.Rd ac457b91032ef7ce7722d3438ee14d24 *man/ansi_grep.Rd 115007a3f20b1ef44567b7ed4cd35858 *man/ansi_has_any.Rd f68da67e7e645edb662d77ddf358905b *man/ansi_hide_cursor.Rd 1a37eeb384364fa8e8fa025273ea3cc9 *man/ansi_html.Rd 7da000a2c8aff64dd809c02a1f91f6df *man/ansi_html_style.Rd 1019c6e5944c48e194d4d47c0179412d *man/ansi_nchar.Rd b7618e93b54e36498d6cfac81e731c66 *man/ansi_nzchar.Rd 7078c14f79f52dd1b8d08644463150a0 *man/ansi_palettes.Rd 0fc4b1c101d6dc994ed588ad5749743f *man/ansi_regex.Rd 32ff45897a16fa7c07c8a0c8746afe80 *man/ansi_simplify.Rd 7f152983b3b20cfbf79d57503961d8b7 *man/ansi_string.Rd e2da8f56c43b6db29581bd22d4cf1e27 *man/ansi_strip.Rd ef9b56f587574fc335142bf13a8120a0 *man/ansi_strsplit.Rd 29b069a307fcdc854c85412cb3927714 *man/ansi_strtrim.Rd 38052410b2c33e82c13df467372ef7fe *man/ansi_strwrap.Rd 9954140be0e125751e93951c0d301182 *man/ansi_substr.Rd 3a90dbf17a37429e8ac1a7a32a40d052 *man/ansi_substring.Rd e8f62d8b62c267af270fbae9c9026655 *man/ansi_toupper.Rd 86ebb521da07bc3f2535d48b5db37d4d *man/ansi_trimws.Rd 72e7f966b14abaf3d88d5cdbf643510b *man/boxx.Rd c56046e570f1b3467f0136119d01da17 *man/builtin_theme.Rd b5c432d6f1ab7a9b463099e28fa76ec4 *man/cat_line.Rd 4711e7141b36ac0371164e75ca84b233 *man/chunks/FAQ.Rmd 287ec651ca4d8fca553740b582dbdd2d *man/chunks/pluralization.Rmd 00ee578e79ce058360e47b563048297d *man/cli-config.Rd 6abb58b065e2b820322c40b271b42e1c *man/cli-package.Rd 965bab2810f5df039a0575d8fcf780a0 *man/cli.Rd cd0af8e1250a39312eb63bae4f2a32a7 *man/cli_abort.Rd 1b2b35608fb5c5fe4d1241aaa3853f5e *man/cli_alert.Rd d700521485443212c9d738948e68ca50 *man/cli_blockquote.Rd c880df8f32d130a0c96e197ebff9e409 *man/cli_bullets.Rd 02126ad6913c4adf9e0946c84195892a *man/cli_bullets_raw.Rd d21a156f76739523030e9c8f91648e4d *man/cli_code.Rd 232d6b4778feadf731bb225998b240c8 *man/cli_debug_doc.Rd 4edc86124419fb3da950ee7fdb695cb7 *man/cli_div.Rd 5ab1fbbe348999934317b8ad2f2f425b *man/cli_dl.Rd 7c42e5de7ff1518ad5f1c1e29dd86dce *man/cli_end.Rd 64d4b5f6656ed5cd75775cb832cc8aaa *man/cli_fmt.Rd b071a2fb01d431263648f0ba0582c925 *man/cli_format.Rd 304d09c6e0020b2247bfa9fe7ac558b8 *man/cli_format_method.Rd eadd91c05f6a2e5bd2a7cd3a96e01531 *man/cli_h1.Rd 4a9be0559baa06b4c74da2418701b2b2 *man/cli_li.Rd 83478eb8af3d7ef1d29d18d2dae2285c *man/cli_list_themes.Rd 58a471e74515063230ed6f5784de4380 *man/cli_ol.Rd d459b7f8ded61e8f59bd9b4191be5c60 *man/cli_output_connection.Rd 5bb2c0ec4105dbcf0f928ad7317f6feb *man/cli_par.Rd 44565d4f14d81135ff5f6372a5b666f6 *man/cli_process_start.Rd e84aac387af347358f0ebf0061154c0f *man/cli_progress_along.Rd 75369351b074f457e5746db23612f1d3 *man/cli_progress_bar.Rd 31a9049d083bfc8722fd6f1813b420f4 *man/cli_progress_builtin_handlers.Rd 2cd22fcc531ad7c5f4209eff10363eb6 *man/cli_progress_demo.Rd d6d9a697de00a8115f683bb39c55f494 *man/cli_progress_message.Rd 89db5f24902625f6c6104a472f208b0c *man/cli_progress_output.Rd 089c6c81024785f96e36146b60da4a02 *man/cli_progress_step.Rd 0a8b190070e00cc03a36f323be10dea4 *man/cli_progress_styles.Rd 2d60f8f57d02944fd433446765f2e244 *man/cli_rule.Rd 703b30512fdf9cf4e5c6e8ae962384d1 *man/cli_sitrep.Rd 0e325a64eb1541277de3b9871ba5f336 *man/cli_status.Rd 063c46dbf201f43e96141de7aa8b690e *man/cli_status_clear.Rd 6b26131864b96c55c6b0f986720901ea *man/cli_status_update.Rd a89ff9df5ed2cf93afdf876e9c22a7de *man/cli_text.Rd fbd392ac81f4efb6abda8517d5c5c126 *man/cli_ul.Rd 990e7498cac20c2a70a8b5c2c923fe05 *man/cli_vec.Rd fd7e89e6fcae6c6ac2f2c1c04134004c *man/cli_verbatim.Rd 326ae23db5c9ea39164e9a8f3d03db06 *man/code_highlight.Rd b0acf80707f7e8f1f9ff5941b2f99dd7 *man/code_theme_list.Rd fd6c759558a78f96d61fa6c00b4a4c11 *man/combine_ansi_styles.Rd 5d54dc2998bb6e9fd3a0d35d8310256a *man/console_width.Rd 947e7a8476c717182da4c5f3f450661e *man/containers.Rd 7ef704253e815c524f51b54e0839701c *man/demo_spinners.Rd d82792e8be7da850aa955041154e329b *man/diff_chr.Rd 50d025ccd01f02ce1931d3789e24f810 *man/diff_str.Rd 100bc227e7b4db9ed2731023ee1d5911 *man/faq.Rd 0948c9a3b0b84289def9b0545f776b89 *man/figures/README/alert-danger-dark.svg efc51fb42ff937df15377dfff157da2f *man/figures/README/alert-danger.svg c128c1fb9b55e4f7830d702bdd333589 *man/figures/README/alert-dark.svg 2a2b1083a591bd9304139c4615234bf2 *man/figures/README/alert-info-dark.svg 31f7cf7cb0ab3e84058d08df59756d89 *man/figures/README/alert-info.svg 12019b6905a82c92531ee877ac003708 *man/figures/README/alert-success-dark.svg d3d61e57ad121177946b4654533b841f *man/figures/README/alert-success.svg 7775df482aedff93689ebe43553f1e46 *man/figures/README/alert-warning-dark.svg b71964f90189a6b0723ce89e062311ad *man/figures/README/alert-warning.svg 39b19c7a753182fca6c679f42c3b5d4e *man/figures/README/alert.svg f7c70c99088de43ba96a1ebcd724e3bc *man/figures/README/glue-dark.svg 51e7fcb5b74eb572578c40574b46ad0e *man/figures/README/glue.svg dbed9edf48756f81ec7dde6c21cd2d96 *man/figures/README/h1-dark.svg e42233be5956061790e0163722f211d0 *man/figures/README/h1.svg 1e615721f77d310ea049259db1969863 *man/figures/README/h2-dark.svg 84118d478f8091ff64efd9638c47b2b7 *man/figures/README/h2.svg 8f762f322278bf146201e626df1bc739 *man/figures/README/h3-dark.svg 61740d55059c9da6f22c5fbc93159b39 *man/figures/README/h3.svg 8891626fb9ca8d7737b30ecb22435d96 *man/figures/README/lists-dark.svg 8f9c7d204cc49ea744c944cfc919908a *man/figures/README/lists.svg d6017acaea4e55cc9c259d632fae75e5 *man/figures/README/plurals-dark.svg 4b6acaca49a1551dcb9d6b967162925f *man/figures/README/plurals.svg 139b74c2c899cf1d364f2df75848d634 *man/figures/README/progress-dark.svg be3ffa658a3b517ebb65aeaf96e18026 *man/figures/README/progress.svg e44182e891b3e1e86ba1f7c008393530 *man/figures/README/themes-dark.svg 08d49aa5ecba5df8775a38d05a32015a *man/figures/README/themes.svg bd84cb28693c63aa23bbe74512417665 *man/figures/demo-spinners.svg ab6de8f8eec056c56e44b5de2edca236 *man/figures/get-spinner.svg e7bad1f8dceb766729a88ab41beb7deb *man/figures/make-spinner-custom.svg bfb1c13e199f4f29a8691059e929f63a *man/figures/make-spinner-default.svg 9b254f89709a46381b3b47521dc52bae *man/figures/make-spinner-template.svg f760025377f8f89e3b7e9b1703c07fbd *man/figures/progress-1.svg f8e74bd6560da27db0d89036d1626d3e *man/figures/progress-after.svg 901d317546a5b3b94bf28ee39935e55d *man/figures/progress-along-1.svg f449ae9ad17d71f33c2bfb4e9ae48983 *man/figures/progress-along-2.svg 08e3bb15ccf8fde1abbc2727a7739e5d *man/figures/progress-along-3.svg 88f13eca244f1eb182ef028fafe2288d *man/figures/progress-clear.svg b36eb4f1a2fc8f22d55f9380a607a61c *man/figures/progress-current.svg 7f5826300ef1ba2d253f5bc9a1211cb9 *man/figures/progress-format.svg cd2640b2e121b3d38197922db06d18c2 *man/figures/progress-message.svg 2bb2a2910743123c0670b7be2568e3e8 *man/figures/progress-natotal.svg 1003a95e281792562549e4ac6118da3a *man/figures/progress-output.svg e19cc09fc7bd3dd9e6da86b8867db773 *man/figures/progress-output2.svg 5a3b43377c4823fca54b44b18769fe99 *man/figures/progress-step-dynamic.svg 289df71c958c7758bc454af70ca53f0f *man/figures/progress-step-msg.svg 6b058035deee58362c340d48cb07d43c *man/figures/progress-step-spin.svg 6bdd5f1d130daa4fb09acdefd9a0d0a0 *man/figures/progress-step.svg f2e74e2e161402e874a8b7e168fcf250 *man/figures/progress-tasks.svg 94b1378de14a97ce63a1d7c408a293ec *man/format_error.Rd 493347737b52d0121b9f49c352fb2f9e *man/format_inline.Rd 1bc469735d000231392f70b1b5e81250 *man/get_spinner.Rd aca89f2759224a3d3c5a580a8fda8958 *man/has_keypress_support.Rd d5b6c3d69960079834c9c3c4872951f2 *man/hash_animal.Rd c3c14feb6f1eb867bf73c7cd73b65f9f *man/hash_emoji.Rd 821e11198206daf5c61638c53bf59616 *man/hash_md5.Rd 3d703824bdcbe6adcff8182a190547c7 *man/hash_sha1.Rd 0faba9517a54078a1608f9ff38be049a *man/hash_sha256.Rd 42de86a0644cd71433d6c8d7cc945e4f *man/hash_xxhash.Rd ad85631f3a54fff864b707e9a52c0e9d *man/inline-markup.Rd 42d3e3f9e7d0d39e10c984f87c8d4455 *man/is_ansi_tty.Rd a9cc5b0c8cca45d9667781a598b9d196 *man/is_dynamic_tty.Rd db6609161227f964e931096d054ad27d *man/is_utf8_output.Rd 3e08f2605bcbf344f6c13924da6d331b *man/keypress.Rd 68e63b0439397070e8ec67ce063b8a3a *man/links.Rd 5873e187476cb94ea1f54d2899ee892e *man/list_spinners.Rd 186de79eed30dedbab1d56f0393bb279 *man/make_ansi_style.Rd 934728dbc8965cc88e4d9d8ed862aed4 *man/make_spinner.Rd af2aa306413ad76d65eeb0a5e8d0f705 *man/match_selector.Rd 8b59012e34cadc44db3e0b42f4387169 *man/match_selector_node.Rd 1fe828d9565aa6f89d6ae6e81d421fa5 *man/num_ansi_colors.Rd 4a7e9434b649515b41c09d181174bdd5 *man/parse_selector.Rd 644dcb99c2ce692b6838412d3f8386dc *man/pluralization-helpers.Rd a1dd2ea99ff1224540bc2984ba47957e *man/pluralization.Rd 30d263a463982180ea458df213b5b989 *man/pluralize.Rd 2c956b9d2d264febabfb8f6a2a17dbf7 *man/pretty_print_code.Rd 3bf66406895a5ec9edc3e72223874b7a *man/progress-c.Rd c27df66d839e94c9cd1070d15d7a0018 *man/progress-utils.Rd 1c69cc0ac3b1fbff078f848424ab3967 *man/progress-variables.Rd a676d55fc6357874873788384e875a2d *man/roxygen/meta.R 4ae78ceb990a4d5fb5b7275bd8b24ccb *man/rule.Rd 304fe11b14091714031feb005e745821 *man/ruler.Rd 2d368b4704ad48c6b3e82b604b23131a *man/simple_theme.Rd 82dbefc4e8150bd4464df09dbd8fb56d *man/spark_bar.Rd 5ec47aa6007c4b6c8d9ecabff3439b0f *man/spark_line.Rd a1885f5e91610f989cab217160a42ef0 *man/start_app.Rd 7aa6422865101d56aa1acbdb642230ad *man/style_hyperlink.Rd 9f2d24afdb3b55694fdc0cfb4180403a *man/symbol.Rd e85445bd4eee4a65964e9498b04a3705 *man/test_that_cli.Rd 027e82cb63ee9c067dcec2a1d2d622e8 *man/themes.Rd 12b6f6cb6ab0519d2f297cfa8e84f5b7 *man/tree.Rd 30cd9349d566e2c83cde2279e70d3886 *man/unicode-width-workaround.Rd 1bf6714e8b9005b6495cfc690049eaf2 *man/utf8_graphemes.Rd 06cc7204e61f88f01a553fb821c07118 *man/utf8_nchar.Rd af2d6e3e7de13a9ecf27814f6ef5370b *man/utf8_substr.Rd 3dd1973ed96dece02ef6fd2ab7accc8e *man/vt_output.Rd bbfcba42b4f98691a1255dcf5f8f9ddf *src/Makevars 0961a1aea4a66f01da14d7ca99d8f990 *src/ansi.c 0443af0035350eb49d5ad7519e1a7677 *src/charwidth.h 85d497ac098b98f621eb0a16c32c63dc *src/cleancall.c d07e7a5009d72400834256e000215ea0 *src/cleancall.h c28440a99e064039d0ad2de35a022c8f *src/cli.h 157c5c338120623b10e5bfd4054f5ade *src/diff.c 9f1ee6d9b40e7a78246c6b6ffcfdfbc2 *src/errors.c 001ad320075ddf2288694894dabc1354 *src/errors.h 77298488a0bfb3081194813aa4e153ec *src/glue.c 5b122569ab6ec5bf8efc23e0a1bc5363 *src/graphbreak.h 5c1edd655a868df6c76b770b23143f9c *src/init.c 4446689ca675a62bd28cb157e2817d42 *src/inst.c cb591f98d44be3504245df03afbd6323 *src/keypress-unix.c 62612e883a6591cdf5cfe0b4f00ceea6 *src/keypress-win.c 1025b6c9fc136185d08a1315a37d60bc *src/keypress.c e5804e34362d24528a4333564cf1b1d7 *src/keypress.h 1dd9c2665def508c087fc0628c3e1683 *src/md5.c 29f9c450b1c517bc4dea762ee2a8057e *src/md5.h 172e1edd1358d01c8f40fec25a8397a3 *src/progress-altrep.c c58d48238aeaf76f7cbff962eae56636 *src/progress.c b199f82390ba67d54754416c4adc813d *src/sha1.c 4eaa42f5af90351e55841f7b20e8da74 *src/sha256.c 8269c224734188bbb17ab1c97b5a6959 *src/thread.c 649f0ce1652c0565ee6229becd13606a *src/tty.c ec7d59ace939aeaf39549844df6ecd3c *src/utf8.c ac97d171c39388dd326d2fa721e18650 *src/utils.c 3d235e51f41f6927fc9dee7baffb4cf9 *src/vt.c ea170ca3afb3f57ab623c9dd1c34b5de *src/vtparse.c 4277becc460dbda6bb285da55e8a1b21 *src/vtparse.h 6d373947ae7e83e2ed820b36db69f48c *src/vtparse_table.c 655bd7547add5b768e193dbf34a4df13 *src/vtparse_table.h 3831a036c7d7ed391136fd84250c289b *src/win-utf8.c 8496818b99808f581e40d9618b0c82de *src/winfiles.c bdcb51aada6be4f06b441c6e08a2836c *src/winfiles.h 0dc41356fc0ba89d42c05d60c5beaee6 *src/xxhash.c 322119a72933bdb526d797d24ecb6a0e *src/xxhash.h 8949e6b654073597857b5dbe79c379de *src/xxhash2.c 6d90f87e885ca9f532e48e742fa4bc04 *tests/testthat.R e8cec59e39fca820d8fba08d6fa5af96 *tests/testthat/_snaps/alerts.md 094482716c495d87982fd49f3ccdf14b *tests/testthat/_snaps/ansi-html.md 244241392b7a287c167faf2b5adaf283 *tests/testthat/_snaps/ansi-hyperlink.md 927f5ba7f53fb9b12636e281b2588224 *tests/testthat/_snaps/ansi-make.md cccb93b1328336728bb1d62f5ffba27b *tests/testthat/_snaps/ansi-palette.md 17c954eff9ae0d0e25985547fa51c0d8 *tests/testthat/_snaps/ansi-utils.md 145ba333fb209f9e259d40507dc7e340 *tests/testthat/_snaps/ansi.md 3558032f2991dd305b80e7748695f669 *tests/testthat/_snaps/ansiex-2.md e9b94aaebb4bb6ef7a850d9a60ffe58e *tests/testthat/_snaps/ansiex.md 70efde7892895e5c10b195bfd14d7ebd *tests/testthat/_snaps/app.md ceef50134041119fb9805db00c9dd1e9 *tests/testthat/_snaps/box-styles.md d76acacaf48198050fb5d7cad932ea8d *tests/testthat/_snaps/boxes.md 1aea0e19b61c258ca82565aaebaed3a5 *tests/testthat/_snaps/bullets.md 9e40e2581262433f3193ad9faebeb258 *tests/testthat/_snaps/cat-helpers.md 73792b791b7602e70d9e453de342acb0 *tests/testthat/_snaps/code.md c119d272ee5bffa0f59179d01676e604 *tests/testthat/_snaps/collapsing.md af064586bf93c5af7ad9f4cc5864db5b *tests/testthat/_snaps/console-width.md 0cd5c3fd04647cf678cba3a83bf3236f *tests/testthat/_snaps/containers.md 2fa2e4d6fc2a7b3bf22dc7a0cd7f59e6 *tests/testthat/_snaps/deep-lists.md 1821f1e530ff6a0c70eee9ebcdc7534c *tests/testthat/_snaps/defer.md 5a241b84abad50bbf92b18265cb2f332 *tests/testthat/_snaps/diff.md 11f797d339417f3859156cfb15657b2c *tests/testthat/_snaps/format-conditions.md 081a193219bf208963ee6c44db3cc5ed *tests/testthat/_snaps/glue.md c82d4bb588a5c69220531092a4aa8498 *tests/testthat/_snaps/hash.md 2a6ff90d8115e66638c8de7ad47ce5d5 *tests/testthat/_snaps/inline-2.md 8e0bbd568634d9eeee0b50e795dfe430 *tests/testthat/_snaps/inline.md 203e012f92de5049c6bcc8b9a8f5871d *tests/testthat/_snaps/keypress.md 4043089de4ad7ee6e6f06f6f4ff08639 *tests/testthat/_snaps/links.md 9648c977edea46d525dbe057d4963ac7 *tests/testthat/_snaps/lists.md a99c22851f7244367f80fd51e43d5597 *tests/testthat/_snaps/meta.md 1a515b9cea1b237caa639ce86d15d60d *tests/testthat/_snaps/new-r/inline-2.md 65fef925e39b7536e0a9cc0b779c1958 *tests/testthat/_snaps/new/headers.md e89b8c6698e9690b99fb45aa383f5afd *tests/testthat/_snaps/non-breaking-space.md 1b4bb12c9ce65153368e8518f298264d *tests/testthat/_snaps/old-r/inline-2.md 267635917ae348214fb5e2aaf6da38ca *tests/testthat/_snaps/pluralization.md 772a8a7632c2f74a6a214aa6daf225dd *tests/testthat/_snaps/prettycode.md de3d87915d5f57997e941988e5d8ac4c *tests/testthat/_snaps/progress-along.md 73893adc52abb613848dea7f6eb45a88 *tests/testthat/_snaps/progress-bar.md cb4cecf3d9778b123ee3b805bef951de *tests/testthat/_snaps/progress-c.md 66b4ede9fb3c7fd209ffdf424246110a *tests/testthat/_snaps/progress-client.md c5ffd4a57d4b42d416854e615d5d275d *tests/testthat/_snaps/progress-handler-logger.md b5cde8366fbe55f2847aae193088bc6d *tests/testthat/_snaps/progress-message.md a49d6213ddcc9c3038d9b27ee1516b20 *tests/testthat/_snaps/progress-ticking.md 43a383e62fa70c8eed95ee0acc93301a *tests/testthat/_snaps/progress-types.md f6422b6b78c6f175bb1ba8154db48ad9 *tests/testthat/_snaps/progress-variables.md 2d2e4095075090b3ba0a38890b2357c1 *tests/testthat/_snaps/rlang-1.1.0/rlang-errors.md 2d2e4095075090b3ba0a38890b2357c1 *tests/testthat/_snaps/rlang-1.1.4/rlang-errors.md a488c9c459fdf4ba7bc583fcb372d7dd *tests/testthat/_snaps/rlang-errors.md 2b56eff607faa35ae4ad937c40cb1546 *tests/testthat/_snaps/rules.md 7be1ce9ff76491fb01eb09d199bae791 *tests/testthat/_snaps/spark.md c9aec0bc754f9f0f16345c2603b5b6d2 *tests/testthat/_snaps/text.md 70c35d11c1485c6f152399567d01213e *tests/testthat/_snaps/themes.md 3d2fe655fe6f198260cb818cc622d075 *tests/testthat/_snaps/tree.md a296d019dc3da66983d023a39a969a22 *tests/testthat/_snaps/type.md c4128d331b90aa9ca85f90c537d06c27 *tests/testthat/_snaps/utf8.md 37fdf0e661eb86778f8c9295707415a0 *tests/testthat/_snaps/utf8/utf8-output.txt ebd582551f78b805a6acc0ea28969bad *tests/testthat/_snaps/utils.md 9db0f90524e16b9c18fd36d0585c59d0 *tests/testthat/_snaps/verbatim.md dd0a6cc6b1040d1b65dc7e76fb935a76 *tests/testthat/_snaps/vt.md 0d0cf9ec7a089746d1cd383b4e09ee1c *tests/testthat/helper.R eb908eab0a24cdd49c59230f9791f3ef *tests/testthat/progress-1.c 48e6ab53af6b509a082e3eba93ca9c19 *tests/testthat/progress-2.c 6c52b38fcaec1ae2fee8ad605846ff42 *tests/testthat/progresstest/DESCRIPTION 2518492b56a7c0b5623c742c05d4ff21 *tests/testthat/progresstest/NAMESPACE 92f660761358ad7ae192ad2f9739eee9 *tests/testthat/progresstest/R/test.R f0efa1ca8ffc5bbec994ffc083d0d09f *tests/testthat/progresstest/src/cleancall.c 13558bb3112208a0ac9f415b1ef8660b *tests/testthat/progresstest/src/cleancall.h 3a2b34e623fd3ca2596002e49a9c0194 *tests/testthat/progresstest/src/test.c 734cf6f20c35c9fe23eb2a8906012ca4 *tests/testthat/progresstestcpp/DESCRIPTION bef3e566c22a023a089901bb301ce1e6 *tests/testthat/progresstestcpp/NAMESPACE 02bc76b103a369ef11396a5fdadefcef *tests/testthat/progresstestcpp/R/cpp11.R bd70e7dab02792db681e814e8d741735 *tests/testthat/progresstestcpp/R/testcpp.R a87316bb6365e458053c6409d342b0ad *tests/testthat/progresstestcpp/src/cpp11.cpp b280d9669debb2a66a7eb376cdcb2ecc *tests/testthat/progresstestcpp/src/testcpp.cpp dd595f8abc436ae18b37de94c6aead71 *tests/testthat/setup.R f1490e0d8d70ba01c03e0a0092947b03 *tests/testthat/test-alerts.R d0709b0ebdd1d467ed5bf00a54c7dba6 *tests/testthat/test-ansi-combine.R e5e2c73bcf15713d0b845b8cbbee42d1 *tests/testthat/test-ansi-html.R 724564fea4ea14457a190b71c22c44a2 *tests/testthat/test-ansi-hyperlink.R 14c459a067368b756a2bc7ae0478e57b *tests/testthat/test-ansi-make.R d8216f4ed9a723131a00557b38fb9f8b *tests/testthat/test-ansi-palette.R 174d27c7bd38d118df13c42dbf142a31 *tests/testthat/test-ansi-utils.R 04d4470b01cbc65135c89fa3ca18a0e6 *tests/testthat/test-ansi.R cc7b36b2c2b1b1818b6726254e0aabe7 *tests/testthat/test-ansiex-2.R 3f7d99cc3773c7f92d016c7f11d082f5 *tests/testthat/test-ansiex.R 9f015463498ebd8a946bf0167b9fbaa1 *tests/testthat/test-app.R 81bbac0236af9a1f4f1d7676febd7c00 *tests/testthat/test-assertions.R 8d40cbc5200117591d15994f7987fceb *tests/testthat/test-box-styles.R 05a3288515dd857c20eae61c79d85b7d *tests/testthat/test-boxes.R 69a96c34ecf1d465efe5010544465520 *tests/testthat/test-bullets.R c244e69b9696767bb88157d78f5fdb91 *tests/testthat/test-cat-helpers.R 43cea694a210de503bf50ac47c2658bf *tests/testthat/test-cat.R 9f7f258a42ddcae408feb0831ad80600 *tests/testthat/test-cliapp-output.R b55cdba5b931847a10baac7323aee513 *tests/testthat/test-code.R 1a0139736d69e8a7bb377057afa9adab *tests/testthat/test-collapsing.R 637218fd6627baaada8676611bfb026c *tests/testthat/test-console-width.R eee00910f680d2a43b1a6de030897729 *tests/testthat/test-containers.R 4b19b56de860a9a8eebe099b2639a1b1 *tests/testthat/test-css.R a99d724761d870a08f7921d35953d08a *tests/testthat/test-custom-handler.R a083726c76a940f3cc3855115eed8742 *tests/testthat/test-deep-lists.R e01ff4e8473227c2cce9183266ff8ba5 *tests/testthat/test-defer.R 097a9f73d826068950356b05da41ae0b *tests/testthat/test-diff.R 18b53d996109c47ebc1d8bebc4903dd0 *tests/testthat/test-format-conditions.R e09aab533c10e50773924d2b15ea2571 *tests/testthat/test-glue.R dbe415b0ebb9a569f85e490e195b07b4 *tests/testthat/test-hash.R 330e3e7a5ac4b57c70d62c39482e72b3 *tests/testthat/test-headers.R 8c4aa69f7422fab754eff2100072c05e *tests/testthat/test-inline-2.R a9846b52fd720d73d9bec3e4fb0991d4 *tests/testthat/test-inline.R 7fe812d777d939204063c4aee03b4304 *tests/testthat/test-keypress.R 37002d55d0facbfad2c31e4a9213071c *tests/testthat/test-links.R 293c88c7bea1808e28f3a528abd10336 *tests/testthat/test-lists.R 1ff002d5eac823a687c0352b78e13de5 *tests/testthat/test-meta.R 00698022f5e57064ccbe92190ab699f4 *tests/testthat/test-non-breaking-space.R 3ff7bded9a4d17c06af4a36799d0c598 *tests/testthat/test-num-ansi-colors.R f67ce38bb496ffec3a6b42e79d464ad7 *tests/testthat/test-package.R dac311d2660b97b4d9bdf02dfc217d95 *tests/testthat/test-pluralization.R 3f53552b3ec15d0f19a7efda2b3555b8 *tests/testthat/test-prettycode.R 83d3080aa0a78ff478a8bd95b27f649f *tests/testthat/test-progress-along.R ca32cce5ab076174d4780dbca5d1ba23 *tests/testthat/test-progress-bar.R d4ab1fb42e81175eaa3a4b60b0d61891 *tests/testthat/test-progress-c.R 2245b812c27d153f9ed05c1a1615a49f *tests/testthat/test-progress-client.R 6b07f646d609e57a2793b3219c9c12a8 *tests/testthat/test-progress-handler-logger.R 018a20b71002bdde23d3c63ef09c03e4 *tests/testthat/test-progress-handler-say.R b06231cb90a6f5749aef418aed5bd583 *tests/testthat/test-progress-handlers.R 67b1583cb4eb9277bdd69579de0ea9f2 *tests/testthat/test-progress-message.R d024e0a698f86970ad998d8236429e8b *tests/testthat/test-progress-ticking.R 32d090bf07a019dbe0d17e18c96c96f8 *tests/testthat/test-progress-types.R 4202b6fd7657ae051b0d0b902a75faf9 *tests/testthat/test-progress-utils.R 82bd0f2ddd97aedf2eed791e6961ce87 *tests/testthat/test-progress-variables.R a5d306c80076434678ec39c944432aa4 *tests/testthat/test-rlang-errors.R e56ec94c878f9ce6b6ee5fe771033832 *tests/testthat/test-rules.R 037ecf8db1a9d0cc8077b192883151c1 *tests/testthat/test-sitrep.R a6b6be95920356bb6566e5a2a58e679c *tests/testthat/test-spark.R 8ab08942dfb9b53c9b390a1c2f5e8a22 *tests/testthat/test-spinners.R 2e8b9e68ea02fdb333c8c43a83edb296 *tests/testthat/test-status-bar.R 1f0959408fb5034dbb9d8f61c0d0f477 *tests/testthat/test-subprocess.R 68bbc9e2c5c4c3d82e1737129d49a46e *tests/testthat/test-substitution.R 8e104eea7455e251633e41c600bf05c1 *tests/testthat/test-suppress.R fc889f8cb06b02a49b6ec4fe0970f818 *tests/testthat/test-text.R 215bf5ca5e59b77a44ab7a9af2895e77 *tests/testthat/test-themes.R 194f344b5bce58d05d6fbfa12f73efec *tests/testthat/test-timer.R 8e6658fead82151cc0eff994f249e6f6 *tests/testthat/test-tree.R 23ce2e3045ea453e804fa54a80acd2f0 *tests/testthat/test-type.R 310581e17c9b9e246d239d37e0d70c60 *tests/testthat/test-utf8.R 2ca25fda4639e0611c1c0a7358e12fca *tests/testthat/test-utils.R 49cb0a3b078068cc8771e6c1690edc46 *tests/testthat/test-verbatim.R ccb18e8d5ca8ae6d10f23eefa7e267ef *tests/testthat/test-vt.R a9d484b6e7e5f9e472f0449a0b8f000f *tools/ansi-iterm-palettes.txt 211e6b484b96b9108bb28c2b376c9a54 *tools/ansi-palettes.txt dc0faff9b19aa33b1b4011671c9b86ca *tools/dark.itermcolors 8b6b60f2ffd808e750a60b15bb560fee *tools/get-rstudio-themes.R cd1762365cd3d845211ebbfa73257ffe *tools/light.itermcolors 22f655751179d105d91e775e4f3ebb43 *tools/parse-iterm.R 8ccf6089ae485e075a586edfb20fde54 *tools/pastel.itermcolors 40e77f073d866f05eb4a794d32742283 *tools/smoooooth.itermcolors 06c031bbf79680952dd99ab546e391a0 *tools/snazzy.itermcolors bc67cdfe4b3ac499dddbf749c1a4ea6a *tools/sol-dark.itermcolors f6fb9e2795a8845dd4937016a6d2a769 *tools/sol-light.itermcolors 1e556f9691a2417a29e18eac6d1e9049 *tools/spinners.R 220365a1c26d9bd2759a0a67b0fb8e33 *tools/tango-dark.itermcolors 4f01dbbbc77d1b33a92fcbae99ea4f6c *tools/tango-light.itermcolors a80c1f97e0e100545c1a240ceff0ed97 *tools/unicode.R cli/R/0000755000176200001440000000000014752735214011234 5ustar liggesuserscli/R/format.R0000644000176200001440000000634014557444176012661 0ustar liggesusers #' Format a value for printing #' #' This function can be used directly, or via the `{.val ...}` inline #' style. `{.val {expr}}` calls `cli_format()` automatically on the value #' of `expr`, before styling and collapsing it. #' #' ## Default style #' #' ```{asciicast cli-format-default} #' months <- month.name[1:3] #' cli_text("{.val {months}}") #' ``` #' #' ```{asciicast cli-format-num} #' nums <- 1:5 / 7 #' cli_text("{.val {nums}}") #' ``` #' #' ## Styling with themes #' #' ```{asciicast cli-format-theme} #' nums <- 1:5 / 7 #' divid <- cli_div(theme = list(.val = list(digits = 3))) #' cli_text("{.val {nums}}") #' cli_end(divid) #' ``` #' #' It is possible to define new S3 methods for `cli_format` and then #' these will be used automatically for `{.val ...}` expressions. #' #' ```{asciicast cli-format-class} #' cli_format.month <- function(x, style = NULL, ...) { #' x <- encodeString(substr(x, 1, 3), quote = "\"") #' NextMethod("cli_format") #' } #' registerS3method("cli_format", "month", cli_format.month) #' months <- structure(month.name[1:3], class = "month") #' cli_text("{.val {months}}") #' ``` #' #' @param x The object to format. #' @param style List of formatting options, see the individual methods #' for the style options they support. #' @param ... Additional arguments for methods. #' #' @export #' @seealso [cli_vec()] cli_format <- function(x, style = NULL, ...) { if (is.null(style) && !is.null(default_app())) { style <- default_app()$get_current_style() cli_format(x, style, ...) } else { UseMethod("cli_format") } } #' @rdname cli_format #' @export cli_format.default <- function(x, style = NULL, ...) { x } #' * Styles for character vectors: #' - `string-quote` is the quoting character for [encodeString()]. #' #' @rdname cli_format #' @export cli_format.character <- function(x, style = NULL, ...) { quote <- style$`string-quote` %||% style$string_quote %||% "\"" encodeString(x, quote = quote) } #' * Styles for numeric vectors: #' - `digits` is the number of digits to print after the decimal point. #' #' @rdname cli_format #' @export cli_format.numeric <- function(x, style = NULL, ...) { digits <- style$digits if (!is.null(digits)) x <- round(x, digits) x } #' Add custom cli style to a vector #' #' @details #' You can use this function to change the default parameters of #' collapsing the vector into a string, see an example below. #' #' The style is added as an attribute, so operations that remove #' attributes will remove the style as well. #' #' ## Custom collapsing separator #' #' ```{asciicast cli-vec} #' v <- cli_vec( #' c("foo", "bar", "foobar"), #' style = list("vec-sep" = " & ", "vec-last" = " & ") #' ) #' cli_text("My list: {v}.") #' ``` #' #' ## Custom truncation #' #' ```{asciicast cli-vec-2} #' x <- cli_vec(names(mtcars), list("vec-trunc" = 3)) #' cli_text("Column names: {x}.") #' ``` #' #' @param x Vector that will be collapsed by cli. #' @param style Style to apply to the vector. It is used as a theme on #' a `span` element that is created for the vector. You can set `vec-sep` #' and `vec-last` to modify the separator and the last separator. #' #' @export #' @seealso [cli_format()] cli_vec <- function(x, style = list()) { attr(x, "cli_style") <- style x } cli/R/ansi-palette.R0000644000176200001440000001511714557444176013761 0ustar liggesusers get_palette_color <- function(style, colors = num_ansi_colors()) { opt <- getOption("cli.palette") if (is.null(opt) || colors < 256) return(style) cache_palette_color(opt, style$palette, colors) } palette_cache <- new.env(parent = emptyenv()) cache_palette_color <- function(pal, idx, colors = num_ansi_colors()) { if (is_string(pal)) { if (! pal %in% rownames(ansi_palettes)) { opt <- options(cli.palette = NULL) defer(options(opt)) throw(cli_error( "Cannot find cli ANSI palette {.val {pal}}", "i" = "Know palettes are {.val {rownames(cli::ansi_palettes)}}.", "i" = "Maybe the {.code cli.palette} option is incorrect?" )) } pal <- ansi_palettes[pal, ] } bg <- idx < 0 idx <- abs(idx) col <- pal[[idx]] colkey <- as.character(colors) key <- paste0(col, bg) if (key %in% names(palette_cache[[colkey]])) { return(palette_cache[[colkey]][[key]]) } val <- ansi_style_from_r_color( col, bg = bg, colors, grey = FALSE ) if (is.null(palette_cache[[colkey]])) { palette_cache[[colkey]] <- new.env(parent = emptyenv()) } palette_cache[[colkey]][[key]] <- val return(val) } #' @details #' `truecolor` is an integer constant for the number of 24 bit ANSI colors. #' #' @format `truecolor` is an integer scalar. #' #' @export #' @rdname ansi_palettes truecolor <- as.integer(256 ^ 3) #' ANSI colors palettes #' #' If your platform supports at least 256 colors, then you can configure #' the colors that cli uses for the eight base and the eight bright colors. #' (I.e. the colors of [col_black()], [col_red()], and [col_br_black()], #' [col_br_red()], etc. #' #' To customize the default palette, set the `cli.palette` option to the #' name of a built-in palette (see `ansi_palettes()`), or the list of #' 16 colors. Colors can be specified with RGB colors strings: #' `#rrggbb` or R color names (see the output of [grDevices::colors()]). #' #' For example, you can put this in your R profile: #' ```r #' options(cli.palette = "vscode") #' ``` #' #' It is currently not possible to configure the background colors #' separately, these will be always the same as the foreground colors. #' #' If your platform only has 256 colors, then the colors specified in the #' palette have to be interpolated. On true color platforms they RGB #' values are used as-is. #' #' `ansi_palettes` is a data frame of the built-in palettes, each row #' is one palette. #' #' `ansi_palette_show()` shows the colors of an ANSI palette on the screen. #' #' @format `ansi_palettes` is a data frame with one row for each palette, #' and one column for each base ANSI color. `attr(ansi_palettes, "info")` #' contains a list with information about each palette. #' #' @export #' @examples #' ansi_palettes #' ansi_palette_show("dichro", colors = truecolor) ansi_palettes <- rbind( utils::read.table( "tools/ansi-palettes.txt", comment.char = ";", stringsAsFactors = FALSE ), utils::read.table( "tools/ansi-iterm-palettes.txt", comment.char = ";", stringsAsFactors = FALSE ) ) attr(ansi_palettes, "info") <- list( dichro = paste( "Colorblind friendly palette, from", "https://github.com/romainl/vim-dichromatic#dichromatic." ), vga = paste( "Typical colors that are used when booting PCs and leaving them in", "text mode, which used a 16-entry color table. The colors are", "different in the EGA/VGA graphic modes.", "From https://en.wikipedia.org/wiki/ANSI_escape_code#SGR." ), winxp = paste( "Windows XP Console. Seen in Windows XP through Windows 8.1.", "From https://en.wikipedia.org/wiki/ANSI_escape_code#SGR." ), vscode = paste( "Visual Studio Debug console, 'Dark+' theme.", "From https://en.wikipedia.org/wiki/ANSI_escape_code#SGR." ), win10 = paste0( "Campbell theme, used as of Windows 10 version 1709. Also used", "by PowerShell 6.", "From https://en.wikipedia.org/wiki/ANSI_escape_code#SGR." ), macos = paste0( "Terminal.app in macOS", "From https://en.wikipedia.org/wiki/ANSI_escape_code#SGR." ), putty = paste0( "From https://en.wikipedia.org/wiki/ANSI_escape_code#SGR." ), mirc = paste0( "From https://en.wikipedia.org/wiki/ANSI_escape_code#SGR." ), xterm = paste0( "From https://en.wikipedia.org/wiki/ANSI_escape_code#SGR." ), ubuntu = paste0( "For virtual terminals, from /etc/vtrgb.", "From https://en.wikipedia.org/wiki/ANSI_escape_code#SGR." ), eclipse = paste0( "From https://en.wikipedia.org/wiki/ANSI_escape_code#SGR." ), iterm = "Built-in iTerm2 theme.", "iterm-pastel" = "Built-In iTerm2 theme.", "iterm-smoooooth" = "Built-In iTerm2 theme.", "iterm-snazzy" = "From https://github.com/sindresorhus/iterm2-snazzy.", "iterm-solarized" = "Built-In iTerm2 theme.", "iterm-tango" = "Built-In iTerm2 theme." ) #' @param palette The palette to show, in the same format as for the #' `cli.palette` option, so it can be the name of a built-in palette, #' of a list of 16 colors. #' @param colors Number of ANSI colors to use the show the palette. If the #' platform does not have sufficient support, the output might have #' a lower color resolution. Without color support it will have no color #' at all. #' @param rows The number of colored rows to print. #' @return `ansi_palette_show` returns a character vector, the rows that #' are printed to the screen, invisibly. #' #' @export #' @rdname ansi_palettes ansi_palette_show <- function(palette = NULL, colors = num_ansi_colors(), rows = 4) { opts <- options( cli.palette = palette %||% getOption("cli.palette"), cli.num_colors = colors ) on.exit(options(opts), add = TRUE) blk <- strrep(symbol$lower_block_8, 4) blks <- c( "blck" = col_black(blk), "red " = col_red(blk), "grn " = col_green(blk), "yllw" = col_yellow(blk), "blue" = col_blue(blk), "mgnt" = col_magenta(blk), "cyan" = col_cyan(blk), "whte" = col_white(blk), "blck" = col_br_black(blk), "red " = col_br_red(blk), "grn " = col_br_green(blk), "yllw" = col_br_yellow(blk), "blue" = col_br_blue(blk), "mgnt" = col_br_magenta(blk), "cyan" = col_br_cyan(blk), "whte" = col_br_white(blk) ) join <- function(x) { paste0( paste(x[1:8], collapse = " "), " ", paste(x[9:16], collapse = " ") ) } nms <- join(names(blks)) str <- join(blks) out <- c( paste(strrep(" ", 52), "bright variants"), nms, "", rep(str, rows) ) cat_line(out) invisible(out) } cli/R/sitrep.R0000644000176200001440000000300514557444176012672 0ustar liggesusers #' cli situation report #' #' Contains currently: #' * `cli_unicode_option`: whether the `cli.unicode` option is set and its #' value. See [is_utf8_output()]. #' * `symbol_charset`: the selected character set for [symbol], UTF-8, #' Windows, or ASCII. #' * `console_utf8`: whether the console supports UTF-8. See #' [base::l10n_info()]. #' * `latex_active`: whether we are inside knitr, creating a LaTeX #' document. #' * `num_colors`: number of ANSI colors. See [num_ansi_colors()]. #' * `console_with`: detected console width. #' #' @return Named list with entries listed above. It has a `cli_sitrep` #' class, with a `print()` and `format()` method. #' #' @export #' @examples #' cli_sitrep() cli_sitrep <- function() { structure( list( cli_unicode_option = getOption("cli.unicode", NULL), symbol_charset = get_active_symbol_set(), console_utf8 = l10n_info()$`UTF-8`, latex_active = is_latex_output(), num_colors = num_ansi_colors(), console_width = console_width()), class = "cli_sitrep") } #' @export print.cli_sitrep <- function(x, ...) { cat(format(x, ...), sep = "\n") invisible(x) } get_active_symbol_set <- function() { if (identical(symbol, symbol_utf8)) { "UTF-8" } else { "ASCII (non UTF-8)" } } #' @export format.cli_sitrep <- function(x, ...) { fmt_names <- format(names(x)) fmt_vals <- vapply(x, format, character(1)) paste0("- ", fmt_names, " : ", fmt_vals) } #' @export as.character.cli_sitrep <- function(x, ...) { "" } cli/R/box-styles.R0000644000176200001440000000336214557444176013503 0ustar liggesusers box_styles <- function() { styles <- list( single = list( top_left = "\u250c", top_right = "\u2510", bottom_right = "\u2518", bottom_left = "\u2514", vertical = "\u2502", horizontal = "\u2500" ), double = list( top_left = "\u2554", top_right = "\u2557", bottom_right = "\u255d", bottom_left = "\u255a", vertical = "\u2551", horizontal = "\u2550" ), round= list( top_left = "\u256d", top_right = "\u256e", bottom_right = "\u256f", bottom_left = "\u2570", vertical = "\u2502", horizontal = "\u2500" ), "single-double" = list( top_left = "\u2553", top_right = "\u2556", bottom_right = "\u255c", bottom_left = "\u2559", vertical = "\u2551", horizontal = "\u2500" ), "double-single" = list( top_left = "\u2552", top_right = "\u2555", bottom_right = "\u255b", bottom_left = "\u2558", vertical = "\u2502", horizontal = "\u2550" ), classic = list( top_left = "+", top_right = "+", bottom_right = "+", bottom_left = "+", vertical = "|", horizontal = "-" ), none = list( top_left = " ", top_right = " ", bottom_right = " ", bottom_left = " ", vertical = " ", horizontal = " " ) ) ## If the platform is not UTF-8, then we replace the styles that have ## Unicode characters, with the classic style. if (!is_utf8_output()) { for (n in setdiff(names(styles), c("classic", "none"))) { styles[[n]] <- styles[["classic"]] } } do.call(rbind, styles) } #' @export #' @rdname boxx list_border_styles <- function() { rownames(box_styles()) } cli/R/ansi.R0000644000176200001440000003067414557444176012332 0ustar liggesusers # this is install time # nocov start palette_idx <- function(id) { ifelse( id < 38, id - (30 - 1), ifelse( id < 48, -(id - (40 - 1)), ifelse( id < 98, id - (90 - 9), -(id - (100 - 9)) ))) } palette_color <- function(x) { c(x, palette = palette_idx(x[[1]])) } ansi_builtin_styles <- list( reset = list(0, c(0, 22, 23, 24, 27, 28, 29, 39, 49)), bold = list(1, 22), # 21 isn't widely supported and 22 does the same thing blurred = list(2, 22), italic = list(3, 23), underline = list(4, 24), inverse = list(7, 27), hidden = list(8, 28), strikethrough = list(9, 29), black = palette_color(list(30, 39)), red = palette_color(list(31, 39)), green = palette_color(list(32, 39)), yellow = palette_color(list(33, 39)), blue = palette_color(list(34, 39)), magenta = palette_color(list(35, 39)), cyan = palette_color(list(36, 39)), white = palette_color(list(37, 39)), silver = list(90, 39), br_black = palette_color(list(90, 39)), br_red = palette_color(list(91, 39)), br_green = palette_color(list(92, 39)), br_yellow = palette_color(list(93, 39)), br_blue = palette_color(list(94, 39)), br_magenta = palette_color(list(95, 39)), br_cyan = palette_color(list(96, 39)), br_white = palette_color(list(97, 39)), bg_black = palette_color(list(40, 49)), bg_red = palette_color(list(41, 49)), bg_green = palette_color(list(42, 49)), bg_yellow = palette_color(list(43, 49)), bg_blue = palette_color(list(44, 49)), bg_magenta = palette_color(list(45, 49)), bg_cyan = palette_color(list(46, 49)), bg_white = palette_color(list(47, 49)), bg_br_black = palette_color(list(100, 49)), bg_br_red = palette_color(list(101, 49)), bg_br_green = palette_color(list(102, 49)), bg_br_yellow = palette_color(list(103, 49)), bg_br_blue = palette_color(list(104, 49)), bg_br_magenta = palette_color(list(105, 49)), bg_br_cyan = palette_color(list(106, 49)), bg_br_white = palette_color(list(107, 49)), # similar to reset, but only for a single property no_bold = list(c(0, 23, 24, 27, 28, 29, 39, 49), 22), no_blurred = list(c(0, 23, 24, 27, 28, 29, 39, 49), 22), no_italic = list(c(0, 22, 24, 27, 28, 29, 39, 49), 23), no_underline = list(c(0, 22, 23, 27, 28, 29, 39, 49), 24), no_inverse = list(c(0, 22, 23, 24, 28, 29, 39, 49), 27), no_hidden = list(c(0, 22, 23, 24, 27, 29, 39, 49), 28), no_strikethrough = list(c(0, 22, 23, 24, 27, 28, 39, 49), 29), none = list(c(0, 22, 23, 24, 27, 28, 29, 49), 39), no_color = list(c(0, 22, 23, 24, 27, 28, 29, 49), 39), bg_none = list(c(0, 22, 23, 24, 27, 28, 29, 39 ), 49), no_bg_color = list(c(0, 22, 23, 24, 27, 28, 29, 39 ), 49) ) # nocov end is_builtin_style <- function(x) { is_string(x) && x %in% names(ansi_builtin_styles) } ansi_fg_r <- c( "black" = "black", "red" = "red", "green" = "green", "yellow" = "yellow", "blue" = "blue", "magenta" = "magenta", "cyan" = "cyan", "white" = "white", "silver" = "grey" ) ansi_fg_rgb <- grDevices::col2rgb(ansi_fg_r) ansi_bg_r <- c( "bg_black" = "black", "bg_red" = "red", "bg_green" = "green", "bg_yellow" = "yellow", "bg_blue" = "blue", "bg_magenta" = "magenta", "bg_cyan" = "cyan", "bg_white" = "white" ) ansi_bg_rgb <- grDevices::col2rgb(ansi_bg_r) ansi_style_str <- function(x) { paste0("\u001b[", x, "m", collapse = "") } create_ansi_style_tag <- function(name, open, close, palette = NULL) { structure( list(list(open = open, close = close, palette = palette)), names = name ) } create_ansi_style_fun <- function(styles) { fun <- eval(substitute(function(...) { txt <- paste0(...) nc <- num_ansi_colors() if (nc > 1 && length(txt) > 0) { mystyles <- .styles for (st in rev(mystyles)) { if (!is.null(st$palette)) st <- get_palette_color(st, nc) txt <- paste0( st$open, gsub(st$close, st$open, txt, fixed = TRUE), st$close ) } } class(txt) <- c("cli_ansi_string", "ansi_string", "character") txt }, list(.styles = styles))) class(fun) <- c("cli_ansi_style", "ansi_style") attr(fun, "_styles") <- styles fun } create_ansi_style <- function(name, open = NULL, close = NULL) { open <- open %||% ansi_style_str(ansi_builtin_styles[[name]][[1]]) close <- close %||% ansi_style_str(ansi_builtin_styles[[name]][[2]]) palette <- ansi_builtin_styles[[name]]$palette style <- create_ansi_style_tag(name, open, close, palette) create_ansi_style_fun(style) } #' @export print.cli_ansi_string <- function(x, ...) { cat("\n") if (length(x)) { cat(format(paste0("[", seq_along(x), "] ", format(x))), sep = "\n") } invisible(x) } #' @export print.cli_ansi_style <- function(x, ...) { cat("\n") cat(x("Example output")) cat("\n") invisible(x) } #' Create a new ANSI style #' #' Create a function that can be used to add ANSI styles to text. #' #' @param ... The style to create. See details and examples below. #' @param bg Whether the color applies to the background. #' @param grey Whether to specifically create a grey color. #' This flag is included, because ANSI 256 has a finer color scale #' for greys, then the usual 0:5 scale for red, green and blue components. #' It is only used for RGB color specifications (either numerically #' or via a hexadecimal string), and it is ignored on eight color ANSI #' terminals. #' @param colors Number of colors, detected automatically #' by default. #' @return A function that can be used to color (style) strings. #' #' @details #' The `...` style argument can be any of the following: #' * A cli ANSI style function of class `cli_ansi_style`. This is returned #' as is, without looking at the other arguments. #' * An R color name, see [grDevices::colors()]. #' * A 6- or 8-digit hexadecimal color string, e.g. `#ff0000` means #' red. Transparency (alpha channel) values are ignored. #' * A one-column matrix with three rows for the red, green #' and blue channels, as returned by [grDevices::col2rgb()]. #' #' `make_ansi_style()` detects the number of colors to use #' automatically (this can be overridden using the `colors` #' argument). If the number of colors is less than 256 (detected or given), #' then it falls back to the color in the ANSI eight color mode that #' is closest to the specified (RGB or R) color. #' #' #' @family ANSI styling #' @export #' @examples #' make_ansi_style("orange") #' make_ansi_style("#123456") #' make_ansi_style("orange", bg = TRUE) #' #' orange <- make_ansi_style("orange") #' orange("foobar") #' cat(orange("foobar")) make_ansi_style <- function(..., bg = FALSE, grey = FALSE, colors = num_ansi_colors()) { style <- list(...)[[1]] if (inherits(style, "cli_ansi_style")) return(style) if (inherits(style, "crayon")) { return(create_ansi_style_fun(attr(style, "_styles"))) } if (identical(style, "dim")) style <- "blurred" orig_style_name <- style_name <- names(args)[1] stop_if_not( is.character(style) && length(style) == 1 || is_rgb_matrix(style) && ncol(style) == 1, message = c( "{.arg style} must be an ANSI style", "i" = paste( "an ANSI style is a character scalar (cli style name, RGB or R color", "name), or a [3x1] or [4x1] numeric RGB matrix"), "i" = "{.arg style} is {.type {style}}" ) ) stopifnot( is.logical(bg) && length(bg) == 1, is.numeric(colors) && length(colors) == 1 ) ansi_seqs <- if (is_builtin_style(style)) { if (bg && substr(style, 1, 3) != "bg_") { style <- paste0("bg_", style) } if (is.null(style_name)) style_name <- style ansi_builtin_styles[[style]] } else if (is_r_color(style)) { if (is.null(style_name)) style_name <- style ansi_style_from_r_color(style, bg, colors, grey) } else if (is_rgb_matrix(style)) { if (is.null(style_name)) { style_name <- paste0( c("rgb", style, if (bg) "-bg", if (grey) "-grey"), collapse = "-" ) } ansi_style_from_rgb(style, bg, colors, grey) } else { throw(cli_error( "Unknown style specification: {.val style}, it must be one of", "*" = "a builtin cli style, e.g. {.val bold} or {.val red},", "*" = "an R color name, see {.help grDevices::colors}.", "*" = "a [3x1] or [4x1] numeric RGB matrix with, range 0-255." )) } create_ansi_style(style_name, ansi_seqs$open, ansi_seqs$close) } hash_color_regex <- "^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{8})$" is_r_color <- function(x) { if (!is.character(x) || length(x) != 1 || is.na(x)) { FALSE } else { x %in% grDevices::colors() || grepl(hash_color_regex, x) } } is_rgb_matrix <- function(x) { is.matrix(x) && is.numeric(x) && (nrow(x) == 3 || nrow(x) == 4) } ansi_style_from_r_color <- function(color, bg, num_colors, grey) { ansi_style_from_rgb(grDevices::col2rgb(color), bg, num_colors, grey) } ansi_style_8_from_rgb <- function(rgb, bg) { ansi_cols <- if (bg) ansi_bg_rgb else ansi_fg_rgb dist <- colSums((ansi_cols - as.vector(rgb)) ^ 2 ) builtin_name <- names(which.min(dist))[1] btn <- ansi_builtin_styles[[builtin_name]] list(open = ansi_style_str(btn[[1]]), close = ansi_style_str(btn[[2]])) } ansi_style_from_rgb <- function(rgb, bg, num_colors, grey) { if (num_colors < 256) { return(ansi_style_8_from_rgb(rgb, bg)) } if (num_colors < truecolor || grey) return(ansi256(rgb, bg, grey)) return(ansitrue(rgb, bg)) } # nocov start fgcodes <- c(paste0('\x1b[38;5;', 0:255, 'm'), '\x1b[39m') bgcodes <- c(paste0('\x1b[48;5;', 0:255, 'm'), '\x1b[49m') rgb_index <- 17:232 gray_index <- 233:256 reset_index <- 257 # nocov end ansi_scale <- function(x, from = c(0, 255), to = c(0, 5), round = TRUE) { y <- (x - from[1]) / (from[2] - from[1]) * (to[2] - to[1]) + to[1] if (round) { round(y) } else { y } } ansi256 <- function(rgb, bg = FALSE, grey = FALSE) { codes <- if (bg) bgcodes else fgcodes if (grey) { ## Gray list( open = codes[gray_index][ansi_scale(rgb[1], to = c(0, 23)) + 1], close = codes[reset_index] ) } else { ## Not gray list( open = codes[ansi256_rgb_index(rgb[1L], rgb[2L], rgb[3L])], close = codes[reset_index] ) } } ## This is based off the algorithm in the ruby "paint" gem, as ## implemented in rainbowrite. ansi256_rgb_index <- function(red, green, blue) { gray_possible <- TRUE sep <- 42.5 while (gray_possible) { if (red < sep || green < sep || blue < sep) { gray <- red < sep && green < sep && blue < sep gray_possible <- FALSE } sep <- sep + 42.5 } ## NOTE: The +1 here translates from base0 to base1 for the index ## that does the same. Not ideal, but that does get the escape ## characters in nicely. if (gray) { 232 + round((red + green + blue) / 33) + 1 } else { 16 + sum(floor(6 * c(red, green, blue) / 256) * c(36, 6, 1)) + 1 } } ansitrue <- function(rgb, bg = FALSE) { if (bg) { list( open = paste0("\x1b[48;2;", rgb[1], ";", rgb[2], ";", rgb[3], "m"), close = "\x1b[49m" ) } else { list( open = paste0("\x1b[38;2;", rgb[1], ";", rgb[2], ";", rgb[3], "m"), close = "\x1b[39m" ) } } #' Combine two or more ANSI styles #' #' Combine two or more styles or style functions into a new style function #' that can be called on strings to style them. #' #' It does not usually make sense to combine two foreground #' colors (or two background colors), because only the first one #' applied will be used. #' #' It does make sense to combine different kind of styles, #' e.g. background color, foreground color, bold font. #' #' @param ... The styles to combine. For character strings, the #' [make_ansi_style()] function is used to create a style first. #' They will be applied from right to left. #' @return The combined style function. #' #' @family ANSI styling #' @export #' @examples #' ## Use style names #' alert <- combine_ansi_styles("bold", "red4") #' cat(alert("Warning!"), "\n") #' #' ## Or style functions #' alert <- combine_ansi_styles(style_bold, col_red, bg_cyan) #' cat(alert("Warning!"), "\n") #' #' ## Combine a composite style #' alert <- combine_ansi_styles( #' "bold", #' combine_ansi_styles("red", bg_cyan)) #' cat(alert("Warning!"), "\n") combine_ansi_styles <- function(...) { styles <- lapply( list(...), function(x) attr(make_ansi_style(x), "_styles") ) styles <- unlist(styles, recursive = FALSE) create_ansi_style_fun(styles) } cli/R/boxes.R0000644000176200001440000001460114557444176012510 0ustar liggesusers #' Draw a banner-like box in the console #' #' @details #' #' ## Defaults #' #' ```{asciicast box-default} #' boxx("Hello there!") #' ``` #' #' ## Change border style #' #' ```{asciicast box-border} #' boxx("Hello there!", border_style = "double") #' ``` #' #' ## Multiple lines #' #' ```{asciicast box-lines} #' boxx(c("Hello", "there!"), padding = 1) #' ``` #' #' ## Padding #' #' ```{asciicast box-padding} #' boxx("Hello there!", padding = 1) #' boxx("Hello there!", padding = c(1, 5, 1, 5)) #' ``` #' #' ## Floating #' #' ```{asciicast box-float} #' boxx("Hello there!", padding = 1, float = "center") #' boxx("Hello there!", padding = 1, float = "right") #' ``` #' #' ## Text color #' #' ```{asciicast box-text-color} #' boxx(col_cyan("Hello there!"), padding = 1, float = "center") #' ``` #' #' ## Background color #' #' ```{asciicast box-bg-color} #' boxx("Hello there!", padding = 1, background_col = "brown") #' boxx("Hello there!", padding = 1, background_col = bg_red) #' ``` #' #' ## Border color #' #' ```{asciicast box-border-color} #' boxx("Hello there!", padding = 1, border_col = "green") #' boxx("Hello there!", padding = 1, border_col = col_red) #' ``` #' #' ## Label alignment #' #' ```{asciicast box-label-align} #' boxx(c("Hi", "there", "you!"), padding = 1, align = "left") #' boxx(c("Hi", "there", "you!"), padding = 1, align = "center") #' boxx(c("Hi", "there", "you!"), padding = 1, align = "right") #' ``` #' #' ## A very customized box #' #' ```{asciicast box-custom} #' star <- symbol$star #' label <- c(paste(star, "Hello", star), " there!") #' boxx( #' col_white(label), #' border_style="round", #' padding = 1, #' float = "center", #' border_col = "tomato3", #' background_col="darkolivegreen" #' ) #' ``` #' #' @param label Label to show, a character vector. Each element will be #' in a new line. You can color it using the `col_*`, `bg_*` and #' `style_*` functions, see [ANSI styles][ansi-styles] and the examples #' below. #' @param header Text to show on top border of the box. If too long, #' it will be cut. #' @param footer Text to show on the bottom border of the box. If too long, #' it will be cut. #' @param border_style String that specifies the border style. #' `list_border_styles` lists all current styles. #' @param padding Padding within the box. Either an integer vector of #' four numbers (bottom, left, top, right), or a single number `x`, which #' is interpreted as `c(x, 3*x, x, 3*x)`. #' @param margin Margin around the box. Either an integer vector of four #' numbers (bottom, left, top, right), or a single number `x`, which is #' interpreted as `c(x, 3*x, x, 3*x)`. #' @param float Whether to display the box on the `"left"`, `"center"`, or #' the `"right"` of the screen. #' @param background_col Background color of the inside of the box. #' Either a style function (see [ANSI styles][ansi-styles]), or a color #' name which will be used in [make_ansi_style()] to create a #' *background* style (i.e. `bg = TRUE` is used). #' @param col Color of text, and default border color. Either a style #' function (see [ANSI styles][ansi-styles]) or a color name that is #' passed to [make_ansi_style()]. #' @param border_col Color of the border. Either a style function #' (see [ANSI styles][ansi-styles]) or a color name that is passed to #' [make_ansi_style()]. #' @param align Alignment of the label within the box: `"left"`, #' `"center"`, or `"right"`. #' @param width Width of the screen, defaults to [console_width()]. #' #' @section About fonts and terminal settings: #' The boxes might or might not look great in your terminal, depending #' on the box style you use and the font the terminal uses. We found that #' the Menlo font looks nice in most terminals an also in Emacs. #' #' RStudio currently has a line height greater than one for console output, #' which makes the boxes ugly. #' #' @export boxx <- function(label, header = "", footer = "", border_style = "single", padding = 1, margin = 0, float = c("left", "center", "right"), col = NULL, background_col = NULL, border_col = col, align = c("left", "center", "right"), width = console_width()) { label <- apply_style(as.character(label), col) widest <- max(ansi_nchar(label, "width"), 0) stopifnot( is_border_style(border_style), is_padding_or_margin(padding), is_padding_or_margin(margin) ) float <- match.arg(float) align <- match.arg(align) if (length(padding) == 1) { padding <- c(padding, padding * 3, padding, padding * 3) } if (length(margin) == 1) { margin <- c(margin, margin * 3, margin, margin * 3) } label <- ansi_align(label, align = align, width = widest) content_width <- widest + padding[2] + padding[4] mar_left <- if (float == "center") { make_space((width - content_width) / 2) } else if (float == "right") { make_space(max(width - content_width - 2, 0)) } else { make_space(margin[2]) } color_border <- function(x) apply_style(x, border_col) color_content <- function(x) apply_style(x, background_col, bg = TRUE) label <- c(rep("", padding[3]), label, rep("", padding[1])) chars <- box_styles()[border_style, ] pad_left <- make_space(padding[2]) pad_right <- make_space( content_width - ansi_nchar(label, "width") - padding[2] ) if (header != "") { header <- paste0(" ", ansi_strtrim(header, content_width - 2), " ") } hdw <- ansi_nchar(header, "width") if (footer != "") { footer <- paste0(" ", ansi_strtrim(footer, content_width - 2), " ") } ftw <- ansi_nchar(footer, "width") hdline <- paste0(header, strrep(chars$horizontal, content_width - hdw)) top <- color_border(paste0( strrep("\n", margin[3]), mar_left, chars$top_left, hdline, chars$top_right )) ftline <- paste0(strrep(chars$horizontal, content_width - ftw), footer) bottom <- color_border(paste0( mar_left, chars$bottom_left, ftline, chars$bottom_right, strrep("\n", margin[1]) )) side <- color_border(chars$vertical) middle <- paste0(mar_left, side, color_content(paste0(pad_left, label, pad_right)), side) box <- paste0(top, "\n", paste0(middle, collapse = "\n"), "\n", bottom) class(box) <- unique(c("cli_boxx", "boxx", class(box), "character")) box } methods::setOldClass(c("cli_boxx", "character")) #' @export print.cli_boxx <- function(x, ..., sep = "\n") { cat(x, ..., sep = sep) invisible(x) } cli/R/progress-client.R0000644000176200001440000007022414752735214014504 0ustar liggesusers #' cli progress bars #' #' @description #' This is the reference manual of the three functions that create, #' update and terminate progress bars. For a tutorial see the #' [cli progress bars](https://cli.r-lib.org/articles/progress.html). #' #' `cli_progress_bar()` creates a new progress bar. #' #' @details #' #' ## Basic usage #' #' `cli_progress_bar()` creates a progress bar, `cli_progress_update()` #' updates an existing progress bar, and `cli_progress_done()` terminates #' it. #' #' It is good practice to always set the `name` argument, to make the #' progress bar more informative. #' #' ```{asciicast progress-1} #' #| asciicast_at = "all", #' #| asciicast_knitr_output = "svg", #' #| asciicast_cursor = FALSE #' clean <- function() { #' cli_progress_bar("Cleaning data", total = 100) #' for (i in 1:100) { #' Sys.sleep(5/100) #' cli_progress_update() #' } #' cli_progress_done() #' } #' clean() #' ``` #' #' ## Progress bar types #' #' There are three builtin types of progress bars, and a custom type. #' #' ```{asciicast progress-tasks} #' #| asciicast_at = "all", #' #| asciicast_knitr_output = "svg", #' #| asciicast_cursor = FALSE #' tasks <- function() { #' cli_progress_bar("Tasks", total = 3, type = "tasks") #' for (i in 1:3) { #' Sys.sleep(1) #' cli_progress_update() #' } #' cli_progress_done() #' } #' tasks() #' ``` #' #' ## Unknown `total` #' #' If `total` is not known, then cli shows a different progress bar. #' Note that you can also set `total` in `cli_progress_update()`, if it #' not known when the progress bar is created, but you learn it later. #' #' ```{asciicast progress-natotal} #' #| asciicast_at = "all", #' #| asciicast_knitr_output = "svg", #' #| asciicast_cursor = FALSE #' nototal <- function() { #' cli_progress_bar("Parameter tuning") #' for (i in 1:100) { #' Sys.sleep(3/100) #' cli_progress_update() #' } #' cli_progress_done() #' } #' nototal() #' ``` #' #' ## Clearing the progress bar #' #' By default cli removes terminated progress bars from the screen, if #' the terminal supports this. If you want to change this, use the #' `clear` argument of `cli_progress_bar()`, or the `cli.progress_clear` #' global option (see [cli-config]) to change this. #' #' (In the cli documentation we usually set `cli.progress_clear` to `FALSE`, #' so users can see how finished progress bars look.) #' #' In this example the first progress bar is cleared, the second is not. #' #' ```{asciicast progress-clear} #' #| asciicast_at = "all", #' #| asciicast_knitr_output = "svg", #' #| asciicast_cursor = FALSE #' fun <- function() { #' cli_progress_bar("Data cleaning", total = 100, clear = TRUE) #' for (i in 1:100) { #' Sys.sleep(3/100) #' cli_progress_update() #' } #' cli_progress_bar("Parameter tuning", total = 100, clear = FALSE) #' for (i in 1:100) { #' Sys.sleep(3/100) #' cli_progress_update() #' } #' } #' fun() #' ``` #' #' ## Initial delay #' #' Updating a progress bar on the screen is costly, so cli tries to avoid #' it for quick loops. By default a progress bar is only shown after two #' seconds, or after half of that if less than 50% of the iterations are #' complete. You can change the two second default with the #' `cli.progress_show_after` global option (see [cli-config]). #' #' (In the cli documentation we usually set `cli.progress_show_after` to #' `0` (zero seconds), so progress bars are shown immediately.) #' #' In this example we only show the progress bar after one second, because #' more than 50% of the iterations remain after one second. #' #' ```{asciicast progress-after} #' #| asciicast_at = "all", #' #| asciicast_knitr_output = "svg", #' #| asciicast_cursor = FALSE #' fun <- function() { #' cli_alert("Starting now, at {Sys.time()}") #' cli_progress_bar( #' total = 100, #' format = "{cli::pb_bar} {pb_percent} @ {Sys.time()}" #' ) #' for (i in 1:100) { #' Sys.sleep(4/100) #' cli_progress_update() #' } #' } #' options(cli.progress_show_after = 2) #' fun() #' ``` #' #' ```{asciicast, include = FALSE, cache = FALSE} #' # reset to our default #' options(cli.progress_show_after = 0) #' ``` #' #' ## The _current_ progress bar #' #' By default cli sets the new progress bar as the _current_ progress bar #' of the calling function. The current progress bar is the default one #' in cli progress bar operations. E.g. if no progress bar id is supplied #' in `cli_progress_update()`, then the current progress bar is updated. #' #' Every function can only have a single _current_ progress bar, and if a #' new one is created, then the previous one (if any) is automatically #' terminated. The current progress bar is also terminated when the function #' that created it exits. Thanks to these rules, most often you don't need #' to explicitly deal with progress bar ids, and you don't need to #' explicitly call `cli_progress_done()`: #' #' ```{asciicast progress-current} #' #| asciicast_at = "all", #' #| asciicast_knitr_output = "svg", #' #| asciicast_cursor = FALSE #' fun <- function() { #' cli_progress_bar("First step ", total = 100) #' for (i in 1:100) { #' Sys.sleep(2/100) #' cli_progress_update() #' } #' cli_progress_bar("Second step", total = 100) #' for (i in 1:100) { #' Sys.sleep(2/100) #' cli_progress_update() #' } #' } #' fun() #' ``` #' #' ## cli output while the progress bar is active #' #' cli allows emitting regular cli output (alerts, headers, lists, etc.) #' while a progress bar is active. On terminals that support this, cli #' will remove the progress bar temporarily, emit the output, and then #' restores the progress bar. #' #' ```{asciicast progress-output} #' #| asciicast_at = "all", #' #| asciicast_knitr_output = "svg", #' #| asciicast_cursor = FALSE #' fun <- function() { #' cli_alert_info("Before the progress bar") #' cli_progress_bar("Calculating", total = 100) #' for (i in 1:50) { #' Sys.sleep(4/100) #' cli_progress_update() #' } #' cli_alert_info("Already half way!") #' for (i in 1:50) { #' Sys.sleep(4/100) #' cli_progress_update() #' } #' cli_alert_info("All done") #' } #' fun() #' ``` #' #' See also [cli_progress_output()], which sends text for the current #' progress handler. E.g. in a Shiny app it will send the output to the #' Shiny progress bar, as opposed to the `cli_alert()` etc. cli functions #' which will print the text to the console. #' #' ## Custom formats #' #' In addition to the builtin types, you can also specify a custom #' format string. In this case [progress variables][progress-variables] #' are probably useful to avoid calculating some progress bar quantities #' like the elapsed time, of the ETA manually. You can also use your own #' variables in the calling function: #' #' ```{asciicast progress-format} #' #| asciicast_at = "all", #' #| asciicast_knitr_output = "svg", #' #| asciicast_cursor = FALSE #' fun <- function(urls) { #' cli_progress_bar( #' format = paste0( #' "{pb_spin} Downloading {.path {basename(url)}} ", #' "[{pb_current}/{pb_total}] ETA:{pb_eta}" #' ), #' format_done = paste0( #' "{col_green(symbol$tick)} Downloaded {pb_total} files ", #' "in {pb_elapsed}." #' ),, #' total = length(urls) #' ) #' for (url in urls) { #' cli_progress_update() #' Sys.sleep(5/10) #' } #' } #' fun(paste0("https://acme.com/data-", 1:10, ".zip")) #' ``` #' #' @param name This is typically used as a label, and should be short, #' at most 20 characters. #' @param status Initial status of the progress bar. If not empty, then #' it is typically shown after the label. #' @param type Type of the progress bar. It is used to select a default #' display if `format` is not specified. Currently supported types: #' * `iterator`: e.g. a for loop or a mapping function, #' * `tasks`: a (typically small) number of tasks, #' * `download`: download of one file, #' * `custom`: custom type, `format` must not be `NULL` for this type. #' @param total Total number of progress units, or `NA` if it is unknown. #' `cli_progress_update()` can update the total number of units. This is #' handy if you don't know the size of a download at the beginning, and #' also in some other cases. If `format` is set to `NULL`, `format` (plus #' `format_done` and `format_failed`) will be updated when you change #' `total` from `NA` to a number. I.e. default format strings will be #' updated, custom ones won't be. #' @param format Format string. It has to be specified for custom progress #' bars, otherwise it is optional, and a default display is selected #' based on the progress bat type and whether the number of total units #' is known. Format strings may contain glue substitution, the support #' pluralization and cli styling. See [progress-variables] for special #' variables that you can use in the custom format. #' @param format_done Format string for successful termination. By default #' the same as `format`. #' @param format_failed Format string for unsuccessful termination. By #' default the same as `format`. #' @param clear Whether to remove the progress bar from the screen after #' it has terminated. Defaults to the `cli.progress_clear` option, or #' `TRUE` if unset. #' @param current Whether to use this progress bar as the current progress #' bar of the calling function. See more at 'The current progress bar' #' below. #' @param auto_terminate Whether to terminate the progress bar if the #' number of current units reaches the number of total units. #' @param extra Extra data to add to the progress bar. This can be #' used in custom format strings for example. It should be a named list. #' `cli_progress_update()` can update the extra data. Often you can get #' away with referring to local variables in the format string, and #' then you don't need to use this argument. Explicitly including these #' constants or variables in `extra` can result in cleaner code. In #' the rare cases when you need to refer to the same progress bar from #' multiple functions, and you can them to `extra`. #' @param .auto_close Whether to terminate the progress bar when the #' calling function (or the one with execution environment in `.envir` #' exits. (Auto termination does not work for progress bars created #' from the global environment, e.g. from a script.) #' @param .envir The environment to use for auto-termination and for glue #' substitution. It is also used to find and set the current progress bar. #' #' @return `cli_progress_bar()` returns the id of the new progress bar. #' The id is a string constant. #' #' @seealso These functions support [inline markup][inline-markup]. #' @seealso [cli_progress_message()] and [cli_progress_step()] for simpler #' progress messages. #' @family progress bar functions #' @family functions supporting inline markup #' @aliases __cli_update_due cli_tick_reset ccli_tick_reset ticking #' @export cli_progress_bar <- function(name = NULL, status = NULL, type = c("iterator", "tasks", "download", "custom"), total = NA, format = NULL, format_done = NULL, format_failed = NULL, clear = getOption("cli.progress_clear", TRUE), current = TRUE, auto_terminate = type != "download", extra = NULL, .auto_close = TRUE, .envir = parent.frame()) { start <- .Call(clic_get_time) id <- new_uuid() envkey <- format(.envir) type <- match.arg(type) if (type == "custom" && is.null(format)) { stop("Need to specify format if `type == \"custom\"") } ## If `total` is infinite, use behavior seen when `total` is NA if (is.infinite(total)) { total <- NA } ## If changes, synchronize with C API in progress.c bar <- new.env(parent = emptyenv()) bar$id <- id bar$name <- name bar$status <- status bar$type <- match.arg(type) bar$total <- total bar$show_after <- start + getOption("cli.progress_show_after", 2) bar$show_50 <- start + getOption("cli.progress_show_after", 2) / 2 bar$format_orig <- bar$format <- format bar$format_done_orig <- bar$format_done <- format_done %||% format bar$format_failed_orig <- bar$format_failed <- format_failed %||% format bar$clear <- clear bar$auto_terminate <- auto_terminate bar$envkey <- if (current) envkey else NULL bar$current <- 0L bar$start <- start bar$tick <- 0L bar$extra <- extra clienv$progress[[id]] <- bar if (current) { if (!is.null(clienv$progress_ids[[envkey]])) { cli_progress_done(clienv$progress_ids[[envkey]], .envir = .envir, result = "done") } clienv$progress_ids[[envkey]] <- id } if (.auto_close && envkey != clienv$globalenv) { defer( cli_progress_done(id = id, .envir = .envir, result = "auto"), envir = .envir ) } opt <- options(cli__pb = bar) on.exit(options(opt), add = TRUE) bar$handlers <- cli_progress_select_handlers(bar, .envir) for (h in bar$handlers) { if ("create" %in% names(h)) h$create(bar, .envir = .envir) } invisible(id) } #' @description #' `cli_progress_update()` updates the state of a progress bar, and #' potentially the display as well. #' #' @param inc Increment in progress units. This is ignored if `set` is #' not `NULL`. #' @param set Set the current number of progress units to this value. #' Ignored if `NULL`. #' @param status New status string of the progress bar, if not `NULL`. #' @param id Progress bar to update or terminate. If `NULL`, then the #' current progress bar of the calling function (or `.envir` if #' specified) is updated or terminated. #' @param force Whether to force a display update, even if no update is #' due. #' #' @return `cli_progress_update()` returns the id of the progress bar, #' invisibly. #' #' @name cli_progress_bar #' @export cli_progress_update <- function(inc = NULL, set = NULL, total = NULL, status = NULL, extra = NULL, id = NULL, force = FALSE, .envir = parent.frame()) { id <- id %||% clienv$progress_ids[[format(.envir)]] if (is.null(id)) { envkey <- format(.envir) stop("Cannot find current progress bar for `", envkey, "`") } pb <- clienv$progress[[id]] if (is.null(pb)) stop("Cannot find progress bar `", id, "`") if (!is.null(status)) pb$status <- status if (!is.null(extra)) pb$extra <- utils::modifyList(pb$extra, extra) if (!is.null(set)) { pb$current <- set } else { inc <- inc %||% 1L pb$current <- pb$current + inc } if (!is.null(total)) { if (is.na(pb$total) != is.na(total) || (!is.na(total) && pb$total != total)) { pb$total <- total if (!is.null(pb$format) && is.null(pb$format_orig)) { pb$format <- pb__default_format(pb$type, pb$total) pb$format_done <- pb$format_done_orig %||% pb$format pb$format_failed <- pb$format_failed_orig %||% pb$format } } } if (pb$auto_terminate && !is.na(pb$total) && pb$current == pb$total) { cli_progress_done(id, .envir = .envir, result = "done") return(invisible(id)) } now <- .Call(clic_get_time) upd <- .Call(clic_update_due) if (force || (upd && now > pb$show_after) || (!is.na(pb$total) && upd && now > pb$show_50 && pb$current <= pb$total / 2)) { if (upd) cli_tick_reset() pb$tick <- pb$tick + 1L if (is.null(pb$format)) { pb$format <- pb__default_format(pb$type, pb$total) pb$format_done <- pb$format_done_orig %||% pb$format pb$format_failed <- pb$format_failed_orig %||% pb$format } opt <- options(cli__pb = pb) on.exit(options(opt), add = TRUE) if (is.null(pb$added)) { pb$added <- TRUE for (h in pb$handlers) { if ("add" %in% names(h)) h$add(pb, .envir = .envir) } } for (h in pb$handlers) { if ("set" %in% names(h)) h$set(pb, .envir = .envir) } } # Return TRUE, to allow cli_progress_update() && break in loops invisible(id) } #' @description #' `cli_progress_done()` terminates a progress bar. #' #' @param result String to select successful or unsuccessful termination. #' It is only used if the progress bar is not cleared from the screen. #' It can be one of `"done"`, `"failed"`, `"clear"`, and `"auto"`. #' #' @return `cli_progress_done()` returns `TRUE`, invisibly, always. #' #' @name cli_progress_bar #' @export cli_progress_done <- function(id = NULL, .envir = parent.frame(), result = "done") { envkey <- format(.envir) id <- id %||% clienv$progress_ids[[envkey]] if (is.null(id)) return(invisible(TRUE)) pb <- clienv$progress[[id]] if (is.null(pb)) return(invisible(TRUE)) opt <- options(cli__pb = pb) on.exit(options(opt), add = TRUE) if (result == "auto") { r1 <- random_marker if (identical(returnValue(r1), r1)) { result <- "failed" } else { result <- "done" } } for (h in pb$handlers) { if ("complete" %in% names(h)) { h$complete(pb, .envir = .envir, result = result) } } clienv$progress[[id]] <- NULL if (!is.null(pb$envkey)) clienv$progress_ids[[pb$envkey]] <- NULL invisible(TRUE) } #' Add text output to a progress bar #' #' The text is calculated via [cli_text()], so all cli features can be #' used here, including progress variables. #' #' The text is passed to the progress handler(s), that may or may not be #' able to print it. #' #' ```{asciicast progress-output2} #' #| asciicast_at = "all", #' #| asciicast_knitr_output = "svg", #' #| asciicast_cursor = FALSE #' fun <- function() { #' cli_alert_info("Before the progress bar") #' cli_progress_bar("Calculating", total = 100) #' for (i in 1:50) { #' Sys.sleep(4/100) #' cli_progress_update() #' } #' cli_progress_output("Already half way!") #' for (i in 1:50) { #' Sys.sleep(4/100) #' cli_progress_update() #' } #' cli_alert_info("All done") #' } #' fun() #' ``` #' #' @param text Text to output. It is formatted via [cli_text()]. #' @param id Progress bar id. The default is the current progress bar. #' @param .envir Environment to use for glue interpolation of `text`. #' @return `TRUE`, always. #' #' @seealso This function supports [inline markup][inline-markup]. #' @family progress bar functions #' @family functions supporting inline markup #' @export cli_progress_output <- function(text, id = NULL, .envir = parent.frame()) { envkey <- format(.envir) id <- id %||% clienv$progress_ids[[envkey]] if (is.null(id)) { stop("Cannot find current progress bar for `", envkey, "`") } pb <- clienv$progress[[id]] if (is.null(pb)) stop("Cannot find progress bar `", id, "`") txt <- cli_fmt(cli_text(text, .envir = .envir)) for (h in pb$handlers) { if ("output" %in% names(h)) { h$output(pb, .envir = .envir, text = txt) } } invisible(TRUE) } # ------------------------------------------------------------------------ #' Simplified cli progress messages #' #' @description This is a simplified progress bar, a single (dynamic) #' message, without progress units. #' #' @details `cli_progress_message()` always shows the message, even if no #' update is due. When the progress message is terminated, it is removed #' from the screen by default. #' #' Note that the message can be dynamic: if you update it with #' [cli_progress_update()], then cli uses the current values in the string #' substitutions. #' #' ```{asciicast progress-message} #' #| echo = c(-2, -3), #' #| asciicast_at = "all", #' #| asciicast_knitr_output = "svg", #' #| asciicast_cursor = FALSE #' fun <- function() { #' opts <- options(cli.progress_clear = TRUE) #' on.exit(options(opts), add = TRUE) #' cli_progress_message("Task one is running...") #' Sys.sleep(2) #' #' cli_progress_message("Task two is running...") #' Sys.sleep(2) #' #' step <- 1L #' cli_progress_message("Task three is underway: step {step}") #' for (step in 1:5) { #' Sys.sleep(0.5) #' cli_progress_update() #' } #' } #' fun() #' ``` #' #' @param msg Message to show. It may contain glue substitution and cli #' styling. It can be updated via [cli_progress_update()], as usual. #' @param current Passed to [cli_progress_bar()]. #' @param .auto_close Passed to [cli_progress_bar()]. #' @param .envir Passed to [cli_progress_bar()]. #' @param ... Passed to [cli_progress_bar()]. #' #' @return The id of the new progress bar. #' #' @seealso This function supports [inline markup][inline-markup]. #' @seealso [cli_progress_bar()] for the complete progress bar API. #' [cli_progress_step()] for a similar display that is styled by default. #' @family progress bar functions #' @family functions supporting inline markup #' @export cli_progress_message <- function(msg, current = TRUE, .auto_close = TRUE, .envir = parent.frame(), ...) { id <- cli_progress_bar( type = "custom", format = msg, current = current, .auto_close = .auto_close, .envir = .envir, ... ) cli_progress_update(id = id, force = TRUE, .envir = .envir) invisible(id) } # ------------------------------------------------------------------------ #' Simplified cli progress messages, with styling #' #' @description This is a simplified progress bar, a single (dynamic) #' message, without progress units. #' #' @details `cli_progress_step()` always shows the progress message, #' even if no update is due. #' #' ## Basic use #' #' ```{asciicast progress-step} #' #| asciicast_at = "all", #' #| asciicast_knitr_output = "svg", #' #| asciicast_cursor = FALSE #' f <- function() { #' cli_progress_step("Downloading data") #' Sys.sleep(2) #' cli_progress_step("Importing data") #' Sys.sleep(1) #' cli_progress_step("Cleaning data") #' Sys.sleep(2) #' cli_progress_step("Fitting model") #' Sys.sleep(3) #' } #' f() #' ``` #' #' ## Spinner #' #' You can add a spinner to some or all steps with `spinner = TRUE`, #' but note that this will only work if you call [cli_progress_update()] #' regularly. #' #' ```{asciicast progress-step-spin} #' #| asciicast_at = "all", #' #| asciicast_knitr_output = "svg", #' #| asciicast_cursor = FALSE #' f <- function() { #' cli_progress_step("Downloading data", spinner = TRUE) #' for (i in 1:100) { Sys.sleep(2/100); cli_progress_update() } #' cli_progress_step("Importing data") #' Sys.sleep(1) #' cli_progress_step("Cleaning data") #' Sys.sleep(2) #' cli_progress_step("Fitting model", spinner = TRUE) #' for (i in 1:100) { Sys.sleep(3/100); cli_progress_update() } #' } #' f() #' ``` #' #' ## Dynamic messages #' #' You can make the step messages dynamic, using glue templates. #' Since `cli_progress_step()` show that message immediately, we need #' to initialize `msg` first. #' #' ```{asciicast progress-step-dynamic} #' #| asciicast_at = "all", #' #| asciicast_knitr_output = "svg", #' #| asciicast_cursor = FALSE #' f <- function() { #' msg <- "" #' cli_progress_step("Downloading data{msg}", spinner = TRUE) #' for (i in 1:100) { #' Sys.sleep(2/100) #' msg <- glue::glue(", got file {i}/100") #' cli_progress_update() #' } #' cli_progress_step("Importing data") #' Sys.sleep(1) #' cli_progress_step("Cleaning data") #' Sys.sleep(2) #' cli_progress_step("Fitting model", spinner = TRUE) #' for (i in 1:100) { Sys.sleep(3/100); cli_progress_update() } #' } #' f() #' ``` #' #' ## Termination messages #' #' You can specify a different message for successful and/or #' unsuccessful termination: #' #' ```{asciicast progress-step-msg} #' #| error = FALSE, #' #| asciicast_at = "all", #' #| asciicast_knitr_output = "svg", #' #| asciicast_cursor = FALSE #' f <- function() { #' size <- 0L #' cli_progress_step( #' "Downloading data.", #' msg_done = "Downloaded {prettyunits::pretty_bytes(size)}.", #' spinner = TRUE #' ) #' for (i in 1:100) { #' Sys.sleep(3/100) #' size <- size + 8192 #' cli_progress_update() #' } #' } #' f() #' ``` #' #' @param msg Message to show. It may contain glue substitution and cli #' styling. It can be updated via [cli_progress_update()], as usual. #' It is style as a cli info alert (see [cli_alert_info()]). #' @param msg_done Message to show on successful termination. By default #' this it is the same as `msg` and it is styled as a cli success alert #' (see [cli_alert_success()]). #' @param msg_failed Message to show on unsuccessful termination. By #' default it is the same as `msg` and it is styled as a cli danger alert #' (see [cli_alert_danger()]). #' @param spinner Whether to show a spinner at the beginning of the line. #' To make the spinner spin, you'll need to call `cli_progress_update()` #' regularly. #' @param class cli class to add to the message. By default there is no #' class for steps with a spinner. #' @param current Passed to [cli_progress_bar()]. #' @param .auto_close Passed to [cli_progress_bar()]. #' @param .envir Passed to [cli_progress_bar()]. #' @param ... Passed to [cli_progress_bar()]. #' #' @seealso This function supports [inline markup][inline-markup]. #' @family progress bar functions #' @family functions supporting inline markup #' @export cli_progress_step <- function(msg, msg_done = msg, msg_failed = msg, spinner = FALSE, class = if (!spinner) ".alert-info", current = TRUE, .auto_close = TRUE, .envir = parent.frame(), ...) { format <- paste0( if (!is.null(class)) paste0("{", class, " "), if (spinner) "{cli::pb_spin} ", msg, if (!is.null(class)) "}" ) ts <- " {.timestamp {cli::pb_elapsed}}" format_done <- paste0("{.alert-success ", msg_done, ts, "}") format_failed <- paste0("{.alert-danger ", msg_failed, ts, "}") opt <- options(cli.progress_show_after = 0) on.exit(options(opt), add = TRUE) id <- cli_progress_bar( type = "custom", format = format, format_done = format_done, format_failed = format_failed, clear = FALSE, current = current, .auto_close = .auto_close, .envir = .envir, ... ) cli_progress_update(id = id, force = TRUE, .envir = .envir) invisible(id) } # ------------------------------------------------------------------------ pb__default_format <- function(type, total) { if (type == "iterator") { if (!is.na(total)) { opt <- getOption("cli.progress_format_iterator") if (!is.null(opt)) return(opt) paste0( "{cli::pb_name}{cli::pb_bar} {cli::pb_percent} | {cli::pb_status}", "ETA: {cli::pb_eta}" ) } else { opt <- getOption("cli.progress_format_iterator_nototal") %||% getOption("cli.progress_format_iterator") if (!is.null(opt)) return(opt) paste0( "{cli::pb_spin} {cli::pb_name}{cli::pb_status}", "{cli::pb_current} done ({cli::pb_rate}) | {cli::pb_elapsed}" ) } } else if (type == "tasks") { if (!is.na(total)) { opt <- getOption("cli.progress_format_tasks") if (!is.null(opt)) return(opt) paste0( "{cli::pb_spin} {cli::pb_current}/{cli::pb_total} ", "ETA: {cli::pb_eta} | {cli::pb_name}{cli::pb_status}" ) } else { opt <- getOption("cli.progress_format_tasks_nototal") %||% getOption("cli.progress_format_tasks") if (!is.null(opt)) return(opt) paste0( "{cli::pb_spin} {cli::pb_name}{cli::pb_status}", "{cli::pb_current} done ({cli::pb_rate}) | {cli::pb_elapsed}" ) } } else if (type == "download") { if (!is.na(total)) { opt <- getOption("cli.progress_format_download") if (!is.null(opt)) return(opt) paste0( "{cli::pb_name}{cli::pb_status}{cli::pb_bar}| ", "{cli::pb_current_bytes}/{cli::pb_total_bytes} {cli::pb_eta_str}" ) } else { opt <- getOption("cli.progress_format_download_nototal") %||% getOption("cli.progress_format_download") if (!is.null(opt)) return(opt) paste0( "{cli::pb_name}{cli::pb_status}{cli::pb_spin} ", "{cli::pb_current_bytes} ({cli::pb_rate_bytes}) | {cli::pb_elapsed}" ) } } } cli/R/print.R0000644000176200001440000000547714557444176012537 0ustar liggesusers #' Create a format method for an object using cli tools #' #' This method can be typically used in `format()` S3 methods. Then the #' `print()` method of the class can be easily defined in terms of such a #' `format()` method. See examples below. #' #' @param expr Expression that calls `cli_*` methods, [base::cat()] or #' [base::print()] to format an object's printout. #' @param theme Theme to use for the formatting. #' @return Character vector, one element for each line of the printout. #' #' @export #' @examples #' #' # Let's create format and print methods for a new S3 class that #' # represents the an installed R package: `r_package` #' #' # An `r_package` will contain the DESCRIPTION metadata of the package #' # and also its installation path. #' new_r_package <- function(pkg) { #' tryCatch( #' desc <- packageDescription(pkg), #' warning = function(e) stop("Cannot find R package `", pkg, "`") #' ) #' file <- dirname(attr(desc, "file")) #' if (basename(file) != pkg) file <- dirname(file) #' structure( #' list(desc = unclass(desc), lib = dirname(file)), #' class = "r_package" #' ) #' } #' #' format.r_package <- function(x, ...) { #' cli_format_method({ #' cli_h1("{.pkg {x$desc$Package}} {cli::symbol$line} {x$desc$Title}") #' cli_text("{x$desc$Description}") #' cli_ul(c( #' "Version: {x$desc$Version}", #' if (!is.null(x$desc$Maintainer)) "Maintainer: {x$desc$Maintainer}", #' "License: {x$desc$License}" #' )) #' if (!is.na(x$desc$URL)) cli_text("See more at {.url {x$desc$URL}}") #' }) #' } #' #' # Now the print method is easy: #' print.r_package <- function(x, ...) { #' cat(format(x, ...), sep = "\n") #' } #' #' # Try it out #' new_r_package("cli") #' #' # The formatting of the output depends on the current theme: #' opt <- options(cli.theme = simple_theme()) #' print(new_r_package("cli")) #' options(opt) # <- restore theme cli_format_method <- function(expr, theme = getOption("cli.theme")) { # This is not needed for cli, but needed for sink() and crayon nc <- num_ansi_colors() opts <- options( cli.num_colors = nc, crayon.enabled = nc > 1, crayon.colors = nc ) on.exit(options(opts), add = TRUE) # Redirect everything to the connection con <- textConnection(NULL, open = "w", local = TRUE, encoding = "bytes") sink(con) on.exit(sink(NULL), add = TRUE) on.exit(close(con), add = TRUE) start_app(theme = theme, output = con) # Run the code withCallingHandlers( expr, cli_message = function(msg) { withCallingHandlers( cli_server_default(msg), cliMessage = function(msg2) { cat(conditionMessage(msg2), file = con, sep = "") invokeRestart("muffleMessage") } ) invokeRestart("cli_message_handled") } ) # Collect the output textConnectionValue(con) } cli/R/timer.R0000644000176200001440000000201014557444176012477 0ustar liggesusers #' @export `__cli_update_due` <- FALSE #' @export cli_tick_reset <- function() { .Call(clic_tick_reset) } #' @export ccli_tick_reset <- NULL cli_tick_set <- function(tick_time = NULL, speed_time = NULL) { tick_time <- tick_time %||% clienv$tick_time speed_time <- speed_time %||% clienv$speed_time clienv$speed_time <- as.double(speed_time) clienv$tick_time <- as.integer(tick_time) .Call(clic_tick_set, clienv$tick_time, clienv$speed_time) invisible() } cli_tick_pause <- function(state = TRUE) { .Call(clic_tick_pause, state) } cli_tick_resume <- function(state = TRUE) { .Call(clic_tick_resume, state) } cli_with_ticks <- function(expr) { on.exit(cli_tick_resume(TRUE), add = TRUE) opts <- options(cli.progress_show_after = 0) on.exit(options(opts), add = TRUE) cli_tick_pause(TRUE) expr } cli_without_ticks <- function(expr) { on.exit(cli_tick_resume(TRUE), add = TRUE) opts <- options(cli.progress_show_after = 0) on.exit(options(opts), add = TRUE) cli_tick_pause(FALSE) expr } cli/R/rematch2.R0000644000176200001440000000172714557444176013102 0ustar liggesusers re_match <- function(text, pattern, perl = TRUE, ...) { stopifnot(is.character(pattern), length(pattern) == 1, !is.na(pattern)) text <- as.character(text) match <- regexpr(pattern, text, perl = perl, ...) start <- as.vector(match) length <- attr(match, "match.length") end <- start + length - 1L matchstr <- substring(text, start, end) matchstr[ start == -1 ] <- NA_character_ empty <- data.frame(stringsAsFactors = FALSE, .text = text)[, numeric()] res <- list(match = !is.na(matchstr), groups = empty) if (!is.null(attr(match, "capture.start"))) { gstart <- attr(match, "capture.start") glength <- attr(match, "capture.length") gend <- gstart + glength - 1L groupstr <- substring(text, gstart, gend) groupstr[ gstart == -1 ] <- NA_character_ dim(groupstr) <- dim(gstart) res$groups <- cbind(groupstr, res$groups, stringsAsFactors = FALSE) names(res$groups) <- attr(match, "capture.names") } res$groups } cli/R/width.R0000644000176200001440000000774114557444176012516 0ustar liggesusers #' Determine the width of the console #' #' It uses the `cli.width` option, if set. Otherwise it tries to #' determine the size of the terminal or console window. #' #' These are the exact rules: #' * If the `cli.width` option is set to a positive integer, it is used. #' * If the `cli.width` option is set, but it is not a positive integer, #' and error is thrown. #' #' Then we try to determine the size of the terminal or console window: #' * If we are not in RStudio, or we are in an RStudio terminal, #' then we try to use the `tty_size()` function to query the #' terminal size. This might fail if R is not running in a terminal, #' but failures are ignored. #' * If we are in the RStudio build pane, then the `RSTUDIO_CONSOLE_WIDTH` #' environment variable is used. If the build pane is resized, then this #' environment variable is not accurate any more, and the output might #' get garbled. #' * We are _not_ using the `RSTUDIO_CONSOLE_WIDTH` environment variable #' if we are in the RStudio console. #' #' If we cannot determine the size of the terminal or console window, then #' we use the `width` option. If the `width` option is not set, then #' we return 80L. #' #' @return Integer scalar, the console with, in number of characters. #' #' @export #' @examples #' console_width() console_width <- function() { # cli.width option always takes priotity cwopt <- getOption("cli.width") if (!is.null(cwopt)) { if (!is.numeric(cwopt) || length(cwopt) != 1) { opt <- options(cli.width = 60) on.exit(options(opt), add = TRUE) throw(cli_error( "{.code options(\"cli.width\")} must be an integer scalar.", "i" = "{.code options(\"cli.width\")} is {.type {cwopt}}." )) } if (is.na(cwopt)) { opt <- options(cli.width = 60) on.exit(options(opt), add = TRUE) throw(cli_error("{.code options(\"cli.width\")} cannot be {.code NA}.")) } if (cwopt == Inf) { cwopti <- .Machine$integer.max } else { cwopti <- as.integer(cwopt) } if (cwopti <= 0) { opt <- options(cli.width = 60) on.exit(options(opt), add = TRUE) throw(cli_error( "{.code options(\"cli.width\")} must be a positive integer and not {.val {cwopti}}." )) } return(cwopti) } # detect if in RStudio rs <- rstudio$detect() if (rs$type == "not_rstudio") { # maybe a terminal? width <- terminal_width() } else if (rs$type == "rstudio_console_starting") { # there isn't much we can do here, options and env vars are not set width <- NULL } else if (rs$type == "rstudio_console") { # will just use getOption("width"), in case the user changed it, # and ignore the RSTUDIO_CONSOLE_WIDTH env var width <- NULL } else if (rs$type == "rstudio_build_pane") { # RStudio explicitly sets this for build pane processes # It is only good when the build starts, but we cannot do better width <- rs_console_width() } else if (rs$type == "rstudio_terminal") { # Can also be a subprocess of the terminal, with a pty, # but that's fine, the pty should have a width set up. # We do not fall back to the RSTUDIO_CONSOLE_WIDTH env var, # because the user might have changed options("width") and the env # var is only good when the terminal starts, anyway. width <- terminal_width() } else { # rstudio_subprocess width <- NULL } # If not set, then use the option width <- width %||% getOption("width") %||% 80L width } tty_size <- function() { ret <- .Call(clic_tty_size) c(width = ret[1], height = ret[2]) } terminal_width <- function() { if (isTRUE(clienv$notaconsole)) return(NULL) w <- tryCatch( tty_size()[["width"]], error = function(e) { clienv$notaconsole <- TRUE NULL } ) # this is probably a pty that does not set the width, use st sensible if (!is.null(w) && w == 0) w <- 80L w } rs_console_width <- function() { ev <- as.integer(Sys.getenv("RSTUDIO_CONSOLE_WIDTH", ""))[1] if (!is.na(ev)) ev else NULL } cli/R/server.R0000644000176200001440000000047714557444176012704 0ustar liggesusers cli_server_default <- function(msg) { cli_server_default_safe(msg) } cli_server_default_safe <- function(msg) { type <- as.character(msg$type)[1] app <- default_app() %||% start_app(.auto_close = FALSE) do.call(app[[type]], msg$args) } cli_server_callr_handler <- function(msg) { cli_server_default(msg) } cli/R/containers.R0000644000176200001440000001253714557444176013543 0ustar liggesusers add_child <- function(x, tag, ...) { push(x, list(tag = tag, ...)) } clii__container_start <- function(app, tag, class = NULL, id = NULL, theme = NULL) { id <- id %||% new_uuid() if (!length(class)) class <- "" class <- setdiff(unique(strsplit(class, " ", fixed = TRUE)[[1]]), "") app$doc <- add_child(app$doc, tag, id = id, class = class, theme = theme) ## Go over all themes, and collect the selectors that match the ## current element new_sels <- list() for (t in seq_along(app$themes)) { theme <- app$themes[[t]] for (i in seq_len(nrow(theme))) { if (match_selector(theme$parsed[[i]], app$doc)) { app$themes[[t]]$cnt[i] <- id new_sels <- utils::modifyList(new_sels, theme$style[[i]]) } } } new_style <- merge_embedded_styles(last(app$styles) %||% list(), new_sels) app$styles <- push(app$styles, new_style, name = id) ## Top margin, if any app$vspace(new_style$`margin-top` %||% 0) invisible(id) } clii__container_end <- function(app, id) { debug <- is_yes(Sys.getenv("CLI_DEBUG_BAD_END", "")) ## Defaults to last container if (is.null(id) || is.na(id)) id <- last(app$doc)$id ## Do not remove the if (id == "body") { if (debug) warning("No cli container to close") return(invisible(app)) } ## Do we have 'id' at all? wh <- which(vlapply(app$doc, function(x) identical(x$id, id)))[1] if (is.na(wh)) { if (debug) warning("Can't find cli container '", id, "' to close") return(invisible(app)) } ## ids to remove del_ids <- unlist(lapply(utils::tail(app$doc, - (wh - 1L)), "[[", "id")) ## themes to remove del_thm <- unlist(lapply(utils::tail(app$doc, - (wh - 1L)), "[[", "theme")) ## Remove the whole subtree of 'cnt' app$doc <- utils::head(app$doc, wh - 1L) ## Bottom margin del_from <- match(id, names(app$styles)) bottom <- max(viapply( app$styles[del_from:length(app$styles)], function(x) as.integer(x$`margin-bottom` %||% 0L) )) app$vspace(bottom) ## Remove styles app$styles <- utils::head(app$styles, del_from - 1L) ## Remove claimed styles that are not used any more for (t in seq_along(app$themes)) { m <- app$themes[[t]]$cnt %in% del_ids app$themes[[t]]$cnt[m] <- NA_character_ } ## Remove themes app$themes <- app$themes[setdiff(names(app$themes), del_thm)] invisible(app) } ## div -------------------------------------------------------------- clii_div <- function(app, id, class, theme) { theme_id <- app$add_theme(theme) clii__container_start(app, "div", class, id, theme = theme_id) id } ## Paragraph -------------------------------------------------------- clii_par <- function(app, id, class) { clii__container_start(app, "par", class, id) } ## Lists ------------------------------------------------------------ clii_ul <- function(app, items, id, class, .close) { id <- clii__container_start(app, "ul", id = id, class = class) if (length(items)) { app$li(items); if (.close) app$end(id) } invisible(id) } clii_ol <- function(app, items, id, class, .close) { id <- clii__container_start(app, "ol", id = id, class = class) if (length(items)) { app$li(items); if (.close) app$end(id) } invisible(id) } clii_dl <- function(app, items, labels, id, class, .close) { id <- clii__container_start(app, "dl", id = id, class = class) if (length(items)) { app$li(items, labels); if (.close) app$end(id) } invisible(id) } clii_li <- function(app, items, labels, id, class) { id <- id %||% new_uuid() ## check the last active list container last <- length(app$doc) while (! app$doc[[last]]$tag %in% c("ul", "ol", "dl", "body")) { last <- last - 1L } ## if not the last container, close the ones below it if (app$doc[[last]]$tag != "body" && last != length(app$doc)) { app$end(app$doc[[last + 1L]]$id) } ## if none, then create an ul container if (app$doc[[last]]$tag == "body") { cnt_id <- app$ul() type <- "ul" } else { cnt_id <- app$doc[[last]]$id type <- app$doc[[last]]$tag } if (length(items) > 0) { for (i in seq_along(items)) { id <- clii__container_start(app, "li", id = id, class = class) app$item_text(type, labels[[i]], cnt_id, items[[i]]) if (i < length(items)) app$end(id) } } else { app$delayed_item <- list(type = type, cnt_id = cnt_id) id <- clii__container_start(app, "li", id = id, class = class) } invisible(id) } clii__item_text <- function(app, type, name, cnt_id, text, .list) { style <- app$get_current_style() cnt_style <- app$styles[[cnt_id]] head <- if (type == "dl") name else glue_delay(name) head$str <- if (type == "ul") { paste0(call_if_fun(style$`list-style-type`) %||% "*", " ") } else if (type == "ol") { res <- paste0(cnt_style$start %||% 1L, ". ") app$styles[[cnt_id]]$start <- (cnt_style$start %||% 1L) + 1L res } else if (type == "dl") { mrk <- text$values$marker text$str <- paste0("<", mrk, ".dd ", text$str, mrk, ">") mrk2 <- head$values$marker paste0("<", mrk2, ".dt ", head$str, mrk2, ">") } app$xtext( .list = c(list(head), list(text), .list), indent = - (style$`padding-left` %||% 0), padding = (cnt_style$`padding-left` %||% 0) ) } ## Close container(s) ----------------------------------------------- clii_end <- function(app, id) { clii__container_end(app, id) } cli/R/onload.R0000644000176200001440000001065614557444176012652 0ustar liggesusers #' @useDynLib cli, .registration=TRUE NULL ## nocov start dummy <- function() { } cli_timer_dynamic <- 200L cli_timer_non_dynamic <- 3000L clienv <- new.env(parent = emptyenv()) clienv$pid <- Sys.getpid() clienv$globalenv <- format(.GlobalEnv) clienv$status <- list() clienv$progress <- list() clienv$progress_ids <- list() clienv$load_time <- NULL clienv$speed_time <- 1.0 clienv$tick_time <- 200L task_callback <- NULL clienv$unloaded <- FALSE rstudio_r_fix <- 0 .onLoad <- function(libname, pkgname) { err$onload_hook() # Try to restore cursor as much as we can if (Sys.getenv("R_CLI_HIDE_CURSOR") != "false" && isatty(stdout())) { reg.finalizer(clienv, function(e) cli::ansi_show_cursor(), TRUE) task_callback <<- addTaskCallback( function(...) { cli::ansi_show_cursor(); TRUE }, "cli-show-cursor" ) } # https://github.com/r-lib/cli/issues/352 rstudio_r_fix <<- (Sys.getenv("RSTUDIO") == 1) + 0L pkgenv <- environment(dummy) clienv$load_time <- Sys.time() clienv$speed_time <- as.double(Sys.getenv("CLI_SPEED_TIME", "1.0")) tt <- as.integer(Sys.getenv("CLI_TICK_TIME", NA_character_)) if (is.na(tt)) { tt <- if (interactive() || is_dynamic_tty()) { cli_timer_dynamic } else { cli_timer_non_dynamic } } clienv$tick_time <- as.integer(tt) .Call( clic_start_thread, pkgenv, clienv$tick_time, clienv$speed_time ) # For valgrind: https://github.com/r-lib/cli/issues/311 reg.finalizer(asNamespace("cli"), function(x) x$unload(), TRUE) if (getRversion() >= "3.5.0") { `__cli_update_due` <<- .Call(clic_make_timer); } else { rm("__cli_update_due", envir = pkgenv) makeActiveBinding( "__cli_update_due", function() .Call(clic_update_due), pkgenv ) } ccli_tick_reset <<- clic_tick_reset makeActiveBinding( "symbol", function() { ## If `cli.unicode` is set we use that opt <- getOption("cli.unicode", NULL) if (!is.null(opt)) { if (isTRUE(opt)) { return(symbol_utf8) } else { return(symbol_ascii) } } ## Otherwise we try to auto-detect rst <- rstudio$detect()$type rok <- c("rstudio_console", "rstudio_console_starting") if (is_utf8_output()) { symbol_utf8 } else if (is_latex_output()) { symbol_ascii } else { symbol_ascii } }, pkgenv ) makeActiveBinding("pb_bar", cli__pb_bar, pkgenv) makeActiveBinding("pb_current", cli__pb_current, pkgenv) makeActiveBinding("pb_current_bytes", cli__pb_current_bytes, pkgenv) makeActiveBinding("pb_elapsed", cli__pb_elapsed, pkgenv) makeActiveBinding("pb_elapsed_clock", cli__pb_elapsed_clock, pkgenv) makeActiveBinding("pb_elapsed_raw", cli__pb_elapsed_raw, pkgenv) makeActiveBinding("pb_eta", cli__pb_eta, pkgenv) makeActiveBinding("pb_eta_raw", cli__pb_eta_raw, pkgenv) makeActiveBinding("pb_eta_str", cli__pb_eta_str, pkgenv) makeActiveBinding("pb_extra", cli__pb_extra, pkgenv) makeActiveBinding("pb_id", cli__pb_id, pkgenv) makeActiveBinding("pb_name", cli__pb_name, pkgenv) makeActiveBinding("pb_percent", cli__pb_percent, pkgenv) makeActiveBinding("pb_pid", cli__pb_pid, pkgenv) makeActiveBinding("pb_rate", cli__pb_rate, pkgenv) makeActiveBinding("pb_rate_raw", cli__pb_rate_raw, pkgenv) makeActiveBinding("pb_rate_bytes", cli__pb_rate_bytes, pkgenv) makeActiveBinding("pb_spin", cli__pb_spin, pkgenv) makeActiveBinding("pb_status", cli__pb_status, pkgenv) makeActiveBinding("pb_timestamp", cli__pb_timestamp, pkgenv) makeActiveBinding("pb_total", cli__pb_total, pkgenv) makeActiveBinding("pb_total_bytes", cli__pb_total_bytes, pkgenv) if (is.null(getOption("callr.condition_handler_cli_message"))) { options(callr.condition_handler_cli_message = cli__default_handler) } } unload <- function() { if (!clienv$unloaded) .Call(clic_unload) clienv$unloaded <- TRUE } .onUnload <- function(libpath) { tryCatch(removeTaskCallback(task_callback), error = function(e) NULL) tryCatch(cli_progress_cleanup(), error = function(e) NULL) tryCatch(ansi_show_cursor(), error = function(e) NULL) unload() } ## nocov end cli/R/cat.R0000644000176200001440000000344414557444176012142 0ustar liggesusers#' `cat()` helpers #' #' These helpers provide useful wrappers around [cat()]: most importantly #' they all set `sep = ""`, and `cat_line()` automatically adds a newline. #' #' @export #' @param ... For `cat_line()` and `cat_bullet()`, pasted together with #' `collapse = "\n"`. For `cat_rule()` and `cat_boxx()` passed on to #' [rule()] and [boxx()] respectively. #' @param bullet Name of bullet character. Indexes into [symbol] #' @param col,background_col,bullet_col Colors for text, background, and #' bullets respectively. #' @param x An object to print. #' @param file Output destination. Defaults to standard output. #' @examples #' cat_line("This is ", "a ", "line of text.", col = "red") #' cat_bullet(letters[1:5]) #' cat_bullet(letters[1:5], bullet = "tick", bullet_col = "green") #' cat_rule() cat_line <- function(..., col = NULL, background_col = NULL, file = stdout()) { out <- paste0(..., collapse = "\n") out <- apply_style(out, col) out <- apply_style(out, background_col, bg = TRUE) cat(out, "\n", sep = "", file = file, append = TRUE) } #' @export #' @rdname cat_line cat_bullet <- function(..., col = NULL, background_col = NULL, bullet = "bullet", bullet_col = NULL, file = stdout()) { out <- apply_style(paste0(...), col) bullet <- apply_style(symbol[[bullet]], bullet_col) cat_line(paste(bullet, out), background_col = background_col, file = file) } #' @export #' @rdname cat_line cat_boxx <- function(..., file = stdout()) { cat_line(boxx(...), file = file) } #' @export #' @rdname cat_line cat_rule <- function(..., file = stdout()) { cat_line(rule(...), file = file) } #' @export #' @rdname cat_line cat_print <- function(x, file = "") { if (!identical(file, "")) { sink(file) on.exit(sink(NULL)) } print(x) } cli/R/prettycode.R0000644000176200001440000003052714752735214013550 0ustar liggesusers operator_tokens <- function() { c( "'-'", "'+'", "'!'", "'~'", "'?'", "':'", "'*'", "'/'", "'^'", "SPECIAL", "LT", "GT", "EQ", "GE", "LE", "AND", "AND2", "OR", "OR2", "LEFT_ASSIGN", "RIGHT_ASSIGN", "'$'", "'@'", "EQ_ASSIGN", "PIPE" ) } reserved_words <- function() { c("FUNCTION", "'\\\\'", "IF", "ELSE", "REPEAT", "WHILE", "FOR", "IN", "NEXT", "BREAK") } #' Syntax highlight R code #' #' @details #' See [code_theme_list()] for the default syntax highlighting theme and #' how to change it. #' #' If `code` does not parse, then it is returned unchanged and a #' `cli_parse_failure` condition is thrown. Note that this is not an error, #' and the condition is ignored, unless explicitly caught. #' #' @param code Character vector, each element is one line of code. #' @param code_theme Theme see [code_theme_list()]. #' @param envir Environment to look up function calls for hyperlinks. #' If `NULL`, then the global search path is used. #' @return Character vector, the highlighted code. #' #' @family syntax highlighting #' @importFrom utils getSrcref getParseData #' @export #' @examples #' code_highlight(deparse(ls)) #' cat(code_highlight(deparse(ls)), sep = "\n") code_highlight <- function(code, code_theme = NULL, envir = NULL) { code_theme <- code_theme %||% code_theme_default() parsed <- tryCatch( parse(text = code, keep.source = TRUE), error = function(e) e ) if (inherits(parsed, "error")) { cnd <- structure( list(message = conditionMessage(parsed), code = code), class = c("cli_parse_failure", "condition") ) signalCondition(cnd) return(code) } theme <- code_theme_make(code_theme) data <- getParseData(parsed, includeText = NA) hitext <- data$text cnv <- function(x) do.call(combine_ansi_styles, as.list(x)) brackettheme <- lapply(theme$bracket, cnv) theme <- theme[names(theme) != "bracket"] theme <- structure(lapply(theme, cnv), names = names(theme)) ## Reserved words if else repeat while function for in next break if (!is.null(theme$reserved)) { reserved <- data$token %in% reserved_words() hitext[reserved] <- theme$reserved(data$text[reserved]) } ## Numeric constants, including NAs, NaN and Inf if (!is.null(theme$number)) { num_const <- data$token == "NUM_CONST" hitext[num_const] <- theme$number(data$text[num_const]) } ## NULL if (!is.null(theme$null)) { null <- data$token == "NULL_CONST" hitext[null] <- theme$null(data$text[null]) } ## Operators if (!is.null(theme$operator)) { operator <- data$token %in% operator_tokens() hitext[operator] <- theme$operator(data$text[operator]) } ## Function calls fun_call <- data$token == "SYMBOL_FUNCTION_CALL" if (ansi_hyperlink_types()$help) { hitext[fun_call] <- pretty_fun_link(data, fun_call, envir) } if (!is.null(theme$call)) { hitext[fun_call] <- theme$call(hitext[fun_call]) } ## Strings if (!is.null(theme$string)) { string <- data$token == "STR_CONST" reserved <- theme$reserved %||% function(x) x raw <- substr(data$text[string], 1, 1) == "r" hitext[string][raw] <- paste0( rep(reserved("r"), sum(raw)), theme$string(substr(data$text[string][raw], 2, nchar(data$text[string][raw]))) ) hitext[string][!raw] <- theme$string(data$text[string][!raw]) } ## Comments if (!is.null(theme$comment)) { comment <- data$token == "COMMENT" hitext[comment] <- theme$comment(data$text[comment]) } ## Brackets if (length(brackettheme)) { bracket <- data$token %in% bracket_tokens() hitext[bracket] <- color_brackets(data$text[bracket], brackettheme) } do_subst(code, data, hitext) } do_subst <- function(code, pdata, hitext) { pdata$hitext <- hitext ## Need to do this line by line. TODO: multiline stuff might be broken vapply(seq_along(code), FUN.VALUE = character(1), function(no) { my <- pdata[pdata$line1 == no & pdata$line2 == no,, drop = FALSE] replace_in_place(code[no], my$col1, my$col2, my$hitext) }) } open_brackets <- function() { c("(", "{", "[") } close_brackets <- function(){ c(")", "}", "]") } bracket_tokens <- function() { s <- c(open_brackets(), close_brackets()) c(paste0("'", s, "'"), "LBB") } apply_color <- function(x, lvl, l){ k <- (lvl - 1) %% length(l) + 1 l[[k]](x) } #' Colored brackets #' #' Add color to brackets. Brackets will be coloured consecutively with the #' colors provided in \code{color_seq} by scope. #' #' @param x a character vector of brackets consisting of a valid sequence of any #' of the following: \code{'[[', '[', ']', '(', ')', '{', '}'} #' @param color_seq a list of functions that take and return a character scalar. The #' ordering defines the sequence of color functions to apply to a given scope level. #' Color functions are recycled when the scope level exceeds the length of \code{color_seq} #' #' @details Meant for coloring brackets encountered within \code{highlight}. #' Note that occurrences of 'orphan' brackets are not taken into account #' mainly due to the fact that cases such as #' #' \code{foo <- function(x){ `[[`(x, 1) }} #' #' will either be converted to #' #' \code{foo <- function(x){ x[[1]] }} #' #' before the brackets are coloured if passed in as #' \code{highlight(deparse(foo))} or will be identified as a #' 'SYMBOL_FUNCTION_CALL' token instead of 'LBB' if passed in as #' #' \code{highlight("foo <- function(x){ `[[`(x, 1) }")} #' #' Similarly, invalid code that would lead to orphaned brackets is not taken #' into account as this would be caught before hand in \code{highlight}. #' #' @noRd color_brackets <- function(x, color_seq = list(col_yellow, col_blue, col_cyan)) { stopifnot(vapply(color_seq, is.function, logical(1))) open <- c(open_brackets(), "[[") o <- character() lvl <- 0 i <- 1 while (i <= length(x)) { if (x[i] %in% open) { o[length(o) + 1] <- x[i] lvl <- lvl + 1 x[i] <- apply_color(x[i], lvl, color_seq) i <- i + 1 next } j <- nchar(o[length(o)]) x[i:(i + j - 1)] <- apply_color(x[i:(i + j - 1)], lvl, color_seq) i <- i + j lvl <- lvl - 1 o <- o[-length(o)] } x } replace_in_place <- function(str, start, end, replacement) { stopifnot( length(str) == 1, length(start) == length(end), length(end) == length(replacement) ) keep <- substring(str, c(1, end + 1), c(start - 1, nchar(str))) pieces <- character(length(replacement) * 2 + 1) even <- seq_along(replacement) * 2 odd <- c(1, even + 1) pieces[even] <- replacement pieces[odd] <- keep paste0(pieces, collapse = "") } code_theme_default <- function() { opt <- code_theme_opt("cli.code_theme") if (!is.null(opt)) return(opt) rs <- rstudio_detect() if (rs$type %in% c("rstudio_console", "rstudio_console_starting")) { opt <- code_theme_opt("cli.code_theme_rstudio") if (!is.null(opt)) return(opt) if (requireNamespace("rstudioapi", quietly = TRUE)) { return(code_theme_default_rstudio()) } } opt <- code_theme_opt("cli.code_theme_terminal") if (!is.null(opt)) return(opt) code_theme_default_term() } code_theme_opt <- function(option) { theme <- getOption(option) if (is.null(theme)) return(NULL) code_theme_make(theme) } code_theme_make <- function(theme) { if (is.list(theme)) return(theme) if (is_string(theme)) { if (theme %in% names(rstudio_themes)) return(rstudio_themes[[theme]]) lcs <- gsub(" ", "_", tolower(names(rstudio_themes)), fixed = TRUE) if (theme %in% lcs) return(rstudio_themes[[ match(theme, lcs)[1] ]]) warning("Unknown cli code theme: `", theme, "`.") return(NULL) } warning("Invalid cli code theme, see documentation") NULL } code_theme_default_rstudio <- function() { theme <- get_rstudio_theme()$editor if (! theme %in% names(rstudio_themes)) { if (!getOption("cli.ignore_unknown_rstudio_theme", FALSE)) { warning( "cli does not know this RStudio theme: '", theme, "'.", "\nSet `options(cli.ignore_unknown_rstudio_theme = TRUE)` ", "to suppress this warning" ) } return(code_theme_default_term()) } rstudio_themes[[theme]] } code_theme_default_term <- function() { "Solarized Dark" } #' Syntax highlighting themes #' #' @description #' `code_theme_list()` lists the built-in code themes. #' #' # Code themes #' A theme is a list of character vectors, except for `bracket`, see below. #' Each character vector must contain RGB colors (e.g. `"#a9a9a9"`), #' and cli styles, e.g. `"bold"`. Entries in the list: #' * `reserved`: reserved words #' * `number`: numeric literals #' * `null`: the `NULL` constant #' * `operator`: operators, including assignment #' * `call`: function calls #' * `string`: character literals #' * `comment`: comments #' * `bracket`: brackets: \code{(){}[]} This is a list of character vectors, #' to create "rainbow" brackets. It is recycled for deeply nested lists. #' #' # The default code theme #' #' In RStudio, it matches the current theme of the IDE. #' #' You can use three options to customize the code theme: #' * If `cli.code_theme` is set, it is used. #' * Otherwise if R is running in RStudio and `cli.code_theme_rstudio` is #' set, then it is used. #' * Otherwise if T is not running in RStudio and `cli.code_theme_terminal` #' is set, then it is used. #' #' You can set these options to the name of a built-in theme, or to list #' that specifies a custom theme. See [code_theme_list()] for the list #' of the built-in themes. #' #' @return Character vector of the built-in code theme names. #' #' @family syntax highlighting #' @export #' @examples #' code_theme_list() #' code_highlight(deparse(get), code_theme = "Solarized Dark") code_theme_list <- function() { names(rstudio_themes) } pretty_print_function <- function(x, useSource = TRUE, code_theme = NULL, ...) { if (num_ansi_colors() == 1L) return(base::print.function(x, useSource)) srcref <- getSrcref(x) src <- if (useSource && ! is.null(srcref)) { as.character(srcref) } else { deparse(x) } err <- FALSE hisrc <- tryCatch( code_highlight(src, code_theme = code_theme, envir = environment(x)), error = function(e) err <<- TRUE) if (err) return(base::print.function(x, useSource)) ## Environment of the function hisrc <- c(hisrc, utils::capture.output(print(environment(x)))) cat(hisrc, sep = "\n") invisible(x) } #' Turn on pretty-printing functions at the R console #' #' Defines a print method for functions, in the current session, that supports #' syntax highlighting. #' #' The new print method takes priority over the built-in one. Use #' [base::suppressMessages()] to suppress the alert message. #' #' @export pretty_print_code <- function() { registerS3method("print", "function", pretty_print_function, asNamespace("cli")) cli::cli_alert_success("Registered pretty printing function method") } pretty_fun_link <- function(data, fun_call, envir) { sprt <- ansi_hyperlink_types()$help wch <- which(fun_call) txt <- data$text[wch] if (! sprt || length(wch) == 0) return(txt) scheme <- if (identical(attr(sprt, "type"), "rstudio")) { "ide:help" } else { "x-r-help" } pkg <- vcapply(wch, function(idx) { prt <- data$parent[idx] sgs <- which(data$parent == prt) # not a pkg::fun call? if (length(sgs) != 3 || data$token[sgs[1]] != "SYMBOL_PACKAGE" || data$token[sgs[2]] != "NS_GET") { # note: we do not process ::: which would be NS_GET_INT find_function_symbol(data$text[idx], envir %||% .GlobalEnv) } else { data$text[sgs[1]] } }) wlnk <- which(!is.na(pkg)) txt[wlnk] <- style_hyperlink( text = txt[wlnk], url = paste0(scheme, ":", pkg[wlnk], "::", txt[wlnk]) ) txt } find_function_symbol <- function(name, envir = .GlobalEnv) { empty <- emptyenv() while (!identical(envir, empty)) { if (exists(name, envir = envir, inherits = FALSE, mode = "function")) { env_name <- environmentName(envir) if (grepl("package:", env_name, fixed = TRUE)) { env_name <- sub("^package:", "", env_name) } if (grepl("imports:", env_name, fixed = TRUE)) { env_name <- environmentName(environment(get(name, envir))) } if (grepl("package:", env_name, fixed = TRUE)) { env_name <- sub("^package:", "", env_name) } if (env_name %in% c("", "R_GlobalEnv")) { env_name <- NA_character_ } return(env_name) } else { envir <- parent.env(envir) } } NA_character_ } cli/R/ansiex.R0000644000176200001440000010131314557444176012654 0ustar liggesusers#' Labels a character vector as containing ANSI control codes. #' #' This function sets the class of its argument, activating #' ANSI-string-specific methods such as for printing. #' #' @param x A character vector or something that can be #' coerced into one. #' @return A `cli_ansi_string` object, a subclass of #' `character`, with the same length and contents #' as `x`. #' @family low level ANSI functions #' @export ansi_string <- function(x) { if (!is.character(x)) x <- as.character(x) x <- enc2utf8(x) class(x) <- unique(c("cli_ansi_string", "ansi_string", class(x), "character")) x } #' Perl compatible regular expression that matches ANSI escape #' sequences #' #' Don't forget to use `perl = TRUE` when using this with [grepl()] and #' friends. #' #' @return String scalar, the regular expression. #' #' @family low level ANSI functions #' @export ansi_regex <- function() { paste0( "(?:(?:\\x{001b}\\[)|\\x{009b})", "(?:(?:[0-9]{1,3})?(?:(?:;[0-9]{0,3})*)?[A-M|f-m])", "|\\x{001b}[A-M]", # this is for hyperlinks, we must be non-greedy "|\\x{001b}\\]8;.*?;.*?\\x{001b}\\\\", "|\\x{001b}\\]8;.*?;.*?\\x{0007}" ) } #' Check if a string has some ANSI styling #' #' @param string The string to check. It can also be a character #' vector. #' @param sgr Whether to look for SGR (styling) control sequences. #' @param csi Whether to look for non-SGR control sequences. #' @param link Whether to look for ANSI hyperlinks. #' @return Logical vector, `TRUE` for the strings that have some #' ANSI styling. #' #' @family low level ANSI functions #' @export #' @examples #' ## The second one has style if ANSI colors are supported #' ansi_has_any("foobar") #' ansi_has_any(col_red("foobar")) ansi_has_any <- function(string, sgr = TRUE, csi = TRUE, link = TRUE) { if (!is.character(string)) string <- as.character(string) string <- enc2utf8(string) stopifnot( is_flag(sgr), is_flag(csi), is_flag(link) ) .Call(clic_ansi_has_any, string, sgr, csi, link) } #' Remove ANSI escape sequences from a string #' #' The input may be of class `cli_ansi_string` class, this is also dropped #' from the result. #' #' @param string The input string. #' @param sgr Whether to remove for SGR (styling) control sequences. #' @param csi Whether to remove for non-SGR control sequences. #' @param link Whether to remove ANSI hyperlinks. #' @return The cleaned up string. Note that `ansi_strip()` always drops #' the `cli_ansi_string` class, even if `sgr` and sci` are `FALSE`. #' #' @family low level ANSI functions #' @export #' @examples #' ansi_strip(col_red("foobar")) == "foobar" ansi_strip <- function(string, sgr = TRUE, csi = TRUE, link = TRUE) { if (!is.character(string)) string <- as.character(string) string <- enc2utf8(string) stopifnot( is_flag(sgr), is_flag(csi), is_flag(link) ) clean <- .Call(clic_ansi_strip, string, sgr, csi, link) class(clean) <- setdiff(class(clean), c("cli_ansi_string", "ansi_string")) clean } #' Count number of characters in an ANSI colored string #' #' This is a color-aware counterpart of [utf8_nchar()]. By default it #' counts Unicode grapheme clusters, instead of code points. #' #' @param x Character vector, potentially ANSI styled, or a vector to be #' coerced to character. If it converted to UTF-8. #' @param type Whether to count graphemes (characters), code points, #' bytes, or calculate the display width of the string. #' @return Numeric vector, the length of the strings in the character #' vector. #' #' @family ANSI string operations #' @export #' @examples #' str <- paste( #' col_red("red"), #' "default", #' col_green("green") #' ) #' #' cat(str, "\n") #' nchar(str) #' ansi_nchar(str) #' nchar(ansi_strip(str)) ansi_nchar <- function(x, type = c("chars", "bytes", "width", "graphemes", "codepoints")) { type <- match.arg(type) if (type == "chars") type <- "graphemes" type <- match(type, c("graphemes", "bytes", "width", "codepoints")) if (!is.character(x)) x <- as.character(x) x <- enc2utf8(x) .Call(clic_ansi_nchar, x, type) } #' Substring(s) of an ANSI colored string #' #' This is a color-aware counterpart of [base::substr()]. #' It works exactly like the original, but keeps the colors #' in the substrings. The ANSI escape sequences are ignored when #' calculating the positions within the string. #' #' @param x Character vector, potentially ANSI styled, or a vector to #' coerced to character. #' @param start Starting index or indices, recycled to match the length #' of `x`. #' @param stop Ending index or indices, recycled to match the length #' of `x`. #' @return Character vector of the same length as `x`, containing #' the requested substrings. ANSI styles are retained. #' #' @family ANSI string operations #' @export #' @examples #' str <- paste( #' col_red("red"), #' "default", #' col_green("green") #' ) #' #' cat(str, "\n") #' cat(ansi_substr(str, 1, 5), "\n") #' cat(ansi_substr(str, 1, 15), "\n") #' cat(ansi_substr(str, 3, 7), "\n") #' #' substr(ansi_strip(str), 1, 5) #' substr(ansi_strip(str), 1, 15) #' substr(ansi_strip(str), 3, 7) #' #' str2 <- paste( #' "another", #' col_red("multi-", style_underline("style")), #' "text" #' ) #' #' cat(str2, "\n") #' cat(ansi_substr(c(str, str2), c(3,5), c(7, 18)), sep = "\n") #' substr(ansi_strip(c(str, str2)), c(3,5), c(7, 18)) ansi_substr <- function(x, start, stop) { if (!is.character(x)) x <- as.character(x) if (!length(x)) return(ansi_string(x)) start <- suppressWarnings(as.integer(start)) stop <- suppressWarnings(as.integer(stop)) if (!length(start) || !length(stop)) { throw(cli_error( "{.code ansi_substr()} must have non-empty {.arg start} and {.arg stop} arguments", "i" = if (!length(start)) "{.arg start} has length {length(start)}", "i" = if (!length(stop)) "{.arg stop} has length {length(stop)}" )) } nastart <- anyNA(start) nastop <- anyNA(stop) if (nastart || nastop) { throw(cli_error( "{.arg start} and {.arg stop} must not have {.code NA} values", "i" = if (nastart) paste( "{.arg start} has {sum(is.na(start))}", "{.code NA} value{?s}, after coercion to integer"), "i" = if (nastop) paste( "{.arg stop} has {sum(is.na(stop))} {.code NA} value{?s},", "after coercion to integer") )) } x <- enc2utf8(x) start <- rep_len(start, length(x)) stop <- rep_len(stop, length(x)) .Call(clic_ansi_substr, x, start, stop) } #' Substring(s) of an ANSI colored string #' #' This is the color-aware counterpart of [base::substring()]. #' It works exactly like the original, but keeps the colors in the #' substrings. The ANSI escape sequences are ignored when #' calculating the positions within the string. #' #' @param text Character vector, potentially ANSI styled, or a vector to #' coerced to character. It is recycled to the longest of `first` #' and `last`. #' @param first Starting index or indices, recycled to match the length #' of `x`. #' @param last Ending index or indices, recycled to match the length #' of `x`. #' @return Character vector of the same length as `x`, containing #' the requested substrings. ANSI styles are retained. #' #' @family ANSI string operations #' @export #' @examples #' str <- paste( #' col_red("red"), #' "default", #' col_green("green") #' ) #' #' cat(str, "\n") #' cat(ansi_substring(str, 1, 5), "\n") #' cat(ansi_substring(str, 1, 15), "\n") #' cat(ansi_substring(str, 3, 7), "\n") #' #' substring(ansi_strip(str), 1, 5) #' substring(ansi_strip(str), 1, 15) #' substring(ansi_strip(str), 3, 7) #' #' str2 <- paste( #' "another", #' col_red("multi-", style_underline("style")), #' "text" #' ) #' #' cat(str2, "\n") #' cat(ansi_substring(str2, c(3,5), c(7, 18)), sep = "\n") #' substring(ansi_strip(str2), c(3,5), c(7, 18)) ansi_substring <- function(text, first, last = 1000000L) { if (!is.character(text)) text <- as.character(text) n <- max(lt <- length(text), length(first), length(last)) if (lt && lt < n) text <- rep_len(text, length.out = n) text <- enc2utf8(text) first <- rep_len(as.integer(first), n) last <- rep_len(as.integer(last), n) .Call(clic_ansi_substr, text, first, last) } #' Split an ANSI colored string #' #' This is the color-aware counterpart of [base::strsplit()]. #' It works almost exactly like the original, but keeps the colors in the #' substrings. #' #' @param x Character vector, potentially ANSI styled, or a vector to #' coerced to character. #' @param split Character vector of length 1 (or object which can be coerced to #' such) containing regular expression(s) (unless `fixed = TRUE`) to use #' for splitting. If empty matches occur, in particular if `split` has #' zero characters, `x` is split into single characters. #' @param ... Extra arguments are passed to `base::strsplit()`. #' @return A list of the same length as `x`, the `i`-th element of #' which contains the vector of splits of `x[i]`. ANSI styles are #' retained. #' #' @family ANSI string operations #' @export #' @examples #' str <- paste0( #' col_red("I am red---"), #' col_green("and I am green-"), #' style_underline("I underlined") #' ) #' #' cat(str, "\n") #' #' # split at dashes, keep color #' cat(ansi_strsplit(str, "[-]+")[[1]], sep = "\n") #' strsplit(ansi_strip(str), "[-]+") #' #' # split to characters, keep color #' cat(ansi_strsplit(str, "")[[1]], "\n", sep = " ") #' strsplit(ansi_strip(str), "") ansi_strsplit <- function(x, split, ...) { split <- try(as.character(split), silent = TRUE) if (inherits(split, "try-error") || !is.character(split) || length(split) > 1L) { throw(cli_error( "{.arg split} must be character of length <= 1, or must coerce to that", i = "{.arg split} is (or was coerced to) {.type {split}}" )) } if (!is.character(x)) x <- as.character(x) x <- enc2utf8(x) if(!length(split)) split <- "" plain <- ansi_strip(x) splits <- re_table(split, plain, ...) chunks <- non_matching(splits, plain, empty = TRUE) # silently recycle `split`; doesn't matter currently since we don't support # split longer than 1, but might in future split.r <- rep(split, length.out=length(x)) # Drop empty chunks to align with `substr` behavior chunks <- lapply( seq_along(chunks), function(i) { y <- chunks[[i]] # empty split means drop empty first match if(nrow(y) && !nzchar(split.r[[i]]) && !utils::head(y, 1L)[, "length"]) { y <- y[-1L, , drop=FALSE] } # drop empty last matches if(nrow(y) && !utils::tail(y, 1L)[, "length"]) y[-nrow(y), , drop=FALSE] else y } ) zero.chunks <- !vapply(chunks, nrow, integer(1L)) # Pull out zero chunks from colored string b/c ansi_substring won't work # with them res <- vector("list", length(chunks)) res[zero.chunks] <- list(character(0L)) res[!zero.chunks] <- mapply( chunks[!zero.chunks], x[!zero.chunks], SIMPLIFY = FALSE, FUN = function(tab, xx) ansi_substring(xx, tab[, "start"], tab[, "end"]) ) lapply(res, ansi_string) } #' Align an ANSI colored string #' #' @details #' #' ```{asciicast ansi-align} #' str <- c( #' col_red("This is red"), #' style_bold("This is bold") #' ) #' astr <- ansi_align(str, width = 30) #' boxx(astr) #' ``` #' #' ```{asciicast ansi-align-center} #' str <- c( #' col_red("This is red"), #' style_bold("This is bold") #' ) #' astr <- ansi_align(str, align = "center", width = 30) #' boxx(astr) #' ``` #' #' ```{asciicast ansi-align-right} #' str <- c( #' col_red("This is red"), #' style_bold("This is bold") #' ) #' astr <- ansi_align(str, align = "right", width = 30) #' boxx(astr) #' ``` #' #' @param text The character vector to align. #' @param width Width of the field to align in. #' @param align Whether to align `"left"`, `"center"` or `"right"`. #' @param type Passed on to [ansi_nchar()] and there to [nchar()] #' @return The aligned character vector. #' #' @family ANSI string operations #' @export # TODO: show wide Unicode charadcters, once they work in asciicast ansi_align <- function(text, width = console_width(), align = c("left", "center", "right"), type = "width") { align <- match.arg(align) text <- enc2utf8(text) nc <- ansi_nchar(text, type = type) if (!length(text)) return(ansi_string(text)) res <- if (align == "left") { paste0(text, make_space(width - nc)) } else if (align == "center") { paste0(make_space(ceiling((width - nc) / 2)), text, make_space(floor((width - nc) / 2))) } else { paste0(make_space(width - nc), text) } ansi_string(res) } make_space <- function(num, filling = " ") { num <- pmax(0, num) res <- strrep(filling, num) Encoding(res) <- Encoding(filling) res } strrep <- function (x, times) { x = as.character(x) if (length(x) == 0L) return(x) mapply( function(x, times) { if (is.na(x) || is.na(times)) { NA_character_ } else if (times <= 0L) { "" } else { paste0(rep(x, times), collapse = "") } }, x, times, USE.NAMES = FALSE ) } #' Remove leading and/or trailing whitespace from an ANSI string #' #' This function is similar to [base::trimws()] but works on ANSI strings, #' and keeps color and other styling. #' #' @param x ANSI string vector. #' @param which Whether to remove leading or trailing whitespace or both. #' @return ANSI string, with the whitespace removed. #' #' @family ANSI string operations #' @export #' @examples #' trimws(paste0(" ", col_red("I am red"), " ")) #' ansi_trimws(paste0(" ", col_red("I am red"), " ")) #' trimws(col_red(" I am red ")) #' ansi_trimws(col_red(" I am red ")) ansi_trimws <- function(x, which = c("both", "left", "right")) { if (!is.character(x)) x <- as.character(x) which <- match.arg(which) x <- enc2utf8(x) if (!length(x)) return(ansi_string(x)) sl <- 0L if (which %in% c("both", "left")) { xs <- ansi_strip(x) xl <- trimws(xs, "left") nxs <- nchar(xs) sl <- nxs - nchar(xl) } rl <- 0L if (which %in% c("both", "right")) { xs <- ansi_strip(x) xr <- trimws(xs, "right") nxs <- nchar(xs) rl <- nxs - nchar(xr) } if (any(sl > 0L | rl > 0L)) { start <- rep_len(1L + sl, length(x)) x <- .Call(clic_ansi_substr, x, start, ansi_nchar(x) - rl) } ansi_string(x) } #' Wrap an ANSI styled string to a certain width #' #' This function is similar to [base::strwrap()], but works on ANSI #' styled strings, and leaves the styling intact. #' #' @param x ANSI string. #' @param width Width to wrap to. #' @param indent Indentation of the first line of each paragraph. #' @param exdent Indentation of the subsequent lines of each paragraph. #' @param simplify Whether to return all wrapped strings in a single #' character vector, or wrap each element of `x` independently and return #' a list. #' @return If `simplify` is `FALSE`, then a list of character vectors, #' each an ANSI string. Otherwise a single ANSI string vector. #' #' @family ANSI string operations #' @export #' @examples #' text <- cli:::lorem_ipsum() #' # Highlight some words, that start with 's' #' rexp <- gregexpr("\\b([sS][a-zA-Z]+)\\b", text) #' regmatches(text, rexp) <- lapply(regmatches(text, rexp), col_red) #' cat(text) #' #' wrp <- ansi_strwrap(text, width = 40) #' cat(wrp, sep = "\n") ansi_strwrap <- function(x, width = console_width(), indent = 0, exdent = 0, simplify = TRUE) { if (!is.character(x)) x <- as.character(x) x <- enc2utf8(x) if (length(x) == 0) { return(ansi_string(x)) } if (length(x) > 1) { wrp <- lapply(x, ansi_strwrap, width = width, indent = indent, exdent = exdent, simplify = FALSE) if (simplify) wrp <- ansi_string(unlist(wrp)) return(wrp) } # Workaround for bad Unicode width x <- unicode_pre(x) # Form feeds are forced line breaks # R 4.2 removes the \f after # se we need to put in a random marker instead mark <- "yShtnpteEk" smark <- paste0("\n\n", mark, "\n\n") x <- gsub_("\f", smark, x, fixed = TRUE, useBytes = TRUE) fix_ff <- function(x) { xs <- ansi_strip(x) rem <- which(xs == mark) if (length(rem)) { x <- x[-c(rem - 1, rem + 1)] xs <- xs[-c(rem - 1, rem + 1)] if (xs[length(xs)] == mark) { x <- c(x, mark) xs <- c(xs, mark) } if (length(x) >= 2 && x[1] == "" && xs[2] == mark) { x <- x[-1] xs <- xs[-1] } # At this point, we have as many marks as many newlines we need # But (except for the begnning) we need one less empty lines than # newlines, because an empty line corresponds to two newlines at # the end of a non-empty line. del <- which(xs[-1] == mark & xs[-length(xs)] != mark) + 1L if (length(del) > 0) { x <- x[-del] xs <- xs[-del] } x[xs == mark] <- "" x } else { x } } # First we need to remove the multiple spaces, to make it easier to # map the strings later on. We do this per paragraph, to keep paragraphs. pars <- strsplit(x, "\n[ \t\n]*\n", perl = TRUE) pars <- lapply(pars, ansi_trimws) # Within paragraphs, replace multiple spaces with one, except when there # were two spaces at the end of a sentence, where we keep two. # This does not work well, when some space is inside an ANSI tag, and # some is outside, but for now, we'll live with this limitation. pars <- lapply(pars, function(s) { # First replace multiple spaces that are not at the end of a sentence s <- gsub("(? xwlen) { splits <- c(splits, xsidx) xwidx[1] <- xwidx[1] + 1L xwidx[2] <- 1L xwlen <- nchar(xw[xwidx[1]]) } } splits <- c(splits, xsidx) wrp <- vcapply(seq_along(splits[-1]), function(i) { from <- splits[i] to <- splits[i + 1L] - 1L while (from %in% drop) from <- from + 1L .Call(clic_ansi_substr, xx, from, to) }) indent <- strrep(" ", indent) ansi_string(unicode_post(fix_ff(paste0(indent, wrp)))) } #' Truncate an ANSI string #' #' This function is similar to [base::strtrim()], but works correctly with #' ANSI styled strings. It also adds `...` (or the corresponding Unicode #' character if Unicode characters are allowed) to the end of truncated #' strings. #' #' Note: `ansi_strtrim()` does not support NA values currently. #' #' @param x Character vector of ANSI strings. #' @param width The width to truncate to. #' @param ellipsis The string to append to truncated strings. Supply an #' empty string if you don't want a marker. #' #' @family ANSI string operations #' @export #' @examples #' text <- cli::col_red(cli:::lorem_ipsum()) #' ansi_strtrim(c(text, "foobar"), 40) ansi_strtrim <- function(x, width = console_width(), ellipsis = symbol$ellipsis) { if (width < 0) { throw(cli_error( "{.arg width} must be non-negative in {.fun cli::ansi_strtrim}." )) } x <- enc2utf8(x) # Unicode width notes. We have nothing to fix here, because we'll just # use ansi_substr() and ansi_nchar(), which work correctly with wide # characters. # if ellipsis is already longer than width, then we just return that tw <- ansi_nchar(ellipsis, "width") if (tw == width) { x[] <- ellipsis return(x) } else if (tw > width) { x[] <- ansi_strtrim(ellipsis, width, ellipsis = "") return(x) } # First we cut according to _characters_. This might be too wide if we # have wide characters. lx <- length(x) xt <- .Call(clic_ansi_substr, x, rep(1L, lx), rep(as.integer(width), lx)) # If there was a cut, or xt is too wide (using _width_!), that's bad # We keep the initial bad ones, these are the ones that need an ellipsis. # Then we keep chopping off single characters from the too wide ones, # until they are narrow enough. if (ansi_nzchar(ellipsis)) { bad0 <- bad <- !is.na(x) & (ansi_strip(xt) != ansi_strip(x) | ansi_nchar(xt, "width") > width) } else { # if ellipsis is zero length, then the truncated ones are not bad bad0 <- bad <- !is.na(x) & ansi_nchar(xt, "width") > width } while (any(bad)) { xt[bad] <- .Call( clic_ansi_substr, xt[bad], rep(1L, sum(bad)), ansi_nchar(xt[bad]) - 1L ) bad <- ansi_nchar(xt, "width") > width - tw } xt[bad0] <- paste0(xt[bad0], ellipsis) xt } #' Format a character vector in multiple columns #' #' This function helps with multi-column output of ANSI styles strings. #' It works well together with [boxx()], see the example below. #' #' If a string does not fit into the specified `width`, it will be #' truncated using [ansi_strtrim()]. #' #' ```{asciicast ansi-column} #' fmt <- ansi_columns( #' paste(col_red("foo"), 1:10), #' width = 50, #' fill = "rows", #' max_cols=10, #' align = "center", #' sep = " " #' ) #' boxx(fmt, padding = c(0,1,0,1), header = col_cyan("Columns")) #' ``` #' #' @param text Character vector to format. Each element will formatted #' as a cell of a table. #' @param width Width of the screen. #' @param sep Separator between the columns. It may have ANSI styles. #' @param fill Whether to fill the columns row-wise or column-wise. #' @param max_cols Maximum number of columns to use. Will not use more, #' even if there is space for it. #' @param align Alignment within the columns. #' @param type Passed to [ansi_nchar()] and [ansi_align()]. Most probably #' you want the default, `"width"`. #' @inheritParams ansi_strtrim #' @return ANSI string vector. #' #' @family ANSI string operations #' @export ansi_columns <- function(text, width = console_width(), sep = " ", fill = c("rows", "cols"), max_cols = 4, align = c("left", "center", "right"), type = "width", ellipsis = symbol$ellipsis) { fill <- match.arg(fill) align <- match.arg(align) text <- enc2utf8(text) if (length(text) == 0) return(ansi_string(text)) swdh <- ansi_nchar(sep, type = "width") twdh <- max(ansi_nchar(text, type = type)) + swdh cols <- min(floor(width / twdh), max_cols) if (cols == 0) { cols <- 1 text <- ansi_strtrim(text, width = width, ellipsis = ellipsis) } len <- length(text) extra <- ceiling(len / cols) * cols - len text <- c(text, rep("", extra)) tm <- matrix(text, byrow = fill == "rows", ncol = cols) colwdh <- diff(c(0, round((width / cols) * (1:cols)))) for (c in seq_len(ncol(tm))) { tm[, c] <- ansi_align( paste0(tm[, c], if (cols > 1) sep), colwdh[c], align = align, type = type ) } clp <- apply(tm, 1, paste0, collapse = "") ansi_string(clp) } #' ANSI character translation and case folding #' #' There functions are similar to [toupper()], [tolower()] and #' [chartr()], but they keep the ANSI colors of the string. #' #' @inheritParams base::chartr #' @param x Input string. May have ANSI colors and styles. #' @return Character vector of the same length as `x`, containing #' the translated strings. ANSI styles are retained. #' #' @family ANSI string operations #' @export #' @examples #' ansi_toupper(col_red("Uppercase")) #' #' ansi_tolower(col_red("LowerCase")) #' #' x <- paste0(col_green("MiXeD"), col_red(" cAsE 123")) #' ansi_chartr("iXs", "why", x) ansi_toupper <- function(x) { ansi_convert(x, toupper) } #' @family ANSI string operations #' @export #' @rdname ansi_toupper ansi_tolower <- function(x) { ansi_convert(x, tolower) } #' @family ANSI string operations #' @export #' @rdname ansi_toupper ansi_chartr <- function(old, new, x) { ansi_convert(x, chartr, old, new) } ansi_convert <- function(x, converter, ...) { x <- enc2utf8(x) ansi <- re_table(ansi_regex(), x) text <- non_matching(ansi, x, empty=TRUE) out <- mapply(x, text, USE.NAMES = FALSE, FUN = function(x1, t1) { t1 <- t1[t1[,1] <= t1[,2], , drop = FALSE] for (i in seq_len(nrow(t1))) { substring(x1, t1[i, 1], t1[i, 2]) <- converter(x = substring(x1, t1[i, 1], t1[i, 2]), ...) } x1 }) ansi_string(out) } #' Simplify ANSI styling tags #' #' It creates an equivalent, but possibly shorter ANSI styled string, by #' removing duplicate and empty tags. #' #' @param x Input string #' @param csi What to do with non-SGR ANSI sequences, either `"keep"`, #' or `"drop"` them. #' @return Simplified `cli_ansi_string` vector. #' #' @export ansi_simplify <- function(x, csi = c("keep", "drop")) { if (!is.character(x)) x <- as.character(x) csi <- match.arg(csi) x <- enc2utf8(x) .Call(clic_ansi_simplify, x, csi == "keep") } #' Convert ANSI styled text to HTML #' #' @param x Input character vector. #' @param escape_reserved Whether to escape characters that are reserved #' in HTML (`&`, `<` and `>`). #' @param csi What to do with non-SGR ANSI sequences, either `"keep"`, #' or `"drop"` them. #' @return Character vector of HTML. #' #' @family ANSI to HTML conversion #' @export #' @examplesIf cli:::has_packages(c("htmltools", "withr")) #' ## Syntax highlight the source code of an R function with ANSI tags, #' ## and export it to a HTML file. #' code <- withr::with_options( #' list(ansi.num_colors = 256), #' code_highlight(format(ansi_html)) #' ) #' hcode <- paste(ansi_html(code), collapse = "\n") #' css <- paste(format(ansi_html_style()), collapse= "\n") #' page <- htmltools::tagList( #' htmltools::tags$head(htmltools::tags$style(css)), #' htmltools::tags$pre(htmltools::HTML(hcode)) #' ) #' #' if (interactive()) htmltools::html_print(page) ansi_html <- function(x, escape_reserved = TRUE, csi = c("drop", "keep")) { if (!is.character(x)) x <- as.character(x) csi <- match.arg(csi) x <- enc2utf8(x) if (escape_reserved) { x <- gsub_("&", "&", x, fixed = TRUE, useBytes = TRUE) x <- gsub_("<", "<", x, fixed = TRUE, useBytes = TRUE) x <- gsub_(">", ">", x, fixed = TRUE, useBytes = TRUE) } .Call(clic_ansi_html, x, csi == "keep") } #' CSS styles for the output of `ansi_html()` #' #' #' #' @param colors Whether or not to include colors. `FALSE` will not include #' colors, `TRUE` or `8` will include eight colors (plus their bright #' variants), `256` will include 256 colors. #' @param palette Character scalar, palette to use for the first eight colors #' plus their bright variants. Terminals define these colors differently, #' and cli includes a couple of examples. Sources of palettes: #' * https://en.wikipedia.org/wiki/ANSI_escape_code#3-bit_and_4-bit #' * iTerm2 builtin palettes #' * #' @return Named list of CSS declaration blocks, where the names are #' CSS selectors. It has a `format()` and `print()` methods, which you #' can use to write the output to a CSS or HTML file. #' #' @family ANSI to HTML conversion #' @export #' @examples #' ansi_html_style(colors = FALSE) #' ansi_html_style(colors = 8, palette = "iterm-snazzy") ansi_html_style <- function(colors = TRUE, palette = NULL) { if (is.character(palette)) { palette <- match.arg(palette) palette <- as.list(ansi_palettes[palette, ]) } stopifnot( isTRUE(colors) || identical(colors, FALSE) || (is_count(colors) && colors %in% c(8,256)), is_string(palette) || is.list(palette) && length(palette) == 16 ) ret <- list( ".ansi-bold" = "{ font-weight: bold; }", # .ansi-faint ??? ".ansi-italic" = "{ font-style: italic; }", ".ansi-underline" = "{ text-decoration: underline; }", ".ansi-blink" = "{ text-decoration: blink; }", # .ansi-inverse ??? ".ansi-hide" = "{ visibility: hidden; }", ".ansi-crossedout" = "{ text-decoration: line-through; }", ".ansi-link:hover" = "{ text-decoration: underline; }" ) if (!identical(colors, FALSE)) { fg <- structure( names = paste0(".ansi-color-", 0:15), paste0("{ color: ", palette, " }") ) bg <- structure( names = paste0(".ansi-bg-color-", 0:15), paste0("{ background-color: ", palette, " }") ) ret <- c(ret, fg, bg) } if (isTRUE(colors) || colors == 256) { grid <- expand.grid(r = 0:5, g = 0:5, b = 0:5) num <- 16 + 36 * grid$r + 6 * grid$g + grid$b cols <- grDevices::rgb(grid$r, grid$g, grid$b, maxColorValue = 5) fg256 <- structure( names = paste0(".ansi-color-", num), paste0("{ color: ", tolower(cols), " }") ) bg256 <- structure( names = paste0(".ansi-bg-color-", num), paste0("{ background-color: ", tolower(cols), " }") ) gr <- seq(1, 24) grcols <- grDevices::rgb(gr, gr, gr, maxColorValue = 25) fggrey <- structure( names = paste0(".ansi-color-", 232:255), paste0("{ color: ", tolower(grcols), " }") ) bggrey <- structure( names = paste0(".ansi-bg-color-", 232:255), paste0("{ background-color: ", tolower(grcols), " }") ) ret <- c(ret, fg256, fggrey, bg256, bggrey) } class(ret) <- "cli_ansi_html_style" ret } # This avoids duplication, but messes up the source ref of the function... formals(ansi_html_style)$palette <- c("vscode", setdiff(rownames(ansi_palettes), "vscode")) attr(body(ansi_html_style), "srcref") <- NULL attr(body(ansi_html_style), "wholeSrcref") <- NULL attr(body(ansi_html_style), "srcfile") <- NULL #' @export format.cli_ansi_html_style <- function(x, ...) { paste0(format(names(x)), " ", x) } #' @export print.cli_ansi_html_style <- function(x, ...) { cat(format(x, ...), sep = "\n") } #' Like [base::grep()] and [base::grepl()], but for ANSI strings #' #' First ANSI sequences will be stripped with [ansi_strip()], both #' #' Note that these functions work on code points (or bytes if #' `useBytes = TRUE`), and not graphemes. #' #' Unlike [base::grep()] and [base::grepl()] these functions do not special #' case factors. #' #' Both `pattern` and `x` are converted to UTF-8. #' #' @param pattern Character scalar, regular expression or fixed string #' (if `fixed = TRUE`), the pattern to search for. Other objects will be #' coerced using [as.character()]. #' @param x Character vector to search in. Other objects will be coerced #' using [as.character()]. #' @param ignore.case,perl,value Passed to [base::grep()]. #' @param ... Extra arguments are passed to [base::grep()] or [base::grepl()]. #' @return The same as [base::grep()] and [base::grepl()], respectively. #' #' @export #' @examples #' red_needle <- col_red("needle") #' haystack <- c("foo", "needle", "foo") #' green_haystack <- col_green(haystack) #' ansi_grepl(red_needle, haystack) #' ansi_grepl(red_needle, green_haystack) ansi_grep <- function(pattern, x, ignore.case = FALSE, perl = FALSE, value = FALSE, ...) { # if value = FALSE, then we want to return the original values as # ansi strings, so we need to special case that if (value) { idx <- ansi_grep(pattern, x, ignore.case = ignore.case, perl = perl, value = FALSE, ...) ansi_string(x[idx]) } else { ansi_grep_internal(grep, pattern, x, ignore.case = ignore.case, perl = perl, value = value, ...) } } #' @rdname ansi_grep #' @export ansi_grepl <- function(pattern, x, ...) { ansi_grep_internal(grepl, pattern, x, ...) } ansi_grep_internal <- function(fun, pattern, x, ...) { pattern <- ansi_strip(pattern) x <- ansi_strip(x) fun(pattern, x, ...) } #' Like [base::nzchar()], but for ANSI strings #' #' @param x Charcater vector. Other objects are coarced using #' [base::as.character()]. #' @param ... Passed to [base::nzchar()]. #' @export #' @examples #' ansi_nzchar("") #' ansi_nzchar(col_red("")) ansi_nzchar <- function(x, ...) { x <- ansi_strip(x) nzchar(x, ...) } cli/R/sizes.R0000644000176200001440000000557614557444176012540 0ustar liggesusers format_bytes <- local({ pretty_bytes <- function(bytes, style = c("default", "nopad", "6")) { style <- switch( match.arg(style), "default" = pretty_bytes_default, "nopad" = pretty_bytes_nopad, "6" = pretty_bytes_6 ) style(bytes) } compute_bytes <- function(bytes, smallest_unit = "B") { units0 <- c("B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB") stopifnot( is.numeric(bytes), is.character(smallest_unit), length(smallest_unit) == 1, !is.na(smallest_unit), smallest_unit %in% units0 ) limits <- c(1000, 999950 * 1000 ^ (seq_len(length(units0) - 2) - 1)) low <- match(smallest_unit, units0) units <- units0[low:length(units0)] limits <- limits[low:length(limits)] neg <- bytes < 0 & !is.na(bytes) bytes <- abs(bytes) mat <- matrix( rep(bytes, each = length(limits)), nrow = length(limits), ncol = length(bytes) ) mat2 <- matrix(mat < limits, nrow = length(limits), ncol = length(bytes)) exponent <- length(limits) - colSums(mat2) + low - 1L res <- bytes / 1000 ^ exponent unit <- units[exponent - low + 2L] ## Zero bytes res[bytes == 0] <- 0 unit[bytes == 0] <- units[1] ## NA and NaN bytes res[is.na(bytes)] <- NA_real_ res[is.nan(bytes)] <- NaN unit[is.na(bytes)] <- units0[low] # Includes NaN as well data.frame( stringsAsFactors = FALSE, amount = res, unit = unit, negative = neg ) } pretty_bytes_default <- function(bytes) { szs <- compute_bytes(bytes) amt <- szs$amount ## String. For fractions we always show two fraction digits res <- character(length(amt)) int <- is.na(amt) | amt == as.integer(amt) res[int] <- format( ifelse(szs$negative[int], -1, 1) * amt[int], scientific = FALSE ) res[!int] <- sprintf("%.2f", ifelse(szs$negative[!int], -1, 1) * amt[!int]) format(paste(res, szs$unit), justify = "right") } pretty_bytes_nopad <- function(bytes) { sub("^\\s+", "", pretty_bytes_default(bytes)) } pretty_bytes_6 <- function(bytes) { szs <- compute_bytes(bytes, smallest_unit = "kB") amt <- szs$amount na <- is.na(amt) nan <- is.nan(amt) neg <- !na & !nan & szs$negative l10 <- !na & !nan & !neg & amt < 10 l100 <- !na & !nan & !neg & amt >= 10 & amt < 100 b100 <- !na & !nan & !neg & amt >= 100 szs$unit[neg] <- "kB" famt <- character(length(amt)) famt[na] <- " NA" famt[nan] <- "NaN" famt[neg] <- "< 0" famt[l10] <- sprintf("%.1f", amt[l10]) famt[l100] <- sprintf(" %.0f", amt[l100]) famt[b100] <- sprintf("%.0f", amt[b100]) paste0(famt, " ", szs$unit) } structure( list( .internal = environment(), pretty_bytes = pretty_bytes, compute_bytes = compute_bytes ), class = c("standalone_bytes", "standalone") ) }) cli/R/progress-c.R0000644000176200001440000000243214557444176013453 0ustar liggesusers progress_c_update <- function(pb, auto_done = TRUE) { cli_tick_reset() caller <- pb$caller %||% sys.frame(sys.nframe() - 1L) pb$tick <- pb$tick + 1L if (is.null(pb$format)) { pb$format <- pb__default_format(pb$type, pb$total) } if (pb$auto_terminate && auto_done && !is.na(pb$total) && pb$current == pb$total) { progress_c_done(pb, caller = caller) return(NULL) } opt <- options(cli__pb = pb) on.exit(options(opt), add = TRUE) handlers <- cli_progress_select_handlers(pb, caller) if (is.null(pb$added)) { pb$added <- TRUE for (h in handlers) { if ("add" %in% names(h)) h$add(pb, .envir = caller) } } for (h in handlers) { if ("set" %in% names(h)) h$set(pb, .envir = caller) } NULL } progress_c_done <- function(pb, caller = NULL) { if (isTRUE(pb$done)) return() caller <- caller %||% pb$caller %||% sys.frame(sys.nframe() - 1L) opt <- options(cli__pb = pb) on.exit(options(opt), add = TRUE) handlers <- cli_progress_select_handlers() for (h in handlers) { if ("complete" %in% names(h)) { h$complete(pb, .envir = caller, result = "done") } } if (!is.null(pb$id)) clienv$progress[[pb$id]] <- NULL if (!is.null(pb$envkey)) clienv$progress_ids[[pb$envkey]] <- NULL pb$done <- TRUE NULL } cli/R/ansi-hyperlink.R0000644000176200001440000004047214752735214014323 0ustar liggesusers #' Auto-linking existing styles #' #' They keep formatting. It is not possible to use a different link text #' with them. We could add link text support, but theming is applied to the #' result of these tags, and it would look weird for link text. (I.e. if #' there is link text you don't want to append `()` to the function name, #' etc.) #' #' N | Goal | Input |Links to (link text is always the verbatim content, styled) #' --|---------------------------------------------|---------------------------------|--------------------------------------------------------------------- #' 1 | auto-link emails | `{.email foo@bar.com}` | `mailto:foo@bar.com` #' 2 | auto-link file | `{.file path/file}` | `file:///abs/path/dile` #' 3 | auto-link file with line and column numbers | `{.file /abs/path:line:col}` | `file:///abs/path:line:col`, `params = list(line = line, col = col)` #' 4 | auto-link function | `{.fun pkg::fun}` | `x-r-help:pkg::fun` #' 5 | mention function w/o package | `{.fun fun}` | no link is created for this form #' 6 | auto-link url | `{.url url}` | `url` #' #' ## New styles to create links #' #' These all have link text support, via the `[text](link)` markdown syntax. #' #' N | Goal | Input | Link text | Links to | Non-link form #' --|---------------------------------------------|---------------------------------|-------------------|--------------------------|------------------------------------ #' 7 | link qualified function name to help | `{.help pkg::fun}` | `{.fun pkg::fun}` | `x-r-help:pkg::fun` | `{.fun ?pkg::fun}` #' 8 | link to function with link text | `{.help [text](pkg::fun)}` | `text` | `x-r-help:pkg::fun` | `text ({.fun pkg::fun})` #' 9 | link to topic | `{.topic pkg::topic}` | `pkg::topic` | `x-r-help:pkg::topic` | `{.code pkg::topic}` #' 10| link to topic with link text | `{.topic [text](pkg::topic)}` | `text` | `x-r-help:pkg::topic` | `text ({.code pkg::topic})` #' 11| link url | `{.href url}` | `{.url url}` | `url` | `{.url url}` #' 12| link url with link text | `{.href [text](url)}` | `text` | `url` | `text ({.url url})` #' 13| link running expr | `{.run expr}` | `{.code expr}` | `x-r-run:expr` | `{.code expr}` #' 14| link running expr, show code | `{.run [code](expr)}` | `{.code code}` | `x-r-run:expr` | `{.code expr}` #' 15| link to vignette | `{.vignette pkg::name}` | `pkg::name` | `x-r-vignette:pkg::name` | `{.code vignette(pkg::name)}` #' 16| link to vignette with link text | `{.vignette [text](pkg::name)}` | `text` | `x-r-vignette:pkg::name` | `text ({.code vignette(pkg::name)})` #' #' @name cli-links #' @noRd NULL make_link <- function(txt, type = c("email", "file", "fun", "help", "href", "run", "topic", "url", "vignette")) { type <- match.arg(type) switch( type, email = make_link_email(txt), file = make_link_file(txt), fun = make_link_fun(txt), help = make_link_help(txt), href = make_link_href(txt), run = make_link_run(txt), topic = make_link_topic(txt), url = make_link_url(txt), vignette = make_link_vignette(txt), throw(cli_error("Unknown hyperlink type: {.code {type}}, internal cli error")) # nocov ) } # -- {.email} ------------------------------------------------------------- make_link_email <- function(txt) { style_hyperlink(txt, paste0("mailto:", txt)) } # -- {.file} and {.path} -------------------------------------------------- # if txt already contains a hyperlink, then we do not add another link # this is needed because some packages, e.g. roxygen2 currently create # links to files manually: # https://github.com/r-lib/roxygen2/blob/3ddfd7f2e35c3a71d5705ab4f49e851cd8da306d/R/utils.R#L91 make_link_file <- function(txt) { ret <- txt linked <- grepl("\007|\033\\\\", txt) ret[!linked] <- vcapply(which(!linked), function(i) { params <- parse_file_link_params(txt[i]) link <- construct_file_link(params) style_hyperlink( txt[i], link$url, params = link$params ) }) ret } parse_file_link_params <- function(txt) { pattern <- "^(?.*?)(?::(?\\d*))?(?::(?\\d*))?$" matches <- re_match(txt, pattern) ret <- as.list(matches) ret[!nzchar(ret)] <- list(NULL) if (is.null(ret[["path"]])) ret[["path"]] <- "" ret } construct_file_link <- function(params) { fmt <- get_config_chr("hyperlink_file_url_format") if (is.null(fmt)) { return(construct_file_link_OG(params)) } params$path <- sub("^file://", "", params$path) params$path <- path.expand(params$path) looks_absolute <- function(path) { grepl("^/", params$path) || (is_windows() && grepl("^[a-zA-Z]:", params$path)) } if (!looks_absolute(params$path)) { params$path <- file.path(getwd(), params$path) } if (!grepl("^/", params$path)) { params$path <- paste0("/", params$path) } res <- interpolate_parts(fmt, params) list(url = res) } # the order of operations is very intentional and important: # column, then line, then path # relates to how interpolate_part() works interpolate_parts <- function(fmt, params) { res <- interpolate_part(fmt, "column", params$column) res <- interpolate_part(res, "line", params$line) interpolate_part(res, "path", params$path) } # interpolate a part, if possible # if no placeholder for part, this is a no-op # if placeholder exists, but no value to fill, remove placeholder (and everything after it!) interpolate_part <- function(fmt, part = c("column", "line", "path"), value = NULL) { part <- match.arg(part) re <- glue( "^(?.*)(?\\{<<>>\\})(?.*?)$", .open = "<<<", .close = ">>>" ) m <- re_match(fmt, re) if (is.na(m$part) || !nzchar(m$part)) { return(fmt) } if (is.null(value) || !nzchar(value)) { return(sub("}[^}]*$", "}", m$before)) } paste0(m$before, value, m$after) } # handle the iterm and RStudio cases, which predated the notion of configuring # the file hyperlink format construct_file_link_OG <- function(params) { params$path <- abs_path(params$path) if (Sys.getenv("R_CLI_HYPERLINK_STYLE") == "iterm") { fmt <- "{path}#{line}:{column}" res <- interpolate_parts(fmt, params) return(list(url = res)) } # RStudio takes line and col via params loc <- if (is.null(params$line)) { NULL } else { list(line = params$line, col = params$column %||% 1) } list(url = params$path, params = loc) } abs_path <- function(x) { x <- path.expand(x) vcapply(x, abs_path1, USE.NAMES = FALSE) } abs_path1 <- function(x) { if (grepl("^file://", x)) return(x) if (grepl("^/", x)) return(paste0("file://", x)) if (is_windows() && grepl("^[a-zA-Z]:", x)) return(paste0("file://", x)) paste0("file://", file.path(getwd(), x)) } # -- {.fun} --------------------------------------------------------------- make_link_fun <- function(txt) { tolink <- grepl("::", txt, fixed = TRUE) linked <- grepl("\007|\033\\\\", txt) todo <- tolink & !linked if (!any(todo)) return(txt) sprt <- ansi_hyperlink_types()$help if (!sprt) { return(txt) } fmt <- get_hyperlink_format("help") # the format has a placeholder for 'topic' topic <- txt[todo] done <- style_hyperlink(text = topic, url = glue(fmt)) txt[todo] <- done txt } # -- {.help} -------------------------------------------------------------- make_link_help <- function(txt) { mch <- re_match(txt, "^\\[(?.*)\\]\\((?.*)\\)$") text <- ifelse(is.na(mch$text), txt, mch$text) topic <- ifelse(is.na(mch$url), txt, mch$url) sprt <- ansi_hyperlink_types()$help if (!sprt) { topic2 <- vcapply(topic, function(x) format_inline("{.fun ?{x}}")) return(ifelse(text == topic, topic2, paste0(text, " (", topic2, ")"))) } fmt <- get_hyperlink_format("help") style_hyperlink(text = text, url = glue(fmt)) } # -- {.href} -------------------------------------------------------------- make_link_href <- function(txt) { mch <- re_match(txt, "^\\[(?.*)\\]\\((?.*)\\)$") text <- ifelse(is.na(mch$text), txt, mch$text) url <- ifelse(is.na(mch$url), txt, mch$url) if (ansi_has_hyperlink_support()) { link <- style_hyperlink(text = text, url = url) style <- is.na(mch$text) link[style] <- vcapply( url[style], function(url1) format_inline("{.url {url1}}") ) link } else { url2 <- vcapply(url, function(url1) format_inline("{.url {url1}}")) ifelse(text == url, url2, paste0(text, " (", url2, ")")) } } # -- {.run} --------------------------------------------------------------- make_link_run <- function(txt) { mch <- re_match(txt, "^\\[(?.*)\\]\\((?.*)\\)$") text <- ifelse(is.na(mch$text), txt, mch$text) code <- ifelse(is.na(mch$url), txt, mch$url) sprt <- ansi_hyperlink_types()$run if (!sprt) { return(vcapply(text, function(code1) format_inline("{.code {code1}}"))) } fmt <- get_hyperlink_format("run") style_hyperlink(text = text, url = glue(fmt)) } # -- {.topic} ------------------------------------------------------------- make_link_topic <- function(txt) { mch <- re_match(txt, "^\\[(?.*)\\]\\((?.*)\\)$") text <- ifelse(is.na(mch$text), txt, mch$text) topic <- ifelse(is.na(mch$url), txt, mch$url) sprt <- ansi_hyperlink_types()$help if (!sprt) { topic2 <- vcapply(topic, function(x) format_inline("{.code ?{x}}")) return(ifelse(text == topic, topic2, paste0(text, " (", topic2, ")"))) } fmt <- get_hyperlink_format("help") style_hyperlink(text = text, url = glue(fmt)) } # -- {.url} --------------------------------------------------------------- make_link_url <- function(txt) { linked <- grepl("\007|\033\\\\", txt) if (all(linked)) return(txt) txt[!linked] <- style_hyperlink(txt[!linked], txt[!linked]) txt } # -- {.vignette} ---------------------------------------------------------- make_link_vignette <- function(txt) { mch <- re_match(txt, "^\\[(?.*)\\]\\((?.*)\\)$") text <- ifelse(is.na(mch$text), txt, mch$text) vignette <- ifelse(is.na(mch$url), txt, mch$url) sprt <- ansi_hyperlink_types()$vignette if (!sprt) { vignette2 <- vcapply(vignette, function(x) format_inline("{.code vignette({x})}")) return(ifelse(text == vignette, vignette2, paste0(text, " (", vignette2, ")"))) } fmt <- get_hyperlink_format("vignette") style_hyperlink(text = text, url = glue(fmt)) } #' Terminal Hyperlinks #' #' `ansi_hyperlink()` creates an ANSI hyperlink. #' #' @details #' This function is currently experimental. In particular, many of the #' `ansi_*()` functions do not support it properly. #' #' `ansi_has_hyperlink_support()` checks if the current `stdout()` #' supports hyperlinks. #' #' See also #' . #' #' @param text Text to show. `text` and `url` are recycled to match their #' length, via a `paste0()` call. #' @param url URL to link to. #' @param params A named character vector of additional parameters, or `NULL`. #' @return Styled `cli_ansi_string` for `style_hyperlink()`. #' Logical scalar for `ansi_has_hyperlink_support()`. #' #' @export #' @examples #' cat("This is an", style_hyperlink("R", "https://r-project.org"), "link.\n") style_hyperlink <- function(text, url, params = NULL) { params <- if (length(params)) { paste( names(params), "=", params, collapse = ":" ) } if (Sys.getenv("R_CLI_HYPERLINK_MODE") == "posix") { ST <- "\033\\" } else { ST <- "\u0007" } out <- if (ansi_has_hyperlink_support()) { paste0("\u001B]8;", params, ";", url, ST, text, "\u001B]8;;", ST) } else { text } class(out) <- c("cli_ansi_string", "ansi_string", "character") out } #' @export #' @rdname style_hyperlink #' @examples #' ansi_has_hyperlink_support() ansi_has_hyperlink_support <- function() { ## Hyperlinks forced? enabled <- getOption("cli.hyperlink", getOption("crayon.hyperlink")) if (!is.null(enabled)) { return(isTRUE(enabled)) } ## forced by environment variable enabled <- Sys.getenv("R_CLI_HYPERLINKS", "") if (isTRUE(as.logical(enabled))){ return(TRUE) } ## If ANSI support is off, then this is off as well if (num_ansi_colors() == 1) return(FALSE) ## Are we in RStudio? rstudio <- rstudio_detect() if (rstudio$type != "not_rstudio") { return(rstudio$hyperlink) } ## Are we in a terminal? No? if (!isatty(stdout())) { return(FALSE) } ## Are we in a windows terminal? if (is_windows() && Sys.getenv("WT_SESSION") != "") { return(TRUE) } ## Better to avoid it in CIs if (nzchar(Sys.getenv("CI")) || nzchar(Sys.getenv("TEAMCITY_VERSION"))) { return(FALSE) } ## iTerm if (nzchar(TERM_PROGRAM <- Sys.getenv("TERM_PROGRAM"))) { version <- package_version( Sys.getenv("TERM_PROGRAM_VERSION"), strict = FALSE) if (TERM_PROGRAM == "iTerm.app") { if (!is.na(version) && version >= "3.1") return(TRUE) } } if (nzchar(VTE_VERSION <- Sys.getenv("VTE_VERSION"))) { # See #441 -- some apparent heterogeneity in how the version gets # encoded to this env variable. Accept either form. if (grepl("^\\d{4}$", VTE_VERSION)) { VTE_VERSION <- sprintf("%2.02f", as.numeric(VTE_VERSION) / 100) VTE_VERSION <- package_version(list(major = "0", minor = VTE_VERSION)) } else { VTE_VERSION <- package_version(VTE_VERSION, strict = FALSE) if (is.na(VTE_VERSION)) { VTE_VERSION <- package_version("0.1.0") } } if (VTE_VERSION >= "0.50.1") return(TRUE) } FALSE } #' @details #' `ansi_hyperlink_types()` checks if current `stdout()` supports various #' types of hyperlinks. It returns a list with entries `href`, `run`, #' `help` and `vignettes`. #' #' @rdname style_hyperlink #' @export ansi_hyperlink_types <- function() { get_config <- function(x, default = NULL) { opt <- getOption(paste0("cli.", tolower(x))) if (!is.null(opt)) return(isTRUE(opt)) env <- Sys.getenv(paste0("R_CLI_", toupper(x)), NA_character_) if (!is.na(env)) return(isTRUE(as.logical(env))) default } rs <- rstudio_detect() has <- ansi_has_hyperlink_support() # they are on by default in RStudio, but not otherwise run <- get_config("hyperlink_run", default = rs$hyperlink) hlp <- get_config("hyperlink_help", default = rs$hyperlink) vgn <- get_config("hyperlink_vignette", default = rs$hyperlink) if (!has) { list( href = FALSE, run = FALSE, help = FALSE, vignette = FALSE ) } else if (isTRUE(rs$hyperlink)) { list( href = TRUE, run = structure(run, type = "rstudio"), help = structure(hlp, type = "rstudio"), vignette = structure(vgn, type = "rstudio") ) } else { list( href = TRUE, run = structure(run, type = "standard"), help = structure(hlp, type = "standard"), vignette = structure(vgn, type = "standard") ) } } get_hyperlink_format <- function(type = c("run", "help", "vignette")) { type <- match.arg(type) key <- glue("hyperlink_{type}_url_format") sprt <- ansi_hyperlink_types()[[type]] custom_fmt <- get_config_chr(key) if (is.null(custom_fmt)) { if (identical(attr(sprt, "type"), "rstudio")) { fmt_type <- "rstudio" } else { fmt_type <- "standard" } } else { fmt_type <- "custom" } variable <- c(run = "code", help = "topic", vignette = "vignette") fmt <- switch( fmt_type, custom = custom_fmt, rstudio = glue("ide:{type}:{{{variable[type]}}}"), standard = glue("x-r-{type}:{{{variable[type]}}}") ) fmt } get_config_chr <- function(x, default = NULL) { opt <- getOption(paste0("cli.", tolower(x))) if (!is.null(opt)) { stopifnot(is_string(opt)) return(opt) } env <- Sys.getenv(paste0("R_CLI_", toupper(x)), NA_character_) if (!is.na(env)) return(env) default } cli/R/progress-bar.R0000644000176200001440000000572414557444176014004 0ustar liggesusers make_progress_bar <- function(percent, width = 30, style = list()) { complete_len <- round(width * percent) def <- default_progress_style() chr_complete <- style[["progress-complete"]] %||% def[["complete"]] chr_incomplete <- style[["progress-incomplete"]] %||% def[["incomplete"]] chr_current <- style[["progress-current"]] %||% def[["current"]] complete <- paste(rep(chr_complete, complete_len), collapse = "") current <- if (percent == 100) chr_complete else chr_current incomplete <- paste(rep(chr_incomplete, width - complete_len), collapse = "") paste0(complete, current, incomplete, " ") } default_progress_style <- function() { opt <- progress_style(getOption("cli.progress_bar_style")) if (is_utf8_output()) { opu <- progress_style(getOption("cli.progress_bar_style_unicode")) list( complete = opu$complete %||% opt$complete %||% "\u25A0", current = opu$current %||% opt$current %||% opu$complete %||% opt$complete %||% "\u25A0", incomplete = opu$incomplete %||% opt$incomplete %||% "\u00a0" ) } else { opa <- progress_style(getOption("cli.progress_bar_style_ascii")) list( complete = opa$complete %||% opt$complete %||% "=", current = opa$current %||% opt$current %||% opa$complete %||% opt$complete %||% ">", incomplete = opa$incomplete %||% opt$incomplete %||% "-" ) } } progress_style <- function(x) { if (is.null(x)) return(x) if (is_string(x)) return(cli_progress_styles()[[x]]) x } #' List of built-in cli progress styles #' #' The following options are used to select a style: #' * `cli_progress_bar_style` #' * `cli_progress_bar_style_ascii` #' * `cli_progress_bar_style_unicode` #' #' On Unicode terminals (if [is_utf8_output()] is `TRUE`), the #' `cli_progress_bar_style_unicode` and `cli_progress_bar_style` #' options are used. #' #' On ASCII terminals (if [is_utf8_output()] is `FALSE`), the #' `cli_pgoress_bar_style_ascii` and `cli_progress_bar_style` options #' are are used. #' #' ```{asciicast progress-style} #' for (style in names(cli_progress_styles())) { #' options(cli.progress_bar_style = style) #' label <- ansi_align(paste0("Style '", style, "'"), 20) #' print(cli_progress_demo(label, live = FALSE, at = 66, total = 100)) #' } #' options(cli.progress_var_style = NULL) #' ``` #' #' @return A named list with sublists containing elements #' `complete`, `incomplete` and potentially `current`. #' #' @family progress bar functions #' @export cli_progress_styles <- function() { list( classic = list( complete = "#", incomplete = "\u00a0" ), squares = list( complete = "\u25a0", incomplete = "\u00a0" ), dot = list( complete = col_grey("\u2500"), incomplete = col_grey("\u2500"), current = col_red(symbol$record) ), fillsquares = list( complete = "\u25a0", incomplete = col_grey("\u25a1") ), bar = list( complete = "\u2588", incomplete = col_grey("\u2588") ) ) } cli/R/unicode.R0000644000176200001440000000374014557444176013020 0ustar liggesusers #' Working around the bad Unicode character widths #' #' R 3.6.2 and also the coming 3.6.3 and 4.0.0 versions use the Unicode 8 #' standard to calculate the display width of Unicode characters. #' Unfortunately the widths of most emojis are incorrect in this standard, #' and width 1 is reported instead of the correct 2 value. #' #' cli implements a workaround for this. The package contains a table that #' contains all Unicode ranges that have wide characters (display width 2). #' #' On first use of one of the workaround wrappers (in `ansi_nchar()`, etc.) #' we check what the current version of R thinks about the width of these #' characters, and then create a regex that matches the ones that R #' is wrong about (`re_bad_char_width`). #' #' Then we use this regex to duplicate all of the problematic characters #' in the input string to the wrapper function, before calling the real #' string manipulation function (`nchar()`, `strwrap()`) etc. At end we #' undo the duplication before we return the result. #' #' This workaround is fine for `nchar()` and `strwrap()`, and consequently #' `ansi_align()` and `ansi_strtrim()` as well. #' #' The rest of the `ansi_*()` functions work on characters, and do not #' deal with character width. #' #' @keywords internal #' @name unicode-width-workaround NULL setup_unicode_width_fix <- function() { bad <- base::nchar(wide_chars$test, type = "width") == 1 re <- paste0(wide_chars$regex[bad], collapse = "") clienv$re_bad_char_width <- paste0("([", re, "])") clienv$re_bad_char_width_fix <- paste0("([", re, "])\\1") } unicode_pre <- function(x) { if (is.null(clienv$re_bad_char_width)) setup_unicode_width_fix() if (clienv$re_bad_char_width != "([])") { x <- gsub(clienv$re_bad_char_width, "\\1\\1", x, perl = TRUE) } x } unicode_post <- function(x) { if (is.null(clienv$re_bad_char_width)) setup_unicode_width_fix() if (clienv$re_bad_char_width != "([])") { x <- gsub(clienv$re_bad_char_width_fix, "\\1", x, perl = TRUE) } x } cli/R/errors.R0000644000176200001440000010632614557444176012712 0ustar liggesusers # # Standalone file for better error handling ---------------------------- # # If can allow package dependencies, then you are probably better off # using rlang's functions for errors. # # The canonical location of this file is in the processx package: # https://github.com/r-lib/processx/blob/main/R/errors.R # # ## Dependencies # - rstudio-detect.R for better printing in RStudio # # ## Features # # - Throw conditions and errors with the same API. # - Automatically captures the right calls and adds them to the conditions. # - Sets `.Last.error`, so you can easily inspect the errors, even if they # were not caught. # - It only sets `.Last.error` for the errors that are not caught. # - Hierarchical errors, to allow higher level error messages, that are # more meaningful for the users, while also keeping the lower level # details in the error object. (So in `.Last.error` as well.) # - `.Last.error` always includes a stack trace. (The stack trace is # common for the whole error hierarchy.) The trace is accessible within # the error, e.g. `.Last.error$trace`. The trace of the last error is # also at `.Last.error.trace`. # - Can merge errors and traces across multiple processes. # - Pretty-print errors and traces, if the cli package is loaded. # - Automatically hides uninformative parts of the stack trace when # printing. # # ## API # # ``` # new_cond(..., call. = TRUE, srcref = NULL, domain = NA) # new_error(..., call. = TRUE, srcref = NULL, domain = NA) # throw(cond, parent = NULL, frame = environment()) # throw_error(cond, parent = NULL, frame = environment()) # chain_error(expr, err, call = sys.call(-1)) # chain_call(.NAME, ...) # chain_clean_call(.NAME, ...) # onload_hook() # add_trace_back(cond, frame = NULL) # format$advice(x) # format$call(call) # format$class(x) # format$error(x, trace = FALSE, class = FALSE, advice = !trace, ...) # format$error_heading(x, prefix = NULL) # format$header_line(x, prefix = NULL) # format$srcref(call, srcref = NULL) # format$trace(x, ...) # ``` # # ## Roadmap: # - better printing of anonymous function in the trace # # ## NEWS: # # ### 1.0.0 -- 2019-06-18 # # * First release. # # ### 1.0.1 -- 2019-06-20 # # * Add `rlib_error_always_trace` option to always add a trace # # ### 1.0.2 -- 2019-06-27 # # * Internal change: change topenv of the functions to baseenv() # # ### 1.1.0 -- 2019-10-26 # # * Register print methods via onload_hook() function, call from .onLoad() # * Print the error manually, and the trace in non-interactive sessions # # ### 1.1.1 -- 2019-11-10 # # * Only use `trace` in parent errors if they are `rlib_error`s. # Because e.g. `rlang_error`s also have a trace, with a slightly # different format. # # ### 1.2.0 -- 2019-11-13 # # * Fix the trace if a non-thrown error is re-thrown. # * Provide print_this() and print_parents() to make it easier to define # custom print methods. # * Fix annotating our throw() methods with the incorrect `base::`. # # ### 1.2.1 -- 2020-01-30 # # * Update wording of error printout to be less intimidating, avoid jargon # * Use default printing in interactive mode, so RStudio can detect the # error and highlight it. # * Add the rethrow_call_with_cleanup function, to work with embedded # cleancall. # # ### 1.2.2 -- 2020-11-19 # # * Add the `call` argument to `catch_rethrow()` and `rethrow()`, to be # able to omit calls. # # ### 1.2.3 -- 2021-03-06 # # * Use cli instead of crayon # # ### 1.2.4 -- 2021-04-01 # # * Allow omitting the call with call. = FALSE in `new_cond()`, etc. # # ### 1.3.0 -- 2021-04-19 # # * Avoid embedding calls in trace with embed = FALSE. # # ### 2.0.0 -- 2021-04-19 # # * Versioned classes and print methods # # ### 2.0.1 -- 2021-06-29 # # * Do not convert error messages to native encoding before printing, # to be able to print UTF-8 error messages on Windows. # # ### 2.0.2 -- 2021-09-07 # # * Do not translate error messages, as this converts them to the native # encoding. We keep messages in UTF-8 now. # # ### 3.0.0 -- 2022-04-19 # # * Major rewrite, use rlang compatible error objects. New API. # # ### 3.0.1 -- 2022-06-17 # # * Remove the `rlang_error` and `rlang_trace` classes, because our new # deparsed `call` column in the trace is not compatible with rlang. # # ### 3.0.2 -- 2022-08-01 # # * Use a `procsrcref` column for processed source references. # Otherwise testthat (and probably other rlang based packages), will # pick up the `srcref` column, and they expect an `srcref` object there. # # ### 3.1.0 -- 2022-10-04 # # * Add ANSI hyperlinks to stack traces, if we have a recent enough # cli package that supports this. # # ### 3.1.1 -- 2022-11-17 # # * Use `[[` instead of `$` to fix some partial matches. # * Use fully qualified `base::stop()` to enable overriding `stop()` # in a package. (Makes sense if compat files use `stop()`. # * The `is_interactive()` function is now exported. # # ### 3.1.2 -- 2022-11-18 # # * The `parent` condition can now be an interrupt. # # ### 3.1.3 -- 2023-01-15 # # * Now we do not load packages when walking the trace. err <- local({ # -- dependencies ----------------------------------------------------- rstudio_detect <- rstudio$detect # -- condition constructors ------------------------------------------- #' Create a new condition #' #' @noRd #' @param ... Parts of the error message, they will be converted to #' character and then concatenated, like in [stop()]. #' @param call. A call object to include in the condition, or `TRUE` #' or `NULL`, meaning that [throw()] should add a call object #' automatically. If `FALSE`, then no call is added. #' @param srcref Alternative source reference object to use instead of #' the one of `call.`. #' @param domain Translation domain, see [stop()]. We set this to #' `NA` by default, which means that no translation occurs. This #' has the benefit that the error message is not re-encoded into #' the native locale. #' @return Condition object. Currently a list, but you should not rely #' on that. new_cond <- function(..., call. = TRUE, srcref = NULL, domain = NA) { message <- .makeMessage(..., domain = domain) structure( list(message = message, call = call., srcref = srcref), class = c("condition")) } #' Create a new error condition #' #' It also adds the `rlib_error` class. #' #' @noRd #' @param ... Passed to [new_cond()]. #' @param call. Passed to [new_cond()]. #' @param srcref Passed tp [new_cond()]. #' @param domain Passed to [new_cond()]. #' @return Error condition object with classes `rlib_error`, `error` #' and `condition`. new_error <- function(..., call. = TRUE, srcref = NULL, domain = NA) { cond <- new_cond(..., call. = call., domain = domain, srcref = srcref) class(cond) <- c("rlib_error_3_0", "rlib_error", "error", "condition") cond } # -- throwing conditions ---------------------------------------------- #' Throw a condition #' #' If the condition is an error, it will also call [stop()], after #' signalling the condition first. This means that if the condition is #' caught by an exiting handler, then [stop()] is not called. #' #' @noRd #' @param cond Condition object to throw. If it is an error condition, #' then it calls [stop()]. #' @param parent Parent condition. #' @param frame The throwing context. Can be used to hide frames from #' the backtrace. throw <- throw_error <- function(cond, parent = NULL, frame = environment()) { if (!inherits(cond, "condition")) { cond <- new_error(cond) } if (!is.null(parent) && !inherits(parent, "condition")) { throw(new_error("Parent condition must be a condition object")) } if (isTRUE(cond[["call"]])) { cond[["call"]] <- sys.call(-1) %||% sys.call() } else if (identical(cond[["call"]], FALSE)) { cond[["call"]] <- NULL } cond <- process_call(cond) if (!is.null(parent)) { cond$parent <- process_call(parent) } # We can set an option to always add the trace to the thrown # conditions. This is useful for example in context that always catch # errors, e.g. in testthat tests or knitr. This options is usually not # set and we signal the condition here always_trace <- isTRUE(getOption("rlib_error_always_trace")) .hide_from_trace <- 1L # .error_frame <- cond if (!always_trace) signalCondition(cond) if (is.null(cond$`_pid`)) cond$`_pid` <- Sys.getpid() if (is.null(cond$`_timestamp`)) cond$`_timestamp` <- Sys.time() # If we get here that means that the condition was not caught by # an exiting handler. That means that we need to create a trace. # If there is a hand-constructed trace already in the error object, # then we'll just leave it there. if (is.null(cond$trace)) cond <- add_trace_back(cond, frame = frame) # Set up environment to store .Last.error, it will be just before # baseenv(), so it is almost as if it was in baseenv() itself, like # .Last.value. We save the print methods here as well, and then they # will be found automatically. if (! "org:r-lib" %in% search()) { do.call("attach", list(new.env(), pos = length(search()), name = "org:r-lib")) } env <- as.environment("org:r-lib") env$.Last.error <- cond env$.Last.error.trace <- cond$trace # If we always wanted a trace, then we signal the condition here if (always_trace) signalCondition(cond) # If this is not an error, then we'll just return here. This allows # throwing interrupt conditions for example, with the same UI. if (! inherits(cond, "error")) return(invisible()) .hide_from_trace <- NULL # Top-level handler, this is intended for testing only for now, # and its design might change. if (!is.null(th <- getOption("rlib_error_handler")) && is.function(th)) { return(th(cond)) } # In non-interactive mode, we print the error + the traceback # manually, to make sure that it won't be truncated by R's error # message length limit. out <- format( cond, trace = !is_interactive(), class = FALSE, full = !is_interactive() ) writeLines(out, con = default_output()) # Dropping the classes and adding "duplicate_condition" is a workaround # for the case when we have non-exiting handlers on throw()-n # conditions. These would get the condition twice, because stop() # will also signal it. If we drop the classes, then only handlers # on "condition" objects (i.e. all conditions) get duplicate signals. # This is probably quite rare, but for this rare case they can also # recognize the duplicates from the "duplicate_condition" extra class. class(cond) <- c("duplicate_condition", "condition") # Turn off the regular error printing to avoid printing # the error twice. opts <- options(show.error.messages = FALSE) on.exit(options(opts), add = TRUE) base::stop(cond) } # -- rethrow with parent ----------------------------------------------- #' Re-throw an error with a better error message #' #' Evaluate `expr` and if it errors, then throw a new error `err`, #' with the original error set as its parent. #' #' @noRd #' @param expr Expression to evaluate. #' @param err Error object or message to use for the child error. #' @param call Call to use in the re-thrown error. See [throw()]. chain_error <- function(expr, err, call = sys.call(-1), srcref = NULL) { .hide_from_trace <- 1 force(call) srcref <- srcref %||% utils::getSrcref(sys.call()) withCallingHandlers({ expr }, error = function(e) { .hide_from_trace <- 0:1 e$srcref <- srcref e$procsrcref <- NULL if (!inherits(err, "condition")) { err <- new_error(err, call. = call) } throw_error(err, parent = e) }) } # -- rethrowing conditions from C code --------------------------------- #' Version of .Call that throw()s errors #' #' It re-throws error from compiled code. If the error had class #' `simpleError`, like all errors, thrown via `error()` in C do, it also #' adds the `c_error` class. #' #' @noRd #' @param .NAME Compiled function to call, see [.Call()]. #' @param ... Function arguments, see [.Call()]. #' @return Result of the call. chain_call <- function(.NAME, ...) { .hide_from_trace <- 1:3 # withCallingHandlers + do.call + .handleSimpleError (?) call <- sys.call() call1 <- sys.call(-1) srcref <- utils::getSrcref(call) withCallingHandlers( do.call(".Call", list(.NAME, ...)), error = function(e) { .hide_from_trace <- 0:1 e$srcref <- srcref e$procsrcref <- NULL e[["call"]] <- call name <- native_name(.NAME) err <- new_error("Native call to `", name, "` failed", call. = call1) cerror <- if (inherits(e, "simpleError")) "c_error" class(err) <- c(cerror, "rlib_error_3_0", "rlib_error", "error", "condition") throw_error(err, parent = e) } ) } package_env <- topenv() #' Version of entrace_call that supports cleancall #' #' This function is the same as [entrace_call()], except that it #' uses cleancall's [.Call()] wrapper, to enable resource cleanup. #' See https://github.com/r-lib/cleancall#readme for more about #' resource cleanup. #' #' @noRd #' @param .NAME Compiled function to call, see [.Call()]. #' @param ... Function arguments, see [.Call()]. #' @return Result of the call. chain_clean_call <- function(.NAME, ...) { .hide_from_trace <- 1:3 call <- sys.call() call1 <- sys.call(-1) srcref <- utils::getSrcref(call) withCallingHandlers( package_env$call_with_cleanup(.NAME, ...), error = function(e) { .hide_from_trace <- 0:1 e$srcref <- srcref e$procsrcref <- NULL e[["call"]] <- call name <- native_name(.NAME) err <- new_error("Native call to `", name, "` failed", call. = call1) cerror <- if (inherits(e, "simpleError")) "c_error" class(err) <- c(cerror, "rlib_error_3_0", "rlib_error", "error", "condition") throw_error(err, parent = e) } ) } # -- create traceback ------------------------------------------------- #' Create a traceback #' #' [throw()] calls this function automatically if an error is not caught, #' so there is currently not much use to call it directly. #' #' @param cond Condition to add the trace to #' @param frame Use this context to hide some frames from the traceback. #' #' @return A condition object, with the trace added. add_trace_back <- function(cond, frame = NULL) { idx <- seq_len(sys.parent(1L)) frames <- sys.frames()[idx] # TODO: remove embedded objects from calls calls <- as.list(sys.calls()[idx]) parents <- sys.parents()[idx] namespaces <- unlist(lapply( seq_along(frames), function(i) { if (is_operator(calls[[i]])) { "o" } else { env_label(topenvx(environment(sys.function(i)))) } } )) pids <- rep(cond$`_pid` %||% Sys.getpid(), length(calls)) mch <- match(format(frame), sapply(frames, format)) if (is.na(mch)) { visibles <- TRUE } else { visibles <- c(rep(TRUE, mch), rep(FALSE, length(frames) - mch)) } scopes <- vapply(idx, FUN.VALUE = character(1), function(i) { tryCatch( get_call_scope(calls[[i]], namespaces[[i]]), error = function(e) "" ) }) namespaces <- ifelse(scopes %in% c("::", ":::"), namespaces, NA_character_) funs <- ifelse( is.na(namespaces), ifelse(scopes != "", paste0(scopes, " "), ""), paste0(namespaces, scopes) ) funs <- paste0( funs, vapply(calls, function(x) format_name(x[[1]])[1], character(1)) ) visibles <- visibles & mark_invisible_frames(funs, frames) pcs <- lapply(calls, function(c) process_call(list(call = c))) calls <- lapply(pcs, "[[", "call") srcrefs <- I(lapply(pcs, "[[", "srcref")) procsrcrefs <- I(lapply(pcs, "[[", "procsrcref")) cond$trace <- new_trace( calls, parents, visibles = visibles, namespaces = namespaces, scopes = scopes, srcrefs = srcrefs, procsrcrefs = procsrcrefs, pids ) cond } is_operator <- function(cl) { is.call(cl) && length(cl) >= 1 && is.symbol(cl[[1]]) && grepl("^[^.a-zA-Z]", as.character(cl[[1]])) } mark_invisible_frames <- function(funs, frames) { visibles <- rep(TRUE, length(frames)) hide <- lapply(frames, "[[", ".hide_from_trace") w_hide <- unlist(mapply(seq_along(hide), hide, FUN = function(i, w) { i + w }, SIMPLIFY = FALSE)) w_hide <- w_hide[w_hide <= length(frames)] visibles[w_hide] <- FALSE hide_from <- which(funs %in% names(invisible_frames)) for (start in hide_from) { hide_this <- invisible_frames[[ funs[start] ]] for (i in seq_along(hide_this)) { if (start + i > length(funs)) break if (funs[start + i] != hide_this[i]) break visibles[start + i] <- FALSE } } visibles } invisible_frames <- list( "base::source" = c("base::withVisible", "base::eval", "base::eval"), "base::stop" = "base::.handleSimpleError", "cli::cli_abort" = c( "rlang::abort", "rlang:::signal_abort", "base::signalCondition"), "rlang::abort" = c("rlang:::signal_abort", "base::signalCondition") ) call_name <- function(x) { if (is.call(x)) { if (is.symbol(x[[1]])) { as.character(x[[1]]) } else if (x[[1]][[1]] == quote(`::`) || x[[1]][[1]] == quote(`:::`)) { as.character(x[[1]][[2]]) } else { NULL } } else { NULL } } get_call_scope <- function(call, ns) { if (is.na(ns)) return("global") if (!is.call(call)) return("") if (is.call(call[[1]]) && (call[[1]][[1]] == quote(`::`) || call[[1]][[1]] == quote(`:::`))) return("") if (ns == "base") return("::") if (! ns %in% loadedNamespaces()) return("") name <- call_name(call) if (! ns %in% loadedNamespaces()) return("::") nsenv <- asNamespace(ns)$.__NAMESPACE__. if (is.null(nsenv)) return("::") if (is.null(nsenv$exports)) return(":::") if (exists(name, envir = nsenv$exports, inherits = FALSE)) { "::" } else if (exists(name, envir = asNamespace(ns), inherits = FALSE)) { ":::" } else { "local" } } topenvx <- function(x) { topenv(x, matchThisEnv = err_env) } new_trace <- function (calls, parents, visibles, namespaces, scopes, srcrefs, procsrcrefs, pids) { trace <- data.frame( stringsAsFactors = FALSE, parent = parents, visible = visibles, namespace = namespaces, scope = scopes, srcref = srcrefs, procsrcref = procsrcrefs, pid = pids ) trace[["call"]] <- calls class(trace) <- c("rlib_trace_3_0", "rlib_trace", "tbl", "data.frame") trace } env_label <- function(env) { nm <- env_name(env) if (nzchar(nm)) { nm } else { env_address(env) } } env_address <- function(env) { class(env) <- "environment" sub("^.*(0x[0-9a-f]+)>$", "\\1", format(env), perl = TRUE) } env_name <- function(env) { if (identical(env, err_env)) { return(env_name(package_env)) } if (identical(env, globalenv())) { return(NA_character_) } if (identical(env, baseenv())) { return("base") } if (identical(env, emptyenv())) { return("empty") } nm <- environmentName(env) if (isNamespace(env)) { return(nm) } nm } # -- S3 methods ------------------------------------------------------- format_error <- function(x, trace = FALSE, class = FALSE, advice = !trace, full = trace, header = TRUE, ...) { if (has_cli()) { format_error_cli(x, trace, class, advice, full, header, ...) } else { format_error_plain(x, trace, class, advice, full, header, ...) } } print_error <- function(x, trace = TRUE, class = TRUE, advice = !trace, ...) { writeLines(format_error(x, trace, class, advice, ...)) } format_trace <- function(x, ...) { if (has_cli()) { format_trace_cli(x, ...) } else { format_trace_plain(x, ...) } } print_trace <- function(x, ...) { writeLines(format_trace(x, ...)) } cnd_message <- function(cond) { paste(cnd_message_(cond, full = FALSE), collapse = "\n") } cnd_message_ <- function(cond, full = FALSE) { if (has_cli()) { cnd_message_cli(cond, full) } else { cnd_message_plain(cond, full) } } # -- format API ------------------------------------------------------- format_advice <- function(x) { if (has_cli()) { format_advice_cli(x) } else { format_advice_plain(x) } } format_call <- function(call) { if (has_cli()) { format_call_cli(call) } else { format_call_plain(call) } } format_class <- function(x) { if (has_cli()) { format_class_cli(x) } else { format_class_plain(x) } } format_error_heading <- function(x, prefix = NULL) { if (has_cli()) { format_error_heading_cli(x, prefix) } else { format_error_heading_plain(x, prefix) } } format_header_line <- function(x, prefix = NULL) { if (has_cli()) { format_header_line_cli(x, prefix) } else { format_header_line_plain(x, prefix) } } format_srcref <- function(call, srcref = NULL) { if (has_cli()) { format_srcref_cli(call, srcref) } else { format_srcref_plain(call, srcref) } } # -- condition message with cli --------------------------------------- cnd_message_robust <- function(cond) { class(cond) <- setdiff(class(cond), "rlib_error_3_0") conditionMessage(cond) %||% (if (inherits(cond, "interrupt")) "interrupt") %||% "" } cnd_message_cli <- function(cond, full = FALSE) { exp <- paste0(cli::col_yellow("!"), " ") add_exp <- is.null(names(cond$message)) msg <- cnd_message_robust(cond) c( paste0(if (add_exp) exp, msg), if (inherits(cond$parent, "condition")) { msg <- if (full && inherits(cond$parent, "rlib_error_3_0")) { format(cond$parent, trace = FALSE, full = TRUE, class = FALSE, header = FALSE, advice = FALSE ) } else if (inherits(cond$parent, "interrupt")) { "interrupt" } else { conditionMessage(cond$parent) } add_exp <- substr(cli::ansi_strip(msg[1]), 1, 1) != "!" if (add_exp) msg[1] <- paste0(exp, msg[1]) c(format_header_line_cli(cond$parent, prefix = "Caused by error"), msg ) } ) } # -- condition message w/o cli ---------------------------------------- cnd_message_plain <- function(cond, full = FALSE) { exp <- "! " add_exp <- is.null(names(cond$message)) c( paste0(if (add_exp) exp, cnd_message_robust(cond)), if (inherits(cond$parent, "condition")) { msg <- if (full && inherits(cond$parent, "rlib_error_3_0")) { format(cond$parent, trace = FALSE, full = TRUE, class = FALSE, header = FALSE, advice = FALSE ) } else if (inherits(cond$parent, "interrupt")) { "interrupt" } else { conditionMessage(cond$parent) } add_exp <- substr(msg[1], 1, 1) != "!" if (add_exp) { msg[1] <- paste0(exp, msg[1]) } c(format_header_line_plain(cond$parent, prefix = "Caused by error"), msg ) } ) } # -- printing error with cli ------------------------------------------ # Error parts: # - "Error:" or "Error in " prefix, the latter if the error has a call # - the call, possibly syntax highlightedm possibly trimmed (?) # - source ref, with link to the file, potentially in a new line in cli # - error message, just `conditionMessage()` # - advice about .Last.error and/or .Last.error.trace format_error_cli <- function(x, trace = TRUE, class = TRUE, advice = !trace, full = trace, header = TRUE, ...) { p_class <- if (class) format_class_cli(x) p_header <- if (header) format_header_line_cli(x) p_msg <- cnd_message_cli(x, full) p_advice <- if (advice) format_advice_cli(x) else NULL p_trace <- if (trace && !is.null(x$trace)) { c("---", "Backtrace:", format_trace_cli(x$trace)) } c(p_class, p_header, p_msg, p_advice, p_trace) } format_header_line_cli <- function(x, prefix = NULL) { p_error <- format_error_heading_cli(x, prefix) p_call <- format_call_cli(x[["call"]]) p_srcref <- format_srcref_cli(conditionCall(x), x$procsrcref %||% x$srcref) paste0(p_error, p_call, p_srcref, if (!is.null(conditionCall(x))) ":") } format_class_cli <- function(x) { cls <- unique(setdiff(class(x), "condition")) cls # silence codetools cli::format_inline("{.cls {cls}}") } format_error_heading_cli <- function(x, prefix = NULL) { str_error <- if (is.null(prefix)) { cli::style_bold(cli::col_yellow("Error")) } else { cli::style_bold(paste0(prefix)) } if (is.null(conditionCall(x))) { paste0(str_error, ": ") } else { paste0(str_error, " in ") } } format_call_cli <- function(call) { if (is.null(call)) { NULL } else { cl <- trimws(format(call)) if (length(cl) > 1) cl <- paste0(cl[1], " ", cli::symbol$ellipsis) cli::format_inline("{.code {cl}}") } } format_srcref_cli <- function(call, srcref = NULL) { ref <- get_srcref(call, srcref) if (is.null(ref)) return("") link <- if (ref$file != "") { if (Sys.getenv("R_CLI_HYPERLINK_STYLE") == "iterm") { cli::style_hyperlink( cli::format_inline("{basename(ref$file)}:{ref$line}:{ref$col}"), paste0("file://", ref$file, "#", ref$line, ":", ref$col) ) } else { cli::style_hyperlink( cli::format_inline("{basename(ref$file)}:{ref$line}:{ref$col}"), paste0("file://", ref$file), params = c(line = ref$line, col = ref$col) ) } } else { paste0("line ", ref$line) } cli::col_silver(paste0(" at ", link)) } str_advice <- "Type .Last.error to see the more details." format_advice_cli <- function(x) { cli::col_silver(str_advice) } format_trace_cli <- function(x, ...) { x$num <- seq_len(nrow(x)) scope <- ifelse( is.na(x$namespace), ifelse(x$scope != "", paste0(x$scope, " "), ""), paste0(x$namespace, x$scope) ) visible <- if ("visible" %in% names(x)) { x$visible } else { rep(TRUE, nrow(x)) } srcref <- if ("srcref" %in% names(x) || "procsrcref" %in% names(x)) { vapply( seq_len(nrow(x)), function(i) format_srcref_cli(x[["call"]][[i]], x$procsrcref[[i]] %||% x$srcref[[i]]), character(1) ) } else { unname(vapply(x[["call"]], format_srcref_cli, character(1))) } lines <- paste0( cli::col_silver(format(x$num), ". "), ifelse (visible, "", "| "), scope, vapply(seq_along(x$call), function(i) { format_trace_call_cli(x$call[[i]], x$namespace[[i]]) }, character(1)), srcref ) lines[!visible] <- cli::col_silver(cli::ansi_strip( lines[!visible], link = FALSE )) lines } format_trace_call_cli <- function(call, ns = "") { envir <- tryCatch({ if (!ns %in% loadedNamespaces()) stop("no") asNamespace(ns) }, error = function(e) .GlobalEnv) cl <- trimws(format(call)) if (length(cl) > 1) { cl <- paste0(cl[1], " ", cli::symbol$ellipsis) } # Older cli does not have 'envir'. if ("envir" %in% names(formals(cli::code_highlight))) { fmc <- cli::code_highlight(cl, envir = envir)[1] } else { fmc <- cli::code_highlight(cl)[1] } cli::ansi_strtrim(fmc, cli::console_width() - 5) } # ---------------------------------------------------------------------- format_error_plain <- function(x, trace = TRUE, class = TRUE, advice = !trace, full = trace, header = TRUE, ...) { p_class <- if (class) format_class_plain(x) p_header <- if (header) format_header_line_plain(x) p_msg <- cnd_message_plain(x, full) p_advice <- if (advice) format_advice_plain(x) else NULL p_trace <- if (trace && !is.null(x$trace)) { c("---", "Backtrace:", format_trace_plain(x$trace)) } c(p_class, p_header, p_msg, p_advice, p_trace) } format_trace_plain <- function(x, ...) { x$num <- seq_len(nrow(x)) scope <- ifelse( is.na(x$namespace), ifelse(x$scope != "", paste0(x$scope, " "), ""), paste0(x$namespace, x$scope) ) visible <- if ("visible" %in% names(x)) { x$visible } else { rep(TRUE, nrow(x)) } srcref <- if ("srcref" %in% names(x) || "procsrfref" %in% names(x)) { vapply( seq_len(nrow(x)), function(i) format_srcref_plain(x[["call"]][[i]], x$procsrcref[[i]] %||% x$srcref[[i]]), character(1) ) } else { unname(vapply(x[["call"]], format_srcref_plain, character(1))) } lines <- paste0( paste0(format(x$num), ". "), ifelse (visible, "", "| "), scope, vapply(x[["call"]], format_trace_call_plain, character(1)), srcref ) lines } format_advice_plain <- function(x, ...) { str_advice } format_header_line_plain <- function(x, prefix = NULL) { p_error <- format_error_heading_plain(x, prefix) p_call <- format_call_plain(x[["call"]]) p_srcref <- format_srcref_plain(conditionCall(x), x$procsrcref %||% x$srcref) paste0(p_error, p_call, p_srcref, if (!is.null(conditionCall(x))) ":") } format_error_heading_plain <- function(x, prefix = NULL) { str_error <- if (is.null(prefix)) "Error" else prefix if (is.null(conditionCall(x))) { paste0(str_error, ": ") } else { paste0(str_error, " in ") } } format_class_plain <- function(x) { cls <- unique(setdiff(class(x), "condition")) paste0("<", paste(cls, collapse = "/"), ">") } format_call_plain <- function(call) { if (is.null(call)) { NULL } else { cl <- trimws(format(call)) if (length(cl) > 1) cl <- paste0(cl[1], " ...") paste0("`", cl, "`") } } format_srcref_plain <- function(call, srcref = NULL) { ref <- get_srcref(call, srcref) if (is.null(ref)) return("") link <- if (ref$file != "") { paste0(basename(ref$file), ":", ref$line, ":", ref$col) } else { paste0("line ", ref$line) } paste0(" at ", link) } format_trace_call_plain <- function(call) { fmc <- trimws(format(call)[1]) if (length(fmc) > 1) { fmc <- paste0(fmc[1], " ...") } strtrim(fmc, getOption("width") - 5) } # -- utilities --------------------------------------------------------- cli_version <- function() { # this loads cli! package_version(asNamespace("cli")[[".__NAMESPACE__."]]$spec[["version"]]) } has_cli <- function() { "cli" %in% loadedNamespaces() && cli_version() >= "3.3.0" } `%||%` <- function(l, r) if (is.null(l)) r else l bytes <- function(x) { nchar(x, type = "bytes") } process_call <- function(cond) { cond[c("call", "srcref", "procsrcref")] <- list( call = if (is.null(cond[["call"]])) { NULL } else if (is.character(cond[["call"]])) { cond[["call"]] } else { deparse(cond[["call"]], nlines = 2) }, srcref = NULL, procsrcref = get_srcref(cond[["call"]], cond$procsrcref %||% cond$srcref) ) cond } get_srcref <- function(call, srcref = NULL) { ref <- srcref %||% utils::getSrcref(call) if (is.null(ref)) return(NULL) if (inherits(ref, "processed_srcref")) return(ref) file <- utils::getSrcFilename(ref, full.names = TRUE)[1] if (is.na(file)) file <- "" line <- utils::getSrcLocation(ref) %||% "" col <- utils::getSrcLocation(ref, which = "column") %||% "" structure( list(file = file, line = line, col = col), class = "processed_srcref" ) } is_interactive <- function() { opt <- getOption("rlib_interactive") if (isTRUE(opt)) { TRUE } else if (identical(opt, FALSE)) { FALSE } else if (tolower(getOption("knitr.in.progress", "false")) == "true") { FALSE } else if (tolower(getOption("rstudio.notebook.executing", "false")) == "true") { FALSE } else if (identical(Sys.getenv("TESTTHAT"), "true")) { FALSE } else { interactive() } } no_sink <- function() { sink.number() == 0 && sink.number("message") == 2 } rstudio_stdout <- function() { rstudio <- rstudio_detect() rstudio$type %in% c( "rstudio_console", "rstudio_console_starting", "rstudio_build_pane", "rstudio_job", "rstudio_render_pane" ) } default_output <- function() { if ((is_interactive() || rstudio_stdout()) && no_sink()) { stdout() } else { stderr() } } onload_hook <- function() { reg_env <- Sys.getenv("R_LIB_ERROR_REGISTER_PRINT_METHODS", "TRUE") if (tolower(reg_env) != "false") { registerS3method("format", "rlib_error_3_0", format_error, baseenv()) registerS3method("format", "rlib_trace_3_0", format_trace, baseenv()) registerS3method("print", "rlib_error_3_0", print_error, baseenv()) registerS3method("print", "rlib_trace_3_0", print_trace, baseenv()) registerS3method("conditionMessage", "rlib_error_3_0", cnd_message, baseenv()) } } native_name <- function(x) { if (inherits(x, "NativeSymbolInfo")) { x$name } else { format(x) } } # There is no format() for 'name' in R 3.6.x and before format_name <- function(x) { if (is.name(x)) { as.character(x) } else { format(x) } } # -- public API -------------------------------------------------------- err_env <- environment() parent.env(err_env) <- baseenv() structure( list( .internal = err_env, new_cond = new_cond, new_error = new_error, throw = throw, throw_error = throw_error, chain_error = chain_error, chain_call = chain_call, chain_clean_call = chain_clean_call, add_trace_back = add_trace_back, process_call = process_call, onload_hook = onload_hook, is_interactive = is_interactive, format = list( advice = format_advice, call = format_call, class = format_class, error = format_error, error_heading = format_error_heading, header_line = format_header_line, srcref = format_srcref, trace = format_trace ) ), class = c("standalone_errors", "standalone")) }) # These are optional, and feel free to remove them if you prefer to # call them through the `err` object. new_cond <- err$new_cond new_error <- err$new_error throw <- err$throw throw_error <- err$throw_error chain_error <- err$chain_error chain_call <- err$chain_call chain_clean_call <- err$chain_clean_call cli/R/utf8.R0000644000176200001440000001101614557444176012253 0ustar liggesusers #' Whether cli is emitting UTF-8 characters #' #' UTF-8 cli characters can be turned on by setting the `cli.unicode` #' option to `TRUE`. They can be turned off by setting if to `FALSE`. #' If this option is not set, then [base::l10n_info()] is used to detect #' UTF-8 support. #' #' @return Flag, whether cli uses UTF-8 characters. #' #' @export is_utf8_output <- function() { opt <- getOption("cli.unicode", NULL) if (! is.null(opt)) { isTRUE(opt) } else { l10n_info()$`UTF-8` && !is_latex_output() } } #' Count the number of characters in a character vector #' #' By default it counts Unicode grapheme clusters, instead of code points. #' #' @param x Character vector, it is converted to UTF-8. #' @param type Whether to count graphemes (characters), code points, #' bytes, or calculate the display width of the string. #' @return Numeric vector, the length of the strings in the character #' vector. #' #' @family UTF-8 string manipulation #' @export #' @examples #' # Grapheme example, emoji with combining characters. This is a single #' # grapheme, consisting of five Unicode code points: #' # * `\U0001f477` is the construction worker emoji #' # * `\U0001f3fb` is emoji modifier that changes the skin color #' # * `\u200d` is the zero width joiner #' # * `\u2640` is the female sign #' # * `\ufe0f` is variation selector 16, requesting an emoji style glyph #' emo <- "\U0001f477\U0001f3fb\u200d\u2640\ufe0f" #' cat(emo) #' #' utf8_nchar(emo, "chars") # = graphemes #' utf8_nchar(emo, "bytes") #' utf8_nchar(emo, "width") #' utf8_nchar(emo, "codepoints") #' #' # For comparision, the output for width depends on the R version used: #' nchar(emo, "chars") #' nchar(emo, "bytes") #' nchar(emo, "width") utf8_nchar <- function(x, type = c("chars", "bytes", "width", "graphemes", "codepoints")) { type <- match.arg(type) if (type == "chars") type <- "graphemes" x <- enc2utf8(x) if (type == "width") { .Call(clic_utf8_display_width, x) } else if (type == "graphemes") { .Call(clic_utf8_nchar_graphemes, x) } else if (type == "codepoints") { base::nchar(x, allowNA = FALSE, keepNA = TRUE, type = "chars") } else { # bytes base::nchar(x, allowNA = FALSE, keepNA = TRUE, type = "bytes") } } #' Substring of an UTF-8 string #' #' This function uses grapheme clusters instead of Unicode code points in #' UTF-8 strings. #' #' @param x Character vector. #' @param start Starting index or indices, recycled to match the length #' of `x`. #' @param stop Ending index or indices, recycled to match the length of #' `x`. #' @return Character vector of the same length as `x`, containing #' the requested substrings. #' #' @family UTF-8 string manipulation #' @export #' @examples #' # Five grapheme clusters, select the middle three #' str <- paste0( #' "\U0001f477\U0001f3ff\u200d\u2640\ufe0f", #' "\U0001f477\U0001f3ff", #' "\U0001f477\u200d\u2640\ufe0f", #' "\U0001f477\U0001f3fb", #' "\U0001f477\U0001f3ff") #' cat(str) #' str24 <- utf8_substr(str, 2, 4) #' cat(str24) utf8_substr <- function(x, start, stop) { if (!is.character(x)) x <- as.character(x) if (!is.numeric(start) || !is.numeric(stop)) { throw(cli_error( "{.arg start} and {.arg stop} must be numeric vectors", "i" = if (!is.numeric(start)) "{.arg start} is {.typeof {start}}", "i" = if (!is.numeric(stop)) "{.arg stop} is {.typeof {stop}}" )) } start2 <- suppressWarnings(as.integer(start)) stop2 <- suppressWarnings(as.integer(stop)) if (!length(start2) || !length(stop2)) { throw(cli_error( "{.arg start} and {.arg stop} must have at least length 1", "i" = if (!length(start2)) "{.arg start} has length 0", "i" = if (!length(stop2)) "{.arg stop} has length 0" )) } x <- enc2utf8(x) # TODO: better recycling start2 <- rep_len(start2, length(x)) stop2 <- rep_len(stop2, length(x)) .Call(clic_utf8_substr, x, start2, stop2) } #' Break an UTF-8 character vector into grapheme clusters #' #' @param x Character vector. #' @return List of characters vectors, the grapheme clusters of the input #' string. #' #' @family UTF-8 string manipulation #' @export #' @examples #' # Five grapheme clusters #' str <- paste0( #' "\U0001f477\U0001f3ff\u200d\u2640\ufe0f", #' "\U0001f477\U0001f3ff", #' "\U0001f477\u200d\u2640\ufe0f", #' "\U0001f477\U0001f3fb", #' "\U0001f477\U0001f3ff") #' cat(str, "\n") #' chrs <- utf8_graphemes(str) utf8_graphemes <- function(x) { if (!is.character(x)) x <- as.character(x) x <- enc2utf8(x) .Call(clic_utf8_graphemes, x) } cli/R/progress-ticking.R0000644000176200001440000000053714557444176014665 0ustar liggesusers #' @export ticking <- function(cond, name = NULL, ..., .envir = parent.frame()) { val <- force(cond) new <- is.null(clienv$progress_ids[[format(.envir)]]) if (new && val) cli_progress_bar(name = name, ..., .envir = .envir) if (val) { cli_progress_update(.envir = .envir) } else { cli_progress_done(.envir = .envir) } val } cli/R/zzz.R0000644000176200001440000001757614557444176012243 0ustar liggesusers #' ANSI colored text #' #' cli has a number of functions to color and style text at the command #' line. They provide a more modern interface than the crayon package. #' #' The `col_*` functions change the (foreground) color to the text. #' These are the eight original ANSI colors. Note that in some terminals, #' they might actually look differently, as terminals have their own #' settings for how to show them. `col_none()` is the default color, this #' is useful in a substring of a colored string. #' #' The `col_br_*` functions are bright versions of the eight ANSI colors. #' Note that on some terminal configurations and themes they might be the #' same as the non-bright colors. #' #' The `bg_*` functions change the background color of the text. #' These are the eight original ANSI background colors. These, too, can #' vary in appearance, depending on terminal settings. `bg_none()` the #' the default background color, this is useful in a substring of a #' background-colored string. #' #' The `bg_br_*` functions are the bright versions of the eight ANSI #' background colors. Note that on some terminal configurations and themes #' they might be the same as the non-bright colors. #' #' The `style_*` functions apply other styling to the text. The currently #' supported styling functions are: #' * `style_reset()` to remove any style, including color, #' * `style_bold()` for boldface / strong text, although some terminals #' show a bright, high intensity text instead, #' * `style_dim()` (or `style_blurred()` reduced intensity text. #' * `style_italic()` (not widely supported). #' * `style_underline()`, #' * `style_inverse()`, #' * `style_hidden()`, #' * `style_strikethrough()` (not widely supported). #' #' The style functions take any number of character vectors as arguments, #' and they concatenate them using `paste0()` before adding the style. #' #' Styles can also be nested, and then inner style takes precedence, see #' examples below. #' #' Sometimes you want to revert back to the default text color, in the #' middle of colored text, or you want to have a normal font in the middle #' of italic text. You can use the `style_no_*` functions for this. Every #' `style_*()` function has a `style_no_*()` pair, which defends its #' argument from taking on the style. See examples below. #' #' @param ... Character strings, they will be pasted together with #' `paste0()`, before applying the style function. #' @return An ANSI string (class `cli_ansi_string`), that contains ANSI #' sequences, if the current platform supports them. You can simply #' use `cat()` to print them to the terminal. #' #' @family ANSI styling #' @name ansi-styles #' @examples #' col_blue("Hello ", "world!") #' cat(col_blue("Hello ", "world!")) #' #' cat("... to highlight the", col_red("search term"), #' "in a block of text\n") #' #' ## Style stack properly #' cat(col_green( #' "I am a green line ", #' col_blue(style_underline(style_bold("with a blue substring"))), #' " that becomes green again!" #' )) #' #' error <- combine_ansi_styles("red", "bold") #' warn <- combine_ansi_styles("magenta", "underline") #' note <- col_cyan #' cat(error("Error: subscript out of bounds!\n")) #' cat(warn("Warning: shorter argument was recycled.\n")) #' cat(note("Note: no such directory.\n")) #' #' # style_no_* functions, note that the color is not removed #' style_italic(col_green(paste0( #' "italic before, ", #' style_no_italic("normal here, "), #' "italic after" #' ))) #' #' # avoiding color for substring #' style_italic(col_red(paste( #' "red before", #' col_none("not red between"), #' "red after" #' ))) NULL #' @export #' @name ansi-styles bg_black <- create_ansi_style("bg_black") #' @export #' @name ansi-styles bg_blue <- create_ansi_style("bg_blue") #' @export #' @name ansi-styles bg_cyan <- create_ansi_style("bg_cyan") #' @export #' @name ansi-styles bg_green <- create_ansi_style("bg_green") #' @export #' @name ansi-styles bg_magenta <- create_ansi_style("bg_magenta") #' @export #' @name ansi-styles bg_red <- create_ansi_style("bg_red") #' @export #' @name ansi-styles bg_white <- create_ansi_style("bg_white") #' @export #' @name ansi-styles bg_yellow <- create_ansi_style("bg_yellow") #' @export #' @name ansi-styles bg_none <- create_ansi_style("no_bg_color") #' @export #' @name ansi-styles bg_br_black <- create_ansi_style("bg_br_black") #' @export #' @name ansi-styles bg_br_blue <- create_ansi_style("bg_br_blue") #' @export #' @name ansi-styles bg_br_cyan <- create_ansi_style("bg_br_cyan") #' @export #' @name ansi-styles bg_br_green <- create_ansi_style("bg_br_green") #' @export #' @name ansi-styles bg_br_magenta <- create_ansi_style("bg_br_magenta") #' @export #' @name ansi-styles bg_br_red <- create_ansi_style("bg_br_red") #' @export #' @name ansi-styles bg_br_white <- create_ansi_style("bg_br_white") #' @export #' @name ansi-styles bg_br_yellow <- create_ansi_style("bg_br_yellow") #' @export #' @name ansi-styles col_black <- create_ansi_style("black") #' @export #' @name ansi-styles col_blue <- create_ansi_style("blue") #' @export #' @name ansi-styles col_cyan <- create_ansi_style("cyan") #' @export #' @name ansi-styles col_green <- create_ansi_style("green") #' @export #' @name ansi-styles col_magenta <- create_ansi_style("magenta") #' @export #' @name ansi-styles col_red <- create_ansi_style("red") #' @export #' @name ansi-styles col_white <- create_ansi_style("white") #' @export #' @name ansi-styles col_yellow <- create_ansi_style("yellow") #' @export #' @name ansi-styles col_grey <- create_ansi_style("silver") #' @export #' @name ansi-styles col_silver <- create_ansi_style("silver") #' @export #' @name ansi-styles col_none <- create_ansi_style("no_color") #' @export #' @name ansi-styles col_br_black <- create_ansi_style("br_black") #' @export #' @name ansi-styles col_br_blue <- create_ansi_style("br_blue") #' @export #' @name ansi-styles col_br_cyan <- create_ansi_style("br_cyan") #' @export #' @name ansi-styles col_br_green <- create_ansi_style("br_green") #' @export #' @name ansi-styles col_br_magenta <- create_ansi_style("br_magenta") #' @export #' @name ansi-styles col_br_red <- create_ansi_style("br_red") #' @export #' @name ansi-styles col_br_white <- create_ansi_style("br_white") #' @export #' @name ansi-styles col_br_yellow <- create_ansi_style("br_yellow") #' @export #' @name ansi-styles style_dim <- create_ansi_style("blurred") #' @export #' @name ansi-styles style_blurred <- create_ansi_style("blurred") #' @export #' @name ansi-styles style_bold <- create_ansi_style("bold") #' @export #' @name ansi-styles style_hidden <- create_ansi_style("hidden") #' @export #' @name ansi-styles style_inverse <- create_ansi_style("inverse") #' @export #' @name ansi-styles style_italic <- create_ansi_style("italic") #' @export #' @name ansi-styles style_reset <- create_ansi_style("reset") #' @export #' @name ansi-styles style_strikethrough <- create_ansi_style("strikethrough") #' @export #' @name ansi-styles style_underline <- create_ansi_style("underline") #' @export #' @name ansi-styles style_no_bold <- create_ansi_style("no_bold") #' @export #' @name ansi-styles style_no_blurred <- create_ansi_style("no_blurred") #' @export #' @name ansi-styles style_no_dim <- create_ansi_style("no_blurred") #' @export #' @name ansi-styles style_no_italic <- create_ansi_style("no_italic") #' @export #' @name ansi-styles style_no_underline <- create_ansi_style("no_underline") #' @export #' @name ansi-styles style_no_inverse <- create_ansi_style("no_inverse") #' @export #' @name ansi-styles style_no_hidden <- create_ansi_style("no_hidden") #' @export #' @name ansi-styles style_no_strikethrough <- create_ansi_style("no_strikethrough") #' @export #' @name ansi-styles style_no_color <- create_ansi_style("no_color") #' @export #' @name ansi-styles style_no_bg_color <- create_ansi_style("no_bg_color") cli/R/tty.R0000644000176200001440000002072714557444176012216 0ustar liggesusers is_interactive <- function() { opt <- getOption("rlib_interactive") if (isTRUE(opt)) { TRUE } else if (identical(opt, FALSE)) { FALSE } else if (tolower(getOption("knitr.in.progress", "false")) == "true") { FALSE } else if (tolower(getOption("rstudio.notebook.executing", "false")) == "true") { FALSE } else if (identical(Sys.getenv("TESTTHAT"), "true")) { FALSE } else { interactive() } } #' The connection option that cli would use #' #' Note that this only refers to the current R process. If the output #' is produced in another process, then it is not relevant. #' #' In interactive sessions the standard output is chosen, otherwise the #' standard error is used. This is to avoid painting output messages red #' in the R GUIs. #' #' @return Connection object. #' #' @export cli_output_connection <- function() { if ((is_interactive() || rstudio_stdout()) && no_sink()) stdout() else stderr() } no_sink <- function() { sink.number() == 0 && sink.number("message") == 2 } rstudio_stdout <- function() { rstudio <- rstudio_detect() rstudio$type %in% c( "rstudio_console", "rstudio_console_starting", "rstudio_build_pane", "rstudio_job", "rstudio_render_pane" ) } is_stdout <- function(stream) { identical(stream, stdout()) && sink.number() == 0 } is_stderr <- function(stream) { identical(stream, stderr()) && sink.number("message") == 2 } is_stdx <- function(stream){ is_stdout(stream) || is_stderr(stream) } is_rstudio_dynamic_tty <- function(stream) { rstudio$detect()[["dynamic_tty"]] && (is_stdout(stream) || is_stderr(stream)) } is_rapp <- function() { Sys.getenv("R_GUI_APP_VERSION") != "" } is_rapp_stdx <- function(stream) { interactive() && is_rapp() && (is_stdout(stream) || is_stderr(stream)) } is_emacs <- function() { Sys.getenv("EMACS") != "" || Sys.getenv("INSIDE_EMACS") != "" } is_rkward <- function() { "rkward" %in% (.packages()) } is_rkward_stdx <- function(stream) { interactive() && is_rkward() && (is_stdout(stream) || is_stderr(stream)) } #' Detect whether a stream supports `\\r` (Carriage return) #' #' In a terminal, `\\r` moves the cursor to the first position of the #' same line. It is also supported by most R IDEs. `\\r` is typically #' used to achieve a more dynamic, less cluttered user interface, e.g. #' to create progress bars. #' #' If the output is directed to a file, then `\\r` characters are typically #' unwanted. This function detects if `\\r` can be used for the given #' stream or not. #' #' The detection mechanism is as follows: #' 1. If the `cli.dynamic` option is set to `TRUE`, `TRUE` is returned. #' 2. If the `cli.dynamic` option is set to anything else, `FALSE` is #' returned. #' 3. If the `R_CLI_DYNAMIC` environment variable is not empty and set to #' the string `"true"`, `"TRUE"` or `"True"`, `TRUE` is returned. #' 4. If `R_CLI_DYNAMIC` is not empty and set to anything else, `FALSE` is #' returned. #' 5. If the stream is a terminal, then `TRUE` is returned. #' 6. If the stream is the standard output or error within RStudio, #' the macOS R app, or RKWard IDE, `TRUE` is returned. #' 7. Otherwise `FALSE` is returned. #' #' @param stream The stream to inspect or manipulate, an R connection #' object. It can also be a string, one of `"auto"`, `"message"`, #' `"stdout"`, `"stderr"`. `"auto"` will select `stdout()` if the session is #' interactive and there are no sinks, otherwise it will select `stderr()`. #' #' @family terminal capabilities #' @export #' @examples #' is_dynamic_tty() #' is_dynamic_tty(stdout()) is_dynamic_tty <- function(stream = "auto") { stream <- get_real_output(stream) ## Option? if (!is.null(x <- getOption("cli.dynamic"))) { return(isTRUE(x)) } ## Env var? if ((x <- Sys.getenv("R_CLI_DYNAMIC", "")) != "") { return(isTRUE(as.logical(x))) } ## Autodetect... ## RGui has isatty(stdout()) and isatty(stderr()), so we don't need ## to check that explicitly isatty(stream) || is_rstudio_dynamic_tty(stream) || is_rapp_stdx(stream) || is_rkward_stdx(stream) } ANSI_ESC <- "\u001B[" ANSI_HIDE_CURSOR <- paste0(ANSI_ESC, "?25l") ANSI_SHOW_CURSOR <- paste0(ANSI_ESC, "?25h") ANSI_EL <- paste0(ANSI_ESC, "K") #' Detect if a stream support ANSI escape characters #' #' We check that all of the following hold: #' * The stream is a terminal. #' * The platform is Unix. #' * R is not running inside R.app (the macOS GUI). #' * R is not running inside RStudio. #' * R is not running inside Emacs. #' * The terminal is not "dumb". #' * `stream` is either the standard output or the standard error stream. #' #' @inheritParams is_dynamic_tty #' @return `TRUE` or `FALSE`. #' #' @family terminal capabilities #' @export #' @examples #' is_ansi_tty() is_ansi_tty <- function(stream = "auto") { stream <- get_real_output(stream) # Option takes precedence opt <- getOption("cli.ansi") if (isTRUE(opt)) { return(TRUE) } else if (identical(opt, FALSE)) { return(FALSE) } # RStudio is handled separately if (rstudio$detect()[["ansi_tty"]] && is_stdx(stream)) return(TRUE) isatty(stream) && .Platform$OS.type == "unix" && !is_rapp() && !is_emacs() && Sys.getenv("TERM", "") != "dumb" && is_stdx(stream) } #' Hide/show cursor in a terminal #' #' This only works in terminal emulators. In other environments, it #' does nothing. #' #' `ansi_hide_cursor()` hides the cursor. #' #' `ansi_show_cursor()` shows the cursor. #' #' `ansi_with_hidden_cursor()` temporarily hides the cursor for #' evaluating an expression. #' #' @inheritParams is_dynamic_tty #' @param expr R expression to evaluate. #' #' @family terminal capabilities #' @family low level ANSI functions #' @export ansi_hide_cursor <- function(stream = "auto") { if (Sys.getenv("R_CLI_HIDE_CURSOR") == "false") return() stream <- get_real_output(stream) if (is_ansi_tty(stream)) cat(ANSI_HIDE_CURSOR, file = stream) } #' @export #' @name ansi_hide_cursor ansi_show_cursor <- function(stream = "auto") { if (Sys.getenv("R_CLI_HIDE_CURSOR") == "false") return() stream <- get_real_output(stream) if (is_ansi_tty(stream)) cat(ANSI_SHOW_CURSOR, file = stream) } #' @export #' @name ansi_hide_cursor ansi_with_hidden_cursor <- function(expr, stream = "auto") { stream <- get_real_output(stream) ansi_hide_cursor(stream) on.exit(ansi_show_cursor(), add = TRUE) expr } get_embedded_utf8 <- function() { .Call(clic_get_embedded_utf8) } set_embedded_utf8 <- function(value = TRUE) { .Call(clic_set_embedded_utf8, value) } r_utf8 <- function(func, args = list(), package = FALSE, timeout = 5000L) { out <- tempfile() on.exit(unlink(out), add = TRUE) opts <- callr::r_process_options( func = func, args = args, package = package, stdout = out, stderr = out ) if (.Platform$OS.type == "windows") { opts$load_hook <- c( opts$load_hook, "invisible(cli:::set_embedded_utf8())" ) } rp <- callr::r_process$new(opts) rp$wait(timeout) if (rp$is_alive()) { rp$kill() throw(cli_error("R subprocess timeout")) } list( status = rp$get_exit_status(), stdout = fix_r_utf8_output(readBin(out, "raw", file.size(out))) ) } fix_r_utf8_output <- function(x) { beg <- grepRaw(as.raw(c(2, 255, 254)), x, fixed = TRUE, all = TRUE) end <- grepRaw(as.raw(c(3, 255, 254)), x, fixed = TRUE, all = TRUE) # In case the output is incomplete, and an UTF-8 tag is left open if (length(end) < length(beg)) end <- c(end, length(x) + 1L) if (length(beg) != length(end)) { throw(cli_error( "Invalid output from UTF-8 R", "i" = "Found {length(beg)} UTF-8 begin marker{?s} and {length(end)} end marker{?s}." )) } # Easier to handle corner cases with this beg <- c(beg, length(x) + 1L) end <- c(end, length(x) + 1L) out <- file(open = "w+b") size <- 0L on.exit(close(out), add = TRUE) doutf8 <- function(from, to) { if (from > to) return() writeBin(x[from:to], out) size <<- size + (to - from + 1L) } donati <- function(from, to) { if (from > to) return() xx <- iconv(list(x[from:to]), "", "UTF-8", toRaw = TRUE)[[1]] writeBin(xx, out) size <<- size + length(xx) } # Initial native part if (beg[1] > 1) donati(1, beg[1] - 1L) # UTF-8 chunk, and native part after them for (i in seq_along(beg)) { doutf8(beg[i] + 3L, end[i] - 1L) if (i < length(beg)) { donati(end[i] + 3L, beg[i + 1L] - 1L) } } chr <- readChar(out, size) Encoding(chr) <- "UTF-8" chr } cli/R/pluralize.R0000644000176200001440000001252614752735214013374 0ustar liggesusers #' About cli pluralization #' #' @name pluralization #' @family pluralization #' @includeRmd man/chunks/pluralization.Rmd NULL make_quantity <- function(object) { val <- if (is.numeric(object)) { stopifnot(length(object) == 1) if (is.finite(object)) as.integer(object) else object } else { length(object) } } #' Pluralization helper functions #' #' @rdname pluralization-helpers #' @param expr For `no()` it is an expression that is printed as "no" in #' cli expressions, it is interpreted as a zero quantity. For `qty()` #' an expression that sets the pluralization quantity without printing #' anything. See examples below. #' #' @examples #' nfile <- 0; cli_text("Found {no(nfile)} file{?s}.") #' #' #> Found no files. #' #' nfile <- 1; cli_text("Found {no(nfile)} file{?s}.") #' #' #> Found 1 file. #' #' nfile <- 2; cli_text("Found {no(nfile)} file{?s}.") #' #' #> Found 2 files. #' #' @export #' @family pluralization no <- function(expr) { stopifnot(is.numeric(expr), length(expr) == 1, !is.na(expr)) structure( expr, class = "cli_no" ) } #' @export as.character.cli_no <- function(x, ...) { if (make_quantity(x) == 0) "no" else as.character(unclass(x)) } #' @rdname pluralization-helpers #' @export qty <- function(expr) { structure( make_quantity(expr), class = "cli_noprint" ) } #' @export as.character.cli_noprint <- function(x, ...) { "" } parse_plural <- function(code, values) { # If we have the quantity already, then process it now. # Otherwise we put in a marker for it, and request post-processing. qty <- make_quantity(values$qty) if (!is.na(qty)) { process_plural(qty, code) } else { values$postprocess <- TRUE id <- random_id() values$pmarkers[[id]] <- code id } } process_plural <- function(qty, code) { parts <- strsplit(str_tail(code), "/", fixed = TRUE)[[1]] if (last_character(code) == "/") parts <- c(parts, "") if (length(parts) == 1) { if (is.finite(qty) & qty == 1) "" else parts[1] } else if (length(parts) == 2) { if (is.finite(qty) & qty == 1) parts[1] else parts[2] } else if (length(parts) == 3) { if (is.finite(qty) & qty == 0) { parts[1] } else if (is.finite(qty) & qty == 1) { parts[2] } else { parts[3] } } else { stop("Invalid pluralization directive: `", code, "`") } } post_process_plurals <- function(str, values) { if (!values$postprocess) return(str) if (values$num_subst == 0) { stop("Cannot pluralize without a quantity") } if (values$num_subst != 1) { stop("Multiple quantities for pluralization") } qty <- make_quantity(values$qty) for (i in seq_along(values$pmarkers)) { mark <- values$pmarkers[i] str <- sub(names(mark), process_plural(qty, mark[[1]]), str) } str } #' String templating with pluralization #' #' `pluralize()` is similar to [glue::glue()], with two differences: #' * It supports cli's [pluralization] syntax, using `{?}` markers. #' * It collapses substituted vectors into a comma separated string. #' #' See [pluralization] and some examples below. #' #' You need to install the glue package to use this function. #' #' @param ...,.envir,.transformer All arguments are passed to [glue::glue()]. #' #' @export #' @family pluralization #' @examplesIf requireNamespace("glue", quietly = TRUE) #' # Regular plurals #' nfile <- 0; pluralize("Found {nfile} file{?s}.") #' nfile <- 1; pluralize("Found {nfile} file{?s}.") #' nfile <- 2; pluralize("Found {nfile} file{?s}.") #' #' # Irregular plurals #' ndir <- 1; pluralize("Found {ndir} director{?y/ies}.") #' ndir <- 5; pluralize("Found {ndir} director{?y/ies}.") #' #' # Use 'no' instead of zero #' nfile <- 0; pluralize("Found {no(nfile)} file{?s}.") #' nfile <- 1; pluralize("Found {no(nfile)} file{?s}.") #' nfile <- 2; pluralize("Found {no(nfile)} file{?s}.") #' #' # Use the length of character vectors #' pkgs <- "pkg1" #' pluralize("Will remove the {pkgs} package{?s}.") #' pkgs <- c("pkg1", "pkg2", "pkg3") #' pluralize("Will remove the {pkgs} package{?s}.") #' #' pkgs <- character() #' pluralize("Will remove {?no/the/the} {pkgs} package{?s}.") #' pkgs <- c("pkg1", "pkg2", "pkg3") #' pluralize("Will remove {?no/the/the} {pkgs} package{?s}.") #' #' # Multiple quantities #' nfiles <- 3; ndirs <- 1 #' pluralize("Found {nfiles} file{?s} and {ndirs} director{?y/ies}") #' #' # Explicit quantities #' nupd <- 3; ntotal <- 10 #' cli_text("{nupd}/{ntotal} {qty(nupd)} file{?s} {?needs/need} updates") pluralize <- function(..., .envir = parent.frame(), .transformer = glue::identity_transformer) { values <- new.env(parent = emptyenv()) values$empty <- random_id() values$qty <- values$empty values$num_subst <- 0L values$postprocess <- FALSE values$pmarkers <- list() tf <- function(text, envir) { if (substr(text, 1, 1) == "?") { if (identical(values$qty, values$empty)) { values$postprocess <- TRUE id <- random_id() values$pmarkers[[id]] <- text return(id) } else { return(process_plural(make_quantity(values$qty), text)) } } else { values$num_subst <- values$num_subst + 1 qty <- .transformer(text, envir) values$qty <- qty return(inline_collapse(qty)) } } raw <- glue::glue(..., .envir = .envir, .transformer = tf, .comment = "") post_process_plurals(raw, values) } cli/R/vt.R0000644000176200001440000000557614752735214012025 0ustar liggesusers #' Simulate (a subset of) a VT-5xx ANSI terminal #' #' This is utility function that calculates the state of a VT-5xx screen #' after a certain set of output. #' #' Currently it supports: #' #' - configurable terminal width and height #' - ASCII printable characters. #' - `\n`, `\r`. #' - ANSI SGR colors, 8 color mode, 256 color mode and true color mode. #' - Other ANSI SGR features: bold, italic, underline, strikethrough, #' blink, inverse. #' #' It does _not_ currently supports other features, mode notably: #' #' - Other ANSI control sequences and features. Other control sequences #' are silently ignored. #' - Wide Unicode characters. Their width is not taken into account #' correctly. #' - Unicode graphemes. #' #' @param output Character vector or raw vector. Character vectors are #' collapsed (without a separater), and converted to a raw vector using #' [base::charToRaw()]. #' @param width Terminal width. #' @param height Terminal height. #' @return Data frame with columns `lineno`, `segmentno`, `segment`, #' `attributes`. #' #' @note #' This function is experimental, and the virtual temrinal API will #' likely change in future versions of cli. #' #' @export vt_output <- function(output, width = 80L, height = 25L) { if (is.character(output)) { output <- charToRaw(paste(output, collapse = "")) } res <- .Call( clic_vt_output, output, as.integer(width), as.integer(height) ) linksx <- vapply(res$links, intToUtf8, character(1)) links <- sub("^[^;]*;", "", linksx) links_params <- sub(";[^;]*$", "", linksx) df <- data.frame( stringsAsFactors = FALSE, lineno = integer(), segmentno = integer(), segment = character(), attributes = character() ) segments <- lapply(seq_along(res$lines), function(i) { line <- intToUtf8(res$lines[[i]]) attr <- res$attrs[[i]] lgs <- rle(attr) clgs <- cumsum(c(0, lgs$lengths)) segs <- mapply(clgs[-length(clgs)], clgs[-1], FUN = function(s, e) { utf8_substr(line, s + 1, e) }) fg <- re_match(lgs$values, "fg:([0-9]+|#[0-9a-f]+);")[,1] bg <- re_match(lgs$values, "bg:([0-9]+|#[0-9a-f]+);")[,1] linkno <- as.integer(re_match(lgs$values, "link:([0-9]+);")[,1]) link <- links[linkno] link_params <- links_params[linkno] data.frame( stringsAsFactors = FALSE, lineno = i, segmentno = seq_along(segments), segment = segs, bold = grepl("bold;", lgs$values, fixed = TRUE), italic = grepl("italic;", lgs$values, fixed = TRUE), underline = grepl("underline;", lgs$values, fixed = TRUE), strikethrough = grepl("strikethrough;", lgs$values, fixed = TRUE), blink = grepl("blink;", lgs$values, fixed = TRUE), inverse = grepl("inverse;", lgs$values, fixed = TRUE), color = fg, background_color = bg, link = link, link_params = link_params ) }) do.call(rbind, c(list(df), segments)) } cli/R/keypress.R0000644000176200001440000000424014557444176013233 0ustar liggesusers #' Read a single keypress at the terminal #' #' It currently only works at Linux/Unix and OSX terminals, #' and at the Windows command line. see \code{\link{has_keypress_support}}. #' #' The following special keys are supported: #' * Arrow keys: 'up', 'down', 'right', 'left'. #' * Function keys: from 'f1' to 'f12'. #' * Others: 'home', 'end', 'insert', 'delete', 'pageup', 'pagedown', #' 'tab', 'enter', 'backspace' (same as 'delete' on OSX keyboards), #' 'escape'. #' * Control with one of the following keys: 'a', 'b', 'c', 'd', 'e', 'f', #' 'h', 'k', 'l', 'n', 'p', 't', 'u', 'w'. #' #' @param block Whether to wait for a key press, if there is none #' available now. #' @return The key pressed, a character scalar. For non-blocking reads #' `NA` is returned if no keys are available. #' #' @family keypress function #' @export #' @examplesIf FALSE #' x <- keypress() #' cat("You pressed key", x, "\n") keypress <- function(block = TRUE) { if (!has_keypress_support()) { stop("Your platform/terminal does not support `keypress()`.") } block <- as.logical(block) if (length(block) != 1) stop("'block' must be a logical scalar") ret <- .Call(cli_keypress, block) if (ret == "none") NA_character_ else ret } #' Check if the current platform/terminal supports reading #' single keys. #' #' @details #' Supported platforms: #' * Terminals in Windows and Unix. #' * RStudio terminal. #' #' Not supported: #' * RStudio (if not in the RStudio terminal). #' * R.app on macOS. #' * Rgui on Windows. #' * Emacs ESS. #' * Others. #' #' @return Whether there is support for waiting for individual #' keypressses. #' #' @family keypress function #' @export #' @examples #' has_keypress_support() has_keypress_support <- function() { ## Supported if we have a terminal or RStudio terminal. ## Not supported otherwise in RStudio, R.app, Rgui or Emacs rs <- rstudio$detect() if (rs$type != "not_rstudio") { rs$has_canonical_mode } else { isatty(stdin()) && Sys.getenv("R_GUI_APP_VERSION") == "" && .Platform$GUI != "Rgui" && ! identical(getOption("STERM"), "iESS") && Sys.getenv("EMACS") != "t" && Sys.getenv("TERM") != "dumb" } } cli/R/progress-utils.R0000644000176200001440000000213714557444176014373 0ustar liggesusers #' @title Progress bar utility functions. #' @details `cli_progress_num()` returns the number of currently #' active progress bars. (These do not currently include the progress #' bars created in C/C++ code.) #' @return `cli_progress_num()` returns an integer scalar. #' #' @rdname progress-utils #' @family progress bar functions #' @export cli_progress_num <- function() { length(clienv$progress) } #' @details `cli_progress_cleanup()` terminates all active progress bars. #' (It currently ignores progress bars created in the C/C++ code.) #' @return `cli_progress_cleanup() does not return anything. #' #' @rdname progress-utils #' @export cli_progress_cleanup <- function() { while ((n <- cli_progress_num()) > 0) { cli_progress_done(clienv$progress[[n]]$id) } ansi_show_cursor() invisible() } should_run_progress_examples <- function() { if (is_rcmd_check()) return(FALSE) tolower(Sys.getenv("R_PROGRESS_NO_EXAMPLES")) != "true" } is_rcmd_check <- function() { if (identical(Sys.getenv("NOT_CRAN"), "true")) { FALSE } else { Sys.getenv("_R_CHECK_PACKAGE_NAME_", "") != "" } } cli/R/ansi-utils.R0000644000176200001440000000203014557444176013451 0ustar liggesusers re_table <- function(...) { lapply(gregexpr(...), function(x) { res <- cbind( start = x, end = x + attr(x, "match.length") - 1, length = attr(x, "match.length") ) res <- res[res[, "start"] != -1, , drop=FALSE] }) } ## Create the non-matching table from the matching table non_matching <- function(table, str, empty = FALSE) { mapply(table, str, SIMPLIFY = FALSE, FUN = function(t, s) { if (! nrow(t)) { cbind(start = 1, end = base::nchar(s), length = base::nchar(s)) } else { start <- c(1, t[, "end"] + 1) end <- c(t[, "start"] - 1, base::nchar(s)) res <- cbind(start = start, end = end, length = end - start + 1) if (!empty) res[ res[, "length"] != 0, , drop = FALSE ] else res } }) } myseq <- function(from, to, by = 1) { stopifnot(by != 0) if (by > 0) { if (to < from) { integer() } else { seq(from, to, by = by) } } else { if (to > from) { integer() } else { seq(from, to, by = by) } } } `%:%` <- myseq cli/R/cli-errors.R0000644000176200001440000000142014557444176013444 0ustar liggesusers cli_error <- function(..., .data = NULL, .class = NULL, .envir = parent.frame(), call. = TRUE) { .hide_from_trace <- TRUE cnd <- new_error( call. = call., format_error( .envir = .envir, c( ... ) ) ) if (length(.data)) cnd[names(.data)] <- .data if (length(class)) class(cnd) <- c(.class, class(cnd)) cnd } stop_if_not <- function(message, ..., .envir = parent.frame(), call. = sys.call(-1)) { conds <- list(...) for (cond in conds) { if (!cond) { throw( new_error(format_error(.envir = .envir, message), call. = call.), frame = .envir ) } } } `%??%` <- function(expr, err) { chain_error(expr, err, srcref = utils::getSrcref(sys.call())) } cli/R/spinner.R0000644000176200001440000002472014557444176013051 0ustar liggesusers ## See tools/spinners.R for how the RDS file is created #' Character vector to put a spinner on the screen #' #' `cli` contains many different spinners, you choose one according to your #' taste. #' #' ```{asciicast get-spinner} #' #| asciicast_at = "all", #' #| asciicast_knitr_output = "svg", #' #| asciicast_cursor = FALSE #' options(cli.spinner = "hearts") #' fun <- function() { #' cli_progress_bar("Spinning") #' for (i in 1:100) { #' Sys.sleep(4/100) #' cli_progress_update() #' } #' } #' fun() #' options(cli.spinner = NULL) #' ``` #' #' @param which The name of the chosen spinner. If `NULL`, then the default #' is used, which can be customized via the `cli.spinner_unicode`, #' `cli.spinner_ascii` and `cli.spinner` options. (The latter applies to #' both Unicode and ASCII displays. These options can be set to the name #' of a built-in spinner, or to a list that has an entry called `frames`, #' a character vector of frames. #' @return A list with entries: `name`, `interval`: the suggested update #' interval in milliseconds and `frames`: the character vector of the #' spinner's frames. #' #' @family spinners #' @export get_spinner <- function(which = NULL) { stopifnot(is.null(which) || is_string(which) || is.list(which)) if (is.null(which)) { if (is_utf8_output()) { which <- getOption("cli.spinner_unicode") %||% getOption("cli.spinner") %||% "dots" } else { which <- getOption("cli.spinner_ascii") %||% getOption("cli.spinner") %||% "line" } } if (is.character(which)) { row <- match(which, spinners$name) which <- list( name = which, interval = spinners$interval[[row]], frames = spinners$frames[[row]]) } if (!is.character(which$frames)) { stop("Spinner frames must be a character vector") } which$name <- which$name %||% NA_character_ which$interval <- which$interval %||% 100L which } #' List all available spinners #' #' @return Character vector of all available spinner names. #' #' @family spinners #' @export #' @examples #' list_spinners() #' get_spinner(list_spinners()[1]) list_spinners <- function() { spinners$name } #' Create a spinner #' #' @param template A template string, that will contain the spinner. The #' spinner itself will be substituted for `{spin}`. See example below. #' @param stream The stream to use for the spinner. Typically this is #' standard error, or maybe the standard output stream. #' It can also be a string, one of `"auto"`, `"message"`, `"stdout"`, #' `"stderr"`. `"auto"` will select `stdout()` if the session is #' interactive and there are no sinks, otherwise it will select #' `stderr()`. #' @param static What to do if the terminal does not support dynamic #' displays: #' * `"dots"`: show a dot for each `$spin()` call. #' * `"print"`: just print the frames of the spinner, one after another. #' * `"print_line"`: print the frames of the spinner, each on its own line. #' * `"silent"` do not print anything, just the `template`. #' @inheritParams get_spinner #' @return A `cli_spinner` object, which is a list of functions. See #' its methods below. #' #' `cli_spinner` methods: #' * `$spin()`: output the next frame of the spinner. #' * `$finish()`: terminate the spinner. Depending on terminal capabilities #' this removes the spinner from the screen. Spinners can be reused, #' you can start calling the `$spin()` method again. #' #' All methods return the spinner object itself, invisibly. #' #' The spinner is automatically throttled to its ideal update frequency. #' #' @section Examples: #' #' ## Default spinner #' #' ```{asciicast make-spinner-default} #' #| asciicast_at = "all", #' #| asciicast_knitr_output = "svg", #' #| asciicast_cursor = FALSE, #' #| asciicast_end_wait = 0 #' sp1 <- make_spinner() #' fun_with_spinner <- function() { #' lapply(1:100, function(x) { sp1$spin(); Sys.sleep(0.05) }) #' sp1$finish() #' } #' ansi_with_hidden_cursor(fun_with_spinner()) #' ``` #' #' ## Spinner with a template #' #' ```{asciicast make-spinner-template} #' #| asciicast_at = "all", #' #| asciicast_knitr_output = "svg", #' #| asciicast_cursor = FALSE, #' #| asciicast_end_wait = 0 #' sp2 <- make_spinner(template = "Computing {spin}") #' fun_with_spinner2 <- function() { #' lapply(1:100, function(x) { sp2$spin(); Sys.sleep(0.05) }) #' sp2$finish() #' } #' ansi_with_hidden_cursor(fun_with_spinner2()) #' ``` #' #' ## Custom spinner #' #' ```{asciicast make-spinner-custom} #' #| asciicast_at = "all", #' #| asciicast_knitr_output = "svg", #' #| asciicast_cursor = FALSE #' sp3 <- make_spinner("simpleDotsScrolling", template = "Downloading {spin}") #' fun_with_spinner3 <- function() { #' lapply(1:100, function(x) { sp3$spin(); Sys.sleep(0.05) }) #' sp3$finish() #' } #' ansi_with_hidden_cursor(fun_with_spinner3()) #' ``` #' #' @family spinners #' @export make_spinner <- function(which = NULL, stream = "auto", template = "{spin}", static = c("dots", "print", "print_line", "silent")) { stopifnot( inherits(stream, "connection") || is_string(stream), is_string(template)) c_stream <- get_real_output(stream) c_spinner <- get_spinner(which) c_template <- template c_static <- match.arg(static) c_state <- 1L c_first <- TRUE c_col <- 1L c_width <- 0L c_last <- Sys.time() - as.difftime(1, units = "secs") c_int <- as.difftime(c_spinner$interval / 1000, units = "secs") c_res <- list() throttle <- function() Sys.time() - c_last < c_int clear_line <- function() { str <- paste0(c("\r", rep(" ", c_width), "\r"), collapse = "") cat(str, file = c_stream) } inc <- function() { c_state <<- c_state + 1L c_first <<- FALSE if (c_state > length(c_spinner$frames)) c_state <<- 1L c_last <<- Sys.time() invisible(c_res) } c_res$finish <- function() { c_state <<- 1L c_first <<- TRUE c_col <<- 1L c_last <<- Sys.time() if (is_dynamic_tty(c_stream)) clear_line() else cat("\n", file = c_stream) invisible(c_res) } if (is_dynamic_tty(c_stream)) { c_res$spin <- function(template = NULL) { if (!is.null(template)) c_template <<- template if (throttle()) return() line <- sub("{spin}", c_spinner$frames[[c_state]], c_template, fixed = TRUE) line_width <- ansi_nchar(line) if (is_ansi_tty(c_stream)) { cat("\r", line, ANSI_EL, sep = "", file = c_stream) } else { # extra padding in case the line width has changed # so that we don't get any garbage in the output padding <- if (line_width < c_width) { paste0(rep(" ", line_width), collapse = "") } else { "" } cat("\r", line, padding, sep = "", file = c_stream) } # save the new line width c_width <<- line_width inc() } } else { if (c_static == "dots") { c_res$spin <- function(template = NULL) { if (!is.null(template)) c_template <<- template if (c_first) cat(template, "\n", sep = "", file = c_stream) if (throttle()) return() cat(".", file = c_stream) c_col <<- c_col + 1L if (c_col == console_width()) { cat("\n", file = c_stream) c_col <<- 1L } inc() } } else if (c_static == "print") { c_res$spin <- function(template = NULL) { if (!is.null(template)) c_template <<- template if (throttle()) return() line <- sub("{spin}", c_spinner$frames[[c_state]], c_template, fixed = TRUE) cat(line, file = c_stream) inc() } } else if (c_static == "print_line") { c_res$spin <- function(template = NULL) { if (!is.null(template)) c_template <<- template if (throttle()) return() line <- sub("{spin}", c_spinner$frames[[c_state]], c_template, fixed = TRUE) cat(line, "\n", sep = "", file = c_stream) inc() } } else if (c_static == "silent") { c_res$spin <- function(template = NULL) { if (!is.null(template)) c_template <<- template if (throttle()) return() inc() } } } class(c_res) <- "cli_spinner" c_res } #' @export print.cli_spinner <- function(x, ...) { cat("\n") invisible(x) } ## nocov start #' Show a demo of some (by default all) spinners #' #' Each spinner is shown for about 2-3 seconds. #' #' @details #' #' ```{asciicast demo-spinners} #' #| asciicast_at = "all", #' #| asciicast_knitr_output = "svg", #' #| asciicast_cursor = FALSE, #' #| asciicast_end_wait = 0 #' demo_spinners("clock") #' ``` #' #' @param which Character vector, which spinners to demo. #' #' @family spinners #' @export demo_spinners <- function(which = NULL) { stopifnot(is.null(which) || is.character(which)) all <- list_spinners() which <- which %||% all if (length(bad <- setdiff(which, all))) { stop("Unknown spinners: ", paste(bad, collapse = ", ")) } for (w in which) { sp <- get_spinner(w) interval <- sp$interval / 1000 frames <- sp$frames cycles <- max(round(2.5 / ((length(frames) - 1) * interval)), 1) for (i in 1:(length(frames) * cycles) - 1) { fr <- unclass(frames[i %% length(frames) + 1]) cat("\r", rpad(fr, width = 10), w, sep = "") Sys.sleep(interval) } cat("\n") } } demo_spinners_terminal <- function(ticks = 100 * 3000) { up <- function(n) cat(paste0("\u001B[", n, "A")) show <- function() cat("\u001b[?25h") hide <- function() cat("\u001b[?25l") on.exit(show(), add = TRUE) names <- unlist(spinners$name) frames <- spinners$frames intervals <- unlist(spinners$interval) num_frames <- viapply(frames, length) spin_width <- viapply(frames, function(x) max(nchar(x, type = "width"))) name_width <- nchar(names, type = "width") col_width <- spin_width + max(name_width) + 3 col1_width <- max(col_width[1:(length(col_width)/2)]) frames <- mapply( frames, names, FUN = function(f, n) { rpad(paste(lpad(n, max(name_width) + 2), f), col1_width) } ) hide() for (tick in 0:ticks) { tic <- Sys.time() wframe <- trunc(tick / intervals) %% num_frames + 1 sp <- mapply(frames, wframe, FUN = "[") sp2 <- paste( sep = " ", sp[1:(length(sp) / 2)], sp[(length(sp) / 2 + 1):length(sp)] ) cat(sp2, sep = "\n") up(length(sp2)) took <- Sys.time() - tic togo <- as.difftime(1/1000, units = "secs") - took if (togo > 0) Sys.sleep(togo) } } ## nocov end cli/R/progress-variables.R0000644000176200001440000004653314557444176015213 0ustar liggesusers # ------------------------------------------------------------------------ #' @title Progress bar variables #' #' @details These variables can be used in cli progress bar format #' strings. They are calculated on demand. To use a variable, e.g. `pb_bar` #' in a package, you either need to to import `pb_bar` from cli, or use #' the qualified form in the format string: `cli::pb_bar`. #' #' Similarly, in R scripts, you can use `pb_bar` after `library(cli)`, #' or `cli::pb_bar` if you do not attach the cli package. #' #' @family progress bar functions #' @name progress-variables NULL #' @name progress-variables #' @export pb_bar #' @usage NULL #' @aliases pb_bar #' #' @details #' ### `pb_bar` #' #' Creates a visual progress bar. If the number of total units #' is unknown, then it will return an empty string. #' #' ```{asciicast progress-var-bar, echo = 2:5} #' x <- invisible(quote( #' cli_progress_bar( #' total = 100, #' format = "Fitting model {cli::pb_bar} {cli::pb_percent}" #' ) #' )) #' cli:::var_helper(x, current = 66) #' ``` cli__pb_bar <- function(pb = getOption("cli__pb")) { if (is.null(pb)) return("") if (is.na(pb$total)) return("") structure( list(current = pb$current, total = pb$total), class = "cli-progress-bar" ) } #' @name progress-variables #' @export pb_current #' @usage NULL #' @aliases pb_current #' #' @details #' ### `pb_current` #' #' The number of current progress units. #' #' ```{asciicast progress-var-current, echo = 2:5} #' x <- invisible(quote( #' cli_progress_bar( #' total = 100, #' format = "{cli::pb_spin} Reading file {cli::pb_current}/{cli::pb_total}" #' ) #' )) #' cli:::var_helper(x, current = 66) #' ``` cli__pb_current <- function(pb = getOption("cli__pb")) { if (is.null(pb)) return("") pb$current } #' @name progress-variables #' @export pb_current_bytes #' @usage NULL #' @aliases pb_current_bytes #' #' @details #' ### `pb_current_bytes` #' #' The number of current progress units formatted as bytes. #' The output has a constant width of six characters. #' #' ```{asciicast progress-var-current-bytes, echo = 2:4} #' x <- invisible(quote( #' cli_progress_bar( #' format = "Got {cli::pb_current_bytes} in {cli::pb_elapsed}" #' ) #' )) #' cli:::var_helper2(x, current = 1024 * 512, delay = 5) #' ``` cli__pb_current_bytes <- function(pb = getOption("cli__pb")) { if (is.null(pb)) return("") format_bytes$pretty_bytes(pb$current, style = "6") } #' @name progress-variables #' @export pb_elapsed #' @usage NULL #' @aliases pb_elapsed #' #' @details #' ### `pb_elapsed` #' #' The elapsed time since the start of the progress bar. The time is #' measured since the progress bar was created with [cli_progress_bar()] #' or similar. #' #' ```{asciicast progress-var-elapsed, echo = 2:5} #' x <- invisible(quote( #' cli_progress_bar( #' total = 100, #' format = "{cli::pb_bar} {cli::pb_percent} [{cli::pb_elapsed}]" #' ) #' )) #' cli:::var_helper2(x, current = 65, delay = 5) #' ``` cli__pb_elapsed <- function(pb = getOption("cli__pb")) { if (is.null(pb)) return("") secs <- (.Call(clic_get_time) - pb$start) * clienv$speed_time format_time$pretty_sec(secs) } #' @name progress-variables #' @export pb_elapsed_clock #' @usage NULL #' @aliases pb_elapsed_clock #' #' @details #' ### `pb_elapsed_clock` #' #' The elapsed time, in `hh::mm::ss` format. #' #' ```{asciicast progress-var-elapsed-clock, echo = 2:5} #' x <- invisible(quote( #' cli_progress_bar( #' total = 100, #' format = "{cli::pb_bar} {cli::pb_percent} [{cli::pb_elapsed_clock}]" #' ) #' )) #' cli:::var_helper2(x, current = 65, delay = 5) #' ``` cli__pb_elapsed_clock <- function(pb = getOption("cli__pb")) { if (is.null(pb)) return("") s <- (.Call(clic_get_time) - pb$start) * clienv$speed_time hours <- floor(s / 3600) minutes <- floor((s / 60) %% 60) seconds <- round(s %% 60, 1) paste0( formatC(hours, width = 2, flag = "0"), ":", formatC(minutes, width = 2, flag = "0"), ":", formatC(seconds, width = 2, flag = "0") ) } #' @name progress-variables #' @export pb_elapsed_raw #' @usage NULL #' @aliases pb_elapsed_raw #' #' @details #' ### `pb_elapsed_raw` #' #' The number of seconds since the start of the progress bar. #' #' ```{asciicast progress-var-elapsed-raw, echo = 2:5} #' x <- invisible(quote( #' cli_progress_bar( #' total = 100, #' format = "{cli::pb_bar} {cli::pb_percent} [{round(cli::pb_elapsed_raw)}s]" #' ) #' )) #' cli:::var_helper2(x, current = 65, delay = 5) #' ``` cli__pb_elapsed_raw <- function(pb = getOption("cli__pb")) { if (is.null(pb)) return("") (.Call(clic_get_time) - pb$start) * clienv$speed_time } #' @name progress-variables #' @export pb_eta #' @usage NULL #' @aliases pb_eta #' #' @details #' ### `pb_eta` #' #' The estimated time until the end of the progress bar, #' in human readable form. #' #' ```{asciicast progress-var-eta, echo = 2:5} #' x <- invisible(quote( #' cli_progress_bar( #' total = 100, #' format = "{cli::pb_bar} {cli::pb_percent} | ETA: {cli::pb_eta}" #' ) #' )) #' cli:::var_helper2(x, current = 65, delay = 5) #' ``` cli__pb_eta <- function(pb = getOption("cli__pb")) { if (is.null(pb)) return("") eta <- cli__pb_eta_raw(pb) if (is.na(eta)) { "?" } else { format_time_ago$vague_dt(eta, format = "terse") } } #' @name progress-variables #' @export pb_eta_raw #' @usage NULL #' @aliases pb_eta_raw #' #' @details #' ### `pb_eta_raw` #' #' The estimated time until the end of the progress #' bar, in seconds. This is useful if you want to adjust the default #' `pb_eta` display. #' #' ```{asciicast progress-var-eta-raw, echo = 2:5} #' x <- invisible(quote( #' cli_progress_bar( #' total = 100, #' format = "{cli::pb_bar} {cli::pb_percent} | ETA: {round(cli::pb_eta_raw)}s" #' ) #' )) #' cli:::var_helper2(x, current = 65, delay = 5) #' ``` cli__pb_eta_raw <- function(pb = getOption("cli__pb")) { if (is.null(pb)) return("") if (is.na(pb$total)) return(NA_real_) if (pb$current == pb$total) return(as.difftime(0, units = "secs")) if (pb$current == 0L) return(NA_real_) elapsed <- (.Call(clic_get_time) - pb$start) * clienv$speed_time as.difftime(elapsed * (pb$total / pb$current - 1.0), units = "secs") } #' @name progress-variables #' @export pb_eta_str #' @usage NULL #' @aliases pb_eta_str #' #' @details #' ### `pb_eta_str` #' #' The estimated time until the end of the progress bar. #' It includes the `"ETA:"` prefix. It is only shown if the time can be #' estimated, otherwise it is the empty string. #' #' ```{asciicast progress-var-eta-str, echo = 2:5} #' x <- invisible(quote( #' cli_progress_bar( #' total = 100, #' format = "{cli::pb_bar} {cli::pb_percent} | {cli::pb_eta_str}" #' ) #' )) #' cli:::var_helper2(x, current = 65, delay = 5) #' ``` cli__pb_eta_str <- function(pb = getOption("cli__pb")) { if (is.null(pb)) return("") eta <- cli__pb_eta(pb) if (eta != "?") paste0("ETA: ", eta) else "" } #' @name progress-variables #' @export pb_extra #' @usage NULL #' @aliases pb_extra #' #' @details #' ### `pb_extra` #' #' `pb_extra` can be used to access extra data, see the `extra` argument #' of `cli_progress_bar()` and `cli_progress_update()`. #' #' ```{asciicast progress-var-extra, echo = 2:6} #' x <- invisible(quote( #' cli_progress_bar( #' total = 100, #' extra = list(user = whoami::username()), #' format = "Cleaning cache for user '{cli::pb_extra$user}': {cli::pb_current_bytes}" #' ) #' )) #' cli:::var_helper(x, current = 1024 * 1024 * 154) #' ``` cli__pb_extra <- function(pb = getOption("cli__pb")) { if (is.null(pb)) return("") pb$extra } #' @name progress-variables #' @export pb_id #' @usage NULL #' @aliases pb_id #' #' @details #' ### `pb_id` #' #' The id of the progress bar. The id has the format #' `cli--` where `` is the process id, and #' `` is an integer counter that is incremented every time #' cli needs a new unique id. #' #' This is useful for debugging progress bars. #' #' ```{asciicast progress-var-id, echo = 2:4} #' x <- invisible(quote( #' cli_progress_bar( #' format = "Progress bar '{cli::pb_id}' is at {cli::pb_current}" #' ) #' )) #' cli:::var_helper(x, current = 64) #' ``` cli__pb_id <- function(pb = getOption("cli__pb")) { if (is.null(pb)) return("") pb$id } #' @name progress-variables #' @export pb_name #' @usage NULL #' @aliases pb_name #' #' @details #' ### `pb_name` #' #' The name of the progress bar. This is supplied by the #' developer, and it is by default the empty string. A space character #' is added to non-empty names. #' #' ```{asciicast progress-var-name, echo = 2:6} #' x <- invisible(quote( #' cli_progress_bar( #' name = "Loading training data", #' total = 100, #' format = "{cli::pb_name} {cli::pb_bar} {cli::pb_percent}" #' ) #' )) #' cli:::var_helper(x, current = 66) #' ``` #' cli__pb_name <- function(pb = getOption("cli__pb")) { if (is.null(pb)) return("") if (!is.null(pb$name)) { paste0(pb$name, " ") } else { "" } } #' @name progress-variables #' @export pb_percent #' @usage NULL #' @aliases pb_percent #' #' @details #' ### `pb_percent` #' #' The percentage of the progress bar, always formatted #' in three characters plus the percentage sign. If the total number of #' units is unknown, then it is `" NA%"`. #' #' ```{asciicast progress-var-percent, echo = 2:5} #' x <- invisible(quote( #' cli_progress_bar( #' total = 100, #' format = "{cli::pb_bar} {cli::pb_percent}" #' ) #' )) #' cli:::var_helper(x, current = 66) #' ``` cli__pb_percent <- function(pb = getOption("cli__pb")) { if (is.null(pb)) return("") paste0(format(round(pb$current / pb$total * 100), width = 3), "%") } #' @name progress-variables #' @export pb_pid #' @usage NULL #' @aliases pb_pid #' #' @details #' ### `pb_pid` #' #' The integer process id of the progress bar. This is useful if you are #' aggregating logging output or progress results from multiple processes. cli__pb_pid <- function(pb = getOption("cli__pb")) { if (is.null(pb)) return("") pb$pid %||% Sys.getpid() } #' @name progress-variables #' @export pb_rate #' @usage NULL #' @aliases pb_rate #' #' @details #' ### `pb_rate` #' #' The progress rate, in number of units per second, formatted in a string. #' #' ```{asciicast progress-var-rate, echo = 2:5} #' x <- invisible(quote( #' cli_progress_bar( #' total = 156, #' format = "Reading input files {pb_current}/{pb_total} [{pb_rate}]" #' ) #' )) #' cli:::var_helper2(x, current = 67, delay = 5) #' ``` cli__pb_rate <- function(pb = getOption("cli__pb")) { if (is.null(pb)) return("") rate <- cli__pb_rate_raw(pb) if (is.nan(rate) || is.na(rate) || is.infinite(rate)) return("?/s") paste0(format(rate, digits = 2), "/s") } #' @name progress-variables #' @export pb_rate_raw #' @usage NULL #' @aliases pb_rate_raw #' #' @details #' ### `pb_rate_raw` #' #' The raw progress rate, in number of units per second. #' #' ```{asciicast progress-var-rate-raw, echo = 2:5} #' x <- invisible(quote( #' cli_progress_bar( #' total = 156, #' format = "Reading input files {pb_current}/{pb_total} [{round(pb_rate_raw)}/s]" #' ) #' )) #' cli:::var_helper2(x, current = 67, delay = 5) #' ``` cli__pb_rate_raw <- function(pb = getOption("cli__pb")) { if (is.null(pb)) return("") elapsed <- cli__pb_elapsed_raw(pb) pb$current / elapsed } #' @name progress-variables #' @export pb_rate_bytes #' @usage NULL #' @aliases pb_rate_bytes #' #' @details #' ### `pb_rate_bytes` #' #' The progress rate, formatted as bytes per second, in human readable form. #' #' ```{asciicast progress-var-rate-bytes, echo = 2:7} #' x <- invisible(quote( #' cli_progress_bar( #' total = 256 * 1024 * 1014, #' format = paste0( #' "Reading data {pb_current_bytes}/{pb_total_bytes} ", #' "[{ansi_trimws(pb_rate_bytes)}]" #' ) #' ) #' )) #' cli:::var_helper2(x, current = 67 * 1024 * 1024, delay = 5) #' ``` cli__pb_rate_bytes <- function(pb = getOption("cli__pb")) { if (is.null(pb)) return("") rate <- cli__pb_rate_raw(pb) paste0( format_bytes$pretty_bytes(rate, style = "6"), "/s" ) } #' @name progress-variables #' @export pb_spin #' @usage NULL #' @aliases pb_spin #' #' @details #' ### `pb_spin` #' #' A spinner. The default spinner is selected via a [get_spinner()] call. #' #' ```{asciicast progress-var-current, echo = 2:5} #' x <- invisible(quote( #' cli_progress_bar( #' total = 100, #' format = "{cli::pb_spin} Reading file {cli::pb_current}/{cli::pb_total}" #' ) #' )) #' cli:::var_helper(x, current = 66) #' ``` cli__pb_spin <- function(pb = getOption("cli__pb")) { if (is.null(pb)) return("") pb$spinner <- pb$spinner %||% get_spinner() nx <- pb$tick %% length(pb$spinner$frames) + 1L pb$spinner$frames[[nx]] } #' @name progress-variables #' @export pb_status #' @usage NULL #' @aliases pb_status #' #' @details #' ### `pb_status` #' #' The status string of the progress bar. By default this is an empty #' string, but it is possible to set it in [cli_progress_bar()] #' and `cli_progress_update()]. #' #' ```{asciicast progress-var-status, echo = 2} #' x <- invisible(quote( #' cli_progress_bar(status = "Connecting...") #' )) #' cli:::var_helper(x, current = 0, delay = 1) #' ``` cli__pb_status <- function(pb = getOption("cli__pb")) { if (is.null(pb)) return("") if (!is.null(pb$status)) { paste0(pb$status, " ") } else { "" } } #' @name progress-variables #' @export pb_timestamp #' @usage NULL #' @aliases pb_timestamp #' #' @details #' ### `pb_timestamp` #' #' A time stamp for the current time in ISO 8601 format. #' #' ```{asciicast progress-var-timestamp, echo = 2:4} #' x <- invisible(quote( #' cli_progress_bar( #' "Loading training data files", #' format = "{pb_timestamp} {pb_current} ({pb_rate})" #' ) #' )) #' cli:::var_helper(x, current = 125, delay = 5) #' ``` cli__pb_timestamp <- function(pb = getOption("cli__pb")) { if (is.null(pb)) return("") st <- Sys.time() if (clienv$speed_time != 1.0) { st <- clienv$load_time + (st - clienv$load_time) * clienv$speed_time } format_iso_8601(st) } #' @name progress-variables #' @export pb_total #' @usage NULL #' @aliases pb_total #' #' @details #' ### `pb_total` #' #' The total number of progress units, or `NA` if the number of units is #' unknown. #' #' ```{asciicast progress-var-current, echo = 2:5} #' x <- invisible(quote( #' cli_progress_bar( #' total = 100, #' format = "{cli::pb_spin} Reading file {cli::pb_current}/{cli::pb_total}" #' ) #' )) #' cli:::var_helper(x, current = 66) #' ``` cli__pb_total <- function(pb = getOption("cli__pb")) { if (is.null(pb)) return("") pb$total } #' @name progress-variables #' @export pb_total_bytes #' @usage NULL #' @aliases pb_total_bytes #' #' @details #' ### `pb_total_bytes` #' #' The total number of progress units, formatted as #' bytes, in a human readable format. #' #' ```{asciicast progress-var-rate-bytes, echo = 2:7} #' x <- invisible(quote( #' cli_progress_bar( #' total = 256 * 1024 * 1014, #' format = paste0( #' "Reading data {pb_current_bytes}/{pb_total_bytes} ", #' "[{ansi_trimws(pb_rate_bytes)}]" #' ) #' ) #' )) #' cli:::var_helper2(x, current = 67 * 1024 * 1024, delay = 5) #' ``` cli__pb_total_bytes <- function(pb = getOption("cli__pb")) { if (is.null(pb)) return("") format_bytes$pretty_bytes(pb$total, style = "6") } # ------------------------------------------------------------------------ var_helper <- function(expr, current = 66, delay = 1) { expr[[1]] <- quote(cli_progress_demo) expr$at <- current expr$start <- as.difftime(delay, units = "secs") eval(expr) } var_helper2 <- function(expr, clear = TRUE, delay = 0, ...) { expr$.envir <- environment() id <- eval(expr, envir = new.env()) bar <- clienv$progress[[id]] bar$start <- bar$start - delay bar$clear <- clear args <- list(...) for (i in seq_along(args)) bar[[names(args)[i]]] <- args[[i]] cli_progress_update(force = TRUE, id = id) cat("\n") suppressMessages(cli_progress_done(id = id)) } # ------------------------------------------------------------------------ #' cli progress bar demo #' #' Useful for experimenting with format strings and for documentation. #' It creates a progress bar, iterates it until it terminates and saves the #' progress updates. #' #' @param name Passed to [cli_progress_bar()]. #' @param status Passed to [cli_progress_bar()]. #' @param type Passed to [cli_progress_bar()]. #' @param total Passed to [cli_progress_bar()]. #' @param .envir Passed to [cli_progress_bar()]. #' @param ... Passed to [cli_progress_bar()]. #' @param at The number of progress units to show and capture the progress #' bar at. If `NULL`, then a sequence of states is generated to show the #' progress from beginning to end. #' @param show_after Delay to show the progress bar. Overrides the #' `cli.progress_show_after` option. #' @param live Whether to show the progress bat on the screen, or just #' return the recorded updates. Defaults to the value of the #' `cli.progress_demo_live` options. If unset, then it is `TRUE` in #' interactive sessions. #' @param delay Delay between progress bar updates. #' @param start Time to subtract from the start time, to simulate a #' progress bar that takes longer to run. #' #' @return List with class `cli_progress_demo`, which has a print and a #' format method for pretty printing. The `lines` entry contains the #' output lines, each corresponding to one update. #' #' @export # TODO: examples cli_progress_demo <- function(name = NULL, status = NULL, type = c("iterator", "tasks", "download", "custom"), total = NA, .envir = parent.frame(), ..., at = if (is_interactive()) NULL else 50, show_after = 0, live = NULL, delay = 0, start = as.difftime(5, units = "secs")) { opt <- options(cli.progress_show_after = show_after) on.exit(options(opt), add = TRUE) live <- live %||% getOption("cli.progress_demo_live") %||% is_interactive() id <- cli_progress_bar( name = name, status = status, type = type, total = total, ..., .envir = .envir, current = FALSE ) bar <- clienv$progress[[id]] bar$start <- bar$start - as.double(start, units = "secs") last <- is.null(at) if (is.null(at)) { if (is.na(total)) { at <- 1:5 } else { at <- seq_len(total) } } output <- file(open = "w+b") on.exit(close(output), add = TRUE) size <- 0L withCallingHandlers({ for (crnt in at) { cli_progress_update(set = crnt, id = id, force = TRUE, .envir = .envir) if (delay > 0) Sys.sleep(delay) } if (last) { cli_progress_done(id = id, .envir = .envir) } else { suppressMessages(cli_progress_done(id = id, .envir = .envir)) } }, cliMessage = function(msg) { cat(file = output, msg$message) size <<- size + nchar(msg$message, type = "bytes") if (!live) invokeRestart("muffleMessage") }) lines <- readChar(output, size, useBytes = TRUE) lines <- sub_("^\r\r*", "", lines, useBytes = TRUE) lines <- sub_("\r\r*$", "", lines, useBytes = TRUE) lines <- gsub_("\r\r*", "\r", lines, useBytes = TRUE) lines <- strsplit_(lines, "[\r\n]", useBytes = TRUE)[[1]] res <- structure( list(lines = lines), class = "cli_progress_demo" ) if (live) invisible(res) else res } #' @export format.cli_progress_demo <- function(x, ...) { x$lines } #' @export print.cli_progress_demo <- function(x, ...) { cat(format(x, ...), sep = "\n") } cli/R/lorem.R0000644000176200001440000000310614557444176012504 0ustar liggesusers lorem_words <- c( "ad", "adipisicing", "aliqua", "aliquip", "amet", "anim", "aute", "cillum", "commodo", "consectetur", "consequat", "culpa", "cupidatat", "deserunt", "do", "dolor", "dolore", "duis", "ea", "eiusmod", "elit", "enim", "esse", "est", "et", "eu", "ex", "excepteur", "exercitation", "fugiat", "id", "in", "incididunt", "ipsum", "irure", "labore", "laboris", "laborum", "Lorem", "magna", "minim", "mollit", "nisi", "non", "nostrud", "nulla", "occaecat", "officia", "pariatur", "proident", "qui", "quis", "reprehenderit", "sint", "sit", "sunt", "tempor", "ullamco", "ut", "velit", "veniam", "voluptate" ) lorem_ipsum <- function(paragraphs = 1, par_sentence_range = 5:10, sentence_word_range = 5:15) { vcapply( 1:paragraphs, function(x, ...) lorem_paragraph(...), par_sentence_range = par_sentence_range, sentence_word_range = sentence_word_range ) } lorem_paragraph <- function(par_sentence_range, sentence_word_range) { num <- sample(par_sentence_range, 1) paste( collapse = " ", vcapply( 1:num, function(x, ...) lorem_sentence(...), sentence_word_range = sentence_word_range ) ) } lorem_sentence <- function(sentence_word_range) { num <- sample(sentence_word_range, 1) words <- sample(lorem_words, num, replace = TRUE) words[1] <- capitalize(words[1]) paste0(paste(words, collapse = " "), ".") } capitalize <- function(x) { substr(x, 1, 1) <- toupper(substr(x, 1, 1)) x } cli/R/format-conditions.R0000644000176200001440000001132314557444176015025 0ustar liggesusers #' Format an error, warning or diagnostic message #' #' You can then throw this message with [stop()] or `rlang::abort()`. #' #' The messages can use inline styling, pluralization and glue #' substitutions. #' #' ```{asciicast format-error} #' n <- "boo" #' stop(format_error(c( #' "{.var n} must be a numeric vector", #' "x" = "You've supplied a {.cls {class(n)}} vector." #' ))) #' ``` #' #' ```{asciicast format-error-2} #' len <- 26 #' idx <- 100 #' stop(format_error(c( #' "Must index an existing element:", #' "i" = "There {?is/are} {len} element{?s}.", #' "x" = "You've tried to subset element {idx}." #' ))) #' ``` #' #' @param message It is formatted via a call to [cli_bullets()]. #' @param .envir Environment to evaluate the glue expressions in. #' #' @seealso These functions support [inline markup][inline-markup]. #' @family functions supporting inline markup #' @export format_error <- function(message, .envir = parent.frame()) { if (length(message) > 0 && (is.null(names(message)) || names(message)[1] == "")) { # The default theme will make this bold names(message)[1] <- "1" } if (length(message) > 0) { message[1] <- paste0("Error: ", message[1]) } rsconsole <- c("rstudio_console", "rstudio_console_starting") oldopt <- options( cli.width = getOption("cli.condition_width") %||% getOption("cli.width") ) on.exit(options(oldopt), add =TRUE) # We need to create a frame here, so cli_div() is closed. # Cannot use local(), it does not work in snapshot tests, it potentially # has issues elsewhere as well. formatted1 <- cli_fmt((function() { cli_div(class = "cli_rlang cli_abort", theme = cnd_theme()) cli_bullets(message, .envir = .envir) })(), collapse = TRUE, strip_newline = TRUE) # remove "Error: " that was only needed for the wrapping formatted1[1] <- sub("Error:[ ]?", "", formatted1[1]) update_rstudio_color(formatted1) } #' @rdname format_error #' @export format_warning <- function(message, .envir = parent.frame()) { if (length(message) > 0 && (is.null(names(message)) || names(message)[1] == "")) { # The default theme will make this bold names(message)[1] <- "1" } oldopt <- options( cli.width = getOption("cli.condition_width") %||% getOption("cli.width") ) on.exit(options(oldopt), add = TRUE) formatted1 <- cli_fmt((function() { cli_div(class = "cli_rlang cli_warn", theme = cnd_theme()) cli_bullets(message, .envir = .envir) })(), collapse = TRUE, strip_newline = TRUE) update_rstudio_color(formatted1) } #' @rdname format_error #' @export format_message <- function(message, .envir = parent.frame()) { oldopt <- options( cli.width = getOption("cli.condition_width") %||% getOption("cli.width") ) on.exit(options(oldopt), add = TRUE) formatted1 <- cli_fmt((function() { cli_div(class = "cli_rlang cli_inform", theme = cnd_theme()) cli_bullets(message, .envir = .envir) })(), collapse = TRUE, strip_newline = TRUE) update_rstudio_color(formatted1) } update_rstudio_color <- function(message) { rscol <- get_rstudio_fg_color() if (!is.null(rscol)) { # in RStudio we only need to change the color message[] <- rscol(message) } else { # in a terminal we need to undo the bold message <- paste0(style_bold(""), message) } message } get_rstudio_fg_color <- function() { tryCatch( get_rstudio_fg_color0(), error = function(e) NULL ) } get_rstudio_fg_color0 <- function() { rs <- rstudio_detect() oktypes <- c("rstudio_console", "rstudio_console_starting") if (! rs$type %in% oktypes) return(NULL) if (rs$num_colors == 1) return(NULL) colstr <- get_rstudio_theme()$foreground if (is.null(colstr)) return(NULL) colstr0 <- substr(colstr, 5, nchar(colstr) - 1) rgbnum <- scan(text = colstr0, sep = ",", quiet = TRUE) rgb <- grDevices::rgb(rgbnum[1]/255, rgbnum[2]/255, rgbnum[3]/255) make_ansi_style(rgb) } rstudio_detect <- function() { rstudio$detect() } cnd_theme <- function() { list( ".cli_rlang .bullets .bullet-v" = list( before = function(x) paste0(col_green(cnd_symb("tick")), " ") ), ".bullets .bullet-x" = list( before = function(x) paste0(col_red(cnd_symb("cross")), " ") ), ".bullets .bullet-i" = list( before = function(x) paste0(col_cyan(cnd_symb("info")), " ") ), ".bullets .bullet-*" = list( before = function(x) paste0(col_cyan(cnd_symb("bullet")), " ") ), ".bullets .bullet->" = list( before = function(x) paste0(cnd_symb("arrow_right"), " ") ) ) } cnd_symb <- function(name) { opt <- getOption("cli.condition_unicode_bullets", NULL) if (isTRUE(opt)) { symbol_utf8[[name]] } else if (isFALSE(opt)) { symbol_ascii[[name]] } else { symbol[[name]] } } cli/R/rlang.R0000644000176200001440000000332314557444176012472 0ustar liggesusers #' Signal an error, warning or message with a cli formatted #' message #' #' These functions let you create error, warning or diagnostic #' messages with cli formatting, including inline styling, #' pluralization and glue substitutions. #' #' @details #' #' ```{asciicast cli-abort} #' n <- "boo" #' cli_abort(c( #' "{.var n} must be a numeric vector", #' "x" = "You've supplied a {.cls {class(n)}} vector." #' )) #' ``` #' #' ```{asciicast cli-abort-2} #' len <- 26 #' idx <- 100 #' cli_abort(c( #' "Must index an existing element:", #' "i" = "There {?is/are} {len} element{?s}.", #' "x" = "You've tried to subset element {idx}." #' )) #' ``` #' #' @param message It is formatted via a call to [cli_bullets()]. #' @param ... Passed to [rlang::abort()], [rlang::warn()] or #' [rlang::inform()]. #' @param .envir Environment to evaluate the glue expressions in. #' @inheritParams rlang::abort #' #' @seealso These functions support [inline markup][inline-markup]. #' @family functions supporting inline markup #' @export cli_abort <- function(message, ..., call = .envir, .envir = parent.frame(), .frame = .envir) { message[] <- vcapply(message, format_inline, .envir = .envir) rlang::abort( message, ..., call = call, use_cli_format = TRUE, .frame = .frame ) } #' @rdname cli_abort #' @export cli_warn <- function(message, ..., .envir = parent.frame()) { rlang::warn( format_warning(message, .envir = .envir), ... ) } #' @rdname cli_abort #' @export cli_inform <- function(message, ..., .envir = parent.frame()) { rlang::inform( format_message(message, .envir = .envir), ... ) } cli/R/test.R0000644000176200001440000001466414752735214012351 0ustar liggesusers #' Test cli output with testthat #' #' Use this function in your testthat test files, to test cli output. #' It requires testthat edition 3, and works best with snapshot tests. #' #' `test_that_cli()` calls [testthat::test_that()] multiple times, with #' different cli configurations. This makes it simple to test cli output #' with and without ANSI colors, with and without Unicode characters. #' #' Currently available configurations: #' * `plain`: no ANSI colors, ASCII characters only. #' * `ansi`: ANSI colors, ASCII characters only. #' * `unicode`: no ANSI colors, Unicode characters. #' * `fancy`; ANSI colors, Unicode characters. #' #' See examples below and in cli's own tests, e.g. in #' #' and the corresponding snapshots at #' #' #' ## Important note regarding Windows #' #' Because of base R's limitation to record Unicode characters on Windows, #' we suggest that you record your snapshots on Unix, or you restrict #' your tests to ASCII configurations. #' #' Unicode tests on Windows are automatically skipped by testthat #' currently. #' #' @param desc Test description, passed to [testthat::test_that()], after #' appending the name of the cli configuration to it. #' @param code Test code, it is modified to set up the cli config, and #' then passed to [testthat::test_that()] #' @param configs cli configurations to test `code` with. The default is #' `NULL`, which includes all possible configurations. It can also be a #' character vector, to restrict the tests to some configurations only. #' See available configurations below. #' @param links Whether to run the code with various hyperlinks allowed. #' If `NULL` then hyperlinks are turned off. Otherwise it can be a character #' vector with possible hyperlink configurations: #' * `"all"`: turn on all hyperlinks, #' * `"none"`: turn off all hyperlinks. #' #' @export #' @examples #' # testthat cannot record or compare snapshots when you run these #' # examples interactively, so you might want to copy them into a test #' # file #' #' # Default configurations #' cli::test_that_cli("success", { #' testthat::local_edition(3) #' testthat::expect_snapshot({ #' cli::cli_alert_success("wow") #' }) #' }) #' #' # Only use two configurations, because this output does not have colors #' cli::test_that_cli(configs = c("plain", "unicode"), "cat_bullet", { #' testthat::local_edition(3) #' testthat::expect_snapshot({ #' cli::cat_bullet(letters[1:5]) #' }) #' }) #' #' # You often need to evaluate all cli calls of a test case in the same #' # environment. Use `local()` to do that: #' cli::test_that_cli("theming", { #' testthat::local_edition(3) #' testthat::expect_snapshot(local({ #' cli::cli_div(theme = list(".alert" = list(before = "!!! "))) #' cli::cli_alert("wow") #' })) #' }) test_that_cli <- function(desc, code, configs = c("plain", "ansi", "unicode", "fancy"), links = NULL) { code <- substitute(code) configs <- apply(expand.grid(configs, links %||% ""), 1, paste, collapse = "-") configs <- sub("-$", "", configs) doconfigs <- list( list(id = "plain", unicode = FALSE, num_colors = 1, links = FALSE), list(id = "ansi", unicode = FALSE, num_colors = 256, links = FALSE), list(id = "unicode", unicode = TRUE, num_colors = 1, links = FALSE), list(id = "fancy", unicode = TRUE, num_colors = 256, links = FALSE), list(id = "plain-none", unicode = FALSE, num_colors = 1, links = FALSE), list(id = "ansi-none", unicode = FALSE, num_colors = 256, links = FALSE), list(id = "unicode-none", unicode = TRUE, num_colors = 1, links = FALSE), list(id = "fancy-none", unicode = TRUE, num_colors = 256, links = FALSE), list(id = "plain-all", unicode = FALSE, num_colors = 1, links = TRUE), list(id = "ansi-all", unicode = FALSE, num_colors = 256, links = TRUE), list(id = "unicode-all", unicode = TRUE, num_colors = 1, links = TRUE), list(id = "fancy-all", unicode = TRUE, num_colors = 256, links = TRUE) ) parent <- parent.frame() lapply(doconfigs, function(conf) { if (!is.null(configs) && ! conf$id %in% configs) return() code2 <- substitute({ testthat::local_reproducible_output( crayon = num_colors > 1, unicode = unicode ) withr::local_options( cli.hyperlink = links, cli.hyperlink_help = links, cli.hyperlink_run = links, cli.hyperlink_vignette = links, cli.hyperlink_file_url_format = NULL, cli.hyperlink_run_url_format = NULL, cli.hyperlink_help_url_format = NULL, cli.hyperlink_vignette_url_format = NULL ) withr::local_envvar( R_CLI_HYPERLINK_FILE_URL_FORMAT = NA_character_, R_CLI_HYPERLINK_RUN_URL_FORMAT = NA_character_, R_CLI_HYPERLINK_HELP_URL_FORMAT = NA_character_, R_CLI_HYPERLINK_VIGNETTE_URL_FORMAT = NA_character_ ) code_ }, c(conf, list(code_ = code))) desc2 <- paste0(desc, " [", conf$id, "]") test <- substitute( testthat::test_that(desc, code), list(desc = desc2, code = code2) ) eval(test, envir = parent) }) } local_clean_cli_context <- function(.local_envir = parent.frame()) { withr::local_options( .local_envir = .local_envir, cli.hyperlink = NULL, cli.hyperlink_run = NULL, cli.hyperlink_help = NULL, cli.hyperlink_vignette = NULL, cli.hyperlink_file_url_format = NULL, cli.hyperlink_run_url_format = NULL, cli.hyperlink_help_url_format = NULL, cli.hyperlink_vignette_url_format = NULL, cli.num_colors = NULL, cli.palette = NULL, crayon.enabled = NULL ) withr::local_envvar( .local_envir = .local_envir, R_CLI_HYPERLINKS = NA_character_, R_CLI_HYPERLINK_RUN = NA_character_, R_CLI_HYPERLINK_HELP = NA_character_, R_CLI_HYPERLINK_VIGNETTE = NA_character_, R_CLI_HYPERLINK_FILE_URL_FORMAT = NA_character_, R_CLI_HYPERLINK_RUN_URL_FORMAT = NA_character_, R_CLI_HYPERLINK_HELP_URL_FORMAT = NA_character_, R_CLI_HYPERLINK_VIGNETTE_URL_FORMAT = NA_character_, RSTUDIO_CLI_HYPERLINKS = NA_character_, R_CLI_NUM_COLORS = NA_character_, NO_COLOR = NA_character_, WT_SESSION = NA_character_, CI = NA_character_, TEAMCITY_VERSION = NA_character_, TERM_PROGRAM = NA_character_, TERM_PROGRAM_VERSION = NA_character_, VTE_VERSION = NA_character_ ) } cli/R/debug.R0000644000176200001440000000420014557444176012450 0ustar liggesusers #' Debug cli internals #' #' Return the current state of a cli app. It includes the currently #' open tags, their ids, classes and their computed styles. #' #' The returned data frame has a print method, and if you want to create #' a plain data frame from it, index it with an empty bracket: #' `cli_debug_doc()[]`. #' #' To see all currently active themes, use `app$themes`, e.g. for the #' default app: `default_app()$themes`. #' #' @param app The cli app to debug. Defaults to the current app. #' if there is no app, then it creates one by calling [start_app()]. #' @return Data frame with columns: `tag`, `id`, `class` (space separated), #' theme (id of the theme the element added), `styles` (computed styles #' for the element). #' #' @seealso [cli_sitrep()]. To debug containers, you can set the #' `CLI-DEBUG_BAD_END` environment variable to `true`, and then cli will #' warn when it cannot find the specified container to close (or any #' contained at all). #' #' @examples #' \dontrun{ #' cli_debug_doc() #' #' olid <- cli_ol() #' cli_li() #' cli_debug_doc() #' cli_debug_doc()[] #' #' cli_end(olid) #' cli_debug_doc() #' } cli_debug_doc <- function(app = default_app() %||% start_app()) { tgs <- vcapply(app$doc, "[[", "tag") ids <- vcapply(app$doc, "[[", "id") cls <- vcapply(app$doc, function(x) paste(x$class, collapse = " ")) thm <- lapply(app$doc, function(x) x$theme) df <- data.frame( stringsAsFactors = FALSE, tag = tgs, id = ids, class = cls, theme = I(as.list(thm)), styles = I(as.list(unname(app$styles))) ) class(df) <- c("cli_doc", class(df)) df } #' @export format.cli_doc <- function(x, ...) { nz <- nrow(x) > 0 c("", paste0( if (nz) "<", x$tag, if (nz) " id=\"", x$id, if (nz) "\"", ifelse (x$class == "", "", paste0(" class=\"", x$class, "\"")), if (nz) ">", ifelse (vlapply(x$theme, is.null), "", " +theme") ) ) } #' @export print.cli_doc <- function(x, ...) { cat(format(x, ...), sep = "\n") invisible(x) } #' @export `[.cli_doc` <- function(x, ...) { class(x) <- setdiff(class(x), "cli_doc") NextMethod() } cli/R/themes.R0000644000176200001440000003764114752735214012657 0ustar liggesusers #' List the currently active themes #' #' If there is no active app, then it calls [start_app()]. #' #' @return A list of data frames with the active themes. #' Each data frame row is a style that applies to selected CLI tree nodes. #' Each data frame has columns: #' * `selector`: The original CSS-like selector string. See [themes]. #' * `parsed`: The parsed selector, as used by cli for matching to nodes. #' * `style`: The original style. #' * `cnt`: The id of the container the style is currently applied to, or #' `NA` if the style is not used. #' #' @export #' @seealso [themes] cli_list_themes <- function() { app <- default_app() %||% start_app() app$list_themes() } clii_list_themes <- function(app) { app$themes } clii_add_theme <- function(app, theme) { id <- new_uuid() app$themes <- c(app$themes, structure(list(theme_create(theme)), names = id)) id } clii_remove_theme <- function(app, id) { if (! id %in% names(app$themes)) return(invisible(FALSE)) app$themes[[id]] <- NULL invisible(TRUE) } #' The built-in CLI theme #' #' This theme is always active, and it is at the bottom of the theme #' stack. See [themes]. #' #' # Showcase #' #' ```{asciicast builtin-theme} #' cli_h1("Heading 1") #' cli_h2("Heading 2") #' cli_h3("Heading 3") #' #' cli_par() #' cli_alert_danger("Danger alert") #' cli_alert_warning("Warning alert") #' cli_alert_info("Info alert") #' cli_alert_success("Success alert") #' cli_alert("Alert for starting a process or computation", #' class = "alert-start") #' cli_end() #' #' cli_text("Packages and versions: {.pkg cli} {.version 1.0.0}.") #' cli_text("Time intervals: {.timestamp 3.4s}") #' #' cli_text("{.emph Emphasis} and {.strong strong emphasis}") #' #' cli_text("This is a piece of code: {.code sum(x) / length(x)}") #' cli_text("Function names: {.fn cli::simple_theme}") #' #' cli_text("Files: {.file /usr/bin/env}") #' cli_text("URLs: {.url https://r-project.org}") #' #' cli_h2("Longer code chunk") #' cli_par(class = "code R") #' cli_verbatim( #' '# window functions are useful for grouped mutates', #' 'mtcars %>%', #' ' group_by(cyl) %>%', #' ' mutate(rank = min_rank(desc(mpg)))') #' ``` #' #' @seealso [themes], [simple_theme()]. #' @return A named list, a CLI theme. #' #' @param dark Whether to use a dark theme. The `cli.theme_dark` option #' can be used to request a dark theme explicitly. If this is not set, #' or set to `"auto"`, then cli tries to detect a dark theme, this #' works in recent RStudio versions and in iTerm on macOS. #' @export builtin_theme <- function(dark = getOption("cli.theme_dark", "auto")) { dark <- detect_dark_theme(dark) list( body = list( "class-map" = list( fs_path = "file", "cli-progress-bar" = "progress-bar" ) ), h1 = list( "font-weight" = "bold", "margin-top" = 1, "margin-bottom" = 0, fmt = function(x) cli::rule(x, line_col = "cyan")), h2 = list( "font-weight" = "bold", "margin-top" = 1, "margin-bottom" = 1, fmt = function(x) paste0(symbol$line, symbol$line, " ", x, " ", symbol$line, symbol$line)), h3 = list( "margin-top" = 1, fmt = function(x) paste0(symbol$line, symbol$line, " ", x, " ")), ".alert" = list( before = function() paste0(symbol$arrow_right, " ") ), ".alert-success" = list( before = function() paste0(col_green(symbol$tick), " ") ), ".alert-danger" = list( before = function() paste0(col_red(symbol$cross), " ") ), ".alert-warning" = list( before = function() paste0(col_yellow("!"), " ") ), ".alert-info" = list( before = function() paste0(col_cyan(symbol$info), " ") ), ".bullets .bullet-empty" = list(), ".bullets .bullet-space" = list("margin-left" = 2), ".bullets .bullet-v" = list( "text-exdent" = 2, before = function(x) paste0(col_green(symbol$tick), " ") ), ".bullets .bullet-x" = list( "text-exdent" = 2, before = function(x) paste0(col_red(symbol$cross), " ") ), ".bullets .bullet-!" = list( "text-exdent" = 2, before = function(x) paste0(col_yellow("!"), " ") ), ".bullets .bullet-i" = list( "text-exdent" = 2, before = function(x) paste0(col_cyan(symbol$info), " ") ), ".bullets .bullet-*" = list( "text-exdent" = 2, before = function(x) paste0(col_cyan(symbol$bullet), " ") ), ".bullets .bullet->" = list( "text-exdent" = 2, before = function(x) paste0(symbol$arrow_right, " ") ), ".bullets .bullet-1" = list( ), par = list("margin-top" = 0, "margin-bottom" = 1), ul = list( "list-style-type" = function() symbol$bullet ), # these are tags in HTML, but in cli they are inline span.dt = list(postfix = ": "), span.dd = list(), # This means that list elements have a margin, if they are nested "ul ul li" = list("margin-left" = 2), "ul ol li" = list("margin-left" = 2), "ul dl li" = list("margin-left" = 2), "ol ul li" = list("margin-left" = 2), "ol ol li" = list("margin-left" = 2), "ol dl li" = list("margin-left" = 2), "ol ul li" = list("margin-left" = 2), "ol ol li" = list("margin-left" = 2), "ol dl li" = list("margin-left" = 2), blockquote = list("padding-left" = 4L, "padding-right" = 10L, "font-style" = "italic", "margin-top" = 1L, "margin-bottom" = 1L, before = function() symbol$dquote_left, after = function() symbol$dquote_right), "blockquote cite" = list( before = function() paste0(symbol$em_dash, " "), "font-style" = "italic", "font-weight" = "bold" ), .code = list(fmt = format_code(dark)), .code.R = list(fmt = format_r_code(dark)), span.emph = list("font-style" = "italic"), span.strong = list("font-weight" = "bold"), span.code = theme_code_tick(dark), span.q = list(fmt = quote_weird_name2), span.pkg = list(color = "blue"), span.fn = theme_function(dark), span.fun = theme_function(dark), span.arg = theme_code_tick(dark), span.kbd = list(before = "[", after = "]", color = "blue"), span.key = list(before = "[", after = "]", color = "blue"), span.file = theme_file(), span.path = theme_file(), span.email = list( color = "blue", transform = function(x) make_link(x, type = "email"), fmt = quote_weird_name ), span.url = list( before = "<", after = ">", color = "blue", "font-style" = "italic", transform = function(x) make_link(x, type = "url") ), span.href = list( transform = function(x) make_link(x, type = "href") ), span.help = list( transform = function(x) make_link(x, type = "help") ), span.topic = list( transform = function(x) make_link(x, type = "topic") ), span.vignette = list( transform = function(x) make_link(x, type = "vignette") ), span.run = list( transform = function(x) make_link(x, type = "run") ), span.var = theme_code_tick(dark), span.col = theme_code_tick(dark), span.str = list(fmt = encode_string), span.envvar = theme_code_tick(dark), span.val = list( transform = function(x, ...) cli_format(x, ...), color = "blue" ), span.field = list(color = "green"), span.cls = list(collapse = "/", color = "blue", before = "<", after = ">"), "span.progress-bar" = list( transform = theme_progress_bar, color = "green" ), span.obj_type_friendly = list( transform = function(x) format_inline(typename(x)) ), span.type = list( transform = function(x) format_inline(typename(x)) ), span.or = list("vec-sep2" = " or ", "vec-last" = ", or "), span.timestamp = list(before = "[", after = "]", color = "grey") ) } encode_string <- function(x) { encodeString(x, quote = "\"") } quote_weird_name0 <- function(x) { x <- gsub(" ", "\u00a0", x, fixed = TRUE) x2 <- ansi_strip(x) fc <- first_character(x2) sc <- second_character(x2) lc <- last_character(x2) wfst <- !is_alnum(fc, ok = "~") || (fc == "~" && !is_alnum(sc)) wlst <- !is_alnum(lc) if (wfst || wlst) { lsp <- leading_space(x2) tsp <- trailing_space(x2) if (nzchar(lsp)) { x <- paste0( bg_blue(lsp), ansi_substr(x, nchar(lsp) + 1, ansi_nchar(x)) ) } if (nzchar(tsp)) { x <- paste0( ansi_substr(x, 1, ansi_nchar(x) - nchar(tsp)), bg_blue(tsp) ) } } list(x, wfst || wlst) } quote_weird_name <- function(x) { x2 <- quote_weird_name0(x) if (x2[[2]] || num_ansi_colors() == 1) { x2[[1]] <- paste0("'", x2[[1]], "'") } x2[[1]] } quote_weird_name2 <- function(x) { x2 <- quote_weird_name0(x) paste0("\"", x2[[1]], "\"") } theme_progress_bar <- function(x, app, style) { make_progress_bar(x$current / x$total, style = style) } detect_dark_theme <- function(dark) { tryCatch({ if (dark == "auto") { dark <- if (Sys.getenv("RSTUDIO", "0") == "1") { get_rstudio_theme()$dark } else if (is_iterm()) { is_iterm_dark() } else if (is_emacs()) { Sys.getenv("ESS_BACKGROUND_MODE", "light") == "dark" } else { FALSE } } }, error = function(e) FALSE) isTRUE(dark) } theme_code <- function(dark) { list() } tick_formatter <- function(x) { tt <- grepl("`", x, fixed = TRUE) + 1L t1 <- c("`", "`` ")[tt] t2 <- c("`", " ``")[tt] paste0(t1, x, t2) } tick_formatter_fun <- function(x) { tt <- grepl("`", x, fixed = TRUE) + 1L t1 <- c("`", "`` ")[tt] t2 <- c("()`", " ()``")[tt] paste0(t1, x, t2) } theme_code_tick <- function(dark) { utils::modifyList( theme_code(dark), list(transform = tick_formatter) ) } theme_function <- function(dark) { utils::modifyList( theme_code(dark), list(transform = function(x) tick_formatter_fun(make_link(x, type = "fun"))) ) } theme_file <- function() { list( color = "blue", transform = function(x) make_link(x, type = "file"), fmt = quote_weird_name ) } format_r_code <- function(dark) { function(x) { x <- ansi_strip(x) lines <- unlist(strsplit(x, "\n", fixed = TRUE)) code_highlight(lines) } } format_code <- function(dark) { function(x) { unlist(strsplit(x, "\n", fixed = TRUE)) } } theme_create <- function(theme) { mtheme <- theme mtheme[] <- lapply(mtheme, create_formatter) selectors <- names(theme) res <- data.frame( stringsAsFactors = FALSE, selector = as.character(selectors), parsed = I(lapply(selectors, parse_selector) %||% list()), style = I(mtheme %||% list()), cnt = rep(NA_character_, length(selectors)) ) rownames(res) <- NULL res } create_formatter <- function(x) { is_bold <- identical(x[["font-weight"]], "bold") is_italic <- identical(x[["font-style"]], "italic") is_underline <- identical(x[["text-decoration"]], "underline") is_color <- "color" %in% names(x) is_bg_color <- "background-color" %in% names(x) if (!is_bold && !is_italic && !is_underline && !is_color && !is_bg_color) return(x) if (is_color && is.null(x[["color"]])) { x[["color"]] <- "none" } if (is_bg_color && is.null(x[["background-color"]])) { x[["background-color"]] <- "none" } fmt <- c( if (is_bold) list(style_bold), if (is_italic) list(style_italic), if (is_underline) list(style_underline), if (is_color) make_ansi_style(x[["color"]]), if (is_bg_color) make_ansi_style(x[["background-color"]], bg = TRUE) ) new_fmt <- do.call(combine_ansi_styles, fmt) if (is.null(x[["fmt"]])) { x[["fmt"]] <- new_fmt } else { orig_fmt <- x[["fmt"]] x[["fmt"]] <- function(x) orig_fmt(new_fmt(x)) } x } merge_embedded_styles <- function(old, new) { # before and after is not inherited, fmt is not inherited, either # side margins are additive, class mappings are merged # rest is updated, counter is reset, prefix and postfix are merged old$before <- old$after <- old$fmt <- NULL old$transform <- NULL # these will be applied on the container, so we don't need them inside old$color <- old$`background-color` <- NULL top <- new$`margin-top` %||% 0L bottom <- new$`margin-bottom` %||% 0L left <- (old$`margin-left` %||% 0L) + (new$`margin-left` %||% 0L) right <- (old$`margin-right` %||% 0L) + (new$`margin-right` %||% 0L) prefix <- paste0(old$prefix, new$prefix) postfix <- paste0(new$postfix, old$postfix) map <- utils::modifyList(old$`class-map` %||% list(), new$`class-map` %||% list()) start <- new$start %||% 1L mrg <- utils::modifyList(old, new) mrg[c("margin-top", "margin-bottom", "margin-left", "margin-right", "start", "class-map", "prefix", "postfix")] <- list(top, bottom, left, right, start, map, prefix, postfix) ## Formatter needs to be re-generated create_formatter(mrg) } #' Parse a CSS3-like selector #' #' This is the rather small subset of CSS3 that is supported: #' #' Selectors: #' #' * Type selectors, e.g. `input` selects all `` elements. #' * Class selectors, e.g. `.index` selects any element that has a class #' of "index". #' * ID selector. `#toc` will match the element that has the ID `"toc"`. #' #' Combinators: #' #' * Descendant combinator, i.e. the space, that combinator selects nodes #' that are descendants of the first element. E.g. `div span` will match #' all `` elements that are inside a `
` element. #' #' @param x CSS3-like selector string. #' #' @keywords internal parse_selector <- function(x) { lapply(strsplit(x, " ", fixed = TRUE)[[1]], parse_selector_node) } parse_selector_node <- function(x) { parse_ids <- function(y) { r <- strsplit(y, "#", fixed = TRUE)[[1]] if (length(r) > 1) r[-1] <- paste0("#", r[-1]) r } parts <- strsplit(x, ".", fixed = TRUE)[[1]] if (length(parts) > 1) parts[-1] <- paste0(".", parts[-1]) parts <- unlist(lapply(parts, parse_ids)) parts <- parts[parts != ""] m_cls <- grepl("^\\.", parts) m_ids <- grepl("^#", parts) list(tag = as.character(unique(parts[!m_cls & !m_ids])), class = str_tail(unique(parts[m_cls])), id = str_tail(unique(parts[m_ids]))) } #' Match a selector node to a container #' #' @param node Selector node, as parsed by `parse_selector_node()`. #' @param cnt Container node, has elements `tag`, `id`, `class`. #' #' The selector node matches the container, if all these hold: #' #' * The id of the selector is missing or unique. #' * The tag of the selector is missing or unique. #' * The id of the container is missing or unique. #' * The tag of the container is unique. #' * If the selector specifies an id, it matches the id of the container. #' * If the selector specifies a tag, it matches the tag of the container. #' * If the selector specifies class names, the container has all these #' classes. #' #' @keywords internal match_selector_node <- function(node, cnt) { if (length(node$id) > 1 || length(cnt$id) > 1) return(FALSE) if (length(node$tag) > 1 || length(cnt$tag) > 1) return(FALSE) all(node$id %in% cnt$id) && all(node$tag %in% cnt$tag) && all(node$class %in% cnt$class) } #' Match a selector to a container stack #' #' @param sels A list of selector nodes. #' @param cnts A list of container nodes. #' #' The last selector in the list must match the last container, so we #' do the matching from the back. This is because we use this function #' to calculate the style of newly encountered containers. #' #' @keywords internal match_selector <- function(sels, cnts) { sptr <- length(sels) cptr <- length(cnts) # Last selector must match the last container if (sptr == 0 || sptr > cptr) return(FALSE) match <- match_selector_node(sels[[sptr]], cnts[[cptr]]) if (!match) return (FALSE) # Plus the rest should match somehow sptr <- sptr - 1L cptr <- cptr - 1L while (sptr != 0L && sptr <= cptr) { match <- match_selector_node(sels[[sptr]], cnts[[cptr]]) if (match) { sptr <- sptr - 1L cptr <- cptr - 1L } else { cptr <- cptr - 1L } } sptr == 0 } cli/R/rules.R0000644000176200001440000001444614557444176012531 0ustar liggesusers make_line <- function(x, char = symbol$line, col = NULL) { ## Easiest to handle this specially if (x <= 0) return("") cw <- ansi_nchar(char, "width") ## We handle the simple case differently, to make it faster if (cw == 1) { line <- paste(rep(char, x), collapse = "") } else { line <- ansi_substr(paste(rep(char, ceiling(x / cw)), collapse = ""), 1, x) } unclass(apply_style(line, col)) } #' Make a rule with one or two text labels #' #' @description #' The rule can include either a centered text label, or labels on the #' left and right side. #' #' To color the labels, use the functions `col_*`, `bg_*` and `style_*` #' functions, see [ANSI styles][ansi-styles], and the examples below. #' To color the line, either these functions directly, or the `line_col` #' option. #' #' #' @details #' ## Simple rule #' #' ```{asciicast rule-simple} #' rule() #' ``` #' #' ## Line styles #' Some strings for the `line` argument are interpreted specially: #' #' * `"single"`: (same as `1`), a single line, #' * `"double"`: (same as `2`), a double line, #' * `"bar1"`, `"bar2"`, `"bar3"`, etc., `"bar8"` uses varying height bars. #' #' ### Double rule #' #' ```{asciicast rule-double} #' rule(line = 2) #' ``` #' #' ### Bars #' #' ```{asciicast rule-bars} #' rule(line = "bar2") #' rule(line = "bar5") #' ``` #' #' ### Custom lines #' #' ```{asciicast rule-custom-line} #' rule(center = "TITLE", line = "~") #' ``` #' #' ```{asciicast rule-custom-line-2} #' rule(center = "TITLE", line = col_blue("~-")) #' ``` #' #' ```{asciicast rule-custom-line-3} #' rule(center = bg_red(" ", symbol$star, "TITLE", #' symbol$star, " "), #' line = "\u2582", #' line_col = "orange") #' ``` #' #' ## Left label #' #' ```{asciicast rule-left-label} #' rule(left = "Results") #' ``` #' #' ## Centered label #' #' ```{asciicast rule-center-label} #' rule(center = " * RESULTS * ") #' ``` #' #' ## Colored labels #' #' ```{asciicast rule-colored-label} #' rule(center = col_red(" * RESULTS * ")) #' ``` #' #' ## Colored line #' #' ```{asciicast rule-colored-line} #' rule(center = col_red(" * RESULTS * "), line_col = "red") #' ``` #' #' @param left Label to show on the left. It interferes with the `center` #' label, only at most one of them can be present. #' @param center Label to show at the center. It interferes with the #' `left` and `right` labels. #' @param right Label to show on the right. It interferes with the `center` #' label, only at most one of them can be present. #' @param line The character or string that is used to draw the line. #' It can also `1` or `2`, to request a single line (Unicode, if #' available), or a double line. Some strings are interpreted specially, #' see *Line styles* below. #' @param col Color of text, and default line color. Either an ANSI style #' function (see [ANSI styles][ansi-styles]), or a color name that is #' passed to [make_ansi_style()]. #' @param line_col,background_col Either a color name (used in #' [make_ansi_style()]), or a style function (see #' [ANSI styles][ansi-styles]), to color the line and background. #' @param width Width of the rule. Defaults to the `width` option, see #' [base::options()]. #' @return Character scalar, the rule. #' #' @export rule <- function(left = "", center = "", right = "", line = 1, col = NULL, line_col = col, background_col = NULL, width = console_width()) { try_silently(left <- as.character(left)) try_silently(center <- as.character(center)) try_silently(right <- as.character(right)) stopifnot( is_string(left), is_string(center), is_string(right), is_string(line) || line == 1 || line == 2, is_col(col), is_col(line_col), is_count(width) ) left <- apply_style(left, col) center <- apply_style(center, col) right <- apply_style(right, col) options <- as.list(environment()) options$line <- get_line_char(options$line) res <- if (ansi_nchar(center)) { if (ansi_nchar(left) || ansi_nchar(right)) { stop(sQuote("center"), " cannot be specified with ", sQuote("left"), " or ", sQuote("right")) } rule_center(options) } else if (ansi_nchar(left) && ansi_nchar(right)) { rule_left_right(options) } else if (ansi_nchar(left)) { rule_left(options) } else if (ansi_nchar(right)) { rule_right(options) } else { rule_line(options) } res <- ansi_substr(res, 1, width) res <- apply_style(res, background_col, bg = TRUE) class(res) <- unique(c("cli_rule", "rule", class(res), "character")) res } get_line_char <- function(line) { if (identical(line, 1) || identical(line, 1L) || identical(line, "single")) { symbol$line } else if (identical(line, 2) || identical(line, 2L) || identical(line, "double")) { symbol$double_line } else if (length(line) == 1 && line %in% paste0("bar", 1:8)) { bars <- structure( paste0("lower_block_", 1:8), names = paste0("bar", 1:8) ) symbol[[ bars[[line]] ]] } else { paste(as.character(line), collapse = "") } } rule_line <- function(o) { make_line(o$width, o$line, o$line_col) } rule_center <- function(o) { o$center <- ansi_substring(o$center, 1, o$width - 4) o$center <- paste0(" ", o$center, " ") ncc <- ansi_nchar(o$center, "width") ndashes <- o$width - ncc paste0( make_line(ceiling(ndashes / 2), o$line, o$line_col), o$center, make_line(floor(ndashes / 2), o$line, o$line_col) ) } rule_left <- function(o) { ncl <- ansi_nchar(o$left, "width") paste0( make_line(2, get_line_char(o$line), o$line_col), " ", o$left, " ", make_line(o$width - ncl - 4, o$line, o$line_col) ) } rule_right <- function(o) { ncr <- ansi_nchar(o$right, "width") paste0( make_line(o$width - ncr - 4, o$line, o$line_col), " ", o$right, " ", make_line(2, o$line, o$line_col) ) } rule_left_right <- function(o) { ncl <- ansi_nchar(o$left, "width") ncr <- ansi_nchar(o$right, "width") ## -- (ncl) -- (ncr) -- if (ncl + ncr + 10 > o$width) return(rule_left(o)) paste0( make_line(2, o$line, o$line_col), " ", o$left, " ", make_line(o$width - ncl - ncr - 8, o$line, o$line_col), " ", o$right, " ", make_line(2, o$line, o$line_col) ) } methods::setOldClass(c("cli_rule", "character")) #' @export print.cli_rule <- function(x, ..., sep = "\n") { cat(x, ..., sep = sep) invisible(x) } cli/R/tree.R0000644000176200001440000001465414557444176012337 0ustar liggesusers #' Draw a tree #' #' Draw a tree using box drawing characters. Unicode characters are #' used if available. (Set the `cli.unicode` option if auto-detection #' fails.) #' #' A node might appear multiple times in the tree, or might not appear #' at all. #' #' @details #' #' ```{asciicast, tree} #' data <- data.frame( #' stringsAsFactors = FALSE, #' package = c("processx", "backports", "assertthat", "Matrix", #' "magrittr", "rprojroot", "clisymbols", "prettyunits", "withr", #' "desc", "igraph", "R6", "crayon", "debugme", "digest", "irlba", #' "rcmdcheck", "callr", "pkgconfig", "lattice"), #' dependencies = I(list( #' c("assertthat", "crayon", "debugme", "R6"), character(0), #' character(0), "lattice", character(0), "backports", character(0), #' c("magrittr", "assertthat"), character(0), #' c("assertthat", "R6", "crayon", "rprojroot"), #' c("irlba", "magrittr", "Matrix", "pkgconfig"), character(0), #' character(0), "crayon", character(0), "Matrix", #' c("callr", "clisymbols", "crayon", "desc", "digest", "prettyunits", #' "R6", "rprojroot", "withr"), #' c("processx", "R6"), character(0), character(0) #' )) #' ) #' tree(data) #' ``` #' #' ```{asciicast, tree-root} #' tree(data, root = "rcmdcheck") #' ``` #' #' ## Colored nodes #' #' ```{asciicast tree-colored} #' data$label <- paste(data$package, #' style_dim(paste0("(", c("2.0.0.1", "1.1.1", "0.2.0", "1.2-11", #' "1.5", "1.2", "1.2.0", "1.0.2", "2.0.0", "1.1.1.9000", "1.1.2", #' "2.2.2", "1.3.4", "1.0.2", "0.6.12", "2.2.1", "1.2.1.9002", #' "1.0.0.9000", "2.0.1", "0.20-35"), ")")) #' ) #' roots <- ! data$package %in% unlist(data$dependencies) #' data$label[roots] <- col_cyan(style_italic(data$label[roots])) #' tree(data, root = "rcmdcheck") #' ``` #' #' ## Trimming #' #' ```{asciicast tree-trimming} #' pkgdeps <- list( #' "dplyr@0.8.3" = c("assertthat@0.2.1", "glue@1.3.1", "magrittr@1.5", #' "R6@2.4.0", "Rcpp@1.0.2", "rlang@0.4.0", "tibble@2.1.3", #' "tidyselect@0.2.5"), #' "assertthat@0.2.1" = character(), #' "glue@1.3.1" = character(), #' "magrittr@1.5" = character(), #' "pkgconfig@2.0.3" = character(), #' "R6@2.4.0" = character(), #' "Rcpp@1.0.2" = character(), #' "rlang@0.4.0" = character(), #' "tibble@2.1.3" = c("cli@1.1.0", "crayon@1.3.4", "fansi@0.4.0", #' "pillar@1.4.2", "pkgconfig@2.0.3", "rlang@0.4.0"), #' "cli@1.1.0" = c("assertthat@0.2.1", "crayon@1.3.4"), #' "crayon@1.3.4" = character(), #' "fansi@0.4.0" = character(), #' "pillar@1.4.2" = c("cli@1.1.0", "crayon@1.3.4", "fansi@0.4.0", #' "rlang@0.4.0", "utf8@1.1.4", "vctrs@0.2.0"), #' "utf8@1.1.4" = character(), #' "vctrs@0.2.0" = c("backports@1.1.5", "ellipsis@0.3.0", #' "digest@0.6.21", "glue@1.3.1", "rlang@0.4.0", "zeallot@0.1.0"), #' "backports@1.1.5" = character(), #' "ellipsis@0.3.0" = c("rlang@0.4.0"), #' "digest@0.6.21" = character(), #' "glue@1.3.1" = character(), #' "zeallot@0.1.0" = character(), #' "tidyselect@0.2.5" = c("glue@1.3.1", "purrr@1.3.1", "rlang@0.4.0", #' "Rcpp@1.0.2"), #' "purrr@0.3.3" = c("magrittr@1.5", "rlang@0.4.0") #' ) #' #' pkgs <- data.frame( #' stringsAsFactors = FALSE, #' name = names(pkgdeps), #' deps = I(unname(pkgdeps)) #' ) #' #' tree(pkgs, trim = TRUE) #' ``` #' #' ```{asciicast tree-trim-mark} #' # Mark the trimmed nodes #' pkgs$label <- pkgs$name #' pkgs$trimmed <- paste(pkgs$name, " (trimmed)") #' tree(pkgs, trim = TRUE) #' ``` #' #' @param data Data frame that contains the tree structure. #' The first column is an id, and the second column is a list column, #' that contains the ids of the child nodes. The optional third column #' may contain the text to print to annotate the node. #' @param root The name of the root node. #' @param style Optional box style list. #' @param width Maximum width of the output. Defaults to the `width` #' option, see [base::options()]. #' @param trim Whether to avoid traversing the same nodes multiple times. #' If `TRUE` and `data` has a `trimmed` column, then that is used for #' printing repeated nodes. #' @return Character vector, the lines of the tree drawing. #' #' @export tree <- function(data, root = data[[1]][[1]], style = NULL, width = console_width(), trim = FALSE) { stopifnot( is.data.frame(data), ncol(data) >= 2, is_string(root), is.null(style) || (is_tree_style(style)), is_count(width) ) style <- style %||% box_chars() labels <- if (ncol(data) >= 3) data[[3]] else data[[1]] trimlabs <- data[["trimmed"]] %||% labels seen <- character() res <- character() pt <- function(root, n = integer(), mx = integer(), used = character()) { num_root <- match(root, data[[1]]) if (is.na(num_root)) return() level <- length(n) - 1 prefix <- vcapply(seq_along(n), function(i) { if (n[i] < mx[i]) { if (i == length(n)) { paste0(style$j, style$h) } else { paste0(style$v, " ") } } else if (n[i] == mx[i] && i == length(n)) { paste0(style$l, style$h) } else { " " } }) root_seen <- root %in% seen root_lab <- if (trim && root_seen) trimlabs[[num_root]] else labels[[num_root]] res <<- c(res, paste0(paste(prefix, collapse = ""), root_lab)) # Detect infinite loops if (!trim && root %in% used) { warning(call. = FALSE, "Endless loop found in tree: ", paste0(c(used, root), collapse = " -> ")) } else if (! trim || ! root_seen) { seen <<- c(seen, root) children <- data[[2]][[num_root]] for (d in seq_along(children)) { pt(children[[d]], c(n, d), c(mx, length(children)), c(used, root)) } } } if (nrow(data)) pt(root) res <- ansi_substr(res, 1, width) class(res) <- unique(c("cli_tree", "tree", class(res), "character")) res } box_chars <- function() { if (is_utf8_output()) { list( "h" = "\u2500", # horizontal "v" = "\u2502", # vertical "l" = "\u2514", # leaf "j" = "\u251C" # junction ) } else { list( "h" = "-", # horizontal "v" = "|", # vertical "l" = "\\", # leaf "j" = "+" # junction ) } } methods::setOldClass(c("cli_tree", "character")) #' @export print.cli_tree <- function(x, ..., sep = "\n") { cat(x, ..., sep = sep) invisible(x) } cli/R/aab-rstudio-detect.R0000644000176200001440000002034614752735214015044 0ustar liggesusers rstudio <- local({ standalone_env <- environment() parent.env(standalone_env) <- baseenv() # -- Collect data ------------------------------------------------------ data <- NULL get_data <- function() { envs <- c( "R_BROWSER", "R_PDFVIEWER", "RSTUDIO", "RSTUDIO_TERM", "RSTUDIO_CLI_HYPERLINKS", "RSTUDIO_CONSOLE_COLOR", "RSTUDIOAPI_IPC_REQUESTS_FILE", "XPC_SERVICE_NAME", "ASCIICAST") d <- list( pid = Sys.getpid(), envs = Sys.getenv(envs), api = tryCatch( asNamespace("rstudioapi")$isAvailable(), error = function(err) FALSE ), tty = isatty(stdin()), gui = .Platform$GUI, args = commandArgs(), search = search() ) if (d$api) { ns <- asNamespace("rstudioapi") d$ver <- if (d$api) ns$getVersion() new_api <- package_version(getNamespaceVersion(ns)) >= "0.17.0" d$desktop <- if (new_api) ns$getMode() else ns$versionInfo()$mode } d } # -- Auto-detect environment ------------------------------------------- is_rstudio <- function() { Sys.getenv("RSTUDIO") == "1" } detect <- function(clear_cache = FALSE) { # Check this up front, in case we are in a testthat 3e test block. # We cannot cache this, because we might be in RStudio in reality. if (!is_rstudio()) { return(get_caps(type = "not_rstudio")) } # Cached? if (clear_cache) data <<- NULL if (!is.null(data)) return(get_caps(data)) if ((rspid <- Sys.getenv("RSTUDIO_SESSION_PID")) != "" && any(c("ps", "cli") %in% loadedNamespaces())) { detect_new(rspid, clear_cache) } else { detect_old(clear_cache) } } get_parentpid <- function() { if ("cli" %in% loadedNamespaces()) { asNamespace("cli")$get_ppid() } else { ps::ps_ppid() } } detect_new <- function(rspid, clear_cache) { mypid <- Sys.getpid() new <- get_data() if (mypid == rspid) { return(get_caps(new, type = "rstudio_console")) } # need explicit namespace reference because we mess up the environment parentpid <- get_parentpid() pane <- Sys.getenv("RSTUDIO_CHILD_PROCESS_PANE") # this should not happen, but be defensive and fall back if (pane == "") return(detect_old(clear_cache)) # direct subprocess new$type <- if (rspid == parentpid) { if (pane == "job") { "rstudio_job" } else if (pane == "build") { "rstudio_build_pane" } else if (pane == "render") { "rstudio_render_pane" } else if (pane == "terminal" && new$tty && new$envs["ASCIICAST"] != "true") { # not possible, because there is a shell in between, just in case "rstudio_terminal" } else { # don't know what kind of direct subprocess "rstudio_subprocess" } } else if (pane == "terminal" && new$tty && new$envs[["ASCIICAST"]] != "true") { # not a direct subproces, so check other criteria as well "rstudio_terminal" } else { # don't know what kind of subprocess "rstudio_subprocess" } get_caps(new) } detect_old <- function(clear_cache = FALSE) { # Cache unless told otherwise cache <- TRUE new <- get_data() new$type <- if (new$envs[["RSTUDIO"]] != "1") { # 1. Not RStudio at all "not_rstudio" } else if (new$gui == "RStudio" && new$api) { # 2. RStudio console, properly initialized "rstudio_console" } else if (! new$api && basename(new$args[1]) == "RStudio") { # 3. RStudio console, initializing cache <- FALSE "rstudio_console_starting" } else if (new$gui == "Rgui") { # Still not RStudio, but Rgui that was started from RStudio "not_rstudio" } else if (new$tty && new$envs[["ASCIICAST"]] != "true") { # 4. R in the RStudio terminal # This could also be a subprocess of the console or build pane # with a pseudo-terminal. There isn't really a way to rule that # out, without inspecting some process data with ps::ps_*(). # At least we rule out asciicast "rstudio_terminal" } else if (! new$tty && new$envs[["RSTUDIO_TERM"]] == "" && new$envs[["R_BROWSER"]] == "false" && new$envs[["R_PDFVIEWER"]] == "false" && is_build_pane_command(new$args)) { # 5. R in the RStudio build pane # https://github.com/rstudio/rstudio/blob/main/src/cpp/session/ # modules/build/SessionBuild.cpp#L231-L240 "rstudio_build_pane" } else if (new$envs[["RSTUDIOAPI_IPC_REQUESTS_FILE"]] != "" && grepl("rstudio", new$envs[["XPC_SERVICE_NAME"]], fixed = TRUE)) { # RStudio job, XPC_SERVICE_NAME=0 in the subprocess of a job # process. Hopefully this is reliable. "rstudio_job" } else if (new$envs[["RSTUDIOAPI_IPC_REQUESTS_FILE"]] != "" && any(grepl("SourceWithProgress.R", new$args))) { # Or we can check SourceWithProgress.R in the command line, see # https://github.com/r-lib/cli/issues/367 "rstudio_job" } else { # Otherwise it is a subprocess of the console, terminal or # build pane, and it is hard to say which, so we do not try. "rstudio_subprocess" } installing <- Sys.getenv("R_PACKAGE_DIR", "") if (cache && installing == "") data <<- new get_caps(new) } is_build_pane_command <- function(args) { cmd <- gsub("[\"']", "", args[[length(args)]], useBytes = TRUE) calls <- c( "devtools::build", "devtools::test", "devtools::check", "testthat::test_file" ) any(vapply(calls, grepl, logical(1), cmd, useBytes = TRUE)) } # -- Capabilities ------------------------------------------------------ caps <- list() caps$not_rstudio <- function(data) { list( type = "not_rstudio", dynamic_tty = FALSE, ansi_tty = FALSE, ansi_color = FALSE, num_colors = 1L, hyperlink = FALSE, has_canonical_mode = FALSE ) } caps$rstudio_console <- function(data) { list( type = "rstudio_console", dynamic_tty = TRUE, ansi_tty = FALSE, ansi_color = data$envs[["RSTUDIO_CONSOLE_COLOR"]] != "", num_colors = as.integer(data$envs[["RSTUDIO_CONSOLE_COLOR"]]), hyperlink = data$envs[["RSTUDIO_CLI_HYPERLINKS"]] != "", has_canonical_mode = FALSE ) } caps$rstudio_console_starting <- function(data) { res <- caps$rstudio_console(data) res$type <- "rstudio_console_starting" res } caps$rstudio_terminal <- function(data) { list( type = "rstudio_terminal", dynamic_tty = TRUE, ansi_tty = FALSE, ansi_color = FALSE, num_colors = 1L, hyperlink = FALSE, has_canonical_mode = FALSE ) } caps$rstudio_build_pane <- function(data) { list( type = "rstudio_build_pane", dynamic_tty = TRUE, ansi_tty = FALSE, ansi_color = data$envs[["RSTUDIO_CONSOLE_COLOR"]] != "", num_colors = as.integer(data$envs[["RSTUDIO_CONSOLE_COLOR"]]), hyperlink = data$envs[["RSTUDIO_CLI_HYPERLINKS"]] != "", has_canonical_mode = FALSE ) } caps$rstudio_job <- function(data) { list( type = "rstudio_job", dynamic_tty = FALSE, ansi_tty = FALSE, ansi_color = data$envs[["RSTUDIO_CONSOLE_COLOR"]] != "", num_colors = as.integer(data$envs[["RSTUDIO_CONSOLE_COLOR"]]), hyperlink = data$envs[["RSTUDIO_CLI_HYPERLINKS"]] != "", has_canonical_mode = FALSE ) } caps$rstudio_render_pane <- function(data) { list( type = "rstudio_render_pane", dynamic_tty = TRUE, ansi_tty = FALSE, ansi_color = FALSE, num_colors = 1L, hyperlink = FALSE, has_canonical_mode = FALSE ) } caps$rstudio_subprocess <- function(data) { list( type = "rstudio_subprocess", dynamic_tty = FALSE, ansi_tty = FALSE, ansi_color = FALSE, num_colors = 1L, hyperlink = FALSE, has_canonical_mode = FALSE ) } get_caps <- function(data, type = data$type) caps[[type]](data) structure( list( .internal = standalone_env, is_rstudio = is_rstudio, detect = detect ), class = c("standalone_rstudio_detect", "standalone") ) }) cli/R/enc-utils.R0000644000176200001440000000101314557444176013264 0ustar liggesusers # keep encoding, even if useBytes = TRUE sub_ <- function(pattern, replacement, x, ...) { enc <- Encoding(x) ret <- sub(pattern, replacement, x, ...) if (length(ret)) Encoding(ret) <- enc ret } gsub_ <- function(pattern, replacement, x, ...) { enc <- Encoding(x) ret <- gsub(pattern, replacement, x, ...) if (length(ret)) Encoding(ret) <- enc ret } strsplit_ <- function(x, ...) { enc <- Encoding(x) ret <- strsplit(x, ...) for (i in seq_along(ret)) { Encoding(ret[[i]]) <- enc[i] } ret } cli/R/utils.R0000644000176200001440000000101614557444176012524 0ustar liggesusers is_yes <- function(x) { tolower(x) %in% c("true", "yes", "y", "t", "1") } format_iso_8601 <- function(p) { format(p, "%Y-%m-%dT%H:%M:%S+00:00") } has_packages <- function(pkgs) { all(vapply(pkgs, requireNamespace, logical(1), quietly = TRUE)) } cli_escape <- function(x) { x <- gsub("{", "{{", x, fixed = TRUE) x <- gsub("}", "}}", x, fixed = TRUE) x } # missing from older R isFALSE <- function (x) { is.logical(x) && length(x) == 1L && !is.na(x) && !x } get_ppid <- function() { .Call(clic_getppid) } cli/R/aaa-utils.R0000644000176200001440000000725014752735214013243 0ustar liggesusers `%||%` <- function(l, r) if (is.null(l)) r else l new_class <- function(class_name, ...) { structure(as.environment(list(...)), class = class_name) } make_space <- function(len) { strrep(" ", len) } strrep <- function(x, times) { x <- as.character(x) if (length(x) == 0L) return(x) r <- .mapply( function(x, times) { if (is.na(x) || is.na(times)) return(NA_character_) if (times <= 0L) return("") paste0(replicate(times, x), collapse = "") }, list(x = x, times = times), MoreArgs = list() ) res <- unlist(r, use.names = FALSE) Encoding(res) <- Encoding(x) res } is_latex_output <- function() { if (!("knitr" %in% loadedNamespaces())) return(FALSE) get("is_latex_output", asNamespace("knitr"))() } is_windows <- function() { .Platform$OS.type == "windows" } apply_style <- function(text, style, bg = FALSE) { if (identical(text, "")) return(text) if (is.function(style)) { style(text) } else if (is.character(style)) { make_ansi_style(style, bg = bg)(text) } else if (is.null(style)) { text } else { throw(cli_error( "{.arg style} must be a color name or an ANSI style function", "i" = "{.arg style} is {.typeof {style}}" )) } } vcapply <- function(X, FUN, ..., USE.NAMES = TRUE) { vapply(X, FUN, FUN.VALUE = character(1), ..., USE.NAMES = USE.NAMES) } viapply <- function(X, FUN, ..., USE.NAMES = TRUE) { vapply(X, FUN, FUN.VALUE = integer(1), ..., USE.NAMES = USE.NAMES) } vlapply <- function(X, FUN, ..., USE.NAMES = TRUE) { vapply(X, FUN, FUN.VALUE = logical(1), ..., USE.NAMES = USE.NAMES) } rpad <- function(x, width = NULL) { if (!length(x)) return(x) w <- nchar(x, type = "width") if (is.null(width)) width <- max(w) paste0(x, strrep(" ", pmax(width - w, 0))) } lpad <- function(x, width = NULL) { if (!length(x)) return(x) w <- nchar(x, type = "width") if (is.null(width)) width <- max(w) paste0(strrep(" ", pmax(width - w, 0)), x) } tail_na <- function(x, n = 1) { utils::tail(c(rep(NA, n), x), n) } dedent <- function(x, n = 2) { first_n_char <- strsplit(ansi_substr(x, 1, n), "", fixed = TRUE)[[1]] n_space <- cumsum(first_n_char == " ") d_n_space <- diff(c(0, n_space)) first_not_space <- utils::head(c(which(d_n_space == 0), n + 1), 1) ansi_substr(x, first_not_space, nchar(x)) } new_uuid <- (function() { cnt <- 0 function() { cnt <<- cnt + 1 paste0("cli-", clienv$pid, "-", cnt) } })() na.omit <- function(x) { if (is.atomic(x)) x[!is.na(x)] else x } last <- function(x) { utils::tail(x, 1)[[1]] } str_tail <- function(x) { substr(x, 2, nchar(x)) } push <- function(l, el, name = NULL) { c(l, structure(list(el), names = name)) } try_silently <- function(expr) { suppressWarnings(tryCatch(expr, error = function(x) x)) } random_id <- local({ i <- 0 function() { i <<- i + 1 paste0("FCkNXbE-", i) } }) random_marker <- "ImzV8dciA4cn4POI" str_trim <- function(x) { sub("^\\s+", "", sub("\\s+$", "", x)) } last_character <- function(x) { substr(x, nchar(x), nchar(x)) } first_character <- function(x) { substr(x, 1, 1) } second_character <- function(x) { substr(x, 2, 2) } is_alnum <- function(x, ok = "") { grepl(paste0("^[[:alnum:]/_.", ok, "]*$"), x) } os_type <- function() { .Platform$OS.type } leading_space <- function(x) { sub("^([\\s\u00a0]*).*$", "\\1", x, perl = TRUE) } trailing_space <- function(x) { sub("^.*[^\\s\u00a0]([\\s\u00a0]*)$", "\\1", x, perl = TRUE) } get_rstudio_theme <- function() { suppressWarnings(rstudioapi::getThemeInfo()) } # ansi_strtrim might not support NAs abbrev <- function(x, len = 10) { # this is better than strtrim() because it adds ... ansi_strtrim(x, len) } cli/R/assertions.R0000644000176200001440000000142314752735214013551 0ustar liggesusers is_string <- function(x) { is.character(x) && length(x) == 1 && !is.na(x) } is_flag <- function(x) { is.logical(x) && length(x) == 1 && !is.na(x) } is_border_style <- function(x) { is_string(x) && x %in% rownames(box_styles()) } is_padding_or_margin <- function(x) { is.numeric(x) && length(x) %in% c(1, 4) && !anyNA(x) && all(as.integer(x) == x) } is_col <- function(x) { is.null(x) || is_string(x) || is.function(x) } is_count <- function(x) { is.numeric(x) && length(x) == 1 && !is.na(x) && as.integer(x) == x && x >= 0 } is_tree_style <- function(x) { is.list(x) && length(x) == 4 && !is.null(names(x)) && all(sort(names(x)) == sort(c("h", "v", "l", "j"))) && all(sapply(x, is_string)) } is_named <- function(x) { !is.null(names(x)) } cli/R/num-ansi-colors.R0000644000176200001440000002556214752735214014417 0ustar liggesusers #' Detect the number of ANSI colors to use #' #' @description #' Certain Unix and Windows terminals, and also certain R GUIs, e.g. #' RStudio, support styling terminal output using special control #' sequences (ANSI sequences). #' #' `num_ansi_colors()` detects if the current R session supports ANSI #' sequences, and if it does how many colors are supported. #' #' @param stream The stream that will be used for output, an R connection #' object. It can also be a string, one of `"auto"`, `"message"`, #' `"stdout"`, `"stderr"`. `"auto"` will select `stdout()` if the session is #' interactive and there are no sinks, otherwise it will select `stderr()`. #' @return Integer, the number of ANSI colors the current R session #' supports for `stream`. #' #' @family ANSI styling #' @export #' @examples #' num_ansi_colors() #' #' @details #' The detection mechanism is quite involved and it is designed to work #' out of the box on most systems. If it does not work on your system, #' please report a bug. Setting options and environment variables to turn #' on ANSI support is error prone, because they are inherited in other #' environments, e.g. knitr, that might not have ANSI support. #' #' If you want to _turn off_ ANSI colors, set the `NO_COLOR` environment #' variable to a non-empty value. #' #' The exact detection mechanism is as follows: num_ansi_colors <- function(stream = "auto") { #' 1. If the `cli.num_colors` options is set, that is returned. opt <- getOption("cli.num_colors", NULL) if (!is.null(opt)) return(as.integer(opt)) #' 1. If the `R_CLI_NUM_COLORS` environment variable is set to a #' non-empty value, then it is used. if ((env <- Sys.getenv("R_CLI_NUM_COLORS", "")) != "") { return(as.integer(env)) } #' 1. If the `crayon.enabled` option is set to `FALSE`, 1L is returned. #' (This is for compatibility with code that uses the crayon package.) #' 1. If the `crayon.enabled` option is set to `TRUE` and the #' `crayon.colors` option is not set, then the value of the #' `cli.default_num_colors` option, or if it is unset, then 8L is #' returned. #' 1. If the `crayon.enabled` option is set to `TRUE` and the #' `crayon.colors` option is also set, then the latter is returned. #' (This is for compatibility with code that uses the crayon package.) cray_opt_has <- getOption("crayon.enabled", NULL) cray_opt_num <- getOption("crayon.colors", NULL) if (!is.null(cray_opt_has) && !isTRUE(cray_opt_has)) return(1L) if (isTRUE(cray_opt_has) && !is.null(cray_opt_num)) { return(as.integer(cray_opt_num)) } if (isTRUE(cray_opt_has) && is.null(cray_opt_num)) { default <- get_default_number_of_colors() return(default %||% 8L) } #' 1. If the `NO_COLOR` environment variable is set, then 1L is returned. if (!is.na(Sys.getenv("NO_COLOR", NA_character_))) return(1L) #' 1. If we are in knitr, then 1L is returned, to turn off colors in #' `.Rmd` chunks. if (isTRUE(getOption("knitr.in.progress"))) return(1L) #' 1. If `stream` is `"auto"` (the default) and there is an active #' sink (either for `"output"` or `"message"`), then we return 1L. #' (In theory we would only need to check the stream that will be #' be actually used, but there is no easy way to tell that.) if (stream == "auto" && !no_sink()) return(1L) # Defer computation on streams to speed up common case # when environment variables are set orig_stream <- stream stream <- get_real_output(stream) is_stdout <- is_stderr <- is_std <- FALSE std <- "nope" if (identical(stream, stdout())) { is_stdout <- is_std <- TRUE std <- "stdout" } else if (identical(stream, stderr())) { is_stderr <- is_std <- TRUE std <- "stderr" } #' 1. If `stream` is not `"auto"`, but it is `stderr()` and there is an #' active sink for it, then 1L is returned. #' (If a sink is active for "output", then R changes the `stdout()` #' stream, so this check is not needed.) # If a sink is active for "message" (ie. stderr), then R does not update # the `stderr()` stream, so we need to catch this case. if (is_stderr && sink.number("message") != 2) return(1L) #' 1. If the `cli.default_num_colors` option is set, then we use that. dopt <- get_default_number_of_colors() if (!is.null(dopt)) return(as.integer(dopt)) #' 1. If R is running inside RGui on Windows, or R.app on macOS, then we #' return 1L. # RStudio sets GUI to RGui initially, so we'll handle that after RStudio. if (.Platform$GUI == "AQUA") return(1L) #' 1. If R is running inside RStudio, with color support, then the #' appropriate number of colors is returned, usually 256L. rstudio <- rstudio$detect() rstudio_colors <- c( "rstudio_console", "rstudio_console_starting", "rstudio_build_pane", "rstudio_job" ) if (is.na(rstudio$num_colors)) rstudio$num_colors <- 1L if (rstudio$type %in% rstudio_colors && is_std) { return(rstudio$num_colors) } # RGui? We need to do this after RStudio, because .Platform$GUI is # "Rgui" in RStudio when we are starting up if (.Platform$GUI == "Rgui") return(1L) #' 1. If R is running on Windows, inside an Emacs version that is recent #' enough to support ANSI colors, then the value of the #' `cli.default_num_colors` option, or if unset 8L is returned. #' (On Windows, Emacs has `isatty(stdout()) == FALSE`, so we need to #' check for this here before dealing with terminals.) # Windows Emacs? The top R process will have `--ess` in ESS, but the # subprocesses won't. (Without ESS subprocesses will also report 8L # colors, this is a problem, but we expect most people use ESS in Emacs.) if (os_type() == "windows" && "--ess" %in% commandArgs() && is_emacs_with_color()) { default <- get_default_number_of_colors() return(default %||% 8L) } #' 1. If `stream` is not the standard output or standard error in a #' terminal, then 1L is returned. if (!isatty(stream)) return(1L) if (!is_std) return(1L) #' 1. Otherwise we use and cache the result of the terminal color #' detection (see below). # Otherwise use/set the cache if (is.null(clienv$num_colors)) clienv$num_colors <- list() clienv$num_colors[[std]] <- clienv$num_colors[[std]] %||% detect_tty_colors() clienv$num_colors[[std]] } #' @rdname num_ansi_colors #' @details #' The terminal color detection algorithm: detect_tty_colors <- function() { default <- get_default_number_of_colors() #' 1. If the `COLORTERM` environment variable is set to `truecolor` or #' `24bit`, then we return 16 million colors. #' 1. If the `COLORTERM` environment variable is set to anything else, #' then we return the value of the `cli.num_default_colors` option, #' 8L if unset. ct <- Sys.getenv("COLORTERM", NA_character_) if (!is.na(ct)) { if (ct == "truecolor" || ct == "24bit") { return(truecolor) } else { return(default %||% 8L) } } #' 1. If R is running on Unix, inside an Emacs version that is recent #' enough to support ANSI colors, then the value of the #' `cli.default_num_colors` option is returned, or 8L if unset. if (os_type() == "unix" && is_emacs_with_color()) return(default %||% 8L) #' 1. If we are on Windows in an RStudio terminal, then apparently #' we only have eight colors, but the `cli.default_num_colors` option #' can be used to override this. win10 <- win10_build() if (os_type() == "windows" && win10 >= 10586 && rstudio_detect()$type == "rstudio_terminal") { # this is rather weird, but echo turns on color support :D system2("cmd", c("/c", "echo 1 >NUL")) return(default %||% 8L) } #' 1. If we are in a recent enough Windows 10 terminal, then there #' is either true color (from build 14931) or 256 color (from #' build 10586) support. You can also use the `cli.default_num_colors` #' option to override these. if (os_type() == "windows" && win10 >= 10586) { # this is rather weird, but echo turns on color support :D system2("cmd", c("/c", "echo 1 >NUL")) # https://devblogs.microsoft.com/commandline/24-bit-color-in-the-windows-console/ if (win10 >= 14931) { return(default %||% truecolor) } else { return(default %||% 256L) } } if (os_type() == "windows") { #' 1. If we are on Windows, under ConEmu or cmder, or ANSICON is loaded, #' then the value of `cli.default_num_colors`, or 8L if unset, is #' returned. if (Sys.getenv("ConEmuANSI") == "ON" || Sys.getenv("CMDER_ROOT") != "") { return(default %||% 8L) } if (Sys.getenv("ANSICON") != "") return(default %||% 8L) #' 1. Otherwise if we are on Windows, return 1L. return(1L) } #' 1. Otherwise we are on Unix and try to run `tput colors` to determine #' the number of colors. If this succeeds, we return its return value. cols <- suppressWarnings(try( silent = TRUE, as.numeric(system("tput colors 2>/dev/null", intern = TRUE))[1] )) if (inherits(cols, "try-error") || !length(cols) || is.na(cols)) { return(guess_tty_colors()) } if (cols %in% c(-1, 0, 1)) { return(1) } #' If the `TERM` environment variable is `xterm` and `tput` #' returned 8L, we return 256L, because xterm compatible terminals #' tend to support 256 colors #' () #' You can override this with the `cli.default_num_colors` option. if (cols == 8 && identical(Sys.getenv("TERM"), "xterm")) { cols <- default %||% 256 } #' 1. If `TERM` is set to `dumb`, we return 1L. #' 1. If `TERM` starts with `screen`, `xterm`, or `vt100`, we return 8L. #' 1. If `TERM` contains `color`, `ansi`, `cygwin` or `linux`, we return 8L. #' 1. Otherwise we return 1L. cols } get_default_number_of_colors <- function() { dft <- getOption("cli.default_num_colors") if (!is.null(dft)) { if (!is_count(dft)) { warning( "The `cli.default_num_colors` option must be an integer scalar" ) dft <- NULL } } dft } guess_tty_colors <- function() { term <- Sys.getenv("TERM") if (term == "dumb") return (1L) if (grepl( "^screen|^xterm|^vt100|color|ansi|cygwin|linux", term, ignore.case = TRUE, perl = TRUE )) { 8L } else { 1L } } is_emacs_with_color <- function() { (Sys.getenv("EMACS") != "" || Sys.getenv("INSIDE_EMACS") != "") && ! is.na(emacs_version()[1]) && emacs_version()[1] >= 23 } emacs_version <- function() { ver <- Sys.getenv("INSIDE_EMACS") if (ver == "") return(NA_integer_) ver <- gsub("'", "", ver, fixed = TRUE) ver <- strsplit(ver, ",", fixed = TRUE)[[1]] ver <- strsplit(ver, ".", fixed = TRUE)[[1]] suppressWarnings(as.numeric(ver)) } win10_build <- function() { os <- utils::sessionInfo()$running %||% "" if (!grepl("^Windows 10 ", os)) return(0L) mch <- re_match(os, "[(]build (?[0-9]+)[)]") mch <- suppressWarnings(as.integer(mch)) if (is.na(mch)) return(0L) mch } cli/R/spark.R0000644000176200001440000000560514602231456012476 0ustar liggesusers # from pillar #' Draw a sparkline bar graph with unicode block characters #' #' @description #' Rendered using [block elements](https://en.wikipedia.org/wiki/Block_Elements). #' In most common fixed width fonts these are rendered wider than regular #' characters which means they are not suitable if you need precise alignment. #' #' You might want to avoid sparklines on non-UTF-8 systems, because they #' do not look good. You can use [is_utf8_output()] to test for support #' for them. #' #' @details #' #' ```{asciicast spark-bar-1} #' x <- seq(0, 1, length = 6) #' spark_bar(x) #' ``` #' #' ```{asciicast spark-bar-2} #' x <- seq(0, 1, length = 6) #' spark_bar(sample(x)) #' ``` #' #' ```{asciicast spark-bar-3} #' spark_bar(seq(0, 1, length = 8)) #' ``` #' #' `NA`s are left out: #' #' ```{asciicast spark-bar-na} #' spark_bar(c(0, NA, 0.5, NA, 1)) #' ``` #' #' @param x A numeric vector between 0 and 1 #' @export #' @seealso [spark_line()] spark_bar <- function(x) { stopifnot(is.numeric(x)) chars <- spark_bar_chars(x) structure( paste0(chars, collapse = ""), class = c("cli_spark_bar", "cli_spark") ) } #' @export format.cli_spark <- function(x, ...) { unclass(x) } #' @export print.cli_spark <- function(x, ...) { cat(format(x, ...), sep = "\n") } spark_bar_chars <- function(x, bars = NULL) { if (is.null(bars)) { if (is_utf8_output()) { bars <- vapply(0x2581:0x2588, intToUtf8, character(1)) } else { bars <- c("_", ",", "*", "#") } } factor <- cut( x, breaks = seq(0, 1, length.out = length(bars) + 1), labels = bars, include.lowest = TRUE ) chars <- as.character(factor) chars[is.na(chars)] <- " " chars } #' Draw a sparkline line graph with Braille characters. #' #' You might want to avoid sparklines on non-UTF-8 systems, because they #' do not look good. You can use [is_utf8_output()] to test for support #' for them. #' #' @details #' #' ```{asciicast spark-line} #' x <- seq(0, 1, length = 10) #' spark_line(x) #' ``` #' #' @inheritParams spark_bar #' @export #' @seealso [spark_bar()] spark_line <- function(x) { stopifnot(is.numeric(x)) if (length(x) %% 2 == 1) { x <- c(x, NA) } if (is_utf8_output()) { y <- findInterval(x, seq(0, 1, length.out = 5), all.inside = TRUE) ind <- matrix(y, ncol = 2, byrow = TRUE) ind[, 2] <- ind[, 2] + 4 chars <- apply(ind, 1, braille) } else { ind <- matrix(x, ncol = 2, byrow = TRUE) bars <- c("_", ",", "-", "^") chars <- spark_bar_chars(apply(ind, 1, mean), bars) } structure( paste0(chars, collapse = ""), class = c("cli_spark_line", "cli_spark") ) } # https://en.wikipedia.org/wiki/Braille_Patterns braille <- function(x) { # remap to braille sequence x <- c(7L, 3L, 2L, 1L, 8L, 6L, 5L, 4L)[x] raised <- 1:8 %in% x binary <- raised * 2^(0:7) # offset in hex is 2800 val <- 10240 + sum(raised * 2^(0:7)) intToUtf8(val) } cli/R/ruler.R0000644000176200001440000000055614557444176012525 0ustar liggesusers #' Print the helpful ruler to the screen #' #' @export #' @param width Ruler width. #' @examples #' ruler() ruler <- function(width = console_width()) { x <- seq_len(width) y <- rep("-", length(x)) y[x %% 5 == 0] <- "+" y[x %% 10 == 0] <- style_bold(as.character((x[x %% 10 == 0] %/% 10) %% 10)) cat(y, "\n", sep = "") cat(x %% 10, "\n", sep = "") } cli/R/defer.R0000644000176200001440000001263114557444176012456 0ustar liggesusers # NOTE: patched to use `cli_error()` # nocov start --- compat-defer --- # # This drop-in file implements withr::defer(). Please find the most # recent version in withr's repository. # # 2022-03-03 # * Support for `source()` and `knitr::knit()` # * Handlers are now stored in environments instead of lists to avoid # infinite recursion issues. # * The handler list is now soft-namespaced. defer <- function(expr, envir = parent.frame(), priority = c("first", "last")) { } local({ defer <<- defer <- function(expr, envir = parent.frame(), priority = c("first", "last")) { priority <- match.arg(priority) invisible( add_handler( envir, handler = new_handler(substitute(expr), parent.frame()), front = priority == "first" ) ) } new_handler <- function(expr, envir) { hnd <- new.env(FALSE, size = 2) hnd[["expr"]] <- expr hnd[["envir"]] <- envir hnd } add_handler <- function(envir, handler, front, frames = as.list(sys.frames()), calls = as.list(sys.calls())) { envir <- exit_frame(envir, frames, calls) if (front) { handlers <- c(list(handler), get_handlers(envir)) } else { handlers <- c(get_handlers(envir), list(handler)) } set_handlers(envir, handlers, frames = frames, calls = calls) handler } set_handlers <- function(envir, handlers, frames, calls) { if (is.null(get_handlers(envir))) { # Ensure that list of handlers called when environment "ends" setup_handlers(envir) } attr(envir, "withr_handlers") <- handlers } # Evaluate `frames` lazily setup_handlers <- function(envir, frames = as.list(sys.frames()), calls = as.list(sys.calls())) { if (is_top_level_global_env(envir, frames)) { # For session scopes we use reg.finalizer() if (is_interactive()) { message( sprintf("Setting global deferred event(s).\n"), "i These will be run:\n", " * Automatically, when the R session ends.\n", " * On demand, if you call `withr::deferred_run()`.\n", "i Use `withr::deferred_clear()` to clear them without executing." ) } reg.finalizer(envir, function(env) deferred_run(env), onexit = TRUE) } else { # for everything else we use on.exit() call <- make_call(execute_handlers, envir) # We have to use do.call here instead of eval because of the way on.exit # determines its evaluation context # (https://stat.ethz.ch/pipermail/r-devel/2013-November/067867.html) do.call(base::on.exit, list(call, TRUE), envir = envir) } } exit_frame <- function(envir, frames = as.list(sys.frames()), calls = as.list(sys.calls())) { frame_loc <- frame_loc(envir, frames) if (!frame_loc) { return(envir) } if (in_knitr(envir)) { out <- knitr_frame(envir, frames, calls, frame_loc) if (!is.null(out)) { return(out) } } out <- source_frame(envir, frames, calls, frame_loc) if (!is.null(out)) { return(out) } envir } knitr_frame <- function(envir, frames, calls, frame_loc) { knitr_ns <- asNamespace("knitr") # This doesn't handle correctly the recursive case (knitr called # within a chunk). Handling this would be a little fiddly for an # uncommon edge case. for (i in seq(1, frame_loc)) { if (identical(topenv(frames[[i]]), knitr_ns)) { return(frames[[i]]) } } NULL } source_frame <- function(envir, frames, calls, frame_loc) { i <- frame_loc if (i < 4) { return(NULL) } is_call <- function(x, fn) { is.call(x) && identical(x[[1]], fn) } calls <- as.list(calls) if (!is_call(calls[[i - 3]], quote(source))) { return(NULL) } if (!is_call(calls[[i - 2]], quote(withVisible))) { return(NULL) } if (!is_call(calls[[i - 1]], quote(eval))) { return(NULL) } if (!is_call(calls[[i - 0]], quote(eval))) { return(NULL) } frames[[i - 3]] } frame_loc <- function(envir, frames) { n <- length(frames) if (!n) { return(0) } for (i in seq_along(frames)) { if (identical(frames[[n - i + 1]], envir)) { return(n - i + 1) } } 0 } in_knitr <- function(envir) { knitr_in_progress() && identical(knitr::knit_global(), envir) } is_top_level_global_env <- function(envir, frames) { if (!identical(envir, globalenv())) { return(FALSE) } # Check if another global environment is on the stack !any(vapply(frames, identical, NA, globalenv())) } get_handlers <- function(envir) { attr(envir, "withr_handlers") } execute_handlers <- function(envir) { handlers <- get_handlers(envir) errors <- list() for (handler in handlers) { tryCatch(eval(handler$expr, handler$envir), error = function(e) { errors[[length(errors) + 1]] <<- e } ) } attr(envir, "withr_handlers") <- NULL for (error in errors) { stop(error) %??% cli_error("Error in a deferred {.code on.exit()} clause") } } make_call <- function(...) { as.call(list(...)) } # base implementation of rlang::is_interactive() is_interactive <- function() { opt <- getOption("rlang_interactive") if (!is.null(opt)) { return(opt) } if (knitr_in_progress()) { return(FALSE) } if (identical(Sys.getenv("TESTTHAT"), "true")) { return(FALSE) } interactive() } knitr_in_progress <- function() { isTRUE(getOption("knitr.in.progress")) } }) # defer() namespace # nocov end cli/R/bullets.R0000644000176200001440000000632014557444176013041 0ustar liggesusers #' List of items #' #' It is often useful to print out a list of items, tasks a function or #' package performs, or a list of notes. #' #' @details #' #' Items may be formatted differently, e.g. they can have a prefix symbol. #' Formatting is specified by the names of `text`, and can be themed. #' cli creates a `div` element of class `bullets` for the whole bullet list. #' Each item is another `div` element of class `bullet-`, where #' `` is the name of the entry in `text`. Entries in `text` without #' a name create a `div` element of class `bullet-empty`, and if the #' name is a single space character, the class is `bullet-space`. #' #' The built-in theme defines the following item types: #' * No name: Item without a prefix. #' * ` `: Indented item. #' * `*`: Item with a bullet. #' * `>`: Item with an arrow or pointer. #' * `v`: Item with a green "tick" symbol, like [cli_alert_success()]. #' * `x`: Item with a ref cross, like [cli_alert_danger()]. #' * `!`: Item with a yellow exclamation mark, like [cli_alert_warning()]. #' * `i`: Info item, like [cli_alert_info()]. #' #' You can define new item type by simply defining theming for the #' corresponding `bullet-` classes. #' #' ```{asciicast cli-bullets} #' cli_bullets(c( #' "noindent", #' " " = "indent", #' "*" = "bullet", #' ">" = "arrow", #' "v" = "success", #' "x" = "danger", #' "!" = "warning", #' "i" = "info" #' )) #' ``` #' #' @param text Character vector of items. See details below on how names #' are interpreted. #' @param id Optional id of the `div.bullets` element, can be used in themes. #' @param class Optional additional class(es) for the `div.bullets` element. #' @param .envir Environment to evaluate the glue expressions in. #' #' @seealso This function supports [inline markup][inline-markup]. #' @family functions supporting inline markup #' @export cli_bullets <- function(text, id = NULL, class = NULL, .envir = parent.frame()) { cli__message( "bullets", list( text = structure( lapply(text, glue_cmd, .envir = .envir), names = names(text) ), id = id, class = class ) ) } #' List of verbatim items #' #' `cli_format_bullets_raw()` is similar to [cli_bullets()], but it does #' not perform any inline styling or glue substitutions in the input. #' #' `format_bullets_raw()` returns the output instead of printing it. #' #' @param text Character vector of items. See details below on how names #' are interpreted. #' @param id Optional id of the `div.bullets` element, can be used in themes. #' @param class Optional additional class(es) for the `div.bullets` element. #' #' @seealso These functions support [inline markup][inline-markup]. #' @seealso See [cli_bullets()] for examples. #' @family functions supporting inline markup #' @export cli_bullets_raw <- function(text, id = NULL, class = NULL) { text <- cli_escape(text) cli__message( "bullets", list( text = structure( lapply(text, glue_no_cmd), names = names(text) ), id = id, class = class ) ) } #' @rdname cli_bullets_raw #' @export format_bullets_raw <- function(text, id = NULL, class = NULL) { cli_fmt(cli_bullets_raw(text, id, class)) } cli/R/symbol.R0000644000176200001440000001075714557444176012705 0ustar liggesusers#' Various handy symbols to use in a command line UI #' #' @usage #' symbol #' #' @format A named list, see \code{names(symbol)} for all sign names. #' #' @details #' #' On Windows they have a fallback to less fancy symbols. #' #' `list_symbols()` prints a table with all symbols to the screen. #' #' @name symbol #' @aliases symbol #' @export symbol #' #' @examples #' cat(symbol$tick, " SUCCESS\n", symbol$cross, " FAILURE\n", sep = "") #' #' ## All symbols #' cat(paste(format(names(symbol), width = 20), #' unlist(symbol)), sep = "\n") NULL symbol_utf8 <- list( "tick" = '\u2714', "cross" = '\u2716', "star" = '\u2605', "square" = '\u2587', "square_small" = '\u25FB', "square_small_filled" = '\u25FC', "circle" = '\u25EF', "circle_filled" = '\u25C9', "circle_dotted" = '\u25CC', "circle_double" = '\u25CE', "circle_circle" = '\u24DE', "circle_cross" = '\u24E7', "circle_pipe" = '\u24be', "circle_question_mark" = '?\u20DD', "bullet" = '\u2022', "dot" = '\u2024', "line" = '\u2500', "double_line" = "\u2550", "ellipsis" = '\u2026', "continue" = '\u2026', "pointer" = '\u276F', "info" = '\u2139', "warning" = '\u26A0', "menu" = '\u2630', "smiley" = '\u263A', "mustache" = '\u0DF4', "heart" = '\u2665', "arrow_up" = '\u2191', "arrow_down" = '\u2193', "arrow_left" = '\u2190', "arrow_right" = '\u2192', "radio_on" = '\u25C9', "radio_off" = '\u25EF', "checkbox_on" = '\u2612', "checkbox_off" = '\u2610', "checkbox_circle_on" = '\u24E7', "checkbox_circle_off" = '\u24BE', "fancy_question_mark" = '\u2753', "neq" = "\u2260", "geq" = "\u2265", "leq" = "\u2264", "times" = "\u00d7", "upper_block_1" = "\u2594", "upper_block_4" = "\u2580", "lower_block_1" = "\u2581", "lower_block_2" = "\u2582", "lower_block_3" = "\u2583", "lower_block_4" = "\u2584", "lower_block_5" = "\u2585", "lower_block_6" = "\u2586", "lower_block_7" = "\u2587", "lower_block_8" = "\u2588", "full_block" = "\u2588", "sup_0" = "\u2070", "sup_1" = "\u00b9", "sup_2" = "\u00b2", "sup_3" = "\u00b3", "sup_4" = "\u2074", "sup_5" = "\u2075", "sup_6" = "\u2076", "sup_7" = "\u2077", "sup_8" = "\u2078", "sup_9" = "\u2079", "sup_minus" = "\u207b", "sup_plus" = "\u207a", "play" = "\u25b6", "stop" = "\u25a0", "record" = "\u25cf", "figure_dash" = "\u2012", "en_dash" = "\u2013", "em_dash" = "\u2014", "dquote_left" = "\u201c", "dquote_right" = "\u201d", "squote_left" = "\u2018", "squote_right" = "\u2019" ) symbol_ascii <- list( "tick" = 'v', "cross" = 'x', "star" = '*', "square" = '[ ]', "square_small" = '[ ]', "square_small_filled" = '[x]', "circle" = '( )', "circle_filled" = '(*)', "circle_dotted" = '( )', "circle_double" = '(o)', "circle_circle" = '(o)', "circle_cross" = '(x)', "circle_pipe" = '(|)', "circle_question_mark" = '(?)', "bullet" = '*', "dot" = '.', "line" = '-', "double_line" = "=", "ellipsis" = '...', "continue" = '~', "pointer" = '>', "info" = 'i', "warning" = '!', "menu" = '=', "smiley" = ':)', "mustache" = '/\\/', "heart" = '<3', "arrow_up" = '^', "arrow_down" = 'v', "arrow_left" = '<', "arrow_right" = '>', "radio_on" = '(*)', "radio_off" = '( )', "checkbox_on" = '[x]', "checkbox_off" = '[ ]', "checkbox_circle_on" = '(x)', "checkbox_circle_off" = '( )', "fancy_question_mark" = "(?)", "neq" = "!=", "geq" = ">=", "leq" = "<=", "times" = "x", "upper_block_1" = "^", "upper_block_4" = "^", "lower_block_1" = ".", "lower_block_2" = "_", "lower_block_3" = "_", "lower_block_4" = "=", "lower_block_5" = "=", "lower_block_6" = "*", "lower_block_7" = "#", "lower_block_8" = "#", "full_block" = "#", "sup_0" = "0", "sup_1" = "1", "sup_2" = "2", "sup_3" = "3", "sup_4" = "4", "sup_5" = "5", "sup_6" = "6", "sup_7" = "7", "sup_8" = "8", "sup_9" = "9", "sup_minus" = "-", "sup_plus" = "+", "play" = ">", "stop" = "#", "record" = "o", "figure_dash" = "-", "en_dash" = "--", "em_dash" = "---", "dquote_left" = "\"", "dquote_right" = "\"", "squote_left" = "'", "squote_right" = "'" ) #' @export #' @rdname symbol list_symbols <- function() { rpad <- function(x, width) { w <- nchar(x, type = "width") paste0(x, strrep(" ", width - w)) } chars <- rpad(paste0(symbol, "\t", names(symbol)), 25) if (length(chars) %% 2) chars <- c(chars, "") chars <- paste( sep = " ", chars[1:(length(chars)/2)], chars[(length(chars)/2 + 1):length(chars)]) cat(chars, sep = "\n") } cli/R/sysdata.rda0000644000176200001440000034122314557444176013410 0ustar liggesusersBZh91AY&SYnRyh$^}_4``fP!: ;CJ@2( 'Ώ2>}sv{t@hƀ6Q,@i 4 &jKA P()lh(AТ< CYTUBCe b@os_'HJR9jkYY-mW|uw{jzz:hyz}/)U:۴{;;y*\e@PgkYiJPw3;v=qT2 wg}<vw ӷݛy{qu\.VV=\n^ m)Z>w`;.z}ڷ4Ǿw-#;cOkt {8{ڨ(=hh} ms{7{˽{UJmVe]bhs[^n PnݼWuHݷN7uy׮zO`gsv{;gky2`gw.A77x+:`Vˡ5_'՛1k->^@ɹm.6n3znwrް7e պ{x磽{u7AȔ)7^WJlۢ"ڏ'FDRAIUEAO` I8!QEDVF"QEF*0b("Qb *Tb!TAbĄ1d DDIHd*,`,{IPA ((}[ P # ]LB,7@0PځP5WU"APV.nu -jh G,U04%5Db "!b"r7 Zj"UlB "$ !b@,* Ȫ,cR61P )bJ"*((eXPV(N.@@ DAOkKi2mB2__Vs["Q W"c-l`>z=?pϫE.k~g{fncZںZۿuh`C쿅}ыz= L>?Oߛ}oO~~Y~o~r|vS/NC m2Y7w 3c\71Lt9-#h9}`ut:^_g[z.Kw}ev~ s̭_s7|ωN2C?e8~}:W=N/}K{-6}m[/tcAe=h;.:/w;/E mO]]3[~7]lLNwEx]?/|,nAWvu<:s:>'|{]뿯 iA`S{]'߯;u[6>)zj5]_g4囬Zyz?7Mv=?Qi5>w_].Kuz_S}_??c_AK'>o-/O5og< /߻~5|6^wW?MN5{}<N_2Z?wS]ߕwn_C6=ޯj|?YizF|c^g^b2|6^g/;^G[~/Oxݧq2ہ{~{]Gz^l}wG]ׅ^x95}7c;gt/{蹮sg!gt7H5Fr~Xzx3ܧ鼏_8υ2 դ(]Y}L__ouIxO)7⿯ ߹8'˗VG9s9柃z~#?;?O<_9zyh :k8mnmmYg,k1^;,œ(gt0F,U]T("ҁED|N+*LF28e(W;^׮'ri-3q Ȝe>_1!dt;j 8Qgĵ5?H12~Qcߒ6$VLX¥Y  E45jsCT9VsИ5MuI|!E‡|O,D5}3l;vvM"w976P)5JWRƭcL3|3S :W3cԢp#ZĀ?L)sYC ⭃gdvrsMVlb?],x%k&8k$ut殠a%i@\`wR}y81 tֳ(\1zN=n].F,AΖq ap;i)^;f,cgBh1cG7l7)l"C-LmvI;b^eXM^eĿ:X: h1#ךsN/X{֛ 0=׷ pdgvGmWQN4ɖ_RQc\&B֥ugڏ@.ټ}dN|^q9nNEt!d3z@m2}"HOƽ>P`mbzc! ZGg50z:C͋65О}Q/f):vyq w_Lx8Օ;=^ã9dNئ 7^Y8IoVn!M<҇",L+iNl8LtJCQ@3/ pH#U@ГJ RTU=(&$;0)i(^TX<`M!OBgb(_~?QkAo`f}w*!hv.q~/6~8?sÖ(S,vVmxH>6mوCKdPD."o& r]G ݸx:b"6@<#Wo)b2??TNZ 3<*!@}XGwdp''8gS?{u' /zy1Wߎ'Pt'J4c75K&d38qeaBff\yq(Ɓ0,rfcihxLh|:זKe֠'};'6& Q&yqn/VY)zeA&`dZ$iT =msf4[Iw6Gl crǩ)Yg@"&,d-\s6{_O5ũb!溲,pT&Y〃Sd 6:`<8]f 'AˮkKeC@߆Nj=!.up|8Y RhTWtLŬņvm;z;9X?o/SKىF ;v#9W^Vc._FOk<޽6^oԑ{8.>|2Is^Z%+~Oc9K_Pog h/_`3}5e@FF}_z-0<:t'2~`o?q%.NÐ iA/ә9IʑX:yB?XF }.KAg$ZW_W\C˴(|vooooggj;;{{uv{8ݽo?ooooonO_oō_g_ݺ{{{{{{{{{{{{{{{uv{S>k=z'{uh?wwwt=~~{=:F`sc;wywT1eytc z;}k~Xy7.^yo;pw;w(v;p3O_w<:W5e%Y:9jէ4k,YNM#6>O*Azil/v&u>cylu=^N<'GD ˯ Wo/Wf92_oov緡OLlzy>F}Mju<7VxvzvoFuY~.^ZW4-tuxzu8/wY|],qtx?+.x|^.?O O |rW-R'ț.zetź w3Q >Kner-^Z>_FlݗųzezC}]pkS;7tE;iMx7^+MQS0O cT OSB H_Q!{ޑSxX8rȐy1^wb5s gUQ0L214{>,a~6W8kZZֵk[m;|d_$dO7]I'$D}rI'ޒOI>$2I'$O$zI?}$II'$I>$$fI?$u$I'RI$I'O$O$I'$$i$rI?NI?FI?VI?ZI?6I>$OI>$OI?BImI5$djI?RI?ZI?O'$\~|I'$<|I'|?eP}Yxk>.,O'R|<$Nv|_W9ؿEˇYۗNa-uodQM ZiWQE]gD1A>ܢ(؃g>zjϛ6lٳft((((EQEQEQEh(((z QEQEQEOA(((4QEQEQEQ=((('EQEQEQD((((eĝH?!6|HUdc@MR~I}x3gň+UAO|<+~U}w|o3l9~_r/Oi.CyF8?Oucݷ%om>Nco?;~?y}}sxgxFsݾN>4{8~^N7iY{Gz&y'aO[_^:~ooMᶒI$I$I$rI%l۴ggn<2a|?qO~ʡ,-@Q$GPC_ē]UzsZ]{WV-so]{c<8Ǐl!cw=~[-$I!$I$I$I$w=_˗{Ow{{\[nݻsw{w{uw{w{OI$I$I$I$I{gߗ)};嗿v۷||dI$I$I$H$I{w{w~wݗ/~^>=ww{I$I$I$I I$ry9|7ӫ8}?Pw/N|$c{_/~¿G{G}>[}o_w]$I$II$9$,`X, `I,-XZ'?\QT53&@32d, 2Nt:ɵ*TRi!a4SHM#xHفkK`, (a`X, `  `X!dP ( T,    H0` `X,A`X, 0BHP ```X, RD$HrH gKEP`Lb,$HI9"N޹QL+?ya6\yRWԤ0?3Z79;׀;ceTQJJ+ZFдZ%-Y* ֕ 62)m%`Rk d, m**$*JJQZեQ jaX,Gc-!rň%U$02S\\F b+ +@R`K(jUERҌU(V(""c")b娶¢(Ƣ1cG0I(DDFQ@IZ@(P2,8X(I* H)$ D`E "X) @*AB @%Q EI AII~ؾ xIv^2İr\U Ze-2ūV]( lv792_ΥX?_Οt5/ÈZ?ۓ~'>yE{?ǯW^;y^>?ԽO;c^lr1&a1n#^>Zlz׋j3okf (b-s"̻$)²Ʉ=ʭ}Mے֪UsG~.dCf@t׋./CPg&DK=mkEo%SԮamm  9o0acmPQFT  HLm3fhM۶yՅ'A]]v4_qf^|oV (H09&݌epE4ļg*A(V~5\i}V`+fvR`J䎂lڔdsՒBr"&\'u@?IqzZDG\Xg#rtOя-#߳gcnDY]x)Ig^Cҡ-z/sԑgKeRVc^ϽZ@d&>x7VUZnc#Զ:a/#k el+WFZ>/Whp6^bQkbkҼUzԦ. $21ՀY vFOүZoe35b¯11Enޢ}Ewݧ\17ȀNnqϚUǪMK6Q[X~i+"W_./67/)sɍC{w3x7~xͬ_ߨ2ns~|'ϕ8ϯ{qH=w7~լs\n=)kmuQiΚS:9S4J3gs2cMz@LIoC_-~#D꒢O`?4+ υ~v@co)CgYF2x#m75wE1 N[fEoCV>5;2*Zf ڸuM,4%Ř2/WZ' o W7_ӻ\mףOU.-㾓\~~ϞX_q'R'V5. ޴>_&0|&d]si65d?"كXpݝm=!Z 1 pN2YۭUF𔪹~s39B>-U|\G{taq)VS~Syهif7Rћ=xSZ1@Ş.D=RQu Fʏ!HbX vˣ5AfZae)CYɛj4]M,+*:gg~4֑8aפOZۮ]p:E. ksDC/h& &{".;W;冷(v8Yc[=+nu˱=Xkc9co{붱ݟ>֝/ktd k+?Jny6 /Ms͆ޛx_RoF8U{OƧ}Ov}'ZzP_\ o@^q Ar-uoiܭ劧t,nݭn99^ [20d_Lǵ>=hXq=g_ƛ^.7oU]F9OS 0 vm:rᶗv[ImJK]Q~74۔;0Owvc$OC;}G_ɻz냞kvS=3Z)֞DޕB`Hq4 `[>a*+@LM Q"Ԩ@a0բʰ>v^)9q%eېc ;QYG*睉N/-}[p鸯?+d8nվz:0zIVsy]s2ZjFjm)dHtԦ.t$DIudC :po-Yek]ZȰ(>xK,^jiԵY#n/SBxgeDt!t|A,{ 3kȁB'lXy5ìi]lxOٺ[7=EpP! 0+}׎].tC^;qաN9lTD#R51 L_Y/oP@[仄>x3R P̃zA evεeJZI$#wO<$GMpex6݁Ď)j'ua]1gX֚Tc1vjhi뻿vc }4 hb(]?:8EP1 gnbl?YRnֺSOAOЀ gD@/>\%9KS.ZcTO'՜Fbv0޼n[T*p^jhn5Kr>k9^i̡ӆ08;Wo 6i5+YJT'>͏OH2coYo]kRݝLU,c}"O>w:lj""5ﺷf}[kLfk5-L*x|ުIML^i; *AN;33^QC ͂b?郝/_[VLT rP}\Hng1d3Tm\'Yzj,k8vǫåY13֮%ML5j;hs56aߜjw)ρl"|P{gY=d364# NL{"uOzɇn)6L" hw.ݝR/CV 8uk9AmC`$*CEN.=|31~@T%%T/)p=Ӵ\b%iC[6{%3%)_Wl!_:vͽ󳶼&k#۬gjƢYUVJ]BͰELua[_$5C"~<2ٺ@b `Qy; ֎ml7|MKg;O8Ε#fPlÓcṃ.# L!Mk(7awS0l"/Uٱnһ9@wV< ,#E[peق>bq٤'&[40ܺq,t\JjOq'Ǫ?j^uӉ\Yn/w NN,Rp91el@*{}f5[H;ttleA-/c W5EE4 CQE;$*?"ZB,{ ,Fa~hUf_ 1C΢mܬ2t!Z.3w;RwM)naUs c1k/}^,=B-f]"GUN[xl]^1شXf6ƸjX|rr)jhNsvxQs3"s6587e3,ab_ihus۝'7nT G9BiqëSi$(&okzΖUp+WvQ{~\Hظo?*l4K/{EyhNxio; }d$'6YCbyc <_no zf {m*7:|Heix}m_q{Q9I3# !^W&e&ـc#;NbU8XJ-Zl覆@on`JpWq&{@x1|ޝ {q3W4<66wkK\f>df$ /gDfݰ-L@HOMvβ77\2d:SRz‹^z3uN=5ji¸7""'m µrЗ~XS8XOf&;3Q}29YaS۷YGa[*U=:⸺=r"_c#?>~UNi:†s4[p(fKv$W}|;9 %8=es0;+ : bgoڨT1#&[Q˺v4_8o]Z.a pˣw?w{,SMTICvzkᶕƬ+xڌpD Xx}B s; fW}юYP0o vfx{S:Pm{cGِU. 8Dr$=[;2{?J+7;]LJV45ݜ)B8O0vy>kyXRj/T1l@SKm"Fzwuaf-#?Oþn ٰj\{!"sa,A-l3DSaY˞; :gG5un7,s,tG^d1Cϯ|vwmDD7~6Cz,n`vfOi@ ƒ2׽ l$.'/i x5!W]ԁ뭳TH.5"1ʽ,<3I& _6XiSWFN$V |^USɰHg  `*P5P2)UL zֆX`zi&X\%:~M$/n>Fp63\rBZDž5'{M ޮ+0k'wx'|FʽVc=m{#$R:] ݊΍ C7_\'(58dXɛ=ڽyFVy]O]:È݃(UEĜ'TL[65V,֖!9UE!9nkp3ŰʪT=JN5a#$>ucpG^ݑL>}=.rhj1y KN]; w S~iτ:-'|Og~uv%ӭmٓGH;Vqq7=5ȉ4PogpWL Vb^Xҽ-2JjΦ젶-B tB9qquuFfsY9ֳbb"3?f618Ͱ>+`곜1sDFUU1εmWY%ڷgzֵoT'9Z][ֵg91F5kZlVuޯߌ;36II,R'+RAl莆}3bCih@Aӆ?OiNF畱7Wi!`kZgI#aBdzlUNՒxHs՞/=k;LfFHc -# 6öE,(Imܥha&m={߿\㓲dch)֚FID"R&PgG\';Ū$]C?`l6Hťd"MfKُ9L*K BUW&mśL 蟯v. &uDA.f${M]ȂEE[Kkt'ռX >Үs,&Ux0)܏Mm8gCZmN<)JW轔tM&971~o(ߊ[4J`]o8r0) sS6:q4 qYNDGFC6tHtTg`fch5<P6Y[Tc[ /]l̈́(U-k<(jY UOy pA„TLf FyJĦqJ-Z22"X>ӥ,ZZk◭٘%t[LiZjf[jE:%#*x=ԫ!2l![{8\ՙ<DAcCs( c0',\`UK*J6y%v;Ӥsy?gj }n&;[" GUHORg-;ǘd[!?&\(P BR>o<\ M{6M<_Q>p/Wo CooכSDr;YXMm-D[-D LIQ2LMHG'L3ő|_( }|>b=N,|7_ Ma,S!|L,$וnC Hw=(LR9?y]zxO#䞯n+o=\huj4%kGRv붍EhBO IY{RWϓV/bWcUljYZi:D"sM=iUd˦iHxgJl3iᑱįm~{/ ߧawA&p8oEGu'Kw8xe~ = 1ň}jͱ<5 a/pfff4y_/ j;kmCt.e┟)sPd*U2-]4F U:_yY,o[Mx$}y[ZIʽQ͐@1F/Iӭ30َpq l.P=hcUOxn u9w: _uJG͗C|dǭs.ҳ^=&H ϹʮxU)r /ߋ K,搐ϡ:0Y=gy8I^T}MC'<@a_e \:w3Zi p9V),δB0ǥxDhwb5&T{%Pϣ׈X㥯o 5>̠~}IM3FW/P&>yV}#}Y$ĚߟdBçgzvLe%UyEPrfWXE0kŗU-m; 0::gˈz93KfF<$o'7~̜! ye: 4n9,G1*̤f%C;Y z-5HP{gXoƵDPK|2#CXL }kq+⥐~;:-O&NhJ@ ա]ly{U!:}4C%A!]ڽc#EGzƮPaȕ~0=LtDs)AB /!S.aj<os,\ U`ff<*ȥ=k4\jjyƮxt =DB2=#i~kuY HָѹO7ѵ~:kWEw'4ùɺuNv11 -{{⹈|X5xC틮4p*Pg ՛XS@|YD$63~.lir[^e*Zcھ&m"ySBs~gT*СNP1C.fŀ+8$4OJ}ɀ]qy4Ax}s@fiƹމX 20biHEy#oIqV2YI2FX%^KVLjQ_Ւ,k+zD&{_u?v~ջAZ4ӃŏM *I"4;ߧiW=o-k$ź\8U[9 U\OՔYɳth ҽibD x{/䥖zϦzFRhP5GZKvUK^p{OzqHf }Dl1c3{)VKAFb/sV f6C7´0M{q0Ҝ1*bw2|?FS4 WZBZ4^_E{%ѾW{pz">ѡ" vy _( ,wgÚ>HۯhvUm&ӯL@wOoT3Gs?#J; ^O6ݠ*_2c׶Z:k==GԱFDq{1{kwK\kw-svt^{1{kwK\kw-svt^{o>3_8xBJ hlpvݲCVi:|j]Zl>Japctn'ٮ?VLЮl!ĚG|S ve6D  YY?G|ȸO^Yf(6a9Kwdt`QI(lxnkvUG~՘)ݱ9zeuK~)Gn*"Rtu:3 K^۹6~Vs@}nXk 8Φv \rf]kԸx'eu@Fn8‰ ?'?'~d/a09uDY6B6(I<^2 \u*ĚL>yкw:rCOGj{3X7δf`gF^bU$jrmP.jCJzx TDC@*ha`x5Fvt(C|Zi%"=u" #&VLTS/ּ+ʆEUex񐘪deHIMO|O)e }?fJže AUR*S|ћ)C۬_&0bEe  -EQQQ*$@E*/nMoZqdQU^ @(&fQx"LJb"!pP?1e*[5*[V?_?sNd\EdԷYTB͟ݑe~āc|c?y?9רH"pgc j6:*.ECw.hVId1vJ $rȢ`X0bE) 1``Ŋ^ 2 ,F,,F,D j4D1UP,R, DQ"DbIB QB $!KE X `$XbH XERŋ( AV؉ZŋAEA-E<"Y`T X."- " 0 $X"`A E PEHV,E`_4:3EMz(5CzFёb ,B$oڅ9 +@EojE, YQ"Y&J;iȄT@qXx_nI n*5k^D {=B Q!{z{h D@$PCHŠAJ)"*  (_MzM TAxAQ$ADM4tG8 uV-*H YmilE! eX r1E "$"$PAB*TDUUH(0FDEB E$ #PT P 0EP E@EdA뮬Pl ((* " "2( "H R+ #0D` 2* ,  $ HB 2X"(0`"B) H  HA8:m Dۮl@.[DG("4Qxe]unQs "[b7֢$E AQ",YdQI"X(BAdPT,ED$DE$U$Y  ADP"F(@PdY$ Aa V AbłH)EH(A`, 0"P"ńBF  PRA#(,0FqR((VXX lc-2B*4/J?dD+Zֶ1  R30@˭U-AYgWiz(]eX6íu]tHUѴk,c]夒I, <q]vYdHYeָ>zzt9.7d[uw.ӓ g@_;_FQQ6)j7Oe'Oڜ.C[ ~ϱD?ĺ;@G~;Śֵqqy^yN~~~{6ffsfccŚֵqqpֵ=zt6ZC9!-c{UOq,ts7O1fkqqn5kLںyjjqsfccn%v}]skZJڄv{*c,F1,vFfjӬZLwwI.I0eI& $wy$2$%Kd+r ˥U7ӍI0eI& $wy$YwwI.I82^I& $wy$2$ $.I0eI&e[]u]kDoL5l! D ?ĠT>TnؕUUpw!O}w>8!@ `:udd^IUX"xdk?~yHM][7F ʈ0p:Ȱ2"?n&64/*Wc8 ~ H,@a'Q~S?w_扆qT+c u/wUX1浴|_t)!pKˇ; +)3{$&gk>@+P!.dܱHH!7H a ~#{q`G ϸ["EU\3z,>\873X3l!P>Pt|%"$*B!@z=pER2+u*%ЀK- Kd,Xb :{>-Z'E;aLː.żB>;3ƶ6VU$I$xOÖvګwjݪUm@J$%[@>r5Sb_(A$;|)uX8 ]/&E.X2\ MגZnMVVRMNyeNG<w:cЈUP`]saH`dg8vB(Zyp'q;e<=E v)\xnd34^U(̎fKN,S}I҈O[z5sգllqeFDY<2ic s2:e x<35]Q#cB@&L]@C#yhsok"tΈ:'5njp%܆Ѫ4H&pzrac^2"0H($PY JԴDFAKlQXj+)KiUR[eT)KJ(--V[b2TV[-,ZlUQ"EmZ5m,RE"m(%eQ ȶ4BґUQbVhj%Z} yq= O.Lg4^z.UVC9dr G!A탞i8ҁ@rGZDRõ.4p{߭X9"r&J(wNu>'&7e,G&f3:HO{$a, BQ`\ ئБŋȍI%\ddl:ZQEժNܪmIMmmj #?s SxE7h`r9'⸿qzZ [e13sk_dtyeҠ~+B6~ mUU^ڐH2>}~Tl fԽ|k'?NV5[ڡuc8w3e&#q/(w&r).ݴa۷"I$I$K$I$$ʯnsS Hf4/e&[ٌJg уV! ",8!o{˝ D<ȰeZnjwwi"xY$8 prr4;<̂ôD0,b&i+=U111@@A(JuhѧN$@^pw?{`e??gޱnw[bk{\ebˎjݴv~6O6"kYUUUUUUM.n\5{BF!aAa @XD((QQB! (p}uHPb@#4HKQ LuQZ, uЯ EwِW2 'fw{:Ń[+$+YdI$خE X-mQ1D₊k8tH"$@"b0XDA"*@`0 Eb@b$ A"lkl=#hBD$!P $i(D X,dB 1NeZ)j4UjȰc`X, ´j!I? ]fL .d'g jTU0_6d jl 6lj@/tQGCw;`^(, `X ,uXD @`pA `b@bHA`X0m,0X, A H0aDD!I`Xh-A`X, 0BHP ```X, `X,~܏ߡx>/}ߠxx2~?+XD8/Bz%VڰzTuأ_gE|q"eLZ)@d-5Ey/ڟ$I$I$U/ǏwwwwwwwwZnloҸs$  /ƤL\&j]k*3$3WbhCbAd:LȖ8ULUbצNp +s {l D$E-kܡ#`c6 k5j\NkNt srssP%;h=IOcc狷{}~1e/5V/͔Y~Ouujz4DI$I$I$I%ίwwwu7Vw{­ ́l SV8!C@~ :RE'``jd3{w0]ȊăQ5$S R73$d%ffA<J3"dx[Z /^2&Jb5NWLkY<*ĸ-Va^7ƴ U!oE߯~-7M1ŏ2}3f(+xWg\;k}ӋտA_S3@ϯXf`mar= ߬b",2*Eq<[uկ8E e M f8$dy; mɨ['n"g=:N2n598%5[SᝡD{ǝ6m۶饊#ˊ?.Yi2eF !Z|]/3Sְ335Woo_Ýv9B*EWP{!A݀ !:7<(R>7.bbL =wn^$H<:X9LQ3R!ڦ*ĥ >ԻLȼ;f= ksB8˻י"$Ў~?zj׿tu1?otH-nd8ף4QYQTQ`v۵`K,,YeY,+T,v{وSd]F&?Y#c,8끳יebi1u;gV)ҵӠ'80,cրYi쩋H / L7@"]9C%>D `sW.͊ ` ^.F־WYKEݯ>ݻ~y@P:o+<j/?CLY;C~W|f["e6iIu?GgӎWӯ΁^nb If}SХ~/{=I|ּrM9j 5+B|2ΉDzVH0C D1{\]„DRÜ!hZ/Ac r4j9WX{>@B|2։DzVX XijE.B"ut)a^ϐxf0L2LB4h,r}vUzbi=qmm]$#bYcp:V'u^4d%+B|2։DzVcj*@P;v~M׆ݜ{#F]J_*b?"B1թ$$5=>*-Vỏ3}vW eA'=o k_?۾ggj|`I$ IC4h$wwwv)iWK1`e$}lj<^veUE2G3Nd 4V kJf*ϮO @ƘA)r;12 E^34]ù#DI'Y]X^~;qtpqQe>wf( `y$I `zF0 (zb7zAȟQ8GD*(h{Vz(.zRAy$U(BI$rz`|<>oyDpARI$?DQG!I *;;9<~v?!W*H!_#d@u)E$D? ŇfNd$$(POJg*I.3?/@+ Aoz RI%@I{0[?;Xĉ q"׆w33gI:+2!Iy1o `Ej|fF?~?EUUѠ!!:'g& / {T,_b#ֿ˝iÞ73՝_W8z[Mv.]E+^P @rsTߖjD W~r>H@gwKim-[mq |^C@ƋǠD ݋z_@ #9A]&G6 Z89D3vA0'p 2`VP8$ݮ]KX(v0iΚLf2s Ѓ[ɑS]Ķ8ExKN<| S4L\KzsfˈcZ]7ˠ5@"O۸C?)]vR6C;,]?lÊmq@ʌ_E0f(^]ʞMΌeIAQW9̈)=Zl܅il`@eUUAK9ɸy穣tA8]H4A0`\qCCVodDX闐I&5^w LQem-tPF+Ep$\/ Ԃ=91&Q97VcAdd#2?HCeOW)0;zC #ZA5 Ì/--mmKr-Wuqaqۖګwjݪnw h6[@Ý$ H .t~&.(Mɠ: p4T̰L QnU{ݬ  x>@~\7Dq :9ɂyK8ծ 1,kP\!KsfȚ<3r>WQk^%,aNZG*glpO^(A\[z[jX3M]„D Xs6Dᛔ03y 3iPY]aG?_^Ʃ=qmm;@0W0x*ik9J5fjjjM%c[Vw4seJ}$!]hS )JNIv\s(_h f 6hhbEDC ]rE y>X"e`jd`̸̊u\t`F8`*$8]]خi&KM/6 \@b@$ jUmF؋m4RUĭYZeeb"*DKQEEm-m6 [jX 0U,EڴkFQjX)EbTQJ-mc[Tm4h"*2IѭjZT*lVO9<:t玖ֱl>ʪm*i0yC4FKՊZ̀'Ŭ2IA!H3j0pM 6 ' $6~P,o {^[ͱ~{Wõ;=_7NLouxO;&VĒv+'m zdl-Kd߀^8|ۉwe : H+& )̪bY /ye2WxD5k0pff Ʈ]o+yŭ 1dC[j5칒w7egFm;C(wzXp޿vI,e Ѣ? k0\B,`̐qLYJh* 3j(nirQuCYTi_˗1A76+i{{eo!f5"]`g8'eMmeW5f_ڨν 샧~7|β5YIw9RkZOfX,>q~մX}qU o.1nvu۶p,a8Y >/k$駽0oʸ#wL*0'n ZqDkc>um{* &TMv#+&ʹrx޳3}㰕mN-h)/ bWKT*M"_dFɛrqK:w^WBHޔ&,@f2H7j7D}+ {b *c G,־O p,Ld^  $j,"媫+,JUp_x*aABV|C, X]?>n!9>C,?H:bIW~ y[_ׅQ~QBt(@`/BbB!DH^EV=T@C+'vp'Ky} DPzo\B!ZVFh4qD󼉂EL߮|L'9cjer%=On-P: Z(K#0@Jdܮw(dƕeUAfD/$x\.42yz^mQ3tofܳ0yՎ0#%(5){)D F Zt4 [z H=9)8벷 \cPc^d0$%h,5V[@+X R`ֆ5H4kcNL@H#c m@4(M1~NbMEE-VCP-ca]ѱm9z/ J(Wd+ wp7QSOLL&\feWVfRen:{1qOrVJk)4 Cނ:4=ދep㧅T,E6(ej>n3~)x}{{ৄ-h,|#]11P/YYV"<"MO#<'ˎ zZ`/{WcTi97v(HHB4`ÎܬWB6X @8.D$[ $Ȇc+e}iLӥI}}:hqy"Swxaĉ\ ܑ { M߇fI-nʸ[Z#^65 SiAӥ1ss;^KD|%M 1D"(cHvV"P&R%^evN2҆vfSUwt 7iS ,zvoida2 Q܍_@o&;> d+k,lmp #kD.;s85:AZȲ՟8i| } &q }Eࣄ62Ghu|x +2kL\V%hFlr[xH dYWTHXk`PkJGB`}gZG1ry0&B* f\[ߞN& [nS 8Pͪ&?ݞMI} ;h 먲=CllZx\{C$lqޚԆwy7\E{WH<M$f\ȨNnxvd>'6% ÁGnϊB )|->>+rBApjZa=f>m?k=#6Z[D\̉wnX'L?埵__ m`)]4M=q=@ (Dzzv(^˹OW8uQ䦦_噅"S0Cp4RCђn{y]}:4|>fhXGv0}ot9 ˏ(e.W^ם0D1II`)1 ,@>ڝ LZ3z) PcvD [}ֽk>p8z#6 ᨦCV=Yma]zfXHQ:ғx pW}+hiA)oJMx?-~~xDhFD կsYp`@H"'>v3Pqzp-GL3Baj] A D2#\ꃴ.oYo\>n ;NK߷!d**{<0~7lt Ȉ,]"2#"2# 54=00KP8 Z 58mHȌeP- ȑ` %9׫*$6ҍTkv%!=̲%ŕG0\J!ڽ>9)nO^l@I> g`2Q"JcDTYP$DH ?zXM!6ҒaȐICH%RW#UMO<gm7j0jfŭ8W7'BQ$/ ?(yԨl/w: :ǷtLvנ9׹xlrsިo2 >,AuͶ X2 `$7 1ZAŷVrZ }1G@zk6(PIDڶȊ Ǖ55j+_Y`qI0U@01U*w<'p늋53+!r1Rn &V2{ZB9τgPN<W.)^$r>vO VbqH{p_?n[&#J4 F Aئ<@(&Bꪀ|/8Jv7]>FwѬ+FIMqB1+YԱȂU D%kƗ05M# pOM"~vHq~ $.\2V\ :iCmZeϊ耺CD !DZr,2e%)l0P0{P$?0 UF H1ug UJt]UAHK)!HJ`LK1UW1\;1%C[Ə=jgݣ:Yps ijD6N~@e鹄; Q9c]u[օOst $ G6Ժ~m(3{9ˆY#w{ hf8r*C.72c%"8DC,)] $vug32!|mԋslm ipO$l02!! %"!(bو;/ d(BTbѳAko(8ؘʖ, '35y2@~5(| *Pֻz|'L23‡apf IG;DAIXDd eH$@9 Bi㭦 ##+X4>.oG0t=.+Mtdxd j#LēB >ToLFM%d T)1#Ԍmx.D?NO](]=ENuBLUH % Vq-dġ؎Z@x {iYZAr͇j|CGJz2a*߸ঢ&<(79㟥sXU@*%0g-9j\>7Pё2|@TM`~mT!OC"jMڙ PXU6z<|>E%%\0x{d94""Bh۝bJ_W]t'G0AKג?H`+QTUD(I$) Q@޴L)fQ"svaG~ްś5AMѡl&^ b@a""&kvQEk^zgPMw>q*|2#Qr%_(zţת._DGy[GouËùJ0h%Eda}$X4JYܚv%zϓ8HD\DH =LT~ B{]ͦPUTkAM=[jk2N 0N)tj+>r0JTjG.f:;|ďmQhd&=oV*g J" L6iJDP=n!`@  zټf"Kب ˋ& 5<wз'+H*uA I^ˑ(HI^YI9pj^;HFDTLna!,bcZ AEq7z|r*>X9'ڋUxiG(`oʇ upDƉI7u*C;U  lB $`s82+U8٤:Rŗ/# C!*4t(;DB _OGz"jH|~X=`hleh4 ~_89s,cGvfJ9tVI4Kҙ}˼^ѫ5ƟS,D"Ӊ+. [H DT\ppA0 0@Ϋ1KOVT6e:Ya3*92r뗓C˷vRzֈ`.c@j<мVD=RUz''ҹ_Q(#PgbtΔ-%fD^$gsavρ0=f{Cj颉XLؠ @M5(,)EH+(rU.ȯF*ZڂZi.yVm-^Gy4}~+ʖ ͽiufE!>˥7h teAӌ7dhmnl 1ͱ 2}0fn Sm"wŶC9˪&o{,.~:^@hwyNYӟC iPҎ*PQJB2-@#FĒH uT#|֋_Al2ˑG(ę,sQl2R}3VJfHrۊ|yr1`R& jepZi!#,}~]aMQV1j|_`:汌qgX بD|0 O,M#.\({4DG6P~z_o\ڶfЄ&x]в*Rf^&P(Cmri<İٌ5r1p)n_DѕX9ic!U`V!"cp .$ :=:&魠GSO3ɟ5:fpJY<BTu(.yI7hxU37S2 -"ks #YqtlXPb.u>1U jЕS49#ĔOuD֎kauۍ*KWS3k1Y+DB2I"15m좴W{>,pU/RQKD8.`Yf3> $_2Xl`CMJHy@O Oޡ &$ (E""  em-PP "*n48'Fq&r GPlË>h<"_*7Z)4}/W+XXt+K%!jHxTEzD*=I"` }>oA[Te˥n H 3`#)3BHdIaDp3M`{߂[}ڵxȦͷ;1>S!}|KUZ<1"@"'!#l'0\lr +UU$ ITxei"ʪMnjRDNZQS.AO?-"LS}̀B 9)1T>g~oaB?qʥ~ ~[:+-`m b+ο,Xcq>J IM,0@UE@KJ>r>it<91Z a Dj r&Qoqz^ (O$ EZ:&eT"ńaXX~2bEEX#EpdUD$ JƤ+ᚹ4ʋPEeBa*V@RCYD LKl P-a+mm&G !i µ[ytR!|UHѹ g?+J 91`8HL F-)T0m0708*DF-|E``#r:]%"! hRY{&B.| 8EkB `=:O\R"ޔ))N8wx D8Jl4q:Xr&(<6E݀J$Ic*$vtLX9_ w Κ"%V3q\Eֻ$ wŞYFA'D4ERԿ}S1 .I2̵m,Pg>Z7ܗ&K˸6 hPNcKk-S7FˆB0@ LV+ (h q8~/ũݍ} ufpvv-qvVN5IJP8f} uAmJW:˜@D1j} vCrA$17_??*u7`b iuh?rϪ8SNQh@m1 !Ɣ<stJ+aN/0\BYFHF]sǪQ{XisYnbsCPv ^`1,YFZ%XXQ(a!+M<c`S/:$I$*zkUUUo:v8=>t׾|w?C~?"sǻ^bErxh%$*{˃톃o0/DI%uac+$fͺM0<|]~YIqꋯklBāg)Ja7”ޘ"AE%X_n' {^OmLc<{wz-=<ZG~gol6P'HED"! X4#jYLװ.ݮM ay+ $O 5C4{B"͕ߦQYٔSYzWěB!@WPX~NQ}Ȉ(ן׷yFs=|4NIY%7̰@@֬ik+#!w$QS1"X*|)ײϻ@0aZna=d}f7M/%hK29ҩĽo%9@=<;~s[u!= R*惴](+FJU0)5.G8n1yAM3t@!8z QT |vpPBfp]ma"I#vyYklrYl;!PAAV"s&k<17RyY*WX`1Y 3CqVS^9Tl #X{#,p 8!G\ot7n!GCOH\5`fs`lV@ haǵb=2c PHAIqCwlXj2=O^y!" cA2HtY8-8ʳF Xn}KnI;#VT*[[D~,VFdQ[uL\+#)`hY.p#W t`C,7C uFWZ4fnXeT090i1ih `0`- .*A)j-,- )VcϚR xb .(W0!G_Y8_3Ċ=$`EN+[_Wmg}w}% "f  )j@VHA KՁ"f [] b+`8vI6c  ,+b#g3K<eKҿIzJi>^pǕB"H_P$OCIhd 7[X"VQTDti%Љgc֬7A!Jm9 n*.+yxư#K1QK Au_Un'=vo< 9vXvZ59M"*x?;s~2?S,f7Mf3e7EM.jAP4 hf 5n>kYȏ5FTn7j:,{sE|fާzqkDJ(E֡) 6[RT؋!PWxx~Gt={T .sVYƵ)߮u6StWvisnQz?Hl}cY<|zwߗ]bBĕ4mms=# Z>}HG )UBM]D 4{[M"*Tr ;V-@WS\~\Nxͼ#& C-%nӉL/O.δА-5ܤC9hvlBJbq˾ꫲJ @0U*j"xYr4ӓ_\m sZ`[d1|<$iia@'co]|,0Q1a75`BB[ W!Ev'7.v0hhȊWp`7,,R^ykah5xψoDΚ@?8=C{XItFoi_+͌ g/ePHyq$zP}G&MTtH "_dkkЯBj_:iOV>#/-=p[r ; \v|{2 1 W/y,A돠,VmOi=Ws C^7|zę!3v,{WOJX%S_O#ZZ_ x0Fӹ,4sWvѤVQI͈&Վ(B-9LqCH7cZ3'% 2 -4Řijg#=UҸ?*/4$PHBݧ i-uSsui]xv'5^}9zk1?4`  zh-@y0%hgDvxqÎɢ԰8&ƐYp^rp!1-H2ŁJ &k34Q=L!K;,@VA faq1' 'P>QZ`rp\p &xbx{e"`mÊ%I $}P!hR@A$U;b !c+!!+Erj=Zƽ"y$݃/Tbx] QC@}z]+Nִ^.1l¿=cԉ[9~d&_|fz}@4±&^3sG%:k\yi ¡@%>k% )*B_q"`4oW]&<5{Du,i>wkRvdQC\$] 9 Ffg A/Eeh':wxis5xHh@3pJc7E\**lI%7-CalDmqK;n;8\ًVEF*ߵ{s807a csvc5tʩD㵴 Qۈ 8Ad$Yuԡon2).-5v={Ŧ2 !5H>=՞0]doYP%S"ϖ{e#B;sgo|_ hI4 UN2V)c}:I8Ls}}AD.7xlػf{ڭWd1 9]Ӳ̍^Σ7 fհy<[9Uљ/j LL*-Ѵ+cţVTZv;C2rNņ4 Q*(*&|-(ʼnP۱ w(u`eR`T krڱ%#̲.A @BÚx84g#E5'7;D9Д)椚AT)K vPu۷{}hE,@MolR6eoee2()1 DVq ^ગx(~\e]`1ρ%zu \Dfz5,Y$aC:,kuǑ 5t]a%䊹%{&*2\d-{ YS r 6HFB!]QF@7"Zܔ̊:J@HxT_aǕQ.1Y̴ d20%LL@ B臡Y80!Π2&r0Y¼`ق,7m,$&^".vjp7s͑Z"&]Qߘ>KfZf\S%(Zd>t(#X]gYY̻n+Z^\4E<{ o<`@7<_,{mZXf3a*m6⧻>ʟ"Ldd~YF=1NjDj֥Cs0 #,b Vott':*3δ29L{ll?#?|F/0&w ʸ6'#_}0M[@vw8 Qŷ2v5," ֵ,KD5ّjKQ[Þq2O˓ ;<]Z,x XPn"J׮,M p/mg2`% f0q[=r$)J$Rt}7QdMՠ 4T0kPHN ҂$\CAX53X|&tQևMOKQHg~mWHA¬1 25?C`K33 W\QKٵgǚ<7MsյQ<_r5Cꖏ]v$1 ]^qr:)8ڠݐ0W@;>RUtOLB +{u3+b.ø|1n Д z+tnwSY:j$ţ 6 :02~WGkCSFliF!w>;wgSP0ĺw@2b8Nύj:،ҝ%.،+V({&鹀l(/jPAFM;W'KYtwzތ&r7q6#est|dË:ZPwLՐ6^LLyŏLiJ!f 7^/i\d3! VԱl˃\ta7 ëlıYw`ΨԔܭȁZl͔ Kd Y kmy 6/ @pÀ̜zz 9hk|cǻa]2 $/ϛWUh-=c"BI ^P c"}lHs΀ך61|5RǦW$s]uh~2`Tu{Djϧ>:"fW}ZrC0~|?g.iEٰXa8۫;nA[``l7LI=Rcݚ^ǯއvDbD km o{8):5}Na,̈GWh!~VH.V]mM .Ukvx;cc.J[Wo>0ܖH} Y"[~SeɷOL ~u};jef~#&0a~[I<ܗ}6$$k/ uDG/ɚ4’OGXֵ EqNA?el><[=-] p8u9P2tCɞtꅥX>] ؘccCǪ*)T1\qi1'?GcPN3f U6J@2 tu.2:;Waڀ2~z܎ϩH"˗X?w NCg~t||s3:&g C(~pP~=\А`C Ū(ɗ)xzg},Q<_^JuY Iz D SegKMuKY4  D=X+ )'E2WJQ|O+ZfLkHY˱/meYYR" X^w\猺/@8W}'u8cf6@5$B&dbdXf0\f$sBQ2Y^/X(ZtٝxR|uaS;] +B*|n(Dp,%O/z̢;0TIm9WĹQ"*Cjav9;2o\lĖ)ʭtUJ]o&B8lv JP W]X52"";=򌜎Xԡ C3 ްDLj\װhqy143ZOfV#! hmA@u@i*& )x dhHEF L_Yq JxxjF:s l׈fl!coЯiMxG%y&#]Tht #g誆ŅI=I\ʔd1*1{GO?lY{cZm;de'Hoިh3iEbݛI;p'0E'q\qJ9Au%V:'/v0^bQ+%v̊ !q:[RM1j# "Nɬ1`i2l9Lnf ÙQg޸"L qmI my`i2l9LJܑqwl` 8]dyfh4vXƌ!2gA!NU1Ny׌f4TՔ VUf;ۂS#}C5͝ί Ol43G}nwR0m{3t: kV1=U>5o&\BPIFXގ⧐|nT|'Ύz7sCmk A'81[߶T嗗:-57<Rޗ3tx"#~-N-uۮSY#B4=L=b@as˞qyg g~;M90=w)kB/t,ށ?މEKLr612Kbp!I1Ю&PŢeI-{}G::0-*.XwM|f͜^|2 )*y%[ְ4D/ )~&gQ,d(ˆ9{Kcd-BpQ ܡ?"ZnHhͅ7bɌT8ևt[6|g{ 5mYas&=rO]볤7_ MZndۈ"HGRg$~N0A\R#$߱tAj#mu+2TȽnԍ)u P h_>?>PׯyîT@0&0I֒-lbvi<,eOfxsូqZ 7A3?cw (!sQ >A_;T%z;cw=CcC/@ 7ȑveCנ uZ5sN;*L& kH9Z_Y]^)2hOHu# $(TFWZ¡7jYA=ٸ;cw#饳ɧJ* I4P6z$}AO(4I%~ r@"!@!:5? ;.fVy4qb{Y8llx'#Z$`q''<2֟#WgdIgd~ŬOlij~gRI!3~'Þn&Cg3]zXzhgXsgg:?L믔B1S ݣ傄@=2ЇG* 0#1\ 9bcmFJ7F-? ' ׉^bەi& !2y4CJDCATy@,E=ܞ72A*֣aܢWe_cGC4U@|@ӢzgT;@s/tkZ~>Cgx1SJ@N"!C``(x.YN+?EQ^P^5 .3.46r[C80ҼZDYΪ@i:BX$iA4Ԙ_TϡДFm6GmXpg~嚖]v|ۣG0f]3!M̝[ aZ79IVN΄mƆؗ ],ضV&Rp.fiƔnL}78H> zP# QZQb;cu x#a AT S#¸a:󲥾'S3Os~No?qj}IUUUU_ a:MCnA@2ӇˁyN_&9:A#"HAC;h[?? @ˉһMkHq/u=t- T_}9CԽ 4hӮ)NE"^y)G~rdkI#,XP(d,cAzzV?}X8aWS&q]V&=t{nlh.])B9=;PӉ$S{+_o:6Y.]ݛF0,-1].c7 u4JPOz'*tm**1kgfX`bn5 ~l˪dӃihqЮe¦Nae˭r``^/5_tT!a|~ DjpїVO' jNk+X4n S/G)݅*iwN65FƬ5,' Qȏ (/dH%@&j`zMP]Zsq:}34PiM4ȟ5w{bbysvЭ>Gr`|yR0~=:4*P~|?a~ ^(#;jXvErc_/^g}Y 1zUC30g%iC-yҌD#$*P,Ee9*p/($!̨?R΢A{J7xu.g']Ki=E5!cbsB!+eR# ZUB"V*#[[=3 (j!ᰐG}"7WX` IeY"`nb[hVD iSYV*,8k aeeEswL.M5 J`V XR)RLtՕ*@[qs؛Z#Q0Ld(%H2̭4AV] X3edUX" 2fOw|(QV\ϼV@~y4>J~ZEVO.YV'+ UEMPJqt00t_ 2;.B5ぎ}==R!l20"%yaBq H .^a\7ɂ]ƈeA S @ D1 p.zpGǴTmnj=$T@@"Yy{k#' o( K-  *CvwoNgo?jst;v ZnT I%^@ y _&\A&{ƫBe%yX{"=Q{N8{}< "*ŀ~]g,:*= lfkWHFF$?OT=Z0:熡=4Ia͉kV5KF(,XJʕJTZ(ĴIR-D!B͝tظB6 jj7SYi3' N|JDDI0\2Ҟ0TBBl18WuLLLrҤ!F G0 >|vYD.GCWb,v $ЍZf=5kޭa&XIg37Ť'BښNS[*OBc|,{9X$a$c${Vض^.=0 @3O҅ /-:k=}粚A0ߩ}#Х.Q0Zщz+T`(1 j}CX14jj r2G뢉N0QlP?`dz"̻/\@m R|q4yQj:p9V˨NIc {HL Yr1WR,) %< Tok]mK@`i GҮ_Wh Xa N*b&v6,HͺIP?9@I(,tplIE>IzjT>wְrYbVEF8R %+~ y]2@}{38 3' rb?BΈ P.on2}.(U=RP"`տYa?|59ߛqwf$Kw kX^/E* 4b!rޠ)ŭ{KzP : 4d40oM3szwdffht-|cqB 1kGgm '4H&pfG @K^t{DOdD"È5jŕe anѩGL <KladD|x>lwmNci+IJٱѶPI5t埥k}$o~mlƹ:py>e*oɡ T@>I$L6\V_ؑY^٪i#>U}Z &=[ eB3?;.ZB)+vҬBЇpYߦt´OApH]X{ ?S_?B3a{|5ӏyNڧ[fw޺mˇ86SCMbR eQ3c  `F\;I )8El|YޢWysXGcQ}r{^= gFѽBfֵ(d[sڿx4zQQ%vlB)I$q}Zx\}:'$JN˘U 6tAd!z3B-T>9pp8!9]%jkr %  qĎޮTݴ@#.g:1e$4zzq@PmPL$Mu YpƸO<(o6 i6X`b^J׳1Jcvtv=iqkMXAda Rڻ5&CK&\8Ї+xQ5Bk.J ؼ7k&՚mqlXxjpzabލ/[睲uiM=aEf9In:9-7c-9ka-WCn%s)Wg%$dYVw6-8#\o\Bֺ0_m^mBKNo@ƫ Ha h- a+jƋV 2E:0bMv&6cQ6a[Ƅ6MB+eX]c^$,7iz[W[¶CoNG F 9sΚҵ$M7'd׃C|84/fLR`?+CK%^ C3^#*@*Wr,'5(V9s6vx7tq"#@!LsK#qL5JR \]F,ѠTY fMWpUV| `]j&Cm;beyeu;NGQŌYXuZ糅V@f}߁JQ옒~Vn'Y\3d݄=μ1Ȓ.#5omWȠ$4uD}l ~Tș}q ln *Rv00ќhoMozP xE2) aFu~K<2ˍa 9R3#}.8Uu?<˾Wl4c}w~}M8^} e/?)gNM4LJUcpHK,| d2ISv>_. { # iK^b@s O?v=4D53:b.D7CF4`"4}njQiHI"1Ʀ݇ 4Ω؃$ q[ɔCE=ҝz X 0ǻYr!n=Ģ=.lY݄țY‚P@-eJ@ɾl,*(xP(2d}=I `ºz-%" wG x$ ]B.dZA30۽nx LT7j(4;Ci?C.$.e&CMݜ[Rk4\dI`lS,UcRE_< MVlےR2[]:S>.F2K(7H II,IM|_wJ T!8pG _]=,߰2;==M%+J$~L[b\r!|{turYngz䀿Z.Yis/=&6L@SH>Vy),L6-hgso=8 oP Og$uXk;3TC]Di6NN &S{׿}Ϗڠ[rM,`)Y|6¦=Kךk,.6yXonzQsھL8uES]? n'q \PSū+IBMӨ46k Hkkq25l5K=F]ZN .Pb#Tf>gD, P䨊E?<gi*K֡TG5DR [٦_SDi@MGo}^<?}. ^[G1F%4 3TDU"pA!+\]_;!PU%`04 lDŽ#+[ V /͙|`t& X BILxS(y 68O)ө+&#aDy/2'̹f^2qhr8͞&sW<Em7IdkKN[c{bT![9+iih:{ptF7JN Z;*V&FsnPL3 ZɻkXDL4)eA8p%P=X^5I$JV RL8cAգ2XT+{^6OZX]fi5\}Sa#k0@V9[%׋B}'gz23k^(eu<* 1LoL# ʥi .J\.fMαmh36hCr&xiY.QA4y0 >%xu6ͬO1i(zJҭ't0Bf7v[c_:?9>Gm}u7Z\|K7M6"Hn+ f9BJL2T"+߾2.g jMg:QiЛ: yl! Umǔ3+5p[tD\47AnPbPnanNu7;w;Uj ޵*-k#9 kƎps(uX(WKM$mmv imm%y< GsSmΐhCh;kbc=Z{%{%{%OKR9r0Zc0k8#\fMn8.EڮnuM [םUQN}szȮmm KQIRHRJ ~um{.{jH.wR^{l.wR^{l.wR^{UܾEɳXW qnP[&U=㬙c{zJ$I @EQEEP@2S(mx{eLXXA: 6W+QDz{X{蝂b\s[V1j %zVR[" Xje%\HOS.L^)MÚi(*1h&!6m`Gq"R(*ntM7\" )$^&}M3` | };r"Q*M<QQn\ҳ+12f w"^7!0O1()aTfR0`R1Up (0D۪>[ 3E3ӉZU*̂ t4o<~}~! @!hO㮍I۵x轺sA&VRiQ=@ U\iU:DZeHYҪJ\V/ /'9\^ڦs³)?Ϝx:t*AM%[B.6MjH\5@HaR@#,w̠@Egd+,!Ef,ӜqgoۦR[!]`Ք<̀lt-@̬{1$G} .}"m$#Ɔ4J,*j%;6n0XWb,18:s~š0ïo#ɡO"ڇbY`̃(5P|]? D<=|+?'M~~|R:3R.8$pmh Ƈ "n4̹<"eA_wϖvm;udS)@O(L;J:>9" tIӝuժJ9|}s|,7.zT4a!|I3w-j|Ԥ" )' ISG H4p7 8$";׏"ǗCRg9'f;`C\$!!id/^4rFwATln,jV^?^<ۻ|U[zA==6izIfI(y-U{}婻}JzZEqpܦ0W`졖8j +?i@e >6S~Xuדٞ~9fGzR7Sl#;Y)4,-W"}KE=Ti @a VfR#P`(DBj3(m=e^Iƶ)=x4@eCۍt}>DžsO2QJcӧ]O/b-q14Q^bVڊյj+VV-caTV[QZZ&"'3DP:7cioϴA/c U;C}NCշ 7Ǝ6.M7Ƕw'b0('<5JTߦS~^47AQf@ a4"n6%hp]7DlC"@)E`kX )2팁x"?v;ߐ?qx#xl=)Ah=Q?Y'h`ï72J!h {B ljeyjr;SqFP8q\733!x?~8Ƕ "{T Tnl =.* bBs4<,e_`Kk!H̜\ :bb~{{ 4¥W.hf~S"@Txt'r"!(:@T=tMCv?o'9t2eӀvQhJ3:g΋zT $'@ E;2>M(g"Got%X 5̆1E<.XE YQ`)TGX mDb+ De}SE1A"DbHňK t 7X9#fŞyX.@(EmFXɪsrc,v-pW 'TrI1D QjW!> ݻDˏ'FC6hM7\cQAb1K ބT'/Z9_,=a9;&?(r(ǐ@t,;AWqKk+(PdՆPj u ac  4W劳D(AwtSDr" 9vg^>|<}>xiL)M-n 1Eř8M v4^N(}֬ۍh~XiɸhylFqXP].Ж#f[L|] Ft"Sq2b#"b@˪r3UpeCx2-([pܒnpg[N08n.IYzA*mEkitbrh$f @T otq䚖K7/]N?oOkM[ιչinqudö Nd9śdgL6 ,APHP )&@bYHC.nfeQ^mN|C z:r`CxjsgY4req+%]hb"ȉ'xΌrw! =d9{=}ܖeC4#L\JBxĀs-rBgSч}38dSNw_lm)YW:ON.I4cd’- h"HZxnv)Fo~~|ϵKbtLc'=9zttn`JMvַO͞r\3il7iH0*KԹH$&[oxFjTS0Mώ.䗯C~/{+Z)`몧R ] LZ澍 1 S)<gv/fiF ThFưfH"dNj4X, րCpBo(%ێnr[#7lM&.HR sF]1ln l6]un m*kZV7ZLsZ8JəfݠnIi4UaSQ Y'8Sz1\J3!XLWkEY]%b$F,m%Mns&$ ꡂ"(IKHZՌm F"*a;(GTEY4ɢ 5)uBAdŐb( IZId5n$]`A!&!8ClޛB 08I/6`rZrmǖ) 0̱d:fPdR6TRsK˱U͛ݒk fԮ@3F.wqx995ŦܚPނ6XiaIX6mm04rՋ|1P5]$mqRVYjW#Օ Un7$>)9SH\p7k21D WW * iF{3m[|uX:| 9z. ~j>CR 0X='Cƫ<;cw!kםVmfVu6"D V@6RIs3om(o;+<.Qg^?dUɳ|VN|쩺 @i'i}rDYCrgx;s5q *k#"Mx<,/L(f'M +r,7-slqe%B~Nf1jf&Y M2k)iˍaaRl`i3ѩ66WL$2L`D;6,hy}4~.bn=ԗs8D[P4Qh?zY5f`іKq{xN `#ķ8nxXfz06"uf=Cd4)"aXtCIC{DĨLIPjhcÖTc6miĝͧK^T! %d$^x@ eI*uMr* )e.ΙRm/sb)h TIh&P^+w32kYˑnD&lg/.tM:%҈8,cz/IƄ c>f헸`ʗyl?G:}+L 5 m+ө]Rʲ%%]3mBTR5gC9j3>wmۦ ,WM >K=!B \!8יƥs=N#v6ϱ3׿,p0|6ʶna_k!kN$-)F!ɘZE"2J,%4f&. j.Z.w܆?TMx =(i+<0K$" 3"N("| s<0ݝ3Ӛ,Y5]3VK-qtAR}tz8)_3$Xā5bw Ukkd- 2QP1,޷COӍ$' (A,AAH( DDbTF,QcEU )(R",QQ;@uS1t: M$ #8B,:x>Fk<"ݝΒCw{ĠJt]n԰@Z|s bR ^_`i/FT.A,WeiZPXk*LllXIZ^QHAzN`cuYoPz;{zkZ״7 8jp`}r)Ȑ.@y`9&1̹X@p&sFQ%7 s RfyF$Jє:_6_2/g> {\q@42~㟏3^^ P@!h#3 zs2a@cI"2yv(=`g8)=4*gE]"H$)0ƨen'ǝK$Xf%nIT }l͍cibVMi Kpet,5 &k!tӨf0Թ-.#!JӠ5 JLf2ZMETDVP#)5Ds51ƥIs*Jbʩq֍8iZ+#uh1Bɬk#!G (tVRʗO: dcs*h. dK̓fQفQnŀWl +JYmlm,w01CKDf&94$6eBf`vaSaA4\0YƻsلL_01p/ E$ H~~I1Hw3\e\c@?4"7p ٱ :sn&-U/"!h<ޤ>l9eÐ]H|| C\21`Oܓ.p"{ |xvYJY$?/_w.˱M SX7PTk+*$UKmjSkc5sv孷2,4 LbDrnJZnej a)Ji܇UVb]UYտaG&r =ϴP"ɯ!́ nk],⥓[ΘWq߲7-v,v\5fJ)۬8ıҺG 2ʽCyK۫ ֖CT m+VCn< |KN>pv8&JTIRg)# VH/FVXLEc TZi,4R+6lOMr. w/"WmiF0 th^4EŮ]L5ˎ"U6iyų5whrMkBLeq@/@ EjDC*r6Iia&43WplQ y|2B"S|Cţs`9CMy5'߷־P,̢p0c0"5`T>`KIǥ#ǮhHRTQX" `Q(*Y˚U@@d(ЀrrfrZd-_;MWkܯÑO2I*AP`Xz$b+©LŇMރH R O!.#|uƱ~# &EU,A b~CyȲgiWxA i?q(xFo"D4&Ii4Gc7Ish9 oqQ=ݿ7 EQTU"*n~՟S|{S~Ngkj;JXfC,\aw#i=GQҵ&'ޢsYiºiE3#6NSl$ N sf> CYb"QTn.3G!DGI#S̅N"+ĸ#Ad1%#b9MF.k/7F)h4i^Cޯ//;%qNI$A_/) dVv$ )O Ka\ aFFt ~!Xȿdl9H@'c=8Ķ̞yX^RJ̓4r;YJ8P6i(HG(/ZRh`˾Z;YL``"g$!kMJi)ST9zx \Ń]Ve~tveף.v( {w8Mwo@-8v 麡ޟj0ۣN@D Lf9t ʶ*i-rvmGkC YF@!b( k\YY&"T/˥YŴj 8rq`2kRLT*cцPECA"Re r7o<c% lcOD;:0}h@k ܽ!r3|"v'DUT{rh~UBQfD&u H/VǍs>3/8`1Uҥ4QV y8 I=܈;3g#@N~qJඔL)i qw~{;߹_ƨ 9`'(ĐwM5M)RڔX3 'D8E H 7tY#[ kq e9kOc~/Ƃ?'x~9-uk-xt*DT1=%ћ޵S1!jF4g кcT1ǫ={eA$r k_uo\.ˊ5zwBzN˓QgMW 9h?<$ z̔uuF T,fA6[%PY#6?/k[۞9#8|oO]~N{naI0޹ĉ"9/on_ lSnňZIhknʆRp|=mc~~rB۲'Ps'Q#,*-LFQZRg[H,}zQx&M\lˏ_v8#wuDX(,.NqӜ"O31BIT>cIkˇ Ř~PN[9",3} ϸ d4 J\ !1 ˞ "\Ar97,p݁o!* ;Ur*}`NaK_v__rUC2eTPToZc+ &rDcF 33qԚua\5bQm *p!54WV|79V,kDYs/_/)>>~6Fj-rfݜ.>IhF]0,v O ':nAX@!_h UG01No0<ľ*9S3yV t~R>a6^ES/ ߸x<qӗ`(H"xDjuoKޒ) ,Pf"wcY.VԋṜ&in8ff]uq0Yna0dT,]!b`1S@ 4ba$/&o ik!:JBo'oEdnqf#" qR2 jbqm04]Վ[/h [6 h#\l%$A4K#2ɆskNih\M:ѐ[vf]m,0,Ytőt 2b+bܧ0XxJ4,64aE!Y-cȆd2B(q5@ 2$B`PKX+# I+m,4(eQH X‰m5# iDJ6űvI @VugfPF 4-H]2 ))8PEYĆY5 -@h;E@- 6`ZhiZ Ȁ@;/GzW yNNJ猹`5i !4432pfMyuXbA5rJFb $1e MZAV6$G<  )meFxH%nQ{# 1X# !T2 FzTe)l4 -[ K E T1@lB"QV(nar@U0J2 T&RdL4Cz35p%B2ѱ FZ¶VePQDG00&FJ.R2MwwQV(narH-brD&К# ,؜[qV piź)PeY,dX[-@pF+^vhKhVI';I[Ql) U<9xҮsAbp(o;dpkHgT  @5Ԭ$*-Ua@V((>h1x b[+YE͆Ȥ2͎KFELC1&CO{ EEم>\2I/,.{@ 77&f\" L !όk JH#DvdSmSG#i۔sN;MH?C=sv J#*xD4|EH1F< T.Ln&%>\,xP+.pFWv건daF4Q k3Sfbq]FJKCLLEm`KR0rWTHZkW5JɽPֳ !r(,h(VV W2(]7E:3$w,++2U pbɫ(($4W,s` 93(cՆFAECV,- c(hBCTGY3)QrQEʱvFE.HJ&sJP%wZ*4@˩s#%*2*eT+LjزR0`,5fm(ff46L˒@*!{2MTk&.EN%M-2i`i\e̴4 h59UM0+$I%K4Q ӫRLH( "!+AC(UF k%hZhjT"E tZբLJ 1,E@b#]5Ɗi,[&0i)Ry1[" $L! +H2)kJ ÛG[Q9̘Z=xC@ԴeؘW@UI9rGэC q4Truϳ4v 1~xx0edaOlNE>{offh5*eA!7Z YB2\TKF63qj.o\1y`,%J`(!P  6 HTj*@ c)$ $0CTAA@P$@TdDIHu4jҺ`ZB҄eً 7&AT@)dԌɫ M&'1ޤV` 8a3-cIwMDcTޤD1b,ԫ,$٭+H6 q31873NJ ]D3UJ1FXRJgYm*Fl}?yr~\WL7eWana\hWS,[kJ$78)uw7;зV>xcm-n-G oFgK ҚXA^DMxGb oԨ8ǭѕX بUY?s>O݂MQFŢ`0 un2k2H2hH E$y&!2 ,!UBh^AQT,Cs*dl[,ϙ8F>':K,+9k\1r7E7ކе5A̓.0Ź{~_k[F0kG U!JP EN`{mo9ӍuV[uw([7nwgǢ 7xX9vd"DJJmAujcl@**~$ }sNES, s]>y-@&P#?E46 {U2ʪiuEU5]X&eD430U8)ve)R#j0!̊.L "5DW{$lŦtrL 6+mb,6Aֳ24JdY+љ- nv K&F\R oVZb di4"Y*0M&:w XGv b1F1aE"ԳV"$UL,bQjJDUUU"DV0PR̪bnM !HiЕ\E*@c5(tXj A O܌%@B&!mƦVko )!B XtihB&c@ѲH)$PPDX`p:CaH4:JHf(Q#(DLf(+hѡcXF%"FVՓa!R.5YH YXb! @Sb`f 6/gSLKBܒ:sMDeY/mACP@4Ct.[lhjD\Bl: ':hE4_#+mnhDmY)fnb+B ]N:uQI>?]pʾr5>W iRltj"_ei[rxzXP_KdO{NJokE0u@oe3/MppbTWXF4p4 bαykxIXI[7k_vNy˦{q=1 ~L ?|'x*=}s, 1rfXHoP6!_90g0eӧ[$޳$F}U4!sD3/fQZ[WK_\$?a׽ŷ ~4*D O$9TWm {vqWX2t~/=t! VDc?tQVGwnՎY{ox\ium[ʕ2 Rck"qAɭP95Ľ%,6HW5 }iUk d `|(!F4'@zRO;ar ?>-Q\p)Eš tש*_g#hi oLi;'&B1lZGOP\A|^C0" H:=M A6& 'y28]TP~z6Kyr|~!+XYBY3yCXΙze?'jKBVYzg?^lt+ɻTJa=%,"Y]=!xkTV}z S tq3JeRPҕ_{~\8q?oM(}߲&~L WG2PiNRw}N;ᷘnJh{/8ਈǝuר<4%uggUԚ=y>?D50ԇ>d+IPP 9o)KIan #*R3V s{MY3,UdFQ2}j ,%eQ2 If|B![Ap""pj TB0*fcyri$bY*4r KBQM7^J`PdT 01/0}%,+ZM}!V>l S[,ۍ|&Aَ@@]Z/Bw0<5F]Ј)h"#b$1F %ҁĚ}i5c`]ܿYJǃs:EXw3OH8fo-=tP:{:#3DckS lƁ cy՗7h;\! T)+ Iu\Z&t)axql򮙅AD7&|f3)v', WYBӴ:\Ӽs@pl&_ @2|82?(Ԣkhh~0_{[-dN 3ҝɣ=d ^ N2ptКxyp( XMeVȞ{ׅ(S~;T:%Wӷiᓤuj\ ? S>.'ծ_4[ o]yW Y;EA @#d :K uߖR-@R e2k{Tc:9Z/lg8jѵ +0  ySK¡^:@ mn-wgQ){ӻ ({^Wn $N_>2=21K f؛5\JzΠYz۱sva8-P4PEhbi$DDdIDbf%,4YDołGT4$Be ds^f$/c%rbM) G} C4wHূmgro?x|ޏ?A5;J eADb4)vX?_aAWW>v-ua[>'¨*@$H!?bmnaDQO7ެy ȂƳ TI'ѝ(Pi XQbT%n돵TjA $" n`^.nN`>;*T@Y нq%z !OH鲏/?0/l(%JI-*,㚢QB: ,"K$0}n>0ff2i½9~_mDBY1(Ҏ `j⍖h ٱ@q(fcI1y0?n5f"Pd <'hz]J¤Q`^4RsL룤@ו$H"Z(O/oc!Mbd!*GםV&PR딣$YDWC*Ӈ EzjnvM8g _#Z,ʄע ޠ"`jFۇeRzxݐ<zVpLHVB"m @]o˼ū(CL-ir=:zo0.wapyICfY{am 4ݯ5wdđ N 1ae ) 9CF`%9UˍZ(! 8ۘxTJG79^MKf e[?08yj NI|Y薔Bƈ:"Bp }C!I9>XC`˭ n?/["u߶Ts55k v~8Z͈{"UڃQSh_(iu ك2 DO/77 8 8݇tHw:6mT˧,Ξ5Tꍹ@:\=%Y6rM۷o^ 4cNZ:F/@<<mW.Si?Fc;-XplBVwitq) A>ƂnciqymjaU fx|/?f󆅪S# 2"e&)1'wPSn٩QL,-PB%c\qB}4`EC`*$6JJHAAqIUk &uXӞx"*D!K Zo mLZ7II+B~(R|FAYr?{/|UbvݶHR[zبVwl z! bd @.YBm#Xb:6ŋm[s<δ~Cn^CfݬG9Z6 CjDʉV@ϰD3W ]kgsU>V0 `;0s sA@tT@ ^ f UmKh T,0w"XxQ ֮ `*̙5ζny^M:DcH z7j~!}9EEu NiUnbGHOT.K?!x, I" "@cb <2!M/eCW&Yb!ڵݖ ;ײ4V]cT,O[ ?s1J!U41kC3,pDSA-$Ahl<n*!"q:9{L_S.pƜ?.'*c-O}TDeZʀ^@@8\ B1yǨ}5>|Iج6-`` \ ɼj1}z}m8΅Rth*-ضI NW'R~h 3cɆ .=_=:k |~~R DkTAj$J>g1Aa(Ye$y?5s!9M2x%@j:tqq 疬羗n1%h2/{ko[;fCZk9|rˆ^&=Tz P].vY 3(9~atD[T,&2b* 6^j}38` o;St}y~S+ E \y~zč߮xLG "uѺ|vc˖ebeՍ (TkEqLIGuVF."9e9`;N+;Bmo;XSoX.x޳>\,hxDXK!zͫ ;(-`$ᓬF,θ^u廡w}^%t;k2R$b ,%CZj@S&ˇbE!Ǧ5pLC%s]TP ?Q72\rP/r[1S_=s6cM(o_ dzRͳmR4`C\ @!dEQ!Z3OCN Ѭ%VAbV{r[(vK亞}w';64 ,+A,n]ͥL[){,tb3eG+H =euR J !q@_䫁ov0Gk{r;&aXfjDrs5AkaER2Y,P41(;De&ae¢$rQq߿\c1DzB:p$zR+!J);-o [/_t^د*|y$2' AA&v,+ɔCbC{;,ˊHJ³Ūq) հH4YD x1QlTMd5 XK^HSP/S!kiiUa6tCAT DQ\/TQIdXT0l`?=jʂa7ʪY_x|@?'OW?ĥWCzoO͎U8<اc b h/t0(Q`zcK N! D'z~= b3p%J@lq%x|fmF PHGl#1bP*@`0YFEˋRШ(.EhJŽUA7L[pbR FAȸCN,Q%A`QưhU{l& -1 IRi)HZբ()U#$ն(Ve3-,Qm%j*C$.XVT5 5*iJQ0)m(tJ~xލօP#T#xul& AEdET-I $T*.RJRL͢&btЁTEASF*E"K2.(dFJo0 q ݋2hЂ !FXAaZ%k[hfr $XAI SaGNE>Lڃ~Y.[C։`~J2S*zhLD-UTƜE.)5 R7V-Ux,}d -D $~4P[A̍H?q @nPZCݶ~FW" D=>[Nmm(8c76z?Uہ>>)fh $%pfmi$%RNbUr<#{>`},o{"$|,b&_S}1I EߘrrxՀ"f8.@Z AY91[D!HUn( (gD@R$"A_S1i}]6\ w(Ht_|- ŒfT ̅q\D ty5Ô: OZi0*/J؅ SLS_ R a5ldA VdU̘IY)B%i)ʔJQ.!H!5TXK,ae \aRUDEMZ*1AAHQF@YPbc2#4 k 8XERk 2 4X\ R AKniMC%١ED~2[`sXWTe7f H;7(ȲJiۭ1U]o*}>γZ|>}|{A,NVx|ĀHBF (BmXUDt쭐" VDH heWldy-l*^'b&aN-¨P:<Ǡ߫O_pqhH3ږ/p鴾;e3"X*~H;DXZ@2v,RHHFfHbܑJٶiI-C„[z?AyT,80vJ|.Efy[h7/czlqӟhTÁ{hw*F [K8}H(lW.SSu1JqTآ[@QL|p!WI'd KDR-rRVb$ؑ0 ;Gt5"IZs6P8 ه  E>@uĠH[,DLWJḷ́:fDLbE>nh d]!F .;HJRHbd,n@,dpC#B6mIPER_Vf:ݭ,ա♕EbXݺ+i($Tabz~5gO/(D7Ÿly[?Io%(SȖ638r43rpR$!Z^@ f ;#@uPcRɠ̓[ F`ҞG: sBkqt)1G81ھ"z6QlzOhi$jg…y"%4@#_4r"/&2:_6&A:ct 5\;Z/_JE9eD0DhXhEŃavXv]zSm,lQ}2`O@܄)>Rs}u>XF$6"U>/1˓Ni3P1),Uʽ񆾧9FtZJ ;]?y[C }&)s1)r1MrR=uL0%Xv 0TUe.Qp$X,IbNfywb~}L8f7χ^q.y9j6m[J,(GMQ[Yϱ<L8Ko'!~ҹ FxH*<$Th0z#E! DB" v |O=xxn،b.e$C5d@5aQD\J$f2h&0thbf.LH*%ՙaML2V@A`Sm-e˖ۙ-h*q2Q$'`vTYb$rfYȈdYE2 8XtHTBl)L`cV(:hjdKmE4[NJL0ha1DŒ!`YPh၀bT"(ڕR ( \ `XLJ$_Ia)nY0,`% d% $f#IB0XY&1qE )F T5Ei$'⤜kkz RzY @!ap3lnyPi1!!+ %HسԔ;=AP5=I%ډ!T mqM$rQ3J%2=Vj(I9ʄY*Ihߜ7dJmawKfqj_n†N"",QwXSb妅 V tpg^' tg xL*KۡDtjƶ0(,k{[(fu3^tŊ:)Id!t ** !ML bD&k0'GNN[Z^Rf{cD;Ux23TVL@Y1"3-Sg(h}p疩˜(i!Sx~2^ݻ(͐7g A<7O'0.i`|%*l1DPDr}'}K!&lrR4k=[vv2k9ɺ:> ܅ܦk.+:stQBQc"Υ(ܖ\k8*7T=>캫ӴٺMMs10~@ws]xb&[g#Sͤ󽈛2p8h]l6E&ȳdA`z][ü!P>8( E8U?7$젃hz&+6~%W\Ebב^4LF Ԍd ;\b;hHcPs4f>]'O(f@ ͛ZBI $cqm'>1w~]r lXy8|B8Edqd1*av@݌L(V`@vI3[!re +f9@\ty? y!郘(AeX' VR8rt(5r#pAiaF@djC.ԬfVld:vPkkC,e^RÒ/SH^0%:1-L0iF>9}>(iY[nN{je#GJ!XZkCATJc`PhU6QDt圶[S)A4 ڦUgFRȢl2A0*20` R@vl>q'_+{mӗb_{i\N j1S}S+Yẍ́ 6da]-~LYCcufB ft/fz<8}$& "fD߯"oΟ@Z 5šz.ҩdBCDžm߽u pN|w̚gfS `Ƞ,}a{JO8(@DuKyjk- gf0y j9:[T%Îa}!Ю#qʨ%eHTPD N4 AIHHT@(SLm[@N1 ;:Ww1Аgzf29uT'g\[,KU"MH+_|?5cղ1yo-F/>qLx0HuؔL4 3@X`UTukERYHQ5?!r}Lu_@"5s0 P-ʛePR2:* ZTEBQI ~p{r#!:IŝܼHCi}^g Dv,kWIQߧrr20Kb) ]$}(k?/!pUA #"X 8T/?TK ߦGHU u1r_&:&MPJFq0ӍEBA0db$'"UX|q솒XӧBu|q˼ݑ:~P! )BN#dac[$vMսkf ބ6ĹFKze'=N9 ** v}zoHr 3i4>~}\rx*"ض5^^Š,_1Y"B.4PDCw1r E|%I*P<|!$0){Lڙڢg#NاXM;LG@?S"Z8yr0 ߜifb6dž_-2YDV$#Ԍ“%0UV`vZ56k(ohE2Z0޳6=Q48fM rp,t'㐿'h}'8ろ%JG ZEf& TCw2Jn X(E*vH[tp_؁Fo5\d]^ OZIw0rZkHDhflHTevay CAI5ޕejq(4(/"asX/sPg̿rN&D0߸\b3>_4m+$$PԯŧZ'|–޹'xf5kxIzpbI ȀjXowϏ> hOlysƮND45IȊxCOcpлĨ}>>ݑ;iBOxX| k+CRP6k,trL_T|g,d 6oc1NB^N8H=8X C'F7WJB*}=[_4ZBSC.zIcٱ Szwstl$f[ c .EApCr$IH٬LȱEH"F[\4$gM15^ С%Uw%"GdL"xύP%Y88c4]qah⸴htAvDX 2Hw[X01`b&te//x^u\o O?*>rCT5K?w@ϴc$" o  `)--e';??bs\̾xZtfxL.[6'A:Jwryt)2C'4?}NC_1<ֽFƉFkVf( p햙Nj}\c6B(#s{sέNm6$k6ZŚͼ:J@(Nc}p<PB kO'lǴCAjgDYˋY4̠C9H%lId_.ؐҝ}<=9rW$ `ʃNcWa9wq.jł,cMds+XR@̟V>MRPg6HYB2ջqe,ҠG\(oM?c)aIeTdO1BӦS+ sZ4sL3}V&]y^6q+8rAX@9$CPJ4`c0aHZ1*\zkz|OIęoL]u }X$w-v۬mEo8@̰- gLk U~>s.ʪ=}ީZfztQ^WYC 2Tg֜=hHHKdM?]"!LJOVt\")ٷx:_+P$_ JDqgM&IR3HeVID-QA=(֛ U ZǛy\;kY pEZ4_3>y&4!O̭eN}I8+j` \}NcNTZ1۞fj+.駢T4iEC;ӯ5z$wqkCRA0$_U<⃛lXD )l;)Eqy2'aLJf͗jylZhv@Pظ%"3ͤ9;UllmAi2mŇљ5&m4a&Ae-^OzrɥUięY5A{#Pi|@|b]- '3`AE/+Vʕ]}VP2hXST[ac^=DU_x&0S0j^PJ[T_뗉[ZpM&HlҪM۲a5t薪m0Ȏ+jݸ牵4'%TꆲCk#@`E;w/{ 9ϕ{λL8~RJ?J'tYf"uF474DDp9J l{[8 JRe 󭺲9#[(h؆H3Ud1ŽH7;7ŶKêL20(:h,v-*sLr6Z Ĩ0X/R@\6{q*͓~;L.e頡_׸fC.ӄ2%t4 }:Ns@V,X8v85W L8?u'ݗWjxJl6t Jnl m\75F:XjPaI֒TK#C_;€&kٔ3euЮo|R.PZ( KE#EbX B@$%&8vXmOXZ{tמtNRQD Zdpnܠ*Kx+vƙ2>]QU٩k]yPR&_]MhXr)j* qz/, !J#x1=v||cJS:%@ jP7?l8<2++c &oFN!|V8N~ZU2-2^#3߼L--ĦljPHTQ7ܴC^5#%mRdC--!{L'$7yZH̥TEa*7$lUB̪:z\clyx_Ez==GÇ*tTEE{W 6UhuC{je}x̥lKfƋ>p42pF bel.Yֱl*bD/\xYaS TccFI^g0yg5H"eU0G?KĘOO_zÅJDD&\$#Yi Q O&fY_{&/+?\)0.֋  C܏E`K-b$ᆥ; Nc=h 6{ųY3\T>J1U(b!$guMi Iu؛VNR &W-X$G¤CnƈVPd"Kx}DA>~}B0rIj(n[-?N {x$ca, =Sc2A<7N'L8y@r`e[*vt_>1|W_l8l~\ْ ڈ k`1k͟Œ%3P{ a6e`pk yFhOW:\ enK|=_+lKNl, 1oN:c xʊ֨4mv}YIY"}#؈D"@% _Z8l=yCyRhsqT.tО[46{бeͰT!¿G \~V5Kxx-{gv;>ftN})WꊜrըobMr9h|߭8} U@6lIo,;w8 BPxҽ 2TӜP+- D82 2QZ DL#b(mԀg Ep"2N 6D+!s+xI:r,q3=@ccȴb" >LvκҮx2ϦIܾZ[}\TT2yst9wmzC) @Xr:B/ّț p< =ahq|L)c' 5GMz)[B1+x=W&l GݛWYb QaQްjas.EV0:10f cCߓceDx'J@H7-(td1-ߗn s 80 OkX-V'T[$"@A%<ƥ {B[>fnFy:FH!9 Zs6"#6g{AXҀa'CXc}l1nUȓeRɈ*41X|ÑSf |h*0|?KZ%ïR\|"Ȥl-h2IJenY[;KX* (O'1[*%@@*$$%@8`b`d`# ᮂʪX4R#paEj W|PDȢEؘ\hrkb`EA CèdH, ϫow? 3GmvRX vֈ;S3m6-UNӴ.g r i%CPsR.\2B32iGH\z#y>OwpR%( ` HT[4c6}u_S.Y͊YEZy9TyZR@FE@m`, 5Z%q((D cB*QRA;-;*eZݹo(];1RD &|Έ{,$9_j8jhtUu/ ~)ȉߋgٹ":0j@d\ .ѤZy hWr Db]m%0\.{#aÁ5ò7lWC_Yb98:\ߝrDFѴ M0dcUd %>&E!7苰$av3p zJl4RMU6R1|q$CgQ! b Q( A eAYQ[ "'1R8!D%:5o=c! Ǥ{%j0 vE$Qmu->{ITx  CID$+fo3?lL":V83JLQnUOm_혉Ʃ~X[6n&&CE6~P -sZ_mj0za0B2r |܂ jU=? /ъ?ZkV<.&Uaj, ٬LYTKjߎa|`X8la42OtGE>|ϋڸ[Ojֺ=]vÛq,XY67 #=Ue>/2(YNk0].gKi ram^̈ DvU<{-K~keMqs8x֭_poXGC7x)h<8gMӿk1E$ _HQFdPJYJcay[kl'͠/ {F|mgӄo~yGCʱvN ( W,VYIk#VOٲfgKZ*EAJlT 2;d7z2M&X5U Ksc(n>^4݆t/wn8 5,oxuq[%өfzk$tY\.-77<0Qj286\9ńp:;],!T`:,W[fML\~k|k.[mG6gr"0D D$ړz Pco#r.ٟ&sMp@& awKpyK[٠1&0vU9+ wNS+fէ;sϺS*wlxdb[D=(&zGnl|q/ZG-'o4{<,/(ƊniL;*Y0' Ӂub|-nV58:z|N/Z,89\)0{iʝb# >u9}e;%i9צofu;q;Z:,;b1]M{)Rg<6j*m\],堃Oc!~H󿧝pS`$@*b3 d 61 ղl dwZrC h@ g9quD '$8vIg릋*E5XT^K&2{j89 [붗^hv 2m'{XdjPLfe%0@ E@Ni$ BwCӂa9:zn%=bjPI)hjF(0e`` 2 bS㑣:@hN~("ZHLymF8wZƫ|#,,G3e1綖޵35WM7/}Y +YaF"٩_!#c}3CŊ(q@QGKY4N5(E2dMBwh`pВ!̝ܴń Q6`HZW?ۢ-2r#G}60F'n)t8DJx|_GU\C1Y`kקz&p=a4R,RyX5nҮ\k8~4y&TCckCOr(()c],K%qv5"r3K7~XǣHP Fmx>ࠍh**BL\cƜyĀ@J|i}'we :Ygm B  AM bYcazc}$EY񘙖`:[kYUEUX5Cɸ"nZQ>8M>0ȕrXBTK (xپ/XP6&IlPVjYPz3ğF5A-_̩Xr8)TV$XFB0+"DX,R,F+  X(EHVH E(E`P(*0%* z?.]oI TIDE##"b+.J,Y VUdB #   T@}( Dh-Abb,Q XPZXE) U@-[hEI,#%5m ʔa"$RFM(,"$` `# ȁ rHPYor7}/Cg(Q)U *Oem1pU1xkݴ_ĝgssNw?A'@q`V$Md۷n}tc&ݫY=Ep#&X"#ZֹȏpeD)$!t!A (QJ$PI{m>:VG~ZLL렔FPX:gWKx1@_l D""Y ʃïfc@lݣf-SFmZ6k۷l6ڂd퓕PO$ꪪJϢB)HӧN[v:tbǎƛM@5C,tMFdMq&\S6KfF Im1 ϟN"kvKVziӢ/Ѣ^x$kIACYUUUUTNӧNfϛ>|X\wAPUJ%T*P$ UUUUrer)e͘ugb{|~O_w}QI$G|61c1%Y=:gАSF>|><Ϟ<|>ȇm$FP3E1 " t\'DPӣ6ϟF5A$H(I2 Yȃ^z!N:Eqi&4jӦ5qqx 9])$N4TMNMJ4ǣ&SiӧMXYux]$UUUUU+3f˛Br%Ѡh1h|͓FK!}kx,"80F2$kZֵkZֱUݻv趍vfmկo~[STֈ&5e׭ 3ΪU5ׯ Q'۷lvwn.:a~ZIC $N:44 Dks:$D2ɮjr6d kQ2RJ8qZH!'!ʄEXE=0PDQA܎0pdI-̆O%vmM/Z18eoѿOO'2g. @f͛4STh<9@DI򌹹yo6qݻ>xrSO'%|kdB k"""&I؃V:jԀ Z_Nm93g͗67dŧAq8$:uG* 6lݻy6>w p;ͫf(n\4rUd )Anc^z)n}yuOӳ^UJ^@$@$@@=eJ MMdիfp7߽Ҝ{ٿ~ÇGWjT~>>D  p8D 5$}<[p cN8d&.-nE;qp=;́R#ŽD@B $,(I1@d`~͑EZ$xp::y/'.x3oɯ%v\/v>Os{BZjǧF-:fՆ;ry^a H@UUUUUs >|=l^ld- tFNOӪQXɏ hџV]ܸkesJ " B{fPz=wsoޫZ#7 S~91/ųg 8p6S'0R&L|}릜ƔAOJ % >?,|wqY qNM:yfǻܼ9x`U" Mqq;n۷ 7iٯN{wl׻n7R 5Eܚtϟ>|~|-ߣ6Ѳz"1:fէNnnz <6lٯgNݫݻn|'(A5DJF4h3~|g˟G&z$JgӡF7dŋN}91h˟>>0QDG$ P7>xPI$q.\l߆AvL,u((~ߨl~>ldXhHӌ -$ 7fA#œώs3ϟ.}h'V@nAA!9L"aVQ&|:8BuKv2dϻ&}fۺv2"n9' 8VM6qvu[whN].vۢMrǦP>fϟ>w.$vxZ-?R V,1ǏuUQL NA(F8#a|2dUFLd,\2ˌ Ǫ1]qGXQN\^lb.ɣ;9I$Kmkc1c5kzխ bG.VͫVtDL|#w\$I'V͛6٨ z5u_>M3g3Ƃ!\Qo K '@y$tVi4#N:hϚէVL&̹cA0"0i4G$NkiӧHӳ5V]zի6>|un!4A(#Af Vkמ4[n}ZăuCs@~e˘f 00~3W&LpA{+ۃcظ険 gw4h >j$ٳт  e 2d&LrK0-se @2 FZ{6!A6_$BA8nv00F0 &Bj iUM%:H3 @/wmHV۸>w /DL+=B'P+UG P53gr|]V q嬥rUWj)Ul$UV33ԂTX~g7 |L -ADPiCC(qee+XWi廗yC{#rInLwwI.I%Oh=kZԒ`˻LwwI.I0eI& $wy$͌#d!( $OBpIAu]jI0eI& $wy$ff]peܼLwwI.I0emu^xvHb(ÚñF#no1͐v[qHSA.>/m/(M11b FHT 0QX"2$" dH(1" 1lPY+ ,HF0$b""@HA Bb"B2,,,K McBD(Ȁ(V-ddTYd! iI DI JRidJXRJPX'3jWWJMIIvRʭP/7ÐQcDl4=i$$d = ȒJ9Ck Ȟݙa\L2 !ĆDbl"abw3?w>sm>r13W=45wb ϻ4D@p3a]:!Cꪪߙ|, .|^+XB#in1,"',jm`96';CB)/| L $PAx/!$6 *yem>G|" "TJE*Ec iRI$I fI$JI5lmmmmm*RmI/>u$3.s_ªl -ڭJ8,ܽ|. /y`ZBDDDDDZok#Wgr ń{'PoJrtf~77x0|~~o{t[<~WO°[Y?/2ݔNv~O~zsL'g4}Y?srU.&A:]n(8x߲_=wdv}N¯^zzzmlyǟ><]yPnξ;ʭQE^z>sv۷6j} n}͛=2dɓ'_/I$I$I$I$Io~}NWy$:::yYOOOOO??OGgf^|EZjݝvۛ5[|}nvvvlٓ&L2y:$I$I$I$I$[߯GGg+fvI$2tttvYa쿧FZtK/f>~xVZ]~~~~~nMv͚>Ʒ{{;;;6lɓ&L9OQ$I$I$I$ $Yݫw??o+|~9$N~~_vvvbӧ^]ٓ(ׯ^wv;nݻsfo͛;2dɓ&NaI$I$I$I$I$g]?q&,]:7`2k䰆)$I$H$Jl$1M~?aX, `X,CB "-uPҒII!Psh Zljifm{%J=N e[,'3%Ȇd`QE0X, `A 0X,OU`,2 (D 4 if (!is.character(x)) x <- as.character(x) stopifnot( is.character(x), is_count(size), size >= 1 && size <= 4 ) hashes <- lapply(x, hash_emoji1, size = size) emojis <- lapply(hashes, "[[", "emoji") names <- lapply(hashes, "[[", "names") data.frame( stringsAsFactors = FALSE, hash = vapply(emojis, hash_collapse, character(1)), emojis = I(emojis), text = vapply(names, hash_collapse, character(1), sep = ", "), names = I(names) ) } hash_collapse <- function(x, sep = "") { if (anyNA(x)) { NA_character_ } else { paste(x, collapse = sep) } } hash_emoji1 <- function(x, size = 3) { if (is.na(x)) { return(list( emoji = rep(NA_character_, size), names = rep(NA_character_, size) )) } md5 <- hash_md5(x) hash_emoji1_transform(md5, size) } hash_emoji1_transform <- function(md5, size) { md513 <- substr(md5, 1, 13) mdint <- as.integer(as.hexmode(strsplit(md513, "", fixed = TRUE)[[1]])) hash <- sum(mdint * 16^(0:12)) base <- nrow(emojis) ehash <- hash %% (base ** size) digits <- integer() while (ehash > 0) { digits <- c(digits, ehash %% base) ehash <- ehash %/% base } digits <- c(digits, rep(0, 10))[1:size] nms <- emojis$name[digits + 1] emo <- emojis$emoji[digits + 1] list( emoji = emo, names = nms ) } #' @export #' @rdname hash_emoji #' @details `hash_raw_emoji()` calculates the emoji hash of the bytes #' of a raw vector. #' #' @return `hash_raw_emoji()` and `hash_obj_emoji()` return a list with #' entries: #' * `hash`: the emoji hash, a string of requested size, #' * `emojis`: the individual emoji characters in a character vector, #' * `text`: text representation of `hash`, comma separated, #' * `names`: names of the emojis, in a character vector. hash_raw_emoji <- function(x, size = 3) { stopifnot(is.raw(x)) md5 <- hash_raw_md5(x) emo <- hash_emoji1_transform(md5, size) list( hash = hash_collapse(emo$emoji), emojis = emo$emoji, text = hash_collapse(emo$emoji, sep = ", "), names = emo$names ) } #' @export #' @rdname hash_emoji #' @param serialize_version Workspace format version to use, see #' [base::serialize()]. #' @details `hash_obj_emoji()` calculates the emoji hash of an R #' object. The object is serialized into a binary vector first. hash_obj_emoji <- function(x, size = 3, serialize_version = 2) { sr <- serialize(x, NULL, version = serialize_version)[-(1:14)] hash_raw_emoji(sr, size = size) } #' Adjective-animal hash #' #' @details #' It uses the first 13 hexadecimal characters (out of the 32) of the MD5 #' hash of the input, and converts them into an adjective-animal form to #' create a human readable hash. #' #' ## Number of possible hash values #' #' ```{r include = FALSE} #' hf <- function(n_adj) { #' format( #' length(gfycat_adjectives) ** n_adj * length(gfycat_animals), #' big.mark = ",", #' scientific = FALSE #' ) #' } #' ``` #' #' `hash_animal()` uses `r length(gfycat_animals)` animal names and #' `r length(gfycat_adjectives)` different adjectives. The number of #' different hashes you can get for different values of `n_adj`: #' #' | `n_adj` | size of the hash table space | #' | ------: | ---------------------------: | #' | 0 | `r hf(0)` | #' | 1 | `r hf(1)` | #' | 2 | `r hf(2)` | #' | 3 | `r hf(3)` | #' #' ## Source #' #' The list of adjectives and animals comes from the ids package, #' and in turn from #' , and #' from `https://gfycat.com` (now gone). #' #' @param x Character vector. `NA` entries will have an `NA` hash. #' @param n_adj Number of adjectives to use. It must be from 0 through 3. #' @return A data frame with columns #' * `hash`: the hash value, a string. #' * `words`: list column with the adjectives and the animal name in a #' character vector. #' #' @family hash functions #' @seealso the ids package for generating random adjective-animal ids #' #' @export #' @examples #' hash_animal(c("foo", "bar")) #' #' # if you increase `n_adj`, the shorter hash is a suffix of the longer: #' hash_animal("cli package", 0)$hash #' hash_animal("cli package", 1)$hash #' hash_animal("cli package", 2)$hash #' hash_animal("cli package", 3)$hash hash_animal <- function(x, n_adj = 2) { if (!is.character(x)) x <- as.character(x) stopifnot( is.character(x), is_count(n_adj), n_adj >= 0 && n_adj <= 3 ) hashes <- lapply(x, hash_animal1, n_adj = n_adj) data.frame( stringsAsFactors = FALSE, hash = vapply(hashes, hash_collapse, character(1), sep = " "), words = I(hashes) ) } hash_animal1 <- function(x, n_adj = 2) { if (is.na(x)) { return(rep(NA_character_, n_adj + 1)) } md5 <- hash_md5(x) hash_animal1_transform(md5, n_adj) } hash_animal1_transform <- function(md5, n_adj) { md513 <- substr(md5, 1, 13) mdint <- as.integer(as.hexmode(strsplit(md513, "", fixed = TRUE)[[1]])) hash <- sum(mdint * 16^(0:12)) len_ani <- length(gfycat_animals) len_adj <- length(gfycat_adjectives) ehash <- hash %% (len_adj ** n_adj * len_ani) digits <- ehash %% len_ani ehash <- ehash %/% len_ani while (ehash > 0) { digits <- c(digits, ehash %% len_adj) ehash <- ehash %/% len_adj } digits <- c(digits, rep(0, 10))[1:(n_adj + 1)] digits <- rev(digits) c( gfycat_adjectives[digits[-length(digits)] + 1], gfycat_animals[digits[length(digits)] + 1] ) } #' @export #' @rdname hash_animal #' @details `hash_raw_animal()` calculates the adjective-animal hash of #' the bytes of a raw vector. #' #' @return `hash_raw_animal()` and `hash_obj_animal()` return a list #' with entries: #' * `hash`: the hash value, a string, #' * `words: the adjectives and the animal name in a character vector. hash_raw_animal <- function(x, n_adj = 2) { stopifnot(is.raw(x)) md5 <- hash_raw_md5(x) hash <- hash_animal1_transform(md5, n_adj) list( hash = hash_collapse(hash, sep = ", "), words = hash ) } #' @export #' @rdname hash_animal #' @param serialize_version Workspace format version to use, see #' [base::serialize()]. #' @details `hash_obj_animal()` calculates the adjective-animal hash of #' an R object. The object is serialized into a binary vector first. hash_obj_animal <- function(x, n_adj = 2, serialize_version = 2) { sr <- serialize(x, NULL, version = serialize_version)[-(1:14)] hash_raw_animal(sr, n_adj = n_adj) } #' xxHash #' #' Extremely fast hash algorithm. #' #' @param x Character vector. If not a character vector, then #' [as.character()] is used to try to coerce it into one. `NA` entries #' will have an `NA` hash. #' @return `hash_xxhash()` returns a character vector of hexadecimal #' xxHash hashes. #' #' @family hash functions #' #' @export #' @examples #' hash_xxhash(c("foo", NA, "bar", "")) hash_xxhash <- function(x) { if (!is.character(x)) x <- as.character(x) na <- is.na(x) x[na] <- NA_character_ x[!na] <- .Call(clic_xxhash, x[!na]) x } #' @export #' @rdname hash_xxhash #' @details `hash_raw_xxhash()` calculates the xxHash hash of the bytes #' of a raw vector. #' @return `hash_raw_xxhash()` returns a character scalar. hash_raw_xxhash <- function(x) { stopifnot(is.raw(x)) .Call(clic_xxhash_raw, x) } #' @export #' @rdname hash_xxhash #' @param serialize_version Workspace format version to use, see #' [base::serialize()]. #' @details `hash_obj_xxhash()` calculates the xxHash hash of an R #' object. The object is serialized into a binary vector first. #' @return `hash_obj_xxhash()` returns a character scalar. hash_obj_xxhash <- function(x, serialize_version = 2) { sr <- serialize(x, NULL, version = serialize_version)[-(1:14)] hash_raw_xxhash(sr) } #' @export #' @rdname hash_xxhash #' @param paths Character vector of file names. #' @details `hash_file_xxhash()` calculates the xxHash hash of one or #' more files. #' #' @return `hash_file_xxhash()` returns a character vector of xxHash #' hashes. hash_file_xxhash <- function(paths) { if (!is.character(paths)) paths <- as.character(paths) paths <- normalizePath(paths, mustWork = FALSE) if (is_windows()) { paths <- enc2utf8(paths) } else { paths <- enc2native(paths) } .Call(clic_xxhash_file, paths) } #' @export #' @rdname hash_xxhash #' @details The `64` functions caculate the 64 bit variant #' of xxHash. Otherwise they work the same. hash_xxhash64 <- function(x) { if (!is.character(x)) x <- as.character(x) na <- is.na(x) x[na] <- NA_character_ x[!na] <- .Call(clic_xxhash64, x[!na]) x } #' @export #' @rdname hash_xxhash hash_raw_xxhash64 <- function(x) { stopifnot(is.raw(x)) .Call(clic_xxhash64_raw, x) } #' @export #' @rdname hash_xxhash hash_obj_xxhash64 <- function(x, serialize_version = 2) { sr <- serialize(x, NULL, version = serialize_version)[-(1:14)] hash_raw_xxhash64(sr) } #' @export #' @rdname hash_xxhash hash_file_xxhash64 <- function(paths) { if (!is.character(paths)) paths <- as.character(paths) paths <- normalizePath(paths, mustWork = FALSE) if (is_windows()) { paths <- enc2utf8(paths) } else { paths <- enc2native(paths) } .Call(clic_xxhash64_file, paths) } cli/R/inline.R0000644000176200001440000002606714752735214012650 0ustar liggesusers if (getRversion() >= "2.15.1") utils::globalVariables("app") inline_generic <- function(app, x, style) { if (is.character(x) && any(grepl("\n", x))) { if (getOption("cli.warn_inline_newlines", FALSE)) { warning("cli replaced newlines within {. ... } with spaces") } x <- gsub_("\n", " ", x, useBytes = TRUE, fixed = TRUE) } before <- call_if_fun(style$before) after <- call_if_fun(style$after) transform <- style$transform if (is.function(transform)) { if (length(formals(transform)) == 1) { x <- transform(x) } else { x <- transform(x, app = app, style = style) } } collapse <- style$collapse if (is.character(collapse)) { x <- paste0(x, collapse = collapse[1]) } if (is.function(collapse)) { x <- collapse(x) } xx <- paste0(before, x, after) fmt <- style$fmt if (!is.null(fmt) && is.function(fmt)) { if (length(formals(fmt)) == 1) { xx <- vcapply(xx, fmt) } else { xx <- vcapply(xx, fmt, app = app, style = style) } } prefix <- call_if_fun(style$prefix) postfix <- call_if_fun(style$postfix) paste0(prefix, xx, postfix) } inline_collapse <- function(x, style = list()) { last <- style[["vec-last"]] %||% style[["vec_last"]] %||% ", and " sep <- style[["vec-sep"]] %||% style[["vec_sep"]] %||% ", " sep2 <- style[["vec-sep2"]] %||% style[["vec_sep2"]] %||% sub("^,", "", last) trunc <- style[["vec-trunc"]] %||% style[["vec_trunc"]] %||% 20L col_style <- style[["vec-trunc-style"]] %||% "both-ends" ansi_collapse( x, sep = sep, sep2 = sep2, last = last, trunc = trunc, style = col_style ) } #' This glue transformer performs the inline styling of cli #' #' The two rules are the following: #' * If `code` is a class expression (i.e. it starts with a dot), #' then we open a `` with the right class and recurse. #' * If `code` is not a class expression (i.e. it does not start with a #' dor), then we collapse vectors. #' #' The rest of the work is about: #' * Making sure that the outside container's non-inherited style is _not_ #' applied to the substitution. E.g. in #' ```r #' cli_h2("This is heading number {n}") #' ``` #' The `before` and `after`, etc. style attributes should not be applied #' to `{n}`. #' * While making sure that the inlide style's non-interited style is #' applied to brace expressions. I.e. in #' ```r #' cli_text("{.fun {x}}") #' ``` #' every element of `x` should be formatted as a function name. #' * Adding extra classes from the `class-map` to the right ``. #' * Adding extra styles from [cli_vec()] to the right ``. #' #' A class expression is a brace expression if it is of the form: #' ``` #' {.class {expr}} #' ``` #' I.e. `{expr}` must be a single glue substitution which is not a class #' expression. These are treated differently internally, because they do #' collapsing, and the styling must be applied before collapsing. For other #' expressions the styling is applied after collapsing. E.g. #' ```r #' cli_text("{.fun {1:3}}") #' #> `1()`, `2()`, and `3()` #' #' cli_text("{.fun f{1}}") #' #> `f1()` #' ``` #' In the first case `.fun` is applied to each element of `1:3`, whereas #' in the second case, the `{1}` (rather trivial) substitution is performed #' first, and then `.fun` is applied to `"f1"`. #' #' See the rest of the comments inline (pun intended). #' #' @param code The text inside the `{...}` glue substitution. #' @param envir Environment with the data to perform the styling. #' The actual substituted values have the form `v`, where `` is #' a number. The rest of the values are metadata. E.g. the app itself is #' added as `envir$app`. #' @return The substituted and styles text, a character scalar. #' #' @noRd inline_transformer <- function(code, envir) { app <- envir$app match <- regexpr(inline_regex(), code, perl = TRUE) has_style <- match != -1 if (has_style) { # styling starts <- attr(match, "capture.start") ends <- starts + attr(match, "capture.length") - 1L captures <- substring(code, starts, ends) funname <- captures[[1]] text <- captures[[2]] id <- clii__container_start(app, "span", class = funname) on.exit(clii__container_end(app, id), add = TRUE) # If we don't have a brace expression, then we add another class-less # `` here, because this will be the one replaced by the pure # substitutions (the other branch of the `if`). This ensures that # (non-inherited) styling will _not_ be applied before collapsing them, # but only to the whole non-brace expression. We don't need to end this # container, because the one above (`id`) will end this one as well. braceexp <- grepl("^[<][^.][^}]*[>]$", text) && count_brace_exp(text, .open = "<", .close = ">") == 1 if (!braceexp) { id2 <- clii__container_start(app, "span", class = NULL) } out <- glue( text, .envir = envir, .transformer = inline_transformer, .open = paste0("<", envir$marker), .close = paste0(envir$marker, ">") ) # If we don't have a brace expression, then (non-inherited) styling was # not applied internally, and we need to apply it now. We also need to # end the dummy class-less `` here, so we use the original styled # contained (`id`). if (!braceexp) { clii__container_end(app, id2) style <- app$get_current_style() out <- inline_generic(app, out, style) } out } else { # plain substitution expr <- parse(text = code, keep.source = FALSE) val <- eval(expr, envir = envir) # If we are inside another ``, then we'll "replace" that with a # new one, so we can add extra classes (from `class-map`) and styles # (from [cli_vec()] to it. Replacing means that we look up the right # classes and the id, end the container, and create another one with # the same classes (+ from `class_map`), the same id, and potentially # the styles from [cli_vec()]. # # If we are not inside another ``, then we'll just add a # class-less span, so that the non-inherited styles (e.g. `before`) are # not used before collapsing. node <- utils::tail(app$doc, 1)[[1]] if (node$tag == "span") { class <- node$class id <- node$id clii__container_end(app, id = node$id) } else { class <- NULL id <- NULL } rcls <- class(val) stls <- app$get_current_style()$`class-map` cls <- na.omit(match(rcls, names(stls)))[1] if (!is.na(cls)) class <- c(class, stls[[cls]]) vec_style <- attr(val, "cli_style") tid <- if (!is.null(vec_style)) { app$add_theme(list(span = vec_style)) } id <- clii__container_start( app, "span", id = id, class = paste(class, collapse = " "), theme = tid ) # We don't need to end the replacement container, that happens upstream. if (node$tag != "span") { on.exit(clii__container_end(app, id), add = TRUE) } style <- app$get_current_style() inline_collapse( inline_generic(app, val, style = style), style = style ) } } clii__inline <- function(app, text, .list) { ## Inject that app, so we can style texts <- c(if (!is.null(text)) list(text), .list) out <- lapply(texts, function(t) { t$values$app <- app glue( t$str, .envir = t$values, .transformer = inline_transformer, .open = paste0("<", t$values$marker), .close = paste0(t$values$marker, ">"), .trim = FALSE ) }) paste(out, collapse = "") } inline_regex <- function() "(?s)^[.]([-[:alnum:]_]+)[[:space:]]+(.*)" make_cmd_transformer <- function(values, .call = NULL) { values$marker <- random_id() values$qty <- NA_integer_ values$num_subst <- 0L values$postprocess <- FALSE values$pmarkers <- list() # These are common because of purrr's default argument names, so we # hardcode them es exceptions. They are in packages # crossmap, crosstable, rstudio.prefs, rxode2, starter. # rxode2 has the other ones, and we should fix that in rxode2 # the function calls are in the oolong packagee, need to fix this as well. exceptions <- c( ".x", ".y", ".", ".md", ".met", ".med", ".mul", ".muR", ".dir", ".muU", ".sym_flip(bool_word)", ".sym_flip(bool_topic)", ".sym_flip(bool_wsi)" ) # it is not easy to do better than this, we would need to pass a call # down from the exported functions caller <- .call %||% sys.call(-1) function(code, envir) { first_char <- substr(code, 1, 1) # {?} pluralization if (first_char == "?") { parse_plural(code, values) # {.} cli style } else if (first_char == "." && ! code %in% exceptions) { m <- regexpr(inline_regex(), code, perl = TRUE) has_match <- m != -1 if (!has_match) { throw(cli_error( call. = caller, "Invalid cli literal: {.code {{{abbrev(code, 10)}}}} starts with a dot.", "i" = "Interpreted literals must not start with a dot in cli >= 3.4.0.", "i" = paste("{.code {{}}} expressions starting with a dot are", "now only used for cli styles."), "i" = paste("To avoid this error, put a space character after", "the starting {.code {'{'}} or use parentheses:", "{.code {{({abbrev(code, 10)})}}}.") )) } starts <- attr(m, "capture.start") ends <- starts + attr(m, "capture.length") - 1L captures <- substring(code, starts, ends) funname <- captures[[1]] text <- captures[[2]] out <- glue( text, .envir = envir, .transformer = sys.function(), .cli = TRUE ) paste0("<", values$marker, ".", funname, " ", out, values$marker, ">") # {} plain substitution } else { expr <- parse(text = code, keep.source = FALSE) %??% cli_error( call. = caller, "Could not parse cli {.code {{}}} expression: {.code {abbrev(code, 20)}}." ) res <- eval(expr, envir = envir) %??% cli_error( call. = caller, "Could not evaluate cli {.code {{}}} expression: {.code {abbrev(code, 20)}}." ) id <- paste0("v", length(values)) values[[id]] <- res values$qty <- if (length(res) == 0) 0 else res values$num_subst <- values$num_subst + 1L paste0("<", values$marker, id, values$marker, ">") } } } glue_cmd <- function(..., .envir, .call = sys.call(-1), .trim = TRUE) { str <- paste0(unlist(list(...), use.names = FALSE), collapse = "") values <- new.env(parent = emptyenv()) transformer <- make_cmd_transformer(values, .call = .call) pstr <- glue( str, .envir = .envir, .transformer = transformer, .cli = TRUE, .trim = .trim ) glue_delay( str = post_process_plurals(pstr, values), values = values ) } glue_no_cmd <- function(...) { str <- paste0(unlist(list(...), use.names = FALSE), collapse = "") values <-new.env(parent = emptyenv()) glue_delay( str = str, values = values ) } glue_delay <- function(str, values = NULL) { structure( list(str = str, values = values), class = "cli_glue_delay" ) } cli/R/progress-server.R0000644000176200001440000002554414752606741014543 0ustar liggesusers # ------------------------------------------------------------------------ #' cli progress handlers #' #' The progress handler(s) to use can be selected with global options. #' #' There are three options that specify which handlers will be selected, #' but most of the time you only need to use one of them. You can set these #' options to a character vector, the names of the built-in cli handlers you #' want to use: #' #' * If `cli.progress_handlers_only` is set, then these handlers are used, #' without considering others and without checking if they are able to #' handle a progress bar. This option is mainly intended for testing #' purposes. #' * The handlers named in `cli.progress_handlers` are checked if they are #' able to handle the progress bar, and from the ones that are, the first #' one is selected. This is usually the option that the end use would want #' to set. #' * The handlers named in `cli.progress_handlers_force` are always appended #' to the ones selected via `cli.progress_handlers`. This option is useful #' to add an additional handler, e.g. a logger that writes to a file. #' #' # The built-in progress handlers #' #' ### `cli` #' #' Use cli's internal status bar, the last line of the screen, to show the #' progress bar. This handler is always able to handle all progress bars. #' #' ### `logger` #' #' Log progress updates to the screen, with one line for each update and with #' time stamps. This handler is always able to handle all progress bars. #' #' ### `progressr` #' #' Use the progressr package to create #' progress bars. This handler is always able to handle all progress bars. #' (The progressr package needs to be installed.) #' #' ### `rstudio` #' #' Use [RStudio's job panel](https://posit.co/blog/rstudio-1-2-jobs/) #' to show the progress bars. This handler is available at the RStudio console, #' in recent versions of RStudio. #' #' ### `say` #' #' Use the macOS `say` command to announce progress events in speech (type #' `man say` on a terminal for more info). Set the `cli.progress_say_frequency` #' option to set the minimum delay between `say` invocations, the default is #' three seconds. This handler is available on macOS, if the `say` command is #' on the path. #' #' The external command and its arguments can be configured with options: #' #' * `cli_progress_say_args`: command line arguments, e.g. you can use this #' to select a voice on macOS, #' * `cli_progress_say_command`: external command to run, #' * `cli_progress_say_frequency`: wait at least this many seconds between #' calling the external command. #' #' ### `shiny` #' #' Use [shiny's progress bars](https://shiny.rstudio.com/articles/progress.html). #' This handler is available if a shiny app is running. #' #' @return `cli_progress_builtin_handlers()` returns the names of the #' currently supported progress handlers. #' #' @family progress bar functions #' @export # TODO: examples cli_progress_builtin_handlers <- function() { names(builtin_handlers()) } cli_progress_select_handlers <- function(bar, .envir) { hnd <- getOption("cli.progress_handlers", c("shiny", "cli")) frc <- getOption("cli.progress_handlers_force") onl <- getOption("cli.progress_handlers_only") bin <- builtin_handlers() if (!is.null(onl)) return(bin[onl]) hnd_imp <- bin[hnd] hnd_able <- Filter(function(h) is.null(h$able) || h$able(bar, .envir), hnd_imp) if (length(hnd_able) > 1) hnd_able <- hnd_able[1] c(hnd_able, bin[frc]) } # ------------------------------------------------------------------------ builtin_handler_cli <- list( add = function(bar, .envir) { bar$cli_statusbar <- cli_status( bar$format, msg_done = bar$format_done %||% bar$format, msg_failed = bar$format_failed %||% bar$format, .auto_close = FALSE, .envir = .envir, ) bar$last_shown <- bar$current bar$justadded <- TRUE }, set = function(bar, .envir) { if (isTRUE(bar$justadded)) { bar$justadded <- FALSE return() } bar$last_shown <- bar$current cli_status_update(id = bar$cli_statusbar, bar$format, .envir = .envir) }, complete = function(bar, .envir, result) { if (isTRUE(bar$added)) { if (bar$clear) { # Show the full bar non-dynamic ttys if (!is_dynamic_tty() && !identical(bar$last_shown, bar$current)) { cli_status_update(id = bar$cli_statusbar, bar$format, .envir = .envir) } cli_status_clear(bar$cli_statusbar, result = "clear", .envir = .envir) } else { if (result == "done" && !is.na(bar$total)) bar$current <- bar$total cli_status_clear( bar$cli_statusbar, result = result, msg_done = bar$format_done %||% bar$format, msg_failed = bar$format_failed %||% bar$format, .envir = .envir ) } } bar$cli_statusbar <- TRUE }, output = function(bar, .envir, text) { cli_verbatim(text) } ) # ------------------------------------------------------------------------ builtin_handler_progressr <- list( add = function(bar, .envir) { steps <- if (is.na(bar$total)) 0 else bar$total bar$progressr_progressor <- asNamespace("progressr")$progressor( steps, auto_finish = FALSE, on_exit = TRUE, envir = .envir, label = bar$name %||% NA_character_ ) }, set = function(bar, .envir) { if (!is.null(bar$progressr_progressor)) { bar$progressr_progressor(step = bar$current) } }, complete = function(bar, .envir, result) { if (!is.null(bar$progressr_progressor)) { bar$progressr_progressor(step = bar$current, type = "finish") } }, output = function(bar, .envir, text) { if (!is.null(bar$progressr_progressor)) { bar$progressr_progressor(message = text, class = "sticky", amount = 0) } } ) # ------------------------------------------------------------------------ logger_out <- function(bar, event) { cat(sep = "", format_iso_8601(Sys.time()), " ", bar$id, " ", bar$current, "/", bar$total, " ", event, "\n") } builtin_handler_logger <- list( create = function(bar, .envir) { logger_out(bar, "created") }, add = function(bar, .envir) { logger_out(bar, "added") }, set = function(bar, .envir) { logger_out(bar, "updated") }, complete = function(bar, .envir, result) { logger_out(bar, paste0("terminated (", result, ")")) }, output = function(bar, .envir, text) { logger_out(bar, text) } ) # ------------------------------------------------------------------------ say_out <- function(text) { say <- getOption("cli.progress_say_command", "say") args <- getOption("cli.progress_say_args", character()) processx::process$new(say, c(args, text)) } say_update <- function(bar) { now <- .Call(clic_get_time) freq <- getOption("cli.progress_say_frequency", 3.0) if (is.null(bar$say_last) || now - bar$say_last > freq) { txt <- if (is.na(bar$total)) bar$current else cli__pb_percent(bar) bar$say_proc <- say_out(txt) bar$say_last <- now } } builtin_handler_say <- list( able = function(bar, .envir) { if (!is.null(getOption("cli.progress_say_command"))) return(TRUE) Sys.info()[["sysname"]] == "Darwin" && Sys.which("say") != "" }, add = function(bar, .envir) { ## Nothing to do here }, set = function(bar, .envir) { say_update(bar) }, complete = function(bar, .envir, result) { if (!is.null(bar$say_proc)) { bar$say_proc$kill() say_out("done") } } ) # ------------------------------------------------------------------------ builtin_handler_rstudio <- list( able = function(bar, .envir) { tryCatch( .Platform$GUI == "Rstudio" && rstudioapi::isAvailable(), error = function(err) FALSE ) }, add = function(bar, .envir) { total <- if (is.na(bar$total)) 0L else as.integer(bar$total) bar$status <- bar$status %||% "" rstudio_id <- rstudioapi::jobAdd( name = bar$name %||% "", status = bar$status, progressUnits = total, running = TRUE, show = FALSE ) # so the name is not duplicated in the format string as well if (is.na(bar$total)) bar$name <- NULL bar$rstudio_id <- rstudio_id bar$rstudio_status <- bar$status }, set = function(bar, .envir) { if (!is.na(bar$total)) { rstudioapi::jobSetProgress(bar$rstudio_id, bar$current) if (bar$rstudio_status != bar$status) { rstudioapi::jobSetStatus(bar$rstudio_id, bar$status) bar$rstudio_status <- bar$status } } else { status <- cli_fmt( cli_text(bar$format, .envir = .envir), collapse = TRUE, strip_newline = TRUE ) rstudioapi::jobSetStatus(bar$rstudio_id, status) } }, complete = function(bar, .envir, results) { if (!is.null(bar$rstudio_id)) { rstudioapi::jobRemove(bar$rstudio_id) } }, output = function(bar, .envir, text) { rstudioapi::jobAddOutput(bar$rstudio_id, text) } ) # ------------------------------------------------------------------------ shiny_detail <- function(bar, .envir) { status <- if (is.null(bar$format_orig)) { bar$status %||% "" } else { cli_fmt( cli_text(bar$format, .envir = .envir), collapse = TRUE, strip_newline = TRUE ) } output <- bar$shiny_output %||% "" paste0( status, if (status != "" && output != "") "\n", output ) } last_lines <- function(txt, keep = 5) { txt <- sub("^\n*", "", txt) txt <- sub("\n*$", "", txt) lines <- strwrap(txt, width = 40) paste(utils::tail(lines, keep), collapse = "\n") } builtin_handler_shiny <- list( able = function(bar, .envir) { "shiny" %in% loadedNamespaces() && asNamespace("shiny")$isRunning() }, add = function(bar, .envir) { bar$shiny_progress <- asNamespace("shiny")$Progress$new( asNamespace("shiny")$getDefaultReactiveDomain(), min = 0, max = bar$total ) bar$shiny_progress$set( message = bar$name %||% "", detail = shiny_detail(bar, .envir) ) }, set = function(bar, .envir) { bar$shiny_progress$set( value = bar$current, detail = shiny_detail(bar, .envir) ) }, complete = function(bar, .envir, results) { if (!is.null(bar$shiny_progress)) { bar$shiny_progress$set( value = bar$current, detail = shiny_detail(bar, .envir) ) bar$shiny_progress$close() } bar$shiny_progress <- NULL }, output = function(bar, .envir, text) { bar$shiny_output <- last_lines(paste0(bar$shiny_output, " \u2022 ", text)) bar$shiny_progress$set( value = bar$current, detail = shiny_detail(bar, .envir) ) } ) # ------------------------------------------------------------------------ builtin_handlers <- function() { list( cli = builtin_handler_cli, logger = builtin_handler_logger, progressr = builtin_handler_progressr, rstudio = builtin_handler_rstudio, say = builtin_handler_say, shiny = builtin_handler_shiny ) } cli/R/cli-package.R0000644000176200001440000000017214557444176013526 0ustar liggesusers#' @aliases cli-package NULL #' @keywords internal "_PACKAGE" ## usethis namespace: start ## usethis namespace: end NULL cli/R/glue.R0000644000176200001440000001714614752735214012324 0ustar liggesusers # Compared to glue::glue(), these are fixed: # - .sep = "" # - .trim = TRUE # - .null = character() # - .literal = TRUE # - .comment = "" # # we also don't allow passing in data as arguments, and `text` is # a single argument, no need to `paste()` etc. glue <- function(text, .envir = parent.frame(), .transformer = identity_transformer, .open = "{", .close = "}", .cli = FALSE, .trim = TRUE) { text <- paste0(text, collapse = "") if (length(text) < 1L) { return(text) } if (is.na(text)) { return(text) } if (.trim) { text <- trim(text) } f <- function(expr) { eval_func <- as.character(.transformer(expr, .envir) %||% character()) } res <- .Call(glue_, text, f, .open, .close, .cli) res <- drop_null(res) if (any(lengths(res) == 0L)) { return(character(0L)) } res[] <- lapply(res, function(x) replace(x, is.na(x), "NA")) do.call(paste0, res) } count_brace_exp <- function(text, .open = "{", .close = "}") { cnt <- 0L trans <- function(text, envir) { cnt <<- cnt + 1L "" } glue(text, .transformer = trans, .open = .open, .close = .close) cnt } identity_transformer <- function(text, envir) { eval(parse(text = text, keep.source = FALSE), envir) } drop_null <- function(x) { x[!vapply(x, is.null, logical(1L))] } #' Collapse a vector into a string scalar #' #' @description #' Features: #' #' - custom separator (`sep`), #' - custom separator for length-two input (`sep2`), #' - custom last separator (`last`), #' - adds ellipsis to truncated strings, #' - uses Unicode ellipsis character on UTF-8 console, #' - can collapse "from both ends", with `style = "both-ends"`, #' - can consider a limit for the display width of the result, in characters, #' - handles ANSI control sequences correctly when measuring display width. #' #' @param x Character vector, or an object with an `as.character()` method #' to collapse. #' @param sep Separator. A character string. #' @param sep2 Separator for the special case that `x` contains only two #' elements. A character string. Defaults to the value of `last` without the #' serial comma. #' @param last Last separator, if there is no truncation. E.g. use #' `", and "` for the [serial #' comma](https://en.wikipedia.org/wiki/Serial_comma). A character string. #' @param trunc Maximum number of elements to show. For `style = "head"` #' at least `trunc = 1` is used. For `style = "both-ends"` at least #' `trunc = 5` is used, even if a smaller number is specified. #' @param width Limit for the display width of the result, in characters. #' This is a hard limit, and the output will never exceed it. #' This argument is not implemented for the `"both-ends"` style, which #' always uses `Inf`, with a warning if a finite `width` value is set. #' @param ellipsis Character string to use at the place of the truncation. #' By default, the Unicode ellipsis character is used if the console is #' UTF-8, and three dots otherwise. #' @param style Truncation style: #' * `both-ends`: the default, shows the beginning and end of the vector, #' and skips elements in the middle if needed. #' * `head`: shows the beginning of the vector, and skips elements at the #' end, if needed. #' @return Character scalar. It is `NA_character_` if any elements in `x` #' are `NA`. #' #' @seealso `glue_collapse` in the glue package inspired this function. #' @export #' @examples #' ansi_collapse(letters) #' #' # truncate #' ansi_collapse(letters, trunc = 5) #' #' # head style #' ansi_collapse(letters, trunc = 5, style = "head") ansi_collapse <- function(x, sep = ", ", sep2 = sub("^,", "", last), last = ", and ", trunc = Inf, width = Inf, ellipsis = symbol$ellipsis, style = c("both-ends", "head")) { style <- match.arg(style) switch( style, "both-ends" = collapse_both_ends( x, sep, sep2, last, trunc, width, ellipsis ), "head" = collapse_head(x, sep, sep2, last, trunc, width, ellipsis) ) } collapse_head_notrim <- function(x, trunc, sep, sep2, last, ellipsis) { lnx <- length(x) if (lnx == 1L) return(x) if (lnx == 2L) return(paste0(x, collapse = sep2)) if (lnx <= trunc) { # no truncation return(paste0( paste(x[1:(lnx - 1L)], collapse = sep), last, x[lnx] )) } else { # truncation, no need for 'last' return(paste0( paste(x[1:trunc], collapse = sep), sep, ellipsis )) } } collapse_head <- function(x, sep, sep2, last, trunc, width, ellipsis) { trunc <- max(trunc, 1L) x <- as.character(x) lnx <- length(x) # special cases that do not need trimming if (lnx == 0L) { return("") } else if (anyNA(x)) { return(NA_character_) } # easier case, no width trimming if (width == Inf) { return(collapse_head_notrim(x, trunc, sep, sep2, last, ellipsis)) } # complex case, with width wrapping # first we truncate tcd <- lnx > trunc if (tcd) x <- x[1:trunc] # then we calculate the width w/o trimming wx <- ansi_nchar(x) wsep <- ansi_nchar(sep, "width") wsep2 <- ansi_nchar(sep2, "width") wlast <- ansi_nchar(last, "width") well <- ansi_nchar(ellipsis, "width") if (!tcd) { # x[1] # x[1] and x[2] # x[1], x[2], and x[3] nsep <- if (lnx > 2L) lnx - 2L else 0L nsep2 <- if (lnx == 2L) 1L else 0L nlast <- if (lnx > 2L) 1L else 0L wtot <- sum(wx) + nsep * wsep + nsep2 * wsep2 + nlast * wlast if (wtot <= width) { if (lnx == 1L) { return(x) } else if (lnx == 2L) { return(paste0(x, collapse = sep2)) } else { return(paste0( paste(x[1:(lnx - 1L)], collapse = sep), last, x[lnx] )) } } } else { # x[1], x[2], x[trunc], ... wtot <- sum(wx) + trunc * wsep + well if (wtot <= width) { return(paste0( paste(x, collapse = sep), sep, ellipsis )) } } # we need to find the longest possible truncation for the form # x[1], x[2], x[trunc], ... # each item is wx + wsep wide, so we search how many fits, with ellipsis last <- function(x) if (length(x) >= 1L) x[length(x)] else x[NA_integer_] trunc <- last(which(cumsum(wx + wsep) + well <= width)) # not even one element fits if (is.na(trunc)) { if (well > width) { return(ansi_strtrim(ellipsis, width, ellipsis = "")) } else if (well == width) { return(ellipsis) } else if (well + wsep >= width) { return(paste0(ansi_strtrim(x[1L], width, ellipsis = ""), ellipsis)) } else { return(paste0( ansi_strtrim(x[1L], max(width - well - wsep, 0L), ellipsis = ellipsis), sep, ellipsis )) } } return(paste0( paste(x[1:trunc], collapse = sep), sep, ellipsis )) } collapse_both_ends <- function(x, sep, sep2, last, trunc, width, ellipsis) { if (width != Inf) { warning(format_warning(c( "!" = "finite {.arg width} is not implemented in {.fun cli::ansi_collapse}.", "i" = "{.code width = Inf} is used instead." ))) width <- Inf } # we always list at least 5 elements trunc <- max(trunc, 5L) trunc <- min(trunc, length(x)) if (length(x) <= 5L || length(x) <= trunc) { return(collapse_head(x, sep, sep2, last, trunc = trunc, width, ellipsis)) } # we have at least six elements in the vector # 1, 2, 3, ..., 9, and 10 x <- as.character(c(x[1:(trunc - 2L)], x[length(x) - 1L], x[length(x)])) paste0( c(x[1:(trunc - 2L)], ellipsis, paste0(x[trunc - 1L], last, x[trunc])), collapse = sep ) } trim <- function(x) { has_newline <- function(x) any(grepl("\\n", x)) if (length(x) == 0L || !has_newline(x)) { return(x) } .Call(trim_, x) } cli/R/status-bar.R0000644000176200001440000003567114557444176013467 0ustar liggesusers #' Update the status bar (superseded) #' #' @description #' **The `cli_status_*()` functions are superseded by #' the [cli_progress_message()] and [cli_progress_step()] functions, #' because they have a better default behavior.** #' #' The status bar is the last line of the terminal. cli apps can use this #' to show status information, progress bars, etc. The status bar is kept #' intact by all semantic cli output. #' #' @details #' Use [cli_status_clear()] to clear the status bar. #' #' Often status messages are associated with processes. E.g. the app starts #' downloading a large file, so it sets the status bar accordingly. Once the #' download is done (or has failed), the app typically updates the status bar #' again. cli automates much of this, via the `msg_done`, `msg_failed`, and #' `.auto_result` arguments. See examples below. #' #' @param msg The text to show, a character vector. It will be #' collapsed into a single string, and the first line is kept and cut to #' [console_width()]. The message is often associated with the start of #' a calculation. #' @param msg_done The message to use when the message is cleared, when #' the calculation finishes successfully. If `.auto_close` is `TRUE` #' and `.auto_result` is `"done"`, then this is printed automatically #' when the calling function (or `.envir`) finishes. #' @param msg_failed The message to use when the message is cleared, when #' the calculation finishes unsuccessfully. If `.auto_close` is `TRUE` #' and `.auto_result` is `"failed"`, then this is printed automatically #' when the calling function (or `.envir`) finishes. #' @param .keep What to do when this status bar is cleared. If `TRUE` then #' the content of this status bar is kept, as regular cli output (the #' screen is scrolled up if needed). If `FALSE`, then this status bar #' is deleted. #' @param .auto_close Whether to clear the status bar when the calling #' function finishes (or `.envir` is removed from the stack, if #' specified). #' @param .envir Environment to evaluate the glue expressions in. It is #' also used to auto-clear the status bar if `.auto_close` is `TRUE`. #' @param .auto_result What to do when auto-closing the status bar. #' @return The id of the new status bar container element, invisibly. #' #' @seealso Status bars support [inline markup][inline-markup]. #' @seealso The [cli_progress_message()] and [cli_progress_step()] #' functions, for a superior API. #' @family status bar #' @family functions supporting inline markup #' @export cli_status <- function(msg, msg_done = paste(msg, "... done"), msg_failed = paste(msg, "... failed"), .keep = FALSE, .auto_close = TRUE, .envir = parent.frame(), .auto_result = c("clear", "done", "failed", "auto")) { id <- new_uuid() cli__message( "status", list( id = id, msg = glue_cmd(msg, .envir = .envir), msg_done = glue_cmd(msg_done, .envir = .envir), msg_failed = glue_cmd(msg_failed, .envir = .envir), keep = .keep, auto_result = match.arg(.auto_result), globalenv = identical(.envir, .GlobalEnv) ), .auto_close = .auto_close, .envir = .envir ) invisible(id) } #' Clear the status bar (superseded) #' #' @description #' **The `cli_status_*()` functions are superseded by #' the [cli_progress_message()] and [cli_progress_step()] functions, #' because they have a better default behavior.** #' #' Clear the status bar #' #' @param id Id of the status bar container to clear. If `id` is not the id #' of the current status bar (because it was overwritten by another #' status bar container), then the status bar is not cleared. If `NULL` #' (the default) then the status bar is always cleared. #' @param result Whether to show a message for success or failure or just #' clear the status bar. #' @param msg_done If not `NULL`, then the message to use for successful #' process termination. This overrides the message given when the status #' bar was created. #' @param msg_failed If not `NULL`, then the message to use for failed #' process termination. This overrides the message give when the status #' bar was created. #' @inheritParams cli_status #' #' @family status bar #' @seealso The [cli_progress_message()] and [cli_progress_step()] #' functions, for a superior API. #' @export cli_status_clear <- function(id = NULL, result = c("clear", "done", "failed"), msg_done = NULL, msg_failed = NULL, .envir = parent.frame()) { cli__message( "status_clear", list( id = id %||% NA_character_, result = match.arg(result[1], c("clear", "done", "failed", "auto")), msg_done = if (!is.null(msg_done)) glue_cmd(msg_done, .envir = .envir), msg_failed = if (!is.null(msg_failed)) glue_cmd(msg_failed, .envir = .envir) ) ) } #' Update the status bar (superseded) #' #' @description #' **The `cli_status_*()` functions are superseded by #' the [cli_progress_message()] and [cli_progress_step()] functions, #' because they have a better default behavior.** #' #' Update the status bar #' #' @param msg Text to update the status bar with. `NULL` if you don't want #' to change it. #' @param msg_done Updated "done" message. `NULL` if you don't want to #' change it. #' @param msg_failed Updated "failed" message. `NULL` if you don't want to #' change it. #' @param id Id of the status bar to update. Defaults to the current #' status bar container. #' @param .envir Environment to evaluate the glue expressions in. #' @return Id of the status bar container. #' #' @seealso This function supports [inline markup][inline-markup]. #' @seealso The [cli_progress_message()] and [cli_progress_step()] #' functions, for a superior API. #' @family status bar #' @family functions supporting inline markup #' @export cli_status_update <- function(id = NULL, msg = NULL, msg_done = NULL, msg_failed = NULL, .envir = parent.frame()) { cli__message( "status_update", list( msg = if (!is.null(msg)) glue_cmd(msg, .envir = .envir), msg_done = if (!is.null(msg_done)) glue_cmd(msg_done, .envir = .envir), msg_failed = if (!is.null(msg_failed)) glue_cmd(msg_failed, .envir = .envir), id = id %||% NA_character_ ) ) } #' Indicate the start and termination of some computation in the status bar #' (superseded) #' #' @description #' **The `cli_process_*()` functions are superseded by #' the [cli_progress_message()] and [cli_progress_step()] functions, #' because they have a better default behavior.** #' #' Typically you call `cli_process_start()` to start the process, and then #' `cli_process_done()` when it is done. If an error happens before #' `cli_process_done()` is called, then cli automatically shows the message #' for unsuccessful termination. #' #' @details #' If you handle the errors of the process or computation, then you can do #' the opposite: call `cli_process_start()` with `on_exit = "done"`, and #' in the error handler call `cli_process_failed()`. cli will automatically #' call `cli_process_done()` on successful termination, when the calling #' function finishes. #' #' See examples below. #' #' @param msg The message to show to indicate the start of the process or #' computation. It will be collapsed into a single string, and the first #' line is kept and cut to [console_width()]. #' @param msg_done The message to use for successful termination. #' @param msg_failed The message to use for unsuccessful termination. #' @param on_exit Whether this process should fail or terminate #' successfully when the calling function (or the environment in `.envir`) #' exits. #' @param msg_class The style class to add to the message. Use an empty #' string to suppress styling. #' @param done_class The style class to add to the successful termination #' message. Use an empty string to suppress styling.a #' @param failed_class The style class to add to the unsuccessful #' termination message. Use an empty string to suppress styling.a #' @inheritParams cli_status #' @return Id of the status bar container. #' #' @seealso This function supports [inline markup][inline-markup]. #' @seealso The [cli_progress_message()] and [cli_progress_step()] #' functions, for a superior API. #' @family status bar #' @family functions supporting inline markup #' @export #' @examples #' #' ## Failure by default #' fun <- function() { #' cli_process_start("Calculating") #' if (interactive()) Sys.sleep(1) #' if (runif(1) < 0.5) stop("Failed") #' cli_process_done() #' } #' tryCatch(fun(), error = function(err) err) #' #' ## Success by default #' fun2 <- function() { #' cli_process_start("Calculating", on_exit = "done") #' tryCatch({ #' if (interactive()) Sys.sleep(1) #' if (runif(1) < 0.5) stop("Failed") #' }, error = function(err) cli_process_failed()) #' } #' fun2() cli_process_start <- function(msg, msg_done = paste(msg, "... done"), msg_failed = paste(msg, "... failed"), on_exit = c("auto", "failed", "done"), msg_class = "alert-info", done_class = "alert-success", failed_class = "alert-danger", .auto_close = TRUE, .envir = parent.frame()) { # Force the defaults, because we might modify msg msg_done msg_failed if (length(msg_class) > 0 && msg_class != "") { msg <- paste0("{.", msg_class, " ", msg, "}") } if (length(done_class) > 0 && done_class != "") { msg_done <- paste0("{.", done_class, " ", msg_done, "}") } if (length(failed_class) > 0 && failed_class != "") { msg_failed <- paste0("{.", failed_class, " ", msg_failed, "}") } cli_status(msg, msg_done, msg_failed, .auto_close = .auto_close, .envir = .envir, .auto_result = match.arg(on_exit)) } #' @param id Id of the status bar container to clear. If `id` is not the id #' of the current status bar (because it was overwritten by another #' status bar container), then the status bar is not cleared. If `NULL` #' (the default) then the status bar is always cleared. #' #' @rdname cli_process_start #' @export cli_process_done <- function(id = NULL, msg_done = NULL, .envir = parent.frame(), done_class = "alert-success") { if (!is.null(msg_done) && length(done_class) > 0 && done_class != "") { msg_done <- paste0("{.", done_class, " ", msg_done, "}") } cli_status_clear(id, result = "done", msg_done = msg_done, .envir = .envir) } #' @rdname cli_process_start #' @export cli_process_failed <- function(id = NULL, msg = NULL, msg_failed = NULL, .envir = parent.frame(), failed_class = "alert-danger") { if (!is.null(msg_failed) && length(failed_class) > 0 && failed_class != "") { msg_failed <- paste0("{.", failed_class, " ", msg_failed, "}") } cli_status_clear( id, result = "failed", msg_failed = msg_failed, .envir = .envir ) } # ----------------------------------------------------------------------- clii_status <- function(app, id, msg, msg_done, msg_failed, keep, auto_result, globalenv) { app$status_bar[[id]] <- list( content = "", msg_done = msg_done, msg_failed = msg_failed, keep = keep, auto_result = auto_result ) if (isTRUE(getOption("cli.hide_cursor", TRUE)) && !isTRUE(globalenv)) { ansi_hide_cursor(app$output) } clii_status_update(app, id, msg, msg_done = NULL, msg_failed = NULL) } clii_status_clear <- function(app, id, result, msg_done, msg_failed) { ## If NA then the most recent one if (is.na(id)) id <- names(app$status_bar)[1] ## If no active status bar, then ignore if (is.null(id) || is.na(id)) return(invisible()) if (! id %in% names(app$status_bar)) return(invisible()) if (result == "auto") { r1 <- random_marker if (identical(returnValue(r1), r1)) { result <- "failed" } else { result <- "done" } } if (result == "done") { msg <- msg_done %||% app$status_bar[[id]]$msg_done clii_status_update(app, id, msg, NULL, NULL) app$status_bar[[id]]$keep <- TRUE } else if (result == "failed") { msg <- msg_failed %||% app$status_bar[[id]]$msg_failed clii_status_update(app, id, msg, NULL, NULL) app$status_bar[[id]]$keep <- TRUE } if (names(app$status_bar)[1] == id) { ## This is the active one if (app$status_bar[[id]]$keep) { ## Keep? Just emit it app$cat("\n") } else { ## Not keep? Remove it clii__clear_status_bar(app) } if (isTRUE(getOption("cli.hide_cursor", TRUE))) { ansi_show_cursor(app$output) } } else { if (app$status_bar[[id]]$keep) { ## Keep? clii__clear_status_bar(app) app$cat(paste0(app$status_bar[[id]]$content, "\n")) app$cat(paste0(app$status_bar[[1]]$content, "\r")) } else { ## Not keep? Nothing to output } } ## Remove app$status_bar[[id]] <- NULL ## Switch to the previous one if (length(app$status_bar)) { app$cat(paste0(app$status_bar[[1]]$content, "\r")) } } clii_status_update <- function(app, id, msg, msg_done, msg_failed) { ## If NA then the most recent one if (is.na(id)) id <- names(app$status_bar)[1] ## If no active status bar, then ignore if (is.na(id)) return(invisible()) ## Update messages if (!is.null(msg_done)) app$status_bar[[id]]$msg_done <- msg_done if (!is.null(msg_failed)) app$status_bar[[id]]$msg_failed <- msg_failed ## Do we have a new message? if (is.null(msg)) return(invisible()) ## Do we need to clear the current content? current <- paste0("", app$status_bar[[1]]$content) ## Format the line content <- "" fmsg <- app$inline(msg) cfmsg <- ansi_strtrim(fmsg, width = app$get_width()) content <- strsplit(cfmsg, "\r?\n")[[1]][1] if (is.na(content)) content <- "" ## Update status bar, put it in front app$status_bar[[id]]$content <- content app$status_bar <- c( app$status_bar[id], app$status_bar[setdiff(names(app$status_bar), id)]) ## New content, if it is an ANSI terminal we'll overwrite and clear ## until the end of the line. Otherwise we add some space characters ## to the content to make sure we clear up residual content. output <- get_real_output(app$output) if (is_ansi_tty(output)) { app$cat(paste0("\r", content, ANSI_EL, "\r")) } else if (is_dynamic_tty(output)) { nsp <- max(ansi_nchar(current) - ansi_nchar(content), 0) app$cat(paste0("\r", content, strrep(" ", nsp), "\r")) } else { app$cat(paste0(content, "\n")) } ## Reset timer .Call(clic_tick_reset) invisible() } clii__clear_status_bar <- function(app) { output <- get_real_output(app$output) if (is_ansi_tty(output)) { app$cat(paste0("\r", ANSI_EL)) } else if (is_dynamic_tty(output)) { text <- app$status_bar[[1]]$content len <- ansi_nchar(text, type = "width") app$cat(paste0("\r", strrep(" ", len + rstudio_r_fix), "\r")) } } cli/R/internals.R0000644000176200001440000000710014752735214013354 0ustar liggesusers call_if_fun <- function(x) { if (is.function(x)) x() else x } clii__xtext <- function(app, text, .list, indent, padding, ln = TRUE, wrap = TRUE) { style <- app$get_current_style() text <- app$inline(text, .list = .list) exdent <- style$`text-exdent` %||% 0L esc <- function(x) gsub(" ", "\u00a0", x, fixed = TRUE) bef <- call_if_fun(style$before) if (!is.null(bef)) text[1] <- paste0(esc(bef), text[1]) aft <- call_if_fun(style$after) if (!is.null(aft)) text[length(text)] <- paste0(text[length(text)], esc(aft)) if (!is.null(style$fmt)) text <- style$fmt(text) if (wrap) { text <- ansi_strwrap( text, exdent = exdent, width = app$get_width(extra = padding) ) } else { text <- ansi_simplify(text) } app$cat_ln(text, indent = indent, padding) invisible(app) } clii__get_width <- function(app, extra) { style <- app$get_current_style() left <- style$`margin-left` %||% 0 + style$`padding-left` %||% 0 right <- style$`margin-right` %||% 0 + style$`padding-right` %||% 0 console_width() - left - right - extra } clii__cat <- function(app, lines) { clii__message(lines, appendLF = FALSE, output = app$output, signal = app$signal) } clii__cat_ln <- function(app, lines, indent, padding) { if (!is.null(item <- app$state$delayed_item)) { app$state$delayed_item <- NULL return(app$item_text(item$type, NULL, item$cnt_id, .list = lines)) } style <- app$get_current_style() ## left margin left <- padding + (style$`margin-left` %||% 0) + (style$`padding-left` %||% 0) if (length(lines) && left) lines <- paste0(strrep(" ", left), lines) ## indent or negative indent if (length(lines)) { if (indent < 0) { lines[1] <- dedent(lines[1], - indent) } else if (indent > 0) { lines[1] <- paste0(strrep(" ", indent), lines[1]) } } ## zero out margin app$margin <- 0 signal <- !identical(app$signal, FALSE) if (signal && length(app$status_bar)) clii__clear_status_bar(app) app$cat(paste0(paste0(lines, "\n"), collapse = "")) if (signal && length(app$status_bar)) { app$cat(paste0(app$status_bar[[1]]$content, "\r")) } } clii__vspace <- function(app, n) { if (app$margin < n) { sp <- strrep("\n", n - app$margin) signal <- !identical(app$signal, FALSE) if (signal && length(app$status_bar)) clii__clear_status_bar(app) clii__message(sp, appendLF = FALSE, output = app$output, signal = app$signal) app$margin <- n if (signal && length(app$status_bar)) { app$cat(paste0(app$status_bar[[1]]$content, "\r")) } } } get_real_output <- function(output) { if (! inherits(output, "connection")) { output <- switch( output, "auto" = cli_output_connection(), "message" = , "stderr" = stderr(), "stdout" = stdout() ) } output } clii__message <- function(..., domain = NA, appendLF = TRUE, output = stderr(), signal = TRUE) { msg <- .makeMessage(..., domain = domain, appendLF = appendLF) output <- get_real_output(output) # to avoid non-breaking spaces in files, if output is redirected msg <- gsub("\u00a0", " ", msg, fixed = TRUE) if (identical(signal, FALSE)) { safe_cat0(msg, file = output) } else { withRestarts(muffleMessage = function() NULL, { cond <- simpleMessage(msg) class(cond) <- c("cliMessage", class(cond)) signalCondition(cond) safe_cat0(msg, file = output) }) } } safe_cat0 <- function(x, file) { if (inherits(file, "rawConnection")) { x <- enc2utf8(x) writeBin(charToRaw(x), file) } else { cat(x, file = file, sep = "") } } cli/R/friendly-type.R0000644000176200001440000000765514564611102014155 0ustar liggesusers # This is based on rlang:::obj_type_friendly, but adapted to cli friendly_type <- local({ friendly_type <- function(x, value = TRUE, length = FALSE) { if (is_missing(x)) { return("absent") } if (is.object(x)) { if (inherits(x, "quosure")) { return("a {.cls quosure} object") } else if (identical(class(x), "data.frame")) { return("a data frame") } else if (identical(class(x), c("tbl_df", "tbl", "data.frame"))) { return("a tibble") } else { # this is sometimes wrong for 'h', but ce la vie fst <- tolower(substr(class(x)[1], 1, 1)) prop <- if (fst %in% c("a", "e", "i", "o", "u")) { "an" } else { "a" } return(paste0(prop, " {.cls {class(x)[1]}} object")) } } if (!is_vector(x)) { return(as_friendly_type(typeof(x))) } n_dim <- length(dim(x)) if (value && !n_dim) { if (is_na(x)) { return(switch( typeof(x), logical = "{.code NA}", integer = "an integer {.code NA}", double = "a numeric {.code NA}", complex = "a complex {.code NA}", character = "a character {.code NA}", typeof(x) )) } if (length(x) == 1 && !is_list(x)) { return(switch( typeof(x), logical = if (x) "{.code TRUE}" else "{.code FALSE}", integer = "an integer", double = "a number", complex = "a complex number", character = if (nzchar(x)) "a string" else "{.code \"\"}", raw = "a raw value", sprintf("a %s value", typeof(x)) )) } if (length(x) == 0) { return(switch( typeof(x), logical = "an empty logical vector", integer = "an empty integer vector", double = "an empty numeric vector", complex = "an empty complex vector", character = "an empty character vector", raw = "an empty raw vector", list = "an empty list", sprintf("a %s of length one", typeof(x)) )) } } type <- friendly_vector_type(typeof(x), n_dim) if (length && !n_dim) { type <- paste0(type, sprintf(" of length %s", length(x))) } type } friendly_vector_type <- function(type, n_dim) { if (type == "list") { if (n_dim < 2) { return("a list") } else if (n_dim == 2) { return("a list matrix") } else { return("a list array") } } type <- switch( type, logical = "a logical %s", integer = "an integer %s", numeric = , double = "a double %s", complex = "a complex %s", character = "a character %s", raw = "a raw %s", type = paste0("a ", type, " %s") ) if (n_dim < 2) { kind <- "vector" } else if (n_dim == 2) { kind <- "matrix" } else { kind <- "array" } sprintf(type, kind) } as_friendly_type <- function(type) { switch( type, list = "a list", NULL = "NULL", environment = "an environment", externalptr = "a pointer", weakref = "a weak reference", S4 = "an S4 object", name = , symbol = "a symbol", language = "a call", pairlist = "a pairlist node", expression = "an expression vector", char = "an internal string", promise = "an internal promise", ... = "an internal dots object", any = "an internal {.code any} object", bytecode = "an internal bytecode object", primitive = , builtin = , special = "a primitive function", closure = "a function", type ) } is_missing <- function(x) { missing(x) || identical(x, quote(expr = )) } is_vector <- function(x) { t <- typeof(x) t %in% c( "logical", "integer", "double", "complex", "character", "raw", "list" ) } is_scalar_vector <- function(x) { is_vector(x) && length(x) == 1L } is_na <- function(x) { is_scalar_vector(x) && is.na(x) } is_list <- function(x) { typeof(x) == "list" } list( .internal = environment(), friendly_type = friendly_type ) }) typename <- friendly_type$friendly_type cli/R/time.R0000644000176200001440000000365514557444176012335 0ustar liggesusers format_time <- local({ parse_ms <- function(ms) { stopifnot(is.numeric(ms)) data.frame( days = floor(ms / 86400000), hours = floor((ms / 3600000) %% 24), minutes = floor((ms / 60000) %% 60), seconds = round((ms / 1000) %% 60, 1) ) } first_positive <- function(x) which(x > 0)[1] trim <- function (x) gsub("^\\s+|\\s+$", "", x) pretty_ms <- function(ms, compact = FALSE) { stopifnot(is.numeric(ms)) parsed <- t(parse_ms(ms)) if (compact) { units <- c("d", "h", "m", "s") parsed2 <- parsed parsed2[] <- paste0(parsed, units) idx <- cbind( apply(parsed, 2, first_positive), seq_len(length(ms)) ) tmp <- paste0("~", parsed2[idx]) # handle NAs tmp[is.na(parsed2[idx])] <- NA_character_ tmp } else { ## Exact for small ones exact <- paste0(ceiling(ms), "ms") exact[is.na(ms)] <- NA_character_ ## Approximate for others, in seconds merge_pieces <- function(pieces) { ## handle NAs if (all(is.na(pieces))) { return(NA_character_) } ## handle non-NAs paste0( if (pieces[1]) paste0(pieces[1], "d "), if (pieces[2]) paste0(pieces[2], "h "), if (pieces[3]) paste0(pieces[3], "m "), if (pieces[4]) paste0(pieces[4], "s ") ) } approx <- trim(apply(parsed, 2, merge_pieces)) ifelse(ms < 1000, exact, approx) } } pretty_sec <- function(sec, compact = FALSE) { pretty_ms(sec * 1000, compact = compact) } pretty_dt <- function(dt, compact = FALSE) { assert_diff_time(dt) units(dt) <- "secs" pretty_sec(as.vector(dt), compact = compact) } structure( list( .internal = environment(), pretty_ms = pretty_ms, pretty_sec = pretty_sec, pretty_dt = pretty_dt ), class = c("standalone_time", "standalone") ) }) cli/R/time-ago.R0000644000176200001440000000627414557444176013101 0ustar liggesusers format_time_ago <- local({ e <- expression `%s%` <- function(lhs, rhs) { assert_string(lhs) do.call( sprintf, c(list(lhs), as.list(rhs)) ) } assert_string <- function(x) { stopifnot(is.character(x), length(x) == 1L) } assert_diff_time <- function(x) { stopifnot(inherits(x, "difftime")) } vague_dt_default <- list( list(c = e(seconds < 10), s = "moments ago"), list(c = e(seconds < 45), s = "less than a minute ago"), list(c = e(seconds < 90), s = "about a minute ago"), list(c = e(minutes < 45), s = e("%d minutes ago" %s% round(minutes))), list(c = e(minutes < 90), s = "about an hour ago"), list(c = e(hours < 24), s = e("%d hours ago" %s% round(hours))), list(c = e(hours < 42), s = "a day ago"), list(c = e(days < 30), s = e("%d days ago" %s% round(days))), list(c = e(days < 45), s = "about a month ago"), list(c = e(days < 335), s = e("%d months ago" %s% round(days / 30))), list(c = e(years < 1.5), s = "about a year ago"), list(c = TRUE, s = e("%d years ago" %s% round(years))) ) vague_dt_short <- list( list(c = e(seconds < 50), s = "<1 min"), list(c = e(minutes < 50), s = e("%d min" %s% round(minutes))), list(c = e(hours < 1.5), s = "1 hour"), list(c = e(hours < 18), s = e("%d hours" %s% round(hours))), list(c = e(hours < 42), s = "1 day"), list(c = e(days < 30), s = e("%d day" %s% round(days))), list(c = e(days < 45), s = "1 mon"), list(c = e(days < 335), s = e("%d mon" %s% round(days / 30))), list(c = e(years < 1.5), s = "1 year"), list(c = TRUE, s = e("%d years" %s% round(years))) ) vague_dt_terse <- list( list(c = e(seconds < 50), s = e("%2ds" %s% round(seconds))), list(c = e(minutes < 50), s = e("%2dm" %s% round(minutes))), list(c = e(hours < 18), s = e("%2dh" %s% round(hours))), list(c = e(days < 30), s = e("%2dd" %s% round(days))), list(c = e(days < 335), s = e("%2dM" %s% round(days / 30))), list(c = TRUE, s = e("%2dy" %s% round(years))) ) vague_dt_formats <- list( "default" = vague_dt_default, "short" = vague_dt_short, "terse" = vague_dt_terse ) time_ago <- function(date, format = c("default", "short", "terse")) { date <- as.POSIXct(date) if (length(date) > 1) return(sapply(date, time_ago, format = format)) seconds <- difftime(Sys.time(), date, units = "secs") vague_dt(seconds, format = format) } vague_dt <- function(dt, format = c("default", "short", "terse")) { assert_diff_time(dt) units(dt) <- "secs" seconds <- as.vector(dt) ## Simplest to quit here for empty input if (!length(seconds)) return(character()) pieces <- list( minutes = seconds / 60, hours = seconds / 60 / 60, days = seconds / 60 / 60 / 24, years = seconds / 60 / 60 / 24 / 365.25 ) format <- match.arg(format) for (p in vague_dt_formats[[format]]) { if (eval(p$c, pieces)) return(eval(p$s, pieces)) } } structure( list( .internal = environment(), time_ago = time_ago, vague_dt = vague_dt ), class = c("standalone_time_ago", "standalone") ) }) cli/R/cliapp.R0000644000176200001440000002232314752735214012631 0ustar liggesusers cliapp <- function(theme = getOption("cli.theme"), user_theme = getOption("cli.user_theme"), output = c("auto", "message", "stdout", "stderr")) { app <- new_class( "cliapp", new = function(theme, user_theme, output) clii_init(app, theme, user_theme, output), ## Meta meta = function(...) { txt <- cli__fmt(list(...), collapse = TRUE, app = app) clii__message(txt, appendLF = FALSE, output = app$output, signal = app$signal) }, ## Themes list_themes = function() clii_list_themes(app), add_theme = function(theme) clii_add_theme(app, theme), remove_theme = function(id) clii_remove_theme(app, id), ## Close container(s) end = function(id = NULL) clii_end(app, id), ## Generic container div = function(id = NULL, class = NULL, theme = NULL) clii_div(app, id, class, theme), ## Paragraphs par = function(id = NULL, class = NULL) clii_par(app, id, class), ## Text, wrapped text = function(text) clii_text(app, text), ## Text, not wrapped inline_text = function(text) clii_inline_text(app, text), ## Text, not wrapped, verbatim verbatim = function(...) clii_verbatim(app, ...), ## Markdow(ish) text, wrapped: emphasis, strong emphasis, links, code md_text = function(...) clii_md_text(app, ...), ## Headings h1 = function(text, id = NULL, class = NULL) clii_h1(app, text, id, class), h2 = function(text, id = NULL, class = NULL) clii_h2(app, text, id, class), h3 = function(text, id = NULL, class = NULL) clii_h3(app, text, id, class), ## Block quote blockquote = function(quote, citation = NULL, id, class = NULL) clii_blockquote(app, quote, citation, id, class), ## Lists ul = function(items = NULL, id = NULL, class = NULL, .close = TRUE) clii_ul(app, items, id, class, .close), ol = function(items = NULL, id = NULL, class = NULL, .close = TRUE) clii_ol(app, items, id, class, .close), dl = function(items = NULL, labels = NULL, id = NULL, class = NULL, .close = TRUE) clii_dl(app, items, labels, id, class, .close), li = function(items = NULL, labels = NULL, id = NULL, class = NULL) clii_li(app, items, labels, id, class), ## Tables table = function(cells, id = NULL, class = NULL) clii_table(app, cells, class), ## Alerts alert = function(text, id = NULL, class = NULL, wrap = FALSE) clii_alert(app, "alert", text, id, class, wrap), alert_success = function(text, id = NULL, class = NULL, wrap = FALSE) clii_alert(app, "alert-success", text, id, class, wrap), alert_danger = function(text, id = NULL, class = NULL, wrap = FALSE) clii_alert(app, "alert-danger", text, id, class, wrap), alert_warning = function(text, id = NULL, class = NULL, wrap = FALSE) clii_alert(app, "alert-warning", text, id, class, wrap), alert_info = function(text, id = NULL, class = NULL, wrap = FALSE) clii_alert(app, "alert-info", text, id, class, wrap), ## Bullets bullets = function(text, id = NULL, class = NULL) clii_bullets(app, text, id, class), ## Horizontal rule rule = function(left, center, right, id = NULL) clii_rule(app, left, center, right, id), ## Status bar status = function(id = NULL, msg, msg_done = NULL, msg_failed = NULL, keep = FALSE, auto_result = "clear", globalenv = FALSE) clii_status(app, id, msg, msg_done, msg_failed, keep, auto_result, globalenv), status_clear = function(id = NULL, result, msg_done = NULL, msg_failed = NULL) clii_status_clear(app, id, result, msg_done, msg_failed), status_update = function(id = NULL, msg, msg_done = NULL, msg_failed = NULL) clii_status_update(app, id, msg, msg_done, msg_failed), doc = NULL, themes = NULL, styles = NULL, delayed_item = NULL, status_bar = list(), margin = 0, output = NULL, get_current_style = function() utils::tail(app$styles, 1)[[1]], xtext = function(text = NULL, .list = NULL, indent = 0, padding = 0, wrap = TRUE) clii__xtext(app, text, .list = .list, indent = indent, padding = padding, wrap = wrap), vspace = function(n = 1) clii__vspace(app, n), inline = function(text = NULL, .list = NULL) clii__inline(app, text, .list = .list), item_text = function(type, name, cnt_id, items = list(), .list = NULL) clii__item_text(app, type, name, cnt_id, items, .list = .list), get_width = function(extra = 0) clii__get_width(app, extra), cat = function(lines) clii__cat(app, lines), cat_ln = function(lines, indent = 0, padding = 0) clii__cat_ln(app, lines, indent, padding) ) if (! inherits(output, "connection")) output <- match.arg(output) app$new(theme, user_theme, output) app } clii_init <- function(app, theme, user_theme, output) { app$doc <- list() app$output <- output app$styles <- NULL if (Sys.getenv("CLI_NO_BUILTIN_THEME", "") != "true") { app$add_theme(builtin_theme()) } app$add_theme(theme) app$add_theme(user_theme) clii__container_start(app, "body", id = "body") invisible(app) } ## Text ------------------------------------------------------------- clii_text <- function(app, text) { app$xtext(text) } clii_inline_text <- function(app, text) { app$xtext(text, wrap = FALSE) } clii_verbatim <- function(app, ..., .envir) { style <- app$get_current_style() text <- unlist(strsplit(unlist(list(...)), "\n", fixed = TRUE)) if (!is.null(style$fmt)) text <- style$fmt(text) app$cat_ln(text) invisible(app) } clii_md_text <- function(app, ...) { throw(cli_error("Markdown text is not implemented yet")) } ## Headings ---------------------------------------------------------- clii_h1 <- function(app, text, id, class) { clii__heading(app, "h1", text, id, class) } clii_h2 <- function(app, text, id, class) { clii__heading(app, "h2", text, id, class) } clii_h3 <- function(app, text, id, class) { clii__heading(app, "h3", text, id, class) } clii__heading <- function(app, type, text, id, class) { id <- new_uuid() clii__container_start(app, type, id = id, class = class) on.exit(clii__container_end(app, id), add = TRUE) text <- app$inline(text) style <- app$get_current_style() if (is.function(style$fmt)) text <- style$fmt(text) app$cat_ln(text) invisible(app) } ## Block quote ------------------------------------------------------ clii_blockquote <- function(app, quote, citation, id, class) { c1 <- clii__container_start(app, "blockquote", id = id, class = class) on.exit(clii__container_end(app, id), add = TRUE) app$xtext(quote) c2 <- clii__container_start(app, "cite", id = new_uuid()) app$xtext(citation) } ## Table ------------------------------------------------------------ clii_table <- function(app, cells, id, class) { throw(cli_error("Tables are not implemented yet")) } ## Rule ------------------------------------------------------------- clii_rule <- function(app, left, center, right, id) { left <- app$inline(left) center <- app$inline(center) right <- app$inline(right) clii__container_start(app, "rule", id = id) on.exit(clii__container_end(app, id), add = TRUE) style <- app$get_current_style() before <- call_if_fun(style$before) %||% "" after <- call_if_fun(style$after) %||% "" width <- console_width() - ansi_nchar(before) - ansi_nchar(after) text <- rule(left, center, right, line = style$`line-type` %||% 1) text[1] <- paste0(before, text[1]) text[length(text)] <- paste0(text[length(text)], after) if (is.function(style$fmt)) text <- style$fmt(text) app$cat_ln(text) } ## Alerts ----------------------------------------------------------- clii_alert <- function(app, type, text, id, class, wrap) { clii__container_start(app, "div", id = id, class = paste(class, "alert", type)) on.exit(clii__container_end(app, id), add = TRUE) if (wrap) { app$xtext(text) } else { text <- app$inline(text) style <- app$get_current_style() before <- call_if_fun(style$before) %||% "" after <- call_if_fun(style$after) %||% "" before <- gsub(" ", "\u00a0", before, fixed = TRUE) after <- gsub(" ", "\u00a0", after, fixed = TRUE) text[1] <- paste0(before, text[1]) text[length(text)] <- paste0(text[length(text)], after) if (is.function(style$fmt)) text <- style$fmt(text) app$cat_ln(text) } } ## Bullets ------------------------------------------------------------- clii_bullets <- function(app, text, id, class) { clii__container_start(app, "div", id = id, class = paste("memo bullets", class)) on.exit(clii__container_end(app, id), add = TRUE) # Normalize names a bit, so we can use them as class names nms <- as.character(names(text)) length(nms) <- length(text) nms[is.na(nms) | nms == ""] <- "empty" nms[nms == " "] <- "space" nms <- gsub(" ", "-", nms, fixed = TRUE) # cls is vectorized here (!) cls <- paste0("bullet memo-item bullet-", nms, " memo-item=", nms) lapply(seq_along(text), function(i) { iid <- new_uuid() clii__container_start(app, "div", id = iid, class = cls[i]) on.exit(clii__container_end(app, iid), add = TRUE) app$text(text[[i]]) }) invisible() } cli/R/mocks.R0000644000176200001440000000025414752735214012474 0ustar liggesusers.Call <- NULL Sys.time <- NULL commandArgs <- NULL get <- NULL getRversion <- NULL isatty <- NULL l10n_info <- NULL loadedNamespaces <- NULL system <- NULL system2 <- NULL cli/R/diff.R0000644000176200001440000002133614557444176012303 0ustar liggesusers #' Compare two character vectors elementwise #' #' Its printed output is similar to calling `diff -u` at the command #' line. #' #' @param old First character vector. #' @param new Second character vector. #' @param max_dist Maximum distance to consider, or `Inf` for no limit. #' If the LCS edit distance is larger than this, then the function #' throws an error with class `"cli_diff_max_dist"`. (If you specify #' `Inf` the real limit is `.Machine$integer.max` but to reach this the #' function would have to run a very long time.) #' @return A list that is a `cli_diff_chr` object, with a `format()` and a #' `print()` method. You can also access its members: #' * `old` and `new` are the original inputs, #' * `lcs` is a data frame of LCS edit that transform `old` into `new`. #' #' The `lcs` data frame has the following columns: #' * `operation`: one of `"match"`, `"delete"` or `"insert"`. #' * `offset`: offset in `old` for matches and deletions, offset in `new` #' for insertions. #' * `length`: length of the operation, i.e. number of matching, deleted #' or inserted elements. #' * `old_offset`: offset in `old` _after_ the operation. #' * `new_offset`: offset in `new` _after_ the operation. #' #' @family diff functions in cli #' @seealso The diffobj package for a much more comprehensive set of #' `diff`-like tools. #' @export #' @examples #' letters2 <- c("P", "R", "E", letters, "P", "O", "S", "T") #' letters2[11:16] <- c("M", "I", "D", "D", "L", "E") #' diff_chr(letters, letters2) diff_chr <- function(old, new, max_dist = Inf) { stopifnot( is.character(old), is.character(new), max_dist == Inf || is_count(max_dist) ) max_dist2 <- as_max_dist(max_dist) lcs <- .Call(clic_diff_chr, old, new, max_dist2) if (max_dist2 != 0 && lcs[[4]] == max_dist2) { throw(cli_error( "Diff edit distance is larger than the limit.", "i" = "The edit distance limit is {max_dist}.", .data = list(max_dist = max_dist), .class = "cli_diff_max_dist" )) } op <- c("match", "delete", "insert")[lcs[[1]]] lcs <- data.frame( stringsAsFactors = FALSE, operation = op, offset = lcs[[2]], length = lcs[[3]], old_offset = cumsum(ifelse(op == "insert", 0, lcs[[3]])), new_offset = cumsum(ifelse(op == "delete", 0, lcs[[3]])) ) ret <- structure( list(old = old, new = new, lcs = lcs), class = c("cli_diff_chr", "cli_diff", "list") ) ret } #' Compare two character strings, character by character #' #' Characters are defined by UTF-8 graphemes. #' #' @param old First string, must not be `NA`. #' @param new Second string, must not be `NA`. #' @inheritParams diff_chr #' @return A list that is a `cli_diff_str` object and also a #' `cli_diff_chr` object, see [diff_str] for the details about its #' structure. #' #' @family diff functions in cli #' @seealso The diffobj package for a much more comprehensive set of #' `diff`-like tools. #' #' @export #' @examples #' str1 <- "abcdefghijklmnopqrstuvwxyz" #' str2 <- "PREabcdefgMIDDLEnopqrstuvwxyzPOST" #' diff_str(str1, str2) diff_str <- function(old, new, max_dist = Inf) { stopifnot( is_string(old), is_string(new) # max_dist is checked in diff_chr ) old1 <- utf8_graphemes(old)[[1]] new1 <- utf8_graphemes(new)[[1]] ret <- diff_chr(old1, new1, max_dist) class(ret) <- c("cli_diff_str", class(ret)) ret } #' @export format.cli_diff_chr <- function(x, context = 3L, ...) { stopifnot(context == Inf || is_count(context)) if (length(list(...)) > 0) { warning("Extra arguments were ignored in `format.cli_diff_chr()`.") } chunks <- get_diff_chunks(x$lcs, context = context) out <- lapply( seq_len(nrow(chunks)), format_chunk, x = x, chunks = chunks, context = context ) ret <- as.character(unlist(out)) if (context == Inf && length(ret) > 0) ret <- ret[-1] ret } get_diff_chunks <- function(lcs, context = 3L) { # the number of chunks is the number of non-matching sequences if # context == 0, but short matching parts do not separate chunks runs <- rle(lcs$operation != "match" | lcs$length <= 2 * context) nchunks <- sum(runs$values) # special case for a single match chunk if (nrow(lcs) == 1 && lcs$operation == "match") { nchunks <- if (context == Inf) 1 else 0 } chunks <- data.frame( op_begin = integer(nchunks), # first op in chunk op_length = integer(nchunks), # number of operations in chunk old_begin = integer(nchunks), # first line from `old` in chunk old_length = integer(nchunks), # number of lines from `old` in chunk new_begin = integer(nchunks), # first line from `new` in chunk new_length = integer(nchunks) # number of lines from `new` in chunk ) if (nchunks == 0) return(chunks) # infer some data about the original diff input old_off <- c(0, lcs$old_offset) new_off <- c(0, lcs$new_offset) old_size <- old_off[length(old_off)] new_size <- new_off[length(new_off)] old_empty <- old_size == 0 new_empty <- new_size == 0 # avoid working with Inf if (context == Inf) context <- max(old_size, new_size) # chunk starts at operation number sum(length) before it, plus 1, but # at the end we change this to include the context chunks are well chunks$op_begin <- c(0, cumsum(runs$lengths))[which(runs$values)] + 1 chunks$op_length <- runs$lengths[runs$values] # `old` positions are from `old_off`, but need to fix the boundaries chunks$old_begin <- old_off[chunks$op_begin] - context + 1 chunks$old_begin[chunks$old_begin <= 1] <- if (old_empty) 0 else 1 old_end <- old_off[chunks$op_begin + chunks$op_length] + context old_end[old_end > old_size] <- old_size chunks$old_length <- old_end - chunks$old_begin + 1 # `new` positions are similar chunks$new_begin <- new_off[chunks$op_begin] - context + 1 chunks$new_begin[chunks$new_begin <= 1] <- if (new_empty) 0 else 1 new_end <- new_off[chunks$op_begin + chunks$op_length] + context new_end[new_end > new_size] <- new_size chunks$new_length <- new_end - chunks$new_begin + 1 # change to include context chunks if (context > 0) { # calculae the end before updating the begin op_end <- chunks$op_begin + chunks$op_length - 1 + 1 op_end[op_end > nrow(lcs)] <- nrow(lcs) chunks$op_begin <- chunks$op_begin - 1 chunks$op_begin[chunks$op_begin == 0] <- 1 chunks$op_length <- op_end - chunks$op_begin + 1 } chunks } format_chunk <- function(x, chunks, num, context) { hdr <- paste0( "@@ -", chunks$old_begin[num], if ((l <- chunks$old_length[num]) != 1) paste0(",", l), " +", chunks$new_begin[num], if ((l <- chunks$new_length[num]) != 1) paste0(",", l), " @@" ) from <- chunks$op_begin[num] to <- chunks$op_begin[num] + chunks$op_length[num] - 1 lines <- lapply(from:to, function(i) { op <- x$lcs$operation[i] off <- x$lcs$offset[i] len <- x$lcs$length[i] if (op == "match") { if (len > context) { if (i == from) { # start later off <- off + len - context len <- context } else { # finish earlier len <- context } } paste0(" ", x$old[off + 1:len]) } else if (op == "delete") { col_blue(paste0("-", x$old[off + 1:len])) } else if (op == "insert") { col_green(paste0("+", x$new[off + 1:len])) } }) c(hdr, lines) } #' @export print.cli_diff_chr <- function(x, ...) { writeLines(format(x, ...)) } #' @export format.cli_diff_str <- function(x, ...) { if (length(list(...)) > 0) { warning("Extra arguments were ignored in `format.cli_diff_chr()`.") } if (num_ansi_colors() == 1) { format_diff_str_nocolor(x, ...) } else { format_diff_str_color(x, ...) } } format_diff_str_color <- function(x, ...) { out <- lapply(seq_len(nrow(x$lcs)), function(i) { op <- x$lcs$operation[i] off <- x$lcs$offset[i] len <- x$lcs$length[i] if (op == "match") { paste0(x$old[off + 1:len], collapse = "") } else if (op == "delete") { bg_blue(col_black(paste0(x$old[off + 1:len], collapse = ""))) } else if (op == "insert") { bg_green(col_black(paste0(x$new[off + 1:len], collapse = ""))) } }) paste(out, collapse = "") } format_diff_str_nocolor <- function(x, ...) { out <- lapply(seq_len(nrow(x$lcs)), function(i) { op <- x$lcs$operation[i] off <- x$lcs$offset[i] len <- x$lcs$length[i] if (op == "match") { paste0(x$old[off + 1:len], collapse = "") } else if (op == "delete") { paste0(c("[-", x$old[off + 1:len], "-]"), collapse = "") } else if (op == "insert") { paste0(c("{+", x$new[off + 1:len], "+}"), collapse = "") } }) paste(out, collapse = "") } as_max_dist <- function(max_dist) { if (max_dist == Inf) { 0L } else { as.integer(max_dist + 1L) } } cli/R/cliapp-docs.R0000644000176200001440000006021414752735214013560 0ustar liggesusers #' @title About inline markup in the semantic cli #' #' @description #' To learn how to use cli’s semantic markup, start with the ‘Building #' a semantic CLI’ article at . #' #' @section Command substitution: #' #' All text emitted by cli supports glue interpolation. Expressions #' enclosed by braces will be evaluated as R code. See [glue::glue()] for #' details. #' #' In addition to regular glue interpolation, cli can also add classes #' to parts of the text, and these classes can be used in themes. For #' example #' #' ```{asciicast inline-text} #' cli_text("This is {.emph important}.") #' ``` #' #' adds a class to the "important" word, class `"emph"`. Note that in this #' case the string within the braces is usually not a valid R expression. #' If you want to mix classes with interpolation, add another pair of #' braces: #' #' ```{asciicast inline-text-2} #' adjective <- "great" #' cli_text("This is {.emph {adjective}}.") #' ``` #' #' An inline class will always create a `span` element internally. So in #' themes, you can use the `span.emph` CSS selector to change how inline #' text is emphasized: #' #' ```{asciicast inline-text-3} #' cli_div(theme = list(span.emph = list(color = "red"))) #' adjective <- "nice and red" #' cli_text("This is {.emph {adjective}}.") #' ``` #' #' @section Classes: #' #' The default theme defines the following inline classes: #' * `arg` for a function argument. #' * `cls` for an S3, S4, R6 or other class name. #' * `code` for a piece of code. #' * `dt` is used for the terms in a definition list ([cli_dl()]). #' * `dd` is used for the descriptions in a definition list ([cli_dl()]). #' * `email` for an email address. #' If the terminal supports ANSI hyperlinks (e.g. RStudio, iTerm2, etc.), #' then cli creates a clickable link. #' See [links] for more information about cli hyperlinks. #' * `emph` for emphasized text. #' * `envvar` for the name of an environment variable. #' * `field` for a generic field, e.g. in a named list. #' * `file` for a file name. If the terminal supports ANSI hyperlinks (e.g. #' RStudio, iTerm2, etc.), then cli creates a clickable link that opens #' the file in RStudio or with the default app for the file type. #' See [links] for more information about cli hyperlinks. #' * `fn` for a function name. If it is in the `package::function_name` #' form, and the terminal supports ANSI hyperlinks (e.g. RStudio, #' iTerm2, etc.), then cli creates a clickable link. #' See [links] for more information about cli hyperlinks. #' * `fun` same as `fn`. #' * `help` is a help page of a _function_. #' If the terminal supports ANSI hyperlinks to help pages (e.g. RStudio), #' then cli creates a clickable link. It supports link text. #' See [links] for more information about cli hyperlinks. #' * `href` creates a hyperlink, potentially with a link text. #' If the terminal supports ANSI hyperlinks (e.g. RStudio, iTerm2, etc.), #' then cli creates a clickable link. #' See [links] for more information about cli hyperlinks. #' * `kbd` for a keyboard key. #' * `key` same as `kbd`. #' * `obj_type_friendly` formats the type of an R object in a readable way, #' and it should be used with `{}`, see an example below. #' * `or` changes the string that separates the last two elements of #' collapsed vectors (see below) from "and" to "or". #' * `path` for a path (the same as `file` in the default theme). #' * `pkg` for a package name. #' * `run` is an R expression, that is potentially clickable if the terminal #' supports ANSI hyperlinks to runnable code (e.g. RStudio). #' It supports link text. See [links] for more information about cli hyperlinks. #' * `str` for a double quoted string escaped by [base::encodeString()]. #' * `strong` for strong importance. #' * `topic` is a help page of a _topic_. #' If the terminal supports ANSI hyperlinks to help pages (e.g. RStudio), #' then cli creates a clickable link. It supports link text. #' See [links] for more information about cli hyperlinks. #' * `type` formats the type of an R object in a readable way, and it #' should be used with `{}`, see an example below. #' * `url` for a URL. If the terminal supports ANSI hyperlinks (e.g. #' RStudio, iTerm2, etc.), then cli creates a clickable link. #' See [links] for more information about cli hyperlinks. #' * `var` for a variable name. #' * `val` for a generic "value". #' * `vignette` is a vignette. #' If the terminal supports ANSI hyperlinks to help pages (e.g. RStudio), #' then cli creates a clickable link. It supports link text. #' See [links] for more information about cli hyperlinks. #' #' ```{asciicast inline-examples} #' ul <- cli_ul() #' cli_li("{.emph Emphasized} text.") #' cli_li("{.strong Strong} importance.") #' cli_li("A piece of code: {.code sum(a) / length(a)}.") #' cli_li("A package name: {.pkg cli}.") #' cli_li("A function name: {.fn cli_text}.") #' cli_li("A keyboard key: press {.kbd ENTER}.") #' cli_li("A file name: {.file /usr/bin/env}.") #' cli_li("An email address: {.email bugs.bunny@acme.com}.") #' cli_li("A URL: {.url https://example.com}.") #' cli_li("An environment variable: {.envvar R_LIBS}.") #' cli_li("`mtcars` is {.obj_type_friendly {mtcars}}") #' cli_end(ul) #' ``` #' #' You can add new classes by defining them in the theme, and then using #' them. #' #' ```{asciicast inline-newclass} #' cli_div(theme = list( #' span.myclass = list(color = "lightgrey"), #' "span.myclass" = list(before = "<<"), #' "span.myclass" = list(after = ">>"))) #' cli_text("This is {.myclass in angle brackets}.") #' cli_end() #' ``` #' #' ## Highlighting weird-looking values #' #' Often it is useful to highlight a weird file or path name, e.g. one #' that starts or ends with space characters. The built-in theme does this #' for `.file`, `.path` and `.email` by default. You can highlight #' any string inline by adding the `.q` class to it. #' #' The current highlighting algorithm #' * adds single quotes to the string if it does not start or end with an #' alphanumeric character, underscore, dot or forward slash. #' * Highlights the background colors of leading and trailing spaces on #' terminals that support ANSI colors. #' #' @section Collapsing inline vectors: #' #' When cli performs inline text formatting, it automatically collapses #' glue substitutions, after formatting. This is handy to create lists of #' files, packages, etc. #' #' ```{asciicast inline-collapse} #' pkgs <- c("pkg1", "pkg2", "pkg3") #' cli_text("Packages: {pkgs}.") #' cli_text("Packages: {.pkg {pkgs}}.") #' ``` #' #' Class names are collapsed differently by default #' #' ```{asciicast inline-collapse-2} #' x <- Sys.time() #' cli_text("Hey, {.var x} has class {.cls {class(x)}}.") #' ``` #' #' By default cli truncates long vectors. The truncation limit is by default #' twenty elements, but you can change it with the `vec-trunc` style. #' #' ```{asciicast inline-collapse-trunc} #' nms <- cli_vec(names(mtcars), list("vec-trunc" = 5)) #' cli_text("Column names: {nms}.") #' ``` #' #' @section Formatting values: #' #' The `val` inline class formats values. By default (c.f. the built-in #' theme), it calls the [cli_format()] generic function, with the current #' style as the argument. See [cli_format()] for examples. #' #' `str` is for formatting strings, it uses [base::encodeString()] with #' double quotes. #' #' @section Escaping `{` and `}`: #' #' It might happen that you want to pass a string to `cli_*` functions, #' and you do _not_ want command substitution in that string, because it #' might contain `{` and `}` characters. The simplest solution for this is #' to refer to the string from a template: #' #' ```{asciicast inline-escape} #' msg <- "Error in if (ncol(dat$y)) {: argument is of length zero" #' cli_alert_warning("{msg}") #' ``` #' #' If you want to explicitly escape `{` and `}` characters, just double #' them: #' #' ```{asciicast inline-escape-2} #' cli_alert_warning("A warning with {{ braces }}.") #' ``` #' #' See also examples below. #' #' @section Pluralization: #' #' All cli commands that emit text support pluralization. Some examples: #' #' ```{asciicast inline-plural} #' ndirs <- 1 #' nfiles <- 13 #' pkgs <- c("pkg1", "pkg2", "pkg3") #' cli_alert_info("Found {ndirs} director{?y/ies} and {nfiles} file{?s}.") #' cli_text("Will install {length(pkgs)} package{?s}: {.pkg {pkgs}}") #' ``` #' #' See [pluralization] for details. #' #' @section Wrapping: #' #' Most cli containers wrap the text to width the container's width, #' while observing margins requested by the theme. #' #' To avoid a line break, you can use the UTF_8 non-breaking space #' character: `\u00a0`. cli will not break a line here. #' #' To force a line break, insert a form feed character: `\f` or #' `\u000c`. cli will insert a line break there. #' #' @name inline-markup NULL #' About cli containers #' #' Container elements may contain other elements. Currently the following #' commands create container elements: [cli_div()], [cli_par()], the list #' elements: [cli_ul()], [cli_ol()], [cli_dl()], and list items are #' containers as well: [cli_li()]. #' #' ## Themes #' #' A container can add a new theme, which is removed when the container #' exits. #' #' ```{asciicast cnt-theme} #' d <- cli_div(theme = list(h1 = list(color = "blue", #' "font-weight" = "bold"))) #' cli_h1("Custom title") #' cli_end(d) #' ``` #' #' ## Auto-closing #' #' Container elements are closed with [cli_end()]. For convenience, #' by default they are closed automatically when the function that created #' them terminated (either regularly or with an error). The default #' behavior can be changed with the `.auto_close` argument. #' #' ```{asciicast cnt-auto-close} #' div <- function() { #' cli_div(class = "tmp", theme = list(.tmp = list(color = "yellow"))) #' cli_text("This is yellow") #' } #' div() #' cli_text("This is not yellow any more") #' ``` #' #' ## Debugging #' #' You can use the internal `cli:::cli_debug_doc()` function to see the #' currently open containers. #' #' ```{asciicast cnt-debug, echo = -1} #' stop_app() #' fun <- function() { #' cli_div(id = "mydiv") #' cli_par(class = "myclass") #' cli:::cli_debug_doc() #' } #' fun() #' ``` #' #' @name containers NULL #' About cli themes #' #' CLI elements can be styled via a CSS-like language of selectors and #' properties. Only a small subset of CSS3 is supported, and #' a lot visual properties cannot be implemented on a terminal, so these #' will be ignored as well. #' #' @section Adding themes: #' The style of an element is calculated from themes from four sources. #' These form a stack, and the themes on the top of the stack take #' precedence, over themes in the bottom. #' #' 1. The cli package has a built-in theme. This is always active. #' See [builtin_theme()]. #' 2. When an app object is created via [start_app()], the caller can #' specify a theme, that is added to theme stack. If no theme is #' specified for [start_app()], the content of the `cli.theme` option #' is used. Removed when the corresponding app stops. #' 3. The user may specify a theme in the `cli.user_theme` option. This #' is added to the stack _after_ the app's theme (step 2.), so it can #' override its settings. Removed when the app that added it stops. #' 4. Themes specified explicitly in [cli_div()] elements. These are #' removed from the theme stack, when the corresponding [cli_div()] #' elements are closed. #' #' @section Writing themes: #' A theme is a named list of lists. The name of each entry is a CSS #' selector. Only a subset of CSS is supported: #' * Type selectors, e.g. `input` selects all `` elements. #' * Class selectors, e.g. `.index` selects any element that has a class #' of "index". #' * ID selector. `#toc` will match the element that has the ID "toc". #' * The descendant combinator, i.e. the space, that selects nodes #' that are descendants of the first element. E.g. `div span` will match #' all `` elements that are inside a `
` element. #' #' The content of a theme list entry is another named list, where the #' names are CSS properties, e.g. `color`, or `font-weight` or #' `margin-left`, and the list entries themselves define the values of #' the properties. See [builtin_theme()] and [simple_theme()] for examples. #' #' @section Formatter callbacks: #' For flexibility, themes may also define formatter functions, with #' property name `fmt`. These will be called once the other styles are #' applied to an element. They are only called on elements that produce #' output, i.e. _not_ on container elements. #' #' @section Supported properties: #' Right now only a limited set of properties are supported. These include #' left, right, top and bottom margins, background and foreground colors, #' bold and italic fonts, underlined text. The `before` and `after` #' properties are supported to insert text before and after the #' content of the element. #' #' The current list of properties: #' #' * `after`: A string literal to insert after the element. It can also be #' a function that returns a string literal. Supported by all inline #' elements, list items, alerts and rules. #' * `background-color`: An R color name, or HTML hexadecimal color. #' It can be applied to most elements (inline elements, rules, text, #' etc.), but the background of containers is not colored properly #' currently. #' * `before`: A string literal to insert before the element. It can also be #' a function that returns a string literal. Supported by all inline #' elements, list items, alerts and rules. #' * `class-map`: Its value can be a named list, and it specifies how #' R (S3) class names are mapped to cli class names. E.g. #' `list(fs_path = "file")` specifies that `fs_path` objects (from the fs #' package) should always print as `.file` objects in cli. #' * `color`: Text color, an R color name or a HTML hexadecimal color. It #' can be applied to most elements that are printed. #' * `collapse`: Specifies how to collapse a vector, before applying #' styling. If a character string, then that is used as the separator. #' If a function, then it is called, with the vector as the only #' argument. #' * `digits`: Number of digits after the decimal point for numeric inline #' element of class `.val`. #' * `fmt`: Generic formatter function that takes an input text and returns #' formatted text. Can be applied to most elements. If colors are in use, #' the input text provided to `fmt` already includes ANSI sequences. #' * `font-style`: If `"italic"` then the text is printed as cursive. #' * `font-weight`: If `"bold"`, then the text is printed in boldface. #' * `line-type`: Line type for [cli_rule()]. #' * `list-style-type`: String literal or functions that returns a string #' literal, to be used as a list item marker in un-ordered lists. #' * `margin-bottom`, `margin-left`, `margin-right`, `margin-top`: Margins. #' * `padding-left`, `padding-right`: This is currently used the same way #' as the margins, but this might change later. #' * `start`: Integer number, the first element in an ordered list. #' * `string-quote`: Quoting character for inline elements of class `.val`. #' * `text-decoration`: If `"underline"`, then underlined text is created. #' * `text-exdent`: Amount of indentation from the second line of wrapped #' text. #' * `transform`: A function to call on glue substitutions, before #' collapsing them. Note that `transform` is applied prior to #' implementing color via ANSI sequences. #' * `vec-last`: The last separator when collapsing vectors. #' * `vec-sep`: The separator to use when collapsing vectors. #' * `vec-sep2`: The separator to use for two elements when collapsing #' vectors. If not set, then `vec-sep` is used for these as well. #' * `vec-trunc`: Vectors longer than this will be truncated. Defaults to #' 100. #' * `vec-trunc-style`: Select between two ways of collapsing vectors: #' - `"both-ends"` is the current default and it shows the beginning and #' the end of the vector. #' - `"head"` only shows the beginning of the vector. #' #' More properties might be added later. If you think that a property is #' not applied properly to an element, please open an issue about it in #' the cli issue tracker. #' #' @section Examples: #' Color of headings, that are only active in paragraphs with an #' 'output' class: #' ``` #' list( #' "par.output h1" = list("background-color" = "red", color = "#e0e0e0"), #' "par.output h2" = list("background-color" = "orange", color = "#e0e0e0"), #' "par.output h3" = list("background-color" = "blue", color = "#e0e0e0") #' ) #' ``` #' #' Create a custom alert type: #' ``` #' list( #' ".alert-start" = list(before = symbol$play), #' ".alert-stop" = list(before = symbol$stop) #' ) #' ``` #' @name themes # TODO: examples NULL #' cli hyperlinks #' #' @description #' Certain cli styles create clickable links, if your IDE or terminal #' supports them. #' #' # Note: hyperlinks are currently experimental #' #' The details of the styles that create hyperlinks will prrobably change #' in the near future, based on user feedback. #' #' # About the links in this manual page #' #' The hyperlinks that are included in this manual are demonstrative #' only, except for the `https:` links. They look like a hyperlink, and #' you can click on them, but they do nothing. I.e. a `.run` link will #' not run the linked expression if you click on it. #' #' # Hyperlink Support #' #' As of today, the latest release of RStudio (version v2022.07.0+548) #' supports all hyperlink types discussed here. Certain terminals, e.g. #' iTerm on macOS, Linux terminals based on VTE (GNOME terminal) support #' `.href`, `.email` and `.file` links. #' #' You can use [ansi_has_hyperlink_support()] to check if your terminal or #' IDE has hyperlink support in general, and [ansi_hyperlink_types()] to #' check if various types of hyperlinks are supported. #' #' If your hyperlink support is not detected properly in your IDE or #' terminal, please open a cli issue at #' . #' #' ```{asciicast links-setup, include = FALSE, cache = FALSE} #' options( #' cli.hyperlink = TRUE, #' cli.hyperlink_run = TRUE, #' cli.hyperlink_help = TRUE, #' cli.hyperlink_vignette = TRUE #' ) #' ``` #' #' # Link text #' #' Before we delve into the various types of hyperlinks, a general comment #' about link texts. Some link styles support a custom link text: #' #' * `.href` #' * `.help` #' * `.topic` #' * `.vignette` #' * `.run` #' #' Others, i.e. `.email`, `.file`, `.fun` and `.url` do not support custom #' link text. #' #' The generic syntax for link text is the same as for Markdown hyperlinks: #' ``` #' {.style [link text](url)} #' ``` #' #' ## Vectorization #' #' Note that it is not possible to add link text to a vector of URLs. E.g. #' this will create a list of three URLs, all clickable: #' #' ```{asciicast link-example} #' urls <- paste0("https://httpbin.org/status/", c(200, 403, 404)) #' cli::cli_text("Some httpbin URLs: {.url {urls}}.") #' ``` #' But it is not possible to use a different link text for them. #' #' ## What if hyperlinks are not available? #' #' If ANSI hyperlinks are not available, then the link text for of these #' styles outputs both the link text and the URL in a (hopefully) helpful #' way. See examples below. #' #' # URLs #' #' There are two cli styles to link to generic URLs. `.url` does not #' allow custom link text, but `\href` does. #' #' ```{asciicast links-url-1} #' cli_text( #' "See the cli homepage at {.url https://cli.r-lib.org} for details." #' ) #' ``` #' #'```{asciicast links-url-2} #' cli_text( #' "See the {.href [cli homepage](https://cli.r-lib.org)} for details." #' ) #' ``` #' #' ## Without hyperlink support #' #' This is how these links look without hyperlink support: #' #' ```{asciicast links-url-3} #' local({ #' withr::local_options(cli.hyperlink = FALSE) #' cli_text( #' "See the cli homepage at {.url https://cli.r-lib.org} for details." #' ) #' cli_text( #' "See the {.href [cli homepage](https://cli.r-lib.org)} for details." #' ) #' }) #' ``` #' #' ## URL encoding #' #' Note that cli does not encode the url, so you might need to call #' `utils::URLencode()` on it, especially, if it is substituted in #' via `{}`. #' #' ```{asciicast links-url-4} #' weirdurl <- utils::URLencode("https://example.com/has some spaces") #' cli_text("See more at {.url {weirdurl}}.") #' ``` #' #' # Files #' #' The `.file` style now automatically creates a `file:` hyperlink. #' Because `file:` hyperlinks must contain an absolute path, cli tries to #' convert relative paths, and paths starting with `~` to aboslute path. #' #' ```{asciicast links-file-1} #' cli_text("... edit your {.file ~/.Rprofile} file.") #' ``` #' #' ## Link text #' #' `.file` cannot use a custom link text. If you custom link text, then #' you can use `.href` with a `file:` URL. #' #' ```{asciicast links-file-2} #' prof <- path.expand("~/.Rprofile") #' cli_text("... edit your {.href [R profile](file://{prof})}.") #' ``` #' #' ## Line and column numbers #' #' You may add a line number to a file name, separated by `:`. Handlers #' typically place the cursor at that line after opening the file. #' You may also add a column number, after the line number, separated by #' another `:`. #' #' ```{asciicast links-file-3} #' cli_text("... see line 5 in {.file ~/.Rprofile:5}.") #' ``` #' #' ## Default handler #' #' In RStudio `file:` URLs open within RStudio. If you click on a file #' link outside of RStudio, typically the operating system is consulted #' for the application to open it. #' #' ## Without hyperlink support #' #' One issue with using `.href` file files is that it does not look great #' if hyperlinks are not available. This will be improved in the future: #' #' ```{asciicast links-file-4} #' local({ #' withr::local_options(cli.hyperlink = FALSE) #' prof <- path.expand("~/.Rprofile") #' cli_text("... edit your {.href [R profile](file://{prof})}.") #' }) #' ``` #' #' # Links to the manual #' #' `.fun` automatically creates links to the manual page of the function, #' provided the function name is in the `packagename::functionname` form: #' #' ```{asciicast links-fun-1} #' cli::cli_text("... see {.fun stats::lm} to learn more.") #' ``` #' #' ## Link text #' #' For a custom link text, use `.help` instead of `.fun`. #' #' ```{asciicast links-fun-2} #' cli::cli_text("... see {.help [{.fun lm}](stats::lm)} to learn more.") #' ``` #' #' ## Without hyperlink support #' #' The same message without hyperlink support looks like this: #' #' ```{asciicast links-fun-3} #' local({ #' withr::local_options(cli.hyperlink = FALSE) #' cli::cli_text("... see {.help [{.fun lm}](stats::lm)} to learn more.") #' }) #' ``` #' #' ## Topics #' #' To link to a help topic that is not a function, use `.topic`: #' #' ```{asciicast links-topic} #' cli::cli_text("... the tibble options at {.topic tibble::tibble_options}.") #' ``` #' #' `.topic` support link text. #' #' ## Vignettes #' #' To link to a vignette, use `.vignette`: #' #' ```{asciicast links-vignette} #' cli::cli_text("... see the {.vignette tibble::types} vignette.") #' ``` #' #' # Click to run code #' #' RStudio also supports a special link type that runs R code in the #' current R session upon clicking. #' #' You can create these links with `.run`: #' #' ```{asciicast links-run} #' cli::cli_text("Run {.run testthat::snapshot_review()} to review") #' ``` #' #' ## Link text #' #' Sometimes you want to show a slightly different expression in the link, #' than the one that is evaluated. E.g. the evaluated expression probably #' needs to qualify packages with `::`, but you might not want to show this: #' #' ```{asciicast links-run-2} #' cli::cli_text( #' "Run {.run [snapshot_review()](testthat::snapshot_review())} to review" #' ) #' ``` #' #' ## Security considerations #' #' To make `.run` hyperlinks more secure, RStudio will not run code #' #' * that is not in the `pkg::fun(args)` form, #' * if `args` contains `(`, `)` or `;`, #' * if it calls a core package (base, stats, etc.), #' * if it calls a package that is not loaded, and it is not one of #' testthat, devtools, usethis, rlang, pkgload, or pkgdown which are explicitly allowed. #' #' When RStudio does not run a `.run` hyperlink, then it shows the code #' and the user can copy and paste it to the console, if they consider #' it safe to run. #' #' Note that depending on your version of RStudio, the behavior can change. #' @name links NULL cli/R/docs.R0000644000176200001440000000220314557444176012313 0ustar liggesusers #' Frequently Asked Questions #' #' @name faq #' @includeRmd man/chunks/FAQ.Rmd NULL docs_progress_c_api <- function() { if (file.exists("inst/include/cli/progress.h")) { lines <- readLines("inst/include/cli/progress.h") } else { lines <- readLines("../inst/include/cli/progress.h") } ## Remove non-matching lines, but leave an empty line between blocks ptn <- "^//'[ ]?" mtch <- grepl(ptn, lines) lines[!mtch] <- "" prev <- c("", lines[-length(lines)]) lines <- lines[mtch | prev != lines] ## Remove doc pattern lines <- sub(ptn, "", lines) tmp <- tempfile(fileext = ".Rmd") cat(lines, sep = "\n", file = tmp) tmp } #' @title The cli progress C API #' @name progress-c #' @section The cli progress C API: #' #' ```{r include = FALSE, cache = FALSE, child = cli:::docs_progress_c_api()} #' ``` NULL #' @title cli environment variables and options #' @name cli-config #' #' @section User facing configuration: #' #' ```{r include = FALSE, child = "vignettes/cli-config-user.Rmd"} #' ``` #' #' @section Internal configuration: #' #' ```{r include = FALSE, child = "vignettes/cli-config-internal.Rmd"} #' ``` NULL cli/R/app.R0000644000176200001440000000435514557444176012155 0ustar liggesusers cliappenv <- new.env() cliappenv$stack <- list() cliappenv$pid <- Sys.getpid() #' Start, stop, query the default cli application #' #' `start_app` creates an app, and places it on the top of the app stack. #' #' `stop_app` removes the top app, or multiple apps from the app stack. #' #' `default_app` returns the default app, the one on the top of the stack. #' #' @param theme Theme to use. #' @param output How to print the output. #' @param .auto_close Whether to stop the app, when the calling frame #' is destroyed. #' @param .envir The environment to use, instead of the calling frame, #' to trigger the stop of the app. #' @param app App to stop. If `NULL`, the current default app is stopped. #' Otherwise we find the supplied app in the app stack, and remote it, #' together with all the apps above it. #' @return #' `start_app` returns the new app, `default_app` returns the default app. #' `stop_app` does not return anything. #' #' @export start_app <- function(theme = getOption("cli.theme"), output = c("auto", "message", "stdout", "stderr"), .auto_close = TRUE, .envir = parent.frame()) { if (! inherits(output, "connection")) output <- match.arg(output) app <- cliapp( theme = theme, user_theme = getOption("cli.user_theme"), output = output ) cliappenv$stack[[length(cliappenv$stack) + 1]] <- app if (.auto_close && !identical(.envir, globalenv())) { defer(stop_app(app = app), envir = .envir, priority = "first") } invisible(app) } #' @export #' @name start_app stop_app <- function(app = NULL) { if (is.null(app)) { cliappenv$stack <- utils::head(cliappenv$stack, -1) } else { if (!inherits(app, "cliapp")) { throw(cli_error( "{.arg app} must be a CLI app", "i" = "{.arg app} is {.type {app}}" )) } ndl <- format.default(app) nms <- vapply(cliappenv$stack, format.default, character(1)) if (! ndl %in% nms) { warning("No app to end") return() } wh <- which(nms == ndl)[1] cliappenv$stack <- utils::head(cliappenv$stack, wh - 1) } invisible() } #' @export #' @name start_app default_app <- function() { top <- utils::tail(cliappenv$stack, 1) if (length(top)) top[[1]] else NULL } cli/R/simple-theme.R0000644000176200001440000001250614752735214013754 0ustar liggesusers #' A simple CLI theme #' #' To use this theme, you can set it as the `cli.theme` option. #' Note that this is in addition to the builtin theme, which is still in #' effect. #' #' ```r #' options(cli.theme = cli::simple_theme()) #' ``` #' #' and then CLI apps started after this will use it as the default theme. #' You can also use it temporarily, in a div element: #' #' ```r #' cli_div(theme = cli::simple_theme()) #' ``` #' #' # Showcase #' #' ```{asciicast simple-theme} #' show <- cli_div(theme = cli::simple_theme()) #' #' cli_h1("Heading 1") #' cli_h2("Heading 2") #' cli_h3("Heading 3") #' #' cli_par() #' cli_alert_danger("Danger alert") #' cli_alert_warning("Warning alert") #' cli_alert_info("Info alert") #' cli_alert_success("Success alert") #' cli_alert("Alert for starting a process or computation", #' class = "alert-start") #' cli_end() #' #' cli_text("Packages and versions: {.pkg cli} {.version 1.0.0}.") #' cli_text("Time intervals: {.timestamp 3.4s}") #' #' cli_text("{.emph Emphasis} and {.strong strong emphasis}") #' #' cli_text("This is a piece of code: {.code sum(x) / length(x)}") #' cli_text("Function names: {.fn cli::simple_theme}") #' #' cli_text("Files: {.file /usr/bin/env}") #' cli_text("URLs: {.url https://r-project.org}") #' #' cli_h2("Longer code chunk") #' cli_par(class = "code R") #' cli_verbatim( #' '# window functions are useful for grouped mutates', #' 'mtcars %>%', #' ' group_by(cyl) %>%', #' ' mutate(rank = min_rank(desc(mpg)))') #' #' cli_end(show) #' ``` #' #' @param dark Whether the theme should be optimized for a dark #' background. If `"auto"`, then cli will try to detect this. #' Detection usually works in recent RStudio versions, and in iTerm #' on macOS, but not on other platforms. #' #' @seealso [themes], [builtin_theme()]. #' @export simple_theme <- function(dark = getOption("cli.theme_dark", "auto")) { dark <- detect_dark_theme(dark) list( h1 = list( "margin-top" = 1, "margin-bottom" = 0, color = "cyan", fmt = function(x) cli::rule(x, line_col = "cyan")), h2 = list( "margin-top" = 1, "margin-bottom" = 0, color = "cyan", fmt = function(x) paste0(symbol$line, " ", x, " ", symbol$line, symbol$line)), h3 = list( "margin-top" = 1, "margin-bottom" = 0, color = "cyan"), par = list("margin-top" = 0, "margin-bottom" = 1), ".alert-danger" = list( "background-color" = "red", color = "white", before = function() paste0(symbol$cross, " ") ), ".alert-warning" = list( color = "orange", "font-weight" = "bold", before = paste0("!", " ") ), ".alert-success" = list( before = function() paste0(col_green(symbol$tick), " ") ), ".alert-info" = list( before = function() paste0(col_cyan(symbol$info), " ") ), ".alert-start" = list( before = function() paste0(symbol$arrow_right, " ")), span.pkg = list( color = "blue", "font-weight" = "bold"), span.version = list(color = "blue"), span.emph = simple_theme_emph(), span.strong = list("font-weight" = "bold", "font-style" = "italic"), span.fun = utils::modifyList(simple_theme_code(dark), list(after = "()")), span.fn = utils::modifyList(simple_theme_code(dark), list(after = "()")), span.arg = simple_theme_code(dark), span.kbd = utils::modifyList(simple_theme_code(dark), list(before = "<", after = ">")), span.key = utils::modifyList(simple_theme_code(dark), list(before = "<", after = ">")), span.file = simple_theme_file(), span.path = simple_theme_file(), span.email = simple_theme_url(), span.url = utils::modifyList(simple_theme_url(), list(before = "<", after = ">")), span.var = simple_theme_code(dark), span.envvar = simple_theme_code(dark), span.timestamp = list(before = "[", after = "]", color = "grey") ) } simple_theme_emph <- function() { list("font-style" = "italic") } simple_theme_url <- function() { list(color = "blue") } simple_theme_code <- function(dark) { if (dark) { list("background-color" = "#232323", color = "#f0f0f0") } else{ list("background-color" = "#f8f8f8", color = "#202020") } } simple_theme_file <- function() { list(color = "blue") } simple_theme_r_code <- function(dark) { dark <- dark style <- if (dark) { make_ansi_style("#f0f0f0") } else { make_ansi_style("#202020") } function(x) { x <- ansi_strip(x) lines <- strsplit(x, "\n", fixed = TRUE)[[1]] fmd <- code_highlight(lines) style(fmd) } } is_iterm <- function() { isatty(stdout()) && Sys.getenv("TERM_PROGRAM", "") == "iTerm.app" } is_iterm_dark <- function() { if (is.null(clienv[["is_iterm_dark"]])) { clienv$is_iterm_dark <- tryCatch( error = function(x) FALSE, { osa <- ' tell application "iTerm2" tell current session of current window get background color end tell end tell ' out <- suppressWarnings(system2( "osascript", c("-e", shQuote(osa)), stdout = TRUE, stderr = TRUE )) nums <- scan(text = gsub(",", "", out, fixed = TRUE), quiet = TRUE) mean(nums) < 20000 }) } clienv[["is_iterm_dark"]] } cli/LICENSE.note0000644000176200001440000000110114557444176013004 0ustar liggesusers ## utf8lite Some parts of cli are based on the utf8lite library (https://github.com/patperry/utf8lite), which is licensed under the Apache License 2.0. In particular, * `src/utf8.c` contains parts modified from utf8lite, * `src/cli.h` contains parts modified from utf8lite, * The `src/graphbreak.h` and `src/charwidth` files are generated with scripts from utf8lite. ## vtparse The files `src/vtparse.h`, `src/vtparse.c`, `src/vtparse_table.h`, `src/vtparse_tablre.c` are in the public domain, see https://github.com/haberman/vtparse/ Pull request #1 is also included. cli/exec/0000755000176200001440000000000014752735214011757 5ustar liggesuserscli/exec/up.R0000755000176200001440000000300614752735214012530 0ustar liggesusers#! /usr/bin/env Rscript ## To get the async package: ## source("https://install-github.me/r-lib/async") setup_app <- function() { theme <- list("url" = list(color = "blue")) app <- cli::start_app(theme = theme, output = "stdout") } load_packages <- function() { tryCatch({ library(cli) library(async) library(docopt) }, error = function(e) { cli_alert_danger("The {.pkg async} and {.pkg docopt} packages are needed!") q(save = "no", status = 1) }) } up <- function(urls, timeout = 5) { load_packages() setup_app() chk_url <- async(function(url, ...) { http_head(url, ...)$ then(function(res) { if (res$status_code < 300) { cli_alert_success("{.url {url}} ({res$times[['total']]}s)") } else { cli_alert_danger("{.url {url}} (HTTP {res$status_code})") } })$ catch(error = function(err) { e <- if (grepl("timed out", err$message, fixed = TRUE)) "timed out" else "error" cli_alert_danger("{.url {url}} ({e})") }) }) invisible(synchronise( async_map(urls, chk_url, options = list(timeout = timeout)) )) } parse_arguments <- function() { "Usage: up.R [-t timeout] [URLS ...] up.R -h | --help Options: -t timeout Timeout for giving up on a site, in seconds [default: 5]. -h --help Print this help message Check if web sites are up. " -> doc docopt(doc) } if (is.null(sys.calls())) { load_packages() opts <- parse_arguments() up(opts$URLS, timeout = as.numeric(opts$t)) } cli/exec/outdated.R0000755000176200001440000000376114557444176013734 0ustar liggesusers#! /usr/bin/env Rscript ## To get the pkgcache package: ## source("https://install-github.me/r-lib/pkgcache") setup_app <- function() { theme <- list( "url" = list(color = "blue"), ".pkg" = list(color = "orange")) start_app(theme = theme, output = "stdout") } load_packages <- function() { tryCatch(suppressPackageStartupMessages({ library(cli) library(pkgcache) library(docopt) }), error = function(e) { cli_alert_danger("The {.pkg pkgcache} and {.pkg docopt} packages are needed!") q(save = "no", status = 1) }) } outdated <- function(lib = NULL, notcran = FALSE) { load_packages() setup_app() if (is.null(lib)) lib <- .libPaths()[1] inst <- utils::installed.packages(lib = lib) cli_alert_info("Getting repository metadata") repo <- meta_cache_list(rownames(inst)) if (!notcran) inst <- inst[inst[, "Package"] %in% repo$package, ] for (i in seq_len(nrow(inst))) { pkg <- inst[i, "Package"] iver <- inst[i, "Version"] if (! pkg %in% repo$package) { cli_alert_info("{.pkg {pkg}}: \tnot a CRAN/BioC package") next } rpkg <- repo[repo$package == pkg, ] newer <- rpkg[package_version(rpkg$version) > iver, ] if (!nrow(newer)) next nver <- package_version(newer$version) mnver <- max(nver) newest <- newer[mnver == nver, ] bin <- if (any(newest$platform != "source")) "bin" else "" src <- if (any(newest$platform == "source")) "src" else "" cli_alert_danger( "{.pkg {pkg}} \t{iver} {symbol$arrow_right} {mnver} {emph ({bin} {src})}") } } parse_arguments <- function() { "Usage: outdated.R [-l lib] [-x] outdated.R -h | --help Options: -x Print not CRAN/BioC packages as well -l lib Library directory, default is first directory in the lib path -h --help Print this help message Check for outdated packages in a package library. " -> doc docopt(doc) } if (is.null(sys.calls())) { load_packages() opts <- parse_arguments() outdated(opts$l, opts$x) } cli/exec/search.R0000755000176200001440000000402714557444176013364 0ustar liggesusers#! /usr/bin/env Rscript setup_app <- function() { theme <- list( "url" = list(color = "blue"), ".pkg" = list(color = "orange")) start_app(theme = theme, output = "stdout") } load_packages <- function() { tryCatch({ library(cli) library(pkgsearch) library(docopt) library(prettyunits) error = function(e) { cli_alert_danger( "The {.pkg pkgsearch}, {.pkg prettyunits} and {.pkg docopt} packages are needed!") q(save = "no", status = 1) } }) } search <- function(terms, from = 1, size = 5) { load_packages() setup_app() term <- paste(encodeString(quote = '"', terms), collapse = " ") result <- do_query(term, from = from, size = size) format_result(result, from = from, size = size) invisible() } `%||%` <- function(l, r) if (is.null(l)) r else l do_query <- function(query, from, size) { cli_alert_info("Searching...") pkg_search(query, from = from, size = size) } format_result <- function(obj, from, size) { meta <- attr(obj, "metadata") if (!meta$total) { cli_alert_danger("No results :(") return() } cli_alert_success("Found {meta$total} packages in {pretty_ms(meta$took)}") cli_text() cli_div(theme = list(ul = list("list-style-type" = ""))) cli_ol() lapply(seq_len(nrow(obj)), function(i) format_hit(obj[i,])) } format_hit <- function(hit) { ago <- vague_dt(Sys.time() - hit$date) cli_li() cli_text("{.pkg {hit$package}} {hit$version} -- {.emph {hit$title}}") cli_par() cli_text(hit$description) cli_text("{.emph {ago} by {hit$maintainer_name}}") } parse_arguments <- function() { "Usage: cransearch.R [-h | --help] [ -f from ] [ -n size ] ... Options: -h --help Print this help message -f first First hit to include -n size Number of hits to include Seach for CRAN packages on r-pkg.org " -> doc docopt(doc) } if (is.null(sys.calls())) { load_packages() opts <- parse_arguments() search(opts$term, from = as.numeric(opts$f %||% 1), size = as.numeric(opts$n %||% 5)) } cli/exec/news.R0000755000176200001440000000570414557444176013076 0ustar liggesusers#! /usr/bin/env Rscript setup_app <- function() { theme <- list( "url" = list(color = "blue"), ".pkg" = list(color = "orange"), "it" = list("margin-bottom" = 1)) start_app(theme = theme, output = "stdout") } load_packages <- function() { tryCatch({ library(cli) library(httr) library(jsonlite) library(prettyunits) library(glue) library(parsedate) library(docopt) }, error = function(e) { cli_alert_danger( "The {.pkg glue}, {.pkg httr}, {.pkg jsonlite}, {.pkg prettyunits},", " {.pkg parsedate} and {.pkg docopt} packages are needed!") q(save = "no", status = 1) }) } news <- function(n = 10, day = FALSE, week = FALSE, since = NULL, reverse = FALSE) { load_packages() setup_app() result <- if (day) news_day() else if (week) news_week() else if (!is.null(since)) news_since(since) else news_n(as.numeric(n)) if (reverse) result <- rev(result) format_results(result) invisible() } news_day <- function() { date <- format_iso_8601(Sys.time() - as.difftime(1, units="days")) ep <- glue("/-/pkgreleases?descending=true&endkey=%22{date}%22") do_query(ep) } news_week <- function() { date <- format_iso_8601(Sys.time() - as.difftime(7, units="days")) ep <- glue("/-/pkgreleases?descending=true&endkey=%22{date}%22") do_query(ep) } news_since <- function(since) { date <- format_iso_8601(parse_date(since)) ep <- glue("/-/pkgreleases?descending=true&endkey=%22{date}%22") do_query(ep) } news_n <- function(n) { ep <- glue("/-/pkgreleases?limit={n}&descending=true") do_query(ep) } do_query <- function(ep) { base <- "https://crandb.r-pkg.org" url <- glue("{base}{ep}") response <- GET(url) stop_for_status(response) fromJSON(content(response, as = "text"), simplifyVector = FALSE) } format_results <- function(results) { cli_div(theme = list(ul = list("list-style-type" = ""))) cli_ol() lapply(results, format_result) } parse_arguments <- function() { "Usage: news.R [-r | --reverse] [-n num ] news.R [-r | --reverse] --day | --week | --since date news.R [-h | --help] Options: -n num Show the last 'n' releases [default: 10]. --day Show releases in the last 24 hours --week Show relaases in the last 7 * 24 hours --since date Show releases since 'date' -r --reverse Reverse the order, show older on top -h --help Print this help message New package releases on CRAN " -> doc docopt(doc) } format_result <- function(result) { pkg <- result$package ago <- vague_dt(Sys.time() - parse_iso_8601(result$date)) url <- paste0("https://r-pkg.org/pkg/", pkg$Package) cli_li() cli_text("{.pkg {pkg$Package}} {pkg$Version} -- {ago} by {.emph {pkg$Maintainer}}") cli_text("{pkg$Title}") cli_text("{.url {url}}") } if (is.null(sys.calls())) { load_packages() opts <- parse_arguments() news(opts$n, opts$day, opts$week, opts$since, opts$reverse) } cli/src/0000755000176200001440000000000014752736621011625 5ustar liggesuserscli/src/errors.h0000644000176200001440000001301114557444176013312 0ustar liggesusers /* Informative error messages from C in R packages. * * Features: * - templating * - include the function name * - include the file name and line number of the error * - look up (localized) system error messages from errno on Unix, or for * POSIX functions on Windows. * - look up (localized) system error messages from GetLastError() * on Windows * * See the API below. */ #ifndef R_THROW_ERROR_H #define R_THROW_ERROR_H #ifndef _GNU_SOURCE #define _GNU_SOURCE 1 #endif #ifdef _WIN32 #include #else #include #endif #include /* Throw a generic (non-system) error. * * ARGUMENTS * ... Error message template, and values to be substituted into the * template. They are passed to `vsnprintf()`. * * EXAMPLES * If `fun` is a character string, then * * R_THROW_ERROR("`%s` must be a function", fun); * * will produce an error message like this: * * Error in set_mock(...): `old_fun` must be a function * @reassign.c:9 (reassign_function) */ #define R_THROW_ERROR(...) \ r_throw_error(__func__, __FILE__, __LINE__, __VA_ARGS__) SEXP r_throw_error(const char *func, const char *filename, int line, const char *msg, ...); #ifdef _WIN32 /* Throw a system error on Windows. * * DESCRIPTION * `R_THROW_SYSTEM_ERROR()` queries the error code via `GetLastError()`, * and constructs an error message that includes both the error code and * the (localized) error message. * * `R_THROW_SYSTEM_ERROR_CODE()` is similar, but you can specify the * error code explicitly. Use this if you already had to query the * error code before deciding to throw an error. * * ARGUMENTS * errorcode The Windows error code. Sometimes you need to query this * explicitly, because some `GetLastError()` codes are not errors. * ... Error message template, and values to be substituted into the * template. They are passed to `vsnprintf()`. * * EXAMPLES * This is a way to handle a `CreateFileW()` failure on Windows. * (Some details omitted for brevity.) * * HANDLE hnd = CreateFileW(filename, ...); * if (hnd == INVALID_HANDLE_VALUE) { * R_THROW_SYSTEM_ERROR("cannot open file `%ls`", filename); * } * * which will create an error message like this: * * Error in read_file(...): cannot open file `input.txt` * (system error 5, Access is denied.) @read.c:234 (read_file) */ #define R_THROW_SYSTEM_ERROR(...) \ r_throw_system_error(__func__, __FILE__, __LINE__, (-1), NULL, __VA_ARGS__) #define R_THROW_SYSTEM_ERROR_CODE(errorcode, ...) \ r_throw_system_error(__func__, __FILE__, __LINE__, (errorcode), NULL, __VA_ARGS__) SEXP r_throw_system_error(const char *func, const char *filename, int line, DWORD errorcode, const char *sysmsg, const char *msg, ...); /* Throw an error for a POSIX system call failure on Windows or in * portable code that is shared between Unix and Windows. * * DESCRIPTION * `R_THROW_POSIX_ERROR()` queries the error code from `errno`, and * constructs and error message and includes both the error code and * the localized error message. * * `R_THROW_POSIX_ERROR_CODE()` is similar, but you can pass in the * POSIX error code directly. * * Use these functions for POSIX system call failures in Windows. * You can also use them for code that is shared between Unix and * Windows. * * ARGUMENTS * errorcode The POSIX error code. * ... Error message template, and values to be substituted into the * template. They are passed to `vsnprintf()`. * * EXAMPLES * Here is a way to handle a `fopen()` failure on Windows or in * portable code: * * FILE infile = fopen(filename, "r"); * if (infile == NULL) { * R_THROW_POSIX_ERROR("cannot open `%s`", filename); * } * * which will create an error message like this: * * Error in read_file(...): cannot open file `input.txt` * (system error 13, Permission denied) @read.c:234 (read_file) */ #define R_THROW_POSIX_ERROR(...) \ r_throw_posix_error(__func__, __FILE__, __LINE__, errno, NULL, __VA_ARGS__) #define R_THROW_POSIX_ERROR_CODE(errorcode, ...) \ r_throw_posix_error(__func__, __FILE__, __LINE__, errorcode, NULL, __VA_ARGS__) SEXP r_throw_posix_error(const char *func, const char *filename, int line, int errorcode, const char *sysmsg, const char *msg, ...); #else /* See R_THROW_SYSTEM_ERROR(...) above. On Unix `R_THROW_SYSTEM_ERROR()` * is the same as `R_THROW_POSIX_ERROR()`, and `R_THROW_SYSTEM_ERROR_CODE()` * is the same as `R_THROW_POSIX_ERROR_CODE(). */ #define R_THROW_SYSTEM_ERROR(...) \ r_throw_system_error(__func__, __FILE__, __LINE__, errno, NULL, __VA_ARGS__) #define R_THROW_SYSTEM_ERROR_CODE(errorcode, ...) \ r_throw_system_error(__func__, __FILE__, __LINE__, errorcode, NULL, __VA_ARGS__) #define R_THROW_POSIX_ERROR(...) \ r_throw_system_error(__func__, __FILE__, __LINE__, errno, NULL, __VA_ARGS__) #define R_THROW_POSIX_ERROR_CODE(errorcode, ...) \ r_throw_system_error(__func__, __FILE__, __LINE__, errorcode, NULL, __VA_ARGS__) SEXP r_throw_system_error(const char *func, const char *filename, int line, int errorcode, const char *sysmsg, const char *msg, ...); #endif #endif cli/src/utils.c0000644000176200001440000000167514557444176013146 0ustar liggesusers #include #ifdef _WIN32 #include #include #endif #include #include "errors.h" #ifdef _WIN32 SEXP clic_getppid(void) { DWORD pid = GetCurrentProcessId(); HANDLE handle = NULL; PROCESSENTRY32W pe = { 0 }; pe.dwSize = sizeof(PROCESSENTRY32W); handle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (handle == INVALID_HANDLE_VALUE) { R_THROW_SYSTEM_ERROR("Cannot query parent pid"); } if (Process32FirstW(handle, &pe)) { do { if (pe.th32ProcessID == pid) { DWORD ppid = pe.th32ParentProcessID; CloseHandle(handle); return ScalarInteger(ppid); } } while (Process32NextW(handle, &pe)); } /* Should not get here */ CloseHandle(handle); R_THROW_ERROR("Cannot find my own process, internal error"); return R_NilValue; } #else SEXP clic_getppid(void) { pid_t pid = getppid(); return Rf_ScalarInteger(pid); } #endif cli/src/inst.c0000644000176200001440000000030014557444176012743 0ustar liggesusers#include #include // This file only tests that `inst/cli/progress.h` can be compiled // without issues void test(void) { cli_progress_bar(0, R_NilValue); } cli/src/md5.c0000644000176200001440000000514514557444176012467 0ustar liggesusers #include #include #define MD5_STATIC static #include "md5.h" #include "errors.h" #include "winfiles.h" #include #include #include static void bin2str(char *to, const unsigned char *p, size_t len) { static const char *hex = "0123456789abcdef"; for (; len--; p++) { *to++ = hex[p[0] >> 4]; *to++ = hex[p[0] & 0x0f]; } } SEXP clic_md5(SEXP strs) { md5_byte_t hash[16]; char hexhash[32]; md5_state_t ctx; R_xlen_t i, len = XLENGTH(strs); SEXP result = PROTECT(Rf_allocVector(STRSXP, len)); for (i = 0; i < len; i++) { const char *s = CHAR(STRING_ELT(strs, i)); md5_init(&ctx); md5_append(&ctx, (const md5_byte_t*) s, strlen(s)); md5_finish(&ctx, hash); bin2str(hexhash, hash, sizeof(hash)); SET_STRING_ELT( result, i, Rf_mkCharLenCE((const char*) hexhash, sizeof(hexhash), CE_UTF8) ); } UNPROTECT(1); return result; } SEXP clic_md5_raw(SEXP r) { Rbyte *ptr = RAW(r); Rbyte *end = ptr + XLENGTH(r); size_t step = SIZE_MAX < 0x40000000 ? SIZE_MAX & ~63 : 0x40000000; md5_state_t ctx; md5_byte_t hash[16]; char hexhash[32]; md5_init(&ctx); while (ptr < end) { Rbyte *nxt = ptr + step; if (nxt > end) nxt = end; md5_append(&ctx, (const md5_byte_t*) ptr, nxt - ptr); ptr = nxt; } md5_finish(&ctx, hash); bin2str(hexhash, hash, sizeof(hash)); return Rf_ScalarString(Rf_mkCharLenCE( (const char*) hexhash, sizeof(hexhash), CE_UTF8 )); } SEXP clic_md5_file(SEXP paths) { md5_byte_t hash[16]; char hexhash[32]; md5_state_t ctx; R_xlen_t i, len = XLENGTH(paths); #define BUFSIZE (1 * 1024*1024) char *buffer = R_alloc(1, BUFSIZE); SEXP result = PROTECT(Rf_allocVector(STRSXP, len)); for (i = 0; i < len; i++) { const char *cpath = CHAR(STRING_ELT(paths, i)); int fd = open_file(cpath, O_RDONLY); if (fd == -1) { R_THROW_SYSTEM_ERROR("Cannot open file `%s`", cpath); } md5_init(&ctx); ssize_t got = read(fd, buffer, BUFSIZE); if (got == -1) { close(fd); R_THROW_SYSTEM_ERROR("Cannot read from file `%s`", cpath); } while (got > 0) { md5_append(&ctx, (const md5_byte_t*) buffer, got); got = read(fd, buffer, BUFSIZE); if (got == -1) { close(fd); R_THROW_SYSTEM_ERROR("Cannot read from file `%s`", cpath); } } close(fd); md5_finish(&ctx, hash); bin2str(hexhash, hash, sizeof(hash)); SET_STRING_ELT( result, i, Rf_mkCharLenCE((const char*) hexhash, sizeof(hexhash), CE_UTF8) ); } UNPROTECT(1); return result; } cli/src/utf8.c0000644000176200001440000002600214557444176012663 0ustar liggesusers /* Much of this is adapted from the great utf8lite library: * https://github.com/patperry/utf8lite */ #include "charwidth.h" #include "graphbreak.h" #include "cli.h" #include "errors.h" void utf8lite_decode_utf8(const uint8_t **bufptr, int32_t *codeptr) { const uint8_t *ptr = *bufptr; int32_t code; uint_fast8_t ch; unsigned nc; ch = *ptr++; if (!(ch & 0x80)) { code = ch; nc = 0; } else if (!(ch & 0x20)) { code = ch & 0x1F; nc = 1; } else if (!(ch & 0x10)) { code = ch & 0x0F; nc = 2; } else { code = ch & 0x07; nc = 3; } while (nc-- > 0) { ch = *ptr++; if (ch == 0) R_THROW_ERROR("Incomplete UTF-8 character"); code = (code << 6) + (ch & 0x3F); } *bufptr = ptr; *codeptr = code; } void utf8lite_encode_utf8(int32_t code, uint8_t **bufptr) { uint8_t *ptr = *bufptr; int32_t x = code; if (x <= 0x7F) { *ptr++ = (uint8_t)x; } else if (x <= 0x07FF) { *ptr++ = (uint8_t)(0xC0 | (x >> 6)); *ptr++ = (uint8_t)(0x80 | (x & 0x3F)); } else if (x <= 0xFFFF) { *ptr++ = (uint8_t)(0xE0 | (x >> 12)); *ptr++ = (uint8_t)(0x80 | ((x >> 6) & 0x3F)); *ptr++ = (uint8_t)(0x80 | (x & 0x3F)); } else { *ptr++ = (uint8_t)(0xF0 | (x >> 18)); *ptr++ = (uint8_t)(0x80 | ((x >> 12) & 0x3F)); *ptr++ = (uint8_t)(0x80 | ((x >> 6) & 0x3F)); *ptr++ = (uint8_t)(0x80 | (x & 0x3F)); } *bufptr = ptr; } static int display_width_map[7] = { /* CHARWIDTH_NONE = */ 0, /* CHARWIDTH_IGNORABLE = */ 0, /* CHARWIDTH_MARK = */ 0, /* CHARWIDTH_NARROW = */ 1, /* CHARWIDTH_AMBIGUOUS = */ 1, /* CHARWIDTH_WIDE = */ 2, /* CHARWIDTH_EMOJI = */ 2 }; #define NEXT() do { \ iter->cnd = iter->nxt_ptr; \ if (*(iter->nxt_ptr) == '\0') { \ iter->nxt_prop = -1; \ } else { \ utf8lite_decode_utf8(&iter->nxt_ptr, &iter->nxt_code); \ iter->nxt_prop = graph_break(iter->nxt_code); \ } \ if (iter->cnd_width_done >= 0) { \ if (iter->nxt_cw >= 0) { \ if (!iter->cnd_width_done) { \ iter->cnd_width += display_width_map[iter->nxt_cw]; \ if (iter->nxt_cw == CHARWIDTH_EMOJI) { \ iter->cnd_width_done = 1; \ } \ } \ } \ if (iter->nxt_prop != -1) { \ iter->nxt_cw = charwidth(iter->nxt_code); \ } \ } \ } while (0) void clic_utf8_graphscan_make(struct grapheme_iterator *iter, const uint8_t *txt, int width) { iter->nxt_ptr = txt; iter->nxt_cw = -1; iter->cnd_width = 0; iter->cnd_width_done = -1 * (width == 0); NEXT(); } void clic_utf8_graphscan_next(struct grapheme_iterator *iter, uint8_t **ptr, int *width) { if (ptr) *ptr = (uint8_t*) iter->cnd; Start: // GB2: Break at the end of text if (iter->nxt_prop < 0) { goto Break; } switch (iter->nxt_prop) { case GRAPH_BREAK_CR: NEXT(); goto CR; case GRAPH_BREAK_CONTROL: case GRAPH_BREAK_LF: // Break after controls // GB4: (Newline | LF) + NEXT(); goto Break; case GRAPH_BREAK_L: NEXT(); goto L; case GRAPH_BREAK_LV: case GRAPH_BREAK_V: NEXT(); goto V; case GRAPH_BREAK_LVT: case GRAPH_BREAK_T: NEXT(); goto T; case GRAPH_BREAK_PREPEND: NEXT(); goto Prepend; case GRAPH_BREAK_INCB_CONSONANT: NEXT(); goto InCB_Consonant; case GRAPH_BREAK_EXTENDED_PICTOGRAPHIC: NEXT(); goto Extended_Pictographic; case GRAPH_BREAK_REGIONAL_INDICATOR: NEXT(); goto Regional_Indicator; case GRAPH_BREAK_EXTEND_OTHER: case GRAPH_BREAK_EXTEND_INCB_EXTEND: case GRAPH_BREAK_EXTEND_INCB_LINKER: case GRAPH_BREAK_SPACINGMARK: case GRAPH_BREAK_ZWJ: case GRAPH_BREAK_OTHER: NEXT(); goto MaybeBreak; } R_THROW_ERROR("internal error, unhandled grapheme break property"); CR: // GB3: Do not break within CRLF // GB4: Otherwise break after controls if (iter->nxt_prop == GRAPH_BREAK_LF) { NEXT(); } goto Break; L: // GB6: Do not break Hangul syllable sequences. switch (iter->nxt_prop) { case GRAPH_BREAK_L: NEXT(); goto L; case GRAPH_BREAK_V: case GRAPH_BREAK_LV: NEXT(); goto V; case GRAPH_BREAK_LVT: NEXT(); goto T; default: goto MaybeBreak; } V: // GB7: Do not break Hangul syllable sequences. switch (iter->nxt_prop) { case GRAPH_BREAK_V: NEXT(); goto V; case GRAPH_BREAK_T: NEXT(); goto T; default: goto MaybeBreak; } T: // GB8: Do not break Hangul syllable sequences. switch (iter->nxt_prop) { case GRAPH_BREAK_T: NEXT(); goto T; default: goto MaybeBreak; } Prepend: switch (iter->nxt_prop) { case GRAPH_BREAK_CONTROL: case GRAPH_BREAK_CR: case GRAPH_BREAK_LF: // GB5: break before controls goto Break; default: // GB9b: do not break after Prepend characters. goto Start; } InCB_Consonant: // GB0c: Do not break within certain combinations with Indic_Conjunct_Break (InCB)=Linker. while (iter->nxt_prop == GRAPH_BREAK_EXTEND_INCB_EXTEND || iter->nxt_prop == GRAPH_BREAK_ZWJ) { NEXT(); } if (iter->nxt_prop == GRAPH_BREAK_EXTEND_INCB_LINKER) { NEXT(); goto InCB_Consonant_Linker; } goto MaybeBreak; InCB_Consonant_Linker: // GB0c: Do not break within certain combinations with Indic_Conjunct_Break (InCB)=Linker. while (iter->nxt_prop == GRAPH_BREAK_EXTEND_INCB_EXTEND || iter->nxt_prop == GRAPH_BREAK_EXTEND_INCB_LINKER || iter->nxt_prop == GRAPH_BREAK_ZWJ) { NEXT(); } if (iter->nxt_prop == GRAPH_BREAK_INCB_CONSONANT) { NEXT(); goto InCB_Consonant; } goto MaybeBreak; Extended_Pictographic: // GB9: Do not break before extending characters while (iter->nxt_prop == GRAPH_BREAK_EXTEND_OTHER || iter->nxt_prop == GRAPH_BREAK_EXTEND_INCB_EXTEND || iter->nxt_prop == GRAPH_BREAK_EXTEND_INCB_LINKER) { NEXT(); } // GB9: Do not break before ZWJ if (iter->nxt_prop == GRAPH_BREAK_ZWJ) { NEXT(); // GB11: Do not break within emoji modifier sequences // or emoji zwj sequences. if (iter->nxt_prop == GRAPH_BREAK_EXTENDED_PICTOGRAPHIC) { NEXT(); goto Extended_Pictographic; } } goto MaybeBreak; Regional_Indicator: // Do not break within emoji flag sequences. That is, do not break // between regional indicator (RI) symbols if there is an odd number // of RI characters before the break point if (iter->nxt_prop == GRAPH_BREAK_REGIONAL_INDICATOR) { // GB12/13: [^RI] RI * RI NEXT(); } goto MaybeBreak; MaybeBreak: // GB9: Do not break before extending characters or ZWJ. // GB9a: Do not break before SpacingMark [extended grapheme clusters] // GB999: Otherwise, break everywhere switch (iter->nxt_prop) { case GRAPH_BREAK_EXTEND_OTHER: case GRAPH_BREAK_EXTEND_INCB_EXTEND: case GRAPH_BREAK_EXTEND_INCB_LINKER: case GRAPH_BREAK_SPACINGMARK: case GRAPH_BREAK_ZWJ: NEXT(); goto MaybeBreak; default: goto Break; } Break: if (width) *width = iter->cnd_width; iter->cnd_width = 0; if (iter->cnd_width_done > 0) iter->cnd_width_done = 0; return; } SEXP clic_utf8_display_width(SEXP x) { R_xlen_t i, len = XLENGTH(x); SEXP res = PROTECT(allocVector(INTSXP, len)); int *pres = INTEGER(res); for (i = 0; i < len; i++) { SEXP x1 = STRING_ELT(x, i); if (x1 == NA_STRING) { pres[i] = NA_INTEGER; } else { struct grapheme_iterator iter; const uint8_t *chr = (const uint8_t*) CHAR(x1); clic_utf8_graphscan_make(&iter, chr, /* width= */ 1); int len = 0; int width; while (iter.nxt_prop != -1) { clic_utf8_graphscan_next(&iter, NULL, &width); len += width; } pres[i] = len; } } UNPROTECT(1); return res; } SEXP clic_utf8_nchar_graphemes(SEXP x) { R_xlen_t i, len = XLENGTH(x); SEXP res = PROTECT(allocVector(INTSXP, len)); int *pres = INTEGER(res); for (i = 0; i < len; i++) { SEXP x1 = STRING_ELT(x, i); if (x1 == NA_STRING) { pres[i] = NA_INTEGER; } else { struct grapheme_iterator iter; const uint8_t *chr = (const uint8_t*) CHAR(x1); int len = 0; clic_utf8_graphscan_make(&iter, chr, /* width= */ 0); while (iter.nxt_prop != -1) { clic_utf8_graphscan_next(&iter, NULL, NULL); len ++; } pres[i] = len; } } UNPROTECT(1); return res; } SEXP clic_utf8_substr(SEXP x, SEXP sstart, SEXP sstop) { R_xlen_t i, len = XLENGTH(x); SEXP res = PROTECT(allocVector(STRSXP, len)); for (i = 0; i < len; i++) { SEXP x1 = STRING_ELT(x, i); if (x1 == NA_STRING) { SET_STRING_ELT(res, i, x1); } else { const uint8_t *str = (const uint8_t*) CHAR(x1); int pos = 1; int start = INTEGER(sstart)[i]; int stop = INTEGER(sstop)[i]; struct grapheme_iterator iter; /* Skip initial part */ clic_utf8_graphscan_make(&iter, (const uint8_t*) str, /* width = */ 0); while (pos < start && iter.nxt_prop != -1) { clic_utf8_graphscan_next(&iter, NULL, NULL); pos++; } const char* from = (const char*) iter.cnd; /* Iterate to the end */ while (pos <= stop && iter.nxt_prop != -1) { clic_utf8_graphscan_next(&iter, NULL, NULL); pos++; } const char *to = (const char*) iter.cnd; if (from < to) { SET_STRING_ELT(res, i, Rf_mkCharLenCE(from, to - from, CE_UTF8)); } } } UNPROTECT(1); return res; } SEXP clic_utf8_graphemes(SEXP x) { R_xlen_t i, len = XLENGTH(x); SEXP res = PROTECT(allocVector(VECSXP, len)); for (i = 0; i < len; i++) { SEXP x1 = STRING_ELT(x, i); if (x1 == NA_STRING) { SET_VECTOR_ELT(res, i, Rf_ScalarString(x1)); } else { const uint8_t *str = (const uint8_t*) CHAR(x1); struct grapheme_iterator iter; SEXP pieces = PROTECT(allocVector(STRSXP, strlen((const char*) str))); R_xlen_t idx = 0; uint8_t *start = 0; clic_utf8_graphscan_make(&iter, str, /* width = */ 0); while (iter.nxt_prop != -1) { clic_utf8_graphscan_next(&iter, &start, NULL); SET_STRING_ELT( pieces, idx++, Rf_mkCharLenCE((const char*) start, iter.cnd - start, CE_UTF8) ); } SET_VECTOR_ELT(res, i, PROTECT(Rf_xlengthgets(pieces, idx))); UNPROTECT(2); } } UNPROTECT(1); return res; } cli/src/tty.c0000644000176200001440000000226714557444176012624 0ustar liggesusers #include "cli.h" #include "errors.h" #include "cleancall.h" #ifdef WIN32 #include #else #include #include #include #include #endif SEXP clic_tty_size(void) { SEXP result = PROTECT(Rf_allocVector(INTSXP, 2)); #ifdef WIN32 CONSOLE_SCREEN_BUFFER_INFO info; BOOL ok = GetConsoleScreenBufferInfo( GetStdHandle(STD_OUTPUT_HANDLE), &info ); if (!ok) R_THROW_SYSTEM_ERROR("Cannot determine terminal size"); INTEGER(result)[0] = info.srWindow.Right - info.srWindow.Left + 1; INTEGER(result)[1] = info.srWindow.Bottom - info.srWindow.Top + 1; #elif defined(TIOCGWINSZ) struct winsize w; int err = ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); if (err == -1) R_THROW_SYSTEM_ERROR("Cannot determine terminal size"); INTEGER(result)[0] = w.ws_col; INTEGER(result)[1] = w.ws_row; #elif defined(TIOCGSIZE) struct ttysize ts; int err = ioctl(STDOUT_FILENO, TIOCGSIZE, &ts); if (err == -1) R_THROW_SYSTEM_ERROR("Cannot determine terminal size"); INTEGER(result)[0] = ts.ts_cols; INTEGER(result)[1] = ts.ts_rows; #else R_THROW_ERROR("Don't know how to determine terminal size"); #endif UNPROTECT(1); return result; } cli/src/charwidth.h0000644000176200001440000054465714557444176014004 0ustar liggesusers/* This file is automatically generated. DO NOT EDIT! Instead, edit gen-charwidth.py and re-run. */ /* * Unicode East_Asian_Width property values. * * Defined in UAX #11 "East Asian Width" * * http://www.unicode.org/reports/tr11/ * * We use the two-stage lookup strategy described at * * http://www.strchr.com/multi-stage_tables * */ #ifndef CHARWIDTH_H #define CHARWIDTH_H #include enum charwidth_prop { CHARWIDTH_NONE = 0, CHARWIDTH_IGNORABLE = 1, CHARWIDTH_MARK = 2, CHARWIDTH_NARROW = 3, CHARWIDTH_AMBIGUOUS = 4, CHARWIDTH_WIDE = 5, CHARWIDTH_EMOJI = 6 }; static const uint8_t charwidth_stage1[] = { /* U+0000 */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* U+0800 */ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, /* U+1000 */ 32, 33, 34, 35, 36, 37, 38, 39, 35, 35, 35, 35, 35, 40, 41, 42, /* U+1800 */ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 35, 53, 35, 35, 54, 55, /* U+2000 */ 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, /* U+2800 */ 35, 35, 35, 35, 35, 35, 72, 73, 35, 74, 75, 76, 77, 78, 79, 80, /* U+3000 */ 81, 82, 83, 84, 85, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, /* U+3800 */ 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, /* U+4000 */ 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, /* U+4800 */ 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 86, 79, 79, 79, 79, /* U+5000 */ 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, /* U+5800 */ 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, /* U+6000 */ 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, /* U+6800 */ 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, /* U+7000 */ 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, /* U+7800 */ 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, /* U+8000 */ 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, /* U+8800 */ 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, /* U+9000 */ 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, /* U+9800 */ 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, /* U+A000 */ 79, 79, 79, 79, 79, 79, 79, 79, 79, 87, 35, 35, 88, 89, 35, 90, /* U+A800 */ 91, 92, 93, 94, 95, 96, 97, 98, 79, 79, 79, 79, 79, 79, 79, 79, /* U+B000 */ 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, /* U+B800 */ 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, /* U+C000 */ 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, /* U+C800 */ 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, /* U+D000 */ 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 99, /* U+D800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+E000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+E800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+F000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+F800 */100,100, 79, 79,101,102,103,104, 35, 35, 35,105,106,107,108,109, /* U+10000 */110,111,112,113,100,114,115,116, 35,117,118,119, 35, 35,120,121, /* U+10800 */122,123,124,125,126,127,128,129,130,131,132,100,133,134,135,136, /* U+11000 */137,138,139,140,141,142,143,100,144,145,100,146,147,148,149,100, /* U+11800 */150,151,152,153,154,155,156,100,157,158,159,160,100,161,162,163, /* U+12000 */ 35, 35, 35, 35, 35, 35, 35,164,165, 35,166,100,100,100,100,100, /* U+12800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,167, /* U+13000 */ 35, 35, 35, 35, 35, 35, 35, 35,168,100,100,100,100,100,100,100, /* U+13800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+14000 */100,100,100,100,100,100,100,100, 35, 35, 35, 35,169,100,100,100, /* U+14800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+15000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+15800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+16000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+16800 */ 35, 35, 35, 35,170,171,172,173,100,100,100,100,174,175,176,177, /* U+17000 */ 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, /* U+17800 */ 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, /* U+18000 */ 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79,178, /* U+18800 */ 79, 79, 79, 79, 79, 79, 79, 79, 79,179,180,100,100,100,100,100, /* U+19000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+19800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+1A000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+1A800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,181, /* U+1B000 */ 79, 79,182, 79, 79,183,100,100,100,100,100,100,100,100,100,100, /* U+1B800 */100,100,100,100,100,100,100,100,184,185,100,100,100,100,100,100, /* U+1C000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+1C800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,186,166, /* U+1D000 */ 35,187,188,189,190,191,192,100,193,194,195, 35, 35,196, 35,197, /* U+1D800 */ 35, 35, 35, 35,198,199,100,100,100,100,100,100,100,100,200,100, /* U+1E000 */201,202,203,100,100,204,100,100,100,205,100,100,100,100,100,206, /* U+1E800 */ 35,207,208,100,100,100,100,100,209,210,211,100,212,213,100,100, /* U+1F000 */214,215,216,217,218,100,219,220,221,222,223,224,225,226,227,228, /* U+1F800 */229,230,231,232,233,234, 35,235,100,100,100,100,100,100,100,100, /* U+20000 */ 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, /* U+20800 */ 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, /* U+21000 */ 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, /* U+21800 */ 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, /* U+22000 */ 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, /* U+22800 */ 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, /* U+23000 */ 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, /* U+23800 */ 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, /* U+24000 */ 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, /* U+24800 */ 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, /* U+25000 */ 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, /* U+25800 */ 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, /* U+26000 */ 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, /* U+26800 */ 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, /* U+27000 */ 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, /* U+27800 */ 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, /* U+28000 */ 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, /* U+28800 */ 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, /* U+29000 */ 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, /* U+29800 */ 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, /* U+2A000 */ 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79,236, 79, 79, /* U+2A800 */ 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, /* U+2B000 */ 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79,237, 79, /* U+2B800 */238, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, /* U+2C000 */ 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, /* U+2C800 */ 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79,239, 79, 79, /* U+2D000 */ 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, /* U+2D800 */ 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, /* U+2E000 */ 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, /* U+2E800 */ 79, 79, 79, 79, 79, 79, 79,240, 79, 79, 79, 79,241,100,100,100, /* U+2F000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+2F800 */ 79, 79, 79, 79,242,100,100,100,100,100,100,100,100,100,100,100, /* U+30000 */ 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, /* U+30800 */ 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, /* U+31000 */ 79, 79, 79, 79, 79, 79,243, 79, 79, 79, 79, 79, 79, 79, 79, 79, /* U+31800 */ 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, /* U+32000 */ 79, 79, 79, 79, 79, 79, 79,244,100,100,100,100,100,100,100,100, /* U+32800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+33000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+33800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+34000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+34800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+35000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+35800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+36000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+36800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+37000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+37800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+38000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+38800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+39000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+39800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+3A000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+3A800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+3B000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+3B800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+3C000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+3C800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+3D000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+3D800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+3E000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+3E800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+3F000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+3F800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+40000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+40800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+41000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+41800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+42000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+42800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+43000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+43800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+44000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+44800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+45000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+45800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+46000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+46800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+47000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+47800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+48000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+48800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+49000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+49800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+4A000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+4A800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+4B000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+4B800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+4C000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+4C800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+4D000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+4D800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+4E000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+4E800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+4F000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+4F800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+50000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+50800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+51000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+51800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+52000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+52800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+53000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+53800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+54000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+54800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+55000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+55800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+56000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+56800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+57000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+57800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+58000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+58800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+59000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+59800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+5A000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+5A800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+5B000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+5B800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+5C000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+5C800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+5D000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+5D800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+5E000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+5E800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+5F000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+5F800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+60000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+60800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+61000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+61800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+62000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+62800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+63000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+63800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+64000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+64800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+65000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+65800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+66000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+66800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+67000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+67800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+68000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+68800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+69000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+69800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+6A000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+6A800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+6B000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+6B800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+6C000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+6C800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+6D000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+6D800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+6E000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+6E800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+6F000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+6F800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+70000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+70800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+71000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+71800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+72000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+72800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+73000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+73800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+74000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+74800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+75000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+75800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+76000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+76800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+77000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+77800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+78000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+78800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+79000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+79800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+7A000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+7A800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+7B000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+7B800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+7C000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+7C800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+7D000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+7D800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+7E000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+7E800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+7F000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+7F800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+80000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+80800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+81000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+81800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+82000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+82800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+83000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+83800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+84000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+84800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+85000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+85800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+86000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+86800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+87000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+87800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+88000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+88800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+89000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+89800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+8A000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+8A800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+8B000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+8B800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+8C000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+8C800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+8D000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+8D800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+8E000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+8E800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+8F000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+8F800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+90000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+90800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+91000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+91800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+92000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+92800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+93000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+93800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+94000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+94800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+95000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+95800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+96000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+96800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+97000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+97800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+98000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+98800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+99000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+99800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+9A000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+9A800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+9B000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+9B800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+9C000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+9C800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+9D000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+9D800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+9E000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+9E800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+9F000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+9F800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+A0000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+A0800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+A1000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+A1800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+A2000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+A2800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+A3000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+A3800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+A4000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+A4800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+A5000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+A5800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+A6000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+A6800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+A7000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+A7800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+A8000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+A8800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+A9000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+A9800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+AA000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+AA800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+AB000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+AB800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+AC000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+AC800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+AD000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+AD800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+AE000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+AE800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+AF000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+AF800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+B0000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+B0800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+B1000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+B1800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+B2000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+B2800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+B3000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+B3800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+B4000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+B4800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+B5000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+B5800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+B6000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+B6800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+B7000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+B7800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+B8000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+B8800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+B9000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+B9800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+BA000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+BA800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+BB000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+BB800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+BC000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+BC800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+BD000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+BD800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+BE000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+BE800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+BF000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+BF800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+C0000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+C0800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+C1000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+C1800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+C2000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+C2800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+C3000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+C3800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+C4000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+C4800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+C5000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+C5800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+C6000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+C6800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+C7000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+C7800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+C8000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+C8800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+C9000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+C9800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+CA000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+CA800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+CB000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+CB800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+CC000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+CC800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+CD000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+CD800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+CE000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+CE800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+CF000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+CF800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+D0000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+D0800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+D1000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+D1800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+D2000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+D2800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+D3000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+D3800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+D4000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+D4800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+D5000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+D5800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+D6000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+D6800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+D7000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+D7800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+D8000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+D8800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+D9000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+D9800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+DA000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+DA800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+DB000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+DB800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+DC000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+DC800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+DD000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+DD800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+DE000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+DE800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+DF000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+DF800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+E0000 */245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245, /* U+E0800 */245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245, /* U+E1000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+E1800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+E2000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+E2800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+E3000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+E3800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+E4000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+E4800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+E5000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+E5800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+E6000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+E6800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+E7000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+E7800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+E8000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+E8800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+E9000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+E9800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+EA000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+EA800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+EB000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+EB800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+EC000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+EC800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+ED000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+ED800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+EE000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+EE800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+EF000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+EF800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+F0000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+F0800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+F1000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+F1800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+F2000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+F2800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+F3000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+F3800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+F4000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+F4800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+F5000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+F5800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+F6000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+F6800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+F7000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+F7800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+F8000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+F8800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+F9000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+F9800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+FA000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+FA800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+FB000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+FB800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+FC000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+FC800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+FD000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+FD800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+FE000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+FE800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+FF000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+FF800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+100000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+100800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+101000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+101800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+102000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+102800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+103000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+103800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+104000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+104800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+105000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+105800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+106000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+106800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+107000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+107800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+108000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+108800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+109000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+109800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+10A000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+10A800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+10B000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+10B800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+10C000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+10C800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+10D000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+10D800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+10E000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+10E800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+10F000 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, /* U+10F800 */100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100 }; static const int8_t charwidth_stage2[][128] = { /* block 0 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0 }, /* block 1 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 4, 3, 3, 4, 3, 3, 4, 4, 3, 4, 3, 3, 1, 4, 3, 4, 4, 4, 4, 4, 3, 4, 4, 4, 4, 4, 3, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 3, 3, 3, 3, 3, 4, 4, 3, 3, 3, 3, 3, 4, 4, 4, 4, 3, 3, 3, 3, 4, 3, 4, 4, 4, 3, 4, 4, 3, 3, 4, 3, 4, 4, 3, 3, 3, 4, 4, 4, 4, 3, 4, 3, 4, 3 }, /* block 2 */ { 3, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 4, 3, 3, 3, 3, 3, 3, 3, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 3, 3, 3, 4, 3, 3, 3, 3, 3, 4, 4, 4, 3, 3, 3, 3, 4, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 3, 4, 3, 3, 3, 4, 4, 4, 4, 3, 4, 3, 3, 3, 3, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 3, 3, 3, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, /* block 3 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, /* block 4 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, /* block 5 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 3, 4, 3, 4, 4, 4, 3, 4, 3, 3, 4, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 3, 4, 3, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, /* block 6 */ { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 3, 3, 3, 3, 3, 3 }, /* block 7 */ { 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 0, 3, 0, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, /* block 8 */ { 3, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, /* block 9 */ { 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, /* block 10 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, /* block 11 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 3, 3, 3, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 3, 2, 2, 3, 2, 2, 3, 2, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 12 */ { 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, /* block 13 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 3, 3, 2, 2, 3, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, /* block 14 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 2, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, /* block 15 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 0, 0, 2, 3, 3 }, /* block 16 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 3, 2, 2, 2, 2, 2, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 0, 0, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, /* block 17 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 2, 2, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 }, /* block 18 */ { 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 3, 2, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 2, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, /* block 19 */ { 3, 2, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 3, 3, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 0, 3, 0, 0, 0, 3, 3, 3, 3, 0, 0, 2, 3, 3, 3, 3, 2, 2, 2, 2, 0, 0, 3, 3, 0, 0, 3, 3, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 3, 3, 0, 3, 3, 3, 2, 2, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 0 }, /* block 20 */ { 0, 2, 2, 3, 0, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 3, 3, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 0, 3, 3, 0, 3, 3, 0, 0, 2, 0, 3, 3, 3, 2, 2, 0, 0, 0, 0, 2, 2, 0, 0, 2, 2, 2, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 3, 3, 3, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 21 */ { 0, 2, 2, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 0, 3, 3, 3, 3, 3, 0, 0, 2, 3, 3, 3, 3, 2, 2, 2, 2, 2, 0, 2, 2, 3, 0, 3, 3, 2, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 2, 2, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 3, 2, 2, 2, 2, 2, 2 }, /* block 22 */ { 0, 2, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 3, 3, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 0, 3, 3, 3, 3, 3, 0, 0, 2, 3, 3, 2, 3, 2, 2, 2, 2, 0, 0, 3, 3, 0, 0, 3, 3, 2, 0, 0, 0, 0, 0, 0, 0, 2, 2, 3, 0, 0, 0, 0, 3, 3, 0, 3, 3, 3, 2, 2, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 23 */ { 0, 0, 2, 3, 0, 3, 3, 3, 3, 3, 3, 0, 0, 0, 3, 3, 3, 0, 3, 3, 3, 3, 0, 0, 0, 3, 3, 0, 3, 0, 3, 3, 0, 0, 0, 3, 3, 0, 0, 0, 3, 3, 3, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 3, 3, 2, 3, 3, 0, 0, 0, 3, 3, 3, 0, 3, 3, 3, 2, 0, 0, 3, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0 }, /* block 24 */ { 2, 3, 3, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 2, 3, 2, 2, 2, 3, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 3, 3, 3, 0, 0, 3, 0, 0, 3, 3, 2, 2, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, /* block 25 */ { 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 0, 0, 2, 3, 3, 2, 3, 3, 3, 3, 3, 0, 2, 3, 3, 0, 3, 3, 2, 2, 0, 0, 0, 0, 0, 0, 0, 3, 3, 0, 0, 0, 0, 0, 0, 3, 3, 0, 3, 3, 2, 2, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 26 */ { 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 3, 3, 3, 3, 2, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 2, 3, 3, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, /* block 27 */ { 0, 2, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 0, 0, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 2, 0, 0, 0, 0, 3, 3, 3, 2, 2, 2, 0, 2, 0, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 28 */ { 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 3, 3, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 29 */ { 0, 3, 3, 0, 3, 0, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 0, 0, 3, 3, 3, 3, 3, 0, 3, 0, 2, 2, 2, 2, 2, 2, 2, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 30 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 3, 2, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3 }, /* block 31 */ { 2, 2, 2, 2, 2, 3, 2, 2, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 3, 3, 3, 3, 3, 3, 3, 3, 2, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 32 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 3, 2, 2, 3, 3, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 3, 3, 3, 3, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, /* block 33 */ { 3, 3, 2, 3, 3, 2, 2, 3, 3, 3, 3, 3, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 0, 0, 0, 0, 0, 3, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, /* block 34 */ { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, /* block 35 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, /* block 36 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 0, 0, 3, 3, 3, 3, 3, 3, 3, 0, 3, 0, 3, 3, 3, 3, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, /* block 37 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 0, 0, 3, 3, 3, 3, 3, 3, 3, 0, 3, 0, 3, 3, 3, 3, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, /* block 38 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0 }, /* block 39 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 3, 3, 3, 3, 3, 3, 0, 0 }, /* block 40 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0 }, /* block 41 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 42 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 3, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 2, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0 }, /* block 43 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0 }, /* block 44 */ { 3, 3, 3, 3, 3, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 3, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 45 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 2, 2, 2, 3, 3, 3, 3, 2, 2, 3, 3, 3, 0, 0, 0, 0, 3, 3, 2, 3, 3, 3, 3, 3, 3, 2, 2, 2, 0, 0, 0, 0, 3, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 46 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, /* block 47 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 3, 3, 2, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 3, 2, 2, 2, 2, 2, 2, 2, 0, 2, 3, 2, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 2 }, /* block 48 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 49 */ { 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 3, 2, 2, 2, 2, 2, 3, 2, 3, 3, 3, 3, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0 }, /* block 50 */ { 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 3, 3, 2, 2, 3, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 3, 2, 2, 3, 3, 3, 2, 3, 2, 2, 2, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3 }, /* block 51 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 2, 2, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, /* block 52 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 2, 3, 3, 3, 3, 3, 3, 2, 3, 3, 3, 2, 2, 3, 0, 0, 0, 0, 0 }, /* block 53 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 }, /* block 54 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 3, 3, 3, 3, 3, 3, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 3, 3, 3, 3, 3, 3, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 0, 3, 0, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0 }, /* block 55 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0 }, /* block 56 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 4, 3, 3, 4, 4, 4, 4, 3, 4, 4, 3, 3, 4, 4, 3, 3, 4, 4, 4, 3, 4, 4, 4, 4, 0, 0, 1, 1, 1, 1, 1, 3, 4, 3, 4, 4, 3, 4, 3, 3, 3, 3, 3, 4, 3, 3, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 0, 0, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4 }, /* block 57 */ { 3, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 58 */ { 3, 3, 3, 4, 3, 4, 3, 3, 3, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 3, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 3, 3, 3, 4, 3, 3, 3, 3, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3 }, /* block 59 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 3, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, /* block 60 */ { 4, 3, 4, 4, 3, 3, 3, 4, 4, 3, 3, 4, 3, 3, 3, 4, 3, 4, 3, 3, 3, 4, 3, 3, 3, 3, 4, 3, 3, 4, 4, 4, 4, 3, 3, 4, 3, 4, 3, 4, 4, 4, 4, 4, 4, 3, 4, 3, 3, 3, 3, 3, 4, 4, 4, 4, 3, 3, 3, 3, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 3, 3, 4, 3, 3, 3, 3, 3, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 3, 3, 4, 4, 4, 4, 3, 3, 4, 4, 3, 3, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, /* block 61 */ { 3, 3, 4, 4, 3, 3, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 3, 3, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, /* block 62 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 3, 3, 3, 3, 3, 3, 6, 6, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 5, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, /* block 63 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 3, 3, 3, 6, 3, 3, 6, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, /* block 64 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 }, /* block 65 */ { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 }, /* block 66 */ { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, /* block 67 */ { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 3, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 3, 3, 4, 4, 3, 3, 3, 3, 4, 4, 3, 3, 4, 4, 3, 3, 3, 3, 4, 4, 4, 3, 3, 4, 3, 3, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 6, 6, 3 }, /* block 68 */ { 3, 3, 3, 3, 3, 4, 4, 3, 3, 4, 3, 3, 3, 3, 4, 4, 3, 3, 3, 3, 6, 6, 3, 3, 3, 3, 3, 3, 4, 3, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 4, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 3, 4, 4, 4, 3, 4, 4, 4, 4, 3, 4, 4, 3, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 6 }, /* block 69 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 6, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 3, 6, 3, 3, 3, 3, 3, 3, 3, 3, 6, 6, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 6, 6, 4, 3, 3, 3, 3, 6, 6, 4, 4, 4, 4, 4, 4, 4, 4, 6, 4, 4, 4, 4, 4, 6, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 4, 3, 3, 3, 3, 4, 4, 6, 4, 4, 4, 4, 4, 4, 4, 6, 6, 4, 6, 4, 4, 4, 4, 6, 4, 4, 6, 4, 4 }, /* block 70 */ { 3, 3, 3, 3, 3, 6, 3, 3, 3, 3, 6, 6, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 6, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 6, 3, 6, 3, 3, 3, 3, 6, 6, 6, 3, 6, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 }, /* block 71 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 6, 6, 6, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 6, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 6, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, /* block 72 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 6, 6, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 6, 3, 3, 3, 3, 6, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, /* block 73 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, /* block 74 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 3, 3, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3 }, /* block 75 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 0, 0, 0, 0, 0, 3, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2 }, /* block 76 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 }, /* block 77 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 78 */ { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 79 */ { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 }, /* block 80 */ { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 }, /* block 81 */ { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 3, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 }, /* block 82 */ { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 2, 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 }, /* block 83 */ { 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 1, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 }, /* block 84 */ { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 }, /* block 85 */ { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 }, /* block 86 */ { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, /* block 87 */ { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, /* block 88 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3 }, /* block 89 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 90 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 3, 3, 0, 3, 0, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, /* block 91 */ { 3, 3, 2, 3, 3, 3, 2, 3, 3, 3, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 3, 3, 3, 3, 3, 2, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 92 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2 }, /* block 93 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0 }, /* block 94 */ { 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 3, 3, 2, 2, 2, 2, 3, 3, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0 }, /* block 95 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 3, 3, 2, 2, 3, 3, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 2, 3, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 3, 3, 3 }, /* block 96 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 3, 2, 2, 2, 3, 3, 2, 2, 3, 3, 3, 3, 3, 2, 2, 3, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 97 */ { 0, 3, 3, 3, 3, 3, 3, 0, 0, 3, 3, 3, 3, 3, 3, 0, 0, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, /* block 98 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 3, 3, 2, 3, 3, 3, 3, 2, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0 }, /* block 99 */ { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0 }, /* block 100 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 101 */ { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 }, /* block 102 */ { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 103 */ { 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 0, 3, 0, 3, 3, 0, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, /* block 104 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, /* block 105 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, /* block 106 */ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 5, 5, 5, 5, 0, 0, 0, 0, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, /* block 107 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 1 }, /* block 108 */ { 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, /* block 109 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 3, 3, 3, 3, 3, 3, 0, 0, 3, 3, 3, 3, 3, 3, 0, 0, 3, 3, 3, 3, 3, 3, 0, 0, 3, 3, 3, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 0, 3, 3, 3, 3, 3, 3, 3, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 3, 4, 0, 0 }, /* block 110 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 111 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0 }, /* block 112 */ { 3, 3, 3, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, /* block 113 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 0, 0 }, /* block 114 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0 }, /* block 115 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0 }, /* block 116 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 117 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0 }, /* block 118 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3 }, /* block 119 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 120 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 121 */ { 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 122 */ { 3, 3, 3, 3, 3, 3, 0, 0, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 0, 0, 0, 3, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, /* block 123 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3 }, /* block 124 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 125 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, /* block 126 */ { 3, 2, 2, 2, 0, 2, 2, 0, 0, 0, 0, 0, 2, 2, 2, 2, 3, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 2, 2, 2, 0, 0, 0, 0, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, /* block 127 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 128 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3 }, /* block 129 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 130 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 131 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3 }, /* block 132 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 133 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0 }, /* block 134 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 2, 2, 3, 0, 0, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2 }, /* block 135 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, /* block 136 */ { 3, 3, 2, 2, 2, 2, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 137 */ { 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 3, 3, 2, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2 }, /* block 138 */ { 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 3, 3, 2, 2, 3, 3, 2, 3, 3, 3, 3, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0 }, /* block 139 */ { 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 140 */ { 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 3, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 141 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 3, 3, 2, 3, 2, 2, 3, 3, 3, 3, 3, 3, 2, 3, 3, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 142 */ { 3, 3, 3, 3, 3, 3, 3, 0, 3, 0, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0 }, /* block 143 */ { 2, 2, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 3, 3, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 0, 3, 3, 3, 3, 3, 0, 2, 2, 3, 3, 3, 2, 3, 3, 3, 3, 0, 0, 3, 3, 0, 0, 3, 3, 3, 0, 0, 3, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 0, 0, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 144 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 2, 2, 2, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 2, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 145 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 3, 2, 3, 3, 3, 3, 2, 2, 3, 2, 2, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 146 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 0, 0, 3, 3, 3, 3, 2, 2, 3, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 147 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 2, 3, 2, 2, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 148 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 3, 2, 3, 3, 2, 2, 2, 2, 2, 2, 3, 2, 3, 3, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 149 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 2, 2, 2, 3, 3, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 150 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 151 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3 }, /* block 152 */ { 3, 3, 3, 3, 3, 3, 3, 0, 0, 3, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 0, 0, 2, 2, 3, 2, 3, 3, 3, 3, 2, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 153 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 0, 0, 2, 2, 3, 3, 3, 3, 2, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 154 */ { 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 3, 3, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 2, 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, 2, 2, 2, 2, 2, 3, 3, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, /* block 155 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0 }, /* block 156 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 157 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 3, 2, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, /* block 158 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 3, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 159 */ { 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 0, 0, 0, 2, 0, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 3, 2, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 0, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, /* block 160 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 2, 2, 0, 3, 3, 2, 3, 2, 3, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 161 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0 }, /* block 162 */ { 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 0, 0, 0, 3, 3, 2, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 163 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3 }, /* block 164 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 165 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 166 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 167 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 168 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 169 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 170 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, /* block 171 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 2, 2, 2, 2, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 172 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 3, 3, 3 }, /* block 173 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 174 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, /* block 175 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 176 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, /* block 177 */ { 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 178 */ { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 179 */ { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 180 */ { 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 181 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 0, 5, 5, 5, 5, 5, 5, 5, 0, 5, 5, 0 }, /* block 182 */ { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 }, /* block 183 */ { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0 }, /* block 184 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0 }, /* block 185 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 3, 2, 2, 3, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 186 */ { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, /* block 187 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 188 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2 }, /* block 189 */ { 2, 2, 2, 3, 3, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 190 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 191 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 192 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0 }, /* block 193 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, /* block 194 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 0, 0, 3, 0, 0, 3, 3, 0, 0, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 0, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, /* block 195 */ { 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 0, 3, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, /* block 196 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, /* block 197 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, /* block 198 */ { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, /* block 199 */ { 3, 3, 3, 3, 2, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 200 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 201 */ { 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 0, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 202 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 203 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 204 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 3 }, /* block 205 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0 }, /* block 206 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 0, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0 }, /* block 207 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 208 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 3, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 209 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, /* block 210 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 211 */ { 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 212 */ { 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 0, 3, 0, 0, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 0, 3, 0, 3, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 3, 0, 3, 0, 3, 0, 3, 3, 3, 0, 3, 3, 0, 3, 0, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 3, 0, 3, 0, 0, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 0, 3, 3, 3, 3, 0, 3, 0 }, /* block 213 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 3, 3, 3, 0, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 214 */ { 3, 3, 3, 3, 6, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, /* block 215 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 6, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 216 */ { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 }, /* block 217 */ { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 6, 4, 4, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, /* block 218 */ { 5, 6, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 5, 5, 6, 6, 6, 6, 6, 5, 6, 6, 6, 5, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 219 */ { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 6, 6, 6, 3, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 3, 6, 6 }, /* block 220 */ { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 3, 3, 3, 6, 3, 3, 3, 6, 6, 6, 5, 5, 5, 5, 5 }, /* block 221 */ { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 3, 6, 3, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6 }, /* block 222 */ { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 3, 3, 6 }, /* block 223 */ { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 3, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 6, 3, 3, 3, 3, 3 }, /* block 224 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 6, 6, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 6, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6 }, /* block 225 */ { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, /* block 226 */ { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 6, 3, 3, 3, 6, 6, 6, 3, 3, 6, 6, 6, 0, 0, 0, 0, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 6, 6, 0, 0, 0, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0, 0, 0 }, /* block 227 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 3, 3, 3, 3, 3 }, /* block 228 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 229 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, /* block 230 */ { 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 231 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 3, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 3, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6 }, /* block 232 */ { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6 }, /* block 233 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0, 0, 0 }, /* block 234 */ { 6, 6, 6, 6, 6, 6, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0, 6, 6, 6, 6, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0 }, /* block 235 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0 }, /* block 236 */ { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 237 */ { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 }, /* block 238 */ { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 }, /* block 239 */ { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 }, /* block 240 */ { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 }, /* block 241 */ { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 242 */ { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 243 */ { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 }, /* block 244 */ { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 245 */ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } }; static int charwidth(int32_t code) { const int32_t block_size = 128; uint8_t i = charwidth_stage1[code / block_size]; return charwidth_stage2[i][code % block_size]; } #endif /* CHARWIDTH_H */ cli/src/win-utf8.c0000644000176200001440000000141314557444176013455 0ustar liggesusers #include "cli.h" #include "errors.h" #include "cleancall.h" #include #ifdef WIN32 extern Rboolean EmitEmbeddedUTF8; #endif SEXP clic_get_embedded_utf8(void) { #ifdef WIN32 #if R_VERSION < R_Version(4, 0, 0) error("get_embedded_utf8() needs at least R 4.0.0"); #else return ScalarLogical(EmitEmbeddedUTF8); #endif #else error("get_embedded_utf8() only works on Windows"); return R_NilValue; #endif } SEXP clic_set_embedded_utf8(SEXP value) { #ifdef WIN32 #if R_VERSION < R_Version(4, 0, 0) error("set_embedded_utf8() needs at least R 4.0.0"); #else Rboolean prev = EmitEmbeddedUTF8; EmitEmbeddedUTF8 = LOGICAL(value)[0]; return ScalarLogical(prev); #endif #else error("set_embedded_utf8() only works on Windows"); return R_NilValue; #endif } cli/src/thread.c0000644000176200001440000000741414557444176013252 0ustar liggesusers #include "cli.h" #include #ifdef __TERMUX__ #include #endif #include #ifndef _WIN32 #include #endif SEXP cli_pkgenv = 0; pthread_t tick_thread = { 0 }; volatile int cli__timer_flag = 1; volatile int* cli_timer_flag = &cli__timer_flag; struct timespec cli__tick_ts; double cli_speed_time = 1.0; volatile int cli__reset = 1; static int unloaded = 0; void* clic_thread_func(void *arg) { #ifndef _WIN32 sigset_t set; sigfillset(&set); int ret = pthread_sigmask(SIG_SETMASK, &set, NULL); /* We chicken out if the signals cannot be blocked. */ if (ret) return NULL; #endif int old; pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &old); while (1) { /* TODO: handle signals */ nanosleep(&cli__tick_ts, NULL); if (cli__reset) cli__timer_flag = 1; } } int cli__start_thread(SEXP ticktime, SEXP speedtime) { cli_speed_time = REAL(speedtime)[0]; int cticktime = INTEGER(ticktime)[0] / REAL(speedtime)[0]; if (cticktime == 0) cticktime = 1; cli__tick_ts.tv_sec = cticktime / 1000; cli__tick_ts.tv_nsec = (cticktime % 1000) * 1000 * 1000; int ret = 0; #ifdef __EMSCRIPTEN__ cli__reset = 0; #else if (! getenv("CLI_NO_THREAD")) { ret = pthread_create( & tick_thread, /* attr = */ 0, clic_thread_func, /* arg = */ NULL ); /* detaching makes it easier to clean up resources * On Windows this causes issues and the thread cannot * be cancelled, so we don't do it there. */ #ifndef _WIN32 if (!ret) pthread_detach(tick_thread); #endif } else { cli__reset = 0; } #endif return ret; } SEXP clic_start_thread(SEXP pkg, SEXP ticktime, SEXP speedtime) { R_PreserveObject(pkg); cli_pkgenv = pkg; int ret = cli__start_thread(ticktime, speedtime); if (ret) warning("Cannot create cli tick thread"); return R_NilValue; } int cli__kill_thread(void) { int ret = 0; #ifdef _WIN32 // On ARM64 builds of Windows (when running through x86 emulation), // cancelling the running tick thread seems to cause issues during // process shutdown. Avoid the issue by just neglecting to cancel // the thread altogether. const char* arch = getenv("PROCESSOR_ARCHITECTURE"); if (!strcmp(arch, "ARM64")) { return 0; } #endif /* This should not happen, but be extra careful */ if (tick_thread) { ret = pthread_cancel(tick_thread); if (ret) { /* If we could not cancel, then accept the memory leak. We do not try to free the R object, because the tick thread might refer to it, still. The tick thread is always cancellable, so this should not happen. */ warning("Could not cancel cli thread"); // __NO_COVERAGE__ return ret; // __NO_COVERAGE__ } } return ret; } #ifndef __has_feature #define __has_feature(x) 0 #endif SEXP clic_stop_thread(void) { if (unloaded) return R_NilValue; int ret = 1; #if defined(__clang__) && defined(__has_feature) # if __has_feature(address_sanitizer) /* clang in ASAN, do nothing */ # else ret = cli__kill_thread(); # endif #else ret = cli__kill_thread(); #endif if (!ret) { R_ReleaseObject(cli_pkgenv); } unloaded = 1; return R_NilValue; } SEXP clic_tick_reset(void) { if (cli__reset) { cli__timer_flag = 0; } return R_NilValue; } SEXP clic_tick_set(SEXP ticktime, SEXP speedtime) { cli__timer_flag = 1; int ret = cli__kill_thread(); if (ret) error("Cannot terminate progress thread"); ret = cli__start_thread(ticktime, speedtime); if (ret) warning("Cannot create progress thread"); return R_NilValue; } SEXP clic_tick_pause(SEXP state) { cli__reset = 0; cli__timer_flag = LOGICAL(state)[0]; return R_NilValue; } SEXP clic_tick_resume(SEXP state) { cli__timer_flag = LOGICAL(state)[0]; cli__reset = 1; return R_NilValue; } cli/src/cli.h0000644000176200001440000001060314752735214012542 0ustar liggesusers #ifndef CLI_H #define CLI_H #include #include #include #include #if R_VERSION < R_Version(3, 5, 0) # define STRING_PTR_RO(x) STRING_PTR(x) #endif SEXP clic_diff_chr(SEXP a, SEXP b, SEXP max); SEXP clic_getppid(void); SEXP clic_md5(SEXP strs); SEXP clic_md5_raw(SEXP r); SEXP clic_md5_file(SEXP paths); SEXP clic_sha256(SEXP strs); SEXP clic_sha256_raw(SEXP r); SEXP clic_sha256_file(SEXP paths); SEXP clic_sha1(SEXP strs); SEXP clic_sha1_raw(SEXP r); SEXP clic_sha1_file(SEXP paths); SEXP clic_xxhash(SEXP strs); SEXP clic_xxhash_raw(SEXP r); SEXP clic_xxhash_file(SEXP paths); SEXP clic_xxhash64(SEXP strs); SEXP clic_xxhash64_raw(SEXP r); SEXP clic_xxhash64_file(SEXP paths); SEXP clic_tty_size(void); SEXP clic_ansi_simplify(SEXP x, SEXP keep_csi); SEXP clic_ansi_substr(SEXP x, SEXP start, SEXP stop); SEXP clic_ansi_html(SEXP x, SEXP keep_csi); SEXP clic_ansi_has_any(SEXP x, SEXP sgr, SEXP csi, SEXP link); SEXP clic_ansi_strip(SEXP x, SEXP sgr, SEXP csi, SEXP link); SEXP clic_ansi_nchar(SEXP x, SEXP type); SEXP clic_utf8_nchar_graphemes(SEXP x); SEXP clic_utf8_display_width(SEXP x); SEXP clic_utf8_substr(SEXP sx, SEXP start, SEXP stop); SEXP clic_utf8_graphemes(SEXP sx); typedef volatile int vint; extern volatile int* cli_timer_flag; extern volatile int cli__reset; void cli_progress_add(SEXP bar, double inc); SEXP cli_progress_bar(vint **ptr, double total, SEXP config); void cli_progress_done(SEXP bar); void cli_progress_init_timer(vint **ptr); int cli_progress_num(void); void cli_progress_set(SEXP bar, double set); void cli_progress_set_clear(SEXP bar, int); void cli_progress_set_format(SEXP bar, const char *name); void cli_progress_set_name(SEXP bar, const char *name); void cli_progress_set_status(SEXP bar, const char *name); void cli_progress_set_type(SEXP bar, const char *name); void cli_progress_sleep(int s, long ns); void cli_progress_update(SEXP bar, double set, double inc, int force); SEXP cli__progress_update(SEXP bar); SEXP clic_progress_along(SEXP seq, SEXP bar); extern SEXP cli_pkgenv; #if R_VERSION >= R_Version(3, 5, 0) void cli_init_altrep(DllInfo *dll); #endif double clic__get_time(void); SEXP clic__find_var(SEXP rho, SEXP symbol); SEXP clic_start_thread(SEXP pkgenv, SEXP tick, SEXP speed); SEXP clic_stop_thread(void); SEXP clic_tick_reset(void); SEXP clic_get_time(void); SEXP clic_tick_set(SEXP ticktime, SEXP speedtime); SEXP clic_tick_pause(SEXP state); SEXP clic_tick_resume(SEXP state); SEXP clic_make_timer(void); SEXP clic_update_due(void); /** Indicates whether a given unsigned integer is a valid ASCII codepoint */ #define UTF8LITE_IS_ASCII(x) \ ((x) <= 0x7F) /** Given the first byte in a valid UTF-8 byte sequence, determine the number of * total bytes */ #define UTF8LITE_UTF8_TOTAL_LEN(x) \ ( ((x) & 0x80) == 0x00 ? 1 \ : ((x) & 0xE0) == 0xC0 ? 2 \ : ((x) & 0xF0) == 0xE0 ? 3 : 4) /** Last valid unicode codepoint */ #define UTF8LITE_CODE_MAX 0x10FFFF /** Indicates whether a 16-bit code unit is a UTF-16 high surrogate. * High surrogates are in the range 0xD800 `(1101 1000 0000 0000)` * to 0xDBFF `(1101 1011 1111 1111)`. */ #define UTF8LITE_IS_UTF16_HIGH(x) (((x) & 0xFC00) == 0xD800) /** Indicates whether a 16-bit code unit is a UTF-16 low surrogate. * Low surrogates are in the range 0xDC00 `(1101 1100 0000 0000)` * to 0xDFFF `(1101 1111 1111 1111)`. */ #define UTF8LITE_IS_UTF16_LOW(x) (((x) & 0xFC00) == 0xDC00) /** Indicates whether a given unsigned integer is a valid unicode codepoint */ #define UTF8LITE_IS_UNICODE(x) \ (((x) <= UTF8LITE_CODE_MAX) \ && !UTF8LITE_IS_UTF16_HIGH(x) \ && !UTF8LITE_IS_UTF16_LOW(x)) SEXP clic_get_embedded_utf8(void); SEXP clic_set_embedded_utf8(SEXP value); int clic__utf8_display_width_char(const uint8_t **x); struct grapheme_iterator { const uint8_t *nxt_ptr; int32_t nxt_code; int nxt_prop; int nxt_cw; const uint8_t *cnd; int cnd_width; char cnd_width_done; /* -1: do not measure width */ }; void clic_utf8_graphscan_make(struct grapheme_iterator *iter, const uint8_t *txt, int width); void clic_utf8_graphscan_next(struct grapheme_iterator *iter, uint8_t **ptr, int *width); SEXP glue_(SEXP x, SEXP f, SEXP open_arg, SEXP close_arg, SEXP cli_arg); SEXP trim_(SEXP x); SEXP clic_vt_output(SEXP bytes, SEXP width, SEXP height); #endif cli/src/errors.c0000644000176200001440000000415614557444176013317 0ustar liggesusers #include "errors.h" #include #include #define ERRORBUF_SIZE 4096 static char errorbuf[ERRORBUF_SIZE]; SEXP r_throw_error(const char *func, const char *filename, int line, const char *msg, ...) { va_list args; errorbuf[0] = '\0'; va_start(args, msg); vsnprintf(errorbuf, ERRORBUF_SIZE, msg, args); va_end (args); error("%s @%s:%d (%s)", errorbuf, filename, line, func); return R_NilValue; } #ifdef _WIN32 SEXP r_throw_system_error(const char *func, const char *filename, int line, DWORD errorcode, const char *sysmsg, const char *msg, ...) { va_list args; LPVOID lpMsgBuf; char *realsysmsg = sysmsg ? (char*) sysmsg : NULL; char *failmsg = "Formatting the system message failed :("; if (errorcode == -1) errorcode = GetLastError(); if (!realsysmsg) { DWORD ret = FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorcode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL); if (ret == 0) { realsysmsg = failmsg; } else { realsysmsg = R_alloc(1, strlen(lpMsgBuf) + 1); strcpy(realsysmsg, lpMsgBuf); LocalFree(lpMsgBuf); } } errorbuf[0] = '\0'; va_start(args, msg); vsnprintf(errorbuf, ERRORBUF_SIZE, msg, args); va_end(args); error("%s (system error %ld, %s) @%s:%d (%s)", errorbuf, errorcode, realsysmsg, filename, line, func); return R_NilValue; } #endif #ifdef _WIN32 SEXP r_throw_posix_error( #else SEXP r_throw_system_error( #endif const char *func, const char *filename, int line, int errorcode, const char *sysmsg, const char *msg, ...) { va_list args; if (!sysmsg) sysmsg = strerror(errorcode); errorbuf[0] = '\0'; va_start(args, msg); vsnprintf(errorbuf, ERRORBUF_SIZE, msg, args); va_end(args); error("%s (system error %d, %s) @%s:%d (%s)", errorbuf, errorcode, sysmsg, filename, line, func); return R_NilValue; } cli/src/winfiles.c0000644000176200001440000000352314557444176013620 0ustar liggesusers #include "errors.h" #ifdef WIN32 #include #include #include static int utf8_to_utf16(const char* s, WCHAR** ws_ptr) { int ws_len, r; WCHAR* ws; ws_len = MultiByteToWideChar( /* CodePage = */ CP_UTF8, /* dwFlags = */ 0, /* lpMultiByteStr = */ s, /* cbMultiByte = */ -1, /* lpWideCharStr = */ NULL, /* cchWideChar = */ 0); if (ws_len <= 0) { return GetLastError(); } /* Jumps on error */ ws = (WCHAR*) R_alloc(ws_len, sizeof(WCHAR)); r = MultiByteToWideChar( /* CodePage = */ CP_UTF8, /* dwFlags = */ 0, /* lpMultiByteStr = */ s, /* cbMultiBytes = */ -1, /* lpWideCharStr = */ ws, /* cchWideChar = */ ws_len); if (r != ws_len) { R_THROW_ERROR("error converting UTF-8 file name to UTF-16"); } *ws_ptr = ws; return 0; } int open_file(const char *path, int oflag) { WCHAR *wpath; int ret = utf8_to_utf16(path, &wpath); if (ret) { R_THROW_SYSTEM_ERROR_CODE( ret, "Failed to open `%s`, cannot convert path to UTF-16", path ); } return _wopen(wpath, oflag | _O_BINARY); } FILE *fopen_file(const char *filename, const char *mode) { WCHAR *wfilename, *wmode; int ret = utf8_to_utf16(filename, &wfilename); if (ret) { R_THROW_SYSTEM_ERROR_CODE( ret, "Failed to open `%s`, cannot convert filename to UTF-16", filename ); } ret = utf8_to_utf16(mode, &wmode); if (ret) { R_THROW_SYSTEM_ERROR_CODE( ret, "Failed to open `%s`, cannot convert mode `%s` to UTF-16", filename, mode ); } return _wfopen(wfilename, wmode); } #else #include int open_file(const char *path, int oflag) { return open(path, oflag); } FILE *fopen_file(const char *filename, const char *mode) { return fopen(filename, mode); } #endif cli/src/progress.c0000644000176200001440000003015114635021626013625 0ustar liggesusers #include "cli.h" #include "errors.h" #include "cleancall.h" #include #include #include /* ---------------------------------------------------------------------*/ /* Internals */ /* ---------------------------------------------------------------------*/ /* for older macOS versions */ #if defined(__APPLE__) && defined(__MACH__) #include #include #include #include /* It doesn't really matter what these are defined to, as long as they are defined */ #ifndef CLOCK_REALTIME #define CLOCK_REALTIME 0 #endif #ifndef CLOCK_MONOTONIC #define CLOCK_MONOTONIC 1 #endif static int cli_clock_gettime(int clk_id, struct timespec *t) { memset(t, 0, sizeof(*t)); if (clk_id == CLOCK_REALTIME) { struct timeval now; int rv = gettimeofday(&now, NULL); // __NO_COVERAGE__ if (rv) { // __NO_COVERAGE__ return rv; // __NO_COVERAGE__ } // __NO_COVERAGE__ t->tv_sec = now.tv_sec; // __NO_COVERAGE__ t->tv_nsec = now.tv_usec * 1000; // __NO_COVERAGE__ return 0; // __NO_COVERAGE__ } else if (clk_id == CLOCK_MONOTONIC) { static uint64_t clock_start_time = 0; static mach_timebase_info_data_t timebase_ifo = {0, 0}; uint64_t now = mach_absolute_time(); if (clock_start_time == 0) { kern_return_t mach_status = mach_timebase_info(&timebase_ifo); /* appease "unused variable" warning for release builds */ (void)mach_status; clock_start_time = now; } now = (uint64_t)((double)(now - clock_start_time) * (double)timebase_ifo.numer / (double)timebase_ifo.denom); t->tv_sec = now / 1000000000; t->tv_nsec = now % 1000000000; return 0; } return EINVAL; /* EINVAL - Clock ID is unknown */ // __NO_COVERAGE__ } #else #define cli_clock_gettime(a,b) clock_gettime(a,b) #endif static R_INLINE SEXP new_env(void) { SEXP env; #if R_VERSION >= R_Version(4, 1, 0) PROTECT(env = R_NewEnv(R_EmptyEnv, 1, 29)); #else PROTECT(env = allocSExp(ENVSXP)); SET_FRAME(env, R_NilValue); SET_ENCLOS(env, R_EmptyEnv); SET_HASHTAB(env, R_NilValue); SET_ATTRIB(env, R_NilValue); #endif UNPROTECT(1); return env; } double clic__get_time(void) { struct timespec t; int ret = cli_clock_gettime(CLOCK_MONOTONIC, &t); if (ret) R_THROW_POSIX_ERROR("Cannot query monotonic clock"); return (double) t.tv_sec + 1e-9 * (double) t.tv_nsec; } SEXP clic_get_time(void) { struct timespec t; int ret = cli_clock_gettime(CLOCK_MONOTONIC, &t); if (ret) R_THROW_POSIX_ERROR("Cannot query monotonic clock"); double ts = (double) t.tv_sec + 1e-9 * (double) t.tv_nsec; return Rf_ScalarReal(ts); } SEXP clic__find_var(SEXP rho, SEXP symbol) { SEXP ret = Rf_findVarInFrame(rho, symbol); if (ret == R_UnboundValue) { error("Cannot find variable `%s`.", CHAR(PRINTNAME(symbol))); } else if (TYPEOF(ret) == PROMSXP) { PROTECT(ret); SEXP ret2 = Rf_eval(ret, rho); UNPROTECT(1); return(ret2); } else { return ret; } } static int cli__counter = 0; #define P(x) PROTECT(x) SEXP cli__progress_update(SEXP bar) { /* We can't throw a condition from C, unfortunately... */ SEXP call = PROTECT(Rf_lang2(install("progress_c_update"), bar)); SEXP retv = PROTECT(Rf_eval(call, cli_pkgenv)); UNPROTECT(2); return retv; } /* ---------------------------------------------------------------------*/ /* Public API */ /* ---------------------------------------------------------------------*/ void cli_progress_init_timer(vint **ptr) { *ptr = cli_timer_flag; } SEXP cli_progress_bar(vint **ptr, double total, SEXP config) { *ptr = cli_timer_flag; /* FALSE means no progress bar */ if (config && Rf_isLogical(config) && LENGTH(config) == 1 && !LOGICAL(config)[0]) { return R_NilValue; } /* If changes, synchronize with R API in progress-client.R */ double now = clic__get_time(); SEXP bar = PROTECT(new_env()); SEXP show_after = PROTECT(Rf_GetOption1(Rf_install("cli.progress_show_after"))); double sa = 2; if (!isNull(show_after)) sa = REAL(show_after)[0]; SEXP clear = PROTECT(Rf_GetOption1(Rf_install("cli.progress_clear"))); int cl = 1; if (!isNull(clear)) cl = LOGICAL(clear)[0]; char idstr[64]; static pid_t pid = 0; if (pid == 0) pid = getpid(); snprintf(idstr, sizeof(idstr) - 1, "cli-%d-%d", (int) pid, cli__counter++); Rf_defineVar(P(Rf_install("id")), P(Rf_mkString(idstr)), bar); Rf_defineVar(P(Rf_install("name")), P(Rf_mkString("")), bar); Rf_defineVar(P(Rf_install("status")), P(Rf_mkString("")), bar); Rf_defineVar(P(Rf_install("type")), P(Rf_mkString("iterator")), bar); Rf_defineVar(P(Rf_install("total")), P(Rf_ScalarReal(total)), bar); Rf_defineVar(P(Rf_install("show_after")), P(Rf_ScalarReal(now + sa)), bar); Rf_defineVar(P(Rf_install("show_50")), P(Rf_ScalarReal(now + sa/2)), bar); Rf_defineVar(P(Rf_install("format")), R_NilValue, bar); Rf_defineVar(P(Rf_install("format_done")), R_NilValue, bar); Rf_defineVar(P(Rf_install("format_failed")), R_NilValue, bar); Rf_defineVar(P(Rf_install("clear")), P(Rf_ScalarLogical(cl)), bar); Rf_defineVar(P(Rf_install("auto_terminate")), P(Rf_ScalarLogical(1)), bar); Rf_defineVar(P(Rf_install("envkey")), R_NilValue, bar); Rf_defineVar(P(Rf_install("current")), P(Rf_ScalarReal(0)), bar); Rf_defineVar(P(Rf_install("start")), P(Rf_ScalarReal(now)), bar); Rf_defineVar(P(Rf_install("statusbar")), R_NilValue, bar); Rf_defineVar(P(Rf_install("tick")), P(Rf_ScalarReal(0)), bar); Rf_defineVar(P(Rf_install("extra")), R_NilValue, bar); UNPROTECT(30); if (!config || Rf_isNull(config)) { /* NULL pointer or R NULL, use defaults */ } else if (Rf_isLogical(config) && LENGTH(config) == 1) { /* TRUE, use defaults */ } else if (TYPEOF(config) == VECSXP) { /* Proper config */ int i, n = LENGTH(config); SEXP nms = getAttrib(config, R_NamesSymbol); if (isNull(nms)) { error("Invalid cli progress bar configuration, list elements must " "be named."); } for (i = 0; i < n; i++) { Rf_defineVar( Rf_install(CHAR(STRING_ELT(nms, i))), VECTOR_ELT(config, i), bar ); } } else if (TYPEOF(config) == STRSXP) { /* String, use as name */ Rf_defineVar(Rf_install("name"), config, bar); } else { error("Unknown cli progress bar configuation, see manual."); } UNPROTECT(3); return bar; } void cli_progress_set_name(SEXP bar, const char *name) { PROTECT(bar); if (isNull(bar)) { UNPROTECT(1); return; } Rf_defineVar(PROTECT(Rf_install("name")), PROTECT(Rf_mkString(name)), bar); UNPROTECT(3); } void cli_progress_set_status(SEXP bar, const char *status) { PROTECT(bar); if (isNull(bar)) { UNPROTECT(1); return; } Rf_defineVar(PROTECT(Rf_install("status")), PROTECT(Rf_mkString(status)), bar); UNPROTECT(3); } void cli_progress_set_type(SEXP bar, const char *type) { PROTECT(bar); if (isNull(bar)) { UNPROTECT(1); return; } Rf_defineVar(PROTECT(Rf_install("type")), PROTECT(Rf_mkString(type)), bar); UNPROTECT(3); } void cli_progress_set_format(SEXP bar, const char *format) { PROTECT(bar); if (isNull(bar)) { UNPROTECT(1); return; } Rf_defineVar(PROTECT(Rf_install("format")), PROTECT(Rf_mkString(format)), bar); UNPROTECT(3); } void cli_progress_set_clear(SEXP bar, int clear) { PROTECT(bar); if (isNull(bar)) { UNPROTECT(1); return; } Rf_defineVar(PROTECT(Rf_install("clear")), PROTECT(Rf_ScalarLogical(clear)), bar); UNPROTECT(3); } void cli_progress_set(SEXP bar, double set) { PROTECT(bar); if (isNull(bar)) { UNPROTECT(1); return; } Rf_defineVar(PROTECT(Rf_install("current")), PROTECT(ScalarReal(set)), bar); if (*cli_timer_flag) { if (cli__reset) *cli_timer_flag = 0; double now = clic__get_time(); SEXP show_after = PROTECT(clic__find_var(bar, PROTECT(Rf_install("show_after")))); if (now > REAL(show_after)[0]) { cli__progress_update(bar); } else { SEXP show_50 = PROTECT(clic__find_var(bar, PROTECT(Rf_install("show_50")))); SEXP total = PROTECT(clic__find_var(bar, PROTECT(Rf_install("total")))); if (now > REAL(show_50)[0] && REAL(total)[0] != NA_REAL && set <= REAL(total)[0] / 2) { cli__progress_update(bar); } UNPROTECT(4); } UNPROTECT(2); } UNPROTECT(3); } void cli_progress_add(SEXP bar, double inc) { PROTECT(bar); if (isNull(bar)) { UNPROTECT(1); return; } SEXP current = PROTECT(Rf_install("current")); double crnt = REAL(PROTECT(clic__find_var(bar, current)))[0]; Rf_defineVar(current, PROTECT(ScalarReal(crnt + inc)), bar); if (*cli_timer_flag) { if (cli__reset) *cli_timer_flag = 0; double now = clic__get_time(); SEXP show_after = PROTECT(clic__find_var(bar, PROTECT(Rf_install("show_after")))); if (now > REAL(show_after)[0]) { cli__progress_update(bar); } else { SEXP show_50 = PROTECT(clic__find_var(bar, PROTECT(Rf_install("show_50")))); SEXP total = PROTECT(clic__find_var(bar, PROTECT(Rf_install("total")))); if (now > REAL(show_50)[0] && REAL(total)[0] != NA_REAL && crnt + inc <= REAL(total)[0] / 2) { cli__progress_update(bar); } UNPROTECT(4); } UNPROTECT(2); } UNPROTECT(4); } void cli_progress_done(SEXP bar) { PROTECT(bar); if (isNull(bar)) { UNPROTECT(1); return; } SEXP call = PROTECT(Rf_lang2(PROTECT(install("progress_c_done")), bar)); PROTECT(Rf_eval(call, cli_pkgenv)); UNPROTECT(4); } int cli_progress_num(void) { SEXP clienv = PROTECT(clic__find_var(cli_pkgenv, Rf_install("clienv"))); if (clienv == R_UnboundValue) error("Cannot find 'clienv'"); SEXP bars = PROTECT(clic__find_var(clienv, Rf_install("progress"))); if (bars == R_UnboundValue) error("Cannot find 'clienv$progress'"); UNPROTECT(2); return LENGTH(bars); } extern double cli_speed_time; void cli_progress_sleep(int s, long ns) { struct timespec ts; int s2 = s; long ns2 = ns; if (cli_speed_time != 1.0) { s2 = s / cli_speed_time; // __NO_COVERAGE__ ns2 = // __NO_COVERAGE__ (s / cli_speed_time - s2) * 1000 * 1000 * 1000 + // __NO_COVERAGE__ ns / cli_speed_time; // __NO_COVERAGE__ } // __NO_COVERAGE__ ts.tv_sec = s2; ts.tv_nsec = ns2; nanosleep(&ts, NULL); } void cli_progress_update(SEXP bar, double set, double inc, int force) { double crnt = 0; PROTECT(bar); if (isNull(bar)) { UNPROTECT(1); return; } SEXP current = PROTECT(Rf_install("current")); if (set >= 0) { crnt = set; Rf_defineVar(current, PROTECT(ScalarReal(set)), bar); UNPROTECT(1); } else { crnt = REAL(PROTECT(clic__find_var(bar, current)))[0]; if (inc != 0) { crnt = crnt + inc; Rf_defineVar(current, PROTECT(ScalarReal(crnt)), bar); UNPROTECT(1); } UNPROTECT(1); } if (force) { cli__progress_update(bar); } else if (*cli_timer_flag) { if (cli__reset) *cli_timer_flag = 0; double now = clic__get_time(); SEXP show_after = PROTECT(clic__find_var(bar, PROTECT(Rf_install("show_after")))); if (now > REAL(show_after)[0]) { cli__progress_update(bar); } else { SEXP show_50 = PROTECT(clic__find_var(bar, PROTECT(Rf_install("show_50")))); SEXP total = PROTECT(clic__find_var(bar, PROTECT(Rf_install("total")))); if (now > REAL(show_50)[0] && REAL(total)[0] != NA_REAL && crnt <= REAL(total)[0] / 2) { cli__progress_update(bar); } UNPROTECT(4); } UNPROTECT(2); } UNPROTECT(2); } cli/src/winfiles.h0000644000176200001440000000014014557444176013615 0ustar liggesusers #ifndef R_WINFILES_H #define R_WINFILES_H int open_file(const char *path, int oflag); #endif cli/src/vtparse.h0000644000176200001440000000216514557444176013472 0ustar liggesusers/* * VTParse - an implementation of Paul Williams' DEC compatible state machine parser * * Author: Joshua Haberman * * This code is in the public domain. */ #ifndef VTPARSE_DOT_H #define VTPARSE_DOT_H #ifdef __cplusplus extern "C" { #endif #include "vtparse_table.h" #define MAX_INTERMEDIATE_CHARS 2 #define ACTION(state_change) (state_change & 0x0F) #define STATE(state_change) (state_change >> 4) struct vtparse; typedef void (*vtparse_callback_t)(struct vtparse*, vtparse_action_t, unsigned int); typedef struct vtparse { vtparse_state_t state; vtparse_callback_t cb; unsigned char intermediate_chars[MAX_INTERMEDIATE_CHARS+1]; int num_intermediate_chars; char ignore_flagged; int params[16]; int num_params; void* user_data; int characterBytes; unsigned int utf8Character; } vtparse_t; void vtparse_init(vtparse_t *parser, vtparse_callback_t cb); void vtparse(vtparse_t *parser, unsigned char *data, unsigned int len); #ifdef __cplusplus } #endif #endif cli/src/vtparse.c0000644000176200001440000001245414557444176013467 0ustar liggesusers/* * VTParse - an implementation of Paul Williams' DEC compatible state machine parser * * Author: Joshua Haberman * * This code is in the public domain. */ #include "vtparse.h" void vtparse_init(vtparse_t *parser, vtparse_callback_t cb) { parser->state = VTPARSE_STATE_GROUND; parser->num_intermediate_chars = 0; parser->num_params = 0; parser->ignore_flagged = 0; parser->cb = cb; parser->characterBytes = 1; parser->utf8Character = 0; } static void do_action(vtparse_t *parser, vtparse_action_t action, unsigned int ch) { /* Some actions we handle internally (like parsing parameters), others * we hand to our client for processing */ switch(action) { case VTPARSE_ACTION_PRINT: case VTPARSE_ACTION_EXECUTE: case VTPARSE_ACTION_HOOK: case VTPARSE_ACTION_PUT: case VTPARSE_ACTION_OSC_START: case VTPARSE_ACTION_OSC_PUT: case VTPARSE_ACTION_OSC_END: case VTPARSE_ACTION_UNHOOK: case VTPARSE_ACTION_CSI_DISPATCH: case VTPARSE_ACTION_ESC_DISPATCH: parser->cb(parser, action, ch); break; case VTPARSE_ACTION_IGNORE: /* do nothing */ break; case VTPARSE_ACTION_COLLECT: { /* Append the character to the intermediate params */ if(parser->num_intermediate_chars + 1 > MAX_INTERMEDIATE_CHARS) parser->ignore_flagged = 1; else parser->intermediate_chars[parser->num_intermediate_chars++] = (unsigned char)ch; break; } case VTPARSE_ACTION_PARAM: { /* process the param character */ if(ch == ';') { parser->num_params += 1; parser->params[parser->num_params-1] = 0; } else { /* the character is a digit */ int current_param; if(parser->num_params == 0) { parser->num_params = 1; parser->params[0] = 0; } current_param = parser->num_params - 1; parser->params[current_param] *= 10; parser->params[current_param] += ch - '0'; } break; } case VTPARSE_ACTION_CLEAR: parser->num_intermediate_chars = 0; parser->num_params = 0; parser->ignore_flagged = 0; break; default: parser->cb(parser, VTPARSE_ACTION_ERROR, 0); } } static void do_state_change(vtparse_t *parser, state_change_t change, unsigned int ch) { /* A state change is an action and/or a new state to transition to. */ vtparse_state_t new_state = STATE(change); vtparse_action_t action = ACTION(change); if(new_state) { /* Perform up to three actions: * 1. the exit action of the old state * 2. the action associated with the transition * 3. the entry action of the new state */ vtparse_action_t exit_action = EXIT_ACTIONS[parser->state-1]; vtparse_action_t entry_action = ENTRY_ACTIONS[new_state-1]; if(exit_action) do_action(parser, exit_action, 0); if(action) do_action(parser, action, ch); if(entry_action) do_action(parser, entry_action, 0); parser->state = new_state; } else { do_action(parser, action, ch); } } void vtparse(vtparse_t *parser, unsigned char *data, unsigned int len) { int i; for(i = 0; i < len; i++) { unsigned char ch = data[i]; if(parser->characterBytes != 1) { parser->utf8Character = (parser->utf8Character << 6) | (ch & 0x3F); parser->characterBytes--; if(parser->characterBytes == 1) { state_change_t change = VTPARSE_ACTION_PRINT; do_state_change(parser, change, parser->utf8Character); } } else if((ch&(1<<7)) != 0) { int bit = 6; do { if((ch&(1< 1); parser->utf8Character = 0; parser->characterBytes = 7-bit; switch(parser->characterBytes) { case 2: parser->utf8Character = ch & (1 | (1<<1) | (1<<2) | (1<<3) | (1<<4)); break; case 3: parser->utf8Character = ch & (1 | (1<<1) | (1<<2) | (1<<3)); break; case 4: parser->utf8Character = ch & (1 | (1<<1) | (1<<2)); break; case 5: parser->utf8Character = ch & (1 | (1<<1)); break; case 6: parser->utf8Character = ch & 1; break; } } else { state_change_t change = STATE_TABLE[parser->state-1][ch]; do_state_change(parser, change, (unsigned int)ch); } } } cli/src/graphbreak.h0000644000176200001440000037543314557444176014127 0ustar liggesusers/* This file is automatically generated. DO NOT EDIT! Instead, edit gen-graphbreak.py and re-run. */ /* * Unicode Grapheme_Break property values. * * Defined in UAX #29 "Unicode Text Segmentation" * * http://www.unicode.org/reports/tr29/ * * Section 4.1, Table 3. * * * We use the two-stage lookup strategy described at * * http://www.strchr.com/multi-stage_tables * */ #ifndef UNICODE_GRAPHBREAK_H #define UNICODE_GRAPHBREAK_H #include enum graph_break_prop { GRAPH_BREAK_OTHER = 0, GRAPH_BREAK_CR = 1, GRAPH_BREAK_CONTROL = 2, GRAPH_BREAK_EXTEND_INCB_EXTEND = 3, GRAPH_BREAK_EXTEND_INCB_LINKER = 4, GRAPH_BREAK_EXTEND_OTHER = 5, GRAPH_BREAK_EXTENDED_PICTOGRAPHIC = 6, GRAPH_BREAK_INCB_CONSONANT = 7, GRAPH_BREAK_L = 8, GRAPH_BREAK_LF = 9, GRAPH_BREAK_LV = 10, GRAPH_BREAK_LVT = 11, GRAPH_BREAK_PREPEND = 12, GRAPH_BREAK_REGIONAL_INDICATOR = 13, GRAPH_BREAK_SPACINGMARK = 14, GRAPH_BREAK_T = 15, GRAPH_BREAK_V = 16, GRAPH_BREAK_ZWJ = 17 }; static const uint8_t graph_break_stage1[] = { /* U+0000 */ 0, 1, 2, 2, 2, 2, 3, 2, 2, 4, 2, 5, 6, 7, 8, 9, /* U+0800 */ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, /* U+1000 */ 26, 27, 28, 29, 2, 2, 30, 2, 2, 2, 2, 2, 2, 2, 31, 32, /* U+1800 */ 33, 34, 35, 2, 36, 37, 38, 39, 40, 41, 2, 42, 2, 2, 2, 2, /* U+2000 */ 43, 44, 45, 46, 2, 2, 47, 48, 2, 49, 2, 50, 51, 52, 53, 54, /* U+2800 */ 2, 2, 55, 2, 2, 2, 56, 2, 2, 57, 58, 59, 2, 2, 2, 2, /* U+3000 */ 60, 61, 2, 2, 2, 62, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+3800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+4000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+4800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+5000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+5800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+6000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+6800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+7000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+7800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+8000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+8800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+9000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+9800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+A000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 63, 64, 2, 2, /* U+A800 */ 65, 66, 67, 68, 69, 70, 2, 71, 72, 73, 74, 75, 76, 77, 78, 72, /* U+B000 */ 73, 74, 75, 76, 77, 78, 72, 73, 74, 75, 76, 77, 78, 72, 73, 74, /* U+B800 */ 75, 76, 77, 78, 72, 73, 74, 75, 76, 77, 78, 72, 73, 74, 75, 76, /* U+C000 */ 77, 78, 72, 73, 74, 75, 76, 77, 78, 72, 73, 74, 75, 76, 77, 78, /* U+C800 */ 72, 73, 74, 75, 76, 77, 78, 72, 73, 74, 75, 76, 77, 78, 72, 73, /* U+D000 */ 74, 75, 76, 77, 78, 72, 73, 74, 75, 76, 77, 78, 72, 73, 74, 79, /* U+D800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+E000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+E800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+F000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+F800 */ 2, 2, 2, 2, 2, 2, 80, 2, 2, 2, 2, 2, 81, 82, 2, 83, /* U+10000 */ 2, 2, 2, 84, 2, 85, 86, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+10800 */ 2, 2, 2, 2, 87, 88, 2, 2, 2, 2, 89, 2, 2, 90, 91, 92, /* U+11000 */ 93, 94, 95, 96, 97, 98, 99, 2,100,101, 2,102,103,104,105, 2, /* U+11800 */106, 2,107,108,109,110, 2, 2,111,112,113,114, 2,115,116, 2, /* U+12000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+12800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+13000 */ 2, 2, 2, 2, 2, 2, 2, 2,117, 2, 2, 2, 2, 2, 2, 2, /* U+13800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+14000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+14800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+15000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+15800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+16000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+16800 */ 2, 2, 2, 2, 2,118,119, 2, 2, 2, 2, 2, 2, 2,120,121, /* U+17000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+17800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+18000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+18800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+19000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+19800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+1A000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+1A800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+1B000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+1B800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2,122, 2, 2, 2, 2, 2, 2, /* U+1C000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+1C800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,123, 2, /* U+1D000 */ 2, 2,124,125,126, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+1D800 */ 2, 2, 2, 2,127,128, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+1E000 */129,130,119, 2, 2,131, 2, 2, 2,132, 2, 2, 2, 2, 2, 2, /* U+1E800 */ 2,133,134, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+1F000 */135,135,136,137,138,135,135,139,135,135,140,135,141,135,142,143, /* U+1F800 */144,145,146,135,135,135, 2, 2,135,135,135,135,135,135,135,147, /* U+20000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+20800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+21000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+21800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+22000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+22800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+23000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+23800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+24000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+24800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+25000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+25800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+26000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+26800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+27000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+27800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+28000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+28800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+29000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+29800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+2A000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+2A800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+2B000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+2B800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+2C000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+2C800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+2D000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+2D800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+2E000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+2E800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+2F000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+2F800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+30000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+30800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+31000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+31800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+32000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+32800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+33000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+33800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+34000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+34800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+35000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+35800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+36000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+36800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+37000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+37800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+38000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+38800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+39000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+39800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+3A000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+3A800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+3B000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+3B800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+3C000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+3C800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+3D000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+3D800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+3E000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+3E800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+3F000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+3F800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+40000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+40800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+41000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+41800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+42000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+42800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+43000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+43800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+44000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+44800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+45000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+45800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+46000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+46800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+47000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+47800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+48000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+48800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+49000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+49800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+4A000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+4A800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+4B000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+4B800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+4C000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+4C800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+4D000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+4D800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+4E000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+4E800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+4F000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+4F800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+50000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+50800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+51000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+51800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+52000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+52800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+53000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+53800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+54000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+54800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+55000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+55800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+56000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+56800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+57000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+57800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+58000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+58800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+59000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+59800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+5A000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+5A800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+5B000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+5B800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+5C000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+5C800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+5D000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+5D800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+5E000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+5E800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+5F000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+5F800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+60000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+60800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+61000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+61800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+62000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+62800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+63000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+63800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+64000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+64800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+65000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+65800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+66000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+66800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+67000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+67800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+68000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+68800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+69000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+69800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+6A000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+6A800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+6B000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+6B800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+6C000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+6C800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+6D000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+6D800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+6E000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+6E800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+6F000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+6F800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+70000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+70800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+71000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+71800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+72000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+72800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+73000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+73800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+74000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+74800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+75000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+75800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+76000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+76800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+77000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+77800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+78000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+78800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+79000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+79800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+7A000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+7A800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+7B000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+7B800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+7C000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+7C800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+7D000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+7D800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+7E000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+7E800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+7F000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+7F800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+80000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+80800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+81000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+81800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+82000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+82800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+83000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+83800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+84000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+84800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+85000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+85800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+86000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+86800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+87000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+87800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+88000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+88800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+89000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+89800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+8A000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+8A800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+8B000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+8B800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+8C000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+8C800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+8D000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+8D800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+8E000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+8E800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+8F000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+8F800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+90000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+90800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+91000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+91800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+92000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+92800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+93000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+93800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+94000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+94800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+95000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+95800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+96000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+96800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+97000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+97800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+98000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+98800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+99000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+99800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+9A000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+9A800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+9B000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+9B800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+9C000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+9C800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+9D000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+9D800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+9E000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+9E800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+9F000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+9F800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+A0000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+A0800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+A1000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+A1800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+A2000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+A2800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+A3000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+A3800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+A4000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+A4800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+A5000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+A5800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+A6000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+A6800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+A7000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+A7800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+A8000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+A8800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+A9000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+A9800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+AA000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+AA800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+AB000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+AB800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+AC000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+AC800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+AD000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+AD800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+AE000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+AE800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+AF000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+AF800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+B0000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+B0800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+B1000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+B1800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+B2000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+B2800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+B3000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+B3800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+B4000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+B4800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+B5000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+B5800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+B6000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+B6800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+B7000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+B7800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+B8000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+B8800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+B9000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+B9800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+BA000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+BA800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+BB000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+BB800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+BC000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+BC800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+BD000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+BD800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+BE000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+BE800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+BF000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+BF800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+C0000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+C0800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+C1000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+C1800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+C2000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+C2800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+C3000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+C3800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+C4000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+C4800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+C5000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+C5800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+C6000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+C6800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+C7000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+C7800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+C8000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+C8800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+C9000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+C9800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+CA000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+CA800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+CB000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+CB800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+CC000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+CC800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+CD000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+CD800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+CE000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+CE800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+CF000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+CF800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+D0000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+D0800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+D1000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+D1800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+D2000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+D2800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+D3000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+D3800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+D4000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+D4800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+D5000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+D5800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+D6000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+D6800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+D7000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+D7800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+D8000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+D8800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+D9000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+D9800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+DA000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+DA800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+DB000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+DB800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+DC000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+DC800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+DD000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+DD800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+DE000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+DE800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+DF000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+DF800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+E0000 */148,149,150,151,149,149,149,149,149,149,149,149,149,149,149,149, /* U+E0800 */149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149, /* U+E1000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+E1800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+E2000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+E2800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+E3000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+E3800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+E4000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+E4800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+E5000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+E5800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+E6000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+E6800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+E7000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+E7800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+E8000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+E8800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+E9000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+E9800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+EA000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+EA800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+EB000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+EB800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+EC000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+EC800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+ED000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+ED800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+EE000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+EE800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+EF000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+EF800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+F0000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+F0800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+F1000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+F1800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+F2000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+F2800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+F3000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+F3800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+F4000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+F4800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+F5000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+F5800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+F6000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+F6800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+F7000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+F7800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+F8000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+F8800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+F9000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+F9800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+FA000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+FA800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+FB000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+FB800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+FC000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+FC800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+FD000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+FD800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+FE000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+FE800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+FF000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+FF800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+100000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+100800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+101000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+101800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+102000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+102800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+103000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+103800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+104000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+104800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+105000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+105800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+106000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+106800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+107000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+107800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+108000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+108800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+109000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+109800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+10A000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+10A800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+10B000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+10B800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+10C000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+10C800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+10D000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+10D800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+10E000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+10E800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+10F000 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+10F800 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 }; static const int8_t graph_break_stage2[][128] = { /* block 0 */ { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 9, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2 }, /* block 1 */ { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 2, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 2 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 3 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 4 */ { 0, 0, 0, 3, 3, 3, 3, 3, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 5 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 0, 3, 3, 0, 3, 3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 6 */ { 12, 12, 12, 12, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 7 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 12, 0, 3, 3, 3, 3, 3, 3, 0, 0, 3, 3, 0, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 8 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 9 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0 }, /* block 10 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 11 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 12, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, /* block 12 */ { 5, 5, 5, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 5, 14, 3, 0, 14, 14, 14, 5, 5, 5, 5, 5, 5, 5, 5, 14, 14, 14, 14, 4, 14, 14, 0, 3, 3, 3, 3, 5, 5, 5, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7 }, /* block 13 */ { 0, 5, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 7, 7, 7, 7, 7, 7, 7, 0, 7, 0, 0, 0, 7, 7, 7, 7, 0, 0, 3, 0, 5, 14, 14, 5, 5, 5, 5, 0, 0, 14, 14, 0, 0, 14, 14, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 7, 7, 0, 7, 0, 0, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0 }, /* block 14 */ { 0, 5, 5, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 14, 14, 14, 5, 5, 0, 0, 0, 0, 5, 5, 0, 0, 5, 5, 5, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 15 */ { 0, 5, 5, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 7, 7, 7, 7, 7, 7, 7, 0, 7, 7, 0, 7, 7, 7, 7, 7, 0, 0, 3, 0, 14, 14, 14, 5, 5, 5, 5, 5, 0, 5, 5, 14, 0, 14, 14, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 5, 5, 5, 5, 5, 5 }, /* block 16 */ { 0, 5, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 7, 7, 7, 7, 7, 7, 7, 0, 7, 7, 0, 7, 7, 7, 7, 7, 0, 0, 3, 0, 5, 5, 14, 5, 5, 5, 5, 0, 0, 14, 14, 0, 0, 14, 14, 4, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 0, 0, 0, 7, 7, 0, 7, 0, 0, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 17 */ { 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 14, 5, 14, 14, 0, 0, 0, 14, 14, 14, 0, 14, 14, 14, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 18 */ { 5, 14, 14, 14, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 3, 0, 5, 5, 5, 14, 14, 14, 14, 0, 5, 5, 5, 0, 5, 5, 5, 4, 0, 0, 0, 0, 0, 0, 0, 3, 3, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 19 */ { 0, 5, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 14, 5, 14, 14, 5, 14, 14, 0, 5, 14, 14, 0, 14, 14, 5, 5, 0, 0, 0, 0, 0, 0, 0, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 20 */ { 5, 5, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 3, 3, 0, 5, 14, 14, 5, 5, 5, 5, 0, 14, 14, 14, 0, 14, 14, 14, 4, 12, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 21 */ { 0, 5, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 5, 14, 14, 5, 5, 5, 0, 5, 0, 14, 14, 14, 14, 14, 14, 14, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 22 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 14, 5, 5, 5, 5, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 3, 3, 3, 3, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 23 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 14, 5, 5, 5, 5, 3, 3, 3, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 24 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 3, 0, 3, 0, 0, 0, 0, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 5, 3, 5, 5, 5, 5, 5, 3, 3, 3, 3, 5, 14 }, /* block 25 */ { 3, 5, 3, 3, 3, 0, 3, 3, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 26 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 14, 5, 5, 5, 5, 5, 3, 0, 3, 3, 14, 14, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 5, 5, 0, 0, 0, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 27 */ { 0, 0, 5, 0, 14, 5, 5, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 28 */ { 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16 }, /* block 29 */ { 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15 }, /* block 30 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 31 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 3, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 32 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 14, 5, 5, 5, 5, 5, 5, 5, 14, 14, 14, 14, 14, 14, 14, 14, 5, 14, 14, 5, 5, 5, 5, 5, 5, 5, 5, 5, 3, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 33 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 2, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 34 */ { 0, 0, 0, 0, 0, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 35 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 14, 14, 14, 14, 5, 5, 14, 14, 14, 0, 0, 0, 0, 14, 14, 5, 14, 14, 14, 14, 14, 14, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 36 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 14, 14, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 5, 14, 5, 5, 5, 5, 5, 5, 5, 0, 3, 0, 5, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 14, 14, 14, 14, 14, 14, 5, 5, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 3 }, /* block 37 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 38 */ { 5, 5, 5, 5, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 5, 5, 5, 5, 5, 5, 14, 5, 14, 14, 14, 14, 14, 5, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 39 */ { 5, 5, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 5, 5, 5, 5, 14, 14, 5, 5, 14, 3, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 14, 5, 5, 14, 14, 14, 5, 14, 5, 5, 5, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 40 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 14, 14, 14, 14, 14, 5, 5, 5, 5, 5, 5, 5, 5, 14, 14, 5, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 41 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 14, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 3, 0, 0, 14, 3, 3, 0, 0, 0, 0, 0, 0 }, /* block 42 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, /* block 43 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 5, 17, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 44 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 5, 5, 5, 3, 5, 5, 5, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 45 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 46 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 47 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 48 */ { 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0, 0, 0, 0, 6, 6, 6, 0, 0, 0, 0, 0 }, /* block 49 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 50 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 6, 0 }, /* block 51 */ { 6, 6, 6, 6, 6, 6, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6 }, /* block 52 */ { 6, 6, 6, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6 }, /* block 53 */ { 6, 6, 6, 6, 6, 6, 0, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0, 6, 0, 6, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 6, 0, 0, 0, 0, 6, 0, 6, 0, 0, 0, 0, 6, 6, 6, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 54 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 55 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 56 */ { 0, 0, 0, 0, 0, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 57 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 58 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3 }, /* block 59 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, /* block 60 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 61 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 62 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 63 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 5, 5, 5, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0 }, /* block 64 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 65 */ { 0, 0, 5, 0, 0, 0, 5, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 5, 5, 14, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 66 */ { 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5 }, /* block 67 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0 }, /* block 68 */ { 5, 5, 5, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 14, 14, 5, 5, 5, 5, 14, 14, 5, 5, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 69 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 14, 14, 5, 5, 14, 14, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 5, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0 }, /* block 70 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 3, 3, 3, 0, 0, 3, 3, 0, 0, 0, 0, 0, 3, 3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 5, 5, 14, 14, 0, 0, 0, 0, 0, 14, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 71 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 5, 14, 14, 5, 14, 14, 0, 14, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 72 */ { 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11 }, /* block 73 */ { 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 10, 11, 11, 11 }, /* block 74 */ { 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11 }, /* block 75 */ { 11, 11, 11, 11, 11, 11, 11, 11, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 10, 11, 11, 11, 11, 11, 11, 11 }, /* block 76 */ { 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11 }, /* block 77 */ { 11, 11, 11, 11, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11 }, /* block 78 */ { 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11 }, /* block 79 */ { 11, 11, 11, 11, 11, 11, 11, 11, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0 }, /* block 80 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 81 */ { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 82 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2 }, /* block 83 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0 }, /* block 84 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0 }, /* block 85 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 86 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0 }, /* block 87 */ { 0, 5, 5, 5, 0, 5, 5, 0, 0, 0, 0, 0, 5, 3, 5, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 88 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 89 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 90 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3 }, /* block 91 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 92 */ { 0, 0, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 93 */ { 14, 5, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3 }, /* block 94 */ { 5, 5, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 5, 5, 5, 5, 14, 14, 5, 3, 0, 0, 12, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 95 */ { 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 14, 5, 5, 5, 5, 5, 5, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 96 */ { 5, 5, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 5, 5, 5, 5, 5, 5, 5, 5, 5, 14, 14, 0, 12, 12, 0, 0, 0, 0, 0, 5, 3, 5, 5, 0, 14, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 97 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 5, 5, 5, 14, 14, 5, 14, 3, 5, 0, 0, 0, 0, 0, 0, 5, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 98 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 14, 14, 14, 5, 5, 5, 5, 5, 5, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 99 */ { 5, 5, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 0, 5, 14, 5, 14, 14, 14, 14, 0, 0, 14, 14, 0, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 0, 0, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 100 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 5, 5, 5, 5, 5, 5, 5, 5, 14, 14, 5, 5, 5, 14, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 101 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 14, 14, 5, 5, 5, 5, 5, 5, 14, 5, 14, 14, 5, 14, 5, 5, 14, 5, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 102 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 14, 14, 5, 5, 5, 5, 0, 0, 14, 14, 14, 14, 5, 5, 14, 5, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 103 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 5, 5, 5, 5, 5, 5, 5, 5, 14, 14, 5, 14, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 104 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 14, 5, 14, 14, 5, 5, 5, 5, 5, 5, 14, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 105 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 0, 5, 5, 5, 5, 14, 5, 5, 5, 5, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 106 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 5, 5, 5, 5, 5, 5, 5, 5, 5, 14, 5, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 107 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 14, 14, 14, 14, 14, 0, 14, 14, 0, 0, 5, 5, 14, 3, 12, 14, 12, 14, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 108 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 5, 5, 5, 5, 0, 0, 5, 5, 14, 14, 14, 14, 5, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 109 */ { 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 3, 5, 5, 5, 5, 14, 12, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 14, 14, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 110 */ { 0, 0, 0, 0, 12, 12, 12, 12, 12, 12, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 14, 5, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 111 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 5, 5, 5, 5, 5, 5, 5, 0, 5, 5, 5, 5, 5, 5, 14, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 112 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 14, 5, 5, 5, 5, 5, 5, 5, 14, 5, 5, 14, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 113 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 0, 0, 0, 5, 0, 5, 5, 0, 5, 5, 5, 3, 5, 3, 3, 12, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 114 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 14, 14, 0, 5, 5, 0, 14, 14, 5, 14, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 115 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 116 */ { 5, 5, 12, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 5, 5, 5, 5, 5, 0, 0, 0, 14, 14, 5, 14, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 117 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 118 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 119 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 120 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14 }, /* block 121 */ { 14, 14, 14, 14, 14, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 122 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 3, 0, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 123 */ { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 124 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 14, 3, 3, 3, 0, 0, 0, 14, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3 }, /* block 125 */ { 3, 3, 3, 0, 0, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 126 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 127 */ { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 128 */ { 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 129 */ { 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 0, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 130 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 131 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 132 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 133 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 134 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 135 */ { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6 }, /* block 136 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6 }, /* block 137 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13 }, /* block 138 */ { 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0, 6, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6 }, /* block 139 */ { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5 }, /* block 140 */ { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6 }, /* block 141 */ { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 142 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6 }, /* block 143 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6 }, /* block 144 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 145 */ { 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6 }, /* block 146 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6 }, /* block 147 */ { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0, 0 }, /* block 148 */ { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 }, /* block 149 */ { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 }, /* block 150 */ { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 }, /* block 151 */ { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 } }; static int graph_break(int32_t code) { const int32_t block_size = 128; uint8_t i = graph_break_stage1[code / block_size]; return graph_break_stage2[i][code % block_size]; } #endif /* UNICODE_GRAPHBREAK_H */ cli/src/init.c0000644000176200001440000001066314752735214012737 0ustar liggesusers #include "cli.h" #include "keypress.h" #include "cleancall.h" #include #include // Compile with `C_VISIBILITY = -fvisibility=hidden` if you link to // this library #include #define r_export attribute_visible extern SEXP clic_unload(void) { clic_stop_thread(); return R_NilValue; } SEXP clic_dataptr(SEXP x); #ifdef GCOV_COMPILE void __gcov_dump(); SEXP clic__gcov_flush() { REprintf("Flushing coverage info\n"); __gcov_dump(); return R_NilValue; } #else SEXP clic__gcov_flush(void) { return R_NilValue; } #endif static const R_CallMethodDef callMethods[] = { CLEANCALL_METHOD_RECORD, { "clic_diff_chr", (DL_FUNC) clic_diff_chr, 3 }, { "clic_getppid", (DL_FUNC) clic_getppid, 0 }, { "clic_md5", (DL_FUNC) clic_md5, 1 }, { "clic_md5_raw", (DL_FUNC) clic_md5_raw, 1 }, { "clic_md5_file", (DL_FUNC) clic_md5_file, 1 }, { "clic_sha256", (DL_FUNC) clic_sha256, 1 }, { "clic_sha256_raw", (DL_FUNC) clic_sha256_raw, 1 }, { "clic_sha256_file", (DL_FUNC) clic_sha256_file, 1 }, { "clic_sha1", (DL_FUNC) clic_sha1, 1 }, { "clic_sha1_raw", (DL_FUNC) clic_sha1_raw, 1 }, { "clic_sha1_file", (DL_FUNC) clic_sha1_file, 1 }, { "clic_xxhash", (DL_FUNC) clic_xxhash, 1 }, { "clic_xxhash_raw", (DL_FUNC) clic_xxhash_raw, 1 }, { "clic_xxhash_file", (DL_FUNC) clic_xxhash_file, 1 }, { "clic_xxhash64", (DL_FUNC) clic_xxhash64, 1 }, { "clic_xxhash64_raw", (DL_FUNC) clic_xxhash64_raw, 1 }, { "clic_xxhash64_file", (DL_FUNC) clic_xxhash64_file, 1 }, { "clic_tty_size", (DL_FUNC) clic_tty_size, 0 }, { "clic_ansi_simplify", (DL_FUNC) clic_ansi_simplify, 2 }, { "clic_ansi_substr", (DL_FUNC) clic_ansi_substr, 3 }, { "clic_ansi_html", (DL_FUNC) clic_ansi_html, 2 }, { "clic_ansi_has_any", (DL_FUNC) clic_ansi_has_any, 4 }, { "clic_ansi_strip", (DL_FUNC) clic_ansi_strip, 4 }, { "clic_ansi_nchar", (DL_FUNC) clic_ansi_nchar, 2 }, { "clic_utf8_display_width", (DL_FUNC) clic_utf8_display_width, 1 }, { "clic_utf8_nchar_graphemes", (DL_FUNC) clic_utf8_nchar_graphemes, 1 }, { "clic_utf8_substr", (DL_FUNC) clic_utf8_substr, 3 }, { "clic_utf8_graphemes", (DL_FUNC) clic_utf8_graphemes, 1 }, { "clic_dataptr", (DL_FUNC) clic_dataptr, 1 }, { "clic_start_thread", (DL_FUNC) clic_start_thread, 3 }, { "clic_stop_thread", (DL_FUNC) clic_stop_thread, 0 }, { "clic_tick_reset", (DL_FUNC) clic_tick_reset, 0 }, { "clic_tick_set", (DL_FUNC) clic_tick_set, 2 }, { "clic_tick_pause", (DL_FUNC) clic_tick_pause, 1 }, { "clic_tick_resume", (DL_FUNC) clic_tick_resume, 1 }, { "clic_unload", (DL_FUNC) clic_unload, 0 }, { "clic_get_time", (DL_FUNC) clic_get_time, 0 }, { "clic_make_timer", (DL_FUNC) clic_make_timer, 0 }, { "clic_update_due", (DL_FUNC) clic_update_due, 0 }, { "clic_progress_along", (DL_FUNC) clic_progress_along, 2 }, { "clic__find_var", (DL_FUNC) clic__find_var, 2 }, { "clic__gcov_flush", (DL_FUNC) clic__gcov_flush, 0 }, { "clic_get_embedded_utf8", (DL_FUNC) clic_get_embedded_utf8, 0 }, { "clic_set_embedded_utf8", (DL_FUNC) clic_set_embedded_utf8, 1 }, { "glue_", (DL_FUNC) glue_, 5 }, { "trim_", (DL_FUNC) trim_, 1 }, { "clic_vt_output", (DL_FUNC) clic_vt_output, 3 }, { "cli_keypress", (DL_FUNC) cli_keypress, 1 }, { NULL, NULL, 0 } }; #define RCC(fun) R_RegisterCCallable("cli", # fun, (DL_FUNC) fun); r_export void R_init_cli(DllInfo *dll) { #if R_VERSION >= R_Version(3, 5, 0) cli_init_altrep(dll); #endif R_registerRoutines(dll, NULL, callMethods, NULL, NULL); R_useDynamicSymbols(dll, FALSE); R_forceSymbols(dll, TRUE); cleancall_fns_dot_call = Rf_findVar(Rf_install(".Call"), R_BaseEnv); RCC(cli_progress_add); RCC(cli_progress_bar); RCC(cli_progress_done); RCC(cli_progress_init_timer); RCC(cli_progress_num); RCC(cli_progress_set); RCC(cli_progress_set_clear); RCC(cli_progress_set_format); RCC(cli_progress_set_name); RCC(cli_progress_set_status); RCC(cli_progress_set_type); RCC(cli_progress_update); RCC(cli_progress_sleep); } cli/src/keypress-win.c0000644000176200001440000000765114557444176014446 0ustar liggesusers /* Avoid warning about empty compilation unit. */ void keypress_win_dummy(void) { } #ifdef WIN32 #include "errors.h" #include "keypress.h" #include static HANDLE console_in, console_out; static int enableRawMode(void) { if (!console_in) { HANDLE hin, hout; hin = GetStdHandle(STD_INPUT_HANDLE); if (hin == INVALID_HANDLE_VALUE) { R_THROW_SYSTEM_ERROR("Cannot get standard input handle"); } hout = GetStdHandle(STD_OUTPUT_HANDLE); if (hout == INVALID_HANDLE_VALUE) { R_THROW_SYSTEM_ERROR("Cannot get standard output handle"); } console_in = hin; console_out = hout; } return 0; } static int disableRawMode(void) { /* Nothing to do yet */ return 0; } keypress_key_t getWinChar(int block) { INPUT_RECORD rec; DWORD count; char buf[2] = { 0, 0 }; int chr; for (;; Sleep(10)) { GetNumberOfConsoleInputEvents(console_in, &count); if ((count == 0) && (block == NON_BLOCKING)) { return keypress_special(KEYPRESS_NONE); } if (! ReadConsoleInputA(console_in, &rec, 1, &count)) { R_THROW_SYSTEM_ERROR("Cannot read from console"); } if (rec.EventType != KEY_EVENT) continue; if (! rec.Event.KeyEvent.bKeyDown) continue; buf[0] = chr = rec.Event.KeyEvent.uChar.AsciiChar; switch (rec.Event.KeyEvent.wVirtualKeyCode) { case VK_RETURN: return keypress_special(KEYPRESS_ENTER); case VK_BACK: return keypress_special(KEYPRESS_BACKSPACE); case VK_LEFT: return keypress_special(KEYPRESS_LEFT); case VK_RIGHT: return keypress_special(KEYPRESS_RIGHT); case VK_UP: return keypress_special(KEYPRESS_UP); case VK_DOWN: return keypress_special(KEYPRESS_DOWN); case VK_INSERT: return keypress_special(KEYPRESS_INSERT); case VK_DELETE: return keypress_special(KEYPRESS_DELETE); case VK_HOME: return keypress_special(KEYPRESS_HOME); case VK_END: return keypress_special(KEYPRESS_END); case VK_ESCAPE: return keypress_special(KEYPRESS_ESCAPE); case VK_F1: return keypress_special(KEYPRESS_F1); case VK_F2: return keypress_special(KEYPRESS_F2); case VK_F3: return keypress_special(KEYPRESS_F3); case VK_F4: return keypress_special(KEYPRESS_F4); case VK_F5: return keypress_special(KEYPRESS_F5); case VK_F6: return keypress_special(KEYPRESS_F6); case VK_F7: return keypress_special(KEYPRESS_F7); case VK_F8: return keypress_special(KEYPRESS_F8); case VK_F9: return keypress_special(KEYPRESS_F9); case VK_F10: return keypress_special(KEYPRESS_F10); case VK_F11: return keypress_special(KEYPRESS_F11); case VK_F12: return keypress_special(KEYPRESS_F12); default: if (rec.Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) { switch (chr) { case 1: return keypress_special(KEYPRESS_CTRL_A); case 2: return keypress_special(KEYPRESS_CTRL_B); case 3: return keypress_special(KEYPRESS_CTRL_C); case 4: return keypress_special(KEYPRESS_CTRL_D); case 5: return keypress_special(KEYPRESS_CTRL_E); case 6: return keypress_special(KEYPRESS_CTRL_F); case 8: return keypress_special(KEYPRESS_CTRL_H); case 9: return keypress_special(KEYPRESS_TAB); case 11: return keypress_special(KEYPRESS_CTRL_K); case 12: return keypress_special(KEYPRESS_CTRL_L); case 14: return keypress_special(KEYPRESS_CTRL_N); case 16: return keypress_special(KEYPRESS_CTRL_P); case 20: return keypress_special(KEYPRESS_CTRL_T); case 21: return keypress_special(KEYPRESS_CTRL_U); case 22: return keypress_special(KEYPRESS_CTRL_W); } } else if (buf[0]) { return keypress_utf8(buf); } } } } keypress_key_t keypress_read(int block) { keypress_key_t res; CONSOLE_SCREEN_BUFFER_INFO inf; enableRawMode(); if (! GetConsoleScreenBufferInfo(console_out, &inf)) { R_THROW_SYSTEM_ERROR("Cannot query console information"); } res = getWinChar(block); disableRawMode(); return res; } #endif cli/src/sha256.c0000644000176200001440000002151414557444176013010 0ustar liggesusers /********************************************************************* * Filename: sha256.h * Author: Brad Conte (brad AT bradconte.com) * Copyright: * Disclaimer: This code is presented "as is" without any guarantees. * Details: Defines the API for the corresponding SHA1 implementation. *********************************************************************/ #ifndef SHA256_H #define SHA256_H /*************************** HEADER FILES ***************************/ #include /****************************** MACROS ******************************/ #define SHA256_BLOCK_SIZE 32 // SHA256 outputs a 32 byte digest /**************************** DATA TYPES ****************************/ typedef unsigned char BYTE; // 8-bit byte typedef unsigned int WORD32; // 32-bit word, change to "long" for 16-bit machines typedef struct { BYTE data[64]; WORD32 datalen; unsigned long long bitlen; WORD32 state[8]; } SHA256_CTX; /*********************** FUNCTION DECLARATIONS **********************/ void sha256_init(SHA256_CTX *ctx); void sha256_update(SHA256_CTX *ctx, const BYTE data[], size_t len); void sha256_final(SHA256_CTX *ctx, BYTE hash[]); #endif // SHA256_H /********************************************************************* * Filename: sha256.c * Author: Brad Conte (brad AT bradconte.com) * Copyright: * Disclaimer: This code is presented "as is" without any guarantees. * Details: Implementation of the SHA-256 hashing algorithm. SHA-256 is one of the three algorithms in the SHA2 specification. The others, SHA-384 and SHA-512, are not offered in this implementation. Algorithm specification can be found here: * http://csrc.nist.gov/publications/fips/fips180-2/fips180-2withchangenotice.pdf This implementation uses little endian byte order. *********************************************************************/ /*************************** HEADER FILES ***************************/ #include #include /****************************** MACROS ******************************/ #define ROTLEFT(a,b) (((a) << (b)) | ((a) >> (32-(b)))) #define ROTRIGHT(a,b) (((a) >> (b)) | ((a) << (32-(b)))) #define CH(x,y,z) (((x) & (y)) ^ (~(x) & (z))) #define MAJ(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) #define EP0(x) (ROTRIGHT(x,2) ^ ROTRIGHT(x,13) ^ ROTRIGHT(x,22)) #define EP1(x) (ROTRIGHT(x,6) ^ ROTRIGHT(x,11) ^ ROTRIGHT(x,25)) #define SIG0(x) (ROTRIGHT(x,7) ^ ROTRIGHT(x,18) ^ ((x) >> 3)) #define SIG1(x) (ROTRIGHT(x,17) ^ ROTRIGHT(x,19) ^ ((x) >> 10)) /**************************** VARIABLES *****************************/ static const WORD32 k[64] = { 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5, 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174, 0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da, 0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967, 0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85, 0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070, 0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3, 0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2 }; /*********************** FUNCTION DEFINITIONS ***********************/ void sha256_transform(SHA256_CTX *ctx, const BYTE data[]) { WORD32 a, b, c, d, e, f, g, h, i, j, t1, t2, m[64]; for (i = 0, j = 0; i < 16; ++i, j += 4) m[i] = ((WORD32)data[j] << 24) | ((WORD32)data[j + 1] << 16) | ((WORD32)data[j + 2] << 8) | ((WORD32)data[j + 3]); for ( ; i < 64; ++i) m[i] = SIG1(m[i - 2]) + m[i - 7] + SIG0(m[i - 15]) + m[i - 16]; a = ctx->state[0]; b = ctx->state[1]; c = ctx->state[2]; d = ctx->state[3]; e = ctx->state[4]; f = ctx->state[5]; g = ctx->state[6]; h = ctx->state[7]; for (i = 0; i < 64; ++i) { t1 = h + EP1(e) + CH(e,f,g) + k[i] + m[i]; t2 = EP0(a) + MAJ(a,b,c); h = g; g = f; f = e; e = d + t1; d = c; c = b; b = a; a = t1 + t2; } ctx->state[0] += a; ctx->state[1] += b; ctx->state[2] += c; ctx->state[3] += d; ctx->state[4] += e; ctx->state[5] += f; ctx->state[6] += g; ctx->state[7] += h; } void sha256_init(SHA256_CTX *ctx) { ctx->datalen = 0; ctx->bitlen = 0; ctx->state[0] = 0x6a09e667; ctx->state[1] = 0xbb67ae85; ctx->state[2] = 0x3c6ef372; ctx->state[3] = 0xa54ff53a; ctx->state[4] = 0x510e527f; ctx->state[5] = 0x9b05688c; ctx->state[6] = 0x1f83d9ab; ctx->state[7] = 0x5be0cd19; } void sha256_update(SHA256_CTX *ctx, const BYTE data[], size_t len) { WORD32 i; for (i = 0; i < len; ++i) { ctx->data[ctx->datalen] = data[i]; ctx->datalen++; if (ctx->datalen == 64) { sha256_transform(ctx, ctx->data); ctx->bitlen += 512; ctx->datalen = 0; } } } void sha256_final(SHA256_CTX *ctx, BYTE hash[]) { WORD32 i; i = ctx->datalen; // Pad whatever data is left in the buffer. if (ctx->datalen < 56) { ctx->data[i++] = 0x80; while (i < 56) ctx->data[i++] = 0x00; } else { ctx->data[i++] = 0x80; while (i < 64) ctx->data[i++] = 0x00; sha256_transform(ctx, ctx->data); memset(ctx->data, 0, 56); } // Append to the padding the total message's length in bits and transform. ctx->bitlen += ctx->datalen * 8; ctx->data[63] = ctx->bitlen; ctx->data[62] = ctx->bitlen >> 8; ctx->data[61] = ctx->bitlen >> 16; ctx->data[60] = ctx->bitlen >> 24; ctx->data[59] = ctx->bitlen >> 32; ctx->data[58] = ctx->bitlen >> 40; ctx->data[57] = ctx->bitlen >> 48; ctx->data[56] = ctx->bitlen >> 56; sha256_transform(ctx, ctx->data); // Since this implementation uses little endian byte ordering and SHA uses big endian, // reverse all the bytes when copying the final state to the output hash. for (i = 0; i < 4; ++i) { hash[i] = (ctx->state[0] >> (24 - i * 8)) & 0x000000ff; hash[i + 4] = (ctx->state[1] >> (24 - i * 8)) & 0x000000ff; hash[i + 8] = (ctx->state[2] >> (24 - i * 8)) & 0x000000ff; hash[i + 12] = (ctx->state[3] >> (24 - i * 8)) & 0x000000ff; hash[i + 16] = (ctx->state[4] >> (24 - i * 8)) & 0x000000ff; hash[i + 20] = (ctx->state[5] >> (24 - i * 8)) & 0x000000ff; hash[i + 24] = (ctx->state[6] >> (24 - i * 8)) & 0x000000ff; hash[i + 28] = (ctx->state[7] >> (24 - i * 8)) & 0x000000ff; } } static void bin2str(char *to, const unsigned char *p, size_t len) { static const char *hex = "0123456789abcdef"; for (; len--; p++) { *to++ = hex[p[0] >> 4]; *to++ = hex[p[0] & 0x0f]; } } #include "errors.h" #include #include SEXP clic_sha256(SEXP strs) { BYTE hash[32]; char hex[64]; SHA256_CTX ctx; R_xlen_t i, len = XLENGTH(strs); SEXP result = PROTECT(Rf_allocVector(STRSXP, len)); for (i = 0; i < len; i++) { const char *s = CHAR(STRING_ELT(strs, i)); sha256_init(&ctx); sha256_update(&ctx, (const BYTE*) s, strlen(s)); sha256_final(&ctx, hash); bin2str(hex, hash, sizeof(hash)); SET_STRING_ELT( result, i, Rf_mkCharLenCE((const char*) hex, sizeof(hex), CE_UTF8) ); } UNPROTECT(1); return result; } SEXP clic_sha256_raw(SEXP r) { Rbyte *ptr = RAW(r); Rbyte *end = ptr + XLENGTH(r); size_t step = SIZE_MAX < 0x40000000 ? SIZE_MAX & ~63 : 0x40000000; SHA256_CTX ctx; BYTE hash[32]; char hex[64]; sha256_init(&ctx); while (ptr < end) { Rbyte *nxt = ptr + step; if (nxt > end) nxt = end; sha256_update(&ctx, ptr, nxt - ptr); ptr = nxt; } sha256_final(&ctx, hash); bin2str(hex, hash, sizeof(hash)); return Rf_ScalarString(Rf_mkCharLenCE( (const char*) hex, sizeof(hex), CE_UTF8 )); } #include "winfiles.h" #include #include SEXP clic_sha256_file(SEXP paths) { BYTE hash[32]; char hex[64]; SHA256_CTX ctx; R_xlen_t i, len = XLENGTH(paths); #define BUFSIZE (1 * 1024*1024) char *buffer = R_alloc(1, BUFSIZE); SEXP result = PROTECT(Rf_allocVector(STRSXP, len)); for (i = 0; i < len; i++) { const char *cpath = CHAR(STRING_ELT(paths, i)); int fd = open_file(cpath, O_RDONLY); if (fd == -1) { R_THROW_SYSTEM_ERROR("Cannot open file `%s`", cpath); } sha256_init(&ctx); ssize_t got = read(fd, buffer, BUFSIZE); if (got == -1) { close(fd); R_THROW_SYSTEM_ERROR("Cannot read from file `%s`", cpath); } while (got > 0) { sha256_update(&ctx, (const BYTE*) buffer, got); got = read(fd, buffer, BUFSIZE); if (got == -1) { close(fd); R_THROW_SYSTEM_ERROR("Cannot read from file `%s`", cpath); } } close(fd); sha256_final(&ctx, hash); bin2str(hex, hash, sizeof(hash)); SET_STRING_ELT( result, i, Rf_mkCharLenCE((const char*) hex, sizeof(hex), CE_UTF8) ); } UNPROTECT(1); return result; } cli/src/glue.c0000644000176200001440000002071014557444176012731 0ustar liggesusers #define STRICT_R_HEADERS #define R_NO_REMAP #include "Rinternals.h" #include #include #include SEXP set(SEXP x, int i, SEXP val) { R_xlen_t len = Rf_xlength(x); if (i >= len) { len *= 2; x = Rf_lengthgets(x, len); } SET_VECTOR_ELT(x, i, val); return x; } SEXP resize(SEXP out, R_xlen_t n) { if (n == Rf_xlength(out)) { return out; } return Rf_xlengthgets(out, n); } // This is almost like the original glue parser, except that // - no comment_arg (always empty string) // - no literal_arg // - If cli_arg is FALSE, then literal = 1, always // - If cli_arg is TRUE, then we use literal = 1, except in {} // evaluations (as opposed to {.} for cli styles), where literal = 0 is // used. SEXP glue_(SEXP x, SEXP f, SEXP open_arg, SEXP close_arg, SEXP cli_arg) { typedef enum { text, escape, single_quote, double_quote, backtick, delim, comment } states; const char* xx = Rf_translateCharUTF8(STRING_ELT(x, 0)); size_t str_len = strlen(xx); char* str = (char*)malloc(str_len + 1); const char* open = CHAR(STRING_ELT(open_arg, 0)); size_t open_len = strlen(open); const char* close = CHAR(STRING_ELT(close_arg, 0)); size_t close_len = strlen(close); char comment_char = '\0'; Rboolean cli = LOGICAL(cli_arg)[0]; Rboolean literal = 1; int delim_equal = strncmp(open, close, open_len) == 0; SEXP out = Rf_allocVector(VECSXP, 1); PROTECT_INDEX out_idx; PROTECT_WITH_INDEX(out, &out_idx); size_t j = 0; size_t k = 0; int delim_level = 0; size_t start = 0; states state = text; states prev_state = text; size_t i = 0; for (i = 0; i < str_len; ++i) { switch (state) { case text: { if (strncmp(&xx[i], open, open_len) == 0) { /* check for open delim doubled */ if (strncmp(&xx[i + open_len], open, open_len) == 0) { i += open_len; } else { state = delim; delim_level = 1; start = i + open_len; // In cli mode we switch to literal = FALSE for a {} block if (cli && xx[i + open_len] != '.') literal = 0; break; } } if (strncmp(&xx[i], close, close_len) == 0 && strncmp(&xx[i + close_len], close, close_len) == 0) { i += close_len; } str[j++] = xx[i]; break; } case escape: { state = prev_state; break; } case single_quote: { if (xx[i] == '\\') { prev_state = single_quote; state = escape; } else if (xx[i] == '\'') { state = delim; } break; } case double_quote: { if (xx[i] == '\\') { prev_state = double_quote; state = escape; } else if (xx[i] == '\"') { state = delim; } break; } case backtick: { if (xx[i] == '\\') { prev_state = backtick; state = escape; } else if (xx[i] == '`') { state = delim; } break; } case comment: { if (xx[i] == '\n') { state = delim; } break; } case delim: { if (!delim_equal && strncmp(&xx[i], open, open_len) == 0) { ++delim_level; // In cli mode we switch to literal = FALSE for a {} block if (cli && xx[i + open_len] != '.') literal = 0; i += open_len - 1; } else if (strncmp(&xx[i], close, close_len) == 0) { // in non-{} blocks (i.e. {.}) we need literal = 1. We can always // switch to literal = 1 here, because {} blocks cannot be nested. literal = 1; --delim_level; i += close_len - 1; } else { if (!literal && xx[i] == comment_char) { state = comment; } else { switch (xx[i]) { case '\'': if (!literal) { state = single_quote; } break; case '"': if (!literal) { state = double_quote; } break; case '`': if (!literal) { state = backtick; } break; }; } } if (delim_level == 0) { /* Result of the current glue statement */ SEXP expr = PROTECT(Rf_ScalarString( Rf_mkCharLenCE(&xx[start], (i - close_len) + 1 - start, CE_UTF8))); SEXP call = PROTECT(Rf_lang2(f, expr)); SEXP result = PROTECT(Rf_eval(call, R_EmptyEnv)); /* text in between last glue statement */ if (j > 0) { str[j] = '\0'; SEXP str_ = PROTECT(Rf_ScalarString(Rf_mkCharLenCE(str, j, CE_UTF8))); REPROTECT(out = set(out, k++, str_), out_idx); UNPROTECT(1); } REPROTECT(out = set(out, k++, result), out_idx); /* Clear the string buffer */ memset(str, 0, j); j = 0; UNPROTECT(3); state = text; } break; } }; } if (k == 0 || j > 0) { str[j] = '\0'; SEXP str_ = PROTECT(Rf_ScalarString(Rf_mkCharLenCE(str, j, CE_UTF8))); REPROTECT(out = set(out, k++, str_), out_idx); UNPROTECT(1); } if (state == delim) { free(str); Rf_error("Expecting '%s'", close); } else if (state == single_quote) { free(str); Rf_error("Unterminated quote (')"); } else if (state == double_quote) { free(str); Rf_error("Unterminated quote (\")"); } else if (state == backtick) { free(str); Rf_error("Unterminated quote (`)"); } else if (state == comment) { free(str); Rf_error("Unterminated comment"); } free(str); out = resize(out, k); UNPROTECT(1); return out; } SEXP trim_(SEXP x) { size_t len = LENGTH(x); SEXP out = PROTECT(Rf_allocVector(STRSXP, len)); size_t num; for (num = 0; num < len; ++num) { const char* xx = Rf_translateCharUTF8(STRING_ELT(x, num)); size_t str_len = strlen(xx); char* str = (char*)malloc(str_len + 1); size_t i = 0, start = 0; bool new_line = false; /* skip leading blanks on first line */ while (start < str_len && (xx[start] == ' ' || xx[start] == '\t')) { ++start; } /* Skip first newline */ if (start < str_len && xx[start] == '\n') { new_line = true; ++start; } i = start; /* Ignore first line */ if (!new_line) { while (i < str_len && xx[i] != '\n') { ++i; } new_line = true; } size_t indent = 0; /* Maximum size of size_t */ size_t min_indent = (size_t)-1; /* find minimum indent */ while (i < str_len) { if (xx[i] == '\n') { new_line = true; indent = 0; } else if (new_line) { if (xx[i] == ' ' || xx[i] == '\t') { ++indent; } else { if (indent < min_indent) { min_indent = indent; } indent = 0; new_line = false; } } ++i; } /* if string ends with '\n', `indent = 0` only because we made it so */ if (xx[str_len - 1] != '\n' && new_line && indent < min_indent) { min_indent = indent; } new_line = true; i = start; size_t j = 0; /*Rprintf("start: %i\nindent: %i\nmin_indent: %i", start, indent, * min_indent);*/ /* copy the string removing the minimum indent from new lines */ while (i < str_len) { if (xx[i] == '\n') { new_line = true; } else if (xx[i] == '\\' && i + 1 < str_len && xx[i + 1] == '\n') { new_line = true; i += 2; continue; } else if (new_line) { size_t skipped = strspn(xx + i, "\t "); /* * if the line consists only of tabs and spaces, and if the line is * shorter than min_indent, copy the entire line and proceed to the * next */ if (*(xx + i + skipped) == '\n' && skipped < min_indent) { strncpy(str + j, xx + i, skipped); i += skipped; j += skipped; } else { if (i + min_indent < str_len && (xx[i] == ' ' || xx[i] == '\t')) { i += min_indent; } } new_line = false; continue; } str[j++] = xx[i++]; } str[j] = '\0'; /* Remove trailing whitespace up to the first newline */ size_t end = j; while (j > 0) { if (str[j] == '\n') { end = j; break; } else if (str[j] == '\0' || str[j] == ' ' || str[j] == '\t') { --j; } else { break; } } str[end] = '\0'; SET_STRING_ELT(out, num, Rf_mkCharCE(str, CE_UTF8)); free(str); } UNPROTECT(1); return out; } cli/src/xxhash2.c0000644000176200001440000001075214752735214013360 0ustar liggesusers#include #include #include #include "errors.h" // must match xxhash.c #define XXH_STATIC_LINKING_ONLY /* access advanced declarations */ #define XXH_IMPLEMENTATION /* access definitions */ #define XXH_INLINE_ALL #include "xxhash.h" SEXP clic_xxhash(SEXP strs) { XXH128_hash_t hash; char str[32 + 1]; R_xlen_t i, len = XLENGTH(strs); SEXP result = PROTECT(Rf_allocVector(STRSXP, len)); for (i = 0; i < len; i++) { const char *s = CHAR(STRING_ELT(strs, i)); hash = XXH3_128bits_withSeed(s, strlen(s), 0); snprintf(str, sizeof(str), "%016" PRIx64 "%016" PRIx64, hash.high64, hash.low64); SET_STRING_ELT(result, i, Rf_mkCharLenCE(str, 32, CE_UTF8)); } UNPROTECT(1); return result; } SEXP clic_xxhash64(SEXP strs) { XXH64_hash_t hash; char str[16 + 1]; R_xlen_t i, len = XLENGTH(strs); SEXP result = PROTECT(Rf_allocVector(STRSXP, len)); for (i = 0; i < len; i++) { const char *s = CHAR(STRING_ELT(strs, i)); hash = XXH3_64bits_withSeed(s, strlen(s), 0); snprintf(str, sizeof(str), "%016" PRIx64, hash); SET_STRING_ELT(result, i, Rf_mkCharLenCE(str, 16, CE_UTF8)); } UNPROTECT(1); return result; } SEXP clic_xxhash_raw(SEXP r) { XXH128_hash_t hash = XXH3_128bits_withSeed( RAW(r), Rf_length(r), 0 ); char str[32 + 1]; snprintf(str, sizeof(str), "%016" PRIx64 "%016" PRIx64, hash.high64, hash.low64); return Rf_mkString(str); } SEXP clic_xxhash64_raw(SEXP r) { XXH64_hash_t hash = XXH3_64bits_withSeed( RAW(r), Rf_length(r), 0 ); char str[16 + 1]; snprintf(str, sizeof(str), "%016" PRIx64, hash); return Rf_mkString(str); } #include "winfiles.h" #include #include SEXP clic_xxhash_file(SEXP paths) { R_xlen_t i, len = XLENGTH(paths); size_t const bufferSize = 1 * 1024 * 1024; char str[32 + 1]; char *buffer = R_alloc(1, bufferSize); SEXP result = PROTECT(Rf_allocVector(STRSXP, len)); XXH128_hash_t hash; XXH3_state_t* const state = XXH3_createState(); if (state == NULL) { R_THROW_ERROR("Failed to init xx hash state"); } for (i = 0; i < len; i++) { const char *cpath = CHAR(STRING_ELT(paths, i)); int fd = open_file(cpath, O_RDONLY); if (fd == -1) { R_THROW_SYSTEM_ERROR("Cannot open file `%s`", cpath); } if (XXH3_128bits_reset(state) == XXH_ERROR) { close(fd); R_THROW_ERROR("Could not initialize xxhash"); } ssize_t got = read(fd, buffer, bufferSize); if (got == -1) { close(fd); R_THROW_SYSTEM_ERROR("Cannot read from file `%s`", cpath); } while (got > 0) { if (XXH3_128bits_update(state, buffer, got) == XXH_ERROR) { close(fd); R_THROW_ERROR("Failed to calcu;late xxhash"); } got = read(fd, buffer, bufferSize); if (got == -1) { close(fd); R_THROW_SYSTEM_ERROR("Cannot read from file `%s`", cpath); } } close(fd); hash = XXH3_128bits_digest(state); snprintf(str, sizeof(str), "%016" PRIx64 "%016" PRIx64, hash.high64, hash.low64); SET_STRING_ELT(result, i, Rf_mkCharLen(str, 32)); } UNPROTECT(1); return result; } SEXP clic_xxhash64_file(SEXP paths) { R_xlen_t i, len = XLENGTH(paths); size_t const bufferSize = 1 * 1024 * 1024; char str[16 + 1]; char *buffer = R_alloc(1, bufferSize); SEXP result = PROTECT(Rf_allocVector(STRSXP, len)); XXH64_hash_t hash; XXH3_state_t* const state = XXH3_createState(); if (state == NULL) { R_THROW_ERROR("Failed to init xx hash state"); } for (i = 0; i < len; i++) { const char *cpath = CHAR(STRING_ELT(paths, i)); int fd = open_file(cpath, O_RDONLY); if (fd == -1) { R_THROW_SYSTEM_ERROR("Cannot open file `%s`", cpath); } if (XXH3_64bits_reset(state) == XXH_ERROR) { close(fd); R_THROW_ERROR("Could not initialize xxhash"); } ssize_t got = read(fd, buffer, bufferSize); if (got == -1) { close(fd); R_THROW_SYSTEM_ERROR("Cannot read from file `%s`", cpath); } while (got > 0) { if (XXH3_64bits_update(state, buffer, got) == XXH_ERROR) { close(fd); R_THROW_ERROR("Failed to calcu;late xxhash"); } got = read(fd, buffer, bufferSize); if (got == -1) { close(fd); R_THROW_SYSTEM_ERROR("Cannot read from file `%s`", cpath); } } close(fd); hash = XXH3_64bits_digest(state); snprintf(str, sizeof(str), "%016" PRIx64, hash); SET_STRING_ELT(result, i, Rf_mkCharLen(str, 16)); } UNPROTECT(1); return result; } cli/src/Makevars0000644000176200001440000000010414704677167013322 0ustar liggesusersPKG_CFLAGS = $(C_VISIBILITY) -I../inst/include PKG_LIBS = -lpthread cli/src/xxhash.c0000644000176200001440000000352614752735214013277 0ustar liggesusers/* * xxHash - Extremely Fast Hash algorithm * Copyright (C) 2012-2021 Yann Collet * * BSD 2-Clause License (https://www.opensource.org/licenses/bsd-license.php) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * You can contact the author at: * - xxHash homepage: https://www.xxhash.com * - xxHash source repository: https://github.com/Cyan4973/xxHash */ /* * xxhash.c instantiates functions defined in xxhash.h */ #define XXH_STATIC_LINKING_ONLY /* access advanced declarations */ #define XXH_IMPLEMENTATION /* access definitions */ #define XXH_INLINE_ALL #include "xxhash.h" cli/src/vtparse_table.c0000644000176200001440000060124014557444176014633 0ustar liggesusers #include "vtparse_table.h" char *ACTION_NAMES[] = { "", "CLEAR", "COLLECT", "CSI_DISPATCH", "ESC_DISPATCH", "EXECUTE", "HOOK", "IGNORE", "OSC_END", "OSC_PUT", "OSC_START", "PARAM", "PRINT", "PUT", "UNHOOK", "ERROR", }; char *STATE_NAMES[] = { "", "CSI_ENTRY", "CSI_IGNORE", "CSI_INTERMEDIATE", "CSI_PARAM", "DCS_ENTRY", "DCS_IGNORE", "DCS_INTERMEDIATE", "DCS_PARAM", "DCS_PASSTHROUGH", "ESCAPE", "ESCAPE_INTERMEDIATE", "GROUND", "OSC_STRING", "SOS_PM_APC_STRING", }; state_change_t STATE_TABLE[14][256] = { { /* VTPARSE_STATE_CSI_ENTRY = 0 */ /*0 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*1 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*2 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*3 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*4 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*5 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*6 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*7 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*8 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*9 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*10 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*11 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*12 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*13 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*14 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*15 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*16 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*17 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*18 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*19 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*20 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*21 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*22 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*23 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*24 */ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*25 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*26 */ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*27 */ 0 | (VTPARSE_STATE_ESCAPE << 4), /*28 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*29 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*30 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*31 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*32 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_CSI_INTERMEDIATE << 4), /*33 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_CSI_INTERMEDIATE << 4), /*34 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_CSI_INTERMEDIATE << 4), /*35 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_CSI_INTERMEDIATE << 4), /*36 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_CSI_INTERMEDIATE << 4), /*37 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_CSI_INTERMEDIATE << 4), /*38 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_CSI_INTERMEDIATE << 4), /*39 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_CSI_INTERMEDIATE << 4), /*40 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_CSI_INTERMEDIATE << 4), /*41 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_CSI_INTERMEDIATE << 4), /*42 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_CSI_INTERMEDIATE << 4), /*43 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_CSI_INTERMEDIATE << 4), /*44 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_CSI_INTERMEDIATE << 4), /*45 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_CSI_INTERMEDIATE << 4), /*46 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_CSI_INTERMEDIATE << 4), /*47 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_CSI_INTERMEDIATE << 4), /*48 */ VTPARSE_ACTION_PARAM | (VTPARSE_STATE_CSI_PARAM << 4), /*49 */ VTPARSE_ACTION_PARAM | (VTPARSE_STATE_CSI_PARAM << 4), /*50 */ VTPARSE_ACTION_PARAM | (VTPARSE_STATE_CSI_PARAM << 4), /*51 */ VTPARSE_ACTION_PARAM | (VTPARSE_STATE_CSI_PARAM << 4), /*52 */ VTPARSE_ACTION_PARAM | (VTPARSE_STATE_CSI_PARAM << 4), /*53 */ VTPARSE_ACTION_PARAM | (VTPARSE_STATE_CSI_PARAM << 4), /*54 */ VTPARSE_ACTION_PARAM | (VTPARSE_STATE_CSI_PARAM << 4), /*55 */ VTPARSE_ACTION_PARAM | (VTPARSE_STATE_CSI_PARAM << 4), /*56 */ VTPARSE_ACTION_PARAM | (VTPARSE_STATE_CSI_PARAM << 4), /*57 */ VTPARSE_ACTION_PARAM | (VTPARSE_STATE_CSI_PARAM << 4), /*58 */ 0 | (VTPARSE_STATE_CSI_IGNORE << 4), /*59 */ VTPARSE_ACTION_PARAM | (VTPARSE_STATE_CSI_PARAM << 4), /*60 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_CSI_PARAM << 4), /*61 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_CSI_PARAM << 4), /*62 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_CSI_PARAM << 4), /*63 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_CSI_PARAM << 4), /*64 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*65 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*66 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*67 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*68 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*69 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*70 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*71 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*72 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*73 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*74 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*75 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*76 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*77 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*78 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*79 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*80 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*81 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*82 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*83 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*84 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*85 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*86 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*87 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*88 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*89 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*90 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*91 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*92 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*93 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*94 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*95 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*96 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*97 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*98 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*99 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*100*/ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*101*/ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*102*/ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*103*/ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*104*/ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*105*/ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*106*/ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*107*/ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*108*/ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*109*/ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*110*/ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*111*/ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*112*/ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*113*/ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*114*/ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*115*/ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*116*/ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*117*/ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*118*/ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*119*/ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*120*/ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*121*/ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*122*/ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*123*/ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*124*/ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*125*/ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*126*/ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*127*/ VTPARSE_ACTION_IGNORE | (0 << 4), /*128*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*129*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*130*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*131*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*132*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*133*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*134*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*135*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*136*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*137*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*138*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*139*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*140*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*141*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*142*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*143*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*144*/ 0 | (VTPARSE_STATE_DCS_ENTRY << 4), /*145*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*146*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*147*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*148*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*149*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*150*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*151*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*152*/ 0 | (VTPARSE_STATE_SOS_PM_APC_STRING << 4), /*153*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*154*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*155*/ 0 | (VTPARSE_STATE_CSI_ENTRY << 4), /*156*/ 0 | (VTPARSE_STATE_GROUND << 4), /*157*/ 0 | (VTPARSE_STATE_OSC_STRING << 4), /*158*/ 0 | (VTPARSE_STATE_SOS_PM_APC_STRING << 4), /*159*/ 0 | (VTPARSE_STATE_SOS_PM_APC_STRING << 4), }, { /* VTPARSE_STATE_CSI_IGNORE = 1 */ /*0 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*1 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*2 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*3 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*4 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*5 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*6 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*7 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*8 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*9 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*10 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*11 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*12 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*13 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*14 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*15 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*16 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*17 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*18 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*19 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*20 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*21 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*22 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*23 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*24 */ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*25 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*26 */ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*27 */ 0 | (VTPARSE_STATE_ESCAPE << 4), /*28 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*29 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*30 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*31 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*32 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*33 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*34 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*35 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*36 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*37 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*38 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*39 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*40 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*41 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*42 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*43 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*44 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*45 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*46 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*47 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*48 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*49 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*50 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*51 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*52 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*53 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*54 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*55 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*56 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*57 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*58 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*59 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*60 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*61 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*62 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*63 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*64 */ 0 | (VTPARSE_STATE_GROUND << 4), /*65 */ 0 | (VTPARSE_STATE_GROUND << 4), /*66 */ 0 | (VTPARSE_STATE_GROUND << 4), /*67 */ 0 | (VTPARSE_STATE_GROUND << 4), /*68 */ 0 | (VTPARSE_STATE_GROUND << 4), /*69 */ 0 | (VTPARSE_STATE_GROUND << 4), /*70 */ 0 | (VTPARSE_STATE_GROUND << 4), /*71 */ 0 | (VTPARSE_STATE_GROUND << 4), /*72 */ 0 | (VTPARSE_STATE_GROUND << 4), /*73 */ 0 | (VTPARSE_STATE_GROUND << 4), /*74 */ 0 | (VTPARSE_STATE_GROUND << 4), /*75 */ 0 | (VTPARSE_STATE_GROUND << 4), /*76 */ 0 | (VTPARSE_STATE_GROUND << 4), /*77 */ 0 | (VTPARSE_STATE_GROUND << 4), /*78 */ 0 | (VTPARSE_STATE_GROUND << 4), /*79 */ 0 | (VTPARSE_STATE_GROUND << 4), /*80 */ 0 | (VTPARSE_STATE_GROUND << 4), /*81 */ 0 | (VTPARSE_STATE_GROUND << 4), /*82 */ 0 | (VTPARSE_STATE_GROUND << 4), /*83 */ 0 | (VTPARSE_STATE_GROUND << 4), /*84 */ 0 | (VTPARSE_STATE_GROUND << 4), /*85 */ 0 | (VTPARSE_STATE_GROUND << 4), /*86 */ 0 | (VTPARSE_STATE_GROUND << 4), /*87 */ 0 | (VTPARSE_STATE_GROUND << 4), /*88 */ 0 | (VTPARSE_STATE_GROUND << 4), /*89 */ 0 | (VTPARSE_STATE_GROUND << 4), /*90 */ 0 | (VTPARSE_STATE_GROUND << 4), /*91 */ 0 | (VTPARSE_STATE_GROUND << 4), /*92 */ 0 | (VTPARSE_STATE_GROUND << 4), /*93 */ 0 | (VTPARSE_STATE_GROUND << 4), /*94 */ 0 | (VTPARSE_STATE_GROUND << 4), /*95 */ 0 | (VTPARSE_STATE_GROUND << 4), /*96 */ 0 | (VTPARSE_STATE_GROUND << 4), /*97 */ 0 | (VTPARSE_STATE_GROUND << 4), /*98 */ 0 | (VTPARSE_STATE_GROUND << 4), /*99 */ 0 | (VTPARSE_STATE_GROUND << 4), /*100*/ 0 | (VTPARSE_STATE_GROUND << 4), /*101*/ 0 | (VTPARSE_STATE_GROUND << 4), /*102*/ 0 | (VTPARSE_STATE_GROUND << 4), /*103*/ 0 | (VTPARSE_STATE_GROUND << 4), /*104*/ 0 | (VTPARSE_STATE_GROUND << 4), /*105*/ 0 | (VTPARSE_STATE_GROUND << 4), /*106*/ 0 | (VTPARSE_STATE_GROUND << 4), /*107*/ 0 | (VTPARSE_STATE_GROUND << 4), /*108*/ 0 | (VTPARSE_STATE_GROUND << 4), /*109*/ 0 | (VTPARSE_STATE_GROUND << 4), /*110*/ 0 | (VTPARSE_STATE_GROUND << 4), /*111*/ 0 | (VTPARSE_STATE_GROUND << 4), /*112*/ 0 | (VTPARSE_STATE_GROUND << 4), /*113*/ 0 | (VTPARSE_STATE_GROUND << 4), /*114*/ 0 | (VTPARSE_STATE_GROUND << 4), /*115*/ 0 | (VTPARSE_STATE_GROUND << 4), /*116*/ 0 | (VTPARSE_STATE_GROUND << 4), /*117*/ 0 | (VTPARSE_STATE_GROUND << 4), /*118*/ 0 | (VTPARSE_STATE_GROUND << 4), /*119*/ 0 | (VTPARSE_STATE_GROUND << 4), /*120*/ 0 | (VTPARSE_STATE_GROUND << 4), /*121*/ 0 | (VTPARSE_STATE_GROUND << 4), /*122*/ 0 | (VTPARSE_STATE_GROUND << 4), /*123*/ 0 | (VTPARSE_STATE_GROUND << 4), /*124*/ 0 | (VTPARSE_STATE_GROUND << 4), /*125*/ 0 | (VTPARSE_STATE_GROUND << 4), /*126*/ 0 | (VTPARSE_STATE_GROUND << 4), /*127*/ VTPARSE_ACTION_IGNORE | (0 << 4), /*128*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*129*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*130*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*131*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*132*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*133*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*134*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*135*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*136*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*137*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*138*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*139*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*140*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*141*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*142*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*143*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*144*/ 0 | (VTPARSE_STATE_DCS_ENTRY << 4), /*145*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*146*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*147*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*148*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*149*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*150*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*151*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*152*/ 0 | (VTPARSE_STATE_SOS_PM_APC_STRING << 4), /*153*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*154*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*155*/ 0 | (VTPARSE_STATE_CSI_ENTRY << 4), /*156*/ 0 | (VTPARSE_STATE_GROUND << 4), /*157*/ 0 | (VTPARSE_STATE_OSC_STRING << 4), /*158*/ 0 | (VTPARSE_STATE_SOS_PM_APC_STRING << 4), /*159*/ 0 | (VTPARSE_STATE_SOS_PM_APC_STRING << 4), }, { /* VTPARSE_STATE_CSI_INTERMEDIATE = 2 */ /*0 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*1 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*2 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*3 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*4 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*5 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*6 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*7 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*8 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*9 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*10 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*11 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*12 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*13 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*14 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*15 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*16 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*17 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*18 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*19 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*20 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*21 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*22 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*23 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*24 */ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*25 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*26 */ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*27 */ 0 | (VTPARSE_STATE_ESCAPE << 4), /*28 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*29 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*30 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*31 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*32 */ VTPARSE_ACTION_COLLECT | (0 << 4), /*33 */ VTPARSE_ACTION_COLLECT | (0 << 4), /*34 */ VTPARSE_ACTION_COLLECT | (0 << 4), /*35 */ VTPARSE_ACTION_COLLECT | (0 << 4), /*36 */ VTPARSE_ACTION_COLLECT | (0 << 4), /*37 */ VTPARSE_ACTION_COLLECT | (0 << 4), /*38 */ VTPARSE_ACTION_COLLECT | (0 << 4), /*39 */ VTPARSE_ACTION_COLLECT | (0 << 4), /*40 */ VTPARSE_ACTION_COLLECT | (0 << 4), /*41 */ VTPARSE_ACTION_COLLECT | (0 << 4), /*42 */ VTPARSE_ACTION_COLLECT | (0 << 4), /*43 */ VTPARSE_ACTION_COLLECT | (0 << 4), /*44 */ VTPARSE_ACTION_COLLECT | (0 << 4), /*45 */ VTPARSE_ACTION_COLLECT | (0 << 4), /*46 */ VTPARSE_ACTION_COLLECT | (0 << 4), /*47 */ VTPARSE_ACTION_COLLECT | (0 << 4), /*48 */ 0 | (VTPARSE_STATE_CSI_IGNORE << 4), /*49 */ 0 | (VTPARSE_STATE_CSI_IGNORE << 4), /*50 */ 0 | (VTPARSE_STATE_CSI_IGNORE << 4), /*51 */ 0 | (VTPARSE_STATE_CSI_IGNORE << 4), /*52 */ 0 | (VTPARSE_STATE_CSI_IGNORE << 4), /*53 */ 0 | (VTPARSE_STATE_CSI_IGNORE << 4), /*54 */ 0 | (VTPARSE_STATE_CSI_IGNORE << 4), /*55 */ 0 | (VTPARSE_STATE_CSI_IGNORE << 4), /*56 */ 0 | (VTPARSE_STATE_CSI_IGNORE << 4), /*57 */ 0 | (VTPARSE_STATE_CSI_IGNORE << 4), /*58 */ 0 | (VTPARSE_STATE_CSI_IGNORE << 4), /*59 */ 0 | (VTPARSE_STATE_CSI_IGNORE << 4), /*60 */ 0 | (VTPARSE_STATE_CSI_IGNORE << 4), /*61 */ 0 | (VTPARSE_STATE_CSI_IGNORE << 4), /*62 */ 0 | (VTPARSE_STATE_CSI_IGNORE << 4), /*63 */ 0 | (VTPARSE_STATE_CSI_IGNORE << 4), /*64 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*65 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*66 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*67 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*68 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*69 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*70 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*71 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*72 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*73 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*74 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*75 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*76 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*77 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*78 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*79 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*80 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*81 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*82 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*83 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*84 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*85 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*86 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*87 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*88 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*89 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*90 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*91 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*92 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*93 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*94 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*95 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*96 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*97 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*98 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*99 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*100*/ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*101*/ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*102*/ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*103*/ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*104*/ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*105*/ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*106*/ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*107*/ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*108*/ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*109*/ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*110*/ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*111*/ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*112*/ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*113*/ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*114*/ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*115*/ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*116*/ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*117*/ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*118*/ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*119*/ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*120*/ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*121*/ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*122*/ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*123*/ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*124*/ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*125*/ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*126*/ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*127*/ VTPARSE_ACTION_IGNORE | (0 << 4), /*128*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*129*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*130*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*131*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*132*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*133*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*134*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*135*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*136*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*137*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*138*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*139*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*140*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*141*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*142*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*143*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*144*/ 0 | (VTPARSE_STATE_DCS_ENTRY << 4), /*145*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*146*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*147*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*148*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*149*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*150*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*151*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*152*/ 0 | (VTPARSE_STATE_SOS_PM_APC_STRING << 4), /*153*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*154*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*155*/ 0 | (VTPARSE_STATE_CSI_ENTRY << 4), /*156*/ 0 | (VTPARSE_STATE_GROUND << 4), /*157*/ 0 | (VTPARSE_STATE_OSC_STRING << 4), /*158*/ 0 | (VTPARSE_STATE_SOS_PM_APC_STRING << 4), /*159*/ 0 | (VTPARSE_STATE_SOS_PM_APC_STRING << 4), }, { /* VTPARSE_STATE_CSI_PARAM = 3 */ /*0 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*1 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*2 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*3 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*4 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*5 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*6 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*7 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*8 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*9 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*10 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*11 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*12 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*13 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*14 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*15 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*16 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*17 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*18 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*19 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*20 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*21 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*22 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*23 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*24 */ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*25 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*26 */ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*27 */ 0 | (VTPARSE_STATE_ESCAPE << 4), /*28 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*29 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*30 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*31 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*32 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_CSI_INTERMEDIATE << 4), /*33 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_CSI_INTERMEDIATE << 4), /*34 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_CSI_INTERMEDIATE << 4), /*35 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_CSI_INTERMEDIATE << 4), /*36 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_CSI_INTERMEDIATE << 4), /*37 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_CSI_INTERMEDIATE << 4), /*38 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_CSI_INTERMEDIATE << 4), /*39 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_CSI_INTERMEDIATE << 4), /*40 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_CSI_INTERMEDIATE << 4), /*41 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_CSI_INTERMEDIATE << 4), /*42 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_CSI_INTERMEDIATE << 4), /*43 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_CSI_INTERMEDIATE << 4), /*44 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_CSI_INTERMEDIATE << 4), /*45 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_CSI_INTERMEDIATE << 4), /*46 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_CSI_INTERMEDIATE << 4), /*47 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_CSI_INTERMEDIATE << 4), /*48 */ VTPARSE_ACTION_PARAM | (0 << 4), /*49 */ VTPARSE_ACTION_PARAM | (0 << 4), /*50 */ VTPARSE_ACTION_PARAM | (0 << 4), /*51 */ VTPARSE_ACTION_PARAM | (0 << 4), /*52 */ VTPARSE_ACTION_PARAM | (0 << 4), /*53 */ VTPARSE_ACTION_PARAM | (0 << 4), /*54 */ VTPARSE_ACTION_PARAM | (0 << 4), /*55 */ VTPARSE_ACTION_PARAM | (0 << 4), /*56 */ VTPARSE_ACTION_PARAM | (0 << 4), /*57 */ VTPARSE_ACTION_PARAM | (0 << 4), /*58 */ 0 | (VTPARSE_STATE_CSI_IGNORE << 4), /*59 */ VTPARSE_ACTION_PARAM | (0 << 4), /*60 */ 0 | (VTPARSE_STATE_CSI_IGNORE << 4), /*61 */ 0 | (VTPARSE_STATE_CSI_IGNORE << 4), /*62 */ 0 | (VTPARSE_STATE_CSI_IGNORE << 4), /*63 */ 0 | (VTPARSE_STATE_CSI_IGNORE << 4), /*64 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*65 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*66 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*67 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*68 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*69 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*70 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*71 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*72 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*73 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*74 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*75 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*76 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*77 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*78 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*79 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*80 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*81 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*82 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*83 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*84 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*85 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*86 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*87 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*88 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*89 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*90 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*91 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*92 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*93 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*94 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*95 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*96 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*97 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*98 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*99 */ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*100*/ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*101*/ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*102*/ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*103*/ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*104*/ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*105*/ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*106*/ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*107*/ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*108*/ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*109*/ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*110*/ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*111*/ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*112*/ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*113*/ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*114*/ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*115*/ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*116*/ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*117*/ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*118*/ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*119*/ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*120*/ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*121*/ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*122*/ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*123*/ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*124*/ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*125*/ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*126*/ VTPARSE_ACTION_CSI_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*127*/ VTPARSE_ACTION_IGNORE | (0 << 4), /*128*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*129*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*130*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*131*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*132*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*133*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*134*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*135*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*136*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*137*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*138*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*139*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*140*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*141*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*142*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*143*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*144*/ 0 | (VTPARSE_STATE_DCS_ENTRY << 4), /*145*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*146*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*147*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*148*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*149*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*150*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*151*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*152*/ 0 | (VTPARSE_STATE_SOS_PM_APC_STRING << 4), /*153*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*154*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*155*/ 0 | (VTPARSE_STATE_CSI_ENTRY << 4), /*156*/ 0 | (VTPARSE_STATE_GROUND << 4), /*157*/ 0 | (VTPARSE_STATE_OSC_STRING << 4), /*158*/ 0 | (VTPARSE_STATE_SOS_PM_APC_STRING << 4), /*159*/ 0 | (VTPARSE_STATE_SOS_PM_APC_STRING << 4), }, { /* VTPARSE_STATE_DCS_ENTRY = 4 */ /*0 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*1 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*2 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*3 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*4 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*5 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*6 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*7 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*8 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*9 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*10 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*11 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*12 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*13 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*14 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*15 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*16 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*17 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*18 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*19 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*20 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*21 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*22 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*23 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*24 */ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*25 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*26 */ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*27 */ 0 | (VTPARSE_STATE_ESCAPE << 4), /*28 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*29 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*30 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*31 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*32 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_DCS_INTERMEDIATE << 4), /*33 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_DCS_INTERMEDIATE << 4), /*34 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_DCS_INTERMEDIATE << 4), /*35 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_DCS_INTERMEDIATE << 4), /*36 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_DCS_INTERMEDIATE << 4), /*37 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_DCS_INTERMEDIATE << 4), /*38 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_DCS_INTERMEDIATE << 4), /*39 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_DCS_INTERMEDIATE << 4), /*40 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_DCS_INTERMEDIATE << 4), /*41 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_DCS_INTERMEDIATE << 4), /*42 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_DCS_INTERMEDIATE << 4), /*43 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_DCS_INTERMEDIATE << 4), /*44 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_DCS_INTERMEDIATE << 4), /*45 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_DCS_INTERMEDIATE << 4), /*46 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_DCS_INTERMEDIATE << 4), /*47 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_DCS_INTERMEDIATE << 4), /*48 */ VTPARSE_ACTION_PARAM | (VTPARSE_STATE_DCS_PARAM << 4), /*49 */ VTPARSE_ACTION_PARAM | (VTPARSE_STATE_DCS_PARAM << 4), /*50 */ VTPARSE_ACTION_PARAM | (VTPARSE_STATE_DCS_PARAM << 4), /*51 */ VTPARSE_ACTION_PARAM | (VTPARSE_STATE_DCS_PARAM << 4), /*52 */ VTPARSE_ACTION_PARAM | (VTPARSE_STATE_DCS_PARAM << 4), /*53 */ VTPARSE_ACTION_PARAM | (VTPARSE_STATE_DCS_PARAM << 4), /*54 */ VTPARSE_ACTION_PARAM | (VTPARSE_STATE_DCS_PARAM << 4), /*55 */ VTPARSE_ACTION_PARAM | (VTPARSE_STATE_DCS_PARAM << 4), /*56 */ VTPARSE_ACTION_PARAM | (VTPARSE_STATE_DCS_PARAM << 4), /*57 */ VTPARSE_ACTION_PARAM | (VTPARSE_STATE_DCS_PARAM << 4), /*58 */ 0 | (VTPARSE_STATE_DCS_IGNORE << 4), /*59 */ VTPARSE_ACTION_PARAM | (VTPARSE_STATE_DCS_PARAM << 4), /*60 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_DCS_PARAM << 4), /*61 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_DCS_PARAM << 4), /*62 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_DCS_PARAM << 4), /*63 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_DCS_PARAM << 4), /*64 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*65 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*66 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*67 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*68 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*69 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*70 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*71 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*72 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*73 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*74 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*75 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*76 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*77 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*78 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*79 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*80 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*81 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*82 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*83 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*84 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*85 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*86 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*87 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*88 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*89 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*90 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*91 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*92 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*93 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*94 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*95 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*96 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*97 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*98 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*99 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*100*/ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*101*/ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*102*/ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*103*/ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*104*/ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*105*/ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*106*/ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*107*/ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*108*/ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*109*/ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*110*/ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*111*/ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*112*/ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*113*/ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*114*/ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*115*/ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*116*/ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*117*/ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*118*/ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*119*/ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*120*/ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*121*/ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*122*/ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*123*/ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*124*/ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*125*/ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*126*/ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*127*/ VTPARSE_ACTION_IGNORE | (0 << 4), /*128*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*129*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*130*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*131*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*132*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*133*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*134*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*135*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*136*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*137*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*138*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*139*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*140*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*141*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*142*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*143*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*144*/ 0 | (VTPARSE_STATE_DCS_ENTRY << 4), /*145*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*146*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*147*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*148*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*149*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*150*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*151*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*152*/ 0 | (VTPARSE_STATE_SOS_PM_APC_STRING << 4), /*153*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*154*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*155*/ 0 | (VTPARSE_STATE_CSI_ENTRY << 4), /*156*/ 0 | (VTPARSE_STATE_GROUND << 4), /*157*/ 0 | (VTPARSE_STATE_OSC_STRING << 4), /*158*/ 0 | (VTPARSE_STATE_SOS_PM_APC_STRING << 4), /*159*/ 0 | (VTPARSE_STATE_SOS_PM_APC_STRING << 4), }, { /* VTPARSE_STATE_DCS_IGNORE = 5 */ /*0 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*1 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*2 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*3 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*4 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*5 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*6 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*7 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*8 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*9 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*10 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*11 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*12 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*13 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*14 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*15 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*16 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*17 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*18 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*19 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*20 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*21 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*22 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*23 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*24 */ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*25 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*26 */ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*27 */ 0 | (VTPARSE_STATE_ESCAPE << 4), /*28 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*29 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*30 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*31 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*32 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*33 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*34 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*35 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*36 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*37 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*38 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*39 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*40 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*41 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*42 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*43 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*44 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*45 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*46 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*47 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*48 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*49 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*50 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*51 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*52 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*53 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*54 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*55 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*56 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*57 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*58 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*59 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*60 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*61 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*62 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*63 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*64 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*65 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*66 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*67 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*68 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*69 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*70 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*71 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*72 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*73 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*74 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*75 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*76 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*77 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*78 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*79 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*80 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*81 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*82 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*83 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*84 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*85 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*86 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*87 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*88 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*89 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*90 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*91 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*92 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*93 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*94 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*95 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*96 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*97 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*98 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*99 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*100*/ VTPARSE_ACTION_IGNORE | (0 << 4), /*101*/ VTPARSE_ACTION_IGNORE | (0 << 4), /*102*/ VTPARSE_ACTION_IGNORE | (0 << 4), /*103*/ VTPARSE_ACTION_IGNORE | (0 << 4), /*104*/ VTPARSE_ACTION_IGNORE | (0 << 4), /*105*/ VTPARSE_ACTION_IGNORE | (0 << 4), /*106*/ VTPARSE_ACTION_IGNORE | (0 << 4), /*107*/ VTPARSE_ACTION_IGNORE | (0 << 4), /*108*/ VTPARSE_ACTION_IGNORE | (0 << 4), /*109*/ VTPARSE_ACTION_IGNORE | (0 << 4), /*110*/ VTPARSE_ACTION_IGNORE | (0 << 4), /*111*/ VTPARSE_ACTION_IGNORE | (0 << 4), /*112*/ VTPARSE_ACTION_IGNORE | (0 << 4), /*113*/ VTPARSE_ACTION_IGNORE | (0 << 4), /*114*/ VTPARSE_ACTION_IGNORE | (0 << 4), /*115*/ VTPARSE_ACTION_IGNORE | (0 << 4), /*116*/ VTPARSE_ACTION_IGNORE | (0 << 4), /*117*/ VTPARSE_ACTION_IGNORE | (0 << 4), /*118*/ VTPARSE_ACTION_IGNORE | (0 << 4), /*119*/ VTPARSE_ACTION_IGNORE | (0 << 4), /*120*/ VTPARSE_ACTION_IGNORE | (0 << 4), /*121*/ VTPARSE_ACTION_IGNORE | (0 << 4), /*122*/ VTPARSE_ACTION_IGNORE | (0 << 4), /*123*/ VTPARSE_ACTION_IGNORE | (0 << 4), /*124*/ VTPARSE_ACTION_IGNORE | (0 << 4), /*125*/ VTPARSE_ACTION_IGNORE | (0 << 4), /*126*/ VTPARSE_ACTION_IGNORE | (0 << 4), /*127*/ VTPARSE_ACTION_IGNORE | (0 << 4), /*128*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*129*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*130*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*131*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*132*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*133*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*134*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*135*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*136*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*137*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*138*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*139*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*140*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*141*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*142*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*143*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*144*/ 0 | (VTPARSE_STATE_DCS_ENTRY << 4), /*145*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*146*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*147*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*148*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*149*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*150*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*151*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*152*/ 0 | (VTPARSE_STATE_SOS_PM_APC_STRING << 4), /*153*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*154*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*155*/ 0 | (VTPARSE_STATE_CSI_ENTRY << 4), /*156*/ 0 | (VTPARSE_STATE_GROUND << 4), /*157*/ 0 | (VTPARSE_STATE_OSC_STRING << 4), /*158*/ 0 | (VTPARSE_STATE_SOS_PM_APC_STRING << 4), /*159*/ 0 | (VTPARSE_STATE_SOS_PM_APC_STRING << 4), }, { /* VTPARSE_STATE_DCS_INTERMEDIATE = 6 */ /*0 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*1 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*2 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*3 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*4 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*5 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*6 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*7 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*8 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*9 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*10 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*11 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*12 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*13 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*14 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*15 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*16 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*17 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*18 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*19 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*20 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*21 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*22 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*23 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*24 */ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*25 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*26 */ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*27 */ 0 | (VTPARSE_STATE_ESCAPE << 4), /*28 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*29 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*30 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*31 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*32 */ VTPARSE_ACTION_COLLECT | (0 << 4), /*33 */ VTPARSE_ACTION_COLLECT | (0 << 4), /*34 */ VTPARSE_ACTION_COLLECT | (0 << 4), /*35 */ VTPARSE_ACTION_COLLECT | (0 << 4), /*36 */ VTPARSE_ACTION_COLLECT | (0 << 4), /*37 */ VTPARSE_ACTION_COLLECT | (0 << 4), /*38 */ VTPARSE_ACTION_COLLECT | (0 << 4), /*39 */ VTPARSE_ACTION_COLLECT | (0 << 4), /*40 */ VTPARSE_ACTION_COLLECT | (0 << 4), /*41 */ VTPARSE_ACTION_COLLECT | (0 << 4), /*42 */ VTPARSE_ACTION_COLLECT | (0 << 4), /*43 */ VTPARSE_ACTION_COLLECT | (0 << 4), /*44 */ VTPARSE_ACTION_COLLECT | (0 << 4), /*45 */ VTPARSE_ACTION_COLLECT | (0 << 4), /*46 */ VTPARSE_ACTION_COLLECT | (0 << 4), /*47 */ VTPARSE_ACTION_COLLECT | (0 << 4), /*48 */ 0 | (VTPARSE_STATE_DCS_IGNORE << 4), /*49 */ 0 | (VTPARSE_STATE_DCS_IGNORE << 4), /*50 */ 0 | (VTPARSE_STATE_DCS_IGNORE << 4), /*51 */ 0 | (VTPARSE_STATE_DCS_IGNORE << 4), /*52 */ 0 | (VTPARSE_STATE_DCS_IGNORE << 4), /*53 */ 0 | (VTPARSE_STATE_DCS_IGNORE << 4), /*54 */ 0 | (VTPARSE_STATE_DCS_IGNORE << 4), /*55 */ 0 | (VTPARSE_STATE_DCS_IGNORE << 4), /*56 */ 0 | (VTPARSE_STATE_DCS_IGNORE << 4), /*57 */ 0 | (VTPARSE_STATE_DCS_IGNORE << 4), /*58 */ 0 | (VTPARSE_STATE_DCS_IGNORE << 4), /*59 */ 0 | (VTPARSE_STATE_DCS_IGNORE << 4), /*60 */ 0 | (VTPARSE_STATE_DCS_IGNORE << 4), /*61 */ 0 | (VTPARSE_STATE_DCS_IGNORE << 4), /*62 */ 0 | (VTPARSE_STATE_DCS_IGNORE << 4), /*63 */ 0 | (VTPARSE_STATE_DCS_IGNORE << 4), /*64 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*65 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*66 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*67 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*68 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*69 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*70 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*71 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*72 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*73 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*74 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*75 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*76 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*77 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*78 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*79 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*80 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*81 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*82 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*83 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*84 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*85 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*86 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*87 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*88 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*89 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*90 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*91 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*92 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*93 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*94 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*95 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*96 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*97 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*98 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*99 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*100*/ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*101*/ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*102*/ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*103*/ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*104*/ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*105*/ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*106*/ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*107*/ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*108*/ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*109*/ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*110*/ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*111*/ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*112*/ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*113*/ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*114*/ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*115*/ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*116*/ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*117*/ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*118*/ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*119*/ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*120*/ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*121*/ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*122*/ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*123*/ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*124*/ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*125*/ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*126*/ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*127*/ VTPARSE_ACTION_IGNORE | (0 << 4), /*128*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*129*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*130*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*131*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*132*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*133*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*134*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*135*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*136*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*137*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*138*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*139*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*140*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*141*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*142*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*143*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*144*/ 0 | (VTPARSE_STATE_DCS_ENTRY << 4), /*145*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*146*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*147*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*148*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*149*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*150*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*151*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*152*/ 0 | (VTPARSE_STATE_SOS_PM_APC_STRING << 4), /*153*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*154*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*155*/ 0 | (VTPARSE_STATE_CSI_ENTRY << 4), /*156*/ 0 | (VTPARSE_STATE_GROUND << 4), /*157*/ 0 | (VTPARSE_STATE_OSC_STRING << 4), /*158*/ 0 | (VTPARSE_STATE_SOS_PM_APC_STRING << 4), /*159*/ 0 | (VTPARSE_STATE_SOS_PM_APC_STRING << 4), }, { /* VTPARSE_STATE_DCS_PARAM = 7 */ /*0 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*1 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*2 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*3 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*4 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*5 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*6 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*7 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*8 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*9 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*10 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*11 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*12 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*13 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*14 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*15 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*16 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*17 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*18 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*19 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*20 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*21 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*22 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*23 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*24 */ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*25 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*26 */ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*27 */ 0 | (VTPARSE_STATE_ESCAPE << 4), /*28 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*29 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*30 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*31 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*32 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_DCS_INTERMEDIATE << 4), /*33 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_DCS_INTERMEDIATE << 4), /*34 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_DCS_INTERMEDIATE << 4), /*35 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_DCS_INTERMEDIATE << 4), /*36 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_DCS_INTERMEDIATE << 4), /*37 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_DCS_INTERMEDIATE << 4), /*38 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_DCS_INTERMEDIATE << 4), /*39 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_DCS_INTERMEDIATE << 4), /*40 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_DCS_INTERMEDIATE << 4), /*41 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_DCS_INTERMEDIATE << 4), /*42 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_DCS_INTERMEDIATE << 4), /*43 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_DCS_INTERMEDIATE << 4), /*44 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_DCS_INTERMEDIATE << 4), /*45 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_DCS_INTERMEDIATE << 4), /*46 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_DCS_INTERMEDIATE << 4), /*47 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_DCS_INTERMEDIATE << 4), /*48 */ VTPARSE_ACTION_PARAM | (0 << 4), /*49 */ VTPARSE_ACTION_PARAM | (0 << 4), /*50 */ VTPARSE_ACTION_PARAM | (0 << 4), /*51 */ VTPARSE_ACTION_PARAM | (0 << 4), /*52 */ VTPARSE_ACTION_PARAM | (0 << 4), /*53 */ VTPARSE_ACTION_PARAM | (0 << 4), /*54 */ VTPARSE_ACTION_PARAM | (0 << 4), /*55 */ VTPARSE_ACTION_PARAM | (0 << 4), /*56 */ VTPARSE_ACTION_PARAM | (0 << 4), /*57 */ VTPARSE_ACTION_PARAM | (0 << 4), /*58 */ 0 | (VTPARSE_STATE_DCS_IGNORE << 4), /*59 */ VTPARSE_ACTION_PARAM | (0 << 4), /*60 */ 0 | (VTPARSE_STATE_DCS_IGNORE << 4), /*61 */ 0 | (VTPARSE_STATE_DCS_IGNORE << 4), /*62 */ 0 | (VTPARSE_STATE_DCS_IGNORE << 4), /*63 */ 0 | (VTPARSE_STATE_DCS_IGNORE << 4), /*64 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*65 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*66 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*67 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*68 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*69 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*70 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*71 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*72 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*73 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*74 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*75 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*76 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*77 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*78 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*79 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*80 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*81 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*82 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*83 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*84 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*85 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*86 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*87 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*88 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*89 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*90 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*91 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*92 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*93 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*94 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*95 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*96 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*97 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*98 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*99 */ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*100*/ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*101*/ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*102*/ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*103*/ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*104*/ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*105*/ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*106*/ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*107*/ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*108*/ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*109*/ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*110*/ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*111*/ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*112*/ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*113*/ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*114*/ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*115*/ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*116*/ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*117*/ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*118*/ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*119*/ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*120*/ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*121*/ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*122*/ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*123*/ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*124*/ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*125*/ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*126*/ 0 | (VTPARSE_STATE_DCS_PASSTHROUGH << 4), /*127*/ VTPARSE_ACTION_IGNORE | (0 << 4), /*128*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*129*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*130*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*131*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*132*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*133*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*134*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*135*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*136*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*137*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*138*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*139*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*140*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*141*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*142*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*143*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*144*/ 0 | (VTPARSE_STATE_DCS_ENTRY << 4), /*145*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*146*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*147*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*148*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*149*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*150*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*151*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*152*/ 0 | (VTPARSE_STATE_SOS_PM_APC_STRING << 4), /*153*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*154*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*155*/ 0 | (VTPARSE_STATE_CSI_ENTRY << 4), /*156*/ 0 | (VTPARSE_STATE_GROUND << 4), /*157*/ 0 | (VTPARSE_STATE_OSC_STRING << 4), /*158*/ 0 | (VTPARSE_STATE_SOS_PM_APC_STRING << 4), /*159*/ 0 | (VTPARSE_STATE_SOS_PM_APC_STRING << 4), }, { /* VTPARSE_STATE_DCS_PASSTHROUGH = 8 */ /*0 */ VTPARSE_ACTION_PUT | (0 << 4), /*1 */ VTPARSE_ACTION_PUT | (0 << 4), /*2 */ VTPARSE_ACTION_PUT | (0 << 4), /*3 */ VTPARSE_ACTION_PUT | (0 << 4), /*4 */ VTPARSE_ACTION_PUT | (0 << 4), /*5 */ VTPARSE_ACTION_PUT | (0 << 4), /*6 */ VTPARSE_ACTION_PUT | (0 << 4), /*7 */ VTPARSE_ACTION_PUT | (0 << 4), /*8 */ VTPARSE_ACTION_PUT | (0 << 4), /*9 */ VTPARSE_ACTION_PUT | (0 << 4), /*10 */ VTPARSE_ACTION_PUT | (0 << 4), /*11 */ VTPARSE_ACTION_PUT | (0 << 4), /*12 */ VTPARSE_ACTION_PUT | (0 << 4), /*13 */ VTPARSE_ACTION_PUT | (0 << 4), /*14 */ VTPARSE_ACTION_PUT | (0 << 4), /*15 */ VTPARSE_ACTION_PUT | (0 << 4), /*16 */ VTPARSE_ACTION_PUT | (0 << 4), /*17 */ VTPARSE_ACTION_PUT | (0 << 4), /*18 */ VTPARSE_ACTION_PUT | (0 << 4), /*19 */ VTPARSE_ACTION_PUT | (0 << 4), /*20 */ VTPARSE_ACTION_PUT | (0 << 4), /*21 */ VTPARSE_ACTION_PUT | (0 << 4), /*22 */ VTPARSE_ACTION_PUT | (0 << 4), /*23 */ VTPARSE_ACTION_PUT | (0 << 4), /*24 */ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*25 */ VTPARSE_ACTION_PUT | (0 << 4), /*26 */ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*27 */ 0 | (VTPARSE_STATE_ESCAPE << 4), /*28 */ VTPARSE_ACTION_PUT | (0 << 4), /*29 */ VTPARSE_ACTION_PUT | (0 << 4), /*30 */ VTPARSE_ACTION_PUT | (0 << 4), /*31 */ VTPARSE_ACTION_PUT | (0 << 4), /*32 */ VTPARSE_ACTION_PUT | (0 << 4), /*33 */ VTPARSE_ACTION_PUT | (0 << 4), /*34 */ VTPARSE_ACTION_PUT | (0 << 4), /*35 */ VTPARSE_ACTION_PUT | (0 << 4), /*36 */ VTPARSE_ACTION_PUT | (0 << 4), /*37 */ VTPARSE_ACTION_PUT | (0 << 4), /*38 */ VTPARSE_ACTION_PUT | (0 << 4), /*39 */ VTPARSE_ACTION_PUT | (0 << 4), /*40 */ VTPARSE_ACTION_PUT | (0 << 4), /*41 */ VTPARSE_ACTION_PUT | (0 << 4), /*42 */ VTPARSE_ACTION_PUT | (0 << 4), /*43 */ VTPARSE_ACTION_PUT | (0 << 4), /*44 */ VTPARSE_ACTION_PUT | (0 << 4), /*45 */ VTPARSE_ACTION_PUT | (0 << 4), /*46 */ VTPARSE_ACTION_PUT | (0 << 4), /*47 */ VTPARSE_ACTION_PUT | (0 << 4), /*48 */ VTPARSE_ACTION_PUT | (0 << 4), /*49 */ VTPARSE_ACTION_PUT | (0 << 4), /*50 */ VTPARSE_ACTION_PUT | (0 << 4), /*51 */ VTPARSE_ACTION_PUT | (0 << 4), /*52 */ VTPARSE_ACTION_PUT | (0 << 4), /*53 */ VTPARSE_ACTION_PUT | (0 << 4), /*54 */ VTPARSE_ACTION_PUT | (0 << 4), /*55 */ VTPARSE_ACTION_PUT | (0 << 4), /*56 */ VTPARSE_ACTION_PUT | (0 << 4), /*57 */ VTPARSE_ACTION_PUT | (0 << 4), /*58 */ VTPARSE_ACTION_PUT | (0 << 4), /*59 */ VTPARSE_ACTION_PUT | (0 << 4), /*60 */ VTPARSE_ACTION_PUT | (0 << 4), /*61 */ VTPARSE_ACTION_PUT | (0 << 4), /*62 */ VTPARSE_ACTION_PUT | (0 << 4), /*63 */ VTPARSE_ACTION_PUT | (0 << 4), /*64 */ VTPARSE_ACTION_PUT | (0 << 4), /*65 */ VTPARSE_ACTION_PUT | (0 << 4), /*66 */ VTPARSE_ACTION_PUT | (0 << 4), /*67 */ VTPARSE_ACTION_PUT | (0 << 4), /*68 */ VTPARSE_ACTION_PUT | (0 << 4), /*69 */ VTPARSE_ACTION_PUT | (0 << 4), /*70 */ VTPARSE_ACTION_PUT | (0 << 4), /*71 */ VTPARSE_ACTION_PUT | (0 << 4), /*72 */ VTPARSE_ACTION_PUT | (0 << 4), /*73 */ VTPARSE_ACTION_PUT | (0 << 4), /*74 */ VTPARSE_ACTION_PUT | (0 << 4), /*75 */ VTPARSE_ACTION_PUT | (0 << 4), /*76 */ VTPARSE_ACTION_PUT | (0 << 4), /*77 */ VTPARSE_ACTION_PUT | (0 << 4), /*78 */ VTPARSE_ACTION_PUT | (0 << 4), /*79 */ VTPARSE_ACTION_PUT | (0 << 4), /*80 */ VTPARSE_ACTION_PUT | (0 << 4), /*81 */ VTPARSE_ACTION_PUT | (0 << 4), /*82 */ VTPARSE_ACTION_PUT | (0 << 4), /*83 */ VTPARSE_ACTION_PUT | (0 << 4), /*84 */ VTPARSE_ACTION_PUT | (0 << 4), /*85 */ VTPARSE_ACTION_PUT | (0 << 4), /*86 */ VTPARSE_ACTION_PUT | (0 << 4), /*87 */ VTPARSE_ACTION_PUT | (0 << 4), /*88 */ VTPARSE_ACTION_PUT | (0 << 4), /*89 */ VTPARSE_ACTION_PUT | (0 << 4), /*90 */ VTPARSE_ACTION_PUT | (0 << 4), /*91 */ VTPARSE_ACTION_PUT | (0 << 4), /*92 */ VTPARSE_ACTION_PUT | (0 << 4), /*93 */ VTPARSE_ACTION_PUT | (0 << 4), /*94 */ VTPARSE_ACTION_PUT | (0 << 4), /*95 */ VTPARSE_ACTION_PUT | (0 << 4), /*96 */ VTPARSE_ACTION_PUT | (0 << 4), /*97 */ VTPARSE_ACTION_PUT | (0 << 4), /*98 */ VTPARSE_ACTION_PUT | (0 << 4), /*99 */ VTPARSE_ACTION_PUT | (0 << 4), /*100*/ VTPARSE_ACTION_PUT | (0 << 4), /*101*/ VTPARSE_ACTION_PUT | (0 << 4), /*102*/ VTPARSE_ACTION_PUT | (0 << 4), /*103*/ VTPARSE_ACTION_PUT | (0 << 4), /*104*/ VTPARSE_ACTION_PUT | (0 << 4), /*105*/ VTPARSE_ACTION_PUT | (0 << 4), /*106*/ VTPARSE_ACTION_PUT | (0 << 4), /*107*/ VTPARSE_ACTION_PUT | (0 << 4), /*108*/ VTPARSE_ACTION_PUT | (0 << 4), /*109*/ VTPARSE_ACTION_PUT | (0 << 4), /*110*/ VTPARSE_ACTION_PUT | (0 << 4), /*111*/ VTPARSE_ACTION_PUT | (0 << 4), /*112*/ VTPARSE_ACTION_PUT | (0 << 4), /*113*/ VTPARSE_ACTION_PUT | (0 << 4), /*114*/ VTPARSE_ACTION_PUT | (0 << 4), /*115*/ VTPARSE_ACTION_PUT | (0 << 4), /*116*/ VTPARSE_ACTION_PUT | (0 << 4), /*117*/ VTPARSE_ACTION_PUT | (0 << 4), /*118*/ VTPARSE_ACTION_PUT | (0 << 4), /*119*/ VTPARSE_ACTION_PUT | (0 << 4), /*120*/ VTPARSE_ACTION_PUT | (0 << 4), /*121*/ VTPARSE_ACTION_PUT | (0 << 4), /*122*/ VTPARSE_ACTION_PUT | (0 << 4), /*123*/ VTPARSE_ACTION_PUT | (0 << 4), /*124*/ VTPARSE_ACTION_PUT | (0 << 4), /*125*/ VTPARSE_ACTION_PUT | (0 << 4), /*126*/ VTPARSE_ACTION_PUT | (0 << 4), /*127*/ VTPARSE_ACTION_IGNORE | (0 << 4), /*128*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*129*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*130*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*131*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*132*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*133*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*134*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*135*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*136*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*137*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*138*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*139*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*140*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*141*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*142*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*143*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*144*/ 0 | (VTPARSE_STATE_DCS_ENTRY << 4), /*145*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*146*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*147*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*148*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*149*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*150*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*151*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*152*/ 0 | (VTPARSE_STATE_SOS_PM_APC_STRING << 4), /*153*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*154*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*155*/ 0 | (VTPARSE_STATE_CSI_ENTRY << 4), /*156*/ 0 | (VTPARSE_STATE_GROUND << 4), /*157*/ 0 | (VTPARSE_STATE_OSC_STRING << 4), /*158*/ 0 | (VTPARSE_STATE_SOS_PM_APC_STRING << 4), /*159*/ 0 | (VTPARSE_STATE_SOS_PM_APC_STRING << 4), }, { /* VTPARSE_STATE_ESCAPE = 9 */ /*0 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*1 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*2 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*3 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*4 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*5 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*6 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*7 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*8 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*9 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*10 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*11 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*12 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*13 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*14 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*15 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*16 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*17 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*18 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*19 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*20 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*21 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*22 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*23 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*24 */ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*25 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*26 */ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*27 */ 0 | (VTPARSE_STATE_ESCAPE << 4), /*28 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*29 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*30 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*31 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*32 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_ESCAPE_INTERMEDIATE << 4), /*33 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_ESCAPE_INTERMEDIATE << 4), /*34 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_ESCAPE_INTERMEDIATE << 4), /*35 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_ESCAPE_INTERMEDIATE << 4), /*36 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_ESCAPE_INTERMEDIATE << 4), /*37 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_ESCAPE_INTERMEDIATE << 4), /*38 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_ESCAPE_INTERMEDIATE << 4), /*39 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_ESCAPE_INTERMEDIATE << 4), /*40 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_ESCAPE_INTERMEDIATE << 4), /*41 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_ESCAPE_INTERMEDIATE << 4), /*42 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_ESCAPE_INTERMEDIATE << 4), /*43 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_ESCAPE_INTERMEDIATE << 4), /*44 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_ESCAPE_INTERMEDIATE << 4), /*45 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_ESCAPE_INTERMEDIATE << 4), /*46 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_ESCAPE_INTERMEDIATE << 4), /*47 */ VTPARSE_ACTION_COLLECT | (VTPARSE_STATE_ESCAPE_INTERMEDIATE << 4), /*48 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*49 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*50 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*51 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*52 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*53 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*54 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*55 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*56 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*57 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*58 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*59 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*60 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*61 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*62 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*63 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*64 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*65 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*66 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*67 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*68 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*69 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*70 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*71 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*72 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*73 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*74 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*75 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*76 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*77 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*78 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*79 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*80 */ 0 | (VTPARSE_STATE_DCS_ENTRY << 4), /*81 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*82 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*83 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*84 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*85 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*86 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*87 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*88 */ 0 | (VTPARSE_STATE_SOS_PM_APC_STRING << 4), /*89 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*90 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*91 */ 0 | (VTPARSE_STATE_CSI_ENTRY << 4), /*92 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*93 */ 0 | (VTPARSE_STATE_OSC_STRING << 4), /*94 */ 0 | (VTPARSE_STATE_SOS_PM_APC_STRING << 4), /*95 */ 0 | (VTPARSE_STATE_SOS_PM_APC_STRING << 4), /*96 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*97 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*98 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*99 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*100*/ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*101*/ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*102*/ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*103*/ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*104*/ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*105*/ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*106*/ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*107*/ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*108*/ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*109*/ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*110*/ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*111*/ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*112*/ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*113*/ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*114*/ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*115*/ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*116*/ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*117*/ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*118*/ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*119*/ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*120*/ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*121*/ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*122*/ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*123*/ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*124*/ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*125*/ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*126*/ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*127*/ VTPARSE_ACTION_IGNORE | (0 << 4), /*128*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*129*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*130*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*131*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*132*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*133*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*134*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*135*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*136*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*137*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*138*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*139*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*140*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*141*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*142*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*143*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*144*/ 0 | (VTPARSE_STATE_DCS_ENTRY << 4), /*145*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*146*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*147*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*148*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*149*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*150*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*151*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*152*/ 0 | (VTPARSE_STATE_SOS_PM_APC_STRING << 4), /*153*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*154*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*155*/ 0 | (VTPARSE_STATE_CSI_ENTRY << 4), /*156*/ 0 | (VTPARSE_STATE_GROUND << 4), /*157*/ 0 | (VTPARSE_STATE_OSC_STRING << 4), /*158*/ 0 | (VTPARSE_STATE_SOS_PM_APC_STRING << 4), /*159*/ 0 | (VTPARSE_STATE_SOS_PM_APC_STRING << 4), }, { /* VTPARSE_STATE_ESCAPE_INTERMEDIATE = 10 */ /*0 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*1 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*2 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*3 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*4 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*5 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*6 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*7 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*8 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*9 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*10 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*11 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*12 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*13 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*14 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*15 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*16 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*17 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*18 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*19 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*20 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*21 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*22 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*23 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*24 */ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*25 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*26 */ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*27 */ 0 | (VTPARSE_STATE_ESCAPE << 4), /*28 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*29 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*30 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*31 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*32 */ VTPARSE_ACTION_COLLECT | (0 << 4), /*33 */ VTPARSE_ACTION_COLLECT | (0 << 4), /*34 */ VTPARSE_ACTION_COLLECT | (0 << 4), /*35 */ VTPARSE_ACTION_COLLECT | (0 << 4), /*36 */ VTPARSE_ACTION_COLLECT | (0 << 4), /*37 */ VTPARSE_ACTION_COLLECT | (0 << 4), /*38 */ VTPARSE_ACTION_COLLECT | (0 << 4), /*39 */ VTPARSE_ACTION_COLLECT | (0 << 4), /*40 */ VTPARSE_ACTION_COLLECT | (0 << 4), /*41 */ VTPARSE_ACTION_COLLECT | (0 << 4), /*42 */ VTPARSE_ACTION_COLLECT | (0 << 4), /*43 */ VTPARSE_ACTION_COLLECT | (0 << 4), /*44 */ VTPARSE_ACTION_COLLECT | (0 << 4), /*45 */ VTPARSE_ACTION_COLLECT | (0 << 4), /*46 */ VTPARSE_ACTION_COLLECT | (0 << 4), /*47 */ VTPARSE_ACTION_COLLECT | (0 << 4), /*48 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*49 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*50 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*51 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*52 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*53 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*54 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*55 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*56 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*57 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*58 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*59 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*60 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*61 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*62 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*63 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*64 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*65 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*66 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*67 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*68 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*69 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*70 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*71 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*72 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*73 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*74 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*75 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*76 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*77 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*78 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*79 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*80 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*81 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*82 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*83 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*84 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*85 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*86 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*87 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*88 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*89 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*90 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*91 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*92 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*93 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*94 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*95 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*96 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*97 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*98 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*99 */ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*100*/ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*101*/ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*102*/ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*103*/ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*104*/ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*105*/ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*106*/ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*107*/ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*108*/ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*109*/ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*110*/ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*111*/ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*112*/ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*113*/ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*114*/ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*115*/ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*116*/ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*117*/ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*118*/ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*119*/ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*120*/ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*121*/ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*122*/ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*123*/ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*124*/ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*125*/ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*126*/ VTPARSE_ACTION_ESC_DISPATCH | (VTPARSE_STATE_GROUND << 4), /*127*/ VTPARSE_ACTION_IGNORE | (0 << 4), /*128*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*129*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*130*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*131*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*132*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*133*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*134*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*135*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*136*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*137*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*138*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*139*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*140*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*141*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*142*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*143*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*144*/ 0 | (VTPARSE_STATE_DCS_ENTRY << 4), /*145*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*146*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*147*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*148*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*149*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*150*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*151*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*152*/ 0 | (VTPARSE_STATE_SOS_PM_APC_STRING << 4), /*153*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*154*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*155*/ 0 | (VTPARSE_STATE_CSI_ENTRY << 4), /*156*/ 0 | (VTPARSE_STATE_GROUND << 4), /*157*/ 0 | (VTPARSE_STATE_OSC_STRING << 4), /*158*/ 0 | (VTPARSE_STATE_SOS_PM_APC_STRING << 4), /*159*/ 0 | (VTPARSE_STATE_SOS_PM_APC_STRING << 4), }, { /* VTPARSE_STATE_GROUND = 11 */ /*0 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*1 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*2 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*3 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*4 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*5 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*6 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*7 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*8 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*9 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*10 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*11 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*12 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*13 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*14 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*15 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*16 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*17 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*18 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*19 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*20 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*21 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*22 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*23 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*24 */ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*25 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*26 */ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*27 */ 0 | (VTPARSE_STATE_ESCAPE << 4), /*28 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*29 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*30 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*31 */ VTPARSE_ACTION_EXECUTE | (0 << 4), /*32 */ VTPARSE_ACTION_PRINT | (0 << 4), /*33 */ VTPARSE_ACTION_PRINT | (0 << 4), /*34 */ VTPARSE_ACTION_PRINT | (0 << 4), /*35 */ VTPARSE_ACTION_PRINT | (0 << 4), /*36 */ VTPARSE_ACTION_PRINT | (0 << 4), /*37 */ VTPARSE_ACTION_PRINT | (0 << 4), /*38 */ VTPARSE_ACTION_PRINT | (0 << 4), /*39 */ VTPARSE_ACTION_PRINT | (0 << 4), /*40 */ VTPARSE_ACTION_PRINT | (0 << 4), /*41 */ VTPARSE_ACTION_PRINT | (0 << 4), /*42 */ VTPARSE_ACTION_PRINT | (0 << 4), /*43 */ VTPARSE_ACTION_PRINT | (0 << 4), /*44 */ VTPARSE_ACTION_PRINT | (0 << 4), /*45 */ VTPARSE_ACTION_PRINT | (0 << 4), /*46 */ VTPARSE_ACTION_PRINT | (0 << 4), /*47 */ VTPARSE_ACTION_PRINT | (0 << 4), /*48 */ VTPARSE_ACTION_PRINT | (0 << 4), /*49 */ VTPARSE_ACTION_PRINT | (0 << 4), /*50 */ VTPARSE_ACTION_PRINT | (0 << 4), /*51 */ VTPARSE_ACTION_PRINT | (0 << 4), /*52 */ VTPARSE_ACTION_PRINT | (0 << 4), /*53 */ VTPARSE_ACTION_PRINT | (0 << 4), /*54 */ VTPARSE_ACTION_PRINT | (0 << 4), /*55 */ VTPARSE_ACTION_PRINT | (0 << 4), /*56 */ VTPARSE_ACTION_PRINT | (0 << 4), /*57 */ VTPARSE_ACTION_PRINT | (0 << 4), /*58 */ VTPARSE_ACTION_PRINT | (0 << 4), /*59 */ VTPARSE_ACTION_PRINT | (0 << 4), /*60 */ VTPARSE_ACTION_PRINT | (0 << 4), /*61 */ VTPARSE_ACTION_PRINT | (0 << 4), /*62 */ VTPARSE_ACTION_PRINT | (0 << 4), /*63 */ VTPARSE_ACTION_PRINT | (0 << 4), /*64 */ VTPARSE_ACTION_PRINT | (0 << 4), /*65 */ VTPARSE_ACTION_PRINT | (0 << 4), /*66 */ VTPARSE_ACTION_PRINT | (0 << 4), /*67 */ VTPARSE_ACTION_PRINT | (0 << 4), /*68 */ VTPARSE_ACTION_PRINT | (0 << 4), /*69 */ VTPARSE_ACTION_PRINT | (0 << 4), /*70 */ VTPARSE_ACTION_PRINT | (0 << 4), /*71 */ VTPARSE_ACTION_PRINT | (0 << 4), /*72 */ VTPARSE_ACTION_PRINT | (0 << 4), /*73 */ VTPARSE_ACTION_PRINT | (0 << 4), /*74 */ VTPARSE_ACTION_PRINT | (0 << 4), /*75 */ VTPARSE_ACTION_PRINT | (0 << 4), /*76 */ VTPARSE_ACTION_PRINT | (0 << 4), /*77 */ VTPARSE_ACTION_PRINT | (0 << 4), /*78 */ VTPARSE_ACTION_PRINT | (0 << 4), /*79 */ VTPARSE_ACTION_PRINT | (0 << 4), /*80 */ VTPARSE_ACTION_PRINT | (0 << 4), /*81 */ VTPARSE_ACTION_PRINT | (0 << 4), /*82 */ VTPARSE_ACTION_PRINT | (0 << 4), /*83 */ VTPARSE_ACTION_PRINT | (0 << 4), /*84 */ VTPARSE_ACTION_PRINT | (0 << 4), /*85 */ VTPARSE_ACTION_PRINT | (0 << 4), /*86 */ VTPARSE_ACTION_PRINT | (0 << 4), /*87 */ VTPARSE_ACTION_PRINT | (0 << 4), /*88 */ VTPARSE_ACTION_PRINT | (0 << 4), /*89 */ VTPARSE_ACTION_PRINT | (0 << 4), /*90 */ VTPARSE_ACTION_PRINT | (0 << 4), /*91 */ VTPARSE_ACTION_PRINT | (0 << 4), /*92 */ VTPARSE_ACTION_PRINT | (0 << 4), /*93 */ VTPARSE_ACTION_PRINT | (0 << 4), /*94 */ VTPARSE_ACTION_PRINT | (0 << 4), /*95 */ VTPARSE_ACTION_PRINT | (0 << 4), /*96 */ VTPARSE_ACTION_PRINT | (0 << 4), /*97 */ VTPARSE_ACTION_PRINT | (0 << 4), /*98 */ VTPARSE_ACTION_PRINT | (0 << 4), /*99 */ VTPARSE_ACTION_PRINT | (0 << 4), /*100*/ VTPARSE_ACTION_PRINT | (0 << 4), /*101*/ VTPARSE_ACTION_PRINT | (0 << 4), /*102*/ VTPARSE_ACTION_PRINT | (0 << 4), /*103*/ VTPARSE_ACTION_PRINT | (0 << 4), /*104*/ VTPARSE_ACTION_PRINT | (0 << 4), /*105*/ VTPARSE_ACTION_PRINT | (0 << 4), /*106*/ VTPARSE_ACTION_PRINT | (0 << 4), /*107*/ VTPARSE_ACTION_PRINT | (0 << 4), /*108*/ VTPARSE_ACTION_PRINT | (0 << 4), /*109*/ VTPARSE_ACTION_PRINT | (0 << 4), /*110*/ VTPARSE_ACTION_PRINT | (0 << 4), /*111*/ VTPARSE_ACTION_PRINT | (0 << 4), /*112*/ VTPARSE_ACTION_PRINT | (0 << 4), /*113*/ VTPARSE_ACTION_PRINT | (0 << 4), /*114*/ VTPARSE_ACTION_PRINT | (0 << 4), /*115*/ VTPARSE_ACTION_PRINT | (0 << 4), /*116*/ VTPARSE_ACTION_PRINT | (0 << 4), /*117*/ VTPARSE_ACTION_PRINT | (0 << 4), /*118*/ VTPARSE_ACTION_PRINT | (0 << 4), /*119*/ VTPARSE_ACTION_PRINT | (0 << 4), /*120*/ VTPARSE_ACTION_PRINT | (0 << 4), /*121*/ VTPARSE_ACTION_PRINT | (0 << 4), /*122*/ VTPARSE_ACTION_PRINT | (0 << 4), /*123*/ VTPARSE_ACTION_PRINT | (0 << 4), /*124*/ VTPARSE_ACTION_PRINT | (0 << 4), /*125*/ VTPARSE_ACTION_PRINT | (0 << 4), /*126*/ VTPARSE_ACTION_PRINT | (0 << 4), /*127*/ VTPARSE_ACTION_PRINT | (0 << 4), /*128*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*129*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*130*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*131*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*132*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*133*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*134*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*135*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*136*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*137*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*138*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*139*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*140*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*141*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*142*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*143*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*144*/ 0 | (VTPARSE_STATE_DCS_ENTRY << 4), /*145*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*146*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*147*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*148*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*149*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*150*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*151*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*152*/ 0 | (VTPARSE_STATE_SOS_PM_APC_STRING << 4), /*153*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*154*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*155*/ 0 | (VTPARSE_STATE_CSI_ENTRY << 4), /*156*/ 0 | (VTPARSE_STATE_GROUND << 4), /*157*/ 0 | (VTPARSE_STATE_OSC_STRING << 4), /*158*/ 0 | (VTPARSE_STATE_SOS_PM_APC_STRING << 4), /*159*/ 0 | (VTPARSE_STATE_SOS_PM_APC_STRING << 4), }, { /* VTPARSE_STATE_OSC_STRING = 12 */ /*0 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*1 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*2 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*3 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*4 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*5 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*6 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*7 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*8 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*9 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*10 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*11 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*12 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*13 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*14 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*15 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*16 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*17 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*18 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*19 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*20 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*21 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*22 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*23 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*24 */ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*25 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*26 */ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*27 */ 0 | (VTPARSE_STATE_ESCAPE << 4), /*28 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*29 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*30 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*31 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*32 */ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*33 */ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*34 */ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*35 */ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*36 */ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*37 */ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*38 */ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*39 */ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*40 */ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*41 */ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*42 */ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*43 */ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*44 */ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*45 */ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*46 */ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*47 */ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*48 */ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*49 */ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*50 */ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*51 */ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*52 */ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*53 */ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*54 */ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*55 */ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*56 */ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*57 */ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*58 */ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*59 */ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*60 */ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*61 */ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*62 */ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*63 */ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*64 */ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*65 */ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*66 */ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*67 */ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*68 */ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*69 */ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*70 */ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*71 */ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*72 */ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*73 */ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*74 */ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*75 */ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*76 */ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*77 */ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*78 */ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*79 */ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*80 */ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*81 */ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*82 */ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*83 */ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*84 */ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*85 */ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*86 */ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*87 */ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*88 */ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*89 */ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*90 */ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*91 */ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*92 */ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*93 */ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*94 */ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*95 */ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*96 */ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*97 */ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*98 */ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*99 */ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*100*/ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*101*/ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*102*/ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*103*/ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*104*/ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*105*/ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*106*/ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*107*/ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*108*/ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*109*/ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*110*/ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*111*/ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*112*/ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*113*/ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*114*/ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*115*/ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*116*/ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*117*/ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*118*/ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*119*/ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*120*/ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*121*/ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*122*/ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*123*/ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*124*/ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*125*/ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*126*/ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*127*/ VTPARSE_ACTION_OSC_PUT | (0 << 4), /*128*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*129*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*130*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*131*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*132*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*133*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*134*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*135*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*136*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*137*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*138*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*139*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*140*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*141*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*142*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*143*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*144*/ 0 | (VTPARSE_STATE_DCS_ENTRY << 4), /*145*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*146*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*147*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*148*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*149*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*150*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*151*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*152*/ 0 | (VTPARSE_STATE_SOS_PM_APC_STRING << 4), /*153*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*154*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*155*/ 0 | (VTPARSE_STATE_CSI_ENTRY << 4), /*156*/ 0 | (VTPARSE_STATE_GROUND << 4), /*157*/ 0 | (VTPARSE_STATE_OSC_STRING << 4), /*158*/ 0 | (VTPARSE_STATE_SOS_PM_APC_STRING << 4), /*159*/ 0 | (VTPARSE_STATE_SOS_PM_APC_STRING << 4), }, { /* VTPARSE_STATE_SOS_PM_APC_STRING = 13 */ /*0 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*1 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*2 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*3 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*4 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*5 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*6 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*7 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*8 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*9 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*10 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*11 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*12 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*13 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*14 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*15 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*16 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*17 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*18 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*19 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*20 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*21 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*22 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*23 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*24 */ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*25 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*26 */ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*27 */ 0 | (VTPARSE_STATE_ESCAPE << 4), /*28 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*29 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*30 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*31 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*32 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*33 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*34 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*35 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*36 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*37 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*38 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*39 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*40 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*41 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*42 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*43 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*44 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*45 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*46 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*47 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*48 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*49 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*50 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*51 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*52 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*53 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*54 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*55 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*56 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*57 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*58 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*59 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*60 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*61 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*62 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*63 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*64 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*65 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*66 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*67 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*68 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*69 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*70 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*71 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*72 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*73 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*74 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*75 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*76 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*77 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*78 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*79 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*80 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*81 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*82 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*83 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*84 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*85 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*86 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*87 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*88 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*89 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*90 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*91 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*92 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*93 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*94 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*95 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*96 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*97 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*98 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*99 */ VTPARSE_ACTION_IGNORE | (0 << 4), /*100*/ VTPARSE_ACTION_IGNORE | (0 << 4), /*101*/ VTPARSE_ACTION_IGNORE | (0 << 4), /*102*/ VTPARSE_ACTION_IGNORE | (0 << 4), /*103*/ VTPARSE_ACTION_IGNORE | (0 << 4), /*104*/ VTPARSE_ACTION_IGNORE | (0 << 4), /*105*/ VTPARSE_ACTION_IGNORE | (0 << 4), /*106*/ VTPARSE_ACTION_IGNORE | (0 << 4), /*107*/ VTPARSE_ACTION_IGNORE | (0 << 4), /*108*/ VTPARSE_ACTION_IGNORE | (0 << 4), /*109*/ VTPARSE_ACTION_IGNORE | (0 << 4), /*110*/ VTPARSE_ACTION_IGNORE | (0 << 4), /*111*/ VTPARSE_ACTION_IGNORE | (0 << 4), /*112*/ VTPARSE_ACTION_IGNORE | (0 << 4), /*113*/ VTPARSE_ACTION_IGNORE | (0 << 4), /*114*/ VTPARSE_ACTION_IGNORE | (0 << 4), /*115*/ VTPARSE_ACTION_IGNORE | (0 << 4), /*116*/ VTPARSE_ACTION_IGNORE | (0 << 4), /*117*/ VTPARSE_ACTION_IGNORE | (0 << 4), /*118*/ VTPARSE_ACTION_IGNORE | (0 << 4), /*119*/ VTPARSE_ACTION_IGNORE | (0 << 4), /*120*/ VTPARSE_ACTION_IGNORE | (0 << 4), /*121*/ VTPARSE_ACTION_IGNORE | (0 << 4), /*122*/ VTPARSE_ACTION_IGNORE | (0 << 4), /*123*/ VTPARSE_ACTION_IGNORE | (0 << 4), /*124*/ VTPARSE_ACTION_IGNORE | (0 << 4), /*125*/ VTPARSE_ACTION_IGNORE | (0 << 4), /*126*/ VTPARSE_ACTION_IGNORE | (0 << 4), /*127*/ VTPARSE_ACTION_IGNORE | (0 << 4), /*128*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*129*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*130*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*131*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*132*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*133*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*134*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*135*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*136*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*137*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*138*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*139*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*140*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*141*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*142*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*143*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*144*/ 0 | (VTPARSE_STATE_DCS_ENTRY << 4), /*145*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*146*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*147*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*148*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*149*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*150*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*151*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*152*/ 0 | (VTPARSE_STATE_SOS_PM_APC_STRING << 4), /*153*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*154*/ VTPARSE_ACTION_EXECUTE | (VTPARSE_STATE_GROUND << 4), /*155*/ 0 | (VTPARSE_STATE_CSI_ENTRY << 4), /*156*/ 0 | (VTPARSE_STATE_GROUND << 4), /*157*/ 0 | (VTPARSE_STATE_OSC_STRING << 4), /*158*/ 0 | (VTPARSE_STATE_SOS_PM_APC_STRING << 4), /*159*/ 0 | (VTPARSE_STATE_SOS_PM_APC_STRING << 4), }, }; vtparse_action_t ENTRY_ACTIONS[] = { VTPARSE_ACTION_CLEAR, /* CSI_ENTRY */ 0 /* none for CSI_IGNORE */, 0 /* none for CSI_INTERMEDIATE */, 0 /* none for CSI_PARAM */, VTPARSE_ACTION_CLEAR, /* DCS_ENTRY */ 0 /* none for DCS_IGNORE */, 0 /* none for DCS_INTERMEDIATE */, 0 /* none for DCS_PARAM */, VTPARSE_ACTION_HOOK, /* DCS_PASSTHROUGH */ VTPARSE_ACTION_CLEAR, /* ESCAPE */ 0 /* none for ESCAPE_INTERMEDIATE */, 0 /* none for GROUND */, VTPARSE_ACTION_OSC_START, /* OSC_STRING */ 0 /* none for SOS_PM_APC_STRING */, }; vtparse_action_t EXIT_ACTIONS[] = { 0 /* none for CSI_ENTRY */, 0 /* none for CSI_IGNORE */, 0 /* none for CSI_INTERMEDIATE */, 0 /* none for CSI_PARAM */, 0 /* none for DCS_ENTRY */, 0 /* none for DCS_IGNORE */, 0 /* none for DCS_INTERMEDIATE */, 0 /* none for DCS_PARAM */, VTPARSE_ACTION_UNHOOK, /* DCS_PASSTHROUGH */ 0 /* none for ESCAPE */, 0 /* none for ESCAPE_INTERMEDIATE */, 0 /* none for GROUND */, VTPARSE_ACTION_OSC_END, /* OSC_STRING */ 0 /* none for SOS_PM_APC_STRING */, }; cli/src/diff.c0000644000176200001440000002406614634775634012717 0ustar liggesusers/* diff - compute a shortest edit script (SES) given two sequences * Copyright (c) 2004 Michael B. Allen * * The MIT License * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /* This algorithm is basically Myers' solution to SES/LCS with * the Hirschberg linear space refinement as described in the * following publication: * * E. Myers, ``An O(ND) Difference Algorithm and Its Variations,'' * Algorithmica 1, 2 (1986), 251-266. * http://www.cs.arizona.edu/people/gene/PAPERS/diff.ps * * This is the same algorithm used by GNU diff(1). */ #include #include #include #include #include #include "cli.h" #include "errors.h" typedef enum { DIFF_MATCH = 1, DIFF_DELETE, DIFF_INSERT } diff_op; struct diff_edit { short op; int off; /* off into s1 if MATCH or DELETE but s2 if INSERT */ int len; }; typedef int (*cmp_fn)(int a, int b, void *context); static int _diff(const void *a, int aoff, int n, const void *b, int boff, int m, cmp_fn cmp, void *context, int dmax, struct diff_edit *ses, int *sn, int *buf, int bufsize); struct _chr_data { const SEXP* aptr; const SEXP* bptr; }; static int _cmp_chr(int a, int b, void *context) { struct _chr_data *data = (struct _chr_data*) context; return data->aptr[a] != data->bptr[b]; } SEXP clic_diff_chr(SEXP old, SEXP new, SEXP max) { int l_old = Rf_length(old); int l_new = Rf_length(new); int dmax = INTEGER(max)[0]; int snmax = l_old + l_new + 1; // upper bound is sum of lengths int bufsize = snmax; struct diff_edit *ses = (struct diff_edit*) S_alloc(snmax, sizeof(struct diff_edit)); int *buf = (int*) S_alloc(bufsize, sizeof(int)); int sn; struct _chr_data data; data.aptr = STRING_PTR_RO(old); data.bptr = STRING_PTR_RO(new); int out = _diff(old, 0, l_old, new, 0, l_new, _cmp_chr, &data, dmax, ses, &sn, buf, bufsize); /* AFAICT we'll never error like this, but it does not hurt... */ if (out < 0) { // __NO_COVERAGE__ R_THROW_ERROR( // __NO_COVERAGE__ "Could not calculate diff, internal error: %d, %d", // __NO_COVERAGE__ out, // __NO_COVERAGE__ errno // __NO_COVERAGE__ ); // __NO_COVERAGE__ } // __NO_COVERAGE__ SEXP result = PROTECT(allocVector(VECSXP, 4)); SET_VECTOR_ELT(result, 0, allocVector(INTSXP, sn)); SET_VECTOR_ELT(result, 1, allocVector(INTSXP, sn)); SET_VECTOR_ELT(result, 2, allocVector(INTSXP, sn)); SET_VECTOR_ELT(result, 3, ScalarInteger(out)); int i; int *op_ptr = INTEGER(VECTOR_ELT(result, 0)); int *off_ptr = INTEGER(VECTOR_ELT(result, 1)); int *len_ptr = INTEGER(VECTOR_ELT(result, 2)); for (i = 0; i < sn; i++, op_ptr++, off_ptr++, len_ptr++) { struct diff_edit *e = ses + i; *op_ptr = e->op; *off_ptr = e->off; *len_ptr = e->len; } UNPROTECT(1); return result; } #define FV(k) _v(ctx, (k), 0) #define RV(k) _v(ctx, (k), 1) struct _ctx { cmp_fn cmp; void *context; int *buf; int bufsize; struct diff_edit *ses; int si; int dmax; }; struct middle_snake { int x, y, u, v; }; static void _setv(struct _ctx *ctx, int k, int r, int val) { /* Pack -N to N into 0 to N * 2 */ int j = k <= 0 ? -k * 4 + r : k * 4 + (r - 2); if (j >= ctx->bufsize) { int newsize = j + 1; ctx->buf = (int*) S_realloc((char*) ctx->buf, newsize, ctx->bufsize, sizeof(int)); ctx->bufsize = newsize; } ctx->buf[j] = val; } static int _v(struct _ctx *ctx, int k, int r) { int j = k <= 0 ? -k * 4 + r : k * 4 + (r - 2); if (j > ctx->bufsize) { int newsize = j + 1; ctx->buf = (int*) S_realloc((char*) ctx->buf, newsize, ctx->bufsize, sizeof(int)); ctx->bufsize = newsize; } return ctx->buf[j]; } static int _find_middle_snake(const void *a, int aoff, int n, const void *b, int boff, int m, struct _ctx *ctx, struct middle_snake *ms) { int delta, odd, mid, d; delta = n - m; odd = delta & 1; mid = (n + m) / 2; mid += odd; _setv(ctx, 1, 0, 0); _setv(ctx, delta - 1, 1, n); for (d = 0; d <= mid; d++) { int k, x, y; R_CheckUserInterrupt(); if ((2 * d - 1) >= ctx->dmax) { return ctx->dmax; } for (k = d; k >= -d; k -= 2) { if (k == -d || (k != d && FV(k - 1) < FV(k + 1))) { x = FV(k + 1); } else { x = FV(k - 1) + 1; } y = x - k; ms->x = x; ms->y = y; while (x < n && y < m && ctx->cmp(aoff + x, boff + y, ctx->context) == 0) { x++; y++; } _setv(ctx, k, 0, x); if (odd && k >= (delta - (d - 1)) && k <= (delta + (d - 1))) { if (x >= RV(k)) { ms->u = x; ms->v = y; return 2 * d - 1; } } } for (k = d; k >= -d; k -= 2) { int kr = (n - m) + k; if (k == d || (k != -d && RV(kr - 1) < RV(kr + 1))) { x = RV(kr - 1); } else { x = RV(kr + 1) - 1; } y = x - kr; ms->u = x; ms->v = y; while (x > 0 && y > 0 && ctx->cmp(aoff + (x - 1), boff + (y - 1), ctx->context) == 0) { x--; y--; } _setv(ctx, kr, 1, x); if (!odd && kr >= -d && kr <= d) { if (x <= FV(kr)) { ms->x = x; ms->y = y; return 2 * d; } } } } errno = EFAULT; // __NO_COVERAGE__ return -1; // __NO_COVERAGE__ } static void _edit(struct _ctx *ctx, diff_op op, int off, int len) { struct diff_edit *e; if (len == 0 || ctx->ses == NULL) { return; } /* Add an edit to the SES (or * coalesce if the op is the same) */ e = &ctx->ses[ctx->si]; if (e->op != op) { if (e->op) { ctx->si++; e = &ctx->ses[ctx->si]; } e->op = op; e->off = off; e->len = len; } else { e->len += len; } } static int _ses(const void *a, int aoff, int n, const void *b, int boff, int m, struct _ctx *ctx) { struct middle_snake ms; int d; if (n == 0) { _edit(ctx, DIFF_INSERT, boff, m); d = m; } else if (m == 0) { _edit(ctx, DIFF_DELETE, aoff, n); d = n; } else { /* Find the middle "snake" around which we * recursively solve the sub-problems. */ d = _find_middle_snake(a, aoff, n, b, boff, m, ctx, &ms); if (d == -1) { return -1; } else if (d >= ctx->dmax) { return ctx->dmax; } else if (ctx->ses == NULL) { return d; } else if (d > 1) { if (_ses(a, aoff, ms.x, b, boff, ms.y, ctx) == -1) { return -1; } _edit(ctx, DIFF_MATCH, aoff + ms.x, ms.u - ms.x); aoff += ms.u; boff += ms.v; n -= ms.u; m -= ms.v; if (_ses(a, aoff, n, b, boff, m, ctx) == -1) { return -1; } } else { int x = ms.x; int u = ms.u; /* There are only 4 base cases when the * edit distance is 1. * * n > m m > n * * - | * \ \ x != u * \ \ * * \ \ * \ \ x == u * - | */ if (m > n) { if (x == u) { _edit(ctx, DIFF_MATCH, aoff, n); _edit(ctx, DIFF_INSERT, boff + (m - 1), 1); } else { _edit(ctx, DIFF_INSERT, boff, 1); _edit(ctx, DIFF_MATCH, aoff, n); } } else { if (x == u) { _edit(ctx, DIFF_MATCH, aoff, m); _edit(ctx, DIFF_DELETE, aoff + (n - 1), 1); } else { _edit(ctx, DIFF_DELETE, aoff, 1); _edit(ctx, DIFF_MATCH, aoff + 1, m); } } } } return d; } static int _diff(const void *a, int aoff, int n, const void *b, int boff, int m, cmp_fn cmp, void *context, int dmax, struct diff_edit *ses, int *sn, int *buf, int bufsize) { struct _ctx ctx; int d, x, y; struct diff_edit *e = NULL; ctx.cmp = cmp; ctx.context = context; ctx.buf = buf; ctx.bufsize = bufsize; ctx.ses = ses; ctx.si = 0; ctx.dmax = dmax ? dmax : INT_MAX; if (ses && sn) { if ((e = ses) == NULL) { return -1; // __NO_COVERAGE__ } e->op = 0; } /* The _ses function assumes the SES will begin or end with a delete * or insert. The following will ensure this is true by eating any * beginning matches. This is also a quick way to process sequences * that match entirely. */ x = y = 0; while (x < n && y < m && cmp(aoff + x, boff + y, context) == 0) { x++; y++; } _edit(&ctx, DIFF_MATCH, aoff, x); if ((d = _ses(a, aoff + x, n - x, b, boff + y, m - y, &ctx)) == -1) { return -1; } if (ses && sn) { *sn = e->op ? ctx.si + 1 : 0; } return d; } cli/src/keypress.c0000644000176200001440000000333214557444176013643 0ustar liggesusers #include "keypress.h" const char *keypress_key_names[KEYPRESS_NAME_SIZE] = { "", /* 0 */ "enter", /* 1 */ "backspace", /* 2 */ "left", /* 3 */ "right", /* 4 */ "up", /* 5 */ "down", /* 6 */ "insert", /* 7 */ "delete", /* 8 */ "home", /* 9 */ "end", /* 10 */ "f1", /* 11 */ "f2", /* 12 */ "f3", /* 13 */ "f4", /* 14 */ "f5", /* 15 */ "f6", /* 16 */ "f7", /* 17 */ "f8", /* 18 */ "f9", /* 19 */ "f10", /* 20 */ "f11", /* 21 */ "f12", /* 22 */ "ctrl-a", /* 23 */ "ctrl-b", /* 24 */ "ctrl-c", /* 25 */ "ctrl-d", /* 26 */ "ctrl-e", /* 27 */ "ctrl-f", /* 28 */ "ctrl-h", /* 29 */ "ctrl-k", /* 30 */ "ctrl-l", /* 31 */ "ctrl-n", /* 32 */ "ctrl-p", /* 33 */ "ctrl-t", /* 34 */ "ctrl-u", /* 35 */ "ctrl-w", /* 36 */ "escape", /* 37 */ "tab", /* 38 */ "pageup", /* 39 */ "pagedown", /* 40 */ "none", /* 41 */ "unknown" /* 42 */ }; keypress_key_t keypress_special(int key) { keypress_key_t result; result.code = key; result.ascii = '0'; result.utf8[0] = '0'; return result; } keypress_key_t keypress_utf8(const char *buf) { keypress_key_t result; result.code = KEYPRESS_CHAR; result.ascii = '0'; strncpy(result.utf8, buf, KEYPRESS_UTF8_BUFFER_SIZE); result.utf8[KEYPRESS_UTF8_BUFFER_SIZE] = '0'; return result; } SEXP cli_keypress(SEXP s_block) { SEXP result = NULL; int block = LOGICAL(s_block)[0]; keypress_key_t key = keypress_read(block); if (key.code == KEYPRESS_CHAR) { return ScalarString(mkCharCE(key.utf8, CE_UTF8)); } else { return ScalarString(mkCharCE(keypress_key_names[key.code], CE_UTF8)); } return result; } cli/src/sha1.c0000644000176200001440000001677714557444176012653 0ustar liggesusers/********************************************************************* * Filename: sha1.h * Author: Brad Conte (brad AT bradconte.com) * Copyright: * Disclaimer: This code is presented "as is" without any guarantees. * Details: Defines the API for the corresponding SHA1 implementation. *********************************************************************/ #ifndef SHA1_H #define SHA1_H /*************************** HEADER FILES ***************************/ #include /****************************** MACROS ******************************/ #define SHA1_BLOCK_SIZE 20 // SHA1 outputs a 20 byte digest /**************************** DATA TYPES ****************************/ typedef unsigned char BYTE; // 8-bit byte typedef unsigned int WORD32; // 32-bit word, change to "long" for 16-bit machines typedef struct { BYTE data[64]; WORD32 datalen; unsigned long long bitlen; WORD32 state[5]; WORD32 k[4]; } SHA1_CTX; /*********************** FUNCTION DECLARATIONS **********************/ void sha1_init(SHA1_CTX *ctx); void sha1_update(SHA1_CTX *ctx, const BYTE data[], size_t len); void sha1_final(SHA1_CTX *ctx, BYTE hash[]); #endif // SHA1_H /********************************************************************* * Filename: sha1.c * Author: Brad Conte (brad AT bradconte.com) * Copyright: * Disclaimer: This code is presented "as is" without any guarantees. * Details: Implementation of the SHA1 hashing algorithm. Algorithm specification can be found here: * http://csrc.nist.gov/publications/fips/fips180-2/fips180-2withchangenotice.pdf This implementation uses little endian byte order. *********************************************************************/ /*************************** HEADER FILES ***************************/ #include #include /****************************** MACROS ******************************/ #define ROTLEFT(a, b) ((a << b) | (a >> (32 - b))) /*********************** FUNCTION DEFINITIONS ***********************/ void sha1_transform(SHA1_CTX *ctx, const BYTE data[]) { WORD32 a, b, c, d, e, i, j, t, m[80]; for (i = 0, j = 0; i < 16; ++i, j += 4) m[i] = ((WORD32)data[j] << 24) + ((WORD32)data[j + 1] << 16) + ((WORD32)data[j + 2] << 8) + ((WORD32)data[j + 3]); for ( ; i < 80; ++i) { m[i] = (m[i - 3] ^ m[i - 8] ^ m[i - 14] ^ m[i - 16]); m[i] = (m[i] << 1) | (m[i] >> 31); } a = ctx->state[0]; b = ctx->state[1]; c = ctx->state[2]; d = ctx->state[3]; e = ctx->state[4]; for (i = 0; i < 20; ++i) { t = ROTLEFT(a, 5) + ((b & c) ^ (~b & d)) + e + ctx->k[0] + m[i]; e = d; d = c; c = ROTLEFT(b, 30); b = a; a = t; } for ( ; i < 40; ++i) { t = ROTLEFT(a, 5) + (b ^ c ^ d) + e + ctx->k[1] + m[i]; e = d; d = c; c = ROTLEFT(b, 30); b = a; a = t; } for ( ; i < 60; ++i) { t = ROTLEFT(a, 5) + ((b & c) ^ (b & d) ^ (c & d)) + e + ctx->k[2] + m[i]; e = d; d = c; c = ROTLEFT(b, 30); b = a; a = t; } for ( ; i < 80; ++i) { t = ROTLEFT(a, 5) + (b ^ c ^ d) + e + ctx->k[3] + m[i]; e = d; d = c; c = ROTLEFT(b, 30); b = a; a = t; } ctx->state[0] += a; ctx->state[1] += b; ctx->state[2] += c; ctx->state[3] += d; ctx->state[4] += e; } void sha1_init(SHA1_CTX *ctx) { ctx->datalen = 0; ctx->bitlen = 0; ctx->state[0] = 0x67452301; ctx->state[1] = 0xEFCDAB89; ctx->state[2] = 0x98BADCFE; ctx->state[3] = 0x10325476; ctx->state[4] = 0xc3d2e1f0; ctx->k[0] = 0x5a827999; ctx->k[1] = 0x6ed9eba1; ctx->k[2] = 0x8f1bbcdc; ctx->k[3] = 0xca62c1d6; } void sha1_update(SHA1_CTX *ctx, const BYTE data[], size_t len) { size_t i; for (i = 0; i < len; ++i) { ctx->data[ctx->datalen] = data[i]; ctx->datalen++; if (ctx->datalen == 64) { sha1_transform(ctx, ctx->data); ctx->bitlen += 512; ctx->datalen = 0; } } } void sha1_final(SHA1_CTX *ctx, BYTE hash[]) { WORD32 i; i = ctx->datalen; // Pad whatever data is left in the buffer. if (ctx->datalen < 56) { ctx->data[i++] = 0x80; while (i < 56) ctx->data[i++] = 0x00; } else { ctx->data[i++] = 0x80; while (i < 64) ctx->data[i++] = 0x00; sha1_transform(ctx, ctx->data); memset(ctx->data, 0, 56); } // Append to the padding the total message's length in bits and transform. ctx->bitlen += ctx->datalen * 8; ctx->data[63] = ctx->bitlen; ctx->data[62] = ctx->bitlen >> 8; ctx->data[61] = ctx->bitlen >> 16; ctx->data[60] = ctx->bitlen >> 24; ctx->data[59] = ctx->bitlen >> 32; ctx->data[58] = ctx->bitlen >> 40; ctx->data[57] = ctx->bitlen >> 48; ctx->data[56] = ctx->bitlen >> 56; sha1_transform(ctx, ctx->data); // Since this implementation uses little endian byte ordering and MD uses big endian, // reverse all the bytes when copying the final state to the output hash. for (i = 0; i < 4; ++i) { hash[i] = (ctx->state[0] >> (24 - i * 8)) & 0x000000ff; hash[i + 4] = (ctx->state[1] >> (24 - i * 8)) & 0x000000ff; hash[i + 8] = (ctx->state[2] >> (24 - i * 8)) & 0x000000ff; hash[i + 12] = (ctx->state[3] >> (24 - i * 8)) & 0x000000ff; hash[i + 16] = (ctx->state[4] >> (24 - i * 8)) & 0x000000ff; } } static void bin2str(char *to, const unsigned char *p, size_t len) { static const char *hex = "0123456789abcdef"; for (; len--; p++) { *to++ = hex[p[0] >> 4]; *to++ = hex[p[0] & 0x0f]; } } #include "errors.h" #include #include SEXP clic_sha1(SEXP strs) { BYTE hash[20]; char hex[40]; SHA1_CTX ctx; R_xlen_t i, len = XLENGTH(strs); SEXP result = PROTECT(Rf_allocVector(STRSXP, len)); for (i = 0; i < len; i++) { const char *s = CHAR(STRING_ELT(strs, i)); sha1_init(&ctx); sha1_update(&ctx, (const BYTE*) s, strlen(s)); sha1_final(&ctx, hash); bin2str(hex, hash, sizeof(hash)); SET_STRING_ELT( result, i, Rf_mkCharLenCE((const char*) hex, sizeof(hex), CE_UTF8) ); } UNPROTECT(1); return result; } SEXP clic_sha1_raw(SEXP r) { Rbyte *ptr = RAW(r); Rbyte *end = ptr + XLENGTH(r); size_t step = SIZE_MAX < 0x40000000 ? SIZE_MAX & ~63 : 0x40000000; SHA1_CTX ctx; BYTE hash[20]; char hex[40]; sha1_init(&ctx); while (ptr < end) { Rbyte *nxt = ptr + step; if (nxt > end) nxt = end; sha1_update(&ctx, ptr, nxt - ptr); ptr = nxt; } sha1_final(&ctx, hash); bin2str(hex, hash, sizeof(hash)); return Rf_ScalarString(Rf_mkCharLenCE( (const char*) hex, sizeof(hex), CE_UTF8 )); } #include "winfiles.h" #include #include SEXP clic_sha1_file(SEXP paths) { BYTE hash[20]; char hex[40]; SHA1_CTX ctx; R_xlen_t i, len = XLENGTH(paths); #define BUFSIZE (1 * 1024*1024) char *buffer = R_alloc(1, BUFSIZE); SEXP result = PROTECT(Rf_allocVector(STRSXP, len)); for (i = 0; i < len; i++) { const char *cpath = CHAR(STRING_ELT(paths, i)); int fd = open_file(cpath, O_RDONLY); if (fd == -1) { R_THROW_SYSTEM_ERROR("Cannot open file `%s`", cpath); } sha1_init(&ctx); ssize_t got = read(fd, buffer, BUFSIZE); if (got == -1) { close(fd); R_THROW_SYSTEM_ERROR("Cannot read from file `%s`", cpath); } while (got > 0) { sha1_update(&ctx, (const BYTE*) buffer, got); got = read(fd, buffer, BUFSIZE); if (got == -1) { close(fd); R_THROW_SYSTEM_ERROR("Cannot read from file `%s`", cpath); } } close(fd); sha1_final(&ctx, hash); bin2str(hex, hash, sizeof(hash)); SET_STRING_ELT( result, i, Rf_mkCharLenCE((const char*) hex, sizeof(hex), CE_UTF8) ); } UNPROTECT(1); return result; } cli/src/ansi.c0000644000176200001440000010701714557444176012735 0ustar liggesusers #include "cli.h" #include "errors.h" #include "cleancall.h" #include #include /* ---------------------------------------------------------------------- */ #define BUFFER_SIZE 4096 static char static_buffer[BUFFER_SIZE]; struct cli_buffer { char *buf; char *ptr; size_t size; }; static void clic__buffer_init(struct cli_buffer *buf); static void clic__buffer_free(struct cli_buffer *buf); static void clic__buffer_reset(struct cli_buffer *buf); static inline char *clic__buffer_get(struct cli_buffer *buf); static inline size_t clic__buffer_size(struct cli_buffer *buf); static inline void clic__buffer_push_str(struct cli_buffer *buf, const char *str); /* static inline void clic__buffer_push_str_len(struct cli_buffer *buf, */ /* const char *str, */ /* size_t len); */ static inline void clic__buffer_push_piece(struct cli_buffer *buf, const char *from, const char *to); static void clic__buffer_realloc(struct cli_buffer *buf, size_t size); static void clic__buffer_checklen(struct cli_buffer *buf, size_t len); static void clic__buffer_init(struct cli_buffer *buf) { buf->buf = static_buffer; buf->ptr = static_buffer; buf->size = sizeof(static_buffer); } static void clic__buffer_reset(struct cli_buffer *buf) { buf->ptr = buf->buf; } static inline char *clic__buffer_get(struct cli_buffer *buf) { return buf->buf; } static inline size_t clic__buffer_size(struct cli_buffer *buf) { return buf->ptr - buf->buf; } static void clic__buffer_free(struct cli_buffer *buf) { if (buf->buf != static_buffer) free(buf->buf); } static inline void clic__buffer_push_str(struct cli_buffer *buf, const char *str) { size_t len = strlen(str); clic__buffer_checklen(buf, len); strcpy(buf->ptr, str); buf->ptr += len; } /* static inline void clic__buffer_push_str_len(struct cli_buffer *buf, */ /* const char *str, */ /* size_t len) { */ /* clic__buffer_checklen(buf, len); */ /* memcpy(buf->ptr, str, len); */ /* buf->ptr += len; */ /* } */ static inline void clic__buffer_push_piece(struct cli_buffer *buf, const char *from, const char *to) { size_t len = to - from; clic__buffer_checklen(buf, len); memcpy(buf->ptr, from, len); buf->ptr += len; } static void clic__buffer_realloc(struct cli_buffer *buf, size_t size) { size_t current = buf->ptr - buf->buf; char *old = buf->buf; buf->size = size; if (buf->buf == static_buffer) { buf->buf = malloc(size); if (!buf->buf) R_THROW_SYSTEM_ERROR("ANSI string error"); memcpy(buf->buf, old, current); } else { buf->buf = realloc(buf->buf, size); if (!buf->buf) R_THROW_SYSTEM_ERROR("ANSI string error"); } buf->ptr = buf->buf + current; } static void clic__buffer_checklen(struct cli_buffer *buf, size_t len) { if (buf->ptr + len >= buf->buf + buf->size) { size_t current = buf->ptr - buf->buf; size_t prop = buf->size * 2; if (prop < current + len) prop = current + len; clic__buffer_realloc(buf, prop); } } /* ---------------------------------------------------------------------- */ static int clic__hyperlink_mode_posix(void) { char *ev = getenv("R_CLI_HYPERLINK_MODE"); if (ev == NULL) return 0; return !strcmp("posix", ev); } #define CLI_COL_256 254 #define CLI_COL_RGB 255 struct cli_color { /* 0 is off * 30-37, 40-47, 90-97, 100-107 * CLI_COL_256 (254) is 8 bit * CLI_COL_RGB (255) is 24 bit */ unsigned char col; unsigned char r, g, b; }; #define DIFFERENT_COLOR(c1,c2) memcmp(&(c1), &(c2), sizeof(struct cli_color)) struct cli_sgr_state { struct cli_color fg; struct cli_color bg; char bold; char faint; char italic; char underline; char blink; char inverse; char hide; char crossedout; const char* link_param; const char* link_uri; const char* link_end; }; struct cli_ansi_state { struct cli_sgr_state old; struct cli_sgr_state new; char unknown; char off; }; static void clic__readnum(char **ptr, unsigned int *num) { int len = 0; if ((*ptr)[0] != ';') return; (*ptr) ++; sscanf(*ptr, "%u%n", num, &len); *ptr += len; while (**ptr != ';' && **ptr != '\0') (*ptr) ++; } static void clic__parse_color(char **ptr, const char *end, struct cli_color *col) { /* This can be: * - 5; * - 2;;; */ /* Has to start with ;5; or ;2;, otherwise we skip the whole tag */ if ((*ptr)[0] != ';' || ((*ptr)[1] != '5' && (*ptr)[1] != '2') || (*ptr)[2] != ';') { *ptr = (char*) end; col->r = col->g = col->b = 0; return; } col->col = (*ptr)[1] == '5' ? CLI_COL_256 : CLI_COL_RGB; (*ptr) += 2; /* Temporarily create a zero terminated string for sscanf */ char backup = *end; char *end2 = (char*) end; *end2 = '\0'; unsigned int r = 0, g = 0, b = 0; clic__readnum(ptr, &r); if (col->col == CLI_COL_RGB) { clic__readnum(ptr, &g); clic__readnum(ptr, &b); } col->r = (unsigned char) r; col->g = (unsigned char) g; col->b = (unsigned char) b; *end2 = backup; } static void clic__ansi_update_state(const char *param, const char *intermed, const char *end, struct cli_buffer *buffer, struct cli_ansi_state *state) { char *startptr = (char*) param, *endptr; do { long num = strtol(startptr, &endptr, 10); if (endptr == startptr || num == 0) { memset(&state->new, 0, sizeof(state->new)); state->off = 1; } else if (num == 1) { state->new.bold = 1; } else if (num == 2) { state->new.faint = 1; } else if (num == 3) { state->new.italic = 1; } else if (num == 4) { state->new.underline = 1; } else if (num == 5) { state->new.blink = 1; } else if (num == 7) { state->new.inverse = 1; } else if (num == 8) { state->new.hide = 1; } else if (num == 9) { state->new.crossedout = 1; } else if (num == 22) { state->new.bold = state->new.faint = 0; } else if (num == 23) { state->new.italic = 0; } else if (num == 24) { state->new.underline = 0; } else if (num == 25) { state->new.blink = 0; } else if (num == 27) { state->new.inverse = 0; } else if (num == 28) { state->new.hide = 0; } else if (num == 29) { state->new.crossedout = 0; } else if ((num >= 30 && num <= 37) || (num >= 90 && num <= 97)) { state->new.fg.col = num; } else if (num == 38) { clic__parse_color(&endptr, intermed, &state->new.fg); } else if (num == 39) { state->new.fg.col = 0; } else if ((num >= 40 && num <= 47) || (num >= 100 && num <= 107)) { state->new.bg.col = num; } else if (num == 48) { clic__parse_color(&endptr, intermed, &state->new.bg); } else if (num == 49) { state->new.bg.col = 0; } else { /* Keep tag as is, and emit it right away */ state->unknown = 1; clic__buffer_push_piece(buffer, param - 2, end + 1); } /* The next attribute, if any */ startptr = endptr + 1; } while (endptr < intermed && *endptr == ';'); } static void clic__ansi_update_state_link(const char *param, const char *uri, const char *end, struct cli_ansi_state *state) { if ((*uri == '\033' && *(uri + 1) == '\\') || *uri == '\007') { // turn off links state->new.link_param = NULL; state->new.link_uri = NULL; state->new.link_end = NULL; } else { // start of a link state->new.link_param = param; state->new.link_uri = uri; state->new.link_end = end; } } #define EMIT(s) clic__buffer_push_str(buffer, "\033[" s "m") #define EMITS(s) clic__buffer_push_str(buffer, (s)) #define EMITP(s,e) clic__buffer_push_piece(buffer, (s), (e)) static void clic__state_update_buffer(struct cli_buffer *buffer, struct cli_ansi_state *state) { char col[20]; if (state->unknown && state->off) { state->unknown = state->off = 0; EMIT("0"); } /* Closing tags ------------------------------------------------------ */ if (state->old.bg.col != 0 && state->new.bg.col != state->old.bg.col) { EMIT("49"); } if (state->old.fg.col != 0 && state->new.fg.col != state->old.fg.col) { EMIT("39"); } if (state->new.crossedout < state->old.crossedout) { EMIT("29"); } if (state->new.hide < state->old.hide) { EMIT("28"); } if (state->new.inverse < state->old.inverse) { EMIT("27"); } if (state->new.blink < state->old.blink) { EMIT("25"); } if (state->new.underline < state->old.underline) { EMIT("24"); } if (state->new.italic < state->old.italic) { EMIT("23"); } if (state->new.faint < state->old.faint) { EMIT("22"); } if (state->new.bold < state->old.bold) { /* TODO: handle bold + faint interaction */ EMIT("22"); } if (state->old.link_uri && state->new.link_uri != state->old.link_uri) { if (clic__hyperlink_mode_posix()) { EMITS("\033]8;;\033\\"); } else { EMITS("\033]8;;\007"); } } /* Opening tags in reverse order ------------------------------------- */ if (state->new.link_uri && state->new.link_uri != state->old.link_uri) { EMITS("\033]8;"); // EMITP(state->new.link_param, state->new.link_end + 1); EMITP(state->new.link_param, state->new.link_uri); if (*(state->new.link_end) == '\007') { EMITP(state->new.link_uri, state->new.link_end); } else if (*(state->new.link_end) == '\\' && *(state->new.link_end-1) == '\033') { EMITP(state->new.link_uri, state->new.link_end - 1); } else { EMITP(state->new.link_uri, state->new.link_end - 1); } if (clic__hyperlink_mode_posix()) { EMITS("\033\\"); } else { EMITS("\007"); } } if (state->new.bold > state->old.bold) { EMIT("1"); } if (state->new.faint > state->old.faint) { EMIT("2"); } if (state->new.italic > state->old.italic) { EMIT("3"); } if (state->new.underline > state->old.underline) { EMIT("4"); } if (state->new.blink > state->old.blink) { EMIT("5"); } if (state->new.inverse > state->old.inverse) { EMIT("7"); } if (state->new.hide > state->old.hide) { EMIT("8"); } if (state->new.crossedout > state->old.crossedout) { EMIT("9"); } if (state->new.fg.col != 0 && DIFFERENT_COLOR(state->new.fg, state->old.fg)) { if (state->new.fg.col == CLI_COL_256) { snprintf(col, sizeof(col), "\033[38;5;%um", state->new.fg.r); } else if (state->new.fg.col == CLI_COL_RGB) { snprintf(col, sizeof(col), "\033[38;2;%u;%u;%um", state->new.fg.r, state->new.fg.g, state->new.fg.b); } else { snprintf(col, sizeof(col), "\033[%um", state->new.fg.col); } EMITS(col); } if (state->new.bg.col != 0 && DIFFERENT_COLOR(state->new.bg, state->old.bg)) { if (state->new.bg.col == CLI_COL_256) { snprintf(col, sizeof(col), "\033[48;5;%um", state->new.bg.r); } else if (state->new.bg.col == CLI_COL_RGB) { snprintf(col, sizeof(col), "\033[48;2;%u;%u;%um", state->new.bg.r, state->new.bg.g, state->new.bg.b); } else { snprintf(col, sizeof(col), "\033[%um", state->new.bg.col); } EMITS(col); } state->old = state->new; } typedef int (*clic__start_callback_t)(SEXP rstr, const char *str, void *data); typedef int (*clic__tag_callback_t)(const char *param, const char *intermed, const char *end, void *data); typedef int (*clic__text_callback_t)(const char *str, const char *end, void *data); typedef int (*clic__end_callback_t)(SEXP rstr, const char *str, void *data); void clic__ansi_iterator(SEXP sx, clic__start_callback_t start_cb, clic__tag_callback_t sgr_cb, clic__tag_callback_t csi_cb, clic__tag_callback_t link_cb, clic__text_callback_t text_cb, clic__end_callback_t end_cb, void *data) { R_xlen_t i, len = XLENGTH(sx); for (i = 0; i < len; i++) { SEXP str = STRING_ELT(sx, i); const char *ox = CHAR(str); const char *x = ox; const char *shaft = ox; const char *s_start; const char *s_param; const char *s_intermed; const char *s_end; const char *s_uri; if (start_cb) if (start_cb(str, ox, data)) goto end; if (str == NA_STRING) goto end; while (*x != 0) { if (*x == '\033' && *(x + 1) == '[') { // CSI s_start = x; s_param = s_intermed = x + 2; while (*s_intermed >= 0x30 && *s_intermed <= 0x3f) s_intermed++; s_end = s_intermed; while (*s_end >= 0x20 && *s_end <= 0x2f) s_end++; if (s_start > shaft && text_cb) { if (text_cb(shaft, s_start, data)) goto end; } if (*s_end == 'm') { if (sgr_cb) { if (sgr_cb(s_param, s_intermed, s_end, data)) goto end; } } else { if (csi_cb) { if (csi_cb(s_param, s_intermed, s_end, data)) goto end; } } shaft = s_end + 1; x = *s_end ? s_end + 1 : s_end; } else if (*x == '\033' && *(x + 1) == ']' && *(x + 2) == '8' && *(x + 3) == ';') { // OSC s_start = x; s_param = s_uri = x + 4; while (*s_uri != ';' && *s_uri != '\0') s_uri++; s_uri++; s_end = s_uri; for (;;) { if (*s_end == '\0') break; if (*s_end == '\007') break; if (*s_end == '\\' && *(s_end - 1) == '\033') break; s_end++; } if (s_start > shaft && text_cb) { if (text_cb(shaft, s_start, data)) goto end; } if (link_cb) { if (link_cb(s_param, s_uri, s_end, data)) goto end; } shaft = s_end + 1; x = *s_end ? s_end + 1 : s_end; } else { x++; } /* This is not needed, but slightly faster this way */ while (*x != '\033' && *x != '\0') x++; } if (x > shaft && text_cb) text_cb(shaft, x, data); end: if (end_cb) end_cb(str, ox, data); } } /* ---------------------------------------------------------------------- */ struct simplify_data { struct cli_ansi_state state; struct cli_buffer buffer; R_xlen_t done; size_t num_tags; SEXP result; char keep_csi; }; static int simplify_cb_start(SEXP rstr, const char *str, void *vdata) { struct simplify_data *data = vdata; data->num_tags = 0; clic__buffer_reset(&data->buffer); return 0; } static int simplify_cb_sgr(const char *param, const char *intermed, const char *end, void *vdata) { struct simplify_data *data = vdata; data->num_tags ++; clic__ansi_update_state(param, intermed, end, &data->buffer, &data->state); return 0; } static int simplify_cb_csi(const char *param, const char *intermed, const char *end, void *vdata) { struct simplify_data *data = vdata; if (data->keep_csi) { clic__buffer_push_piece(&data->buffer, param - 2, end + 1); } else { /* Need to count, to avoid a verbatim STRSXP copy */ data->num_tags ++; } return 0; } static int simplify_cb_link(const char *param, const char *uri, const char *end, void *vdata) { struct simplify_data *data = vdata; data->num_tags ++; clic__ansi_update_state_link(param, uri, end, &data->state); return 0; } static int simplify_cb_text(const char *str, const char *end, void *vdata) { struct simplify_data *data = vdata; clic__state_update_buffer(&data->buffer, &data->state); clic__buffer_push_piece(&data->buffer, str, end); return 0; } static int simplify_cb_end(SEXP rstr, const char *str, void *vdata) { struct simplify_data *data = vdata; memset(&data->state.new, 0, sizeof(struct cli_sgr_state)); clic__state_update_buffer(&data->buffer, &data->state); if (data->num_tags == 0) { SET_STRING_ELT(data->result, data->done, rstr); } else { SET_STRING_ELT( data->result, data->done, Rf_mkCharLenCE( clic__buffer_get(&data->buffer), clic__buffer_size(&data->buffer), CE_UTF8 ) ); } data->done ++; return 0; } SEXP clic_ansi_simplify(SEXP sx, SEXP keep_csi) { struct simplify_data data; memset(&data.state, 0, sizeof(data.state)); clic__buffer_init(&data.buffer); data.done = 0; data.result = PROTECT(allocVector(STRSXP, XLENGTH(sx))); data.keep_csi = LOGICAL(keep_csi)[0]; clic__ansi_iterator( sx, simplify_cb_start, simplify_cb_sgr, simplify_cb_csi, simplify_cb_link, simplify_cb_text, simplify_cb_end, &data ); clic__buffer_free(&data.buffer); SEXP ocls = PROTECT(getAttrib(sx, R_ClassSymbol)); int oclslen = isNull(ocls) ? 0 : LENGTH(ocls); int has_as = oclslen == 0 ? 0 : Rf_inherits(sx, "cli_ansi_string"); int has_as2 = oclslen == 0 ? 0 : Rf_inherits(sx, "ansi_string"); int has_ch = oclslen == 0 ? 0 : Rf_inherits(sx, "character"); int i, j = 0, clslen = oclslen + !has_as + !has_as2 + !has_ch; SEXP cls = PROTECT(allocVector(STRSXP, clslen)); if (!has_as) SET_STRING_ELT(cls, j++, mkChar("cli_ansi_string")); if (!has_as2) SET_STRING_ELT(cls, j++, mkChar("ansi_string")); for (i = 0; i < oclslen; i++) { SET_STRING_ELT(cls, j++, STRING_ELT(ocls, i)); } if (!has_ch) SET_STRING_ELT(cls, j++, mkChar("character")); setAttrib(data.result, R_ClassSymbol, cls); UNPROTECT(3); return data.result; } /* ---------------------------------------------------------------------- */ struct substr_data { struct cli_ansi_state state; struct cli_buffer buffer; R_xlen_t done; SEXP result; int *start; int *stop; int pos; }; static int substr_cb_start(SEXP rstr, const char *str, void *vdata) { struct substr_data *data = vdata; data->pos = 1; clic__buffer_reset(&data->buffer); return rstr == NA_STRING; } static int substr_cb_sgr(const char *param, const char *intermed, const char *end, void *vdata) { struct substr_data *data = vdata; clic__ansi_update_state(param, intermed, end, &data->buffer, &data->state); return 0; } static int substr_cb_link(const char *param, const char *uri, const char *end, void *vdata) { struct substr_data *data = vdata; clic__ansi_update_state_link(param, uri, end, &data->state); return 0; } static int substr_cb_text(const char *str, const char *end, void *vdata) { struct substr_data *data = vdata; int start = data->start[data->done]; int stop = data->stop[data->done]; char *end2 = (char*) end; char oldend = *end2; *end2 = '\0'; /* Skip before start */ struct grapheme_iterator iter; if (data->pos < start) { clic_utf8_graphscan_make(&iter, (const uint8_t*) str, /* width = */ 0); while (data->pos < start && iter.nxt_prop != -1) { clic_utf8_graphscan_next(&iter, NULL, NULL); data->pos++; } str = (const char*) iter.cnd; } /* Add before stop */ if (data->pos <= stop) { const char *from = str; clic_utf8_graphscan_make(&iter, (const uint8_t*) str, /* width = */ 0); while (data->pos <= stop && iter.nxt_prop != -1) { clic_utf8_graphscan_next(&iter, NULL, NULL); data->pos++; } str = (const char*) iter.cnd; if (from < str) { clic__state_update_buffer(&data->buffer, &data->state); clic__buffer_push_piece(&data->buffer, from, str); } } *end2 = oldend; /* If we are done, then just close all open tags */ if (data->pos > stop) { memset(&data->state.new, 0, sizeof(struct cli_sgr_state)); clic__state_update_buffer(&data->buffer, &data->state); return 1; } else { return 0; } } static int substr_cb_end(SEXP rstr, const char *str, void *vdata) { struct substr_data *data = vdata; memset(&data->state.new, 0, sizeof(struct cli_sgr_state)); clic__state_update_buffer(&data->buffer, &data->state); if (rstr == NA_STRING) { SET_STRING_ELT(data->result, data->done, rstr); } else { SET_STRING_ELT( data->result, data->done, Rf_mkCharLenCE( clic__buffer_get(&data->buffer), clic__buffer_size(&data->buffer), CE_UTF8 ) ); } data->done++; return 0; } SEXP clic_ansi_substr(SEXP sx, SEXP start, SEXP stop) { struct substr_data data; memset(&data.state, 0, sizeof(data.state)); clic__buffer_init(&data.buffer); data.done = 0; data.result = PROTECT(allocVector(STRSXP, XLENGTH(sx))); data.start = INTEGER(start); data.stop = INTEGER(stop); clic__ansi_iterator( sx, substr_cb_start, substr_cb_sgr, NULL, substr_cb_link, substr_cb_text, substr_cb_end, &data ); clic__buffer_free(&data.buffer); SEXP ocls = PROTECT(getAttrib(sx, R_ClassSymbol)); int oclslen = isNull(ocls) ? 0 : LENGTH(ocls); int has_as = oclslen == 0 ? 0 : Rf_inherits(sx, "cli_ansi_string"); int has_as2 = oclslen == 0 ? 0 : Rf_inherits(sx, "ansi_string"); int has_ch = oclslen == 0 ? 0 : Rf_inherits(sx, "character"); int i, j = 0, clslen = oclslen + !has_as + !has_as2 + !has_ch; SEXP cls = PROTECT(allocVector(STRSXP, clslen)); if (!has_as) SET_STRING_ELT(cls, j++, mkChar("cli_ansi_string")); if (!has_as2) SET_STRING_ELT(cls, j++, mkChar("ansi_string")); for (i = 0; i < oclslen; i++) { SET_STRING_ELT(cls, j++, STRING_ELT(ocls, i)); } if (!has_ch) SET_STRING_ELT(cls, j++, mkChar("character")); setAttrib(data.result, R_ClassSymbol, cls); UNPROTECT(3); return data.result; } /* ---------------------------------------------------------------------- */ struct html_data { struct cli_ansi_state state; struct cli_buffer buffer; const char *str; R_xlen_t done; SEXP result; char had_tags; char is_link; char keep_csi; }; #define EMITS1(s) do { \ if (first) { \ EMITS("buffer; struct cli_ansi_state *state = &data->state; char col[64]; int first = 1; data->is_link = 0; /* Opening tags ------------------------------------------------------ */ if (state->new.link_uri && state->new.link_uri != state->old.link_uri) { EMITS("new.link_end) == '\007') { EMITP(state->new.link_uri, state->new.link_end); } else if (*(state->new.link_end) == '\\' && *(state->new.link_end-1) == '\033') { EMITP(state->new.link_uri, state->new.link_end - 1); } else { EMITP(state->new.link_uri, state->new.link_end - 1); } EMITS("\">"); data->is_link = 1; } if (state->new.bold > state->old.bold) { EMITS1(" ansi-bold"); } if (state->new.faint > state->old.faint) { EMITS1(" ansi-faint"); } if (state->new.italic > state->old.italic) { EMITS1(" ansi-italic"); } if (state->new.underline > state->old.underline) { EMITS1(" ansi-underline"); } if (state->new.blink > state->old.blink) { EMITS1(" ansi-blink"); } if (state->new.inverse > state->old.inverse) { EMITS1(" ansi-inverse"); } if (state->new.hide > state->old.hide) { EMITS1(" ansi-hide"); } if (state->new.crossedout > state->old.crossedout) { EMITS1(" ansi-crossedout"); } if (state->new.fg.col != 0 && DIFFERENT_COLOR(state->new.fg, state->old.fg)) { if (state->new.fg.col == CLI_COL_256) { snprintf(col, sizeof(col), " ansi-color-%u", state->new.fg.r); } else if (state->new.fg.col == CLI_COL_RGB) { snprintf(col, sizeof(col), " ansi-color-%u-%u-%u", state->new.fg.r, state->new.fg.g, state->new.fg.b); } else { unsigned char ncol = state->new.fg.col - 30; if (ncol > 7) ncol -= 60; snprintf(col, sizeof(col), " ansi-color-%u", ncol); } EMITS1(col); } if (state->new.bg.col != 0 && DIFFERENT_COLOR(state->new.bg, state->old.bg)) { if (state->new.bg.col == CLI_COL_256) { snprintf(col, sizeof(col), " ansi-bg-color-%u", state->new.bg.r); } else if (state->new.bg.col == CLI_COL_RGB) { snprintf(col, sizeof(col), " ansi-bg-color-%u-%u-%u", state->new.bg.r, state->new.bg.g, state->new.bg.b); } else { unsigned char ncol = state->new.bg.col - 40; if (ncol > 7) ncol -= 60; snprintf(col, sizeof(col), " ansi-bg-color-%u", ncol); } EMITS1(col); } state->old = state->new; if (!first) EMITS("\">"); data->had_tags = !first; } static void clic__html_end(struct html_data *data) { struct cli_buffer *buffer = &data->buffer; if (data->had_tags) EMITS(""); if (data->is_link) EMITS(""); } static int html_cb_start(SEXP rstr, const char *str, void *vdata) { struct html_data *data = vdata; clic__buffer_reset(&data->buffer); return rstr == NA_STRING; } static int html_cb_sgr(const char *param, const char *intermed, const char *end, void *vdata) { struct html_data *data = vdata; clic__ansi_update_state(param, intermed, end, &data->buffer, &data->state); return 0; } static int html_cb_csi(const char *param, const char *intermed, const char *end, void *vdata) { struct html_data *data = vdata; if (data->keep_csi) { clic__buffer_push_piece(&data->buffer, param - 2, end + 1); } return 0; } static int html_cb_link(const char *param, const char *uri, const char *end, void *vdata) { struct html_data *data = vdata; clic__ansi_update_state_link(param, uri, end, &data->state); return 0; } static int html_cb_text(const char *str, const char *end, void *vdata) { struct html_data *data = vdata; clic__html_start(data); clic__buffer_push_piece(&data->buffer, str, end); clic__html_end(data); return 0; } static int html_cb_end(SEXP rstr, const char *str, void *vdata) { struct html_data *data = vdata; memset(&data->state.new, 0, sizeof(data->state.new)); if (rstr == NA_STRING) { SET_STRING_ELT(data->result, data->done, rstr); } else { SET_STRING_ELT( data->result, data->done, Rf_mkCharLenCE( clic__buffer_get(&data->buffer), clic__buffer_size(&data->buffer), CE_UTF8 ) ); } data->done++; return 0; } SEXP clic_ansi_html(SEXP sx, SEXP keep_csi) { struct html_data data; memset(&data.state, 0, sizeof(data.state)); clic__buffer_init(&data.buffer); data.done = 0; data.result = PROTECT(allocVector(STRSXP, XLENGTH(sx))); data.keep_csi = LOGICAL(keep_csi)[0]; clic__ansi_iterator( sx, html_cb_start, html_cb_sgr, html_cb_csi, html_cb_link, html_cb_text, html_cb_end, &data ); clic__buffer_free(&data.buffer); UNPROTECT(1); return data.result; } /* ---------------------------------------------------------------------- */ struct has_any_data { R_xlen_t done; SEXP result; char sgr; char csi; char link; char has; }; static int has_any_cb_sgr(const char *param, const char *intermed, const char *end, void *vdata) { struct has_any_data *data = vdata; if (data->sgr) { data->has = 1; return 1; } else { return 0; } } static int has_any_cb_csi(const char *param, const char *intermed, const char *end, void *vdata) { struct has_any_data *data = vdata; if (data->csi) { data->has = 1; return 1; } else { return 0; } } static int has_any_cb_link(const char *param, const char *uri, const char *end, void *vdata) { struct has_any_data *data = vdata; if (data->link) { data->has = 1; return 1; } else { return 0; } } static int has_any_cb_end(SEXP rstr, const char *str, void *vdata) { struct has_any_data *data = vdata; if (rstr == NA_STRING) { LOGICAL(data->result)[data->done] = NA_LOGICAL; } else { LOGICAL(data->result)[data->done] = data->has; } data->has = 0; data->done ++; return 0; } SEXP clic_ansi_has_any(SEXP sx, SEXP sgr, SEXP csi, SEXP link) { struct has_any_data data; data.done = 0; data.has = 0; data.result = PROTECT(allocVector(LGLSXP, XLENGTH(sx))); data.sgr = LOGICAL(sgr)[0]; data.csi = LOGICAL(csi)[0]; data.link = LOGICAL(link)[0]; clic__ansi_iterator( sx, /* cb_start = */ 0, has_any_cb_sgr, has_any_cb_csi, has_any_cb_link, /* cb_text = */ 0, has_any_cb_end, &data ); UNPROTECT(1); return data.result; } /* ---------------------------------------------------------------------- */ struct strip_data { struct cli_buffer buffer; R_xlen_t done; size_t num_tags; SEXP result; char sgr; char csi; char link; }; static int strip_cb_start(SEXP rstr, const char *str, void *vdata) { struct strip_data *data = vdata; data->num_tags = 0; clic__buffer_reset(&data->buffer); return 0; } static int strip_cb_sgr(const char *param, const char *intermed, const char *end, void *vdata) { struct strip_data *data = vdata; if (data->sgr) { data->num_tags ++; } else { clic__buffer_push_piece(&data->buffer, param - 2, end + 1); } return 0; } static int strip_cb_csi(const char *param, const char *intermed, const char *end, void *vdata) { struct strip_data *data = vdata; if (data->csi) { data->num_tags ++; } else { clic__buffer_push_piece(&data->buffer, param - 2, end + 1); } return 0; } static int strip_cb_link(const char *param, const char *uri, const char *end, void *vdata) { struct strip_data *data = vdata; if (data->link) { data->num_tags ++; } else { clic__buffer_push_piece(&data->buffer, param - 4, end + 1); } return 0; } static int strip_cb_text(const char *str, const char *end, void *vdata) { struct strip_data *data = vdata; clic__buffer_push_piece(&data->buffer, str, end); return 0; } static int strip_cb_end(SEXP rstr, const char *str, void *vdata) { struct strip_data *data = vdata; if (data->num_tags == 0) { SET_STRING_ELT(data->result, data->done, rstr); } else { SET_STRING_ELT( data->result, data->done, Rf_mkCharLenCE( clic__buffer_get(&data->buffer), clic__buffer_size(&data->buffer), CE_UTF8 ) ); } data->done ++; return 0; } /* TODO: this would benefit from a non-iterator implementation, that would be much faster. */ /* TODO: strip hyperlinks */ SEXP clic_ansi_strip(SEXP sx, SEXP sgr, SEXP csi, SEXP link) { struct strip_data data; clic__buffer_init(&data.buffer); data.done = 0; data.result = PROTECT(allocVector(STRSXP, XLENGTH(sx))); data.sgr = LOGICAL(sgr)[0]; data.csi = LOGICAL(csi)[0]; data.link = LOGICAL(link)[0]; clic__ansi_iterator( sx, strip_cb_start, strip_cb_sgr, strip_cb_csi, strip_cb_link, strip_cb_text, strip_cb_end, &data ); clic__buffer_free(&data.buffer); UNPROTECT(1); return data.result; } /* ---------------------------------------------------------------------- */ struct nchar_data { R_xlen_t done; int *resptr; int *result; }; static int nchar_cb_start(SEXP rstr, const char *str, void *vdata) { struct nchar_data *data = vdata; data->resptr = data->result + data->done; if (rstr == NA_STRING) { *data->resptr = NA_INTEGER; return 1; } else { *data->resptr = 0; return 0; } } static int nchar_cb_text_graphemes(const char *str, const char *end, void *vdata) { struct nchar_data *data = vdata; char *end2 = (char*) end; char oldend = *end2; int len = 0; struct grapheme_iterator iter; *end2 = '\0'; clic_utf8_graphscan_make(&iter, (const uint8_t*) str, /* width = */ 0); while (iter.nxt_prop != -1) { clic_utf8_graphscan_next(&iter, NULL, NULL); len ++; } *data->resptr += len; *end2 = oldend; return 0; } static int nchar_cb_text_bytes(const char *str, const char *end, void *vdata) { struct nchar_data *data = vdata; *data->resptr += (end - str); return 0; } static int nchar_cb_text_width(const char *str, const char *end, void *vdata) { struct nchar_data *data = vdata; char *end2 = (char*) end; char oldend = *end2; int len = 0, width; struct grapheme_iterator iter; *end2 = '\0'; clic_utf8_graphscan_make(&iter, (const uint8_t*) str, /* width = */ 1); while (iter.nxt_prop != -1) { clic_utf8_graphscan_next(&iter, NULL, &width); len += width; } *data->resptr += len; *end2 = oldend; return 0; } static int nchar_cb_text_codepoints(const char *str, const char *end, void *vdata) { struct nchar_data *data = vdata; while (str < end) { int len = UTF8LITE_UTF8_TOTAL_LEN(*str); str += len; *data->resptr += 1; } return 0; } static int nchar_cb_end(SEXP rstr, const char *str, void *vdata) { struct nchar_data *data = vdata; data->done ++; return 0; } static clic__text_callback_t nchar_text_cbs[] = { nchar_cb_text_graphemes, nchar_cb_text_bytes, nchar_cb_text_width, nchar_cb_text_codepoints }; /* TODO: this would benefit from a non-iterator implementation, that would be much faster. */ SEXP clic_ansi_nchar(SEXP sx, SEXP type) { int ctype = INTEGER(type)[0] - 1; struct nchar_data data; data.done = 0; SEXP result = PROTECT(allocVector(INTSXP, XLENGTH(sx))); data.result = INTEGER(result); clic__ansi_iterator( sx, nchar_cb_start, /* sgr = */ NULL, /* csi = */ NULL, /* link = */ NULL, nchar_text_cbs[ctype], nchar_cb_end, &data ); UNPROTECT(1); return result; } cli/src/progress-altrep.c0000644000176200001440000001433214557444176015131 0ustar liggesusers #include "cli.h" #include #if R_VERSION < R_Version(3, 5, 0) SEXP clic_progress_along(SEXP seq, SEXP bar) { error("internal cli error"); return R_NilValue; } SEXP clic_make_timer() { return R_NilValue; } SEXP clic_update_due() { return ScalarLogical(*cli_timer_flag); } SEXP clic_dataptr(SEXP x) { int i, n = LENGTH(x); SEXP ret = PROTECT(allocVector(INTSXP, n)); for (i = 0; i < n; i++) { INTEGER(ret)[i] = INTEGER(x)[i] * 2; } UNPROTECT(1); return ret; } #else #include R_altrep_class_t progress_along_t; R_altrep_class_t disable_gc_t; R_altrep_class_t cli_timer_t; static SEXP cli__current_progress_bar = 0; static SEXP cli__disable_gc = 0; void *disable_gc_DataPtr(SEXP x, Rboolean writeable) { /* We can't throw a condition from C, unfortunately... */ SEXP call = PROTECT(Rf_lang2(install("progress_altrep_update"), cli__current_progress_bar)); Rf_eval(call, cli_pkgenv); UNPROTECT(1); return NULL; } /* --------------------------------------------------------------------- */ static SEXP cli__timer = 0; SEXP clic_make_timer(void) { return cli__timer; } SEXP clic_update_due(void) { /* This will make a copy, which leads to better semantics. */ return ScalarLogical(*cli_timer_flag); } R_xlen_t cli_timer_Length(SEXP x) { return 1; } void* cli_timer_DataPtr(SEXP x, Rboolean writeable) { return (void*) cli_timer_flag; } int cli_timer_Elt(SEXP x, R_xlen_t i) { return *cli_timer_flag; } /* --------------------------------------------------------------------- */ SEXP clic_progress_along(SEXP seq, SEXP bar) { SEXP val = R_new_altrep(progress_along_t, seq, bar); return val; } R_xlen_t progress_along_Length(SEXP x) { SEXP data1 = R_altrep_data1(x); return XLENGTH(data1); } SEXP progress_along_Duplicate(SEXP x, Rboolean deep) { SEXP data1 = R_altrep_data1(x); SEXP bar = R_altrep_data2(x); return clic_progress_along(data1, bar); } Rboolean progress_along_Inspect(SEXP x, int pre, int deep, int pvec, void (*inspect_subtree)(SEXP, int, int, int)) { Rprintf(" progress_along %s\n", type2char(TYPEOF(x))); return FALSE; } void* progress_along_Dataptr(SEXP x, Rboolean writeable) { SEXP data1 = R_altrep_data1(x); if (writeable) { return DATAPTR(data1); } else { return (void*) DATAPTR_RO(data1); } } const void* progress_along_Dataptr_or_null(SEXP x) { SEXP data1 = R_altrep_data1(x); return DATAPTR_OR_NULL(data1); } // TODO: long vector support? int progress_along_Elt(SEXP x, R_xlen_t i) { if (*cli_timer_flag) { if (cli__reset) *cli_timer_flag = 0; SEXP bar = R_altrep_data2(x); double now = clic__get_time(); Rf_defineVar(PROTECT(Rf_install("current")), PROTECT(ScalarReal((int) i)), bar); cli__current_progress_bar = bar; SEXP show_after = clic__find_var(bar, Rf_install("show_after")); if (now > REAL(show_after)[0]) DATAPTR(cli__disable_gc); UNPROTECT(2); } return (int) (i + 1); } R_xlen_t progress_along_Get_region(SEXP x, R_xlen_t i, R_xlen_t n, int *buf) { SEXP data1 = R_altrep_data1(x); return INTEGER_GET_REGION(data1, i, n, buf); } SEXP progress_along_Sum(SEXP x, Rboolean narm) { SEXP data1 = R_altrep_data1(x); R_xlen_t n = XLENGTH(data1); return ScalarReal(n * ( n + 1.0) / 2.0); } SEXP progress_along_Max(SEXP x, Rboolean narm) { SEXP data1 = R_altrep_data1(x); R_xlen_t n = XLENGTH(data1); return ScalarReal(n); } SEXP progress_along_Min(SEXP x, Rboolean narm) { SEXP data1 = R_altrep_data1(x); R_xlen_t n = XLENGTH(data1); if (n > 0) { return ScalarInteger(1); } else { return ScalarReal(R_PosInf); } } int progress_along_Is_sorted(SEXP x) { return SORTED_INCR; } void cli_init_altrep(DllInfo *dll) { // -- progress_along_t -------------------------------------------------- progress_along_t = R_make_altinteger_class("progress_along_t", "cli", dll); // override ALTREP methods R_set_altrep_Duplicate_method(progress_along_t, progress_along_Duplicate); R_set_altrep_Inspect_method(progress_along_t, progress_along_Inspect); R_set_altrep_Length_method(progress_along_t, progress_along_Length); // override ALTVEC methods R_set_altvec_Dataptr_method(progress_along_t, progress_along_Dataptr); R_set_altvec_Dataptr_or_null_method(progress_along_t, progress_along_Dataptr_or_null); // override ALTINTEGER methods R_set_altinteger_Elt_method(progress_along_t, progress_along_Elt); R_set_altinteger_Get_region_method(progress_along_t, progress_along_Get_region); R_set_altinteger_Sum_method(progress_along_t, progress_along_Sum); R_set_altinteger_Max_method(progress_along_t, progress_along_Max); R_set_altinteger_Min_method(progress_along_t, progress_along_Min); // R_set_altinteger_No_NA_method(progress_along_t, progress_along_No_NA); R_set_altinteger_Is_sorted_method(progress_along_t, progress_along_Is_sorted); // -- disable_gc_t -------------------------------------------------- disable_gc_t = R_make_altinteger_class("disable_gc_t", "cli", dll); R_set_altvec_Dataptr_method(disable_gc_t, disable_gc_DataPtr); cli__disable_gc = R_new_altrep(disable_gc_t, R_NilValue, R_NilValue); R_PreserveObject(cli__disable_gc); // -- cli_timer_t --------------------------------------------------- #if R_VERSION < R_Version(3, 6, 0) cli_timer_t = R_make_altinteger_class("cli_timer_t", "cli", dll); R_set_altrep_Length_method(cli_timer_t, cli_timer_Length); R_set_altvec_Dataptr_method(cli_timer_t, cli_timer_DataPtr); R_set_altinteger_Elt_method(cli_timer_t, cli_timer_Elt); #else cli_timer_t = R_make_altlogical_class("cli_timer_t", "cli", dll); R_set_altrep_Length_method(cli_timer_t, cli_timer_Length); R_set_altvec_Dataptr_method(cli_timer_t, cli_timer_DataPtr); R_set_altlogical_Elt_method(cli_timer_t, cli_timer_Elt); #endif cli__timer = R_new_altrep(cli_timer_t, R_NilValue, R_NilValue); MARK_NOT_MUTABLE(cli__timer); R_PreserveObject(cli__timer); } SEXP clic_dataptr(SEXP x) { int i, n = LENGTH(x); SEXP ret = PROTECT(allocVector(INTSXP, n)); for (i = 0; i < n; i++) { INTEGER(ret)[i] = INTEGER(x)[i] + INTEGER_RO(x)[i]; } UNPROTECT(1); return ret; } #endif cli/src/xxhash.h0000644000176200001440000075625014752735214013315 0ustar liggesusers/* * xxHash - Extremely Fast Hash algorithm * Header File * Copyright (C) 2012-2021 Yann Collet * * BSD 2-Clause License (https://www.opensource.org/licenses/bsd-license.php) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * You can contact the author at: * - xxHash homepage: https://www.xxhash.com * - xxHash source repository: https://github.com/Cyan4973/xxHash */ /*! * @mainpage xxHash * * xxHash is an extremely fast non-cryptographic hash algorithm, working at RAM speed * limits. * * It is proposed in four flavors, in three families: * 1. @ref XXH32_family * - Classic 32-bit hash function. Simple, compact, and runs on almost all * 32-bit and 64-bit systems. * 2. @ref XXH64_family * - Classic 64-bit adaptation of XXH32. Just as simple, and runs well on most * 64-bit systems (but _not_ 32-bit systems). * 3. @ref XXH3_family * - Modern 64-bit and 128-bit hash function family which features improved * strength and performance across the board, especially on smaller data. * It benefits greatly from SIMD and 64-bit without requiring it. * * Benchmarks * --- * The reference system uses an Intel i7-9700K CPU, and runs Ubuntu x64 20.04. * The open source benchmark program is compiled with clang v10.0 using -O3 flag. * * | Hash Name | ISA ext | Width | Large Data Speed | Small Data Velocity | * | -------------------- | ------- | ----: | ---------------: | ------------------: | * | XXH3_64bits() | @b AVX2 | 64 | 59.4 GB/s | 133.1 | * | MeowHash | AES-NI | 128 | 58.2 GB/s | 52.5 | * | XXH3_128bits() | @b AVX2 | 128 | 57.9 GB/s | 118.1 | * | CLHash | PCLMUL | 64 | 37.1 GB/s | 58.1 | * | XXH3_64bits() | @b SSE2 | 64 | 31.5 GB/s | 133.1 | * | XXH3_128bits() | @b SSE2 | 128 | 29.6 GB/s | 118.1 | * | RAM sequential read | | N/A | 28.0 GB/s | N/A | * | ahash | AES-NI | 64 | 22.5 GB/s | 107.2 | * | City64 | | 64 | 22.0 GB/s | 76.6 | * | T1ha2 | | 64 | 22.0 GB/s | 99.0 | * | City128 | | 128 | 21.7 GB/s | 57.7 | * | FarmHash | AES-NI | 64 | 21.3 GB/s | 71.9 | * | XXH64() | | 64 | 19.4 GB/s | 71.0 | * | SpookyHash | | 64 | 19.3 GB/s | 53.2 | * | Mum | | 64 | 18.0 GB/s | 67.0 | * | CRC32C | SSE4.2 | 32 | 13.0 GB/s | 57.9 | * | XXH32() | | 32 | 9.7 GB/s | 71.9 | * | City32 | | 32 | 9.1 GB/s | 66.0 | * | Blake3* | @b AVX2 | 256 | 4.4 GB/s | 8.1 | * | Murmur3 | | 32 | 3.9 GB/s | 56.1 | * | SipHash* | | 64 | 3.0 GB/s | 43.2 | * | Blake3* | @b SSE2 | 256 | 2.4 GB/s | 8.1 | * | HighwayHash | | 64 | 1.4 GB/s | 6.0 | * | FNV64 | | 64 | 1.2 GB/s | 62.7 | * | Blake2* | | 256 | 1.1 GB/s | 5.1 | * | SHA1* | | 160 | 0.8 GB/s | 5.6 | * | MD5* | | 128 | 0.6 GB/s | 7.8 | * @note * - Hashes which require a specific ISA extension are noted. SSE2 is also noted, * even though it is mandatory on x64. * - Hashes with an asterisk are cryptographic. Note that MD5 is non-cryptographic * by modern standards. * - Small data velocity is a rough average of algorithm's efficiency for small * data. For more accurate information, see the wiki. * - More benchmarks and strength tests are found on the wiki: * https://github.com/Cyan4973/xxHash/wiki * * Usage * ------ * All xxHash variants use a similar API. Changing the algorithm is a trivial * substitution. * * @pre * For functions which take an input and length parameter, the following * requirements are assumed: * - The range from [`input`, `input + length`) is valid, readable memory. * - The only exception is if the `length` is `0`, `input` may be `NULL`. * - For C++, the objects must have the *TriviallyCopyable* property, as the * functions access bytes directly as if it was an array of `unsigned char`. * * @anchor single_shot_example * **Single Shot** * * These functions are stateless functions which hash a contiguous block of memory, * immediately returning the result. They are the easiest and usually the fastest * option. * * XXH32(), XXH64(), XXH3_64bits(), XXH3_128bits() * * @code{.c} * #include * #include "xxhash.h" * * // Example for a function which hashes a null terminated string with XXH32(). * XXH32_hash_t hash_string(const char* string, XXH32_hash_t seed) * { * // NULL pointers are only valid if the length is zero * size_t length = (string == NULL) ? 0 : strlen(string); * return XXH32(string, length, seed); * } * @endcode * * @anchor streaming_example * **Streaming** * * These groups of functions allow incremental hashing of unknown size, even * more than what would fit in a size_t. * * XXH32_reset(), XXH64_reset(), XXH3_64bits_reset(), XXH3_128bits_reset() * * @code{.c} * #include * #include * #include "xxhash.h" * // Example for a function which hashes a FILE incrementally with XXH3_64bits(). * XXH64_hash_t hashFile(FILE* f) * { * // Allocate a state struct. Do not just use malloc() or new. * XXH3_state_t* state = XXH3_createState(); * assert(state != NULL && "Out of memory!"); * // Reset the state to start a new hashing session. * XXH3_64bits_reset(state); * char buffer[4096]; * size_t count; * // Read the file in chunks * while ((count = fread(buffer, 1, sizeof(buffer), f)) != 0) { * // Run update() as many times as necessary to process the data * XXH3_64bits_update(state, buffer, count); * } * // Retrieve the finalized hash. This will not change the state. * XXH64_hash_t result = XXH3_64bits_digest(state); * // Free the state. Do not use free(). * XXH3_freeState(state); * return result; * } * @endcode * * @file xxhash.h * xxHash prototypes and implementation */ #if defined (__cplusplus) extern "C" { #endif /* **************************** * INLINE mode ******************************/ /*! * @defgroup public Public API * Contains details on the public xxHash functions. * @{ */ #ifdef XXH_DOXYGEN /*! * @brief Gives access to internal state declaration, required for static allocation. * * Incompatible with dynamic linking, due to risks of ABI changes. * * Usage: * @code{.c} * #define XXH_STATIC_LINKING_ONLY * #include "xxhash.h" * @endcode */ # define XXH_STATIC_LINKING_ONLY /* Do not undef XXH_STATIC_LINKING_ONLY for Doxygen */ /*! * @brief Gives access to internal definitions. * * Usage: * @code{.c} * #define XXH_STATIC_LINKING_ONLY * #define XXH_IMPLEMENTATION * #include "xxhash.h" * @endcode */ # define XXH_IMPLEMENTATION /* Do not undef XXH_IMPLEMENTATION for Doxygen */ /*! * @brief Exposes the implementation and marks all functions as `inline`. * * Use these build macros to inline xxhash into the target unit. * Inlining improves performance on small inputs, especially when the length is * expressed as a compile-time constant: * * https://fastcompression.blogspot.com/2018/03/xxhash-for-small-keys-impressive-power.html * * It also keeps xxHash symbols private to the unit, so they are not exported. * * Usage: * @code{.c} * #define XXH_INLINE_ALL * #include "xxhash.h" * @endcode * Do not compile and link xxhash.o as a separate object, as it is not useful. */ # define XXH_INLINE_ALL # undef XXH_INLINE_ALL /*! * @brief Exposes the implementation without marking functions as inline. */ # define XXH_PRIVATE_API # undef XXH_PRIVATE_API /*! * @brief Emulate a namespace by transparently prefixing all symbols. * * If you want to include _and expose_ xxHash functions from within your own * library, but also want to avoid symbol collisions with other libraries which * may also include xxHash, you can use @ref XXH_NAMESPACE to automatically prefix * any public symbol from xxhash library with the value of @ref XXH_NAMESPACE * (therefore, avoid empty or numeric values). * * Note that no change is required within the calling program as long as it * includes `xxhash.h`: Regular symbol names will be automatically translated * by this header. */ # define XXH_NAMESPACE /* YOUR NAME HERE */ # undef XXH_NAMESPACE #endif #if (defined(XXH_INLINE_ALL) || defined(XXH_PRIVATE_API)) \ && !defined(XXH_INLINE_ALL_31684351384) /* this section should be traversed only once */ # define XXH_INLINE_ALL_31684351384 /* give access to the advanced API, required to compile implementations */ # undef XXH_STATIC_LINKING_ONLY /* avoid macro redef */ # define XXH_STATIC_LINKING_ONLY /* make all functions private */ # undef XXH_PUBLIC_API # if defined(__GNUC__) # define XXH_PUBLIC_API static __inline __attribute__((unused)) # elif defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) # define XXH_PUBLIC_API static inline # elif defined(_MSC_VER) # define XXH_PUBLIC_API static __inline # else /* note: this version may generate warnings for unused static functions */ # define XXH_PUBLIC_API static # endif /* * This part deals with the special case where a unit wants to inline xxHash, * but "xxhash.h" has previously been included without XXH_INLINE_ALL, * such as part of some previously included *.h header file. * Without further action, the new include would just be ignored, * and functions would effectively _not_ be inlined (silent failure). * The following macros solve this situation by prefixing all inlined names, * avoiding naming collision with previous inclusions. */ /* Before that, we unconditionally #undef all symbols, * in case they were already defined with XXH_NAMESPACE. * They will then be redefined for XXH_INLINE_ALL */ # undef XXH_versionNumber /* XXH32 */ # undef XXH32 # undef XXH32_createState # undef XXH32_freeState # undef XXH32_reset # undef XXH32_update # undef XXH32_digest # undef XXH32_copyState # undef XXH32_canonicalFromHash # undef XXH32_hashFromCanonical /* XXH64 */ # undef XXH64 # undef XXH64_createState # undef XXH64_freeState # undef XXH64_reset # undef XXH64_update # undef XXH64_digest # undef XXH64_copyState # undef XXH64_canonicalFromHash # undef XXH64_hashFromCanonical /* XXH3_64bits */ # undef XXH3_64bits # undef XXH3_64bits_withSecret # undef XXH3_64bits_withSeed # undef XXH3_64bits_withSecretandSeed # undef XXH3_createState # undef XXH3_freeState # undef XXH3_copyState # undef XXH3_64bits_reset # undef XXH3_64bits_reset_withSeed # undef XXH3_64bits_reset_withSecret # undef XXH3_64bits_update # undef XXH3_64bits_digest # undef XXH3_generateSecret /* XXH3_128bits */ # undef XXH128 # undef XXH3_128bits # undef XXH3_128bits_withSeed # undef XXH3_128bits_withSecret # undef XXH3_128bits_reset # undef XXH3_128bits_reset_withSeed # undef XXH3_128bits_reset_withSecret # undef XXH3_128bits_reset_withSecretandSeed # undef XXH3_128bits_update # undef XXH3_128bits_digest # undef XXH128_isEqual # undef XXH128_cmp # undef XXH128_canonicalFromHash # undef XXH128_hashFromCanonical /* Finally, free the namespace itself */ # undef XXH_NAMESPACE /* employ the namespace for XXH_INLINE_ALL */ # define XXH_NAMESPACE XXH_INLINE_ /* * Some identifiers (enums, type names) are not symbols, * but they must nonetheless be renamed to avoid redeclaration. * Alternative solution: do not redeclare them. * However, this requires some #ifdefs, and has a more dispersed impact. * Meanwhile, renaming can be achieved in a single place. */ # define XXH_IPREF(Id) XXH_NAMESPACE ## Id # define XXH_OK XXH_IPREF(XXH_OK) # define XXH_ERROR XXH_IPREF(XXH_ERROR) # define XXH_errorcode XXH_IPREF(XXH_errorcode) # define XXH32_canonical_t XXH_IPREF(XXH32_canonical_t) # define XXH64_canonical_t XXH_IPREF(XXH64_canonical_t) # define XXH128_canonical_t XXH_IPREF(XXH128_canonical_t) # define XXH32_state_s XXH_IPREF(XXH32_state_s) # define XXH32_state_t XXH_IPREF(XXH32_state_t) # define XXH64_state_s XXH_IPREF(XXH64_state_s) # define XXH64_state_t XXH_IPREF(XXH64_state_t) # define XXH3_state_s XXH_IPREF(XXH3_state_s) # define XXH3_state_t XXH_IPREF(XXH3_state_t) # define XXH128_hash_t XXH_IPREF(XXH128_hash_t) /* Ensure the header is parsed again, even if it was previously included */ # undef XXHASH_H_5627135585666179 # undef XXHASH_H_STATIC_13879238742 #endif /* XXH_INLINE_ALL || XXH_PRIVATE_API */ /* **************************************************************** * Stable API *****************************************************************/ #ifndef XXHASH_H_5627135585666179 #define XXHASH_H_5627135585666179 1 /*! @brief Marks a global symbol. */ #if !defined(XXH_INLINE_ALL) && !defined(XXH_PRIVATE_API) # if defined(WIN32) && defined(_MSC_VER) && (defined(XXH_IMPORT) || defined(XXH_EXPORT)) # ifdef XXH_EXPORT # define XXH_PUBLIC_API __declspec(dllexport) # elif XXH_IMPORT # define XXH_PUBLIC_API __declspec(dllimport) # endif # else # define XXH_PUBLIC_API /* do nothing */ # endif #endif #ifdef XXH_NAMESPACE # define XXH_CAT(A,B) A##B # define XXH_NAME2(A,B) XXH_CAT(A,B) # define XXH_versionNumber XXH_NAME2(XXH_NAMESPACE, XXH_versionNumber) /* XXH32 */ # define XXH32 XXH_NAME2(XXH_NAMESPACE, XXH32) # define XXH32_createState XXH_NAME2(XXH_NAMESPACE, XXH32_createState) # define XXH32_freeState XXH_NAME2(XXH_NAMESPACE, XXH32_freeState) # define XXH32_reset XXH_NAME2(XXH_NAMESPACE, XXH32_reset) # define XXH32_update XXH_NAME2(XXH_NAMESPACE, XXH32_update) # define XXH32_digest XXH_NAME2(XXH_NAMESPACE, XXH32_digest) # define XXH32_copyState XXH_NAME2(XXH_NAMESPACE, XXH32_copyState) # define XXH32_canonicalFromHash XXH_NAME2(XXH_NAMESPACE, XXH32_canonicalFromHash) # define XXH32_hashFromCanonical XXH_NAME2(XXH_NAMESPACE, XXH32_hashFromCanonical) /* XXH64 */ # define XXH64 XXH_NAME2(XXH_NAMESPACE, XXH64) # define XXH64_createState XXH_NAME2(XXH_NAMESPACE, XXH64_createState) # define XXH64_freeState XXH_NAME2(XXH_NAMESPACE, XXH64_freeState) # define XXH64_reset XXH_NAME2(XXH_NAMESPACE, XXH64_reset) # define XXH64_update XXH_NAME2(XXH_NAMESPACE, XXH64_update) # define XXH64_digest XXH_NAME2(XXH_NAMESPACE, XXH64_digest) # define XXH64_copyState XXH_NAME2(XXH_NAMESPACE, XXH64_copyState) # define XXH64_canonicalFromHash XXH_NAME2(XXH_NAMESPACE, XXH64_canonicalFromHash) # define XXH64_hashFromCanonical XXH_NAME2(XXH_NAMESPACE, XXH64_hashFromCanonical) /* XXH3_64bits */ # define XXH3_64bits XXH_NAME2(XXH_NAMESPACE, XXH3_64bits) # define XXH3_64bits_withSecret XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_withSecret) # define XXH3_64bits_withSeed XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_withSeed) # define XXH3_64bits_withSecretandSeed XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_withSecretandSeed) # define XXH3_createState XXH_NAME2(XXH_NAMESPACE, XXH3_createState) # define XXH3_freeState XXH_NAME2(XXH_NAMESPACE, XXH3_freeState) # define XXH3_copyState XXH_NAME2(XXH_NAMESPACE, XXH3_copyState) # define XXH3_64bits_reset XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_reset) # define XXH3_64bits_reset_withSeed XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_reset_withSeed) # define XXH3_64bits_reset_withSecret XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_reset_withSecret) # define XXH3_64bits_reset_withSecretandSeed XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_reset_withSecretandSeed) # define XXH3_64bits_update XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_update) # define XXH3_64bits_digest XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_digest) # define XXH3_generateSecret XXH_NAME2(XXH_NAMESPACE, XXH3_generateSecret) # define XXH3_generateSecret_fromSeed XXH_NAME2(XXH_NAMESPACE, XXH3_generateSecret_fromSeed) /* XXH3_128bits */ # define XXH128 XXH_NAME2(XXH_NAMESPACE, XXH128) # define XXH3_128bits XXH_NAME2(XXH_NAMESPACE, XXH3_128bits) # define XXH3_128bits_withSeed XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_withSeed) # define XXH3_128bits_withSecret XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_withSecret) # define XXH3_128bits_withSecretandSeed XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_withSecretandSeed) # define XXH3_128bits_reset XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_reset) # define XXH3_128bits_reset_withSeed XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_reset_withSeed) # define XXH3_128bits_reset_withSecret XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_reset_withSecret) # define XXH3_128bits_reset_withSecretandSeed XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_reset_withSecretandSeed) # define XXH3_128bits_update XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_update) # define XXH3_128bits_digest XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_digest) # define XXH128_isEqual XXH_NAME2(XXH_NAMESPACE, XXH128_isEqual) # define XXH128_cmp XXH_NAME2(XXH_NAMESPACE, XXH128_cmp) # define XXH128_canonicalFromHash XXH_NAME2(XXH_NAMESPACE, XXH128_canonicalFromHash) # define XXH128_hashFromCanonical XXH_NAME2(XXH_NAMESPACE, XXH128_hashFromCanonical) #endif /* ************************************* * Compiler specifics ***************************************/ /* specific declaration modes for Windows */ #if !defined(XXH_INLINE_ALL) && !defined(XXH_PRIVATE_API) # if defined(WIN32) && defined(_MSC_VER) && (defined(XXH_IMPORT) || defined(XXH_EXPORT)) # ifdef XXH_EXPORT # define XXH_PUBLIC_API __declspec(dllexport) # elif XXH_IMPORT # define XXH_PUBLIC_API __declspec(dllimport) # endif # else # define XXH_PUBLIC_API /* do nothing */ # endif #endif #if defined (__GNUC__) # define XXH_CONSTF __attribute__((const)) # define XXH_PUREF __attribute__((pure)) # define XXH_MALLOCF __attribute__((malloc)) #else # define XXH_CONSTF /* disable */ # define XXH_PUREF # define XXH_MALLOCF #endif /* ************************************* * Version ***************************************/ #define XXH_VERSION_MAJOR 0 #define XXH_VERSION_MINOR 8 #define XXH_VERSION_RELEASE 2 /*! @brief Version number, encoded as two digits each */ #define XXH_VERSION_NUMBER (XXH_VERSION_MAJOR *100*100 + XXH_VERSION_MINOR *100 + XXH_VERSION_RELEASE) /*! * @brief Obtains the xxHash version. * * This is mostly useful when xxHash is compiled as a shared library, * since the returned value comes from the library, as opposed to header file. * * @return @ref XXH_VERSION_NUMBER of the invoked library. */ XXH_PUBLIC_API XXH_CONSTF unsigned XXH_versionNumber (void); /* **************************** * Common basic types ******************************/ #include /* size_t */ /*! * @brief Exit code for the streaming API. */ typedef enum { XXH_OK = 0, /*!< OK */ XXH_ERROR /*!< Error */ } XXH_errorcode; /*-********************************************************************** * 32-bit hash ************************************************************************/ #if defined(XXH_DOXYGEN) /* Don't show include */ /*! * @brief An unsigned 32-bit integer. * * Not necessarily defined to `uint32_t` but functionally equivalent. */ typedef uint32_t XXH32_hash_t; #elif !defined (__VMS) \ && (defined (__cplusplus) \ || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) ) # include typedef uint32_t XXH32_hash_t; #else # include # if UINT_MAX == 0xFFFFFFFFUL typedef unsigned int XXH32_hash_t; # elif ULONG_MAX == 0xFFFFFFFFUL typedef unsigned long XXH32_hash_t; # else # error "unsupported platform: need a 32-bit type" # endif #endif /*! * @} * * @defgroup XXH32_family XXH32 family * @ingroup public * Contains functions used in the classic 32-bit xxHash algorithm. * * @note * XXH32 is useful for older platforms, with no or poor 64-bit performance. * Note that the @ref XXH3_family provides competitive speed for both 32-bit * and 64-bit systems, and offers true 64/128 bit hash results. * * @see @ref XXH64_family, @ref XXH3_family : Other xxHash families * @see @ref XXH32_impl for implementation details * @{ */ /*! * @brief Calculates the 32-bit hash of @p input using xxHash32. * * Speed on Core 2 Duo @ 3 GHz (single thread, SMHasher benchmark): 5.4 GB/s * * See @ref single_shot_example "Single Shot Example" for an example. * * @param input The block of data to be hashed, at least @p length bytes in size. * @param length The length of @p input, in bytes. * @param seed The 32-bit seed to alter the hash's output predictably. * * @pre * The memory between @p input and @p input + @p length must be valid, * readable, contiguous memory. However, if @p length is `0`, @p input may be * `NULL`. In C++, this also must be *TriviallyCopyable*. * * @return The calculated 32-bit hash value. * * @see * XXH64(), XXH3_64bits_withSeed(), XXH3_128bits_withSeed(), XXH128(): * Direct equivalents for the other variants of xxHash. * @see * XXH32_createState(), XXH32_update(), XXH32_digest(): Streaming version. */ XXH_PUBLIC_API XXH_PUREF XXH32_hash_t XXH32 (const void* input, size_t length, XXH32_hash_t seed); #ifndef XXH_NO_STREAM /*! * Streaming functions generate the xxHash value from an incremental input. * This method is slower than single-call functions, due to state management. * For small inputs, prefer `XXH32()` and `XXH64()`, which are better optimized. * * An XXH state must first be allocated using `XXH*_createState()`. * * Start a new hash by initializing the state with a seed using `XXH*_reset()`. * * Then, feed the hash state by calling `XXH*_update()` as many times as necessary. * * The function returns an error code, with 0 meaning OK, and any other value * meaning there is an error. * * Finally, a hash value can be produced anytime, by using `XXH*_digest()`. * This function returns the nn-bits hash as an int or long long. * * It's still possible to continue inserting input into the hash state after a * digest, and generate new hash values later on by invoking `XXH*_digest()`. * * When done, release the state using `XXH*_freeState()`. * * @see streaming_example at the top of @ref xxhash.h for an example. */ /*! * @typedef struct XXH32_state_s XXH32_state_t * @brief The opaque state struct for the XXH32 streaming API. * * @see XXH32_state_s for details. */ typedef struct XXH32_state_s XXH32_state_t; /*! * @brief Allocates an @ref XXH32_state_t. * * Must be freed with XXH32_freeState(). * @return An allocated XXH32_state_t on success, `NULL` on failure. */ XXH_PUBLIC_API XXH_MALLOCF XXH32_state_t* XXH32_createState(void); /*! * @brief Frees an @ref XXH32_state_t. * * Must be allocated with XXH32_createState(). * @param statePtr A pointer to an @ref XXH32_state_t allocated with @ref XXH32_createState(). * @return XXH_OK. */ XXH_PUBLIC_API XXH_errorcode XXH32_freeState(XXH32_state_t* statePtr); /*! * @brief Copies one @ref XXH32_state_t to another. * * @param dst_state The state to copy to. * @param src_state The state to copy from. * @pre * @p dst_state and @p src_state must not be `NULL` and must not overlap. */ XXH_PUBLIC_API void XXH32_copyState(XXH32_state_t* dst_state, const XXH32_state_t* src_state); /*! * @brief Resets an @ref XXH32_state_t to begin a new hash. * * This function resets and seeds a state. Call it before @ref XXH32_update(). * * @param statePtr The state struct to reset. * @param seed The 32-bit seed to alter the hash result predictably. * * @pre * @p statePtr must not be `NULL`. * * @return @ref XXH_OK on success, @ref XXH_ERROR on failure. */ XXH_PUBLIC_API XXH_errorcode XXH32_reset (XXH32_state_t* statePtr, XXH32_hash_t seed); /*! * @brief Consumes a block of @p input to an @ref XXH32_state_t. * * Call this to incrementally consume blocks of data. * * @param statePtr The state struct to update. * @param input The block of data to be hashed, at least @p length bytes in size. * @param length The length of @p input, in bytes. * * @pre * @p statePtr must not be `NULL`. * @pre * The memory between @p input and @p input + @p length must be valid, * readable, contiguous memory. However, if @p length is `0`, @p input may be * `NULL`. In C++, this also must be *TriviallyCopyable*. * * @return @ref XXH_OK on success, @ref XXH_ERROR on failure. */ XXH_PUBLIC_API XXH_errorcode XXH32_update (XXH32_state_t* statePtr, const void* input, size_t length); /*! * @brief Returns the calculated hash value from an @ref XXH32_state_t. * * @note * Calling XXH32_digest() will not affect @p statePtr, so you can update, * digest, and update again. * * @param statePtr The state struct to calculate the hash from. * * @pre * @p statePtr must not be `NULL`. * * @return The calculated xxHash32 value from that state. */ XXH_PUBLIC_API XXH_PUREF XXH32_hash_t XXH32_digest (const XXH32_state_t* statePtr); #endif /* !XXH_NO_STREAM */ /******* Canonical representation *******/ /* * The default return values from XXH functions are unsigned 32 and 64 bit * integers. * This the simplest and fastest format for further post-processing. * * However, this leaves open the question of what is the order on the byte level, * since little and big endian conventions will store the same number differently. * * The canonical representation settles this issue by mandating big-endian * convention, the same convention as human-readable numbers (large digits first). * * When writing hash values to storage, sending them over a network, or printing * them, it's highly recommended to use the canonical representation to ensure * portability across a wider range of systems, present and future. * * The following functions allow transformation of hash values to and from * canonical format. */ /*! * @brief Canonical (big endian) representation of @ref XXH32_hash_t. */ typedef struct { unsigned char digest[4]; /*!< Hash bytes, big endian */ } XXH32_canonical_t; /*! * @brief Converts an @ref XXH32_hash_t to a big endian @ref XXH32_canonical_t. * * @param dst The @ref XXH32_canonical_t pointer to be stored to. * @param hash The @ref XXH32_hash_t to be converted. * * @pre * @p dst must not be `NULL`. */ XXH_PUBLIC_API void XXH32_canonicalFromHash(XXH32_canonical_t* dst, XXH32_hash_t hash); /*! * @brief Converts an @ref XXH32_canonical_t to a native @ref XXH32_hash_t. * * @param src The @ref XXH32_canonical_t to convert. * * @pre * @p src must not be `NULL`. * * @return The converted hash. */ XXH_PUBLIC_API XXH_PUREF XXH32_hash_t XXH32_hashFromCanonical(const XXH32_canonical_t* src); /*! @cond Doxygen ignores this part */ #ifdef __has_attribute # define XXH_HAS_ATTRIBUTE(x) __has_attribute(x) #else # define XXH_HAS_ATTRIBUTE(x) 0 #endif /*! @endcond */ /*! @cond Doxygen ignores this part */ /* * C23 __STDC_VERSION__ number hasn't been specified yet. For now * leave as `201711L` (C17 + 1). * TODO: Update to correct value when its been specified. */ #define XXH_C23_VN 201711L /*! @endcond */ /*! @cond Doxygen ignores this part */ /* C-language Attributes are added in C23. */ #if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= XXH_C23_VN) && defined(__has_c_attribute) # define XXH_HAS_C_ATTRIBUTE(x) __has_c_attribute(x) #else # define XXH_HAS_C_ATTRIBUTE(x) 0 #endif /*! @endcond */ /*! @cond Doxygen ignores this part */ #if defined(__cplusplus) && defined(__has_cpp_attribute) # define XXH_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x) #else # define XXH_HAS_CPP_ATTRIBUTE(x) 0 #endif /*! @endcond */ /*! @cond Doxygen ignores this part */ /* * Define XXH_FALLTHROUGH macro for annotating switch case with the 'fallthrough' attribute * introduced in CPP17 and C23. * CPP17 : https://en.cppreference.com/w/cpp/language/attributes/fallthrough * C23 : https://en.cppreference.com/w/c/language/attributes/fallthrough */ #if XXH_HAS_C_ATTRIBUTE(fallthrough) || XXH_HAS_CPP_ATTRIBUTE(fallthrough) # define XXH_FALLTHROUGH [[fallthrough]] #elif XXH_HAS_ATTRIBUTE(__fallthrough__) # define XXH_FALLTHROUGH __attribute__ ((__fallthrough__)) #else # define XXH_FALLTHROUGH /* fallthrough */ #endif /*! @endcond */ /*! @cond Doxygen ignores this part */ /* * Define XXH_NOESCAPE for annotated pointers in public API. * https://clang.llvm.org/docs/AttributeReference.html#noescape * As of writing this, only supported by clang. */ #if XXH_HAS_ATTRIBUTE(noescape) # define XXH_NOESCAPE __attribute__((noescape)) #else # define XXH_NOESCAPE #endif /*! @endcond */ /*! * @} * @ingroup public * @{ */ #ifndef XXH_NO_LONG_LONG /*-********************************************************************** * 64-bit hash ************************************************************************/ #if defined(XXH_DOXYGEN) /* don't include */ /*! * @brief An unsigned 64-bit integer. * * Not necessarily defined to `uint64_t` but functionally equivalent. */ typedef uint64_t XXH64_hash_t; #elif !defined (__VMS) \ && (defined (__cplusplus) \ || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) ) # include typedef uint64_t XXH64_hash_t; #else # include # if defined(__LP64__) && ULONG_MAX == 0xFFFFFFFFFFFFFFFFULL /* LP64 ABI says uint64_t is unsigned long */ typedef unsigned long XXH64_hash_t; # else /* the following type must have a width of 64-bit */ typedef unsigned long long XXH64_hash_t; # endif #endif /*! * @} * * @defgroup XXH64_family XXH64 family * @ingroup public * @{ * Contains functions used in the classic 64-bit xxHash algorithm. * * @note * XXH3 provides competitive speed for both 32-bit and 64-bit systems, * and offers true 64/128 bit hash results. * It provides better speed for systems with vector processing capabilities. */ /*! * @brief Calculates the 64-bit hash of @p input using xxHash64. * * This function usually runs faster on 64-bit systems, but slower on 32-bit * systems (see benchmark). * * @param input The block of data to be hashed, at least @p length bytes in size. * @param length The length of @p input, in bytes. * @param seed The 64-bit seed to alter the hash's output predictably. * * @pre * The memory between @p input and @p input + @p length must be valid, * readable, contiguous memory. However, if @p length is `0`, @p input may be * `NULL`. In C++, this also must be *TriviallyCopyable*. * * @return The calculated 64-bit hash. * * @see * XXH32(), XXH3_64bits_withSeed(), XXH3_128bits_withSeed(), XXH128(): * Direct equivalents for the other variants of xxHash. * @see * XXH64_createState(), XXH64_update(), XXH64_digest(): Streaming version. */ XXH_PUBLIC_API XXH_PUREF XXH64_hash_t XXH64(XXH_NOESCAPE const void* input, size_t length, XXH64_hash_t seed); /******* Streaming *******/ #ifndef XXH_NO_STREAM /*! * @brief The opaque state struct for the XXH64 streaming API. * * @see XXH64_state_s for details. */ typedef struct XXH64_state_s XXH64_state_t; /* incomplete type */ /*! * @brief Allocates an @ref XXH64_state_t. * * Must be freed with XXH64_freeState(). * @return An allocated XXH64_state_t on success, `NULL` on failure. */ XXH_PUBLIC_API XXH_MALLOCF XXH64_state_t* XXH64_createState(void); /*! * @brief Frees an @ref XXH64_state_t. * * Must be allocated with XXH64_createState(). * @param statePtr A pointer to an @ref XXH64_state_t allocated with @ref XXH64_createState(). * @return XXH_OK. */ XXH_PUBLIC_API XXH_errorcode XXH64_freeState(XXH64_state_t* statePtr); /*! * @brief Copies one @ref XXH64_state_t to another. * * @param dst_state The state to copy to. * @param src_state The state to copy from. * @pre * @p dst_state and @p src_state must not be `NULL` and must not overlap. */ XXH_PUBLIC_API void XXH64_copyState(XXH_NOESCAPE XXH64_state_t* dst_state, const XXH64_state_t* src_state); /*! * @brief Resets an @ref XXH64_state_t to begin a new hash. * * This function resets and seeds a state. Call it before @ref XXH64_update(). * * @param statePtr The state struct to reset. * @param seed The 64-bit seed to alter the hash result predictably. * * @pre * @p statePtr must not be `NULL`. * * @return @ref XXH_OK on success, @ref XXH_ERROR on failure. */ XXH_PUBLIC_API XXH_errorcode XXH64_reset (XXH_NOESCAPE XXH64_state_t* statePtr, XXH64_hash_t seed); /*! * @brief Consumes a block of @p input to an @ref XXH64_state_t. * * Call this to incrementally consume blocks of data. * * @param statePtr The state struct to update. * @param input The block of data to be hashed, at least @p length bytes in size. * @param length The length of @p input, in bytes. * * @pre * @p statePtr must not be `NULL`. * @pre * The memory between @p input and @p input + @p length must be valid, * readable, contiguous memory. However, if @p length is `0`, @p input may be * `NULL`. In C++, this also must be *TriviallyCopyable*. * * @return @ref XXH_OK on success, @ref XXH_ERROR on failure. */ XXH_PUBLIC_API XXH_errorcode XXH64_update (XXH_NOESCAPE XXH64_state_t* statePtr, XXH_NOESCAPE const void* input, size_t length); /*! * @brief Returns the calculated hash value from an @ref XXH64_state_t. * * @note * Calling XXH64_digest() will not affect @p statePtr, so you can update, * digest, and update again. * * @param statePtr The state struct to calculate the hash from. * * @pre * @p statePtr must not be `NULL`. * * @return The calculated xxHash64 value from that state. */ XXH_PUBLIC_API XXH_PUREF XXH64_hash_t XXH64_digest (XXH_NOESCAPE const XXH64_state_t* statePtr); #endif /* !XXH_NO_STREAM */ /******* Canonical representation *******/ /*! * @brief Canonical (big endian) representation of @ref XXH64_hash_t. */ typedef struct { unsigned char digest[sizeof(XXH64_hash_t)]; } XXH64_canonical_t; /*! * @brief Converts an @ref XXH64_hash_t to a big endian @ref XXH64_canonical_t. * * @param dst The @ref XXH64_canonical_t pointer to be stored to. * @param hash The @ref XXH64_hash_t to be converted. * * @pre * @p dst must not be `NULL`. */ XXH_PUBLIC_API void XXH64_canonicalFromHash(XXH_NOESCAPE XXH64_canonical_t* dst, XXH64_hash_t hash); /*! * @brief Converts an @ref XXH64_canonical_t to a native @ref XXH64_hash_t. * * @param src The @ref XXH64_canonical_t to convert. * * @pre * @p src must not be `NULL`. * * @return The converted hash. */ XXH_PUBLIC_API XXH_PUREF XXH64_hash_t XXH64_hashFromCanonical(XXH_NOESCAPE const XXH64_canonical_t* src); #ifndef XXH_NO_XXH3 /*! * @} * ************************************************************************ * @defgroup XXH3_family XXH3 family * @ingroup public * @{ * * XXH3 is a more recent hash algorithm featuring: * - Improved speed for both small and large inputs * - True 64-bit and 128-bit outputs * - SIMD acceleration * - Improved 32-bit viability * * Speed analysis methodology is explained here: * * https://fastcompression.blogspot.com/2019/03/presenting-xxh3.html * * Compared to XXH64, expect XXH3 to run approximately * ~2x faster on large inputs and >3x faster on small ones, * exact differences vary depending on platform. * * XXH3's speed benefits greatly from SIMD and 64-bit arithmetic, * but does not require it. * Most 32-bit and 64-bit targets that can run XXH32 smoothly can run XXH3 * at competitive speeds, even without vector support. Further details are * explained in the implementation. * * XXH3 has a fast scalar implementation, but it also includes accelerated SIMD * implementations for many common platforms: * - AVX512 * - AVX2 * - SSE2 * - ARM NEON * - WebAssembly SIMD128 * - POWER8 VSX * - s390x ZVector * This can be controlled via the @ref XXH_VECTOR macro, but it automatically * selects the best version according to predefined macros. For the x86 family, an * automatic runtime dispatcher is included separately in @ref xxh_x86dispatch.c. * * XXH3 implementation is portable: * it has a generic C90 formulation that can be compiled on any platform, * all implementations generate exactly the same hash value on all platforms. * Starting from v0.8.0, it's also labelled "stable", meaning that * any future version will also generate the same hash value. * * XXH3 offers 2 variants, _64bits and _128bits. * * When only 64 bits are needed, prefer invoking the _64bits variant, as it * reduces the amount of mixing, resulting in faster speed on small inputs. * It's also generally simpler to manipulate a scalar return type than a struct. * * The API supports one-shot hashing, streaming mode, and custom secrets. */ /*-********************************************************************** * XXH3 64-bit variant ************************************************************************/ /*! * @brief 64-bit unseeded variant of XXH3. * * This is equivalent to @ref XXH3_64bits_withSeed() with a seed of 0, however * it may have slightly better performance due to constant propagation of the * defaults. * * @see * XXH32(), XXH64(), XXH3_128bits(): equivalent for the other xxHash algorithms * @see * XXH3_64bits_withSeed(), XXH3_64bits_withSecret(): other seeding variants * @see * XXH3_64bits_reset(), XXH3_64bits_update(), XXH3_64bits_digest(): Streaming version. */ XXH_PUBLIC_API XXH_PUREF XXH64_hash_t XXH3_64bits(XXH_NOESCAPE const void* input, size_t length); /*! * @brief 64-bit seeded variant of XXH3 * * This variant generates a custom secret on the fly based on default secret * altered using the `seed` value. * * While this operation is decently fast, note that it's not completely free. * * @note * seed == 0 produces the same results as @ref XXH3_64bits(). * * @param input The data to hash * @param length The length * @param seed The 64-bit seed to alter the state. */ XXH_PUBLIC_API XXH_PUREF XXH64_hash_t XXH3_64bits_withSeed(XXH_NOESCAPE const void* input, size_t length, XXH64_hash_t seed); /*! * The bare minimum size for a custom secret. * * @see * XXH3_64bits_withSecret(), XXH3_64bits_reset_withSecret(), * XXH3_128bits_withSecret(), XXH3_128bits_reset_withSecret(). */ #define XXH3_SECRET_SIZE_MIN 136 /*! * @brief 64-bit variant of XXH3 with a custom "secret". * * It's possible to provide any blob of bytes as a "secret" to generate the hash. * This makes it more difficult for an external actor to prepare an intentional collision. * The main condition is that secretSize *must* be large enough (>= XXH3_SECRET_SIZE_MIN). * However, the quality of the secret impacts the dispersion of the hash algorithm. * Therefore, the secret _must_ look like a bunch of random bytes. * Avoid "trivial" or structured data such as repeated sequences or a text document. * Whenever in doubt about the "randomness" of the blob of bytes, * consider employing "XXH3_generateSecret()" instead (see below). * It will generate a proper high entropy secret derived from the blob of bytes. * Another advantage of using XXH3_generateSecret() is that * it guarantees that all bits within the initial blob of bytes * will impact every bit of the output. * This is not necessarily the case when using the blob of bytes directly * because, when hashing _small_ inputs, only a portion of the secret is employed. */ XXH_PUBLIC_API XXH_PUREF XXH64_hash_t XXH3_64bits_withSecret(XXH_NOESCAPE const void* data, size_t len, XXH_NOESCAPE const void* secret, size_t secretSize); /******* Streaming *******/ #ifndef XXH_NO_STREAM /* * Streaming requires state maintenance. * This operation costs memory and CPU. * As a consequence, streaming is slower than one-shot hashing. * For better performance, prefer one-shot functions whenever applicable. */ /*! * @brief The state struct for the XXH3 streaming API. * * @see XXH3_state_s for details. */ typedef struct XXH3_state_s XXH3_state_t; XXH_PUBLIC_API XXH_MALLOCF XXH3_state_t* XXH3_createState(void); XXH_PUBLIC_API XXH_errorcode XXH3_freeState(XXH3_state_t* statePtr); /*! * @brief Copies one @ref XXH3_state_t to another. * * @param dst_state The state to copy to. * @param src_state The state to copy from. * @pre * @p dst_state and @p src_state must not be `NULL` and must not overlap. */ XXH_PUBLIC_API void XXH3_copyState(XXH_NOESCAPE XXH3_state_t* dst_state, XXH_NOESCAPE const XXH3_state_t* src_state); /*! * @brief Resets an @ref XXH3_state_t to begin a new hash. * * This function resets `statePtr` and generate a secret with default parameters. Call it before @ref XXH3_64bits_update(). * Digest will be equivalent to `XXH3_64bits()`. * * @param statePtr The state struct to reset. * * @pre * @p statePtr must not be `NULL`. * * @return @ref XXH_OK on success, @ref XXH_ERROR on failure. * */ XXH_PUBLIC_API XXH_errorcode XXH3_64bits_reset(XXH_NOESCAPE XXH3_state_t* statePtr); /*! * @brief Resets an @ref XXH3_state_t with 64-bit seed to begin a new hash. * * This function resets `statePtr` and generate a secret from `seed`. Call it before @ref XXH3_64bits_update(). * Digest will be equivalent to `XXH3_64bits_withSeed()`. * * @param statePtr The state struct to reset. * @param seed The 64-bit seed to alter the state. * * @pre * @p statePtr must not be `NULL`. * * @return @ref XXH_OK on success, @ref XXH_ERROR on failure. * */ XXH_PUBLIC_API XXH_errorcode XXH3_64bits_reset_withSeed(XXH_NOESCAPE XXH3_state_t* statePtr, XXH64_hash_t seed); /*! * XXH3_64bits_reset_withSecret(): * `secret` is referenced, it _must outlive_ the hash streaming session. * Similar to one-shot API, `secretSize` must be >= `XXH3_SECRET_SIZE_MIN`, * and the quality of produced hash values depends on secret's entropy * (secret's content should look like a bunch of random bytes). * When in doubt about the randomness of a candidate `secret`, * consider employing `XXH3_generateSecret()` instead (see below). */ XXH_PUBLIC_API XXH_errorcode XXH3_64bits_reset_withSecret(XXH_NOESCAPE XXH3_state_t* statePtr, XXH_NOESCAPE const void* secret, size_t secretSize); /*! * @brief Consumes a block of @p input to an @ref XXH3_state_t. * * Call this to incrementally consume blocks of data. * * @param statePtr The state struct to update. * @param input The block of data to be hashed, at least @p length bytes in size. * @param length The length of @p input, in bytes. * * @pre * @p statePtr must not be `NULL`. * @pre * The memory between @p input and @p input + @p length must be valid, * readable, contiguous memory. However, if @p length is `0`, @p input may be * `NULL`. In C++, this also must be *TriviallyCopyable*. * * @return @ref XXH_OK on success, @ref XXH_ERROR on failure. */ XXH_PUBLIC_API XXH_errorcode XXH3_64bits_update (XXH_NOESCAPE XXH3_state_t* statePtr, XXH_NOESCAPE const void* input, size_t length); /*! * @brief Returns the calculated XXH3 64-bit hash value from an @ref XXH3_state_t. * * @note * Calling XXH3_64bits_digest() will not affect @p statePtr, so you can update, * digest, and update again. * * @param statePtr The state struct to calculate the hash from. * * @pre * @p statePtr must not be `NULL`. * * @return The calculated XXH3 64-bit hash value from that state. */ XXH_PUBLIC_API XXH_PUREF XXH64_hash_t XXH3_64bits_digest (XXH_NOESCAPE const XXH3_state_t* statePtr); #endif /* !XXH_NO_STREAM */ /* note : canonical representation of XXH3 is the same as XXH64 * since they both produce XXH64_hash_t values */ /*-********************************************************************** * XXH3 128-bit variant ************************************************************************/ /*! * @brief The return value from 128-bit hashes. * * Stored in little endian order, although the fields themselves are in native * endianness. */ typedef struct { XXH64_hash_t low64; /*!< `value & 0xFFFFFFFFFFFFFFFF` */ XXH64_hash_t high64; /*!< `value >> 64` */ } XXH128_hash_t; /*! * @brief Unseeded 128-bit variant of XXH3 * * The 128-bit variant of XXH3 has more strength, but it has a bit of overhead * for shorter inputs. * * This is equivalent to @ref XXH3_128bits_withSeed() with a seed of 0, however * it may have slightly better performance due to constant propagation of the * defaults. * * @see * XXH32(), XXH64(), XXH3_64bits(): equivalent for the other xxHash algorithms * @see * XXH3_128bits_withSeed(), XXH3_128bits_withSecret(): other seeding variants * @see * XXH3_128bits_reset(), XXH3_128bits_update(), XXH3_128bits_digest(): Streaming version. */ XXH_PUBLIC_API XXH_PUREF XXH128_hash_t XXH3_128bits(XXH_NOESCAPE const void* data, size_t len); /*! @brief Seeded 128-bit variant of XXH3. @see XXH3_64bits_withSeed(). */ XXH_PUBLIC_API XXH_PUREF XXH128_hash_t XXH3_128bits_withSeed(XXH_NOESCAPE const void* data, size_t len, XXH64_hash_t seed); /*! @brief Custom secret 128-bit variant of XXH3. @see XXH3_64bits_withSecret(). */ XXH_PUBLIC_API XXH_PUREF XXH128_hash_t XXH3_128bits_withSecret(XXH_NOESCAPE const void* data, size_t len, XXH_NOESCAPE const void* secret, size_t secretSize); /******* Streaming *******/ #ifndef XXH_NO_STREAM /* * Streaming requires state maintenance. * This operation costs memory and CPU. * As a consequence, streaming is slower than one-shot hashing. * For better performance, prefer one-shot functions whenever applicable. * * XXH3_128bits uses the same XXH3_state_t as XXH3_64bits(). * Use already declared XXH3_createState() and XXH3_freeState(). * * All reset and streaming functions have same meaning as their 64-bit counterpart. */ /*! * @brief Resets an @ref XXH3_state_t to begin a new hash. * * This function resets `statePtr` and generate a secret with default parameters. Call it before @ref XXH3_128bits_update(). * Digest will be equivalent to `XXH3_128bits()`. * * @param statePtr The state struct to reset. * * @pre * @p statePtr must not be `NULL`. * * @return @ref XXH_OK on success, @ref XXH_ERROR on failure. * */ XXH_PUBLIC_API XXH_errorcode XXH3_128bits_reset(XXH_NOESCAPE XXH3_state_t* statePtr); /*! * @brief Resets an @ref XXH3_state_t with 64-bit seed to begin a new hash. * * This function resets `statePtr` and generate a secret from `seed`. Call it before @ref XXH3_128bits_update(). * Digest will be equivalent to `XXH3_128bits_withSeed()`. * * @param statePtr The state struct to reset. * @param seed The 64-bit seed to alter the state. * * @pre * @p statePtr must not be `NULL`. * * @return @ref XXH_OK on success, @ref XXH_ERROR on failure. * */ XXH_PUBLIC_API XXH_errorcode XXH3_128bits_reset_withSeed(XXH_NOESCAPE XXH3_state_t* statePtr, XXH64_hash_t seed); /*! @brief Custom secret 128-bit variant of XXH3. @see XXH_64bits_reset_withSecret(). */ XXH_PUBLIC_API XXH_errorcode XXH3_128bits_reset_withSecret(XXH_NOESCAPE XXH3_state_t* statePtr, XXH_NOESCAPE const void* secret, size_t secretSize); /*! * @brief Consumes a block of @p input to an @ref XXH3_state_t. * * Call this to incrementally consume blocks of data. * * @param statePtr The state struct to update. * @param input The block of data to be hashed, at least @p length bytes in size. * @param length The length of @p input, in bytes. * * @pre * @p statePtr must not be `NULL`. * @pre * The memory between @p input and @p input + @p length must be valid, * readable, contiguous memory. However, if @p length is `0`, @p input may be * `NULL`. In C++, this also must be *TriviallyCopyable*. * * @return @ref XXH_OK on success, @ref XXH_ERROR on failure. */ XXH_PUBLIC_API XXH_errorcode XXH3_128bits_update (XXH_NOESCAPE XXH3_state_t* statePtr, XXH_NOESCAPE const void* input, size_t length); /*! * @brief Returns the calculated XXH3 128-bit hash value from an @ref XXH3_state_t. * * @note * Calling XXH3_128bits_digest() will not affect @p statePtr, so you can update, * digest, and update again. * * @param statePtr The state struct to calculate the hash from. * * @pre * @p statePtr must not be `NULL`. * * @return The calculated XXH3 128-bit hash value from that state. */ XXH_PUBLIC_API XXH_PUREF XXH128_hash_t XXH3_128bits_digest (XXH_NOESCAPE const XXH3_state_t* statePtr); #endif /* !XXH_NO_STREAM */ /* Following helper functions make it possible to compare XXH128_hast_t values. * Since XXH128_hash_t is a structure, this capability is not offered by the language. * Note: For better performance, these functions can be inlined using XXH_INLINE_ALL */ /*! * XXH128_isEqual(): * Return: 1 if `h1` and `h2` are equal, 0 if they are not. */ XXH_PUBLIC_API XXH_PUREF int XXH128_isEqual(XXH128_hash_t h1, XXH128_hash_t h2); /*! * @brief Compares two @ref XXH128_hash_t * This comparator is compatible with stdlib's `qsort()`/`bsearch()`. * * @return: >0 if *h128_1 > *h128_2 * =0 if *h128_1 == *h128_2 * <0 if *h128_1 < *h128_2 */ XXH_PUBLIC_API XXH_PUREF int XXH128_cmp(XXH_NOESCAPE const void* h128_1, XXH_NOESCAPE const void* h128_2); /******* Canonical representation *******/ typedef struct { unsigned char digest[sizeof(XXH128_hash_t)]; } XXH128_canonical_t; /*! * @brief Converts an @ref XXH128_hash_t to a big endian @ref XXH128_canonical_t. * * @param dst The @ref XXH128_canonical_t pointer to be stored to. * @param hash The @ref XXH128_hash_t to be converted. * * @pre * @p dst must not be `NULL`. */ XXH_PUBLIC_API void XXH128_canonicalFromHash(XXH_NOESCAPE XXH128_canonical_t* dst, XXH128_hash_t hash); /*! * @brief Converts an @ref XXH128_canonical_t to a native @ref XXH128_hash_t. * * @param src The @ref XXH128_canonical_t to convert. * * @pre * @p src must not be `NULL`. * * @return The converted hash. */ XXH_PUBLIC_API XXH_PUREF XXH128_hash_t XXH128_hashFromCanonical(XXH_NOESCAPE const XXH128_canonical_t* src); #endif /* !XXH_NO_XXH3 */ #endif /* XXH_NO_LONG_LONG */ /*! * @} */ #endif /* XXHASH_H_5627135585666179 */ #if defined(XXH_STATIC_LINKING_ONLY) && !defined(XXHASH_H_STATIC_13879238742) #define XXHASH_H_STATIC_13879238742 /* **************************************************************************** * This section contains declarations which are not guaranteed to remain stable. * They may change in future versions, becoming incompatible with a different * version of the library. * These declarations should only be used with static linking. * Never use them in association with dynamic linking! ***************************************************************************** */ /* * These definitions are only present to allow static allocation * of XXH states, on stack or in a struct, for example. * Never **ever** access their members directly. */ /*! * @internal * @brief Structure for XXH32 streaming API. * * @note This is only defined when @ref XXH_STATIC_LINKING_ONLY, * @ref XXH_INLINE_ALL, or @ref XXH_IMPLEMENTATION is defined. Otherwise it is * an opaque type. This allows fields to safely be changed. * * Typedef'd to @ref XXH32_state_t. * Do not access the members of this struct directly. * @see XXH64_state_s, XXH3_state_s */ struct XXH32_state_s { XXH32_hash_t total_len_32; /*!< Total length hashed, modulo 2^32 */ XXH32_hash_t large_len; /*!< Whether the hash is >= 16 (handles @ref total_len_32 overflow) */ XXH32_hash_t v[4]; /*!< Accumulator lanes */ XXH32_hash_t mem32[4]; /*!< Internal buffer for partial reads. Treated as unsigned char[16]. */ XXH32_hash_t memsize; /*!< Amount of data in @ref mem32 */ XXH32_hash_t reserved; /*!< Reserved field. Do not read nor write to it. */ }; /* typedef'd to XXH32_state_t */ #ifndef XXH_NO_LONG_LONG /* defined when there is no 64-bit support */ /*! * @internal * @brief Structure for XXH64 streaming API. * * @note This is only defined when @ref XXH_STATIC_LINKING_ONLY, * @ref XXH_INLINE_ALL, or @ref XXH_IMPLEMENTATION is defined. Otherwise it is * an opaque type. This allows fields to safely be changed. * * Typedef'd to @ref XXH64_state_t. * Do not access the members of this struct directly. * @see XXH32_state_s, XXH3_state_s */ struct XXH64_state_s { XXH64_hash_t total_len; /*!< Total length hashed. This is always 64-bit. */ XXH64_hash_t v[4]; /*!< Accumulator lanes */ XXH64_hash_t mem64[4]; /*!< Internal buffer for partial reads. Treated as unsigned char[32]. */ XXH32_hash_t memsize; /*!< Amount of data in @ref mem64 */ XXH32_hash_t reserved32; /*!< Reserved field, needed for padding anyways*/ XXH64_hash_t reserved64; /*!< Reserved field. Do not read or write to it. */ }; /* typedef'd to XXH64_state_t */ #ifndef XXH_NO_XXH3 #if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) /* >= C11 */ # include # define XXH_ALIGN(n) alignas(n) #elif defined(__cplusplus) && (__cplusplus >= 201103L) /* >= C++11 */ /* In C++ alignas() is a keyword */ # define XXH_ALIGN(n) alignas(n) #elif defined(__GNUC__) # define XXH_ALIGN(n) __attribute__ ((aligned(n))) #elif defined(_MSC_VER) # define XXH_ALIGN(n) __declspec(align(n)) #else # define XXH_ALIGN(n) /* disabled */ #endif /* Old GCC versions only accept the attribute after the type in structures. */ #if !(defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)) /* C11+ */ \ && ! (defined(__cplusplus) && (__cplusplus >= 201103L)) /* >= C++11 */ \ && defined(__GNUC__) # define XXH_ALIGN_MEMBER(align, type) type XXH_ALIGN(align) #else # define XXH_ALIGN_MEMBER(align, type) XXH_ALIGN(align) type #endif /*! * @brief The size of the internal XXH3 buffer. * * This is the optimal update size for incremental hashing. * * @see XXH3_64b_update(), XXH3_128b_update(). */ #define XXH3_INTERNALBUFFER_SIZE 256 /*! * @internal * @brief Default size of the secret buffer (and @ref XXH3_kSecret). * * This is the size used in @ref XXH3_kSecret and the seeded functions. * * Not to be confused with @ref XXH3_SECRET_SIZE_MIN. */ #define XXH3_SECRET_DEFAULT_SIZE 192 /*! * @internal * @brief Structure for XXH3 streaming API. * * @note This is only defined when @ref XXH_STATIC_LINKING_ONLY, * @ref XXH_INLINE_ALL, or @ref XXH_IMPLEMENTATION is defined. * Otherwise it is an opaque type. * Never use this definition in combination with dynamic library. * This allows fields to safely be changed in the future. * * @note ** This structure has a strict alignment requirement of 64 bytes!! ** * Do not allocate this with `malloc()` or `new`, * it will not be sufficiently aligned. * Use @ref XXH3_createState() and @ref XXH3_freeState(), or stack allocation. * * Typedef'd to @ref XXH3_state_t. * Do never access the members of this struct directly. * * @see XXH3_INITSTATE() for stack initialization. * @see XXH3_createState(), XXH3_freeState(). * @see XXH32_state_s, XXH64_state_s */ struct XXH3_state_s { XXH_ALIGN_MEMBER(64, XXH64_hash_t acc[8]); /*!< The 8 accumulators. See @ref XXH32_state_s::v and @ref XXH64_state_s::v */ XXH_ALIGN_MEMBER(64, unsigned char customSecret[XXH3_SECRET_DEFAULT_SIZE]); /*!< Used to store a custom secret generated from a seed. */ XXH_ALIGN_MEMBER(64, unsigned char buffer[XXH3_INTERNALBUFFER_SIZE]); /*!< The internal buffer. @see XXH32_state_s::mem32 */ XXH32_hash_t bufferedSize; /*!< The amount of memory in @ref buffer, @see XXH32_state_s::memsize */ XXH32_hash_t useSeed; /*!< Reserved field. Needed for padding on 64-bit. */ size_t nbStripesSoFar; /*!< Number or stripes processed. */ XXH64_hash_t totalLen; /*!< Total length hashed. 64-bit even on 32-bit targets. */ size_t nbStripesPerBlock; /*!< Number of stripes per block. */ size_t secretLimit; /*!< Size of @ref customSecret or @ref extSecret */ XXH64_hash_t seed; /*!< Seed for _withSeed variants. Must be zero otherwise, @see XXH3_INITSTATE() */ XXH64_hash_t reserved64; /*!< Reserved field. */ const unsigned char* extSecret; /*!< Reference to an external secret for the _withSecret variants, NULL * for other variants. */ /* note: there may be some padding at the end due to alignment on 64 bytes */ }; /* typedef'd to XXH3_state_t */ #undef XXH_ALIGN_MEMBER /*! * @brief Initializes a stack-allocated `XXH3_state_s`. * * When the @ref XXH3_state_t structure is merely emplaced on stack, * it should be initialized with XXH3_INITSTATE() or a memset() * in case its first reset uses XXH3_NNbits_reset_withSeed(). * This init can be omitted if the first reset uses default or _withSecret mode. * This operation isn't necessary when the state is created with XXH3_createState(). * Note that this doesn't prepare the state for a streaming operation, * it's still necessary to use XXH3_NNbits_reset*() afterwards. */ #define XXH3_INITSTATE(XXH3_state_ptr) \ do { \ XXH3_state_t* tmp_xxh3_state_ptr = (XXH3_state_ptr); \ tmp_xxh3_state_ptr->seed = 0; \ tmp_xxh3_state_ptr->extSecret = NULL; \ } while(0) /*! * simple alias to pre-selected XXH3_128bits variant */ XXH_PUBLIC_API XXH_PUREF XXH128_hash_t XXH128(XXH_NOESCAPE const void* data, size_t len, XXH64_hash_t seed); /* === Experimental API === */ /* Symbols defined below must be considered tied to a specific library version. */ /*! * XXH3_generateSecret(): * * Derive a high-entropy secret from any user-defined content, named customSeed. * The generated secret can be used in combination with `*_withSecret()` functions. * The `_withSecret()` variants are useful to provide a higher level of protection * than 64-bit seed, as it becomes much more difficult for an external actor to * guess how to impact the calculation logic. * * The function accepts as input a custom seed of any length and any content, * and derives from it a high-entropy secret of length @p secretSize into an * already allocated buffer @p secretBuffer. * * The generated secret can then be used with any `*_withSecret()` variant. * The functions @ref XXH3_128bits_withSecret(), @ref XXH3_64bits_withSecret(), * @ref XXH3_128bits_reset_withSecret() and @ref XXH3_64bits_reset_withSecret() * are part of this list. They all accept a `secret` parameter * which must be large enough for implementation reasons (>= @ref XXH3_SECRET_SIZE_MIN) * _and_ feature very high entropy (consist of random-looking bytes). * These conditions can be a high bar to meet, so @ref XXH3_generateSecret() can * be employed to ensure proper quality. * * @p customSeed can be anything. It can have any size, even small ones, * and its content can be anything, even "poor entropy" sources such as a bunch * of zeroes. The resulting `secret` will nonetheless provide all required qualities. * * @pre * - @p secretSize must be >= @ref XXH3_SECRET_SIZE_MIN * - When @p customSeedSize > 0, supplying NULL as customSeed is undefined behavior. * * Example code: * @code{.c} * #include * #include * #include * #define XXH_STATIC_LINKING_ONLY // expose unstable API * #include "xxhash.h" * // Hashes argv[2] using the entropy from argv[1]. * int main(int argc, char* argv[]) * { * char secret[XXH3_SECRET_SIZE_MIN]; * if (argv != 3) { return 1; } * XXH3_generateSecret(secret, sizeof(secret), argv[1], strlen(argv[1])); * XXH64_hash_t h = XXH3_64bits_withSecret( * argv[2], strlen(argv[2]), * secret, sizeof(secret) * ); * printf("%016llx\n", (unsigned long long) h); * } * @endcode */ XXH_PUBLIC_API XXH_errorcode XXH3_generateSecret(XXH_NOESCAPE void* secretBuffer, size_t secretSize, XXH_NOESCAPE const void* customSeed, size_t customSeedSize); /*! * @brief Generate the same secret as the _withSeed() variants. * * The generated secret can be used in combination with *`*_withSecret()` and `_withSecretandSeed()` variants. * * Example C++ `std::string` hash class: * @code{.cpp} * #include * #define XXH_STATIC_LINKING_ONLY // expose unstable API * #include "xxhash.h" * // Slow, seeds each time * class HashSlow { * XXH64_hash_t seed; * public: * HashSlow(XXH64_hash_t s) : seed{s} {} * size_t operator()(const std::string& x) const { * return size_t{XXH3_64bits_withSeed(x.c_str(), x.length(), seed)}; * } * }; * // Fast, caches the seeded secret for future uses. * class HashFast { * unsigned char secret[XXH3_SECRET_SIZE_MIN]; * public: * HashFast(XXH64_hash_t s) { * XXH3_generateSecret_fromSeed(secret, seed); * } * size_t operator()(const std::string& x) const { * return size_t{ * XXH3_64bits_withSecret(x.c_str(), x.length(), secret, sizeof(secret)) * }; * } * }; * @endcode * @param secretBuffer A writable buffer of @ref XXH3_SECRET_SIZE_MIN bytes * @param seed The seed to seed the state. */ XXH_PUBLIC_API void XXH3_generateSecret_fromSeed(XXH_NOESCAPE void* secretBuffer, XXH64_hash_t seed); /*! * These variants generate hash values using either * @p seed for "short" keys (< XXH3_MIDSIZE_MAX = 240 bytes) * or @p secret for "large" keys (>= XXH3_MIDSIZE_MAX). * * This generally benefits speed, compared to `_withSeed()` or `_withSecret()`. * `_withSeed()` has to generate the secret on the fly for "large" keys. * It's fast, but can be perceptible for "not so large" keys (< 1 KB). * `_withSecret()` has to generate the masks on the fly for "small" keys, * which requires more instructions than _withSeed() variants. * Therefore, _withSecretandSeed variant combines the best of both worlds. * * When @p secret has been generated by XXH3_generateSecret_fromSeed(), * this variant produces *exactly* the same results as `_withSeed()` variant, * hence offering only a pure speed benefit on "large" input, * by skipping the need to regenerate the secret for every large input. * * Another usage scenario is to hash the secret to a 64-bit hash value, * for example with XXH3_64bits(), which then becomes the seed, * and then employ both the seed and the secret in _withSecretandSeed(). * On top of speed, an added benefit is that each bit in the secret * has a 50% chance to swap each bit in the output, via its impact to the seed. * * This is not guaranteed when using the secret directly in "small data" scenarios, * because only portions of the secret are employed for small data. */ XXH_PUBLIC_API XXH_PUREF XXH64_hash_t XXH3_64bits_withSecretandSeed(XXH_NOESCAPE const void* data, size_t len, XXH_NOESCAPE const void* secret, size_t secretSize, XXH64_hash_t seed); /*! @copydoc XXH3_64bits_withSecretandSeed() */ XXH_PUBLIC_API XXH_PUREF XXH128_hash_t XXH3_128bits_withSecretandSeed(XXH_NOESCAPE const void* input, size_t length, XXH_NOESCAPE const void* secret, size_t secretSize, XXH64_hash_t seed64); #ifndef XXH_NO_STREAM /*! @copydoc XXH3_64bits_withSecretandSeed() */ XXH_PUBLIC_API XXH_errorcode XXH3_64bits_reset_withSecretandSeed(XXH_NOESCAPE XXH3_state_t* statePtr, XXH_NOESCAPE const void* secret, size_t secretSize, XXH64_hash_t seed64); /*! @copydoc XXH3_64bits_withSecretandSeed() */ XXH_PUBLIC_API XXH_errorcode XXH3_128bits_reset_withSecretandSeed(XXH_NOESCAPE XXH3_state_t* statePtr, XXH_NOESCAPE const void* secret, size_t secretSize, XXH64_hash_t seed64); #endif /* !XXH_NO_STREAM */ #endif /* !XXH_NO_XXH3 */ #endif /* XXH_NO_LONG_LONG */ #if defined(XXH_INLINE_ALL) || defined(XXH_PRIVATE_API) # define XXH_IMPLEMENTATION #endif #endif /* defined(XXH_STATIC_LINKING_ONLY) && !defined(XXHASH_H_STATIC_13879238742) */ /* ======================================================================== */ /* ======================================================================== */ /* ======================================================================== */ /*-********************************************************************** * xxHash implementation *-********************************************************************** * xxHash's implementation used to be hosted inside xxhash.c. * * However, inlining requires implementation to be visible to the compiler, * hence be included alongside the header. * Previously, implementation was hosted inside xxhash.c, * which was then #included when inlining was activated. * This construction created issues with a few build and install systems, * as it required xxhash.c to be stored in /include directory. * * xxHash implementation is now directly integrated within xxhash.h. * As a consequence, xxhash.c is no longer needed in /include. * * xxhash.c is still available and is still useful. * In a "normal" setup, when xxhash is not inlined, * xxhash.h only exposes the prototypes and public symbols, * while xxhash.c can be built into an object file xxhash.o * which can then be linked into the final binary. ************************************************************************/ #if ( defined(XXH_INLINE_ALL) || defined(XXH_PRIVATE_API) \ || defined(XXH_IMPLEMENTATION) ) && !defined(XXH_IMPLEM_13a8737387) # define XXH_IMPLEM_13a8737387 /* ************************************* * Tuning parameters ***************************************/ /*! * @defgroup tuning Tuning parameters * @{ * * Various macros to control xxHash's behavior. */ #ifdef XXH_DOXYGEN /*! * @brief Define this to disable 64-bit code. * * Useful if only using the @ref XXH32_family and you have a strict C90 compiler. */ # define XXH_NO_LONG_LONG # undef XXH_NO_LONG_LONG /* don't actually */ /*! * @brief Controls how unaligned memory is accessed. * * By default, access to unaligned memory is controlled by `memcpy()`, which is * safe and portable. * * Unfortunately, on some target/compiler combinations, the generated assembly * is sub-optimal. * * The below switch allow selection of a different access method * in the search for improved performance. * * @par Possible options: * * - `XXH_FORCE_MEMORY_ACCESS=0` (default): `memcpy` * @par * Use `memcpy()`. Safe and portable. Note that most modern compilers will * eliminate the function call and treat it as an unaligned access. * * - `XXH_FORCE_MEMORY_ACCESS=1`: `__attribute__((aligned(1)))` * @par * Depends on compiler extensions and is therefore not portable. * This method is safe _if_ your compiler supports it, * and *generally* as fast or faster than `memcpy`. * * - `XXH_FORCE_MEMORY_ACCESS=2`: Direct cast * @par * Casts directly and dereferences. This method doesn't depend on the * compiler, but it violates the C standard as it directly dereferences an * unaligned pointer. It can generate buggy code on targets which do not * support unaligned memory accesses, but in some circumstances, it's the * only known way to get the most performance. * * - `XXH_FORCE_MEMORY_ACCESS=3`: Byteshift * @par * Also portable. This can generate the best code on old compilers which don't * inline small `memcpy()` calls, and it might also be faster on big-endian * systems which lack a native byteswap instruction. However, some compilers * will emit literal byteshifts even if the target supports unaligned access. * * * @warning * Methods 1 and 2 rely on implementation-defined behavior. Use these with * care, as what works on one compiler/platform/optimization level may cause * another to read garbage data or even crash. * * See https://fastcompression.blogspot.com/2015/08/accessing-unaligned-memory.html for details. * * Prefer these methods in priority order (0 > 3 > 1 > 2) */ # define XXH_FORCE_MEMORY_ACCESS 0 /*! * @def XXH_SIZE_OPT * @brief Controls how much xxHash optimizes for size. * * xxHash, when compiled, tends to result in a rather large binary size. This * is mostly due to heavy usage to forced inlining and constant folding of the * @ref XXH3_family to increase performance. * * However, some developers prefer size over speed. This option can * significantly reduce the size of the generated code. When using the `-Os` * or `-Oz` options on GCC or Clang, this is defined to 1 by default, * otherwise it is defined to 0. * * Most of these size optimizations can be controlled manually. * * This is a number from 0-2. * - `XXH_SIZE_OPT` == 0: Default. xxHash makes no size optimizations. Speed * comes first. * - `XXH_SIZE_OPT` == 1: Default for `-Os` and `-Oz`. xxHash is more * conservative and disables hacks that increase code size. It implies the * options @ref XXH_NO_INLINE_HINTS == 1, @ref XXH_FORCE_ALIGN_CHECK == 0, * and @ref XXH3_NEON_LANES == 8 if they are not already defined. * - `XXH_SIZE_OPT` == 2: xxHash tries to make itself as small as possible. * Performance may cry. For example, the single shot functions just use the * streaming API. */ # define XXH_SIZE_OPT 0 /*! * @def XXH_FORCE_ALIGN_CHECK * @brief If defined to non-zero, adds a special path for aligned inputs (XXH32() * and XXH64() only). * * This is an important performance trick for architectures without decent * unaligned memory access performance. * * It checks for input alignment, and when conditions are met, uses a "fast * path" employing direct 32-bit/64-bit reads, resulting in _dramatically * faster_ read speed. * * The check costs one initial branch per hash, which is generally negligible, * but not zero. * * Moreover, it's not useful to generate an additional code path if memory * access uses the same instruction for both aligned and unaligned * addresses (e.g. x86 and aarch64). * * In these cases, the alignment check can be removed by setting this macro to 0. * Then the code will always use unaligned memory access. * Align check is automatically disabled on x86, x64, ARM64, and some ARM chips * which are platforms known to offer good unaligned memory accesses performance. * * It is also disabled by default when @ref XXH_SIZE_OPT >= 1. * * This option does not affect XXH3 (only XXH32 and XXH64). */ # define XXH_FORCE_ALIGN_CHECK 0 /*! * @def XXH_NO_INLINE_HINTS * @brief When non-zero, sets all functions to `static`. * * By default, xxHash tries to force the compiler to inline almost all internal * functions. * * This can usually improve performance due to reduced jumping and improved * constant folding, but significantly increases the size of the binary which * might not be favorable. * * Additionally, sometimes the forced inlining can be detrimental to performance, * depending on the architecture. * * XXH_NO_INLINE_HINTS marks all internal functions as static, giving the * compiler full control on whether to inline or not. * * When not optimizing (-O0), using `-fno-inline` with GCC or Clang, or if * @ref XXH_SIZE_OPT >= 1, this will automatically be defined. */ # define XXH_NO_INLINE_HINTS 0 /*! * @def XXH3_INLINE_SECRET * @brief Determines whether to inline the XXH3 withSecret code. * * When the secret size is known, the compiler can improve the performance * of XXH3_64bits_withSecret() and XXH3_128bits_withSecret(). * * However, if the secret size is not known, it doesn't have any benefit. This * happens when xxHash is compiled into a global symbol. Therefore, if * @ref XXH_INLINE_ALL is *not* defined, this will be defined to 0. * * Additionally, this defaults to 0 on GCC 12+, which has an issue with function pointers * that are *sometimes* force inline on -Og, and it is impossible to automatically * detect this optimization level. */ # define XXH3_INLINE_SECRET 0 /*! * @def XXH32_ENDJMP * @brief Whether to use a jump for `XXH32_finalize`. * * For performance, `XXH32_finalize` uses multiple branches in the finalizer. * This is generally preferable for performance, * but depending on exact architecture, a jmp may be preferable. * * This setting is only possibly making a difference for very small inputs. */ # define XXH32_ENDJMP 0 /*! * @internal * @brief Redefines old internal names. * * For compatibility with code that uses xxHash's internals before the names * were changed to improve namespacing. There is no other reason to use this. */ # define XXH_OLD_NAMES # undef XXH_OLD_NAMES /* don't actually use, it is ugly. */ /*! * @def XXH_NO_STREAM * @brief Disables the streaming API. * * When xxHash is not inlined and the streaming functions are not used, disabling * the streaming functions can improve code size significantly, especially with * the @ref XXH3_family which tends to make constant folded copies of itself. */ # define XXH_NO_STREAM # undef XXH_NO_STREAM /* don't actually */ #endif /* XXH_DOXYGEN */ /*! * @} */ #ifndef XXH_FORCE_MEMORY_ACCESS /* can be defined externally, on command line for example */ /* prefer __packed__ structures (method 1) for GCC * < ARMv7 with unaligned access (e.g. Raspbian armhf) still uses byte shifting, so we use memcpy * which for some reason does unaligned loads. */ # if defined(__GNUC__) && !(defined(__ARM_ARCH) && __ARM_ARCH < 7 && defined(__ARM_FEATURE_UNALIGNED)) # define XXH_FORCE_MEMORY_ACCESS 1 # endif #endif #ifndef XXH_SIZE_OPT /* default to 1 for -Os or -Oz */ # if (defined(__GNUC__) || defined(__clang__)) && defined(__OPTIMIZE_SIZE__) # define XXH_SIZE_OPT 1 # else # define XXH_SIZE_OPT 0 # endif #endif #ifndef XXH_FORCE_ALIGN_CHECK /* can be defined externally */ /* don't check on sizeopt, x86, aarch64, or arm when unaligned access is available */ # if XXH_SIZE_OPT >= 1 || \ defined(__i386) || defined(__x86_64__) || defined(__aarch64__) || defined(__ARM_FEATURE_UNALIGNED) \ || defined(_M_IX86) || defined(_M_X64) || defined(_M_ARM64) || defined(_M_ARM) /* visual */ # define XXH_FORCE_ALIGN_CHECK 0 # else # define XXH_FORCE_ALIGN_CHECK 1 # endif #endif #ifndef XXH_NO_INLINE_HINTS # if XXH_SIZE_OPT >= 1 || defined(__NO_INLINE__) /* -O0, -fno-inline */ # define XXH_NO_INLINE_HINTS 1 # else # define XXH_NO_INLINE_HINTS 0 # endif #endif #ifndef XXH3_INLINE_SECRET # if (defined(__GNUC__) && !defined(__clang__) && __GNUC__ >= 12) \ || !defined(XXH_INLINE_ALL) # define XXH3_INLINE_SECRET 0 # else # define XXH3_INLINE_SECRET 1 # endif #endif #ifndef XXH32_ENDJMP /* generally preferable for performance */ # define XXH32_ENDJMP 0 #endif /*! * @defgroup impl Implementation * @{ */ /* ************************************* * Includes & Memory related functions ***************************************/ #if defined(XXH_NO_STREAM) /* nothing */ #elif defined(XXH_NO_STDLIB) /* When requesting to disable any mention of stdlib, * the library loses the ability to invoked malloc / free. * In practice, it means that functions like `XXH*_createState()` * will always fail, and return NULL. * This flag is useful in situations where * xxhash.h is integrated into some kernel, embedded or limited environment * without access to dynamic allocation. */ static XXH_CONSTF void* XXH_malloc(size_t s) { (void)s; return NULL; } static void XXH_free(void* p) { (void)p; } #else /* * Modify the local functions below should you wish to use * different memory routines for malloc() and free() */ #include /*! * @internal * @brief Modify this function to use a different routine than malloc(). */ static XXH_MALLOCF void* XXH_malloc(size_t s) { return malloc(s); } /*! * @internal * @brief Modify this function to use a different routine than free(). */ static void XXH_free(void* p) { free(p); } #endif /* XXH_NO_STDLIB */ #include /*! * @internal * @brief Modify this function to use a different routine than memcpy(). */ static void* XXH_memcpy(void* dest, const void* src, size_t size) { return memcpy(dest,src,size); } #include /* ULLONG_MAX */ /* ************************************* * Compiler Specific Options ***************************************/ #ifdef _MSC_VER /* Visual Studio warning fix */ # pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ #endif #if XXH_NO_INLINE_HINTS /* disable inlining hints */ # if defined(__GNUC__) || defined(__clang__) # define XXH_FORCE_INLINE static __attribute__((unused)) # else # define XXH_FORCE_INLINE static # endif # define XXH_NO_INLINE static /* enable inlining hints */ #elif defined(__GNUC__) || defined(__clang__) # define XXH_FORCE_INLINE static __inline__ __attribute__((always_inline, unused)) # define XXH_NO_INLINE static __attribute__((noinline)) #elif defined(_MSC_VER) /* Visual Studio */ # define XXH_FORCE_INLINE static __forceinline # define XXH_NO_INLINE static __declspec(noinline) #elif defined (__cplusplus) \ || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) /* C99 */ # define XXH_FORCE_INLINE static inline # define XXH_NO_INLINE static #else # define XXH_FORCE_INLINE static # define XXH_NO_INLINE static #endif #if XXH3_INLINE_SECRET # define XXH3_WITH_SECRET_INLINE XXH_FORCE_INLINE #else # define XXH3_WITH_SECRET_INLINE XXH_NO_INLINE #endif /* ************************************* * Debug ***************************************/ /*! * @ingroup tuning * @def XXH_DEBUGLEVEL * @brief Sets the debugging level. * * XXH_DEBUGLEVEL is expected to be defined externally, typically via the * compiler's command line options. The value must be a number. */ #ifndef XXH_DEBUGLEVEL # ifdef DEBUGLEVEL /* backwards compat */ # define XXH_DEBUGLEVEL DEBUGLEVEL # else # define XXH_DEBUGLEVEL 0 # endif #endif #if (XXH_DEBUGLEVEL>=1) # include /* note: can still be disabled with NDEBUG */ # define XXH_ASSERT(c) assert(c) #else # if defined(__INTEL_COMPILER) # define XXH_ASSERT(c) XXH_ASSUME((unsigned char) (c)) # else # define XXH_ASSERT(c) XXH_ASSUME(c) # endif #endif /* note: use after variable declarations */ #ifndef XXH_STATIC_ASSERT # if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) /* C11 */ # define XXH_STATIC_ASSERT_WITH_MESSAGE(c,m) do { _Static_assert((c),m); } while(0) # elif defined(__cplusplus) && (__cplusplus >= 201103L) /* C++11 */ # define XXH_STATIC_ASSERT_WITH_MESSAGE(c,m) do { static_assert((c),m); } while(0) # else # define XXH_STATIC_ASSERT_WITH_MESSAGE(c,m) do { struct xxh_sa { char x[(c) ? 1 : -1]; }; } while(0) # endif # define XXH_STATIC_ASSERT(c) XXH_STATIC_ASSERT_WITH_MESSAGE((c),#c) #endif /*! * @internal * @def XXH_COMPILER_GUARD(var) * @brief Used to prevent unwanted optimizations for @p var. * * It uses an empty GCC inline assembly statement with a register constraint * which forces @p var into a general purpose register (eg eax, ebx, ecx * on x86) and marks it as modified. * * This is used in a few places to avoid unwanted autovectorization (e.g. * XXH32_round()). All vectorization we want is explicit via intrinsics, * and _usually_ isn't wanted elsewhere. * * We also use it to prevent unwanted constant folding for AArch64 in * XXH3_initCustomSecret_scalar(). */ #if defined(__GNUC__) || defined(__clang__) # define XXH_COMPILER_GUARD(var) __asm__("" : "+r" (var)) #else # define XXH_COMPILER_GUARD(var) ((void)0) #endif /* Specifically for NEON vectors which use the "w" constraint, on * Clang. */ #if defined(__clang__) && defined(__ARM_ARCH) && !defined(__wasm__) # define XXH_COMPILER_GUARD_CLANG_NEON(var) __asm__("" : "+w" (var)) #else # define XXH_COMPILER_GUARD_CLANG_NEON(var) ((void)0) #endif /* ************************************* * Basic Types ***************************************/ #if !defined (__VMS) \ && (defined (__cplusplus) \ || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) ) # include typedef uint8_t xxh_u8; #else typedef unsigned char xxh_u8; #endif typedef XXH32_hash_t xxh_u32; #ifdef XXH_OLD_NAMES # warning "XXH_OLD_NAMES is planned to be removed starting v0.9. If the program depends on it, consider moving away from it by employing newer type names directly" # define BYTE xxh_u8 # define U8 xxh_u8 # define U32 xxh_u32 #endif /* *** Memory access *** */ /*! * @internal * @fn xxh_u32 XXH_read32(const void* ptr) * @brief Reads an unaligned 32-bit integer from @p ptr in native endianness. * * Affected by @ref XXH_FORCE_MEMORY_ACCESS. * * @param ptr The pointer to read from. * @return The 32-bit native endian integer from the bytes at @p ptr. */ /*! * @internal * @fn xxh_u32 XXH_readLE32(const void* ptr) * @brief Reads an unaligned 32-bit little endian integer from @p ptr. * * Affected by @ref XXH_FORCE_MEMORY_ACCESS. * * @param ptr The pointer to read from. * @return The 32-bit little endian integer from the bytes at @p ptr. */ /*! * @internal * @fn xxh_u32 XXH_readBE32(const void* ptr) * @brief Reads an unaligned 32-bit big endian integer from @p ptr. * * Affected by @ref XXH_FORCE_MEMORY_ACCESS. * * @param ptr The pointer to read from. * @return The 32-bit big endian integer from the bytes at @p ptr. */ /*! * @internal * @fn xxh_u32 XXH_readLE32_align(const void* ptr, XXH_alignment align) * @brief Like @ref XXH_readLE32(), but has an option for aligned reads. * * Affected by @ref XXH_FORCE_MEMORY_ACCESS. * Note that when @ref XXH_FORCE_ALIGN_CHECK == 0, the @p align parameter is * always @ref XXH_alignment::XXH_unaligned. * * @param ptr The pointer to read from. * @param align Whether @p ptr is aligned. * @pre * If @p align == @ref XXH_alignment::XXH_aligned, @p ptr must be 4 byte * aligned. * @return The 32-bit little endian integer from the bytes at @p ptr. */ #if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==3)) /* * Manual byteshift. Best for old compilers which don't inline memcpy. * We actually directly use XXH_readLE32 and XXH_readBE32. */ #elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==2)) /* * Force direct memory access. Only works on CPU which support unaligned memory * access in hardware. */ static xxh_u32 XXH_read32(const void* memPtr) { return *(const xxh_u32*) memPtr; } #elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==1)) /* * __attribute__((aligned(1))) is supported by gcc and clang. Originally the * documentation claimed that it only increased the alignment, but actually it * can decrease it on gcc, clang, and icc: * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69502, * https://gcc.godbolt.org/z/xYez1j67Y. */ #ifdef XXH_OLD_NAMES typedef union { xxh_u32 u32; } __attribute__((packed)) unalign; #endif static xxh_u32 XXH_read32(const void* ptr) { typedef __attribute__((aligned(1))) xxh_u32 xxh_unalign32; return *((const xxh_unalign32*)ptr); } #else /* * Portable and safe solution. Generally efficient. * see: https://fastcompression.blogspot.com/2015/08/accessing-unaligned-memory.html */ static xxh_u32 XXH_read32(const void* memPtr) { xxh_u32 val; XXH_memcpy(&val, memPtr, sizeof(val)); return val; } #endif /* XXH_FORCE_DIRECT_MEMORY_ACCESS */ /* *** Endianness *** */ /*! * @ingroup tuning * @def XXH_CPU_LITTLE_ENDIAN * @brief Whether the target is little endian. * * Defined to 1 if the target is little endian, or 0 if it is big endian. * It can be defined externally, for example on the compiler command line. * * If it is not defined, * a runtime check (which is usually constant folded) is used instead. * * @note * This is not necessarily defined to an integer constant. * * @see XXH_isLittleEndian() for the runtime check. */ #ifndef XXH_CPU_LITTLE_ENDIAN /* * Try to detect endianness automatically, to avoid the nonstandard behavior * in `XXH_isLittleEndian()` */ # if defined(_WIN32) /* Windows is always little endian */ \ || defined(__LITTLE_ENDIAN__) \ || (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) # define XXH_CPU_LITTLE_ENDIAN 1 # elif defined(__BIG_ENDIAN__) \ || (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) # define XXH_CPU_LITTLE_ENDIAN 0 # else /*! * @internal * @brief Runtime check for @ref XXH_CPU_LITTLE_ENDIAN. * * Most compilers will constant fold this. */ static int XXH_isLittleEndian(void) { /* * Portable and well-defined behavior. * Don't use static: it is detrimental to performance. */ const union { xxh_u32 u; xxh_u8 c[4]; } one = { 1 }; return one.c[0]; } # define XXH_CPU_LITTLE_ENDIAN XXH_isLittleEndian() # endif #endif /* **************************************** * Compiler-specific Functions and Macros ******************************************/ #define XXH_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) #ifdef __has_builtin # define XXH_HAS_BUILTIN(x) __has_builtin(x) #else # define XXH_HAS_BUILTIN(x) 0 #endif /* * C23 and future versions have standard "unreachable()". * Once it has been implemented reliably we can add it as an * additional case: * * ``` * #if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= XXH_C23_VN) * # include * # ifdef unreachable * # define XXH_UNREACHABLE() unreachable() * # endif * #endif * ``` * * Note C++23 also has std::unreachable() which can be detected * as follows: * ``` * #if defined(__cpp_lib_unreachable) && (__cpp_lib_unreachable >= 202202L) * # include * # define XXH_UNREACHABLE() std::unreachable() * #endif * ``` * NB: `__cpp_lib_unreachable` is defined in the `` header. * We don't use that as including `` in `extern "C"` blocks * doesn't work on GCC12 */ #if XXH_HAS_BUILTIN(__builtin_unreachable) # define XXH_UNREACHABLE() __builtin_unreachable() #elif defined(_MSC_VER) # define XXH_UNREACHABLE() __assume(0) #else # define XXH_UNREACHABLE() #endif #if XXH_HAS_BUILTIN(__builtin_assume) # define XXH_ASSUME(c) __builtin_assume(c) #else # define XXH_ASSUME(c) if (!(c)) { XXH_UNREACHABLE(); } #endif /*! * @internal * @def XXH_rotl32(x,r) * @brief 32-bit rotate left. * * @param x The 32-bit integer to be rotated. * @param r The number of bits to rotate. * @pre * @p r > 0 && @p r < 32 * @note * @p x and @p r may be evaluated multiple times. * @return The rotated result. */ #if !defined(NO_CLANG_BUILTIN) && XXH_HAS_BUILTIN(__builtin_rotateleft32) \ && XXH_HAS_BUILTIN(__builtin_rotateleft64) # define XXH_rotl32 __builtin_rotateleft32 # define XXH_rotl64 __builtin_rotateleft64 /* Note: although _rotl exists for minGW (GCC under windows), performance seems poor */ #elif defined(_MSC_VER) # define XXH_rotl32(x,r) _rotl(x,r) # define XXH_rotl64(x,r) _rotl64(x,r) #else # define XXH_rotl32(x,r) (((x) << (r)) | ((x) >> (32 - (r)))) # define XXH_rotl64(x,r) (((x) << (r)) | ((x) >> (64 - (r)))) #endif /*! * @internal * @fn xxh_u32 XXH_swap32(xxh_u32 x) * @brief A 32-bit byteswap. * * @param x The 32-bit integer to byteswap. * @return @p x, byteswapped. */ #if defined(_MSC_VER) /* Visual Studio */ # define XXH_swap32 _byteswap_ulong #elif XXH_GCC_VERSION >= 403 # define XXH_swap32 __builtin_bswap32 #else static xxh_u32 XXH_swap32 (xxh_u32 x) { return ((x << 24) & 0xff000000 ) | ((x << 8) & 0x00ff0000 ) | ((x >> 8) & 0x0000ff00 ) | ((x >> 24) & 0x000000ff ); } #endif /* *************************** * Memory reads *****************************/ /*! * @internal * @brief Enum to indicate whether a pointer is aligned. */ typedef enum { XXH_aligned, /*!< Aligned */ XXH_unaligned /*!< Possibly unaligned */ } XXH_alignment; /* * XXH_FORCE_MEMORY_ACCESS==3 is an endian-independent byteshift load. * * This is ideal for older compilers which don't inline memcpy. */ #if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==3)) XXH_FORCE_INLINE xxh_u32 XXH_readLE32(const void* memPtr) { const xxh_u8* bytePtr = (const xxh_u8 *)memPtr; return bytePtr[0] | ((xxh_u32)bytePtr[1] << 8) | ((xxh_u32)bytePtr[2] << 16) | ((xxh_u32)bytePtr[3] << 24); } XXH_FORCE_INLINE xxh_u32 XXH_readBE32(const void* memPtr) { const xxh_u8* bytePtr = (const xxh_u8 *)memPtr; return bytePtr[3] | ((xxh_u32)bytePtr[2] << 8) | ((xxh_u32)bytePtr[1] << 16) | ((xxh_u32)bytePtr[0] << 24); } #else XXH_FORCE_INLINE xxh_u32 XXH_readLE32(const void* ptr) { return XXH_CPU_LITTLE_ENDIAN ? XXH_read32(ptr) : XXH_swap32(XXH_read32(ptr)); } static xxh_u32 XXH_readBE32(const void* ptr) { return XXH_CPU_LITTLE_ENDIAN ? XXH_swap32(XXH_read32(ptr)) : XXH_read32(ptr); } #endif XXH_FORCE_INLINE xxh_u32 XXH_readLE32_align(const void* ptr, XXH_alignment align) { if (align==XXH_unaligned) { return XXH_readLE32(ptr); } else { return XXH_CPU_LITTLE_ENDIAN ? *(const xxh_u32*)ptr : XXH_swap32(*(const xxh_u32*)ptr); } } /* ************************************* * Misc ***************************************/ /*! @ingroup public */ XXH_PUBLIC_API unsigned XXH_versionNumber (void) { return XXH_VERSION_NUMBER; } /* ******************************************************************* * 32-bit hash functions *********************************************************************/ /*! * @} * @defgroup XXH32_impl XXH32 implementation * @ingroup impl * * Details on the XXH32 implementation. * @{ */ /* #define instead of static const, to be used as initializers */ #define XXH_PRIME32_1 0x9E3779B1U /*!< 0b10011110001101110111100110110001 */ #define XXH_PRIME32_2 0x85EBCA77U /*!< 0b10000101111010111100101001110111 */ #define XXH_PRIME32_3 0xC2B2AE3DU /*!< 0b11000010101100101010111000111101 */ #define XXH_PRIME32_4 0x27D4EB2FU /*!< 0b00100111110101001110101100101111 */ #define XXH_PRIME32_5 0x165667B1U /*!< 0b00010110010101100110011110110001 */ #ifdef XXH_OLD_NAMES # define PRIME32_1 XXH_PRIME32_1 # define PRIME32_2 XXH_PRIME32_2 # define PRIME32_3 XXH_PRIME32_3 # define PRIME32_4 XXH_PRIME32_4 # define PRIME32_5 XXH_PRIME32_5 #endif /*! * @internal * @brief Normal stripe processing routine. * * This shuffles the bits so that any bit from @p input impacts several bits in * @p acc. * * @param acc The accumulator lane. * @param input The stripe of input to mix. * @return The mixed accumulator lane. */ static xxh_u32 XXH32_round(xxh_u32 acc, xxh_u32 input) { acc += input * XXH_PRIME32_2; acc = XXH_rotl32(acc, 13); acc *= XXH_PRIME32_1; #if (defined(__SSE4_1__) || defined(__aarch64__) || defined(__wasm_simd128__)) && !defined(XXH_ENABLE_AUTOVECTORIZE) /* * UGLY HACK: * A compiler fence is the only thing that prevents GCC and Clang from * autovectorizing the XXH32 loop (pragmas and attributes don't work for some * reason) without globally disabling SSE4.1. * * The reason we want to avoid vectorization is because despite working on * 4 integers at a time, there are multiple factors slowing XXH32 down on * SSE4: * - There's a ridiculous amount of lag from pmulld (10 cycles of latency on * newer chips!) making it slightly slower to multiply four integers at * once compared to four integers independently. Even when pmulld was * fastest, Sandy/Ivy Bridge, it is still not worth it to go into SSE * just to multiply unless doing a long operation. * * - Four instructions are required to rotate, * movqda tmp, v // not required with VEX encoding * pslld tmp, 13 // tmp <<= 13 * psrld v, 19 // x >>= 19 * por v, tmp // x |= tmp * compared to one for scalar: * roll v, 13 // reliably fast across the board * shldl v, v, 13 // Sandy Bridge and later prefer this for some reason * * - Instruction level parallelism is actually more beneficial here because * the SIMD actually serializes this operation: While v1 is rotating, v2 * can load data, while v3 can multiply. SSE forces them to operate * together. * * This is also enabled on AArch64, as Clang is *very aggressive* in vectorizing * the loop. NEON is only faster on the A53, and with the newer cores, it is less * than half the speed. * * Additionally, this is used on WASM SIMD128 because it JITs to the same * SIMD instructions and has the same issue. */ XXH_COMPILER_GUARD(acc); #endif return acc; } /*! * @internal * @brief Mixes all bits to finalize the hash. * * The final mix ensures that all input bits have a chance to impact any bit in * the output digest, resulting in an unbiased distribution. * * @param hash The hash to avalanche. * @return The avalanched hash. */ static xxh_u32 XXH32_avalanche(xxh_u32 hash) { hash ^= hash >> 15; hash *= XXH_PRIME32_2; hash ^= hash >> 13; hash *= XXH_PRIME32_3; hash ^= hash >> 16; return hash; } #define XXH_get32bits(p) XXH_readLE32_align(p, align) /*! * @internal * @brief Processes the last 0-15 bytes of @p ptr. * * There may be up to 15 bytes remaining to consume from the input. * This final stage will digest them to ensure that all input bytes are present * in the final mix. * * @param hash The hash to finalize. * @param ptr The pointer to the remaining input. * @param len The remaining length, modulo 16. * @param align Whether @p ptr is aligned. * @return The finalized hash. * @see XXH64_finalize(). */ static XXH_PUREF xxh_u32 XXH32_finalize(xxh_u32 hash, const xxh_u8* ptr, size_t len, XXH_alignment align) { #define XXH_PROCESS1 do { \ hash += (*ptr++) * XXH_PRIME32_5; \ hash = XXH_rotl32(hash, 11) * XXH_PRIME32_1; \ } while (0) #define XXH_PROCESS4 do { \ hash += XXH_get32bits(ptr) * XXH_PRIME32_3; \ ptr += 4; \ hash = XXH_rotl32(hash, 17) * XXH_PRIME32_4; \ } while (0) if (ptr==NULL) XXH_ASSERT(len == 0); /* Compact rerolled version; generally faster */ if (!XXH32_ENDJMP) { len &= 15; while (len >= 4) { XXH_PROCESS4; len -= 4; } while (len > 0) { XXH_PROCESS1; --len; } return XXH32_avalanche(hash); } else { switch(len&15) /* or switch(bEnd - p) */ { case 12: XXH_PROCESS4; XXH_FALLTHROUGH; /* fallthrough */ case 8: XXH_PROCESS4; XXH_FALLTHROUGH; /* fallthrough */ case 4: XXH_PROCESS4; return XXH32_avalanche(hash); case 13: XXH_PROCESS4; XXH_FALLTHROUGH; /* fallthrough */ case 9: XXH_PROCESS4; XXH_FALLTHROUGH; /* fallthrough */ case 5: XXH_PROCESS4; XXH_PROCESS1; return XXH32_avalanche(hash); case 14: XXH_PROCESS4; XXH_FALLTHROUGH; /* fallthrough */ case 10: XXH_PROCESS4; XXH_FALLTHROUGH; /* fallthrough */ case 6: XXH_PROCESS4; XXH_PROCESS1; XXH_PROCESS1; return XXH32_avalanche(hash); case 15: XXH_PROCESS4; XXH_FALLTHROUGH; /* fallthrough */ case 11: XXH_PROCESS4; XXH_FALLTHROUGH; /* fallthrough */ case 7: XXH_PROCESS4; XXH_FALLTHROUGH; /* fallthrough */ case 3: XXH_PROCESS1; XXH_FALLTHROUGH; /* fallthrough */ case 2: XXH_PROCESS1; XXH_FALLTHROUGH; /* fallthrough */ case 1: XXH_PROCESS1; XXH_FALLTHROUGH; /* fallthrough */ case 0: return XXH32_avalanche(hash); } XXH_ASSERT(0); return hash; /* reaching this point is deemed impossible */ } } #ifdef XXH_OLD_NAMES # define PROCESS1 XXH_PROCESS1 # define PROCESS4 XXH_PROCESS4 #else # undef XXH_PROCESS1 # undef XXH_PROCESS4 #endif /*! * @internal * @brief The implementation for @ref XXH32(). * * @param input , len , seed Directly passed from @ref XXH32(). * @param align Whether @p input is aligned. * @return The calculated hash. */ XXH_FORCE_INLINE XXH_PUREF xxh_u32 XXH32_endian_align(const xxh_u8* input, size_t len, xxh_u32 seed, XXH_alignment align) { xxh_u32 h32; if (input==NULL) XXH_ASSERT(len == 0); if (len>=16) { const xxh_u8* const bEnd = input + len; const xxh_u8* const limit = bEnd - 15; xxh_u32 v1 = seed + XXH_PRIME32_1 + XXH_PRIME32_2; xxh_u32 v2 = seed + XXH_PRIME32_2; xxh_u32 v3 = seed + 0; xxh_u32 v4 = seed - XXH_PRIME32_1; do { v1 = XXH32_round(v1, XXH_get32bits(input)); input += 4; v2 = XXH32_round(v2, XXH_get32bits(input)); input += 4; v3 = XXH32_round(v3, XXH_get32bits(input)); input += 4; v4 = XXH32_round(v4, XXH_get32bits(input)); input += 4; } while (input < limit); h32 = XXH_rotl32(v1, 1) + XXH_rotl32(v2, 7) + XXH_rotl32(v3, 12) + XXH_rotl32(v4, 18); } else { h32 = seed + XXH_PRIME32_5; } h32 += (xxh_u32)len; return XXH32_finalize(h32, input, len&15, align); } /*! @ingroup XXH32_family */ XXH_PUBLIC_API XXH32_hash_t XXH32 (const void* input, size_t len, XXH32_hash_t seed) { #if !defined(XXH_NO_STREAM) && XXH_SIZE_OPT >= 2 /* Simple version, good for code maintenance, but unfortunately slow for small inputs */ XXH32_state_t state; XXH32_reset(&state, seed); XXH32_update(&state, (const xxh_u8*)input, len); return XXH32_digest(&state); #else if (XXH_FORCE_ALIGN_CHECK) { if ((((size_t)input) & 3) == 0) { /* Input is 4-bytes aligned, leverage the speed benefit */ return XXH32_endian_align((const xxh_u8*)input, len, seed, XXH_aligned); } } return XXH32_endian_align((const xxh_u8*)input, len, seed, XXH_unaligned); #endif } /******* Hash streaming *******/ #ifndef XXH_NO_STREAM /*! @ingroup XXH32_family */ XXH_PUBLIC_API XXH32_state_t* XXH32_createState(void) { return (XXH32_state_t*)XXH_malloc(sizeof(XXH32_state_t)); } /*! @ingroup XXH32_family */ XXH_PUBLIC_API XXH_errorcode XXH32_freeState(XXH32_state_t* statePtr) { XXH_free(statePtr); return XXH_OK; } /*! @ingroup XXH32_family */ XXH_PUBLIC_API void XXH32_copyState(XXH32_state_t* dstState, const XXH32_state_t* srcState) { XXH_memcpy(dstState, srcState, sizeof(*dstState)); } /*! @ingroup XXH32_family */ XXH_PUBLIC_API XXH_errorcode XXH32_reset(XXH32_state_t* statePtr, XXH32_hash_t seed) { XXH_ASSERT(statePtr != NULL); memset(statePtr, 0, sizeof(*statePtr)); statePtr->v[0] = seed + XXH_PRIME32_1 + XXH_PRIME32_2; statePtr->v[1] = seed + XXH_PRIME32_2; statePtr->v[2] = seed + 0; statePtr->v[3] = seed - XXH_PRIME32_1; return XXH_OK; } /*! @ingroup XXH32_family */ XXH_PUBLIC_API XXH_errorcode XXH32_update(XXH32_state_t* state, const void* input, size_t len) { if (input==NULL) { XXH_ASSERT(len == 0); return XXH_OK; } { const xxh_u8* p = (const xxh_u8*)input; const xxh_u8* const bEnd = p + len; state->total_len_32 += (XXH32_hash_t)len; state->large_len |= (XXH32_hash_t)((len>=16) | (state->total_len_32>=16)); if (state->memsize + len < 16) { /* fill in tmp buffer */ XXH_memcpy((xxh_u8*)(state->mem32) + state->memsize, input, len); state->memsize += (XXH32_hash_t)len; return XXH_OK; } if (state->memsize) { /* some data left from previous update */ XXH_memcpy((xxh_u8*)(state->mem32) + state->memsize, input, 16-state->memsize); { const xxh_u32* p32 = state->mem32; state->v[0] = XXH32_round(state->v[0], XXH_readLE32(p32)); p32++; state->v[1] = XXH32_round(state->v[1], XXH_readLE32(p32)); p32++; state->v[2] = XXH32_round(state->v[2], XXH_readLE32(p32)); p32++; state->v[3] = XXH32_round(state->v[3], XXH_readLE32(p32)); } p += 16-state->memsize; state->memsize = 0; } if (p <= bEnd-16) { const xxh_u8* const limit = bEnd - 16; do { state->v[0] = XXH32_round(state->v[0], XXH_readLE32(p)); p+=4; state->v[1] = XXH32_round(state->v[1], XXH_readLE32(p)); p+=4; state->v[2] = XXH32_round(state->v[2], XXH_readLE32(p)); p+=4; state->v[3] = XXH32_round(state->v[3], XXH_readLE32(p)); p+=4; } while (p<=limit); } if (p < bEnd) { XXH_memcpy(state->mem32, p, (size_t)(bEnd-p)); state->memsize = (unsigned)(bEnd-p); } } return XXH_OK; } /*! @ingroup XXH32_family */ XXH_PUBLIC_API XXH32_hash_t XXH32_digest(const XXH32_state_t* state) { xxh_u32 h32; if (state->large_len) { h32 = XXH_rotl32(state->v[0], 1) + XXH_rotl32(state->v[1], 7) + XXH_rotl32(state->v[2], 12) + XXH_rotl32(state->v[3], 18); } else { h32 = state->v[2] /* == seed */ + XXH_PRIME32_5; } h32 += state->total_len_32; return XXH32_finalize(h32, (const xxh_u8*)state->mem32, state->memsize, XXH_aligned); } #endif /* !XXH_NO_STREAM */ /******* Canonical representation *******/ /*! * @ingroup XXH32_family * The default return values from XXH functions are unsigned 32 and 64 bit * integers. * * The canonical representation uses big endian convention, the same convention * as human-readable numbers (large digits first). * * This way, hash values can be written into a file or buffer, remaining * comparable across different systems. * * The following functions allow transformation of hash values to and from their * canonical format. */ XXH_PUBLIC_API void XXH32_canonicalFromHash(XXH32_canonical_t* dst, XXH32_hash_t hash) { XXH_STATIC_ASSERT(sizeof(XXH32_canonical_t) == sizeof(XXH32_hash_t)); if (XXH_CPU_LITTLE_ENDIAN) hash = XXH_swap32(hash); XXH_memcpy(dst, &hash, sizeof(*dst)); } /*! @ingroup XXH32_family */ XXH_PUBLIC_API XXH32_hash_t XXH32_hashFromCanonical(const XXH32_canonical_t* src) { return XXH_readBE32(src); } #ifndef XXH_NO_LONG_LONG /* ******************************************************************* * 64-bit hash functions *********************************************************************/ /*! * @} * @ingroup impl * @{ */ /******* Memory access *******/ typedef XXH64_hash_t xxh_u64; #ifdef XXH_OLD_NAMES # define U64 xxh_u64 #endif #if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==3)) /* * Manual byteshift. Best for old compilers which don't inline memcpy. * We actually directly use XXH_readLE64 and XXH_readBE64. */ #elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==2)) /* Force direct memory access. Only works on CPU which support unaligned memory access in hardware */ static xxh_u64 XXH_read64(const void* memPtr) { return *(const xxh_u64*) memPtr; } #elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==1)) /* * __attribute__((aligned(1))) is supported by gcc and clang. Originally the * documentation claimed that it only increased the alignment, but actually it * can decrease it on gcc, clang, and icc: * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69502, * https://gcc.godbolt.org/z/xYez1j67Y. */ #ifdef XXH_OLD_NAMES typedef union { xxh_u32 u32; xxh_u64 u64; } __attribute__((packed)) unalign64; #endif static xxh_u64 XXH_read64(const void* ptr) { typedef __attribute__((aligned(1))) xxh_u64 xxh_unalign64; return *((const xxh_unalign64*)ptr); } #else /* * Portable and safe solution. Generally efficient. * see: https://fastcompression.blogspot.com/2015/08/accessing-unaligned-memory.html */ static xxh_u64 XXH_read64(const void* memPtr) { xxh_u64 val; XXH_memcpy(&val, memPtr, sizeof(val)); return val; } #endif /* XXH_FORCE_DIRECT_MEMORY_ACCESS */ #if defined(_MSC_VER) /* Visual Studio */ # define XXH_swap64 _byteswap_uint64 #elif XXH_GCC_VERSION >= 403 # define XXH_swap64 __builtin_bswap64 #else static xxh_u64 XXH_swap64(xxh_u64 x) { return ((x << 56) & 0xff00000000000000ULL) | ((x << 40) & 0x00ff000000000000ULL) | ((x << 24) & 0x0000ff0000000000ULL) | ((x << 8) & 0x000000ff00000000ULL) | ((x >> 8) & 0x00000000ff000000ULL) | ((x >> 24) & 0x0000000000ff0000ULL) | ((x >> 40) & 0x000000000000ff00ULL) | ((x >> 56) & 0x00000000000000ffULL); } #endif /* XXH_FORCE_MEMORY_ACCESS==3 is an endian-independent byteshift load. */ #if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==3)) XXH_FORCE_INLINE xxh_u64 XXH_readLE64(const void* memPtr) { const xxh_u8* bytePtr = (const xxh_u8 *)memPtr; return bytePtr[0] | ((xxh_u64)bytePtr[1] << 8) | ((xxh_u64)bytePtr[2] << 16) | ((xxh_u64)bytePtr[3] << 24) | ((xxh_u64)bytePtr[4] << 32) | ((xxh_u64)bytePtr[5] << 40) | ((xxh_u64)bytePtr[6] << 48) | ((xxh_u64)bytePtr[7] << 56); } XXH_FORCE_INLINE xxh_u64 XXH_readBE64(const void* memPtr) { const xxh_u8* bytePtr = (const xxh_u8 *)memPtr; return bytePtr[7] | ((xxh_u64)bytePtr[6] << 8) | ((xxh_u64)bytePtr[5] << 16) | ((xxh_u64)bytePtr[4] << 24) | ((xxh_u64)bytePtr[3] << 32) | ((xxh_u64)bytePtr[2] << 40) | ((xxh_u64)bytePtr[1] << 48) | ((xxh_u64)bytePtr[0] << 56); } #else XXH_FORCE_INLINE xxh_u64 XXH_readLE64(const void* ptr) { return XXH_CPU_LITTLE_ENDIAN ? XXH_read64(ptr) : XXH_swap64(XXH_read64(ptr)); } static xxh_u64 XXH_readBE64(const void* ptr) { return XXH_CPU_LITTLE_ENDIAN ? XXH_swap64(XXH_read64(ptr)) : XXH_read64(ptr); } #endif XXH_FORCE_INLINE xxh_u64 XXH_readLE64_align(const void* ptr, XXH_alignment align) { if (align==XXH_unaligned) return XXH_readLE64(ptr); else return XXH_CPU_LITTLE_ENDIAN ? *(const xxh_u64*)ptr : XXH_swap64(*(const xxh_u64*)ptr); } /******* xxh64 *******/ /*! * @} * @defgroup XXH64_impl XXH64 implementation * @ingroup impl * * Details on the XXH64 implementation. * @{ */ /* #define rather that static const, to be used as initializers */ #define XXH_PRIME64_1 0x9E3779B185EBCA87ULL /*!< 0b1001111000110111011110011011000110000101111010111100101010000111 */ #define XXH_PRIME64_2 0xC2B2AE3D27D4EB4FULL /*!< 0b1100001010110010101011100011110100100111110101001110101101001111 */ #define XXH_PRIME64_3 0x165667B19E3779F9ULL /*!< 0b0001011001010110011001111011000110011110001101110111100111111001 */ #define XXH_PRIME64_4 0x85EBCA77C2B2AE63ULL /*!< 0b1000010111101011110010100111011111000010101100101010111001100011 */ #define XXH_PRIME64_5 0x27D4EB2F165667C5ULL /*!< 0b0010011111010100111010110010111100010110010101100110011111000101 */ #ifdef XXH_OLD_NAMES # define PRIME64_1 XXH_PRIME64_1 # define PRIME64_2 XXH_PRIME64_2 # define PRIME64_3 XXH_PRIME64_3 # define PRIME64_4 XXH_PRIME64_4 # define PRIME64_5 XXH_PRIME64_5 #endif /*! @copydoc XXH32_round */ static xxh_u64 XXH64_round(xxh_u64 acc, xxh_u64 input) { acc += input * XXH_PRIME64_2; acc = XXH_rotl64(acc, 31); acc *= XXH_PRIME64_1; return acc; } static xxh_u64 XXH64_mergeRound(xxh_u64 acc, xxh_u64 val) { val = XXH64_round(0, val); acc ^= val; acc = acc * XXH_PRIME64_1 + XXH_PRIME64_4; return acc; } /*! @copydoc XXH32_avalanche */ static xxh_u64 XXH64_avalanche(xxh_u64 hash) { hash ^= hash >> 33; hash *= XXH_PRIME64_2; hash ^= hash >> 29; hash *= XXH_PRIME64_3; hash ^= hash >> 32; return hash; } #define XXH_get64bits(p) XXH_readLE64_align(p, align) /*! * @internal * @brief Processes the last 0-31 bytes of @p ptr. * * There may be up to 31 bytes remaining to consume from the input. * This final stage will digest them to ensure that all input bytes are present * in the final mix. * * @param hash The hash to finalize. * @param ptr The pointer to the remaining input. * @param len The remaining length, modulo 32. * @param align Whether @p ptr is aligned. * @return The finalized hash * @see XXH32_finalize(). */ static XXH_PUREF xxh_u64 XXH64_finalize(xxh_u64 hash, const xxh_u8* ptr, size_t len, XXH_alignment align) { if (ptr==NULL) XXH_ASSERT(len == 0); len &= 31; while (len >= 8) { xxh_u64 const k1 = XXH64_round(0, XXH_get64bits(ptr)); ptr += 8; hash ^= k1; hash = XXH_rotl64(hash,27) * XXH_PRIME64_1 + XXH_PRIME64_4; len -= 8; } if (len >= 4) { hash ^= (xxh_u64)(XXH_get32bits(ptr)) * XXH_PRIME64_1; ptr += 4; hash = XXH_rotl64(hash, 23) * XXH_PRIME64_2 + XXH_PRIME64_3; len -= 4; } while (len > 0) { hash ^= (*ptr++) * XXH_PRIME64_5; hash = XXH_rotl64(hash, 11) * XXH_PRIME64_1; --len; } return XXH64_avalanche(hash); } #ifdef XXH_OLD_NAMES # define PROCESS1_64 XXH_PROCESS1_64 # define PROCESS4_64 XXH_PROCESS4_64 # define PROCESS8_64 XXH_PROCESS8_64 #else # undef XXH_PROCESS1_64 # undef XXH_PROCESS4_64 # undef XXH_PROCESS8_64 #endif /*! * @internal * @brief The implementation for @ref XXH64(). * * @param input , len , seed Directly passed from @ref XXH64(). * @param align Whether @p input is aligned. * @return The calculated hash. */ XXH_FORCE_INLINE XXH_PUREF xxh_u64 XXH64_endian_align(const xxh_u8* input, size_t len, xxh_u64 seed, XXH_alignment align) { xxh_u64 h64; if (input==NULL) XXH_ASSERT(len == 0); if (len>=32) { const xxh_u8* const bEnd = input + len; const xxh_u8* const limit = bEnd - 31; xxh_u64 v1 = seed + XXH_PRIME64_1 + XXH_PRIME64_2; xxh_u64 v2 = seed + XXH_PRIME64_2; xxh_u64 v3 = seed + 0; xxh_u64 v4 = seed - XXH_PRIME64_1; do { v1 = XXH64_round(v1, XXH_get64bits(input)); input+=8; v2 = XXH64_round(v2, XXH_get64bits(input)); input+=8; v3 = XXH64_round(v3, XXH_get64bits(input)); input+=8; v4 = XXH64_round(v4, XXH_get64bits(input)); input+=8; } while (input= 2 /* Simple version, good for code maintenance, but unfortunately slow for small inputs */ XXH64_state_t state; XXH64_reset(&state, seed); XXH64_update(&state, (const xxh_u8*)input, len); return XXH64_digest(&state); #else if (XXH_FORCE_ALIGN_CHECK) { if ((((size_t)input) & 7)==0) { /* Input is aligned, let's leverage the speed advantage */ return XXH64_endian_align((const xxh_u8*)input, len, seed, XXH_aligned); } } return XXH64_endian_align((const xxh_u8*)input, len, seed, XXH_unaligned); #endif } /******* Hash Streaming *******/ #ifndef XXH_NO_STREAM /*! @ingroup XXH64_family*/ XXH_PUBLIC_API XXH64_state_t* XXH64_createState(void) { return (XXH64_state_t*)XXH_malloc(sizeof(XXH64_state_t)); } /*! @ingroup XXH64_family */ XXH_PUBLIC_API XXH_errorcode XXH64_freeState(XXH64_state_t* statePtr) { XXH_free(statePtr); return XXH_OK; } /*! @ingroup XXH64_family */ XXH_PUBLIC_API void XXH64_copyState(XXH_NOESCAPE XXH64_state_t* dstState, const XXH64_state_t* srcState) { XXH_memcpy(dstState, srcState, sizeof(*dstState)); } /*! @ingroup XXH64_family */ XXH_PUBLIC_API XXH_errorcode XXH64_reset(XXH_NOESCAPE XXH64_state_t* statePtr, XXH64_hash_t seed) { XXH_ASSERT(statePtr != NULL); memset(statePtr, 0, sizeof(*statePtr)); statePtr->v[0] = seed + XXH_PRIME64_1 + XXH_PRIME64_2; statePtr->v[1] = seed + XXH_PRIME64_2; statePtr->v[2] = seed + 0; statePtr->v[3] = seed - XXH_PRIME64_1; return XXH_OK; } /*! @ingroup XXH64_family */ XXH_PUBLIC_API XXH_errorcode XXH64_update (XXH_NOESCAPE XXH64_state_t* state, XXH_NOESCAPE const void* input, size_t len) { if (input==NULL) { XXH_ASSERT(len == 0); return XXH_OK; } { const xxh_u8* p = (const xxh_u8*)input; const xxh_u8* const bEnd = p + len; state->total_len += len; if (state->memsize + len < 32) { /* fill in tmp buffer */ XXH_memcpy(((xxh_u8*)state->mem64) + state->memsize, input, len); state->memsize += (xxh_u32)len; return XXH_OK; } if (state->memsize) { /* tmp buffer is full */ XXH_memcpy(((xxh_u8*)state->mem64) + state->memsize, input, 32-state->memsize); state->v[0] = XXH64_round(state->v[0], XXH_readLE64(state->mem64+0)); state->v[1] = XXH64_round(state->v[1], XXH_readLE64(state->mem64+1)); state->v[2] = XXH64_round(state->v[2], XXH_readLE64(state->mem64+2)); state->v[3] = XXH64_round(state->v[3], XXH_readLE64(state->mem64+3)); p += 32 - state->memsize; state->memsize = 0; } if (p+32 <= bEnd) { const xxh_u8* const limit = bEnd - 32; do { state->v[0] = XXH64_round(state->v[0], XXH_readLE64(p)); p+=8; state->v[1] = XXH64_round(state->v[1], XXH_readLE64(p)); p+=8; state->v[2] = XXH64_round(state->v[2], XXH_readLE64(p)); p+=8; state->v[3] = XXH64_round(state->v[3], XXH_readLE64(p)); p+=8; } while (p<=limit); } if (p < bEnd) { XXH_memcpy(state->mem64, p, (size_t)(bEnd-p)); state->memsize = (unsigned)(bEnd-p); } } return XXH_OK; } /*! @ingroup XXH64_family */ XXH_PUBLIC_API XXH64_hash_t XXH64_digest(XXH_NOESCAPE const XXH64_state_t* state) { xxh_u64 h64; if (state->total_len >= 32) { h64 = XXH_rotl64(state->v[0], 1) + XXH_rotl64(state->v[1], 7) + XXH_rotl64(state->v[2], 12) + XXH_rotl64(state->v[3], 18); h64 = XXH64_mergeRound(h64, state->v[0]); h64 = XXH64_mergeRound(h64, state->v[1]); h64 = XXH64_mergeRound(h64, state->v[2]); h64 = XXH64_mergeRound(h64, state->v[3]); } else { h64 = state->v[2] /*seed*/ + XXH_PRIME64_5; } h64 += (xxh_u64) state->total_len; return XXH64_finalize(h64, (const xxh_u8*)state->mem64, (size_t)state->total_len, XXH_aligned); } #endif /* !XXH_NO_STREAM */ /******* Canonical representation *******/ /*! @ingroup XXH64_family */ XXH_PUBLIC_API void XXH64_canonicalFromHash(XXH_NOESCAPE XXH64_canonical_t* dst, XXH64_hash_t hash) { XXH_STATIC_ASSERT(sizeof(XXH64_canonical_t) == sizeof(XXH64_hash_t)); if (XXH_CPU_LITTLE_ENDIAN) hash = XXH_swap64(hash); XXH_memcpy(dst, &hash, sizeof(*dst)); } /*! @ingroup XXH64_family */ XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(XXH_NOESCAPE const XXH64_canonical_t* src) { return XXH_readBE64(src); } #ifndef XXH_NO_XXH3 /* ********************************************************************* * XXH3 * New generation hash designed for speed on small keys and vectorization ************************************************************************ */ /*! * @} * @defgroup XXH3_impl XXH3 implementation * @ingroup impl * @{ */ /* === Compiler specifics === */ #if ((defined(sun) || defined(__sun)) && __cplusplus) /* Solaris includes __STDC_VERSION__ with C++. Tested with GCC 5.5 */ # define XXH_RESTRICT /* disable */ #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* >= C99 */ # define XXH_RESTRICT restrict #elif (defined (__GNUC__) && ((__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))) \ || (defined (__clang__)) \ || (defined (_MSC_VER) && (_MSC_VER >= 1400)) \ || (defined (__INTEL_COMPILER) && (__INTEL_COMPILER >= 1300)) /* * There are a LOT more compilers that recognize __restrict but this * covers the major ones. */ # define XXH_RESTRICT __restrict #else # define XXH_RESTRICT /* disable */ #endif #if (defined(__GNUC__) && (__GNUC__ >= 3)) \ || (defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 800)) \ || defined(__clang__) # define XXH_likely(x) __builtin_expect(x, 1) # define XXH_unlikely(x) __builtin_expect(x, 0) #else # define XXH_likely(x) (x) # define XXH_unlikely(x) (x) #endif #ifndef XXH_HAS_INCLUDE # ifdef __has_include # define XXH_HAS_INCLUDE(x) __has_include(x) # else # define XXH_HAS_INCLUDE(x) 0 # endif #endif #if defined(__GNUC__) || defined(__clang__) # if defined(__ARM_FEATURE_SVE) # include # endif # if defined(__ARM_NEON__) || defined(__ARM_NEON) \ || (defined(_M_ARM) && _M_ARM >= 7) \ || defined(_M_ARM64) || defined(_M_ARM64EC) \ || (defined(__wasm_simd128__) && XXH_HAS_INCLUDE()) /* WASM SIMD128 via SIMDe */ # define inline __inline__ /* circumvent a clang bug */ # include # undef inline # elif defined(__AVX2__) # include # elif defined(__SSE2__) # include # endif #endif #if defined(_MSC_VER) # include #endif /* * One goal of XXH3 is to make it fast on both 32-bit and 64-bit, while * remaining a true 64-bit/128-bit hash function. * * This is done by prioritizing a subset of 64-bit operations that can be * emulated without too many steps on the average 32-bit machine. * * For example, these two lines seem similar, and run equally fast on 64-bit: * * xxh_u64 x; * x ^= (x >> 47); // good * x ^= (x >> 13); // bad * * However, to a 32-bit machine, there is a major difference. * * x ^= (x >> 47) looks like this: * * x.lo ^= (x.hi >> (47 - 32)); * * while x ^= (x >> 13) looks like this: * * // note: funnel shifts are not usually cheap. * x.lo ^= (x.lo >> 13) | (x.hi << (32 - 13)); * x.hi ^= (x.hi >> 13); * * The first one is significantly faster than the second, simply because the * shift is larger than 32. This means: * - All the bits we need are in the upper 32 bits, so we can ignore the lower * 32 bits in the shift. * - The shift result will always fit in the lower 32 bits, and therefore, * we can ignore the upper 32 bits in the xor. * * Thanks to this optimization, XXH3 only requires these features to be efficient: * * - Usable unaligned access * - A 32-bit or 64-bit ALU * - If 32-bit, a decent ADC instruction * - A 32 or 64-bit multiply with a 64-bit result * - For the 128-bit variant, a decent byteswap helps short inputs. * * The first two are already required by XXH32, and almost all 32-bit and 64-bit * platforms which can run XXH32 can run XXH3 efficiently. * * Thumb-1, the classic 16-bit only subset of ARM's instruction set, is one * notable exception. * * First of all, Thumb-1 lacks support for the UMULL instruction which * performs the important long multiply. This means numerous __aeabi_lmul * calls. * * Second of all, the 8 functional registers are just not enough. * Setup for __aeabi_lmul, byteshift loads, pointers, and all arithmetic need * Lo registers, and this shuffling results in thousands more MOVs than A32. * * A32 and T32 don't have this limitation. They can access all 14 registers, * do a 32->64 multiply with UMULL, and the flexible operand allowing free * shifts is helpful, too. * * Therefore, we do a quick sanity check. * * If compiling Thumb-1 for a target which supports ARM instructions, we will * emit a warning, as it is not a "sane" platform to compile for. * * Usually, if this happens, it is because of an accident and you probably need * to specify -march, as you likely meant to compile for a newer architecture. * * Credit: large sections of the vectorial and asm source code paths * have been contributed by @easyaspi314 */ #if defined(__thumb__) && !defined(__thumb2__) && defined(__ARM_ARCH_ISA_ARM) # warning "XXH3 is highly inefficient without ARM or Thumb-2." #endif /* ========================================== * Vectorization detection * ========================================== */ #ifdef XXH_DOXYGEN /*! * @ingroup tuning * @brief Overrides the vectorization implementation chosen for XXH3. * * Can be defined to 0 to disable SIMD or any of the values mentioned in * @ref XXH_VECTOR_TYPE. * * If this is not defined, it uses predefined macros to determine the best * implementation. */ # define XXH_VECTOR XXH_SCALAR /*! * @ingroup tuning * @brief Possible values for @ref XXH_VECTOR. * * Note that these are actually implemented as macros. * * If this is not defined, it is detected automatically. * internal macro XXH_X86DISPATCH overrides this. */ enum XXH_VECTOR_TYPE /* fake enum */ { XXH_SCALAR = 0, /*!< Portable scalar version */ XXH_SSE2 = 1, /*!< * SSE2 for Pentium 4, Opteron, all x86_64. * * @note SSE2 is also guaranteed on Windows 10, macOS, and * Android x86. */ XXH_AVX2 = 2, /*!< AVX2 for Haswell and Bulldozer */ XXH_AVX512 = 3, /*!< AVX512 for Skylake and Icelake */ XXH_NEON = 4, /*!< * NEON for most ARMv7-A, all AArch64, and WASM SIMD128 * via the SIMDeverywhere polyfill provided with the * Emscripten SDK. */ XXH_VSX = 5, /*!< VSX and ZVector for POWER8/z13 (64-bit) */ XXH_SVE = 6, /*!< SVE for some ARMv8-A and ARMv9-A */ }; /*! * @ingroup tuning * @brief Selects the minimum alignment for XXH3's accumulators. * * When using SIMD, this should match the alignment required for said vector * type, so, for example, 32 for AVX2. * * Default: Auto detected. */ # define XXH_ACC_ALIGN 8 #endif /* Actual definition */ #ifndef XXH_DOXYGEN # define XXH_SCALAR 0 # define XXH_SSE2 1 # define XXH_AVX2 2 # define XXH_AVX512 3 # define XXH_NEON 4 # define XXH_VSX 5 # define XXH_SVE 6 #endif #ifndef XXH_VECTOR /* can be defined on command line */ # if defined(__ARM_FEATURE_SVE) # define XXH_VECTOR XXH_SVE # elif ( \ defined(__ARM_NEON__) || defined(__ARM_NEON) /* gcc */ \ || defined(_M_ARM) || defined(_M_ARM64) || defined(_M_ARM64EC) /* msvc */ \ || (defined(__wasm_simd128__) && XXH_HAS_INCLUDE()) /* wasm simd128 via SIMDe */ \ ) && ( \ defined(_WIN32) || defined(__LITTLE_ENDIAN__) /* little endian only */ \ || (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) \ ) # define XXH_VECTOR XXH_NEON # elif defined(__AVX512F__) # define XXH_VECTOR XXH_AVX512 # elif defined(__AVX2__) # define XXH_VECTOR XXH_AVX2 # elif defined(__SSE2__) || defined(_M_AMD64) || defined(_M_X64) || (defined(_M_IX86_FP) && (_M_IX86_FP == 2)) # define XXH_VECTOR XXH_SSE2 # elif (defined(__PPC64__) && defined(__POWER8_VECTOR__)) \ || (defined(__s390x__) && defined(__VEC__)) \ && defined(__GNUC__) /* TODO: IBM XL */ # define XXH_VECTOR XXH_VSX # else # define XXH_VECTOR XXH_SCALAR # endif #endif /* __ARM_FEATURE_SVE is only supported by GCC & Clang. */ #if (XXH_VECTOR == XXH_SVE) && !defined(__ARM_FEATURE_SVE) # ifdef _MSC_VER # pragma warning(once : 4606) # else # warning "__ARM_FEATURE_SVE isn't supported. Use SCALAR instead." # endif # undef XXH_VECTOR # define XXH_VECTOR XXH_SCALAR #endif /* * Controls the alignment of the accumulator, * for compatibility with aligned vector loads, which are usually faster. */ #ifndef XXH_ACC_ALIGN # if defined(XXH_X86DISPATCH) # define XXH_ACC_ALIGN 64 /* for compatibility with avx512 */ # elif XXH_VECTOR == XXH_SCALAR /* scalar */ # define XXH_ACC_ALIGN 8 # elif XXH_VECTOR == XXH_SSE2 /* sse2 */ # define XXH_ACC_ALIGN 16 # elif XXH_VECTOR == XXH_AVX2 /* avx2 */ # define XXH_ACC_ALIGN 32 # elif XXH_VECTOR == XXH_NEON /* neon */ # define XXH_ACC_ALIGN 16 # elif XXH_VECTOR == XXH_VSX /* vsx */ # define XXH_ACC_ALIGN 16 # elif XXH_VECTOR == XXH_AVX512 /* avx512 */ # define XXH_ACC_ALIGN 64 # elif XXH_VECTOR == XXH_SVE /* sve */ # define XXH_ACC_ALIGN 64 # endif #endif #if defined(XXH_X86DISPATCH) || XXH_VECTOR == XXH_SSE2 \ || XXH_VECTOR == XXH_AVX2 || XXH_VECTOR == XXH_AVX512 # define XXH_SEC_ALIGN XXH_ACC_ALIGN #elif XXH_VECTOR == XXH_SVE # define XXH_SEC_ALIGN XXH_ACC_ALIGN #else # define XXH_SEC_ALIGN 8 #endif #if defined(__GNUC__) || defined(__clang__) # define XXH_ALIASING __attribute__((may_alias)) #else # define XXH_ALIASING /* nothing */ #endif /* * UGLY HACK: * GCC usually generates the best code with -O3 for xxHash. * * However, when targeting AVX2, it is overzealous in its unrolling resulting * in code roughly 3/4 the speed of Clang. * * There are other issues, such as GCC splitting _mm256_loadu_si256 into * _mm_loadu_si128 + _mm256_inserti128_si256. This is an optimization which * only applies to Sandy and Ivy Bridge... which don't even support AVX2. * * That is why when compiling the AVX2 version, it is recommended to use either * -O2 -mavx2 -march=haswell * or * -O2 -mavx2 -mno-avx256-split-unaligned-load * for decent performance, or to use Clang instead. * * Fortunately, we can control the first one with a pragma that forces GCC into * -O2, but the other one we can't control without "failed to inline always * inline function due to target mismatch" warnings. */ #if XXH_VECTOR == XXH_AVX2 /* AVX2 */ \ && defined(__GNUC__) && !defined(__clang__) /* GCC, not Clang */ \ && defined(__OPTIMIZE__) && XXH_SIZE_OPT <= 0 /* respect -O0 and -Os */ # pragma GCC push_options # pragma GCC optimize("-O2") #endif #if XXH_VECTOR == XXH_NEON /* * UGLY HACK: While AArch64 GCC on Linux does not seem to care, on macOS, GCC -O3 * optimizes out the entire hashLong loop because of the aliasing violation. * * However, GCC is also inefficient at load-store optimization with vld1q/vst1q, * so the only option is to mark it as aliasing. */ typedef uint64x2_t xxh_aliasing_uint64x2_t XXH_ALIASING; /*! * @internal * @brief `vld1q_u64` but faster and alignment-safe. * * On AArch64, unaligned access is always safe, but on ARMv7-a, it is only * *conditionally* safe (`vld1` has an alignment bit like `movdq[ua]` in x86). * * GCC for AArch64 sees `vld1q_u8` as an intrinsic instead of a load, so it * prohibits load-store optimizations. Therefore, a direct dereference is used. * * Otherwise, `vld1q_u8` is used with `vreinterpretq_u8_u64` to do a safe * unaligned load. */ #if defined(__aarch64__) && defined(__GNUC__) && !defined(__clang__) XXH_FORCE_INLINE uint64x2_t XXH_vld1q_u64(void const* ptr) /* silence -Wcast-align */ { return *(xxh_aliasing_uint64x2_t const *)ptr; } #else XXH_FORCE_INLINE uint64x2_t XXH_vld1q_u64(void const* ptr) { return vreinterpretq_u64_u8(vld1q_u8((uint8_t const*)ptr)); } #endif /*! * @internal * @brief `vmlal_u32` on low and high halves of a vector. * * This is a workaround for AArch64 GCC < 11 which implemented arm_neon.h with * inline assembly and were therefore incapable of merging the `vget_{low, high}_u32` * with `vmlal_u32`. */ #if defined(__aarch64__) && defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 11 XXH_FORCE_INLINE uint64x2_t XXH_vmlal_low_u32(uint64x2_t acc, uint32x4_t lhs, uint32x4_t rhs) { /* Inline assembly is the only way */ __asm__("umlal %0.2d, %1.2s, %2.2s" : "+w" (acc) : "w" (lhs), "w" (rhs)); return acc; } XXH_FORCE_INLINE uint64x2_t XXH_vmlal_high_u32(uint64x2_t acc, uint32x4_t lhs, uint32x4_t rhs) { /* This intrinsic works as expected */ return vmlal_high_u32(acc, lhs, rhs); } #else /* Portable intrinsic versions */ XXH_FORCE_INLINE uint64x2_t XXH_vmlal_low_u32(uint64x2_t acc, uint32x4_t lhs, uint32x4_t rhs) { return vmlal_u32(acc, vget_low_u32(lhs), vget_low_u32(rhs)); } /*! @copydoc XXH_vmlal_low_u32 * Assume the compiler converts this to vmlal_high_u32 on aarch64 */ XXH_FORCE_INLINE uint64x2_t XXH_vmlal_high_u32(uint64x2_t acc, uint32x4_t lhs, uint32x4_t rhs) { return vmlal_u32(acc, vget_high_u32(lhs), vget_high_u32(rhs)); } #endif /*! * @ingroup tuning * @brief Controls the NEON to scalar ratio for XXH3 * * This can be set to 2, 4, 6, or 8. * * ARM Cortex CPUs are _very_ sensitive to how their pipelines are used. * * For example, the Cortex-A73 can dispatch 3 micro-ops per cycle, but only 2 of those * can be NEON. If you are only using NEON instructions, you are only using 2/3 of the CPU * bandwidth. * * This is even more noticeable on the more advanced cores like the Cortex-A76 which * can dispatch 8 micro-ops per cycle, but still only 2 NEON micro-ops at once. * * Therefore, to make the most out of the pipeline, it is beneficial to run 6 NEON lanes * and 2 scalar lanes, which is chosen by default. * * This does not apply to Apple processors or 32-bit processors, which run better with * full NEON. These will default to 8. Additionally, size-optimized builds run 8 lanes. * * This change benefits CPUs with large micro-op buffers without negatively affecting * most other CPUs: * * | Chipset | Dispatch type | NEON only | 6:2 hybrid | Diff. | * |:----------------------|:--------------------|----------:|-----------:|------:| * | Snapdragon 730 (A76) | 2 NEON/8 micro-ops | 8.8 GB/s | 10.1 GB/s | ~16% | * | Snapdragon 835 (A73) | 2 NEON/3 micro-ops | 5.1 GB/s | 5.3 GB/s | ~5% | * | Marvell PXA1928 (A53) | In-order dual-issue | 1.9 GB/s | 1.9 GB/s | 0% | * | Apple M1 | 4 NEON/8 micro-ops | 37.3 GB/s | 36.1 GB/s | ~-3% | * * It also seems to fix some bad codegen on GCC, making it almost as fast as clang. * * When using WASM SIMD128, if this is 2 or 6, SIMDe will scalarize 2 of the lanes meaning * it effectively becomes worse 4. * * @see XXH3_accumulate_512_neon() */ # ifndef XXH3_NEON_LANES # if (defined(__aarch64__) || defined(__arm64__) || defined(_M_ARM64) || defined(_M_ARM64EC)) \ && !defined(__APPLE__) && XXH_SIZE_OPT <= 0 # define XXH3_NEON_LANES 6 # else # define XXH3_NEON_LANES XXH_ACC_NB # endif # endif #endif /* XXH_VECTOR == XXH_NEON */ /* * VSX and Z Vector helpers. * * This is very messy, and any pull requests to clean this up are welcome. * * There are a lot of problems with supporting VSX and s390x, due to * inconsistent intrinsics, spotty coverage, and multiple endiannesses. */ #if XXH_VECTOR == XXH_VSX /* Annoyingly, these headers _may_ define three macros: `bool`, `vector`, * and `pixel`. This is a problem for obvious reasons. * * These keywords are unnecessary; the spec literally says they are * equivalent to `__bool`, `__vector`, and `__pixel` and may be undef'd * after including the header. * * We use pragma push_macro/pop_macro to keep the namespace clean. */ # pragma push_macro("bool") # pragma push_macro("vector") # pragma push_macro("pixel") /* silence potential macro redefined warnings */ # undef bool # undef vector # undef pixel # if defined(__s390x__) # include # else # include # endif /* Restore the original macro values, if applicable. */ # pragma pop_macro("pixel") # pragma pop_macro("vector") # pragma pop_macro("bool") typedef __vector unsigned long long xxh_u64x2; typedef __vector unsigned char xxh_u8x16; typedef __vector unsigned xxh_u32x4; /* * UGLY HACK: Similar to aarch64 macOS GCC, s390x GCC has the same aliasing issue. */ typedef xxh_u64x2 xxh_aliasing_u64x2 XXH_ALIASING; # ifndef XXH_VSX_BE # if defined(__BIG_ENDIAN__) \ || (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) # define XXH_VSX_BE 1 # elif defined(__VEC_ELEMENT_REG_ORDER__) && __VEC_ELEMENT_REG_ORDER__ == __ORDER_BIG_ENDIAN__ # warning "-maltivec=be is not recommended. Please use native endianness." # define XXH_VSX_BE 1 # else # define XXH_VSX_BE 0 # endif # endif /* !defined(XXH_VSX_BE) */ # if XXH_VSX_BE # if defined(__POWER9_VECTOR__) || (defined(__clang__) && defined(__s390x__)) # define XXH_vec_revb vec_revb # else /*! * A polyfill for POWER9's vec_revb(). */ XXH_FORCE_INLINE xxh_u64x2 XXH_vec_revb(xxh_u64x2 val) { xxh_u8x16 const vByteSwap = { 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08 }; return vec_perm(val, val, vByteSwap); } # endif # endif /* XXH_VSX_BE */ /*! * Performs an unaligned vector load and byte swaps it on big endian. */ XXH_FORCE_INLINE xxh_u64x2 XXH_vec_loadu(const void *ptr) { xxh_u64x2 ret; XXH_memcpy(&ret, ptr, sizeof(xxh_u64x2)); # if XXH_VSX_BE ret = XXH_vec_revb(ret); # endif return ret; } /* * vec_mulo and vec_mule are very problematic intrinsics on PowerPC * * These intrinsics weren't added until GCC 8, despite existing for a while, * and they are endian dependent. Also, their meaning swap depending on version. * */ # if defined(__s390x__) /* s390x is always big endian, no issue on this platform */ # define XXH_vec_mulo vec_mulo # define XXH_vec_mule vec_mule # elif defined(__clang__) && XXH_HAS_BUILTIN(__builtin_altivec_vmuleuw) && !defined(__ibmxl__) /* Clang has a better way to control this, we can just use the builtin which doesn't swap. */ /* The IBM XL Compiler (which defined __clang__) only implements the vec_* operations */ # define XXH_vec_mulo __builtin_altivec_vmulouw # define XXH_vec_mule __builtin_altivec_vmuleuw # else /* gcc needs inline assembly */ /* Adapted from https://github.com/google/highwayhash/blob/master/highwayhash/hh_vsx.h. */ XXH_FORCE_INLINE xxh_u64x2 XXH_vec_mulo(xxh_u32x4 a, xxh_u32x4 b) { xxh_u64x2 result; __asm__("vmulouw %0, %1, %2" : "=v" (result) : "v" (a), "v" (b)); return result; } XXH_FORCE_INLINE xxh_u64x2 XXH_vec_mule(xxh_u32x4 a, xxh_u32x4 b) { xxh_u64x2 result; __asm__("vmuleuw %0, %1, %2" : "=v" (result) : "v" (a), "v" (b)); return result; } # endif /* XXH_vec_mulo, XXH_vec_mule */ #endif /* XXH_VECTOR == XXH_VSX */ #if XXH_VECTOR == XXH_SVE #define ACCRND(acc, offset) \ do { \ svuint64_t input_vec = svld1_u64(mask, xinput + offset); \ svuint64_t secret_vec = svld1_u64(mask, xsecret + offset); \ svuint64_t mixed = sveor_u64_x(mask, secret_vec, input_vec); \ svuint64_t swapped = svtbl_u64(input_vec, kSwap); \ svuint64_t mixed_lo = svextw_u64_x(mask, mixed); \ svuint64_t mixed_hi = svlsr_n_u64_x(mask, mixed, 32); \ svuint64_t mul = svmad_u64_x(mask, mixed_lo, mixed_hi, swapped); \ acc = svadd_u64_x(mask, acc, mul); \ } while (0) #endif /* XXH_VECTOR == XXH_SVE */ /* prefetch * can be disabled, by declaring XXH_NO_PREFETCH build macro */ #if defined(XXH_NO_PREFETCH) # define XXH_PREFETCH(ptr) (void)(ptr) /* disabled */ #else # if XXH_SIZE_OPT >= 1 # define XXH_PREFETCH(ptr) (void)(ptr) # elif defined(_MSC_VER) && (defined(_M_X64) || defined(_M_IX86)) /* _mm_prefetch() not defined outside of x86/x64 */ # include /* https://msdn.microsoft.com/fr-fr/library/84szxsww(v=vs.90).aspx */ # define XXH_PREFETCH(ptr) _mm_prefetch((const char*)(ptr), _MM_HINT_T0) # elif defined(__GNUC__) && ( (__GNUC__ >= 4) || ( (__GNUC__ == 3) && (__GNUC_MINOR__ >= 1) ) ) # define XXH_PREFETCH(ptr) __builtin_prefetch((ptr), 0 /* rw==read */, 3 /* locality */) # else # define XXH_PREFETCH(ptr) (void)(ptr) /* disabled */ # endif #endif /* XXH_NO_PREFETCH */ /* ========================================== * XXH3 default settings * ========================================== */ #define XXH_SECRET_DEFAULT_SIZE 192 /* minimum XXH3_SECRET_SIZE_MIN */ #if (XXH_SECRET_DEFAULT_SIZE < XXH3_SECRET_SIZE_MIN) # error "default keyset is not large enough" #endif /*! Pseudorandom secret taken directly from FARSH. */ XXH_ALIGN(64) static const xxh_u8 XXH3_kSecret[XXH_SECRET_DEFAULT_SIZE] = { 0xb8, 0xfe, 0x6c, 0x39, 0x23, 0xa4, 0x4b, 0xbe, 0x7c, 0x01, 0x81, 0x2c, 0xf7, 0x21, 0xad, 0x1c, 0xde, 0xd4, 0x6d, 0xe9, 0x83, 0x90, 0x97, 0xdb, 0x72, 0x40, 0xa4, 0xa4, 0xb7, 0xb3, 0x67, 0x1f, 0xcb, 0x79, 0xe6, 0x4e, 0xcc, 0xc0, 0xe5, 0x78, 0x82, 0x5a, 0xd0, 0x7d, 0xcc, 0xff, 0x72, 0x21, 0xb8, 0x08, 0x46, 0x74, 0xf7, 0x43, 0x24, 0x8e, 0xe0, 0x35, 0x90, 0xe6, 0x81, 0x3a, 0x26, 0x4c, 0x3c, 0x28, 0x52, 0xbb, 0x91, 0xc3, 0x00, 0xcb, 0x88, 0xd0, 0x65, 0x8b, 0x1b, 0x53, 0x2e, 0xa3, 0x71, 0x64, 0x48, 0x97, 0xa2, 0x0d, 0xf9, 0x4e, 0x38, 0x19, 0xef, 0x46, 0xa9, 0xde, 0xac, 0xd8, 0xa8, 0xfa, 0x76, 0x3f, 0xe3, 0x9c, 0x34, 0x3f, 0xf9, 0xdc, 0xbb, 0xc7, 0xc7, 0x0b, 0x4f, 0x1d, 0x8a, 0x51, 0xe0, 0x4b, 0xcd, 0xb4, 0x59, 0x31, 0xc8, 0x9f, 0x7e, 0xc9, 0xd9, 0x78, 0x73, 0x64, 0xea, 0xc5, 0xac, 0x83, 0x34, 0xd3, 0xeb, 0xc3, 0xc5, 0x81, 0xa0, 0xff, 0xfa, 0x13, 0x63, 0xeb, 0x17, 0x0d, 0xdd, 0x51, 0xb7, 0xf0, 0xda, 0x49, 0xd3, 0x16, 0x55, 0x26, 0x29, 0xd4, 0x68, 0x9e, 0x2b, 0x16, 0xbe, 0x58, 0x7d, 0x47, 0xa1, 0xfc, 0x8f, 0xf8, 0xb8, 0xd1, 0x7a, 0xd0, 0x31, 0xce, 0x45, 0xcb, 0x3a, 0x8f, 0x95, 0x16, 0x04, 0x28, 0xaf, 0xd7, 0xfb, 0xca, 0xbb, 0x4b, 0x40, 0x7e, }; static const xxh_u64 PRIME_MX1 = 0x165667919E3779F9ULL; /*!< 0b0001011001010110011001111001000110011110001101110111100111111001 */ static const xxh_u64 PRIME_MX2 = 0x9FB21C651E98DF25ULL; /*!< 0b1001111110110010000111000110010100011110100110001101111100100101 */ #ifdef XXH_OLD_NAMES # define kSecret XXH3_kSecret #endif #ifdef XXH_DOXYGEN /*! * @brief Calculates a 32-bit to 64-bit long multiply. * * Implemented as a macro. * * Wraps `__emulu` on MSVC x86 because it tends to call `__allmul` when it doesn't * need to (but it shouldn't need to anyways, it is about 7 instructions to do * a 64x64 multiply...). Since we know that this will _always_ emit `MULL`, we * use that instead of the normal method. * * If you are compiling for platforms like Thumb-1 and don't have a better option, * you may also want to write your own long multiply routine here. * * @param x, y Numbers to be multiplied * @return 64-bit product of the low 32 bits of @p x and @p y. */ XXH_FORCE_INLINE xxh_u64 XXH_mult32to64(xxh_u64 x, xxh_u64 y) { return (x & 0xFFFFFFFF) * (y & 0xFFFFFFFF); } #elif defined(_MSC_VER) && defined(_M_IX86) # define XXH_mult32to64(x, y) __emulu((unsigned)(x), (unsigned)(y)) #else /* * Downcast + upcast is usually better than masking on older compilers like * GCC 4.2 (especially 32-bit ones), all without affecting newer compilers. * * The other method, (x & 0xFFFFFFFF) * (y & 0xFFFFFFFF), will AND both operands * and perform a full 64x64 multiply -- entirely redundant on 32-bit. */ # define XXH_mult32to64(x, y) ((xxh_u64)(xxh_u32)(x) * (xxh_u64)(xxh_u32)(y)) #endif /*! * @brief Calculates a 64->128-bit long multiply. * * Uses `__uint128_t` and `_umul128` if available, otherwise uses a scalar * version. * * @param lhs , rhs The 64-bit integers to be multiplied * @return The 128-bit result represented in an @ref XXH128_hash_t. */ static XXH128_hash_t XXH_mult64to128(xxh_u64 lhs, xxh_u64 rhs) { /* * GCC/Clang __uint128_t method. * * On most 64-bit targets, GCC and Clang define a __uint128_t type. * This is usually the best way as it usually uses a native long 64-bit * multiply, such as MULQ on x86_64 or MUL + UMULH on aarch64. * * Usually. * * Despite being a 32-bit platform, Clang (and emscripten) define this type * despite not having the arithmetic for it. This results in a laggy * compiler builtin call which calculates a full 128-bit multiply. * In that case it is best to use the portable one. * https://github.com/Cyan4973/xxHash/issues/211#issuecomment-515575677 */ #if (defined(__GNUC__) || defined(__clang__)) && !defined(__wasm__) \ && defined(__SIZEOF_INT128__) \ || (defined(_INTEGRAL_MAX_BITS) && _INTEGRAL_MAX_BITS >= 128) __uint128_t const product = (__uint128_t)lhs * (__uint128_t)rhs; XXH128_hash_t r128; r128.low64 = (xxh_u64)(product); r128.high64 = (xxh_u64)(product >> 64); return r128; /* * MSVC for x64's _umul128 method. * * xxh_u64 _umul128(xxh_u64 Multiplier, xxh_u64 Multiplicand, xxh_u64 *HighProduct); * * This compiles to single operand MUL on x64. */ #elif (defined(_M_X64) || defined(_M_IA64)) && !defined(_M_ARM64EC) #ifndef _MSC_VER # pragma intrinsic(_umul128) #endif xxh_u64 product_high; xxh_u64 const product_low = _umul128(lhs, rhs, &product_high); XXH128_hash_t r128; r128.low64 = product_low; r128.high64 = product_high; return r128; /* * MSVC for ARM64's __umulh method. * * This compiles to the same MUL + UMULH as GCC/Clang's __uint128_t method. */ #elif defined(_M_ARM64) || defined(_M_ARM64EC) #ifndef _MSC_VER # pragma intrinsic(__umulh) #endif XXH128_hash_t r128; r128.low64 = lhs * rhs; r128.high64 = __umulh(lhs, rhs); return r128; #else /* * Portable scalar method. Optimized for 32-bit and 64-bit ALUs. * * This is a fast and simple grade school multiply, which is shown below * with base 10 arithmetic instead of base 0x100000000. * * 9 3 // D2 lhs = 93 * x 7 5 // D2 rhs = 75 * ---------- * 1 5 // D2 lo_lo = (93 % 10) * (75 % 10) = 15 * 4 5 | // D2 hi_lo = (93 / 10) * (75 % 10) = 45 * 2 1 | // D2 lo_hi = (93 % 10) * (75 / 10) = 21 * + 6 3 | | // D2 hi_hi = (93 / 10) * (75 / 10) = 63 * --------- * 2 7 | // D2 cross = (15 / 10) + (45 % 10) + 21 = 27 * + 6 7 | | // D2 upper = (27 / 10) + (45 / 10) + 63 = 67 * --------- * 6 9 7 5 // D4 res = (27 * 10) + (15 % 10) + (67 * 100) = 6975 * * The reasons for adding the products like this are: * 1. It avoids manual carry tracking. Just like how * (9 * 9) + 9 + 9 = 99, the same applies with this for UINT64_MAX. * This avoids a lot of complexity. * * 2. It hints for, and on Clang, compiles to, the powerful UMAAL * instruction available in ARM's Digital Signal Processing extension * in 32-bit ARMv6 and later, which is shown below: * * void UMAAL(xxh_u32 *RdLo, xxh_u32 *RdHi, xxh_u32 Rn, xxh_u32 Rm) * { * xxh_u64 product = (xxh_u64)*RdLo * (xxh_u64)*RdHi + Rn + Rm; * *RdLo = (xxh_u32)(product & 0xFFFFFFFF); * *RdHi = (xxh_u32)(product >> 32); * } * * This instruction was designed for efficient long multiplication, and * allows this to be calculated in only 4 instructions at speeds * comparable to some 64-bit ALUs. * * 3. It isn't terrible on other platforms. Usually this will be a couple * of 32-bit ADD/ADCs. */ /* First calculate all of the cross products. */ xxh_u64 const lo_lo = XXH_mult32to64(lhs & 0xFFFFFFFF, rhs & 0xFFFFFFFF); xxh_u64 const hi_lo = XXH_mult32to64(lhs >> 32, rhs & 0xFFFFFFFF); xxh_u64 const lo_hi = XXH_mult32to64(lhs & 0xFFFFFFFF, rhs >> 32); xxh_u64 const hi_hi = XXH_mult32to64(lhs >> 32, rhs >> 32); /* Now add the products together. These will never overflow. */ xxh_u64 const cross = (lo_lo >> 32) + (hi_lo & 0xFFFFFFFF) + lo_hi; xxh_u64 const upper = (hi_lo >> 32) + (cross >> 32) + hi_hi; xxh_u64 const lower = (cross << 32) | (lo_lo & 0xFFFFFFFF); XXH128_hash_t r128; r128.low64 = lower; r128.high64 = upper; return r128; #endif } /*! * @brief Calculates a 64-bit to 128-bit multiply, then XOR folds it. * * The reason for the separate function is to prevent passing too many structs * around by value. This will hopefully inline the multiply, but we don't force it. * * @param lhs , rhs The 64-bit integers to multiply * @return The low 64 bits of the product XOR'd by the high 64 bits. * @see XXH_mult64to128() */ static xxh_u64 XXH3_mul128_fold64(xxh_u64 lhs, xxh_u64 rhs) { XXH128_hash_t product = XXH_mult64to128(lhs, rhs); return product.low64 ^ product.high64; } /*! Seems to produce slightly better code on GCC for some reason. */ XXH_FORCE_INLINE XXH_CONSTF xxh_u64 XXH_xorshift64(xxh_u64 v64, int shift) { XXH_ASSERT(0 <= shift && shift < 64); return v64 ^ (v64 >> shift); } /* * This is a fast avalanche stage, * suitable when input bits are already partially mixed */ static XXH64_hash_t XXH3_avalanche(xxh_u64 h64) { h64 = XXH_xorshift64(h64, 37); h64 *= PRIME_MX1; h64 = XXH_xorshift64(h64, 32); return h64; } /* * This is a stronger avalanche, * inspired by Pelle Evensen's rrmxmx * preferable when input has not been previously mixed */ static XXH64_hash_t XXH3_rrmxmx(xxh_u64 h64, xxh_u64 len) { /* this mix is inspired by Pelle Evensen's rrmxmx */ h64 ^= XXH_rotl64(h64, 49) ^ XXH_rotl64(h64, 24); h64 *= PRIME_MX2; h64 ^= (h64 >> 35) + len ; h64 *= PRIME_MX2; return XXH_xorshift64(h64, 28); } /* ========================================== * Short keys * ========================================== * One of the shortcomings of XXH32 and XXH64 was that their performance was * sub-optimal on short lengths. It used an iterative algorithm which strongly * favored lengths that were a multiple of 4 or 8. * * Instead of iterating over individual inputs, we use a set of single shot * functions which piece together a range of lengths and operate in constant time. * * Additionally, the number of multiplies has been significantly reduced. This * reduces latency, especially when emulating 64-bit multiplies on 32-bit. * * Depending on the platform, this may or may not be faster than XXH32, but it * is almost guaranteed to be faster than XXH64. */ /* * At very short lengths, there isn't enough input to fully hide secrets, or use * the entire secret. * * There is also only a limited amount of mixing we can do before significantly * impacting performance. * * Therefore, we use different sections of the secret and always mix two secret * samples with an XOR. This should have no effect on performance on the * seedless or withSeed variants because everything _should_ be constant folded * by modern compilers. * * The XOR mixing hides individual parts of the secret and increases entropy. * * This adds an extra layer of strength for custom secrets. */ XXH_FORCE_INLINE XXH_PUREF XXH64_hash_t XXH3_len_1to3_64b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) { XXH_ASSERT(input != NULL); XXH_ASSERT(1 <= len && len <= 3); XXH_ASSERT(secret != NULL); /* * len = 1: combined = { input[0], 0x01, input[0], input[0] } * len = 2: combined = { input[1], 0x02, input[0], input[1] } * len = 3: combined = { input[2], 0x03, input[0], input[1] } */ { xxh_u8 const c1 = input[0]; xxh_u8 const c2 = input[len >> 1]; xxh_u8 const c3 = input[len - 1]; xxh_u32 const combined = ((xxh_u32)c1 << 16) | ((xxh_u32)c2 << 24) | ((xxh_u32)c3 << 0) | ((xxh_u32)len << 8); xxh_u64 const bitflip = (XXH_readLE32(secret) ^ XXH_readLE32(secret+4)) + seed; xxh_u64 const keyed = (xxh_u64)combined ^ bitflip; return XXH64_avalanche(keyed); } } XXH_FORCE_INLINE XXH_PUREF XXH64_hash_t XXH3_len_4to8_64b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) { XXH_ASSERT(input != NULL); XXH_ASSERT(secret != NULL); XXH_ASSERT(4 <= len && len <= 8); seed ^= (xxh_u64)XXH_swap32((xxh_u32)seed) << 32; { xxh_u32 const input1 = XXH_readLE32(input); xxh_u32 const input2 = XXH_readLE32(input + len - 4); xxh_u64 const bitflip = (XXH_readLE64(secret+8) ^ XXH_readLE64(secret+16)) - seed; xxh_u64 const input64 = input2 + (((xxh_u64)input1) << 32); xxh_u64 const keyed = input64 ^ bitflip; return XXH3_rrmxmx(keyed, len); } } XXH_FORCE_INLINE XXH_PUREF XXH64_hash_t XXH3_len_9to16_64b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) { XXH_ASSERT(input != NULL); XXH_ASSERT(secret != NULL); XXH_ASSERT(9 <= len && len <= 16); { xxh_u64 const bitflip1 = (XXH_readLE64(secret+24) ^ XXH_readLE64(secret+32)) + seed; xxh_u64 const bitflip2 = (XXH_readLE64(secret+40) ^ XXH_readLE64(secret+48)) - seed; xxh_u64 const input_lo = XXH_readLE64(input) ^ bitflip1; xxh_u64 const input_hi = XXH_readLE64(input + len - 8) ^ bitflip2; xxh_u64 const acc = len + XXH_swap64(input_lo) + input_hi + XXH3_mul128_fold64(input_lo, input_hi); return XXH3_avalanche(acc); } } XXH_FORCE_INLINE XXH_PUREF XXH64_hash_t XXH3_len_0to16_64b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) { XXH_ASSERT(len <= 16); { if (XXH_likely(len > 8)) return XXH3_len_9to16_64b(input, len, secret, seed); if (XXH_likely(len >= 4)) return XXH3_len_4to8_64b(input, len, secret, seed); if (len) return XXH3_len_1to3_64b(input, len, secret, seed); return XXH64_avalanche(seed ^ (XXH_readLE64(secret+56) ^ XXH_readLE64(secret+64))); } } /* * DISCLAIMER: There are known *seed-dependent* multicollisions here due to * multiplication by zero, affecting hashes of lengths 17 to 240. * * However, they are very unlikely. * * Keep this in mind when using the unseeded XXH3_64bits() variant: As with all * unseeded non-cryptographic hashes, it does not attempt to defend itself * against specially crafted inputs, only random inputs. * * Compared to classic UMAC where a 1 in 2^31 chance of 4 consecutive bytes * cancelling out the secret is taken an arbitrary number of times (addressed * in XXH3_accumulate_512), this collision is very unlikely with random inputs * and/or proper seeding: * * This only has a 1 in 2^63 chance of 8 consecutive bytes cancelling out, in a * function that is only called up to 16 times per hash with up to 240 bytes of * input. * * This is not too bad for a non-cryptographic hash function, especially with * only 64 bit outputs. * * The 128-bit variant (which trades some speed for strength) is NOT affected * by this, although it is always a good idea to use a proper seed if you care * about strength. */ XXH_FORCE_INLINE xxh_u64 XXH3_mix16B(const xxh_u8* XXH_RESTRICT input, const xxh_u8* XXH_RESTRICT secret, xxh_u64 seed64) { #if defined(__GNUC__) && !defined(__clang__) /* GCC, not Clang */ \ && defined(__i386__) && defined(__SSE2__) /* x86 + SSE2 */ \ && !defined(XXH_ENABLE_AUTOVECTORIZE) /* Define to disable like XXH32 hack */ /* * UGLY HACK: * GCC for x86 tends to autovectorize the 128-bit multiply, resulting in * slower code. * * By forcing seed64 into a register, we disrupt the cost model and * cause it to scalarize. See `XXH32_round()` * * FIXME: Clang's output is still _much_ faster -- On an AMD Ryzen 3600, * XXH3_64bits @ len=240 runs at 4.6 GB/s with Clang 9, but 3.3 GB/s on * GCC 9.2, despite both emitting scalar code. * * GCC generates much better scalar code than Clang for the rest of XXH3, * which is why finding a more optimal codepath is an interest. */ XXH_COMPILER_GUARD(seed64); #endif { xxh_u64 const input_lo = XXH_readLE64(input); xxh_u64 const input_hi = XXH_readLE64(input+8); return XXH3_mul128_fold64( input_lo ^ (XXH_readLE64(secret) + seed64), input_hi ^ (XXH_readLE64(secret+8) - seed64) ); } } /* For mid range keys, XXH3 uses a Mum-hash variant. */ XXH_FORCE_INLINE XXH_PUREF XXH64_hash_t XXH3_len_17to128_64b(const xxh_u8* XXH_RESTRICT input, size_t len, const xxh_u8* XXH_RESTRICT secret, size_t secretSize, XXH64_hash_t seed) { XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); (void)secretSize; XXH_ASSERT(16 < len && len <= 128); { xxh_u64 acc = len * XXH_PRIME64_1; #if XXH_SIZE_OPT >= 1 /* Smaller and cleaner, but slightly slower. */ unsigned int i = (unsigned int)(len - 1) / 32; do { acc += XXH3_mix16B(input+16 * i, secret+32*i, seed); acc += XXH3_mix16B(input+len-16*(i+1), secret+32*i+16, seed); } while (i-- != 0); #else if (len > 32) { if (len > 64) { if (len > 96) { acc += XXH3_mix16B(input+48, secret+96, seed); acc += XXH3_mix16B(input+len-64, secret+112, seed); } acc += XXH3_mix16B(input+32, secret+64, seed); acc += XXH3_mix16B(input+len-48, secret+80, seed); } acc += XXH3_mix16B(input+16, secret+32, seed); acc += XXH3_mix16B(input+len-32, secret+48, seed); } acc += XXH3_mix16B(input+0, secret+0, seed); acc += XXH3_mix16B(input+len-16, secret+16, seed); #endif return XXH3_avalanche(acc); } } #define XXH3_MIDSIZE_MAX 240 XXH_NO_INLINE XXH_PUREF XXH64_hash_t XXH3_len_129to240_64b(const xxh_u8* XXH_RESTRICT input, size_t len, const xxh_u8* XXH_RESTRICT secret, size_t secretSize, XXH64_hash_t seed) { XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); (void)secretSize; XXH_ASSERT(128 < len && len <= XXH3_MIDSIZE_MAX); #define XXH3_MIDSIZE_STARTOFFSET 3 #define XXH3_MIDSIZE_LASTOFFSET 17 { xxh_u64 acc = len * XXH_PRIME64_1; xxh_u64 acc_end; unsigned int const nbRounds = (unsigned int)len / 16; unsigned int i; XXH_ASSERT(128 < len && len <= XXH3_MIDSIZE_MAX); for (i=0; i<8; i++) { acc += XXH3_mix16B(input+(16*i), secret+(16*i), seed); } /* last bytes */ acc_end = XXH3_mix16B(input + len - 16, secret + XXH3_SECRET_SIZE_MIN - XXH3_MIDSIZE_LASTOFFSET, seed); XXH_ASSERT(nbRounds >= 8); acc = XXH3_avalanche(acc); #if defined(__clang__) /* Clang */ \ && (defined(__ARM_NEON) || defined(__ARM_NEON__)) /* NEON */ \ && !defined(XXH_ENABLE_AUTOVECTORIZE) /* Define to disable */ /* * UGLY HACK: * Clang for ARMv7-A tries to vectorize this loop, similar to GCC x86. * In everywhere else, it uses scalar code. * * For 64->128-bit multiplies, even if the NEON was 100% optimal, it * would still be slower than UMAAL (see XXH_mult64to128). * * Unfortunately, Clang doesn't handle the long multiplies properly and * converts them to the nonexistent "vmulq_u64" intrinsic, which is then * scalarized into an ugly mess of VMOV.32 instructions. * * This mess is difficult to avoid without turning autovectorization * off completely, but they are usually relatively minor and/or not * worth it to fix. * * This loop is the easiest to fix, as unlike XXH32, this pragma * _actually works_ because it is a loop vectorization instead of an * SLP vectorization. */ #pragma clang loop vectorize(disable) #endif for (i=8 ; i < nbRounds; i++) { /* * Prevents clang for unrolling the acc loop and interleaving with this one. */ XXH_COMPILER_GUARD(acc); acc_end += XXH3_mix16B(input+(16*i), secret+(16*(i-8)) + XXH3_MIDSIZE_STARTOFFSET, seed); } return XXH3_avalanche(acc + acc_end); } } /* ======= Long Keys ======= */ #define XXH_STRIPE_LEN 64 #define XXH_SECRET_CONSUME_RATE 8 /* nb of secret bytes consumed at each accumulation */ #define XXH_ACC_NB (XXH_STRIPE_LEN / sizeof(xxh_u64)) #ifdef XXH_OLD_NAMES # define STRIPE_LEN XXH_STRIPE_LEN # define ACC_NB XXH_ACC_NB #endif #ifndef XXH_PREFETCH_DIST # ifdef __clang__ # define XXH_PREFETCH_DIST 320 # else # if (XXH_VECTOR == XXH_AVX512) # define XXH_PREFETCH_DIST 512 # else # define XXH_PREFETCH_DIST 384 # endif # endif /* __clang__ */ #endif /* XXH_PREFETCH_DIST */ /* * These macros are to generate an XXH3_accumulate() function. * The two arguments select the name suffix and target attribute. * * The name of this symbol is XXH3_accumulate_() and it calls * XXH3_accumulate_512_(). * * It may be useful to hand implement this function if the compiler fails to * optimize the inline function. */ #define XXH3_ACCUMULATE_TEMPLATE(name) \ void \ XXH3_accumulate_##name(xxh_u64* XXH_RESTRICT acc, \ const xxh_u8* XXH_RESTRICT input, \ const xxh_u8* XXH_RESTRICT secret, \ size_t nbStripes) \ { \ size_t n; \ for (n = 0; n < nbStripes; n++ ) { \ const xxh_u8* const in = input + n*XXH_STRIPE_LEN; \ XXH_PREFETCH(in + XXH_PREFETCH_DIST); \ XXH3_accumulate_512_##name( \ acc, \ in, \ secret + n*XXH_SECRET_CONSUME_RATE); \ } \ } XXH_FORCE_INLINE void XXH_writeLE64(void* dst, xxh_u64 v64) { if (!XXH_CPU_LITTLE_ENDIAN) v64 = XXH_swap64(v64); XXH_memcpy(dst, &v64, sizeof(v64)); } /* Several intrinsic functions below are supposed to accept __int64 as argument, * as documented in https://software.intel.com/sites/landingpage/IntrinsicsGuide/ . * However, several environments do not define __int64 type, * requiring a workaround. */ #if !defined (__VMS) \ && (defined (__cplusplus) \ || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) ) typedef int64_t xxh_i64; #else /* the following type must have a width of 64-bit */ typedef long long xxh_i64; #endif /* * XXH3_accumulate_512 is the tightest loop for long inputs, and it is the most optimized. * * It is a hardened version of UMAC, based off of FARSH's implementation. * * This was chosen because it adapts quite well to 32-bit, 64-bit, and SIMD * implementations, and it is ridiculously fast. * * We harden it by mixing the original input to the accumulators as well as the product. * * This means that in the (relatively likely) case of a multiply by zero, the * original input is preserved. * * On 128-bit inputs, we swap 64-bit pairs when we add the input to improve * cross-pollination, as otherwise the upper and lower halves would be * essentially independent. * * This doesn't matter on 64-bit hashes since they all get merged together in * the end, so we skip the extra step. * * Both XXH3_64bits and XXH3_128bits use this subroutine. */ #if (XXH_VECTOR == XXH_AVX512) \ || (defined(XXH_DISPATCH_AVX512) && XXH_DISPATCH_AVX512 != 0) #ifndef XXH_TARGET_AVX512 # define XXH_TARGET_AVX512 /* disable attribute target */ #endif XXH_FORCE_INLINE XXH_TARGET_AVX512 void XXH3_accumulate_512_avx512(void* XXH_RESTRICT acc, const void* XXH_RESTRICT input, const void* XXH_RESTRICT secret) { __m512i* const xacc = (__m512i *) acc; XXH_ASSERT((((size_t)acc) & 63) == 0); XXH_STATIC_ASSERT(XXH_STRIPE_LEN == sizeof(__m512i)); { /* data_vec = input[0]; */ __m512i const data_vec = _mm512_loadu_si512 (input); /* key_vec = secret[0]; */ __m512i const key_vec = _mm512_loadu_si512 (secret); /* data_key = data_vec ^ key_vec; */ __m512i const data_key = _mm512_xor_si512 (data_vec, key_vec); /* data_key_lo = data_key >> 32; */ __m512i const data_key_lo = _mm512_srli_epi64 (data_key, 32); /* product = (data_key & 0xffffffff) * (data_key_lo & 0xffffffff); */ __m512i const product = _mm512_mul_epu32 (data_key, data_key_lo); /* xacc[0] += swap(data_vec); */ __m512i const data_swap = _mm512_shuffle_epi32(data_vec, (_MM_PERM_ENUM)_MM_SHUFFLE(1, 0, 3, 2)); __m512i const sum = _mm512_add_epi64(*xacc, data_swap); /* xacc[0] += product; */ *xacc = _mm512_add_epi64(product, sum); } } XXH_FORCE_INLINE XXH_TARGET_AVX512 XXH3_ACCUMULATE_TEMPLATE(avx512) /* * XXH3_scrambleAcc: Scrambles the accumulators to improve mixing. * * Multiplication isn't perfect, as explained by Google in HighwayHash: * * // Multiplication mixes/scrambles bytes 0-7 of the 64-bit result to * // varying degrees. In descending order of goodness, bytes * // 3 4 2 5 1 6 0 7 have quality 228 224 164 160 100 96 36 32. * // As expected, the upper and lower bytes are much worse. * * Source: https://github.com/google/highwayhash/blob/0aaf66b/highwayhash/hh_avx2.h#L291 * * Since our algorithm uses a pseudorandom secret to add some variance into the * mix, we don't need to (or want to) mix as often or as much as HighwayHash does. * * This isn't as tight as XXH3_accumulate, but still written in SIMD to avoid * extraction. * * Both XXH3_64bits and XXH3_128bits use this subroutine. */ XXH_FORCE_INLINE XXH_TARGET_AVX512 void XXH3_scrambleAcc_avx512(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret) { XXH_ASSERT((((size_t)acc) & 63) == 0); XXH_STATIC_ASSERT(XXH_STRIPE_LEN == sizeof(__m512i)); { __m512i* const xacc = (__m512i*) acc; const __m512i prime32 = _mm512_set1_epi32((int)XXH_PRIME32_1); /* xacc[0] ^= (xacc[0] >> 47) */ __m512i const acc_vec = *xacc; __m512i const shifted = _mm512_srli_epi64 (acc_vec, 47); /* xacc[0] ^= secret; */ __m512i const key_vec = _mm512_loadu_si512 (secret); __m512i const data_key = _mm512_ternarylogic_epi32(key_vec, acc_vec, shifted, 0x96 /* key_vec ^ acc_vec ^ shifted */); /* xacc[0] *= XXH_PRIME32_1; */ __m512i const data_key_hi = _mm512_srli_epi64 (data_key, 32); __m512i const prod_lo = _mm512_mul_epu32 (data_key, prime32); __m512i const prod_hi = _mm512_mul_epu32 (data_key_hi, prime32); *xacc = _mm512_add_epi64(prod_lo, _mm512_slli_epi64(prod_hi, 32)); } } XXH_FORCE_INLINE XXH_TARGET_AVX512 void XXH3_initCustomSecret_avx512(void* XXH_RESTRICT customSecret, xxh_u64 seed64) { XXH_STATIC_ASSERT((XXH_SECRET_DEFAULT_SIZE & 63) == 0); XXH_STATIC_ASSERT(XXH_SEC_ALIGN == 64); XXH_ASSERT(((size_t)customSecret & 63) == 0); (void)(&XXH_writeLE64); { int const nbRounds = XXH_SECRET_DEFAULT_SIZE / sizeof(__m512i); __m512i const seed_pos = _mm512_set1_epi64((xxh_i64)seed64); __m512i const seed = _mm512_mask_sub_epi64(seed_pos, 0xAA, _mm512_set1_epi8(0), seed_pos); const __m512i* const src = (const __m512i*) ((const void*) XXH3_kSecret); __m512i* const dest = ( __m512i*) customSecret; int i; XXH_ASSERT(((size_t)src & 63) == 0); /* control alignment */ XXH_ASSERT(((size_t)dest & 63) == 0); for (i=0; i < nbRounds; ++i) { dest[i] = _mm512_add_epi64(_mm512_load_si512(src + i), seed); } } } #endif #if (XXH_VECTOR == XXH_AVX2) \ || (defined(XXH_DISPATCH_AVX2) && XXH_DISPATCH_AVX2 != 0) #ifndef XXH_TARGET_AVX2 # define XXH_TARGET_AVX2 /* disable attribute target */ #endif XXH_FORCE_INLINE XXH_TARGET_AVX2 void XXH3_accumulate_512_avx2( void* XXH_RESTRICT acc, const void* XXH_RESTRICT input, const void* XXH_RESTRICT secret) { XXH_ASSERT((((size_t)acc) & 31) == 0); { __m256i* const xacc = (__m256i *) acc; /* Unaligned. This is mainly for pointer arithmetic, and because * _mm256_loadu_si256 requires a const __m256i * pointer for some reason. */ const __m256i* const xinput = (const __m256i *) input; /* Unaligned. This is mainly for pointer arithmetic, and because * _mm256_loadu_si256 requires a const __m256i * pointer for some reason. */ const __m256i* const xsecret = (const __m256i *) secret; size_t i; for (i=0; i < XXH_STRIPE_LEN/sizeof(__m256i); i++) { /* data_vec = xinput[i]; */ __m256i const data_vec = _mm256_loadu_si256 (xinput+i); /* key_vec = xsecret[i]; */ __m256i const key_vec = _mm256_loadu_si256 (xsecret+i); /* data_key = data_vec ^ key_vec; */ __m256i const data_key = _mm256_xor_si256 (data_vec, key_vec); /* data_key_lo = data_key >> 32; */ __m256i const data_key_lo = _mm256_srli_epi64 (data_key, 32); /* product = (data_key & 0xffffffff) * (data_key_lo & 0xffffffff); */ __m256i const product = _mm256_mul_epu32 (data_key, data_key_lo); /* xacc[i] += swap(data_vec); */ __m256i const data_swap = _mm256_shuffle_epi32(data_vec, _MM_SHUFFLE(1, 0, 3, 2)); __m256i const sum = _mm256_add_epi64(xacc[i], data_swap); /* xacc[i] += product; */ xacc[i] = _mm256_add_epi64(product, sum); } } } XXH_FORCE_INLINE XXH_TARGET_AVX2 XXH3_ACCUMULATE_TEMPLATE(avx2) XXH_FORCE_INLINE XXH_TARGET_AVX2 void XXH3_scrambleAcc_avx2(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret) { XXH_ASSERT((((size_t)acc) & 31) == 0); { __m256i* const xacc = (__m256i*) acc; /* Unaligned. This is mainly for pointer arithmetic, and because * _mm256_loadu_si256 requires a const __m256i * pointer for some reason. */ const __m256i* const xsecret = (const __m256i *) secret; const __m256i prime32 = _mm256_set1_epi32((int)XXH_PRIME32_1); size_t i; for (i=0; i < XXH_STRIPE_LEN/sizeof(__m256i); i++) { /* xacc[i] ^= (xacc[i] >> 47) */ __m256i const acc_vec = xacc[i]; __m256i const shifted = _mm256_srli_epi64 (acc_vec, 47); __m256i const data_vec = _mm256_xor_si256 (acc_vec, shifted); /* xacc[i] ^= xsecret; */ __m256i const key_vec = _mm256_loadu_si256 (xsecret+i); __m256i const data_key = _mm256_xor_si256 (data_vec, key_vec); /* xacc[i] *= XXH_PRIME32_1; */ __m256i const data_key_hi = _mm256_srli_epi64 (data_key, 32); __m256i const prod_lo = _mm256_mul_epu32 (data_key, prime32); __m256i const prod_hi = _mm256_mul_epu32 (data_key_hi, prime32); xacc[i] = _mm256_add_epi64(prod_lo, _mm256_slli_epi64(prod_hi, 32)); } } } XXH_FORCE_INLINE XXH_TARGET_AVX2 void XXH3_initCustomSecret_avx2(void* XXH_RESTRICT customSecret, xxh_u64 seed64) { XXH_STATIC_ASSERT((XXH_SECRET_DEFAULT_SIZE & 31) == 0); XXH_STATIC_ASSERT((XXH_SECRET_DEFAULT_SIZE / sizeof(__m256i)) == 6); XXH_STATIC_ASSERT(XXH_SEC_ALIGN <= 64); (void)(&XXH_writeLE64); XXH_PREFETCH(customSecret); { __m256i const seed = _mm256_set_epi64x((xxh_i64)(0U - seed64), (xxh_i64)seed64, (xxh_i64)(0U - seed64), (xxh_i64)seed64); const __m256i* const src = (const __m256i*) ((const void*) XXH3_kSecret); __m256i* dest = ( __m256i*) customSecret; # if defined(__GNUC__) || defined(__clang__) /* * On GCC & Clang, marking 'dest' as modified will cause the compiler: * - do not extract the secret from sse registers in the internal loop * - use less common registers, and avoid pushing these reg into stack */ XXH_COMPILER_GUARD(dest); # endif XXH_ASSERT(((size_t)src & 31) == 0); /* control alignment */ XXH_ASSERT(((size_t)dest & 31) == 0); /* GCC -O2 need unroll loop manually */ dest[0] = _mm256_add_epi64(_mm256_load_si256(src+0), seed); dest[1] = _mm256_add_epi64(_mm256_load_si256(src+1), seed); dest[2] = _mm256_add_epi64(_mm256_load_si256(src+2), seed); dest[3] = _mm256_add_epi64(_mm256_load_si256(src+3), seed); dest[4] = _mm256_add_epi64(_mm256_load_si256(src+4), seed); dest[5] = _mm256_add_epi64(_mm256_load_si256(src+5), seed); } } #endif /* x86dispatch always generates SSE2 */ #if (XXH_VECTOR == XXH_SSE2) || defined(XXH_X86DISPATCH) #ifndef XXH_TARGET_SSE2 # define XXH_TARGET_SSE2 /* disable attribute target */ #endif XXH_FORCE_INLINE XXH_TARGET_SSE2 void XXH3_accumulate_512_sse2( void* XXH_RESTRICT acc, const void* XXH_RESTRICT input, const void* XXH_RESTRICT secret) { /* SSE2 is just a half-scale version of the AVX2 version. */ XXH_ASSERT((((size_t)acc) & 15) == 0); { __m128i* const xacc = (__m128i *) acc; /* Unaligned. This is mainly for pointer arithmetic, and because * _mm_loadu_si128 requires a const __m128i * pointer for some reason. */ const __m128i* const xinput = (const __m128i *) input; /* Unaligned. This is mainly for pointer arithmetic, and because * _mm_loadu_si128 requires a const __m128i * pointer for some reason. */ const __m128i* const xsecret = (const __m128i *) secret; size_t i; for (i=0; i < XXH_STRIPE_LEN/sizeof(__m128i); i++) { /* data_vec = xinput[i]; */ __m128i const data_vec = _mm_loadu_si128 (xinput+i); /* key_vec = xsecret[i]; */ __m128i const key_vec = _mm_loadu_si128 (xsecret+i); /* data_key = data_vec ^ key_vec; */ __m128i const data_key = _mm_xor_si128 (data_vec, key_vec); /* data_key_lo = data_key >> 32; */ __m128i const data_key_lo = _mm_shuffle_epi32 (data_key, _MM_SHUFFLE(0, 3, 0, 1)); /* product = (data_key & 0xffffffff) * (data_key_lo & 0xffffffff); */ __m128i const product = _mm_mul_epu32 (data_key, data_key_lo); /* xacc[i] += swap(data_vec); */ __m128i const data_swap = _mm_shuffle_epi32(data_vec, _MM_SHUFFLE(1,0,3,2)); __m128i const sum = _mm_add_epi64(xacc[i], data_swap); /* xacc[i] += product; */ xacc[i] = _mm_add_epi64(product, sum); } } } XXH_FORCE_INLINE XXH_TARGET_SSE2 XXH3_ACCUMULATE_TEMPLATE(sse2) XXH_FORCE_INLINE XXH_TARGET_SSE2 void XXH3_scrambleAcc_sse2(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret) { XXH_ASSERT((((size_t)acc) & 15) == 0); { __m128i* const xacc = (__m128i*) acc; /* Unaligned. This is mainly for pointer arithmetic, and because * _mm_loadu_si128 requires a const __m128i * pointer for some reason. */ const __m128i* const xsecret = (const __m128i *) secret; const __m128i prime32 = _mm_set1_epi32((int)XXH_PRIME32_1); size_t i; for (i=0; i < XXH_STRIPE_LEN/sizeof(__m128i); i++) { /* xacc[i] ^= (xacc[i] >> 47) */ __m128i const acc_vec = xacc[i]; __m128i const shifted = _mm_srli_epi64 (acc_vec, 47); __m128i const data_vec = _mm_xor_si128 (acc_vec, shifted); /* xacc[i] ^= xsecret[i]; */ __m128i const key_vec = _mm_loadu_si128 (xsecret+i); __m128i const data_key = _mm_xor_si128 (data_vec, key_vec); /* xacc[i] *= XXH_PRIME32_1; */ __m128i const data_key_hi = _mm_shuffle_epi32 (data_key, _MM_SHUFFLE(0, 3, 0, 1)); __m128i const prod_lo = _mm_mul_epu32 (data_key, prime32); __m128i const prod_hi = _mm_mul_epu32 (data_key_hi, prime32); xacc[i] = _mm_add_epi64(prod_lo, _mm_slli_epi64(prod_hi, 32)); } } } XXH_FORCE_INLINE XXH_TARGET_SSE2 void XXH3_initCustomSecret_sse2(void* XXH_RESTRICT customSecret, xxh_u64 seed64) { XXH_STATIC_ASSERT((XXH_SECRET_DEFAULT_SIZE & 15) == 0); (void)(&XXH_writeLE64); { int const nbRounds = XXH_SECRET_DEFAULT_SIZE / sizeof(__m128i); # if defined(_MSC_VER) && defined(_M_IX86) && _MSC_VER < 1900 /* MSVC 32bit mode does not support _mm_set_epi64x before 2015 */ XXH_ALIGN(16) const xxh_i64 seed64x2[2] = { (xxh_i64)seed64, (xxh_i64)(0U - seed64) }; __m128i const seed = _mm_load_si128((__m128i const*)seed64x2); # else __m128i const seed = _mm_set_epi64x((xxh_i64)(0U - seed64), (xxh_i64)seed64); # endif int i; const void* const src16 = XXH3_kSecret; __m128i* dst16 = (__m128i*) customSecret; # if defined(__GNUC__) || defined(__clang__) /* * On GCC & Clang, marking 'dest' as modified will cause the compiler: * - do not extract the secret from sse registers in the internal loop * - use less common registers, and avoid pushing these reg into stack */ XXH_COMPILER_GUARD(dst16); # endif XXH_ASSERT(((size_t)src16 & 15) == 0); /* control alignment */ XXH_ASSERT(((size_t)dst16 & 15) == 0); for (i=0; i < nbRounds; ++i) { dst16[i] = _mm_add_epi64(_mm_load_si128((const __m128i *)src16+i), seed); } } } #endif #if (XXH_VECTOR == XXH_NEON) /* forward declarations for the scalar routines */ XXH_FORCE_INLINE void XXH3_scalarRound(void* XXH_RESTRICT acc, void const* XXH_RESTRICT input, void const* XXH_RESTRICT secret, size_t lane); XXH_FORCE_INLINE void XXH3_scalarScrambleRound(void* XXH_RESTRICT acc, void const* XXH_RESTRICT secret, size_t lane); /*! * @internal * @brief The bulk processing loop for NEON and WASM SIMD128. * * The NEON code path is actually partially scalar when running on AArch64. This * is to optimize the pipelining and can have up to 15% speedup depending on the * CPU, and it also mitigates some GCC codegen issues. * * @see XXH3_NEON_LANES for configuring this and details about this optimization. * * NEON's 32-bit to 64-bit long multiply takes a half vector of 32-bit * integers instead of the other platforms which mask full 64-bit vectors, * so the setup is more complicated than just shifting right. * * Additionally, there is an optimization for 4 lanes at once noted below. * * Since, as stated, the most optimal amount of lanes for Cortexes is 6, * there needs to be *three* versions of the accumulate operation used * for the remaining 2 lanes. * * WASM's SIMD128 uses SIMDe's arm_neon.h polyfill because the intrinsics overlap * nearly perfectly. */ XXH_FORCE_INLINE void XXH3_accumulate_512_neon( void* XXH_RESTRICT acc, const void* XXH_RESTRICT input, const void* XXH_RESTRICT secret) { XXH_ASSERT((((size_t)acc) & 15) == 0); XXH_STATIC_ASSERT(XXH3_NEON_LANES > 0 && XXH3_NEON_LANES <= XXH_ACC_NB && XXH3_NEON_LANES % 2 == 0); { /* GCC for darwin arm64 does not like aliasing here */ xxh_aliasing_uint64x2_t* const xacc = (xxh_aliasing_uint64x2_t*) acc; /* We don't use a uint32x4_t pointer because it causes bus errors on ARMv7. */ uint8_t const* xinput = (const uint8_t *) input; uint8_t const* xsecret = (const uint8_t *) secret; size_t i; #ifdef __wasm_simd128__ /* * On WASM SIMD128, Clang emits direct address loads when XXH3_kSecret * is constant propagated, which results in it converting it to this * inside the loop: * * a = v128.load(XXH3_kSecret + 0 + $secret_offset, offset = 0) * b = v128.load(XXH3_kSecret + 16 + $secret_offset, offset = 0) * ... * * This requires a full 32-bit address immediate (and therefore a 6 byte * instruction) as well as an add for each offset. * * Putting an asm guard prevents it from folding (at the cost of losing * the alignment hint), and uses the free offset in `v128.load` instead * of adding secret_offset each time which overall reduces code size by * about a kilobyte and improves performance. */ XXH_COMPILER_GUARD(xsecret); #endif /* Scalar lanes use the normal scalarRound routine */ for (i = XXH3_NEON_LANES; i < XXH_ACC_NB; i++) { XXH3_scalarRound(acc, input, secret, i); } i = 0; /* 4 NEON lanes at a time. */ for (; i+1 < XXH3_NEON_LANES / 2; i+=2) { /* data_vec = xinput[i]; */ uint64x2_t data_vec_1 = XXH_vld1q_u64(xinput + (i * 16)); uint64x2_t data_vec_2 = XXH_vld1q_u64(xinput + ((i+1) * 16)); /* key_vec = xsecret[i]; */ uint64x2_t key_vec_1 = XXH_vld1q_u64(xsecret + (i * 16)); uint64x2_t key_vec_2 = XXH_vld1q_u64(xsecret + ((i+1) * 16)); /* data_swap = swap(data_vec) */ uint64x2_t data_swap_1 = vextq_u64(data_vec_1, data_vec_1, 1); uint64x2_t data_swap_2 = vextq_u64(data_vec_2, data_vec_2, 1); /* data_key = data_vec ^ key_vec; */ uint64x2_t data_key_1 = veorq_u64(data_vec_1, key_vec_1); uint64x2_t data_key_2 = veorq_u64(data_vec_2, key_vec_2); /* * If we reinterpret the 64x2 vectors as 32x4 vectors, we can use a * de-interleave operation for 4 lanes in 1 step with `vuzpq_u32` to * get one vector with the low 32 bits of each lane, and one vector * with the high 32 bits of each lane. * * The intrinsic returns a double vector because the original ARMv7-a * instruction modified both arguments in place. AArch64 and SIMD128 emit * two instructions from this intrinsic. * * [ dk11L | dk11H | dk12L | dk12H ] -> [ dk11L | dk12L | dk21L | dk22L ] * [ dk21L | dk21H | dk22L | dk22H ] -> [ dk11H | dk12H | dk21H | dk22H ] */ uint32x4x2_t unzipped = vuzpq_u32( vreinterpretq_u32_u64(data_key_1), vreinterpretq_u32_u64(data_key_2) ); /* data_key_lo = data_key & 0xFFFFFFFF */ uint32x4_t data_key_lo = unzipped.val[0]; /* data_key_hi = data_key >> 32 */ uint32x4_t data_key_hi = unzipped.val[1]; /* * Then, we can split the vectors horizontally and multiply which, as for most * widening intrinsics, have a variant that works on both high half vectors * for free on AArch64. A similar instruction is available on SIMD128. * * sum = data_swap + (u64x2) data_key_lo * (u64x2) data_key_hi */ uint64x2_t sum_1 = XXH_vmlal_low_u32(data_swap_1, data_key_lo, data_key_hi); uint64x2_t sum_2 = XXH_vmlal_high_u32(data_swap_2, data_key_lo, data_key_hi); /* * Clang reorders * a += b * c; // umlal swap.2d, dkl.2s, dkh.2s * c += a; // add acc.2d, acc.2d, swap.2d * to * c += a; // add acc.2d, acc.2d, swap.2d * c += b * c; // umlal acc.2d, dkl.2s, dkh.2s * * While it would make sense in theory since the addition is faster, * for reasons likely related to umlal being limited to certain NEON * pipelines, this is worse. A compiler guard fixes this. */ XXH_COMPILER_GUARD_CLANG_NEON(sum_1); XXH_COMPILER_GUARD_CLANG_NEON(sum_2); /* xacc[i] = acc_vec + sum; */ xacc[i] = vaddq_u64(xacc[i], sum_1); xacc[i+1] = vaddq_u64(xacc[i+1], sum_2); } /* Operate on the remaining NEON lanes 2 at a time. */ for (; i < XXH3_NEON_LANES / 2; i++) { /* data_vec = xinput[i]; */ uint64x2_t data_vec = XXH_vld1q_u64(xinput + (i * 16)); /* key_vec = xsecret[i]; */ uint64x2_t key_vec = XXH_vld1q_u64(xsecret + (i * 16)); /* acc_vec_2 = swap(data_vec) */ uint64x2_t data_swap = vextq_u64(data_vec, data_vec, 1); /* data_key = data_vec ^ key_vec; */ uint64x2_t data_key = veorq_u64(data_vec, key_vec); /* For two lanes, just use VMOVN and VSHRN. */ /* data_key_lo = data_key & 0xFFFFFFFF; */ uint32x2_t data_key_lo = vmovn_u64(data_key); /* data_key_hi = data_key >> 32; */ uint32x2_t data_key_hi = vshrn_n_u64(data_key, 32); /* sum = data_swap + (u64x2) data_key_lo * (u64x2) data_key_hi; */ uint64x2_t sum = vmlal_u32(data_swap, data_key_lo, data_key_hi); /* Same Clang workaround as before */ XXH_COMPILER_GUARD_CLANG_NEON(sum); /* xacc[i] = acc_vec + sum; */ xacc[i] = vaddq_u64 (xacc[i], sum); } } } XXH_FORCE_INLINE XXH3_ACCUMULATE_TEMPLATE(neon) XXH_FORCE_INLINE void XXH3_scrambleAcc_neon(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret) { XXH_ASSERT((((size_t)acc) & 15) == 0); { xxh_aliasing_uint64x2_t* xacc = (xxh_aliasing_uint64x2_t*) acc; uint8_t const* xsecret = (uint8_t const*) secret; size_t i; /* WASM uses operator overloads and doesn't need these. */ #ifndef __wasm_simd128__ /* { prime32_1, prime32_1 } */ uint32x2_t const kPrimeLo = vdup_n_u32(XXH_PRIME32_1); /* { 0, prime32_1, 0, prime32_1 } */ uint32x4_t const kPrimeHi = vreinterpretq_u32_u64(vdupq_n_u64((xxh_u64)XXH_PRIME32_1 << 32)); #endif /* AArch64 uses both scalar and neon at the same time */ for (i = XXH3_NEON_LANES; i < XXH_ACC_NB; i++) { XXH3_scalarScrambleRound(acc, secret, i); } for (i=0; i < XXH3_NEON_LANES / 2; i++) { /* xacc[i] ^= (xacc[i] >> 47); */ uint64x2_t acc_vec = xacc[i]; uint64x2_t shifted = vshrq_n_u64(acc_vec, 47); uint64x2_t data_vec = veorq_u64(acc_vec, shifted); /* xacc[i] ^= xsecret[i]; */ uint64x2_t key_vec = XXH_vld1q_u64(xsecret + (i * 16)); uint64x2_t data_key = veorq_u64(data_vec, key_vec); /* xacc[i] *= XXH_PRIME32_1 */ #ifdef __wasm_simd128__ /* SIMD128 has multiply by u64x2, use it instead of expanding and scalarizing */ xacc[i] = data_key * XXH_PRIME32_1; #else /* * Expanded version with portable NEON intrinsics * * lo(x) * lo(y) + (hi(x) * lo(y) << 32) * * prod_hi = hi(data_key) * lo(prime) << 32 * * Since we only need 32 bits of this multiply a trick can be used, reinterpreting the vector * as a uint32x4_t and multiplying by { 0, prime, 0, prime } to cancel out the unwanted bits * and avoid the shift. */ uint32x4_t prod_hi = vmulq_u32 (vreinterpretq_u32_u64(data_key), kPrimeHi); /* Extract low bits for vmlal_u32 */ uint32x2_t data_key_lo = vmovn_u64(data_key); /* xacc[i] = prod_hi + lo(data_key) * XXH_PRIME32_1; */ xacc[i] = vmlal_u32(vreinterpretq_u64_u32(prod_hi), data_key_lo, kPrimeLo); #endif } } } #endif #if (XXH_VECTOR == XXH_VSX) XXH_FORCE_INLINE void XXH3_accumulate_512_vsx( void* XXH_RESTRICT acc, const void* XXH_RESTRICT input, const void* XXH_RESTRICT secret) { /* presumed aligned */ xxh_aliasing_u64x2* const xacc = (xxh_aliasing_u64x2*) acc; xxh_u8 const* const xinput = (xxh_u8 const*) input; /* no alignment restriction */ xxh_u8 const* const xsecret = (xxh_u8 const*) secret; /* no alignment restriction */ xxh_u64x2 const v32 = { 32, 32 }; size_t i; for (i = 0; i < XXH_STRIPE_LEN / sizeof(xxh_u64x2); i++) { /* data_vec = xinput[i]; */ xxh_u64x2 const data_vec = XXH_vec_loadu(xinput + 16*i); /* key_vec = xsecret[i]; */ xxh_u64x2 const key_vec = XXH_vec_loadu(xsecret + 16*i); xxh_u64x2 const data_key = data_vec ^ key_vec; /* shuffled = (data_key << 32) | (data_key >> 32); */ xxh_u32x4 const shuffled = (xxh_u32x4)vec_rl(data_key, v32); /* product = ((xxh_u64x2)data_key & 0xFFFFFFFF) * ((xxh_u64x2)shuffled & 0xFFFFFFFF); */ xxh_u64x2 const product = XXH_vec_mulo((xxh_u32x4)data_key, shuffled); /* acc_vec = xacc[i]; */ xxh_u64x2 acc_vec = xacc[i]; acc_vec += product; /* swap high and low halves */ #ifdef __s390x__ acc_vec += vec_permi(data_vec, data_vec, 2); #else acc_vec += vec_xxpermdi(data_vec, data_vec, 2); #endif xacc[i] = acc_vec; } } XXH_FORCE_INLINE XXH3_ACCUMULATE_TEMPLATE(vsx) XXH_FORCE_INLINE void XXH3_scrambleAcc_vsx(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret) { XXH_ASSERT((((size_t)acc) & 15) == 0); { xxh_aliasing_u64x2* const xacc = (xxh_aliasing_u64x2*) acc; const xxh_u8* const xsecret = (const xxh_u8*) secret; /* constants */ xxh_u64x2 const v32 = { 32, 32 }; xxh_u64x2 const v47 = { 47, 47 }; xxh_u32x4 const prime = { XXH_PRIME32_1, XXH_PRIME32_1, XXH_PRIME32_1, XXH_PRIME32_1 }; size_t i; for (i = 0; i < XXH_STRIPE_LEN / sizeof(xxh_u64x2); i++) { /* xacc[i] ^= (xacc[i] >> 47); */ xxh_u64x2 const acc_vec = xacc[i]; xxh_u64x2 const data_vec = acc_vec ^ (acc_vec >> v47); /* xacc[i] ^= xsecret[i]; */ xxh_u64x2 const key_vec = XXH_vec_loadu(xsecret + 16*i); xxh_u64x2 const data_key = data_vec ^ key_vec; /* xacc[i] *= XXH_PRIME32_1 */ /* prod_lo = ((xxh_u64x2)data_key & 0xFFFFFFFF) * ((xxh_u64x2)prime & 0xFFFFFFFF); */ xxh_u64x2 const prod_even = XXH_vec_mule((xxh_u32x4)data_key, prime); /* prod_hi = ((xxh_u64x2)data_key >> 32) * ((xxh_u64x2)prime >> 32); */ xxh_u64x2 const prod_odd = XXH_vec_mulo((xxh_u32x4)data_key, prime); xacc[i] = prod_odd + (prod_even << v32); } } } #endif #if (XXH_VECTOR == XXH_SVE) XXH_FORCE_INLINE void XXH3_accumulate_512_sve( void* XXH_RESTRICT acc, const void* XXH_RESTRICT input, const void* XXH_RESTRICT secret) { uint64_t *xacc = (uint64_t *)acc; const uint64_t *xinput = (const uint64_t *)(const void *)input; const uint64_t *xsecret = (const uint64_t *)(const void *)secret; svuint64_t kSwap = sveor_n_u64_z(svptrue_b64(), svindex_u64(0, 1), 1); uint64_t element_count = svcntd(); if (element_count >= 8) { svbool_t mask = svptrue_pat_b64(SV_VL8); svuint64_t vacc = svld1_u64(mask, xacc); ACCRND(vacc, 0); svst1_u64(mask, xacc, vacc); } else if (element_count == 2) { /* sve128 */ svbool_t mask = svptrue_pat_b64(SV_VL2); svuint64_t acc0 = svld1_u64(mask, xacc + 0); svuint64_t acc1 = svld1_u64(mask, xacc + 2); svuint64_t acc2 = svld1_u64(mask, xacc + 4); svuint64_t acc3 = svld1_u64(mask, xacc + 6); ACCRND(acc0, 0); ACCRND(acc1, 2); ACCRND(acc2, 4); ACCRND(acc3, 6); svst1_u64(mask, xacc + 0, acc0); svst1_u64(mask, xacc + 2, acc1); svst1_u64(mask, xacc + 4, acc2); svst1_u64(mask, xacc + 6, acc3); } else { svbool_t mask = svptrue_pat_b64(SV_VL4); svuint64_t acc0 = svld1_u64(mask, xacc + 0); svuint64_t acc1 = svld1_u64(mask, xacc + 4); ACCRND(acc0, 0); ACCRND(acc1, 4); svst1_u64(mask, xacc + 0, acc0); svst1_u64(mask, xacc + 4, acc1); } } XXH_FORCE_INLINE void XXH3_accumulate_sve(xxh_u64* XXH_RESTRICT acc, const xxh_u8* XXH_RESTRICT input, const xxh_u8* XXH_RESTRICT secret, size_t nbStripes) { if (nbStripes != 0) { uint64_t *xacc = (uint64_t *)acc; const uint64_t *xinput = (const uint64_t *)(const void *)input; const uint64_t *xsecret = (const uint64_t *)(const void *)secret; svuint64_t kSwap = sveor_n_u64_z(svptrue_b64(), svindex_u64(0, 1), 1); uint64_t element_count = svcntd(); if (element_count >= 8) { svbool_t mask = svptrue_pat_b64(SV_VL8); svuint64_t vacc = svld1_u64(mask, xacc + 0); do { /* svprfd(svbool_t, void *, enum svfprop); */ svprfd(mask, xinput + 128, SV_PLDL1STRM); ACCRND(vacc, 0); xinput += 8; xsecret += 1; nbStripes--; } while (nbStripes != 0); svst1_u64(mask, xacc + 0, vacc); } else if (element_count == 2) { /* sve128 */ svbool_t mask = svptrue_pat_b64(SV_VL2); svuint64_t acc0 = svld1_u64(mask, xacc + 0); svuint64_t acc1 = svld1_u64(mask, xacc + 2); svuint64_t acc2 = svld1_u64(mask, xacc + 4); svuint64_t acc3 = svld1_u64(mask, xacc + 6); do { svprfd(mask, xinput + 128, SV_PLDL1STRM); ACCRND(acc0, 0); ACCRND(acc1, 2); ACCRND(acc2, 4); ACCRND(acc3, 6); xinput += 8; xsecret += 1; nbStripes--; } while (nbStripes != 0); svst1_u64(mask, xacc + 0, acc0); svst1_u64(mask, xacc + 2, acc1); svst1_u64(mask, xacc + 4, acc2); svst1_u64(mask, xacc + 6, acc3); } else { svbool_t mask = svptrue_pat_b64(SV_VL4); svuint64_t acc0 = svld1_u64(mask, xacc + 0); svuint64_t acc1 = svld1_u64(mask, xacc + 4); do { svprfd(mask, xinput + 128, SV_PLDL1STRM); ACCRND(acc0, 0); ACCRND(acc1, 4); xinput += 8; xsecret += 1; nbStripes--; } while (nbStripes != 0); svst1_u64(mask, xacc + 0, acc0); svst1_u64(mask, xacc + 4, acc1); } } } #endif /* scalar variants - universal */ #if defined(__aarch64__) && (defined(__GNUC__) || defined(__clang__)) /* * In XXH3_scalarRound(), GCC and Clang have a similar codegen issue, where they * emit an excess mask and a full 64-bit multiply-add (MADD X-form). * * While this might not seem like much, as AArch64 is a 64-bit architecture, only * big Cortex designs have a full 64-bit multiplier. * * On the little cores, the smaller 32-bit multiplier is used, and full 64-bit * multiplies expand to 2-3 multiplies in microcode. This has a major penalty * of up to 4 latency cycles and 2 stall cycles in the multiply pipeline. * * Thankfully, AArch64 still provides the 32-bit long multiply-add (UMADDL) which does * not have this penalty and does the mask automatically. */ XXH_FORCE_INLINE xxh_u64 XXH_mult32to64_add64(xxh_u64 lhs, xxh_u64 rhs, xxh_u64 acc) { xxh_u64 ret; /* note: %x = 64-bit register, %w = 32-bit register */ __asm__("umaddl %x0, %w1, %w2, %x3" : "=r" (ret) : "r" (lhs), "r" (rhs), "r" (acc)); return ret; } #else XXH_FORCE_INLINE xxh_u64 XXH_mult32to64_add64(xxh_u64 lhs, xxh_u64 rhs, xxh_u64 acc) { return XXH_mult32to64((xxh_u32)lhs, (xxh_u32)rhs) + acc; } #endif /*! * @internal * @brief Scalar round for @ref XXH3_accumulate_512_scalar(). * * This is extracted to its own function because the NEON path uses a combination * of NEON and scalar. */ XXH_FORCE_INLINE void XXH3_scalarRound(void* XXH_RESTRICT acc, void const* XXH_RESTRICT input, void const* XXH_RESTRICT secret, size_t lane) { xxh_u64* xacc = (xxh_u64*) acc; xxh_u8 const* xinput = (xxh_u8 const*) input; xxh_u8 const* xsecret = (xxh_u8 const*) secret; XXH_ASSERT(lane < XXH_ACC_NB); XXH_ASSERT(((size_t)acc & (XXH_ACC_ALIGN-1)) == 0); { xxh_u64 const data_val = XXH_readLE64(xinput + lane * 8); xxh_u64 const data_key = data_val ^ XXH_readLE64(xsecret + lane * 8); xacc[lane ^ 1] += data_val; /* swap adjacent lanes */ xacc[lane] = XXH_mult32to64_add64(data_key /* & 0xFFFFFFFF */, data_key >> 32, xacc[lane]); } } /*! * @internal * @brief Processes a 64 byte block of data using the scalar path. */ XXH_FORCE_INLINE void XXH3_accumulate_512_scalar(void* XXH_RESTRICT acc, const void* XXH_RESTRICT input, const void* XXH_RESTRICT secret) { size_t i; /* ARM GCC refuses to unroll this loop, resulting in a 24% slowdown on ARMv6. */ #if defined(__GNUC__) && !defined(__clang__) \ && (defined(__arm__) || defined(__thumb2__)) \ && defined(__ARM_FEATURE_UNALIGNED) /* no unaligned access just wastes bytes */ \ && XXH_SIZE_OPT <= 0 # pragma GCC unroll 8 #endif for (i=0; i < XXH_ACC_NB; i++) { XXH3_scalarRound(acc, input, secret, i); } } XXH_FORCE_INLINE XXH3_ACCUMULATE_TEMPLATE(scalar) /*! * @internal * @brief Scalar scramble step for @ref XXH3_scrambleAcc_scalar(). * * This is extracted to its own function because the NEON path uses a combination * of NEON and scalar. */ XXH_FORCE_INLINE void XXH3_scalarScrambleRound(void* XXH_RESTRICT acc, void const* XXH_RESTRICT secret, size_t lane) { xxh_u64* const xacc = (xxh_u64*) acc; /* presumed aligned */ const xxh_u8* const xsecret = (const xxh_u8*) secret; /* no alignment restriction */ XXH_ASSERT((((size_t)acc) & (XXH_ACC_ALIGN-1)) == 0); XXH_ASSERT(lane < XXH_ACC_NB); { xxh_u64 const key64 = XXH_readLE64(xsecret + lane * 8); xxh_u64 acc64 = xacc[lane]; acc64 = XXH_xorshift64(acc64, 47); acc64 ^= key64; acc64 *= XXH_PRIME32_1; xacc[lane] = acc64; } } /*! * @internal * @brief Scrambles the accumulators after a large chunk has been read */ XXH_FORCE_INLINE void XXH3_scrambleAcc_scalar(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret) { size_t i; for (i=0; i < XXH_ACC_NB; i++) { XXH3_scalarScrambleRound(acc, secret, i); } } XXH_FORCE_INLINE void XXH3_initCustomSecret_scalar(void* XXH_RESTRICT customSecret, xxh_u64 seed64) { /* * We need a separate pointer for the hack below, * which requires a non-const pointer. * Any decent compiler will optimize this out otherwise. */ const xxh_u8* kSecretPtr = XXH3_kSecret; XXH_STATIC_ASSERT((XXH_SECRET_DEFAULT_SIZE & 15) == 0); #if defined(__GNUC__) && defined(__aarch64__) /* * UGLY HACK: * GCC and Clang generate a bunch of MOV/MOVK pairs for aarch64, and they are * placed sequentially, in order, at the top of the unrolled loop. * * While MOVK is great for generating constants (2 cycles for a 64-bit * constant compared to 4 cycles for LDR), it fights for bandwidth with * the arithmetic instructions. * * I L S * MOVK * MOVK * MOVK * MOVK * ADD * SUB STR * STR * By forcing loads from memory (as the asm line causes the compiler to assume * that XXH3_kSecretPtr has been changed), the pipelines are used more * efficiently: * I L S * LDR * ADD LDR * SUB STR * STR * * See XXH3_NEON_LANES for details on the pipsline. * * XXH3_64bits_withSeed, len == 256, Snapdragon 835 * without hack: 2654.4 MB/s * with hack: 3202.9 MB/s */ XXH_COMPILER_GUARD(kSecretPtr); #endif { int const nbRounds = XXH_SECRET_DEFAULT_SIZE / 16; int i; for (i=0; i < nbRounds; i++) { /* * The asm hack causes the compiler to assume that kSecretPtr aliases with * customSecret, and on aarch64, this prevented LDP from merging two * loads together for free. Putting the loads together before the stores * properly generates LDP. */ xxh_u64 lo = XXH_readLE64(kSecretPtr + 16*i) + seed64; xxh_u64 hi = XXH_readLE64(kSecretPtr + 16*i + 8) - seed64; XXH_writeLE64((xxh_u8*)customSecret + 16*i, lo); XXH_writeLE64((xxh_u8*)customSecret + 16*i + 8, hi); } } } typedef void (*XXH3_f_accumulate)(xxh_u64* XXH_RESTRICT, const xxh_u8* XXH_RESTRICT, const xxh_u8* XXH_RESTRICT, size_t); typedef void (*XXH3_f_scrambleAcc)(void* XXH_RESTRICT, const void*); typedef void (*XXH3_f_initCustomSecret)(void* XXH_RESTRICT, xxh_u64); #if (XXH_VECTOR == XXH_AVX512) #define XXH3_accumulate_512 XXH3_accumulate_512_avx512 #define XXH3_accumulate XXH3_accumulate_avx512 #define XXH3_scrambleAcc XXH3_scrambleAcc_avx512 #define XXH3_initCustomSecret XXH3_initCustomSecret_avx512 #elif (XXH_VECTOR == XXH_AVX2) #define XXH3_accumulate_512 XXH3_accumulate_512_avx2 #define XXH3_accumulate XXH3_accumulate_avx2 #define XXH3_scrambleAcc XXH3_scrambleAcc_avx2 #define XXH3_initCustomSecret XXH3_initCustomSecret_avx2 #elif (XXH_VECTOR == XXH_SSE2) #define XXH3_accumulate_512 XXH3_accumulate_512_sse2 #define XXH3_accumulate XXH3_accumulate_sse2 #define XXH3_scrambleAcc XXH3_scrambleAcc_sse2 #define XXH3_initCustomSecret XXH3_initCustomSecret_sse2 #elif (XXH_VECTOR == XXH_NEON) #define XXH3_accumulate_512 XXH3_accumulate_512_neon #define XXH3_accumulate XXH3_accumulate_neon #define XXH3_scrambleAcc XXH3_scrambleAcc_neon #define XXH3_initCustomSecret XXH3_initCustomSecret_scalar #elif (XXH_VECTOR == XXH_VSX) #define XXH3_accumulate_512 XXH3_accumulate_512_vsx #define XXH3_accumulate XXH3_accumulate_vsx #define XXH3_scrambleAcc XXH3_scrambleAcc_vsx #define XXH3_initCustomSecret XXH3_initCustomSecret_scalar #elif (XXH_VECTOR == XXH_SVE) #define XXH3_accumulate_512 XXH3_accumulate_512_sve #define XXH3_accumulate XXH3_accumulate_sve #define XXH3_scrambleAcc XXH3_scrambleAcc_scalar #define XXH3_initCustomSecret XXH3_initCustomSecret_scalar #else /* scalar */ #define XXH3_accumulate_512 XXH3_accumulate_512_scalar #define XXH3_accumulate XXH3_accumulate_scalar #define XXH3_scrambleAcc XXH3_scrambleAcc_scalar #define XXH3_initCustomSecret XXH3_initCustomSecret_scalar #endif #if XXH_SIZE_OPT >= 1 /* don't do SIMD for initialization */ # undef XXH3_initCustomSecret # define XXH3_initCustomSecret XXH3_initCustomSecret_scalar #endif XXH_FORCE_INLINE void XXH3_hashLong_internal_loop(xxh_u64* XXH_RESTRICT acc, const xxh_u8* XXH_RESTRICT input, size_t len, const xxh_u8* XXH_RESTRICT secret, size_t secretSize, XXH3_f_accumulate f_acc, XXH3_f_scrambleAcc f_scramble) { size_t const nbStripesPerBlock = (secretSize - XXH_STRIPE_LEN) / XXH_SECRET_CONSUME_RATE; size_t const block_len = XXH_STRIPE_LEN * nbStripesPerBlock; size_t const nb_blocks = (len - 1) / block_len; size_t n; XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); for (n = 0; n < nb_blocks; n++) { f_acc(acc, input + n*block_len, secret, nbStripesPerBlock); f_scramble(acc, secret + secretSize - XXH_STRIPE_LEN); } /* last partial block */ XXH_ASSERT(len > XXH_STRIPE_LEN); { size_t const nbStripes = ((len - 1) - (block_len * nb_blocks)) / XXH_STRIPE_LEN; XXH_ASSERT(nbStripes <= (secretSize / XXH_SECRET_CONSUME_RATE)); f_acc(acc, input + nb_blocks*block_len, secret, nbStripes); /* last stripe */ { const xxh_u8* const p = input + len - XXH_STRIPE_LEN; #define XXH_SECRET_LASTACC_START 7 /* not aligned on 8, last secret is different from acc & scrambler */ XXH3_accumulate_512(acc, p, secret + secretSize - XXH_STRIPE_LEN - XXH_SECRET_LASTACC_START); } } } XXH_FORCE_INLINE xxh_u64 XXH3_mix2Accs(const xxh_u64* XXH_RESTRICT acc, const xxh_u8* XXH_RESTRICT secret) { return XXH3_mul128_fold64( acc[0] ^ XXH_readLE64(secret), acc[1] ^ XXH_readLE64(secret+8) ); } static XXH64_hash_t XXH3_mergeAccs(const xxh_u64* XXH_RESTRICT acc, const xxh_u8* XXH_RESTRICT secret, xxh_u64 start) { xxh_u64 result64 = start; size_t i = 0; for (i = 0; i < 4; i++) { result64 += XXH3_mix2Accs(acc+2*i, secret + 16*i); #if defined(__clang__) /* Clang */ \ && (defined(__arm__) || defined(__thumb__)) /* ARMv7 */ \ && (defined(__ARM_NEON) || defined(__ARM_NEON__)) /* NEON */ \ && !defined(XXH_ENABLE_AUTOVECTORIZE) /* Define to disable */ /* * UGLY HACK: * Prevent autovectorization on Clang ARMv7-a. Exact same problem as * the one in XXH3_len_129to240_64b. Speeds up shorter keys > 240b. * XXH3_64bits, len == 256, Snapdragon 835: * without hack: 2063.7 MB/s * with hack: 2560.7 MB/s */ XXH_COMPILER_GUARD(result64); #endif } return XXH3_avalanche(result64); } #define XXH3_INIT_ACC { XXH_PRIME32_3, XXH_PRIME64_1, XXH_PRIME64_2, XXH_PRIME64_3, \ XXH_PRIME64_4, XXH_PRIME32_2, XXH_PRIME64_5, XXH_PRIME32_1 } XXH_FORCE_INLINE XXH64_hash_t XXH3_hashLong_64b_internal(const void* XXH_RESTRICT input, size_t len, const void* XXH_RESTRICT secret, size_t secretSize, XXH3_f_accumulate f_acc, XXH3_f_scrambleAcc f_scramble) { XXH_ALIGN(XXH_ACC_ALIGN) xxh_u64 acc[XXH_ACC_NB] = XXH3_INIT_ACC; XXH3_hashLong_internal_loop(acc, (const xxh_u8*)input, len, (const xxh_u8*)secret, secretSize, f_acc, f_scramble); /* converge into final hash */ XXH_STATIC_ASSERT(sizeof(acc) == 64); /* do not align on 8, so that the secret is different from the accumulator */ #define XXH_SECRET_MERGEACCS_START 11 XXH_ASSERT(secretSize >= sizeof(acc) + XXH_SECRET_MERGEACCS_START); return XXH3_mergeAccs(acc, (const xxh_u8*)secret + XXH_SECRET_MERGEACCS_START, (xxh_u64)len * XXH_PRIME64_1); } /* * It's important for performance to transmit secret's size (when it's static) * so that the compiler can properly optimize the vectorized loop. * This makes a big performance difference for "medium" keys (<1 KB) when using AVX instruction set. * When the secret size is unknown, or on GCC 12 where the mix of NO_INLINE and FORCE_INLINE * breaks -Og, this is XXH_NO_INLINE. */ XXH3_WITH_SECRET_INLINE XXH64_hash_t XXH3_hashLong_64b_withSecret(const void* XXH_RESTRICT input, size_t len, XXH64_hash_t seed64, const xxh_u8* XXH_RESTRICT secret, size_t secretLen) { (void)seed64; return XXH3_hashLong_64b_internal(input, len, secret, secretLen, XXH3_accumulate, XXH3_scrambleAcc); } /* * It's preferable for performance that XXH3_hashLong is not inlined, * as it results in a smaller function for small data, easier to the instruction cache. * Note that inside this no_inline function, we do inline the internal loop, * and provide a statically defined secret size to allow optimization of vector loop. */ XXH_NO_INLINE XXH_PUREF XXH64_hash_t XXH3_hashLong_64b_default(const void* XXH_RESTRICT input, size_t len, XXH64_hash_t seed64, const xxh_u8* XXH_RESTRICT secret, size_t secretLen) { (void)seed64; (void)secret; (void)secretLen; return XXH3_hashLong_64b_internal(input, len, XXH3_kSecret, sizeof(XXH3_kSecret), XXH3_accumulate, XXH3_scrambleAcc); } /* * XXH3_hashLong_64b_withSeed(): * Generate a custom key based on alteration of default XXH3_kSecret with the seed, * and then use this key for long mode hashing. * * This operation is decently fast but nonetheless costs a little bit of time. * Try to avoid it whenever possible (typically when seed==0). * * It's important for performance that XXH3_hashLong is not inlined. Not sure * why (uop cache maybe?), but the difference is large and easily measurable. */ XXH_FORCE_INLINE XXH64_hash_t XXH3_hashLong_64b_withSeed_internal(const void* input, size_t len, XXH64_hash_t seed, XXH3_f_accumulate f_acc, XXH3_f_scrambleAcc f_scramble, XXH3_f_initCustomSecret f_initSec) { #if XXH_SIZE_OPT <= 0 if (seed == 0) return XXH3_hashLong_64b_internal(input, len, XXH3_kSecret, sizeof(XXH3_kSecret), f_acc, f_scramble); #endif { XXH_ALIGN(XXH_SEC_ALIGN) xxh_u8 secret[XXH_SECRET_DEFAULT_SIZE]; f_initSec(secret, seed); return XXH3_hashLong_64b_internal(input, len, secret, sizeof(secret), f_acc, f_scramble); } } /* * It's important for performance that XXH3_hashLong is not inlined. */ XXH_NO_INLINE XXH64_hash_t XXH3_hashLong_64b_withSeed(const void* XXH_RESTRICT input, size_t len, XXH64_hash_t seed, const xxh_u8* XXH_RESTRICT secret, size_t secretLen) { (void)secret; (void)secretLen; return XXH3_hashLong_64b_withSeed_internal(input, len, seed, XXH3_accumulate, XXH3_scrambleAcc, XXH3_initCustomSecret); } typedef XXH64_hash_t (*XXH3_hashLong64_f)(const void* XXH_RESTRICT, size_t, XXH64_hash_t, const xxh_u8* XXH_RESTRICT, size_t); XXH_FORCE_INLINE XXH64_hash_t XXH3_64bits_internal(const void* XXH_RESTRICT input, size_t len, XXH64_hash_t seed64, const void* XXH_RESTRICT secret, size_t secretLen, XXH3_hashLong64_f f_hashLong) { XXH_ASSERT(secretLen >= XXH3_SECRET_SIZE_MIN); /* * If an action is to be taken if `secretLen` condition is not respected, * it should be done here. * For now, it's a contract pre-condition. * Adding a check and a branch here would cost performance at every hash. * Also, note that function signature doesn't offer room to return an error. */ if (len <= 16) return XXH3_len_0to16_64b((const xxh_u8*)input, len, (const xxh_u8*)secret, seed64); if (len <= 128) return XXH3_len_17to128_64b((const xxh_u8*)input, len, (const xxh_u8*)secret, secretLen, seed64); if (len <= XXH3_MIDSIZE_MAX) return XXH3_len_129to240_64b((const xxh_u8*)input, len, (const xxh_u8*)secret, secretLen, seed64); return f_hashLong(input, len, seed64, (const xxh_u8*)secret, secretLen); } /* === Public entry point === */ /*! @ingroup XXH3_family */ XXH_PUBLIC_API XXH64_hash_t XXH3_64bits(XXH_NOESCAPE const void* input, size_t length) { return XXH3_64bits_internal(input, length, 0, XXH3_kSecret, sizeof(XXH3_kSecret), XXH3_hashLong_64b_default); } /*! @ingroup XXH3_family */ XXH_PUBLIC_API XXH64_hash_t XXH3_64bits_withSecret(XXH_NOESCAPE const void* input, size_t length, XXH_NOESCAPE const void* secret, size_t secretSize) { return XXH3_64bits_internal(input, length, 0, secret, secretSize, XXH3_hashLong_64b_withSecret); } /*! @ingroup XXH3_family */ XXH_PUBLIC_API XXH64_hash_t XXH3_64bits_withSeed(XXH_NOESCAPE const void* input, size_t length, XXH64_hash_t seed) { return XXH3_64bits_internal(input, length, seed, XXH3_kSecret, sizeof(XXH3_kSecret), XXH3_hashLong_64b_withSeed); } XXH_PUBLIC_API XXH64_hash_t XXH3_64bits_withSecretandSeed(XXH_NOESCAPE const void* input, size_t length, XXH_NOESCAPE const void* secret, size_t secretSize, XXH64_hash_t seed) { if (length <= XXH3_MIDSIZE_MAX) return XXH3_64bits_internal(input, length, seed, XXH3_kSecret, sizeof(XXH3_kSecret), NULL); return XXH3_hashLong_64b_withSecret(input, length, seed, (const xxh_u8*)secret, secretSize); } /* === XXH3 streaming === */ #ifndef XXH_NO_STREAM /* * Malloc's a pointer that is always aligned to align. * * This must be freed with `XXH_alignedFree()`. * * malloc typically guarantees 16 byte alignment on 64-bit systems and 8 byte * alignment on 32-bit. This isn't enough for the 32 byte aligned loads in AVX2 * or on 32-bit, the 16 byte aligned loads in SSE2 and NEON. * * This underalignment previously caused a rather obvious crash which went * completely unnoticed due to XXH3_createState() not actually being tested. * Credit to RedSpah for noticing this bug. * * The alignment is done manually: Functions like posix_memalign or _mm_malloc * are avoided: To maintain portability, we would have to write a fallback * like this anyways, and besides, testing for the existence of library * functions without relying on external build tools is impossible. * * The method is simple: Overallocate, manually align, and store the offset * to the original behind the returned pointer. * * Align must be a power of 2 and 8 <= align <= 128. */ static XXH_MALLOCF void* XXH_alignedMalloc(size_t s, size_t align) { XXH_ASSERT(align <= 128 && align >= 8); /* range check */ XXH_ASSERT((align & (align-1)) == 0); /* power of 2 */ XXH_ASSERT(s != 0 && s < (s + align)); /* empty/overflow */ { /* Overallocate to make room for manual realignment and an offset byte */ xxh_u8* base = (xxh_u8*)XXH_malloc(s + align); if (base != NULL) { /* * Get the offset needed to align this pointer. * * Even if the returned pointer is aligned, there will always be * at least one byte to store the offset to the original pointer. */ size_t offset = align - ((size_t)base & (align - 1)); /* base % align */ /* Add the offset for the now-aligned pointer */ xxh_u8* ptr = base + offset; XXH_ASSERT((size_t)ptr % align == 0); /* Store the offset immediately before the returned pointer. */ ptr[-1] = (xxh_u8)offset; return ptr; } return NULL; } } /* * Frees an aligned pointer allocated by XXH_alignedMalloc(). Don't pass * normal malloc'd pointers, XXH_alignedMalloc has a specific data layout. */ static void XXH_alignedFree(void* p) { if (p != NULL) { xxh_u8* ptr = (xxh_u8*)p; /* Get the offset byte we added in XXH_malloc. */ xxh_u8 offset = ptr[-1]; /* Free the original malloc'd pointer */ xxh_u8* base = ptr - offset; XXH_free(base); } } /*! @ingroup XXH3_family */ /*! * @brief Allocate an @ref XXH3_state_t. * * Must be freed with XXH3_freeState(). * @return An allocated XXH3_state_t on success, `NULL` on failure. */ XXH_PUBLIC_API XXH3_state_t* XXH3_createState(void) { XXH3_state_t* const state = (XXH3_state_t*)XXH_alignedMalloc(sizeof(XXH3_state_t), 64); if (state==NULL) return NULL; XXH3_INITSTATE(state); return state; } /*! @ingroup XXH3_family */ /*! * @brief Frees an @ref XXH3_state_t. * * Must be allocated with XXH3_createState(). * @param statePtr A pointer to an @ref XXH3_state_t allocated with @ref XXH3_createState(). * @return XXH_OK. */ XXH_PUBLIC_API XXH_errorcode XXH3_freeState(XXH3_state_t* statePtr) { XXH_alignedFree(statePtr); return XXH_OK; } /*! @ingroup XXH3_family */ XXH_PUBLIC_API void XXH3_copyState(XXH_NOESCAPE XXH3_state_t* dst_state, XXH_NOESCAPE const XXH3_state_t* src_state) { XXH_memcpy(dst_state, src_state, sizeof(*dst_state)); } static void XXH3_reset_internal(XXH3_state_t* statePtr, XXH64_hash_t seed, const void* secret, size_t secretSize) { size_t const initStart = offsetof(XXH3_state_t, bufferedSize); size_t const initLength = offsetof(XXH3_state_t, nbStripesPerBlock) - initStart; XXH_ASSERT(offsetof(XXH3_state_t, nbStripesPerBlock) > initStart); XXH_ASSERT(statePtr != NULL); /* set members from bufferedSize to nbStripesPerBlock (excluded) to 0 */ memset((char*)statePtr + initStart, 0, initLength); statePtr->acc[0] = XXH_PRIME32_3; statePtr->acc[1] = XXH_PRIME64_1; statePtr->acc[2] = XXH_PRIME64_2; statePtr->acc[3] = XXH_PRIME64_3; statePtr->acc[4] = XXH_PRIME64_4; statePtr->acc[5] = XXH_PRIME32_2; statePtr->acc[6] = XXH_PRIME64_5; statePtr->acc[7] = XXH_PRIME32_1; statePtr->seed = seed; statePtr->useSeed = (seed != 0); statePtr->extSecret = (const unsigned char*)secret; XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); statePtr->secretLimit = secretSize - XXH_STRIPE_LEN; statePtr->nbStripesPerBlock = statePtr->secretLimit / XXH_SECRET_CONSUME_RATE; } /*! @ingroup XXH3_family */ XXH_PUBLIC_API XXH_errorcode XXH3_64bits_reset(XXH_NOESCAPE XXH3_state_t* statePtr) { if (statePtr == NULL) return XXH_ERROR; XXH3_reset_internal(statePtr, 0, XXH3_kSecret, XXH_SECRET_DEFAULT_SIZE); return XXH_OK; } /*! @ingroup XXH3_family */ XXH_PUBLIC_API XXH_errorcode XXH3_64bits_reset_withSecret(XXH_NOESCAPE XXH3_state_t* statePtr, XXH_NOESCAPE const void* secret, size_t secretSize) { if (statePtr == NULL) return XXH_ERROR; XXH3_reset_internal(statePtr, 0, secret, secretSize); if (secret == NULL) return XXH_ERROR; if (secretSize < XXH3_SECRET_SIZE_MIN) return XXH_ERROR; return XXH_OK; } /*! @ingroup XXH3_family */ XXH_PUBLIC_API XXH_errorcode XXH3_64bits_reset_withSeed(XXH_NOESCAPE XXH3_state_t* statePtr, XXH64_hash_t seed) { if (statePtr == NULL) return XXH_ERROR; if (seed==0) return XXH3_64bits_reset(statePtr); if ((seed != statePtr->seed) || (statePtr->extSecret != NULL)) XXH3_initCustomSecret(statePtr->customSecret, seed); XXH3_reset_internal(statePtr, seed, NULL, XXH_SECRET_DEFAULT_SIZE); return XXH_OK; } /*! @ingroup XXH3_family */ XXH_PUBLIC_API XXH_errorcode XXH3_64bits_reset_withSecretandSeed(XXH_NOESCAPE XXH3_state_t* statePtr, XXH_NOESCAPE const void* secret, size_t secretSize, XXH64_hash_t seed64) { if (statePtr == NULL) return XXH_ERROR; if (secret == NULL) return XXH_ERROR; if (secretSize < XXH3_SECRET_SIZE_MIN) return XXH_ERROR; XXH3_reset_internal(statePtr, seed64, secret, secretSize); statePtr->useSeed = 1; /* always, even if seed64==0 */ return XXH_OK; } /*! * @internal * @brief Processes a large input for XXH3_update() and XXH3_digest_long(). * * Unlike XXH3_hashLong_internal_loop(), this can process data that overlaps a block. * * @param acc Pointer to the 8 accumulator lanes * @param nbStripesSoFarPtr In/out pointer to the number of leftover stripes in the block* * @param nbStripesPerBlock Number of stripes in a block * @param input Input pointer * @param nbStripes Number of stripes to process * @param secret Secret pointer * @param secretLimit Offset of the last block in @p secret * @param f_acc Pointer to an XXH3_accumulate implementation * @param f_scramble Pointer to an XXH3_scrambleAcc implementation * @return Pointer past the end of @p input after processing */ XXH_FORCE_INLINE const xxh_u8 * XXH3_consumeStripes(xxh_u64* XXH_RESTRICT acc, size_t* XXH_RESTRICT nbStripesSoFarPtr, size_t nbStripesPerBlock, const xxh_u8* XXH_RESTRICT input, size_t nbStripes, const xxh_u8* XXH_RESTRICT secret, size_t secretLimit, XXH3_f_accumulate f_acc, XXH3_f_scrambleAcc f_scramble) { const xxh_u8* initialSecret = secret + *nbStripesSoFarPtr * XXH_SECRET_CONSUME_RATE; /* Process full blocks */ if (nbStripes >= (nbStripesPerBlock - *nbStripesSoFarPtr)) { /* Process the initial partial block... */ size_t nbStripesThisIter = nbStripesPerBlock - *nbStripesSoFarPtr; do { /* Accumulate and scramble */ f_acc(acc, input, initialSecret, nbStripesThisIter); f_scramble(acc, secret + secretLimit); input += nbStripesThisIter * XXH_STRIPE_LEN; nbStripes -= nbStripesThisIter; /* Then continue the loop with the full block size */ nbStripesThisIter = nbStripesPerBlock; initialSecret = secret; } while (nbStripes >= nbStripesPerBlock); *nbStripesSoFarPtr = 0; } /* Process a partial block */ if (nbStripes > 0) { f_acc(acc, input, initialSecret, nbStripes); input += nbStripes * XXH_STRIPE_LEN; *nbStripesSoFarPtr += nbStripes; } /* Return end pointer */ return input; } #ifndef XXH3_STREAM_USE_STACK # if XXH_SIZE_OPT <= 0 && !defined(__clang__) /* clang doesn't need additional stack space */ # define XXH3_STREAM_USE_STACK 1 # endif #endif /* * Both XXH3_64bits_update and XXH3_128bits_update use this routine. */ XXH_FORCE_INLINE XXH_errorcode XXH3_update(XXH3_state_t* XXH_RESTRICT const state, const xxh_u8* XXH_RESTRICT input, size_t len, XXH3_f_accumulate f_acc, XXH3_f_scrambleAcc f_scramble) { if (input==NULL) { XXH_ASSERT(len == 0); return XXH_OK; } XXH_ASSERT(state != NULL); { const xxh_u8* const bEnd = input + len; const unsigned char* const secret = (state->extSecret == NULL) ? state->customSecret : state->extSecret; #if defined(XXH3_STREAM_USE_STACK) && XXH3_STREAM_USE_STACK >= 1 /* For some reason, gcc and MSVC seem to suffer greatly * when operating accumulators directly into state. * Operating into stack space seems to enable proper optimization. * clang, on the other hand, doesn't seem to need this trick */ XXH_ALIGN(XXH_ACC_ALIGN) xxh_u64 acc[8]; XXH_memcpy(acc, state->acc, sizeof(acc)); #else xxh_u64* XXH_RESTRICT const acc = state->acc; #endif state->totalLen += len; XXH_ASSERT(state->bufferedSize <= XXH3_INTERNALBUFFER_SIZE); /* small input : just fill in tmp buffer */ if (len <= XXH3_INTERNALBUFFER_SIZE - state->bufferedSize) { XXH_memcpy(state->buffer + state->bufferedSize, input, len); state->bufferedSize += (XXH32_hash_t)len; return XXH_OK; } /* total input is now > XXH3_INTERNALBUFFER_SIZE */ #define XXH3_INTERNALBUFFER_STRIPES (XXH3_INTERNALBUFFER_SIZE / XXH_STRIPE_LEN) XXH_STATIC_ASSERT(XXH3_INTERNALBUFFER_SIZE % XXH_STRIPE_LEN == 0); /* clean multiple */ /* * Internal buffer is partially filled (always, except at beginning) * Complete it, then consume it. */ if (state->bufferedSize) { size_t const loadSize = XXH3_INTERNALBUFFER_SIZE - state->bufferedSize; XXH_memcpy(state->buffer + state->bufferedSize, input, loadSize); input += loadSize; XXH3_consumeStripes(acc, &state->nbStripesSoFar, state->nbStripesPerBlock, state->buffer, XXH3_INTERNALBUFFER_STRIPES, secret, state->secretLimit, f_acc, f_scramble); state->bufferedSize = 0; } XXH_ASSERT(input < bEnd); if (bEnd - input > XXH3_INTERNALBUFFER_SIZE) { size_t nbStripes = (size_t)(bEnd - 1 - input) / XXH_STRIPE_LEN; input = XXH3_consumeStripes(acc, &state->nbStripesSoFar, state->nbStripesPerBlock, input, nbStripes, secret, state->secretLimit, f_acc, f_scramble); XXH_memcpy(state->buffer + sizeof(state->buffer) - XXH_STRIPE_LEN, input - XXH_STRIPE_LEN, XXH_STRIPE_LEN); } /* Some remaining input (always) : buffer it */ XXH_ASSERT(input < bEnd); XXH_ASSERT(bEnd - input <= XXH3_INTERNALBUFFER_SIZE); XXH_ASSERT(state->bufferedSize == 0); XXH_memcpy(state->buffer, input, (size_t)(bEnd-input)); state->bufferedSize = (XXH32_hash_t)(bEnd-input); #if defined(XXH3_STREAM_USE_STACK) && XXH3_STREAM_USE_STACK >= 1 /* save stack accumulators into state */ XXH_memcpy(state->acc, acc, sizeof(acc)); #endif } return XXH_OK; } /*! @ingroup XXH3_family */ XXH_PUBLIC_API XXH_errorcode XXH3_64bits_update(XXH_NOESCAPE XXH3_state_t* state, XXH_NOESCAPE const void* input, size_t len) { return XXH3_update(state, (const xxh_u8*)input, len, XXH3_accumulate, XXH3_scrambleAcc); } XXH_FORCE_INLINE void XXH3_digest_long (XXH64_hash_t* acc, const XXH3_state_t* state, const unsigned char* secret) { xxh_u8 lastStripe[XXH_STRIPE_LEN]; const xxh_u8* lastStripePtr; /* * Digest on a local copy. This way, the state remains unaltered, and it can * continue ingesting more input afterwards. */ XXH_memcpy(acc, state->acc, sizeof(state->acc)); if (state->bufferedSize >= XXH_STRIPE_LEN) { /* Consume remaining stripes then point to remaining data in buffer */ size_t const nbStripes = (state->bufferedSize - 1) / XXH_STRIPE_LEN; size_t nbStripesSoFar = state->nbStripesSoFar; XXH3_consumeStripes(acc, &nbStripesSoFar, state->nbStripesPerBlock, state->buffer, nbStripes, secret, state->secretLimit, XXH3_accumulate, XXH3_scrambleAcc); lastStripePtr = state->buffer + state->bufferedSize - XXH_STRIPE_LEN; } else { /* bufferedSize < XXH_STRIPE_LEN */ /* Copy to temp buffer */ size_t const catchupSize = XXH_STRIPE_LEN - state->bufferedSize; XXH_ASSERT(state->bufferedSize > 0); /* there is always some input buffered */ XXH_memcpy(lastStripe, state->buffer + sizeof(state->buffer) - catchupSize, catchupSize); XXH_memcpy(lastStripe + catchupSize, state->buffer, state->bufferedSize); lastStripePtr = lastStripe; } /* Last stripe */ XXH3_accumulate_512(acc, lastStripePtr, secret + state->secretLimit - XXH_SECRET_LASTACC_START); } /*! @ingroup XXH3_family */ XXH_PUBLIC_API XXH64_hash_t XXH3_64bits_digest (XXH_NOESCAPE const XXH3_state_t* state) { const unsigned char* const secret = (state->extSecret == NULL) ? state->customSecret : state->extSecret; if (state->totalLen > XXH3_MIDSIZE_MAX) { XXH_ALIGN(XXH_ACC_ALIGN) XXH64_hash_t acc[XXH_ACC_NB]; XXH3_digest_long(acc, state, secret); return XXH3_mergeAccs(acc, secret + XXH_SECRET_MERGEACCS_START, (xxh_u64)state->totalLen * XXH_PRIME64_1); } /* totalLen <= XXH3_MIDSIZE_MAX: digesting a short input */ if (state->useSeed) return XXH3_64bits_withSeed(state->buffer, (size_t)state->totalLen, state->seed); return XXH3_64bits_withSecret(state->buffer, (size_t)(state->totalLen), secret, state->secretLimit + XXH_STRIPE_LEN); } #endif /* !XXH_NO_STREAM */ /* ========================================== * XXH3 128 bits (a.k.a XXH128) * ========================================== * XXH3's 128-bit variant has better mixing and strength than the 64-bit variant, * even without counting the significantly larger output size. * * For example, extra steps are taken to avoid the seed-dependent collisions * in 17-240 byte inputs (See XXH3_mix16B and XXH128_mix32B). * * This strength naturally comes at the cost of some speed, especially on short * lengths. Note that longer hashes are about as fast as the 64-bit version * due to it using only a slight modification of the 64-bit loop. * * XXH128 is also more oriented towards 64-bit machines. It is still extremely * fast for a _128-bit_ hash on 32-bit (it usually clears XXH64). */ XXH_FORCE_INLINE XXH_PUREF XXH128_hash_t XXH3_len_1to3_128b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) { /* A doubled version of 1to3_64b with different constants. */ XXH_ASSERT(input != NULL); XXH_ASSERT(1 <= len && len <= 3); XXH_ASSERT(secret != NULL); /* * len = 1: combinedl = { input[0], 0x01, input[0], input[0] } * len = 2: combinedl = { input[1], 0x02, input[0], input[1] } * len = 3: combinedl = { input[2], 0x03, input[0], input[1] } */ { xxh_u8 const c1 = input[0]; xxh_u8 const c2 = input[len >> 1]; xxh_u8 const c3 = input[len - 1]; xxh_u32 const combinedl = ((xxh_u32)c1 <<16) | ((xxh_u32)c2 << 24) | ((xxh_u32)c3 << 0) | ((xxh_u32)len << 8); xxh_u32 const combinedh = XXH_rotl32(XXH_swap32(combinedl), 13); xxh_u64 const bitflipl = (XXH_readLE32(secret) ^ XXH_readLE32(secret+4)) + seed; xxh_u64 const bitfliph = (XXH_readLE32(secret+8) ^ XXH_readLE32(secret+12)) - seed; xxh_u64 const keyed_lo = (xxh_u64)combinedl ^ bitflipl; xxh_u64 const keyed_hi = (xxh_u64)combinedh ^ bitfliph; XXH128_hash_t h128; h128.low64 = XXH64_avalanche(keyed_lo); h128.high64 = XXH64_avalanche(keyed_hi); return h128; } } XXH_FORCE_INLINE XXH_PUREF XXH128_hash_t XXH3_len_4to8_128b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) { XXH_ASSERT(input != NULL); XXH_ASSERT(secret != NULL); XXH_ASSERT(4 <= len && len <= 8); seed ^= (xxh_u64)XXH_swap32((xxh_u32)seed) << 32; { xxh_u32 const input_lo = XXH_readLE32(input); xxh_u32 const input_hi = XXH_readLE32(input + len - 4); xxh_u64 const input_64 = input_lo + ((xxh_u64)input_hi << 32); xxh_u64 const bitflip = (XXH_readLE64(secret+16) ^ XXH_readLE64(secret+24)) + seed; xxh_u64 const keyed = input_64 ^ bitflip; /* Shift len to the left to ensure it is even, this avoids even multiplies. */ XXH128_hash_t m128 = XXH_mult64to128(keyed, XXH_PRIME64_1 + (len << 2)); m128.high64 += (m128.low64 << 1); m128.low64 ^= (m128.high64 >> 3); m128.low64 = XXH_xorshift64(m128.low64, 35); m128.low64 *= PRIME_MX2; m128.low64 = XXH_xorshift64(m128.low64, 28); m128.high64 = XXH3_avalanche(m128.high64); return m128; } } XXH_FORCE_INLINE XXH_PUREF XXH128_hash_t XXH3_len_9to16_128b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) { XXH_ASSERT(input != NULL); XXH_ASSERT(secret != NULL); XXH_ASSERT(9 <= len && len <= 16); { xxh_u64 const bitflipl = (XXH_readLE64(secret+32) ^ XXH_readLE64(secret+40)) - seed; xxh_u64 const bitfliph = (XXH_readLE64(secret+48) ^ XXH_readLE64(secret+56)) + seed; xxh_u64 const input_lo = XXH_readLE64(input); xxh_u64 input_hi = XXH_readLE64(input + len - 8); XXH128_hash_t m128 = XXH_mult64to128(input_lo ^ input_hi ^ bitflipl, XXH_PRIME64_1); /* * Put len in the middle of m128 to ensure that the length gets mixed to * both the low and high bits in the 128x64 multiply below. */ m128.low64 += (xxh_u64)(len - 1) << 54; input_hi ^= bitfliph; /* * Add the high 32 bits of input_hi to the high 32 bits of m128, then * add the long product of the low 32 bits of input_hi and XXH_PRIME32_2 to * the high 64 bits of m128. * * The best approach to this operation is different on 32-bit and 64-bit. */ if (sizeof(void *) < sizeof(xxh_u64)) { /* 32-bit */ /* * 32-bit optimized version, which is more readable. * * On 32-bit, it removes an ADC and delays a dependency between the two * halves of m128.high64, but it generates an extra mask on 64-bit. */ m128.high64 += (input_hi & 0xFFFFFFFF00000000ULL) + XXH_mult32to64((xxh_u32)input_hi, XXH_PRIME32_2); } else { /* * 64-bit optimized (albeit more confusing) version. * * Uses some properties of addition and multiplication to remove the mask: * * Let: * a = input_hi.lo = (input_hi & 0x00000000FFFFFFFF) * b = input_hi.hi = (input_hi & 0xFFFFFFFF00000000) * c = XXH_PRIME32_2 * * a + (b * c) * Inverse Property: x + y - x == y * a + (b * (1 + c - 1)) * Distributive Property: x * (y + z) == (x * y) + (x * z) * a + (b * 1) + (b * (c - 1)) * Identity Property: x * 1 == x * a + b + (b * (c - 1)) * * Substitute a, b, and c: * input_hi.hi + input_hi.lo + ((xxh_u64)input_hi.lo * (XXH_PRIME32_2 - 1)) * * Since input_hi.hi + input_hi.lo == input_hi, we get this: * input_hi + ((xxh_u64)input_hi.lo * (XXH_PRIME32_2 - 1)) */ m128.high64 += input_hi + XXH_mult32to64((xxh_u32)input_hi, XXH_PRIME32_2 - 1); } /* m128 ^= XXH_swap64(m128 >> 64); */ m128.low64 ^= XXH_swap64(m128.high64); { /* 128x64 multiply: h128 = m128 * XXH_PRIME64_2; */ XXH128_hash_t h128 = XXH_mult64to128(m128.low64, XXH_PRIME64_2); h128.high64 += m128.high64 * XXH_PRIME64_2; h128.low64 = XXH3_avalanche(h128.low64); h128.high64 = XXH3_avalanche(h128.high64); return h128; } } } /* * Assumption: `secret` size is >= XXH3_SECRET_SIZE_MIN */ XXH_FORCE_INLINE XXH_PUREF XXH128_hash_t XXH3_len_0to16_128b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) { XXH_ASSERT(len <= 16); { if (len > 8) return XXH3_len_9to16_128b(input, len, secret, seed); if (len >= 4) return XXH3_len_4to8_128b(input, len, secret, seed); if (len) return XXH3_len_1to3_128b(input, len, secret, seed); { XXH128_hash_t h128; xxh_u64 const bitflipl = XXH_readLE64(secret+64) ^ XXH_readLE64(secret+72); xxh_u64 const bitfliph = XXH_readLE64(secret+80) ^ XXH_readLE64(secret+88); h128.low64 = XXH64_avalanche(seed ^ bitflipl); h128.high64 = XXH64_avalanche( seed ^ bitfliph); return h128; } } } /* * A bit slower than XXH3_mix16B, but handles multiply by zero better. */ XXH_FORCE_INLINE XXH128_hash_t XXH128_mix32B(XXH128_hash_t acc, const xxh_u8* input_1, const xxh_u8* input_2, const xxh_u8* secret, XXH64_hash_t seed) { acc.low64 += XXH3_mix16B (input_1, secret+0, seed); acc.low64 ^= XXH_readLE64(input_2) + XXH_readLE64(input_2 + 8); acc.high64 += XXH3_mix16B (input_2, secret+16, seed); acc.high64 ^= XXH_readLE64(input_1) + XXH_readLE64(input_1 + 8); return acc; } XXH_FORCE_INLINE XXH_PUREF XXH128_hash_t XXH3_len_17to128_128b(const xxh_u8* XXH_RESTRICT input, size_t len, const xxh_u8* XXH_RESTRICT secret, size_t secretSize, XXH64_hash_t seed) { XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); (void)secretSize; XXH_ASSERT(16 < len && len <= 128); { XXH128_hash_t acc; acc.low64 = len * XXH_PRIME64_1; acc.high64 = 0; #if XXH_SIZE_OPT >= 1 { /* Smaller, but slightly slower. */ unsigned int i = (unsigned int)(len - 1) / 32; do { acc = XXH128_mix32B(acc, input+16*i, input+len-16*(i+1), secret+32*i, seed); } while (i-- != 0); } #else if (len > 32) { if (len > 64) { if (len > 96) { acc = XXH128_mix32B(acc, input+48, input+len-64, secret+96, seed); } acc = XXH128_mix32B(acc, input+32, input+len-48, secret+64, seed); } acc = XXH128_mix32B(acc, input+16, input+len-32, secret+32, seed); } acc = XXH128_mix32B(acc, input, input+len-16, secret, seed); #endif { XXH128_hash_t h128; h128.low64 = acc.low64 + acc.high64; h128.high64 = (acc.low64 * XXH_PRIME64_1) + (acc.high64 * XXH_PRIME64_4) + ((len - seed) * XXH_PRIME64_2); h128.low64 = XXH3_avalanche(h128.low64); h128.high64 = (XXH64_hash_t)0 - XXH3_avalanche(h128.high64); return h128; } } } XXH_NO_INLINE XXH_PUREF XXH128_hash_t XXH3_len_129to240_128b(const xxh_u8* XXH_RESTRICT input, size_t len, const xxh_u8* XXH_RESTRICT secret, size_t secretSize, XXH64_hash_t seed) { XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); (void)secretSize; XXH_ASSERT(128 < len && len <= XXH3_MIDSIZE_MAX); { XXH128_hash_t acc; unsigned i; acc.low64 = len * XXH_PRIME64_1; acc.high64 = 0; /* * We set as `i` as offset + 32. We do this so that unchanged * `len` can be used as upper bound. This reaches a sweet spot * where both x86 and aarch64 get simple agen and good codegen * for the loop. */ for (i = 32; i < 160; i += 32) { acc = XXH128_mix32B(acc, input + i - 32, input + i - 16, secret + i - 32, seed); } acc.low64 = XXH3_avalanche(acc.low64); acc.high64 = XXH3_avalanche(acc.high64); /* * NB: `i <= len` will duplicate the last 32-bytes if * len % 32 was zero. This is an unfortunate necessity to keep * the hash result stable. */ for (i=160; i <= len; i += 32) { acc = XXH128_mix32B(acc, input + i - 32, input + i - 16, secret + XXH3_MIDSIZE_STARTOFFSET + i - 160, seed); } /* last bytes */ acc = XXH128_mix32B(acc, input + len - 16, input + len - 32, secret + XXH3_SECRET_SIZE_MIN - XXH3_MIDSIZE_LASTOFFSET - 16, (XXH64_hash_t)0 - seed); { XXH128_hash_t h128; h128.low64 = acc.low64 + acc.high64; h128.high64 = (acc.low64 * XXH_PRIME64_1) + (acc.high64 * XXH_PRIME64_4) + ((len - seed) * XXH_PRIME64_2); h128.low64 = XXH3_avalanche(h128.low64); h128.high64 = (XXH64_hash_t)0 - XXH3_avalanche(h128.high64); return h128; } } } XXH_FORCE_INLINE XXH128_hash_t XXH3_hashLong_128b_internal(const void* XXH_RESTRICT input, size_t len, const xxh_u8* XXH_RESTRICT secret, size_t secretSize, XXH3_f_accumulate f_acc, XXH3_f_scrambleAcc f_scramble) { XXH_ALIGN(XXH_ACC_ALIGN) xxh_u64 acc[XXH_ACC_NB] = XXH3_INIT_ACC; XXH3_hashLong_internal_loop(acc, (const xxh_u8*)input, len, secret, secretSize, f_acc, f_scramble); /* converge into final hash */ XXH_STATIC_ASSERT(sizeof(acc) == 64); XXH_ASSERT(secretSize >= sizeof(acc) + XXH_SECRET_MERGEACCS_START); { XXH128_hash_t h128; h128.low64 = XXH3_mergeAccs(acc, secret + XXH_SECRET_MERGEACCS_START, (xxh_u64)len * XXH_PRIME64_1); h128.high64 = XXH3_mergeAccs(acc, secret + secretSize - sizeof(acc) - XXH_SECRET_MERGEACCS_START, ~((xxh_u64)len * XXH_PRIME64_2)); return h128; } } /* * It's important for performance that XXH3_hashLong() is not inlined. */ XXH_NO_INLINE XXH_PUREF XXH128_hash_t XXH3_hashLong_128b_default(const void* XXH_RESTRICT input, size_t len, XXH64_hash_t seed64, const void* XXH_RESTRICT secret, size_t secretLen) { (void)seed64; (void)secret; (void)secretLen; return XXH3_hashLong_128b_internal(input, len, XXH3_kSecret, sizeof(XXH3_kSecret), XXH3_accumulate, XXH3_scrambleAcc); } /* * It's important for performance to pass @p secretLen (when it's static) * to the compiler, so that it can properly optimize the vectorized loop. * * When the secret size is unknown, or on GCC 12 where the mix of NO_INLINE and FORCE_INLINE * breaks -Og, this is XXH_NO_INLINE. */ XXH3_WITH_SECRET_INLINE XXH128_hash_t XXH3_hashLong_128b_withSecret(const void* XXH_RESTRICT input, size_t len, XXH64_hash_t seed64, const void* XXH_RESTRICT secret, size_t secretLen) { (void)seed64; return XXH3_hashLong_128b_internal(input, len, (const xxh_u8*)secret, secretLen, XXH3_accumulate, XXH3_scrambleAcc); } XXH_FORCE_INLINE XXH128_hash_t XXH3_hashLong_128b_withSeed_internal(const void* XXH_RESTRICT input, size_t len, XXH64_hash_t seed64, XXH3_f_accumulate f_acc, XXH3_f_scrambleAcc f_scramble, XXH3_f_initCustomSecret f_initSec) { if (seed64 == 0) return XXH3_hashLong_128b_internal(input, len, XXH3_kSecret, sizeof(XXH3_kSecret), f_acc, f_scramble); { XXH_ALIGN(XXH_SEC_ALIGN) xxh_u8 secret[XXH_SECRET_DEFAULT_SIZE]; f_initSec(secret, seed64); return XXH3_hashLong_128b_internal(input, len, (const xxh_u8*)secret, sizeof(secret), f_acc, f_scramble); } } /* * It's important for performance that XXH3_hashLong is not inlined. */ XXH_NO_INLINE XXH128_hash_t XXH3_hashLong_128b_withSeed(const void* input, size_t len, XXH64_hash_t seed64, const void* XXH_RESTRICT secret, size_t secretLen) { (void)secret; (void)secretLen; return XXH3_hashLong_128b_withSeed_internal(input, len, seed64, XXH3_accumulate, XXH3_scrambleAcc, XXH3_initCustomSecret); } typedef XXH128_hash_t (*XXH3_hashLong128_f)(const void* XXH_RESTRICT, size_t, XXH64_hash_t, const void* XXH_RESTRICT, size_t); XXH_FORCE_INLINE XXH128_hash_t XXH3_128bits_internal(const void* input, size_t len, XXH64_hash_t seed64, const void* XXH_RESTRICT secret, size_t secretLen, XXH3_hashLong128_f f_hl128) { XXH_ASSERT(secretLen >= XXH3_SECRET_SIZE_MIN); /* * If an action is to be taken if `secret` conditions are not respected, * it should be done here. * For now, it's a contract pre-condition. * Adding a check and a branch here would cost performance at every hash. */ if (len <= 16) return XXH3_len_0to16_128b((const xxh_u8*)input, len, (const xxh_u8*)secret, seed64); if (len <= 128) return XXH3_len_17to128_128b((const xxh_u8*)input, len, (const xxh_u8*)secret, secretLen, seed64); if (len <= XXH3_MIDSIZE_MAX) return XXH3_len_129to240_128b((const xxh_u8*)input, len, (const xxh_u8*)secret, secretLen, seed64); return f_hl128(input, len, seed64, secret, secretLen); } /* === Public XXH128 API === */ /*! @ingroup XXH3_family */ XXH_PUBLIC_API XXH128_hash_t XXH3_128bits(XXH_NOESCAPE const void* input, size_t len) { return XXH3_128bits_internal(input, len, 0, XXH3_kSecret, sizeof(XXH3_kSecret), XXH3_hashLong_128b_default); } /*! @ingroup XXH3_family */ XXH_PUBLIC_API XXH128_hash_t XXH3_128bits_withSecret(XXH_NOESCAPE const void* input, size_t len, XXH_NOESCAPE const void* secret, size_t secretSize) { return XXH3_128bits_internal(input, len, 0, (const xxh_u8*)secret, secretSize, XXH3_hashLong_128b_withSecret); } /*! @ingroup XXH3_family */ XXH_PUBLIC_API XXH128_hash_t XXH3_128bits_withSeed(XXH_NOESCAPE const void* input, size_t len, XXH64_hash_t seed) { return XXH3_128bits_internal(input, len, seed, XXH3_kSecret, sizeof(XXH3_kSecret), XXH3_hashLong_128b_withSeed); } /*! @ingroup XXH3_family */ XXH_PUBLIC_API XXH128_hash_t XXH3_128bits_withSecretandSeed(XXH_NOESCAPE const void* input, size_t len, XXH_NOESCAPE const void* secret, size_t secretSize, XXH64_hash_t seed) { if (len <= XXH3_MIDSIZE_MAX) return XXH3_128bits_internal(input, len, seed, XXH3_kSecret, sizeof(XXH3_kSecret), NULL); return XXH3_hashLong_128b_withSecret(input, len, seed, secret, secretSize); } /*! @ingroup XXH3_family */ XXH_PUBLIC_API XXH128_hash_t XXH128(XXH_NOESCAPE const void* input, size_t len, XXH64_hash_t seed) { return XXH3_128bits_withSeed(input, len, seed); } /* === XXH3 128-bit streaming === */ #ifndef XXH_NO_STREAM /* * All initialization and update functions are identical to 64-bit streaming variant. * The only difference is the finalization routine. */ /*! @ingroup XXH3_family */ XXH_PUBLIC_API XXH_errorcode XXH3_128bits_reset(XXH_NOESCAPE XXH3_state_t* statePtr) { return XXH3_64bits_reset(statePtr); } /*! @ingroup XXH3_family */ XXH_PUBLIC_API XXH_errorcode XXH3_128bits_reset_withSecret(XXH_NOESCAPE XXH3_state_t* statePtr, XXH_NOESCAPE const void* secret, size_t secretSize) { return XXH3_64bits_reset_withSecret(statePtr, secret, secretSize); } /*! @ingroup XXH3_family */ XXH_PUBLIC_API XXH_errorcode XXH3_128bits_reset_withSeed(XXH_NOESCAPE XXH3_state_t* statePtr, XXH64_hash_t seed) { return XXH3_64bits_reset_withSeed(statePtr, seed); } /*! @ingroup XXH3_family */ XXH_PUBLIC_API XXH_errorcode XXH3_128bits_reset_withSecretandSeed(XXH_NOESCAPE XXH3_state_t* statePtr, XXH_NOESCAPE const void* secret, size_t secretSize, XXH64_hash_t seed) { return XXH3_64bits_reset_withSecretandSeed(statePtr, secret, secretSize, seed); } /*! @ingroup XXH3_family */ XXH_PUBLIC_API XXH_errorcode XXH3_128bits_update(XXH_NOESCAPE XXH3_state_t* state, XXH_NOESCAPE const void* input, size_t len) { return XXH3_64bits_update(state, input, len); } /*! @ingroup XXH3_family */ XXH_PUBLIC_API XXH128_hash_t XXH3_128bits_digest (XXH_NOESCAPE const XXH3_state_t* state) { const unsigned char* const secret = (state->extSecret == NULL) ? state->customSecret : state->extSecret; if (state->totalLen > XXH3_MIDSIZE_MAX) { XXH_ALIGN(XXH_ACC_ALIGN) XXH64_hash_t acc[XXH_ACC_NB]; XXH3_digest_long(acc, state, secret); XXH_ASSERT(state->secretLimit + XXH_STRIPE_LEN >= sizeof(acc) + XXH_SECRET_MERGEACCS_START); { XXH128_hash_t h128; h128.low64 = XXH3_mergeAccs(acc, secret + XXH_SECRET_MERGEACCS_START, (xxh_u64)state->totalLen * XXH_PRIME64_1); h128.high64 = XXH3_mergeAccs(acc, secret + state->secretLimit + XXH_STRIPE_LEN - sizeof(acc) - XXH_SECRET_MERGEACCS_START, ~((xxh_u64)state->totalLen * XXH_PRIME64_2)); return h128; } } /* len <= XXH3_MIDSIZE_MAX : short code */ if (state->seed) return XXH3_128bits_withSeed(state->buffer, (size_t)state->totalLen, state->seed); return XXH3_128bits_withSecret(state->buffer, (size_t)(state->totalLen), secret, state->secretLimit + XXH_STRIPE_LEN); } #endif /* !XXH_NO_STREAM */ /* 128-bit utility functions */ #include /* memcmp, memcpy */ /* return : 1 is equal, 0 if different */ /*! @ingroup XXH3_family */ XXH_PUBLIC_API int XXH128_isEqual(XXH128_hash_t h1, XXH128_hash_t h2) { /* note : XXH128_hash_t is compact, it has no padding byte */ return !(memcmp(&h1, &h2, sizeof(h1))); } /* This prototype is compatible with stdlib's qsort(). * @return : >0 if *h128_1 > *h128_2 * <0 if *h128_1 < *h128_2 * =0 if *h128_1 == *h128_2 */ /*! @ingroup XXH3_family */ XXH_PUBLIC_API int XXH128_cmp(XXH_NOESCAPE const void* h128_1, XXH_NOESCAPE const void* h128_2) { XXH128_hash_t const h1 = *(const XXH128_hash_t*)h128_1; XXH128_hash_t const h2 = *(const XXH128_hash_t*)h128_2; int const hcmp = (h1.high64 > h2.high64) - (h2.high64 > h1.high64); /* note : bets that, in most cases, hash values are different */ if (hcmp) return hcmp; return (h1.low64 > h2.low64) - (h2.low64 > h1.low64); } /*====== Canonical representation ======*/ /*! @ingroup XXH3_family */ XXH_PUBLIC_API void XXH128_canonicalFromHash(XXH_NOESCAPE XXH128_canonical_t* dst, XXH128_hash_t hash) { XXH_STATIC_ASSERT(sizeof(XXH128_canonical_t) == sizeof(XXH128_hash_t)); if (XXH_CPU_LITTLE_ENDIAN) { hash.high64 = XXH_swap64(hash.high64); hash.low64 = XXH_swap64(hash.low64); } XXH_memcpy(dst, &hash.high64, sizeof(hash.high64)); XXH_memcpy((char*)dst + sizeof(hash.high64), &hash.low64, sizeof(hash.low64)); } /*! @ingroup XXH3_family */ XXH_PUBLIC_API XXH128_hash_t XXH128_hashFromCanonical(XXH_NOESCAPE const XXH128_canonical_t* src) { XXH128_hash_t h; h.high64 = XXH_readBE64(src); h.low64 = XXH_readBE64(src->digest + 8); return h; } /* ========================================== * Secret generators * ========================================== */ #define XXH_MIN(x, y) (((x) > (y)) ? (y) : (x)) XXH_FORCE_INLINE void XXH3_combine16(void* dst, XXH128_hash_t h128) { XXH_writeLE64( dst, XXH_readLE64(dst) ^ h128.low64 ); XXH_writeLE64( (char*)dst+8, XXH_readLE64((char*)dst+8) ^ h128.high64 ); } /*! @ingroup XXH3_family */ XXH_PUBLIC_API XXH_errorcode XXH3_generateSecret(XXH_NOESCAPE void* secretBuffer, size_t secretSize, XXH_NOESCAPE const void* customSeed, size_t customSeedSize) { #if (XXH_DEBUGLEVEL >= 1) XXH_ASSERT(secretBuffer != NULL); XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); #else /* production mode, assert() are disabled */ if (secretBuffer == NULL) return XXH_ERROR; if (secretSize < XXH3_SECRET_SIZE_MIN) return XXH_ERROR; #endif if (customSeedSize == 0) { customSeed = XXH3_kSecret; customSeedSize = XXH_SECRET_DEFAULT_SIZE; } #if (XXH_DEBUGLEVEL >= 1) XXH_ASSERT(customSeed != NULL); #else if (customSeed == NULL) return XXH_ERROR; #endif /* Fill secretBuffer with a copy of customSeed - repeat as needed */ { size_t pos = 0; while (pos < secretSize) { size_t const toCopy = XXH_MIN((secretSize - pos), customSeedSize); memcpy((char*)secretBuffer + pos, customSeed, toCopy); pos += toCopy; } } { size_t const nbSeg16 = secretSize / 16; size_t n; XXH128_canonical_t scrambler; XXH128_canonicalFromHash(&scrambler, XXH128(customSeed, customSeedSize, 0)); for (n=0; n #include // -------------------------------------------------------------------- // Internals // -------------------------------------------------------------------- typedef union {void* p; DL_FUNC fn;} fn_ptr; #if (defined(R_VERSION) && R_VERSION < R_Version(3, 4, 0)) SEXP R_MakeExternalPtrFn(DL_FUNC p, SEXP tag, SEXP prot); DL_FUNC R_ExternalPtrAddrFn(SEXP s); #endif // -------------------------------------------------------------------- // API for packages that embed cleancall // -------------------------------------------------------------------- // The R API does not have a setter for external function pointers SEXP cleancall_MakeExternalPtrFn(DL_FUNC p, SEXP tag, SEXP prot); void cleancall_SetExternalPtrAddrFn(SEXP s, DL_FUNC p); #define CLEANCALL_METHOD_RECORD \ {"cleancall_call", (DL_FUNC) &cleancall_call, 2} SEXP cleancall_call(SEXP args, SEXP env); extern SEXP cleancall_fns_dot_call; void cleancall_init(void); // -------------------------------------------------------------------- // Public API // -------------------------------------------------------------------- #define R_CLEANCALL_SUPPORT 1 SEXP r_with_cleanup_context(SEXP (*fn)(void* data), void* data); void r_call_on_exit(void (*fn)(void* data), void* data); void r_call_on_early_exit(void (*fn)(void* data), void* data); int r_cleancall_is_active(void); #endif cli/src/vt.c0000644000176200001440000005044714557444176012440 0ustar liggesusers #include #include #include "errors.h" #include "vtparse.h" #define CUR(term) (((term)->cursor_y) * ((term)->width) + ((term)->cursor_x)) #define POS(term, x, y) ((y) * ((term)->width) + (x)) #define CLI_COL_256 254 #define CLI_COL_RGB 255 struct color { /* 0 is off * 30-37, 40-47, 90-97, 100-107 * CLI_COL_256 (254) is 8 bit * CLI_COL_RGB (255) is 24 bit */ unsigned char col; unsigned char r, g, b; }; struct pen { struct color fg; struct color bg; int bold; int italic; int underline; int strikethrough; int blink; int inverse; int link; // 0 is no link, i is link no (i-1) }; void cli_term_reset_pen(struct pen *pen) { memset(pen, 0, sizeof(struct pen)); } typedef unsigned int CHARTYPE; struct cell { CHARTYPE ch; struct pen pen; }; #define OSC_LEN 1024 #define OSC_NUM_LINKS 512 #define OSC_LINK_DATA_LEN 8192 struct terminal { vtparse_t *vt; int width; int height; struct cell *screen; int cursor_x; int cursor_y; struct pen pen; CHARTYPE *osc; int oscptr; int *links; int linkptr; CHARTYPE *linkdata; int linkdataptr; }; void cli_term_clear_cells(struct terminal *term, int beg, int end) { memset( term->screen + beg, 0, sizeof(struct cell) * (end - beg) ); for (; beg <= end; beg++) { term->screen[beg].ch = ' '; } } void cli_term_clear_line(struct terminal *term, int line) { cli_term_clear_cells(term, POS(term, 0, line), POS(term, 0, line + 1) - 1); } void cli_term_clear_screen(struct terminal *term) { int i, n = term->width * term->height; memset(term->screen, 0, sizeof(struct cell) * n); for (i = 0; i < n; i++) { term->screen[i].ch = ' '; } } int cli_term_init(struct terminal *term, int width, int height) { term->width = width; term->height = height; term->screen = (struct cell*) R_alloc(width * height, sizeof(struct cell)); term->osc = NULL; term->oscptr = 0; term->links = NULL; term->linkptr = 0; term->linkdata = NULL; term->linkdataptr = 0; cli_term_clear_screen(term); return 0; } // We return a static buffer here!!! const char *cli_term_color_fg_to_string(struct color *col) { static char buf[20]; if (col->col == 0) return(""); if (col->col == CLI_COL_256) { snprintf(buf, sizeof(buf), "fg:%d;", col->r); } else if (col->col == CLI_COL_RGB) { snprintf(buf, sizeof(buf), "fg:#%02x%02x%02x;", col->r, col->g, col->b); } else if (col->col >= 30 && col->col <= 37) { snprintf(buf, sizeof(buf), "fg:%d;", col->col - 30); } else if (col->col >= 90 && col->col <= 97) { snprintf(buf, sizeof(buf), "fg:%d;", col->col - 90 + 8); } return buf; } // We return a static buffer here!!! const char *cli_term_color_bg_to_string(struct color *col) { static char buf[20]; if (col->col == 0) return(""); if (col->col == CLI_COL_256) { snprintf(buf, sizeof(buf), "bg:%d;", col->r); } else if (col->col == CLI_COL_RGB) { snprintf(buf, sizeof(buf), "bg:#%02x%02x%02x;", col->r, col->g, col->b); } else if (col->col >= 40 && col->col <= 47) { snprintf(buf, sizeof(buf), "bg:%d;", col->col - 40); } else if (col->col >= 100 && col->col <= 107) { snprintf(buf, sizeof(buf), "bg:%d;", col->col - 100 + 8); } return buf; } const char *cli_term_link_to_string(struct terminal *term, int linkno) { static char buf[20]; snprintf(buf, sizeof(buf), "link:%d;", linkno); return buf; } SEXP cli_term_pen_to_string(struct terminal *term, struct pen *pen) { // TODO: calculate max possible buf length char buf[100]; int ret = snprintf( buf, sizeof(buf), "%s%s%s%s%s%s%s%s%s", pen->fg.col ? cli_term_color_fg_to_string(&pen->fg) : "", pen->bg.col ? cli_term_color_bg_to_string(&pen->bg) : "", pen->bold ? "bold;" : "", pen->italic ? "italic;" : "", pen->underline ? "underline;" : "", pen->strikethrough ? "strikethrough;" : "", pen->blink ? "blink;" : "", pen->inverse ? "inverse;" : "", pen->link ? cli_term_link_to_string(term, pen->link) : "" ); if (ret < 0) { R_THROW_POSIX_ERROR("Internal virtual terminal error"); } return Rf_mkCharCE(buf, CE_UTF8); } int cli_term_pen_empty(struct pen *pen) { return pen->fg.col == 0 && pen->bg.col == 0 && !pen->bold && !pen->italic && !pen->underline && !pen->strikethrough && !pen->blink && !pen->inverse && !pen->link; } SEXP cli_term_links(struct terminal *term) { int i, n = term->linkptr; SEXP res = PROTECT(Rf_allocVector(VECSXP, n)); for (i = 0; i < n; i++) { int start = term->links[i]; int end = (i == n - 1) ? term->linkdataptr : term->links[i + 1]; int len = end - start; SEXP elt = PROTECT(Rf_allocVector(INTSXP, len)); memcpy(INTEGER(elt), term->linkdata + start, len * sizeof(CHARTYPE)); SET_VECTOR_ELT(res, i, elt); UNPROTECT(1); } UNPROTECT(1); return res; } SEXP cli_term_state(struct terminal *term) { const char *res_names[] = { "lines", "attrs", "cursor_x", "cursor_y", "links", "" }; SEXP res = PROTECT(Rf_mkNamed(VECSXP, res_names)); SEXP lines = PROTECT(Rf_allocVector(VECSXP, term->height)); SEXP attrs = PROTECT(Rf_allocVector(VECSXP, term->height)); SET_VECTOR_ELT(res, 2, Rf_ScalarInteger(term->cursor_x)); SET_VECTOR_ELT(res, 3, Rf_ScalarInteger(term->cursor_y)); SET_VECTOR_ELT(res, 4, cli_term_links(term)); int i, j, p; for (i = 0, p = 0; i < term->height; i++) { SEXP line = PROTECT(Rf_allocVector(INTSXP, term->width)); SEXP attr = PROTECT(Rf_allocVector(STRSXP, term->width)); for (j = 0; j < term->width; j++) { INTEGER(line)[j] = term->screen[p].ch; struct pen *current_pen = &term->screen[p].pen; if (!cli_term_pen_empty(current_pen)) { SET_STRING_ELT(attr, j, cli_term_pen_to_string(term, current_pen)); } p++; } SET_VECTOR_ELT(lines, i, line); SET_VECTOR_ELT(attrs, i, attr); UNPROTECT(2); } SET_VECTOR_ELT(res, 0, lines); SET_VECTOR_ELT(res, 1, attrs); UNPROTECT(3); return res; } void cli_term_scroll_up(struct terminal *term) { memmove( term->screen, term->screen + term->width, term->width * (term->height - 1) * sizeof(struct cell) ); cli_term_clear_line(term, term->height - 1); } void cli_term_move_cursor_rel_col(struct terminal *term, int n) { // TODO } void cli_term_move_cursor_down(struct terminal *term) { if (term->cursor_y == term->height - 1) { cli_term_scroll_up(term); } else { term->cursor_y += 1; } term->cursor_x = 0; } void cli_term_execute(struct terminal *term, int ch) { switch (ch) { case 0x08: // bs cli_term_move_cursor_rel_col(term, -1); break; case 0x09: // ht // TODO: tab support (to next tab) break; case 0x0a: // nl case 0x0b: // vt case 0x0c: // np case 0x84: // case 0x85: // nel cli_term_move_cursor_down(term); break; case 0x0d: // cr term->cursor_x = 0; break; case 0x0e: // so // TODO: charset support break; case 0x0f: // si // TODO: charset support break; case 0x88: // hts // TODO: tab support (set tab) break; case 0x8d: // ri // TODO: ??? break; default: break; } } int cli_term_get_param(vtparse_t *vt, int which, int dflt) { if (vt->num_params <= which) return dflt; return vt->params[which]; } // See also https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences // '@' insert character, insert n spaces (MS) void cli_term_execute_ich(vtparse_t *vt, struct terminal *term) { // TODO: should we support MS? } // 'A' cursor up (n), no effect if at edge void cli_term_execute_cuu(vtparse_t *vt, struct terminal *term) { int n = cli_term_get_param(vt, 0, 1); term->cursor_y -= n; if (term->cursor_y < 0) term->cursor_y = 0; } // 'B' cursor down (n), no effect if at edge void cli_term_execute_cud(vtparse_t *vt, struct terminal *term) { int n = cli_term_get_param(vt, 0, 1); term->cursor_y += n; if (term->cursor_y >= term->height) term->cursor_y = term->height - 1; } // 'C' cursor forward (n), no effect if at edge void cli_term_execute_cuf(vtparse_t *vt, struct terminal *term) { int n = cli_term_get_param(vt, 0, 1); term->cursor_x += n; if (term->cursor_x >= term->width) term->cursor_x = term->width - 1; } // 'D' cursor back (n), no effect if at edge void cli_term_execute_cub(vtparse_t *vt, struct terminal *term) { int n = cli_term_get_param(vt, 0, 1); term->cursor_x -= n; if (term->cursor_x < 0) term->cursor_x = 0; } // 'E' cursor next line (n) void cli_term_execute_cnl(vtparse_t *vt, struct terminal *term) { int n = cli_term_get_param(vt, 0, 1); term->cursor_x = 0; term->cursor_y += n; if (term->cursor_y >= term->height) term->cursor_y = term->height - 1; } // 'F' cursor previous line (n) void cli_term_execute_cpl(vtparse_t *vt, struct terminal *term) { int n = cli_term_get_param(vt, 0, 1); term->cursor_x = 0; term->cursor_y -= n; if (term->cursor_y < 0) term->cursor_y = 0; } // 'G' cursor horizontal absolute (n) void cli_term_execute_cha(vtparse_t *vt, struct terminal *term) { int n = cli_term_get_param(vt, 0, 1); term->cursor_x = n - 1; if (term->cursor_x < 0) term->cursor_x = 0; if (term->cursor_x >= term->width) term->cursor_x = term->width -1; } // 'H' cursor position (n,m) void cli_term_execute_cup(vtparse_t *vt, struct terminal *term) { int n = cli_term_get_param(vt, 0, 1); int m = cli_term_get_param(vt, 1, 1); term->cursor_y = n - 1; term->cursor_x = m - 1; if (term->cursor_x < 0) term->cursor_x = 0; if (term->cursor_x >= term->width) term->cursor_x = term->width -1; if (term->cursor_y < 0) term->cursor_y = 0; if (term->cursor_y >= term->height) term->cursor_y = term->height - 1; } // 'I' cursor horizontal (forward) tab (n) (MS) void cli_term_execute_cht(vtparse_t *vt, struct terminal *term) { // TODO: should we support MS? } // 'J' erase in display (n) void cli_term_execute_ed(vtparse_t *vt, struct terminal *term) { int n = cli_term_get_param(vt, 0, 0); int cur = CUR(term); int disp_beg = 0; int disp_end = (term->width) * (term->height) - 1; int del_beg = disp_beg; int del_end = disp_end; switch (n) { case 0: // cursor to end of screen del_beg = cur; break; case 1: // beginning of screen to cursor del_end = cur; break; case 2: // clear screen case 3: // clear screen + scrollback buffer, but we don't have scrollback // buffer yet, so it is the same for now // ANSI.SYS moves the cursor, but Unix terminals don't, so we don't break; default: break; } cli_term_clear_cells(term, del_beg, del_end); } // 'K' erase in line (n) void cli_term_execute_el(vtparse_t *vt, struct terminal *term) { int n = cli_term_get_param(vt, 0, 0); int cur = CUR(term); int line_beg = POS(term, 0, term->cursor_y); int line_end = POS(term, 0, term->cursor_y + 1) - 1; int del_beg = line_beg; int del_end = line_end; switch (n) { case 0: // cursor (inclusive) to end of line del_beg = cur; break; case 1: // beginning of line to cursor (inclusive (!)) del_end = cur; break; case 2: // entire line break; default: break; } cli_term_clear_cells(term, del_beg, del_end); } // insert line (n) (MS) void cli_term_execute_il(vtparse_t *vt, struct terminal *term) { // TODO: should we support MS? } // delete line (n) (MS) void cli_term_execute_dl(vtparse_t *vt, struct terminal *term) { // TODO: should we support MS? } // delete character (MS) void cli_term_execute_dch(vtparse_t *vt, struct terminal *term) { // TODO: should we support MS? } // scroll up (n) void cli_term_execute_su(vtparse_t *vt, struct terminal *term) { // TODO: scroll support } // scrool down (n) void cli_term_execute_sd(vtparse_t *vt, struct terminal *term) { // TODO: scroll support } void cli_term_execute_ctc(vtparse_t *vt, struct terminal *term) { // TODO: ??? } // erase character (MS) void cli_term_execute_ech(vtparse_t *vt, struct terminal *term) { // TODO: should we support MS? } // cursor backwards tab (n) MS void cli_term_execute_cbt(vtparse_t *vt, struct terminal *term) { // TODO: should we support MS? } void cli_term_execute_rep(vtparse_t *vt, struct terminal *term) { // TODO: ??? } // vertical line position absolute (n) (MS) void cli_term_execute_vpa(vtparse_t *vt, struct terminal *term) { // TODO: should we support MS? } void cli_term_execute_sm(vtparse_t *vt, struct terminal *term) { // TODO: ??? } void cli_term_execute_rm(vtparse_t *vt, struct terminal *term) { // TODO: ??? } void cli_term_execute_sgr(vtparse_t *vt, struct terminal *term) { int i = 0, np = vt->num_params; while (i < np) { int param = vt->params[i]; switch (param) { case 0: cli_term_reset_pen(&term->pen); i++; break; case 1: term->pen.bold = 1; i++; break; case 3: term->pen.italic = 1; i++; break; case 4: term->pen.underline = 1; i++; break; case 5: term->pen.blink = 1; i++; break; case 7: term->pen.inverse = 1; i++; break; case 9: term->pen.strikethrough = 1; i++; break; case 21: term->pen.bold = 0; i++; break; case 22: term->pen.bold = 0; i++; break; case 23: term->pen.italic = 0; i++; break; case 24: term->pen.underline = 0; i++; break; case 25: term->pen.blink = 0; i++; break; case 27: term->pen.inverse = 0; i++; break; case 30: case 31: case 32: case 33: case 34: case 35: case 36: case 37: case 90: case 91: case 92: case 93: case 94: case 95: case 96: case 97: term->pen.fg.col = param; i++; break; case 38: i++; if (i == np) break; if (vt->params[i] == 2) { i++; if (i + 2 < np) { term->pen.fg.col = CLI_COL_RGB; term->pen.fg.r = vt->params[i]; term->pen.fg.g = vt->params[i + 1]; term->pen.fg.b = vt->params[i + 2]; i += 3; } } else if (vt->params[i] == 5) { i++; if (i < np) { term->pen.fg.col = CLI_COL_256; term->pen.fg.r = vt->params[i]; i++; } } else { i++; } break; case 39: term->pen.fg.col = 0; i++; break; case 40: case 41: case 42: case 43: case 44: case 45: case 46: case 47: case 100: case 101: case 102: case 103: case 104: case 105: case 106: case 107: term->pen.bg.col = param; i++; break; case 48: i++; if (i == np) break; if (vt->params[i] == 2) { i++; if (i + 2 < np) { term->pen.bg.col = CLI_COL_RGB; term->pen.bg.r = vt->params[i]; term->pen.bg.g = vt->params[i + 1]; term->pen.bg.b = vt->params[i + 2]; i += 3; } } else if (vt->params[i] == 5) { i++; if (i < np) { term->pen.bg.col = CLI_COL_256; term->pen.bg.r = vt->params[i]; i++; } } else { i++; } break; case 49: term->pen.bg.col = 0; i++; break; default: i++; break; } } } // 'r' void cli_term_execute_decstbm(vtparse_t *vt, struct terminal *term) { // TODO: ??? } void cli_term_csi_dispatch(vtparse_t *vt, struct terminal *term, CHARTYPE ch) { // TODO: check intermediates for Dec stuff // TODO: rest switch (ch) { case '@': cli_term_execute_ich(vt, term); break; case 'A': cli_term_execute_cuu(vt, term); break; case 'B': cli_term_execute_cud(vt, term); break; case 'C': cli_term_execute_cuf(vt, term); break; case 'D': cli_term_execute_cub(vt, term); break; case 'E': cli_term_execute_cnl(vt, term); break; case 'F': cli_term_execute_cpl(vt, term); break; case 'G': cli_term_execute_cha(vt, term); break; case 'H': cli_term_execute_cup(vt, term); break; case 'I': cli_term_execute_cht(vt, term); break; case 'J': cli_term_execute_ed(vt, term); break; case 'K': cli_term_execute_el(vt, term); break; case 'L': cli_term_execute_il(vt, term); break; case 'M': cli_term_execute_dl(vt, term); break; case 'P': cli_term_execute_dch(vt, term); break; case 'S': cli_term_execute_su(vt, term); break; case 'T': cli_term_execute_sd(vt, term); break; case 'W': cli_term_execute_ctc(vt, term); break; case 'X': cli_term_execute_ech(vt, term); break; case 'Z': cli_term_execute_cbt(vt, term); break; case ' ': cli_term_execute_cha(vt, term); break; case 'a': cli_term_execute_cuf(vt, term); break; case 'b': cli_term_execute_rep(vt, term); break; case 'd': cli_term_execute_vpa(vt, term); break; case 'e': cli_term_execute_cuu(vt, term); break; case 'f': cli_term_execute_cbt(vt, term); break; case 'g': cli_term_execute_cup(vt, term); break; case 'h': cli_term_execute_sm(vt, term); break; case 'l': cli_term_execute_rm(vt, term); break; case 'm': cli_term_execute_sgr(vt, term); break; case 'r': cli_term_execute_decstbm(vt, term); break; default: break; } } void cli_term_osc_end(struct terminal *term) { if (!term->osc) { R_THROW_ERROR("Internal vt error, OSC buffer not alloaced"); } if (term->oscptr == 3 && term->osc[0] == '8' && term->osc[1] == ';' && term->osc[2] == ';') { // closing hyperlinks are ESC ] 8 ; ; term->pen.link = 0; } else if (term->oscptr >= 2 && term->osc[0] == '8' && term->osc[1] == ';') { // opening hyperlinks are ESC ] 8 ; URL if (!term->links) { term->links = (int*) R_alloc(OSC_NUM_LINKS, sizeof(int)); term->linkdata = (CHARTYPE*) R_alloc(OSC_LINK_DATA_LEN, sizeof(CHARTYPE)); } if (term->linkptr == OSC_NUM_LINKS) { R_THROW_ERROR("Too many hyperlinks, internal vt limit in cli"); } if (term->linkdataptr + term->oscptr - 2 > OSC_LINK_DATA_LEN) { R_THROW_ERROR("Too many, too long hyperlinks, internal vt limit in cli"); } memcpy( term->linkdata + term->linkdataptr, term->osc + 2, (term->oscptr - 2) * sizeof(CHARTYPE) ); term->links[term->linkptr] = term->linkdataptr; term->linkptr += 1; term->linkdataptr += (term->oscptr - 2); term->pen.link = term->linkptr; // We need a +1 here, 0 means no link } } void cli_term_osc_put(struct terminal *term, CHARTYPE ch) { if (!term->osc) { R_THROW_ERROR("Internal vt error, OSC buffer not alloaced"); } if (term->oscptr == OSC_LEN) { R_THROW_ERROR("Internal vt error, OSC buffer is full"); } term->osc[term->oscptr] = ch; term->oscptr += 1; } void cli_term_osc_start(struct terminal *term) { if (!term->osc) { term->osc = (CHARTYPE*) R_alloc(OSC_LEN, sizeof(CHARTYPE)); } term->oscptr = 0; } void clic_vt_callback(vtparse_t *vt, vtparse_action_t action, CHARTYPE ch) { struct terminal *term = (struct terminal*) vt->user_data; switch (action) { case VTPARSE_ACTION_CSI_DISPATCH: cli_term_csi_dispatch(vt, term, ch); break; case VTPARSE_ACTION_EXECUTE: cli_term_execute(term, ch); break; case VTPARSE_ACTION_OSC_END: cli_term_osc_end(term); break; case VTPARSE_ACTION_OSC_PUT: cli_term_osc_put(term, ch); break; case VTPARSE_ACTION_OSC_START: cli_term_osc_start(term); break; case VTPARSE_ACTION_PRINT: if (term->cursor_x == term->width) { if (term->cursor_y == term->height - 1) { cli_term_scroll_up(term); } else { term->cursor_y += 1; } term->cursor_x = 0; } term->screen[CUR(term)].ch = ch; term->screen[CUR(term)].pen = term->pen; term->cursor_x += 1; break; default: break; } } SEXP clic_vt_output(SEXP bytes, SEXP width, SEXP height) { int c_width = INTEGER(width)[0]; int c_height = INTEGER(height)[0]; vtparse_t vt; struct terminal term = { 0 }; if (cli_term_init(&term, c_width, c_height)) { R_THROW_ERROR("Cannot initialize vittual terminal"); } term.vt = &vt; vtparse_init(&vt, clic_vt_callback); vt.user_data = &term; vtparse(&vt, RAW(bytes), LENGTH(bytes)); return cli_term_state(&term); } cli/src/keypress.h0000644000176200001440000000363414557444176013655 0ustar liggesusers #ifndef KEYPRESS_H #define KEYPRESS_H #include #include #define BLOCKING 1 #define NON_BLOCKING 0 #define KEYPRESS_CHAR 0 #define KEYPRESS_ENTER 1 #define KEYPRESS_BACKSPACE 2 #define KEYPRESS_LEFT 3 #define KEYPRESS_RIGHT 4 #define KEYPRESS_UP 5 #define KEYPRESS_DOWN 6 #define KEYPRESS_INSERT 7 #define KEYPRESS_DELETE 8 #define KEYPRESS_HOME 9 #define KEYPRESS_END 10 #define KEYPRESS_F1 11 #define KEYPRESS_F2 12 #define KEYPRESS_F3 13 #define KEYPRESS_F4 14 #define KEYPRESS_F5 15 #define KEYPRESS_F6 16 #define KEYPRESS_F7 17 #define KEYPRESS_F8 18 #define KEYPRESS_F9 19 #define KEYPRESS_F10 20 #define KEYPRESS_F11 21 #define KEYPRESS_F12 22 #define KEYPRESS_CTRL_A 23 #define KEYPRESS_CTRL_B 24 #define KEYPRESS_CTRL_C 25 #define KEYPRESS_CTRL_D 26 #define KEYPRESS_CTRL_E 27 #define KEYPRESS_CTRL_F 28 #define KEYPRESS_CTRL_H 29 #define KEYPRESS_CTRL_K 30 #define KEYPRESS_CTRL_L 31 #define KEYPRESS_CTRL_N 32 #define KEYPRESS_CTRL_P 33 #define KEYPRESS_CTRL_T 34 #define KEYPRESS_CTRL_U 35 #define KEYPRESS_CTRL_W 36 #define KEYPRESS_ESCAPE 37 #define KEYPRESS_TAB 38 #define KEYPRESS_PAGEUP 39 #define KEYPRESS_PAGEDOWN 40 /* Nothing read, for non-blocking reads */ #define KEYPRESS_NONE 41 /* Something, e.g. escape seq, but don't know what exactly */ #define KEYPRESS_UNKNOWN 42 #define KEYPRESS_NAME_SIZE 43 /* The longest UTF8 character in bytes */ #define KEYPRESS_UTF8_BUFFER_SIZE 4 typedef struct { int code; char ascii; char utf8[KEYPRESS_UTF8_BUFFER_SIZE + 1]; } keypress_key_t; keypress_key_t keypress_read(int block); keypress_key_t keypress_special(int key); keypress_key_t keypress_utf8(const char *buf); SEXP cli_keypress(SEXP s_block); extern const char *keypress_key_names[KEYPRESS_NAME_SIZE]; #endif cli/src/md5.h0000644000176200001440000003632114557444176012474 0ustar liggesusers/* * This an amalgamation of md5.c and md5.h into a single file * with all static declaration to reduce linker conflicts * in Civetweb. * * The MD5_STATIC declaration was added to facilitate static * inclusion. * No Face Press, LLC */ /* $Id: md5.h,v 1.4 2002/04/13 19:20:28 lpd Exp $ */ /* Independent implementation of MD5 (RFC 1321). This code implements the MD5 Algorithm defined in RFC 1321, whose text is available at http://www.ietf.org/rfc/rfc1321.txt The code is derived from the text of the RFC, including the test suite (section A.5) but excluding the rest of Appendix A. It does not include any code or documentation that is identified in the RFC as being copyrighted. The original and principal author of md5.h is L. Peter Deutsch . Other authors are noted in the change history that follows (in reverse chronological order): 2002-04-13 lpd Removed support for non-ANSI compilers; removed references to Ghostscript; clarified derivation from RFC 1321; now handles byte order either statically or dynamically. 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5); added conditionalization for C++ compilation from Martin Purschke . 1999-05-03 lpd Original version. */ #if !defined(md5_INCLUDED) #define md5_INCLUDED /* * This package supports both compile-time and run-time determination of CPU * byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is * defined as non-zero, the code will be compiled to run only on big-endian * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to * run on either big- or little-endian CPUs, but will run slightly less * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined. */ typedef unsigned char md5_byte_t; /* 8-bit byte */ typedef unsigned int md5_word_t; /* 32-bit word */ /* Define the state of the MD5 Algorithm. */ typedef struct md5_state_s { md5_word_t count[2]; /* message length in bits, lsw first */ md5_word_t abcd[4]; /* digest buffer */ md5_byte_t buf[64]; /* accumulate block */ } md5_state_t; #if defined(__cplusplus) extern "C" { #endif /* Initialize the algorithm. */ MD5_STATIC void md5_init(md5_state_t *pms); /* Append a string to the message. */ MD5_STATIC void md5_append(md5_state_t *pms, const md5_byte_t *data, size_t nbytes); /* Finish the message and return the digest. */ MD5_STATIC void md5_finish(md5_state_t *pms, md5_byte_t digest[16]); #if defined(__cplusplus) } /* end extern "C" */ #endif #endif /* md5_INCLUDED */ /* Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved. This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. L. Peter Deutsch ghost@aladdin.com */ /* $Id: md5.c,v 1.6 2002/04/13 19:20:28 lpd Exp $ */ /* Independent implementation of MD5 (RFC 1321). This code implements the MD5 Algorithm defined in RFC 1321, whose text is available at http://www.ietf.org/rfc/rfc1321.txt The code is derived from the text of the RFC, including the test suite (section A.5) but excluding the rest of Appendix A. It does not include any code or documentation that is identified in the RFC as being copyrighted. The original and principal author of md5.c is L. Peter Deutsch . Other authors are noted in the change history that follows (in reverse chronological order): 2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order either statically or dynamically; added missing #include in library. 2002-03-11 lpd Corrected argument list for main(), and added int return type, in test program and T value program. 2002-02-21 lpd Added missing #include in test program. 2000-07-03 lpd Patched to eliminate warnings about "constant is unsigned in ANSI C, signed in traditional"; made test program self-checking. 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5). 1999-05-03 lpd Original version. */ #if !defined(MD5_STATIC) #include #endif #undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */ #if defined(ARCH_IS_BIG_ENDIAN) #define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1) #else #define BYTE_ORDER (0) #endif #define T_MASK ((md5_word_t)~0) #define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87) #define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9) #define T3 (0x242070db) #define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111) #define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050) #define T6 (0x4787c62a) #define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec) #define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe) #define T9 (0x698098d8) #define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850) #define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e) #define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841) #define T13 (0x6b901122) #define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c) #define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71) #define T16 (0x49b40821) #define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d) #define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf) #define T19 (0x265e5a51) #define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855) #define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2) #define T22 (0x02441453) #define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e) #define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437) #define T25 (0x21e1cde6) #define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829) #define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278) #define T28 (0x455a14ed) #define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa) #define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07) #define T31 (0x676f02d9) #define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375) #define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd) #define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e) #define T35 (0x6d9d6122) #define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3) #define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb) #define T38 (0x4bdecfa9) #define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f) #define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f) #define T41 (0x289b7ec6) #define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805) #define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a) #define T44 (0x04881d05) #define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6) #define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a) #define T47 (0x1fa27cf8) #define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a) #define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb) #define T50 (0x432aff97) #define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58) #define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6) #define T53 (0x655b59c3) #define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d) #define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82) #define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e) #define T57 (0x6fa87e4f) #define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f) #define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb) #define T60 (0x4e0811a1) #define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d) #define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca) #define T63 (0x2ad7d2bb) #define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e) static void md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/) { md5_word_t a = pms->abcd[0], b = pms->abcd[1], c = pms->abcd[2], d = pms->abcd[3]; md5_word_t t; #if BYTE_ORDER > 0 /* Define storage only for big-endian CPUs. */ md5_word_t X[16]; #else /* Define storage for little-endian or both types of CPUs. */ md5_word_t xbuf[16]; const md5_word_t *X; #endif { #if BYTE_ORDER == 0 /* * Determine dynamically whether this is a big-endian or * little-endian machine, since we can use a more efficient * algorithm on the latter. */ static const int w = 1; if (*((const md5_byte_t *)&w)) /* dynamic little-endian */ #endif #if BYTE_ORDER <= 0 /* little-endian */ { /* * On little-endian machines, we can process properly aligned * data without copying it. */ if (!((data - (const md5_byte_t *)0) & 3)) { /* data are properly aligned, a direct assignment is possible */ /* cast through a (void *) should avoid a compiler warning, see https://github.com/bel2125/civetweb/issues/94#issuecomment-98112861 */ X = (const md5_word_t *)(const void *)data; } else { /* not aligned */ memcpy(xbuf, data, 64); X = xbuf; } } #endif #if BYTE_ORDER == 0 else /* dynamic big-endian */ #endif #if BYTE_ORDER >= 0 /* big-endian */ { /* * On big-endian machines, we must arrange the bytes in the * right order. */ const md5_byte_t *xp = data; int i; #if BYTE_ORDER == 0 X = xbuf; /* (dynamic only) */ #else #define xbuf X /* (static only) */ #endif for (i = 0; i < 16; ++i, xp += 4) xbuf[i] = (md5_word_t)(xp[0]) + (md5_word_t)(xp[1] << 8) + (md5_word_t)(xp[2] << 16) + (md5_word_t)(xp[3] << 24); } #endif } #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) /* Round 1. */ /* Let [abcd k s i] denote the operation a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */ #define F(x, y, z) (((x) & (y)) | (~(x) & (z))) #define SET(a, b, c, d, k, s, Ti) \ t = a + F(b, c, d) + X[k] + Ti; \ a = ROTATE_LEFT(t, s) + b /* Do the following 16 operations. */ SET(a, b, c, d, 0, 7, T1); SET(d, a, b, c, 1, 12, T2); SET(c, d, a, b, 2, 17, T3); SET(b, c, d, a, 3, 22, T4); SET(a, b, c, d, 4, 7, T5); SET(d, a, b, c, 5, 12, T6); SET(c, d, a, b, 6, 17, T7); SET(b, c, d, a, 7, 22, T8); SET(a, b, c, d, 8, 7, T9); SET(d, a, b, c, 9, 12, T10); SET(c, d, a, b, 10, 17, T11); SET(b, c, d, a, 11, 22, T12); SET(a, b, c, d, 12, 7, T13); SET(d, a, b, c, 13, 12, T14); SET(c, d, a, b, 14, 17, T15); SET(b, c, d, a, 15, 22, T16); #undef SET /* Round 2. */ /* Let [abcd k s i] denote the operation a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */ #define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) #define SET(a, b, c, d, k, s, Ti) \ t = a + G(b, c, d) + X[k] + Ti; \ a = ROTATE_LEFT(t, s) + b /* Do the following 16 operations. */ SET(a, b, c, d, 1, 5, T17); SET(d, a, b, c, 6, 9, T18); SET(c, d, a, b, 11, 14, T19); SET(b, c, d, a, 0, 20, T20); SET(a, b, c, d, 5, 5, T21); SET(d, a, b, c, 10, 9, T22); SET(c, d, a, b, 15, 14, T23); SET(b, c, d, a, 4, 20, T24); SET(a, b, c, d, 9, 5, T25); SET(d, a, b, c, 14, 9, T26); SET(c, d, a, b, 3, 14, T27); SET(b, c, d, a, 8, 20, T28); SET(a, b, c, d, 13, 5, T29); SET(d, a, b, c, 2, 9, T30); SET(c, d, a, b, 7, 14, T31); SET(b, c, d, a, 12, 20, T32); #undef SET /* Round 3. */ /* Let [abcd k s t] denote the operation a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */ #define H(x, y, z) ((x) ^ (y) ^ (z)) #define SET(a, b, c, d, k, s, Ti) \ t = a + H(b, c, d) + X[k] + Ti; \ a = ROTATE_LEFT(t, s) + b /* Do the following 16 operations. */ SET(a, b, c, d, 5, 4, T33); SET(d, a, b, c, 8, 11, T34); SET(c, d, a, b, 11, 16, T35); SET(b, c, d, a, 14, 23, T36); SET(a, b, c, d, 1, 4, T37); SET(d, a, b, c, 4, 11, T38); SET(c, d, a, b, 7, 16, T39); SET(b, c, d, a, 10, 23, T40); SET(a, b, c, d, 13, 4, T41); SET(d, a, b, c, 0, 11, T42); SET(c, d, a, b, 3, 16, T43); SET(b, c, d, a, 6, 23, T44); SET(a, b, c, d, 9, 4, T45); SET(d, a, b, c, 12, 11, T46); SET(c, d, a, b, 15, 16, T47); SET(b, c, d, a, 2, 23, T48); #undef SET /* Round 4. */ /* Let [abcd k s t] denote the operation a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */ #define I(x, y, z) ((y) ^ ((x) | ~(z))) #define SET(a, b, c, d, k, s, Ti) \ t = a + I(b, c, d) + X[k] + Ti; \ a = ROTATE_LEFT(t, s) + b /* Do the following 16 operations. */ SET(a, b, c, d, 0, 6, T49); SET(d, a, b, c, 7, 10, T50); SET(c, d, a, b, 14, 15, T51); SET(b, c, d, a, 5, 21, T52); SET(a, b, c, d, 12, 6, T53); SET(d, a, b, c, 3, 10, T54); SET(c, d, a, b, 10, 15, T55); SET(b, c, d, a, 1, 21, T56); SET(a, b, c, d, 8, 6, T57); SET(d, a, b, c, 15, 10, T58); SET(c, d, a, b, 6, 15, T59); SET(b, c, d, a, 13, 21, T60); SET(a, b, c, d, 4, 6, T61); SET(d, a, b, c, 11, 10, T62); SET(c, d, a, b, 2, 15, T63); SET(b, c, d, a, 9, 21, T64); #undef SET /* Then perform the following additions. (That is increment each of the four registers by the value it had before this block was started.) */ pms->abcd[0] += a; pms->abcd[1] += b; pms->abcd[2] += c; pms->abcd[3] += d; } MD5_STATIC void md5_init(md5_state_t *pms) { pms->count[0] = pms->count[1] = 0; pms->abcd[0] = 0x67452301; pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476; pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301; pms->abcd[3] = 0x10325476; } MD5_STATIC void md5_append(md5_state_t *pms, const md5_byte_t *data, size_t nbytes) { const md5_byte_t *p = data; size_t left = nbytes; size_t offset = (pms->count[0] >> 3) & 63; md5_word_t nbits = (md5_word_t)(nbytes << 3); if (nbytes <= 0) return; /* Update the message length. */ pms->count[1] += (md5_word_t)(nbytes >> 29); pms->count[0] += nbits; if (pms->count[0] < nbits) pms->count[1]++; /* Process an initial partial block. */ if (offset) { size_t copy = (offset + nbytes > 64 ? 64 - offset : nbytes); memcpy(pms->buf + offset, p, copy); if (offset + copy < 64) return; p += copy; left -= copy; md5_process(pms, pms->buf); } /* Process full blocks. */ for (; left >= 64; p += 64, left -= 64) md5_process(pms, p); /* Process a final partial block. */ if (left) memcpy(pms->buf, p, left); } MD5_STATIC void md5_finish(md5_state_t *pms, md5_byte_t digest[16]) { static const md5_byte_t pad[64] = {0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; md5_byte_t data[8]; int i; /* Save the length before padding. */ for (i = 0; i < 8; ++i) data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3)); /* Pad to 56 bytes mod 64. */ md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1); /* Append the length. */ md5_append(pms, data, 8); for (i = 0; i < 16; ++i) digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3)); } /* End of md5.inl */ cli/src/keypress-unix.c0000644000176200001440000002121714557444176014626 0ustar liggesusers /* Avoid warning about empty compilation unit. */ void keypress_unix_dummy(void) { } #ifndef _WIN32 #include "errors.h" #include "keypress.h" #include #include #include #include keypress_key_t single_char(const char *buf) { int ch = buf[0]; switch(ch) { case 1: return keypress_special(KEYPRESS_CTRL_A); case 2: return keypress_special(KEYPRESS_CTRL_B); case 3: return keypress_special(KEYPRESS_CTRL_C); case 4: return keypress_special(KEYPRESS_CTRL_D); case 5: return keypress_special(KEYPRESS_CTRL_E); case 6: return keypress_special(KEYPRESS_CTRL_F); case 8: return keypress_special(KEYPRESS_CTRL_H); case 9: return keypress_special(KEYPRESS_TAB); case 10: return keypress_special(KEYPRESS_ENTER); case 11: return keypress_special(KEYPRESS_CTRL_K); case 12: return keypress_special(KEYPRESS_CTRL_L); case 13: return keypress_special(KEYPRESS_ENTER); case 14: return keypress_special(KEYPRESS_CTRL_N); case 16: return keypress_special(KEYPRESS_CTRL_P); case 20: return keypress_special(KEYPRESS_CTRL_T); case 21: return keypress_special(KEYPRESS_CTRL_U); case 23: return keypress_special(KEYPRESS_CTRL_W); case 27: return keypress_special(KEYPRESS_ESCAPE); case 127: return keypress_special(KEYPRESS_BACKSPACE); default : return keypress_utf8(buf); } } keypress_key_t function_key(const char *buf, size_t buf_size) { buf++; /* escape character */ buf_size -= 2; /* minus first escape and trailing zero */ /* xterm */ if (! strncmp(buf, "[A", buf_size)) { return keypress_special(KEYPRESS_UP); } else if (!strncmp(buf, "[B", buf_size)) { return keypress_special(KEYPRESS_DOWN); } else if (!strncmp(buf, "[C", buf_size)) { return keypress_special(KEYPRESS_RIGHT); } else if (!strncmp(buf, "[D", buf_size)) { return keypress_special(KEYPRESS_LEFT); } else if (!strncmp(buf, "[F", buf_size)) { return keypress_special(KEYPRESS_END); } else if (!strncmp(buf, "[H", buf_size)) { return keypress_special(KEYPRESS_HOME); /* xterm/gnome */ } else if (!strncmp(buf, "OA", buf_size)) { return keypress_special(KEYPRESS_UP); } else if (!strncmp(buf, "OB", buf_size)) { return keypress_special(KEYPRESS_DOWN); } else if (!strncmp(buf, "OC", buf_size)) { return keypress_special(KEYPRESS_RIGHT); } else if (!strncmp(buf, "OD", buf_size)) { return keypress_special(KEYPRESS_LEFT); } else if (!strncmp(buf, "OF", buf_size)) { return keypress_special(KEYPRESS_END); } else if (!strncmp(buf, "OH", buf_size)) { return keypress_special(KEYPRESS_HOME); /* xterm/rxvt */ } else if (!strncmp(buf, "[1~", buf_size)) { return keypress_special(KEYPRESS_HOME); } else if (!strncmp(buf, "[2~", buf_size)) { return keypress_special(KEYPRESS_INSERT); } else if (!strncmp(buf, "[3~", buf_size)) { return keypress_special(KEYPRESS_DELETE); } else if (!strncmp(buf, "[4~", buf_size)) { return keypress_special(KEYPRESS_END); } else if (!strncmp(buf, "[5~", buf_size)) { return keypress_special(KEYPRESS_PAGEUP); } else if (!strncmp(buf, "[6~", buf_size)) { return keypress_special(KEYPRESS_PAGEDOWN); /* putty */ } else if (!strncmp(buf, "[[5~", buf_size)) { return keypress_special(KEYPRESS_PAGEUP); } else if (!strncmp(buf, "[[6~", buf_size)) { return keypress_special(KEYPRESS_PAGEDOWN); /* rxvt */ } else if (!strncmp(buf, "[[7~", buf_size)) { return keypress_special(KEYPRESS_HOME); } else if (!strncmp(buf, "[[8~", buf_size)) { return keypress_special(KEYPRESS_END); /* xterm/gnome */ } else if (!strncmp(buf, "OP", buf_size)) { return keypress_special(KEYPRESS_F1); } else if (!strncmp(buf, "OQ", buf_size)) { return keypress_special(KEYPRESS_F2); } else if (!strncmp(buf, "OR", buf_size)) { return keypress_special(KEYPRESS_F3); } else if (!strncmp(buf, "OS", buf_size)) { return keypress_special(KEYPRESS_F4); /* common */ } else if (!strncmp(buf, "[15~", buf_size)) { return keypress_special(KEYPRESS_F5); } else if (!strncmp(buf, "[17~", buf_size)) { return keypress_special(KEYPRESS_F6); } else if (!strncmp(buf, "[18~", buf_size)) { return keypress_special(KEYPRESS_F7); } else if (!strncmp(buf, "[19~", buf_size)) { return keypress_special(KEYPRESS_F8); } else if (!strncmp(buf, "[20~", buf_size)) { return keypress_special(KEYPRESS_F9); } else if (!strncmp(buf, "[21~", buf_size)) { return keypress_special(KEYPRESS_F10); } else if (!strncmp(buf, "[23~", buf_size)) { return keypress_special(KEYPRESS_F11); } else if (!strncmp(buf, "[24~", buf_size)) { return keypress_special(KEYPRESS_F12); /* xterm / rxvt */ } else if (!strncmp(buf, "[11~", buf_size)) { return keypress_special(KEYPRESS_F1); } else if (!strncmp(buf, "[12~", buf_size)) { return keypress_special(KEYPRESS_F2); } else if (!strncmp(buf, "[13~", buf_size)) { return keypress_special(KEYPRESS_F3); } else if (!strncmp(buf, "[14~", buf_size)) { return keypress_special(KEYPRESS_F4); } else if (strlen(buf) == 0) { return keypress_special(KEYPRESS_ESCAPE); } else { return keypress_utf8(buf - 1); } return keypress_special(KEYPRESS_UNKNOWN); } keypress_key_t keypress_read(int block) { char buf[11] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; struct termios term = { 0 }; int flags = fcntl(0, F_GETFL, 0); if (tcgetattr(0, &term) < 0) { R_THROW_SYSTEM_ERROR("Cannot query terminal flags"); } tcflag_t term_flags = term.c_lflag; int term_vmin = term.c_cc[VMIN]; int term_vtime = term.c_cc[VTIME]; term.c_lflag &= ~ICANON; term.c_lflag &= ~ECHO; term.c_cc[VMIN] = 1; term.c_cc[VTIME] = 0; if (tcsetattr(0, TCSANOW, &term) < 0) { R_THROW_SYSTEM_ERROR("Cannot set canonical mode"); } if (! block) { if (fcntl(0, F_SETFL, flags | O_NONBLOCK) == -1) { R_THROW_SYSTEM_ERROR("Cannot set terminal to non-blocking"); } } if (read(0, buf, 1) < 0) { if (fcntl(0, F_SETFL, flags) == -1) { R_THROW_SYSTEM_ERROR("Cannot set terminal flags"); } term.c_lflag = term_flags; term.c_cc[VMIN] = term_vmin; term.c_cc[VTIME] = term_vtime; tcsetattr(0, TCSADRAIN, &term); if (block) { R_THROW_SYSTEM_ERROR("Cannot read key"); } else { return keypress_special(KEYPRESS_NONE); } } /* If an escape sequence, then we read the rest. We cannot read everything in one go, because of copy-and-paste. This way for a copy-and-paste we only read the first character. */ if (buf[0] == '\033') { /* At least two more characters are needed. We do a non-blocking read to detect if the user only pressed ESC */ ssize_t chars = 0; if (fcntl(0, F_SETFL, flags | O_NONBLOCK) == -1) { R_THROW_SYSTEM_ERROR("Cannot set terminal flags"); } chars = read(0, buf + 1, 2); if (fcntl(0, F_SETFL, flags) == -1) { R_THROW_SYSTEM_ERROR("Cannot set terminal flags"); } if (chars == 2 && buf[1] == '[' && buf[2] >= '1' && buf[2] <= '6') { /* A third one is needed, too */ if (read(0, buf + 3, 1) < 0) { R_THROW_SYSTEM_ERROR("Cannot read from terminal"); } if (buf[3] >= '0' && buf[3] <= '9') { /* A fourth one is needed, too */ if (read(0, buf + 4, 1) < 0) { R_THROW_SYSTEM_ERROR("Cannot read from terminal"); } } } else if (chars == 2 && buf[1] == '[' && buf[2] == '[') { /* Two more is needed if it starts with [[ */ if (read(0, buf + 3, 2) < 0) { R_THROW_SYSTEM_ERROR("Cannot read from terminal"); } } } /* For UTF8 characters, we might need to read more bytes We don't handle errors here, if there are not enough bytes to read, we'll just return whatever is available. */ if ((buf[0] & 0x80) == 0) { /* Nothing to do */ } else if ((buf[0] & 0xe0) == 0xc0) { if (read(0, &buf[1], 1) < 0) { R_THROW_SYSTEM_ERROR("Cannot read from terminal"); } } else if ((buf[0] & 0xf0) == 0xe0) { if (read(0, &buf[1], 2) < 0) { R_THROW_SYSTEM_ERROR("Cannot read from terminal"); } } else if ((buf[0] & 0xf8) == 0xf0) { if (read(0, &buf[1], 3) < 0) { R_THROW_SYSTEM_ERROR("Cannot read from terminal"); } } if (fcntl(0, F_SETFL, flags) == -1) { R_THROW_SYSTEM_ERROR("Cannot set terminal flags"); } term.c_lflag = term_flags; term.c_cc[VMIN] = term_vmin; term.c_cc[VTIME] = term_vtime; if (tcsetattr(0, TCSADRAIN, &term) < 0) { R_THROW_SYSTEM_ERROR("Cannot reset terminal flags"); } if (buf[0] == '\033') { /* Some excape sequence */ return function_key(buf, sizeof(buf)); } else { /* Single character */ return single_char(buf); } } #endif cli/src/cleancall.c0000644000176200001440000001027314557444176013716 0ustar liggesusers#define R_NO_REMAP #include #include "cleancall.h" #if (defined(R_VERSION) && R_VERSION < R_Version(3, 4, 0)) SEXP R_MakeExternalPtrFn(DL_FUNC p, SEXP tag, SEXP prot) { fn_ptr ptr; ptr.fn = p; return R_MakeExternalPtr(ptr.p, tag, prot); } DL_FUNC R_ExternalPtrAddrFn(SEXP s) { fn_ptr ptr; ptr.p = R_ExternalPtrAddr(s); return ptr.fn; } #endif // The R API does not have a setter for function pointers SEXP cleancall_MakeExternalPtrFn(DL_FUNC p, SEXP tag, SEXP prot) { fn_ptr tmp; tmp.fn = p; return R_MakeExternalPtr(tmp.p, tag, prot); } void cleancall_SetExternalPtrAddrFn(SEXP s, DL_FUNC p) { fn_ptr ptr; ptr.fn = p; R_SetExternalPtrAddr(s, ptr.p); } // Initialised at load time with the `.Call` primitive SEXP cleancall_fns_dot_call = NULL; void cleancall_init(void) { cleancall_fns_dot_call = Rf_findVar(Rf_install(".Call"), R_BaseEnv); } struct eval_args { SEXP call; SEXP env; }; static SEXP eval_wrap(void* data) { struct eval_args* args = (struct eval_args*) data; return Rf_eval(args->call, args->env); } SEXP cleancall_call(SEXP args, SEXP env) { SEXP call = PROTECT(Rf_lcons(cleancall_fns_dot_call, args)); struct eval_args data = { call, env }; SEXP out = r_with_cleanup_context(&eval_wrap, &data); UNPROTECT(1); return out; } static SEXP callbacks = NULL; // Preallocate a callback static void push_callback(SEXP stack) { SEXP top = CDR(stack); SEXP early_handler = PROTECT(Rf_allocVector(LGLSXP, 1)); SEXP fn_extptr = PROTECT(cleancall_MakeExternalPtrFn(NULL, R_NilValue, R_NilValue)); SEXP data_extptr = PROTECT(R_MakeExternalPtr(NULL, early_handler, R_NilValue)); SEXP cb = Rf_cons(Rf_cons(fn_extptr, data_extptr), top); SETCDR(stack, cb); UNPROTECT(3); } struct data_wrapper { SEXP (*fn)(void* data); void *data; SEXP callbacks; int success; }; static void call_exits(void* data) { // Remove protecting node. Don't remove the preallocated callback on // the top as it might contain a handler when something went wrong. SEXP top = CDR(callbacks); // Restore old stack struct data_wrapper* state = data; callbacks = (SEXP) state->callbacks; // Handlers should not jump while (top != R_NilValue) { SEXP cb = CAR(top); top = CDR(top); void (*fn)(void*) = (void (*)(void*)) R_ExternalPtrAddrFn(CAR(cb)); void *data = (void*) R_ExternalPtrAddr(CDR(cb)); int early_handler = LOGICAL(R_ExternalPtrTag(CDR(cb)))[0]; // Check for empty pointer in preallocated callbacks if (fn) { if (!early_handler || !state->success) fn(data); } } } static SEXP with_cleanup_context_wrap(void *data) { struct data_wrapper* cdata = data; SEXP ret = cdata->fn(cdata->data); cdata->success = 1; return ret; } SEXP r_with_cleanup_context(SEXP (*fn)(void* data), void* data) { // Preallocate new stack before changing `callbacks` to avoid // leaving the global variable in a bad state if alloc fails SEXP new = PROTECT(Rf_cons(R_NilValue, R_NilValue)); push_callback(new); if (!callbacks) callbacks = R_NilValue; SEXP old = callbacks; callbacks = new; struct data_wrapper state = { fn, data, old, 0 }; SEXP out = R_ExecWithCleanup(with_cleanup_context_wrap, &state, &call_exits, &state); UNPROTECT(1); return out; } int r_cleancall_is_active(void) { return callbacks != NULL; } static void call_save_handler(void (*fn)(void *data), void* data, int early) { if (!callbacks) { fn(data); Rf_error("Internal error: Exit handler pushed outside " "of an exit context"); } SEXP cb = CADR(callbacks); // Update pointers cleancall_SetExternalPtrAddrFn(CAR(cb), (DL_FUNC) fn); R_SetExternalPtrAddr(CDR(cb), data); LOGICAL(R_ExternalPtrTag(CDR(cb)))[0] = early; // Preallocate the next callback in case the allocator jumps push_callback(callbacks); } void r_call_on_exit(void (*fn)(void* data), void* data) { call_save_handler(fn, data, /* early = */ 0); } void r_call_on_early_exit(void (*fn)(void* data), void* data) { call_save_handler(fn, data, /* early = */ 1); } cli/NAMESPACE0000644000176200001440000001344414752735214012260 0ustar liggesusers# Generated by roxygen2: do not edit by hand S3method("[",cli_doc) S3method(as.character,cli_no) S3method(as.character,cli_noprint) S3method(as.character,cli_sitrep) S3method(cli_format,character) S3method(cli_format,default) S3method(cli_format,numeric) S3method(format,cli_ansi_html_style) S3method(format,cli_diff_chr) S3method(format,cli_diff_str) S3method(format,cli_doc) S3method(format,cli_progress_demo) S3method(format,cli_sitrep) S3method(format,cli_spark) S3method(print,cli_ansi_html_style) S3method(print,cli_ansi_string) S3method(print,cli_ansi_style) S3method(print,cli_boxx) S3method(print,cli_diff_chr) S3method(print,cli_doc) S3method(print,cli_progress_demo) S3method(print,cli_rule) S3method(print,cli_sitrep) S3method(print,cli_spark) S3method(print,cli_spinner) S3method(print,cli_tree) export("__cli_update_due") export(ansi_align) export(ansi_chartr) export(ansi_collapse) export(ansi_columns) export(ansi_grep) export(ansi_grepl) export(ansi_has_any) export(ansi_has_hyperlink_support) export(ansi_hide_cursor) export(ansi_html) export(ansi_html_style) export(ansi_hyperlink_types) export(ansi_nchar) export(ansi_nzchar) export(ansi_palette_show) export(ansi_palettes) export(ansi_regex) export(ansi_show_cursor) export(ansi_simplify) export(ansi_string) export(ansi_strip) export(ansi_strsplit) export(ansi_strtrim) export(ansi_strwrap) export(ansi_substr) export(ansi_substring) export(ansi_tolower) export(ansi_toupper) export(ansi_trimws) export(ansi_with_hidden_cursor) export(bg_black) export(bg_blue) export(bg_br_black) export(bg_br_blue) export(bg_br_cyan) export(bg_br_green) export(bg_br_magenta) export(bg_br_red) export(bg_br_white) export(bg_br_yellow) export(bg_cyan) export(bg_green) export(bg_magenta) export(bg_none) export(bg_red) export(bg_white) export(bg_yellow) export(boxx) export(builtin_theme) export(cat_boxx) export(cat_bullet) export(cat_line) export(cat_print) export(cat_rule) export(ccli_tick_reset) export(cli) export(cli_abort) export(cli_alert) export(cli_alert_danger) export(cli_alert_info) export(cli_alert_success) export(cli_alert_warning) export(cli_blockquote) export(cli_bullets) export(cli_bullets_raw) export(cli_code) export(cli_div) export(cli_dl) export(cli_end) export(cli_fmt) export(cli_format) export(cli_format_method) export(cli_h1) export(cli_h2) export(cli_h3) export(cli_inform) export(cli_li) export(cli_list_themes) export(cli_ol) export(cli_output_connection) export(cli_par) export(cli_process_done) export(cli_process_failed) export(cli_process_start) export(cli_progress_along) export(cli_progress_bar) export(cli_progress_builtin_handlers) export(cli_progress_cleanup) export(cli_progress_demo) export(cli_progress_done) export(cli_progress_message) export(cli_progress_num) export(cli_progress_output) export(cli_progress_step) export(cli_progress_styles) export(cli_progress_update) export(cli_rule) export(cli_sitrep) export(cli_status) export(cli_status_clear) export(cli_status_update) export(cli_text) export(cli_tick_reset) export(cli_ul) export(cli_vec) export(cli_verbatim) export(cli_warn) export(code_highlight) export(code_theme_list) export(col_black) export(col_blue) export(col_br_black) export(col_br_blue) export(col_br_cyan) export(col_br_green) export(col_br_magenta) export(col_br_red) export(col_br_white) export(col_br_yellow) export(col_cyan) export(col_green) export(col_grey) export(col_magenta) export(col_none) export(col_red) export(col_silver) export(col_white) export(col_yellow) export(combine_ansi_styles) export(console_width) export(default_app) export(demo_spinners) export(diff_chr) export(diff_str) export(format_bullets_raw) export(format_error) export(format_inline) export(format_message) export(format_warning) export(get_spinner) export(has_keypress_support) export(hash_animal) export(hash_emoji) export(hash_file_md5) export(hash_file_sha1) export(hash_file_sha256) export(hash_file_xxhash) export(hash_file_xxhash64) export(hash_md5) export(hash_obj_animal) export(hash_obj_emoji) export(hash_obj_md5) export(hash_obj_sha1) export(hash_obj_sha256) export(hash_obj_xxhash) export(hash_obj_xxhash64) export(hash_raw_animal) export(hash_raw_emoji) export(hash_raw_md5) export(hash_raw_sha1) export(hash_raw_sha256) export(hash_raw_xxhash) export(hash_raw_xxhash64) export(hash_sha1) export(hash_sha256) export(hash_xxhash) export(hash_xxhash64) export(is_ansi_tty) export(is_dynamic_tty) export(is_utf8_output) export(keypress) export(list_border_styles) export(list_spinners) export(list_symbols) export(make_ansi_style) export(make_spinner) export(no) export(num_ansi_colors) export(pb_bar) export(pb_current) export(pb_current_bytes) export(pb_elapsed) export(pb_elapsed_clock) export(pb_elapsed_raw) export(pb_eta) export(pb_eta_raw) export(pb_eta_str) export(pb_extra) export(pb_id) export(pb_name) export(pb_percent) export(pb_pid) export(pb_rate) export(pb_rate_bytes) export(pb_rate_raw) export(pb_spin) export(pb_status) export(pb_timestamp) export(pb_total) export(pb_total_bytes) export(pluralize) export(pretty_print_code) export(qty) export(rule) export(ruler) export(simple_theme) export(spark_bar) export(spark_line) export(start_app) export(stop_app) export(style_blurred) export(style_bold) export(style_dim) export(style_hidden) export(style_hyperlink) export(style_inverse) export(style_italic) export(style_no_bg_color) export(style_no_blurred) export(style_no_bold) export(style_no_color) export(style_no_dim) export(style_no_hidden) export(style_no_inverse) export(style_no_italic) export(style_no_strikethrough) export(style_no_underline) export(style_reset) export(style_strikethrough) export(style_underline) export(symbol) export(test_that_cli) export(ticking) export(tree) export(truecolor) export(utf8_graphemes) export(utf8_nchar) export(utf8_substr) export(vt_output) importFrom(utils,getParseData) importFrom(utils,getSrcref) useDynLib(cli, .registration=TRUE) cli/LICENSE0000644000176200001440000000005114557444176012043 0ustar liggesusersYEAR: 2023 COPYRIGHT HOLDER: cli authors cli/NEWS.md0000644000176200001440000004417014752736552012145 0ustar liggesusers# cli 3.6.4 * Pluralization now handles edge cases (`NA`, `NaN`, `Inf` and `-Inf`) better (@rundel, #716). * The URI generated for `.file`, `.run`, `.help` and `.vignette` hyperlinks can now be configured via options and env vars (@jennybc, #739, #744). * `cli_progress_bar()` now accepts `total` = Inf or -Inf which mimics the behavior of when `total` is NA (@LouisMPenrod, #630). * `num_ansi_colors()` now does not warn in Emacs if the `INSIDE_EMACS` environment variable is not a proper version number (@rundel, #689). * `ansi_collapse()` and inline collapsing now uses `last` as the separator (without the serial comma) for two-element vectors if `sep2` is not given (@rundel, #681). * `ansi_collapse()` is now correct for length-1 vectors with style "head" if width is specified (@rundel, #590). * New `hash_xxhash()` etc. functions to calculate the xxHash of strings, raw vectors, objects, files. # cli 3.6.3 * cli now builds on ARM Windows. * "Solarized Dark" is now the default syntax highlighting theme in terminals. * The `{.obj_type_friendly}` inline style now only shows the first class name (#669 @olivroy). * Syntax highlighting now does not fail in RStudio if the rstudioapi package is not installed (#697). # cli 3.6.2 * `ansi_collapse(x, trunc = 1, style = "head")` now indeed shows one element if `length(x) == 2`, as documented (@salim-b, #572). * `ansi_collapse()` gains a `sep2` argument to specify a seperate separator for length-two inputs. It defaults to `" and "` which, in conjunction with the other defaults, produces a collapsed string that fully adheres to the [serial comma](https://en.wikipedia.org/wiki/Serial_comma) rules. (@salim-b, #569) * `ansi_string()` is now an exported function (@multimeric, #573). # cli 3.6.1 * ANSI hyperlinks are now turned off on the RStudio render plane (#581). # cli 3.6.0 * The progressr progress handler now reports progress correctly (@HenrikBengtsson, #558). * New `hash_*sha1()` functions to calculate the SHA-1 hash of strings, objects, files. * cli now shows progress bars after one second by default, if they are less than half way at the point. (Or after two seconds, unconditionally, as before.) See the the `cli.progress_show_after` option in `?cli-config` for details (#542). * `format_inline()` now has a new argument `keep_whitespace`, and it keeps whitespace, including newline and form feed characters by default. # cli 3.5.0 * New `keypress()` function to read a single key press from a terminal. * New function `pretty_print_code()` to print function objects with syntax highlighting at the R console. * `col_*` and `bg_*` functions how handle zero-length input correctly (#532). * New function `ansi_collapse()` to collapse character vectors into a single string. * `ansi_strtrim()` now handles some edge cases better, when `ellipsis` has length zero, and when it is wider than `width`. * New `hash_file_md5()` function to calculate the MD5 hash of one or more files. # cli 3.4.1 * cli has better error messages now. * New `format_inline()` argument: `collapse`, to collapse multi-line output, potentially because of `\f` characters. # cli 3.4.0 * New experimental styles to create ANSI hyperlinks in RStudio and terminals that support them. See `?cli::links` for details (#513). * Expressions that start and end with a `{}` substitution are now styled correctly. E.g. `{.code {var1} + {var2}}` (#517). * New `{.obj_type_friendly}` inline style to format the type of an R object in a user friendly way (#463). * Improved vector collapsing behavior. cli now shows both the beginning and end of the collapsed vector, by default (#419). * Nested `cli()` calls work now (#497). * Return values now work as they should within `cli()` calls (#496). * Style attributes with underscores have new names with dashes instead: `vec_sep`, `vec_last`, `vec_trunc`, `string-quote`. The old names still work, but the new ones take precedence (#483). * cli now does not crash at the end of the R session on Arm Windows (#494; @kevinushey) * Vectors are truncated at 20 elements now by default, instead of 100 (#430). * 20 new spinners from the awesome [cli-spinners](https://github.com/sindresorhus/cli-spinners) package, and from @HenrikBengtsson in #469. Run this to demo them, some need UTF-8 and emoji support: ```r new <- c("dots13", "dots8Bit", "sand", "material", "weather", "christmas", "grenade", "point", "layer", "betaWave", "fingerDance", "fistBump", "soccerHeader", "mindblown", "speaker", "orangePulse", "bluePulse", "orangeBluePulse", "timeTravel", "aesthetic", "growVeriticalDotsLR", "growVeriticalDotsRL", "growVeriticalDotsLL", "growVeriticalDotsRR") demo_spinners(new) ``` * cli exit handlers are now compatible again with the withr package (#437). * cli functions now keep trailing `\f` characters as newlines. They also keep multiple consecutive `\f` as multiple newlinees (#491). * `{}` substitutions within inline styles are now formatted correctly. E.g. `{.code download({url})}` will not add backticks to `url`, and `{.val pre-{x}-post}` will format the whole value instead of `x`. (#422, #474). * cli now replaces newline characters within `{.class ... }` inline styles with spaces. If the `cli.warn_inline_newlines` option is set to TRUE, then it also throws a warning. (#417). * `code_highlight` now falls back to the default theme (instead of no theme) for unknown RStudio themes (#482, @rossellhayes). * `cli_abort()` now supplies `.frame` to `abort()`. This fixes an issue with the `.internal = TRUE` argument (r-lib/rlang#1386). * cli now does a better job at detecting the RStudio build pane, job pane and render pane, and their capabilities w.r.t. ANSI colors and hyperlinks. Note that this requires a daily build of RStudio (#465). * New functions for ANSI strings: `ansi_grep()`, `ansi_grepl()`, `ansi_nzchar()`. They work like the corresponding base R functions, but handle ANSI markup. * `style_hyperlink()` (really) no longer breaks if the env variable `VTE_VERSION` is of the form `\d{4}`, i.e., 4 consecutive numbers (#441, @michaelchirico) * `cli_dl()` and its corresponding `cli_li()` can now style the labels. * The behavior cli's inline styling expressions is now more predictable. cli does not try to evaluate a styled string as an R expression any more. E.g. the meaning of `"{.emph +1}"` is now always the "+1", with style `.emph`, even if an `.emph` variable is available and the `.emph + 1` expression can be evaluated. * Functions that apply bright background colors (e.g. `bg_br_yellow()`) now close themselves. They no longer format text after the end of the function (#484, @rossellhayes). # cli 3.3.0 * `style_hyperlink()` no longer breaks if the env variable `VTE_VERSION` is of the form `\d{4}`, i.e., 4 consecutive numbers (#441, @michaelchirico) * `ansi_*()` functions support ANSI hyperlinks again (#444). * Turning off ANSI colors via the `cli.num_colors` option or the `R_CLI_NUM_COLORS` or the `NO_COLOR` environment variable now also turns off ANSI hyperlinks (#447). * `symbol` now only has two variants: UTF-8 and ASCII. There are no special variants for RStudio and Windows RGui any more (#424). # cli 3.2.0 ## Breaking change * The `cli_theme_dark` option is now known as `cli.theme_dark`, to be consistent with all other cli option names (#380). ## Other changes * The preferred names of the S3 classes `ansi_string`, `ansi_style`, `boxx`, `rule` and `tree` now have `cli_` prefix: `cli_ansi_string`, etc. This will help avoiding name conflicts with other packages eventually, but for now the old names are kept as well, for compatibility. * `cli_abort()` has been updated to work nicely with rlang 1.0. The default `call` and backtrace soft-truncation are set to `.envir` (which itself is set to the immediate caller of `cli_abort()` by default). Line formatting now happens lazily at display time via `rlang::cnd_message()` (which is called by the `conditionMessage()` method for rlang errors). * New `hash_sha256()` function to calculate SHA-256 hashes. New `hash_raw_*()`, `hash_obj_*()` and `hash_file_*()` functions to calculate various hashes of raw vectors, R objects and files. * You can use the new `cli.default_num_colors` option to set the default number of ANSI colors, only if ANSI support is otherwise detected. See the details in the manual of `num_ansi_colors()`. * You can set the new `ESS_BACKGROUND_MODE` environment variable to `dark` to indicate dark mode. * cli now handles quotes and comment characters better in the semantion `cli_*()` functions that perform glue string interpolation (#370). # cli 3.1.1 * `style_hyperlink()` gains a `params=` argument (#384). # cli 3.1.0 ## Breaking changes * The C progress bar API now uses `double` instead of `int` as the data type of the progress units (#335). ## New features * Several improvements and changes in the `ansi_*()` functions: - most `ansi_*()` functions are now implemented in C and they are much faster (#316). - they handle `NA` values better. - many functions now use UTF-8 graphemes by default instead of code points. E.g. `ansi_nchar()` counts graphemes, etc. - they convert their input to UTF-8 and always return UTF-8 encoded strings. - new function `ansi_simplify()` to remove superfluous ANSI tags. - new function `ansi_html()` to convert ANSI-highlighted strings to HTML. - `ansi_has_any()` and `ansi_strip()` now have `sgr` and `csi` arguments to look for SGR tags, CSI tags, or both. * New functions that handle UTF-8 encoded strings correctly: `utf8_graphemes()`, `utf8_nchar()`, `utf8_substr()`. * Support for palettes, including a colorblind friendly palette. See `?ansi_palettes` for details. * True color support: `num_ansi_colors()` now detects terminals with 24 bit color support, and `make_ansi_style()` uses the exact RGB colors on these terminals (#208). * The new `col_br_*()` and `bg_br_()` functions create bright versions of eight base ANSI colors (#327). * New function `code_highlight()` to syntax highlight R code. It supports several themes out of the box, see `code_theme_list()` (#348). * New functions for hashing: `hash_animal()`, `hash_emoji()` and `hash_md5()`. * New `diff_chr()` and `diff_str()` functions to calculate the difference of character vectors and letters of strings. ## Smaller improvements * Progress bars with `clear = FALSE` now print the last, completed, state properly. * The progress bar for Shiny apps now handles output from `cli_progress_output()`. * Progress variables in C `format_done` strings work correctly now (#337). * `cli_dl()` now works with an empty description, and gives a better error for invalid input (#347). * `rule()` is now works better if the labels have ANSI markup. * `cli_spark` objects now have `format()` and `print()` methods. * `cli_process_done()` now does not error without a process (#351). * ANSI markup is now supported in RStudio jobs (#353). * The lack of ANSI support is now again correctly detected if there is an active `sink()` (#366). # cli 3.0.1 * `ansi_strtrim()` now correctly keeps `NA` values (#309). * `format_inline()` now uses the correct environment (@rundel, #314). # cli 3.0.0 * New functions for progress bars, please see the new articles at https://cli.r-lib.org/articles/ for details. * New `cli_abort()`, `cli_warn()` and `cli_inform()` functions, to throw errors with cli pluralization and styling. * New `format_inline()` function to format a cli string without emitting it (#278). # cli 2.5.0 * New `style_no_*()` functions to locally undo styling. New `col_none()` and `bg_none()` functions to locally undo text color and background color. * It is now possible to undo text and background color in a theme, by setting them to `NULL` or `"none"`. * `cli_memo()` was renamed to `cli_bullets()`, as it is by default formatted as a bullet list (#250). * New `ansi_toupper()`, `ansi_tolower` and `ansi_chartr()` functions, the ANSI styling aware variants of `toupper()`, `tolower()` and `chartr()` (#248). * New `test_that_cli()` helper function to write testthat tests for cli output. * `tree()` now does not produce warnings for tibbles (#238). * New inline style: `.cls` to format class names, e.g. `"{.var fit} must be an {.cls lm} object"`. # cli 2.4.0 * New `cli_memo()` function to create a list of items or tasks. * New `cli::cli()` function to create a single cli message from multiple cli calls (#170). * cli now highlights weird names, e.g. path names with leading or trailing space (#227). * Styling is fixed at several places. In particular, nested lists should be now formatted better (#221). * New `spark_bar()` and `spark_line()` functions to draw small bar or line charts. # cli 2.3.1 * ANSI color support detection works correctly now in older RStudio, and also on older R versions. * `cli_h1()`, `cli_h2()` and `cli_h3()` now work with multiple glue substitutions (#218). # cli 2.3.0 * `boxx()` now correctly calculates the width of the box for non-ASCII characters. * New `ansi_trimws()` and `ansi_strwrap()` functions, they are similar to `trimws()` and `strwrap()` but work on ANSI strings. * New `ansi_columns()` function to format ANSI strings in multiple columns. * `ansi_substr()`, `ansi_substring()`, `ansi_strsplit()`, `ansi_align()` now always return `cli_ansi_string` objects. * `ansi_nchar()`, `ansi_align()`, `ansi_strtrim()` and the new `ansi_strwrap()` as well handle wide Unicode correctly, according to their display width. * `boxx()` can now add headers and footers to boxes. # cli 2.2.0 * New `style_hyperlink()` function to add hyperlinks, on terminals that support them. * `cli_format_method()` now works properly in knitr, and other environments that catch message conditions (#159). * ANSI strings created by `col_*`, `bg_*` and `style_*` now also add the `character` class to the result. This fixes issues with code that expect `character` objects. * New functions to manipulate ANSI strings: `ansi_aling()`, `ansi_has_any()`, `ansi_nchar()`, `ansi_regex()`, `ansi_strip()`, `ansi_strsplit()`, `ansi_substr()`, `ansi_substring()`. # cli 2.1.0 * New `cli_vec()` function to allow easier formatting of collapsed vectors. It is now also possible to use styling to set the collapsing parameters (#129). * New `pluralize()` function to perform pluralization without generating cli output (#155). * `console_width()` works better now in RStudio, and also in terminals. * Styling of verbatim text work properly now (#147, @tzakharko). * Messages (i.e. `message` conditions) coming from cli now have the `cliMessage` class, so you can easily suppress them without suppressing other messages (#156). * cli prints the output to `stderr()` now, if there is an output or message sink. This is to make interactive and non-interactive sessions consistent (#153). * Pluralization works correctly now if the last alternative is the empty string (#158). * cli now caches the result of the dark background detection in iTerm on macOS. Reload cli to delete the cache (#131). * The `is_dynamic_tty()`, `is_ansi_tty()` and `ansi_hide_cursor()` and related functions now default to the `"auto"` stream, which is automatically selected to be either `stdout()` or `stderr()`. See the manual for details (#144). * The default theme now quotes file names, paths, email addresses if they don't start or end with an alphanumeric character or a slash. This is to make it easier to spot names that start or end with a space (#167). * `make_spinner()` clears the line properly now (@tzakharko, #164). * Semantic cli functions now automatically replace Unicode non-breaking space characters (`\u00a0`) with regular space characters, right before output. They are still used to calculate the line breaks, but not outputted (#161). * Progress bars now respect `is_dynamic_tty()` and do not output `\r` when this is false (@jimhester, #177) # cli 2.0.2 * The status bar now does not simplify multiple spaces by a single space. * cli now does not crash if it fails to detect whether the RStudio theme is a dark theme (#138). * cli now works better with wide Unicode characters, for example emojis. In particular, a status bar containing emojis is cleared properly (#133). * The status bar now does not flicker when updated, in terminals (#135). # cli 2.0.1 * Symbols (`symbol$*`) are now correctly printed in RStudio on Windows (#124). * The default theme for `cli_code()` output looks better now, especially in RStudio (#123). * Remove spurious newline after a `cli_process_start()` was cleared manually, and also at the end of the function. * Use Oxford comma when listing 3 or more items (@jonocarroll, #128). # cli 2.0.0 ## Semantic command line interface tools cli 2.0.0 has a new set of functions that help creating a CLI using a set of higher level elements: headings, paragraphs, lists, alerts, code blocks, etc. The formatting of all elements can be customized via themes. See the "Building a semantic CLI" article on the package web site: https://cli.r-lib.org ## Bug fixes: * Fix a bug in `is_dynamic_tty()`, setting `R_CLI_DYNAMIC="FALSE"` now properly turns dynamic tty off (#70). # cli 1.1.0 * cli has now functions to add ANSI styles to text. These use the crayon package internally, and provide a simpler interface. See the `col_*`, `bg_*`, `style_*` and also the `make_ansi_style()` and `combine_ansi_styles()` functions (#51). * New `is_dynamic_tty()` function detects if `\r` should be used for a stream (#62). * New `is_ansi_tty()` function detects if ANSI control sequences can be used for a stream. * New `ansi_hide_cursor()`, `ansi_show_cursor()` and `ansi_with_hidden_cursor()` functions to hide and show the cursor in terminals. * New `make_spinner()` function helps integrating spinners into your functions. * Now `symbol` always uses ASCII symbols when the `cli.unicode` option is set to `FALSE`. # 1.0.1 * New `cli_sitrep()` function, situation report about UTF-8 and ANSI color support (#53). * Fall back to ASCII only characters on non-Windows platforms without UTF-8 support, and also in LaTeX when running knitr (#34). # cli 1.0.0 First public release. cli/inst/0000755000176200001440000000000014557444176012017 5ustar liggesuserscli/inst/include/0000755000176200001440000000000014557444176013442 5ustar liggesuserscli/inst/include/cli/0000755000176200001440000000000014557444176014211 5ustar liggesuserscli/inst/include/cli/progress.h0000644000176200001440000002677414557444176016246 0ustar liggesusers#ifndef R_CLI_PROGRESS_H #define R_CLI_PROGRESS_H #include #include #ifdef __cplusplus extern "C" { #endif // ---------------------------------------------------------------------- // Public API // ---------------------------------------------------------------------- //' ### `CLI_SHOULD_TICK` //' //' A macro that evaluates to (int) 1 if a cli progress bar update is due, //' and to (int) 0 otherwise. If the timer hasn't been initialized in this //' compilation unit yet, then it is always 0. To initialize the timer, //' call `cli_progress_init_timer()` or create a progress bar with //' `cli_progress_bar()`. #define CLI_SHOULD_TICK //' ### `cli_progress_add()` //' //' ```c //' void cli_progress_add(SEXP bar, double inc); //' ``` //' //' Add a number of progress units to the progress bar. It will also //' trigger an update if an update is due. //' //' * `bar`: progress bar object. //' * `inc`: progress increment. static R_INLINE void cli_progress_add(SEXP bar, double inc); //' ### `cli_progress_bar()` //' //' ```c //' SEXP cli_progress_bar(double total, SEXP config); //' ``` //' //' Create a new progress bar object. The returned progress bar object //' must be `PROTECT()`-ed. //' //' * `total`: Total number of progress units. Use `NA_REAL` if it is not //' known. //' * `config`: R named list object of additional parameters. May be `NULL` //' (the C `NULL~) or `R_NilValue` (the R `NULL`) for the defaults. //' //' `config` may contain the following entries: //' //' * `name`: progress bar name. //' * `status`: (initial) progress bar status. //' * `type`: progress bar type. //' * `total`: total number of progress units. //' * `show_after`: show the progress bar after the specified number of //' seconds. This overrides the global `show_after` option. //' * `format`: format string, must be specified for custom progress bars. //' * `format_done`: format string for successful termination. //' * `format_failed`: format string for unsuccessful termination. //' * `clear`: whether to remove the progress bar from the screen after //' termination. //' * `auto_terminate`: whether to terminate the progress bar when the //' number of current units equals the number of total progress units. //' //' #### Example //' //' ```c //' #include //' SEXP progress_test1() { //' int i; //' SEXP bar = PROTECT(cli_progress_bar(1000, NULL)); //' for (i = 0; i < 1000; i++) { //' cli_progress_sleep(0, 4 * 1000 * 1000); //' if (CLI_SHOULD_TICK) cli_progress_set(bar, i); //' } //' cli_progress_done(bar); //' UNPROTECT(1); //' return Rf_ScalarInteger(i); //' } //' ``` static R_INLINE SEXP cli_progress_bar(double total, SEXP config); //' ### `cli_progress_done()` //' //' ```c //' void cli_progress_done(SEXP bar); //' ``` //' //' Terminate the progress bar. //' //' * `bar`: progress bar object. static R_INLINE void cli_progress_done(SEXP bar); //' ### `cli_progress_init_timer()` //' //' ```c //' void cli_progress_init_timer(); //' ``` //' //' Initialize the cli timer without creating a progress bar. static R_INLINE void cli_progress_init_timer(void); //' ### `cli_progress_num()` //' //' ```c //' int cli_progress_num(); //' ``` //' //' Returns the number of currently active progress bars. static R_INLINE int cli_progress_num(void); //' ### `cli_progress_set()` //' //' ```c //' void cli_progress_set(SEXP bar, double set); //' ``` //' //' Set the progress bar to the specified number of progress units. //' //' * `bar`: progress bar object. //' * `set`: number of current progress progress units. static R_INLINE void cli_progress_set(SEXP bar, double set); //' ### `cli_progress_set_clear()` //' //' ```c //' void cli_progress_set_clear(SEXP bar, int clear); //' ``` //' //' Set whether to remove the progress bar from the screen. You can call //' this any time before `cli_progress_done()` is called. //' //' * `bar`: progress bar object. //' * `clear`: whether to remove the progress bar from the screen, zero or //' one. static R_INLINE void cli_progress_set_clear(SEXP bar, int clear); //' ### `cli_progress_set_format()` //' //' ```c //' void cli_progress_set_format(SEXP bar, const char *format, ...); //' ``` //' //' Set a custom format string for the progress bar. This call does not //' try to update the progress bar. If you want to request an update, //' call `cli_progress_add()`, `cli_progress_set()` or //' `cli_progress_update()`. //' //' * `bar`: progress bar object. //' * `format`: format string. //' * `...`: values to substitute into `format`. //' //' `format` and `...` are passed to `vsnprintf()` to create a format //' string. //' //' Format strings may contain glue substitutions, referring to //' [progress variables][progress-variables], pluralization, and cli //' styling. //' //' [progress-variables]: https://cli.r-lib.org/dev/reference/progress-variables.html static R_INLINE void cli_progress_set_format(SEXP bar, const char *format, ...); //' ### `cli_progress_set_name()` //' //' ```c //' void cli_progress_set_name(SEXP bar, const char *name); //' ``` //' //' Set the name of the progress bar. //' //' * `bar`; progress bar object. //' * `name`: progress bar name. static R_INLINE void cli_progress_set_name(SEXP bar, const char *name); //' ### `cli_progress_set_status()` //' //' ```c //' void cli_progress_set_status(SEXP bar, const char *status); //' ``` //' //' Set the status of the progress bar. //' //' * `bar`: progress bar object. //' * `status `: progress bar status. static R_INLINE void cli_progress_set_status(SEXP bar, const char *status); //' ### `cli_progress_set_type()` //' //' ```c //' void cli_progress_set_type(SEXP bar, const char *type); //' ``` //' //' Set the progress bar type. Call this function right after creating //' the progress bar with `cli_progress_bar()`. Otherwise the behavior is //' undefined. //' //' * `bar`: progress bar object. //' * `type`: progress bar type. Possible progress bar types: //' `iterator`, `tasks`, `download` and `custom`. static R_INLINE void cli_progress_set_type(SEXP bar, const char *type); //' ### `cli_progress_update()` //' //' ```c //' void cli_progress_update(SEXP bar, double set, double inc, int force); //' ``` //' //' Update the progress bar. Unlike the simpler `cli_progress_add()` and //' `cli_progress_set()` function, it can force an update if `force` is //' set to 1. //' //' * `bar`: progress bar object. //' * `set`: the number of current progress units. It is ignored if //' negative. //' * `inc`: increment to add to the current number of progress units. //' It is ignored if `set` is not negative. //' * `force`: whether to force an update, even if no update is due. //' //' To force an update without changing the current number of progress units, //' supply `set = -1`, `inc = 0` and `force = 1`. static R_INLINE void cli_progress_update(SEXP bar, double set, double inc, int force); // ---------------------------------------------------------------------- // Internals // ---------------------------------------------------------------------- typedef volatile int vint; static vint cli__false = 0; static vint *cli__should_tick = &cli__false; #ifndef __has_builtin // Optional of course. #define __has_builtin(x) 0 // Compatibility with non-clang compilers. #endif #if __has_builtin (__builtin_expect) # define CLI_UNLIKELY(a) __builtin_expect((a), 0) # define CLI_LIKELY(a) __builtin_expect((a), 1) # else # define CLI_UNLIKELY(a) a # define CLI_LIKELY(a) a #endif #undef CLI_SHOULD_TICK #define CLI_SHOULD_TICK (CLI_UNLIKELY(*cli__should_tick)) static R_INLINE void cli_progress_done(SEXP bar) { if (Rf_isNull(bar)) return; static void (*ptr)(SEXP) = NULL; if (ptr == NULL) { ptr = (void (*)(SEXP)) R_GetCCallable("cli", "cli_progress_done"); } ptr(bar); } #ifdef R_CLEANCALL_SUPPORT static void cli_progress_done2(SEXP bar) { if (Rf_isNull(bar)) return; static void (*ptr)(SEXP) = NULL; if (ptr == NULL) { ptr = (void (*)(SEXP)) R_GetCCallable("cli", "cli_progress_done"); } ptr(bar); } #endif static R_INLINE void cli_progress_init_timer(void) { static void (*ptr)(vint **) = NULL; if (ptr == NULL) { ptr = (void (*)(vint **)) R_GetCCallable("cli", "cli_progress_init_timer"); } ptr(&cli__should_tick); } static R_INLINE SEXP cli_progress_bar(double total, SEXP config) { static SEXP (*ptr)(vint **, double, SEXP) = NULL; if (ptr == NULL) { ptr = (SEXP (*)(vint **, double, SEXP)) R_GetCCallable("cli", "cli_progress_bar"); } SEXP bar = PROTECT(ptr(&cli__should_tick, total, config)); #ifdef R_CLEANCALL_SUPPORT if (r_cleancall_is_active()) { r_call_on_early_exit((void (*)(void *)) cli_progress_done2, (void*) bar); } #endif UNPROTECT(1); return bar; } static R_INLINE void cli_progress_set_name(SEXP bar, const char *name) { if (Rf_isNull(bar)) return; static void (*ptr)(SEXP, const char*) = NULL; if (ptr == NULL) { ptr = (void (*)(SEXP, const char*)) R_GetCCallable("cli", "cli_progress_set_name"); } ptr(bar, name); } static R_INLINE void cli_progress_set_status(SEXP bar, const char *status) { if (Rf_isNull(bar)) return; static void (*ptr)(SEXP, const char*) = NULL; if (ptr == NULL) { ptr = (void (*)(SEXP, const char*)) R_GetCCallable("cli", "cli_progress_set_status"); } ptr(bar, status); } static R_INLINE void cli_progress_set_type(SEXP bar, const char *type) { if (Rf_isNull(bar)) return; static void (*ptr)(SEXP, const char*) = NULL; if (ptr == NULL) { ptr = (void (*)(SEXP, const char*)) R_GetCCallable("cli", "cli_progress_set_type"); } ptr(bar, type); } static R_INLINE void cli_progress_set_clear(SEXP bar, int clear) { if (Rf_isNull(bar)) return; static void (*ptr)(SEXP, int) = NULL; if (ptr == NULL) { ptr = (void (*)(SEXP, int)) R_GetCCallable("cli", "cli_progress_set_clear"); } ptr(bar, clear); } static R_INLINE void cli_progress_set(SEXP bar, double set) { if (Rf_isNull(bar)) return; static void (*ptr)(SEXP, double) = NULL; if (ptr == NULL) { ptr = (void (*)(SEXP, double)) R_GetCCallable("cli", "cli_progress_set"); } ptr(bar, set); } static R_INLINE void cli_progress_set_format(SEXP bar, const char *format, ...) { if (Rf_isNull(bar)) return; static void (*ptr)(SEXP, const char*) = NULL; static char str[1024]; if (ptr == NULL) { ptr = (void (*)(SEXP, const char*)) R_GetCCallable("cli", "cli_progress_set_format"); } va_list ap; va_start(ap, format); vsnprintf(str, sizeof(str) / sizeof(char), format, ap); ptr(bar, str); } static R_INLINE void cli_progress_add(SEXP bar, double inc) { if (Rf_isNull(bar)) return; static void (*ptr)(SEXP, double) = NULL; if (ptr == NULL) { ptr = (void (*)(SEXP, double)) R_GetCCallable("cli", "cli_progress_add"); } ptr(bar, inc); } static R_INLINE int cli_progress_num(void) { static int (*ptr)(void) = NULL; if (ptr == NULL) { ptr = (int (*)(void)) R_GetCCallable("cli", "cli_progress_num"); } return ptr(); } static R_INLINE void cli_progress_sleep(int s, long ns) { static void (*ptr)(int, long) = NULL; if (ptr == NULL) { ptr = (void (*)(int, long)) R_GetCCallable("cli", "cli_progress_sleep"); } ptr(s, ns); } static R_INLINE void cli_progress_update(SEXP bar, double set, double inc, int force) { static void (*ptr)(SEXP, double, double, int) = NULL; if (ptr == NULL) { ptr = (void (*)(SEXP, double, double, int)) R_GetCCallable("cli", "cli_progress_update"); } ptr(bar, set, inc, force); } #ifdef __cplusplus } #endif #endif cli/inst/shiny/0000755000176200001440000000000014557444176013151 5ustar liggesuserscli/inst/shiny/along/0000755000176200001440000000000014557444176014251 5ustar liggesuserscli/inst/shiny/along/app.R0000644000176200001440000000250014557444176015151 0ustar liggesusers# modified from https://shiny.rstudio.com/articles/progress.html # This example uses `cli_progress_along()`. library(cli) # !!! You don't need these in real code. # cli.progress_show_after makes sure that we see the progress bar from # the beginning, not only after a delay. options(cli.progress_show_after = 0) # !!! You don't need these in real code. # This also requests logging the progress bar to the standard output, # in the console. options(cli.progress_handlers_only = c("shiny", "logger")) server <- function(input, output) { output$plot <- renderPlot({ input$goPlot # Re-run when button is clicked # Create 0-row data frame which will be used to store data dat <- data.frame(x = numeric(0), y = numeric(0)) # Number of times we'll go through the loop n <- 10 for (i in cli_progress_along(1:n, "Rendering", format = "At {i}")) { # Each time through the loop, add another row of data. This is # a stand-in for a long-running computation. dat <- rbind(dat, data.frame(x = rnorm(1), y = rnorm(1))) # Pause for 0.1 seconds to simulate a long computation. Sys.sleep(0.5) } plot(dat$x, dat$y) }) } ui <- shinyUI(basicPage( plotOutput('plot', width = "300px", height = "300px"), actionButton('goPlot', 'Go plot') )) shinyApp(ui = ui, server = server) cli/inst/shiny/nested/0000755000176200001440000000000014557444176014433 5ustar liggesuserscli/inst/shiny/nested/app.R0000644000176200001440000000323614557444176015342 0ustar liggesusers# modified from https://shiny.rstudio.com/articles/progress.html # Nested progress bars library(cli) # !!! You don't need these in real code. # cli.progress_show_after makes sure that we see the progress bar from # the beginning, not only after a delay. options(cli.progress_show_after = 0) # !!! You don't need these in real code. # This also requests logging the progress bar to the standard output, # in the console. options(cli.progress_handlers_only = c("shiny", "logger")) server <- function(input, output) { output$plot <- renderPlot({ input$goPlot # Re-run when button is clicked # Create 0-row data frame which will be used to store data dat <- data.frame(x = numeric(0), y = numeric(0)) # Number of times we'll go through the loop n <- 10 # Set auto-terminate to FALSE, as we do not want the progress bar # terminated when we reach step 10, as at that point we are only at # the beginning of the iteration cli_progress_bar( "Rendering plot", total = n, format = "Starting {i}" ) for (i in 1:n) { cli_progress_update(set = i - 1) # Each time through the loop, add another row of data. This is # a stand-in for a long-running computation. dat <- rbind(dat, data.frame(x = rnorm(1), y = rnorm(1))) render_plot_detail(i) } plot(dat$x, dat$y) }) } ui <- shinyUI(basicPage( plotOutput('plot', width = "300px", height = "300px"), actionButton('goPlot', 'Go plot') )) render_plot_detail <- function(i) { cli_progress_bar(total = 10, paste("Detailing", i)) for (i in 1:10) { cli_progress_update() Sys.sleep(0.1) } } shinyApp(ui = ui, server = server) cli/inst/shiny/simple/0000755000176200001440000000000014557444176014442 5ustar liggesuserscli/inst/shiny/simple/app.R0000644000176200001440000000251514557444176015350 0ustar liggesusers# modified from https://shiny.rstudio.com/articles/progress.html library(cli) # !!! You don't need these in real code. # cli.progress_show_after makes sure that we see the progress bar from # the beginning, not only after a delay. options(cli.progress_show_after = 0) # !!! You don't need these in real code. # This also requests logging the progress bar to the standard output, # in the console. options(cli.progress_handlers_only = c("shiny", "logger")) server <- function(input, output) { output$plot <- renderPlot({ input$goPlot # Re-run when button is clicked # Create 0-row data frame which will be used to store data dat <- data.frame(x = numeric(0), y = numeric(0)) # Number of times we'll go through the loop n <- 10 cli_progress_bar(total = n, "Rendering plot") for (i in 1:n) { # Each time through the loop, add another row of data. This is # a stand-in for a long-running computation. dat <- rbind(dat, data.frame(x = rnorm(1), y = rnorm(1))) cli_progress_update(status = paste("Doing part", i)) # Pause for 0.1 seconds to simulate a long computation. Sys.sleep(0.5) } plot(dat$x, dat$y) }) } ui <- shinyUI(basicPage( plotOutput('plot', width = "300px", height = "300px"), actionButton('goPlot', 'Go plot') )) shinyApp(ui = ui, server = server) cli/inst/shiny/output/0000755000176200001440000000000014557444176014511 5ustar liggesuserscli/inst/shiny/output/app.R0000644000176200001440000000260714557444176015421 0ustar liggesusers# modified from https://shiny.rstudio.com/articles/progress.html library(cli) # !!! You don't need these in real code. # cli.progress_show_after makes sure that we see the progress bar from # the beginning, not only after a delay. options(cli.progress_show_after = 0) # !!! You don't need this in real code. options(cli.progress_handlers_only = "shiny") server <- function(input, output) { output$plot <- renderPlot({ input$goPlot # Re-run when button is clicked # Create 0-row data frame which will be used to store data dat <- data.frame(x = numeric(0), y = numeric(0)) # Number of times we'll go through the loop n <- 10 cli_progress_bar(total = n, "Rendering plot") for (i in 1:n) { # Each time through the loop, add another row of data. This is # a stand-in for a long-running computation. dat <- rbind(dat, data.frame(x = rnorm(1), y = rnorm(1))) cli_progress_update(status = paste("Doing part", i)) # Pause for 0.5 seconds to simulate a long computation. # Produce some extra output Sys.sleep(0.5) msg <- paste(strwrap(cli:::lorem_ipsum(1, 1)), collapse = "\n") if (i != n) cli_progress_output(msg) Sys.sleep(0.5) } plot(dat$x, dat$y) }) } ui <- shinyUI(basicPage( plotOutput('plot', width = "300px", height = "300px"), actionButton('goPlot', 'Go plot') )) shinyApp(ui = ui, server = server) cli/inst/shiny/format/0000755000176200001440000000000014557444176014441 5ustar liggesuserscli/inst/shiny/format/app.R0000644000176200001440000000256314557444176015352 0ustar liggesusers# modified from https://shiny.rstudio.com/articles/progress.html # This app has a custom format string library(cli) # !!! You don't need these in real code. # cli.progress_show_after makes sure that we see the progress bar from # the beginning, not only after a delay. options(cli.progress_show_after = 0) # !!! You don't need these in real code. # This also requests logging the progress bar to the standard output, # in the console. options(cli.progress_handlers_only = c("shiny", "logger")) server <- function(input, output) { output$plot <- renderPlot({ input$goPlot # Re-run when button is clicked # Create 0-row data frame which will be used to store data dat <- data.frame(x = numeric(0), y = numeric(0)) # Number of times we'll go through the loop n <- 10 cli_progress_bar(total = n, "Rendering plot", format = "Starting part {i}") for (i in 1:n) { # Each time through the loop, add another row of data. This is # a stand-in for a long-running computation. dat <- rbind(dat, data.frame(x = rnorm(1), y = rnorm(1))) cli_progress_update() # Pause for 0.1 seconds to simulate a long computation. Sys.sleep(0.5) } plot(dat$x, dat$y) }) } ui <- shinyUI(basicPage( plotOutput('plot', width = "300px", height = "300px"), actionButton('goPlot', 'Go plot') )) shinyApp(ui = ui, server = server) cli/inst/examples/0000755000176200001440000000000014557444176013635 5ustar liggesuserscli/inst/examples/apps/0000755000176200001440000000000014557444176014600 5ustar liggesuserscli/inst/examples/apps/up.R0000755000176200001440000000277614557444176015366 0ustar liggesusers#! /usr/bin/env Rscript ## To get the async package: ## source("https://install-github.me/r-lib/async") setup_app <- function() { theme <- list("url" = list(color = "blue")) app <- cliapp::start_app(theme = theme, output = "stdout") } load_packages <- function() { tryCatch({ library(cliapp) library(async) library(docopt) }, error = function(e) { cli_alert_danger("The {.pkg async} and {.pkg docopt} packages are needed!") q(save = "no", status = 1) }) } up <- function(urls, timeout = 5) { load_packages() setup_app() chk_url <- async(function(url, ...) { http_head(url, ...)$ then(function(res) { if (res$status_code < 300) { cli_alert_success("{.url {url}} ({res$times[['total']]}s)") } else { cli_alert_danger("{.url {url}} (HTTP {res$status_code})") } })$ catch(error = function(err) { e <- if (grepl("timed out", err$message)) "timed out" else "error" cli_alert_danger("{.url {url}} ({e})") }) }) invisible(synchronise( async_map(urls, chk_url, options = list(timeout = timeout)) )) } parse_arguments <- function() { "Usage: up.R [-t timeout] [URLS ...] up.R -h | --help Options: -t timeout Timeout for giving up on a site, in seconds [default: 5]. -h --help Print this help message Check if web sites are up. " -> doc docopt(doc) } if (is.null(sys.calls())) { load_packages() opts <- parse_arguments() up(opts$URLS, timeout = as.numeric(opts$t)) } cli/inst/examples/apps/outdated.R0000755000176200001440000000403014557444176016534 0ustar liggesusers#! /usr/bin/env Rscript ## To get the pkgcache package: ## source("https://install-github.me/r-lib/pkgcache") setup_app <- function() { theme <- list( "url" = list(color = "blue"), ".pkg" = list(color = "orange")) start_app(theme = theme, output = "stdout") } load_packages <- function() { tryCatch(suppressPackageStartupMessages({ library(cli) library(pkgcache) library(docopt) }), error = function(e) { cli_alert_danger("The {.pkg pkgcache} and {.pkg docopt} packages are needed!") q(save = "no", status = 1) }) } outdated <- function(lib = NULL, notcran = FALSE) { load_packages() setup_app() if (is.null(lib)) lib <- .libPaths()[1] inst <- utils::installed.packages(lib = lib) cli_alert_info("Getting repository metadata") repo <- meta_cache_list(rownames(inst)) if (!notcran) inst <- inst[inst[, "Package"] %in% repo$package, ] for (i in seq_len(nrow(inst))) { pkg <- inst[i, "Package"] iver <- inst[i, "Version"] if (! pkg %in% repo$package) { cli_alert_info("{.pkg {pkg}}: \tnot a CRAN/BioC package") next } rpkg <- repo[repo$package == pkg, ] newer <- rpkg[package_version(rpkg$version) > iver, ] if (!nrow(newer)) next nver <- package_version(newer$version) mnver <- max(nver) newest <- newer[mnver == nver, ] bin <- if (any(newest$platform != "source")) "bin" else "" src <- if (any(newest$platform == "source")) "src" else "" cli_alert_danger("{.emph {pkg}}") cli_alert_danger( "{.pkg {pkg}} \t{iver} {symbol$arrow_right} {mnver} {.emph ({bin} {src})}") } } parse_arguments <- function() { "Usage: outdated.R [-l lib] [-x] outdated.R -h | --help Options: -x Print not CRAN/BioC packages as well -l lib Library directory, default is first directory in the lib path -h --help Print this help message Check for outdated packages in a package library. " -> doc docopt(doc) } if (is.null(sys.calls())) { load_packages() opts <- parse_arguments() outdated(opts$l, opts$x) } cli/inst/examples/apps/search.R0000755000176200001440000000403214557444176016172 0ustar liggesusers#! /usr/bin/env Rscript setup_app <- function() { theme <- list( "url" = list(color = "blue"), ".pkg" = list(color = "orange")) start_app(theme = theme, output = "stdout") } load_packages <- function() { tryCatch({ library(cliapp) library(pkgsearch) library(docopt) library(prettyunits) error = function(e) { cli_alert_danger( "The {.pkg pkgsearch}, {.pkg prettyunits} and {.pkg docopt} packages are needed!") q(save = "no", status = 1) } }) } search <- function(terms, from = 1, size = 5) { load_packages() setup_app() term <- paste(encodeString(quote = '"', terms), collapse = " ") result <- do_query(term, from = from, size = size) format_result(result, from = from, size = size) invisible() } `%||%` <- function(l, r) if (is.null(l)) r else l do_query <- function(query, from, size) { cli_alert_info("Searching...") pkg_search(query, from = from, size = size) } format_result <- function(obj, from, size) { meta <- attr(obj, "metadata") if (!meta$total) { cli_alert_danger("No results :(") return() } cli_alert_success("Found {meta$total} packages in {pretty_ms(meta$took)}") cli_text() cli_div(theme = list(ul = list("list-style-type" = ""))) cli_ol() lapply(seq_len(nrow(obj)), function(i) format_hit(obj[i,])) } format_hit <- function(hit) { ago <- vague_dt(Sys.time() - hit$date) cli_li() cli_text("{.pkg {hit$package}} {hit$version} -- {.emph {hit$title}}") cli_par() cli_text(hit$description) cli_text("{.emph {ago} by {hit$maintainer_name}}") } parse_arguments <- function() { "Usage: cransearch.R [-h | --help] [ -f from ] [ -n size ] ... Options: -h --help Print this help message -f first First hit to include -n size Number of hits to include Seach for CRAN packages on r-pkg.org " -> doc docopt(doc) } if (is.null(sys.calls())) { load_packages() opts <- parse_arguments() search(opts$term, from = as.numeric(opts$f %||% 1), size = as.numeric(opts$n %||% 5)) } cli/inst/examples/apps/news.R0000755000176200001440000000570414557444176015710 0ustar liggesusers#! /usr/bin/env Rscript setup_app <- function() { theme <- list( "url" = list(color = "blue"), ".pkg" = list(color = "orange"), "it" = list("margin-bottom" = 1)) start_app(theme = theme, output = "stdout") } load_packages <- function() { tryCatch({ library(cli) library(httr) library(jsonlite) library(prettyunits) library(glue) library(parsedate) library(docopt) }, error = function(e) { cli_alert_danger( "The {.pkg glue}, {.pkg httr}, {.pkg jsonlite}, {.pkg prettyunits},", " {.pkg parsedate} and {.pkg docopt} packages are needed!") q(save = "no", status = 1) }) } news <- function(n = 10, day = FALSE, week = FALSE, since = NULL, reverse = FALSE) { load_packages() setup_app() result <- if (day) news_day() else if (week) news_week() else if (!is.null(since)) news_since(since) else news_n(as.numeric(n)) if (reverse) result <- rev(result) format_results(result) invisible() } news_day <- function() { date <- format_iso_8601(Sys.time() - as.difftime(1, units="days")) ep <- glue("/-/pkgreleases?descending=true&endkey=%22{date}%22") do_query(ep) } news_week <- function() { date <- format_iso_8601(Sys.time() - as.difftime(7, units="days")) ep <- glue("/-/pkgreleases?descending=true&endkey=%22{date}%22") do_query(ep) } news_since <- function(since) { date <- format_iso_8601(parse_date(since)) ep <- glue("/-/pkgreleases?descending=true&endkey=%22{date}%22") do_query(ep) } news_n <- function(n) { ep <- glue("/-/pkgreleases?limit={n}&descending=true") do_query(ep) } do_query <- function(ep) { base <- "https://crandb.r-pkg.org" url <- glue("{base}{ep}") response <- GET(url) stop_for_status(response) fromJSON(content(response, as = "text"), simplifyVector = FALSE) } format_results <- function(results) { cli_div(theme = list(ul = list("list-style-type" = ""))) cli_ol() lapply(results, format_result) } parse_arguments <- function() { "Usage: news.R [-r | --reverse] [-n num ] news.R [-r | --reverse] --day | --week | --since date news.R [-h | --help] Options: -n num Show the last 'n' releases [default: 10]. --day Show releases in the last 24 hours --week Show relaases in the last 7 * 24 hours --since date Show releases since 'date' -r --reverse Reverse the order, show older on top -h --help Print this help message New package releases on CRAN " -> doc docopt(doc) } format_result <- function(result) { pkg <- result$package ago <- vague_dt(Sys.time() - parse_iso_8601(result$date)) url <- paste0("https://r-pkg.org/pkg/", pkg$Package) cli_li() cli_text("{.pkg {pkg$Package}} {pkg$Version} -- {ago} by {.emph {pkg$Maintainer}}") cli_text("{pkg$Title}") cli_text("{.url {url}}") } if (is.null(sys.calls())) { load_packages() opts <- parse_arguments() news(opts$n, opts$day, opts$week, opts$since, opts$reverse) } cli/inst/logo.txt0000644000176200001440000000526614557444176013531 0ustar liggesusers                     oooo    o8o Yb                   `888    `"'  `Yb       .ooooo.    888   oooo    `Yb    d88' `"Y8   888   `888    .dP    888         888    888  .dP      888   .o8   888    888 dP        `Y8bod8P'  o888o  o888o cli/tools/0000755000176200001440000000000014752735214012173 5ustar liggesuserscli/tools/get-rstudio-themes.R0000644000176200001440000001504714752735214016056 0ustar liggesusers library(css) rstudio_theme_details_map <- list( "ambiance" = list(name = "Ambiance", isDark = TRUE), "chaos" = list(name = "Chaos", isDark = TRUE), "chrome" = list(name = "Chrome", isDark = FALSE), "clouds" = list(name = "Clouds", isDark = FALSE), "clouds_midnight" = list(name = "Clouds Midnight", isDark = TRUE), "cobalt" = list(name = "Cobalt", isDark = TRUE), "crimson_editor" = list(name = "Crimson Editor", isDark = FALSE), "dawn" = list(name = "Dawn", isDark = FALSE), "dracula" = list(name = "Dracula", isDark = TRUE), "dreamweaver" = list(name = "Dreamweaver", isDark = FALSE), "eclipse" = list(name = "Eclipse", isDark = FALSE), "idle_fingers" = list(name = "Idle Fingers", isDark = TRUE), "katzenmilch" = list(name = "Katzenmilch", isDark = FALSE), "kr_theme" = list(name = "Kr Theme", isDark = TRUE), "material" = list(name = "Material", isDark = TRUE), "merbivore" = list(name = "Merbivore", isDark = TRUE), "merbivore_soft" = list(name = "Merbivore Soft", isDark = TRUE), "mono_industrial" = list(name = "Mono Industrial", isDark = TRUE), "monokai" = list(name = "Monokai", isDark = TRUE), "pastel_on_dark" = list(name = "Pastel On Dark", isDark = TRUE), "solarized_dark" = list(name = "Solarized Dark", isDark = TRUE), "solarized_light" = list(name = "Solarized Light", isDark = FALSE), "textmate" = list(name = "Textmate (default)", isDark = FALSE), "tomorrow" = list(name = "Tomorrow", isDark = FALSE), "tomorrow_night" = list(name = "Tomorrow Night", isDark = TRUE), "tomorrow_night_blue" = list(name = "Tomorrow Night Blue", isDark = TRUE), "tomorrow_night_bright" = list(name = "Tomorrow Night Bright", isDark = TRUE), "tomorrow_night_eighties" = list(name = "Tomorrow Night 80s", isDark = TRUE), "twilight" = list(name = "Twilight", isDark = TRUE), "vibrant_ink" = list(name = "Vibrant Ink", isDark = TRUE), "xcode" = list(name = "Xcode", isDark = FALSE) ) rstudio_theme_url_template <- paste0( "https://raw.githubusercontent.com/", "rstudio/rstudio/master/src/cpp/session/resources/themes/%s.rstheme" ) ## A set of operator colors to use, for each theme. Should match the name ## of the theme file in ace. ## We need to explicity set themes that should be overridden with the default ## vaue to NULL operator_theme_map <- list( "solarized_light" = "#93A1A1", "solarized_dark" = "#B58900", "twilight" = "#7587A6", "idle_fingers" = "#6892B2", "clouds_midnight" = "#A53553", "cobalt" = "#BED6FF", "kr_theme" = "#A56464", "clouds" = NULL, "dawn" = NULL, "eclipse" = NULL, "katzenmilch" = NULL, "merbivore" = NULL, "merbivore_soft" = NULL, "monokai" = NULL, "pastel_on_dark" = NULL, "vibrant_ink" = NULL, "xcode" = NULL ) ## Similarly, colors for keywords that we might override. keyword_theme_map <- list( "eclipse" = "#800080", "clouds" = "#800080" ) # Needs https://github.com/romainfrancois/css rstudio_css <- function(theme) { message("Downloading theme '", theme, "'") url <- sprintf(rstudio_theme_url_template, theme) css <- asNamespace("css")$read_css(url) g <- function(sel) { col <- vapply( sel, FUN.VALUE = "", function(sel1) { tail(c(NA_character_, css$value[grepl(sel1, css$rule) & css$property == "color"]), 1) } ) col <- na.omit(col)[1] if (is.na(col) || length(col) != 1) { stop("Cannot get '", sel, "' from theme '", theme, "'") } col <- sub("[ ]+!important", "", col) ## Three digit colors are not handled by cli... if (grepl("^#[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]$", col)) { col <- paste(rep(strsplit(col, "", fixed = TRUE)[[1]], c(1, 2, 2, 2)), collapse = "") } ## rgb () form if (grepl("^rgb", col)) { col <- gsub("[^0-9 ]", "", col) col <- do.call(rgb, as.list(scan(text = col, quiet = TRUE) / 255)) } unname(col) } if (theme %in% names(keyword_theme_map)) { kw <- keyword_theme_map[[theme]] } else { kw <- g("\\.ace_keyword$|\\.ace_keyword,") } if (theme %in% names(operator_theme_map)) { if (is.null(operator_theme_map[[theme]])) { if (rstudio_theme_details_map[[theme]]$isDark) { op <- "#aaaaaa" } else { op <- "#888888" } } else { op <- operator_theme_map[[theme]] } } else { op <- g(c( "^\\.ace_keyword\\.ace_operator$", "^\\.ace_constant\\.ace_language$", "^\\.ace_variable\\.ace_language$", "\\.ace_constant,", "\\.ace_constant\\.ace_buildin" )) } list( reserved_ = kw, number_ = g(c("\\.ace_constant\\.ace_numeric$", "\\.ace_constant,")), null_ = g(c("\\.ace_constant\\.ace_language$", "\\.ace_variable\\.ace_language$", "\\.ace_constant,", "\\.ace_constant\\.ace_buildin")), operator_ = op, call_ = NA_character_, string_ = g("\\.ace_string$|\\.ace_string,"), comment_ = g("\\.ace_comment$|\\.ace_comment,"), bracket_ = g(c("\\.ace_paren\\.ace_keyword\\.ace_operator", "\\.ace_keyword\\.ace_operator", "\\.ace_keyword")) ) } create_rstudio_data <- function() { themes <- lapply(names(rstudio_theme_details_map), rstudio_css) names(themes) <- names(rstudio_theme_details_map) # Some substitutions for (nm in names(operator_theme_map)) { if (is.null(operator_theme_map[[nm]])) { } else { themes[[nm]]$null_ <- operator_theme_map[[nm]] themes[[nm]]$operator_ <- operator_theme_map[[nm]] themes[[nm]]$bracket_ <- operator_theme_map[[nm]] } } for (nm in names(keyword_theme_map)) { themes[[nm]]$reserved_ <- keyword_theme_map[[nm]] } # check that cli can handle these, otherwise it will error lapply(na.omit(unlist(themes)), cli::make_ansi_style) themes2 <- lapply(themes, function(theme) { list( reserved = theme$reserved_, number = theme$number_, null = theme$null_, operator = theme$operator_, call = "bold", string = theme$string_, comment = theme$comment_, bracket = list(theme$bracket_, "yellow", "blue", "cyan") ) }) names(themes2) <- vapply(rstudio_theme_details_map, "[[", "", "name") message("Saving sysdata.rda... ", appendLF = FALSE) sysenv <- new.env(parent = emptyenv()) load(file.path("R", "sysdata.rda"), envir = sysenv) sysenv$rstudio_themes <- themes2 save( list = ls(sysenv), envir = sysenv, file = file.path("R", "sysdata.rda"), version = 2 ) message("done.") invisible(themes2) } if (is.null(sys.calls())) { create_rstudio_data() } cli/tools/unicode.R0000644000176200001440000000153414557444176013756 0ustar liggesusers# To create the data: update_wide_unicode_data <- function() { tab <- read.delim( stringsAsFactors = FALSE, "https://unicode.org/Public/UNIDATA/EastAsianWidth.txt", comment.char = "#", sep = ";", strip.white = TRUE, header = FALSE ) # Keep wide ones wide <- tab$V1[tab$V2 == "W"] first <- sub("\\.\\..*$", "", wide) range <- sub("^([0-9A-F]+)\\.\\.([0-9A-F]+)$", "\\\\U\\1-\\\\U\\2", wide) range <- sub("^([0-9A-F]+)$", "\\\\U\\1", range) wide_chars <- data.frame( stringsAsFactors = FALSE, test = sapply(parse(text = paste0('"', "\\U", first, '"')), eval), regex = sapply(parse(text = paste0('"', range, '"')), eval) ) env <- new.env(parent = emptyenv()) load("R/sysdata.rda", envir = env) env$wide_chars <- wide_chars save(list = ls(env), file = "R/sysdata.rda", envir = env, version = 2) } cli/tools/sol-light.itermcolors0000644000176200001440000002060214557444176016370 0ustar liggesusers Ansi 0 Color Alpha Component 1 Blue Component 0.25882354378700256 Color Space sRGB Green Component 0.21176470816135406 Red Component 0.027450980618596077 Ansi 1 Color Alpha Component 1 Blue Component 0.18431372940540314 Color Space sRGB Green Component 0.19607843458652496 Red Component 0.86274510622024536 Ansi 10 Color Alpha Component 1 Blue Component 0.45882353186607361 Color Space sRGB Green Component 0.43137255311012268 Red Component 0.34509804844856262 Ansi 11 Color Alpha Component 1 Blue Component 0.51372551918029785 Color Space sRGB Green Component 0.48235294222831726 Red Component 0.3960784375667572 Ansi 12 Color Alpha Component 1 Blue Component 0.58823531866073608 Color Space sRGB Green Component 0.58039218187332153 Red Component 0.51372551918029785 Ansi 13 Color Alpha Component 1 Blue Component 0.76862746477127075 Color Space sRGB Green Component 0.44313725829124451 Red Component 0.42352941632270813 Ansi 14 Color Alpha Component 1 Blue Component 0.63137257099151611 Color Space sRGB Green Component 0.63137257099151611 Red Component 0.57647061347961426 Ansi 15 Color Alpha Component 1 Blue Component 0.89019608497619629 Color Space sRGB Green Component 0.96470588445663452 Red Component 0.99215686321258545 Ansi 2 Color Alpha Component 1 Blue Component 0.0 Color Space sRGB Green Component 0.60000002384185791 Red Component 0.5215686559677124 Ansi 3 Color Alpha Component 1 Blue Component 0.0 Color Space sRGB Green Component 0.5372549295425415 Red Component 0.70980393886566162 Ansi 4 Color Alpha Component 1 Blue Component 0.82352942228317261 Color Space sRGB Green Component 0.54509806632995605 Red Component 0.14901961386203766 Ansi 5 Color Alpha Component 1 Blue Component 0.50980395078659058 Color Space sRGB Green Component 0.21176470816135406 Red Component 0.82745099067687988 Ansi 6 Color Alpha Component 1 Blue Component 0.59607845544815063 Color Space sRGB Green Component 0.63137257099151611 Red Component 0.16470588743686676 Ansi 7 Color Alpha Component 1 Blue Component 0.83529412746429443 Color Space sRGB Green Component 0.90980392694473267 Red Component 0.93333333730697632 Ansi 8 Color Alpha Component 1 Blue Component 0.21176470816135406 Color Space sRGB Green Component 0.16862745583057404 Red Component 0.0 Ansi 9 Color Alpha Component 1 Blue Component 0.086274512112140656 Color Space sRGB Green Component 0.29411765933036804 Red Component 0.79607844352722168 Background Color Alpha Component 1 Blue Component 0.89019608497619629 Color Space sRGB Green Component 0.96470588445663452 Red Component 0.99215686321258545 Badge Color Alpha Component 0.5 Blue Component 0.0 Color Space sRGB Green Component 0.1491314172744751 Red Component 1 Bold Color Alpha Component 1 Blue Component 0.45882353186607361 Color Space sRGB Green Component 0.43137255311012268 Red Component 0.34509804844856262 Cursor Color Alpha Component 1 Blue Component 0.51372551918029785 Color Space sRGB Green Component 0.48235294222831726 Red Component 0.3960784375667572 Cursor Guide Color Alpha Component 0.25 Blue Component 1 Color Space sRGB Green Component 0.9268307089805603 Red Component 0.70213186740875244 Cursor Text Color Alpha Component 1 Blue Component 0.83529412746429443 Color Space sRGB Green Component 0.90980392694473267 Red Component 0.93333333730697632 Foreground Color Alpha Component 1 Blue Component 0.51372551918029785 Color Space sRGB Green Component 0.48235294222831726 Red Component 0.3960784375667572 Link Color Alpha Component 1 Blue Component 0.73423302173614502 Color Space sRGB Green Component 0.35916060209274292 Red Component 0.0 Selected Text Color Alpha Component 1 Blue Component 0.45882353186607361 Color Space sRGB Green Component 0.43137255311012268 Red Component 0.34509804844856262 Selection Color Alpha Component 1 Blue Component 0.83529412746429443 Color Space sRGB Green Component 0.90980392694473267 Red Component 0.93333333730697632 cli/tools/ansi-iterm-palettes.txt0000644000176200001440000000170214557444176016632 0ustar liggesusersblack red green yellow blue magenta cyan white br_black br_red br_green br_yellow br_blue br_magenta br_cyan br_white iterm #000000 #c91b00 #00c200 #c7c400 #0225c7 #ca30c7 #00c5c7 #c7c7c7 #686868 #ff6e67 #5ffa68 #fffc67 #6871ff #ff77ff #60fdff #ffffff iterm-pastel #626262 #ff8373 #b4fb73 #fffdc3 #a5d5fe #ff90fe #d1d1fe #f1f1f1 #8f8f8f #ffc4be #d6fcba #fffed5 #c2e3ff #ffb2fe #e6e7fe #ffffff iterm-smoooooth #14191e #b43c2a #00c200 #c7c400 #2744c7 #c040be #00c5c7 #c7c7c7 #686868 #dd7975 #58e790 #ece100 #a7abf2 #e17ee1 #60fdff #ffffff iterm-snazzy #000000 #ff5c57 #5af78e #f3f99d #57c7ff #ff6ac1 #9aedfe #f1f1f0 #686868 #ff5c57 #5af78e #f3f99d #57c7ff #ff6ac1 #9aedfe #f1f1f0 iterm-solarized #073642 #dc322f #859900 #b58900 #268bd2 #d33682 #2aa198 #eee8d5 #002b36 #cb4b16 #586e75 #657b83 #839496 #6c71c4 #93a1a1 #fdf6e3 iterm-tango #000000 #d81e00 #5ea702 #cfae00 #427ab3 #89658e #00a7aa #dbded8 #686a66 #f54235 #99e343 #fdeb61 #84b0d8 #bc94b7 #37e6e8 #f1f1f0 cli/tools/snazzy.itermcolors0000644000176200001440000002043314557444176016026 0ustar liggesusers Ansi 0 Color Alpha Component 1 Blue Component 0.0 Color Space sRGB Green Component 0.0 Red Component 0.0 Ansi 1 Color Alpha Component 1 Blue Component 0.34117639064788818 Color Space sRGB Green Component 0.36078426241874695 Red Component 1 Ansi 10 Color Alpha Component 1 Blue Component 0.55686265230178833 Color Space sRGB Green Component 0.96862751245498657 Red Component 0.35294127464294434 Ansi 11 Color Alpha Component 1 Blue Component 0.61568623781204224 Color Space sRGB Green Component 0.97647064924240112 Red Component 0.95294123888015747 Ansi 12 Color Alpha Component 1 Blue Component 0.99999994039535522 Color Space sRGB Green Component 0.78039222955703735 Red Component 0.34117650985717773 Ansi 13 Color Alpha Component 1 Blue Component 0.75686269998550415 Color Space sRGB Green Component 0.4156862199306488 Red Component 1 Ansi 14 Color Alpha Component 1 Blue Component 0.99607843160629272 Color Space sRGB Green Component 0.92941170930862427 Red Component 0.60392171144485474 Ansi 15 Color Alpha Component 1 Blue Component 0.94117647409439087 Color Space sRGB Green Component 0.94509810209274292 Red Component 0.94509810209274292 Ansi 2 Color Alpha Component 1 Blue Component 0.55686265230178833 Color Space sRGB Green Component 0.96862751245498657 Red Component 0.35294127464294434 Ansi 3 Color Alpha Component 1 Blue Component 0.61568623781204224 Color Space sRGB Green Component 0.97647064924240112 Red Component 0.95294123888015747 Ansi 4 Color Alpha Component 1 Blue Component 0.99999994039535522 Color Space sRGB Green Component 0.78039222955703735 Red Component 0.34117650985717773 Ansi 5 Color Alpha Component 1 Blue Component 0.75686269998550415 Color Space sRGB Green Component 0.4156862199306488 Red Component 1 Ansi 6 Color Alpha Component 1 Blue Component 0.99607843160629272 Color Space sRGB Green Component 0.92941170930862427 Red Component 0.60392171144485474 Ansi 7 Color Alpha Component 1 Blue Component 0.94117647409439087 Color Space sRGB Green Component 0.94509810209274292 Red Component 0.94509810209274292 Ansi 8 Color Alpha Component 1 Blue Component 0.40784311294555664 Color Space sRGB Green Component 0.40784311294555664 Red Component 0.40784323215484619 Ansi 9 Color Alpha Component 1 Blue Component 0.34117639064788818 Color Space sRGB Green Component 0.36078426241874695 Red Component 1 Background Color Alpha Component 1 Blue Component 0.21176469326019287 Color Space sRGB Green Component 0.16470584273338318 Red Component 0.15686270594596863 Badge Color Alpha Component 0.5 Blue Component 0.0 Color Space sRGB Green Component 0.1491314172744751 Red Component 1 Bold Color Alpha Component 1 Blue Component 0.97102349996566772 Color Space sRGB Green Component 0.97102349996566772 Red Component 0.97102361917495728 Cursor Color Alpha Component 1 Blue Component 0.91647690534591675 Color Space sRGB Green Component 0.91648870706558228 Red Component 0.91646724939346313 Cursor Guide Color Alpha Component 0.25 Blue Component 1 Color Space sRGB Green Component 0.9268307089805603 Red Component 0.70213186740875244 Cursor Text Color Alpha Component 1 Blue Component 0.21176469326019287 Color Space sRGB Green Component 0.16470584273338318 Red Component 0.15686270594596863 Foreground Color Alpha Component 1 Blue Component 0.92156857252120972 Color Space sRGB Green Component 0.94117647409439087 Red Component 0.93725490570068359 Link Color Alpha Component 1 Blue Component 0.85775750875473022 Color Space sRGB Green Component 0.66938728094100952 Red Component 0.29264676570892334 Selected Text Color Alpha Component 1 Blue Component 0.0 Color Space sRGB Green Component 0.0 Red Component 0.0 Selection Color Alpha Component 1 Blue Component 0.81719964742660522 Color Space sRGB Green Component 0.73586553335189819 Red Component 0.57319694757461548 cli/tools/sol-dark.itermcolors0000644000176200001440000002056614557444176016213 0ustar liggesusers Ansi 0 Color Alpha Component 1 Blue Component 0.25882354378700256 Color Space sRGB Green Component 0.21176470816135406 Red Component 0.027450980618596077 Ansi 1 Color Alpha Component 1 Blue Component 0.18431372940540314 Color Space sRGB Green Component 0.19607843458652496 Red Component 0.86274510622024536 Ansi 10 Color Alpha Component 1 Blue Component 0.45882353186607361 Color Space sRGB Green Component 0.43137255311012268 Red Component 0.34509804844856262 Ansi 11 Color Alpha Component 1 Blue Component 0.51372551918029785 Color Space sRGB Green Component 0.48235294222831726 Red Component 0.3960784375667572 Ansi 12 Color Alpha Component 1 Blue Component 0.58823531866073608 Color Space sRGB Green Component 0.58039218187332153 Red Component 0.51372551918029785 Ansi 13 Color Alpha Component 1 Blue Component 0.76862746477127075 Color Space sRGB Green Component 0.44313725829124451 Red Component 0.42352941632270813 Ansi 14 Color Alpha Component 1 Blue Component 0.63137257099151611 Color Space sRGB Green Component 0.63137257099151611 Red Component 0.57647061347961426 Ansi 15 Color Alpha Component 1 Blue Component 0.89019608497619629 Color Space sRGB Green Component 0.96470588445663452 Red Component 0.99215686321258545 Ansi 2 Color Alpha Component 1 Blue Component 0.0 Color Space sRGB Green Component 0.60000002384185791 Red Component 0.5215686559677124 Ansi 3 Color Alpha Component 1 Blue Component 0.0 Color Space sRGB Green Component 0.5372549295425415 Red Component 0.70980393886566162 Ansi 4 Color Alpha Component 1 Blue Component 0.82352942228317261 Color Space sRGB Green Component 0.54509806632995605 Red Component 0.14901961386203766 Ansi 5 Color Alpha Component 1 Blue Component 0.50980395078659058 Color Space sRGB Green Component 0.21176470816135406 Red Component 0.82745099067687988 Ansi 6 Color Alpha Component 1 Blue Component 0.59607845544815063 Color Space sRGB Green Component 0.63137257099151611 Red Component 0.16470588743686676 Ansi 7 Color Alpha Component 1 Blue Component 0.83529412746429443 Color Space sRGB Green Component 0.90980392694473267 Red Component 0.93333333730697632 Ansi 8 Color Alpha Component 1 Blue Component 0.21176470816135406 Color Space sRGB Green Component 0.16862745583057404 Red Component 0.0 Ansi 9 Color Alpha Component 1 Blue Component 0.086274512112140656 Color Space sRGB Green Component 0.29411765933036804 Red Component 0.79607844352722168 Background Color Alpha Component 1 Blue Component 0.21176470816135406 Color Space sRGB Green Component 0.16862745583057404 Red Component 0.0 Badge Color Alpha Component 0.5 Blue Component 0.0 Color Space sRGB Green Component 0.1491314172744751 Red Component 1 Bold Color Alpha Component 1 Blue Component 0.63137257099151611 Color Space sRGB Green Component 0.63137257099151611 Red Component 0.57647061347961426 Cursor Color Alpha Component 1 Blue Component 0.58823531866073608 Color Space sRGB Green Component 0.58039218187332153 Red Component 0.51372551918029785 Cursor Guide Color Alpha Component 0.25 Blue Component 1 Color Space sRGB Green Component 0.9268307089805603 Red Component 0.70213186740875244 Cursor Text Color Alpha Component 1 Blue Component 0.25882354378700256 Color Space sRGB Green Component 0.21176470816135406 Red Component 0.027450980618596077 Foreground Color Alpha Component 1 Blue Component 0.58823531866073608 Color Space sRGB Green Component 0.58039218187332153 Red Component 0.51372551918029785 Link Color Alpha Component 1 Blue Component 0.73423302173614502 Color Space sRGB Green Component 0.35916060209274292 Red Component 0.0 Selected Text Color Alpha Component 1 Blue Component 0.63137257099151611 Color Space sRGB Green Component 0.63137257099151611 Red Component 0.57647061347961426 Selection Color Alpha Component 1 Blue Component 0.25882354378700256 Color Space sRGB Green Component 0.21176470816135406 Red Component 0.027450980618596077 cli/tools/pastel.itermcolors0000644000176200001440000002026714557444176015765 0ustar liggesusers Ansi 0 Color Alpha Component 1 Blue Component 0.38308101892471313 Color Space sRGB Green Component 0.38308626413345337 Red Component 0.38307660818099976 Ansi 1 Color Alpha Component 1 Blue Component 0.45018774271011353 Color Space sRGB Green Component 0.51372170448303223 Red Component 1 Ansi 10 Color Alpha Component 1 Blue Component 0.72799390554428101 Color Space sRGB Green Component 0.98994415998458862 Red Component 0.84051257371902466 Ansi 11 Color Alpha Component 1 Blue Component 0.8365439772605896 Color Space sRGB Green Component 0.99525755643844604 Red Component 0.99980658292770386 Ansi 12 Color Alpha Component 1 Blue Component 0.99912863969802856 Color Space sRGB Green Component 0.89107227325439453 Red Component 0.75904428958892822 Ansi 13 Color Alpha Component 1 Blue Component 0.99761480093002319 Color Space sRGB Green Component 0.69791680574417114 Red Component 1 Ansi 14 Color Alpha Component 1 Blue Component 0.99795502424240112 Color Space sRGB Green Component 0.90393000841140747 Red Component 0.9003327488899231 Ansi 15 Color Alpha Component 1 Blue Component 1 Color Space sRGB Green Component 1 Red Component 0.99999600648880005 Ansi 2 Color Alpha Component 1 Blue Component 0.44994193315505981 Color Space sRGB Green Component 0.98347383737564087 Red Component 0.70657283067703247 Ansi 3 Color Alpha Component 1 Blue Component 0.76331329345703125 Color Space sRGB Green Component 0.99347144365310669 Red Component 0.99973577260971069 Ansi 4 Color Alpha Component 1 Blue Component 0.99758428335189819 Color Space sRGB Green Component 0.83712881803512573 Red Component 0.64852482080459595 Ansi 5 Color Alpha Component 1 Blue Component 0.9942595362663269 Color Space sRGB Green Component 0.56355088949203491 Red Component 1 Ansi 6 Color Alpha Component 1 Blue Component 0.99741238355636597 Color Space sRGB Green Component 0.82124459743499756 Red Component 0.81801408529281616 Ansi 7 Color Alpha Component 1 Blue Component 0.9469638466835022 Color Space sRGB Green Component 0.94697576761245728 Red Component 0.94695359468460083 Ansi 8 Color Alpha Component 1 Blue Component 0.55935078859329224 Color Space sRGB Green Component 0.55935806035995483 Red Component 0.55934453010559082 Ansi 9 Color Alpha Component 1 Blue Component 0.74329870939254761 Color Space sRGB Green Component 0.769095778465271 Red Component 1 Background Color Alpha Component 1 Blue Component 0.0 Color Space sRGB Green Component 0.0 Red Component 0.0 Badge Color Alpha Component 0.5 Blue Component 0.0 Color Space sRGB Green Component 0.1491314172744751 Red Component 1 Bold Color Alpha Component 1 Blue Component 1 Color Space sRGB Green Component 1 Red Component 0.99999600648880005 Cursor Color Alpha Component 1 Blue Component 0.4497559666633606 Color Space sRGB Green Component 0.70702856779098511 Red Component 1 Cursor Guide Color Alpha Component 0.25 Blue Component 1 Color Space sRGB Green Component 0.9268307089805603 Red Component 0.70213186740875244 Cursor Text Color Alpha Component 1 Blue Component 1 Color Space sRGB Green Component 1 Red Component 0.99999600648880005 Foreground Color Alpha Component 1 Blue Component 0.78104829788208008 Color Space sRGB Green Component 0.78105825185775757 Red Component 0.7810397744178772 Link Color Alpha Component 1 Blue Component 0.73423302173614502 Color Space sRGB Green Component 0.35916060209274292 Red Component 0.0 Selected Text Color Alpha Component 1 Blue Component 0.95826774835586548 Color Space sRGB Green Component 0.95827978849411011 Red Component 0.95825737714767456 Selection Color Alpha Component 1 Blue Component 0.58733552694320679 Color Space sRGB Green Component 0.30240094661712646 Red Component 0.27248409390449524 cli/tools/parse-iterm.R0000644000176200001440000000361014557444176014555 0ustar liggesusers parse_iterm <- function(path) { doc <- xml2::read_xml(path) elm <- xml2::xml_find_first(doc, "/plist/dict") key <- sapply( xml2::xml_find_all(elm, "/plist/dict/key"), xml2::xml_text ) val <- xml2::xml_find_all(elm, "/plist/dict/dict") get <- function(k) { wh <- match(k, key) v <- val[[wh]] vks <- sapply( xml2::xml_find_all(v, "key"), xml2::xml_text ) if (! "Color Space" %in% vks) stop("Unknown color space") chd <- xml2::xml_children(v) csp <- xml2::xml_text( chd[[which(vks == "Color Space") * 2]] ) if (csp != "sRGB") stop("Color space is not sRGB") r <- as.numeric(xml2::xml_text(chd[[which(vks == "Red Component") * 2]])) g <- as.numeric(xml2::xml_text(chd[[which(vks == "Green Component") * 2]])) b <- as.numeric(xml2::xml_text(chd[[which(vks == "Blue Component") * 2]])) tolower(grDevices::rgb(r, g, b)) } rn <- sub(".itermcolors", "", basename(path), fixed = TRUE) data.frame( stringsAsFactors = FALSE, row.names = paste0("iterm-", rn), black = get("Ansi 0 Color"), red = get("Ansi 1 Color"), green = get("Ansi 2 Color"), yellow = get("Ansi 3 Color"), blue = get("Ansi 4 Color"), magenta = get("Ansi 5 Color"), cyan = get("Ansi 6 Color"), white = get("Ansi 7 Color"), bblack = get("Ansi 8 Color"), bred = get("Ansi 9 Color"), bgreen = get("Ansi 10 Color"), byellow = get("Ansi 11 Color"), bblue = get("Ansi 12 Color"), bmagenta = get("Ansi 13 Color"), bcyan = get("Ansi 14 Color"), bwhite = get("Ansi 15 Color") ) } parse_all <- function(dir = "tools") { paths <- dir(dir, pattern = "[.]itermcolors$", full.names = TRUE) cols <- lapply(paths, parse_iterm) all <- do.call(rbind, cols) write.table(all, "tools/ansi-iterm-themes.txt", quote = FALSE) } if (is.null(sys.calls())) { parse_all() } cli/tools/tango-light.itermcolors0000644000176200001440000002007114557444176016703 0ustar liggesusers Ansi 0 Color Alpha Component 1 Blue Component 0.0 Color Space sRGB Green Component 0.0 Red Component 0.0 Ansi 1 Color Alpha Component 1 Blue Component 0.0 Color Space sRGB Green Component 0.11767414957284927 Red Component 0.84674292802810669 Ansi 10 Color Alpha Component 1 Blue Component 0.26148656010627747 Color Space sRGB Green Component 0.89173698425292969 Red Component 0.59970396757125854 Ansi 11 Color Alpha Component 1 Blue Component 0.37922361493110657 Color Space sRGB Green Component 0.92064303159713745 Red Component 0.99169927835464478 Ansi 12 Color Alpha Component 1 Blue Component 0.84789222478866577 Color Space sRGB Green Component 0.68869423866271973 Red Component 0.51713955402374268 Ansi 13 Color Alpha Component 1 Blue Component 0.71664512157440186 Color Space sRGB Green Component 0.57970219850540161 Red Component 0.73733323812484741 Ansi 14 Color Alpha Component 1 Blue Component 0.90933424234390259 Color Space sRGB Green Component 0.90141081809997559 Red Component 0.21587523818016052 Ansi 15 Color Alpha Component 1 Blue Component 0.9404633641242981 Color Space sRGB Green Component 0.94661098718643188 Red Component 0.94678574800491333 Ansi 2 Color Alpha Component 1 Blue Component 0.0088730743154883385 Color Space sRGB Green Component 0.65366500616073608 Red Component 0.36692649126052856 Ansi 3 Color Alpha Component 1 Blue Component 0.0 Color Space sRGB Green Component 0.68127995729446411 Red Component 0.81349855661392212 Ansi 4 Color Alpha Component 1 Blue Component 0.70342475175857544 Color Space sRGB Green Component 0.47867023944854736 Red Component 0.25807341933250427 Ansi 5 Color Alpha Component 1 Blue Component 0.55586665868759155 Color Space sRGB Green Component 0.39761847257614136 Red Component 0.5363890528678894 Ansi 6 Color Alpha Component 1 Blue Component 0.6682930588722229 Color Space sRGB Green Component 0.65514689683914185 Red Component 0.0 Ansi 7 Color Alpha Component 1 Blue Component 0.8471907377243042 Color Space sRGB Green Component 0.87220901250839233 Red Component 0.85992234945297241 Ansi 8 Color Alpha Component 1 Blue Component 0.39959198236465454 Color Space sRGB Green Component 0.41529536247253418 Red Component 0.40758803486824036 Ansi 9 Color Alpha Component 1 Blue Component 0.20832169055938721 Color Space sRGB Green Component 0.25720733404159546 Red Component 0.96001332998275757 Background Color Alpha Component 1 Blue Component 1 Color Space sRGB Green Component 1 Red Component 0.99999600648880005 Badge Color Alpha Component 0.5 Blue Component 0.0 Color Space sRGB Green Component 0.1491314172744751 Red Component 1 Bold Color Alpha Component 1 Blue Component 0.0 Color Space sRGB Green Component 0.0 Red Component 0.0 Cursor Color Alpha Component 1 Blue Component 0.0 Color Space sRGB Green Component 0.0 Red Component 0.0 Cursor Guide Color Alpha Component 0.25 Blue Component 1 Color Space sRGB Green Component 0.9268307089805603 Red Component 0.70213186740875244 Cursor Text Color Alpha Component 1 Blue Component 1 Color Space sRGB Green Component 1 Red Component 0.99999600648880005 Foreground Color Alpha Component 1 Blue Component 0.0 Color Space sRGB Green Component 0.0 Red Component 0.0 Link Color Alpha Component 1 Blue Component 0.73423302173614502 Color Space sRGB Green Component 0.35916060209274292 Red Component 0.0 Selected Text Color Alpha Component 1 Blue Component 0.0 Color Space sRGB Green Component 0.0 Red Component 0.0 Selection Color Alpha Component 1 Blue Component 1 Color Space sRGB Green Component 0.86970102787017822 Red Component 0.75813239812850952 cli/tools/spinners.R0000644000176200001440000000202014752735214014151 0ustar liggesusers json <- "https://raw.githubusercontent.com/sindresorhus/cli-spinners/45cef9dff64ac5e36b46a194c68bccba448899ac/spinners.json" parsed <- jsonlite::fromJSON(json, simplifyVector = TRUE) pasis <- lapply(parsed, function(x) { x$frames <- I(x$frames); x }) pdt <- as.data.frame(do.call(rbind, pasis)) pdt$name <- rownames(pdt) rownames(pdt) <- NULL spinners <- pdt[, c("name", "interval", "frames")] usethis::use_data(spinners, internal = TRUE) spinners <- rbind( spinners, list(name = "growVeriticalDotsLR", interval = 80, frames = strsplit("⠀⡀⣀⣄⣤⣦⣶⣷⣿⣾⣶⣴⣤⣠⣀⢀", "", fixed = TRUE)), list(name = "growVeriticalDotsRL", interval = 80, frames = strsplit("⠀⢀⣀⣠⣤⣴⣶⣾⣿⣷⣶⣦⣤⣄⣀⡀", "", fixed = TRUE)), list(name = "growVeriticalDotsLL", interval = 80, frames = strsplit("⠀⡀⣀⣄⣤⣦⣶⣷⣿⣷⣶⣦⣤⣄⣀⡀", "", fixed = TRUE)), list(name = "growVeriticalDotsRR", interval = 80, frames = strsplit("⠀⡀⣀⣠⣤⣴⣶⣾⣿⣾⣶⣴⣤⣠⣀⢀", "", fixed = TRUE)) ) cli/tools/light.itermcolors0000644000176200001440000001763314557444176015607 0ustar liggesusers Ansi 0 Color Alpha Component 1 Blue Component 0.0 Color Space sRGB Green Component 0.0 Red Component 0.0 Ansi 1 Color Alpha Component 1 Blue Component 0.0 Color Space sRGB Green Component 0.10676553100347519 Red Component 0.789775550365448 Ansi 10 Color Alpha Component 1 Blue Component 0.40609359741210938 Color Space sRGB Green Component 0.98006147146224976 Red Component 0.37424531579017639 Ansi 11 Color Alpha Component 1 Blue Component 0.40395939350128174 Color Space sRGB Green Component 0.98757272958755493 Red Component 0.99950331449508667 Ansi 12 Color Alpha Component 1 Blue Component 1 Color Space sRGB Green Component 0.44485551118850708 Red Component 0.40937519073486328 Ansi 13 Color Alpha Component 1 Blue Component 1 Color Space sRGB Green Component 0.46518981456756592 Red Component 1 Ansi 14 Color Alpha Component 1 Blue Component 1 Color Space sRGB Green Component 0.99263292551040649 Red Component 0.37597531080245972 Ansi 15 Color Alpha Component 1 Blue Component 1 Color Space sRGB Green Component 1 Red Component 0.99999600648880005 Ansi 2 Color Alpha Component 1 Blue Component 0.0 Color Space sRGB Green Component 0.76266151666641235 Red Component 0.0 Ansi 3 Color Alpha Component 1 Blue Component 0.0 Color Space sRGB Green Component 0.76959484815597534 Red Component 0.78058648109436035 Ansi 4 Color Alpha Component 1 Blue Component 0.78216177225112915 Color Space sRGB Green Component 0.14576995372772217 Red Component 0.0096152340993285179 Ansi 5 Color Alpha Component 1 Blue Component 0.78154844045639038 Color Space sRGB Green Component 0.18891248106956482 Red Component 0.79022186994552612 Ansi 6 Color Alpha Component 1 Blue Component 0.78166204690933228 Color Space sRGB Green Component 0.77425903081893921 Red Component 0.0 Ansi 7 Color Alpha Component 1 Blue Component 0.78104829788208008 Color Space sRGB Green Component 0.78105825185775757 Red Component 0.7810397744178772 Ansi 8 Color Alpha Component 1 Blue Component 0.4078223705291748 Color Space sRGB Green Component 0.40782788395881653 Red Component 0.40781760215759277 Ansi 9 Color Alpha Component 1 Blue Component 0.40569943189620972 Color Space sRGB Green Component 0.43035173416137695 Red Component 1 Background Color Alpha Component 1 Blue Component 1 Color Space sRGB Green Component 1 Red Component 0.99999600648880005 Badge Color Alpha Component 0.5 Blue Component 0.0 Color Space sRGB Green Component 0.1491314172744751 Red Component 1 Bold Color Alpha Component 1 Blue Component 0.0 Color Space sRGB Green Component 0.0 Red Component 0.0 Cursor Color Alpha Component 1 Blue Component 0.0 Color Space sRGB Green Component 0.0 Red Component 0.0 Cursor Guide Color Alpha Component 0.25 Blue Component 1 Color Space sRGB Green Component 0.9268307089805603 Red Component 0.70213186740875244 Cursor Text Color Alpha Component 1 Blue Component 1 Color Space sRGB Green Component 1 Red Component 0.99999600648880005 Foreground Color Alpha Component 1 Blue Component 0.0 Color Space sRGB Green Component 0.0 Red Component 0.0 Link Color Alpha Component 1 Blue Component 0.73423302173614502 Color Space sRGB Green Component 0.35916060209274292 Red Component 0.0 Selected Text Color Alpha Component 1 Blue Component 0.0 Color Space sRGB Green Component 0.0 Red Component 0.0 Selection Color Alpha Component 1 Blue Component 1 Color Space sRGB Green Component 0.86970102787017822 Red Component 0.75813239812850952 cli/tools/ansi-palettes.txt0000644000176200001440000000314714557444176015521 0ustar liggesusers black red green yellow blue magenta cyan white br_black br_red br_green br_yellow br_blue br_magenta br_cyan br_white dichro #000000 #882255 #117733 #ddcc77 #332288 #aa4499 #88ccee #e5e5e5 #000000 #cc6677 #999933 #ddcc77 #44aa99 #aa4499 #88ccee #ffffff vga #000000 #aa0000 #00aa00 #aa5500 #0000aa #aa00aa #00aaaa #aaaaaa #555555 #ff5555 #55ff55 #ffff55 #5555ff #ff55ff #55ffff #ffffff winxp #000000 #800000 #008000 #808000 #000080 #800080 #008080 #c0c0c0 #808080 #ff0000 #00ff00 #ffff00 #0000ff #ff00ff #00ffff #ffffff vscode #000000 #cd3131 #0dbc79 #e5e510 #2472c8 #bc3fbc #11a8cd #e5e5e5 #666666 #f14c4c #23d18b #f5f543 #3b8eea #d670d6 #29b8db #e5e5e5 win10 #0c0c0c #c50f1f #13a10e #c19c00 #0037da #881798 #3a96dd #cccccc #767676 #e74856 #16c60c #f9f1a5 #3b78ff #b4009e #61d6d6 #f2f2f2 macos #000000 #c23621 #25bc24 #adad27 #492ee1 #d338d3 #33bbc8 #cbcccd #818383 #fc391f #31e722 #eaec23 #5833ff #f935f8 #14f0f0 #e9ebeb putty #000000 #bb0000 #00bb00 #bbbb00 #0000bb #bb00bb #00bbbb #bbbbbb #555555 #ff5555 #55ff55 #ffff55 #5555ff #ff55ff #55ffff #ffffff mirc #000000 #7f0000 #009300 #fc7f00 #00007f #9c009c #009393 #d2d2d2 #7f7f7f #ff0000 #00fc00 #ffff00 #0000fc #ff00ff #00ffff #ffffff xterm #000000 #cd0000 #00cd00 #cdcd00 #0000ee #cd00cd #00cdcd #e5e5e5 #7f7f7f #ff0000 #00ff00 #ffff00 #5c5cff #ff00ff #00ffff #ffffff ubuntu #010101 #de382b #39b54a #ffc706 #006fb8 #762671 #2cb5e9 #cccccc #808080 #ff0000 #00ff00 #ffff00 #0000ff #ff00ff #00ffff #ffffff eclipse #000000 #cd0000 #00cd00 #cdcd00 #0000ee #cd00cd #00cdcd #e5e5e5 #000000 #ff0000 #00ff00 #ffff00 #5c5cff #ff00ff #00ffff #ffffff cli/tools/smoooooth.itermcolors0000644000176200001440000002014414557444176016515 0ustar liggesusers Ansi 0 Color Alpha Component 1 Blue Component 0.11764705926179886 Color Space sRGB Green Component 0.098039217293262482 Red Component 0.078431375324726105 Ansi 1 Color Alpha Component 1 Blue Component 0.16300037503242493 Color Space sRGB Green Component 0.23660069704055786 Red Component 0.7074432373046875 Ansi 10 Color Alpha Component 1 Blue Component 0.56541937589645386 Color Space sRGB Green Component 0.9042816162109375 Red Component 0.3450070321559906 Ansi 11 Color Alpha Component 1 Blue Component 0.0 Color Space sRGB Green Component 0.8833775520324707 Red Component 0.9259033203125 Ansi 12 Color Alpha Component 1 Blue Component 0.9485321044921875 Color Space sRGB Green Component 0.67044717073440552 Red Component 0.65349078178405762 Ansi 13 Color Alpha Component 1 Blue Component 0.8821563720703125 Color Space sRGB Green Component 0.4927266538143158 Red Component 0.8821563720703125 Ansi 14 Color Alpha Component 1 Blue Component 1 Color Space sRGB Green Component 0.99263292551040649 Red Component 0.37597531080245972 Ansi 15 Color Alpha Component 1 Blue Component 1 Color Space sRGB Green Component 1 Red Component 0.99999600648880005 Ansi 2 Color Alpha Component 1 Blue Component 0.0 Color Space sRGB Green Component 0.7607843279838562 Red Component 0.0 Ansi 3 Color Alpha Component 1 Blue Component 0.0 Color Space sRGB Green Component 0.76959484815597534 Red Component 0.78058648109436035 Ansi 4 Color Alpha Component 1 Blue Component 0.78216177225112915 Color Space sRGB Green Component 0.26474356651306152 Red Component 0.15404300391674042 Ansi 5 Color Alpha Component 1 Blue Component 0.74494361877441406 Color Space sRGB Green Component 0.24931684136390686 Red Component 0.752197265625 Ansi 6 Color Alpha Component 1 Blue Component 0.78166204690933228 Color Space sRGB Green Component 0.77425903081893921 Red Component 0.0 Ansi 7 Color Alpha Component 1 Blue Component 0.78104829788208008 Color Space sRGB Green Component 0.78105825185775757 Red Component 0.7810397744178772 Ansi 8 Color Alpha Component 1 Blue Component 0.4078223705291748 Color Space sRGB Green Component 0.40782788395881653 Red Component 0.40781760215759277 Ansi 9 Color Alpha Component 1 Blue Component 0.45833224058151245 Color Space sRGB Green Component 0.47524076700210571 Red Component 0.8659515380859375 Background Color Alpha Component 1 Blue Component 0.12103271484375 Color Space sRGB Green Component 0.099111050367355347 Red Component 0.0806884765625 Badge Color Alpha Component 0.5 Blue Component 1 Color Space sRGB Green Component 1 Red Component 1 Bold Color Alpha Component 1 Blue Component 1 Color Space sRGB Green Component 1 Red Component 0.99999600648880005 Cursor Color Alpha Component 1 Blue Component 0.99998724460601807 Color Space sRGB Green Component 1 Red Component 0.99997633695602417 Cursor Guide Color Alpha Component 0.25 Blue Component 1 Color Space sRGB Green Component 0.9268307089805603 Red Component 0.70213186740875244 Cursor Text Color Alpha Component 1 Blue Component 0.0 Color Space sRGB Green Component 0.0 Red Component 0.0 Foreground Color Alpha Component 1 Blue Component 0.86198854446411133 Color Space sRGB Green Component 0.86199951171875 Red Component 0.86197912693023682 Link Color Alpha Component 1 Blue Component 0.9337158203125 Color Space sRGB Green Component 0.55789834260940552 Red Component 0.19802422821521759 Selected Text Color Alpha Component 1 Blue Component 0.0 Color Space sRGB Green Component 0.0 Red Component 0.0 Selection Color Alpha Component 1 Blue Component 1 Color Space sRGB Green Component 0.84313726425170898 Red Component 0.70196080207824707 cli/tools/dark.itermcolors0000644000176200001440000001777114557444176015424 0ustar liggesusers Ansi 0 Color Alpha Component 1 Blue Component 0.0 Color Space sRGB Green Component 0.0 Red Component 0.0 Ansi 1 Color Alpha Component 1 Blue Component 0.0 Color Space sRGB Green Component 0.10676553100347519 Red Component 0.789775550365448 Ansi 10 Color Alpha Component 1 Blue Component 0.40609359741210938 Color Space sRGB Green Component 0.98006147146224976 Red Component 0.37424531579017639 Ansi 11 Color Alpha Component 1 Blue Component 0.40395939350128174 Color Space sRGB Green Component 0.98757272958755493 Red Component 0.99950331449508667 Ansi 12 Color Alpha Component 1 Blue Component 1 Color Space sRGB Green Component 0.44485551118850708 Red Component 0.40937519073486328 Ansi 13 Color Alpha Component 1 Blue Component 1 Color Space sRGB Green Component 0.46518981456756592 Red Component 1 Ansi 14 Color Alpha Component 1 Blue Component 1 Color Space sRGB Green Component 0.99263292551040649 Red Component 0.37597531080245972 Ansi 15 Color Alpha Component 1 Blue Component 1 Color Space sRGB Green Component 1 Red Component 0.99999600648880005 Ansi 2 Color Alpha Component 1 Blue Component 0.0 Color Space sRGB Green Component 0.76266151666641235 Red Component 0.0 Ansi 3 Color Alpha Component 1 Blue Component 0.0 Color Space sRGB Green Component 0.76959484815597534 Red Component 0.78058648109436035 Ansi 4 Color Alpha Component 1 Blue Component 0.78216177225112915 Color Space sRGB Green Component 0.14576995372772217 Red Component 0.0096152340993285179 Ansi 5 Color Alpha Component 1 Blue Component 0.78154844045639038 Color Space sRGB Green Component 0.18891248106956482 Red Component 0.79022186994552612 Ansi 6 Color Alpha Component 1 Blue Component 0.78166204690933228 Color Space sRGB Green Component 0.77425903081893921 Red Component 0.0 Ansi 7 Color Alpha Component 1 Blue Component 0.78104829788208008 Color Space sRGB Green Component 0.78105825185775757 Red Component 0.7810397744178772 Ansi 8 Color Alpha Component 1 Blue Component 0.4078223705291748 Color Space sRGB Green Component 0.40782788395881653 Red Component 0.40781760215759277 Ansi 9 Color Alpha Component 1 Blue Component 0.40569943189620972 Color Space sRGB Green Component 0.43035173416137695 Red Component 1 Background Color Alpha Component 1 Blue Component 0.0 Color Space sRGB Green Component 0.0 Red Component 0.0 Badge Color Alpha Component 0.5 Blue Component 0.0 Color Space sRGB Green Component 0.1491314172744751 Red Component 1 Bold Color Alpha Component 1 Blue Component 1 Color Space sRGB Green Component 1 Red Component 0.99999600648880005 Cursor Color Alpha Component 1 Blue Component 0.78104829788208008 Color Space sRGB Green Component 0.78105825185775757 Red Component 0.7810397744178772 Cursor Guide Color Alpha Component 0.25 Blue Component 1 Color Space sRGB Green Component 0.9268307089805603 Red Component 0.70213186740875244 Cursor Text Color Alpha Component 1 Blue Component 1 Color Space sRGB Green Component 1 Red Component 0.99999600648880005 Foreground Color Alpha Component 1 Blue Component 0.78104829788208008 Color Space sRGB Green Component 0.78105825185775757 Red Component 0.7810397744178772 Link Color Alpha Component 1 Blue Component 0.73423302173614502 Color Space sRGB Green Component 0.35916060209274292 Red Component 0.0 Selected Text Color Alpha Component 1 Blue Component 0.0 Color Space sRGB Green Component 0.0 Red Component 0.0 Selection Color Alpha Component 1 Blue Component 1 Color Space sRGB Green Component 0.86970102787017822 Red Component 0.75813239812850952 cli/tools/tango-dark.itermcolors0000644000176200001440000002010514557444176016513 0ustar liggesusers Ansi 0 Color Alpha Component 1 Blue Component 0.0 Color Space sRGB Green Component 0.0 Red Component 0.0 Ansi 1 Color Alpha Component 1 Blue Component 0.0 Color Space sRGB Green Component 0.11767414957284927 Red Component 0.84674292802810669 Ansi 10 Color Alpha Component 1 Blue Component 0.26148656010627747 Color Space sRGB Green Component 0.89173698425292969 Red Component 0.59970396757125854 Ansi 11 Color Alpha Component 1 Blue Component 0.37922361493110657 Color Space sRGB Green Component 0.92064303159713745 Red Component 0.99169927835464478 Ansi 12 Color Alpha Component 1 Blue Component 0.84789222478866577 Color Space sRGB Green Component 0.68869423866271973 Red Component 0.51713955402374268 Ansi 13 Color Alpha Component 1 Blue Component 0.71664512157440186 Color Space sRGB Green Component 0.57970219850540161 Red Component 0.73733323812484741 Ansi 14 Color Alpha Component 1 Blue Component 0.90933424234390259 Color Space sRGB Green Component 0.90141081809997559 Red Component 0.21587523818016052 Ansi 15 Color Alpha Component 1 Blue Component 0.9404633641242981 Color Space sRGB Green Component 0.94661098718643188 Red Component 0.94678574800491333 Ansi 2 Color Alpha Component 1 Blue Component 0.0088730743154883385 Color Space sRGB Green Component 0.65366500616073608 Red Component 0.36692649126052856 Ansi 3 Color Alpha Component 1 Blue Component 0.0 Color Space sRGB Green Component 0.68127995729446411 Red Component 0.81349855661392212 Ansi 4 Color Alpha Component 1 Blue Component 0.70342475175857544 Color Space sRGB Green Component 0.47867023944854736 Red Component 0.25807341933250427 Ansi 5 Color Alpha Component 1 Blue Component 0.55586665868759155 Color Space sRGB Green Component 0.39761847257614136 Red Component 0.5363890528678894 Ansi 6 Color Alpha Component 1 Blue Component 0.6682930588722229 Color Space sRGB Green Component 0.65514689683914185 Red Component 0.0 Ansi 7 Color Alpha Component 1 Blue Component 0.8471907377243042 Color Space sRGB Green Component 0.87220901250839233 Red Component 0.85992234945297241 Ansi 8 Color Alpha Component 1 Blue Component 0.39959198236465454 Color Space sRGB Green Component 0.41529536247253418 Red Component 0.40758803486824036 Ansi 9 Color Alpha Component 1 Blue Component 0.20832169055938721 Color Space sRGB Green Component 0.25720733404159546 Red Component 0.96001332998275757 Background Color Alpha Component 1 Blue Component 0.0 Color Space sRGB Green Component 0.0 Red Component 0.0 Badge Color Alpha Component 0.5 Blue Component 0.0 Color Space sRGB Green Component 0.1491314172744751 Red Component 1 Bold Color Alpha Component 1 Blue Component 1 Color Space sRGB Green Component 1 Red Component 0.99999600648880005 Cursor Color Alpha Component 1 Blue Component 1 Color Space sRGB Green Component 1 Red Component 0.99999600648880005 Cursor Guide Color Alpha Component 0.25 Blue Component 1 Color Space sRGB Green Component 0.9268307089805603 Red Component 0.70213186740875244 Cursor Text Color Alpha Component 1 Blue Component 0.0 Color Space sRGB Green Component 0.0 Red Component 0.0 Foreground Color Alpha Component 1 Blue Component 1 Color Space sRGB Green Component 1 Red Component 0.99999600648880005 Link Color Alpha Component 1 Blue Component 0.73423302173614502 Color Space sRGB Green Component 0.35916060209274292 Red Component 0.0 Selected Text Color Alpha Component 1 Blue Component 0.0 Color Space sRGB Green Component 0.0 Red Component 0.0 Selection Color Alpha Component 1 Blue Component 1 Color Space sRGB Green Component 0.86970102787017822 Red Component 0.75813239812850952 cli/README.md0000644000176200001440000001370614557444176012330 0ustar liggesuserscli ================ > Helpers for Developing Command Line Interfaces [![R-CMD-check](https://github.com/r-lib/cli/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/r-lib/cli/actions/workflows/R-CMD-check.yaml) [![](https://www.r-pkg.org/badges/version/cli)](https://www.r-pkg.org/pkg/cli) [![CRAN RStudio mirror downloads](https://cranlogs.r-pkg.org/badges/cli)](https://www.r-pkg.org/pkg/cli) [![Codecov test coverage](https://codecov.io/gh/r-lib/cli/branch/main/graph/badge.svg)](https://app.codecov.io/gh/r-lib/cli?branch=main) A suite of tools to build attractive command line interfaces (CLIs), from semantic elements: headers, lists, alerts, paragraphs, etc. Supports theming via a CSS-like language. It also contains a number of lower level CLI elements: rules, boxes, trees, and Unicode symbols with ASCII alternatives. It supports ANSI markup for terminal colors and font styles. ------------------------------------------------------------------------ # Features - Build a CLI using semantic elements: headings, lists, alerts, paragraphs. - Theming via a CSS-like language. - Terminal colors and font styles. - All cli text can contain interpreted string literals, via the [glue](https://github.com/tidyverse/glue) package. - Progress bars from R and C code. - Error and warning messages with rich text formatting. - Support for pluralized messages. - ANSI styled string manipulation. # Installation Install the stable version from CRAN: ``` r install.packages("cli") ``` Install the development version from GitHub: ``` r pak::pak("r-lib/cli") ``` # Short tour Some of the more commonly used cli elements, and features. ## Short alert messages One liner messages to inform or warn. ``` r pkgs <- c("foo", "bar", "foobar") cli_alert_success("Downloaded {length(pkgs)} packages.") ``` ``` r db_url <- "example.com:port" cli_alert_info("Reopened database {.url {db_url}}.") ``` ``` r cli_alert_warning("Cannot reach GitHub, using local database cache.") ``` ``` r cli_alert_danger("Failed to connect to database.") ``` ``` r cli_alert("A generic alert") ``` ## Headings Three levels of headings. ``` r cli_h1("Heading 1") ``` ``` r cli_h2("Heading 2") ``` ``` r cli_h3("Heading 3") ``` ## Lists Ordered, unordered and description lists, that can be nested. ``` r fun <- function() { cli_ol() cli_li("Item 1") ulid <- cli_ul() cli_li("Subitem 1") cli_li("Subitem 2") cli_end(ulid) cli_li("Item 2") cli_end() } fun() ``` ## Themes Theming via a CSS-like language. ``` r fun <- function() { cli_div(theme = list(span.emph = list(color = "orange"))) cli_text("This is very {.emph important}") cli_end() cli_text("Back to the {.emph previous theme}") } fun() ``` ## Command substitution Automatic command substitution via the [glue](https://github.com/tidyverse/glue) package. ``` r size <- 123143123 dt <- 1.3454 cli_alert_info(c( "Downloaded {prettyunits::pretty_bytes(size)} in ", "{prettyunits::pretty_sec(dt)}")) ``` ## Pluralization Pluralization support. ``` r nfiles <- 3 ndirs <- 1 cli_alert_info("Found {nfiles} file{?s} and {ndirs} director{?y/ies}.") ``` ## Progress bars ``` r clean <- function() { cli_progress_bar("Cleaning data", total = 100) for (i in 1:100) { Sys.sleep(5/100) cli_progress_update() } } clean() ``` # Documentation See at [`https://cli.r-lib.org/`](https://cli.r-lib.org/reference/index.html) and also in the installed package: `help(package = "cli")`. # Code of Conduct Please note that the cli project is released with a [Contributor Code of Conduct](https://cli.r-lib.org/dev/CODE_OF_CONDUCT.html). By contributing to this project, you agree to abide by its terms. # License MIT © Posit Software, PBC cli/man/0000755000176200001440000000000014752736636011617 5ustar liggesuserscli/man/cli_abort.Rd0000644000176200001440000001125014752735214014032 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/rlang.R \name{cli_abort} \alias{cli_abort} \alias{cli_warn} \alias{cli_inform} \title{Signal an error, warning or message with a cli formatted message} \usage{ cli_abort( message, ..., call = .envir, .envir = parent.frame(), .frame = .envir ) cli_warn(message, ..., .envir = parent.frame()) cli_inform(message, ..., .envir = parent.frame()) } \arguments{ \item{message}{It is formatted via a call to \code{\link[=cli_bullets]{cli_bullets()}}.} \item{...}{Passed to \code{\link[rlang:abort]{rlang::abort()}}, \code{\link[rlang:abort]{rlang::warn()}} or \code{\link[rlang:abort]{rlang::inform()}}.} \item{call}{The execution environment of a currently running function, e.g. \code{call = caller_env()}. The corresponding function call is retrieved and mentioned in error messages as the source of the error. You only need to supply \code{call} when throwing a condition from a helper function which wouldn't be relevant to mention in the message. Can also be \code{NULL} or a \link[rlang:topic-defuse]{defused function call} to respectively not display any call or hard-code a code to display. For more information about error calls, see \ifelse{html}{\link[rlang:topic-error-call]{Including function calls in error messages}}{\link[rlang:topic-error-call]{Including function calls in error messages}}.} \item{.envir}{Environment to evaluate the glue expressions in.} \item{.frame}{The throwing context. Used as default for \code{.trace_bottom}, and to determine the internal package to mention in internal errors when \code{.internal} is \code{TRUE}.} } \description{ These functions let you create error, warning or diagnostic messages with cli formatting, including inline styling, pluralization and glue substitutions. } \details{ \if{html}{\out{
}}\preformatted{n <- "boo" cli_abort(c( "\{.var n\} must be a numeric vector", "x" = "You've supplied a \{.cls \{class(n)\}\} vector." )) }\if{html}{\out{
}}\if{html}{\out{
#> Error:                                                                          
#> ! `n` must be a numeric vector                                                  
#>  You've supplied a <character> vector.                                         
#> Run `rlang::last_error()` to see where the error occurred.                      
}} \if{html}{\out{
}}\preformatted{len <- 26 idx <- 100 cli_abort(c( "Must index an existing element:", "i" = "There \{?is/are\} \{len\} element\{?s\}.", "x" = "You've tried to subset element \{idx\}." )) }\if{html}{\out{
}}\if{html}{\out{
#> Error:                                                                          
#> ! Must index an existing element:                                               
#>  There are 26 elements.                                                        
#>  You've tried to subset element 100.                                           
#> Run `rlang::last_error()` to see where the error occurred.                      
}} } \seealso{ These functions support \link[=inline-markup]{inline markup}. Other functions supporting inline markup: \code{\link{cli_alert}()}, \code{\link{cli_blockquote}()}, \code{\link{cli_bullets}()}, \code{\link{cli_bullets_raw}()}, \code{\link{cli_dl}()}, \code{\link{cli_h1}()}, \code{\link{cli_li}()}, \code{\link{cli_ol}()}, \code{\link{cli_process_start}()}, \code{\link{cli_progress_along}()}, \code{\link{cli_progress_bar}()}, \code{\link{cli_progress_message}()}, \code{\link{cli_progress_output}()}, \code{\link{cli_progress_step}()}, \code{\link{cli_rule}}, \code{\link{cli_status}()}, \code{\link{cli_status_update}()}, \code{\link{cli_text}()}, \code{\link{cli_ul}()}, \code{\link{format_error}()}, \code{\link{format_inline}()} } \concept{functions supporting inline markup} cli/man/ansi_trimws.Rd0000644000176200001440000000212414752735214014433 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/ansiex.R \name{ansi_trimws} \alias{ansi_trimws} \title{Remove leading and/or trailing whitespace from an ANSI string} \usage{ ansi_trimws(x, which = c("both", "left", "right")) } \arguments{ \item{x}{ANSI string vector.} \item{which}{Whether to remove leading or trailing whitespace or both.} } \value{ ANSI string, with the whitespace removed. } \description{ This function is similar to \code{\link[base:trimws]{base::trimws()}} but works on ANSI strings, and keeps color and other styling. } \examples{ trimws(paste0(" ", col_red("I am red"), " ")) ansi_trimws(paste0(" ", col_red("I am red"), " ")) trimws(col_red(" I am red ")) ansi_trimws(col_red(" I am red ")) } \seealso{ Other ANSI string operations: \code{\link{ansi_align}()}, \code{\link{ansi_columns}()}, \code{\link{ansi_nchar}()}, \code{\link{ansi_strsplit}()}, \code{\link{ansi_strtrim}()}, \code{\link{ansi_strwrap}()}, \code{\link{ansi_substr}()}, \code{\link{ansi_substring}()}, \code{\link{ansi_toupper}()} } \concept{ANSI string operations} cli/man/cli_ul.Rd0000644000176200001440000000701014752735214013342 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/cli.R \name{cli_ul} \alias{cli_ul} \title{Unordered CLI list} \usage{ cli_ul( items = NULL, id = NULL, class = NULL, .close = TRUE, .auto_close = TRUE, .envir = parent.frame() ) } \arguments{ \item{items}{If not \code{NULL}, then a character vector. Each element of the vector will be one list item, and the list container will be closed by default (see the \code{.close} argument).} \item{id}{Id of the list container. Can be used for closing it with \code{\link[=cli_end]{cli_end()}} or in themes. If \code{NULL}, then an id is generated and returned invisibly.} \item{class}{Class of the list container. Can be used in themes.} \item{.close}{Whether to close the list container if the \code{items} were specified. If \code{FALSE} then new items can be added to the list.} \item{.auto_close}{Whether to close the container, when the calling function finishes (or \code{.envir} is removed, if specified).} \item{.envir}{Environment to evaluate the glue expressions in. It is also used to auto-close the container if \code{.auto_close} is \code{TRUE}.} } \value{ The id of the new container element, invisibly. } \description{ An unordered list is a container, see \link{containers}. } \details{ \subsection{Adding all items at once}{ \if{html}{\out{
}}\preformatted{fun <- function() \{ cli_ul(c("one", "two", "three")) \} fun() }\if{html}{\out{
}}\if{html}{\out{
#> • one                                                                           
#> • two                                                                           
#> • three                                                                         
}} } \subsection{Adding items one by one}{ \if{html}{\out{
}}\preformatted{fun <- function() \{ cli_ul() cli_li("\{.emph one\}") cli_li("\{.emph two\}") cli_li("\{.emph three\}") cli_end() \} fun() }\if{html}{\out{
}}\if{html}{\out{
#> • one                                                                           
#> • two                                                                           
#> • three                                                                         
}} } } \seealso{ This function supports \link[=inline-markup]{inline markup}. Other functions supporting inline markup: \code{\link{cli_abort}()}, \code{\link{cli_alert}()}, \code{\link{cli_blockquote}()}, \code{\link{cli_bullets}()}, \code{\link{cli_bullets_raw}()}, \code{\link{cli_dl}()}, \code{\link{cli_h1}()}, \code{\link{cli_li}()}, \code{\link{cli_ol}()}, \code{\link{cli_process_start}()}, \code{\link{cli_progress_along}()}, \code{\link{cli_progress_bar}()}, \code{\link{cli_progress_message}()}, \code{\link{cli_progress_output}()}, \code{\link{cli_progress_step}()}, \code{\link{cli_rule}}, \code{\link{cli_status}()}, \code{\link{cli_status_update}()}, \code{\link{cli_text}()}, \code{\link{format_error}()}, \code{\link{format_inline}()} } \concept{functions supporting inline markup} cli/man/ansi_nchar.Rd0000644000176200001440000000235514752735214014207 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/ansiex.R \name{ansi_nchar} \alias{ansi_nchar} \title{Count number of characters in an ANSI colored string} \usage{ ansi_nchar(x, type = c("chars", "bytes", "width", "graphemes", "codepoints")) } \arguments{ \item{x}{Character vector, potentially ANSI styled, or a vector to be coerced to character. If it converted to UTF-8.} \item{type}{Whether to count graphemes (characters), code points, bytes, or calculate the display width of the string.} } \value{ Numeric vector, the length of the strings in the character vector. } \description{ This is a color-aware counterpart of \code{\link[=utf8_nchar]{utf8_nchar()}}. By default it counts Unicode grapheme clusters, instead of code points. } \examples{ str <- paste( col_red("red"), "default", col_green("green") ) cat(str, "\n") nchar(str) ansi_nchar(str) nchar(ansi_strip(str)) } \seealso{ Other ANSI string operations: \code{\link{ansi_align}()}, \code{\link{ansi_columns}()}, \code{\link{ansi_strsplit}()}, \code{\link{ansi_strtrim}()}, \code{\link{ansi_strwrap}()}, \code{\link{ansi_substr}()}, \code{\link{ansi_substring}()}, \code{\link{ansi_toupper}()}, \code{\link{ansi_trimws}()} } \concept{ANSI string operations} cli/man/cli_text.Rd0000644000176200001440000001372314752735214013716 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/cli.R \name{cli_text} \alias{cli_text} \title{CLI text} \usage{ cli_text(..., .envir = parent.frame()) } \arguments{ \item{...}{The text to show, in character vectors. They will be concatenated into a single string. Newlines are \emph{not} preserved.} \item{.envir}{Environment to evaluate the glue expressions in.} } \description{ Write some text to the screen. This function is most appropriate for longer paragraphs. See \code{\link[=cli_alert]{cli_alert()}} for shorter status messages. } \details{ \subsection{Text wrapping}{ Text is wrapped to the console width, see \code{\link[=console_width]{console_width()}}. \if{html}{\out{
}}\preformatted{cli_text(cli:::lorem_ipsum()) }\if{html}{\out{
}}\if{html}{\out{
#> Lorem ad ipsum veniam esse nisi deserunt duis. Qui incididunt elit              
#> elit mollit sint nulla consectetur aute commodo do elit laboris minim           
#> et. Laboris ipsum mollit voluptate et non do incididunt eiusmod. Anim           
#> consectetur mollit laborum occaecat eiusmod excepteur. Ullamco non              
#> tempor esse anim tempor magna non.                                              
}} } \subsection{New lines}{ A \code{cli_text()} call always appends a newline character to the end. \if{html}{\out{
}}\preformatted{cli_text("First line.") cli_text("Second line.") }\if{html}{\out{
}}\if{html}{\out{
#> First line.                                                                     
#> Second line.                                                                    
}} } \subsection{Styling}{ You can use \link[=inline-markup]{inline markup}, as usual. \if{html}{\out{
}}\preformatted{cli_text("The \{.fn cli_text\} function in the \{.pkg cli\} package.") }\if{html}{\out{
}}\if{html}{\out{
#> The `cli_text()` function in the cli package.                                   
}} } \subsection{Interpolation}{ String interpolation via glue works as usual. Interpolated vectors are collapsed. \if{html}{\out{
}}\preformatted{pos <- c(5, 14, 25, 26) cli_text("We have \{length(pos)\} missing measurements: \{pos\}.") }\if{html}{\out{
}}\if{html}{\out{
#> We have 4 missing measurements: 5, 14, 25, and 26.                              
}} } \subsection{Styling and interpolation}{ Use double braces to combine styling and string interpolation. \if{html}{\out{
}}\preformatted{fun <- "cli-text" pkg <- "cli" cli_text("The \{.fn \{fun\}\} function in the \{.pkg \{pkg\}\} package.") }\if{html}{\out{
}}\if{html}{\out{
#> The `cli-text()` function in the cli package.                                   
}} } \subsection{Multiple arguments}{ Arguments are concatenated. \if{html}{\out{
}}\preformatted{cli_text(c("This ", "will ", "all "), "be ", "one ", "sentence.") }\if{html}{\out{
}}\if{html}{\out{
#> This will all be one sentence.                                                  
}} } \subsection{Containers}{ You can use \code{cli_text()} within cli \link{containers}. \if{html}{\out{
}}\preformatted{ul <- cli_ul() cli_li("First item.") cli_text("Still the \{.emph first\} item") cli_li("Second item.") cli_text("Still the \{.emph second\} item") cli_end(ul) }\if{html}{\out{
}}\if{html}{\out{
#> • First item.                                                                   
#> Still the first item                                                            
#> • Second item.                                                                  
#> Still the second item                                                           
}} } } \seealso{ This function supports \link[=inline-markup]{inline markup}. Other functions supporting inline markup: \code{\link{cli_abort}()}, \code{\link{cli_alert}()}, \code{\link{cli_blockquote}()}, \code{\link{cli_bullets}()}, \code{\link{cli_bullets_raw}()}, \code{\link{cli_dl}()}, \code{\link{cli_h1}()}, \code{\link{cli_li}()}, \code{\link{cli_ol}()}, \code{\link{cli_process_start}()}, \code{\link{cli_progress_along}()}, \code{\link{cli_progress_bar}()}, \code{\link{cli_progress_message}()}, \code{\link{cli_progress_output}()}, \code{\link{cli_progress_step}()}, \code{\link{cli_rule}}, \code{\link{cli_status}()}, \code{\link{cli_status_update}()}, \code{\link{cli_ul}()}, \code{\link{format_error}()}, \code{\link{format_inline}()} } \concept{functions supporting inline markup} cli/man/diff_chr.Rd0000644000176200001440000000350614557444176013654 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/diff.R \name{diff_chr} \alias{diff_chr} \title{Compare two character vectors elementwise} \usage{ diff_chr(old, new, max_dist = Inf) } \arguments{ \item{old}{First character vector.} \item{new}{Second character vector.} \item{max_dist}{Maximum distance to consider, or \code{Inf} for no limit. If the LCS edit distance is larger than this, then the function throws an error with class \code{"cli_diff_max_dist"}. (If you specify \code{Inf} the real limit is \code{.Machine$integer.max} but to reach this the function would have to run a very long time.)} } \value{ A list that is a \code{cli_diff_chr} object, with a \code{format()} and a \code{print()} method. You can also access its members: \itemize{ \item \code{old} and \code{new} are the original inputs, \item \code{lcs} is a data frame of LCS edit that transform \code{old} into \code{new}. } The \code{lcs} data frame has the following columns: \itemize{ \item \code{operation}: one of \code{"match"}, \code{"delete"} or \code{"insert"}. \item \code{offset}: offset in \code{old} for matches and deletions, offset in \code{new} for insertions. \item \code{length}: length of the operation, i.e. number of matching, deleted or inserted elements. \item \code{old_offset}: offset in \code{old} \emph{after} the operation. \item \code{new_offset}: offset in \code{new} \emph{after} the operation. } } \description{ Its printed output is similar to calling \code{diff -u} at the command line. } \examples{ letters2 <- c("P", "R", "E", letters, "P", "O", "S", "T") letters2[11:16] <- c("M", "I", "D", "D", "L", "E") diff_chr(letters, letters2) } \seealso{ The diffobj package for a much more comprehensive set of \code{diff}-like tools. Other diff functions in cli: \code{\link{diff_str}()} } \concept{diff functions in cli} cli/man/code_highlight.Rd0000644000176200001440000000214414557444176015046 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/prettycode.R \name{code_highlight} \alias{code_highlight} \title{Syntax highlight R code} \usage{ code_highlight(code, code_theme = NULL, envir = NULL) } \arguments{ \item{code}{Character vector, each element is one line of code.} \item{code_theme}{Theme see \code{\link[=code_theme_list]{code_theme_list()}}.} \item{envir}{Environment to look up function calls for hyperlinks. If \code{NULL}, then the global search path is used.} } \value{ Character vector, the highlighted code. } \description{ Syntax highlight R code } \details{ See \code{\link[=code_theme_list]{code_theme_list()}} for the default syntax highlighting theme and how to change it. If \code{code} does not parse, then it is returned unchanged and a \code{cli_parse_failure} condition is thrown. Note that this is not an error, and the condition is ignored, unless explicitly caught. } \examples{ code_highlight(deparse(ls)) cat(code_highlight(deparse(ls)), sep = "\n") } \seealso{ Other syntax highlighting: \code{\link{code_theme_list}()} } \concept{syntax highlighting} cli/man/cli_progress_styles.Rd0000644000176200001440000000562214752364056016202 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/progress-bar.R \name{cli_progress_styles} \alias{cli_progress_styles} \title{List of built-in cli progress styles} \usage{ cli_progress_styles() } \value{ A named list with sublists containing elements \code{complete}, \code{incomplete} and potentially \code{current}. } \description{ The following options are used to select a style: \itemize{ \item \code{cli_progress_bar_style} \item \code{cli_progress_bar_style_ascii} \item \code{cli_progress_bar_style_unicode} } } \details{ On Unicode terminals (if \code{\link[=is_utf8_output]{is_utf8_output()}} is \code{TRUE}), the \code{cli_progress_bar_style_unicode} and \code{cli_progress_bar_style} options are used. On ASCII terminals (if \code{\link[=is_utf8_output]{is_utf8_output()}} is \code{FALSE}), the \code{cli_pgoress_bar_style_ascii} and \code{cli_progress_bar_style} options are are used. \if{html}{\out{
}}\preformatted{for (style in names(cli_progress_styles())) \{ options(cli.progress_bar_style = style) label <- ansi_align(paste0("Style '", style, "'"), 20) print(cli_progress_demo(label, live = FALSE, at = 66, total = 100)) \} options(cli.progress_var_style = NULL) }\if{html}{\out{
}}\if{html}{\out{
#> Style 'classic'      #####################             66% | ETA:  3s           
#> Style 'squares'      ■■■■■■■■■■■■■■■■■■■■■             66% | ETA:  3s           
#> Style 'dot'          ──────────────────────────────   66% | ETA:  3s           
#> Style 'fillsquares'  ■■■■■■■■■■■■■■■■■■■■■□□□□□□□□□□   66% | ETA:  3s           
#> Style 'bar'          ███████████████████████████████   66% | ETA:  3s           
}} } \seealso{ Other progress bar functions: \code{\link{cli_progress_along}()}, \code{\link{cli_progress_bar}()}, \code{\link{cli_progress_builtin_handlers}()}, \code{\link{cli_progress_message}()}, \code{\link{cli_progress_num}()}, \code{\link{cli_progress_output}()}, \code{\link{cli_progress_step}()}, \code{\link{progress-variables}} } \concept{progress bar functions} cli/man/console_width.Rd0000644000176200001440000000271014557444176014745 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/width.R \name{console_width} \alias{console_width} \title{Determine the width of the console} \usage{ console_width() } \value{ Integer scalar, the console with, in number of characters. } \description{ It uses the \code{cli.width} option, if set. Otherwise it tries to determine the size of the terminal or console window. } \details{ These are the exact rules: \itemize{ \item If the \code{cli.width} option is set to a positive integer, it is used. \item If the \code{cli.width} option is set, but it is not a positive integer, and error is thrown. } Then we try to determine the size of the terminal or console window: \itemize{ \item If we are not in RStudio, or we are in an RStudio terminal, then we try to use the \code{tty_size()} function to query the terminal size. This might fail if R is not running in a terminal, but failures are ignored. \item If we are in the RStudio build pane, then the \code{RSTUDIO_CONSOLE_WIDTH} environment variable is used. If the build pane is resized, then this environment variable is not accurate any more, and the output might get garbled. \item We are \emph{not} using the \code{RSTUDIO_CONSOLE_WIDTH} environment variable if we are in the RStudio console. } If we cannot determine the size of the terminal or console window, then we use the \code{width} option. If the \code{width} option is not set, then we return 80L. } \examples{ console_width() } cli/man/pretty_print_code.Rd0000644000176200001440000000076714557444176015653 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/prettycode.R \name{pretty_print_code} \alias{pretty_print_code} \title{Turn on pretty-printing functions at the R console} \usage{ pretty_print_code() } \description{ Defines a print method for functions, in the current session, that supports syntax highlighting. } \details{ The new print method takes priority over the built-in one. Use \code{\link[base:message]{base::suppressMessages()}} to suppress the alert message. } cli/man/cli_h1.Rd0000644000176200001440000000553414752735214013243 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/cli.R \name{cli_h1} \alias{cli_h1} \alias{cli_h2} \alias{cli_h3} \title{CLI headings} \usage{ cli_h1(text, id = NULL, class = NULL, .envir = parent.frame()) cli_h2(text, id = NULL, class = NULL, .envir = parent.frame()) cli_h3(text, id = NULL, class = NULL, .envir = parent.frame()) } \arguments{ \item{text}{Text of the heading. It can contain inline markup.} \item{id}{Id of the heading element, string. It can be used in themes.} \item{class}{Class of the heading element, string. It can be used in themes.} \item{.envir}{Environment to evaluate the glue expressions in.} } \description{ cli has three levels of headings. } \details{ This is how the headings look with the default builtin theme. \if{html}{\out{
}}\preformatted{cli_h1("Header \{.emph 1\}") cli_h2("Header \{.emph 2\}") cli_h3("Header \{.emph 3\}") }\if{html}{\out{
}}\if{html}{\out{
#>                                                                                 
#> ── Header 1 ──────────────────────────────────────────────────────────          
#>                                                                                 
#> ── Header 2 ──                                                                  
#>                                                                                 
#> ── Header 3                                                                     
}} } \seealso{ These functions supports \link[=inline-markup]{inline markup}. Other functions supporting inline markup: \code{\link{cli_abort}()}, \code{\link{cli_alert}()}, \code{\link{cli_blockquote}()}, \code{\link{cli_bullets}()}, \code{\link{cli_bullets_raw}()}, \code{\link{cli_dl}()}, \code{\link{cli_li}()}, \code{\link{cli_ol}()}, \code{\link{cli_process_start}()}, \code{\link{cli_progress_along}()}, \code{\link{cli_progress_bar}()}, \code{\link{cli_progress_message}()}, \code{\link{cli_progress_output}()}, \code{\link{cli_progress_step}()}, \code{\link{cli_rule}}, \code{\link{cli_status}()}, \code{\link{cli_status_update}()}, \code{\link{cli_text}()}, \code{\link{cli_ul}()}, \code{\link{format_error}()}, \code{\link{format_inline}()} } \concept{functions supporting inline markup} cli/man/links.Rd0000644000176200001440000003567314752364056013235 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/cliapp-docs.R \name{links} \alias{links} \title{cli hyperlinks} \description{ Certain cli styles create clickable links, if your IDE or terminal supports them. } \section{Note: hyperlinks are currently experimental}{ The details of the styles that create hyperlinks will prrobably change in the near future, based on user feedback. } \section{About the links in this manual page}{ The hyperlinks that are included in this manual are demonstrative only, except for the \verb{https:} links. They look like a hyperlink, and you can click on them, but they do nothing. I.e. a \code{.run} link will not run the linked expression if you click on it. } \section{Hyperlink Support}{ As of today, the latest release of RStudio (version v2022.07.0+548) supports all hyperlink types discussed here. Certain terminals, e.g. iTerm on macOS, Linux terminals based on VTE (GNOME terminal) support \code{.href}, \code{.email} and \code{.file} links. You can use \code{\link[=ansi_has_hyperlink_support]{ansi_has_hyperlink_support()}} to check if your terminal or IDE has hyperlink support in general, and \code{\link[=ansi_hyperlink_types]{ansi_hyperlink_types()}} to check if various types of hyperlinks are supported. If your hyperlink support is not detected properly in your IDE or terminal, please open a cli issue at \url{https://github.com/r-lib/cli/issues}. } \section{Link text}{ Before we delve into the various types of hyperlinks, a general comment about link texts. Some link styles support a custom link text: \itemize{ \item \code{.href} \item \code{.help} \item \code{.topic} \item \code{.vignette} \item \code{.run} } Others, i.e. \code{.email}, \code{.file}, \code{.fun} and \code{.url} do not support custom link text. The generic syntax for link text is the same as for Markdown hyperlinks: \if{html}{\out{
}}\preformatted{\{.style [link text](url)\} }\if{html}{\out{
}} \subsection{Vectorization}{ Note that it is not possible to add link text to a vector of URLs. E.g. this will create a list of three URLs, all clickable: \if{html}{\out{
}}\preformatted{urls <- paste0("https://httpbin.org/status/", c(200, 403, 404)) cli::cli_text("Some httpbin URLs: \{.url \{urls\}\}.") }\if{html}{\out{
}}\if{html}{\out{ But it is not possible to use a different link text for them. }} } \subsection{What if hyperlinks are not available?}{ If ANSI hyperlinks are not available, then the link text for of these styles outputs both the link text and the URL in a (hopefully) helpful way. See examples below. } } \section{URLs}{ There are two cli styles to link to generic URLs. \code{.url} does not allow custom link text, but \verb{\\href} does. \if{html}{\out{
}}\preformatted{cli_text( "See the cli homepage at \{.url https://cli.r-lib.org\} for details." ) }\if{html}{\out{
}}\if{html}{\out{
#> See the cli homepage at <https://cli.r-lib.org> for details.                    
}} \if{html}{\out{
}}\preformatted{cli_text( "See the \{.href [cli homepage](https://cli.r-lib.org)\} for details." ) }\if{html}{\out{
}}\if{html}{\out{
#> See the cli homepage for details.                                               
}} \subsection{Without hyperlink support}{ This is how these links look without hyperlink support: \if{html}{\out{
}}\preformatted{local(\{ withr::local_options(cli.hyperlink = FALSE) cli_text( "See the cli homepage at \{.url https://cli.r-lib.org\} for details." ) cli_text( "See the \{.href [cli homepage](https://cli.r-lib.org)\} for details." ) \}) }\if{html}{\out{
}}\if{html}{\out{
#> See the cli homepage at <https://cli.r-lib.org> for details.                    
#> See the cli homepage (<https://cli.r-lib.org>) for details.                     
}} } \subsection{URL encoding}{ Note that cli does not encode the url, so you might need to call \code{utils::URLencode()} on it, especially, if it is substituted in via \code{{}}. \if{html}{\out{
}}\preformatted{weirdurl <- utils::URLencode("https://example.com/has some spaces") cli_text("See more at \{.url \{weirdurl\}\}.") }\if{html}{\out{
}}\if{html}{\out{ }} } } \section{Files}{ The \code{.file} style now automatically creates a \verb{file:} hyperlink. Because \verb{file:} hyperlinks must contain an absolute path, cli tries to convert relative paths, and paths starting with \code{~} to aboslute path. \if{html}{\out{
}}\preformatted{cli_text("... edit your \{.file ~/.Rprofile\} file.\}") }\if{html}{\out{
}}\if{html}{\out{
#> ... edit your ~/.Rprofile file.\}                                                
}} \subsection{Link text}{ \code{.file} cannot use a custom link text. If you custom link text, then you can use \code{.href} with a \verb{file:} URL. \if{html}{\out{
}}\preformatted{prof <- path.expand("~/.Rprofile") cli_text("... edit your \{.href [R profile](file://\{prof\})\}.") }\if{html}{\out{
}}\if{html}{\out{
#> ... edit your R profile.                                                        
}} } \subsection{Line and column numbers}{ You may add a line number to a file name, separated by \code{:}. Handlers typically place the cursor at that line after opening the file. You may also add a column number, after the line number, separated by another \code{:}. \if{html}{\out{
}}\preformatted{cli_text("... see line 5 in \{.file ~/.Rprofile:5\}.") }\if{html}{\out{
}}\if{html}{\out{
#> ... see line 5 in ~/.Rprofile:5.                                                
}} } \subsection{Default handler}{ In RStudio \verb{file:} URLs open within RStudio. If you click on a file link outside of RStudio, typically the operating system is consulted for the application to open it. } \subsection{Without hyperlink support}{ One issue with using \code{.href} file files is that it does not look great if hyperlinks are not available. This will be improved in the future: \if{html}{\out{
}}\preformatted{local(\{ withr::local_options(cli.hyperlink = FALSE) prof <- path.expand("~/.Rprofile") cli_text("... edit your \{.href [R profile](file://\{prof\})\}.") \}) }\if{html}{\out{
}}\if{html}{\out{
#> ... edit your R profile (<file:///Users/gaborcsardi/.Rprofile>).                
}} } } \section{Links to the manual}{ \code{.fun} automatically creates links to the manual page of the function, provided the function name is in the \code{packagename::functionname} form: \if{html}{\out{
}}\preformatted{cli::cli_text("... see \{.fun stats::lm\} to learn more.") }\if{html}{\out{
}}\if{html}{\out{
#> ... see `stats::lm()` to learn more.                                            
}} \subsection{Link text}{ For a custom link text, use \code{.help} instead of \code{.fun}. \if{html}{\out{
}}\preformatted{cli::cli_text("... see \{.help [\{.fun lm\}](stats::lm)\} to learn more.") }\if{html}{\out{
}}\if{html}{\out{
#> ... see `lm()` to learn more.                                                   
}} } \subsection{Without hyperlink support}{ The same message without hyperlink support looks like this: \if{html}{\out{
}}\preformatted{local(\{ withr::local_options(cli.hyperlink = FALSE) cli::cli_text("... see \{.help [\{.fun lm\}](stats::lm)\} to learn more.") \}) }\if{html}{\out{
}}\if{html}{\out{
#> ... see `lm()` (`?stats::lm()`) to learn more.                                  
}} } \subsection{Topics}{ To link to a help topic that is not a function, use \code{.topic}: \if{html}{\out{
}}\preformatted{cli::cli_text("... the tibble options at \{.topic tibble::tibble_options\}.") }\if{html}{\out{
}}\if{html}{\out{
#> ... the tibble options at tibble::tibble_options.                               
}} \code{.topic} support link text. } \subsection{Vignettes}{ To link to a vignette, use \code{.vignette}: \if{html}{\out{
}}\preformatted{cli::cli_text("... see the \{.vignette tibble::types\} vignette.") }\if{html}{\out{
}}\if{html}{\out{
#> ... see the tibble::types vignette.                                             
}} } } \section{Click to run code}{ RStudio also supports a special link type that runs R code in the current R session upon clicking. You can create these links with \code{.run}: \if{html}{\out{
}}\preformatted{cli::cli_text("Run \{.run testthat::snapshot_review()\} to review") }\if{html}{\out{
}}\if{html}{\out{
#> Run testthat::snapshot_review() to review                                       
}} \subsection{Link text}{ Sometimes you want to show a slightly different expression in the link, than the one that is evaluated. E.g. the evaluated expression probably needs to qualify packages with \code{::}, but you might not want to show this: \if{html}{\out{
}}\preformatted{cli::cli_text( "Run \{.run [snapshot_review()](testthat::snapshot_review())\} to review" ) }\if{html}{\out{
}}\if{html}{\out{
#> Run snapshot_review() to review                                                 
}} } \subsection{Security considerations}{ To make \code{.run} hyperlinks more secure, RStudio will not run code \itemize{ \item that is not in the \code{pkg::fun(args)} form, \item if \code{args} contains \code{(}, \verb{)} or \verb{;}, \item if it calls a core package (base, stats, etc.), \item if it calls a package that is not loaded, and it is not one of testthat, devtools, usethis, rlang, pkgload, or pkgdown which are explicitly allowed. } When RStudio does not run a \code{.run} hyperlink, then it shows the code and the user can copy and paste it to the console, if they consider it safe to run. Note that depending on your version of RStudio, the behavior can change. } } cli/man/progress-variables.Rd0000644000176200001440000004140514752364056015715 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/progress-variables.R \name{progress-variables} \alias{progress-variables} \alias{cli__pb_bar} \alias{pb_bar} \alias{cli__pb_current} \alias{pb_current} \alias{cli__pb_current_bytes} \alias{pb_current_bytes} \alias{cli__pb_elapsed} \alias{pb_elapsed} \alias{cli__pb_elapsed_clock} \alias{pb_elapsed_clock} \alias{cli__pb_elapsed_raw} \alias{pb_elapsed_raw} \alias{cli__pb_eta} \alias{pb_eta} \alias{cli__pb_eta_raw} \alias{pb_eta_raw} \alias{cli__pb_eta_str} \alias{pb_eta_str} \alias{cli__pb_extra} \alias{pb_extra} \alias{cli__pb_id} \alias{pb_id} \alias{cli__pb_name} \alias{pb_name} \alias{cli__pb_percent} \alias{pb_percent} \alias{cli__pb_pid} \alias{pb_pid} \alias{cli__pb_rate} \alias{pb_rate} \alias{cli__pb_rate_raw} \alias{pb_rate_raw} \alias{cli__pb_rate_bytes} \alias{pb_rate_bytes} \alias{cli__pb_spin} \alias{pb_spin} \alias{cli__pb_status} \alias{pb_status} \alias{cli__pb_timestamp} \alias{pb_timestamp} \alias{cli__pb_total} \alias{pb_total} \alias{cli__pb_total_bytes} \alias{pb_total_bytes} \title{Progress bar variables} \description{ Progress bar variables } \details{ These variables can be used in cli progress bar format strings. They are calculated on demand. To use a variable, e.g. \code{pb_bar} in a package, you either need to to import \code{pb_bar} from cli, or use the qualified form in the format string: \code{cli::pb_bar}. Similarly, in R scripts, you can use \code{pb_bar} after \code{library(cli)}, or \code{cli::pb_bar} if you do not attach the cli package. \subsection{\code{pb_bar}}{ Creates a visual progress bar. If the number of total units is unknown, then it will return an empty string. \if{html}{\out{
}}\preformatted{cli_progress_bar( total = 100, format = "Fitting model \{cli::pb_bar\} \{cli::pb_percent\}" ) }\if{html}{\out{
}}\if{html}{\out{
#> Fitting model ███████████████████████████████   66%                             
}} } \subsection{\code{pb_current}}{ The number of current progress units. \if{html}{\out{
}}\preformatted{cli_progress_bar( total = 100, format = "\{cli::pb_spin\} Reading file \{cli::pb_current\}/\{cli::pb_total\}" ) }\if{html}{\out{
}}\if{html}{\out{
#> ⠙ Reading file 66/100                                                           
}} } \subsection{\code{pb_current_bytes}}{ The number of current progress units formatted as bytes. The output has a constant width of six characters. \if{html}{\out{
}}\preformatted{cli_progress_bar( format = "Got \{cli::pb_current_bytes\} in \{cli::pb_elapsed\}" ) }\if{html}{\out{
}}\if{html}{\out{
#> Got 524 kB in 5s                                                                
}} } \subsection{\code{pb_elapsed}}{ The elapsed time since the start of the progress bar. The time is measured since the progress bar was created with \code{\link[=cli_progress_bar]{cli_progress_bar()}} or similar. \if{html}{\out{
}}\preformatted{cli_progress_bar( total = 100, format = "\{cli::pb_bar\} \{cli::pb_percent\} [\{cli::pb_elapsed\}]" ) }\if{html}{\out{
}}\if{html}{\out{
#> ███████████████████████████████   66% [5s]                                      
}} } \subsection{\code{pb_elapsed_clock}}{ The elapsed time, in \verb{hh::mm::ss} format. \if{html}{\out{
}}\preformatted{cli_progress_bar( total = 100, format = "\{cli::pb_bar\} \{cli::pb_percent\} [\{cli::pb_elapsed_clock\}]" ) }\if{html}{\out{
}}\if{html}{\out{
#> ███████████████████████████████   66% [00:00:05]                                
}} } \subsection{\code{pb_elapsed_raw}}{ The number of seconds since the start of the progress bar. \if{html}{\out{
}}\preformatted{cli_progress_bar( total = 100, format = "\{cli::pb_bar\} \{cli::pb_percent\} [\{round(cli::pb_elapsed_raw)\}s]" ) }\if{html}{\out{
}}\if{html}{\out{
#> ███████████████████████████████   66% [5s]                                      
}} } \subsection{\code{pb_eta}}{ The estimated time until the end of the progress bar, in human readable form. \if{html}{\out{
}}\preformatted{cli_progress_bar( total = 100, format = "\{cli::pb_bar\} \{cli::pb_percent\} | ETA: \{cli::pb_eta\}" ) }\if{html}{\out{
}}\if{html}{\out{
#> ███████████████████████████████   66% | ETA:  3s                                
}} } \subsection{\code{pb_eta_raw}}{ The estimated time until the end of the progress bar, in seconds. This is useful if you want to adjust the default \code{pb_eta} display. \if{html}{\out{
}}\preformatted{cli_progress_bar( total = 100, format = "\{cli::pb_bar\} \{cli::pb_percent\} | ETA: \{round(cli::pb_eta_raw)\}s" ) }\if{html}{\out{
}}\if{html}{\out{
#> ███████████████████████████████   66% | ETA: 3s                                 
}} } \subsection{\code{pb_eta_str}}{ The estimated time until the end of the progress bar. It includes the \code{"ETA:"} prefix. It is only shown if the time can be estimated, otherwise it is the empty string. \if{html}{\out{
}}\preformatted{cli_progress_bar( total = 100, format = "\{cli::pb_bar\} \{cli::pb_percent\} | \{cli::pb_eta_str\}" ) }\if{html}{\out{
}}\if{html}{\out{
#> ███████████████████████████████   66% | ETA:  3s                                
}} } \subsection{\code{pb_extra}}{ \code{pb_extra} can be used to access extra data, see the \code{extra} argument of \code{cli_progress_bar()} and \code{cli_progress_update()}. \if{html}{\out{
}}\preformatted{cli_progress_bar( total = 100, extra = list(user = whoami::username()), format = "Cleaning cache for user '\{cli::pb_extra$user\}': \{cli::pb_current_bytes\}" ) }\if{html}{\out{
}}\if{html}{\out{
#> Cleaning cache for user 'gaborcsardi': 161 MB                                   
}} } \subsection{\code{pb_id}}{ The id of the progress bar. The id has the format \verb{cli--} where \verb{} is the process id, and \verb{} is an integer counter that is incremented every time cli needs a new unique id. This is useful for debugging progress bars. \if{html}{\out{
}}\preformatted{cli_progress_bar( format = "Progress bar '\{cli::pb_id\}' is at \{cli::pb_current\}" ) }\if{html}{\out{
}}\if{html}{\out{
#> Progress bar 'cli-82040-1814' is at 64                                          
}} } \subsection{\code{pb_name}}{ The name of the progress bar. This is supplied by the developer, and it is by default the empty string. A space character is added to non-empty names. \if{html}{\out{
}}\preformatted{cli_progress_bar( name = "Loading training data", total = 100, format = "\{cli::pb_name\} \{cli::pb_bar\} \{cli::pb_percent\}" ) }\if{html}{\out{
}}\if{html}{\out{
#> Loading training data  ███████████████████████████████   66%                    
}} } \subsection{\code{pb_percent}}{ The percentage of the progress bar, always formatted in three characters plus the percentage sign. If the total number of units is unknown, then it is \code{" NA\%"}. \if{html}{\out{
}}\preformatted{cli_progress_bar( total = 100, format = "\{cli::pb_bar\} \{cli::pb_percent\}" ) }\if{html}{\out{
}}\if{html}{\out{
#> ███████████████████████████████   66%                                           
}} } \subsection{\code{pb_pid}}{ The integer process id of the progress bar. This is useful if you are aggregating logging output or progress results from multiple processes. } \subsection{\code{pb_rate}}{ The progress rate, in number of units per second, formatted in a string. \if{html}{\out{
}}\preformatted{cli_progress_bar( total = 156, format = "Reading input files \{pb_current\}/\{pb_total\} [\{pb_rate\}]" ) }\if{html}{\out{
}}\if{html}{\out{
#> Reading input files 68/156 [14/s]                                               
}} } \subsection{\code{pb_rate_raw}}{ The raw progress rate, in number of units per second. \if{html}{\out{
}}\preformatted{cli_progress_bar( total = 156, format = "Reading input files \{pb_current\}/\{pb_total\} [\{round(pb_rate_raw)\}/s]" ) }\if{html}{\out{
}}\if{html}{\out{
#> Reading input files 68/156 [14/s]                                               
}} } \subsection{\code{pb_rate_bytes}}{ The progress rate, formatted as bytes per second, in human readable form. \if{html}{\out{
}}\preformatted{cli_progress_bar( total = 256 * 1024 * 1014, format = paste0( "Reading data \{pb_current_bytes\}/\{pb_total_bytes\} ", "[\{ansi_trimws(pb_rate_bytes)\}]" ) }\if{html}{\out{
}}\if{html}{\out{
#> Reading data  70 MB/266 MB [14 MB/s]                                            
}} } \subsection{\code{pb_spin}}{ A spinner. The default spinner is selected via a \code{\link[=get_spinner]{get_spinner()}} call. \if{html}{\out{
}}\preformatted{cli_progress_bar( total = 100, format = "\{cli::pb_spin\} Reading file \{cli::pb_current\}/\{cli::pb_total\}" ) }\if{html}{\out{
}}\if{html}{\out{
#> ⠙ Reading file 66/100                                                           
}} } \subsection{\code{pb_status}}{ The status string of the progress bar. By default this is an empty string, but it is possible to set it in \code{\link[=cli_progress_bar]{cli_progress_bar()}} and `cli_progress_update()]. \if{html}{\out{
}}\preformatted{cli_progress_bar(status = "Connecting...") }\if{html}{\out{
}}\if{html}{\out{
#> ⠙ Connecting... 0 done (0/s) | 1s                                               
}} } \subsection{\code{pb_timestamp}}{ A time stamp for the current time in ISO 8601 format. \if{html}{\out{
}}\preformatted{cli_progress_bar( "Loading training data files", format = "\{pb_timestamp\} \{pb_current\} (\{pb_rate\})" }\if{html}{\out{
}}\if{html}{\out{
#> 2022-09-07T11:27:50+00:00 125 (25/s)                                            
}} } \subsection{\code{pb_total}}{ The total number of progress units, or \code{NA} if the number of units is unknown. \if{html}{\out{
}}\preformatted{cli_progress_bar( total = 100, format = "\{cli::pb_spin\} Reading file \{cli::pb_current\}/\{cli::pb_total\}" ) }\if{html}{\out{
}}\if{html}{\out{
#> ⠙ Reading file 66/100                                                           
}} } \subsection{\code{pb_total_bytes}}{ The total number of progress units, formatted as bytes, in a human readable format. \if{html}{\out{
}}\preformatted{cli_progress_bar( total = 256 * 1024 * 1014, format = paste0( "Reading data \{pb_current_bytes\}/\{pb_total_bytes\} ", "[\{ansi_trimws(pb_rate_bytes)\}]" ) }\if{html}{\out{
}}\if{html}{\out{
#> Reading data  70 MB/266 MB [14 MB/s]                                            
}} } } \seealso{ Other progress bar functions: \code{\link{cli_progress_along}()}, \code{\link{cli_progress_bar}()}, \code{\link{cli_progress_builtin_handlers}()}, \code{\link{cli_progress_message}()}, \code{\link{cli_progress_num}()}, \code{\link{cli_progress_output}()}, \code{\link{cli_progress_step}()}, \code{\link{cli_progress_styles}()} } \concept{progress bar functions} cli/man/ansi_html.Rd0000644000176200001440000000250114557444176014060 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/ansiex.R \name{ansi_html} \alias{ansi_html} \title{Convert ANSI styled text to HTML} \usage{ ansi_html(x, escape_reserved = TRUE, csi = c("drop", "keep")) } \arguments{ \item{x}{Input character vector.} \item{escape_reserved}{Whether to escape characters that are reserved in HTML (\code{&}, \code{<} and \code{>}).} \item{csi}{What to do with non-SGR ANSI sequences, either \code{"keep"}, or \code{"drop"} them.} } \value{ Character vector of HTML. } \description{ Convert ANSI styled text to HTML } \examples{ \dontshow{if (cli:::has_packages(c("htmltools", "withr"))) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} ## Syntax highlight the source code of an R function with ANSI tags, ## and export it to a HTML file. code <- withr::with_options( list(ansi.num_colors = 256), code_highlight(format(ansi_html)) ) hcode <- paste(ansi_html(code), collapse = "\n") css <- paste(format(ansi_html_style()), collapse= "\n") page <- htmltools::tagList( htmltools::tags$head(htmltools::tags$style(css)), htmltools::tags$pre(htmltools::HTML(hcode)) ) if (interactive()) htmltools::html_print(page) \dontshow{\}) # examplesIf} } \seealso{ Other ANSI to HTML conversion: \code{\link{ansi_html_style}()} } \concept{ANSI to HTML conversion} cli/man/cli-config.Rd0000644000176200001440000003233514752364056014117 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/docs.R \name{cli-config} \alias{cli-config} \title{cli environment variables and options} \description{ cli environment variables and options } \section{User facing configuration}{ These are environment variables and options that uses may set, to modify the behavior of cli. \subsection{User facing environment variables}{ \subsection{\code{R_CLI_HYPERLINK_MODE}}{ Set to \code{posix} to force generating POSIX compatible ANSI hyperlinks. If not set, then RStudio compatible links are generated. This is a temporary crutch until RStudio handles POSIX hyperlinks correctly, and after that it will be removed. } \subsection{\code{NO_COLOR}}{ Set to a nonempty value to turn off ANSI colors. See \code{\link[=num_ansi_colors]{num_ansi_colors()}}. } \subsection{\code{ESS_BACKGROUND_MODE}}{ Set this environment variable to \code{light} or \code{dark} to indicate dark mode in Emacs. Once https://github.com/emacs-ess/ESS/pull/1178 is merged, ESS will set this automatically. } \subsection{\code{R_CLI_DYNAMIC}}{ Set to \code{true}, \code{TRUE} or \code{True} to assume a dynamic terminal, that supports \verb{\\r}. Set to anything else to assume a non-dynamic terminal. See \code{\link[=is_dynamic_tty]{is_dynamic_tty()}}. } \subsection{\code{R_CLI_NUM_COLORS}}{ Set to a positive integer to assume a given number of colors. See \code{\link[=num_ansi_colors]{num_ansi_colors()}}. } \subsection{\code{R_CLI_HYPERLINKS}}{ Set to \code{true}, \code{TRUE} or \code{True} to tell cli that the terminal supports ANSI hyperlinks. Set to anything else to assume no hyperlink support. See \code{\link[=style_hyperlink]{style_hyperlink()}}. } } \subsection{User facing options}{ \subsection{\code{cli.ansi}}{ Set to \code{true}, \code{TRUE} or \code{True} to assume a terminal that supports ANSI control sequences. Set to anything else to assume a non-ANSI terminal. See \code{\link[=is_ansi_tty]{is_ansi_tty()}}. } \subsection{\code{cli.condition_unicode_bullets}}{ \code{TRUE} or \code{FALSE} to force turn on or off the Unicode symbols when printing conditions. E.g. in \code{format_error()}, \code{format_warning()}, \code{format_message()} and also in \code{cli_abort()}, \code{cli_warn()} and \code{cli_inform()}. } \subsection{\code{cli.condition_width}}{ Integer scalar (or \code{Inf}) to set the console width when cli is formatting errors, warnings or messages in \code{format_error()}, \code{format_warning()} and \code{format_message()}. When formatting conditions this option takes precedence over \code{cli.width}. } \subsection{\code{cli.default_handler}}{ General handler function for all cli conditions. See \url{https://cli.r-lib.org/articles/semantic-cli.html#cli-messages-1} } \subsection{\code{cli.default_num_colors}}{ Default number of ANSI colors. This value is used if the number of colors is not already set by \itemize{ \item the \code{cli.num_colors} option, \item the \code{R_CLI_NUM_COLORS} environment variable, \item the \code{crayon.enabled} and \code{crayon.colors} options, \item the \code{NO_COLOR} environment variable, \item the \code{knitr.in.progress} option, \item a \code{sink()} call for the stream. } You can also use this option if color support is detected correctly, but you want to adjust the number of colors. E.g. \itemize{ \item if \code{crayon.enabled} is \code{TRUE}, but \code{crayon.colors} is not, \item in Emacs on Windows, \item in terminals. } See \code{\link[=num_ansi_colors]{num_ansi_colors()}}. See also the \code{cli.num_colors} option. } \subsection{\code{cli.dynamic}}{ Set to \code{TRUE} to assume a dynamic terminal, that supports \verb{\\r}. Set to anything else to assume a non-dynamic terminal. See \code{\link[=is_dynamic_tty]{is_dynamic_tty()}}. } \subsection{\code{cli.hide_cursor}}{ Whether the cli status bar should try to hide the cursor on terminals. Set the \code{FALSE} if the hidden cursor causes issues. } \subsection{\code{cli.hyperlink}}{ Set to \code{true}, \code{TRUE} or \code{True} to tell cli that the terminal supports ANSI hyperlinks. Set to anything else to assume no hyperlink support. See \code{\link[=style_hyperlink]{style_hyperlink()}}. } \subsection{\code{cli.ignore_unknown_rstudio_theme}}{ Set to \code{TRUE} to omit a warning for an unknown RStudio theme in \code{code_highlight()}. } \subsection{\code{cli.num_colors}}{ Number of ANSI colors. See \code{\link[=num_ansi_colors]{num_ansi_colors()}}. See also the \code{cli.default_num_colors} option. } \subsection{\code{cli.message_class}}{ Character vector of classes to add to cli's conditions. } \subsection{\code{cli.progress_bar_style}}{ Progress bar style. See \code{\link[=cli_progress_styles]{cli_progress_styles()}}. } \subsection{\code{cli.progress_bar_style_ascii}}{ Progress bar style on ASCII consoles. See \code{\link[=cli_progress_styles]{cli_progress_styles()}}. } \subsection{\code{cli.progress_bar_style_unicode}}{ Progress bar style on Unicode (UTF-8) consoles; See \code{\link[=cli_progress_styles]{cli_progress_styles()}}. } \subsection{\code{cli.progress_clear}}{ Whether to clear terminated progress bar from the screen on dynamic terminals. See \code{\link[=cli_progress_bar]{cli_progress_bar()}}. } \subsection{\code{cli.progress_demo_live}}{ Whether \code{cli_progress_demo()} should show a live demo, or just record the progress bar frames. } \subsection{\code{cli.progress_format_download}}{ Default format string for \code{download} progress bars. } \subsection{\code{cli.progress_format_download_nototal}}{ Default format string for \code{download} progress bars with unknown totals. } \subsection{\code{cli.progress_format_iterator}}{ Default format string for \code{iterator} progress bars. } \subsection{\code{cli.progress_format_iterator_nototal}}{ Default format string for \code{iterator} progress bars with unknown total number of progress units. } \subsection{\code{cli.progress_format_tasks}}{ Default format string for \code{tasks} progress bars. } \subsection{\code{cli.progress_format_tasks_nototal}}{ Default format string for \code{tasks} progress bars with unknown totals. } \subsection{\code{cli.progress_handlers}}{ Progress handlers to try. See \code{\link[=cli_progress_builtin_handlers]{cli_progress_builtin_handlers()}}. } \subsection{\code{cli.progress_handlers_force}}{ Progress handlers that will always be used, even if another handler was already selected. See \code{\link[=cli_progress_builtin_handlers]{cli_progress_builtin_handlers()}}. } \subsection{\code{cli.progress_handlers_only}}{ Progress handlers to force, ignoring handlers set in \code{cli.progress_handlers} and \code{cli.progress_handlers_force}. See \code{\link[=cli_progress_builtin_handlers]{cli_progress_builtin_handlers()}}. } \subsection{\code{cli.progress_say_args}}{ Command line arguments for the \code{say} progress handlers. See \code{\link[=cli_progress_builtin_handlers]{cli_progress_builtin_handlers()}}. } \subsection{\code{cli.progress_say_command}}{ External command to use in the \code{say} progress handler. See \code{\link[=cli_progress_builtin_handlers]{cli_progress_builtin_handlers()}}. } \subsection{\code{cli.progress_say_frequency}}{ Minimum delay between \code{say} calls in the \code{say} progress handler. \code{say} ignores very frequent updates, to keep the speech comprehensible. See \code{\link[=cli_progress_builtin_handlers]{cli_progress_builtin_handlers()}}. } \subsection{\code{cli.progress_show_after}}{ Delay before showing a progress bar, in seconds. Progress bars that finish before this delay are not shown at all. cli also shows progress bars that have more than 50\% to go after half of this delay has passed. } \subsection{\code{cli.spinner}}{ Default spinner to use, see \code{\link[=get_spinner]{get_spinner()}}. } \subsection{\code{cli.spinner_ascii}}{ Default spinner to use on ASCII terminals, see \code{\link[=get_spinner]{get_spinner()}}. } \subsection{\code{cli.spinner_unicode}}{ Default spinner to use on Unicode terminals, see \code{\link[=get_spinner]{get_spinner()}}. } \subsection{\code{cli.theme}}{ Default cli theme, in addition to the built-in theme. This option in intended for the package developers. See \link{themes} and \code{\link[=start_app]{start_app()}}. } \subsection{\code{cli.theme_dark}}{ Whether cli should assume a dark theme for the builtin theme. See \code{\link[=builtin_theme]{builtin_theme()}}. } \subsection{\code{cli.unicode}}{ Whether to assume a Unicode terminal. If not set, then it is auto-detected. See \code{\link[=is_utf8_output]{is_utf8_output()}}. } \subsection{\code{cli.user_theme}}{ cli user theme. This option is intended for end users. See \link{themes}. } \subsection{\code{cli.warn_inline_newlines}}{ Whether to emit a warning when cli replaces newline characters with spaces within a \code{{.class }} inline style. Defaults to \code{FALSE}. } \subsection{\code{cli.width}}{ Terminal width to assume. If not set, then it is auto-detected. See \code{\link[=console_width]{console_width()}}. } \subsection{\code{rlib_interactive}}{ Whether to assume an interactive R session. If not set, then it is auto-detected. } \subsection{\code{width}}{ Terminal width. This is used on some platforms, if \code{cli.width} is not set. } } } \section{Internal configuration}{ These are environment variables and options are for cli developers, users should not rely on them as they may change between cli releases. \subsection{Internal environment variables}{ \subsection{\code{ASCIICAST}}{ Used to detect an asciicast sub-process in RStudio. } \subsection{\code{ANSICON}}{ Used to detect ANSICON when detecting the number of ANSI colors. } \subsection{\code{CI}}{ Used to detect if the code is running on a CI. If yes, we avoid ANSI hyperlinks. } \subsection{\code{CLI_DEBUG_BAD_END}}{ Whether to warn about \code{cli_end()} calls when there is no container to close. } \subsection{\code{CLI_NO_BUILTIN_THEME}}{ Set it to \code{true} to omit the builtin theme. } \subsection{\code{CLI_SPEED_TIME}}{ Can be used to speed up cli's timer. It is a factor, e.g. setting it to 2 makes cli's time go twice as fast. } \subsection{\code{CLI_TICK_TIME}}{ How often the cli timer should alert, in milliseconds. } \subsection{\code{CMDER_ROOT}}{ Used to detect cmder when detecting the number of ANSI colors. } \subsection{\code{COLORTERM}}{ Used when detecting ANSI color support. } \subsection{\code{ConEmuANSI}}{ Used to detect ConEmu when detecting the number of ANSI colors. } \subsection{\code{EMACS}}{ Used to detect Emacs. } \subsection{\code{INSIDE_EMACS}}{ Used to detect Emacs. } \subsection{\code{NOT_CRAN}}{ Set to \code{true} to run tests / examples / checks, that do not run on CRAN. } \subsection{\verb{_R_CHECK_PACKAGE_NAME_}}{ Used to detect \verb{R CMD check}. } \subsection{\code{R_BROWSER}}{ Used to detect the RStudio build pane. } \subsection{\code{R_GUI_APP_VERSION}}{ Used to detect R.app on macOS, to decide if the console has ANSI control sequences. } \subsection{\code{R_PACKAGE_DIR}}{ Used to detect if the code is running under \verb{R CMD INSTALL}. } \subsection{\code{R_PDFVIEWER}}{ Used to detect the RStudio build pane. } \subsection{\code{R_PROGRESS_NO_EXAMPLES}}{ Set to \code{true} to avoid running examples, outside of \verb{R CMD check}. } \subsection{\code{RSTUDIO}}{ Used to detect RStudio, in various functions. } \subsection{\code{RSTUDIO_CONSOLE_COLOR}}{ Used to detect the number of colors in RStudio. See \code{\link[=num_ansi_colors]{num_ansi_colors()}}. } \subsection{\code{RSTUDIO_CONSOLE_WIDTH}}{ Used to auto-detect console width in RStudio. } \subsection{\code{RSTUDIO_TERM}}{ Used to detect the RStudio build pane. } \subsection{\code{TEAMCITY_VERSION}}{ Used to detect the TeamCity CI, to turn off ANSI hyperlinks. } \subsection{\code{TERM}}{ Used to detect if the console has ANSI control sequences, in a terminal. } \subsection{\code{TERM_PROGRAM}}{ Used to detect iTerm for the dark theme detection and the ANSI hyperlink support detection. } \subsection{\code{TERM_PROGRAM_VERSION}}{ Used to detect a suitable iTerm version for ANSI hyperlink support. } \subsection{\code{TESTTHAT}}{ Used to detect running in testthat tests. } \subsection{\code{VTE_VERSION}}{ Used to detect a suitable VTE version for ANSI hyperlinks. } } \subsection{Internal options}{ \subsection{\code{cli__pb}}{ This option is set to the progress bar that is being updated, when interpolating the format string. } \subsection{\code{cli.record}}{ Internal option to mark the state that cli is recording messages. } \subsection{\code{crayon.colors}}{ Deprecated option for the number of ANSI colors, that is still supported by cli, when the new options are not set. See \code{\link[=num_ansi_colors]{num_ansi_colors()}}. } \subsection{\code{crayon.enabled}}{ Deprecated option to turn ANSI colors on/off. This is still supported by cli when the new options are not set. See \code{\link[=num_ansi_colors]{num_ansi_colors()}}. } \subsection{\code{crayon.hyperlink}}{ Whether to assume ANSI hyperlink support. See \code{\link[=ansi_has_hyperlink_support]{ansi_has_hyperlink_support()}}. } \subsection{\code{knitr.in.progress}}{ Used to detect knitr when detecting interactive sessions and ANSI color support. } \subsection{\code{rstudio.notebook.executing}}{ Used to detect knitr when detecting interactive sessions. } } } cli/man/cli_div.Rd0000644000176200001440000000463414557444176013524 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/cli.R \name{cli_div} \alias{cli_div} \title{Generic CLI container} \usage{ cli_div( id = NULL, class = NULL, theme = NULL, .auto_close = TRUE, .envir = parent.frame() ) } \arguments{ \item{id}{Element id, a string. If \code{NULL}, then a new id is generated and returned.} \item{class}{Class name, sting. Can be used in themes.} \item{theme}{A custom theme for the container. See \link{themes}.} \item{.auto_close}{Whether to close the container, when the calling function finishes (or \code{.envir} is removed, if specified).} \item{.envir}{Environment to evaluate the glue expressions in. It is also used to auto-close the container if \code{.auto_close} is \code{TRUE}.} } \value{ The id of the new container element, invisibly. } \description{ See \link{containers}. A \code{cli_div} container is special, because it may add new themes, that are valid within the container. } \details{ \subsection{Custom themes}{ \if{html}{\out{
}}\preformatted{d <- cli_div(theme = list(h1 = list(color = "cyan", "font-weight" = "bold"))) cli_h1("Custom title") cli_end(d) }\if{html}{\out{
}}\if{html}{\out{
#>                                                                                 
#> Custom title                                                                    
}} } \subsection{Auto-closing}{ By default a \code{cli_div()} is closed automatically when the calling frame exits. \if{html}{\out{
}}\preformatted{div <- function() \{ cli_div(class = "tmp", theme = list(.tmp = list(color = "yellow"))) cli_text("This is yellow") \} div() cli_text("This is not yellow any more") }\if{html}{\out{
}}\if{html}{\out{
#> This is yellow                                                                  
#> This is not yellow any more                                                     
}} } } cli/man/faq.Rd0000644000176200001440000000562014557444176012656 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/docs.R \name{faq} \alias{faq} \title{Frequently Asked Questions} \description{ Frequently Asked Questions } \details{ \subsection{My platform supports ANSI colors, why does cli not use them?}{ It is probably a mistake in the ANSI support detection algorithm. Please open an issue at \url{https://github.com/r-lib/cli/issues} and do not forget to tell us the details of your platform and terminal or GUI. } \subsection{How do I turn off ANSI colors and styles?}{ Set the \code{NO_COLOR} environment variable to a non-empty value. You can do this in your \code{.Renviron} file (use \code{usethis::edit_r_environ()}). If you want to do this for testthat tests, then consider using the 3rd edition on testthat, which does turn off ANSI styling automatically inside \code{test_that()}. } \subsection{cli does not show the output before \code{file.choose()}}{ Try calling \code{flush.console()} to flush the console, before \code{file.choose()}. If flushing does not work and you are in RStudio, then it is probably this RStudio bug: \url{https://github.com/rstudio/rstudio/issues/8040} See more details at \url{https://github.com/r-lib/cli/issues/151} } \subsection{Why are heading separators wider than my screen in RStudio?}{ The display width of some Unicode characters ambiguous in the Unicode standard. Some software treats them as narrow (one column on the screen), other as wide (two columns). In some terminal emulators (for example iTerm2), you can configure the preferred behavior. Unfortunately the box drawing characters that cli uses also have ambiguous width. In RStudio the behavior depends on the font. In particular, Consolas, Courier and Inconsolata treats them as wide characters, so cli output will not look great with these. Some good, modern fonts that look good include Menlo, Fira Code and Source Code Pro. If you do not want to change your font, you can also turn off Unicode output, by setting the \code{cli.unicode} option: \if{html}{\out{
}}\preformatted{options(cli.unicode = FALSE) }\if{html}{\out{
}} A related issue: \url{https://github.com/r-lib/cli/issues/320} } \subsection{Is there a suggested font to use with cli?}{ In modern terminals, cli output usually looks good. If you see too wide heading separators in RStudio, then see the previous question: Why are heading separators wider than my screen in RStudio?. If some output is garbled, then cli probably misdetected Unicode support for your terminal or font. You can try choosing a different font. In our experience output looks good with Menlo, Fira Code and Source Code Pro. Alternatively you can turn off Unicode output: \if{html}{\out{
}}\preformatted{options(cli.unicode = FALSE) }\if{html}{\out{
}} If you think this is our fault, then please also file an issue at \url{https://github.com/r-lib/cli/issues} } } cli/man/tree.Rd0000644000176200001440000004016114557444176013045 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/tree.R \name{tree} \alias{tree} \title{Draw a tree} \usage{ tree( data, root = data[[1]][[1]], style = NULL, width = console_width(), trim = FALSE ) } \arguments{ \item{data}{Data frame that contains the tree structure. The first column is an id, and the second column is a list column, that contains the ids of the child nodes. The optional third column may contain the text to print to annotate the node.} \item{root}{The name of the root node.} \item{style}{Optional box style list.} \item{width}{Maximum width of the output. Defaults to the \code{width} option, see \code{\link[base:options]{base::options()}}.} \item{trim}{Whether to avoid traversing the same nodes multiple times. If \code{TRUE} and \code{data} has a \code{trimmed} column, then that is used for printing repeated nodes.} } \value{ Character vector, the lines of the tree drawing. } \description{ Draw a tree using box drawing characters. Unicode characters are used if available. (Set the \code{cli.unicode} option if auto-detection fails.) } \details{ A node might appear multiple times in the tree, or might not appear at all. \if{html}{\out{
}}\preformatted{data <- data.frame( stringsAsFactors = FALSE, package = c("processx", "backports", "assertthat", "Matrix", "magrittr", "rprojroot", "clisymbols", "prettyunits", "withr", "desc", "igraph", "R6", "crayon", "debugme", "digest", "irlba", "rcmdcheck", "callr", "pkgconfig", "lattice"), dependencies = I(list( c("assertthat", "crayon", "debugme", "R6"), character(0), character(0), "lattice", character(0), "backports", character(0), c("magrittr", "assertthat"), character(0), c("assertthat", "R6", "crayon", "rprojroot"), c("irlba", "magrittr", "Matrix", "pkgconfig"), character(0), character(0), "crayon", character(0), "Matrix", c("callr", "clisymbols", "crayon", "desc", "digest", "prettyunits", "R6", "rprojroot", "withr"), c("processx", "R6"), character(0), character(0) )) ) tree(data) }\if{html}{\out{
}}\if{html}{\out{
#> processx                                                                        
#> ├─assertthat                                                                    
#> ├─crayon                                                                        
#> ├─debugme                                                                       
#> │ └─crayon                                                                      
#> └─R6                                                                            
}} \if{html}{\out{
}}\preformatted{tree(data, root = "rcmdcheck") }\if{html}{\out{
}}\if{html}{\out{
#> rcmdcheck                                                                       
#> ├─callr                                                                         
#> │ ├─processx                                                                    
#> │ │ ├─assertthat                                                                
#> │ │ ├─crayon                                                                    
#> │ │ ├─debugme                                                                   
#> │ │ │ └─crayon                                                                  
#> │ │ └─R6                                                                        
#> │ └─R6                                                                          
#> ├─clisymbols                                                                    
#> ├─crayon                                                                        
#> ├─desc                                                                          
#> │ ├─assertthat                                                                  
#> │ ├─R6                                                                          
#> │ ├─crayon                                                                      
#> │ └─rprojroot                                                                   
#> │   └─backports                                                                 
#> ├─digest                                                                        
#> ├─prettyunits                                                                   
#> │ ├─magrittr                                                                    
#> │ └─assertthat                                                                  
#> ├─R6                                                                            
#> ├─rprojroot                                                                     
#> │ └─backports                                                                   
#> └─withr                                                                         
}} \subsection{Colored nodes}{ \if{html}{\out{
}}\preformatted{data$label <- paste(data$package, style_dim(paste0("(", c("2.0.0.1", "1.1.1", "0.2.0", "1.2-11", "1.5", "1.2", "1.2.0", "1.0.2", "2.0.0", "1.1.1.9000", "1.1.2", "2.2.2", "1.3.4", "1.0.2", "0.6.12", "2.2.1", "1.2.1.9002", "1.0.0.9000", "2.0.1", "0.20-35"), ")")) ) roots <- ! data$package \%in\% unlist(data$dependencies) data$label[roots] <- col_cyan(style_italic(data$label[roots])) tree(data, root = "rcmdcheck") }\if{html}{\out{
}}\if{html}{\out{
#> rcmdcheck (1.2.1.9002)                                                          
#> ├─callr (1.0.0.9000)                                                            
#> │ ├─processx (2.0.0.1)                                                          
#> │ │ ├─assertthat (0.2.0)                                                        
#> │ │ ├─crayon (1.3.4)                                                            
#> │ │ ├─debugme (1.0.2)                                                           
#> │ │ │ └─crayon (1.3.4)                                                          
#> │ │ └─R6 (2.2.2)                                                                
#> │ └─R6 (2.2.2)                                                                  
#> ├─clisymbols (1.2.0)                                                            
#> ├─crayon (1.3.4)                                                                
#> ├─desc (1.1.1.9000)                                                             
#> │ ├─assertthat (0.2.0)                                                          
#> │ ├─R6 (2.2.2)                                                                  
#> │ ├─crayon (1.3.4)                                                              
#> │ └─rprojroot (1.2)                                                             
#> │   └─backports (1.1.1)                                                         
#> ├─digest (0.6.12)                                                               
#> ├─prettyunits (1.0.2)                                                           
#> │ ├─magrittr (1.5)                                                              
#> │ └─assertthat (0.2.0)                                                          
#> ├─R6 (2.2.2)                                                                    
#> ├─rprojroot (1.2)                                                               
#> │ └─backports (1.1.1)                                                           
#> └─withr (2.0.0)                                                                 
}} } \subsection{Trimming}{ \if{html}{\out{
}}\preformatted{pkgdeps <- list( "dplyr@0.8.3" = c("assertthat@0.2.1", "glue@1.3.1", "magrittr@1.5", "R6@2.4.0", "Rcpp@1.0.2", "rlang@0.4.0", "tibble@2.1.3", "tidyselect@0.2.5"), "assertthat@0.2.1" = character(), "glue@1.3.1" = character(), "magrittr@1.5" = character(), "pkgconfig@2.0.3" = character(), "R6@2.4.0" = character(), "Rcpp@1.0.2" = character(), "rlang@0.4.0" = character(), "tibble@2.1.3" = c("cli@1.1.0", "crayon@1.3.4", "fansi@0.4.0", "pillar@1.4.2", "pkgconfig@2.0.3", "rlang@0.4.0"), "cli@1.1.0" = c("assertthat@0.2.1", "crayon@1.3.4"), "crayon@1.3.4" = character(), "fansi@0.4.0" = character(), "pillar@1.4.2" = c("cli@1.1.0", "crayon@1.3.4", "fansi@0.4.0", "rlang@0.4.0", "utf8@1.1.4", "vctrs@0.2.0"), "utf8@1.1.4" = character(), "vctrs@0.2.0" = c("backports@1.1.5", "ellipsis@0.3.0", "digest@0.6.21", "glue@1.3.1", "rlang@0.4.0", "zeallot@0.1.0"), "backports@1.1.5" = character(), "ellipsis@0.3.0" = c("rlang@0.4.0"), "digest@0.6.21" = character(), "glue@1.3.1" = character(), "zeallot@0.1.0" = character(), "tidyselect@0.2.5" = c("glue@1.3.1", "purrr@1.3.1", "rlang@0.4.0", "Rcpp@1.0.2"), "purrr@0.3.3" = c("magrittr@1.5", "rlang@0.4.0") ) pkgs <- data.frame( stringsAsFactors = FALSE, name = names(pkgdeps), deps = I(unname(pkgdeps)) ) tree(pkgs, trim = TRUE) }\if{html}{\out{
}}\if{html}{\out{
#> dplyr@0.8.3                                                                     
#> ├─assertthat@0.2.1                                                              
#> ├─glue@1.3.1                                                                    
#> ├─magrittr@1.5                                                                  
#> ├─R6@2.4.0                                                                      
#> ├─Rcpp@1.0.2                                                                    
#> ├─rlang@0.4.0                                                                   
#> ├─tibble@2.1.3                                                                  
#> │ ├─cli@1.1.0                                                                   
#> │ │ ├─assertthat@0.2.1                                                          
#> │ │ └─crayon@1.3.4                                                              
#> │ ├─crayon@1.3.4                                                                
#> │ ├─fansi@0.4.0                                                                 
#> │ ├─pillar@1.4.2                                                                
#> │ │ ├─cli@1.1.0                                                                 
#> │ │ ├─crayon@1.3.4                                                              
#> │ │ ├─fansi@0.4.0                                                               
#> │ │ ├─rlang@0.4.0                                                               
#> │ │ ├─utf8@1.1.4                                                                
#> │ │ └─vctrs@0.2.0                                                               
#> │ │   ├─backports@1.1.5                                                         
#> │ │   ├─ellipsis@0.3.0                                                          
#> │ │   │ └─rlang@0.4.0                                                           
#> │ │   ├─digest@0.6.21                                                           
#> │ │   ├─glue@1.3.1                                                              
#> │ │   ├─rlang@0.4.0                                                             
#> │ │   └─zeallot@0.1.0                                                           
#> │ ├─pkgconfig@2.0.3                                                             
#> │ └─rlang@0.4.0                                                                 
#> └─tidyselect@0.2.5                                                              
#>   ├─glue@1.3.1                                                                  
#>   ├─rlang@0.4.0                                                                 
#>   └─Rcpp@1.0.2                                                                  
}} \if{html}{\out{
}}\preformatted{# Mark the trimmed nodes pkgs$label <- pkgs$name pkgs$trimmed <- paste(pkgs$name, " (trimmed)") tree(pkgs, trim = TRUE) }\if{html}{\out{
}}\if{html}{\out{
#> dplyr@0.8.3                                                                     
#> ├─assertthat@0.2.1                                                              
#> ├─glue@1.3.1                                                                    
#> ├─magrittr@1.5                                                                  
#> ├─R6@2.4.0                                                                      
#> ├─Rcpp@1.0.2                                                                    
#> ├─rlang@0.4.0                                                                   
#> ├─tibble@2.1.3                                                                  
#> │ ├─cli@1.1.0                                                                   
#> │ │ ├─assertthat@0.2.1  (trimmed)                                               
#> │ │ └─crayon@1.3.4                                                              
#> │ ├─crayon@1.3.4  (trimmed)                                                     
#> │ ├─fansi@0.4.0                                                                 
#> │ ├─pillar@1.4.2                                                                
#> │ │ ├─cli@1.1.0  (trimmed)                                                      
#> │ │ ├─crayon@1.3.4  (trimmed)                                                   
#> │ │ ├─fansi@0.4.0  (trimmed)                                                    
#> │ │ ├─rlang@0.4.0  (trimmed)                                                    
#> │ │ ├─utf8@1.1.4                                                                
#> │ │ └─vctrs@0.2.0                                                               
#> │ │   ├─backports@1.1.5                                                         
#> │ │   ├─ellipsis@0.3.0                                                          
#> │ │   │ └─rlang@0.4.0  (trimmed)                                                
#> │ │   ├─digest@0.6.21                                                           
#> │ │   ├─glue@1.3.1  (trimmed)                                                   
#> │ │   ├─rlang@0.4.0  (trimmed)                                                  
#> │ │   └─zeallot@0.1.0                                                           
#> │ ├─pkgconfig@2.0.3                                                             
#> │ └─rlang@0.4.0  (trimmed)                                                      
#> └─tidyselect@0.2.5                                                              
#>   ├─glue@1.3.1  (trimmed)                                                       
#>   ├─rlang@0.4.0  (trimmed)                                                      
#>   └─Rcpp@1.0.2  (trimmed)                                                       
}} } } cli/man/start_app.Rd0000644000176200001440000000233714557444176014106 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/app.R \name{start_app} \alias{start_app} \alias{stop_app} \alias{default_app} \title{Start, stop, query the default cli application} \usage{ start_app( theme = getOption("cli.theme"), output = c("auto", "message", "stdout", "stderr"), .auto_close = TRUE, .envir = parent.frame() ) stop_app(app = NULL) default_app() } \arguments{ \item{theme}{Theme to use.} \item{output}{How to print the output.} \item{.auto_close}{Whether to stop the app, when the calling frame is destroyed.} \item{.envir}{The environment to use, instead of the calling frame, to trigger the stop of the app.} \item{app}{App to stop. If \code{NULL}, the current default app is stopped. Otherwise we find the supplied app in the app stack, and remote it, together with all the apps above it.} } \value{ \code{start_app} returns the new app, \code{default_app} returns the default app. \code{stop_app} does not return anything. } \description{ \code{start_app} creates an app, and places it on the top of the app stack. } \details{ \code{stop_app} removes the top app, or multiple apps from the app stack. \code{default_app} returns the default app, the one on the top of the stack. } cli/man/cli_process_start.Rd0000644000176200001440000001115014752735214015615 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/status-bar.R \name{cli_process_start} \alias{cli_process_start} \alias{cli_process_done} \alias{cli_process_failed} \title{Indicate the start and termination of some computation in the status bar (superseded)} \usage{ cli_process_start( msg, msg_done = paste(msg, "... done"), msg_failed = paste(msg, "... failed"), on_exit = c("auto", "failed", "done"), msg_class = "alert-info", done_class = "alert-success", failed_class = "alert-danger", .auto_close = TRUE, .envir = parent.frame() ) cli_process_done( id = NULL, msg_done = NULL, .envir = parent.frame(), done_class = "alert-success" ) cli_process_failed( id = NULL, msg = NULL, msg_failed = NULL, .envir = parent.frame(), failed_class = "alert-danger" ) } \arguments{ \item{msg}{The message to show to indicate the start of the process or computation. It will be collapsed into a single string, and the first line is kept and cut to \code{\link[=console_width]{console_width()}}.} \item{msg_done}{The message to use for successful termination.} \item{msg_failed}{The message to use for unsuccessful termination.} \item{on_exit}{Whether this process should fail or terminate successfully when the calling function (or the environment in \code{.envir}) exits.} \item{msg_class}{The style class to add to the message. Use an empty string to suppress styling.} \item{done_class}{The style class to add to the successful termination message. Use an empty string to suppress styling.a} \item{failed_class}{The style class to add to the unsuccessful termination message. Use an empty string to suppress styling.a} \item{.auto_close}{Whether to clear the status bar when the calling function finishes (or \code{.envir} is removed from the stack, if specified).} \item{.envir}{Environment to evaluate the glue expressions in. It is also used to auto-clear the status bar if \code{.auto_close} is \code{TRUE}.} \item{id}{Id of the status bar container to clear. If \code{id} is not the id of the current status bar (because it was overwritten by another status bar container), then the status bar is not cleared. If \code{NULL} (the default) then the status bar is always cleared.} } \value{ Id of the status bar container. } \description{ \strong{The \verb{cli_process_*()} functions are superseded by the \code{\link[=cli_progress_message]{cli_progress_message()}} and \code{\link[=cli_progress_step]{cli_progress_step()}} functions, because they have a better default behavior.} Typically you call \code{cli_process_start()} to start the process, and then \code{cli_process_done()} when it is done. If an error happens before \code{cli_process_done()} is called, then cli automatically shows the message for unsuccessful termination. } \details{ If you handle the errors of the process or computation, then you can do the opposite: call \code{cli_process_start()} with \code{on_exit = "done"}, and in the error handler call \code{cli_process_failed()}. cli will automatically call \code{cli_process_done()} on successful termination, when the calling function finishes. See examples below. } \examples{ ## Failure by default fun <- function() { cli_process_start("Calculating") if (interactive()) Sys.sleep(1) if (runif(1) < 0.5) stop("Failed") cli_process_done() } tryCatch(fun(), error = function(err) err) ## Success by default fun2 <- function() { cli_process_start("Calculating", on_exit = "done") tryCatch({ if (interactive()) Sys.sleep(1) if (runif(1) < 0.5) stop("Failed") }, error = function(err) cli_process_failed()) } fun2() } \seealso{ This function supports \link[=inline-markup]{inline markup}. The \code{\link[=cli_progress_message]{cli_progress_message()}} and \code{\link[=cli_progress_step]{cli_progress_step()}} functions, for a superior API. Other status bar: \code{\link{cli_status}()}, \code{\link{cli_status_clear}()}, \code{\link{cli_status_update}()} Other functions supporting inline markup: \code{\link{cli_abort}()}, \code{\link{cli_alert}()}, \code{\link{cli_blockquote}()}, \code{\link{cli_bullets}()}, \code{\link{cli_bullets_raw}()}, \code{\link{cli_dl}()}, \code{\link{cli_h1}()}, \code{\link{cli_li}()}, \code{\link{cli_ol}()}, \code{\link{cli_progress_along}()}, \code{\link{cli_progress_bar}()}, \code{\link{cli_progress_message}()}, \code{\link{cli_progress_output}()}, \code{\link{cli_progress_step}()}, \code{\link{cli_rule}}, \code{\link{cli_status}()}, \code{\link{cli_status_update}()}, \code{\link{cli_text}()}, \code{\link{cli_ul}()}, \code{\link{format_error}()}, \code{\link{format_inline}()} } \concept{functions supporting inline markup} \concept{status bar} cli/man/cat_line.Rd0000644000176200001440000000253114557444176013663 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/cat.R \name{cat_line} \alias{cat_line} \alias{cat_bullet} \alias{cat_boxx} \alias{cat_rule} \alias{cat_print} \title{\code{cat()} helpers} \usage{ cat_line(..., col = NULL, background_col = NULL, file = stdout()) cat_bullet( ..., col = NULL, background_col = NULL, bullet = "bullet", bullet_col = NULL, file = stdout() ) cat_boxx(..., file = stdout()) cat_rule(..., file = stdout()) cat_print(x, file = "") } \arguments{ \item{...}{For \code{cat_line()} and \code{cat_bullet()}, pasted together with \code{collapse = "\\n"}. For \code{cat_rule()} and \code{cat_boxx()} passed on to \code{\link[=rule]{rule()}} and \code{\link[=boxx]{boxx()}} respectively.} \item{col, background_col, bullet_col}{Colors for text, background, and bullets respectively.} \item{file}{Output destination. Defaults to standard output.} \item{bullet}{Name of bullet character. Indexes into \link{symbol}} \item{x}{An object to print.} } \description{ These helpers provide useful wrappers around \code{\link[=cat]{cat()}}: most importantly they all set \code{sep = ""}, and \code{cat_line()} automatically adds a newline. } \examples{ cat_line("This is ", "a ", "line of text.", col = "red") cat_bullet(letters[1:5]) cat_bullet(letters[1:5], bullet = "tick", bullet_col = "green") cat_rule() } cli/man/unicode-width-workaround.Rd0000644000176200001440000000262514557444176017045 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/unicode.R \name{unicode-width-workaround} \alias{unicode-width-workaround} \title{Working around the bad Unicode character widths} \description{ R 3.6.2 and also the coming 3.6.3 and 4.0.0 versions use the Unicode 8 standard to calculate the display width of Unicode characters. Unfortunately the widths of most emojis are incorrect in this standard, and width 1 is reported instead of the correct 2 value. } \details{ cli implements a workaround for this. The package contains a table that contains all Unicode ranges that have wide characters (display width 2). On first use of one of the workaround wrappers (in \code{ansi_nchar()}, etc.) we check what the current version of R thinks about the width of these characters, and then create a regex that matches the ones that R is wrong about (\code{re_bad_char_width}). Then we use this regex to duplicate all of the problematic characters in the input string to the wrapper function, before calling the real string manipulation function (\code{nchar()}, \code{strwrap()}) etc. At end we undo the duplication before we return the result. This workaround is fine for \code{nchar()} and \code{strwrap()}, and consequently \code{ansi_align()} and \code{ansi_strtrim()} as well. The rest of the \verb{ansi_*()} functions work on characters, and do not deal with character width. } \keyword{internal} cli/man/chunks/0000755000176200001440000000000014752736636013112 5ustar liggesuserscli/man/chunks/FAQ.Rmd0000644000176200001440000000514414557444176014167 0ustar liggesusers ```{r, include = FALSE} knitr::opts_chunk$set( R.options = list( cli.num_colors = 1L, cli.unicode = FALSE ), results = "hold", comment = "#>", cache = TRUE ) ``` ## My platform supports ANSI colors, why does cli not use them? It is probably a mistake in the ANSI support detection algorithm. Please open an issue at https://github.com/r-lib/cli/issues and do not forget to tell us the details of your platform and terminal or GUI. ## How do I turn off ANSI colors and styles? Set the `NO_COLOR` environment variable to a non-empty value. You can do this in your `.Renviron` file (use `usethis::edit_r_environ()`). If you want to do this for testthat tests, then consider using the 3rd edition on testthat, which does turn off ANSI styling automatically inside `test_that()`. ## cli does not show the output before `file.choose()` Try calling `flush.console()` to flush the console, before `file.choose()`. If flushing does not work and you are in RStudio, then it is probably this RStudio bug: https://github.com/rstudio/rstudio/issues/8040 See more details at https://github.com/r-lib/cli/issues/151 ## Why are heading separators wider than my screen in RStudio? The display width of some Unicode characters ambiguous in the Unicode standard. Some software treats them as narrow (one column on the screen), other as wide (two columns). In some terminal emulators (for example iTerm2), you can configure the preferred behavior. Unfortunately the box drawing characters that cli uses also have ambiguous width. In RStudio the behavior depends on the font. In particular, Consolas, Courier and Inconsolata treats them as wide characters, so cli output will not look great with these. Some good, modern fonts that look good include Menlo, Fira Code and Source Code Pro. If you do not want to change your font, you can also turn off Unicode output, by setting the `cli.unicode` option: ```r options(cli.unicode = FALSE) ``` A related issue: https://github.com/r-lib/cli/issues/320 ## Is there a suggested font to use with cli? In modern terminals, cli output usually looks good. If you see too wide heading separators in RStudio, then see the previous question: Why are heading separators wider than my screen in RStudio?. If some output is garbled, then cli probably misdetected Unicode support for your terminal or font. You can try choosing a different font. In our experience output looks good with Menlo, Fira Code and Source Code Pro. Alternatively you can turn off Unicode output: ```r options(cli.unicode = FALSE) ``` If you think this is our fault, then please also file an issue at https://github.com/r-lib/cli/issues cli/man/chunks/pluralization.Rmd0000644000176200001440000001323614557444176016456 0ustar liggesusers--- editor_options: markdown: wrap: sentence --- ```{r, include = FALSE, cache = FALSE} knitr::opts_chunk$set( R.options = list( cli.num_colors = 1L, cli.unicode = FALSE ), results = "hold", comment = "#>", cache = TRUE ) ``` # Introduction cli has tools to create messages that are printed correctly in singular and plural forms. This usually requires minimal extra work, and increases the quality of the messages greatly. In this document we first show some pluralization examples that you can use as guidelines. Hopefully these are intuitive enough, so that they can be used without knowing the exact cli pluralization rules. If you need pluralization without the semantic cli functions, see the `pluralize()` function. # Examples ## Pluralization markup In the simplest case the message contains a single `{}` glue substitution, which specifies the quantity that is used to select between the singular and plural forms. Pluralization uses markup that is similar to glue, but uses the `{?` and `}` delimiters: ```{r} library(cli) nfile <- 0; cli_text("Found {nfile} file{?s}.") nfile <- 1; cli_text("Found {nfile} file{?s}.") nfile <- 2; cli_text("Found {nfile} file{?s}.") ``` Here the value of `nfile` is used to decide whether the singular or plural form of `file` is used. This is the most common case for English messages. ## Irregular plurals If the plural form is more difficult than a simple `s` suffix, then the singular and plural forms can be given, separated with a forward slash: ```{r} ndir <- 1; cli_text("Found {ndir} director{?y/ies}.") ndir <- 5; cli_text("Found {ndir} director{?y/ies}.") ``` ## Use `"no"` instead of zero For readability, it is better to use the `no()` helper function to include a count in a message. `no()` prints the word `"no"` if the count is zero, and prints the numeric count otherwise: ```{r} nfile <- 0; cli_text("Found {no(nfile)} file{?s}.") nfile <- 1; cli_text("Found {no(nfile)} file{?s}.") nfile <- 2; cli_text("Found {no(nfile)} file{?s}.") ``` ## Use the length of character vectors With the auto-collapsing feature of cli it is easy to include a list of objects in a message. When cli interprets a character vector as a pluralization quantity, it takes the length of the vector: ```{r} pkgs <- "pkg1" cli_text("Will remove the {.pkg {pkgs}} package{?s}.") pkgs <- c("pkg1", "pkg2", "pkg3") cli_text("Will remove the {.pkg {pkgs}} package{?s}.") ``` Note that the length is only used for non-numeric vectors (when `is.numeric(x)` return `FALSE`). If you want to use the length of a numeric vector, convert it to character via `as.character()`. You can combine collapsed vectors with `"no"`, like this: ```{r} pkgs <- character() cli_text("Will remove {?no/the/the} {.pkg {pkgs}} package{?s}.") pkgs <- c("pkg1", "pkg2", "pkg3") cli_text("Will remove {?no/the/the} {.pkg {pkgs}} package{?s}.") ``` When the pluralization markup contains three alternatives, like above, the first one is used for zero, the second for one, and the third one for larger quantities. ## Choosing the right quantity When the text contains multiple glue `{}` substitutions, the one right before the pluralization markup is used. For example: ```{r} nfiles <- 3; ndirs <- 1 cli_text("Found {nfiles} file{?s} and {ndirs} director{?y/ies}") ``` This is sometimes not the the correct one. You can explicitly specify the correct quantity using the `qty()` function. This sets that quantity without printing anything: ```{r} nupd <- 3; ntotal <- 10 cli_text("{nupd}/{ntotal} {qty(nupd)} file{?s} {?needs/need} updates") ``` Note that if the message only contains a single `{}` substitution, then this may appear before or after the pluralization markup. If the message contains multiple `{}` substitutions *after* pluralization markup, an error is thrown. Similarly, if the message contains no `{}` substitutions at all, but has pluralization markup, an error is thrown. # Rules The exact rules of cli pluralization. There are two sets of rules. The first set specifies how a quantity is associated with a `{?}` pluralization markup. The second set describes how the `{?}` is parsed and interpreted. ## Quantities 1. `{}` substitutions define quantities. If the value of a `{}` substitution is numeric (when `is.numeric(x)` holds), then it has to have length one to define a quantity. This is only enforced if the `{}` substitution is used for pluralization. The quantity is defined as the value of `{}` then, rounded with `as.integer()`. If the value of `{}` is not numeric, then its quantity is defined as its length. 2. If a message has `{?}` markup but no `{}` substitution, an error is thrown. 3. If a message has exactly one `{}` substitution, its value is used as the pluralization quantity for all `{?}` markup in the message. 4. If a message has multiple `{}` substitutions, then for each `{?}` markup cli uses the quantity of the `{}` substitution that precedes it. 5. If a message has multiple `{}` substitutions and has pluralization markup without a preceding `{}` substitution, an error is thrown. ## Pluralization markup 1. Pluralization markup starts with `{?` and ends with `}`. It may not contain `{` and `}` characters, so it may not contain `{}` substitutions either. 2. Alternative words or suffixes are separated by `/`. 3. If there is a single alternative, then *nothing* is used if `quantity == 1` and this single alternative is used if `quantity != 1`. 4. If there are two alternatives, the first one is used for `quantity == 1`, the second one for `quantity != 1` (including \``quantity == 0`). 5. If there are three alternatives, the first one is used for `quantity == 0`, the second one for `quantity == 1`, and the third one otherwise. cli/man/ansi_strwrap.Rd0000644000176200001440000000302114752735214014605 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/ansiex.R \name{ansi_strwrap} \alias{ansi_strwrap} \title{Wrap an ANSI styled string to a certain width} \usage{ ansi_strwrap( x, width = console_width(), indent = 0, exdent = 0, simplify = TRUE ) } \arguments{ \item{x}{ANSI string.} \item{width}{Width to wrap to.} \item{indent}{Indentation of the first line of each paragraph.} \item{exdent}{Indentation of the subsequent lines of each paragraph.} \item{simplify}{Whether to return all wrapped strings in a single character vector, or wrap each element of \code{x} independently and return a list.} } \value{ If \code{simplify} is \code{FALSE}, then a list of character vectors, each an ANSI string. Otherwise a single ANSI string vector. } \description{ This function is similar to \code{\link[base:strwrap]{base::strwrap()}}, but works on ANSI styled strings, and leaves the styling intact. } \examples{ text <- cli:::lorem_ipsum() # Highlight some words, that start with 's' rexp <- gregexpr("\\\\b([sS][a-zA-Z]+)\\\\b", text) regmatches(text, rexp) <- lapply(regmatches(text, rexp), col_red) cat(text) wrp <- ansi_strwrap(text, width = 40) cat(wrp, sep = "\n") } \seealso{ Other ANSI string operations: \code{\link{ansi_align}()}, \code{\link{ansi_columns}()}, \code{\link{ansi_nchar}()}, \code{\link{ansi_strsplit}()}, \code{\link{ansi_strtrim}()}, \code{\link{ansi_substr}()}, \code{\link{ansi_substring}()}, \code{\link{ansi_toupper}()}, \code{\link{ansi_trimws}()} } \concept{ANSI string operations} cli/man/boxx.Rd0000644000176200001440000004222514557444176013071 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/box-styles.R, R/boxes.R \name{list_border_styles} \alias{list_border_styles} \alias{boxx} \title{Draw a banner-like box in the console} \usage{ list_border_styles() boxx( label, header = "", footer = "", border_style = "single", padding = 1, margin = 0, float = c("left", "center", "right"), col = NULL, background_col = NULL, border_col = col, align = c("left", "center", "right"), width = console_width() ) } \arguments{ \item{label}{Label to show, a character vector. Each element will be in a new line. You can color it using the \verb{col_*}, \verb{bg_*} and \verb{style_*} functions, see \link[=ansi-styles]{ANSI styles} and the examples below.} \item{header}{Text to show on top border of the box. If too long, it will be cut.} \item{footer}{Text to show on the bottom border of the box. If too long, it will be cut.} \item{border_style}{String that specifies the border style. \code{list_border_styles} lists all current styles.} \item{padding}{Padding within the box. Either an integer vector of four numbers (bottom, left, top, right), or a single number \code{x}, which is interpreted as \code{c(x, 3*x, x, 3*x)}.} \item{margin}{Margin around the box. Either an integer vector of four numbers (bottom, left, top, right), or a single number \code{x}, which is interpreted as \code{c(x, 3*x, x, 3*x)}.} \item{float}{Whether to display the box on the \code{"left"}, \code{"center"}, or the \code{"right"} of the screen.} \item{col}{Color of text, and default border color. Either a style function (see \link[=ansi-styles]{ANSI styles}) or a color name that is passed to \code{\link[=make_ansi_style]{make_ansi_style()}}.} \item{background_col}{Background color of the inside of the box. Either a style function (see \link[=ansi-styles]{ANSI styles}), or a color name which will be used in \code{\link[=make_ansi_style]{make_ansi_style()}} to create a \emph{background} style (i.e. \code{bg = TRUE} is used).} \item{border_col}{Color of the border. Either a style function (see \link[=ansi-styles]{ANSI styles}) or a color name that is passed to \code{\link[=make_ansi_style]{make_ansi_style()}}.} \item{align}{Alignment of the label within the box: \code{"left"}, \code{"center"}, or \code{"right"}.} \item{width}{Width of the screen, defaults to \code{\link[=console_width]{console_width()}}.} } \description{ Draw a banner-like box in the console } \details{ \subsection{Defaults}{ \if{html}{\out{
}}\preformatted{boxx("Hello there!") }\if{html}{\out{
}}\if{html}{\out{
#> ┌──────────────────┐                                                            
#> │                  │                                                            
#> │   Hello there!   │                                                            
#> │                  │                                                            
#> └──────────────────┘                                                            
}} } \subsection{Change border style}{ \if{html}{\out{
}}\preformatted{boxx("Hello there!", border_style = "double") }\if{html}{\out{
}}\if{html}{\out{
#> ╔══════════════════╗                                                            
#> ║                  ║                                                            
#> ║   Hello there!   ║                                                            
#> ║                  ║                                                            
#> ╚══════════════════╝                                                            
}} } \subsection{Multiple lines}{ \if{html}{\out{
}}\preformatted{boxx(c("Hello", "there!"), padding = 1) }\if{html}{\out{
}}\if{html}{\out{
#> ┌────────────┐                                                                  
#> │            │                                                                  
#> │   Hello    │                                                                  
#> │   there!   │                                                                  
#> │            │                                                                  
#> └────────────┘                                                                  
}} } \subsection{Padding}{ \if{html}{\out{
}}\preformatted{boxx("Hello there!", padding = 1) boxx("Hello there!", padding = c(1, 5, 1, 5)) }\if{html}{\out{
}}\if{html}{\out{
#> ┌──────────────────┐                                                            
#> │                  │                                                            
#> │   Hello there!   │                                                            
#> │                  │                                                            
#> └──────────────────┘                                                            
#> ┌──────────────────────┐                                                        
#> │                      │                                                        
#> │     Hello there!     │                                                        
#> │                      │                                                        
#> └──────────────────────┘                                                        
}} } \subsection{Floating}{ \if{html}{\out{
}}\preformatted{boxx("Hello there!", padding = 1, float = "center") boxx("Hello there!", padding = 1, float = "right") }\if{html}{\out{
}}\if{html}{\out{
#>                           ┌──────────────────┐                                  
#>                           │                  │                                  
#>                           │   Hello there!   │                                  
#>                           │                  │                                  
#>                           └──────────────────┘                                  
#>                                                   ┌──────────────────┐          
#>                                                   │                  │          
#>                                                   │   Hello there!   │          
#>                                                   │                  │          
#>                                                   └──────────────────┘          
}} } \subsection{Text color}{ \if{html}{\out{
}}\preformatted{boxx(col_cyan("Hello there!"), padding = 1, float = "center") }\if{html}{\out{
}}\if{html}{\out{
#>                           ┌──────────────────┐                                  
#>                           │                  │                                  
#>                           │   Hello there!   │                                  
#>                           │                  │                                  
#>                           └──────────────────┘                                  
}} } \subsection{Background color}{ \if{html}{\out{
}}\preformatted{boxx("Hello there!", padding = 1, background_col = "brown") boxx("Hello there!", padding = 1, background_col = bg_red) }\if{html}{\out{
}}\if{html}{\out{
#> ┌──────────────────┐                                                            
#> │                  │                                                            
#> │   Hello there!   │                                                            
#> │                  │                                                            
#> └──────────────────┘                                                            
#> ┌──────────────────┐                                                            
#> │                  │                                                            
#> │   Hello there!   │                                                            
#> │                  │                                                            
#> └──────────────────┘                                                            
}} } \subsection{Border color}{ \if{html}{\out{
}}\preformatted{boxx("Hello there!", padding = 1, border_col = "green") boxx("Hello there!", padding = 1, border_col = col_red) }\if{html}{\out{
}}\if{html}{\out{
#> ┌──────────────────┐                                                            
#>                                                                               
#>    Hello there!                                                               
#>                                                                               
#> └──────────────────┘                                                            
#> ┌──────────────────┐                                                            
#>                                                                               
#>    Hello there!                                                               
#>                                                                               
#> └──────────────────┘                                                            
}} } \subsection{Label alignment}{ \if{html}{\out{
}}\preformatted{boxx(c("Hi", "there", "you!"), padding = 1, align = "left") boxx(c("Hi", "there", "you!"), padding = 1, align = "center") boxx(c("Hi", "there", "you!"), padding = 1, align = "right") }\if{html}{\out{
}}\if{html}{\out{
#> ┌───────────┐                                                                   
#> │           │                                                                   
#> │   Hi      │                                                                   
#> │   there   │                                                                   
#> │   you!    │                                                                   
#> │           │                                                                   
#> └───────────┘                                                                   
#> ┌───────────┐                                                                   
#> │           │                                                                   
#> │     Hi    │                                                                   
#> │   there   │                                                                   
#> │    you!   │                                                                   
#> │           │                                                                   
#> └───────────┘                                                                   
#> ┌───────────┐                                                                   
#> │           │                                                                   
#> │      Hi   │                                                                   
#> │   there   │                                                                   
#> │    you!   │                                                                   
#> │           │                                                                   
#> └───────────┘                                                                   
}} } \subsection{A very customized box}{ \if{html}{\out{
}}\preformatted{star <- symbol$star label <- c(paste(star, "Hello", star), " there!") boxx( col_white(label), border_style="round", padding = 1, float = "center", border_col = "tomato3", background_col="darkolivegreen" ) }\if{html}{\out{
}}\if{html}{\out{
#>                            ╭───────────────╮                                    
#>                                                                               
#>                               ★ Hello ★                                       
#>                                 there!                                        
#>                                                                               
#>                            ╰───────────────╯                                    
}} } } \section{About fonts and terminal settings}{ The boxes might or might not look great in your terminal, depending on the box style you use and the font the terminal uses. We found that the Menlo font looks nice in most terminals an also in Emacs. RStudio currently has a line height greater than one for console output, which makes the boxes ugly. } cli/man/ansi_has_any.Rd0000644000176200001440000000171014557444176014537 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/ansiex.R \name{ansi_has_any} \alias{ansi_has_any} \title{Check if a string has some ANSI styling} \usage{ ansi_has_any(string, sgr = TRUE, csi = TRUE, link = TRUE) } \arguments{ \item{string}{The string to check. It can also be a character vector.} \item{sgr}{Whether to look for SGR (styling) control sequences.} \item{csi}{Whether to look for non-SGR control sequences.} \item{link}{Whether to look for ANSI hyperlinks.} } \value{ Logical vector, \code{TRUE} for the strings that have some ANSI styling. } \description{ Check if a string has some ANSI styling } \examples{ ## The second one has style if ANSI colors are supported ansi_has_any("foobar") ansi_has_any(col_red("foobar")) } \seealso{ Other low level ANSI functions: \code{\link{ansi_hide_cursor}()}, \code{\link{ansi_regex}()}, \code{\link{ansi_string}()}, \code{\link{ansi_strip}()} } \concept{low level ANSI functions} cli/man/ansi_grep.Rd0000644000176200001440000000315314557444176014055 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/ansiex.R \name{ansi_grep} \alias{ansi_grep} \alias{ansi_grepl} \title{Like \code{\link[base:grep]{base::grep()}} and \code{\link[base:grep]{base::grepl()}}, but for ANSI strings} \usage{ ansi_grep(pattern, x, ignore.case = FALSE, perl = FALSE, value = FALSE, ...) ansi_grepl(pattern, x, ...) } \arguments{ \item{pattern}{Character scalar, regular expression or fixed string (if \code{fixed = TRUE}), the pattern to search for. Other objects will be coerced using \code{\link[=as.character]{as.character()}}.} \item{x}{Character vector to search in. Other objects will be coerced using \code{\link[=as.character]{as.character()}}.} \item{ignore.case, perl, value}{Passed to \code{\link[base:grep]{base::grep()}}.} \item{...}{Extra arguments are passed to \code{\link[base:grep]{base::grep()}} or \code{\link[base:grep]{base::grepl()}}.} } \value{ The same as \code{\link[base:grep]{base::grep()}} and \code{\link[base:grep]{base::grepl()}}, respectively. } \description{ First ANSI sequences will be stripped with \code{\link[=ansi_strip]{ansi_strip()}}, both } \details{ Note that these functions work on code points (or bytes if \code{useBytes = TRUE}), and not graphemes. Unlike \code{\link[base:grep]{base::grep()}} and \code{\link[base:grep]{base::grepl()}} these functions do not special case factors. Both \code{pattern} and \code{x} are converted to UTF-8. } \examples{ red_needle <- col_red("needle") haystack <- c("foo", "needle", "foo") green_haystack <- col_green(haystack) ansi_grepl(red_needle, haystack) ansi_grepl(red_needle, green_haystack) } cli/man/ansi_collapse.Rd0000644000176200001440000000507414752735214014717 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/glue.R \name{ansi_collapse} \alias{ansi_collapse} \title{Collapse a vector into a string scalar} \usage{ ansi_collapse( x, sep = ", ", sep2 = sub("^,", "", last), last = ", and ", trunc = Inf, width = Inf, ellipsis = symbol$ellipsis, style = c("both-ends", "head") ) } \arguments{ \item{x}{Character vector, or an object with an \code{as.character()} method to collapse.} \item{sep}{Separator. A character string.} \item{sep2}{Separator for the special case that \code{x} contains only two elements. A character string. Defaults to the value of \code{last} without the serial comma.} \item{last}{Last separator, if there is no truncation. E.g. use \code{", and "} for the \href{https://en.wikipedia.org/wiki/Serial_comma}{serial comma}. A character string.} \item{trunc}{Maximum number of elements to show. For \code{style = "head"} at least \code{trunc = 1} is used. For \code{style = "both-ends"} at least \code{trunc = 5} is used, even if a smaller number is specified.} \item{width}{Limit for the display width of the result, in characters. This is a hard limit, and the output will never exceed it. This argument is not implemented for the \code{"both-ends"} style, which always uses \code{Inf}, with a warning if a finite \code{width} value is set.} \item{ellipsis}{Character string to use at the place of the truncation. By default, the Unicode ellipsis character is used if the console is UTF-8, and three dots otherwise.} \item{style}{Truncation style: \itemize{ \item \code{both-ends}: the default, shows the beginning and end of the vector, and skips elements in the middle if needed. \item \code{head}: shows the beginning of the vector, and skips elements at the end, if needed. }} } \value{ Character scalar. It is \code{NA_character_} if any elements in \code{x} are \code{NA}. } \description{ Features: \itemize{ \item custom separator (\code{sep}), \item custom separator for length-two input (\code{sep2}), \item custom last separator (\code{last}), \item adds ellipsis to truncated strings, \item uses Unicode ellipsis character on UTF-8 console, \item can collapse "from both ends", with \code{style = "both-ends"}, \item can consider a limit for the display width of the result, in characters, \item handles ANSI control sequences correctly when measuring display width. } } \examples{ ansi_collapse(letters) # truncate ansi_collapse(letters, trunc = 5) # head style ansi_collapse(letters, trunc = 5, style = "head") } \seealso{ \code{glue_collapse} in the glue package inspired this function. } cli/man/themes.Rd0000644000176200001440000001571614557444176013403 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/cliapp-docs.R \name{themes} \alias{themes} \title{About cli themes} \description{ CLI elements can be styled via a CSS-like language of selectors and properties. Only a small subset of CSS3 is supported, and a lot visual properties cannot be implemented on a terminal, so these will be ignored as well. } \section{Adding themes}{ The style of an element is calculated from themes from four sources. These form a stack, and the themes on the top of the stack take precedence, over themes in the bottom. \enumerate{ \item The cli package has a built-in theme. This is always active. See \code{\link[=builtin_theme]{builtin_theme()}}. \item When an app object is created via \code{\link[=start_app]{start_app()}}, the caller can specify a theme, that is added to theme stack. If no theme is specified for \code{\link[=start_app]{start_app()}}, the content of the \code{cli.theme} option is used. Removed when the corresponding app stops. \item The user may specify a theme in the \code{cli.user_theme} option. This is added to the stack \emph{after} the app's theme (step 2.), so it can override its settings. Removed when the app that added it stops. \item Themes specified explicitly in \code{\link[=cli_div]{cli_div()}} elements. These are removed from the theme stack, when the corresponding \code{\link[=cli_div]{cli_div()}} elements are closed. } } \section{Writing themes}{ A theme is a named list of lists. The name of each entry is a CSS selector. Only a subset of CSS is supported: \itemize{ \item Type selectors, e.g. \code{input} selects all \verb{} elements. \item Class selectors, e.g. \code{.index} selects any element that has a class of "index". \item ID selector. \verb{#toc} will match the element that has the ID "toc". \item The descendant combinator, i.e. the space, that selects nodes that are descendants of the first element. E.g. \verb{div span} will match all \verb{} elements that are inside a \verb{
} element. } The content of a theme list entry is another named list, where the names are CSS properties, e.g. \code{color}, or \code{font-weight} or \code{margin-left}, and the list entries themselves define the values of the properties. See \code{\link[=builtin_theme]{builtin_theme()}} and \code{\link[=simple_theme]{simple_theme()}} for examples. } \section{Formatter callbacks}{ For flexibility, themes may also define formatter functions, with property name \code{fmt}. These will be called once the other styles are applied to an element. They are only called on elements that produce output, i.e. \emph{not} on container elements. } \section{Supported properties}{ Right now only a limited set of properties are supported. These include left, right, top and bottom margins, background and foreground colors, bold and italic fonts, underlined text. The \code{before} and \code{after} properties are supported to insert text before and after the content of the element. The current list of properties: \itemize{ \item \code{after}: A string literal to insert after the element. It can also be a function that returns a string literal. Supported by all inline elements, list items, alerts and rules. \item \code{background-color}: An R color name, or HTML hexadecimal color. It can be applied to most elements (inline elements, rules, text, etc.), but the background of containers is not colored properly currently. \item \code{before}: A string literal to insert before the element. It can also be a function that returns a string literal. Supported by all inline elements, list items, alerts and rules. \item \code{class-map}: Its value can be a named list, and it specifies how R (S3) class names are mapped to cli class names. E.g. \code{list(fs_path = "file")} specifies that \code{fs_path} objects (from the fs package) should always print as \code{.file} objects in cli. \item \code{color}: Text color, an R color name or a HTML hexadecimal color. It can be applied to most elements that are printed. \item \code{collapse}: Specifies how to collapse a vector, before applying styling. If a character string, then that is used as the separator. If a function, then it is called, with the vector as the only argument. \item \code{digits}: Number of digits after the decimal point for numeric inline element of class \code{.val}. \item \code{fmt}: Generic formatter function that takes an input text and returns formatted text. Can be applied to most elements. If colors are in use, the input text provided to \code{fmt} already includes ANSI sequences. \item \code{font-style}: If \code{"italic"} then the text is printed as cursive. \item \code{font-weight}: If \code{"bold"}, then the text is printed in boldface. \item \code{line-type}: Line type for \code{\link[=cli_rule]{cli_rule()}}. \item \code{list-style-type}: String literal or functions that returns a string literal, to be used as a list item marker in un-ordered lists. \item \code{margin-bottom}, \code{margin-left}, \code{margin-right}, \code{margin-top}: Margins. \item \code{padding-left}, \code{padding-right}: This is currently used the same way as the margins, but this might change later. \item \code{start}: Integer number, the first element in an ordered list. \item \code{string-quote}: Quoting character for inline elements of class \code{.val}. \item \code{text-decoration}: If \code{"underline"}, then underlined text is created. \item \code{text-exdent}: Amount of indentation from the second line of wrapped text. \item \code{transform}: A function to call on glue substitutions, before collapsing them. Note that \code{transform} is applied prior to implementing color via ANSI sequences. \item \code{vec-last}: The last separator when collapsing vectors. \item \code{vec-sep}: The separator to use when collapsing vectors. \item \code{vec-sep2}: The separator to use for two elements when collapsing vectors. If not set, then \code{vec-sep} is used for these as well. \item \code{vec-trunc}: Vectors longer than this will be truncated. Defaults to 100. \item \code{vec-trunc-style}: Select between two ways of collapsing vectors: \itemize{ \item \code{"both-ends"} is the current default and it shows the beginning and the end of the vector. \item \code{"head"} only shows the beginning of the vector. } } More properties might be added later. If you think that a property is not applied properly to an element, please open an issue about it in the cli issue tracker. } \section{Examples}{ Color of headings, that are only active in paragraphs with an 'output' class: \if{html}{\out{
}}\preformatted{list( "par.output h1" = list("background-color" = "red", color = "#e0e0e0"), "par.output h2" = list("background-color" = "orange", color = "#e0e0e0"), "par.output h3" = list("background-color" = "blue", color = "#e0e0e0") ) }\if{html}{\out{
}} Create a custom alert type: \if{html}{\out{
}}\preformatted{list( ".alert-start" = list(before = symbol$play), ".alert-stop" = list(before = symbol$stop) ) }\if{html}{\out{
}} } cli/man/ansi_strip.Rd0000644000176200001440000000173214557444176014262 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/ansiex.R \name{ansi_strip} \alias{ansi_strip} \title{Remove ANSI escape sequences from a string} \usage{ ansi_strip(string, sgr = TRUE, csi = TRUE, link = TRUE) } \arguments{ \item{string}{The input string.} \item{sgr}{Whether to remove for SGR (styling) control sequences.} \item{csi}{Whether to remove for non-SGR control sequences.} \item{link}{Whether to remove ANSI hyperlinks.} } \value{ The cleaned up string. Note that \code{ansi_strip()} always drops the \code{cli_ansi_string} class, even if \code{sgr} and sci\code{are}FALSE`. } \description{ The input may be of class \code{cli_ansi_string} class, this is also dropped from the result. } \examples{ ansi_strip(col_red("foobar")) == "foobar" } \seealso{ Other low level ANSI functions: \code{\link{ansi_has_any}()}, \code{\link{ansi_hide_cursor}()}, \code{\link{ansi_regex}()}, \code{\link{ansi_string}()} } \concept{low level ANSI functions} cli/man/cli-package.Rd0000644000176200001440000000216214752735214014236 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/cli-package.R \docType{package} \name{cli-package} \alias{cli-package} \title{cli: Helpers for Developing Command Line Interfaces} \description{ A suite of tools to build attractive command line interfaces ('CLIs'), from semantic elements: headings, lists, alerts, paragraphs, etc. Supports custom themes via a 'CSS'-like language. It also contains a number of lower level 'CLI' elements: rules, boxes, trees, and 'Unicode' symbols with 'ASCII' alternatives. It support ANSI colors and text styles as well. } \seealso{ Useful links: \itemize{ \item \url{https://cli.r-lib.org} \item \url{https://github.com/r-lib/cli} \item Report bugs at \url{https://github.com/r-lib/cli/issues} } } \author{ \strong{Maintainer}: Gábor Csárdi \email{gabor@posit.co} Other contributors: \itemize{ \item Hadley Wickham [contributor] \item Kirill Müller [contributor] \item Salim Brüggemann \email{salim-b@pm.me} (\href{https://orcid.org/0000-0002-5329-5987}{ORCID}) [contributor] \item Posit Software, PBC [copyright holder, funder] } } \keyword{internal} cli/man/cli_ol.Rd0000644000176200001440000001067114752735214013343 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/cli.R \name{cli_ol} \alias{cli_ol} \title{Ordered CLI list} \usage{ cli_ol( items = NULL, id = NULL, class = NULL, .close = TRUE, .auto_close = TRUE, .envir = parent.frame() ) } \arguments{ \item{items}{If not \code{NULL}, then a character vector. Each element of the vector will be one list item, and the list container will be closed by default (see the \code{.close} argument).} \item{id}{Id of the list container. Can be used for closing it with \code{\link[=cli_end]{cli_end()}} or in themes. If \code{NULL}, then an id is generated and returned invisibly.} \item{class}{Class of the list container. Can be used in themes.} \item{.close}{Whether to close the list container if the \code{items} were specified. If \code{FALSE} then new items can be added to the list.} \item{.auto_close}{Whether to close the container, when the calling function finishes (or \code{.envir} is removed, if specified).} \item{.envir}{Environment to evaluate the glue expressions in. It is also used to auto-close the container if \code{.auto_close} is \code{TRUE}.} } \value{ The id of the new container element, invisibly. } \description{ An ordered list is a container, see \link{containers}. } \details{ \subsection{Adding all items at once}{ \if{html}{\out{
}}\preformatted{fun <- function() \{ cli_ol(c("one", "two", "three")) \} fun() }\if{html}{\out{
}}\if{html}{\out{
#> 1. one                                                                          
#> 2. two                                                                          
#> 3. three                                                                        
}} } \subsection{Adding items one by one}{ \if{html}{\out{
}}\preformatted{## Adding items one by one fun <- function() \{ cli_ol() cli_li("\{.emph one\}") cli_li("\{.emph two\}") cli_li("\{.emph three\}") cli_end() \} fun() }\if{html}{\out{
}}\if{html}{\out{
#> 1. one                                                                          
#> 2. two                                                                          
#> 3. three                                                                        
}} } \subsection{Nested lists}{ \if{html}{\out{
}}\preformatted{fun <- function() \{ cli_div(theme = list(ol = list("margin-left" = 2))) cli_ul() cli_li("one") cli_ol(c("foo", "bar", "foobar")) cli_li("two") cli_end() cli_end() \} fun() }\if{html}{\out{
}}\if{html}{\out{
#> • one                                                                           
#>     1. foo                                                                      
#>     2. bar                                                                      
#>     3. foobar                                                                   
#> • two                                                                           
}} } } \seealso{ This function supports \link[=inline-markup]{inline markup}. Other functions supporting inline markup: \code{\link{cli_abort}()}, \code{\link{cli_alert}()}, \code{\link{cli_blockquote}()}, \code{\link{cli_bullets}()}, \code{\link{cli_bullets_raw}()}, \code{\link{cli_dl}()}, \code{\link{cli_h1}()}, \code{\link{cli_li}()}, \code{\link{cli_process_start}()}, \code{\link{cli_progress_along}()}, \code{\link{cli_progress_bar}()}, \code{\link{cli_progress_message}()}, \code{\link{cli_progress_output}()}, \code{\link{cli_progress_step}()}, \code{\link{cli_rule}}, \code{\link{cli_status}()}, \code{\link{cli_status_update}()}, \code{\link{cli_text}()}, \code{\link{cli_ul}()}, \code{\link{format_error}()}, \code{\link{format_inline}()} } \concept{functions supporting inline markup} cli/man/cli_list_themes.Rd0000644000176200001440000000145314557444176015256 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/themes.R \name{cli_list_themes} \alias{cli_list_themes} \title{List the currently active themes} \usage{ cli_list_themes() } \value{ A list of data frames with the active themes. Each data frame row is a style that applies to selected CLI tree nodes. Each data frame has columns: \itemize{ \item \code{selector}: The original CSS-like selector string. See \link{themes}. \item \code{parsed}: The parsed selector, as used by cli for matching to nodes. \item \code{style}: The original style. \item \code{cnt}: The id of the container the style is currently applied to, or \code{NA} if the style is not used. } } \description{ If there is no active app, then it calls \code{\link[=start_app]{start_app()}}. } \seealso{ \link{themes} } cli/man/cli_verbatim.Rd0000644000176200001440000000331514557444176014546 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/cli.R \name{cli_verbatim} \alias{cli_verbatim} \title{CLI verbatim text} \usage{ cli_verbatim(..., .envir = parent.frame()) } \arguments{ \item{...}{The text to show, in character vectors. Each element is printed on a new line.} \item{.envir}{Environment to evaluate the glue expressions in.} } \description{ It is not wrapped, but printed as is. Long lines will overflow. No glue substitution is performed on verbatim text. } \details{ \subsection{Line breaks}{ \if{html}{\out{
}}\preformatted{cli_verbatim("This has\\nthree\\nlines,") }\if{html}{\out{
}}\if{html}{\out{
#> This has                                                                        
#> three                                                                           
#> lines,                                                                          
}} } \subsection{Special characters}{ No glue substitution happens here. \if{html}{\out{
}}\preformatted{cli_verbatim("No string \{interpolation\} or \{.emph styling\} here") }\if{html}{\out{
}}\if{html}{\out{
#> No string \{interpolation\} or \{.emph styling\} here                               
}} } } \seealso{ \code{\link[=cli_code]{cli_code()}} for printing R or other source code. } cli/man/cli_progress_output.Rd0000644000176200001440000000453014752735214016212 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/progress-client.R \name{cli_progress_output} \alias{cli_progress_output} \title{Add text output to a progress bar} \usage{ cli_progress_output(text, id = NULL, .envir = parent.frame()) } \arguments{ \item{text}{Text to output. It is formatted via \code{\link[=cli_text]{cli_text()}}.} \item{id}{Progress bar id. The default is the current progress bar.} \item{.envir}{Environment to use for glue interpolation of \code{text}.} } \value{ \code{TRUE}, always. } \description{ The text is calculated via \code{\link[=cli_text]{cli_text()}}, so all cli features can be used here, including progress variables. } \details{ The text is passed to the progress handler(s), that may or may not be able to print it. \if{html}{\out{
}}\preformatted{fun <- function() \{ cli_alert_info("Before the progress bar") cli_progress_bar("Calculating", total = 100) for (i in 1:50) \{ Sys.sleep(4/100) cli_progress_update() \} cli_progress_output("Already half way!") for (i in 1:50) \{ Sys.sleep(4/100) cli_progress_update() \} cli_alert_info("All done") \} fun() }\if{html}{\out{
}} \if{html}{\figure{progress-output2.svg}} } \seealso{ This function supports \link[=inline-markup]{inline markup}. Other progress bar functions: \code{\link{cli_progress_along}()}, \code{\link{cli_progress_bar}()}, \code{\link{cli_progress_builtin_handlers}()}, \code{\link{cli_progress_message}()}, \code{\link{cli_progress_num}()}, \code{\link{cli_progress_step}()}, \code{\link{cli_progress_styles}()}, \code{\link{progress-variables}} Other functions supporting inline markup: \code{\link{cli_abort}()}, \code{\link{cli_alert}()}, \code{\link{cli_blockquote}()}, \code{\link{cli_bullets}()}, \code{\link{cli_bullets_raw}()}, \code{\link{cli_dl}()}, \code{\link{cli_h1}()}, \code{\link{cli_li}()}, \code{\link{cli_ol}()}, \code{\link{cli_process_start}()}, \code{\link{cli_progress_along}()}, \code{\link{cli_progress_bar}()}, \code{\link{cli_progress_message}()}, \code{\link{cli_progress_step}()}, \code{\link{cli_rule}}, \code{\link{cli_status}()}, \code{\link{cli_status_update}()}, \code{\link{cli_text}()}, \code{\link{cli_ul}()}, \code{\link{format_error}()}, \code{\link{format_inline}()} } \concept{functions supporting inline markup} \concept{progress bar functions} cli/man/containers.Rd0000644000176200001440000000631214752364056014246 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/cliapp-docs.R \name{containers} \alias{containers} \title{About cli containers} \description{ Container elements may contain other elements. Currently the following commands create container elements: \code{\link[=cli_div]{cli_div()}}, \code{\link[=cli_par]{cli_par()}}, the list elements: \code{\link[=cli_ul]{cli_ul()}}, \code{\link[=cli_ol]{cli_ol()}}, \code{\link[=cli_dl]{cli_dl()}}, and list items are containers as well: \code{\link[=cli_li]{cli_li()}}. } \details{ \subsection{Themes}{ A container can add a new theme, which is removed when the container exits. \if{html}{\out{
}}\preformatted{d <- cli_div(theme = list(h1 = list(color = "blue", "font-weight" = "bold"))) cli_h1("Custom title") cli_end(d) }\if{html}{\out{
}}\if{html}{\out{
#>                                                                                 
#> Custom title                                                                    
}} } \subsection{Auto-closing}{ Container elements are closed with \code{\link[=cli_end]{cli_end()}}. For convenience, by default they are closed automatically when the function that created them terminated (either regularly or with an error). The default behavior can be changed with the \code{.auto_close} argument. \if{html}{\out{
}}\preformatted{div <- function() \{ cli_div(class = "tmp", theme = list(.tmp = list(color = "yellow"))) cli_text("This is yellow") \} div() cli_text("This is not yellow any more") }\if{html}{\out{
}}\if{html}{\out{
#> This is yellow                                                                  
#> This is not yellow any more                                                     
}} } \subsection{Debugging}{ You can use the internal \code{cli:::cli_debug_doc()} function to see the currently open containers. \if{html}{\out{
}}\preformatted{fun <- function() \{ cli_div(id = "mydiv") cli_par(class = "myclass") cli:::cli_debug_doc() \} fun() }\if{html}{\out{
}}\if{html}{\out{
#>                                                                                 
#> <cli document>                                                                  
#> <body id="body">                                                                
#> <div id="mydiv"> +theme                                                         
#> <par id="cli-82040-226" class="myclass">                                        
}} } } cli/man/spark_line.Rd0000644000176200001440000000166414557444176014242 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/spark.R \name{spark_line} \alias{spark_line} \title{Draw a sparkline line graph with Braille characters.} \usage{ spark_line(x) } \arguments{ \item{x}{A numeric vector between 0 and 1} } \description{ You might want to avoid sparklines on non-UTF-8 systems, because they do not look good. You can use \code{\link[=is_utf8_output]{is_utf8_output()}} to test for support for them. } \details{ \if{html}{\out{
}}\preformatted{x <- seq(0, 1, length = 10) spark_line(x) }\if{html}{\out{
}}\if{html}{\out{
#> ⣀⡠⠔⠊⠉                                                                           
}} } \seealso{ \code{\link[=spark_bar]{spark_bar()}} } cli/man/cli_vec.Rd0000644000176200001440000000351614557444176013515 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/format.R \name{cli_vec} \alias{cli_vec} \title{Add custom cli style to a vector} \usage{ cli_vec(x, style = list()) } \arguments{ \item{x}{Vector that will be collapsed by cli.} \item{style}{Style to apply to the vector. It is used as a theme on a \code{span} element that is created for the vector. You can set \code{vec-sep} and \code{vec-last} to modify the separator and the last separator.} } \description{ Add custom cli style to a vector } \details{ You can use this function to change the default parameters of collapsing the vector into a string, see an example below. The style is added as an attribute, so operations that remove attributes will remove the style as well. \subsection{Custom collapsing separator}{ \if{html}{\out{
}}\preformatted{v <- cli_vec( c("foo", "bar", "foobar"), style = list("vec-sep" = " & ", "vec-last" = " & ") ) cli_text("My list: \{v\}.") }\if{html}{\out{
}}\if{html}{\out{
#> My list: foo & bar & foobar.                                                    
}} } \subsection{Custom truncation}{ \if{html}{\out{
}}\preformatted{x <- cli_vec(names(mtcars), list("vec-trunc" = 3)) cli_text("Column names: \{x\}.") }\if{html}{\out{
}}\if{html}{\out{
#> Column names: mpg, cyl, disp, …, gear, and carb.                                
}} } } \seealso{ \code{\link[=cli_format]{cli_format()}} } cli/man/cli_output_connection.Rd0000644000176200001440000000106114557444176016510 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/tty.R \name{cli_output_connection} \alias{cli_output_connection} \title{The connection option that cli would use} \usage{ cli_output_connection() } \value{ Connection object. } \description{ Note that this only refers to the current R process. If the output is produced in another process, then it is not relevant. } \details{ In interactive sessions the standard output is chosen, otherwise the standard error is used. This is to avoid painting output messages red in the R GUIs. } cli/man/list_spinners.Rd0000644000176200001440000000075614557444176015010 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/spinner.R \name{list_spinners} \alias{list_spinners} \title{List all available spinners} \usage{ list_spinners() } \value{ Character vector of all available spinner names. } \description{ List all available spinners } \examples{ list_spinners() get_spinner(list_spinners()[1]) } \seealso{ Other spinners: \code{\link{demo_spinners}()}, \code{\link{get_spinner}()}, \code{\link{make_spinner}()} } \concept{spinners} cli/man/pluralize.Rd0000644000176200001440000000412114557444176014111 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/pluralize.R \name{pluralize} \alias{pluralize} \title{String templating with pluralization} \usage{ pluralize( ..., .envir = parent.frame(), .transformer = glue::identity_transformer ) } \arguments{ \item{..., .envir, .transformer}{All arguments are passed to \code{\link[glue:glue]{glue::glue()}}.} } \description{ \code{pluralize()} is similar to \code{\link[glue:glue]{glue::glue()}}, with two differences: \itemize{ \item It supports cli's \link{pluralization} syntax, using \verb{\{?\}} markers. \item It collapses substituted vectors into a comma separated string. } } \details{ See \link{pluralization} and some examples below. You need to install the glue package to use this function. } \examples{ \dontshow{if (requireNamespace("glue", quietly = TRUE)) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} # Regular plurals nfile <- 0; pluralize("Found {nfile} file{?s}.") nfile <- 1; pluralize("Found {nfile} file{?s}.") nfile <- 2; pluralize("Found {nfile} file{?s}.") # Irregular plurals ndir <- 1; pluralize("Found {ndir} director{?y/ies}.") ndir <- 5; pluralize("Found {ndir} director{?y/ies}.") # Use 'no' instead of zero nfile <- 0; pluralize("Found {no(nfile)} file{?s}.") nfile <- 1; pluralize("Found {no(nfile)} file{?s}.") nfile <- 2; pluralize("Found {no(nfile)} file{?s}.") # Use the length of character vectors pkgs <- "pkg1" pluralize("Will remove the {pkgs} package{?s}.") pkgs <- c("pkg1", "pkg2", "pkg3") pluralize("Will remove the {pkgs} package{?s}.") pkgs <- character() pluralize("Will remove {?no/the/the} {pkgs} package{?s}.") pkgs <- c("pkg1", "pkg2", "pkg3") pluralize("Will remove {?no/the/the} {pkgs} package{?s}.") # Multiple quantities nfiles <- 3; ndirs <- 1 pluralize("Found {nfiles} file{?s} and {ndirs} director{?y/ies}") # Explicit quantities nupd <- 3; ntotal <- 10 cli_text("{nupd}/{ntotal} {qty(nupd)} file{?s} {?needs/need} updates") \dontshow{\}) # examplesIf} } \seealso{ Other pluralization: \code{\link{no}()}, \code{\link{pluralization}} } \concept{pluralization} cli/man/ansi_simplify.Rd0000644000176200001440000000101514557444176014747 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/ansiex.R \name{ansi_simplify} \alias{ansi_simplify} \title{Simplify ANSI styling tags} \usage{ ansi_simplify(x, csi = c("keep", "drop")) } \arguments{ \item{x}{Input string} \item{csi}{What to do with non-SGR ANSI sequences, either \code{"keep"}, or \code{"drop"} them.} } \value{ Simplified \code{cli_ansi_string} vector. } \description{ It creates an equivalent, but possibly shorter ANSI styled string, by removing duplicate and empty tags. } cli/man/match_selector_node.Rd0000644000176200001440000000170714557444176016112 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/themes.R \name{match_selector_node} \alias{match_selector_node} \title{Match a selector node to a container} \usage{ match_selector_node(node, cnt) } \arguments{ \item{node}{Selector node, as parsed by \code{parse_selector_node()}.} \item{cnt}{Container node, has elements \code{tag}, \code{id}, \code{class}. The selector node matches the container, if all these hold: \itemize{ \item The id of the selector is missing or unique. \item The tag of the selector is missing or unique. \item The id of the container is missing or unique. \item The tag of the container is unique. \item If the selector specifies an id, it matches the id of the container. \item If the selector specifies a tag, it matches the tag of the container. \item If the selector specifies class names, the container has all these classes. }} } \description{ Match a selector node to a container } \keyword{internal} cli/man/demo_spinners.Rd0000644000176200001440000000120714557444176014751 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/spinner.R \name{demo_spinners} \alias{demo_spinners} \title{Show a demo of some (by default all) spinners} \usage{ demo_spinners(which = NULL) } \arguments{ \item{which}{Character vector, which spinners to demo.} } \description{ Each spinner is shown for about 2-3 seconds. } \details{ \if{html}{\out{
}}\preformatted{demo_spinners("clock") }\if{html}{\out{
}} \if{html}{\figure{demo-spinners.svg}} } \seealso{ Other spinners: \code{\link{get_spinner}()}, \code{\link{list_spinners}()}, \code{\link{make_spinner}()} } \concept{spinners} cli/man/diff_str.Rd0000644000176200001440000000223414557444176013705 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/diff.R \name{diff_str} \alias{diff_str} \title{Compare two character strings, character by character} \usage{ diff_str(old, new, max_dist = Inf) } \arguments{ \item{old}{First string, must not be \code{NA}.} \item{new}{Second string, must not be \code{NA}.} \item{max_dist}{Maximum distance to consider, or \code{Inf} for no limit. If the LCS edit distance is larger than this, then the function throws an error with class \code{"cli_diff_max_dist"}. (If you specify \code{Inf} the real limit is \code{.Machine$integer.max} but to reach this the function would have to run a very long time.)} } \value{ A list that is a \code{cli_diff_str} object and also a \code{cli_diff_chr} object, see \link{diff_str} for the details about its structure. } \description{ Characters are defined by UTF-8 graphemes. } \examples{ str1 <- "abcdefghijklmnopqrstuvwxyz" str2 <- "PREabcdefgMIDDLEnopqrstuvwxyzPOST" diff_str(str1, str2) } \seealso{ The diffobj package for a much more comprehensive set of \code{diff}-like tools. Other diff functions in cli: \code{\link{diff_chr}()} } \concept{diff functions in cli} cli/man/is_ansi_tty.Rd0000644000176200001440000000214414557444176014432 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/tty.R \name{is_ansi_tty} \alias{is_ansi_tty} \title{Detect if a stream support ANSI escape characters} \usage{ is_ansi_tty(stream = "auto") } \arguments{ \item{stream}{The stream to inspect or manipulate, an R connection object. It can also be a string, one of \code{"auto"}, \code{"message"}, \code{"stdout"}, \code{"stderr"}. \code{"auto"} will select \code{stdout()} if the session is interactive and there are no sinks, otherwise it will select \code{stderr()}.} } \value{ \code{TRUE} or \code{FALSE}. } \description{ We check that all of the following hold: \itemize{ \item The stream is a terminal. \item The platform is Unix. \item R is not running inside R.app (the macOS GUI). \item R is not running inside RStudio. \item R is not running inside Emacs. \item The terminal is not "dumb". \item \code{stream} is either the standard output or the standard error stream. } } \examples{ is_ansi_tty() } \seealso{ Other terminal capabilities: \code{\link{ansi_hide_cursor}()}, \code{\link{is_dynamic_tty}()} } \concept{terminal capabilities} cli/man/symbol.Rd0000644000176200001440000000124314557444176013411 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/symbol.R \name{symbol} \alias{symbol} \alias{list_symbols} \title{Various handy symbols to use in a command line UI} \format{ A named list, see \code{names(symbol)} for all sign names. } \usage{ symbol list_symbols() } \description{ Various handy symbols to use in a command line UI } \details{ On Windows they have a fallback to less fancy symbols. \code{list_symbols()} prints a table with all symbols to the screen. } \examples{ cat(symbol$tick, " SUCCESS\n", symbol$cross, " FAILURE\n", sep = "") ## All symbols cat(paste(format(names(symbol), width = 20), unlist(symbol)), sep = "\n") } cli/man/hash_md5.Rd0000644000176200001440000000300314752735214013561 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/hash.R \name{hash_md5} \alias{hash_md5} \alias{hash_raw_md5} \alias{hash_obj_md5} \alias{hash_file_md5} \title{MD5 hash} \usage{ hash_md5(x) hash_raw_md5(x) hash_obj_md5(x, serialize_version = 2) hash_file_md5(paths) } \arguments{ \item{x}{Character vector. If not a character vector, then \code{\link[=as.character]{as.character()}} is used to try to coerce it into one. \code{NA} entries will have an \code{NA} hash.} \item{serialize_version}{Workspace format version to use, see \code{\link[base:serialize]{base::serialize()}}.} \item{paths}{Character vector of file names.} } \value{ \code{hash_md5()} returns a character vector of hexadecimal MD5 hashes. \code{hash_raw_md5()} returns a character scalar. \code{hash_obj_md5()} returns a character scalar. } \description{ Calculate the MD5 hash of each element of a character vector. } \details{ \code{hash_raw_md5()} calculates the MD5 hash of the bytes of a raw vector. \code{hash_obj_md5()} calculates the MD5 hash of an R object. The object is serialized into a binary vector first. \code{hash_file_md5()} calculates the MD5 hash of one or more files. } \examples{ hash_md5(c("foo", NA, "bar", "")) } \seealso{ \code{\link[tools:md5sum]{tools::md5sum()}} for a base R MD5 function that works on files. Other hash functions: \code{\link{hash_animal}()}, \code{\link{hash_emoji}()}, \code{\link{hash_sha1}()}, \code{\link{hash_sha256}()}, \code{\link{hash_xxhash}()} } \concept{hash functions} cli/man/ansi_string.Rd0000644000176200001440000000135614557444176014431 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/ansiex.R \name{ansi_string} \alias{ansi_string} \title{Labels a character vector as containing ANSI control codes.} \usage{ ansi_string(x) } \arguments{ \item{x}{A character vector or something that can be coerced into one.} } \value{ A \code{cli_ansi_string} object, a subclass of \code{character}, with the same length and contents as \code{x}. } \description{ This function sets the class of its argument, activating ANSI-string-specific methods such as for printing. } \seealso{ Other low level ANSI functions: \code{\link{ansi_has_any}()}, \code{\link{ansi_hide_cursor}()}, \code{\link{ansi_regex}()}, \code{\link{ansi_strip}()} } \concept{low level ANSI functions} cli/man/cli_alert.Rd0000644000176200001440000001360314752735214014036 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/cli.R \name{cli_alert} \alias{cli_alert} \alias{cli_alert_success} \alias{cli_alert_danger} \alias{cli_alert_warning} \alias{cli_alert_info} \title{CLI alerts} \usage{ cli_alert(text, id = NULL, class = NULL, wrap = FALSE, .envir = parent.frame()) cli_alert_success( text, id = NULL, class = NULL, wrap = FALSE, .envir = parent.frame() ) cli_alert_danger( text, id = NULL, class = NULL, wrap = FALSE, .envir = parent.frame() ) cli_alert_warning( text, id = NULL, class = NULL, wrap = FALSE, .envir = parent.frame() ) cli_alert_info( text, id = NULL, class = NULL, wrap = FALSE, .envir = parent.frame() ) } \arguments{ \item{text}{Text of the alert.} \item{id}{Id of the alert element. Can be used in themes.} \item{class}{Class of the alert element. Can be used in themes.} \item{wrap}{Whether to auto-wrap the text of the alert.} \item{.envir}{Environment to evaluate the glue expressions in.} } \description{ Alerts are typically short status messages. } \details{ \subsection{Success}{ \if{html}{\out{
}}\preformatted{nbld <- 11 tbld <- prettyunits::pretty_sec(5.6) cli_alert_success("Built \{.emph \{nbld\}\} status report\{?s\} in \{tbld\}.") }\if{html}{\out{
}}\if{html}{\out{
#>  Built 11 status reports in 5.6s.                                              
}} } \subsection{Info}{ \if{html}{\out{
}}\preformatted{cfl <- "~/.cache/files/latest.cache" cli_alert_info("Updating cache file \{.path \{cfl\}\}.") }\if{html}{\out{
}}\if{html}{\out{
#>  Updating cache file ~/.cache/files/latest.cache.                              
}} } \subsection{Warning}{ \if{html}{\out{
}}\preformatted{cfl <- "~/.cache/files/latest.cache" cli_alert_warning("Failed to update cache file \{.path \{cfl\}\}.") }\if{html}{\out{
}}\if{html}{\out{
#> ! Failed to update cache file ~/.cache/files/latest.cache.                      
}} } \subsection{Danger}{ \if{html}{\out{
}}\preformatted{cfl <- "~/.config/report.yaml" cli_alert_danger("Cannot validate config file at \{.path \{cfl\}\}.") }\if{html}{\out{
}}\if{html}{\out{
#>  Cannot validate config file at ~/.config/report.yaml.                         
}} } \subsection{Text wrapping}{ Alerts are printed without wrapping, unless you set \code{wrap = TRUE}: \if{html}{\out{
}}\preformatted{cli_alert_info("Data columns: \{.val \{names(mtcars)\}\}.") cli_alert_info("Data columns: \{.val \{names(mtcars)\}\}.", wrap = TRUE) }\if{html}{\out{
}}\if{html}{\out{
#>  Data columns: "mpg", "cyl", "disp", "hp", "drat", "wt", "qsec", "vs", "am", "g
#> ear", and "carb".                                                               
#>  Data columns: "mpg", "cyl", "disp", "hp", "drat", "wt", "qsec",               
#> "vs", "am", "gear", and "carb".                                                 
}} } } \seealso{ These functions supports \link[=inline-markup]{inline markup}. Other functions supporting inline markup: \code{\link{cli_abort}()}, \code{\link{cli_blockquote}()}, \code{\link{cli_bullets}()}, \code{\link{cli_bullets_raw}()}, \code{\link{cli_dl}()}, \code{\link{cli_h1}()}, \code{\link{cli_li}()}, \code{\link{cli_ol}()}, \code{\link{cli_process_start}()}, \code{\link{cli_progress_along}()}, \code{\link{cli_progress_bar}()}, \code{\link{cli_progress_message}()}, \code{\link{cli_progress_output}()}, \code{\link{cli_progress_step}()}, \code{\link{cli_rule}}, \code{\link{cli_status}()}, \code{\link{cli_status_update}()}, \code{\link{cli_text}()}, \code{\link{cli_ul}()}, \code{\link{format_error}()}, \code{\link{format_inline}()} } \concept{functions supporting inline markup} cli/man/cli_status_clear.Rd0000644000176200001440000000334714752735214015424 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/status-bar.R \name{cli_status_clear} \alias{cli_status_clear} \title{Clear the status bar (superseded)} \usage{ cli_status_clear( id = NULL, result = c("clear", "done", "failed"), msg_done = NULL, msg_failed = NULL, .envir = parent.frame() ) } \arguments{ \item{id}{Id of the status bar container to clear. If \code{id} is not the id of the current status bar (because it was overwritten by another status bar container), then the status bar is not cleared. If \code{NULL} (the default) then the status bar is always cleared.} \item{result}{Whether to show a message for success or failure or just clear the status bar.} \item{msg_done}{If not \code{NULL}, then the message to use for successful process termination. This overrides the message given when the status bar was created.} \item{msg_failed}{If not \code{NULL}, then the message to use for failed process termination. This overrides the message give when the status bar was created.} \item{.envir}{Environment to evaluate the glue expressions in. It is also used to auto-clear the status bar if \code{.auto_close} is \code{TRUE}.} } \description{ \strong{The \verb{cli_status_*()} functions are superseded by the \code{\link[=cli_progress_message]{cli_progress_message()}} and \code{\link[=cli_progress_step]{cli_progress_step()}} functions, because they have a better default behavior.} Clear the status bar } \seealso{ The \code{\link[=cli_progress_message]{cli_progress_message()}} and \code{\link[=cli_progress_step]{cli_progress_step()}} functions, for a superior API. Other status bar: \code{\link{cli_process_start}()}, \code{\link{cli_status}()}, \code{\link{cli_status_update}()} } \concept{status bar} cli/man/keypress.Rd0000644000176200001440000000235614557444176013757 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/keypress.R \name{keypress} \alias{keypress} \title{Read a single keypress at the terminal} \usage{ keypress(block = TRUE) } \arguments{ \item{block}{Whether to wait for a key press, if there is none available now.} } \value{ The key pressed, a character scalar. For non-blocking reads \code{NA} is returned if no keys are available. } \description{ It currently only works at Linux/Unix and OSX terminals, and at the Windows command line. see \code{\link{has_keypress_support}}. } \details{ The following special keys are supported: \itemize{ \item Arrow keys: 'up', 'down', 'right', 'left'. \item Function keys: from 'f1' to 'f12'. \item Others: 'home', 'end', 'insert', 'delete', 'pageup', 'pagedown', 'tab', 'enter', 'backspace' (same as 'delete' on OSX keyboards), 'escape'. \item Control with one of the following keys: 'a', 'b', 'c', 'd', 'e', 'f', 'h', 'k', 'l', 'n', 'p', 't', 'u', 'w'. } } \examples{ \dontshow{if (FALSE) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} x <- keypress() cat("You pressed key", x, "\n") \dontshow{\}) # examplesIf} } \seealso{ Other keypress function: \code{\link{has_keypress_support}()} } \concept{keypress function} cli/man/cli_status_update.Rd0000644000176200001440000000413614752735214015615 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/status-bar.R \name{cli_status_update} \alias{cli_status_update} \title{Update the status bar (superseded)} \usage{ cli_status_update( id = NULL, msg = NULL, msg_done = NULL, msg_failed = NULL, .envir = parent.frame() ) } \arguments{ \item{id}{Id of the status bar to update. Defaults to the current status bar container.} \item{msg}{Text to update the status bar with. \code{NULL} if you don't want to change it.} \item{msg_done}{Updated "done" message. \code{NULL} if you don't want to change it.} \item{msg_failed}{Updated "failed" message. \code{NULL} if you don't want to change it.} \item{.envir}{Environment to evaluate the glue expressions in.} } \value{ Id of the status bar container. } \description{ \strong{The \verb{cli_status_*()} functions are superseded by the \code{\link[=cli_progress_message]{cli_progress_message()}} and \code{\link[=cli_progress_step]{cli_progress_step()}} functions, because they have a better default behavior.} Update the status bar } \seealso{ This function supports \link[=inline-markup]{inline markup}. The \code{\link[=cli_progress_message]{cli_progress_message()}} and \code{\link[=cli_progress_step]{cli_progress_step()}} functions, for a superior API. Other status bar: \code{\link{cli_process_start}()}, \code{\link{cli_status}()}, \code{\link{cli_status_clear}()} Other functions supporting inline markup: \code{\link{cli_abort}()}, \code{\link{cli_alert}()}, \code{\link{cli_blockquote}()}, \code{\link{cli_bullets}()}, \code{\link{cli_bullets_raw}()}, \code{\link{cli_dl}()}, \code{\link{cli_h1}()}, \code{\link{cli_li}()}, \code{\link{cli_ol}()}, \code{\link{cli_process_start}()}, \code{\link{cli_progress_along}()}, \code{\link{cli_progress_bar}()}, \code{\link{cli_progress_message}()}, \code{\link{cli_progress_output}()}, \code{\link{cli_progress_step}()}, \code{\link{cli_rule}}, \code{\link{cli_status}()}, \code{\link{cli_text}()}, \code{\link{cli_ul}()}, \code{\link{format_error}()}, \code{\link{format_inline}()} } \concept{functions supporting inline markup} \concept{status bar} cli/man/cli_format.Rd0000644000176200001440000000735414557444176014234 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/format.R \name{cli_format} \alias{cli_format} \alias{cli_format.default} \alias{cli_format.character} \alias{cli_format.numeric} \title{Format a value for printing} \usage{ cli_format(x, style = NULL, ...) \method{cli_format}{default}(x, style = NULL, ...) \method{cli_format}{character}(x, style = NULL, ...) \method{cli_format}{numeric}(x, style = NULL, ...) } \arguments{ \item{x}{The object to format.} \item{style}{List of formatting options, see the individual methods for the style options they support.} \item{...}{Additional arguments for methods.} } \description{ This function can be used directly, or via the \verb{\{.val ...\}} inline style. \verb{\{.val \{expr\}\}} calls \code{cli_format()} automatically on the value of \code{expr}, before styling and collapsing it. } \details{ \subsection{Default style}{ \if{html}{\out{
}}\preformatted{months <- month.name[1:3] cli_text("\{.val \{months\}\}") }\if{html}{\out{
}}\if{html}{\out{
#> "January", "February", and "March"                                              
}} \if{html}{\out{
}}\preformatted{nums <- 1:5 / 7 cli_text("\{.val \{nums\}\}") }\if{html}{\out{
}}\if{html}{\out{
#> 0.142857142857143, 0.285714285714286, 0.428571428571429,                        
#> 0.571428571428571, and 0.714285714285714                                        
}} } \subsection{Styling with themes}{ \if{html}{\out{
}}\preformatted{nums <- 1:5 / 7 divid <- cli_div(theme = list(.val = list(digits = 3))) cli_text("\{.val \{nums\}\}") cli_end(divid) }\if{html}{\out{
}}\if{html}{\out{
#> 0.143, 0.286, 0.429, 0.571, and 0.714                                           
}} It is possible to define new S3 methods for \code{cli_format} and then these will be used automatically for \verb{\{.val ...\}} expressions. \if{html}{\out{
}}\preformatted{cli_format.month <- function(x, style = NULL, ...) \{ x <- encodeString(substr(x, 1, 3), quote = "\\"") NextMethod("cli_format") \} registerS3method("cli_format", "month", cli_format.month) months <- structure(month.name[1:3], class = "month") cli_text("\{.val \{months\}\}") }\if{html}{\out{
}}\if{html}{\out{
#> "Jan", "Feb", and "Mar"                                                         
}} } } \seealso{ \code{\link[=cli_vec]{cli_vec()}} } cli/man/spark_bar.Rd0000644000176200001440000000466714557444176014065 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/spark.R \name{spark_bar} \alias{spark_bar} \title{Draw a sparkline bar graph with unicode block characters} \usage{ spark_bar(x) } \arguments{ \item{x}{A numeric vector between 0 and 1} } \description{ Rendered using \href{https://en.wikipedia.org/wiki/Block_Elements}{block elements}. In most common fixed width fonts these are rendered wider than regular characters which means they are not suitable if you need precise alignment. You might want to avoid sparklines on non-UTF-8 systems, because they do not look good. You can use \code{\link[=is_utf8_output]{is_utf8_output()}} to test for support for them. } \details{ \if{html}{\out{
}}\preformatted{x <- seq(0, 1, length = 6) spark_bar(x) }\if{html}{\out{
}}\if{html}{\out{
#> ▁▂▄▅▇█                                                                          
}} \if{html}{\out{
}}\preformatted{x <- seq(0, 1, length = 6) spark_bar(sample(x)) }\if{html}{\out{
}}\if{html}{\out{
#> ▅▁█▄▇▂                                                                          
}} \if{html}{\out{
}}\preformatted{spark_bar(seq(0, 1, length = 8)) }\if{html}{\out{
}}\if{html}{\out{
#> ▁▂▃▄▅▆▇█                                                                        
}} \code{NA}s are left out: \if{html}{\out{
}}\preformatted{spark_bar(c(0, NA, 0.5, NA, 1)) }\if{html}{\out{
}}\if{html}{\out{
#> ▁ ▄ █                                                                           
}} } \seealso{ \code{\link[=spark_line]{spark_line()}} } cli/man/utf8_graphemes.Rd0000644000176200001440000000144514557444176015031 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/utf8.R \name{utf8_graphemes} \alias{utf8_graphemes} \title{Break an UTF-8 character vector into grapheme clusters} \usage{ utf8_graphemes(x) } \arguments{ \item{x}{Character vector.} } \value{ List of characters vectors, the grapheme clusters of the input string. } \description{ Break an UTF-8 character vector into grapheme clusters } \examples{ # Five grapheme clusters str <- paste0( "\U0001f477\U0001f3ff\u200d\u2640\ufe0f", "\U0001f477\U0001f3ff", "\U0001f477\u200d\u2640\ufe0f", "\U0001f477\U0001f3fb", "\U0001f477\U0001f3ff") cat(str, "\n") chrs <- utf8_graphemes(str) } \seealso{ Other UTF-8 string manipulation: \code{\link{utf8_nchar}()}, \code{\link{utf8_substr}()} } \concept{UTF-8 string manipulation} cli/man/ansi_hide_cursor.Rd0000644000176200001440000000246114557444176015427 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/tty.R \name{ansi_hide_cursor} \alias{ansi_hide_cursor} \alias{ansi_show_cursor} \alias{ansi_with_hidden_cursor} \title{Hide/show cursor in a terminal} \usage{ ansi_hide_cursor(stream = "auto") ansi_show_cursor(stream = "auto") ansi_with_hidden_cursor(expr, stream = "auto") } \arguments{ \item{stream}{The stream to inspect or manipulate, an R connection object. It can also be a string, one of \code{"auto"}, \code{"message"}, \code{"stdout"}, \code{"stderr"}. \code{"auto"} will select \code{stdout()} if the session is interactive and there are no sinks, otherwise it will select \code{stderr()}.} \item{expr}{R expression to evaluate.} } \description{ This only works in terminal emulators. In other environments, it does nothing. } \details{ \code{ansi_hide_cursor()} hides the cursor. \code{ansi_show_cursor()} shows the cursor. \code{ansi_with_hidden_cursor()} temporarily hides the cursor for evaluating an expression. } \seealso{ Other terminal capabilities: \code{\link{is_ansi_tty}()}, \code{\link{is_dynamic_tty}()} Other low level ANSI functions: \code{\link{ansi_has_any}()}, \code{\link{ansi_regex}()}, \code{\link{ansi_string}()}, \code{\link{ansi_strip}()} } \concept{low level ANSI functions} \concept{terminal capabilities} cli/man/inline-markup.Rd0000644000176200001440000003462614752735214014663 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/cliapp-docs.R \name{inline-markup} \alias{inline-markup} \title{About inline markup in the semantic cli} \description{ To learn how to use cli’s semantic markup, start with the ‘Building a semantic CLI’ article at \url{https://cli.r-lib.org}. } \section{Command substitution}{ All text emitted by cli supports glue interpolation. Expressions enclosed by braces will be evaluated as R code. See \code{\link[glue:glue]{glue::glue()}} for details. In addition to regular glue interpolation, cli can also add classes to parts of the text, and these classes can be used in themes. For example \if{html}{\out{
}}\preformatted{cli_text("This is \{.emph important\}.") }\if{html}{\out{
}}\if{html}{\out{
#> This is important.                                                              
}} adds a class to the "important" word, class \code{"emph"}. Note that in this case the string within the braces is usually not a valid R expression. If you want to mix classes with interpolation, add another pair of braces: \if{html}{\out{
}}\preformatted{adjective <- "great" cli_text("This is \{.emph \{adjective\}\}.") }\if{html}{\out{
}}\if{html}{\out{
#> This is great.                                                                  
}} An inline class will always create a \code{span} element internally. So in themes, you can use the \code{span.emph} CSS selector to change how inline text is emphasized: \if{html}{\out{
}}\preformatted{cli_div(theme = list(span.emph = list(color = "red"))) adjective <- "nice and red" cli_text("This is \{.emph \{adjective\}\}.") }\if{html}{\out{
}}\if{html}{\out{
#> This is nice and red.                                                           
}} } \section{Classes}{ The default theme defines the following inline classes: \itemize{ \item \code{arg} for a function argument. \item \code{cls} for an S3, S4, R6 or other class name. \item \code{code} for a piece of code. \item \code{dt} is used for the terms in a definition list (\code{\link[=cli_dl]{cli_dl()}}). \item \code{dd} is used for the descriptions in a definition list (\code{\link[=cli_dl]{cli_dl()}}). \item \code{email} for an email address. If the terminal supports ANSI hyperlinks (e.g. RStudio, iTerm2, etc.), then cli creates a clickable link. See \link{links} for more information about cli hyperlinks. \item \code{emph} for emphasized text. \item \code{envvar} for the name of an environment variable. \item \code{field} for a generic field, e.g. in a named list. \item \code{file} for a file name. If the terminal supports ANSI hyperlinks (e.g. RStudio, iTerm2, etc.), then cli creates a clickable link that opens the file in RStudio or with the default app for the file type. See \link{links} for more information about cli hyperlinks. \item \code{fn} for a function name. If it is in the \code{package::function_name} form, and the terminal supports ANSI hyperlinks (e.g. RStudio, iTerm2, etc.), then cli creates a clickable link. See \link{links} for more information about cli hyperlinks. \item \code{fun} same as \code{fn}. \item \code{help} is a help page of a \emph{function}. If the terminal supports ANSI hyperlinks to help pages (e.g. RStudio), then cli creates a clickable link. It supports link text. See \link{links} for more information about cli hyperlinks. \item \code{href} creates a hyperlink, potentially with a link text. If the terminal supports ANSI hyperlinks (e.g. RStudio, iTerm2, etc.), then cli creates a clickable link. See \link{links} for more information about cli hyperlinks. \item \code{kbd} for a keyboard key. \item \code{key} same as \code{kbd}. \item \code{obj_type_friendly} formats the type of an R object in a readable way, and it should be used with \code{{}}, see an example below. \item \code{or} changes the string that separates the last two elements of collapsed vectors (see below) from "and" to "or". \item \code{path} for a path (the same as \code{file} in the default theme). \item \code{pkg} for a package name. \item \code{run} is an R expression, that is potentially clickable if the terminal supports ANSI hyperlinks to runnable code (e.g. RStudio). It supports link text. See \link{links} for more information about cli hyperlinks. \item \code{str} for a double quoted string escaped by \code{\link[base:encodeString]{base::encodeString()}}. \item \code{strong} for strong importance. \item \code{topic} is a help page of a \emph{topic}. If the terminal supports ANSI hyperlinks to help pages (e.g. RStudio), then cli creates a clickable link. It supports link text. See \link{links} for more information about cli hyperlinks. \item \code{type} formats the type of an R object in a readable way, and it should be used with \code{{}}, see an example below. \item \code{url} for a URL. If the terminal supports ANSI hyperlinks (e.g. RStudio, iTerm2, etc.), then cli creates a clickable link. See \link{links} for more information about cli hyperlinks. \item \code{var} for a variable name. \item \code{val} for a generic "value". \item \code{vignette} is a vignette. If the terminal supports ANSI hyperlinks to help pages (e.g. RStudio), then cli creates a clickable link. It supports link text. See \link{links} for more information about cli hyperlinks. } \if{html}{\out{
}}\preformatted{ul <- cli_ul() cli_li("\{.emph Emphasized\} text.") cli_li("\{.strong Strong\} importance.") cli_li("A piece of code: \{.code sum(a) / length(a)\}.") cli_li("A package name: \{.pkg cli\}.") cli_li("A function name: \{.fn cli_text\}.") cli_li("A keyboard key: press \{.kbd ENTER\}.") cli_li("A file name: \{.file /usr/bin/env\}.") cli_li("An email address: \{.email bugs.bunny@acme.com\}.") cli_li("A URL: \{.url https://example.com\}.") cli_li("An environment variable: \{.envvar R_LIBS\}.") cli_li("`mtcars` is \{.obj_type_friendly \{mtcars\}\}") cli_end(ul) }\if{html}{\out{
}}\if{html}{\out{
#> • Emphasized text.                                                              
#> • Strong importance.                                                            
#> • A piece of code: `sum(a) / length(a)`.                                        
#> • A package name: cli.                                                          
#> • A function name: `cli_text()`.                                                
#> • A keyboard key: press [ENTER].                                                
#> • A file name: /usr/bin/env.                                                    
#> • An email address: bugs.bunny@acme.com.                                        
#> • A URL: <https://example.com>.                                                 
#> • An environment variable: `R_LIBS`.                                            
#> • `mtcars` is a data frame                                                      
}} You can add new classes by defining them in the theme, and then using them. \if{html}{\out{
}}\preformatted{cli_div(theme = list( span.myclass = list(color = "lightgrey"), "span.myclass" = list(before = "<<"), "span.myclass" = list(after = ">>"))) cli_text("This is \{.myclass in angle brackets\}.") cli_end() }\if{html}{\out{
}}\if{html}{\out{
#> This is <<in angle brackets>>.                                                  
}} \subsection{Highlighting weird-looking values}{ Often it is useful to highlight a weird file or path name, e.g. one that starts or ends with space characters. The built-in theme does this for \code{.file}, \code{.path} and \code{.email} by default. You can highlight any string inline by adding the \code{.q} class to it. The current highlighting algorithm \itemize{ \item adds single quotes to the string if it does not start or end with an alphanumeric character, underscore, dot or forward slash. \item Highlights the background colors of leading and trailing spaces on terminals that support ANSI colors. } } } \section{Collapsing inline vectors}{ When cli performs inline text formatting, it automatically collapses glue substitutions, after formatting. This is handy to create lists of files, packages, etc. \if{html}{\out{
}}\preformatted{pkgs <- c("pkg1", "pkg2", "pkg3") cli_text("Packages: \{pkgs\}.") cli_text("Packages: \{.pkg \{pkgs\}\}.") }\if{html}{\out{
}}\if{html}{\out{
#> Packages: pkg1, pkg2, and pkg3.                                                 
#> Packages: pkg1, pkg2, and pkg3.                                                 
}} Class names are collapsed differently by default \if{html}{\out{
}}\preformatted{x <- Sys.time() cli_text("Hey, \{.var x\} has class \{.cls \{class(x)\}\}.") }\if{html}{\out{
}}\if{html}{\out{
#> Hey, `x` has class <POSIXct/POSIXt>.                                            
}} By default cli truncates long vectors. The truncation limit is by default twenty elements, but you can change it with the \code{vec-trunc} style. \if{html}{\out{
}}\preformatted{nms <- cli_vec(names(mtcars), list("vec-trunc" = 5)) cli_text("Column names: \{nms\}.") }\if{html}{\out{
}}\if{html}{\out{
#> Column names: mpg, cyl, disp, …, gear, and carb.                                
}} } \section{Formatting values}{ The \code{val} inline class formats values. By default (c.f. the built-in theme), it calls the \code{\link[=cli_format]{cli_format()}} generic function, with the current style as the argument. See \code{\link[=cli_format]{cli_format()}} for examples. \code{str} is for formatting strings, it uses \code{\link[base:encodeString]{base::encodeString()}} with double quotes. } \section{Escaping \verb{\{} and \verb{\}}}{ It might happen that you want to pass a string to \verb{cli_*} functions, and you do \emph{not} want command substitution in that string, because it might contain \verb{\{} and \verb{\}} characters. The simplest solution for this is to refer to the string from a template: \if{html}{\out{
}}\preformatted{msg <- "Error in if (ncol(dat$y)) \{: argument is of length zero" cli_alert_warning("\{msg\}") }\if{html}{\out{
}}\if{html}{\out{
#> ! Error in if (ncol(dat$y)) \{: argument is of length zero                       
}} If you want to explicitly escape \verb{\{} and \verb{\}} characters, just double them: \if{html}{\out{
}}\preformatted{cli_alert_warning("A warning with \{\{ braces \}\}.") }\if{html}{\out{
}}\if{html}{\out{
#> ! A warning with \{ braces \}.                                                    
}} See also examples below. } \section{Pluralization}{ All cli commands that emit text support pluralization. Some examples: \if{html}{\out{
}}\preformatted{ndirs <- 1 nfiles <- 13 pkgs <- c("pkg1", "pkg2", "pkg3") cli_alert_info("Found \{ndirs\} director\{?y/ies\} and \{nfiles\} file\{?s\}.") cli_text("Will install \{length(pkgs)\} package\{?s\}: \{.pkg \{pkgs\}\}") }\if{html}{\out{
}}\if{html}{\out{
#>  Found 1 directory and 13 files.                                               
#> Will install 3 packages: pkg1, pkg2, and pkg3                                   
}} See \link{pluralization} for details. } \section{Wrapping}{ Most cli containers wrap the text to width the container's width, while observing margins requested by the theme. To avoid a line break, you can use the UTF_8 non-breaking space character: \verb{\\u00a0}. cli will not break a line here. To force a line break, insert a form feed character: \verb{\\f} or \verb{\\u000c}. cli will insert a line break there. } cli/man/cli_par.Rd0000644000176200001440000000440714557444176013522 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/cli.R \name{cli_par} \alias{cli_par} \title{CLI paragraph} \usage{ cli_par(id = NULL, class = NULL, .auto_close = TRUE, .envir = parent.frame()) } \arguments{ \item{id}{Element id, a string. If \code{NULL}, then a new id is generated and returned.} \item{class}{Class name, sting. Can be used in themes.} \item{.auto_close}{Whether to close the container, when the calling function finishes (or \code{.envir} is removed, if specified).} \item{.envir}{Environment to evaluate the glue expressions in. It is also used to auto-close the container if \code{.auto_close} is \code{TRUE}.} } \value{ The id of the new container element, invisibly. } \description{ The builtin theme leaves an empty line between paragraphs. See also \link{containers}. } \details{ \if{html}{\out{
}}\preformatted{clifun <- function() \{ cli_par() cli_text(cli:::lorem_ipsum()) \} clifun() clifun() }\if{html}{\out{
}}\if{html}{\out{
#> Sunt anim ullamco Lorem qui mollit anim est in deserunt adipisicing.            
#> Enim deserunt laborum ad qui qui. Anim esse non anim magna Lorem                
#> consequat dolore labore cupidatat magna et. Esse nulla eiusmod Lorem            
#> exercitation cupidatat velit enim exercitation excepteur non officia            
#> incididunt. Id laborum dolore commodo Lorem esse ea sint proident.              
#>                                                                                 
#> Fugiat mollit in Lorem velit qui exercitation ipsum consectetur ad              
#> nisi ut eu do ullamco. Mollit officia reprehenderit culpa Lorem est             
#> reprehenderit excepteur enim magna incididunt ea. Irure nisi ad                 
#> exercitation deserunt enim anim excepteur quis minim laboris veniam             
#> nulla pariatur. Enim irure aute nulla irure qui non. Minim velit                
#> proident sunt sint. Proident sit occaecat ex aute.                              
#>                                                                                 
}} } cli/man/get_spinner.Rd0000644000176200001440000000253714557444176014430 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/spinner.R \name{get_spinner} \alias{get_spinner} \title{Character vector to put a spinner on the screen} \usage{ get_spinner(which = NULL) } \arguments{ \item{which}{The name of the chosen spinner. If \code{NULL}, then the default is used, which can be customized via the \code{cli.spinner_unicode}, \code{cli.spinner_ascii} and \code{cli.spinner} options. (The latter applies to both Unicode and ASCII displays. These options can be set to the name of a built-in spinner, or to a list that has an entry called \code{frames}, a character vector of frames.} } \value{ A list with entries: \code{name}, \code{interval}: the suggested update interval in milliseconds and \code{frames}: the character vector of the spinner's frames. } \description{ \code{cli} contains many different spinners, you choose one according to your taste. } \details{ \if{html}{\out{
}}\preformatted{options(cli.spinner = "hearts") fun <- function() \{ cli_progress_bar("Spinning") for (i in 1:100) \{ Sys.sleep(4/100) cli_progress_update() \} \} fun() options(cli.spinner = NULL) }\if{html}{\out{
}} \if{html}{\figure{get-spinner.svg}} } \seealso{ Other spinners: \code{\link{demo_spinners}()}, \code{\link{list_spinners}()}, \code{\link{make_spinner}()} } \concept{spinners} cli/man/cli_fmt.Rd0000644000176200001440000000132514557444176013522 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/cli.R \name{cli_fmt} \alias{cli_fmt} \title{Capture the output of cli functions instead of printing it} \usage{ cli_fmt(expr, collapse = FALSE, strip_newline = FALSE) } \arguments{ \item{expr}{Expression to evaluate, containing \verb{cli_*()} calls, typically.} \item{collapse}{Whether to collapse the output into a single character scalar, or return a character vector with one element for each line.} \item{strip_newline}{Whether to strip the trailing newline.} } \description{ Capture the output of cli functions instead of printing it } \examples{ cli_fmt({ cli_alert_info("Loading data file") cli_alert_success("Loaded data file") }) } cli/man/cli_code.Rd0000644000176200001440000000534014752364056013642 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/cli.R \name{cli_code} \alias{cli_code} \title{A block of code} \usage{ cli_code( lines = NULL, ..., language = "R", .auto_close = TRUE, .envir = environment() ) } \arguments{ \item{lines}{Character vector, each line will be a line of code, and newline characters also create new lines. Note that \emph{no} glue substitution is performed on the code.} \item{...}{More character vectors, they are appended to \code{lines}.} \item{language}{Programming language. This is also added as a class, in addition to \code{code}.} \item{.auto_close}{Passed to \code{cli_div()} when creating the container of the code. By default the code container is closed after emitting \code{lines} and \code{...} via \code{cli_verbatim()}. You can keep that container open with \code{.auto_close} and/or \code{.envir}, and then calling \code{cli_verbatim()} to add (more) code. Note that the code will be formatted and syntax highlighted separately for each \code{cli_verbatim()} call.} \item{.envir}{Passed to \code{cli_div()} when creating the container of the code.} } \value{ The id of the container that contains the code. } \description{ A helper function that creates a \code{div} with class \code{code} and then calls \code{cli_verbatim()} to output code lines. The builtin theme formats these containers specially. In particular, it adds syntax highlighting to valid R code. } \details{ \if{html}{\out{
}}\preformatted{myfun <- function() \{ message("Just an example function") graphics::pairs(iris, col = 1:4) \} cli_code(format(myfun)) }\if{html}{\out{
}}\if{html}{\out{
#> function ()                                                                     
#> \{                                                                               
#>     message("Just an example function")                                         
#>     graphics::pairs(iris, col = 1:4)                                            
#> \}                                                                               
}} } cli/man/utf8_substr.Rd0000644000176200001440000000200714557444176014373 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/utf8.R \name{utf8_substr} \alias{utf8_substr} \title{Substring of an UTF-8 string} \usage{ utf8_substr(x, start, stop) } \arguments{ \item{x}{Character vector.} \item{start}{Starting index or indices, recycled to match the length of \code{x}.} \item{stop}{Ending index or indices, recycled to match the length of \code{x}.} } \value{ Character vector of the same length as \code{x}, containing the requested substrings. } \description{ This function uses grapheme clusters instead of Unicode code points in UTF-8 strings. } \examples{ # Five grapheme clusters, select the middle three str <- paste0( "\U0001f477\U0001f3ff\u200d\u2640\ufe0f", "\U0001f477\U0001f3ff", "\U0001f477\u200d\u2640\ufe0f", "\U0001f477\U0001f3fb", "\U0001f477\U0001f3ff") cat(str) str24 <- utf8_substr(str, 2, 4) cat(str24) } \seealso{ Other UTF-8 string manipulation: \code{\link{utf8_graphemes}()}, \code{\link{utf8_nchar}()} } \concept{UTF-8 string manipulation} cli/man/hash_xxhash.Rd0000644000176200001440000000347214752735214014411 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/hash.R \name{hash_xxhash} \alias{hash_xxhash} \alias{hash_raw_xxhash} \alias{hash_obj_xxhash} \alias{hash_file_xxhash} \alias{hash_xxhash64} \alias{hash_raw_xxhash64} \alias{hash_obj_xxhash64} \alias{hash_file_xxhash64} \title{xxHash} \usage{ hash_xxhash(x) hash_raw_xxhash(x) hash_obj_xxhash(x, serialize_version = 2) hash_file_xxhash(paths) hash_xxhash64(x) hash_raw_xxhash64(x) hash_obj_xxhash64(x, serialize_version = 2) hash_file_xxhash64(paths) } \arguments{ \item{x}{Character vector. If not a character vector, then \code{\link[=as.character]{as.character()}} is used to try to coerce it into one. \code{NA} entries will have an \code{NA} hash.} \item{serialize_version}{Workspace format version to use, see \code{\link[base:serialize]{base::serialize()}}.} \item{paths}{Character vector of file names.} } \value{ \code{hash_xxhash()} returns a character vector of hexadecimal xxHash hashes. \code{hash_raw_xxhash()} returns a character scalar. \code{hash_obj_xxhash()} returns a character scalar. \code{hash_file_xxhash()} returns a character vector of xxHash hashes. } \description{ Extremely fast hash algorithm. } \details{ \code{hash_raw_xxhash()} calculates the xxHash hash of the bytes of a raw vector. \code{hash_obj_xxhash()} calculates the xxHash hash of an R object. The object is serialized into a binary vector first. \code{hash_file_xxhash()} calculates the xxHash hash of one or more files. The \code{64} functions caculate the 64 bit variant of xxHash. Otherwise they work the same. } \examples{ hash_xxhash(c("foo", NA, "bar", "")) } \seealso{ Other hash functions: \code{\link{hash_animal}()}, \code{\link{hash_emoji}()}, \code{\link{hash_md5}()}, \code{\link{hash_sha1}()}, \code{\link{hash_sha256}()} } \concept{hash functions} cli/man/cli.Rd0000644000176200001440000000370314557444176012656 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/cli.R \name{cli} \alias{cli} \title{Compose multiple cli functions} \usage{ cli(expr) } \arguments{ \item{expr}{Expression that contains \verb{cli_*} calls. Their output is collected and sent as a single message.} } \value{ Nothing. } \description{ \code{cli()} will record all \verb{cli_*} calls in \code{expr}, and emit them together in a single message. This is useful if you want to built a larger piece of output from multiple \verb{cli_*} calls. } \details{ Use this function to build a more complex piece of CLI that would not make sense to show in pieces. \if{html}{\out{
}}\preformatted{cli(\{ cli_h1("Title") cli_h2("Subtitle") cli_ul(c("this", "that", "end")) \}) }\if{html}{\out{
}}\if{html}{\out{
#>                                                                                 
#> ── Title ─────────────────────────────────────────────────────────────          
#>                                                                                 
#> ── Subtitle ──                                                                  
#>                                                                                 
#> • this                                                                          
#> • that                                                                          
#> • end                                                                           
}} } cli/man/cli_progress_along.Rd0000644000176200001440000000761614752735214015762 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/progress-along.R \name{cli_progress_along} \alias{cli_progress_along} \title{Add a progress bar to a mapping function or for loop} \usage{ cli_progress_along( x, name = NULL, total = length(x), ..., .envir = parent.frame() ) } \arguments{ \item{x}{Sequence to add the progress bar to.} \item{name}{Name of the progress bar, a label, passed to \code{\link[=cli_progress_bar]{cli_progress_bar()}}.} \item{total}{Passed to \code{\link[=cli_progress_bar]{cli_progress_bar()}}.} \item{...}{Passed to \code{\link[=cli_progress_bar]{cli_progress_bar()}}.} \item{.envir}{Passed to \code{\link[=cli_progress_bar]{cli_progress_bar()}}.} } \value{ An index vector from 1 to \code{length(x)} that triggers progress updates as you iterate over it. } \description{ Note that this function is currently experimental! Use \code{cli_progress_along()} in a mapping function or in a for loop, to add a progress bar. It uses \code{\link[=cli_progress_bar]{cli_progress_bar()}} internally. } \details{ \subsection{\code{for} loop}{ A \code{for} loop with \code{cli_progress_along()} looks like this: \if{html}{\out{
}}\preformatted{for (i in cli_progress_along(seq)) \{ ... \} }\if{html}{\out{
}} A complete example: \if{html}{\out{
}}\preformatted{clifun <- function() \{ for (i in cli_progress_along(1:100, "Downloading")) \{ Sys.sleep(4/100) \} \} clifun() }\if{html}{\out{
}} \if{html}{\figure{progress-along-1.svg}} } \subsection{\code{lapply()} and other mapping functions}{ They will look like this: \if{html}{\out{
}}\preformatted{lapply(cli_progress_along(X), function(i) ...) }\if{html}{\out{
}} A complete example: \if{html}{\out{
}}\preformatted{res <- lapply(cli_progress_along(1:100, "Downloading"), function(i) \{ Sys.sleep(4/100) \}) }\if{html}{\out{
}} \if{html}{\figure{progress-along-2.svg}} } \subsection{Custom format string}{ \if{html}{\out{
}}\preformatted{clifun <- function() \{ for (i in cli_progress_along(1:100, format = "Downloading data file \{cli::pb_current\}")) \{ Sys.sleep(4/100) \} \} clifun() }\if{html}{\out{
}} \if{html}{\figure{progress-along-3.svg}} } \subsection{Breaking out of loops}{ Note that if you use \code{break} in the \code{for} loop, you probably want to terminate the progress bar explicitly when breaking out of the loop, or right after the loop: \if{html}{\out{
}}\preformatted{for (i in cli_progress_along(seq)) \{ ... if (cond) cli_progress_done() && break ... \} }\if{html}{\out{
}} } } \seealso{ This function supports \link[=inline-markup]{inline markup}. \code{\link[=cli_progress_bar]{cli_progress_bar()}} and the traditional progress bar API. Other progress bar functions: \code{\link{cli_progress_bar}()}, \code{\link{cli_progress_builtin_handlers}()}, \code{\link{cli_progress_message}()}, \code{\link{cli_progress_num}()}, \code{\link{cli_progress_output}()}, \code{\link{cli_progress_step}()}, \code{\link{cli_progress_styles}()}, \code{\link{progress-variables}} Other functions supporting inline markup: \code{\link{cli_abort}()}, \code{\link{cli_alert}()}, \code{\link{cli_blockquote}()}, \code{\link{cli_bullets}()}, \code{\link{cli_bullets_raw}()}, \code{\link{cli_dl}()}, \code{\link{cli_h1}()}, \code{\link{cli_li}()}, \code{\link{cli_ol}()}, \code{\link{cli_process_start}()}, \code{\link{cli_progress_bar}()}, \code{\link{cli_progress_message}()}, \code{\link{cli_progress_output}()}, \code{\link{cli_progress_step}()}, \code{\link{cli_rule}}, \code{\link{cli_status}()}, \code{\link{cli_status_update}()}, \code{\link{cli_text}()}, \code{\link{cli_ul}()}, \code{\link{format_error}()}, \code{\link{format_inline}()} } \concept{functions supporting inline markup} \concept{progress bar functions} cli/man/ruler.Rd0000644000176200001440000000047414557444176013242 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/ruler.R \name{ruler} \alias{ruler} \title{Print the helpful ruler to the screen} \usage{ ruler(width = console_width()) } \arguments{ \item{width}{Ruler width.} } \description{ Print the helpful ruler to the screen } \examples{ ruler() } cli/man/figures/0000755000176200001440000000000014752364056013254 5ustar liggesuserscli/man/figures/progress-along-1.svg0000644000176200001440000003363014752364056017102 0ustar liggesusersDownloading■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■100%|ETA:0sDownloading0%|ETA:?Downloading■■■6%|ETA:4sDownloading■■■■11%|ETA:4sDownloading■■■■■15%|ETA:4sDownloading■■■■■■■19%|ETA:4sDownloading■■■■■■■■24%|ETA:4sDownloading■■■■■■■■■28%|ETA:3sDownloading■■■■■■■■■■■32%|ETA:3sDownloading■■■■■■■■■■■■37%|ETA:3sDownloading■■■■■■■■■■■■■■42%|ETA:3sDownloading■■■■■■■■■■■■■■■46%|ETA:2sDownloading■■■■■■■■■■■■■■■■50%|ETA:2sDownloading■■■■■■■■■■■■■■■■■55%|ETA:2sDownloading■■■■■■■■■■■■■■■■■■■59%|ETA:2sDownloading■■■■■■■■■■■■■■■■■■■■64%|ETA:2sDownloading■■■■■■■■■■■■■■■■■■■■■68%|ETA:1sDownloading■■■■■■■■■■■■■■■■■■■■■■■72%|ETA:1sDownloading■■■■■■■■■■■■■■■■■■■■■■■■77%|ETA:1sDownloading■■■■■■■■■■■■■■■■■■■■■■■■■81%|ETA:1sDownloading■■■■■■■■■■■■■■■■■■■■■■■■■■■85%|ETA:1sDownloading■■■■■■■■■■■■■■■■■■■■■■■■■■■■90%|ETA:0sDownloading■■■■■■■■■■■■■■■■■■■■■■■■■■■■■94%|ETA:0sDownloading■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■98%|ETA:0scli/man/figures/README/0000755000176200001440000000000014557444176014216 5ustar liggesuserscli/man/figures/README/glue.svg0000644000176200001440000000257114557444176015700 0ustar liggesusersDownloaded123.14MBin1.3scli/man/figures/README/alert-success-dark.svg0000644000176200001440000000237214557444176020437 0ustar liggesusersDownloaded3packages.cli/man/figures/README/lists.svg0000644000176200001440000000333214557444176016076 0ustar liggesusers1.Item1Subitem1Subitem22.Item2cli/man/figures/README/alert-success.svg0000644000176200001440000000237514557444176017523 0ustar liggesusersDownloaded3packages.cli/man/figures/README/alert.svg0000644000176200001440000000230214557444176016043 0ustar liggesusersAgenericalertcli/man/figures/README/plurals.svg0000644000176200001440000000266414557444176016431 0ustar liggesusersFound3filesand1directory.cli/man/figures/README/lists-dark.svg0000644000176200001440000000332714557444176017021 0ustar liggesusers1.Item1Subitem1Subitem22.Item2cli/man/figures/README/plurals-dark.svg0000644000176200001440000000266114557444176017345 0ustar liggesusersFound3filesand1directory.cli/man/figures/README/h3.svg0000644000176200001440000000222114557444176015246 0ustar liggesusers──Heading3cli/man/figures/README/h2.svg0000644000176200001440000000244014557444176015250 0ustar liggesusers──Heading2──cli/man/figures/README/h1-dark.svg0000644000176200001440000000300214557444176016161 0ustar liggesusers──Heading1───────────────────────────────────────────────────────────────────cli/man/figures/README/alert-warning.svg0000644000176200001440000000305714557444176017516 0ustar liggesusers!CannotreachGitHub,usinglocaldatabasecache.cli/man/figures/README/h3-dark.svg0000644000176200001440000000221614557444176016171 0ustar liggesusers──Heading3cli/man/figures/README/progress-dark.svg0000644000176200001440000012063214557444176017526 0ustar liggesusersCleaningdata■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■100%|ETA:0sCleaningdata1%|ETA:6sCleaningdata■■2%|ETA:6sCleaningdata■■4%|ETA:6sCleaningdata■■■5%|ETA:6sCleaningdata■■■6%|ETA:6sCleaningdata■■■8%|ETA:6sCleaningdata■■■■10%|ETA:6sCleaningdata■■■■11%|ETA:6sCleaningdata■■■■■13%|ETA:6sCleaningdata■■■■■14%|ETA:6sCleaningdata■■■■■■16%|ETA:6sCleaningdata■■■■■■17%|ETA:6sCleaningdata■■■■■■■19%|ETA:5sCleaningdata■■■■■■■21%|ETA:5sCleaningdata■■■■■■■■22%|ETA:5sCleaningdata■■■■■■■■24%|ETA:5sCleaningdata■■■■■■■■■25%|ETA:5sCleaningdata■■■■■■■■■27%|ETA:5sCleaningdata■■■■■■■■■28%|ETA:5sCleaningdata■■■■■■■■■■29%|ETA:5sCleaningdata■■■■■■■■■■31%|ETA:5sCleaningdata■■■■■■■■■■■32%|ETA:5sCleaningdata■■■■■■■■■■■34%|ETA:4sCleaningdata■■■■■■■■■■■35%|ETA:4sCleaningdata■■■■■■■■■■■■37%|ETA:4sCleaningdata■■■■■■■■■■■■■39%|ETA:4sCleaningdata■■■■■■■■■■■■■40%|ETA:4sCleaningdata■■■■■■■■■■■■■■42%|ETA:4sCleaningdata■■■■■■■■■■■■■■43%|ETA:4sCleaningdata■■■■■■■■■■■■■■■45%|ETA:4sCleaningdata■■■■■■■■■■■■■■■46%|ETA:4sCleaningdata■■■■■■■■■■■■■■■48%|ETA:3sCleaningdata■■■■■■■■■■■■■■■■50%|ETA:3sCleaningdata■■■■■■■■■■■■■■■■51%|ETA:3sCleaningdata■■■■■■■■■■■■■■■■■53%|ETA:3sCleaningdata■■■■■■■■■■■■■■■■■54%|ETA:3sCleaningdata■■■■■■■■■■■■■■■■■■56%|ETA:3sCleaningdata■■■■■■■■■■■■■■■■■■57%|ETA:3sCleaningdata■■■■■■■■■■■■■■■■■■■59%|ETA:3sCleaningdata■■■■■■■■■■■■■■■■■■■60%|ETA:3sCleaningdata■■■■■■■■■■■■■■■■■■■■62%|ETA:3sCleaningdata■■■■■■■■■■■■■■■■■■■■63%|ETA:2sCleaningdata■■■■■■■■■■■■■■■■■■■■■65%|ETA:2sCleaningdata■■■■■■■■■■■■■■■■■■■■■66%|ETA:2sCleaningdata■■■■■■■■■■■■■■■■■■■■■68%|ETA:2sCleaningdata■■■■■■■■■■■■■■■■■■■■■■69%|ETA:2sCleaningdata■■■■■■■■■■■■■■■■■■■■■■70%|ETA:2sCleaningdata■■■■■■■■■■■■■■■■■■■■■■■72%|ETA:2sCleaningdata■■■■■■■■■■■■■■■■■■■■■■■74%|ETA:2sCleaningdata■■■■■■■■■■■■■■■■■■■■■■■75%|ETA:2sCleaningdata■■■■■■■■■■■■■■■■■■■■■■■■77%|ETA:2sCleaningdata■■■■■■■■■■■■■■■■■■■■■■■■78%|ETA:1sCleaningdata■■■■■■■■■■■■■■■■■■■■■■■■■80%|ETA:1sCleaningdata■■■■■■■■■■■■■■■■■■■■■■■■■81%|ETA:1sCleaningdata■■■■■■■■■■■■■■■■■■■■■■■■■■83%|ETA:1sCleaningdata■■■■■■■■■■■■■■■■■■■■■■■■■■84%|ETA:1sCleaningdata■■■■■■■■■■■■■■■■■■■■■■■■■■■86%|ETA:1sCleaningdata■■■■■■■■■■■■■■■■■■■■■■■■■■■87%|ETA:1sCleaningdata■■■■■■■■■■■■■■■■■■■■■■■■■■■■89%|ETA:1sCleaningdata■■■■■■■■■■■■■■■■■■■■■■■■■■■■91%|ETA:1sCleaningdata■■■■■■■■■■■■■■■■■■■■■■■■■■■■■92%|ETA:1sCleaningdata■■■■■■■■■■■■■■■■■■■■■■■■■■■■■94%|ETA:0sCleaningdata■■■■■■■■■■■■■■■■■■■■■■■■■■■■■95%|ETA:0sCleaningdata■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■97%|ETA:0sCleaningdata■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■98%|ETA:0scli/man/figures/README/alert-info-dark.svg0000644000176200001440000000262014557444176017716 0ustar liggesusersReopeneddatabase<example.com:port>.cli/man/figures/README/progress.svg0000644000176200001440000012063514557444176016612 0ustar liggesusersCleaningdata■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■100%|ETA:0sCleaningdata1%|ETA:6sCleaningdata■■2%|ETA:6sCleaningdata■■4%|ETA:6sCleaningdata■■■5%|ETA:6sCleaningdata■■■6%|ETA:6sCleaningdata■■■8%|ETA:6sCleaningdata■■■■10%|ETA:6sCleaningdata■■■■11%|ETA:6sCleaningdata■■■■■13%|ETA:6sCleaningdata■■■■■14%|ETA:6sCleaningdata■■■■■■16%|ETA:6sCleaningdata■■■■■■17%|ETA:6sCleaningdata■■■■■■■19%|ETA:5sCleaningdata■■■■■■■21%|ETA:5sCleaningdata■■■■■■■■22%|ETA:5sCleaningdata■■■■■■■■24%|ETA:5sCleaningdata■■■■■■■■■25%|ETA:5sCleaningdata■■■■■■■■■27%|ETA:5sCleaningdata■■■■■■■■■28%|ETA:5sCleaningdata■■■■■■■■■■29%|ETA:5sCleaningdata■■■■■■■■■■31%|ETA:5sCleaningdata■■■■■■■■■■■32%|ETA:5sCleaningdata■■■■■■■■■■■34%|ETA:4sCleaningdata■■■■■■■■■■■35%|ETA:4sCleaningdata■■■■■■■■■■■■37%|ETA:4sCleaningdata■■■■■■■■■■■■■39%|ETA:4sCleaningdata■■■■■■■■■■■■■40%|ETA:4sCleaningdata■■■■■■■■■■■■■■42%|ETA:4sCleaningdata■■■■■■■■■■■■■■43%|ETA:4sCleaningdata■■■■■■■■■■■■■■■45%|ETA:4sCleaningdata■■■■■■■■■■■■■■■46%|ETA:4sCleaningdata■■■■■■■■■■■■■■■48%|ETA:3sCleaningdata■■■■■■■■■■■■■■■■50%|ETA:3sCleaningdata■■■■■■■■■■■■■■■■51%|ETA:3sCleaningdata■■■■■■■■■■■■■■■■■53%|ETA:3sCleaningdata■■■■■■■■■■■■■■■■■54%|ETA:3sCleaningdata■■■■■■■■■■■■■■■■■■56%|ETA:3sCleaningdata■■■■■■■■■■■■■■■■■■57%|ETA:3sCleaningdata■■■■■■■■■■■■■■■■■■■59%|ETA:3sCleaningdata■■■■■■■■■■■■■■■■■■■60%|ETA:3sCleaningdata■■■■■■■■■■■■■■■■■■■■62%|ETA:3sCleaningdata■■■■■■■■■■■■■■■■■■■■63%|ETA:2sCleaningdata■■■■■■■■■■■■■■■■■■■■■65%|ETA:2sCleaningdata■■■■■■■■■■■■■■■■■■■■■66%|ETA:2sCleaningdata■■■■■■■■■■■■■■■■■■■■■68%|ETA:2sCleaningdata■■■■■■■■■■■■■■■■■■■■■■69%|ETA:2sCleaningdata■■■■■■■■■■■■■■■■■■■■■■70%|ETA:2sCleaningdata■■■■■■■■■■■■■■■■■■■■■■■72%|ETA:2sCleaningdata■■■■■■■■■■■■■■■■■■■■■■■74%|ETA:2sCleaningdata■■■■■■■■■■■■■■■■■■■■■■■75%|ETA:2sCleaningdata■■■■■■■■■■■■■■■■■■■■■■■■77%|ETA:2sCleaningdata■■■■■■■■■■■■■■■■■■■■■■■■78%|ETA:1sCleaningdata■■■■■■■■■■■■■■■■■■■■■■■■■80%|ETA:1sCleaningdata■■■■■■■■■■■■■■■■■■■■■■■■■81%|ETA:1sCleaningdata■■■■■■■■■■■■■■■■■■■■■■■■■■83%|ETA:1sCleaningdata■■■■■■■■■■■■■■■■■■■■■■■■■■84%|ETA:1sCleaningdata■■■■■■■■■■■■■■■■■■■■■■■■■■■86%|ETA:1sCleaningdata■■■■■■■■■■■■■■■■■■■■■■■■■■■87%|ETA:1sCleaningdata■■■■■■■■■■■■■■■■■■■■■■■■■■■■89%|ETA:1sCleaningdata■■■■■■■■■■■■■■■■■■■■■■■■■■■■91%|ETA:1sCleaningdata■■■■■■■■■■■■■■■■■■■■■■■■■■■■■92%|ETA:1sCleaningdata■■■■■■■■■■■■■■■■■■■■■■■■■■■■■94%|ETA:0sCleaningdata■■■■■■■■■■■■■■■■■■■■■■■■■■■■■95%|ETA:0sCleaningdata■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■97%|ETA:0sCleaningdata■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■98%|ETA:0scli/man/figures/README/alert-warning-dark.svg0000644000176200001440000000305414557444176020432 0ustar liggesusers!CannotreachGitHub,usinglocaldatabasecache.cli/man/figures/README/alert-danger.svg0000644000176200001440000000260514557444176017307 0ustar liggesusersFailedtoconnecttodatabase.cli/man/figures/README/alert-dark.svg0000644000176200001440000000227714557444176016775 0ustar liggesusersAgenericalertcli/man/figures/README/glue-dark.svg0000644000176200001440000000256614557444176016623 0ustar liggesusersDownloaded123.14MBin1.3scli/man/figures/README/alert-info.svg0000644000176200001440000000262314557444176017002 0ustar liggesusersReopeneddatabase<example.com:port>.cli/man/figures/README/h1.svg0000644000176200001440000000300514557444176015245 0ustar liggesusers──Heading1───────────────────────────────────────────────────────────────────cli/man/figures/README/h2-dark.svg0000644000176200001440000000243514557444176016173 0ustar liggesusers──Heading2──cli/man/figures/README/themes.svg0000644000176200001440000000330214557444176016222 0ustar liggesusersThisisveryimportantBacktothepreviousthemecli/man/figures/README/alert-danger-dark.svg0000644000176200001440000000260214557444176020223 0ustar liggesusersFailedtoconnecttodatabase.cli/man/figures/README/themes-dark.svg0000644000176200001440000000327714557444176017154 0ustar liggesusersThisisveryimportantBacktothepreviousthemecli/man/figures/make-spinner-default.svg0000644000176200001440000007517214752364056020024 0ustar liggesuserscli/man/figures/progress-step-msg.svg0000644000176200001440000001432114752364056017377 0ustar liggesusersDownloadingdata.Downloadingdata.Downloadingdata.Downloadingdata.Downloadingdata.Downloadingdata.Downloadingdata.Downloadingdata.Downloaded819.20kB.[3.5s]Downloadingdata.Downloadingdata.cli/man/figures/progress-step-spin.svg0000644000176200001440000003606614752364056017574 0ustar liggesusersDownloadingdataDownloadingdataDownloadingdataDownloadingdata[2.5s]Importingdata[1s]Cleaningdata[2s]FittingmodelFittingmodelFittingmodelFittingmodelFittingmodelFittingmodelFittingmodelFittingmodelFittingmodel[3.4s]DownloadingdataDownloadingdataDownloadingdataDownloadingdataDownloadingdataDownloadingdataDownloadingdataImportingdataCleaningdataFittingmodelFittingmodelcli/man/figures/make-spinner-template.svg0000644000176200001440000007617014752364056020212 0ustar liggesusersComputingComputingComputingComputingComputingComputingComputingComputingComputingComputingcli/man/figures/progress-natotal.svg0000644000176200001440000003357614752364056017317 0ustar liggesusersParametertuning100done(27/s)|3.7sParametertuning1done(28/s)|36msParametertuning4done(28/s)|146msParametertuning9done(27/s)|328msParametertuning15done(28/s)|535msParametertuning21done(28/s)|752msParametertuning27done(28/s)|968msParametertuning32done(28/s)|1.2sParametertuning38done(28/s)|1.4sParametertuning43done(28/s)|1.6sParametertuning49done(28/s)|1.8sParametertuning55done(28/s)|2sParametertuning60done(28/s)|2.2sParametertuning66done(28/s)|2.4sParametertuning72done(28/s)|2.6sParametertuning77done(28/s)|2.8sParametertuning82done(28/s)|3sParametertuning88done(28/s)|3.2sParametertuning93done(27/s)|3.4sParametertuning99done(27/s)|3.6scli/man/figures/progress-message.svg0000644000176200001440000001216414752364056017267 0ustar liggesusersTaskthreeisunderway:step1Taskoneisrunning...Tasktwoisrunning...Taskthreeisunderway:step2Taskthreeisunderway:step3Taskthreeisunderway:step4Taskthreeisunderway:step5cli/man/figures/progress-clear.svg0000644000176200001440000006752314752364056016742 0ustar liggesusersParametertuning███████████████████████████████100%|ETA:0sDatacleaning██████████████████████████████1%|ETA:3sDatacleaning███████████████████████████████6%|ETA:3sDatacleaning███████████████████████████████11%|ETA:3sDatacleaning███████████████████████████████17%|ETA:3sDatacleaning███████████████████████████████22%|ETA:3sDatacleaning███████████████████████████████28%|ETA:3sDatacleaning███████████████████████████████33%|ETA:2sDatacleaning███████████████████████████████38%|ETA:2sDatacleaning███████████████████████████████44%|ETA:2sDatacleaning███████████████████████████████49%|ETA:2sDatacleaning███████████████████████████████55%|ETA:2sDatacleaning███████████████████████████████60%|ETA:1sDatacleaning███████████████████████████████66%|ETA:1sDatacleaning███████████████████████████████71%|ETA:1sDatacleaning███████████████████████████████77%|ETA:1sDatacleaning███████████████████████████████82%|ETA:1sDatacleaning███████████████████████████████88%|ETA:0sDatacleaning███████████████████████████████94%|ETA:0sDatacleaning███████████████████████████████99%|ETA:0sParametertuning███████████████████████████████4%|ETA:3sParametertuning███████████████████████████████10%|ETA:3sParametertuning███████████████████████████████15%|ETA:3sParametertuning███████████████████████████████21%|ETA:3sParametertuning███████████████████████████████26%|ETA:3sParametertuning███████████████████████████████32%|ETA:2sParametertuning███████████████████████████████38%|ETA:2sParametertuning███████████████████████████████43%|ETA:2sParametertuning███████████████████████████████48%|ETA:2sParametertuning███████████████████████████████54%|ETA:2sParametertuning███████████████████████████████59%|ETA:1sParametertuning███████████████████████████████65%|ETA:1sParametertuning███████████████████████████████70%|ETA:1sParametertuning███████████████████████████████76%|ETA:1sParametertuning███████████████████████████████81%|ETA:1sParametertuning███████████████████████████████87%|ETA:0sParametertuning███████████████████████████████93%|ETA:0sParametertuning██████████████████████████████98%|ETA:0scli/man/figures/progress-along-2.svg0000644000176200001440000003322714752364056017105 0ustar liggesusersDownloading■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■100%|ETA:0sDownloading0%|ETA:?Downloading■■■6%|ETA:4sDownloading■■■■10%|ETA:4sDownloading■■■■■15%|ETA:4sDownloading■■■■■■■19%|ETA:4sDownloading■■■■■■■■23%|ETA:4sDownloading■■■■■■■■■28%|ETA:3sDownloading■■■■■■■■■■■32%|ETA:3sDownloading■■■■■■■■■■■■36%|ETA:3sDownloading■■■■■■■■■■■■■41%|ETA:3sDownloading■■■■■■■■■■■■■■■45%|ETA:3sDownloading■■■■■■■■■■■■■■■■49%|ETA:2sDownloading■■■■■■■■■■■■■■■■■54%|ETA:2sDownloading■■■■■■■■■■■■■■■■■■58%|ETA:2sDownloading■■■■■■■■■■■■■■■■■■■■62%|ETA:2sDownloading■■■■■■■■■■■■■■■■■■■■■67%|ETA:2sDownloading■■■■■■■■■■■■■■■■■■■■■■71%|ETA:1sDownloading■■■■■■■■■■■■■■■■■■■■■■■■76%|ETA:1sDownloading■■■■■■■■■■■■■■■■■■■■■■■■■80%|ETA:1sDownloading■■■■■■■■■■■■■■■■■■■■■■■■■■84%|ETA:1sDownloading■■■■■■■■■■■■■■■■■■■■■■■■■■■■89%|ETA:1sDownloading■■■■■■■■■■■■■■■■■■■■■■■■■■■■■93%|ETA:0sDownloading■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■97%|ETA:0scli/man/figures/progress-1.svg0000644000176200001440000005340514752364056016006 0ustar liggesusersCleaningdata███████████████████████████████100%|ETA:0sCleaningdata███████████████████████████████3%|ETA:5sCleaningdata███████████████████████████████7%|ETA:5sCleaningdata███████████████████████████████10%|ETA:5sCleaningdata███████████████████████████████14%|ETA:5sCleaningdata███████████████████████████████17%|ETA:5sCleaningdata███████████████████████████████20%|ETA:5sCleaningdata███████████████████████████████24%|ETA:4sCleaningdata███████████████████████████████27%|ETA:4sCleaningdata███████████████████████████████31%|ETA:4sCleaningdata███████████████████████████████34%|ETA:4sCleaningdata███████████████████████████████38%|ETA:4sCleaningdata███████████████████████████████41%|ETA:3sCleaningdata███████████████████████████████45%|ETA:3sCleaningdata███████████████████████████████48%|ETA:3sCleaningdata███████████████████████████████51%|ETA:3sCleaningdata███████████████████████████████55%|ETA:3sCleaningdata███████████████████████████████58%|ETA:2sCleaningdata███████████████████████████████62%|ETA:2sCleaningdata███████████████████████████████65%|ETA:2sCleaningdata███████████████████████████████69%|ETA:2sCleaningdata███████████████████████████████72%|ETA:2sCleaningdata███████████████████████████████76%|ETA:1sCleaningdata███████████████████████████████79%|ETA:1sCleaningdata███████████████████████████████83%|ETA:1sCleaningdata███████████████████████████████87%|ETA:1sCleaningdata███████████████████████████████90%|ETA:1sCleaningdata███████████████████████████████94%|ETA:0sCleaningdata██████████████████████████████97%|ETA:0scli/man/figures/progress-current.svg0000644000176200001440000005666714752364056017345 0ustar liggesusersFirststep███████████████████████████████100%|ETA:0sSecondstep███████████████████████████████100%|ETA:0sFirststep██████████████████████████████1%|ETA:3sFirststep███████████████████████████████2%|ETA:3sFirststep███████████████████████████████11%|ETA:2sFirststep███████████████████████████████18%|ETA:2sFirststep███████████████████████████████26%|ETA:2sFirststep███████████████████████████████33%|ETA:2sFirststep███████████████████████████████40%|ETA:2sFirststep███████████████████████████████48%|ETA:1sFirststep███████████████████████████████55%|ETA:1sFirststep███████████████████████████████63%|ETA:1sFirststep███████████████████████████████70%|ETA:1sFirststep███████████████████████████████78%|ETA:1sFirststep███████████████████████████████85%|ETA:0sFirststep███████████████████████████████93%|ETA:0sSecondstep███████████████████████████████7%|ETA:2sSecondstep███████████████████████████████15%|ETA:2sSecondstep███████████████████████████████22%|ETA:2sSecondstep███████████████████████████████30%|ETA:2sSecondstep███████████████████████████████37%|ETA:2sSecondstep███████████████████████████████45%|ETA:1sSecondstep███████████████████████████████53%|ETA:1sSecondstep███████████████████████████████60%|ETA:1sSecondstep███████████████████████████████67%|ETA:1sSecondstep███████████████████████████████74%|ETA:1sSecondstep███████████████████████████████82%|ETA:0sSecondstep███████████████████████████████89%|ETA:0sSecondstep██████████████████████████████97%|ETA:0scli/man/figures/progress-after.svg0000644000176200001440000002712114752364056016743 0ustar liggesusersStartingnow,at2022-09-0711:26:44███████████████████████████████100%@2022-09-0711:26:49███████████████████████████████47%@2022-09-0711:26:46███████████████████████████████49%@2022-09-0711:26:46███████████████████████████████53%@2022-09-0711:26:46███████████████████████████████58%@2022-09-0711:26:47███████████████████████████████62%@2022-09-0711:26:47███████████████████████████████67%@2022-09-0711:26:47███████████████████████████████71%@2022-09-0711:26:47███████████████████████████████75%@2022-09-0711:26:48███████████████████████████████80%@2022-09-0711:26:48███████████████████████████████84%@2022-09-0711:26:48███████████████████████████████88%@2022-09-0711:26:48███████████████████████████████92%@2022-09-0711:26:48██████████████████████████████97%@2022-09-0711:26:49cli/man/figures/progress-format.svg0000644000176200001440000001474214752364056017137 0ustar liggesusersDownloaded10filesin4.7s.Downloadingdata-1.zip[1/10]ETA:0sDownloadingdata-2.zip[2/10]ETA:2sDownloadingdata-3.zip[3/10]ETA:2sDownloadingdata-4.zip[4/10]ETA:2sDownloadingdata-5.zip[5/10]ETA:2sDownloadingdata-6.zip[6/10]ETA:2sDownloadingdata-7.zip[7/10]ETA:1sDownloadingdata-8.zip[8/10]ETA:1sDownloadingdata-9.zip[9/10]ETA:0scli/man/figures/get-spinner.svg0000644000176200001440000003632614752364056016242 0ustar liggesusers❤️Spinning100done(21/s)|4.8s💙Spinning1done(22/s)|46ms💜Spinning2done(21/s)|94ms💚Spinning7done(22/s)|324ms❤️Spinning11done(21/s)|521ms💛Spinning15done(21/s)|721ms💙Spinning19done(21/s)|920ms💜Spinning24done(21/s)|1.2s💚Spinning28done(21/s)|1.3s❤️Spinning32done(21/s)|1.5s💛Spinning36done(21/s)|1.7s💙Spinning41done(21/s)|2s💜Spinning45done(21/s)|2.2s💚Spinning49done(21/s)|2.3s❤️Spinning54done(21/s)|2.6s💛Spinning58done(21/s)|2.8s💙Spinning62done(21/s)|3s💜Spinning67done(21/s)|3.2s💚Spinning71done(21/s)|3.4s❤️Spinning75done(21/s)|3.6s💛Spinning79done(21/s)|3.8s💙Spinning84done(21/s)|4s💜Spinning88done(21/s)|4.2s💚Spinning92done(21/s)|4.4s❤️Spinning96done(21/s)|4.6scli/man/figures/progress-step-dynamic.svg0000644000176200001440000004443514752364056020246 0ustar liggesusersDownloadingdata,gotfile100/100[2.6s]Importingdata[1s]Cleaningdata[2s]FittingmodelFittingmodelFittingmodelFittingmodelFittingmodelFittingmodelFittingmodelFittingmodelFittingmodel[3.5s]DownloadingdataDownloadingdata,gotfile7/100Downloadingdata,gotfile15/100Downloadingdata,gotfile22/100Downloadingdata,gotfile30/100Downloadingdata,gotfile38/100Downloadingdata,gotfile46/100Downloadingdata,gotfile54/100Downloadingdata,gotfile62/100Downloadingdata,gotfile69/100Downloadingdata,gotfile76/100Downloadingdata,gotfile84/100Downloadingdata,gotfile92/100Downloadingdata,gotfile100/100ImportingdataCleaningdataFittingmodelFittingmodelcli/man/figures/progress-along-3.svg0000644000176200001440000002271614752364056017107 0ustar liggesusersDownloadingdatafile100Downloadingdatafile0Downloadingdatafile7Downloadingdatafile11Downloadingdatafile16Downloadingdatafile21Downloadingdatafile25Downloadingdatafile30Downloadingdatafile35Downloadingdatafile39Downloadingdatafile44Downloadingdatafile48Downloadingdatafile53Downloadingdatafile57Downloadingdatafile62Downloadingdatafile66Downloadingdatafile71Downloadingdatafile76Downloadingdatafile81Downloadingdatafile85Downloadingdatafile90Downloadingdatafile95Downloadingdatafile99cli/man/figures/make-spinner-custom.svg0000644000176200001440000004047414752364056017707 0ustar liggesusersDownloading.Downloading..Downloading...Downloading..Downloading.Downloadingcli/man/figures/demo-spinners.svg0000644000176200001440000004107414752364056016566 0ustar liggesusers🕛🕛clock🕐clock🕑clock🕒clock🕓clock🕔clock🕕clock🕖clock🕗clock🕘clock🕙clock🕚clockcli/man/figures/progress-step.svg0000644000176200001440000001467614752364056016630 0ustar liggesusersDownloadingdata[2s]Importingdata[1s]Cleaningdata[2s]Fittingmodel[3s]DownloadingdataImportingdataCleaningdataFittingmodelcli/man/figures/progress-output.svg0000644000176200001440000005255014752364056017206 0ustar liggesusersBeforetheprogressbarCalculating███████████████████████████████48%|ETA:2sAlreadyhalfway!Calculating███████████████████████████████100%|ETA:0sAlldoneCalculating██████████████████████████████1%|ETA:5sCalculating███████████████████████████████2%|ETA:5sCalculating███████████████████████████████6%|ETA:4sCalculating███████████████████████████████10%|ETA:4sCalculating███████████████████████████████15%|ETA:4sCalculating███████████████████████████████19%|ETA:4sCalculating███████████████████████████████23%|ETA:4sCalculating███████████████████████████████28%|ETA:3sCalculating███████████████████████████████32%|ETA:3sCalculating███████████████████████████████36%|ETA:3sCalculating███████████████████████████████40%|ETA:3sCalculating███████████████████████████████45%|ETA:3sCalculating███████████████████████████████53%|ETA:2sCalculating███████████████████████████████57%|ETA:2sCalculating███████████████████████████████61%|ETA:2sCalculating███████████████████████████████65%|ETA:2sCalculating███████████████████████████████70%|ETA:1sCalculating███████████████████████████████74%|ETA:1sCalculating███████████████████████████████78%|ETA:1sCalculating███████████████████████████████83%|ETA:1sCalculating███████████████████████████████87%|ETA:1sCalculating███████████████████████████████91%|ETA:0sCalculating███████████████████████████████95%|ETA:0scli/man/figures/progress-tasks.svg0000644000176200001440000000571414752364056016773 0ustar liggesusers3/3ETA:0s|Tasks1/3ETA:2s|Tasks2/3ETA:1s|Taskscli/man/figures/progress-output2.svg0000644000176200001440000005242614752364056017272 0ustar liggesusersBeforetheprogressbarCalculating███████████████████████████████50%|ETA:2sAlreadyhalfway!Calculating███████████████████████████████100%|ETA:0sAlldoneCalculating██████████████████████████████1%|ETA:5sCalculating███████████████████████████████2%|ETA:5sCalculating███████████████████████████████6%|ETA:4sCalculating███████████████████████████████11%|ETA:4sCalculating███████████████████████████████15%|ETA:4sCalculating███████████████████████████████19%|ETA:4sCalculating███████████████████████████████24%|ETA:4sCalculating███████████████████████████████28%|ETA:3sCalculating███████████████████████████████32%|ETA:3sCalculating███████████████████████████████37%|ETA:3sCalculating███████████████████████████████41%|ETA:3sCalculating███████████████████████████████46%|ETA:3sCalculating███████████████████████████████55%|ETA:2sCalculating███████████████████████████████59%|ETA:2sCalculating███████████████████████████████64%|ETA:2sCalculating███████████████████████████████68%|ETA:1sCalculating███████████████████████████████72%|ETA:1sCalculating███████████████████████████████76%|ETA:1sCalculating███████████████████████████████81%|ETA:1sCalculating███████████████████████████████85%|ETA:1sCalculating███████████████████████████████89%|ETA:1sCalculating███████████████████████████████93%|ETA:0sCalculating██████████████████████████████98%|ETA:0scli/man/combine_ansi_styles.Rd0000644000176200001440000000252114557444176016135 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/ansi.R \name{combine_ansi_styles} \alias{combine_ansi_styles} \title{Combine two or more ANSI styles} \usage{ combine_ansi_styles(...) } \arguments{ \item{...}{The styles to combine. For character strings, the \code{\link[=make_ansi_style]{make_ansi_style()}} function is used to create a style first. They will be applied from right to left.} } \value{ The combined style function. } \description{ Combine two or more styles or style functions into a new style function that can be called on strings to style them. } \details{ It does not usually make sense to combine two foreground colors (or two background colors), because only the first one applied will be used. It does make sense to combine different kind of styles, e.g. background color, foreground color, bold font. } \examples{ ## Use style names alert <- combine_ansi_styles("bold", "red4") cat(alert("Warning!"), "\n") ## Or style functions alert <- combine_ansi_styles(style_bold, col_red, bg_cyan) cat(alert("Warning!"), "\n") ## Combine a composite style alert <- combine_ansi_styles( "bold", combine_ansi_styles("red", bg_cyan)) cat(alert("Warning!"), "\n") } \seealso{ Other ANSI styling: \code{\link{ansi-styles}}, \code{\link{make_ansi_style}()}, \code{\link{num_ansi_colors}()} } \concept{ANSI styling} cli/man/rule.Rd0000644000176200001440000001773214557444176013065 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/rules.R \name{rule} \alias{rule} \title{Make a rule with one or two text labels} \usage{ rule( left = "", center = "", right = "", line = 1, col = NULL, line_col = col, background_col = NULL, width = console_width() ) } \arguments{ \item{left}{Label to show on the left. It interferes with the \code{center} label, only at most one of them can be present.} \item{center}{Label to show at the center. It interferes with the \code{left} and \code{right} labels.} \item{right}{Label to show on the right. It interferes with the \code{center} label, only at most one of them can be present.} \item{line}{The character or string that is used to draw the line. It can also \code{1} or \code{2}, to request a single line (Unicode, if available), or a double line. Some strings are interpreted specially, see \emph{Line styles} below.} \item{col}{Color of text, and default line color. Either an ANSI style function (see \link[=ansi-styles]{ANSI styles}), or a color name that is passed to \code{\link[=make_ansi_style]{make_ansi_style()}}.} \item{line_col, background_col}{Either a color name (used in \code{\link[=make_ansi_style]{make_ansi_style()}}), or a style function (see \link[=ansi-styles]{ANSI styles}), to color the line and background.} \item{width}{Width of the rule. Defaults to the \code{width} option, see \code{\link[base:options]{base::options()}}.} } \value{ Character scalar, the rule. } \description{ The rule can include either a centered text label, or labels on the left and right side. To color the labels, use the functions \verb{col_*}, \verb{bg_*} and \verb{style_*} functions, see \link[=ansi-styles]{ANSI styles}, and the examples below. To color the line, either these functions directly, or the \code{line_col} option. } \details{ \subsection{Simple rule}{ \if{html}{\out{
}}\preformatted{rule() }\if{html}{\out{
}}\if{html}{\out{
#> ──────────────────────────────────────────────────────────────────────          
}} } \subsection{Line styles}{ Some strings for the \code{line} argument are interpreted specially: \itemize{ \item \code{"single"}: (same as \code{1}), a single line, \item \code{"double"}: (same as \code{2}), a double line, \item \code{"bar1"}, \code{"bar2"}, \code{"bar3"}, etc., \code{"bar8"} uses varying height bars. } \subsection{Double rule}{ \if{html}{\out{
}}\preformatted{rule(line = 2) }\if{html}{\out{
}}\if{html}{\out{
#> ══════════════════════════════════════════════════════════════════════          
}} } \subsection{Bars}{ \if{html}{\out{
}}\preformatted{rule(line = "bar2") rule(line = "bar5") }\if{html}{\out{
}}\if{html}{\out{
#> ▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂          
#> ▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅          
}} } \subsection{Custom lines}{ \if{html}{\out{
}}\preformatted{rule(center = "TITLE", line = "~") }\if{html}{\out{
}}\if{html}{\out{
#> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ TITLE ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~          
}} \if{html}{\out{
}}\preformatted{rule(center = "TITLE", line = col_blue("~-")) }\if{html}{\out{
}}\if{html}{\out{
#> ~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- TITLE ~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~          
}} \if{html}{\out{
}}\preformatted{rule(center = bg_red(" ", symbol$star, "TITLE", symbol$star, " "), line = "\\u2582", line_col = "orange") }\if{html}{\out{
}}\if{html}{\out{
#> ▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂  ★TITLE★  ▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂          
}} } } \subsection{Left label}{ \if{html}{\out{
}}\preformatted{rule(left = "Results") }\if{html}{\out{
}}\if{html}{\out{
#> ── Results ───────────────────────────────────────────────────────────          
}} } \subsection{Centered label}{ \if{html}{\out{
}}\preformatted{rule(center = " * RESULTS * ") }\if{html}{\out{
}}\if{html}{\out{
#> ────────────────────────────  * RESULTS *  ───────────────────────────          
}} } \subsection{Colored labels}{ \if{html}{\out{
}}\preformatted{rule(center = col_red(" * RESULTS * ")) }\if{html}{\out{
}}\if{html}{\out{
#> ────────────────────────────  * RESULTS *  ───────────────────────────          
}} } \subsection{Colored line}{ \if{html}{\out{
}}\preformatted{rule(center = col_red(" * RESULTS * "), line_col = "red") }\if{html}{\out{
}}\if{html}{\out{
#> ────────────────────────────  * RESULTS *  ───────────────────────────          
}} } } cli/man/ansi_strsplit.Rd0000644000176200001440000000326014752735214014774 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/ansiex.R \name{ansi_strsplit} \alias{ansi_strsplit} \title{Split an ANSI colored string} \usage{ ansi_strsplit(x, split, ...) } \arguments{ \item{x}{Character vector, potentially ANSI styled, or a vector to coerced to character.} \item{split}{Character vector of length 1 (or object which can be coerced to such) containing regular expression(s) (unless \code{fixed = TRUE}) to use for splitting. If empty matches occur, in particular if \code{split} has zero characters, \code{x} is split into single characters.} \item{...}{Extra arguments are passed to \code{base::strsplit()}.} } \value{ A list of the same length as \code{x}, the \code{i}-th element of which contains the vector of splits of \code{x[i]}. ANSI styles are retained. } \description{ This is the color-aware counterpart of \code{\link[base:strsplit]{base::strsplit()}}. It works almost exactly like the original, but keeps the colors in the substrings. } \examples{ str <- paste0( col_red("I am red---"), col_green("and I am green-"), style_underline("I underlined") ) cat(str, "\n") # split at dashes, keep color cat(ansi_strsplit(str, "[-]+")[[1]], sep = "\n") strsplit(ansi_strip(str), "[-]+") # split to characters, keep color cat(ansi_strsplit(str, "")[[1]], "\n", sep = " ") strsplit(ansi_strip(str), "") } \seealso{ Other ANSI string operations: \code{\link{ansi_align}()}, \code{\link{ansi_columns}()}, \code{\link{ansi_nchar}()}, \code{\link{ansi_strtrim}()}, \code{\link{ansi_strwrap}()}, \code{\link{ansi_substr}()}, \code{\link{ansi_substring}()}, \code{\link{ansi_toupper}()}, \code{\link{ansi_trimws}()} } \concept{ANSI string operations} cli/man/cli_status.Rd0000644000176200001440000000741514752735214014256 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/status-bar.R \name{cli_status} \alias{cli_status} \title{Update the status bar (superseded)} \usage{ cli_status( msg, msg_done = paste(msg, "... done"), msg_failed = paste(msg, "... failed"), .keep = FALSE, .auto_close = TRUE, .envir = parent.frame(), .auto_result = c("clear", "done", "failed", "auto") ) } \arguments{ \item{msg}{The text to show, a character vector. It will be collapsed into a single string, and the first line is kept and cut to \code{\link[=console_width]{console_width()}}. The message is often associated with the start of a calculation.} \item{msg_done}{The message to use when the message is cleared, when the calculation finishes successfully. If \code{.auto_close} is \code{TRUE} and \code{.auto_result} is \code{"done"}, then this is printed automatically when the calling function (or \code{.envir}) finishes.} \item{msg_failed}{The message to use when the message is cleared, when the calculation finishes unsuccessfully. If \code{.auto_close} is \code{TRUE} and \code{.auto_result} is \code{"failed"}, then this is printed automatically when the calling function (or \code{.envir}) finishes.} \item{.keep}{What to do when this status bar is cleared. If \code{TRUE} then the content of this status bar is kept, as regular cli output (the screen is scrolled up if needed). If \code{FALSE}, then this status bar is deleted.} \item{.auto_close}{Whether to clear the status bar when the calling function finishes (or \code{.envir} is removed from the stack, if specified).} \item{.envir}{Environment to evaluate the glue expressions in. It is also used to auto-clear the status bar if \code{.auto_close} is \code{TRUE}.} \item{.auto_result}{What to do when auto-closing the status bar.} } \value{ The id of the new status bar container element, invisibly. } \description{ \strong{The \verb{cli_status_*()} functions are superseded by the \code{\link[=cli_progress_message]{cli_progress_message()}} and \code{\link[=cli_progress_step]{cli_progress_step()}} functions, because they have a better default behavior.} The status bar is the last line of the terminal. cli apps can use this to show status information, progress bars, etc. The status bar is kept intact by all semantic cli output. } \details{ Use \code{\link[=cli_status_clear]{cli_status_clear()}} to clear the status bar. Often status messages are associated with processes. E.g. the app starts downloading a large file, so it sets the status bar accordingly. Once the download is done (or has failed), the app typically updates the status bar again. cli automates much of this, via the \code{msg_done}, \code{msg_failed}, and \code{.auto_result} arguments. See examples below. } \seealso{ Status bars support \link[=inline-markup]{inline markup}. The \code{\link[=cli_progress_message]{cli_progress_message()}} and \code{\link[=cli_progress_step]{cli_progress_step()}} functions, for a superior API. Other status bar: \code{\link{cli_process_start}()}, \code{\link{cli_status_clear}()}, \code{\link{cli_status_update}()} Other functions supporting inline markup: \code{\link{cli_abort}()}, \code{\link{cli_alert}()}, \code{\link{cli_blockquote}()}, \code{\link{cli_bullets}()}, \code{\link{cli_bullets_raw}()}, \code{\link{cli_dl}()}, \code{\link{cli_h1}()}, \code{\link{cli_li}()}, \code{\link{cli_ol}()}, \code{\link{cli_process_start}()}, \code{\link{cli_progress_along}()}, \code{\link{cli_progress_bar}()}, \code{\link{cli_progress_message}()}, \code{\link{cli_progress_output}()}, \code{\link{cli_progress_step}()}, \code{\link{cli_rule}}, \code{\link{cli_status_update}()}, \code{\link{cli_text}()}, \code{\link{cli_ul}()}, \code{\link{format_error}()}, \code{\link{format_inline}()} } \concept{functions supporting inline markup} \concept{status bar} cli/man/code_theme_list.Rd0000644000176200001440000000342714557444176015241 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/prettycode.R \name{code_theme_list} \alias{code_theme_list} \title{Syntax highlighting themes} \usage{ code_theme_list() } \value{ Character vector of the built-in code theme names. } \description{ \code{code_theme_list()} lists the built-in code themes. } \section{Code themes}{ A theme is a list of character vectors, except for \code{bracket}, see below. Each character vector must contain RGB colors (e.g. \code{"#a9a9a9"}), and cli styles, e.g. \code{"bold"}. Entries in the list: \itemize{ \item \code{reserved}: reserved words \item \code{number}: numeric literals \item \code{null}: the \code{NULL} constant \item \code{operator}: operators, including assignment \item \code{call}: function calls \item \code{string}: character literals \item \code{comment}: comments \item \code{bracket}: brackets: \code{(){}[]} This is a list of character vectors, to create "rainbow" brackets. It is recycled for deeply nested lists. } } \section{The default code theme}{ In RStudio, it matches the current theme of the IDE. You can use three options to customize the code theme: \itemize{ \item If \code{cli.code_theme} is set, it is used. \item Otherwise if R is running in RStudio and \code{cli.code_theme_rstudio} is set, then it is used. \item Otherwise if T is not running in RStudio and \code{cli.code_theme_terminal} is set, then it is used. } You can set these options to the name of a built-in theme, or to list that specifies a custom theme. See \code{\link[=code_theme_list]{code_theme_list()}} for the list of the built-in themes. } \examples{ code_theme_list() code_highlight(deparse(get), code_theme = "Solarized Dark") } \seealso{ Other syntax highlighting: \code{\link{code_highlight}()} } \concept{syntax highlighting} cli/man/cli_progress_bar.Rd0000644000176200001440000003177214752735214015426 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/progress-client.R \name{cli_progress_bar} \alias{cli_progress_bar} \alias{__cli_update_due} \alias{cli_tick_reset} \alias{ccli_tick_reset} \alias{ticking} \alias{cli_progress_update} \alias{cli_progress_done} \title{cli progress bars} \usage{ cli_progress_bar( name = NULL, status = NULL, type = c("iterator", "tasks", "download", "custom"), total = NA, format = NULL, format_done = NULL, format_failed = NULL, clear = getOption("cli.progress_clear", TRUE), current = TRUE, auto_terminate = type != "download", extra = NULL, .auto_close = TRUE, .envir = parent.frame() ) cli_progress_update( inc = NULL, set = NULL, total = NULL, status = NULL, extra = NULL, id = NULL, force = FALSE, .envir = parent.frame() ) cli_progress_done(id = NULL, .envir = parent.frame(), result = "done") } \arguments{ \item{name}{This is typically used as a label, and should be short, at most 20 characters.} \item{status}{New status string of the progress bar, if not \code{NULL}.} \item{type}{Type of the progress bar. It is used to select a default display if \code{format} is not specified. Currently supported types: \itemize{ \item \code{iterator}: e.g. a for loop or a mapping function, \item \code{tasks}: a (typically small) number of tasks, \item \code{download}: download of one file, \item \code{custom}: custom type, \code{format} must not be \code{NULL} for this type. }} \item{total}{Total number of progress units, or \code{NA} if it is unknown. \code{cli_progress_update()} can update the total number of units. This is handy if you don't know the size of a download at the beginning, and also in some other cases. If \code{format} is set to \code{NULL}, \code{format} (plus \code{format_done} and \code{format_failed}) will be updated when you change \code{total} from \code{NA} to a number. I.e. default format strings will be updated, custom ones won't be.} \item{format}{Format string. It has to be specified for custom progress bars, otherwise it is optional, and a default display is selected based on the progress bat type and whether the number of total units is known. Format strings may contain glue substitution, the support pluralization and cli styling. See \link{progress-variables} for special variables that you can use in the custom format.} \item{format_done}{Format string for successful termination. By default the same as \code{format}.} \item{format_failed}{Format string for unsuccessful termination. By default the same as \code{format}.} \item{clear}{Whether to remove the progress bar from the screen after it has terminated. Defaults to the \code{cli.progress_clear} option, or \code{TRUE} if unset.} \item{current}{Whether to use this progress bar as the current progress bar of the calling function. See more at 'The current progress bar' below.} \item{auto_terminate}{Whether to terminate the progress bar if the number of current units reaches the number of total units.} \item{extra}{Extra data to add to the progress bar. This can be used in custom format strings for example. It should be a named list. \code{cli_progress_update()} can update the extra data. Often you can get away with referring to local variables in the format string, and then you don't need to use this argument. Explicitly including these constants or variables in \code{extra} can result in cleaner code. In the rare cases when you need to refer to the same progress bar from multiple functions, and you can them to \code{extra}.} \item{.auto_close}{Whether to terminate the progress bar when the calling function (or the one with execution environment in \code{.envir} exits. (Auto termination does not work for progress bars created from the global environment, e.g. from a script.)} \item{.envir}{The environment to use for auto-termination and for glue substitution. It is also used to find and set the current progress bar.} \item{inc}{Increment in progress units. This is ignored if \code{set} is not \code{NULL}.} \item{set}{Set the current number of progress units to this value. Ignored if \code{NULL}.} \item{id}{Progress bar to update or terminate. If \code{NULL}, then the current progress bar of the calling function (or \code{.envir} if specified) is updated or terminated.} \item{force}{Whether to force a display update, even if no update is due.} \item{result}{String to select successful or unsuccessful termination. It is only used if the progress bar is not cleared from the screen. It can be one of \code{"done"}, \code{"failed"}, \code{"clear"}, and \code{"auto"}.} } \value{ \code{cli_progress_bar()} returns the id of the new progress bar. The id is a string constant. \code{cli_progress_update()} returns the id of the progress bar, invisibly. \code{cli_progress_done()} returns \code{TRUE}, invisibly, always. } \description{ This is the reference manual of the three functions that create, update and terminate progress bars. For a tutorial see the \href{https://cli.r-lib.org/articles/progress.html}{cli progress bars}. \code{cli_progress_bar()} creates a new progress bar. \code{cli_progress_update()} updates the state of a progress bar, and potentially the display as well. \code{cli_progress_done()} terminates a progress bar. } \details{ \subsection{Basic usage}{ \code{cli_progress_bar()} creates a progress bar, \code{cli_progress_update()} updates an existing progress bar, and \code{cli_progress_done()} terminates it. It is good practice to always set the \code{name} argument, to make the progress bar more informative. \if{html}{\out{
}}\preformatted{clean <- function() \{ cli_progress_bar("Cleaning data", total = 100) for (i in 1:100) \{ Sys.sleep(5/100) cli_progress_update() \} cli_progress_done() \} clean() }\if{html}{\out{
}} \if{html}{\figure{progress-1.svg}} } \subsection{Progress bar types}{ There are three builtin types of progress bars, and a custom type. \if{html}{\out{
}}\preformatted{tasks <- function() \{ cli_progress_bar("Tasks", total = 3, type = "tasks") for (i in 1:3) \{ Sys.sleep(1) cli_progress_update() \} cli_progress_done() \} tasks() }\if{html}{\out{
}} \if{html}{\figure{progress-tasks.svg}} } \subsection{Unknown \code{total}}{ If \code{total} is not known, then cli shows a different progress bar. Note that you can also set \code{total} in \code{cli_progress_update()}, if it not known when the progress bar is created, but you learn it later. \if{html}{\out{
}}\preformatted{nototal <- function() \{ cli_progress_bar("Parameter tuning") for (i in 1:100) \{ Sys.sleep(3/100) cli_progress_update() \} cli_progress_done() \} nototal() }\if{html}{\out{
}} \if{html}{\figure{progress-natotal.svg}} } \subsection{Clearing the progress bar}{ By default cli removes terminated progress bars from the screen, if the terminal supports this. If you want to change this, use the \code{clear} argument of \code{cli_progress_bar()}, or the \code{cli.progress_clear} global option (see \link{cli-config}) to change this. (In the cli documentation we usually set \code{cli.progress_clear} to \code{FALSE}, so users can see how finished progress bars look.) In this example the first progress bar is cleared, the second is not. \if{html}{\out{
}}\preformatted{fun <- function() \{ cli_progress_bar("Data cleaning", total = 100, clear = TRUE) for (i in 1:100) \{ Sys.sleep(3/100) cli_progress_update() \} cli_progress_bar("Parameter tuning", total = 100, clear = FALSE) for (i in 1:100) \{ Sys.sleep(3/100) cli_progress_update() \} \} fun() }\if{html}{\out{
}} \if{html}{\figure{progress-clear.svg}} } \subsection{Initial delay}{ Updating a progress bar on the screen is costly, so cli tries to avoid it for quick loops. By default a progress bar is only shown after two seconds, or after half of that if less than 50\% of the iterations are complete. You can change the two second default with the \code{cli.progress_show_after} global option (see \link{cli-config}). (In the cli documentation we usually set \code{cli.progress_show_after} to \code{0} (zero seconds), so progress bars are shown immediately.) In this example we only show the progress bar after one second, because more than 50\% of the iterations remain after one second. \if{html}{\out{
}}\preformatted{fun <- function() \{ cli_alert("Starting now, at \{Sys.time()\}") cli_progress_bar( total = 100, format = "\{cli::pb_bar\} \{pb_percent\} @ \{Sys.time()\}" ) for (i in 1:100) \{ Sys.sleep(4/100) cli_progress_update() \} \} options(cli.progress_show_after = 2) fun() }\if{html}{\out{
}} \if{html}{\figure{progress-after.svg}} } \subsection{The \emph{current} progress bar}{ By default cli sets the new progress bar as the \emph{current} progress bar of the calling function. The current progress bar is the default one in cli progress bar operations. E.g. if no progress bar id is supplied in \code{cli_progress_update()}, then the current progress bar is updated. Every function can only have a single \emph{current} progress bar, and if a new one is created, then the previous one (if any) is automatically terminated. The current progress bar is also terminated when the function that created it exits. Thanks to these rules, most often you don't need to explicitly deal with progress bar ids, and you don't need to explicitly call \code{cli_progress_done()}: \if{html}{\out{
}}\preformatted{fun <- function() \{ cli_progress_bar("First step ", total = 100) for (i in 1:100) \{ Sys.sleep(2/100) cli_progress_update() \} cli_progress_bar("Second step", total = 100) for (i in 1:100) \{ Sys.sleep(2/100) cli_progress_update() \} \} fun() }\if{html}{\out{
}} \if{html}{\figure{progress-current.svg}} } \subsection{cli output while the progress bar is active}{ cli allows emitting regular cli output (alerts, headers, lists, etc.) while a progress bar is active. On terminals that support this, cli will remove the progress bar temporarily, emit the output, and then restores the progress bar. \if{html}{\out{
}}\preformatted{fun <- function() \{ cli_alert_info("Before the progress bar") cli_progress_bar("Calculating", total = 100) for (i in 1:50) \{ Sys.sleep(4/100) cli_progress_update() \} cli_alert_info("Already half way!") for (i in 1:50) \{ Sys.sleep(4/100) cli_progress_update() \} cli_alert_info("All done") \} fun() }\if{html}{\out{
}} \if{html}{\figure{progress-output.svg}} See also \code{\link[=cli_progress_output]{cli_progress_output()}}, which sends text for the current progress handler. E.g. in a Shiny app it will send the output to the Shiny progress bar, as opposed to the \code{cli_alert()} etc. cli functions which will print the text to the console. } \subsection{Custom formats}{ In addition to the builtin types, you can also specify a custom format string. In this case \link[=progress-variables]{progress variables} are probably useful to avoid calculating some progress bar quantities like the elapsed time, of the ETA manually. You can also use your own variables in the calling function: \if{html}{\out{
}}\preformatted{fun <- function(urls) \{ cli_progress_bar( format = paste0( "\{pb_spin\} Downloading \{.path \{basename(url)\}\} ", "[\{pb_current\}/\{pb_total\}] ETA:\{pb_eta\}" ), format_done = paste0( "\{col_green(symbol$tick)\} Downloaded \{pb_total\} files ", "in \{pb_elapsed\}." ),, total = length(urls) ) for (url in urls) \{ cli_progress_update() Sys.sleep(5/10) \} \} fun(paste0("https://acme.com/data-", 1:10, ".zip")) }\if{html}{\out{
}} \if{html}{\figure{progress-format.svg}} } } \seealso{ These functions support \link[=inline-markup]{inline markup}. \code{\link[=cli_progress_message]{cli_progress_message()}} and \code{\link[=cli_progress_step]{cli_progress_step()}} for simpler progress messages. Other progress bar functions: \code{\link{cli_progress_along}()}, \code{\link{cli_progress_builtin_handlers}()}, \code{\link{cli_progress_message}()}, \code{\link{cli_progress_num}()}, \code{\link{cli_progress_output}()}, \code{\link{cli_progress_step}()}, \code{\link{cli_progress_styles}()}, \code{\link{progress-variables}} Other functions supporting inline markup: \code{\link{cli_abort}()}, \code{\link{cli_alert}()}, \code{\link{cli_blockquote}()}, \code{\link{cli_bullets}()}, \code{\link{cli_bullets_raw}()}, \code{\link{cli_dl}()}, \code{\link{cli_h1}()}, \code{\link{cli_li}()}, \code{\link{cli_ol}()}, \code{\link{cli_process_start}()}, \code{\link{cli_progress_along}()}, \code{\link{cli_progress_message}()}, \code{\link{cli_progress_output}()}, \code{\link{cli_progress_step}()}, \code{\link{cli_rule}}, \code{\link{cli_status}()}, \code{\link{cli_status_update}()}, \code{\link{cli_text}()}, \code{\link{cli_ul}()}, \code{\link{format_error}()}, \code{\link{format_inline}()} } \concept{functions supporting inline markup} \concept{progress bar functions} cli/man/ansi_palettes.Rd0000644000176200001440000000506014557444176014740 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/ansi-palette.R \docType{data} \name{truecolor} \alias{truecolor} \alias{ansi_palettes} \alias{ansi_palette_show} \title{ANSI colors palettes} \format{ \code{truecolor} is an integer scalar. \code{ansi_palettes} is a data frame with one row for each palette, and one column for each base ANSI color. \code{attr(ansi_palettes, "info")} contains a list with information about each palette. } \usage{ truecolor ansi_palettes ansi_palette_show(palette = NULL, colors = num_ansi_colors(), rows = 4) } \arguments{ \item{palette}{The palette to show, in the same format as for the \code{cli.palette} option, so it can be the name of a built-in palette, of a list of 16 colors.} \item{colors}{Number of ANSI colors to use the show the palette. If the platform does not have sufficient support, the output might have a lower color resolution. Without color support it will have no color at all.} \item{rows}{The number of colored rows to print.} } \value{ \code{ansi_palette_show} returns a character vector, the rows that are printed to the screen, invisibly. } \description{ If your platform supports at least 256 colors, then you can configure the colors that cli uses for the eight base and the eight bright colors. (I.e. the colors of \code{\link[=col_black]{col_black()}}, \code{\link[=col_red]{col_red()}}, and \code{\link[=col_br_black]{col_br_black()}}, \code{\link[=col_br_red]{col_br_red()}}, etc. } \details{ \code{truecolor} is an integer constant for the number of 24 bit ANSI colors. To customize the default palette, set the \code{cli.palette} option to the name of a built-in palette (see \code{ansi_palettes()}), or the list of 16 colors. Colors can be specified with RGB colors strings: \verb{#rrggbb} or R color names (see the output of \code{\link[grDevices:colors]{grDevices::colors()}}). For example, you can put this in your R profile: \if{html}{\out{
}}\preformatted{options(cli.palette = "vscode") }\if{html}{\out{
}} It is currently not possible to configure the background colors separately, these will be always the same as the foreground colors. If your platform only has 256 colors, then the colors specified in the palette have to be interpolated. On true color platforms they RGB values are used as-is. \code{ansi_palettes} is a data frame of the built-in palettes, each row is one palette. \code{ansi_palette_show()} shows the colors of an ANSI palette on the screen. } \examples{ ansi_palettes ansi_palette_show("dichro", colors = truecolor) } \keyword{datasets} cli/man/cli_bullets_raw.Rd0000644000176200001440000000322014752735214015244 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/bullets.R \name{cli_bullets_raw} \alias{cli_bullets_raw} \alias{format_bullets_raw} \title{List of verbatim items} \usage{ cli_bullets_raw(text, id = NULL, class = NULL) format_bullets_raw(text, id = NULL, class = NULL) } \arguments{ \item{text}{Character vector of items. See details below on how names are interpreted.} \item{id}{Optional id of the \code{div.bullets} element, can be used in themes.} \item{class}{Optional additional class(es) for the \code{div.bullets} element.} } \description{ \code{cli_format_bullets_raw()} is similar to \code{\link[=cli_bullets]{cli_bullets()}}, but it does not perform any inline styling or glue substitutions in the input. } \details{ \code{format_bullets_raw()} returns the output instead of printing it. } \seealso{ These functions support \link[=inline-markup]{inline markup}. See \code{\link[=cli_bullets]{cli_bullets()}} for examples. Other functions supporting inline markup: \code{\link{cli_abort}()}, \code{\link{cli_alert}()}, \code{\link{cli_blockquote}()}, \code{\link{cli_bullets}()}, \code{\link{cli_dl}()}, \code{\link{cli_h1}()}, \code{\link{cli_li}()}, \code{\link{cli_ol}()}, \code{\link{cli_process_start}()}, \code{\link{cli_progress_along}()}, \code{\link{cli_progress_bar}()}, \code{\link{cli_progress_message}()}, \code{\link{cli_progress_output}()}, \code{\link{cli_progress_step}()}, \code{\link{cli_rule}}, \code{\link{cli_status}()}, \code{\link{cli_status_update}()}, \code{\link{cli_text}()}, \code{\link{cli_ul}()}, \code{\link{format_error}()}, \code{\link{format_inline}()} } \concept{functions supporting inline markup} cli/man/format_error.Rd0000644000176200001440000000574514752735214014611 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/format-conditions.R \name{format_error} \alias{format_error} \alias{format_warning} \alias{format_message} \title{Format an error, warning or diagnostic message} \usage{ format_error(message, .envir = parent.frame()) format_warning(message, .envir = parent.frame()) format_message(message, .envir = parent.frame()) } \arguments{ \item{message}{It is formatted via a call to \code{\link[=cli_bullets]{cli_bullets()}}.} \item{.envir}{Environment to evaluate the glue expressions in.} } \description{ You can then throw this message with \code{\link[=stop]{stop()}} or \code{rlang::abort()}. } \details{ The messages can use inline styling, pluralization and glue substitutions. \if{html}{\out{
}}\preformatted{n <- "boo" stop(format_error(c( "\{.var n\} must be a numeric vector", "x" = "You've supplied a \{.cls \{class(n)\}\} vector." ))) }\if{html}{\out{
}}\if{html}{\out{
#> Error: `n` must be a numeric vector                                             
#>  You've supplied a <character> vector.                                         
}} \if{html}{\out{
}}\preformatted{len <- 26 idx <- 100 stop(format_error(c( "Must index an existing element:", "i" = "There \{?is/are\} \{len\} element\{?s\}.", "x" = "You've tried to subset element \{idx\}." ))) }\if{html}{\out{
}}\if{html}{\out{
#> Error: Must index an existing element:                                          
#>  There are 26 elements.                                                        
#>  You've tried to subset element 100.                                           
}} } \seealso{ These functions support \link[=inline-markup]{inline markup}. Other functions supporting inline markup: \code{\link{cli_abort}()}, \code{\link{cli_alert}()}, \code{\link{cli_blockquote}()}, \code{\link{cli_bullets}()}, \code{\link{cli_bullets_raw}()}, \code{\link{cli_dl}()}, \code{\link{cli_h1}()}, \code{\link{cli_li}()}, \code{\link{cli_ol}()}, \code{\link{cli_process_start}()}, \code{\link{cli_progress_along}()}, \code{\link{cli_progress_bar}()}, \code{\link{cli_progress_message}()}, \code{\link{cli_progress_output}()}, \code{\link{cli_progress_step}()}, \code{\link{cli_rule}}, \code{\link{cli_status}()}, \code{\link{cli_status_update}()}, \code{\link{cli_text}()}, \code{\link{cli_ul}()}, \code{\link{format_inline}()} } \concept{functions supporting inline markup} cli/man/utf8_nchar.Rd0000644000176200001440000000267114557444176014153 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/utf8.R \name{utf8_nchar} \alias{utf8_nchar} \title{Count the number of characters in a character vector} \usage{ utf8_nchar(x, type = c("chars", "bytes", "width", "graphemes", "codepoints")) } \arguments{ \item{x}{Character vector, it is converted to UTF-8.} \item{type}{Whether to count graphemes (characters), code points, bytes, or calculate the display width of the string.} } \value{ Numeric vector, the length of the strings in the character vector. } \description{ By default it counts Unicode grapheme clusters, instead of code points. } \examples{ # Grapheme example, emoji with combining characters. This is a single # grapheme, consisting of five Unicode code points: # * `\U0001f477` is the construction worker emoji # * `\U0001f3fb` is emoji modifier that changes the skin color # * `\u200d` is the zero width joiner # * `\u2640` is the female sign # * `\ufe0f` is variation selector 16, requesting an emoji style glyph emo <- "\U0001f477\U0001f3fb\u200d\u2640\ufe0f" cat(emo) utf8_nchar(emo, "chars") # = graphemes utf8_nchar(emo, "bytes") utf8_nchar(emo, "width") utf8_nchar(emo, "codepoints") # For comparision, the output for width depends on the R version used: nchar(emo, "chars") nchar(emo, "bytes") nchar(emo, "width") } \seealso{ Other UTF-8 string manipulation: \code{\link{utf8_graphemes}()}, \code{\link{utf8_substr}()} } \concept{UTF-8 string manipulation} cli/man/ansi_html_style.Rd0000644000176200001440000000274714557444176015314 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/ansiex.R \name{ansi_html_style} \alias{ansi_html_style} \title{CSS styles for the output of \code{ansi_html()}} \usage{ ansi_html_style( colors = TRUE, palette = c("vscode", "dichro", "vga", "winxp", "win10", "macos", "putty", "mirc", "xterm", "ubuntu", "eclipse", "iterm", "iterm-pastel", "iterm-smoooooth", "iterm-snazzy", "iterm-solarized", "iterm-tango") ) } \arguments{ \item{colors}{Whether or not to include colors. \code{FALSE} will not include colors, \code{TRUE} or \code{8} will include eight colors (plus their bright variants), \code{256} will include 256 colors.} \item{palette}{Character scalar, palette to use for the first eight colors plus their bright variants. Terminals define these colors differently, and cli includes a couple of examples. Sources of palettes: \itemize{ \item https://en.wikipedia.org/wiki/ANSI_escape_code#3-bit_and_4-bit \item iTerm2 builtin palettes \item \url{https://github.com/sindresorhus/iterm2-snazzy} }} } \value{ Named list of CSS declaration blocks, where the names are CSS selectors. It has a \code{format()} and \code{print()} methods, which you can use to write the output to a CSS or HTML file. } \description{ CSS styles for the output of \code{ansi_html()} } \examples{ ansi_html_style(colors = FALSE) ansi_html_style(colors = 8, palette = "iterm-snazzy") } \seealso{ Other ANSI to HTML conversion: \code{\link{ansi_html}()} } \concept{ANSI to HTML conversion} cli/man/hash_sha1.Rd0000644000176200001440000000300714752735214013734 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/hash.R \name{hash_sha1} \alias{hash_sha1} \alias{hash_raw_sha1} \alias{hash_obj_sha1} \alias{hash_file_sha1} \title{SHA-1 hash} \usage{ hash_sha1(x) hash_raw_sha1(x) hash_obj_sha1(x, serialize_version = 2) hash_file_sha1(paths) } \arguments{ \item{x}{Character vector. If not a character vector, then \code{\link[=as.character]{as.character()}} is used to try to coerce it into one. \code{NA} entries will have an \code{NA} hash.} \item{serialize_version}{Workspace format version to use, see \code{\link[base:serialize]{base::serialize()}}.} \item{paths}{Character vector of file names.} } \value{ \code{hash_sha1()} returns a character vector of hexadecimal SHA-1 hashes. \code{hash_raw_sha1()} returns a character scalar. \code{hash_obj_sha1()} returns a character scalar. \code{hash_file_sha1()} returns a character vector of SHA-1 hashes. } \description{ Calculate the SHA-1 hash of each element of a character vector. } \details{ \code{hash_raw_sha1()} calculates the SHA-1 hash of the bytes of a raw vector. \code{hash_obj_sha1()} calculates the SHA-1 hash of an R object. The object is serialized into a binary vector first. \code{hash_file_sha1()} calculates the SHA-1 hash of one or more files. } \examples{ hash_sha1(c("foo", NA, "bar", "")) } \seealso{ Other hash functions: \code{\link{hash_animal}()}, \code{\link{hash_emoji}()}, \code{\link{hash_md5}()}, \code{\link{hash_sha256}()}, \code{\link{hash_xxhash}()} } \concept{hash functions} cli/man/vt_output.Rd0000644000176200001440000000262314557444176014160 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/vt.R \name{vt_output} \alias{vt_output} \title{Simulate (a subset of) a VT-5xx ANSI terminal} \usage{ vt_output(output, width = 80L, height = 25L) } \arguments{ \item{output}{Character vector or raw vector. Character vectors are collapsed (without a separater), and converted to a raw vector using \code{\link[base:rawConversion]{base::charToRaw()}}.} \item{width}{Terminal width.} \item{height}{Terminal height.} } \value{ Data frame with columns \code{lineno}, \code{segmentno}, \code{segment}, \code{attributes}. } \description{ This is utility function that calculates the state of a VT-5xx screen after a certain set of output. } \details{ Currently it supports: \itemize{ \item configurable terminal width and height \item ASCII printable characters. \item \verb{\\n}, \verb{\\r}. \item ANSI SGR colors, 8 color mode, 256 color mode and true color mode. \item Other ANSI SGR features: bold, italic, underline, strikethrough, blink, inverse. } It does \emph{not} currently supports other features, mode notably: \itemize{ \item Other ANSI control sequences and features. Other control sequences are silently ignored. \item Wide Unicode characters. Their width is not taken into account correctly. \item Unicode graphemes. } } \note{ This function is experimental, and the virtual temrinal API will likely change in future versions of cli. } cli/man/hash_emoji.Rd0000644000176200001440000000522514752735214014207 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/hash.R \name{hash_emoji} \alias{hash_emoji} \alias{hash_raw_emoji} \alias{hash_obj_emoji} \title{Emoji hash} \usage{ hash_emoji(x, size = 3) hash_raw_emoji(x, size = 3) hash_obj_emoji(x, size = 3, serialize_version = 2) } \arguments{ \item{x}{Character vector. \code{NA} entries will have an \code{NA} hash.} \item{size}{Number of emojis to use in a hash. Currently it has to be from 1 through 4.} \item{serialize_version}{Workspace format version to use, see \code{\link[base:serialize]{base::serialize()}}.} } \value{ \code{hash_emoji()} returns a data frame with columns \itemize{ \item \code{hash}: the emoji hash, a string of the requested size. \item \code{emojis}: list column with the emoji characters in character vectors. Note that an emoji might have multiple code points. \item \code{text}: text representation of \code{hash}, comma separated. \item \code{names}: list column with the text representations of \code{emojis}, in character vectors. } \code{hash_raw_emoji()} and \code{hash_obj_emoji()} return a list with entries: \itemize{ \item \code{hash}: the emoji hash, a string of requested size, \item \code{emojis}: the individual emoji characters in a character vector, \item \code{text}: text representation of \code{hash}, comma separated, \item \code{names}: names of the emojis, in a character vector. } } \description{ Emoji hash } \details{ It uses the first 13 hexadecimal characters (out of the 32) of the MD5 hash of the input, and converts them into an emoji representation. It uses a manually selected subset of all emojis, that tend to be displayed correctly. \subsection{Number of possible hash values}{ cli uses 2280 possible emojis. This is the number of different hashes you can get for different values of \code{size}:\tabular{rr}{ \code{size} \tab size of hash table space \cr 1 \tab 2,280 \cr 2 \tab 5,198,400 \cr 3 \tab 11,852,352,000 \cr 4 \tab 27,023,362,560,000 \cr } } \code{hash_raw_emoji()} calculates the emoji hash of the bytes of a raw vector. \code{hash_obj_emoji()} calculates the emoji hash of an R object. The object is serialized into a binary vector first. } \examples{ hash_emoji(c("foo", NA, "bar", ""))$text # if you increase `size`, the shorter hash is a prefix of the longer: hash_emoji("foobar", 1)$text hash_emoji("foobar", 2)$text hash_emoji("foobar", 3)$text hash_emoji("foobar", 4)$text } \seealso{ the emoji package for a comprehensive list of emojis Other hash functions: \code{\link{hash_animal}()}, \code{\link{hash_md5}()}, \code{\link{hash_sha1}()}, \code{\link{hash_sha256}()}, \code{\link{hash_xxhash}()} } \concept{hash functions} cli/man/progress-utils.Rd0000644000176200001440000000211314557444176015103 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/progress-utils.R \name{cli_progress_num} \alias{cli_progress_num} \alias{cli_progress_cleanup} \title{Progress bar utility functions.} \usage{ cli_progress_num() cli_progress_cleanup() } \value{ \code{cli_progress_num()} returns an integer scalar. `cli_progress_cleanup() does not return anything. } \description{ Progress bar utility functions. } \details{ \code{cli_progress_num()} returns the number of currently active progress bars. (These do not currently include the progress bars created in C/C++ code.) \code{cli_progress_cleanup()} terminates all active progress bars. (It currently ignores progress bars created in the C/C++ code.) } \seealso{ Other progress bar functions: \code{\link{cli_progress_along}()}, \code{\link{cli_progress_bar}()}, \code{\link{cli_progress_builtin_handlers}()}, \code{\link{cli_progress_message}()}, \code{\link{cli_progress_output}()}, \code{\link{cli_progress_step}()}, \code{\link{cli_progress_styles}()}, \code{\link{progress-variables}} } \concept{progress bar functions} cli/man/make_spinner.Rd0000644000176200001440000000656414557444176014572 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/spinner.R \name{make_spinner} \alias{make_spinner} \title{Create a spinner} \usage{ make_spinner( which = NULL, stream = "auto", template = "{spin}", static = c("dots", "print", "print_line", "silent") ) } \arguments{ \item{which}{The name of the chosen spinner. If \code{NULL}, then the default is used, which can be customized via the \code{cli.spinner_unicode}, \code{cli.spinner_ascii} and \code{cli.spinner} options. (The latter applies to both Unicode and ASCII displays. These options can be set to the name of a built-in spinner, or to a list that has an entry called \code{frames}, a character vector of frames.} \item{stream}{The stream to use for the spinner. Typically this is standard error, or maybe the standard output stream. It can also be a string, one of \code{"auto"}, \code{"message"}, \code{"stdout"}, \code{"stderr"}. \code{"auto"} will select \code{stdout()} if the session is interactive and there are no sinks, otherwise it will select \code{stderr()}.} \item{template}{A template string, that will contain the spinner. The spinner itself will be substituted for \code{{spin}}. See example below.} \item{static}{What to do if the terminal does not support dynamic displays: \itemize{ \item \code{"dots"}: show a dot for each \verb{$spin()} call. \item \code{"print"}: just print the frames of the spinner, one after another. \item \code{"print_line"}: print the frames of the spinner, each on its own line. \item \code{"silent"} do not print anything, just the \code{template}. }} } \value{ A \code{cli_spinner} object, which is a list of functions. See its methods below. \code{cli_spinner} methods: \itemize{ \item \verb{$spin()}: output the next frame of the spinner. \item \verb{$finish()}: terminate the spinner. Depending on terminal capabilities this removes the spinner from the screen. Spinners can be reused, you can start calling the \verb{$spin()} method again. } All methods return the spinner object itself, invisibly. The spinner is automatically throttled to its ideal update frequency. } \description{ Create a spinner } \section{Examples}{ \subsection{Default spinner}{ \if{html}{\out{
}}\preformatted{sp1 <- make_spinner() fun_with_spinner <- function() \{ lapply(1:100, function(x) \{ sp1$spin(); Sys.sleep(0.05) \}) sp1$finish() \} ansi_with_hidden_cursor(fun_with_spinner()) }\if{html}{\out{
}} \if{html}{\figure{make-spinner-default.svg}} } \subsection{Spinner with a template}{ \if{html}{\out{
}}\preformatted{sp2 <- make_spinner(template = "Computing \{spin\}") fun_with_spinner2 <- function() \{ lapply(1:100, function(x) \{ sp2$spin(); Sys.sleep(0.05) \}) sp2$finish() \} ansi_with_hidden_cursor(fun_with_spinner2()) }\if{html}{\out{
}} \if{html}{\figure{make-spinner-template.svg}} } \subsection{Custom spinner}{ \if{html}{\out{
}}\preformatted{sp3 <- make_spinner("simpleDotsScrolling", template = "Downloading \{spin\}") fun_with_spinner3 <- function() \{ lapply(1:100, function(x) \{ sp3$spin(); Sys.sleep(0.05) \}) sp3$finish() \} ansi_with_hidden_cursor(fun_with_spinner3()) }\if{html}{\out{
}} \if{html}{\figure{make-spinner-custom.svg}} } } \seealso{ Other spinners: \code{\link{demo_spinners}()}, \code{\link{get_spinner}()}, \code{\link{list_spinners}()} } \concept{spinners} cli/man/cli_progress_message.Rd0000644000176200001440000000600714752735214016277 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/progress-client.R \name{cli_progress_message} \alias{cli_progress_message} \title{Simplified cli progress messages} \usage{ cli_progress_message( msg, current = TRUE, .auto_close = TRUE, .envir = parent.frame(), ... ) } \arguments{ \item{msg}{Message to show. It may contain glue substitution and cli styling. It can be updated via \code{\link[=cli_progress_update]{cli_progress_update()}}, as usual.} \item{current}{Passed to \code{\link[=cli_progress_bar]{cli_progress_bar()}}.} \item{.auto_close}{Passed to \code{\link[=cli_progress_bar]{cli_progress_bar()}}.} \item{.envir}{Passed to \code{\link[=cli_progress_bar]{cli_progress_bar()}}.} \item{...}{Passed to \code{\link[=cli_progress_bar]{cli_progress_bar()}}.} } \value{ The id of the new progress bar. } \description{ This is a simplified progress bar, a single (dynamic) message, without progress units. } \details{ \code{cli_progress_message()} always shows the message, even if no update is due. When the progress message is terminated, it is removed from the screen by default. Note that the message can be dynamic: if you update it with \code{\link[=cli_progress_update]{cli_progress_update()}}, then cli uses the current values in the string substitutions. \if{html}{\out{
}}\preformatted{fun <- function() \{ cli_progress_message("Task one is running...") Sys.sleep(2) cli_progress_message("Task two is running...") Sys.sleep(2) step <- 1L cli_progress_message("Task three is underway: step \{step\}") for (step in 1:5) \{ Sys.sleep(0.5) cli_progress_update() \} \} fun() }\if{html}{\out{
}} \if{html}{\figure{progress-message.svg}} } \seealso{ This function supports \link[=inline-markup]{inline markup}. \code{\link[=cli_progress_bar]{cli_progress_bar()}} for the complete progress bar API. \code{\link[=cli_progress_step]{cli_progress_step()}} for a similar display that is styled by default. Other progress bar functions: \code{\link{cli_progress_along}()}, \code{\link{cli_progress_bar}()}, \code{\link{cli_progress_builtin_handlers}()}, \code{\link{cli_progress_num}()}, \code{\link{cli_progress_output}()}, \code{\link{cli_progress_step}()}, \code{\link{cli_progress_styles}()}, \code{\link{progress-variables}} Other functions supporting inline markup: \code{\link{cli_abort}()}, \code{\link{cli_alert}()}, \code{\link{cli_blockquote}()}, \code{\link{cli_bullets}()}, \code{\link{cli_bullets_raw}()}, \code{\link{cli_dl}()}, \code{\link{cli_h1}()}, \code{\link{cli_li}()}, \code{\link{cli_ol}()}, \code{\link{cli_process_start}()}, \code{\link{cli_progress_along}()}, \code{\link{cli_progress_bar}()}, \code{\link{cli_progress_output}()}, \code{\link{cli_progress_step}()}, \code{\link{cli_rule}}, \code{\link{cli_status}()}, \code{\link{cli_status_update}()}, \code{\link{cli_text}()}, \code{\link{cli_ul}()}, \code{\link{format_error}()}, \code{\link{format_inline}()} } \concept{functions supporting inline markup} \concept{progress bar functions} cli/man/style_hyperlink.Rd0000644000176200001440000000257214557444176015337 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/ansi-hyperlink.R \name{style_hyperlink} \alias{style_hyperlink} \alias{ansi_has_hyperlink_support} \alias{ansi_hyperlink_types} \title{Terminal Hyperlinks} \usage{ style_hyperlink(text, url, params = NULL) ansi_has_hyperlink_support() ansi_hyperlink_types() } \arguments{ \item{text}{Text to show. \code{text} and \code{url} are recycled to match their length, via a \code{paste0()} call.} \item{url}{URL to link to.} \item{params}{A named character vector of additional parameters, or \code{NULL}.} } \value{ Styled \code{cli_ansi_string} for \code{style_hyperlink()}. Logical scalar for \code{ansi_has_hyperlink_support()}. } \description{ \code{ansi_hyperlink()} creates an ANSI hyperlink. } \details{ This function is currently experimental. In particular, many of the \verb{ansi_*()} functions do not support it properly. \code{ansi_has_hyperlink_support()} checks if the current \code{stdout()} supports hyperlinks. See also \url{https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda}. \code{ansi_hyperlink_types()} checks if current \code{stdout()} supports various types of hyperlinks. It returns a list with entries \code{href}, \code{run}, \code{help} and \code{vignettes}. } \examples{ cat("This is an", style_hyperlink("R", "https://r-project.org"), "link.\n") ansi_has_hyperlink_support() } cli/man/cli_rule.Rd0000644000176200001440000000654314752735214013703 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/cli.R \name{cli_rule} \alias{cli_rule} \title{CLI horizontal rule} \usage{ cli_rule( left = "", center = "", right = "", id = NULL, .envir = parent.frame() ) } \arguments{ \item{left}{Label to show on the left. It interferes with the \code{center} label, only at most one of them can be present.} \item{center}{Label to show at the center. It interferes with the \code{left} and \code{right} labels.} \item{right}{Label to show on the right. It interferes with the \code{center} label, only at most one of them can be present.} \item{id}{Element id, a string. If \code{NULL}, then a new id is generated and returned.} \item{.envir}{Environment to evaluate the glue expressions in.} } \description{ It can be used to separate parts of the output. } \details{ \subsection{Inline styling and interpolation}{ \if{html}{\out{
}}\preformatted{pkg <- "mypackage" cli_rule(left = "\{.pkg \{pkg\}\} results") }\if{html}{\out{
}}\if{html}{\out{
#> ── mypackage results ─────────────────────────────────────────────────          
}} } \subsection{Theming}{ The line style of the rule can be changed via the the \code{line-type} property. Possible values are: \itemize{ \item \code{"single"}: (same as \code{1}), a single line, \item \code{"double"}: (same as \code{2}), a double line, \item \code{"bar1"}, \code{"bar2"}, \code{"bar3"}, etc., \code{"bar8"} uses varying height bars. } Colors and background colors can similarly changed via a theme. \if{html}{\out{
}}\preformatted{d <- cli_div(theme = list(rule = list( color = "cyan", "line-type" = "double"))) cli_rule("Summary", right = "\{.pkg mypackage\}") cli_end(d) }\if{html}{\out{
}}\if{html}{\out{
#> ══ Summary ══════════════════════════════════════════════ mypackage ══          
}} } } \seealso{ This function supports \link[=inline-markup]{inline markup}. Other functions supporting inline markup: \code{\link{cli_abort}()}, \code{\link{cli_alert}()}, \code{\link{cli_blockquote}()}, \code{\link{cli_bullets}()}, \code{\link{cli_bullets_raw}()}, \code{\link{cli_dl}()}, \code{\link{cli_h1}()}, \code{\link{cli_li}()}, \code{\link{cli_ol}()}, \code{\link{cli_process_start}()}, \code{\link{cli_progress_along}()}, \code{\link{cli_progress_bar}()}, \code{\link{cli_progress_message}()}, \code{\link{cli_progress_output}()}, \code{\link{cli_progress_step}()}, \code{\link{cli_status}()}, \code{\link{cli_status_update}()}, \code{\link{cli_text}()}, \code{\link{cli_ul}()}, \code{\link{format_error}()}, \code{\link{format_inline}()} } \concept{functions supporting inline markup} cli/man/simple_theme.Rd0000644000176200001440000001372314752364056014560 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/simple-theme.R \name{simple_theme} \alias{simple_theme} \title{A simple CLI theme} \usage{ simple_theme(dark = getOption("cli.theme_dark", "auto")) } \arguments{ \item{dark}{Whether the theme should be optimized for a dark background. If \code{"auto"}, then cli will try to detect this. Detection usually works in recent RStudio versions, and in iTerm on macOS, but not on other platforms.} } \description{ To use this theme, you can set it as the \code{cli.theme} option. Note that this is in addition to the builtin theme, which is still in effect. } \details{ \if{html}{\out{
}}\preformatted{options(cli.theme = cli::simple_theme()) }\if{html}{\out{
}} and then CLI apps started after this will use it as the default theme. You can also use it temporarily, in a div element: \if{html}{\out{
}}\preformatted{cli_div(theme = cli::simple_theme()) }\if{html}{\out{
}} } \section{Showcase}{ \if{html}{\out{
}}\preformatted{show <- cli_div(theme = cli::simple_theme()) cli_h1("Heading 1") cli_h2("Heading 2") cli_h3("Heading 3") cli_par() cli_alert_danger("Danger alert") cli_alert_warning("Warning alert") cli_alert_info("Info alert") cli_alert_success("Success alert") cli_alert("Alert for starting a process or computation", class = "alert-start") cli_end() cli_text("Packages and versions: \{.pkg cli\} \{.version 1.0.0\}.") cli_text("Time intervals: \{.timestamp 3.4s\}") cli_text("\{.emph Emphasis\} and \{.strong strong emphasis\}") cli_text("This is a piece of code: \{.code sum(x) / length(x)\}") cli_text("Function names: \{.fn cli::simple_theme\}") cli_text("Files: \{.file /usr/bin/env\}") cli_text("URLs: \{.url https://r-project.org\}") cli_h2("Longer code chunk") cli_par(class = "code R") cli_verbatim( '# window functions are useful for grouped mutates', 'mtcars \%>\%', ' group_by(cyl) \%>\%', ' mutate(rank = min_rank(desc(mpg)))') cli_end(show) }\if{html}{\out{
}}\if{html}{\out{
#>                                                                                 
#> ── Heading 1 ─────────────────────────────────────────────────────────          
#>                                                                                 
#> ─ Heading 2 ──                                                                  
#>                                                                                 
#> Heading 3                                                                       
#> ✖ Danger alert                                                                  
#> ! Warning alert                                                                 
#>  Info alert                                                                    
#>  Success alert                                                                 
#> → Alert for starting a process or computation                                   
#>                                                                                 
#> Packages and versions: cli 1.0.0.                                               
#> Time intervals: [3.4s]                                                          
#> Emphasis and strong emphasis                                                    
#> This is a piece of code: `sum(x) / length(x)`                                   
#> Function names: `cli::simple_theme()`()                                         
#> Files: /usr/bin/env                                                             
#> URLs: <https://r-project.org>                                                   
#>                                                                                 
#> ─ Longer code chunk ──                                                          
#> # window functions are useful for grouped mutates                               
#> mtcars %>%                                                                      
#>   group_by(cyl) %>%                                                             
#>   mutate(rank = min_rank(desc(mpg)))                                            
#>                                                                                 
}} } \seealso{ \link{themes}, \code{\link[=builtin_theme]{builtin_theme()}}. } cli/man/cli_blockquote.Rd0000644000176200001440000000606714752735214015105 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/cli.R \name{cli_blockquote} \alias{cli_blockquote} \title{CLI block quote} \usage{ cli_blockquote( quote, citation = NULL, id = NULL, class = NULL, .envir = parent.frame() ) } \arguments{ \item{quote}{Text of the quotation.} \item{citation}{Source of the quotation, typically a link or the name of a person.} \item{id}{Element id, a string. If \code{NULL}, then a new id is generated and returned.} \item{class}{Class name, sting. Can be used in themes.} \item{.envir}{Environment to evaluate the glue expressions in. It is also used to auto-close the container if \code{.auto_close} is \code{TRUE}.} } \description{ A section that is quoted from another source. It is typically indented. } \details{ \if{html}{\out{
}}\preformatted{evil <- paste( "The real problem is that programmers have spent far too much time", "worrying about efficiency in the wrong places and at the wrong", "times; premature optimization is the root of all evil (or at least", "most of it) in programming.") cli_blockquote(evil, citation = "Donald Ervin Knuth") }\if{html}{\out{
}}\if{html}{\out{
#>                                                                                 
#>     “The real problem is that programmers have spent far                        
#>     too much time worrying about efficiency in the wrong                        
#>     places and at the wrong times; premature optimization                       
#>     is the root of all evil (or at least most of it) in                         
#>     programming.”                                                               
#>     — Donald Ervin Knuth                                                        
#>                                                                                 
}} } \seealso{ This function supports \link[=inline-markup]{inline markup}. Other functions supporting inline markup: \code{\link{cli_abort}()}, \code{\link{cli_alert}()}, \code{\link{cli_bullets}()}, \code{\link{cli_bullets_raw}()}, \code{\link{cli_dl}()}, \code{\link{cli_h1}()}, \code{\link{cli_li}()}, \code{\link{cli_ol}()}, \code{\link{cli_process_start}()}, \code{\link{cli_progress_along}()}, \code{\link{cli_progress_bar}()}, \code{\link{cli_progress_message}()}, \code{\link{cli_progress_output}()}, \code{\link{cli_progress_step}()}, \code{\link{cli_rule}}, \code{\link{cli_status}()}, \code{\link{cli_status_update}()}, \code{\link{cli_text}()}, \code{\link{cli_ul}()}, \code{\link{format_error}()}, \code{\link{format_inline}()} } \concept{functions supporting inline markup} cli/man/is_dynamic_tty.Rd0000644000176200001440000000357714557444176015137 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/tty.R \name{is_dynamic_tty} \alias{is_dynamic_tty} \title{Detect whether a stream supports \verb{\\\\r} (Carriage return)} \usage{ is_dynamic_tty(stream = "auto") } \arguments{ \item{stream}{The stream to inspect or manipulate, an R connection object. It can also be a string, one of \code{"auto"}, \code{"message"}, \code{"stdout"}, \code{"stderr"}. \code{"auto"} will select \code{stdout()} if the session is interactive and there are no sinks, otherwise it will select \code{stderr()}.} } \description{ In a terminal, \verb{\\\\r} moves the cursor to the first position of the same line. It is also supported by most R IDEs. \verb{\\\\r} is typically used to achieve a more dynamic, less cluttered user interface, e.g. to create progress bars. } \details{ If the output is directed to a file, then \verb{\\\\r} characters are typically unwanted. This function detects if \verb{\\\\r} can be used for the given stream or not. The detection mechanism is as follows: \enumerate{ \item If the \code{cli.dynamic} option is set to \code{TRUE}, \code{TRUE} is returned. \item If the \code{cli.dynamic} option is set to anything else, \code{FALSE} is returned. \item If the \code{R_CLI_DYNAMIC} environment variable is not empty and set to the string \code{"true"}, \code{"TRUE"} or \code{"True"}, \code{TRUE} is returned. \item If \code{R_CLI_DYNAMIC} is not empty and set to anything else, \code{FALSE} is returned. \item If the stream is a terminal, then \code{TRUE} is returned. \item If the stream is the standard output or error within RStudio, the macOS R app, or RKWard IDE, \code{TRUE} is returned. \item Otherwise \code{FALSE} is returned. } } \examples{ is_dynamic_tty() is_dynamic_tty(stdout()) } \seealso{ Other terminal capabilities: \code{\link{ansi_hide_cursor}()}, \code{\link{is_ansi_tty}()} } \concept{terminal capabilities} cli/man/ansi_strtrim.Rd0000644000176200001440000000231414752735214014613 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/ansiex.R \name{ansi_strtrim} \alias{ansi_strtrim} \title{Truncate an ANSI string} \usage{ ansi_strtrim(x, width = console_width(), ellipsis = symbol$ellipsis) } \arguments{ \item{x}{Character vector of ANSI strings.} \item{width}{The width to truncate to.} \item{ellipsis}{The string to append to truncated strings. Supply an empty string if you don't want a marker.} } \description{ This function is similar to \code{\link[base:strtrim]{base::strtrim()}}, but works correctly with ANSI styled strings. It also adds \code{...} (or the corresponding Unicode character if Unicode characters are allowed) to the end of truncated strings. } \details{ Note: \code{ansi_strtrim()} does not support NA values currently. } \examples{ text <- cli::col_red(cli:::lorem_ipsum()) ansi_strtrim(c(text, "foobar"), 40) } \seealso{ Other ANSI string operations: \code{\link{ansi_align}()}, \code{\link{ansi_columns}()}, \code{\link{ansi_nchar}()}, \code{\link{ansi_strsplit}()}, \code{\link{ansi_strwrap}()}, \code{\link{ansi_substr}()}, \code{\link{ansi_substring}()}, \code{\link{ansi_toupper}()}, \code{\link{ansi_trimws}()} } \concept{ANSI string operations} cli/man/cli_progress_demo.Rd0000644000176200001440000000371114557444176015605 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/progress-variables.R \name{cli_progress_demo} \alias{cli_progress_demo} \title{cli progress bar demo} \usage{ cli_progress_demo( name = NULL, status = NULL, type = c("iterator", "tasks", "download", "custom"), total = NA, .envir = parent.frame(), ..., at = if (is_interactive()) NULL else 50, show_after = 0, live = NULL, delay = 0, start = as.difftime(5, units = "secs") ) } \arguments{ \item{name}{Passed to \code{\link[=cli_progress_bar]{cli_progress_bar()}}.} \item{status}{Passed to \code{\link[=cli_progress_bar]{cli_progress_bar()}}.} \item{type}{Passed to \code{\link[=cli_progress_bar]{cli_progress_bar()}}.} \item{total}{Passed to \code{\link[=cli_progress_bar]{cli_progress_bar()}}.} \item{.envir}{Passed to \code{\link[=cli_progress_bar]{cli_progress_bar()}}.} \item{...}{Passed to \code{\link[=cli_progress_bar]{cli_progress_bar()}}.} \item{at}{The number of progress units to show and capture the progress bar at. If \code{NULL}, then a sequence of states is generated to show the progress from beginning to end.} \item{show_after}{Delay to show the progress bar. Overrides the \code{cli.progress_show_after} option.} \item{live}{Whether to show the progress bat on the screen, or just return the recorded updates. Defaults to the value of the \code{cli.progress_demo_live} options. If unset, then it is \code{TRUE} in interactive sessions.} \item{delay}{Delay between progress bar updates.} \item{start}{Time to subtract from the start time, to simulate a progress bar that takes longer to run.} } \value{ List with class \code{cli_progress_demo}, which has a print and a format method for pretty printing. The \code{lines} entry contains the output lines, each corresponding to one update. } \description{ Useful for experimenting with format strings and for documentation. It creates a progress bar, iterates it until it terminates and saves the progress updates. } cli/man/match_selector.Rd0000644000176200001440000000107614557444176015104 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/themes.R \name{match_selector} \alias{match_selector} \title{Match a selector to a container stack} \usage{ match_selector(sels, cnts) } \arguments{ \item{sels}{A list of selector nodes.} \item{cnts}{A list of container nodes. The last selector in the list must match the last container, so we do the matching from the back. This is because we use this function to calculate the style of newly encountered containers.} } \description{ Match a selector to a container stack } \keyword{internal} cli/man/cli_li.Rd0000644000176200001440000000541414752735214013334 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/cli.R \name{cli_li} \alias{cli_li} \title{CLI list item(s)} \usage{ cli_li( items = NULL, labels = names(items), id = NULL, class = NULL, .auto_close = TRUE, .envir = parent.frame() ) } \arguments{ \item{items}{Character vector of items, or \code{NULL}.} \item{labels}{For definition lists the item labels.} \item{id}{Id of the new container. Can be used for closing it with \code{\link[=cli_end]{cli_end()}} or in themes. If \code{NULL}, then an id is generated and returned invisibly.} \item{class}{Class of the item container. Can be used in themes.} \item{.auto_close}{Whether to close the container, when the calling function finishes (or \code{.envir} is removed, if specified).} \item{.envir}{Environment to evaluate the glue expressions in. It is also used to auto-close the container if \code{.auto_close} is \code{TRUE}.} } \value{ The id of the new container element, invisibly. } \description{ A list item is a container, see \link{containers}. } \details{ \subsection{Nested lists}{ \if{html}{\out{
}}\preformatted{fun <- function() \{ ul <- cli_ul() cli_li("one:") cli_ol(letters[1:3]) cli_li("two:") cli_li("three") cli_end(ul) \} fun() }\if{html}{\out{
}}\if{html}{\out{
#> • one:                                                                          
#>   1. a                                                                          
#>   2. b                                                                          
#>   3. c                                                                          
#> • two:                                                                          
#> • three                                                                         
}} } } \seealso{ This function supports \link[=inline-markup]{inline markup}. Other functions supporting inline markup: \code{\link{cli_abort}()}, \code{\link{cli_alert}()}, \code{\link{cli_blockquote}()}, \code{\link{cli_bullets}()}, \code{\link{cli_bullets_raw}()}, \code{\link{cli_dl}()}, \code{\link{cli_h1}()}, \code{\link{cli_ol}()}, \code{\link{cli_process_start}()}, \code{\link{cli_progress_along}()}, \code{\link{cli_progress_bar}()}, \code{\link{cli_progress_message}()}, \code{\link{cli_progress_output}()}, \code{\link{cli_progress_step}()}, \code{\link{cli_rule}}, \code{\link{cli_status}()}, \code{\link{cli_status_update}()}, \code{\link{cli_text}()}, \code{\link{cli_ul}()}, \code{\link{format_error}()}, \code{\link{format_inline}()} } \concept{functions supporting inline markup} cli/man/parse_selector.Rd0000644000176200001440000000154614557444176015124 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/themes.R \name{parse_selector} \alias{parse_selector} \title{Parse a CSS3-like selector} \usage{ parse_selector(x) } \arguments{ \item{x}{CSS3-like selector string.} } \description{ This is the rather small subset of CSS3 that is supported: } \details{ Selectors: \itemize{ \item Type selectors, e.g. \code{input} selects all \verb{} elements. \item Class selectors, e.g. \code{.index} selects any element that has a class of "index". \item ID selector. \verb{#toc} will match the element that has the ID \code{"toc"}. } Combinators: \itemize{ \item Descendant combinator, i.e. the space, that combinator selects nodes that are descendants of the first element. E.g. \verb{div span} will match all \verb{} elements that are inside a \verb{
} element. } } \keyword{internal} cli/man/hash_animal.Rd0000644000176200001440000000477114752735214014352 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/hash.R \name{hash_animal} \alias{hash_animal} \alias{hash_raw_animal} \alias{hash_obj_animal} \title{Adjective-animal hash} \usage{ hash_animal(x, n_adj = 2) hash_raw_animal(x, n_adj = 2) hash_obj_animal(x, n_adj = 2, serialize_version = 2) } \arguments{ \item{x}{Character vector. \code{NA} entries will have an \code{NA} hash.} \item{n_adj}{Number of adjectives to use. It must be from 0 through 3.} \item{serialize_version}{Workspace format version to use, see \code{\link[base:serialize]{base::serialize()}}.} } \value{ A data frame with columns \itemize{ \item \code{hash}: the hash value, a string. \item \code{words}: list column with the adjectives and the animal name in a character vector. } \code{hash_raw_animal()} and \code{hash_obj_animal()} return a list with entries: \itemize{ \item \code{hash}: the hash value, a string, \item `words: the adjectives and the animal name in a character vector. } } \description{ Adjective-animal hash } \details{ It uses the first 13 hexadecimal characters (out of the 32) of the MD5 hash of the input, and converts them into an adjective-animal form to create a human readable hash. \subsection{Number of possible hash values}{ \code{hash_animal()} uses 1748 animal names and 8946 different adjectives. The number of different hashes you can get for different values of \code{n_adj}:\tabular{rr}{ \code{n_adj} \tab size of the hash table space \cr 0 \tab 1,748 \cr 1 \tab 15,637,608 \cr 2 \tab 139,894,041,168 \cr 3 \tab 1,251,492,092,288,928 \cr } } \subsection{Source}{ The list of adjectives and animals comes from the ids package, and in turn from \url{https://github.com/a-type/adjective-adjective-animal}, and from \verb{https://gfycat.com} (now gone). } \code{hash_raw_animal()} calculates the adjective-animal hash of the bytes of a raw vector. \code{hash_obj_animal()} calculates the adjective-animal hash of an R object. The object is serialized into a binary vector first. } \examples{ hash_animal(c("foo", "bar")) # if you increase `n_adj`, the shorter hash is a suffix of the longer: hash_animal("cli package", 0)$hash hash_animal("cli package", 1)$hash hash_animal("cli package", 2)$hash hash_animal("cli package", 3)$hash } \seealso{ the ids package for generating random adjective-animal ids Other hash functions: \code{\link{hash_emoji}()}, \code{\link{hash_md5}()}, \code{\link{hash_sha1}()}, \code{\link{hash_sha256}()}, \code{\link{hash_xxhash}()} } \concept{hash functions} cli/man/ansi-styles.Rd0000644000176200001440000001351414557444176014363 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/zzz.R \name{ansi-styles} \alias{ansi-styles} \alias{bg_black} \alias{bg_blue} \alias{bg_cyan} \alias{bg_green} \alias{bg_magenta} \alias{bg_red} \alias{bg_white} \alias{bg_yellow} \alias{bg_none} \alias{bg_br_black} \alias{bg_br_blue} \alias{bg_br_cyan} \alias{bg_br_green} \alias{bg_br_magenta} \alias{bg_br_red} \alias{bg_br_white} \alias{bg_br_yellow} \alias{col_black} \alias{col_blue} \alias{col_cyan} \alias{col_green} \alias{col_magenta} \alias{col_red} \alias{col_white} \alias{col_yellow} \alias{col_grey} \alias{col_silver} \alias{col_none} \alias{col_br_black} \alias{col_br_blue} \alias{col_br_cyan} \alias{col_br_green} \alias{col_br_magenta} \alias{col_br_red} \alias{col_br_white} \alias{col_br_yellow} \alias{style_dim} \alias{style_blurred} \alias{style_bold} \alias{style_hidden} \alias{style_inverse} \alias{style_italic} \alias{style_reset} \alias{style_strikethrough} \alias{style_underline} \alias{style_no_bold} \alias{style_no_blurred} \alias{style_no_dim} \alias{style_no_italic} \alias{style_no_underline} \alias{style_no_inverse} \alias{style_no_hidden} \alias{style_no_strikethrough} \alias{style_no_color} \alias{style_no_bg_color} \title{ANSI colored text} \usage{ bg_black(...) bg_blue(...) bg_cyan(...) bg_green(...) bg_magenta(...) bg_red(...) bg_white(...) bg_yellow(...) bg_none(...) bg_br_black(...) bg_br_blue(...) bg_br_cyan(...) bg_br_green(...) bg_br_magenta(...) bg_br_red(...) bg_br_white(...) bg_br_yellow(...) col_black(...) col_blue(...) col_cyan(...) col_green(...) col_magenta(...) col_red(...) col_white(...) col_yellow(...) col_grey(...) col_silver(...) col_none(...) col_br_black(...) col_br_blue(...) col_br_cyan(...) col_br_green(...) col_br_magenta(...) col_br_red(...) col_br_white(...) col_br_yellow(...) style_dim(...) style_blurred(...) style_bold(...) style_hidden(...) style_inverse(...) style_italic(...) style_reset(...) style_strikethrough(...) style_underline(...) style_no_bold(...) style_no_blurred(...) style_no_dim(...) style_no_italic(...) style_no_underline(...) style_no_inverse(...) style_no_hidden(...) style_no_strikethrough(...) style_no_color(...) style_no_bg_color(...) } \arguments{ \item{...}{Character strings, they will be pasted together with \code{paste0()}, before applying the style function.} } \value{ An ANSI string (class \code{cli_ansi_string}), that contains ANSI sequences, if the current platform supports them. You can simply use \code{cat()} to print them to the terminal. } \description{ cli has a number of functions to color and style text at the command line. They provide a more modern interface than the crayon package. } \details{ The \verb{col_*} functions change the (foreground) color to the text. These are the eight original ANSI colors. Note that in some terminals, they might actually look differently, as terminals have their own settings for how to show them. \code{col_none()} is the default color, this is useful in a substring of a colored string. The \verb{col_br_*} functions are bright versions of the eight ANSI colors. Note that on some terminal configurations and themes they might be the same as the non-bright colors. The \verb{bg_*} functions change the background color of the text. These are the eight original ANSI background colors. These, too, can vary in appearance, depending on terminal settings. \code{bg_none()} the the default background color, this is useful in a substring of a background-colored string. The \verb{bg_br_*} functions are the bright versions of the eight ANSI background colors. Note that on some terminal configurations and themes they might be the same as the non-bright colors. The \verb{style_*} functions apply other styling to the text. The currently supported styling functions are: \itemize{ \item \code{style_reset()} to remove any style, including color, \item \code{style_bold()} for boldface / strong text, although some terminals show a bright, high intensity text instead, \item \code{style_dim()} (or \code{style_blurred()} reduced intensity text. \item \code{style_italic()} (not widely supported). \item \code{style_underline()}, \item \code{style_inverse()}, \item \code{style_hidden()}, \item \code{style_strikethrough()} (not widely supported). } The style functions take any number of character vectors as arguments, and they concatenate them using \code{paste0()} before adding the style. Styles can also be nested, and then inner style takes precedence, see examples below. Sometimes you want to revert back to the default text color, in the middle of colored text, or you want to have a normal font in the middle of italic text. You can use the \verb{style_no_*} functions for this. Every \verb{style_*()} function has a \verb{style_no_*()} pair, which defends its argument from taking on the style. See examples below. } \examples{ col_blue("Hello ", "world!") cat(col_blue("Hello ", "world!")) cat("... to highlight the", col_red("search term"), "in a block of text\n") ## Style stack properly cat(col_green( "I am a green line ", col_blue(style_underline(style_bold("with a blue substring"))), " that becomes green again!" )) error <- combine_ansi_styles("red", "bold") warn <- combine_ansi_styles("magenta", "underline") note <- col_cyan cat(error("Error: subscript out of bounds!\n")) cat(warn("Warning: shorter argument was recycled.\n")) cat(note("Note: no such directory.\n")) # style_no_* functions, note that the color is not removed style_italic(col_green(paste0( "italic before, ", style_no_italic("normal here, "), "italic after" ))) # avoiding color for substring style_italic(col_red(paste( "red before", col_none("not red between"), "red after" ))) } \seealso{ Other ANSI styling: \code{\link{combine_ansi_styles}()}, \code{\link{make_ansi_style}()}, \code{\link{num_ansi_colors}()} } \concept{ANSI styling} cli/man/cli_sitrep.Rd0000644000176200001440000000172614557444176014247 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/sitrep.R \name{cli_sitrep} \alias{cli_sitrep} \title{cli situation report} \usage{ cli_sitrep() } \value{ Named list with entries listed above. It has a \code{cli_sitrep} class, with a \code{print()} and \code{format()} method. } \description{ Contains currently: \itemize{ \item \code{cli_unicode_option}: whether the \code{cli.unicode} option is set and its value. See \code{\link[=is_utf8_output]{is_utf8_output()}}. \item \code{symbol_charset}: the selected character set for \link{symbol}, UTF-8, Windows, or ASCII. \item \code{console_utf8}: whether the console supports UTF-8. See \code{\link[base:l10n_info]{base::l10n_info()}}. \item \code{latex_active}: whether we are inside knitr, creating a LaTeX document. \item \code{num_colors}: number of ANSI colors. See \code{\link[=num_ansi_colors]{num_ansi_colors()}}. \item \code{console_with}: detected console width. } } \examples{ cli_sitrep() } cli/man/pluralization-helpers.Rd0000644000176200001440000000151114752735214016430 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/pluralize.R \name{no} \alias{no} \alias{qty} \title{Pluralization helper functions} \usage{ no(expr) qty(expr) } \arguments{ \item{expr}{For \code{no()} it is an expression that is printed as "no" in cli expressions, it is interpreted as a zero quantity. For \code{qty()} an expression that sets the pluralization quantity without printing anything. See examples below.} } \description{ Pluralization helper functions } \examples{ nfile <- 0; cli_text("Found {no(nfile)} file{?s}.") #> Found no files. nfile <- 1; cli_text("Found {no(nfile)} file{?s}.") #> Found 1 file. nfile <- 2; cli_text("Found {no(nfile)} file{?s}.") #> Found 2 files. } \seealso{ Other pluralization: \code{\link{pluralization}}, \code{\link{pluralize}()} } \concept{pluralization} cli/man/cli_end.Rd0000644000176200001440000000745514752364056013507 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/cli.R \name{cli_end} \alias{cli_end} \title{Close a CLI container} \usage{ cli_end(id = NULL) } \arguments{ \item{id}{Id of the container to close. If missing, the current container is closed, if any.} } \description{ Containers aut0-close by default, but sometimes you need to explicitly close them. Closing a container also closes all of its nested containers. } \details{ \subsection{Explicit closing}{ \if{html}{\out{
}}\preformatted{cnt <- cli_par() cli_text("First paragraph.") cli_end(cnt) cnt <- cli_par() cli_text("Second paragraph.") cli_end(cnt) }\if{html}{\out{
}}\if{html}{\out{
#> First paragraph.                                                                
#>                                                                                 
#> Second paragraph.                                                               
#>                                                                                 
}} } \subsection{Closing a stack of containers}{ \if{html}{\out{
}}\preformatted{list <- cli_ul() cli_li("Item one:") cli_li("Item two:") cli_par() cli_text("Still item two.") cli_end(list) cli_text("Not in the list any more") }\if{html}{\out{
}}\if{html}{\out{
#> • Item one:                                                                     
#> • Item two:                                                                     
#> Still item two.                                                                 
#>                                                                                 
#> Not in the list any more                                                        
}} } \subsection{Omitting \code{id}}{ If \code{id} is omitted, the container that was opened last will be closed. \if{html}{\out{
}}\preformatted{cli_par() cli_text("First paragraph") cli_end() cli_par() cli_text("Second paragraph") cli_end() }\if{html}{\out{
}}\if{html}{\out{
#> First paragraph                                                                 
#>                                                                                 
#> Second paragraph                                                                
#>                                                                                 
}} } \subsection{Debugging containers}{ You can use the internal \code{cli:::cli_debug_doc()} function to see the currently open containers. \if{html}{\out{
}}\preformatted{fun <- function() \{ cli_div(id = "mydiv") cli_par(class = "myclass") cli:::cli_debug_doc() \} fun() }\if{html}{\out{
}}\if{html}{\out{
#> <cli document>                                                                  
#> <body id="body">                                                                
#> <div id="mydiv"> +theme                                                         
#> <par id="cli-82040-64" class="myclass">                                         
}} } } cli/man/ansi_substr.Rd0000644000176200001440000000326114557444176014442 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/ansiex.R \name{ansi_substr} \alias{ansi_substr} \title{Substring(s) of an ANSI colored string} \usage{ ansi_substr(x, start, stop) } \arguments{ \item{x}{Character vector, potentially ANSI styled, or a vector to coerced to character.} \item{start}{Starting index or indices, recycled to match the length of \code{x}.} \item{stop}{Ending index or indices, recycled to match the length of \code{x}.} } \value{ Character vector of the same length as \code{x}, containing the requested substrings. ANSI styles are retained. } \description{ This is a color-aware counterpart of \code{\link[base:substr]{base::substr()}}. It works exactly like the original, but keeps the colors in the substrings. The ANSI escape sequences are ignored when calculating the positions within the string. } \examples{ str <- paste( col_red("red"), "default", col_green("green") ) cat(str, "\n") cat(ansi_substr(str, 1, 5), "\n") cat(ansi_substr(str, 1, 15), "\n") cat(ansi_substr(str, 3, 7), "\n") substr(ansi_strip(str), 1, 5) substr(ansi_strip(str), 1, 15) substr(ansi_strip(str), 3, 7) str2 <- paste( "another", col_red("multi-", style_underline("style")), "text" ) cat(str2, "\n") cat(ansi_substr(c(str, str2), c(3,5), c(7, 18)), sep = "\n") substr(ansi_strip(c(str, str2)), c(3,5), c(7, 18)) } \seealso{ Other ANSI string operations: \code{\link{ansi_align}()}, \code{\link{ansi_columns}()}, \code{\link{ansi_nchar}()}, \code{\link{ansi_strsplit}()}, \code{\link{ansi_strtrim}()}, \code{\link{ansi_strwrap}()}, \code{\link{ansi_substring}()}, \code{\link{ansi_toupper}()}, \code{\link{ansi_trimws}()} } \concept{ANSI string operations} cli/man/format_inline.Rd0000644000176200001440000000336414752735214014731 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/cli.R \name{format_inline} \alias{format_inline} \title{Format and returns a line of text} \usage{ format_inline( ..., .envir = parent.frame(), collapse = TRUE, keep_whitespace = TRUE ) } \arguments{ \item{...}{Passed to \code{\link[=cli_text]{cli_text()}}.} \item{.envir}{Environment to evaluate the expressions in.} \item{collapse}{Whether to collapse the result if it has multiple lines, e.g. because of \verb{\\f} characters.} \item{keep_whitespace}{Whether to keep all whitepace (spaces, newlines and form feeds) as is in the input.} } \value{ Character scalar, the formatted string. } \description{ You can use this function to format a line of cli text, without emitting it to the screen. It uses \code{\link[=cli_text]{cli_text()}} internally. } \details{ \code{format_inline()} performs no width-wrapping. } \examples{ format_inline("A message for {.emph later}, thanks {.fn format_inline}.") } \seealso{ This function supports \link[=inline-markup]{inline markup}. Other functions supporting inline markup: \code{\link{cli_abort}()}, \code{\link{cli_alert}()}, \code{\link{cli_blockquote}()}, \code{\link{cli_bullets}()}, \code{\link{cli_bullets_raw}()}, \code{\link{cli_dl}()}, \code{\link{cli_h1}()}, \code{\link{cli_li}()}, \code{\link{cli_ol}()}, \code{\link{cli_process_start}()}, \code{\link{cli_progress_along}()}, \code{\link{cli_progress_bar}()}, \code{\link{cli_progress_message}()}, \code{\link{cli_progress_output}()}, \code{\link{cli_progress_step}()}, \code{\link{cli_rule}}, \code{\link{cli_status}()}, \code{\link{cli_status_update}()}, \code{\link{cli_text}()}, \code{\link{cli_ul}()}, \code{\link{format_error}()} } \concept{functions supporting inline markup} cli/man/ansi_align.Rd0000644000176200001440000001064414752735214014206 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/ansiex.R \name{ansi_align} \alias{ansi_align} \title{Align an ANSI colored string} \usage{ ansi_align( text, width = console_width(), align = c("left", "center", "right"), type = "width" ) } \arguments{ \item{text}{The character vector to align.} \item{width}{Width of the field to align in.} \item{align}{Whether to align \code{"left"}, \code{"center"} or \code{"right"}.} \item{type}{Passed on to \code{\link[=ansi_nchar]{ansi_nchar()}} and there to \code{\link[=nchar]{nchar()}}} } \value{ The aligned character vector. } \description{ Align an ANSI colored string } \details{ \if{html}{\out{
}}\preformatted{str <- c( col_red("This is red"), style_bold("This is bold") ) astr <- ansi_align(str, width = 30) boxx(astr) }\if{html}{\out{
}}\if{html}{\out{
#> ┌────────────────────────────────────┐                                          
#> │                                    │                                          
#> │   This is red                      │                                          
#> │   This is bold                     │                                          
#> │                                    │                                          
#> └────────────────────────────────────┘                                          
}} \if{html}{\out{
}}\preformatted{str <- c( col_red("This is red"), style_bold("This is bold") ) astr <- ansi_align(str, align = "center", width = 30) boxx(astr) }\if{html}{\out{
}}\if{html}{\out{
#> ┌────────────────────────────────────┐                                          
#> │                                    │                                          
#> │             This is red            │                                          
#> │            This is bold            │                                          
#> │                                    │                                          
#> └────────────────────────────────────┘                                          
}} \if{html}{\out{
}}\preformatted{str <- c( col_red("This is red"), style_bold("This is bold") ) astr <- ansi_align(str, align = "right", width = 30) boxx(astr) }\if{html}{\out{
}}\if{html}{\out{
#> ┌────────────────────────────────────┐                                          
#> │                                    │                                          
#> │                      This is red   │                                          
#> │                     This is bold   │                                          
#> │                                    │                                          
#> └────────────────────────────────────┘                                          
}} } \seealso{ Other ANSI string operations: \code{\link{ansi_columns}()}, \code{\link{ansi_nchar}()}, \code{\link{ansi_strsplit}()}, \code{\link{ansi_strtrim}()}, \code{\link{ansi_strwrap}()}, \code{\link{ansi_substr}()}, \code{\link{ansi_substring}()}, \code{\link{ansi_toupper}()}, \code{\link{ansi_trimws}()} } \concept{ANSI string operations} cli/man/has_keypress_support.Rd0000644000176200001440000000144114557444176016400 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/keypress.R \name{has_keypress_support} \alias{has_keypress_support} \title{Check if the current platform/terminal supports reading single keys.} \usage{ has_keypress_support() } \value{ Whether there is support for waiting for individual keypressses. } \description{ Check if the current platform/terminal supports reading single keys. } \details{ Supported platforms: \itemize{ \item Terminals in Windows and Unix. \item RStudio terminal. } Not supported: \itemize{ \item RStudio (if not in the RStudio terminal). \item R.app on macOS. \item Rgui on Windows. \item Emacs ESS. \item Others. } } \examples{ has_keypress_support() } \seealso{ Other keypress function: \code{\link{keypress}()} } \concept{keypress function} cli/man/ansi_toupper.Rd0000644000176200001440000000412514752735214014607 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/ansiex.R \name{ansi_toupper} \alias{ansi_toupper} \alias{ansi_tolower} \alias{ansi_chartr} \title{ANSI character translation and case folding} \usage{ ansi_toupper(x) ansi_tolower(x) ansi_chartr(old, new, x) } \arguments{ \item{x}{Input string. May have ANSI colors and styles.} \item{old}{a character string specifying the characters to be translated. If a character vector of length 2 or more is supplied, the first element is used with a warning.} \item{new}{a character string specifying the translations. If a character vector of length 2 or more is supplied, the first element is used with a warning.} } \value{ Character vector of the same length as \code{x}, containing the translated strings. ANSI styles are retained. } \description{ There functions are similar to \code{\link[=toupper]{toupper()}}, \code{\link[=tolower]{tolower()}} and \code{\link[=chartr]{chartr()}}, but they keep the ANSI colors of the string. } \examples{ ansi_toupper(col_red("Uppercase")) ansi_tolower(col_red("LowerCase")) x <- paste0(col_green("MiXeD"), col_red(" cAsE 123")) ansi_chartr("iXs", "why", x) } \seealso{ Other ANSI string operations: \code{\link{ansi_align}()}, \code{\link{ansi_columns}()}, \code{\link{ansi_nchar}()}, \code{\link{ansi_strsplit}()}, \code{\link{ansi_strtrim}()}, \code{\link{ansi_strwrap}()}, \code{\link{ansi_substr}()}, \code{\link{ansi_substring}()}, \code{\link{ansi_trimws}()} Other ANSI string operations: \code{\link{ansi_align}()}, \code{\link{ansi_columns}()}, \code{\link{ansi_nchar}()}, \code{\link{ansi_strsplit}()}, \code{\link{ansi_strtrim}()}, \code{\link{ansi_strwrap}()}, \code{\link{ansi_substr}()}, \code{\link{ansi_substring}()}, \code{\link{ansi_trimws}()} Other ANSI string operations: \code{\link{ansi_align}()}, \code{\link{ansi_columns}()}, \code{\link{ansi_nchar}()}, \code{\link{ansi_strsplit}()}, \code{\link{ansi_strtrim}()}, \code{\link{ansi_strwrap}()}, \code{\link{ansi_substr}()}, \code{\link{ansi_substring}()}, \code{\link{ansi_trimws}()} } \concept{ANSI string operations} cli/man/progress-c.Rd0000644000176200001440000001556414557444176014203 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/docs.R \name{progress-c} \alias{progress-c} \title{The cli progress C API} \description{ The cli progress C API } \section{The cli progress C API}{ \subsection{\code{CLI_SHOULD_TICK}}{ A macro that evaluates to (int) 1 if a cli progress bar update is due, and to (int) 0 otherwise. If the timer hasn't been initialized in this compilation unit yet, then it is always 0. To initialize the timer, call \code{cli_progress_init_timer()} or create a progress bar with \code{cli_progress_bar()}. } \subsection{\code{cli_progress_add()}}{ \if{html}{\out{
}}\preformatted{void cli_progress_add(SEXP bar, double inc); }\if{html}{\out{
}} Add a number of progress units to the progress bar. It will also trigger an update if an update is due. \itemize{ \item \code{bar}: progress bar object. \item \code{inc}: progress increment. } } \subsection{\code{cli_progress_bar()}}{ \if{html}{\out{
}}\preformatted{SEXP cli_progress_bar(double total, SEXP config); }\if{html}{\out{
}} Create a new progress bar object. The returned progress bar object must be \code{PROTECT()}-ed. \itemize{ \item \code{total}: Total number of progress units. Use \code{NA_REAL} if it is not known. \item \code{config}: R named list object of additional parameters. May be \code{NULL} (the C \verb{NULL~) or }R_NilValue\verb{(the R}NULL`) for the defaults. } \code{config} may contain the following entries: \itemize{ \item \code{name}: progress bar name. \item \code{status}: (initial) progress bar status. \item \code{type}: progress bar type. \item \code{total}: total number of progress units. \item \code{show_after}: show the progress bar after the specified number of seconds. This overrides the global \code{show_after} option. \item \code{format}: format string, must be specified for custom progress bars. \item \code{format_done}: format string for successful termination. \item \code{format_failed}: format string for unsuccessful termination. \item \code{clear}: whether to remove the progress bar from the screen after termination. \item \code{auto_terminate}: whether to terminate the progress bar when the number of current units equals the number of total progress units. } \subsection{Example}{ \if{html}{\out{
}}\preformatted{#include SEXP progress_test1() \{ int i; SEXP bar = PROTECT(cli_progress_bar(1000, NULL)); for (i = 0; i < 1000; i++) \{ cli_progress_sleep(0, 4 * 1000 * 1000); if (CLI_SHOULD_TICK) cli_progress_set(bar, i); \} cli_progress_done(bar); UNPROTECT(1); return Rf_ScalarInteger(i); \} }\if{html}{\out{
}} } } \subsection{\code{cli_progress_done()}}{ \if{html}{\out{
}}\preformatted{void cli_progress_done(SEXP bar); }\if{html}{\out{
}} Terminate the progress bar. \itemize{ \item \code{bar}: progress bar object. } } \subsection{\code{cli_progress_init_timer()}}{ \if{html}{\out{
}}\preformatted{void cli_progress_init_timer(); }\if{html}{\out{
}} Initialize the cli timer without creating a progress bar. } \subsection{\code{cli_progress_num()}}{ \if{html}{\out{
}}\preformatted{int cli_progress_num(); }\if{html}{\out{
}} Returns the number of currently active progress bars. } \subsection{\code{cli_progress_set()}}{ \if{html}{\out{
}}\preformatted{void cli_progress_set(SEXP bar, double set); }\if{html}{\out{
}} Set the progress bar to the specified number of progress units. \itemize{ \item \code{bar}: progress bar object. \item \code{set}: number of current progress progress units. } } \subsection{\code{cli_progress_set_clear()}}{ \if{html}{\out{
}}\preformatted{void cli_progress_set_clear(SEXP bar, int clear); }\if{html}{\out{
}} Set whether to remove the progress bar from the screen. You can call this any time before \code{cli_progress_done()} is called. \itemize{ \item \code{bar}: progress bar object. \item \code{clear}: whether to remove the progress bar from the screen, zero or one. } } \subsection{\code{cli_progress_set_format()}}{ \if{html}{\out{
}}\preformatted{void cli_progress_set_format(SEXP bar, const char *format, ...); }\if{html}{\out{
}} Set a custom format string for the progress bar. This call does not try to update the progress bar. If you want to request an update, call \code{cli_progress_add()}, \code{cli_progress_set()} or \code{cli_progress_update()}. \itemize{ \item \code{bar}: progress bar object. \item \code{format}: format string. \item \code{...}: values to substitute into \code{format}. } \code{format} and \code{...} are passed to \code{vsnprintf()} to create a format string. Format strings may contain glue substitutions, referring to \href{https://cli.r-lib.org/dev/reference/progress-variables.html}{progress variables}, pluralization, and cli styling. } \subsection{\code{cli_progress_set_name()}}{ \if{html}{\out{
}}\preformatted{void cli_progress_set_name(SEXP bar, const char *name); }\if{html}{\out{
}} Set the name of the progress bar. \itemize{ \item \code{bar}; progress bar object. \item \code{name}: progress bar name. } } \subsection{\code{cli_progress_set_status()}}{ \if{html}{\out{
}}\preformatted{void cli_progress_set_status(SEXP bar, const char *status); }\if{html}{\out{
}} Set the status of the progress bar. \itemize{ \item \code{bar}: progress bar object. \item \code{status }: progress bar status. } } \subsection{\code{cli_progress_set_type()}}{ \if{html}{\out{
}}\preformatted{void cli_progress_set_type(SEXP bar, const char *type); }\if{html}{\out{
}} Set the progress bar type. Call this function right after creating the progress bar with \code{cli_progress_bar()}. Otherwise the behavior is undefined. \itemize{ \item \code{bar}: progress bar object. \item \code{type}: progress bar type. Possible progress bar types: \code{iterator}, \code{tasks}, \code{download} and \code{custom}. } } \subsection{\code{cli_progress_update()}}{ \if{html}{\out{
}}\preformatted{void cli_progress_update(SEXP bar, double set, double inc, int force); }\if{html}{\out{
}} Update the progress bar. Unlike the simpler \code{cli_progress_add()} and \code{cli_progress_set()} function, it can force an update if \code{force} is set to 1. \itemize{ \item \code{bar}: progress bar object. \item \code{set}: the number of current progress units. It is ignored if negative. \item \code{inc}: increment to add to the current number of progress units. It is ignored if \code{set} is not negative. \item \code{force}: whether to force an update, even if no update is due. } To force an update without changing the current number of progress units, supply \code{set = -1}, \code{inc = 0} and \code{force = 1}. } } cli/man/test_that_cli.Rd0000644000176200001440000000620014557444176014730 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/test.R \name{test_that_cli} \alias{test_that_cli} \title{Test cli output with testthat} \usage{ test_that_cli( desc, code, configs = c("plain", "ansi", "unicode", "fancy"), links = NULL ) } \arguments{ \item{desc}{Test description, passed to \code{\link[testthat:test_that]{testthat::test_that()}}, after appending the name of the cli configuration to it.} \item{code}{Test code, it is modified to set up the cli config, and then passed to \code{\link[testthat:test_that]{testthat::test_that()}}} \item{configs}{cli configurations to test \code{code} with. The default is \code{NULL}, which includes all possible configurations. It can also be a character vector, to restrict the tests to some configurations only. See available configurations below.} \item{links}{Whether to run the code with various hyperlinks allowed. If \code{NULL} then hyperlinks are turned off. Otherwise it can be a character vector with possible hyperlink configurations: \itemize{ \item \code{"all"}: turn on all hyperlinks, \item \code{"none"}: turn off all hyperlinks. }} } \description{ Use this function in your testthat test files, to test cli output. It requires testthat edition 3, and works best with snapshot tests. } \details{ \code{test_that_cli()} calls \code{\link[testthat:test_that]{testthat::test_that()}} multiple times, with different cli configurations. This makes it simple to test cli output with and without ANSI colors, with and without Unicode characters. Currently available configurations: \itemize{ \item \code{plain}: no ANSI colors, ASCII characters only. \item \code{ansi}: ANSI colors, ASCII characters only. \item \code{unicode}: no ANSI colors, Unicode characters. \item \code{fancy}; ANSI colors, Unicode characters. } See examples below and in cli's own tests, e.g. in \url{https://github.com/r-lib/cli/tree/main/tests/testthat} and the corresponding snapshots at \url{https://github.com/r-lib/cli/tree/main/tests/testthat/_snaps} \subsection{Important note regarding Windows}{ Because of base R's limitation to record Unicode characters on Windows, we suggest that you record your snapshots on Unix, or you restrict your tests to ASCII configurations. Unicode tests on Windows are automatically skipped by testthat currently. } } \examples{ # testthat cannot record or compare snapshots when you run these # examples interactively, so you might want to copy them into a test # file # Default configurations cli::test_that_cli("success", { testthat::local_edition(3) testthat::expect_snapshot({ cli::cli_alert_success("wow") }) }) # Only use two configurations, because this output does not have colors cli::test_that_cli(configs = c("plain", "unicode"), "cat_bullet", { testthat::local_edition(3) testthat::expect_snapshot({ cli::cat_bullet(letters[1:5]) }) }) # You often need to evaluate all cli calls of a test case in the same # environment. Use `local()` to do that: cli::test_that_cli("theming", { testthat::local_edition(3) testthat::expect_snapshot(local({ cli::cli_div(theme = list(".alert" = list(before = "!!! "))) cli::cli_alert("wow") })) }) } cli/man/is_utf8_output.Rd0000644000176200001440000000102714557444176015105 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/utf8.R \name{is_utf8_output} \alias{is_utf8_output} \title{Whether cli is emitting UTF-8 characters} \usage{ is_utf8_output() } \value{ Flag, whether cli uses UTF-8 characters. } \description{ UTF-8 cli characters can be turned on by setting the \code{cli.unicode} option to \code{TRUE}. They can be turned off by setting if to \code{FALSE}. If this option is not set, then \code{\link[base:l10n_info]{base::l10n_info()}} is used to detect UTF-8 support. } cli/man/roxygen/0000755000176200001440000000000014557444176013310 5ustar liggesuserscli/man/roxygen/meta.R0000644000176200001440000000147314557444176014366 0ustar liggesusers if (exists(".knitr_asciicast_process", envir = .GlobalEnv)) { rm(list = ".knitr_asciicast_process", envir = .GlobalEnv) } asciicast::init_knitr_engine( echo = TRUE, echo_input = FALSE, interactive = TRUE, timeout = as.integer(Sys.getenv("ASCIICAST_TIMEOUT", 10)), startup = quote({ options(cli.width = 70) options(cli.progress_show_after = 0) options(cli.progress_clear = FALSE) library(cli) set.seed(1) }) ) knitr::opts_chunk$set( asciicast_knitr_output = "html", asciicast_include_style = FALSE, asciicast_theme = "pkgdown" ) list( markdown = TRUE, knitr_chunk_options = list( cache = TRUE, cache_lazy = FALSE, cache.path = file.path(getwd(), "man/_cache/"), fig.path = file.path(getwd(), "man/figures"), error = TRUE ), restrict_image_formats = TRUE ) cli/man/ansi_substring.Rd0000644000176200001440000000342414557444176015141 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/ansiex.R \name{ansi_substring} \alias{ansi_substring} \title{Substring(s) of an ANSI colored string} \usage{ ansi_substring(text, first, last = 1000000L) } \arguments{ \item{text}{Character vector, potentially ANSI styled, or a vector to coerced to character. It is recycled to the longest of \code{first} and \code{last}.} \item{first}{Starting index or indices, recycled to match the length of \code{x}.} \item{last}{Ending index or indices, recycled to match the length of \code{x}.} } \value{ Character vector of the same length as \code{x}, containing the requested substrings. ANSI styles are retained. } \description{ This is the color-aware counterpart of \code{\link[base:substr]{base::substring()}}. It works exactly like the original, but keeps the colors in the substrings. The ANSI escape sequences are ignored when calculating the positions within the string. } \examples{ str <- paste( col_red("red"), "default", col_green("green") ) cat(str, "\n") cat(ansi_substring(str, 1, 5), "\n") cat(ansi_substring(str, 1, 15), "\n") cat(ansi_substring(str, 3, 7), "\n") substring(ansi_strip(str), 1, 5) substring(ansi_strip(str), 1, 15) substring(ansi_strip(str), 3, 7) str2 <- paste( "another", col_red("multi-", style_underline("style")), "text" ) cat(str2, "\n") cat(ansi_substring(str2, c(3,5), c(7, 18)), sep = "\n") substring(ansi_strip(str2), c(3,5), c(7, 18)) } \seealso{ Other ANSI string operations: \code{\link{ansi_align}()}, \code{\link{ansi_columns}()}, \code{\link{ansi_nchar}()}, \code{\link{ansi_strsplit}()}, \code{\link{ansi_strtrim}()}, \code{\link{ansi_strwrap}()}, \code{\link{ansi_substr}()}, \code{\link{ansi_toupper}()}, \code{\link{ansi_trimws}()} } \concept{ANSI string operations} cli/man/make_ansi_style.Rd0000644000176200001440000000414114557444176015253 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/ansi.R \name{make_ansi_style} \alias{make_ansi_style} \title{Create a new ANSI style} \usage{ make_ansi_style(..., bg = FALSE, grey = FALSE, colors = num_ansi_colors()) } \arguments{ \item{...}{The style to create. See details and examples below.} \item{bg}{Whether the color applies to the background.} \item{grey}{Whether to specifically create a grey color. This flag is included, because ANSI 256 has a finer color scale for greys, then the usual 0:5 scale for red, green and blue components. It is only used for RGB color specifications (either numerically or via a hexadecimal string), and it is ignored on eight color ANSI terminals.} \item{colors}{Number of colors, detected automatically by default.} } \value{ A function that can be used to color (style) strings. } \description{ Create a function that can be used to add ANSI styles to text. } \details{ The \code{...} style argument can be any of the following: \itemize{ \item A cli ANSI style function of class \code{cli_ansi_style}. This is returned as is, without looking at the other arguments. \item An R color name, see \code{\link[grDevices:colors]{grDevices::colors()}}. \item A 6- or 8-digit hexadecimal color string, e.g. \verb{#ff0000} means red. Transparency (alpha channel) values are ignored. \item A one-column matrix with three rows for the red, green and blue channels, as returned by \code{\link[grDevices:col2rgb]{grDevices::col2rgb()}}. } \code{make_ansi_style()} detects the number of colors to use automatically (this can be overridden using the \code{colors} argument). If the number of colors is less than 256 (detected or given), then it falls back to the color in the ANSI eight color mode that is closest to the specified (RGB or R) color. } \examples{ make_ansi_style("orange") make_ansi_style("#123456") make_ansi_style("orange", bg = TRUE) orange <- make_ansi_style("orange") orange("foobar") cat(orange("foobar")) } \seealso{ Other ANSI styling: \code{\link{ansi-styles}}, \code{\link{combine_ansi_styles}()}, \code{\link{num_ansi_colors}()} } \concept{ANSI styling} cli/man/cli_bullets.Rd0000644000176200001440000000774014752735214014406 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/bullets.R \name{cli_bullets} \alias{cli_bullets} \title{List of items} \usage{ cli_bullets(text, id = NULL, class = NULL, .envir = parent.frame()) } \arguments{ \item{text}{Character vector of items. See details below on how names are interpreted.} \item{id}{Optional id of the \code{div.bullets} element, can be used in themes.} \item{class}{Optional additional class(es) for the \code{div.bullets} element.} \item{.envir}{Environment to evaluate the glue expressions in.} } \description{ It is often useful to print out a list of items, tasks a function or package performs, or a list of notes. } \details{ Items may be formatted differently, e.g. they can have a prefix symbol. Formatting is specified by the names of \code{text}, and can be themed. cli creates a \code{div} element of class \code{bullets} for the whole bullet list. Each item is another \code{div} element of class \verb{bullet-}, where \verb{} is the name of the entry in \code{text}. Entries in \code{text} without a name create a \code{div} element of class \code{bullet-empty}, and if the name is a single space character, the class is \code{bullet-space}. The built-in theme defines the following item types: \itemize{ \item No name: Item without a prefix. \item \verb{ }: Indented item. \item \code{*}: Item with a bullet. \item \code{>}: Item with an arrow or pointer. \item \code{v}: Item with a green "tick" symbol, like \code{\link[=cli_alert_success]{cli_alert_success()}}. \item \code{x}: Item with a ref cross, like \code{\link[=cli_alert_danger]{cli_alert_danger()}}. \item \code{!}: Item with a yellow exclamation mark, like \code{\link[=cli_alert_warning]{cli_alert_warning()}}. \item \code{i}: Info item, like \code{\link[=cli_alert_info]{cli_alert_info()}}. } You can define new item type by simply defining theming for the corresponding \verb{bullet-} classes. \if{html}{\out{
}}\preformatted{cli_bullets(c( "noindent", " " = "indent", "*" = "bullet", ">" = "arrow", "v" = "success", "x" = "danger", "!" = "warning", "i" = "info" )) }\if{html}{\out{
}}\if{html}{\out{
#> noindent                                                                        
#>   indent                                                                        
#>  bullet                                                                        
#> → arrow                                                                         
#>  success                                                                       
#>  danger                                                                        
#> ! warning                                                                       
#>  info                                                                          
}} } \seealso{ This function supports \link[=inline-markup]{inline markup}. Other functions supporting inline markup: \code{\link{cli_abort}()}, \code{\link{cli_alert}()}, \code{\link{cli_blockquote}()}, \code{\link{cli_bullets_raw}()}, \code{\link{cli_dl}()}, \code{\link{cli_h1}()}, \code{\link{cli_li}()}, \code{\link{cli_ol}()}, \code{\link{cli_process_start}()}, \code{\link{cli_progress_along}()}, \code{\link{cli_progress_bar}()}, \code{\link{cli_progress_message}()}, \code{\link{cli_progress_output}()}, \code{\link{cli_progress_step}()}, \code{\link{cli_rule}}, \code{\link{cli_status}()}, \code{\link{cli_status_update}()}, \code{\link{cli_text}()}, \code{\link{cli_ul}()}, \code{\link{format_error}()}, \code{\link{format_inline}()} } \concept{functions supporting inline markup} cli/man/pluralization.Rd0000644000176200001440000002134014557444176015001 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/pluralize.R \name{pluralization} \alias{pluralization} \title{About cli pluralization} \description{ About cli pluralization } \section{Introduction}{ cli has tools to create messages that are printed correctly in singular and plural forms. This usually requires minimal extra work, and increases the quality of the messages greatly. In this document we first show some pluralization examples that you can use as guidelines. Hopefully these are intuitive enough, so that they can be used without knowing the exact cli pluralization rules. If you need pluralization without the semantic cli functions, see the \code{pluralize()} function. } \section{Examples}{ \subsection{Pluralization markup}{ In the simplest case the message contains a single \code{{}} glue substitution, which specifies the quantity that is used to select between the singular and plural forms. Pluralization uses markup that is similar to glue, but uses the \verb{\{?} and \verb{\}} delimiters: \if{html}{\out{
}}\preformatted{library(cli) nfile <- 0; cli_text("Found \{nfile\} file\{?s\}.") }\if{html}{\out{
}} \if{html}{\out{
}}\preformatted{#> Found 0 files. }\if{html}{\out{
}} \if{html}{\out{
}}\preformatted{nfile <- 1; cli_text("Found \{nfile\} file\{?s\}.") }\if{html}{\out{
}} \if{html}{\out{
}}\preformatted{#> Found 1 file. }\if{html}{\out{
}} \if{html}{\out{
}}\preformatted{nfile <- 2; cli_text("Found \{nfile\} file\{?s\}.") }\if{html}{\out{
}} \if{html}{\out{
}}\preformatted{#> Found 2 files. }\if{html}{\out{
}} Here the value of \code{nfile} is used to decide whether the singular or plural form of \code{file} is used. This is the most common case for English messages. } \subsection{Irregular plurals}{ If the plural form is more difficult than a simple \code{s} suffix, then the singular and plural forms can be given, separated with a forward slash: \if{html}{\out{
}}\preformatted{ndir <- 1; cli_text("Found \{ndir\} director\{?y/ies\}.") }\if{html}{\out{
}} \if{html}{\out{
}}\preformatted{#> Found 1 directory. }\if{html}{\out{
}} \if{html}{\out{
}}\preformatted{ndir <- 5; cli_text("Found \{ndir\} director\{?y/ies\}.") }\if{html}{\out{
}} \if{html}{\out{
}}\preformatted{#> Found 5 directories. }\if{html}{\out{
}} } \subsection{Use \code{"no"} instead of zero}{ For readability, it is better to use the \code{no()} helper function to include a count in a message. \code{no()} prints the word \code{"no"} if the count is zero, and prints the numeric count otherwise: \if{html}{\out{
}}\preformatted{nfile <- 0; cli_text("Found \{no(nfile)\} file\{?s\}.") }\if{html}{\out{
}} \if{html}{\out{
}}\preformatted{#> Found no files. }\if{html}{\out{
}} \if{html}{\out{
}}\preformatted{nfile <- 1; cli_text("Found \{no(nfile)\} file\{?s\}.") }\if{html}{\out{
}} \if{html}{\out{
}}\preformatted{#> Found 1 file. }\if{html}{\out{
}} \if{html}{\out{
}}\preformatted{nfile <- 2; cli_text("Found \{no(nfile)\} file\{?s\}.") }\if{html}{\out{
}} \if{html}{\out{
}}\preformatted{#> Found 2 files. }\if{html}{\out{
}} } \subsection{Use the length of character vectors}{ With the auto-collapsing feature of cli it is easy to include a list of objects in a message. When cli interprets a character vector as a pluralization quantity, it takes the length of the vector: \if{html}{\out{
}}\preformatted{pkgs <- "pkg1" cli_text("Will remove the \{.pkg \{pkgs\}\} package\{?s\}.") }\if{html}{\out{
}} \if{html}{\out{
}}\preformatted{#> Will remove the pkg1 package. }\if{html}{\out{
}} \if{html}{\out{
}}\preformatted{pkgs <- c("pkg1", "pkg2", "pkg3") cli_text("Will remove the \{.pkg \{pkgs\}\} package\{?s\}.") }\if{html}{\out{
}} \if{html}{\out{
}}\preformatted{#> Will remove the pkg1, pkg2, and pkg3 packages. }\if{html}{\out{
}} Note that the length is only used for non-numeric vectors (when \code{is.numeric(x)} return \code{FALSE}). If you want to use the length of a numeric vector, convert it to character via \code{as.character()}. You can combine collapsed vectors with \code{"no"}, like this: \if{html}{\out{
}}\preformatted{pkgs <- character() cli_text("Will remove \{?no/the/the\} \{.pkg \{pkgs\}\} package\{?s\}.") }\if{html}{\out{
}} \if{html}{\out{
}}\preformatted{#> Will remove no packages. }\if{html}{\out{
}} \if{html}{\out{
}}\preformatted{pkgs <- c("pkg1", "pkg2", "pkg3") cli_text("Will remove \{?no/the/the\} \{.pkg \{pkgs\}\} package\{?s\}.") }\if{html}{\out{
}} \if{html}{\out{
}}\preformatted{#> Will remove the pkg1, pkg2, and pkg3 packages. }\if{html}{\out{
}} When the pluralization markup contains three alternatives, like above, the first one is used for zero, the second for one, and the third one for larger quantities. } \subsection{Choosing the right quantity}{ When the text contains multiple glue \code{{}} substitutions, the one right before the pluralization markup is used. For example: \if{html}{\out{
}}\preformatted{nfiles <- 3; ndirs <- 1 cli_text("Found \{nfiles\} file\{?s\} and \{ndirs\} director\{?y/ies\}") }\if{html}{\out{
}} \if{html}{\out{
}}\preformatted{#> Found 3 files and 1 directory }\if{html}{\out{
}} This is sometimes not the the correct one. You can explicitly specify the correct quantity using the \code{qty()} function. This sets that quantity without printing anything: \if{html}{\out{
}}\preformatted{nupd <- 3; ntotal <- 10 cli_text("\{nupd\}/\{ntotal\} \{qty(nupd)\} file\{?s\} \{?needs/need\} updates") }\if{html}{\out{
}} \if{html}{\out{
}}\preformatted{#> 3/10 files need updates }\if{html}{\out{
}} Note that if the message only contains a single \code{{}} substitution, then this may appear before or after the pluralization markup. If the message contains multiple \code{{}} substitutions \emph{after} pluralization markup, an error is thrown. Similarly, if the message contains no \code{{}} substitutions at all, but has pluralization markup, an error is thrown. } } \section{Rules}{ The exact rules of cli pluralization. There are two sets of rules. The first set specifies how a quantity is associated with a \verb{\{?\}} pluralization markup. The second set describes how the \verb{\{?\}} is parsed and interpreted. \subsection{Quantities}{ \enumerate{ \item \code{{}} substitutions define quantities. If the value of a \code{{}} substitution is numeric (when \code{is.numeric(x)} holds), then it has to have length one to define a quantity. This is only enforced if the \code{{}} substitution is used for pluralization. The quantity is defined as the value of \code{{}} then, rounded with \code{as.integer()}. If the value of \code{{}} is not numeric, then its quantity is defined as its length. \item If a message has \verb{\{?\}} markup but no \code{{}} substitution, an error is thrown. \item If a message has exactly one \code{{}} substitution, its value is used as the pluralization quantity for all \verb{\{?\}} markup in the message. \item If a message has multiple \code{{}} substitutions, then for each \verb{\{?\}} markup cli uses the quantity of the \code{{}} substitution that precedes it. \item If a message has multiple \code{{}} substitutions and has pluralization markup without a preceding \code{{}} substitution, an error is thrown. } } \subsection{Pluralization markup}{ \enumerate{ \item Pluralization markup starts with \verb{\{?} and ends with \verb{\}}. It may not contain \verb{\{} and \verb{\}} characters, so it may not contain \code{{}} substitutions either. \item Alternative words or suffixes are separated by \code{/}. \item If there is a single alternative, then \emph{nothing} is used if \code{quantity == 1} and this single alternative is used if \code{quantity != 1}. \item If there are two alternatives, the first one is used for \code{quantity == 1}, the second one for \code{quantity != 1} (including `\code{quantity == 0}). \item If there are three alternatives, the first one is used for \code{quantity == 0}, the second one for \code{quantity == 1}, and the third one otherwise. } } } \seealso{ Other pluralization: \code{\link{no}()}, \code{\link{pluralize}()} } \concept{pluralization} cli/man/cli_dl.Rd0000644000176200001440000000664714752735214013340 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/cli.R \name{cli_dl} \alias{cli_dl} \title{Definition list} \usage{ cli_dl( items = NULL, labels = names(items), id = NULL, class = NULL, .close = TRUE, .auto_close = TRUE, .envir = parent.frame() ) } \arguments{ \item{items}{Named character vector, or \code{NULL}. If not \code{NULL}, they are used as list items.} \item{labels}{Item labels. Defaults the names in \code{items}.} \item{id}{Id of the list container. Can be used for closing it with \code{\link[=cli_end]{cli_end()}} or in themes. If \code{NULL}, then an id is generated and returned invisibly.} \item{class}{Class of the list container. Can be used in themes.} \item{.close}{Whether to close the list container if the \code{items} were specified. If \code{FALSE} then new items can be added to the list.} \item{.auto_close}{Whether to close the container, when the calling function finishes (or \code{.envir} is removed, if specified).} \item{.envir}{Environment to evaluate the glue expressions in. It is also used to auto-close the container if \code{.auto_close} is \code{TRUE}.} } \value{ The id of the new container element, invisibly. } \description{ A definition list is a container, see \link{containers}. } \details{ \subsection{All items at once}{ \if{html}{\out{
}}\preformatted{fun <- function() \{ cli_dl(c(foo = "one", bar = "two", baz = "three")) \} fun() }\if{html}{\out{
}}\if{html}{\out{
#> foo: one                                                                        
#> bar: two                                                                        
#> baz: three                                                                      
}} } \subsection{Items one by one}{ \if{html}{\out{
}}\preformatted{fun <- function() \{ cli_dl() cli_li(c(foo = "\{.emph one\}")) cli_li(c(bar = "two")) cli_li(c(baz = "three")) \} fun() }\if{html}{\out{
}}\if{html}{\out{
#> foo: one                                                                        
#> bar: two                                                                        
#> baz: three                                                                      
}} } } \seealso{ This function supports \link[=inline-markup]{inline markup}. Other functions supporting inline markup: \code{\link{cli_abort}()}, \code{\link{cli_alert}()}, \code{\link{cli_blockquote}()}, \code{\link{cli_bullets}()}, \code{\link{cli_bullets_raw}()}, \code{\link{cli_h1}()}, \code{\link{cli_li}()}, \code{\link{cli_ol}()}, \code{\link{cli_process_start}()}, \code{\link{cli_progress_along}()}, \code{\link{cli_progress_bar}()}, \code{\link{cli_progress_message}()}, \code{\link{cli_progress_output}()}, \code{\link{cli_progress_step}()}, \code{\link{cli_rule}}, \code{\link{cli_status}()}, \code{\link{cli_status_update}()}, \code{\link{cli_text}()}, \code{\link{cli_ul}()}, \code{\link{format_error}()}, \code{\link{format_inline}()} } \concept{functions supporting inline markup} cli/man/ansi_nzchar.Rd0000644000176200001440000000106114557444176014401 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/ansiex.R \name{ansi_nzchar} \alias{ansi_nzchar} \title{Like \code{\link[base:nchar]{base::nzchar()}}, but for ANSI strings} \usage{ ansi_nzchar(x, ...) } \arguments{ \item{x}{Charcater vector. Other objects are coarced using \code{\link[base:character]{base::as.character()}}.} \item{...}{Passed to \code{\link[base:nchar]{base::nzchar()}}.} } \description{ Like \code{\link[base:nchar]{base::nzchar()}}, but for ANSI strings } \examples{ ansi_nzchar("") ansi_nzchar(col_red("")) } cli/man/cli_progress_step.Rd0000644000176200001440000001244114752735214015625 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/progress-client.R \name{cli_progress_step} \alias{cli_progress_step} \title{Simplified cli progress messages, with styling} \usage{ cli_progress_step( msg, msg_done = msg, msg_failed = msg, spinner = FALSE, class = if (!spinner) ".alert-info", current = TRUE, .auto_close = TRUE, .envir = parent.frame(), ... ) } \arguments{ \item{msg}{Message to show. It may contain glue substitution and cli styling. It can be updated via \code{\link[=cli_progress_update]{cli_progress_update()}}, as usual. It is style as a cli info alert (see \code{\link[=cli_alert_info]{cli_alert_info()}}).} \item{msg_done}{Message to show on successful termination. By default this it is the same as \code{msg} and it is styled as a cli success alert (see \code{\link[=cli_alert_success]{cli_alert_success()}}).} \item{msg_failed}{Message to show on unsuccessful termination. By default it is the same as \code{msg} and it is styled as a cli danger alert (see \code{\link[=cli_alert_danger]{cli_alert_danger()}}).} \item{spinner}{Whether to show a spinner at the beginning of the line. To make the spinner spin, you'll need to call \code{cli_progress_update()} regularly.} \item{class}{cli class to add to the message. By default there is no class for steps with a spinner.} \item{current}{Passed to \code{\link[=cli_progress_bar]{cli_progress_bar()}}.} \item{.auto_close}{Passed to \code{\link[=cli_progress_bar]{cli_progress_bar()}}.} \item{.envir}{Passed to \code{\link[=cli_progress_bar]{cli_progress_bar()}}.} \item{...}{Passed to \code{\link[=cli_progress_bar]{cli_progress_bar()}}.} } \description{ This is a simplified progress bar, a single (dynamic) message, without progress units. } \details{ \code{cli_progress_step()} always shows the progress message, even if no update is due. \subsection{Basic use}{ \if{html}{\out{
}}\preformatted{f <- function() \{ cli_progress_step("Downloading data") Sys.sleep(2) cli_progress_step("Importing data") Sys.sleep(1) cli_progress_step("Cleaning data") Sys.sleep(2) cli_progress_step("Fitting model") Sys.sleep(3) \} f() }\if{html}{\out{
}} \if{html}{\figure{progress-step.svg}} } \subsection{Spinner}{ You can add a spinner to some or all steps with \code{spinner = TRUE}, but note that this will only work if you call \code{\link[=cli_progress_update]{cli_progress_update()}} regularly. \if{html}{\out{
}}\preformatted{f <- function() \{ cli_progress_step("Downloading data", spinner = TRUE) for (i in 1:100) \{ Sys.sleep(2/100); cli_progress_update() \} cli_progress_step("Importing data") Sys.sleep(1) cli_progress_step("Cleaning data") Sys.sleep(2) cli_progress_step("Fitting model", spinner = TRUE) for (i in 1:100) \{ Sys.sleep(3/100); cli_progress_update() \} \} f() }\if{html}{\out{
}} \if{html}{\figure{progress-step-spin.svg}} } \subsection{Dynamic messages}{ You can make the step messages dynamic, using glue templates. Since \code{cli_progress_step()} show that message immediately, we need to initialize \code{msg} first. \if{html}{\out{
}}\preformatted{f <- function() \{ msg <- "" cli_progress_step("Downloading data\{msg\}", spinner = TRUE) for (i in 1:100) \{ Sys.sleep(2/100) msg <- glue::glue(", got file \{i\}/100") cli_progress_update() \} cli_progress_step("Importing data") Sys.sleep(1) cli_progress_step("Cleaning data") Sys.sleep(2) cli_progress_step("Fitting model", spinner = TRUE) for (i in 1:100) \{ Sys.sleep(3/100); cli_progress_update() \} \} f() }\if{html}{\out{
}} \if{html}{\figure{progress-step-dynamic.svg}} } \subsection{Termination messages}{ You can specify a different message for successful and/or unsuccessful termination: \if{html}{\out{
}}\preformatted{f <- function() \{ size <- 0L cli_progress_step( "Downloading data.", msg_done = "Downloaded \{prettyunits::pretty_bytes(size)\}.", spinner = TRUE ) for (i in 1:100) \{ Sys.sleep(3/100) size <- size + 8192 cli_progress_update() \} \} f() }\if{html}{\out{
}} \if{html}{\figure{progress-step-msg.svg}} } } \seealso{ This function supports \link[=inline-markup]{inline markup}. Other progress bar functions: \code{\link{cli_progress_along}()}, \code{\link{cli_progress_bar}()}, \code{\link{cli_progress_builtin_handlers}()}, \code{\link{cli_progress_message}()}, \code{\link{cli_progress_num}()}, \code{\link{cli_progress_output}()}, \code{\link{cli_progress_styles}()}, \code{\link{progress-variables}} Other functions supporting inline markup: \code{\link{cli_abort}()}, \code{\link{cli_alert}()}, \code{\link{cli_blockquote}()}, \code{\link{cli_bullets}()}, \code{\link{cli_bullets_raw}()}, \code{\link{cli_dl}()}, \code{\link{cli_h1}()}, \code{\link{cli_li}()}, \code{\link{cli_ol}()}, \code{\link{cli_process_start}()}, \code{\link{cli_progress_along}()}, \code{\link{cli_progress_bar}()}, \code{\link{cli_progress_message}()}, \code{\link{cli_progress_output}()}, \code{\link{cli_rule}}, \code{\link{cli_status}()}, \code{\link{cli_status_update}()}, \code{\link{cli_text}()}, \code{\link{cli_ul}()}, \code{\link{format_error}()}, \code{\link{format_inline}()} } \concept{functions supporting inline markup} \concept{progress bar functions} cli/man/ansi_regex.Rd0000644000176200001440000000112114557444176014223 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/ansiex.R \name{ansi_regex} \alias{ansi_regex} \title{Perl compatible regular expression that matches ANSI escape sequences} \usage{ ansi_regex() } \value{ String scalar, the regular expression. } \description{ Don't forget to use \code{perl = TRUE} when using this with \code{\link[=grepl]{grepl()}} and friends. } \seealso{ Other low level ANSI functions: \code{\link{ansi_has_any}()}, \code{\link{ansi_hide_cursor}()}, \code{\link{ansi_string}()}, \code{\link{ansi_strip}()} } \concept{low level ANSI functions} cli/man/hash_sha256.Rd0000644000176200001440000000306514752735214014114 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/hash.R \name{hash_sha256} \alias{hash_sha256} \alias{hash_raw_sha256} \alias{hash_obj_sha256} \alias{hash_file_sha256} \title{SHA-256 hash} \usage{ hash_sha256(x) hash_raw_sha256(x) hash_obj_sha256(x, serialize_version = 2) hash_file_sha256(paths) } \arguments{ \item{x}{Character vector. If not a character vector, then \code{\link[=as.character]{as.character()}} is used to try to coerce it into one. \code{NA} entries will have an \code{NA} hash.} \item{serialize_version}{Workspace format version to use, see \code{\link[base:serialize]{base::serialize()}}.} \item{paths}{Character vector of file names.} } \value{ \code{hash_sha256()} returns a character vector of hexadecimal SHA-256 hashes. \code{hash_raw_sha256()} returns a character scalar. \code{hash_obj_sha256()} returns a character scalar. \code{hash_file_sha256()} returns a character vector of SHA-256 hashes. } \description{ Calculate the SHA-256 hash of each element of a character vector. } \details{ \code{hash_raw_sha256()} calculates the SHA-256 hash of the bytes of a raw vector. \code{hash_obj_sha256()} calculates the SHA-256 hash of an R object. The object is serialized into a binary vector first. \code{hash_file_sha256()} calculates the SHA-256 hash of one or more files. } \examples{ hash_sha256(c("foo", NA, "bar", "")) } \seealso{ Other hash functions: \code{\link{hash_animal}()}, \code{\link{hash_emoji}()}, \code{\link{hash_md5}()}, \code{\link{hash_sha1}()}, \code{\link{hash_xxhash}()} } \concept{hash functions} cli/man/builtin_theme.Rd0000644000176200001440000001234014752364056014727 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/themes.R \name{builtin_theme} \alias{builtin_theme} \title{The built-in CLI theme} \usage{ builtin_theme(dark = getOption("cli.theme_dark", "auto")) } \arguments{ \item{dark}{Whether to use a dark theme. The \code{cli.theme_dark} option can be used to request a dark theme explicitly. If this is not set, or set to \code{"auto"}, then cli tries to detect a dark theme, this works in recent RStudio versions and in iTerm on macOS.} } \value{ A named list, a CLI theme. } \description{ This theme is always active, and it is at the bottom of the theme stack. See \link{themes}. } \section{Showcase}{ \if{html}{\out{
}}\preformatted{cli_h1("Heading 1") cli_h2("Heading 2") cli_h3("Heading 3") cli_par() cli_alert_danger("Danger alert") cli_alert_warning("Warning alert") cli_alert_info("Info alert") cli_alert_success("Success alert") cli_alert("Alert for starting a process or computation", class = "alert-start") cli_end() cli_text("Packages and versions: \{.pkg cli\} \{.version 1.0.0\}.") cli_text("Time intervals: \{.timestamp 3.4s\}") cli_text("\{.emph Emphasis\} and \{.strong strong emphasis\}") cli_text("This is a piece of code: \{.code sum(x) / length(x)\}") cli_text("Function names: \{.fn cli::simple_theme\}") cli_text("Files: \{.file /usr/bin/env\}") cli_text("URLs: \{.url https://r-project.org\}") cli_h2("Longer code chunk") cli_par(class = "code R") cli_verbatim( '# window functions are useful for grouped mutates', 'mtcars \%>\%', ' group_by(cyl) \%>\%', ' mutate(rank = min_rank(desc(mpg)))') }\if{html}{\out{
}}\if{html}{\out{
#> ── Heading 1 ─────────────────────────────────────────────────────────          
#>                                                                                 
#> ── Heading 2 ──                                                                 
#>                                                                                 
#> ── Heading 3                                                                    
#>  Danger alert                                                                  
#> ! Warning alert                                                                 
#>  Info alert                                                                    
#>  Success alert                                                                 
#> → Alert for starting a process or computation                                   
#>                                                                                 
#> Packages and versions: cli 1.0.0.                                               
#> Time intervals: [3.4s]                                                          
#> Emphasis and strong emphasis                                                    
#> This is a piece of code: `sum(x) / length(x)`                                   
#> Function names: `cli::simple_theme()`                                           
#> Files: /usr/bin/env                                                             
#> URLs: <https://r-project.org>                                                   
#>                                                                                 
#> ── Longer code chunk ──                                                         
#>                                                                                 
#> # window functions are useful for grouped mutates                               
#> mtcars %>%                                                                      
#>   group_by(cyl) %>%                                                             
#>   mutate(rank = min_rank(desc(mpg)))                                            
}} } \seealso{ \link{themes}, \code{\link[=simple_theme]{simple_theme()}}. } cli/man/cli_debug_doc.Rd0000644000176200001440000000254314557444176014652 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/debug.R \name{cli_debug_doc} \alias{cli_debug_doc} \title{Debug cli internals} \usage{ cli_debug_doc(app = default_app() \%||\% start_app()) } \arguments{ \item{app}{The cli app to debug. Defaults to the current app. if there is no app, then it creates one by calling \code{\link[=start_app]{start_app()}}.} } \value{ Data frame with columns: \code{tag}, \code{id}, \code{class} (space separated), theme (id of the theme the element added), \code{styles} (computed styles for the element). } \description{ Return the current state of a cli app. It includes the currently open tags, their ids, classes and their computed styles. } \details{ The returned data frame has a print method, and if you want to create a plain data frame from it, index it with an empty bracket: \code{cli_debug_doc()[]}. To see all currently active themes, use \code{app$themes}, e.g. for the default app: \code{default_app()$themes}. } \examples{ \dontrun{ cli_debug_doc() olid <- cli_ol() cli_li() cli_debug_doc() cli_debug_doc()[] cli_end(olid) cli_debug_doc() } } \seealso{ \code{\link[=cli_sitrep]{cli_sitrep()}}. To debug containers, you can set the \code{CLI-DEBUG_BAD_END} environment variable to \code{true}, and then cli will warn when it cannot find the specified container to close (or any contained at all). } cli/man/ansi_columns.Rd0000644000176200001440000000620014752735214014565 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/ansiex.R \name{ansi_columns} \alias{ansi_columns} \title{Format a character vector in multiple columns} \usage{ ansi_columns( text, width = console_width(), sep = " ", fill = c("rows", "cols"), max_cols = 4, align = c("left", "center", "right"), type = "width", ellipsis = symbol$ellipsis ) } \arguments{ \item{text}{Character vector to format. Each element will formatted as a cell of a table.} \item{width}{Width of the screen.} \item{sep}{Separator between the columns. It may have ANSI styles.} \item{fill}{Whether to fill the columns row-wise or column-wise.} \item{max_cols}{Maximum number of columns to use. Will not use more, even if there is space for it.} \item{align}{Alignment within the columns.} \item{type}{Passed to \code{\link[=ansi_nchar]{ansi_nchar()}} and \code{\link[=ansi_align]{ansi_align()}}. Most probably you want the default, \code{"width"}.} \item{ellipsis}{The string to append to truncated strings. Supply an empty string if you don't want a marker.} } \value{ ANSI string vector. } \description{ This function helps with multi-column output of ANSI styles strings. It works well together with \code{\link[=boxx]{boxx()}}, see the example below. } \details{ If a string does not fit into the specified \code{width}, it will be truncated using \code{\link[=ansi_strtrim]{ansi_strtrim()}}. \if{html}{\out{
}}\preformatted{fmt <- ansi_columns( paste(col_red("foo"), 1:10), width = 50, fill = "rows", max_cols=10, align = "center", sep = " " ) boxx(fmt, padding = c(0,1,0,1), header = col_cyan("Columns")) }\if{html}{\out{
}}\if{html}{\out{
#> ┌ Columns ───────────────────────────────────────────┐                          
#> │  foo 1     foo 2     foo 3     foo 4     foo 5     │                          
#> │  foo 6     foo 7     foo 8     foo 9     foo 10    │                          
#> └────────────────────────────────────────────────────┘                          
}} } \seealso{ Other ANSI string operations: \code{\link{ansi_align}()}, \code{\link{ansi_nchar}()}, \code{\link{ansi_strsplit}()}, \code{\link{ansi_strtrim}()}, \code{\link{ansi_strwrap}()}, \code{\link{ansi_substr}()}, \code{\link{ansi_substring}()}, \code{\link{ansi_toupper}()}, \code{\link{ansi_trimws}()} } \concept{ANSI string operations} cli/man/cli_format_method.Rd0000644000176200001440000000403014557444176015560 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/print.R \name{cli_format_method} \alias{cli_format_method} \title{Create a format method for an object using cli tools} \usage{ cli_format_method(expr, theme = getOption("cli.theme")) } \arguments{ \item{expr}{Expression that calls \verb{cli_*} methods, \code{\link[base:cat]{base::cat()}} or \code{\link[base:print]{base::print()}} to format an object's printout.} \item{theme}{Theme to use for the formatting.} } \value{ Character vector, one element for each line of the printout. } \description{ This method can be typically used in \code{format()} S3 methods. Then the \code{print()} method of the class can be easily defined in terms of such a \code{format()} method. See examples below. } \examples{ # Let's create format and print methods for a new S3 class that # represents the an installed R package: `r_package` # An `r_package` will contain the DESCRIPTION metadata of the package # and also its installation path. new_r_package <- function(pkg) { tryCatch( desc <- packageDescription(pkg), warning = function(e) stop("Cannot find R package `", pkg, "`") ) file <- dirname(attr(desc, "file")) if (basename(file) != pkg) file <- dirname(file) structure( list(desc = unclass(desc), lib = dirname(file)), class = "r_package" ) } format.r_package <- function(x, ...) { cli_format_method({ cli_h1("{.pkg {x$desc$Package}} {cli::symbol$line} {x$desc$Title}") cli_text("{x$desc$Description}") cli_ul(c( "Version: {x$desc$Version}", if (!is.null(x$desc$Maintainer)) "Maintainer: {x$desc$Maintainer}", "License: {x$desc$License}" )) if (!is.na(x$desc$URL)) cli_text("See more at {.url {x$desc$URL}}") }) } # Now the print method is easy: print.r_package <- function(x, ...) { cat(format(x, ...), sep = "\n") } # Try it out new_r_package("cli") # The formatting of the output depends on the current theme: opt <- options(cli.theme = simple_theme()) print(new_r_package("cli")) options(opt) # <- restore theme } cli/man/num_ansi_colors.Rd0000644000176200001440000001320414557444176015276 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/num-ansi-colors.R \name{num_ansi_colors} \alias{num_ansi_colors} \alias{detect_tty_colors} \title{Detect the number of ANSI colors to use} \usage{ num_ansi_colors(stream = "auto") detect_tty_colors() } \arguments{ \item{stream}{The stream that will be used for output, an R connection object. It can also be a string, one of \code{"auto"}, \code{"message"}, \code{"stdout"}, \code{"stderr"}. \code{"auto"} will select \code{stdout()} if the session is interactive and there are no sinks, otherwise it will select \code{stderr()}.} } \value{ Integer, the number of ANSI colors the current R session supports for \code{stream}. } \description{ Certain Unix and Windows terminals, and also certain R GUIs, e.g. RStudio, support styling terminal output using special control sequences (ANSI sequences). \code{num_ansi_colors()} detects if the current R session supports ANSI sequences, and if it does how many colors are supported. } \details{ The detection mechanism is quite involved and it is designed to work out of the box on most systems. If it does not work on your system, please report a bug. Setting options and environment variables to turn on ANSI support is error prone, because they are inherited in other environments, e.g. knitr, that might not have ANSI support. If you want to \emph{turn off} ANSI colors, set the \code{NO_COLOR} environment variable to a non-empty value. The exact detection mechanism is as follows: \enumerate{ \item If the \code{cli.num_colors} options is set, that is returned. \item If the \code{R_CLI_NUM_COLORS} environment variable is set to a non-empty value, then it is used. \item If the \code{crayon.enabled} option is set to \code{FALSE}, 1L is returned. (This is for compatibility with code that uses the crayon package.) \item If the \code{crayon.enabled} option is set to \code{TRUE} and the \code{crayon.colors} option is not set, then the value of the \code{cli.default_num_colors} option, or if it is unset, then 8L is returned. \item If the \code{crayon.enabled} option is set to \code{TRUE} and the \code{crayon.colors} option is also set, then the latter is returned. (This is for compatibility with code that uses the crayon package.) \item If the \code{NO_COLOR} environment variable is set, then 1L is returned. \item If we are in knitr, then 1L is returned, to turn off colors in \code{.Rmd} chunks. \item If \code{stream} is \code{"auto"} (the default) and there is an active sink (either for \code{"output"} or \code{"message"}), then we return 1L. (In theory we would only need to check the stream that will be be actually used, but there is no easy way to tell that.) \item If \code{stream} is not \code{"auto"}, but it is \code{stderr()} and there is an active sink for it, then 1L is returned. (If a sink is active for "output", then R changes the \code{stdout()} stream, so this check is not needed.) \item If the \code{cli.default_num_colors} option is set, then we use that. \item If R is running inside RGui on Windows, or R.app on macOS, then we return 1L. \item If R is running inside RStudio, with color support, then the appropriate number of colors is returned, usually 256L. \item If R is running on Windows, inside an Emacs version that is recent enough to support ANSI colors, then the value of the \code{cli.default_num_colors} option, or if unset 8L is returned. (On Windows, Emacs has \code{isatty(stdout()) == FALSE}, so we need to check for this here before dealing with terminals.) \item If \code{stream} is not the standard output or standard error in a terminal, then 1L is returned. \item Otherwise we use and cache the result of the terminal color detection (see below). } The terminal color detection algorithm: \enumerate{ \item If the \code{COLORTERM} environment variable is set to \code{truecolor} or \verb{24bit}, then we return 16 million colors. \item If the \code{COLORTERM} environment variable is set to anything else, then we return the value of the \code{cli.num_default_colors} option, 8L if unset. \item If R is running on Unix, inside an Emacs version that is recent enough to support ANSI colors, then the value of the \code{cli.default_num_colors} option is returned, or 8L if unset. \item If we are on Windows in an RStudio terminal, then apparently we only have eight colors, but the \code{cli.default_num_colors} option can be used to override this. \item If we are in a recent enough Windows 10 terminal, then there is either true color (from build 14931) or 256 color (from build 10586) support. You can also use the \code{cli.default_num_colors} option to override these. \item If we are on Windows, under ConEmu or cmder, or ANSICON is loaded, then the value of \code{cli.default_num_colors}, or 8L if unset, is returned. \item Otherwise if we are on Windows, return 1L. \item Otherwise we are on Unix and try to run \verb{tput colors} to determine the number of colors. If this succeeds, we return its return value. If the \code{TERM} environment variable is \code{xterm} and \code{tput} returned 8L, we return 256L, because xterm compatible terminals tend to support 256 colors (\url{https://github.com/r-lib/crayon/issues/17}) You can override this with the \code{cli.default_num_colors} option. \item If \code{TERM} is set to \code{dumb}, we return 1L. \item If \code{TERM} starts with \code{screen}, \code{xterm}, or \code{vt100}, we return 8L. \item If \code{TERM} contains \code{color}, \code{ansi}, \code{cygwin} or \code{linux}, we return 8L. \item Otherwise we return 1L. } } \examples{ num_ansi_colors() } \seealso{ Other ANSI styling: \code{\link{ansi-styles}}, \code{\link{combine_ansi_styles}()}, \code{\link{make_ansi_style}()} } \concept{ANSI styling} cli/man/cli_progress_builtin_handlers.Rd0000644000176200001440000000655414557444176020217 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/progress-server.R \name{cli_progress_builtin_handlers} \alias{cli_progress_builtin_handlers} \title{cli progress handlers} \usage{ cli_progress_builtin_handlers() } \value{ \code{cli_progress_builtin_handlers()} returns the names of the currently supported progress handlers. } \description{ The progress handler(s) to use can be selected with global options. } \details{ There are three options that specify which handlers will be selected, but most of the time you only need to use one of them. You can set these options to a character vector, the names of the built-in cli handlers you want to use: \itemize{ \item If \code{cli.progress_handlers_only} is set, then these handlers are used, without considering others and without checking if they are able to handle a progress bar. This option is mainly intended for testing purposes. \item The handlers named in \code{cli.progress_handlers} are checked if they are able to handle the progress bar, and from the ones that are, the first one is selected. This is usually the option that the end use would want to set. \item The handlers named in \code{cli.progress_handlers_force} are always appended to the ones selected via \code{cli.progress_handlers}. This option is useful to add an additional handler, e.g. a logger that writes to a file. } } \section{The built-in progress handlers}{ \subsection{\code{cli}}{ Use cli's internal status bar, the last line of the screen, to show the progress bar. This handler is always able to handle all progress bars. } \subsection{\code{logger}}{ Log progress updates to the screen, with one line for each update and with time stamps. This handler is always able to handle all progress bars. } \subsection{\code{progressr}}{ Use the progressr package to create progress bars. This handler is always able to handle all progress bars. (The progressr package needs to be installed.) } \subsection{\code{rstudio}}{ Use \href{https://posit.co/blog/rstudio-1-2-jobs/}{RStudio's job panel} to show the progress bars. This handler is available at the RStudio console, in recent versions of RStudio. } \subsection{\code{say}}{ Use the macOS \code{say} command to announce progress events in speech (type \verb{man say} on a terminal for more info). Set the \code{cli.progress_say_frequency} option to set the minimum delay between \code{say} invocations, the default is three seconds. This handler is available on macOS, if the \code{say} command is on the path. The external command and its arguments can be configured with options: \itemize{ \item \code{cli_progress_say_args}: command line arguments, e.g. you can use this to select a voice on macOS, \item \code{cli_progress_say_command}: external command to run, \item \code{cli_progress_say_frequency}: wait at least this many seconds between calling the external command. } } \subsection{\code{shiny}}{ Use \href{https://shiny.rstudio.com/articles/progress.html}{shiny's progress bars}. This handler is available if a shiny app is running. } } \seealso{ Other progress bar functions: \code{\link{cli_progress_along}()}, \code{\link{cli_progress_bar}()}, \code{\link{cli_progress_message}()}, \code{\link{cli_progress_num}()}, \code{\link{cli_progress_output}()}, \code{\link{cli_progress_step}()}, \code{\link{cli_progress_styles}()}, \code{\link{progress-variables}} } \concept{progress bar functions} cli/DESCRIPTION0000644000176200001440000000350014753300402012523 0ustar liggesusersPackage: cli Title: Helpers for Developing Command Line Interfaces Version: 3.6.4 Authors@R: c( person("Gábor", "Csárdi", , "gabor@posit.co", role = c("aut", "cre")), person("Hadley", "Wickham", role = "ctb"), person("Kirill", "Müller", role = "ctb"), person("Salim", "Brüggemann", , "salim-b@pm.me", role = "ctb", comment = c(ORCID = "0000-0002-5329-5987")), person("Posit Software, PBC", role = c("cph", "fnd")) ) Description: A suite of tools to build attractive command line interfaces ('CLIs'), from semantic elements: headings, lists, alerts, paragraphs, etc. Supports custom themes via a 'CSS'-like language. It also contains a number of lower level 'CLI' elements: rules, boxes, trees, and 'Unicode' symbols with 'ASCII' alternatives. It support ANSI colors and text styles as well. License: MIT + file LICENSE URL: https://cli.r-lib.org, https://github.com/r-lib/cli BugReports: https://github.com/r-lib/cli/issues Depends: R (>= 3.4) Imports: utils Suggests: callr, covr, crayon, digest, glue (>= 1.6.0), grDevices, htmltools, htmlwidgets, knitr, methods, processx, ps (>= 1.3.4.9000), rlang (>= 1.0.2.9003), rmarkdown, rprojroot, rstudioapi, testthat (>= 3.2.0), tibble, whoami, withr Config/Needs/website: r-lib/asciicast, bench, brio, cpp11, decor, desc, fansi, prettyunits, sessioninfo, tidyverse/tidytemplate, usethis, vctrs Config/testthat/edition: 3 Encoding: UTF-8 RoxygenNote: 7.3.2 NeedsCompilation: yes Packaged: 2025-02-11 21:14:07 UTC; gaborcsardi Author: Gábor Csárdi [aut, cre], Hadley Wickham [ctb], Kirill Müller [ctb], Salim Brüggemann [ctb] (), Posit Software, PBC [cph, fnd] Maintainer: Gábor Csárdi Repository: CRAN Date/Publication: 2025-02-13 05:20:02 UTC