Web-Ide mit aufgenommen
This commit is contained in:
@@ -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());
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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 [];
|
||||
}
|
||||
}
|
||||
@@ -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),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user