Skip to content

Commit ae8010c

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 0248d2d commit ae8010c

6 files changed

Lines changed: 110 additions & 6 deletions

File tree

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
@@ -35,7 +35,13 @@ def stdout
3535
def initialize(project_path, **options)
3636
@project_path = project_path
3737
@branch = options[:branch] #: String?
38+
@path = options[:path] #: String?
3839
@launcher = options[:launcher] #: bool?
40+
41+
if @branch && !@branch.empty? && @path && !@path.empty?
42+
raise ArgumentError, "Branch and path options are mutually exclusive. Please specify only one."
43+
end
44+
3945
patch_thor_to_print_progress_to_stderr! if @launcher
4046

4147
# Regular bundle paths
@@ -165,7 +171,13 @@ def write_custom_gemfile
165171

166172
unless @dependencies["ruby-lsp"]
167173
ruby_lsp_entry = +'gem "ruby-lsp", require: false, group: :development'
168-
ruby_lsp_entry << ", github: \"Shopify/ruby-lsp\", branch: \"#{@branch}\"" if @branch
174+
if @branch && !@branch.empty?
175+
ruby_lsp_entry << ", github: \"Shopify/ruby-lsp\", branch: \"#{@branch}\""
176+
end
177+
if @path && !@path.empty?
178+
absolute_path = File.expand_path(@path, @project_path)
179+
ruby_lsp_entry << ", path: \"#{absolute_path}\""
180+
end
169181
parts << ruby_lsp_entry
170182
end
171183

test/setup_bundler_test.rb

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,38 @@ def test_creates_composed_bundle_with_specified_branch
280280
end
281281
end
282282

283+
def test_creates_composed_bundle_with_specified_path
284+
Dir.mktmpdir do |dir|
285+
local_path = "local-ruby-lsp"
286+
FileUtils.mkdir_p(File.join(dir, local_path, "lib"))
287+
288+
Dir.chdir(dir) do
289+
bundle_gemfile = Pathname.new(".ruby-lsp").expand_path(Dir.pwd) + "Gemfile"
290+
Bundler.with_unbundled_env do
291+
stub_bundle_with_env(bundle_env(dir, bundle_gemfile.to_s))
292+
run_script(File.realpath(dir), path: local_path)
293+
end
294+
295+
assert_path_exists(".ruby-lsp")
296+
assert_path_exists(".ruby-lsp/Gemfile")
297+
expected_absolute_path = File.expand_path(local_path, File.realpath(dir))
298+
assert_match(%r{ruby-lsp.*path: "#{Regexp.escape(expected_absolute_path)}"}, File.read(".ruby-lsp/Gemfile"))
299+
assert_match("debug", File.read(".ruby-lsp/Gemfile"))
300+
end
301+
end
302+
end
303+
304+
def test_raises_error_when_both_branch_and_path_are_specified
305+
Dir.mktmpdir do |dir|
306+
Dir.chdir(dir) do
307+
error = assert_raises(ArgumentError) do
308+
RubyLsp::SetupBundler.new(dir, branch: "test-branch", path: "local-path")
309+
end
310+
assert_equal("Branch and path options are mutually exclusive. Please specify only one.", error.message)
311+
end
312+
end
313+
end
314+
283315
def test_returns_bundle_app_config_if_there_is_local_config
284316
Dir.mktmpdir do |dir|
285317
Dir.chdir(dir) do

vscode/package.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -467,6 +467,11 @@
467467
"type": "string",
468468
"default": ""
469469
},
470+
"rubyLsp.serverPath": {
471+
"description": "Absolute or workspace-relative path to a local ruby-lsp repository or its ruby-lsp executable. Only supported if not using bundleGemfile",
472+
"type": "string",
473+
"default": ""
474+
},
470475
"rubyLsp.pullDiagnosticsOn": {
471476
"description": "When to pull diagnostics from the server (on change, save or both). Selecting 'save' may significantly improve performance on large files",
472477
"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)