diff --git a/package.json b/package.json index 7ab1ee8..da31a05 100644 --- a/package.json +++ b/package.json @@ -273,7 +273,7 @@ { "view": "miseEnvsView", "contents": "[Environment variables](https://mise.jdx.dev/environments.html) will be displayed here.", - "when": "config.mise.binPath && config.mise.enable" + "when": "config.mise.binPath && config.mise.enable && !mise.envProviderError" }, { "view": "miseEnvsView", diff --git a/src/miseService.ts b/src/miseService.ts index aa493c9..2a9ac46 100644 --- a/src/miseService.ts +++ b/src/miseService.ts @@ -36,7 +36,7 @@ const STATE_DIR = process.env.MISE_STATE_DIR ?? path.join(XDG_STATE_HOME, "mise"); const TRACKED_CONFIG_DIR = path.join(STATE_DIR, "tracked-configs"); -const MIN_MISE_VERSION = [2024, 11, 32] as const; +const MIN_MISE_VERSION = [2024, 12, 2] as const; function compareVersions( a: readonly [number, number, number], @@ -186,7 +186,7 @@ export class MiseService { execution, ); - const p = new Promise((resolve, reject) => { + const p = new Promise((resolve) => { const disposable = vscode.tasks.onDidEndTask((e) => { if (e.execution.task === task) { vscode.commands.executeCommand(MISE_RELOAD); @@ -462,6 +462,24 @@ export class MiseService { } } + async getEnvWithInfo() { + if (!this.getMiseBinaryPath()) { + return []; + } + + const { stdout } = await this.cache.execCmd({ + command: "env --json-extended", + }); + + const parsed = JSON.parse(stdout) as Record; + return Object.entries(parsed).map(([key, info]) => ({ + name: key, + value: info.value, + tool: info?.tool, + source: info?.source ? expandPath(info.source) : undefined, + })); + } + async miseFmt() { await this.execMiseCommand("fmt", { setMiseEnv: false }); } diff --git a/src/providers/envProvider.ts b/src/providers/envProvider.ts index 64c4a3f..c4ccb01 100644 --- a/src/providers/envProvider.ts +++ b/src/providers/envProvider.ts @@ -3,6 +3,7 @@ import { MISE_COPY_ENV_VARIABLE_NAME, MISE_COPY_ENV_VARIABLE_VALUE, MISE_OPEN_ENV_VAR_DEFINITION, + MISE_OPEN_TOOL_DEFINITION, MISE_SET_ENV_VARIABLE, } from "../commands"; import { @@ -34,7 +35,7 @@ export class MiseEnvsProvider implements vscode.TreeDataProvider { } async getEnvItems() { - const envs = await this.miseService.getEnvs(); + const envs = await this.miseService.getEnvWithInfo(); return envs.map((env) => new EnvItem(env)); } @@ -58,9 +59,16 @@ export class MiseEnvsProvider implements vscode.TreeDataProvider { } class EnvItem extends vscode.TreeItem { - constructor(public env: MiseEnv) { + constructor(public env: MiseEnvWithInfo) { const label = env.value ? `${env.name}=${env.value}` : env.name; super(label, vscode.TreeItemCollapsibleState.None); + this.tooltip = [ + `${env.name}=${env.value}`, + env.source ? `source: ${env.source}` : "", + env.tool ? `Tool: ${env.tool}` : "", + ] + .filter(Boolean) + .join("\n"); this.contextValue = "envItem"; this.command = { @@ -79,7 +87,7 @@ export function registerEnvsCommands( vscode.commands.registerCommand( MISE_OPEN_ENV_VAR_DEFINITION, async (name: string | undefined) => { - const possibleEnvs = await miseService.getEnvs(); + const possibleEnvs = await miseService.getEnvWithInfo(); let selectedName = name; if (!selectedName) { selectedName = await vscode.window.showQuickPick( @@ -93,20 +101,36 @@ export function registerEnvsCommands( return; } - const configs = (await miseService.getMiseConfigFiles()).filter((c) => - c.path.endsWith(".toml"), - ); - - const documents = await Promise.all( - configs.map((config) => - vscode.workspace.openTextDocument(config.path), - ), - ); - const needle = findEnvVarPosition(documents, env.name); - if (needle?.range) { - void vscode.window.showTextDocument(needle.document, { - selection: needle.range, - }); + if (env.source) { + const document = await vscode.workspace.openTextDocument(env.source); + const needle = findEnvVarPosition([document], env.name); + if (needle?.range) { + void vscode.window.showTextDocument(needle.document, { + selection: needle.range, + }); + } + } else if (env.tool) { + await vscode.commands.executeCommand( + MISE_OPEN_TOOL_DEFINITION, + env.tool, + ); + } else { + const configs = (await miseService.getMiseConfigFiles()).filter((c) => + c.path.endsWith(".toml"), + ); + + const documents = await Promise.all( + configs.map((config) => + vscode.workspace.openTextDocument(config.path), + ), + ); + const needle = findEnvVarPosition(documents, env.name); + + if (needle?.range) { + void vscode.window.showTextDocument(needle.document, { + selection: needle.range, + }); + } } }, ), diff --git a/src/providers/toolsProvider.ts b/src/providers/toolsProvider.ts index 9b4e528..a43205a 100644 --- a/src/providers/toolsProvider.ts +++ b/src/providers/toolsProvider.ts @@ -227,8 +227,12 @@ export function registerToolsCommands( context.subscriptions.push( vscode.commands.registerCommand( MISE_OPEN_TOOL_DEFINITION, - async (tool: MiseTool | undefined) => { + async (tool: MiseTool | string | undefined) => { let selectedTool = tool; + if (typeof selectedTool === "string") { + const tools = await miseService.getCurrentTools(); + selectedTool = tools.find((t) => t.name === tool); + } if (!selectedTool) { const tools = await miseService.getCurrentTools(); const toolNames = tools.map( diff --git a/src/types.ts b/src/types.ts index 52bfdbd..7f9906d 100644 --- a/src/types.ts +++ b/src/types.ts @@ -32,3 +32,8 @@ type MiseEnv = { name: string; value: string; }; + +type MiseEnvWithInfo = MiseEnv & { + source?: string; + tool?: string; +}; diff --git a/src/utils/miseFileParser.ts b/src/utils/miseFileParser.ts index 0a6db0f..87e1c68 100644 --- a/src/utils/miseFileParser.ts +++ b/src/utils/miseFileParser.ts @@ -89,10 +89,22 @@ export function findEnvVarPosition( envVarName: string, ) { for (const document of documents) { - const parser = new TomlParser(document.getText()); - const range = parser.findRange(parser.parsed.env ?? {}, envVarName); - if (range) { - return { document, range }; + if (document.fileName.endsWith("toml")) { + const parser = new TomlParser(document.getText()); + const range = parser.findRange(parser.parsed.env ?? {}, envVarName); + if (range) { + return { document, range }; + } + } else { + const lines = document.getText().split("\n"); + for (let i = 0; i < lines.length; i++) { + const line = lines[i]; + if (line?.includes(envVarName)) { + const startPos = new vscode.Position(i, line.indexOf(envVarName)); + const endPos = startPos.translate(0, envVarName.length); + return { document, range: new vscode.Range(startPos, endPos) }; + } + } } } return undefined;