Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get last top level command as a character string

Tags:

r

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.

like image 398
Dason Avatar asked Sep 24 '13 04:09

Dason


Video Answer


1 Answers

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.

like image 160
Thomas Avatar answered Oct 27 '22 05:10

Thomas