Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Language Status indicator #1547

Merged
merged 3 commits into from
Jul 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 18 additions & 13 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,12 @@ import { ShowReferencesFeature } from './features/showReferences';
import { CustomSemanticTokens } from './features/semanticTokens';
import { ModuleProvidersFeature } from './features/moduleProviders';
import { ModuleCallsFeature } from './features/moduleCalls';
import { TerraformVersionFeature } from './features/terraformVersion';
import { LanguageStatusFeature } from './features/languageStatus';
import { getInitializationOptions } from './settings';
import { TerraformLSCommands } from './commands/terraformls';
import { TerraformCommands } from './commands/terraform';
import { TerraformVersionFeature } from './features/terraformVersion';
import * as lsStatus from './status/language';

const id = 'terraform';
const brand = `HashiCorp Terraform`;
Expand Down Expand Up @@ -69,6 +71,7 @@ export async function activate(context: vscode.ExtensionContext): Promise<void>

const clientOptions: LanguageClientOptions = {
documentSelector: documentSelector,
progressOnInitialization: true,
synchronize: {
fileEvents: [
vscode.workspace.createFileSystemWatcher('**/*.tf'),
Expand Down Expand Up @@ -176,12 +179,22 @@ export async function activate(context: vscode.ExtensionContext): Promise<void>
client = new LanguageClient(id, serverOptions, clientOptions);
client.onDidChangeState((event) => {
outputChannel.appendLine(`Client: ${State[event.oldState]} --> ${State[event.newState]}`);
if (event.newState === State.Stopped) {
reporter.sendTelemetryEvent('stopClient');
switch (event.newState) {
case State.Starting:
lsStatus.setLanguageServerStarting();
break;
case State.Running:
lsStatus.setLanguageServerRunning();
break;
case State.Stopped:
lsStatus.setLanguageServerStopped();
reporter.sendTelemetryEvent('stopClient');
break;
}
});

client.registerFeatures([
new LanguageStatusFeature(client, reporter, outputChannel),
new CustomSemanticTokens(client, manifest),
new ModuleProvidersFeature(client, new ModuleProvidersDataProvider(context, client, reporter)),
new ModuleCallsFeature(client, new ModuleCallsDataProvider(context, client, reporter)),
Expand All @@ -194,17 +207,7 @@ export async function activate(context: vscode.ExtensionContext): Promise<void>
context.subscriptions.push(new GenerateBugReportCommand(context), new TerraformCommands(client, reporter));

try {
outputChannel.appendLine('Starting client');

await client.start();

reporter.sendTelemetryEvent('startClient');

const initializeResult = client.initializeResult;
if (initializeResult !== undefined) {
const multiFoldersSupported = initializeResult.capabilities.workspace?.workspaceFolders?.supported;
outputChannel.appendLine(`Multi-folder support: ${multiFoldersSupported}`);
}
} catch (error) {
await handleLanguageClientStartError(error, context, reporter);
}
Expand All @@ -218,10 +221,12 @@ export async function deactivate(): Promise<void> {
outputChannel.appendLine(error.message);
reporter.sendTelemetryException(error);
vscode.window.showErrorMessage(error.message);
lsStatus.setLanguageServerState(error.message, false, vscode.LanguageStatusSeverity.Error);
} else if (typeof error === 'string') {
outputChannel.appendLine(error);
reporter.sendTelemetryException(new Error(error));
vscode.window.showErrorMessage(error);
lsStatus.setLanguageServerState(error, false, vscode.LanguageStatusSeverity.Error);
}
}
}
49 changes: 49 additions & 0 deletions src/features/languageStatus.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: MPL-2.0
*/

import * as vscode from 'vscode';
import TelemetryReporter from '@vscode/extension-telemetry';
import { BaseLanguageClient, ClientCapabilities, FeatureState, StaticFeature } from 'vscode-languageclient';

import { ExperimentalClientCapabilities } from './types';
import * as lsStatus from '../status/language';

export class LanguageStatusFeature implements StaticFeature {
private disposables: vscode.Disposable[] = [];

constructor(
private client: BaseLanguageClient,
private reporter: TelemetryReporter,
private outputChannel: vscode.OutputChannel,
) {}

getState(): FeatureState {
return {
kind: 'static',
};
}

public fillClientCapabilities(capabilities: ClientCapabilities & ExperimentalClientCapabilities): void {
if (!capabilities['experimental']) {
capabilities['experimental'] = {};
}
}

public initialize(): void {
this.reporter.sendTelemetryEvent('startClient');
this.outputChannel.appendLine('Started client');

const initializeResult = this.client.initializeResult;
if (initializeResult === undefined) {
return;
}

lsStatus.setVersion(initializeResult.serverInfo?.version ?? '');
}

public dispose(): void {
this.disposables.forEach((d: vscode.Disposable) => d.dispose());
}
}
40 changes: 19 additions & 21 deletions src/features/terraformVersion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,35 +11,20 @@ import { ExperimentalClientCapabilities } from './types';
import { Utils } from 'vscode-uri';
import TelemetryReporter from '@vscode/extension-telemetry';
import { LanguageClient } from 'vscode-languageclient/node';
import * as lsStatus from '../status/language';
import * as versionStatus from '../status/installedVersion';
import * as requiredVersionStatus from '../status/requiredVersion';

export class TerraformVersionFeature implements StaticFeature {
private disposables: vscode.Disposable[] = [];

private clientTerraformVersionCommandId = 'client.refreshTerraformVersion';

private installedVersion = vscode.languages.createLanguageStatusItem('terraform.installedVersion', [
{ language: 'terraform' },
{ language: 'terraform-vars' },
]);
private requiredVersion = vscode.languages.createLanguageStatusItem('terraform.requiredVersion', [
{ language: 'terraform' },
{ language: 'terraform-vars' },
]);

constructor(
private client: LanguageClient,
private reporter: TelemetryReporter,
private outputChannel: vscode.OutputChannel,
) {
this.installedVersion.name = 'TerraformInstalledVersion';
this.installedVersion.detail = 'Installed Version';

this.requiredVersion.name = 'TerraformRequiredVersion';
this.requiredVersion.detail = 'Required Version';

this.disposables.push(this.installedVersion);
this.disposables.push(this.requiredVersion);
}
) {}

getState(): FeatureState {
return {
Expand Down Expand Up @@ -67,9 +52,18 @@ export class TerraformVersionFeature implements StaticFeature {
const moduleDir = Utils.dirname(editor.document.uri);

try {
versionStatus.setWaiting();
requiredVersionStatus.setWaiting();

lsStatus.setLanguageServerBusy();

const response = await terraform.terraformVersion(moduleDir.toString(), this.client, this.reporter);
this.installedVersion.text = response.discovered_version || 'unknown';
this.requiredVersion.text = response.required_version || 'any';
versionStatus.setVersion(response.discovered_version || 'unknown');
requiredVersionStatus.setVersion(response.required_version || 'any');

lsStatus.setLanguageServerRunning();
versionStatus.setReady();
requiredVersionStatus.setReady();
} catch (error) {
let message = 'Unknown Error';
if (error instanceof Error) {
Expand All @@ -86,6 +80,10 @@ export class TerraformVersionFeature implements StaticFeature {
see this errored here.
*/
this.outputChannel.appendLine(message);

lsStatus.setLanguageServerRunning();
versionStatus.setReady();
requiredVersionStatus.setReady();
}
});

Expand Down
25 changes: 25 additions & 0 deletions src/status/installedVersion.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: MPL-2.0
*/

import * as vscode from 'vscode';

const installedVersion = vscode.languages.createLanguageStatusItem('terraform.installedVersion', [
{ language: 'terraform' },
{ language: 'terraform-vars' },
]);
installedVersion.name = 'TerraformInstalledVersion';
installedVersion.detail = 'Terraform Installed';

export function setVersion(version: string) {
installedVersion.text = version;
}

export function setReady() {
installedVersion.busy = false;
}

export function setWaiting() {
installedVersion.busy = true;
}
50 changes: 50 additions & 0 deletions src/status/language.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: MPL-2.0
*/

import * as vscode from 'vscode';

const lsStatus = vscode.languages.createLanguageStatusItem('terraform-ls.status', [
{ language: 'terraform' },
{ language: 'terraform-vars' },
]);
lsStatus.name = 'Terraform LS';
lsStatus.detail = 'Terraform LS';

export function setVersion(version: string) {
lsStatus.text = version;
}

export function setLanguageServerRunning() {
lsStatus.busy = false;
}

export function setLanguageServerReady() {
lsStatus.busy = false;
}

export function setLanguageServerStarting() {
lsStatus.busy = true;
}

export function setLanguageServerBusy() {
lsStatus.busy = true;
}

export function setLanguageServerStopped() {
// this makes the statusItem a different color in the bar
// and triggers an alert, so the user 'sees' that the LS is stopped
lsStatus.severity = vscode.LanguageStatusSeverity.Warning;
lsStatus.busy = false;
}

export function setLanguageServerState(
detail: string,
busy: boolean,
severity: vscode.LanguageStatusSeverity = vscode.LanguageStatusSeverity.Information,
) {
lsStatus.busy = busy;
lsStatus.detail = detail;
lsStatus.severity = severity;
}
25 changes: 25 additions & 0 deletions src/status/requiredVersion.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: MPL-2.0
*/

import * as vscode from 'vscode';

const requiredVersion = vscode.languages.createLanguageStatusItem('terraform.requiredVersion', [
{ language: 'terraform' },
{ language: 'terraform-vars' },
]);
requiredVersion.name = 'TerraformRequiredVersion';
requiredVersion.detail = 'Terraform Required';

export function setVersion(version: string) {
requiredVersion.text = version;
}

export function setReady() {
requiredVersion.busy = false;
}

export function setWaiting() {
requiredVersion.busy = true;
}