diff options
| author | Simon Law | 2012-10-21 23:15:44 -0400 |
|---|---|---|
| committer | Stefan Monnier | 2012-10-21 23:15:44 -0400 |
| commit | b1d39ccce419eeec83a4bc723f6c9daf4ffb2be4 (patch) | |
| tree | ab245066cbdda726e5f4b667f03d01182a761911 | |
| parent | 4ee8774065666426cda990f91fdec8fe343bdf30 (diff) | |
| download | emacs-b1d39ccce419eeec83a4bc723f6c9daf4ffb2be4.tar.gz emacs-b1d39ccce419eeec83a4bc723f6c9daf4ffb2be4.zip | |
* lisp/delsel.el (delete-selection-helper): New function, extracted from
delete-selection-pre-hook.
(delete-selection-pre-hook): Use it.
(delete-selection-self-insert-function): New function.
(delete-selection-self-insert-hooks): New hook.
(self-insert-command, self-insert-iso): Use it.
* lisp/electric.el (electric-pair-syntax): New function, extracted from
electric-pair-post-self-insert-function.
(electric-pair-post-self-insert-function): Use it.
(electric-pair-delete-selection-self-insert-function): New function.
(electric-pair-mode): Require delsel and setup
delete-selection-self-insert-hooks.
Fixes: debbugs:11520
| -rw-r--r-- | lisp/ChangeLog | 19 | ||||
| -rw-r--r-- | lisp/delsel.el | 143 | ||||
| -rw-r--r-- | lisp/electric.el | 33 |
3 files changed, 134 insertions, 61 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 7d532ba899f..6edf13719ce 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog | |||
| @@ -1,3 +1,18 @@ | |||
| 1 | 2012-10-22 Simon Law <sfllaw@sfllaw.ca> (tiny change) | ||
| 2 | |||
| 3 | * delsel.el (delete-selection-helper): New function, extracted from | ||
| 4 | delete-selection-pre-hook. | ||
| 5 | (delete-selection-pre-hook): Use it. | ||
| 6 | (delete-selection-self-insert-function): New function. | ||
| 7 | (delete-selection-self-insert-hooks): New hook. | ||
| 8 | (self-insert-command, self-insert-iso): Use it. | ||
| 9 | * electric.el (electric-pair-syntax): New function, extracted from | ||
| 10 | electric-pair-post-self-insert-function. | ||
| 11 | (electric-pair-post-self-insert-function): Use it. | ||
| 12 | (electric-pair-delete-selection-self-insert-function): New function. | ||
| 13 | (electric-pair-mode): Require delsel and setup | ||
| 14 | delete-selection-self-insert-hooks (bug#11520). | ||
| 15 | |||
| 1 | 2012-10-20 Chong Yidong <cyd@gnu.org> | 16 | 2012-10-20 Chong Yidong <cyd@gnu.org> |
| 2 | 17 | ||
| 3 | * vc/vc.el (vc-diff-internal): Set up Diff mode even if there are | 18 | * vc/vc.el (vc-diff-internal): Set up Diff mode even if there are |
| @@ -8,8 +23,8 @@ | |||
| 8 | 23 | ||
| 9 | 2012-10-20 Arne Jørgensen <arne@arnested.dk> | 24 | 2012-10-20 Arne Jørgensen <arne@arnested.dk> |
| 10 | 25 | ||
| 11 | * progmodes/flymake.el (flymake-create-temp-inplace): Use | 26 | * progmodes/flymake.el (flymake-create-temp-inplace): |
| 12 | file-truename. | 27 | Use file-truename. |
| 13 | 28 | ||
| 14 | 2012-10-20 Eli Zaretskii <eliz@gnu.org> | 29 | 2012-10-20 Eli Zaretskii <eliz@gnu.org> |
| 15 | 30 | ||
diff --git a/lisp/delsel.el b/lisp/delsel.el index a6435672201..09f58e086a2 100644 --- a/lisp/delsel.el +++ b/lisp/delsel.el | |||
| @@ -47,6 +47,9 @@ | |||
| 47 | ;; non-nil | 47 | ;; non-nil |
| 48 | ;; The normal case: delete the active region prior to executing | 48 | ;; The normal case: delete the active region prior to executing |
| 49 | ;; the command which will insert replacement text. | 49 | ;; the command which will insert replacement text. |
| 50 | ;; hooks | ||
| 51 | ;; For commands which need to dynamically determine this behaviour. | ||
| 52 | ;; Each hook should return one of the above values or nil. | ||
| 50 | 53 | ||
| 51 | ;;; Code: | 54 | ;;; Code: |
| 52 | 55 | ||
| @@ -71,66 +74,106 @@ any selection." | |||
| 71 | (transient-mark-mode t))) | 74 | (transient-mark-mode t))) |
| 72 | 75 | ||
| 73 | (defun delete-active-region (&optional killp) | 76 | (defun delete-active-region (&optional killp) |
| 77 | "Delete the active region. | ||
| 78 | If KILLP in not-nil, the active region is killed instead of deleted." | ||
| 74 | (if killp | 79 | (if killp |
| 75 | (kill-region (point) (mark)) | 80 | (kill-region (point) (mark)) |
| 76 | (delete-region (point) (mark))) | 81 | (delete-region (point) (mark))) |
| 77 | t) | 82 | t) |
| 78 | 83 | ||
| 84 | (defun delete-selection-helper (type) | ||
| 85 | "Deletes selection according to TYPE: | ||
| 86 | 'yank | ||
| 87 | For commands which do a yank; ensures the region about to be | ||
| 88 | deleted isn't yanked. | ||
| 89 | 'supersede | ||
| 90 | Delete the active region and ignore the current command, | ||
| 91 | i.e. the command will just delete the region. | ||
| 92 | 'kill | ||
| 93 | `kill-region' is used on the selection, rather than | ||
| 94 | `delete-region'. (Text selected with the mouse will typically | ||
| 95 | be yankable anyhow.) | ||
| 96 | non-nil | ||
| 97 | The normal case: delete the active region prior to executing | ||
| 98 | the command which will insert replacement text. | ||
| 99 | hooks | ||
| 100 | For commands which need to dynamically determine this behaviour. | ||
| 101 | Each hook should return one of the above values or nil." | ||
| 102 | (condition-case data | ||
| 103 | (cond ((eq type 'kill) | ||
| 104 | (delete-active-region t)) | ||
| 105 | ((eq type 'yank) | ||
| 106 | ;; Before a yank command, make sure we don't yank the | ||
| 107 | ;; head of the kill-ring that really comes from the | ||
| 108 | ;; currently active region we are going to delete. | ||
| 109 | ;; That would make yank a no-op. | ||
| 110 | (when (and (string= (buffer-substring-no-properties | ||
| 111 | (point) (mark)) | ||
| 112 | (car kill-ring)) | ||
| 113 | (fboundp 'mouse-region-match) | ||
| 114 | (mouse-region-match)) | ||
| 115 | (current-kill 1)) | ||
| 116 | (delete-active-region)) | ||
| 117 | ((eq type 'supersede) | ||
| 118 | (let ((empty-region (= (point) (mark)))) | ||
| 119 | (delete-active-region) | ||
| 120 | (unless empty-region | ||
| 121 | (setq this-command 'ignore)))) | ||
| 122 | ((and (symbolp type) (not (booleanp type))) | ||
| 123 | (delete-selection-helper | ||
| 124 | (run-hook-with-args-until-success type))) | ||
| 125 | (type | ||
| 126 | (delete-active-region) | ||
| 127 | (if (and overwrite-mode | ||
| 128 | (eq this-command 'self-insert-command)) | ||
| 129 | (let ((overwrite-mode nil)) | ||
| 130 | (self-insert-command | ||
| 131 | (prefix-numeric-value current-prefix-arg)) | ||
| 132 | (setq this-command 'ignore))))) | ||
| 133 | ;; If ask-user-about-supersession-threat signals an error, | ||
| 134 | ;; stop safe_run_hooks from clearing out pre-command-hook. | ||
| 135 | (file-supersession (message "%s" (cadr data)) (ding)) | ||
| 136 | (text-read-only | ||
| 137 | ;; This signal may come either from `delete-active-region' or | ||
| 138 | ;; `self-insert-command' (when `overwrite-mode' is non-nil). | ||
| 139 | ;; To avoid clearing out `pre-command-hook' we handle this case | ||
| 140 | ;; by issuing a simple message. Note, however, that we do not | ||
| 141 | ;; handle all related problems: When read-only text ends before | ||
| 142 | ;; the end of the region, the latter is not deleted but any | ||
| 143 | ;; subsequent insertion will succeed. We could avoid this case | ||
| 144 | ;; by doing a (setq this-command 'ignore) here. This would, | ||
| 145 | ;; however, still not handle the case where read-only text ends | ||
| 146 | ;; precisely where the region starts: In that case the deletion | ||
| 147 | ;; would succeed but the subsequent insertion would fail with a | ||
| 148 | ;; text-read-only error. To handle that case we would have to | ||
| 149 | ;; investigate text properties at both ends of the region and | ||
| 150 | ;; skip the deletion when inserting text is forbidden there. | ||
| 151 | (message "Text is read-only") (ding)))) | ||
| 152 | |||
| 79 | (defun delete-selection-pre-hook () | 153 | (defun delete-selection-pre-hook () |
| 154 | "Normal hook run before commands that delete selections are executed. | ||
| 155 | Commands which will delete the selection need a 'delete-selection | ||
| 156 | property on their symbols; commands which insert text but don't | ||
| 157 | have this property won't delete the selection. | ||
| 158 | |||
| 159 | See `delete-selection-helper'. | ||
| 160 | " | ||
| 80 | (when (and delete-selection-mode transient-mark-mode mark-active | 161 | (when (and delete-selection-mode transient-mark-mode mark-active |
| 81 | (not buffer-read-only)) | 162 | (not buffer-read-only)) |
| 82 | (let ((type (and (symbolp this-command) | 163 | (let ((type (and (symbolp this-command) |
| 83 | (get this-command 'delete-selection)))) | 164 | (get this-command 'delete-selection)))) |
| 84 | (condition-case data | 165 | (delete-selection-helper type)))) |
| 85 | (cond ((eq type 'kill) | 166 | |
| 86 | (delete-active-region t)) | 167 | (defun delete-selection-self-insert-function () |
| 87 | ((eq type 'yank) | 168 | t) |
| 88 | ;; Before a yank command, make sure we don't yank the | 169 | |
| 89 | ;; head of the kill-ring that really comes from the | 170 | (defvar delete-selection-self-insert-hooks |
| 90 | ;; currently active region we are going to delete. | 171 | '(delete-selection-self-insert-function) |
| 91 | ;; That would make yank a no-op. | 172 | "Abnormal hook run before commands that insert characters. |
| 92 | (when (and (string= (buffer-substring-no-properties | 173 | This hook should return a TYPE that `delete-selection-helper' understands.") |
| 93 | (point) (mark)) | 174 | |
| 94 | (car kill-ring)) | 175 | (put 'self-insert-command 'delete-selection 'delete-selection-self-insert-hooks) |
| 95 | (fboundp 'mouse-region-match) | 176 | (put 'self-insert-iso 'delete-selection 'delete-selection-self-insert-hooks) |
| 96 | (mouse-region-match)) | ||
| 97 | (current-kill 1)) | ||
| 98 | (delete-active-region)) | ||
| 99 | ((eq type 'supersede) | ||
| 100 | (let ((empty-region (= (point) (mark)))) | ||
| 101 | (delete-active-region) | ||
| 102 | (unless empty-region | ||
| 103 | (setq this-command 'ignore)))) | ||
| 104 | (type | ||
| 105 | (delete-active-region) | ||
| 106 | (if (and overwrite-mode | ||
| 107 | (eq this-command 'self-insert-command)) | ||
| 108 | (let ((overwrite-mode nil)) | ||
| 109 | (self-insert-command | ||
| 110 | (prefix-numeric-value current-prefix-arg)) | ||
| 111 | (setq this-command 'ignore))))) | ||
| 112 | ;; If ask-user-about-supersession-threat signals an error, | ||
| 113 | ;; stop safe_run_hooks from clearing out pre-command-hook. | ||
| 114 | (file-supersession (message "%s" (cadr data)) (ding)) | ||
| 115 | (text-read-only | ||
| 116 | ;; This signal may come either from `delete-active-region' or | ||
| 117 | ;; `self-insert-command' (when `overwrite-mode' is non-nil). | ||
| 118 | ;; To avoid clearing out `pre-command-hook' we handle this case | ||
| 119 | ;; by issuing a simple message. Note, however, that we do not | ||
| 120 | ;; handle all related problems: When read-only text ends before | ||
| 121 | ;; the end of the region, the latter is not deleted but any | ||
| 122 | ;; subsequent insertion will succeed. We could avoid this case | ||
| 123 | ;; by doing a (setq this-command 'ignore) here. This would, | ||
| 124 | ;; however, still not handle the case where read-only text ends | ||
| 125 | ;; precisely where the region starts: In that case the deletion | ||
| 126 | ;; would succeed but the subsequent insertion would fail with a | ||
| 127 | ;; text-read-only error. To handle that case we would have to | ||
| 128 | ;; investigate text properties at both ends of the region and | ||
| 129 | ;; skip the deletion when inserting text is forbidden there. | ||
| 130 | (message "Text is read-only") (ding)))))) | ||
| 131 | |||
| 132 | (put 'self-insert-command 'delete-selection t) | ||
| 133 | (put 'self-insert-iso 'delete-selection t) | ||
| 134 | 177 | ||
| 135 | (put 'yank 'delete-selection 'yank) | 178 | (put 'yank 'delete-selection 'yank) |
| 136 | (put 'clipboard-yank 'delete-selection 'yank) | 179 | (put 'clipboard-yank 'delete-selection 'yank) |
diff --git a/lisp/electric.el b/lisp/electric.el index 3108a0ed4c0..e6fa1df914f 100644 --- a/lisp/electric.el +++ b/lisp/electric.el | |||
| @@ -301,14 +301,17 @@ This can be convenient for people who find it easier to hit ) than C-f." | |||
| 301 | :version "24.1" | 301 | :version "24.1" |
| 302 | :type 'boolean) | 302 | :type 'boolean) |
| 303 | 303 | ||
| 304 | (defun electric-pair-syntax (command-event) | ||
| 305 | (and electric-pair-mode | ||
| 306 | (let ((x (assq command-event electric-pair-pairs))) | ||
| 307 | (cond | ||
| 308 | (x (if (eq (car x) (cdr x)) ?\" ?\()) | ||
| 309 | ((rassq command-event electric-pair-pairs) ?\)) | ||
| 310 | (t (char-syntax command-event)))))) | ||
| 311 | |||
| 304 | (defun electric-pair-post-self-insert-function () | 312 | (defun electric-pair-post-self-insert-function () |
| 305 | (let* ((syntax (and (eq (char-before) last-command-event) ; Sanity check. | 313 | (let* ((syntax (and (eq (char-before) last-command-event) ; Sanity check. |
| 306 | electric-pair-mode | 314 | (electric-pair-syntax last-command-event))) |
| 307 | (let ((x (assq last-command-event electric-pair-pairs))) | ||
| 308 | (cond | ||
| 309 | (x (if (eq (car x) (cdr x)) ?\" ?\()) | ||
| 310 | ((rassq last-command-event electric-pair-pairs) ?\)) | ||
| 311 | (t (char-syntax last-command-event)))))) | ||
| 312 | ;; FIXME: when inserting the closer, we should maybe use | 315 | ;; FIXME: when inserting the closer, we should maybe use |
| 313 | ;; self-insert-command, although it may prove tricky running | 316 | ;; self-insert-command, although it may prove tricky running |
| 314 | ;; post-self-insert-hook recursively, and we wouldn't want to trigger | 317 | ;; post-self-insert-hook recursively, and we wouldn't want to trigger |
| @@ -355,6 +358,12 @@ This can be convenient for people who find it easier to hit ) than C-f." | |||
| 355 | (eq (char-syntax (following-char)) ?w))) | 358 | (eq (char-syntax (following-char)) ?w))) |
| 356 | (save-excursion (insert closer)))))) | 359 | (save-excursion (insert closer)))))) |
| 357 | 360 | ||
| 361 | (defun electric-pair-delete-selection-self-insert-function () | ||
| 362 | (let ((syntax (electric-pair-syntax last-command-event))) | ||
| 363 | (if (and (memq syntax '(?\( ?\" ?\$)) (use-region-p)) | ||
| 364 | 'keep | ||
| 365 | t))) | ||
| 366 | |||
| 358 | ;;;###autoload | 367 | ;;;###autoload |
| 359 | (define-minor-mode electric-pair-mode | 368 | (define-minor-mode electric-pair-mode |
| 360 | "Toggle automatic parens pairing (Electric Pair mode). | 369 | "Toggle automatic parens pairing (Electric Pair mode). |
| @@ -370,10 +379,16 @@ See options `electric-pair-pairs' and `electric-pair-skip-self'." | |||
| 370 | :global t | 379 | :global t |
| 371 | :group 'electricity | 380 | :group 'electricity |
| 372 | (if electric-pair-mode | 381 | (if electric-pair-mode |
| 373 | (add-hook 'post-self-insert-hook | 382 | (progn |
| 374 | #'electric-pair-post-self-insert-function) | 383 | (require 'delsel) |
| 384 | (add-hook 'post-self-insert-hook | ||
| 385 | #'electric-pair-post-self-insert-function) | ||
| 386 | (add-hook 'delete-selection-self-insert-hooks | ||
| 387 | #'electric-pair-delete-selection-self-insert-function)) | ||
| 375 | (remove-hook 'post-self-insert-hook | 388 | (remove-hook 'post-self-insert-hook |
| 376 | #'electric-pair-post-self-insert-function))) | 389 | #'electric-pair-post-self-insert-function) |
| 390 | (remove-hook 'delete-selection-self-insert-hooks | ||
| 391 | #'electric-pair-delete-selection-self-insert-function))) | ||
| 377 | 392 | ||
| 378 | ;; Automatically add newlines after/before/around some chars. | 393 | ;; Automatically add newlines after/before/around some chars. |
| 379 | 394 | ||