@@ -143,6 +143,7 @@ class PhpDebugSession extends vscode.DebugSession {
143
143
supportsEvaluateForHovers : false ,
144
144
supportsConditionalBreakpoints : true ,
145
145
supportsFunctionBreakpoints : true ,
146
+ supportsCompletionsRequest : true ,
146
147
exceptionBreakpointFilters : [
147
148
{
148
149
filter : 'Notice' ,
@@ -706,6 +707,105 @@ class PhpDebugSession extends vscode.DebugSession {
706
707
this . sendResponse ( response ) ;
707
708
}
708
709
710
+ protected async completionsRequest ( response : VSCodeDebugProtocol . CompletionsResponse , args : VSCodeDebugProtocol . CompletionsArguments ) {
711
+ try {
712
+ if ( ! args . frameId ) {
713
+ throw new Error ( 'No stack frame given' ) ;
714
+ }
715
+ const lineIndex : number = args . line ? args . line - 1 : 0 ;
716
+ const lines : string [ ] = args . text . split ( '\n' ) ;
717
+ /** The text before the cursor */
718
+ const typed : string = [ ...lines . slice ( 0 , Math . max ( lineIndex - 1 , 0 ) ) , lines [ lineIndex ] . substring ( 0 , args . column ) ] . join ( '\n' ) ;
719
+ let i = typed . length ;
720
+ let containerName : string ;
721
+ let operator : string | undefined ;
722
+ let query : string ;
723
+ while ( true ) {
724
+ const substr = typed . substring ( 0 , i ) ;
725
+ if ( / \[ $ / . test ( substr ) ) {
726
+ // Numeric array index
727
+ operator = '[' ;
728
+ } else if ( / \[ ' $ / . test ( substr ) ) {
729
+ // String array index
730
+ operator = `['` ;
731
+ } else if ( / - > $ / . test ( substr ) ) {
732
+ operator = '->' ;
733
+ } else if ( i > 0 ) {
734
+ i -- ;
735
+ continue ;
736
+ }
737
+ query = typed . substr ( i ) . toLowerCase ( ) ;
738
+ containerName = typed . substring ( 0 , operator ? i - operator . length : i ) ;
739
+ break ;
740
+ }
741
+ const frame = this . _stackFrames . get ( args . frameId ) ;
742
+ const contexts = await frame . getContexts ( ) ;
743
+ const targets : VSCodeDebugProtocol . CompletionItem [ ] = [ ] ;
744
+ if ( ! containerName || ! operator ) {
745
+ const responses = await Promise . all ( contexts . map ( context => context . getProperties ( ) ) ) ;
746
+ for ( const properties of responses ) {
747
+ for ( const property of properties ) {
748
+ if ( property . name . toLowerCase ( ) . startsWith ( query ) ) {
749
+ const text = property . name [ 0 ] === '$' ? property . name . substr ( 1 ) : property . name ;
750
+ targets . push ( { label : property . name , text, type : 'variable' , start : i , length : property . name . length } ) ;
751
+ }
752
+ }
753
+ }
754
+ } else {
755
+ // Search all contexts
756
+ for ( const context of contexts ) {
757
+ let response : xdebug . PropertyGetResponse | undefined ;
758
+ try {
759
+ response = await frame . connection . sendPropertyGetCommand ( { context, fullName : containerName } ) ;
760
+ } catch ( err ) {
761
+ // ignore
762
+ }
763
+ if ( response ) {
764
+ for ( const property of response . children ) {
765
+ if ( property . name . toLowerCase ( ) . startsWith ( query ) ) {
766
+ let type : VSCodeDebugProtocol . CompletionItemType | undefined ;
767
+ let text : string = property . name ;
768
+ if ( operator === '->' ) {
769
+ // Object
770
+ type = 'property' ;
771
+ } else if ( operator [ 0 ] === '[' ) {
772
+ // Array
773
+ if ( parseInt ( property . name ) + '' === property . name ) {
774
+ // Numeric index
775
+ if ( operator [ 1 ] === `'` ) {
776
+ continue ;
777
+ }
778
+ type = 'value' ;
779
+ text += ']' ;
780
+ } else {
781
+ // String index
782
+ if ( operator [ 1 ] !== `'` ) {
783
+ if ( query ) {
784
+ continue ;
785
+ } else {
786
+ text = `'` + text ;
787
+ }
788
+ }
789
+ type = 'text' ;
790
+ text += `']` ;
791
+ }
792
+ }
793
+ targets . push ( { label : property . name , text, type, start : i , length : property . name . length } ) ;
794
+ }
795
+ }
796
+ // If we found the variable in one context (typically Locals), abort
797
+ break ;
798
+ }
799
+ }
800
+ }
801
+ response . body = { targets} ;
802
+ } catch ( err ) {
803
+ this . sendErrorResponse ( response , err ) ;
804
+ return ;
805
+ }
806
+ this . sendResponse ( response ) ;
807
+ }
808
+
709
809
protected async continueRequest ( response : VSCodeDebugProtocol . ContinueResponse , args : VSCodeDebugProtocol . ContinueArguments ) {
710
810
let xdebugResponse : xdebug . StatusResponse | undefined ;
711
811
try {
0 commit comments