From 8ad44334d82c5fea14df2844e9f7040f0f28d69e Mon Sep 17 00:00:00 2001 From: koniifer Date: Fri, 8 Nov 2024 21:49:10 +0000 Subject: [PATCH] 0.2.1, bug fixes and new match new compiler --- package.json | 13 ++- src/main.ts | 218 ++++++++++++++++++++++---------------------- tests/dont-erase.hb | 3 + 3 files changed, 122 insertions(+), 112 deletions(-) create mode 100644 tests/dont-erase.hb diff --git a/package.json b/package.json index 9432b28..67cfb3f 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,18 @@ } } } - ] + ], + "configuration": { + "title": "hblang", + "properties": { + "hblang.compilerPath": { + "type": "string", + "default": "PATH", + "description": "Set the optional path for the hbc compiler. If set to 'PATH', it will rely on the system to provide hbc.", + "scope": "machine-overridable" + } + } + } }, "scripts": { "vscode:prepublish": "webpack", diff --git a/src/main.ts b/src/main.ts index 7f48e3b..0984059 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,124 +1,120 @@ -import * as vscode from 'vscode'; -import { execFile } from 'child_process'; -import * as fs from 'fs'; -import * as path from 'path'; - -vscode.languages.registerDocumentFormattingEditProvider('hblang', { - async provideDocumentFormattingEdits(document: vscode.TextDocument): Promise { - const filePath = document.uri.fsPath; - const tempFilePath = path.join(path.dirname(filePath), `temp_${path.basename(filePath)}`); - - try { - await fs.promises.writeFile(tempFilePath, document.getText()); - - const stdout = await new Promise((resolve, reject) => { - execFile('hbc', ['--fmt-stdout', tempFilePath], (error, stdout, stderr) => { - if (error) { - if (error.code === 'ENOENT') { - vscode.window.showErrorMessage("hblang compiler not found. ensure 'hbc' is installed and available in PATH."); - } else { - vscode.window.showErrorMessage(`error formatting document with hbc: ${stderr || `exit code: ${error.code}`}`); - } - return reject(new Error(stderr || `exit code: ${error.code}`)); - } - resolve(stdout); - }); - }); - - const fullRange = new vscode.Range( - document.positionAt(0), - document.positionAt(document.getText().length) - ); - const edit = vscode.TextEdit.replace(fullRange, stdout); - return [edit]; - - } catch (error) { - - if (error instanceof Error && error.message.includes('ENOENT')) { - return []; - } - - - const message = error instanceof Error ? error.message : 'unknown error occurred.'; - vscode.window.showErrorMessage(`error formatting document: ${message}`); - return []; - } finally { - fs.promises.unlink(tempFilePath).catch((err) => { - console.error('error removing temp file:', err); - }); - } - } -}); - - +import * as vscode from "vscode"; +import { execFile } from "child_process"; +import * as fs from "fs"; +import * as path from "path"; +const DEFAULT_EXECUTABLE = "hbc"; let diagnosticCollection: vscode.DiagnosticCollection; -export function activate(context: vscode.ExtensionContext) { - diagnosticCollection = vscode.languages.createDiagnosticCollection('hblang'); - context.subscriptions.push(diagnosticCollection); - - vscode.workspace.onDidSaveTextDocument(onDocumentSaved); +function getExecutablePath(): string { + const config = vscode.workspace.getConfiguration("hblang"); + return config.get("compilerPath") === "Use PATH" + ? DEFAULT_EXECUTABLE + : config.get("compilerPath")!; } -async function onDocumentSaved(document: vscode.TextDocument) { - if (document.languageId === 'hblang') { - await lintDocument(document); - } +async function runCommand(filePath: string, args: string[]): Promise { + return new Promise((resolve, reject) => { + execFile(getExecutablePath(), args, (error, stdout, stderr) => { + if (error && error.code === "ENOENT") { + vscode.window.showErrorMessage( + "hblang compiler not found. Ensure 'hbc' is installed and available in PATH." + ); + return reject(new Error(`Compiler not found: ${stderr || stdout}`)); + } + return error + ? reject(new Error(stderr || `Exit code: ${error.code}`)) + : resolve(stdout); + }); + }); +} + +async function provideDocumentFormattingEdits( + document: vscode.TextDocument +): Promise { + const tempFilePath = path.join( + path.dirname(document.uri.fsPath), + `temp_${path.basename(document.uri.fsPath)}` + ); + await fs.promises.writeFile(tempFilePath, document.getText()); + + try { + const stdout = await runCommand(tempFilePath, [ + "--fmt-stdout", + tempFilePath, + ]); + const fullRange = new vscode.Range( + document.positionAt(0), + document.positionAt(document.getText().length) + ); + + diagnosticCollection.delete(document.uri); + + return [vscode.TextEdit.replace(fullRange, stdout)]; + } catch (error) { + return []; + } finally { + fs.promises.unlink(tempFilePath).catch(console.error); + } } async function lintDocument(document: vscode.TextDocument) { - const filePath = document.uri.fsPath; - - try { - const stderr = await runCompiler(filePath); - const diagnostics = parseLintingErrors(stderr); - diagnosticCollection.set(document.uri, diagnostics); - } catch (error) { - if (error instanceof Error) { - const diagnostics = parseLintingErrors(error.message); - diagnosticCollection.set(document.uri, diagnostics); - } else { - vscode.window.showErrorMessage(`error linting hblang document for some reason`) - } - } -} - -async function runCompiler(filePath: string): Promise { - return new Promise((resolve, reject) => { - execFile('hbc', [filePath], (error, stdout, stderr) => { - if (error) { - if (error.code === 'ENOENT') { - - vscode.window.showErrorMessage("hblang compiler not found. ensure 'hbc' is installed and available in PATH."); - } - reject(new Error(stderr || `Exit code: ${error.code}`)); - } else { - resolve(stderr); - } - }); - }); + try { + const stderr = await runCommand(document.uri.fsPath, [document.uri.fsPath]); + diagnosticCollection.set(document.uri, parseLintingErrors(stderr)); + } catch (error) { + if (error instanceof Error) { + diagnosticCollection.set(document.uri, parseLintingErrors(error.message)); + } else { + vscode.window.showErrorMessage("Error linting hblang document."); + } + } } function parseLintingErrors(stderr: string): vscode.Diagnostic[] { - const diagnostics: vscode.Diagnostic[] = []; - const lines = stderr.trim().split('\n'); + return stderr + .split("\n") + .filter((line) => line && !line.includes("missing main function")) + .map((lineText) => { + const match = lineText.match(/^([^:]+):(\d+):(\d+):\s*(.+)$/); + if (!match) return null; - for (const line of lines) { - const match = line.match(/^([^:]+):(\d+):(\d+):\s*(.+)$/); - if (match && !line.includes('missing main function')) { - const [, filePath, lineStr, columnStr, message] = match; - const line = parseInt(lineStr, 10) - 1; - const column = parseInt(columnStr, 10) - 1; - const diagnostic = new vscode.Diagnostic( - new vscode.Range(line, column, line, column + message.length), - message, - vscode.DiagnosticSeverity.Error - ); - diagnostic.source = 'hbc'; - diagnostics.push(diagnostic); - } - } + const [, , lineStr, columnStr, message] = match; + const lineNum = parseInt(lineStr, 10) - 1; + const columnNum = parseInt(columnStr, 10) - 1; - return diagnostics; -} \ No newline at end of file + return new vscode.Diagnostic( + new vscode.Range( + lineNum, + columnNum, + lineNum, + columnNum + message.length + ), + message, + vscode.DiagnosticSeverity.Error + ); + }) + .filter(Boolean) as vscode.Diagnostic[]; +} + +export function activate(context: vscode.ExtensionContext) { + diagnosticCollection = vscode.languages.createDiagnosticCollection("hblang"); + context.subscriptions.push(diagnosticCollection); + + vscode.workspace.onDidSaveTextDocument(async (document) => { + if (document.languageId === "hblang") { + await lintDocument(document); + + if (diagnosticCollection.get(document.uri)?.length === 0) { + vscode.commands.executeCommand( + "editor.action.formatDocument", + document + ); + } + } + }); + + vscode.languages.registerDocumentFormattingEditProvider("hblang", { + provideDocumentFormattingEdits, + }); +} diff --git a/tests/dont-erase.hb b/tests/dont-erase.hb new file mode 100644 index 0000000..4f1e1ba --- /dev/null +++ b/tests/dont-erase.hb @@ -0,0 +1,3 @@ +main := fn(): void { + undefined_identifier +} \ No newline at end of file