diff --git a/.github/workflows/R-CMD-check.yaml b/.github/workflows/R-CMD-check.yaml index 2b7f125..055974c 100644 --- a/.github/workflows/R-CMD-check.yaml +++ b/.github/workflows/R-CMD-check.yaml @@ -2,7 +2,7 @@ on: push: branches: - master - - devel + - dev pull_request: branches: - master diff --git a/DESCRIPTION b/DESCRIPTION index fe64f3c..e08186e 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,7 +1,7 @@ Type: Package Package: mustashe Title: Stash and Load Objects -Version: 0.1.2 +Version: 0.1.3 Authors@R: c(person(given = c("Joshua", "H"), family = "Cook", @@ -29,7 +29,8 @@ Imports: digest (>= 0.6.0), formatR (>= 1.7), qs (>= 0.21.2), - tibble (>= 2.1.0) + tibble (>= 2.1.0), + here (>= 0.1.0) Suggests: covr (>= 3.3.0), knitr (>= 1.28), @@ -42,4 +43,4 @@ VignetteBuilder: Encoding: UTF-8 Language: en-US LazyData: true -RoxygenNote: 7.1.0 +RoxygenNote: 7.1.1 diff --git a/NAMESPACE b/NAMESPACE index 52f3e7b..e1afe7c 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,5 +1,7 @@ # Generated by roxygen2: do not edit by hand export(clear_stash) +export(dont_use_here) export(stash) export(unstash) +export(use_here) diff --git a/NEWS.md b/NEWS.md index 37ba5fb..847d2b2 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,9 @@ +# mustashe 0.1.3 + +* An error is raised if the '.mustashe' directory cannot be created (#9). +* Add an option to use the ['here'](https://CRAN.R-project.org/package=here) package for creating file paths for stashed objects. +* Minor fixes for CRAN package checking process. + # mustashe 0.1.2 * Jimmy changed the reading and writing system from the base R RDS system to using the ['qs: Quick Serialization of R Objects'](https://CRAN.R-project.org/package=qs) package for faster reading and writing. diff --git a/R/clear_stash.R b/R/clear_stash.R index f8cae25..f1522fc 100644 --- a/R/clear_stash.R +++ b/R/clear_stash.R @@ -6,13 +6,12 @@ #' #' @examples #' clear_stash() -#' #' @export clear_stash clear_stash <- function() { - message("Clearing stash.") - file.remove(c( - list.files(.stash_dir, full.names = TRUE, pattern = "qs$"), - list.files(.stash_dir, full.names = TRUE, pattern = "hash$") - )) - invisible(NULL) + message("Clearing stash.") + file.remove(c( + list.files(get_stash_dir(), full.names = TRUE, pattern = "qs$"), + list.files(get_stash_dir(), full.names = TRUE, pattern = "hash$") + )) + invisible(NULL) } diff --git a/R/stash.R b/R/stash.R index cde5706..661c7c8 100644 --- a/R/stash.R +++ b/R/stash.R @@ -14,180 +14,220 @@ #' @examples #' \donttest{ #' # A value that is used to create `rnd_vals`. -#' x <<- 1e6 # The `<<-` is not normally required, just for this example. +#' x <<- 1e6 # The `<<-` is not normally required, just for this example. #' #' # Stash the results of the comuption of `rnd_vals`. #' stash("rnd_vals", depends_on = "x", { -#' # Some long running computation. -#' rnd_vals <- rnorm(x) +#' # Some long running computation. +#' rnd_vals <- rnorm(x) #' }) +#' +#' # Remove directory for this example - do not do in real use. +#' unlink(".mustashe", recursive = TRUE) #' } #' #' @export stash stash <- function(var, code, depends_on = NULL) { - - check_stash_dir() - - deparsed_code <- deparse(substitute(code)) - formatted_code <- format_code(deparsed_code) - - if (is.null(var)) stop("`var` cannot be NULL") - if (formatted_code == "NULL") stop("`code` cannot be NULL") - - new_hash_tbl <- make_hash_table(formatted_code, depends_on) - - # if the variable has been stashed: - # if the hash tables are equivalent: - # load the stored variable - # else: - # make a new stash - # else: - # make a new stash - if (has_been_stashed(var)) { - old_hash_tbl <- get_hash_table(var) - if (hash_tables_are_equivalent(old_hash_tbl, new_hash_tbl)) { - message("Loading stashed object.") - load_variable(var) - } else { - message("Updating stash.") - new_stash(var, formatted_code, new_hash_tbl) - } + check_stash_dir() + + deparsed_code <- deparse(substitute(code)) + formatted_code <- format_code(deparsed_code) + + if (is.null(var)) stop("`var` cannot be NULL") + if (formatted_code == "NULL") stop("`code` cannot be NULL") + + new_hash_tbl <- make_hash_table(formatted_code, depends_on) + + # if the variable has been stashed: + # if the hash tables are equivalent: + # load the stored variable + # else: + # make a new stash + # else: + # make a new stash + if (has_been_stashed(var)) { + old_hash_tbl <- get_hash_table(var) + if (hash_tables_are_equivalent(old_hash_tbl, new_hash_tbl)) { + message("Loading stashed object.") + load_variable(var) } else { - message("Stashing object.") - new_stash(var, formatted_code, new_hash_tbl) + message("Updating stash.") + new_stash(var, formatted_code, new_hash_tbl) } + } else { + message("Stashing object.") + new_stash(var, formatted_code, new_hash_tbl) + } - invisible(NULL) + invisible(NULL) } # Make a new stash from a variable, code, and hash table. new_stash <- function(var, code, hash_tbl) { - val <- evaluate_code(code) - assign_value(var, val) - write_hash_table(var, hash_tbl) - write_val(var, val) + val <- evaluate_code(code) + assign_value(var, val) + write_hash_table(var, hash_tbl) + write_val(var, val) } # Format the code. format_code <- function(code) { - fmt_code <- formatR::tidy_source( - text = code, - comment = FALSE, - blank = FALSE, - arrow = TRUE, - brace.newline = FALSE, - indent = 4, - wrap = TRUE, - output = FALSE, - width.cutoff = 80 - )$text.tidy - paste(fmt_code, sep="", collapse="\n") + fmt_code <- formatR::tidy_source( + text = code, + comment = FALSE, + blank = FALSE, + arrow = TRUE, + brace.newline = FALSE, + indent = 4, + wrap = TRUE, + output = FALSE, + width.cutoff = 80 + )$text.tidy + paste(fmt_code, sep = "", collapse = "\n") } # Make a hash table for code and any variables in the dependencies. make_hash_table <- function(code, depends_on) { - code_hash <- make_hash("code", env = environment()) - depends_on <- sort(depends_on) - dependency_hashes <- make_hash(depends_on, .TargetEnv) - tibble::tibble( - name = c("CODE", depends_on), - hash = c(code_hash, dependency_hashes) - ) - + code_hash <- make_hash("code", env = environment()) + depends_on <- sort(depends_on) + dependency_hashes <- make_hash(depends_on, .TargetEnv) + tibble::tibble( + name = c("CODE", depends_on), + hash = c(code_hash, dependency_hashes) + ) } # Make hash of an object. make_hash <- function(vars, env) { - if (is.null(vars)) return(NULL) + if (is.null(vars)) { + return(NULL) + } - missing <- !unlist(lapply(vars, exists, envir = env)) - if (any(missing)) { - stop("Some dependencies are missing from the environment.") - } + missing <- !unlist(lapply(vars, exists, envir = env)) + if (any(missing)) { + stop("Some dependencies are missing from the environment.") + } - hashes <- c() - for (var in vars) { - hashes <- c(hashes, digest::digest(get(var, envir = env))) - } + hashes <- c() + for (var in vars) { + hashes <- c(hashes, digest::digest(get(var, envir = env))) + } - return(hashes) + return(hashes) } # Are the two hash tables equivalent? hash_tables_are_equivalent <- function(tbl1, tbl2) { - isTRUE(all.equal(tbl1, tbl2, check.attributes = TRUE, use.names = TRUE)) + isTRUE(all.equal(tbl1, tbl2, check.attributes = TRUE, use.names = TRUE)) } # Has the `var` been stashed before? has_been_stashed <- function(var) { - paths <- stash_filename(var) - isTRUE(all(unlist(lapply(paths, file.exists)))) + paths <- stash_filename(var) + isTRUE(all(unlist(lapply(paths, file.exists)))) } # Retrieve the hash table as a `tibble`. get_hash_table <- function(var) { - dat <- qs::qread(stash_filename(var)$hash_name) - dat <- tibble::as_tibble(dat) - return(dat) + dat <- qs::qread(stash_filename(var)$hash_name) + dat <- tibble::as_tibble(dat) + return(dat) } # Write the hash table to file. write_hash_table <- function(var, tbl) { - qs::qsave(tbl, stash_filename(var)$hash_name) + qs::qsave(tbl, stash_filename(var)$hash_name) } # Write the value to disk. write_val <- function(var, val) { - path <- stash_filename(var)$data_name - qs::qsave(val, path) + path <- stash_filename(var)$data_name + qs::qsave(val, path) } # Load in a variable from disk and assign it to the global environment. load_variable <- function(var) { - path <- stash_filename(var)$data_name - val <- qs::qread(path) - assign_value(var, val) + path <- stash_filename(var)$data_name + val <- qs::qread(path) + assign_value(var, val) } # Evaluate the code in a new environment. evaluate_code <- function(code) { - eval(parse(text = code), envir = new.env()) + eval(parse(text = code), envir = new.env()) } # Assign the value `val` to the variable `var`. assign_value <- function(var, val) { - assign(var, val, envir = .TargetEnv) + assign(var, val, envir = .TargetEnv) } # Get the file names for staching stash_filename <- function(var) { - return(list( - data_name = file.path(.stash_dir, paste0(var, ".qs")), - hash_name = file.path(.stash_dir, paste0(var, ".hash")) - )) + stash_dir <- get_stash_dir() + return(list( + data_name = file.path(stash_dir, paste0(var, ".qs")), + hash_name = file.path(stash_dir, paste0(var, ".hash")) + )) } check_stash_dir <- function() { - if (!dir.exists(.stash_dir)) { - dir.create(.stash_dir, recursive = TRUE) - } - invisible(NULL) + stash_dir <- get_stash_dir() + if (!dir.exists(stash_dir)) { + tryCatch( + dir.create(stash_dir, showWarnings = TRUE, recursive = TRUE), + warning = stash_dir_warning + ) + } + invisible(NULL) } +stash_dir_warning <- function(w) { + warning(w) + # if (grep("cannot create dir", w) > 0 & grep("Permission denied", w) > 0) { + if (TRUE) { + stop_msg1 <- " +'mustashe' is unable to create a directory to stash your objects. +Please create the directory manually using:" + + stop_msg2 <- paste0("\n dir.create(", get_stash_dir(), ")") + + stop_msg3 <- " +If that does not work, please create the directory from the command line and open an issue at: + https://github.com/jhrcook/mustashe" + + stop_msg <- paste(stop_msg1, stop_msg2, stop_msg3, sep = "\n") + stop(stop_msg) + } +} + + +get_stash_dir <- function() { + stash_dir <- ".mustashe" + + use_here_option <- getOption("mustashe.here") + # print(use_here_option) + if (!is.null(use_here_option)) { + if (use_here_option == TRUE) { + return(here::here(stash_dir)) + } + } + return(stash_dir) +} # The environment where all code is evaluated and variables assigned. .TargetEnv <- .GlobalEnv -.stash_dir <- ".mustashe" +# .stash_dir <- ".mustashe" diff --git a/R/unstash.R b/R/unstash.R index 2149e53..b8b1aed 100644 --- a/R/unstash.R +++ b/R/unstash.R @@ -8,25 +8,26 @@ #' #' @examples #' \donttest{ -#' stash("x", -#' { -#' x <- 1 +#' stash("x", { +#' x <- 1 #' }) #' #' unstash("x") +#' +#' #' # Remove directory for this example - do not do in real use. +#' unlink(".mustashe", recursive = TRUE) #' } #' #' @export unstash unstash <- function(var) { - - f <- function(v) { - if (has_been_stashed(v)) { - message(paste0("Unstashing '", v, "'.")) - file.remove(unlist(stash_filename(v))) - } else { - message(paste0("No object '", v, "' in stash.")) - } + f <- function(v) { + if (has_been_stashed(v)) { + message(paste0("Unstashing '", v, "'.")) + file.remove(unlist(stash_filename(v))) + } else { + message(paste0("No object '", v, "' in stash.")) } - lapply(var, f) - invisible(NULL) + } + lapply(var, f) + invisible(NULL) } diff --git a/R/use_here.R b/R/use_here.R new file mode 100644 index 0000000..ba6ef90 --- /dev/null +++ b/R/use_here.R @@ -0,0 +1,62 @@ +#' Use the 'here' package when writing stashes to file +#' +#' Sets an option that tells \code{stash()} to write the stashed objects to a +#' path created using the \code{here::here()} function from the +#' \href{https://here.r-lib.org}{'here'} package: "The 'here' package creates +#' paths relative to the top-level directory." It is particularly useful when +#' using an RStudio project. +#' +#' Add \code{mustashe::use_here(silent = TRUE)} to your '.Rprofile' or +#' \code{setup} code block in an R Markdown to set this feature automatically in +#' the future. +#' +#' @param silent A logical to silence the message from the function. (default +#' \code{FALSE}) +#' +#' @return Returns \code{NULL} (invisibly). +#' +#' @examples +#' use_here() +#' +#' @export use_here +use_here <- function(silent = FALSE) { + option_name <- "mustashe.here" + set_use_here(TRUE) + if (!silent) { + msg <- list( + paste0("The global option \"", option_name, "\" has been set `TRUE`."), + "Add `mustashe::use_here(silent = TRUE)` to you're '.Rprofile'", + " to have it set automatically in the future.") + message(paste(msg, collapse = "\n")) + } + invisible(NULL) +} + + +#' Stop using the 'here' package when writing stashes to file +#' +#' Stop using the \code{here::here()} function from the +#' \href{https://here.r-lib.org}{'here'} package to create the file paths for +#' stashed objects. +#' +#' @param silent A logical to silence the message from the function. (default +#' \code{FALSE}) +#' +#' @return Returns \code{NULL} (invisibly). +#' +#' @examples +#' dont_use_here() +#' +#' @export dont_use_here +dont_use_here <- function(silent = FALSE) { + set_use_here(FALSE) + if (!silent) { + message("No longer using `here::here()` for creating stash file paths.") + } + invisible(NULL) +} + + +set_use_here <- function(val) { + options("mustashe.here" = val) +} diff --git a/README.Rmd b/README.Rmd index aae96e3..667aa59 100644 --- a/README.Rmd +++ b/README.Rmd @@ -6,10 +6,10 @@ output: github_document ```{r, include = FALSE} knitr::opts_chunk$set( - collapse = TRUE, - comment = "#>", - fig.path = "man/figures/README-", - out.width = "100%" + collapse = TRUE, + comment = "#>", + fig.path = "man/figures/README-", + out.width = "100%" ) mustashe::clear_stash() @@ -19,10 +19,12 @@ mustashe::clear_stash() [![CRAN status](https://www.r-pkg.org/badges/version/mustashe)](https://CRAN.R-project.org/package=mustashe) +[![CRAN downloads](http://cranlogs.r-pkg.org/badges/grand-total/mustashe)](https://cran.r-project.org/package=mustashe) [![R build status](https://github.com/jhrcook/mustashe/workflows/R-CMD-check/badge.svg)](https://github.com/jhrcook/mustashe/actions) [![Travis build status](https://travis-ci.org/jhrcook/mustashe.svg?branch=master)](https://travis-ci.org/jhrcook/mustashe) [![AppVeyor build status](https://ci.appveyor.com/api/projects/status/github/jhrcook/mustashe?branch=master&svg=true)](https://ci.appveyor.com/project/jhrcook/mustashe) [![Codecov test coverage](https://codecov.io/gh/jhrcook/mustashe/branch/master/graph/badge.svg)](https://codecov.io/gh/jhrcook/mustashe?branch=master) +[![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0) The goal of 'mustashe' is to save time on long-running computations by storing and reloading the resulting object after the first run. @@ -62,8 +64,8 @@ We can time this process using the 'tictoc' library. ```{r} tictoc::tic("random simulation") stash("rnd_vals", { - Sys.sleep(3) - rnd_vals <- rnorm(1e5) + Sys.sleep(3) + rnd_vals <- rnorm(1e5) }) tictoc::toc() ``` @@ -74,8 +76,8 @@ Instead, the random values `rnd_vals` is loaded. ```{r} tictoc::tic("random simulation") stash("rnd_vals", { - Sys.sleep(3) - rnd_vals <- rnorm(1e5) + Sys.sleep(3) + rnd_vals <- rnorm(1e5) }) tictoc::toc() ``` @@ -93,8 +95,8 @@ For instance, let's say we are calculating some value `foo` using `x`. x <- 100 stash("foo", depends_on = "x", { - print("Calculating `foo` using `x`.") - foo <- x + 1 + print("Calculating `foo` using `x`.") + foo <- x + 1 }) foo @@ -106,8 +108,8 @@ Now if `x` is not changed, then the code for `foo` does not get re-evaluated. x <- 100 stash("foo", depends_on = "x", { - print("Calculating `foo` using `x`.") - foo <- x + 1 + print("Calculating `foo` using `x`.") + foo <- x + 1 }) foo @@ -119,16 +121,38 @@ But if `x` does change, then `foo` gets re-evaluated. x <- 200 stash("foo", depends_on = "x", { - print("Calculating `foo` using `x`.") - foo <- x + 1 + print("Calculating `foo` using `x`.") + foo <- x + 1 }) foo ``` + +## Using ['here'](https://here.r-lib.org) to create file paths + +The ['here'](https://here.r-lib.org) package is useful for handling file paths in R projects, particularly when using an RStudio project. +The main function, `here::here()`, can be used to create the file path for stashing an object by calling `use_here()`. + +```{r} +use_here() +``` + +This behavior can be turned off, too. + +```{r} +dont_use_here() +``` + + + --- ### Attribution The inspiration for this package came from the `cache()` feature in the ['ProjectTemplate'](http://projecttemplate.net/index.html) package. While the functionality and implementation are a bit different, this would have been far more difficult to do without referencing the source code from 'ProjectTemplate'. + +```{r, echo=FALSE} +unlink(".mustashe", recursive = TRUE) +``` diff --git a/README.md b/README.md index a4b0421..8837248 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,15 @@ -# mustashe +mustashe +========================================================================================================================================== [![CRAN status](https://www.r-pkg.org/badges/version/mustashe)](https://CRAN.R-project.org/package=mustashe) +[![CRAN +downloads](http://cranlogs.r-pkg.org/badges/grand-total/mustashe)](https://cran.r-project.org/package=mustashe) [![R build status](https://github.com/jhrcook/mustashe/workflows/R-CMD-check/badge.svg)](https://github.com/jhrcook/mustashe/actions) [![Travis build @@ -15,6 +18,8 @@ status](https://travis-ci.org/jhrcook/mustashe.svg?branch=master)](https://travi status](https://ci.appveyor.com/api/projects/status/github/jhrcook/mustashe?branch=master&svg=true)](https://ci.appveyor.com/project/jhrcook/mustashe) [![Codecov test coverage](https://codecov.io/gh/jhrcook/mustashe/branch/master/graph/badge.svg)](https://codecov.io/gh/jhrcook/mustashe?branch=master) +[![License: GPL +v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0) The goal of ‘mustashe’ is to save time on long-running computations by @@ -23,33 +28,30 @@ time the computation is run, instead of evaluating the code, the stashed object is loaded. ‘mustashe’ is great for storing intermediate objects in an analysis. -## Installation +Installation +------------ You can install the released version of ‘mustashe’ from [CRAN](https://CRAN.R-project.org) with: -``` r -install.packages("mustashe") -``` + install.packages("mustashe") And the development version from [GitHub](https://github.com/jhrcook/mustashe) with: -``` r -# install.packages("devtools") -devtools::install_github("jhrcook/mustashe") -``` + # install.packages("devtools") + devtools::install_github("jhrcook/mustashe") -## Loading ‘mustashe’ +Loading ‘mustashe’ +------------------ The ‘mustashe’ package is loaded like any other, using the `library()` function. -``` r -library(mustashe) -``` + library(mustashe) -## Basic example +Basic example +------------- Below is a simple example of how to use the `stash()` function from ‘mustashe’. @@ -59,34 +61,31 @@ generate random data `rnd_vals`. This is mocked below using the `Sys.sleep()` function. We can time this process using the ‘tictoc’ library. -``` r -tictoc::tic("random simulation") -stash("rnd_vals", { - Sys.sleep(3) - rnd_vals <- rnorm(1e5) -}) -#> Stashing object. -tictoc::toc() -#> random simulation: 3.382 sec elapsed -``` + tictoc::tic("random simulation") + stash("rnd_vals", { + Sys.sleep(3) + rnd_vals <- rnorm(1e5) + }) + #> Stashing object. + tictoc::toc() + #> random simulation: 3.319 sec elapsed Now, if we come back tomorrow and continue working on the same analysis, the second time this process is run the code is not evaluated because the code passed to `stash()` has not changed. Instead, the random values `rnd_vals` is loaded. -``` r -tictoc::tic("random simulation") -stash("rnd_vals", { - Sys.sleep(3) - rnd_vals <- rnorm(1e5) -}) -#> Loading stashed object. -tictoc::toc() -#> random simulation: 0.053 sec elapsed -``` + tictoc::tic("random simulation") + stash("rnd_vals", { + Sys.sleep(3) + rnd_vals <- rnorm(1e5) + }) + #> Loading stashed object. + tictoc::toc() + #> random simulation: 0.012 sec elapsed -## Dependencies +Dependencies +------------ A common problem with storing intermediates is that they have dependencies that can change. If a dependency changes, then we want the @@ -97,53 +96,65 @@ For instance, let’s say we are calculating some value `foo` using `x`. (For the following example, I will use a print statement to indicate when the code is evaluated.) -``` r -x <- 100 + x <- 100 -stash("foo", depends_on = "x", { - print("Calculating `foo` using `x`.") - foo <- x + 1 -}) -#> Stashing object. -#> [1] "Calculating `foo` using `x`." + stash("foo", depends_on = "x", { + print("Calculating `foo` using `x`.") + foo <- x + 1 + }) + #> Stashing object. + #> [1] "Calculating `foo` using `x`." -foo -#> [1] 101 -``` + foo + #> [1] 101 Now if `x` is not changed, then the code for `foo` does not get re-evaluated. -``` r -x <- 100 + x <- 100 -stash("foo", depends_on = "x", { - print("Calculating `foo` using `x`.") - foo <- x + 1 -}) -#> Loading stashed object. + stash("foo", depends_on = "x", { + print("Calculating `foo` using `x`.") + foo <- x + 1 + }) + #> Loading stashed object. -foo -#> [1] 101 -``` + foo + #> [1] 101 But if `x` does change, then `foo` gets re-evaluated. -``` r -x <- 200 + x <- 200 + + stash("foo", depends_on = "x", { + print("Calculating `foo` using `x`.") + foo <- x + 1 + }) + #> Updating stash. + #> [1] "Calculating `foo` using `x`." + + foo + #> [1] 201 + +Using [‘here’](https://here.r-lib.org) to create file paths +----------------------------------------------------------- + +The [‘here’](https://here.r-lib.org) package is useful for handling file +paths in R projects, particularly when using an RStudio project. The +main function, `here::here()`, can be used to create the file path for +stashing an object by calling `use_here()`. + + use_here() + #> The global option "mustashe.here" has been set `TRUE`. + #> Add `mustashe::use_here(silent = TRUE)` to you're '.Rprofile' + #> to have it set automatically in the future. -stash("foo", depends_on = "x", { - print("Calculating `foo` using `x`.") - foo <- x + 1 -}) -#> Updating stash. -#> [1] "Calculating `foo` using `x`." +This behavior can be turned off, too. -foo -#> [1] 201 -``` + dont_use_here() + #> No longer using `here::here()` for creating stash file paths. ------ +------------------------------------------------------------------------ ### Attribution diff --git a/_pkgdown.yml b/_pkgdown.yml index 0c14e53..46f4dc3 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -29,7 +29,7 @@ navbar: - text: How 'mustashe' works href: articles/how-mustashe-works.html news: - text: Versions + text: News href: news/index.html github: icon: fa-github fa-lg @@ -44,4 +44,6 @@ reference: - '`stash`' - '`clear_stash`' - '`unstash`' + - '`use_here`' + - '`dont_use_here`' - '`mustashe`' diff --git a/docs/404.html b/docs/404.html index ee3fd98..b5c3335 100644 --- a/docs/404.html +++ b/docs/404.html @@ -79,7 +79,7 @@ @@ -112,7 +112,7 @@