mirror of
https://git.savannah.gnu.org/git/emacs.git
synced 2024-12-23 10:34:07 +00:00
* lisp/electric.el (electricity): New group.
(electric-indent-chars): New var. (electric-indent-post-self-insert-function): New fun. (electric-indent-mode): New minor mode. (electric-pair-skip-self): New custom. (electric-pair-post-self-insert-function): New function. (electric-pair-mode): New minor mode.
This commit is contained in:
parent
0da208548b
commit
3b843809ca
2
etc/NEWS
2
etc/NEWS
@ -427,6 +427,8 @@ system or session bus.
|
||||
|
||||
* New Modes and Packages in Emacs 24.1
|
||||
|
||||
** New global minor modes electric-pair-mode and electric-indent-mode.
|
||||
|
||||
** pcase.el provides the ML-style pattern matching macro `pcase'.
|
||||
|
||||
** smie.el is a package providing a simple generic indentation engine.
|
||||
|
@ -1,5 +1,13 @@
|
||||
2010-09-03 Stefan Monnier <monnier@iro.umontreal.ca>
|
||||
|
||||
* electric.el (electricity): New group.
|
||||
(electric-indent-chars): New var.
|
||||
(electric-indent-post-self-insert-function): New fun.
|
||||
(electric-indent-mode): New minor mode.
|
||||
(electric-pair-skip-self): New custom.
|
||||
(electric-pair-post-self-insert-function): New function.
|
||||
(electric-pair-mode): New minor mode.
|
||||
|
||||
* calc/calc-aent.el (calcAlg-blink-matching-check): New fun, to replace
|
||||
calcAlg-blink-matching-open.
|
||||
(calc-alg-ent-map, calc-alg-ent-esc-map): Initialize in the declaration.
|
||||
|
140
lisp/electric.el
140
lisp/electric.el
@ -24,10 +24,23 @@
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
; zaaaaaaap
|
||||
;; "Electric" has been used in Emacs to refer to different things.
|
||||
;; Among them:
|
||||
;;
|
||||
;; - electric modes and buffers: modes that typically pop-up in a modal kind of
|
||||
;; way a transient buffer that automatically disappears as soon as the user
|
||||
;; is done with it.
|
||||
;;
|
||||
;; - electric keys: self inserting keys which additionally perform some side
|
||||
;; operation which happens to be often convenient at that time. Examples of
|
||||
;; such side operations are: reindenting code, inserting a newline,
|
||||
;; ... auto-fill-mode and abbrev-mode can be considered as built-in forms of
|
||||
;; electric key behavior.
|
||||
|
||||
;;; 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
|
||||
@ -157,6 +170,131 @@
|
||||
(fit-window-to-buffer win max-height))
|
||||
win)))
|
||||
|
||||
;;; Electric keys.
|
||||
|
||||
(defgroup electricity ()
|
||||
"Electric behavior for self inserting keys."
|
||||
:group 'editing)
|
||||
|
||||
;; Electric indentation.
|
||||
|
||||
(defvar electric-indent-chars '(?\n)
|
||||
"Characters that should cause automatic reindentation.")
|
||||
|
||||
(defun electric-indent-post-self-insert-function ()
|
||||
;; FIXME: This reindents the current line, but what we really want instead is
|
||||
;; to reindent the whole affected text. That's the current line for simple
|
||||
;; cases, but not all cases. We do take care of the newline case in an
|
||||
;; ad-hoc fashion, but there are still missing cases such as the case of
|
||||
;; electric-pair-mode wrapping a region with a pair of parens.
|
||||
;; There might be a way to get it working by analyzing buffer-undo-list, but
|
||||
;; it looks challenging.
|
||||
(when (and (memq last-command-event electric-indent-chars)
|
||||
;; 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))))
|
||||
;; Not in a string or comment.
|
||||
(not (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 (and (eq last-command-event ?\n)
|
||||
;; Sanity check.
|
||||
(eq (char-before) last-command-event))
|
||||
(let ((pos (copy-marker (1- (point)) t)))
|
||||
(save-excursion
|
||||
(goto-char pos)
|
||||
(indent-according-to-mode)
|
||||
;; We are at EOL before the call to indent-according-to-mode, and
|
||||
;; after it we usually are as well, but not always. We tried to
|
||||
;; address it with `save-excursion' but that uses a normal marker
|
||||
;; whereas we need `move after insertion', so we do the
|
||||
;; save/restore by hand.
|
||||
(goto-char pos)
|
||||
;; Remove the trailing whitespace after indentation because
|
||||
;; indentation may (re)introduce the whitespace.
|
||||
(delete-horizontal-space t))))
|
||||
(indent-according-to-mode)))
|
||||
|
||||
;;;###autoload
|
||||
(define-minor-mode electric-indent-mode
|
||||
"Automatically reindent lines of code when inserting particular chars.
|
||||
`electric-indent-chars' specifies the set of chars that should cause reindentation."
|
||||
:global t
|
||||
:group 'electricity
|
||||
(if electric-indent-mode
|
||||
(add-hook 'post-self-insert-hook
|
||||
#'electric-indent-post-self-insert-function)
|
||||
(remove-hook 'post-self-insert-hook
|
||||
#'electric-indent-post-self-insert-function)))
|
||||
|
||||
;; Electric pairing.
|
||||
|
||||
(defcustom electric-pair-skip-self t
|
||||
"If non-nil, skip char instead of inserting a second closing paren.
|
||||
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."
|
||||
:type 'boolean)
|
||||
|
||||
(defun electric-pair-post-self-insert-function ()
|
||||
(let* ((syntax (and (eq (char-before) last-command-event) ; Sanity check.
|
||||
(char-syntax last-command-event)))
|
||||
;; FIXME: when inserting the closer, we should maybe use
|
||||
;; self-insert-command, although it may prove tricky running
|
||||
;; post-self-insert-hook recursively, and we wouldn't want to trigger
|
||||
;; blink-matching-open.
|
||||
(closer (if (eq syntax ?\()
|
||||
(cdr (aref (syntax-table) last-command-event))
|
||||
last-command-event)))
|
||||
(cond
|
||||
;; Wrap a pair around the active region.
|
||||
((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
|
||||
(goto-char (mark))
|
||||
(insert last-command-event)))
|
||||
(insert closer))
|
||||
;; Backslash-escaped: no pairing, no skipping.
|
||||
((save-excursion
|
||||
(goto-char (1- (point)))
|
||||
(not (zerop (% (skip-syntax-backward "\\") 2))))
|
||||
nil)
|
||||
;; Skip self.
|
||||
((and (memq syntax '(?\) ?\" ?\$))
|
||||
electric-pair-skip-self
|
||||
(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 goes in the
|
||||
;; undo-log and in the intermediate state which might be visible to other
|
||||
;; post-self-insert-hook. We'll just have to live with it for now.
|
||||
(delete-char 1))
|
||||
;; Insert matching pair.
|
||||
((not (or (not (memq syntax `(?\( ?\" ?\$)))
|
||||
overwrite-mode
|
||||
;; I find it more often preferable not to pair when the
|
||||
;; same char is next.
|
||||
(eq last-command-event (char-after))
|
||||
(eq last-command-event (char-before (1- (point))))
|
||||
;; I also find it often preferable not to pair next to a word.
|
||||
(eq (char-syntax (following-char)) ?w)))
|
||||
(save-excursion (insert closer))))))
|
||||
|
||||
;;;###autoload
|
||||
(define-minor-mode electric-pair-mode
|
||||
"Automatically pair-up parens when inserting an open paren."
|
||||
:global t
|
||||
:group 'electricity
|
||||
(if electric-pair-mode
|
||||
(add-hook 'post-self-insert-hook
|
||||
#'electric-pair-post-self-insert-function)
|
||||
(remove-hook 'post-self-insert-hook
|
||||
#'electric-pair-post-self-insert-function)))
|
||||
|
||||
(provide 'electric)
|
||||
|
||||
;; arch-tag: dae045eb-dc2d-4fb7-9f27-9cc2ce277be8
|
||||
|
Loading…
Reference in New Issue
Block a user