apache / apache/netbeans

lsp.client: no per-file server binding (project×mime only), and rename merges WorkspaceEdits from every bound server

Open
#9,582 0 comments 0 reactions 0 assignees View on GitHub
LSP
Dominant language
Java
Stars
3.1k
Forks
935
Avg merge
2d 3h
Merged PRs (30d)
17

Description

### Apache NetBeans version

Apache NetBeans 25 (observed on RELEASE300, still present on RELEASE310)

### Bug description

Two related limitations in ide/lsp.client that together make it impossible to attach a language server to a *subset* of files sharing a MIME type — and make it hazardous for two servers to share a mime at all:

**1. Bindings are per PROJECT × MIME, never per file.** `LSPBindings` keys server bindings by (project, mime). `LanguageServerProvider.startServer` receives no file/document context, so a provider cannot decide per file whether to attach. Concrete case: Angular CLI ≥ 21 generates *suffixless* templates (`widget.html` beside `widget.ts`), which want the Angular Language Service — but binding `ngserver` under `text/html` attaches it to **every** html file in the project, plain documents included.

**2. Rename applies WorkspaceEdits from EVERY bound server.** When two servers are bound to one mime (which `lookupAll` deliberately allows — useful for eslint-style diagnostic servers), the platform's rename collects and applies edits from **all** of them. With two servers that both implement rename (e.g. `ngserver` beside `typescript-language-server` on `text/typescript`), every rename is applied twice — we measured real double-renames before suppressing one server's mime binding entirely.

Also worth noting: the bindings consult the FileObject's resolver-assigned mime, not the document mime — a `DataObject` that pins the editor content type via the public `CloneableEditorSupport.setMIMEType` gets the full editor surface (coloring, keybindings, popup) for the new mime, but LSP still binds by the file mime, so the two disagree.

### Steps to reproduce

For (2): register two `LanguageServerProvider`s for one mime where both back rename; rename a symbol; observe the edit applied twice.

For (1): attempt to attach a server to only those `text/html` files matching a project-structural condition — there is no seam: `startServer` has no file, and mime-folder registration is all-or-nothing per project.

### Expected behavior

Either of these would unblock the use case safely:

- a per-file consultation in the provider SPI (e.g. the provider sees the triggering FileObject/document and may decline), or
- bindings consulting the document mime (so `setMIMEType` reroutes LSP together with the editor surface), or
- rename asking one authoritative server per capability instead of merging all bindings' edits.

### Context

Found while building NMOX Studio (Apache-2.0, NetBeans-Platform based): https://github.com/NMOX/NMOX-Studio — engineering ledger entries 81/82 (docs/engineering/tech-debt.md) carry the measurements and the decompiled details. Related: #9581 (multi-mime provider registrations and the instance-keyed reuse map). Happy to test patches or provide more detail.

Contributor guide

Open the contributing guide

Research direction

Start by reading ide/lsp.client, especially LSPBindings and the LanguageServerProvider.startServer SPI, then trace the rename path that merges WorkspaceEdits from lookupAll bindings. Reproduce the issue with two providers registered for one MIME and verify that the chosen design supports per-file binding or one authoritative rename server without applying duplicate edits.

Written by the indexing model from the issue text.

Assessment

Tech stack
java
Domain
developer-experience, tooling
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Needs clarification
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.