Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I automate these emacs ESS (ess-remote) commands?

Tags:

emacs

r

elisp

ess

I'm using a local emacs instance (aquamacs) to run R processes on a remote server, and I'd like to automate the process of connecting to my server. The process is as follows:

[in emacs]

M-x shell

[in the resulting console]

TERM=xterm
ssh -Y -C <my remote server>
screen -rd [and/or] R

[in emacs]

M-x ess-remote
r

I discovered this general approach here: http://blog.nguyenvq.com/2010/07/11/using-r-ess-remote-with-screen-in-emacs/. The -Y -C options allow you use xterm to view plots. I don't know lisp and tho I've googled around a bit, I can't seem to piece together how to actually define a function to automate this (e.g., in .emacs.el). Has anyone implemented anything like this?

like image 338
Solomon Avatar asked Nov 22 '12 18:11

Solomon


1 Answers

Let's assume you just want to call shell in code. In Lisp, everything is prefix notation surrounded by parentheses. So we enter this into a buffer (say, the scratch buffer):

(shell)

Move your pointer to the end of the line after the close-paren, and type <C-x C-e> to execute the Lisp code. You should see that the shell function is called.

Now, let's make it a function, so we can add other things to it. The command to create a function is defun, and it takes the name of the function, the argument list (in parentheses), and then the body of the function:

(defun automate-connection ()
  (shell))

Move your cursor to the end of the code, hit <C-x C-e>, and the function will be defined. You can call it from Lisp by executing

(automate-connection)

Ok, now we just need to put some text into the shell buffer.

(defun automate-connection ()
  (shell)
  (insert "TERM=xterm"))

Now, when we run that, we get "TERM=xterm" put into the shell buffer. But it doesn't actually send the command. Let's try putting a newline.

(defun automate-connection ()
  (shell)
  (insert "TERM=xterm\n"))

That puts in a newline, but doesn't actually make the command run. Why not? Let's see what the enter key does. Go to your *shell* buffer, and type <C-h c>, then hit the return key. (<C-h c> runs describe-key-briefly, which prints the name of the function invoked by hitting the given key). That says that when you hit RET, it's not putting a newline, but actually calling comint-send-input. So let's do that:

(defun automate-connection ()
  (shell)
  (insert "TERM=xterm")
  (comint-send-input))

Now, when you run `(automate-connection) from any Lisp code, you should get the given thing sent. I leave it as an exercise to the reader to add your other commands.

But wait! We're not really done, are we? I assume you don't want to have to move to a Lisp scratch buffer, type in (automate-connection), then evaluate that code. You probably just want to type , and call it a day. You can't do that by default with the function we just created. Luckily, it's simple to allow that: just add a call to (interactive) in your function:

(defun automate-connection ()
  (interactive)
  (shell)
  (insert "TERM=xterm")
  (comint-send-input))

Now you can call it as you want, and it'll open the *shell* buffer, put in the text, and tell Emacs to tell the shell to run that text.

like image 127
zck Avatar answered Sep 21 '22 03:09

zck