This commit is contained in:
Connor Peet 2021-12-31 11:04:02 -08:00
Родитель 477787b208
Коммит cfa37d833d
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: CF8FD2EA0DBC61BD
6 изменённых файлов: 69 добавлений и 53 удалений

Просмотреть файл

@ -31,30 +31,27 @@
"compile": "tsc -p ./",
"lint": "eslint src --ext ts",
"typecheck": "tsc -p tsconfig.json --noEmit",
"esbuild-base": "esbuild ./src/extension.ts --bundle --tsconfig=./tsconfig.json --external:vscode --format=cjs --platform=node --outfile=dist/extension.js",
"watch": "npm run -S esbuild-base -- --sourcemap --sources-content=false --watch",
"esbuild-web": "esbuild ./src/web-extension.ts --bundle --tsconfig=./tsconfig.json --external:vscode --format=cjs --platform=browser --outfile=dist/web-extension.js",
"watch-web": "npm run -S esbuild-web -- --sourcemap --sources-content=false --watch",
"build": "npm run -S esbuild-base -- --sourcemap --sources-content=false && npm run -S esbuild-web -- --sourcemap --sources-content=false",
"package": "vsce package",
"publish": "vsce publish",
"publish-pre-release": "vsce publish --pre-release",
"vscode:prepublish": "rimraf dist && npm run -S esbuild-base -- --minify && npm run -S esbuild-web -- --minify"
},
"devDependencies": {
"@types/vscode": "^1.61.0",
"@types/glob": "^7.2.0",
"@types/mocha": "^9.0.0",
"@types/node": "^14.14.37",
"@types/vscode": "^1.61.0",
"@typescript-eslint/eslint-plugin": "^5.2.0",
"@typescript-eslint/parser": "^5.2.0",
"await-notify": "1.0.1",
"eslint": "^8.1.0",
"base64-js": "^1.5.1",
"esbuild": "^0.13.12",
"eslint": "^8.1.0",
"events": "^3.3.0",
"glob": "^7.2.0",
"mocha": "^9.1.3",
@ -137,7 +134,9 @@
"debuggers": [
{
"type": "mock",
"languages": ["markdown"],
"languages": [
"markdown"
],
"label": "Mock Debug",
"program": "./out/debugAdapter.js",
"runtime": "node",
@ -207,4 +206,4 @@
}
]
}
}
}

Просмотреть файл

@ -183,38 +183,29 @@ class MockConfigurationProvider implements vscode.DebugConfigurationProvider {
}
export const workspaceFileAccessor: FileAccessor = {
async readFile(path: string): Promise<string> {
async readFile(path: string): Promise<Uint8Array> {
let uri: vscode.Uri;
try {
uri = vscode.Uri.file(path);
uri = pathToUri(path);
} catch (e) {
try {
uri = vscode.Uri.parse(path);
} catch (e) {
return `cannot read '${path}'`;
}
return new TextEncoder().encode(`cannot read '${path}'`);
}
const bytes = await vscode.workspace.fs.readFile(uri);
var result: string[] = [];
for (let i = 0; i < bytes.length;) {
const c = bytes[i++];
var cp: number;
if (c <= 0x7F) {
cp = c;
} else if (c <= 0xDF) {
cp = ((c & 0x1F) << 6) | (bytes[i++] & 0x3F);
} else if (c <= 0xEF) {
cp = ((c & 0x0F) << 12) | ((bytes[i++] & 0x3F) << 6) | (bytes[i++] & 0x3F);
} else {
cp = ((c & 0x07) << 18) | ((bytes[i++] & 0x3F) << 12) | ((bytes[i++] & 0x3F) << 6) | (bytes[i++] & 0x3F);
}
result.push(String.fromCodePoint(cp));
}
return result.join('');
return await vscode.workspace.fs.readFile(uri);
},
async writeFile(path: string, contents: Uint8Array) {
await vscode.workspace.fs.writeFile(pathToUri(path), contents);
}
};
function pathToUri(path: string) {
try {
return vscode.Uri.file(path);
} catch (e) {
return vscode.Uri.parse(path);
}
}
class InlineDebugAdapterFactory implements vscode.DebugAdapterDescriptorFactory {
createDebugAdapterDescriptor(_session: vscode.DebugSession): ProviderResult<vscode.DebugAdapterDescriptor> {

Просмотреть файл

@ -21,6 +21,7 @@ import { DebugProtocol } from 'vscode-debugprotocol';
import { basename } from 'path-browserify';
import { MockRuntime, IRuntimeBreakpoint, FileAccessor, IRuntimeVariable, timeout, IRuntimeVariableType } from './mockRuntime';
import { Subject } from 'await-notify';
import * as base64 from 'base64-js';
/**
* This interface describes the mock-debug specific launch attributes
@ -198,8 +199,9 @@ export class MockDebugSession extends LoggingDebugSession {
response.body.supportsSteppingGranularity = true;
response.body.supportsInstructionBreakpoints = true;
// make VS Code able to read variable memory
// make VS Code able to read and write variable memory
response.body.supportsReadMemoryRequest = true;
response.body.supportsWriteMemoryRequest = true;
this.sendResponse(response);
@ -384,14 +386,21 @@ export class MockDebugSession extends LoggingDebugSession {
this.sendResponse(response);
}
protected async writeMemoryRequest(response: DebugProtocol.WriteMemoryResponse, { data, memoryReference, offset = 0 }: DebugProtocol.WriteMemoryArguments) {
const [start] = JSON.parse(memoryReference);
const decoded = base64.toByteArray(data);
this._runtime.writeData(start + offset, decoded);
this.sendResponse(response);
}
protected async readMemoryRequest(response: DebugProtocol.ReadMemoryResponse, { offset = 0, count, memoryReference }: DebugProtocol.ReadMemoryArguments) {
const [start, end] = JSON.parse(memoryReference);
const realCount = Math.max(0, Math.min(count, end - (start + offset)));
const data = realCount > 0 ? this._runtime.memory.slice(offset + start, offset + start + realCount) : Buffer.alloc(0);
const encoded = realCount > 0 ? this._runtime.memory.slice(offset + start, offset + start + realCount) : new Uint8Array();
response.body = {
address: (start + offset).toString(),
data: data.toString('base64'),
data: base64.fromByteArray(encoded),
unreadableBytes: count - realCount
};
this.sendResponse(response);

Просмотреть файл

@ -5,7 +5,8 @@
import { EventEmitter } from 'events';
export interface FileAccessor {
readFile(path: string): Promise<string>;
readFile(path: string): Promise<Uint8Array>;
writeFile(path: string, contents: Uint8Array): Promise<void>;
}
export interface IRuntimeBreakpoint {
@ -87,7 +88,7 @@ export class MockRuntime extends EventEmitter {
private instructions: Word[] = [];
private starts: number[] = [];
private ends: number[] = [];
private sourceTextAsMemory = Buffer.alloc(0);
private sourceTextAsMemory = new Uint8Array();
public get memory() {
return this.sourceTextAsMemory;
@ -447,21 +448,27 @@ export class MockRuntime extends EventEmitter {
private async loadSource(file: string): Promise<void> {
if (this._sourceFile !== file) {
this._sourceFile = file;
const contents = await this.fileAccessor.readFile(file);
this.sourceTextAsMemory = Buffer.from(contents);
this.sourceLines = contents.split(/\r?\n/);
this.initializeContents(await this.fileAccessor.readFile(file));
}
}
this.instructions = [];
private initializeContents(memory: Uint8Array) {
this.sourceTextAsMemory = memory;
this.sourceLines = new TextDecoder().decode(memory).split(/\r?\n/);
for (let l = 0; l < this.sourceLines.length; l++) {
this.starts.push(this.instructions.length);
const words = this.getWords(l, this.sourceLines[l]);
for (let word of words) {
this.instructions.push(word);
}
this.ends.push(this.instructions.length);
this.instructions = [];
this.starts = [];
this.instructions = [];
this.ends = [];
for (let l = 0; l < this.sourceLines.length; l++) {
this.starts.push(this.instructions.length);
const words = this.getWords(l, this.sourceLines[l]);
for (let word of words) {
this.instructions.push(word);
}
this.ends.push(this.instructions.length);
}
}
@ -506,6 +513,15 @@ export class MockRuntime extends EventEmitter {
return false;
}
/**
* Updates the source file contents and re-parses variables/instructions.
*/
public async writeData(offset: number, data: Uint8Array) {
this.sourceTextAsMemory.set(data, offset);
await this.fileAccessor.writeFile(this._sourceFile, this.sourceTextAsMemory);
this.initializeContents(this.sourceTextAsMemory);
}
/**
* "execute a line" of the readme markdown.
* Returns true if execution sent out a stopped event and needs to stop.
@ -652,7 +668,7 @@ export class MockRuntime extends EventEmitter {
private lineByteOffset(lineNumber: number) {
let offset = 0;
for (; lineNumber > 0; lineNumber--) {
offset = this.sourceTextAsMemory.indexOf('\n', offset) + 1;
offset = this.sourceTextAsMemory.indexOf(10 /* \n */, offset) + 1;
}
return offset;

Просмотреть файл

@ -1,10 +1,11 @@
{
"compilerOptions": {
"module": "commonjs",
"target": "es6",
"target": "ES2020",
"outDir": "out",
"lib": [
"es6"
"WebWorker",
"ES2020"
],
"sourceMap": true,
"rootDir": "src",

Просмотреть файл

@ -293,7 +293,7 @@ balanced-match@^1.0.0:
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
base64-js@^1.3.1:
base64-js@^1.3.1, base64-js@^1.5.1:
version "1.5.1"
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==