Skip to content

Commit bcc803c

Browse files
committed
✨ impl jsdos
1 parent cd426d3 commit bcc803c

File tree

7 files changed

+242
-72
lines changed

7 files changed

+242
-72
lines changed

.github/workflows/ci.yml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,15 +47,16 @@ jobs:
4747
echo ">>> Started xvfb"
4848
if: runner.os == 'Linux'
4949
50-
51-
- name: yarn,test,lint
50+
- name: yarn,test
5251
run: |
5352
yarn
5453
yarn test
55-
yarn lint
5654
env:
5755
DISPLAY: ":99.0"
5856

57+
- run: yarn lint
58+
if: runner.os == 'Linux'
59+
5960
- name: Publish
6061
if: success() && startsWith( github.ref, 'refs/tags/') && matrix.os == 'ubuntu-latest'
6162
run: yarn deploy

src/ASM/main.ts

Lines changed: 109 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { API } from './vscode-dosbox';
66
import * as statusBar from './statusBar';
77
import * as Diag from '../diagnose/main';
88
import * as conf from '../utils/configuration';
9+
import { messageCollector } from '../diagnose/messageCollector';
910

1011
const fs = vscode.workspace.fs;
1112

@@ -24,6 +25,12 @@ type ACTIONS = {
2425
}
2526
};
2627

28+
export interface AsmResult {
29+
message?: string,
30+
error?: number,
31+
warn?: number
32+
}
33+
2734
export async function activate(context: vscode.ExtensionContext) {
2835
statusBar.activate(context);
2936
const diag = Diag.activate(context);
@@ -34,7 +41,8 @@ export async function activate(context: vscode.ExtensionContext) {
3441
const assemblyToolsFolder = vscode.Uri.joinPath(context.globalStorageUri, conf.extConf.asmType);
3542
const seperateSpaceFolder = vscode.Uri.joinPath(context.globalStorageUri, "workspace");
3643

37-
async function singleFileMode(type: actionType, _uri: vscode.Uri) {
44+
async function singleFileMode(type: actionType, _uri: vscode.Uri): Promise<AsmResult> {
45+
3846
if (nodefs.existsSync(seperateSpaceFolder.fsPath)) {
3947
await fs.delete(seperateSpaceFolder, { recursive: true, useTrash: false });
4048
}
@@ -59,69 +67,116 @@ export async function activate(context: vscode.ExtensionContext) {
5967
const bundle = await fs.readFile(bundlePath);
6068

6169
let result = "<should-not-return>";
62-
63-
switch (conf.extConf.emulator) {
64-
case conf.DosEmulatorType.dosbox:
65-
case conf.DosEmulatorType.dosboxX:
66-
const uri = vscode.Uri.joinPath(seperateSpaceFolder, ("test" + path.extname(_uri.fsPath)).toUpperCase());
67-
await fs.copy(_uri, uri);
68-
const fileInfo = path.parse(uri.fsPath);
69-
const folder = vscode.Uri.joinPath(uri, '..');
70-
71-
const autoexec = [
72-
`mount c "${assemblyToolsFolder.fsPath}""`,
73-
`mount d "${folder.fsPath}""`,
74-
'd:',
75-
...action.before
76-
];
77-
78-
const logFilename = 'box.log'.toUpperCase();
79-
const logUri = vscode.Uri.joinPath(assemblyToolsFolder, logFilename);
80-
if (nodefs.existsSync(logUri.fsPath)) {
81-
await fs.delete(logUri);
70+
const uri = vscode.Uri.joinPath(seperateSpaceFolder, ("test" + path.extname(_uri.fsPath)).toUpperCase());
71+
await fs.copy(_uri, uri);
72+
const fileInfo = path.parse(uri.fsPath);
73+
const folder = vscode.Uri.joinPath(uri, '..');
74+
75+
if (conf.extConf.emulator === conf.DosEmulatorType.dosbox || conf.extConf.emulator === conf.DosEmulatorType.dosboxX) {
76+
const autoexec = [
77+
`mount c "${assemblyToolsFolder.fsPath}""`,
78+
`mount d "${folder.fsPath}""`,
79+
'd:',
80+
...action.before
81+
];
82+
const timeStamp = new Date().getTime().toString();
83+
const logFilename = 't' + timeStamp.substr(timeStamp.length - 6, 8) + '.log'.toUpperCase();
84+
const logUri = vscode.Uri.joinPath(assemblyToolsFolder, logFilename);
85+
if (nodefs.existsSync(logUri.fsPath)) {
86+
await fs.delete(logUri);
87+
}
88+
function cb(val: string) {
89+
const r = val
90+
.replace("${file}", fileInfo.base)
91+
.replace("${filename}", fileInfo.name);
92+
if (val.startsWith('>')) {
93+
return r.replace(">", "");
8294
}
83-
function cb(val: string) {
84-
const r = val
85-
.replace("${file}", fileInfo.base)
86-
.replace("${filename}", fileInfo.name);
87-
if (val.startsWith('>')) {
88-
return r.replace(">", "");
95+
return r + " >>C:\\" + logFilename;
96+
}
97+
if (type === actionType.run) {
98+
autoexec.push(...action.run.map(cb));
99+
}
100+
if (type === actionType.debug) {
101+
autoexec.push(...action.debug.map(cb));
102+
}
103+
104+
autoexec.push("exit");
105+
106+
const box = conf.extConf.emulator === conf.DosEmulatorType.dosboxX ? api.dosboxX : api.dosbox;
107+
await box.fromBundle(bundle, assemblyToolsFolder);
108+
box.updateAutoexec(autoexec);
109+
110+
if (type !== actionType.open) {
111+
const [hook, promise] = messageCollector();
112+
nodefs.watchFile(logUri.fsPath, () => {
113+
try {
114+
if (nodefs.existsSync(logUri.fsPath)) {
115+
const _result = nodefs.readFileSync(logUri.fsPath, { encoding: 'utf-8' });
116+
hook(_result);
117+
}
89118
}
90-
return r + " >>C:\\" + logFilename;
91-
}
92-
if (type === actionType.run) {
93-
autoexec.push(...action.run.map(cb));
94-
}
95-
if (type === actionType.debug) {
96-
autoexec.push(...action.debug.map(cb));
97-
}
119+
catch (e) {
120+
console.error(e);
121+
}
122+
});
123+
promise.then(val => result = val);
124+
}
125+
await box.run();
126+
if (result === '<should-not-return>') {
127+
result = (await fs.readFile(logUri)).toString();
128+
}
129+
}
98130

99-
autoexec.push("exit");
131+
if (conf.extConf.emulator === conf.DosEmulatorType.jsdos) {
132+
await api.jsdos.jszip.loadAsync(bundle);
133+
api.jsdos.jszip.file('code/' + fileInfo.base, doc.getText());
134+
const autoexec = [
135+
`mount c .`,
136+
`mount d ./code`,
137+
'd:',
138+
...action.before
139+
];
140+
function cb(val: string) {
141+
const r = val
142+
.replace("${file}", fileInfo.base)
143+
.replace("${filename}", fileInfo.name);
144+
if (val.startsWith('>')) {
145+
return r.replace(">", "");
146+
}
147+
return r;
148+
}
149+
if (type === actionType.run) {
150+
autoexec.push(...action.run.map(cb));
151+
}
152+
if (type === actionType.debug) {
153+
autoexec.push(...action.debug.map(cb));
154+
}
155+
api.jsdos.updateAutoexec(autoexec);
156+
const webview = await api.jsdos.runInWebview();
157+
if (type !== actionType.open) {
158+
const [hook, promise] = messageCollector();
159+
webview.onDidReceiveMessage(e => {
160+
switch (e.command) {
161+
case 'stdout':
162+
hook(e.value);
163+
break;
164+
}
165+
});
166+
result = await promise;
167+
}
168+
}
100169

101-
const box = conf.extConf.emulator === conf.DosEmulatorType.dosboxX ? api.dosboxX : api.dosbox;
102-
await box.fromBundle(bundle, assemblyToolsFolder);
103-
box.updateAutoexec(autoexec);
104-
const _run = box.run();
105-
const _wait = new Promise<void>(
106-
resolve => setTimeout(resolve, 10000)
107-
);
108-
await Promise.race([_run, _wait]);
109-
result = (await fs.readFile(logUri)).toString();
110-
break;
111-
case conf.DosEmulatorType.jsdos:
112-
api.jsdos.setBundle(bundle);
113-
api.jsdos.runInWebview();
114-
break;
115-
case conf.DosEmulatorType.msdos:
116-
api.msdosPlayer();
117-
break;
170+
if (conf.extConf.emulator === conf.DosEmulatorType.msdos) {
171+
api.msdosPlayer();
118172
}
119173

120174
const diagnose = diag.process(result, doc, conf.extConf.asmType);
121175

122176
return {
123177
message: result,
124-
diagnose
178+
error: diagnose?.error,
179+
warn: diagnose?.warn
125180
};
126181
}
127182

src/ASM/statusBar.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ async function statusBarCommand() {
3838
const [emu1, asm1] = Selected?.split(' ');
3939
const target = vscode.ConfigurationTarget.Workspace;
4040
await _conf.update('emulator', emu1, target);
41-
await _conf.update('MASMorTASM', asm1, target);
41+
await _conf.update('assembler', asm1, target);
4242
showStatus();
4343
}
4444
}

src/ASM/vscode-dosbox.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
*/
55

66
import { CommandInterface, Emulators } from 'emulators';
7+
import * as Jszip from 'jszip';
78
import * as vscode from 'vscode';
89

910
export interface DosboxResult {
@@ -37,6 +38,7 @@ export interface Dosbox {
3738
}
3839

3940
export interface Jsdos {
41+
jszip: Jszip,
4042
/**
4143
* set the jsdos bundle to use
4244
* @param bundle the Uint8Array data of the jsdos bundle or its Uri

src/diagnose/messageCollector.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
2+
3+
export function messageCollector(): [(msg: string) => void, Promise<string>] {
4+
let allmsg = "";
5+
let resolve: ((value: string) => void) | undefined = undefined;
6+
return [
7+
(msg: string) => {
8+
allmsg += msg;
9+
let re = allmsg.match(/Microsoft \(R\) MASM Compatibility Driver([\s\S]*)Microsoft \(R\) Segmented Executable Linker/);
10+
if (re && re[1] && resolve) {
11+
resolve(re[1]);
12+
resolve = undefined;
13+
}
14+
re = allmsg.match(/Turbo Assembler Version 4.1 Copyright \(c\) 1988, 1996 Borland International([\s\S]*)Turbo Link Version 7\./);
15+
if (re && re[1] && resolve) {
16+
resolve(re[1]);
17+
resolve = undefined;
18+
}
19+
}
20+
,
21+
new Promise<string>(
22+
_resolve => resolve = _resolve
23+
)];
24+
25+
}

src/test/suite/ASM.test.ts renamed to src/test/suite/dosbox.test.ts

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ import * as assert from 'assert';
44
// You can import and use all API from the 'vscode' module
55
// as well as import your extension to test it
66
import * as vscode from 'vscode';
7-
import { DIAGCODE, DIAGINFO } from '../../diagnose/main';
7+
import { AsmResult } from '../../ASM/main';
8+
import { DIAGCODE } from '../../diagnose/main';
89
import { DosEmulatorType, Assembler } from '../../utils/configuration';
910

1011
// import * as myExtension from '../../extension';
@@ -18,15 +19,14 @@ suite('Extension Test Suite', function () {
1819
Assembler.TASM,
1920
];
2021
const emulator: DosEmulatorType[] = [
21-
// DosEmulatorType.jsdos,
2222
DosEmulatorType.dosbox,
2323
DosEmulatorType.dosboxX,
2424
];
2525

26-
const filelist: [string, DIAGCODE][] = [
27-
['1.asm', DIAGCODE.ok],
26+
const filelist: [string, number][] = [
27+
['1.asm', 0],
2828
// ['2.asm', DIAGCODE.ok],
29-
['3中文路径hasError.asm', DIAGCODE.hasError]
29+
['3中文路径hasError.asm', 1]
3030
];
3131

3232
const args: [string, DIAGCODE, DosEmulatorType, Assembler][] = [];
@@ -41,11 +41,11 @@ suite('Extension Test Suite', function () {
4141
shuffle(args).forEach((val) => { testAsmCode(...val); });
4242
});
4343

44-
function testAsmCode(file: string, diagcode: DIAGCODE, emu: DosEmulatorType, asm: Assembler): void {
45-
test(`test file ${file} in ${emu} use ${asm} want ${DIAGCODE[diagcode]} ${diagcode}`,
44+
function testAsmCode(file: string, shouldErr: number, emu: DosEmulatorType, asm: Assembler): void {
45+
test(`test file ${file} in ${emu} use ${asm} want should ${shouldErr} error`,
4646
async function () {
47-
this.timeout('120s');
48-
this.slow('10s');
47+
this.timeout('60s');
48+
this.slow('20s');
4949
//skip azure pipeline test for this condition
5050
if (file === '3中文路径hasError.asm' && emu === DosEmulatorType.msdos && asm === Assembler.MASM && !process.env.LANG?.includes('zh_CN')) {
5151
this.skip();
@@ -56,9 +56,9 @@ function testAsmCode(file: string, diagcode: DIAGCODE, emu: DosEmulatorType, asm
5656
await vscode.commands.executeCommand('vscode.open', samplefile);
5757

5858
//update settings
59-
await vscode.workspace.getConfiguration('masmtasm').update("dosbox.run", "exit", vscode.ConfigurationTarget.Global);
60-
await vscode.workspace.getConfiguration('masmtasm').update("ASM.emulator", emu, vscode.ConfigurationTarget.Global);
61-
await vscode.workspace.getConfiguration('masmtasm').update("ASM.assembler", asm, vscode.ConfigurationTarget.Global);
59+
await vscode.workspace.getConfiguration('masmtasm').update("dosbox.run", "exit");
60+
await vscode.workspace.getConfiguration('masmtasm').update("ASM.emulator", emu);
61+
await vscode.workspace.getConfiguration('masmtasm').update("ASM.assembler", asm);
6262

6363
//assert the extension activated and command contributed
6464
const vscodecmds = await vscode.commands.getCommands(true);
@@ -72,8 +72,9 @@ function testAsmCode(file: string, diagcode: DIAGCODE, emu: DosEmulatorType, asm
7272

7373
//assert message processed
7474
const _result = await vscode.commands.executeCommand(cmd, samplefile);
75-
const { message, diagnose } = _result as { message: string, diagnose: DIAGINFO | undefined };
76-
assert.strictEqual(diagnose?.code, diagcode, DIAGCODE[diagcode] + message);
75+
const { message, error } = _result as AsmResult;
76+
assert.strictEqual(error, shouldErr, message);
77+
7778
});
7879
}
7980

0 commit comments

Comments
 (0)