|
| 1 | +#' Create a new blog post |
| 2 | +#' |
| 3 | +#' Creates (and potentially opens) the `index.qmd` file for a new blog post. |
| 4 | +#' |
| 5 | +#' @inheritParams rlang::args_error_context |
| 6 | +#' @param title A character string for the title of the post. It is converted |
| 7 | +#' to title case via [tools::toTitleCase()]. |
| 8 | +#' @param dest A character string (or NULL) for the path within `posts`. By |
| 9 | +#' default, the title is adapted as the directory name. |
| 10 | +#' @param wd An optional working directory. If `NULL`, the current working is used. |
| 11 | +#' @param open A logical: have the default editor open a window to edit the |
| 12 | +#' `index.qmd` file? |
| 13 | +#' @param ... A named list of values to be added to the yaml header, such as |
| 14 | +#' `date`, `author`, `categories`, `description`, etc. |
| 15 | +#' If no `date` is provided, the current date is used. |
| 16 | +#' If no `author` is provided, `whoami::fullname()` is used to get the user's name. |
| 17 | +#' @return The path to the index file. |
| 18 | +#' @export |
| 19 | +#' @examples |
| 20 | +#' \dontrun{ |
| 21 | +#' \donttest{ |
| 22 | +#' new_blog_post("making quarto blog posts", categories = c("R")) |
| 23 | +#' |
| 24 | +#' } |
| 25 | +#' } |
| 26 | +#' |
| 27 | +new_blog_post <- function( |
| 28 | + title, |
| 29 | + dest = NULL, |
| 30 | + wd = NULL, |
| 31 | + open = rlang::is_interactive(), |
| 32 | + call = rlang::current_env(), |
| 33 | + ... |
| 34 | +) { |
| 35 | + rlang::check_installed("whoami") |
| 36 | + |
| 37 | + if (is.null(dest)) { |
| 38 | + # Scrub title to make directory name |
| 39 | + dest <- gsub("[[:space:]]", "-", tolower(title)) |
| 40 | + } |
| 41 | + dest_path <- make_post_dir(dest, wd, call) |
| 42 | + post_yaml <- make_post_yaml(title, ...) |
| 43 | + qmd_path <- write_post_yaml(post_yaml, dest_path, call) |
| 44 | + if (open) { |
| 45 | + edit_file <- utils::file.edit |
| 46 | + if ( |
| 47 | + rlang::is_installed("usethis") && |
| 48 | + is.function(asNamespace("usethis")$edit_file) |
| 49 | + ) { |
| 50 | + edit_file <- utils::getFromNamespace("edit_file", "usethis") |
| 51 | + } |
| 52 | + edit_file(qmd_path) |
| 53 | + } |
| 54 | + invisible(qmd_path) |
| 55 | +} |
| 56 | + |
| 57 | +make_post_dir <- function(dest, wd, call) { |
| 58 | + working <- if (is.null(wd)) fs::path_wd() else fs::path_abs(wd) |
| 59 | + |
| 60 | + # is this a quarto project for blog ? Expecting _quarto.yml in working dir |
| 61 | + if (!fs::file_exists(fs::path(working, "_quarto.yml"))) { |
| 62 | + cli::cli_abort( |
| 63 | + "You need to be at root of a Quarto project to create a blog post in the {.file posts/} directory at {.file {fs::path_real(working)}}.", |
| 64 | + call = call |
| 65 | + ) |
| 66 | + } |
| 67 | + |
| 68 | + post_path <- fs::path(working, "posts", dest) |
| 69 | + |
| 70 | + if (fs::dir_exists(post_path)) { |
| 71 | + cli::cli_abort( |
| 72 | + "There is already a {.file {dest}} directory in 'posts/'", |
| 73 | + call = call |
| 74 | + ) |
| 75 | + } else { |
| 76 | + ret <- fs::dir_create(post_path) |
| 77 | + } |
| 78 | + ret |
| 79 | +} |
| 80 | + |
| 81 | +make_post_yaml <- function(title, ...) { |
| 82 | + default_values <- list( |
| 83 | + title = tools::toTitleCase(title), |
| 84 | + author = tools::toTitleCase(whoami::fullname("Your name")), |
| 85 | + date = format(Sys.Date(), "%Y-%m-%d"), |
| 86 | + categories = character(0) |
| 87 | + ) |
| 88 | + |
| 89 | + user_values <- list(...) |
| 90 | + |
| 91 | + yml_values <- merge_list(default_values, user_values) |
| 92 | + if (length(yml_values$categories) == 0) { |
| 93 | + yml_values <- yml_values[names(yml_values) != "categories"] |
| 94 | + } |
| 95 | + yml_values <- as_yaml(yml_values) |
| 96 | + yml_values <- paste0("---\n", yml_values, "---\n") |
| 97 | + yml_values |
| 98 | +} |
| 99 | + |
| 100 | +write_post_yaml <- function(x, dest, call) { |
| 101 | + dest_file <- fs::path(dest, "index.qmd") |
| 102 | + if (fs::file_exists(dest_file)) { |
| 103 | + cli::cli_abort( |
| 104 | + "There is already am index.qmd file at {.code {path}}", |
| 105 | + call = call |
| 106 | + ) |
| 107 | + } else { |
| 108 | + ret <- xfun::write_utf8(x, con = dest_file) |
| 109 | + } |
| 110 | + dest_file |
| 111 | +} |
0 commit comments