tags:

views:

286

answers:

3

I'm writing an interactive function that I'd like to have remember the last argument the user supplied and use it as the default.

(defun run-rake (param)
  (interactive "sTask: ")
  (shell-command (format "rake %s" task)))

The first time the function is invoked I want it to remember the argument the user supplied so that the next time they invoke the function they can just press enter and it will use the value they supplied the previous time.

I can't seem to find this in the documentation - how do you do this in elisp?

A: 

I figured out how to do this manually using a defvar (global), but this feels like the kind of thing that should already be provided by the core library (kind of like scheme's make-parameter). This just seems like more code, and more manual than it should be:

(defvar *editconf-ruby-run-rake-last-rake-task* nil)

(defun editconf-ruby-run-rake-last-rake-task (&optional new-val)
  (when new-val
    (setf *editconf-ruby-run-rake-last-rake-task* new-val))
  *editconf-ruby-run-rake-last-rake-task*)

(defun editconf-ruby-run-rake (task-name)
  "Execute rake `task-name'.  See                                                                                            
`krb-ruby-get-rakefile-path-for-current-buffer' for how the                                                                  
Rakefile is located.."
  (interactive
   (let* ((rakefile (krb-ruby-get-rakefile-path-for-current-buffer))
          (rake-tasks (krb-ruby-get-rake-tasks rakefile))
          (default-task (or (editconf-ruby-run-rake-last-rake-task)
                            (editconf-ruby-run-rake-last-rake-task (car rake-tasks)))))
     (list
      (read-string (format "Task [%s|%s]: "
                           rake-tasks
                           default-task)
                   nil nil default-task))))
  (editconf-ruby-run-rake-last-rake-task task-name)
  (let ((cmd (format "cd %s; rake %s"
                     (krb-lisp-strip-path-suffix rakefile 1)
                     task-name)))
    (message "editconf-ruby-run-rake: cmd='%s'" cmd)
    (shell-command cmd)))
Kyle Burton
+5  A: 

You can see how the compile command does this. Bring up the help text for the compile command with C-h f compile, move the cursor over the name of the file that contains the function, then hit RETURN. This will bring up the source file for compile.

Basically, there's a dynamic/global variable compile-command that holds the last compile command. Emacs is a single-user, single-threaded system, so there's really no need for much more. Also keep in mind that Elisp is a very old school Lisp, and variables have dynamic (call stack), not lexical, scope. In this kind of system it is natural to:

(let ((compile-command "gcc -o foo foo.c frobnicate.c"))
     ...
     (compile)
     ...)

Speaking of the compile command, have you tried using it instead of your own run-rake function?

jfm3
+4  A: 
read-from-minibuffer

is what you want to use. It has a spot for a history variable.

Here is some sample code:

(defvar run-rake-history nil "History for run-rake")
(defun run-rake (cmd)
(interactive (list (read-from-minibuffer "Task: " (car run-rake-history) nil nil 'run-rake-history)))
  (shell-command (format "rake %s " cmd)))

Obviously customize to your needs. The 'run-rake-history is simply a variable that is used to store the history for this invocation of 'read-from-minibuffer. Another option would be to use 'completing-read - but that assumes you've got a list of choices you want to restrict the user to using (which usually isn't the case for shell-like commands).

Trey Jackson
This should be the accepted answer.
A. Levy