diff --git a/vscode-cairo/package.json b/vscode-cairo/package.json index db468746422..7228362eb20 100644 --- a/vscode-cairo/package.json +++ b/vscode-cairo/package.json @@ -135,6 +135,12 @@ }, "default": {}, "markdownDescription": "Extra environment variables that will be passed to the `cairo-language-server` executable.\nUseful for passing e.g. `CAIRO_LS_LOG` for debugging." + }, + "cairo1.showInStatusBar": { + "type": "boolean", + "default": true, + "description": "Show CairoLS information in the status bar.", + "scope": "window" } } } diff --git a/vscode-cairo/src/config.ts b/vscode-cairo/src/config.ts index 1a644e1fa5c..1f0dc89b7e1 100644 --- a/vscode-cairo/src/config.ts +++ b/vscode-cairo/src/config.ts @@ -3,6 +3,7 @@ import * as vscode from "vscode"; interface ConfigProps { enableLanguageServer: boolean; + showInStatusBar: boolean; languageServerPath: string; enableScarb: boolean; preferScarbLanguageServer: boolean; diff --git a/vscode-cairo/src/context.ts b/vscode-cairo/src/context.ts index 80d60d63209..527397f9015 100644 --- a/vscode-cairo/src/context.ts +++ b/vscode-cairo/src/context.ts @@ -1,6 +1,7 @@ import * as vscode from "vscode"; import { Config } from "./config"; import { RootLogOutputChannel } from "./logging"; +import { StatusBar } from "./statusBar"; export class Context { public static create(extensionContext: vscode.ExtensionContext): Context { @@ -9,15 +10,19 @@ export class Context { log: true, }), ); + extensionContext.subscriptions.push(log); return new Context(extensionContext, log); } public readonly config: Config = new Config(); + public readonly statusBar: StatusBar; private constructor( public readonly extension: vscode.ExtensionContext, public readonly log: RootLogOutputChannel, - ) {} + ) { + this.statusBar = new StatusBar(this); + } } diff --git a/vscode-cairo/src/extension.ts b/vscode-cairo/src/extension.ts index cc854169bf7..e216513b996 100644 --- a/vscode-cairo/src/extension.ts +++ b/vscode-cairo/src/extension.ts @@ -14,11 +14,14 @@ export async function activate(extensionContext: vscode.ExtensionContext) { ctx.log.warn("language server is disabled"); ctx.log.warn("note: set `cairo1.enableLanguageServer` to `true` to enable it"); } + + await ctx.statusBar.setup(client); } export function deactivate(): Thenable | undefined { if (!client) { return undefined; } + return client.stop(); } diff --git a/vscode-cairo/src/scarb.ts b/vscode-cairo/src/scarb.ts index 77add6a9158..8d1605192c2 100644 --- a/vscode-cairo/src/scarb.ts +++ b/vscode-cairo/src/scarb.ts @@ -87,6 +87,11 @@ export class Scarb implements LanguageServerExecutableProvider { return this.hasCommand("cairo-language-server", ctx); } + public async getVersion(ctx: Context): Promise { + const output = await this.execWithOutput(["--version"], ctx); + return output.trim(); + } + public async cacheClean(ctx: Context): Promise { await this.execWithOutput(["cache", "clean"], ctx); } diff --git a/vscode-cairo/src/statusBar.ts b/vscode-cairo/src/statusBar.ts new file mode 100644 index 00000000000..068b332450b --- /dev/null +++ b/vscode-cairo/src/statusBar.ts @@ -0,0 +1,80 @@ +import * as vscode from "vscode"; +import * as lc from "vscode-languageclient/node"; +import type { Context } from "./context"; +import { Scarb } from "./scarb"; + +const CAIRO_STATUS_BAR_COMMAND = "cairo1.statusBar.clicked"; + +export class StatusBar { + private statusBarItem: vscode.StatusBarItem; + + constructor(private readonly context: Context) { + this.statusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left, 100); + + this.context.extension.subscriptions.push(this.statusBarItem); + } + + public async setup(client?: lc.LanguageClient): Promise { + this.context.extension.subscriptions.push( + vscode.workspace.onDidChangeConfiguration(() => { + this.update(); + }), + ); + + this.context.extension.subscriptions.push( + vscode.commands.registerCommand(CAIRO_STATUS_BAR_COMMAND, () => { + if (client) { + client.outputChannel.show(); + } else { + vscode.window.showWarningMessage("Cairo Language Server is not active"); + } + }), + ); + + await this.initializeStatusBarItem(); + } + + private async initializeStatusBarItem(): Promise { + this.statusBarItem.command = CAIRO_STATUS_BAR_COMMAND; + this.statusBarItem.text = "Cairo"; + this.statusBarItem.tooltip = "Cairo Language"; + + await this.updateScarbVersion(); + } + + private async updateScarbVersion(): Promise { + try { + // TODO(mkaput): Support multi-root workspaces. + const scarb = await Scarb.find(vscode.workspace.workspaceFolders?.[0], this.context); + if (scarb) { + const version = await scarb.getVersion(this.context); + this.statusBarItem.tooltip = `Cairo Language\n${version}`; + } + } catch (error) { + this.context.log.error(`Error getting Scarb version: ${error}`); + } + } + + /** + * Updates the status bar item based on the current workspace configuration. + */ + private async update(): Promise { + const config = vscode.workspace.getConfiguration("cairo1"); + const showInStatusBar = config.get("showInStatusBar", true); + + if (showInStatusBar) { + await this.updateScarbVersion(); + this.showStatusBarItem(); + } else { + this.hideStatusBarItem(); + } + } + + public showStatusBarItem(): void { + this.statusBarItem.show(); + } + + public hideStatusBarItem(): void { + this.statusBarItem.hide(); + } +}