20

Search and replace, by M-% and !, is done from current position to the end of the buffer. How can I do it for the entire buffer? Thanks.

3
  • 2
    I suggest changing the title to "search and replace entire buffer". Globally could also be referring to entire projects.
    – Malabarba
    Sep 25 '14 at 16:01
  • 2
    This is one area where Vim/Evil is hard to beat: :%s/foo/bar
    – shosti
    Sep 25 '14 at 18:31
  • @shosti: Actually, I think your method requires more keystrokes. Just sayin' ;-)
    – nispio
    Sep 25 '14 at 20:13
17

I don't see that supported while still retaining your starting position. (I don't see a way to wrap to the beginning of the buffer when search reaches the end.)

Your best bet is using M-< to go to the start of the buffer, then do the query-replace, when you're done press C-uC-spaceC-uC-space to jump back to your starting point.

2
  • 1
    This works when transient-mark-mode is on. Otherwise C-SPC C-SPC will temporarily enable transient-mark-mode
    – nispio
    Sep 25 '14 at 16:43
  • 5
    No need to set the mark manually with C-SPC. M-< (and many other commands that potentially "move point a long way") does it for you. Sep 25 '14 at 18:45
12

You can follow the following steps:

  • C-x h — Select the whole buffer or M-< - Go to the top of the buffer
  • M-% — Initiate query-replace
  • ! — Force replace all
  • C-u C-SPC C-u C-SPC — Move back to your starting position
1
  • This should get more attention.
    – Indra
    May 29 '19 at 9:05
9

You could add the following command to your emacs initialization file, and bind it to the keystroke of your choice.

(defun replace-regexp-entire-buffer (pattern replacement)
  "Perform regular-expression replacement throughout buffer."
  (interactive
   (let ((args (query-replace-read-args "Replace" t)))
     (setcdr (cdr args) nil)    ; remove third value returned from query---args
     args))
  (save-excursion
    (goto-char (point-min))
    (while (re-search-forward pattern nil t)
      (replace-match replacement))))
1
  • Can it iterate to replace each one by one?
    – alper
    Jun 30 at 0:36
3

You can add this to your init.el file to update the behavior of M-% to to replace the word in the entire buffer by default:

(defun my/query-replace (from-string to-string &optional delimited start end)
  "Replace some occurrences of FROM-STRING with TO-STRING.  As each match is
found, the user must type a character saying what to do with it. This is a
modified version of the standard `query-replace' function in `replace.el',
This modified version defaults to operating on the entire buffer instead of
working only from POINT to the end of the buffer. For more information, see
the documentation of `query-replace'"
  (interactive
   (let ((common
      (query-replace-read-args
       (concat "Query replace"
           (if current-prefix-arg " word" "")
           (if (and transient-mark-mode mark-active) " in region" ""))
       nil)))
     (list (nth 0 common) (nth 1 common) (nth 2 common)
       (if (and transient-mark-mode mark-active)
           (region-beginning)
         (buffer-end -1))
       (if (and transient-mark-mode mark-active)
           (region-end)
         (buffer-end 1)))))
  (perform-replace from-string to-string t nil delimited nil nil start end))
;; Replace the default key mapping
(define-key esc-map "%" 'my/query-replace)

And to get the same behavior from query-replace-regexp:

(defun my/query-replace-regexp (regexp to-string &optional delimited start end)
  "Replace some things after point matching REGEXP with TO-STRING.  As each
match is found, the user must type a character saying what to do with
it. This is a modified version of the standard `query-replace-regexp'
function in `replace.el', This modified version defaults to operating on the
entire buffer instead of working only from POINT to the end of the
buffer. For more information, see the documentation of `query-replace-regexp'"
  (interactive
   (let ((common
      (query-replace-read-args
       (concat "Query replace"
           (if current-prefix-arg " word" "")
           " regexp"
           (if (and transient-mark-mode mark-active) " in region" ""))
       t)))
     (list (nth 0 common) (nth 1 common) (nth 2 common)
       (if (and transient-mark-mode mark-active)
           (region-beginning)
         (buffer-end -1))
       (if (and transient-mark-mode mark-active)
           (region-end)
         (buffer-end 1)))))
  (perform-replace regexp to-string t t delimited nil nil start end))
;; Replace the default key mapping
(define-key esc-map [?\C-%] 'my/query-replace-regexp)
1
  • Very useful. Thanks.
    – NVaughan
    Feb 10 '19 at 15:58
2

If you use Icicles then you can search-and-replace over the entire buffer (or multiple buffers or files or bookmark targets).

And unlike query-replace (e.g. C-x h M-%):

  • You can navigate the matches in any order.

  • Replacement is on demand: you need not visit each match and answer whether or not to replace it.

2
  • Icicles link seems dead
    – alper
    Feb 6 '20 at 13:54
  • @alper: Thanks; corrected. Emacs Wiki changed from http to https, and added an emacs/ subdir.
    – Drew
    Feb 6 '20 at 16:00
1

This is the solution I'm currently using, it start from the begining of the buffer and will go back to old point after replacing.

    (defun query-replace-region-or-from-top ()
      "If marked, query-replace for the region, else for the whole buffer (start from the top)"
      (interactive)
      (progn
        (let ((orig-point (point)))
          (if (use-region-p)
              (call-interactively 'query-replace)
            (save-excursion
              (goto-char (point-min))
              (call-interactively 'query-replace)))
          (message "Back to old point.")
          (goto-char orig-point))))
    (bind-key* "M-%" 'query-replace-region-or-from-top)
4
  • It gives Args out of range: #<buffer rsync.sh>, 0, 1 error once in a while, what might be the reason for it?
    – alper
    May 23 at 19:17
  • @alper Check the updated version, I personally never got any issue.
    – CodyChan
    May 24 at 18:44
  • Could you please try again with having (setq frame-background-mode 'dark) line?
    – alper
    Jun 23 at 21:29
  • Please see: emacs.stackexchange.com/questions/66460/…
    – alper
    Jun 25 at 12:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.