File: editAddin.R

package info (click to toggle)
r-cran-rhandsontable 0.3.6%2Bdfsg1-1
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 2,920 kB
  • sloc: makefile: 18; sh: 10
file content (138 lines) | stat: -rw-r--r-- 3,965 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
#' Edit a Data Frame.
#'
#' Interactively edit a \code{data.frame} or \code{data.table}. The resulting
#' code will be emitted as a call to reload the data from a temp RDS file.
#'
#' This addin can be used to interactively edit.
#' The intended way to use this is as follows:
#'
#' 1. Highlight a symbol naming a \code{data.frame} or \code{data.table}
#'    in your R session, e.g. \code{mtcars}.
#' 2. Execute this addin, to interactively edit it.
#'
#' When you're done, the code performing this operation will be emitted
#' at the cursor position.
#'
#' This function borrows heavily from \href{rstudio/addinexamples/subsetAddin}{https://github.com/rstudio/addinexamples/blob/master/R/subsetAddin.R}
#'
#' @export
editAddin <- function() {

  # Get the document context.
  context <- rstudioapi::getActiveDocumentContext()

  # Set the default data to use based on the selection.
  text <- context$selection[[1]]$text
  defaultData <- text

  # create a temp file
  fname = gsub("\\\\", "/", tempfile())

  # Generate UI for the gadget.
  ui <- miniUI::miniPage(
    miniUI::gadgetTitleBar("Edit a data.frame"),
    miniUI::miniContentPanel(
      stableColumnLayout(
        shiny::textInput("data", "Data", value = defaultData),
        shiny::radioButtons("outType", "Output type",
                            choices = c("Update original data" = "update",
                                        "Print updates to script (no update)" = "print")
        )
      ),
      shiny::uiOutput("pending"),
      rHandsontableOutput("hot")
    )
  )

  # Server code for the gadget.
  server <- function(input, output, session) {
    values = shiny::reactiveValues()
    setHot = function(x) values[["hot"]] = x

    reactiveData <- shiny::reactive({

      # Collect inputs.
      dataString <- input$data

      # Check to see if there is data called 'data',
      # and access it if possible.
      if (!nzchar(dataString))
        return(errorMessage("data", "No dataset available."))

      if (!exists(dataString, envir = .GlobalEnv))
        return(errorMessage("data", paste("No dataset named '", dataString, "' available.")))

      data <- get(dataString, envir = .GlobalEnv)

      data
    })

    output$pending <- shiny::renderUI({
      data <- reactiveData()
      if (isErrorMessage(data))
        htmltools::h4(style = "color: #AA7732;", data$message)
    })

    output$hot <- renderRHandsontable({
      data <- reactiveData()
      if (isErrorMessage(data))
        return(NULL)

      if (is.null(input$hot))
        DF = data
      else
        DF = hot_to_r(input$hot)

      setHot(DF)
      rhandsontable(DF) %>%
        hot_table(highlightCol = TRUE, highlightRow = TRUE)
    })

    # Listen for 'done'.
    shiny::observeEvent(input$done, {

      if (input$outType == "print") {
        rslt <- capture.output(dput(values[["hot"]]))
        rstudioapi::insertText(Inf, paste0(input$data, " = ",
                                           paste(rslt, collapse = "\n")))
      } else {
        if (nzchar(input$data) && !is.null(values[["hot"]])) {
          saveRDS(values[["hot"]], fname)
          code <- paste(input$data, " = readRDS('", fname, "')", sep = "")
          rstudioapi::sendToConsole(code)
        }
      }

      invisible(shiny::stopApp())
    })
  }

  # Use a modal dialog as a viewr.
  viewer <- shiny::dialogViewer("Edit", width = 1000, height = 800)
  shiny::runGadget(ui, server, viewer = viewer)

}

# these functions come from rstudio/addinexamples
stableColumnLayout <- function(...) {
  dots <- list(...)
  n <- length(dots)
  width <- 12 / n
  class <- sprintf("col-xs-%s col-md-%s", width, width)
  shiny::fluidRow(
    lapply(dots, function(el) {
      shiny::div(class = class, el)
    })
  )
}

isErrorMessage <- function(object) {
  inherits(object, "error_message")
}

errorMessage <- function(type, message) {
  structure(
    list(type = type, message = message),
    class = "error_message"
  )
}