Skip to content

Commit

Permalink
Add Show Parsed Tokens as Warnings toggle and enable client logging (#40
Browse files Browse the repository at this point in the history
)

* add showParsedTokensAsWarnings flag and client logging

* formatting
  • Loading branch information
JoshuaBatty authored Apr 7, 2022
1 parent 7e4a2d1 commit cb318c3
Show file tree
Hide file tree
Showing 4 changed files with 195 additions and 37 deletions.
97 changes: 97 additions & 0 deletions client/src/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import * as vscode from "vscode";
import { log } from "./util";

export class Config {
readonly extensionId = "fuellabs.sway-vscode-plugin";
readonly rootSection = "sway-lsp";
private readonly requiresReloadOpts = ["debug"].map(
(opt) => `${this.rootSection}.${opt}`
);

readonly package: {
version: string;
} = vscode.extensions.getExtension(this.extensionId)!.packageJSON;

readonly globalStorageUri: vscode.Uri;

constructor(ctx: vscode.ExtensionContext) {
this.globalStorageUri = ctx.globalStorageUri;
vscode.workspace.onDidChangeConfiguration(
this.onDidChangeConfiguration,
this,
ctx.subscriptions
);
this.refreshLogging();
}

private refreshLogging() {
log.setEnabled(this.traceExtension);
log.info("Starting the Sway Language Client and Server");
log.info("Extension version:", this.package.version);

const cfg = Object.entries(this.cfg).filter(
([_, val]) => !(val instanceof Function)
);
log.info("Using configuration", Object.fromEntries(cfg));
}

private async onDidChangeConfiguration(
event: vscode.ConfigurationChangeEvent
) {
this.refreshLogging();

const requiresReloadOpt = this.requiresReloadOpts.find((opt) =>
event.affectsConfiguration(opt)
);

if (!requiresReloadOpt) return;

const userResponse = await vscode.window.showInformationMessage(
`Changing "${requiresReloadOpt}" requires a reload`,
"Reload now"
);

if (userResponse === "Reload now") {
await vscode.commands.executeCommand("workbench.action.reloadWindow");
}
}

// We don't do runtime config validation here for simplicity. More on stackoverflow:
// https://stackoverflow.com/questions/60135780/what-is-the-best-way-to-type-check-the-configuration-for-vscode-extension

private get cfg(): vscode.WorkspaceConfiguration {
return vscode.workspace.getConfiguration(this.rootSection);
}

/**
* Beware that postfix `!` operator erases both `null` and `undefined`.
* This is why the following doesn't work as expected:
*
* ```ts
* const nullableNum = vscode
* .workspace
* .getConfiguration
* .getConfiguration("sway-lsp")
* .get<number | null>(path)!;
*
* // What happens is that type of `nullableNum` is `number` but not `null | number`:
* const fullFledgedNum: number = nullableNum;
* ```
* So this getter handles this quirk by not requiring the caller to use postfix `!`
*/
private get<T>(path: string): T {
return this.cfg.get<T>(path)!;
}

get traceExtension() {
return this.get<boolean>("trace.extension");
}

get debug() {
return {
showParsedTokensAsWarnings: this.get<boolean>(
"debug.showParsedTokensAsWarnings"
),
};
}
}
71 changes: 35 additions & 36 deletions client/src/extension.ts → client/src/main.ts
Original file line number Diff line number Diff line change
@@ -1,34 +1,25 @@
import {
workspace,
ExtensionContext,
ExtensionMode,
WorkspaceConfiguration,
} from "vscode";

import {
Executable,
LanguageClient,
LanguageClientOptions,
ServerOptions,
TransportKind,
} from "vscode-languageclient/node";

let client: LanguageClient;

export function activate(context: ExtensionContext) {
client = new LanguageClient(
import * as vscode from "vscode";
import * as lc from "vscode-languageclient/node";
import { Config } from "./config";
import { log } from "./util";

let client: lc.LanguageClient;

export function activate(context: vscode.ExtensionContext) {
const config = new Config(context);

client = new lc.LanguageClient(
"sway-lsp",
"Sway Language Server",
getServerOptions(context),
getServerOptions(context, config),
getClientOptions()
);

// Start the client. This will also launch the server
console.log("Starting Client and Server");
client.start();

client.onReady().then((_) => {
console.log("Client has Connected to the Server successfully!");
log.info("Client has Connected to the Sway Language Server Successfully!");
});
}

Expand All @@ -39,24 +30,32 @@ export function deactivate(): Thenable<void> | undefined {
return client.stop();
}

function getServerOptions(context: ExtensionContext): ServerOptions {
const serverExecutable: Executable = {
function getServerOptions(
context: vscode.ExtensionContext,
config: Config
): lc.ServerOptions {
let args = ["lsp"];
if (config.debug.showParsedTokensAsWarnings) {
args.push(" --parsed-tokens-as-warnings");
}

const serverExecutable: lc.Executable = {
command: "forc",
args: ["lsp"],
args,
options: {
shell: true,
},
};

const devServerOptions: ServerOptions = {
const devServerOptions: lc.ServerOptions = {
run: serverExecutable,
debug: serverExecutable,
transport: TransportKind.stdio,
transport: lc.TransportKind.stdio,
};

switch (context.extensionMode) {
case ExtensionMode.Development:
case ExtensionMode.Test:
case vscode.ExtensionMode.Development:
case vscode.ExtensionMode.Test:
return devServerOptions;

default:
Expand All @@ -65,9 +64,9 @@ function getServerOptions(context: ExtensionContext): ServerOptions {
}
}

function getClientOptions(): LanguageClientOptions {
function getClientOptions(): lc.LanguageClientOptions {
// Options to control the language client
const clientOptions: LanguageClientOptions = {
const clientOptions: lc.LanguageClientOptions = {
// Register the server for plain text documents
documentSelector: [
{ scheme: "file", language: "sway" },
Expand All @@ -76,8 +75,8 @@ function getClientOptions(): LanguageClientOptions {
synchronize: {
// Notify the server about file changes to *.sw files contained in the workspace
fileEvents: [
workspace.createFileSystemWatcher("**/.sw"),
workspace.createFileSystemWatcher("**/*.sw"),
vscode.workspace.createFileSystemWatcher("**/.sw"),
vscode.workspace.createFileSystemWatcher("**/*.sw"),
],
},
initializationOptions: {
Expand Down Expand Up @@ -115,9 +114,9 @@ function getSwayConfigOptions(): SwayConfig {
}
}

function getSwayFormattingOptions(): WorkspaceConfiguration | null {
const swayOptions = workspace.getConfiguration("sway");
const swayOptionsBracket = workspace.getConfiguration("[sway]");
function getSwayFormattingOptions(): vscode.WorkspaceConfiguration | null {
const swayOptions = vscode.workspace.getConfiguration("sway");
const swayOptionsBracket = vscode.workspace.getConfiguration("[sway]");

if (swayOptions && swayOptions.format) {
if (swayOptionsBracket && swayOptionsBracket.format) {
Expand Down
47 changes: 47 additions & 0 deletions client/src/util.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import * as vscode from "vscode";
import { inspect } from "util";

export const log = new (class {
private enabled = true;
private readonly output =
vscode.window.createOutputChannel("Sway LSP Client");

setEnabled(yes: boolean): void {
log.enabled = yes;
}

// Hint: the type [T, ...T[]] means a non-empty array
debug(...msg: [unknown, ...unknown[]]): void {
if (!log.enabled) return;
log.write("DEBUG", ...msg);
}

info(...msg: [unknown, ...unknown[]]): void {
log.write("INFO", ...msg);
}

warn(...msg: [unknown, ...unknown[]]): void {
debugger;
log.write("WARN", ...msg);
}

error(...msg: [unknown, ...unknown[]]): void {
debugger;
log.write("ERROR", ...msg);
log.output.show(true);
}

private write(label: string, ...messageParts: unknown[]): void {
const message = messageParts.map(log.stringify).join(" ");
const dateTime = new Date().toLocaleString();
log.output.appendLine(`${label} [${dateTime}]: ${message}`);
}

private stringify(val: unknown): string {
if (typeof val === "string") return val;
return inspect(val, {
colors: false,
depth: 6, // heuristic
});
}
})();
17 changes: 16 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
"Snippets",
"Themes"
],
"main": "./client/out/extension",
"main": "./client/out/main",
"activationEvents": [
"onLanguage:sway"
],
Expand All @@ -45,7 +45,22 @@
"messages",
"verbose"
],
"enumDescriptions": [
"No traces",
"Error only",
"Full log"
],
"default": "off"
},
"sway-lsp.trace.extension": {
"description": "Enable logging of the Sway VS Code extension itself.",
"type": "boolean",
"default": false
},
"sway-lsp.debug.showParsedTokensAsWarnings": {
"markdownDescription": "Show successfully parsed tokens by the sway-lsp server as warnings. If set to false, sway-lsp will revert to only showing warnings and errors reported by the compiler.",
"default": false,
"type": "boolean"
}
}
},
Expand Down

0 comments on commit cb318c3

Please sign in to comment.