How can I find out which version of emacs introduced a function? - emacs

I want to write a .emacs that uses as much of the mainline emacs functionality as possible, falling back gracefully when run under previous versions. I've found through trial and error some functions that didn't exist, for example, in emacs 22 but now do in emacs 23 on the rare occasion that I've ended up running my dotfiles under emacs 22. However, I'd like to take a more proactive approach to this, and have subsets of my dotfiles that only take effect when version >= <some-threshold> (for example). The function I'm focusing on right now is scroll-bar-mode but I'd like a general solution.
I have not seen a consistent source for this info; I've checked the gnu.org online docs, the function code itself, and so far nothing. How can I determine this, without keeping every version of emacs I want to support kicking around?

I cannot answer your question directly, but one technique I use is to check the functionp function that tells me if a function exists.
e.g.
(if (load "completion" t)
(progn
(initialize-completions)
(if (functionp 'dynamic-completion-mode)
(dynamic-completion-mode) ; if exists
(completion-mode) ; otherwise use old version
)
) ; progn
) ; if
update: adding version specific macros
In addition to using functionp I also have some version specific macros:
(defmacro GNU_EMACS_21 (&rest stuff)
(list 'if (string-match "GNU Emacs 21" (emacs-version)) (cons 'progn stuff)))
(defmacro GNU_EMACS_20 (&rest stuff)
(list 'if (string-match "GNU Emacs 20" (emacs-version)) (cons 'progn stuff)))
(defmacro GNU_EMACS_19 (&rest stuff)
(list 'if (string-match "GNU Emacs 19" (emacs-version)) (cons 'progn stuff)))
(defmacro WINSYS_X (&rest stuff)
(list 'if (eq window-system 'x) (cons 'progn stuff)))
(defmacro WINSYS_W32 (&rest stuff)
(list 'if (eq window-system 'w32) (cons 'progn stuff)))
(defmacro WINSYS_NIL (&rest stuff)
(list 'if (eq window-system nil) (cons 'progn stuff)))
(defmacro SYSTYPE_LINUX (&rest stuff)
(list 'if (string-match "linux" (symbol-name system-type)) (cons 'progn stuff)))
I can then use these:
(GNU_EMACS_21
(if (load "cua" t)
(CUA-mode t)
)
)
(WINSYS_NIL ; when running in text mode
(push (cons 'foreground-color "white") default-frame-alist)
(push (cons 'background-color "black") default-frame-alist)
(push (cons 'cursor-color "cyan") default-frame-alist)
(push (cons 'minibuffer t) default-frame-alist)
)
I'm guessing you already know this, however; and questions like "when did CUA mode get included with Emacs" are difficult to answer..

The "NEWS" files (accessible via C-h N) may give hints as to when functions were introduced.

It's usually better practice to test the existence of the function or variable you want to use, rather than test the Emacs version. Use fboundp and boundp, for example. Occasionally it makes sense to check featurep, but there again it is usually better to use fboundp or boundp.

Related

How to make eshell-autojump case insensitive under Linux

Under Linux, eshell-autojump will do case sensitive matching which I just find a nuisance. I've tried to circumvent this by advising eshell/j with a eshell-under-windows-p that always returns t but to my chagrin eshell-under-windows-p invoked in eshell/j is unaffected by cl-letf. I've modified my eshell/j a bit to give me some debug info:
;; Modified eshell/j inside eshell-autojump.el to this
(defun eshell/j (&rest args) ; all but first ignored
"Jump to a directory you often cd to.
This compares the argument with the list of directories you usually jump to.
Without an argument, list the ten most common directories.
With a positive integer argument, list the n most common directories.
Otherwise, call `eshell/cd' with the result."
(setq args (eshell-flatten-list args))
(let ((path (car args))
(candidates (eshell-autojump-candidates))
(case-fold-search (eshell-under-windows-p))
result)
(when (not path)
(setq path 10))
(message "case-fold-search = %S" case-fold-search)
(message "eshell-under-windows-p returns %s from inside eshell/j" (eshell-under-windows-p))
(if (and (integerp path) (> path 0))
(progn
(let ((n (nthcdr (1- path) candidates)))
(when n
(setcdr n nil)))
(eshell-lisp-command (mapconcat 'identity candidates "\n")))
(while (and candidates (not result))
(if (string-match path (car candidates))
(setq result (car candidates))
(setq candidates (cdr candidates))))
(eshell/cd result))))
My init.el adds the advice to attempt to make eshell/j caseless by trying to trick it to think we are on Windows:
;; Added to init.el
(require 'eshell-autojump)
(advice-add 'eshell/j :around
(lambda (orig-fun &rest xs)
(cl-letf (((symbol-function 'eshell-under-windows-p) (lambda () t)))
(progn (message "eshell-under-windows-p returns %s from lambda" (eshell-under-windows-p)) (apply orig-fun xs)))))
But all I get in Messages buffer when I try to jump in eshell is:
;; I get in *Messages*
eshell-under-windows-p returns t from lambda
case-fold-search = nil
eshell-under-windows-p returns nil from inside eshell/j
My rookie knowledge of elisp is not enough to wrestle with probable scoping issues here. Can anyone decode why eshell-under-window-p is unaffected when called from eshell/j here?
I've found the answer. cl-letf does not work for byte compiled functions. As eshell-autojump is a package it gets byte compiled upon installation and cl-letf cannot be used to modify it's internal behavior. I had to resort to redefining the eshell/j which is a suboptimal solution.

Is there any way to see the implementations of built-in macros in Common Lisp?

Common Lisp built-in functions are probably implemented in C. But I imagine macros are implemented in lisp (sorry if I'm wrong about any of two sentences). Is there any way (through some function or some macro) to see the implementations of built-in macros in Common Lisp? I'm using CLisp.
The ability to inspect function and macro definitions is a feature of your development environment. These days it is typical to use SLIME or SLY with emacs as the basis of a Lisp development environment. I personally use SLIME, but I have heard good things about SLY, too.
In SLIME you can invoke slime-edit-definition (either by keying M-x slime-edit-definition or by using the keybinding M-.) to visit a definition for the symbol under the cursor in a source file. This works both when editing in a source file, or from the REPL. This feature is extremely useful when you want to inspect some library code you are working with, but you can also view a lot of built-in definitions this way. You can even jump to a new definition from a new symbol found in whatever definition you are currently inspecting.
After you are done looking at a definition, you can use M-x slime-pop-find-definition-stack, or the easier to remember keybinding M-, (M-* will also work), to back out through the previously viewed definitions, eventually returning to your starting point.
Here is an example, in SBCL:
CL-USER> with-open-file[press M-.]
(Note that the "[press M-.]" above is not typed, but only meant to remind what action is taken here). With the cursor on or right after the symbol with-open-file, press M-. to see the definition:
(sb-xc:defmacro with-open-file ((stream filespec &rest options)
&body body)
(multiple-value-bind (forms decls) (parse-body body nil)
(let ((abortp (gensym)))
`(let ((,stream (open ,filespec ,#options))
(,abortp t))
,#decls
(unwind-protect
(multiple-value-prog1
(progn ,#forms)
(setq ,abortp nil))
(when ,stream
(close ,stream :abort ,abortp)))))))
This time after keying M-. SLIME gives a choice of definitions to view:
CL-USER> and[press M-.]
Displayed in an emacs buffer:
/path-to-source/sbcl-2.0.4/src/code/macros.lisp
(DEFMACRO AND)
/path-to-source/sbcl-2.0.4/src/pcl/ctypes.lisp
(DEFINE-METHOD-COMBINATION AND)
We want to see the macro definition, so move the cursor to the line showing (DEFMACRO AND), and the following definition is displayed:
;; AND and OR are defined in terms of IF.
(sb-xc:defmacro and (&rest forms)
(named-let expand-forms ((nested nil) (forms forms) (ignore-last nil))
(cond ((endp forms) t)
((endp (rest forms))
(let ((car (car forms)))
(cond (nested
car)
(t
;; Preserve non-toplevelness of the form!
`(the t ,car)))))
((and ignore-last
(endp (cddr forms)))
(car forms))
;; Better code that way, since the result will only have two
;; values, NIL or the last form, and the precedeing tests
;; will only be used for jumps
((and (not nested) (cddr forms))
`(if ,(expand-forms t forms t)
,#(last forms)))
(t
`(if ,(first forms)
,(expand-forms t (rest forms) ignore-last))))))
There is more stuff here, since you are now actually in the source file that contains the definition for and; if you scroll down a bit you can also find the definition for or.
A lot of SBCL functions are written in Lisp; SBCL has a very high-quality compiler, so a lot of stuff that you might otherwise expect to be written in C can be written in Lisp without loss of performance. Here is the definition for the function list-length:
CL-USER> list-length[press M-.]
(defun list-length (list)
"Return the length of the given List, or Nil if the List is circular."
(do ((n 0 (+ n 2))
(y list (cddr y))
(z list (cdr z)))
(())
(declare (type fixnum n)
(type list y z))
(when (endp y) (return n))
(when (endp (cdr y)) (return (+ n 1)))
(when (and (eq y z) (> n 0)) (return nil))))
The same thing can be done when using CLISP with SLIME. Here is with-open-file as defined in CLISP:
CL-USER> with-open-file[press M-.]
(defmacro with-open-file ((stream &rest options) &body body)
(multiple-value-bind (body-rest declarations) (SYSTEM::PARSE-BODY body)
`(LET ((,stream (OPEN ,#options)))
(DECLARE (READ-ONLY ,stream) ,#declarations)
(UNWIND-PROTECT
(MULTIPLE-VALUE-PROG1
(PROGN ,#body-rest)
;; Why do we do a first CLOSE invocation inside the protected form?
;; For reliability: Because the stream may be a buffered file stream,
;; therefore (CLOSE ,stream) may produce a disk-full error while
;; writing the last block of the file. In this case, we need to erase
;; the file again, through a (CLOSE ,stream :ABORT T) invocation.
(WHEN ,stream (CLOSE ,stream)))
(WHEN ,stream (CLOSE ,stream :ABORT T))))))
But, many CLISP functions are written in C, and those definitions are not available to inspect in the same way as before:
CL-USER> list-length[press M-.]
No known definition for: list-length (in COMMON-LISP-USER)

Could Emacs fontify elisp string constants?

The Dilemma: readability or maintainability?
Let's look at the following function.
It doesn't really matter what it does, the important part is that
it's using twice the string "(let\\*?[ \t]*":
(defun setq-expression-or-sexp ()
"Return the smallest list that contains point.
If inside VARLIST part of `let' form,
return the corresponding `setq' expression."
(interactive)
(ignore-errors
(save-excursion
(up-list)
(let ((sexp (preceding-sexp)))
(backward-list 1)
(cond
((looking-back "(let\\*?[ \t]*")
(cons 'setq
(if (= (length sexp) 1)
(car sexp)
(cl-mapcan
(lambda (x) (unless (listp x) (list x nil)))
sexp))))
((progn
(up-list)
(backward-list 1)
(looking-back "(let\\*?[ \t]*"))
(cons 'setq sexp))
(t
sexp))))))
Since it's a headache having to update the string in two (or more) locations,
I'd have to defconst it like so:
(defconst regex-let-form "(let\\*?[ \t]*")
Although the code became more maintainable, it became less readable as well,
because it's hard to see at a glance what regex-let-form really is:
(defun setq-expression-or-sexp ()
"Return the smallest list that contains point.
If inside VARLIST part of `let' form,
return the corresponding `setq' expression."
(interactive)
(ignore-errors
(save-excursion
(up-list)
(let ((sexp (preceding-sexp)))
(backward-list 1)
(cond
((looking-back regex-let-form)
(cons 'setq
(if (= (length sexp) 1)
(car sexp)
(cl-mapcan
(lambda (x) (unless (listp x) (list x nil)))
sexp))))
((progn
(up-list)
(backward-list 1)
(looking-back regex-let-form))
(cons 'setq sexp))
(t
sexp))))))
The idea: why not both?
Since it's a constant anyway, why not font-lock it
and make regex-let-form appear as if it's "(let\\*?[ \t]*"?
It's a feasable job, since:
It's possible to font-lock identifiers like so: http://www.emacswiki.org/emacs/PrettyLambda,
or even so: rainbow-mode.
And it's possible to font-lock constants. It's already done for c++-mode,
but not yet for emacs-lisp-mode, as far as I know.
Then it remains only to connect the two. Unfortunately, I don't know
enough of font-lock innards to do it, but maybe someone else does?
Or is there already a package that does this?
Tweaking the code from this answer,
I've solved the problem:
(font-lock-add-keywords
'emacs-lisp-mode
'((fl-string-constant . 'font-lock-constant-face)) 'append)
(defun fl-string-constant (_limit)
(while (not
(ignore-errors
(save-excursion
(skip-chars-forward "'")
(let ((opoint (point))
(obj (read (current-buffer)))
obj-val)
(and (symbolp obj)
(risky-local-variable-p obj)
(special-variable-p obj)
(stringp (setq obj-val (eval obj)))
(progn
(put-text-property
(1- (point)) (point) 'display
(format "%c\"%s\"" (char-before) obj-val))
(set-match-data (list opoint (point)))
t))))))
(if (looking-at "\\(\\sw\\|\\s_\\)")
(forward-sexp 1)
(forward-char 1)))
t)
This displays the value of a string constant right after the constant name.
It works quite nicely with fontified string constants as well.
Speed is a bit of an issue - suggestions to improve are welcome.
Also, I couldn't find anything better than risky-local-variable-p to determine
that it's a constant. The doc says that defconst marks the variable
as special and risky, but nothing else.
hl-defined.el (updated today, 2013-10-20) can highlight constant Emacs-Lisp symbols as such, that is, variables whose current value is the symbol itself. If your defconst has been evaluated then this will do what you are requesting.
This seems to work (source: http://www.emacswiki.org/emacs/PrettyLambda):
(font-lock-add-keywords 'emacs-lisp-mode
`(("\\<\\(regex-let-form\\)\\>" (0 (prog1 nil
(compose-region (match-beginning 1)
(match-end 1)
"\"(let\\\\*?[ \\t]*\""))))))
Although I think adding regex-let-form into the existing let block would be a cleaner solution:
(let ((sexp (preceding-sexp))
(regex-let-form "(let\\*?[ \t]*"))
...
Perhaps your example is not indicative of the real problem, and you really do want to do some display replacement or font-locking, as you say.
But I will answer wrt your example and the problem as posed, regarding maintainability vs readability: Just let-bind your regexp. The binding, unlike a defconst will be nearby and clearly related to the occurrences of the bound variable.
This is typically what people do. Again, you might have had another use case in mind --- I am responding only to the problem as posed narrowly.

Enabling certain emacs modes or features *almost* always

There's a couple of emacs features, such as flyspell-mode,
highlight-beyond-fill-column, or auto-fill-mode, I find so useful that I
want them enabled almost all the time. However, there's always certain
conditions in which they don't make much sense.
highlight-beyond-fill-column, for example, I tend to want for pretty much
everything I edit myself, but for reading things others wrote, like in Gnus or
when reading the built-in documentation, it's actually quite annoying.
Similarly auto-fill-mode is incredibly handy when writing just Text. However,
it's entirely unhelpful when programming.
For those reasons I can't just enable features like that globally. Always
enabling them manually isn't very practical as well, but so is having to write
hooks for each and every mode or application I'm using within emacs, obviously
not being able to cover all of them, and still ending up enabling those features
manually.
What I believe I'm looking for is a way to globally enable some features, but
selectively turn them off again, based on various conditions such as which major
or minor modes are being used, if the buffer is read-only or writable, or
depending on the buffer containing text or source code. I do realize that at
least the last thing might not be easy for emacs to answer, but at least for
that I believe I'd be fine with a hard-coded list of "programming-modes" i use
regularly.
So you want total control over what's executed when a particular mode is opened or a particular type of file... OK here is what you need :
;; The function where you could put all your customization
(defun my-func ()
(turn-on-auto-fill))
;; This is an example, customize it like you need it.
(defvar functions-to-call
`(((c-mode c++-mode) ".h$" (my-func))
((cperl-mode perl-mode) nil (my-func)))
"A list of triples, used for storing functions.
A triplet is composed of a symbol for the major mode (or a list of symbols),
a regular expression to match against the buffer's file name,
and the functions to call when both the major mode and regular expr match.")
(defun call-mode-functions ()
"call functions, based on major mode and buffer name regexp matching"
(interactive)
(let ((l functions-to-call))
(while l
(let* ((elt (car l))
(modes (if (listp (car elt)) (car elt) (list (car elt))))
(re (cadr elt))
(fcts (caddr elt)))
(when (and (member major-mode modes)
(or (null re)
(string-match re (buffer-file-name))))
(while fcts
(funcall (car fcts))
(setq fcts (cdr fcts)))
(setq l nil)))
(setq l (cdr l)))))
(add-hook 'after-change-major-mode-hook 'call-mode-functions)
With this code, you can can do the fine-grained customization you require. This is just an example, you can adapt it to your needs.
Interesting idea. I recommend using the
espect extension from your github.
It sounds like you basically want to turn specific minor-modes on or off for "specific buffers". Usually, the "specific buffers" can be distinguished by their major mode, which is how I usually look at this type of problem. How to turn minor modes on or off depends on the implementation of both the minor mode you're trying to turn on/off and the major mode you're trying to turn it on/off in.
The usual way to enable/disable things based on major-mode is via the major-mode-hook variable. This is where you stick things to customize the mode:
(add-hook 'text-mode-hook 'auto-fill-mode)
I usually write my own function, even if it's a simple one-liner, because I almost always will add stuff later on:
(defun my-text-mode-hook ()
"Stuff to do when `text-mode' is invoked."
(auto-fill-mode 1))
(add-hook 'text-mode-hook 'my-text-mode-hook)
You can also make things within the hook conditional:
(defun my-text-mode-hook ()
"Stuff to do when `text-mode' is invoked."
;; skip modes based on text-mode
(when (eq major-mode 'text-mode)
(auto-fill-mode 1))
)
(add-hook 'text-mode-hook 'my-text-mode-hook)
I usually do all of this in a major-mode-load-hook, so that it only happens when the major-mode's code is loaded:
(defun my-tnt-load-hook ()
(defun my-tnt-im-mode-hook ()
"Hook for TNT's im-mode hook."
(flyspell-mode 1)
(setq fill-column (- (frame-width) 5)))
(add-hook 'tnt-im-mode-hook 'my-tnt-im-mode-hook)
(add-hook 'tnt-chat-mode-hook 'my-tnt-im-mode-hook))
(add-hook 'tnt-load-hook 'my-tnt-load-hook)
A well-written major-mode will have a load-hook variable defined (I usually look at the mode's source code to find out). If it doesn't have a load-hook, you can simulate one with the eval-after-load function:
(defun my-view-mode-after-load-hook ()
"Stuff to do after view mode loads."
(defun my-view-mode-hook ()
"Stuff to run in `view-mode'."
(flyspell-mode 0))
(add-hook 'view-mode-hook 'my-view-mode-hook)
(define-key view-mode-map "b" 'View-scroll-page-backward)
(define-key view-mode-map [(delete)] 'View-scroll-page-backward)
(define-key view-mode-map "q" 'View-kill-and-leave)
(define-key view-mode-map "Q" 'View-quit))
(eval-after-load 'view '(my-view-mode-after-load-hook))
If you don't do this in a load-hook then you have to make sure the mode-hook is customizable, and then add in your my-mode-hook via customize; I'd rather have all of the stuff in one place in my .emacs, so I don't usually customize my hooks this way.
If you ever find a major-mode that does not have a major-mode-hook you can create your own major-mode based off of it using define-derived-mode. You'll then have to get the newly defined mode invoked whenever the old mode was.
(defun replace-alist-mode (alist oldmode newmode)
(dolist (aitem alist)
(if (eq (cdr aitem) oldmode)
(setcdr aitem newmode))))
(define-derived-mode hooked-foobar-mode foobar-mode "Foobar")
(replace-alist-mode auto-mode-alist 'foobar-mode 'hooked-foobar-mode)
(defun my-hooked-foobar-mode-hook ()
"Hook to run when `hooked-foobar-mode' is called."
(flyspell-mode 0))
(add-hook 'hooked-foobar-mode-hook 'my-hooked-foobar-mode-hook)
Some minor modes can be enabled globally. If you want them on most of the time and it supports it, you can turn it on globally and then turn it off for specific major modes.
(global-font-lock-mode 1)
;; example of how to do it without a defun
(add-hook 'text-mode-hook (function
(lambda () ""
(interactive)
(font-lock-mode 0))))
If the minor mode can't be enabled globally, or you don't want it enabled globally, just turn it on for specific modes, as shown above.
So here's what I came up with after reading [Jérôme Radix][1]'s excellent
reply. Especially the pointer to after-change-major-mode-hook has helped a
lot.
I now define my buffer-specific settings in a list like this:
;; no `highlight-beyond-fill-column' for w3m and gnus
'((((:not ((:mode "^gnus") (:mode w3m-mode))))
(lambda () (highlight-beyond-fill-column)))
;; `flyspell-mode` and `auto-fill-mode` for text-ish buffers
(((:mode message-mode)
(:mode org-mode)
(:mode pod-mode)
(:mode markdown-mode)
(:name "\\.\\(txt\\|mkn\\)$"))
(lambda ()
(flyspell-mode)
(auto-fill-mode)))
;; indenting with tabs for certain projects
(((:name t :fun (lambda () (and (not eproject-root)
(eproject-maybe-turn-on)))))
(lambda () (setq indent-tabs-mode t)))
When the major mode changes, I then iterate over all those settings, evaluate
the defined conditions in the buffer, and call the appropriate lambda if a
condition matches:
(add-hook 'after-change-major-mode-hook
(lambda () (rafl:apply-buffer-settings rafl:buffer-settings)))
(defun rafl:apply-buffer-settings (settings)
(dolist (setting rafl:buffer-settings)
(let ((condition (car setting))
(action (cadr setting)))
(when (rafl:evaluate-buffer-condition condition)
(funcall action)))))
Evaluating those conditions is a little messy, but works rather well for me.
(defun rafl:evaluate-buffer-condition (con)
(cond
((functionp con)
(funcall con))
((listp con)
(cond
((listp (car con))
(reduce
(lambda (a b) (or a b))
(cons nil (mapcar #'rafl:evaluate-buffer-condition con))))
(t
(reduce
(lambda (a b) (and a b))
(cons
t
(let (ret)
(while con
(let ((k (pop con))
(v (pop con)))
(push (cond
((eq k :fun)
(funcall v))
((eq k :not)
(when (not (listp v))
(error ":not requires a list"))
(not (rafl:evaluate-buffer-condition v)))
((eq k :mode)
(if (stringp v)
(string-match-p v (symbol-name major-mode))
(eq v major-mode)))
((eq k :name)
(cond
((and (buffer-file-name) (stringp v))
(string-match-p v (buffer-file-name)))
((buffer-file-name)
v)
(t
(not v))))
(t
(error "unknown cond")))
ret)))
ret))))))
(t
(error "invalid condition"))))
It also turns out that I could do all my per-project setting, which I did quite
differently before, using this mechanism. I'm very happy about that.
1: Enabling certain emacs modes or features *almost* always
I do this
(require 'linum)
;(global-linum-mode t)
(add-hook 'find-file-hook (lambda ()
(if (not(equal major-mode 'term-mode))
(linum-mode nil))))

matching keys in association lists in emacs lisp

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!
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.
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.
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.