standardrb / vscode-standard-ruby

The official VS Code extension for the Standard Ruby linter and code formatter
Other
101 stars 7 forks source link

Wrong shell used when VS code is launched via the GUI #19

Open teoulas opened 7 months ago

teoulas commented 7 months ago

I've read these older issues and they seem to be related:

I have a similar issue as the ones above:

If I launch VS code from a terminal the Standard extension loads fine. It doesn't load when I launch VS code from the GUI launcher (Gnome on Arch Linux). I installed VS code using this AUR package that supports appending certain command-line arguments, but to eliminate this as a source of issues, I basically launch the executable directly, with ALT+F2 (opens a run dialog) and using the full path: /opt/visual-studio-code/bin/code

The result is this:

[client] Command `bundle list --name-only` failed with exit code 127 (exec options: {"cwd":"/home/username/project_path"})
[client] stderr:
/bin/sh: line 1: bundle: command not found

From the error message above, this is suspicious: /bin/sh is a symlink to /bin/bash but my login shell is zsh. I also use Shopify's RubyLSP extension which seems to run bundler fine. This leads me to believe the difference between the two extensions lies in the way they launch bundler/another process.

RubyLSP does detect my shell fine:

2023-12-05 12:21:31.021 [info] Checking if asdf is available on the path with command: /usr/bin/zsh -ic 'asdf --version'

The internal VS code terminal also loads zsh properly.

Briefly looking at the code it seems /bin/sh is the default for node's child_process.exec function, however, there's definitely more to that, because running VS code from a terminal clearly doesn't use /bin/sh.

searls commented 6 months ago

I wonder if the solution is spawn(…, { shell: process.env.SHELL })?

teoulas commented 6 months ago

I wonder if the solution is spawn(…, { shell: process.env.SHELL })?

Thanks for the tip! This is one part of the solution. process.env.SHELL consistently returns /usr/bin/zsh, so it is always set regardless of how I launch VS code (from an interactive terminal, or the GUI launcher).

I have compared my process.env under both launch scenarios and it's obvious that asdf is not loaded (which makes sense, as it's only loaded from interactive shells). So even with exec(...{shell: process.env.SHELL}) it still doesn't find bundle. That means the solution is probably running the user's shell with -ic '${bundle/whatever_command_here}' just like RubyLSP does.

I need to play around a bit and hopefully I can send a PR with a fix :crossed_fingers:

searls commented 6 months ago

Thanks. Since I use brew bash and don't have this problem, it'd probably be easier for you to attempt a PR

teoulas commented 6 months ago

So I tried the simplest change:

diff --git a/src/extension.ts b/src/extension.ts
index ebb71b5..dc91247 100644
--- a/src/extension.ts
+++ b/src/extension.ts
@@ -55,6 +55,7 @@ class ExecError extends Error {
 }

 const promiseExec = async function (command: string, options = { cwd: getCwd() }): Promise<{ stdout: string, stderr: string }> {
+  command = `${process.env.SHELL} -ic '${command}'`
   return await new Promise((resolve, reject) => {
     exec(command, options, (error, stdout, stderr) => {
       stdout = stdout.toString().trim()

Which then fails when it tries to start the language server:

[client] Starting language server: bundle exec standardrb --lsp
[Error - 5:03:36 PM] Standard Ruby client: couldn't create connection to server.
Launching server using command bundle failed. Error: spawn bundle ENOENT

Which is weird, because bundle is certainly available (otherwise bundle show standard which runs earlier, would fail). :thinking: