@@ -819,19 +819,20 @@ class SuggestAdapter {
819819 const disposables = new DisposableStore ( ) ;
820820 this . _disposables . set ( pid , disposables ) ;
821821
822+ const completions : extHostProtocol . ISuggestDataDto [ ] = [ ] ;
822823 const result : extHostProtocol . ISuggestResultDto = {
823824 x : pid ,
824- b : [ ] ,
825- a : { replace : typeConvert . Range . from ( replaceRange ) , insert : typeConvert . Range . from ( insertRange ) } ,
826- c : list . isIncomplete || undefined
825+ [ extHostProtocol . ISuggestResultDtoField . completions ] : completions ,
826+ [ extHostProtocol . ISuggestResultDtoField . defaultRanges ] : { replace : typeConvert . Range . from ( replaceRange ) , insert : typeConvert . Range . from ( insertRange ) } ,
827+ [ extHostProtocol . ISuggestResultDtoField . isIncomplete ] : list . isIncomplete || undefined
827828 } ;
828829
829830 for ( let i = 0 ; i < list . items . length ; i ++ ) {
830- const suggestion = this . _convertCompletionItem ( list . items [ i ] , pos , [ pid , i ] ) ;
831- // check for bad completion item
832- // for the converter did warn
833- if ( suggestion ) {
834- result . b . push ( suggestion ) ;
831+ const item = list . items [ i ] ;
832+ // check for bad completion item first
833+ if ( this . _validateCompletionItem ( item , pos ) ) {
834+ const dto = this . _convertCompletionItem ( item , [ pid , i ] , insertRange , replaceRange ) ;
835+ completions . push ( dto ) ;
835836 }
836837 }
837838
@@ -850,12 +851,13 @@ class SuggestAdapter {
850851 return Promise . resolve ( undefined ) ;
851852 }
852853
854+ const pos = typeConvert . Position . to ( position ) ;
853855 const _mustNotChange = SuggestAdapter . _mustNotChangeHash ( item ) ;
854856 const _mayNotChange = SuggestAdapter . _mayNotChangeHash ( item ) ;
855857
856858 return asPromise ( ( ) => this . _provider . resolveCompletionItem ! ( item , token ) ) . then ( resolvedItem => {
857859
858- if ( ! resolvedItem ) {
860+ if ( ! resolvedItem || ! this . _validateCompletionItem ( resolvedItem , pos ) ) {
859861 return undefined ;
860862 }
861863
@@ -885,8 +887,7 @@ class SuggestAdapter {
885887 this . _didWarnShould = true ;
886888 }
887889
888- const pos = typeConvert . Position . to ( position ) ;
889- return this . _convertCompletionItem ( resolvedItem , pos , id ) ;
890+ return this . _convertCompletionItem ( resolvedItem , id ) ;
890891 } ) ;
891892 }
892893
@@ -896,11 +897,7 @@ class SuggestAdapter {
896897 this . _cache . delete ( id ) ;
897898 }
898899
899- private _convertCompletionItem ( item : vscode . CompletionItem , position : vscode . Position , id : extHostProtocol . ChainedCacheId ) : extHostProtocol . ISuggestDataDto | undefined {
900- if ( typeof item . label !== 'string' || item . label . length === 0 ) {
901- this . _logService . warn ( 'INVALID text edit -> must have at least a label' ) ;
902- return undefined ;
903- }
900+ private _convertCompletionItem ( item : vscode . CompletionItem , id : extHostProtocol . ChainedCacheId , defaultInsertRange ?: vscode . Range , defaultReplaceRange ?: vscode . Range ) : extHostProtocol . ISuggestDataDto {
904901
905902 const disposables = this . _disposables . get ( id [ 0 ] ) ;
906903 if ( ! disposables ) {
@@ -928,9 +925,7 @@ class SuggestAdapter {
928925
929926 // 'insertText'-logic
930927 if ( item . textEdit ) {
931- this . _apiDeprecation . report ( 'CompletionItem.textEdit' , this . _extension ,
932- `Use 'CompletionItem.insertText' and 'CompletionItem.range' instead.` ) ;
933-
928+ this . _apiDeprecation . report ( 'CompletionItem.textEdit' , this . _extension , `Use 'CompletionItem.insertText' and 'CompletionItem.range' instead.` ) ;
934929 result [ extHostProtocol . ISuggestDataDtoField . insertText ] = item . textEdit . newText ;
935930
936931 } else if ( typeof item . insertText === 'string' ) {
@@ -949,36 +944,44 @@ class SuggestAdapter {
949944 range = item . range ;
950945 }
951946
952- if ( range ) {
953- if ( Range . isRange ( range ) ) {
954- if ( ! SuggestAdapter . _isValidRangeForCompletion ( range , position ) ) {
955- this . _logService . trace ( 'INVALID range -> must be single line and on the same line' ) ;
956- return undefined ;
957- }
958- result [ extHostProtocol . ISuggestDataDtoField . range ] = typeConvert . Range . from ( range ) ;
947+ if ( Range . isRange ( range ) ) {
948+ // "old" range
949+ result [ extHostProtocol . ISuggestDataDtoField . range ] = typeConvert . Range . from ( range ) ;
959950
960- } else {
961- if (
962- ! SuggestAdapter . _isValidRangeForCompletion ( range . inserting , position )
963- || ! SuggestAdapter . _isValidRangeForCompletion ( range . replacing , position )
964- || ! range . inserting . start . isEqual ( range . replacing . start )
965- || ! range . replacing . contains ( range . inserting )
966- ) {
967- this . _logService . trace ( 'INVALID range -> must be single line, on the same line, insert range must be a prefix of replace range' ) ;
968- return undefined ;
969- }
970- result [ extHostProtocol . ISuggestDataDtoField . range ] = {
971- insert : typeConvert . Range . from ( range . inserting ) ,
972- replace : typeConvert . Range . from ( range . replacing )
973- } ;
974- }
951+ } else if ( range && ! defaultInsertRange ?. isEqual ( range . inserting ) && ! defaultReplaceRange ?. isEqual ( range . replacing ) ) {
952+ // ONLY send range when it's different from the default ranges (safe bandwidth)
953+ result [ extHostProtocol . ISuggestDataDtoField . range ] = {
954+ insert : typeConvert . Range . from ( range . inserting ) ,
955+ replace : typeConvert . Range . from ( range . replacing )
956+ } ;
975957 }
976958
977959 return result ;
978960 }
979961
980- private static _isValidRangeForCompletion ( range : vscode . Range , position : vscode . Position ) : boolean {
981- return range . isSingleLine || range . start . line === position . line ;
962+ private _validateCompletionItem ( item : vscode . CompletionItem , position : vscode . Position ) : boolean {
963+ if ( typeof item . label !== 'string' || item . label . length === 0 ) {
964+ this . _logService . warn ( 'INVALID text edit -> must have at least a label' ) ;
965+ return false ;
966+ }
967+
968+ if ( Range . isRange ( item . range ) ) {
969+ if ( ! item . range . isSingleLine || item . range . start . line !== position . line ) {
970+ this . _logService . trace ( 'INVALID range -> must be single line and on the same line' ) ;
971+ return false ;
972+ }
973+
974+ } else if ( item . range ) {
975+ if ( ! item . range . inserting . isSingleLine || item . range . inserting . start . line !== position . line
976+ || ! item . range . replacing . isSingleLine || item . range . replacing . start . line !== position . line
977+ || ! item . range . inserting . start . isEqual ( item . range . replacing . start )
978+ || ! item . range . replacing . contains ( item . range . inserting )
979+ ) {
980+ this . _logService . trace ( 'INVALID range -> must be single line, on the same line, insert range must be a prefix of replace range' ) ;
981+ return false ;
982+ }
983+ }
984+ return true ;
982985 }
983986
984987 private static _mustNotChangeHash ( item : vscode . CompletionItem ) {
0 commit comments