Web-Ide mit aufgenommen

This commit is contained in:
Riwoldt
2026-04-09 14:14:56 +02:00
parent 64816c45cc
commit 15cfaf332d
489 changed files with 186891 additions and 0 deletions
+14
View File
@@ -0,0 +1,14 @@
import * as vscode from "vscode";
type Callback = Parameters<typeof vscode.commands.registerCommand>[1];
export function makeCommands(): [string, Callback][] {
const hardwareCommand: [string, Callback] = [
"nand2tetris.hardware",
async (fileUri: string) => {
console.log("Hardware Command");
},
];
return [hardwareCommand];
}
@@ -0,0 +1,6 @@
export async function hardware(fileUri: string) {
// The await eval() hack is for https://github.com/microsoft/TypeScript/issues/43329
const tst = await import("@nand2tetris/simulator/test/chiptst.js");
console.log(`Hardware for ${fileUri}`);
console.log(new tst.ChipTest());
}
+41
View File
@@ -0,0 +1,41 @@
import * as vscode from "vscode";
import * as lang from "./languages/index.js";
async function getDiagnostics(document: vscode.TextDocument) {
switch (document.languageId) {
case "cmp":
case "out":
return lang.cmp.getDiagnostics(document);
case "hdl":
return lang.hdl.getDiagnostics(document);
case "tst":
return lang.tst.getDiagnostics(document);
default:
return [];
}
}
let diagnosticCollection: vscode.DiagnosticCollection;
function getDiagnosticCollection() {
if (diagnosticCollection === undefined) {
diagnosticCollection = vscode.languages.createDiagnosticCollection();
}
return diagnosticCollection;
}
async function runDiagnostics(document: vscode.TextDocument) {
getDiagnosticCollection().delete(document.uri);
const allDiagnostics = await getDiagnostics(document);
for (const [file, diagnostics] of allDiagnostics) {
getDiagnosticCollection().set(file, diagnostics);
}
}
export function makeDiagnostics() {
vscode.workspace.textDocuments.forEach(runDiagnostics);
vscode.workspace.onDidOpenTextDocument(runDiagnostics);
vscode.workspace.onDidChangeTextDocument(async (event) => {
runDiagnostics(event.document);
});
return getDiagnosticCollection();
}
+18
View File
@@ -0,0 +1,18 @@
import * as vscode from "vscode";
import { makeCommands } from "./commands.js";
import { makeDiagnostics } from "./diagnostics.js";
import { activateHdlView } from "./views/hdl.js";
export function activate(context: vscode.ExtensionContext) {
makeCommands().forEach(([name, callback]) =>
context.subscriptions.push(vscode.commands.registerCommand(name, callback)),
);
context.subscriptions.push(makeDiagnostics());
activateHdlView(context);
}
export function deactivate() {
console.log("Deactivating extension");
}
@@ -0,0 +1,40 @@
import type { Grammar } from "ohm-js";
import {
Diagnostic,
DiagnosticSeverity,
Range,
TextDocument,
Uri,
} from "vscode";
export async function getDiagnostics(
document: TextDocument,
parser: Grammar,
): Promise<[Uri, Diagnostic[]][]> {
const parsed = parser.match(document.getText());
if (!parsed.failed()) return [];
const { line, column, message } =
/Line (?<line>\d+), col (?<column>\d+): (?<message>.*)/.exec(
parsed.shortMessage ?? "",
)?.groups ?? { line: 1, column: 1, message: "could not parse error" };
const startLineNumber = Number(line);
const endLineNumber = startLineNumber;
const startColumn = Number(column);
const restOfLine = document
.lineAt(startLineNumber)
.text.substring(startColumn - 1);
let endColumn = startColumn + (restOfLine.match(/([^\s]+)/)?.[0].length ?? 1);
if (endColumn <= startColumn) {
endColumn = startColumn + 1;
}
const range = new Range(
startLineNumber - 1,
startColumn - 1,
endLineNumber - 1,
endColumn - 1,
);
const diagnostic = new Diagnostic(range, message, DiagnosticSeverity.Error);
return [[document.uri, [diagnostic]]];
}
@@ -0,0 +1,25 @@
import type { CMP } from "@nand2tetris/simulator/languages/cmp";
import { Diagnostic, TextDocument, Uri } from "vscode";
import * as base from "./base.js";
// import { load } from "../loader.js";
let cmp: typeof CMP | undefined = undefined;
async function getCmp(): Promise<typeof CMP> {
if (cmp) return Promise.resolve(cmp);
cmp = (await import("@nand2tetris/simulator/languages/cmp.js"))
.CMP as typeof CMP;
return cmp;
}
export async function getDiagnostics(
document: TextDocument,
): Promise<[Uri, Diagnostic[]][]> {
try {
const { parser } = await getCmp();
return base.getDiagnostics(document, parser);
} catch (e) {
console.error("Failed to load tst parser", e);
return [];
}
}
@@ -0,0 +1,19 @@
import type { HDL } from "@nand2tetris/simulator/languages/hdl";
import { Diagnostic, TextDocument, Uri } from "vscode";
import * as base from "./base.js";
let hdl: typeof HDL | undefined = undefined;
async function getHdl(): Promise<typeof HDL> {
if (hdl) return Promise.resolve(hdl);
hdl = (await import("@nand2tetris/simulator/languages/hdl.js"))
.HDL as typeof HDL;
return hdl;
}
export async function getDiagnostics(
document: TextDocument,
): Promise<[Uri, Diagnostic[]][]> {
const { parser } = await getHdl();
return base.getDiagnostics(document, parser);
}
@@ -0,0 +1,5 @@
export const LANGUAGE_IDS = ["cmp", "hdl", "out", "tst"];
export * as base from "./base.js";
export * as cmp from "./cmp.js";
export * as hdl from "./hdl.js";
export * as tst from "./tst.js";
@@ -0,0 +1,23 @@
import type { TST } from "@nand2tetris/simulator/languages/tst";
import { Diagnostic, TextDocument, Uri } from "vscode";
import * as base from "./base.js";
let tst: typeof TST | undefined = undefined;
async function getTst(): Promise<typeof TST> {
if (tst) return Promise.resolve(tst);
tst = (await import("@nand2tetris/simulator/languages/tst.js"))
.TST as typeof TST;
return tst;
}
export async function getDiagnostics(
document: TextDocument,
): Promise<[Uri, Diagnostic[]][]> {
try {
const { parser } = await getTst();
return base.getDiagnostics(document, parser);
} catch (e) {
console.error("Failed to load tst parser", e);
return [];
}
}
+104
View File
@@ -0,0 +1,104 @@
import { parse } from "path";
import * as vscode from "vscode";
import { hdl as HDL } from "../languages/index.js";
export function activateHdlView(context: vscode.ExtensionContext) {
const provider = new HdlViewProvider(context.extensionUri);
vscode.window.registerWebviewViewProvider(HdlViewProvider.viewType, provider);
}
class HdlViewProvider implements vscode.WebviewViewProvider {
public static readonly viewType = "nand2tetris.hdlView";
private _hdl = "";
private _view?: vscode.WebviewView;
constructor(private readonly extensionUri: vscode.Uri) {}
public resolveWebviewView(
webviewView: vscode.WebviewView,
context: vscode.WebviewViewResolveContext,
_token: vscode.CancellationToken,
) {
this._view = webviewView;
webviewView.webview.options = {
// Allow scripts in the webview
enableScripts: true,
localResourceRoots: [this.extensionUri],
};
webviewView.webview.html = this._getHtmlForWebview(webviewView.webview);
webviewView.webview.onDidReceiveMessage(
(message: { nand2tetris: boolean; ready: boolean }) => {
if (message.nand2tetris && message.ready) {
this.updateHdl(vscode.window.activeTextEditor?.document);
}
},
);
webviewView.onDidChangeVisibility(() => {
if (this._view?.visible !== true) {
this.clearHdl();
} else {
this.updateHdl(vscode.window.activeTextEditor?.document);
}
});
vscode.window.onDidChangeActiveTextEditor((e) => {
this.updateHdl(e?.document);
});
vscode.workspace.onDidSaveTextDocument(async (document) => {
this.updateHdl(document);
});
}
clearHdl() {
this._hdl = "";
}
async updateHdl(document?: vscode.TextDocument) {
if (document?.languageId !== "hdl") return;
const hdl = document.getText();
if (this._hdl === hdl) {
return;
}
const diagnostics = await HDL.getDiagnostics(document);
if ((diagnostics[0] ?? ["", []])[1].length === 0) {
const chipName = parse(document.fileName).name;
this._view?.webview.postMessage({ nand2tetris: true, hdl, chipName });
this._hdl = hdl;
}
}
private _getHtmlForWebview(webview: vscode.Webview) {
const stylesUri = this.getUri(webview, ["hdl", "styles.css"]);
const scriptUri = this.getUri(webview, ["hdl", "main.js"]);
return /*html*/ `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no">
<meta name="theme-color" content="#000000">
<link rel="stylesheet" type="text/css" href="${stylesUri}">
<title>HDL - NAND2Tetris</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<script src="${scriptUri}"></script>
</body>
</html>
`;
}
private getUri(webview: vscode.Webview, pathList: string[]) {
return webview.asWebviewUri(
vscode.Uri.joinPath(this.extensionUri, "out", "views", ...pathList),
);
}
}