R/code.R

Defines functions toolsEnv toolsName usingTools findFun hasFun callFun getMode getVersion verifyAvailable version_ok isAvailable

Documented in callFun findFun getMode getVersion hasFun isAvailable verifyAvailable

#' Check if RStudio is running
#'
#' Check if RStudio is running.
#'
#' @aliases isAvailable verifyAvailable
#'
#' @param version_needed An optional version specification. If supplied, ensures
#'   that RStudio is at least that version.
#'
#' @param child_ok Boolean; check if the current R process is a child process of
#'   the main RStudio session? This can be useful for e.g. RStudio Jobs, where
#'   you'd like to communicate back with the main R session from a child process
#'   through \code{rstudioapi}.
#'
#' @return \code{isAvailable} a boolean; \code{verifyAvailable} an error message
#'   if RStudio is not running
#'
#' @examples
#'
#' rstudioapi::isAvailable()
#' \dontrun{rstudioapi::verifyAvailable()}
#'
#' @export
isAvailable <- function(version_needed = NULL, child_ok = FALSE) {

  if (child_ok && isJob())
    return(callRemote(sys.call(), parent.frame()))

  identical(.Platform$GUI, "RStudio") && version_ok(version_needed)

}

version_ok <- function(version = NULL) {
  if (is.null(version)) return(TRUE)

  getVersion() >= version
}

#' @rdname isAvailable
#' @export
verifyAvailable <- function(version_needed = NULL) {
  if (!isAvailable()) stop("RStudio not running", call. = FALSE)
  if (!version_ok(version_needed)) {
    stop("Need at least version ", version_needed, " of RStudio. ",
      "Currently running ", getVersion(), call. = FALSE)
  }
  invisible(TRUE)
}



#' Determine the version of RStudio
#'
#' Use `getVersion()` to determine the current version of RStudio.
#' This can be useful for \R packages which need to gate certain functionality
#' based on the version of RStudio currently available.
#'
#' @returns A `"numeric_version"` object, giving the version of RStudio in use.
#'
#' @export
getVersion <- function() {

  # use API if available
  if (hasFun("getVersion"))
    return(callFun("getVersion"))

  # use fallback if not
  verifyAvailable()
  base <- .BaseNamespaceEnv
  version <- base$.Call("rs_rstudioVersion", PACKAGE = "(embedding)")
  package_version(version)

}

#' Report whether RStudio Desktop or RStudio Server is in use
#'
#' Use `getMode()` if you need to differentiate between server
#' and desktop installations of RStudio.
#'
#' @returns "desktop" for RStudio Desktop installations, and
#'   "server" for RStudio Server / RStudio Workbench installations.
#'
#' @export
getMode <- function() {

  # use API if available
  if (hasFun("getMode"))
    return(callFun("getMode"))

  # use fallback if not
  verifyAvailable()
  rstudio <- as.environment("tools:rstudio")
  if (rstudio$.rs.isDesktop()) "desktop" else "server"

}


#' Call an RStudio API function
#'
#' This function will return an error if RStudio is not running, or the
#' function is not available. If you want to fall back to different behavior,
#' use \code{\link{hasFun}}.
#'
#'
#' @param fname name of the RStudio function to call.
#' @param ... Other arguments passed on to the function
#' @examples
#'
#' if (rstudioapi::isAvailable()) {
#'   rstudioapi::callFun("versionInfo")
#' }
#'
#' @export callFun
callFun <- function(fname, ...) {

  if (isJob())
    return(callRemote(sys.call(), parent.frame()))

  verifyAvailable()

  # get reference to RStudio function
  f <- tryCatch(findFun(fname, mode = "function"), error = identity)
  if (inherits(f, "error"))
    stop("Function ", fname, " not found in RStudio", call. = FALSE)

  # drop arguments that aren't accepted by RStudio
  # (ensure backwards-compatibility with older versions of RStudio)
  args <- list(...)
  if (!"..." %in% names(formals(f)))
    if (length(args) > length(formals(f)))
      length(args) <- length(formals(f))

  # invoke the function
  do.call(f, args)

}



#' Exists/get for RStudio functions
#'
#' These are specialized versions of \code{\link[base]{get}} and
#' \code{\link[base]{exists}} that look in the rstudio package namespace. If
#' RStudio is not running, \code{hasFun} will return \code{FALSE}.
#'
#'
#' @aliases hasFun findFun
#' @param name name of object to look for
#' @param version_needed An optional version specification. If supplied,
#' ensures that RStudio is at least that version. This is useful if function
#' behavior has changed over time.
#' @param ... other arguments passed on to \code{\link[base]{exists}} and
#' \code{\link[base]{get}}
#' @examples
#'
#' rstudioapi::hasFun("viewer")
#'
#' @export hasFun
hasFun <- function(name, version_needed = NULL, ...) {

  if (!isAvailable(version_needed))
    return(FALSE)

  if (usingTools())
    return(exists(toolsName(name), toolsEnv(), ...))

  exists(name, envir = asNamespace("rstudio"), ...)

}

#' @export
#' @rdname hasFun
findFun <- function(name, version_needed = NULL, ...) {
  verifyAvailable(version_needed)
  if (usingTools())
    get(toolsName(name), toolsEnv(), ...)
  else
    get(name, envir = asNamespace("rstudio"), ...)
}

usingTools <- function() {
  exists(toolsName("versionInfo"), envir = toolsEnv())
}

toolsName <- function(name) {
  paste(".rs.api.", name, sep="")
}

toolsEnv <- function() {
  as.environment(match("tools:rstudio", search()))
}

Try the rstudioapi package in your browser

Any scripts or data that you put into this service are public.

rstudioapi documentation built on Oct. 23, 2024, 1:07 a.m.