From 38f88ade600eceab6f6658002bb055bf0e4ef2da Mon Sep 17 00:00:00 2001 From: Zachary Yedidia Date: Thu, 13 Feb 2020 19:48:48 -0500 Subject: [PATCH] Search and replace within a selection Closes #1098 --- internal/action/command.go | 26 ++++++++++++-------------- internal/buffer/loc.go | 9 ++++++--- internal/buffer/search.go | 14 +++++++++----- internal/display/bufwindow.go | 7 +++---- 4 files changed, 30 insertions(+), 26 deletions(-) diff --git a/internal/action/command.go b/internal/action/command.go index 2d9b2fbb..64d0aab8 100644 --- a/internal/action/command.go +++ b/internal/action/command.go @@ -732,23 +732,22 @@ func (h *BufPane) ReplaceCmd(args []string) { nreplaced := 0 start := h.Buf.Start() - // end := h.Buf.End() - // if h.Cursor.HasSelection() { - // start = h.Cursor.CurSelection[0] - // end = h.Cursor.CurSelection[1] - // } + end := h.Buf.End() + if h.Cursor.HasSelection() { + start = h.Cursor.CurSelection[0] + end = h.Cursor.CurSelection[1] + } if all { - nreplaced = h.Buf.ReplaceRegex(start, h.Buf.End(), regex, replace) + nreplaced, _ = h.Buf.ReplaceRegex(start, end, regex, replace) } else { inRange := func(l buffer.Loc) bool { - return l.GreaterEqual(start) && l.LessEqual(h.Buf.End()) + return l.GreaterEqual(start) && l.LessEqual(end) } searchLoc := start - searching := true var doReplacement func() doReplacement = func() { - locs, found, err := h.Buf.FindNext(search, start, h.Buf.End(), searchLoc, true, !noRegex) + locs, found, err := h.Buf.FindNext(search, start, end, searchLoc, true, !noRegex) if err != nil { InfoBar.Error(err) return @@ -764,10 +763,11 @@ func (h *BufPane) ReplaceCmd(args []string) { InfoBar.YNPrompt("Perform replacement (y,n,esc)", func(yes, canceled bool) { if !canceled && yes { - h.Buf.ReplaceRegex(locs[0], locs[1], regex, replace) + _, nrunes := h.Buf.ReplaceRegex(locs[0], locs[1], regex, replace) searchLoc = locs[0] - searchLoc.X += utf8.RuneCount(replace) + searchLoc.X += nrunes + locs[0].Diff(locs[1], h.Buf) + end.Move(nrunes, h.Buf) h.Cursor.Loc = searchLoc nreplaced++ } else if !canceled && !yes { @@ -778,9 +778,7 @@ func (h *BufPane) ReplaceCmd(args []string) { h.Buf.RelocateCursors() return } - if searching { - doReplacement() - } + doReplacement() }) } doReplacement() diff --git a/internal/buffer/loc.go b/internal/buffer/loc.go index 5687f977..16a62f9b 100644 --- a/internal/buffer/loc.go +++ b/internal/buffer/loc.go @@ -102,7 +102,7 @@ func (l Loc) left(buf *LineArray) Loc { return res } -// Move moves the cursor n characters to the left or right +// MoveLA moves the cursor n characters to the left or right // It moves the cursor left if n is negative func (l Loc) MoveLA(n int, buf *LineArray) Loc { if n > 0 { @@ -117,9 +117,12 @@ func (l Loc) MoveLA(n int, buf *LineArray) Loc { return l } -func (l Loc) Diff(a, b Loc, buf *Buffer) int { - return DiffLA(a, b, buf.LineArray) +// Diff returns the difference between two locs +func (l Loc) Diff(b Loc, buf *Buffer) int { + return DiffLA(l, b, buf.LineArray) } + +// Move moves a loc n characters func (l Loc) Move(n int, buf *Buffer) Loc { return l.MoveLA(n, buf.LineArray) } diff --git a/internal/buffer/search.go b/internal/buffer/search.go index 64bcc48c..d537347a 100644 --- a/internal/buffer/search.go +++ b/internal/buffer/search.go @@ -120,24 +120,27 @@ func (b *Buffer) FindNext(s string, start, end, from Loc, down bool, useRegex bo if down { l, found = b.findDown(r, from, end) if !found { - l, found = b.findDown(r, start, from) + l, found = b.findDown(r, start, end) } } else { l, found = b.findUp(r, from, start) if !found { - l, found = b.findUp(r, end, from) + l, found = b.findUp(r, end, start) } } return l, found, nil } // ReplaceRegex replaces all occurrences of 'search' with 'replace' in the given area -// and returns the number of replacements made -func (b *Buffer) ReplaceRegex(start, end Loc, search *regexp.Regexp, replace []byte) int { +// and returns the number of replacements made and the number of runes +// added or removed +func (b *Buffer) ReplaceRegex(start, end Loc, search *regexp.Regexp, replace []byte) (int, int) { if start.GreaterThan(end) { start, end = end, start } + netrunes := 0 + found := 0 var deltas []Delta for i := start.Y; i <= end.Y; i++ { @@ -160,6 +163,7 @@ func (b *Buffer) ReplaceRegex(start, end Loc, search *regexp.Regexp, replace []b result = search.Expand(result, replace, in, submatches) } found++ + netrunes += utf8.RuneCount(in) - utf8.RuneCount(result) return result }) @@ -170,5 +174,5 @@ func (b *Buffer) ReplaceRegex(start, end Loc, search *regexp.Regexp, replace []b } b.MultipleReplace(deltas) - return found + return found, netrunes } diff --git a/internal/display/bufwindow.go b/internal/display/bufwindow.go index fb52728a..42fd489c 100644 --- a/internal/display/bufwindow.go +++ b/internal/display/bufwindow.go @@ -638,13 +638,12 @@ func (w *BufWindow) displayBuffer() { break } vloc.X = 0 - if b.Settings["diffgutter"].(bool) { - w.drawDiffGutter(lineNumStyle, true, &vloc, &bloc) - } - if hasMessage { w.drawGutter(&vloc, &bloc) } + if b.Settings["diffgutter"].(bool) { + w.drawDiffGutter(lineNumStyle, true, &vloc, &bloc) + } // This will draw an empty line number because the current line is wrapped if b.Settings["ruler"].(bool) {