Access/manipulate history stack in R (up/down arrow) - r

I am working on a little interactive shell-like tool in R that uses readline to prompt stdin, like this:
console <- function(){
while(nchar(input <- readline(">>> "))) {
message("You typed: ", input)
}
}
It works but the only thing that bothers me is that lines entered this way do not get pushed upon the history stack. Pressing the up-arrow in R gives the last R command that was entered before starting the console.
Is there any way I can manually push the input lines upon the history stack, such that pressing the up-arrow will show the latest line entered in the console function?

I use this in rite to add commands to the command history. In essence, you can just savehistory and loadhistory from a local file. I do:
tmphistory <- tempfile()
savehistory(tmphistory)
histcon <- file(tmphistory, open="a")
writeLines(code, histcon)
close(histcon)
loadhistory(tmphistory)
unlink(tmphistory)
Note: Mac doesn't use history in the same way as other OS's, so be careful with this.

Related

How to automatically enter input in readline() instead of manually entering it at the console in R?

I have a readline() function in a for loop
For Simplicity let's say I have this code:
x <- character()
for (i in 1:500) x[i] <- readline('Enter Value')
How can I automatically enter input instead of manually entering it at the console 500 times?
readline() isn't intended for automatic input. From ?readline:
Description
readline reads a line from the terminal (in interactive use).
and:
Details
The prompt string will be truncated to a maximum allowed length,
normally 256 chars (but can be changed in the source code).
This can only be used in an interactive session.
Looking at ?interactive we can read the following:
An interactive R session is one in which it is assumed that there is a
human operator to interact with, so for example R can prompt for
corrections to incorrect input or ask what to do next or if it is OK
to move to the next plot.
So, basically you are trying to use readline for something it isn't intended for.
You can vectorize this command, assuming you're looking to fill the column with the same value. If that's not what you're trying to do, I'm confused as to what you want. Run my example below and say whether that's the kind of thing you're looking for
working <- iris
head(working)
working$like <- readline("Do you like this flower? ")
head(working)

.Rprofile's search path is not the same as the default one

Consider the two lines below:
Sys.setenv(R_IMPORT_PATH = "/path/to/my/r_import")
foo <- modules::import("foo")
If I execute this code from within an already-established interactive R session, it works fine.
But if I put the same two lines in my .Rprofile and start a new interactive R session, the modules::import line fails with
Error in module_init_files(module, module_path) :
could not find function "setNames"
If I then attempt the following fix/hack
Sys.setenv(R_IMPORT_PATH = "/path/to/my/r_import")
library(stats)
foo <- modules::import("foo")
...then the modules::import line still fails, but with the following
Error in lapply(x, f) : could not find function "lsf.str"
So the idea of patching the missing names seems like it will be an unmaintainable nightmare...
The crucial issue is this: It appears that the search path right after an interactive search session starts is different from the one that an .Rprofile script sees.
Q1: Is there a way that I can tell R to make the search path exactly as it will be when the first > prompt appears in the interactive session?
Q2: Alternatively, is there a way for the .Rprofile to schedule some code to run after the session's default search path is in place?
NB: Solutions like the following:
Sys.setenv(R_IMPORT_PATH = "/path/to/my/r_import")
library(stats)
library(utils)
foo <- modules::import("foo")
...are liable to break every time that the (third-party) modules package is modified.

use readLines() in R without waiting for an ENTER

I am working on a small Rscript that has a readLines function:
n <- readLines("stdin",n=1);
if (n =="y"){ ... }
I want to know if there is a way for R to go to the next part of the script without waiting for me to hit the ENTER button after I gave the input. In my script I only care whether I type in "n" or not.

Make R wait for console input?

Is there a way to make R wait for console input before continuing?
Let's say I source two scripts like this in a main script called run.R:
# some more R Code here
source("script1.R")
source("script2.R")
# some more R Code there
Script1 contains some readLine statement that asks the user for a username.
Unfortunately if I just run the entire run.R file R doesn't wait for the username to be entered. It starts script2.R before the username is entered which leads to an error because the 2nd script needs the username.
I have an ugly workaround for this using R Studio's .rs.askForPassword which actually waits for the the input, but covers the password. Which is cool for passwords, but not so much for usernames. Plus it's an RStudio feature, not R.
readline can only be used in interactive sessions. In non-interactive use of readline the result is an empty string. On the help page of ?interactive you find the following about interactive sessions:
GUI consoles will arrange to start R in an interactive session. When R
is run in a terminal (via Rterm.exe on Windows), it assumes that it is
interactive if ‘stdin’ is connected to a (pseudo-)terminal and not if
‘stdin’ is redirected to a file or pipe. Command-line options
--interactive (Unix) and --ess (Windows, Rterm.exe) override the default assumption.
Try scan function.
This is test.R file:
y <- 2
cat('y=',y)
cat("\nEnter username")
x <- scan(what=character(),nmax=1,quiet=TRUE)
"ala ma kota"
y <- 2*2
cat('y=',y)
cat('\nx=',x)
and then I run this:
> source("test.R")
y= 2
Enter username
1: login
y= 4
x= login
--edit--
To read only one character quietly run this:
> x <- scan(what=character(),nmax=1,quiet=TRUE)
1: username
> x
[1] "username"
what sets the type, nmax sets the maximal numbers of elements to read and quiet determine if print a line, saying how many items have been read.
Why not putting
source("script2.R")
into the file script1.R?

Making a series of plots that proceed by a click

In the example below I would like to be able to control when I go to the next plot by a using mouse click (or keyboard entry)
for (i in 1:5){
plot(1:i)
Sys.sleep(1)
#add something here that requests mouse click to proceed
}
Is this possible? There is a setting in the X11() help file caled 'clickToConfirm' but I can't work out what that does.
It would also be helpful to me to be to be able to scroll back and forth through plots using the arrow keys. Is this possible?
Currently if I need to look at lots of plots I output them into a big .pdf file and scroll though them all there, but that is a bit cumbersome.
Thanks
Tom
In R, that would be done by setting par(ask=TRUE). Try the following code, which shows how to reset the par when exiting the function :
op <- par(ask=TRUE)
for (i in 1:5){
plot(1:i)
}
par(op)
If you want to keep a history to browse through, you can either open a window and click on recording in the History menu, or you can open the window yourself with the history on. Demonstrated in a function :
plot.fun <- function(){
windows(record=TRUE) # opens a window and starts recording
op <- par(ask=TRUE)
on.exit(par(op))
for (i in 1:5){
plot(1:i)
}
windows.options(record=FALSE) #stops recording.
}
plot.fun()
This will however keep all previous plots in the history for browsing as well, so if you run this code 3 times you'll have 15 plots in the plot history. Also note that the open plot window will keep on recording until you turn off the recording in the menu.
You can play with the plot history, as you'll have a variable .SavedPlots which contains the saved plot history. It can be cleared using the menu History > clear history in the plot window. If you want to clear the history from the console, you could hack that by
.SavedPlots <- NULL
But I advise you not to do this, as changing the .SavedPlots variable can cause R to crash.
See also ?windows and ?recordPlot for a bit more information. But as you're getting close to the internal code of R, be warned that you can get pretty awkward behaviour if you start playing around with these things.
For scrolling back and forth between plots using the arrow keys: it depends on the platform/R interface.
Windows: there is a recording function (see Q5 of the R for Windows FAQ) which uses Page Up/Page Down
MacOS: under the standard GUI, the Quartz window has Apple-left and Apple-right arrow
under the standard Unix (no-GUI) interface, things are more limited. You can use RStudio (which has a lot of buzz right now) ... I would have thought that JGR would have plot history as well, but it doesn't seem to ...
You can use locator - now plots change on click
for (i in 1:5){
plot(1:i)
locator(1)
}

Resources