diff --git a/doc/misc/autotype.texi b/doc/misc/autotype.texi index c53be54d0af..377dcda3efd 100644 --- a/doc/misc/autotype.texi +++ b/doc/misc/autotype.texi @@ -273,13 +273,15 @@ empty file is visited. This is accomplished by putting @vindex auto-insert-alist What gets inserted, if anything, is determined by the variable -@code{auto-insert-alist}. The @sc{car} of each element of this list -is either a mode name, making the element applicable when a buffer is -in that mode, or a string, which is a regexp matched against a -buffer's file name (the latter enables you to distinguish between -different kinds of files that have the same mode in Emacs). The -@sc{car} of an element may also be a cons cell, consisting of mode -name or regexp, as above, and an additional descriptive string. +@code{auto-insert-alist}. The @sc{car} of each element of this list is +either a mode name, making the element applicable when a buffer is in +that mode, or a string, which is a regexp matched against a buffer's +file name (the latter enables you to distinguish between different kinds +of files that have the same mode in Emacs). It can also be a predicate +declared through a plist of the form @code{(predicate @var{function})}. +@var{function} should be a predicate function of no arguments. The +@sc{car} of an element may also be a cons cell, consisting of mode name +or regexp, as above, and an additional descriptive string. When a matching element is found, the @sc{cdr} says what to do. It may be a string, which is a file name, whose contents are to be inserted, if diff --git a/etc/NEWS b/etc/NEWS index 13d1d1cba20..a2dd1c7299d 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -700,6 +700,15 @@ you could already use 'C-u C-x C-n' to clear the goal column. * Changes in Specialized Modes and Packages in Emacs 31.1 +** Autoinsert + ++++ +*** New condition for 'auto-insert-alist'. +'auto-insert-alist' now also allows to have a predicate taking no +argument as conditions. These types of conditions should be declared +with '(predicate FUNCTION)'. This allows to trigger 'auto-insert' +with finer grained control. + ** Register *** The "*Register Preview*" buffer shows only suitable registers. diff --git a/lisp/autoinsert.el b/lisp/autoinsert.el index e7492d1b9ed..a09689d65b9 100644 --- a/lisp/autoinsert.el +++ b/lisp/autoinsert.el @@ -325,6 +325,9 @@ The document was typeset with Elements look like (CONDITION . ACTION) or ((CONDITION . DESCRIPTION) . ACTION). CONDITION may be a regexp that must match the new file's name, or it may be a symbol that must match the major mode for this element to apply. +CONDITION can also be a custom predicate of no arguments declared with +'(predicate FUNCTION)'. Emacs will insert the text if the predicate +function returns non-nil. Only the first matching element is effective. Optional DESCRIPTION is a string for filling `auto-insert-prompt'. ACTION may be a skeleton to insert (see `skeleton-insert'), an absolute @@ -368,12 +371,24 @@ Matches the visited file name against the elements of `auto-insert-alist'." (pcase-lambda (`(,cond . ,action)) (if (atom cond) (setq desc cond) - (setq desc (cdr cond) - cond (car cond))) - (when (if (symbolp cond) - (derived-mode-p cond) + ;; if `cond' is a predicate, don't split it but set `desc' to a custom string + (if (and (consp cond) (equal (car cond) 'predicate)) + (setq desc "predicate") + (setq desc (cdr cond) + cond (car cond)))) + (when (cond + ;; `cond' should be a major-mode variable + ((symbolp cond) + (derived-mode-p cond)) + + ;; `cond' should be a predicate that takes no argument + ((and (consp cond) (equal (car cond) 'predicate)) + (funcall (cadr cond))) + + ;; cond should be a regexp + (t (and buffer-file-name - (string-match cond buffer-file-name))) + (string-match cond buffer-file-name)))) action)) auto-insert-alist))) (goto-char 1) diff --git a/test/lisp/autoinsert-tests.el b/test/lisp/autoinsert-tests.el index 5c97f0c2b33..5791ffd5c53 100644 --- a/test/lisp/autoinsert-tests.el +++ b/test/lisp/autoinsert-tests.el @@ -76,6 +76,40 @@ (auto-insert) (should (equal (buffer-string) "2nd"))))) +(ert-deftest autoinsert-tests-auto-insert-lambda () + (let ((auto-insert-alist + '(((predicate (lambda () t)) . (lambda () (insert "foo"))))) + (auto-insert-query nil)) + (with-temp-buffer + (auto-insert) + (should (equal (buffer-string) "foo"))))) + +(ert-deftest autoinsert-tests-auto-insert-predicate () + (defun predicate () t) + (let ((auto-insert-alist + '(((predicate predicate) . (lambda () (insert "foo"))))) + (auto-insert-query nil)) + (with-temp-buffer + (auto-insert) + (should (equal (buffer-string) "foo"))))) + +(ert-deftest autoinsert-tests-auto-insert-lambda-nil () + (let ((auto-insert-alist + '(((predicate (lambda () nil)) . (lambda () (insert "foo"))))) + (auto-insert-query nil)) + (with-temp-buffer + (auto-insert) + (should (equal (buffer-string) ""))))) + +(ert-deftest autoinsert-tests-auto-insert-predicate-nil () + (defun predicate () nil) + (let ((auto-insert-alist + '(((predicate predicate) . (lambda () (insert "foo"))))) + (auto-insert-query nil)) + (with-temp-buffer + (auto-insert) + (should (equal (buffer-string) ""))))) + (ert-deftest autoinsert-tests-define-auto-insert-before () (let ((auto-insert-alist (list (cons 'text-mode (lambda () (insert "foo")))))