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: # Usage guide:
1. run `cargo install hblang --git https://git.ablecorp.us/ableos/holey-bytes` 1. `cargo +nightly install hblang --git https://git.ablecorp.us/ableos/holey-bytes`
2. add `$HOME/.cargo/bin` (or wherever you installed hblang) to `$PATH` > remember to keep this updated
> in bash, `export PATH=$PATH:$HOME/.cargo/bin`<br> 2.
> in other shells, there may be other ways - 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) 3. log out and log back in (or something, idk)

View file

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

2
package-lock.json generated
View file

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

View file

@ -6,14 +6,15 @@
"publisher": "koniifer", "publisher": "koniifer",
"displayName": "hblang", "displayName": "hblang",
"description": "Syntax highlighter and formatter for holey-bytes lang", "description": "Syntax highlighter and formatter for holey-bytes lang",
"version": "0.1.0", "version": "0.2.3",
"engines": { "engines": {
"vscode": "^1.75.0" "vscode": "^1.75.0"
}, },
"main": "./out/main.js", "main": "./out/main.js",
"categories": [ "categories": [
"Programming Languages", "Programming Languages",
"Formatters" "Formatters",
"Linters"
], ],
"activationEvents": [ "activationEvents": [
"onCommand:extension.formatDocument" "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": { "scripts": {
"vscode:prepublish": "webpack", "vscode:prepublish": "webpack",
@ -63,6 +75,6 @@
"typescript": "^4.0.0", "typescript": "^4.0.0",
"vscode": "^1.1.37", "vscode": "^1.1.37",
"webpack": "^5.0.0", "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 * as vscode from "vscode";
import { spawn } from 'child_process'; import { execFile } from "child_process";
import * as fs from 'fs'; import * as fs from "fs";
import * as os from 'os'; import * as path from "path";
import * as path from 'path';
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 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) {
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[] {
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) { export function activate(context: vscode.ExtensionContext) {
// Register a document formatting edit provider for the language diagnosticCollection = vscode.languages.createDiagnosticCollection("hblang");
context.subscriptions.push( context.subscriptions.push(diagnosticCollection);
vscode.languages.registerDocumentFormattingEditProvider('hblang', {
async provideDocumentFormattingEdits(document: vscode.TextDocument): Promise<vscode.TextEdit[]> {
try { vscode.workspace.onDidSaveTextDocument(async (document) => {
const formattedText = await formatDocument(document.fileName); if (document.languageId === "hblang") {
await lintDocument(document);
const edit = new vscode.TextEdit( if (diagnosticCollection.get(document.uri)?.length === 0) {
new vscode.Range(0, 0, document.lineCount, 0), vscode.commands.executeCommand(
formattedText "editor.action.formatDocument",
); document
);
}
}
});
return [edit]; vscode.languages.registerDocumentFormattingEditProvider("hblang", {
} catch (error: unknown) { provideDocumentFormattingEdits,
if (error instanceof Error) { });
vscode.window.showErrorMessage(`Formatting failed: ${error.message}`);
} else {
vscode.window.showErrorMessage(`Formatting failed: ${String(error)}`);
}
return []; // Return an empty array if formatting fails
}
}
})
);
}
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}`));
}
});
});
} }

View file

@ -19,28 +19,28 @@
"include": "#string" "include": "#string"
}, },
{ {
"include": "#keyword" "include": "#struct"
}, },
{ {
"include": "#function" "include": "#keyword"
}, },
{ {
"include": "#number" "include": "#number"
}, },
{ {
"include": "#struct" "include": "#punctuation"
}, },
{ {
"include": "#type" "include": "#function"
},
{
"include": "#variable"
}, },
{ {
"include": "#operator" "include": "#operator"
}, },
{ {
"include": "#punctuation" "include": "#variable"
},
{
"include": "#type"
}, },
{ {
"include": "#array" "include": "#array"
@ -51,19 +51,31 @@
"patterns": [ "patterns": [
{ {
"name": "variable.parameter.hblang", "name": "variable.parameter.hblang",
"match": "\\b\\w+\\b" "match": "\\b\\w+\\s*:\\s*(?:\\^)?[\\w\\$]+\\b"
} }
] ]
}, },
"number": { "number": {
"patterns": [ "patterns": [
{ {
"name": "constant.numeric.hblang", "name": "constant.numeric.float.hblang",
"match": "\\b\\d+(\\.\\d+)?\\b" "match": "\\b\\d+\\.\\d+\\b"
}, },
{ {
"name": "constant.numeric.hex.hblang", "name": "constant.numeric.hex.hblang",
"match": "0x[0-9A-Fa-f]+" "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", "name": "string.quoted.double.hblang",
"begin": "\"", "begin": "\"",
"end": "\"", "end": "\"",
"beginCaptures": {
"0": {
"name": "punctuation.definition.string.begin.hblang"
}
},
"endCaptures": {
"0": {
"name": "punctuation.definition.string.end.hblang"
}
},
"patterns": [ "patterns": [
{ {
"name": "constant.character.escape.hblang", "name": "constant.character.escape.hblang",
"match": "\\\\[\"'\\\\bfnrt]|\\\\(\\{[^}]+\\}|\\[[^]]+\\]|[a-zA-Z])" "match": "\\\\(?:[\"'\\\\bfnrt]|[{\\[]\\w+[}\\]]|[a-zA-Z])"
}, },
{ {
"name": "invalid.illegal.escaped.hblang", "name": "invalid.illegal.escaped.hblang",
@ -114,7 +116,7 @@
"patterns": [ "patterns": [
{ {
"name": "keyword.control.hblang", "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,60 +124,86 @@
"patterns": [ "patterns": [
{ {
"name": "storage.type.hblang", "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": { "variable": {
"patterns": [ "patterns": [
{ {
"name": "variable.parameter.hblang", "name": "variable.declaration.hblang",
"match": "\\b\\w+\\s*:=\\b" "match": "\\b\\w+\\b(?=\\s*:=)"
}, },
{ {
"name": "variable.parameter.hblang", "name": "variable.assignment.hblang",
"match": "\\b\\w+\\s*=\\b" "match": "\\b\\w+\\b(?=\\s*=(?!=))"
}, },
{ {
"name": "variable.parameter.hblang", "name": "variable.member.hblang",
"match": "(?<=\\w+\\.)(\\w+)\\b" "match": "(?<=\\.)\\w+\\b"
} }
] ]
}, },
"operator": { "operator": {
"patterns": [ "patterns": [
{
"name": "keyword.operator.assignment.hblang",
"match": ":="
},
{
"name": "keyword.operator.assignment.hblang",
"match": "=(?!=)"
},
{ {
"name": "keyword.operator.hblang", "name": "keyword.operator.hblang",
"match": "(@|:=|<<=|>>=|>=|<=|^=|\\+=|-=|\\*=|\\/=|%=|\\|=|&=|\\^|\\*|&|&&|\\|\\||<<|>>|\\+|\\-|\\/|%|\\||!|==|!=|<|>|=)" "match": "(\\$|\\?|@|<<=|>>=|>=|<=|\\^=|\\+=|-=|\\*=|\\/=|%=|\\|=|&=|\\^|\\*|&|<<|>>|\\+|\\-|\\/|%|\\||!|==|!=|<|>)"
}
]
},
"struct": {
"patterns": [
{
"name": "entity.name.type.struct.hblang",
"match": "\\b[A-Z]\\w+\\b"
}
]
},
"punctuation": {
"patterns": [
{
"name": "punctuation.terminator.statement.hblang",
"match": ";|\\.|,|(?<!:):(?!=)"
} }
] ]
}, },
"function": { "function": {
"patterns": [ "patterns": [
{ {
"name": "entity.name.function.hblang", "name": "meta.function.declaration.hblang",
"begin": "(?<!\\w)fn\\s*\\(", "begin": "(\\b\\w+\\b)\\s*(:=)\\s*(fn)\\s*\\(",
"end": "\\)", "end": "\\)",
"captures": { "beginCaptures": {
"0": { "1": {
"name": "keyword.hblang" "name": "entity.name.function.hblang"
},
"2": {
"name": "keyword.operator.assignment.hblang"
},
"3": {
"name": "keyword.control.hblang"
} }
}, },
"patterns": [ "patterns": [
{ {
"include": "#all" "include": "#all"
},
{
"name": "variable.parameter.hblang",
"match": "\\b\\w+\\b(\\s*,\\s*\\b\\w+\\b)*"
} }
] ]
}, },
{ {
"name": "entity.name.function.hblang", "name": "meta.function.call.hblang",
"begin": "(?:@)?\\b\\w+\\s*\\(", "begin": "@?\\w+\\s*\\(",
"end": "\\)", "end": "\\)",
"captures": { "beginCaptures": {
"0": { "0": {
"name": "entity.name.function.hblang" "name": "entity.name.function.hblang"
} }
@ -183,39 +211,24 @@
"patterns": [ "patterns": [
{ {
"include": "#all" "include": "#all"
}, }
]
}
]
},
"array": {
"patterns": [
{
"name": "meta.array.initialization.hblang",
"begin": "\\.\\(",
"end": "\\)",
"patterns": [
{ {
"name": "variable.parameter.hblang", "include": "#all"
"match": "\\b\\w+\\b(\\s*,\\s*\\b\\w+\\b)*"
} }
] ]
} }
] ]
} }
},
"struct": {
"patterns": [
{
"name": "entity.name.type.struct.hblang",
"match": "\\b[A-Z]\\w+\\b"
}
]
},
"array": {
"patterns": [
{
"name": "storage.type.array.hblang",
"begin": "\\.\\(",
"end": "\\)"
}
]
},
"punctuation": {
"patterns": [
{
"name": "punctuation.terminator.statement.hblang",
"match": ";|\\.|,|:"
}
]
} }
} }

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