Skip to content

Commit ba80803

Browse files
knightburtonyichoi
authored andcommitted
Impore the source sending feature (#30)
- Move the file handling into the extension file - Create custom event and custom request - Fix the after state of source sending IoT.js-Debug-DCO-1.0-Signed-off-by: Imre Kiss [email protected]
1 parent 14bc9c0 commit ba80803

File tree

5 files changed

+124
-54
lines changed

5 files changed

+124
-54
lines changed

package.json

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,7 @@
5656
},
5757
"activationEvents": [
5858
"onDebug",
59-
"onCommand:iotjs-debug.initialConfigurations",
60-
"onCommand:iotjs-debug.getProgramName"
59+
"onCommand:iotjs-debug.initialConfigurations"
6160
],
6261
"main": "./out/extension.js",
6362
"files": [
@@ -115,11 +114,6 @@
115114
"type": "boolean",
116115
"description": "Allowes to log debug messages to the console.",
117116
"default": false
118-
},
119-
"program": {
120-
"type": "string",
121-
"description": "Absolute path to file. Leave it blank if you started server in normal mode.",
122-
"default": "${command:AskForProgramName}"
123117
}
124118
}
125119
}
@@ -136,14 +130,10 @@
136130
"port": 5001,
137131
"localRoot": "${workspaceRoot}",
138132
"stopOnEntry": false,
139-
"debugLog": false,
140-
"program": "^\"\\${command:AskForProgramName}\""
133+
"debugLog": false
141134
}
142135
}
143-
],
144-
"variables": {
145-
"AskForProgramName": "iotjs-debug.getProgramName"
146-
}
136+
]
147137
}
148138
]
149139
}

src/IotjsDebugger.ts

Lines changed: 58 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -17,21 +17,28 @@
1717
'use strict';
1818

1919
import {
20-
LoggingDebugSession, DebugSession, Logger, logger, InitializedEvent, OutputEvent, Thread, Source,
21-
StoppedEvent, ContinuedEvent, StackFrame, TerminatedEvent, Breakpoint as AdapterBreakpoint
20+
DebugSession, InitializedEvent, OutputEvent, Thread, Source,
21+
StoppedEvent, ContinuedEvent, StackFrame, TerminatedEvent, Breakpoint as AdapterBreakpoint, Event, ErrorDestination
2222
} from 'vscode-debugadapter';
2323
import { DebugProtocol } from 'vscode-debugprotocol';
2424
import * as Fs from 'fs';
2525
import * as Path from 'path';
26-
import { IAttachRequestArguments } from './IotjsDebuggerInterfaces';
26+
import { IAttachRequestArguments, SourceSendingOptions } from './IotjsDebuggerInterfaces';
2727
import { JerryDebuggerClient, JerryDebuggerOptions } from './JerryDebuggerClient';
2828
import {
2929
JerryDebugProtocolDelegate, JerryDebugProtocolHandler, JerryMessageScriptParsed, JerryEvalResult,
3030
JerryMessageExceptionHit
3131
} from './JerryProtocolHandler';
32-
import { EVAL_RESULT_SUBTYPE } from './JerryProtocolConstants';
32+
import { EVAL_RESULT_SUBTYPE, CLIENT as CLIENT_PACKAGE } from './JerryProtocolConstants';
3333

34-
class IotjsDebugSession extends LoggingDebugSession {
34+
enum SOURCE_SENDING_STATES {
35+
NOP = 0,
36+
WAITING = 1,
37+
IN_PROGRESS = 2,
38+
LAST_SENT = 3
39+
}
40+
41+
class IotjsDebugSession extends DebugSession {
3542

3643
// We don't support multiple threads, so we can use a hardcoded ID for the default thread
3744
private static THREAD_ID = 1;
@@ -40,15 +47,14 @@ class IotjsDebugSession extends LoggingDebugSession {
4047
private _debugLog: boolean = false;
4148
private _debuggerClient: JerryDebuggerClient;
4249
private _protocolhandler: JerryDebugProtocolHandler;
50+
private _sourceSendingOptions: SourceSendingOptions;
4351

4452
public constructor() {
45-
super('iotjs-debug.txt');
53+
super();
4654

4755
// The debugger uses zero-based lines and columns.
4856
this.setDebuggerLinesStartAt1(false);
4957
this.setDebuggerColumnsStartAt1(false);
50-
51-
logger.setup(Logger.LogLevel.Verbose, /*logToFile=*/false);
5258
}
5359

5460
protected threadsRequest(response: DebugProtocol.ThreadsResponse): void {
@@ -79,6 +85,11 @@ class IotjsDebugSession extends LoggingDebugSession {
7985
response.body.supportsStepBack = false;
8086
response.body.supportsRestartRequest = true;
8187

88+
this._sourceSendingOptions = <SourceSendingOptions>{
89+
contextReset: false,
90+
state: SOURCE_SENDING_STATES.NOP
91+
};
92+
8293
this.sendResponse(response);
8394
}
8495

@@ -140,23 +151,14 @@ class IotjsDebugSession extends LoggingDebugSession {
140151

141152
const onWaitForSource = async () => {
142153
this.log('onWaitForSource');
143-
144-
if (args.program !== '' && args.program !== '\0') {
145-
if (Fs.existsSync(`${args.localRoot}/${args.program}`)) {
146-
const content = Fs.readFileSync(`${args.localRoot}/${args.program}`, {
147-
encoding: 'utf8',
148-
flag: 'r'
149-
});
150-
await this._protocolhandler.sendClientSource(args.program, content)
151-
.then(() => this.log('Source has been sended to the engine.'))
152-
.catch(error => {
153-
this.sendErrorResponse(response, 0, error);
154-
});
155-
} else {
156-
this.sendErrorResponse(response, 0, 'You must provide a valid path to source');
154+
if (this._sourceSendingOptions.state === SOURCE_SENDING_STATES.NOP) {
155+
this._sourceSendingOptions.state = SOURCE_SENDING_STATES.WAITING;
156+
this.sendEvent(new Event('waitForSource'));
157+
} else if (this._sourceSendingOptions.state === SOURCE_SENDING_STATES.LAST_SENT) {
158+
if (!this._sourceSendingOptions.contextReset) {
159+
this._sourceSendingOptions.state = SOURCE_SENDING_STATES.NOP;
160+
this._protocolhandler.sendClientSourceControl(CLIENT_PACKAGE.JERRY_DEBUGGER_NO_MORE_SOURCES);
157161
}
158-
} else {
159-
this.sendErrorResponse(response, 0, 'You must provide a source');
160162
}
161163
};
162164

@@ -180,10 +182,15 @@ class IotjsDebugSession extends LoggingDebugSession {
180182
this._protocolhandler.debuggerClient = this._debuggerClient;
181183

182184
this._debuggerClient.connect()
183-
.then(() => this.log(`Connected to: ${args.address}:${args.port}`))
184-
.catch(error => this.log(error));
185+
.then(() => {
186+
this.log(`Connected to: ${args.address}:${args.port}`);
187+
this.sendResponse(response);
188+
})
189+
.catch(error => {
190+
this.log(error);
191+
this.sendErrorResponse(response, 0, error.message);
192+
});
185193

186-
this.sendResponse(response);
187194
this.sendEvent(new InitializedEvent());
188195
}
189196

@@ -349,6 +356,30 @@ class IotjsDebugSession extends LoggingDebugSession {
349356
.catch(error => this.sendErrorResponse(response, 0, error));
350357
}
351358

359+
protected customRequest(command: string, response: DebugProtocol.Response, args: any): void {
360+
this.log('customRequest');
361+
362+
switch (command) {
363+
case 'sendSource': {
364+
this._sourceSendingOptions.state = SOURCE_SENDING_STATES.IN_PROGRESS;
365+
this._protocolhandler.sendClientSource(args.program.name, args.program.source)
366+
.then(() => {
367+
this.log('Source has been sent to the engine.');
368+
this._sourceSendingOptions.state = SOURCE_SENDING_STATES.LAST_SENT;
369+
this.sendResponse(response);
370+
})
371+
.catch(error => {
372+
this.log(error);
373+
this._sourceSendingOptions.state = SOURCE_SENDING_STATES.NOP;
374+
this.sendErrorResponse(response, 0, error, null, ErrorDestination.User);
375+
});
376+
return;
377+
}
378+
default:
379+
super.customRequest(command, response, args);
380+
}
381+
}
382+
352383
private handleSource(data: JerryMessageScriptParsed): void {
353384
const path = `${this._args.localRoot}/${this.pathToBasename(data.name)}`;
354385
const src = this._protocolhandler.getSource(data.id);

src/IotjsDebuggerInterfaces.d.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,10 @@ export interface IAttachRequestArguments extends DebugProtocol.AttachRequestArgu
3232
// Ask for filename if in wait-for-source mode.
3333
provideSource: boolean;
3434
}
35+
36+
export interface SourceSendingOptions {
37+
// Engine context reset is available or not.
38+
contextReset: boolean;
39+
// Actual state of source sending.
40+
state: number;
41+
}

src/JerryProtocolHandler.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -758,6 +758,16 @@ export class JerryDebugProtocolHandler {
758758
return result;
759759
}
760760

761+
public sendClientSourceControl(code: number): Promise<any> {
762+
const validCodes: number[] = [SP.CLIENT.JERRY_DEBUGGER_NO_MORE_SOURCES, SP.CLIENT.JERRY_DEBUGGER_CONTEXT_RESET];
763+
764+
if (validCodes.indexOf(code) === -1) {
765+
return Promise.reject('Invalid source sending control code.');
766+
}
767+
768+
return this.sendSimpleRequest(encodeMessage(this.byteConfig, 'B', [code]));
769+
}
770+
761771
onWaitForSource() {
762772
this.waitForSourceEnabled = true;
763773
if (this.delegate.onWaitForSource) {

src/extension.ts

Lines changed: 46 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,7 @@ const initialConfigurations = [{
2828
port: 5001,
2929
localRoot: '${workspaceRoot}',
3030
stopOnEntry: false,
31-
debugLog: false,
32-
program: '${command:AskForProgramName}'
31+
debugLog: false
3332
}];
3433

3534
const provideInitialConfigurations = (): string => {
@@ -45,33 +44,66 @@ const provideInitialConfigurations = (): string => {
4544
].join('\n');
4645
};
4746

48-
const getListOfFiles = (): Array<string> => {
49-
let wsFiles = Array<string>();
47+
const walkSync = (dir: string, filelist: string[] = []): string[] => {
48+
fs.readdirSync(dir).forEach(file => {
49+
filelist = fs.statSync(path.join(dir, file)).isDirectory()
50+
? walkSync(path.join(dir, file), filelist)
51+
: filelist.concat(path.join(dir, file));
52+
});
53+
54+
return filelist.filter(f => path.extname(f).toLowerCase().match(/\.(js)$/i) && f !== '');
55+
};
56+
57+
const getListOfFiles = (): string[] => {
58+
let wsFiles: string[] = [];
5059

5160
vscode.workspace.workspaceFolders.map(folder => folder.uri.fsPath).forEach(entry => {
52-
fs.readdirSync(entry).forEach(file => {
53-
if ((fs.statSync(`${entry}/${file}`)).isFile()) {
54-
if (path.extname(file).toLowerCase().match(/\.(js)$/i)) {
55-
wsFiles.push(file);
56-
}
57-
}
58-
});
61+
console.log(walkSync(entry));
62+
wsFiles = [...wsFiles, ...walkSync(entry)];
5963
});
6064

61-
return ['\0', ...wsFiles];
65+
return wsFiles;
6266
};
6367

6468
const getProgramName = (): Thenable<string> => {
6569
return vscode.window.showQuickPick(getListOfFiles(), {
66-
placeHolder: 'Select a file you want to debug or press Enter if you are in normal mode',
70+
placeHolder: 'Select a file you want to debug',
6771
ignoreFocusOut: true
6872
});
6973
};
7074

75+
const getProgramSource = (path: string): string => {
76+
return fs.readFileSync(path, {
77+
encoding: 'utf8',
78+
flag: 'r'
79+
});
80+
};
81+
82+
const processCustomEvent = async (e: vscode.DebugSessionCustomEvent): Promise<any> => {
83+
switch (e.event) {
84+
case 'waitForSource': {
85+
if (vscode.debug.activeDebugSession) {
86+
const path = await getProgramName().then(path => path);
87+
const source = getProgramSource(path);
88+
89+
vscode.debug.activeDebugSession.customRequest('sendSource', {
90+
program: {
91+
name: path.split('/').pop(),
92+
source
93+
}
94+
});
95+
}
96+
return true;
97+
}
98+
default:
99+
return undefined;
100+
}
101+
};
102+
71103
export const activate = (context: vscode.ExtensionContext) => {
72104
context.subscriptions.push(
73105
vscode.commands.registerCommand('iotjs-debug.provideInitialConfigurations', provideInitialConfigurations),
74-
vscode.commands.registerCommand('iotjs-debug.getProgramName', getProgramName)
106+
vscode.debug.onDidReceiveDebugSessionCustomEvent(e => processCustomEvent(e))
75107
);
76108
};
77109

0 commit comments

Comments
 (0)