diff --git a/squawk-vscode/README.md b/squawk-vscode/README.md index 6b6ccf2c..968c028c 100644 --- a/squawk-vscode/README.md +++ b/squawk-vscode/README.md @@ -6,10 +6,6 @@ Surface SQL related lint errors directly in VSCode. ## Install -Install via the [VSCode marketplace](https://marketplace.visualstudio.com/items?itemName=sbdchd.squawk). - -## Install - ### From online marketplace Open the [online marketplace listing](https://marketplace.visualstudio.com/items?itemName=sbdchd.squawk) for Squawk and click "Install". Follow the prompts to open VSCode and install Squawk. @@ -26,6 +22,15 @@ Download the extension package from the [latest Github release](https://github.c With `vsce` installed from NPM (`npm install -g @vscode/vsce`), clone [this repo](https://github.com/sbdchd/vscode-squawk) and run `vsce package`. Install the resulting package with `code --install-extension squawk-*.vsix` +## Settings + +```json +{ + // enable tracing logs + "squawk.trace.server": "verbose" +} +``` + ## Dev Make sure you're on a vscode version >= the one defined in the `package.json`, diff --git a/squawk-vscode/eslint.config.mjs b/squawk-vscode/eslint.config.mjs index 6cac8cfe..b3f2abeb 100644 --- a/squawk-vscode/eslint.config.mjs +++ b/squawk-vscode/eslint.config.mjs @@ -21,6 +21,7 @@ export default tseslint.config( plugins: {}, rules: { "no-console": "error", + "quotes": ["error", "double", { "avoidEscape": true }], "@typescript-eslint/no-unused-vars": [ "error", { diff --git a/squawk-vscode/src/extension.ts b/squawk-vscode/src/extension.ts index d8c688ae..1eb1148c 100644 --- a/squawk-vscode/src/extension.ts +++ b/squawk-vscode/src/extension.ts @@ -9,6 +9,65 @@ import { StateChangeEvent, } from "vscode-languageclient/node" +// via rust-analyzer +// https://github.com/rust-lang/rust-analyzer/blob/f14bf95931f17ae1830a77d6f0dff38cabb401da/editors/code/src/util.ts#L157C1-L157C1 +class LazyOutputChannel implements vscode.OutputChannel { + constructor(name: string) { + this.name = name + } + + name: string + _channel: vscode.OutputChannel | undefined + + get channel(): vscode.OutputChannel { + if (!this._channel) { + this._channel = vscode.window.createOutputChannel(this.name) + } + return this._channel + } + + append(value: string): void { + this.channel.append(value) + } + + appendLine(value: string): void { + this.channel.appendLine(value) + } + + replace(value: string): void { + this.channel.replace(value) + } + + clear(): void { + if (this._channel) { + this._channel.clear() + } + } + + show( + columnOrPreserveFocus?: vscode.ViewColumn | boolean, + preserveFocus?: boolean, + ): void { + if (typeof columnOrPreserveFocus === "boolean") { + this.channel.show(columnOrPreserveFocus) + } else { + this.channel.show(columnOrPreserveFocus, preserveFocus) + } + } + + hide(): void { + if (this._channel) { + this._channel.hide() + } + } + + dispose(): void { + if (this._channel) { + this._channel.dispose() + } + } +} + let client: LanguageClient | undefined let log: Pick< vscode.LogOutputChannel, @@ -144,7 +203,7 @@ function updateStatusBarItem(statusBarItem: vscode.StatusBarItem) { switch (client.state) { case State.Stopped: statusText = "Stopped" - icon = "$(error) " + icon = "$(stop-circle) " backgroundColor = new vscode.ThemeColor("statusBarItem.warningBackground") break case State.Starting: @@ -207,6 +266,7 @@ async function startServer(context: vscode.ExtensionContext) { const serverOptions: ServerOptions = serverExecutable const clientOptions: LanguageClientOptions = { documentSelector: [{ language: "sql" }, { language: "postgres" }], + traceOutputChannel: new LazyOutputChannel("Squawk Trace"), outputChannel: vscode.window.createOutputChannel("Squawk Language Server"), } client = new LanguageClient( @@ -228,7 +288,7 @@ async function startServer(context: vscode.ExtensionContext) { await client.start() log.info("server started successfully") } catch (error) { - log.error(`Failed to start server:`, error) + log.error("Failed to start server:", error) vscode.window.showErrorMessage(`Failed to start server: ${String(error)}`) } } @@ -307,10 +367,12 @@ class SyntaxTreeProvider implements vscode.TextDocumentContentProvider { try { const document = this._activeEditor?.document if (!document) { - return "Error: no active editor found" + vscode.window.showErrorMessage("Error: no active editor found") + return "" } if (!client) { - return "Error: no client found" + vscode.window.showErrorMessage("Error: no client found") + return "" } const uri = document.uri.toString() log.info(`Requesting syntax tree for: ${uri}`) @@ -320,8 +382,11 @@ class SyntaxTreeProvider implements vscode.TextDocumentContentProvider { log.info("Syntax tree received") return response } catch (error) { - log.error(`Failed to get syntax tree:`, error) - return `Error: Failed to get syntax tree: ${String(error)}` + log.error("Failed to get syntax tree:", error) + vscode.window.showErrorMessage( + `Failed to get syntax tree:\n${String(error)}`, + ) + return "" } } } @@ -378,10 +443,12 @@ class TokensProvider implements vscode.TextDocumentContentProvider { try { const document = this._activeEditor?.document if (!document) { - return "Error: no active editor found" + vscode.window.showErrorMessage("Error: no active editor found") + return "" } if (!client) { - return "Error: no client found" + vscode.window.showErrorMessage("Error: no client found") + return "" } const uri = document.uri.toString() log.info(`Requesting tokens for: ${uri}`) @@ -391,8 +458,11 @@ class TokensProvider implements vscode.TextDocumentContentProvider { log.info("Tokens received") return response } catch (error) { - log.error(`Failed to get tokens:`, error) - return `Error: Failed to get tokens: ${String(error)}` + log.error("Failed to get tokens:", error) + vscode.window.showErrorMessage( + `Error: Failed to get tokens:\n${String(error)}`, + ) + return "" } } }