command: Fix replace to be able to insert '$' (#2954)

* command: Fix replace to be able to insert '$'

* help: commands: Precise the documentation of `replace`

* help: commands: Further improvement suggested within the review

Co-authored-by: Beni Cherniavsky-Paskin <cben@redhat.com>

* Fix replace with '$' in a more kosher way

On top of JoeKar's fix.

---------

Co-authored-by: Beni Cherniavsky-Paskin <cben@redhat.com>
Co-authored-by: Dmytro Maluka <dmitrymaluka@gmail.com>
This commit is contained in:
Jöran Karl 2024-03-17 21:37:16 +01:00 committed by GitHub
parent 5ae2799b70
commit c64add289b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 16 additions and 6 deletions

View File

@ -820,7 +820,7 @@ func (h *BufPane) ReplaceCmd(args []string) {
end = h.Cursor.CurSelection[1] end = h.Cursor.CurSelection[1]
} }
if all { if all {
nreplaced, _ = h.Buf.ReplaceRegex(start, end, regex, replace) nreplaced, _ = h.Buf.ReplaceRegex(start, end, regex, replace, !noRegex)
} else { } else {
inRange := func(l buffer.Loc) bool { inRange := func(l buffer.Loc) bool {
return l.GreaterEqual(start) && l.LessEqual(end) return l.GreaterEqual(start) && l.LessEqual(end)
@ -850,7 +850,7 @@ func (h *BufPane) ReplaceCmd(args []string) {
InfoBar.YNPrompt("Perform replacement (y,n,esc)", func(yes, canceled bool) { InfoBar.YNPrompt("Perform replacement (y,n,esc)", func(yes, canceled bool) {
if !canceled && yes { if !canceled && yes {
_, nrunes := h.Buf.ReplaceRegex(locs[0], locs[1], regex, replace) _, nrunes := h.Buf.ReplaceRegex(locs[0], locs[1], regex, replace, !noRegex)
searchLoc = locs[0] searchLoc = locs[0]
searchLoc.X += nrunes + locs[0].Diff(locs[1], h.Buf) searchLoc.X += nrunes + locs[0].Diff(locs[1], h.Buf)

View File

@ -148,7 +148,7 @@ func (b *Buffer) FindNext(s string, start, end, from Loc, down bool, useRegex bo
// ReplaceRegex replaces all occurrences of 'search' with 'replace' in the given area // ReplaceRegex replaces all occurrences of 'search' with 'replace' in the given area
// and returns the number of replacements made and the number of runes // and returns the number of replacements made and the number of runes
// added or removed on the last line of the range // added or removed on the last line of the range
func (b *Buffer) ReplaceRegex(start, end Loc, search *regexp.Regexp, replace []byte) (int, int) { func (b *Buffer) ReplaceRegex(start, end Loc, search *regexp.Regexp, replace []byte, captureGroups bool) (int, int) {
if start.GreaterThan(end) { if start.GreaterThan(end) {
start, end = end, start start, end = end, start
} }
@ -172,9 +172,13 @@ func (b *Buffer) ReplaceRegex(start, end Loc, search *regexp.Regexp, replace []b
l = util.SliceStart(l, end.X) l = util.SliceStart(l, end.X)
} }
newText := search.ReplaceAllFunc(l, func(in []byte) []byte { newText := search.ReplaceAllFunc(l, func(in []byte) []byte {
result := []byte{} var result []byte
for _, submatches := range search.FindAllSubmatchIndex(in, -1) { if captureGroups {
result = search.Expand(result, replace, in, submatches) for _, submatches := range search.FindAllSubmatchIndex(in, -1) {
result = search.Expand(result, replace, in, submatches)
}
} else {
result = replace
} }
found++ found++
if i == end.Y { if i == end.Y {

View File

@ -43,6 +43,12 @@ quotes here but these are not necessary when entering the command in micro.
Note that `search` must be a valid regex (unless `-l` is passed). If one Note that `search` must be a valid regex (unless `-l` is passed). If one
of the arguments does not have any spaces in it, you may omit the quotes. of the arguments does not have any spaces in it, you may omit the quotes.
In case the search is done non-literal (without `-l`), the 'value'
is interpreted as a template:
* `$3` or `${3}` substitutes the submatch of the 3rd (capturing group)
* `$foo` or `${foo}` substitutes the submatch of the (?P<foo>named group)
* You have to write `$$` to substitute a literal dollar.
* `replaceall 'search' 'value'`: this will replace all occurrences of `search` * `replaceall 'search' 'value'`: this will replace all occurrences of `search`
with `value` without user confirmation. with `value` without user confirmation.