Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Package: quarto
Title: R Interface to 'Quarto' Markdown Publishing System
Version: 1.4.4.9007
Version: 1.4.4.9008
Authors@R: c(
person("JJ", "Allaire", , "[email protected]", role = "aut",
comment = c(ORCID = "0000-0003-0174-9868")),
Expand Down
3 changes: 3 additions & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,17 @@ export(quarto_add_extension)
export(quarto_binary_sitrep)
export(quarto_create_project)
export(quarto_inspect)
export(quarto_list_extensions)
export(quarto_path)
export(quarto_preview)
export(quarto_preview_stop)
export(quarto_publish_app)
export(quarto_publish_doc)
export(quarto_publish_site)
export(quarto_remove_extension)
export(quarto_render)
export(quarto_serve)
export(quarto_update_extension)
export(quarto_use_template)
export(quarto_version)
export(theme_brand_flextable)
Expand Down
5 changes: 5 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# quarto (development version)

- Add several new wrapper function (thanks, @parmsam, #192):
- `quarto_list_extensions()` to list installed extensions using `quarto list extensions`
- `quarto_remove_extension()` to remove an installed extension using `quarto remove extensions`
- `quarto_update_extension()` to update an installed extension using `quarto update extensions`

- `quarto_create_project()` offers better user experience now (thanks, @jennybc, #206, #153).

- `quarto_preview()` gains a `quiet` argument to suppress any output from R or Quarto CLI (thanks, @cwickham, #232.)
Expand Down
38 changes: 38 additions & 0 deletions R/list.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#' List Installed Quarto extensions
#'
#' List Quarto Extensions in this folder or project by running `quarto list`
#'
#' @return A data frame with the installed extensions or NULL (invisibly) if no extensions are installed.
#'
#' @examples
#' \dontrun{
#' # List Quarto Extensions in this folder or project
#' quarto_list_extensions()
#' }
#'
#' @export
quarto_list_extensions <- function() {
quarto_bin <- find_quarto()

# quarto list extensions --quiet will return nothing so we need to prevent that.
args <- c("extensions")
x <- quarto_list(args, quarto_bin = quarto_bin, echo = FALSE)
# Clean the stderr output to remove extra spaces and ensure consistent formatting
stderr_cleaned <- gsub("\\s+$", "", x$stderr)
if (grepl("No extensions are installed", stderr_cleaned)) {
invisible()
} else {
df <- utils::read.table(
text = stderr_cleaned,
header = TRUE,
fill = TRUE,
sep = "",
stringsAsFactors = FALSE
)
df[order(df$Id), ]
}
}

quarto_list <- function(args = character(), ...) {
quarto_run_what("list", args = args, ...)
}
62 changes: 62 additions & 0 deletions R/remove.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#' Remove a Quarto extensions
#'
#' Remove an extension in this folder or project by running `quarto remove`
#'
#' @inheritParams quarto_render
#'
#' @param extension The extension name to remove, as in `quarto remove <extension-name>`.
#'
#' @param no_prompt Do not prompt to confirm approval to download external extension.
#'
#'
#' @return Returns invisibly `TRUE` if the extension was removed, `FALSE` otherwise.
#'
#' @seealso `quarto_add_extension()` and [Quarto Website](https://quarto.org/docs/extensions/managing.html).
#'
#' @examples
#' \dontrun{
#' # Remove an already installed extension
#' quarto_remove_extension("quarto-ext/fontawesome")
#' }
#' @export
quarto_remove_extension <- function(
extension = NULL,
no_prompt = FALSE,
quiet = FALSE,
quarto_args = NULL
) {
rlang::check_required(extension)

installed_extensions <- quarto_list_extensions()
if (is.null(installed_extensions)) {
if (!quiet) {
cli::cli_alert_warning("No extensions installed.")
}
return(invisible(FALSE))
}

quarto_bin <- find_quarto()

# This will ask for approval or stop installation
approval <- check_removal_approval(
no_prompt,
extension,
"https://quarto.org/docs/extensions/managing.html"
)

if (approval) {
args <- c(extension, "--no-prompt", if (quiet) cli_arg_quiet(), quarto_args)
quarto_remove(args, quarto_bin = quarto_bin, echo = FALSE)
if (!quiet) {
cli::cli_alert_success(
"Extension {.code {extension}} successfully removed."
)
}
}

invisible(TRUE)
}

quarto_remove <- function(args = character(), ...) {
quarto_run_what("remove", args = args, ...)
}
20 changes: 12 additions & 8 deletions R/theme.R
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
#' @param fg The foreground color
#' @param brand_yml The path to a brand.yml file


#' @rdname theme_helpers
#'
#' @export
Expand Down Expand Up @@ -41,7 +40,8 @@ theme_colors_ggplot <- function(bg, fg) {
if (!requireNamespace("ggplot2", quietly = TRUE)) {
return(NULL)
}
ggplot2::`%+%`(ggplot2::theme_minimal(base_size = 11),
ggplot2::`%+%`(
ggplot2::theme_minimal(base_size = 11),
ggplot2::theme(
panel.border = ggplot2::element_blank(),
panel.grid.major.y = ggplot2::element_blank(),
Expand All @@ -54,7 +54,8 @@ theme_colors_ggplot <- function(bg, fg) {
plot.background = ggplot2::element_rect(fill = bg, colour = NA),
axis.line = ggplot2::element_line(colour = fg),
axis.ticks = ggplot2::element_line(colour = fg)
))
)
)
}

#' @rdname theme_helpers
Expand Down Expand Up @@ -92,10 +93,12 @@ theme_brand_gt <- function(brand_yml) {
#' @export
theme_colors_plotly <- function(bg, fg) {
(function(plot) {
plot |> plotly::layout(paper_bgcolor = bg,
plot_bgcolor = bg,
font = list(color = fg)
)
plot |>
plotly::layout(
paper_bgcolor = bg,
plot_bgcolor = bg,
font = list(color = fg)
)
})
}

Expand All @@ -116,7 +119,8 @@ theme_colors_thematic <- function(bg, fg) {
thematic::thematic_rmd(
bg = bg,
fg = fg,
)})
)
})
}

#' @rdname theme_helpers
Expand Down
64 changes: 64 additions & 0 deletions R/update.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#' Update a Quarto extensions
#'
#' Update an extension to this folder or project by running `quarto update`
#'
#' # Extension Trust
#'
#' Quarto extensions may execute code when documents are rendered. Therefore, if
#' you do not trust the author of an extension, we recommend that you do not
#' install or use the extension.
#' By default `no_prompt = FALSE` which means that
#' the function will ask for explicit approval when used interactively, or
#' disallow installation.
#'
#' @inheritParams quarto_render
#'
#' @param extension The extension to update, either by its name (i.e ` quarto update extension <gh-org>/<gh-repo>`), an archive (` quarto update extension <path-to-zip>`) or a url (`quarto update extension <url>`).
#'
#' @param no_prompt Do not prompt to confirm approval to download external extension. Setting `no_prompt = FALSE` means [Extension Trust](#extension-trust) is accepted.
#'
#' @seealso [quarto_add_extension()], [quarto_remove_extension()], and [Quarto website](https://quarto.org/docs/extensions/managing.html).
#'
#' @return Returns invisibly `TRUE` if the extension was updated, `FALSE` otherwise.
#'
#' @examples
#' \dontrun{
#' # Update a template and set up a draft document from a GitHub repository
#' quarto_update_extension("quarto-ext/fontawesome")
#'
#' # Update a template and set up a draft document from a ZIP archive
#' quarto_update_extension("https://github.com/quarto-ext/fontawesome/archive/refs/heads/main.zip")
#' }
#' @export
quarto_update_extension <- function(
extension = NULL,
no_prompt = FALSE,
quiet = FALSE,
quarto_args = NULL
) {
rlang::check_required(extension)

quarto_bin <- find_quarto()

# This will ask for approval or stop installation
approval <- check_extension_approval(
no_prompt,
"Quarto extension",
"https://quarto.org/docs/extensions/managing.html"
)

if (!approval) {
return(invisible(FALSE))
}

args <- c(extension, "--no-prompt", if (quiet) cli_arg_quiet(), quarto_args)
quarto_update(args, quarto_bin = quarto_bin, echo = TRUE)
if (!quiet) {
cli::cli_inform("Extension {.code {extension}} updated.")
}
invisible(TRUE)
}

quarto_update <- function(args = character(), ...) {
quarto_run_what("update", args = args, ...)
}
94 changes: 72 additions & 22 deletions R/utils-prompt.R
Original file line number Diff line number Diff line change
@@ -1,32 +1,82 @@
check_extension_approval <- function(
check_approval <- function(
no_prompt = FALSE,
what = "Something",
see_more_at = NULL
not_action = "approved",
see_more_at = NULL,
prompt_message = NULL,
interactive_info = NULL, # could use `{ what }` as used in `cli_inform()`
.call = rlang::caller_env()
) {
if (no_prompt) return(TRUE)

if (!rlang::is_interactive()) {
cli::cli_abort(c(
"{ what } requires explicit approval.",
">" = "Set {.arg no_prompt = TRUE} if you agree.",
if (!is.null(see_more_at)) {
c(i = "See more at {.url {see_more_at}}")
}
))
if (!is_interactive()) {
cli::cli_abort(
c(
"{ what } requires explicit approval.",
">" = "Set {.arg no_prompt = TRUE} if you agree.",
if (!is.null(see_more_at)) {
c(i = "See more at {.url {see_more_at}}")
}
),
call = .call
)
} else {
cli::cli_inform(c(
"{what} may execute code when documents are rendered. ",
"*" = "If you do not trust the author(s) of this {what}, we recommend that you do not install or use this {what}."
))
prompt_value <- tolower(readline(sprintf(
"Do you trust the authors of this %s (Y/n)? ",
what
)))
if (!prompt_value %in% "y") {
cli::cli_inform("{what} not installed.")
if (!is.null(interactive_info)) {
cli::cli_inform(interactive_info)
}
prompt_value <- tolower(readline(prompt_message))
if (!prompt_value %in% c("", "y")) {
cli::cli_alert_info(paste0(what, " not {not_action}"))
return(invisible(FALSE))
} else {
return(invisible(TRUE))
}
}
return(invisible(TRUE))
}

check_extension_approval <- function(
no_prompt = FALSE,
what = "Something",
see_more_at = NULL
) {
interactive_info <- c(
"{what} may execute code when documents are rendered. ",
"*" = "If you do not trust the author(s) of this {what}, we recommend that you do not install or use this {what}."
)

prompt_message <- sprintf(
"Do you trust the authors of this %s (Y/n)? ",
what
)

check_approval(
no_prompt = no_prompt,
what = what,
not_action = "installed",
see_more_at = see_more_at,
prompt_message = prompt_message,
interactive_info = interactive_info
)
}

check_removal_approval <- function(
no_prompt = FALSE,
what = "Something",
see_more_at = NULL
) {
prompt_message <- sprintf(
"Are you sure you'd like to remove %s (Y/n)? ",
what
)

check_approval(
no_prompt = no_prompt,
what = what,
not_action = "removed",
see_more_at = see_more_at,
prompt_message = prompt_message,
interactive_info = NULL
)
}

# Needed for testthat to mock base function
readline <- NULL
7 changes: 4 additions & 3 deletions _pkgdown.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,12 @@ reference:

- title: "Extensions"
desc: >
This functions enable you to install extensions and use template from extensions in your folder and projects.
These functions enable you to manage Quarto extensions and use template from extensions in your folder and projects.
More about Quarto extensions at <https://quarto.org/docs/extensions/>
contents:
- starts_with("quarto_add")
- starts_with("quarto_use")
- ends_with("_extension")
- ends_with("_extensions")
- quarto_use_template

- title: "Projects"
desc: >
Expand Down
Loading