diff options
| author | Dmitry Gutov | 2015-11-14 13:02:35 +0200 |
|---|---|---|
| committer | Dmitry Gutov | 2015-11-14 13:02:35 +0200 |
| commit | f234fc2cb319de1e5e2eca1a84450ec220ce7955 (patch) | |
| tree | 37134b43d4270bf955757a7c7f571756b493c7a8 | |
| parent | 4d71d2471aaf341791fd728287bf8db62aebb3ba (diff) | |
| parent | 138ad3d93b7abe08ac399f582aa6c8aac869e17e (diff) | |
| download | emacs-f234fc2cb319de1e5e2eca1a84450ec220ce7955.tar.gz emacs-f234fc2cb319de1e5e2eca1a84450ec220ce7955.zip | |
Merge branch 'master' into emacs-25
| -rw-r--r-- | lisp/emulation/cua-rect.el | 26 | ||||
| -rw-r--r-- | lisp/progmodes/elisp-mode.el | 41 | ||||
| -rw-r--r-- | lisp/progmodes/etags.el | 21 | ||||
| -rw-r--r-- | lisp/progmodes/xref.el | 249 | ||||
| -rw-r--r-- | lisp/rect.el | 32 | ||||
| -rw-r--r-- | lisp/replace.el | 87 | ||||
| -rw-r--r-- | lisp/simple.el | 229 | ||||
| -rw-r--r-- | lisp/vc/diff-mode.el | 2 | ||||
| -rw-r--r-- | src/casefiddle.c | 22 |
9 files changed, 415 insertions, 294 deletions
diff --git a/lisp/emulation/cua-rect.el b/lisp/emulation/cua-rect.el index ea8b52476f7..d389f6ec0a2 100644 --- a/lisp/emulation/cua-rect.el +++ b/lisp/emulation/cua-rect.el | |||
| @@ -666,6 +666,22 @@ If command is repeated at same position, delete the rectangle." | |||
| 666 | (setq rect (cons row rect)))))) | 666 | (setq rect (cons row rect)))))) |
| 667 | (nreverse rect))) | 667 | (nreverse rect))) |
| 668 | 668 | ||
| 669 | (defun cua--extract-rectangle-bounds () | ||
| 670 | (let (rect) | ||
| 671 | (if (not (cua--rectangle-virtual-edges)) | ||
| 672 | (cua--rectangle-operation nil nil nil nil nil ; do not tabify | ||
| 673 | (lambda (s e _l _r) | ||
| 674 | (setq rect (cons (cons s e) rect)))) | ||
| 675 | (cua--rectangle-operation nil 1 nil nil nil ; do not tabify | ||
| 676 | (lambda (s e l r _v) | ||
| 677 | (goto-char s) | ||
| 678 | (move-to-column l) | ||
| 679 | (setq s (point)) | ||
| 680 | (move-to-column r) | ||
| 681 | (setq e (point)) | ||
| 682 | (setq rect (cons (cons s e) rect))))) | ||
| 683 | (nreverse rect))) | ||
| 684 | |||
| 669 | (defun cua--insert-rectangle (rect &optional below paste-column line-count) | 685 | (defun cua--insert-rectangle (rect &optional below paste-column line-count) |
| 670 | ;; Insert rectangle as insert-rectangle, but don't set mark and exit with | 686 | ;; Insert rectangle as insert-rectangle, but don't set mark and exit with |
| 671 | ;; point at either next to top right or below bottom left corner | 687 | ;; point at either next to top right or below bottom left corner |
| @@ -1394,6 +1410,8 @@ With prefix arg, indent to that column." | |||
| 1394 | 1410 | ||
| 1395 | (add-function :around region-extract-function | 1411 | (add-function :around region-extract-function |
| 1396 | #'cua--rectangle-region-extract) | 1412 | #'cua--rectangle-region-extract) |
| 1413 | (add-function :around region-insert-function | ||
| 1414 | #'cua--insert-rectangle) | ||
| 1397 | (add-function :around redisplay-highlight-region-function | 1415 | (add-function :around redisplay-highlight-region-function |
| 1398 | #'cua--rectangle-highlight-for-redisplay) | 1416 | #'cua--rectangle-highlight-for-redisplay) |
| 1399 | 1417 | ||
| @@ -1405,8 +1423,12 @@ With prefix arg, indent to that column." | |||
| 1405 | 1423 | ||
| 1406 | (defun cua--rectangle-region-extract (orig &optional delete) | 1424 | (defun cua--rectangle-region-extract (orig &optional delete) |
| 1407 | (cond | 1425 | (cond |
| 1408 | ((not cua--rectangle) (funcall orig delete)) | 1426 | ((not cua--rectangle) |
| 1409 | ((eq delete 'delete-only) (cua--delete-rectangle)) | 1427 | (funcall orig delete)) |
| 1428 | ((eq delete 'bounds) | ||
| 1429 | (cua--extract-rectangle-bounds)) | ||
| 1430 | ((eq delete 'delete-only) | ||
| 1431 | (cua--delete-rectangle)) | ||
| 1410 | (t | 1432 | (t |
| 1411 | (let* ((strs (cua--extract-rectangle)) | 1433 | (let* ((strs (cua--extract-rectangle)) |
| 1412 | (str (mapconcat #'identity strs "\n"))) | 1434 | (str (mapconcat #'identity strs "\n"))) |
diff --git a/lisp/progmodes/elisp-mode.el b/lisp/progmodes/elisp-mode.el index af2ea56dcee..2c22483e86f 100644 --- a/lisp/progmodes/elisp-mode.el +++ b/lisp/progmodes/elisp-mode.el | |||
| @@ -228,8 +228,7 @@ Blank lines separate paragraphs. Semicolons start comments. | |||
| 228 | 228 | ||
| 229 | \\{emacs-lisp-mode-map}" | 229 | \\{emacs-lisp-mode-map}" |
| 230 | :group 'lisp | 230 | :group 'lisp |
| 231 | (defvar xref-find-function) | 231 | (defvar xref-backend-functions) |
| 232 | (defvar xref-identifier-completion-table-function) | ||
| 233 | (defvar project-library-roots-function) | 232 | (defvar project-library-roots-function) |
| 234 | (lisp-mode-variables nil nil 'elisp) | 233 | (lisp-mode-variables nil nil 'elisp) |
| 235 | (add-hook 'after-load-functions #'elisp--font-lock-flush-elisp-buffers) | 234 | (add-hook 'after-load-functions #'elisp--font-lock-flush-elisp-buffers) |
| @@ -239,9 +238,7 @@ Blank lines separate paragraphs. Semicolons start comments. | |||
| 239 | (setq imenu-case-fold-search nil) | 238 | (setq imenu-case-fold-search nil) |
| 240 | (add-function :before-until (local 'eldoc-documentation-function) | 239 | (add-function :before-until (local 'eldoc-documentation-function) |
| 241 | #'elisp-eldoc-documentation-function) | 240 | #'elisp-eldoc-documentation-function) |
| 242 | (setq-local xref-find-function #'elisp-xref-find) | 241 | (add-hook 'xref-backend-functions #'elisp--xref-backend nil t) |
| 243 | (setq-local xref-identifier-completion-table-function | ||
| 244 | #'elisp--xref-identifier-completion-table) | ||
| 245 | (setq-local project-library-roots-function #'elisp-library-roots) | 242 | (setq-local project-library-roots-function #'elisp-library-roots) |
| 246 | (add-hook 'completion-at-point-functions | 243 | (add-hook 'completion-at-point-functions |
| 247 | #'elisp-completion-at-point nil 'local)) | 244 | #'elisp-completion-at-point nil 'local)) |
| @@ -588,21 +585,7 @@ It can be quoted, or be inside a quoted form." | |||
| 588 | (declare-function xref-make "xref" (summary location)) | 585 | (declare-function xref-make "xref" (summary location)) |
| 589 | (declare-function xref-collect-references "xref" (symbol dir)) | 586 | (declare-function xref-collect-references "xref" (symbol dir)) |
| 590 | 587 | ||
| 591 | (defun elisp-xref-find (action id) | 588 | (defun elisp--xref-backend () 'elisp) |
| 592 | (require 'find-func) | ||
| 593 | ;; FIXME: use information in source near point to filter results: | ||
| 594 | ;; (dvc-log-edit ...) - exclude 'feature | ||
| 595 | ;; (require 'dvc-log-edit) - only 'feature | ||
| 596 | ;; Semantic may provide additional information | ||
| 597 | (pcase action | ||
| 598 | (`definitions | ||
| 599 | (let ((sym (intern-soft id))) | ||
| 600 | (when sym | ||
| 601 | (elisp--xref-find-definitions sym)))) | ||
| 602 | (`references | ||
| 603 | (elisp--xref-find-references id)) | ||
| 604 | (`apropos | ||
| 605 | (elisp--xref-find-apropos id)))) | ||
| 606 | 589 | ||
| 607 | ;; WORKAROUND: This is nominally a constant, but the text properties | 590 | ;; WORKAROUND: This is nominally a constant, but the text properties |
| 608 | ;; are not preserved thru dump if use defconst. See bug#21237. | 591 | ;; are not preserved thru dump if use defconst. See bug#21237. |
| @@ -638,7 +621,17 @@ Each function should return a list of xrefs, or nil; the first | |||
| 638 | non-nil result supercedes the xrefs produced by | 621 | non-nil result supercedes the xrefs produced by |
| 639 | `elisp--xref-find-definitions'.") | 622 | `elisp--xref-find-definitions'.") |
| 640 | 623 | ||
| 641 | ;; FIXME: name should be singular; match xref-find-definition | 624 | (cl-defmethod xref-backend-definitions ((_backend (eql elisp)) identifier) |
| 625 | (require 'find-func) | ||
| 626 | ;; FIXME: use information in source near point to filter results: | ||
| 627 | ;; (dvc-log-edit ...) - exclude 'feature | ||
| 628 | ;; (require 'dvc-log-edit) - only 'feature | ||
| 629 | ;; Semantic may provide additional information | ||
| 630 | ;; | ||
| 631 | (let ((sym (intern-soft identifier))) | ||
| 632 | (when sym | ||
| 633 | (elisp--xref-find-definitions sym)))) | ||
| 634 | |||
| 642 | (defun elisp--xref-find-definitions (symbol) | 635 | (defun elisp--xref-find-definitions (symbol) |
| 643 | ;; The file name is not known when `symbol' is defined via interactive eval. | 636 | ;; The file name is not known when `symbol' is defined via interactive eval. |
| 644 | (let (xrefs) | 637 | (let (xrefs) |
| @@ -805,7 +798,7 @@ non-nil result supercedes the xrefs produced by | |||
| 805 | (declare-function project-roots "project") | 798 | (declare-function project-roots "project") |
| 806 | (declare-function project-current "project") | 799 | (declare-function project-current "project") |
| 807 | 800 | ||
| 808 | (defun elisp--xref-find-references (symbol) | 801 | (cl-defmethod xref-backend-references ((_backend (eql elisp)) symbol) |
| 809 | "Find all references to SYMBOL (a string) in the current project." | 802 | "Find all references to SYMBOL (a string) in the current project." |
| 810 | (cl-mapcan | 803 | (cl-mapcan |
| 811 | (lambda (dir) | 804 | (lambda (dir) |
| @@ -815,7 +808,7 @@ non-nil result supercedes the xrefs produced by | |||
| 815 | (project-roots pr) | 808 | (project-roots pr) |
| 816 | (project-library-roots pr))))) | 809 | (project-library-roots pr))))) |
| 817 | 810 | ||
| 818 | (defun elisp--xref-find-apropos (regexp) | 811 | (cl-defmethod xref-backend-apropos ((_backend (eql elisp)) regexp) |
| 819 | (apply #'nconc | 812 | (apply #'nconc |
| 820 | (let (lst) | 813 | (let (lst) |
| 821 | (dolist (sym (apropos-internal regexp)) | 814 | (dolist (sym (apropos-internal regexp)) |
| @@ -832,7 +825,7 @@ non-nil result supercedes the xrefs produced by | |||
| 832 | (facep sym))) | 825 | (facep sym))) |
| 833 | 'strict)) | 826 | 'strict)) |
| 834 | 827 | ||
| 835 | (defun elisp--xref-identifier-completion-table () | 828 | (cl-defmethod xref-backend-identifier-completion-table ((_backend (eql elisp))) |
| 836 | elisp--xref-identifier-completion-table) | 829 | elisp--xref-identifier-completion-table) |
| 837 | 830 | ||
| 838 | (cl-defstruct (xref-elisp-location | 831 | (cl-defstruct (xref-elisp-location |
diff --git a/lisp/progmodes/etags.el b/lisp/progmodes/etags.el index 38c5cc2bdb6..ae1aa11fbc2 100644 --- a/lisp/progmodes/etags.el +++ b/lisp/progmodes/etags.el | |||
| @@ -2084,17 +2084,12 @@ for \\[find-tag] (which see)." | |||
| 2084 | 2084 | ||
| 2085 | (defvar etags-xref-find-definitions-tag-order '(tag-exact-match-p | 2085 | (defvar etags-xref-find-definitions-tag-order '(tag-exact-match-p |
| 2086 | tag-implicit-name-match-p) | 2086 | tag-implicit-name-match-p) |
| 2087 | "Tag order used in `etags-xref-find' to look for definitions.") | 2087 | "Tag order used in `xref-backend-definitions' to look for definitions.") |
| 2088 | 2088 | ||
| 2089 | ;;;###autoload | 2089 | (cl-defmethod xref-backend-identifier-completion-table ((_backend (eql etags))) |
| 2090 | (defun etags-xref-find (action id) | 2090 | (tags-lazy-completion-table)) |
| 2091 | (pcase action | 2091 | |
| 2092 | (`definitions (etags--xref-find-definitions id)) | 2092 | (cl-defmethod xref-backend-references ((_backend (eql etags)) symbol) |
| 2093 | (`references (etags--xref-find-references id)) | ||
| 2094 | (`apropos (etags--xref-find-definitions id t)))) | ||
| 2095 | |||
| 2096 | (defun etags--xref-find-references (symbol) | ||
| 2097 | ;; TODO: Merge together with the Elisp impl. | ||
| 2098 | (cl-mapcan | 2093 | (cl-mapcan |
| 2099 | (lambda (dir) | 2094 | (lambda (dir) |
| 2100 | (xref-collect-references symbol dir)) | 2095 | (xref-collect-references symbol dir)) |
| @@ -2103,6 +2098,12 @@ for \\[find-tag] (which see)." | |||
| 2103 | (project-roots pr) | 2098 | (project-roots pr) |
| 2104 | (project-library-roots pr))))) | 2099 | (project-library-roots pr))))) |
| 2105 | 2100 | ||
| 2101 | (cl-defmethod xref-backend-definitions ((_backend (eql etags)) symbol) | ||
| 2102 | (etags--xref-find-definitions symbol)) | ||
| 2103 | |||
| 2104 | (cl-defmethod xref-backend-apropos ((_backend (eql etags)) symbol) | ||
| 2105 | (etags--xref-find-definitions symbol t)) | ||
| 2106 | |||
| 2106 | (defun etags--xref-find-definitions (pattern &optional regexp?) | 2107 | (defun etags--xref-find-definitions (pattern &optional regexp?) |
| 2107 | ;; This emulates the behaviour of `find-tag-in-order' but instead of | 2108 | ;; This emulates the behaviour of `find-tag-in-order' but instead of |
| 2108 | ;; returning one match at a time all matches are returned as list. | 2109 | ;; returning one match at a time all matches are returned as list. |
diff --git a/lisp/progmodes/xref.el b/lisp/progmodes/xref.el index 89a06046ca2..6a3b42ff646 100644 --- a/lisp/progmodes/xref.el +++ b/lisp/progmodes/xref.el | |||
| @@ -23,14 +23,21 @@ | |||
| 23 | ;; referencing commands, in particular "find-definition". | 23 | ;; referencing commands, in particular "find-definition". |
| 24 | ;; | 24 | ;; |
| 25 | ;; Some part of the functionality must be implemented in a language | 25 | ;; Some part of the functionality must be implemented in a language |
| 26 | ;; dependent way and that's done by defining `xref-find-function', | 26 | ;; dependent way and that's done by defining an xref backend. |
| 27 | ;; `xref-identifier-at-point-function' and | ||
| 28 | ;; `xref-identifier-completion-table-function', which see. | ||
| 29 | ;; | 27 | ;; |
| 30 | ;; A major mode should make these variables buffer-local first. | 28 | ;; That consists of a constructor function, which should return a |
| 29 | ;; backend value, and a set of implementations for the generic | ||
| 30 | ;; functions: | ||
| 31 | ;; | 31 | ;; |
| 32 | ;; `xref-find-function' can be called in several ways, see its | 32 | ;; `xref-backend-identifier-at-point', |
| 33 | ;; description. It has to operate with "xref" and "location" values. | 33 | ;; `xref-backend-identifier-completion-table', |
| 34 | ;; `xref-backend-definitions', `xref-backend-references', | ||
| 35 | ;; `xref-backend-apropos', which see. | ||
| 36 | ;; | ||
| 37 | ;; A major mode would normally use `add-hook' to add the backend | ||
| 38 | ;; constructor to `xref-backend-functions'. | ||
| 39 | ;; | ||
| 40 | ;; The last three methods operate with "xref" and "location" values. | ||
| 34 | ;; | 41 | ;; |
| 35 | ;; One would usually call `make-xref' and `xref-make-file-location', | 42 | ;; One would usually call `make-xref' and `xref-make-file-location', |
| 36 | ;; `xref-make-buffer-location' or `xref-make-bogus-location' to create | 43 | ;; `xref-make-buffer-location' or `xref-make-bogus-location' to create |
| @@ -38,15 +45,19 @@ | |||
| 38 | ;; class inheriting from `xref-location' and implementing | 45 | ;; class inheriting from `xref-location' and implementing |
| 39 | ;; `xref-location-group' and `xref-location-marker'. | 46 | ;; `xref-location-group' and `xref-location-marker'. |
| 40 | ;; | 47 | ;; |
| 48 | ;; There's a special kind of xrefs we call "match xrefs", which | ||
| 49 | ;; correspond to search results. For these values, | ||
| 50 | ;; `xref-match-length' must be defined, and `xref-location-marker' | ||
| 51 | ;; must return the beginning of the match. | ||
| 52 | ;; | ||
| 41 | ;; Each identifier must be represented as a string. Implementers can | 53 | ;; Each identifier must be represented as a string. Implementers can |
| 42 | ;; use string properties to store additional information about the | 54 | ;; use string properties to store additional information about the |
| 43 | ;; identifier, but they should keep in mind that values returned from | 55 | ;; identifier, but they should keep in mind that values returned from |
| 44 | ;; `xref-identifier-completion-table-function' should still be | 56 | ;; `xref-backend-identifier-completion-table' should still be |
| 45 | ;; distinct, because the user can't see the properties when making the | 57 | ;; distinct, because the user can't see the properties when making the |
| 46 | ;; choice. | 58 | ;; choice. |
| 47 | ;; | 59 | ;; |
| 48 | ;; See the functions `etags-xref-find' and `elisp-xref-find' for full | 60 | ;; See the etags and elisp-mode implementations for full examples. |
| 49 | ;; examples. | ||
| 50 | 61 | ||
| 51 | ;;; Code: | 62 | ;;; Code: |
| 52 | 63 | ||
| @@ -79,8 +90,8 @@ This is typically the filename.") | |||
| 79 | "Return the line number corresponding to the location." | 90 | "Return the line number corresponding to the location." |
| 80 | nil) | 91 | nil) |
| 81 | 92 | ||
| 82 | (cl-defgeneric xref-match-bounds (_item) | 93 | (cl-defgeneric xref-match-length (_item) |
| 83 | "Return a cons with columns of the beginning and end of the match." | 94 | "Return the length of the match." |
| 84 | nil) | 95 | nil) |
| 85 | 96 | ||
| 86 | ;;;; Commonly needed location classes are defined here: | 97 | ;;;; Commonly needed location classes are defined here: |
| @@ -109,7 +120,7 @@ Line numbers start from 1 and columns from 0.") | |||
| 109 | (save-excursion | 120 | (save-excursion |
| 110 | (goto-char (point-min)) | 121 | (goto-char (point-min)) |
| 111 | (beginning-of-line line) | 122 | (beginning-of-line line) |
| 112 | (move-to-column column) | 123 | (forward-char column) |
| 113 | (point-marker)))))) | 124 | (point-marker)))))) |
| 114 | 125 | ||
| 115 | (cl-defmethod xref-location-group ((l xref-file-location)) | 126 | (cl-defmethod xref-location-group ((l xref-file-location)) |
| @@ -176,55 +187,60 @@ LOCATION is an `xref-location'." | |||
| 176 | (location :initarg :location | 187 | (location :initarg :location |
| 177 | :type xref-file-location | 188 | :type xref-file-location |
| 178 | :reader xref-item-location) | 189 | :reader xref-item-location) |
| 179 | (end-column :initarg :end-column)) | 190 | (length :initarg :length :reader xref-match-length)) |
| 180 | :comment "An xref item describes a reference to a location | 191 | :comment "A match xref item describes a search result.") |
| 181 | somewhere.") | ||
| 182 | |||
| 183 | (cl-defmethod xref-match-bounds ((i xref-match-item)) | ||
| 184 | (with-slots (end-column location) i | ||
| 185 | (cons (xref-file-location-column location) | ||
| 186 | end-column))) | ||
| 187 | 192 | ||
| 188 | (defun xref-make-match (summary end-column location) | 193 | (defun xref-make-match (summary location length) |
| 189 | "Create and return a new `xref-match-item'. | 194 | "Create and return a new `xref-match-item'. |
| 190 | SUMMARY is a short string to describe the xref. | 195 | SUMMARY is a short string to describe the xref. |
| 191 | END-COLUMN is the match end column number inside SUMMARY. | 196 | LOCATION is an `xref-location'. |
| 192 | LOCATION is an `xref-location'." | 197 | LENGTH is the match length, in characters." |
| 193 | (make-instance 'xref-match-item :summary summary :location location | 198 | (make-instance 'xref-match-item :summary summary |
| 194 | :end-column end-column)) | 199 | :location location :length length)) |
| 195 | 200 | ||
| 196 | 201 | ||
| 197 | ;;; API | 202 | ;;; API |
| 198 | 203 | ||
| 199 | (declare-function etags-xref-find "etags" (action id)) | 204 | ;; We make the etags backend the default for now, until something |
| 200 | (declare-function tags-lazy-completion-table "etags" ()) | 205 | ;; better comes along. |
| 206 | (defvar xref-backend-functions (list #'xref--etags-backend) | ||
| 207 | "Special hook to find the xref backend for the current context. | ||
| 208 | Each functions on this hook is called in turn with no arguments | ||
| 209 | and should return either nil to mean that it is not applicable, | ||
| 210 | or an xref backend, which is a value to be used to dispatch the | ||
| 211 | generic functions.") | ||
| 201 | 212 | ||
| 202 | ;; For now, make the etags backend the default. | 213 | (defun xref-find-backend () |
| 203 | (defvar xref-find-function #'etags-xref-find | 214 | (run-hook-with-args-until-success 'xref-backend-functions)) |
| 204 | "Function to look for cross-references. | ||
| 205 | It can be called in several ways: | ||
| 206 | 215 | ||
| 207 | (definitions IDENTIFIER): Find definitions of IDENTIFIER. The | 216 | (defun xref--etags-backend () 'etags) |
| 208 | result must be a list of xref objects. If IDENTIFIER contains | ||
| 209 | sufficient information to determine a unique definition, returns | ||
| 210 | only that definition. If there are multiple possible definitions, | ||
| 211 | return all of them. If no definitions can be found, return nil. | ||
| 212 | 217 | ||
| 213 | (references IDENTIFIER): Find references of IDENTIFIER. The | 218 | (cl-defgeneric xref-backend-definitions (backend identifier) |
| 214 | result must be a list of xref objects. If no references can be | 219 | "Find definitions of IDENTIFIER. |
| 215 | found, return nil. | ||
| 216 | 220 | ||
| 217 | (apropos PATTERN): Find all symbols that match PATTERN. PATTERN | 221 | The result must be a list of xref objects. If IDENTIFIER |
| 218 | is a regexp. | 222 | contains sufficient information to determine a unique definition, |
| 223 | return only that definition. If there are multiple possible | ||
| 224 | definitions, return all of them. If no definitions can be found, | ||
| 225 | return nil. | ||
| 219 | 226 | ||
| 220 | IDENTIFIER can be any string returned by | 227 | IDENTIFIER can be any string returned by |
| 221 | `xref-identifier-at-point-function', or from the table returned | 228 | `xref-backend-identifier-at-point', or from the table returned by |
| 222 | by `xref-identifier-completion-table-function'. | 229 | `xref-backend-identifier-completion-table'. |
| 223 | 230 | ||
| 224 | To create an xref object, call `xref-make'.") | 231 | To create an xref object, call `xref-make'.") |
| 225 | 232 | ||
| 226 | (defvar xref-identifier-at-point-function #'xref-default-identifier-at-point | 233 | (cl-defgeneric xref-backend-references (backend identifier) |
| 227 | "Function to get the relevant identifier at point. | 234 | "Find references of IDENTIFIER. |
| 235 | The result must be a list of xref objects. If no references can | ||
| 236 | be found, return nil.") | ||
| 237 | |||
| 238 | (cl-defgeneric xref-backend-apropos (backend pattern) | ||
| 239 | "Find all symbols that match PATTERN. | ||
| 240 | PATTERN is a regexp") | ||
| 241 | |||
| 242 | (cl-defgeneric xref-backend-identifier-at-point (_backend) | ||
| 243 | "Return the relevant identifier at point. | ||
| 228 | 244 | ||
| 229 | The return value must be a string or nil. nil means no | 245 | The return value must be a string or nil. nil means no |
| 230 | identifier at point found. | 246 | identifier at point found. |
| @@ -232,16 +248,14 @@ identifier at point found. | |||
| 232 | If it's hard to determine the identifier precisely (e.g., because | 248 | If it's hard to determine the identifier precisely (e.g., because |
| 233 | it's a method call on unknown type), the implementation can | 249 | it's a method call on unknown type), the implementation can |
| 234 | return a simple string (such as symbol at point) marked with a | 250 | return a simple string (such as symbol at point) marked with a |
| 235 | special text property which `xref-find-function' would recognize | 251 | special text property which e.g. `xref-backend-definitions' would |
| 236 | and then delegate the work to an external process.") | 252 | recognize and then delegate the work to an external process." |
| 237 | |||
| 238 | (defvar xref-identifier-completion-table-function #'tags-lazy-completion-table | ||
| 239 | "Function that returns the completion table for identifiers.") | ||
| 240 | |||
| 241 | (defun xref-default-identifier-at-point () | ||
| 242 | (let ((thing (thing-at-point 'symbol))) | 253 | (let ((thing (thing-at-point 'symbol))) |
| 243 | (and thing (substring-no-properties thing)))) | 254 | (and thing (substring-no-properties thing)))) |
| 244 | 255 | ||
| 256 | (cl-defgeneric xref-backend-identifier-completion-table (backend) | ||
| 257 | "Returns the completion table for identifiers.") | ||
| 258 | |||
| 245 | 259 | ||
| 246 | ;;; misc utilities | 260 | ;;; misc utilities |
| 247 | (defun xref--alistify (list key test) | 261 | (defun xref--alistify (list key test) |
| @@ -345,22 +359,14 @@ elements is negated." | |||
| 345 | (pcase-let ((`(,beg . ,end) | 359 | (pcase-let ((`(,beg . ,end) |
| 346 | (save-excursion | 360 | (save-excursion |
| 347 | (or | 361 | (or |
| 348 | (xref--match-buffer-bounds xref--current-item) | 362 | (let ((length (xref-match-length xref--current-item))) |
| 363 | (and length (cons (point) (+ (point) length)))) | ||
| 349 | (back-to-indentation) | 364 | (back-to-indentation) |
| 350 | (if (eolp) | 365 | (if (eolp) |
| 351 | (cons (line-beginning-position) (1+ (point))) | 366 | (cons (line-beginning-position) (1+ (point))) |
| 352 | (cons (point) (line-end-position))))))) | 367 | (cons (point) (line-end-position))))))) |
| 353 | (pulse-momentary-highlight-region beg end 'next-error))) | 368 | (pulse-momentary-highlight-region beg end 'next-error))) |
| 354 | 369 | ||
| 355 | (defun xref--match-buffer-bounds (item) | ||
| 356 | (save-excursion | ||
| 357 | (let ((bounds (xref-match-bounds item))) | ||
| 358 | (when bounds | ||
| 359 | (cons (progn (move-to-column (car bounds)) | ||
| 360 | (point)) | ||
| 361 | (progn (move-to-column (cdr bounds)) | ||
| 362 | (point))))))) | ||
| 363 | |||
| 364 | ;; etags.el needs this | 370 | ;; etags.el needs this |
| 365 | (defun xref-clear-marker-stack () | 371 | (defun xref-clear-marker-stack () |
| 366 | "Discard all markers from the marker stack." | 372 | "Discard all markers from the marker stack." |
| @@ -487,50 +493,54 @@ WINDOW controls how the buffer is displayed: | |||
| 487 | (progn | 493 | (progn |
| 488 | (save-excursion | 494 | (save-excursion |
| 489 | (goto-char (point-min)) | 495 | (goto-char (point-min)) |
| 490 | ;; TODO: Check that none of the matches are out of date; | ||
| 491 | ;; offer to re-scan otherwise. Note that saving the last | ||
| 492 | ;; modification tick won't work, as long as not all of the | ||
| 493 | ;; buffers are kept open. | ||
| 494 | (while (setq item (xref--search-property 'xref-item)) | 496 | (while (setq item (xref--search-property 'xref-item)) |
| 495 | (when (xref-match-bounds item) | 497 | (when (xref-match-length item) |
| 496 | (save-excursion | 498 | (save-excursion |
| 497 | ;; FIXME: Get rid of xref--goto-location, by making | 499 | (let* ((loc (xref-item-location item)) |
| 498 | ;; xref-match-bounds return markers already. | 500 | (beg (xref-location-marker loc)) |
| 499 | (xref--goto-location (xref-item-location item)) | 501 | (len (xref-match-length item))) |
| 500 | (let ((bounds (xref--match-buffer-bounds item)) | 502 | ;; Perform sanity check first. |
| 501 | (beg (make-marker)) | 503 | (xref--goto-location loc) |
| 502 | (end (make-marker))) | 504 | ;; FIXME: The check should probably be a generic |
| 503 | (move-marker beg (car bounds)) | 505 | ;; function, instead of the assumption that all |
| 504 | (move-marker end (cdr bounds)) | 506 | ;; matches contain the full line as summary. |
| 505 | (push (cons beg end) pairs))))) | 507 | ;; TODO: Offer to re-scan otherwise. |
| 508 | (unless (equal (buffer-substring-no-properties | ||
| 509 | (line-beginning-position) | ||
| 510 | (line-end-position)) | ||
| 511 | (xref-item-summary item)) | ||
| 512 | (user-error "Search results out of date")) | ||
| 513 | (push (cons beg len) pairs))))) | ||
| 506 | (setq pairs (nreverse pairs))) | 514 | (setq pairs (nreverse pairs))) |
| 507 | (unless pairs (user-error "No suitable matches here")) | 515 | (unless pairs (user-error "No suitable matches here")) |
| 508 | (xref--query-replace-1 from to pairs)) | 516 | (xref--query-replace-1 from to pairs)) |
| 509 | (dolist (pair pairs) | 517 | (dolist (pair pairs) |
| 510 | (move-marker (car pair) nil) | 518 | (move-marker (car pair) nil))))) |
| 511 | (move-marker (cdr pair) nil))))) | ||
| 512 | 519 | ||
| 520 | ;; FIXME: Write a nicer UI. | ||
| 513 | (defun xref--query-replace-1 (from to pairs) | 521 | (defun xref--query-replace-1 (from to pairs) |
| 514 | (let* ((query-replace-lazy-highlight nil) | 522 | (let* ((query-replace-lazy-highlight nil) |
| 515 | current-pair current-buf | 523 | current-beg current-len current-buf |
| 516 | ;; Counteract the "do the next match now" hack in | 524 | ;; Counteract the "do the next match now" hack in |
| 517 | ;; `perform-replace'. And still, it'll report that those | 525 | ;; `perform-replace'. And still, it'll report that those |
| 518 | ;; matches were "filtered out" at the end. | 526 | ;; matches were "filtered out" at the end. |
| 519 | (isearch-filter-predicate | 527 | (isearch-filter-predicate |
| 520 | (lambda (beg end) | 528 | (lambda (beg end) |
| 521 | (and current-pair | 529 | (and current-beg |
| 522 | (eq (current-buffer) current-buf) | 530 | (eq (current-buffer) current-buf) |
| 523 | (>= beg (car current-pair)) | 531 | (>= beg current-beg) |
| 524 | (<= end (cdr current-pair))))) | 532 | (<= end (+ current-beg current-len))))) |
| 525 | (replace-re-search-function | 533 | (replace-re-search-function |
| 526 | (lambda (from &optional _bound noerror) | 534 | (lambda (from &optional _bound noerror) |
| 527 | (let (found) | 535 | (let (found pair) |
| 528 | (while (and (not found) pairs) | 536 | (while (and (not found) pairs) |
| 529 | (setq current-pair (pop pairs) | 537 | (setq pair (pop pairs) |
| 530 | current-buf (marker-buffer (car current-pair))) | 538 | current-beg (car pair) |
| 539 | current-len (cdr pair) | ||
| 540 | current-buf (marker-buffer current-beg)) | ||
| 531 | (pop-to-buffer current-buf) | 541 | (pop-to-buffer current-buf) |
| 532 | (goto-char (car current-pair)) | 542 | (goto-char current-beg) |
| 533 | (when (re-search-forward from (cdr current-pair) noerror) | 543 | (when (re-search-forward from (+ current-beg current-len) noerror) |
| 534 | (setq found t))) | 544 | (setq found t))) |
| 535 | found)))) | 545 | found)))) |
| 536 | ;; FIXME: Despite this being a multi-buffer replacement, `N' | 546 | ;; FIXME: Despite this being a multi-buffer replacement, `N' |
| @@ -695,7 +705,8 @@ Return an alist of the form ((FILENAME . (XREF ...)) ...)." | |||
| 695 | 705 | ||
| 696 | (defun xref--read-identifier (prompt) | 706 | (defun xref--read-identifier (prompt) |
| 697 | "Return the identifier at point or read it from the minibuffer." | 707 | "Return the identifier at point or read it from the minibuffer." |
| 698 | (let ((id (funcall xref-identifier-at-point-function))) | 708 | (let* ((backend (xref-find-backend)) |
| 709 | (id (xref-backend-identifier-at-point backend))) | ||
| 699 | (cond ((or current-prefix-arg | 710 | (cond ((or current-prefix-arg |
| 700 | (not id) | 711 | (not id) |
| 701 | (xref--prompt-p this-command)) | 712 | (xref--prompt-p this-command)) |
| @@ -705,7 +716,7 @@ Return an alist of the form ((FILENAME . (XREF ...)) ...)." | |||
| 705 | "[ :]+\\'" prompt)) | 716 | "[ :]+\\'" prompt)) |
| 706 | id) | 717 | id) |
| 707 | prompt) | 718 | prompt) |
| 708 | (funcall xref-identifier-completion-table-function) | 719 | (xref-backend-identifier-completion-table backend) |
| 709 | nil nil nil | 720 | nil nil nil |
| 710 | 'xref--read-identifier-history id)) | 721 | 'xref--read-identifier-history id)) |
| 711 | (t id)))) | 722 | (t id)))) |
| @@ -714,7 +725,9 @@ Return an alist of the form ((FILENAME . (XREF ...)) ...)." | |||
| 714 | ;;; Commands | 725 | ;;; Commands |
| 715 | 726 | ||
| 716 | (defun xref--find-xrefs (input kind arg window) | 727 | (defun xref--find-xrefs (input kind arg window) |
| 717 | (let ((xrefs (funcall xref-find-function kind arg))) | 728 | (let ((xrefs (funcall (intern (format "xref-backend-%s" kind)) |
| 729 | (xref-find-backend) | ||
| 730 | arg))) | ||
| 718 | (unless xrefs | 731 | (unless xrefs |
| 719 | (user-error "No %s found for: %s" (symbol-name kind) input)) | 732 | (user-error "No %s found for: %s" (symbol-name kind) input)) |
| 720 | (xref--show-xrefs xrefs window))) | 733 | (xref--show-xrefs xrefs window))) |
| @@ -799,14 +812,9 @@ and just use etags." | |||
| 799 | :lighter "" | 812 | :lighter "" |
| 800 | (if xref-etags-mode | 813 | (if xref-etags-mode |
| 801 | (progn | 814 | (progn |
| 802 | (setq xref-etags-mode--saved | 815 | (setq xref-etags-mode--saved xref-backend-functions) |
| 803 | (cons xref-find-function | 816 | (kill-local-variable 'xref-backend-functions)) |
| 804 | xref-identifier-completion-table-function)) | 817 | (setq-local xref-backend-functions xref-etags-mode--saved))) |
| 805 | (kill-local-variable 'xref-find-function) | ||
| 806 | (kill-local-variable 'xref-identifier-completion-table-function)) | ||
| 807 | (setq-local xref-find-function (car xref-etags-mode--saved)) | ||
| 808 | (setq-local xref-identifier-completion-table-function | ||
| 809 | (cdr xref-etags-mode--saved)))) | ||
| 810 | 818 | ||
| 811 | (declare-function semantic-symref-find-references-by-name "semantic/symref") | 819 | (declare-function semantic-symref-find-references-by-name "semantic/symref") |
| 812 | (declare-function semantic-find-file-noselect "semantic/fw") | 820 | (declare-function semantic-find-file-noselect "semantic/fw") |
| @@ -826,10 +834,11 @@ tools are used, and when." | |||
| 826 | (hits (and res (oref res hit-lines))) | 834 | (hits (and res (oref res hit-lines))) |
| 827 | (orig-buffers (buffer-list))) | 835 | (orig-buffers (buffer-list))) |
| 828 | (unwind-protect | 836 | (unwind-protect |
| 829 | (delq nil | 837 | (cl-mapcan (lambda (hit) (xref--collect-matches |
| 830 | (mapcar (lambda (hit) (xref--collect-match | 838 | hit (format "\\_<%s\\_>" (regexp-quote symbol)))) |
| 831 | hit (format "\\_<%s\\_>" (regexp-quote symbol)))) | 839 | hits) |
| 832 | hits)) | 840 | ;; TODO: Implement "lightweight" buffer visiting, so that we |
| 841 | ;; don't have to kill them. | ||
| 833 | (mapc #'kill-buffer | 842 | (mapc #'kill-buffer |
| 834 | (cl-set-difference (buffer-list) orig-buffers))))) | 843 | (cl-set-difference (buffer-list) orig-buffers))))) |
| 835 | 844 | ||
| @@ -860,9 +869,9 @@ IGNORES is a list of glob patterns." | |||
| 860 | (match-string 1)) | 869 | (match-string 1)) |
| 861 | hits))) | 870 | hits))) |
| 862 | (unwind-protect | 871 | (unwind-protect |
| 863 | (delq nil | 872 | (cl-mapcan (lambda (hit) (xref--collect-matches hit regexp)) |
| 864 | (mapcar (lambda (hit) (xref--collect-match hit regexp)) | 873 | (nreverse hits)) |
| 865 | (nreverse hits))) | 874 | ;; TODO: Same as above. |
| 866 | (mapc #'kill-buffer | 875 | (mapc #'kill-buffer |
| 867 | (cl-set-difference (buffer-list) orig-buffers))))) | 876 | (cl-set-difference (buffer-list) orig-buffers))))) |
| 868 | 877 | ||
| @@ -918,7 +927,7 @@ IGNORES is a list of glob patterns." | |||
| 918 | (match-string 1 str))))) | 927 | (match-string 1 str))))) |
| 919 | str t t)) | 928 | str t t)) |
| 920 | 929 | ||
| 921 | (defun xref--collect-match (hit regexp) | 930 | (defun xref--collect-matches (hit regexp) |
| 922 | (pcase-let* ((`(,line . ,file) hit) | 931 | (pcase-let* ((`(,line . ,file) hit) |
| 923 | (buf (or (find-buffer-visiting file) | 932 | (buf (or (find-buffer-visiting file) |
| 924 | (semantic-find-file-noselect file)))) | 933 | (semantic-find-file-noselect file)))) |
| @@ -926,18 +935,22 @@ IGNORES is a list of glob patterns." | |||
| 926 | (save-excursion | 935 | (save-excursion |
| 927 | (goto-char (point-min)) | 936 | (goto-char (point-min)) |
| 928 | (forward-line (1- line)) | 937 | (forward-line (1- line)) |
| 929 | (syntax-propertize (line-end-position)) | 938 | (let ((line-end (line-end-position)) |
| 930 | ;; TODO: Handle multiple matches per line. | 939 | (line-beg (line-beginning-position)) |
| 931 | (when (re-search-forward regexp (line-end-position) t) | 940 | matches) |
| 932 | (goto-char (match-beginning 0)) | 941 | (syntax-propertize line-end) |
| 933 | (let ((loc (xref-make-file-location file line | 942 | ;; FIXME: This results in several lines with the same |
| 934 | (current-column)))) | 943 | ;; summary. Solve with composite pattern? |
| 935 | (goto-char (match-end 0)) | 944 | (while (re-search-forward regexp line-end t) |
| 936 | (xref-make-match (buffer-substring | 945 | (let* ((beg-column (- (match-beginning 0) line-beg)) |
| 937 | (line-beginning-position) | 946 | (end-column (- (match-end 0) line-beg)) |
| 938 | (line-end-position)) | 947 | (loc (xref-make-file-location file line beg-column)) |
| 939 | (current-column) | 948 | (summary (buffer-substring line-beg line-end))) |
| 940 | loc))))))) | 949 | (add-face-text-property beg-column end-column 'highlight |
| 950 | t summary) | ||
| 951 | (push (xref-make-match summary loc (- end-column beg-column)) | ||
| 952 | matches))) | ||
| 953 | (nreverse matches)))))) | ||
| 941 | 954 | ||
| 942 | (provide 'xref) | 955 | (provide 'xref) |
| 943 | 956 | ||
diff --git a/lisp/rect.el b/lisp/rect.el index acd3a48f2da..46ebbf259cf 100644 --- a/lisp/rect.el +++ b/lisp/rect.el | |||
| @@ -257,6 +257,19 @@ Return it as a list of strings, one for each line of the rectangle." | |||
| 257 | (apply-on-rectangle 'extract-rectangle-line start end lines) | 257 | (apply-on-rectangle 'extract-rectangle-line start end lines) |
| 258 | (nreverse (cdr lines)))) | 258 | (nreverse (cdr lines)))) |
| 259 | 259 | ||
| 260 | (defun extract-rectangle-bounds (start end) | ||
| 261 | "Return the bounds of the rectangle with corners at START and END. | ||
| 262 | Return it as a list of (START . END) positions, one for each line of | ||
| 263 | the rectangle." | ||
| 264 | (let (bounds) | ||
| 265 | (apply-on-rectangle | ||
| 266 | (lambda (startcol endcol) | ||
| 267 | (move-to-column startcol) | ||
| 268 | (push (cons (prog1 (point) (move-to-column endcol)) (point)) | ||
| 269 | bounds)) | ||
| 270 | start end) | ||
| 271 | (nreverse bounds))) | ||
| 272 | |||
| 260 | (defvar killed-rectangle nil | 273 | (defvar killed-rectangle nil |
| 261 | "Rectangle for `yank-rectangle' to insert.") | 274 | "Rectangle for `yank-rectangle' to insert.") |
| 262 | 275 | ||
| @@ -563,6 +576,8 @@ with a prefix argument, prompt for START-AT and FORMAT." | |||
| 563 | #'rectangle--unhighlight-for-redisplay) | 576 | #'rectangle--unhighlight-for-redisplay) |
| 564 | (add-function :around region-extract-function | 577 | (add-function :around region-extract-function |
| 565 | #'rectangle--extract-region) | 578 | #'rectangle--extract-region) |
| 579 | (add-function :around region-insert-function | ||
| 580 | #'rectangle--insert-region) | ||
| 566 | 581 | ||
| 567 | (defvar rectangle-mark-mode-map | 582 | (defvar rectangle-mark-mode-map |
| 568 | (let ((map (make-sparse-keymap))) | 583 | (let ((map (make-sparse-keymap))) |
| @@ -681,8 +696,12 @@ Ignores `line-move-visual'." | |||
| 681 | 696 | ||
| 682 | 697 | ||
| 683 | (defun rectangle--extract-region (orig &optional delete) | 698 | (defun rectangle--extract-region (orig &optional delete) |
| 684 | (if (not rectangle-mark-mode) | 699 | (cond |
| 685 | (funcall orig delete) | 700 | ((not rectangle-mark-mode) |
| 701 | (funcall orig delete)) | ||
| 702 | ((eq delete 'bounds) | ||
| 703 | (extract-rectangle-bounds (region-beginning) (region-end))) | ||
| 704 | (t | ||
| 686 | (let* ((strs (funcall (if delete | 705 | (let* ((strs (funcall (if delete |
| 687 | #'delete-extract-rectangle | 706 | #'delete-extract-rectangle |
| 688 | #'extract-rectangle) | 707 | #'extract-rectangle) |
| @@ -696,7 +715,14 @@ Ignores `line-move-visual'." | |||
| 696 | (put-text-property 0 (length str) 'yank-handler | 715 | (put-text-property 0 (length str) 'yank-handler |
| 697 | `(rectangle--insert-for-yank ,strs t) | 716 | `(rectangle--insert-for-yank ,strs t) |
| 698 | str) | 717 | str) |
| 699 | str)))) | 718 | str))))) |
| 719 | |||
| 720 | (defun rectangle--insert-region (orig strings) | ||
| 721 | (cond | ||
| 722 | ((not rectangle-mark-mode) | ||
| 723 | (funcall orig strings)) | ||
| 724 | (t | ||
| 725 | (funcall #'insert-rectangle strings)))) | ||
| 700 | 726 | ||
| 701 | (defun rectangle--insert-for-yank (strs) | 727 | (defun rectangle--insert-for-yank (strs) |
| 702 | (push (point) buffer-undo-list) | 728 | (push (point) buffer-undo-list) |
diff --git a/lisp/replace.el b/lisp/replace.el index d6590c5516a..b6802aeaf57 100644 --- a/lisp/replace.el +++ b/lisp/replace.el | |||
| @@ -284,7 +284,7 @@ the original string if not." | |||
| 284 | (and current-prefix-arg (not (eq current-prefix-arg '-))) | 284 | (and current-prefix-arg (not (eq current-prefix-arg '-))) |
| 285 | (and current-prefix-arg (eq current-prefix-arg '-))))) | 285 | (and current-prefix-arg (eq current-prefix-arg '-))))) |
| 286 | 286 | ||
| 287 | (defun query-replace (from-string to-string &optional delimited start end backward) | 287 | (defun query-replace (from-string to-string &optional delimited start end backward region-noncontiguous-p) |
| 288 | "Replace some occurrences of FROM-STRING with TO-STRING. | 288 | "Replace some occurrences of FROM-STRING with TO-STRING. |
| 289 | As each match is found, the user must type a character saying | 289 | As each match is found, the user must type a character saying |
| 290 | what to do with it. For directions, type \\[help-command] at that time. | 290 | what to do with it. For directions, type \\[help-command] at that time. |
| @@ -328,22 +328,21 @@ To customize possible responses, change the bindings in `query-replace-map'." | |||
| 328 | (if current-prefix-arg | 328 | (if current-prefix-arg |
| 329 | (if (eq current-prefix-arg '-) " backward" " word") | 329 | (if (eq current-prefix-arg '-) " backward" " word") |
| 330 | "") | 330 | "") |
| 331 | (if (and transient-mark-mode mark-active) " in region" "")) | 331 | (if (use-region-p) " in region" "")) |
| 332 | nil))) | 332 | nil))) |
| 333 | (list (nth 0 common) (nth 1 common) (nth 2 common) | 333 | (list (nth 0 common) (nth 1 common) (nth 2 common) |
| 334 | ;; These are done separately here | 334 | ;; These are done separately here |
| 335 | ;; so that command-history will record these expressions | 335 | ;; so that command-history will record these expressions |
| 336 | ;; rather than the values they had this time. | 336 | ;; rather than the values they had this time. |
| 337 | (if (and transient-mark-mode mark-active) | 337 | (if (use-region-p) (region-beginning)) |
| 338 | (region-beginning)) | 338 | (if (use-region-p) (region-end)) |
| 339 | (if (and transient-mark-mode mark-active) | 339 | (nth 3 common) |
| 340 | (region-end)) | 340 | (if (use-region-p) (region-noncontiguous-p))))) |
| 341 | (nth 3 common)))) | 341 | (perform-replace from-string to-string t nil delimited nil nil start end backward region-noncontiguous-p)) |
| 342 | (perform-replace from-string to-string t nil delimited nil nil start end backward)) | ||
| 343 | 342 | ||
| 344 | (define-key esc-map "%" 'query-replace) | 343 | (define-key esc-map "%" 'query-replace) |
| 345 | 344 | ||
| 346 | (defun query-replace-regexp (regexp to-string &optional delimited start end backward) | 345 | (defun query-replace-regexp (regexp to-string &optional delimited start end backward region-noncontiguous-p) |
| 347 | "Replace some things after point matching REGEXP with TO-STRING. | 346 | "Replace some things after point matching REGEXP with TO-STRING. |
| 348 | As each match is found, the user must type a character saying | 347 | As each match is found, the user must type a character saying |
| 349 | what to do with it. For directions, type \\[help-command] at that time. | 348 | what to do with it. For directions, type \\[help-command] at that time. |
| @@ -408,18 +407,17 @@ Use \\[repeat-complex-command] after this command for details." | |||
| 408 | (if (eq current-prefix-arg '-) " backward" " word") | 407 | (if (eq current-prefix-arg '-) " backward" " word") |
| 409 | "") | 408 | "") |
| 410 | " regexp" | 409 | " regexp" |
| 411 | (if (and transient-mark-mode mark-active) " in region" "")) | 410 | (if (use-region-p) " in region" "")) |
| 412 | t))) | 411 | t))) |
| 413 | (list (nth 0 common) (nth 1 common) (nth 2 common) | 412 | (list (nth 0 common) (nth 1 common) (nth 2 common) |
| 414 | ;; These are done separately here | 413 | ;; These are done separately here |
| 415 | ;; so that command-history will record these expressions | 414 | ;; so that command-history will record these expressions |
| 416 | ;; rather than the values they had this time. | 415 | ;; rather than the values they had this time. |
| 417 | (if (and transient-mark-mode mark-active) | 416 | (if (use-region-p) (region-beginning)) |
| 418 | (region-beginning)) | 417 | (if (use-region-p) (region-end)) |
| 419 | (if (and transient-mark-mode mark-active) | 418 | (nth 3 common) |
| 420 | (region-end)) | 419 | (if (use-region-p) (region-noncontiguous-p))))) |
| 421 | (nth 3 common)))) | 420 | (perform-replace regexp to-string t t delimited nil nil start end backward region-noncontiguous-p)) |
| 422 | (perform-replace regexp to-string t t delimited nil nil start end backward)) | ||
| 423 | 421 | ||
| 424 | (define-key esc-map [?\C-%] 'query-replace-regexp) | 422 | (define-key esc-map [?\C-%] 'query-replace-regexp) |
| 425 | 423 | ||
| @@ -485,10 +483,8 @@ for Lisp calls." "22.1")) | |||
| 485 | ;; and the user might enter a single token. | 483 | ;; and the user might enter a single token. |
| 486 | (replace-match-string-symbols to) | 484 | (replace-match-string-symbols to) |
| 487 | (list from (car to) current-prefix-arg | 485 | (list from (car to) current-prefix-arg |
| 488 | (if (and transient-mark-mode mark-active) | 486 | (if (use-region-p) (region-beginning)) |
| 489 | (region-beginning)) | 487 | (if (use-region-p) (region-end)))))) |
| 490 | (if (and transient-mark-mode mark-active) | ||
| 491 | (region-end)))))) | ||
| 492 | (perform-replace regexp (cons 'replace-eval-replacement to-expr) | 488 | (perform-replace regexp (cons 'replace-eval-replacement to-expr) |
| 493 | t 'literal delimited nil nil start end)) | 489 | t 'literal delimited nil nil start end)) |
| 494 | 490 | ||
| @@ -523,10 +519,8 @@ Fourth and fifth arg START and END specify the region to operate on." | |||
| 523 | (list from to | 519 | (list from to |
| 524 | (and current-prefix-arg | 520 | (and current-prefix-arg |
| 525 | (prefix-numeric-value current-prefix-arg)) | 521 | (prefix-numeric-value current-prefix-arg)) |
| 526 | (if (and transient-mark-mode mark-active) | 522 | (if (use-region-p) (region-beginning)) |
| 527 | (region-beginning)) | 523 | (if (use-region-p) (region-end))))) |
| 528 | (if (and transient-mark-mode mark-active) | ||
| 529 | (region-end))))) | ||
| 530 | (let (replacements) | 524 | (let (replacements) |
| 531 | (if (listp to-strings) | 525 | (if (listp to-strings) |
| 532 | (setq replacements to-strings) | 526 | (setq replacements to-strings) |
| @@ -587,13 +581,11 @@ and TO-STRING is also null.)" | |||
| 587 | (if (eq current-prefix-arg '-) " backward" " word") | 581 | (if (eq current-prefix-arg '-) " backward" " word") |
| 588 | "") | 582 | "") |
| 589 | " string" | 583 | " string" |
| 590 | (if (and transient-mark-mode mark-active) " in region" "")) | 584 | (if (use-region-p) " in region" "")) |
| 591 | nil))) | 585 | nil))) |
| 592 | (list (nth 0 common) (nth 1 common) (nth 2 common) | 586 | (list (nth 0 common) (nth 1 common) (nth 2 common) |
| 593 | (if (and transient-mark-mode mark-active) | 587 | (if (use-region-p) (region-beginning)) |
| 594 | (region-beginning)) | 588 | (if (use-region-p) (region-end)) |
| 595 | (if (and transient-mark-mode mark-active) | ||
| 596 | (region-end)) | ||
| 597 | (nth 3 common)))) | 589 | (nth 3 common)))) |
| 598 | (perform-replace from-string to-string nil nil delimited nil nil start end backward)) | 590 | (perform-replace from-string to-string nil nil delimited nil nil start end backward)) |
| 599 | 591 | ||
| @@ -661,13 +653,11 @@ which will run faster and will not set the mark or print anything." | |||
| 661 | (if (eq current-prefix-arg '-) " backward" " word") | 653 | (if (eq current-prefix-arg '-) " backward" " word") |
| 662 | "") | 654 | "") |
| 663 | " regexp" | 655 | " regexp" |
| 664 | (if (and transient-mark-mode mark-active) " in region" "")) | 656 | (if (use-region-p) " in region" "")) |
| 665 | t))) | 657 | t))) |
| 666 | (list (nth 0 common) (nth 1 common) (nth 2 common) | 658 | (list (nth 0 common) (nth 1 common) (nth 2 common) |
| 667 | (if (and transient-mark-mode mark-active) | 659 | (if (use-region-p) (region-beginning)) |
| 668 | (region-beginning)) | 660 | (if (use-region-p) (region-end)) |
| 669 | (if (and transient-mark-mode mark-active) | ||
| 670 | (region-end)) | ||
| 671 | (nth 3 common)))) | 661 | (nth 3 common)))) |
| 672 | (perform-replace regexp to-string nil t delimited nil nil start end backward)) | 662 | (perform-replace regexp to-string nil t delimited nil nil start end backward)) |
| 673 | 663 | ||
| @@ -832,7 +822,7 @@ a previously found match." | |||
| 832 | (unless (or (bolp) (eobp)) | 822 | (unless (or (bolp) (eobp)) |
| 833 | (forward-line 0)) | 823 | (forward-line 0)) |
| 834 | (point-marker))))) | 824 | (point-marker))))) |
| 835 | (if (and interactive transient-mark-mode mark-active) | 825 | (if (and interactive (use-region-p)) |
| 836 | (setq rstart (region-beginning) | 826 | (setq rstart (region-beginning) |
| 837 | rend (progn | 827 | rend (progn |
| 838 | (goto-char (region-end)) | 828 | (goto-char (region-end)) |
| @@ -901,7 +891,7 @@ starting on the same line at which another match ended is ignored." | |||
| 901 | (progn | 891 | (progn |
| 902 | (goto-char (min rstart rend)) | 892 | (goto-char (min rstart rend)) |
| 903 | (setq rend (copy-marker (max rstart rend)))) | 893 | (setq rend (copy-marker (max rstart rend)))) |
| 904 | (if (and interactive transient-mark-mode mark-active) | 894 | (if (and interactive (use-region-p)) |
| 905 | (setq rstart (region-beginning) | 895 | (setq rstart (region-beginning) |
| 906 | rend (copy-marker (region-end))) | 896 | rend (copy-marker (region-end))) |
| 907 | (setq rstart (point) | 897 | (setq rstart (point) |
| @@ -951,7 +941,7 @@ a previously found match." | |||
| 951 | (setq rend (max rstart rend))) | 941 | (setq rend (max rstart rend))) |
| 952 | (goto-char rstart) | 942 | (goto-char rstart) |
| 953 | (setq rend (point-max))) | 943 | (setq rend (point-max))) |
| 954 | (if (and interactive transient-mark-mode mark-active) | 944 | (if (and interactive (use-region-p)) |
| 955 | (setq rstart (region-beginning) | 945 | (setq rstart (region-beginning) |
| 956 | rend (region-end)) | 946 | rend (region-end)) |
| 957 | (setq rstart (point) | 947 | (setq rstart (point) |
| @@ -2068,7 +2058,7 @@ It is called with three arguments, as if it were | |||
| 2068 | 2058 | ||
| 2069 | (defun perform-replace (from-string replacements | 2059 | (defun perform-replace (from-string replacements |
| 2070 | query-flag regexp-flag delimited-flag | 2060 | query-flag regexp-flag delimited-flag |
| 2071 | &optional repeat-count map start end backward) | 2061 | &optional repeat-count map start end backward region-noncontiguous-p) |
| 2072 | "Subroutine of `query-replace'. Its complexity handles interactive queries. | 2062 | "Subroutine of `query-replace'. Its complexity handles interactive queries. |
| 2073 | Don't use this in your own program unless you want to query and set the mark | 2063 | Don't use this in your own program unless you want to query and set the mark |
| 2074 | just as `query-replace' does. Instead, write a simple loop like this: | 2064 | just as `query-replace' does. Instead, write a simple loop like this: |
| @@ -2115,6 +2105,9 @@ It must return a string." | |||
| 2115 | 2105 | ||
| 2116 | ;; If non-nil, it is marker saying where in the buffer to stop. | 2106 | ;; If non-nil, it is marker saying where in the buffer to stop. |
| 2117 | (limit nil) | 2107 | (limit nil) |
| 2108 | ;; Use local binding in add-function below. | ||
| 2109 | (isearch-filter-predicate isearch-filter-predicate) | ||
| 2110 | (region-bounds nil) | ||
| 2118 | 2111 | ||
| 2119 | ;; Data for the next match. If a cons, it has the same format as | 2112 | ;; Data for the next match. If a cons, it has the same format as |
| 2120 | ;; (match-data); otherwise it is t if a match is possible at point. | 2113 | ;; (match-data); otherwise it is t if a match is possible at point. |
| @@ -2127,6 +2120,24 @@ It must return a string." | |||
| 2127 | "Query replacing %s with %s: (\\<query-replace-map>\\[help] for help) ") | 2120 | "Query replacing %s with %s: (\\<query-replace-map>\\[help] for help) ") |
| 2128 | minibuffer-prompt-properties)))) | 2121 | minibuffer-prompt-properties)))) |
| 2129 | 2122 | ||
| 2123 | ;; Unless a single contiguous chunk is selected, operate on multiple chunks. | ||
| 2124 | (when region-noncontiguous-p | ||
| 2125 | (setq region-bounds | ||
| 2126 | (mapcar (lambda (position) | ||
| 2127 | (cons (copy-marker (car position)) | ||
| 2128 | (copy-marker (cdr position)))) | ||
| 2129 | (funcall region-extract-function 'bounds))) | ||
| 2130 | (add-function :after-while isearch-filter-predicate | ||
| 2131 | (lambda (start end) | ||
| 2132 | (delq nil (mapcar | ||
| 2133 | (lambda (bounds) | ||
| 2134 | (and | ||
| 2135 | (>= start (car bounds)) | ||
| 2136 | (<= start (cdr bounds)) | ||
| 2137 | (>= end (car bounds)) | ||
| 2138 | (<= end (cdr bounds)))) | ||
| 2139 | region-bounds))))) | ||
| 2140 | |||
| 2130 | ;; If region is active, in Transient Mark mode, operate on region. | 2141 | ;; If region is active, in Transient Mark mode, operate on region. |
| 2131 | (if backward | 2142 | (if backward |
| 2132 | (when end | 2143 | (when end |
diff --git a/lisp/simple.el b/lisp/simple.el index b115a2a0cbb..deb5c888c92 100644 --- a/lisp/simple.el +++ b/lisp/simple.el | |||
| @@ -970,15 +970,34 @@ instead of deleted." | |||
| 970 | (defvar region-extract-function | 970 | (defvar region-extract-function |
| 971 | (lambda (delete) | 971 | (lambda (delete) |
| 972 | (when (region-beginning) | 972 | (when (region-beginning) |
| 973 | (if (eq delete 'delete-only) | 973 | (cond |
| 974 | (delete-region (region-beginning) (region-end)) | 974 | ((eq delete 'bounds) |
| 975 | (filter-buffer-substring (region-beginning) (region-end) delete)))) | 975 | (list (cons (region-beginning) (region-end)))) |
| 976 | ((eq delete 'delete-only) | ||
| 977 | (delete-region (region-beginning) (region-end))) | ||
| 978 | (t | ||
| 979 | (filter-buffer-substring (region-beginning) (region-end) delete))))) | ||
| 976 | "Function to get the region's content. | 980 | "Function to get the region's content. |
| 977 | Called with one argument DELETE. | 981 | Called with one argument DELETE. |
| 978 | If DELETE is `delete-only', then only delete the region and the return value | 982 | If DELETE is `delete-only', then only delete the region and the return value |
| 979 | is undefined. If DELETE is nil, just return the content as a string. | 983 | is undefined. If DELETE is nil, just return the content as a string. |
| 984 | If DELETE is `bounds', then don't delete, but just return the | ||
| 985 | boundaries of the region as a list of (START . END) positions. | ||
| 980 | If anything else, delete the region and return its content as a string.") | 986 | If anything else, delete the region and return its content as a string.") |
| 981 | 987 | ||
| 988 | (defvar region-insert-function | ||
| 989 | (lambda (lines) | ||
| 990 | (let ((first t)) | ||
| 991 | (while lines | ||
| 992 | (or first | ||
| 993 | (insert ?\n)) | ||
| 994 | (insert-for-yank (car lines)) | ||
| 995 | (setq lines (cdr lines) | ||
| 996 | first nil)))) | ||
| 997 | "Function to insert the region's content. | ||
| 998 | Called with one argument LINES. | ||
| 999 | Insert the region as a list of lines.") | ||
| 1000 | |||
| 982 | (defun delete-backward-char (n &optional killflag) | 1001 | (defun delete-backward-char (n &optional killflag) |
| 983 | "Delete the previous N characters (following if N is negative). | 1002 | "Delete the previous N characters (following if N is negative). |
| 984 | If Transient Mark mode is enabled, the mark is active, and N is 1, | 1003 | If Transient Mark mode is enabled, the mark is active, and N is 1, |
| @@ -3419,7 +3438,8 @@ and only used if a buffer is displayed." | |||
| 3419 | 3438 | ||
| 3420 | (defun shell-command-on-region (start end command | 3439 | (defun shell-command-on-region (start end command |
| 3421 | &optional output-buffer replace | 3440 | &optional output-buffer replace |
| 3422 | error-buffer display-error-buffer) | 3441 | error-buffer display-error-buffer |
| 3442 | region-noncontiguous-p) | ||
| 3423 | "Execute string COMMAND in inferior shell with region as input. | 3443 | "Execute string COMMAND in inferior shell with region as input. |
| 3424 | Normally display output (if any) in temp buffer `*Shell Command Output*'; | 3444 | Normally display output (if any) in temp buffer `*Shell Command Output*'; |
| 3425 | Prefix arg means replace the region with it. Return the exit code of | 3445 | Prefix arg means replace the region with it. Return the exit code of |
| @@ -3482,7 +3502,8 @@ interactively, this is t." | |||
| 3482 | current-prefix-arg | 3502 | current-prefix-arg |
| 3483 | current-prefix-arg | 3503 | current-prefix-arg |
| 3484 | shell-command-default-error-buffer | 3504 | shell-command-default-error-buffer |
| 3485 | t))) | 3505 | t |
| 3506 | (region-noncontiguous-p)))) | ||
| 3486 | (let ((error-file | 3507 | (let ((error-file |
| 3487 | (if error-buffer | 3508 | (if error-buffer |
| 3488 | (make-temp-file | 3509 | (make-temp-file |
| @@ -3491,96 +3512,109 @@ interactively, this is t." | |||
| 3491 | temporary-file-directory))) | 3512 | temporary-file-directory))) |
| 3492 | nil)) | 3513 | nil)) |
| 3493 | exit-status) | 3514 | exit-status) |
| 3494 | (if (or replace | 3515 | ;; Unless a single contiguous chunk is selected, operate on multiple chunks. |
| 3495 | (and output-buffer | 3516 | (if region-noncontiguous-p |
| 3496 | (not (or (bufferp output-buffer) (stringp output-buffer))))) | 3517 | (let ((input (concat (funcall region-extract-function 'delete) "\n")) |
| 3497 | ;; Replace specified region with output from command. | 3518 | output) |
| 3498 | (let ((swap (and replace (< start end)))) | 3519 | (with-temp-buffer |
| 3499 | ;; Don't muck with mark unless REPLACE says we should. | 3520 | (insert input) |
| 3500 | (goto-char start) | 3521 | (call-process-region (point-min) (point-max) |
| 3501 | (and replace (push-mark (point) 'nomsg)) | 3522 | shell-file-name t t |
| 3502 | (setq exit-status | 3523 | nil shell-command-switch |
| 3503 | (call-process-region start end shell-file-name replace | 3524 | command) |
| 3504 | (if error-file | 3525 | (setq output (split-string (buffer-string) "\n"))) |
| 3505 | (list t error-file) | 3526 | (goto-char start) |
| 3506 | t) | 3527 | (funcall region-insert-function output)) |
| 3507 | nil shell-command-switch command)) | 3528 | (if (or replace |
| 3508 | ;; It is rude to delete a buffer which the command is not using. | 3529 | (and output-buffer |
| 3509 | ;; (let ((shell-buffer (get-buffer "*Shell Command Output*"))) | 3530 | (not (or (bufferp output-buffer) (stringp output-buffer))))) |
| 3510 | ;; (and shell-buffer (not (eq shell-buffer (current-buffer))) | 3531 | ;; Replace specified region with output from command. |
| 3511 | ;; (kill-buffer shell-buffer))) | 3532 | (let ((swap (and replace (< start end)))) |
| 3512 | ;; Don't muck with mark unless REPLACE says we should. | 3533 | ;; Don't muck with mark unless REPLACE says we should. |
| 3513 | (and replace swap (exchange-point-and-mark))) | 3534 | (goto-char start) |
| 3514 | ;; No prefix argument: put the output in a temp buffer, | 3535 | (and replace (push-mark (point) 'nomsg)) |
| 3515 | ;; replacing its entire contents. | 3536 | (setq exit-status |
| 3516 | (let ((buffer (get-buffer-create | 3537 | (call-process-region start end shell-file-name replace |
| 3517 | (or output-buffer "*Shell Command Output*")))) | 3538 | (if error-file |
| 3518 | (unwind-protect | 3539 | (list t error-file) |
| 3519 | (if (eq buffer (current-buffer)) | 3540 | t) |
| 3520 | ;; If the input is the same buffer as the output, | 3541 | nil shell-command-switch command)) |
| 3521 | ;; delete everything but the specified region, | 3542 | ;; It is rude to delete a buffer which the command is not using. |
| 3522 | ;; then replace that region with the output. | 3543 | ;; (let ((shell-buffer (get-buffer "*Shell Command Output*"))) |
| 3523 | (progn (setq buffer-read-only nil) | 3544 | ;; (and shell-buffer (not (eq shell-buffer (current-buffer))) |
| 3524 | (delete-region (max start end) (point-max)) | 3545 | ;; (kill-buffer shell-buffer))) |
| 3525 | (delete-region (point-min) (min start end)) | 3546 | ;; Don't muck with mark unless REPLACE says we should. |
| 3526 | (setq exit-status | 3547 | (and replace swap (exchange-point-and-mark))) |
| 3527 | (call-process-region (point-min) (point-max) | 3548 | ;; No prefix argument: put the output in a temp buffer, |
| 3528 | shell-file-name t | 3549 | ;; replacing its entire contents. |
| 3529 | (if error-file | 3550 | (let ((buffer (get-buffer-create |
| 3530 | (list t error-file) | 3551 | (or output-buffer "*Shell Command Output*")))) |
| 3531 | t) | 3552 | (unwind-protect |
| 3532 | nil shell-command-switch | 3553 | (if (eq buffer (current-buffer)) |
| 3533 | command))) | 3554 | ;; If the input is the same buffer as the output, |
| 3534 | ;; Clear the output buffer, then run the command with | 3555 | ;; delete everything but the specified region, |
| 3535 | ;; output there. | 3556 | ;; then replace that region with the output. |
| 3536 | (let ((directory default-directory)) | 3557 | (progn (setq buffer-read-only nil) |
| 3537 | (with-current-buffer buffer | 3558 | (delete-region (max start end) (point-max)) |
| 3538 | (setq buffer-read-only nil) | 3559 | (delete-region (point-min) (min start end)) |
| 3539 | (if (not output-buffer) | 3560 | (setq exit-status |
| 3540 | (setq default-directory directory)) | 3561 | (call-process-region (point-min) (point-max) |
| 3541 | (erase-buffer))) | 3562 | shell-file-name t |
| 3542 | (setq exit-status | 3563 | (if error-file |
| 3543 | (call-process-region start end shell-file-name nil | 3564 | (list t error-file) |
| 3544 | (if error-file | 3565 | t) |
| 3545 | (list buffer error-file) | 3566 | nil shell-command-switch |
| 3546 | buffer) | 3567 | command))) |
| 3547 | nil shell-command-switch command))) | 3568 | ;; Clear the output buffer, then run the command with |
| 3548 | ;; Report the output. | 3569 | ;; output there. |
| 3549 | (with-current-buffer buffer | 3570 | (let ((directory default-directory)) |
| 3550 | (setq mode-line-process | 3571 | (with-current-buffer buffer |
| 3551 | (cond ((null exit-status) | 3572 | (setq buffer-read-only nil) |
| 3552 | " - Error") | 3573 | (if (not output-buffer) |
| 3553 | ((stringp exit-status) | 3574 | (setq default-directory directory)) |
| 3554 | (format " - Signal [%s]" exit-status)) | 3575 | (erase-buffer))) |
| 3555 | ((not (equal 0 exit-status)) | 3576 | (setq exit-status |
| 3556 | (format " - Exit [%d]" exit-status))))) | 3577 | (call-process-region start end shell-file-name nil |
| 3557 | (if (with-current-buffer buffer (> (point-max) (point-min))) | 3578 | (if error-file |
| 3558 | ;; There's some output, display it | 3579 | (list buffer error-file) |
| 3559 | (display-message-or-buffer buffer) | 3580 | buffer) |
| 3560 | ;; No output; error? | 3581 | nil shell-command-switch command))) |
| 3561 | (let ((output | 3582 | ;; Report the output. |
| 3562 | (if (and error-file | 3583 | (with-current-buffer buffer |
| 3563 | (< 0 (nth 7 (file-attributes error-file)))) | 3584 | (setq mode-line-process |
| 3564 | (format "some error output%s" | 3585 | (cond ((null exit-status) |
| 3565 | (if shell-command-default-error-buffer | 3586 | " - Error") |
| 3566 | (format " to the \"%s\" buffer" | 3587 | ((stringp exit-status) |
| 3567 | shell-command-default-error-buffer) | 3588 | (format " - Signal [%s]" exit-status)) |
| 3568 | "")) | 3589 | ((not (equal 0 exit-status)) |
| 3569 | "no output"))) | 3590 | (format " - Exit [%d]" exit-status))))) |
| 3570 | (cond ((null exit-status) | 3591 | (if (with-current-buffer buffer (> (point-max) (point-min))) |
| 3571 | (message "(Shell command failed with error)")) | 3592 | ;; There's some output, display it |
| 3572 | ((equal 0 exit-status) | 3593 | (display-message-or-buffer buffer) |
| 3573 | (message "(Shell command succeeded with %s)" | 3594 | ;; No output; error? |
| 3574 | output)) | 3595 | (let ((output |
| 3575 | ((stringp exit-status) | 3596 | (if (and error-file |
| 3576 | (message "(Shell command killed by signal %s)" | 3597 | (< 0 (nth 7 (file-attributes error-file)))) |
| 3577 | exit-status)) | 3598 | (format "some error output%s" |
| 3578 | (t | 3599 | (if shell-command-default-error-buffer |
| 3579 | (message "(Shell command failed with code %d and %s)" | 3600 | (format " to the \"%s\" buffer" |
| 3580 | exit-status output)))) | 3601 | shell-command-default-error-buffer) |
| 3581 | ;; Don't kill: there might be useful info in the undo-log. | 3602 | "")) |
| 3582 | ;; (kill-buffer buffer) | 3603 | "no output"))) |
| 3583 | )))) | 3604 | (cond ((null exit-status) |
| 3605 | (message "(Shell command failed with error)")) | ||
| 3606 | ((equal 0 exit-status) | ||
| 3607 | (message "(Shell command succeeded with %s)" | ||
| 3608 | output)) | ||
| 3609 | ((stringp exit-status) | ||
| 3610 | (message "(Shell command killed by signal %s)" | ||
| 3611 | exit-status)) | ||
| 3612 | (t | ||
| 3613 | (message "(Shell command failed with code %d and %s)" | ||
| 3614 | exit-status output)))) | ||
| 3615 | ;; Don't kill: there might be useful info in the undo-log. | ||
| 3616 | ;; (kill-buffer buffer) | ||
| 3617 | ))))) | ||
| 3584 | 3618 | ||
| 3585 | (when (and error-file (file-exists-p error-file)) | 3619 | (when (and error-file (file-exists-p error-file)) |
| 3586 | (if (< 0 (nth 7 (file-attributes error-file))) | 3620 | (if (< 0 (nth 7 (file-attributes error-file))) |
| @@ -5175,6 +5209,11 @@ also checks the value of `use-empty-active-region'." | |||
| 5175 | ;; region is active when there's no mark. | 5209 | ;; region is active when there's no mark. |
| 5176 | (progn (cl-assert (mark)) t))) | 5210 | (progn (cl-assert (mark)) t))) |
| 5177 | 5211 | ||
| 5212 | (defun region-noncontiguous-p () | ||
| 5213 | "Return non-nil if the region contains several pieces. | ||
| 5214 | An example is a rectangular region handled as a list of | ||
| 5215 | separate contiguous regions for each line." | ||
| 5216 | (> (length (funcall region-extract-function 'bounds)) 1)) | ||
| 5178 | 5217 | ||
| 5179 | (defvar redisplay-unhighlight-region-function | 5218 | (defvar redisplay-unhighlight-region-function |
| 5180 | (lambda (rol) (when (overlayp rol) (delete-overlay rol)))) | 5219 | (lambda (rol) (when (overlayp rol) (delete-overlay rol)))) |
diff --git a/lisp/vc/diff-mode.el b/lisp/vc/diff-mode.el index 464e3754eb9..f4d7fe7d9aa 100644 --- a/lisp/vc/diff-mode.el +++ b/lisp/vc/diff-mode.el | |||
| @@ -1821,7 +1821,7 @@ With a prefix argument, try to REVERSE the hunk." | |||
| 1821 | "Kill all hunks that have already been applied starting at point." | 1821 | "Kill all hunks that have already been applied starting at point." |
| 1822 | (interactive) | 1822 | (interactive) |
| 1823 | (while (not (eobp)) | 1823 | (while (not (eobp)) |
| 1824 | (pcase-let ((`(,buf ,line-offset ,pos ,src ,_dst ,switched) | 1824 | (pcase-let ((`(,_buf ,line-offset ,_pos ,_src ,_dst ,switched) |
| 1825 | (diff-find-source-location nil nil))) | 1825 | (diff-find-source-location nil nil))) |
| 1826 | (if (and line-offset switched) | 1826 | (if (and line-offset switched) |
| 1827 | (diff-hunk-kill) | 1827 | (diff-hunk-kill) |
diff --git a/src/casefiddle.c b/src/casefiddle.c index b94ea8e212e..6a2983ef018 100644 --- a/src/casefiddle.c +++ b/src/casefiddle.c | |||
| @@ -306,14 +306,30 @@ See also `capitalize-region'. */) | |||
| 306 | return Qnil; | 306 | return Qnil; |
| 307 | } | 307 | } |
| 308 | 308 | ||
| 309 | DEFUN ("downcase-region", Fdowncase_region, Sdowncase_region, 2, 2, "r", | 309 | DEFUN ("downcase-region", Fdowncase_region, Sdowncase_region, 2, 3, |
| 310 | "(list (region-beginning) (region-end) (region-noncontiguous-p))", | ||
| 310 | doc: /* Convert the region to lower case. In programs, wants two arguments. | 311 | doc: /* Convert the region to lower case. In programs, wants two arguments. |
| 311 | These arguments specify the starting and ending character numbers of | 312 | These arguments specify the starting and ending character numbers of |
| 312 | the region to operate on. When used as a command, the text between | 313 | the region to operate on. When used as a command, the text between |
| 313 | point and the mark is operated on. */) | 314 | point and the mark is operated on. */) |
| 314 | (Lisp_Object beg, Lisp_Object end) | 315 | (Lisp_Object beg, Lisp_Object end, Lisp_Object region_noncontiguous_p) |
| 315 | { | 316 | { |
| 316 | casify_region (CASE_DOWN, beg, end); | 317 | Lisp_Object bounds = Qnil; |
| 318 | |||
| 319 | if (!NILP (region_noncontiguous_p)) | ||
| 320 | { | ||
| 321 | bounds = call1 (Fsymbol_value (intern ("region-extract-function")), | ||
| 322 | intern ("bounds")); | ||
| 323 | |||
| 324 | while (CONSP (bounds)) | ||
| 325 | { | ||
| 326 | casify_region (CASE_DOWN, XCAR (XCAR (bounds)), XCDR (XCAR (bounds))); | ||
| 327 | bounds = XCDR (bounds); | ||
| 328 | } | ||
| 329 | } | ||
| 330 | else | ||
| 331 | casify_region (CASE_DOWN, beg, end); | ||
| 332 | |||
| 317 | return Qnil; | 333 | return Qnil; |
| 318 | } | 334 | } |
| 319 | 335 | ||