Skip to content
This repository has been archived by the owner on Jul 3, 2024. It is now read-only.

Commit

Permalink
feat(solidity/extension): fmt cli wrapper and vscode linter integration
Browse files Browse the repository at this point in the history
  • Loading branch information
EnergyCube authored and 0xmemorygrinder committed Jan 9, 2024
1 parent 7898c10 commit da7106a
Show file tree
Hide file tree
Showing 3 changed files with 309 additions and 10 deletions.
21 changes: 19 additions & 2 deletions toolchains/solidity/extension/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,27 @@
"contributes": {
"commands": [
{
"command": "extension.helloWorld",
"title": "Hello World"
"command": "osmium.lint-sol-file",
"title": "Osmium: Lint Solidity File"
},
{
"command": "osmium.lint-sol-workspace",
"title": "Osmium: Lint Solidity Workspace"
},
{
"command": "osmium.lint-sol-file-from-explorer",
"title": "Osmium: Lint Solidity File"
}
],
"menus": {
"explorer/context": [
{
"when": "resourceLangId == solidity",
"command": "extension.lint-sol-file-from-explorer",
"group": "navigation"
}
]
},
"languages": [
{
"id": "solidity",
Expand Down
11 changes: 3 additions & 8 deletions toolchains/solidity/extension/src/extension.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
* ------------------------------------------------------------------------------------------ */

import * as path from 'path';
import { workspace, ExtensionContext } from 'vscode';
[]
import * as path from "path";
import { workspace, ExtensionContext, Uri } from "vscode";
import { TextDecoder } from "util";
import {
LanguageClient,
} from 'vscode-languageclient/node';
Expand Down
287 changes: 287 additions & 0 deletions toolchains/solidity/extension/src/fmt-wrapper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,287 @@
import { exec } from "child_process";
import * as vscode from "vscode";

type ForgeFmtOptions = {
root?: string; // Root is used to get fmt config from forge.toml
} & (
| {
check: true;
raw?: boolean;
}
| {
check?: false;
raw: false;
}
);

type ForgeFmtArgs = {
options: ForgeFmtOptions;
files: string[];
};

type ForgeFmtResult = {
exitCode: number;
output: string;
};

function isFmtInstalled(): boolean {
try {
exec("forge fmt --version", (error, _stdout, _stderr) => {
if (error) {
throw error;
}
});
return true;
} catch (error) {
return false;
}
}

function forgeFmt(
args: ForgeFmtArgs,
debug?: boolean
): Promise<ForgeFmtResult> {
const { options, files } = args;
const { root, check, raw } = options;

const commandArgs = ["fmt"];

if (root) {
commandArgs.push("--root", root);
}

if (check) {
commandArgs.push("--check");
}

if (raw) {
commandArgs.push("--raw");
}

commandArgs.push(...files);

const command = `forge ${commandArgs.join(" ")}`;

if (debug) {
console.debug(command);
}

return new Promise((resolve, reject) => {
exec(command, (error, stdout, _stderr) => {
if (error && !check) {
reject(error);
} else {
resolve({
exitCode: 0,
output: stdout,
});
}
});
});
}

function registerForgeFmtLinter(context: vscode.ExtensionContext) {
const lintSolFromExplorer = vscode.commands.registerCommand(
"osmium.lint-sol-file-from-explorer",
function (uri) {
if (!isFmtInstalled()) {
vscode.window.showErrorMessage(
"Forge fmt is not installed. Please install it and try again."
);
return;
}

const options: ForgeFmtOptions = {
root: vscode.workspace.workspaceFolders?.[0].uri.fsPath,
check: false,
raw: false,
};

const args: ForgeFmtArgs = {
options,
files: [uri.fsPath],
};

forgeFmt(args)
.then((result) => {
if (result.exitCode === 0) {
vscode.window.showInformationMessage("Forge fmt ran successfully.");
} else {
vscode.window.showErrorMessage(
"Forge fmt failed. Please check the output for details."
);

console.log(result.output);
}
})
.catch((error) => {
vscode.window.showErrorMessage(
"Forge fmt failed. Please check the output for details."
);
console.error(error);
});
}
);

const lintSolFile = vscode.commands.registerCommand(
"osmium.lint-sol-file",
function () {
if (!isFmtInstalled()) {
vscode.window.showErrorMessage(
"Forge fmt is not installed. Please install it and try again."
);
return;
}

// Get the active text editor
const editor = vscode.window.activeTextEditor;

if (editor) {
const document = editor.document;

if (
document.languageId !== "solidity" &&
editor.document.fileName.split(".").pop() !== "sol"
) {
vscode.window.showErrorMessage(
"Forge fmt is only available for solidity files."
);
return;
}

const options: ForgeFmtOptions = {
root: vscode.workspace.workspaceFolders?.[0].uri.fsPath,
check: false,
raw: false,
};

const args: ForgeFmtArgs = {
options,
files: [document.fileName],
};

forgeFmt(args)
.then((result) => {
if (result.exitCode === 0) {
vscode.window.showInformationMessage(
"Forge fmt ran successfully."
);
} else {
vscode.window.showErrorMessage(
"Forge fmt failed. Please check the output for details."
);

console.log(result.output);
}
})
.catch((error) => {
vscode.window.showErrorMessage(
"Forge fmt failed. Please check the output for details."
);
console.error(error);
});
} else {
vscode.window.showErrorMessage(
"Forge fmt is only available for solidity files."
);
}
}
);

const lintSolWorkspace = vscode.commands.registerCommand(
"osmium.lint-sol-workspace",
function () {
if (!isFmtInstalled()) {
vscode.window.showErrorMessage(
"Forge fmt is not installed. Please install it and try again."
);
return;
}

if (!vscode.workspace.workspaceFolders?.[0]) {
vscode.window.showErrorMessage(
"Unable to find workspace root. Please open a folder and try again."
);
return;
}

const options: ForgeFmtOptions = {
root: vscode.workspace.workspaceFolders?.[0].uri.fsPath,
check: false,
raw: false,
};

const args: ForgeFmtArgs = {
options,
files: [vscode.workspace.workspaceFolders?.[0].uri.fsPath],
};

forgeFmt(args, true)
.then((result) => {
if (result.exitCode === 0) {
vscode.window.showInformationMessage("Forge fmt ran successfully.");
} else {
vscode.window.showErrorMessage(
"Forge fmt failed. Please check the output for details."
);

console.log(result.output);
}
})
.catch((error) => {
vscode.window.showErrorMessage(
"Forge fmt failed. Please check the output for details."
);
console.error(error);
});
}
);

const linter = vscode.languages.registerDocumentFormattingEditProvider(
"solidity",
{
provideDocumentFormattingEdits: (document) => {
if (!isFmtInstalled()) {
vscode.window.showErrorMessage(
"Forge fmt is not installed. Please install it and try again."
);
return;
}

const options: ForgeFmtOptions = {
root: vscode.workspace.workspaceFolders?.[0].uri.fsPath,
check: false,
raw: false,
};

const args: ForgeFmtArgs = {
options,
files: [document.fileName],
};

return forgeFmt(args).then((result) => {
if (result.exitCode === 0) {
vscode.window.showInformationMessage("Forge fmt ran successfully.");
} else {
vscode.window.showErrorMessage(
"Forge fmt failed. Please check the output for details."
);

console.log(result.output);
}

return [];
});
},
}
);

context.subscriptions.push(lintSolFromExplorer);

context.subscriptions.push(lintSolFile);
context.subscriptions.push(lintSolWorkspace);

context.subscriptions.push(linter);
}

export default registerForgeFmtLinter;

0 comments on commit da7106a

Please sign in to comment.