fix: zero-length regex matches (^, $, \b) cause FindNext to silently no-op#88
Conversation
…eNext - SelectSearchMatch now accepts length==0, clears selection anchor, moves caret - FindNext/FindPrevious skip zero-length match at current position (advance by 1) - FindForward/FindBackward allow length==0 search regions - TryMatchSelection detects zero-length match at caret for ReplaceNext - ReplaceNext inserts at position for zero-length matches (vim/sed convention) - Add tests for ^ and \b regex cycling, and ReplaceNext/ReplaceAll with anchors Agent-Logs-Url: https://github.com/gui-cs/Text/sessions/ea950c9c-82cd-447a-8d94-3cacc050e1e9 Co-authored-by: tig <585482+tig@users.noreply.github.com>
|
@copilot resolve the merge conflicts in this pull request |
…ength-regex-no-op # Conflicts: # src/Terminal.Gui.Editor/Editor.FindReplace.cs # tests/Terminal.Gui.Editor.Tests/EditorFindReplaceTests.cs Co-authored-by: tig <585482+tig@users.noreply.github.com>
Merge conflicts resolved in f890272. The conflict was in |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 82f14b7334
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if (match is { Length: 0 } && match.Offset == startOffset) | ||
| { | ||
| match = FindForward (startOffset + 1); | ||
| } |
There was a problem hiding this comment.
Preserve sole zero-length match in FindNext
When FindNext encounters a zero-length match at the current start offset, it always discards it and retries from startOffset + 1. In a document where that current position is the only valid match (for example ^ in a single-line buffer with caret at offset 0), the retry returns null and FindNext returns false even though a valid match exists. This regresses zero-length search by making some real matches unreachable unless another match exists elsewhere.
Useful? React with 👍 / 👎.
|
|
||
| // The caret anchor (AfterInsertion) already moved past the inserted text. | ||
| // Force a refresh of virtual column state. | ||
| SetCaretOffset (insertPos + replacementText.Length, true); |
There was a problem hiding this comment.
Advance past empty zero-length replacements
In the zero-length replacement path, caret advancement is based only on replacementText.Length. If the replacement resolves to an empty string (e.g. replacement is "" or an unmatched backreference), the caret stays at the same offset and the document is unchanged, so repeated ReplaceNext keeps matching the same anchor and returns true indefinitely without progress. This reintroduces a no-op loop for zero-length regex replacements.
Useful? React with 👍 / 👎.
SelectSearchMatchto handle zero-length matches (move caret, clear selection)FindNextto skip zero-length match at current search start (advance by 1)FindPreviousto skip zero-length match at current search startTryMatchSelectionto handle zero-length matches forReplaceNextFindForward/FindBackwardto allow zero-length search regions^pattern lands at 0 → 6 → 12 → wrap → 0\bcycle on"ab cd"lands at 0 → 2 → 3 → 5 → wrap → 0ReplaceNextwith^inserts at position (prepend to each line)ReplaceAllwith^inserts at all line startsReplaceNextfor zero-length matches inserts at position (vim/sed convention)All 434 tests pass (230 Text + 96 Editor + 108 Integration).