Skip to content

Instantly share code, notes, and snippets.

@elipousson
Created September 5, 2023 02:00
Show Gist options
  • Save elipousson/f14171dbbe5c7587349a9be624ac5206 to your computer and use it in GitHub Desktop.
Save elipousson/f14171dbbe5c7587349a9be624ac5206 to your computer and use it in GitHub Desktop.
A R function to read an Excalidraw Markdown file created with Obsidian to a list
#' Read an Excalidraw Markdown file created using the Obsidian Excalidraw
#' plugin.
#'
#' Plugin: https://github.com/zsviczian/obsidian-excalidraw-plugin
#'
#' This function uses the experimental yyjsonr package
#' <https://github.com/coolbutuseless/yyjsonr>. jsonlite would also work here.
#'
#' @param file A Markdown file created with the Obsidian Excalidraw plugin.
#' @param ... Additional parameters passed to [readr::read_lines()]
#' @noRd
read_excalidraw <- function(file, ...) {
file_txt <- readr::read_lines(file, ...)
# Read text elements from Markdown
txt_elements <- file_txt[index_txt(file_txt, c("# Text Elements", "%%"))]
txt_elements <- data.frame("elements" = text_elements[txt_elements != ""])
txt_elements <- tidyr::separate_wider_delim(
txt_elements,
cols = all_of("elements"),
" ^",
names = c("text", "id")
)
# Read and parse JSON (which also includes text elements)
drawing <- file_txt[index_txt(file_txt, c("```json", "```"))]
# pak::pkg_install("coolbutuseless/yyjsonr")
drawing <- yyjsonr::from_json_str(paste0(drawing, collapse = ""))
# Return list
list(
"text" = txt_elements,
"drawing" = drawing
)
}
#' Helper function to index a text file based on limit strings
#'
#' @param txt A text file read with [readr::read_lines()] or a path to a text
#' file.
#' @param lims A length 2 character vector with unique values where the first
#' appearance of the first value and first appearance of the second value
#' define the start and end of the indexed range
#' @noRd
index_txt <- function(txt = NULL, lims = c("```json", "```"), ...) {
if (rlang::is_string(txt) && fs::is_file(txt)) {
txt <- readr::read_lines(txt, ...)
}
stopifnot(
all(lims %in% txt),
length(unique(lims)) == 2
)
c((which(txt == lims[[1]])[[1]] + 1):(which(txt == lims[[2]])[[1]] - 1))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment