X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/65bd19ff8af487f16c55d250967321c0ee3e58a0..267b82ff2374a43cb38617a648c5bfa58ef2b039:/lisp/electric.el diff --git a/lisp/electric.el b/lisp/electric.el index 69acb77364..3108a0ed4c 100644 --- a/lisp/electric.el +++ b/lisp/electric.el @@ -1,6 +1,6 @@ ;;; electric.el --- window maker and Command loop for `electric' modes -;; Copyright (C) 1985-1986, 1995, 2001-2011 Free Software Foundation, Inc. +;; Copyright (C) 1985-1986, 1995, 2001-2012 Free Software Foundation, Inc. ;; Author: K. Shane Hartman ;; Maintainer: FSF @@ -38,8 +38,6 @@ ;;; Code: -(eval-when-compile (require 'cl)) - ;; This loop is the guts for non-standard modes which retain control ;; until some event occurs. It is a `do-forever', the only way out is ;; to throw. It assumes that you have set up the keymap, window, and @@ -85,7 +83,7 @@ (eq last-input-event ?\C-g)) (progn (setq unread-command-events nil prefix-arg nil) - ;; If it wasn't cancelling a prefix character, then quit. + ;; If it wasn't canceling a prefix character, then quit. (if (or (= (length (this-command-keys)) 1) (not inhibit-quit)) ; safety (progn (ding) @@ -197,11 +195,13 @@ Returns nil when we can't find this char." ;; value, which only works well if the variable is preloaded. ;;;###autoload (defvar electric-indent-chars '(?\n) - "Characters that should cause automatic reindentation. -Each entry of the list can be either a character or a cons of the -form (CHAR . PREDICATE) which means that CHAR should cause reindentation -only if PREDICATE returns non-nil. PREDICATE is called with no arguments -and with point before the inserted char.") + "Characters that should cause automatic reindentation.") + +(defvar electric-indent-functions nil + "Special hook run to decide whether to auto-indent. +Each function is called with one argument (the inserted char), with +point right after that char, and it should return t to cause indentation, +`no-indent' to prevent indentation or nil to let other functions decide.") (defun electric-indent-post-self-insert-function () ;; FIXME: This reindents the current line, but what we really want instead is @@ -212,18 +212,22 @@ and with point before the inserted char.") ;; There might be a way to get it working by analyzing buffer-undo-list, but ;; it looks challenging. (let (pos) - (when (and (or (memq last-command-event electric-indent-chars) - (let ((cp (assq last-command-event electric-indent-chars))) - (and cp (setq pos (electric--after-char-pos)) - (save-excursion - (goto-char (1- pos)) - (funcall (cdr cp)))))) - ;; Don't reindent while inserting spaces at beginning of line. - (or (not (memq last-command-event '(?\s ?\t))) - (save-excursion (skip-chars-backward " \t") (not (bolp)))) - (setq pos (electric--after-char-pos)) - ;; Not in a string or comment. - (not (nth 8 (save-excursion (syntax-ppss pos))))) + (when (and + electric-indent-mode + ;; Don't reindent while inserting spaces at beginning of line. + (or (not (memq last-command-event '(?\s ?\t))) + (save-excursion (skip-chars-backward " \t") (not (bolp)))) + (setq pos (electric--after-char-pos)) + (save-excursion + (goto-char pos) + (let ((act (or (run-hook-with-args-until-success + 'electric-indent-functions + last-command-event) + (memq last-command-event electric-indent-chars)))) + (not + (or (memq act '(nil no-indent)) + ;; In a string or comment. + (unless (eq act 'do-indent) (nth 8 (syntax-ppss)))))))) ;; For newline, we want to reindent both lines and basically behave like ;; reindent-then-newline-and-indent (whose code we hence copied). (when (< (1- pos) (line-beginning-position)) @@ -231,7 +235,7 @@ and with point before the inserted char.") (save-excursion (unless (memq indent-line-function '(indent-relative indent-to-left-margin - indent-relative-maybe)) + indent-relative-maybe)) ;; Don't reindent the previous line if the indentation function ;; is not a real one. (goto-char before) @@ -255,26 +259,36 @@ With a prefix argument ARG, enable Electric Indent mode if ARG is positive, and disable it otherwise. If called from Lisp, enable the mode if ARG is omitted or nil. -Electric Indent mode is a global minor mode. When enabled, -reindentation is triggered whenever you insert a character listed -in `electric-indent-chars'." +This is a global minor mode. When enabled, it reindents whenever +the hook `electric-indent-functions' returns non-nil, or you +insert a character from `electric-indent-chars'." :global t :group 'electricity - (if electric-indent-mode - (add-hook 'post-self-insert-hook - #'electric-indent-post-self-insert-function - ;; post-self-insert-hooks interact in non-trivial ways. - ;; It turns out that electric-indent-mode generally works - ;; better last. - 'append) - (remove-hook 'post-self-insert-hook - #'electric-indent-post-self-insert-function))) + (if (not electric-indent-mode) + (remove-hook 'post-self-insert-hook + #'electric-indent-post-self-insert-function) + ;; post-self-insert-hooks interact in non-trivial ways. + ;; It turns out that electric-indent-mode generally works better if run + ;; late, but still before blink-paren. + (add-hook 'post-self-insert-hook + #'electric-indent-post-self-insert-function + 'append) + ;; FIXME: Ugly! + (let ((bp (memq #'blink-paren-post-self-insert-function + (default-value 'post-self-insert-hook)))) + (when (memq #'electric-indent-post-self-insert-function bp) + (setcar bp #'electric-indent-post-self-insert-function) + (setcdr bp (cons #'blink-paren-post-self-insert-function + (delq #'electric-indent-post-self-insert-function + (cdr bp)))))))) ;; Electric pairing. (defcustom electric-pair-pairs '((?\" . ?\")) "Alist of pairs that should be used regardless of major mode." + :group 'electricity + :version "24.1" :type '(repeat (cons character character))) (defcustom electric-pair-skip-self t @@ -283,6 +297,8 @@ When inserting a closing paren character right before the same character, just skip that character instead, so that hitting ( followed by ) results in \"()\" rather than \"())\". This can be convenient for people who find it easier to hit ) than C-f." + :group 'electricity + :version "24.1" :type 'boolean) (defun electric-pair-post-self-insert-function () @@ -306,12 +322,13 @@ This can be convenient for people who find it easier to hit ) than C-f." ((and (memq syntax '(?\( ?\" ?\$)) (use-region-p)) (if (> (mark) (point)) (goto-char (mark)) - ;; We already inserted the open-paren but at the end of the region, - ;; so we have to remove it and start over. - (delete-char -1) - (save-excursion + ;; We already inserted the open-paren but at the end of the + ;; region, so we have to remove it and start over. + (delete-char -1) + (save-excursion (goto-char (mark)) - (insert last-command-event))) + ;; Do not insert after `save-excursion' marker (Bug#11520). + (insert-before-markers last-command-event))) (insert closer)) ;; Backslash-escaped: no pairing, no skipping. ((save-excursion @@ -347,7 +364,9 @@ 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 -closing parenthesis. \(Likewise for brackets, etc.)" +closing parenthesis. \(Likewise for brackets, etc.) + +See options `electric-pair-pairs' and `electric-pair-skip-self'." :global t :group 'electricity (if electric-pair-mode @@ -362,8 +381,8 @@ closing parenthesis. \(Likewise for brackets, etc.)" "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: nil, `before', `after', `around', or a function that returns -one of those symbols.") +and can be: nil, `before', `after', `around', or a function of no +arguments that returns one of those symbols.") (defun electric-layout-post-self-insert-function () (let* ((rule (cdr (assq last-command-event electric-layout-rules))) @@ -374,16 +393,16 @@ one of those symbols.") (not (nth 8 (save-excursion (syntax-ppss pos))))) (let ((end (copy-marker (point) t))) (goto-char pos) - (case (if (functionp rule) (funcall rule) rule) + (pcase (if (functionp rule) (funcall rule) rule) ;; 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. - (before (goto-char (1- pos)) (skip-chars-backward " \t") + (`before (goto-char (1- pos)) (skip-chars-backward " \t") (unless (bolp) (insert "\n"))) - (after (insert "\n")) ; FIXME: check eolp before inserting \n? - (around (save-excursion + (`after (insert "\n")) ; FIXME: check eolp before inserting \n? + (`around (save-excursion (goto-char (1- pos)) (skip-chars-backward " \t") (unless (bolp) (insert "\n"))) (insert "\n"))) ; FIXME: check eolp before inserting \n? @@ -391,7 +410,11 @@ one of those symbols.") ;;;###autoload (define-minor-mode electric-layout-mode - "Automatically insert newlines around some chars." + "Automatically insert newlines around some chars. +With a prefix argument ARG, enable Electric Layout mode if ARG is +positive, and disable it otherwise. If called from Lisp, enable +the mode if ARG is omitted or nil. +The variable `electric-layout-rules' says when and how to insert newlines." :global t :group 'electricity (if electric-layout-mode