editor.suggest.insertMode: "insert" not respected for completions using LSP InsertReplaceEdit (clangd 23.1.0+)
- Dominant language
- TypeScript
- Stars
- 193k
- Forks
- 42.4k
- PR merge metrics
- PR metrics pending
Description
Does this issue occur when all extensions are disabled?: N/A — reproducing this requires a language server that emits an LSP `InsertReplaceEdit` completion item (e.g. clangd 23.1.0+); no such completion is generated with all extensions disabled. However, the raw LSP response captured from the server (see "Evidence" below) shows a correctly-scoped `insert` range, which isolates the bug to how VS Code applies `editor.suggest.insertMode` rather than to the extension's logic.
- VS Code Version: 1.136.2 (user setup), commit 88e44fa0e00b08f7758b4f6d05632e4fd5e4df6f, 2026-09-04
- OS Version: Windows 10.0.19045 x64
Steps to Reproduce:
1. Install the `clangd` extension (llvm-vs-code-extensions) with clangd 23.1.0 or later configured for a C++ project.
2. In a `.cpp` file, given a class `Foo` with method `bar()` declared, place the caret immediately before an existing call/definition of `bar`, e.g. `|bar()`.
3. Trigger completion, type a prefix matching `Foo`, and accept the `Foo` suggestion from the popup.
4. Observe that `bar` is deleted and replaced, instead of `Foo` being inserted before the caret.
Expected: with `editor.suggest.insertMode` at its default value `"insert"`, only the typed prefix before the caret should be replaced; `bar` should remain untouched, producing `Foo|bar()`.
Actual: the entire identifier `bar` is deleted, producing `Foo()`.
Evidence (raw LSP response from clangd, captured via `--log=verbose`):
{
"textEdit": {
"insert": { "start": {"line":46,"character":4}, "end": {"line":46,"character":5} },
"replace": { "start": {"line":46,"character":4}, "end": {"line":46,"character":22} },
"newText": "GameplayInputAdapter"
}
}
The `insert` range is correctly scoped to only the typed prefix (width 1). The `replace` range spans the entire following identifier (width 18, matching `validatedEntityId` in the real repro). The observed deletion matches applying `replace`, contradicting the configured `insert` mode.
Regression note: not reproducible with clangd 22.1.18, which did not yet send `InsertReplaceEdit` (it returned a single narrow `TextEdit`, leaving no ambiguity for the client). The regression appeared once clangd 23.1.0 added `InsertReplaceEdit` support (fixing clangd/clangd#2190). A similar class of bug was previously reported for gopls: golang/go#61215.
`editor.suggest.insertMode`: left at default (`"insert"`), confirmed not overridden in settings.
Contributor guide
Assessment
This issue has not been assessed yet.