diff options
| author | Stefan Monnier | 2010-09-03 15:06:51 +0200 |
|---|---|---|
| committer | Stefan Monnier | 2010-09-03 15:06:51 +0200 |
| commit | 3b843809cab8990cb1e239ef7d60262b6139ba34 (patch) | |
| tree | baea3fbeee58ce57dea651b2b9e59415c88a08bf | |
| parent | 0da208548b7029e608567112c0f4613613aae688 (diff) | |
| download | emacs-3b843809cab8990cb1e239ef7d60262b6139ba34.tar.gz emacs-3b843809cab8990cb1e239ef7d60262b6139ba34.zip | |
* 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.
| -rw-r--r-- | etc/NEWS | 2 | ||||
| -rw-r--r-- | lisp/ChangeLog | 8 | ||||
| -rw-r--r-- | lisp/electric.el | 140 |
3 files changed, 149 insertions, 1 deletions
| @@ -427,6 +427,8 @@ system or session bus. | |||
| 427 | 427 | ||
| 428 | * New Modes and Packages in Emacs 24.1 | 428 | * New Modes and Packages in Emacs 24.1 |
| 429 | 429 | ||
| 430 | ** New global minor modes electric-pair-mode and electric-indent-mode. | ||
| 431 | |||
| 430 | ** pcase.el provides the ML-style pattern matching macro `pcase'. | 432 | ** pcase.el provides the ML-style pattern matching macro `pcase'. |
| 431 | 433 | ||
| 432 | ** smie.el is a package providing a simple generic indentation engine. | 434 | ** smie.el is a package providing a simple generic indentation engine. |
diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 1c83ea2ad61..65beeb6e531 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog | |||
| @@ -1,5 +1,13 @@ | |||
| 1 | 2010-09-03 Stefan Monnier <monnier@iro.umontreal.ca> | 1 | 2010-09-03 Stefan Monnier <monnier@iro.umontreal.ca> |
| 2 | 2 | ||
| 3 | * electric.el (electricity): New group. | ||
| 4 | (electric-indent-chars): New var. | ||
| 5 | (electric-indent-post-self-insert-function): New fun. | ||
| 6 | (electric-indent-mode): New minor mode. | ||
| 7 | (electric-pair-skip-self): New custom. | ||
| 8 | (electric-pair-post-self-insert-function): New function. | ||
| 9 | (electric-pair-mode): New minor mode. | ||
| 10 | |||
| 3 | * calc/calc-aent.el (calcAlg-blink-matching-check): New fun, to replace | 11 | * calc/calc-aent.el (calcAlg-blink-matching-check): New fun, to replace |
| 4 | calcAlg-blink-matching-open. | 12 | calcAlg-blink-matching-open. |
| 5 | (calc-alg-ent-map, calc-alg-ent-esc-map): Initialize in the declaration. | 13 | (calc-alg-ent-map, calc-alg-ent-esc-map): Initialize in the declaration. |
diff --git a/lisp/electric.el b/lisp/electric.el index fb3e462efba..48d865d8957 100644 --- a/lisp/electric.el +++ b/lisp/electric.el | |||
| @@ -24,10 +24,23 @@ | |||
| 24 | 24 | ||
| 25 | ;;; Commentary: | 25 | ;;; Commentary: |
| 26 | 26 | ||
| 27 | ; zaaaaaaap | 27 | ;; "Electric" has been used in Emacs to refer to different things. |
| 28 | ;; Among them: | ||
| 29 | ;; | ||
| 30 | ;; - electric modes and buffers: modes that typically pop-up in a modal kind of | ||
| 31 | ;; way a transient buffer that automatically disappears as soon as the user | ||
| 32 | ;; is done with it. | ||
| 33 | ;; | ||
| 34 | ;; - electric keys: self inserting keys which additionally perform some side | ||
| 35 | ;; operation which happens to be often convenient at that time. Examples of | ||
| 36 | ;; such side operations are: reindenting code, inserting a newline, | ||
| 37 | ;; ... auto-fill-mode and abbrev-mode can be considered as built-in forms of | ||
| 38 | ;; electric key behavior. | ||
| 28 | 39 | ||
| 29 | ;;; Code: | 40 | ;;; Code: |
| 30 | 41 | ||
| 42 | (eval-when-compile (require 'cl)) | ||
| 43 | |||
| 31 | ;; This loop is the guts for non-standard modes which retain control | 44 | ;; This loop is the guts for non-standard modes which retain control |
| 32 | ;; until some event occurs. It is a `do-forever', the only way out is | 45 | ;; until some event occurs. It is a `do-forever', the only way out is |
| 33 | ;; to throw. It assumes that you have set up the keymap, window, and | 46 | ;; to throw. It assumes that you have set up the keymap, window, and |
| @@ -157,6 +170,131 @@ | |||
| 157 | (fit-window-to-buffer win max-height)) | 170 | (fit-window-to-buffer win max-height)) |
| 158 | win))) | 171 | win))) |
| 159 | 172 | ||
| 173 | ;;; Electric keys. | ||
| 174 | |||
| 175 | (defgroup electricity () | ||
| 176 | "Electric behavior for self inserting keys." | ||
| 177 | :group 'editing) | ||
| 178 | |||
| 179 | ;; Electric indentation. | ||
| 180 | |||
| 181 | (defvar electric-indent-chars '(?\n) | ||
| 182 | "Characters that should cause automatic reindentation.") | ||
| 183 | |||
| 184 | (defun electric-indent-post-self-insert-function () | ||
| 185 | ;; FIXME: This reindents the current line, but what we really want instead is | ||
| 186 | ;; to reindent the whole affected text. That's the current line for simple | ||
| 187 | ;; cases, but not all cases. We do take care of the newline case in an | ||
| 188 | ;; ad-hoc fashion, but there are still missing cases such as the case of | ||
| 189 | ;; electric-pair-mode wrapping a region with a pair of parens. | ||
| 190 | ;; There might be a way to get it working by analyzing buffer-undo-list, but | ||
| 191 | ;; it looks challenging. | ||
| 192 | (when (and (memq last-command-event electric-indent-chars) | ||
| 193 | ;; Don't reindent while inserting spaces at beginning of line. | ||
| 194 | (or (not (memq last-command-event '(?\s ?\t))) | ||
| 195 | (save-excursion (skip-chars-backward " \t") (not (bolp)))) | ||
| 196 | ;; Not in a string or comment. | ||
| 197 | (not (nth 8 (syntax-ppss)))) | ||
| 198 | ;; For newline, we want to reindent both lines and basically behave like | ||
| 199 | ;; reindent-then-newline-and-indent (whose code we hence copied). | ||
| 200 | (when (and (eq last-command-event ?\n) | ||
| 201 | ;; Sanity check. | ||
| 202 | (eq (char-before) last-command-event)) | ||
| 203 | (let ((pos (copy-marker (1- (point)) t))) | ||
| 204 | (save-excursion | ||
| 205 | (goto-char pos) | ||
| 206 | (indent-according-to-mode) | ||
| 207 | ;; We are at EOL before the call to indent-according-to-mode, and | ||
| 208 | ;; after it we usually are as well, but not always. We tried to | ||
| 209 | ;; address it with `save-excursion' but that uses a normal marker | ||
| 210 | ;; whereas we need `move after insertion', so we do the | ||
| 211 | ;; save/restore by hand. | ||
| 212 | (goto-char pos) | ||
| 213 | ;; Remove the trailing whitespace after indentation because | ||
| 214 | ;; indentation may (re)introduce the whitespace. | ||
| 215 | (delete-horizontal-space t)))) | ||
| 216 | (indent-according-to-mode))) | ||
| 217 | |||
| 218 | ;;;###autoload | ||
| 219 | (define-minor-mode electric-indent-mode | ||
| 220 | "Automatically reindent lines of code when inserting particular chars. | ||
| 221 | `electric-indent-chars' specifies the set of chars that should cause reindentation." | ||
| 222 | :global t | ||
| 223 | :group 'electricity | ||
| 224 | (if electric-indent-mode | ||
| 225 | (add-hook 'post-self-insert-hook | ||
| 226 | #'electric-indent-post-self-insert-function) | ||
| 227 | (remove-hook 'post-self-insert-hook | ||
| 228 | #'electric-indent-post-self-insert-function))) | ||
| 229 | |||
| 230 | ;; Electric pairing. | ||
| 231 | |||
| 232 | (defcustom electric-pair-skip-self t | ||
| 233 | "If non-nil, skip char instead of inserting a second closing paren. | ||
| 234 | When inserting a closing paren character right before the same character, | ||
| 235 | just skip that character instead, so that hitting ( followed by ) results | ||
| 236 | in \"()\" rather than \"())\". | ||
| 237 | This can be convenient for people who find it easier to hit ) than C-f." | ||
| 238 | :type 'boolean) | ||
| 239 | |||
| 240 | (defun electric-pair-post-self-insert-function () | ||
| 241 | (let* ((syntax (and (eq (char-before) last-command-event) ; Sanity check. | ||
| 242 | (char-syntax last-command-event))) | ||
| 243 | ;; FIXME: when inserting the closer, we should maybe use | ||
| 244 | ;; self-insert-command, although it may prove tricky running | ||
| 245 | ;; post-self-insert-hook recursively, and we wouldn't want to trigger | ||
| 246 | ;; blink-matching-open. | ||
| 247 | (closer (if (eq syntax ?\() | ||
| 248 | (cdr (aref (syntax-table) last-command-event)) | ||
| 249 | last-command-event))) | ||
| 250 | (cond | ||
| 251 | ;; Wrap a pair around the active region. | ||
| 252 | ((and (memq syntax '(?\( ?\" ?\$)) (use-region-p)) | ||
| 253 | (if (> (mark) (point)) | ||
| 254 | (goto-char (mark)) | ||
| 255 | ;; We already inserted the open-paren but at the end of the region, | ||
| 256 | ;; so we have to remove it and start over. | ||
| 257 | (delete-char -1) | ||
| 258 | (save-excursion | ||
| 259 | (goto-char (mark)) | ||
| 260 | (insert last-command-event))) | ||
| 261 | (insert closer)) | ||
| 262 | ;; Backslash-escaped: no pairing, no skipping. | ||
| 263 | ((save-excursion | ||
| 264 | (goto-char (1- (point))) | ||
| 265 | (not (zerop (% (skip-syntax-backward "\\") 2)))) | ||
| 266 | nil) | ||
| 267 | ;; Skip self. | ||
| 268 | ((and (memq syntax '(?\) ?\" ?\$)) | ||
| 269 | electric-pair-skip-self | ||
| 270 | (eq (char-after) last-command-event)) | ||
| 271 | ;; This is too late: rather than insert&delete we'd want to only skip (or | ||
| 272 | ;; insert in overwrite mode). The difference is in what goes in the | ||
| 273 | ;; undo-log and in the intermediate state which might be visible to other | ||
| 274 | ;; post-self-insert-hook. We'll just have to live with it for now. | ||
| 275 | (delete-char 1)) | ||
| 276 | ;; Insert matching pair. | ||
| 277 | ((not (or (not (memq syntax `(?\( ?\" ?\$))) | ||
| 278 | overwrite-mode | ||
| 279 | ;; I find it more often preferable not to pair when the | ||
| 280 | ;; same char is next. | ||
| 281 | (eq last-command-event (char-after)) | ||
| 282 | (eq last-command-event (char-before (1- (point)))) | ||
| 283 | ;; I also find it often preferable not to pair next to a word. | ||
| 284 | (eq (char-syntax (following-char)) ?w))) | ||
| 285 | (save-excursion (insert closer)))))) | ||
| 286 | |||
| 287 | ;;;###autoload | ||
| 288 | (define-minor-mode electric-pair-mode | ||
| 289 | "Automatically pair-up parens when inserting an open paren." | ||
| 290 | :global t | ||
| 291 | :group 'electricity | ||
| 292 | (if electric-pair-mode | ||
| 293 | (add-hook 'post-self-insert-hook | ||
| 294 | #'electric-pair-post-self-insert-function) | ||
| 295 | (remove-hook 'post-self-insert-hook | ||
| 296 | #'electric-pair-post-self-insert-function))) | ||
| 297 | |||
| 160 | (provide 'electric) | 298 | (provide 'electric) |
| 161 | 299 | ||
| 162 | ;; arch-tag: dae045eb-dc2d-4fb7-9f27-9cc2ce277be8 | 300 | ;; arch-tag: dae045eb-dc2d-4fb7-9f27-9cc2ce277be8 |