r
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

155 lines
5.1KB

  1. #' Make a wrapper function
  2. #'
  3. #' @description Wrapper functions are passed to the `wrapper=` argument of
  4. #' [redoc()] to specify what text in R Markdown files should be
  5. #' captured and restored when de-rendering (in addition to code chunks, inline
  6. #' code, and YAML blocks). `make_wrapper()` simplifies creation of these
  7. #' wrapper functions and returns a function that can be passed to [redoc()].
  8. #'
  9. #' Wrappers included in the package, all of which are used by default, are:
  10. #'
  11. #' \tabular{llll}{
  12. #' **Type of markup** \tab **Function** \tab **Label** \tab **Type** \cr
  13. #' HTML Comments \tab `htmlcommentwrap()` \tab `"htmlcomment"` \tab inline \cr
  14. #' Single-line LaTeX \tab `latexwrap()` \tab `"latex"` \tab block \cr
  15. #' Pandoc citations \tab `citationwrap()` \tab `"citation"` \tab inline \cr
  16. #' Raw Blocks \tab `rawblockwrap()` \tab `"rawblock"` \tab block \cr
  17. #' Raw Spans \tab `rawspanwrap()` \tab `"rawspan"` \tab inline
  18. #' }
  19. #'
  20. #' @details
  21. #' Some captured text can not be selected by regular expressions, in which case
  22. #' custom functions can be provided to parse out the relevant text. See the vignette "Developing
  23. #' with redoc" for more detail.
  24. #' @param regex A regular expression that identifies the text to be wrapped and
  25. #' restored, including all delimiters. It will search in a single string with
  26. #' line breaks. [ICU regular expressions][stringi::stringi-search-regex] are used.
  27. #' The `(?s)` flag is recommended for multi-line expressions.
  28. #' @param label the label to use for chunks of this type, e.g., "citation", "table".
  29. #' These should be unique for each type of wrapper used. [redoc()]
  30. #' will throw an error otherwise.
  31. #' @param type whether the text should be treated as inline or block text. Inlines
  32. #' are wrapped in `span` elements and blocks are wrapped in `divs`. These are
  33. #' treated differently in several ways, especially when restoring text in [dedoc()].
  34. #' @return A function of class `redoc_wrapper`
  35. #' @export
  36. #' @importFrom stringi stri_extract_all_regex stri_replace_first_fixed
  37. #' @aliases wrappers
  38. #' @examples
  39. #'
  40. #' rmarkdown::render(
  41. #' redoc_example_rmd(),
  42. #' output_format = redoc(
  43. #' wrappers = list(
  44. #' htmlcommentwrap,
  45. #' latexwrap)))
  46. #'
  47. #' # This is how each of these functions are defined in the redoc package
  48. #' htmlcommentwrap <- make_wrapper(
  49. #' label = "htmlcomment",
  50. #' regex = "(?s)<!--.*?-->",
  51. #' type = "inline")
  52. #'
  53. #' latexwrap <- make_wrapper(
  54. #' label = "latex",
  55. #' regex = "(?<=[\n\r])\\\\\\w+.*?(?=[\n\r])",
  56. #' type = "block")
  57. #'
  58. #' rawblockwrap <- make_wrapper(
  59. #' label = "rawblock",
  60. #' regex = "(?s)```\\{=\\w+\\}.*?```\\h*",
  61. #' type = "block")
  62. #'
  63. #' rawspanwrap <- make_wrapper(
  64. #' label = "rawspan",
  65. #' regex = "(?s)`[^`]`\\{=\\w+?\\}",
  66. #' type = "inline")
  67. #'
  68. #' citationwrap <- make_wrapper(
  69. #' label = "citation",
  70. #' regex = "(?:@\\w+|\\[.*?-?@\\w+.*?\\](?!\\[\\(\\{))",
  71. #' type = "inline")
  72. make_wrapper <- function(label, regex, type = c("block", "inline")) {
  73. type <- match.arg(type)
  74. if (type == "block")
  75. container_wrapper <- divwrap
  76. else if (type == "inline")
  77. container_wrapper <- spanwrap
  78. wrapper <- function(rmd) {
  79. counter <- 0
  80. chunks <- lapply(
  81. stri_extract_all_regex(rmd$text, regex)[[1]],
  82. function(x) {
  83. counter <<- counter + 1
  84. list(code = x,
  85. label = label,
  86. type = type,
  87. name = stri_join(prefix, label, "-", counter))
  88. })
  89. if (length(chunks) == 0 || (length(chunks) == 1 && any(is.na(chunks[[1]]))))
  90. return(rmd)
  91. for (i in seq_along(chunks)) {
  92. chunks[[i]]$lineno <- stri_lineno_first_fixed(rmd$text, chunks[[i]]$code)
  93. rmd$text <- stri_replace_first_fixed(rmd$text,
  94. chunks[[i]]$code,
  95. container_wrapper(
  96. chunks[[i]]$code,
  97. chunks[[i]]$name)
  98. )
  99. }
  100. rmd$code <- c(rmd$code, chunks)
  101. rmd
  102. }
  103. class(wrapper) <- "redoc_wrapper"
  104. attr(wrapper, "args") <- list(label = label, regex = regex, type = type)
  105. return(wrapper)
  106. }
  107. #' @export
  108. #' @usage NULL
  109. #' @rdname make_wrapper
  110. htmlcommentwrap <- make_wrapper(
  111. label = "htmlcomment",
  112. regex = "(?s)<!--.*?-->",
  113. type = "inline")
  114. #' @export
  115. #' @usage NULL
  116. #' @rdname make_wrapper
  117. latexwrap <- make_wrapper(
  118. label = "latex",
  119. regex = "(?<=[\n\r])\\\\\\w+.*?(?=[\n\r])",
  120. type = "block")
  121. #' @export
  122. #' @usage NULL
  123. #' @rdname make_wrapper
  124. rawblockwrap <- make_wrapper(
  125. label = "rawblock",
  126. regex = "(?s)```\\{=\\w+\\}.*?```\\h*",
  127. type = "block")
  128. #' @export
  129. #' @usage NULL
  130. #' @rdname make_wrapper
  131. rawspanwrap <- make_wrapper(
  132. label = "rawspan",
  133. regex = "(?s)`[^`]`\\{=\\w+?\\}",
  134. type = "inline")
  135. #' @export
  136. #' @usage NULL
  137. #' @rdname make_wrapper
  138. citationwrap <- make_wrapper(
  139. label = "citation",
  140. regex = "(?:@\\w+|\\[.*?-?@\\w+.*?\\](?!\\[\\(\\{))",
  141. type = "inline")