benma / visual-regexp.el

A regexp/replace command for Emacs with interactive visual feedback
396 stars 28 forks source link

Operate on the entire buffer #16

Open wavexx opened 10 years ago

wavexx commented 10 years ago

Is it possible to have a setting (and a prefix argument to override it) for vr/replace and vr/query-replace to operate on the entire buffer when there's no mark?

Ideally, the when matching the entire buffer, the point should not be moved until the replace is executed (so that I can match on the text I'm looking at, not at the beginning of the buffer which might contain nothing).

For query-replace, it would be nice if the query would wrap around like isearch, but I would be absolutely happy if it would just start from (point-min).

I'm tired of going to the beginning of the buffer just to perform a global replace...

Thanks

benma commented 10 years ago

I try to be consistent with how the builtin replace-regexp and query-replace-regexp behave. Both of them work on the active region or from the current point onwards.

It should be possible to create a wrapper function, or a keyboard macro, that does what you want though.

Maybe something like this, though I haven't checked if it works in all circumstances:


(defun vr-replace-whole-buffer () 
  (interactive)
  (save-excursion
    (beginning-of-buffer)
    (call-interactively 'vr/replace)))

If you insist on using the prefix argument to choose between the two behaviors:

(defun vr-replace-whole-buffer (arg) 
  (interactive "P")
  (save-excursion
    (when arg
      (beginning-of-buffer))
    (call-interactively 'vr/replace)))

Though I would not recommend it, as this might conflict with a potential future use of the prefix argument in those functions.

wavexx commented 10 years ago

On 07/23/2014 12:14 PM, benma wrote:

I try to be consistent with how the builtin replace-regexp and query-replace-regexp behave. Both of them work on the active region or from the current point onwards.

I'd like replace-regexp/query-regexp to be consistent with the isearch-* functions to be totally honest. They should start from the current point, show the preview matches also above the point. The query functions should also start from the point, but then wrap around.

It should be possible to create a wrapper function, or a keyboard macro, that does what you want though.

Not "exactly", as calling (beginning-of-buffer) will move the point away from the current position. So if I was trying to match something just above/under the cursor, it's would be suddenly out of sight.

For the normal replace-string/query-replace/query-regexp-replace it doesn't matter, as they are not interactive.

But for vr/query|vr/replace it does, as ideally the preview should not move the point, but still highlight matches above.

I was able to define a new interactive function by using directly (vr--interactive-get-args) and then setting the point/calling vr/replace... But of course you won't have a preview/count for matches above the point :(

Having proper wrappers around the replace functions is also tricky to get right. I've currently refined this this:

(defmacro global-replace-function (fun) `(defun ,(intern (concat "global-" (symbol-name fun))) () (interactive) (setq this-original-command ',fun) ; fix mc/maybe-m-c-m loop (let ((region (use-region-p)) (mark (point-marker))) (unless region (goto-char (point-min))) (unwind-protect (call-interactively ',fun) (if (and (not region) ; region initially active (not (use-region-p))) ; region re-activated (goto-char (marker-position mark)))))))

(global-replace-function vr/mc-mark) (global-replace-function vr/replace) ....

in order to define global-* variants that operate correctly when the mark is active, when using mc-mark, etc. And still it sucks!

benma commented 10 years ago

For a wrap-around query-replace, how about using vr--interactive-get-args to get the arguments, and then call vr/query-replace twice in succession, once with current point to point-max, and then once again from point-min to original point?

Disregarding some details, something like this (where the arguments are obtained beforehand with vr--interactive-get-args):

(let ((current-point (point)))
    (vr/query-replace "regexp" "replace" current-point (point-max))
    (vr/query-replace "regexp" "replace" (point-min) current-point)
  ))

I could patch vr--interactive-get-args to accept arguments to control start and end. Preview feedback while entering the arguments would then be decoupled from where the replacement would actually be performed. This way, you could use it to display preview from (window-start) or (point-min), i.e. the region before point.

In the same way, you could get feedback from before point, and afterwards run vr/replace with whatever range you want, to get a full buffer replace.

Sounds good?

wavexx commented 10 years ago

On 07/27/2014 08:54 AM, benma wrote:

For a wrap-around query-replace, how about using vr--interactive-get-args to get the arguments, and then call vr/query-replace twice in succession, once with current point to point-max, and then once again from point-min to original point?

Disregarding some details, something like this (where the arguments are obtained beforehand with vr--interactive-get-args):

(let ((current-point (point)))
    (vr/query-replace "regexp" "replace" current-point (point-max))
    (vr/query-replace "regexp" "replace" (point-min) current-point)
  ))

Sounds good. As for query-replace, please return some different value if the replace is aborted, so we can skip the second call if the user wants to stop.

I could patch vr--interactive-get-args to accept arguments to control start and end. Preview feedback while entering the arguments would then be decoupled from where the replacement would actually be performed. This way, you could use it to display preview from (window-start) or (point-min), i.e. the region before point.

Yes, if the preview region is decoupled, it would work nicely.

Sounds good?

I like the proposal :)

nispio commented 8 years ago

Any updates on the status of this issue? Do the new helper functions make this any easier to implement?

adbull commented 3 years ago

Not sure if there are any updates on this, but as a workaround, I've added the following to my .emacs:

(defun vr--use-whole-buffer ()
  (unless (region-active-p) (setq vr--target-buffer-start (point-min))))
(advice-add 'vr--set-target-buffer-start-end :after 'vr--use-whole-buffer)

This will search the whole buffer in vr/replace and vr/query-replace when there's no region selected.