2
votes

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

3 Answers

5
votes

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.

3
votes

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.

0
votes

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.