Preserve replace string when match has no cased characters - #336815
Lakshya Pandey (pandeylakshya207-max) wants to merge 5 commits into
Conversation
buildReplaceStringWithCasePreserved treated a match unchanged by toUpperCase() as uppercase, so matches made only of punctuation or digits caused the replace string to be uppercased. Return the pattern unchanged when the match contains no cased characters. Fixes microsoft#192168
|
@microsoft-github-policy-service agree |
There was a problem hiding this comment.
🟡 Changes recommended
The segmented-match assertions do not exercise the recursive behavior they intend to cover.
Get a fresh assessment by requesting another Copilot review.
Pull request overview
Fixes preserve-case replacement for matches containing no cased characters.
Changes:
- Returns replacement patterns unchanged for caseless matches.
- Adds regression coverage for punctuation and numeric matches.
File summaries
| File | Description |
|---|---|
src/vs/base/common/search.ts |
Detects caseless matches before transforming replacement case. |
src/vs/editor/contrib/find/test/browser/replacePattern.test.ts |
Adds caseless-match tests. |
Review details
Suppressed comments (1)
src/vs/editor/contrib/find/test/browser/replacePattern.test.ts:262
- This wrapper assertion also ignores the second array item because only
matches[0]drives case preservation, so it duplicates the punctuation case rather than covering separator recursion. Use a mixed cased/caseless segmented match instead.
assertReplace(['(', ')'], 'fontSize: 20', 'fontSize: 20');
- Files reviewed: 2/2 changed files
- Comments generated: 2
- Review effort level: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| assertReplace(['()'], 'fontSize: 20', 'fontSize: 20'); | ||
| assertReplace(['123'], 'Def', 'Def'); | ||
| assertReplace(['!'], 'someValue', 'someValue'); | ||
| assertReplace(['(', ')'], 'fontSize: 20', 'fontSize: 20'); |
| // The match has no cased characters (e.g. punctuation or digits), so there is | ||
| // no case to preserve and the replace pattern is used as-is. |
…ub.com/pandeylakshya207-max/vscode into fix/192168-preserve-case-uncased-match
|
Thanks — both good catches, addressed in fb2a976. The Comment condensed to a single line. All 16 tests in the suite still pass locally. |
Fixes #192168
Problem
With "Preserve Case" enabled, replacing a match that contains no cased
characters uppercases the replace string. Searching for
()and replacingwith
fontSize: 20producesFONTSIZE: 20.buildReplaceStringWithCasePreserveddecides the match is uppercase usingmatches[0].toUpperCase() === matches[0]. Punctuation and digits areunchanged by
toUpperCase(), so that check passes for matches that have nocase at all, and the replace string is uppercased. The same applies to
matches like
123.Fix
Return the replace pattern unchanged when the match contains no cased
characters, detected with
toLowerCase() === toUpperCase(). This is trueonly for strings with no cased characters, so it also covers whitespace and
scripts without case.
The check runs before the hyphen/underscore handling, which recurses into
this function per segment, so caseless segments are left alone too.
Testing
buildReplaceStringWithCasePreserved testandpreserve caseinreplacePattern.test.ts. All 16 tests in the suitepass; the 22 existing assertions are unaffected since every one of them
has a match containing letters.
npm run eslintis clean.()andreplacing with
fontSize: 20with Preserve Case on now yieldsfontSize: 20. Checked thatabc→Defstill givesdef,ABC→Defgives
DEF, andAbc→DefgivesDef.