🔍 An RStudio addin slash regex utility belt
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

178 lines
5.4KB

  1. #' RegExplain gadget
  2. #'
  3. #' The function behind the RegExplain Selection and RegExplain File
  4. #' addins. Opens the RegExplain gadget interface in an RStudio viewer
  5. #' pane.
  6. #'
  7. #' @import miniUI
  8. #' @import shiny
  9. #' @param text Text to explore in gadget (editable using interface)
  10. #' @param pattern Regular Expression to edit or visualize using RegExplain
  11. #' @param start_page Open gadget to this tab, one of `"Text"`, `"RegEx"`,
  12. #' `"Output"`, or `"Help"`
  13. #' @export
  14. regexplain_gadget <- function(
  15. text = NULL,
  16. pattern = NULL,
  17. start_page = if (is.null(text)) "Text" else "RegEx"
  18. ) {
  19. stopifnot(requireNamespace("miniUI"), requireNamespace("shiny"))
  20. viewer <- shiny::paneViewer(minHeight = 800)
  21. runGadget(
  22. regexplain_gadget_ui(text, pattern, start_page),
  23. regexplain_gadget_server(check_version()),
  24. viewer = viewer)
  25. }
  26. #' @describeIn regexplain_gadget Launches the RegExplain gadget in a browser or an
  27. #' RStduio viewer pane.
  28. #' @inheritDotParams shiny::shinyApp
  29. #' @export
  30. regexplain_web <- function(text = NULL, pattern = NULL, start_page = "Text", ...) {
  31. stopifnot(requireNamespace("miniUI"), requireNamespace("shiny"))
  32. shinyApp(
  33. regexplain_gadget_ui(text, pattern, start_page),
  34. regexplain_gadget_server(check_version()), ...)
  35. }
  36. # ---- Gadget Helper Functions and Variables ----
  37. sanitize_text_input <- function(x) {
  38. if (is.null(x) || !nchar(x)) return(x)
  39. rx_unicode <- "\\\\u[0-9a-f]{4,8}"
  40. rx_hex <- "\\\\x[0-9a-f]{2}|\\\\x\\{[0-9a-f]{1,6}\\}"
  41. rx_octal <- "\\\\[0][0-7]{1,3}"
  42. rx_escape <- paste(rx_unicode, rx_hex, rx_octal, sep = "|")
  43. if (grepl(rx_escape, x, ignore.case = TRUE)) {
  44. try({
  45. y <- stringi::stri_unescape_unicode(x)
  46. }, silent = TRUE)
  47. if (!is.na(y)) x <- y
  48. }
  49. # x <- gsub("\u201C|\u201D", '"', x)
  50. # x <- gsub("\u2018|\u2019", "'", x)
  51. x
  52. }
  53. toHTML <- function(...) {
  54. x <- paste(..., collapse = "")
  55. x <- gsub("\n", "\\\\n", x)
  56. x <- gsub("\t", "\\\\t", x)
  57. x <- gsub("\r", "\\\\r", x)
  58. HTML(x)
  59. }
  60. regexFn_choices <- list(
  61. "Choose a function" = "",
  62. base = c(
  63. "grep",
  64. "grepl",
  65. "sub", #<<
  66. "gsub", #<<
  67. "regexpr",
  68. "gregexpr",
  69. "regexec"
  70. ),
  71. stringr = c(
  72. "str_detect",
  73. "str_locate",
  74. "str_locate_all",
  75. "str_extract",
  76. "str_extract_all",
  77. "str_match",
  78. "str_match_all",
  79. "str_replace", #<<
  80. "str_replace_all", #<<
  81. "str_split"
  82. ),
  83. "rematch2" = c(
  84. "re_match",
  85. "re_match_all",
  86. "re_exec",
  87. "re_exec_all"
  88. )
  89. )
  90. regexFn_substitute <- c(
  91. paste0(c("", "g"), "sub"),
  92. paste0("str_replace", c("", "_all"))
  93. )
  94. get_pkg_namespace <- function(fn) {
  95. x <- names(purrr::keep(regexFn_choices, ~ (fn %in% .)))
  96. if (length(x) > 1) warning(fn, " matches multiple functions in regexFn_choices, please review.")
  97. x
  98. }
  99. #' Check if an updated version is available
  100. #'
  101. #' I included this because it can be difficult to tell if your RStudio Addins
  102. #' are up to date. I may add new features that you want but you won't hear about
  103. #' the updates. This function checks if an update is available, using GitHub
  104. #' tags. If an update is available, a modal dialog is shown when you start
  105. #' the regexplain gadget. This only happens once per R session, though, so feel
  106. #' free to ignore the message.
  107. #'
  108. #' @param gh_user GitHub user account
  109. #' @param gh_repo GitHub repo name
  110. #' @param this_version The currently installed version of the package
  111. #' @keywords internal
  112. check_version <- function(
  113. gh_user = "gadenbuie",
  114. gh_repo = "regexplain",
  115. this_version = packageVersion('regexplain')
  116. ) {
  117. ok_to_check <- getOption("regexplain.no.check.version", TRUE)
  118. if (!isTRUE(ok_to_check)) return(NULL)
  119. if (!requireNamespace('jsonlite', quietly = TRUE)) return(NULL)
  120. get_json <- purrr::possibly(jsonlite::fromJSON, NULL)
  121. gh_tags <- get_json(
  122. paste0("https://api.github.com/repos/", gh_user, "/", gh_repo, "/git/refs/tags"),
  123. simplifyDataFrame = TRUE
  124. )
  125. if (!is.null(gh_tags)) {
  126. gh_tags$tag <- sub("refs/tags/", "", gh_tags$ref, fixed = TRUE)
  127. gh_tags$version <- sub("^v\\.?", "", gh_tags$tag)
  128. }
  129. if (!is.null(gh_tags) && any(gh_tags$version > this_version)) {
  130. max_version <- max(gh_tags$version)
  131. max_tag <- gh_tags$tag[gh_tags$version == max_version]
  132. options(regexplain.no.check.version = FALSE)
  133. return(
  134. list(
  135. version = max_version,
  136. link = paste("https://github.com", gh_user, gh_repo, "releases/tag", max_tag, sep = "/")
  137. )
  138. )
  139. } else return(NULL)
  140. }
  141. #' Loads Regex Pattern Library
  142. #'
  143. #' Patterns sourced from [Regex Hub](https://projects.lukehaas.me/regexhub)
  144. #' are available at <https://github.com/lukehaas/RegexHub> and are copyright
  145. #' Luke Haas licensed under the MIT license available at
  146. #' <https://github.com/lukehaas/RegexHub/commit/3ab87b5a4fd2817b42e2e45dcf040d4f0164ea37>.
  147. #' Patterns source from [qdapRegex](https://github.com/trinker/qdapRegex) are
  148. #' copyright Tyler Rinker and Jason Gray, licensed under the GPL-2 license.
  149. #'
  150. #' @keywords internal
  151. get_regex_library <- function() {
  152. if (!requireNamespace("jsonlite")) {
  153. warning("Please install the `jsonlite` package to use template features")
  154. return(NULL)
  155. }
  156. f_patterns <- system.file("extdata", "patterns.json", package = "regexplain")
  157. if (!file.exists(f_patterns)) return(NULL)
  158. patterns <- jsonlite::fromJSON(
  159. f_patterns,
  160. simplifyVector = FALSE,
  161. simplifyDataFrame = FALSE,
  162. simplifyMatrix = FALSE
  163. )
  164. patterns <- purrr::keep(patterns, ~ .$name != "")
  165. patterns[order(purrr::map_chr(patterns, 'name'))]
  166. }