Skip to content

Commit 707be3d

Browse files
committed
fix: Add protocol level support for extended properties (#566)
* fix: Add protocol level support for extended properties * Added tests and always enable 'extended_properties' feature.
1 parent 7091fb8 commit 707be3d

File tree

6 files changed

+70
-9
lines changed

6 files changed

+70
-9
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
1010

1111
- Option to start PHP built-in web server without router script.
1212
- Extended logging with DBGp packets.
13+
- Extended properties support. Always enable extended properties so fields are decoded in UTF-8.
1314

1415
### Changed
1516

src/phpDebug.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,10 @@ class PhpDebugSession extends vscode.DebugSession {
313313
if (feat_no.supported === '1') {
314314
await connection.sendFeatureSetCommand('notify_ok', '1')
315315
}
316+
let feat_ep = await connection.sendFeatureGetCommand('extended_properties')
317+
if (feat_ep.supported === '1') {
318+
await connection.sendFeatureSetCommand('extended_properties', '1')
319+
}
316320

317321
// override features from launch.json
318322
try {

src/test/adapter.ts

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -399,7 +399,7 @@ describe('PHP Debug Adapter', () => {
399399
}),
400400
client.waitForEvent('initialized'),
401401
])
402-
await client.setBreakpointsRequest({ source: { path: program }, breakpoints: [{ line: 17 }] })
402+
await client.setBreakpointsRequest({ source: { path: program }, breakpoints: [{ line: 19 }] })
403403
const [, event] = await Promise.all([
404404
client.configurationDoneRequest(),
405405
client.waitForEvent('stopped') as Promise<DebugProtocol.StoppedEvent>,
@@ -495,6 +495,38 @@ describe('PHP Debug Adapter', () => {
495495
assert.propertyVal(arrayWithSpaceKeyItems[0], 'name', 'space key')
496496
assert.propertyVal(arrayWithSpaceKeyItems[0], 'value', '1')
497497
})
498+
499+
it('should report values with null correctly', async () => {
500+
const arrayExtended = localVariables.find(variable => variable.name === '$arrayExtended')
501+
assert.isDefined(arrayExtended)
502+
assert.propertyVal(arrayExtended!, 'value', 'array(1)')
503+
assert.property(arrayExtended!, 'variablesReference')
504+
const arrayExtendedItems = (
505+
await client.variablesRequest({
506+
variablesReference: arrayExtended!.variablesReference,
507+
})
508+
).body.variables
509+
assert.lengthOf(arrayExtendedItems, 1)
510+
assert.propertyVal(arrayExtendedItems[0], 'name', 'a\0b')
511+
assert.propertyVal(arrayExtendedItems[0], 'value', '"c\0d"')
512+
})
513+
514+
it('should report values with unicode correctly', async () => {
515+
const arrayExtended = localVariables.find(variable => variable.name === '$arrayExtended2')
516+
assert.isDefined(arrayExtended)
517+
assert.propertyVal(arrayExtended!, 'value', 'array(2)')
518+
assert.property(arrayExtended!, 'variablesReference')
519+
const arrayExtendedItems = (
520+
await client.variablesRequest({
521+
variablesReference: arrayExtended!.variablesReference,
522+
})
523+
).body.variables
524+
assert.lengthOf(arrayExtendedItems, 2)
525+
assert.propertyVal(arrayExtendedItems[0], 'name', 'Приветствие')
526+
assert.propertyVal(arrayExtendedItems[0], 'value', '"КУ-КУ"')
527+
assert.propertyVal(arrayExtendedItems[1], 'name', 'Прощание')
528+
assert.propertyVal(arrayExtendedItems[1], 'value', '"Па-Ка"')
529+
})
498530
})
499531

500532
// support for user defined constants was added in 2.3.0

src/test/dbgp.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { assert } from 'chai'
66
describe('DbgpConnection', () => {
77
function makePacket(message: string): Buffer {
88
const messageBuffer = iconv.encode(message, ENCODING)
9-
return Buffer.concat([new Buffer(messageBuffer.length + '\0'), messageBuffer, new Buffer('\0')])
9+
return Buffer.concat([Buffer.from(messageBuffer.length + '\0'), messageBuffer, Buffer.from('\0')])
1010
}
1111

1212
const message =

src/xdebugConnection.ts

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -398,7 +398,7 @@ export class SourceResponse extends Response {
398398
source: string
399399
constructor(document: XMLDocument, connection: Connection) {
400400
super(document, connection)
401-
this.source = new Buffer(document.documentElement.textContent!, 'base64').toString()
401+
this.source = Buffer.from(document.documentElement.textContent!, 'base64').toString()
402402
}
403403
}
404404

@@ -464,20 +464,28 @@ export abstract class BaseProperty {
464464
constructor(propertyNode: Element) {
465465
if (propertyNode.hasAttribute('name')) {
466466
this.name = propertyNode.getAttribute('name')!
467+
} else if (propertyNode.getElementsByTagName('name').length > 0) {
468+
this.name = decodeTag(propertyNode, 'name')
467469
}
468470
this.type = propertyNode.getAttribute('type')!
469471
if (propertyNode.hasAttribute('classname')) {
470472
this.class = propertyNode.getAttribute('classname')!
473+
} else if (propertyNode.getElementsByTagName('classname').length > 0) {
474+
this.class = decodeTag(propertyNode, 'classname')
471475
}
472476
this.hasChildren = !!parseInt(propertyNode.getAttribute('children')!)
473477
if (this.hasChildren) {
474478
this.numberOfChildren = parseInt(propertyNode.getAttribute('numchildren')!)
475479
} else {
476-
const encoding = propertyNode.getAttribute('encoding')
477-
if (encoding) {
478-
this.value = iconv.encode(propertyNode.textContent!, encoding) + ''
480+
if (propertyNode.getElementsByTagName('value').length > 0) {
481+
this.value = decodeTag(propertyNode, 'value')
479482
} else {
480-
this.value = propertyNode.textContent!
483+
const encoding = propertyNode.getAttribute('encoding')
484+
if (encoding) {
485+
this.value = iconv.encode(propertyNode.textContent!, encoding) + ''
486+
} else {
487+
this.value = propertyNode.textContent!
488+
}
481489
}
482490
}
483491
}
@@ -498,7 +506,11 @@ export class Property extends BaseProperty {
498506
*/
499507
constructor(propertyNode: Element, context: Context) {
500508
super(propertyNode)
501-
this.fullName = propertyNode.getAttribute('fullname')!
509+
if (propertyNode.hasAttribute('fullname')) {
510+
this.fullName = propertyNode.getAttribute('fullname')!
511+
} else if (propertyNode.getElementsByTagName('fullname').length > 0) {
512+
this.fullName = decodeTag(propertyNode, 'fullname')
513+
}
502514
this.context = context
503515
if (this.hasChildren) {
504516
this.children = Array.from(propertyNode.childNodes).map(
@@ -518,6 +530,16 @@ export class Property extends BaseProperty {
518530
}
519531
}
520532

533+
function decodeTag(propertyNode: Element, tagName: string): string {
534+
const tag = propertyNode.getElementsByTagName(tagName).item(0)!
535+
const encoding = tag.getAttribute('encoding')
536+
if (encoding) {
537+
return iconv.encode(tag.textContent!, encoding) + ''
538+
} else {
539+
return tag.textContent!
540+
}
541+
}
542+
521543
/** The response to a context_get command */
522544
export class ContextGetResponse extends Response {
523545
/** the available properties inside the context */
@@ -741,7 +763,7 @@ export class Connection extends DbgpConnection {
741763
commandString += ' ' + command.args
742764
}
743765
if (command.data) {
744-
commandString += ' -- ' + new Buffer(command.data).toString('base64')
766+
commandString += ' -- ' + Buffer.from(command.data).toString('base64')
745767
}
746768
commandString += '\0'
747769
const data = iconv.encode(commandString, ENCODING)

testproject/variables.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,7 @@
1313
$variableThatsNotSet;
1414
$aLargeArray = array_fill(0, 100, 'test');
1515
$arrayWithSpaceKey = array('space key' => 1);
16+
$arrayExtended = array("a\0b" => "c\0d");
17+
$arrayExtended2 = array("Приветствие" => "КУ-КУ", "Прощание" => "Па-Ка");
1618

1719
exit;

0 commit comments

Comments
 (0)