Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Search and replace inside a rectangle in emacs

Is it possible to perform a replace-string operation inside of a rectangular region in emacs? If so, how?

like image 573
user545424 Avatar asked Jun 21 '12 01:06

user545424


People also ask

How do I find and replace in Emacs?

Simple Search and Replace Operations When you want to replace every instance of a given string, you can use a simple command that tells Emacs to do just that. Type ESC x replace-string RETURN, then type the search string and press RETURN.

How do I select a rectangle in Emacs?

The command C-x SPC ( rectangle-mark-mode ) toggles whether the region-rectangle or the standard region is highlighted (first activating the region if necessary).


1 Answers

If you enable CUA selection mode:

M-x cua-selection-mode RET

or permanently in your init file:

(cua-selection-mode 1) 

You can then use its advanced rectangle editing facilities.

(or if you're a cua-mode user, then you don't need to do that.)

  • C-RET to mark a corner.
  • Move point to opposite corner.
  • M-r to do a regexp replace within the marked rectangle.
  • C-RET to unmark/exit rectangle editing.

For documentation, look for the "CUA rectangle support" heading in the commentary in M-x find-library RET cua-base RET

If you don't want to use the cua rectangle facilities for some reason (perhaps if you really need replace-string specifically), a custom function using apply-on-rectangle would be pretty simply to put together.

Edit: Actually, slightly more complex than I had expected, but most of the code is the interactive spec and the support for the 'delimited' prefix argument behaviour (both based on replace-string).

Edit 2: I decided this was worth doing in a more fully-featured manner:

The following provides C-xrM-% and C-xrC-M-%, which (hopefully) act the way you would expect.

(require 'rect)  (defun my-search-replace-in-rectangle   (start end search-pattern replacement search-function literal)   "Replace all instances of SEARCH-PATTERN (as found by SEARCH-FUNCTION) with REPLACEMENT, in each line of the rectangle established by the START and END buffer positions.  SEARCH-FUNCTION should take the same BOUND and NOERROR arguments as `search-forward' and `re-search-forward'.  The LITERAL argument is passed to `replace-match' during replacement.  If `case-replace' is nil, do not alter case of replacement text."   (apply-on-rectangle    (lambda (start-col end-col search-function search-pattern replacement)      (move-to-column start-col)      (let ((bound (min (+ (point) (- end-col start-col))                        (line-end-position)))            (fixedcase (not case-replace)))        (while (funcall search-function search-pattern bound t)          (replace-match replacement fixedcase literal))))    start end search-function search-pattern replacement))  (defun my-replace-regexp-rectangle-read-args (regexp-flag)   "Interactively read arguments for `my-replace-regexp-rectangle' or `my-replace-string-rectangle' (depending upon REGEXP-FLAG)."   (let ((args (query-replace-read-args                (concat "Replace"                        (if current-prefix-arg " word" "")                        (if regexp-flag " regexp" " string"))                regexp-flag)))     (list (region-beginning) (region-end)           (nth 0 args) (nth 1 args) (nth 2 args))))  (defun my-replace-regexp-rectangle   (start end regexp to-string &optional delimited)   "Perform a regexp search and replace on each line of a rectangle established by START and END (interactively, the marked region), similar to `replace-regexp'.  Optional arg DELIMITED (prefix arg if interactive), if non-nil, means replace only matches surrounded by word boundaries.  If `case-replace' is nil, do not alter case of replacement text."   (interactive (my-replace-regexp-rectangle-read-args t))   (when delimited     (setq regexp (concat "\\b" regexp "\\b")))   (my-search-replace-in-rectangle    start end regexp to-string 're-search-forward nil))  (defun my-replace-string-rectangle   (start end from-string to-string &optional delimited)   "Perform a string search and replace on each line of a rectangle established by START and END (interactively, the marked region), similar to `replace-string'.  Optional arg DELIMITED (prefix arg if interactive), if non-nil, means replace only matches surrounded by word boundaries.  If `case-replace' is nil, do not alter case of replacement text."   (interactive (my-replace-regexp-rectangle-read-args nil))   (let ((search-function 'search-forward))     (when delimited       (setq search-function 're-search-forward             from-string (concat "\\b" (regexp-quote from-string) "\\b")))     (my-search-replace-in-rectangle      start end from-string to-string search-function t)))  (global-set-key (kbd "C-x r M-%") 'my-replace-string-rectangle) (global-set-key (kbd "C-x r C-M-%") 'my-replace-regexp-rectangle) 
like image 141
phils Avatar answered Sep 24 '22 23:09

phils