tags:

views:

82

answers:

2

Hi

I would like to translate the following function from vim script to emacs elisp (I use it to set the email recipients when writing emails).

My question is mainly how to get and set line contents in emacs, because with quick googling I could not find this out (probably I just did not know the right terms to google for, "getline" and "setline" in any case did show any results).

function! G_set_to()  
    let address = system('my-address-script')  "shell command to choose addresses  
    let line = getline (2)  
    if strlen(line) == 4  
        call setline(2,  line . address)  
    else  
        call setline(2,  line . "; " . address)  
    endif  
endfunction  

Sorry if the answer is obvious, I am am completely new to emacs and don't even know how to use its in-built help system.

Cheers Arian

+2  A: 

Give this a shot, obviously customizing the variable G-address-script to suit your needs.

(require 'sendmail)
(defvar G-address-script "echo [email protected]")
(defun G-set-to ()
  "execute script in G-address-script and populate the To: line with the results"
  (interactive)
  (save-excursion
    (mail-to)
    (unless (= (current-column) 4)
      (insert "; "))
    (insert (shell-command-to-string G-address-script))
    (when (looking-at "^$") ; when shell command has extra newline, delete it
      (delete-backward-char 1))))

As far as using the help, there's a reasonable introduction to Emacs lisp here. But the quick intro is:

  • C-h i (that's control-h then i to see the info pages, there is one for Emacs and one for Emacs Lisp.
  • M-x apropos searches for terms
  • C-h f gives you help on a function
  • C-h v gives you help on a variable
  • In the *scratch* buffer, C-j will evaluate the expression right before the point (cursor)
  • M-x edebug-defun when the point is in a emacs lisp function will turn the debugger on, and the next time a function is run you'll step through it (M-x eval-defun in the function will turn the debugger off)
  • M-x eldoc-mode will turn on automatic documentation for emacs lisp functions and variables as you type them, read more here.
Trey Jackson
I get "Symbol's function definition is void: mail-to"when I do M-x G-set-to. Not sure if it is relevant but I do not use any kind of built-in emacs mail client. I just use emacs as my external email editor. Maybe that is why "mail-to" is not defined? If understand the above code correctly, is there no way to specify a line in the buffer to operate on (like vim's "setline") explicitly instead of using mail-to (if that is what mail-to does). As the "To:" line will always be the second line that would be a sufficient solution I think.
@hnihno I added the line `(require 'sendmail)` which will get rid of the error. And you can't always be sure that the `To:` line is the second.
Trey Jackson
+1  A: 

I took Trey's code and changed a few things and now it seems to work:

(defvar G-address-script "goobook_dmenu_with_cache")  
  (defun G-set-to ()  
    "execute script in G-address-script and populate the To: line with the results"  
    (interactive)  
    (save-excursion  
  (goto-line 2)  
  (re-search-forward "$")  
  (unless (= (current-column) 4)  
    (insert "; "))  
  (insert (shell-command-to-string G-address-script))))

Some remaining questions:

  1. The bit where Trey's code checks if the string returned from G-address-script is empty doesn't work at the moment, what do I have to change?
  2. Is there really no function to get the content of a specified line as a string?
  3. Is there a better/more elegant way to do this? The vim script solution looks so much simpler, surely I am missing something.

Anyway, I'll mark this as solved in a day or so if there are no more answers as Trey solution basically does what I wanted. Thank you Trey!

Re #1: Actually, the code was checking for an extra newline at the end - I added a comment to clear that up. Re #2: The code to get the content of a line would be `(goto-line N) (buffer-substring (line-beginning-position) (line-end-position))`. Re #3: the elisp could be pared down more minimally. Additional feedback: `(goto-line 2)` assumes the `To:` is on line #2, and that the `To:` field is only one line long - not always valid. To go to the end of a line, you can use `(end-of-line)`.
Trey Jackson
awesome, thanks for the elisp primer! marked as solved (but more questions to come for sure).