import { search , Canceler } from '@donaldpipowitch/vscode-extension-core' ; import { TextDocuments , CompletionItemKind , Connection } from 'vscode-languageserver' ; import { parseTree , findNodeAtOffset , Node } from 'jsonc-parser' ; let lastCancel = null ; export function configureCompletion ( connection , documents ) { connection . onCompletion ( async ( { position , textDocument } , token ) => { token . onCancellationRequested ( ( ) => { if ( lastCancel ) { lastCancel ( ) ; lastCancel = null ; } } ) ; if ( lastCancel ) { lastCancel ( ) ; lastCancel = null ; } if ( ! textDocument . uri . endsWith ( '.vscode/extensions.json' ) ) return ; const document = documents . get ( textDocument . uri ) ; if ( ! document ) return ; const tree = parseTree ( document . getText ( ) ) ; const node = findNodeAtOffset ( tree , document . offsetAt ( position ) ) ; if ( ! isExtensionValue ( node ) ) return ; if ( node . value && node . value . length <= 2 ) return ; const query = node . value ; const { cancel , request } = search ( query ) ; lastCancel = cancel ; const extensions = await request ; lastCancel = null ; if ( ! extensions ) return ; const completionItems = extensions . map ( ( { publisher : { publisherName } , extensionName , displayName , shortDescription } ) => ( { label : `"${ publisherName }.${ extensionName }` , kind : CompletionItemKind . Text , detail : displayName , documentation : shortDescription } ) ) ; return completionItems ; } ) ; } function isExtensionValue ( node ) { if ( ! node ) return false ; if ( node . type !== 'string' ) return false ; if ( ! node . parent ) return false ; if ( node . parent . type !== 'array' ) return false ; if ( ! node . parent . parent ) return false ; if ( node . parent . parent . type !== 'property' ) return false ; if ( node . parent . parent . children ! [ 0 ] . value !== 'recommendations' && node . parent . parent . children ! [ 0 ] . value !== 'unwantedRecommendations' ) return false ; if ( ! node . parent . parent . parent ) return false ; if ( node . parent . parent . parent . type !== 'object' ) return false ; if ( node . parent . parent . parent . parent ) return false ; return true ; }