From 38037e04cb05cb1f2b604f0b1602d36b0bcf6985 Mon Sep 17 00:00:00 2001 From: akater Date: Sat, 25 Sep 2021 03:27:29 +0200 Subject: [PATCH] Indent bodies of local function definitions properly in elisp-mode * lisp/emacs-lisp/lisp-mode.el (lisp-indent-function): Check for local defforms (`cl-flet' and `cl-labels'). (lisp--local-defform-body): New auxiliary function (bug#9622). --- etc/NEWS | 8 +++++ lisp/emacs-lisp/lisp-mode.el | 45 +++++++++++++++++++------ test/lisp/emacs-lisp/lisp-mode-tests.el | 11 ++++++ 3 files changed, 54 insertions(+), 10 deletions(-) diff --git a/etc/NEWS b/etc/NEWS index c266dddafa3..2f8fbc76144 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -3220,6 +3220,14 @@ file: (add-hook 'foo-mode-hook (lambda () (auto-fill-mode -1)) +--- +** Indentation of 'cl-flet' and 'cl-labels' has changed. +These forms now indent like this: + + (cl-flet ((bla (x) + (* x x))) + (bla 42)) + * Incompatible Lisp Changes in Emacs 28.1 diff --git a/lisp/emacs-lisp/lisp-mode.el b/lisp/emacs-lisp/lisp-mode.el index eac3c03cd1e..7ce857e990b 100644 --- a/lisp/emacs-lisp/lisp-mode.el +++ b/lisp/emacs-lisp/lisp-mode.el @@ -29,6 +29,7 @@ ;;; Code: (eval-when-compile (require 'cl-lib)) +(eval-when-compile (require 'subr-x)) (defvar font-lock-comment-face) (defvar font-lock-doc-face) @@ -1105,6 +1106,27 @@ is the buffer position of the start of the containing expression." (t normal-indent)))))) +(defun lisp--local-defform-body (state) + "Return non-nil if at local definition body according to STATE. +STATE is the `parse-partial-sexp' state for current position." + (when-let ((start-of-innermost-containing-list (nth 1 state))) + (let* ((parents (nth 9 state)) + (second-cons-after (cddr parents)) + second-order-parent) + (while second-cons-after + (when (= start-of-innermost-containing-list + (car second-cons-after)) + (setq second-order-parent (car parents) + ;; Leave the loop. + second-cons-after nil)) + (pop second-cons-after) + (pop parents)) + (and second-order-parent + (save-excursion + (goto-char (1+ second-order-parent)) + (memq (read (current-buffer)) + '(cl-flet cl-labels))))))) + (defun lisp-indent-function (indent-point state) "This function is the normal value of the variable `lisp-indent-function'. The function `calculate-lisp-indent' calls this to determine @@ -1138,16 +1160,17 @@ Lisp function does not specify a special indentation." (if (and (elt state 2) (not (looking-at "\\sw\\|\\s_"))) ;; car of form doesn't seem to be a symbol - (progn + (if (lisp--local-defform-body state) + (lisp-indent-defform state indent-point) (if (not (> (save-excursion (forward-line 1) (point)) calculate-lisp-indent-last-sexp)) - (progn (goto-char calculate-lisp-indent-last-sexp) - (beginning-of-line) - (parse-partial-sexp (point) - calculate-lisp-indent-last-sexp 0 t))) - ;; Indent under the list or under the first sexp on the same - ;; line as calculate-lisp-indent-last-sexp. Note that first - ;; thing on that line has to be complete sexp since we are + (progn (goto-char calculate-lisp-indent-last-sexp) + (beginning-of-line) + (parse-partial-sexp (point) + calculate-lisp-indent-last-sexp 0 t))) + ;; Indent under the list or under the first sexp on the same + ;; line as calculate-lisp-indent-last-sexp. Note that first + ;; thing on that line has to be complete sexp since we are ;; inside the innermost containing sexp. (backward-prefix-chars) (current-column)) @@ -1160,13 +1183,15 @@ Lisp function does not specify a special indentation." (cond ((or (eq method 'defun) (and (null method) (> (length function) 3) - (string-match "\\`def" function))) + (string-match "\\`def" function)) + ;; Check whether we are in flet or labels. + (lisp--local-defform-body state)) (lisp-indent-defform state indent-point)) ((integerp method) (lisp-indent-specform method state indent-point normal-indent)) (method - (funcall method indent-point state))))))) + (funcall method indent-point state))))))) (defcustom lisp-body-indent 2 "Number of columns to indent the second line of a `(def...)' form." diff --git a/test/lisp/emacs-lisp/lisp-mode-tests.el b/test/lisp/emacs-lisp/lisp-mode-tests.el index e2cecdf6b01..5e533b370ed 100644 --- a/test/lisp/emacs-lisp/lisp-mode-tests.el +++ b/test/lisp/emacs-lisp/lisp-mode-tests.el @@ -330,5 +330,16 @@ Expected initialization file: `%s'\" (faceup-clean-buffer) (should (faceup-test-font-lock-buffer 'emacs-lisp-mode faceup))))) +(ert-deftest test-cl-flet-indentation () + (should (equal + (with-temp-buffer + (lisp-mode) + (insert "(cl-flet ((bla (x)\n(* x x)))\n(bla 42))") + (indent-region (point-min) (point-max)) + (buffer-string)) + "(cl-flet ((bla (x) + (* x x))) + (bla 42))"))) + (provide 'lisp-mode-tests) ;;; lisp-mode-tests.el ends here -- 2.39.2