Is there a way to get the last top level command stored into a character string without saving the history to a file and reading it back in just to grab the last command? I have code for that
lastcmd <- function(){
tmp <- tempfile()
savehistory(tmp)
# If we call this function then that call will
# be the last line in the history so we want the one
# before that
tail(readLines(tmp), 2)[1]
}
and this isn't too bad but I was wondering if there was a way to get the history as characters without first writing to a file.
This is a good use-case for a task callback. Basically, you can register a callback that will store the last top-level expression in a variable, which you can then subsequently access.
.lastcall <- NULL # create an empty variable to store into
# register your callback
addTaskCallback(function(expr,value,ok,visible) {
assign(".lastcall", as.character(substitute(expr))[2], .GlobalEnv)
TRUE},
name='storelast')
# storelast
# 1
# check the callback on a bunch of things
2+2
# [1] 4
.lastcall
# [1] "2 + 2"
1:4
# [1] 1 2 3 4
.lastcall
# [1] "1:4"
matrix(1:4, nrow=2)
# [,1] [,2]
# [1,] 1 3
# [2,] 2 4
.lastcall
# [1] "matrix(1:4, nrow = 2)"
a <- 2; b <- 3
.lastcall
# [1] "b <- 3"
# cleanup everything; check that everything is cleaned up
removeTaskCallback('storelast')
# [1] TRUE
2+2
# [1] 4
.lastcall # confirm 2+2 was not stored as .lastcall
# [1] ".lastcall"
rm(.lastcall)
.lastcall
# Error: object '.lastcall' not found
You could also write the callback function so that it simply adds the last call to a vector (or a list or whatever) so that you build a full command history:
.lastcall <- character() # create an empty variable to store into
# register your callback
addTaskCallback(function(expr,value,ok,visible) {
assign(".lastcall",
append(.lastcall, as.character(substitute(expr))[2]),
.GlobalEnv)
TRUE},
name='storelast')
# storelast
# 1
# check the callback on a bunch of things
2+2
# [1] 4
.lastcall
# [1] "addTaskCallback(function(expr, value, ok, visible) {\n assign(\".lastcall\", append(.lastcall, as.character(substitute(expr))[2]), .GlobalEnv)\n TRUE\n}, name = \"storelast\")"
# [2] "2 + 2"
1:4
# [1] 1 2 3 4
.lastcall
# [1] "addTaskCallback(function(expr, value, ok, visible) {\n assign(\".lastcall\", append(.lastcall, as.character(substitute(expr))[2]), .GlobalEnv)\n TRUE\n}, name = \"storelast\")"
# [2] "2 + 2"
# [3] ".lastcall"
# [4] "1:4"
matrix(1:4, nrow=2)
# [,1] [,2]
# [1,] 1 3
# [2,] 2 4
.lastcall
# [1] "addTaskCallback(function(expr, value, ok, visible) {\n assign(\".lastcall\", append(.lastcall, as.character(substitute(expr))[2]), .GlobalEnv)\n TRUE\n}, name = \"storelast\")"
# [2] "2 + 2"
# [3] ".lastcall"
# [4] "1:4"
# [5] ".lastcall"
# [6] "matrix(1:4, nrow = 2)"
a <- 2; b <- 3
.lastcall
# [1] "addTaskCallback(function(expr, value, ok, visible) {\n assign(\".lastcall\", append(.lastcall, as.character(substitute(expr))[2]), .GlobalEnv)\n TRUE\n}, name = \"storelast\")"
# [2] "2 + 2"
# [3] ".lastcall"
# [4] "1:4"
# [5] ".lastcall"
# [6] "matrix(1:4, nrow = 2)"
# [7] ".lastcall"
# [8] "a <- 2"
# [9] "b <- 3"
# cleanup everything; check that everything is cleaned up
removeTaskCallback('storelast')
# [1] TRUE
2+2
# [1] 4
.lastcall # confirm 2+2 was not added to .lastcall
# [1] "addTaskCallback(function(expr, value, ok, visible) {\n assign(\".lastcall\", append(.lastcall, as.character(substitute(expr))[2]), .GlobalEnv)\n TRUE\n}, name = \"storelast\")"
# [2] "2 + 2"
# [3] ".lastcall"
# [4] "1:4"
# [5] ".lastcall"
# [6] "matrix(1:4, nrow = 2)"
# [7] ".lastcall"
# [8] "a <- 2"
# [9] "b <- 3"
# [10] ".lastcall"
rm(.lastcall)
.lastcall
# Error: object '.lastcall' not found
Remember with task callbacks, though, that it's really important that you cleanup after yourself with removeTaskCallback
(or you can write the callback function to remove itself after some condition is satisfied; see ?addTaskCallback
for an example of that) otherwise .lastcall
will linger around in your environment forever and keep being updated unnecessarily.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With