From 45ed358bbee2febc0bbfcd6525cce26fb263bda7 Mon Sep 17 00:00:00 2001 From: hardliner66 Date: Sun, 9 Mar 2025 17:03:43 +0100 Subject: read odin_command from ols.json to check if it exists --- editors/vscode/src/config.ts | 67 ++-- editors/vscode/src/extension.ts | 683 ++++++++++++++++++++-------------------- editors/vscode/src/toolchain.ts | 87 ++--- 3 files changed, 426 insertions(+), 411 deletions(-) (limited to 'editors/vscode/src') diff --git a/editors/vscode/src/config.ts b/editors/vscode/src/config.ts index af93db8..1950b2c 100644 --- a/editors/vscode/src/config.ts +++ b/editors/vscode/src/config.ts @@ -3,51 +3,52 @@ import { log } from "./util"; export class Config { - readonly extensionId = "danielgavin.ols"; - readonly rootSection = "ols"; + readonly extensionId = "danielgavin.ols"; + readonly rootSection = "ols"; readonly globalStorageUri: vscode.Uri; - readonly package: { - version: string; - releaseTag: string | null; - enableProposedApi: boolean | undefined; - } = vscode.extensions.getExtension(this.extensionId)!.packageJSON; + readonly package: { + version: string; + releaseTag: string | null; + enableProposedApi: boolean | undefined; + } = vscode.extensions.getExtension(this.extensionId)!.packageJSON; - constructor(ctx: vscode.ExtensionContext) { - this.globalStorageUri = ctx.globalStorageUri; - } + constructor(ctx: vscode.ExtensionContext) { + this.globalStorageUri = ctx.globalStorageUri; + } - private get cfg(): vscode.WorkspaceConfiguration { - return vscode.workspace.getConfiguration(this.rootSection); - } + private get cfg(): vscode.WorkspaceConfiguration { + return vscode.workspace.getConfiguration(this.rootSection); + } - get serverPath() { - return this.get("server.path") ?? this.get("serverPath"); - } + get serverPath() { + return this.get("server.path") ?? this.get("serverPath"); + } - get httpProxy() { - const httpProxy = vscode - .workspace - .getConfiguration('http') - .get("proxy")!; + get httpProxy() { + const httpProxy = vscode + .workspace + .getConfiguration('http') + .get("proxy")!; - return httpProxy || process.env["https_proxy"] || process.env["HTTPS_PROXY"]; - } + return httpProxy || process.env["https_proxy"] || process.env["HTTPS_PROXY"]; + } - private get(path: string): T { - return this.cfg.get(path)!; - } + private get(path: string): T { + return this.cfg.get(path)!; + } - get askBeforeDownload() { return this.get("updates.askBeforeDownload"); } + get askBeforeDownload() { return this.get("updates.askBeforeDownload"); } - get debugEngine() { return this.get("debug.engine"); } + get debugEngine() { return this.get("debug.engine"); } get askCreateOLS() { return this.get("prompt.AskCreateOLS"); } - public updateAskCreateOLS(ask: boolean) { - this.cfg.update("prompt.AskCreateOLS", ask, vscode.ConfigurationTarget.Global); - } - - collections: any [] = []; + public updateAskCreateOLS(ask: boolean) { + this.cfg.update("prompt.AskCreateOLS", ask, vscode.ConfigurationTarget.Global); + } + + collections: any[] = []; + odinCommand: string = null; } diff --git a/editors/vscode/src/extension.ts b/editors/vscode/src/extension.ts index ae776f8..0d1f578 100644 --- a/editors/vscode/src/extension.ts +++ b/editors/vscode/src/extension.ts @@ -1,5 +1,5 @@ /* - HIGHLY inspired by the wonderful rust-analyzer, and contains modification of code from rust-analyzer vscode extension. + HIGHLY inspired by the wonderful rust-analyzer, and contains modification of code from rust-analyzer vscode extension. */ import * as vscode from 'vscode'; @@ -10,9 +10,9 @@ import { promises as fs, constants, writeFileSync} from "fs"; var AdmZip = require('adm-zip'); import { - LanguageClient, - LanguageClientOptions, - ServerOptions + LanguageClient, + LanguageClientOptions, + ServerOptions } from 'vscode-languageclient/node'; import { log, assert, isValidExecutable } from './util'; @@ -28,429 +28,436 @@ import { watchOlsConfigFile } from './watch'; const onDidChange: vscode.EventEmitter = new vscode.EventEmitter(); const defaultConfig = JSON.stringify( - { - $schema: "https://raw.githubusercontent.com/DanielGavin/ols/master/misc/ols.schema.json", - enable_document_symbols: true, - enable_hover: true, - enable_snippets: true - }, - null, - 4, + { + $schema: "https://raw.githubusercontent.com/DanielGavin/ols/master/misc/ols.schema.json", + enable_document_symbols: true, + enable_hover: true, + enable_snippets: true + }, + null, + 4, ); let ctx: Ctx; export async function activate(context: vscode.ExtensionContext) { - const config = new Config(context); - const state = new PersistentState(context.globalState); + const config = new Config(context); + const state = new PersistentState(context.globalState); - log.setEnabled(true); + log.setEnabled(true); - const serverPath = await bootstrap(config, state).catch(err => { - let message = "bootstrap error. "; + const serverPath = await bootstrap(config, state).catch(err => { + let message = "bootstrap error. "; - if (err.code === "EBUSY" || err.code === "ETXTBSY" || err.code === "EPERM") { - message += "Other vscode windows might be using ols, "; - message += "you should close them and reload this window to retry. "; - } + if (err.code === "EBUSY" || err.code === "ETXTBSY" || err.code === "EPERM") { + message += "Other vscode windows might be using ols, "; + message += "you should close them and reload this window to retry. "; + } - log.error("Bootstrap error", err); - throw new Error(message); - }); + log.error("Bootstrap error", err); + throw new Error(message); + }); - const workspaceFolder = vscode.workspace.workspaceFolders?.[0]; + const workspaceFolder = vscode.workspace.workspaceFolders?.[0]; - if (workspaceFolder === undefined) { - throw new Error("no folder is opened"); - } + if (workspaceFolder === undefined) { + throw new Error("no folder is opened"); + } - const codeLensProvider = new RunnableCodeLensProvider( - onDidChange, - ); + const codeLensProvider = new RunnableCodeLensProvider( + onDidChange, + ); - const disposable = vscode.languages.registerCodeLensProvider( - { scheme: "file", language: "odin" }, - codeLensProvider - ); + const disposable = vscode.languages.registerCodeLensProvider( + { scheme: "file", language: "odin" }, + codeLensProvider + ); - context.subscriptions.push( - vscode.workspace.onDidChangeConfiguration(e => { - codeLensProvider.updateArgs(); - }) - ); + context.subscriptions.push( + vscode.workspace.onDidChangeConfiguration(e => { + codeLensProvider.updateArgs(); + }) + ); - context.subscriptions.push(disposable); + context.subscriptions.push(disposable); - if (!serverPath) { - vscode.window.showErrorMessage("Failed to find ols executable!"); - return; - } + if (!serverPath) { + vscode.window.showErrorMessage("Failed to find ols executable!"); + return; + } - let serverOptions: ServerOptions = { - command: serverPath, - args: [], - options: { - cwd: path.dirname(serverPath), - }, - }; + let serverOptions: ServerOptions = { + command: serverPath, + args: [], + options: { + cwd: path.dirname(serverPath), + }, + }; - let clientOptions: LanguageClientOptions = { - documentSelector: [{ scheme: 'file', language: 'odin' }], - outputChannel: vscode.window.createOutputChannel("Odin Language Server") - }; + let clientOptions: LanguageClientOptions = { + documentSelector: [{ scheme: 'file', language: 'odin' }], + outputChannel: vscode.window.createOutputChannel("Odin Language Server") + }; - var client = new LanguageClient( - 'ols', - 'Odin Language Server Client', - serverOptions, - clientOptions - ); + var client = new LanguageClient( + 'ols', + 'Odin Language Server Client', + serverOptions, + clientOptions + ); - ctx = await Ctx.create(config, client, context, serverPath, workspaceFolder.uri.fsPath); + ctx = await Ctx.create(config, client, context, serverPath, workspaceFolder.uri.fsPath); - ctx.registerCommand("runDebugTest", runDebugTest); - ctx.registerCommand("runTest", runTest); + ctx.registerCommand("runDebugTest", runDebugTest); + ctx.registerCommand("runTest", runTest); - const projectConfigPath = path.join(workspaceFolder.uri.fsPath, "ols.json"); - const userConfigPath = path.join(path.dirname(serverPath), "ols.json"); + const projectConfigPath = path.join(workspaceFolder.uri.fsPath, "ols.json"); + const userConfigPath = path.join(path.dirname(serverPath), "ols.json"); - fs.access(projectConfigPath, constants.F_OK).catch(async (_e1) => { + fs.access(projectConfigPath, constants.F_OK).catch(async (_e1) => { fs.access(userConfigPath, constants.F_OK).catch( async (_e2) => { - if (!config.askCreateOLS) { - return; - } - - const userResponse = await vscode.window.showInformationMessage( - "No ols config file found. Do you wish to create one?", - "Yes", - "No", - "Don't ask again", - ); - - if (userResponse === "Yes") { - const clarification = await vscode.window.showInformationMessage( - "should it be specific to this project or to all your odin projects?", - "This project", - "All projects", - ); - if (clarification == "This project") { - createOrEditProjectConfig(); - parseOlsFile(config, projectConfigPath); - } else { - createOrEditUserConfig(serverPath); - parseOlsFile(config, userConfigPath); - } - } else if (userResponse === "Don't ask again") { - config.updateAskCreateOLS(false); - return; - } - }) - }); - - if(!isOdinInstalled()) { - vscode.window.showErrorMessage("Odin cannot be found in your path environment. Please install Odin or add it into your path environment before going any further: [Install](https://odin-lang.org/docs/install/)."); - } - - vscode.commands.registerCommand("ols.start", () => { - client.start(); - }); - - vscode.commands.registerCommand("ols.stop", async () => { - await client.stop(); - }); - - vscode.commands.registerCommand("ols.restart", async () => { - await client.stop(); - client.start(); - }); + if (!config.askCreateOLS) { + return; + } + + const userResponse = await vscode.window.showInformationMessage( + "No ols config file found. Do you wish to create one?", + "Yes", + "No", + "Don't ask again", + ); + + if (userResponse === "Yes") { + const clarification = await vscode.window.showInformationMessage( + "should it be specific to this project or to all your odin projects?", + "This project", + "All projects", + ); + if (clarification == "This project") { + createOrEditProjectConfig(); + parseOlsFile(config, projectConfigPath); + } else { + createOrEditUserConfig(serverPath); + parseOlsFile(config, userConfigPath); + } + } else if (userResponse === "Don't ask again") { + config.updateAskCreateOLS(false); + return; + } + }) + }); + + // parse ols file first, so we can pass it to "isOdinInstalled" + // in order to check if the path to odin was defined in the ols file + await parseOlsFile(config, projectConfigPath); + + if (!isOdinInstalled(config)) { + vscode.window.showErrorMessage("Odin cannot be found in your path environment. Please install Odin or add it into your path environment before going any further: [Install](https://odin-lang.org/docs/install/)."); + } + + vscode.commands.registerCommand("ols.start", () => { + client.start(); + }); + + vscode.commands.registerCommand("ols.stop", async () => { + await client.stop(); + }); + + vscode.commands.registerCommand("ols.restart", async () => { + await client.stop(); + client.start(); + }); vscode.commands.registerCommand("ols.editProjectConfig", async() => { - createOrEditProjectConfig(); - }); + createOrEditProjectConfig(); + }); - vscode.commands.registerCommand("ols.editUserConfig", async () => { - createOrEditUserConfig(serverPath); - }); + vscode.commands.registerCommand("ols.editUserConfig", async () => { + createOrEditUserConfig(serverPath); + }); - client.start(); + client.start(); - parseOlsFile(config, projectConfigPath); - watchOlsConfigFile(ctx, projectConfigPath); + watchOlsConfigFile(ctx, projectConfigPath); } async function bootstrap(config: Config, state: PersistentState): Promise { - await fs.mkdir(config.globalStorageUri.fsPath, { recursive: true }); + await fs.mkdir(config.globalStorageUri.fsPath, { recursive: true }); - const path = await bootstrapServer(config, state); + const path = await bootstrapServer(config, state); - await removeOldServers(config, state); + await removeOldServers(config, state); - return path; + return path; } async function bootstrapServer(config: Config, state: PersistentState): Promise { - const path = await getServer(config, state); - if (!path) { - throw new Error( - "ols is not available. " + - "Please, ensure its [installed](https://github.com/DanielGavin/ols/#installation)." - ); - } - - log.info("Using server binary at", path); - - /* - TODO(add version) - if (!isValidExecutable(path)) { - throw new Error(`Failed to execute ${path} --version`); - } - */ - - return path; + const path = await getServer(config, state); + if (!path) { + throw new Error( + "ols is not available. " + + "Please, ensure its [installed](https://github.com/DanielGavin/ols/#installation)." + ); + } + + log.info("Using server binary at", path); + + /* + TODO(add version) + if (!isValidExecutable(path)) { + throw new Error(`Failed to execute ${path} --version`); + } + */ + + return path; } async function removeOldServers(config: Config, state: PersistentState): Promise { - if (process.platform != "win32") { - // only on windows, releases are put into their separate folders, so no cleanup needed - return; - } - const releasesFolder = config.globalStorageUri.fsPath; - - // get list of all old releases - const currentRelease = state.releaseId?.toString() ?? "" - const releases = (await fs.readdir(releasesFolder, { withFileTypes: true })) - .filter(dirent => dirent.isDirectory() && dirent.name != currentRelease) - .map(dirent => dirent.name) - - // try to delete all old releases - for (const release of releases) { - try { - let pathToRemove = path.join(releasesFolder, release) - if (release[0] !== '_') { - // windows: rename path first to ensure it is not in use anymore - const renamedPath = path.join(releasesFolder, '_' + release) - await fs.rename(pathToRemove, renamedPath) - pathToRemove = renamedPath - } - fs.rm(pathToRemove, { recursive: true, force: true }) - } catch { - // ignore if the release can't be renamed/removed, probably still in use - continue; - } - } + if (process.platform != "win32") { + // only on windows, releases are put into their separate folders, so no cleanup needed + return; + } + const releasesFolder = config.globalStorageUri.fsPath; + + // get list of all old releases + const currentRelease = state.releaseId?.toString() ?? "" + const releases = (await fs.readdir(releasesFolder, { withFileTypes: true })) + .filter(dirent => dirent.isDirectory() && dirent.name != currentRelease) + .map(dirent => dirent.name) + + // try to delete all old releases + for (const release of releases) { + try { + let pathToRemove = path.join(releasesFolder, release) + if (release[0] !== '_') { + // windows: rename path first to ensure it is not in use anymore + const renamedPath = path.join(releasesFolder, '_' + release) + await fs.rename(pathToRemove, renamedPath) + pathToRemove = renamedPath + } + fs.rm(pathToRemove, { recursive: true, force: true }) + } catch { + // ignore if the release can't be renamed/removed, probably still in use + continue; + } + } } export function createOrEditProjectConfig() { - const projectConfigPath = vscode.workspace.workspaceFolders![0].uri.fsPath; - openFileAndCreateIfNotExists("ols.json", projectConfigPath, defaultConfig); + const projectConfigPath = vscode.workspace.workspaceFolders![0].uri.fsPath; + openFileAndCreateIfNotExists("ols.json", projectConfigPath, defaultConfig); } export function createOrEditUserConfig(serverPath: string) { - const userConfigPath = path.dirname(serverPath); - openFileAndCreateIfNotExists("ols.json", userConfigPath, defaultConfig); + const userConfigPath = path.dirname(serverPath); + openFileAndCreateIfNotExists("ols.json", userConfigPath, defaultConfig); } function openFileAndCreateIfNotExists(file: string, folder: string, defaultContents: string) { - const filePath = path.join(folder, file); - console.log(filePath); - - vscode.workspace.openTextDocument(filePath).then( - (document) => { vscode.window.showTextDocument(document) }, - () => { - writeFileSync(filePath, defaultContents); - vscode.workspace.openTextDocument(filePath).then( - (document) => { vscode.window.showTextDocument(document) } - ); - } - ); - + const filePath = path.join(folder, file); + console.log(filePath); + + vscode.workspace.openTextDocument(filePath).then( + (document) => { vscode.window.showTextDocument(document) }, + () => { + writeFileSync(filePath, defaultContents); + vscode.workspace.openTextDocument(filePath).then( + (document) => { vscode.window.showTextDocument(document) } + ); + } + ); + } export async function parseOlsFile(config: Config, file: string) { - /* - We have to parse the collections that they have specificed through the json(This will be changed when odin gets it's own builder files) - */ - fs.readFile(file).then( - (data) => { - const conf = JSON.parse(data.toString()); - config.collections = conf.collections; - }, - (error) => { - console.info("no ols.json found in workspace"); - }, - ); + /* + We have to parse the collections that they have specificed through the json(This will be changed when odin gets it's own builder files) + */ + await fs.readFile(file).then( + (data) => { + const conf = JSON.parse(data.toString()); + config.collections = conf.collections; + if (conf.hasOwnProperty("odin_command")) { + config.odinCommand = conf.odin_command; + } + + }, + (error) => { + console.info("no ols.json found in workspace"); + }, + ); } function serverPath(config: Config): string | null { - return config.serverPath; + return config.serverPath; } async function getServer(config: Config, state: PersistentState): Promise { - const explicitPath = serverPath(config); - if (explicitPath) { - if (explicitPath.startsWith("~/")) { - return os.homedir() + explicitPath.slice("~".length); - } - return explicitPath; - }; - - const platforms: { [key: string]: string } = { - "x64 win32": "x86_64-pc-windows-msvc", - "x64 linux": "x86_64-unknown-linux-gnu", - "x64 darwin": "x86_64-darwin", - "arm64 darwin": "arm64-darwin" - }; - - let platform = platforms[`${process.arch} ${process.platform}`]; - - if (platform === undefined) { - await vscode.window.showErrorMessage( - "Unfortunately we don't ship binaries for your platform yet. " + - "You need to manually clone ols, build it, set the ols.server.path to the executable" - ); - return undefined; - } - - /* - if (platform === "x86_64-unknown-linux-gnu" && isMusl()) { - platform = "x86_64-unknown-linux-musl"; - } - */ - - const isWindows = platform.indexOf("-windows-") !== -1; - const ext = isWindows ? ".exe" : ""; - // use a separate folder for each release on windows because we can't overwrite files while they are still in use - const getDestFolder = (releaseId: number | undefined) => path.join(config.globalStorageUri.fsPath, (releaseId ?? 0).toString()); - const getExecutable = (releaseId: number | undefined) => path.join(getDestFolder(releaseId), `ols-${platform}${ext}`); - const zipFolder = config.globalStorageUri.fsPath; - const destExecutable = getExecutable(state.releaseId); - - const exists = await fs.stat(destExecutable).then(() => true, () => false); - - if (!exists) { - await state.updateReleaseId(0); - } - - /* - Temp: right now it doesn't check for versions, since ols has no versioning right now - */ + const explicitPath = serverPath(config); + if (explicitPath) { + if (explicitPath.startsWith("~/")) { + return os.homedir() + explicitPath.slice("~".length); + } + return explicitPath; + }; + + const platforms: { [key: string]: string } = { + "x64 win32": "x86_64-pc-windows-msvc", + "x64 linux": "x86_64-unknown-linux-gnu", + "x64 darwin": "x86_64-darwin", + "arm64 darwin": "arm64-darwin" + }; + + let platform = platforms[`${process.arch} ${process.platform}`]; + + if (platform === undefined) { + await vscode.window.showErrorMessage( + "Unfortunately we don't ship binaries for your platform yet. " + + "You need to manually clone ols, build it, set the ols.server.path to the executable" + ); + return undefined; + } + + /* + if (platform === "x86_64-unknown-linux-gnu" && isMusl()) { + platform = "x86_64-unknown-linux-musl"; + } + */ + + const isWindows = platform.indexOf("-windows-") !== -1; + const ext = isWindows ? ".exe" : ""; + // use a separate folder for each release on windows because we can't overwrite files while they are still in use + const getDestFolder = (releaseId: number | undefined) => path.join(config.globalStorageUri.fsPath, (releaseId ?? 0).toString()); + const getExecutable = (releaseId: number | undefined) => path.join(getDestFolder(releaseId), `ols-${platform}${ext}`); + const zipFolder = config.globalStorageUri.fsPath; + const destExecutable = getExecutable(state.releaseId); + + const exists = await fs.stat(destExecutable).then(() => true, () => false); + + if (!exists) { + await state.updateReleaseId(0); + } + + /* + Temp: right now it doesn't check for versions, since ols has no versioning right now + */ if (exists && state.lastCheck !== undefined && state.lastCheck + (3 * 60 * 60 * 1000) > Date.now()) { - return destExecutable; - } + return destExecutable; + } - const release = await downloadWithRetryDialog(state, !exists, async () => { - return await fetchRelease("nightly", state.githubToken, config.httpProxy); - }); + const release = await downloadWithRetryDialog(state, !exists, async () => { + return await fetchRelease("nightly", state.githubToken, config.httpProxy); + }); - if (release === undefined || release.id === state.releaseId) { - await state.updateLastCheck(Date.now()); - return destExecutable; - } + if (release === undefined || release.id === state.releaseId) { + await state.updateLastCheck(Date.now()); + return destExecutable; + } - const userResponse = await vscode.window.showInformationMessage( - "New version of ols (nightly) is available (requires reload).", - "Update" - ); + const userResponse = await vscode.window.showInformationMessage( + "New version of ols (nightly) is available (requires reload).", + "Update" + ); - if (userResponse !== "Update") { - return destExecutable; - } + if (userResponse !== "Update") { + return destExecutable; + } - const artifact = release.assets.find(artifact => artifact.name === `ols-${platform}.zip`); - assert(!!artifact, `Bad release: ${JSON.stringify(release)}`); + const artifact = release.assets.find(artifact => artifact.name === `ols-${platform}.zip`); + assert(!!artifact, `Bad release: ${JSON.stringify(release)}`); - const destZip = path.join(zipFolder, `ols-${platform}.zip`); + const destZip = path.join(zipFolder, `ols-${platform}.zip`); - await downloadWithRetryDialog(state, true, async () => { - await download({ - url: artifact.browser_download_url, - dest: destZip, - progressTitle: "Downloading ols", - httpProxy: config.httpProxy, - }); - }); + await downloadWithRetryDialog(state, true, async () => { + await download({ + url: artifact.browser_download_url, + dest: destZip, + progressTitle: "Downloading ols", + httpProxy: config.httpProxy, + }); + }); - var zip = new AdmZip(destZip); + var zip = new AdmZip(destZip); - const latestDestFolder = getDestFolder(release.id); - const latestExecutable = getExecutable(release.id); + const latestDestFolder = getDestFolder(release.id); + const latestExecutable = getExecutable(release.id); - if (!await fs.stat(latestDestFolder).then(() => true, () => false)) { - await fs.mkdir(latestDestFolder) - } + if (!await fs.stat(latestDestFolder).then(() => true, () => false)) { + await fs.mkdir(latestDestFolder) + } - zip.extractAllTo(latestDestFolder, true); + zip.extractAllTo(latestDestFolder, true); - if (ext !== ".exe") { - fs.chmod(latestExecutable, 0o755); - } + if (ext !== ".exe") { + fs.chmod(latestExecutable, 0o755); + } - await state.updateServerVersion(config.package.version); - await state.updateReleaseId(release.id); - await state.updateLastCheck(Date.now()); - await vscode.commands.executeCommand("workbench.action.reloadWindow"); + await state.updateServerVersion(config.package.version); + await state.updateReleaseId(release.id); + await state.updateLastCheck(Date.now()); + await vscode.commands.executeCommand("workbench.action.reloadWindow"); - return latestExecutable; + return latestExecutable; } async function downloadWithRetryDialog(state: PersistentState, required: boolean, downloadFunc: () => Promise): Promise { - while (true) { - try { - return await downloadFunc(); - } catch (e) { - const selected = await vscode.window.showErrorMessage("Failed to download: " + e.message, {}, { - title: "Update Github Auth Token", - updateToken: true, - }, { - title: "Retry download", - retry: true, - }, { - title: "Dismiss", - }); - - if (selected?.updateToken) { - await queryForGithubToken(state); - continue; - } else if (selected?.retry) { - continue; - } else if (!required) { - return; - } - throw e; - }; - } + while (true) { + try { + return await downloadFunc(); + } catch (e) { + const selected = await vscode.window.showErrorMessage("Failed to download: " + e.message, {}, { + title: "Update Github Auth Token", + updateToken: true, + }, { + title: "Retry download", + retry: true, + }, { + title: "Dismiss", + }); + + if (selected?.updateToken) { + await queryForGithubToken(state); + continue; + } else if (selected?.retry) { + continue; + } else if (!required) { + return; + } + throw e; + }; + } } async function queryForGithubToken(state: PersistentState): Promise { - const githubTokenOptions: vscode.InputBoxOptions = { - value: state.githubToken, - password: true, - prompt: ` + const githubTokenOptions: vscode.InputBoxOptions = { + value: state.githubToken, + password: true, + prompt: ` This dialog allows to store a Github authorization token. The usage of an authorization token will increase the rate limit on the use of Github APIs and can thereby prevent getting throttled. Auth tokens can be created at https://github.com/settings/tokens`, - }; - - const newToken = await vscode.window.showInputBox(githubTokenOptions); - if (newToken === undefined) { - // The user aborted the dialog => Do not update the stored token - return; - } - - if (newToken === "") { - log.info("Clearing github token"); - await state.updateGithubToken(undefined); - } else { - log.info("Storing new github token"); - await state.updateGithubToken(newToken); - } + }; + + const newToken = await vscode.window.showInputBox(githubTokenOptions); + if (newToken === undefined) { + // The user aborted the dialog => Do not update the stored token + return; + } + + if (newToken === "") { + log.info("Clearing github token"); + await state.updateGithubToken(undefined); + } else { + log.info("Storing new github token"); + await state.updateGithubToken(newToken); + } } export function deactivate(): Thenable { - return ctx!.client.stop(); + return ctx!.client.stop(); } diff --git a/editors/vscode/src/toolchain.ts b/editors/vscode/src/toolchain.ts index 3a559de..d62f6ba 100644 --- a/editors/vscode/src/toolchain.ts +++ b/editors/vscode/src/toolchain.ts @@ -4,60 +4,67 @@ import * as path from "path"; import * as fs from "fs"; import { execute, log, memoize } from './util'; +import { Config } from "./config"; -export function isOdinInstalled(): boolean { - return getPathForExecutable("odin") !== ""; +export function isOdinInstalled(config: Config): boolean { + return vscode.workspace.workspaceFolders?.some(folder => { + if (config.odinCommand) { + let command = path.isAbsolute(config.odinCommand) ? config.odinCommand : + path.join(folder.uri.fsPath, config.odinCommand); + return isFile(command) && fs.existsSync(command); + } + }) || getPathForExecutable("odin") !== ""; } export const getPathForExecutable = memoize( - // We apply caching to decrease file-system interactions - (executableName: "odin"): string => { - { - const envVar = process.env[executableName.toUpperCase()]; - if (envVar) { + // We apply caching to decrease file-system interactions + (executableName: "odin"): string => { + { + const envVar = process.env[executableName.toUpperCase()]; + if (envVar) { return envVar; } - } + } - const path = lookupInPath(executableName); - if (path != undefined) { + const path = lookupInPath(executableName); + if (path != undefined) { return path; } - return ""; - } + return ""; + } ); function lookupInPath(exec: string): string | undefined { - const paths = process.env.PATH ?? ""; - - const candidates = paths.split(path.delimiter).flatMap(dirInPath => { - const candidate = path.join(dirInPath, exec); - return os.type() === "Windows_NT" - ? [candidate, `${candidate}.exe`] - : [candidate]; - }); - - for (let i = 0; i < candidates.length; i += 1) { - try { - const pathToOdin = fs.realpathSync(candidates[i]); - if (!!pathToOdin) { - return pathToOdin; - } - } catch (realpathError) { - console.debug("couldn't find odin at", candidates[i], "on account of", realpathError) - } - } - - return undefined; + const paths = process.env.PATH ?? ""; + + const candidates = paths.split(path.delimiter).flatMap(dirInPath => { + const candidate = path.join(dirInPath, exec); + return os.type() === "Windows_NT" + ? [candidate, `${candidate}.exe`] + : [candidate]; + }); + + for (let i = 0; i < candidates.length; i += 1) { + try { + const pathToOdin = fs.realpathSync(candidates[i]); + if (!!pathToOdin) { + return pathToOdin; + } + } catch (realpathError) { + console.debug("couldn't find odin at", candidates[i], "on account of", realpathError) + } + } + + return undefined; } function isFile(suspectPath: string): boolean { - // It is not mentionned in docs, but `statSync()` throws an error when - // the path doesn't exist - try { - return fs.statSync(suspectPath).isFile(); - } catch { - return false; - } + // It is not mentionned in docs, but `statSync()` throws an error when + // the path doesn't exist + try { + return fs.statSync(suspectPath).isFile(); + } catch { + return false; + } } \ No newline at end of file -- cgit v1.2.3