From: João Távora Date: Sun, 23 Dec 2018 22:49:55 +0000 (+0000) Subject: Slightly more powerful electric-layout-rules X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=1173d5092d1c832cf1fc5b5ca3a97203eb1142ff;p=emacs.git Slightly more powerful electric-layout-rules * lisp/electric.el (electric-layout-rules): Expand slightly. (electric-layout-post-self-insert-function-1): Accept new rules. * test/lisp/electric-tests.el (electric-pair-mode-newline-between-parens) (electric-layout-mode-newline-between-parens-without-e-p-m): New (failing) tests. --- diff --git a/lisp/electric.el b/lisp/electric.el index 96468077263..fb0a913f3be 100644 --- a/lisp/electric.el +++ b/lisp/electric.el @@ -363,9 +363,15 @@ use `electric-indent-local-mode'." (defvar electric-layout-rules nil "List of rules saying where to automatically insert newlines. -Each rule has the form (CHAR . WHERE) where CHAR is the char that -was just inserted and WHERE specifies where to insert newlines -and can be: +Each rule has the form (MATCHER . WHERE) where MATCHER examines +the state of the buffer after a certain character was inserted +and WHERE specifies where to insert newlines. + +MATCHER can be a character CHAR or a boolean function of no +arguments. The rule matches if the character just inserted was +CHAR or if the function return non-nil. + +WHERE and can be: * one of the symbols `before', `after', `around' and `after-stay'; @@ -375,9 +381,10 @@ and can be: * a function of no arguments that returns one of the previous values. -Each symbol specifies where in relation to CHAR the newline -character(s) should be inserted. `after-stay' means insert a -newline after CHAR but stay in the same place. +Each symbol specifies where, in relation to the position POS of +the character inserted, the newline character(s) should be +inserted. `after-stay' means insert a newline after POS but stay +in the same place. If multiple rules match, only first one is executed.") @@ -387,8 +394,19 @@ If multiple rules match, only first one is executed.") ;; for edebug's sake, a separate function (defun electric-layout-post-self-insert-function-1 () - (let (pos - (rule (cdr (assq last-command-event electric-layout-rules)))) + (let* (pos + probe + (rules electric-layout-rules) + (rule + (catch 'done + (while (setq probe (pop rules)) + (cond ((and (consp probe) + (or (eq (car probe) last-command-event) + (and (functionp (car probe)) + (funcall (car probe))))) + (throw 'done (cdr probe))) + ((functionp probe) + (throw 'done (funcall probe)))))))) (when (and rule (setq pos (electric--after-char-pos)) ;; Not in a string or comment. diff --git a/test/lisp/electric-tests.el b/test/lisp/electric-tests.el index af27fab0c6a..71ff73b3f8a 100644 --- a/test/lisp/electric-tests.el +++ b/test/lisp/electric-tests.el @@ -816,51 +816,89 @@ baz\"\"" ;;; tests for `electric-layout-mode' (ert-deftest electric-layout-int-main-kernel-style () - (save-electric-modes - (ert-with-test-buffer () - (c-mode) - (electric-layout-local-mode 1) - (electric-pair-local-mode 1) - (electric-indent-local-mode 1) - (setq-local electric-layout-rules - '((?\{ . (after-stay after)))) - (insert "int main () ") - (let ((last-command-event ?\{)) - (call-interactively (key-binding `[,last-command-event]))) - (should (equal (buffer-string) "int main () {\n \n}"))))) + (ert-with-test-buffer () + (c-mode) + (electric-layout-local-mode 1) + (electric-pair-local-mode 1) + (electric-indent-local-mode 1) + (setq-local electric-layout-rules + '((?\{ . (after-stay after)))) + (insert "int main () ") + (let ((last-command-event ?\{)) + (call-interactively (key-binding `[,last-command-event]))) + (should (equal (buffer-string) "int main () {\n \n}")))) (ert-deftest electric-layout-int-main-allman-style () - (save-electric-modes - (ert-with-test-buffer () - (c-mode) - (electric-layout-local-mode 1) - (electric-pair-local-mode 1) - (electric-indent-local-mode 1) - (setq-local electric-layout-rules - '((?\{ . (before after-stay after)))) - (insert "int main () ") - (let ((last-command-event ?\{)) - (call-interactively (key-binding `[,last-command-event]))) - (should (equal (buffer-string) "int main ()\n{\n \n}"))))) + (ert-with-test-buffer () + (c-mode) + (electric-layout-local-mode 1) + (electric-pair-local-mode 1) + (electric-indent-local-mode 1) + (setq-local electric-layout-rules + '((?\{ . (before after-stay after)))) + (insert "int main () ") + (let ((last-command-event ?\{)) + (call-interactively (key-binding `[,last-command-event]))) + (should (equal (buffer-string) "int main ()\n{\n \n}")))) (define-derived-mode plainer-c-mode c-mode "pC" - "A plainer C-mode") + "A plainer/saner C-mode with no internal electric machinery." + (c-toggle-electric-state -1) + (setq-local electric-indent-local-mode-hook nil) + (setq-local electric-indent-mode-hook nil) + (electric-indent-local-mode 1) + (dolist (key '(?\" ?\' ?\{ ?\} ?\( ?\) ?\[ ?\])) + (local-set-key (vector key) 'self-insert-command))) (ert-deftest electric-modes-in-c-mode-with-self-insert-command () - (save-electric-modes - (ert-with-test-buffer () - (plainer-c-mode) - (electric-layout-local-mode 1) - (electric-pair-local-mode 1) - (electric-indent-local-mode 1) - (dolist (key '(?\" ?\' ?\{ ?\} ?\( ?\) ?\[ ?\])) - (local-set-key (vector key) 'self-insert-command)) - (setq-local electric-layout-rules - '((?\{ . (before after-stay after)))) - (insert "int main () ") - (let ((last-command-event ?\{)) - (call-interactively (key-binding `[,last-command-event]))) - (should (equal (buffer-string) "int main ()\n{\n \n}"))))) + (ert-with-test-buffer () + (plainer-c-mode) + (electric-layout-local-mode 1) + (electric-pair-local-mode 1) + (electric-indent-local-mode 1) + (setq-local electric-layout-rules + '((?\{ . (before after-stay after)))) + (insert "int main () ") + (let ((last-command-event ?\{)) + (call-interactively (key-binding `[,last-command-event]))) + (should (equal (buffer-string) "int main ()\n{\n \n}")))) + +;; FIXME: The two following tests fail, because the newline simulation +;; fails to indent the new line. Interactively, they work fine. +;; Don't know why... +(ert-deftest electric-pair-mode-newline-between-parens () + :expected-result :failed + (ert-with-test-buffer (:name "electric-pair-mode-newline-between-parens") + (plainer-c-mode) + (electric-layout-local-mode -1) ;; ensure e-l-m mode is off + (electric-pair-local-mode 1) + (insert-before-markers "int main () {}") + (backward-char 1) + (let ((last-command-event ?\n)) + (call-interactively (key-binding `[,last-command-event]))) + (should (equal (buffer-string) "int main ()\n{\n \n}")))) + +(ert-deftest electric-layout-mode-newline-between-parens-without-e-p-m () + :expected-result :failed + (ert-with-test-buffer (:name "electric-pair-mode-newline-between-parens") + (plainer-c-mode) + (electric-layout-local-mode 1) + (electric-pair-local-mode -1) ;; ensure e-p-m mode is off + (electric-indent-local-mode 1) + (setq-local electric-layout-rules + '((?\n + . + (lambda () + (when (eq (save-excursion + (skip-chars-backward "\t\s") + (char-before (1- (point)))) + (matching-paren (char-after))) + '(after-stay)))))) + (insert "int main () {}") + (backward-char 1) + (let ((last-command-event ?\n)) + (call-interactively (key-binding `[,last-command-event]))) + (should (equal (buffer-string) "int main ()\n{\n \n}")))) (provide 'electric-tests) ;;; electric-tests.el ends here