[med-svn] [r-cran-progress] 05/07: New upstream version 1.1.2
Andreas Tille
tille at debian.org
Sat Sep 30 08:24:26 UTC 2017
This is an automated email from the git hooks/post-receive script.
tille pushed a commit to branch master
in repository r-cran-progress.
commit 8786a043357fb30929a8de2237498f0c547d4e62
Author: Andreas Tille <tille at debian.org>
Date: Sat Sep 30 10:21:59 2017 +0200
New upstream version 1.1.2
---
DESCRIPTION | 22 ++
LICENSE | 2 +
MD5 | 23 ++
NAMESPACE | 7 +
R/progress.R | 406 ++++++++++++++++++++++++++++++++++
R/utils.R | 105 +++++++++
debian/README.test | 8 -
debian/changelog | 5 -
debian/compat | 1 -
debian/control | 27 ---
debian/copyright | 32 ---
debian/docs | 3 -
debian/rules | 8 -
debian/source/format | 1 -
debian/tests/control | 5 -
debian/tests/run-unit-test | 17 --
debian/watch | 2 -
inst/NEWS.md | 22 ++
inst/README.metacran | 217 ++++++++++++++++++
inst/include/RProgress.h | 369 ++++++++++++++++++++++++++++++
inst/logo.png | Bin 0 -> 5935 bytes
inst/logo.svg | 199 +++++++++++++++++
inst/progresstest/DESCRIPTION | 12 +
inst/progresstest/LICENSE | 2 +
inst/progresstest/NAMESPACE | 6 +
inst/progresstest/R/RcppExports.R | 11 +
inst/progresstest/R/test.R | 9 +
inst/progresstest/README.md | 10 +
inst/progresstest/src/RcppExports.cpp | 28 +++
inst/progresstest/src/test.cpp | 58 +++++
man/progress_bar.Rd | 156 +++++++++++++
tests/testthat.R | 6 +
tests/testthat/helper.R | 39 ++++
tests/testthat/test-cpp.R | 42 ++++
tests/testthat/test-progress.R | 389 ++++++++++++++++++++++++++++++++
35 files changed, 2140 insertions(+), 109 deletions(-)
diff --git a/DESCRIPTION b/DESCRIPTION
new file mode 100644
index 0000000..440cbb2
--- /dev/null
+++ b/DESCRIPTION
@@ -0,0 +1,22 @@
+Package: progress
+Title: Terminal Progress Bars
+Version: 1.1.2
+Author: Gábor Csárdi [aut, cre], Rich FitzJohn [aut]
+Maintainer: Gábor Csárdi <csardi.gabor at gmail.com>
+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
+LazyData: true
+URL: https://github.com/gaborcsardi/progress#readme
+BugReports: https://github.com/gaborcsardi/progress/issues
+Imports: prettyunits, R6
+Suggests: testthat
+RoxygenNote: 5.0.1.9000
+Encoding: UTF-8
+NeedsCompilation: no
+Packaged: 2016-12-14 09:09:03 UTC; gaborcsardi
+Repository: CRAN
+Date/Publication: 2016-12-14 17:23:33
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..99ce77d
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,2 @@
+YEAR: 2015-2016
+COPYRIGHT HOLDER: Gábor Csárdi
diff --git a/MD5 b/MD5
new file mode 100644
index 0000000..8d629af
--- /dev/null
+++ b/MD5
@@ -0,0 +1,23 @@
+22a1bb1188d47dcba16533993a530159 *DESCRIPTION
+e4c81207cdbd596c9e35a231e630e872 *LICENSE
+8c924c80c47fd4b443134b51ba5ffcd9 *NAMESPACE
+b814ea50b680ffb9db27ad4baaf7b94f *R/progress.R
+35e20d402c9bd0054a782d01fc4b61dd *R/utils.R
+0c9e74abc8221a0c1c9b5b5d6a6a4dae *inst/NEWS.md
+b8e0ee67cec086fe5622fc959d3c8e97 *inst/README.metacran
+6ddb5651141969fda582967e204cd0e2 *inst/include/RProgress.h
+76f1f04c00cae388f24f4ff00636c2ae *inst/logo.png
+4a607a53806f2e5afe5a834bcace11eb *inst/logo.svg
+b5981f6a5d933fb66575a38a8a15d187 *inst/progresstest/DESCRIPTION
+8488c7e8cbfc04df9ff69dd011f878da *inst/progresstest/LICENSE
+1906d818824028e3d8c5a38121018524 *inst/progresstest/NAMESPACE
+9d75ffa9d3665660c3cdcf39ad5065b8 *inst/progresstest/R/RcppExports.R
+1db6705374372ff537ad6a1856de075a *inst/progresstest/R/test.R
+7c0b75a11963c889f7f87acfd22660c4 *inst/progresstest/README.md
+7d4c5db3fbe2c2b7c93be3062b280604 *inst/progresstest/src/RcppExports.cpp
+8a6f1090313e7c4b076ef60cd0838175 *inst/progresstest/src/test.cpp
+22fa2206d93e2b35d881c622a29a4751 *man/progress_bar.Rd
+95d3bb15732f376a121c2d619708824e *tests/testthat.R
+13dc299450724118ac82173b952468fd *tests/testthat/helper.R
+367aa8feade5b32c0307395662836aaf *tests/testthat/test-cpp.R
+62bfdd32271e3f6a629473f52d792de8 *tests/testthat/test-progress.R
diff --git a/NAMESPACE b/NAMESPACE
new file mode 100644
index 0000000..99b6f69
--- /dev/null
+++ b/NAMESPACE
@@ -0,0 +1,7 @@
+# Generated by roxygen2: do not edit by hand
+
+export(progress_bar)
+importFrom(R6,R6Class)
+importFrom(prettyunits,pretty_bytes)
+importFrom(prettyunits,vague_dt)
+importFrom(utils,flush.console)
diff --git a/R/progress.R b/R/progress.R
new file mode 100644
index 0000000..5bb2c9e
--- /dev/null
+++ b/R/progress.R
@@ -0,0 +1,406 @@
+
+#' 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
+#' \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. 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}{The output stream to put the progress bar on.
+#' It defaults to \code{stderr()}, except in R Studio that has
+#' a bug when printing on the standard error, so there we use
+#' \code{stdout}. If the output stream is not a terminal and
+#' we are not in R Studio, then no progress bar is printed.}
+#' \item{complete}{Completion character, defaults to \code{=}.}
+#' \item{incomplete}{Incomplete 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 support it.}
+#' }
+#'
+#' @section Using the progress bar:
+#' Two 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.
+#'
+#' 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.
+#'
+#' @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{:eta}{Estimated completion time in seconds.}
+#' \item{:percent}{Completion percentage.}
+#' \item{:rate}{Download rate, bytes per second. See example below.}
+#' \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.
+#'
+#' @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 = 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()
+#'
+#' }
+#'
+#' @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 = "-", callback = function(self) {}, clear = TRUE,
+ show_after = 0.2, force = FALSE) {
+ pb_init(self, private, format, total, width, stream, complete,
+ incomplete, callback, clear, show_after, force)
+ },
+ tick = function(len = 1, tokens = list()) {
+ pb_tick(self, private, len, tokens) },
+ update = function(ratio, tokens = list()) {
+ pb_update(self, private, ratio, tokens) }
+ ),
+
+ private = list(
+
+ render = function(tokens) { pb_render(self, private, tokens) },
+ terminate = function() { pb_terminate(self, private) },
+ ratio = function() { pb_ratio(self, private) },
+
+ first = TRUE,
+ supported = NA,
+ format = NULL,
+ total = NULL,
+ current = 0,
+ width = NULL,
+ stream = NULL,
+ chars = list(
+ complete = "=",
+ incomplete = "-"
+ ),
+ callback = NULL,
+ clear = NULL,
+ show_after = NULL,
+ last_draw = "",
+
+ start = NULL,
+ toupdate = FALSE,
+ complete = FALSE,
+
+ spin = NULL,
+
+ has_token = c(current = FALSE, total = FALSE, elapsed = FALSE,
+ eta = FALSE, percent = FALSE, rate = FALSE, bytes = FALSE,
+ bar = FALSE, spin = FALSE)
+ )
+)
+
+pb_init <- function(self, private, format, total, width, stream,
+ complete, incomplete, callback, clear, show_after,
+ force) {
+
+ stream <- default_stream(stream)
+
+ assert_character_scalar(format)
+ assert_positive_scalar(total)
+ assert_nonzero_count(width)
+ assert_connection(stream)
+ assert_single_char(complete)
+ assert_single_char(incomplete)
+ assert_function(callback)
+ assert_flag(clear)
+ assert_nonnegative_scalar(show_after)
+
+ private$first <- TRUE
+ private$supported <- force || is_supported(stream)
+ private$format <- format
+ private$total <- total
+ private$width <- width
+ private$stream <- stream
+ private$chars$complete <- complete
+ private$chars$incomplete <- incomplete
+ private$callback <- callback
+ private$clear <- clear
+ private$show_after <- as.difftime(show_after, units = "secs")
+ private$spin <- spin_symbols()
+
+ 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)
+
+ 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 (private$current >= private$total) private$complete <- TRUE
+
+ if (private$toupdate) private$render(tokens)
+
+ if (private$complete) {
+ private$terminate()
+ private$callback()
+ }
+
+ 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
+}
+
+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["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"]) {
+ 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["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)) {
+ str <- gsub(paste0(":", t), tokens[[t]], str, fixed = TRUE)
+ }
+
+ if (private$has_token["bar"]) {
+ bar_width <- 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 + 1),
+ collapse = private$chars$complete)
+ incomplete <- paste(rep("", bar_width - complete_len + 1),
+ collapse = private$chars$incomplete)
+
+ str <- sub(":bar", paste0(complete, incomplete), str)
+ }
+
+ if (private$last_draw != str) {
+ if (nchar(private$last_draw) > nchar(str)) {
+ clear_line(private$stream, private$width)
+ }
+ cursor_to_start(private$stream)
+ cat(str, file = private$stream)
+ private$last_draw <- str
+ }
+
+ flush.console()
+
+ self
+}
+
+pb_update <- function(self, private, ratio, tokens) {
+ assert_ratio(ratio)
+ goal <- floor(ratio * private$total)
+ self$tick(goal - private$current, tokens)
+}
+
+pb_terminate <- function(self, private) {
+ if (!private$supported || !private$toupdate) return(invisible())
+ if (private$clear) {
+ clear_line(private$stream, private$width)
+ cursor_to_start(private$stream)
+ } else {
+ cat("\n", file = private$stream)
+ }
+}
+
+spin_symbols <- function() {
+ sym <- c("-", "\\", "|", "/")
+ i <- 0L
+ n <- length(sym)
+ function() {
+ sym[[i <<- if (i >= n) 1L else i + 1L]]
+ }
+}
diff --git a/R/utils.R b/R/utils.R
new file mode 100644
index 0000000..6ef3fe6
--- /dev/null
+++ b/R/utils.R
@@ -0,0 +1,105 @@
+
+clear_line <- function(tty, width) {
+ str <- paste0(c("\r", rep(" ", width)), collapse = "")
+ cat(str, file = tty)
+}
+
+cursor_to_start <- function(tty) {
+ cat("\r", file = tty)
+}
+
+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_stdout <- function(stream) {
+ interactive() &&
+ is_r_studio() &&
+ identical(stream, stdout()) &&
+ is_stdout(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_supported <- function(stream) {
+ isatty(stream) || r_studio_stdout(stream) || r_app_stdx(stream)
+}
+
+default_stream <- function(stream) {
+ if (! is.null(stream)) {
+ stream
+ } else {
+ if (is_r_studio()) stdout() else stderr()
+ }
+}
+
+assert_character_scalar <- function(x) {
+ stopifnot(is.character(x),
+ length(x) == 1,
+ !is.na(x))
+}
+
+assert_scalar <- function(x, finite = TRUE) {
+ stopifnot(is.numeric(x),
+ length(x) == 1,
+ !is.na(x),
+ !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) {
+ assert_scalar(x, finite = finite)
+ stopifnot(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)))
+}
diff --git a/debian/README.test b/debian/README.test
deleted file mode 100644
index 53fb4d7..0000000
--- a/debian/README.test
+++ /dev/null
@@ -1,8 +0,0 @@
-Notes on how this package can be tested.
-────────────────────────────────────────
-
-This package can be tested by running the provided test:
-
- sh ./run-unit-test
-
-in order to confirm its integrity.
diff --git a/debian/changelog b/debian/changelog
deleted file mode 100644
index 8e4f417..0000000
--- a/debian/changelog
+++ /dev/null
@@ -1,5 +0,0 @@
-r-cran-progress (1.1.2-1) unstable; urgency=medium
-
- * Initial release (closes: #848659)
-
- -- Andreas Tille <tille at debian.org> Mon, 19 Dec 2016 11:43:31 +0100
diff --git a/debian/compat b/debian/compat
deleted file mode 100644
index f599e28..0000000
--- a/debian/compat
+++ /dev/null
@@ -1 +0,0 @@
-10
diff --git a/debian/control b/debian/control
deleted file mode 100644
index cb8431e..0000000
--- a/debian/control
+++ /dev/null
@@ -1,27 +0,0 @@
-Source: r-cran-progress
-Maintainer: Debian Med Packaging Team <debian-med-packaging at lists.alioth.debian.org>
-Uploaders: Andreas Tille <tille at debian.org>
-Section: gnu-r
-Priority: optional
-Build-Depends: debhelper (>= 10),
- dh-r,
- r-base-dev,
- r-cran-r6,
- r-cran-prettyunits
-Standards-Version: 3.9.8
-Vcs-Browser: https://anonscm.debian.org/viewvc/debian-med/trunk/packages/R/r-cran-progress/trunk/
-Vcs-Svn: svn://anonscm.debian.org/debian-med/trunk/packages/R/r-cran-progress/trunk/
-Homepage: https://cran.r-project.org/package=progress
-
-Package: r-cran-progress
-Architecture: all
-Depends: ${R:Depends},
- ${misc:Depends}
-Recommends: ${R:Recommends}
-Suggests: ${R:Suggests}
-Description: GNU R terminal progress bars
- Configurable Progress bars for GNU R, 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'.
diff --git a/debian/copyright b/debian/copyright
deleted file mode 100644
index 2959ed2..0000000
--- a/debian/copyright
+++ /dev/null
@@ -1,32 +0,0 @@
-Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
-Upstream-Name: progress
-Upstream-Contact: Gábor Csárdi <csardi.gabor at gmail.com>
-Source: https://cran.r-project.org/package=progress
-
-Files: *
-Copyright: 2015-2016 Gábor Csárdi, Rich FitzJohn
-License: MIT
-
-Files: debian/*
-Copyright: 2016 Andreas Tille <tille at debian.org>
-License: MIT
-
-License: MIT
- 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.
diff --git a/debian/docs b/debian/docs
deleted file mode 100644
index 6466d39..0000000
--- a/debian/docs
+++ /dev/null
@@ -1,3 +0,0 @@
-debian/tests/run-unit-test
-debian/README.test
-tests
diff --git a/debian/rules b/debian/rules
deleted file mode 100755
index ae86733..0000000
--- a/debian/rules
+++ /dev/null
@@ -1,8 +0,0 @@
-#!/usr/bin/make -f
-
-%:
- dh $@ --buildsystem R
-
-override_dh_install:
- dh_install
- find debian -name LICENSE -delete
diff --git a/debian/source/format b/debian/source/format
deleted file mode 100644
index 163aaf8..0000000
--- a/debian/source/format
+++ /dev/null
@@ -1 +0,0 @@
-3.0 (quilt)
diff --git a/debian/tests/control b/debian/tests/control
deleted file mode 100644
index a62fb6e..0000000
--- a/debian/tests/control
+++ /dev/null
@@ -1,5 +0,0 @@
-Tests: run-unit-test
-Depends: @, r-cran-testthat,
-Restrictions: allow-stderr
-
-
diff --git a/debian/tests/run-unit-test b/debian/tests/run-unit-test
deleted file mode 100644
index a8e03f0..0000000
--- a/debian/tests/run-unit-test
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/sh -e
-
-pkgname=progress
-debname=r-cran-progress
-
-if [ "$ADTTMP" = "" ] ; then
- ADTTMP=`mktemp -d /tmp/${debname}-test.XXXXXX`
- trap "rm -rf $ADTTMP" 0 INT QUIT ABRT PIPE TERM
-fi
-cd $ADTTMP
-cp -a /usr/share/doc/$debname/tests/* $ADTTMP
-gunzip -r *
-for testfile in *.R; do
- echo "BEGIN TEST $testfile"
- LC_ALL=C R --no-save < $testfile
-done
-
diff --git a/debian/watch b/debian/watch
deleted file mode 100644
index a30a454..0000000
--- a/debian/watch
+++ /dev/null
@@ -1,2 +0,0 @@
-version=4
-https://cran.r-project.org/src/contrib/progress_([-\d.]*)\.tar\.gz
diff --git a/inst/NEWS.md b/inst/NEWS.md
new file mode 100644
index 0000000..d5b96fe
--- /dev/null
+++ b/inst/NEWS.md
@@ -0,0 +1,22 @@
+
+# 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.
diff --git a/inst/README.metacran b/inst/README.metacran
new file mode 100644
index 0000000..a0ba8a3
--- /dev/null
+++ b/inst/README.metacran
@@ -0,0 +1,217 @@
+
+<h1 align="center">
+ <br>
+ <br>
+ <img width="400" src="./inst/logo.png" alt="progress">
+ <br>
+ <br>
+ <br>
+</h1>
+
+[![Linux Build Status](https://travis-ci.org/gaborcsardi/progress.svg?branch=master)](https://travis-ci.org/gaborcsardi/progress)
+[![Windows Build status](https://ci.appveyor.com/api/projects/status/github/gaborcsardi/progress?svg=true)](https://ci.appveyor.com/project/gaborcsardi/progress)
+[![](https://www.r-pkg.org/badges/version/progress)](https://r-pkg.org/pkg/progress)
+
+> 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
+
+```r
+devtools::install_github("gaborcsardi/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
+```
+
+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.
+
+## 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](inst/progresstest/src/test.cpp) that
+is [included](inst/progresstest) within `progress`. Here is a short excerpt
+that shows how it works:
+
+```CPP
+
+#include <RProgress.h>
+
+...
+
+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
diff --git a/inst/include/RProgress.h b/inst/include/RProgress.h
new file mode 100644
index 0000000..a8da98c
--- /dev/null
+++ b/inst/include/RProgress.h
@@ -0,0 +1,369 @@
+/* -*- mode: c++ -*- */
+
+#ifndef R_PROGRESS_H
+#define R_PROGRESS_H
+
+#include <unistd.h>
+#include <sys/time.h>
+
+#ifdef Win32
+# include <io.h>
+#endif
+
+#include <string>
+#include <sstream>
+#include <iomanip>
+#include <cmath>
+#include <cstring>
+#include <cstdlib>
+
+#include <Rinternals.h>
+#include <R_ext/Print.h>
+
+// 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 = "[: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), width(width),
+ complete_char(complete_char), incomplete_char(incomplete_char),
+ clear(clear), show_after(show_after), last_draw(""), start(0),
+ toupdate(false), complete(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_complete_char(char complete_char) {
+ this->complete_char = complete_char;
+ }
+ void set_incomplete_char(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 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
+ char complete_char; // Character for completed ticks
+ char 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?
+
+ 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
+ double rate_num = current / elapsed_secs;
+ buffer << pretty_bytes(round(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(round(current)));
+
+ // spin
+ replace_all(str, ":spin", spin_symbol());
+
+ // bar
+ std::string str_no_bar = str;
+ replace_all(str_no_bar, ":bar", "");
+ int bar_width = width - str_no_bar.length();
+ if (bar_width < 0) bar_width = 0;
+
+ double complete_len = round(bar_width * ratio_now);
+ char bar[bar_width + 1];
+ for (int i = 0; i < complete_len; i++) { bar[i] = complete_char; }
+ for (int i = complete_len; i < bar_width; i++) {
+ bar[i] = incomplete_char;
+ }
+ bar[bar_width] = '\0';
+ 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(str.c_str());
+ } else {
+ Rprintf(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[width + 2];
+ for (int i = 1; i <= width; i++) spaces[i] = ' ';
+ spaces[0] = '\r';
+ spaces[width + 1] = '\0';
+
+ if (use_stderr) {
+ REprintf(spaces);
+ } else {
+ Rprintf(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 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 <Windows.h>
+#include <stdint.h> // 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(long bytes) {
+
+ if (bytes == 0) { return "0B"; }
+
+ std::string units[] = { "B", "kB", "MB", "GB", "TB", "PB", "EB",
+ "ZB", "YB" };
+ int num_units = std::floor(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();
+ }
+
+}; // class RProgress
+
+} // namespace RProgress
+
+#endif
diff --git a/inst/logo.png b/inst/logo.png
new file mode 100644
index 0000000..5d80b4c
Binary files /dev/null and b/inst/logo.png differ
diff --git a/inst/logo.svg b/inst/logo.svg
new file mode 100644
index 0000000..6301496
--- /dev/null
+++ b/inst/logo.svg
@@ -0,0 +1,199 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="46.846344mm"
+ height="15.024148mm"
+ viewBox="0 0 165.99098 53.23517"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.91 r13725"
+ sodipodi:docname="logo.svg">
+ <defs
+ id="defs4" />
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="4.0042847"
+ inkscape:cx="77.616416"
+ inkscape:cy="16.931869"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="false"
+ fit-margin-top="1"
+ fit-margin-left="1"
+ fit-margin-right="1"
+ fit-margin-bottom="1"
+ inkscape:window-width="1676"
+ inkscape:window-height="1005"
+ inkscape:window-x="4"
+ inkscape:window-y="0"
+ inkscape:window-maximized="1" />
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(-138.8815,-336.25359)">
+ <g
+ id="g4348">
+ <g
+ id="g4191">
+ <path
+ inkscape:connector-curvature="0"
+ id="path4143"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:125%;font-family:'Electric Boots';-inkscape-font-specification:'Electric Boots';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 169.02881,355.1689 -10.188,0 -1.08,10.296 -5.184,0 2.7,-25.668 15.372,0 -1.62,15.372 z m -4.572,-5.148 0.504,-5.076 -5.076,0 -0.54,5.076 5.112,0 z m -11.808,-7.704 -10.224,0 0.252,-2.52 10.224,0 -0.252,2.52 z m -0.54,5.148 -8.532,0 0.288,-2.52 8.496,0 -0.252,2.52 z m -0.54,5.148 -6.804,0 0.252,-2.52 6.804,0 -0.252,2.52 z m -0.54,5.112 -5.076,0 0.252,-2.52 5.076,0 -0.252,2.52 z m -0.54,5.148 -3.384,0 0.288,-2.52 3.348,0 -0.252,2.52 z" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path4145"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:125%;font-family:'Electric Boots';-inkscape-font-specification:'Electric Boots';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 184.84574,365.4649 -5.112,0 0.324,-3.312 -2.664,-6.984 -1.692,0 -1.08,10.296 -5.184,0 2.7,-25.668 15.372,0 -1.62,15.372 -2.412,0 1.836,5.58 -0.468,4.716 z m -3.528,-15.444 0.504,-5.076 -5.076,0 -0.54,5.076 5.112,0 z" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path4147"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:125%;font-family:'Electric Boots';-inkscape-font-specification:'Electric Boots';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 202.45818,365.4649 -15.372,0 2.7,-25.668 15.372,0 -2.7,25.668 z m -4.572,-5.148 1.584,-15.372 -5.076,0 -1.62,15.372 5.112,0 z" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path4149"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:125%;font-family:'Electric Boots';-inkscape-font-specification:'Electric Boots';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 220.10662,365.4649 -15.372,0 2.7,-25.668 15.372,0 -0.54,5.076 -10.224,0 -1.62,15.444 5.112,0 0.54,-5.076 -2.556,0 0.54,-5.148 7.668,0 -1.62,15.372 z" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path4151"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:125%;font-family:'Electric Boots';-inkscape-font-specification:'Electric Boots';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 237.79106,365.4649 -5.112,0 0.324,-3.312 -2.664,-6.984 -1.692,0 -1.08,10.296 -5.184,0 2.7,-25.668 15.372,0 -1.62,15.372 -2.412,0 1.836,5.58 -0.468,4.716 z m -3.528,-15.444 0.504,-5.076 -5.076,0 -0.54,5.076 5.112,0 z" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path4153"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:125%;font-family:'Electric Boots';-inkscape-font-specification:'Electric Boots';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 255.40349,365.4649 -15.372,0 2.7,-25.668 15.372,0 -0.54,5.076 -10.224,0 -0.54,5.112 10.26,0 -0.576,5.184 -10.224,0 -0.54,5.112 10.26,0 -0.576,5.184 z" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path4155"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:125%;font-family:'Electric Boots';-inkscape-font-specification:'Electric Boots';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 272.63006,365.4649 -15.372,0 0.54,-5.112 10.26,0 0.54,-5.112 -10.26,0 1.62,-15.444 15.372,0 -0.54,5.076 -10.224,0 -0.54,5.112 10.26,0 -1.656,15.48 z" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path4157"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:125%;font-family:'Electric Boots';-inkscape-font-specification:'Electric Boots';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 290.27849,365.4649 -15.372,0 0.54,-5.112 10.26,0 0.54,-5.112 -10.26,0 1.62,-15.444 15.372,0 -0.54,5.076 -10.224,0 -0.54,5.112 10.26,0 -1.656,15.48 z" />
+ </g>
+ <g
+ transform="translate(-0.49946499,-0.24973254)"
+ id="g4328">
+ <g
+ id="g4310">
+ <path
+ inkscape:connector-curvature="0"
+ id="path4280"
+ d="m 167.16147,374.75152 -16.22484,0 0.56996,-5.076 16.22484,0 -0.56996,5.076 z"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:125%;font-family:'Electric Boots';-inkscape-font-specification:'Electric Boots';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path4251"
+ d="m 166.02155,381.79886 -16.22484,0 0.56996,-5.112 16.22484,0 -0.56996,5.112 z"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:125%;font-family:'Electric Boots';-inkscape-font-specification:'Electric Boots';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path4284"
+ d="m 184.75006,374.75152 -16.22484,0 0.56996,-5.076 16.22484,0 -0.56996,5.076 z"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:125%;font-family:'Electric Boots';-inkscape-font-specification:'Electric Boots';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path4253"
+ d="m 183.61014,381.79886 -16.22484,0 0.56996,-5.112 16.22484,0 -0.56996,5.112 z"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:125%;font-family:'Electric Boots';-inkscape-font-specification:'Electric Boots';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path4288"
+ d="m 202.33865,374.75152 -16.22484,0 0.56996,-5.076 16.22484,0 -0.56996,5.076 z"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:125%;font-family:'Electric Boots';-inkscape-font-specification:'Electric Boots';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path4255"
+ d="m 201.19873,381.79886 -16.22484,0 0.56996,-5.112 16.22484,0 -0.56996,5.112 z"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:125%;font-family:'Electric Boots';-inkscape-font-specification:'Electric Boots';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path4292"
+ d="m 219.92725,374.75152 -16.22484,0 0.56996,-5.076 16.22484,0 -0.56996,5.076 z"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:125%;font-family:'Electric Boots';-inkscape-font-specification:'Electric Boots';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path4257"
+ d="m 218.78733,381.79886 -16.22484,0 0.56996,-5.112 16.22484,0 -0.56996,5.112 z"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:125%;font-family:'Electric Boots';-inkscape-font-specification:'Electric Boots';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path4296"
+ d="m 237.51584,374.75152 -16.22484,0 0.56996,-5.076 16.22484,0 -0.56996,5.076 z"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:125%;font-family:'Electric Boots';-inkscape-font-specification:'Electric Boots';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path4259"
+ d="m 236.37593,381.79886 -16.22485,0 0.56996,-5.112 16.22484,0 -0.56995,5.112 z"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:125%;font-family:'Electric Boots';-inkscape-font-specification:'Electric Boots';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path4300"
+ d="m 255.10443,374.75152 -16.22484,0 0.56996,-5.076 16.22484,0 -0.56996,5.076 z"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:125%;font-family:'Electric Boots';-inkscape-font-specification:'Electric Boots';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path4261"
+ d="m 253.96452,381.79886 -16.22485,0 0.56996,-5.112 16.22484,0 -0.56995,5.112 z"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:125%;font-family:'Electric Boots';-inkscape-font-specification:'Electric Boots';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path4304"
+ d="m 272.69302,374.75152 -16.22484,0 0.56996,-5.076 16.22484,0 -0.56996,5.076 z"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:125%;font-family:'Electric Boots';-inkscape-font-specification:'Electric Boots';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path4263"
+ d="m 271.55311,381.79886 -16.22485,0 0.56996,-5.112 16.22485,0 -0.56996,5.112 z"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:125%;font-family:'Electric Boots';-inkscape-font-specification:'Electric Boots';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path4308"
+ d="m 290.28163,374.75152 -16.22485,0 0.56996,-5.076 16.22485,0 -0.56996,5.076 z"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:125%;font-family:'Electric Boots';-inkscape-font-specification:'Electric Boots';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path4265"
+ d="m 289.14171,381.79886 -16.22485,0 0.56996,-5.112 16.22485,0 -0.56996,5.112 z"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:125%;font-family:'Electric Boots';-inkscape-font-specification:'Electric Boots';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ </g>
+ <path
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:125%;font-family:'Electric Boots';-inkscape-font-specification:'Electric Boots';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ inkscape:connector-curvature="0"
+ id="path4267"
+ d="m 292.21533,367.72719 3.26777,7.992 -5.01565,7.992 4.52168,2.484 6.83952,-10.476 -4.52168,-10.44 -5.09164,2.448 z" />
+ </g>
+ </g>
+ </g>
+</svg>
diff --git a/inst/progresstest/DESCRIPTION b/inst/progresstest/DESCRIPTION
new file mode 100644
index 0000000..bdfeb7a
--- /dev/null
+++ b/inst/progresstest/DESCRIPTION
@@ -0,0 +1,12 @@
+Package: progresstest
+Title: Testing Terminal Progress Bars
+Version: 1.0.0
+Authors at R: person("Gabor", "Csardi", , "csardi.gabort at gmail.com", role = c("aut", "cre"))
+Description: Test progress bars from the progress package.
+License: MIT + file LICENSE
+Imports:
+ progress,
+ Rcpp
+LinkingTo:
+ progress,
+ Rcpp
diff --git a/inst/progresstest/LICENSE b/inst/progresstest/LICENSE
new file mode 100644
index 0000000..9236fad
--- /dev/null
+++ b/inst/progresstest/LICENSE
@@ -0,0 +1,2 @@
+YEAR: 2015
+COPYRIGHT HOLDER: Gabor Csardi
diff --git a/inst/progresstest/NAMESPACE b/inst/progresstest/NAMESPACE
new file mode 100644
index 0000000..6b525d9
--- /dev/null
+++ b/inst/progresstest/NAMESPACE
@@ -0,0 +1,6 @@
+# Generated by roxygen2 (4.1.0): do not edit by hand
+
+importFrom(Rcpp,loadRcppModules)
+importFrom(progress,progress_bar)
+useDynLib(progresstest)
+export(my_test_progress)
diff --git a/inst/progresstest/R/RcppExports.R b/inst/progresstest/R/RcppExports.R
new file mode 100644
index 0000000..c1257d2
--- /dev/null
+++ b/inst/progresstest/R/RcppExports.R
@@ -0,0 +1,11 @@
+# This file was generated by Rcpp::compileAttributes
+# Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393
+
+test_progress <- function(formatSEXP = "[:bar] :percent ") {
+ .Call('progresstest_test_progress', PACKAGE = 'progresstest', formatSEXP)
+}
+
+test_units <- function() {
+ .Call('progresstest_test_units', PACKAGE = 'progresstest')
+}
+
diff --git a/inst/progresstest/R/test.R b/inst/progresstest/R/test.R
new file mode 100644
index 0000000..0c077fe
--- /dev/null
+++ b/inst/progresstest/R/test.R
@@ -0,0 +1,9 @@
+
+#' @importFrom progress progress_bar
+#' @importFrom Rcpp loadRcppModules
+#' @useDynLib progresstest
+#' @export
+
+my_test_progress <- function(format = "[:bar] :percent ") {
+ test_progress(format)
+}
diff --git a/inst/progresstest/README.md b/inst/progresstest/README.md
new file mode 100644
index 0000000..70377f4
--- /dev/null
+++ b/inst/progresstest/README.md
@@ -0,0 +1,10 @@
+
+## Example package for the C++ API of `progress`
+
+Progress bars for your C++ code in R packages.
+The `progress` package has a pure C++ API for
+managing progress bars. This is an example package
+that shows how to use it.
+
+The test package uses Rcpp, for simplicity, but this
+is not necessary, the API itself does not rely on Rcpp.
diff --git a/inst/progresstest/src/RcppExports.cpp b/inst/progresstest/src/RcppExports.cpp
new file mode 100644
index 0000000..59ce6f2
--- /dev/null
+++ b/inst/progresstest/src/RcppExports.cpp
@@ -0,0 +1,28 @@
+// This file was generated by Rcpp::compileAttributes
+// Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393
+
+#include <Rcpp.h>
+
+using namespace Rcpp;
+
+// test_progress
+Rcpp::CharacterVector test_progress(Rcpp::CharacterVector formatSEXP);
+RcppExport SEXP progresstest_test_progress(SEXP formatSEXPSEXP) {
+BEGIN_RCPP
+ Rcpp::RObject __result;
+ Rcpp::RNGScope __rngScope;
+ Rcpp::traits::input_parameter< Rcpp::CharacterVector >::type formatSEXP(formatSEXPSEXP);
+ __result = Rcpp::wrap(test_progress(formatSEXP));
+ return __result;
+END_RCPP
+}
+// test_units
+Rcpp::CharacterVector test_units();
+RcppExport SEXP progresstest_test_units() {
+BEGIN_RCPP
+ Rcpp::RObject __result;
+ Rcpp::RNGScope __rngScope;
+ __result = Rcpp::wrap(test_units());
+ return __result;
+END_RCPP
+}
diff --git a/inst/progresstest/src/test.cpp b/inst/progresstest/src/test.cpp
new file mode 100644
index 0000000..aa189d9
--- /dev/null
+++ b/inst/progresstest/src/test.cpp
@@ -0,0 +1,58 @@
+
+#include <Rcpp.h>
+#include <RProgress.h>
+#include <unistd.h>
+
+// [[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(2.0 / 100 * 1000000);
+ pb.tick();
+ }
+
+ Rcpp::CharacterVector result(1);
+ result[0] = "DONE";
+ 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(13333333337);
+
+ return result;
+
+ END_RCPP
+}
diff --git a/man/progress_bar.Rd b/man/progress_bar.Rd
new file mode 100644
index 0000000..c78afb4
--- /dev/null
+++ b/man/progress_bar.Rd
@@ -0,0 +1,156 @@
+% 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. 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}{The output stream to put the progress bar on.
+ It defaults to \code{stderr()}, except in R Studio that has
+ a bug when printing on the standard error, so there we use
+ \code{stdout}. If the output stream is not a terminal and
+ we are not in R Studio, then no progress bar is printed.}
+ \item{complete}{Completion character, defaults to \code{=}.}
+ \item{incomplete}{Incomplete 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 support it.}
+}
+}
+
+\section{Using the progress bar}{
+
+Two 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.
+
+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.
+}
+
+\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{:eta}{Estimated completion time in seconds.}
+ \item{:percent}{Completion percentage.}
+ \item{:rate}{Download rate, bytes per second. See example below.}
+ \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.
+}
+\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 = 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()
+
+}
+
+}
+
diff --git a/tests/testthat.R b/tests/testthat.R
new file mode 100644
index 0000000..cb63df2
--- /dev/null
+++ b/tests/testthat.R
@@ -0,0 +1,6 @@
+
+if (Sys.getenv("NOT_CRAN", "") != "") {
+ library(testthat)
+ library(progress)
+ test_check("progress")
+}
diff --git a/tests/testthat/helper.R b/tests/testthat/helper.R
new file mode 100644
index 0000000..d89ac9f
--- /dev/null
+++ b/tests/testthat/helper.R
@@ -0,0 +1,39 @@
+
+get_output <- function(..., stream = stdout()) {
+
+ if (identical(stream, stdout())) {
+ type <- "output"
+ } else if (identical(stream, stderr())) {
+ type <- "message"
+ }
+
+ cleanup <- function() {
+ unlink(tmp)
+ sink(NULL, type = type)
+ }
+
+ tmp <- tempfile()
+ on.exit(cleanup())
+
+ sink(tmp, type = type)
+ force(...)
+
+ ## Windows has some strange readBin and sink interplay,
+ ## so we need to remove the sink before reading the file
+ sink(NULL, type = type)
+ x <- readBin(tmp, raw(0), n = file.info(tmp)$size)
+ unlink(tmp)
+
+ ## No cleanup is needed any more
+ on.exit(force(1))
+
+ rawToChar(x)
+}
+
+win_newline <- function(..., collapse = NULL) {
+ x <- paste0(...)
+ if (.Platform$OS.type == "windows") {
+ x <- gsub("\n", "\r\n", x, fixed = TRUE)
+ }
+ x
+}
diff --git a/tests/testthat/test-cpp.R b/tests/testthat/test-cpp.R
new file mode 100644
index 0000000..6453a94
--- /dev/null
+++ b/tests/testthat/test-cpp.R
@@ -0,0 +1,42 @@
+
+context("C++ API")
+
+test_that("C++ API works", {
+
+ skip_on_cran()
+
+ Sys.setenv("R_TESTS" = "")
+
+ ## Need to "link to" the current package
+ test_pkg_dir <- system.file("progresstest", package = "progress")
+
+ f <- file(tempfile(), open = "w")
+ sink(f)
+ sink(f, type = "message")
+ install.packages("Rcpp", repos = c(CRAN = "https://cran.rstudio.com"),
+ quiet = TRUE)
+ sink(NULL, type = "message")
+ sink(NULL)
+ close(f)
+ unlink(f)
+
+ ## OK, we could install it
+ try(silent = TRUE, unloadNamespace("progresstest"))
+ install.packages(test_pkg_dir, repos = NULL, type = "source",
+ quiet = TRUE)
+
+ ## OK, we could load it
+ do.call("library", list("progresstest", character.only = TRUE))
+
+ f <- file(tempfile(), open = "w")
+ sink(f)
+ sink(f, type = "message")
+ my_test_progress()
+ sink(NULL, type = "message")
+ sink(NULL)
+ close(f)
+ unlink(f)
+
+ try(silent = TRUE, unloadNamespace("progresstest"))
+
+})
diff --git a/tests/testthat/test-progress.R b/tests/testthat/test-progress.R
new file mode 100644
index 0000000..14c67b9
--- /dev/null
+++ b/tests/testthat/test-progress.R
@@ -0,0 +1,389 @@
+
+context("Progress bar")
+
+test_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 <- win_newline(
+ "\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 <- win_newline(
+ "\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 <- win_newline(
+ "\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 <- win_newline(
+ "\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 <- win_newline(
+ "\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 <- win_newline(
+ "\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 = "#", incomplete = " ",
+ clear = FALSE)
+ for (i in 1:5) pb$tick(1)
+ })
+
+ sout <- win_newline(
+ "\r[### ] 20%",
+ "\r[##### ] 40%",
+ "\r[######## ] 60%",
+ "\r[########## ] 80%",
+ "\r[#############] 100%",
+ "\n"
+ )
+
+ expect_equal(out, sout)
+})
+
+test_that("callback function", {
+
+ x <- ""
+ cb <- function() {
+ 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 <- win_newline(
+ "\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 <- win_newline(
+ "\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 <- win_newline(
+ "\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 <- win_newline(
+ "\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 <- win_newline(
+ "\rtext [==------] 25%",
+ "\rlong text [==-] 50%",
+ "\rtext [========] 100%",
+ "\n"
+ )
+
+ expect_equal(out, sout)
+})
+
+test_that("custom streams", {
+
+ str <- file(tmp <- tempfile(), open = "w")
+ on.exit(unlink(tmp), add = TRUE)
+ pb <- progress_bar$new(stream = str, force = TRUE,
+ show_after = 0, width = 20)
+ pb$tick(0)
+ pb$tick(50)
+ pb$tick(50)
+ close(str)
+
+ out <- rawToChar(readBin(tmp, raw(0), n = file.info(tmp)$size))
+
+ sout <- win_newline(
+ "\r[-------------] 0%",
+ "\r[======-------] 50%",
+ "\r[=============] 100%",
+ "\r ",
+ "\r"
+ )
+
+ 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 <- win_newline(
+ "^\\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 <- win_newline("")
+ expect_equal(out, sout)
+
+})
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-med/r-cran-progress.git
More information about the debian-med-commit
mailing list