0.2.1, bug fixes and new match new compiler

This commit is contained in:
koniifer 2024-11-08 21:49:10 +00:00
parent 69a82a563e
commit 8ad44334d8
3 changed files with 122 additions and 112 deletions

View file

@ -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": { "scripts": {
"vscode:prepublish": "webpack", "vscode:prepublish": "webpack",

View file

@ -1,124 +1,120 @@
import * as vscode from 'vscode'; import * as vscode from "vscode";
import { execFile } from 'child_process'; import { execFile } from "child_process";
import * as fs from 'fs'; import * as fs from "fs";
import * as path from 'path'; import * as path from "path";
vscode.languages.registerDocumentFormattingEditProvider('hblang', { const DEFAULT_EXECUTABLE = "hbc";
async provideDocumentFormattingEdits(document: vscode.TextDocument): Promise<vscode.TextEdit[]> { let diagnosticCollection: vscode.DiagnosticCollection;
const filePath = document.uri.fsPath;
const tempFilePath = path.join(path.dirname(filePath), `temp_${path.basename(filePath)}`);
try { function getExecutablePath(): string {
const config = vscode.workspace.getConfiguration("hblang");
return config.get<string>("compilerPath") === "Use PATH"
? DEFAULT_EXECUTABLE
: config.get<string>("compilerPath")!;
}
async function runCommand(filePath: string, args: string[]): Promise<string> {
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<vscode.TextEdit[]> {
const tempFilePath = path.join(
path.dirname(document.uri.fsPath),
`temp_${path.basename(document.uri.fsPath)}`
);
await fs.promises.writeFile(tempFilePath, document.getText()); await fs.promises.writeFile(tempFilePath, document.getText());
const stdout = await new Promise<string>((resolve, reject) => { try {
execFile('hbc', ['--fmt-stdout', tempFilePath], (error, stdout, stderr) => { const stdout = await runCommand(tempFilePath, [
if (error) { "--fmt-stdout",
if (error.code === 'ENOENT') { tempFilePath,
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( const fullRange = new vscode.Range(
document.positionAt(0), document.positionAt(0),
document.positionAt(document.getText().length) document.positionAt(document.getText().length)
); );
const edit = vscode.TextEdit.replace(fullRange, stdout);
return [edit];
diagnosticCollection.delete(document.uri);
return [vscode.TextEdit.replace(fullRange, stdout)];
} catch (error) { } 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 []; return [];
} finally { } finally {
fs.promises.unlink(tempFilePath).catch((err) => { fs.promises.unlink(tempFilePath).catch(console.error);
console.error('error removing temp file:', err);
});
}
}
});
let diagnosticCollection: vscode.DiagnosticCollection;
export function activate(context: vscode.ExtensionContext) {
diagnosticCollection = vscode.languages.createDiagnosticCollection('hblang');
context.subscriptions.push(diagnosticCollection);
vscode.workspace.onDidSaveTextDocument(onDocumentSaved);
}
async function onDocumentSaved(document: vscode.TextDocument) {
if (document.languageId === 'hblang') {
await lintDocument(document);
} }
} }
async function lintDocument(document: vscode.TextDocument) { async function lintDocument(document: vscode.TextDocument) {
const filePath = document.uri.fsPath;
try { try {
const stderr = await runCompiler(filePath); const stderr = await runCommand(document.uri.fsPath, [document.uri.fsPath]);
const diagnostics = parseLintingErrors(stderr); diagnosticCollection.set(document.uri, parseLintingErrors(stderr));
diagnosticCollection.set(document.uri, diagnostics);
} catch (error) { } catch (error) {
if (error instanceof Error) { if (error instanceof Error) {
const diagnostics = parseLintingErrors(error.message); diagnosticCollection.set(document.uri, parseLintingErrors(error.message));
diagnosticCollection.set(document.uri, diagnostics);
} else { } else {
vscode.window.showErrorMessage(`error linting hblang document for some reason`) vscode.window.showErrorMessage("Error linting hblang document.");
} }
} }
} }
async function runCompiler(filePath: string): Promise<string> {
return new Promise<string>((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);
}
});
});
}
function parseLintingErrors(stderr: string): vscode.Diagnostic[] { function parseLintingErrors(stderr: string): vscode.Diagnostic[] {
const diagnostics: vscode.Diagnostic[] = []; return stderr
const lines = stderr.trim().split('\n'); .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 [, , lineStr, columnStr, message] = match;
const match = line.match(/^([^:]+):(\d+):(\d+):\s*(.+)$/); const lineNum = parseInt(lineStr, 10) - 1;
if (match && !line.includes('missing main function')) { const columnNum = parseInt(columnStr, 10) - 1;
const [, filePath, lineStr, columnStr, message] = match;
const line = parseInt(lineStr, 10) - 1; return new vscode.Diagnostic(
const column = parseInt(columnStr, 10) - 1; new vscode.Range(
const diagnostic = new vscode.Diagnostic( lineNum,
new vscode.Range(line, column, line, column + message.length), columnNum,
lineNum,
columnNum + message.length
),
message, message,
vscode.DiagnosticSeverity.Error vscode.DiagnosticSeverity.Error
); );
diagnostic.source = 'hbc'; })
diagnostics.push(diagnostic); .filter(Boolean) as vscode.Diagnostic[];
} }
}
export function activate(context: vscode.ExtensionContext) {
return diagnostics; 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,
});
} }

3
tests/dont-erase.hb Normal file
View file

@ -0,0 +1,3 @@
main := fn(): void {
undefined_identifier
}