progress/0000755000176200001440000000000014534046452012125 5ustar liggesusersprogress/NAMESPACE0000644000176200001440000000042214214027113013326 0ustar liggesusers# Generated by roxygen2: do not edit by hand export(progress_bar) importFrom(R6,R6Class) importFrom(crayon,col_nchar) importFrom(crayon,col_substr) importFrom(hms,as.hms) importFrom(prettyunits,pretty_bytes) importFrom(prettyunits,vague_dt) importFrom(utils,flush.console) progress/LICENSE0000644000176200001440000000005614521424003013117 0ustar liggesusersYEAR: 2023 COPYRIGHT HOLDER: progress authors progress/README.md0000644000176200001440000001415014533533446013410 0ustar liggesusers



progress


[![R-CMD-check](https://github.com/r-lib/progress/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/r-lib/progress/actions/workflows/R-CMD-check.yaml) [![](https://www.r-pkg.org/badges/version/progress)](https://r-pkg.org/pkg/progress) [![Codecov test coverage](https://codecov.io/gh/r-lib/progress/branch/main/graph/badge.svg)](https://app.codecov.io/gh/r-lib/progress?branch=main) > Progress bar in your R terminal An R package to show ASCII progress bars. Heavily influenced by the https://github.com/tj/node-progress JavaScript project. ## Installation Install the package from CRAN: ```r install.packages("progress") ``` If you need the development version, install it from GitHub: ```r pak::pak("r-lib/progress") ``` ## Usage Use the `progress_bar` R6 class: ```r library(progress) pb <- progress_bar$new(total = 100) for (i in 1:100) { pb$tick() Sys.sleep(1 / 100) } ``` ``` [==========================================================-------------] 81% ``` The progress bar is displayed after the first `tick` command. This might not be desirable for long computations, because nothing is shown before the first tick. It is good practice to call `tick(0)` at the beginning of the computation or download, which shows the progress bar immediately. ```r pb <- progress_bar$new(total = 100) f <- function() { pb$tick(0) Sys.sleep(3) for (i in 1:100) { pb$tick() Sys.sleep(1 / 100) } } f() ``` Custom format, with estimated time of completion: ```r pb <- progress_bar$new( format = " downloading [:bar] :percent eta: :eta", total = 100, clear = FALSE, width= 60) for (i in 1:100) { pb$tick() Sys.sleep(1 / 100) } ``` ``` downloading [========----------------------] 28% eta: 1s ``` With elapsed time: ```r pb <- progress_bar$new( format = " downloading [:bar] :percent in :elapsed", total = 100, clear = FALSE, width= 60) for (i in 1:100) { pb$tick() Sys.sleep(1 / 100) } ``` ``` downloading [==========================------] 80% in 1s ``` ```r pb <- progress_bar$new( format = " downloading [:bar] :elapsedfull", total = 1000, clear = FALSE, width= 60) for (i in 1:1000) { pb$tick() Sys.sleep(1 / 100) } ``` ``` downloading [=====================--------------] 00:00:08 ``` With number of number of ticks/total: ```r total <- 1000 pb <- progress_bar$new(format = "[:bar] :current/:total (:percent)", total = total) f <- function() { pb$tick(0) Sys.sleep(3) for (i in 1:total) { pb$tick(1) Sys.sleep(1 / 100) } } f() ``` ``` [============================-------------------------------------------------] 370/1000 ( 37%) ``` With custom tokens: ```r pb <- progress_bar$new( format = " downloading :what [:bar] :percent eta: :eta", clear = FALSE, total = 200, width = 60) f <- function() { for (i in 1:100) { pb$tick(tokens = list(what = "foo ")) Sys.sleep(2 / 100) } for (i in 1:100) { pb$tick(tokens = list(what = "foobar")) Sys.sleep(2 / 100) } } f() ``` ``` downloading foo [======------------------] 27% eta: 4s ``` It can show download rates for files with unknown sizes: ```r pb <- progress_bar$new( format = " downloading foobar at :rate, got :bytes in :elapsed", clear = FALSE, total = 1e7, width = 60) f <- function() { for (i in 1:100) { pb$tick(sample(1:100 * 1000, 1)) Sys.sleep(2/100) } pb$tick(1e7) invisible() } f() ``` ``` downloading foobar at 5.42 MB/s, got 15.45 MB in 3s ``` Progress bars can also digress, by supplying negative values to `tick()`: ```r pb <- progress_bar$new() f <- function() { pb$tick(50) ; Sys.sleep(1) pb$tick(-20) ; Sys.sleep(1) pb$tick(50) ; Sys.sleep(1) pb$tick(-30) ; Sys.sleep(1) pb$tick(100) } f() ``` See the manual for details and other options. ## Usage with `purrr` iterators If you prefer to do your iterative tasks using the `purrr` family of functional programming tools, rather than with `for` loops, there are two straightforward ways to add progress bars: 1. Increment the ticks *in-line* when calling the `purrr` iterator. 2. Define the task and increment the ticks in a separate wrapper function. ***Option 1*** is concise for simple one-line tasks (*e.g.* requiring only a single function call), while ***Option 2*** is probably preferred for more complex multi-line tasks. ```r # Option 1 pb <- progress_bar$new(total = 100) purrr::walk(1:100, ~{pb$tick(); Sys.sleep(0.1)}) ``` ``` [================================================>------] 89% ``` ```r # Option 2 pb <- progress_bar$new(total = 100) foo <- function(x){ pb$tick() Sys.sleep(0.1) } purrr::walk(1:100, foo) ``` ``` [==================>------------------------------------] 34% ``` ## Creating a plyr compatible progress bar It is easy to create progress bars for [plyr](https://github.com/hadley/plyr): ```r progress_progress <- function(...) { pb <- NULL list( init = function(x, ...) { pb <<- progress_bar$new(total = x, ...) }, step = function() { pb$tick() }, term = function() NULL ) } ``` You can try it with ```r plyr::l_ply( 1:100, .fun = function(...) Sys.sleep(0.01), .progress = 'progress' ) ``` ## C++ API The package also provides a C++ API, that can be used with or without Rcpp. See [the example package](tests/testthat/progresstest/src/test.cpp) that is [included](tests/testthat/progresstest) within `progress`. Here is a short excerpt that shows how it works: ```CPP #include ... RProgress::RProgress pb("Downloading [:bar] ETA: :eta"); pb.tick(0); for (int i = 0; i < 100; i++) { usleep(2.0 / 100 * 1000000); pb.tick(); } ... ``` The C++ API has almost the same functionality as the R API, except that it does not currently support custom tokens, custom streams, and callback functions. Note that the C++ and the R APIs are independent and for a single progress bar you need to use either one exclusively. ## License MIT @ [Gábor Csárdi](https://github.com/gaborcsardi), [RStudio Inc](https://github.com/rstudio) progress/man/0000755000176200001440000000000014521421364012673 5ustar liggesusersprogress/man/figures/0000755000176200001440000000000014214027113014330 5ustar liggesusersprogress/man/figures/logo.png0000644000176200001440000001345714214027113016010 0ustar liggesusersPNG  IHDR%?sBIT|d pHYs![![&ttEXtSoftwarewww.inkscape.org<IDATx{_Uu?%kݬ̙o]眽s-pqqqqqqqqqqqq,0s ,ʨ?6? 8=ucZܶsڃQ\pR`ya- X;c=h#οxIa-x1 /-+e,)ulf3Mgn{5;hl>+V?k.u-6WqrM% 4ՏZNqflLw"`afZkk1R࠾v[A_ccS#F]F{>rޒltq %tޤCQBWG֦H=%yXbBư`*Vy:9b]_+Z;Z5ljh:\M\.dUv=^vjiiòM- N{Yٿg6>ٙ V? ;X4T@(K{8,L5=H>?m2Y-t oLB t7YYEM@4>ٿ }N/C~lk8oeG PCoA# vZ 6jh}+;@dXx轲KqpK^]FQw 5$ he+ljA4je$z%ְxtv`3QkT'(cVmyM`] }oN碩%'17WJtXd&LN&'Ԟ;;ii-u')@,&}jr./Eh=3#PR΍rny..n(礈rNjM5mv r1 I5A#FԞ!,i maL^^cJ&݅.՘Rm9MS!*} 8 mM{A@Πk PFY-HVws_$K%-z6aفzscŞEI;-==Y+~M' M>f@TKv *NjDo X1r2Ut۾*%ȣ߇MK4rR!FHWa-F> 3-)uRPƤss9aͤװX@oyh‚=!u ȍ4&(ޤT/PҼ{CF7iVs1&Q=Ѽ@j6%8*ڰ`bhu WdМ75JYļҗm$$w3rJN p^zo-G2 ; S;'GN^`1Rn^L@N87I)*Q[@@ 𖛶ĆT/G$糊Fz YI& ƜR*l"^Sb}}kO9UJ3SٖrDckdrK2HW㔠@i|ri/AMWo;sX~ih{y*Wdb>'ٗH[o+v[$-!O̕{z"?,,k@l&):ӾVaD7 RXz2K ˁrtkAXŵ楻܁"J{9'(#f(7y!L$BDžv 1!aBO5)DhIg=a-`iXȤѴB)*5cƩĄ>R[ppTJ[q '54 TTFҪ4?DI*2:NcWڌIӒ,EׅeOVc]ߤ܊|5رϷ/$t[<J MZs> ,,Rz&t8;I{k)8FYHμU-߻mǗ'7 bDzO({Ց<נ3&FUY+˅4kcmַ55Cؼطʚ+T?>`ϘU%#'V۰cRv'݈zDVBOkٖVz%!keh8]C<97=1rEÁ4uR)IIQ[y9脼 [Cx]%!s'ꬣQg[#89ȸ>k_r"]7W+/g]uf354J*[D($9X13=Ĵt&DS1!ar3KV/gs%!K8_~JlS%cʜ%ks 1c6f3iRٖm\bHJ<\Y a{ 1+s3HeWyYp ';+HaQLF+<'-5R%Inrrnd<})A݁X8@Vw 5R%sױ#wA_:%aihU3eՁ%8+M:ٟ)A/$}Lx$-݁hJ![qMX}lDY; `m ])v\YѹJc7aoVՊ i;0hj;^QIzڎVt@Oіb[K1t@5*QO5DfNdfVlZyz{0cʊMr%q1~0%r= -IY vfiB5kbZ,(aizeY@>3A;a7NJV99OV ЬՊM:g} E*rON~0՛sa%V,v{ЭʽHnfKgzW>F9@V- 9`bѦu>JX4@Q=e1\~0VxKe6ZbS+:Aw#w\Y ܁ c`XJﳞ"VV+6>ˀ2YKx!|'|k+cUިZ|-PXG0_3u1 ,Ji2M{ _ 5Tje4Z#ֲfZyMWdItp7ibaȀÀ=iǃ@Aj%: :V~?Z:| gYʉYv8>ȧu}zq%@Xp@v/w>&qld8jqq qCX_r NcpޟeU~?n I9<ޟ_Q8>ϋ? xRF_8G-x%3H8Q' n62*:Rfhj;^[Azڎ\@O۱ 7*v|zڎ;)ڎWҝ jJbhs%K5ਗ਼m:΁ Ȳb! ZAp:@M--[J5`ŦQ, nv2l[JiѦ+2zc}sMU> ]{ `e}Ejֹ02ߧɩCE} @ya` &̛LDR ћWg52֎cxbkr$z$|Se& ]=?8c6Hzq ,qq̵9==uqpCWqQ•9{z8(:dCWZ3:8."@C88󗃀ОaFIqids ;8*BD+{84t=vqqqqqqqqqqqq ЄwmIENDB`progress/man/figures/logo.svg0000644000176200001440000004273414214027113016023 0ustar liggesusers image/svg+xml progress/man/progress_bar.Rd0000644000176200001440000001276614521415367015674 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/progress.R \name{progress_bar} \alias{progress_bar} \title{Progress bar in the terminal} \description{ Progress bars are configurable, may include percentage, elapsed time, and/or the estimated completion time. They work in the command line, in Emacs and in R Studio. The progress package was heavily influenced by https://github.com/tj/node-progress } \section{Creating the progress bar}{ A progress bar is an R6 object, that can be created with \code{progress_bar$new()}. It has the following arguments: \describe{ \item{format}{The format of the progress bar. A number of tokens can be used here, see them below. It defaults to \code{"[:bar] :percent"}, which means that the progress bar is within brackets on the left, and the percentage is printed on the right.} \item{total}{Total number of ticks to complete. If it is unknown, use \code{NA} here. Defaults to 100.} \item{width}{Width of the progress bar. Default is the current terminal width (see \code{options()} and \code{width}) minus two.} \item{stream}{This argument is deprecated, and \code{message()} is used to print the progress bar.} \item{complete}{Completion character, defaults to \code{=}.} \item{incomplete}{Incomplete character, defaults to \code{-}.} \item{current}{Current character, defaults to \code{>}.} \item{callback}{Callback function to call when the progress bar finishes. The progress bar object itself is passed to it as the single parameter.} \item{clear}{Whether to clear the progress bar on completion. Defaults to \code{TRUE}.} \item{show_after}{Amount of time in seconds, after which the progress bar is shown on the screen. For very short processes, it is probably not worth showing it at all. Defaults to two tenth of a second.} \item{force}{Whether to force showing the progress bar, even if the given (or default) stream does not seem to support it.} \item{message_class}{Extra classes to add to the message conditions signalled by the progress bar.} } } \section{Using the progress bar}{ Three functions can update a progress bar. \code{progress_bar$tick()} increases the number of ticks by one (or another specified value). \code{progress_bar$update()} sets a given ratio and \code{progress_bar$terminate()} removes the progress bar. \code{progress_bar$finished} can be used to see if the progress bar has finished. Note that the progress bar is not shown immediately, but only after \code{show_after} seconds. (Set this to zero, and call \code{tick(0)} to force showing the progress bar.) \code{progress_bar$message()} prints a message above the progress bar. It fails if the progress bar has already finished. } \section{Tokens}{ They can be used in the \code{format} argument when creating the progress bar. \describe{ \item{:bar}{The progress bar itself.} \item{:current}{Current tick number.} \item{:total}{Total ticks.} \item{:elapsed}{Elapsed time in seconds.} \item{:elapsedfull}{Elapsed time in hh:mm:ss format.} \item{:eta}{Estimated completion time in seconds.} \item{:percent}{Completion percentage.} \item{:rate}{Download rate, bytes per second. See example below.} \item{:tick_rate}{Similar to \verb{:rate}, but we don't assume that the units are bytes, we just print the raw number of ticks per second.} \item{:bytes}{Shows :current, formatted as bytes. Useful for downloads or file reads if you don't know the size of the file in advance. See example below.} \item{:spin}{Shows a spinner that updates even when progress is advanced by zero.} } Custom tokens are also supported, and you need to pass their values to \code{progress_bar$tick()} or \code{progress_bar$update()}, in a named list. See example below. } \section{Options}{ The \code{progress_enabled} option can be set to \code{FALSE} to turn off the progress bar. This works for the C++ progress bar as well. } \examples{ ## We don't run the examples on CRAN, because they takes >10s ## altogether. Unfortunately it is hard to create a set of ## meaningful progress bar examples that also run quickly. \dontrun{ ## Basic pb <- progress_bar$new(total = 100) for (i in 1:100) { pb$tick() Sys.sleep(1 / 100) } ## ETA pb <- progress_bar$new( format = " downloading [:bar] :percent eta: :eta", total = 100, clear = FALSE, width= 60) for (i in 1:100) { pb$tick() Sys.sleep(1 / 100) } ## Elapsed time pb <- progress_bar$new( format = " downloading [:bar] :percent in :elapsed", total = 100, clear = FALSE, width= 60) for (i in 1:100) { pb$tick() Sys.sleep(1 / 100) } ## Spinner pb <- progress_bar$new( format = "(:spin) [:bar] :percent", total = 30, clear = FALSE, width = 60) for (i in 1:30) { pb$tick() Sys.sleep(3 / 100) } ## Custom tokens pb <- progress_bar$new( format = " downloading :what [:bar] :percent eta: :eta", clear = FALSE, total = 200, width = 60) f <- function() { for (i in 1:100) { pb$tick(tokens = list(what = "foo ")) Sys.sleep(2 / 100) } for (i in 1:100) { pb$tick(tokens = list(what = "foobar")) Sys.sleep(2 / 100) } } f() ## Download (or other) rates pb <- progress_bar$new( format = " downloading foobar at :rate, got :bytes in :elapsed", clear = FALSE, total = NA, width = 60) f <- function() { for (i in 1:100) { pb$tick(sample(1:100 * 1000, 1)) Sys.sleep(2/100) } pb$tick(1e7) invisible() } f() pb <- progress_bar$new( format = " got :current rows at :tick_rate/sec", clear = FALSE, total = NA, width = 60) f <- function() { for (i in 1:100) { pb$tick(sample(1:100, 1)) Sys.sleep(2/100) } pb$terminate() invisible() } f() } } progress/man/progress-package.Rd0000644000176200001440000000202314521423614016414 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/progress-package.R \docType{package} \name{progress-package} \alias{progress} \alias{progress-package} \title{progress: Terminal Progress Bars} \description{ \if{html}{\figure{logo.png}{options: style='float: right' alt='logo' width='120'}} Configurable Progress bars, they may include percentage, elapsed time, and/or the estimated completion time. They work in terminals, in 'Emacs' 'ESS', 'RStudio', 'Windows' 'Rgui' and the 'macOS' 'R.app'. The package also provides a 'C++' 'API', that works with or without 'Rcpp'. } \seealso{ Useful links: \itemize{ \item \url{https://github.com/r-lib/progress#readme} \item \url{http://r-lib.github.io/progress/} \item Report bugs at \url{https://github.com/r-lib/progress/issues} } } \author{ \strong{Maintainer}: Gábor Csárdi \email{csardi.gabor@gmail.com} Authors: \itemize{ \item Rich FitzJohn } Other contributors: \itemize{ \item Posit Software, PBC [copyright holder, funder] } } \keyword{internal} progress/DESCRIPTION0000644000176200001440000000231214534046452013631 0ustar liggesusersPackage: progress Title: Terminal Progress Bars Version: 1.2.3 Authors@R: c( person("Gábor", "Csárdi", , "csardi.gabor@gmail.com", role = c("aut", "cre")), person("Rich", "FitzJohn", role = "aut"), person("Posit Software, PBC", role = c("cph", "fnd")) ) Description: Configurable Progress bars, they may include percentage, elapsed time, and/or the estimated completion time. They work in terminals, in 'Emacs' 'ESS', 'RStudio', 'Windows' 'Rgui' and the 'macOS' 'R.app'. The package also provides a 'C++' 'API', that works with or without 'Rcpp'. License: MIT + file LICENSE URL: https://github.com/r-lib/progress#readme, http://r-lib.github.io/progress/ BugReports: https://github.com/r-lib/progress/issues Depends: R (>= 3.6) Imports: crayon, hms, prettyunits, R6 Suggests: Rcpp, testthat (>= 3.0.0), withr Config/Needs/website: tidyverse/tidytemplate Config/testthat/edition: 3 Encoding: UTF-8 RoxygenNote: 7.2.3 NeedsCompilation: no Packaged: 2023-12-05 09:33:10 UTC; gaborcsardi Author: Gábor Csárdi [aut, cre], Rich FitzJohn [aut], Posit Software, PBC [cph, fnd] Maintainer: Gábor Csárdi Repository: CRAN Date/Publication: 2023-12-06 10:30:02 UTC progress/tests/0000755000176200001440000000000014214027113013253 5ustar liggesusersprogress/tests/testthat/0000755000176200001440000000000014534046452015127 5ustar liggesusersprogress/tests/testthat/test-cpp.R0000644000176200001440000000137114533535131017007 0ustar liggesuserstest_that("C++ API works", { skip_on_cran() if (getRversion() < "4.0.0" && .Platform$OS.type == "windows") { skip("Fails on older R") } Sys.setenv("R_TESTS" = "") dir.create(lib <- tempfile()) on.exit(unlink(lib, recursive = TRUE), add = TRUE) install.packages("progresstest_1.0.0.tar.gz", lib = lib, quiet = FALSE) on.exit(unloadNamespace("progresstest"), add = TRUE) withr::with_libpaths(lib, action = "prefix", { withr::with_message_sink( file.path(lib, basename(tempfile())), expect_error(progresstest::my_test_progress(), NA) ) }) withr::with_libpaths(lib, action = "prefix", { withr::with_options(list(progress_enabled = FALSE), expect_false(progresstest::my_is_option_enabled()) ) }) }) progress/tests/testthat/progresstest_1.0.0.tar.gz0000644000176200001440000000364214214027113021527 0ustar liggesusersY{sH;T]D`o*/Sٺ-In-@b!w{L٠G{z_xaD輭߶]wCQSU]i[{LTO$Eե"J(ixr*cfhKdn 1 Sّv'lp F_hڞ*VEҌ xPbF-U+N\0S5 <` %# h\&mG\i,P )]?YUI6T;wp c%t;-w(\O~Yy[ozZa˛c$iH& 3Q=elhrCV]Rkap@bW@ ۍn\=O? ˼{EMFTMz]b/1~՛q5Һ:\t?t q G{klE/? Yӎ (#昂'ԕAP ѿPx7DtD u/$[ƝM(004Ǩ NeFq.?4q|C/~/(vbzm؋z4T' Wy賿xwksZ~W,t(n A7M,+]CvrMg؝blKNK,RvwsU Xy>x QqngrnɧH1jmmex mcX #include #include // [[Rcpp::export]] Rcpp::CharacterVector test_progress(Rcpp::CharacterVector formatSEXP = "[:bar] :percent ") { BEGIN_RCPP const char *format = formatSEXP[0]; RProgress::RProgress pb(format); pb.tick(0); for (int i = 0; i < 100; i++) { usleep( (useconds_t) (2.0 / 100 * 1000000)); pb.tick(); } Rcpp::CharacterVector result(1); result[0] = "DONE"; return result; END_RCPP } // [[Rcpp::export]] Rcpp::LogicalVector test_is_option_enabled() { BEGIN_RCPP Rcpp::LogicalVector result(1); result[0] = RProgress::RProgress::is_option_enabled(); return result; END_RCPP } // [[Rcpp::export]] Rcpp::CharacterVector test_units() { BEGIN_RCPP Rcpp::CharacterVector result(20); result[0] = RProgress::RProgress::vague_dt(0); result[1] = RProgress::RProgress::vague_dt(1); result[2] = RProgress::RProgress::vague_dt(1.1); result[3] = RProgress::RProgress::vague_dt(51); result[4] = RProgress::RProgress::vague_dt(2 * 60); result[5] = RProgress::RProgress::vague_dt(3 * 60 * 60); result[6] = RProgress::RProgress::vague_dt(3 * 60 * 60 * 24); result[7] = RProgress::RProgress::vague_dt(31 * 60 * 60 * 24); result[8] = RProgress::RProgress::vague_dt(400 * 60 * 60 * 24); result[9] = RProgress::RProgress::vague_dt(1500 * 60 * 60 * 24); result[10] = RProgress::RProgress::pretty_bytes(0); result[11] = RProgress::RProgress::pretty_bytes(133); result[12] = RProgress::RProgress::pretty_bytes(1337); result[13] = RProgress::RProgress::pretty_bytes(13337); result[14] = RProgress::RProgress::pretty_bytes(133337); result[15] = RProgress::RProgress::pretty_bytes(1333337); result[16] = RProgress::RProgress::pretty_bytes(13333337); result[17] = RProgress::RProgress::pretty_bytes(133333337); result[18] = RProgress::RProgress::pretty_bytes(1333333337); result[19] = RProgress::RProgress::pretty_bytes(1333333337); return result; END_RCPP } progress/tests/testthat/progresstest/src/RcppExports.cpp0000644000176200001440000000317014214027113023444 0ustar liggesusers// Generated by using Rcpp::compileAttributes() -> do not edit by hand // Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393 #include using namespace Rcpp; // test_progress Rcpp::CharacterVector test_progress(Rcpp::CharacterVector formatSEXP); RcppExport SEXP _progresstest_test_progress(SEXP formatSEXPSEXP) { BEGIN_RCPP Rcpp::RObject rcpp_result_gen; Rcpp::RNGScope rcpp_rngScope_gen; Rcpp::traits::input_parameter< Rcpp::CharacterVector >::type formatSEXP(formatSEXPSEXP); rcpp_result_gen = Rcpp::wrap(test_progress(formatSEXP)); return rcpp_result_gen; END_RCPP } // test_is_option_enabled Rcpp::LogicalVector test_is_option_enabled(); RcppExport SEXP _progresstest_test_is_option_enabled() { BEGIN_RCPP Rcpp::RObject rcpp_result_gen; Rcpp::RNGScope rcpp_rngScope_gen; rcpp_result_gen = Rcpp::wrap(test_is_option_enabled()); return rcpp_result_gen; END_RCPP } // test_units Rcpp::CharacterVector test_units(); RcppExport SEXP _progresstest_test_units() { BEGIN_RCPP Rcpp::RObject rcpp_result_gen; Rcpp::RNGScope rcpp_rngScope_gen; rcpp_result_gen = Rcpp::wrap(test_units()); return rcpp_result_gen; END_RCPP } static const R_CallMethodDef CallEntries[] = { {"_progresstest_test_progress", (DL_FUNC) &_progresstest_test_progress, 1}, {"_progresstest_test_is_option_enabled", (DL_FUNC) &_progresstest_test_is_option_enabled, 0}, {"_progresstest_test_units", (DL_FUNC) &_progresstest_test_units, 0}, {NULL, NULL, 0} }; RcppExport void R_init_progresstest(DllInfo *dll) { R_registerRoutines(dll, NULL, CallEntries, NULL, NULL); R_useDynamicSymbols(dll, FALSE); } progress/tests/testthat/progresstest/R/0000755000176200001440000000000014214027113020060 5ustar liggesusersprogress/tests/testthat/progresstest/R/RcppExports.R0000644000176200001440000000074214214027113022477 0ustar liggesusers# Generated by using Rcpp::compileAttributes() -> do not edit by hand # Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393 test_progress <- function(formatSEXP = "[:bar] :percent ") { .Call('_progresstest_test_progress', PACKAGE = 'progresstest', formatSEXP) } test_is_option_enabled <- function() { .Call('_progresstest_test_is_option_enabled', PACKAGE = 'progresstest') } test_units <- function() { .Call('_progresstest_test_units', PACKAGE = 'progresstest') } progress/tests/testthat/progresstest/R/test.R0000644000176200001440000000042614214027113021164 0ustar liggesusers #' @importFrom progress progress_bar #' @importFrom Rcpp loadRcppModules #' @useDynLib progresstest #' @export my_test_progress <- function(format = "[:bar] :percent ") { test_progress(format) } #' @export my_is_option_enabled <- function() { test_is_option_enabled() } progress/tests/testthat/helper.R0000644000176200001440000000033114214027113016512 0ustar liggesusers get_output <- function(expr) { msgs <- character() i <- 0 suppressMessages(withCallingHandlers( expr, message = function(e) msgs[[i <<- i + 1]] <<- conditionMessage(e))) paste0(msgs, collapse = "") } progress/tests/testthat/test-progress.R0000644000176200001440000002231214521423300020056 0ustar liggesuserstest_that("Vanilla progress bar works", { out <- get_output({ pb <- progress_bar$new(stream = stdout(), force = TRUE, show_after = 0, width = 20) for (i in 1:5) { pb$tick(20) } }) sout <- paste0( "\r[==>----------] 20%", "\r[====>--------] 40%", "\r[=======>-----] 60%", "\r[=========>---] 80%", "\r[=============] 100%", "\r ", "\r" ) expect_equal(out, sout) }) test_that("Update method works", { out <- get_output({ pb <- progress_bar$new(stream = stdout(), force = TRUE, show_after = 0, width = 20) updates = c(20, 40, 20, 80, 100) / 100 for (i in 1:5) { pb$update(updates[i]) } }) sout <- paste0( "\r[==>----------] 20%", "\r[====>--------] 40%", "\r[==>----------] 20%", "\r[=========>---] 80%", "\r[=============] 100%", "\r ", "\r" ) expect_equal(out, sout) }) test_that("Calling tick(0)", { out <- get_output({ pb <- progress_bar$new(stream = stdout(), force = TRUE, show_after = 0, width = 20) pb$tick(0) for (i in 1:5) { pb$tick(20) } }) sout <- paste0( "\r[-------------] 0%", "\r[==>----------] 20%", "\r[====>--------] 40%", "\r[=======>-----] 60%", "\r[=========>---] 80%", "\r[=============] 100%", "\r ", "\r" ) expect_equal(out, sout) }) test_that("Digress", { out <- get_output({ pb <- progress_bar$new(stream = stdout(), force = TRUE, show_after = 0, width = 20) f <- function() { pb$tick(50) pb$tick(-20) pb$tick(50) pb$tick(-30) pb$tick(100) } f() }) sout <- paste0( "\r[=====>-------] 50%", "\r[===>---------] 30%", "\r[=========>---] 80%", "\r[=====>-------] 50%", "\r[=============] 100%", "\r ", "\r" ) expect_equal(out, sout) }) test_that("No :bar item, :current and :total tokens", { out <- get_output({ pb <- progress_bar$new(stream = stdout(), force = TRUE, show_after = 0, width = 20, total = 10, clear = FALSE, format = ":current/:total") pb$tick(2) pb$tick(5) pb$tick(3) }) sout <- paste0( "\r2/10", "\r7/10", "\r10/10\n" ) expect_equal(out, sout) }) ## This is somewhat timing dependent, but ## should work in general test_that(":eta and :elapsed tokens", { skip_on_cran() out <- get_output({ pb <- progress_bar$new(stream = stdout(), force = TRUE, show_after = 0, width = 20, total = 4, format = "[:eta :elapsed]") pb$tick(0) Sys.sleep(1) # 1 sec per tick pb$tick(1) # So 3 more ticks is 3 secs Sys.sleep(1) pb$tick(1) # 2 more is 2 secs pb$tick(2) }) sout <- paste0( "\r[ ?s 0s]", "\r[ 3s 1s]", "\r[ 2s 2s]", "\r[ 0s 2s]", "\r ", "\r" ) expect_equal(out, sout) }) test_that("complete and incomplete chars", { out <- get_output({ pb <- progress_bar$new(stream = stdout(), force = TRUE, show_after = 0, width = 20, total = 5, complete = "#", current = "@", incomplete = " ", clear = FALSE) for (i in 1:5) pb$tick(1) }) sout <- paste0( "\r[##@ ] 20%", "\r[####@ ] 40%", "\r[#######@ ] 60%", "\r[#########@ ] 80%", "\r[#############] 100%", "\n" ) expect_equal(out, sout) }) test_that("callback function", { x <- "" cb <- function(self) { x <<- "done" } out <- get_output({ pb <- progress_bar$new(stream = stdout(), force = TRUE, show_after = 0, width = 20, callback = cb) pb$tick(0) pb$tick(50) pb$tick(50) }) expect_equal(x, "done") x <- "" str <- file(tmp <- tempfile(), open = "w") on.exit(unlink(tmp), add = TRUE) pb <- progress_bar$new(stream = str, show_after = 0, width = 20, callback = cb) pb$tick(0) pb$tick(50) pb$tick(50) close(str) expect_equal(x, "done") }) test_that("clearing and not clearing", { out <- get_output({ pb <- progress_bar$new(stream = stdout(), force = TRUE, show_after = 0, width = 20, clear = TRUE) pb$tick(0) pb$tick(50) pb$tick(50) }) sout <- paste0( "\r[-------------] 0%", "\r[=====>-------] 50%", "\r[=============] 100%", "\r ", "\r" ) expect_equal(out, sout) out <- get_output({ pb <- progress_bar$new(stream = stdout(), force = TRUE, show_after = 0, width = 20, clear = FALSE) pb$tick(0) pb$tick(50) pb$tick(50) }) sout <- paste0( "\r[-------------] 0%", "\r[=====>-------] 50%", "\r[=============] 100%", "\n" ) expect_equal(out, sout) }) test_that("show_after argument", { skip_on_cran() out <- get_output({ pb <- progress_bar$new(stream = stdout(), force = TRUE, show_after = .1, width = 20, clear = TRUE) pb$tick(0) pb$tick(25) pb$tick(25) Sys.sleep(.1) pb$tick(25) pb$tick(25) }) sout <- paste0( "\r[=========>---] 75%", "\r[=============] 100%", "\r ", "\r" ) expect_equal(out, sout) }) test_that("custom tokens", { out <- get_output({ pb <- progress_bar$new(stream = stdout(), force = TRUE, show_after = 0, width = 20, format = ":what [:bar] :percent", clear = FALSE, total = 200) pb$tick(50, tokens = list(what = "foo ")) pb$tick(50, tokens = list(what = "foo ")) pb$tick(50, tokens = list(what = "foobar")) pb$tick(50, tokens = list(what = "foobar")) }) sout <- paste0( "\rfoo [=>----] 25%", "\rfoo [==>---] 50%", "\rfoobar [===>--] 75%", "\rfoobar [======] 100%", "\n" ) expect_equal(out, sout) }) test_that("bar adepts to width of custom tokens", { out <- get_output({ pb <- progress_bar$new(stream = stdout(), force = TRUE, show_after = 0, width = 20, format = ":what [:bar] :percent", clear = FALSE, total = 200) pb$tick(50, tokens = list(what = "text")) pb$tick(50, tokens = list(what = "long text")) pb$tick(100, tokens = list(what = "text")) }) sout <- paste0( "\rtext [=>------] 25%", "\rlong text [=>-] 50%", "\rtext [========] 100%", "\n" ) expect_equal(out, sout) }) test_that(":rate and :bytes tokens", { skip_on_cran() out <- get_output({ pb <- progress_bar$new(stream = stdout(), force = TRUE, show_after = 0, width = 20, total = 4 * 1024, format = "[:rate :bytes]") pb$tick(0) Sys.sleep(1) # 1 sec per 1000 bytes pb$tick(1024) # So 3000 more bytes is 3 secs Sys.sleep(1) pb$tick(1024) # 2000 more is 2 secs pb$tick(2048) }) ## Next output line might be shorter, so 'progress_bar$render' ## might to erase it first soutm <- paste0( "^\\r\\[0 B/s 0 B\\]", "\\r?[ ]*", "\\r\\[[0-9\\.]+ k?B/s [0-9\\.]+ k?B\\]", "\\r?[ ]*", "\\r\\[[0-9\\.]+ k?B/s [0-9\\.]+ kB\\]", "\\r?[ ]*", "\\r\\[[0-9\\.]+ k?B/s [0-9\\.]+ kB\\]", "\\r[ ]*", "\\r$" ) expect_match(out, soutm) }) test_that("very quick loops, only the nothing is shown", { out <- get_output({ pb <- progress_bar$new(total = 100, stream = stdout(), force = TRUE, width = 20) for (i in 1:100) pb$tick() }) sout <- paste0("") expect_equal(out, sout) }) test_that("message works", { out <- get_output({ pb <- progress_bar$new(stream = stdout(), force = TRUE, show_after = 0, width = 20) for (i in 1:4) { if (i %% 2 == 0) { pb$message(as.character(i)) } pb$tick(25) } }) sout <- paste0( "\r[==>----------] 25%", "\r ", "\r2\n", "[==>----------] 25%", "\r[=====>-------] 50%", "\r[=========>---] 75%", "\r ", "\r4\n", "[=========>---] 75%", "\r[=============] 100%", "\r ", "\r" ) expect_equal(out, sout) }) test_that("terminate works", { out <- get_output({ pb <- progress_bar$new(stream = stdout(), force = TRUE, show_after = 0, width = 20) for (i in 1:4) { if (i == 3) { pb$terminate() break } pb$tick(25) } }) sout <- paste0( "\r[==>----------] 25%", "\r[=====>-------] 50%", "\r ", "\r" ) expect_equal(out, sout) }) test_that("custom message class", { out <- get_output({ pb <- progress_bar$new(force = TRUE, message_class = "myclass", show_after = 0, width = 20) msg <- tryCatch(pb$tick(25), message = function(x) x) expect_s3_class(msg, "myclass") msg <- tryCatch(pb$terminate(), message = function(x) x) expect_s3_class(msg, "myclass") }) }) progress/tests/testthat.R0000644000176200001440000000061414521423207015244 0ustar liggesusers# This file is part of the standard setup for testthat. # It is recommended that you do not modify it. # # Where should you do additional test configuration? # Learn more about the roles of various files in: # * https://r-pkgs.org/testing-design.html#sec-tests-files-overview # * https://testthat.r-lib.org/articles/special-files.html library(testthat) library(progress) test_check("progress") progress/R/0000755000176200001440000000000014521421362012317 5ustar liggesusersprogress/R/utils.R0000644000176200001440000000507314214027113013602 0ustar liggesusers is_stdout <- function(stream) { identical(stream, stdout()) && sink.number() == 0 } is_stderr <- function(stream) { identical(stream, stderr()) } is_r_studio <- function() { Sys.getenv("RSTUDIO") == 1 } r_studio_stdx <- function(stream) { r_studio_stdout(stream) || r_studio_stderr(stream) } r_studio_stdout <- function(stream) { interactive() && is_r_studio() && identical(stream, stdout()) && is_stdout(stream) } r_studio_stderr <- function(stream) { interactive() && is_r_studio() && identical(stream, stderr()) && is_stderr(stream) } is_r_app <- function() { Sys.getenv("R_GUI_APP_VERSION") != "" } r_app_stdx <- function(stream) { interactive() && is_r_app() && (is_stdout(stream) || is_stderr(stream)) } is_rkward <- function() { "rkward" %in% (.packages()) } rkward_stdx <- function(stream) { interactive() && is_rkward() && (is_stdout(stream) || is_stderr(stream)) } is_supported <- function(stream) { is_option_enabled() && (isatty(stream) || r_studio_stdx(stream) || r_app_stdx(stream) || rkward_stdx(stream)) } is_option_enabled <- function() { isTRUE(getOption("progress_enabled", TRUE)) } default_stream <- function(stream) { if (! is.null(stream)) { stream } else { if (is_r_studio()) stdout() else stderr() } } assert_character <- function(x) { stopifnot(is.character(x), length(x) > 0) } assert_character_scalar <- function(x) { stopifnot(is.character(x), length(x) == 1, !is.na(x)) } assert_scalar <- function(x, finite = TRUE, na = FALSE) { stopifnot(is.numeric(x), length(x) == 1, na || !is.na(x), na || !finite || is.finite(x)) } assert_positive_scalar <- function(x, finite = TRUE) { assert_scalar(x, finite = finite) stopifnot(x > 0) } assert_nonnegative_scalar <- function(x, finite = TRUE, na = FALSE) { assert_scalar(x, finite = finite, na = na) stopifnot(na || x >= 0) } assert_ratio <- function(x) { assert_nonnegative_scalar(x) stopifnot(x <= 1) } assert_nonzero_count <- function(x, finite = TRUE) { assert_positive_scalar(x, finite = TRUE) stopifnot(as.integer(x) == x) } assert_connection <- function(x) { stopifnot(inherits(x, "connection")) } assert_single_char <- function(x) { assert_character_scalar(x) stopifnot(nchar(x) == 1) } assert_function <- function(x) { stopifnot(is.function(x)) } assert_flag <- function(x) { stopifnot(is.logical(x), length(x) == 1, !is.na(x)) } assert_named_or_empty_list <- function(x) { stopifnot(length(x) == 0 || !is.null(names(x))) } progress/R/progress.R0000644000176200001440000003736114521415365014326 0ustar liggesusers #' Progress bar in the terminal #' #' Progress bars are configurable, may include percentage, elapsed time, #' and/or the estimated completion time. They work in the command line, #' in Emacs and in R Studio. The progress package was heavily influenced by #' https://github.com/tj/node-progress #' #' @section Creating the progress bar: #' A progress bar is an R6 object, that can be created with #' `progress_bar$new()`. It has the following arguments: #' \describe{ #' \item{format}{The format of the progress bar. A number of #' tokens can be used here, see them below. It defaults to #' `"[:bar] :percent"`, which means that the progress #' bar is within brackets on the left, and the percentage #' is printed on the right.} #' \item{total}{Total number of ticks to complete. If it is unknown, #' use `NA` here. Defaults to 100.} #' \item{width}{Width of the progress bar. Default is the current #' terminal width (see `options()` and `width`) minus two.} #' \item{stream}{This argument is deprecated, and `message()` is #' used to print the progress bar.} #' \item{complete}{Completion character, defaults to `=`.} #' \item{incomplete}{Incomplete character, defaults to `-`.} #' \item{current}{Current character, defaults to `>`.} #' \item{callback}{Callback function to call when the progress #' bar finishes. The progress bar object itself is passed to it #' as the single parameter.} #' \item{clear}{Whether to clear the progress bar on completion. #' Defaults to `TRUE`.} #' \item{show_after}{Amount of time in seconds, after which the progress #' bar is shown on the screen. For very short processes, #' it is probably not worth showing it at all. Defaults to two #' tenth of a second.} #' \item{force}{Whether to force showing the progress bar, #' even if the given (or default) stream does not seem to support it.} #' \item{message_class}{Extra classes to add to the message conditions #' signalled by the progress bar.} #' } #' #' @section Using the progress bar: #' Three functions can update a progress bar. `progress_bar$tick()` #' increases the number of ticks by one (or another specified value). #' `progress_bar$update()` sets a given ratio and #' `progress_bar$terminate()` removes the progress bar. #' `progress_bar$finished` can be used to see if the progress bar has #' finished. #' #' Note that the progress bar is not shown immediately, but only after #' `show_after` seconds. (Set this to zero, and call `tick(0)` to #' force showing the progress bar.) #' #' `progress_bar$message()` prints a message above the progress bar. #' It fails if the progress bar has already finished. #' #' @section Tokens: #' They can be used in the `format` argument when creating the #' progress bar. #' \describe{ #' \item{:bar}{The progress bar itself.} #' \item{:current}{Current tick number.} #' \item{:total}{Total ticks.} #' \item{:elapsed}{Elapsed time in seconds.} #' \item{:elapsedfull}{Elapsed time in hh:mm:ss format.} #' \item{:eta}{Estimated completion time in seconds.} #' \item{:percent}{Completion percentage.} #' \item{:rate}{Download rate, bytes per second. See example below.} #' \item{:tick_rate}{Similar to `:rate`, but we don't assume that #' the units are bytes, we just print the raw number of ticks per #' second.} #' \item{:bytes}{Shows :current, formatted as bytes. Useful #' for downloads or file reads if you don't know the size of the #' file in advance. See example below.} #' \item{:spin}{Shows a spinner that updates even when progress is #' advanced by zero.} #' } #' #' Custom tokens are also supported, and you need to pass their #' values to `progress_bar$tick()` or `progress_bar$update()`, #' in a named list. See example below. #' #' @section Options: #' The `progress_enabled` option can be set to `FALSE` to turn off the #' progress bar. This works for the C++ progress bar as well. #' #' @importFrom R6 R6Class #' #' @export #' @examples #' #' ## We don't run the examples on CRAN, because they takes >10s #' ## altogether. Unfortunately it is hard to create a set of #' ## meaningful progress bar examples that also run quickly. #' \dontrun{ #' #' ## Basic #' pb <- progress_bar$new(total = 100) #' for (i in 1:100) { #' pb$tick() #' Sys.sleep(1 / 100) #' } #' #' ## ETA #' pb <- progress_bar$new( #' format = " downloading [:bar] :percent eta: :eta", #' total = 100, clear = FALSE, width= 60) #' for (i in 1:100) { #' pb$tick() #' Sys.sleep(1 / 100) #' } #' #' ## Elapsed time #' pb <- progress_bar$new( #' format = " downloading [:bar] :percent in :elapsed", #' total = 100, clear = FALSE, width= 60) #' for (i in 1:100) { #' pb$tick() #' Sys.sleep(1 / 100) #' } #' #' ## Spinner #' pb <- progress_bar$new( #' format = "(:spin) [:bar] :percent", #' total = 30, clear = FALSE, width = 60) #' for (i in 1:30) { #' pb$tick() #' Sys.sleep(3 / 100) #' } #' #' ## Custom tokens #' pb <- progress_bar$new( #' format = " downloading :what [:bar] :percent eta: :eta", #' clear = FALSE, total = 200, width = 60) #' f <- function() { #' for (i in 1:100) { #' pb$tick(tokens = list(what = "foo ")) #' Sys.sleep(2 / 100) #' } #' for (i in 1:100) { #' pb$tick(tokens = list(what = "foobar")) #' Sys.sleep(2 / 100) #' } #' } #' f() #' #' ## Download (or other) rates #' pb <- progress_bar$new( #' format = " downloading foobar at :rate, got :bytes in :elapsed", #' clear = FALSE, total = NA, width = 60) #' f <- function() { #' for (i in 1:100) { #' pb$tick(sample(1:100 * 1000, 1)) #' Sys.sleep(2/100) #' } #' pb$tick(1e7) #' invisible() #' } #' f() #' #' pb <- progress_bar$new( #' format = " got :current rows at :tick_rate/sec", #' clear = FALSE, total = NA, width = 60) #' f <- function() { #' for (i in 1:100) { #' pb$tick(sample(1:100, 1)) #' Sys.sleep(2/100) #' } #' pb$terminate() #' invisible() #' } #' f() #' #' } #' #' @name progress_bar NULL progress_bar <- R6Class("progress_bar", public = list( initialize = function(format = "[:bar] :percent", total = 100, width = getOption("width") - 2, stream = NULL, complete = "=", incomplete = "-", current = ">", callback = function(self) {}, clear = TRUE, show_after = 0.2, force = FALSE, message_class = NULL) { pb_init(self, private, format, total, width, stream, complete, incomplete, current, callback, clear, show_after, force, message_class) }, tick = function(len = 1, tokens = list()) { pb_tick(self, private, len, tokens) }, update = function(ratio, tokens = list()) { pb_update(self, private, ratio, tokens) }, message = function(msg, set_width = TRUE) { pb_message(self, private, msg, set_width) }, terminate = function() { pb_terminate(self, private) }, finished = FALSE ), private = list( render = function(tokens) { pb_render(self, private, tokens) }, ratio = function() { pb_ratio(self, private) }, progress_message = function(..., domain = NULL, appendLF = TRUE) { pb_progress_message(self, private, ..., domain = domain, appendLF = appendLF) }, clear_line = function(width) { pb_clear_line(self, private, width) }, cursor_to_start = function() { pb_cursor_to_start(self, private) }, first = TRUE, supported = NA, format = NULL, total = NULL, current = 0, width = NULL, chars = list( complete = "=", incomplete = "-", current = ">" ), callback = NULL, clear = NULL, show_after = NULL, last_draw = "", message_class = NULL, start = NULL, toupdate = FALSE, complete = FALSE, spin = NULL, has_token = c(current = FALSE, total = FALSE, elapsedfull = FALSE, elapsed = FALSE, eta = FALSE, percent = FALSE, rate = FALSE, bytes = FALSE, bar = FALSE, spin = FALSE, tick_rate = FALSE) ) ) pb_init <- function(self, private, format, total, width, stream, complete, incomplete, current, callback, clear, show_after, force, message_class) { assert_character_scalar(format) assert_nonnegative_scalar(total <- as.numeric(total), na = TRUE) assert_nonzero_count(width) assert_single_char(complete) assert_single_char(incomplete) assert_single_char(current) assert_function(callback) assert_flag(clear) assert_nonnegative_scalar(show_after) private$first <- TRUE private$supported <- force || is_supported(stderr()) private$format <- format private$total <- total private$width <- width private$chars$complete <- complete private$chars$incomplete <- incomplete private$chars$current <- current private$callback <- callback private$clear <- clear private$show_after <- as.difftime(show_after, units = "secs") private$spin <- spin_symbols() private$message_class <- message_class private$has_token <- pb_update_has_token(private$has_token, format) self } pb_update_has_token <- function(tokens, format) { for (n in names(tokens)) { tokens[n] <- grepl(paste0(":", n), format, fixed = TRUE) } tokens } pb_tick <- function(self, private, len, tokens) { assert_scalar(len) assert_named_or_empty_list(tokens) stopifnot(!self$finished) if (private$first) { private$first <- FALSE private$start <- Sys.time() } private$current <- private$current + len if (!private$toupdate) { if (Sys.time() - private$start >= private$show_after) { private$toupdate <- TRUE } } if (!is.na(private$total) && private$current >= private$total) { private$complete <- TRUE } if (private$toupdate) private$render(tokens) if (private$complete) { self$terminate() private$callback(self) } self } #' @importFrom prettyunits vague_dt pretty_bytes #' @importFrom utils flush.console pb_ratio <- function(self, private) { ratio <- (private$current / private$total) ratio <- max(ratio, 0) ratio <- min(ratio, 1) ratio } #' @importFrom hms as.hms #' @importFrom crayon col_nchar col_substr pb_render <- function(self, private, tokens) { if (! private$supported) return(invisible()) str <- private$format if (private$has_token["percent"]) { percent <- private$ratio() * 100 str <- sub(str, pattern = ":percent", replacement = paste0(format(round(percent), width = 3), "%")) } if (private$has_token["elapsedfull"]) { elapsed <- Sys.time() - private$start units(elapsed) <- "secs" elapsedfull <- format(as.hms(as.integer(elapsed))) str <- sub(str, pattern = ":elapsedfull", replacement = elapsedfull) } if (private$has_token["elapsed"]) { elapsed_secs <- Sys.time() - private$start elapsed <- vague_dt(elapsed_secs, format = "terse") str <- sub(str, pattern = ":elapsed", replacement = elapsed) } if (private$has_token["eta"]) { if (is.na(private$total)) { eta <- "?" } else { percent <- private$ratio() * 100 elapsed_secs <- Sys.time() - private$start eta_secs <- if (percent == 100) { 0 } else { elapsed_secs * (private$total / private$current - 1.0) } eta <- as.difftime(eta_secs, units = "secs") if (is.nan(eta) || eta == Inf) { eta <- " ?s" } else { eta <- vague_dt(eta, format = "terse") } } str <- sub(str, pattern = ":eta", replacement = eta) } if (private$has_token["rate"]) { elapsed_secs <- Sys.time() - private$start rate <- private$current / as.double(elapsed_secs, units = "secs") if (is.nan(rate)) rate <- 0 rate <- paste0(pretty_bytes(round(rate)), "/s") str <- sub(str, pattern = ":rate", replacement = rate) } if (private$has_token["tick_rate"]) { elapsed_secs <- Sys.time() - private$start tick_rate <- private$current / as.double(elapsed_secs, units = "secs") if (is.nan(tick_rate)) tick_rate <- 0 tick_rate <- format(tick_rate, digits = 2) str <- sub(str, pattern = ":tick_rate", replacement = tick_rate) } if (private$has_token["current"]) { str <- sub(str, pattern = ":current", replacement = round(private$current)) } if (private$has_token["total"]) { str <- sub(str, pattern = ":total", replacement = round(private$total)) } if (private$has_token["bytes"]) { bytes <- pretty_bytes(round(private$current)) str <- sub(str, pattern = ":bytes", replacement = bytes) } if (private$has_token["spin"]) { ## NOTE: fixed = TRUE is needed here or "\\" causes trouble with ## the replacement (I think it's interpreted as an invalid ## backreference). str <- sub(str, pattern = ":spin", replacement = private$spin(), fixed = TRUE) } for (t in names(tokens)) { txt <- tryCatch(as.character(tokens[[t]])[[1]], error = function(e) "???") str <- gsub(paste0(":", t), txt, str, fixed = TRUE) } if (private$has_token["bar"]) { bar_width <- col_nchar(sub(str, pattern = ":bar", replacement = "")) bar_width <- private$width - bar_width bar_width <- max(0, bar_width) ratio <- private$ratio() complete_len <- round(bar_width * ratio) complete <- paste(rep("", complete_len), collapse = private$chars$complete) current <- if (private$complete) { private$chars$complete } else if (complete_len >= 1) { private$chars$current } incomplete <- paste(rep("", bar_width - complete_len + 1), collapse = private$chars$incomplete) str <- sub( ":bar", paste0(complete, current, incomplete), str) } if (col_nchar(str) > private$width) { str <- paste0(col_substr(str, 1, private$width - 3), "...") } if (private$last_draw != str) { if (col_nchar(private$last_draw) > col_nchar(str)) { private$clear_line(private$width) } private$cursor_to_start() private$progress_message(str, appendLF = FALSE) private$last_draw <- str } flush.console() self } pb_update <- function(self, private, ratio, tokens) { assert_ratio(ratio) stopifnot(!self$finished) goal <- floor(ratio * private$total) self$tick(goal - private$current, tokens) } pb_message <- function(self, private, msg, set_width) { assert_character(msg) stopifnot(!self$finished) if (set_width) { too_long <- col_nchar(msg) > private$width if (any(too_long)) { msg[too_long] <- paste0(col_substr(msg[too_long], 1, private$width - 3), "...") } } if (!private$supported) { private$progress_message(paste0(msg, "\n"), appendLF = FALSE) } else { private$clear_line(private$width) private$cursor_to_start() private$progress_message(paste0(msg, "\n"), appendLF = FALSE) if (!self$finished) { private$progress_message(private$last_draw, appendLF = FALSE) } } } pb_terminate <- function(self, private) { self$finished <- TRUE if (!private$supported || !private$toupdate) return(invisible()) if (private$clear) { private$clear_line(private$width) private$cursor_to_start() } else { private$progress_message("\n", appendLF = FALSE) } } spin_symbols <- function() { sym <- c("-", "\\", "|", "/") i <- 0L n <- length(sym) function() { sym[[i <<- if (i >= n) 1L else i + 1L]] } } pb_progress_message <- function(self, private, ..., domain, appendLF) { msg <- .makeMessage(..., domain = domain, appendLF = appendLF) cond <- structure( list(message = msg, call = NULL), class = c(private$message_class, "message", "condition")) defaultHandler <- function(c) { cat(conditionMessage(c), file = stderr(), sep = "") } withRestarts({ signalCondition(cond) defaultHandler(cond) }, muffleMessage = function() NULL) invisible() } pb_clear_line <- function(self, private, width) { str <- paste0(c("\r", rep(" ", width)), collapse = "") private$progress_message(str, appendLF = FALSE) } pb_cursor_to_start <- function(self, private) { private$progress_message("\r", appendLF = FALSE) } progress/R/progress-package.R0000644000176200001440000000013514521421362015676 0ustar liggesusers#' @keywords internal "_PACKAGE" ## usethis namespace: start ## usethis namespace: end NULL progress/NEWS.md0000644000176200001440000000407314533567072013234 0ustar liggesusers# progress 1.2.3 * Compiling packages linking to progress with `-Wformat-security` does not produce warnings now. # 1.2.2 * Fix two bugs in the C++ API that can potentially cause irregular behavior (#94, @jimhester). # 1.2.1 * Add the `message_class` argument, to add extra classes to the messages thrown by progress. * Add support for RKWard, running interactive session (#76, @devillemereuil). * Add support for unicode characters and a right to left progress bar (#86, @jimhester). * Fix a potential crash in the C++ API (#91, @jimhester). # 1.2.0 * Option to change the 'current' character in the progress bar. #47 * New `:tick_rate` token, similar to `:rate`, but units are not assumed to be bytes. #45 * Total number of ticks can be set to `NA` now, if unknown. #48 * All progress bars (including the ones from the C++ API) can be turned off via the `progress_enabled` option #44 * The `stream` argument is deprecated and the progress bar is always printed with `message()` calls. * Total number of iterations can be zero, to support special cases better. * Add `finished` variable, which can be queried to see if a progress bar is finished. #54 @jimhester. * Add a `terminate()` method, which can be called to explicitly remove the progress bar, #53 @jimhester. * Outputs greater than the bar width are automatically trimmed, @jimhester. * Add a `message()` method to print a message line(s) above the progress bar, @jimhester. * :elapsedfull token: elapsed time in hh:mm:ss format. * Fix C++ compiler warnings. #43 * Fix C++ API on Windows. #56 * Pass `self` to the callback function. #55 @jimhester # 1.1.2 * Do not run tests on CRAN, Solaris does not have microbenchmark # 1.1.1 * Move README.md, so that it is not parsed on CRAN * Use https URLs instead of http, whenever possible # 1.1.0 * Support for the `:spin` token which adds a simple ASCII spinner, @richfitz * Respect custom token width for calculation of the bar width, @mllg # 1.0.2 * Fix the C++ API on Windows, and on older compilers in general. # 1.0.1 First version on CRAN. progress/MD50000644000176200001440000000301414534046452012433 0ustar liggesusers11f806377c7dfc3d3dad9420bb7a61af *DESCRIPTION 5a20935193b3a9d7647e38833c1e4e31 *LICENSE 451fe80009d43151fe0886ae44115397 *NAMESPACE 6123757dd068aaf865b141f58b854e5a *NEWS.md df6cc46bc7fae1a55b713f3d5065b35a *R/progress-package.R 2dc54e7733de9444aaeff080d1a73d6e *R/progress.R 1b02db14e760d0e9c2bc30f8867495fe *R/utils.R 353a3b97c2c5efc158cf35058145506e *README.md a0515fd2f2cc1e1e123e0cf0d98df0b3 *inst/include/RProgress.h 76f1f04c00cae388f24f4ff00636c2ae *man/figures/logo.png 4a607a53806f2e5afe5a834bcace11eb *man/figures/logo.svg d0ce98e6e470fc8c836ea949d928887c *man/progress-package.Rd 1ad6662e47d336a398e5f09a073a0098 *man/progress_bar.Rd 3dbcd1266497b7e99a346de399a3feb0 *tests/testthat.R c309786b4650345d8c91cdb57fe5b974 *tests/testthat/helper.R af33800129d8624fb14021937fcd8772 *tests/testthat/progresstest/DESCRIPTION 8488c7e8cbfc04df9ff69dd011f878da *tests/testthat/progresstest/LICENSE 3371cd47afc5c5d98fa417ecc159da01 *tests/testthat/progresstest/NAMESPACE c2cdf5a1e55a49006429aeb7dd31a594 *tests/testthat/progresstest/R/RcppExports.R ae293a874cbe1e425688493db9b3f7e1 *tests/testthat/progresstest/R/test.R 7c0b75a11963c889f7f87acfd22660c4 *tests/testthat/progresstest/README.md b9d306186d80dffa089a9f895d2cf673 *tests/testthat/progresstest/src/RcppExports.cpp ef246194c410954cfe185e60803dfbb4 *tests/testthat/progresstest/src/test.cpp a3f9288b2ac03c3232e92f397742b55d *tests/testthat/progresstest_1.0.0.tar.gz f0136cf66bf858dc154a3f7fea72cbaa *tests/testthat/test-cpp.R db8ec7c80325238e4ec58204335dcc7d *tests/testthat/test-progress.R progress/inst/0000755000176200001440000000000014214027113013066 5ustar liggesusersprogress/inst/include/0000755000176200001440000000000014533531711014521 5ustar liggesusersprogress/inst/include/RProgress.h0000644000176200001440000002606514533531711016631 0ustar liggesusers/* -*- mode: c++ -*- */ #ifndef R_PROGRESS_H #define R_PROGRESS_H #include #include #ifdef Win32 # include #endif #include #include #include #include #include #include #include #include #include #include // For gettimeofday implementation on windows #ifdef Win32 // MSVC defines this in winsock2.h!? typedef struct timeval { long tv_sec; long tv_usec; } timeval; int gettimeofday(struct timeval * tp, struct timezone * tzp); #endif namespace RProgress { class RProgress { public: RProgress(std::string format, double total, int width, std::string cursor_char, std::string complete_char, std::string incomplete_char, bool clear, double show_after) : first(true), format(format), total(total), current(0), count(0), width(width), cursor_char(cursor_char), complete_char(complete_char), incomplete_char(incomplete_char), clear(clear), show_after(show_after), last_draw(""), start(0), toupdate(false), complete(false), reverse(false) { supported = is_supported(); use_stderr = default_stderr(); } RProgress(std::string format = "[:bar] :percent", double total = 100, int width = Rf_GetOptionWidth() - 2, char complete_char = '=', char incomplete_char = '-', bool clear = true, double show_after = 0.2) : first(true), format(format), total(total), current(0), count(0), width(width), cursor_char(1, complete_char), complete_char(1, complete_char), incomplete_char(1, incomplete_char), clear(clear), show_after(show_after), last_draw(""), start(0), toupdate(false), complete(false), reverse(false) { supported = is_supported(); use_stderr = default_stderr(); } ~RProgress() { } void set_format(std::string format) { this->format = format; } void set_total(double total) { this->total = total; } void set_width(int width) { this->width = width; } void set_cursor_char(const char* cursor_char) { this->cursor_char = cursor_char; } void set_complete_char(const char* complete_char) { this->complete_char = complete_char; } void set_incomplete_char(const char* incomplete_char) { this->incomplete_char = incomplete_char; } void set_clear(bool clear) { this->clear = clear; } void set_show_after(double show_after) { this->show_after = show_after; } void set_reverse(bool reverse) { this->reverse = reverse; } void tick(double len = 1) { // Start the timer if (first) { start = time_now(); } current += len; count++; // We only update after show_after secs toupdate = toupdate || time_now() - start > show_after; if (current >= total) complete = true; // Need to render at the beginning and at the end, always if (first || toupdate || complete) this->render(); if (complete) this->terminate(); first = false; } void update(double ratio) { double goal = ratio * total; this->tick(goal - current); } private: bool first; // Is the next one the first tick? bool supported; // \r supported at all? std::string format; // Format template double total; // Total number of ticks double current; // Current number of ticks int count; // Total number of calls int width; // Width of progress bar bool use_stderr; // Whether to print to stderr std::string cursor_char; // Character for cursor tick std::string complete_char; // Character for completed ticks std::string incomplete_char; // Character for incomplete ticks bool clear; // Should we clear the line at the end? double show_after; // Delay to show/increase the progress bar std::string last_draw; // Last progress bar drawn double start; // Start time bool toupdate; // Are we updating? (After show_after.) bool complete; // Are we complete? bool reverse; // go from right to left rather than left to right void render() { if (!supported) return; std::string str = format; std::stringstream buffer; double ratio_now = ratio(); // percent buffer << std::setw(3) << ratio_now * 100 << "%"; replace_all(str, ":percent", buffer.str()); buffer.str(""); buffer.clear(); // elapsed double elapsed_secs = time_now() - start; std::string elapsed = vague_dt(elapsed_secs); replace_all(str, ":elapsed", elapsed); // eta double percent = round(ratio_now * 100); double eta_secs = percent == 100 ? 0 : elapsed_secs * (total / current - 1.0); std::string eta = std::isinf(eta_secs) ? "?s" : vague_dt(eta_secs); replace_all(str, ":eta", eta); // rate if (elapsed_secs == 0) { buffer << "?"; } else { double rate_num = elapsed_secs == 0 ? 0 : current / elapsed_secs; buffer << pretty_bytes(rate_num) << "/s"; } replace_all(str, ":rate", buffer.str()); buffer.str(""); buffer.clear(); // current buffer << round(current); replace_all(str, ":current", buffer.str()); buffer.str(""); buffer.clear(); // total buffer << round(total); replace_all(str, ":total", buffer.str()); buffer.str(""); buffer.clear(); // bytes replace_all(str, ":bytes", pretty_bytes(current)); // spin replace_all(str, ":spin", spin_symbol()); // bar std::string str_no_bar = str; replace_all(str_no_bar, ":bar", ""); long int bar_width = width - str_no_bar.length(); if (bar_width < 0) bar_width = 0; double complete_len = round(bar_width * ratio_now); std::string bar; if (reverse) { for (long int i = (long int) complete_len; i < bar_width; i++) { bar += incomplete_char; } if (complete_len > 0) { bar += cursor_char; } for (int i = 0; i < (complete_len - 1); i++) { bar += complete_char; } } else { for (int i = 0; i < (complete_len - 1); i++) { bar += complete_char; } if (complete_len > 0) { bar += cursor_char; } for (long int i = (long int) complete_len; i < bar_width; i++) { bar += incomplete_char; } } replace_all(str, ":bar", bar); if (last_draw != str) { if (last_draw.length() > str.length()) { clear_line(use_stderr, width); } cursor_to_start(use_stderr); if (use_stderr) { REprintf("%s", str.c_str()); } else { Rprintf("%s", str.c_str()); } last_draw = str; } } void terminate() { if (! supported) return; if (clear) { clear_line(use_stderr, width); cursor_to_start(use_stderr); } else { if (use_stderr) { REprintf("\n"); } else { Rprintf("\n"); } } } double ratio() { double ratio = current / total; if (ratio < 0) ratio = 0; if (ratio > 1) ratio = 1; return ratio; } std::string spin_symbol() { const char symbols[4] = {'-', '\\', '|', '/'}; return std::string(1, symbols[(count - 1) % 4]); } void clear_line(bool use_stderr, int width) { char *spaces = (char*) calloc(width + 2, sizeof(char)); if (!spaces) Rf_error("Progress bar: out of memory"); for (int i = 1; i <= width; i++) spaces[i] = ' '; spaces[0] = '\r'; spaces[width + 1] = '\0'; if (use_stderr) { REprintf("%s", spaces); } else { Rprintf("%s", spaces); } free(spaces); } void cursor_to_start(bool use_stderr) { if (use_stderr) { REprintf("\r"); } else { Rprintf("\r"); } } bool is_r_studio() { char *v = std::getenv("RSTUDIO"); return v != 0 && v[0] == '1' && v[1] == '\0'; } bool is_r_app() { char *v = std::getenv("R_GUI_APP_VERSION"); return v != 0; } // In R Studio we should print to stdout, because priting a \r // to stderr is buggy (reported) bool default_stderr() { return !is_r_studio(); } // If stdout is a terminal, or R Studio or macOS R.app // On windows, stdout is a terminal, apparently bool is_supported() { return is_option_enabled() && (isatty(1) || is_r_studio() || is_r_app()); } // gettimeofday for windows, from // https://stackoverflow.com/questions/10905892 #ifdef Win32 #define WIN32_LEAN_AND_MEAN #include #include // portable: uint64_t MSVC: __int64 int gettimeofday(struct timeval * tp, struct timezone * tzp) { // Note: some broken versions only have 8 trailing zero's, the correct epoch has 9 trailing zero's static const uint64_t EPOCH = ((uint64_t) 116444736000000000ULL); SYSTEMTIME system_time; FILETIME file_time; uint64_t time; GetSystemTime( &system_time ); SystemTimeToFileTime( &system_time, &file_time ); time = ((uint64_t)file_time.dwLowDateTime ) ; time += ((uint64_t)file_time.dwHighDateTime) << 32; tp->tv_sec = (long) ((time - EPOCH) / 10000000L); tp->tv_usec = (long) (system_time.wMilliseconds * 1000); return 0; } #endif static double time_now() { struct timeval now; gettimeofday(&now, /* tzp = */ 0); return now.tv_sec + now.tv_usec / 1000000.0; } static void replace_all(std::string& str, const std::string& from, const std::string& to) { if (from.empty()) return; size_t start_pos = 0; while ((start_pos = str.find(from, start_pos)) != std::string::npos) { str.replace(start_pos, from.length(), to); start_pos += to.length(); } } public: static std::string vague_dt(double seconds) { double minutes = seconds / 60; double hours = minutes / 60; double days = hours / 24; double years = days / 365.25; std::stringstream buffer; buffer << std::setw(2); if (seconds < 50) { buffer << round(seconds) << "s"; } else if (minutes < 50) { buffer << round(minutes) << "m"; } else if (hours < 18) { buffer << round(hours) << "h"; } else if (days < 30) { buffer << round(days) << "d"; } else if (days < 335) { buffer << round(days/30) << "M"; } else { buffer << round(years) << "y"; } return buffer.str(); } static std::string pretty_bytes(double rate) { errno = 0; long bytes = lround(rate); if (errno == ERANGE) { bytes = LONG_MAX; } if (bytes == 0) { return "0B"; } std::string units[] = { "B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" }; long int num_units = (long int)(sizeof(units) / sizeof(units[0])); double idx = std::floor(std::log(bytes) / std::log(1000.0)); if (idx >= num_units) { idx = num_units - 1; } double res = round(bytes / std::pow(1000.0, idx) * 100.0) / 100.0; std::stringstream buffer; buffer.precision(2); buffer << std::fixed << res << units[(long) idx]; return buffer.str(); } static bool is_option_enabled() { SEXP opt = PROTECT(Rf_GetOption1(Rf_install("progress_enabled"))); if (Rf_isNull(opt)) { UNPROTECT(1); return true; } Rboolean t = R_compute_identical(opt, Rf_ScalarLogical(1), 16); UNPROTECT(1); return t; } }; // class RProgress } // namespace RProgress #endif