cli/0000755000175000017500000000000014202425203011145 5ustar nileshnileshcli/MD50000644000175000017500000007242314202425203011465 0ustar nileshnilesh819edd34e8bbf2643875817ac294fab9 *DESCRIPTION fb71a6cc8aab0b0534ae3ac11be95125 *LICENSE cad1dce5d454f2e73fb7e0d24a1f6b7a *NAMESPACE 27489176b927a7e81f664ae0401308ed *NEWS.md 04c367e028d73ffc66e37dea8ebe6bad *R/aaa-utils.R d75a462da2272b3f2453030012994cac *R/ansi-hyperlink.R f4fd10cebe7a0a3137c381aded069ced *R/ansi-palette.R cd9a096faf39d45ff9084969533b5ec3 *R/ansi-utils.R 21d4619e487af744fe8ea149e763d96d *R/ansi.R 88204ec704ec6775d58854a82779d99f *R/ansiex.R 250d952a5c3aa0c300df2b649a17122c *R/app.R 07684410c3bf35409938b2b2f1a49aa9 *R/assertions.R f70df326a4e14bbdc143d1c984663303 *R/box-styles.R 347f09c3281a10bcdc0d2be40bf7e25a *R/boxes.R 32564b1e09268523a28f8d33b1837de6 *R/bullets.R 516839eb767f2f32445cd6ec1e64c34e *R/cat.R 8e13d94b974c1d916a76cfafc3f75326 *R/cli.R 54220815eaaab6c9c32b1932687158ea *R/cliapp-docs.R 0ee16b8c73fc3b2c220ca6cf6f35e6d5 *R/cliapp.R dd20850a837456f6b175a6f7960976b0 *R/containers.R 87d9b64fa630b7a669d4e51cede01854 *R/debug.R 3180b2d8841fd2361e3ba364018d7e0e *R/defer.R c3d4ab3aa14ed6a0ff3629276a1c1fbe *R/diff.R 3b776cb5d6a93f08073c0f40ddab4778 *R/docs.R 0938759f85540fbe09a1cda88e48f844 *R/format-conditions.R f4ad1b8ba598c7b95bc250b7bbdeba70 *R/format.R c2c129c53249e518ecd70440c1fded63 *R/hash.R e02081d89c36081a195f217be5f58ccb *R/inline.R 1bed34054f17ae9860aa88ec76fcf60d *R/internals.R ff681a26e738a802bd685bd2961a5039 *R/lorem.R e73321fc24f803906a9b5a01578838c0 *R/num-ansi-colors.R f592fa4b51208dd9d1ab31bd71781e61 *R/onload.R 2469145fab94feaf488a83b7ba65dbc2 *R/pluralize.R d230d9cfafcb73b904ff0fa013df8614 *R/prettycode.R 0684c80487792c973578cff43389a0c7 *R/print.R 920877f703be0a30e1443d94500bbee7 *R/progress-along.R 3c793f40a7f45b6c6ff17982471e9975 *R/progress-bar.R 52a904d067ccd88ab3d0b04d210197c4 *R/progress-c.R 7e760461ef3429bc32bfaf6582065db6 *R/progress-client.R 265e22c481ee7542f31fcb58a554d920 *R/progress-server.R 55a2556795e8cc0d29f874900b1a51d4 *R/progress-ticking.R 26db36b79d1e882b64f6068cf43a39b1 *R/progress-utils.R b2056d6f47db32f34e70ba8a6b6dfc7c *R/progress-variables.R 6d32216035fb4ac46d9401e1bdde9596 *R/rematch2.R 921c2f5f4a1c1143dd25aa9d5258c7d9 *R/rlang.R de9230c7f4e3c3c6a210aabff2cad858 *R/rstudio-detect.R 02973c8e5edd0acad617c03f82ce894e *R/ruler.R 01e86ed0edf7d0f67104adab8958d2de *R/rules.R 6314e0be26278524847b03e0eaa82536 *R/server.R 2eeed00e8c9a58fa0d3f5c9029b0450a *R/simple-theme.R 8bd1542a5554b9b71de0b856b284bdbb *R/sitrep.R fe5d0e7464286dd1e07746d3da593ad9 *R/sizes.R 41524d862b234ea5b160e3f298e1d706 *R/spark.R 74cfd6ceecab3e00dbb034c12102337d *R/spinner.R 96cf9ab55afed72b2e83aeb799b13785 *R/status-bar.R 1794c9f2be4320a515584c48a21d9268 *R/symbol.R 85cee35af8fc40303d756c9eb4371826 *R/sysdata.rda cb2d0852a8289426912f231db7b74e14 *R/test.R a90bdf937b277d0467a7ce65f63500cd *R/themes.R dd7f5ddd6a39f483fe1606a1f80b3e0c *R/time-ago.R 5b1c514866de7bd0ca2a88a6c0889cd8 *R/time.R 57c041c648b8e5d4cf17e5e8b0a43ccb *R/timer.R 6e671b6ff7561f2782e0f6a657a4ec00 *R/tree.R dcc940048d3ecdff9c7b3c1702a8e139 *R/tty.R 50794dc6d843381ccd68d7bc8fa424cb *R/unicode.R 9b1789b88675dea5cff28c5149c530b8 *R/utf8.R 34217a36fa4a9dda32c13a4414a3adc4 *R/utils.R 6d6a3ef7695e93fabf343a238e6aad3c *R/width.R b67833e062cb24419948d58a7009dfdd *R/zzz.R 366853a223aa2cdfbb936bbd9fa3ddb9 *README.md 31e4fcd9b4c135bb253e9314857084b5 *inst/examples/apps/news.R d71030204ac721b2b6fb9dd1f013066b *inst/examples/apps/outdated.R e3540d59292af42b3b1570c25cb55260 *inst/examples/apps/search.R 234ede852bac1dc638fc0d774a764ee8 *inst/examples/apps/up.R 0d405bb846a9ed43df83e1faddc3804e *inst/include/cli/progress.h aaffd10fd0246bb9d2333d0d2c920093 *inst/logo.txt 31e4fcd9b4c135bb253e9314857084b5 *inst/scripts/news.R b6a34628690fc7587a54c6f271956f3c *inst/scripts/outdated.R 7b3b382306a00ed2ed4751dc20684556 *inst/scripts/search.R 004ffa924d426a2165686502c0aab396 *inst/scripts/up.R 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 c0bb9af2ac0848aa61113d42f0963c8f *man/ansi-styles.Rd 6f9da4a1367c0b7c6582780ae771341c *man/ansi_align.Rd 9c0d6739c756c96ef931be7286eb8cfa *man/ansi_columns.Rd 2af35f6959a1a2265b694bb5d74a74e6 *man/ansi_has_any.Rd 43c5929ecf4666221aca5e3e2ecddea0 *man/ansi_hide_cursor.Rd 1a37eeb384364fa8e8fa025273ea3cc9 *man/ansi_html.Rd 7da000a2c8aff64dd809c02a1f91f6df *man/ansi_html_style.Rd b0acef4b94a29ee74cc3a0ac4e835c6b *man/ansi_nchar.Rd 1d91a128d1d47d5ea894e34fe92ab1b8 *man/ansi_palettes.Rd c5295588cf82a5d8d763f685a3013413 *man/ansi_regex.Rd 32ff45897a16fa7c07c8a0c8746afe80 *man/ansi_simplify.Rd 647685c24a63f0a999925823c7cd5052 *man/ansi_strip.Rd 90b5478800dfc95198cbb8c35e8bc203 *man/ansi_strsplit.Rd bfc8bdab92695b11e9d2386af79fda02 *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 5d7578a050da1b8e1674c828080cf808 *man/boxx.Rd 2ae081a0f40ce67e56b1becea5f3ecff *man/builtin_theme.Rd b5c432d6f1ab7a9b463099e28fa76ec4 *man/cat_line.Rd 4711e7141b36ac0371164e75ca84b233 *man/chunks/FAQ.Rmd 287ec651ca4d8fca553740b582dbdd2d *man/chunks/pluralization.Rmd ca7a40ef71b78177efa502ad9355af10 *man/cli-config.Rd 147f1e4f3583d4af94a4053d67237857 *man/cli.Rd cc1bfc1f40e137b7348ea6260025b2e1 *man/cli_abort.Rd 5d1ebe0bd2bbaf402abafa8833f9d63a *man/cli_alert.Rd bbdffef44449f770fb962ed35ef36a33 *man/cli_blockquote.Rd a446eab06c0a7d07ffe4c731ae1a9c32 *man/cli_bullets.Rd 52f069f1d4a943dc36050cb1447f38d5 *man/cli_bullets_raw.Rd 8fc41ec766f8b2301d31123760050ddb *man/cli_code.Rd 232d6b4778feadf731bb225998b240c8 *man/cli_debug_doc.Rd 0f48cee13c10005b3c347d9628d1c2b1 *man/cli_div.Rd 8cfcd79893d1e010cc9e591d20a8439c *man/cli_dl.Rd 11ec60706cff78ae989259ab4695392b *man/cli_end.Rd 010d82b27ff12bcacbcc68cd5bf26aff *man/cli_format.Rd 304d09c6e0020b2247bfa9fe7ac558b8 *man/cli_format_method.Rd aa3a11d4a5bd2d19222082a32b173c6a *man/cli_h1.Rd 69f1bb5a96c65786884784fa9e28f5b4 *man/cli_li.Rd 83478eb8af3d7ef1d29d18d2dae2285c *man/cli_list_themes.Rd 466ad3bd85a11ed076f3a973727f4011 *man/cli_ol.Rd d459b7f8ded61e8f59bd9b4191be5c60 *man/cli_output_connection.Rd c3142c4aecc3acd86fff273acd011a06 *man/cli_par.Rd 6cd75c7969b32adf7762970f2c550eb5 *man/cli_process_start.Rd b1569a5c6aaa0a7a7ccbf744afe12cac *man/cli_progress_along.Rd 56cf20317c92318ff237a98944bc3934 *man/cli_progress_bar.Rd ea1f9c7b1f76b7be9d7d36b24d889dce *man/cli_progress_builtin_handlers.Rd 2cd22fcc531ad7c5f4209eff10363eb6 *man/cli_progress_demo.Rd 99db915b8697a7744bde268093ab1ab7 *man/cli_progress_message.Rd 7bdb31a6373ae9fa5fe581ffb829c022 *man/cli_progress_output.Rd 4f749a7c1a8dd471d21baac48f80462c *man/cli_progress_step.Rd 104f151c7be9e7faec1220e504108cc7 *man/cli_progress_styles.Rd 842f3fbfc9194bb166a12c04aba47215 *man/cli_rule.Rd 703b30512fdf9cf4e5c6e8ae962384d1 *man/cli_sitrep.Rd 51bc149db7cc8dbf92355a6e25512f09 *man/cli_status.Rd d11ae8830bfa6d5bbced969a817615ea *man/cli_status_clear.Rd 44d403dacb556da03fd364cd495ef237 *man/cli_status_update.Rd 7eeaf1a0751d1f73052b82a1861c9c88 *man/cli_text.Rd dacafe36799135a38cd1e6dffa2f8d5b *man/cli_ul.Rd 661060eaa4d0e37bca2b87c585593b2b *man/cli_vec.Rd 210b40a943417e5c2f4032a175230791 *man/cli_verbatim.Rd 52ac3c184e6a5a4130e50c44195a7d39 *man/code_highlight.Rd b0acf80707f7e8f1f9ff5941b2f99dd7 *man/code_theme_list.Rd fd6c759558a78f96d61fa6c00b4a4c11 *man/combine_ansi_styles.Rd 5d54dc2998bb6e9fd3a0d35d8310256a *man/console_width.Rd 074aa0b6f53c002dad791e7c40787190 *man/containers.Rd 7ef704253e815c524f51b54e0839701c *man/demo_spinners.Rd d82792e8be7da850aa955041154e329b *man/diff_chr.Rd 50d025ccd01f02ce1931d3789e24f810 *man/diff_str.Rd 40853b8d0ec6f8606067420a6f4fb9cb *man/faq.Rd b2a1fe480374ffb57759688b8db402e4 *man/figures/README/alert-danger.svg 682f9d1a7c8cd48e10b1d238e439b694 *man/figures/README/alert-info.svg 6cfb9d42fc2ebb92937da1aa5bf99c95 *man/figures/README/alert-success.svg c27ccd26dedd1fbe7205508fabcd9678 *man/figures/README/alert-warning.svg 0d6017c8849788b39079e42ab860df79 *man/figures/README/alert.svg 864bfbc7604b6b2d396cb145b71a6af2 *man/figures/README/glue.svg 65667c91bf957204f06ce0149670b418 *man/figures/README/h1.svg 462d80ccdc44979b121913ba4c4b53bf *man/figures/README/h2.svg 08c35184df22da6c5cc4c66dc72c2e71 *man/figures/README/h3.svg 8e1d8a604835eae2873aac75005bd76d *man/figures/README/lists.svg 8525851a5e88f0d2819fb55b7f8af733 *man/figures/README/plurals.svg d1d53c8f7e5050393e14cbc910f50017 *man/figures/README/progress-setup.svg 66f4ffe4eae6cd9367f30ca2ca4996d9 *man/figures/README/progress.svg 207ccb03f7c7b31eea7349423490c974 *man/figures/README/themes.svg aaf0e5b8b6585d136572244aee9fe2f0 *man/figures/alert-danger.svg a31fe2f1e2cb5efa0998d3ee6c767568 *man/figures/alert-info.svg 0ef7b0c0dc2cfdd7b88ee65c6834f970 *man/figures/alert-success.svg 9e511a6afaa93aa5194234b73906503e *man/figures/alert-warning.svg 8df928b652ad163e72b6dbed200858f6 *man/figures/alert-wrap.svg 43e087e182b6005663e30af5de14bcda *man/figures/ansi-align-center.svg afdc0c10970d76565d949aa23fbea944 *man/figures/ansi-align-right.svg cbd26364b6a34181bcaa975e5763712f *man/figures/ansi-align.svg 7b5c339b1da0b841cc4d801af60da598 *man/figures/ansi-column.svg c61174edafea23e54ec020f840781393 *man/figures/box-bg-color.svg a6ce3c057abacbea590dd377488ee6f2 *man/figures/box-border-color.svg 44b53e9179e719b2f034e6096ce61c8a *man/figures/box-border.svg 3d7e07ff1f376204400506749ac108d6 *man/figures/box-custom.svg fe66bf9e43aba7019e17ffd6a913c095 *man/figures/box-default.svg ceb889cceed4f1a3bda5f38590a3aecd *man/figures/box-float.svg b9d6128b8389aa5c9b7e49a1082d084a *man/figures/box-label-align.svg 25adfea79fdf082821b6bfd488247ce2 *man/figures/box-lines.svg ca823bba1b5817b7db4156f175d4f2c1 *man/figures/box-padding.svg 73711c6cad722adcf7655f3cdbd11ac7 *man/figures/box-text-color.svg 12c34f857be198c671b958e2a71ea5b7 *man/figures/builtin-theme.svg 099c0e1f6620c64fb789a2523b278179 *man/figures/cli-abort-2.svg 35b4c98d69ac653e869d87895959f2da *man/figures/cli-abort.svg b5c3012fecb07cf66a8c5f36895da2d2 *man/figures/cli-blockquote.svg 7af2f4d9ed57661c5d0da6e4f0c9a9f6 *man/figures/cli-bullets.svg 1ed101244e3737d859d637f82db6db73 *man/figures/cli-cli.svg e56d9b03ac8d4899de6c595675d0658d *man/figures/cli-code.svg d7dd239ca8dfa934103ae0947110a00d *man/figures/cli-div-close.svg 92b48fb7ff7e2441736242361b90cf79 *man/figures/cli-div.svg e494214bd785bdbec0508015b3ebbe89 *man/figures/cli-dl-2.svg a1f4c6576271ef6f9fed38e51085b593 *man/figures/cli-dl.svg d7089d12578deb05f97657afc7ba4108 *man/figures/cli-end-debug.svg 458b65223dd689e7097f849c157b4a3c *man/figures/cli-end-many.svg 552eea91a29a82f642d93654c68126a3 *man/figures/cli-end-noid.svg 490f54045b4ac223bacd6ec4d3dede02 *man/figures/cli-end.svg ccd4d104abc48f4597c8cbfa55e84b2c *man/figures/cli-format-class.svg 5515e9ea05d8355251fa3c19c005c9af *man/figures/cli-format-default.svg 713b8e4416e817320072f841fe11a90f *man/figures/cli-format-num.svg 394a5f1bf0c8b3d460eaec1924d5aa29 *man/figures/cli-format-theme.svg ee9bab524c556fe32b5718c6783cbfac *man/figures/cli-h1.svg 38a3941004c6e0ed6119516d31e542a4 *man/figures/cli-li.svg 205ed90f9684e615829f239665bcfcee *man/figures/cli-ol-2.svg ee83ee083a51952f25267f3e86faf98a *man/figures/cli-ol-3.svg 1e6de8021e8246853b35d79c34d5cc91 *man/figures/cli-ol.svg ac7e27aa677e8cd38fa58029476b446d *man/figures/cli-par.svg 421c9eb646721e02cdb6102160a9d966 *man/figures/cli-rule-line-type.svg fb4a68ba78d1025692bf9d180cf9400b *man/figures/cli-rule.svg 8bc33a404d0bb223d1e846746228f15d *man/figures/cli-text-concat.svg 2851b81aa7449132012857dc4eea1eda *man/figures/cli-text-containers.svg 5be6df60ee997918cdce38209f35db3b *man/figures/cli-text-glue-style.svg 6ccf450fe4bcf000f653ba9bf2b8b0c6 *man/figures/cli-text-glue.svg 2a91f16e32d6732aa4cd6fe06cdc8b64 *man/figures/cli-text-markup.svg 8530c0e5e6db1fc1e33ac04ab88c0516 *man/figures/cli-text-newline.svg 939a63ed2c4c6a62d2f651a449f2530f *man/figures/cli-text.svg 779d674fa05833936199724669e8cd23 *man/figures/cli-ul-2.svg a287112b710ea2a4c8f46eef21e38b24 *man/figures/cli-ul.svg 22da1c5916f911941ce67fe4bac274c7 *man/figures/cli-vec-2.svg 6c79df60a886cfed9609d1e588e562f8 *man/figures/cli-vec.svg 40674d02b6b800b166c9deb4d27b8a61 *man/figures/cli-verbatim-2.svg 7d4aac4f3a31f6098fbe2ec2859e4dfe *man/figures/cli-verbatim.svg d7dd239ca8dfa934103ae0947110a00d *man/figures/cnt-auto-close.svg 51b04dda8609780ea2b15d9c1df3114a *man/figures/cnt-debug.svg b0fe2284828725b5ea39acb2f8e907d8 *man/figures/cnt-theme.svg 48c0535cffd032906ee5dea450e07c3a *man/figures/demo-spinners.svg e746a903fdbcbe2ca44b1e8aa8706588 *man/figures/format-error-2.svg 7af488294a63ee1eec3dd489d1672ff8 *man/figures/format-error.svg 43ac32a1e2e040f6303ea162925cf9fc *man/figures/get-spinner.svg f6b40b24cf02685e04b7b05b756c6397 *man/figures/inline-collapse-2.svg 1f928c459f31f2e98ac06f0900792064 *man/figures/inline-collapse-trunc.svg 57448176f2db3b034fbf8d7d65dfaca2 *man/figures/inline-collapse.svg 2025d330d00904fd190fc54e5887eeea *man/figures/inline-escape-2.svg 1ac62aabb40dbe605a686b1ac594ecdc *man/figures/inline-escape.svg 8c14a7dd3fe6279bf927400f011c58ca *man/figures/inline-examples.svg 10a1ba86fe2dbc75aadd882d484fcab9 *man/figures/inline-newclass.svg 59ff7634da851d04284ccb3dee662954 *man/figures/inline-plural.svg 4c939ff985c3608709def0c24993bd3d *man/figures/inline-text-2.svg 3a496215da4f2ce054b1a130fbf1ccfd *man/figures/inline-text-3.svg 75805b952342e53c7d5a90f0238da896 *man/figures/inline-text.svg 9187f5e519d35e167c2cb0b27b4b0e85 *man/figures/make-spinner-custom.svg 8c424f7f20ec06d1ae10d05b400d2e66 *man/figures/make-spinner-default.svg bd60a843a29596edb20bf6b9778e609c *man/figures/make-spinner-template.svg 741489c0def75c94f704281d8e7e08dc *man/figures/progress-1.svg e554dee46f2c2008abdf517ffe53bab3 *man/figures/progress-after.svg 9120171f3108b28e790381ea631ebb22 *man/figures/progress-along-1.svg 9b2525a0e762dc8f12cb29f244522ece *man/figures/progress-along-2.svg 990b194895d34f325961576e887148a8 *man/figures/progress-along-3.svg 830086b46a9d63e960c495e59853a3fe *man/figures/progress-clear.svg 299f516d3ee866a153e3be6c85273d69 *man/figures/progress-current.svg 5c295055f492f337c3e68e85c48aabe8 *man/figures/progress-format.svg bc610173dc455fa02e8bcb4c65e5cd08 *man/figures/progress-message.svg 0baa8e2ec39dddca34cb5389b63acfd1 *man/figures/progress-natotal.svg ff02b67de53d072c96a75ed9355d8385 *man/figures/progress-output.svg c3752fcfd3231339f62f3224c873d647 *man/figures/progress-output2.svg b8a79033e3150820be5c132824efe9c2 *man/figures/progress-step-dynamic.svg 482540223247d1c748769b9d69b33248 *man/figures/progress-step-msg.svg 00e849fa661bb98bae1e72e9f139813d *man/figures/progress-step-spin.svg 1b066958ebd1fa58ed8d1e4ab2bccb3e *man/figures/progress-step.svg dc3cbe4a151b68668ced587bb1b5312b *man/figures/progress-style.svg c046384fc628bcf108e0ad960c778f7d *man/figures/progress-tasks.svg 91f30facac6672a84f28e849ca84038c *man/figures/progress-var-bar.svg 00eb3185b6408cab6e002d4f19543a20 *man/figures/progress-var-current-bytes.svg 2883477418eee77956973ba41d46264d *man/figures/progress-var-current.svg 088abdbe4d8d6fb14c76c5282250a242 *man/figures/progress-var-elapsed-clock.svg 0e9397cee4113b85fe5c2aedf8dbe2d9 *man/figures/progress-var-elapsed-raw.svg 0e9397cee4113b85fe5c2aedf8dbe2d9 *man/figures/progress-var-elapsed.svg 72ec978fd0ad1accd9f10453723d211c *man/figures/progress-var-eta-raw.svg e4aa1f5d2e7e0931c2014cfe2d719d36 *man/figures/progress-var-eta-str.svg e4aa1f5d2e7e0931c2014cfe2d719d36 *man/figures/progress-var-eta.svg 1247a06ae5ce8e6e6c73330fcc34a67d *man/figures/progress-var-extra.svg 5dc4262364a1ade6fbfe979ba24e16d7 *man/figures/progress-var-id.svg 392ed1f51d5ca51ab55242aa65ecafe4 *man/figures/progress-var-name.svg 7f2c4aef21d98d92ea546a065b1ef32c *man/figures/progress-var-percent.svg 47d47cc91a0280b563cc08d7ee0b44df *man/figures/progress-var-rate-bytes.svg 04171e447a362f57073d3cf7c009d74d *man/figures/progress-var-rate-raw.svg 04171e447a362f57073d3cf7c009d74d *man/figures/progress-var-rate.svg c2a6045ba94e9e7b222cae48e0a0e4c3 *man/figures/progress-var-status.svg 0adea0b45621df0162d6350cc8ed132c *man/figures/progress-var-timestamp.svg a3c5630bcbf1d733f077288d899337f6 *man/figures/rule-bars.svg 5e8e2a2b2f2426c11f1a3d022d26ab8c *man/figures/rule-center-label.svg 77dc048a448dd7970d3dc8e1823ee59a *man/figures/rule-colored-label.svg b40d2cfc3a3bfb8c6d7fcda73b474e2d *man/figures/rule-colored-line.svg c4aeb147cb2317bcf02bbf83db0c4adb *man/figures/rule-custom-line-2.svg 0621749d9d534897d2789854495b4e1d *man/figures/rule-custom-line-3.svg 1e11e0f64a48262d69b9fb86e48d08db *man/figures/rule-custom-line.svg b79b8e05278fd24d66f999c12962cd6c *man/figures/rule-double.svg 0e6ff654773e9a8ac6e6a15f18414217 *man/figures/rule-left-label.svg ec150eb48e15cf672b52e8413db2ab52 *man/figures/rule-simple.svg 4ceea5cb95c9a54b9fd822bb10c72461 *man/figures/simple-theme.svg 175923db061959c710d55162c9b68386 *man/figures/spark-bar-1.svg 26ea9c2b02ba70da71fe81490d93fc1e *man/figures/spark-bar-2.svg 4ee761999504eaa54c836f8905fc7f68 *man/figures/spark-bar-3.svg 4fa2b98d27a00983e2bb9c54ec89c90a *man/figures/spark-bar-na.svg ebb2c170330ffe1e5b1899eb257f3252 *man/figures/spark-line.svg 96651cffb162a919387c23237e8a3c53 *man/figures/tree-colored.svg 736b6419f2f2a11ebd6974f4a57e59d5 *man/figures/tree-root.svg 440e8d093a55138ec13471d1368f9073 *man/figures/tree-trim-mark.svg 06114a52dc3ff751d03e1a27e207c287 *man/figures/tree-trimming.svg e296565c8291a26b81ec40ec1fee3ab5 *man/figures/tree.svg 364a8296b8cb489ee02d2988f4b8e699 *man/figures/unnamed-chunk-1.svg 555886abcd4eabccf1e12d01b94539ac *man/format_error.Rd 50ce0336265c4830e606bcf73569415c *man/format_inline.Rd 1bc469735d000231392f70b1b5e81250 *man/get_spinner.Rd 441360727ffcfd695c65b743fc263c66 *man/hash_animal.Rd 266c6fb6ec029a2adab5216cdc881ea9 *man/hash_emoji.Rd 368069bd1bea8078888182d280797126 *man/hash_md5.Rd 56582684f44ebb29c2694ef4db9ace53 *man/hash_sha256.Rd 3bf6fa9ed22fe1bed414cb8addb8a893 *man/inline-markup.Rd 42d3e3f9e7d0d39e10c984f87c8d4455 *man/is_ansi_tty.Rd a9cc5b0c8cca45d9667781a598b9d196 *man/is_dynamic_tty.Rd db6609161227f964e931096d054ad27d *man/is_utf8_output.Rd 5873e187476cb94ea1f54d2899ee892e *man/list_spinners.Rd 186de79eed30dedbab1d56f0393bb279 *man/make_ansi_style.Rd e6a4fd99aea9c129eeecfadbbf11adb0 *man/make_spinner.Rd af2aa306413ad76d65eeb0a5e8d0f705 *man/match_selector.Rd 8b59012e34cadc44db3e0b42f4387169 *man/match_selector_node.Rd 590050b38cd8d5a6193f37a281ffd695 *man/num_ansi_colors.Rd 4a7e9434b649515b41c09d181174bdd5 *man/parse_selector.Rd 6223030d2e881be9d93150cfcbd9e158 *man/pluralization-helpers.Rd 193e28171e2d1cd40e5f71c859ed303d *man/pluralization.Rd a71f70adfe09bf0979293e16afd2f0ed *man/pluralize.Rd a66f6b85a2ce483b90b3875916b6fb52 *man/progress-c.Rd 121c6e843abd7f6af6ea95294cc69b61 *man/progress-utils.Rd f80310065c38f31701d2c01746e3939d *man/progress-variables.Rd c906592f96a33ae2aa702ad6e3ea1a96 *man/roxygen/meta.R ba2bc758a5bdc03915384aeb231b3a9f *man/rule.Rd 304fe11b14091714031feb005e745821 *man/ruler.Rd d789be3edeec12df1184cc876458144b *man/simple_theme.Rd c4e1a67475b39a2b67036a0640071ac9 *man/spark_bar.Rd 8fa4f38f40ef640253776d08fa4ed606 *man/spark_line.Rd a1885f5e91610f989cab217160a42ef0 *man/start_app.Rd 15afd79857b2953bd6b08149bba0973f *man/style_hyperlink.Rd 9f2d24afdb3b55694fdc0cfb4180403a *man/symbol.Rd 5b3ed0a6b4f0a4bb098f0df0f5e93db2 *man/test_that_cli.Rd 345bb340d16ac97c543c0feb2c719e22 *man/themes.Rd 4dcbb45edf65b8a68d44cc774a6665ce *man/tree.Rd 30cd9349d566e2c83cde2279e70d3886 *man/unicode-width-workaround.Rd 1bf6714e8b9005b6495cfc690049eaf2 *man/utf8_graphemes.Rd 06cc7204e61f88f01a553fb821c07118 *man/utf8_nchar.Rd af2d6e3e7de13a9ecf27814f6ef5370b *man/utf8_substr.Rd 3f095419a6b4cb9c59c9ec31aac03892 *src/ansi.c af218c4bda60f0825ccd65cb0f816ba3 *src/charwidth.h f0efa1ca8ffc5bbec994ffc083d0d09f *src/cleancall.c a815d0eafe2058e92848c2f9bfe4a5fc *src/cleancall.h dbf7c77122c416ec39d36d39669be0ad *src/cli.h a6ccef6e42b6f8979c37bbe2ebd04acd *src/diff.c bc57a7d677a95e5b3e78250e4a5e0beb *src/errors.c 001ad320075ddf2288694894dabc1354 *src/errors.h 7be27f7fb88f3bae07a93a14b7881ffa *src/graphbreak.h 195e2ef0393c3f75762563b595180f42 *src/init.c aeb4475d37cf3e3ca76088bbe2e0f9dc *src/md5.c 29f9c450b1c517bc4dea762ee2a8057e *src/md5.h 5be948cc433cc19c00831e1b05fbb5af *src/progress-altrep.c 505fda8da8b2d41eedc6ec81b4d718d3 *src/progress.c 4eaa42f5af90351e55841f7b20e8da74 *src/sha256.c ffbb3912dafd747657627c0d94daa2f4 *src/thread.c 62dba94df7bc3ddea939c5c85cf74cc7 *src/tty.c 28e48003483618a7a7ad9419d3b034da *src/utf8.c 10e129ecc2321a5e9bbb6842a4574d8e *src/win-utf8.c 8496818b99808f581e40d9618b0c82de *src/winfiles.c bdcb51aada6be4f06b441c6e08a2836c *src/winfiles.h 6d90f87e885ca9f532e48e742fa4bc04 *tests/testthat.R cc20fead11ef8a0c4d23d8d1caecbbfc *tests/testthat/_snaps/alerts.md eb87716827bf0ab9157012e30cf2742b *tests/testthat/_snaps/ansi-html.md 3558032f2991dd305b80e7748695f669 *tests/testthat/_snaps/ansiex-2.md ba13c6ed253a22ea22995056d798cc62 *tests/testthat/_snaps/ansiex.md ceef50134041119fb9805db00c9dd1e9 *tests/testthat/_snaps/box-styles.md d76acacaf48198050fb5d7cad932ea8d *tests/testthat/_snaps/boxes.md 2d0773c031d9117ecce80932a2277f1e *tests/testthat/_snaps/bullets.md 9e40e2581262433f3193ad9faebeb258 *tests/testthat/_snaps/cat-helpers.md ff6f3bc1ab4779b25d400bb206f812d6 *tests/testthat/_snaps/code.md 32c099bf9ab62da1f3a2f8a589437f07 *tests/testthat/_snaps/collapsing.md 35efa92b63f04fb6b9bb7eeea347531a *tests/testthat/_snaps/containers.md c5ade3c81620698c20d544b10ed6bfd3 *tests/testthat/_snaps/deep-lists.md 9c23e324abb7d5c7d06cd46b4a020b8c *tests/testthat/_snaps/diff.md d3cd6685bc9762fa0e577cdabf391aaa *tests/testthat/_snaps/format-conditions.md ea5539097fd7dedacadc8736483aa5e4 *tests/testthat/_snaps/glue.md 51e2379ada0a3a5900d6c197ebad0c33 *tests/testthat/_snaps/hash.md 8cfcb563c85fc75bd6899558b923d48e *tests/testthat/_snaps/headers.md 2660f17c4b7fce8fd8295d767aa1b3ab *tests/testthat/_snaps/inline-2.md d3293e1c0eddb1aa6b3888f94a6d6af0 *tests/testthat/_snaps/inline.md c957fa895b24c82ca31b9e84a63afcb9 *tests/testthat/_snaps/lists.md f09a9556fbc244ee4eecc1375f6414ae *tests/testthat/_snaps/meta.md 4110fb0a5103292fa9de78afdf35fcf6 *tests/testthat/_snaps/non-breaking-space.md 527c69a2640c83543f4c13a906cdae88 *tests/testthat/_snaps/pluralization.md 772a8a7632c2f74a6a214aa6daf225dd *tests/testthat/_snaps/prettycode.md 4a6dbace1c978cb0cfde7f27b6130d35 *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 a6fb0b0d425405289dfa89440efe8f55 *tests/testthat/_snaps/progress-variables.md 5c805664b666adb846b671796eace351 *tests/testthat/_snaps/rlang-errors.md 2b56eff607faa35ae4ad937c40cb1546 *tests/testthat/_snaps/rules.md 7b44a77c4d1276c937892b8ad4fbf88e *tests/testthat/_snaps/spark.md 3755e8a0f51473417ce0150cb930377e *tests/testthat/_snaps/text.md c999982b6e458a353212cc7c11e59980 *tests/testthat/_snaps/themes.md 3d2fe655fe6f198260cb818cc622d075 *tests/testthat/_snaps/tree.md 37fdf0e661eb86778f8c9295707415a0 *tests/testthat/_snaps/utf8/utf8-output.txt 10e094b3591b13b32735b120d9cf54f3 *tests/testthat/_snaps/utils.md fcc695e662235716767ee796d0241e96 *tests/testthat/_snaps/verbatim.md 9dbf23e98213ef574041dfebae50f1dd *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 72a567a38b6ed84daa4f17c2c4779ea0 *tests/testthat/test-ansi-make.R 780890f89ba1a8c163f4ad977f08483f *tests/testthat/test-ansi.R 5f83df3ada7314845900eb79b4b505b9 *tests/testthat/test-ansiex-2.R 06e411443fc0a2be2077b389d7783c94 *tests/testthat/test-ansiex.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 ddce418529a8e3573cbe758282e113c0 *tests/testthat/test-collapsing.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 11c31c537e86fbe6661f904143540e2b *tests/testthat/test-diff.R 919ed62e8355f26d8c8aa649665f2f3a *tests/testthat/test-format-conditions.R fdb9a0f187d556cafd4fb57b922582ee *tests/testthat/test-glue.R 086dd3d8d5ee0144de2066baf926d09f *tests/testthat/test-hash.R 086133be7e24fbbbe5467e9efd69a89f *tests/testthat/test-headers.R fd3fee492c9613b06fbfdaae0f7ce8bf *tests/testthat/test-inline-2.R ab7bb8b919b213061894f9a864048a7a *tests/testthat/test-inline.R 8b94d876077d1aaeb8b8f281e6dbe376 *tests/testthat/test-lists.R 119a05fbdfa22c387bc946dadef82b07 *tests/testthat/test-meta.R 3dc038ee70b7c2102f86ac58b26632d4 *tests/testthat/test-non-breaking-space.R 519b7bc2de64b06992bb1e9960c86d2b *tests/testthat/test-num-ansi-colors.R b31d5996288ab82084841d30f79ee0aa *tests/testthat/test-pluralization.R 2683bc611ced35828fb86a49f43beaea *tests/testthat/test-prettycode.R 32dba57a0e359d98cf9329045d08049b *tests/testthat/test-progress-along.R ca32cce5ab076174d4780dbca5d1ba23 *tests/testthat/test-progress-bar.R d4ab1fb42e81175eaa3a4b60b0d61891 *tests/testthat/test-progress-c.R 50c6b7c785d238978c5d98e3d915655e *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 764d9e2d4709473435ad5c3760affd3e *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 f65d402f21a635869f3a6f96d01af57a *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 ea41f02eb275099dfcbbc6cb5e52d82a *tests/testthat/test-text.R 41208e5e0ee561945f71eb6b15910def *tests/testthat/test-themes.R 194f344b5bce58d05d6fbfa12f73efec *tests/testthat/test-timer.R 8e6658fead82151cc0eff994f249e6f6 *tests/testthat/test-tree.R 5c4893dea21b420a0dbf258b8f0032a2 *tests/testthat/test-utf8.R 5a55051dbf54ffd59eabb017fe9e1988 *tests/testthat/test-utils.R 49cb0a3b078068cc8771e6c1690edc46 *tests/testthat/test-verbatim.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 220365a1c26d9bd2759a0a67b0fb8e33 *tools/tango-dark.itermcolors 4f01dbbbc77d1b33a92fcbae99ea4f6c *tools/tango-light.itermcolors a80c1f97e0e100545c1a240ceff0ed97 *tools/unicode.R cli/NEWS.md0000644000175000017500000002572114201250425012253 0ustar nileshnilesh # cli 3.2.0 ## Breaking change * The `cli_theme_dark` option is know known as `cli.theme_dark`, to be consistent with all other cli option names (#380). ## Other changes * The preferred names of the S3 clases `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/DESCRIPTION0000644000175000017500000000306614202425203012660 0ustar nileshnileshPackage: cli Title: Helpers for Developing Command Line Interfaces Version: 3.2.0 Authors@R: c( person("Gábor", "Csárdi", , "csardi.gabor@gmail.com", c("aut", "cre")), person("Hadley", "Wickham", role = c("ctb")), person("Kirill", "Müller", role = c("ctb")), person("RStudio", role = "cph") ) 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#readme BugReports: https://github.com/r-lib/cli/issues RoxygenNote: 7.1.2.9000 Depends: R (>= 2.10) Imports: glue (>= 1.6.0), utils Suggests: asciicast, callr, covr, digest, grDevices, htmltools, htmlwidgets, knitr, methods, mockery, processx, ps (>= 1.3.4.9000), rlang, rmarkdown, rstudioapi, shiny, testthat, tibble, whoami, withr Config/testthat/edition: 3 Config/Needs/website: r-lib/asciicast, bench, brio, cpp11, decor, desc, fansi, sessioninfo, usethis, vctrs Encoding: UTF-8 NeedsCompilation: yes Packaged: 2022-02-10 17:53:58 UTC; gaborcsardi Author: Gábor Csárdi [aut, cre], Hadley Wickham [ctb], Kirill Müller [ctb], RStudio [cph] Maintainer: Gábor Csárdi Repository: CRAN Date/Publication: 2022-02-14 10:10:11 UTC cli/README.md0000644000175000017500000001036314143453131012434 0ustar nileshnilesh cli === > Helpers for Developing Command Line Interfaces [![R build status](https://github.com/r-lib/cli/workflows/R-CMD-check/badge.svg)](https://github.com/r-lib/cli/actions) [![](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) [![Coverage Status](https://img.shields.io/codecov/c/github/r-lib/cli/main.svg)](https://codecov.io/github/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") ``` 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")`. License ======= MIT © RStudio cli/man/0000755000175000017500000000000014201250466011726 5ustar nileshnileshcli/man/ansi_regex.Rd0000644000175000017500000000106414143453131014341 0ustar nileshnilesh% 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_strip}()} } \concept{low level ANSI functions} cli/man/demo_spinners.Rd0000644000175000017500000000120714175725167015101 0ustar nileshnilesh% 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/cli_format.Rd0000644000175000017500000000412014175725167014350 0ustar nileshnilesh% 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}{\figure{cli-format-default.svg}}\if{html}{\out{
}}\preformatted{nums <- 1:5 / 7 cli_text("\{.val \{nums\}\}") }\if{html}{\out{
}} \if{html}{\figure{cli-format-num.svg}} } \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}{\figure{cli-format-theme.svg}} 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}{\figure{cli-format-class.svg}} } } \seealso{ \code{\link[=cli_vec]{cli_vec()}} } cli/man/progress-c.Rd0000644000175000017500000001553214143453131014306 0ustar nileshnilesh% 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/cli_progress_step.Rd0000644000175000017500000001024014175725167015757 0ustar nileshnilesh% 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 not 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}} } } cli/man/cli_code.Rd0000644000175000017500000000325214175725167013777 0ustar nileshnilesh% 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}{\figure{cli-code.svg}} } cli/man/cli_progress_output.Rd0000644000175000017500000000234214175725167016350 0ustar nileshnilesh% 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}} } cli/man/inline-markup.Rd0000644000175000017500000001603214175725167015011 0ustar nileshnilesh% 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{ About inline markup in the semantic cli } \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}{\figure{inline-text.svg}} 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}{\figure{inline-text-2.svg}} 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}{\figure{inline-text-3.svg}} } \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. \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. \item \code{fun} for a function name. \item \code{key} for a keyboard key. \item \code{path} for a path (essentially the same as \code{file}). \item \code{pkg} for a package name. \item \code{strong} for strong importance. \item \code{url} for a URL. \item \code{var} for a variable name. \item \code{val} for a generic "value". }\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://acme.com\}.") cli_li("An environment variable: \{.envvar R_LIBS\}.") cli_end(ul) }\if{html}{\out{
}} \if{html}{\figure{inline-examples.svg}} 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}{\figure{inline-newclass.svg}} \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}{\figure{inline-collapse.svg}} 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}{\figure{inline-collapse-2.svg}} By default cli truncates long vectors. The truncation limit is by default one hundred 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}{\figure{inline-collapse-trunc.svg}} } \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. } \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}{\figure{inline-escape.svg}} 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}{\figure{inline-escape-2.svg}} See also examples below. } \section{Pluralization}{ All cli commands that emit text support pluralization. Some examples:\if{html}{\out{
}}\preformatted{ndirs <- 1 nfiles <- 13 cli_alert_info("Found \{ndirs\} diretor\{?y/ies\} and \{nfiles\} file\{?s\}.") cli_text("Will install \{length(pkgs)\} package\{?s\}: \{.pkg \{pkgs\}\}") }\if{html}{\out{
}} \if{html}{\figure{inline-plural.svg}} 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/diff_chr.Rd0000644000175000017500000000350614143453131013764 0ustar nileshnilesh% 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/cli_bullets.Rd0000644000175000017500000000427114200476211014517 0ustar nileshnilesh% 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{buller-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}{\figure{cli-bullets.svg}} } cli/man/diff_str.Rd0000644000175000017500000000223414143453131014015 0ustar nileshnilesh% 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_sitrep.Rd0000644000175000017500000000172614143453131014357 0ustar nileshnilesh% 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/cli_h1.Rd0000644000175000017500000000173014175725167013374 0ustar nileshnilesh% 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}{\figure{cli-h1.svg}} } cli/man/console_width.Rd0000644000175000017500000000271014143453131015055 0ustar nileshnilesh% 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/builtin_theme.Rd0000644000175000017500000000335514200476477015066 0ustar nileshnilesh% 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}{\figure{builtin-theme.svg}} } \seealso{ \link{themes}, \code{\link[=simple_theme]{simple_theme()}}. } cli/man/cli-config.Rd0000644000175000017500000003010314200721522014217 0ustar nileshnilesh% 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{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 only used if ANSI color support is detected. You can set this value to keep relying on auto-detection, but to adjust the number of colors when cli detects color support. 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.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. } \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.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/parse_selector.Rd0000644000175000017500000000154614143453131015234 0ustar nileshnilesh% 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_progress_styles.Rd0000644000175000017500000000243514175725167016336 0ustar nileshnilesh% 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}{\figure{progress-style.svg}} } cli/man/cli_progress_message.Rd0000644000175000017500000000363614175725167016443 0ustar nileshnilesh% 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{ \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. } cli/man/make_spinner.Rd0000644000175000017500000000655614175725167014723 0ustar nileshnilesh% 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_blockquote.Rd0000644000175000017500000000231614175725167015235 0ustar nileshnilesh% 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}{\figure{cli-blockquote.svg}} } cli/man/cli_text.Rd0000644000175000017500000000520214175725167014046 0ustar nileshnilesh% 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}{\figure{cli-text.svg}} } \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}{\figure{cli-text-newline.svg}} } \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}{\figure{cli-text-markup.svg}} } \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}{\figure{cli-text-glue.svg}} } \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}{\figure{cli-text-glue-style.svg}} } \subsection{Multiple arguments}{ Arguments are concatenated.\if{html}{\out{
}}\preformatted{cli_text(c("This ", "will ", "all "), "be ", "one ", "sentence.") }\if{html}{\out{
}} \if{html}{\figure{cli-text-concat.svg}} } \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}{\figure{cli-text-containers.svg}} } } cli/man/cli_bullets_raw.Rd0000644000175000017500000000161214200476211015364 0ustar nileshnilesh% 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()} returned the output instead of printing it. } \seealso{ See \code{\link[=cli_bullets]{cli_bullets()}} for examples. } cli/man/pluralize.Rd0000644000175000017500000000357114143453131014231 0ustar nileshnilesh% 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. } \examples{ # 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") } \seealso{ Other pluralization: \code{\link{no}()}, \code{\link{pluralization}} } \concept{pluralization} cli/man/is_utf8_output.Rd0000644000175000017500000000102714143453131015215 0ustar nileshnilesh% 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/spark_line.Rd0000644000175000017500000000125114175725167014362 0ustar nileshnilesh% 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}{\figure{spark-line.svg}} } \seealso{ \code{\link[=spark_bar]{spark_bar()}} } cli/man/cli_alert.Rd0000644000175000017500000000461714175725167014202 0ustar nileshnilesh% 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}{\figure{alert-success.svg}} } \subsection{Info}{\if{html}{\out{
}}\preformatted{cfl <- "~/.cache/files/latest.cache" cli_alert_info("Updating cache file \{.path \{cfl\}\}.") }\if{html}{\out{
}} \if{html}{\figure{alert-info.svg}} } \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}{\figure{alert-warning.svg}} } \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}{\figure{alert-danger.svg}} } \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}{\figure{alert-wrap.svg}} } } cli/man/ansi_hide_cursor.Rd0000644000175000017500000000242414143453131015536 0ustar nileshnilesh% 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_strip}()} } \concept{low level ANSI functions} \concept{terminal capabilities} cli/man/cli_status_clear.Rd0000644000175000017500000000334714143453131015543 0ustar nileshnilesh% 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/faq.Rd0000644000175000017500000000561414143453131012771 0ustar nileshnilesh% 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/ruler.Rd0000644000175000017500000000047414200477712013357 0ustar nileshnilesh% 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/format_inline.Rd0000644000175000017500000000131714143453131015044 0ustar nileshnilesh% 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()) } \arguments{ \item{...}{Passed to \code{\link[=cli_text]{cli_text()}}.} \item{.envir}{Environment to evaluate the expressions in.} } \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}.") } cli/man/chunks/0000755000175000017500000000000014201250466013221 5ustar nileshnileshcli/man/chunks/pluralization.Rmd0000644000175000017500000001323614143453131016566 0ustar nileshnilesh--- 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/chunks/FAQ.Rmd0000644000175000017500000000514414143453131014277 0ustar nileshnilesh ```{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/boxx.Rd0000644000175000017500000001230514175725167013215 0ustar nileshnilesh% 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}{\figure{box-default.svg}} } \subsection{Change border style}{\if{html}{\out{
}}\preformatted{boxx("Hello there!", border_style = "double") }\if{html}{\out{
}} \if{html}{\figure{box-border.svg}} } \subsection{Multiple lines}{\if{html}{\out{
}}\preformatted{boxx(c("Hello", "there!"), padding = 1) }\if{html}{\out{
}} \if{html}{\figure{box-lines.svg}} } \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}{\figure{box-padding.svg}} } \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}{\figure{box-float.svg}} } \subsection{Text color}{\if{html}{\out{
}}\preformatted{boxx(col_cyan("Hello there!"), padding = 1, float = "center") }\if{html}{\out{
}} \if{html}{\figure{box-text-color.svg}} } \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}{\figure{box-bg-color.svg}} } \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}{\figure{box-border-color.svg}} } \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}{\figure{box-label-align.svg}} } \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}{\figure{box-custom.svg}} } } \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/combine_ansi_styles.Rd0000644000175000017500000000252114143453131016245 0ustar nileshnilesh% 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/spark_bar.Rd0000644000175000017500000000260114175725167014177 0ustar nileshnilesh% 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}{\figure{spark-bar-1.svg}}\if{html}{\out{
}}\preformatted{x <- seq(0, 1, length = 6) spark_bar(sample(x)) }\if{html}{\out{
}} \if{html}{\figure{spark-bar-2.svg}}\if{html}{\out{
}}\preformatted{spark_bar(seq(0, 1, length = 8)) }\if{html}{\out{
}} \if{html}{\figure{spark-bar-3.svg}} \code{NA}s are left out:\if{html}{\out{
}}\preformatted{spark_bar(c(0, NA, 0.5, NA, 1)) }\if{html}{\out{
}} \if{html}{\figure{spark-bar-na.svg}} } \seealso{ \code{\link[=spark_line]{spark_line()}} } cli/man/start_app.Rd0000644000175000017500000000233714143453131014216 0ustar nileshnilesh% 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/ansi_strwrap.Rd0000644000175000017500000000302114143453131014724 0ustar nileshnilesh% 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/cli_progress_bar.Rd0000644000175000017500000002734714175725167015570 0ustar nileshnilesh% 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. You can change this 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 two seconds.\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{ \code{\link[=cli_progress_message]{cli_progress_message()}} and \code{\link[=cli_progress_step]{cli_progress_step()}} for simpler progress messages. } cli/man/ansi_align.Rd0000644000175000017500000000334514201142123014314 0ustar nileshnilesh% 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}{\figure{ansi-align.svg}}\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}{\figure{ansi-align-center.svg}}\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}{\figure{ansi-align-right.svg}} } \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/cli_verbatim.Rd0000644000175000017500000000203714175725167014676 0ustar nileshnilesh% 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}{\figure{cli-verbatim.svg}} } \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}{\figure{cli-verbatim-2.svg}} } } \seealso{ \code{\link[=cli_code]{cli_code()}} for printing R or other source code. } cli/man/unicode-width-workaround.Rd0000644000175000017500000000262514143453131017155 0ustar nileshnilesh% 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_format_method.Rd0000644000175000017500000000403014143453131015670 0ustar nileshnilesh% 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/format_error.Rd0000644000175000017500000000246314175725167014742 0ustar nileshnilesh% 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}{\figure{format-error.svg}}\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}{\figure{format-error-2.svg}} } cli/man/style_hyperlink.Rd0000644000175000017500000000220414200445676015450 0ustar nileshnilesh% 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} \title{Terminal Hyperlinks} \usage{ style_hyperlink(text, url, params = NULL) ansi_has_hyperlink_support() } \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}. } \examples{ cat("This is an", style_hyperlink("R", "https://r-project.org"), "link.\n") ansi_has_hyperlink_support() } cli/man/code_highlight.Rd0000644000175000017500000000173414143453131015162 0ustar nileshnilesh% 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) } \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()}}.} } \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/ansi_columns.Rd0000644000175000017500000000403514175725167014730 0ustar nileshnilesh% 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}{\figure{ansi-column.svg}} } \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/cli_par.Rd0000644000175000017500000000202314175725167013642 0ustar nileshnilesh% 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}{\figure{cli-par.svg}} } cli/man/pluralization.Rd0000644000175000017500000001745014200445676015131 0ustar nileshnilesh% 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{
}}\preformatted{#> Found 0 files. }\if{html}{\out{
}}\preformatted{nfile <- 1; cli_text("Found \{nfile\} file\{?s\}.") }\if{html}{\out{
}}\preformatted{#> Found 1 file. }\if{html}{\out{
}}\preformatted{nfile <- 2; cli_text("Found \{nfile\} file\{?s\}.") }\if{html}{\out{
}}\preformatted{#> Found 2 files. } 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{
}}\preformatted{#> Found 1 directory. }\if{html}{\out{
}}\preformatted{ndir <- 5; cli_text("Found \{ndir\} director\{?y/ies\}.") }\if{html}{\out{
}}\preformatted{#> Found 5 directories. } } \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{
}}\preformatted{#> Found no files. }\if{html}{\out{
}}\preformatted{nfile <- 1; cli_text("Found \{no(nfile)\} file\{?s\}.") }\if{html}{\out{
}}\preformatted{#> Found 1 file. }\if{html}{\out{
}}\preformatted{nfile <- 2; cli_text("Found \{no(nfile)\} file\{?s\}.") }\if{html}{\out{
}}\preformatted{#> Found 2 files. } } \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{
}}\preformatted{#> Will remove the pkg1 package. }\if{html}{\out{
}}\preformatted{pkgs <- c("pkg1", "pkg2", "pkg3") cli_text("Will remove the \{.pkg \{pkgs\}\} package\{?s\}.") }\if{html}{\out{
}}\preformatted{#> Will remove the pkg1, pkg2, and pkg3 packages. } 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{
}}\preformatted{#> Will remove no packages. }\if{html}{\out{
}}\preformatted{pkgs <- c("pkg1", "pkg2", "pkg3") cli_text("Will remove \{?no/the/the\} \{.pkg \{pkgs\}\} package\{?s\}.") }\if{html}{\out{
}}\preformatted{#> Will remove the pkg1, pkg2, and pkg3 packages. } 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{
}}\preformatted{#> Found 3 files and 1 directory } 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{
}}\preformatted{#> 3/10 files need updates } 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/ansi_trimws.Rd0000644000175000017500000000212414143453131014552 0ustar nileshnilesh% 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/ansi_strip.Rd0000644000175000017500000000157714200445676014412 0ustar nileshnilesh% 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) } \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.} } \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}()} } \concept{low level ANSI functions} cli/man/match_selector_node.Rd0000644000175000017500000000170714143453131016222 0ustar nileshnilesh% 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/cli_output_connection.Rd0000644000175000017500000000106114143453131016620 0ustar nileshnilesh% 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/cli_list_themes.Rd0000644000175000017500000000145314143453131015366 0ustar nileshnilesh% 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/tree.Rd0000644000175000017500000001100514175725167013170 0ustar nileshnilesh% 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}{\figure{tree.svg}}\if{html}{\out{
}}\preformatted{tree(data, root = "rcmdcheck") }\if{html}{\out{
}} \if{html}{\figure{tree-root.svg}} \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}{\figure{tree-colored.svg}} } \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}{\figure{tree-trimming.svg}}\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}{\figure{tree-trim-mark.svg}} } } cli/man/progress-variables.Rd0000644000175000017500000002332014175725167016046 0ustar nileshnilesh% 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}{\figure{progress-var-bar.svg}} } \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}{\figure{progress-var-current.svg}} } \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}{\figure{progress-var-current-bytes.svg}} } \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}{\figure{progress-var-elapsed.svg}} } \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}{\figure{progress-var-elapsed-clock.svg}} } \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}{\figure{progress-var-elapsed-raw.svg}} } \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}{\figure{progress-var-eta.svg}} } \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}{\figure{progress-var-eta-raw.svg}} } \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}{\figure{progress-var-eta-str.svg}} } \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}{\figure{progress-var-extra.svg}} } \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}{\figure{progress-var-id.svg}} } \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}{\figure{progress-var-name.svg}} } \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}{\figure{progress-var-percent.svg}} } \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}{\figure{progress-var-rate.svg}} } \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}{\figure{progress-var-rate-raw.svg}} } \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}{\figure{progress-var-rate-bytes.svg}} } \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}{\figure{progress-var-current.svg}} } \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}{\figure{progress-var-status.svg}} } \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}{\figure{progress-var-timestamp.svg}} } \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}{\figure{progress-var-current.svg}} } \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}{\figure{progress-var-rate-bytes.svg}} } } cli/man/ansi_html.Rd0000644000175000017500000000250114143453131014170 0ustar nileshnilesh% Generated by roxygen2: do not edit by hand % Please edit documentation in R/ansiex.R \name{ansi_html} \alias{ansi_html} \title{Convert ANSI styled text to HTML} \usage{ ansi_html(x, escape_reserved = TRUE, csi = c("drop", "keep")) } \arguments{ \item{x}{Input character vector.} \item{escape_reserved}{Whether to escape characters that are reserved in HTML (\code{&}, \code{<} and \code{>}).} \item{csi}{What to do with non-SGR ANSI sequences, either \code{"keep"}, or \code{"drop"} them.} } \value{ Character vector of HTML. } \description{ Convert ANSI styled text to HTML } \examples{ \dontshow{if (cli:::has_packages(c("htmltools", "withr"))) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} ## Syntax highlight the source code of an R function with ANSI tags, ## and export it to a HTML file. code <- withr::with_options( list(ansi.num_colors = 256), code_highlight(format(ansi_html)) ) hcode <- paste(ansi_html(code), collapse = "\n") css <- paste(format(ansi_html_style()), collapse= "\n") page <- htmltools::tagList( htmltools::tags$head(htmltools::tags$style(css)), htmltools::tags$pre(htmltools::HTML(hcode)) ) if (interactive()) htmltools::html_print(page) \dontshow{\}) # examplesIf} } \seealso{ Other ANSI to HTML conversion: \code{\link{ansi_html_style}()} } \concept{ANSI to HTML conversion} cli/man/cli_vec.Rd0000644000175000017500000000263314175725167013644 0ustar nileshnilesh% 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 \code{sep} and \code{last} arguments of \code{\link[glue:glue_collapse]{glue::glue_collapse()}}. See an example below.} } \description{ Add custom cli style to a vector } \details{ You can use this function to change the default parameters of \code{\link[glue:glue_collapse]{glue::glue_collapse()}}, 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}{\figure{cli-vec.svg}} } \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}{\figure{cli-vec-2.svg}} } } \seealso{ \code{\link[=cli_format]{cli_format()}} } cli/man/get_spinner.Rd0000644000175000017500000000253714175725167014560 0ustar nileshnilesh% Generated by roxygen2: do not edit by hand % Please edit documentation in R/spinner.R \name{get_spinner} \alias{get_spinner} \title{Character vector to put a spinner on the screen} \usage{ get_spinner(which = NULL) } \arguments{ \item{which}{The name of the chosen spinner. If \code{NULL}, then the default is used, which can be customized via the \code{cli.spinner_unicode}, \code{cli.spinner_ascii} and \code{cli.spinner} options. (The latter applies to both Unicode and ASCII displays. These options can be set to the name of a built-in spinner, or to a list that has an entry called \code{frames}, a character vector of frames.} } \value{ A list with entries: \code{name}, \code{interval}: the suggested update interval in milliseconds and \code{frames}: the character vector of the spinner's frames. } \description{ \code{cli} contains many different spinners, you choose one according to your taste. } \details{ \if{html}{\out{
}}\preformatted{options(cli.spinner = "hearts") fun <- function() \{ cli_progress_bar("Spinning") for (i in 1:100) \{ Sys.sleep(4/100) cli_progress_update() \} \} fun() options(cli.spinner = NULL) }\if{html}{\out{
}} \if{html}{\figure{get-spinner.svg}} } \seealso{ Other spinners: \code{\link{demo_spinners}()}, \code{\link{list_spinners}()}, \code{\link{make_spinner}()} } \concept{spinners} cli/man/cli.Rd0000644000175000017500000000151314175725167013003 0ustar nileshnilesh% 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}{\figure{cli-cli.svg}} } cli/man/cli_end.Rd0000644000175000017500000000330114175725167013626 0ustar nileshnilesh% 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}{\figure{cli-end.svg}} } \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}{\figure{cli-end-many.svg}} } \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}{\figure{cli-end-noid.svg}} } \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}{\figure{cli-end-debug.svg}} } } cli/man/cli_dl.Rd0000644000175000017500000000325414175725167013466 0ustar nileshnilesh% 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, 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{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}{\figure{cli-dl.svg}} } \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}{\figure{cli-dl-2.svg}} } } cli/man/make_ansi_style.Rd0000644000175000017500000000414114200445676015374 0ustar nileshnilesh% 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/test_that_cli.Rd0000644000175000017500000000543414201142044015041 0ustar nileshnilesh% 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 = 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.} } \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/cran/cli/tree/master/tests/testthat} and the corresponding snapshots at \url{https://github.com/cran/cli/tree/master/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/rule.Rd0000644000175000017500000000771214175725167013212 0ustar nileshnilesh% 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}{\figure{rule-simple.svg}} } \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}{\figure{rule-double.svg}} } \subsection{Bars}{\if{html}{\out{
}}\preformatted{rule(line = "bar2") rule(line = "bar5") }\if{html}{\out{
}} \if{html}{\figure{rule-bars.svg}} } \subsection{Custom lines}{\if{html}{\out{
}}\preformatted{rule(center = "TITLE", line = "~") }\if{html}{\out{
}} \if{html}{\figure{rule-custom-line.svg}}\if{html}{\out{
}}\preformatted{rule(center = "TITLE", line = col_blue("~-")) }\if{html}{\out{
}} \if{html}{\figure{rule-custom-line-2.svg}}\if{html}{\out{
}}\preformatted{rule(center = bg_red(" ", symbol$star, "TITLE", symbol$star, " "), line = "\\u2582", line_col = "orange") }\if{html}{\out{
}} \if{html}{\figure{rule-custom-line-3.svg}} } } \subsection{Left label}{\if{html}{\out{
}}\preformatted{rule(left = "Results") }\if{html}{\out{
}} \if{html}{\figure{rule-left-label.svg}} } \subsection{Centered label}{\if{html}{\out{
}}\preformatted{rule(center = " * RESULTS * ") }\if{html}{\out{
}} \if{html}{\figure{rule-center-label.svg}} } \subsection{Colored labels}{\if{html}{\out{
}}\preformatted{rule(center = col_red(" * RESULTS * ")) }\if{html}{\out{
}} \if{html}{\figure{rule-colored-label.svg}} } \subsection{Colored line}{\if{html}{\out{
}}\preformatted{rule(center = col_red(" * RESULTS * "), line_col = "red") }\if{html}{\out{
}} \if{html}{\figure{rule-colored-line.svg}} } } cli/man/cli_progress_demo.Rd0000644000175000017500000000371114143453131015715 0ustar nileshnilesh% 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/pluralization-helpers.Rd0000644000175000017500000000114414143453131016551 0ustar nileshnilesh% 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/ansi_nchar.Rd0000644000175000017500000000235514143453131014326 0ustar nileshnilesh% 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/man/progress-utils.Rd0000644000175000017500000000135514143453131015222 0ustar nileshnilesh% 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.) } \concept{progress bar} cli/man/is_dynamic_tty.Rd0000644000175000017500000000357714143453131015247 0ustar nileshnilesh% 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/cli_progress_along.Rd0000644000175000017500000000542714175725167016117 0ustar nileshnilesh% 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{ \code{\link[=cli_progress_bar]{cli_progress_bar()}} and the traditional progress bar API. } cli/man/symbol.Rd0000644000175000017500000000124314143453131013521 0ustar nileshnilesh% 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/is_ansi_tty.Rd0000644000175000017500000000214414143453131014542 0ustar nileshnilesh% 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/ansi_strtrim.Rd0000644000175000017500000000217614143453131014740 0ustar nileshnilesh% 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. } \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/cli_rule.Rd0000644000175000017500000000335114175725167014034 0ustar nileshnilesh% 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}{\figure{cli-rule.svg}} } \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}{\figure{cli-rule-line-type.svg}} } } cli/man/list_spinners.Rd0000644000175000017500000000075614143453131015120 0ustar nileshnilesh% 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/ansi_has_any.Rd0000644000175000017500000000155314143453131014654 0ustar nileshnilesh% 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) } \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.} } \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_strip}()} } \concept{low level ANSI functions} cli/man/ansi_substr.Rd0000644000175000017500000000326114143453131014552 0ustar nileshnilesh% 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/cli_process_start.Rd0000644000175000017500000000754414143453131015750 0ustar nileshnilesh% 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{ 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}()} } \concept{status bar} cli/man/cat_line.Rd0000644000175000017500000000253114143453131013773 0ustar nileshnilesh% 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/match_selector.Rd0000644000175000017500000000107614143453131015214 0ustar nileshnilesh% 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_html_style.Rd0000644000175000017500000000274714143453131015424 0ustar nileshnilesh% 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/ansi_toupper.Rd0000644000175000017500000000412514143453131014726 0ustar nileshnilesh% 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/code_theme_list.Rd0000644000175000017500000000342714143453131015351 0ustar nileshnilesh% 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/ansi_palettes.Rd0000644000175000017500000000505614143453131015055 0ustar nileshnilesh% 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/roxygen/0000755000175000017500000000000014143453131013420 5ustar nileshnileshcli/man/roxygen/meta.R0000644000175000017500000000020014143453131014461 0ustar nileshnileshlist( markdown = TRUE, knitr_chunk_options = list( cache = TRUE, error = TRUE, cache.path = "man/_cache/" ) ) cli/man/cli_status.Rd0000644000175000017500000000600514143453131014367 0ustar nileshnilesh% 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{ 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}()} } \concept{status bar} cli/man/cli_status_update.Rd0000644000175000017500000000253214143453131015732 0ustar nileshnilesh% 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{ 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}()} } \concept{status bar} cli/man/ansi_strsplit.Rd0000644000175000017500000000326014143453131015113 0ustar nileshnilesh% 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/num_ansi_colors.Rd0000644000175000017500000001307014200710571015405 0ustar nileshnilesh% 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 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_simplify.Rd0000644000175000017500000000101514200445676015070 0ustar nileshnilesh% 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/hash_sha256.Rd0000644000175000017500000000277314200445676014251 0ustar nileshnilesh% 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 aharacter 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}()} } \concept{hash functions} cli/man/hash_emoji.Rd0000644000175000017500000000513414200445676014336 0ustar nileshnilesh% 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 between 1 and 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_sha256}()} } \concept{hash functions} cli/man/themes.Rd0000644000175000017500000001467614143453131013517 0ustar nileshnilesh% 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_trunc}: Vectors longer than this will be truncated. Defaults to 100. } 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:\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") ) } Create a custom alert type:\preformatted{list( ".alert-start" = list(before = symbol$play), ".alert-stop" = list(before = symbol$stop) ) } } cli/man/cli_ol.Rd0000644000175000017500000000415414175725167013501 0ustar nileshnilesh% 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}{\figure{cli-ol.svg}} } \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}{\figure{cli-ol-2.svg}} } \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}{\figure{cli-ol-3.svg}} } } cli/man/containers.Rd0000644000175000017500000000352414175725167014405 0ustar nileshnilesh% 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}{\figure{cnt-theme.svg}} } \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}{\figure{cnt-auto-close.svg}} } \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}{\figure{cnt-debug.svg}} } } cli/man/cli_div.Rd0000644000175000017500000000322014175725167013642 0ustar nileshnilesh% 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}{\figure{cli-div.svg}} } \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}{\figure{cli-div-close.svg}} } } cli/man/utf8_nchar.Rd0000644000175000017500000000267114143453131014263 0ustar nileshnilesh% 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/cli_progress_builtin_handlers.Rd0000644000175000017500000000575114172272425020334 0ustar nileshnilesh% 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://www.rstudio.com/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 \link[shiny:Progress]{shiny's progress bars}. This handler is available if a shiny app is running. } } cli/man/cli_ul.Rd0000644000175000017500000000341114175725167013502 0ustar nileshnilesh% 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}{\figure{cli-ul.svg}} } \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}{\figure{cli-ul-2.svg}} } } cli/man/utf8_graphemes.Rd0000644000175000017500000000144514143453131015141 0ustar nileshnilesh% 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/cli_li.Rd0000644000175000017500000000236114175725167013471 0ustar nileshnilesh% 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, id = NULL, class = NULL, .auto_close = TRUE, .envir = parent.frame() ) } \arguments{ \item{items}{Character vector of items, or \code{NULL}.} \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}{\figure{cli-li.svg}} } } cli/man/ansi-styles.Rd0000644000175000017500000001351414200445676014504 0ustar nileshnilesh% 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 mode modern interface than the crayon package. } \details{ The \verb{col_*} functions change the (foreground) color to the text. These are the eight original ANSI colors. Note that in some terminals, they might actually look differently, as terminals have their own settings for how to show them. \code{col_none()} is the default color, this is useful in a substring of a colored string. The \verb{col_br_*} functions are bright versions of the eight ANSI colors. Note that on some terminal configurations and themes they might be the same as the non-bright colors. The \verb{bg_*} functions change the background color of the text. These are the eight original ANSI background colors. These, too, can vary in appearance, depending on terminal settings. \code{bg_none()} the the default background color, this is useful in a substring of a background-colored string. The \verb{bg_br_*} functions are the bright versions of the eight ANSI background colors. Note that on some terminal configurations and themes they might be the same as the non-bright colors. The \verb{style_*} functions apply other styling to the text. The currently supported styling functions are: \itemize{ \item \code{style_reset()} to remove any style, including color, \item \code{style_bold()} for boldface / strong text, although some terminals show a bright, high intensity text instead, \item \code{style_dim()} (or \code{style_blurred()} reduced intensity text. \item \code{style_italic()} (not widely supported). \item \code{style_underline()}, \item \code{style_inverse()}, \item \code{style_hidden()}, \item \code{style_strikethrough()} (not widely supported). } The style functions take any number of character vectors as arguments, and they concatenate them using \code{paste0()} before adding the style. Styles can also be nested, and then inner style takes precedence, see examples below. Sometimes you want to revert back to the default text color, in the middle of colored text, or you want to have a normal font in the middle of italic text. You can use the \verb{style_no_*} functions for this. Every \verb{style_*()} function has a \verb{style_no_*()} pair, which defends its argument from taking on the style. See examples below. } \examples{ col_blue("Hello ", "world!") cat(col_blue("Hello ", "world!")) cat("... to highlight the", col_red("search term"), "in a block of text\n") ## Style stack properly cat(col_green( "I am a green line ", col_blue(style_underline(style_bold("with a blue substring"))), " that becomes green again!" )) error <- combine_ansi_styles("red", "bold") warn <- combine_ansi_styles("magenta", "underline") note <- col_cyan cat(error("Error: subscript out of bounds!\n")) cat(warn("Warning: shorter argument was recycled.\n")) cat(note("Note: no such directory.\n")) # style_no_* functions, note that the color is not removed style_italic(col_green(paste0( "italic before, ", style_no_italic("normal here, "), "italic after" ))) # avoiding color for substring style_italic(col_red(paste( "red before", col_none("not red between"), "red after" ))) } \seealso{ Other ANSI styling: \code{\link{combine_ansi_styles}()}, \code{\link{make_ansi_style}()}, \code{\link{num_ansi_colors}()} } \concept{ANSI styling} cli/man/cli_abort.Rd0000644000175000017500000000364414200476211014157 0ustar nileshnilesh% 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, ..., .envir = parent.frame(), call = .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{.envir}{Environment to evaluate the glue expressions in.} \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.} } \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}{\figure{cli-abort.svg}}\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}{\figure{cli-abort-2.svg}} } cli/man/cli_debug_doc.Rd0000644000175000017500000000254314143453131014762 0ustar nileshnilesh% 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/hash_animal.Rd0000644000175000017500000000466414200445676014503 0ustar nileshnilesh% 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 between 0 and 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_animals()} 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 \url{https://gfycat.com}. } \code{hash_raw_anima()} 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_sha256}()} } \concept{hash functions} cli/man/figures/0000755000175000017500000000000014201142123013360 5ustar nileshnileshcli/man/figures/ansi-column.svg0000644000175000017500000000550314201001231016323 0ustar nileshnileshColumns───────────────────────────────────────────┐foo1foo2foo3foo4foo5foo6foo7foo8foo9foo10└────────────────────────────────────────────────────┘cli/man/figures/spark-bar-2.svg0000644000175000017500000000177614201142123016135 0ustar nileshnilesh▁▅▄█▂▇cli/man/figures/progress-var-eta-raw.svg0000644000175000017500000000244014201142123020071 0ustar nileshnilesh■■■■■■■■■■■■■■■■■■■■■66%|ETA:3scli/man/figures/progress-clear.svg0000644000175000017500000010556314201142123017043 0ustar nileshnileshParametertuning■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■100%|ETA:0sDatacleaning1%|ETA:3sDatacleaning■■3%|ETA:3sDatacleaning■■■6%|ETA:3sDatacleaning■■■8%|ETA:3sDatacleaning■■■■11%|ETA:3sDatacleaning■■■■■14%|ETA:3sDatacleaning■■■■■■17%|ETA:3sDatacleaning■■■■■■■20%|ETA:3sDatacleaning■■■■■■■■23%|ETA:3sDatacleaning■■■■■■■■■25%|ETA:3sDatacleaning■■■■■■■■■28%|ETA:3sDatacleaning■■■■■■■■■■31%|ETA:2sDatacleaning■■■■■■■■■■■34%|ETA:2sDatacleaning■■■■■■■■■■■■37%|ETA:2sDatacleaning■■■■■■■■■■■■■39%|ETA:2sDatacleaning■■■■■■■■■■■■■■42%|ETA:2sDatacleaning■■■■■■■■■■■■■■■45%|ETA:2sDatacleaning■■■■■■■■■■■■■■■48%|ETA:2sDatacleaning■■■■■■■■■■■■■■■■50%|ETA:2sDatacleaning■■■■■■■■■■■■■■■■■53%|ETA:2sDatacleaning■■■■■■■■■■■■■■■■■■56%|ETA:2sDatacleaning■■■■■■■■■■■■■■■■■■■59%|ETA:1sDatacleaning■■■■■■■■■■■■■■■■■■■■62%|ETA:1sDatacleaning■■■■■■■■■■■■■■■■■■■■64%|ETA:1sDatacleaning■■■■■■■■■■■■■■■■■■■■■67%|ETA:1sDatacleaning■■■■■■■■■■■■■■■■■■■■■■70%|ETA:1sDatacleaning■■■■■■■■■■■■■■■■■■■■■■■73%|ETA:1sDatacleaning■■■■■■■■■■■■■■■■■■■■■■■■76%|ETA:1sDatacleaning■■■■■■■■■■■■■■■■■■■■■■■■■79%|ETA:1sDatacleaning■■■■■■■■■■■■■■■■■■■■■■■■■■82%|ETA:1sDatacleaning■■■■■■■■■■■■■■■■■■■■■■■■■■84%|ETA:1sDatacleaning■■■■■■■■■■■■■■■■■■■■■■■■■■■87%|ETA:0sDatacleaning■■■■■■■■■■■■■■■■■■■■■■■■■■■■90%|ETA:0sDatacleaning■■■■■■■■■■■■■■■■■■■■■■■■■■■■■93%|ETA:0sDatacleaning■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■96%|ETA:0sDatacleaning■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■99%|ETA:0sParametertuning1%|ETA:4sParametertuning■■4%|ETA:4sParametertuning■■■7%|ETA:3sParametertuning■■■■10%|ETA:3sParametertuning■■■■■12%|ETA:3sParametertuning■■■■■15%|ETA:3sParametertuning■■■■■■18%|ETA:3sParametertuning■■■■■■■21%|ETA:3sParametertuning■■■■■■■■24%|ETA:3sParametertuning■■■■■■■■■27%|ETA:3sParametertuning■■■■■■■■■■29%|ETA:3sParametertuning■■■■■■■■■■■32%|ETA:2sParametertuning■■■■■■■■■■■35%|ETA:2sParametertuning■■■■■■■■■■■■38%|ETA:2sParametertuning■■■■■■■■■■■■■41%|ETA:2sParametertuning■■■■■■■■■■■■■■43%|ETA:2sParametertuning■■■■■■■■■■■■■■■46%|ETA:2sParametertuning■■■■■■■■■■■■■■■■49%|ETA:2sParametertuning■■■■■■■■■■■■■■■■■52%|ETA:2sParametertuning■■■■■■■■■■■■■■■■■55%|ETA:2sParametertuning■■■■■■■■■■■■■■■■■■58%|ETA:2sParametertuning■■■■■■■■■■■■■■■■■■■60%|ETA:1sParametertuning■■■■■■■■■■■■■■■■■■■■63%|ETA:1sParametertuning■■■■■■■■■■■■■■■■■■■■■66%|ETA:1sParametertuning■■■■■■■■■■■■■■■■■■■■■■69%|ETA:1sParametertuning■■■■■■■■■■■■■■■■■■■■■■■72%|ETA:1sParametertuning■■■■■■■■■■■■■■■■■■■■■■■75%|ETA:1sParametertuning■■■■■■■■■■■■■■■■■■■■■■■■78%|ETA:1sParametertuning■■■■■■■■■■■■■■■■■■■■■■■■■81%|ETA:1sParametertuning■■■■■■■■■■■■■■■■■■■■■■■■■■84%|ETA:1sParametertuning■■■■■■■■■■■■■■■■■■■■■■■■■■■86%|ETA:1sParametertuning■■■■■■■■■■■■■■■■■■■■■■■■■■■■89%|ETA:0sParametertuning■■■■■■■■■■■■■■■■■■■■■■■■■■■■■92%|ETA:0sParametertuning■■■■■■■■■■■■■■■■■■■■■■■■■■■■■95%|ETA:0sParametertuning■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■97%|ETA:0scli/man/figures/cli-dl-2.svg0000644000175000017500000000237614201001232015407 0ustar nileshnileshfoo:onebar:twobaz:threecli/man/figures/cli-format-num.svg0000644000175000017500000000315314201001232016730 0ustar nileshnilesh0.142857142857143,0.285714285714286,0.428571428571429,0.571428571428571,and0.714285714285714cli/man/figures/rule-custom-line-3.svg0000644000175000017500000000263114201142123017447 0ustar nileshnilesh▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂ ★TITLE★ ▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂cli/man/figures/format-error.svg0000644000175000017500000000376514201142123016533 0ustar nileshnileshError:`n`mustbeanumericvectorYou'vesupplieda<character>vector.cli/man/figures/tree-trim-mark.svg0000644000175000017500000001311514201001233016736 0ustar nileshnileshdplyr@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/figures/tree-trimming.svg0000644000175000017500000001144714201001233016667 0ustar nileshnileshdplyr@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.2cli/man/figures/rule-left-label.svg0000644000175000017500000000241314201001233017051 0ustar nileshnilesh──Results───────────────────────────────────────────────────────────cli/man/figures/alert-wrap.svg0000644000175000017500000000773414201001232016165 0ustar nileshnileshDatacolumns:"mpg","cyl","disp","hp","drat","wt","qsec","vs","am","gear",and"carb".Datacolumns:"mpg","cyl","disp","hp","drat","wt","qsec","vs","am","gear",and"carb".cli/man/figures/progress-var-timestamp.svg0000644000175000017500000000216014201142123020533 0ustar nileshnilesh2021-08-02T13:28:49+00:00125(25/s)cli/man/figures/cli-ul.svg0000644000175000017500000000230314201001232015257 0ustar nileshnileshonetwothreecli/man/figures/cnt-debug.svg0000644000175000017500000000300114201142123015743 0ustar nileshnilesh<clidocument><bodyid="body"><divid="mydiv">+theme<parid="cli-43131-223"class="myclass">cli/man/figures/cli-ol-3.svg0000644000175000017500000000266214201001232015421 0ustar nileshnileshone1.foo2.bar3.foobartwocli/man/figures/cli-verbatim-2.svg0000644000175000017500000000245714201001232016621 0ustar nileshnileshNostring{interpolation}or{.emphstyling}herecli/man/figures/cli-text-concat.svg0000644000175000017500000000236114201001232017074 0ustar nileshnileshThiswillallbeonesentence.cli/man/figures/cli-vec.svg0000644000175000017500000000247214201001232015423 0ustar nileshnileshMylist:foo&bar&foobar.cli/man/figures/spark-bar-1.svg0000644000175000017500000000177614201001233016130 0ustar nileshnilesh▁▂▄▅▇█cli/man/figures/progress-var-rate.svg0000644000175000017500000000227714201001233017470 0ustar nileshnileshReadinginputfiles68/156[14/s]cli/man/figures/spark-line.svg0000644000175000017500000000177314201001233016152 0ustar nileshnilesh⣀⡠⠔⠊⠉cli/man/figures/progress-format.svg0000644000175000017500000001271314201142123017237 0ustar nileshnileshDownloaded10filesin4.6s.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/alert-warning.svg0000644000175000017500000000270014201001232016645 0ustar nileshnilesh!Failedtoupdatecachefile~/.cache/files/latest.cache.cli/man/figures/progress-current.svg0000644000175000017500000006767514201142123017452 0ustar nileshnileshFirststep■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■100%|ETA:0sSecondstep■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■100%|ETA:0sFirststep1%|ETA:2sFirststep■■■5%|ETA:2sFirststep■■■■9%|ETA:2sFirststep■■■■■13%|ETA:2sFirststep■■■■■■18%|ETA:2sFirststep■■■■■■■21%|ETA:2sFirststep■■■■■■■■■25%|ETA:2sFirststep■■■■■■■■■■29%|ETA:2sFirststep■■■■■■■■■■■33%|ETA:2sFirststep■■■■■■■■■■■■37%|ETA:2sFirststep■■■■■■■■■■■■■■42%|ETA:1sFirststep■■■■■■■■■■■■■■■46%|ETA:1sFirststep■■■■■■■■■■■■■■■■50%|ETA:1sFirststep■■■■■■■■■■■■■■■■■54%|ETA:1sFirststep■■■■■■■■■■■■■■■■■■58%|ETA:1sFirststep■■■■■■■■■■■■■■■■■■■■62%|ETA:1sFirststep■■■■■■■■■■■■■■■■■■■■■66%|ETA:1sFirststep■■■■■■■■■■■■■■■■■■■■■■71%|ETA:1sFirststep■■■■■■■■■■■■■■■■■■■■■■■75%|ETA:1sFirststep■■■■■■■■■■■■■■■■■■■■■■■■■79%|ETA:1sFirststep■■■■■■■■■■■■■■■■■■■■■■■■■■83%|ETA:0sFirststep■■■■■■■■■■■■■■■■■■■■■■■■■■■87%|ETA:0sFirststep■■■■■■■■■■■■■■■■■■■■■■■■■■■■91%|ETA:0sFirststep■■■■■■■■■■■■■■■■■■■■■■■■■■■■■95%|ETA:0sFirststep■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■99%|ETA:0sSecondstep■■3%|ETA:2sSecondstep■■■7%|ETA:2sSecondstep■■■■11%|ETA:2sSecondstep■■■■■15%|ETA:2sSecondstep■■■■■■■19%|ETA:2sSecondstep■■■■■■■■23%|ETA:2sSecondstep■■■■■■■■■27%|ETA:2sSecondstep■■■■■■■■■■31%|ETA:2sSecondstep■■■■■■■■■■■35%|ETA:2sSecondstep■■■■■■■■■■■■■40%|ETA:1sSecondstep■■■■■■■■■■■■■■44%|ETA:1sSecondstep■■■■■■■■■■■■■■■48%|ETA:1sSecondstep■■■■■■■■■■■■■■■■■52%|ETA:1sSecondstep■■■■■■■■■■■■■■■■■■56%|ETA:1sSecondstep■■■■■■■■■■■■■■■■■■■60%|ETA:1sSecondstep■■■■■■■■■■■■■■■■■■■■■65%|ETA:1sSecondstep■■■■■■■■■■■■■■■■■■■■■■69%|ETA:1sSecondstep■■■■■■■■■■■■■■■■■■■■■■■73%|ETA:1sSecondstep■■■■■■■■■■■■■■■■■■■■■■■■77%|ETA:1sSecondstep■■■■■■■■■■■■■■■■■■■■■■■■■81%|ETA:0sSecondstep■■■■■■■■■■■■■■■■■■■■■■■■■■■86%|ETA:0sSecondstep■■■■■■■■■■■■■■■■■■■■■■■■■■■■90%|ETA:0sSecondstep■■■■■■■■■■■■■■■■■■■■■■■■■■■■■94%|ETA:0sSecondstep■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■98%|ETA:0scli/man/figures/progress-natotal.svg0000644000175000017500000004657314201142123017424 0ustar nileshnileshParametertuning100done(27/s)|3.6sParametertuning1done(28/s)|36msParametertuning4done(26/s)|152msParametertuning6done(26/s)|228msParametertuning9done(27/s)|335msParametertuning12done(27/s)|442msParametertuning15done(27/s)|549msParametertuning18done(28/s)|655msParametertuning21done(28/s)|761msParametertuning24done(28/s)|869msParametertuning27done(28/s)|975msParametertuning29done(28/s)|1sParametertuning32done(28/s)|1.2sParametertuning35done(28/s)|1.3sParametertuning38done(28/s)|1.4sParametertuning41done(28/s)|1.5sParametertuning43done(28/s)|1.6sParametertuning46done(28/s)|1.7sParametertuning49done(28/s)|1.8sParametertuning52done(28/s)|1.9sParametertuning55done(28/s)|2sParametertuning58done(28/s)|2.1sParametertuning61done(28/s)|2.2sParametertuning63done(28/s)|2.3sParametertuning66done(28/s)|2.4sParametertuning69done(28/s)|2.5sParametertuning72done(28/s)|2.6sParametertuning75done(28/s)|2.7sParametertuning77done(28/s)|2.8sParametertuning80done(28/s)|2.9sParametertuning83done(28/s)|3sParametertuning86done(28/s)|3.1sParametertuning89done(28/s)|3.2sParametertuning91done(28/s)|3.3sParametertuning94done(28/s)|3.4sParametertuning97done(28/s)|3.5sParametertuning99done(28/s)|3.6scli/man/figures/cli-li.svg0000644000175000017500000000272414201001232015252 0ustar nileshnileshone:1.a2.b3.ctwo:threecli/man/figures/cli-blockquote.svg0000644000175000017500000000710414201001232017013 0ustar nileshnilesh“Therealproblemisthatprogrammershavespentfartoomuchtimeworryingaboutefficiencyinthewrongplacesandatthewrongtimes;prematureoptimizationistherootofallevil(oratleastmostofit)inprogramming.”DonaldErvinKnuthcli/man/figures/ansi-align-right.svg0000644000175000017500000000377314201001231017242 0ustar nileshnilesh┌────────────────────────────────────┐ThisisredThisisbold└────────────────────────────────────┘cli/man/figures/alert-info.svg0000644000175000017500000000253414201001232016140 0ustar nileshnileshUpdatingcachefile~/.cache/files/latest.cache.cli/man/figures/progress-var-bar.svg0000644000175000017500000000235714201142123017304 0ustar nileshnileshFittingmodel■■■■■■■■■■■■■■■■■■■■■66%cli/man/figures/inline-escape-2.svg0000644000175000017500000000246714201001232016760 0ustar nileshnilesh!Awarningwith{braces}.cli/man/figures/cli-abort.svg0000644000175000017500000000464014201142123015761 0ustar nileshnileshError:`n`mustbeanumericvectorYou'vesupplieda<character>vector.Run`rlang::last_error()`toseewheretheerroroccurred.cli/man/figures/cli-abort-2.svg0000644000175000017500000000504614201142123016121 0ustar nileshnileshError:Mustindexanexistingelement:Thereare26elements.You'vetriedtosubsetelement100.Run`rlang::last_error()`toseewheretheerroroccurred.cli/man/figures/progress-var-elapsed.svg0000644000175000017500000000227414201142123020153 0ustar nileshnilesh■■■■■■■■■■■■■■■■■■■■■66%[5s]cli/man/figures/box-border-color.svg0000644000175000017500000000434514201001231017260 0ustar nileshnilesh┌──────────────────┐Hellothere!└──────────────────┘┌──────────────────┐Hellothere!└──────────────────┘cli/man/figures/inline-examples.svg0000644000175000017500000001067414201142123017203 0ustar nileshnileshEmphasizedtext.Strongimportance.Apieceofcode:`sum(a) / length(a)`.Apackagename:cli.Afunctionname:`cli_text()`.Akeyboardkey:press[ENTER].Afilename:/usr/bin/env.Anemailaddress:bugs.bunny@acme.com.AURL:<https://acme.com>.Anenvironmentvariable:`R_LIBS`.cli/man/figures/cli-end-noid.svg0000644000175000017500000000222014201001232016332 0ustar nileshnileshFirstparagraphSecondparagraphcli/man/figures/cli-text-newline.svg0000644000175000017500000000224114201001232017263 0ustar nileshnileshFirstline.Secondline.cli/man/figures/rule-custom-line.svg0000644000175000017500000000223614201001233017304 0ustar nileshnilesh~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~TITLE~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~cli/man/figures/cli-par.svg0000644000175000017500000001703214201001232015426 0ustar nileshnileshSuntanimullamcoLoremquimollitanimestindeseruntadipisicing.Enimdeseruntlaborumadquiqui.AnimessenonanimmagnaLoremconsequatdolorelaborecupidatatmagnaet.EssenullaeiusmodLoremexercitationcupidatatvelitenimexercitationexcepteurnonofficiaincididunt.IdlaborumdolorecommodoLoremesseeasintproident.FugiatmollitinLoremvelitquiexercitationipsumconsecteturadnisiuteudoullamco.MollitofficiareprehenderitculpaLoremestreprehenderitexcepteurenimmagnaincididuntea.Irurenisiadexercitationdeseruntenimanimexcepteurquisminimlaborisveniamnullapariatur.Enimirureautenullairurequinon.Minimvelitproidentsuntsint.Proidentsitoccaecatexaute.cli/man/figures/cli-format-class.svg0000644000175000017500000000247714201001232017246 0ustar nileshnilesh"Jan","Feb",and"Mar"cli/man/figures/box-text-color.svg0000644000175000017500000000313014201001231016756 0ustar nileshnilesh┌──────────────────┐Hellothere!└──────────────────┘cli/man/figures/progress-output2.svg0000644000175000017500000006602714201142123017400 0ustar nileshnileshBeforetheprogressbarCalculating■■■■■■■■■■■■■■■■49%|ETA:2sAlreadyhalfway!Calculating■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■100%|ETA:0sAlldoneCalculating1%|ETA:5sCalculating■■2%|ETA:5sCalculating■■4%|ETA:5sCalculating■■■6%|ETA:5sCalculating■■■■9%|ETA:4sCalculating■■■■11%|ETA:4sCalculating■■■■■13%|ETA:4sCalculating■■■■■15%|ETA:4sCalculating■■■■■■17%|ETA:4sCalculating■■■■■■■19%|ETA:4sCalculating■■■■■■■21%|ETA:4sCalculating■■■■■■■■24%|ETA:4sCalculating■■■■■■■■■26%|ETA:4sCalculating■■■■■■■■■28%|ETA:3sCalculating■■■■■■■■■■30%|ETA:3sCalculating■■■■■■■■■■■32%|ETA:3sCalculating■■■■■■■■■■■34%|ETA:3sCalculating■■■■■■■■■■■■36%|ETA:3sCalculating■■■■■■■■■■■■38%|ETA:3sCalculating■■■■■■■■■■■■■41%|ETA:3sCalculating■■■■■■■■■■■■■■43%|ETA:3sCalculating■■■■■■■■■■■■■■■45%|ETA:3sCalculating■■■■■■■■■■■■■■■47%|ETA:3sCalculating■■■■■■■■■■■■■■■■51%|ETA:2sCalculating■■■■■■■■■■■■■■■■■53%|ETA:2sCalculating■■■■■■■■■■■■■■■■■■56%|ETA:2sCalculating■■■■■■■■■■■■■■■■■■58%|ETA:2sCalculating■■■■■■■■■■■■■■■■■■■60%|ETA:2sCalculating■■■■■■■■■■■■■■■■■■■■62%|ETA:2sCalculating■■■■■■■■■■■■■■■■■■■■64%|ETA:2sCalculating■■■■■■■■■■■■■■■■■■■■■66%|ETA:2sCalculating■■■■■■■■■■■■■■■■■■■■■■69%|ETA:1sCalculating■■■■■■■■■■■■■■■■■■■■■■71%|ETA:1sCalculating■■■■■■■■■■■■■■■■■■■■■■■73%|ETA:1sCalculating■■■■■■■■■■■■■■■■■■■■■■■75%|ETA:1sCalculating■■■■■■■■■■■■■■■■■■■■■■■■77%|ETA:1sCalculating■■■■■■■■■■■■■■■■■■■■■■■■■79%|ETA:1sCalculating■■■■■■■■■■■■■■■■■■■■■■■■■81%|ETA:1sCalculating■■■■■■■■■■■■■■■■■■■■■■■■■■83%|ETA:1sCalculating■■■■■■■■■■■■■■■■■■■■■■■■■■■86%|ETA:1sCalculating■■■■■■■■■■■■■■■■■■■■■■■■■■■88%|ETA:1sCalculating■■■■■■■■■■■■■■■■■■■■■■■■■■■■90%|ETA:0sCalculating■■■■■■■■■■■■■■■■■■■■■■■■■■■■■92%|ETA:0sCalculating■■■■■■■■■■■■■■■■■■■■■■■■■■■■■94%|ETA:0sCalculating■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■96%|ETA:0sCalculating■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■98%|ETA:0scli/man/figures/spark-bar-na.svg0000644000175000017500000000211114201001233016346 0ustar nileshnileshcli/man/figures/inline-text-3.svg0000644000175000017500000000241314201001232016474 0ustar nileshnileshThisisniceandred.cli/man/figures/inline-collapse-trunc.svg0000644000175000017500000000255414201001232020311 0ustar nileshnileshColumnnames:mpg,cyl,disp,hp,drat,….cli/man/figures/progress-var-elapsed-clock.svg0000644000175000017500000000230214201142123021234 0ustar nileshnilesh■■■■■■■■■■■■■■■■■■■■■66%[00:00:05]cli/man/figures/builtin-theme.svg0000644000175000017500000001530614201142123016654 0ustar nileshnilesh──Heading1───────────────────────────────────────────────────────────Heading2────Heading3Dangeralert!WarningalertInfoalertSuccessalertAlertforstartingaprocessorcomputationPackagesandversions:cli1.0.0.Timeintervals:[3.4s]EmphasisandstrongemphasisThisisapieceofcode:`sum(x) / length(x)`Functionnames:`cli::simple_theme()`Files:/usr/bin/envURLs:<https://r-project.org>──Longercodechunk──#windowfunctionsareusefulforgroupedmutatesmtcars%>%group_by(cyl)%>%mutate(rank=min_rank(desc(mpg)))cli/man/figures/simple-theme.svg0000644000175000017500000001546714201142123016507 0ustar nileshnilesh──Heading1─────────────────────────────────────────────────────────Heading2──Heading3✖ Danger alert!WarningalertInfoalertSuccessalertAlertforstartingaprocessorcomputationPackagesandversions:cli1.0.0.Timeintervals:[3.4s]EmphasisandstrongemphasisThisisapieceofcode:`sum(x) / length(x)`Functionnames:`cli::simple_theme()Files:/usr/bin/envURLs:<https://r-project.org>Longercodechunk──#windowfunctionsareusefulforgroupedmutatesmtcars%>%group_by(cyl)%>%mutate(rank=min_rank(desc(mpg)))cli/man/figures/cli-ul-2.svg0000644000175000017500000000237614201001232015430 0ustar nileshnileshonetwothreecli/man/figures/cli-rule.svg0000644000175000017500000000251214201001232015610 0ustar nileshnilesh──mypackageresults─────────────────────────────────────────────────cli/man/figures/ansi-align.svg0000644000175000017500000000372314201142123016130 0ustar nileshnilesh┌────────────────────────────────────┐ThisisredThisisbold└────────────────────────────────────┘cli/man/figures/progress-tasks.svg0000644000175000017500000000517614201142123017101 0ustar nileshnilesh3/3ETA:0s|Tasks1/3ETA:2s|Tasks2/3ETA:1s|Taskscli/man/figures/progress-var-rate-raw.svg0000644000175000017500000000227714201001233020257 0ustar nileshnileshReadinginputfiles68/156[14/s]cli/man/figures/cli-end-many.svg0000644000175000017500000000330414201001232016351 0ustar nileshnileshItemone:Itemtwo:Stillitemtwo.Notinthelistanymorecli/man/figures/tree.svg0000644000175000017500000000242014201001233015032 0ustar nileshnileshprocessx├─assertthat├─crayon├─debugme└─crayon└─R6cli/man/figures/progress-var-eta-str.svg0000644000175000017500000000243714201142123020116 0ustar nileshnilesh■■■■■■■■■■■■■■■■■■■■■66%|ETA:3scli/man/figures/box-default.svg0000644000175000017500000000300114201001231016277 0ustar nileshnilesh┌──────────────────┐Hellothere!└──────────────────┘cli/man/figures/unnamed-chunk-1.svg0000644000175000017500000000163514201001233016775 0ustar nileshnileshcli/man/figures/progress-var-rate-bytes.svg0000644000175000017500000000244214201001233020606 0ustar nileshnileshReadingdata70MB/266MB[14MB/s]cli/man/figures/rule-double.svg0000644000175000017500000000227614201001233016323 0ustar nileshnilesh══════════════════════════════════════════════════════════════════════cli/man/figures/inline-plural.svg0000644000175000017500000000375214201001232016656 0ustar nileshnileshFound1diretoryand13files.Willinstall3packages:pkg1,pkg2,andpkg3cli/man/figures/progress-message.svg0000644000175000017500000001077314201142123017377 0ustar nileshnileshTaskthreeisunderway:step1Taskoneisrunning...Tasktwoisrunning...Taskthreeisunderway:step2Taskthreeisunderway:step3Taskthreeisunderway:step4Taskthreeisunderway:step5cli/man/figures/progress-var-extra.svg0000644000175000017500000000251614201001233017654 0ustar nileshnileshCleaningcacheforuser'gaborcsardi':161MBcli/man/figures/get-spinner.svg0000644000175000017500000005660414201142123016347 0ustar nileshnilesh💛Spinning100done(19/s)|5.3s💙Spinning1done(12/s)|83ms💜Spinning2done(5.7/s)|352ms💚Spinning4done(9/s)|448ms❤️Spinning6done(11/s)|547ms💛Spinning8done(12/s)|646ms💙Spinning10done(13/s)|743ms💜Spinning12done(14/s)|839ms💚Spinning14done(15/s)|938ms❤️Spinning16done(15/s)|1s💛Spinning18done(16/s)|1.1s💙Spinning20done(16/s)|1.2s💜Spinning22done(17/s)|1.3s💚Spinning24done(17/s)|1.4s❤️Spinning27done(17/s)|1.6s💛Spinning29done(17/s)|1.7s💙Spinning31done(17/s)|1.8s💜Spinning33done(18/s)|1.9s💚Spinning35done(18/s)|2s❤️Spinning37done(18/s)|2.1s💛Spinning39done(18/s)|2.2s💙Spinning41done(18/s)|2.3s💜Spinning43done(18/s)|2.4s💚Spinning45done(18/s)|2.5s❤️Spinning47done(18/s)|2.6s💛Spinning50done(18/s)|2.7s💙Spinning52done(19/s)|2.8s💜Spinning54done(19/s)|2.9s💚Spinning56done(19/s)|3s❤️Spinning58done(19/s)|3.1s💛Spinning60done(19/s)|3.2s💙Spinning62done(19/s)|3.3s💜Spinning64done(19/s)|3.4s💚Spinning66done(19/s)|3.5s❤️Spinning68done(19/s)|3.6s💛Spinning70done(19/s)|3.7s💙Spinning72done(19/s)|3.8s💜Spinning74done(19/s)|3.9s💚Spinning76done(19/s)|4s❤️Spinning78done(19/s)|4.1s💛Spinning80done(19/s)|4.2s💙Spinning82done(19/s)|4.3s💜Spinning84done(19/s)|4.4s💚Spinning86done(19/s)|4.5s❤️Spinning89done(19/s)|4.7s💛Spinning90done(19/s)|4.8s💙Spinning92done(19/s)|4.9s💜Spinning94done(19/s)|5s💚Spinning96done(19/s)|5.1s❤️Spinning98done(19/s)|5.2scli/man/figures/inline-newclass.svg0000644000175000017500000000243314201142123017176 0ustar nileshnileshThisis<<inanglebrackets>>.cli/man/figures/ansi-align-center.svg0000644000175000017500000000377314201001231017405 0ustar nileshnilesh┌────────────────────────────────────┐ThisisredThisisbold└────────────────────────────────────┘cli/man/figures/box-padding.svg0000644000175000017500000000425414201001231016274 0ustar nileshnilesh┌──────────────────┐Hellothere!└──────────────────┘┌──────────────────────┐Hellothere!└──────────────────────┘cli/man/figures/spark-bar-3.svg0000644000175000017500000000200414201001233016113 0ustar nileshnilesh▁▂▃▄▅▆▇█cli/man/figures/progress-step-spin.svg0000644000175000017500000004414514201142123017675 0ustar nileshnileshDownloadingdataDownloadingdataDownloadingdataDownloadingdataDownloadingdataDownloadingdataDownloadingdataDownloadingdataDownloadingdataDownloadingdataDownloadingdata[2.3s]Importingdata[1s]Cleaningdata[2s]FittingmodelFittingmodelFittingmodelFittingmodelFittingmodelFittingmodelFittingmodelFittingmodelFittingmodelFittingmodelFittingmodel[3.4s]ImportingdataCleaningdatacli/man/figures/demo-spinners.svg0000644000175000017500000001241314201142123016665 0ustar nileshnilesh🕐clock🕑clock🕒clock🕓clock🕔clock🕕clock🕖clock🕗clock🕘clock🕙clock🕚clockcli/man/figures/cli-text-glue.svg0000644000175000017500000000270414201001232016562 0ustar nileshnileshWehave4missingmeasurements:5,14,25,and26.cli/man/figures/tree-root.svg0000644000175000017500000000645214201001233016024 0ustar nileshnileshrcmdcheck├─callr├─processx├─assertthat├─crayon├─debugme└─crayon└─R6└─R6├─clisymbols├─crayon├─desc├─assertthat├─R6├─crayon└─rprojroot└─backports├─digest├─prettyunits├─magrittr└─assertthat├─R6├─rprojroot└─backports└─withrcli/man/figures/cli-text-containers.svg0000644000175000017500000000330714201001232017773 0ustar nileshnileshFirstitem.StillthefirstitemSeconditem.Stilltheseconditemcli/man/figures/box-custom.svg0000644000175000017500000000502514201142123016203 0ustar nileshnilesh ╭───────────────╮ ★ Hello ★ there! ╰───────────────╯cli/man/figures/progress-along-2.svg0000644000175000017500000005155714201142123017217 0ustar nileshnileshDownloading■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■100%|ETA:0sDownloading0%|ETA:?Downloading■■3%|ETA:5sDownloading■■■5%|ETA:4sDownloading■■■7%|ETA:5sDownloading■■■■10%|ETA:4sDownloading■■■■■12%|ETA:4sDownloading■■■■■14%|ETA:4sDownloading■■■■■■16%|ETA:4sDownloading■■■■■■18%|ETA:4sDownloading■■■■■■■20%|ETA:4sDownloading■■■■■■■■23%|ETA:4sDownloading■■■■■■■■■25%|ETA:4sDownloading■■■■■■■■■27%|ETA:3sDownloading■■■■■■■■■■29%|ETA:3sDownloading■■■■■■■■■■31%|ETA:3sDownloading■■■■■■■■■■■33%|ETA:3sDownloading■■■■■■■■■■■35%|ETA:3sDownloading■■■■■■■■■■■■37%|ETA:3sDownloading■■■■■■■■■■■■■39%|ETA:3sDownloading■■■■■■■■■■■■■■42%|ETA:3sDownloading■■■■■■■■■■■■■■44%|ETA:3sDownloading■■■■■■■■■■■■■■■46%|ETA:3sDownloading■■■■■■■■■■■■■■■48%|ETA:2sDownloading■■■■■■■■■■■■■■■■50%|ETA:2sDownloading■■■■■■■■■■■■■■■■■52%|ETA:2sDownloading■■■■■■■■■■■■■■■■■54%|ETA:2sDownloading■■■■■■■■■■■■■■■■■■56%|ETA:2sDownloading■■■■■■■■■■■■■■■■■■58%|ETA:2sDownloading■■■■■■■■■■■■■■■■■■■60%|ETA:2sDownloading■■■■■■■■■■■■■■■■■■■■62%|ETA:2sDownloading■■■■■■■■■■■■■■■■■■■■■65%|ETA:2sDownloading■■■■■■■■■■■■■■■■■■■■■67%|ETA:2sDownloading■■■■■■■■■■■■■■■■■■■■■■69%|ETA:1sDownloading■■■■■■■■■■■■■■■■■■■■■■71%|ETA:1sDownloading■■■■■■■■■■■■■■■■■■■■■■■73%|ETA:1sDownloading■■■■■■■■■■■■■■■■■■■■■■■75%|ETA:1sDownloading■■■■■■■■■■■■■■■■■■■■■■■■77%|ETA:1sDownloading■■■■■■■■■■■■■■■■■■■■■■■■■80%|ETA:1sDownloading■■■■■■■■■■■■■■■■■■■■■■■■■■82%|ETA:1sDownloading■■■■■■■■■■■■■■■■■■■■■■■■■■84%|ETA:1sDownloading■■■■■■■■■■■■■■■■■■■■■■■■■■■86%|ETA:1sDownloading■■■■■■■■■■■■■■■■■■■■■■■■■■■88%|ETA:1sDownloading■■■■■■■■■■■■■■■■■■■■■■■■■■■■90%|ETA:0sDownloading■■■■■■■■■■■■■■■■■■■■■■■■■■■■■93%|ETA:0sDownloading■■■■■■■■■■■■■■■■■■■■■■■■■■■■■95%|ETA:0sDownloading■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■97%|ETA:0sDownloading■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■99%|ETA:0scli/man/figures/progress-along-3.svg0000644000175000017500000003330514201142123017207 0ustar nileshnileshDownloadingdatafile100Downloadingdatafile0Downloadingdatafile5Downloadingdatafile7Downloadingdatafile10Downloadingdatafile12Downloadingdatafile14Downloadingdatafile16Downloadingdatafile19Downloadingdatafile21Downloadingdatafile23Downloadingdatafile26Downloadingdatafile28Downloadingdatafile30Downloadingdatafile33Downloadingdatafile35Downloadingdatafile37Downloadingdatafile39Downloadingdatafile41Downloadingdatafile44Downloadingdatafile46Downloadingdatafile48Downloadingdatafile51Downloadingdatafile53Downloadingdatafile55Downloadingdatafile58Downloadingdatafile60Downloadingdatafile62Downloadingdatafile65Downloadingdatafile67Downloadingdatafile69Downloadingdatafile71Downloadingdatafile74Downloadingdatafile76Downloadingdatafile78Downloadingdatafile81Downloadingdatafile83Downloadingdatafile85Downloadingdatafile87Downloadingdatafile90Downloadingdatafile92Downloadingdatafile94Downloadingdatafile97Downloadingdatafile99cli/man/figures/box-float.svg0000644000175000017500000000433014201001231015766 0ustar nileshnilesh┌──────────────────┐Hellothere!└──────────────────┘┌──────────────────┐Hellothere!└──────────────────┘cli/man/figures/cli-div.svg0000644000175000017500000000213014201001232015417 0ustar nileshnileshCustomtitlecli/man/figures/progress-var-percent.svg0000644000175000017500000000220214201142123020165 0ustar nileshnilesh■■■■■■■■■■■■■■■■■■■■■66%cli/man/figures/rule-colored-label.svg0000644000175000017500000000257214201001233017554 0ustar nileshnilesh────────────────────────────*RESULTS*───────────────────────────cli/man/figures/progress-style.svg0000644000175000017500000000707014201001232017102 0ustar nileshnileshStyle'classic'#####################66%|ETA:3sStyle'squares'■■■■■■■■■■■■■■■■■■■■■66%|ETA:3sStyle'dot'──────────────────────────────66%|ETA:3sStyle'fillsquares'■■■■■■■■■■■■■■■■■■■■■□□□□□□□□□□66%|ETA:3sStyle'bar'███████████████████████████████66%|ETA:3scli/man/figures/inline-collapse-2.svg0000644000175000017500000000266014201142123017322 0ustar nileshnileshHey,`x`hasclass<POSIXct/POSIXt>.cli/man/figures/box-lines.svg0000644000175000017500000000302214201001231015770 0ustar nileshnilesh┌────────────┐Hellothere!└────────────┘cli/man/figures/inline-collapse.svg0000644000175000017500000000334514201001232017157 0ustar nileshnileshPackages:pkg1,pkg2,andpkg3.Packages:pkg1,pkg2,andpkg3.cli/man/figures/progress-var-current-bytes.svg0000644000175000017500000000227214201001233021336 0ustar nileshnileshGot524kBin5scli/man/figures/cli-end-debug.svg0000644000175000017500000000303414201142123016500 0ustar nileshnilesh<clidocument><bodyid="body"><divid="mydiv">+theme<parid="cli-43131-64"class="myclass">cli/man/figures/README/0000755000175000017500000000000014143453131014326 5ustar nileshnileshcli/man/figures/README/alert.svg0000644000175000017500000000220214143453131016152 0ustar nileshnileshAgenericalertcli/man/figures/README/h2.svg0000644000175000017500000000234014143453131015357 0ustar nileshnilesh──Heading2──cli/man/figures/README/alert-warning.svg0000644000175000017500000000265514143453131017631 0ustar nileshnilesh!CannotreachGitHub,usinglocaldatabasecache.cli/man/figures/README/alert-info.svg0000644000175000017500000000250414143453131017110 0ustar nileshnileshReopeneddatabase<example.com:port>.cli/man/figures/README/h3.svg0000644000175000017500000000214214143453131015360 0ustar nileshnilesh──Heading3cli/man/figures/README/progress-setup.svg0000644000175000017500000000164414143453131020056 0ustar nileshnileshcli/man/figures/README/h1.svg0000644000175000017500000000270614143453131015364 0ustar nileshnilesh──Heading1───────────────────────────────────────────────────────────────────cli/man/figures/README/lists.svg0000644000175000017500000000302214143453131016202 0ustar nileshnilesh1.Item1Subitem1Subitem22.Item2cli/man/figures/README/alert-success.svg0000644000175000017500000000227714143453131017634 0ustar nileshnileshDownloaded3packages.cli/man/figures/README/alert-danger.svg0000644000175000017500000000244514143453131017421 0ustar nileshnileshFailedtoconnecttodatabase.cli/man/figures/README/progress.svg0000644000175000017500000007462414143453131016730 0ustar nileshnileshCleaningdata■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■100%|ETA:0sCleaningdata1%|ETA:6sCleaningdata■■2%|ETA:6sCleaningdata■■3%|ETA:6sCleaningdata■■■5%|ETA:6sCleaningdata■■■7%|ETA:6sCleaningdata■■■8%|ETA:6sCleaningdata■■■■10%|ETA:6sCleaningdata■■■■■12%|ETA:5sCleaningdata■■■■■13%|ETA:5sCleaningdata■■■■■15%|ETA:5sCleaningdata■■■■■■17%|ETA:5sCleaningdata■■■■■■■19%|ETA:5sCleaningdata■■■■■■■20%|ETA:5sCleaningdata■■■■■■■■22%|ETA:5sCleaningdata■■■■■■■■24%|ETA:5sCleaningdata■■■■■■■■■25%|ETA:5sCleaningdata■■■■■■■■■27%|ETA:4sCleaningdata■■■■■■■■■■29%|ETA:4sCleaningdata■■■■■■■■■■30%|ETA:4sCleaningdata■■■■■■■■■■■32%|ETA:4sCleaningdata■■■■■■■■■■■34%|ETA:4sCleaningdata■■■■■■■■■■■■36%|ETA:4sCleaningdata■■■■■■■■■■■■37%|ETA:4sCleaningdata■■■■■■■■■■■■■39%|ETA:4sCleaningdata■■■■■■■■■■■■■41%|ETA:4sCleaningdata■■■■■■■■■■■■■■42%|ETA:4sCleaningdata■■■■■■■■■■■■■■44%|ETA:3sCleaningdata■■■■■■■■■■■■■■■46%|ETA:3sCleaningdata■■■■■■■■■■■■■■■47%|ETA:3sCleaningdata■■■■■■■■■■■■■■■■49%|ETA:3sCleaningdata■■■■■■■■■■■■■■■■51%|ETA:3sCleaningdata■■■■■■■■■■■■■■■■■52%|ETA:3sCleaningdata■■■■■■■■■■■■■■■■■54%|ETA:3sCleaningdata■■■■■■■■■■■■■■■■■■56%|ETA:3sCleaningdata■■■■■■■■■■■■■■■■■■58%|ETA:3sCleaningdata■■■■■■■■■■■■■■■■■■■59%|ETA:3sCleaningdata■■■■■■■■■■■■■■■■■■■61%|ETA:2sCleaningdata■■■■■■■■■■■■■■■■■■■■63%|ETA:2sCleaningdata■■■■■■■■■■■■■■■■■■■■64%|ETA:2sCleaningdata■■■■■■■■■■■■■■■■■■■■■66%|ETA:2sCleaningdata■■■■■■■■■■■■■■■■■■■■■68%|ETA:2sCleaningdata■■■■■■■■■■■■■■■■■■■■■■69%|ETA:2sCleaningdata■■■■■■■■■■■■■■■■■■■■■■71%|ETA:2sCleaningdata■■■■■■■■■■■■■■■■■■■■■■■72%|ETA:2sCleaningdata■■■■■■■■■■■■■■■■■■■■■■■74%|ETA:2sCleaningdata■■■■■■■■■■■■■■■■■■■■■■■■76%|ETA:1sCleaningdata■■■■■■■■■■■■■■■■■■■■■■■■77%|ETA:1sCleaningdata■■■■■■■■■■■■■■■■■■■■■■■■■79%|ETA:1sCleaningdata■■■■■■■■■■■■■■■■■■■■■■■■■81%|ETA:1sCleaningdata■■■■■■■■■■■■■■■■■■■■■■■■■■82%|ETA:1sCleaningdata■■■■■■■■■■■■■■■■■■■■■■■■■■84%|ETA:1sCleaningdata■■■■■■■■■■■■■■■■■■■■■■■■■■■86%|ETA:1sCleaningdata■■■■■■■■■■■■■■■■■■■■■■■■■■■88%|ETA:1sCleaningdata■■■■■■■■■■■■■■■■■■■■■■■■■■■■89%|ETA:1sCleaningdata■■■■■■■■■■■■■■■■■■■■■■■■■■■■91%|ETA:1sCleaningdata■■■■■■■■■■■■■■■■■■■■■■■■■■■■■93%|ETA:0sCleaningdata■■■■■■■■■■■■■■■■■■■■■■■■■■■■■94%|ETA:0sCleaningdata■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■96%|ETA:0sCleaningdata■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■98%|ETA:0sCleaningdata■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■99%|ETA:0scli/man/figures/README/themes.svg0000644000175000017500000000305514143453131016337 0ustar nileshnileshThisisveryimportantBacktothepreviousthemecli/man/figures/README/plurals.svg0000644000175000017500000000250214143453131016530 0ustar nileshnileshFound3filesand1directory.cli/man/figures/README/glue.svg0000644000175000017500000000243014143453131016002 0ustar nileshnileshDownloaded123.14MBin1.3scli/man/figures/cli-text-markup.svg0000644000175000017500000000271114201142123017130 0ustar nileshnileshThe`cli_text()`functionintheclipackage.cli/man/figures/cli-dl.svg0000644000175000017500000000230314201001232015236 0ustar nileshnileshfoo:onebar:twobaz:threecli/man/figures/cnt-theme.svg0000644000175000017500000000213014201001232015754 0ustar nileshnileshCustomtitlecli/man/figures/box-label-align.svg0000644000175000017500000000543014201001231017032 0ustar nileshnilesh┌───────────┐there└───────────┘you!Hiyou!HiHicli/man/figures/format-error-2.svg0000644000175000017500000000406414201142123016663 0ustar nileshnileshError:Mustindexanexistingelement:Thereare26elements.You'vetriedtosubsetelement100.cli/man/figures/rule-colored-line.svg0000644000175000017500000000252114201001233017416 0ustar nileshnilesh────────────────────────────*RESULTS*───────────────────────────cli/man/figures/progress-var-elapsed-raw.svg0000644000175000017500000000227414201142123020742 0ustar nileshnilesh■■■■■■■■■■■■■■■■■■■■■66%[5s]cli/man/figures/rule-simple.svg0000644000175000017500000000227614201001233016342 0ustar nileshnilesh──────────────────────────────────────────────────────────────────────cli/man/figures/box-border.svg0000644000175000017500000000300114201001231016130 0ustar nileshnilesh╔══════════════════╗Hellothere!╚══════════════════╝cli/man/figures/alert-success.svg0000644000175000017500000000260614201001232016655 0ustar nileshnileshBuilt11statusreportsin5.6s.cli/man/figures/rule-bars.svg0000644000175000017500000000270214201001233015772 0ustar nileshnilesh▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅cli/man/figures/cli-h1.svg0000644000175000017500000000355714201001232015163 0ustar nileshnilesh──Header1────────────────────────────────────────────────────────────Header2────Header3cli/man/figures/progress-1.svg0000644000175000017500000007171214201142123016113 0ustar nileshnileshCleaningdata■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■100%|ETA:0sCleaningdata1%|ETA:5sCleaningdata■■3%|ETA:6sCleaningdata■■■5%|ETA:6sCleaningdata■■■6%|ETA:6sCleaningdata■■■8%|ETA:5sCleaningdata■■■■10%|ETA:5sCleaningdata■■■■■12%|ETA:5sCleaningdata■■■■■13%|ETA:5sCleaningdata■■■■■15%|ETA:5sCleaningdata■■■■■■17%|ETA:5sCleaningdata■■■■■■18%|ETA:5sCleaningdata■■■■■■■20%|ETA:5sCleaningdata■■■■■■■■22%|ETA:5sCleaningdata■■■■■■■■24%|ETA:4sCleaningdata■■■■■■■■■25%|ETA:4sCleaningdata■■■■■■■■■27%|ETA:4sCleaningdata■■■■■■■■■■29%|ETA:4sCleaningdata■■■■■■■■■■31%|ETA:4sCleaningdata■■■■■■■■■■■32%|ETA:4sCleaningdata■■■■■■■■■■■34%|ETA:4sCleaningdata■■■■■■■■■■■■36%|ETA:4sCleaningdata■■■■■■■■■■■■37%|ETA:4sCleaningdata■■■■■■■■■■■■■39%|ETA:4sCleaningdata■■■■■■■■■■■■■41%|ETA:3sCleaningdata■■■■■■■■■■■■■■43%|ETA:3sCleaningdata■■■■■■■■■■■■■■44%|ETA:3sCleaningdata■■■■■■■■■■■■■■■46%|ETA:3sCleaningdata■■■■■■■■■■■■■■■48%|ETA:3sCleaningdata■■■■■■■■■■■■■■■■49%|ETA:3sCleaningdata■■■■■■■■■■■■■■■■51%|ETA:3sCleaningdata■■■■■■■■■■■■■■■■■53%|ETA:3sCleaningdata■■■■■■■■■■■■■■■■■55%|ETA:3sCleaningdata■■■■■■■■■■■■■■■■■■56%|ETA:3sCleaningdata■■■■■■■■■■■■■■■■■■58%|ETA:2sCleaningdata■■■■■■■■■■■■■■■■■■■60%|ETA:2sCleaningdata■■■■■■■■■■■■■■■■■■■61%|ETA:2sCleaningdata■■■■■■■■■■■■■■■■■■■■63%|ETA:2sCleaningdata■■■■■■■■■■■■■■■■■■■■■65%|ETA:2sCleaningdata■■■■■■■■■■■■■■■■■■■■■67%|ETA:2sCleaningdata■■■■■■■■■■■■■■■■■■■■■68%|ETA:2sCleaningdata■■■■■■■■■■■■■■■■■■■■■■70%|ETA:2sCleaningdata■■■■■■■■■■■■■■■■■■■■■■■72%|ETA:2sCleaningdata■■■■■■■■■■■■■■■■■■■■■■■74%|ETA:2sCleaningdata■■■■■■■■■■■■■■■■■■■■■■■75%|ETA:1sCleaningdata■■■■■■■■■■■■■■■■■■■■■■■■77%|ETA:1sCleaningdata■■■■■■■■■■■■■■■■■■■■■■■■■79%|ETA:1sCleaningdata■■■■■■■■■■■■■■■■■■■■■■■■■81%|ETA:1sCleaningdata■■■■■■■■■■■■■■■■■■■■■■■■■■82%|ETA:1sCleaningdata■■■■■■■■■■■■■■■■■■■■■■■■■■84%|ETA:1sCleaningdata■■■■■■■■■■■■■■■■■■■■■■■■■■■86%|ETA:1sCleaningdata■■■■■■■■■■■■■■■■■■■■■■■■■■■87%|ETA:1sCleaningdata■■■■■■■■■■■■■■■■■■■■■■■■■■■■89%|ETA:1sCleaningdata■■■■■■■■■■■■■■■■■■■■■■■■■■■■91%|ETA:1sCleaningdata■■■■■■■■■■■■■■■■■■■■■■■■■■■■■93%|ETA:0sCleaningdata■■■■■■■■■■■■■■■■■■■■■■■■■■■■■94%|ETA:0sCleaningdata■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■96%|ETA:0sCleaningdata■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■98%|ETA:0scli/man/figures/alert-danger.svg0000644000175000017500000000271314201001232016444 0ustar nileshnileshCannotvalidateconfigfileat~/.config/report.yaml.cli/man/figures/cli-div-close.svg0000644000175000017500000000275614201001232016540 0ustar nileshnileshThisisyellowThisisnotyellowanymorecli/man/figures/cli-text.svg0000644000175000017500000000705114201001232015630 0ustar nileshnileshLoremadipsumveniamessenisideseruntduis.Quiincididuntelitelitmollitsintnullaconsecteturautecommododoelitlaborisminimet.Laborisipsummollitvoluptateetnondoincididunteiusmod.Animconsecteturmollitlaborumoccaecateiusmodexcepteur.Ullamconontemporesseanimtempormagnanon.cli/man/figures/cli-end.svg0000644000175000017500000000222214201001232015405 0ustar nileshnileshFirstparagraph.Secondparagraph.cli/man/figures/progress-var-current.svg0000644000175000017500000000221314201001233020205 0ustar nileshnileshReadingfile66/100cli/man/figures/inline-text-2.svg0000644000175000017500000000226114201001232016474 0ustar nileshnileshThisisgreat.cli/man/figures/cli-ol-2.svg0000644000175000017500000000237314201001232015417 0ustar nileshnilesh1.one2.two3.threecli/man/figures/progress-var-id.svg0000644000175000017500000000243514201142123017131 0ustar nileshnileshProgressbar'cli-43131-2849'isat64cli/man/figures/progress-var-eta.svg0000644000175000017500000000243714201142123017310 0ustar nileshnilesh■■■■■■■■■■■■■■■■■■■■■66%|ETA:3scli/man/figures/cli-cli.svg0000644000175000017500000000352714201001232015417 0ustar nileshnilesh──Title───────────────────────────────────────────────────────────────Subtitle──thisthatendcli/man/figures/progress-after.svg0000644000175000017500000003472414201142123017056 0ustar nileshnileshStartingnow,at2021-08-0213:27:27■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■100%@2021-08-0213:27:32■■■■■■■■■■■■■■■48%@2021-08-0213:27:29■■■■■■■■■■■■■■■■50%@2021-08-0213:27:29■■■■■■■■■■■■■■■■■52%@2021-08-0213:27:29■■■■■■■■■■■■■■■■■54%@2021-08-0213:27:29■■■■■■■■■■■■■■■■■■56%@2021-08-0213:27:30■■■■■■■■■■■■■■■■■■58%@2021-08-0213:27:30■■■■■■■■■■■■■■■■■■■61%@2021-08-0213:27:30■■■■■■■■■■■■■■■■■■■■63%@2021-08-0213:27:30■■■■■■■■■■■■■■■■■■■■■65%@2021-08-0213:27:30■■■■■■■■■■■■■■■■■■■■■67%@2021-08-0213:27:30■■■■■■■■■■■■■■■■■■■■■■70%@2021-08-0213:27:30■■■■■■■■■■■■■■■■■■■■■■■72%@2021-08-0213:27:30■■■■■■■■■■■■■■■■■■■■■■■74%@2021-08-0213:27:30■■■■■■■■■■■■■■■■■■■■■■■■76%@2021-08-0213:27:30■■■■■■■■■■■■■■■■■■■■■■■■78%@2021-08-0213:27:31■■■■■■■■■■■■■■■■■■■■■■■■■81%@2021-08-0213:27:31■■■■■■■■■■■■■■■■■■■■■■■■■■83%@2021-08-0213:27:31■■■■■■■■■■■■■■■■■■■■■■■■■■■85%@2021-08-0213:27:31■■■■■■■■■■■■■■■■■■■■■■■■■■■87%@2021-08-0213:27:31■■■■■■■■■■■■■■■■■■■■■■■■■■■■89%@2021-08-0213:27:31■■■■■■■■■■■■■■■■■■■■■■■■■■■■91%@2021-08-0213:27:31■■■■■■■■■■■■■■■■■■■■■■■■■■■■■94%@2021-08-0213:27:31■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■96%@2021-08-0213:27:31■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■98%@2021-08-0213:27:31cli/man/figures/box-bg-color.svg0000644000175000017500000000475114201142123016402 0ustar nileshnilesh┌──────────────────┐ └──────────────────┘ Hello there! Hello there! cli/man/figures/cnt-auto-close.svg0000644000175000017500000000275614201001232016743 0ustar nileshnileshThisisyellowThisisnotyellowanymorecli/man/figures/rule-center-label.svg0000644000175000017500000000252114201001233017377 0ustar nileshnilesh────────────────────────────*RESULTS*───────────────────────────cli/man/figures/cli-format-theme.svg0000644000175000017500000000276114201001232017237 0ustar nileshnilesh0.143,0.286,0.429,0.571,and0.714cli/man/figures/cli-vec-2.svg0000644000175000017500000000241714201001232015561 0ustar nileshnileshColumnnames:mpg,cyl,disp,….cli/man/figures/make-spinner-custom.svg0000644000175000017500000001210414201142123020000 0ustar nileshnileshDownloading.Downloading..Downloading...Downloading..Downloading.Downloadingcli/man/figures/tree-colored.svg0000644000175000017500000001161114201001233016461 0ustar nileshnileshrcmdcheck(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)cli/man/figures/make-spinner-default.svg0000644000175000017500000001764014201142123020124 0ustar nileshnileshcli/man/figures/progress-output.svg0000644000175000017500000006515614201142123017320 0ustar nileshnileshBeforetheprogressbarCalculating■■■■■■■■■■■■■■■■50%|ETA:2sAlreadyhalfway!Calculating■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■100%|ETA:0sAlldoneCalculating1%|ETA:4sCalculating■■3%|ETA:4sCalculating■■■6%|ETA:4sCalculating■■■8%|ETA:4sCalculating■■■■10%|ETA:4sCalculating■■■■■12%|ETA:4sCalculating■■■■■14%|ETA:4sCalculating■■■■■■16%|ETA:4sCalculating■■■■■■18%|ETA:4sCalculating■■■■■■■20%|ETA:4sCalculating■■■■■■■■22%|ETA:4sCalculating■■■■■■■■■25%|ETA:4sCalculating■■■■■■■■■27%|ETA:3sCalculating■■■■■■■■■■29%|ETA:3sCalculating■■■■■■■■■■31%|ETA:3sCalculating■■■■■■■■■■■33%|ETA:3sCalculating■■■■■■■■■■■35%|ETA:3sCalculating■■■■■■■■■■■■37%|ETA:3sCalculating■■■■■■■■■■■■■40%|ETA:3sCalculating■■■■■■■■■■■■■■42%|ETA:3sCalculating■■■■■■■■■■■■■■44%|ETA:3sCalculating■■■■■■■■■■■■■■■46%|ETA:3sCalculating■■■■■■■■■■■■■■■48%|ETA:2sCalculating■■■■■■■■■■■■■■■■■52%|ETA:2sCalculating■■■■■■■■■■■■■■■■■54%|ETA:2sCalculating■■■■■■■■■■■■■■■■■■57%|ETA:2sCalculating■■■■■■■■■■■■■■■■■■■59%|ETA:2sCalculating■■■■■■■■■■■■■■■■■■■61%|ETA:2sCalculating■■■■■■■■■■■■■■■■■■■■63%|ETA:2sCalculating■■■■■■■■■■■■■■■■■■■■■65%|ETA:2sCalculating■■■■■■■■■■■■■■■■■■■■■67%|ETA:2sCalculating■■■■■■■■■■■■■■■■■■■■■■70%|ETA:1sCalculating■■■■■■■■■■■■■■■■■■■■■■■72%|ETA:1sCalculating■■■■■■■■■■■■■■■■■■■■■■■74%|ETA:1sCalculating■■■■■■■■■■■■■■■■■■■■■■■■76%|ETA:1sCalculating■■■■■■■■■■■■■■■■■■■■■■■■78%|ETA:1sCalculating■■■■■■■■■■■■■■■■■■■■■■■■■80%|ETA:1sCalculating■■■■■■■■■■■■■■■■■■■■■■■■■■82%|ETA:1sCalculating■■■■■■■■■■■■■■■■■■■■■■■■■■84%|ETA:1sCalculating■■■■■■■■■■■■■■■■■■■■■■■■■■■87%|ETA:1sCalculating■■■■■■■■■■■■■■■■■■■■■■■■■■■■89%|ETA:1sCalculating■■■■■■■■■■■■■■■■■■■■■■■■■■■■91%|ETA:0sCalculating■■■■■■■■■■■■■■■■■■■■■■■■■■■■■93%|ETA:0sCalculating■■■■■■■■■■■■■■■■■■■■■■■■■■■■■95%|ETA:0sCalculating■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■98%|ETA:0scli/man/figures/rule-custom-line-2.svg0000644000175000017500000000230714201001233017442 0ustar nileshnilesh~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-TITLE~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~cli/man/figures/progress-step-msg.svg0000644000175000017500000001702314201142123017505 0ustar nileshnileshDownloadingdata.Downloadingdata.Downloadingdata.Downloadingdata.Downloadingdata.Downloadingdata.Downloadingdata.Downloadingdata.Downloadingdata.Downloadingdata.Downloaded819.20kB.[3.4s]cli/man/figures/progress-step.svg0000644000175000017500000001166714201142123016731 0ustar nileshnileshDownloadingdata[2s]Importingdata[1s]Cleaningdata[2s]Fittingmodel[3s]DownloadingdataImportingdataCleaningdataFittingmodelcli/man/figures/progress-var-name.svg0000644000175000017500000000244114201142123017452 0ustar nileshnileshLoadingtrainingdata■■■■■■■■■■■■■■■■■■■■■66%cli/man/figures/make-spinner-template.svg0000644000175000017500000002051514201142123020306 0ustar nileshnileshComputingComputingComputingComputingComputingComputingComputingComputingComputingComputingcli/man/figures/cli-format-default.svg0000644000175000017500000000253014201001232017553 0ustar nileshnilesh"January","February",and"March"cli/man/figures/progress-along-1.svg0000644000175000017500000005120014201142123017177 0ustar nileshnileshDownloading■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■100%|ETA:0sDownloading0%|ETA:?Downloading■■4%|ETA:4sDownloading■■■7%|ETA:4sDownloading■■■■9%|ETA:4sDownloading■■■■11%|ETA:4sDownloading■■■■■13%|ETA:4sDownloading■■■■■15%|ETA:4sDownloading■■■■■■18%|ETA:4sDownloading■■■■■■■20%|ETA:4sDownloading■■■■■■■■22%|ETA:4sDownloading■■■■■■■■24%|ETA:4sDownloading■■■■■■■■■26%|ETA:4sDownloading■■■■■■■■■28%|ETA:3sDownloading■■■■■■■■■■30%|ETA:3sDownloading■■■■■■■■■■■32%|ETA:3sDownloading■■■■■■■■■■■34%|ETA:3sDownloading■■■■■■■■■■■■37%|ETA:3sDownloading■■■■■■■■■■■■■39%|ETA:3sDownloading■■■■■■■■■■■■■41%|ETA:3sDownloading■■■■■■■■■■■■■■43%|ETA:3sDownloading■■■■■■■■■■■■■■■45%|ETA:3sDownloading■■■■■■■■■■■■■■■47%|ETA:3sDownloading■■■■■■■■■■■■■■■■49%|ETA:2sDownloading■■■■■■■■■■■■■■■■51%|ETA:2sDownloading■■■■■■■■■■■■■■■■■53%|ETA:2sDownloading■■■■■■■■■■■■■■■■■55%|ETA:2sDownloading■■■■■■■■■■■■■■■■■■58%|ETA:2sDownloading■■■■■■■■■■■■■■■■■■■60%|ETA:2sDownloading■■■■■■■■■■■■■■■■■■■■62%|ETA:2sDownloading■■■■■■■■■■■■■■■■■■■■64%|ETA:2sDownloading■■■■■■■■■■■■■■■■■■■■■66%|ETA:2sDownloading■■■■■■■■■■■■■■■■■■■■■■69%|ETA:1sDownloading■■■■■■■■■■■■■■■■■■■■■■71%|ETA:1sDownloading■■■■■■■■■■■■■■■■■■■■■■■73%|ETA:1sDownloading■■■■■■■■■■■■■■■■■■■■■■■75%|ETA:1sDownloading■■■■■■■■■■■■■■■■■■■■■■■■77%|ETA:1sDownloading■■■■■■■■■■■■■■■■■■■■■■■■■79%|ETA:1sDownloading■■■■■■■■■■■■■■■■■■■■■■■■■81%|ETA:1sDownloading■■■■■■■■■■■■■■■■■■■■■■■■■■83%|ETA:1sDownloading■■■■■■■■■■■■■■■■■■■■■■■■■■■85%|ETA:1sDownloading■■■■■■■■■■■■■■■■■■■■■■■■■■■87%|ETA:1sDownloading■■■■■■■■■■■■■■■■■■■■■■■■■■■■89%|ETA:1sDownloading■■■■■■■■■■■■■■■■■■■■■■■■■■■■■92%|ETA:0sDownloading■■■■■■■■■■■■■■■■■■■■■■■■■■■■■94%|ETA:0sDownloading■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■96%|ETA:0sDownloading■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■98%|ETA:0scli/man/figures/progress-var-status.svg0000644000175000017500000000245614201001233020057 0ustar nileshnileshConnecting...0done(0/s)|1scli/man/figures/cli-rule-line-type.svg0000644000175000017500000000256214201001232017521 0ustar nileshnilesh══Summary══════════════════════════════════════════════mypackage══cli/man/figures/inline-text.svg0000644000175000017500000000226514201001232016341 0ustar nileshnileshThisisimportant.cli/man/figures/progress-step-dynamic.svg0000644000175000017500000005533014201142123020346 0ustar nileshnileshDownloadingdata,gotfile100/100[2.4s]Importingdata[1s]Cleaningdata[2s]FittingmodelFittingmodelFittingmodelFittingmodelFittingmodelFittingmodelFittingmodelFittingmodelFittingmodelFittingmodelFittingmodel[3.4s]DownloadingdataDownloadingdata,gotfile1/100Downloadingdata,gotfile6/100Downloadingdata,gotfile10/100Downloadingdata,gotfile15/100Downloadingdata,gotfile19/100Downloadingdata,gotfile24/100Downloadingdata,gotfile28/100Downloadingdata,gotfile32/100Downloadingdata,gotfile37/100Downloadingdata,gotfile41/100Downloadingdata,gotfile45/100Downloadingdata,gotfile49/100Downloadingdata,gotfile53/100Downloadingdata,gotfile57/100Downloadingdata,gotfile62/100Downloadingdata,gotfile66/100Downloadingdata,gotfile70/100Downloadingdata,gotfile75/100Downloadingdata,gotfile79/100Downloadingdata,gotfile84/100Downloadingdata,gotfile88/100Downloadingdata,gotfile92/100Downloadingdata,gotfile96/100Downloadingdata,gotfile100/100ImportingdataCleaningdatacli/man/figures/cli-ol.svg0000644000175000017500000000230014201001232015246 0ustar nileshnilesh1.one2.two3.threecli/man/figures/cli-verbatim.svg0000644000175000017500000000213514201001232016453 0ustar nileshnileshThishasthreelines,cli/man/figures/cli-code.svg0000644000175000017500000000424414201001232015557 0ustar nileshnileshfunction(){message("Justanexamplefunction")graphics::pairs(iris,col=1:4)}cli/man/figures/inline-escape.svg0000644000175000017500000000306614201001232016615 0ustar nileshnilesh!Errorinif(ncol(dat$y)){:argumentisoflengthzerocli/man/figures/cli-text-glue-style.svg0000644000175000017500000000271114201142123017723 0ustar nileshnileshThe`cli-text()`functionintheclipackage.cli/man/figures/cli-bullets.svg0000644000175000017500000000342714201001231016320 0ustar nileshnileshnoindentindentbulletarrowsuccessdanger!warninginfocli/man/hash_md5.Rd0000644000175000017500000000245214200445676013720 0ustar nileshnilesh% 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} \title{MD5 hash} \usage{ hash_md5(x) hash_raw_md5(x) hash_obj_md5(x, serialize_version = 2) } \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()}}.} } \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. } \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_sha256}()} } \concept{hash functions} cli/man/simple_theme.Rd0000644000175000017500000000421214200476460014672 0ustar nileshnilesh% 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}{\figure{simple-theme.svg}} } \seealso{ \link{themes}, \code{\link[=builtin_theme]{builtin_theme()}}. } cli/man/ansi_substring.Rd0000644000175000017500000000342414143453131015251 0ustar nileshnilesh% 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/utf8_substr.Rd0000644000175000017500000000200714143453131014503 0ustar nileshnilesh% 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/src/0000755000175000017500000000000014201250465011741 5ustar nileshnileshcli/src/utf8.c0000644000175000017500000002365314143453131013004 0ustar nileshnilesh /* 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_EXTENDED_PICTOGRAPHIC: NEXT(); goto Extended_Pictographic; case GRAPH_BREAK_REGIONAL_INDICATOR: NEXT(); goto Regional_Indicator; case GRAPH_BREAK_EXTEND: 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; } Extended_Pictographic: // GB9: Do not break before extending characters while (iter->nxt_prop == GRAPH_BREAK_EXTEND) { 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: 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/charwidth.h0000644000175000017500000053161114143453131014076 0ustar nileshnilesh/* 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, 74, 75, 76, 77, 78, 79, 80, 81, /* U+3000 */ 82, 83, 84, 85, 86, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, /* U+3800 */ 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, /* U+4000 */ 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, /* U+4800 */ 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 87, 80, 80, 80, 80, /* U+5000 */ 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, /* U+5800 */ 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, /* U+6000 */ 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, /* U+6800 */ 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, /* U+7000 */ 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, /* U+7800 */ 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, /* U+8000 */ 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, /* U+8800 */ 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, /* U+9000 */ 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, /* U+9800 */ 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 88, /* U+A000 */ 80, 80, 80, 80, 80, 80, 80, 80, 80, 89, 35, 35, 90, 91, 35, 92, /* U+A800 */ 93, 94, 95, 96, 97, 98, 99,100, 80, 80, 80, 80, 80, 80, 80, 80, /* U+B000 */ 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, /* U+B800 */ 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, /* U+C000 */ 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, /* U+C800 */ 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, /* U+D000 */ 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80,101, /* U+D800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+E000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+E800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+F000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+F800 */102,102, 80, 80,103,104,105,106, 35, 35,107,108,109,110,111,112, /* U+10000 */113,114,115,116,102,117,118,119, 35,120,121,102, 35, 35,122,102, /* U+10800 */123,124,125,126,127,128,129,130,131,132,133,102,134,135,136,137, /* U+11000 */138,139,140,141,142,143,144,102,145,146,102,147,148,149,150,102, /* U+11800 */151,152,153,154,155,156,102,102,157,158,159,160,102,161,102,162, /* U+12000 */ 35, 35, 35, 35, 35, 35, 35,163,164, 35,165,102,102,102,102,102, /* U+12800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+13000 */ 35, 35, 35, 35, 35, 35, 35, 35,166,102,102,102,102,102,102,102, /* U+13800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+14000 */102,102,102,102,102,102,102,102, 35, 35, 35, 35,167,102,102,102, /* U+14800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+15000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+15800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+16000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+16800 */ 35, 35, 35, 35,168,169,170,171,102,102,102,102,172,173,174,175, /* U+17000 */ 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, /* U+17800 */ 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, /* U+18000 */ 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80,176, /* U+18800 */ 80, 80, 80, 80, 80, 80, 80, 80, 80,177,178,102,102,102,102,102, /* U+19000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+19800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+1A000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+1A800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+1B000 */ 80, 80,179, 80, 80,180,102,102,102,102,102,102,102,102,102,102, /* U+1B800 */102,102,102,102,102,102,102,102,181,182,102,102,102,102,102,102, /* U+1C000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+1C800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+1D000 */ 35,183,184,185,186,187,188,102,189,190,191, 35, 35,192, 35,193, /* U+1D800 */ 35, 35, 35, 35,194,195,102,102,102,102,102,102,102,102,102,102, /* U+1E000 */196,102,197,102,102,198,102,102,102,102,102,102,102,102,102,102, /* U+1E800 */ 35,199,200,102,102,102,102,102,201,202,203,102,204,205,102,102, /* U+1F000 */206,207,208,209,210,102,211,212,213,214,215,216,217,218,219,220, /* U+1F800 */221,222,223,224,225,226, 35,227,102,102,102,102,102,102,102,102, /* U+20000 */ 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, /* U+20800 */ 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, /* U+21000 */ 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, /* U+21800 */ 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, /* U+22000 */ 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, /* U+22800 */ 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, /* U+23000 */ 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, /* U+23800 */ 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, /* U+24000 */ 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, /* U+24800 */ 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, /* U+25000 */ 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, /* U+25800 */ 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, /* U+26000 */ 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, /* U+26800 */ 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, /* U+27000 */ 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, /* U+27800 */ 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, /* U+28000 */ 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, /* U+28800 */ 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, /* U+29000 */ 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, /* U+29800 */ 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, /* U+2A000 */ 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80,228, 80, 80, /* U+2A800 */ 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, /* U+2B000 */ 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80,229, 80, /* U+2B800 */230, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, /* U+2C000 */ 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, /* U+2C800 */ 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80,231, 80, 80, /* U+2D000 */ 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, /* U+2D800 */ 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, /* U+2E000 */ 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, /* U+2E800 */ 80, 80, 80, 80, 80, 80, 80,232,102,102,102,102,102,102,102,102, /* U+2F000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+2F800 */ 80, 80, 80, 80,233,102,102,102,102,102,102,102,102,102,102,102, /* U+30000 */ 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, /* U+30800 */ 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, /* U+31000 */ 80, 80, 80, 80, 80, 80,234,102,102,102,102,102,102,102,102,102, /* U+31800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+32000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+32800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+33000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+33800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+34000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+34800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+35000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+35800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+36000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+36800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+37000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+37800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+38000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+38800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+39000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+39800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+3A000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+3A800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+3B000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+3B800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+3C000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+3C800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+3D000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+3D800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+3E000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+3E800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+3F000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+3F800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+40000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+40800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+41000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+41800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+42000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+42800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+43000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+43800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+44000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+44800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+45000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+45800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+46000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+46800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+47000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+47800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+48000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+48800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+49000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+49800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+4A000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+4A800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+4B000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+4B800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+4C000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+4C800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+4D000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+4D800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+4E000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+4E800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+4F000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+4F800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+50000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+50800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+51000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+51800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+52000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+52800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+53000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+53800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+54000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+54800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+55000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+55800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+56000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+56800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+57000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+57800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+58000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+58800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+59000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+59800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+5A000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+5A800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+5B000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+5B800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+5C000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+5C800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+5D000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+5D800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+5E000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+5E800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+5F000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+5F800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+60000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+60800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+61000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+61800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+62000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+62800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+63000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+63800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+64000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+64800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+65000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+65800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+66000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+66800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+67000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+67800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+68000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+68800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+69000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+69800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+6A000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+6A800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+6B000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+6B800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+6C000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+6C800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+6D000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+6D800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+6E000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+6E800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+6F000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+6F800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+70000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+70800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+71000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+71800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+72000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+72800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+73000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+73800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+74000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+74800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+75000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+75800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+76000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+76800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+77000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+77800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+78000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+78800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+79000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+79800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+7A000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+7A800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+7B000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+7B800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+7C000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+7C800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+7D000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+7D800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+7E000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+7E800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+7F000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+7F800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+80000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+80800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+81000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+81800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+82000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+82800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+83000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+83800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+84000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+84800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+85000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+85800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+86000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+86800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+87000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+87800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+88000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+88800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+89000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+89800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+8A000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+8A800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+8B000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+8B800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+8C000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+8C800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+8D000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+8D800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+8E000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+8E800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+8F000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+8F800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+90000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+90800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+91000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+91800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+92000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+92800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+93000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+93800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+94000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+94800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+95000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+95800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+96000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+96800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+97000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+97800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+98000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+98800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+99000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+99800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+9A000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+9A800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+9B000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+9B800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+9C000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+9C800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+9D000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+9D800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+9E000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+9E800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+9F000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+9F800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+A0000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+A0800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+A1000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+A1800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+A2000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+A2800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+A3000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+A3800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+A4000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+A4800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+A5000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+A5800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+A6000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+A6800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+A7000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+A7800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+A8000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+A8800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+A9000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+A9800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+AA000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+AA800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+AB000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+AB800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+AC000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+AC800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+AD000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+AD800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+AE000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+AE800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+AF000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+AF800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+B0000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+B0800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+B1000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+B1800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+B2000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+B2800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+B3000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+B3800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+B4000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+B4800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+B5000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+B5800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+B6000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+B6800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+B7000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+B7800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+B8000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+B8800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+B9000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+B9800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+BA000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+BA800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+BB000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+BB800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+BC000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+BC800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+BD000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+BD800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+BE000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+BE800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+BF000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+BF800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+C0000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+C0800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+C1000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+C1800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+C2000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+C2800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+C3000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+C3800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+C4000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+C4800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+C5000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+C5800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+C6000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+C6800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+C7000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+C7800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+C8000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+C8800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+C9000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+C9800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+CA000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+CA800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+CB000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+CB800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+CC000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+CC800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+CD000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+CD800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+CE000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+CE800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+CF000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+CF800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+D0000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+D0800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+D1000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+D1800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+D2000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+D2800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+D3000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+D3800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+D4000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+D4800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+D5000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+D5800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+D6000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+D6800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+D7000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+D7800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+D8000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+D8800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+D9000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+D9800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+DA000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+DA800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+DB000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+DB800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+DC000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+DC800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+DD000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+DD800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+DE000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+DE800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+DF000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+DF800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+E0000 */235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, /* U+E0800 */235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, /* U+E1000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+E1800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+E2000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+E2800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+E3000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+E3800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+E4000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+E4800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+E5000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+E5800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+E6000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+E6800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+E7000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+E7800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+E8000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+E8800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+E9000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+E9800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+EA000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+EA800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+EB000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+EB800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+EC000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+EC800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+ED000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+ED800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+EE000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+EE800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+EF000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+EF800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+F0000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+F0800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+F1000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+F1800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+F2000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+F2800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+F3000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+F3800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+F4000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+F4800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+F5000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+F5800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+F6000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+F6800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+F7000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+F7800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+F8000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+F8800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+F9000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+F9800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+FA000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+FA800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+FB000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+FB800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+FC000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+FC800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+FD000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+FD800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+FE000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+FE800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+FF000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+FF800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+100000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+100800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+101000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+101800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+102000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+102800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+103000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+103800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+104000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+104800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+105000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+105800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+106000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+106800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+107000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+107800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+108000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+108800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+109000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+109800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+10A000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+10A800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+10B000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+10B800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+10C000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+10C800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+10D000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+10D800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+10E000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+10E800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+10F000 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, /* U+10F800 */102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102 }; 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, 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, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 17 */ { 0, 0, 0, 0, 0, 0, 0, 0, 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, 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, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 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, 0, 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, 0, 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, 0, 3, 0, 3, 3, 2, 2, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 0, 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, 0, 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, 0, 3, 3, 3, 3, 2, 2, 2, 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, 2, 2, 2, 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, 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, 3, 3, 3, 3, 3, 3, 3, 3, 3, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 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, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 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, 0, 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, 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, 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, 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, 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 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, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 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 76 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 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 77 */ { 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 78 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 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 }, /* 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, 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 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, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 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 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, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 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, 0, 0, 0, 0 }, /* 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, 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 83 */ { 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 84 */ { 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 85 */ { 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, 0, 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, 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 87 */ { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 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 88 */ { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 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 89 */ { 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 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, 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 91 */ { 3, 3, 3, 3, 3, 3, 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 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, 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, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, /* block 93 */ { 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 94 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 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 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, 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 96 */ { 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 97 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 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 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, 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 99 */ { 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 100 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 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 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, 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 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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 */ { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 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 104 */ { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 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 105 */ { 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 106 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 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, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 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 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, 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 }, /* block 108 */ { 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 0, 0 }, /* block 109 */ { 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 110 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 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 111 */ { 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 112 */ { 3, 3, 3, 3, 3, 3, 3, 3, 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 113 */ { 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 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, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 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 115 */ { 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 116 */ { 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 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, 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 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, 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 119 */ { 3, 3, 3, 3, 3, 3, 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 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, 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 121 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 122 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 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 123 */ { 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 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, 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 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, 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 126 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 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 127 */ { 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 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, 0, 0, 0, 0, 0, 0, 0, 0, 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 129 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 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 130 */ { 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 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, 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 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, 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 133 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 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 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, 0, 0, 0, 0, 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 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, 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, 0, 0, 0 }, /* block 136 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 137 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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 138 */ { 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2 }, /* block 139 */ { 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, 0, 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 140 */ { 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 141 */ { 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 142 */ { 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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 143 */ { 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 144 */ { 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 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, 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 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, 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 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, 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 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, 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 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, 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, 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 }, /* 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, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 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 152 */ { 0, 0, 0, 0, 0, 0, 0, 0, 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 153 */ { 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 154 */ { 0, 0, 0, 0, 0, 0, 0, 0, 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 155 */ { 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 156 */ { 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, 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, 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 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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 163 */ { 3, 3, 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 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, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 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 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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 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, 0, 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 }, /* block 167 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 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 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, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 169 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 0, 0, 2, 2, 2, 2, 2, 3, 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, 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 171 */ { 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 172 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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 173 */ { 3, 3, 3, 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 174 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 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 175 */ { 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 176 */ { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 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 177 */ { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 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 178 */ { 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 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 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, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 }, /* block 180 */ { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 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 181 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 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 182 */ { 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 183 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 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 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, 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 185 */ { 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, 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 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 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 187 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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 }, /* 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, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 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 189 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 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 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, 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 191 */ { 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 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, 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 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, 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 194 */ { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 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 195 */ { 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 196 */ { 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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 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, 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 198 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 3 }, /* block 199 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 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 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, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 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 201 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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 202 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 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 203 */ { 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 204 */ { 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 205 */ { 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 206 */ { 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 207 */ { 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 208 */ { 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 209 */ { 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 210 */ { 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 211 */ { 6, 6, 6, 6, 6, 6, 6, 6, 6, 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 212 */ { 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 213 */ { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 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 214 */ { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 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 215 */ { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 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 216 */ { 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 217 */ { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 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 218 */ { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 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, 0, 0, 0, 0, 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 219 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 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 }, /* block 220 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 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, 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 }, /* block 221 */ { 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 222 */ { 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 223 */ { 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, 0, 6, 6, 6, 6, 6, 6 }, /* block 224 */ { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 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, 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 }, /* block 225 */ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 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, 0, 0, 0, 6, 6, 6, 0, 0, 0, 0, 0 }, /* block 226 */ { 6, 6, 6, 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, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 6, 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, 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 }, /* block 227 */ { 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 228 */ { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 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 229 */ { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 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, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 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 230 */ { 5, 5, 5, 5, 5, 5, 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 231 */ { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 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 232 */ { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 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 }, /* block 233 */ { 5, 5, 5, 5, 5, 5, 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 234 */ { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 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 }, /* block 235 */ { 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/thread.c0000644000175000017500000000653514143453131013365 0ustar nileshnilesh #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; 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; } 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() { int ret = 0; /* 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() { 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() { 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/winfiles.c0000644000175000017500000000352314200445676013741 0ustar nileshnilesh #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/win-utf8.c0000644000175000017500000000140714143453131013570 0ustar nileshnilesh #include "cli.h" #include "errors.h" #include "cleancall.h" #include #ifdef WIN32 extern Rboolean EmitEmbeddedUTF8; #endif SEXP clic_get_embedded_utf8() { #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/winfiles.h0000644000175000017500000000014014200445676013736 0ustar nileshnilesh #ifndef R_WINFILES_H #define R_WINFILES_H int open_file(const char *path, int oflag); #endif cli/src/cleancall.h0000644000175000017500000000263614143453131014037 0ustar nileshnilesh#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(); // -------------------------------------------------------------------- // 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(); #endif cli/src/progress.c0000644000175000017500000002544614143453131013764 0ustar nileshnilesh #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() { 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() { 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() { 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 `", 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("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(28); 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); 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); 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() { 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) { PROTECT(bar); if (isNull(bar)) { UNPROTECT(1); return; } SEXP current = PROTECT(Rf_install("current")); if (set >= 0) { Rf_defineVar(current, PROTECT(ScalarReal(set)), bar); UNPROTECT(1); } else { double crnt = REAL(PROTECT(clic__find_var(bar, current)))[0]; if (inc != 0) { Rf_defineVar(current, PROTECT(ScalarReal(crnt + inc)), 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); UNPROTECT(2); } UNPROTECT(2); } cli/src/progress-altrep.c0000644000175000017500000001432214143453131015240 0ustar nileshnilesh #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() { return cli__timer; } SEXP clic_update_due() { /* 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/ansi.c0000644000175000017500000007544614201202051013043 0ustar nileshnilesh #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); } } /* ---------------------------------------------------------------------- */ #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; }; 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 == ';'); } #define EMIT(s) clic__buffer_push_str(buffer, "\033[" s "m") #define EMITS(s) clic__buffer_push_str(buffer, (s)) 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"); } /* Opening tags in reverse order ------------------------------------- */ 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__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; 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) == '[') { 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 { 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_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_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_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_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 keep_csi; }; #define EMITS1(s) do { \ if (first) { \ EMITS("buffer; struct cli_ansi_state *state = &data->state; char col[64]; int first = 1; /* Opening tags ------------------------------------------------------ */ 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(""); } 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_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_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 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_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) { 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]; clic__ansi_iterator( sx, /* cb_start = */ 0, has_any_cb_sgr, has_any_cb_csi, /* 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; }; 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_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) { 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]; clic__ansi_iterator( sx, strip_cb_start, strip_cb_sgr, strip_cb_csi, 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, nchar_text_cbs[ctype], nchar_cb_end, &data ); UNPROTECT(1); return result; } cli/src/sha256.c0000644000175000017500000002151414200445676013131 0ustar nileshnilesh /********************************************************************* * 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/diff.c0000644000175000017500000002404414143453131013021 0ustar nileshnilesh/* 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/src/errors.c0000644000175000017500000000415514143453131013426 0ustar nileshnilesh #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 %d, %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/graphbreak.h0000644000175000017500000036762414143453131014242 0ustar nileshnilesh/* 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 = 3, GRAPH_BREAK_EXTENDED_PICTOGRAPHIC = 4, GRAPH_BREAK_L = 5, GRAPH_BREAK_LF = 6, GRAPH_BREAK_LV = 7, GRAPH_BREAK_LVT = 8, GRAPH_BREAK_PREPEND = 9, GRAPH_BREAK_REGIONAL_INDICATOR = 10, GRAPH_BREAK_SPACINGMARK = 11, GRAPH_BREAK_T = 12, GRAPH_BREAK_V = 13, GRAPH_BREAK_ZWJ = 14 }; 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, 2, /* U+11000 */ 92, 93, 94, 95, 96, 97, 98, 2, 99,100, 2,101,102,103,104, 2, /* U+11800 */105, 2,106,107,108,109, 2, 2,110,111,112,113, 2,114, 2, 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,115, 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,116,117, 2, 2, 2, 2, 2, 2, 2,118,119, /* 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,120, 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, 2, 2, /* U+1D000 */ 2, 2,121,122,123, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+1D800 */ 2, 2, 2, 2,124,125, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+1E000 */126, 2,117, 2, 2,127, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+1E800 */ 2,128,129, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* U+1F000 */130,130,131,132,133,130,130,134,130,130,135,130,136,130,137,138, /* U+1F800 */139,140,141,130,130,130, 2, 2,130,130,130,130,130,130,130,142, /* 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 */143,144,145,146,144,144,144,144,144,144,144,144,144,144,144,144, /* U+E0800 */144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144, /* 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, 6, 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, 4, 0, 0, 0, 2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 3, 3, 3, 3, 3, 3, 3, 3, 3, 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, 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 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 */ { 9, 9, 9, 9, 9, 9, 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, 9, 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, 9, 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, 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, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 9, 3, 3, 3, 3, 3, 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 */ { 3, 3, 3, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 11, 3, 0, 11, 11, 11, 3, 3, 3, 3, 3, 3, 3, 3, 11, 11, 11, 11, 3, 11, 11, 0, 3, 3, 3, 3, 3, 3, 3, 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 }, /* block 13 */ { 0, 3, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 11, 11, 3, 3, 3, 3, 0, 0, 11, 11, 0, 0, 11, 11, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 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, 3, 0 }, /* block 14 */ { 0, 3, 3, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 11, 11, 11, 3, 3, 0, 0, 0, 0, 3, 3, 0, 0, 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, 3, 3, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 15 */ { 0, 3, 3, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 11, 11, 11, 3, 3, 3, 3, 3, 0, 3, 3, 11, 0, 11, 11, 3, 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, 3, 3, 3, 3, 3, 3 }, /* block 16 */ { 0, 3, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 11, 3, 3, 3, 3, 0, 0, 11, 11, 0, 0, 11, 11, 3, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 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 }, /* block 17 */ { 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, 3, 11, 3, 11, 11, 0, 0, 0, 11, 11, 11, 0, 11, 11, 11, 3, 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 }, /* block 18 */ { 3, 11, 11, 11, 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, 3, 3, 3, 11, 11, 11, 11, 0, 3, 3, 3, 0, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 3, 3, 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 }, /* block 19 */ { 0, 3, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 11, 3, 11, 11, 3, 11, 11, 0, 3, 11, 11, 0, 11, 11, 3, 3, 0, 0, 0, 0, 0, 0, 0, 3, 3, 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 }, /* block 20 */ { 3, 3, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 3, 11, 11, 3, 3, 3, 3, 0, 11, 11, 11, 0, 11, 11, 11, 3, 9, 0, 0, 0, 0, 0, 0, 0, 0, 3, 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 }, /* block 21 */ { 0, 3, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 3, 11, 11, 3, 3, 3, 0, 3, 0, 11, 11, 11, 11, 11, 11, 11, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 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, 3, 0, 11, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 3, 0, 11, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 11 }, /* block 25 */ { 3, 3, 3, 3, 3, 0, 3, 3, 0, 0, 0, 0, 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, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 3, 3, 3, 3, 11, 3, 3, 3, 3, 3, 3, 0, 3, 3, 11, 11, 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, 11, 11, 3, 3, 0, 0, 0, 0, 3, 3, 3, 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 }, /* block 27 */ { 0, 0, 3, 0, 11, 3, 3, 0, 0, 0, 0, 0, 0, 3, 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 }, /* block 28 */ { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 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, 13, 13, 13, 13, 13, 13 }, /* block 29 */ { 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, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12 }, /* 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, 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, 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, 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, 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, 3, 3, 11, 3, 3, 3, 3, 3, 3, 3, 11, 11, 11, 11, 11, 11, 11, 11, 3, 11, 11, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 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, 3, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 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, 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, 3, 3, 3, 11, 11, 11, 11, 3, 3, 11, 11, 11, 0, 0, 0, 0, 11, 11, 3, 11, 11, 11, 11, 11, 11, 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, 11, 11, 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, 11, 3, 11, 3, 3, 3, 3, 3, 3, 3, 0, 3, 0, 3, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 11, 11, 11, 11, 11, 11, 3, 3, 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, 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 }, /* block 38 */ { 3, 3, 3, 3, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 11, 3, 11, 11, 11, 11, 11, 3, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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 */ { 3, 3, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 3, 3, 3, 3, 11, 11, 3, 3, 11, 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, 3, 11, 3, 3, 11, 11, 11, 3, 11, 3, 3, 3, 11, 11, 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, 11, 11, 11, 11, 11, 11, 11, 11, 3, 3, 3, 3, 3, 3, 3, 3, 11, 11, 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 }, /* 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, 11, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 3, 0, 0, 11, 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, 0, 3, 3, 3, 3, 3 }, /* block 43 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 14, 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, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 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, 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 }, /* 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, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 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, 0, 0, 0, 0, 4, 4, 4, 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, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 0 }, /* block 51 */ { 4, 4, 4, 4, 4, 4, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 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, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 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 52 */ { 4, 4, 4, 4, 4, 4, 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, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 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 53 */ { 4, 4, 4, 4, 4, 4, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 4, 0, 4, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 4, 0, 0, 0, 0, 4, 0, 4, 0, 0, 0, 0, 4, 4, 4, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 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, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 4, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 3, 3, 3, 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, 3, 0, 0, 0, 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, 11, 11, 3, 3, 11, 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 */ { 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 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, 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 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, 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, 11, 11, 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, 0, 0, 0 }, /* block 68 */ { 3, 3, 3, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 11, 11, 3, 3, 3, 3, 11, 11, 3, 3, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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 }, /* 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, 3, 3, 3, 3, 3, 3, 11, 11, 3, 3, 11, 11, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 3, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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 }, /* 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, 11, 3, 3, 11, 11, 0, 0, 0, 0, 0, 11, 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, 11, 11, 3, 11, 11, 3, 11, 11, 0, 11, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 72 */ { 7, 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, 7, 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, 7, 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, 7, 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, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 }, /* block 73 */ { 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 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, 7, 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, 7, 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, 7, 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, 7, 8, 8, 8 }, /* block 74 */ { 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 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, 7, 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, 7, 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, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 }, /* block 75 */ { 8, 8, 8, 8, 8, 8, 8, 8, 7, 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, 7, 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, 7, 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, 7, 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, 7, 8, 8, 8, 8, 8, 8, 8 }, /* block 76 */ { 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 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, 7, 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, 7, 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, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 }, /* block 77 */ { 8, 8, 8, 8, 7, 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, 7, 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, 7, 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, 7, 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, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 }, /* block 78 */ { 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 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, 7, 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, 7, 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, 7, 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 }, /* block 79 */ { 8, 8, 8, 8, 8, 8, 8, 8, 7, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 0, 0, 0, 0, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 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 */ { 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 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, 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, 3, 3, 3, 0, 3, 3, 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, 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, 0, 0, 0 }, /* 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 */ { 11, 3, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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 93 */ { 3, 3, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 11, 3, 3, 3, 3, 11, 11, 3, 3, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 94 */ { 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, 3, 3, 3, 3, 3, 11, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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 95 */ { 3, 3, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 11, 3, 3, 3, 3, 3, 3, 3, 3, 3, 11, 11, 0, 9, 9, 0, 0, 0, 0, 0, 3, 3, 3, 3, 0, 11, 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 96 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 11, 3, 3, 3, 11, 11, 3, 11, 3, 3, 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 }, /* 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 11, 11, 11, 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 98 */ { 3, 3, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 3, 11, 3, 11, 11, 11, 11, 0, 0, 11, 11, 0, 0, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 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 99 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 11, 3, 3, 3, 3, 3, 3, 3, 3, 11, 11, 3, 3, 3, 11, 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 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, 3, 11, 11, 3, 3, 3, 3, 3, 3, 11, 3, 11, 11, 3, 11, 3, 3, 11, 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 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, 3, 11, 11, 3, 3, 3, 3, 0, 0, 11, 11, 11, 11, 3, 3, 11, 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, 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 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, 0, 11, 11, 11, 3, 3, 3, 3, 3, 3, 3, 3, 11, 11, 3, 11, 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 }, /* 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, 3, 11, 3, 11, 11, 3, 3, 3, 3, 3, 3, 11, 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 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, 3, 3, 3, 11, 11, 3, 3, 3, 3, 11, 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 }, /* 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 11, 3, 3, 3, 3, 3, 3, 3, 3, 3, 11, 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 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, 0, 0, 0, 0, 3, 11, 11, 11, 11, 11, 0, 11, 11, 0, 0, 3, 3, 11, 3, 9, 11, 9, 11, 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 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 11, 3, 3, 3, 3, 0, 0, 3, 3, 11, 11, 11, 11, 3, 0, 0, 0, 11, 0, 0, 0, 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, 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, 3, 3, 3, 3, 3, 3, 11, 9, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 11, 11, 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 109 */ { 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 11, 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 110 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 11, 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 111 */ { 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, 0, 11, 3, 3, 3, 3, 3, 3, 3, 11, 3, 3, 11, 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 112 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 0, 0, 0, 3, 0, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 9, 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 113 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 11, 11, 11, 0, 3, 3, 0, 11, 11, 3, 11, 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 114 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 11, 11, 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, 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 }, /* block 116 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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 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, 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 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, 3, 0, 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, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11 }, /* block 119 */ { 11, 11, 11, 11, 11, 11, 11, 11, 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, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 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, 3, 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 121 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 11, 3, 3, 3, 0, 0, 0, 11, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3 }, /* block 122 */ { 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 123 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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 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, 3, 3, 3, 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, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* block 125 */ { 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, 3, 3, 3, 3, 3, 0, 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 126 */ { 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 127 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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 128 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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 129 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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 130 */ { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 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 131 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4 }, /* block 132 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 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, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10 }, /* block 133 */ { 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 4, 4, 4, 4, 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, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 }, /* block 134 */ { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 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 }, /* block 135 */ { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 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, 4, 4, 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 136 */ { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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 137 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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 }, /* block 138 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 }, /* block 139 */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 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 140 */ { 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 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 141 */ { 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, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 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, 4, 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 142 */ { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0 }, /* block 143 */ { 2, 2, 2, 2, 2, 2, 2, 2, 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, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 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 144 */ { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 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 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, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 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 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, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 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 } }; 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/md5.c0000644000175000017500000000267514200445676012615 0ustar nileshnilesh #include #include #define MD5_STATIC static #include "md5.h" #include "errors.h" #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 )); } cli/src/tty.c0000644000175000017500000000226314143453131012730 0ustar nileshnilesh #include "cli.h" #include "errors.h" #include "cleancall.h" #ifdef WIN32 #include #else #include #include #include #include #endif SEXP clic_tty_size() { 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/cleancall.c0000644000175000017500000001026314143453131014025 0ustar nileshnilesh#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/src/cli.h0000644000175000017500000000741114200445676012675 0ustar nileshnilesh #ifndef CLI_H #define CLI_H #include #include #include #include SEXP clic_diff_chr(SEXP a, SEXP b, SEXP max); SEXP clic_md5(SEXP strs); SEXP clic_md5_raw(SEXP r); SEXP clic_sha256(SEXP strs); SEXP clic_sha256_raw(SEXP r); SEXP clic_sha256_file(SEXP paths); SEXP clic_tty_size(); 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 clic_ansi_strip(SEXP x, SEXP sgr, SEXP csi); 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 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(); SEXP clic__find_var(SEXP rho, SEXP symbol); SEXP clic_start_thread(SEXP pkgenv, SEXP tick, SEXP speed); SEXP clic_stop_thread(); SEXP clic_tick_reset(); SEXP clic_get_time(); SEXP clic_tick_set(SEXP ticktime, SEXP speedtime); SEXP clic_tick_pause(SEXP state); SEXP clic_tick_resume(SEXP state); SEXP clic_make_timer(); SEXP clic_update_due(); /** 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(); 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); #endif cli/src/errors.h0000644000175000017500000001301114143453131013422 0ustar nileshnilesh /* 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/init.c0000644000175000017500000000646514200445676013074 0ustar nileshnilesh #include "cli.h" #include "cleancall.h" #include #include SEXP clic_unload() { clic_stop_thread(); return R_NilValue; } SEXP clic_dataptr(SEXP x); #ifdef GCOV_COMPILE void __gcov_flush(); SEXP clic__gcov_flush() { REprintf("Flushing coverage info\n"); __gcov_flush(); return R_NilValue; } #else SEXP clic__gcov_flush() { return R_NilValue; } #endif static const R_CallMethodDef callMethods[] = { CLEANCALL_METHOD_RECORD, { "clic_diff_chr", (DL_FUNC) clic_diff_chr, 3 }, { "clic_md5", (DL_FUNC) clic_md5, 1 }, { "clic_md5_raw", (DL_FUNC) clic_md5_raw, 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_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, 3 }, { "clic_ansi_strip", (DL_FUNC) clic_ansi_strip, 3 }, { "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 }, { NULL, NULL, 0 } }; #define RCC(fun) R_RegisterCCallable("cli", # fun, (DL_FUNC) fun); 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/md5.h0000644000175000017500000003632114143453131012604 0ustar nileshnilesh/* * 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/tools/0000755000175000017500000000000014143453131012312 5ustar nileshnileshcli/tools/unicode.R0000644000175000017500000000153414143453131014066 0ustar nileshnilesh# 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.itermcolors0000644000175000017500000002026714143453131016075 0ustar nileshnilesh 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.itermcolors0000644000175000017500000002010514143453131016623 0ustar nileshnilesh 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/smoooooth.itermcolors0000644000175000017500000002014414143453131016625 0ustar nileshnilesh 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/get-rstudio-themes.R0000644000175000017500000001503114143453131016166 0ustar nileshnilesh 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/dark.itermcolors0000644000175000017500000001777114143453131015534 0ustar nileshnilesh 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.R0000644000175000017500000000361014143453131014665 0ustar nileshnilesh 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/ansi-palettes.txt0000644000175000017500000000314714143453131015631 0ustar nileshnilesh 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/snazzy.itermcolors0000644000175000017500000002043314143453131016136 0ustar nileshnilesh 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.itermcolors0000644000175000017500000002056614143453131016323 0ustar nileshnilesh Ansi 0 Color Alpha Component 1 Blue Component 0.25882354378700256 Color Space sRGB Green Component 0.21176470816135406 Red Component 0.027450980618596077 Ansi 1 Color Alpha Component 1 Blue Component 0.18431372940540314 Color Space sRGB Green Component 0.19607843458652496 Red Component 0.86274510622024536 Ansi 10 Color Alpha Component 1 Blue Component 0.45882353186607361 Color Space sRGB Green Component 0.43137255311012268 Red Component 0.34509804844856262 Ansi 11 Color Alpha Component 1 Blue Component 0.51372551918029785 Color Space sRGB Green Component 0.48235294222831726 Red Component 0.3960784375667572 Ansi 12 Color Alpha Component 1 Blue Component 0.58823531866073608 Color Space sRGB Green Component 0.58039218187332153 Red Component 0.51372551918029785 Ansi 13 Color Alpha Component 1 Blue Component 0.76862746477127075 Color Space sRGB Green Component 0.44313725829124451 Red Component 0.42352941632270813 Ansi 14 Color Alpha Component 1 Blue Component 0.63137257099151611 Color Space sRGB Green Component 0.63137257099151611 Red Component 0.57647061347961426 Ansi 15 Color Alpha Component 1 Blue Component 0.89019608497619629 Color Space sRGB Green Component 0.96470588445663452 Red Component 0.99215686321258545 Ansi 2 Color Alpha Component 1 Blue Component 0.0 Color Space sRGB Green Component 0.60000002384185791 Red Component 0.5215686559677124 Ansi 3 Color Alpha Component 1 Blue Component 0.0 Color Space sRGB Green Component 0.5372549295425415 Red Component 0.70980393886566162 Ansi 4 Color Alpha Component 1 Blue Component 0.82352942228317261 Color Space sRGB Green Component 0.54509806632995605 Red Component 0.14901961386203766 Ansi 5 Color Alpha Component 1 Blue Component 0.50980395078659058 Color Space sRGB Green Component 0.21176470816135406 Red Component 0.82745099067687988 Ansi 6 Color Alpha Component 1 Blue Component 0.59607845544815063 Color Space sRGB Green Component 0.63137257099151611 Red Component 0.16470588743686676 Ansi 7 Color Alpha Component 1 Blue Component 0.83529412746429443 Color Space sRGB Green Component 0.90980392694473267 Red Component 0.93333333730697632 Ansi 8 Color Alpha Component 1 Blue Component 0.21176470816135406 Color Space sRGB Green Component 0.16862745583057404 Red Component 0.0 Ansi 9 Color Alpha Component 1 Blue Component 0.086274512112140656 Color Space sRGB Green Component 0.29411765933036804 Red Component 0.79607844352722168 Background Color Alpha Component 1 Blue Component 0.21176470816135406 Color Space sRGB Green Component 0.16862745583057404 Red Component 0.0 Badge Color Alpha Component 0.5 Blue Component 0.0 Color Space sRGB Green Component 0.1491314172744751 Red Component 1 Bold Color Alpha Component 1 Blue Component 0.63137257099151611 Color Space sRGB Green Component 0.63137257099151611 Red Component 0.57647061347961426 Cursor Color Alpha Component 1 Blue Component 0.58823531866073608 Color Space sRGB Green Component 0.58039218187332153 Red Component 0.51372551918029785 Cursor Guide Color Alpha Component 0.25 Blue Component 1 Color Space sRGB Green Component 0.9268307089805603 Red Component 0.70213186740875244 Cursor Text Color Alpha Component 1 Blue Component 0.25882354378700256 Color Space sRGB Green Component 0.21176470816135406 Red Component 0.027450980618596077 Foreground Color Alpha Component 1 Blue Component 0.58823531866073608 Color Space sRGB Green Component 0.58039218187332153 Red Component 0.51372551918029785 Link Color Alpha Component 1 Blue Component 0.73423302173614502 Color Space sRGB Green Component 0.35916060209274292 Red Component 0.0 Selected Text Color Alpha Component 1 Blue Component 0.63137257099151611 Color Space sRGB Green Component 0.63137257099151611 Red Component 0.57647061347961426 Selection Color Alpha Component 1 Blue Component 0.25882354378700256 Color Space sRGB Green Component 0.21176470816135406 Red Component 0.027450980618596077 cli/tools/light.itermcolors0000644000175000017500000001763314143453131015717 0ustar nileshnilesh Ansi 0 Color Alpha Component 1 Blue Component 0.0 Color Space sRGB Green Component 0.0 Red Component 0.0 Ansi 1 Color Alpha Component 1 Blue Component 0.0 Color Space sRGB Green Component 0.10676553100347519 Red Component 0.789775550365448 Ansi 10 Color Alpha Component 1 Blue Component 0.40609359741210938 Color Space sRGB Green Component 0.98006147146224976 Red Component 0.37424531579017639 Ansi 11 Color Alpha Component 1 Blue Component 0.40395939350128174 Color Space sRGB Green Component 0.98757272958755493 Red Component 0.99950331449508667 Ansi 12 Color Alpha Component 1 Blue Component 1 Color Space sRGB Green Component 0.44485551118850708 Red Component 0.40937519073486328 Ansi 13 Color Alpha Component 1 Blue Component 1 Color Space sRGB Green Component 0.46518981456756592 Red Component 1 Ansi 14 Color Alpha Component 1 Blue Component 1 Color Space sRGB Green Component 0.99263292551040649 Red Component 0.37597531080245972 Ansi 15 Color Alpha Component 1 Blue Component 1 Color Space sRGB Green Component 1 Red Component 0.99999600648880005 Ansi 2 Color Alpha Component 1 Blue Component 0.0 Color Space sRGB Green Component 0.76266151666641235 Red Component 0.0 Ansi 3 Color Alpha Component 1 Blue Component 0.0 Color Space sRGB Green Component 0.76959484815597534 Red Component 0.78058648109436035 Ansi 4 Color Alpha Component 1 Blue Component 0.78216177225112915 Color Space sRGB Green Component 0.14576995372772217 Red Component 0.0096152340993285179 Ansi 5 Color Alpha Component 1 Blue Component 0.78154844045639038 Color Space sRGB Green Component 0.18891248106956482 Red Component 0.79022186994552612 Ansi 6 Color Alpha Component 1 Blue Component 0.78166204690933228 Color Space sRGB Green Component 0.77425903081893921 Red Component 0.0 Ansi 7 Color Alpha Component 1 Blue Component 0.78104829788208008 Color Space sRGB Green Component 0.78105825185775757 Red Component 0.7810397744178772 Ansi 8 Color Alpha Component 1 Blue Component 0.4078223705291748 Color Space sRGB Green Component 0.40782788395881653 Red Component 0.40781760215759277 Ansi 9 Color Alpha Component 1 Blue Component 0.40569943189620972 Color Space sRGB Green Component 0.43035173416137695 Red Component 1 Background Color Alpha Component 1 Blue Component 1 Color Space sRGB Green Component 1 Red Component 0.99999600648880005 Badge Color Alpha Component 0.5 Blue Component 0.0 Color Space sRGB Green Component 0.1491314172744751 Red Component 1 Bold Color Alpha Component 1 Blue Component 0.0 Color Space sRGB Green Component 0.0 Red Component 0.0 Cursor Color Alpha Component 1 Blue Component 0.0 Color Space sRGB Green Component 0.0 Red Component 0.0 Cursor Guide Color Alpha Component 0.25 Blue Component 1 Color Space sRGB Green Component 0.9268307089805603 Red Component 0.70213186740875244 Cursor Text Color Alpha Component 1 Blue Component 1 Color Space sRGB Green Component 1 Red Component 0.99999600648880005 Foreground Color Alpha Component 1 Blue Component 0.0 Color Space sRGB Green Component 0.0 Red Component 0.0 Link Color Alpha Component 1 Blue Component 0.73423302173614502 Color Space sRGB Green Component 0.35916060209274292 Red Component 0.0 Selected Text Color Alpha Component 1 Blue Component 0.0 Color Space sRGB Green Component 0.0 Red Component 0.0 Selection Color Alpha Component 1 Blue Component 1 Color Space sRGB Green Component 0.86970102787017822 Red Component 0.75813239812850952 cli/tools/ansi-iterm-palettes.txt0000644000175000017500000000170214143453131016742 0ustar nileshnileshblack 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/tango-light.itermcolors0000644000175000017500000002007114143453131017013 0ustar nileshnilesh 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/sol-light.itermcolors0000644000175000017500000002060214143453131016500 0ustar nileshnilesh 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/tests/0000755000175000017500000000000014143453131012314 5ustar nileshnileshcli/tests/testthat/0000755000175000017500000000000014202425203014147 5ustar nileshnileshcli/tests/testthat/test-ansiex.R0000644000175000017500000004171214201202127016540 0ustar nileshnilesh 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_error( ansi_substr("foobar", NULL, 10), "invalid substring arguments" ) expect_error( ansi_substr("foobar", 10, NULL), "invalid substring arguments" ) }) 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' suppressWarnings( expect_error(ansi_substr("abc", "hello", 1), "non-numeric") ) }) 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_error( ansi_strsplit(c("ab", "bd"), c("b", "d")), "must be character" ) 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", { skip("Temporarily defunct") 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"))) ) 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_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-rlang-errors.R0000644000175000017500000001104314200476424017674 0ustar nileshnilesh test_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}." )) })) len <- 26 idx <- 100 wrn <- tryCatch( cli_warn(c( "Must index an existing element:", "i" = "There {?is/are} {len} element{?s}.", "x" = "You've tried to subset element {idx}." )), warning = function(w) w ) expect_snapshot(wrn$cli_bullets) }) 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}." )) })) len <- 26 idx <- 100 # This is weirder because cli_inform emits another cli message first inf <- NULL withCallingHandlers( cli_inform(c( "Must index an existing element:", "i" = "There {?is/are} {len} element{?s}.", "x" = "You've tried to subset element {idx}." )), message = function(m) { inf <<- c(inf, list(m)) invokeRestart("muffleMessage") } ) expect_snapshot(tail(inf, 1)[[1]]$cli_bullets) }) 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")) 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, "rstudioapi::getThemeInfo", 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, "rstudioapi::getThemeInfo", 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", { 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())) }) 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()))) }) }) cli/tests/testthat/test-boxes.R0000644000175000017500000000357614143453131016407 0ustar nileshnilesh 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-diff.R0000644000175000017500000000445414143453131016173 0ustar nileshnilesh 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", { err <- tryCatch( diff_chr("a", c("a", "b"), 0), error = function(e) e ) expect_s3_class(err, "cli_diff_max_dist") expect_silent(diff_chr(c("a", "c"), c("a", "b"), 2)) err <- tryCatch( diff_chr(c("a", "c"), c("a", "b"), 1), error = function(e) e ) expect_s3_class(err, "cli_diff_max_dist") }) cli/tests/testthat/test-inline-2.R0000644000175000017500000000576114200746513016705 0ustar nileshnilesh 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) local_rng_version("3.3.0") set.seed(42) expect_snapshot({ 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}}")) }) cli/tests/testthat/test-ansiex-2.R0000644000175000017500000002503514143453131016707 0ustar nileshnilesh 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" )) ) }) cli/tests/testthat/test-progress-c.R0000644000175000017500000001025214143453131017340 0ustar nileshnilesh 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-progress-handler-say.R0000644000175000017500000000137314143453131021331 0ustar nileshnilesh 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-progress-utils.R0000644000175000017500000000205114143453131020254 0ustar nileshnilesh 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-spark.R0000644000175000017500000000044714143453131016401 0ustar nileshnilesh 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-progress-client.R0000644000175000017500000001170014172272425020402 0ustar nileshnilesh 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", { if (packageVersion("testthat") <= "3.1.1") skip("needs newer testthat") 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/test-progress-variables.R0000644000175000017500000002054414143453131021073 0ustar nileshnilesh 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-glue.R0000644000175000017500000000122414201176501016205 0ustar nileshnilesh # 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}") }) }) cli/tests/testthat/test-substitution.R0000644000175000017500000000026014143453131020026 0ustar nileshnilesh 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-utf8.R0000644000175000017500000000445214143453131016147 0ustar nileshnilesh # 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() 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) }) cli/tests/testthat/test-num-ansi-colors.R0000644000175000017500000001142514200721320020275 0ustar nileshnileshtest_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.R0000644000175000017500000000374614201201243016206 0ustar nileshnilesh 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") }) cli/tests/testthat/test-ansi-combine.R0000644000175000017500000000175014143453131017623 0ustar nileshnilesh 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/progress-2.c0000644000175000017500000000046514143453131016330 0ustar nileshnilesh #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-spinners.R0000644000175000017500000000046714143453131017124 0ustar nileshnilesh 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/progresstestcpp/0000755000175000017500000000000014143453131017423 5ustar nileshnileshcli/tests/testthat/progresstestcpp/DESCRIPTION0000644000175000017500000000053514143453131021134 0ustar nileshnileshPackage: 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/0000755000175000017500000000000014143453131020212 5ustar nileshnileshcli/tests/testthat/progresstestcpp/src/cpp11.cpp0000644000175000017500000000234714143453131021650 0ustar nileshnilesh// 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/src/testcpp.cpp0000644000175000017500000000150614143453131022402 0ustar nileshnilesh #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/R/0000755000175000017500000000000014143453131017624 5ustar nileshnileshcli/tests/testthat/progresstestcpp/R/testcpp.R0000644000175000017500000000036014143453131021430 0ustar nileshnilesh #' @useDynLib progresstestcpp, .registration = TRUE NULL #' @export test_baseline <- function() { test_baseline_() } #' @export test_cli <- function() { test_cli_() } #' @export test_template <- function() { test_template_() } cli/tests/testthat/progresstestcpp/R/cpp11.R0000644000175000017500000000040714143453131020674 0ustar nileshnilesh# 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/NAMESPACE0000644000175000017500000000023414143453131020641 0ustar nileshnilesh# Generated by roxygen2: do not edit by hand export(test_baseline) export(test_cli) export(test_template) useDynLib(progresstestcpp, .registration = TRUE) cli/tests/testthat/test-progress-along.R0000644000175000017500000000723514143453131020225 0ustar nileshnilesh 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())) }) 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-cliapp-output.R0000644000175000017500000001032314143453131020061 0ustar nileshnilesh 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-sitrep.R0000644000175000017500000000077314143453131016571 0ustar nileshnilesh 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/progresstest/0000755000175000017500000000000014201250466016721 5ustar nileshnileshcli/tests/testthat/progresstest/DESCRIPTION0000644000175000017500000000050214143453131020423 0ustar nileshnileshPackage: 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/0000755000175000017500000000000014143453131017507 5ustar nileshnileshcli/tests/testthat/progresstest/src/test.c0000644000175000017500000000454114143453131020636 0ustar nileshnilesh #include #include "cleancall.h" #include SEXP test0() { int i; int res = 0; for (i = 0; i < 2000000000; i++) { res += i % 2; } return ScalarInteger(res); } SEXP test00(SEXP progress) { int i; int res = 0; int progress_ = LOGICAL(progress)[0]; for (i = 0; i < 2000000000; i++) { if (i % 10000 == 0 && progress_) cli_progress_set(R_NilValue, i); res += i % 2; } return ScalarInteger(res); } SEXP test1() { int i; int res = 0; SEXP bar = PROTECT(cli_progress_bar(2000000000, NULL)); for (i = 0; i < 2000000000; i++) { if (CLI_SHOULD_TICK) cli_progress_set(bar, i); res += i % 2; } cli_progress_done(bar); UNPROTECT(1); return ScalarInteger(res); } SEXP testx() { int i; int res = 0; SEXP bar = PROTECT(cli_progress_bar(2000000000, NULL)); cli_progress_set_format( bar, "{%d} package{?s} {cli::pb_bar} | {cli::pb_elapsed}", 4 ); for (i = 0; i < 2000000000; i++) { if (CLI_SHOULD_TICK) cli_progress_set(bar, i); res += i % 2; } cli_progress_done(bar); UNPROTECT(1); return ScalarInteger(res); } SEXP test2() { int i = 0; int res = 0; SEXP bar = PROTECT(cli_progress_bar(2000000000, NULL)); int s, final, step = 2000000000 / 100000; for (s = 0; s < 100000; s++) { if (CLI_SHOULD_TICK) cli_progress_set(bar, i); final = (s + 1) * step; for (i = s * step; i < final; i++) { res += i % 2; } } cli_progress_done(bar); UNPROTECT(1); return ScalarInteger(res); } SEXP testc() { int i; int res = 0; SEXP bar = PROTECT(cli_progress_bar(2000000000, NULL)); for (i = 0; i < 2000000000; i++) { if (CLI_SHOULD_TICK) cli_progress_set(bar, i); res += i % 2; } error("sorry, can't do this any more"); cli_progress_done(bar); UNPROTECT(1); return ScalarInteger(res); } static const R_CallMethodDef CallEntries[] = { CLEANCALL_METHOD_RECORD, { "test0", (DL_FUNC) test0, 0 }, { "test00", (DL_FUNC) test00, 1 }, { "test1", (DL_FUNC) test1, 0 }, { "test2", (DL_FUNC) test2, 0 }, { "testx", (DL_FUNC) testx, 0 }, { "testc", (DL_FUNC) testc, 0 }, { NULL, NULL, 0 } }; void R_init_progresstest(DllInfo *dll) { R_registerRoutines(dll, NULL, CallEntries, NULL, NULL); R_useDynamicSymbols(dll, FALSE); R_forceSymbols(dll, TRUE); cleancall_fns_dot_call = Rf_findVar(Rf_install(".Call"), R_BaseEnv); } cli/tests/testthat/progresstest/src/cleancall.h0000644000175000017500000000274314143453131021604 0ustar nileshnilesh#ifndef CLEANCALL_H #define CLEANCALL_H #include #include #ifdef __cplusplus extern "C" { #endif // -------------------------------------------------------------------- // Internals // -------------------------------------------------------------------- typedef union {void* p; DL_FUNC fn;} fn_ptr; #if (defined(R_VERSION) && R_VERSION < R_Version(3, 4, 0)) SEXP R_MakeExternalPtrFn(DL_FUNC p, SEXP tag, SEXP prot); DL_FUNC R_ExternalPtrAddrFn(SEXP s); #endif // -------------------------------------------------------------------- // API for packages that embed cleancall // -------------------------------------------------------------------- // The R API does not have a setter for external function pointers SEXP cleancall_MakeExternalPtrFn(DL_FUNC p, SEXP tag, SEXP prot); void cleancall_SetExternalPtrAddrFn(SEXP s, DL_FUNC p); #define CLEANCALL_METHOD_RECORD \ {"cleancall_call", (DL_FUNC) &cleancall_call, 2} SEXP cleancall_call(SEXP args, SEXP env); extern SEXP cleancall_fns_dot_call; void cleancall_init(); // -------------------------------------------------------------------- // Public API // -------------------------------------------------------------------- #define R_CLEANCALL_SUPPORT 1 SEXP r_with_cleanup_context(SEXP (*fn)(void* data), void* data); void r_call_on_exit(void (*fn)(void* data), void* data); void r_call_on_early_exit(void (*fn)(void* data), void* data); int r_cleancall_is_active(); #ifdef __cplusplus } #endif #endif cli/tests/testthat/progresstest/src/cleancall.c0000644000175000017500000001026314143453131021573 0ustar nileshnilesh#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/R/0000755000175000017500000000000014143453131017121 5ustar nileshnileshcli/tests/testthat/progresstest/R/test.R0000644000175000017500000000122614143453131020224 0ustar nileshnilesh #' @useDynLib progresstest, .registration = TRUE, .fixes = "c_" NULL #' @export test_baseline <- function() { .Call(c_test0) } #' @export test_modulo <- function(progress = FALSE) { .Call(c_test00, progress) } #' @export test_cli <- function() { .Call(c_test1) } #' @export test_cli_unroll <- function() { this <- "test2" .Call(c_test2) } #' @export testx <- function() { this <- "testx" .Call(c_testx) } test3 <- function() { this <- "test3" test2() } call_with_cleanup <- function(ptr, ...) { .Call(c_cleancall_call, pairlist(ptr, ...), parent.frame()) } testc <- function() { this <- "testc" call_with_cleanup(c_testc) } cli/tests/testthat/progresstest/NAMESPACE0000644000175000017500000000031414143453131020135 0ustar nileshnilesh# 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/test-non-breaking-space.R0000644000175000017500000000032714143453131020721 0ustar nileshnilesh 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-suppress.R0000644000175000017500000000076314143453131017146 0ustar nileshnilesh 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-css.R0000644000175000017500000000676214143453131016057 0ustar nileshnilesh 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-message.R0000644000175000017500000000501214143453131020540 0ustar nileshnilesh 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() { withr::local_options(cli.dynamic = FALSE, cli.ansi = FALSE) suppressWarnings(testthat::local_reproducible_output()) 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() { withr::local_options(cli.dynamic = TRUE, cli.ansi = TRUE) suppressWarnings(testthat::local_reproducible_output()) 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() { withr::local_options(cli.dynamic = FALSE, cli.ansi = FALSE) suppressWarnings(testthat::local_reproducible_output()) 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-ansi-make.R0000644000175000017500000000206614200445676017136 0ustar nileshnilesh 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)) }) cli/tests/testthat/test-bullets.R0000644000175000017500000000155414200722245016732 0ustar nileshnilesh 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-cat-helpers.R0000644000175000017500000000226214172272425017474 0ustar nileshnilesh 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-prettycode.R0000644000175000017500000001402014143453131017433 0ustar nileshnilesh 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, "rstudioapi::getThemeInfo", list(editor = "Solarized Dark") ) expect_equal(code_theme_default_rstudio()$reserved, "#859900") mockery::stub( code_theme_default_rstudio, "rstudioapi::getThemeInfo", list(editor = "Not really") ) expect_warning( cth <- code_theme_default_rstudio(), "cli does not know this RStudio theme" ) expect_equal(cth, list()) }) 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-meta.R0000644000175000017500000000226514143453131016207 0ustar nileshnilesh 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}}") }) })) }) cli/tests/testthat/helper.R0000644000175000017500000001030114201202236015542 0ustar nileshnilesh 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) ) } # to work around https://github.com/r-lib/withr/issues/167 local_rng_version <- function(version, .local_envir = parent.frame()) { withr::defer(RNGversion(as.character(getRversion())), envir = .local_envir) suppressWarnings(RNGversion(version)) } 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) } expect_snapshot <- function(...) { if (packageVersion("testthat") >= "3.1.1" && packageVersion("testthat") < "3.1.1.9000") { skip("testthat bug with snapshots") } testthat::expect_snapshot(...) } cli/tests/testthat/test-lists.R0000644000175000017500000001215014143453131016411 0ustar nileshnilesh 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(after = " -> "), .dd = list(color = "blue") ) ) cli_dl(c(foo = "bar", bar = "baz")) })) }) test_that("cli_dl edge cases", { # invalid input expect_error( cli_dl("foo", "must be a named character vector") ) # empty dd expect_snapshot( cli_dl(c(abc = "foo", empty = "", def = "bar")) ) }) cli/tests/testthat/test-timer.R0000644000175000017500000000043614143453131016377 0ustar nileshnilesh 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-containers.R0000644000175000017500000000461114200445676017434 0ustar nileshnilesh 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-inline.R0000644000175000017500000000335714200746456016553 0ustar nileshnilesh 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-status-bar.R0000644000175000017500000002135214172272425017353 0ustar nileshnileshstart_app() on.exit(stop_app(), add = TRUE) # We can't easily use snapshot tests here, because they don't capture \r test_that("create and clear", { f <- function() { cli_status("* This is the current status") cli_status_clear() } out <- ansi_strip(capt0(f())) expect_match(out, "* This is the current status", fixed = TRUE) out <- ansi_strip(capt0(f())) expect_match(out, "* This is the current status", fixed = TRUE) }) test_that("output while status bar is active", { withr::local_options(list(cli.ansi = FALSE, cli.dynamic = TRUE)) f <- function() { cli_text("out1") sb <- cli_status("status1") cli_text("out2") cli_status_update("status2", id = sb) } out <- ansi_strip(capt0(f())) expect_equal(out, paste0( "out1\n", "\rstatus1\r", "\r \rout2\nstatus1\r", "\rstatus2\r", "\r \r")) }) test_that("interpolation", { withr::local_options(list(cli.ansi = FALSE, cli.dynamic = TRUE)) f <- function() { cli_div(theme = list("span.pkg" = list("before" = "{", after = "}"))) cli_status("You see 1+1={1+1}, this is {.pkg cli}") cli_status_clear() } out <- ansi_strip(capt0(f())) expect_equal(out, paste0( "\rYou see 1+1=2, this is {cli}\r", "\r \r")) }) test_that("update", { withr::local_options(list(cli.ansi = FALSE, cli.dynamic = TRUE)) f <- function() { cli_text("out1") sb <- cli_status("status1") cli_status_update("status2", id = sb) } out <- ansi_strip(capt0(f())) expect_equal(out, paste0( "out1\n", "\rstatus1\r", "\rstatus2\r", "\r \r")) }) test_that("keep", { withr::local_options(list(cli.ansi = FALSE, cli.dynamic = TRUE)) f <- function() { cli_status("* This is the current status", .keep = TRUE) cli_status_clear() } out <- ansi_strip(capt0(f())) expect_equal(out, "\r* This is the current status\r\n") }) test_that("multiple status bars", { withr::local_options(list(cli.ansi = FALSE, cli.dynamic = TRUE)) f <- function() { sb1 <- cli_status("status1") cli_text("text1") sb2 <- cli_status("status2") cli_text("text2") cli_status_clear(sb2) cli_text("text3") } out <- ansi_strip(capt0(f())) expect_equal(out, paste0( "\rstatus1\r", "\r \rtext1\nstatus1\r", # emit text1, restore status1 "\rstatus2\r", # show status2 "\r \rtext2\nstatus2\r", # emit text2, restore status2 "\r \rstatus1\r", # clear status2, restore status1 "\r \rtext3\nstatus1\r", # emit text3, restore status1 "\r \r")) # (auto)clear status1 }) test_that("truncating", { withr::local_options(list( cli.ansi = FALSE, cli.dynamic = TRUE, cli.unicode = FALSE )) f <- function() { withr::local_options(list(cli.width = 40)) txt <- "Eiusmod enim mollit aute aliquip Lorem sunt cupidatat." cli_status(c(txt, txt)) } out <- ansi_strip(capt0(f())) expect_equal(out, paste0( "\rEiusmod enim mollit aute aliquip Lore...\r", "\r \r")) }) test_that("ansi colors and clearing", { withr::local_options(list( cli.num_colors = 256L, cli.ansi = FALSE, cli.dynamic = TRUE )) f <- function() { withr::local_options(list(num_ansi_colors = 256L)) cli_status(col_red("This is red")) cli_status_clear() } out <- capt0(f()) expect_match(out, "\033[31m", fixed = TRUE) expect_match(out, "\r \r", fixed = TRUE) }) test_that("theming status bar", { f <- function() { cli_text("out1") sb <- cli_status("{.alert-info status1}") cli_text("out2") cli_status_update("status2", id = sb) } out <- ansi_strip(capt0(f())) out2 <- ansi_strip(capt0(cli_alert_info("status1"))) expect_match(out, str_trim(out2), fixed = TRUE) }) test_that("successful termination", { withr::local_options(list(cli.ansi = FALSE, cli.dynamic = TRUE)) f <- function() { cli_text("out1") sb <- cli_status("status1") cli_text("out2") cli_status_clear(result = "done") } out <- ansi_strip(capt0(f())) expect_equal(out, paste0( "out1\n", "\rstatus1\r", "\r \rout2\nstatus1\r", "\rstatus1 ... done\r\n" )) }) test_that("terminate with failed", { withr::local_options(list(cli.ansi = FALSE, cli.dynamic = TRUE)) f <- function() { cli_text("out1") sb <- cli_status("status1") cli_text("out2") cli_status_clear(result = "failed") } out <- ansi_strip(capt0(f())) expect_equal(out, paste0( "out1\n", "\rstatus1\r", "\r \rout2\nstatus1\r", "\rstatus1 ... failed\r\n" )) }) test_that("auto close with success", { withr::local_options(list(cli.ansi = FALSE, cli.dynamic = TRUE)) f <- function() { cli_text("out1") sb <- cli_status("status1", .auto_result = "done") cli_text("out2") } out <- ansi_strip(capt0(f())) expect_equal(out, paste0( "out1\n", "\rstatus1\r", "\r \rout2\nstatus1\r", "\rstatus1 ... done\r\n" )) }) test_that("auto close wtih failure", { withr::local_options(list(cli.ansi = FALSE, cli.dynamic = TRUE)) f <- function() { cli_text("out1") sb <- cli_status("status1", .auto_result = "failed") if (is_interactive()) Sys.sleep(2) cli_text("out2") if (is_interactive()) Sys.sleep(2) } out <- ansi_strip(capt0(f())) expect_equal(out, paste0( "out1\n", "\rstatus1\r", "\r \rout2\nstatus1\r", "\rstatus1 ... failed\r\n" )) }) test_that("auto close with styling", { f <- function() { cli_text("out1") sb <- cli_status( msg = "{.alert-info status1}", msg_done = "{.alert-success status1 ... done}", msg_failed = "{.alert-danger status1 ... failed}", .auto_result = "failed" ) if (is_interactive()) Sys.sleep(1) cli_text("out2") if (is_interactive()) Sys.sleep(1) } out <- ansi_strip(capt0(f())) expect_match(out, "status1 ... failed", fixed = TRUE) f2 <- function() { cli_text("out1") sb <- cli_status( msg = "{.alert-info status1}", msg_done = "{.alert-success status1 ... done}", msg_failed = "{.alert-danger status1 ... failed}", .auto_result = "done" ) if (is_interactive()) Sys.sleep(1) cli_text("out2") if (is_interactive()) Sys.sleep(1) } out2 <- ansi_strip(capt0(f2())) expect_match(out2, "status1 ... done", fixed = TRUE) }) test_that("process auto close with success", { f <- function() { cli_text("out1") sb <- cli_process_start("status1", on_exit = "done") cli_text("out2") } out <- ansi_strip(capt0(f())) expect_match(out, "status1 ... done") }) test_that("process auto close with failure", { f <- function() { cli_text("out1") sb <- cli_process_start("status1", on_exit = "failed") if (is_interactive()) Sys.sleep(2) cli_text("out2") if (is_interactive()) Sys.sleep(2) } out <- ansi_strip(capt0(f())) expect_match(out, "status1 ... failed") }) test_that("Multiple spaces are no condensed in a status bar", { f <- function() { cli_status("* This is the current status") cli_status_clear() } out <- ansi_strip(capt0(f())) expect_match(out, "* This is the current status", fixed = TRUE) out <- ansi_strip(capt0(f())) expect_match(out, "* This is the current status", fixed = TRUE) }) test_that("Emojis are cleaned up properly", { skip_on_os("windows") withr::local_options(list(cli.ansi = FALSE, cli.dynamic = TRUE)) f <- function() { cli_text("out1") sb <- cli_status("\U0001F477") cli_text("out2") cli_status_update("\u2728", id = sb) } out <- ansi_strip(capt0(f())) exps <- c( paste0( "out1\n", "\r\U0001F477\r", "\r \rout2\n\U0001F477\r", "\r\u2728\r", "\r \r"), paste0( "out1\n", "\r\r", "\r \rout2\n\r", "\r\r", "\r \r") ) expect_true(out %in% exps) }) test_that("auto-close with done or failure", { withr::local_options(list( cli.ansi = FALSE, cli.dynamic = TRUE, cli.unicode = FALSE )) f <- function() { cli_text("out1") sb <- cli_process_start("status1") cli_text("out2") } out <- ansi_strip(capt0(f())) expect_match(out, "status1 ... done") out <- ansi_strip(capt0(f())) expect_match(out, "status1 ... done") # This fails on older R versions, only if f2() is tryCatch()-ed. if (getRversion() < "3.5.0") skip("Needs R 3.5.0") f2 <- function() { cli_text("out1") sb <- cli_process_start("status1") cli_text("out2") stop("oops") } out2 <- ansi_strip(capt0(tryCatch(f2(), error = function(err) NULL))) expect_match(out2, fixed = TRUE, paste0( "out1\n", "\ri status1\r", "\r \r", "out2\n", "i status1\r", "\rx status1 ... failed\r\n" )) }) cli/tests/testthat/test-cat.R0000644000175000017500000000024414143453131016023 0ustar nileshnilesh 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-tree.R0000644000175000017500000000610314143453131016213 0ustar nileshnilesh 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-rules.R0000644000175000017500000000753214200445676016426 0ustar nileshnilesh 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-verbatim.R0000644000175000017500000000053214143453131017065 0ustar nileshnilesh 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-progress-types.R0000644000175000017500000001021014143453131020254 0ustar nileshnilesh 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/progress-1.c0000644000175000017500000000414514143453131016326 0ustar nileshnilesh #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-progress-handler-logger.R0000644000175000017500000000036514143453131022014 0ustar nileshnilesh 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-progress-handlers.R0000644000175000017500000000325414143453131020722 0ustar nileshnilesh 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-collapsing.R0000644000175000017500000000245114143453131017411 0ustar nileshnilesh 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}.") })) }) cli/tests/testthat/test-subprocess.R0000644000175000017500000000774114143453131017455 0ustar nileshnilesh 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-progress-ticking.R0000644000175000017500000000064614143453131020554 0ustar nileshnilesh 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-custom-handler.R0000644000175000017500000000064514143453131020206 0ustar nileshnilesh test_that("custom handler works", { conds <- list() withr::with_options( list(cli.default_handler = function(msg) conds <<- c(conds, list(msg))), { cli_h1("title"); cli_h2("subtitle"); cli_text("text") } ) expect_equal(length(conds), 3) lapply(conds, expect_s3_class, "cli_message") expect_equal(conds[[1]]$type, "h1") expect_equal(conds[[2]]$type, "h2") expect_equal(conds[[3]]$type, "text") }) cli/tests/testthat/test-hash.R0000644000175000017500000000675514200445676016225 0ustar nileshnilesh 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_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-alerts.R0000644000175000017500000000137414143453131016553 0ustar nileshnilesh 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-format-conditions.R0000644000175000017500000000767014200725223020723 0ustar nileshnilesh 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("format_error width in RStudio", { mockery::stub(format_error, "rstudio_detect", list(type = "rstudio_console")) local_rng_version("3.3.0") set.seed(42) expect_snapshot(error = TRUE, local({ len <- 26 idx <- 100 stop(format_error(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, "rstudioapi::getThemeInfo", 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, "rstudioapi::getThemeInfo", 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(""), "") }) cli/tests/testthat/test-box-styles.R0000644000175000017500000000025214143453131017364 0ustar nileshnilesh 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-text.R0000644000175000017500000000113014143453131016233 0ustar nileshnilesh start_app() on.exit(stop_app(), add = TRUE) test_that("text is wrapped", { withr::local_options(cli.width = 60) 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/setup.R0000644000175000017500000000026414143453131015441 0ustar nileshnilesh 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-pluralization.R0000644000175000017500000000520314143453131020151 0ustar nileshnilesh 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.R0000644000175000017500000000064714143453131016676 0ustar nileshnilesh 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}") })) }) test_that("issue #218", { expect_snapshot({ cli_h1("one {1} two {2} three {3}") cli_h2("one {1} two {2} three {3}") }) }) cli/tests/testthat/test-assertions.R0000644000175000017500000000542214143453131017451 0ustar nileshnilesh test_that("is_string", { strings <- list("foo", "", "111", "1", "-", "NA") not_strings <- list(1, character(), NA_character_, NA, c("foo", NA), c("1", "2"), NULL) for (p in strings) { expect_true(is_string(p)) expect_silent(stopifnot(is_string(p))) } for (n in not_strings) { expect_false(is_string(n)) expect_error( stopifnot(is_string(n)), "is_string(n) is not TRUE", fixed = TRUE ) } }) test_that("is_border_style", { expect_true(is_border_style(rownames(box_styles())[1])) expect_false(is_border_style("blahblahxxx")) expect_silent(stopifnot(is_border_style(rownames(box_styles())[1]))) expect_error( stopifnot(is_border_style("blahblahxxx")), "is_border_style(\"blahblahxxx\") is not TRUE", fixed = TRUE ) }) test_that("is_padding_or_margin", { good <- list(1, 0, 0L, 1L, 237, c(1,2,3,4), c(0,0,0,0), rep(1L, 4)) bad <- list(numeric(), integer(), c(1,2), c(1L, 2L, 3L), 1:5, "1", c("1", "2", "3", "1"), NA, NA_real_, NA_integer_, c(1,2,NA,1), c(1L,NA,3L)) for (g in good) { expect_true(is_padding_or_margin(g)) expect_silent(stopifnot(is_padding_or_margin(g))) } for (b in bad) { expect_false(is_padding_or_margin(b)) expect_error( stopifnot(is_padding_or_margin(b)), "is_padding_or_margin(b) is not TRUE", fixed = TRUE ) } }) test_that("is_col", { good <- list("red", "orange", NULL, col_red) bad <- list(c("red", "orange"), character(), NA_character_) for (g in good) { expect_true(is_col(g)) expect_silent(stopifnot(is_col(g))) } for (b in bad) { expect_false(is_col(b)) expect_error( stopifnot(is_col(b)), "is_col(b) is not TRUE", fixed = TRUE ) } }) test_that("is_count", { counts <- list(1, 1L, 0, 0L, 42, 42L) not_counts <- list(c(1, 2), numeric(), NA_integer_, NA_real_, NA, 1.1, NULL, "1") for (c in counts) { expect_true(is_count(c)) expect_silent(stopifnot(is_count(c))) } for (n in not_counts) { expect_false(is_count(n)) expect_error( stopifnot(is_count(n)), "is_count(n) is not TRUE", fixed = TRUE ) } }) test_that("is_tree_style", { good <- list( list(h = "1", v = "2", l = "3", j = "4"), list(j = "4", v = "2", h = "1", l = "3") ) bad <- list( NULL, 1:4, c(h = "1", v = "2", l = "3", j = "4"), list(h = "1", v = "2", l = "3", j = "4", x = "10"), list(h = "1", v = c("2", "3"), l = "3", j = "4"), list(h = "1", v = "2", l = character(), j = "4"), list(h = "1", v = "2", l = 3, j = "4"), list("1", v = "2", l = "3", j = "4"), list("1", "2", "3", "4") ) for (x in good) expect_true (is_tree_style(x)) for (x in bad ) expect_false(is_tree_style(x)) }) cli/tests/testthat/test-progress-bar.R0000644000175000017500000000231014143453131017656 0ustar nileshnilesh 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-utils.R0000644000175000017500000000623214143453131016417 0ustar nileshnilesh 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)), "Not a colour name or ANSI style" ) }) 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) } }) cli/tests/testthat/test-themes.R0000644000175000017500000000674714200476437016567 0ustar nileshnilesh start_app() on.exit(stop_app(), add = TRUE) test_that_cli("add/remove/list themes", { 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", { if (packageVersion("testthat") <= "3.1.1") skip("needs newer testthat") 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-ansi-html.R0000644000175000017500000000354214143453131017154 0ustar nileshnilesh 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-code.R0000644000175000017500000000020014143453131016156 0ustar nileshnilesh start_app() on.exit(stop_app(), add = TRUE) test_that_cli("issue #154", { expect_snapshot({ cli_code("a\nb\nc") }) }) cli/tests/testthat/test-deep-lists.R0000644000175000017500000000201514143453131017323 0ustar nileshnilesh 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/_snaps/0000755000175000017500000000000014201176515015442 5ustar nileshnileshcli/tests/testthat/_snaps/containers.md0000644000175000017500000000523714201202252020124 0ustar nileshnilesh# 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/meta.md0000644000175000017500000001232614201202255016705 0ustar nileshnilesh# 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 Message 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 Message 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 Message ℹ 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 Message ℹ 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 cli/tests/testthat/_snaps/ansiex-2.md0000644000175000017500000000042214201202247017400 0ustar nileshnilesh# NA Code ansi_html(s) Output [1] "foo" [2] NA [3] "bar" [4] "foobar" cli/tests/testthat/_snaps/deep-lists.md0000644000175000017500000000305214201202252020021 0ustar nileshnilesh# 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/themes.md0000644000175000017500000001141414201202263017240 0ustar nileshnilesh# 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/spark.md0000644000175000017500000000106014201202261017065 0ustar nileshnilesh# 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/progress-bar.md0000644000175000017500000000502514201202256020364 0ustar nileshnilesh# make_progress_bar [plain] Code make_progress_bar(0.5) Output [1] "===============>--------------- " # make_progress_bar [ansi] Code make_progress_bar(0.5) Output [1] "===============>--------------- " # make_progress_bar [unicode] Code make_progress_bar(0.5) Output [1] "■■■■■■■■■■■■■■■■                " # make_progress_bar [fancy] Code make_progress_bar(0.5) Output [1] "■■■■■■■■■■■■■■■■                " # cli_progress_styles [fancy] Code make_progress_bar(0.5) Output [1] "################                " --- Code make_progress_bar(0.5) Output [1] "■■■■■■■■■■■■■■■■                " --- Code make_progress_bar(0.5) Output [1] "\033[90m─\033[39m\033[90m─\033[39m\033[90m─\033[39m\033[90m─\033[39m\033[90m─\033[39m\033[90m─\033[39m\033[90m─\033[39m\033[90m─\033[39m\033[90m─\033[39m\033[90m─\033[39m\033[90m─\033[39m\033[90m─\033[39m\033[90m─\033[39m\033[90m─\033[39m\033[90m─\033[39m\033[31m●\033[39m\033[90m─\033[39m\033[90m─\033[39m\033[90m─\033[39m\033[90m─\033[39m\033[90m─\033[39m\033[90m─\033[39m\033[90m─\033[39m\033[90m─\033[39m\033[90m─\033[39m\033[90m─\033[39m\033[90m─\033[39m\033[90m─\033[39m\033[90m─\033[39m\033[90m─\033[39m\033[90m─\033[39m " --- Code make_progress_bar(0.5) Output [1] "■■■■■■■■■■■■■■■■\033[90m□\033[39m\033[90m□\033[39m\033[90m□\033[39m\033[90m□\033[39m\033[90m□\033[39m\033[90m□\033[39m\033[90m□\033[39m\033[90m□\033[39m\033[90m□\033[39m\033[90m□\033[39m\033[90m□\033[39m\033[90m□\033[39m\033[90m□\033[39m\033[90m□\033[39m\033[90m□\033[39m " --- Code make_progress_bar(0.5) Output [1] "████████████████\033[90m█\033[39m\033[90m█\033[39m\033[90m█\033[39m\033[90m█\033[39m\033[90m█\033[39m\033[90m█\033[39m\033[90m█\033[39m\033[90m█\033[39m\033[90m█\033[39m\033[90m█\033[39m\033[90m█\033[39m\033[90m█\033[39m\033[90m█\033[39m\033[90m█\033[39m\033[90m█\033[39m " # custom style [plain] Code make_progress_bar(0.5) Output [1] "XXXXXXXXXXXXXXX>OOOOOOOOOOOOOOO " # custom style [unicode] Code make_progress_bar(0.5) Output [1] "XXXXXXXXXXXXXXX>OOOOOOOOOOOOOOO " cli/tests/testthat/_snaps/progress-ticking.md0000644000175000017500000000036514201202260021245 0ustar nileshnilesh# ticking Code out Output [1] "\r1/10\033[K\r" "\r2/10\033[K\r" "\r3/10\033[K\r" "\r4/10\033[K\r" [5] "\r5/10\033[K\r" "\r6/10\033[K\r" "\r7/10\033[K\r" "\r8/10\033[K\r" [9] "\r9/10\033[K\r" "\r\033[K" cli/tests/testthat/_snaps/collapsing.md0000644000175000017500000000373514201202252020113 0ustar nileshnilesh# 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. cli/tests/testthat/_snaps/rules.md0000644000175000017500000000012414201202261017077 0ustar nileshnilesh# print.cli_rule Code rule("foo") Output -- foo ------------- cli/tests/testthat/_snaps/progress-handler-logger.md0000644000175000017500000000016714201202257022515 0ustar nileshnilesh# loggerr_out Code logger_out(bar, "updated") Output 2021-06-10T13:51:05+00:00 id 13/113 updated cli/tests/testthat/_snaps/utf8/0000755000175000017500000000000014143453131016325 5ustar nileshnileshcli/tests/testthat/_snaps/utf8/utf8-output.txt0000644000175000017500000000644414143453131021322 0ustar nileshnilesh ── 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/hash.md0000644000175000017500000000734614201202253016706 0ustar nileshnilesh# 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/alerts.md0000644000175000017500000000464414201202247017256 0ustar nileshnilesh# 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/glue.md0000644000175000017500000000070614201202253016710 0ustar nileshnilesh# 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_text("{.url https://example.com/#section}") Message # quotes, etc. within expressions are still OK Code cli::cli_text("{.url URL} {1 + 1 # + 1} {1 + 1}") Message 2 2 cli/tests/testthat/_snaps/ansiex.md0000644000175000017500000000254514201202250017243 0ustar nileshnilesh# 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/diff.md0000644000175000017500000000735214201202252016667 0ustar nileshnilesh# 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 cli/tests/testthat/_snaps/headers.md0000644000175000017500000000374614201202253017376 0ustar nileshnilesh# 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/progress-message.md0000644000175000017500000000164314201202260021241 0ustar nileshnilesh# 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/code.md0000644000175000017500000000065514201202251016667 0ustar nileshnilesh# 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/boxes.md0000644000175000017500000002623214201202250017073 0ustar nileshnilesh# 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/format-conditions.md0000644000175000017500000003051714201202253021416 0ustar nileshnilesh# 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."))) }) 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}."))) }) 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."))) }) 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}."))) }) 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."))) }) 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}."))) }) 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."))) }) 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}."))) }) 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."))) 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}."))) }) 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."))) 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}."))) }) 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."))) 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}."))) }) 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."))) 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}."))) }) 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. # format_error width in RStudio Code local({ len <- 26 idx <- 100 stop(format_error(c(lorem_ipsum(1, 3), i = lorem_ipsum(1, 3), x = lorem_ipsum( 1, 3)))) }) 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 # 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"))) }) 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"))) }) 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"))) }) 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"))) }) 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.md0000644000175000017500000000276214201202250020066 0ustar nileshnilesh# list_border_styles [plain] Code for (st in list_border_styles()) print(boxx("", border_style = st)) Output +------+ | | | | | | +------+ +------+ | | | | | | +------+ +------+ | | | | | | +------+ +------+ | | | | | | +------+ +------+ | | | | | | +------+ +------+ | | | | | | +------+ # list_border_styles [unicode] Code for (st in list_border_styles()) print(boxx("", border_style = st)) Output ┌──────┐ │ │ │ │ │ │ └──────┘ ╔══════╗ ║ ║ ║ ║ ║ ║ ╚══════╝ ╭──────╮ │ │ │ │ │ │ ╰──────╯ ╓──────╖ ║ ║ ║ ║ ║ ║ ╙──────╜ ╒══════╕ │ │ │ │ │ │ ╘══════╛ +------+ | | | | | | +------+ cli/tests/testthat/_snaps/progress-c.md0000644000175000017500000000747414201202257020055 0ustar nileshnilesh# 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-client.md0000644000175000017500000000320314201202257021073 0ustar nileshnilesh# cli_progress_bar Code capture_cli_messages(fun()) Output [1] "\\ name status 1\n" # removes previous progress bar Code capture_cli_messages(fun()) Output [1] "first\n" "first done\n" "\n" "second\n" [5] "second done\n" "\n" # cli_progress_update can update status Code capture_cli_messages(fun()) Output [1] "\\ name status 1\n" "| name new status 2\n" # cli_progress_update can update extra data Code capture_cli_messages(fun()) Output [1] "Extra: bar\n" "Extra: baz\n" # update set Code capture_cli_messages(fun()) Output [1] "name 1/100\n" "name 50/100\n" # format changes if we (un)learn total Code out Output [1] "\\ name 1 done (100/s) | 3ms\n" [2] "name ===============>--------------- 50% | ETA: 1s\n" [3] "/ name 75 done (100/s) | 3ms\n" # auto-terminate Code capture_cli_messages(fun()) Output [1] "first\n" "first done\n" [3] "\n" "First is done by now.\n" [5] "second\n" "second done\n" [7] "\n" # cli_progress_output Code capture_cli_messages(fun()) Output [1] "\rfirst\033[K\r" "\r\033[K" "just 1 text\n" "first\r" [5] "\rfirst\033[K\r" "\r\033[K" --- Code capture_cli_messages(fun()) Output [1] "\rfirst\r" "\r \r" "just 1 text\n" "first\r" [5] "\rfirst\r" "\r \r" cli/tests/testthat/_snaps/progress-types.md0000644000175000017500000000516014201202260020757 0ustar nileshnilesh# 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/cat-helpers.md0000644000175000017500000000443214201202251020161 0ustar nileshnilesh# 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/pluralization.md0000644000175000017500000001006114201202255020646 0ustar nileshnilesh# 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/bullets.md0000644000175000017500000002406714201202251017432 0ustar nileshnilesh# 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/rlang-errors.md0000644000175000017500000003242614201202261020374 0ustar nileshnilesh# 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.")) }) 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}.")) }) 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.")) }) 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}.")) }) 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.")) }) 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}.")) }) 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.")) }) 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}.")) }) 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.")) 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}.")) }) Warning Must index an existing element: i There are 26 elements. x You've tried to subset element 100. --- Code wrn$cli_bullets Output i "Must index an existing element:" "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.")) 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}.")) }) Warning Must index an existing element: i There are 26 elements. x You've tried to subset element 100. --- Code wrn$cli_bullets Output i "Must index an existing element:" "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.")) 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}.")) }) Warning Must index an existing element: ℹ There are 26 elements. ✖ You've tried to subset element 100. --- Code wrn$cli_bullets Output i "Must index an existing element:" "There are 26 elements." x "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.")) 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}.")) }) Warning Must index an existing element: ℹ There are 26 elements. ✖ You've tried to subset element 100. --- Code wrn$cli_bullets Output i "Must index an existing element:" "There are 26 elements." x "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 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 Message Must index an existing element: i There are 26 elements. x You've tried to subset element 100. --- Code tail(inf, 1)[[1]]$cli_bullets Output i "Must index an existing element:" "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 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 Message Must index an existing element: i There are 26 elements. x You've tried to subset element 100. --- Code tail(inf, 1)[[1]]$cli_bullets Output i "Must index an existing element:" "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 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 Message Must index an existing element: ℹ There are 26 elements. ✖ You've tried to subset element 100. --- Code tail(inf, 1)[[1]]$cli_bullets Output i "Must index an existing element:" "There are 26 elements." x "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 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 Message Must index an existing element: ℹ There are 26 elements. ✖ You've tried to subset element 100. --- Code tail(inf, 1)[[1]]$cli_bullets Output i "Must index an existing element:" "There are 26 elements." x "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))) }) 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_abort() captures correct call and backtrace Code print(expect_error(f())) Output Error in `h()`: ! foo Backtrace: 1. base::print(expect_error(f())) 8. cli f() 9. cli g() 10. cli h() --- Code print(expect_error(f(list()))) Output Error in `h()`: ! `x` can't be empty. Backtrace: 1. base::print(expect_error(f(list()))) 8. cli f(list()) 9. cli g(x) 10. cli h(x) cli/tests/testthat/_snaps/lists.md0000644000175000017500000002663014201202255017120 0ustar nileshnilesh# 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(after = " -> "), .dd = list(color = "blue"))) cli_dl(c(foo = "bar", bar = "baz")) }) Message foo -> bar bar -> baz # cli_dl edge cases Code cli_dl(c(abc = "foo", empty = "", def = "bar")) Message abc: foo empty: def: bar cli/tests/testthat/_snaps/text.md0000644000175000017500000000165214201202262016741 0ustar nileshnilesh# 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/utils.md0000644000175000017500000000014414201202263017111 0ustar nileshnilesh# ruler Code ruler(20) Output ----+----1----+----2 12345678901234567890 cli/tests/testthat/_snaps/ansi-html.md0000644000175000017500000007557314201202247017671 0ustar nileshnilesh# 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-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-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/progress-variables.md0000644000175000017500000001263414201202261021570 0ustar nileshnilesh# 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/tree.md0000644000175000017500000001301214201202263016706 0ustar nileshnilesh# tree [plain] Code tree(data) Output processx +-assertthat +-crayon +-debugme | \-crayon \-R6 --- Code tree(data, root = "desc") Output desc +-assertthat +-R6 +-crayon \-rprojroot \-backports # tree [ansi] Code tree(data) Output processx +-assertthat +-crayon +-debugme | \-crayon \-R6 --- Code tree(data, root = "desc") Output desc +-assertthat +-R6 +-crayon \-rprojroot \-backports # tree [unicode] Code tree(data) Output processx ├─assertthat ├─crayon ├─debugme │ └─crayon └─R6 --- Code tree(data, root = "desc") Output desc ├─assertthat ├─R6 ├─crayon └─rprojroot └─backports # tree [fancy] Code tree(data) Output processx ├─assertthat ├─crayon ├─debugme │ └─crayon └─R6 --- Code tree(data, root = "desc") Output desc ├─assertthat ├─R6 ├─crayon └─rprojroot └─backports # trimming [plain] Code tree(pkgs, trim = TRUE) Output dplyr@0.8.3 +-assertthat@0.2.1 +-glue@1.3.1 +-magrittr@1.5 +-R6@2.4.0 +-Rcpp@1.0.2 +-rlang@0.4.0 +-tibble@2.1.3 | +-cli@1.1.0 | | +-assertthat@0.2.1 (trimmed) | | \-crayon@1.3.4 | +-crayon@1.3.4 (trimmed) | +-fansi@0.4.0 | +-pillar@1.4.2 | | +-cli@1.1.0 (trimmed) | | +-crayon@1.3.4 (trimmed) | | +-fansi@0.4.0 (trimmed) | | +-rlang@0.4.0 (trimmed) | | +-utf8@1.1.4 | | \-vctrs@0.2.0 | | +-backports@1.1.5 | | +-ellipsis@0.3.0 | | | \-rlang@0.4.0 (trimmed) | | +-digest@0.6.21 | | +-glue@1.3.1 (trimmed) | | +-rlang@0.4.0 (trimmed) | | \-zeallot@0.1.0 | +-pkgconfig@2.0.3 | \-rlang@0.4.0 (trimmed) \-tidyselect@0.2.5 +-glue@1.3.1 (trimmed) +-rlang@0.4.0 (trimmed) \-Rcpp@1.0.2 (trimmed) # trimming [ansi] Code tree(pkgs, trim = TRUE) Output dplyr@0.8.3 +-assertthat@0.2.1 +-glue@1.3.1 +-magrittr@1.5 +-R6@2.4.0 +-Rcpp@1.0.2 +-rlang@0.4.0 +-tibble@2.1.3 | +-cli@1.1.0 | | +-assertthat@0.2.1 (trimmed) | | \-crayon@1.3.4 | +-crayon@1.3.4 (trimmed) | +-fansi@0.4.0 | +-pillar@1.4.2 | | +-cli@1.1.0 (trimmed) | | +-crayon@1.3.4 (trimmed) | | +-fansi@0.4.0 (trimmed) | | +-rlang@0.4.0 (trimmed) | | +-utf8@1.1.4 | | \-vctrs@0.2.0 | | +-backports@1.1.5 | | +-ellipsis@0.3.0 | | | \-rlang@0.4.0 (trimmed) | | +-digest@0.6.21 | | +-glue@1.3.1 (trimmed) | | +-rlang@0.4.0 (trimmed) | | \-zeallot@0.1.0 | +-pkgconfig@2.0.3 | \-rlang@0.4.0 (trimmed) \-tidyselect@0.2.5 +-glue@1.3.1 (trimmed) +-rlang@0.4.0 (trimmed) \-Rcpp@1.0.2 (trimmed) # trimming [unicode] Code tree(pkgs, trim = TRUE) Output dplyr@0.8.3 ├─assertthat@0.2.1 ├─glue@1.3.1 ├─magrittr@1.5 ├─R6@2.4.0 ├─Rcpp@1.0.2 ├─rlang@0.4.0 ├─tibble@2.1.3 │ ├─cli@1.1.0 │ │ ├─assertthat@0.2.1 (trimmed) │ │ └─crayon@1.3.4 │ ├─crayon@1.3.4 (trimmed) │ ├─fansi@0.4.0 │ ├─pillar@1.4.2 │ │ ├─cli@1.1.0 (trimmed) │ │ ├─crayon@1.3.4 (trimmed) │ │ ├─fansi@0.4.0 (trimmed) │ │ ├─rlang@0.4.0 (trimmed) │ │ ├─utf8@1.1.4 │ │ └─vctrs@0.2.0 │ │ ├─backports@1.1.5 │ │ ├─ellipsis@0.3.0 │ │ │ └─rlang@0.4.0 (trimmed) │ │ ├─digest@0.6.21 │ │ ├─glue@1.3.1 (trimmed) │ │ ├─rlang@0.4.0 (trimmed) │ │ └─zeallot@0.1.0 │ ├─pkgconfig@2.0.3 │ └─rlang@0.4.0 (trimmed) └─tidyselect@0.2.5 ├─glue@1.3.1 (trimmed) ├─rlang@0.4.0 (trimmed) └─Rcpp@1.0.2 (trimmed) # trimming [fancy] Code tree(pkgs, trim = TRUE) Output dplyr@0.8.3 ├─assertthat@0.2.1 ├─glue@1.3.1 ├─magrittr@1.5 ├─R6@2.4.0 ├─Rcpp@1.0.2 ├─rlang@0.4.0 ├─tibble@2.1.3 │ ├─cli@1.1.0 │ │ ├─assertthat@0.2.1 (trimmed) │ │ └─crayon@1.3.4 │ ├─crayon@1.3.4 (trimmed) │ ├─fansi@0.4.0 │ ├─pillar@1.4.2 │ │ ├─cli@1.1.0 (trimmed) │ │ ├─crayon@1.3.4 (trimmed) │ │ ├─fansi@0.4.0 (trimmed) │ │ ├─rlang@0.4.0 (trimmed) │ │ ├─utf8@1.1.4 │ │ └─vctrs@0.2.0 │ │ ├─backports@1.1.5 │ │ ├─ellipsis@0.3.0 │ │ │ └─rlang@0.4.0 (trimmed) │ │ ├─digest@0.6.21 │ │ ├─glue@1.3.1 (trimmed) │ │ ├─rlang@0.4.0 (trimmed) │ │ └─zeallot@0.1.0 │ ├─pkgconfig@2.0.3 │ └─rlang@0.4.0 (trimmed) └─tidyselect@0.2.5 ├─glue@1.3.1 (trimmed) ├─rlang@0.4.0 (trimmed) └─Rcpp@1.0.2 (trimmed) cli/tests/testthat/_snaps/prettycode.md0000644000175000017500000001452114201202255020140 0ustar nileshnilesh# 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/non-breaking-space.md0000644000175000017500000000044014201202255021414 0ustar nileshnilesh# 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/progress-along.md0000644000175000017500000000402614201202256020720 0ustar nileshnilesh# 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()) Warning cli progress bar update failed: non-numeric argument to binary operator Output [1] 1 2 3 4 5 cli/tests/testthat/_snaps/verbatim.md0000644000175000017500000000065314201202263017567 0ustar nileshnilesh# 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/inline-2.md0000644000175000017500000001455014201202253017373 0ustar nileshnilesh# 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, 4, 5, .... Code cli_text("Some numbers: {.val {x}}.") Message Some numbers: 1, 2, 3, 4, 5, .... # custom truncation [ansi] Code x <- cli_vec(1:100, list(vec_trunc = 5)) cli_text("Some numbers: {x}.") Message Some numbers: 1, 2, 3, 4, 5, .... Code cli_text("Some numbers: {.val {x}}.") Message Some numbers: 1, 2, 3, 4, 5, .... # custom truncation [unicode] Code x <- cli_vec(1:100, list(vec_trunc = 5)) cli_text("Some numbers: {x}.") Message Some numbers: 1, 2, 3, 4, 5, …. Code cli_text("Some numbers: {.val {x}}.") Message Some numbers: 1, 2, 3, 4, 5, …. # custom truncation [fancy] Code x <- cli_vec(1:100, list(vec_trunc = 5)) cli_text("Some numbers: {x}.") Message Some numbers: 1, 2, 3, 4, 5, …. Code cli_text("Some numbers: {.val {x}}.") Message Some numbers: 1, 2, 3, 4, 5, …. # 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 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" cli/tests/testthat/_snaps/inline.md0000644000175000017500000000467114201202253017237 0ustar nileshnilesh# 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.R0000644000175000017500000000006214143453131014275 0ustar nileshnileshlibrary(testthat) library(cli) test_check("cli") cli/R/0000755000175000017500000000000014201221670011347 5ustar nileshnileshcli/R/box-styles.R0000644000175000017500000000336214143453131013613 0ustar nileshnilesh 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/debug.R0000644000175000017500000000420014143453131012560 0ustar nileshnilesh #' 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/ruler.R0000644000175000017500000000055614200477743012646 0ustar nileshnilesh #' 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/num-ansi-colors.R0000644000175000017500000002527714201221401014525 0ustar nileshnilesh #' 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 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, useBytes = TRUE) 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/spinner.R0000644000175000017500000002477614143453131013174 0ustar nileshnilesh ## This is how the RDS file is created: ' json <- "https://raw.githubusercontent.com/sindresorhus/cli-spinners/dac4fc6571059bb9e9bc204711e9dfe8f72e5c6f/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) ' #' Character vector to put a spinner on the screen #' #' `cli` contains many different spinners, you choose one according to your #' taste. #' #' ```{asciicast get-spinner, R.options = list(asciicast_at = NULL)} #' 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, R.options = list(asciicast_at = NULL)} #' 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, R.options = list(asciicast_at = NULL)} #' 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, R.options = list(asciicast_at = NULL)} #' 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, R.options =list(asciicast_at = NULL)} #' 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/boxes.R0000644000175000017500000001460114201157065012622 0ustar nileshnilesh #' 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/containers.R0000644000175000017500000001235014143453131013644 0ustar nileshnilesh 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, id, class, .close) { id <- clii__container_start(app, "dl", id = id, class = class) if (length(items)) { app$li(items); if (.close) app$end(id) } invisible(id) } clii_li <- function(app, items, 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, names(items)[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 == "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, "}") paste0("{.dt ", name, "}") } app$xtext( .list = c(list(glue_delay(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/progress-variables.R0000644000175000017500000004646514143453131015327 0ustar nileshnilesh # ------------------------------------------------------------------------ #' @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. #' #' @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/defer.R0000644000175000017500000000274714143453131012575 0ustar nileshnilesh defer <- function(expr, envir = parent.frame(), priority = c("first", "last")) { if (identical(envir, .GlobalEnv)) { stop("attempt to defer event on global environment") } priority <- match.arg(priority) front <- priority == "first" invisible(add_handler( envir, list(expr = substitute(expr), envir = parent.frame()), front)) } # Handlers used for 'defer' calls. Attached as a list of expressions for the # 'handlers' attribute on the environment, with 'on.exit' called to ensure # those handlers get executed on exit. get_handlers <- function(envir) { as.list(attr(envir, "handlers")) } set_handlers <- function(envir, handlers) { has_handlers <- "handlers" %in% names(attributes(envir)) attr(envir, "handlers") <- handlers if (!has_handlers) { call <- as.call(list(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(substitute(call), TRUE), envir = envir) } } execute_handlers <- function(envir) { handlers <- get_handlers(envir) for (handler in handlers) { tryCatch(eval(handler$expr, handler$envir), error = identity) } } add_handler <- function(envir, handler, front) { handlers <- if (front) { c(list(handler), get_handlers(envir)) } else { c(get_handlers(envir), list(handler)) } set_handlers(envir, handlers) handler } cli/R/themes.R0000644000175000017500000003535514200746352013002 0ustar nileshnilesh #' 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(after = ": "), 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 = list(color = "blue", fmt = quote_weird_name), span.path = list(color = "blue", fmt = quote_weird_name), span.email = list(color = "blue", fmt = quote_weird_name), span.url = list(before = "<", after = ">", color = "blue", "font-style" = "italic"), 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.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") { rstudioapi::getThemeInfo()$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 = tick_formatter_fun) ) } 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 old$before <- old$after <- old$fmt <- 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) 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")] <- list(top, bottom, left, right, start, map) ## 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/docs.R0000644000175000017500000000220314143453131012423 0ustar nileshnilesh #' 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/cliapp.R0000644000175000017500000002161614200476211012752 0ustar nileshnilesh 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 = TRUE) }, ## 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 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, id = NULL, class = NULL, .close = TRUE) clii_dl(app, items, id, class, .close), li = function(items = NULL, id = NULL, class = NULL) clii_li(app, items, 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) clii__xtext(app, text, .list = .list, indent = indent, padding = padding), 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_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, ...) { stop("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) { stop("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/unicode.R0000644000175000017500000000374014143453131013130 0ustar nileshnilesh #' 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/ansi.R0000644000175000017500000002732114201157526012441 0ustar nileshnilesh 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, 39)), bg_br_red = palette_color(list(101, 39)), bg_br_green = palette_color(list(102, 39)), bg_br_yellow = palette_color(list(103, 39)), bg_br_blue = palette_color(list(104, 39)), bg_br_magenta = palette_color(list(105, 39)), bg_br_cyan = palette_color(list(106, 39)), bg_br_white = palette_color(list(107, 39)), # 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) ) 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) { 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] stopifnot(is.character(style) && length(style) == 1 || is_rgb_matrix(style) && ncol(style) == 1, 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)) { ansi_style_from_rgb(style, bg, colors, grey) } else { stop("Unknown style specification: ", style) } 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/symbol.R0000644000175000017500000001540014143453131013003 0ustar nileshnilesh#' 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_rstudio <- symbol_utf8 symbol_rstudio$tick <- "\u2713" symbol_rstudio$cross <- "x" symbol_rstudio$star <- "\u066d" symbol_rstudio$square # ??? symbol_rstudio$square_small # ??? symbol_rstudio$suare_small_filled # ??? symbol_rstudio$circle_circle # ??? symbol_rstudio$circle_cross # ??? symbol_rstudio$circle_pipe # ??? symbol_rstudio$circle_question_mark # ??? symbol_rstudio$pointer <- ">" symbol_rstudio$warning <- "!" symbol_rstudio$menu # ??? symbol_rstudio$mustache # ??? symbol_rstudio$checkbox_circle_on # ??? symbol_rstudio$checkbox_circle_off # ??? symbol_rstudio$fancy_question_mark # ??? symbol_win <- list( "tick" = '\u221A', "cross" = 'x', "star" = '*', "square" = '\u2588', "square_small" = '[ ]', "square_small_filled" = '[\u2588]', "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" = '\u203C', "menu" = '\u2261', "smiley" = '\u263A', "mustache" = '\u250C\u2500\u2510', "heart" = '\u2665', "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" = "\u2588", "lower_block_8" = "\u2588", "full_block" = "\u2588", "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" = "'" ) 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/zzz.R0000644000175000017500000001757614200445676012364 0ustar nileshnilesh #' ANSI colored text #' #' cli has a number of functions to color and style text at the command #' line. They provide a mode 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/sizes.R0000644000175000017500000000557614143453131012650 0ustar nileshnilesh 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/simple-theme.R0000644000175000017500000001233314200476352014075 0ustar nileshnilesh #' 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 <- system2("osascript", c("-e", shQuote(osa)), stdout = TRUE) nums <- scan(text = gsub(",", "", out), quiet = TRUE) mean(nums) < 20000 }) } clienv[["is_iterm_dark"]] } cli/R/ansi-hyperlink.R0000644000175000017500000000442614201156506014442 0ustar nileshnilesh #' 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 <- glue::glue_collapse(sep = ":", glue::glue("{names(params)}={params}") ) out <- if (ansi_has_hyperlink_support()) { paste0("\u001B]8;", params, ";", url, "\u0007", text, "\u001B]8;;\u0007") } else { text } class(out) <- c("cli_ansi_string", "ansi_string", "character") out } #' @export #' @name 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) } ## Are we in a terminal? No? if (!isatty(stdout())) { return(FALSE) } ## Are we in a windows terminal? if (os_type() == "windows") { 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"))) { if (package_version(VTE_VERSION) >= "0.50.1") return(TRUE) } FALSE } cli/R/prettycode.R0000644000175000017500000002253314143453131013665 0ustar nileshnilesh 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()]. #' @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) { 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 if (!is.null(theme$call)) { fun_call <- data$token == "SYMBOL_FUNCTION_CALL" hitext[fun_call] <- theme$call(data$text[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 <- rstudioapi::getThemeInfo()$editor if (! theme %in% names(rstudio_themes)) { warning("cli does not know this RStudio theme: ", theme) return(list()) } 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) } cli/R/tty.R0000644000175000017500000001775014143453131012330 0ustar nileshnilesh 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() && no_sink()) stdout() else stderr() } no_sink <- function() { sink.number() == 0 && sink.number("message") == 2 } 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") { 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") { 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() stop("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)) stop("Invalid output from UTF-8 R") # 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/rlang.R0000644000175000017500000000351614200445676012617 0ustar nileshnilesh #' 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 #' #' @export cli_abort <- function(message, ..., .envir = parent.frame(), call = .envir) { message[] <- vcapply(message, format_inline, .envir = .envir) rlang::abort( message, ..., call = call, use_cli_format = TRUE ) } #' @rdname cli_abort #' @export cli_warn <- function(message, ..., .envir = parent.frame()) { message[] <- vcapply(message, format_inline, .envir = .envir) escaped_message <- cli_escape(message) rlang::warn( format_warning(escaped_message, .envir = .envir), cli_bullets = message, ... ) } #' @rdname cli_abort #' @export cli_inform <- function(message, ..., .envir = parent.frame()) { message[] <- vcapply(message, format_inline, .envir = .envir) escaped_message <- cli_escape(message) cli_status("", "", "") rlang::inform( format_message(message, .envir = .envir), cli_bullets = message, ... ) } cli/R/assertions.R0000644000175000017500000000143014143453131013666 0ustar nileshnilesh 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/print.R0000644000175000017500000000547714143453131012647 0ustar nileshnilesh #' 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/spark.R0000644000175000017500000000557514143453131012632 0ustar nileshnilesh # 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/ansi-palette.R0000644000175000017500000001454214172272425014101 0ustar nileshnilesh 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)) { stop("Cannot find cli ANSI palette '", pal, "'.") } 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/cat.R0000644000175000017500000000344414143453131012252 0ustar nileshnilesh#' `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/app.R0000644000175000017500000000420714143453131012261 0ustar nileshnilesh 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")) stop("Not a CLI 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/rules.R0000644000175000017500000001444614201157161012640 0ustar nileshnilesh 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/aaa-utils.R0000644000175000017500000001045114200477547013372 0ustar nileshnilesh #' @details #' ```{r setup, cache = FALSE} #' init_knitr_for_roxygen() #' ``` #' @noRd #' NULL init_knitr_for_roxygen <- function() { # Make progress bars a bit smoother Sys.setenv(CLI_TICK_TIME = "100") # Turn on ANSI colors options( cli.num_colors = 256L, asciicast_cols = 70 ) proc <- .GlobalEnv$.knitr_asciicast_process if (is.null(proc) || !proc$is_alive()) { asciicast::init_knitr_engine( startup = quote({ options(cli.width = 70) options(cli.progress_show_after = 0) options(cli.progress_clear = FALSE) library(cli) set.seed(1) }), echo = TRUE, echo_input = FALSE, options = list( asciicast_cols = 70, asciicast_end_wait = 3 ) ) } invisible("") } `%||%` <- 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 { stop("Not a colour name or ANSI style function", call. = FALSE) } } 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)) } has_asciicast_support <- function() { tryCatch({ asNamespace("asciicast")$is_recording_supported() && asNamespace("asciicast")$is_svg_supported() }, error = function(e) FALSE) } 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) } cli/R/sysdata.rda0000644000175000017500000033523114143453131013522 0ustar nileshnileshBZh91AY&SY!}^$A;|S@O}F5` b}cԥ) P[^( 7F JH>P+Ѫ$A(h: C^ [JV}/‡R}Miq؉n-7=n{{6>wnwN]wwʒK{zywLKsrj_Gjy;ӫ{uwn8|ʧ{מ-9Cm=2ΙP﷠y>SvQ3ݻgZjWy *NϮr=-&n3}`H}(9}{m6܍=W6t۽{r*@I֍efUtiz6wޫ޺ˀТT(+hVvRpF<:n98h 7yO0wgwG*^޼ ׷wR>5+*=8oX]Q$Rj]'AM3lڃ;w{GݧyÊ#7$;u;)Se(˃/x@g^1dta;eMt :a9XހwTP(Yـ r# __@|8P(5zzw u/!:k|*>mBNp==%(pl<=ku9KC@ o/ _wNҲ}NR:wӄ>Tv!NB=`Ѻ(z}{>mv۷yE7nnw>}gk [ހx׊<:lB2n>>HE̳b}2 2{:&AXZ5l y1_f\>VpO\ؼLU*ϠpVvcN(j@o04@GmOm^sJPcRa4@&Aڨ &L6&&M4=iLh6izIhTAhMhS@SM4##A#CM'h 4hL" "4"iyFm'm@h4ѣGS=M idAh4jh4lII#Bɠ f53jOц=AG!I e=='dHiM&)i?S=O)a44ƣѐiޠ5<4m5Fƣ "h#F m4M5s}O3l?׵o{V'ݔ'OW/w|n[Gg/{3;t}/>w}I~ca_EeO|+?^k}۪y?}{w}??}P>nOi>}ս?~Oa|>~o?}Wz^~~~'~/~Q=z+ox~g}gǫ>z;~z}q~OA'xas='|{ηQ_Y5u['ߟxqk?gR|?/xOJ?f_@}ws~7|=~<^/]=_g=Ӽ+?8?_/'<_y|7^>?'~$zc/u_OG}Ϲ^?{ߏ=}H>s>W>?{_ȗ}ݏt>$_7ĿWe|O'˧o3za/1$-_??U3>7~c￧~_~q/~'|f/+y)??yeNaWOazbk{?E!8}x]W?>|/~o|߃w}=]>"GG|sᄋG}??+:~?߰?{3vF;a׏g~o}7>G/q;{0Dg;3#} E`L)˰tr|/?4~gAWwuJRykZֵkPЀ^}B>Gu;޺__lӽ1zS>5m^ae1efv䒋ufyઊ)i馊(ye'}瞦ڥ(h u[rIEM4$ES5SM,,%1M+- S+Q;dǮoWG?8{)Jԥ+JV_ ?7\y$ I?OdI?O$IO'dI<W$FO'd)$I?'II?$I'rI$I?_$O줓rI$I?OP~o{mAJR[8Cm41l)^JR%f?7Fyϟ?$$$$$$$O餓w͟&}OI'Da$ORIOIOI'II?OI̒~d"I?O'i$I?$ǒORIIy$I?'2IHIߍ"azKC^ѷ ^Ar,~,ʆ)e.i$I$?Ö88888888888888888RI$I$I$I$88888888888888888Ož3"4OroVv\= *@,&8^# öpn 27#ZLw`_fpǴ.Sw ^؃}#N4IҬoxy :fG}SA#ɦ""L!H1UK\<$CFj]{KCCþfn]~8Os*E1U'feWJ ]`׊I~$SE-|_ |I[:5TOA:m^ f_S4j1waŲԯ\;> r+Zd\lngkH",^4QM9ԩ'Áޮ8Qم&vh:1,cKc#8mN2W,~R>^Ӳ+"8,g>r,:%}&G7vݭhE u{ uLI4 eLiXhpURI0up-}?vy Z#(dN&ĤOiOZ nT~҉Dc J \dETB|aqrzƭ%r+XdςHI%RL'AZ˷؎%;Z]9[ey|I3!#v}NBsͮlbo]<A#xC7I'!0䀩׽G #c,B=MG:0bZy9{س{]N'L< ;>LRxd{8̞}퓶0vʞOv;%jwx1v_amhUVV1hi\s'f,|+i}lugLwJCSs i{Cʨ Q𒢩aF3zLHy0(>`kP<$@L뽔MOBgbT/X|t??ՄIA[(7r. !f!%O.#"&Ij(.27ނ#ܭCw8d8nvȡ3U@cЃWlC:mݎjLK%8EJ,蹹2d GGkRo_8i^ :ϖ @.~IT%ǿnk画##.e5""[qXvc(.l㈿}U"ؓGlZ%oAJFzvR[`d5@MC#L}4/C>]ReфBJCpLaDD'2},{JuG׋d'T#VW3卑:rC'ٌi]r.PdLHu $]KKhETliEKA'f'W. $91;btοOM.!X+OEiUD]#1&)@l8Ë@aYDYuhjiqõ,]ZbԨ[>3Ibw&P2Q$q^Zq1sgomNہ v\DJ[C_sүҋ'vP:; @wD!Rw*T&%(*!2a f0" ZAE @%C @i=4 ᒆP BR UABR " "08!#H ~GOa-/Gڿ]w _5v5&p8'(ZQAyKĕBVHel'$3"P!sJS)J7Ƭ>^"vR*993d @a%$)(H&ib}tH H"PKdOV[_}g_<}WkWG[o=L?#_ѩ?#'?~*ӇܳeVx+aCޜgCpn'L{_7R~3uœIqy76nE6Ӻ.lcj9 SF-YJ",ۜjp\DZQlN͛s@]ѫb=E0@gؘ:&mÚc BahbP4J\ Pxm`7_fvk&hw=Nzzx4s9;.u*a7ChuG@Q(sG"wuqv~ns{pDM0g}ݩ1Mm5liCDP2!/ ԓVF=w=u󽏓L拗{õv;;::7wwvmGV^*cO=\=}e8CnFS[؞u%' vS[灾^ 5<|V akسBOph@nn5\{p&F[m=;{;Y: v66sou6FcOG/k OS{yJwG'[F}y&1bճV62fg_뭖.'ϣ?776-Z=u,ymja]y:k{|Iٷkǵlhյ.mɻv:{}C~]/hq} QhswoMΧn ujutdofnpqvp¾.yMzዔ뿏Ls==iñ8.iٞ"[#V>~g {8u; v7gVkܛv|RƊ{J;:胣_Fc5Og1i o*xx`^UJ|<ܵf࿏D9>\p-kw}X!dCG!g[knHe0hr:O5ح!L|@f:0ogoEeb E t[ʗ1q8))JRw"דqE.qM۝9orqA[W6/yߟ^ a2O&6ʐ]^*ǃ2:#Bb\({,6# {FCF^N^,Yd$I^s<ϖ~yylsM4ܓY,M5q02nhJ![( vkLGύ[W}]t{uק=yǵ_3U$$d'O$l&[|~d~d~$I$I'$I?\~I?JI:N$2Id'OII'I'II?k$$rI$I$Y$$dOI>$dOI>$$ $Ԓ~)$Ԓ~~~I?m$l}II'$\}rI'$$qѢ}8=\oklv~+F{ys޹k]^܋1WyŠsב̲?{+EI->SQLAfq6ie![{e{{޶[{e{{޶[{e{{޶[{e{{ޢ8(((["+תHgvy~x8˃5-. <wz5z?oso==GFo ~G]Ͼ/k=E>g8c.^oW/{}>;{Y^G;_ޣ}'rGo6W̃__?_w?n/~'~{!)mmm~骫?~~}Z %?_ϋy;罟t9;PP~8fP[Z)3>k__ ^JVcyƩ@3cQMZoJ Vvo魽ֿڔcz[mϧ[{sJPqƵ<` uzomky\Raٚտߎ7A8₃8skc1ߞ|ڔҙib3KLL,xcY/6lKdFC $qq0 aJJI $bsк1w?~~o{mw{O:OeWlhѣF _+^zY=g/쾷<W>P&zkׯ_}nz=g^======:zzz_Vttzzzzzzzzzzzzziu:NS.⪪.zׯ__^zqׇ^z#^zק^o^zjϟ>|{ׯ^zׯ^zӯ^zׯ^(y_UUUUUUQUU:=====<==nOOOgzzzn^xׯ5ׯ^zׯccF4wׯ^zׯ^zNzׯ^zׯ;⪪g|MNm-<>Gv4x<]>O7ֽ>x0b] 7~/yWߣ|3Ex>ϛvw}uuTUUuٝs|]';]0]mh? k/#?R ]APAUPJ#hZ-QJʕRQ YkJQTYX)VUJ BTĭjҊB԰#bebW˒`s s..ZIƪ2E ’K(jUERҌU(V(""c")b娶ߦ6XbdE: iW0I(DD2Rhr&&ZrM* (JiAE)fC0JJl1J@r2i6E$,(IO/{=\͕{#] i85Pj7&R̉0]qkP  `Ys}]J +茔c0 یKlQ$^ w1P wѧzV)L&{jq7B]u Z-5fyLjA{A8|M]31_~[pk܏b <5klИJVpg)Hwy˴ڻsSh #zAɷ,!,Jq>tA(Xڌvk5æ{l=޽}!o~Nչ(r]/w1ssx@̧ae/5>3Z|P J$&8|R- E\)x^#_30f@M..sBr8nFO=tGԹ#MUZ$0WÚ#mj fόlWʭ^LZhti`MU㊝j){+[bss{&B()pB5gb_XV޵77~uv]lܢsG""GD97*DU:,}?Xf?IY3Cد[ݯ/[_ֱWfwS®[1S9kY3Y6m.W{0bՌ!l&︾[iNS]%q}m f|>Ce:Z^ 3 $X}d!C* *Տ5֦sQt2-&b-Ra[ץv1dڼo{!i%mƫaRu|AҧY<_[ZykboF]ڴl3sƯeZjޱ}[6w44Xեn5 KR[Fs-Yzu*b o;meW[s6֋7Jfr󜾯][J{[G{[([f+ִxE1J . CVʻ'[5b+}'jQ>͐VnwjZl1 (9g:k큔Z촠+ vVg.FOKzr z!BNk\;1[|~EeKrk꜖@7ɉKe^#ĢwߡŭDO+:G^$ϖ-?u N!NvSvş8g/ ț pt"elw%hT=x{a>GxϾڻk=d־̍Kpnmb'15i9TrR(5|/3j|3g?!-z:zD \wAfh vS<:bY.;س(y3f=ČܒCB Uo1EˬT K;d<(#Vb@4Ĩ73|]ԚGWYqkR2D}Szd_k SvMO}+_ǎOʗ>0y"2鐾-ܞ|4.[=0.g\s0R@qI.ebk@V e؋Q$I#c!,NrZK JJW)C2)Ps=yvM0{&uj-¦IkSG =‹)AJ9v{9 #x5Mt+yߐkc pI\R*lUJf2+zӗ;d|%JGu\XKGB9@ŗiZ@2;OdS3nwcBg5u('o.mڴZhEda bmp^@{q ;.6EjJr @Dugri1m #)d[ 媜e')^Ebہ,uȪJPIr߲VU >kFfsٛľz\$WQ< ]paiJQqZyWz֤? 8ˎa;iʶBôH]{ ymME]8ͺgJc5$3^ Y튿DuM2.NTZ1_iayKkRm>vsllF ǵ*heEw%3JR'ǢvQ\emCM[yϔ:D9>Y GD9!ɡx[R7cƣ5JST[[S^^my?(x8&߈L/8*J[%cc#di-֊Cn9hAi>\{y]7\6 Ds跏,/5Vɖ)XMYz}OUNmԇѝ4U/iH65`<*-RZ۶Iq6k~/>o~ o?-ӱ`0Dn@7e+z 49~*;aж_sPzѳ@rwGĤZ`r1VKfQ/=ݤ T3ܵRS9HEB*Pȩi^n_V<)NP]/wL(PaƩn]1מܺxcJi L^T23rS 6g]QHxtk V{rNPQKܫcq[{̊w-m]6|əHG}8Jl:?VfAVq;oWnݻ<1Εt1p݈l+LGe B60貔0zX)6h1 "tD! ?m&gXH~SfSMJg(|.m4zAXŗ 98DS`xH%\#j̝bSZR* azd}g-w^(LDFWDa- st\'5=iC؎_Ү0;s̈́<'C1vB-+)DyNxup`k]-ٺY+w *Ʃ=;j=>-kBmQb7f)RZ~L:B,er[1;C϶Ga-,e=QvCbץ)gnjUOKz~qmo`ˑ4]_SY?=)->Db |'m65eqULNapcxu)ih[m9\`XYEcc?j}˦?)Έ7G06mo),l]?bE6R[KWViQ:Ϯw ,4)G01U6kiuVOnxIJP"KASjqz[nd۷s~ ks5[/f~o\C9#{Ủq=kౚfHƙbZuk0٠c dTLƘ3T'_eE]zi[]tsk#)oH1Z;>T*f7YR;;eTCīZP5 Z{Ald/ 'x$cmMsc9UD@Cnnm$DY܂A+ ņF[6ȮDd%1o.d`)ñ>KbZ|LE6 $S|kT{L{BP`zX ݍ/dzk͊Z=?%OVF*us Q~ i`ׄS~0h@m4A}6< EU1cbe !I>Ǝ+f5D6ML5f2) m< )rXJs#]Wx4[ZLq1yŬ,MbFrjZ֓bJOn'T|T:/v@2N x(N iΥ}-B֕x #baT8OoBX!: 6m!fijiޯ䬳ac>-j4B4V^)JPPd!f5Ea:Y8T i)Ȓ(1zP5ڜE}VCU5U~f IˣkY.ŭڍu LJX}0 2#"as/C<=p3Dxt=jxVvtwIyM"M|[\#dW0@3RjJv > XȗT팹=SM)53CrŔy6# ܲM N88ѡ`}Oshjť>vфl29†VH'ZYLYAzi_/9ǓEN'(Uy{q~-D ΄uGqwDa,5W$ z55Ѧ&^K[=;K7GMo{u_xNH=6@ecφPO^:͛:[W!(Ż)W: Zǖ]Vq[%w"""F'tVtR,TaWi_wzkgq]ڤ9]S0u:N%%%j\h[(8%B֏#TH$}/3Ў4zӭ30Av\|& 6( ruN}.HK>Hh:" sgDdRؚ!gij 0ݙl*-THV&#st.<ԋ'" |MW\kJQyfLKi>7EccPsvbJB<I4By{xP`ZC#BhJjwq+^~GLgeC"䮞''׻\r\oiԝ!yD<.4nk%T$׏Do+dۦY[“!VݸTb9l9sdFD #¯x'"~82mJi_a،]E,Fa8K|Nt,v9My>o'78B7 ޟRg γj:%Z'{,:\zjMb-YqQ!>, <~\W΂5@m?py0 %KIc* e(R6T}yiK,<$CV3]lTg'!w޽C#cpH0P]GS=^zRQ.D'~0% 9vT+f&8lWcuV j5HYDU>[ed8z?Kd~ݱ6J_J [mެ|bTv$(&?..e:1TѥN;Hk^xwk֊p3g2LdK)`]/OpyJ|Hlfy䶽}R3ip4$ Z(Z[,b'Mҩ^6灩yKe\#0䀅gfޯl2۹wO5T+\Xx9є-9brJNgP)$U e7JU_z_ L?UdB'RBZL=m?Y&rDz^rde_嬌D:֧oǶo%ʳvO2{"P?&ZDK;U?"S 鲡' *;Y pF ҩ;[,:#5RRRxR'=j(4ϳMhp٠rۧOip6,S¼\0=D(C:3j_T$S:N~l֒ٙ9f6u+\ψelX e? ~~HX"oK~bşW4+'*``QЙm/ɿdnj4ڴ`Jy4A+R'qLS-*s{docɼ{VsCb+lB֭+Tu Z*حR-jثbJ[b+lB֭+Tu Z*حR-jثbJ[b+!x:NqIoKeq`KkJfSΌ A91Prqv0;"X\גIޤ $_;K0um=SUۃս`07Yb3 |vڅbi%݀z"ѿS­-Q8mKϝ͕"CAlו.'ƠX@2 B~ԊC;v6ƓFQahg"$0WժTGɟ'tm ϕ(Uؽ+eCDEUez?.I~?j(dxR@檧 |P)`JR*Sjݜ)C㸾gXJ"2Db|,vm -EQQQUDWK D Ax|Wؼnmy!A;@4 0RB@ݎ(p>tNcqD$[b:t3(."²^-ܭkN<Nȏ͟H/v3?"| 4}M E VcjL eE7P:ċ+RkXJ͒%)V;DXQPaBYE%`eY@e61dYaDeZXUdIdH rqaaYaT% a%$Q% aBDeXQEYRBXŐԊK 2R J ,#I BeYX`%rY`%cR uiaA  ŕԋEФA0K.LY%eHspT݋@{mWdȢ x;YCyvSSH (BBV,,Z `WKnp ]I`!VQ%:LX s1& BT@z]_KCyC0/d!8 @l9qtPN2  1DLR Qۿǎ" Q bT UT$C6 Q( T7ݿg|!APB‡`W|"DJ(B ! Т $ "* "*B"J(0!@B(JB*D ÆAJTBhDQX!BPh $UaFZXV(B)A$$$AYTX$Pa "EH!D""PÆeĕ!Q߿ PD[maUs[mDwȉ$(mȊ/*o7Jw ނ*((j(&h)( hQhQ)DJPZPT  TBRV P)hTY( "h*Z iJE )*@)H)*(F()Hi DhiJ   i Q ߿,@ Zqh%im!,\K ?X8WֵUdUB̼*wf *Hx^ /+$]K]r⪮vM-f@ D)kY2"" ZֿS~ q~c>/y瞡ϗcfX{pd d@ a t }A;y_| o,`22y 2mw ^,umWAF۶ _<zdR?AR^/Y5wyͯj׼mYHw;D_:5' ,D.b"Tk-6nhdGޭYKq {ٖ YVoxv8WD&+Zֶk%kZK1̕S.LS5jfRUPPpW {}VZֳ[syNMg;ymnZֵ*kZ";UUUUUU_R\뮳ǧ[{|ov31[1yNMg;ymnZֵ*kZ";lI$I$I$ﬓ]u{bsFcb&ݳzkZ{ՕvkY{f""""""""$II>D1}w:뮷~֭kYs9Fcb&ͳzkZ{ՕvkY{f"""""""""""HI>DVvJ\i#xhC 5yׯ***I$Q$@+׊}zԒ`˻LwwI.I0eI& $|[^\US%kh ;tPI/wLwwI.I0eI&V]`˻@ I.I0eI& $$rI ˻LwwI.I%NR,OF>ϯZw4\O]pUUZ\ރHl,8pī؃SxǮtLLoe|\}rׂj`'fv nz ZtWٹS%I*X+a3TYbâ.ѹU7dKwqg%Ոz)=I$I$I$V,Isj[vˁm?{|{zɖmcAjԄoi |FoB%vkVb3wUЋ5Aʀ%)_4>`IԜT >N~>m6&`zZCW i =ġf HB& W"?.Jͱ-04nfTĬ$S vchrg֞[cm TRQLе^-Lwi.ҍJ:)sF95 j38x_@z nUc w:ȗ;ᜊ3fwcle{pPo*!O*h%7TL*{iԷqY`BPYqI_6Nd* QZx MaOϞ;Sϙ~FyeU\3{C6]@5kl!P>Pt}m cE@kDv A=Ē$mRwK@fiv9:,&h,XM0X%FU\c%V'#^+ pFjmm۲x=ۆV* ZqګwjݪvW޽PYe)V[amc}]ApytAR vˁB7(uV1K 7bA$,$©2o#4myj&eK)J(XܲP%hq8}ޠ0@bSe2$A^ЫC}Xf ,Ž-^$] ,#6-&晛:'ԸT$ʃp4:mfm-:\p X*)\x;E-1s:o ֔@ LJj-cbEjV"6ت e[b+TUQYJ[Jeleeb"*JZTYEijҠڴV)mb+`ªV֨V+jѭ mE`B,QmQDQ+,lEPVEѢcjkF+Ui*lVmmrlbN¡źFDyq QvV8E>Es ZDf b7I\F [x:%CRh . 4 NYhdj|D1'$zܼJ(y蒹']`qR3{đ43wch6.@%&1 F<)9'ijgXa`6KCbŊۢڃcccc@1"IU\ymI&I6Ie31q;~?_⌟A~oO,;h \IKCB"nd ne 0/(3z `+! @!$}I'$Q@At /ľHIFTAgBi+ 5[ I A`uה;0D yދpm'>վgߑ?Ƀ{o?9>SD ѶI/8}^/r TFkG+ GhVIU<  &5l HH 0D im> ;|+|fo6[6ƣ U-8*ogޑzȠ+J j3.&WkҷP` c@ R4QJED* HҡLJ4BQ61ؓ`&n:˧mY,g~`3 seD|Ke֤ խkR]쪬4fP#HVqFDPgEe+Zo7|yVI30Wʳ2$IY\wn߼wtvx$$ ,00A ) ) J0040R@Ȑ2$ R ;MKOHnvBdFC 7$.`0@:JJI$Ӊbs3쨊oG]W I2RRRRRRRRRRBć$1!2 zε :֐41iO~,* OM//*+b> :t,tiRCygQEnѤI$)) e\I`\H2@ Y)$LI,ĤPbl0lIIIIIl R $XK0!3Y!$ T1)"JI$H`-f?Geގ%<:ldАrpldckuVm1CN}< qǡi\qVRDe3IJE??÷Wmm|Im]ڵkZֵkZֵw\Ώ*4Fv؆4T"Rp Y{aijka$g0M<,Vml92# '0\$(*jx맰Fq)B:y+usa<An~BiM jKXRRH-0766bh恢RнU;f@w;%ǝ,'Zqy6(Sn>.SXŸPf=I$I$I$I$:홙$D(E> ܮ+x=Ն>@\@kC>CaWxZc8h,yrի4thZ]+TM[Rt2/7*ͯ{kV0H2/θo AK1޷BƳW 4l'&eH5V$*Qh4dѣ>Љ  W{O^7HcsPШqgڳֿ +|[%ُsMX[fּggYϷXf`ma*e>/4ˎy+g4ti`?+^(IUQ4BAstNBjn$$5sۄ<6>^gq |xb눰fej^m#BрaVm1jTUUW~u\UU^sqUL &@36\В# CXr'm-Wsl|3<[E[?J})j5JحTRR*ֵ;3?3l}(() ,]b六kY/f60Smi6oueDI F5Tdv)J+6Ɂڷ0]hBQ1€w7wC!""!BiֳXSh@{!fvy!D@ݙ˛6l}H"h Q:sumq<5C)C6ۘg,H`6זeLq>8馔M#Ja3*'+322r3*'$^ "e'Uhn. l.1CvRFQD޺sU+۷nݽ~{q9̈́832@̌;X, PQml-OP;0:ej*+53Zm#~EWk D)QFb9a{ajK坙ʏbgzBwwk3DaIćݽYIYɓ<3(D 3p8z\ǂ-XWȗ w͢Ss**OowoJ`,(Y(YT.,VB: VN:$Ax@0bBVhU00;Zx`bՉ-*ֲVV, 8\#8 q2mqo2`/A|5jUFMփFn.NE y[nл$𐙛Ƞ{j"$1ϟ& ٳ0s: ң/YFk82q\Yg;8|]??9,Aʪ*%I3HQ}Ԟ˧-k3iPO Fqtkqh$W5"Pd9a*wRz+l0I-CAfuA9 1;Q XW 3>lta %u^cG.0I-CAfux4q*DYJX(t 9Uae& ϛ!GjI]WX˅hVXԨ Qhr_ ΍uNyDYG q,HA  ϏsgDi͗mcMy0 D3[L 4{r}߾z7sGuLW=>nuw{^u_itY$AI$m|h D+3,vu;'55;\`e$=tm;2Ītr"CYT
*8l~އL=ik9k0]QD|}6~>TKc7˭%m"^$,!z2pI'zUUUUW'^PL㮓s1oU_ZZ喨_wU^&UUU_`dJLnϹ@ǧ}s(D|{ݶmPEqYEG I6AV (>~~^_b? O8F ,ڵ 8ۛ) <%▢2da05C1ɐAD^/]j(5U^.ΏGM ZQRff1!l-4;12ZԶB-'5!"u>v=ɶi.~/5UU)&FA Ū@8dz\!&>Pvy|>7ȺE)Z@1v9@;Z1:Bcy|_> 3H$H$H$H$l_y<7> i{?nh`)"̇%}?X3գAoK@U*\g%ظi:7|m+fi!QrDsVㆴim XɌ?:Pel[4c|}G_L 0Pv*% iƭlfB-u- c$\ɑ{:6T)X/eoap%um?ךDHU ;~[  1U.y=Z:V&nQXPL}UUh x|hm#{y{yg|d{kw|F#DFOZ Գ_3=r”!#$~^ LQem-tPF+Ep$ ۢ^zsx(cM9U wp&ù,~fH)+W8_#WԂ(Ҋ8 C]BFиFlQcjkL[(""!immmFr[yn,#;r]ۻUwnUݻWdW]<cl-[am$ d t)jױTIW\V(W3LP VGyw4x6vPRɭ ֫UG;xU26[:$]+wbD֮tғ1' ߆Oo}<ٮ싵_hN~D͈ΠPYb;4,2rP;񡳚npʞTQ)TWGkeH "" @1Clmċ^db`<*6W-U; M~o:k{|> ZkL)0@fw:BU=It]E|pKX9& Uqtkw 1}YJX(t 9Uae& ϛ(\tN#3iPY]a JNyDYJЂUb,`tbWU;rZ'UV5*xTZ5È'3]SsD&8uR+8CƺR mr&BB@f6TXI,T&ukVŐSXQ KY ! kBYL b^sY 894t}bzڂ- ,. Ia}V  ))VbO ֞UF8LTIMT`Șb\bB_F ﻑP$VM`N4QNԣ.g $^:(1X,_5Ub-*hV-KTVRҫej[`l-EQZZeڴV)mb+`ªV֨V+jѭ mE`B,QmQDQ+,lEPVEѢ "Ujʰ%ҡVbZ{wۮǏ`ۜOMxW~()Eة7lT 7VPb8  Zr%`Hk1qKsx [,e$!"Mdoc.Pᾍ 6{x_E H7!<\_g^ ZJ/phRm}0o~H*?ʓVw#+X+HcPCZ;ذ]4ݳ[n*4`]*THHL'A&SgE9I+*خw]qxOoyz^ntFd(&##-9=U⮍R0""PC6U uph:޵&^bJWT3U1tf&TV˓#hVi' Rĝ7;oN8֢934fPIlnܴ4J 32hg v㯿lmĀBAYZ9ߠVApGh/fǨP&Rh.f9q=1g=9er5$=.+>!z&F%ImZ蟡 Y:}KF9feś NelARZ9媶"M2e -;2oJ{.k_Y HuS.KvNұڠw&HD].cw>H{ =(:iM d]O]4@QpTLI+HJw.K5Є+,+HB.&K.uˆ&Dgn&ɞFL^/IhH p aKMDҌTn{Llj,xl#xߗ[efgwfhҀX)hJOwumC~yяݴ҄3 ߥ"8#C`H&=4/-4,cn 6aFV_ݭg%.$HjՖP9 1C`ͣy%~6lO#y5㋎Ӈ_xakݬo\x+DSaŻq \eFv62Ӎ $"rJ3E'wbr~`jrD _<7^ϰ8 aᩋ/ 2d2BUDk1jh"C@HhCL0LNr@UUr.pR"$iI) ~_^챝Ue6T&48ΤPmҒ3& 4`w",5`OAcYISmzp6JD-C(=[OiH۰ ztݒl8-t/|Oӧt\w溻y};x͜D׏L#gC唥RQAXbeq*y%6iy"{O9C<+<߯sЉWU3)l҇|1qOZre1F n$iθ-@ k PL-Z_eY~mW:?F$tdt :@%z/[Jg=.ѯ{ͫFCq H\vd,P3\c{JB.beN>Vci6&=Rx}Aoe3n;%`@|%ֆIkzI kvhI/YM8YYx-u8('Z IhHݢ n oxaLԛ/r쫏-55nZoƻCT4z ӥ1ss;K.<1D"(cڑPXG,g%BTH9zg-!o;񖘃+y2ﳠy=;720EKv={Z'hR;A,(FpA7G׉Åʧ6IEⶸSYA  emVtE2,gm#]B΀ۯ$8\h<81!pSE 8>3 u!d-D> 4G;`C Ţ@1C"͚ҧB[\kXx$hR=,]Fus-&ZE@ ˝k}瓡xbA۠%8;uab(f*_}KN@B0H&ﮢ ]f``(N{cߺ#c:BU9BsFuqLN]Gi@,⍦A-+:1zדK?߁^hHj$ZXXX* dV PԬ ړS j)kb"l!I՟{zVd"}&iHXB>>_y]ӹT1{fVo@{})gwvl9a&=7*Wݦ7EC# @HTw+Yw M&ZGH.d[|nёvw 3ӳ +cS᪨ݽȁ@R ND ^ 2Fq[aZ[D\DlZqFrpLi_'O;FkᾷVo:!Jfo{1ѹ3Ov?QȚ\ϡΌ'ԹFL$:eG/:`biim6m3j˄YhQH\УpknFflOJb@M4%n͛^%uGi,{nN9:B'4F~鄭ei ӤѓSlˆK0'PVd3 c4a/g? tVM!]jhѓF 6I4XZ v 9j .L_CïBs LQ2(ߙ ~^p@dt,|7 i,7Dl.|7K߾* " &צߑ'tj=Hx4#@Ǐ; ȥ pMBB\@ԍ#0-| %LT.S/k++1#Ju 0"'3m;!\;^fLC馗8_ui#./sĶk^Vxb!j۹轟aO9@ "PY:),PXO4EEOJ  TP Li^].p=1#1sh1IشЅ^c(R&he S`ykeA"R|J'9yMow2WA<[DfZN/ry6lBň#2$s3UλHmt X`Ϲ 3~^Վdtx34!h+ c(jڞ@ټU=g| D myl]5 rER5X/_Ȩbln7 Oo;zRv}i~~2,TG`6 ~~OX1z~m=mo8MMa(MRd h3 p 8Db$*v5JB @HRmdfwRAElQ _^$8Yq]y?LB^2-lYI^l%QTbh>ƖS 1 J|7RƏ>TϽd;4͈ jD6N~@me鹄; (뇜1u[օOs1Km0hzK "_!%/K$~Nn#Oa@BhՒ*6#䷽ w4X⽤k”"O8.OB8^̟bhZ bgq L6c㊫6|],hl0h9r~ 7\w|4w "bW=iD!TI`a<}^8k.BFE |Oxr ik&鴗fp9y}Dg3+Ȣ]9UC%+ QEӁm#wT:_A,*fTepckߡP[r̘wtlX3OnO4Zm-EW(={3ϳ\ï}:?tv xmߣwF R;&DnCG^qZ4gӉrz< @(0e`8Աȥ1qQBx8$T8eEraz3,Vw_Z"ˎM)FbM4}~>ؗ_olf߼v9>2Ȁ:=]L1U#%f-?= ^#h˧z|%hj6{}Z:3/ˌ{~kZLǒqz+~n="#oy}v"*F{@ g Q@f.==G8G*W[M D:_$n&y` ,nۊpX,RQh5 bc5`l뛨b}>'1[8lWz"ɴ 6N5`a԰z٪ssC |a}͕vWE_0P/JA$1ByM= *{^| 4WN r'!t%D'n Yj10"֐aUR %Ad™zB{iVQ6饇%mOo\&)#2{|.YbH~ɚ.2+;xHxZ g[C<'se >[ss$]jpA$>G.u5;7{Rl@p( |1` P(0 1&֬$r 1d?ni3L h3pȄWaIcX}ZSuFFQqH̅ᝰi._M7ŴHPrxɇ*O H(n\!lQyugP^.^.3~!Ti/,`t:qh"$m#yC3J-PQT^nާď=||UV@;'K%c2V2B(| ͹%kY$>dI׾3|N>t.2Ö5I-#:ejxe~{6*ETAQ'kEV?>oɟWzG!sW|k+>j  ١ܘh&D"ѡlXi^/1 0Ñjd;)x9|x۾ubT Y"Yc#^ΚAƋGd4\0y83v^bMg+U!-U1::O;֮fRB#Wg_}1qb >}^T VI'r3`ty]W =qG܌OVF mۀD-JDh=wϩ>'sEbIeZY<;v݃%%Io8W(õiVvƐkk>QKxhW aĨ `ZC_N ?DpxhZ-a Q?C?LI\ okaɘOCRw}t; ?Mtn $ aB^l)?8>?:/ιfЯƼJۂsKD8fuieajOrago~!dbN &WxoC`kbQq`z؉)k\ B^P?]>t+T18<,q83K|w ?Y~}:b+N5/-M[HNͥ)c_{ÞYٰ;2vmFR"&ښ/&Tu$m -8$ !d!(JWوdQZp!ժp S-T_*zo`:\t8E /7C0~ܱ~TZIdJ$\\Q*i{Ȑ",;[dM6ڢkYJ?3єLuc,-%|ҽie<-5jX50œȧNOS>=[mRgAHZ n`)}.^}m=9Biꦞ\oxB,G/@9 !3̑NP/b@Z5gʓ'3ؐ13Z9<-(뢨L$P@:hp ̄n'pXoJ^|r7|jE 7qKϹ~WaِY>T1@]aVB(c +d}9(G+aLIdFe,2;UHhM6SJ(_Ȍ ل*\${"h"%ԉRe D$AHR H@ETRP-%4R1%I@4PDm"d4}MUbvq1 [!0aa@59ڮ;qX`C6zyU#oCzmpZ-k]~qy>ԺyҹRV袡h[nk'l++հX8Ṗ.R14.(d n\ORuT02Ia1T;zcmP”*U+'NgLy&aקhB:3jڸ}ߦI 4<~|xR4Jq56My5ηp߁ߦg=v_z5W Pߡ>%LVffPo]ϫ^Kn׺Cfk1sm oCszw/(+ɢEKǂ݋hUYb'v*%1ck&/HuU/HQIY V䢵iJł`2!H2|k}P By2XDDŖn=T}>yI(ȗj!CBƐ)[SH-2l67}}*ڕ| =jԆ)Uj+a{IH!ccqip_ + -.J^Kr[u;oN#_ 1Bq\&7))HOi78qJ!p3k})Bko0Ă`7)ael/F>;-+Ս7#ʐzG: 8UCœx%su$ANH~%.P$ pԦè&Om#>^3\yrIm>1*Hy4'dCf6A  JdN_yoݩ=e2Ou ]=62vT vBPP!@+H GP&(P ҽ?2y@;蓳g쟴vKȫ޾|6ko;C9%E`r n E#Ӏ ^C!lB N̲1_4ԆXOZQo݉1ڪoRH1#8R,-_D$b~G&)ں2tr[K@v!G0S㝖IWBc5 fjxb&JCHm9sً-mMs33:_4<Wo_k3xwE\ H~|w?|=Q~v ÷Z\#s3L>o? '}d`z%{ S!J~,Np널<ZfC85zΛmxb!BVz+іOoJ~*f3RwPq$-er&Qo"u{@AXnYUHaV"6ߞLHH9DQ\ai,$$ JƤ+rk*-B- YI $Pb[aBk f9Xkh@4|0YP+Qejk)Q{= Ch Gpڙe>»?.gUaPqY6(:EL1 7E3OL )XK;SX9ۉ|8 DBfR)BIN0:m<~&[;M Ӝ$t!ʺt<a!QM#QG,i2d] Gfۛ@,W/j¨3[]=+Q縥(*׾>ڜmڔ8;=B^0;`x8(z¶Fx["<wJT~멞8r9Iat;{]ovJwh湜X[H"D4Z#4}pڔǏ5&0 9RTqDG|5)7JauJQ `?k]z}=0-ӌbhՎLllx1>&DHrAA yT㿷b,]sKswրOm3d7j ̓joL\ה83 b5 e ƴZEӶM*8#NHIj1h"p38 2'PWD3>83C^&$,y{Tb(1EEWy|mq4pTGK[dx|=25ywO9[ӏ"fd9(:c(܁ tKrV'˿[*E s""ysC?sT%;u,tfIW2J05*3LG)DTRYknf \ˎRp b ")eMBA@BCf٦J!S*,ZZdAWY9Y$,5 I3.1vMȘ\Ra]\uQl)-fjMR N`,8{,[w|Kb^m{-إI~:*-l]U?BEJ#72NZ1gx(%D;U\չϩG,ۉۂ;4tB7G-vzϬo5>'ȽʪRk0rU{UUU[' s|Y@3N|~~־X7KV脕,PmgfDAk:w@>v; VY-4d4Ґ$j 839L .  Jg UkI-!N 0RD*X5UzPÕ)ޚxEZyP;N6D7ɘ%63`失zlMk$~QExɪKJ=t 7H-o Z)1N0p1i]e|s{\"jc _+K%TG!y4*bߙp=SJPz7FnULBF> 1/q!z5 1Qߒޟ5:>@R5- Ab{؋>a0*`CM1-)H)OGʣAR|xۿJ}i*66Ė`C T nNK1_9?ѫ"-u3Ka%)f_LHE5[weO3 z]'+=1 ƚ]eU,!mq:.mRlqk ۅH)Y5k/§V0D/S"X4T/un`QC}|yy#{իXe\dyD,`V`Yh-L\+l/ltK@:`GADYv 12nXehR6HL°ø[۩VA00 Qx5nulЛ0_M0di6E"@BHB!G_Y8_3Ċ=j}E 4Gzez Fվ_=t^|A. s{?8x ٭RLwN\\4߃ڵ4 {>}$r>/yfŽuaɏ&##{u~ݶ'UzN >JH&J(hJ@ib$1/oMPxqym5׏W|ǦT-C@5c Va!r@2BDLxfz QEݘ!!VJC8 :oסF{sW Ůfno.̴>\g2}6=}BA}<[wㅩzSL S괇JÆtIL3S_.l{~geaM=L*}dm4^$F"K)BxWc:ɋ: :4J PX#/.dy<\.L8x2Tw0kVzkx5q F*1x>oo P|YNOrvEN4@=Nk_>a)>j+= Cꜛiz1 kXZ?O\J(bޚ=3s7 f;MDqLP](U93;\乓<ABUl iL FPq< xy}~Zjeq&H7r@Z/־Oؐ^oxVj=_m0qAHeDQqÚS {32w"g01B]-欥Q [sq>APlL: y:$3OUA㫂;voi"\@GiF"%20!&AN@wuijN3u&{K1 ['ay4#έh1J^ Nc[k\4+4I!﬌S=<}y%˴RYSHRQd)T_ 2,$C {dę!83v,{WOJX%bcۋňjzRAv'9;s&PA{{A|PrLZ[J~"=ODx8mw~gGh8}F`xD+QDӏvVN4X`)eAbӍ_Ky/u. ]์Ց $\Joue{V$.;B8{xZצӶ'\~vY{1#~F[ZȪ 㲃 *;hq>u<9|yk7~,\1ώbDeFNls! :q?f|ۍ C^Q_e)9t l͗vrCc\$D,ep$%xHn[ԬQS '֔lp'` ~4$(y:#c9=Xpv8~󔦝~ߨiP<3<^hyM%rɗ jξŗ3qodeS`7>oɉkmaw;tu f""#HK&GD90HXD8i>+fhݐIFQD:$6ysN`YrbƦ\B:©( H sd]|1 W}\% u'?|'TryaWR*.^;ܦp . iV`E3?5FSxhlD y@@əRF90@Xmy"~ZEmTdV4Pd:D5ͭ358CrM 8B1vSʰV5XܬҀz5w43c܆H.yfȋj]M?50,T;:YG9z7AowPz`=/*N0JTlmZ E@M&'!g(z7cրs]%謻 prDw߬;a~9g8Y^̵ HR%pL1TK۫ O!( *}))A6c`1;EUS) W$𑲌dh,dɎ𭑗mC!nT볓2Üw"?3B(Yk'zmjrIw~H||uܡtuaTFT[EI痻>{nPn0ER.g8ssf4|XZ1~,8Ȟ@|;yXրHaeTF;V"{A<;x׿d",=W#v B d͌1\_DY5# .mRCDI}H8;szsyqb1y|C\kLȂTVuڱ:$/W+/Q{;^!8]5}S{U6>Bqf"*SG6̓d0vWkʦhzTa 9!ApTv#J> 0]ßU١l^4h XJ!I5nPbYݷ׾㎃ : v~9-CqW&IAע` Q}]h^i >C +Kx%S1|jjĈ!5m~M#BYϼN.6"p5BpX-;P \PIkK$JꪅB,:Ȉ N.R+]1yĔڄaЀr!em%i UJ8ɣֆE$m؅\t hs/fhda覤ft%03"ԓH*3Ia`]w߉{0@86ViiH[4`U %v;hUMP!Us)cLNl^ -p )4!p`uvM#HI%^ KTa󰨰+L@dhN.db@|W"'(ow)eD;)2[:+9%\`$A?4BA39@BVj h!C~%J^/H/!LDB81 ʒ8V_-;Z&r0Y¼ق,Il1Ad*jj0B5)QEt7V_znJU)Xbq*r'c)Zuh >/&+$;;+~ώ*uipLtͅvG<&hôG &\0fmk 2"RΆ}y<̉!  @LZ$-McL"X Yj!fiF({YmJVӸ:&Nΰ|f0o7pS/3Y!~ Q(K0XӡǷaK;?~Izv,Of_~-}G+a=~g.p8cZ~ ^"(#ղ# @TkAAWK*Hm A fJ46np 4;wp9&."&p^Ѣ4 ttr)Ǖs;p0Pp?WIbtG zfmEZ )7<y0vYt m5BrI0B@Es0 #,}i=~WNa!E-QXTR&]k.=&l7ʧ~D܂GVj.LN?ElϥB2OM3BBg6҇܏˙䞕F  ?çcI!*ISi/{52Gy 6GaV,i6N9`DǮW':nj,2)KrӧGeMD;ޓv{qQ[KPdTiZ6us M6I{Gc"u}3싢rVSBVC)J!YxKRT,aj߿vGhgMɹn/.iL8#|e.Vz@1HL,ގG, uY.:U23RMJZRM6uQtBTo~ ,=}$p2, 3v»e*H>Uh yXȺZl#+Fm ,5EU)iHSE gϊ耕[Yˬ&(|' 6㊃7jd8m{t*iJAr~=.qicCBbvpv kRyc޼mgYiQCt"E~IC >2)rm!hy*twvONu.z|rC]؁텤iwSsRd~o}b;!CmPNVZUymL +3r2έvκDi&gxr2^YKKP h1)lP6kCG(uO ;xzz6!m/KSo%0Tsq/avuC#kz;KY94 .݄o_&={Ank33ջÐCХ)6F$* GV}*=/N'V~!N+L*,cU/o뇿 8l,]jnb=tIpoxoɍƣz&XVgJ bMAJGXQH[^eU:dD93#]j x$d"p,f/). OXi!64m-mњ4i+jejPM:S?趛/?2\% a9Vn >LS%"i1dE ok#!|gڮz1H +O?ҿ =qΠtىj}xY:mS87 ~,J/6ܜV|**t/Uɲ-U @}|;aXPf? -pR4J_lm63hG{0H*4ظ}C3 @]!S65<9MNS8ڛʉ$R!bDYE)glc?%\ F?CG ҠڡErг>Hbk"_d%:0K1F #P>Y +|<3kvM_]R/q{ lcMy5$O3^AX\cޅTi0 M8=H:!)@If1\>P7mi°m!;[:|>4\oR *_X/öRp#;IS-qJ;((4<<ÐS԰zR3Q4bq[ t^RdrOy+7'#S!Fgqr֙ (Mcf嫸lJ= и pYeSx1ŎaP  ͿUxv#l IQ hV=AeĕC ݪ7!fbW\qTnƮ!ob¶09"5e]!Ã,0/F8JJ v¬x}^5]IvS\Cg-hwD/Jhؕ߿ ԝP>?V* >LJnT<$?C] B)JCcb?8C }?g> 8:VyXqxNXm0@EB*2_Va xߋ\0q-6U<1jT ZJTNto}Io{[4-N-vO=˗Hr F-0`R~˯^ϒ> ^/ftzW:ѽrSۣ 4e+iqJI}xc8] Q;%dn0fBh"Mm`^T^};;Z(U\d57ߠ 8u{zd::S5?B<+jRJk\Kr_ #H9";V5KV,BHƠx}hW"JCF6`Kkܚf9b<9X$I^+4&P={5{* $`6 Ww}ʓՁN3:D$׼h&+s̖ctY5+ !Tx1(y5VCl4Y"\4Ph*j GxdHTO% zUV7+e%@O[>g0v.ae|Dr-W\qX|Kũ}CΰqIK1 W@Uыަw52)$ q0*f.eZ+ f+L})6ӓ%GP 5"HGeγ}ϛN0A\Tyד*aa1V2/ nk+a:)GJLC~퇌@0&0\hLU'$0fa$q /Ykg*O<8>fyBM>On?'mm 0[ԼC+BDD,⫐IY#]F[ҾA )h; aw=[k.5,K6.7Z sh3Xn̴bzAk6٬nWcPp74>V92-CI겑$X {p(kx)fGw*oqmM&i.7љ֜\%d0Iָix$ yW(Rf͇tJC4Ӡ`&Qc4c񫻥J6*0}-e/obeK_U7ZZW_XzvƇ'~+ #Y7/I3mӌv%L)pHQi}r ULk^[3{W[B=΢>U;AKF_1-,q/X 0h"'n"W!RO=L\TOPϛX!p' 8Z*r|C:SX0NV޼(I9LdD /ek/ǻ/ۍ _&?uMr6@`fEڸ2v>C%q)RaB(7 3FF?,4C*}W/ٞ9 Eu¨3iT|9*2/GihUk,>[;#TK("j+2COU ЄqK4/ؔdk`>Լ~GMQ-D DA!S=O+{|wЁc}&9)ۯRt.\r F%MtEh[ַF[bJB?5NJhtc!KUn2?caLJT0Ub)J16, &DdFZ*"Fmkߟ?~T?3 }_XP*0,IOǑ$~r64 )^Fj@9!Ȥ%U{#ٞ$Rsgw:*}s0l1]#EWPuk!oJlW<x%瞧0nzaB"n/bxE}_vRrMRԐDB~~ItCa 1ӐN;#mࠚJ7& _lC)q@I)pI7!WIlI$mi֚!i:[DŽcQš1mm^@)E"@ "De26{rrNE0&R7Fb6e'XvMr4$KQ\96K$9VNQ'"i_=|}x0L3~z}_rK0N 5%@X`=[ҹ7ҕ6 4 ռB@L#>hDrr<G0];+򄚔TbBjYŎP#Q/<)8J-ћʴ=*gfU0çj+=!6_).8IǞ;ʼz)(*M["1seM{9v~{~|7ł #cE>Rj~{,HMK!sj5Ș! BQl~kϢZQUAxwe0˧xuLʞX/~l<  "9ȋ~nHյVbq&JtM)3rDB n@ͥcѳ/S6rJpG|ҊsYIT+4%8îuirĤ47-b ºc N܏׶yWkE3ZPQ F߁ԭbf{\u21T9+d:(fv "@"(Cc ݪKS%^,(SW\<{z|RFy0sFpv@QRypm{@ӦiSriߨ  HUdsx3$o'<&kJnPXhUf6o)C5=T >&'7<uoGl`3,|x^S|6ΩGfԄ:'ntLMK{٘390uLDg=S}B(~OTZPRdC7A# ?>#c7^4>Q=R:^m,͘{yX:& n [OYΗVk4% %/caxYiem0lUIs/;7A;i,֤պv%(wP 7SyO3 E]XC?G~$K@EJy(dPZfy,QJmI\k1R 7IYX,!88YEt&( յq$JhbΓ8RTYR d1*Lb1 AYRT'먡H%+E!25)&$la!P!YY dz:N (*gJS0P!ց7l@@HRP! C+ !HP.mқB@@#hU~40pR0U"˖􅜬2dJmpsp|$|cP }Ci'^x7;F~e2/*dv2ϪlEH.tBͣ04R~ 8 ; -%)f|/D#·Q Oj4Bj"""C 8aȖ"&eDJ`9\""#vJ;}Rz{E$ol. 9A:.JcBZ mgz-0Hb#05BZ ")Z;KXD20<($J?u[N ߼R>0{лeHZG br 08 m66%zJB3txe׈9'I8e Ԍ!LHuB aa+tR[%aVXsk[Rmps2VHB9bSSJEV@j]vYy@PMEH.뇆X\r@ P%P#ACi6$mMGCs2p7úB) kiHP PJn=-xS`cLUd3f@6L@CA7F ~`or95|b$I0uveeiDz$Ӱ8ӈJ6( bHx &'R̡eiN{5>dOb->BCO<~u9`FG3wp՛0LpEjˋ:?}J]\Cfa[ 0Hϔ$&C$eLyxmEޥ+Xheǰw=|5Iۆ] zǶ :acIv0JMm :HaJ&B@E'I~ծٟ5<`I<(RFA }NeôoqGIsc4=D '{妈i x (JIy=|z{G).kRչ~.^e*(>.a䇜:hQ{ږXTe((' >?W,z-mdňϏxIrGgN5׷)^px!H ñ' DO>)  y{x8>04xlDHaXt ZՍERѥ (`ҰUJ1-[#>_аdo*V8xdu0>=ԂJ{=>~<69s6"*8P-IdL$j(L uC<&&&9iRL#cc巈[!@((_t0kxH(RPo)%(?*ږR_o/.G.BĒФlP5@d7mOE7JTO{PQ UQy=${qK{b=4 ߉;*v=e <͓hGH`^~Ow8Ub~߲|ܬBAV)$ ٕnK9B E0 9/{0bF[aE,U>0rCj&9c|D6:=$Y B`;i|#c98/m%E,< V#O[0)J& "@s(Bl#xhe8}`nMNXLI':f᷂.Č Ϛ&VkI>5i]f0FvxׅA >yBgK >͑1bًjǺbNbtK<<~Y.y. iJq*ABC2E\>,뜶dM} 4Vm [ lw:+X\5gzOŏwI=TGRxzV.n>ϋC{S;a'@{ުl6zpta!j kRA:%=_O-W<׃GEUWm@p%7\6D/S+ZDD^1P)¢PBs= j&Έ,1/Cq3fx;E7.'1w`ҵ[{5D  qĎޮTݴ@#.g:1e$4z78<сI`>|;q˭0D@=  kP[dv[Sj YdAm 딁7cC)^e#Za'7hXsMU$uL0ѴDZYd0elEhP"K1@}_&һ1ƛd 0-B&VwB+eX]gZHXv#aAm&&\UGBĎquyLVz *wGdדC|84/fLR`?+GK%/& 1qxhP6Q^~@MZi, }LF7rCKz V p:&Pi~]"G}{(o+9h\ p$nQVDb˶YD4ZЕψ;3}=7kQ;#Zi aI3guʘ}xwƗMf%ȯ6S`W$J#57dPc@S=:A\p`¬/kUG$]=iV+,R ѫ 8ؼ@@7]CLNe[4w cF\ĮR0s@15xgΤM ]gj 'Ie2].0XɌ7Gh1[`"1F-U8jm8k%Yxd4.ʟ YYfWp׎? p`o1[mKC1J.6ZV8)';rTߍ" *m])[C hn،kvx*}a2,X| kol\LaskE) _ 3ϰCe#,LѨ1BHҗne"lA}Hʆ!50^"5$PK&C;N F-:MM c[8s͕$"s=A|'>[|0ꅻ9B'/`~a[cJ]V’2P / <+FmMlYzÇrx}~iDF=8!\7; X^G0,p`hAɔmey*Zj*+L~ ҢFA4V'x%Jה}F1t#Wa zJm^A T$Rؒj|ejC/0W.XXٙB6\@󯰅qu.dž! Ҕ /#,.a$fN|ta[~?;~v;TuKdV#mk6ոM *>3[pSkhZ'k%hZ'k%hZ'k%hIqB %ItϹnl7{lti:"fsחٓ|Cv]죫Q$A }p4د%x,mm0R^"JPf`Cq- BVtx1bZ'k%hZ'k%hZ'k%hE.B* i*O0J WEև6= B(($hLc36׾! **ͺ)W:6@TcN4]bwV̚߇c qF+ (dqeɮnq~>\HOLl?ê{)\;VXᑄQi?fϦ~c8>o2+SB ӑ*ќ`iЮmߥҴZ襺?b kOpfӻrᕷ96w~Y7LJӠA q'/7*z2q<~-ND B!ީ/ #g˂&c#_uJph^\pPj>\-RRxnj1x9| y˝Sizlq8)!9;:IDk扮/[mSJȹp%ΎN<އD) SR[o.t q2BqIdaY<2j+<  XB/IU"Yu;O/ߞ hSW3 ߏ1zր0qMp|$G}q(7^ ?㉄DH$G='Cz(0%qĊ,˻Ԍ F0d屳3e T֣Q/B>If G"W3lG| mkz\]yTV~ڨ^}?ihTʸ8mzm9V*mȓPJ'^~3>v|àP2solSѴJ|>n-#_0W`C,p#Բ +?4ՠABK4?x)y%j!oWv"9`҄+sn9[f487S_v\2(X*Up\jÂzk9us}GSU#O{-& cDhdH XUM Cc=pr,YwlV@  Sps!TSh0K&.Wp@n󖓼Vh .p,pŜ$OY Gi(q>WӒӇ?7ITOF^yRgN1\2}ܸm54%RVyrGD.'I7zX$ģǮӧ]O/bzyQ_ bVڊյj+VVXUj+VVVEx|l-E Cv:vB69/L%2!߿sjt5PrĈm |Mq64t|߫ HY)&Dz C]{:5)\ZҐCe u.Q`t>-wj 1벬 صW3TP99d|rLqo\ۮtgVÇ:I(ńL);Qt-i+Ώ,qtOѮMЪ3| P_X  *iU/ @^L"MOhWW弔풔=0ML(Cx]4zkmA{&b@hxD"lߒ/1킈p(7)/ף ^RTX])~ 7S`^7<έ6ДoEEƄ|ztG`Ⱦo:49ƥPA `st3yr9r)< RGhƩz-( <PUB'|}>[2I!={zg)Q bDXb$צ[H9 bz]˖{Z%b6"vV7Y4QAc- T˫H$L24DBM1L =82CxRȕRP`@Pڍ4!GT{grc,ve 9դu9vz7^f"e(|f^\JJ҅f&#!x~0%@R4岦vd+Aa@" =i ~\oWǿ:I#qu}wvzǹs yYF׵>M~م:xk }qӦe(S F>m幒cƋm3:N x^TS>bnXya7v4 HAfLDq T#8(.ʁbhKmK-&>.:a FP1 1 tj;=1Lڸ2٦^!ե+y I!xl'IFu08n.IYzA*eV5thHγXxH cru X|g@&5t:{ Ge3Ꮰ=M>݌: 2,pjh ED1b$ oj.rgeO?o~ sx:uZh}Mp&\p%xKR2Y_۞hgBl aץc'3rƲPiyx-RQ$'}(, 6+ dҒ&&tkx苲ÄGԵ IH׎Gk^ޫ_1PӤhyMhj;ݹm*#fBHn tRa``7.|0^"pH#?(C:V 4L|[Nt*)eܻdVa)Wi\!_O1UҊ9$.j{C"/rioG- :3 bALa(PcT:fQ 8e>])LtA{ϵx7a}tb $yk?|O?AN>89s|w3KaINt' 5lKQqhف{N\o՗ƺ5 9;a}/w&ۢs*le5BB*=z姈eh}aE.?1:r1L7 ~*gRI̐jZc ?c۹@Y12Zk&# nưܔ7(¥@٦)q$C-w2^QDdKCSi ~nb7|  K"`ҭ(a(,^e~A|0h@AХ>'  [7S<լ@hAbU x:(vN3[;Y}?>T>\11*:6v`]lt gyҧo{wt-LQݩFmbv']Cm x Y?1 ^82SS@V^OpK iw7!8po%]y/VmxQ.iE32URhT<2yrD \EZB? Nܔ~N6;]!<ݗdît8phfx]%C+=rdzk{6K ^y0U5%F|JvKfl8AÇ!`2X)[연Z#Oi yM#F~{Xχ{OZ7*2 OoxtTW&akAtVIa)bkFR-O\9dT؜쯝JۤC`Qзlb HKyc,$9_!<1:MsmbsM害m6 U.kk(JǵBE3\ǽ² f\[~Gf춪9LfͰnóv5ɲtH1zM.s * \rKx]­]QvSG8>cǮwUϮx7lGUBL]GiW(p]^\DD@8ho:pb'ڣK]%Δ|B%#vaa&L0YUO$[?s]jc76Hk(>gS=YuvNZ:~#TﳗyWb%c3XX'k .h H 3d0ٲ䴸(Rf,R&3 -&TDV#))n@3f0pc԰^.eQ)Q3p2f\s7Mpj\ܓC,sw#!G ԢҰ,uneP 0˃,$cd06[`Q+E8 ֌JYmlq,y0clUD!$-&nL/*p61D @.TLTm~^{i`3\̶ͤi 8Ą(783Nz,_\7Ç !u3m?F4V6Av-!*0+iu͹v+nRJۢq*gh?,ؤig۰K{lU:ܜOc9ҵe0.B 81c0s[-ia㽽$j ]'IBa (cFBKZlm/6>J{r ˩MrEb!×@L)sfDft.@>/Yo3&9R}7:a~DHKB|a{=A )lXHZh@H[vE/'NXV ^pG׏y/ NnLMέDVjZLݹBs孷2YfkLn08 d*#68.$$CPIl<\8a ߌxEfdxgv=&޳/Rd*ԩ2d)ÙWbUZ]死{Θ)$Gm~R8ٍLOָ$1(%[lwEL+ٸƖ nؔ"fW)va3 *F̭iI{ZiTWp 30JQ%|C"2A؈-ՙQ Y|W^^5Rtmu_~*|m- @U0֨sK0č"8SD&A!bל ff+*tpN,l?Z`F$lSEEV,l8jg*oE) v7p Xuí$Hc$3!\sxG2ƂH'G Yp? 柒?`q1'bn:eX:A ˭ڋk)6\"hK:H8#~gG~mbI ~L%(/!>Cƅx8A68CR13Y8 ÄU||Ye~,x{&VZ,TUAUR"7s,>M~ݯgowte'|_Šg-c'.qisS <泤=bX!9 Cp0s6}GlcCo'(?{ŗ|_Q~[}ok=5OxuTuGIodhp9!vDTrgFw-h31~ԟO>?:(Ty?b' _oO  [C:N"QX}b{2') k8 (c?< [ C)j@hxsړ8'%*&%7ՊNQOy 4frDfWmqןV1fyㅫ##Im)ۧ^ A5#bqj?\MJm$@G7S .D7V@`[Ԡ!lpPl2BLK6A N ` NJ㤏m̕|cB- 9osוN9pA Pz5Oe8}pt}P %6h?Vdfچ pxÆJ;w+0&`Yh9 hd>aK~Oy3>{ϦUֹSmk}-3.E(QqUZk*ygOzVm,vaCzLd~6b Ӹ6I߷469)R"L9G6HA~r׶ K%_`l#<ٛcBchlx@P uJ6/~TXS=1z#*stTQio V\ 1k[Mub=~BC06̍R*7{L=|ׇa1~U㬾Nގ3s|_X&`f(Ep2{<c*qیCNamˣ~i/08T,^579$F<LfR`3 1LJ1@М:@Ζd&ZDb^*ōh.e4֓ N>6_D4xd`~޹ȸf{N3'fgk=XHlZ)kX9fܶBDDvuD*{ka96=D|0H z/$kW|_NQd`n;S>2boHJ+fuVq hċ-L<# }/InVd 9vLB~I{NaMZcVx99drqf#!bJ0Ȃժ1KVUTHmxV9ln&h)x2e+"3aJk!N4e\8rΛ[9Pag(W =rcq8]gXRǯj:A;:eyn6 h0f-5nB36˙t4p"fԮM HbġL n Ad E8!B;`qs"NnaTScd۸QQؐԒcG3!Z``e uv#fECmfY.ZIPP҅ ;2,  hQբR.HfVd S3#%UqȫreR̭3b˔UUq0-Y6L˒@*!s2NMUiEh" H&Qq3m0`4cZlkd8h7LnWs\*̦+$I%K5'd3d8܆ِFrP2 B+AC(UF ܖ&[1aW-DѫiR89KRhrmbPPىb(QQ\hw JT%Lb!Ȃ%@H+H֬ F8^OnF5;o7~z[oECm e`Yi4c _VA$ *  WC% W!C>1G^4P2-Yw6(+̵G^\V\axPߗ @j0IF.T|o{ Z67fx; :,ꝳy_롉_|^Ymf%pz -b`HLբ=9g} eu>9s*ڍJ!d|e-,nTKF63uj\LLaZI' R9 P!+HC\ ԥ B$L\$! M(!( H ]mCuE%Z JHU,$lա54+fF+Jd2lL&&LǛ&f0êV 1(4T،usd&2c$YKcb8a&f'G&k\|C:+(Q ŕRfFXRJgYm*Fp~+%L32m+ZҢN]\9%z`O_årQ3''d( ALm$&]!fǃVEO j"i|5ᮞ FrR n)v(-m-ܸoc>qE\7<ҋjgׅ~`4P%]` t#"ۗk_%=zaqKW'opRfHƒUL06۲#[O?eu0pKN],:P.)%&~4(dP!JPLbÍd^ۘB4n(0^̛}nwKRÄn(bٶN"dd^ԜKl!LY )Hbnw>DH)'\EB|\`XڻKm% ~0JWA kfy$ld HGFad,g>ߞr_%krI뽐lyl\@!xf e0Tˀ1m:2XՌx6~|RdzWö(_ɱ!>$8(IZSݏї. 3jKBl*xF/e}BayU@}"pp=$ BM;]d90jW悑pRaw9Tt8 Վ.s?oj &0/}]RE)b> uflK ؆@G 4= u^WkvDs:` ˟9Y*rw'Kc!"3!_%@olKy{,!nm)Tf6|o |*#(ch?3d%eQ2s)O/9P֬l A=#?m J@ M"…OGFזþ~>z Ay,mPߜӍZ;P+{\}}HcGřO34XYI+ Z, tR =8͙lF첯~X, mYO)¿}~ULb@J7CL;/ j~|~'DS h' ͲM= !Ѿl\0@V/LUS+SV_]'=0݄:)脜~>>J/S8yHoc! )4c!F,b/0>igO04~A 6$vBaS6&'6ǵ.Ь*Lk<]UIĒ}lHxC! > Q !Rt/Yt 0Em#ʗQYLμt}=O40ȁG2 Urb[J-s.SORDe?LhtpscځVKqh/J~ Xfg&Up |C #tri"9T8)']0;m /jP gmE}ʆԠ2:OlvTo E.tPSzRwX4;BF0/%|~&CNbd 9DƛIюƶO44= -Mh;0<`%: S* (TS!;P3')H$ړBH0ጫΧfz~Ȉ8ka k0x!1p$q) WN!Ĩ+N{oVG amW#%.yap{gfY|8/x޶2ɉ#ņc!8U2΅]k^)Fw6q,(KelCKk;\ejyҩ{sӲiөlHG<ǒdŊPCC//-:o7lxu8R$ F8Ӹin7ڌc$TBDnl14%ygPbnGGP޴nϏml$f>$*ZnPrQ«|`^ -Nj{FwgyQ;5vTNcmorI!R.S+H 紬Y7~d (1]Y`5B߹_!pf ͩʡrAp,6ZbFgbm5`;z^"g^ YIDPR' A>aHé1 eѫ%֚TS_AgHjٱߏP"_Bc_f9J>t"0n{/Oí j;y(U?1`6.` Ѿb=UI ARP<آ|5ᵨlPksy}&|5otO:lF~3E&Xgi3~onݿ5LOco]8v&f8Bh$I!ե*44""E}3 j>\~/8OQF/zS2Vf~nt^^iaoا^|#<><3^Zիא)'qxyYe*8dSJC;[ƃ!g0$ "ؘo9`z4~Q3)D"`|՞R^$B YǟCF/"H !kz[was |0ڊ;: JdT[^{UCJ$hhMU Dt\x^2Iޒ 1G۶8l3e鈛 ^']sv <06rE xX"cC;`E~CL^lIE=$| +!Q:DQӽBJVߢғmАq,x MwK}mc0hҔ71Q @Hs O͆8P"c&hkfۯ܍~ŞSBKq um]K=D.`FwPUQ-r\x k9pV~C|P,O%/vەdž^#52$& B粥udr첊x-st,:coU6A G(ŭ ̳Ah#|rDU}ls뀍)A|2Mkrh˓ rep$&[pvOJ4XsHhLep;hcJP5:H&un %﷯Vg.q/(I$dI2fj15Zuʤ`r(E^.i+MUD< LRosd 𺨉$m )3ӷ{tI R 5!/^w%?W99@}zֵh6_լ-kZ8rK=(~=M봻 . dljXԽaTuXpw Z-oW{!VW/3\e˯䞙_zN?Jc87̵k]9.%kZ7YspmN檴Qs;#cWdk~*KiO17-͎-k%^ֵ_oʚsl)HWߗT=CQ6#(xO"%qaЂo>1_)t6j!gQ2DhvoT(y E;؞=$Z>^^6tǸIE]o(-krX)dY3>}ppvE|M)v*o[iU1יRA |9<<|}&XEйm'^z 8%-߸Ly)B"(` QU TRQҁ_MTpΔ|=xSl"FzUT,M=kCj,* axFGS۟Co;+Я3ǝ䒑%sfd6g*p'(9(90|@PIsqFU֜\dS%Ÿ7L{v #]L^}4J 0DaR09TLHq~<F6 7ɸ">SvwVWWe;m|X`A2LkFL7׻kǚr&f:Q3͠aJ\i 4h!:(.hّoۘgaq;`w_:٪;3C^0z9a7;v)7S*W%=].ޙ_?feWsX_S(=GIjײ`~@Y^U/]s&JЦJ]OKՕ oచL&f8@U67J2 ‚60xD+lp9B\;.IU lhrS&jJϟ?3#=yx;9=g]\nCPۄYO8!31mᅠC'z+G&TO:ʻgq^Cuk;/!ffŤ}s q9N8K$L3\Yh#H q͈?_Z7@--@ו? 2Ѱ6TIH ;D@ >HO={Eg/( kwf/#!.9qG~"Gb$mÏoÏn4ʺ( 57[ٴfK.!w_B^Ы<<;~˓nuqUu Ybz8e]l=tea@ljQUD1V( TQQ` c0c,\eũJ* 6"4JŽC!1mJ6)EBE Ķ70j11?0UA LH)Rc*TM)PDPR$ۻv+ e3-,Qm%j+&4IJъP5JQ0)m( )r(!#F,\FA0j+ (( Im%"I ƨB)JIDĘch@*"a@b4E9MlM.F[L-,YK A(0 , Z6łju2KXfTJDLaG])-3˧>ڐ2\|oɽۑdʵ!~q ]læġxKkQr qov}C::|#ŇC''ucJ!3~\xrʷiQRJ|uƃLa ,|AXjAYaAs+u+4qo,3ՇfQL bk9χ33;!U\&8G n1cGAcmm$Ytikt_pZvshb &B IHUs6ZcS%R_ j7vXN}M 1E0}[?5<(q qz1yJC9ÔX? DGWnA_H->iŊ{6~u 06rdcSĥmF1:\õv.syX1[/v@n YH1Z@Y cůL 0 N!JJ@sc=3xev 2,Ʃa Y"C%Ҧh1#I >Y$ցhb}OyZr'IuJֳ=d?_HdEPkta2ۘV@Y5.)X92nT2lf doQ3P !8J,qnSI9JGk2xҾt8 1]V%8# Q jKjU *Z׺Jwy| dwlQh4kf/_tk)Smmڒ-df;ufTV%q[Vm:ED;XV0X#!4<0ҳ= uJ"oGgAX%Z%[6Iq Bê/c=yN9N[g0&i!CH{RVu^Q&FUrOpm8s|?z-t=;Lf2x$#EbZ#bO qhb-=R)CxaXp5X_2Z H6xkrUQ0db@U#*r,;,K|cKq$&sgHt Z0ZYc")„MFQ۾ҜSV݆\2{W]7&{\['wIPi2~G$"hM ^SvM)uW vJ}UZJj.}n ŰYߎ9+hgzԿ8:~ I #-*VAKA q4,- -,̮W02ҩl!:EI0VC \P\@T.J֕q nY.ad3Aq|^}e] @ޜ$9g|=?ف0hњ_(d5!# O#+;?L֨2}0j]9õS'&}=AiOs.^KtxjQMD0+ H [[ _/q?CrNwj!M7CiB\F6S(\ [vUL33 f`A!.r sEvbѺJyj&w!1j ={\qSϮ wb$7Ij5`h3OO6e4.3jUiL \HӘ9mJEbk~0y$gBxwdn@jb}Ъ] J1*@&ko R6 b 'b)3Qb|m([Q[U DvD5'ǀ'^C5ڄǩHNZBIFH? Prx2c[`o<~ooΉ;T.ABQNn a usJT%TLn34S!ٲ0[݆bb)TDfXl&ݚg2 @$0Z-rs%Uc3.2f\(8 7f)19pW3,dD VW2,eCRZZ,b:P r Ru `A߯M54Y5R hN0ې&Sad Z(D'$R P`Y9хĨEQ**J r&ĢEb D0L  B zC7ij0Pɔ }$%bPX %*ufyބUNx\"O=9ʾd,}SKð|SCYʆ~awGl zv0:̞o +Ш^wn0S˩Cx 擦\U3'@eQ,3i_ bDfZ(=5avӳ 1;ܢ,c{RX֏M4͐7g a<{ s>}G=\H!RŵP6'Pna]c x%S}D)ǿ_FZa@7Xoy5q-4 AZcpI'bV$A*4 Ή4kq$* Y|YVd!Õxx^'0*88~Fwi={9RH(H]ߟ#5=N MfȻDl3,h [Tpy'c}~5Z/E;q#hA$X0!YР`g=:k!ˁ[[Q`[0}Co<;fh#I B_)9[w)1{ ԍ"6$Thf#l$ ^-CRA@ZzojE[edbuͽv^0K !\'OK1cQqߖFxmRp(τ_} qJ>mrz>mߗz_ ,pmW*o]S><*g,ǀq~nNt2Y`h,oAk WxΕ8P"@YeZ2kc3 :(9_֘(ݜsqV} ? Py;`ojx(FP+>>vEˌtN;܆] 8 \Eb@+Xjѫ$˵+Yto :v2Z_ |i^#cAB^!*D`GaLsVL0k0V4>i]31 Rn̹2>>?vӍ$nz<8bJu2?<# EN+`6%7!@d 4;PAB)Q Y1LBa$s)OȣSZQPBFrpiklU>g()  1dVxj KvЪ@Œ`V O[kV[Cq3k}9mSmnYX2(  [MF!I)gyH(kֵ=afa~߹v̱ow_ɶ 4%V>=7*XK, jl"ZAiw/z|H77{ NICbYP C5<Zv7gOmFʊ_FvLcSΞ' aCp%_^m$!#HBFrco:[PǶYaڊXw>I*!: Tk"+(pxSwDhэ! uȷV~ O/ԪvJ:oO8Y  AqɟWxpvxg*S9̆p. LCmdtCq喺ө-~ݽ6꿺a0}[6vm |~] JBo8[;PrD8T0 q0cGfבc_ ~rx]T-I+S>/Ξ0/}0\(H (/,`C+w&̬J)5ЊJd8G1 =録'n }& Nt^ߏZ_o"#F<=bUIp:8ALCx8OC۳)jz,P;:;a[QKP%EuJ7Х!w'ϩJM xiF']N[2?/}?-6|o,[/2~= 6lX wCQXiA1]>^<51R cf! IʵmEҾ1 fxw,m!%&Di<bYa\pqaHjkف $?j))$dfhB3bV#lq)0v8偡8W MuiZiII݈/gvZ1yD2YeJTI-!rƹô٬C)j{v^M$1`!f!qn+Ww>PZ*_O{=<o&lpCGK#g"䆕f鉶8|ChF.m++ ,M6»A4 fb)N<[es :I$ ޶<&[# HF'#DcDuZۻ>mqtPFŇW0nmh 5-#er2J7"XI^8zX]>:'SpKXx}luj].L$U.Wg2P} +]`txw' `16˾t@ iNv;kJua[ͧ /6yԮaO$1q/l6Us#G`#7/SY7t8+tG&x WDyPw|XDkI#th=\ .u|Nk|HM#zUh`0wW И/V!ܭKNY3+m Q't=xCvwAIy{&&6E18RT= }`[,tcF]ڳzY/ v-o;=!BXeOnPL ̞Vh5! FqmX6\je1=Iw W;_K?,! a^G|hbl\W)E5QP;ITPH"̉&oɮ'vNC*mJs5_R/kC;\]fErq;:i zb")JK n ^DD>wʈ, =⥁"l׷)YMN 7)Y sS(i _Z:aI8OS١&Dȼm6}~|ZvF%cXA0B7/pw 3l:sP3G\|uvujshqQ&8]aY IH8x ޘ\0X)k8:|Qa.3Īml[5z._"0^HQ씹*!vpB}k-TV%[рjao9ժLp8Vt'$̊`4mQCSFD - m$P;YGFAK{28l^q݇(@PW:+GCæBT7;)dJyaKS :IG@ho5m[/~$itWuǏN~[a@4mՄ4?ohJ`NNG77/74۪֞R[u۝\Ê+5'fՇ3_陜2c/5fM[TP ~)r.uƜR]f:JZ{j:xWBGZ 9a&B* 68wDDCfBm$aKaH+ɖ08E# fS6lU`@ )M4ָ<6m!ڬcgM0Żh KI.#hctfMIB >oXl=hIxKO9Pf  9Ե|Uw`fˢ[ B%+\ab6F`v+fa'X\ǘwJYD'gy23=ϻDB;R ϥٔL428#?mRrtM2Lф᪪9o #\'ie([.lu0gTJ `(K )(L.",l7 %;!u$o^z8É{ޘ]K+ygUii n jR4Ʋ2% \K ߶=L˗ruU| 9A")cy矞RsяzWiw}Z8-c`N:wvrqv+>iYJ]!`]mՑn†Mh45VC[фyóqi]{ӵe{@QEPuz yjcEśV=\J#-aKȫ8O?> q2СAZpͷ-yv/2%t`:Ns@V,X8v85d K*t/dłZF9AV**w.`ΐpeQtM:vG֓w/ ~=@\\1LbzA]ޔ,EgYÍ||i--UqpSJtlBZbC$9Pjn)""((())P! BFK) }1%8ƻCEIeC.|M_ rDE4kόV6_tnyFxmR'@dyRIԫ{ ᥓtXvjuTjD 3Ba{z?WQ,,E3;i2i9&SogTCI/&gp5<6pqKd7~EQq5zi):Ho{[u9s<G[ŃVyGo뇏Tzr@e%S3nt5 1â^g=Rɱ MU0FゎۃymQl[hd 3*;w>y7Li}>јVXƤaPC=.;x$$6B,g5%g[TWx# ,=zSbAՙ {rQob}el{}idff7ܱ ]|ڗh>Grvt炪TdAMP'c_%,cFI 78'-[ͽ%0P^GTf[5cP` n 5{"ؤ3˜3z%n EB%PjU>17, ;#β* *R_ uC!0TMi0B%C䡡)X~~D"˴Ge~u~m%&Ԇ`t>izu>ORVwb|OT( ĬDe2}I!lgFe-d + Q-IA/sՂ^ք9ׁ׺"/3Y=4ܾ8R D5IsWg:)iӮct5qI(%#9U+^1iJ$ߑ9f3ͽ'R;q}|ì]n/?a/'"=d Hr > !'m͟y5û+<0$H]}=TGMƒYCQXzN_?ov!l{ٴe*n!00G1P[E2W$~6 z.Z@q 7 33:*X':1QN>Um8ka6C! f.6 Dג1J^Y ܺ653s$`̦hڠ^V+1벡MNIz4$mmLNH"MrZgc~G?Cmi>zXxVEojX!Ikz\istCԨ=kGx7)akJfk~#=KϨā~@OAB$ʰYмz*|%(*ӭۑMKx`8Vt!tz/ϷL>Wd&Ѓ!-GysB"[5cdS>] /)g$p_WF?gKE|T _CAZ- 96.|#mAGc6YaeJo |r.P6c` a_IQx" V`r.n WXS3xvYg`I {q;TVA+kģ]O0#Z-#;k&?`3o=CE9 ]xfU /KJKtp$/okƊB1b)0S#S"0SB 8P ɳ ,yz$Nkwi#[N`-g%x ߡn:gx&*vN=ci8û䞯L2a{$:@C'8a=FJd&IbUդZajZ@YYؑ0hGd=2'J](֎ia_Cxע: 5rdA$s `s"'&ar>&qBbt=NƏ_5}|-h}9s8n$q]dy0:D00ð ABS $նk翴kdҏ}nůzzţJ(`XM&EwXv1!jRN+Q%wxh &Dߎ3_ \j\t&q4J㌞"}+a6W Kg><ak%*9TDi! rPh6 a Di!Sߛ,̗0i{[GYF4R쁱ܽ/.y$Ő CgX@Ew3zfUun6n}׎Ҫu5!v B6Shh,© C "rAϛ c4 )e <)1"Vfu" ^尊3ahy~17s&Vi(Ȣ@+o ɤ^̷ʝsƜ-lж2qc\2ZVgC>S Cm[m1m0MAFsssu},ֶ#ӤV͊Ԛ:IdZgAM%v?Z'ps˔^>,^1kFS\>x|IFHaaR08G9h D] M d6Ȉ]@wU:fD-P aDc1$1bivG`gw(l:wb^턵7/+xǍ{o?8]ukZ־䭪g j)TځWT߬S*@v -;gOd;fRFIY3ɧ͛>\ \+ʵbl*eQcqPnyZlʴQ,K-)`?yq>sW3Z )C dPͽ!df iҕ,Ɏi3Rn1[Jv*RsMw.z*+(, HEjR)AIbBr"/zLڨL( lbZ+ciUM#t6cbCn]+ʨۄ"ҟ<2#e尗)YVQ7f谘gSުM9<U9cpA߮*\J/bfSd%n4tۆ',ArTp\-W(0.f@U ]*rYڵq񖖼k=OFX|iʝb# >i듥l`3YdÿNIWs:߻fb7{] + F2BFlp@Ϲ)DwzoE@\(0Gd..w fU`I:ܸB,,j7K配08'mk](fkx$"ҒpA]m yw **;h^:v /%gM+hRYݩڜ PS̋F$Z3s80f gU@c@Mdh 01):n,b@;$(p=I3- zpL''X6B<6ߢĵǡLW< JI%8=yE(55[AֲxP}`Fo_ǟsvoFϢدSY &hPQB!$.U@_bξa9%,\gq&0 a=f_fZنQ TH13?G9>zoэ;6˿ /e/恇Θ>F%\‰6:TwM&A/c=ljKѪR~{PRbmX 5u©? !4eh9iɧ'j8:DUE1~X ۞ғ:ΛVn!\@2#@1') +hl A;_ofm{4n驭UŽ! خYM_#T϶ 2#oŃps\vևϝV瞙m>zO_|H!,0Y::)mK'{ :Da|}iPnJ?44D@n (3ЂѧԄPL%8*ڑ==\8GĂ+ZbQIe$YYe% %HXP %`!aeI` dZ%` % .\%  QO;3y[W2 HY%VYU_ae@9` XE BVD Iu ( jQ YW!qbYQhP$CL 0Z\Ų ʔa"$a0X &YaF%Re` Fs{\߱5WWOx?{_Y}׫zs`|B> sf̓6l6f6dJp;.bҔ_CD`A%*#DD8C(̅ dAǔ|\q=d }~(ǻUr!߬~ϳ8gX}7}W_m8bLQ_р -W  p„!BB@ 8{OW&6߇HY""3333-Ӄ.0ّ\?Qfb85Fpo!x1x. ѡhSO t`;Q9ZjyC#TR2/c}333>c.)\@dC(k~euMgfitYm̭ͳxXȁ_U{|` ffff{NO*هV-:dfgzKg_}`N~L%_U]m0g;dC<4ӌubœ&SW @55vY+1?.<0& ` oc0ŋ8k04y u(.L_,DWE1e^.`Ibpۘ*#U,lm% |>Lnh!?sK D XrxߦmM#⼘ݑȋ&s! RRbōg$ۍI,xrbr\'`Q SRXq(llR vhh!Yfw' P$OEA0M4)(Y\ :\" "+엱'ji,9xﰇV0`ȵoM@]Ç4D-x'kv>Ye2e6jaQ3oG"Dfffg6{epɛg@!EY:<h܌Gמ (:ثlɇM8uD s[sdDl]pS܈.mrn~~%vlgW@(a3333CUXSW xkʼn*M`J{mHB!4!nh[,-pU]l[W]Ak`%)JR)4%5ٙ7woloZ-Z3333d,Â[)JR)A7"u`& 0QȊGܸ fffyÇ*p,S6bʼna ^ /mFmO_]O}K mzuX츅D/ 8p$`wjÆ<0SUq+bAJ<[Q80b@ap; uIn 7CxjƐ V hd:TM +e)+w(!_>3G[e.ny7!ݲ!u m[vIjD@j0@BC$eh4B+pXtfwyLM{Xz/VWX ɡy߿߿M z5p,Nfg` VvPA*ZA?uĒ<= [JY%z_Y>++܆b2Mj'?tPa;J $J)w>el9T$ A 3AbfwcXVaZ½e9\fG%=_z?H?{ww$wy$2$YvֵI& $wy$2$]`˻L|:db*)U|ހۄH. RI.I0eI& $ֆ35$2$.`˻LwwI.I>5Gc>~;>=z8A?zƣӛ!8␦- @|jR_q11b PH(~?/;#Z(?%y5? #ܜA{awENFEki"ߠN %1 &ߏ>݁ 9{e_{2?7iro/.jϻgkoӽχsλm> }oF8^~Zy9u|U}JǟFhQ/_$I$I$I$I|$g<`>/_<B! !Fffbgt':SI ;z7^gkQ4Qt8ۆ@ >8m8螆o@o|?*)Z׮1qbE5kjԠl0fkA1ǥjPZuo{)Aֳc)sY=[qJkQfjj{V~87 c9qlP/~yjSDkOJf#WՋb{Zxj|~E(eD$3FFtаԪoSNa`nY:I 0"BrV']d@M mm7?1~S^W~+Wy|'&L7tlhէNSokŋ&<{o82dɒ%~7tt͛6k7WhWޛ.^mmUUUUUUUUU~_??Δronm7'%;ۛۼpŋ,q1Ǐ͛6k7"\r[mo/>35UUUUUUUUηWͽ4N'&8b}K77qxG"7777696sf͚ȥhW'''&\m۶7UUUUEU\?'ownNNJ77y91bɏ#[dɓ&J9ɵ6l&n>E+B9992mݱfffffffffffffffM[d=)b->ndş.EnԍC2cli/R/onload.R0000644000175000017500000001127414143453131012757 0ustar nileshnilesh #' @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) { # Try to restore cursor as much as we can if (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)) { if (rstudio$is_rstudio()) { return(symbol_rstudio) } else { 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() && rstudio$is_rstudio()) { symbol_rstudio } else if (is_utf8_output()) { symbol_utf8 } else if (is_latex_output()) { symbol_ascii } else if (is_windows() && .Platform$GUI == "Rgui") { symbol_win } else if (is_windows() && rst %in% rok) { symbol_win } 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/diff.R0000644000175000017500000002135114143453131012410 0ustar nileshnilesh #' 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) { cnd <- structure( list( message = paste0("diff edit distance is larger than ", max_dist), max_dist = max_dist ), class = c("cli_diff_max_dist", "error", "condition") ) stop(cnd) } 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$length))[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/sitrep.R0000644000175000017500000000322514143453131013006 0ustar nileshnilesh #' 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 if (identical(symbol, symbol_rstudio)) { "RStudio (UTF-8)" } else if (identical(symbol, symbol_win)) { "Windows (non 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/test.R0000644000175000017500000000674014201142012012450 0ustar nileshnilesh #' 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. #' #' @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 = NULL) { code <- substitute(code) doconfigs <- list( list(id = "plain", unicode = FALSE, num_colors = 1, locale = NULL), list(id = "ansi", unicode = FALSE, num_colors = 256, locale = NULL), list(id = "unicode", unicode = TRUE, num_colors = 1, locale = NULL), list(id = "fancy", unicode = TRUE, num_colors = 256, locale = NULL) ) 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 ) 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) }) } cli/R/pluralize.R0000644000175000017500000001153714201176104013511 0ustar nileshnilesh #' 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. #' #' @param ...,.envir,.transformer All arguments are passed to [glue::glue()]. #' #' @export #' @family pluralization #' @examples #' # 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/server.R0000644000175000017500000000047714143453131013014 0ustar nileshnilesh 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/rstudio-detect.R0000644000175000017500000001316714201221670014441 0ustar nileshnilesh 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_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)) # Otherwise get data new <- get_data() # Cache unless told otherwise cache <- TRUE 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/master/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) rcmd <- sub("[(].*$", "", cmd) rcmd %in% c("devtools::build", "devtools::test", "devtools::check") } # -- Capabilities ------------------------------------------------------ caps <- list() caps$not_rstudio <- function(data) { list( type = "not_rstudio", dynamic_tty = FALSE, ansi_tty = FALSE, ansi_color = FALSE, num_colors = 1L ) } 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"]]) ) } 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 ) } 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"]]) ) } 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"]]) ) } caps$rstudio_subprocess <- function(data) { list( type = "rstudio_subprocess", dynamic_tty = FALSE, ansi_tty = FALSE, ansi_color = FALSE, num_colors = 1L ) } 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/progress-client.R0000644000175000017500000006454714143453131014636 0ustar nileshnilesh #' 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, R.options = list(asciicast_at = NULL)} #' 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, R.options = list(asciicast_at = NULL)} #' 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, R.options = list(asciicast_at = NULL)} #' 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, R.options = list(asciicast_at = NULL)} #' 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. You can change this 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 two seconds. #' #' ```{asciicast progress-after, R.options = list(asciicast_at = NULL)} #' 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, dependson = -1} #' # 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, R.options = list(asciicast_at = NULL)} #' 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, R.options = list(asciicast_at = NULL)} #' 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, R.options = list(asciicast_at = NULL)} #' 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 [cli_progress_message()] and [cli_progress_step()] for simpler #' progress messages. #' @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$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)) { 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, R.options = list(asciicast_at = NULL)} #' 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. #' #' @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 <- 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), R.options = list(asciicast_at = NULL)} #' 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 [cli_progress_bar()] for the complete progress bar API. #' [cli_progress_step()] for a similar display that is styled by default. #' @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, R.options = list(asciicast_at = NULL)} #' 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 not that this will only work if you call [cli_progress_update()] #' regularly. #' #' ```{asciicast progress-step-spin, R.options = list(asciicast_at = NULL)} #' 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, R.options = list(asciicast_at = NULL)} #' 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, R.options = list(asciicast_at = NULL)} #' 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()]. #' #' @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/lorem.R0000644000175000017500000000310614143453131012614 0ustar nileshnilesh 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/progress-along.R0000644000175000017500000000713714143453131014450 0ustar nileshnilesh #' 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, R.options = list(asciicast_at = NULL)} #' 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, R.options = list(asciicast_at = NULL)} #' res <- lapply(cli_progress_along(1:100, "Downloading"), function(i) { #' Sys.sleep(4/100) #' }) #' ``` #' #' ## Custom format string #' #' ```{asciicast progress-along-3, R.options = list(asciicast_at = NULL)} #' 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 [cli_progress_bar()] and the traditional progress bar API. #' #' @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/progress-bar.R0000644000175000017500000000566214143453131014115 0ustar nileshnilesh 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`. #' #' @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/time-ago.R0000644000175000017500000000627414143453131013211 0ustar nileshnilesh 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/cli.R0000644000175000017500000005553714143453131012264 0ustar nileshnilesh #' 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__message_emit(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 on.exit(app$output <- old, add = TRUE) on.exit(app$signal <- NULL, 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 } # cli__rec + cli__fmt fmt <- function(expr, collapse = FALSE, strip_newline = FALSE, app = NULL) { rec <- cli__rec(expr) cli__fmt(rec, collapse, strip_newline, app) } #' 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. #' @return Character scalar, the formatted string. #' #' @export #' @examples #' format_inline("A message for {.emph later}, thanks {.fn format_inline}.") format_inline <- function(..., .envir = parent.frame()) { opts <- options(cli.width = Inf) on.exit(options(opts), add = TRUE) fmt(cli_text(..., .envir = .envir)) } #' 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. #' #' @export cli_text <- function(..., .envir = parent.frame()) { cli__message("text", list(text = glue_cmd(..., .envir = .envir))) } #' 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. #' #' @export cli_h1 <- function(text, id = NULL, class = NULL, .envir = parent.frame()) { cli__message("h1", list(text = glue_cmd(text, .envir = .envir), 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), 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), 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. #' #' @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), 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. #' #' @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), 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. #' @inheritParams cli_ul #' @return The id of the new container element, invisibly. #' #' @export cli_dl <- function(items = NULL, id = NULL, class = NULL, .close = TRUE, .auto_close = TRUE, .envir = parent.frame()) { if (!is.null(items) && !is_named(items)) { stop("`items` must be a named character vector.") } cli__message( "dl", list( items = lapply(items, glue_cmd, .envir = .envir), 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 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. #' #' @export cli_li <- function(items = NULL, id = NULL, class = NULL, .auto_close = TRUE, .envir = parent.frame()) { cli__message( "li", list( items = lapply(items, glue_cmd, .envir = .envir), 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, R.options = list(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. #' #' @export cli_alert <- function(text, id = NULL, class = NULL, wrap = FALSE, .envir = parent.frame()) { cli__message( "alert", list( text = glue_cmd(text, .envir = .envir), 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), 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), 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), 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), 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 #' #' @export cli_rule <- function(left = "", center = "", right = "", id = NULL, .envir = parent.frame()) { cli__message("rule", list(left = glue_cmd(left, .envir = .envir), center = glue_cmd(center, .envir = .envir), right = glue_cmd(right, .envir = .envir), 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") #' ``` #' #' @export #' @param quote Text of the quotation. #' @param citation Source of the quotation, typically a link or the name #' of a person. #' @inheritParams cli_div cli_blockquote <- function(quote, citation = NULL, id = NULL, class = NULL, .envir = parent.frame()) { cli__message( "blockquote", list( quote = glue_cmd(quote, .envir = .envir), citation = glue_cmd(citation, .envir = .envir), 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) invisible(args$id) } else { cli_recorded[[record]] <- c(cli_recorded[[record]], list(cond)) invisible(cond) } } 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/status-bar.R0000644000175000017500000003515114143453131013570 0ustar nileshnilesh #' 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 The [cli_progress_message()] and [cli_progress_step()] #' functions, for a superior API. #' @family status bar #' @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. #' #' @family status bar #' @seealso The [cli_progress_message()] and [cli_progress_step()] #' functions, for a superior API. #' @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. #' #' @family status bar #' @seealso The [cli_progress_message()] and [cli_progress_step()] #' functions, for a superior API. #' @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/utf8.R0000644000175000017500000001012714143453131012365 0ustar nileshnilesh #' 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) start <- as.integer(start) stop <- as.integer(stop) if (!length(start) || !length(stop)) { stop("invalid substring arguments") } if (anyNA(start) || anyNA(stop)) { stop("non-numeric substring arguments not supported") } x <- enc2utf8(x) start <- rep_len(start, length(x)) stop <- rep_len(stop, length(x)) .Call(clic_utf8_substr, x, start, stop) } #' Break an UTF-8 character vector into grapheme clusters #' #' @param x Character vector. #' @return List of characters vectors, the grapheme clusters of the input #' string. #' #' @family UTF-8 string manipulation #' @export #' @examples #' # Five grapheme clusters #' str <- paste0( #' "\U0001f477\U0001f3ff\u200d\u2640\ufe0f", #' "\U0001f477\U0001f3ff", #' "\U0001f477\u200d\u2640\ufe0f", #' "\U0001f477\U0001f3fb", #' "\U0001f477\U0001f3ff") #' cat(str, "\n") #' chrs <- utf8_graphemes(str) utf8_graphemes <- function(x) { if (!is.character(x)) x <- as.character(x) x <- enc2utf8(x) .Call(clic_utf8_graphemes, x) } cli/R/progress-utils.R0000644000175000017500000000215514143453131014503 0ustar nileshnilesh #' @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 #' @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 #' @family progress bar #' @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/time.R0000644000175000017500000000365514143453131012445 0ustar nileshnilesh 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/internals.R0000644000175000017500000000673614143453131013511 0ustar nileshnilesh call_if_fun <- function(x) { if (is.function(x)) x() else x } clii__xtext <- function(app, text, .list, indent, padding, ln = 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) text <- ansi_strwrap( text, exdent = exdent, width = app$get_width(extra = padding) ) 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-c.R0000644000175000017500000000243214143453131013563 0ustar nileshnilesh 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/progress-server.R0000644000175000017500000002567714172272425014676 0ustar nileshnilesh # ------------------------------------------------------------------------ #' 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://www.rstudio.com/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][shiny::Progress]. This handler is available if a #' shiny app is running. #' #' @return `cli_progress_builtin_handlers()` returns the names of the #' currently supported progress handlers. #' #' @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_last <- 0L bar$progressr_progressor <- asNamespace("progressr")$progressor( steps, auto_finish = FALSE, on_exit = TRUE, envir = .envir, label = bar$name %||% NA_character_ ) }, set = function(bar, .envir) { amount <- bar$current - bar$progressr_last bar$last <- bar$current if (!is.null(bar$progressr_progressor) && amount > 0) { bar$progressr_progressor(amount = amount) } }, complete = function(bar, .envir, result) { amount <- bar$current - bar$progressr_last bar$last <- bar$current if (!is.null(bar$progressr_progressor) && amount > 0) { bar$progressr_progressor(amount = amount, 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 <- 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 { 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() && shiny::isRunning() }, add = function(bar, .envir) { bar$shiny_progress <- shiny::Progress$new( 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/bullets.R0000644000175000017500000000575214200476211013157 0ustar nileshnilesh #' 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 `buller-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. #' #' @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()` returned 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 See [cli_bullets()] for examples. #' @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) { fmt(cli_bullets_raw(text, id, class)) } cli/R/ansiex.R0000644000175000017500000006745714201156611013006 0ustar nileshnilesh 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{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. #' @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) { if (!is.character(string)) string <- as.character(string) string <- enc2utf8(string) stopifnot( is_flag(sgr), is_flag(csi) ) .Call(clic_ansi_has_any, string, sgr, csi) } #' 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. #' @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) { if (!is.character(string)) string <- as.character(string) string <- enc2utf8(string) stopifnot( is_flag(sgr), is_flag(csi) ) clean <- .Call(clic_ansi_strip, string, sgr, csi) 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 <- as.integer(start) stop <- as.integer(stop) if (!length(start) || !length(stop)) { stop("invalid substring arguments") } if (anyNA(start) || anyNA(stop)) { stop("non-numeric substring arguments not supported") } 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) stop("`split` must be character of length <= 1, or must coerce to that") 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) { rem <- which(ansi_strip(x) == mark) if (length(rem)) { x[-c(rem - 1, rem, rem + 1)] } 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. #' #' @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) { 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. # 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)) tw <- ansi_nchar(ellipsis, "width") # 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. bad0 <- bad <- !is.na(x) & (ansi_strip(xt) != ansi_strip(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; }" ) 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") } cli/R/utils.R0000644000175000017500000000073414200476211012640 0ustar nileshnilesh 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 } cli/R/hash.R0000644000175000017500000002645114201142067012427 0ustar nileshnilesh #' 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 aharacter 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) } #' 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) } #' 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 between 1 and 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, collapse, character(1)), emojis = I(emojis), text = vapply(names, collapse, character(1), sep = ", "), names = I(names) ) } 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 = collapse(emo$emoji), emojis = emo$emoji, text = 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_animals()` 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 . #' #' @param x Character vector. `NA` entries will have an `NA` hash. #' @param n_adj Number of adjectives to use. It must be between 0 and 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, 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_anima()` 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 = 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/inline.R0000644000175000017500000002223214201176160012754 0ustar nileshnilesh if (getRversion() >= "2.15.1") utils::globalVariables("app") inline_generic <- function(app, x, style) { 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) } } xx } inline_collapse <- function(x, style = list()) { sep <- style[["vec_sep"]] %||% ", " if (length(x) >= 3) { last <- style$vec_last %||% ", and " } else { last <- style$vec_sep2 %||% style$vec_last %||% " and " } trunc <- style$vec_trunc %||% 100L if (length(x) > trunc) { x <- c(x[1:trunc], cli::symbol$ellipsis) last <- sep } glue::glue_collapse(as.character(x), sep = sep, last = last) } #' 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) if (!braceexp) { id2 <- clii__container_start(app, "span", class = NULL) } out <- glue::glue( text, .envir = envir, .transformer = inline_transformer, .open = paste0("{", envir$marker), .close = paste0(envir$marker, "}"), .trim = TRUE, .comment = "" ) # 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::glue( t$str, .envir = t$values, .transformer = inline_transformer, .open = paste0("{", t$values$marker), .close = paste0(t$values$marker, "}"), .trim = TRUE, .comment = "" ) }) paste(out, collapse = "") } inline_regex <- function() "(?s)^[.]([-[:alnum:]_]+)[[:space:]]+(.*)" make_cmd_transformer <- function(values) { values$marker <- random_id() values$qty <- NA_integer_ values$num_subst <- 0L values$postprocess <- FALSE values$pmarkers <- list() function(code, envir) { res <- tryCatch({ expr <- parse(text = code, keep.source = FALSE) eval(expr, envir = list("?" = function(...) stop()), enclos = envir) }, error = function(e) e) if (!inherits(res, "error")) { id <- paste0("v", length(values)) if (length(res) == 0) res <- qty(0) values[[id]] <- res values$qty <- res values$num_subst <- values$num_subst + 1L return(paste0("{", values$marker, id, values$marker, "}")) } # plurals if (substr(code, 1, 1) == "?") { return(parse_plural(code, values)) } else { # inline styles m <- regexpr(inline_regex(), code, perl = TRUE) has_match <- m != -1 if (!has_match) stop(res) 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::glue( text, .envir = envir, .transformer = sys.function(), .trim = TRUE, .comment = "" ) paste0("{", values$marker, ".", funname, " ", out, values$marker, "}") } } } glue_cmd <- function(..., .envir) { str <- paste0(unlist(list(...), use.names = FALSE), collapse = "") values <- new.env(parent = emptyenv()) transformer <- make_cmd_transformer(values) pstr <- glue::glue( str, .envir = .envir, .transformer = transformer, .trim = TRUE, .comment = "" ) 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-ticking.R0000644000175000017500000000053714143453131014775 0ustar nileshnilesh #' @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/cliapp-docs.R0000644000175000017500000003266514143453131013710 0ustar nileshnilesh #' About inline markup in the semantic cli #' #' @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. #' * `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. #' * `fun` for a function name. #' * `key` for a keyboard key. #' * `path` for a path (essentially the same as `file`). #' * `pkg` for a package name. #' * `strong` for strong importance. #' * `url` for a URL. #' * `var` for a variable name. #' * `val` for a generic "value". #' #' ```{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://acme.com}.") #' cli_li("An environment variable: {.envvar R_LIBS}.") #' 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 #' one hundred 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. #' #' @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 #' cli_alert_info("Found {ndirs} diretor{?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_trunc`: Vectors longer than this will be truncated. Defaults to #' 100. #' #' 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/R/tree.R0000644000175000017500000001465414201156133012444 0ustar nileshnilesh #' 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/width.R0000644000175000017500000000711414143453131012620 0ustar nileshnilesh #' 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)) stop("options(\"cli.width\") must be integer") if (length(cwopt) != 1) stop("options(\"cli.width\") must be a scalar") if (is.na(cwopt)) stop("options(\"cli.width\") cannot be NA") if (cwopt == Inf) { cwopti <- .Machine$integer.max } else { cwopti <- as.integer(cwopt) } if (cwopti <= 0) stop("options(\"cli.width\") must be a positive integer") 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() { tryCatch( ret <- .Call(clic_tty_size), error = function(err) { class(err) <- c("ps_unknown_tty_size", class(err)) stop(err) } ) c(width = ret[1], height = ret[2]) } terminal_width <- function() { w <- tryCatch(tty_size()[["width"]], error = function(e) 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/format.R0000644000175000017500000000634214143453131012773 0ustar nileshnilesh #' 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 %||% "\"" 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 #' [glue::glue_collapse()], 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 `sep` and `last` arguments of #' [glue::glue_collapse()]. See an example below. #' #' @export #' @seealso [cli_format()] cli_vec <- function(x, style = list()) { attr(x, "cli_style") <- style x } cli/R/ansi-utils.R0000644000175000017500000000203014143453131013561 0ustar nileshnilesh 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/rematch2.R0000644000175000017500000000172714143453131013212 0ustar nileshnilesh 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/timer.R0000644000175000017500000000201014143453131012607 0ustar nileshnilesh #' @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/format-conditions.R0000644000175000017500000001126314200725107015137 0ustar nileshnilesh #' 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. #' #' @export format_error <- function(message, .envir = parent.frame()) { if (is.null(names(message)) || names(message)[1] == "") { # The default theme will make this bold names(message)[1] <- "1" } message[1] <- paste0("Error: ", message[1]) rsconsole <- c("rstudio_console", "rstudio_console_starting") if (rstudio_detect()$type %in% rsconsole) { # leave some space for the traceback buttons in RStudio oldopt <- options(cli.width = console_width() - 15L) } else { 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 <- 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 (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 <- 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 <- 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 <- rstudioapi::getThemeInfo()$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/LICENSE0000644000175000017500000000005114143453131012153 0ustar nileshnileshYEAR: 2020 COPYRIGHT HOLDER: Rstudio Pbc cli/inst/0000755000175000017500000000000014143453131012127 5ustar nileshnileshcli/inst/scripts/0000755000175000017500000000000014143453131013616 5ustar nileshnileshcli/inst/scripts/up.R0000755000175000017500000000277014143453131014376 0ustar nileshnilesh#! /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/inst/scripts/outdated.R0000755000175000017500000000376114143453131015564 0ustar nileshnilesh#! /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/inst/scripts/search.R0000755000175000017500000000402714143453131015214 0ustar nileshnilesh#! /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/inst/scripts/news.R0000755000175000017500000000565314143453131014731 0ustar nileshnilesh#! /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)) cli_li() cli_text("{.pkg {pkg$Package}} {pkg$Version} -- {ago} by {.emph {pkg$Maintainer}}") cli_text("{pkg$Title}") cli_text("{.url https://r-pkg.org/pkg/{pkg$Package}}") } if (is.null(sys.calls())) { load_packages() opts <- parse_arguments() news(opts$n, opts$day, opts$week, opts$since, opts$reverse) } cli/inst/logo.txt0000644000175000017500000000526614143453131013641 0ustar nileshnilesh                     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/shiny/0000755000175000017500000000000014143453131013261 5ustar nileshnileshcli/inst/shiny/simple/0000755000175000017500000000000014143453131014552 5ustar nileshnileshcli/inst/shiny/simple/app.R0000644000175000017500000000251514143453131015460 0ustar nileshnilesh# modified from https://shiny.rstudio.com/articles/progress.html library(cli) # !!! You don't need these in real code. # cli.progress_show_after makes sure that we see the progress bar from # the beginning, not only after a delay. options(cli.progress_show_after = 0) # !!! You don't need these in real code. # This also requests logging the progress bar to the standard output, # in the console. options(cli.progress_handlers_only = c("shiny", "logger")) server <- function(input, output) { output$plot <- renderPlot({ input$goPlot # Re-run when button is clicked # Create 0-row data frame which will be used to store data dat <- data.frame(x = numeric(0), y = numeric(0)) # Number of times we'll go through the loop n <- 10 cli_progress_bar(total = n, "Rendering plot") for (i in 1:n) { # Each time through the loop, add another row of data. This is # a stand-in for a long-running computation. dat <- rbind(dat, data.frame(x = rnorm(1), y = rnorm(1))) cli_progress_update(status = paste("Doing part", i)) # Pause for 0.1 seconds to simulate a long computation. Sys.sleep(0.5) } plot(dat$x, dat$y) }) } ui <- shinyUI(basicPage( plotOutput('plot', width = "300px", height = "300px"), actionButton('goPlot', 'Go plot') )) shinyApp(ui = ui, server = server) cli/inst/shiny/format/0000755000175000017500000000000014143453131014551 5ustar nileshnileshcli/inst/shiny/format/app.R0000644000175000017500000000256314143453131015462 0ustar nileshnilesh# 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/nested/0000755000175000017500000000000014143453131014543 5ustar nileshnileshcli/inst/shiny/nested/app.R0000644000175000017500000000323614143453131015452 0ustar nileshnilesh# 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/0000755000175000017500000000000014143453131014361 5ustar nileshnileshcli/inst/shiny/along/app.R0000644000175000017500000000250014143453131015261 0ustar nileshnilesh# 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/0000755000175000017500000000000014143453131014621 5ustar nileshnileshcli/inst/shiny/output/app.R0000644000175000017500000000260714143453131015531 0ustar nileshnilesh# 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/examples/0000755000175000017500000000000014143453131013745 5ustar nileshnileshcli/inst/examples/apps/0000755000175000017500000000000014143453131014710 5ustar nileshnileshcli/inst/examples/apps/up.R0000755000175000017500000000277614143453131015476 0ustar nileshnilesh#! /usr/bin/env Rscript ## To get the async package: ## source("https://install-github.me/r-lib/async") setup_app <- function() { theme <- list("url" = list(color = "blue")) app <- cliapp::start_app(theme = theme, output = "stdout") } load_packages <- function() { tryCatch({ library(cliapp) library(async) library(docopt) }, error = function(e) { cli_alert_danger("The {.pkg async} and {.pkg docopt} packages are needed!") q(save = "no", status = 1) }) } up <- function(urls, timeout = 5) { load_packages() setup_app() chk_url <- async(function(url, ...) { http_head(url, ...)$ then(function(res) { if (res$status_code < 300) { cli_alert_success("{.url {url}} ({res$times[['total']]}s)") } else { cli_alert_danger("{.url {url}} (HTTP {res$status_code})") } })$ catch(error = function(err) { e <- if (grepl("timed out", err$message)) "timed out" else "error" cli_alert_danger("{.url {url}} ({e})") }) }) invisible(synchronise( async_map(urls, chk_url, options = list(timeout = timeout)) )) } parse_arguments <- function() { "Usage: up.R [-t timeout] [URLS ...] up.R -h | --help Options: -t timeout Timeout for giving up on a site, in seconds [default: 5]. -h --help Print this help message Check if web sites are up. " -> doc docopt(doc) } if (is.null(sys.calls())) { load_packages() opts <- parse_arguments() up(opts$URLS, timeout = as.numeric(opts$t)) } cli/inst/examples/apps/outdated.R0000755000175000017500000000403014143453131016644 0ustar nileshnilesh#! /usr/bin/env Rscript ## To get the pkgcache package: ## source("https://install-github.me/r-lib/pkgcache") setup_app <- function() { theme <- list( "url" = list(color = "blue"), ".pkg" = list(color = "orange")) start_app(theme = theme, output = "stdout") } load_packages <- function() { tryCatch(suppressPackageStartupMessages({ library(cli) library(pkgcache) library(docopt) }), error = function(e) { cli_alert_danger("The {.pkg pkgcache} and {.pkg docopt} packages are needed!") q(save = "no", status = 1) }) } outdated <- function(lib = NULL, notcran = FALSE) { load_packages() setup_app() if (is.null(lib)) lib <- .libPaths()[1] inst <- utils::installed.packages(lib = lib) cli_alert_info("Getting repository metadata") repo <- meta_cache_list(rownames(inst)) if (!notcran) inst <- inst[inst[, "Package"] %in% repo$package, ] for (i in seq_len(nrow(inst))) { pkg <- inst[i, "Package"] iver <- inst[i, "Version"] if (! pkg %in% repo$package) { cli_alert_info("{.pkg {pkg}}: \tnot a CRAN/BioC package") next } rpkg <- repo[repo$package == pkg, ] newer <- rpkg[package_version(rpkg$version) > iver, ] if (!nrow(newer)) next nver <- package_version(newer$version) mnver <- max(nver) newest <- newer[mnver == nver, ] bin <- if (any(newest$platform != "source")) "bin" else "" src <- if (any(newest$platform == "source")) "src" else "" cli_alert_danger("{.emph {pkg}}") cli_alert_danger( "{.pkg {pkg}} \t{iver} {symbol$arrow_right} {mnver} {.emph ({bin} {src})}") } } parse_arguments <- function() { "Usage: outdated.R [-l lib] [-x] outdated.R -h | --help Options: -x Print not CRAN/BioC packages as well -l lib Library directory, default is first directory in the lib path -h --help Print this help message Check for outdated packages in a package library. " -> doc docopt(doc) } if (is.null(sys.calls())) { load_packages() opts <- parse_arguments() outdated(opts$l, opts$x) } cli/inst/examples/apps/search.R0000755000175000017500000000403214143453131016302 0ustar nileshnilesh#! /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.R0000755000175000017500000000565314143453131016023 0ustar nileshnilesh#! /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)) cli_li() cli_text("{.pkg {pkg$Package}} {pkg$Version} -- {ago} by {.emph {pkg$Maintainer}}") cli_text("{pkg$Title}") cli_text("{.url https://r-pkg.org/pkg/{pkg$Package}}") } if (is.null(sys.calls())) { load_packages() opts <- parse_arguments() news(opts$n, opts$day, opts$week, opts$since, opts$reverse) } cli/inst/include/0000755000175000017500000000000014143453131013552 5ustar nileshnileshcli/inst/include/cli/0000755000175000017500000000000014143453131014321 5ustar nileshnileshcli/inst/include/cli/progress.h0000644000175000017500000002674414143453131016353 0ustar nileshnilesh#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(); //' ### `cli_progress_num()` //' //' ```c //' int cli_progress_num(); //' ``` //' //' Returns the number of currently active progress bars. static R_INLINE int cli_progress_num(); //' ### `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() { 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() { static int (*ptr)() = NULL; if (ptr == NULL) { ptr = (int (*)()) 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/NAMESPACE0000644000175000017500000001241514201142107012365 0ustar nileshnilesh# 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_columns) export(ansi_has_any) export(ansi_has_hyperlink_support) export(ansi_hide_cursor) export(ansi_html) export(ansi_html_style) export(ansi_nchar) export(ansi_palette_show) export(ansi_palettes) export(ansi_regex) export(ansi_show_cursor) export(ansi_simplify) 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_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(hash_animal) export(hash_emoji) export(hash_file_sha256) export(hash_md5) export(hash_obj_animal) export(hash_obj_emoji) export(hash_obj_md5) export(hash_obj_sha256) export(hash_raw_animal) export(hash_raw_emoji) export(hash_raw_md5) export(hash_raw_sha256) export(hash_sha256) export(is_ansi_tty) export(is_dynamic_tty) export(is_utf8_output) 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(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) importFrom(utils,getParseData) importFrom(utils,getSrcref) useDynLib(cli, .registration=TRUE)