Full Code of r-lib/hugodown for AI

main f6f23dd74ce5 cached
112 files
113.8 KB
36.0k tokens
1 requests
Download .txt
Repository: r-lib/hugodown
Branch: main
Commit: f6f23dd74ce5
Files: 112
Total size: 113.8 KB

Directory structure:
gitextract_u6vogus0/

├── .Rbuildignore
├── .gitattributes
├── .github/
│   ├── .gitignore
│   └── workflows/
│       ├── R-CMD-check.yaml
│       ├── pkgdown.yaml
│       ├── pr-commands.yaml
│       └── test-coverage.yaml
├── .gitignore
├── DESCRIPTION
├── LICENSE
├── LICENSE.md
├── NAMESPACE
├── R/
│   ├── hugo-install.R
│   ├── hugo-server.R
│   ├── hugo-version.R
│   ├── hugo.R
│   ├── hugodown-package.R
│   ├── md-document.R
│   ├── netlify.R
│   ├── post.R
│   ├── shortcode.R
│   ├── site-academic.R
│   ├── site.R
│   ├── test-fixtures.R
│   ├── tidy.R
│   └── utils.R
├── README.md
├── _pkgdown.yml
├── codecov.yml
├── hugodown.Rproj
├── inst/
│   ├── academic/
│   │   ├── README.md
│   │   ├── highlight-dark.css
│   │   ├── highlight-light.css
│   │   └── index.Rmd
│   └── templates/
│       ├── netlify.toml
│       └── template.Rproj
├── man/
│   ├── create_site_academic.Rd
│   ├── embed_gist.Rd
│   ├── hugo_build.Rd
│   ├── hugo_document.Rd
│   ├── hugo_install.Rd
│   ├── hugo_locate.Rd
│   ├── hugo_start.Rd
│   ├── hugo_version.Rd
│   ├── hugodown-package.Rd
│   ├── md_document.Rd
│   ├── shortcode.Rd
│   ├── site_outdated.Rd
│   ├── use_netlify_toml.Rd
│   ├── use_post.Rd
│   └── use_tidy_post.Rd
├── tests/
│   ├── testthat/
│   │   ├── .gitignore
│   │   ├── _snaps/
│   │   │   └── md-document.md
│   │   ├── archetypes/
│   │   │   ├── _hugodown.yaml
│   │   │   ├── archetypes/
│   │   │   │   ├── Rmd/
│   │   │   │   │   └── index.Rmd
│   │   │   │   ├── blog/
│   │   │   │   │   └── index.Rmd
│   │   │   │   └── md/
│   │   │   │       └── index.md
│   │   │   └── config.yml
│   │   ├── code-invalid.Rmd
│   │   ├── code.Rmd
│   │   ├── config-hugodown/
│   │   │   ├── _hugodown.yaml
│   │   │   └── config.yaml
│   │   ├── config-toml/
│   │   │   └── config.toml
│   │   ├── config-yaml/
│   │   │   └── config.yaml
│   │   ├── config-yml/
│   │   │   └── config.yml
│   │   ├── curly.Rmd
│   │   ├── div.Rmd
│   │   ├── emoji.Rmd
│   │   ├── error.Rmd
│   │   ├── knit-hooks.Rmd
│   │   ├── math.Rmd
│   │   ├── meta.Rmd
│   │   ├── minimal/
│   │   │   ├── .gitignore
│   │   │   ├── LICENSE
│   │   │   ├── README.md
│   │   │   ├── _hugodown.yaml
│   │   │   ├── config.toml
│   │   │   ├── content/
│   │   │   │   └── _index.md
│   │   │   └── themes/
│   │   │       └── bare/
│   │   │           ├── layouts/
│   │   │           │   └── index.html
│   │   │           └── theme.toml
│   │   ├── outdated/
│   │   │   ├── config.yml
│   │   │   └── content/
│   │   │       └── blog/
│   │   │           ├── _index.md
│   │   │           ├── ok-has-html/
│   │   │           │   ├── index.Rmd
│   │   │           │   └── index.html
│   │   │           ├── ok-no-hash/
│   │   │           │   ├── index.Rmd
│   │   │           │   └── index.md
│   │   │           ├── outdated-no-md/
│   │   │           │   └── index.Rmd
│   │   │           └── outdated-old-hash/
│   │   │               ├── index.Rmd
│   │   │               └── index.md
│   │   ├── output.Rmd
│   │   ├── plot.Rmd
│   │   ├── raw-html.Rmd
│   │   ├── table.Rmd
│   │   ├── test-hugo-install.R
│   │   ├── test-hugo-server.R
│   │   ├── test-hugo-version.R
│   │   ├── test-hugo.R
│   │   ├── test-md-document.R
│   │   ├── test-netlify.R
│   │   ├── test-post.R
│   │   ├── test-shortcode-arguments.txt
│   │   ├── test-shortcode-embed.txt
│   │   ├── test-shortcode-wrapper.txt
│   │   ├── test-shortcode.R
│   │   ├── test-site.R
│   │   ├── test-tidy-pleased.txt
│   │   ├── test-tidy.R
│   │   └── widget.Rmd
│   └── testthat.R
└── vignettes/
    ├── .gitignore
    ├── config.Rmd
    └── deploy.Rmd

================================================
FILE CONTENTS
================================================

================================================
FILE: .Rbuildignore
================================================
^hugodown\.Rproj$
^\.Rproj\.user$
^LICENSE\.md$
^codecov\.yml$
^\.github$
^_pkgdown\.yml$
^docs$
^pkgdown$


================================================
FILE: .gitattributes
================================================
*.Rmd text eol=lf


================================================
FILE: .github/.gitignore
================================================
*.html


================================================
FILE: .github/workflows/R-CMD-check.yaml
================================================
# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples
# Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help
#
# NOTE: This workflow is overkill for most R packages and
# check-standard.yaml is likely a better choice.
# usethis::use_github_action("check-standard") will install it.
on:
  push:
    branches: [main, master]
  pull_request:
    branches: [main, master]

name: R-CMD-check

jobs:
  R-CMD-check:
    runs-on: ${{ matrix.config.os }}

    name: ${{ matrix.config.os }} (${{ matrix.config.r }})

    strategy:
      fail-fast: false
      matrix:
        config:
          - {os: macOS-latest,   r: 'release'}

          - {os: windows-latest, r: 'release'}
          # Use 3.6 to trigger usage of RTools35
          - {os: windows-latest, r: '3.6'}

          - {os: ubuntu-latest,   r: 'devel', http-user-agent: 'release'}
          - {os: ubuntu-latest,   r: 'release'}
          - {os: ubuntu-latest,   r: 'oldrel-1'}
          - {os: ubuntu-latest,   r: 'oldrel-2'}
          - {os: ubuntu-latest,   r: 'oldrel-3'}
          - {os: ubuntu-latest,   r: 'oldrel-4'}

    env:
      GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
      R_KEEP_PKG_SOURCE: yes

    steps:
      - uses: actions/checkout@v2

      - uses: r-lib/actions/setup-pandoc@v2

      - uses: r-lib/actions/setup-r@v2
        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
        with:
          extra-packages: any::rcmdcheck
          needs: check

      - uses: r-lib/actions/check-r-package@v2
        with:
          upload-snapshots: true


================================================
FILE: .github/workflows/pkgdown.yaml
================================================
# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples
# Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help
on:
  push:
    branches: [main, master]
  pull_request:
    branches: [main, master]
  release:
    types: [published]
  workflow_dispatch:

name: pkgdown

jobs:
  pkgdown:
    runs-on: ubuntu-latest
    # Only restrict concurrency for non-PR jobs
    concurrency:
      group: pkgdown-${{ github.event_name != 'pull_request' || github.run_id }}
    env:
      GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
    steps:
      - uses: actions/checkout@v2

      - uses: r-lib/actions/setup-pandoc@v2

      - uses: r-lib/actions/setup-r@v2
        with:
          use-public-rspm: true

      - uses: r-lib/actions/setup-r-dependencies@v2
        with:
          extra-packages: any::pkgdown, local::.
          needs: website

      - name: Build site
        run: pkgdown::build_site_github_pages(new_process = FALSE, install = FALSE)
        shell: Rscript {0}

      - name: Deploy to GitHub pages 🚀
        if: github.event_name != 'pull_request'
        uses: JamesIves/github-pages-deploy-action@4.1.4
        with:
          clean: false
          branch: gh-pages
          folder: docs


================================================
FILE: .github/workflows/pr-commands.yaml
================================================
# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples
# Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help
on:
  issue_comment:
    types: [created]

name: Commands

jobs:
  document:
    if: ${{ github.event.issue.pull_request && (github.event.comment.author_association == 'MEMBER' || github.event.comment.author_association == 'OWNER') && startsWith(github.event.comment.body, '/document') }}
    name: document
    runs-on: ubuntu-latest
    env:
      GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
    steps:
      - uses: actions/checkout@v2

      - uses: r-lib/actions/pr-fetch@v2
        with:
          repo-token: ${{ secrets.GITHUB_TOKEN }}

      - uses: r-lib/actions/setup-r@v2
        with:
          use-public-rspm: true

      - uses: r-lib/actions/setup-r-dependencies@v2
        with:
          extra-packages: any::roxygen2
          needs: pr-document

      - name: Document
        run: roxygen2::roxygenise()
        shell: Rscript {0}

      - name: commit
        run: |
          git config --local user.name "$GITHUB_ACTOR"
          git config --local user.email "$GITHUB_ACTOR@users.noreply.github.com"
          git add man/\* NAMESPACE
          git commit -m 'Document'

      - uses: r-lib/actions/pr-push@v2
        with:
          repo-token: ${{ secrets.GITHUB_TOKEN }}

  style:
    if: ${{ github.event.issue.pull_request && (github.event.comment.author_association == 'MEMBER' || github.event.comment.author_association == 'OWNER') && startsWith(github.event.comment.body, '/style') }}
    name: style
    runs-on: ubuntu-latest
    env:
      GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
    steps:
      - uses: actions/checkout@v2

      - uses: r-lib/actions/pr-fetch@v2
        with:
          repo-token: ${{ secrets.GITHUB_TOKEN }}

      - uses: r-lib/actions/setup-r@v2

      - name: Install dependencies
        run: install.packages("styler")
        shell: Rscript {0}

      - name: Style
        run: styler::style_pkg()
        shell: Rscript {0}

      - name: commit
        run: |
          git config --local user.name "$GITHUB_ACTOR"
          git config --local user.email "$GITHUB_ACTOR@users.noreply.github.com"
          git add \*.R
          git commit -m 'Style'

      - uses: r-lib/actions/pr-push@v2
        with:
          repo-token: ${{ secrets.GITHUB_TOKEN }}


================================================
FILE: .github/workflows/test-coverage.yaml
================================================
# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples
# Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help
on:
  push:
    branches: [main, master]
  pull_request:
    branches: [main, master]

name: test-coverage

jobs:
  test-coverage:
    runs-on: ubuntu-latest
    env:
      GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}

    steps:
      - uses: actions/checkout@v2

      - uses: r-lib/actions/setup-r@v2
        with:
          use-public-rspm: true

      - uses: r-lib/actions/setup-r-dependencies@v2
        with:
          extra-packages: any::covr
          needs: coverage

      - name: Test coverage
        run: covr::codecov(quiet = FALSE)
        shell: Rscript {0}


================================================
FILE: .gitignore
================================================
.Rproj.user
.Rhistory
.RData
docs
inst/doc


================================================
FILE: DESCRIPTION
================================================
Package: hugodown
Title: Make websites with hugo and RMarkdown
Version: 0.0.0.9000
Authors@R: c(
    person("Hadley", "Wickham", , "hadley@rstudio.com", role = c("aut", "cre")),
    person("RStudio", role = "cph")
  )
Description: hugodown is a minimal version of blogdown that only supports
    hugo, and more clearly delineates the roles of RMarkdown (turning .Rmd
    into .md) and hugo (turning .md into .html).
License: MIT + file LICENSE
URL: https://github.com/r-lib/hugodown
BugReports: https://github.com/r-lib/hugodown/issues
Imports: 
    brio,
    curl,
    digest,
    downlit,
    evaluate,
    fs,
    later,
    processx,
    rappdirs,
    RcppTOML,
    rlang,
    rmarkdown,
    usethis (>= 1.6.0),
    whisker,
    whoami,
    withr,
    xml2,
    yaml
Suggests: 
    covr,
    DiagrammeR,
    gh,
    htmltools,
    knitr,
    magick,
    rstudioapi,
    testthat (>= 3.0.0)
VignetteBuilder: 
    knitr
Config/testthat/edition: 3
Encoding: UTF-8
LazyData: true
Roxygen: list(markdown = TRUE)
RoxygenNote: 7.2.1


================================================
FILE: LICENSE
================================================
YEAR: 2020
COPYRIGHT HOLDER: RStudio


================================================
FILE: LICENSE.md
================================================
# MIT License

Copyright (c) 2020 RStudio

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.


================================================
FILE: NAMESPACE
================================================
# Generated by roxygen2: do not edit by hand

export(create_site_academic)
export(embed_gist)
export(embed_instagram)
export(embed_tweet)
export(embed_vimeo)
export(embed_youtube)
export(hugo_browse)
export(hugo_build)
export(hugo_document)
export(hugo_install)
export(hugo_locate)
export(hugo_start)
export(hugo_stop)
export(hugo_version)
export(md_document)
export(shortcode)
export(site_outdated)
export(tidy_show_meta)
export(use_netlify_toml)
export(use_post)
export(use_tidy_post)
export(use_tidy_thumbnails)
import(fs)
import(rlang)


================================================
FILE: R/hugo-install.R
================================================
#' Install specified version of hugo
#'
#' Downloads binary from hugo releases, and installs in system wide cache.
#'
#' @param version String giving version (e.g. "0.69.0"). If omitted will
#'   default to latest release.
#' @param os Operating system, one of "Linux", "Windows", "macOS". Defaults
#'   to current operating system.
#' @param arch Architecture
#' @param extended Installed hugo-extended which also includes SCSS etc?
#' @export
#' @examples
#' \dontrun{
#' hugo_install()
#' }
hugo_install <- function(version = NULL, os = hugo_os(), arch = "64bit", extended = TRUE) {
  if (!is_installed("gh")) {
    abort("`gh` package required to install Hugo from GitHub")
  }

  message("Finding release")
  release <- hugo_release(version, os, arch, extended)

  home <- hugo_home(release$version, os, arch, extended)
  if (file.exists(home)) {
    message("hugo " , release$version, " already installed")
    hugo_default_inc(release$version)
    return(invisible())
  }

  message("Downloading ", path_file(release$url), "...")
  temp <- curl::curl_download(release$url, tempfile())

  message("Installing to ", path_dir(home), "...")
  switch(path_ext(release$url),
    "gz" = utils::untar(temp, exdir = home, tar = "internal"),
    "zip" = utils::unzip(temp, exdir = home)
  )
  hugo_default_inc(release$version)

  invisible()
}

hugo_default_inc <- function(version) {
  cur <- hugo_default_get()
  if (is.na(cur) || version > cur) {
    hugo_default_set(version)
  }
}
hugo_default_path <- function() {
  path(rappdirs::user_cache_dir("hugodown"), "VERSION")
}
hugo_default_get <- function() {
  if (!file_exists(hugo_default_path())) {
    NA
  } else {
    package_version(brio::read_lines(hugo_default_path())[[1]])
  }
}
hugo_default_set <- function(version) {
  path <- hugo_default_path()
  if (is.na(version)) {
    if (file_exists(path)) {
      file_delete(path)
    }
  } else {
    brio::write_lines(version, path)
  }
}

hugo_installed <- function() {
  path_file(dir_ls(rappdirs::user_cache_dir("hugodown")))
}

hugo_home <- function(version, os = hugo_os(), arch = "64bit", extended = TRUE) {
  cache_dir <- rappdirs::user_cache_dir("hugodown")
  dir_create(cache_dir)

  hugo <- paste0(
    "hugo", if (extended) "_extended", "_",
    version, "_",
    os, "_", arch
  )
  path(cache_dir, hugo)
}

hugo_release <- function(version = NULL, os = hugo_os(), arch = "64bit", extended = TRUE) {

  json <- hugo_releases()
  if (is.null(version)) {
    i <- 1
    version <- sub("^v", "", json[[1]]$tag_name)
  } else {
    versions <- vapply(json, "[[", "tag_name", FUN.VALUE = character(1))
    versions <- sub("^v", "", versions)

    i <- which(versions == version)
    if (length(i) != 1) {
      abort(paste0("Can't find version '", version, '"'))
    }
  }

  assets <- json[[i]]$assets
  names <- vapply(assets, "[[", "name", FUN.VALUE = character(1))

  asset_name <- hugo_asset_name(version, os, arch, extended)
  asset_i <- which(asset_name == names)
  if (length(asset_i) != 1) {
    abort(paste0("Can't find release asset with name '", asset_name, "'"))
  }

  list(version = version, url = assets[[asset_i]]$browser_download_url)
}

hugo_releases <- function() {
  if (env_has(hugodown, "hugo_releases")) {
    env_get(hugodown, "hugo_releases")
  } else {
    json <- gh::gh(
      "GET /repos/:owner/:repo/releases",
      owner = "gohugoio",
      repo = "hugo",
      .limit = if (is.null(version)) 1 else Inf,
      .progress = FALSE
    )
    env_poke(hugodown, "hugo_releases", json)
    json
  }
}

hugo_asset_name <- function(
                            version,
                            os = c("Linux", "Windows", "macOS"),
                            arch = "64bit",
                            extended = TRUE) {

  os <- arg_match(os)
  ext <- switch(os, Windows = ".zip", macOS = , Linux = ".tar.gz")

  paste0(
    "hugo", if (extended) "_extended", "_",
    version, "_",
    os, "-", arch, ext
  )
}

hugo_os <- function() {
  sysname <- tolower(Sys.info()[["sysname"]])
  switch(sysname,
    darwin = "macOS",
    linux = "Linux",
    windows = "Windows",
    abort("Unknown operating system; please set `os`")
  )
}


================================================
FILE: R/hugo-server.R
================================================
#' Manage the hugo server
#'
#' @section Hugo version:
#' hugodown will attempt to automatically use the correct version of hugo for
#' your site (prompting you to call [hugo_install()] if needed). It looks in
#' two places:
#'
#' * If `_hugodown.yaml` is present, it looks for the `hugo_version` key.
#' * If `netlify.toml` is present, it looks in
#'   `context$production$environment$HUGO_VERSION`
#'
#' This means if you already use netlify, hugodown will automatically match
#' the version of hugo that you're using for deployment.
#'
#' @description
#' `hugo_start()` starts a hugo server that will automatically re-generate
#' the site whenever the input changes. You only need to execute this once
#' per session; it continues to run in the background as you work on the site.
#' For large sites the hugo server can be slow to start; if it takes longer
#' than 30 seconds `hugo_start()` throws an error.
#'
#' `hugo_stop()` kills the server. This happens automatically when you exit
#' R so you shouldn't normally need to run this.
#'
#' `hugo_browse()` opens the site in the RStudio viewer or your web browser.
#' @export
#' @param site Path to hugo site.
#' @param auto_navigate Automatically navigate to the most recently changed
#'   page?
#' @param browse Automatically preview the site after the server starts?
#' @param render_to_disk Render site to disk? The default is to serve the
#'   site from memory, but rendering to disk can be helpful for debugging.
#' @param port Port to run server on. For advanced use only.
hugo_start <- function(site = ".",
                         auto_navigate = TRUE,
                         browse = TRUE,
                         render_to_disk = FALSE,
                         port = 1313) {
  path <- site_root(site)
  hugo_stop()

  if (port_active(port)) {
    abort("`hugo` already launched elsewhere.")
  }

  message("Starting server on port ", port)
  args <- c(
    "server",
    "--port", port,
    "--buildDrafts",
    "--buildFuture",
    if (auto_navigate) "--navigateToChanged",
    if (render_to_disk) "--renderToDisk"
  )
  ps <- hugo_run_bg(path, args, stdout = "|", stderr = "2>&1")
  if (!ps$is_alive()) {
    abort(ps$read_error())
  }

  # Swallow initial text
  init <- ""
  now <- proc.time()[[3]]
  ok <- FALSE

  while (proc.time()[[3]] - now < 30) {
    ps$poll_io(250)
    init <- paste0(init, ps$read_output())

    if (grepl("Ctrl+C", init, fixed = TRUE)) {
      ok <- TRUE
      break
    }
  }

  if (!ok) {
    ps$kill()
    cat(init)
    abort("Failed to start Hugo")
  }

  # Ensure output pipe doesn't get swamped
  poll_process <- function() {
    if (!ps$is_alive()) {
      return()
    }

    out <- ps$read_output()
    if (!identical(out, "")) {
      cat(out)
    }

    later::later(delay = 1, poll_process)
  }
  poll_process()

  hugodown$server <- ps
  if (browse) {
    hugo_browse()
  }

  invisible(ps)
}

#' @rdname hugo_start
#' @export
hugo_stop <- function() {
  if (!hugo_running()) {
    return(invisible())
  }

  hugodown$server$interrupt()
  hugodown$server$poll_io(500)
  hugodown$server$kill()
  env_unbind(hugodown, "server")
  invisible()
}

#' @rdname hugo_start
#' @export
hugo_browse <- function() {
  if (is_installed("rstudioapi") && rstudioapi::hasFun("viewer")) {
    rstudioapi::viewer("http://localhost:1313")
  } else {
    utils::browseURL("http://localhost:1313")
  }
}

hugo_running <- function() {
  env_has(hugodown, "server") && hugodown$server$is_alive()
}

port_active <- function(port) {
  tryCatch({
    suppressWarnings(con <- socketConnection("127.0.0.1", port, timeout = 1))
    close(con)
    TRUE
  }, error = function(e) FALSE)
}


#' Build site
#'
#' Build static html into specified directory. Useful for debugging and some
#' deployment scenarios
#'
#' @inheritParams hugo_start
#' @param dest Destination directory. If `NULL`, the default, will build
#'   in `{site}/public`
#' @param build_drafts,build_future Should drafts and future posts be included
#'   in the built site?
#' @param clean Remove files in `public/` that don't exist in the source.
#' @param base_url `<string>` Optionally override the `baseURL` setting from
#'   hugo config.
#' @param relative_urls `<bool>` Optionally the override the `relativeURL`
#'   setting from hugo config.
#' @export
hugo_build <- function(site = ".",
                       dest = NULL,
                       build_drafts = FALSE,
                       build_future = FALSE,
                       clean = FALSE,
                       base_url = NULL,
                       relative_urls = NULL
                       ) {
  path <- site_root(site)
  dest <- dest %||% path(path, "public")

  args <- c(
    "--destination", dest,
    if (build_drafts) "--buildDrafts",
    if (build_future) "--buildFuture",
    if (clean) "--cleanDestinationDir"
  )

  config <- c(
    character(),
    baseUrl = if (!is.null(base_url)) base_url,
    relativeURLs = if (!is.null(relative_urls)) tolower(relative_urls)
  )

  hugo_run(path, args, config)
  invisible()
}


================================================
FILE: R/hugo-version.R
================================================
#' Find hugo version needed for current site
#'
#' @description
#' Hugo changes rapidly, so it's important to pin your site to a specific
#' version and then deliberately update when needed. This function reports
#' which of hugo your site correctly uses.
#'
#' The primary location of this information is the `hugo_version` field
#' in `hugodown.yaml`. If that doesn't exist, we also look in `netlify.toml`.
#'
#' @seealso [hugo_install()] to install any version of hugo.
#' @inheritParams hugo_start
#' @export
hugo_version <- function(site = ".") {
  site <- site_root(site)

  config <- site_config(site)
  if (!is.null(config$hugo_version)) {
    return(config$hugo_version)
  }

  netlify <- path(site, "netlify.toml")
  if (file_exists(netlify)) {
    toml <- RcppTOML::parseTOML(netlify)
    # First look in production
    version <- toml$context$production$environment$HUGO_VERSION
    if (!is.null(version)) {
      return(version)
    }

    # Then in all
    version <- toml$build$environment$HUGO_VERSION
    if (!is.null(version)) {
      return(version)
    }
  }

  warn("Couldn't find hugo version declaration; falling back to latest install")
  hugo_default_get()
}


================================================
FILE: R/hugo.R
================================================
#' Locates a specific Hugo installation
#'
#' @param version The Hugo version to be located
#'
#' @return Returns the path to the Hugo installation, or an error if no
#' Hugo install is found
#' @export
hugo_locate <- function(version = hugo_default_get()) {
  path <- hugo_home(version)
  if (!file_exists(path)) {
    abort(c(
      paste0("hugo ", version, " not installed"),
      i = paste0("Do you need to call `hugodown::hugo_install('", version, "')`?")
    ))
  }

  path <- first_path(c(
    path(path, "hugo"),
    path(path, "hugo", ext = "exe")
  ))
  path_real(path)
}

hugo_run <- function(site, args, config = NULL, ...) {
  if (length(config) > 0) {
    names(config) <- paste0("HUGO_", toupper(names(config)))
  }

  path <- site_root(site)
  hugo <- hugo_locate(hugo_version(path))
  processx::run(hugo, args, wd = path, env = config, ...)
}

hugo_run_bg <- function(site, args, ...) {
  path <- site_root(site)
  hugo <- hugo_locate(hugo_version(path))
  processx::process$new(hugo, args, wd = path, ...)
}

hugo_config <- function(site = ".", override = NULL) {
  result <- hugo_run(site, "config", config = override)
  if (result$status != 0) {
    abort(paste0("Error running hugo config: ", result$stderr))
  }

  lines <- strsplit(result$stdout, "\n", fixed = TRUE)[[1]]
  vars <- regexec("^([A-Za-z0-9_]+)\\s*=\\s*([^\n]+)$", lines)
  matches <- regmatches(lines, vars)

  config <- lapply(matches, `[[`, 3)
  names(config) <- lapply(matches, `[[`, 2)
  config
}

hugo_config_str <- function(config, key) {
  value <- config[[tolower(key)]]
  sub("^\"?(.*?)\"?$", "\\1", value)
}

hugo_config_bool <- function(config, key) {
  value <- config[[tolower(key)]]
  value == "true"
}

hugo_config_int <- function(config, key) {
  value <- config[[tolower(key)]]
  as.integer(value)
}



================================================
FILE: R/hugodown-package.R
================================================
#' @keywords internal
#' @import rlang
#' @import fs
"_PACKAGE"

hugodown <- new_environment()

# The following block is used by usethis to automatically manage
# roxygen namespace tags. Modify with care!
## usethis namespace: start
## usethis namespace: end
NULL


================================================
FILE: R/md-document.R
================================================
#' An Rmd output format that produces Hugo-flavoured markdown
#'
#' This RMarkdown output format is designed to generate markdown that is
#' maximally compatible with Hugo. It intelligently generates a preview so
#' that you see something useful when Hugo isn't running, but it doesn't
#' get in the way of hugo's full-site preview when it is.
#'
#' @section Syntax highlighting:
#'
#' `md_document()` uses a hybrid system for syntax highlighting.
#' For R code it uses [downlit](http://github.com/r-lib/downlit). For
#' other languages, it relies on Chroma, the syntax highlighter built into
#' hugo.
#'
#' @export
#' @inheritParams rmarkdown::md_document
#' @param fig_width Figure width (in inches).
#' @param fig_asp Figure aspect ratio, defaults to the golden ratio.
#' @param tidyverse_style Use tidyverse knitr conventions? This sets
#'   `collapse = TRUE`, `comment = "#>`, `fig.align = "center"`, and
#'   `out.width = "700px"`.
md_document <- function(fig_width = 7,
                        fig_asp = 0.618,
                        fig_retina = 2,
                        tidyverse_style = TRUE
                        ) {

  knitr <- rmarkdown::knitr_options_html(
    fig_height = NULL,
    fig_width = fig_width,
    fig_retina = fig_retina,
    keep_md = FALSE
  )
  knitr$opts_chunk$fig.asp <- fig_asp
  knitr$opts_chunk$fig.path <- "figs/"
  # Ensure knitr doesn't turn HTML widgets into pngs
  knitr$opts_chunk$screenshot.force <- FALSE

  knitr$knit_hooks <- knit_hooks()

  if (tidyverse_style) {
    knitr$opts_chunk$collapse <- TRUE
    knitr$opts_chunk$comment <- "#>"
    knitr$opts_chunk$fig.align <- "center"
    knitr$opts_chunk$out.width <- "700px"
  }

  pandoc <- rmarkdown::pandoc_options(
    to = goldmark_format(),
    from = paste0(rmarkdown::rmarkdown_format(), "+emoji"),
    args = "--wrap=none",
    ext = ".md"
  )

  input_rmd <- NULL
  old_options <- NULL
  old_env <- NULL

  pre_knit <- function(input, ...) {
    input_rmd <<- input
    old_options <<- options(
      cli.unicode = TRUE,
      cli.num_colors = 8L,
      cli.dynamic = FALSE,
      crayon.enabled = TRUE
    )
    old_env <- set_envvar(c(RSTUDIO = 0))
  }
  on_exit <- function(...) {
    options(old_options)
    set_envvar(old_env)
  }

  hack_always_allow_html <- function(...) {
    # This truly awful hack ensures that rmarkdown doesn't tell us we're
    # producing HTML widgets
    render_env <- env_parent(parent.frame())
    render_env$front_matter$always_allow_html <- TRUE
    NULL
  }

  knit_meta <- NULL
  output_dir <- NULL
  preprocess <- function(metadata, input_file, runtime, knit_meta, files_dir, output_dir) {
    knit_meta <<- knit_meta
    output_dir <<- output_dir
    NULL
  }

  postprocess <- function(metadata, input_file, output_file, clean, verbose) {
    old_yaml <- extract_yaml(brio::read_lines(input_file))

    new_yaml <- list(rmd_hash = rmd_hash(input_rmd))
    if (length(knit_meta) > 0) {
      if (!is_installed("htmltools")) {
        abort("htmltools package required for posts that include HTML widgets")
      }

      # Capture dependencies, remove duplicates, save to directory, and render
      deps <- htmltools::resolveDependencies(knit_meta)
      local <- lapply(deps, htmltools::copyDependencyToDir, outputDir = output_dir)
      local <- lapply(local, htmltools::makeDependencyRelative, output_dir)
      deps <- strsplit(htmltools::renderDependencies(local), "\n")[[1]]
      new_yaml$html_dependencies <- deps
    }

    body <- brio::read_file(output_file)

    output_lines <- c(
      "---", old_yaml, yaml::as.yaml(new_yaml), "---",
      "",
      link_inline(body)
    )
    brio::write_lines(output_lines, output_file)

    # If server not running, and RStudio is rendering the doc, generate
    # a standalone HTML file for preview
    if (!port_active(1313) && !is.na(preview_dir())) {
      output_html <- "preview.html"
      rmarkdown::pandoc_convert(
        input = output_file,
        output = output_html,
        to = "html",
        options = preview_pandoc_args()
      )
      output_file <- file_move(output_html, preview_path())
    } else {
      output_file <- tempdir()
    }

    output_file
  }

  rmarkdown::output_format(
    knitr = knitr,
    pandoc = pandoc,
    pre_processor = preprocess,
    post_processor = postprocess,
    pre_knit = pre_knit,
    post_knit = hack_always_allow_html,
    on_exit = on_exit
  )
}

goldmark_format <- function() {
  paste(
    "markdown_strict",
    # https://github.com/rstudio/rstudio/blob/master/src/gwt/panmirror/src/editor/src/api/pandoc_format.ts#L344-L356
    "all_symbols_escapable",
    "backtick_code_blocks",
    "fenced_code_blocks",
    "space_in_atx_header",
    "intraword_underscores",
    "lists_without_preceding_blankline",
    "shortcut_reference_links",
    # https://github.com/rstudio/rstudio/blob/master/src/gwt/panmirror/src/editor/src/api/pandoc_format.ts#L380-L392
    "pipe_tables",
    "strikeout",
    "autolink_bare_uris",
    "task_lists",
    "definition_lists",
    "footnotes",
    "smart",
    "tex_math_dollars",
    # custom
    "native_divs",
    "emoji",
    sep = "+"
  )
}

preview_pandoc_args <- function() {
  template_path <- path_package(
    "rmarkdown/templates/github_document/resources/preview.html",
    package = "rmarkdown"
  )
  css_path <- path_package(
    "rmarkdown/templates/github_document/resources/github.css",
    package = "rmarkdown"
  )

  args <- c(
    "--standalone",
    "--self-contained",
    "--highlight-style", "pygments",
    "--template", template_path,
    "--email-obfuscation", "none",
    "--variable", paste0("github-markdown-css:", css_path),
    "--metadata", "pagetitle=PREVIEW"
  )
}

preview_dir <- function() {
  Sys.getenv("RMARKDOWN_PREVIEW_DIR", unset = NA)
}
preview_path <- function() {
  file_temp("preview-", preview_dir(), ext = "html")
}

extract_yaml <- function(lines) {
  delim <- grep("^---\\s*$", lines)
  if (length(delim) < 2) {
    return(character())
  }

  lines[(delim[[1]] + 1):(delim[[2]] - 1)]
}


# knitr hooks -------------------------------------------------------------

knit_hooks <- function() {
  in_code <- FALSE
  needs_code <- function(val, x, before = TRUE) {
    if (val == in_code) {
      return(x)
    }

    in_code <<- val
    if (val) {
      html <- "<pre class='chroma'><code class='language-r' data-lang='r'>"
      ws <- ""
    } else {
      html <- "</code></pre>"

      # move trailing newline after code
      if (grepl("\n$", x)) {
        x <- gsub("\n$", "", x)
        ws <- "\n"
      } else {
        ws <- ""
      }
    }

    if (before) {
      paste0(html, x, ws)
    } else {
      paste0(x, html, ws)
    }
  }

  hook_output <- function(type, x, options) {
    if (options$results == "asis") {
      needs_code(FALSE, x)
    } else {
      x <- paste0(x, "\n", collapse = "")
      x <- highlight_if_possible(x, options$engine)
      needs_code(TRUE, x)
    }
  }
  hook_source <- function(x, options) {
    x <- paste0(x, "\n", collapse = "")
    x <- highlight_if_possible(x, options$engine)
    x <- paste0(x, "\n")
    needs_code(TRUE, x)
  }
  hook_plot <- function(x, options) {
    # Repair damage done by pretending to be latex
    if (grepl("linewidth", options$out.width)) {
      width <- as.numeric(gsub("\\\\linewidth", "", options$out.width))
      options$out.width <- paste0(width * 100, "%")
    }

    x <- knitr::hook_plot_md(x, options)
    needs_code(FALSE, x)
  }

  hook_chunk <- function(x, options, ...) {
    x <- needs_code(FALSE, x, before = FALSE) # reset for next chunk
    x <- paste0("<div class='highlight'>", x, "</div>")
    indent(x, options$indent)
  }

  evaluate <- function(input, ...) {
    # Setting output format to latex ensures that asis outputs are still
    # passed to hook_output
    Encoding(input) <- "UTF-8"
    knitr::opts_knit$set(out.format = "latex")
    evaluate::evaluate(input, ...)
  }

  list(
    chunk   = hook_chunk,
    evaluate = evaluate,
    source  = hook_source,
    plot    = hook_plot,
    output  = function(x, opts) hook_output("output", x, opts),
    warning = function(x, opts) hook_output("warning", x, opts),
    error   = function(x, opts) hook_output("error", x, opts),
    message = function(x, opts) hook_output("message", x, opts)
  )
}

# if x is not valid R code, downlit::highlight will return NA
# In this case, we return x without highlighting.
highlight_if_possible <- function(x, engine) {
  if (engine != "R") {
    x
  } else {
    out <- downlit::highlight(x, pre_class = NULL)
    # replace curly operator with HTML entities
    # otherwise Hugo will treat it as a shortcode
    out <- gsub("\\{", "&#123;", out)
    out <- gsub("\\}", "&#125;", out)
    if (is.na(out)) {
      x
    } else {
      out
    }
  }
}


indent <- function(x, indent) {
  if (is.null(indent)) {
    return(x)
  }
  paste0(indent, gsub("\n", paste0("\n", indent), x))
}

# inline code -------------------------------------------------------------

link_inline <- function(x) {
  regexps <- c(
    "\\[[^\\]]+\\]\\([^\\)]*\\)" , # link
    "(?m)^\\s*#{1,}.*$", # heading
    "(?s)<pre.*?</pre>" # code block
  )
  danger <- paste0("(", regexps, ")", collapse = "|")

  protect_code <- function(x) gsub("`", "\u241E", x)
  restore_code <- function(x) gsub("\u241E", "`", x)

  x <- str_replace(x, danger, protect_code)
  x <- str_replace(x, "(?<!``)`([^`]+)`", function(match) {
    code <- gsub("^`|`$", "", match)
    href <- vapply(code, downlit::autolink_url, character(1))
    ifelse(is.na(href), match, paste0("[", match, "](", href, ")"))
  })
  x <- str_replace(x, danger, restore_code)
  x
}

str_replace <- function(x, pattern, fun, ...) {
  loc <- gregexpr(pattern, x, perl = TRUE)
  matches <- regmatches(x, loc)
  out <- lapply(matches, fun, ...)

  regmatches(x, loc) <- out
  x
}

#' Deprecated: please use `md_document()`
#' @export
#' @keywords internal
hugo_document <- md_document


================================================
FILE: R/netlify.R
================================================
#' Create `netlify.toml`
#'
#' This helper creates a basic `netlify.toml` file, automatically setting the
#' hugo version to match your blog. This is needed when publishing your site
#' with [netlify](https://www.netlify.com); see `vignette("deploy")` for more
#' details.
#'
#' @export
#' @inheritParams use_post
use_netlify_toml <- function(site = ".") {
  site <- site_root(site)

  usethis::ui_done("Writing netlify.toml")
  whisker_template(
    path_package("hugodown", "templates", "netlify.toml"),
    path(site, "netlify.toml"),
    list(hugo_version = hugo_version(site))
  )
}


================================================
FILE: R/post.R
================================================
#' Create a new post
#'
#' Post creation takes advantage of Hugo's
#' [archetypes](https://gohugo.io/content-management/archetypes/) or templates,
#' with an extension for `.Rmd` files. `use_post()` first calls `hugo new`
#' (which will apply go templating to `.md` files in the archetype),
#' and then uses [whisker](https://github.com/edwindj/whisker) to template
#' any `.Rmd` files.
#'
#'
#' @param path Directory to create, like `blog/2020-my-favourite-package`.
#' @param kind Kind of archetype of use; usually automatically derived
#'   from the base directory of `path`.
#' @param data Any additional data to be used when templating `.Rmd` files.
#'
#'   The default data includes:
#'   * `date`: today's date (in YYYY-MM-DD format).
#'   * `author`: [whoami::fullname()].
#'   * `slug`: taken from the file name of `path`.
#' @param site Path to the hugo site.
#' @param open Open file for interactive editing?
#' @export
use_post <- function(path, kind = NULL, data = list(), site = ".", open = is_interactive()) {
  site <- site_root(site)

  tld <- path_dir(path)
  if (!dir_exists(path(site, "content", tld))) {
    abort(paste0("Can't find '", tld, "' directory in 'content/'"))
  }

  dest <- path(site, "content", path)
  if (file_exists(dest)) {
    abort(paste0("`path` already exists"))
  }

  args <- c(
    "new", path,
    if (!is.null(kind)) c("--kind", kind)
  )
  hugo_run(site, args)


  # Not a bundle
  if (!file_exists(dest)) {
    return()
  }

  rmds <- dir_ls(dest, glob = "*.Rmd")
  defaults <- list(
    slug = path_file(path),
    title = unslug(path_file(path)),
    author = whoami::fullname("Your name"),
    date = strftime(Sys.Date(), "%Y-%m-%d")
  )
  data <- utils::modifyList(defaults, data)

  lapply(rmds, function(path) whisker_template(path, path, data))

  index <- dir_ls(dest, pattern = "index")
  usethis::edit_file(index, open = open)

  invisible(dest)
}

whisker_template <- function(in_path, out_path, data) {
  file <- brio::read_file(in_path)
  out <- whisker::whisker.render(file, data)
  brio::write_lines(out, out_path)
}


================================================
FILE: R/shortcode.R
================================================
#' Generate a hugo shortcode
#'
#' @description
#' Generate a hugo shortcode with appropriate pandoc markup to preserve it as
#' is when embedded in an R markdown document.
#'
#' Generally, I don't recommend calling this function directly; instead
#' use it inside a function with the same name as the shortcode you want to
#' wrap. See [embed_gist()] and friends for examples
#'
#' @param .name Name of the shortcode
#' @param ... Arguments to the shortcode, supplied either by name or
#'   position depending on the shortcode. By default, strings will
#'   automatically be quoted with single quotes. Suppress this quoting
#'   by wrapping the argument in `I()`.
#' @param .contents Contents of the shortcode for paired shortcodes.
#' @param .output Is the output of the shortcode html or markdown? This
#'   controls whether the shortcode uses `<>` or `%`.
#' @param .inline Is the shortcode designed to be used inline or in its own
#'   paragraph? Controls whether the shortcode is wrapped in a block or inline
#'   [raw attribute](https://pandoc.org/MANUAL.html#extension-raw_attribute).
#' @export
#' @examples
#' pkg <- function(name) {
#'   shortcode("pkg", name, .inline = TRUE)
#' }
#' pkg("hugodown")
shortcode <- function(.name, ..., .contents = NULL, .output = c("html", "md"), .inline = FALSE) {
  call <- paste0(c(.name, shortcode_args(...)), collapse = " ")
  wrap <- switch(arg_match(.output),
    html = function(x) paste0("{{< ", x, " >}}"),
    md = function(x) paste0("{{% ", x, " %}}"),
  )

  if (is.null(.contents)) {
    out <- wrap(call)
  } else {
    out <- paste0(wrap(call), .contents, wrap(paste0("/", .name)))
  }

  if (.inline) {
    paste0("`", out, "`{=html}")
  } else {
    paste0("```{=html}\n", out, "\n```\n")
  }
}

shortcode_args <- function(...) {
  args <- list2(...)
  args <- args[!vapply(args, is.null, logical(1))]

  if (length(args) == 0) {
    return(NULL)
  }

  names <- names2(args)

  as_value <- function(x) {
    if (is.character(x) && !inherits(x, "AsIs")) {
      encodeString(x, quote = "'")
    } else {
      format(x)
    }
  }
  values <- vapply(args, as_value, character(1))
  equals <- ifelse(names == "", "", "=")

  paste0(names, equals, values, collapse = " ")
}


#' Generate hugo shortcodes to embed various types of media
#'
#' @description
#' These are wrappers that make it easy to generate
#' [hugo shortcodes](https://gohugo.io/content-management/shortcodes/) that
#' make it easy to embed various types of media into your pages. You use from
#' inline R code like:
#'
#' ```
#' This tweet announced the release of hugo 0.24:
#'
#' `R embed_tweet("877500564405444608")`
#' ```
#'
#' @param username GitHub/Twitter user name
#' @param id A string giving the object id. You'll usually find this by
#'  inspecting the URL:
#'  * gist: `https://gist.github.com/spf13/7896402` -> `7896402`
#'  * instagram: `https://www.instagram.com/p/BWNjjyYFxVx/` -> `BWNjjyYFxVx`
#'  * twitter: `https://twitter.com/spf13/status/877500564405444608` -> `877500564405444608`
#'  * vimeo: `https://vimeo.com/channels/staffpicks/146022717` -> `146022717`
#'  * youtube: `https://www.youtube.com/watch?v=w7Ft2ymGmfc` -> `w7Ft2ymGmfc`
#' @param filename Pick single file from multiple file gist
#' @export
embed_gist <- function(username, id, filename = NULL) {
  shortcode("gist", username, id, filename)
}
#' @param caption Show instagram caption?
#' @export
#' @rdname embed_gist
embed_instagram <- function(id, caption = TRUE) {
  stopifnot(is.character(id))
  shortcode("instagram", I(id), if (!caption) I("hidecaption"))
}
#' @export
#' @rdname embed_gist
embed_tweet <- function(id, username = NULL) {
  stopifnot(is.character(id))
  shortcode("tweet", username = username, id = id)
}
#' @export
#' @rdname embed_gist
embed_vimeo <- function(id) {
  stopifnot(is.character(id))
  shortcode("vimeo", I(id))
}
#' @param autoplay Automatically play youtube video?
#' @export
#' @rdname embed_gist
embed_youtube <- function(id, autoplay = FALSE) {
  stopifnot(is.character(id))

  if (autoplay) {
    shortcode("youtube", id = I(id), autoplay = "true")
  } else {
    shortcode("youtube", id = id)
  }
}


================================================
FILE: R/site-academic.R
================================================
#' Create a hugo academic site
#'
#' @description
#' Create a hugo academic 4.8.0 site, configured to work well with hugodown.
#' In particular, it ensures that the following features important for R
#' users work correctly:
#'
#' * Syntax highlighting (turns off default js highlighting, renables
#'   default chroma, and sets up styles in `assets/chroma.css`).
#'
#' * Math
#'
#' * HTML widgets
#'
#' * Default post archetype is tweaked to create `.Rmd`
#' @param path Path to create site
#' @param open Open new site after creation?
#' @param rstudio Create RStudio project?
#' @export
create_site_academic <- function(
                                 path = ".",
                                 open = is_interactive(),
                                 rstudio = rstudioapi::isAvailable()) {
  # Use most recent version that release was tested with
  # https://sourcethemes.com/academic/updates/v4.8.0/#breaking-changes
  hugo_locate("0.66.0")

  dir_create(path)
  usethis::ui_silence(old <- usethis::proj_set(path, force = TRUE))
  on.exit(usethis::ui_silence(usethis::proj_set(old)))

  use_rstudio_website_proj(path)

  usethis::ui_done("Downloading academic theme")
  theme_dir <- academic_download("4.8.0")

  usethis::ui_done("Copying site components")
  dir_copy_contents(path(theme_dir, "exampleSite"), path)

  usethis::ui_done("Installing academic theme")
  academic_install(path, theme_dir)

  usethis::ui_done("Patching theme for hugodown compatibility")
  academic_patch(path)

  if (open) {
    usethis::proj_activate(path)
  }
  invisible(path)
}

academic_download <- function(version = "4.8.0") {
  zip <- curl::curl_download(
    paste0("https://github.com/wowchemy/wowchemy-hugo-modules/archive/v", version, ".zip"),
    file_temp("hugodown")
  )
  exdir <- file_temp("hugodown")
  utils::unzip(zip, exdir = exdir)
  path(exdir, paste0("wowchemy-hugo-modules-", version))
}

academic_install <- function(path, theme_dir) {
  theme_path <- dir_create(path(path, "themes", "academic"))
  dir_copy_contents(theme_dir, theme_path)
  dir_delete(path(theme_path, "exampleSite"))
}

# Patch existing theme ----------------------------------------------------

academic_patch <- function(path) {
  config_path <- file_move(path(path, "config", "_default", "config.toml"), path)
  academic_patch_config(config_path)
  academic_patch_params(path(path, "config", "_default", "params.toml"))
  academic_write_hugodown(path)

  # Create Rmd post archetype
  # Must modify template because site archetype is _unioned_ with template
  post_archetype <- path(path, "themes", "academic", "archetypes", "post")
  file_move(path(post_archetype, "index.md"), path(post_archetype, "index.Rmd"))
  academic_patch_post_archetype(path(post_archetype, "index.Rmd"))

  # Patch <head>
  academic_write_custom_head(path)

  usethis::use_git_ignore(c("resources", "public"))
  file_copy(path_package("hugodown", "academic", "README.md"), path)
  file_copy(path_package("hugodown", "academic", "index.Rmd"), path)
}

academic_patch_config <- function(path) {
  lines <- brio::read_lines(path)

  # Ignore knitr intermediates
  knitr_ignore <- "ignoreFiles = ['\\.Rmd$', '_files$', '_cache$', '\\.knit\\.md$', '\\.utf8\\.md$']"
  lines <- line_replace(lines, "^ignoreFiles", knitr_ignore)

  # Use goldmark syntax higlighting (change in params.toml suppresses highlight.js)
  lines <- line_replace(lines, "    codeFences = false", "    codeFences = true")

  # Use highlight classes
  lines <- line_insert_after(lines, "^ignoreFiles", "pygmentsUseClasses = true")

  brio::write_lines(lines, path)
}

academic_patch_params <- function(path) {
  lines <- brio::read_lines(path)

  # Turn math on & js highlighting off
  lines <- line_replace(lines, "math = false", "math = true")
  lines <- line_replace(lines, "highlight = true", "highlight = false")

  brio::write_lines(lines, path)
}

academic_write_hugodown <- function(path) {
  opts <- list(
    hugo_version = "0.66.0"
  )
  yaml::write_yaml(opts, path(path, "_hugodown.yaml"))
}

academic_patch_post_archetype <- function(path) {
  lines <- brio::read_lines(path)
  lines <- c(lines[1],
    "output: hugodown::md_document",
    lines[-1]
  )
  lines <- line_replace(lines,
    'title: "{{ replace .Name "-" " " | title }}',
    'title: "{{ title }}"',
    fixed = TRUE
  )
  lines <- line_replace(lines, 'date: {{ .Date }}', 'date: {{ date }}', fixed = TRUE)
  lines <- line_replace(lines, 'lastmod: {{ .Date }}', 'lastmod: {{ date }}', fixed = TRUE)

  brio::write_lines(lines, path)
}

academic_write_custom_head <- function(path) {
  # hugo gen chromastyles --style=github > inst/academic/highlight-light.css
  # hugo gen chromastyles --style=dracula > inst/academic/highlight-dark.css

  dir_create(path(path, "static", "css"))
  file_copy(path_package("hugodown", "academic", "highlight-light.css"), path(path, "static", "css"))
  file_copy(path_package("hugodown", "academic", "highlight-dark.css"), path(path, "static", "css"))

  head <- path(path, "layouts", "partials", "custom_head.html")
  dir_create(path_dir(head))

  brio::write_lines(c(
    "<link rel='stylesheet' href='{{ \"css/highlight-light.css\" | relURL }}' title='hl-light'>",
    "<link rel='stylesheet' href='{{ \"css/highlight-dark.css\" | relURL }}' title='hl-dark' disabled>",
    "{{ range .Params.html_dependencies }}",
    "  {{ . | safeHTML }}",
    "{{ end }}"
  ), head)
}

# Helpers -----------------------------------------------------------------

line_find <- function(x, pattern, fixed = FALSE) {
  ignore <- grep(pattern, x, fixed = fixed)
  if (length(ignore) != 1) {
    abort(paste0("Found ", length(ignore), " matching lines"))
  }
  ignore
}
line_replace <- function(x, pattern, replacement, fixed = FALSE) {
  x[line_find(x, pattern, fixed = fixed)] <- replacement
  x
}
line_insert_after <- function(x, pattern, lines) {
  n <- length(x)
  i <- line_find(x, pattern)
  c(x[1:i], lines, x[(i + 1):n])
}

dir_copy_contents <- function(path, new_path) {
  for (path in dir_ls(path)) {
    if (is_file(path)) {
      file_copy(path, path(new_path, path_file(path)))
    } else {
      dir_copy(path, path(new_path, path_file(path)))
    }
  }
}

# Replace after https://github.com/r-lib/usethis/issues/1153
use_rstudio_website_proj <- function(path) {
  project_name <- path_file(path_abs(path))
  rproj_file <- paste0(project_name, ".Rproj")
  new <- usethis::use_template("template.Rproj",
    rproj_file,
    package = "hugodown"
  )
  usethis::use_git_ignore(".Rproj.user")
}


================================================
FILE: R/site.R
================================================
site_root <- function(path = ".") {
  path <- as.character(path_abs(path))

  while (!identical(path, path_dir(path))) {
    if (file_exists(path(path, "config.yaml"))) {
      return(path)
    }
    if (file_exists(path(path, "config.yml"))) {
      return(path)
    }
    if (file_exists(path(path, "config.toml"))) {
      return(path)
    }
    path <- path_dir(path)
  }

  abort("Can't find 'config.yml' or 'config.toml'")
}

site_config <- function(path = ".") {
  site <- site_root(path)
  site_yaml <- path(site, "_hugodown.yaml")

  if (!file_exists(site_yaml)) {
    NULL
  } else {
    yaml::read_yaml(site_yaml)
  }
}

#' Find `.Rmd`s that need to be re-rendered.
#'
#' [md_document()] adds a hash of the input `.Rmd` in the YAML metdata of
#' the `.md` file that it creates. This provides a reliable way to determine
#' whether or not a `.Rmd` has been changed since the last time the `.md`
#' was rendered.
#'
#' @param site Path to hugo site.
#' @export
site_outdated <- function(site = ".") {
  site <- site_root(site)

  rmd <- dir_ls(path(site, "content"), recurse = TRUE, regexp = "\\.Rmd$")
  rmd <- rmd[vapply(rmd, rmd_needs_render, logical(1))]
  rmd
}

rmd_needs_render <- function(path) {
  # Has .html, so must've been rendered by blogdown
  if (file_exists(path_ext_set(path, "html"))) {
    return(FALSE)
  }

  md_path <- path_ext_set(path, "md")
  if (!file_exists(md_path)) {
    return(TRUE)
  }

  yaml <- rmarkdown::yaml_front_matter(md_path)
  hash <- yaml$rmd_hash
  if (is.null(hash)) {
    return(FALSE)
  }

  hash != rmd_hash(path)
}

rmd_hash <- function(path) {
  digest::digest(path, file = TRUE, algo = "xxhash64")
}

hugodown_site <- function(input = ".", output_format = NULL) {
  # read config and output directory
  config <- hugo_config(input)
  output_dir <- hugo_config_str(config, "publishdir")

  list(
    # name for site (used as default name for publishing)
    name = hugo_config_str(config, "title"),

    # output directory (e.g. "public")
    output_dir = output_dir,

    # render_site callback
    render = function(input_file, output_format, envir, quiet, ...) {

      # Render the entire site
      if (is.null(input_file)) {

        # render outdated rmds
        lapply(site_outdated(input), function(rmd) {
          cat("Rendering modified Rmd:", fs::path_rel(rmd, input), "\n")
          rmarkdown::render(
            input = rmd,
            output_format = output_format,
            envir = envir,
            quiet = quiet,
            ...
          )
        })

        # build with relative urls so that the site is deployable anywhere
        hugo_build(input, relative_urls = TRUE)

        if (!quiet) {
          cat("Hugo site built:", file.path(input, output_dir))
        }

        # render just a single file (this hook is for doing incremental
        # renders of the site based on a "Knit" in the IDE). Since
        # hugodown already handles this well w/ just delegate here to
        # rmarkdown::render.
      } else {
        rmarkdown::render(
          input = input_file,
          output_format = output_format,
          envir = envir,
          quiet = quiet,
          ...
        )
      }
    },

    # relative path to outputs that require cleaning
    clean = function() {
      files <- output_dir
      files[file.exists(file.path(input, files))]
    }
  )
}


================================================
FILE: R/test-fixtures.R
================================================
local_file <- function(path, env = parent.frame()) {
  tmp <- dir_create(file_temp())
  withr::defer(dir_delete(tmp), envir = env)

  file_copy(path, tmp)
}

local_render <- function(path, env = parent.frame()) {
  tmp_path <- local_file(path, env = env)
  rmarkdown::render(tmp_path, quiet = TRUE)
  out_path <- path_ext_set(tmp_path, "md")

  lines <- brio::read_lines(out_path)
  xml <- paste("<html>", paste0(lines[-(1:5)], collapse = "\n"), "</html>")

  list(
    src = path,
    dst = out_path,
    dir = path_dir(out_path),
    lines = lines,
    xml = xml2::read_html(xml)
  )
}

local_dir <- function(path, env = parent.frame()) {
  tmp <- file_temp("hugodown-")
  withr::defer(dir_delete(tmp), envir = env)

  dir_copy(path, tmp)
}

skip_if_no_hugo <- function() {
  if (is.na(hugo_default_get())) {
    testthat::skip("hugo not installed")
  }
  if (hugo_default_get() < "0.72") {
    testthat::skip("need at least hugo 0.72")
  }
}


================================================
FILE: R/tidy.R
================================================
#' Various helpers for tidyverse.org and similar sites
#'
#' * `use_tidy_post()` makes a new post
#' * `use_tidy_thumbnails()` resizes thumbnails to the correct size
#' * `tidy_show_meta()` prints tags and categories used by existing posts.
#'
#' @export
#' @param slug File name of new post. Year and month will be automatically
#'   appended.
#' @inheritParams use_post
use_tidy_post <- function(slug, site = ".", open = is_interactive()) {
  check_slug(slug)

  post_slug <- paste0("blog/", tolower(slug))
  data <- list(
    pleased = tidy_pleased()
  )
  pieces <- strsplit(slug, "-")[[1]]
  if (is_installed(pieces[[1]])) {
    data$package <- pieces[[1]]
    data$version <- utils::packageVersion(pieces[[1]])
  }

  use_post(post_slug, data = data, site = site, open = open)
}

#' @rdname use_tidy_post
#' @export
#' @param path Path to blog post
use_tidy_thumbnails <- function(path = NULL) {
  if (!is_installed("magick")) {
    abort("Need to install magick package")
  }

  path <- path %||% path_dir(active_file())

  path_sq <- path(path, "thumbnail-sq.jpg")
  if (!file_exists(path_sq)) {
    abort("Can't find 'thumbnail-sq.jpg'")
  }
  path_wd <- path(path, "thumbnail-wd.jpg")
  if (!file_exists(path_wd)) {
    abort("Can't find 'thumbnail-wd.jpg'")
  }

  thumb_sq <- magick::image_read(path_sq)
  thumb_wd <- magick::image_read(path_wd)

  info_sq <- magick::image_info(thumb_sq)
  info_wd <- magick::image_info(thumb_wd)

  if (info_sq$width != info_sq$height) {
    abort("'thumbnail-sq.jpg' is not square")
  }
  if (info_wd$width / (info_wd$height / 200) < 1000) {
    abort("'thumbnail-wd.jpg' is too narrow; must be >5 wider than tall")
  }

  magick::image_write(magick::image_scale(thumb_sq, "300x300"), path_sq, quality = 90)
  magick::image_write(magick::image_scale(thumb_wd, "x200"), path_wd, quality = 90)

  invisible()
}

#' @rdname use_tidy_post
#' @export
#' @param min Minimum number of uses
tidy_show_meta <- function(min = 1, site = ".") {
  site <- site_root(site)
  rmd <- dir_ls(path(site, "content"), recurse = TRUE, regexp = "\\.(Rmd|Rmarkdown)$")

  yaml <- lapply(rmd, rmarkdown::yaml_front_matter)

  tags <- unlist(lapply(yaml, "[[", "tags"), use.names = FALSE)
  tags_df <- as.data.frame(table(tags), responseName = "n")
  tags_df <- tags_df[tags_df$n >= min, , drop = FALSE]

  cats <- unlist(lapply(yaml, "[[", "categories"), use.names = FALSE)
  cats_df <- as.data.frame(table(cats), responseName = "n")
  cats_df <- cats_df[cats_df$n >= min, , drop = FALSE]

  cat_line("## Categories")
  cat_line("* ", cats_df$cats, " (", cats_df$n, ")")
  cat_line()
  cat_line("## Tags")
  cat_line("* ", tags_df$tags, " (", tags_df$n, ")")

  invisible()
}


# helpers -----------------------------------------------------------------

check_slug <- function(slug) {
  if (!is.character(slug) || length(slug) != 1) {
    abort("`slug` must be a single string")
  }

  if (grepl("[ ._]", slug)) {
    abort(c(
      "`slug` must not contain any spaces, `.`, or `_`",
      i = "Separate words with -"
    ))
  }
}

unslug <- function(x) {
  gsub("-", " ", x)
}

tidy_pleased <- function() {
  phrases <- list(
    chuffed =     c(""),
    pleased =     c("", "most", "very", "extremely", "well"),
    stoked =      c(""),
    chuffed =     c("", "very"),
    happy =       c("", "so", "very", "exceedingly"),
    thrilled =    c(""),
    delighted =   c(""),
    "tickled pink" = c("")
  )

  i <- sample(length(phrases), 1)

  word <- names(phrases)[[i]]
  modifier <- sample(phrases[[i]], 1)

  paste0(modifier, if (modifier != "") " ", word)
}

active_file <- function(ext = NULL) {
  if (!is_installed("rstudioapi") || !rstudioapi::isAvailable()) {
    abort("Must supply `path` outside of RStudio")
  }

  path <- rstudioapi::getSourceEditorContext()$path

  if (!is.null(ext) && path_ext(path) != ext) {
    abort(paste0("Open file must have extension (", ext, ")"))
  }

  path
}

cat_line <- function(...) cat(paste0(..., "\n", collapse = ""))


================================================
FILE: R/utils.R
================================================
first_path <- function(paths) {
  for (path in paths) {
    if (file_exists(path)) {
      return(path)
    }
  }

  abort(c(
    "Can't find any of the following candidate paths",
    paths
  ))
}

# copies from withr
set_envvar <- function(envs, action = "replace") {
  if (length(envs) == 0) return()

  stopifnot(is_named(envs))
  stopifnot(is.character(action), length(action) == 1)
  action <- match.arg(action, c("replace", "prefix", "suffix"))

  # if there are duplicated entries keep only the last one
  envs <- envs[!duplicated(names(envs), fromLast = TRUE)]

  old <- Sys.getenv(names(envs), names = TRUE, unset = NA)
  set <- !is.na(envs)

  both_set <- set & !is.na(old)
  if (any(both_set)) {
    if (action == "prefix") {
      envs[both_set] <- paste(envs[both_set], old[both_set])
    } else if (action == "suffix") {
      envs[both_set] <- paste(old[both_set], envs[both_set])
    }
  }

  if (any(set))  do.call("Sys.setenv", as.list(envs[set]))
  if (any(!set)) Sys.unsetenv(names(envs)[!set])

  invisible(old)
}


# helpers for testing -----------------------------------------------------

xpath_xml <- function(x, xpath = ".") {
  x <- xml2::xml_find_all(x, xpath)
  structure(x, class = c("pkgdown_xml", class(x)))
}
xpath_attr <- function(x, xpath, attr) {
  gsub("\r", "", xml2::xml_attr(xml2::xml_find_all(x, xpath), attr), fixed = TRUE)
}
xpath_text <- function(x, xpath = ".", trim = FALSE) {
  xml2::xml_text(xml2::xml_find_all(x, xpath), trim = trim)
}
xpath_length <- function(x, xpath = ".") {
  length(xml2::xml_find_all(x, xpath))
}


================================================
FILE: README.md
================================================

# hugodown <img src='man/figures/logo.png' align="right" height="138.5" />

<!-- badges: start -->
[![Lifecycle: experimental](https://img.shields.io/badge/lifecycle-experimental-orange.svg)](https://www.tidyverse.org/lifecycle/#experimental)
[![R-CMD-check](https://github.com/r-lib/hugodown/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/r-lib/hugodown/actions/workflows/R-CMD-check.yaml)
[![Codecov test coverage](https://codecov.io/gh/r-lib/hugodown/branch/master/graph/badge.svg)](https://codecov.io/gh/r-lib/hugodown?branch=master)
<!-- badges: end -->

hugodown is an experimental package that aims to facilitate the use of [RMarkdown](http://rmarkdown.rstudio.com/) and [hugo](http://gohugo.io/) together. It's similar to [blogdown](https://bookdown.org/yihui/blogdown/), but is focussed purely on Hugo websites, and enforces a stricter partitioning of roles: hugodown is responsible for transforming `.Rmd` to `.md`, and hugo is responsible for transforming `.md` to `.html`.

## Compared to blogdown

* It only re-runs your R code when you explicitly ask for it (by knitting the 
  post). This makes hugodown considerably easier to use for long-running blogs 
  and blogs with multiple contributors. 
  
* Local previews are pinned to a specific version of hugo. This makes it easier
  to work with multiple blogs, and protects your from hugo <-> theme 
  version incompatibilities.
  
* It provides support for getting started with a limited number of themes,
  automatically making needed tweaks to ensure that html widgets, syntax 
  highlighting, and math display work out of the box.

* It does not currently support within page cross-references for figures, 
  tables, and equations.

* It is more opinionated about hugo configuration; see `vignette("config")` 
  for details.
  
* It is designed around a single Rmarkdown format, `.Rmd`.

## Installation

hugodown isn't available from CRAN yet (and might never be), but you can install the development version from GitHub with:

``` r
devtools::install_github("r-lib/hugodown")
```

## Usage

The key to using hugodown is to put `output: hugodown::md_document()` in the YAML metadata of your `.Rmd` files. Then knitting the file will generate a `.md` file designed to work well with hugo. The rest of hugodown just makes your life a little easier:

* `hugo_start()` will automatically start a hugo server in the background,
  automatically previewing your site as you update it.

* `use_post()` will create a new post (filling in default content from
  the hugo [archetype](https://gohugo.io/content-management/archetypes/)).
  
* To knit an `.Rmd` post, you can use the Knit button to knit to the correct output format. You can also use the keyboard shortcut `Cmd+Shift+K` (Mac) or `Ctrl+Shift+K` (Windows/Linux).
  
* `site_outdated()` lists all `.Rmd` files that need to be re-rendered 
  (i.e. they have changed since the last time their `.md` was rendered).
  
With hugodown, knitting an individual post and building the site are two separate processes. A good workflow when working with an existing Hugo site in RStudio is to open the site's `.Rproj` file, use `hugo_start()`, then add or edit your posts. Because the hugo server will only add `.Rmd` content to your site preview after knitting, you'll need to use the keyboard shortcut to knit first.

### Citations

To use citations in a blog post, just provide a `bibliography` in the YAML metadata. If you want to use footnotes for citations (a style that generally works well in blogs), you'll need to find a footnote style CSL file (e.g. [`chicago-fullnote-bibliography.csl`][footnote-csl], and use the following YAML header.

```yaml
bibliography: refs.bib
suppress-bibliography: true
csl: chicago-fullnote-bibliography.csl
```

## Converting from blogdown

* Make sure your post archetype has extension `.Rmd` and includes
  `output: hugodown::md_document` in the YAML. The post archetype
  should typically be `archetypes/blog/index.Rmd`.
  
* Delete `index.Rmd` from the root of your site.

* Ensure that hugo is configured as described in `vignette("config")`.

[yihui-mathjax]: https://yihui.org/en/2018/07/latex-math-markdown/ 
[tourmaline]: https://github.com/rstudio/hugo-tourmaline
[footer_mathjax]: https://github.com/rstudio/hugo-tourmaline/blob/master/layouts/partials/footer_mathjax.html
[footer]: https://github.com/rstudio/hugo-tourmaline/blob/master/layouts/partials/footer.html#L22
[math_code]: https://github.com/rstudio/hugo-tourmaline/blob/master/static/js/math-code.js
[styles]: https://xyproto.github.io/splash/docs/all.html
[footnote-csl]: https://github.com/citation-style-language/styles/blob/master/chicago-fullnote-bibliography.csl


================================================
FILE: _pkgdown.yml
================================================
url: https://hugodown.r-lib.org

template:
  params:
    ganalytics: UA-115082821-1


================================================
FILE: codecov.yml
================================================
comment: false

coverage:
  status:
    project:
      default:
        target: auto
        threshold: 1%
        informational: true
    patch:
      default:
        target: auto
        threshold: 1%
        informational: true


================================================
FILE: hugodown.Rproj
================================================
Version: 1.0

RestoreWorkspace: No
SaveWorkspace: No
AlwaysSaveHistory: Default

EnableCodeIndexing: Yes
UseSpacesForTab: Yes
NumSpacesForTab: 2
Encoding: UTF-8

RnwWeave: knitr
LaTeX: XeLaTeX

AutoAppendNewline: Yes
StripTrailingWhitespace: Yes
LineEndingConversion: Posix

BuildType: Package
PackageUseDevtools: Yes
PackageInstallArgs: --no-multiarch --with-keep.source
PackageRoxygenize: rd,collate,namespace


================================================
FILE: inst/academic/README.md
================================================
This is a [hugo](http://gohugo.io/) [academic](https://sourcethemes.com/academic) created by [hugodown](http://hugodown.r-lib.org/).

## Basic operation

* Preview the site with `hugodown::hugo_start()`; it will automatically
  update (navigating to the latest change) as you modify `content/`.

* Create a new post bundle with `hugodown::use_post('post/short-title')`.


================================================
FILE: inst/academic/highlight-dark.css
================================================
/* Background */ .chroma { color: #f8f8f2; background-color: #282a36 }
/* Other */ .chroma .x {  }
/* Error */ .chroma .err {  }
/* LineTableTD */ .chroma .lntd { vertical-align: top; padding: 0; margin: 0; border: 0; }
/* LineTable */ .chroma .lntable { border-spacing: 0; padding: 0; margin: 0; border: 0; width: auto; overflow: auto; display: block; }
/* LineHighlight */ .chroma .hl { display: block; width: 100%;background-color: #ffffcc }
/* LineNumbersTable */ .chroma .lnt { margin-right: 0.4em; padding: 0 0.4em 0 0.4em;color: #7f7f7f }
/* LineNumbers */ .chroma .ln { margin-right: 0.4em; padding: 0 0.4em 0 0.4em;color: #7f7f7f }
/* Keyword */ .chroma .k { color: #ff79c6 }
/* KeywordConstant */ .chroma .kc { color: #ff79c6 }
/* KeywordDeclaration */ .chroma .kd { color: #8be9fd; font-style: italic }
/* KeywordNamespace */ .chroma .kn { color: #ff79c6 }
/* KeywordPseudo */ .chroma .kp { color: #ff79c6 }
/* KeywordReserved */ .chroma .kr { color: #ff79c6 }
/* KeywordType */ .chroma .kt { color: #8be9fd }
/* Name */ .chroma .n {  }
/* NameAttribute */ .chroma .na { color: #50fa7b }
/* NameBuiltin */ .chroma .nb { color: #8be9fd; font-style: italic }
/* NameBuiltinPseudo */ .chroma .bp {  }
/* NameClass */ .chroma .nc { color: #50fa7b }
/* NameConstant */ .chroma .no {  }
/* NameDecorator */ .chroma .nd {  }
/* NameEntity */ .chroma .ni {  }
/* NameException */ .chroma .ne {  }
/* NameFunction */ .chroma .nf { color: #50fa7b }
/* NameFunctionMagic */ .chroma .fm {  }
/* NameLabel */ .chroma .nl { color: #8be9fd; font-style: italic }
/* NameNamespace */ .chroma .nn {  }
/* NameOther */ .chroma .nx {  }
/* NameProperty */ .chroma .py {  }
/* NameTag */ .chroma .nt { color: #ff79c6 }
/* NameVariable */ .chroma .nv { color: #8be9fd; font-style: italic }
/* NameVariableClass */ .chroma .vc { color: #8be9fd; font-style: italic }
/* NameVariableGlobal */ .chroma .vg { color: #8be9fd; font-style: italic }
/* NameVariableInstance */ .chroma .vi { color: #8be9fd; font-style: italic }
/* NameVariableMagic */ .chroma .vm {  }
/* Literal */ .chroma .l {  }
/* LiteralDate */ .chroma .ld {  }
/* LiteralString */ .chroma .s { color: #f1fa8c }
/* LiteralStringAffix */ .chroma .sa { color: #f1fa8c }
/* LiteralStringBacktick */ .chroma .sb { color: #f1fa8c }
/* LiteralStringChar */ .chroma .sc { color: #f1fa8c }
/* LiteralStringDelimiter */ .chroma .dl { color: #f1fa8c }
/* LiteralStringDoc */ .chroma .sd { color: #f1fa8c }
/* LiteralStringDouble */ .chroma .s2 { color: #f1fa8c }
/* LiteralStringEscape */ .chroma .se { color: #f1fa8c }
/* LiteralStringHeredoc */ .chroma .sh { color: #f1fa8c }
/* LiteralStringInterpol */ .chroma .si { color: #f1fa8c }
/* LiteralStringOther */ .chroma .sx { color: #f1fa8c }
/* LiteralStringRegex */ .chroma .sr { color: #f1fa8c }
/* LiteralStringSingle */ .chroma .s1 { color: #f1fa8c }
/* LiteralStringSymbol */ .chroma .ss { color: #f1fa8c }
/* LiteralNumber */ .chroma .m { color: #bd93f9 }
/* LiteralNumberBin */ .chroma .mb { color: #bd93f9 }
/* LiteralNumberFloat */ .chroma .mf { color: #bd93f9 }
/* LiteralNumberHex */ .chroma .mh { color: #bd93f9 }
/* LiteralNumberInteger */ .chroma .mi { color: #bd93f9 }
/* LiteralNumberIntegerLong */ .chroma .il { color: #bd93f9 }
/* LiteralNumberOct */ .chroma .mo { color: #bd93f9 }
/* Operator */ .chroma .o { color: #ff79c6 }
/* OperatorWord */ .chroma .ow { color: #ff79c6 }
/* Punctuation */ .chroma .p {  }
/* Comment */ .chroma .c { color: #6272a4 }
/* CommentHashbang */ .chroma .ch { color: #6272a4 }
/* CommentMultiline */ .chroma .cm { color: #6272a4 }
/* CommentSingle */ .chroma .c1 { color: #6272a4 }
/* CommentSpecial */ .chroma .cs { color: #6272a4 }
/* CommentPreproc */ .chroma .cp { color: #ff79c6 }
/* CommentPreprocFile */ .chroma .cpf { color: #ff79c6 }
/* Generic */ .chroma .g {  }
/* GenericDeleted */ .chroma .gd { color: #8b080b }
/* GenericEmph */ .chroma .ge { text-decoration: underline }
/* GenericError */ .chroma .gr {  }
/* GenericHeading */ .chroma .gh { font-weight: bold }
/* GenericInserted */ .chroma .gi { font-weight: bold }
/* GenericOutput */ .chroma .go { color: #44475a }
/* GenericPrompt */ .chroma .gp {  }
/* GenericStrong */ .chroma .gs {  }
/* GenericSubheading */ .chroma .gu { font-weight: bold }
/* GenericTraceback */ .chroma .gt {  }
/* GenericUnderline */ .chroma .gl { text-decoration: underline }
/* TextWhitespace */ .chroma .w {  }


================================================
FILE: inst/academic/highlight-light.css
================================================
/* Background */ .chroma { background-color: #ffffff }
/* Other */ .chroma .x {  }
/* Error */ .chroma .err { color: #a61717; background-color: #e3d2d2 }
/* LineTableTD */ .chroma .lntd { vertical-align: top; padding: 0; margin: 0; border: 0; }
/* LineTable */ .chroma .lntable { border-spacing: 0; padding: 0; margin: 0; border: 0; width: auto; overflow: auto; display: block; }
/* LineHighlight */ .chroma .hl { display: block; width: 100%;background-color: #ffffcc }
/* LineNumbersTable */ .chroma .lnt { margin-right: 0.4em; padding: 0 0.4em 0 0.4em;color: #7f7f7f }
/* LineNumbers */ .chroma .ln { margin-right: 0.4em; padding: 0 0.4em 0 0.4em;color: #7f7f7f }
/* Keyword */ .chroma .k { color: #000000; font-weight: bold }
/* KeywordConstant */ .chroma .kc { color: #000000; font-weight: bold }
/* KeywordDeclaration */ .chroma .kd { color: #000000; font-weight: bold }
/* KeywordNamespace */ .chroma .kn { color: #000000; font-weight: bold }
/* KeywordPseudo */ .chroma .kp { color: #000000; font-weight: bold }
/* KeywordReserved */ .chroma .kr { color: #000000; font-weight: bold }
/* KeywordType */ .chroma .kt { color: #445588; font-weight: bold }
/* Name */ .chroma .n {  }
/* NameAttribute */ .chroma .na { color: #008080 }
/* NameBuiltin */ .chroma .nb { color: #0086b3 }
/* NameBuiltinPseudo */ .chroma .bp { color: #999999 }
/* NameClass */ .chroma .nc { color: #445588; font-weight: bold }
/* NameConstant */ .chroma .no { color: #008080 }
/* NameDecorator */ .chroma .nd { color: #3c5d5d; font-weight: bold }
/* NameEntity */ .chroma .ni { color: #800080 }
/* NameException */ .chroma .ne { color: #990000; font-weight: bold }
/* NameFunction */ .chroma .nf { color: #990000; font-weight: bold }
/* NameFunctionMagic */ .chroma .fm {  }
/* NameLabel */ .chroma .nl { color: #990000; font-weight: bold }
/* NameNamespace */ .chroma .nn { color: #555555 }
/* NameOther */ .chroma .nx {  }
/* NameProperty */ .chroma .py {  }
/* NameTag */ .chroma .nt { color: #000080 }
/* NameVariable */ .chroma .nv { color: #008080 }
/* NameVariableClass */ .chroma .vc { color: #008080 }
/* NameVariableGlobal */ .chroma .vg { color: #008080 }
/* NameVariableInstance */ .chroma .vi { color: #008080 }
/* NameVariableMagic */ .chroma .vm {  }
/* Literal */ .chroma .l {  }
/* LiteralDate */ .chroma .ld {  }
/* LiteralString */ .chroma .s { color: #dd1144 }
/* LiteralStringAffix */ .chroma .sa { color: #dd1144 }
/* LiteralStringBacktick */ .chroma .sb { color: #dd1144 }
/* LiteralStringChar */ .chroma .sc { color: #dd1144 }
/* LiteralStringDelimiter */ .chroma .dl { color: #dd1144 }
/* LiteralStringDoc */ .chroma .sd { color: #dd1144 }
/* LiteralStringDouble */ .chroma .s2 { color: #dd1144 }
/* LiteralStringEscape */ .chroma .se { color: #dd1144 }
/* LiteralStringHeredoc */ .chroma .sh { color: #dd1144 }
/* LiteralStringInterpol */ .chroma .si { color: #dd1144 }
/* LiteralStringOther */ .chroma .sx { color: #dd1144 }
/* LiteralStringRegex */ .chroma .sr { color: #009926 }
/* LiteralStringSingle */ .chroma .s1 { color: #dd1144 }
/* LiteralStringSymbol */ .chroma .ss { color: #990073 }
/* LiteralNumber */ .chroma .m { color: #009999 }
/* LiteralNumberBin */ .chroma .mb { color: #009999 }
/* LiteralNumberFloat */ .chroma .mf { color: #009999 }
/* LiteralNumberHex */ .chroma .mh { color: #009999 }
/* LiteralNumberInteger */ .chroma .mi { color: #009999 }
/* LiteralNumberIntegerLong */ .chroma .il { color: #009999 }
/* LiteralNumberOct */ .chroma .mo { color: #009999 }
/* Operator */ .chroma .o { color: #000000; font-weight: bold }
/* OperatorWord */ .chroma .ow { color: #000000; font-weight: bold }
/* Punctuation */ .chroma .p {  }
/* Comment */ .chroma .c { color: #999988; font-style: italic }
/* CommentHashbang */ .chroma .ch { color: #999988; font-style: italic }
/* CommentMultiline */ .chroma .cm { color: #999988; font-style: italic }
/* CommentSingle */ .chroma .c1 { color: #999988; font-style: italic }
/* CommentSpecial */ .chroma .cs { color: #999999; font-weight: bold; font-style: italic }
/* CommentPreproc */ .chroma .cp { color: #999999; font-weight: bold; font-style: italic }
/* CommentPreprocFile */ .chroma .cpf { color: #999999; font-weight: bold; font-style: italic }
/* Generic */ .chroma .g {  }
/* GenericDeleted */ .chroma .gd { color: #000000; background-color: #ffdddd }
/* GenericEmph */ .chroma .ge { color: #000000; font-style: italic }
/* GenericError */ .chroma .gr { color: #aa0000 }
/* GenericHeading */ .chroma .gh { color: #999999 }
/* GenericInserted */ .chroma .gi { color: #000000; background-color: #ddffdd }
/* GenericOutput */ .chroma .go { color: #888888 }
/* GenericPrompt */ .chroma .gp { color: #555555 }
/* GenericStrong */ .chroma .gs { font-weight: bold }
/* GenericSubheading */ .chroma .gu { color: #aaaaaa }
/* GenericTraceback */ .chroma .gt { color: #aa0000 }
/* GenericUnderline */ .chroma .gl { text-decoration: underline }
/* TextWhitespace */ .chroma .w { color: #bbbbbb }


================================================
FILE: inst/academic/index.Rmd
================================================
---
site: hugodown:::hugodown_site
---


================================================
FILE: inst/templates/netlify.toml
================================================
[build]
  publish = "public"
  command = "hugo"

[build.environment]
  HUGO_VERSION = "{{hugo_version}}"
  HUGO_BUILDFUTURE = "true"

[context.deploy-preview.environment]
  command = "hugo --baseURL $DEPLOY_PRIME_URL"


================================================
FILE: inst/templates/template.Rproj
================================================
Version: 1.0

RestoreWorkspace: No
SaveWorkspace: No
AlwaysSaveHistory: Default

EnableCodeIndexing: Yes
UseSpacesForTab: Yes
NumSpacesForTab: 2
Encoding: UTF-8

RnwWeave: Sweave
LaTeX: pdfLaTeX

AutoAppendNewline: Yes
StripTrailingWhitespace: Yes
LineEndingConversion: Posix

BuildType: Website


================================================
FILE: man/create_site_academic.Rd
================================================
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/site-academic.R
\name{create_site_academic}
\alias{create_site_academic}
\title{Create a hugo academic site}
\usage{
create_site_academic(
  path = ".",
  open = is_interactive(),
  rstudio = rstudioapi::isAvailable()
)
}
\arguments{
\item{path}{Path to create site}

\item{open}{Open new site after creation?}

\item{rstudio}{Create RStudio project?}
}
\description{
Create a hugo academic 4.8.0 site, configured to work well with hugodown.
In particular, it ensures that the following features important for R
users work correctly:
\itemize{
\item Syntax highlighting (turns off default js highlighting, renables
default chroma, and sets up styles in \code{assets/chroma.css}).
\item Math
\item HTML widgets
\item Default post archetype is tweaked to create \code{.Rmd}
}
}


================================================
FILE: man/embed_gist.Rd
================================================
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/shortcode.R
\name{embed_gist}
\alias{embed_gist}
\alias{embed_instagram}
\alias{embed_tweet}
\alias{embed_vimeo}
\alias{embed_youtube}
\title{Generate hugo shortcodes to embed various types of media}
\usage{
embed_gist(username, id, filename = NULL)

embed_instagram(id, caption = TRUE)

embed_tweet(id, username = NULL)

embed_vimeo(id)

embed_youtube(id, autoplay = FALSE)
}
\arguments{
\item{username}{GitHub/Twitter user name}

\item{id}{A string giving the object id. You'll usually find this by
inspecting the URL:
\itemize{
\item gist: \verb{https://gist.github.com/spf13/7896402} -> \code{7896402}
\item instagram: \verb{https://www.instagram.com/p/BWNjjyYFxVx/} -> \code{BWNjjyYFxVx}
\item twitter: \verb{https://twitter.com/spf13/status/877500564405444608} -> \code{877500564405444608}
\item vimeo: \verb{https://vimeo.com/channels/staffpicks/146022717} -> \code{146022717}
\item youtube: \verb{https://www.youtube.com/watch?v=w7Ft2ymGmfc} -> \code{w7Ft2ymGmfc}
}}

\item{filename}{Pick single file from multiple file gist}

\item{caption}{Show instagram caption?}

\item{autoplay}{Automatically play youtube video?}
}
\description{
These are wrappers that make it easy to generate
\href{https://gohugo.io/content-management/shortcodes/}{hugo shortcodes} that
make it easy to embed various types of media into your pages. You use from
inline R code like:

\if{html}{\out{<div class="sourceCode">}}\preformatted{This tweet announced the release of hugo 0.24:

`R embed_tweet("877500564405444608")`
}\if{html}{\out{</div>}}
}


================================================
FILE: man/hugo_build.Rd
================================================
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/hugo-server.R
\name{hugo_build}
\alias{hugo_build}
\title{Build site}
\usage{
hugo_build(
  site = ".",
  dest = NULL,
  build_drafts = FALSE,
  build_future = FALSE,
  clean = FALSE,
  base_url = NULL,
  relative_urls = NULL
)
}
\arguments{
\item{site}{Path to hugo site.}

\item{dest}{Destination directory. If \code{NULL}, the default, will build
in \code{{site}/public}}

\item{build_drafts, build_future}{Should drafts and future posts be included
in the built site?}

\item{clean}{Remove files in \verb{public/} that don't exist in the source.}

\item{base_url}{\verb{<string>} Optionally override the \code{baseURL} setting from
hugo config.}

\item{relative_urls}{\verb{<bool>} Optionally the override the \code{relativeURL}
setting from hugo config.}
}
\description{
Build static html into specified directory. Useful for debugging and some
deployment scenarios
}


================================================
FILE: man/hugo_document.Rd
================================================
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/md-document.R
\name{hugo_document}
\alias{hugo_document}
\title{Deprecated: please use \code{md_document()}}
\usage{
hugo_document(
  fig_width = 7,
  fig_asp = 0.618,
  fig_retina = 2,
  tidyverse_style = TRUE
)
}
\description{
Deprecated: please use \code{md_document()}
}
\keyword{internal}


================================================
FILE: man/hugo_install.Rd
================================================
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/hugo-install.R
\name{hugo_install}
\alias{hugo_install}
\title{Install specified version of hugo}
\usage{
hugo_install(version = NULL, os = hugo_os(), arch = "64bit", extended = TRUE)
}
\arguments{
\item{version}{String giving version (e.g. "0.69.0"). If omitted will
default to latest release.}

\item{os}{Operating system, one of "Linux", "Windows", "macOS". Defaults
to current operating system.}

\item{arch}{Architecture}

\item{extended}{Installed hugo-extended which also includes SCSS etc?}
}
\description{
Downloads binary from hugo releases, and installs in system wide cache.
}
\examples{
\dontrun{
hugo_install()
}
}


================================================
FILE: man/hugo_locate.Rd
================================================
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/hugo.R
\name{hugo_locate}
\alias{hugo_locate}
\title{Locates a specific Hugo installation}
\usage{
hugo_locate(version = hugo_default_get())
}
\arguments{
\item{version}{The Hugo version to be located}
}
\value{
Returns the path to the Hugo installation, or an error if no
Hugo install is found
}
\description{
Locates a specific Hugo installation
}


================================================
FILE: man/hugo_start.Rd
================================================
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/hugo-server.R
\name{hugo_start}
\alias{hugo_start}
\alias{hugo_stop}
\alias{hugo_browse}
\title{Manage the hugo server}
\usage{
hugo_start(
  site = ".",
  auto_navigate = TRUE,
  browse = TRUE,
  render_to_disk = FALSE,
  port = 1313
)

hugo_stop()

hugo_browse()
}
\arguments{
\item{site}{Path to hugo site.}

\item{auto_navigate}{Automatically navigate to the most recently changed
page?}

\item{browse}{Automatically preview the site after the server starts?}

\item{render_to_disk}{Render site to disk? The default is to serve the
site from memory, but rendering to disk can be helpful for debugging.}

\item{port}{Port to run server on. For advanced use only.}
}
\description{
\code{hugo_start()} starts a hugo server that will automatically re-generate
the site whenever the input changes. You only need to execute this once
per session; it continues to run in the background as you work on the site.
For large sites the hugo server can be slow to start; if it takes longer
than 30 seconds \code{hugo_start()} throws an error.

\code{hugo_stop()} kills the server. This happens automatically when you exit
R so you shouldn't normally need to run this.

\code{hugo_browse()} opens the site in the RStudio viewer or your web browser.
}
\section{Hugo version}{

hugodown will attempt to automatically use the correct version of hugo for
your site (prompting you to call \code{\link[=hugo_install]{hugo_install()}} if needed). It looks in
two places:
\itemize{
\item If \verb{_hugodown.yaml} is present, it looks for the \code{hugo_version} key.
\item If \code{netlify.toml} is present, it looks in
\code{context$production$environment$HUGO_VERSION}
}

This means if you already use netlify, hugodown will automatically match
the version of hugo that you're using for deployment.
}



================================================
FILE: man/hugo_version.Rd
================================================
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/hugo-version.R
\name{hugo_version}
\alias{hugo_version}
\title{Find hugo version needed for current site}
\usage{
hugo_version(site = ".")
}
\arguments{
\item{site}{Path to hugo site.}
}
\description{
Hugo changes rapidly, so it's important to pin your site to a specific
version and then deliberately update when needed. This function reports
which of hugo your site correctly uses.

The primary location of this information is the \code{hugo_version} field
in \code{hugodown.yaml}. If that doesn't exist, we also look in \code{netlify.toml}.
}
\seealso{
\code{\link[=hugo_install]{hugo_install()}} to install any version of hugo.
}


================================================
FILE: man/hugodown-package.Rd
================================================
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/hugodown-package.R
\docType{package}
\name{hugodown-package}
\alias{hugodown}
\alias{hugodown-package}
\title{hugodown: Make websites with hugo and RMarkdown}
\description{
\if{html}{\figure{logo.png}{options: style='float: right' alt='logo' width='120'}}

hugodown is a minimal version of blogdown that only supports hugo, and more clearly delineates the roles of RMarkdown (turning .Rmd into .md) and hugo (turning .md into .html).
}
\seealso{
Useful links:
\itemize{
  \item \url{https://github.com/r-lib/hugodown}
  \item Report bugs at \url{https://github.com/r-lib/hugodown/issues}
}

}
\author{
\strong{Maintainer}: Hadley Wickham \email{hadley@rstudio.com}

Other contributors:
\itemize{
  \item RStudio [copyright holder]
}

}
\keyword{internal}


================================================
FILE: man/md_document.Rd
================================================
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/md-document.R
\name{md_document}
\alias{md_document}
\title{An Rmd output format that produces Hugo-flavoured markdown}
\usage{
md_document(
  fig_width = 7,
  fig_asp = 0.618,
  fig_retina = 2,
  tidyverse_style = TRUE
)
}
\arguments{
\item{fig_width}{Figure width (in inches).}

\item{fig_asp}{Figure aspect ratio, defaults to the golden ratio.}

\item{fig_retina}{Scaling to perform for retina displays. Defaults to
\code{NULL} which performs no scaling. A setting of 2 will work for all
widely used retina displays, but will also result in the output of
\verb{<img>} tags rather than markdown images due to the need to set the
width of the image explicitly.}

\item{tidyverse_style}{Use tidyverse knitr conventions? This sets
\code{collapse = TRUE}, \verb{comment = "#>}, \code{fig.align = "center"}, and
\code{out.width = "700px"}.}
}
\description{
This RMarkdown output format is designed to generate markdown that is
maximally compatible with Hugo. It intelligently generates a preview so
that you see something useful when Hugo isn't running, but it doesn't
get in the way of hugo's full-site preview when it is.
}
\section{Syntax highlighting}{


\code{md_document()} uses a hybrid system for syntax highlighting.
For R code it uses \href{http://github.com/r-lib/downlit}{downlit}. For
other languages, it relies on Chroma, the syntax highlighter built into
hugo.
}



================================================
FILE: man/shortcode.Rd
================================================
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/shortcode.R
\name{shortcode}
\alias{shortcode}
\title{Generate a hugo shortcode}
\usage{
shortcode(
  .name,
  ...,
  .contents = NULL,
  .output = c("html", "md"),
  .inline = FALSE
)
}
\arguments{
\item{.name}{Name of the shortcode}

\item{...}{Arguments to the shortcode, supplied either by name or
position depending on the shortcode. By default, strings will
automatically be quoted with single quotes. Suppress this quoting
by wrapping the argument in \code{I()}.}

\item{.contents}{Contents of the shortcode for paired shortcodes.}

\item{.output}{Is the output of the shortcode html or markdown? This
controls whether the shortcode uses \verb{<>} or \verb{\%}.}

\item{.inline}{Is the shortcode designed to be used inline or in its own
paragraph? Controls whether the shortcode is wrapped in a block or inline
\href{https://pandoc.org/MANUAL.html#extension-raw_attribute}{raw attribute}.}
}
\description{
Generate a hugo shortcode with appropriate pandoc markup to preserve it as
is when embedded in an R markdown document.

Generally, I don't recommend calling this function directly; instead
use it inside a function with the same name as the shortcode you want to
wrap. See \code{\link[=embed_gist]{embed_gist()}} and friends for examples
}
\examples{
pkg <- function(name) {
  shortcode("pkg", name, .inline = TRUE)
}
pkg("hugodown")
}


================================================
FILE: man/site_outdated.Rd
================================================
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/site.R
\name{site_outdated}
\alias{site_outdated}
\title{Find \code{.Rmd}s that need to be re-rendered.}
\usage{
site_outdated(site = ".")
}
\arguments{
\item{site}{Path to hugo site.}
}
\description{
\code{\link[=md_document]{md_document()}} adds a hash of the input \code{.Rmd} in the YAML metdata of
the \code{.md} file that it creates. This provides a reliable way to determine
whether or not a \code{.Rmd} has been changed since the last time the \code{.md}
was rendered.
}


================================================
FILE: man/use_netlify_toml.Rd
================================================
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/netlify.R
\name{use_netlify_toml}
\alias{use_netlify_toml}
\title{Create \code{netlify.toml}}
\usage{
use_netlify_toml(site = ".")
}
\arguments{
\item{site}{Path to the hugo site.}
}
\description{
This helper creates a basic \code{netlify.toml} file, automatically setting the
hugo version to match your blog. This is needed when publishing your site
with \href{https://www.netlify.com}{netlify}; see \code{vignette("deploy")} for more
details.
}


================================================
FILE: man/use_post.Rd
================================================
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/post.R
\name{use_post}
\alias{use_post}
\title{Create a new post}
\usage{
use_post(path, kind = NULL, data = list(), site = ".", open = is_interactive())
}
\arguments{
\item{path}{Directory to create, like \code{blog/2020-my-favourite-package}.}

\item{kind}{Kind of archetype of use; usually automatically derived
from the base directory of \code{path}.}

\item{data}{Any additional data to be used when templating \code{.Rmd} files.

The default data includes:
\itemize{
\item \code{date}: today's date (in YYYY-MM-DD format).
\item \code{author}: \code{\link[whoami:fullname]{whoami::fullname()}}.
\item \code{slug}: taken from the file name of \code{path}.
}}

\item{site}{Path to the hugo site.}

\item{open}{Open file for interactive editing?}
}
\description{
Post creation takes advantage of Hugo's
\href{https://gohugo.io/content-management/archetypes/}{archetypes} or templates,
with an extension for \code{.Rmd} files. \code{use_post()} first calls \verb{hugo new}
(which will apply go templating to \code{.md} files in the archetype),
and then uses \href{https://github.com/edwindj/whisker}{whisker} to template
any \code{.Rmd} files.
}


================================================
FILE: man/use_tidy_post.Rd
================================================
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/tidy.R
\name{use_tidy_post}
\alias{use_tidy_post}
\alias{use_tidy_thumbnails}
\alias{tidy_show_meta}
\title{Various helpers for tidyverse.org and similar sites}
\usage{
use_tidy_post(slug, site = ".", open = is_interactive())

use_tidy_thumbnails(path = NULL)

tidy_show_meta(min = 1, site = ".")
}
\arguments{
\item{slug}{File name of new post. Year and month will be automatically
appended.}

\item{site}{Path to the hugo site.}

\item{open}{Open file for interactive editing?}

\item{path}{Path to blog post}

\item{min}{Minimum number of uses}
}
\description{
\itemize{
\item \code{use_tidy_post()} makes a new post
\item \code{use_tidy_thumbnails()} resizes thumbnails to the correct size
\item \code{tidy_show_meta()} prints tags and categories used by existing posts.
}
}


================================================
FILE: tests/testthat/.gitignore
================================================
knit-hooks_files


================================================
FILE: tests/testthat/_snaps/md-document.md
================================================
# interweaving of code and output generates correct html

    ---
    output: hugodown::md_document
    rmd_hash: 51bc60383311007d
    
    ---
    
    ## Mixed as_is and coode
    
    <div class="highlight">
    
    <pre class='chroma'><code class='language-r' data-lang='r'><span><span class='nv'>df</span> <span class='o'>&lt;-</span> <span class='nf'><a href='https://rdrr.io/r/base/data.frame.html'>data.frame</a></span><span class='o'>(</span>x <span class='o'>=</span> <span class='m'>1</span><span class='o'>)</span></span>
    <span><span class='nv'>df</span></span>
    <span><span class='c'>#&gt;   x</span></span>
    <span><span class='c'>#&gt; 1 1</span></span>
    <span></span><span></span>
    <span><span class='nf'>knitr</span><span class='nf'>::</span><span class='nf'><a href='https://rdrr.io/pkg/knitr/man/kable.html'>kable</a></span><span class='o'>(</span><span class='nv'>df</span><span class='o'>)</span></span>
    </code></pre>
    
    |   x |
    |----:|
    |   1 |
    
    </div>
    
    ## All code/output
    
    <div class="highlight">
    
    <pre class='chroma'><code class='language-r' data-lang='r'><span><span class='c'># comment</span></span>
    <span><span class='nf'><a href='https://rdrr.io/r/base/print.html'>print</a></span><span class='o'>(</span><span class='s'>"print"</span><span class='o'>)</span></span>
    <span><span class='c'>#&gt; [1] "print"</span></span>
    <span></span><span><span class='nf'><a href='https://rdrr.io/r/base/message.html'>message</a></span><span class='o'>(</span><span class='s'>"message"</span><span class='o'>)</span></span>
    <span><span class='c'>#&gt; message</span></span>
    <span></span><span><span class='kr'><a href='https://rdrr.io/r/base/warning.html'>warning</a></span><span class='o'>(</span><span class='s'>"warning"</span><span class='o'>)</span></span>
    <span><span class='c'>#&gt; Warning: warning</span></span>
    <span></span></code></pre>
    
    </div>
    
    ## Chunk with only a figure
    
    <div class="highlight">
    
    <img src="figs/unnamed-chunk-3-1.png" width="700px" style="display: block; margin: auto;" />
    
    </div>
    



================================================
FILE: tests/testthat/archetypes/_hugodown.yaml
================================================
hugo_version: 0.72.0


================================================
FILE: tests/testthat/archetypes/archetypes/Rmd/index.Rmd
================================================
---
slug: {{ slug }}
---


================================================
FILE: tests/testthat/archetypes/archetypes/blog/index.Rmd
================================================
---
slug: {{ slug }}
package: {{ package }}
---


================================================
FILE: tests/testthat/archetypes/archetypes/md/index.md
================================================
---
slug: {{ .Name }}
title: "{{ replace .Name "-" " " | title }}"
---


================================================
FILE: tests/testthat/archetypes/config.yml
================================================


================================================
FILE: tests/testthat/code-invalid.Rmd
================================================
---
output: hugodown::md_document
---

```{r, eval = FALSE}
1 + 
```


================================================
FILE: tests/testthat/code.Rmd
================================================
---
output: hugodown::md_document
---

```{r}
1 + 1
```

`stats::median()`

```{r, error = TRUE}
print("print")
message("message")
# comment
warning("warning")
stop("error!")
plot(1 + 1)
```


================================================
FILE: tests/testthat/config-hugodown/_hugodown.yaml
================================================
test: true
hugo_version: 0.66.0


================================================
FILE: tests/testthat/config-hugodown/config.yaml
================================================


================================================
FILE: tests/testthat/config-toml/config.toml
================================================


================================================
FILE: tests/testthat/config-yaml/config.yaml
================================================


================================================
FILE: tests/testthat/config-yml/config.yml
================================================


================================================
FILE: tests/testthat/curly.Rmd
================================================
---
output: hugodown::md_document
---

```{r, eval = FALSE}
{{ curly }}
```


================================================
FILE: tests/testthat/div.Rmd
================================================
---
output: hugodown::md_document
---

:::special
This is special
:::


================================================
FILE: tests/testthat/emoji.Rmd
================================================
---
output: hugodown::md_document
---

:smile_cat:


================================================
FILE: tests/testthat/error.Rmd
================================================
---
output: hugodown::md_document
---

```{r}
stop("Failure")
```



================================================
FILE: tests/testthat/knit-hooks.Rmd
================================================
---
output: hugodown::md_document
---

## Mixed as_is and coode

```{r}
df <- data.frame(x = 1)
df

knitr::kable(df)
```


## All code/output

```{r}
# comment
print("print")
message("message")
warning("warning")
```

## Chunk with only a figure

```{r, echo = FALSE}
plot(1:5)
```


================================================
FILE: tests/testthat/math.Rmd
================================================
---
output: hugodown::md_document
---

$a_1 + b_2$


================================================
FILE: tests/testthat/meta.Rmd
================================================
---
author: Hadley
output: hugodown::md_document
# this is a comment
---


================================================
FILE: tests/testthat/minimal/.gitignore
================================================
public


================================================
FILE: tests/testthat/minimal/LICENSE
================================================
License
=========

This project is licensed under the terms of the MIT License describe below.

Copyright (c) 2017 Arun Ravindran

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.

================================================
FILE: tests/testthat/minimal/README.md
================================================
Minimal site created for Hugo, a static site generator

Read the tutorial at http://arunrocks.com for more details.


================================================
FILE: tests/testthat/minimal/_hugodown.yaml
================================================
hugo_version: 0.72.0


================================================
FILE: tests/testthat/minimal/config.toml
================================================
baseURL = "http://example.org/"
theme = "bare"

================================================
FILE: tests/testthat/minimal/content/_index.md
================================================
+++
title = "Home page"
+++

This page has **bold** and *italics* formatting.


================================================
FILE: tests/testthat/minimal/themes/bare/layouts/index.html
================================================
<html>
  <body>
    <h1>Welcome!</h1>
    
    <h2>{{ .Title }}</h2>
    {{ .Content }}

  </body>
</html>


================================================
FILE: tests/testthat/minimal/themes/bare/theme.toml
================================================
name = "Bare"
license = "MIT"


================================================
FILE: tests/testthat/outdated/config.yml
================================================


================================================
FILE: tests/testthat/outdated/content/blog/_index.md
================================================
---
title: Blog
---


================================================
FILE: tests/testthat/outdated/content/blog/ok-has-html/index.Rmd
================================================
---
title: This post is out of date
output: hugodown::md_document
---

Text


================================================
FILE: tests/testthat/outdated/content/blog/ok-has-html/index.html
================================================


================================================
FILE: tests/testthat/outdated/content/blog/ok-no-hash/index.Rmd
================================================
---
title: This post is out of date
output: hugodown::md_document
---

Text


================================================
FILE: tests/testthat/outdated/content/blog/ok-no-hash/index.md
================================================
---
title: This post is out of date
output: hugodown::md_document

---

Text



================================================
FILE: tests/testthat/outdated/content/blog/outdated-no-md/index.Rmd
================================================
---
title: This post is out of date
output: hugodown::md_document
---



================================================
FILE: tests/testthat/outdated/content/blog/outdated-old-hash/index.Rmd
================================================
---
title: This post is out of date
output: hugodown::md_document
---

Text


================================================
FILE: tests/testthat/outdated/content/blog/outdated-old-hash/index.md
================================================
---
title: This post is out of date
output: hugodown::md_document
rmd_hash: wrong

---

Text



================================================
FILE: tests/testthat/output.Rmd
================================================
---
output: hugodown::md_document
---

```{r, echo = FALSE}
cat(cli::col_blue("blue"))
cat(cli::symbol$tick)
```


================================================
FILE: tests/testthat/plot.Rmd
================================================
---
output: hugodown::md_document
---

```{r, echo = FALSE}
plot(1:5, 1:5)
```

```{r, echo = FALSE, out.width="50%"}
plot(1:5, 1:5)
```


================================================
FILE: tests/testthat/raw-html.Rmd
================================================
---
output: hugodown::md_document
---

```{=html}
<raw>
```

This is `<raw>`{=html}


================================================
FILE: tests/testthat/table.Rmd
================================================
---
output: hugodown::md_document
---

                 mpg   cyl 
--------------  ----  ---- 
Mazda RX4         21     6 
Mazda RX4 Wag     21     6 


================================================
FILE: tests/testthat/test-hugo-install.R
================================================
test_that("can retrieve download urls", {
  skip_on_cran()

  expect_equal(
    hugo_release("0.69.0", "Linux")$url,
    "https://github.com/gohugoio/hugo/releases/download/v0.69.0/hugo_extended_0.69.0_Linux-64bit.tar.gz"
  )

  expect_error(hugo_release("foo", "Linux"), "Can't find version")
  expect_error(hugo_release("0.69.0", "Linux", arch = "blah"), "Can't find release")
})

test_that("can install specified linux/mac version", {
  skip_on_cran()
  old <- hugo_default_get()
  on.exit(hugo_default_set(old))

  home <- hugo_home("0.55.0", "Linux")
  if (dir_exists(home)) dir_delete(home)
  suppressMessages(hugo_install("0.55.0", "Linux"))
  expect_true(file_exists(path(home, "hugo")))

  # Returns early if already installed
  suppressMessages(
    expect_message(hugo_install("0.55.0", "Linux"), "installed")
  )
})

test_that("can install specified windows version", {
  skip_on_cran()
  old <- hugo_default_get()
  on.exit(hugo_default_set(old))

  home <- hugo_home("0.55.0", "Windows")
  if (dir_exists(home)) dir_delete(home)
  suppressMessages(hugo_install("0.55.0", "Windows"))
  expect_true(file_exists(path(home, "hugo.exe")))
})

test_that("can get, set, and increment version", {
  old <- hugo_default_get()
  on.exit(hugo_default_set(old))

  if (file_exists(hugo_default_path())) {
    file_delete(hugo_default_path())
  }

  expect_equal(hugo_default_get(), NA)
  hugo_default_inc("0.1.0")
  expect_equal(hugo_default_get(), package_version("0.1.0"))
  hugo_default_inc("0.0.1")
  expect_equal(hugo_default_get(), package_version("0.1.0"))
  hugo_default_inc("1.0.0")
  expect_equal(hugo_default_get(), package_version("1.0.0"))
})


================================================
FILE: tests/testthat/test-hugo-server.R
================================================
test_that("can start, restart, and stop server", {
  skip_if_no_hugo()
  site <- test_path("minimal")

  suppressMessages(hugo_start(site, browse = FALSE))
  expect_true(hugo_running())
  expect_true(port_active(1313))

  suppressMessages(hugo_start(site, browse = FALSE))
  expect_true(hugo_running())

  suppressMessages(hugo_stop())
  expect_false(hugo_running())
  expect_false(port_active(1313))
})

# build -------------------------------------------------------------------

test_that("default builds into public", {
  skip_if_no_hugo()

  path <- local_dir(test_path("minimal"))
  hugo_build(path)
  expect_true(file_exists(path(path, "public", "index.html")))
})

test_that("can build into any directory", {
  skip_if_no_hugo()
  path <- dir_create(file_temp())

  hugo_build(test_path("minimal"), path)
  expect_true(file_exists(path(path, "index.html")))
})


================================================
FILE: tests/testthat/test-hugo-version.R
================================================
test_that("can find version from hugodown.yml", {
  expect_equal(hugo_version(test_path("config-hugodown")), "0.66.0")
})

test_that("falls back to latest with a warning", {
  expect_warning(out <- hugo_version(test_path("config-toml")), "install")
  expect_equal(out, hugo_default_get())
})


================================================
FILE: tests/testthat/test-hugo.R
================================================
test_that("can extract basic config options", {
  skip_if_no_hugo()

  config <- hugo_config(test_path("minimal/"))
  expect_type(config, "list")

  expect_equal(hugo_config_bool(config, "builddrafts"), FALSE)
  expect_equal(hugo_config_int(config, "paginate"), 10)
  expect_equal(hugo_config_str(config, "themesdir"), "themes")
})

test_that("can override config with env var", {
  skip_if_no_hugo()

  config1 <- hugo_config(test_path("minimal/"))
  expect_equal(hugo_config_bool(config1, "builddrafts"), FALSE)

  config2 <- hugo_config(test_path("minimal/"), c(builddrafts = "true"))
  expect_equal(hugo_config_bool(config2, "builddrafts"), TRUE)
})


================================================
FILE: tests/testthat/test-md-document.R
================================================
test_that("errors are handled gracefully", {
  rmd <- local_file(test_path("error.Rmd"))
  expect_message(expect_error(rmarkdown::render(rmd, quiet = TRUE), "Failure"))
  expect_equal(length(dir_ls(path_dir(rmd))), 1L)
})

test_that("figures placed in figs/ directory", {
  rmd <- local_render(test_path("plot.Rmd"))

  figs <- path(rmd$dir, "figs")
  expect_true(dir_exists(figs))
  expect_equal(length(dir_ls(figs)), 2L)

  # Check we're not converting percentage widths to latex
  expect_match(rmd$lines[[15]], 'width="50%"')
})

test_that("tables use pipes", {
  rmd <- local_render(test_path("table.Rmd"))
  expect_equal(sum(grepl("|", rmd$lines, fixed = TRUE)), 4)
})

test_that("code is linked/highlighted", {
  rmd <- local_render(test_path("code.Rmd"))

  expect_equal(
    xpath_text(rmd$xml, "(//pre)[1]"),
    "1 + 1\n#> [1] 2\n"
  )

  expect_equal(sum(grepl("<pre", rmd$lines, fixed = TRUE)), 2)
  expect_equal(sum(grepl("[`stats::median()`]", rmd$lines, fixed = TRUE)), 1)
})

test_that("unparseable code is left as is", {
  rmd <- local_render(test_path("code-invalid.Rmd"))
  expect_match(rmd$lines[9], "1 + ", fixed = TRUE)
})

test_that("output gets unicode and colour", {
  skip_on_os("windows")

  rmd <- local_render(test_path("output.Rmd"))
  code <- xpath_xml(rmd$xml, "//pre//code/span")

  expect_equal(xpath_attr(code[[1]], "./span/span", "style"), "color: #0000BB;")
  expect_equal(xpath_text(code[[3]], "."), "#> \u2714")
})

test_that("interweaving of code and output generates correct html", {
  rmd <- local_render(test_path("knit-hooks.Rmd"))
  expect_snapshot_output(cat_line(rmd$lines))
})

test_that("markdown div syntax is converted to native divs", {
  rmd <- local_render(test_path("div.Rmd"))
  expect_equal(xpath_attr(rmd$xml, "//div", "class"), "special")
})

test_that("emojis are preserved", {
  rmd <- local_render(test_path("emoji.Rmd"))
  expect_equal(xpath_text(rmd$xml, trim = TRUE), ":smile_cat:")
})

test_that("math is untransformed", {
  rmd <- local_render(test_path("math.Rmd"))
  expect_equal(xpath_text(rmd$xml, trim = TRUE), "$a_1 + b_2$")
})

test_that("raw html is preserved", {
  rmd <- local_render(test_path("raw-html.Rmd"))

  expect_equal(rmd$lines[[7]], "<raw>")
  expect_equal(rmd$lines[[9]], "This is <raw>")
})

test_that("hash added to yaml header", {
  rmd <- local_render(test_path("meta.Rmd"))

  yaml <- rmarkdown::yaml_front_matter(rmd$src)
  yaml$rmd_hash <- rmd_hash(rmd$src)
  expect_equal(rmarkdown::yaml_front_matter(rmd$dst), yaml)

  # Test that yaml is preserved as is (i.e. no round-tripping)
  expect_equal(rmd$lines[[4]], "# this is a comment")
})

test_that("html dependencies are captured", {
  rmd <- local_render(test_path("widget.Rmd"))

  # Have copied over dependencies
  widget_js <- path(rmd$dir, paste0("htmlwidgets-", packageVersion("htmlwidgets")))
  expect_true(dir_exists(widget_js))

  # And written in yaml metadata
  yaml <- rmarkdown::yaml_front_matter(rmd$dst)
  expect_type(yaml$html_dependencies, "character")
  expect_true(length(yaml$html_dependencies) > 1)
})

test_that("curly operator is escaped", {
  rmd <- local_render(test_path("curly.Rmd"))

  expect_match(rmd$lines[[9]], "&#123;")
  expect_match(rmd$lines[[9]], "&#125;")
})
# helpers -----------------------------------------------------------------

test_that("link_inline() works with an nubmer of links", {
  expect_equal(link_inline("a"), "a")
  expect_equal(link_inline("`b`"), "`b`")
  expect_equal(link_inline("`c` `d`"), "`c` `d`")

  expect_equal(
    link_inline("`stats::median`"),
    "[`stats::median`](https://rdrr.io/r/stats/median.html)"
  )
})

test_that("link_inline() doesn't link within links or headers", {
  expect_equal(link_inline("# `base::t`"), "# `base::t`")
  expect_equal(link_inline("[`base::t`]()"), "[`base::t`]()")
  expect_equal(link_inline("<pre>\n`base::t`</pre>"), "<pre>\n`base::t`</pre>")
})


================================================
FILE: tests/testthat/test-netlify.R
================================================
test_that("multiplication works", {
  path <- local_dir(test_path("config-hugodown"))
  suppressMessages(use_netlify_toml(path))

  expect_true(file_exists(path(path, "netlify.toml")))

  toml <- RcppTOML::parseTOML(path(path, "netlify.toml"))
  expect_equal(toml$build$environment$HUGO_VERSION, "0.66.0")
})


================================================
FILE: tests/testthat/test-post.R
================================================
test_that("archetypes use hugo or whisker templating", {
  skip_if_no_hugo()

  site <- local_dir(test_path("archetypes"))
  dir_create(path(site, "content", "Rmd"))
  dir_create(path(site, "content", "md"))

  suppressMessages({
    test_Rmd <- use_post("Rmd/test", site = site, open = FALSE)
    test_md <- use_post("md/test", site = site, open = FALSE)
  })

  rmd <- brio::read_lines(path(test_Rmd, "index.Rmd"))
  expect_equal(rmd[[2]], "slug: test")

  md <- brio::read_lines(path(test_md, "index.md"))
  expect_equal(md[[2]], "slug: test")
})

test_that("catch common errors", {
  skip_if_no_hugo()

  site <- local_dir(test_path("archetypes"))
  expect_error(use_post("Rmd/test", site = site), "Can't find")

  dir_create(path(site, "content", "Rmd"))
  suppressMessages({
    use_post("Rmd/test", site = site, open = FALSE)
    expect_error(use_post("Rmd/test", site = site), "already exists")
  })

})


================================================
FILE: tests/testthat/test-shortcode-arguments.txt
================================================
> inline <- (function(...) cat(shortcode(..., .inline = TRUE)))
> # No arguments
> inline("name")
`{{< name >}}`{=html}

> # Position vs name
> inline("name", 1, 2, 3)
`{{< name 1 2 3 >}}`{=html}

> inline("name", x = 1, y = 2, z = 3)
`{{< name x=1 y=2 z=3 >}}`{=html}

> # Quoting
> inline("name", "x")
`{{< name 'x' >}}`{=html}

> inline("name", I("'x'"))
`{{< name 'x' >}}`{=html}

> # Contents
> inline("name", .contents = "contents")
`{{< name >}}contents{{< /name >}}`{=html}



================================================
FILE: tests/testthat/test-shortcode-embed.txt
================================================
> embed_gist("spf13", "7896402")
[1] "```{=html}\n{{< gist 'spf13' '7896402' >}}\n```\n"

> embed_instagram("BWNjjyYFxVx", caption = TRUE)
[1] "```{=html}\n{{< instagram BWNjjyYFxVx >}}\n```\n"

> embed_instagram("BWNjjyYFxVx", caption = FALSE)
[1] "```{=html}\n{{< instagram BWNjjyYFxVx hidecaption >}}\n```\n"

> embed_tweet("877500564405444608")
[1] "```{=html}\n{{< tweet id='877500564405444608' >}}\n```\n"

> embed_vimeo("146022717")
[1] "```{=html}\n{{< vimeo 146022717 >}}\n```\n"

> embed_youtube("w7Ft2ymGmfc", autoplay = FALSE)
[1] "```{=html}\n{{< youtube id='w7Ft2ymGmfc' >}}\n```\n"

> embed_youtube("w7Ft2ymGmfc", autoplay = TRUE)
[1] "```{=html}\n{{< youtube id=w7Ft2ymGmfc autoplay='true' >}}\n```\n"



================================================
FILE: tests/testthat/test-shortcode-wrapper.txt
================================================
> # type
> cat(shortcode("name", .output = "md"))
```{=html}
{{% name %}}
```

> cat(shortcode("name", .output = "html"))
```{=html}
{{< name >}}
```



================================================
FILE: tests/testthat/test-shortcode.R
================================================
test_that("handles all variants of argument specification", {
  verify_output(test_path("test-shortcode-arguments.txt"), {
    inline <- function(...) cat(shortcode(..., .inline = TRUE))
    "No arguments"
    inline("name")

    "Position vs name"
    inline("name", 1, 2, 3)
    inline("name", x = 1, y = 2, z = 3)

    "Quoting"
    inline("name", "x")
    inline("name", I("'x'"))

    "Contents"
    inline("name", .contents = "contents")
  })
})

test_that("handles md and html output", {
  verify_output(test_path("test-shortcode-wrapper.txt"), {
    "type"
    cat(shortcode("name", .output = "md"))
    cat(shortcode("name", .output = "html"))
  })
})


test_that("test built-in embed shortcodes", {
  verify_output(test_path("test-shortcode-embed.txt"), {
    embed_gist("spf13", "7896402")

    embed_instagram("BWNjjyYFxVx", caption = TRUE)
    embed_instagram("BWNjjyYFxVx", caption = FALSE)

    embed_tweet("877500564405444608")

    embed_vimeo("146022717")

    embed_youtube("w7Ft2ymGmfc", autoplay = FALSE)
    embed_youtube("w7Ft2ymGmfc", autoplay = TRUE)
  })
})


================================================
FILE: tests/testthat/test-site.R
================================================
test_that("recognises major config formats", {
  toml <- as.character(path_abs(test_path("config-toml")))
  expect_equal(site_root(toml), toml)

  yaml <- as.character(path_abs(test_path("config-yaml")))
  expect_equal(site_root(yaml), yaml)

  yml <- as.character(path_abs(test_path("config-yml")))
  expect_equal(site_root(yml), yml)
})

test_that("walks up path to find root", {
  outdated <- as.character(path_abs(test_path("outdated")))
  expect_equal(site_root(path(outdated, "content")), outdated)
  expect_equal(site_root(path(outdated, "content", "blog")), outdated)

  expect_error(site_root(test_path(".")), "config")
})

test_that("can find hugodown config", {
  config <- site_config(test_path("config-hugodown"))
  expect_equal(config, list(test = TRUE, hugo_version = "0.66.0"))
})

# out of date -------------------------------------------------------------

test_that("old blogdown posts don't need render", {
  blog <- test_path("outdated/content/blog")

  expect_false(rmd_needs_render(path(blog, "ok-no-hash/index.Rmd")))
  expect_false(rmd_needs_render(path(blog, "ok-has-html/index.Rmd")))
})

test_path("site_outdated() processes whole directory", {
  site <- test_path("outdated")
  outdated <- as.character(path_rel(site_outdated(site), site))

  expect_equal(outdated, c(
    "content/blog/outdated-no-md/index.Rmd",
    "content/blog/outdated-old-hash/index.Rmd"
  ))
})


================================================
FILE: tests/testthat/test-tidy-pleased.txt
================================================
> set.seed(1014)
> writeLines(replicate(20, tidy_pleased()))
very happy
chuffed
so happy
delighted
delighted
thrilled
happy
delighted
delighted
very pleased
thrilled
happy
chuffed
extremely pleased
tickled pink
stoked
thrilled
delighted
so happy
chuffed



================================================
FILE: tests/testthat/test-tidy.R
================================================
test_that("tidy_post() adds additional data", {
  skip_if_no_hugo()

  site <- local_dir(test_path("archetypes"))
  dir_create(path(site, "content", "blog"))
  suppressMessages({
    test_Rmd <- use_tidy_post("testthat-1-0-0", site = site, open = FALSE)
  })

  rmd <- brio::read_lines(path(test_Rmd, "index.Rmd"))
  expect_equal(rmd[[3]], "package: testthat")
})

test_that("tidy_thumnail() complains about bad inputs", {
  skip_if_not_installed("magick")

  thumb_path <- function(x) test_path("thumbs", x)
  expect_error(use_tidy_thumbnails(thumb_path("missing")), "Can't find")
  expect_error(use_tidy_thumbnails(thumb_path("not-square")), "not square")
  expect_error(use_tidy_thumbnails(thumb_path("too-narrow")), "too narrow")
})

test_that("tidy_thumbnail() modifies images", {
  skip_if_not_installed("magick")
  path <- local_dir(test_path("thumbs", "ok"))

  use_tidy_thumbnails(path)

  sq <- magick::image_info(magick::image_read(file.path(path, "thumbnail-sq.jpg")))
  expect_equal(sq$width, 300)
  expect_equal(sq$height, 300)

  wd <- magick::image_info(magick::image_read(file.path(path, "thumbnail-wd.jpg")))
  expect_equal(wd$width, 1000)
  expect_equal(wd$height, 200)
})

test_that("check_slug ensures name ok", {
  expect_error(check_slug(1), "single string")
  expect_error(check_slug(letters[1:3]), "single string")

  expect_error(check_slug("bad name"), "must not contain")
  expect_error(check_slug("bad.name"), "must not contain")
  expect_error(check_slug("bad_name"), "must not contain")
})

test_that("tidy_pleased() generates random phrases", {
  skip_if(getRversion() < "3.6") # RNG changed

  verify_output(test_path("test-tidy-pleased.txt"), {
    set.seed(1014)
    writeLines(replicate(20, tidy_pleased()))
  })
})


================================================
FILE: tests/testthat/widget.Rmd
================================================
---
output: hugodown::md_document
---

```{r}
library(DiagrammeR)
grViz("
  digraph {
    layout = twopi
    node [shape = circle]
    A -> {B C D} 
  }")
```


================================================
FILE: tests/testthat.R
================================================
library(testthat)
library(hugodown)

test_check("hugodown")


================================================
FILE: vignettes/.gitignore
================================================
*.html
*.R


================================================
FILE: vignettes/config.Rmd
================================================
---
title: "Configuration"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Configuration}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r, include = FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>"
)
```

There are three types of configuration related to hugodown:

-   hugo configuration, because hugodown assumes certain things to be true about your hugo setup.

-   Syntax highlight css

-   hugodown specific configuration, which allows you to control over various ways in which hugodown works.

## Hugo

hugodown does not work with every possible hugo site. There is some config that we assume (typically in `config.toml`, but hugo has a bewildering array of places that this might live instead.)

-   You must use the goldmark markdown renderer, and set `unsafe: true`

    ``` {.toml}
    [markup]
      defaultMarkdownHandler = "goldmark"
      [markup.goldmark.renderer]
        unsafe = true
    ```

-   For best syntax hightlighting results, you must use classes:

    ``` {.toml}
    pygmentsUseClasses = true
    ```

    Then you'll need to do some work on CSS side, see [below](#syntax-highlighting) for details.

-   We recommend ignoring knitr intermediates:

    ``` {.toml}
    ignoreFiles = ['\.Rmd$', '_files$', '_cache$', '\.knit\.md$', '\.utf8\.md$']
    ```

-   To use html widgets, you must include the following Go template somewhere in the `<head>` layout file for your theme. This will help Hugo find the HTML dependencies needed to render the widget in a post. You may find this [blog post](https://zwbetz.com/override-a-hugo-theme/) helpful for overriding Hugo layouts.

        {{ range .Params.html_dependencies }}
          {{ . | safeHTML }}
        {{ end }}

-   To use mathjax, you will need to use a series of [small hacks][yihui-mathjax]. The easiest way is to copy from an existing template, like [tourmaline]. Take note of the [`footer_mathjax.html`][footer\_mathjax] partial, which is then included in the [`footer.html`][footer]. You'll also need to include [`math_code.js`][math\_code] in your `static/` directory. Once that's done you can use inline math like `$math$`, and display math like `` `$$ math $$` `` (note the extra backtick compared to usual).

## Syntax highlighting {#syntax-highlighting}

The hugo config above causes downlit/hugo to generate output html with the following structure:

``` {.html}
<div class="highlight">
  <pre class='chroma'><code class='language-r' data-lang='r'>
    <span class='m'>1</span> <span class='o'>+</span> <span class='m'>1</span>
    <span class='c'>#&gt; [1] 2</span>
  </code></pre>
</div>
```

To have that look good on your website, you need to defines styles for the CSS necessary classes. You can generate starter CSS with the code below, substituting `pygments` for the [style of your choice](https://xyproto.github.io/splash/docs/longer/all.html):

    hugo gen chromastyles --style=pygments > static/css/highlight.css

This generates a file containing definitions that look like this:

``` {.css}
/* Background */ .chroma {  }
/* Other */ .chroma .x {  }
/* Error */ .chroma .err {  }
...
/* Keyword */ .chroma .k { color: #008000; }
...
/* LiteralNumber */ .chroma .m { color: #666666 }
...
/* Operator */ .chroma .o { color: #666666 }
```

Unfortunately, the correct location for `highlight.css` file varies by theme, so you'll need to do a little detective work to figure out the best place to put it. Is it:

-   A special file name?

-   A `customCSS` param in the website configuration?

-   A link in a custom layout?

You may also need to do some detective work to figure out how these styles interact with your existing styles, particularly for links within code. Your best bet is to use the [web developer console](https://developer.mozilla.org/en-US/docs/Tools/Web_Console/Opening_the_Web_Console) to figure out what's going wrong. You'll then need to figure out how to tweak `highlight.css` to override these styles. This is a pain, which is why hugodown ships with a couple of themes that are preconfigured.

### highlight.js inactivation

If you are using an old hugo theme that uses highlight.js you may want to convert to server-side syntax highlighting. This is not required (and not important if you only use R code on your blog), but is a good idea if you show a variety of programming languages and want the code style to be as consistent as possible.

From easiest to hardest, based on the theme you chose:

-   Read how the theme currently handles syntax highlighting (docs might be in the GitHub/GitLab repo README or in the example site... that does not necessarily have search). If the theme docs indicate how to turn off highlight.js, yay, do that!
-   Look for "highlight" in existing issues of your theme issue tracker: others might have also asked how to turn it off, and received ideas or posted their tricks.
-   Otherwise, look for all occurrences of "highlight" in *the source* of the theme. Note that highlight.js works with JS and CSS so you might have to remove scripts, stylesheets, and/or links to them from layout files. Your theme might lack docs about syntax highlighting, but it might still contain docs about customization in general. If not you'll probably need to create custom head/footer where you use the theme head and footer minus references to highlight.js.

## hugodown

hugodown also has its own configuration file, `_hugodown.yaml`. Currently this has one option:

-   `hugo_version`: this defines the version of hugo needed by the current site.


================================================
FILE: vignettes/deploy.Rmd
================================================
---
title: "Deployment"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Deployment}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r, include = FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>"
)
```

This vignette describes the process of deployment, how you get your hugodown website off your local computer and on to the internet for everyone to see. The easiest workflow for most people is to use [netlify](https://www.netlify.com). I'll describe this process in details, and then discuss other approaches that require a manual build site.

(Most of these techiques assume that you're already familiar with the basics of Git and GitHub. If you're not, you can try the Dropbox deployment described below, or try reading with [Happy Git and GitHub for the R user](http://happygitwithr.com/) by Jenny Bryan.)

## Netlify

(Adapted from [A Spoonful of Hugo: The netlify.toml File](https://alison.rbind.io/post/2017-06-12-up-and-running-with-blogdown/#deploy-in-netlify) by Alison Hill, with permission.)

First, create an account if you don't already have one:

1.  Navigate to [Netlify](https://www.netlify.com/) and click on the *Sign Up* link.

    ```{r, echo = FALSE, out.width = "400px"}
    knitr::include_graphics("netlify-landing.png")
    ```

2.  Sign up with *GitHub* to connect your GitHub and Netlify accounts.

    ```{r, echo = FALSE, out.width = "400px"}
    knitr::include_graphics("netlify-sign-up.png")
    ```

    If you use a different version control service, select GitLab or BitBucket instead.

Next create a netlify site for your GitHub repo:

1.  On the netlify website, go *New Site from Git* and pick your repo. You'll be prompted to fill in these fields. They are probably already filled in correctly for you:

    ```{r, echo = FALSE, out.width = "400px"}
    knitr::include_graphics("netlify-deploy-settings.png")
    ```

    Leave the advanced settings as is, and click deploy site. (This won't work but we'll fix it momentarily.)

Finally, configure your blog with `netlify.toml`. This prevents the biggest source of pain when deploying with netlify: version mismatches.

1.  Check you have a `_hugodown.yaml` file that contains `hugo_version: 0.66.0` or similar. It's added automatically you created your site with a hugodown helper; you'll need to add it yourself if you've created the site another way.

2.  Run `hugodown::use_netlify_toml()`, check the new `netlify.toml` in, commit, and push to Github.

Now return to [netlify](https://app.netlify.com), and look in the deploy log. You should see entries like:

    10:00:42 PM: Build ready to start
    10:00:43 PM: build-image version: 8e315e54bc4032a32e73290be556cde4f8348c12
    ...
    10:00:56 PM: Found netlify.toml. Overriding site configuration
    ...
    10:01:02 PM: Installing Hugo 0.68.3
    10:01:02 PM: Hugo Static Site Generator v0.68.3-157669A0 linux/amd64 BuildDate: 2020-03-24T12:05:34Z
    ...
    10:01:04 PM: Executing user command: hugo
    10:01:04 PM: Building sites …
    ...
    10:01:23 PM: Site is live

Success!

## Manual builds

The advantage of netlify is that automatically runs hugo for you; in other deployment scenarios you'll need to run `hugodown::build_site()` and publish the `public/` directory that it creates. The following sections provide some advice for deployment scenarios that need this.

### RStudio connect

For most sites, `rmarkdown::publish_site()` should just work.

If you deploy your site this way, and it doesn't look quite right (e.g. missing style sheets) it's likely because the theme you're using requires a `baseURL`. In this case, you'll need to update your `config.toml` with the URL for your site and republish.

### GitHub pages

You'll need to make a few changes to your site:

-   Run `file.create("static/.nojekyll")`. This ensures that GitHub pages knows that you're using a regular HTML website, not a jekyll website (jekyll is GitHub's own blogging system).

-   If you have a custom domain name, create a `static/CNAME` file containing your domain name (e.g. just `tidyverse.org`, not `https://tidyverse.org`). Note that setting a custom domain name in the admin settings on your GitHub repo will not work.

-   In `config.toml`:

    -   Set `publishDir = "docs/"`

    -   Set `baseURL` to the url where you site will be published.

To deploy:

-   Run `hugodown::build_site()` and check in the rendered `docs/` directory. (If no `docs/` directory is created, double check your config above).

After the first deploy, you'll need to go the admin page for your repo and select \"master branch `/docs` folder) for source:

```{r, echo = FALSE, out.width = "400px"}
knitr::include_graphics("github-setup.png")
```

### Site44 (dropbox)

If you don't use Git and GitHub, one deployment option is [Site44](https://www.site44.com/), a service that allows you to publish websites from within Dropbox folders. Site44 creates a `Dropbox/Apps/site44` directory, and any folders within that directory are published as websites.

The recommended workflow for deploying hugodown websites to Site44 is to develop your website in a separate project directory, and then, when it's ready for final publishing, run `build_site()` then copy the contents of the `public` directory to the folder for your website.

### Amazon S3

If you are a user of Amazon Web Services you can serve your website directly from Amazon S3. This option is a bit more technically involved than GitHub Pages, Netlify, or Site 44. See the article on [Hosting a Static Website on Amazon S3](https://docs.aws.amazon.com/AmazonS3/latest/dev/WebsiteHosting.html) for additional details.
Download .txt
gitextract_u6vogus0/

├── .Rbuildignore
├── .gitattributes
├── .github/
│   ├── .gitignore
│   └── workflows/
│       ├── R-CMD-check.yaml
│       ├── pkgdown.yaml
│       ├── pr-commands.yaml
│       └── test-coverage.yaml
├── .gitignore
├── DESCRIPTION
├── LICENSE
├── LICENSE.md
├── NAMESPACE
├── R/
│   ├── hugo-install.R
│   ├── hugo-server.R
│   ├── hugo-version.R
│   ├── hugo.R
│   ├── hugodown-package.R
│   ├── md-document.R
│   ├── netlify.R
│   ├── post.R
│   ├── shortcode.R
│   ├── site-academic.R
│   ├── site.R
│   ├── test-fixtures.R
│   ├── tidy.R
│   └── utils.R
├── README.md
├── _pkgdown.yml
├── codecov.yml
├── hugodown.Rproj
├── inst/
│   ├── academic/
│   │   ├── README.md
│   │   ├── highlight-dark.css
│   │   ├── highlight-light.css
│   │   └── index.Rmd
│   └── templates/
│       ├── netlify.toml
│       └── template.Rproj
├── man/
│   ├── create_site_academic.Rd
│   ├── embed_gist.Rd
│   ├── hugo_build.Rd
│   ├── hugo_document.Rd
│   ├── hugo_install.Rd
│   ├── hugo_locate.Rd
│   ├── hugo_start.Rd
│   ├── hugo_version.Rd
│   ├── hugodown-package.Rd
│   ├── md_document.Rd
│   ├── shortcode.Rd
│   ├── site_outdated.Rd
│   ├── use_netlify_toml.Rd
│   ├── use_post.Rd
│   └── use_tidy_post.Rd
├── tests/
│   ├── testthat/
│   │   ├── .gitignore
│   │   ├── _snaps/
│   │   │   └── md-document.md
│   │   ├── archetypes/
│   │   │   ├── _hugodown.yaml
│   │   │   ├── archetypes/
│   │   │   │   ├── Rmd/
│   │   │   │   │   └── index.Rmd
│   │   │   │   ├── blog/
│   │   │   │   │   └── index.Rmd
│   │   │   │   └── md/
│   │   │   │       └── index.md
│   │   │   └── config.yml
│   │   ├── code-invalid.Rmd
│   │   ├── code.Rmd
│   │   ├── config-hugodown/
│   │   │   ├── _hugodown.yaml
│   │   │   └── config.yaml
│   │   ├── config-toml/
│   │   │   └── config.toml
│   │   ├── config-yaml/
│   │   │   └── config.yaml
│   │   ├── config-yml/
│   │   │   └── config.yml
│   │   ├── curly.Rmd
│   │   ├── div.Rmd
│   │   ├── emoji.Rmd
│   │   ├── error.Rmd
│   │   ├── knit-hooks.Rmd
│   │   ├── math.Rmd
│   │   ├── meta.Rmd
│   │   ├── minimal/
│   │   │   ├── .gitignore
│   │   │   ├── LICENSE
│   │   │   ├── README.md
│   │   │   ├── _hugodown.yaml
│   │   │   ├── config.toml
│   │   │   ├── content/
│   │   │   │   └── _index.md
│   │   │   └── themes/
│   │   │       └── bare/
│   │   │           ├── layouts/
│   │   │           │   └── index.html
│   │   │           └── theme.toml
│   │   ├── outdated/
│   │   │   ├── config.yml
│   │   │   └── content/
│   │   │       └── blog/
│   │   │           ├── _index.md
│   │   │           ├── ok-has-html/
│   │   │           │   ├── index.Rmd
│   │   │           │   └── index.html
│   │   │           ├── ok-no-hash/
│   │   │           │   ├── index.Rmd
│   │   │           │   └── index.md
│   │   │           ├── outdated-no-md/
│   │   │           │   └── index.Rmd
│   │   │           └── outdated-old-hash/
│   │   │               ├── index.Rmd
│   │   │               └── index.md
│   │   ├── output.Rmd
│   │   ├── plot.Rmd
│   │   ├── raw-html.Rmd
│   │   ├── table.Rmd
│   │   ├── test-hugo-install.R
│   │   ├── test-hugo-server.R
│   │   ├── test-hugo-version.R
│   │   ├── test-hugo.R
│   │   ├── test-md-document.R
│   │   ├── test-netlify.R
│   │   ├── test-post.R
│   │   ├── test-shortcode-arguments.txt
│   │   ├── test-shortcode-embed.txt
│   │   ├── test-shortcode-wrapper.txt
│   │   ├── test-shortcode.R
│   │   ├── test-site.R
│   │   ├── test-tidy-pleased.txt
│   │   ├── test-tidy.R
│   │   └── widget.Rmd
│   └── testthat.R
└── vignettes/
    ├── .gitignore
    ├── config.Rmd
    └── deploy.Rmd
Condensed preview — 112 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (129K chars).
[
  {
    "path": ".Rbuildignore",
    "chars": 107,
    "preview": "^hugodown\\.Rproj$\n^\\.Rproj\\.user$\n^LICENSE\\.md$\n^codecov\\.yml$\n^\\.github$\n^_pkgdown\\.yml$\n^docs$\n^pkgdown$\n"
  },
  {
    "path": ".gitattributes",
    "chars": 18,
    "preview": "*.Rmd text eol=lf\n"
  },
  {
    "path": ".github/.gitignore",
    "chars": 7,
    "preview": "*.html\n"
  },
  {
    "path": ".github/workflows/R-CMD-check.yaml",
    "chars": 1740,
    "preview": "# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples\n# Need help debugging build failures? Start at"
  },
  {
    "path": ".github/workflows/pkgdown.yaml",
    "chars": 1261,
    "preview": "# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples\n# Need help debugging build failures? Start at"
  },
  {
    "path": ".github/workflows/pr-commands.yaml",
    "chars": 2392,
    "preview": "# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples\n# Need help debugging build failures? Start at"
  },
  {
    "path": ".github/workflows/test-coverage.yaml",
    "chars": 745,
    "preview": "# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples\n# Need help debugging build failures? Start at"
  },
  {
    "path": ".gitignore",
    "chars": 43,
    "preview": ".Rproj.user\n.Rhistory\n.RData\ndocs\ninst/doc\n"
  },
  {
    "path": "DESCRIPTION",
    "chars": 1030,
    "preview": "Package: hugodown\nTitle: Make websites with hugo and RMarkdown\nVersion: 0.0.0.9000\nAuthors@R: c(\n    person(\"Hadley\", \"W"
  },
  {
    "path": "LICENSE",
    "chars": 37,
    "preview": "YEAR: 2020\nCOPYRIGHT HOLDER: RStudio\n"
  },
  {
    "path": "LICENSE.md",
    "chars": 1066,
    "preview": "# MIT License\n\nCopyright (c) 2020 RStudio\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\n"
  },
  {
    "path": "NAMESPACE",
    "chars": 540,
    "preview": "# Generated by roxygen2: do not edit by hand\n\nexport(create_site_academic)\nexport(embed_gist)\nexport(embed_instagram)\nex"
  },
  {
    "path": "R/hugo-install.R",
    "chars": 4176,
    "preview": "#' Install specified version of hugo\n#'\n#' Downloads binary from hugo releases, and installs in system wide cache.\n#'\n#'"
  },
  {
    "path": "R/hugo-server.R",
    "chars": 5052,
    "preview": "#' Manage the hugo server\n#'\n#' @section Hugo version:\n#' hugodown will attempt to automatically use the correct version"
  },
  {
    "path": "R/hugo-version.R",
    "chars": 1184,
    "preview": "#' Find hugo version needed for current site\n#'\n#' @description\n#' Hugo changes rapidly, so it's important to pin your s"
  },
  {
    "path": "R/hugo.R",
    "chars": 1806,
    "preview": "#' Locates a specific Hugo installation\n#'\n#' @param version The Hugo version to be located\n#'\n#' @return Returns the pa"
  },
  {
    "path": "R/hugodown-package.R",
    "chars": 264,
    "preview": "#' @keywords internal\n#' @import rlang\n#' @import fs\n\"_PACKAGE\"\n\nhugodown <- new_environment()\n\n# The following block is"
  },
  {
    "path": "R/md-document.R",
    "chars": 9958,
    "preview": "#' An Rmd output format that produces Hugo-flavoured markdown\n#'\n#' This RMarkdown output format is designed to generate"
  },
  {
    "path": "R/netlify.R",
    "chars": 588,
    "preview": "#' Create `netlify.toml`\n#'\n#' This helper creates a basic `netlify.toml` file, automatically setting the\n#' hugo versio"
  },
  {
    "path": "R/post.R",
    "chars": 2082,
    "preview": "#' Create a new post\n#'\n#' Post creation takes advantage of Hugo's\n#' [archetypes](https://gohugo.io/content-management/"
  },
  {
    "path": "R/shortcode.R",
    "chars": 4160,
    "preview": "#' Generate a hugo shortcode\n#'\n#' @description\n#' Generate a hugo shortcode with appropriate pandoc markup to preserve "
  },
  {
    "path": "R/site-academic.R",
    "chars": 6528,
    "preview": "#' Create a hugo academic site\n#'\n#' @description\n#' Create a hugo academic 4.8.0 site, configured to work well with hug"
  },
  {
    "path": "R/site.R",
    "chars": 3368,
    "preview": "site_root <- function(path = \".\") {\n  path <- as.character(path_abs(path))\n\n  while (!identical(path, path_dir(path))) {"
  },
  {
    "path": "R/test-fixtures.R",
    "chars": 945,
    "preview": "local_file <- function(path, env = parent.frame()) {\n  tmp <- dir_create(file_temp())\n  withr::defer(dir_delete(tmp), en"
  },
  {
    "path": "R/tidy.R",
    "chars": 3994,
    "preview": "#' Various helpers for tidyverse.org and similar sites\n#'\n#' * `use_tidy_post()` makes a new post\n#' * `use_tidy_thumbna"
  },
  {
    "path": "R/utils.R",
    "chars": 1571,
    "preview": "first_path <- function(paths) {\n  for (path in paths) {\n    if (file_exists(path)) {\n      return(path)\n    }\n  }\n\n  abo"
  },
  {
    "path": "README.md",
    "chars": 4710,
    "preview": "\n# hugodown <img src='man/figures/logo.png' align=\"right\" height=\"138.5\" />\n\n<!-- badges: start -->\n[![Lifecycle: experi"
  },
  {
    "path": "_pkgdown.yml",
    "chars": 84,
    "preview": "url: https://hugodown.r-lib.org\n\ntemplate:\n  params:\n    ganalytics: UA-115082821-1\n"
  },
  {
    "path": "codecov.yml",
    "chars": 232,
    "preview": "comment: false\n\ncoverage:\n  status:\n    project:\n      default:\n        target: auto\n        threshold: 1%\n        infor"
  },
  {
    "path": "hugodown.Rproj",
    "chars": 412,
    "preview": "Version: 1.0\n\nRestoreWorkspace: No\nSaveWorkspace: No\nAlwaysSaveHistory: Default\n\nEnableCodeIndexing: Yes\nUseSpacesForTab"
  },
  {
    "path": "inst/academic/README.md",
    "chars": 370,
    "preview": "This is a [hugo](http://gohugo.io/) [academic](https://sourcethemes.com/academic) created by [hugodown](http://hugodown."
  },
  {
    "path": "inst/academic/highlight-dark.css",
    "chars": 4401,
    "preview": "/* Background */ .chroma { color: #f8f8f2; background-color: #282a36 }\n/* Other */ .chroma .x {  }\n/* Error */ .chroma ."
  },
  {
    "path": "inst/academic/highlight-light.css",
    "chars": 4959,
    "preview": "/* Background */ .chroma { background-color: #ffffff }\n/* Other */ .chroma .x {  }\n/* Error */ .chroma .err { color: #a6"
  },
  {
    "path": "inst/academic/index.Rmd",
    "chars": 39,
    "preview": "---\nsite: hugodown:::hugodown_site\n---\n"
  },
  {
    "path": "inst/templates/netlify.toml",
    "chars": 218,
    "preview": "[build]\n  publish = \"public\"\n  command = \"hugo\"\n\n[build.environment]\n  HUGO_VERSION = \"{{hugo_version}}\"\n  HUGO_BUILDFUT"
  },
  {
    "path": "inst/templates/template.Rproj",
    "chars": 296,
    "preview": "Version: 1.0\n\nRestoreWorkspace: No\nSaveWorkspace: No\nAlwaysSaveHistory: Default\n\nEnableCodeIndexing: Yes\nUseSpacesForTab"
  },
  {
    "path": "man/create_site_academic.Rd",
    "chars": 854,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/site-academic.R\n\\name{create_site_academic"
  },
  {
    "path": "man/embed_gist.Rd",
    "chars": 1612,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/shortcode.R\n\\name{embed_gist}\n\\alias{embed"
  },
  {
    "path": "man/hugo_build.Rd",
    "chars": 951,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/hugo-server.R\n\\name{hugo_build}\n\\alias{hug"
  },
  {
    "path": "man/hugo_document.Rd",
    "chars": 372,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/md-document.R\n\\name{hugo_document}\n\\alias{"
  },
  {
    "path": "man/hugo_install.Rd",
    "chars": 707,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/hugo-install.R\n\\name{hugo_install}\n\\alias{"
  },
  {
    "path": "man/hugo_locate.Rd",
    "chars": 428,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/hugo.R\n\\name{hugo_locate}\n\\alias{hugo_loca"
  },
  {
    "path": "man/hugo_start.Rd",
    "chars": 1864,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/hugo-server.R\n\\name{hugo_start}\n\\alias{hug"
  },
  {
    "path": "man/hugo_version.Rd",
    "chars": 712,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/hugo-version.R\n\\name{hugo_version}\n\\alias{"
  },
  {
    "path": "man/hugodown-package.Rd",
    "chars": 833,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/hugodown-package.R\n\\docType{package}\n\\name"
  },
  {
    "path": "man/md_document.Rd",
    "chars": 1454,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/md-document.R\n\\name{md_document}\n\\alias{md"
  },
  {
    "path": "man/shortcode.Rd",
    "chars": 1426,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/shortcode.R\n\\name{shortcode}\n\\alias{shortc"
  },
  {
    "path": "man/site_outdated.Rd",
    "chars": 557,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/site.R\n\\name{site_outdated}\n\\alias{site_ou"
  },
  {
    "path": "man/use_netlify_toml.Rd",
    "chars": 525,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/netlify.R\n\\name{use_netlify_toml}\n\\alias{u"
  },
  {
    "path": "man/use_post.Rd",
    "chars": 1226,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/post.R\n\\name{use_post}\n\\alias{use_post}\n\\t"
  },
  {
    "path": "man/use_tidy_post.Rd",
    "chars": 857,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/tidy.R\n\\name{use_tidy_post}\n\\alias{use_tid"
  },
  {
    "path": "tests/testthat/.gitignore",
    "chars": 17,
    "preview": "knit-hooks_files\n"
  },
  {
    "path": "tests/testthat/_snaps/md-document.md",
    "chars": 2164,
    "preview": "# interweaving of code and output generates correct html\n\n    ---\n    output: hugodown::md_document\n    rmd_hash: 51bc60"
  },
  {
    "path": "tests/testthat/archetypes/_hugodown.yaml",
    "chars": 21,
    "preview": "hugo_version: 0.72.0\n"
  },
  {
    "path": "tests/testthat/archetypes/archetypes/Rmd/index.Rmd",
    "chars": 25,
    "preview": "---\nslug: {{ slug }}\n---\n"
  },
  {
    "path": "tests/testthat/archetypes/archetypes/blog/index.Rmd",
    "chars": 48,
    "preview": "---\nslug: {{ slug }}\npackage: {{ package }}\n---\n"
  },
  {
    "path": "tests/testthat/archetypes/archetypes/md/index.md",
    "chars": 71,
    "preview": "---\nslug: {{ .Name }}\ntitle: \"{{ replace .Name \"-\" \" \" | title }}\"\n---\n"
  },
  {
    "path": "tests/testthat/archetypes/config.yml",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/testthat/code-invalid.Rmd",
    "chars": 69,
    "preview": "---\noutput: hugodown::md_document\n---\n\n```{r, eval = FALSE}\n1 + \n```\n"
  },
  {
    "path": "tests/testthat/code.Rmd",
    "chars": 191,
    "preview": "---\noutput: hugodown::md_document\n---\n\n```{r}\n1 + 1\n```\n\n`stats::median()`\n\n```{r, error = TRUE}\nprint(\"print\")\nmessage("
  },
  {
    "path": "tests/testthat/config-hugodown/_hugodown.yaml",
    "chars": 32,
    "preview": "test: true\nhugo_version: 0.66.0\n"
  },
  {
    "path": "tests/testthat/config-hugodown/config.yaml",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/testthat/config-toml/config.toml",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/testthat/config-yaml/config.yaml",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/testthat/config-yml/config.yml",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/testthat/curly.Rmd",
    "chars": 76,
    "preview": "---\noutput: hugodown::md_document\n---\n\n```{r, eval = FALSE}\n{{ curly }}\n```\n"
  },
  {
    "path": "tests/testthat/div.Rmd",
    "chars": 70,
    "preview": "---\noutput: hugodown::md_document\n---\n\n:::special\nThis is special\n:::\n"
  },
  {
    "path": "tests/testthat/emoji.Rmd",
    "chars": 51,
    "preview": "---\noutput: hugodown::md_document\n---\n\n:smile_cat:\n"
  },
  {
    "path": "tests/testthat/error.Rmd",
    "chars": 67,
    "preview": "---\noutput: hugodown::md_document\n---\n\n```{r}\nstop(\"Failure\")\n```\n\n"
  },
  {
    "path": "tests/testthat/knit-hooks.Rmd",
    "chars": 282,
    "preview": "---\noutput: hugodown::md_document\n---\n\n## Mixed as_is and coode\n\n```{r}\ndf <- data.frame(x = 1)\ndf\n\nknitr::kable(df)\n```"
  },
  {
    "path": "tests/testthat/math.Rmd",
    "chars": 51,
    "preview": "---\noutput: hugodown::md_document\n---\n\n$a_1 + b_2$\n"
  },
  {
    "path": "tests/testthat/meta.Rmd",
    "chars": 73,
    "preview": "---\nauthor: Hadley\noutput: hugodown::md_document\n# this is a comment\n---\n"
  },
  {
    "path": "tests/testthat/minimal/.gitignore",
    "chars": 7,
    "preview": "public\n"
  },
  {
    "path": "tests/testthat/minimal/LICENSE",
    "chars": 1153,
    "preview": "License\n=========\n\nThis project is licensed under the terms of the MIT License describe below.\n\nCopyright (c) 2017 Arun "
  },
  {
    "path": "tests/testthat/minimal/README.md",
    "chars": 116,
    "preview": "Minimal site created for Hugo, a static site generator\n\nRead the tutorial at http://arunrocks.com for more details.\n"
  },
  {
    "path": "tests/testthat/minimal/_hugodown.yaml",
    "chars": 21,
    "preview": "hugo_version: 0.72.0\n"
  },
  {
    "path": "tests/testthat/minimal/config.toml",
    "chars": 46,
    "preview": "baseURL = \"http://example.org/\"\ntheme = \"bare\""
  },
  {
    "path": "tests/testthat/minimal/content/_index.md",
    "chars": 78,
    "preview": "+++\ntitle = \"Home page\"\n+++\n\nThis page has **bold** and *italics* formatting.\n"
  },
  {
    "path": "tests/testthat/minimal/themes/bare/layouts/index.html",
    "chars": 107,
    "preview": "<html>\n  <body>\n    <h1>Welcome!</h1>\n    \n    <h2>{{ .Title }}</h2>\n    {{ .Content }}\n\n  </body>\n</html>\n"
  },
  {
    "path": "tests/testthat/minimal/themes/bare/theme.toml",
    "chars": 30,
    "preview": "name = \"Bare\"\nlicense = \"MIT\"\n"
  },
  {
    "path": "tests/testthat/outdated/config.yml",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/testthat/outdated/content/blog/_index.md",
    "chars": 20,
    "preview": "---\ntitle: Blog\n---\n"
  },
  {
    "path": "tests/testthat/outdated/content/blog/ok-has-html/index.Rmd",
    "chars": 76,
    "preview": "---\ntitle: This post is out of date\noutput: hugodown::md_document\n---\n\nText\n"
  },
  {
    "path": "tests/testthat/outdated/content/blog/ok-has-html/index.html",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/testthat/outdated/content/blog/ok-no-hash/index.Rmd",
    "chars": 76,
    "preview": "---\ntitle: This post is out of date\noutput: hugodown::md_document\n---\n\nText\n"
  },
  {
    "path": "tests/testthat/outdated/content/blog/ok-no-hash/index.md",
    "chars": 78,
    "preview": "---\ntitle: This post is out of date\noutput: hugodown::md_document\n\n---\n\nText\n\n"
  },
  {
    "path": "tests/testthat/outdated/content/blog/outdated-no-md/index.Rmd",
    "chars": 71,
    "preview": "---\ntitle: This post is out of date\noutput: hugodown::md_document\n---\n\n"
  },
  {
    "path": "tests/testthat/outdated/content/blog/outdated-old-hash/index.Rmd",
    "chars": 76,
    "preview": "---\ntitle: This post is out of date\noutput: hugodown::md_document\n---\n\nText\n"
  },
  {
    "path": "tests/testthat/outdated/content/blog/outdated-old-hash/index.md",
    "chars": 94,
    "preview": "---\ntitle: This post is out of date\noutput: hugodown::md_document\nrmd_hash: wrong\n\n---\n\nText\n\n"
  },
  {
    "path": "tests/testthat/output.Rmd",
    "chars": 113,
    "preview": "---\noutput: hugodown::md_document\n---\n\n```{r, echo = FALSE}\ncat(cli::col_blue(\"blue\"))\ncat(cli::symbol$tick)\n```\n"
  },
  {
    "path": "tests/testthat/plot.Rmd",
    "chars": 137,
    "preview": "---\noutput: hugodown::md_document\n---\n\n```{r, echo = FALSE}\nplot(1:5, 1:5)\n```\n\n```{r, echo = FALSE, out.width=\"50%\"}\npl"
  },
  {
    "path": "tests/testthat/raw-html.Rmd",
    "chars": 84,
    "preview": "---\noutput: hugodown::md_document\n---\n\n```{=html}\n<raw>\n```\n\nThis is `<raw>`{=html}\n"
  },
  {
    "path": "tests/testthat/table.Rmd",
    "chars": 151,
    "preview": "---\noutput: hugodown::md_document\n---\n\n                 mpg   cyl \n--------------  ----  ---- \nMazda RX4         21     "
  },
  {
    "path": "tests/testthat/test-hugo-install.R",
    "chars": 1658,
    "preview": "test_that(\"can retrieve download urls\", {\n  skip_on_cran()\n\n  expect_equal(\n    hugo_release(\"0.69.0\", \"Linux\")$url,\n   "
  },
  {
    "path": "tests/testthat/test-hugo-server.R",
    "chars": 869,
    "preview": "test_that(\"can start, restart, and stop server\", {\n  skip_if_no_hugo()\n  site <- test_path(\"minimal\")\n\n  suppressMessage"
  },
  {
    "path": "tests/testthat/test-hugo-version.R",
    "chars": 292,
    "preview": "test_that(\"can find version from hugodown.yml\", {\n  expect_equal(hugo_version(test_path(\"config-hugodown\")), \"0.66.0\")\n}"
  },
  {
    "path": "tests/testthat/test-hugo.R",
    "chars": 654,
    "preview": "test_that(\"can extract basic config options\", {\n  skip_if_no_hugo()\n\n  config <- hugo_config(test_path(\"minimal/\"))\n  ex"
  },
  {
    "path": "tests/testthat/test-md-document.R",
    "chars": 3901,
    "preview": "test_that(\"errors are handled gracefully\", {\n  rmd <- local_file(test_path(\"error.Rmd\"))\n  expect_message(expect_error(r"
  },
  {
    "path": "tests/testthat/test-netlify.R",
    "chars": 309,
    "preview": "test_that(\"multiplication works\", {\n  path <- local_dir(test_path(\"config-hugodown\"))\n  suppressMessages(use_netlify_tom"
  },
  {
    "path": "tests/testthat/test-post.R",
    "chars": 912,
    "preview": "test_that(\"archetypes use hugo or whisker templating\", {\n  skip_if_no_hugo()\n\n  site <- local_dir(test_path(\"archetypes\""
  },
  {
    "path": "tests/testthat/test-shortcode-arguments.txt",
    "chars": 483,
    "preview": "> inline <- (function(...) cat(shortcode(..., .inline = TRUE)))\n> # No arguments\n> inline(\"name\")\n`{{< name >}}`{=html}\n"
  },
  {
    "path": "tests/testthat/test-shortcode-embed.txt",
    "chars": 719,
    "preview": "> embed_gist(\"spf13\", \"7896402\")\n[1] \"```{=html}\\n{{< gist 'spf13' '7896402' >}}\\n```\\n\"\n\n> embed_instagram(\"BWNjjyYFxVx"
  },
  {
    "path": "tests/testthat/test-shortcode-wrapper.txt",
    "chars": 151,
    "preview": "> # type\n> cat(shortcode(\"name\", .output = \"md\"))\n```{=html}\n{{% name %}}\n```\n\n> cat(shortcode(\"name\", .output = \"html\")"
  },
  {
    "path": "tests/testthat/test-shortcode.R",
    "chars": 1084,
    "preview": "test_that(\"handles all variants of argument specification\", {\n  verify_output(test_path(\"test-shortcode-arguments.txt\"),"
  },
  {
    "path": "tests/testthat/test-site.R",
    "chars": 1398,
    "preview": "test_that(\"recognises major config formats\", {\n  toml <- as.character(path_abs(test_path(\"config-toml\")))\n  expect_equal"
  },
  {
    "path": "tests/testthat/test-tidy-pleased.txt",
    "chars": 255,
    "preview": "> set.seed(1014)\n> writeLines(replicate(20, tidy_pleased()))\nvery happy\nchuffed\nso happy\ndelighted\ndelighted\nthrilled\nha"
  },
  {
    "path": "tests/testthat/test-tidy.R",
    "chars": 1752,
    "preview": "test_that(\"tidy_post() adds additional data\", {\n  skip_if_no_hugo()\n\n  site <- local_dir(test_path(\"archetypes\"))\n  dir_"
  },
  {
    "path": "tests/testthat/widget.Rmd",
    "chars": 159,
    "preview": "---\noutput: hugodown::md_document\n---\n\n```{r}\nlibrary(DiagrammeR)\ngrViz(\"\n  digraph {\n    layout = twopi\n    node [shape"
  },
  {
    "path": "tests/testthat.R",
    "chars": 60,
    "preview": "library(testthat)\nlibrary(hugodown)\n\ntest_check(\"hugodown\")\n"
  },
  {
    "path": "vignettes/.gitignore",
    "chars": 11,
    "preview": "*.html\n*.R\n"
  },
  {
    "path": "vignettes/config.Rmd",
    "chars": 5569,
    "preview": "---\ntitle: \"Configuration\"\noutput: rmarkdown::html_vignette\nvignette: >\n  %\\VignetteIndexEntry{Configuration}\n  %\\Vignet"
  },
  {
    "path": "vignettes/deploy.Rmd",
    "chars": 5673,
    "preview": "---\ntitle: \"Deployment\"\noutput: rmarkdown::html_vignette\nvignette: >\n  %\\VignetteIndexEntry{Deployment}\n  %\\VignetteEngi"
  }
]

About this extraction

This page contains the full source code of the r-lib/hugodown GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 112 files (113.8 KB), approximately 36.0k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!