Skip to content

Commit

Permalink
Rename proj to path in proj_outline() and proj_file(),
Browse files Browse the repository at this point in the history
add `check_proj()` as a `check_string()` wrapper.

Use `NA` for all projects, `NULL` for active project in all `proj_*()` functions.
  • Loading branch information
olivroy committed Jun 9, 2024
1 parent 39385e5 commit 8c5bd9a
Show file tree
Hide file tree
Showing 9 changed files with 99 additions and 66 deletions.
3 changes: 3 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@

* Removed `work_only` argument from `file_outline()`, use `pattern = "WORK"` to
acheive the same result.

* In `proj_outline()`, `proj` has been renamed `path`, but still accepts a project name,
that will passed on to `proj_list()`

## Fixes

Expand Down
4 changes: 4 additions & 0 deletions R/open.R
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ open_rs_doc <- function(path, line = -1L, col = -1L, move_cursor = TRUE) {
invisible(doc_id)
}

active_rs_proj <- function() {
NULL
}

#' @name open_rs_doc
#' @export
active_rs_doc <- function() {
Expand Down
54 changes: 17 additions & 37 deletions R/outline.R
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@
#' @details
#' `proj_outline()` and `dir_outline()` are wrapper of `file_outline()`.
#'
#' The parser is very opinioneted and is not very robust as it is based on regexps.
#' In `proj_outline()`, `path` accepts project names, see [proj_list()] for how to
#' set up reuseme to regognize your projects' locations.
#'
#' The parser is very opinionated and is not very robust as it is based on regexps.
#' For a better file parser, explore other options, like [lightparser](https://thinkr-open.github.io/lightparser/) for Quarto, `{roxygen2}`
#'
#' Will show TODO items and will offer a link to [mark them as
Expand All @@ -37,8 +40,8 @@
#' test files (like in usethis repo) don't help understand a project's outline.
#' Use `dir_outline(recurse = TRUE)` to make sure these are included in your outline.
#'
#' @param path,proj A character vector of file paths, a [project][proj_list()].
#' Defaults to active file, project or directory. `rstudioapi::documentPath()`
#' @param path A character vector of file paths, a [project][proj_list()].
#' Defaults to the [active file][active_rs_doc()], project or directory.
#' @param pattern A string or regex to search for in the outline. If
#' specified, will search only for elements matching this regular expression.
#' The print method will show the document title for context. Previously `regex_outline`
Expand Down Expand Up @@ -210,50 +213,31 @@ file_outline <- function(path = active_rs_doc(),
}
#' @rdname outline
#' @export
proj_outline <- function(proj = proj_get2(), pattern = NULL, dir_tree = FALSE, alpha = FALSE, recent_only = FALSE) {
is_active_proj <- identical(proj, proj_get2())

if (is_active_proj) {
return(dir_outline(
pattern = pattern,
dir_tree = dir_tree,
alpha = alpha,
recent_only = recent_only,
recurse = TRUE
))
}

if (fs::dir_exists(proj)) {
if (!is_active_proj) {
cli::cli_warn("Use {.fn dir_outline} for that.")
}
proj_outline <- function(path = active_rs_proj(), pattern = NULL, dir_tree = FALSE, alpha = FALSE, recent_only = FALSE) {
check_proj(path, allow_null = TRUE)
path_proj <- proj_list(path)

proj_dir <- proj
} else { # when referring to a project by name.
proj_dir <- proj_list(proj)
}

if (!rlang::has_length(proj_dir, 1)) {
if (!rlang::has_length(path_proj, 1)) {
cli::cli_abort("Cannot process more than one project/directory at once.")
}

if (!fs::dir_exists(proj_dir)) {
cli::cli_abort("Internal errors due to path processing. Maybe use fs's path processing ")
if (!fs::dir_exists(path_proj)) {
cli::cli_abort("Internal errors due to path processing. Maybe use fs's path processing problem.")
}

if (!is_proj(proj_dir)) {
if (!is_proj(path_proj)) {
cli::cli_abort("Not in a project. Use {.fn reuseme::dir_outline} instead.")
}

is_active_proj <- identical(fs::path(proj_dir), proj_get2())
if (!is_active_proj) {
if (!is.null(path)) {
proj <- basename(path)
# Add an outline that enables switching projects if searching outside
cli::cli_h1(paste0("{.run [", proj, "](reuseme::proj_switch('", proj, "'))}"))
}

dir_outline(
path = path_proj,
pattern = pattern,
path = proj_dir,
dir_tree = dir_tree,
alpha = alpha,
recurse = TRUE
Expand All @@ -272,11 +256,6 @@ dir_outline <- function(path = ".", pattern = NULL, dir_tree = FALSE, alpha = FA
glob = file_exts_regex,
recurse = recurse
)
file_list_to_outline <- fs::path_filter(
file_list_to_outline,
regexp = "vignette-dump|renv/",
invert = TRUE
)

if (recurse && !identical(Sys.getenv("TESTTHAT"), "true")) {
# Remove examples from outline and test example files to avoid clutter
Expand Down Expand Up @@ -311,6 +290,7 @@ exclude_example_files <- function(path) {
"revdep/", # likely don't need to outline revdep/, use dir_outline() to find something in revdep/
"themes/hugo-theme-console/", # protect blogdown
"vignettes/.+\\.R$", # generated files
"vignette-dump|renv/",
"RcppExports.R",
"pkgdown/assets",
sep = "|"
Expand Down
41 changes: 24 additions & 17 deletions R/proj-list.R
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@
#' If not specified, will generate hyperlinks that call [usethis::proj_activate()].
#' `proj_switch()` looks at `options(reuseme.reposdir)`.
#'
#' @param proj the name of a project located in the default locations or `NULL`
#' @param proj the name of a project located in the default locations or `NA`
#' @param new_session Should open in a new session?
#'
#' @returns Single logical value indicating if current session is modified.
#' @export
#' @seealso [usethis::proj_activate()]
#' @family project management helpers
proj_switch <- function(proj = NULL, new_session = TRUE) {
proj_switch <- function(proj = NA, new_session = TRUE) {
# This is my default places (reuseme.reposdir possibly)
# See fs::path_home
project <- proj_list(proj)
Expand Down Expand Up @@ -38,16 +38,18 @@ proj_switch <- function(proj = NULL, new_session = TRUE) {
#' It can be used as [file_outline()] + `proj`.
#'
#' @param file A filename or regexp to a file inside `proj`
#' @param proj a project path or file [proj_list()]
#' @param path a project path [proj_list()]. If `NULL`,
#' will return active project.
#' @param pattern A regular expression to look for
#' @return The file outline if multiple matches are found
#' @export
#'
#' @examples
#' try(proj_file("A non-existent file"))
#' @family project management helpers
proj_file <- function(file = NULL, proj = NULL, pattern = NULL) {
proj_file <- function(file = NULL, path = active_rs_proj(), pattern = NULL) {
rlang::check_required(file)
check_proj(path, allow_null = TRUE)
# search will only be conducted with pattern
if (is.null(pattern) && is.null(file)) {
cli::cli_abort(
Expand All @@ -56,11 +58,10 @@ proj_file <- function(file = NULL, proj = NULL, pattern = NULL) {
}
file <- file %||% "A non-existent rubbish file placeholder"
if (fs::is_file(file)) {
file_outline(path = file)
file_outline(file)
open_rs_doc(file)
return(invisible(file))
}
proj <- proj %||% proj_get2()
proj_path <- proj_list(proj)
file_path <- fs::path(proj_path, file)
if (fs::is_file(file_path)) {
Expand Down Expand Up @@ -97,24 +98,30 @@ proj_file <- function(file = NULL, proj = NULL, pattern = NULL) {
file_outline(pattern = pattern, path = possible_files)
}

#' Returns a named project list options
#' Specify `proj` in functions
#'
#' @description
#'
#' It peeks `options(reuseme.reposdir)` to find projects.
#' Two main ways to specify proj:
#' * Set `options(reuseme.reposdir)` in `.Rprofile` that contains a character
#' vector of paths to your projects. (i.e. `~/rrr` that contains all your projects)
#' * Specify the full path to `proj`. (like you would for usethis function)
#'
#' @param proj A project path or name to match
#' @param proj A project path or name to match. If `NA`, returns all projects.
#' If `NULL`, returns the active project.
#' @param dirs The directories in which we want to list projects.
#'
#' @return A named character vector with the project name as name, and path as value.
#' @returns A named character vector with the project name as name, and path as value.
#' If `proj` is supplied
#' @export
#' @family project management helpers
proj_list <- function(proj = NULL, dirs = getOption("reuseme.reposdir")) {
check_string(proj, allow_null = TRUE)

if (!is.null(proj) && length(proj) == 1) {
proj_list <- function(proj = NA, dirs = getOption("reuseme.reposdir")) {
check_proj(proj, allow_null = TRUE, allow_na = TRUE)
proj <- proj %||% proj_get2()
if (!is.na(proj) && length(proj) == 1) {
# avoid creating a nested project.
# known direct
if (!proj %in% c("pkgdown", "testthat", "R", "man", "tests", "inst", "src")) {
if (!proj %in% c("pkgdown", "testthat", "R", "man", "tests", "inst", "src", "vignettes")) {
if (fs::dir_exists(proj)) {
return(
rlang::set_names(
Expand All @@ -136,7 +143,7 @@ proj_list <- function(proj = NULL, dirs = getOption("reuseme.reposdir")) {
)

projects <- rlang::set_names(x = as.character(directories), nm = fs::path_file)
if (!is.null(proj) && anyDuplicated(names(projects)) > 0) {
if (!is.na(proj) && anyDuplicated(names(projects)) > 0) {
which_duplicate <- names(projects)[duplicated(names(projects))]
if (proj %in% which_duplicate) {
# R only returns
Expand All @@ -147,7 +154,7 @@ proj_list <- function(proj = NULL, dirs = getOption("reuseme.reposdir")) {
))
}
}
if (!is.null(proj)) {
if (!is.na(proj)) {
if (!grepl("~/", proj, fixed = TRUE)) {
# try to catch an invalid path
rlang::arg_match0(
Expand Down
29 changes: 29 additions & 0 deletions R/utils-proj.R
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,35 @@ get_active_qmd_post <- function(base_path = proj_get(), error_call = caller_env(
fs::path_dir(relative_path)
}

# Tweak check_string
check_proj <- function(x,
...,
allow_null = FALSE, # allow active project.
allow_na = FALSE, # Allow all projects
arg = caller_arg(x),
call = caller_env()) {
if (!missing(x)) {
is_string <- .rlang_check_is_string(
x,
allow_empty = FALSE,
allow_na = allow_na,
allow_null = allow_null
)
if (is_string) {
return(invisible(NULL))
}
}

stop_input_type(
x,
cli::format_inline("a single {.help [proj](reuseme::proj_list)}"),
...,
allow_na = allow_na,
allow_null = allow_null,
arg = arg,
call = call
)
}
# to mock.
is_rstudio <- function(v = NULL) {
rstudioapi::isAvailable(version_needed = v)
Expand Down
11 changes: 7 additions & 4 deletions man/outline.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions man/proj_file.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 10 additions & 4 deletions man/proj_list.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions man/proj_switch.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 8c5bd9a

Please sign in to comment.