diff --git a/.Rbuildignore b/.Rbuildignore index 8410e7f..3663461 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -6,3 +6,7 @@ ^\.github$ ^\.vscode$ ^\.quarto$ +^doc$ +^Meta$ + +^vignettes/*_files$ diff --git a/.github/workflows/R-CMD-check.yaml b/.github/workflows/R-CMD-check.yaml index 39906e4..aebf007 100644 --- a/.github/workflows/R-CMD-check.yaml +++ b/.github/workflows/R-CMD-check.yaml @@ -50,21 +50,24 @@ jobs: - uses: quarto-dev/quarto-actions/setup@v2 with: version: ${{ matrix.config.quarto || 'release' }} + tinytex: true + # replace with setting up QUARTO Pandoc for rmarkdown - - uses: r-lib/actions/setup-pandoc@v2 + - uses: r-lib/actions/setup-pandoc@v2.6.5 - - uses: r-lib/actions/setup-r@v2 + - uses: r-lib/actions/setup-r@v2.6.5 with: r-version: ${{ matrix.config.r }} http-user-agent: ${{ matrix.config.http-user-agent }} use-public-rspm: true - - uses: r-lib/actions/setup-r-dependencies@v2 + - uses: r-lib/actions/setup-r-dependencies@v2.6.5 with: - extra-packages: any::rcmdcheck + # install the package itself as we register vignette engine + extra-packages: any::rcmdcheck, local::. needs: check - - uses: r-lib/actions/check-r-package@v2 + - uses: r-lib/actions/check-r-package@v2.6.5 with: upload-snapshots: true diff --git a/.gitignore b/.gitignore index bb5bb7b..8ffba7c 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,5 @@ inst/doc docs /.quarto/ +/doc/ +/Meta/ diff --git a/DESCRIPTION b/DESCRIPTION index 94f4f8e..87b2d41 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: quarto Title: R Interface to 'Quarto' Markdown Publishing System -Version: 1.3.11 +Version: 1.3.12 Authors@R: c( person("JJ", "Allaire", , "jj@posit.co", role = "aut", comment = c(ORCID = "0000-0003-0174-9868")), @@ -21,17 +21,18 @@ Imports: rlang, rmarkdown, rstudioapi, + tools, utils, yaml Suggests: curl, knitr, rsconnect (>= 0.8.26), - testthat (>= 3.1.0), + testthat (>= 3.1.7), withr, xfun VignetteBuilder: - knitr + quarto Config/testthat/edition: 3 Encoding: UTF-8 Roxygen: list(markdown = TRUE) diff --git a/NAMESPACE b/NAMESPACE index 1c1fcb6..9e9fa9f 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -26,5 +26,6 @@ importFrom(rlang,is_interactive) importFrom(rmarkdown,relative_to) importFrom(rstudioapi,isAvailable) importFrom(rstudioapi,viewer) +importFrom(tools,vignetteEngine) importFrom(utils,browseURL) importFrom(yaml,write_yaml) diff --git a/NEWS.md b/NEWS.md index e30be26..356b439 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,7 @@ # quarto (development version) +- Add registration of vignette engine to use `quarto` as a vignette builder, and use `.qmd` file as vignette. See `vignette("hello", package = "quarto")`. (thanks, @dcnorris, #57). + - Add `quarto_binary_sitrep()` to check possible difference in Quarto binary used by this package, and the one used by RStudio IDE (thanks, @jthomasmock, #12). - Add `quarto_create_project()` function that calls `quarto create project ` (thanks, @maelle, #87). diff --git a/R/quarto-package.R b/R/quarto-package.R index 661d072..01c3ea2 100644 --- a/R/quarto-package.R +++ b/R/quarto-package.R @@ -4,5 +4,6 @@ ## usethis namespace: start #' @import rlang #' @importFrom cli cli_inform +#' @importFrom tools vignetteEngine ## usethis namespace: end NULL diff --git a/R/quarto.R b/R/quarto.R index b2c59d4..e4ea6b7 100644 --- a/R/quarto.R +++ b/R/quarto.R @@ -124,7 +124,7 @@ check_quarto_version <- function(ver, what, url) { #' @export quarto_binary_sitrep <- function(verbose = TRUE, debug = FALSE) { - quarto_found <- normalizePath(quarto_path(), mustWork = FALSE) + quarto_found <- quarto_path() if (is.null(quarto_found)) { if (verbose) { cli::cli_alert_danger(quarto_not_found_msg) @@ -132,6 +132,8 @@ quarto_binary_sitrep <- function(verbose = TRUE, debug = FALSE) { return(FALSE) } + quarto_found <- normalizePath(quarto_found, mustWork = FALSE) + same_config <- TRUE if (debug) verbose <- TRUE diff --git a/R/render.R b/R/render.R index 3282886..d15d1c7 100644 --- a/R/render.R +++ b/R/render.R @@ -34,7 +34,7 @@ #' This will be merged over `metadata-file` options if both are #' specified. #' @param metadata_file A yaml file passed to `--metadata-file` CLI flags to -#' overrite metadata. This will be merged with `metadata` if both are +#' override metadata. This will be merged with `metadata` if both are #' specified, with low precedence on `metadata` options. #' @param debug Leave intermediate files in place after render. #' @param quiet Suppress warning and other messages. diff --git a/R/utils-vignettes.R b/R/utils-vignettes.R new file mode 100644 index 0000000..80810f7 --- /dev/null +++ b/R/utils-vignettes.R @@ -0,0 +1,47 @@ +register_vignette_engines <- function(pkg) { + vig_engine("html", quarto_format = "html") + vig_engine("pdf", quarto_format = "pdf") + vig_engine("format", quarto_format = NULL) +} + + +vig_engine <- function(..., quarto_format) { + rmd_eng <- tools::vignetteEngine('rmarkdown', package = 'knitr') + tools::vignetteEngine( + ..., + weave = vweave_quarto(quarto_format), + tangle = rmd_eng$tangle, + pattern = "[.]qmd$", + package = "quarto", + aspell = rmd_eng$aspell + ) +} + +vweave_quarto <- function(format) { + meta <- get_meta(format) + function(file, driver, syntax, encoding, quiet = FALSE, ...) { + quarto_render(file, ..., output_format = format, metadata = meta) + } +} + +get_meta <- function(format) { + if (is.null(format)) return(NULL) + if (format == "html") { + return(get_meta_for_html()) + } +} + +get_meta_for_html <- function() { + + css <- system.file("rmarkdown", "template", "quarto_vignette", "resources", + "vignette.css", package = "quarto") + meta <- list() + meta$format$html <- + list( + `embed-resources` = TRUE, + minimal = TRUE, + theme = "none", + css = css + ) + meta +} diff --git a/R/utils.R b/R/utils.R index 7539be3..d314c79 100644 --- a/R/utils.R +++ b/R/utils.R @@ -1,5 +1,4 @@ - relative_to_wd <- function(path) { relative_to(getwd(), path) } diff --git a/R/zzz.R b/R/zzz.R new file mode 100644 index 0000000..6ef8350 --- /dev/null +++ b/R/zzz.R @@ -0,0 +1,4 @@ +# Register engines to support Quarto vignettes +.onLoad <- function(lib, pkg) { + register_vignette_engines(pkg) +} diff --git a/inst/rmarkdown/template/quarto_vignette/resources/vignette.css b/inst/rmarkdown/template/quarto_vignette/resources/vignette.css new file mode 100644 index 0000000..c5a5782 --- /dev/null +++ b/inst/rmarkdown/template/quarto_vignette/resources/vignette.css @@ -0,0 +1,158 @@ +body { + background-color: #fff; + margin: 1em auto; + max-width: 700px; + overflow: visible; + padding-left: 2em; + padding-right: 2em; + font-family: "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 14px; + line-height: 1.35; +} + + + +table { + margin: 1em auto; + border-width: 1px; + border-color: #DDDDDD; + border-style: outset; + border-collapse: collapse; +} +table th { + border-width: 2px; + padding: 5px; + border-style: inset; +} +table td { + border-width: 1px; + border-style: inset; + line-height: 18px; + padding: 5px 5px; +} +table, table th, table td { + border-left-style: none; + border-right-style: none; +} +table thead, table tr.even { + background-color: #f7f7f7; +} + +p { + margin: 0.5em 0; +} + +blockquote { + background-color: #f6f6f6; + padding: 0.25em 0.75em; +} + +hr { + border-style: solid; + border: none; + border-top: 1px solid #777; + margin: 28px 0; +} + +dl { + margin-left: 0; +} +dl dd { + margin-bottom: 13px; + margin-left: 13px; +} +dl dt { + font-weight: bold; +} + +ul { + margin-top: 0; +} +ul li { + list-style: circle outside; +} +ul ul { + margin-bottom: 0; +} + +pre, code { + background-color: #f7f7f7; + border-radius: 3px; + color: #333; + white-space: pre-wrap; /* Wrap long lines */ +} +pre { + border-radius: 3px; + margin: 5px 0px 10px 0px; + padding: 10px; +} +pre:not([class]) { + background-color: #f7f7f7; +} + +code { + font-family: Consolas, Monaco, 'Courier New', monospace; + font-size: 85%; +} +p > code, li > code { + padding: 2px 0px; +} + +div.figure { + text-align: center; +} +img { + background-color: #FFFFFF; + padding: 2px; + border: 1px solid #DDDDDD; + border-radius: 3px; + border: 1px solid #CCCCCC; + margin: 0 5px; +} + +h1 { + margin-top: 0; + font-size: 35px; + line-height: 40px; +} + +h2 { + border-bottom: 4px solid #f7f7f7; + padding-top: 10px; + padding-bottom: 2px; + font-size: 145%; +} + +h3 { + border-bottom: 2px solid #f7f7f7; + padding-top: 10px; + font-size: 120%; +} + +h4 { + border-bottom: 1px solid #f7f7f7; + margin-left: 8px; + font-size: 105%; +} + +h5, h6 { + border-bottom: 1px solid #ccc; + font-size: 105%; +} + +a { + color: #0033dd; + text-decoration: none; +} +a:hover { + color: #6666ff; } +a:visited { + color: #800080; } +a:visited:hover { + color: #BB00BB; } +a[href^="http:"] { + text-decoration: underline; } +a[href^="https:"] { + text-decoration: underline; } + + diff --git a/man/quarto-package.Rd b/man/quarto-package.Rd index eb47183..f6656ba 100644 --- a/man/quarto-package.Rd +++ b/man/quarto-package.Rd @@ -18,11 +18,11 @@ Useful links: } \author{ -\strong{Maintainer}: JJ Allaire \email{jj@rstudio.com} (\href{https://orcid.org/0000-0003-0174-9868}{ORCID}) +\strong{Maintainer}: Christophe Dervieux \email{cderv@posit.co} (\href{https://orcid.org/0000-0003-4474-2498}{ORCID}) Authors: \itemize{ - \item Christophe Dervieux \email{cderv@posit.co} (\href{https://orcid.org/0000-0003-4474-2498}{ORCID}) + \item JJ Allaire \email{jj@posit.co} (\href{https://orcid.org/0000-0003-0174-9868}{ORCID}) } } diff --git a/man/quarto_render.Rd b/man/quarto_render.Rd index 0c14a51..f16d112 100644 --- a/man/quarto_render.Rd +++ b/man/quarto_render.Rd @@ -71,7 +71,7 @@ This will be merged over \code{metadata-file} options if both are specified.} \item{metadata_file}{A yaml file passed to \code{--metadata-file} CLI flags to -overrite metadata. This will be merged with \code{metadata} if both are +override metadata. This will be merged with \code{metadata} if both are specified, with low precedence on \code{metadata} options.} \item{debug}{Leave intermediate files in place after render.} diff --git a/tests/testthat/_snaps/quarto.md b/tests/testthat/_snaps/quarto.md index 8d3700f..bda9621 100644 --- a/tests/testthat/_snaps/quarto.md +++ b/tests/testthat/_snaps/quarto.md @@ -77,3 +77,12 @@ Output [1] TRUE +--- + + Code + quarto_binary_sitrep(debug = TRUE) + Message + x Quarto command-line tools path not found! Please make sure you have installed and added Quarto to your PATH or set the QUARTO_PATH environment variable. + Output + [1] FALSE + diff --git a/tests/testthat/test-quarto.R b/tests/testthat/test-quarto.R index acbe22a..81b68c6 100644 --- a/tests/testthat/test-quarto.R +++ b/tests/testthat/test-quarto.R @@ -65,4 +65,12 @@ test_that("quarto CLI sitrep", { transform = transform_quarto_cli_in_output(full_path = TRUE, normalize_path = TRUE) ) ) + + # Mock no quarto found + with_mocked_bindings( + quarto_path = function(...) NULL, + expect_snapshot( + quarto_binary_sitrep(debug = TRUE) + ) + ) }) diff --git a/vignettes/.gitignore b/vignettes/.gitignore index 097b241..ba7abf3 100644 --- a/vignettes/.gitignore +++ b/vignettes/.gitignore @@ -1,2 +1,3 @@ *.html *.R +*_files diff --git a/vignettes/.install_extras b/vignettes/.install_extras new file mode 100644 index 0000000..a1a869c --- /dev/null +++ b/vignettes/.install_extras @@ -0,0 +1 @@ +include diff --git a/vignettes/hello-pdf.qmd b/vignettes/hello-pdf.qmd new file mode 100644 index 0000000..db81677 --- /dev/null +++ b/vignettes/hello-pdf.qmd @@ -0,0 +1,34 @@ +--- +title: "Quarto PDF Vignettes" +format: + pdf: + toc: false +vignette: > + %\VignetteIndexEntry{Quarto PDF Vignettes} + %\VignetteEngine{quarto::pdf} + %\VignetteEncoding{UTF-8} +--- + +{{< include include/_intro.qmd >}} + +## PDF Vignette Engines + +The **quarto** R package registers vignette engines that can be used in `%\VignetteEngine{}` directives in vignette headers. + +To learn more about how vignettes engine works, and how to write vignette engines, see the [Writing R Extensions](https://cran.r-project.org/doc/manuals/r-release/R-exts.html#Non_002dSweave-vignettes) manual and the [R Packages (2e)](https://r-pkgs.org/vignettes.html) book. + + +To produce a PDF vignette engine, add this to your YAML header + +```yaml +format: + pdf: + toc: false +vignette: > + %\VignetteIndexEntry{Vignette's Title} + %\VignetteEngine{quarto::pdf} + %\VignetteEncoding{UTF-8} +``` + +the vignette built will be a PDF vignette using Quarto's defaults for `format: pdf` format, with only Table Of Content opted-out. This format will be using LaTeX to build the PDF, and so you will need to take precaution for a CRAN vignette. Refers to [Writing R Extensions](https://cran.r-project.org/doc/manuals/r-release/R-exts.html#Non_002dSweave-vignettes) manual and CRAN policy. + diff --git a/vignettes/hello.qmd b/vignettes/hello.qmd new file mode 100644 index 0000000..3cb9ac8 --- /dev/null +++ b/vignettes/hello.qmd @@ -0,0 +1,66 @@ +--- +title: "Quarto HTML Vignettes" +vignette: > + %\VignetteIndexEntry{Quarto HTML Vignettes} + %\VignetteEngine{quarto::html} + %\VignetteEncoding{UTF-8} +--- + +{{< include include/_intro.qmd >}} + +## HTML Vignette Engines + +The **quarto** R package registers vignette engines that can be used in `%\VignetteEngine{}` directives in vignette headers. + +To learn more about how vignettes engine works, and how to write vignette engines, see the [Writing R Extensions](https://cran.r-project.org/doc/manuals/r-release/R-exts.html#Non_002dSweave-vignettes) manual and the [R Packages (2e)](https://r-pkgs.org/vignettes.html) book. + + +To produce a HTML vignette engine, add this to your YAML header + +```yaml +vignette: > + %\VignetteIndexEntry{Vignette's Title} + %\VignetteEngine{quarto::html} + %\VignetteEncoding{UTF-8} +--- +``` + +This will build a HTML document using Quarto, suitable for using as vignette to publish on CRAN. Choice has been made to create a very minimal HTML vignette by default, and so it is built with the following changes based to Quarto's `format: html` defaults: + +- The HTML file produced is standalone (i.e. [`embed-resources: true`](https://quarto.org/docs/output-formats/html-publishing.html#standalone-html)) +- Bootstrap has been disabled (i.e. [`theme: none`](https://quarto.org/docs/output-formats/html-themes.html) and [`minimal: true`](https://quarto.org/docs/output-formats/html-basics.html#minimal-html)) +- A custom CSS file is provided. + +This is equivalent to + +```yaml +format: + html: + theme: none + minimal: true + embed-resources: true + css: custom.css +``` + +All those configurations are set in way that they can't be override by YAML header in the vignette source file. Only new configuration can be set, e.g adding a Table Of Content: + +````yaml +format: + html: + toc: true +vignette: > + %\VignetteIndexEntry{Vignette's Title} + %\VignetteEngine{quarto::html} + %\VignetteEncoding{UTF-8} +```` + +This is one limitation of the current implementation of the vignette engine. This is to insure HTML vignette produced are reasonable in size and can be published on CRAN without problem. + +The other limitation concerns the interactive rendering. If you render your vignette `.qmd` file using `quarto render` or any other function, the output will be based on default HTML format from Quarto and not the vignette engine one. Only building the vignette will produce the real results. More about building vignette in the [R Packages (2e)](https://r-pkgs.org/vignettes.html#sec-vignettes-how-built-checked) book. + +Intermediates resources that would be created by an authoring workflow that would `quarto render` with default `format: html` should be ignored in package sources. + +- Added to `.Rbuildignore` (e.g `usethis::use_build_ignore("vignettes/*_files")`) +- Added to `.gitignore` (e.g. `usethis::use_git_ignore("*_files", "vignettes")`) + + diff --git a/vignettes/include/_intro.qmd b/vignettes/include/_intro.qmd new file mode 100644 index 0000000..6f65a33 --- /dev/null +++ b/vignettes/include/_intro.qmd @@ -0,0 +1,10 @@ +This is an example Quarto vignette, demonstrating how the **quarto** package can let you write R package vignettes with Quarto (). + +## Quarto as vignette builder + +Add this to your `DESCRIPTION` file: + +```dcf +VignetteBuilder: + quarto +``` diff --git a/vignettes/publishing.Rmd b/vignettes/publishing.qmd similarity index 98% rename from vignettes/publishing.Rmd rename to vignettes/publishing.qmd index f9e945d..92003bd 100644 --- a/vignettes/publishing.Rmd +++ b/vignettes/publishing.qmd @@ -1,9 +1,11 @@ --- title: "Publishing" -output: rmarkdown::html_vignette +format: + html: + toc: true vignette: > %\VignetteIndexEntry{Publishing} - %\VignetteEngine{knitr::rmarkdown} + %\VignetteEngine{quarto::html} %\VignetteEncoding{UTF-8} ---