From 8126b78db2a1e4fcd0aafd1cdfdf7c01ce228230 Mon Sep 17 00:00:00 2001 From: Joe Kralicky Date: Wed, 19 Jun 2024 19:00:49 -0400 Subject: [PATCH] vscode: add prompt to install if binary is missing --- editors/vscode/client/src/client.ts | 63 ++++++++++++++++++++++++-- editors/vscode/client/src/extension.ts | 9 +++- go.mod | 2 +- go.sum | 4 +- 4 files changed, 70 insertions(+), 8 deletions(-) diff --git a/editors/vscode/client/src/client.ts b/editors/vscode/client/src/client.ts index a715e31..81f7caf 100644 --- a/editors/vscode/client/src/client.ts +++ b/editors/vscode/client/src/client.ts @@ -10,6 +10,8 @@ import { ServerOptions, TransportKind, } from "vscode-languageclient/node" +import semver = require("semver") +import fs = require("fs") export class ProtolsLanguageClient extends LanguageClient @@ -50,6 +52,13 @@ async function lookPath(cmd: string): Promise { } } +async function findProtolsBinary(): Promise { + return ( + (await lookPath("protols")) || + path.join(process.env.HOME, "go", "bin", "protols") + ) +} + export async function buildLanguageClient( context: vscode.ExtensionContext, ): Promise { @@ -63,9 +72,14 @@ export async function buildLanguageClient( .get("alternateBinaryPath") if (!binaryPath) { - binaryPath = - (await lookPath("protols")) || - path.join(process.env.HOME, "go", "bin", "protols") + binaryPath = await findProtolsBinary() + } + if (!binaryExists(binaryPath)) { + if (await promptInstall()) { + binaryPath = await findProtolsBinary() + } else { + throw new Error("protols binary not found") + } } const c = new ProtolsLanguageClient( "protobuf", @@ -85,6 +99,9 @@ export async function buildLanguageClient( outputChannel: vscode.window.createOutputChannel( "Protobuf Language Server", ), + connectionOptions: { + maxRestartCount: 1, + }, markdown: { isTrusted: true, supportHtml: true, @@ -93,3 +110,43 @@ export async function buildLanguageClient( ) return c } + +const protolsToolInfo = { + name: "protols", + importPath: "github.com/kralicky/protols/cmd/protols", + modulePath: "github.com/kralicky/protols", + description: "Protobuf Language Server", + minimumGoVersion: semver.coerce("1.22"), +} + +async function promptInstall(): Promise { + const selected = await vscode.window.showInformationMessage( + `${protolsToolInfo.name} not found in $PATH. Install it with "go install"?`, + "Install", + "Cancel", + ) + if (selected !== "Install") { + return false + } + try { + await vscode.commands.executeCommand("go.tools.install", [protolsToolInfo]) + return true + } catch (error) { + vscode.window.showErrorMessage( + `Failed to install ${protolsToolInfo.name}: ${error}`, + ) + return false + } +} + +function binaryExists(path: string): boolean { + try { + fs.accessSync( + path, + fs.constants.F_OK | fs.constants.R_OK | fs.constants.X_OK, + ) + return true + } catch { + return false + } +} diff --git a/editors/vscode/client/src/extension.ts b/editors/vscode/client/src/extension.ts index 5f7edc2..8eb5f4c 100644 --- a/editors/vscode/client/src/extension.ts +++ b/editors/vscode/client/src/extension.ts @@ -1,14 +1,19 @@ import * as vscode from "vscode" import { LanguageClient } from "vscode-languageclient/node" import { ASTViewer, fromProtoAstUri } from "./astviewer" -import { buildLanguageClient } from "./client" +import { ProtolsLanguageClient, buildLanguageClient } from "./client" import { initCommands } from "./commands" import { Location } from "vscode-languageserver-types" let client: LanguageClient export async function activate(context: vscode.ExtensionContext) { - const client = await buildLanguageClient(context) + let client: ProtolsLanguageClient + try { + client = await buildLanguageClient(context) + } catch { + return + } vscode.workspace.registerTextDocumentContentProvider("proto", client) // Start the client. This will also launch the server client.start() diff --git a/go.mod b/go.mod index e44e13a..b9c4b3a 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/google/uuid v1.6.0 github.com/kralicky/codegen v0.0.0-20240522012557-5193d3fdbeca github.com/kralicky/gpkg v0.0.0-20240119195700-64f32830b14f - github.com/kralicky/protocompile v0.0.0-20240619180838-57d9401fcbbc + github.com/kralicky/protocompile v0.0.0-20240619225839-bdb3c73b0a9f github.com/kralicky/tools-lite v0.0.0-20240313161632-60bfa88304ff github.com/mattn/go-tty v0.0.5 github.com/mitchellh/mapstructure v1.5.0 diff --git a/go.sum b/go.sum index 4116c22..f4c1015 100644 --- a/go.sum +++ b/go.sum @@ -45,8 +45,8 @@ github.com/kralicky/go-adaptive-radix-tree v0.0.0-20240619012453-a8f80032ba31 h1 github.com/kralicky/go-adaptive-radix-tree v0.0.0-20240619012453-a8f80032ba31/go.mod h1:oJwexVSshEat0E3evyKOH6QzN8GFWrhLvEoh8GiJzss= github.com/kralicky/gpkg v0.0.0-20240119195700-64f32830b14f h1:MsNe8A51V+7Fu5OMXSl8SK02erPJ40vFs2zDHn89w1g= github.com/kralicky/gpkg v0.0.0-20240119195700-64f32830b14f/go.mod h1:vOkwMjs49XmP/7Xfo9ZL6eg2ei51lmtD/4U/Az5GTq8= -github.com/kralicky/protocompile v0.0.0-20240619180838-57d9401fcbbc h1:3TJx3pjKKcYN/VARYk4tgeQQI03m23VneHLk1csdUoE= -github.com/kralicky/protocompile v0.0.0-20240619180838-57d9401fcbbc/go.mod h1:aE9D9loDNucSzYmT854laAVbgGQwGOckiSXYuwAJJSI= +github.com/kralicky/protocompile v0.0.0-20240619225839-bdb3c73b0a9f h1:qC7Xkx8Kq5wgiN2fo+1zLXVWhZfMWC6DHVgv+mCh7gA= +github.com/kralicky/protocompile v0.0.0-20240619225839-bdb3c73b0a9f/go.mod h1:aE9D9loDNucSzYmT854laAVbgGQwGOckiSXYuwAJJSI= github.com/kralicky/tools-lite v0.0.0-20240313161632-60bfa88304ff h1:akxm/czMYHdr1xIGm6wmddABmc4M9KDcqksdwpIJx8A= github.com/kralicky/tools-lite v0.0.0-20240313161632-60bfa88304ff/go.mod h1:V8GGYRLr40bvX/W3nZFxG+6S3iDFWn6o5J3NGDClr8U= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=