🔍 An RStudio addin slash regex utility belt
Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

171 lines
5.1KB

  1. #' @import miniUI
  2. #' @import shiny
  3. regex_gadget <- function(text = NULL) {
  4. library("shiny")
  5. library("miniUI")
  6. ui <- miniPage(
  7. shiny::includeCSS(system.file("style.css", package = "regexplain")),
  8. gadgetTitleBar(
  9. "regexplain",
  10. right = miniTitleBarButton("done", "To Console", TRUE)
  11. ),
  12. miniTabstripPanel(
  13. selected = if (is.null(text)) "Text" else "Regex",
  14. miniTabPanel(
  15. "Text", icon = icon('file-text-o'),
  16. miniContentPanel(
  17. fillCol(
  18. flex = c(3, 1),
  19. textAreaInputAlt('text', label = "Text", value = paste(text, collapse = "\n"), resize = "both", width = "100%", height="90%"),
  20. inputPanel(
  21. checkboxInput('text_break_newline', "Break Lines", TRUE)
  22. )
  23. )
  24. )
  25. ),
  26. miniTabPanel(
  27. "Regex", icon = icon('terminal'),
  28. miniContentPanel(
  29. textInputCode('pattern', 'Regex', width = "100%",
  30. placeholder = "Enter regex, double backslash not required"),
  31. htmlOutput('result')
  32. )
  33. ),
  34. miniTabPanel(
  35. "Help", icon = icon("support"),
  36. miniContentPanel(
  37. tags$p("Help will go here.")
  38. )
  39. )
  40. )
  41. )
  42. server <- function(input, output, session) {
  43. rtext <- reactive({
  44. x <- if (input$text_break_newline) {
  45. strsplit(input$text, "\n")[[1]]
  46. } else input$text
  47. x
  48. })
  49. output$result <- renderUI({
  50. if (is.null(rtext())) return(NULL)
  51. if (input$pattern == "") {
  52. return(toHTML(paste('<p class="results">', rtext(), "</p>", collapse = "")))
  53. }
  54. tryCatch({
  55. toHTML(
  56. paste(
  57. view_regex(rtext(), sanitize_text_input(input$pattern), render = FALSE),
  58. collapse = ""
  59. )
  60. )
  61. },
  62. error = function(e) {
  63. toHTML(paste0("<pre class='alert alert-danger' style='padding: 4px; margin-top: 1px; margin-bottom: 4px;'>", paste(e$message, collapse = "<br>"), "</pre>"),
  64. paste('<p class="results">', rtext(), "</p>", collapse = ""))
  65. })
  66. })
  67. observeEvent(input$done, {
  68. # browser()
  69. if (input$pattern != "") {
  70. pattern <- paste0('regex <- "', escape_backslash(sanitize_text_input(input$pattern)), '"')
  71. rstudioapi::sendToConsole(pattern, FALSE)
  72. }
  73. stopApp()
  74. })
  75. observeEvent(input$cancel, {
  76. stopApp()
  77. })
  78. }
  79. viewer <- shiny::paneViewer(700)
  80. runGadget(ui, server, viewer = viewer)
  81. }
  82. sanitize_text_input <- function(x) {
  83. x <- gsub("(“|”)", '"', x)
  84. x <- gsub("‘|’", "'", x)
  85. x
  86. }
  87. toHTML <- function(...) {
  88. x <- paste(..., collapse = "")
  89. x <- gsub("\n", "\\\\n", x)
  90. HTML(x)
  91. }
  92. # ---- Modified Shiny Inputs ----
  93. #' Modified Text Area Input
  94. #'
  95. #' @inheritParams shiny textAreaInput
  96. textAreaInputAlt <- function(inputId, label, value = "", width = NULL, height = NULL,
  97. cols = NULL, rows = NULL, placeholder = NULL, resize = NULL,
  98. is_code = TRUE) {
  99. `%AND%` <- shiny:::`%AND%`
  100. value <- shiny::restoreInput(id = inputId, default = value)
  101. if (!is.null(resize)) {
  102. resize <- match.arg(resize, c("both", "none", "vertical", "horizontal"))
  103. }
  104. style <- paste(
  105. if (!is.null(width)) paste0("width: ", shiny::validateCssUnit(width), ";"),
  106. if (!is.null(height)) paste0("height: ", shiny::validateCssUnit(height), ";"),
  107. if (!is.null(resize)) paste0("resize: ", resize, ";"),
  108. if (is_code) 'font-family: "Monaco", "Inconsolata", monospace;'
  109. )
  110. parent_style <- paste(
  111. if (!is.null(width) && grepl("%", width)) paste0("width: ", width, ";"),
  112. if (!is.null(height) && grepl("%", height)) paste0("height: ", height, ";")
  113. )
  114. # Workaround for tag attribute=character(0) bug:
  115. # https://github.com/rstudio/htmltools/issues/65
  116. if (length(style) == 0) style <- NULL
  117. shiny::div(class = "form-group shiny-input-container",
  118. label %AND% shiny::tags$label(label, `for` = inputId),
  119. style = if (!parent_style %in% c(" ", "", " ")) parent_style,
  120. shiny::tags$textarea(
  121. id = inputId,
  122. class = "form-control",
  123. placeholder = placeholder,
  124. style = style,
  125. rows = rows,
  126. cols = cols,
  127. autocomplete = "off",
  128. autocorrect = "off",
  129. autocapitalize = "off",
  130. spellcheck = "false",
  131. value
  132. )
  133. )
  134. }
  135. #' Modified Text Input
  136. #'
  137. #' @inheritParams shiny textInput
  138. textInputCode <- function(inputId, label, value = "", width = NULL,
  139. placeholder = NULL) {
  140. `%AND%` <- shiny:::`%AND%`
  141. value <- shiny::restoreInput(id = inputId, default = value)
  142. shiny::div(class = "form-group shiny-input-container",
  143. style = if (!is.null(width)) paste0("width: ", shiny::validateCssUnit(width), ";"),
  144. label %AND% shiny::tags$label(label, `for` = inputId),
  145. shiny::tags$input(id = inputId, type="text", class="form-control", value=value,
  146. style = 'font-family: "Monaco", "Inconsolata", monospace;',
  147. autocomplete = "off", autocorrect = "off",
  148. autocapitalize = "off", spellcheck = "false",
  149. placeholder = placeholder)
  150. )
  151. }