From ab036bdedbb49ecc96d550b5e883e43bb03eaccc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20T=C3=A1vora?= Date: Fri, 21 Dec 2018 18:00:08 +0000 Subject: [PATCH 1/2] Extend electric-layout-mode to handle more complex layouts Also, have it play nice with electric-pair-mode. Multiple matching entries in `electric-layout-rules' are executed in order of appearance. When inserting a newline in the 'after-stay rule, ensure electric-pair-open-newline-between-pairs is nil. Arguably the logic behind electric-pair-open-newline-between-pairs should be moved to electric-layout-mode, but the current rule-matching engine doesn't allow for it. The current solution seems to be good enough for the situations reported in bug#33794. * lisp/electric.el (electric-layout-rules): Adjust docstring. (electric-layout-post-self-insert-function): Loop through rules. Bind electric-pair-open-newline-between-pairs to nil when handling after-stay. --- lisp/electric.el | 61 ++++++++++++++++++++++++++---------------------- 1 file changed, 33 insertions(+), 28 deletions(-) diff --git a/lisp/electric.el b/lisp/electric.el index 6dbf46b80c..6a307a49b9 100644 --- a/lisp/electric.el +++ b/lisp/electric.el @@ -370,38 +370,43 @@ electric-layout-rules The symbols specify 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.") +newline after CHAR but stay in the same place. + +If multiple rules match, they are all executed in order of +appearance.") (defun electric-layout-post-self-insert-function () - (let* ((rule (cdr (assq last-command-event electric-layout-rules))) - pos) - (when (and rule - (setq pos (electric--after-char-pos)) + (let (pos) + (when (and (setq pos (electric--after-char-pos)) ;; Not in a string or comment. (not (nth 8 (save-excursion (syntax-ppss pos))))) - (let ((end (point-marker)) - (sym (if (functionp rule) (funcall rule) rule))) - (set-marker-insertion-type end (not (eq sym 'after-stay))) - (goto-char pos) - (pcase sym - ;; FIXME: we used `newline' down here which called - ;; self-insert-command and ran post-self-insert-hook recursively. - ;; It happened to make electric-indent-mode work automatically with - ;; electric-layout-mode (at the cost of re-indenting lines - ;; multiple times), but I'm not sure it's what we want. - ;; - ;; FIXME: check eolp before inserting \n? - ('before (goto-char (1- pos)) (skip-chars-backward " \t") - (unless (bolp) (insert "\n"))) - ('after (insert "\n")) - ('after-stay (save-excursion - (let ((electric-layout-rules nil)) - (newline 1 t)))) - ('around (save-excursion - (goto-char (1- pos)) (skip-chars-backward " \t") - (unless (bolp) (insert "\n"))) - (insert "\n"))) ; FIXME: check eolp before inserting \n? - (goto-char end))))) + (goto-char pos) + (dolist (rule electric-layout-rules) + (when (eq last-command-event (car rule)) + (let* ((end (point-marker)) + (rule (cdr rule)) + (sym (if (functionp rule) (funcall rule) rule))) + (set-marker-insertion-type end (not (eq sym 'after-stay))) + (pcase sym + ;; FIXME: we used `newline' down here which called + ;; self-insert-command and ran post-self-insert-hook recursively. + ;; It happened to make electric-indent-mode work automatically with + ;; electric-layout-mode (at the cost of re-indenting lines + ;; multiple times), but I'm not sure it's what we want. + ;; + ;; FIXME: check eolp before inserting \n? + ('before (goto-char (1- pos)) (skip-chars-backward " \t") + (unless (bolp) (insert "\n"))) + ('after (insert "\n")) + ('after-stay (save-excursion + (let ((electric-layout-rules nil) + (electric-pair-open-newline-between-pairs nil)) + (newline 1 t)))) + ('around (save-excursion + (goto-char (1- pos)) (skip-chars-backward " \t") + (unless (bolp) (insert "\n"))) + (insert "\n"))) ; FIXME: check eolp before inserting \n? + (goto-char end))))))) (put 'electric-layout-post-self-insert-function 'priority 40) -- 2.20.0