diff options
Diffstat (limited to 'lisp/elec-pair.el')
-rw-r--r-- | lisp/elec-pair.el | 94 |
1 files changed, 63 insertions, 31 deletions
diff --git a/lisp/elec-pair.el b/lisp/elec-pair.el index b8a243b38a9..5fb9d751e25 100644 --- a/lisp/elec-pair.el +++ b/lisp/elec-pair.el @@ -155,6 +155,13 @@ return value is considered instead." (const :tag "Newline" ?\n)) (list character))) +(defvar-local electric-pair-skip-whitespace-function + #'electric-pair--skip-whitespace + "Function to use to skip whitespace forward. +Before attempting a skip, if `electric-pair-skip-whitespace' is +non-nil, this function is called. It move point to a new buffer +position, presumably skipping only whitespace in between.") + (defun electric-pair--skip-whitespace () "Skip whitespace forward, not crossing comment or string boundaries." (let ((saved (point)) @@ -220,7 +227,14 @@ inside a comment or string." (defun electric-pair--insert (char) (let ((last-command-event char) (blink-matching-paren nil) - (electric-pair-mode nil)) + (electric-pair-mode nil) + ;; When adding the "closer" delimiter, a job his function is + ;; frequently used for, we don't want to munch any extra + ;; newlines above us. That would be the default behaviour of + ;; `electric-layout-mode', which potentially kicked in before + ;; us to add these newlines, and is probably about to kick in + ;; again after we add the closer. + (electric-layout-allow-duplicate-newlines t)) (self-insert-command 1))) (cl-defmacro electric-pair--with-uncached-syntax ((table &optional start) &rest body) @@ -232,7 +246,7 @@ functions when `parse-sexp-lookup-properties' is non-nil. The cache is flushed from position START, defaulting to point." (declare (debug ((form &optional form) body)) (indent 1)) (let ((start-var (make-symbol "start"))) - `(let ((syntax-propertize-function nil) + `(let ((syntax-propertize-function #'ignore) (,start-var ,(or start '(point)))) (unwind-protect (with-syntax-table ,table @@ -398,6 +412,15 @@ strings." (let ((ppss (electric-pair--syntax-ppss (point) '(comment)))) (memq (nth 3 ppss) (list t char)))) +(defmacro electric-pair--save-literal-point-excursion (&rest body) + ;; FIXME: need this instead of `save-excursion' when functions in + ;; BODY, such as `electric-pair-inhibit-if-helps-balance' and + ;; `electric-pair-skip-if-helps-balance' modify and restore the + ;; buffer in a way that modifies the marker used by save-excursion. + (let ((point (make-symbol "point"))) + `(let ((,point (point))) + (unwind-protect (progn ,@body) (goto-char ,point))))) + (defun electric-pair-inhibit-if-helps-balance (char) "Return non-nil if auto-pairing of CHAR would hurt parentheses' balance. @@ -406,24 +429,28 @@ some list calculations, finally restoring the situation as if nothing happened." (pcase (electric-pair-syntax-info char) (`(,syntax ,pair ,_ ,s-or-c) - (unwind-protect - (progn - (delete-char -1) - (cond ((eq ?\( syntax) - (let* ((pair-data - (electric-pair--balance-info 1 s-or-c)) - (outermost (cdr pair-data))) - (cond ((car outermost) - nil) - (t - (eq (cdr outermost) pair))))) - ((eq syntax ?\") - (electric-pair--unbalanced-strings-p char)))) - (insert-char char))))) + (catch 'done + ;; FIXME: modify+undo is *very* tricky business. We used to + ;; use `delete-char' followed by `insert', but this changed the + ;; position some markers. The real fix would be to compute the + ;; result without having to modify the buffer at all. + (atomic-change-group + (delete-char -1) + (throw + 'done + (cond ((eq ?\( syntax) + (let* ((pair-data + (electric-pair--balance-info 1 s-or-c)) + (outermost (cdr pair-data))) + (cond ((car outermost) + nil) + (t + (eq (cdr outermost) pair))))) + ((eq syntax ?\") + (electric-pair--unbalanced-strings-p char))))))))) (defun electric-pair-skip-if-helps-balance (char) "Return non-nil if skipping CHAR would benefit parentheses' balance. - Works by first removing the character from the buffer, then doing some list calculations, finally restoring the situation as if nothing happened." @@ -445,7 +472,7 @@ happened." (not (eq (cdr outermost) pair))))))) ((eq syntax ?\") (electric-pair--inside-string-p char)))) - (insert-char char))))) + (insert char))))) (defun electric-pair-default-skip-self (char) (if electric-pair-preserve-balance @@ -491,7 +518,9 @@ happened." ((and (memq syntax '(?\) ?\" ?\$)) (and (or unconditional (if (functionp electric-pair-skip-self) - (funcall electric-pair-skip-self last-command-event) + (electric-pair--save-literal-point-excursion + (goto-char pos) + (funcall electric-pair-skip-self last-command-event)) electric-pair-skip-self)) (save-excursion (when (and (not (and unconditional @@ -501,7 +530,7 @@ happened." (functionp electric-pair-skip-whitespace)) (funcall electric-pair-skip-whitespace) electric-pair-skip-whitespace))) - (electric-pair--skip-whitespace)) + (funcall electric-pair-skip-whitespace-function)) (eq (char-after) last-command-event)))) ;; This is too late: rather than insert&delete we'd want to only ;; skip (or insert in overwrite mode). The difference is in what @@ -509,17 +538,19 @@ happened." ;; be visible to other post-self-insert-hook. We'll just have to ;; live with it for now. (when skip-whitespace-info - (electric-pair--skip-whitespace)) + (funcall electric-pair-skip-whitespace-function)) (delete-region (1- pos) (if (eq skip-whitespace-info 'chomp) (point) pos)) (forward-char)) ;; Insert matching pair. - ((and (memq syntax `(?\( ?\" ?\$)) + ((and (memq syntax '(?\( ?\" ?\$)) (not overwrite-mode) (or unconditional - (not (funcall electric-pair-inhibit-predicate - last-command-event)))) + (not (electric-pair--save-literal-point-excursion + (goto-char pos) + (funcall electric-pair-inhibit-predicate + last-command-event))))) (save-excursion (electric-pair--insert pair))))) (_ (when (and (if (functionp electric-pair-open-newline-between-pairs) @@ -533,8 +564,6 @@ happened." (matching-paren (char-after)))) (save-excursion (newline 1 t))))))) -(put 'electric-pair-post-self-insert-function 'priority 20) - (defun electric-pair-will-use-region () (and (use-region-p) (memq (car (electric-pair-syntax-info last-command-event)) @@ -574,9 +603,6 @@ ARG and KILLP are passed directly to ;;;###autoload (define-minor-mode electric-pair-mode "Toggle automatic parens pairing (Electric Pair mode). -With a prefix argument ARG, enable Electric Pair mode if ARG is -positive, and disable it otherwise. If called from Lisp, enable -the mode if ARG is omitted or nil. Electric Pair mode is a global minor mode. When enabled, typing an open parenthesis automatically inserts the corresponding @@ -589,8 +615,14 @@ To toggle the mode in a single buffer, use `electric-pair-local-mode'." (if electric-pair-mode (progn (add-hook 'post-self-insert-hook - #'electric-pair-post-self-insert-function) - (electric--sort-post-self-insertion-hook) + #'electric-pair-post-self-insert-function + ;; Prioritize this to kick in after + ;; `electric-layout-post-self-insert-function': that + ;; considerably simplifies interoperation when + ;; `electric-pair-mode', `electric-layout-mode' and + ;; `electric-indent-mode' are used together. + ;; Use `vc-region-history' on these lines for more info. + 50) (add-hook 'self-insert-uses-region-functions #'electric-pair-will-use-region)) (remove-hook 'post-self-insert-hook |