Skip to content

Implement "Request Forwarding to tsserver"#207

Merged
mizdra merged 4 commits into
mainfrom
tsserver-request
Jun 23, 2025
Merged

Implement "Request Forwarding to tsserver"#207
mizdra merged 4 commits into
mainfrom
tsserver-request

Conversation

@mizdra
Copy link
Copy Markdown
Owner

@mizdra mizdra commented Jun 21, 2025

close: #121
close: #206

Background

The tsserver loaded with ts-plugin will respond to LSP requests for .css. Meanwhile, the standard CSS Language Server also responds to LSP requests for .css.

Which Language Server processes a request depends on the request type. "completions" and "references" requests are sent to both Language Servers, and the merged responses are used. "rename" requests are sent only to the highest-priority Language Server, and its response is used.

The priority of Language Servers depends on the editor and its user settings. Zed allows users to control this with the languages.CSS.language_servers option. In VS Code, the standard CSS Language Server has the highest priority and cannot be controlled by the user.

In VS Code, "rename" and "documentLink" requests are sent only to the standard CSS Language Server, not to tsserver. As a result, there are some bugs in VS Code.

Proposed changes

Use the VS Code Extension API to pseudo-change the priority of the Language Server used for "rename" and "documentLink" requests. I call this approach "Request Forwarding to tsserver".

First, register the provider that receives ‘rename’ and “documentLink” requests in the VS Code Extension. Use the following API to do this.

Next, send "rename" and "documentLink" requests from the provider to tsserver. Use vscode.commands.executeCommand('typescript.tsserverRequest', '_xxx', request) and info.session.addProtocolHandler('_xxx', (request) => {...}) to do this.

Finally, convert the response from tsserver into the format expected by the provider. This ensures that "rename" and "documentLink" requests are sent to tsserver.

The following code demonstrates the concept:

// packages/vscode/index.ts

// ...
export function activate(context: vscode.ExtensionContext) {
  // ...
  context.subscriptions.push(
    // ...
    vscode.languages.registerRenameProvider(
      { scheme: 'file', language: 'css' },
      {
        async provideRenameEdits(document, position, newName, _token) {
          const res = await vscode.commands.executeCommand(
            'typescript.tsserverRequest',
            '_css-modules-kit:rename',
            {
              fileName: document.fileName,
              position: document.offsetAt(position),
            },
          );
          // If the response does not contain any results, return undefined to fall back to standard CSS Language Server.
          if (!res.success || !res.body || !res.body.result || res.body.result.length === 0) return;
          const edit = new vscode.WorkspaceEdit();
          for (const location of res.body.result) {
            const document = await vscode.workspace.openTextDocument(location.fileName);
            const start = document.positionAt(location.textSpan.start);
            const end = document.positionAt(location.textSpan.start + location.textSpan.length);
            edit.replace(vscode.Uri.file(location.fileName), new vscode.Range(start, end), newName);
          }
          return edit;
        },
        // ...
      },
    ),
  );
}
// packages/ts-plugin/index.ts

// ...
const plugin = createLanguageServicePlugin((ts, info) => {
  // ...
  info.session?.addProtocolHandler('_css-modules-kit:rename', () => {
    const project = getConfiguredProjectForFile(ts, info.project, request.arguments.fileName);
    if (!project) return {};
    const languageService = project.getLanguageService();
    const { fileName, position } = request.arguments;
    const result = languageService.findRenameLocations(fileName, position, false, false, {});
    return { response: { result } };
  });
  // ...
});
export = plugin;

Video

2025-06-23.0.59.05.mov
2025-06-23.1.00.37.mov

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Jun 21, 2025

🦋 Changeset detected

Latest commit: d00ba1c

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 2 packages
Name Type
@css-modules-kit/ts-plugin Patch
css-modules-kit-vscode Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@mizdra mizdra force-pushed the tsserver-request branch 2 times, most recently from 6f5fc97 to 706f9fb Compare June 22, 2025 08:00
@mizdra mizdra force-pushed the tsserver-request branch from 706f9fb to e413e95 Compare June 22, 2025 10:12
@mizdra mizdra added the Type: Bug Bug or Bug fixes label Jun 22, 2025
@mizdra mizdra changed the title Avoid LSP request conflicts with typescript.tsserverRequest Implement "Request Forwarding to Tsserver" Jun 22, 2025
@mizdra mizdra changed the title Implement "Request Forwarding to Tsserver" Implement "Request Forwarding to tsserver" Jun 22, 2025
@mizdra
Copy link
Copy Markdown
Owner Author

mizdra commented Jun 22, 2025

TODO:

  • Add comments
  • Organize commits
  • Add changelog
  • Add tests?
    • I will add it later.

@mizdra mizdra force-pushed the tsserver-request branch from 66100a3 to 799eef5 Compare June 23, 2025 12:21
@mizdra mizdra marked this pull request as ready for review June 23, 2025 12:21
@mizdra mizdra force-pushed the tsserver-request branch from 799eef5 to 4bcf571 Compare June 23, 2025 12:36
@mizdra mizdra force-pushed the tsserver-request branch from 4bcf571 to 798f528 Compare June 23, 2025 12:40
@mizdra mizdra merged commit 93cf8d1 into main Jun 23, 2025
10 checks passed
@mizdra mizdra deleted the tsserver-request branch June 23, 2025 12:45
@mizdra
Copy link
Copy Markdown
Owner Author

mizdra commented Jun 23, 2025

A long-standing problem has been resolved! 🎉

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Type: Bug Bug or Bug fixes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Go to Definition for specifiers fails using import alias in VS Code Renaming classes from .css does not work in VS Code

1 participant