Skip to content

Commit

Permalink
Add settings for mise bin path and mise profile
Browse files Browse the repository at this point in the history
  • Loading branch information
hverlin committed Nov 11, 2024
1 parent 157f2ef commit 7d2b193
Show file tree
Hide file tree
Showing 6 changed files with 161 additions and 8 deletions.
17 changes: 16 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"displayName": "Mise VSCode",
"publisher": "hverlin",
"description": "VSCode extension for mise (manged dev tools, tasks and environment variables)",
"version": "0.0.6",
"version": "0.0.7",
"repository": {
"type": "git",
"url": "https://github.com/hverlin/mise-vscode"
Expand All @@ -29,6 +29,21 @@
"icon": "resources/icon.png",
"main": "./dist/extension.js",
"contributes": {
"configuration": {
"title": "Mise",
"properties": {
"mise.binPath": {
"type": "string",
"scope": "resource",
"markdownDescription": "Path to the mise binary (automatically detected on startup).\n\nSee https://mise.jdx.dev/getting-started.html to install mise."
},
"mise.profile": {
"type": "string",
"scope": "resource",
"markdownDescription": "Mise profile to use. (https://mise.jdx.dev/profiles.html)"
}
}
},
"viewsContainers": {
"activitybar": [
{
Expand Down
43 changes: 42 additions & 1 deletion src/extension.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as vscode from "vscode";
import { window } from "vscode";
import { MiseService } from "./miseService";
import { MiseEnvsProvider } from "./providers/envProvider";
import { MiseRunCodeLensProvider } from "./providers/miseRunCodeLensProvider";
Expand All @@ -7,10 +8,41 @@ import {
registerMiseCommands,
} from "./providers/tasksProvider";
import { MiseToolsProvider, registerCommands } from "./providers/toolsProvider";
import { logger } from "./utils/logger";
import { resolveMisePath } from "./utils/miseBinLocator";
import { showSettingsNotification } from "./utils/notify";

let statusBarItem: vscode.StatusBarItem;

export function activate(context: vscode.ExtensionContext) {
async function initializeMisePath() {
let miseBinaryPath = "mise";
try {
miseBinaryPath = await resolveMisePath();
logger.info(`Mise binary path resolved to: ${miseBinaryPath}`);
const config = vscode.workspace.getConfiguration("mise");
const previousPath = config.get<string>("binPath");
if (previousPath !== miseBinaryPath) {
config.update(
"binPath",
miseBinaryPath,
vscode.ConfigurationTarget.Global,
);
void showSettingsNotification(
`Mise binary path has been updated to: ${miseBinaryPath}`,
{ settingsKey: "mise.binPath", type: "info" },
);
}
} catch (error) {
void showSettingsNotification(
"Mise binary not found. Please configure the binary path.",
{ settingsKey: "mise.binPath", type: "error" },
);
logger.error("Failed to resolve mise binary path:", error as Error);
}
}

export async function activate(context: vscode.ExtensionContext) {
await initializeMisePath();
const miseService = new MiseService();

const tasksProvider = new MiseTasksProvider(miseService);
Expand Down Expand Up @@ -38,6 +70,15 @@ export function activate(context: vscode.ExtensionContext) {

const codelensProvider = new MiseRunCodeLensProvider();

vscode.workspace.onDidChangeConfiguration((e) => {
if (
e.affectsConfiguration("mise.binPath") ||
e.affectsConfiguration("mise.profile")
) {
vscode.commands.executeCommand("mise.refreshEntry");
}
});

context.subscriptions.push(
vscode.commands.registerCommand("mise.refreshEntry", async () => {
await vscode.commands.executeCommand(
Expand Down
19 changes: 13 additions & 6 deletions src/miseService.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
import { exec } from "node:child_process";
import { promisify } from "node:util";
import * as vscode from "vscode";
import { logger } from "./utils/logger";
import { execAsync } from "./utils/shell";
import { type MiseTaskInfo, parseTaskInfo } from "./utils/taskInfoParser";

const execAsync = promisify(exec);

export class MiseService {
private terminal: vscode.Terminal | undefined;
private readonly workspaceRoot: string | undefined;
Expand All @@ -15,7 +12,18 @@ export class MiseService {
}

async execMiseCommand(command: string) {
const miseCommand = `mise ${command}`;
const miseBinaryPath = vscode.workspace
.getConfiguration("mise")
.get("binPath");

let miseCommand = `"${miseBinaryPath}" ${command}`;
const miseProfile = vscode.workspace
.getConfiguration("mise")
.get("profile");

if (miseProfile) {
miseCommand = `${miseCommand} --profile ${miseProfile}`;
}
logger.info(`Executing mise command: ${miseCommand}`);
return execAsync(miseCommand, { cwd: this.workspaceRoot });
}
Expand Down Expand Up @@ -49,7 +57,6 @@ export class MiseService {
const { stdout } = await this.execMiseCommand(
"ls --current --offline --json",
);
logger.info(`Got stdout from mise ls 4 command ${stdout}`);
return Object.entries(JSON.parse(stdout)).flatMap(([toolName, tools]) => {
return (tools as MiseTool[]).map((tool) => {
return {
Expand Down
64 changes: 64 additions & 0 deletions src/utils/miseBinLocator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import * as fs from "node:fs/promises";
import * as os from "node:os";
import * as path from "node:path";
import * as vscode from "vscode";
import { logger } from "./logger";
import { execAsync } from "./shell";

export async function resolveMisePath(): Promise<string> {
const config = vscode.workspace.getConfiguration("mise");
const configuredPath = config.get<string>("binPath")?.trim();

if (configuredPath) {
if (await isValidBinary(configuredPath)) {
return configuredPath;
}
logger.warn(
`Configured mise path ${configuredPath} is invalid. Trying to resolve another path...`,
);
}

// Check if mise is in the PATH
const { stdout } = await execAsync("which mise").catch(() => ({
stdout: "",
}));
if (stdout) {
return stdout.trim();
}

// Check common installation locations
const homedir = os.homedir();
const commonPaths = [
path.join(homedir, ".local", "bin", "mise"), // ~/.local/bin/mise
"/usr/local/bin/mise", // Homebrew
"/opt/homebrew/bin/mise", // Homebrew
path.join(homedir, "bin", "mise"), // ~/bin/mise
];

const allPaths = [...commonPaths];

for (const binPath of allPaths) {
if (await isValidBinary(binPath)) {
return binPath;
}
}

throw new Error("Could not find mise binary in any standard location");
}

export async function isValidBinary(filepath: string): Promise<boolean> {
try {
const stats = await fs.stat(filepath);
const isExecutable = (stats.mode & fs.constants.X_OK) !== 0;
if (stats.isFile() && isExecutable) {
const { stdout } = await execAsync(`"${filepath}" --help`);
return stdout.toLowerCase().includes("mise");
}
} catch (error) {
logger.error(
`Path ${filepath} is not a valid mise binary:`,
error as Error,
);
}
return false;
}
22 changes: 22 additions & 0 deletions src/utils/notify.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import * as vscode from "vscode";

type Created = { type?: "info" | "error"; settingsKey?: string };

export async function showSettingsNotification(
message: string,
{ type = "info", settingsKey = "mise." }: Created = {},
) {
const notifyFn =
type === "error"
? vscode.window.showErrorMessage
: vscode.window.showInformationMessage;

const action = "Configure";
const selection = await notifyFn(message, action);
if (selection === action) {
vscode.commands.executeCommand(
"workbench.action.openSettings",
settingsKey,
);
}
}
4 changes: 4 additions & 0 deletions src/utils/shell.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { exec } from "node:child_process";
import { promisify } from "node:util";

export const execAsync = promisify(exec);

0 comments on commit 7d2b193

Please sign in to comment.