Compare commits

...

10 commits
0.1.1 ... trunk

Author SHA1 Message Date
koniifer fa7a4bd245 update & improve grammar somewhat 2024-11-15 21:20:50 +00:00
koniifer 99f66d803a better instructions 2024-11-10 15:07:40 -06:00
koniifer bc84098b77 patch 2024-11-08 21:50:37 +00:00
koniifer d146f51e59 bump version 2024-11-08 21:49:29 +00:00
koniifer 8ad44334d8 0.2.1, bug fixes and new match new compiler 2024-11-08 21:49:10 +00:00
koniifer 69a82a563e don't make people use nightly as default, that is stupid 2024-11-08 13:22:32 -06:00
koniifer c3ade921d7 release 0.2.0
+ error linting
+ clearer missing hblang message
+ misc
2024-11-07 18:59:47 +00:00
koniifer 7c48aa6cad update readme for common problem 2024-10-25 05:32:52 -05:00
koniifer 4b5bb991f7 good enough formatter 2024-09-30 12:57:01 +01:00
koniifer 9098604bf0 fix struct highlight 2024-09-28 16:27:58 +01:00
9 changed files with 247 additions and 150 deletions

13
.vscodeignore Normal file
View file

@ -0,0 +1,13 @@
# ---> VisualStudioCode
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
!.vscode/*.code-snippets
# Local History for Visual Studio Code
.history/
# Built Visual Studio Code Extensions
*.vsix

View file

@ -4,8 +4,11 @@ syntax highlighting for hblang in vscode
# Usage guide:
1. run `cargo install hblang --git https://git.ablecorp.us/ableos/holey-bytes`
2. add `$HOME/.cargo/bin` (or wherever you installed hblang) to `$PATH`
1. `cargo +nightly install hblang --git https://git.ablecorp.us/ableos/holey-bytes`
> remember to keep this updated
2.
- add `$HOME/.cargo/bin` (or wherever you installed hblang) to `$PATH`
> in bash, `export PATH=$PATH:$HOME/.cargo/bin`<br>
> in other shells, there may be other ways
- alternatively, add the path you installed hblang to the extension settings
3. log out and log back in (or something, idk)

View file

@ -68,8 +68,8 @@
],
"folding": {
"markers": {
"start": "^\\s*//\\s*#region\\b",
"end": "^\\s*//\\s*#endregion\\b"
"start": "{\n",
"end": "}"
}
},
"indentationRules": {

2
package-lock.json generated
View file

@ -16,7 +16,7 @@
"typescript": "^4.0.0",
"vscode": "^1.1.37",
"webpack": "^5.0.0",
"webpack-cli": "^4.0.0"
"webpack-cli": "^4.10.0"
},
"engines": {
"vscode": "^1.75.0"

View file

@ -6,14 +6,15 @@
"publisher": "koniifer",
"displayName": "hblang",
"description": "Syntax highlighter and formatter for holey-bytes lang",
"version": "0.1.0",
"version": "0.2.3",
"engines": {
"vscode": "^1.75.0"
},
"main": "./out/main.js",
"categories": [
"Programming Languages",
"Formatters"
"Formatters",
"Linters"
],
"activationEvents": [
"onCommand:extension.formatDocument"
@ -47,7 +48,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",
@ -63,6 +75,6 @@
"typescript": "^4.0.0",
"vscode": "^1.1.37",
"webpack": "^5.0.0",
"webpack-cli": "^4.0.0"
"webpack-cli": "^4.10.0"
}
}

View file

@ -1,66 +1,120 @@
import * as vscode from 'vscode';
import { spawn } from 'child_process';
import * as fs from 'fs';
import * as os from 'os';
import * as path from 'path';
import * as vscode from "vscode";
import { execFile } from "child_process";
import * as fs from "fs";
import * as path from "path";
export function activate(context: vscode.ExtensionContext) {
// Register a document formatting edit provider for the language
context.subscriptions.push(
vscode.languages.registerDocumentFormattingEditProvider('hblang', {
async provideDocumentFormattingEdits(document: vscode.TextDocument): Promise<vscode.TextEdit[]> {
const DEFAULT_EXECUTABLE = "hbc";
let diagnosticCollection: vscode.DiagnosticCollection;
function getExecutablePath(): string {
const config = vscode.workspace.getConfiguration("hblang");
return config.get<string>("compilerPath") === "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());
try {
const formattedText = await formatDocument(document.fileName);
const edit = new vscode.TextEdit(
new vscode.Range(0, 0, document.lineCount, 0),
formattedText
const stdout = await runCommand(tempFilePath, [
"--fmt-stdout",
tempFilePath,
]);
const fullRange = new vscode.Range(
document.positionAt(0),
document.positionAt(document.getText().length)
);
return [edit];
} catch (error: unknown) {
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) {
try {
const stderr = await runCommand(document.uri.fsPath, [document.uri.fsPath]);
diagnosticCollection.set(document.uri, parseLintingErrors(stderr));
} catch (error) {
if (error instanceof Error) {
vscode.window.showErrorMessage(`Formatting failed: ${error.message}`);
diagnosticCollection.set(document.uri, parseLintingErrors(error.message));
} else {
vscode.window.showErrorMessage(`Formatting failed: ${String(error)}`);
}
return []; // Return an empty array if formatting fails
vscode.window.showErrorMessage("Error linting hblang document.");
}
}
}
function parseLintingErrors(stderr: string): vscode.Diagnostic[] {
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;
const [, , lineStr, columnStr, message] = match;
const lineNum = parseInt(lineStr, 10) - 1;
const columnNum = parseInt(columnStr, 10) - 1;
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
);
}
export function deactivate() { }
async function formatDocument(path: string): Promise<string> {
return new Promise((resolve, reject) => {
const child = spawn('hbc', ['--fmt-stdout', path], { shell: true });
let formattedText = '';
// Capture the output
child.stdout.on('data', (data) => {
formattedText += data.toString();
});
// Handle errors
child.stderr.on('data', (data) => {
reject(new Error(data.toString()));
});
// Handle process exit
child.on('exit', (code) => {
if (code === 0) {
resolve(formattedText);
} else {
reject(new Error(`Formatter exited with code ${code}`));
}
});
vscode.languages.registerDocumentFormattingEditProvider("hblang", {
provideDocumentFormattingEdits,
});
}

View file

@ -19,28 +19,28 @@
"include": "#string"
},
{
"include": "#keyword"
"include": "#struct"
},
{
"include": "#function"
"include": "#keyword"
},
{
"include": "#number"
},
{
"include": "#struct"
"include": "#punctuation"
},
{
"include": "#type"
},
{
"include": "#variable"
"include": "#function"
},
{
"include": "#operator"
},
{
"include": "#punctuation"
"include": "#variable"
},
{
"include": "#type"
},
{
"include": "#array"
@ -51,19 +51,31 @@
"patterns": [
{
"name": "variable.parameter.hblang",
"match": "\\b\\w+\\b"
"match": "\\b\\w+\\s*:\\s*(?:\\^)?[\\w\\$]+\\b"
}
]
},
"number": {
"patterns": [
{
"name": "constant.numeric.hblang",
"match": "\\b\\d+(\\.\\d+)?\\b"
"name": "constant.numeric.float.hblang",
"match": "\\b\\d+\\.\\d+\\b"
},
{
"name": "constant.numeric.hex.hblang",
"match": "0x[0-9A-Fa-f]+"
},
{
"name": "constant.numeric.binary.hblang",
"match": "0b[0-1]+"
},
{
"name": "constant.numeric.octal.hblang",
"match": "0o[0-7]+"
},
{
"name": "constant.numeric.decimal.hblang",
"match": "\\b\\d+\\b"
}
]
},
@ -87,20 +99,10 @@
"name": "string.quoted.double.hblang",
"begin": "\"",
"end": "\"",
"beginCaptures": {
"0": {
"name": "punctuation.definition.string.begin.hblang"
}
},
"endCaptures": {
"0": {
"name": "punctuation.definition.string.end.hblang"
}
},
"patterns": [
{
"name": "constant.character.escape.hblang",
"match": "\\\\[\"'\\\\bfnrt]|\\\\(\\{[^}]+\\}|\\[[^]]+\\]|[a-zA-Z])"
"match": "\\\\(?:[\"'\\\\bfnrt]|[{\\[]\\w+[}\\]]|[a-zA-Z])"
},
{
"name": "invalid.illegal.escaped.hblang",
@ -114,7 +116,7 @@
"patterns": [
{
"name": "keyword.control.hblang",
"match": "\\b(loop|break|if|else|return|packed|continue|true|false|struct|idk)\\b"
"match": "\\b(fn|loop|break|if|else|return|packed|continue|true|false|struct|idk|die|null)\\b"
}
]
},
@ -122,77 +124,42 @@
"patterns": [
{
"name": "storage.type.hblang",
"match": "\\b(uint|int|(u|i)(8|16|32)|void|bool|type|never|([A-Z]\\w+))\\b"
"match": "\\b(f(32|64))|(uint|int|(u|i)(8|16|32)|void|bool|type|never)\\b"
}
]
},
"variable": {
"patterns": [
{
"name": "variable.parameter.hblang",
"match": "\\b\\w+\\s*:=\\b"
"name": "variable.declaration.hblang",
"match": "\\b\\w+\\b(?=\\s*:=)"
},
{
"name": "variable.parameter.hblang",
"match": "\\b\\w+\\s*=\\b"
"name": "variable.assignment.hblang",
"match": "\\b\\w+\\b(?=\\s*=(?!=))"
},
{
"name": "variable.parameter.hblang",
"match": "(?<=\\w+\\.)(\\w+)\\b"
"name": "variable.member.hblang",
"match": "(?<=\\.)\\w+\\b"
}
]
},
"operator": {
"patterns": [
{
"name": "keyword.operator.assignment.hblang",
"match": ":="
},
{
"name": "keyword.operator.assignment.hblang",
"match": "=(?!=)"
},
{
"name": "keyword.operator.hblang",
"match": "(@|:=|<<=|>>=|>=|<=|^=|\\+=|-=|\\*=|\\/=|%=|\\|=|&=|\\^|\\*|&|&&|\\|\\||<<|>>|\\+|\\-|\\/|%|\\||!|==|!=|<|>|=)"
"match": "(\\$|\\?|@|<<=|>>=|>=|<=|\\^=|\\+=|-=|\\*=|\\/=|%=|\\|=|&=|\\^|\\*|&|<<|>>|\\+|\\-|\\/|%|\\||!|==|!=|<|>)"
}
]
},
"function": {
"patterns": [
{
"name": "entity.name.function.hblang",
"begin": "(?<!\\w)fn\\s*\\(",
"end": "\\)",
"captures": {
"0": {
"name": "keyword.hblang"
}
},
"patterns": [
{
"include": "#all"
},
{
"name": "variable.parameter.hblang",
"match": "\\b\\w+\\b(\\s*,\\s*\\b\\w+\\b)*"
}
]
},
{
"name": "entity.name.function.hblang",
"begin": "(?:@)?\\b\\w+\\s*\\(",
"end": "\\)",
"captures": {
"0": {
"name": "entity.name.function.hblang"
}
},
"patterns": [
{
"include": "#all"
},
{
"name": "variable.parameter.hblang",
"match": "\\b\\w+\\b(\\s*,\\s*\\b\\w+\\b)*"
}
]
}
]
}
},
"struct": {
"patterns": [
{
@ -201,21 +168,67 @@
}
]
},
"array": {
"patterns": [
{
"name": "storage.type.array.hblang",
"begin": "\\.\\(",
"end": "\\)"
}
]
},
"punctuation": {
"patterns": [
{
"name": "punctuation.terminator.statement.hblang",
"match": ";|\\.|,|:"
"match": ";|\\.|,|(?<!:):(?!=)"
}
]
},
"function": {
"patterns": [
{
"name": "meta.function.declaration.hblang",
"begin": "(\\b\\w+\\b)\\s*(:=)\\s*(fn)\\s*\\(",
"end": "\\)",
"beginCaptures": {
"1": {
"name": "entity.name.function.hblang"
},
"2": {
"name": "keyword.operator.assignment.hblang"
},
"3": {
"name": "keyword.control.hblang"
}
},
"patterns": [
{
"include": "#all"
}
]
},
{
"name": "meta.function.call.hblang",
"begin": "@?\\w+\\s*\\(",
"end": "\\)",
"beginCaptures": {
"0": {
"name": "entity.name.function.hblang"
}
},
"patterns": [
{
"include": "#all"
}
]
}
]
},
"array": {
"patterns": [
{
"name": "meta.array.initialization.hblang",
"begin": "\\.\\(",
"end": "\\)",
"patterns": [
{
"include": "#all"
}
]
}
]
}
}
}

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

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

View file

@ -6,20 +6,19 @@ module.exports = {
output: {
path: path.resolve(__dirname, 'out'),
filename: 'main.js',
libraryTarget: 'commonjs2' // This is correct for VS Code extensions
libraryTarget: 'commonjs2'
},
resolve: {
extensions: ['.ts', '.js'],
fallback: {
// For Node.js core modules not available in browser context, you set them to false
"child_process": false, // Not used in browser context
"fs": false, // Not used in browser context
"os": require.resolve("os-browserify/browser"), // Polyfill for os
"path": require.resolve("path-browserify"), // Polyfill for path
"child_process": false,
"fs": false,
"os": require.resolve("os-browserify/browser"),
"path": require.resolve("path-browserify"),
},
},
externals: {
vscode: 'commonjs vscode' // Externalize the vscode module
vscode: 'commonjs vscode'
},
module: {
rules: [
@ -30,5 +29,5 @@ module.exports = {
}
]
},
target: 'node' // Specify the target environment as Node.js
target: 'node'
};