diff --git a/jerry-debugger/jerry-client-ts/src/lib/__tests__/cdt-controller.test.ts b/jerry-debugger/jerry-client-ts/src/lib/__tests__/cdt-controller.test.ts index ec2951e62e..1c5103764d 100644 --- a/jerry-debugger/jerry-client-ts/src/lib/__tests__/cdt-controller.test.ts +++ b/jerry-debugger/jerry-client-ts/src/lib/__tests__/cdt-controller.test.ts @@ -24,7 +24,7 @@ describe('onError', () => { const controller = new CDTController(); controller.onError(42, 'foo'); expect(spy).toHaveBeenCalled(); - expect(spy.mock.calls[0][0]).toEqual('Error: foo (42)'); + expect(spy.mock.calls[0][0]).toEqual('\nError: foo (42)\n'); }); }); diff --git a/jerry-debugger/jerry-client-ts/src/lib/__tests__/protocol-handler.test.ts b/jerry-debugger/jerry-client-ts/src/lib/__tests__/protocol-handler.test.ts index bf91b4c077..28910eb0da 100644 --- a/jerry-debugger/jerry-client-ts/src/lib/__tests__/protocol-handler.test.ts +++ b/jerry-debugger/jerry-client-ts/src/lib/__tests__/protocol-handler.test.ts @@ -588,7 +588,7 @@ describe('logPacket', () => { const handler = new JerryDebugProtocolHandler({}); handler.logPacket('foo'); expect(spy).toHaveBeenCalled(); - expect(spy.mock.calls[0][0]).toEqual('[foo]'); + expect(spy.mock.calls[0][0]).toEqual('[Debugger > foo]'); }); it('prints packet name in brackets with second arg false', () => { @@ -596,7 +596,7 @@ describe('logPacket', () => { const handler = new JerryDebugProtocolHandler({}); handler.logPacket('foo', false); expect(spy).toHaveBeenCalled(); - expect(spy.mock.calls[0][0]).toEqual('[foo]'); + expect(spy.mock.calls[0][0]).toEqual('[Debugger > foo]'); }); it('prints packet name in brackets with second arg true', () => { @@ -605,6 +605,6 @@ describe('logPacket', () => { (handler as any).evalsPending = 1; handler.logPacket('foo', true); expect(spy).toHaveBeenCalled(); - expect(spy.mock.calls[0][0]).toEqual('[Ignored: foo]'); + expect(spy.mock.calls[0][0]).toEqual('[Debugger > Ignored: foo]'); }); }); diff --git a/jerry-debugger/jerry-client-ts/src/lib/cdt-controller.ts b/jerry-debugger/jerry-client-ts/src/lib/cdt-controller.ts index af32ce94e7..9ad9105acd 100644 --- a/jerry-debugger/jerry-client-ts/src/lib/cdt-controller.ts +++ b/jerry-debugger/jerry-client-ts/src/lib/cdt-controller.ts @@ -17,7 +17,7 @@ import Crdp from 'chrome-remote-debug-protocol'; import { Breakpoint } from './breakpoint'; import { JerryDebugProtocolHandler, JerryMessageScriptParsed, JerryMessageBreakpointHit } from './protocol-handler'; import { ChromeDevToolsProxyServer } from './cdt-proxy'; -import { JERRY_DEBUGGER_EVAL_OK } from './jrs-protocol-constants'; +import * as SP from './jrs-protocol-constants'; export interface JerryDebuggerDelegate { onScriptParsed?(message: JerryMessageScriptParsed): void; @@ -47,7 +47,7 @@ export class CDTController { // JerryDebuggerDelegate functions onError(code: number, message: string) { - console.log(`Error: ${message} (${code})`); + console.log(`\nError: ${message} (${code})\n`); } onScriptParsed(message: JerryMessageScriptParsed) { @@ -81,7 +81,7 @@ export class CDTController { type: 'string', value: result, }; - if (subType === JERRY_DEBUGGER_EVAL_OK) { + if (subType === SP.JERRY_DEBUGGER_EVAL_OK) { functions!.resolve({ result: remoteObject, }); @@ -93,6 +93,28 @@ export class CDTController { } } + onOutputResult(subType: number, message: string) { + let type: 'debug' | 'error' | 'log' | 'trace' | 'warning' = 'log'; + switch (subType) { + case SP.JERRY_DEBUGGER_OUTPUT_DEBUG: + type = 'debug'; + break; + case SP.JERRY_DEBUGGER_OUTPUT_ERROR: + type = 'error'; + break; + case SP.JERRY_DEBUGGER_OUTPUT_TRACE: + type = 'trace'; + break; + case SP.JERRY_DEBUGGER_OUTPUT_WARNING: + type = 'warning'; + break; + } + // NOTE: this drops an early 'Connected' message + if (this.proxyServer) { + this.proxyServer.sendConsoleAPICalled(type, message); + } + } + onResume() { this.proxyServer!.sendResumed(); } diff --git a/jerry-debugger/jerry-client-ts/src/lib/cdt-proxy.ts b/jerry-debugger/jerry-client-ts/src/lib/cdt-proxy.ts index a73bcaf462..835890b51d 100644 --- a/jerry-debugger/jerry-client-ts/src/lib/cdt-proxy.ts +++ b/jerry-debugger/jerry-client-ts/src/lib/cdt-proxy.ts @@ -219,4 +219,18 @@ export class ChromeDevToolsProxyServer { sendResumed() { this.api.Debugger.emitResumed(); } + + sendConsoleAPICalled(type: 'debug' | 'log' | 'error' | 'trace' | 'warning', message: string) { + this.api.Runtime.emitConsoleAPICalled({ + type, + args: [ + { + type: 'string', + value: message, + }, + ], + executionContextId: 1, + timestamp: (new Date()).valueOf(), + }); + } } diff --git a/jerry-debugger/jerry-client-ts/src/lib/protocol-handler.ts b/jerry-debugger/jerry-client-ts/src/lib/protocol-handler.ts index a19a49a6e6..28ddce0f7f 100644 --- a/jerry-debugger/jerry-client-ts/src/lib/protocol-handler.ts +++ b/jerry-debugger/jerry-client-ts/src/lib/protocol-handler.ts @@ -41,6 +41,7 @@ export interface JerryDebugProtocolDelegate { onBreakpointHit?(message: JerryMessageBreakpointHit): void; onEvalResult?(subType: number, result: string): void; onError?(code: number, message: string): void; + onOutputResult?(subType: number, result: string): void; onResume?(): void; onScriptParsed?(message: JerryMessageScriptParsed): void; } @@ -97,6 +98,7 @@ export class JerryDebugProtocolHandler { private functionName?: string; private functionNameData?: Uint8Array; private evalResultData?: Uint8Array; + private outputResultData?: Uint8Array; private functions: FunctionMap = {}; private newFunctions: FunctionMap = {}; private backtrace: Array = []; @@ -135,6 +137,8 @@ export class JerryDebugProtocolHandler { [SP.JERRY_DEBUGGER_BACKTRACE_END]: this.onBacktrace, [SP.JERRY_DEBUGGER_EVAL_RESULT]: this.onEvalResult, [SP.JERRY_DEBUGGER_EVAL_RESULT_END]: this.onEvalResult, + [SP.JERRY_DEBUGGER_OUTPUT_RESULT]: this.onOutputResult, + [SP.JERRY_DEBUGGER_OUTPUT_RESULT_END]: this.onOutputResult, }; } @@ -159,6 +163,7 @@ export class JerryDebugProtocolHandler { if (this.lastBreakpointHit) { throw new Error('attempted pause while at breakpoint'); } + this.logSentPacket('Stop'); this.debuggerClient!.send(encodeMessage(this.byteConfig, 'B', [SP.JERRY_DEBUGGER_STOP])); } @@ -388,6 +393,7 @@ export class JerryDebugProtocolHandler { // just patch up incoming message data[0] = SP.JERRY_DEBUGGER_FREE_BYTE_CODE_CP; + this.logSentPacket('Free Byte Code CP'); this.debuggerClient!.send(data); } @@ -487,6 +493,19 @@ export class JerryDebugProtocolHandler { } } + onOutputResult(data: Uint8Array) { + this.logPacket('Output Result'); + this.outputResultData = assembleUint8Arrays(this.outputResultData, data); + if (data[0] === SP.JERRY_DEBUGGER_OUTPUT_RESULT_END) { + const subType = data[data.length - 1]; + const outputResult = cesu8ToString(this.outputResultData.slice(0, -1)); + if (this.delegate.onOutputResult) { + this.delegate.onOutputResult(subType, outputResult); + } + this.outputResultData = undefined; + } + } + onMessage(message: Uint8Array) { if (message.byteLength < 1) { this.abort('message too short'); @@ -544,6 +563,11 @@ export class JerryDebugProtocolHandler { let offset = 0; while (offset < arrayLength - 1) { const clamped = Math.min(arrayLength - offset, this.maxMessageSize); + if (offset) { + this.logSentPacket('Eval Part'); + } else { + this.logSentPacket('Eval'); + } this.debuggerClient!.send(array.slice(offset, offset + clamped)); offset += clamped - 1; array[offset] = SP.JERRY_DEBUGGER_EVAL_PART; @@ -582,6 +606,7 @@ export class JerryDebugProtocolHandler { delete this.activeBreakpoints[breakpointId]; breakpoint.activeIndex = -1; } + this.logSentPacket('Update Breakpoint'); this.debuggerClient!.send(encodeMessage(this.byteConfig, 'BBCI', [ SP.JERRY_DEBUGGER_UPDATE_BREAKPOINT, Number(enable), @@ -595,18 +620,23 @@ export class JerryDebugProtocolHandler { if (!this.lastBreakpointHit) { throw new Error('backtrace not allowed while app running'); } + this.logSentPacket('Get Backtrace'); this.debuggerClient!.send(encodeMessage(this.byteConfig, 'BI', [SP.JERRY_DEBUGGER_GET_BACKTRACE, 0])); } logPacket(description: string, ignorable: boolean = false) { // certain packets are ignored while evals are pending const ignored = (ignorable && this.evalsPending) ? 'Ignored: ' : ''; - console.log(`[${ignored}${description}]`); + console.log(`[Debugger > ${ignored}${description}]`); + } + + logSentPacket(description: string) { + // certain packets are ignored while evals are pending + console.log(`[Debugger < ${description}]`); } private abort(message: string) { if (this.delegate.onError) { - console.log('Abort:', message); this.delegate.onError(0, message); } } @@ -616,6 +646,15 @@ export class JerryDebugProtocolHandler { throw new Error('attempted resume while not at breakpoint'); } this.lastBreakpointHit = undefined; + let cmd = 'Next'; + if (code === SP.JERRY_DEBUGGER_STEP) { + cmd = 'Step'; + } else if (code === SP.JERRY_DEBUGGER_FINISH) { + cmd = 'Finish'; + } else if (code === SP.JERRY_DEBUGGER_CONTINUE) { + cmd = 'Continue'; + } + this.logSentPacket(cmd); this.debuggerClient!.send(encodeMessage(this.byteConfig, 'B', [code])); if (this.delegate.onResume) { this.delegate.onResume();