#!/usr/bin/env Rscript
print("Hello")
# sad workaround but works :(
programDir <- dirname(sys.frame(1)$ofile)
source(paste(programDir,"other.R",sep='/'))
source(paste(programDir,"other-than-other.R",sep='/'))
this.path <- function (verbose = getOption("verbose"))
{
# loop through functions that lead here from most recent to
# earliest looking for an appropriate source call (a call to
# function source / / sys.source / / debugSource in RStudio)
#
# an appropriate source call is one in which the file argument has
# been evaluated (forced)
#
# for example, this means `source(this.path())` is an inappropriate
# source call. the argument 'file' is stored as a promise
# containing the expression "this.path()". when the value of 'file'
# is requested, the expression is evaluated at which time there
# should be two functions on the calling stack being 'source' and
# 'this.path'. clearly, you don't want to request the 'file'
# argument from that source call because the value of 'file' is
# under evaluation right now! the trick is to ask if 'file' has
# already been evaluated, the easiest way of which is to ask if a
# variable exists, one which is only created after the expression
# is necessarily evaluated.
#
# if that variable does exist, then argument 'file' has been forced
# and the source call is deemed appropriate. For 'source', the
# filename we want is the variable 'ofile' from that function's
# evaluation environment. For 'sys.source', the filename we want is
# the variable 'file' from that function's evaluation environment.
#
# if that variable does NOT exist, then argument 'file' hasn't been
# forced and the source call is deemed inappropriate. the 'for'
# loop moves to the next function up the calling stack
#
# unfortunately, there is no way to check the argument 'fileName'
# has been forced for 'debugSource' since all the work is done
# internally in C. Instead, we have to use a 'tryCatch' statement.
# When we ask for an object by name using 'get', R is capable of
# realizing if a variable is asking for its own definition (a
# recursive promise). The exact error is "promise already under
# evaluation" which indicates that the promise evaluation is
# requesting its own value. So we use the 'tryCatch' to get the
# argument 'fileName' from the evaluation environment of
# 'debugSource', and if it does not raise an error, then we are
# safe to return that value. If not, the condition returns false
# and the 'for' loop moves to the next function up the calling
# stack
debugSource <- if (.Platform$GUI == "RStudio")
get("debugSource", "tools:rstudio", inherits = FALSE)
for (n in seq.int(to = 1L, by = -1L, length.out = sys.nframe() - 1L)) {
if (identical(sys.function(n), source) &&
exists("ofile", envir = sys.frame(n), inherits = FALSE))
{
path <- get("ofile", envir = sys.frame(n), inherits = FALSE)
if (!is.character(path))
path <- summary.connection(path)$description
if (verbose)
cat("Source: call to function source\n")
return(normalizePath(path, mustWork = TRUE))
}
else if (identical(sys.function(n), sys.source) &&
exists("exprs", envir = sys.frame(n), inherits = FALSE))
{
path <- get("file", envir = sys.frame(n), inherits = FALSE)
if (verbose)
cat("Source: call to function sys.source\n")
return(normalizePath(path, mustWork = TRUE))
}
else if (identical(sys.function(n), debugSource) &&
tryCatch({
path <- get("fileName", envir = sys.frame(n), inherits = FALSE)
TRUE
}, error = function(c) FALSE))
{
if (verbose)
cat("Source: call to function debugSource in RStudio\n")
return(normalizePath(path, mustWork = TRUE))
}
}
# if the for loop is passed, no appropriate
# source call was found up the calling stack
# next, check if the user is running R from a shell
# on a Windows OS, the GUI is "RTerm"
# on a Unix OS, the GUI is "X11"
# if (running R from a shell)
if (.Platform$OS.type == "windows" && .Platform$GUI == "RTerm" || # on Windows
.Platform$OS.type == "unix" && .Platform$GUI == "X11") { # under Unix-alikes
# get all shell arguments that start with "--file="
# check the number of shell arguments starting with "--file="
# in case more or less than one were supplied
args <- commandArgs()
# remove all trailing arguments
args <- args[seq_len(length(args) - length(commandArgs(trailingOnly = TRUE)))]
# remove the first argument, the name of the executable by which this R process was invoked
args <- args[-1L]
path <- grep("^--file=", args, value = TRUE)
if (length(path) == 1L) {
path <- sub("^--file=", "", path)
if (verbose)
cat("Source: shell argument 'FILE'\n")
return(normalizePath(path, mustWork = TRUE))
}
else if (length(path)) {
stop("'this.path' used in an inappropriate fashion\n",
"* no appropriate source call was found up the calling stack\n",
"* R is being run from a shell where formal argument 'FILE' matched by multiple actual arguments")
}
else stop("'this.path' used in an inappropriate fashion\n",
"* no appropriate source call was found up the calling stack\n",
"* R is being run from a shell where argument 'FILE' is missing")
}
# if (running R from RStudio)
else if (.Platform$GUI == "RStudio") {
# ".rs.api.getActiveDocumentContext" from "tools:rstudio"
# returns a list of information about the document where your
# cursor is located
#
# ".rs.api.getSourceEditorContext" from "tools:rstudio" returns
# a list of information about the document open in the current
# tab
#
# element 'id' is a character string, an identification for the document
# element 'path' is a character string, the path of the document
context <- get(".rs.api.getActiveDocumentContext",
"tools:rstudio", inherits = FALSE)()
active <- adc[["id"]] != "#console"
if (!active) {
context <- get(".rs.api.getSourceEditorContext",
"tools:rstudio", inherits = FALSE)()
if (is.null(context))
stop("'this.path' used in an inappropriate fashion\n",
"* no appropriate source call was found up the calling stack\n",
"* R is being run from RStudio with no documents open\n",
" (or source document has no path)")
}
path <- context[["path"]]
Encoding(path) <- "UTF-8"
if (nzchar(path)) {
if (verbose)
cat(if (active)
"Source: active document in RStudio\n"
else "Source: source document in RStudio\n")
return(normalizePath(path, mustWork = TRUE))
}
else stop("'this.path' used in an inappropriate fashion\n",
"* no appropriate source call was found up the calling stack\n",
if (active)
"* active document in RStudio does not exist"
else "* source document in RStudio does not exist")
}
# if (running R from RGui on Windows)
else if (.Platform$OS.type == "windows" && .Platform$GUI == "Rgui") {
# "getWindowsHandles" from "utils" (Windows exclusive) returns
# a list of external pointers containing the windows handles.
# The thing of interest are the names of this list, these are
# the names of the windows belonging to the current R process.
# Since Rgui can have files besides R scripts open (such as
# images), a regular expression is used to subset only windows
# handles with names that start with "R Console" or end with
# " - R Editor". From there, similar checks are done as in the
# above section for 'RStudio'
x <- names(utils::getWindowsHandles(pattern = "^R Console| - R Editor$",
minimized = TRUE))
if (!length(x))
stop("no windows in Rgui; should never happen, please report!")
active <- !startsWith(x[[1L]], "R Console")
if (active)
x <- x[[1L]]
else if (length(x) >= 2L)
x <- x[[2L]]
else stop("'this.path' used in an inappropriate fashion\n",
"* no appropriate source call was found up the calling stack\n",
"* R is being run from Rgui with no documents open")
if (x == "Untitled - R Editor")
stop("'this.path' used in an inappropriate fashion\n",
"* no appropriate source call was found up the calling stack\n",
if (active)
"* active document in Rgui does not exist"
else "* source document in Rgui does not exist")
path <- sub(" - R Editor$", "", x)
if (verbose)
cat(if (active)
"Source: active document in Rgui\n"
else "Source: source document in Rgui\n")
return(normalizePath(path, mustWork = TRUE))
}
# if (running R from RGui on macOS)
else if (.Platform$OS.type == "unix" && .Platform$GUI == "AQUA") {
stop("'this.path' used in an inappropriate fashion\n",
"* no appropriate source call was found up the calling stack\n",
"* R is being run from AQUA which is currently unimplemented\n",
" consider using RStudio until such a time when this is implemented")
}
# otherwise
else stop("'this.path' used in an inappropriate fashion\n",
"* no appropriate source call was found up the calling stack\n",
"* R is being run in an unrecognized manner")
}
fun_path = tryCatch(expr =
{file.path(dirname(sys.frame(1)$ofile), "foo.R")},
error = function(e){'foo.R'}
)
if(!file.exists(fun_path))
{
msg = 'Please select "foo.R"'
# ask user to find data
if(Sys.info()[['sysname']] == 'Windows'){#choose.files is only available on Windows
message('\n\n',msg,'\n\n')
Sys.sleep(0.5)#goes too fast for the user to see the message on some computers
fun_path = choose.files(
default = file.path(gsub('\\\\', '/', Sys.getenv('USERPROFILE')),#user
'Documents'),
caption = msg
)
}else{
message('\n\n',msg,'\n\n')
Sys.sleep(0.5)#goes too fast for the user to see the message on some computers
fun_path = file.choose(new=F)
}
}
#source the function
source(file = fun_path,
encoding = 'UTF-8')