From f4b91fe87f30ab3dde1e954ec5b36e1cffa9177f Mon Sep 17 00:00:00 2001 From: Volodymyr Herashchenko Date: Tue, 18 Nov 2025 15:59:40 +0200 Subject: [PATCH 01/11] change installation instructions for lsp --- lsp/README.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lsp/README.md b/lsp/README.md index 5cf0e129..3d3955fb 100644 --- a/lsp/README.md +++ b/lsp/README.md @@ -22,12 +22,10 @@ Language Server for [SimplicityHL language](https://simplicity-lang.org/). ## Installation -Clone this repository and install using Cargo: +Install Language Server using `cargo`: ```bash -https://github.com/distributed-lab/simplicityhl-lsp -cd simplicityhl-lsp -cargo install --path . +cargo install simplicityhl-lsp ``` ## Integration with editors From 7c09cd39e53f6593011ff6eaf002b3d52d2e7403 Mon Sep 17 00:00:00 2001 From: Volodymyr Herashchenko Date: Tue, 18 Nov 2025 17:26:22 +0200 Subject: [PATCH 02/11] add "Install server" option in notification --- vscode/src/find_server.ts | 69 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 65 insertions(+), 4 deletions(-) diff --git a/vscode/src/find_server.ts b/vscode/src/find_server.ts index c57fdccb..01db2612 100644 --- a/vscode/src/find_server.ts +++ b/vscode/src/find_server.ts @@ -2,8 +2,9 @@ import * as cp from "child_process"; import * as fs from "fs"; import * as path from "path"; import * as os from "os"; -import { env, Uri, window, workspace } from "vscode"; +import { env, ProgressLocation, Uri, window, workspace } from "vscode"; import process from "node:process"; +import { spawn } from "node:child_process"; function findExecutable(command: string): string | null { try { @@ -51,6 +52,55 @@ function findExecutable(command: string): string | null { return null; } +async function installServer(command: string) { + const cargoExe = findExecutable("cargo"); + if (!cargoExe) { + throw new Error("Unable to find 'cargo'. Please ensure Rust is installed and in your PATH."); + } + + return window.withProgress({ + location: ProgressLocation.Notification, + title: `Installing ${command}`, + cancellable: true + }, async (progress, token) => { + return new Promise((resolve, reject) => { + const installProcess = spawn(cargoExe!, ["install", "--color", "never", command]); + + token.onCancellationRequested(() => { + installProcess.kill("SIGTERM"); + reject(new Error("Installation canceled")); + }); + + const reportProgress = (data: Buffer) => { + const lines = data.toString() + .split(/\r?\n/) + .map(l => l.trim()) + + for (const line of lines) { + if (line.startsWith("Compiling") && line !== "Compiling") { + progress.report({ message: line }); + } + } + }; + + installProcess.stderr?.on('data', reportProgress); + + installProcess.on('close', (code) => { + if (code === 0) { + resolve(); + } else { + reject(new Error(`Installation failed with exit code ${code}`)); + } + }); + + installProcess.on('error', (err) => { + reject(new Error(`Failed to start cargo process: ${err.message}`)); + }); + }); + }); +} + + export async function ensureExecutable( command: string, ): Promise { @@ -65,13 +115,24 @@ export async function ensureExecutable( if (!exePath && !suppressWarning) { const choice = await window.showWarningMessage( `LSP server "${command}" was not found in PATH or common locations. To use language server feautures, please install server to PATH`, + "Install server", "Learn more", "Don't show again", - "Close", ); - if (choice === "Learn more") { - const url = "https://github.com/distributed-lab/simplicityhl-lsp"; + if (choice === "Install server") { + try { + await installServer(command); + + window.showInformationMessage("Language server installed successfully!"); + return ensureExecutable(command); + } catch (err) { + window.showErrorMessage(`Failed to install language server: ${err}`); + return null; + } + } + else if (choice === "Learn more") { + const url = "https://github.com/BlockstreamResearch/SimplicityHL/tree/master/lsp#installation"; await env.openExternal(Uri.parse(url)); } else if (choice === "Don't show again") { const config = workspace.getConfiguration("simplicityhl"); From b43808960524facc5ef800b93818947578497e73 Mon Sep 17 00:00:00 2001 From: Volodymyr Herashchenko Date: Tue, 18 Nov 2025 17:31:46 +0200 Subject: [PATCH 03/11] bump vscode extension version to 0.2.2 --- vscode/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vscode/package.json b/vscode/package.json index 130f4a3b..331f5be5 100644 --- a/vscode/package.json +++ b/vscode/package.json @@ -2,7 +2,7 @@ "name": "simplicityhl", "displayName": "SimplicityHL Language Support", "description": "Syntax highlighting and autocompletion for SimplicityHL (Simfony) language", - "version": "0.2.1", + "version": "0.2.2", "publisher": "Blockstream", "repository": { "type": "git", From 2980c20d8f9b4678bfcf07db2b5a0963c5671fdb Mon Sep 17 00:00:00 2001 From: Volodymyr Herashchenko Date: Wed, 19 Nov 2025 11:51:04 +0200 Subject: [PATCH 04/11] change server installation process to automatic --- vscode/src/find_server.ts | 54 +++++++++++++++++---------------------- 1 file changed, 24 insertions(+), 30 deletions(-) diff --git a/vscode/src/find_server.ts b/vscode/src/find_server.ts index 01db2612..9c1f2f1e 100644 --- a/vscode/src/find_server.ts +++ b/vscode/src/find_server.ts @@ -53,23 +53,20 @@ function findExecutable(command: string): string | null { } async function installServer(command: string) { - const cargoExe = findExecutable("cargo"); - if (!cargoExe) { + const cargoPath = findExecutable("cargo"); + if (!cargoPath) { throw new Error("Unable to find 'cargo'. Please ensure Rust is installed and in your PATH."); } + let action = findExecutable(command) ? "Updating" : "Installing"; + return window.withProgress({ - location: ProgressLocation.Notification, - title: `Installing ${command}`, - cancellable: true - }, async (progress, token) => { + location: ProgressLocation.Window, + title: `${action} ${command}`, + cancellable: false + }, async (progress) => { return new Promise((resolve, reject) => { - const installProcess = spawn(cargoExe!, ["install", "--color", "never", command]); - - token.onCancellationRequested(() => { - installProcess.kill("SIGTERM"); - reject(new Error("Installation canceled")); - }); + const installProcess = spawn(cargoPath!, ["install", "--color", "never", command]); const reportProgress = (data: Buffer) => { const lines = data.toString() @@ -104,7 +101,7 @@ async function installServer(command: string) { export async function ensureExecutable( command: string, ): Promise { - const exePath = findExecutable(command); + const cargoPath = findExecutable("cargo"); const config = workspace.getConfiguration("simplicityhl"); const suppressWarning = config.get( @@ -112,27 +109,15 @@ export async function ensureExecutable( false, ); - if (!exePath && !suppressWarning) { + if (!cargoPath && !suppressWarning) { const choice = await window.showWarningMessage( - `LSP server "${command}" was not found in PATH or common locations. To use language server feautures, please install server to PATH`, - "Install server", + `To use SimplicityHL language server, please install cargo`, "Learn more", "Don't show again", ); - if (choice === "Install server") { - try { - await installServer(command); - - window.showInformationMessage("Language server installed successfully!"); - return ensureExecutable(command); - } catch (err) { - window.showErrorMessage(`Failed to install language server: ${err}`); - return null; - } - } - else if (choice === "Learn more") { - const url = "https://github.com/BlockstreamResearch/SimplicityHL/tree/master/lsp#installation"; + if (choice === "Learn more") { + const url = "https://rust-lang.org/tools/install"; await env.openExternal(Uri.parse(url)); } else if (choice === "Don't show again") { const config = workspace.getConfiguration("simplicityhl"); @@ -141,5 +126,14 @@ export async function ensureExecutable( return null; } - return exePath; + + if (cargoPath) { + try { + await installServer(command); + return findExecutable(command); + } catch (err) { + window.showErrorMessage(err); + return null; + } + } } From 1166f7371cc8b5e1c830d8a2bd7a1d3a54eeda17 Mon Sep 17 00:00:00 2001 From: Volodymyr Herashchenko Date: Wed, 19 Nov 2025 11:55:16 +0200 Subject: [PATCH 05/11] eslint: change `let` to `const` --- vscode/src/find_server.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vscode/src/find_server.ts b/vscode/src/find_server.ts index 9c1f2f1e..6ef8fee4 100644 --- a/vscode/src/find_server.ts +++ b/vscode/src/find_server.ts @@ -57,7 +57,7 @@ async function installServer(command: string) { if (!cargoPath) { throw new Error("Unable to find 'cargo'. Please ensure Rust is installed and in your PATH."); } - let action = findExecutable(command) ? "Updating" : "Installing"; + const action = findExecutable(command) ? "Updating" : "Installing"; return window.withProgress({ From 90deb28eaa497622917c86ad2efee636cc7e6866 Mon Sep 17 00:00:00 2001 From: Kyryl R Date: Wed, 19 Nov 2025 12:10:23 +0200 Subject: [PATCH 06/11] Linting. Ran npm install. --- vscode/package-lock.json | 4 ++-- vscode/src/find_server.ts | 14 +++++++------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/vscode/package-lock.json b/vscode/package-lock.json index e908eed6..f5681bb3 100644 --- a/vscode/package-lock.json +++ b/vscode/package-lock.json @@ -1,12 +1,12 @@ { "name": "simplicityhl", - "version": "0.2.0", + "version": "0.2.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "simplicityhl", - "version": "0.2.0", + "version": "0.2.2", "license": "MIT", "dependencies": { "vscode-languageclient": "^9.0.1" diff --git a/vscode/src/find_server.ts b/vscode/src/find_server.ts index 6ef8fee4..39371d93 100644 --- a/vscode/src/find_server.ts +++ b/vscode/src/find_server.ts @@ -1,10 +1,11 @@ -import * as cp from "child_process"; +import * as os from "os"; import * as fs from "fs"; import * as path from "path"; -import * as os from "os"; -import { env, ProgressLocation, Uri, window, workspace } from "vscode"; + import process from "node:process"; -import { spawn } from "node:child_process"; +import * as cp from "child_process"; + +import { env, ProgressLocation, Uri, window, workspace } from "vscode"; function findExecutable(command: string): string | null { try { @@ -57,8 +58,8 @@ async function installServer(command: string) { if (!cargoPath) { throw new Error("Unable to find 'cargo'. Please ensure Rust is installed and in your PATH."); } - const action = findExecutable(command) ? "Updating" : "Installing"; + const action = findExecutable(command) ? "Updating" : "Installing"; return window.withProgress({ location: ProgressLocation.Window, @@ -66,7 +67,7 @@ async function installServer(command: string) { cancellable: false }, async (progress) => { return new Promise((resolve, reject) => { - const installProcess = spawn(cargoPath!, ["install", "--color", "never", command]); + const installProcess = cp.spawn(cargoPath!, ["install", "--color", "never", command]); const reportProgress = (data: Buffer) => { const lines = data.toString() @@ -97,7 +98,6 @@ async function installServer(command: string) { }); } - export async function ensureExecutable( command: string, ): Promise { From 9203a40c8b8ffc2ba1c9bac4e8e0881a0612466a Mon Sep 17 00:00:00 2001 From: Volodymyr Herashchenko Date: Wed, 19 Nov 2025 12:21:30 +0200 Subject: [PATCH 07/11] change install to show in notification --- vscode/src/find_server.ts | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/vscode/src/find_server.ts b/vscode/src/find_server.ts index 39371d93..4b2f3e63 100644 --- a/vscode/src/find_server.ts +++ b/vscode/src/find_server.ts @@ -62,13 +62,18 @@ async function installServer(command: string) { const action = findExecutable(command) ? "Updating" : "Installing"; return window.withProgress({ - location: ProgressLocation.Window, + location: ProgressLocation.Notification, title: `${action} ${command}`, - cancellable: false - }, async (progress) => { + cancellable: true + }, async (progress, token) => { return new Promise((resolve, reject) => { const installProcess = cp.spawn(cargoPath!, ["install", "--color", "never", command]); + token.onCancellationRequested(() => { + installProcess.kill("SIGTERM"); + reject(new Error("Installation canceled")); + }); + const reportProgress = (data: Buffer) => { const lines = data.toString() .split(/\r?\n/) From 6e994dc385c923dcf9b1da98fb0bbf95561d6ef5 Mon Sep 17 00:00:00 2001 From: Volodymyr Herashchenko Date: Wed, 19 Nov 2025 13:19:01 +0200 Subject: [PATCH 08/11] fix: ensure server is installed before restarting previously, restarting the server after uninstalling `simplicityhl-lsp` caused an error, because the extension attempted to launch a missing executable. this change ensures that server is checking that this executable is present and install otherwise. --- vscode/src/client.ts | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/vscode/src/client.ts b/vscode/src/client.ts index 975c75b3..96471262 100644 --- a/vscode/src/client.ts +++ b/vscode/src/client.ts @@ -53,11 +53,12 @@ export class LspClient { } } - public stop(): Thenable | undefined { + public async stop(): Promise { if (!this.client) { - return undefined; + return; } - return this.client.stop(); + await this.client.stop(); + this.client = undefined; } public async restart(): Promise { @@ -67,8 +68,8 @@ export class LspClient { } try { - await this.client.stop(); - await this.client.start(); + await this.stop(); + await this.start(); window.showInformationMessage("SimplicityHL Language Server restarted successfully!"); } catch (e) { window.showErrorMessage(`Failed to restart LSP: ${e}`); From a3a210fdbd2accdfd38f25f927bc5e8c9d704147 Mon Sep 17 00:00:00 2001 From: Volodymyr Herashchenko Date: Wed, 19 Nov 2025 13:25:10 +0200 Subject: [PATCH 09/11] add option for disabling autoupdates Installing the server via `cargo` overrides the local installation, even if it has a higher version. This is problematic if we want to test the LSP server inside VSCode, so now there option in settings to disable autoupdate. --- vscode/package.json | 5 +++++ vscode/src/find_server.ts | 36 +++++++++++++++++++++++++----------- 2 files changed, 30 insertions(+), 11 deletions(-) diff --git a/vscode/package.json b/vscode/package.json index 331f5be5..d27de9d3 100644 --- a/vscode/package.json +++ b/vscode/package.json @@ -67,6 +67,11 @@ "type": "boolean", "default": false, "description": "Do not show missing LSP executable warning." + }, + "simplicityhl.disableAutoupdate": { + "type": "boolean", + "default": false, + "description": "Do not autoupdate LSP server." } } }, diff --git a/vscode/src/find_server.ts b/vscode/src/find_server.ts index 4b2f3e63..ce202923 100644 --- a/vscode/src/find_server.ts +++ b/vscode/src/find_server.ts @@ -109,12 +109,17 @@ export async function ensureExecutable( const cargoPath = findExecutable("cargo"); const config = workspace.getConfiguration("simplicityhl"); - const suppressWarning = config.get( - "suppressMissingLspWarning", - false, - ); + let serverPath = findExecutable(command); + + if (!cargoPath && !serverPath) { + const suppressWarning = config.get( + "suppressMissingLspWarning", + false, + ); + if (suppressWarning) { + return null; + } - if (!cargoPath && !suppressWarning) { const choice = await window.showWarningMessage( `To use SimplicityHL language server, please install cargo`, "Learn more", @@ -133,12 +138,21 @@ export async function ensureExecutable( } if (cargoPath) { - try { - await installServer(command); - return findExecutable(command); - } catch (err) { - window.showErrorMessage(err); - return null; + const disableAutoupdate = config.get("disableAutoupdate", false); + + const shouldInstallOrUpdate = (!serverPath) || !disableAutoupdate; + + if (shouldInstallOrUpdate) { + try { + await installServer(command); + + serverPath = findExecutable(command); + } catch (err) { + window.showErrorMessage(err); + return null; + } } } + + return serverPath; } From d9781c77ca69079d476225c88dace728bf156e5b Mon Sep 17 00:00:00 2001 From: Volodymyr Herashchenko <119609754+gerau@users.noreply.github.com> Date: Wed, 19 Nov 2025 13:47:17 +0200 Subject: [PATCH 10/11] apply suggestion for find_server.ts Co-authored-by: Kyrylo Riabov --- vscode/src/find_server.ts | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/vscode/src/find_server.ts b/vscode/src/find_server.ts index ce202923..1cfa290b 100644 --- a/vscode/src/find_server.ts +++ b/vscode/src/find_server.ts @@ -137,21 +137,23 @@ export async function ensureExecutable( return null; } - if (cargoPath) { - const disableAutoupdate = config.get("disableAutoupdate", false); - - const shouldInstallOrUpdate = (!serverPath) || !disableAutoupdate; + if (!cargoPath) { + return serverPath; + } + + const disableAutoupdate = config.get("disableAutoupdate", false); + + if (!serverPath || !disableAutoupdate) { + return serverPath; + } - if (shouldInstallOrUpdate) { - try { - await installServer(command); + try { + await installServer(command); - serverPath = findExecutable(command); - } catch (err) { - window.showErrorMessage(err); - return null; - } - } + serverPath = findExecutable(command); + } catch (err) { + window.showErrorMessage(err); + return null; } return serverPath; From 237deb5be5459bcf08d6361d9e1ec479a4f97379 Mon Sep 17 00:00:00 2001 From: Volodymyr Herashchenko Date: Wed, 19 Nov 2025 13:52:51 +0200 Subject: [PATCH 11/11] fmt + fix boolean logic issue --- vscode/src/find_server.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/vscode/src/find_server.ts b/vscode/src/find_server.ts index 1cfa290b..cc1af06f 100644 --- a/vscode/src/find_server.ts +++ b/vscode/src/find_server.ts @@ -138,13 +138,13 @@ export async function ensureExecutable( } if (!cargoPath) { - return serverPath; + return serverPath; } - + const disableAutoupdate = config.get("disableAutoupdate", false); - - if (!serverPath || !disableAutoupdate) { - return serverPath; + + if (serverPath && disableAutoupdate) { + return serverPath; } try {