microsoft / microsoft/vscode

Search: case modifiers fail on empty or short regex captures

Open
#334,697 0 comments 0 reactions 1 assignee Claimed by @osortega View on GitHub
Dominant language
TypeScript
Stars
193k
Forks
42.4k
PR merge metrics
PR metrics pending

Description

Search view case modifiers mishandle empty or short numbered capture groups. The equivalent replacement in the editor's find widget works correctly.

- VS Code version: 1.136.1
- OS: macOS 27.0, arm64
- Also reproduced directly against the core search replacement implementation at current `main`, `fc0a9e94576224c89cc08d390b38ab760a261f1f`.

Extension isolation: reproduced in core replacement tests without loading extensions. The installed-app UI reproduction below was with extensions enabled; a separate UI run with all extensions disabled has not been verified.

### Reproduction: optional capture

1. Open a folder containing a saved text file with these lines:

```text
user_name
name
id
```

2. Open **Replace in Files** in the Search view (not the editor's single-file find widget).
3. Enable **Use Regular Expression**. Leave **Preserve Case** off.
4. Search for `^(?:([a-z]+)_)?([a-z]+)$`.
5. Replace with `\u$1\u$2`.
6. Inspect the replacement preview, then run Replace All.

Expected saved contents:

```text
UserName
Name
Id
```

Actual preview and saved contents:

```text
UserName
\uName
\uId
```

The first group exists but does not participate in the matches for `name` and `id`; its case modifier should not become literal output.

### Related boundary case: stacked modifiers on a short capture

Search `^([a-z]{1,3})$` and replace with `\u\u\u$1` on separate lines containing `url`, `id`, and `x`. The expected results are `URL`, `ID`, and `X`. In the current core search replacement implementation, `id` and `x` throw `TypeError: Cannot read properties of undefined (reading 'toUpperCase')` because case operations continue past the end of the capture. The editor's find/replace implementation handles these inputs.

### Related reports checked

- #19740 concerns editor find/replace inserting literal `undefined` for an unmatched group without case modifiers. Here, Search view retains the case modifier itself, and editor find/replace produces the expected result.
- #140734 concerns newlines being dropped from multiline replacements using case modifiers. These examples use single-line matches and empty or short captures; the existing newline regression test passes.
- #150070, which was referred to #128134, concerns replacements using lookahead and newline matching with `$1$2$2`. That replacement has no case modifiers and takes the unchanged replacement path.
- #288968 adds named capture group support. These examples use numbered groups; that PR retains the empty-capture check and unbounded case-operation loop involved here.

Workspace search case-modifier support was introduced in #105101.

A small fix with six regression tests is prepared on https://github.com/Suzu1Dev/vscode/tree/fix/search-replace-short-captures. The fixed build passes the same preview and actual Replace All scenarios, 257 related Electron unit tests (3 existing skips), and 83 search integration tests.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.