22

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, 2014 at 16:01
  • 3
    This is one area where Vim/Evil is hard to beat: :%s/foo/bar
    – shosti
    Sep 25, 2014 at 18:31
  • @shosti: Actually, I think your method requires more keystrokes. Just sayin' ;-)
    – nispio
    Sep 25, 2014 at 20:13

7 Answers 7

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, 2014 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, 2014 at 18:45
15

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, 2019 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, 2021 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, 2019 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, 2020 at 13:54
  • @alper: Thanks; corrected. Emacs Wiki changed from http to https, and added an emacs/ subdir.
    – Drew
    Feb 6, 2020 at 16:00
2

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)
3
  • @alper Check the updated version, I personally never got any issue.
    – CodyChan
    May 24, 2021 at 18:44
  • Would it be possible to make this case sensetive?
    – alper
    Oct 4, 2021 at 12:35
  • 1
    @alper use (let ((case-fold-search nil)) check stackoverflow.com/a/5346418/1528712
    – CodyChan
    Oct 4, 2021 at 15:24
1

My very simple but effective variant, which just advises both query-replace and query-replace-regexp to start replacing from the top of the buffer if region is not active. Otherwise, replace in the region only.

So this doesn't need new keybinds - just continue to use M-% and M-C-%.


(defun jj/goto-top-if-no-region (orig-func &rest args)
  "if region is not active, go to the buffer start"
  (save-excursion
    (when (not (use-region-p))
      (goto-char (point-min)))
    (apply orig-func args)))

(advice-add 'query-replace :around #'jj/goto-top-if-no-region)
(advice-add 'query-replace-regexp :around #'jj/goto-top-if-no-region)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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