X-Git-Url: https://git.hcoop.net/bpt/emacs.git/blobdiff_plain/60e565234624f6c38920d233fafabd05c69eddfe..cd99601878e97578ecd8e2209feeda275a3a13f5:/lisp/replace.el diff --git a/lisp/replace.el b/lisp/replace.el index 0578ed09b1..4013e4e5df 100644 --- a/lisp/replace.el +++ b/lisp/replace.el @@ -1,6 +1,6 @@ ;;; replace.el --- replace commands for Emacs -;; Copyright (C) 1985-1987, 1992, 1994, 1996-1997, 2000-2011 +;; Copyright (C) 1985-1987, 1992, 1994, 1996-1997, 2000-2012 ;; Free Software Foundation, Inc. ;; Maintainer: FSF @@ -33,6 +33,22 @@ :type 'boolean :group 'matching) +(defcustom replace-lax-whitespace nil + "Non-nil means `query-replace' matches a sequence of whitespace chars. +When you enter a space or spaces in the strings to be replaced, +it will match any sequence matched by the regexp `search-whitespace-regexp'." + :type 'boolean + :group 'matching + :version "24.3") + +(defcustom replace-regexp-lax-whitespace nil + "Non-nil means `query-replace-regexp' matches a sequence of whitespace chars. +When you enter a space or spaces in the regexps to be replaced, +it will match any sequence matched by the regexp `search-whitespace-regexp'." + :type 'boolean + :group 'matching + :version "24.3") + (defvar query-replace-history nil "Default history list for query-replace commands. See `query-replace-from-history-variable' and @@ -46,6 +62,10 @@ no default value.") (defvar query-replace-interactive nil "Non-nil means `query-replace' uses the last search string. That becomes the \"string to replace\".") +(make-obsolete-variable 'query-replace-interactive + "use `M-n' to pull the last incremental search string +to the minibuffer that reads the string to replace, or invoke replacements +from Isearch by using a key sequence like `C-s C-s M-%'." "24.3") (defcustom query-replace-from-history-variable 'query-replace-history "History list to use for the FROM argument of `query-replace' commands. @@ -112,20 +132,22 @@ wants to replace FROM with TO." (if query-replace-interactive (car (if regexp-flag regexp-search-ring search-ring)) (let* ((history-add-new-input nil) + (prompt + (if query-replace-defaults + (format "%s (default %s -> %s): " prompt + (query-replace-descr (car query-replace-defaults)) + (query-replace-descr (cdr query-replace-defaults))) + (format "%s: " prompt))) (from ;; The save-excursion here is in case the user marks and copies ;; a region in order to specify the minibuffer input. ;; That should not clobber the region for the query-replace itself. (save-excursion - (read-from-minibuffer - (if query-replace-defaults - (format "%s (default %s -> %s): " prompt - (query-replace-descr (car query-replace-defaults)) - (query-replace-descr (cdr query-replace-defaults))) - (format "%s: " prompt)) - nil nil nil - query-replace-from-history-variable - nil t)))) + (if regexp-flag + (read-regexp prompt nil query-replace-from-history-variable) + (read-from-minibuffer + prompt nil nil nil query-replace-from-history-variable + (car (if regexp-flag regexp-search-ring search-ring)) t))))) (if (and (zerop (length from)) query-replace-defaults) (cons (car query-replace-defaults) (query-replace-compile-replacement @@ -214,9 +236,11 @@ what to do with it. For directions, type \\[help-command] at that time. In Transient Mark mode, if the mark is active, operate on the contents of the region. Otherwise, operate from point to the end of the buffer. -If `query-replace-interactive' is non-nil, the last incremental search -string is used as FROM-STRING--you don't have to specify it with the -minibuffer. +Use \\\\[next-history-element] \ +to pull the last incremental search string to the minibuffer +that reads FROM-STRING, or invoke replacements from +incremental search with a key sequence like `C-s C-s M-%' +to use its current search string as the string to replace. Matching is independent of case if `case-fold-search' is non-nil and FROM-STRING has no uppercase letters. Replacement transfers the case @@ -226,6 +250,10 @@ letters. \(Transferring the case pattern means that if the old text matched is all caps, or capitalized, then its replacement is upcased or capitalized.) +If `replace-lax-whitespace' is non-nil, a space or spaces in the string +to be replaced will match a sequence of whitespace chars defined by the +regexp in `search-whitespace-regexp'. + Third arg DELIMITED (prefix arg if interactive), if non-nil, means replace only matches surrounded by word boundaries. Fourth and fifth arg START and END specify the region to operate on. @@ -258,9 +286,11 @@ what to do with it. For directions, type \\[help-command] at that time. In Transient Mark mode, if the mark is active, operate on the contents of the region. Otherwise, operate from point to the end of the buffer. -If `query-replace-interactive' is non-nil, the last incremental search -regexp is used as REGEXP--you don't have to specify it with the -minibuffer. +Use \\\\[next-history-element] \ +to pull the last incremental search regexp to the minibuffer +that reads REGEXP, or invoke replacements from +incremental search with a key sequence like `C-M-s C-M-s C-M-%' +to use its current search regexp as the regexp to replace. Matching is independent of case if `case-fold-search' is non-nil and REGEXP has no uppercase letters. Replacement transfers the case @@ -270,6 +300,10 @@ pattern of the old text to the new text, if `case-replace' and all caps, or capitalized, then its replacement is upcased or capitalized.) +If `replace-regexp-lax-whitespace' is non-nil, a space or spaces in the regexp +to be replaced will match a sequence of whitespace chars defined by the +regexp in `search-whitespace-regexp'. + Third arg DELIMITED (prefix arg if interactive), if non-nil, means replace only matches surrounded by word boundaries. Fourth and fifth arg START and END specify the region to operate on. @@ -339,45 +373,47 @@ In interactive use, `\\#' in itself stands for `replace-count'. In Transient Mark mode, if the mark is active, operate on the contents of the region. Otherwise, operate from point to the end of the buffer. -If `query-replace-interactive' is non-nil, the last incremental search -regexp is used as REGEXP--you don't have to specify it with the -minibuffer. +Use \\\\[next-history-element] \ +to pull the last incremental search regexp to the minibuffer +that reads REGEXP. Preserves case in each replacement if `case-replace' and `case-fold-search' are non-nil and REGEXP has no uppercase letters. +If `replace-regexp-lax-whitespace' is non-nil, a space or spaces in the regexp +to be replaced will match a sequence of whitespace chars defined by the +regexp in `search-whitespace-regexp'. + Third arg DELIMITED (prefix arg if interactive), if non-nil, means replace only matches that are surrounded by word boundaries. Fourth and fifth arg START and END specify the region to operate on." + (declare (obsolete "use the `\\,' feature of `query-replace-regexp' +for interactive calls, and `search-forward-regexp'/`replace-match' +for Lisp calls." "22.1")) (interactive (progn - (barf-if-buffer-read-only) - (let* ((from - ;; Let-bind the history var to disable the "foo -> bar" default. - ;; Maybe we shouldn't disable this default, but for now I'll - ;; leave it off. --Stef - (let ((query-replace-to-history-variable nil)) - (query-replace-read-from "Query replace regexp" t))) - (to (list (read-from-minibuffer - (format "Query replace regexp %s with eval: " - (query-replace-descr from)) - nil nil t query-replace-to-history-variable from t)))) - ;; We make TO a list because replace-match-string-symbols requires one, - ;; and the user might enter a single token. - (replace-match-string-symbols to) - (list from (car to) current-prefix-arg - (if (and transient-mark-mode mark-active) - (region-beginning)) - (if (and transient-mark-mode mark-active) - (region-end)))))) + (barf-if-buffer-read-only) + (let* ((from + ;; Let-bind the history var to disable the "foo -> bar" + ;; default. Maybe we shouldn't disable this default, but + ;; for now I'll leave it off. --Stef + (let ((query-replace-to-history-variable nil)) + (query-replace-read-from "Query replace regexp" t))) + (to (list (read-from-minibuffer + (format "Query replace regexp %s with eval: " + (query-replace-descr from)) + nil nil t query-replace-to-history-variable from t)))) + ;; We make TO a list because replace-match-string-symbols requires one, + ;; and the user might enter a single token. + (replace-match-string-symbols to) + (list from (car to) current-prefix-arg + (if (and transient-mark-mode mark-active) + (region-beginning)) + (if (and transient-mark-mode mark-active) + (region-end)))))) (perform-replace regexp (cons 'replace-eval-replacement to-expr) t 'literal delimited nil nil start end)) -(make-obsolete 'query-replace-regexp-eval - "for interactive use, use the special `\\,' feature of -`query-replace-regexp' instead. Non-interactively, a loop -using `search-forward-regexp' and `replace-match' is preferred." "22.1") - (defun map-query-replace-regexp (regexp to-strings &optional n start end) "Replace some matches for REGEXP with various strings, in rotation. The second argument TO-STRINGS contains the replacement strings, separated @@ -390,19 +426,16 @@ of the region. Otherwise, operate from point to the end of the buffer. Non-interactively, TO-STRINGS may be a list of replacement strings. -If `query-replace-interactive' is non-nil, the last incremental search -regexp is used as REGEXP--you don't have to specify it with the minibuffer. +Use \\\\[next-history-element] \ +to pull the last incremental search regexp to the minibuffer +that reads REGEXP. A prefix argument N says to use each replacement string N times before rotating to the next. Fourth and fifth arg START and END specify the region to operate on." (interactive - (let* ((from (if query-replace-interactive - (car regexp-search-ring) - (read-from-minibuffer "Map query replace (regexp): " - nil nil nil - query-replace-from-history-variable - nil t))) + (let* ((from (read-regexp "Map query replace (regexp): " nil + query-replace-from-history-variable)) (to (read-from-minibuffer (format "Query replace %s with (space-separated strings): " (query-replace-descr from)) @@ -437,6 +470,10 @@ are non-nil and FROM-STRING has no uppercase letters. \(Preserving case means that if the string matched is all caps, or capitalized, then its replacement is upcased or capitalized.) +If `replace-lax-whitespace' is non-nil, a space or spaces in the string +to be replaced will match a sequence of whitespace chars defined by the +regexp in `search-whitespace-regexp'. + In Transient Mark mode, if the mark is active, operate on the contents of the region. Otherwise, operate from point to the end of the buffer. @@ -444,9 +481,9 @@ Third arg DELIMITED (prefix arg if interactive), if non-nil, means replace only matches surrounded by word boundaries. Fourth and fifth arg START and END specify the region to operate on. -If `query-replace-interactive' is non-nil, the last incremental search -string is used as FROM-STRING--you don't have to specify it with the -minibuffer. +Use \\\\[next-history-element] \ +to pull the last incremental search string to the minibuffer +that reads FROM-STRING. This function is usually the wrong thing to use in a Lisp program. What you probably want is a loop like this: @@ -475,6 +512,10 @@ and TO-STRING is also null.)" Preserve case in each match if `case-replace' and `case-fold-search' are non-nil and REGEXP has no uppercase letters. +If `replace-regexp-lax-whitespace' is non-nil, a space or spaces in the regexp +to be replaced will match a sequence of whitespace chars defined by the +regexp in `search-whitespace-regexp'. + In Transient Mark mode, if the mark is active, operate on the contents of the region. Otherwise, operate from point to the end of the buffer. @@ -505,8 +546,9 @@ When using those Lisp features interactively in the replacement text, TO-STRING is actually made a list instead of a string. Use \\[repeat-complex-command] after this command for details. -If `query-replace-interactive' is non-nil, the last incremental search -regexp is used as REGEXP--you don't have to specify it with the minibuffer. +Use \\\\[next-history-element] \ +to pull the last incremental search regexp to the minibuffer +that reads REGEXP. This function is usually the wrong thing to use in a Lisp program. What you probably want is a loop like this: @@ -538,38 +580,47 @@ of `history-length', which see.") (defvar occur-collect-regexp-history '("\\1") "History of regexp for occur's collect operation") -(defun read-regexp (prompt &optional default-value) - "Read regexp as a string using the regexp history and some useful defaults. -Prompt for a regular expression with PROMPT (without a colon and -space) in the minibuffer. The optional argument DEFAULT-VALUE -provides the value to display in the minibuffer prompt that is -returned if the user just types RET. -Values available via M-n are the string at point, the last isearch -regexp, the last isearch string, and the last replacement regexp." - (let* ((defaults - (list (regexp-quote - (or (funcall (or find-tag-default-function - (get major-mode 'find-tag-default-function) - 'find-tag-default)) - "")) - (car regexp-search-ring) - (regexp-quote (or (car search-ring) "")) - (car (symbol-value - query-replace-from-history-variable)))) +(defun read-regexp (prompt &optional defaults history) + "Read and return a regular expression as a string. +When PROMPT doesn't end with a colon and space, it adds a final \": \". +If DEFAULTS is non-nil, it displays the first default in the prompt. + +Non-nil optional arg DEFAULTS is a string or a list of strings that +are prepended to a list of standard default values, which include the +string at point, the last isearch regexp, the last isearch string, and +the last replacement regexp. + +Non-nil HISTORY is a symbol to use for the history list. +If HISTORY is nil, `regexp-history' is used." + (let* ((default (if (consp defaults) (car defaults) defaults)) + (defaults + (append + (if (listp defaults) defaults (list defaults)) + (list (regexp-quote + (or (funcall (or find-tag-default-function + (get major-mode 'find-tag-default-function) + 'find-tag-default)) + "")) + (car regexp-search-ring) + (regexp-quote (or (car search-ring) "")) + (car (symbol-value + query-replace-from-history-variable))))) (defaults (delete-dups (delq nil (delete "" defaults)))) - ;; Don't add automatically the car of defaults for empty input + ;; Do not automatically add default to the history for empty input. (history-add-new-input nil) - (input - (read-from-minibuffer - (if default-value - (format "%s (default %s): " prompt - (query-replace-descr default-value)) - (format "%s: " prompt)) - nil nil nil 'regexp-history defaults t))) + (input (read-from-minibuffer + (cond ((string-match-p ":[ \t]*\\'" prompt) + prompt) + (default + (format "%s (default %s): " prompt + (query-replace-descr default))) + (t + (format "%s: " prompt))) + nil nil nil (or history 'regexp-history) defaults t))) (if (equal input "") - (or default-value input) + (or default input) (prog1 input - (add-to-history 'regexp-history input))))) + (add-to-history (or history 'regexp-history) input))))) (defalias 'delete-non-matching-lines 'keep-lines) @@ -763,45 +814,47 @@ a previously found match." (defvar occur-menu-map (let ((map (make-sparse-keymap))) - (define-key map [next-error-follow-minor-mode] - `(menu-item ,(purecopy "Auto Occurrence Display") + (bindings--define-key map [next-error-follow-minor-mode] + '(menu-item "Auto Occurrence Display" next-error-follow-minor-mode - :help ,(purecopy - "Display another occurrence when moving the cursor") + :help "Display another occurrence when moving the cursor" :button (:toggle . (and (boundp 'next-error-follow-minor-mode) next-error-follow-minor-mode)))) - (define-key map [separator-1] menu-bar-separator) - (define-key map [kill-this-buffer] - `(menu-item ,(purecopy "Kill Occur Buffer") kill-this-buffer - :help ,(purecopy "Kill the current *Occur* buffer"))) - (define-key map [quit-window] - `(menu-item ,(purecopy "Quit Occur Window") quit-window - :help ,(purecopy "Quit the current *Occur* buffer. Bury it, and maybe delete the selected frame"))) - (define-key map [revert-buffer] - `(menu-item ,(purecopy "Revert Occur Buffer") revert-buffer - :help ,(purecopy "Replace the text in the *Occur* buffer with the results of rerunning occur"))) - (define-key map [clone-buffer] - `(menu-item ,(purecopy "Clone Occur Buffer") clone-buffer - :help ,(purecopy "Create and return a twin copy of the current *Occur* buffer"))) - (define-key map [occur-rename-buffer] - `(menu-item ,(purecopy "Rename Occur Buffer") occur-rename-buffer - :help ,(purecopy "Rename the current *Occur* buffer to *Occur: original-buffer-name*."))) - (define-key map [separator-2] menu-bar-separator) - (define-key map [occur-mode-goto-occurrence-other-window] - `(menu-item ,(purecopy "Go To Occurrence Other Window") occur-mode-goto-occurrence-other-window - :help ,(purecopy "Go to the occurrence the current line describes, in another window"))) - (define-key map [occur-mode-goto-occurrence] - `(menu-item ,(purecopy "Go To Occurrence") occur-mode-goto-occurrence - :help ,(purecopy "Go to the occurrence the current line describes"))) - (define-key map [occur-mode-display-occurrence] - `(menu-item ,(purecopy "Display Occurrence") occur-mode-display-occurrence - :help ,(purecopy "Display in another window the occurrence the current line describes"))) - (define-key map [occur-next] - `(menu-item ,(purecopy "Move to Next Match") occur-next - :help ,(purecopy "Move to the Nth (default 1) next match in an Occur mode buffer"))) - (define-key map [occur-prev] - `(menu-item ,(purecopy "Move to Previous Match") occur-prev - :help ,(purecopy "Move to the Nth (default 1) previous match in an Occur mode buffer"))) + (bindings--define-key map [separator-1] menu-bar-separator) + (bindings--define-key map [kill-this-buffer] + '(menu-item "Kill Occur Buffer" kill-this-buffer + :help "Kill the current *Occur* buffer")) + (bindings--define-key map [quit-window] + '(menu-item "Quit Occur Window" quit-window + :help "Quit the current *Occur* buffer. Bury it, and maybe delete the selected frame")) + (bindings--define-key map [revert-buffer] + '(menu-item "Revert Occur Buffer" revert-buffer + :help "Replace the text in the *Occur* buffer with the results of rerunning occur")) + (bindings--define-key map [clone-buffer] + '(menu-item "Clone Occur Buffer" clone-buffer + :help "Create and return a twin copy of the current *Occur* buffer")) + (bindings--define-key map [occur-rename-buffer] + '(menu-item "Rename Occur Buffer" occur-rename-buffer + :help "Rename the current *Occur* buffer to *Occur: original-buffer-name*.")) + (bindings--define-key map [occur-edit-buffer] + '(menu-item "Edit Occur Buffer" occur-edit-mode + :help "Edit the *Occur* buffer and apply changes to the original buffers.")) + (bindings--define-key map [separator-2] menu-bar-separator) + (bindings--define-key map [occur-mode-goto-occurrence-other-window] + '(menu-item "Go To Occurrence Other Window" occur-mode-goto-occurrence-other-window + :help "Go to the occurrence the current line describes, in another window")) + (bindings--define-key map [occur-mode-goto-occurrence] + '(menu-item "Go To Occurrence" occur-mode-goto-occurrence + :help "Go to the occurrence the current line describes")) + (bindings--define-key map [occur-mode-display-occurrence] + '(menu-item "Display Occurrence" occur-mode-display-occurrence + :help "Display in another window the occurrence the current line describes")) + (bindings--define-key map [occur-next] + '(menu-item "Move to Next Match" occur-next + :help "Move to the Nth (default 1) next match in an Occur mode buffer")) + (bindings--define-key map [occur-prev] + '(menu-item "Move to Previous Match" occur-prev + :help "Move to the Nth (default 1) previous match in an Occur mode buffer")) map) "Menu keymap for `occur-mode'.") @@ -810,7 +863,7 @@ a previously found match." ;; We use this alternative name, so we can use \\[occur-mode-mouse-goto]. (define-key map [mouse-2] 'occur-mode-mouse-goto) (define-key map "\C-c\C-c" 'occur-mode-goto-occurrence) - (define-key map "\C-x\C-q" 'occur-edit-mode) + (define-key map "e" 'occur-edit-mode) (define-key map "\C-m" 'occur-mode-goto-occurrence) (define-key map "o" 'occur-mode-goto-occurrence-other-window) (define-key map "\C-o" 'occur-mode-display-occurrence) @@ -819,13 +872,15 @@ a previously found match." (define-key map "r" 'occur-rename-buffer) (define-key map "c" 'clone-buffer) (define-key map "\C-c\C-f" 'next-error-follow-minor-mode) - (define-key map [menu-bar occur] (cons (purecopy "Occur") occur-menu-map)) + (bindings--define-key map [menu-bar occur] (cons "Occur" occur-menu-map)) map) "Keymap for `occur-mode'.") (defvar occur-revert-arguments nil "Arguments to pass to `occur-1' to revert an Occur mode buffer. See `occur-revert-function'.") +(make-variable-buffer-local 'occur-revert-arguments) +(put 'occur-revert-arguments 'permanent-local t) (defcustom occur-mode-hook '(turn-on-font-lock) "Hook run when entering Occur mode." @@ -853,8 +908,6 @@ Alternatively, click \\[occur-mode-mouse-goto] on an item to go to it. \\{occur-mode-map}" (set (make-local-variable 'revert-buffer-function) 'occur-revert-function) - (make-local-variable 'occur-revert-arguments) - (add-hook 'change-major-mode-hook 'font-lock-defontify nil t) (setq next-error-function 'occur-next-error)) @@ -864,10 +917,10 @@ Alternatively, click \\[occur-mode-mouse-goto] on an item to go to it. (let ((map (make-sparse-keymap))) (set-keymap-parent map text-mode-map) (define-key map [mouse-2] 'occur-mode-mouse-goto) - (define-key map "\C-c\C-c" 'occur-mode-goto-occurrence) - (define-key map "\C-x\C-q" 'occur-mode) + (define-key map "\C-c\C-c" 'occur-cease-edit) + (define-key map "\C-o" 'occur-mode-display-occurrence) (define-key map "\C-c\C-f" 'next-error-follow-minor-mode) - (define-key map [menu-bar occur] (cons (purecopy "Occur") occur-menu-map)) + (bindings--define-key map [menu-bar occur] (cons "Occur" occur-menu-map)) map) "Keymap for `occur-edit-mode'.") @@ -876,42 +929,58 @@ Alternatively, click \\[occur-mode-mouse-goto] on an item to go to it. In this mode, changes to the *Occur* buffer are also applied to the originating buffer. -To return to ordinary Occur mode, use \\[occur-mode]." +To return to ordinary Occur mode, use \\[occur-cease-edit]." (setq buffer-read-only nil) - (add-hook 'after-change-functions 'occur-after-change-function nil t)) + (add-hook 'after-change-functions 'occur-after-change-function nil t) + (message (substitute-command-keys + "Editing: Type \\[occur-cease-edit] to return to Occur mode."))) + +(defun occur-cease-edit () + "Switch from Occur Edit mode to Occur mode." + (interactive) + (when (derived-mode-p 'occur-edit-mode) + (occur-mode) + (message "Switching to Occur mode."))) (defun occur-after-change-function (beg end length) (save-excursion (goto-char beg) - (let* ((m (get-text-property (line-beginning-position) 'occur-target)) + (let* ((line-beg (line-beginning-position)) + (m (get-text-property line-beg 'occur-target)) (buf (marker-buffer m)) - (col (current-column))) - (when (= length 0) - ;; Apply occur-target property to inserted (e.g. yanked) text. - (put-text-property beg end 'occur-target m) - ;; Did we insert a newline? Occur Edit mode can't create new - ;; Occur entries; just discard everything after the newline. - (save-excursion - (and (search-forward "\n" end t) - (delete-region (1- (point)) end)))) - (let ((line (- (line-number-at-pos) - (line-number-at-pos (window-start)))) - (readonly (with-current-buffer buf buffer-read-only)) - (win (or (get-buffer-window buf) - (display-buffer buf t))) - (text (save-excursion - (forward-line 0) - (search-forward ":" nil t) - (setq col (- col (current-column))) - (buffer-substring-no-properties (point) (line-end-position))))) - (with-selected-window win - (goto-char m) - (recenter line) - (if readonly - (message "Buffer `%s' is read only." buf) - (delete-region (line-beginning-position) (line-end-position)) - (insert text)) - (move-to-column col)))))) + col) + (when (and (get-text-property line-beg 'occur-prefix) + (not (get-text-property end 'occur-prefix))) + (when (= length 0) + ;; Apply occur-target property to inserted (e.g. yanked) text. + (put-text-property beg end 'occur-target m) + ;; Did we insert a newline? Occur Edit mode can't create new + ;; Occur entries; just discard everything after the newline. + (save-excursion + (and (search-forward "\n" end t) + (delete-region (1- (point)) end)))) + (let* ((line (- (line-number-at-pos) + (line-number-at-pos (window-start)))) + (readonly (with-current-buffer buf buffer-read-only)) + (win (or (get-buffer-window buf) + (display-buffer buf + '(nil (inhibit-same-window . t) + (inhibit-switch-frame . t))))) + (line-end (line-end-position)) + (text (save-excursion + (goto-char (next-single-property-change + line-beg 'occur-prefix nil + line-end)) + (setq col (- (point) line-beg)) + (buffer-substring-no-properties (point) line-end)))) + (with-selected-window win + (goto-char m) + (recenter line) + (if readonly + (message "Buffer `%s' is read only." buf) + (delete-region (line-beginning-position) (line-end-position)) + (insert text)) + (move-to-column col))))))) (defun occur-revert-function (_ignore1 _ignore2) @@ -928,7 +997,7 @@ To return to ordinary Occur mode, use \\[occur-mode]." (defalias 'occur-mode-mouse-goto 'occur-mode-goto-occurrence) (defun occur-mode-goto-occurrence (&optional event) - "Go to the occurrence the current line describes." + "Go to the occurrence on the current line." (interactive (list last-nonmenu-event)) (let ((pos (if (null event) @@ -939,9 +1008,7 @@ To return to ordinary Occur mode, use \\[occur-mode]." (with-current-buffer (window-buffer (posn-window (event-end event))) (save-excursion (goto-char (posn-point (event-end event))) - (occur-mode-find-occurrence))))) - same-window-buffer-names - same-window-regexps) + (occur-mode-find-occurrence)))))) (pop-to-buffer (marker-buffer pos)) (goto-char pos) (run-hooks 'occur-mode-find-occurrence-hook))) @@ -958,11 +1025,8 @@ To return to ordinary Occur mode, use \\[occur-mode]." "Display in another window the occurrence the current line describes." (interactive) (let ((pos (occur-mode-find-occurrence)) - window - ;; Bind these to ensure `display-buffer' puts it in another window. - same-window-buffer-names - same-window-regexps) - (setq window (display-buffer (marker-buffer pos))) + window) + (setq window (display-buffer (marker-buffer pos) t)) ;; This is the way to set point in the proper window. (save-selected-window (select-window window) @@ -1081,9 +1145,9 @@ which means to discard all text properties." "\\&" ;; Get the regexp for collection pattern. (let ((default (car occur-collect-regexp-history))) - (read-string + (read-regexp (format "Regexp to collect (default %s): " default) - nil 'occur-collect-regexp-history default))) + default 'occur-collect-regexp-history))) ;; Otherwise normal occur takes numerical prefix argument. (when current-prefix-arg (prefix-numeric-value current-prefix-arg)))))) @@ -1129,8 +1193,8 @@ contain \\& and \\N which convention follows `replace-match'. For example, providing \"defun\\s +\\(\\S +\\)\" for REGEXP and \"\\1\" for NLINES collects all the function names in a lisp program. When there is no parenthesized subexpressions in REGEXP -the entire match is collected. In any case the searched buffers -are not modified." +the entire match is collected. In any case the searched buffer +is not modified." (interactive (occur-read-primary-args)) (occur-1 regexp nlines (list (current-buffer)))) @@ -1140,7 +1204,8 @@ are not modified." "Show all lines in buffers BUFS containing a match for REGEXP. This function acts on multiple buffers; otherwise, it is exactly like `occur'. When you invoke this command interactively, you must specify -the buffer names that you want, one by one." +the buffer names that you want, one by one. +See also `multi-occur-in-matching-buffers'." (interactive (cons (let* ((bufs (list (read-buffer "First buffer to search: " @@ -1169,14 +1234,10 @@ See also `multi-occur'." (cons (let* ((default (car regexp-history)) (input - (read-from-minibuffer + (read-regexp (if current-prefix-arg "List lines in buffers whose names match regexp: " - "List lines in buffers whose filenames match regexp: ") - nil - nil - nil - 'regexp-history))) + "List lines in buffers whose filenames match regexp: ")))) (if (equal input "") default input)) @@ -1215,7 +1276,7 @@ See also `multi-occur'." (with-current-buffer occur-buf (if (stringp nlines) - (fundamental-mode) ;; This is for collect opeartion. + (fundamental-mode) ;; This is for collect operation. (occur-mode)) (let ((inhibit-read-only t) ;; Don't generate undo entries for creation of the initial contents. @@ -1340,9 +1401,12 @@ See also `multi-occur'." (when prefix-face `(font-lock-face prefix-face)) `(occur-prefix t mouse-face (highlight) - occur-target ,marker follow-link t - read-only t - help-echo "mouse-2: go to this occurrence")))) + ;; Allow insertion of text at + ;; the end of the prefix (for + ;; Occur Edit mode). + front-sticky t rear-nonsticky t + occur-target ,marker follow-link t + help-echo "mouse-2: go to this occurrence")))) (match-str ;; We don't put `mouse-face' on the newline, ;; because that loses. And don't put it @@ -1539,9 +1603,13 @@ Comma to replace but not move point immediately, C-r to enter recursive edit (\\[exit-recursive-edit] to get out again), C-w to delete match and recursive edit, C-l to clear the screen, redisplay, and offer same replacement again, -! to replace all remaining matches with no more questions, +! to replace all remaining matches in this buffer with no more questions, ^ to move point back to previous match, -E to edit the replacement string" +E to edit the replacement string. +In multi-buffer replacements type `Y' to replace all remaining +matches in all remaining buffers with no more questions, +`N' to skip to the next buffer without replacing remaining matches +in the current buffer." "Help message while in `query-replace'.") (defvar query-replace-map @@ -1572,14 +1640,28 @@ E to edit the replacement string" (define-key map "?" 'help) (define-key map "\C-g" 'quit) (define-key map "\C-]" 'quit) - (define-key map "\e" 'exit-prefix) + (define-key map "\C-v" 'scroll-up) + (define-key map "\M-v" 'scroll-down) + (define-key map [next] 'scroll-up) + (define-key map [prior] 'scroll-down) + (define-key map [?\C-\M-v] 'scroll-other-window) + (define-key map [M-next] 'scroll-other-window) + (define-key map [?\C-\M-\S-v] 'scroll-other-window-down) + (define-key map [M-prior] 'scroll-other-window-down) + ;; Binding ESC would prohibit the M-v binding. Instead, callers + ;; should check for ESC specially. + ;; (define-key map "\e" 'exit-prefix) (define-key map [escape] 'exit-prefix) map) - "Keymap that defines the responses to questions in `query-replace'. + "Keymap of responses to questions posed by commands like `query-replace'. The \"bindings\" in this map are not commands; they are answers. The valid answers include `act', `skip', `act-and-show', -`exit', `act-and-exit', `edit', `delete-and-edit', `recenter', -`automatic', `backup', `exit-prefix', and `help'.") +`act-and-exit', `exit', `exit-prefix', `recenter', `scroll-up', +`scroll-down', `scroll-other-window', `scroll-other-window-down', +`edit', `edit-replacement', `delete-and-edit', `automatic', +`backup', `quit', and `help'. + +This keymap is used by `y-or-n-p' as well as `query-replace'.") (defvar multi-query-replace-map (let ((map (make-sparse-keymap))) @@ -1650,7 +1732,7 @@ with the `noescape' argument set. t t))) (defun replace-loop-through-replacements (data count) - ;; DATA is a vector contaning the following values: + ;; DATA is a vector containing the following values: ;; 0 next-rotate-count ;; 1 repeat-count ;; 2 next-replacement @@ -1700,12 +1782,12 @@ passed in. If LITERAL is set, no checking is done, anyway." (replace-match newtext fixedcase literal) noedit) -(defvar replace-search-function 'search-forward +(defvar replace-search-function nil "Function to use when searching for strings to replace. It is used by `query-replace' and `replace-string', and is called with three arguments, as if it were `search-forward'.") -(defvar replace-re-search-function 're-search-forward +(defvar replace-re-search-function nil "Function to use when searching for regexps to replace. It is used by `query-replace-regexp', `replace-regexp', `query-replace-regexp-eval', and `map-query-replace-regexp'. @@ -1738,9 +1820,18 @@ make, or the user didn't cancel the call." (nocasify (not (and case-replace case-fold-search))) (literal (or (not regexp-flag) (eq regexp-flag 'literal))) (search-function - (if regexp-flag - replace-re-search-function - replace-search-function)) + (or (if regexp-flag + replace-re-search-function + replace-search-function) + (let ((isearch-regexp regexp-flag) + (isearch-word delimited-flag) + (isearch-lax-whitespace + replace-lax-whitespace) + (isearch-regexp-lax-whitespace + replace-regexp-lax-whitespace) + (isearch-case-fold-search case-fold-search) + (isearch-forward t)) + (isearch-search-fun)))) (search-string from-string) (real-match-data nil) ; The match data for the current match. (next-replacement nil) @@ -1794,12 +1885,6 @@ make, or the user didn't cancel the call." (vector repeat-count repeat-count replacements replacements))))) - (if delimited-flag - (setq search-function 're-search-forward - search-string (concat "\\b" - (if regexp-flag from-string - (regexp-quote from-string)) - "\\b"))) (when query-replace-lazy-highlight (setq isearch-lazy-highlight-last-string nil)) @@ -1881,7 +1966,7 @@ make, or the user didn't cancel the call." (replace-highlight (nth 0 real-match-data) (nth 1 real-match-data) start end search-string - (or delimited-flag regexp-flag) case-fold-search)) + regexp-flag delimited-flag case-fold-search)) (setq noedit (replace-match-maybe-edit next-replacement nocasify literal @@ -1900,7 +1985,7 @@ make, or the user didn't cancel the call." (replace-highlight (match-beginning 0) (match-end 0) start end search-string - (or delimited-flag regexp-flag) case-fold-search) + regexp-flag delimited-flag case-fold-search) ;; Bind message-log-max so we don't fill up the message log ;; with a bunch of identical messages. (let ((message-log-max nil) @@ -2082,15 +2167,11 @@ make, or the user didn't cancel the call." (if (= replace-count 1) "" "s"))) (or (and keep-going stack) multi-buffer))) -(defvar isearch-error) -(defvar isearch-forward) -(defvar isearch-case-fold-search) -(defvar isearch-string) - (defvar replace-overlay nil) (defun replace-highlight (match-beg match-end range-beg range-end - string regexp case-fold) + search-string regexp-flag delimited-flag + case-fold-search) (if query-replace-highlight (if replace-overlay (move-overlay replace-overlay match-beg match-end (current-buffer)) @@ -2098,15 +2179,16 @@ make, or the user didn't cancel the call." (overlay-put replace-overlay 'priority 1001) ;higher than lazy overlays (overlay-put replace-overlay 'face 'query-replace))) (if query-replace-lazy-highlight - (let ((isearch-string string) - (isearch-regexp regexp) - (search-whitespace-regexp nil) - (isearch-case-fold-search case-fold) + (let ((isearch-string search-string) + (isearch-regexp regexp-flag) + (isearch-word delimited-flag) + (isearch-lax-whitespace + replace-lax-whitespace) + (isearch-regexp-lax-whitespace + replace-regexp-lax-whitespace) + (isearch-case-fold-search case-fold-search) (isearch-forward t) (isearch-error nil)) - ;; Set isearch-word to nil because word-replace is regexp-based, - ;; so `isearch-search-fun' should not use `word-search-forward'. - (if (and isearch-word isearch-regexp) (setq isearch-word nil)) (isearch-lazy-highlight-new-loop range-beg range-end)))) (defun replace-dehighlight ()