🔍 An RStudio addin slash regex utility belt
Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

230 linhas
6.3KB

  1. #' regexplain_addin
  2. #'
  3. #' @keywords internal
  4. regexplain_addin <- function() {
  5. # Get the document context.
  6. context <- rstudioapi::getActiveDocumentContext()
  7. # Get context text
  8. ctx_text <- context$selection[[1]]$text
  9. # If it is one line and evaluates to something, use that
  10. # Otherwise treat as text
  11. obj <- tryCatch({
  12. if (grepl("\n", ctx_text)) {
  13. ctx_text
  14. } else {
  15. x <- eval(parse(text = ctx_text))
  16. x <- as.character(x)
  17. if (length(x) == 1 && grepl("\n", x))
  18. x <- strsplit(x, "\n")[[1]]
  19. if (length(x) > 10) {
  20. message(ctx_text, " gave ", length(x), " lines, limiting to first 10 unique lines.")
  21. x <- unique(x)
  22. x[1:min(length(x), 10)]
  23. } else x
  24. }
  25. },
  26. error = function(e) {as.character(ctx_text)})
  27. regex_gadget(obj)
  28. }
  29. #' regexplain gadget
  30. #'
  31. #' @import miniUI
  32. #' @import shiny
  33. #' @export
  34. regex_gadget <- function(text = NULL) {
  35. stopifnot(requireNamespace("miniUI"), requireNamespace("shiny"))
  36. ui <- miniPage(
  37. shiny::includeCSS(system.file("style.css", package = "regexplain")),
  38. gadgetTitleBar(
  39. "regexplain",
  40. right = miniTitleBarButton("done", "To Console", TRUE)
  41. ),
  42. miniTabstripPanel(
  43. selected = if (is.null(text)) "Text" else "Regex",
  44. miniTabPanel(
  45. "Text", icon = icon('file-text-o'),
  46. miniContentPanel(
  47. fillCol(
  48. textAreaInputAlt('text', label = "Text", value = paste(text, collapse = "\n"), resize = "both", width = "100%", height="90%")
  49. )
  50. )
  51. ),
  52. miniTabPanel(
  53. "Regex", icon = icon('terminal'),
  54. miniContentPanel(
  55. fillCol(
  56. flex = c(1, 3),
  57. fillCol(
  58. flex = c(1, 1),
  59. textInputCode('pattern', 'Regex', width = "90%",
  60. placeholder = "Enter regex, single \\ okay"),
  61. checkboxGroupInput(
  62. 'regex_options',
  63. label = "",
  64. inline = TRUE,
  65. width = "90%",
  66. choices = c("Break Lines" = "text_break_lines",
  67. "Ignore Case" = "ignore.case",
  68. "Perl Style" = "perl",
  69. "Fixed" = "fixed",
  70. "Use Bytes" = "useBytes"
  71. # , "Invert" = "invert"
  72. ),
  73. selected = c('text_break_lines')
  74. )
  75. ),
  76. tags$div(
  77. class = "gadget-result",
  78. htmlOutput('result')
  79. )
  80. )
  81. )
  82. ),
  83. miniTabPanel(
  84. "Output", icon = icon("table"),
  85. miniContentPanel(
  86. fillCol(
  87. flex = c(1, 3),
  88. inputPanel(
  89. width = "100%;",
  90. selectInput('regexFn', label = 'Apply Function',
  91. choices = regexFn_choices)
  92. ),
  93. verbatimTextOutput('output_result',
  94. placeholder = TRUE)
  95. )
  96. )
  97. ),
  98. miniTabPanel(
  99. "Help", icon = icon("support"),
  100. miniContentPanel(
  101. tags$p("Help will go here.")
  102. )
  103. )
  104. )
  105. )
  106. server <- function(input, output, session) {
  107. rtext <- reactive({
  108. x <- if ('text_break_lines' %in% input$regex_options) {
  109. strsplit(input$text, "\n")[[1]]
  110. } else input$text
  111. x
  112. })
  113. output$result <- renderUI({
  114. if (is.null(rtext())) return(NULL)
  115. if (input$pattern == "") {
  116. return(toHTML(paste('<p class="results">', escape_html(rtext()), "</p>", collapse = "")))
  117. }
  118. tryCatch({
  119. toHTML(
  120. paste(
  121. view_regex(
  122. rtext(),
  123. sanitize_text_input(input$pattern),
  124. ignore.case = 'ignore.case' %in% input$regex_options,
  125. perl = 'perl' %in% input$regex_options,
  126. fixed = 'fixed' %in% input$regex_options,
  127. useBytes = 'useBytes' %in% input$regex_options,
  128. # invert = 'invert' %in% input$regex_options,
  129. render = FALSE,
  130. escape = TRUE),
  131. collapse = ""
  132. )
  133. )
  134. },
  135. error = function(e) {
  136. toHTML(paste0("<pre class='alert alert-danger' style='padding: 4px; margin-top: 1px; margin-bottom: 4px;'>", paste(e$message, collapse = "<br>"), "</pre>"),
  137. paste('<p class="results">', escape_html(rtext()), "</p>", collapse = ""))
  138. })
  139. })
  140. output$output_result <- renderPrint({
  141. req(input$regexFn)
  142. regexPkg <- get_pkg_namespace(input$regexFn)
  143. regexFn <- getFromNamespace(input$regexFn, regexPkg)
  144. x <- if (regexPkg == "base") {
  145. regexFn(input$pattern, rtext())
  146. } else if (regexPkg == "stringr") {
  147. regexFn(rtext(), input$pattern)
  148. } else {
  149. "Um. Not sure how I got here."
  150. }
  151. # if (inherits(x, 'logical') || inherits(x, 'character')) {
  152. # if (length(x) < 25) print(x) else print(head(x, 25))
  153. # } else if (inherits(x, 'matrix') | inherits(x, "data.frame")) {
  154. # if (nrow(x) < 15) { print(x)
  155. # } else glimpse(x)
  156. # } else {
  157. # str(x, max.level = 3)
  158. # }
  159. print(x)
  160. })
  161. observeEvent(input$done, {
  162. # browser()
  163. if (input$pattern != "") {
  164. pattern <- paste0('regex <- "', escape_backslash(sanitize_text_input(input$pattern)), '"')
  165. rstudioapi::sendToConsole(pattern, FALSE)
  166. }
  167. stopApp()
  168. })
  169. observeEvent(input$cancel, {
  170. stopApp()
  171. })
  172. }
  173. viewer <- shiny::paneViewer(700)
  174. runGadget(ui, server, viewer = viewer)
  175. }
  176. sanitize_text_input <- function(x) {
  177. x <- gsub("(“|”)", '"', x)
  178. x <- gsub("‘|’", "'", x)
  179. x
  180. }
  181. toHTML <- function(...) {
  182. x <- paste(..., collapse = "")
  183. x <- gsub("\n", "\\\\n", x)
  184. x <- gsub("\t", "\\\\t", x)
  185. x <- gsub("\r", "\\\\r", x)
  186. HTML(x)
  187. }
  188. regexFn_choices <- list(
  189. "Choose a function" = "",
  190. base = c(
  191. "grep",
  192. "grepl",
  193. "regexpr",
  194. "gregexpr",
  195. "regexec"
  196. ),
  197. stringr = c(
  198. "str_detect",
  199. "str_locate",
  200. "str_locate_all",
  201. "str_extract",
  202. "str_extract_all",
  203. "str_match",
  204. "str_match_all",
  205. "str_split"
  206. )
  207. )
  208. get_pkg_namespace <- function(fn) {
  209. x <- names(purrr::keep(regexFn_choices, ~ (fn %in% .)))
  210. if (length(x) > 1) warning(fn, " matches multiple functions in regexFn_choices, please review.")
  211. x
  212. }