cli/0000755000176200001440000000000014535536335011035 5ustar liggesuserscli/NAMESPACE0000644000176200001440000001314214535114677012256 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_md5) export(hash_obj_animal) export(hash_obj_emoji) export(hash_obj_md5) export(hash_obj_sha1) export(hash_obj_sha256) export(hash_raw_animal) export(hash_raw_emoji) export(hash_raw_md5) export(hash_raw_sha1) export(hash_raw_sha256) export(hash_sha1) export(hash_sha256) 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/LICENSE.note0000644000176200001440000000110114312603722012763 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/LICENSE0000644000176200001440000000005114535114677012037 0ustar liggesusersYEAR: 2023 COPYRIGHT HOLDER: cli authors cli/tools/0000755000176200001440000000000014301737210012157 5ustar liggesuserscli/tools/spinners.R0000644000176200001440000000173014301737210014144 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("⠀⡀⣀⣄⣤⣦⣶⣷⣿⣾⣶⣴⣤⣠⣀⢀", "")), list(name = "growVeriticalDotsRL", interval = 80, frames = strsplit("⠀⢀⣀⣠⣤⣴⣶⣾⣿⣷⣶⣦⣤⣄⣀⡀", "")), list(name = "growVeriticalDotsLL", interval = 80, frames = strsplit("⠀⡀⣀⣄⣤⣦⣶⣷⣿⣷⣶⣦⣤⣄⣀⡀", "")), list(name = "growVeriticalDotsRR", interval = 80, frames = strsplit("⠀⡀⣀⣠⣤⣴⣶⣾⣿⣾⣶⣴⣤⣠⣀⢀", "")) ) cli/tools/sol-light.itermcolors0000644000176200001440000002060214143453131016346 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/tango-light.itermcolors0000644000176200001440000002007114143453131016661 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/ansi-palettes.txt0000644000176200001440000000314714143453131015477 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/dark.itermcolors0000644000176200001440000001777114143453131015402 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/parse-iterm.R0000644000176200001440000000361014143453131014533 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/smoooooth.itermcolors0000644000176200001440000002014414143453131016473 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/ansi-iterm-palettes.txt0000644000176200001440000000170214143453131016610 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/get-rstudio-themes.R0000644000176200001440000001503114143453131016034 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, "")[[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/light.itermcolors0000644000176200001440000001763314143453131015565 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/unicode.R0000644000176200001440000000153414143453131013734 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/pastel.itermcolors0000644000176200001440000002026714143453131015743 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/tango-dark.itermcolors0000644000176200001440000002010514143453131016471 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/tools/snazzy.itermcolors0000644000176200001440000002043314143453131016004 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.itermcolors0000644000176200001440000002056614143453131016171 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/exec/0000755000176200001440000000000014521175065011753 5ustar liggesuserscli/exec/search.R0000755000176200001440000000402714521175065013351 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.R0000755000176200001440000000570414521175065013063 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/exec/outdated.R0000755000176200001440000000376114521175065013721 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/up.R0000755000176200001440000000277014521175065012533 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)) "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/README.md0000644000176200001440000001370614535431165012316 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/0000755000176200001440000000000014535436706011611 5ustar liggesuserscli/man/is_utf8_output.Rd0000644000176200001440000000102714143453131015063 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/cli_output_connection.Rd0000644000176200001440000000106114143453131016466 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/links.Rd0000644000176200001440000003567314535114677013236 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{
#> Some httpbin URLs: <https://httpbin.org/status/200>,                            
#> <https://httpbin.org/status/403>, and                                           
#> <https://httpbin.org/status/404>.                                               
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{
#> See more at <https://example.com/has%20some%20spaces>.                          
}} } } \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/format_inline.Rd0000644000176200001440000000336414500305721014714 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_raw}()}, \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_update}()}, \code{\link{cli_status}()}, \code{\link{cli_text}()}, \code{\link{cli_ul}()}, \code{\link{format_error}()} } \concept{functions supporting inline markup} cli/man/ansi_simplify.Rd0000644000176200001440000000101514200445676014736 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/cli_vec.Rd0000644000176200001440000000351614332664317013505 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/pluralization.Rd0000644000176200001440000002134014232501151014752 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/num_ansi_colors.Rd0000644000176200001440000001320414521175065015263 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/ansi_regex.Rd0000644000176200001440000000112114521175065014210 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/utf8_substr.Rd0000644000176200001440000000200714143453131014351 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/make_spinner.Rd0000644000176200001440000000656414300734360014551 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_along.Rd0000644000176200001440000000761614500305721015745 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_raw}()}, \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_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_status}()}, \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/console_width.Rd0000644000176200001440000000271014143453131014723 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/progress-utils.Rd0000644000176200001440000000211314500305721015057 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/progress-c.Rd0000644000176200001440000001556414262015555014167 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/code_highlight.Rd0000644000176200001440000000214414317007616015032 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_text.Rd0000644000176200001440000001372314500305721013701 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_raw}()}, \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_update}()}, \code{\link{cli_status}()}, \code{\link{cli_ul}()}, \code{\link{format_error}()}, \code{\link{format_inline}()} } \concept{functions supporting inline markup} cli/man/unicode-width-workaround.Rd0000644000176200001440000000262514143453131017023 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/cli_dl.Rd0000644000176200001440000000664714500305721013323 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_raw}()}, \code{\link{cli_bullets}()}, \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_status}()}, \code{\link{cli_text}()}, \code{\link{cli_ul}()}, \code{\link{format_error}()}, \code{\link{format_inline}()} } \concept{functions supporting inline markup} cli/man/has_keypress_support.Rd0000644000176200001440000000144114331172227016361 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/cli_progress_builtin_handlers.Rd0000644000176200001440000000655414500305721020173 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/man/cli_li.Rd0000644000176200001440000000541414500305721013317 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_raw}()}, \code{\link{cli_bullets}()}, \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_update}()}, \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} cli/man/cli_progress_bar.Rd0000644000176200001440000003177214500305721015411 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_raw}()}, \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_message}()}, \code{\link{cli_progress_output}()}, \code{\link{cli_progress_step}()}, \code{\link{cli_rule}}, \code{\link{cli_status_update}()}, \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{progress bar functions} cli/man/ansi_strip.Rd0000644000176200001440000000173214521175065014247 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_format_method.Rd0000644000176200001440000000403014143453131015536 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/cli_progress_styles.Rd0000644000176200001440000000562214500305721016163 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/get_spinner.Rd0000644000176200001440000000253714300722604014405 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/ansi_substr.Rd0000644000176200001440000000326114143453131014420 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/ansi_strwrap.Rd0000644000176200001440000000302114143453131014572 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_substring}()}, \code{\link{ansi_substr}()}, \code{\link{ansi_toupper}()}, \code{\link{ansi_trimws}()} } \concept{ANSI string operations} cli/man/simple_theme.Rd0000644000176200001440000001372314332664317014555 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/code_theme_list.Rd0000644000176200001440000000342714143453131015217 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.Rd0000644000176200001440000000370314332664317012646 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-config.Rd0000644000176200001440000003233514521175065014111 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/ansi_strsplit.Rd0000644000176200001440000000326014143453131014761 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_substring}()}, \code{\link{ansi_substr}()}, \code{\link{ansi_toupper}()}, \code{\link{ansi_trimws}()} } \concept{ANSI string operations} cli/man/inline-markup.Rd0000644000176200001440000003462414521175065014655 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()}}.#' * \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/ansi_html.Rd0000644000176200001440000000250114143453131014036 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/match_selector_node.Rd0000644000176200001440000000170714143453131016070 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/hash_animal.Rd0000644000176200001440000000473414535114677014354 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}()} } \concept{hash functions} cli/man/vt_output.Rd0000644000176200001440000000262314312603722014137 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/ansi_has_any.Rd0000644000176200001440000000171014521175065014524 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/cli_sitrep.Rd0000644000176200001440000000172614143453131014225 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/ansi_align.Rd0000644000176200001440000001064414332664317014205 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_substring}()}, \code{\link{ansi_substr}()}, \code{\link{ansi_toupper}()}, \code{\link{ansi_trimws}()} } \concept{ANSI string operations} cli/man/ansi_substring.Rd0000644000176200001440000000342414143453131015117 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/parse_selector.Rd0000644000176200001440000000154614143453131015102 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/cli_process_start.Rd0000644000176200001440000001115014500305721015600 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_clear}()}, \code{\link{cli_status_update}()}, \code{\link{cli_status}()} 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_bullets}()}, \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_update}()}, \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/spark_line.Rd0000644000176200001440000000166414332664317014232 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/match_selector.Rd0000644000176200001440000000107614143453131015062 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/ansi_palettes.Rd0000644000176200001440000000506014232501151014711 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/builtin_theme.Rd0000644000176200001440000001234014535114677014730 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/style_hyperlink.Rd0000644000176200001440000000257214312603722015316 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/roxygen/0000755000176200001440000000000014301737210013265 5ustar liggesuserscli/man/roxygen/meta.R0000644000176200001440000000147314301737210014343 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/list_spinners.Rd0000644000176200001440000000075614143453131014766 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/pluralization-helpers.Rd0000644000176200001440000000114414143453131016417 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 } \seealso{ Other pluralization: \code{\link{pluralization}}, \code{\link{pluralize}()} } \concept{pluralization} cli/man/rule.Rd0000644000176200001440000001773214332664317013055 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/cli_ol.Rd0000644000176200001440000001067114500305721013326 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_raw}()}, \code{\link{cli_bullets}()}, \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_update}()}, \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} cli/man/ansi_string.Rd0000644000176200001440000000135614521175065014416 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_progress_output.Rd0000644000176200001440000000453014500305721016175 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_raw}()}, \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_step}()}, \code{\link{cli_rule}}, \code{\link{cli_status_update}()}, \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{progress bar functions} cli/man/tree.Rd0000644000176200001440000004016114332664317013035 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/cli_bullets.Rd0000644000176200001440000000774014500305721014371 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_update}()}, \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} cli/man/test_that_cli.Rd0000644000176200001440000000620014312603722014707 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/ansi_grep.Rd0000644000176200001440000000315314301737210014032 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_html_style.Rd0000644000176200001440000000274714143453131015272 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/cli_ul.Rd0000644000176200001440000000701014500305721013325 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_raw}()}, \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_update}()}, \code{\link{cli_status}()}, \code{\link{cli_text}()}, \code{\link{format_error}()}, \code{\link{format_inline}()} } \concept{functions supporting inline markup} cli/man/ansi_hide_cursor.Rd0000644000176200001440000000246114521175065015414 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/spark_bar.Rd0000644000176200001440000000466714332664317014055 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/cli_list_themes.Rd0000644000176200001440000000145314535114677015252 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_blockquote.Rd0000644000176200001440000000606714500305721015070 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_raw}()}, \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_update}()}, \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} cli/man/containers.Rd0000644000176200001440000000631214332664317014243 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/cli_rule.Rd0000644000176200001440000000654314500305721013666 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_raw}()}, \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_status_update}()}, \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} cli/man/ansi-styles.Rd0000644000176200001440000001351414535431165014351 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/faq.Rd0000644000176200001440000000562014232501151012627 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/ansi_toupper.Rd0000644000176200001440000000412514143453131014574 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_substring}()}, \code{\link{ansi_substr}()}, \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_substring}()}, \code{\link{ansi_substr}()}, \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_substring}()}, \code{\link{ansi_substr}()}, \code{\link{ansi_trimws}()} } \concept{ANSI string operations} cli/man/progress-variables.Rd0000644000176200001440000004140514500305721015676 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/is_ansi_tty.Rd0000644000176200001440000000214414143453131014410 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/figures/0000755000176200001440000000000014500305721013235 5ustar liggesuserscli/man/figures/README/0000755000176200001440000000000014343071116014175 5ustar liggesuserscli/man/figures/README/lists-dark.svg0000644000176200001440000000332714521141212016771 0ustar liggesusers1.Item1Subitem1Subitem22.Item2cli/man/figures/README/h3.svg0000644000176200001440000000222114521141212015216 0ustar liggesusers──Heading3cli/man/figures/README/progress-dark.svg0000644000176200001440000012063214521141212017476 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/h2.svg0000644000176200001440000000244014521141212015220 0ustar liggesusers──Heading2──cli/man/figures/README/plurals-dark.svg0000644000176200001440000000266114521141212017315 0ustar liggesusersFound3filesand1directory.cli/man/figures/README/progress.svg0000644000176200001440000012063514521141212016562 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/glue.svg0000644000176200001440000000257114521141212015650 0ustar liggesusersDownloaded123.14MBin1.3scli/man/figures/README/h2-dark.svg0000644000176200001440000000243514521141212016143 0ustar liggesusers──Heading2──cli/man/figures/README/h1.svg0000644000176200001440000000300514521141212015215 0ustar liggesusers──Heading1───────────────────────────────────────────────────────────────────cli/man/figures/README/alert-dark.svg0000644000176200001440000000227714521141212016745 0ustar liggesusersAgenericalertcli/man/figures/README/glue-dark.svg0000644000176200001440000000256614521141212016573 0ustar liggesusersDownloaded123.14MBin1.3scli/man/figures/README/alert.svg0000644000176200001440000000230214521141212016013 0ustar liggesusersAgenericalertcli/man/figures/README/h1-dark.svg0000644000176200001440000000300214521141212016131 0ustar liggesusers──Heading1───────────────────────────────────────────────────────────────────cli/man/figures/README/alert-info-dark.svg0000644000176200001440000000262014521141212017666 0ustar liggesusersReopeneddatabase<example.com:port>.cli/man/figures/README/alert-success.svg0000644000176200001440000000237514521141212017473 0ustar liggesusersDownloaded3packages.cli/man/figures/README/alert-info.svg0000644000176200001440000000262314521141212016752 0ustar liggesusersReopeneddatabase<example.com:port>.cli/man/figures/README/alert-danger-dark.svg0000644000176200001440000000260214521141212020173 0ustar liggesusersFailedtoconnecttodatabase.cli/man/figures/README/alert-danger.svg0000644000176200001440000000260514521141212017257 0ustar liggesusersFailedtoconnecttodatabase.cli/man/figures/README/alert-success-dark.svg0000644000176200001440000000237214521141212020407 0ustar liggesusersDownloaded3packages.cli/man/figures/README/themes-dark.svg0000644000176200001440000000327714521141212017124 0ustar liggesusersThisisveryimportantBacktothepreviousthemecli/man/figures/README/alert-warning.svg0000644000176200001440000000305714521141212017466 0ustar liggesusers!CannotreachGitHub,usinglocaldatabasecache.cli/man/figures/README/alert-warning-dark.svg0000644000176200001440000000305414521141212020402 0ustar liggesusers!CannotreachGitHub,usinglocaldatabasecache.cli/man/figures/README/themes.svg0000644000176200001440000000330214521141212016172 0ustar liggesusersThisisveryimportantBacktothepreviousthemecli/man/figures/README/h3-dark.svg0000644000176200001440000000221614521141212016141 0ustar liggesusers──Heading3cli/man/figures/README/lists.svg0000644000176200001440000000333214521141212016046 0ustar liggesusers1.Item1Subitem1Subitem22.Item2cli/man/figures/README/plurals.svg0000644000176200001440000000266414521141212016401 0ustar liggesusersFound3filesand1directory.cli/man/figures/progress-format.svg0000644000176200001440000001474214535432162017130 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/progress-along-1.svg0000644000176200001440000003363014535432162017073 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/progress-message.svg0000644000176200001440000001216414535432163017261 0ustar liggesusersTaskthreeisunderway:step1Taskoneisrunning...Tasktwoisrunning...Taskthreeisunderway:step2Taskthreeisunderway:step3Taskthreeisunderway:step4Taskthreeisunderway:step5cli/man/figures/progress-tasks.svg0000644000176200001440000000571414535432162016764 0ustar liggesusers3/3ETA:0s|Tasks1/3ETA:2s|Tasks2/3ETA:1s|Taskscli/man/figures/progress-current.svg0000644000176200001440000005666714535432162017336 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/get-spinner.svg0000644000176200001440000003632614535432163016234 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-after.svg0000644000176200001440000002712114535432162016734 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/make-spinner-custom.svg0000644000176200001440000004047414535432163017701 0ustar liggesusersDownloading.Downloading..Downloading...Downloading..Downloading.Downloadingcli/man/figures/progress-along-3.svg0000644000176200001440000002271614535432162017100 0ustar liggesusersDownloadingdatafile100Downloadingdatafile0Downloadingdatafile7Downloadingdatafile11Downloadingdatafile16Downloadingdatafile21Downloadingdatafile25Downloadingdatafile30Downloadingdatafile35Downloadingdatafile39Downloadingdatafile44Downloadingdatafile48Downloadingdatafile53Downloadingdatafile57Downloadingdatafile62Downloadingdatafile66Downloadingdatafile71Downloadingdatafile76Downloadingdatafile81Downloadingdatafile85Downloadingdatafile90Downloadingdatafile95Downloadingdatafile99cli/man/figures/progress-step.svg0000644000176200001440000001467614535432163016622 0ustar liggesusersDownloadingdata[2s]Importingdata[1s]Cleaningdata[2s]Fittingmodel[3s]DownloadingdataImportingdataCleaningdataFittingmodelcli/man/figures/make-spinner-default.svg0000644000176200001440000007517214535432163020016 0ustar liggesuserscli/man/figures/progress-along-2.svg0000644000176200001440000003322714535432162017076 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-output2.svg0000644000176200001440000005242614535432163017264 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/figures/progress-1.svg0000644000176200001440000005340514535432162015777 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/make-spinner-template.svg0000644000176200001440000007617014535432163020204 0ustar liggesusersComputingComputingComputingComputingComputingComputingComputingComputingComputingComputingcli/man/figures/progress-output.svg0000644000176200001440000005255014535432162017177 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-natotal.svg0000644000176200001440000003357614535432162017310 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-step-dynamic.svg0000644000176200001440000004443514535432163020240 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-clear.svg0000644000176200001440000006752314535432162016733 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/demo-spinners.svg0000644000176200001440000004107414535432163016560 0ustar liggesusers🕛🕛clock🕐clock🕑clock🕒clock🕓clock🕔clock🕕clock🕖clock🕗clock🕘clock🕙clock🕚clockcli/man/figures/progress-step-msg.svg0000644000176200001440000001432114535432163017371 0ustar liggesusersDownloadingdata.Downloadingdata.Downloadingdata.Downloadingdata.Downloadingdata.Downloadingdata.Downloadingdata.Downloadingdata.Downloaded819.20kB.[3.5s]Downloadingdata.Downloadingdata.cli/man/figures/progress-step-spin.svg0000644000176200001440000003606614535432163017566 0ustar liggesusersDownloadingdataDownloadingdataDownloadingdataDownloadingdata[2.5s]Importingdata[1s]Cleaningdata[2s]FittingmodelFittingmodelFittingmodelFittingmodelFittingmodelFittingmodelFittingmodelFittingmodelFittingmodel[3.4s]DownloadingdataDownloadingdataDownloadingdataDownloadingdataDownloadingdataDownloadingdataDownloadingdataImportingdataCleaningdataFittingmodelFittingmodelcli/man/cli_code.Rd0000644000176200001440000000534014332664317013637 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/ansi_columns.Rd0000644000176200001440000000620014332664317014564 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_substring}()}, \code{\link{ansi_substr}()}, \code{\link{ansi_toupper}()}, \code{\link{ansi_trimws}()} } \concept{ANSI string operations} cli/man/hash_sha1.Rd0000644000176200001440000000275214521175065013736 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}()} } \concept{hash functions} cli/man/cli_format.Rd0000644000176200001440000000735414332664317014224 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/cli_status.Rd0000644000176200001440000000741514500305721014241 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_raw}()}, \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_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/pluralize.Rd0000644000176200001440000000412114301737210014066 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/cli_status_clear.Rd0000644000176200001440000000334714143453131015411 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_update}()}, \code{\link{cli_status}()} } \concept{status bar} cli/man/cli-package.Rd0000644000176200001440000000217214535114677014242 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{csardi.gabor@gmail.com} 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_progress_message.Rd0000644000176200001440000000600714500305721016262 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_raw}()}, \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_output}()}, \code{\link{cli_progress_step}()}, \code{\link{cli_rule}}, \code{\link{cli_status_update}()}, \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{progress bar functions} cli/man/ansi_strtrim.Rd0000644000176200001440000000231414317007616014606 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_substring}()}, \code{\link{ansi_substr}()}, \code{\link{ansi_toupper}()}, \code{\link{ansi_trimws}()} } \concept{ANSI string operations} cli/man/boxx.Rd0000644000176200001440000004222514332664317013061 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/themes.Rd0000644000176200001440000001571614535114677013377 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/hash_md5.Rd0000644000176200001440000000274614521175065013572 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}()} } \concept{hash functions} cli/man/hash_sha256.Rd0000644000176200001440000000303014521175065014100 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}()} } \concept{hash functions} cli/man/ansi_trimws.Rd0000644000176200001440000000212414143453131014420 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_substring}()}, \code{\link{ansi_substr}()}, \code{\link{ansi_toupper}()} } \concept{ANSI string operations} cli/man/utf8_nchar.Rd0000644000176200001440000000267114143453131014131 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_collapse.Rd0000644000176200001440000000476114521175065014715 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 = " and ", 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.} \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/cli_abort.Rd0000644000176200001440000001125014500305721014015 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_raw}()}, \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_update}()}, \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} cli/man/diff_chr.Rd0000644000176200001440000000350614143453131013632 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/utf8_graphemes.Rd0000644000176200001440000000144514143453131015007 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_nzchar.Rd0000644000176200001440000000106114301737210014356 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_debug_doc.Rd0000644000176200001440000000254314143453131014630 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/combine_ansi_styles.Rd0000644000176200001440000000252114143453131016113 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/diff_str.Rd0000644000176200001440000000223414143453131013663 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/cli_verbatim.Rd0000644000176200001440000000331514332664317014536 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_end.Rd0000644000176200001440000000745514332664317013504 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/cli_par.Rd0000644000176200001440000000440714332664317013512 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/format_error.Rd0000644000176200001440000000574514500305721014574 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_raw}()}, \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_update}()}, \code{\link{cli_status}()}, \code{\link{cli_text}()}, \code{\link{cli_ul}()}, \code{\link{format_inline}()} } \concept{functions supporting inline markup} cli/man/ruler.Rd0000644000176200001440000000047414200477712013225 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/cli_progress_step.Rd0000644000176200001440000001244114521175065015621 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_raw}()}, \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_rule}}, \code{\link{cli_status_update}()}, \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{progress bar functions} cli/man/cli_status_update.Rd0000644000176200001440000000413614500305721015600 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_clear}()}, \code{\link{cli_status}()} 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_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_text}()}, \code{\link{cli_ul}()}, \code{\link{format_error}()}, \code{\link{format_inline}()} } \concept{functions supporting inline markup} \concept{status bar} cli/man/cli_h1.Rd0000644000176200001440000000553414500305721013226 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_raw}()}, \code{\link{cli_bullets}()}, \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_update}()}, \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} cli/man/cli_bullets_raw.Rd0000644000176200001440000000322014500305721015227 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_update}()}, \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} cli/man/start_app.Rd0000644000176200001440000000233714143453131014064 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/demo_spinners.Rd0000644000176200001440000000120714300722604014726 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/make_ansi_style.Rd0000644000176200001440000000414114200445676015242 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/cat_line.Rd0000644000176200001440000000253114143453131013641 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/hash_emoji.Rd0000644000176200001440000000517014521175065014202 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}()} } \concept{hash functions} cli/man/chunks/0000755000176200001440000000000014535436706013104 5ustar liggesuserscli/man/chunks/FAQ.Rmd0000644000176200001440000000514414143453131014145 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.Rmd0000644000176200001440000001323614143453131016434 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/cli_progress_demo.Rd0000644000176200001440000000371114143453131015563 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/symbol.Rd0000644000176200001440000000124314143453131013367 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/cli_fmt.Rd0000644000176200001440000000132514312603722013501 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/pretty_print_code.Rd0000644000176200001440000000076714317007616015637 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_div.Rd0000644000176200001440000000463414332664317013514 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/keypress.Rd0000644000176200001440000000235614331172227013740 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_alert.Rd0000644000176200001440000001360314500305721014021 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_raw}()}, \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_update}()}, \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} cli/man/is_dynamic_tty.Rd0000644000176200001440000000357714143453131015115 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_nchar.Rd0000644000176200001440000000235514143453131014174 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_substring}()}, \code{\link{ansi_substr}()}, \code{\link{ansi_toupper}()}, \code{\link{ansi_trimws}()} } \concept{ANSI string operations} cli/DESCRIPTION0000644000176200001440000000351614535536335012550 0ustar liggesusersPackage: cli Title: Helpers for Developing Command Line Interfaces Version: 3.6.2 Authors@R: c( person("Gábor", "Csárdi", , "csardi.gabor@gmail.com", 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, mockery, processx, ps (>= 1.3.4.9000), rlang (>= 1.0.2.9003), rmarkdown, rprojroot, rstudioapi, testthat, 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.2.3 NeedsCompilation: yes Packaged: 2023-12-10 22:38:10 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: 2023-12-11 07:40:13 UTC cli/tests/0000755000176200001440000000000014143453131012162 5ustar liggesuserscli/tests/testthat/0000755000176200001440000000000014535536335014037 5ustar liggesuserscli/tests/testthat/test-progress-variables.R0000644000176200001440000002054414143453131020741 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)) mockery::stub(cli__pb_elapsed, ".Call", 1) expect_snapshot(cli__pb_elapsed()) mockery::stub(cli__pb_elapsed, ".Call", 21) expect_snapshot(cli__pb_elapsed()) mockery::stub(cli__pb_elapsed, ".Call", 58) expect_snapshot(cli__pb_elapsed()) mockery::stub(cli__pb_elapsed, ".Call", 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)) mockery::stub(cli__pb_elapsed_clock, ".Call", 1) expect_snapshot(cli__pb_elapsed_clock()) mockery::stub(cli__pb_elapsed_clock, ".Call", 21) expect_snapshot(cli__pb_elapsed_clock()) mockery::stub(cli__pb_elapsed_clock, ".Call", 58) expect_snapshot(cli__pb_elapsed_clock()) mockery::stub(cli__pb_elapsed_clock, ".Call", 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)) mockery::stub(cli__pb_elapsed_raw, ".Call", 1) expect_snapshot(cli__pb_elapsed_raw()) mockery::stub(cli__pb_elapsed_raw, ".Call", 21) expect_snapshot(cli__pb_elapsed_raw()) mockery::stub(cli__pb_elapsed_raw, ".Call", 58) expect_snapshot(cli__pb_elapsed_raw()) mockery::stub(cli__pb_elapsed_raw, ".Call", 60 * 65) expect_snapshot(cli__pb_elapsed_raw()) }) test_that("pb_eta", { expect_equal(cli__pb_eta(NULL), "") mockery::stub(cli__pb_eta, "cli__pb_eta_raw", NA_real_) expect_snapshot(cli__pb_eta(list())) mockery::stub(cli__pb_eta, "cli__pb_eta_raw", 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_) mockery::stub(cli__pb_eta_raw, ".Call", 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(), "") mockery::stub(cli__pb_eta_str, "cli__pb_eta", "?") expect_snapshot(cli__pb_eta_str(list())) mockery::stub(cli__pb_eta_str, "cli__pb_eta", " 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), "") mockery::stub(cli__pb_rate, "cli__pb_rate_raw", NaN) expect_snapshot(cli__pb_rate(list())) mockery::stub(cli__pb_rate, "cli__pb_rate_raw", Inf) expect_snapshot(cli__pb_rate(list())) mockery::stub(cli__pb_rate, "cli__pb_rate_raw", 1/10) expect_snapshot(cli__pb_rate(list())) mockery::stub(cli__pb_rate, "cli__pb_rate_raw", 12.4) expect_snapshot(cli__pb_rate(list())) }) test_that("pb_rate_raw", { expect_equal(cli__pb_rate_raw(NULL), "") mockery::stub(cli__pb_rate_raw, "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), "") mockery::stub(cli__pb_rate_bytes, "cli__pb_rate_raw", NaN) expect_snapshot(cli__pb_rate_bytes(list())) mockery::stub(cli__pb_rate_bytes, "cli__pb_rate_raw", Inf) expect_snapshot(cli__pb_rate_bytes(list())) mockery::stub(cli__pb_rate_bytes, "cli__pb_rate_raw", 0) expect_snapshot(cli__pb_rate_bytes(list())) mockery::stub(cli__pb_rate_bytes, "cli__pb_rate_raw", 1024) expect_snapshot(cli__pb_rate_bytes(list())) mockery::stub(cli__pb_rate_bytes, "cli__pb_rate_raw", 1024 * 23) expect_snapshot(cli__pb_rate_bytes(list())) mockery::stub(cli__pb_rate_bytes, "cli__pb_rate_raw", 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") mockery::stub(cli__pb_timestamp, "Sys.time", 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-progress-handler-logger.R0000644000176200001440000000036514143453131021662 0ustar liggesusers test_that("loggerr_out", { bar <- new.env(parent = emptyenv()) bar$id <- "id" bar$current <- 13 bar$total <- 113 mockery::stub(logger_out, "Sys.time", .POSIXct(1623325865, tz = "CET")) expect_snapshot(logger_out(bar, "updated")) }) cli/tests/testthat/test-containers.R0000644000176200001440000000461114200445676017302 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-assertions.R0000644000176200001440000000542214143453131017317 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-app.R0000644000176200001440000000035514317007616015713 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-console-width.R0000644000176200001440000000046514313063767017721 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-deep-lists.R0000644000176200001440000000201514143453131017171 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-prettycode.R0000644000176200001440000001402514301763660017315 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") mockery::stub( code_theme_default, "rstudio_detect", 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) mockery::stub(code_theme_default, "code_theme_default_rstudio", "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", { mockery::stub( code_theme_default_rstudio, "get_rstudio_theme", list(editor = "Solarized Dark") ) expect_equal(code_theme_default_rstudio()$reserved, "#859900") mockery::stub( code_theme_default_rstudio, "get_rstudio_theme", 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-utf8.R0000644000176200001440000000466214313063767016033 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-subprocess.R0000644000176200001440000000774114277512450017333 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-cat.R0000644000176200001440000000024414143453131015671 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-progress-along.R0000644000176200001440000000730614313063767020105 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. mockery::stub(cli_progress_along, "getRversion", 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/test-inline-2.R0000644000176200001440000001227214500302326016537 0ustar liggesusers start_app() on.exit(stop_app(), add = TRUE) test_that_cli( config = 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(config = 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(config = 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(config = "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(config = c("ansi", "plain"), "no inherit color, issue #474", { expect_snapshot({ cli::cli_text("pre {.val x {'foo'} y} post") }) }) test_that_cli(config = 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(config = "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-ansi-utils.R0000644000176200001440000000266214317007616017226 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-progress-message.R0000644000176200001440000000502614230006710020405 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-vt.R0000644000176200001440000000677214312603722015570 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(config = "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-ansiex-2.R0000644000176200001440000003140614301737210016553 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-sitrep.R0000644000176200001440000000077314143453131016437 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/test-code.R0000644000176200001440000000020014143453131016024 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/setup.R0000644000176200001440000000026414143453131015307 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-bullets.R0000644000176200001440000000155414200722245016600 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-diff.R0000644000176200001440000000435514313063767016054 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(config = 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/test-meta.R0000644000176200001440000000306214301737210016050 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-timer.R0000644000176200001440000000043614143453131016245 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-glue.R0000644000176200001440000000203114315310046016050 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-spark.R0000644000176200001440000000044714143453131016247 0ustar liggesusers test_that_cli(configs = c("plain", "unicode"), "spark_bar", { expect_snapshot({ spark_bar(seq(0, 1, length = 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 = 10)) }) }) cli/tests/testthat/test-cliapp-output.R0000644000176200001440000001032314143453131017727 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-spinners.R0000644000176200001440000000046714143453131016772 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-ansiex.R0000644000176200001440000004324214535114677016434 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-non-breaking-space.R0000644000176200001440000000032714143453131020567 0ustar liggesusers test_that("does not break", { 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-lists.R0000644000176200001440000001247314313063767016302 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-progress-handler-say.R0000644000176200001440000000137314143453131021177 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) mockery::stub(say_update, "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-format-conditions.R0000644000176200001440000000766414313063774020607 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(config = "ansi", "color in RStudio", { mockery::stub( get_rstudio_fg_color0, "rstudio_detect", list(type = "rstudio_console", num_colors = 256) ) mockery::stub( get_rstudio_fg_color0, "get_rstudio_theme", list(foreground = "rgb(0, 0, 0)") ) expect_snapshot({ col <- get_rstudio_fg_color0() cat(col("this is the new color")) }) mockery::stub( get_rstudio_fg_color0, "get_rstudio_theme", list() ) expect_null(get_rstudio_fg_color0()) mockery::stub( get_rstudio_fg_color0, "rstudio_detect", list(type = "rstudio_console", num_colors = 1) ) expect_null(get_rstudio_fg_color0()) }) test_that_cli(config = "ansi", "update_rstudio_color", { mockery::stub( update_rstudio_color, "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-alerts.R0000644000176200001440000000137414143453131016421 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-hash.R0000644000176200001440000000743514332665014016063 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 }) }) cli/tests/testthat/test-box-styles.R0000644000176200001440000000025214143453131017232 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-package.R0000644000176200001440000000151314301737210016514 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/test-ansi-make.R0000644000176200001440000000415514317007616017002 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/progresstest/0000755000176200001440000000000014535436722016602 5ustar liggesuserscli/tests/testthat/progresstest/NAMESPACE0000644000176200001440000000031414143453131020003 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/DESCRIPTION0000644000176200001440000000050214143453131020271 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/progresstest/src/0000755000176200001440000000000014406600132017352 5ustar liggesuserscli/tests/testthat/progresstest/src/cleancall.c0000644000176200001440000001026314143453131021441 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/src/cleancall.h0000644000176200001440000000274314143453131021452 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/test.c0000644000176200001440000000454114143453131020504 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/R/0000755000176200001440000000000014143453131016767 5ustar liggesuserscli/tests/testthat/progresstest/R/test.R0000644000176200001440000000122614143453131020072 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/test-ansi.R0000644000176200001440000000653014317007616016066 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/test-substitution.R0000644000176200001440000000026014143453131017674 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-ansi-combine.R0000644000176200001440000000175014143453131017471 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-tree.R0000644000176200001440000000610314143453131016061 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-rlang-errors.R0000644000176200001440000001046214500305721017540 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")) mockery::stub(cli_abort, "rstudio_detect", 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(config = "ansi", "color in RStudio", { mockery::stub( get_rstudio_fg_color0, "rstudio_detect", list(type = "rstudio_console", num_colors = 256) ) mockery::stub( get_rstudio_fg_color0, "get_rstudio_theme", list(foreground = "rgb(0, 0, 0)") ) expect_snapshot({ col <- get_rstudio_fg_color0() cat(col("this is the new color")) }) mockery::stub( get_rstudio_fg_color0, "get_rstudio_theme", list() ) expect_null(get_rstudio_fg_color0()) mockery::stub( get_rstudio_fg_color0, "rstudio_detect", list(type = "rstudio_console", num_colors = 1) ) expect_null(get_rstudio_fg_color0()) }) test_that_cli(config = "ansi", "update_rstudio_color", { mockery::stub( update_rstudio_color, "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-rules.R0000644000176200001440000000753214200445676016274 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-progress-utils.R0000644000176200001440000000205114143453131020122 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()) mockery::stub(should_run_progress_examples, "is_rcmd_check", 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/test-ansi-palette.R0000644000176200001440000000172614317007616017524 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-collapsing.R0000644000176200001440000001232114521175065017263 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(config = 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") }) cli/tests/testthat/test-suppress.R0000644000176200001440000000076314143453131017014 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-progress-types.R0000644000176200001440000001021014143453131020122 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 ) 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", { 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 ) 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-pluralization.R0000644000176200001440000000520314143453131020017 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/}")) }) }) cli/tests/testthat/test-headers.R0000644000176200001440000000106514317007616016545 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/progress-2.c0000644000176200001440000000046514143453131016176 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-custom-handler.R0000644000176200001440000000064514143453131020054 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/helper.R0000644000176200001440000001246214331172227015434 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-text.R0000644000176200001440000000113714212141573016111 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/_snaps/0000755000176200001440000000000014535436722015321 5ustar liggesuserscli/tests/testthat/_snaps/format-conditions.md0000644000176200001440000002722414535354346021312 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/box-styles.md0000644000176200001440000000276214535354341017757 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/boxes.md0000644000176200001440000002623214535354342016765 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/ansiex-2.md0000644000176200001440000000042214535354340017262 0ustar liggesusers# NA Code ansi_html(s) Output [1] "foo" [2] NA [3] "bar" [4] "foobar" cli/tests/testthat/_snaps/ansi-utils.md0000644000176200001440000000520614535354337017737 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/diff.md0000644000176200001440000000765314535354345016566 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/progress-variables.md0000644000176200001440000001253314535354365021463 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/ansi-html.md0000644000176200001440000007576214535354337017561 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/text.md0000644000176200001440000000163514535354370016632 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/spark.md0000644000176200001440000000106014535354366016763 0ustar liggesusers# spark_bar [plain] Code spark_bar(seq(0, 1, length = 8)) Output __,,**## Code spark_bar(c(0, NA, 0.5, NA, 1)) Output _ , # # spark_bar [unicode] Code spark_bar(seq(0, 1, length = 8)) Output ▁▂▃▄▅▆▇█ Code spark_bar(c(0, NA, 0.5, NA, 1)) Output ▁ ▄ █ # spark_line [plain] Code spark_line(seq(0, 1, length = 10)) Output _,,-^ # spark_line [unicode] Code spark_line(seq(0, 1, length = 10)) Output ⣀⡠⠔⠊⠉ cli/tests/testthat/_snaps/inline.md0000644000176200001440000000457014535354350017123 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/rlang-1.1.0/0000755000176200001440000000000014500305721017041 5ustar liggesuserscli/tests/testthat/_snaps/rlang-1.1.0/rlang-errors.md0000644000176200001440000000306314500305721022002 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/lists.md0000644000176200001440000002657314535354357017021 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/progress-client.md0000644000176200001440000000320314535354363020761 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/new-r/0000755000176200001440000000000014314545341016342 5ustar liggesuserscli/tests/testthat/_snaps/new-r/inline-2.md0000644000176200001440000000040114535354347020305 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/utf8/0000755000176200001440000000000014535536335016210 5ustar liggesuserscli/tests/testthat/_snaps/utf8/utf8-output.txt0000644000176200001440000000644414506533474021204 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/glue.md0000644000176200001440000000174414535354346016606 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/progress-ticking.md0000644000176200001440000000036514535354364021142 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/console-width.md0000644000176200001440000000036614535354345020427 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/ansi-make.md0000644000176200001440000000176614535354337017523 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.md0000644000176200001440000000026114535354345016727 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/keypress.md0000644000176200001440000000435014535354353017511 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/ansi.md0000644000176200001440000000074614535354337016605 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/collapsing.md0000644000176200001440000002371514535354344020005 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" cli/tests/testthat/_snaps/inline-2.md0000644000176200001440000002634414535354347017273 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/meta.md0000644000176200001440000001263114535354357016577 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/ansi-palette.md0000644000176200001440000001306414535354337020236 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/progress-message.md0000644000176200001440000000164314535354364021136 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/rules.md0000644000176200001440000000012414535354366016775 0ustar liggesusers# print.cli_rule Code rule("foo") Output -- foo ------------- cli/tests/testthat/_snaps/code.md0000644000176200001440000000057114535354344016557 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/utf8.md0000644000176200001440000000014114535354371016524 0ustar liggesusers# errors ! Invalid output from UTF-8 R i Found 1 UTF-8 begin marker and 2 end markers. cli/tests/testthat/_snaps/ansi-hyperlink.md0000644000176200001440000000234614535354337020606 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/progress-types.md0000644000176200001440000000516014535355646020660 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.md0000644000176200001440000000663014535354341017133 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/themes.md0000644000176200001440000001111114535354370017121 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/vt.md0000644000176200001440000002126214535354371016276 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/_snaps/old-r/0000755000176200001440000000000014313121025016313 5ustar liggesuserscli/tests/testthat/_snaps/old-r/inline-2.md0000644000176200001440000000037714313121071020262 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/prettycode.md0000644000176200001440000001452114535354360020025 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/new/0000755000176200001440000000000014535536335016113 5ustar liggesuserscli/tests/testthat/_snaps/new/headers.md0000644000176200001440000000366414535354347020062 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/deep-lists.md0000644000176200001440000000276614535354345017727 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/links.md0000644000176200001440000006741614535354355017002 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()` # {.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;; # {.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;; # {.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;; # {.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;; cli/tests/testthat/_snaps/hash.md0000644000176200001440000000734614535354346016601 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" cli/tests/testthat/_snaps/rlang-errors.md0000644000176200001440000002426214535354366020271 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/containers.md0000644000176200001440000000510414535354345020010 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/alerts.md0000644000176200001440000000427214535354336017142 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/utils.md0000644000176200001440000000630514535354371017006 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/pluralization.md0000644000176200001440000000764214535354357020554 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 cli/tests/testthat/_snaps/progress-handler-logger.md0000644000176200001440000000016714535354363022403 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/progress-c.md0000644000176200001440000000747414535354362017742 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/progress-bar.md0000644000176200001440000000502514535354361020251 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/app.md0000644000176200001440000000044214535354341016417 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/cat-helpers.md0000644000176200001440000000443214535354343020053 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/bullets.md0000644000176200001440000002363314535354343017322 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/verbatim.md0000644000176200001440000000063614535354371017460 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/progress-along.md0000644000176200001440000000420714535354360020605 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/non-breaking-space.md0000644000176200001440000000042314535354357021310 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/type.md0000644000176200001440000000666014535354370016632 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/tree.md0000644000176200001440000001301214535354370016575 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/test-status-bar.R0000644000176200001440000002135214172272425017221 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/progress-1.c0000644000176200001440000000414514143453131016174 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-ansi-hyperlink.R0000644000176200001440000002263714500305721020067 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_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", { 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 mockery::stub(ansi_has_hyperlink_support, "num_ansi_colors", 256L) expect_false(ansi_has_hyperlink_support()) # are we in rstudio with support? mockery::stub(ansi_has_hyperlink_support, "num_ansi_colors", 256L) mockery::stub(ansi_has_hyperlink_support, "rstudio_detect", list(type = "rstudio_console", hyperlink = TRUE)) expect_true(ansi_has_hyperlink_support()) }) test_that("ansi_has_hyperlink_support 2", { local_clean_cli_context() mockery::stub(ansi_has_hyperlink_support, "num_ansi_colors", 256L) mockery::stub(ansi_has_hyperlink_support, "isatty", FALSE) expect_false(ansi_has_hyperlink_support()) }) test_that("ansi_has_hyperlink_support 3", { local_clean_cli_context() mockery::stub(ansi_has_hyperlink_support, "num_ansi_colors", 256L) mockery::stub(ansi_has_hyperlink_support, "isatty", TRUE) mockery::stub(ansi_has_hyperlink_support, "is_windows", 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() mockery::stub(ansi_has_hyperlink_support, "num_ansi_colors", 256L) mockery::stub(ansi_has_hyperlink_support, "isatty", 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() mockery::stub(ansi_has_hyperlink_support, "num_ansi_colors", 256L) mockery::stub(ansi_has_hyperlink_support, "isatty", 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() mockery::stub(ansi_has_hyperlink_support, "num_ansi_colors", 256L) mockery::stub(ansi_has_hyperlink_support, "isatty", 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"]]) }) cli/tests/testthat/test-progress-bar.R0000644000176200001440000000231014143453131017524 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-cat-helpers.R0000644000176200001440000000226214172272425017342 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-progress-c.R0000644000176200001440000001025214143453131017206 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-css.R0000644000176200001440000000676214535114677015743 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-progress-ticking.R0000644000176200001440000000064614143453131020422 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-utils.R0000644000176200001440000001254314317007616016275 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", { mockery::stub( is_utf8_output, "l10n_info", list(MBCS = TRUE, `UTF-8` = TRUE, `Latin-1` = FALSE) ) withr::with_options( list(cli.unicode = NULL), expect_true(is_utf8_output()) ) mockery::stub( is_utf8_output, "l10n_info", 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", { mockery::stub(is_latex_output, "loadedNamespaces", "foobar") expect_false(is_latex_output()) mockery::stub(is_latex_output, "loadedNamespaces", "knitr") mockery::stub( is_latex_output, "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", { mockery::stub( get_rstudio_theme, "rstudioapi::getThemeInfo", function(...) warning("just a word") ) 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", { 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", { 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-boxes.R0000644000176200001440000000357614143453131016255 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-themes.R0000644000176200001440000000672114301737210016414 0ustar liggesusers start_app() on.exit(stop_app(), add = TRUE) test_that_cli("add/remove/list themes", { withr::local_rng_version("3.3.0") set.seed(24) id <- default_app()$add_theme(list(".green" = list(color = "green"))) on.exit(default_app()$remove_theme(id), add = TRUE) 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-defer.R0000644000176200001440000000017214313063767016222 0ustar liggesusers test_that("errors", { fun <- function() { defer(1 + "") } expect_snapshot( error = TRUE, fun() ) }) cli/tests/testthat/test-inline.R0000644000176200001440000000335714307652626016424 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(config = 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-keypress.R0000644000176200001440000000255714331172227017003 0ustar liggesusers test_that("control characaters", { 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", { 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", { 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", { 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-handlers.R0000644000176200001440000000325414143453131020570 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() ) mockery::stub(cli_progress_select_handlers, "builtin_handlers", 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() ) mockery::stub(cli_progress_select_handlers, "builtin_handlers", 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-verbatim.R0000644000176200001440000000053214143453131016733 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-num-ansi-colors.R0000644000176200001440000001142514200721320020143 0ustar liggesuserstest_that("win10_build works for different osVersion", { mockery::stub( win10_build, "utils::sessionInfo", list(running = NULL) ) expect_identical(win10_build(), 0L) mockery::stub( win10_build, "utils::sessionInfo", list(running = "Debian GNU/Linux 11 (bullseye)") ) expect_identical(win10_build(), 0L) mockery::stub( win10_build, "utils::sessionInfo", list(running = "Windows 10 x64 (build 16299)") ) 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 ) mockery::stub(num_ansi_colors, "os_type", "windows") mockery::stub(num_ansi_colors, "commandArgs", "--ess") mockery::stub(num_ansi_colors, "is_emacs_with_color", 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_) mockery::stub(detect_tty_colors, "os_type", "unix") mockery::stub(detect_tty_colors, "is_emacs_with_color", 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_) mockery::stub(detect_tty_colors, "os_type", "windows") mockery::stub(detect_tty_colors, "win10_build", 10586) mockery::stub( detect_tty_colors, "rstudio_detect", list(type = "rstudio_terminal") ) mockery::stub(detect_tty_colors, "system2", 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) mockery::stub(detect_tty_colors, "os_type", "windows") mockery::stub(detect_tty_colors, "win10_build", 10586) mockery::stub( detect_tty_colors, "rstudio_detect", list(type = "not_rstudio") ) mockery::stub(detect_tty_colors, "system2", TRUE) expect_equal(detect_tty_colors(), 256L) mockery::stub(detect_tty_colors, "win10_build", 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) mockery::stub(detect_tty_colors, "os_type", "windows") mockery::stub(detect_tty_colors, "win10_build", 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" ) mockery::stub(detect_tty_colors, "os_type", "unix") mockery::stub(detect_tty_colors, "is_emacs_with_color", FALSE) mockery::stub(detect_tty_colors, "system", "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_ ) mockery::stub(detect_dark_theme, "is_iterm", FALSE) mockery::stub(detect_dark_theme, "is_emacs", TRUE) expect_false(detect_dark_theme("auto")) withr::local_envvar(ESS_BACKGROUND_MODE = "dark") expect_true(detect_dark_theme("auto")) }) cli/tests/testthat/test-ansi-html.R0000644000176200001440000000354214143453131017022 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-links.R0000644000176200001440000001532614317007616016257 0ustar liggesusers # -- {.email} ------------------------------------------------------------- test_that_cli(config = c("plain", "fancy"), links = c("all", "none"), "{.email}", { expect_snapshot({ cli_text("{.email bugs.bunny@acme.com}") }) }) test_that_cli(config = 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(config = 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))) mockery::stub(abs_path1, "is_windows", TRUE) expect_equal( abs_path1("c:/foo/bar"), "file://c:/foo/bar" ) }) # -- {.fun} --------------------------------------------------------------- test_that_cli(config = "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(config = "plain", links = "all", "turning off help", { withr::local_options(cli.hyperlink_help = FALSE) expect_snapshot({ cli_text("{.fun pkg::func}") }) }) # -- {.help} -------------------------------------------------------------- test_that_cli(config = "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}}") }) }) # -- {.href} -------------------------------------------------------------- test_that_cli(config = "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(config = "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(config = "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(config = "plain", links = c("all", "none"), "{.run} vectors", { expect_snapshot({ codes <- paste0("pkg::fun", 1:3, "()") cli_text("{.run {codes}}") }) }) # -- {.topic} ------------------------------------------------------------- test_that_cli(config = "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}}") }) }) # -- {.url} --------------------------------------------------------------- test_that_cli(config = c("plain", "fancy"), links = c("all", "none"), "{.url}", { expect_snapshot({ cli_text("{.url https://cli.r-lib.org}") }) }) test_that_cli(config = 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(config = "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(config = "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}}") }) }) cli/tests/testthat/test-type.R0000644000176200001440000000410514312603722016104 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-progress-client.R0000644000176200001440000001164314230013752020245 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())) }) cli/tests/testthat/progresstestcpp/0000755000176200001440000000000014143453131017271 5ustar liggesuserscli/tests/testthat/progresstestcpp/NAMESPACE0000644000176200001440000000023414143453131020507 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/DESCRIPTION0000644000176200001440000000053514143453131021002 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/progresstestcpp/src/0000755000176200001440000000000014143453131020060 5ustar liggesuserscli/tests/testthat/progresstestcpp/src/testcpp.cpp0000644000176200001440000000150614143453131022250 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.cpp0000644000176200001440000000234714143453131021516 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/R/0000755000176200001440000000000014143453131017472 5ustar liggesuserscli/tests/testthat/progresstestcpp/R/cpp11.R0000644000176200001440000000040714143453131020542 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.R0000644000176200001440000000036014143453131021276 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.R0000644000176200001440000000006214143453131014143 0ustar liggesuserslibrary(testthat) library(cli) test_check("cli") cli/src/0000755000176200001440000000000014535436722011623 5ustar liggesuserscli/src/ansi.c0000644000176200001440000010701714326457260012725 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.c0000644000176200001440000003002114535365323013625 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; PROTECT(env = allocSExp(ENVSXP)); SET_FRAME(env, R_NilValue); SET_ENCLOS(env, R_EmptyEnv); SET_HASHTAB(env, R_NilValue); SET_ATTRIB(env, R_NilValue); 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_findVarInFrame3(rho, symbol, TRUE); 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/cleancall.c0000644000176200001440000001027314326457260013706 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/src/charwidth.h0000644000176200001440000054465714535431167013774 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/tty.c0000644000176200001440000000226714326457260012614 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/vtparse.c0000644000176200001440000001245414312603722013446 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/md5.c0000644000176200001440000000514514332664027012455 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/keypress-win.c0000644000176200001440000000765114331172227014427 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/thread.c0000644000176200001440000000741414440715223013233 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/graphbreak.h0000644000176200001440000037543314535431167014117 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/winfiles.c0000644000176200001440000000352314200445676013607 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/vtparse_table.c0000644000176200001440000060124014312603722014612 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/vtparse_table.h0000644000176200001440000000234614312603722014621 0ustar liggesuserstypedef enum { VTPARSE_STATE_CSI_ENTRY = 1, VTPARSE_STATE_CSI_IGNORE = 2, VTPARSE_STATE_CSI_INTERMEDIATE = 3, VTPARSE_STATE_CSI_PARAM = 4, VTPARSE_STATE_DCS_ENTRY = 5, VTPARSE_STATE_DCS_IGNORE = 6, VTPARSE_STATE_DCS_INTERMEDIATE = 7, VTPARSE_STATE_DCS_PARAM = 8, VTPARSE_STATE_DCS_PASSTHROUGH = 9, VTPARSE_STATE_ESCAPE = 10, VTPARSE_STATE_ESCAPE_INTERMEDIATE = 11, VTPARSE_STATE_GROUND = 12, VTPARSE_STATE_OSC_STRING = 13, VTPARSE_STATE_SOS_PM_APC_STRING = 14, } vtparse_state_t; typedef enum { VTPARSE_ACTION_CLEAR = 1, VTPARSE_ACTION_COLLECT = 2, VTPARSE_ACTION_CSI_DISPATCH = 3, VTPARSE_ACTION_ESC_DISPATCH = 4, VTPARSE_ACTION_EXECUTE = 5, VTPARSE_ACTION_HOOK = 6, VTPARSE_ACTION_IGNORE = 7, VTPARSE_ACTION_OSC_END = 8, VTPARSE_ACTION_OSC_PUT = 9, VTPARSE_ACTION_OSC_START = 10, VTPARSE_ACTION_PARAM = 11, VTPARSE_ACTION_PRINT = 12, VTPARSE_ACTION_PUT = 13, VTPARSE_ACTION_UNHOOK = 14, VTPARSE_ACTION_ERROR = 15, } vtparse_action_t; typedef unsigned char state_change_t; extern state_change_t STATE_TABLE[14][256]; extern vtparse_action_t ENTRY_ACTIONS[14]; extern vtparse_action_t EXIT_ACTIONS[14]; extern char *ACTION_NAMES[16]; extern char *STATE_NAMES[15]; cli/src/errors.c0000644000176200001440000000415614535431652013306 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/init.c0000644000176200001440000001007114410527360012720 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_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/cli.h0000644000176200001440000001015514410527360012534 0ustar liggesusers #ifndef CLI_H #define CLI_H #include #include #include #include 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_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/utils.c0000644000176200001440000000167514521175065013133 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/vtparse.h0000644000176200001440000000216514312603722013451 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/keypress.h0000644000176200001440000000363414331172227013636 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/vt.c0000644000176200001440000005044714312603722012417 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/progress-altrep.c0000644000176200001440000001433214410527360015112 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/sha1.c0000644000176200001440000001677714500302326012625 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/glue.c0000644000176200001440000002071014301737210012706 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/winfiles.h0000644000176200001440000000014014200445676013604 0ustar liggesusers #ifndef R_WINFILES_H #define R_WINFILES_H int open_file(const char *path, int oflag); #endif cli/src/Makevars0000644000176200001440000000005714350632204013305 0ustar liggesusersPKG_CFLAGS = $(C_VISIBILITY) -I../inst/include cli/src/keypress-unix.c0000644000176200001440000002121714331172227014607 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/inst.c0000644000176200001440000000030014350632204012721 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/utf8.c0000644000176200001440000002600214535431167012653 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/md5.h0000644000176200001440000003632114143453131012452 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/sha256.c0000644000176200001440000002151414200445676012777 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/cleancall.h0000644000176200001440000000264614326457260013720 0ustar liggesusers#ifndef CLEANCALL_H #define CLEANCALL_H #include #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/keypress.c0000644000176200001440000000333214331172227013624 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/win-utf8.c0000644000176200001440000000141314326457260013445 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/errors.h0000644000176200001440000001301114143453131013270 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/diff.c0000644000176200001440000002404414143453131012667 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 { SEXP* aptr; 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(old); data.bptr = STRING_PTR(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/R/0000755000176200001440000000000014535431165011231 5ustar liggesuserscli/R/progress-ticking.R0000644000176200001440000000053714143453131014643 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/cli.R0000644000176200001440000006414614500305721012124 0ustar liggesusers #' Compose multiple cli functions #' #' `cli()` will record all `cli_*` calls in `expr`, and emit them together #' in a single message. This is useful if you want to built a larger #' piece of output from multiple `cli_*` calls. #' #' Use this function to build a more complex piece of CLI that would not #' make sense to show in pieces. #' #' ```{asciicast cli-cli} #' cli({ #' cli_h1("Title") #' cli_h2("Subtitle") #' cli_ul(c("this", "that", "end")) #' }) #' ``` #' #' @param expr Expression that contains `cli_*` calls. Their output is #' collected and sent as a single message. #' @return Nothing. #' #' @export cli <- function(expr) { cond <- cli__message_create("meta", cli__rec(expr)) # cli() might be nested record <- getOption("cli.record") if (is.null(record)) { cli__message_emit(cond) } else { cli_recorded[[record]] <- c(cli_recorded[[record]], list(cond)) } invisible() } cli__rec <- function(expr) { id <- new_uuid() cli_recorded[[id]] <- list() on.exit(rm(list = id, envir = cli_recorded), add = TRUE) old <- options(cli.record = id) on.exit(options(old), add = TRUE) expr cli_recorded[[id]] } cli__fmt <- function(record, collapse = FALSE, strip_newline = FALSE, app = NULL) { app <- app %||% default_app() %||% start_app(.auto_close = FALSE) old <- app$output oldsig <- app$signal on.exit(app$output <- old, add = TRUE) on.exit(app$signal <- oldsig, add = TRUE) out <- rawConnection(raw(1000), open = "wb") on.exit(close(out), add = TRUE) app$output <- out app$signal <- FALSE for (msg in record) { do.call(app[[msg$type]], msg$args) } txt <- rawToChar(rawConnectionValue(out)) Encoding(txt) <- "UTF-8" if (!collapse) { txt <- unlist(strsplit(txt, "\n", fixed = TRUE)) } else if (strip_newline) { txt <- substr(txt, 1, nchar(txt) - 1L) } txt } #' Capture the output of cli functions instead of printing it #' #' @param expr Expression to evaluate, containing `cli_*()` calls, #' typically. #' @param collapse Whether to collapse the output into a single character #' scalar, or return a character vector with one element for each line. #' @param strip_newline Whether to strip the trailing newline. #' #' @export #' @examples #' cli_fmt({ #' cli_alert_info("Loading data file") #' cli_alert_success("Loaded data file") #' }) cli_fmt <- function(expr, collapse = FALSE, strip_newline = FALSE) { rec <- cli__rec(expr) cli__fmt(rec, collapse, strip_newline) } #' Format and returns a line of text #' #' You can use this function to format a line of cli text, without emitting #' it to the screen. It uses [cli_text()] internally. #' #' `format_inline()` performs no width-wrapping. #' #' @param ... Passed to [cli_text()]. #' @param .envir Environment to evaluate the expressions in. #' @param collapse Whether to collapse the result if it has multiple #' lines, e.g. because of `\f` characters. #' @param keep_whitespace Whether to keep all whitepace (spaces, newlines #' and form feeds) as is in the input. #' @return Character scalar, the formatted string. #' #' @seealso This function supports [inline markup][inline-markup]. #' @family functions supporting inline markup #' @export #' @examples #' format_inline("A message for {.emph later}, thanks {.fn format_inline}.") format_inline <- function(..., .envir = parent.frame(), collapse = TRUE, keep_whitespace = TRUE) { opts <- options(cli.width = Inf) on.exit(options(opts), add = TRUE) fun <- if (keep_whitespace) cli_inline else cli_text cli_fmt( fun(..., .envir = .envir), collapse = collapse, strip_newline = TRUE ) } #' CLI text #' #' Write some text to the screen. This function is most appropriate for #' longer paragraphs. See [cli_alert()] for shorter status messages. #' #' @details #' #' ## Text wrapping #' #' Text is wrapped to the console width, see [console_width()]. #' #' ```{asciicast cli-text} #' cli_text(cli:::lorem_ipsum()) #' ``` #' #' ## New lines #' #' A `cli_text()` call always appends a newline character to the end. #' #' ```{asciicast cli-text-newline} #' cli_text("First line.") #' cli_text("Second line.") #' ``` #' #' ## Styling #' #' You can use [inline markup][inline-markup], as usual. #' #' ```{asciicast cli-text-markup} #' cli_text("The {.fn cli_text} function in the {.pkg cli} package.") #' ``` #' #' ## Interpolation #' #' String interpolation via glue works as usual. Interpolated vectors #' are collapsed. #' #' ```{asciicast cli-text-glue} #' pos <- c(5, 14, 25, 26) #' cli_text("We have {length(pos)} missing measurements: {pos}.") #' ``` #' #' ## Styling and interpolation #' #' Use double braces to combine styling and string interpolation. #' #' ```{asciicast cli-text-glue-style} #' fun <- "cli-text" #' pkg <- "cli" #' cli_text("The {.fn {fun}} function in the {.pkg {pkg}} package.") #' ``` #' #' ## Multiple arguments #' #' Arguments are concatenated. #' #' ```{asciicast cli-text-concat} #' cli_text(c("This ", "will ", "all "), "be ", "one ", "sentence.") #' ``` #' #' ## Containers #' #' You can use `cli_text()` within cli [containers]. #' #' ```{asciicast cli-text-containers} #' 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) #' ``` #' #' @param ... The text to show, in character vectors. They will be #' concatenated into a single string. Newlines are _not_ preserved. #' @param .envir Environment to evaluate the glue expressions in. #' #' @seealso This function supports [inline markup][inline-markup]. #' @family functions supporting inline markup #' @export cli_text <- function(..., .envir = parent.frame()) { cli__message("text", list(text = glue_cmd(..., .envir = .envir, .call = sys.call()))) } cli_inline <- function(..., .envir = parent.frame()) { cli__message( "inline_text", list( text = glue_cmd(..., .envir = .envir, .call = sys.call(), .trim = FALSE) ) ) } #' CLI verbatim text #' #' It is not wrapped, but printed as is. Long lines will overflow. #' No glue substitution is performed on verbatim text. #' #' @details #' #' ## Line breaks #' #' ```{asciicast cli-verbatim} #' cli_verbatim("This has\nthree\nlines,") #' ``` #' #' ## Special characters #' #' No glue substitution happens here. #' #' ```{asciicast cli-verbatim-2} #' cli_verbatim("No string {interpolation} or {.emph styling} here") #' ``` #' #' @param ... The text to show, in character vectors. Each element is #' printed on a new line. #' @param .envir Environment to evaluate the glue expressions in. #' #' @seealso [cli_code()] for printing R or other source code. #' @export cli_verbatim <- function(..., .envir = parent.frame()) { cli__message("verbatim", c(list(...), list(.envir = .envir))) } #' CLI headings #' #' cli has three levels of headings. #' #' @details #' #' This is how the headings look with the default builtin theme. #' #' ```{asciicast, cli-h1} #' cli_h1("Header {.emph 1}") #' cli_h2("Header {.emph 2}") #' cli_h3("Header {.emph 3}") #' ``` #' #' @param text Text of the heading. It can contain inline markup. #' @param id Id of the heading element, string. It can be used in themes. #' @param class Class of the heading element, string. It can be used in #' themes. #' @param .envir Environment to evaluate the glue expressions in. #' #' @seealso These functions supports [inline markup][inline-markup]. #' @family functions supporting inline markup #' @export cli_h1 <- function(text, id = NULL, class = NULL, .envir = parent.frame()) { cli__message( "h1", list( text = glue_cmd(text, .envir = .envir, .call = sys.call()), id = id, class = class ) ) } #' @rdname cli_h1 #' @export cli_h2 <- function(text, id = NULL, class = NULL, .envir = parent.frame()) { cli__message( "h2", list( text = glue_cmd(text, .envir = .envir, .call = sys.call()), id = id, class = class ) ) } #' @rdname cli_h1 #' @export cli_h3 <- function(text, id = NULL, class = NULL, .envir = parent.frame()) { cli__message( "h3", list( text = glue_cmd(text, .envir = .envir, .call = sys.call()), id = id, class = class ) ) } #' Generic CLI container #' #' See [containers]. A `cli_div` container is special, because it may #' add new themes, that are valid within the container. #' #' @details #' #' ## Custom themes #' #' ```{asciicast cli-div} #' d <- cli_div(theme = list(h1 = list(color = "cyan", #' "font-weight" = "bold"))) #' cli_h1("Custom title") #' cli_end(d) #' ``` #' #' ## Auto-closing #' #' By default a `cli_div()` is closed automatically when the calling #' frame exits. #' #' ```{asciicast cli-div-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") #' ``` #' #' @param id Element id, a string. If `NULL`, then a new id is generated #' and returned. #' @param class Class name, sting. Can be used in themes. #' @param theme A custom theme for the container. See [themes]. #' @param .auto_close Whether to close the container, when the calling #' function finishes (or `.envir` is removed, if specified). #' @param .envir Environment to evaluate the glue expressions in. It is #' also used to auto-close the container if `.auto_close` is `TRUE`. #' @return The id of the new container element, invisibly. #' #' @export cli_div <- function(id = NULL, class = NULL, theme = NULL, .auto_close = TRUE, .envir = parent.frame()) { cli__message("div", list(id = id, class = class, theme = theme), .auto_close = .auto_close, .envir = .envir) } #' CLI paragraph #' #' The builtin theme leaves an empty line between paragraphs. #' See also [containers]. #' #' ```{asciicast cli-par} #' clifun <- function() { #' cli_par() #' cli_text(cli:::lorem_ipsum()) #' } #' clifun() #' clifun() #' ``` #' #' @param id Element id, a string. If `NULL`, then a new id is generated #' and returned. #' @param class Class name, sting. Can be used in themes. #' @inheritParams cli_div #' @return The id of the new container element, invisibly. #' #' @export cli_par <- function(id = NULL, class = NULL, .auto_close = TRUE, .envir = parent.frame()) { cli__message("par", list(id = id, class = class), .auto_close = .auto_close, .envir = .envir) } #' Close a CLI container #' #' Containers aut0-close by default, but sometimes you need to explicitly #' close them. Closing a container also closes all of its nested #' containers. #' #' @details #' #' ## Explicit closing #' #' ```{asciicast cli-end} #' cnt <- cli_par() #' cli_text("First paragraph.") #' cli_end(cnt) #' cnt <- cli_par() #' cli_text("Second paragraph.") #' cli_end(cnt) #' ``` #' #' ## Closing a stack of containers #' #' ```{asciicast cli-end-many} #' 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") #' ``` #' #' ## Omitting `id` #' #' If `id` is omitted, the container that was opened last will be closed. #' #' ```{asciicast cli-end-noid} #' cli_par() #' cli_text("First paragraph") #' cli_end() #' cli_par() #' cli_text("Second paragraph") #' cli_end() #' ``` #' #' ## Debugging containers #' #' You can use the internal `cli:::cli_debug_doc()` function to see the #' currently open containers. #' #' ```{asciicast cli-end-debug} #' fun <- function() { #' cli_div(id = "mydiv") #' cli_par(class = "myclass") #' cli:::cli_debug_doc() #' } #' fun() #' ``` #' #' @param id Id of the container to close. If missing, the current #' container is closed, if any. #' #' @export cli_end <- function(id = NULL) { cli__message("end", list(id = id %||% NA_character_)) } #' Unordered CLI list #' #' An unordered list is a container, see [containers]. #' #' @details #' #' ## Adding all items at once #' #' ```{asciicast cli-ul} #' fun <- function() { #' cli_ul(c("one", "two", "three")) #' } #' fun() #' ``` #' #' ## Adding items one by one #' #' ```{asciicast cli-ul-2} #' fun <- function() { #' cli_ul() #' cli_li("{.emph one}") #' cli_li("{.emph two}") #' cli_li("{.emph three}") #' cli_end() #' } #' fun() #' ``` #' #' @param items If not `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 `.close` argument). #' @param id Id of the list container. Can be used for closing it with #' [cli_end()] or in themes. If `NULL`, then an id is generated and #' returned invisibly. #' @param class Class of the list container. Can be used in themes. #' @param .close Whether to close the list container if the `items` were #' specified. If `FALSE` then new items can be added to the list. #' @inheritParams cli_div #' @return The id of the new container element, invisibly. #' #' @seealso This function supports [inline markup][inline-markup]. #' @family functions supporting inline markup #' @export cli_ul <- function(items = NULL, id = NULL, class = NULL, .close = TRUE, .auto_close = TRUE, .envir = parent.frame()) { cli__message( "ul", list( items = lapply(items, glue_cmd, .envir = .envir, .call = sys.call()), id = id, class = class, .close = .close ), .auto_close = .auto_close, .envir = .envir ) } #' Ordered CLI list #' #' An ordered list is a container, see [containers]. #' #' @details #' #' ## Adding all items at once #' #' ```{asciicast cli-ol} #' fun <- function() { #' cli_ol(c("one", "two", "three")) #' } #' fun() #' ``` #' #' ## Adding items one by one #' #' ```{asciicast cli-ol-2} #' ## Adding items one by one #' fun <- function() { #' cli_ol() #' cli_li("{.emph one}") #' cli_li("{.emph two}") #' cli_li("{.emph three}") #' cli_end() #' } #' fun() #' ``` #' #' ## Nested lists #' #' ```{asciicast cli-ol-3} #' 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() #' ``` #' #' @inheritParams cli_ul #' @return The id of the new container element, invisibly. #' #' @seealso This function supports [inline markup][inline-markup]. #' @family functions supporting inline markup #' @export cli_ol <- function(items = NULL, id = NULL, class = NULL, .close = TRUE, .auto_close = TRUE, .envir = parent.frame()) { cli__message( "ol", list( items = lapply(items, glue_cmd, .envir = .envir, .call = sys.call()), id = id, class = class, .close = .close ), .auto_close = .auto_close, .envir = .envir ) } #' Definition list #' #' A definition list is a container, see [containers]. #' #' @details #' #' ## All items at once #' #' ```{asciicast cli-dl} #' fun <- function() { #' cli_dl(c(foo = "one", bar = "two", baz = "three")) #' } #' fun() #' ``` #' #' ## Items one by one #' #' ```{asciicast cli-dl-2} #' fun <- function() { #' cli_dl() #' cli_li(c(foo = "{.emph one}")) #' cli_li(c(bar = "two")) #' cli_li(c(baz = "three")) #' } #' fun() #' ``` #' #' @param items Named character vector, or `NULL`. If not `NULL`, they #' are used as list items. #' @param labels Item labels. Defaults the names in `items`. #' @inheritParams cli_ul #' @return The id of the new container element, invisibly. #' #' @seealso This function supports [inline markup][inline-markup]. #' @family functions supporting inline markup #' @export cli_dl <- function(items = NULL, labels = names(items), id = NULL, class = NULL, .close = TRUE, .auto_close = TRUE, .envir = parent.frame()) { if (!is.null(items) && !is_named(items)) { throw(cli_error( "{.arg items} must be a named character vector", "i" = if (!is_named(items)) "{.arg items} is not named" )) } cli__message( "dl", list( items = lapply(items, glue_cmd, .envir = .envir, .call = sys.call()), labels = if (!is.null(labels)) { lapply(labels, glue_cmd, .envir = .envir, .call = sys.call()) }, id = id, class = class, .close = .close), .auto_close = .auto_close, .envir = .envir) } #' CLI list item(s) #' #' A list item is a container, see [containers]. #' #' @details #' #' ## Nested lists #' #' ```{asciicast cli-li} #' fun <- function() { #' ul <- cli_ul() #' cli_li("one:") #' cli_ol(letters[1:3]) #' cli_li("two:") #' cli_li("three") #' cli_end(ul) #' } #' fun() #' ``` #' #' @param items Character vector of items, or `NULL`. #' @param labels For definition lists the item labels. #' @param id Id of the new container. Can be used for closing it with #' [cli_end()] or in themes. If `NULL`, then an id is generated and #' returned invisibly. #' @param class Class of the item container. Can be used in themes. #' @inheritParams cli_div #' @return The id of the new container element, invisibly. #' #' @seealso This function supports [inline markup][inline-markup]. #' @family functions supporting inline markup #' @export cli_li <- function(items = NULL, labels = names(items), id = NULL, class = NULL, .auto_close = TRUE, .envir = parent.frame()) { cli__message( "li", list( items = lapply(items, glue_cmd, .envir = .envir, .call = sys.call()), labels = if (!is.null(labels)) { lapply(labels, glue_cmd, .envir = .envir, .call = sys.call()) }, id = id, class = class), .auto_close = .auto_close, .envir = .envir) } #' CLI alerts #' #' Alerts are typically short status messages. #' #' @details #' #' ## Success #' #' ```{asciicast alert-success} #' nbld <- 11 #' tbld <- prettyunits::pretty_sec(5.6) #' cli_alert_success("Built {.emph {nbld}} status report{?s} in {tbld}.") #' ``` #' #' ## Info #' #' ```{asciicast alert-info} #' cfl <- "~/.cache/files/latest.cache" #' cli_alert_info("Updating cache file {.path {cfl}}.") #' ``` #' #' ## Warning #' #' ```{asciicast alert-warning} #' cfl <- "~/.cache/files/latest.cache" #' cli_alert_warning("Failed to update cache file {.path {cfl}}.") #' ``` #' #' ## Danger #' #' ```{asciicast alert-danger} #' cfl <- "~/.config/report.yaml" #' cli_alert_danger("Cannot validate config file at {.path {cfl}}.") #' ``` #' #' ## Text wrapping #' #' Alerts are printed without wrapping, unless you set `wrap = TRUE`: #' #' ```{asciicast alert-wrap, asciicast_rows = 4} #' cli_alert_info("Data columns: {.val {names(mtcars)}}.") #' cli_alert_info("Data columns: {.val {names(mtcars)}}.", wrap = TRUE) #' ``` #' #' @param text Text of the alert. #' @param id Id of the alert element. Can be used in themes. #' @param class Class of the alert element. Can be used in themes. #' @param wrap Whether to auto-wrap the text of the alert. #' @param .envir Environment to evaluate the glue expressions in. #' #' @seealso These functions supports [inline markup][inline-markup]. #' @family functions supporting inline markup #' @export cli_alert <- function(text, id = NULL, class = NULL, wrap = FALSE, .envir = parent.frame()) { cli__message( "alert", list( text = glue_cmd(text, .envir = .envir, .call = sys.call()), id = id, class = class, wrap = wrap ) ) } #' @rdname cli_alert #' @export cli_alert_success <- function(text, id = NULL, class = NULL, wrap = FALSE, .envir = parent.frame()) { cli__message( "alert_success", list( text = glue_cmd(text, .envir = .envir, .call = sys.call()), id = id, class = class, wrap = wrap ) ) } #' @rdname cli_alert #' @export cli_alert_danger <- function(text, id = NULL, class = NULL, wrap = FALSE, .envir = parent.frame()) { cli__message( "alert_danger", list( text = glue_cmd(text, .envir = .envir, .call = sys.call()), id = id, class = class, wrap = wrap ) ) } #' @rdname cli_alert #' @export cli_alert_warning <- function(text, id = NULL, class = NULL, wrap = FALSE, .envir = parent.frame()) { cli__message( "alert_warning", list( text = glue_cmd(text, .envir = .envir, .call = sys.call()), id = id, class = class, wrap = wrap ) ) } #' @rdname cli_alert #' @export cli_alert_info <- function(text, id = NULL, class = NULL, wrap = FALSE, .envir = parent.frame()) { cli__message( "alert_info", list( text = glue_cmd(text, .envir = .envir, .call = sys.call()), id = id, class = class, wrap = wrap ) ) } #' CLI horizontal rule #' #' It can be used to separate parts of the output. #' #' @details #' #' ## Inline styling and interpolation #' #' ```{asciicast cli-rule} #' pkg <- "mypackage" #' cli_rule(left = "{.pkg {pkg}} results") #' ``` #' #' ## Theming #' #' The line style of the rule can be changed via the the `line-type` #' property. Possible values are: #' #' * `"single"`: (same as `1`), a single line, #' * `"double"`: (same as `2`), a double line, #' * `"bar1"`, `"bar2"`, `"bar3"`, etc., `"bar8"` uses varying height bars. #' #' Colors and background colors can similarly changed via a theme. #' #' ```{asciicast cli-rule-line-type} #' d <- cli_div(theme = list(rule = list( #' color = "cyan", #' "line-type" = "double"))) #' cli_rule("Summary", right = "{.pkg mypackage}") #' cli_end(d) #' ``` #' #' @param .envir Environment to evaluate the glue expressions in. #' @inheritParams rule #' @inheritParams cli_div #' #' @seealso This function supports [inline markup][inline-markup]. #' @family functions supporting inline markup #' @export cli_rule <- function(left = "", center = "", right = "", id = NULL, .envir = parent.frame()) { cli__message("rule", list(left = glue_cmd(left, .envir = .envir, .call = sys.call()), center = glue_cmd(center, .envir = .envir, .call = sys.call()), right = glue_cmd(right, .envir = .envir, .call = sys.call()), id = id)) } #' CLI block quote #' #' A section that is quoted from another source. It is typically indented. #' #' @details #' #' ```{asciicast cli-blockquote} #' 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") #' ``` #' #' @param quote Text of the quotation. #' @param citation Source of the quotation, typically a link or the name #' of a person. #' @inheritParams cli_div #' #' @seealso This function supports [inline markup][inline-markup]. #' @family functions supporting inline markup #' @export cli_blockquote <- function(quote, citation = NULL, id = NULL, class = NULL, .envir = parent.frame()) { cli__message( "blockquote", list( quote = glue_cmd(quote, .envir = .envir, .call = sys.call()), citation = glue_cmd(citation, .envir = .envir, .call = sys.call()), id = id, class = class ) ) } #' A block of code #' #' A helper function that creates a `div` with class `code` and then calls #' `cli_verbatim()` to output code lines. The builtin theme formats these #' containers specially. In particular, it adds syntax highlighting to #' valid R code. #' #' @details #' #' ```{asciicast cli-code} #' myfun <- function() { #' message("Just an example function") #' graphics::pairs(iris, col = 1:4) #' } #' cli_code(format(myfun)) #' ``` #' #' @param lines Character vector, each line will be a line of code, and #' newline characters also create new lines. Note that _no_ glue #' substitution is performed on the code. #' @param ... More character vectors, they are appended to `lines`. #' @param language Programming language. This is also added as a class, #' in addition to `code`. #' @param .auto_close Passed to `cli_div()` when creating the container of #' the code. By default the code container is closed after emitting #' `lines` and `...` via `cli_verbatim()`. You can keep that container #' open with `.auto_close` and/or `.envir`, and then calling #' `cli_verbatim()` to add (more) code. Note that the code will be #' formatted and syntax highlighted separately for each `cli_verbatim()` #' call. #' @param .envir Passed to `cli_div()` when creating the container of the #' code. #' @return The id of the container that contains the code. #' #' @export cli_code <- function(lines = NULL, ..., language = "R", .auto_close = TRUE, .envir = environment()) { lines <- c(lines, unlist(list(...))) id <- cli_div( class = paste("code", language), .auto_close = .auto_close, .envir = .envir ) cli_verbatim(lines) invisible(id) } cli_recorded <- new.env(parent = emptyenv()) cli__message <- function(type, args, .auto_close = TRUE, .envir = NULL, record = getOption("cli.record")) { if ("id" %in% names(args) && is.null(args$id)) args$id <- new_uuid() if (.auto_close && !is.null(.envir) && !identical(.envir, .GlobalEnv)) { if (type == "status") { defer(cli_status_clear(id = args$id, result = args$auto_result), envir = .envir, priority = "first") } else { defer(cli_end(id = args$id), envir = .envir, priority = "first") } } cond <- cli__message_create(type, args) if (is.null(record)) { cli__message_emit(cond) } else { cli_recorded[[record]] <- c(cli_recorded[[record]], list(cond)) } invisible(args$id) } cli__message_create <- function(type, args) { cond <- list(message = paste("cli message", type), type = type, args = args, pid = clienv$pid) class(cond) <- c( getOption("cli.message_class"), "cli_message", "condition" ) cond } cli__message_emit <- function(cond) { withRestarts( { signalCondition(cond) cli__default_handler(cond) }, cli_message_handled = function() NULL) } cli__default_handler <- function(msg) { custom_handler <- getOption("cli.default_handler") if (is.function(custom_handler)) { custom_handler(msg) } else { cli_server_default(msg) } } cli/R/print.R0000644000176200001440000000547714143453131012515 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/progress-variables.R0000644000176200001440000004653314500305721015167 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/vt.R0000644000176200001440000000545114312603722012003 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), italic = grepl("italic;", lgs$values), underline = grepl("underline;", lgs$values), strikethrough = grepl("strikethrough;", lgs$values), blink = grepl("blink;", lgs$values), inverse = grepl("inverse;", lgs$values), color= fg, background_color = bg, link = link, link_params = link_params ) }) do.call(rbind, c(list(df), segments)) } cli/R/ansiex.R0000644000176200001440000010131314521175065012641 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/sysdata.rda0000644000176200001440000034122314301737210013365 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= "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()) { sep <- style[["vec-sep"]] %||% style[["vec_sep"]] %||% ", " sep2 <- style[["vec-sep2"]] %||% style[["vec_sep2"]] %||% " and " last <- style[["vec-last"]] %||% style[["vec_last"]] %||% ", and " 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-c.R0000644000176200001440000000243214143453131013431 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/cliapp-docs.R0000644000176200001440000006021414535114677013563 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/utils.R0000644000176200001440000000101614475300741012510 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/zzz.R0000644000176200001440000001757614535431165012231 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/prettycode.R0000644000176200001440000003071214317007616013537 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) code_theme_default_rstudio() } else { 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))) 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() { list( reserved = "red", number = "blue", null = c("blue", "bold"), operator = "green", call = "cyan", string = "yellow", comment = c("#a9a9a9", "italic"), bracket = list("yellow", "blue", "cyan") ) } #' 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)) { env_name <- sub("^package:", "", env_name) } if (grepl("imports:", env_name)) { env_name <- environmentName(environment(get(name, envir))) } if (grepl("package:", env_name)) { 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/ansi-utils.R0000644000176200001440000000203014143453131013427 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/box-styles.R0000644000176200001440000000336214143453131013461 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/cli-errors.R0000644000176200001440000000142014313063767013435 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/friendly-type.R0000644000176200001440000000765214301763662014162 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)}} 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/keypress.R0000644000176200001440000000424014331172227013214 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/onload.R0000644000176200001440000001065614334167766012652 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/ansi-hyperlink.R0000644000176200001440000003434214500305721014305 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]) style_hyperlink( txt[i], paste0(abs_path(params$path), params$suffix), params = params$params ) }) ret } parse_file_link_params <- function(txt) { if (grepl(":[0-9]+:[0-9]+$", txt)) { # path:line:col path <- sub("^(.*):[0-9]+:[0-9]+$", "\\1", txt) num <- strsplit(sub("^.*:([0-9]+:[0-9]+)$", "\\1", txt), ":", fixed = TRUE)[[1]] if (Sys.getenv("R_CLI_HYPERLINK_STYLE") == "iterm") { list(path = path, params = NULL, suffix = paste0("#", num[1], ":", num[2])) } else { list(path = path, params = c(line = num[1], col = num[2])) } } else if (grepl(":[0-9]+$", txt)) { # path:line path <- sub("^(.*):[0-9]+$", "\\1", txt) num <- sub("^.*:([0-9]+$)", "\\1", txt) if (Sys.getenv("R_CLI_HYPERLINK_STYLE") == "iterm") { list(path = path, params = NULL, suffix = paste0("#", num)) } else { list(path = path, params = c(line = num, col = "1")) } } else { list(path = txt, params = NULL) } } 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) linked <- grepl("\007|\033\\\\", txt) todo <- tolink & !linked if (!any(todo)) return(txt) sprt <- ansi_hyperlink_types()$help if (sprt) { scheme <- if (identical(attr(sprt, "type"), "rstudio")) { "ide:help" } else { "x-r-help" } txt[todo] <- style_hyperlink( text = txt[todo], url = paste0(scheme, ":", txt[todo]) ) } txt } # -- {.help} -------------------------------------------------------------- make_link_help <- function(txt) { mch <- re_match(txt, "^\\[(?.*)\\]\\((?.*)\\)$") text <- ifelse(is.na(mch$text), txt, mch$text) url <- ifelse(is.na(mch$url), txt, mch$url) sprt <- ansi_hyperlink_types()$help if (sprt) { scheme <- if (identical(attr(sprt, "type"), "rstudio")) { "ide:help" } else { "x-r-help" } style_hyperlink(text = text, url = paste0(scheme, ":", url)) } else { url2 <- vcapply(url, function(url1) format_inline("{.fun ?{url1}}")) ifelse(text == url, url2, paste0(text, " (", url2, ")")) } } # -- {.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) url <- ifelse(is.na(mch$url), txt, mch$url) sprt <- ansi_hyperlink_types()$run if (sprt) { scheme <- if (identical(attr(sprt, "type"), "rstudio")) { "ide:run" } else { "x-r-run" } style_hyperlink(text = text, url = paste0(scheme, ":", url)) } else { vcapply(text, function(url1) format_inline("{.code {url1}}")) } } # -- {.topic} ------------------------------------------------------------- make_link_topic <- function(txt) { mch <- re_match(txt, "^\\[(?.*)\\]\\((?.*)\\)$") text <- ifelse(is.na(mch$text), txt, mch$text) url <- ifelse(is.na(mch$url), txt, mch$url) sprt <- ansi_hyperlink_types()$help if (sprt) { scheme <- if (identical(attr(sprt, "type"), "rstudio")) { "ide:help" } else { "x-r-help" } style_hyperlink(text = text, url = paste0(scheme, ":", url)) } else { url2 <- vcapply(url, function(url1) format_inline("{.code ?{url1}}")) ifelse(text == url, url2, paste0(text, " (", url2, ")")) } } # -- {.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) url <- ifelse(is.na(mch$url), txt, mch$url) sprt <- ansi_hyperlink_types()$vignette if (sprt) { scheme <- if (identical(attr(sprt, "type"), "rstudio")) { "ide:vignette" } else { "x-r-vignette" } style_hyperlink(text = text, url = paste0(scheme, ":", url)) } else { url2 <- vcapply(url, function(url1) format_inline("{.code vignette({url1})}")) ifelse(text == url, url2, paste0(text, " (", url2, ")")) } } #' 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 (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") ) } } cli/R/cli-package.R0000644000176200001440000000017214535114677013522 0ustar liggesusers#' @aliases cli-package NULL #' @keywords internal "_PACKAGE" ## usethis namespace: start ## usethis namespace: end NULL cli/R/boxes.R0000644000176200001440000001460114300722334012465 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/cat.R0000644000176200001440000000344414143453131012120 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/simple-theme.R0000644000176200001440000001247014301737210013740 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), quiet = TRUE) mean(nums) < 20000 }) } clienv[["is_iterm_dark"]] } cli/R/spinner.R0000644000176200001440000002472014315626477013047 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/lorem.R0000644000176200001440000000310614143453131012462 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/glue.R0000644000176200001440000001676214535114677012332 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. #' @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 = " and ", 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 (any(is.na(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 == 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/progress-utils.R0000644000176200001440000000213714500305721014347 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/ruler.R0000644000176200001440000000055614200477743012514 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/assertions.R0000644000176200001440000000143014303143653013537 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) && all(!is.na(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/containers.R0000644000176200001440000001253714475300741013527 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/defer.R0000644000176200001440000001263114313063767012447 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/utf8.R0000644000176200001440000001101614313063767012244 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/errors.R0000644000176200001440000010632614500305721012666 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/format-conditions.R0000644000176200001440000001132314500305721015001 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/progress-along.R0000644000176200001440000000763514500305721014317 0ustar liggesusers #' Add a progress bar to a mapping function or for loop #' #' @description #' Note that this function is currently experimental! #' #' Use `cli_progress_along()` in a mapping function or in a for loop, to add a #' progress bar. It uses [cli_progress_bar()] internally. #' #' @details #' #' ## `for` loop #' #' A `for` loop with `cli_progress_along()` looks like this: #' #' ```r #' for (i in cli_progress_along(seq)) { #' ... #' } #' ``` #' #' A complete example: #' #' ```{asciicast progress-along-1} #' #| asciicast_at = "all", #' #| asciicast_knitr_output = "svg", #' #| asciciast_cursor = FALSE #' clifun <- function() { #' for (i in cli_progress_along(1:100, "Downloading")) { #' Sys.sleep(4/100) #' } #' } #' clifun() #' ``` #' #' ## `lapply()` and other mapping functions #' #' They will look like this: #' #' ```r #' lapply(cli_progress_along(X), function(i) ...) #' ``` #' #' A complete example: #' #' ```{asciicast progress-along-2} #' #| asciicast_at = "all", #' #| asciicast_knitr_output = "svg", #' #| asciicast_cursor = FALSE #' res <- lapply(cli_progress_along(1:100, "Downloading"), function(i) { #' Sys.sleep(4/100) #' }) #' ``` #' #' ## Custom format string #' #' ```{asciicast progress-along-3} #' #| asciicast_at = "all", #' #| asciicast_knitr_output = "svg", #' #| asciicast_cursor = FALSE #' clifun <- function() { #' for (i in cli_progress_along(1:100, #' format = "Downloading data file {cli::pb_current}")) { #' Sys.sleep(4/100) #' } #' } #' clifun() #' ``` #' #' ## Breaking out of loops #' #' Note that if you use `break` in the `for` loop, you probably want to #' terminate the progress bar explicitly when breaking out of the loop, #' or right after the loop: #' #' ```r #' for (i in cli_progress_along(seq)) { #' ... #' if (cond) cli_progress_done() && break #' ... #' } #' ``` #' #' @param x Sequence to add the progress bar to. #' @param name Name of the progress bar, a label, passed to #' [cli_progress_bar()]. #' @param total Passed to [cli_progress_bar()]. #' @param ... Passed to [cli_progress_bar()]. #' @param .envir Passed to [cli_progress_bar()]. #' #' @return An index vector from 1 to `length(x)` that triggers progress #' updates as you iterate over it. #' #' @seealso This function supports [inline markup][inline-markup]. #' @seealso [cli_progress_bar()] and the traditional progress bar API. #' @family progress bar functions #' @family functions supporting inline markup #' @export cli_progress_along <- function(x, name = NULL, total = length(x), ..., .envir = parent.frame()) { name; total; .envir; list(...) if (getRversion() < "3.5.0") return(seq_along(x)) id <- cli_progress_bar(name = name, total = total, ..., .auto_close = FALSE, .envir = .envir) closeenv <- sys.frame(-1) if (format(closeenv) != clienv$globalenv) { defer( cli_progress_done(id = id, .envir = .envir, result = "auto"), envir = closeenv ) } sax <- seq_along(x) clienv$progress[[id]]$caller <- .envir .Call(clic_progress_along, sax, clienv$progress[[id]]) } progress_altrep_update <- function(pb) { tryCatch({ cli_tick_reset() caller <- pb$caller pb$tick <- pb$tick + 1L if (is.null(pb$format)) { pb$format <- pb__default_format(pb$type, pb$total) } 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) } } else { for (h in handlers) { if ("set" %in% names(h)) h$set(pb, .envir = caller) } } }, error = function(err) { if (!isTRUE(pb$warned)) { warning("cli progress bar update failed: ", conditionMessage(err), immediate. = TRUE) } pb$warned <- TRUE }) NULL } cli/R/rlang.R0000644000176200001440000000332314500305721012446 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/aab-rstudio-detect.R0000644000176200001440000002015214500305721015022 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() ) d$ver <- if (d$api) asNamespace("rstudioapi")$getVersion() d$desktop <- if (d$api) asNamespace("rstudioapi")$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"]])) { # 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/time-ago.R0000644000176200001440000000627414143453131013057 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/server.R0000644000176200001440000000047714143453131012662 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/unicode.R0000644000176200001440000000374014143453131012776 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/spark.R0000644000176200001440000000557514300722547012505 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 = 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 = 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/timer.R0000644000176200001440000000201014143453131012455 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/width.R0000644000176200001440000000774114313063767012507 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/rematch2.R0000644000176200001440000000172714143453131013060 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/internals.R0000644000176200001440000000706214500302326013344 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) 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/progress-server.R0000644000176200001440000002554414500305721014524 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/tree.R0000644000176200001440000001465414300722574012322 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/progress-client.R0000644000176200001440000007004114521175065014475 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 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/pluralize.R0000644000176200001440000001171314505023734013362 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) as.integer(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. #' #' @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 (qty != 1) parts[1] else "" } else if (length(parts) == 2) { if (qty == 1) parts[1] else parts[2] } else if (length(parts) == 3) { if (qty == 0) { parts[1] } else if (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/debug.R0000644000176200001440000000420014143453131012426 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/rules.R0000644000176200001440000001444614300722523012506 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/cliapp.R0000644000176200001440000002225114535114677012634 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) after <- gsub(" ", "\u00a0", after) 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) # 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/time.R0000644000176200001440000000365514143453131012313 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/enc-utils.R0000644000176200001440000000101314301737210013241 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/ansi.R0000644000176200001440000003067414317007616012316 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/sizes.R0000644000176200001440000000557614143453131012516 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/symbol.R0000644000176200001440000001075714230241015012654 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/hash.R0000644000176200001440000003304214535114677012307 0ustar liggesusers #' SHA-256 hash #' #' Calculate the SHA-256 hash of each element of a character vector. #' #' @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_sha256()` returns a character vector of hexadecimal #' SHA-256 hashes. #' @family hash functions #' #' @export #' @examples #' hash_sha256(c("foo", NA, "bar", "")) hash_sha256 <- function(x) { if (!is.character(x)) x <- as.character(x) na <- is.na(x) x[na] <- NA_character_ x[!na] <- .Call(clic_sha256, x[!na]) x } #' @export #' @rdname hash_sha256 #' @details `hash_raw_sha256()` calculates the SHA-256 hash of the bytes #' of a raw vector. #' #' @return `hash_raw_sha256()` returns a character scalar. hash_raw_sha256 <- function(x) { stopifnot(is.raw(x)) .Call(clic_sha256_raw, x) } #' @export #' @rdname hash_sha256 #' @param serialize_version Workspace format version to use, see #' [base::serialize()]. #' @details `hash_obj_sha256()` calculates the SHA-256 hash of an R #' object. The object is serialized into a binary vector first. #' #' @return `hash_obj_sha256()` returns a character scalar. hash_obj_sha256 <- function(x, serialize_version = 2) { sr <- serialize(x, NULL, version = serialize_version)[-(1:14)] hash_raw_sha256(sr) } #' @export #' @rdname hash_sha256 #' @param paths Character vector of file names. #' @details `hash_file_sha256()` calculates the SHA-256 hash of one or #' more files. #' #' @return `hash_file_sha256()` returns a character vector of SHA-256 #' hashes. hash_file_sha256 <- 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_sha256_file, paths) } #' SHA-1 hash #' #' Calculate the SHA-1 hash of each element of a character vector. #' #' @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_sha1()` returns a character vector of hexadecimal #' SHA-1 hashes. #' @family hash functions #' #' @export #' @examples #' hash_sha1(c("foo", NA, "bar", "")) hash_sha1 <- function(x) { if (!is.character(x)) x <- as.character(x) na <- is.na(x) x[na] <- NA_character_ x[!na] <- .Call(clic_sha1, x[!na]) x } #' @export #' @rdname hash_sha1 #' @details `hash_raw_sha1()` calculates the SHA-1 hash of the bytes #' of a raw vector. #' #' @return `hash_raw_sha1()` returns a character scalar. hash_raw_sha1 <- function(x) { stopifnot(is.raw(x)) .Call(clic_sha1_raw, x) } #' @export #' @rdname hash_sha1 #' @param serialize_version Workspace format version to use, see #' [base::serialize()]. #' @details `hash_obj_sha1()` calculates the SHA-1 hash of an R #' object. The object is serialized into a binary vector first. #' #' @return `hash_obj_sha1()` returns a character scalar. hash_obj_sha1 <- function(x, serialize_version = 2) { sr <- serialize(x, NULL, version = serialize_version)[-(1:14)] hash_raw_sha1(sr) } #' @export #' @rdname hash_sha1 #' @param paths Character vector of file names. #' @details `hash_file_sha1()` calculates the SHA-1 hash of one or #' more files. #' #' @return `hash_file_sha1()` returns a character vector of SHA-1 #' hashes. hash_file_sha1 <- 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_sha1_file, paths) } #' MD5 hash #' #' Calculate the MD5 hash of each element of a character vector. #' #' @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_md5()` returns a character vector of hexadecimal MD5 #' hashes. #' #' @family hash functions #' @seealso [tools::md5sum()] for a base R MD5 function that works on #' files. #' #' @export #' @examples #' hash_md5(c("foo", NA, "bar", "")) hash_md5 <- function(x) { if (!is.character(x)) x <- as.character(x) na <- is.na(x) x[na] <- NA_character_ x[!na] <- .Call(clic_md5, x[!na]) x } #' @export #' @rdname hash_md5 #' @details `hash_raw_md5()` calculates the MD5 hash of the bytes #' of a raw vector. #' #' @return `hash_raw_md5()` returns a character scalar. hash_raw_md5 <- function(x) { stopifnot(is.raw(x)) .Call(clic_md5_raw, x) } #' @export #' @rdname hash_md5 #' @param serialize_version Workspace format version to use, see #' [base::serialize()]. #' @details `hash_obj_md5()` calculates the MD5 hash of an R #' object. The object is serialized into a binary vector first. #' #' @return `hash_obj_md5()` returns a character scalar. hash_obj_md5 <- function(x, serialize_version = 2) { sr <- serialize(x, NULL, version = serialize_version)[-(1:14)] hash_raw_md5(sr) } #' @export #' @rdname hash_md5 #' @param paths Character vector of file names. #' @details `hash_file_md5()` calculates the MD5 hash of one or more #' files. hash_file_md5 <- 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_md5_file, paths) } #' 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. #' #' ## Number of possible hash values #' #' ```{r include = FALSE} #' hf <- function(size) { #' format(nrow(emojis)**size, big.mark = ",", scientific = FALSE) #' } #' ``` #' #' cli uses `r nrow(emojis)` possible emojis. This is the number of #' different hashes you can get for different values of `size`: #' #' | `size` | size of hash table space | #' | -----: | -----------------------: | #' | 1 | `r hf(1)` | #' | 2 | `r hf(2)` | #' | 3 | `r hf(3)` | #' | 4 | `r hf(4)` | #' #' @param x Character vector. `NA` entries will have an `NA` hash. #' @param size Number of emojis to use in a hash. Currently it has to #' be from 1 through 4. #' @return `hash_emoji()` returns a data frame with columns #' * `hash`: the emoji hash, a string of the requested size. #' * `emojis`: list column with the emoji characters in character #' vectors. Note that an emoji might have multiple code points. #' * `text`: text representation of `hash`, comma separated. #' * `names`: list column with the text representations of `emojis`, in #' character vectors. #' #' @family hash functions #' @seealso the emoji package for a comprehensive list of emojis #' @export #' @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 hash_emoji <- function(x, size = 3) { # our integer arithmetic does not work if size > 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, "")[[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, "")[[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) } cli/R/docs.R0000644000176200001440000000220314143453131012271 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/bullets.R0000644000176200001440000000632014500305721013015 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/status-bar.R0000644000176200001440000003567114500305721013443 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/aaa-utils.R0000644000176200001440000000723214535114677013246 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), "")[[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/diff.R0000644000176200001440000002133614500305721012257 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/num-ansi-colors.R0000644000176200001440000002552114521175065014406 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) ver <- strsplit(ver, ",", fixed = TRUE)[[1]] ver <- strsplit(ver, ".", fixed = TRUE)[[1]] 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/app.R0000644000176200001440000000435514313063767012146 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/ansi-palette.R0000644000176200001440000001511714317007616013745 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/tty.R0000644000176200001440000002072714331172227012177 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/themes.R0000644000176200001440000003762314535114677012662 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) 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/sitrep.R0000644000176200001440000000300514230241015012641 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/progress-bar.R0000644000176200001440000000572414500305721013760 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/format.R0000644000176200001440000000634014301737210012636 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/test.R0000644000176200001440000001275614317007616012344 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, ) 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.num_colors = NULL, cli.palette = NULL, crayon.enabled = NULL ) withr::local_envvar( .local_envir = .local_envir, R_CLI_HYPERLINKS = 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/NEWS.md0000644000176200001440000004161614535436475012147 0ustar liggesusers# 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/MD50000644000176200001440000006445014535536335011356 0ustar liggesusersebc41588c11a8736684bb841ffc855ae *DESCRIPTION 6f22fdde441ec9cbaddb626d704887aa *LICENSE 178772a56e7476d2074a8431a4660c38 *LICENSE.note 30fe1f82e394739a4696a7a929140a83 *NAMESPACE 27cb80b21fd6682d51141bc37ce708e2 *NEWS.md b5b8c1b1d1155523447fbf0ca71576d5 *R/aaa-utils.R a0a049f78b45ed14cfbd125d34aa7a71 *R/aab-rstudio-detect.R 21299eb59936de10dd73853ad0a4d7df *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 07684410c3bf35409938b2b2f1a49aa9 *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 70f91772b8d7f41f7738305cd00f4270 *R/cliapp-docs.R f541784dd727c1e780370d420683b8f6 *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 7ea7bdfe521d7258e0f8a9514f64e1e9 *R/friendly-type.R c713390fc9012e402cae2206bc9c1e83 *R/glue.R 1e031baa551839d02a7b9c6df362243f *R/hash.R 14ea6de2c944aa0247af51b4ca97e26e *R/inline.R 45af50726e0da89178f93aa2c64d1216 *R/internals.R a9b3f6f15c34370258194e1c518b260a *R/keypress.R ff681a26e738a802bd685bd2961a5039 *R/lorem.R 2c91b6654b4d6f7501a5a5ef1ed36bc6 *R/num-ansi-colors.R 652144408a87dd191039b45a542e3e3f *R/onload.R 9bc6e15564ee58555ed9198105968bbf *R/pluralize.R a8fdf4e1786aac7146dc7cb307e25cb2 *R/prettycode.R 0684c80487792c973578cff43389a0c7 *R/print.R 50cae8bff401023070aba7d12c5d7108 *R/progress-along.R c22944245d1253723fdd3d9e7ebd0703 *R/progress-bar.R 52a904d067ccd88ab3d0b04d210197c4 *R/progress-c.R 0229198c915bd806d0f5c57c2e791b26 *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 16a1c002ec17143b98835c9a2d9ec2c0 *R/simple-theme.R 782d72952cf8982df5c21aedf119c815 *R/sitrep.R fe5d0e7464286dd1e07746d3da593ad9 *R/sizes.R 41524d862b234ea5b160e3f298e1d706 *R/spark.R 4fc4855ca0231186268c3dceb6177ad7 *R/spinner.R 5276ffce0d82412d9944553d7fac08a5 *R/status-bar.R 537925f62ea66c1fec76ac95b58b6a77 *R/symbol.R a0a0a19c474ac3b68b331d14b1a86ea3 *R/sysdata.rda bc2ef65a79960414946a0f24dc19d255 *R/test.R 5a053d529e9ff31634892c0d4575b435 *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 eb34d7d1e5654b2910d96b558c0e1de1 *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 004ffa924d426a2165686502c0aab396 *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 7c34ec7904b5de1d2142e6a1c117af7c *man/ansi_align.Rd a006fab11b8983900766bdc1f34725e3 *man/ansi_collapse.Rd 4699724b4b25dc1c8acfc849322202ac *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 b0acef4b94a29ee74cc3a0ac4e835c6b *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 90b5478800dfc95198cbb8c35e8bc203 *man/ansi_strsplit.Rd d61bf17a84050fa1b5491b33fc1fb713 *man/ansi_strtrim.Rd cc911e82f358079417efb96f31eebf0b *man/ansi_strwrap.Rd 9954140be0e125751e93951c0d301182 *man/ansi_substr.Rd 3a90dbf17a37429e8ac1a7a32a40d052 *man/ansi_substring.Rd 0182204c394704d7a13d5b8b4b3dc277 *man/ansi_toupper.Rd fcdddea70c40111b4fb3d4d31d26f8ea *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 f6e06570b333b80b7fc6e92dd4717b31 *man/cli-package.Rd 965bab2810f5df039a0575d8fcf780a0 *man/cli.Rd 6a502ae776d391ad14940861f9fc01dc *man/cli_abort.Rd 099d76a9e3393fb9293072da6a0d002c *man/cli_alert.Rd 9b3cfc4a9959801ff8e8de5380e58f3c *man/cli_blockquote.Rd c538bc2aae7792d238abffd8faaea26b *man/cli_bullets.Rd b5de4b40bd990852188d4290a5564177 *man/cli_bullets_raw.Rd d21a156f76739523030e9c8f91648e4d *man/cli_code.Rd 232d6b4778feadf731bb225998b240c8 *man/cli_debug_doc.Rd 4edc86124419fb3da950ee7fdb695cb7 *man/cli_div.Rd 8d68c4c99d397e9a122595738d008d12 *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 c8dd3a617286f8d1a0d59e9800412887 *man/cli_h1.Rd 2271ebcd0de13e0e282aa6ef15cb7013 *man/cli_li.Rd 83478eb8af3d7ef1d29d18d2dae2285c *man/cli_list_themes.Rd 8d36e6f3b8c415860cb1d31fe8f53e34 *man/cli_ol.Rd d459b7f8ded61e8f59bd9b4191be5c60 *man/cli_output_connection.Rd 5bb2c0ec4105dbcf0f928ad7317f6feb *man/cli_par.Rd 94fe3ca87a644844657e47e3c1a42094 *man/cli_process_start.Rd 6e5eab44e0770e4b3bec82cd01122d3e *man/cli_progress_along.Rd c4d3c5117431b1eaa9b46b6511f1287a *man/cli_progress_bar.Rd 31a9049d083bfc8722fd6f1813b420f4 *man/cli_progress_builtin_handlers.Rd 2cd22fcc531ad7c5f4209eff10363eb6 *man/cli_progress_demo.Rd 1f5b55d49fd950b661a7689c7b4af88f *man/cli_progress_message.Rd 9245f3725997adbcb6a2ea1e3522bb5d *man/cli_progress_output.Rd 68a1511a6e91df255715ca3e7d92ca77 *man/cli_progress_step.Rd 0a8b190070e00cc03a36f323be10dea4 *man/cli_progress_styles.Rd efca5eec2e742d5ae7a9aa626fa1ebc3 *man/cli_rule.Rd 703b30512fdf9cf4e5c6e8ae962384d1 *man/cli_sitrep.Rd 2e30773e17f59594d1106812549ffef4 *man/cli_status.Rd d11ae8830bfa6d5bbced969a817615ea *man/cli_status_clear.Rd 586db223b1099eeaa19934aae9c6152e *man/cli_status_update.Rd 8d92f2f11b009e055628cb8d34d6e51d *man/cli_text.Rd 608f8fd93259fcd3f3bababdfa5cd350 *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 1fea69b9ee61c3d649d3dbbc02fab76b *man/format_error.Rd 2b2261bbf581ccae33f94091de5de2b7 *man/format_inline.Rd 1bc469735d000231392f70b1b5e81250 *man/get_spinner.Rd aca89f2759224a3d3c5a580a8fda8958 *man/has_keypress_support.Rd f3dc41a24f794905b8de26c85210fc9e *man/hash_animal.Rd a58bc3dc026311668cf415892e309e92 *man/hash_emoji.Rd 2096dc1ba3587b828c7d65a4f36c6ee9 *man/hash_md5.Rd ea2961460cf2f2e539cea86cf3e2e47e *man/hash_sha1.Rd 0ac412bea1821860e97a3954f36614a5 *man/hash_sha256.Rd 23ef4dc092293eb31be9b8f9c11afa9f *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 6223030d2e881be9d93150cfcbd9e158 *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 9687282f63c2c094b55bc119296eaac2 *src/Makevars 0961a1aea4a66f01da14d7ca99d8f990 *src/ansi.c 0443af0035350eb49d5ad7519e1a7677 *src/charwidth.h 85d497ac098b98f621eb0a16c32c63dc *src/cleancall.c d07e7a5009d72400834256e000215ea0 *src/cleancall.h 0a0a6a613231fe8f49d6bcfcbd79332c *src/cli.h a6ccef6e42b6f8979c37bbe2ebd04acd *src/diff.c 9f1ee6d9b40e7a78246c6b6ffcfdfbc2 *src/errors.c 001ad320075ddf2288694894dabc1354 *src/errors.h 77298488a0bfb3081194813aa4e153ec *src/glue.c 5b122569ab6ec5bf8efc23e0a1bc5363 *src/graphbreak.h ae872fd40a97bb36fd15bc605106d760 *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 b408a68758801ca46573020257d3c091 *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 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 4862311424c8ef5d909274dd931de677 *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 51e2379ada0a3a5900d6c197ebad0c33 *tests/testthat/_snaps/hash.md 2a6ff90d8115e66638c8de7ad47ce5d5 *tests/testthat/_snaps/inline-2.md 8e0bbd568634d9eeee0b50e795dfe430 *tests/testthat/_snaps/inline.md 203e012f92de5049c6bcc8b9a8f5871d *tests/testthat/_snaps/keypress.md 899270c195bf4720e3310836d9d181c0 *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 44b8b34bb7ce7ed0e46aa3c926107f06 *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 a488c9c459fdf4ba7bc583fcb372d7dd *tests/testthat/_snaps/rlang-errors.md 2b56eff607faa35ae4ad937c40cb1546 *tests/testthat/_snaps/rules.md 7b44a77c4d1276c937892b8ad4fbf88e *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 9571e6b8fe9a443172892cfffd0b3eae *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 03db9adc3c870b81038b7870667ac183 *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 3641e75a4611093da86aca62d438bbd4 *tests/testthat/test-diff.R 6bb130fc67f28347c50ef4efe2806039 *tests/testthat/test-format-conditions.R e09aab533c10e50773924d2b15ea2571 *tests/testthat/test-glue.R 49d67ea8b4c67a654dff474d35cef153 *tests/testthat/test-hash.R 330e3e7a5ac4b57c70d62c39482e72b3 *tests/testthat/test-headers.R 3b6201199a8413ee823f5ef89d1f0ba0 *tests/testthat/test-inline-2.R ab7bb8b919b213061894f9a864048a7a *tests/testthat/test-inline.R 790d3ab3fa93d2102d5d8808a52939ba *tests/testthat/test-keypress.R 933262f5868b02cac55766049f38160f *tests/testthat/test-links.R 293c88c7bea1808e28f3a528abd10336 *tests/testthat/test-lists.R 1ff002d5eac823a687c0352b78e13de5 *tests/testthat/test-meta.R 3dc038ee70b7c2102f86ac58b26632d4 *tests/testthat/test-non-breaking-space.R 519b7bc2de64b06992bb1e9960c86d2b *tests/testthat/test-num-ansi-colors.R f67ce38bb496ffec3a6b42e79d464ad7 *tests/testthat/test-package.R b31d5996288ab82084841d30f79ee0aa *tests/testthat/test-pluralization.R 68b8a6e024c65c221048584af74b2010 *tests/testthat/test-prettycode.R 2ba7ec0e5f9c0af17cd189935143e0db *tests/testthat/test-progress-along.R ca32cce5ab076174d4780dbca5d1ba23 *tests/testthat/test-progress-bar.R d4ab1fb42e81175eaa3a4b60b0d61891 *tests/testthat/test-progress-c.R 26a159119d9b9a71030b00a780a38aea *tests/testthat/test-progress-client.R 7d49c01f1cedbbb07ea845b0a84b140e *tests/testthat/test-progress-handler-logger.R 44ddd7da90e2220276afb08b8f57e225 *tests/testthat/test-progress-handler-say.R 14a027955aadc4817bc4bda8a43441d7 *tests/testthat/test-progress-handlers.R 67b1583cb4eb9277bdd69579de0ea9f2 *tests/testthat/test-progress-message.R d024e0a698f86970ad998d8236429e8b *tests/testthat/test-progress-ticking.R 52b86402c61b0d1c7baf00509b3b5547 *tests/testthat/test-progress-types.R 4e8e29a3a296b0df832a90941c19dfe7 *tests/testthat/test-progress-utils.R fd9eb4901a07227a23ed28f67480da32 *tests/testthat/test-progress-variables.R 8956f59ab198b008e079c9068f06cf2d *tests/testthat/test-rlang-errors.R e56ec94c878f9ce6b6ee5fe771033832 *tests/testthat/test-rules.R 037ecf8db1a9d0cc8077b192883151c1 *tests/testthat/test-sitrep.R df32ef54a97001c441906cb893dd3c46 *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 227d4a69acbd750f13ffd353a071f6b2 *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 5769ac32883b0f3bf6c8e2efdde8a13b *tests/testthat/test-utils.R 49cb0a3b078068cc8771e6c1690edc46 *tests/testthat/test-verbatim.R 8969a21703db7bbe99c71ff646197136 *tests/testthat/test-vt.R a9d484b6e7e5f9e472f0449a0b8f000f *tools/ansi-iterm-palettes.txt 211e6b484b96b9108bb28c2b376c9a54 *tools/ansi-palettes.txt dc0faff9b19aa33b1b4011671c9b86ca *tools/dark.itermcolors 4e38cc9beeaac74d0648feb929622628 *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 bd05b1fbabd5e8ff1d46be20d9f81036 *tools/spinners.R 220365a1c26d9bd2759a0a67b0fb8e33 *tools/tango-dark.itermcolors 4f01dbbbc77d1b33a92fcbae99ea4f6c *tools/tango-light.itermcolors a80c1f97e0e100545c1a240ceff0ed97 *tools/unicode.R cli/inst/0000755000176200001440000000000014521175065012004 5ustar liggesuserscli/inst/logo.txt0000644000176200001440000000526614143453131013507 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/inst/examples/0000755000176200001440000000000014143453131013613 5ustar liggesuserscli/inst/examples/apps/0000755000176200001440000000000014521175065014565 5ustar liggesuserscli/inst/examples/apps/search.R0000755000176200001440000000403214143453131016150 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.R0000755000176200001440000000570414521175065015675 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/examples/apps/outdated.R0000755000176200001440000000403014143453131016512 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/up.R0000755000176200001440000000277614143453131015344 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/include/0000755000176200001440000000000014143453131013420 5ustar liggesuserscli/inst/include/cli/0000755000176200001440000000000014500302326014163 5ustar liggesuserscli/inst/include/cli/progress.h0000644000176200001440000002677414500302326016220 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/0000755000176200001440000000000014143453131013127 5ustar liggesuserscli/inst/shiny/nested/0000755000176200001440000000000014143453131014411 5ustar liggesuserscli/inst/shiny/nested/app.R0000644000176200001440000000323614143453131015320 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/along/0000755000176200001440000000000014143453131014227 5ustar liggesuserscli/inst/shiny/along/app.R0000644000176200001440000000250014143453131015127 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/output/0000755000176200001440000000000014143453131014467 5ustar liggesuserscli/inst/shiny/output/app.R0000644000176200001440000000260714143453131015377 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/0000755000176200001440000000000014143453131014417 5ustar liggesuserscli/inst/shiny/format/app.R0000644000176200001440000000256314143453131015330 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/shiny/simple/0000755000176200001440000000000014143453131014420 5ustar liggesuserscli/inst/shiny/simple/app.R0000644000176200001440000000251514143453131015326 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)