Skip to content

Commit 752d871

Browse files
committed
Add VS Code rubyLsp.serverPath configuration for local server development...
Also add --path option to the ruby-lsp executable itself
1 parent ba8c270 commit 752d871

File tree

6 files changed

+110
-6
lines changed

6 files changed

+110
-6
lines changed

exe/ruby-lsp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,13 @@ parser = OptionParser.new do |opts|
2929
options[:branch] = branch
3030
end
3131

32+
opts.on(
33+
"--path [PATH]",
34+
"Launch the Ruby LSP using a local PATH rather than the release version",
35+
) do |path|
36+
options[:path] = path
37+
end
38+
3239
opts.on("--doctor", "Run troubleshooting steps") do
3340
options[:doctor] = true
3441
end
@@ -54,6 +61,11 @@ rescue OptionParser::InvalidOption => e
5461
exit(1)
5562
end
5663

64+
if options[:branch] && options[:path]
65+
warn('Invalid options: --branch and --path cannot both be set.')
66+
exit(1)
67+
end
68+
5769
# When we're running without bundler, then we need to make sure the composed bundle is fully configured and re-execute
5870
# using `BUNDLE_GEMFILE=.ruby-lsp/Gemfile bundle exec ruby-lsp` so that we have access to the gems that are a part of
5971
# the application's bundle

jekyll/contributing.markdown

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,20 @@ with a debugger. Note that the debug mode applies only until the editor is close
5858
Caveat: since you are debugging the language server instance that is currently running in your own editor, features will
5959
not be available if the execution is currently suspended at a breakpoint.
6060

61+
#### Configuring the server version
62+
63+
When developing the Ruby LSP server, you may want to test your changes in your own Ruby projects to ensure they work correctly in real-world scenarios.
64+
65+
The running server, even in debug mode, will default to the installed release version*. You can use the `rubyLsp.serverPath` configuration setting in the target workspace to start your local copy instead. Make sure to restart the language server after making changes to pick up your updates.
66+
67+
```jsonc
68+
{
69+
"rubyLsp.serverPath": "/path/to/your/ruby-lsp-clone"
70+
}
71+
```
72+
73+
*Note: There are some exceptions to this. Most notably, when the ruby-lsp repository is opened in VS Code with the extension active, it will run the server contained within the repository.
74+
6175
#### Understanding Prism ASTs
6276

6377
The Ruby LSP uses Prism to parse and understand Ruby code. When working on a feature, it's very common to need to

lib/ruby_lsp/setup_bundler.rb

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,13 @@ def stdout
3939
def initialize(project_path, **options)
4040
@project_path = project_path
4141
@branch = options[:branch] #: String?
42+
@path = options[:path] #: String?
4243
@launcher = options[:launcher] #: bool?
44+
45+
if @branch && !@branch.empty? && @path && !@path.empty?
46+
raise ArgumentError, "Branch and path options are mutually exclusive. Please specify only one."
47+
end
48+
4349
force_output_to_stderr! if @launcher
4450

4551
# Regular bundle paths
@@ -170,7 +176,13 @@ def write_custom_gemfile
170176

171177
unless @dependencies["ruby-lsp"]
172178
ruby_lsp_entry = +'gem "ruby-lsp", require: false, group: :development'
173-
ruby_lsp_entry << ", github: \"Shopify/ruby-lsp\", branch: \"#{@branch}\"" if @branch
179+
if @branch && !@branch.empty?
180+
ruby_lsp_entry << ", github: \"Shopify/ruby-lsp\", branch: \"#{@branch}\""
181+
end
182+
if @path && !@path.empty?
183+
absolute_path = File.expand_path(@path, @project_path)
184+
ruby_lsp_entry << ", path: \"#{absolute_path}\""
185+
end
174186
parts << ruby_lsp_entry
175187
end
176188

test/setup_bundler_test.rb

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,38 @@ def test_creates_composed_bundle_with_specified_branch
316316
end
317317
end
318318

319+
def test_creates_composed_bundle_with_specified_path
320+
Dir.mktmpdir do |dir|
321+
local_path = "local-ruby-lsp"
322+
FileUtils.mkdir_p(File.join(dir, local_path, "lib"))
323+
324+
Dir.chdir(dir) do
325+
bundle_gemfile = Pathname.new(".ruby-lsp").expand_path(Dir.pwd) + "Gemfile"
326+
Bundler.with_unbundled_env do
327+
stub_bundle_with_env(bundle_env(dir, bundle_gemfile.to_s))
328+
run_script(File.realpath(dir), path: local_path)
329+
end
330+
331+
assert_path_exists(".ruby-lsp")
332+
assert_path_exists(".ruby-lsp/Gemfile")
333+
expected_absolute_path = File.expand_path(local_path, File.realpath(dir))
334+
assert_match(%r{ruby-lsp.*path: "#{Regexp.escape(expected_absolute_path)}"}, File.read(".ruby-lsp/Gemfile"))
335+
assert_match("debug", File.read(".ruby-lsp/Gemfile"))
336+
end
337+
end
338+
end
339+
340+
def test_raises_error_when_both_branch_and_path_are_specified
341+
Dir.mktmpdir do |dir|
342+
Dir.chdir(dir) do
343+
error = assert_raises(ArgumentError) do
344+
RubyLsp::SetupBundler.new(dir, branch: "test-branch", path: "local-path")
345+
end
346+
assert_equal("Branch and path options are mutually exclusive. Please specify only one.", error.message)
347+
end
348+
end
349+
end
350+
319351
def test_returns_bundle_app_config_if_there_is_local_config
320352
in_temp_dir do |dir|
321353
Bundler.with_unbundled_env do

vscode/package.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -473,6 +473,11 @@
473473
"type": "string",
474474
"default": ""
475475
},
476+
"rubyLsp.serverPath": {
477+
"description": "Absolute or workspace-relative path to a local ruby-lsp repository or its ruby-lsp executable. Only supported if not using bundleGemfile",
478+
"type": "string",
479+
"default": ""
480+
},
476481
"rubyLsp.pullDiagnosticsOn": {
477482
"description": "When to pull diagnostics from the server (on change, save or both). Selecting 'save' may significantly improve performance on large files",
478483
"type": "string",

vscode/src/client.ts

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import path from "path";
2+
import fs from "fs";
23
import os from "os";
34
import { performance as Perf } from "perf_hooks";
45

@@ -85,6 +86,7 @@ function getLspExecutables(workspaceFolder: vscode.WorkspaceFolder, env: NodeJS.
8586
const customBundleGemfile: string = config.get("bundleGemfile")!;
8687
const useBundlerCompose: boolean = config.get("useBundlerCompose")!;
8788
const bypassTypechecker: boolean = config.get("bypassTypechecker")!;
89+
const serverPath: string = config.get("serverPath")!;
8890

8991
const executableOptions: ExecutableOptions = {
9092
cwd: workspaceFolder.uri.fsPath,
@@ -119,13 +121,40 @@ function getLspExecutables(workspaceFolder: vscode.WorkspaceFolder, env: NodeJS.
119121
options: executableOptions,
120122
};
121123
} else {
124+
const args = [];
122125
const workspacePath = workspaceFolder.uri.fsPath;
123-
const command =
124-
path.basename(workspacePath) === "ruby-lsp" && os.platform() !== "win32"
125-
? path.join(workspacePath, "exe", "ruby-lsp")
126-
: "ruby-lsp";
126+
let command: string;
127127

128-
const args = [];
128+
if (serverPath.length > 0 && branch.length > 0) {
129+
throw new Error(
130+
'Invalid configuration: "rubyLsp.serverPath" and "rubyLsp.branch" cannot both be set. Please unset one of them.',
131+
);
132+
}
133+
134+
if (serverPath.length > 0) {
135+
const absoluteServerPath = path.isAbsolute(serverPath) ? serverPath : path.resolve(workspacePath, serverPath);
136+
const exists = fs.existsSync(absoluteServerPath);
137+
138+
if (exists) {
139+
args.push("--path", absoluteServerPath);
140+
const stat = fs.statSync(absoluteServerPath);
141+
142+
if (stat.isDirectory()) {
143+
command = os.platform() !== "win32" ? path.join(absoluteServerPath, "exe", "ruby-lsp") : "ruby-lsp";
144+
} else {
145+
command = absoluteServerPath;
146+
}
147+
} else {
148+
throw new Error(
149+
`The configured rubyLsp.serverPath "${serverPath}" does not exist at "${absoluteServerPath}". `,
150+
);
151+
}
152+
} else {
153+
command =
154+
path.basename(workspacePath) === "ruby-lsp" && os.platform() !== "win32"
155+
? path.join(workspacePath, "exe", "ruby-lsp")
156+
: "ruby-lsp";
157+
}
129158

130159
if (branch.length > 0) {
131160
args.push("--branch", branch);

0 commit comments

Comments
 (0)