diff --git a/vscode/README.md b/vscode/README.md index 34e923d05..eaf5b8547 100644 --- a/vscode/README.md +++ b/vscode/README.md @@ -85,7 +85,12 @@ by clicking `Change version manager` in the language status center or by changin // "rbenv" // "rvm" // "shadowenv" -"rubyLsp.rubyVersionManager": "chruby" +// "mise" +{ + "rubyLsp.rubyVersionManager": { + "identifier": "chruby", + }, +} ``` To make sure that the Ruby LSP can find the version manager scripts, make sure that they are loaded in the shell's diff --git a/vscode/VERSION_MANAGERS.md b/vscode/VERSION_MANAGERS.md index 02dd25fba..22cb2239c 100644 --- a/vscode/VERSION_MANAGERS.md +++ b/vscode/VERSION_MANAGERS.md @@ -10,13 +10,15 @@ If you're using a different version manager that's not supported by this extensi executable into the PATH, you will probably need to define custom activation so that the extension can find the correct Ruby. -For these cases, set `rubyLsp.rubyVersionManager` to `"custom"` and then set `rubyLsp.customRubyCommand` to a shell -command that will activate the right Ruby version or add the Ruby `bin` folder to the `PATH`. Some examples: +For these cases, set `rubyLsp.rubyVersionManager.identifier` to `"custom"` and then set `rubyLsp.customRubyCommand` to a +shell command that will activate the right Ruby version or add the Ruby `bin` folder to the `PATH`. Some examples: ```jsonc { // Don't forget to set the manager to custom when using this option - "rubyLsp.rubyVersionManager": "custom", + "rubyLsp.rubyVersionManager": { + "identifier": "custom", + }, // Using a different version manager than the ones included by default "rubyLsp.customRubyCommand": "my_custom_version_manager activate", @@ -25,15 +27,3 @@ command that will activate the right Ruby version or add the Ruby `bin` folder t "rubyLsp.customRubyCommand": "PATH=/path/to/ruby/bin:$PATH", } ``` - -### mise (formerly rtx) - -[mise](https://github.com/jdx/mise) is a Rust clone compatible with asdf. You can use it by adding the following -snippet to your user configuration JSON - -```json -{ - "rubyLsp.rubyVersionManager": "custom", - "rubyLsp.customRubyCommand": "eval \"$(mise env -s zsh)\"" // Instructions for zsh, change for bash or fish -} -``` diff --git a/vscode/package.json b/vscode/package.json index c6daddfd9..3af53df01 100644 --- a/vscode/package.json +++ b/vscode/package.json @@ -232,20 +232,28 @@ } }, "rubyLsp.rubyVersionManager": { - "description": "The Ruby version manager to use", - "type": "string", - "enum": [ - "asdf", - "auto", - "chruby", - "none", - "rbenv", - "rvm", - "shadowenv", - "mise", - "custom" - ], - "default": "auto" + "type": "object", + "properties": { + "identifier": { + "description": "The Ruby version manager to use", + "type": "string", + "enum": [ + "asdf", + "auto", + "chruby", + "none", + "rbenv", + "rvm", + "shadowenv", + "mise", + "custom" + ], + "default": "auto" + } + }, + "default": { + "identifier": "auto" + } }, "rubyLsp.customRubyCommand": { "description": "A shell command to activate the right Ruby version or add a custom Ruby bin folder to the PATH. Only used if rubyVersionManager is set to 'custom'", diff --git a/vscode/src/common.ts b/vscode/src/common.ts index 9f5129fef..bb125a209 100644 --- a/vscode/src/common.ts +++ b/vscode/src/common.ts @@ -22,7 +22,7 @@ export enum Command { export interface RubyInterface { error: boolean; - versionManager?: string; + versionManager: { identifier: string }; rubyVersion?: string; } diff --git a/vscode/src/extension.ts b/vscode/src/extension.ts index 2b737f08f..53b81ee49 100644 --- a/vscode/src/extension.ts +++ b/vscode/src/extension.ts @@ -11,8 +11,42 @@ export async function activate(context: vscode.ExtensionContext) { extension = new RubyLsp(context); await extension.activate(); + + await migrateManagerConfigurations(); } export async function deactivate(): Promise { await extension.deactivate(); } + +type InspectKeys = + | "globalValue" + | "workspaceValue" + | "workspaceFolderValue" + | "globalLanguageValue" + | "workspaceLanguageValue" + | "workspaceFolderLanguageValue"; +// Function to migrate the old version manager configuration to the new format. Remove this after a few months +async function migrateManagerConfigurations() { + const configuration = vscode.workspace.getConfiguration("rubyLsp"); + const currentManagerSettings = + configuration.inspect("rubyVersionManager")!; + let identifier: string | undefined; + + const targetMap: Record = { + globalValue: vscode.ConfigurationTarget.Global, + globalLanguageValue: vscode.ConfigurationTarget.Global, + workspaceFolderLanguageValue: vscode.ConfigurationTarget.WorkspaceFolder, + workspaceFolderValue: vscode.ConfigurationTarget.WorkspaceFolder, + workspaceLanguageValue: vscode.ConfigurationTarget.Workspace, + workspaceValue: vscode.ConfigurationTarget.Workspace, + }; + + for (const [key, target] of Object.entries(targetMap)) { + identifier = currentManagerSettings[key as InspectKeys]; + + if (identifier && typeof identifier === "string") { + await configuration.update("rubyVersionManager", { identifier }, target); + } + } +} diff --git a/vscode/src/ruby.ts b/vscode/src/ruby.ts index 24278f278..8c524591d 100644 --- a/vscode/src/ruby.ts +++ b/vscode/src/ruby.ts @@ -29,13 +29,19 @@ export enum ManagerIdentifier { Custom = "custom", } +export interface ManagerConfiguration { + identifier: ManagerIdentifier; +} + export class Ruby implements RubyInterface { public rubyVersion?: string; // This property indicates that Ruby has been compiled with YJIT support and that we're running on a Ruby version // where it will be activated, either by the extension or by the server public yjitEnabled?: boolean; private readonly workspaceFolder: vscode.WorkspaceFolder; - #versionManager?: ManagerIdentifier; + #versionManager: ManagerConfiguration = vscode.workspace + .getConfiguration("rubyLsp") + .get("rubyVersionManager")!; private readonly shell = process.env.SHELL?.replace(/(\s+)/g, "\\$1"); private _env: NodeJS.ProcessEnv = {}; @@ -71,12 +77,18 @@ export class Ruby implements RubyInterface { : this.workspaceFolder.uri.fsPath; } - get versionManager() { + get versionManager(): ManagerConfiguration { return this.#versionManager; } - private set versionManager(versionManager: ManagerIdentifier | undefined) { - this.#versionManager = versionManager; + private set versionManager( + versionManager: ManagerConfiguration | ManagerIdentifier, + ) { + if (typeof versionManager === "string") { + this.#versionManager.identifier = versionManager; + } else { + this.#versionManager = versionManager; + } } get env() { @@ -88,14 +100,14 @@ export class Ruby implements RubyInterface { } async activateRuby( - versionManager: ManagerIdentifier = vscode.workspace + versionManager: ManagerConfiguration = vscode.workspace .getConfiguration("rubyLsp") - .get("rubyVersionManager")!, + .get("rubyVersionManager")!, ) { this.versionManager = versionManager; // If the version manager is auto, discover the actual manager before trying to activate anything - if (this.versionManager === ManagerIdentifier.Auto) { + if (this.versionManager.identifier === ManagerIdentifier.Auto) { await this.discoverVersionManager(); this.outputChannel.info( `Discovered version manager ${this.versionManager}`, @@ -103,7 +115,7 @@ export class Ruby implements RubyInterface { } try { - switch (this.versionManager) { + switch (this.versionManager.identifier) { case ManagerIdentifier.Asdf: await this.activate("asdf exec ruby"); break; @@ -281,7 +293,7 @@ export class Ruby implements RubyInterface { await vscode.workspace.fs.stat( vscode.Uri.joinPath(this.workspaceFolder.uri, ".shadowenv.d"), ); - this.versionManager = ManagerIdentifier.Shadowenv; + this.versionManager.identifier = ManagerIdentifier.Shadowenv; return; } catch (error: any) { // If .shadowenv.d doesn't exist, then we check the other version managers diff --git a/vscode/src/rubyLsp.ts b/vscode/src/rubyLsp.ts index 8c490032b..cb458b807 100644 --- a/vscode/src/rubyLsp.ts +++ b/vscode/src/rubyLsp.ts @@ -5,7 +5,7 @@ import { Telemetry } from "./telemetry"; import DocumentProvider from "./documentProvider"; import { Workspace } from "./workspace"; import { Command, STATUS_EMITTER } from "./common"; -import { ManagerIdentifier } from "./ruby"; +import { ManagerIdentifier, ManagerConfiguration } from "./ruby"; import { StatusItems } from "./status"; import { TestController } from "./testController"; import { Debugger } from "./debugger"; @@ -286,16 +286,18 @@ export class RubyLsp { Command.SelectVersionManager, async () => { const configuration = vscode.workspace.getConfiguration("rubyLsp"); + const managerConfig = + configuration.get("rubyVersionManager")!; const options = Object.values(ManagerIdentifier); - const manager = await vscode.window.showQuickPick(options, { - placeHolder: `Current: ${configuration.get("rubyVersionManager")}`, - }); + const manager = (await vscode.window.showQuickPick(options, { + placeHolder: `Current: ${managerConfig.identifier}`, + })) as ManagerIdentifier | undefined; if (manager !== undefined) { + managerConfig.identifier = manager; await configuration.update( "rubyVersionManager", - manager, - true, + managerConfig, true, ); } diff --git a/vscode/src/status.ts b/vscode/src/status.ts index 97c471fe7..701c88333 100644 --- a/vscode/src/status.ts +++ b/vscode/src/status.ts @@ -49,7 +49,7 @@ export class RubyVersionStatus extends StatusItem { this.item.text = "Failed to activate Ruby"; this.item.severity = vscode.LanguageStatusSeverity.Error; } else { - this.item.text = `Using Ruby ${workspace.ruby.rubyVersion} with ${workspace.ruby.versionManager}`; + this.item.text = `Using Ruby ${workspace.ruby.rubyVersion} with ${workspace.ruby.versionManager.identifier}`; this.item.severity = vscode.LanguageStatusSeverity.Information; } } diff --git a/vscode/src/telemetry.ts b/vscode/src/telemetry.ts index fdc631451..ef08f0fce 100644 --- a/vscode/src/telemetry.ts +++ b/vscode/src/telemetry.ts @@ -74,7 +74,7 @@ export class Telemetry { const promises: Promise[] = [ { namespace: "workbench", field: "colorTheme" }, { namespace: "rubyLsp", field: "enableExperimentalFeatures" }, - { namespace: "rubyLsp", field: "rubyVersionManager" }, + { namespace: "rubyLsp", field: "rubyVersionManager.identifier" }, { namespace: "rubyLsp", field: "formatter" }, ].map(({ namespace, field }) => { return this.sendEvent({ diff --git a/vscode/src/test/suite/client.test.ts b/vscode/src/test/suite/client.test.ts index 4a07d5984..4426f6a89 100644 --- a/vscode/src/test/suite/client.test.ts +++ b/vscode/src/test/suite/client.test.ts @@ -116,7 +116,12 @@ suite("Client", () => { if (process.env.CI) { await vscode.workspace .getConfiguration("rubyLsp") - .update("rubyVersionManager", ManagerIdentifier.None, true, true); + .update( + "rubyVersionManager", + { identifier: ManagerIdentifier.None }, + true, + true, + ); } client = await launchClient(workspaceUri); }); diff --git a/vscode/src/test/suite/debugger.test.ts b/vscode/src/test/suite/debugger.test.ts index bcfb9d465..d3be4367d 100644 --- a/vscode/src/test/suite/debugger.test.ts +++ b/vscode/src/test/suite/debugger.test.ts @@ -168,7 +168,7 @@ suite("Debugger", () => { .returns({ get: (name: string) => { if (name === "rubyVersionManager") { - return manager; + return { identifier: manager }; } else if (name === "bundleGemfile") { return ""; } else if (name === "saveBeforeStart") { diff --git a/vscode/src/test/suite/ruby.test.ts b/vscode/src/test/suite/ruby.test.ts index 57c73d0f3..8c9ab62d2 100644 --- a/vscode/src/test/suite/ruby.test.ts +++ b/vscode/src/test/suite/ruby.test.ts @@ -29,7 +29,7 @@ suite("Ruby environment activation", () => { .returns({ get: (name: string) => { if (name === "rubyVersionManager") { - return manager; + return { identifier: manager }; } else if (name === "bundleGemfile") { return ""; } @@ -66,7 +66,7 @@ suite("Ruby environment activation", () => { .returns({ get: (name: string) => { if (name === "rubyVersionManager") { - return manager; + return { identifier: manager }; } else if (name === "bundleGemfile") { return ""; } diff --git a/vscode/src/test/suite/status.test.ts b/vscode/src/test/suite/status.test.ts index 19f83de30..1ba43bda8 100644 --- a/vscode/src/test/suite/status.test.ts +++ b/vscode/src/test/suite/status.test.ts @@ -28,7 +28,10 @@ suite("StatusItems", () => { suite("RubyVersionStatus", () => { beforeEach(() => { - ruby = { rubyVersion: "3.2.0", versionManager: "shadowenv" } as Ruby; + ruby = { + rubyVersion: "3.2.0", + versionManager: { identifier: "shadowenv" }, + } as Ruby; workspace = { ruby, lspClient: {