tags:

views:

65

answers:

3

Hi, I'm using folding-mode in emacs and was trying to make a function to insert the appropriate folding marker (start or end) depending on mode. So far I have

(defun insert-folding-mode-mark ()
  (interactive)
  (let ((st "##{{{")
        (en "##}}}") 
        string-to-insert)
    (save-excursion
      (setq string-to-insert
            (let ((here (point))
                  sp ep)
              (setq sp (search-backward st))
              (goto-char here)
              (setq ep (search-backward en))
              (if (< sp ep) st en))))
    (insert string-to-insert)))

This inserts "##{{{" at (point) unless "##{{{" precedes it, in which case it inserts "##}}}". I'd like to replace the first (let) assignment with something that determines the start and end markers with something like

(let* ((match (assoc (intern mode-name) folding-mode-marks-alist))
       (st (nth 1 match))
       (en (nth 2 match)))

[is (intern) meant to be called in this way?] A truncated version of my folding-mode-marks-alist looks something like

((ess-mode "##{{{" "##}}}")
 (tex-mode "%{{{" "%}}}")
 (python-mode "# {{{" "# }}}")
 (emacs-lisp-mode ";;{{{" ";;}}}")
 (TeX-mode "%{{{" "%}}}")
 (LaTeX-mode "%{{{" "%}}}"))

while the mode-name returned from various modes are {"Emacs-Lisp", "ESS[S]", "PDFLaTeX", "Python", ...}. Seems like I might want to do some partial matching with strings using (downcase), (concat x "-mode"), and so on, but was wondering if there was an idiomatic way in emacs lisp to do this sort of matching with keys of an alist, or do I just have to have a separate block of code by which I extract the keys with (mapcar 'car folding-mode-marks-alist) and convert each symbol to string (how?) to do the matching?

Thanks much!

+3  A: 

Emacs Lisp has a destructuring-bind facility which may be helpful here. Also taking advantage of the fact that the symbol naming the current major mode is available via the variable major-mode, you can write something like this:

(destructuring-bind (st en) (cdr (assoc major-mode folding-mode-marks-alist))
  ; do stuff
  )

Note that this won't work if (assoc major-mode folding-mode-marks-alist) returns nil, so better replace that with a call to some custom function capable of returning a sensible default.

Michał Marczyk
Thanks! Did it.
Stephen
You're welcome. Also, I think I might be incorporating something like your original function into my config come my next round of Emacs customisation, so thanks for sharing!
Michał Marczyk
+2  A: 

In addition to major-mode being more appropriate than mode-name here, the function insert-folding-mode-mark as listed above would throw an error if there were no folding marker between cursor and beginning of buffer. Here is a revision without that quirk:

(require 'cl)

(defun insert-folding-mode-mark ()
  (interactive)
  (flet ((fn (s) (save-excursion (or (search-backward s () t) 0))))
    (destructuring-bind (mode st en)
        (or (assoc major-mode folding-mode-marks-alist) '(nil "" ""))
      (insert (if (<= (fn st) (fn en)) st en)))))

Edit: fix problem pointed out in comment.

huaiyuan
Thank you - your construction, particularly the use of flet, is beautiful. However... by returning (point) the function cannot distinguish between having the starting mark on the first line and having no marks at all, and so fails when the buffer begins with the mark :P
Stephen
Good catch! Fixed.
huaiyuan
Simply brilliant. I had added additional tests for nils but using the last value returned from the 'or' operator is brilliant.
Stephen
A: 

You may be interested to know there are comment-start and comment-end variables which should already contain the information you need based on major-mode. Something like

(search-backward (concat comment-start "{{{"))
...
(insert comment-start "{{{" comment-end)

should be sufficient. Of course, for lisp modes comment-start is ";" so you may want to do what you are doing to get ";;" but fall back on comment-start for other modes. You can also (setq comment-start ";;") though I'm not entirely sure what difference that makes for the lisp modes.

Ivan Andrus
Thanks - that was my first idea, but as you can see from the example folding-mode-marks-alist provided above the mark requires either 1 or 2 repeat of the comment-start and sometimes there's a space in between that and the triple braces, and so on... which is why I wanted to actually perform a search against the keys of the alist.
Stephen