Skip to content

Use new process API for starting language servers #48

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

vitallium
Copy link
Collaborator

@vitallium vitallium commented Mar 15, 2025

Use new process API for starting language servers

Improve initial developer experience of the Ruby extension by utilizing the new Process API for starting language servers.

Key points:

  • The Ruby extension always should prefer LSPs available in project gemset.
  • The binary.path option acts as a circuit breaker in the activation logic for experienced users and for debugging purposes.

Test cases

All test cases and current activation logic:

  1. If an absolute path lsp.<LSP_NAME>.binary.path is available, ignore the use_bundler configuration option value and use the provided path.
  2. If the use_bundler configuration option is true:
    1. Start an LSP with bundle exec. In most cases, this will activate the version available in the project's gemset.
  3. If the use_bundler configuration option is false:
  4. Check the project's gemset to see if the LSP is available there. See below.
  5. If available, use it.
  6. Otherwise, check the extension's work dir for the installed LSP.
  7. Check for updates.
  8. Start the isolated LSP installed in the extension's work dir.
graph TD;
    A[Start] --> B{Absolute path 'binary.path' available?}
    B -->|Yes| C[Use the provided path]
    B -->|No| D{Is 'use_bundler' configuration option true?}
    D -->|Yes| E[Start LSP with bundler]
    D -->|No| G[Check the project's gemset for LSP]
    G --> H{Is LSP available in gemset?}
    H -->|Yes| I[Use the available LSP]
    H -->|No| J[Check the extension's work dir for installed LSP]
    J --> K{Check for updates}
    K --> L[Start isolated LSP in extension's work dir]
    C --> End[End]
    I --> End
    L --> End
Loading

solargraph (default)

  • Gem name: solargraph
  • Uses bundler by default: true

Demo

Using solargraph from the project' gemset:

solargraph_extension_gemset.mp4

Using solargraph from the extenion' gemset:

solargraph_project_gemset.mp4

ruby-lsp

  • Gem name: ruby-lsp
  • Uses bundler by default: false

rubocop

  • Gem name: rubocop
  • Uses bundler by default: true

TODO

  • Cover newly added functionality with tests
  • Test all supported LSPs
  • Edge cases?

Resources

@vitallium vitallium force-pushed the vs/process-api-impl branch from a1a44a3 to 13ed19e Compare April 6, 2025 18:22
SomeoneToIgnore pushed a commit to zed-industries/zed that referenced this pull request Apr 9, 2025
…28173)

## Description

In #27213 the new feature for
setting env variables for LSPs was added but env vars passed from an
instance of `ExtensionLspAdapter` are lost now. This means if an
extension returns any env variable like this:

```rust
zed::Command {
  command: some_command,
  args: some_args,
  env: vec![("A", "value_for_a")],
}
```

The env variable `A` will never be used by `LspStore`. This commit
preserves env variables passed from an instance of
`ExtensionLspAdapter`.

After this change overwriting of env variables
happens in the following order:

```plaintext
shell <- variables from an extension <- variables from settings
```

## How to reproduce

Allow any extension to return a `zed::Command` with environment
variables to Zed. You can use [this
branch](zed-extensions/ruby#48) for the Ruby
extension:

1. Check out the branch and install the dev version of the Ruby
extension.
2. Ensure you have the `solargraph` LSP configured and enabled for the
Ruby extension. This LSP is enabled by default in Zed and in the Ruby
extension.
3. Make sure you don’t have `solargraph` installed in your user gemset.
4. Open any Ruby project, such as [this
one](https://github.com/vitallium/stimulus-lsp-error-zed).
5. Open a Ruby file and wait for the error message about failing to
start `solargraph`. It should look like this or something similar:

```
[2025-04-05T23:17:26+02:00 ERROR project::lsp_store] server stderr: "/Users/vslobodin/.local/share/mise/installs/ruby/3.4.1/lib/ruby/site_ruby/3.4.0/rubygems.rb:262:in 'Gem.find_spec_for_exe': can't find gem solargraph (>= 0.a) with executable solargraph (Gem::GemNotFoundException)\n\tfrom /Users/vslobodin/.local/share/mise/installs/ruby/3.4.1/lib/ruby/site_ruby/3.4.0/rubygems.rb:281:in 'Gem.activate_bin_path'\n"
```

This error occurs because the Ruby extension passes the `GEM_PATH`
environment variable to specify the location of Ruby gems. Without it,
Zed tries to spawn the `solargraph` gem in the user's gemset scope. Ruby
fails to start it because the `solargraph` gem is not installed in the
user gemset but in the extension directory. By setting the `GEM_PATH`
environment variable, Ruby searches additional locations to start the
`solargraph` LSP.

I hope I've described it correctly. Please let me know if you need more
information. Thanks!

Release Notes:

- Fixed the issue where environment variables from `ExtensionLspAdapter`
were lost
@orangewolf
Copy link

excited about this =-) thanks for working on it

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

Successfully merging this pull request may close these issues.

3 participants