@@ -12,14 +12,14 @@ import { Terminal } from './terminal'
1212import { convertClientPathToDebugger , convertDebuggerPathToClient , isPositiveMatchInGlobs } from './paths'
1313import { minimatch } from 'minimatch'
1414import { BreakpointManager , BreakpointAdapter } from './breakpoints'
15- import * as semver from 'semver'
1615import { LogPointManager } from './logpoint'
1716import { ProxyConnect } from './proxyConnect'
1817import { randomUUID } from 'crypto'
1918import { getConfiguredEnvironment } from './envfile'
2019import { XdebugCloudConnection } from './cloud'
2120import { shouldIgnoreException } from './ignore'
2221import { varExportProperty } from './varExport'
22+ import { supportedEngine } from './xdebugUtils'
2323
2424if ( process . env [ 'VSCODE_NLS_CONFIG' ] ) {
2525 try {
@@ -249,6 +249,7 @@ class PhpDebugSession extends vscode.DebugSession {
249249 supportTerminateDebuggee : true ,
250250 supportsDelayedStackTraceLoading : false ,
251251 supportsClipboardContext : true ,
252+ supportsExceptionInfoRequest : true ,
252253 }
253254 this . sendResponse ( response )
254255 }
@@ -522,29 +523,24 @@ class PhpDebugSession extends vscode.DebugSession {
522523
523524 // support for breakpoints
524525 let feat : xdebug . FeatureGetResponse
525- const supportedEngine =
526- initPacket . engineName === 'Xdebug' &&
527- semver . valid ( initPacket . engineVersion , { loose : true } ) &&
528- semver . gte ( initPacket . engineVersion , '3.0.0' , { loose : true } )
529- const supportedEngine32 =
530- initPacket . engineName === 'Xdebug' &&
531- semver . valid ( initPacket . engineVersion , { loose : true } ) &&
532- semver . gte ( initPacket . engineVersion , '3.2.0' , { loose : true } )
526+ const supportedEngine30 = supportedEngine ( initPacket , '3.0.0' )
527+ const supportedEngine32 = supportedEngine ( initPacket , '3.2.0' )
528+ const supportedEngine35 = supportedEngine ( initPacket , '3.5.0' )
533529 if (
534- supportedEngine ||
530+ supportedEngine30 ||
535531 ( ( feat = await connection . sendFeatureGetCommand ( 'resolved_breakpoints' ) ) && feat . supported === '1' )
536532 ) {
537533 await connection . sendFeatureSetCommand ( 'resolved_breakpoints' , '1' )
538534 }
539535 if (
540- supportedEngine ||
536+ supportedEngine30 ||
541537 ( ( feat = await connection . sendFeatureGetCommand ( 'notify_ok' ) ) && feat . supported === '1' )
542538 ) {
543539 await connection . sendFeatureSetCommand ( 'notify_ok' , '1' )
544540 connection . on ( 'notify_user' , ( notify : xdebug . UserNotify ) => this . handleUserNotify ( notify , connection ) )
545541 }
546542 if (
547- supportedEngine ||
543+ supportedEngine30 ||
548544 ( ( feat = await connection . sendFeatureGetCommand ( 'extended_properties' ) ) && feat . supported === '1' )
549545 ) {
550546 await connection . sendFeatureSetCommand ( 'extended_properties' , '1' )
@@ -556,6 +552,12 @@ class PhpDebugSession extends vscode.DebugSession {
556552 ) {
557553 await connection . sendFeatureSetCommand ( 'breakpoint_include_return_value' , '1' )
558554 }
555+ if (
556+ supportedEngine35 ||
557+ ( ( feat = await connection . sendFeatureGetCommand ( 'virtual_exception_value' ) ) && feat . supported === '1' )
558+ ) {
559+ await connection . sendFeatureSetCommand ( 'virtual_exception_value' , '1' )
560+ }
559561
560562 // override features from launch.json
561563 try {
@@ -1529,6 +1531,77 @@ class PhpDebugSession extends vscode.DebugSession {
15291531 this . sendResponse ( response )
15301532 }
15311533 }
1534+
1535+ protected async exceptionInfoRequest (
1536+ response : VSCodeDebugProtocol . ExceptionInfoResponse ,
1537+ args : VSCodeDebugProtocol . ExceptionInfoArguments
1538+ ) : Promise < void > {
1539+ const connection = this . _connections . get ( args . threadId )
1540+ if ( ! connection ) {
1541+ throw new Error ( 'Unknown thread ID' )
1542+ }
1543+
1544+ const status = this . _statuses . get ( connection ) !
1545+
1546+ let ex : VSCodeDebugProtocol . ExceptionDetails | undefined
1547+
1548+ if ( connection . featureSet ( 'virtual_exception_value' ) ) {
1549+ let old_max_depth = 3
1550+ try {
1551+ const { stack } = await connection . sendStackGetCommand ( ) // CACHE?
1552+
1553+ if ( stack . length > 0 ) {
1554+ const ctx = await stack [ 0 ] . getContexts ( ) // CACHE
1555+ old_max_depth = < number > connection . featureSet ( 'max_depth' ) ?? 1
1556+ if ( old_max_depth < 3 ) {
1557+ await connection . sendFeatureSetCommand ( 'max_depth' , 3 )
1558+ }
1559+
1560+ const res = await connection . sendPropertyGetNameCommand ( '$__EXCEPTION' , ctx [ 0 ] )
1561+
1562+ const s = res . property . children . find (
1563+ p => p . name === 'trace' || p . name === '*Exception*trace' || p . name === '*Error*trace'
1564+ )
1565+
1566+ const at = `Created at ${
1567+ res . property . children . find ( p => p . name == 'file' ) ?. value ?? '**UNKNOWN**'
1568+ } :${ res . property . children . find ( p => p . name == 'line' ) ?. value ?? '?' } \n`
1569+ const st = s ?. children
1570+ . map (
1571+ ( t , i ) =>
1572+ `at ${ t . children . find ( p => p . name == 'class' ) ?. value ?? '' } ${
1573+ t . children . find ( p => p . name == 'type' ) ?. value ?? ''
1574+ } ${ t . children . find ( p => p . name == 'function' ) ?. value ?? '?' } () (${
1575+ t . children . find ( p => p . name == 'file' ) ?. value ?? '**UNKNOWN**'
1576+ } :${ t . children . find ( p => p . name == 'line' ) ?. value ?? '?' } )`
1577+ )
1578+ . join ( '\n' )
1579+ ex = {
1580+ message : res . property . children . find ( p => p . name === 'message' ) ?. value ?? undefined ,
1581+ typeName : res . property . class ,
1582+ fullTypeName : res . property . class ,
1583+ evaluateName : '$__EXCEPTION' ,
1584+ stackTrace : `${ at } ${ st ?? '' } ` ,
1585+ // TODO process inner/previous exception
1586+ }
1587+ }
1588+ } catch {
1589+ // Probably $__EXCEPTION not present
1590+ } finally {
1591+ if ( old_max_depth < 3 ) {
1592+ await connection . sendFeatureSetCommand ( 'max_depth' , old_max_depth )
1593+ }
1594+ }
1595+ }
1596+
1597+ response . body = {
1598+ exceptionId : status . exception . name ,
1599+ breakMode : 'always' ,
1600+ description : status . exception . message ,
1601+ details : ex ,
1602+ }
1603+ this . sendResponse ( response )
1604+ }
15321605}
15331606
15341607vscode . DebugSession . run ( PhpDebugSession )
0 commit comments