-
Notifications
You must be signed in to change notification settings - Fork 3.6k
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
ruby_runtime: Initial implementation #25350
base: main
Are you sure you want to change the base?
Conversation
7a47372
to
a9d182a
Compare
output | ||
.lines() | ||
.find(|line| line.starts_with(name)) | ||
.and_then(|line| { | ||
line.rfind('(') | ||
.and_then(|start| line.rfind(')').map(|end| &line[start + 1..end])) | ||
}) | ||
.map(|versions| versions.split(", ").map(String::from).collect()) | ||
.ok_or_else(|| anyhow!("Failed to parse gem list output.")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately, the gem
command lacks any structured output so this parses the output as-is. For instance, for gem list --remote --all ruby-lsp
the output is:
*** REMOTE GEMS ***
ruby-lsp (0.23.11, 0.23.10, 0.23.9, 0.23.8, 0.23.7, 0.23.6, 0.23.5, 0.23.4, 0.23.3, 0.23.2, 0.23.1, 0.23.0, 0.22.1, 0.22.0, 0.21.3, 0.21.2, 0.21.1, 0.21.0, 0.20.1, 0.20.0, 0.19.1, 0.19.0, 0.18.4, 0.18.3, 0.18.2, 0.18.1, 0.18.0, 0.17.17, 0.17.16, 0.17.15, 0.17.14, 0.17.13, 0.17.12, 0.17.11, 0.17.10, 0.17.9, 0.17.8, 0.17.7, 0.17.6, 0.17.5, 0.17.4, 0.17.3, 0.17.2, 0.17.1, 0.17.0, 0.16.7, 0.16.6, 0.16.5, 0.16.4, 0.16.3, 0.16.2, 0.16.1, 0.16.0, 0.15.0, 0.14.6, 0.14.5, 0.14.4, 0.14.3, 0.14.2, 0.14.1, 0.14.0, 0.13.4, 0.13.3, 0.13.2, 0.13.1, 0.13.0, 0.12.5, 0.12.4, 0.12.3, 0.12.2, 0.12.1, 0.12.0, 0.11.2, 0.11.1, 0.11.0, 0.10.1, 0.10.0, 0.9.4, 0.9.3, 0.9.2, 0.9.1, 0.9.0, 0.8.1, 0.8.0, 0.7.6, 0.7.5, 0.7.4, 0.7.3, 0.7.2, 0.7.1, 0.7.0, 0.6.2, 0.6.1, 0.6.0, 0.5.1, 0.5.0, 0.4.5, 0.4.4, 0.4.3, 0.4.2, 0.4.1, 0.4.0, 0.3.8, 0.3.7, 0.3.6, 0.3.5, 0.3.4, 0.3.3, 0.3.2, 0.3.1, 0.3.0, 0.2.4, 0.2.3, 0.2.2, 0.2.1, 0.2.0, 0.1.0, 0.0.4, 0.0.3, 0.0.2, 0.0.1)
ruby-lsp-brakeman (0.0.1)
ruby-lsp-fabrication (0.3.0, 0.2.1, 0.2.0, 0.1.0)
ruby-lsp-factory_bot (0.3.0, 0.2.2, 0.2.1, 0.2.0, 0.1.0)
ruby-lsp-rails (0.4.0, 0.3.31, 0.3.30, 0.3.29, 0.3.28, 0.3.27, 0.3.26, 0.3.25, 0.3.24, 0.3.23, 0.3.22, 0.3.21, 0.3.20, 0.3.19, 0.3.18, 0.3.17, 0.3.16, 0.3.15, 0.3.14, 0.3.13, 0.3.12, 0.3.11, 0.3.10, 0.3.9, 0.3.8, 0.3.7, 0.3.6, 0.3.5, 0.3.4, 0.3.3, 0.3.2, 0.3.1, 0.3.0, 0.2.10, 0.2.9, 0.2.8, 0.2.7, 0.2.6, 0.2.5, 0.2.4, 0.2.3, 0.2.2, 0.2.1, 0.2.0, 0.1.0)
ruby-lsp-rails-factory-bot (0.5.0, 0.4.0, 0.3.0, 0.2.0, 0.1.0)
ruby-lsp-rake (0.3.4, 0.3.3, 0.3.2, 0.3.1, 0.3.0, 0.2.0, 0.1.5, 0.1.4, 0.1.3, 0.1.2, 0.1.1, 0.1.0)
ruby-lsp-ree (0.1.3, 0.1.2, 0.1.1, 0.1.0)
ruby-lsp-reek (0.3.1, 0.3.0, 0.2.0, 0.1.0)
ruby-lsp-rspec (0.1.22, 0.1.21, 0.1.20, 0.1.19, 0.1.18, 0.1.17, 0.1.16, 0.1.15, 0.1.14, 0.1.13, 0.1.12, 0.1.11, 0.1.10, 0.1.9, 0.1.8, 0.1.7, 0.1.6, 0.1.5, 0.1.4, 0.1.3, 0.1.2, 0.1.1, 0.1.0)
ruby-lsp-rubyfmt (0.1.0)
ruby-lsp-shoulda-context (0.4.9, 0.4.8, 0.4.7, 0.4.6, 0.4.5, 0.4.4, 0.4.3, 0.4.2, 0.4.1, 0.4.0, 0.3.3, 0.3.2, 0.3.1, 0.3.0, 0.2.0, 0.1.0)
Probably using the exact match via the --exact
command line option is a good idea.
a9d182a
to
70f8d6d
Compare
@@ -497,6 +497,52 @@ impl nodejs::Host for WasmState { | |||
} | |||
} | |||
|
|||
impl ruby::Host for WasmState { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This definitely should be in the next version of the Extension API, but this part of Zed is still a mystery to me. I tried the simplest approach by copying and pasting but failed.
@vitallium Just to set expectations, I think it's highly unlikely that we end up shipping a Ruby runtime with Zed. I think a more promising direction would be exposing a process API to extensions to allow them to do this sort of thing themselves. I have a start of one in #25399. And I started a branch to play around with it in the Ruby extension: https://github.com/zed-extensions/ruby/blob/67d8485778f74a10909cd07644be27c5088dbfe9/src/language_servers/language_server.rs#L43-L47 Haven't wired up anything Ruby-specific yet, but I did confirm that the process execution is working. |
It wouldn't be honest to say I completely agree, but I totally understand why shipping a Ruby runtime won't happen. I had a lot of fun working on this proof of concept, though.
That's awesome! Thank you! I can see what I can do with it and get back to you with the results if you'd like feedback. |
Closes #25099
This is a proof of concept for providing Ruby runtime to extensions through Zed extensions API.
The idea
In the spirit of the
node_runtime
which provides limited methods for working with Node.js andnpm
, this PR is about introducing theruby_runtime
- a runtime for providing limited methods for working with Ruby. This is a proof of concept only.How it works
In the same way as Zed does for
node.js
, the Ruby runtime relies on the correct environment when Zed startsWhen an extension installs a Ruby gem, the Ruby runtime uses the detected Ruby version and installs the requested gem into the extenstion's working directory. The installed gem is not installed into the user's gemset to avoid activation errors like
can't activate date (=3.6.3), already activated date-3.6.6] (Gem::Exception)
. Additionally, that method does not alter the user-installed gems. This is achieved by setting theGEM_PATH
environment variable to the extension directory for all operations.In the same way as Node runtime does, the Ruby runtime provides the following functions:
binary_path
returns path to the Ruby binary, for example,/Users/vslobodin/.local/share/mise/installs/ruby/3.4.1/bin/ruby
.gems-latest-version(gem-name: string)
Returns the latest version of the given Ruby gem name viagem-name
.gems-installed-version(gem-name: string)
Returns the installed version of the given Ruby gem, if it exists.gems-install-gem(gem-name: string, version: string, binaries: list<string>)
Installs the specified version of a Ruby gem by its name. Plus, wrappes its binaries with a special shell wrapper that setsGEM_PATH
before running the gem. This is required to run a Gem outside of the user gemset:For instance, a Ruby extension installs the
solargraph
gem. After installing it, if thebinaries
param was passed, the Ruby runtime creates wrappers for each givenbinary
with the following content:where:
gem_path
path to the extension working dir.exec_path
path to the actual Ruby gem binary.For
solargraph
this wrapper will be:bundle-installed-version(gem-name: string)
Not implemented but the idea of this method is to check if the given Ruby gem is available in the worktreeGemfile
.Notes about the implementation
SystemRubyRuntime
- the currently available Ruby runtime which should point to a Ruby version that is activated in a worktree. A shell-based activation of the Ruby version is necessary to ensure the Ruby runtime uses the correct Ruby version.UnavailableRubyRuntime
- unavailale Ruby runtime with stubbed methods.See also my comments please.
Known limitations and issues
Possible improvements and ideas
References
mason.nvim
extension forneovim
.Release Notes: