forked from szermatt/visual-replace
-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathvisual-replace.texi
1205 lines (863 loc) · 38 KB
/
visual-replace.texi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
\input texinfo @c -*-texinfo-*-
@c %**start of header
@setfilename visual-replace.info
@documentencoding UTF-8
@ifinfo
@*Generated by Sphinx.@*
@end ifinfo
@settitle Visual Replace
@defindex ge
@paragraphindent 0
@exampleindent 4
@finalout
@dircategory Emacs
@direntry
* visual-replace: (visual-replace.info). A nicer interface for string-replace and query-replace
that supports previews.
@end direntry
@c %**end of header
@copying
@quotation
Visual-Replace
Stephane Zermatten
Copyright @copyright{} 2020-2024, Stephane Zermatten
@end quotation
@end copying
@titlepage
@title Visual Replace
@insertcopying
@end titlepage
@contents
@c %** start of user preamble
@c %** end of user preamble
@ifnottex
@node Top
@top Visual Replace
@insertcopying
@end ifnottex
@c %**start of body
@anchor{index doc}@anchor{0}
Visual Replace provides a nicer interface to Query-Replace@footnote{https://www.gnu.org/software/emacs/manual/html_node/emacs/Query-Replace.html}
than the built-in one.
The main improvements are:
@quotation
@itemize *
@item
The prompt of Visual Replace includes both the text to be
replaced and the replacement. This makes it easier to craft
possibly complex regular expression search and replace.
@item
You can see the matches and how they’re going to be modified
as you edit the command arguments.
@item
To help craft the search string and its replacement, you
can navigate between matches with the arrow keys and
optionally see the number of matches in the prompt.
@item
You can apply only some replacements, selectively,
using keyboard shortcuts, or by clicking on the preview.
@item
You can modify the scope and type of the search-and-replace
command, to the full buffer, the region or everything after
the point.
@end itemize
@end quotation
Visual Replace is just an interface. The actual replacements are
always done by the standard Emacs commands.
@menu
* Comparison with other packages::
* Contents::
* Index::
@end menu
@node Comparison with other packages,Contents,Top,Top
@anchor{index comparison-with-other-packages}@anchor{1}@anchor{index visual-replace}@anchor{2}
@chapter Comparison with other packages
What seems to be unique about Visual Replace is that the thing to be
replaced and the replacement at the same time are modified at the same
time. The other packages I’ve found make it a 2-step process in most
cases.
visual-regexp@footnote{https://github.com/benma/visual-regexp.el} also
supports a preview, but uses its own search-and-replace mechanism and
only supports a regexp mode.
anzu@footnote{https://github.com/emacsorphanage/anzu} is otherwise very
similar to visual-replace. It was abandoned for a long time, but has
been recently taken up by a new maintainer.
@node Contents,Index,Comparison with other packages,Top
@anchor{index contents}@anchor{3}
@chapter Contents
@menu
* Installation::
* Usage::
* API::
* Contributing::
@end menu
@node Installation,Usage,,Contents
@anchor{install doc}@anchor{4}@anchor{install installation}@anchor{5}
@section Installation
Install Visual Replace:
@itemize -
@item
from MELPA or MELPA Stable@footnote{https://melpa.org/#/getting-started} using @code{M-x package-install visual-replace}
@item
on a recent version of Emacs (29 or later), from the
github repository by doing @code{M-x package-vc-install
https://github.com/szermatt/visual-replace}
@item
from source, using an alternative package managers, such as straight@footnote{https://github.com/radian-software/straight.el}, shown here:
@example
(use-package visual-replace
:straight (:type git :repo "https://github.com/szermatt/visual-replace.git"))
@end example
@item
the old-fashioned way, copying visual-replace.el@footnote{https://raw.githubusercontent.com/szermatt/visual-replace/refs/heads/master/visual-replace.el}
into your @code{.emacs.d} directory.
@end itemize
Visual Replace requires Emacs 26.1 or later.
@node Usage,API,Installation,Contents
@anchor{usage doc}@anchor{6}@anchor{usage usage}@anchor{7}
@section Usage
@menu
* Calling Visual Replace::
* Visual Replace Mode::
* Yank and Pop::
* Single replacements::
* Customization::
* Face Customization::
* Commands::
* Keymaps::
* Hooks::
* Limitations::
@end menu
@node Calling Visual Replace,Visual Replace Mode,,Usage
@anchor{usage calling-visual-replace}@anchor{8}
@subsection Calling Visual Replace
Visual Replace needs to be bound to a key to be of any use.
Choose a reasonably short key combination and bind
@code{visual-replace} to it. It should be reasonably short, because
@code{visual-replace}, by default, uses the key combination it’s
called with as prefix for the commands available in the minibuffer.
Here’s an example that uses @code{M-%} as key combination, since this
is bound by default to @code{query-replace}, which Visual Replace
then, well, replaces:
@example
(use-package visual-replace
:defer t
:bind (("M-%" . visual-replace)
:map isearch-mode-map
("M-%" . visual-replace-from-isearch))
:config
(define-key visual-replace-mode-map (kbd "M-%")
visual-replace-secondary-mode-map))
@end example
The above example also binds @code{M-%} in isearch, so you can just
switch from isearch to Visual Replace. Additionally, while Visual
Replace is active @code{M-%} is the prefix for Visual Replace
commands, so, for example, toggling regexp mode on and off is
@code{M-% r}.
An alternative, which you might prefer to try things out, is to
replace @code{query-replace} and others with Visual Replace. This
then uses whatever shortcut you’ve already installed.
@example
(use-package visual-replace
:defer nil
:config
(visual-replace-global-mode 1))
@end example
Once this is done, launch @code{visual-replace} with the keybinding you chose.
@node Visual Replace Mode,Yank and Pop,Calling Visual Replace,Usage
@anchor{usage visual-replace-mode}@anchor{9}
@subsection Visual Replace Mode
When Visual Replace is running, you’ll see, something like the
following in the minibuffer @cite{Replace from point […]: ┃ →}. The text
before the arrow is the text to replace and the text after the arrow
is the replacement. You can navigate back and forth with @code{TAB} or
by moving the cursor.
See also the example below.
@quotation
@image{visual-replace-figures/cast,,,Screen grab showing Visual Replace in action,gif}
@end quotation
Once both fields are filled, press @code{RET} to execute the
replacement.
When there’s no replacement @code{RET} instead moves the cursor to the
replacement, in case muscle memory kicks in and you type: `text to
replace' @code{RET} `replacement' @code{RET}. That’ll work.
The prompt also displays the mode of replacement:
@itemize *
@item
`text' → `replacement' executes @cite{string-replace}
@item
`text' →? `replacement' executes @cite{query-replace}
@item
`text' →.* `replacement' executes @cite{replace-regexp}
@item
`text' →?.* `replacement' executes @cite{query-replace-regexp}
@end itemize
After typing a few characters of the string to match @cite{visual-replace}
enters preview mode, and highlights the matches. It also scrolls the
window to keep at least one example of matches visible. You can also
press up and down to go through the matches.
In Visual Replace mode:
@itemize *
@item
@code{TAB} navigates between the text to replace and the
replacement string
@item
@code{RET} switches to the replacement string, the first time, then
executes the replacement
@item
@code{M-% r} toggles regexp mode on and off. You know this mode is
on when a @code{.*} follows the arrow.
@item
@code{M-% q} toggles query mode one and off, that is, it toggles
between calling @code{replace-string} and @code{query-replace}.
You know this mode is on when a @code{?} follows the arrow. For an
alternative way of replacing only some matches, see @ref{a,,Single replacements}.
@item
@code{M-% SPC} switches between different scopes: full buffer, from
point, in region. The scope is indicated in the prompt.
Additionally, for from point and in region, the region is
highlighted.
@item
@code{M-% w} toggle limiting search to whole words. You know this
mode is on when a @code{w} follows the arrow.
@item
@code{M-% c} toggle case-fold. You know this mode is on when a
@code{c} follows the arrow.
@item
@code{M-% s} toggle lax whitespace. You know this mode is on when
@code{(lax ws)} follows the arrow.
@item
@code{<up>} and @code{<down>} move the cursor to the next or
previous match, scrolling if necessary.
@item
@code{M-% a} applies a single replacement, to the match right under
the cursor or following the cursor, then move on to the next match.
With a prefix argument N, apply N replacements. See also @ref{a,,Single replacements}.
@item
@code{M-% u} calls @code{undo} on the original buffer, to revert a
previous replacement. With a prefix argument N, repeat undo N times.
@item
As usual, @code{C-p} and @cite{C-n} go up and down the history, like on any prompt.
@end itemize
(Reminder: replace `M-%' with the keyboard shortcut you chose.)
If you leave @code{visual-replace} without confirming, with @code{C-g}, you can
continue where you left off next time by going up in the history.
See Search@footnote{https://www.gnu.org/software/emacs/manual/html_node/emacs/Search.html}
in the Emacs manual for details of the different modes listed above.
@node Yank and Pop,Single replacements,Visual Replace Mode,Usage
@anchor{usage yank}@anchor{b}@anchor{usage yank-and-pop}@anchor{c}
@subsection Yank and Pop
@geindex function; visual-replace-yank
@geindex function; visual-replace-yank-pop
Yank, usually bound to @code{C-y}, works differently in Visual Replace
than it does normally. In Visual Replace mode, it calls
@code{visual-replace-yank}.
@itemize *
@item
In the search section, yanking copies text from the current buffer
into the search section. This avoids typing text when it’s right
under the point.
You can also move to a match with @code{<up>} and @code{<down>} to
capture more text from the buffer.
@item
In the replacement section, yanking copies text from the search
section. This avoids typing the search string again when you just
want to make some small changes to it.
@end itemize
The normal yank can be executed by calling @code{yank-pop}, usually
bound to @code{M-y}.
This can be configured by editing @cite{visual-mode-map}. For example, to
use the normal yank commands, you can do:
@example
(define-key visual-replace-mode-map [remap yank] nil)
(define-key visual-replace-mode-map [remap yank-pop] nil)
@end example
@node Single replacements,Customization,Yank and Pop,Usage
@anchor{usage single}@anchor{a}@anchor{usage single-replacements}@anchor{d}
@subsection Single replacements
If you want to replace only `some' matches within the scope, you can:
@itemize *
@item
use the @code{query-replace} UI to go through all matches using
@code{M-% q}, then typing @code{RET} to enter Query Replace mode. `
@item
in preview mode, click on the replacements you want to apply. You
can scroll the buffer as needed, normally or, from the minibuffer
with @code{<up>} and @code{<down>}.
@item
navigate to the replacements you want to apply with @code{<up>} and
@code{<down>}, the call @code{M-% a} to apply one replacement.
On Emacs 29.1 or later, this enters a mode that allows applying
replacement with @code{a}, the last part of the key sequence, and
also moving through the matches with @code{<down>} or @code{<up>}.
@code{u} reverts the last replacement.
@end itemize
@node Customization,Face Customization,Single replacements,Usage
@anchor{usage customization}@anchor{e}@anchor{usage options}@anchor{f}
@subsection Customization
@geindex variable; visual-replace-keep-initial-position
@geindex variable; visual-replace-display-total
@geindex variable; visual-replace-preview
@geindex variable; visual-replace-first-match
@geindex variable; visual-replace-initial-scope
@geindex variable; visual-replace-default-to-full-scope
@geindex variable; visual-replace-defaults-hook
@geindex variable; visual-replace-minibuffer-mode-hook
@geindex variable; visual-replace-min-length
This section lists a few of the most interesting customization options
available in visual replace. Call @code{M-x customize-group
visual-replace} to see all options. For face customization, see the
:ref`next section<faces>`.
@table @asis
@item visual-replace-preview : customization option
With this option enabled, Visual Replace highlights matches and
offer a preview of their replacements. This is enabled by default.
@item visual-replace-first-match : customization option
With this option enabled, Visual Replace always tries to have at
least one match visible in the preview, even if it means jumping to
another section of the buffer. This is enabled by default.
@item keep-initial-position : customization option
With this option enabled, Visual Replace goes back to the point it
was called from, even if the point was moved during preview, to
display the first match, or manually with @code{<down>} or
@code{<up>}.
Note that in the case where the point is moved during preview,
Visual Replace sets a mark at the original location, to go back too
if necessary.
@item visual-replace-display-total : customization option
By default, in preview mode, visual Replace only searches for and
display matches in the visible portions of the buffer. With this
option enabled, Visual Replace searches the whole buffer, in an idle
timer, and displays the total number of matches in the prompt.
When the point is on a match, the index of the match is also
displayed, in front of the total.
The total might be slow to update on large buffers or when using
complicated regexps.
This is not enabled by default.
@item visual-replace-initial-scope : customization option
With this option set, the initial scope ignores the active region
entirely and is always set to either “From Point” or “Full Buffer”.
By default, the initial scope is:
@quotation
@itemize *
@item
the active region, if there is one
@item
from point if @code{visual-replace-default-to-full-scope} is nil, see below
@item
the full buffer otherwise
@end itemize
@end quotation
@item visual-replace-default-full-scope : customization option
With this option set, when no region is active, replacement applies
by default to the full buffer, instead of to the region following
the point.
@item visual-replace-defaults-hook : customization option
To modify search and replace defaults, such as, for example, having
searches default to regular expressions or search default to word
mode, call the command that turns it on from this hook. This is
called when Visual Replace is started with no initial text, so these
customizations won’t apply to @code{visual-replace-from-isearch},
for example.
@item visual-replace-minibuffer-mode-hook : customization option
This hook is called when Visual Replace is started in the
minibuffer. It can be used to turn on query mode in all cases by
registering the command @code{visual-replace-toggle-query} in this
hook.
Rather than setting the as a customization, with
@code{use-package}, you can force Visual Replace to call
@code{query-replace} by default with:
@example
(use-package visual-replace
[...]
:hook ((visual-replace-minibuffer-mode . visual-replace-toggle-query))
@end example
@item visual-replace-min-length : customization option
This specifies the minimum number of characters that need to be
typed before Visual Replace enters preview mode.
Setting this too low might result in strange highlights happening
when starting to type in the match string.
@end table
@node Face Customization,Commands,Customization,Usage
@anchor{usage face-customization}@anchor{10}@anchor{usage faces}@anchor{11}
@subsection Face Customization
@geindex variable; visual-replace-delete-match
@geindex variable; visual-replace-delete-match-highlight
@geindex variable; visual-replace-match
@geindex variable; visual-replace-match-count
@geindex variable; visual-replace-match-highlight
@geindex variable; visual-replace-region
@geindex variable; visual-replace-replacement
@geindex variable; visual-replace-replacement-highlight
@geindex variable; visual-replace-separator
Visual Replace relies an a large number of faces to display things the way they should be:
@quotation
@itemize *
@item
@code{visual-replace-match}, for matches with no replacement
@item
@code{visual-replace-match-highlight}, for matches at point with no replacement
@item
@code{visual-replace-replacement}, for match replacement
@item
@code{visual-replace-replacement-highlight}, for match replacement, at point
@item
@code{visual-replace-delete-match}, for text to be deleted
@item
@code{visual-replace-delete-match-highlight}, for text to be
deleted at point
@item
@code{visual-replace-match-count}, for displaying the number of
matches before the prompt
@item
@code{visual-replace-separator}, for displaying the separator
between the search and replacement strings in the prompt
@item
@code{visual-replace-region}, for highlighting the area of the
buffer to which search and replace apply
@end itemize
@end quotation
The defaults values for this faces attempt to reuse existing faces as
much as possible to try and look reasonable whatever the current Emacs
theme, but the result isn’t always too great. In particular,
@code{visual-replace-region}, which uses the same face as the region,
is typically too bright and in-your-face. It should ideally use a
fainter color than the region, still visible, but not too different
from the normal background as to cause readability issues.
Therefore, it’s a good idea to configure the Visual Replace faces to
match your theme and preferences.
The sections below list my attempts at configuring Visual Replace for
the Modus themes@footnote{https://protesilaos.com/emacs/modus-themes}, now
installed in Emacs by default, and the Ef themes@footnote{https://protesilaos.com/emacs/ef-themes}, by the same author. This
should hopefully help you get started.
The code snippets rely on @code{after-enable-theme-hook} to detect
theme changes, from the Section 5.23 of the Emacs 29 Manual@footnote{https://www.gnu.org/software/emacs/manual/html_node/modus-themes/A-theme_002dagnostic-hook-for-theme-loading.html}:
@example
(defun run-after-enable-theme-hook (&rest _args)
"Run `after-enable-theme-hook'."
(run-hooks 'after-enable-theme-hook))
(advice-add 'enable-theme :after #'run-after-enable-theme-hook)
@end example
@menu
* Modus Themes::
* Ef Themes::
@end menu
@node Modus Themes,Ef Themes,,Face Customization
@anchor{usage id1}@anchor{12}
@subsubsection Modus Themes
@example
(defun my-modus-themes-custom-faces ()
(when (delq nil (mapcar (lambda (t) (string-prefix-p "modus-" (symbol-name t)))
custom-enabled-themes))
(modus-themes-with-colors
(custom-set-faces
`(visual-replace-match-count ((t :inherit modus-themes-prompts)))
`(visual-replace-separator ((t :inherit modus-themes-prompts)))
`(visual-replace-match ((t :inherit modus-themes-search-success-lazy)))
`(visual-replace-replacement ((t :background ,bg-diff-added :foreground ,fg-diff-added)))
`(visual-replace-delete-match ((t :strike-through t :background ,bg-diff-removed :foreground ,fg-diff-removed)))
`(visual-replace-match-highlight ((t :inherit modus-themes-search-success)))
`(visual-replace-delete-match-highlight ((t :strike-through t :background ,bg-diff-refine-removed :foreground ,fg-diff-refine-removed)))
`(visual-replace-replacement-highlight ((t :background ,bg-diff-refine-added :foreground ,fg-diff-refine-added)))
`(visual-replace-region ((t :background ,bg-special-faint-cold :extend t )))))))
(add-hook 'after-enable-theme-hook #'my-modus-themes-custom-faces)
@end example
@node Ef Themes,,Modus Themes,Face Customization
@anchor{usage id2}@anchor{13}
@subsubsection Ef Themes
@example
(defun my-ef-themes-custom-faces ()
(when (delq nil (mapcar (lambda (t) (string-prefix-p "ef-" (symbol-name t)))
custom-enabled-themes))
(ef-themes-with-colors
(let ((bg-region-fainter (my-color-closer bg-region bg-main 0.3)))
(custom-set-faces
`(visual-replace-match-count ((,c :foreground ,prompt)))
`(visual-replace-separator ((,c :foreground ,prompt)))
`(visual-replace-match ((,c :background ,bg-search-lazy :foreground ,fg-intense)))
`(visual-replace-replacement ((,c :background ,bg-added :foreground ,fg-added)))
`(visual-replace-delete-match ((,c :strike-through t :background ,bg-removed-faint :foreground ,fg-removed)))
`(visual-replace-match-highlight ((,c :background ,bg-search-match :foreground ,fg-intense )))
`(visual-replace-delete-match-highlight ((,c :strike-through t :background ,bg-removed-refine :foreground ,fg-intense)))
`(visual-replace-replacement-highlight ((,c :background ,bg-added-refine :foreground ,fg-intense)))
`(visual-replace-region ((,c :background ,bg-region-fainter :extend t ))))))))
(defun my-color-closer (from to fraction)
"Move FROM luminance closer to TO by the given FRACTION."
(let* ((from-hsl (apply 'color-rgb-to-hsl (color-name-to-rgb from)))
(to-hsl (apply 'color-rgb-to-hsl (color-name-to-rgb to))))
(apply 'color-rgb-to-hex
(color-hsl-to-rgb
(nth 0 from-hsl)
(nth 1 from-hsl)
(+ (nth 2 from-hsl) (* fraction (- (nth 2 to-hsl) (nth 2 from-hsl))))))))
(add-hook 'after-enable-theme-hook #'my-ef-themes-custom-faces)
@end example
@node Commands,Keymaps,Face Customization,Usage
@anchor{usage commands}@anchor{14}@anchor{usage id3}@anchor{15}
@subsection Commands
@geindex command; visual-replace
@geindex command; visual-replace-thing-at-point
@geindex command; visual-replace-selected
@geindex command; visual-replace-from-isearch
@table @asis
@item visual-replace : command
This is the main command that starts Visual Replace and then
executes the search-and-replace. It can replace
@code{replace-string}, @code{query-replace},
@code{replace-regexp} and @code{query-replace-regexp}.
@item visual-replace-thing-at-point : command
This command starts a visual replace session with the symbol at
point as text to replace.
@item visual-replace-selected : command
This command starts with the text within the current active region
as text to replace.
@item visual-replace-from-isearch : command
This command switches from an active isearch session to
@code{visual-replace}, keeping the current search text and
settings, such as regexp mode. This is meant to be called while
isearch is in progress, and bound to @code{isearch-mode-map}.
@end table
@geindex command; visual-replace-toggle-regexp
@geindex command; visual-replace-toggle-scope
@geindex command; visual-replace-toggle-query
@geindex command; visual-replace-toggle-word
@geindex command; visual-replace-toggle-case-fold
@geindex command; visual-replace-toggle-lax-ws
@geindex command; visual-replace-next-match
@geindex command; visual-replace-prev-match
@geindex command; visual-replace-apply-one
@geindex command; visual-replace-apply-one-repeat
@geindex command; visual-replace-undo
@geindex variable; visual-replace-transient-map
The following commands are meant to be called while in Visual Replace
mode, from @code{visual-mode-map}. By default, they’re bound in
@code{visual-replace-secondary-mode-map}:
@table @asis
@item visual-replace-toggle-regexp : <prefix> r , command
toggles regexp mode on and off.
@item visual-replace-toggle-scope : <prefix> SPC, command
changes the scope of the search.
@item visual-replace-toggle-query : <prefix> q, command
toggles the query mode on and off.
@item visual-replace-toggle-word : <prefix> w, command
toggles the word mode on and off.
@item visual-replace-toggle-case-fold : <prefix> c, command
toggles the case fold mode on and off.
@item visual-replace-toggle-lax-ws : <prefix> s, command
toggles the lax whitespace mode on and off.
@item visual-replace-next-match : <down>, command
moves cursor to the next match
@item visual-replace-prev-match : <up>, command
moves cursor to the previous match
@item visual-replace-apply-one : <prefix> a, command
applies a single replacement, to the match at or after the
cursor, then moves on to the next match. With a prefix argument
N, apply N replacements instead of just one.
This command, used together with @code{visual-replace-next-match}
and @code{visual-replace-prev-match} is in many cases functionally
equivalent to using the query mode, but with a different interface
that the possibility of changing the query as you go.
@item visual-replace-apply-one-repeat : <prefix> a, command
on Emacs 29.1 and later, executes @code{visual-replace-apply-one},
then installs a transient map that allows:
@itemize *
@item
repeating @code{visual-replace-apply-one} by typing the last part
of the key sequence used to call @code{visual-replace-apply-one-repeat}
@item
skipping matches with @code{<down>}, which calls @code{visual-replace-next-match}
@item
going up the match previews with @code{<up>}, which calls @code{visual-replace-prev-match}
@item
undoing the last replacement with @code{u}
@item
Typing anything else deactivates the transient map.
@end itemize
The keybindings can be configured by modifying the map @code{visual-replace-transient-map}.
@item visual-replace-undo : <prefix> u, command
reverts the last call to @code{visual-replace-apply-one}. This just
executes @code{undo} in the original buffer. With a prefix argument N,
call undo N times instead of just one.
@end table
@node Keymaps,Hooks,Commands,Usage
@anchor{usage keymaps}@anchor{16}
@subsection Keymaps
@geindex variable; visual-replace-mode-map
@geindex variable; visual-replace-secondary-mode-map
@table @asis
@item visual-replace-mode-map : keymap
This is the map that is active in the minibuffer in Visual Replace
mode. You can add your own keybindings to it.
@item visual-replace-secondary-mode-map : keymap
This is the map that defines keyboard shortcuts for modifying the
search mode, such as @code{r} to toggle regexp mode on or off. It is
bound by default in @code{visual-replace-mode-map} to the shortcut that
was used to launch Visual Replace, but you can bind it to whatever
you want, or define custom shortcuts directly in
@code{visual-replace-mode-map}.
@end table
In the example below, @code{C-l} is bound to secondary mode map and
@code{C-r} toggles the regexp mode, so it is possible to toggle the
regexp mode using either @code{C-l r} or @code{C-r}.
@example
(use-package visual-replace
:defer t
:bind (("C-c l" . visual-replace)
:map visual-replace-mode-map
("C-r" . visual-replace-toggle-regexp))
:config
(define-key visual-replace-mode-map (kbd "C-l")
visual-replace-secondary-mode-map))
@end example
@node Hooks,Limitations,Keymaps,Usage
@anchor{usage hooks}@anchor{17}
@subsection Hooks
@geindex hook; visual-replace-minibuffer-mode-hook
@geindex hook; visual-replace-functions
@geindex variable; visual-replace-defaults-hook
@table @asis
@item visual-replace-minibuffer-mode-hook : hook
This is a normal hook that is run when entering the visual replace
mode, so you can set things up just before Visual Replace starts.
@item visual-replace-defaults-hook : hook
This is a normal hook that is run when entering the visual replace
mode with no initial match or replacement, so you can provide some
default mode without interfering with
@code{visual-replace-from-isearch} or
@code{visual-replace-thing-at-point}.
@item visual-replace-functions : hook
Functions in this abnormal hook are called just before executing the
replacement or just before building the previews. They are passed a
struct of type @code{visual-replace-args}, which they can modify. You
can use it to customize the behavior of the search or modify the
regexp language.
@end table
@node Limitations,,Hooks,Usage
@anchor{usage limitations}@anchor{18}
@subsection Limitations
@itemize *
@item
Visual Replace avoids executing replacement in the whole buffer
during preview; it just executes them in the parts of the buffer
that are currently visible. This means that the preview can show
incorrect replacement in some cases, such as when replacement uses
@cite{\#} directly or within a @cite{\@comma{}} In such cases, the preview can be
wrong but execution will be correct.
Replacements that call stateful functions in @cite{\@comma{}} such as a
function that increment an internal counter, will be executed too
many times during preview, with unpredictable results.
In all other cases, the preview should match what is eventually
executed. If that’s not the case, please report an issue.
(@ref{19,,Reporting issues})
@item
If you use @code{visual-replace-apply-one} to replace single
matches, @code{\\#} in the replacement is always 1, because single
matches are applied separately.
@end itemize
@node API,Contributing,Usage,Contents
@anchor{api doc}@anchor{1a}@anchor{api api}@anchor{1b}
@section API
@geindex function; visual-replace-read
@geindex function; visual-replace-make-args
@geindex function; visual-replace-make-scope
This package provides several different ways of triggering Visual
Replace, from different initial states. For example,
@code{visual-replace} uses the region to restrict the search, while
@code{visual-replace-selection} uses the region text as match string.
Another example is @code{visual-replace-from-isearch}, which copies the
state of a running search.
@subsubheading Public Functions
Public functions are functions without any double dash in their
name. New version of Visual Replace attempt to keep any code calling
public functions backward-compatible, while private function can
change, be renamed, behave differently or disappear from version to
version.
Many more variations are possible. You could imagine a variant of
Visual Replace that uses the current region as match string unless it
contains more tan one line, in which case it’d use it to restrict
search.
In an attempt to support such variations, Visual Replace includes some
public functions you’re encouraged to use to build your own variation.
To add a variation as the one described above, you could write the
following, which modifies the default behavior in one specific case by
overriding the search arguments and scope :
@example
(defun my-visual-replace ()
(interactive)
(let (args scope)
(when (and (region-active-p)
(let ((beg (region-beginning))
(end (region-end)))
(save-excursion
(goto-char beg)
(not (search-forward "\n" end 'noerror)))))
(setq args (visual-replace-make-args
:from (buffer-substring-no-properties
(region-beginning) (region-end))
:to ""))
(setq scope (visual-replace-make-scope
;; Don't use bounds from the region
:bounds nil)))
(apply #'visual-replace
(visual-replace-read args scope))))
@end example
@table @asis
@item (visual-replace-read ARGS SCOPE RUN-HOOK) : function
Build arguments for running @cite{visual-replace} and return
them as a list, containing search range and modified @code{visual-replace-args}.
To call @code{visual-replace} directly after @code{visual-replace-read}, use @code{apply}:
@code{(apply #'visual-replace (visual-replace-args args scope))}
This function takes two optional arguments, ARGS, created with
@code{visual-replace-make-args}, and SCOPE, created with
@code{visual-replace-make-scope}. If an argument is unspecified or
nil, the default behavior applies.
If both ARGS and SCOPE are nil, @code{visual-replace-read} calls
@code{visual-replace-defaults-hook} allow configuring the search
using hooks unless RUN-HOOK is non-nil.
@item (visual-replace-make-args KEY-ARGS) : function
This function builds a struct of type @cite{visual-replace-args}. It can take
the following key arguments: