support writeMemory requests
This commit is contained in:
Родитель
477787b208
Коммит
cfa37d833d
15
package.json
15
package.json
|
@ -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==
|
||||
|
|
Загрузка…
Ссылка в новой задаче