import * as vscode from 'vscode' ; import { PLDocController } from '../pldoc.controller' ; import { PlSqlNavigatorVSC as PlSqlNavigator } from '../plsqlNavigator.vscode' ; import { PLSQLCursorInfosVSC as PLSQLCursorInfos } from '../plsqlNavigator.vscode' ; import PLSQLCompletionCustom from '../plsqlCompletionCustom' ; import PlSqlParser from '../plsqlParser.vscode' ; export class PLSQLCompletionItemProvider implements vscode . CompletionItemProvider { private plDocController = new PLDocController ( ) ; private plsqlCompletionCustom = new PLSQLCompletionCustom ( ) ; private plDocCustomItems : vscode . CompletionItem [ ] ; private plsqlSnippets : vscode . CompletionItem [ ] ; public provideCompletionItems ( document , position , token ) { return new Promise < vscode . CompletionItem [ ] > ( ( resolve , reject ) => { const completeItems = [ ] ; const lineText = document . lineAt ( position . line ) . text , text = document . getText ( ) , wordRange = document . getWordRangeAtPosition ( position ) , word = wordRange && document . getText ( wordRange ) , cursorInfos = PlSqlNavigator . getCursorInfos ( document , position ) ; if ( ! cursorInfos . previousDot ) { const plDocItem = this . getPlDocItem ( document , position , lineText , text ) ; if ( plDocItem ) completeItems . push ( plDocItem ) ; if ( ! this . plDocCustomItems ) this . plDocCustomItems = this . getPlDocCustomItems ( document ) ; Array . prototype . push . apply ( completeItems , this . filterCompletion ( this . plDocCustomItems , word ) ) ; if ( ! this . plsqlSnippets ) this . plsqlSnippets = this . getSnippets ( ) ; Array . prototype . push . apply ( completeItems , this . filterCompletion ( this . plsqlSnippets , word ) ) ; const objects = this . getCompletionCustomItems ( document ) ; Array . prototype . push . apply ( completeItems , this . filterCompletion ( objects , word ) ) ; const items = PlSqlParser . getAllDeclaration ( document ) ; if ( items ) { Array . prototype . push . apply ( completeItems , this . filterCompletion ( items . map ( symbol => this . createSymbolItem ( symbol ) ) , word ) ) ; } return resolve ( this . processCompleteItems ( completeItems ) ) ; } else { if ( cursorInfos . previousWord ) { const members = this . getCompletionCustomItems ( document , cursorInfos . previousWord ) ; if ( members && members . length ) { Array . prototype . push . apply ( completeItems , members ) ; return resolve ( this . processCompleteItems ( completeItems ) ) ; } this . getPackageItems ( document , position , cursorInfos ) . then ( items => { Array . prototype . push . apply ( completeItems , items ) ; return resolve ( this . processCompleteItems ( completeItems ) ) ; } ) . catch ( err => { console . log ( err ) ; return resolve ( undefined ) ; } ) ; } } } ) ; } private processCompleteItems ( completeItems ) { if ( completeItems . length > 0 ) return completeItems ; } private filterCompletion ( items , word ) { if ( items && word ) { const wordL = word . toLowerCase ( ) ; return items . filter ( item => item . label . toLowerCase ( ) . startsWith ( wordL ) ) ; } else if ( items ) return items ; else return [ ] ; } private createSnippetItem ( snippet , origin = '' ) { return this . createCompleteItem ( vscode . CompletionItemKind . Snippet , snippet . prefix , snippet . description , snippet . body . join ( '\n' ) , origin ) ; } private createSymbolItem ( symbol ) { const symbolInfo = PlSqlParser . getSymbolsCompletion ( symbol ) ; return this . createCompleteItem ( symbolInfo . kind , symbolInfo . label , symbolInfo . documentation , symbolInfo . label , symbolInfo . detail ) ; } private createCompleteItem ( type , label , doc = '' , text = label , origin = '' ) { const item = new vscode . CompletionItem ( label , type ) ; if ( type === vscode . CompletionItemKind . Snippet ) { item . insertText = new vscode . SnippetString ( text ) ; } else item . insertText = text ; item . documentation = doc ; item . detail = origin ; return item ; } private getPlDocItem ( document , position , lineText , text ) { if ( ( text !== '' ) && ( lineText . trim ( ) === '' ) && ( document . lineCount > position . line + 1 ) ) { const nextPos = new vscode . Position ( position . line + 1 , 0 ) , nextText = text . substr ( document . offsetAt ( nextPos ) ) ; const snippet = this . plDocController . getDocSnippet ( document , nextText ) ; if ( snippet ) return this . createSnippetItem ( snippet , 'pldoc' ) ; } } private getPlDocCustomItems ( document ) { const snippets = this . plDocController . getCustomSnippets ( document ) ; if ( snippets ) return snippets . map ( snippet => this . createSnippetItem ( snippet ) ) ; return [ ] ; } private getSnippets ( ) { if ( vscode . workspace . getConfiguration ( 'plsql-language' ) . get < boolean > ( 'snippets.enable' ) ) { const parsedJSON = require ( '../../../../snippets/plsql.snippets.json' ) ; return Object . keys ( parsedJSON ) . map ( key => this . createSnippetItem ( parsedJSON [ key ] , 'plsql.snippets' ) ) ; } return [ ] ; } private getPackageItems ( document , position , cursorInfos ) { return new Promise < vscode . CompletionItem [ ] > ( ( resolve , reject ) => { PlSqlNavigator . complete ( document , position , cursorInfos ) . then ( symbols => { if ( symbols ) return resolve ( symbols . map ( symbol => this . createSymbolItem ( symbol ) ) ) ; else return resolve ( [ ] ) ; } ) . catch ( err => resolve ( [ ] ) ) ; } ) ; } private getCompletionCustomItems ( document , text ? ) { const items = this . plsqlCompletionCustom . getCompletion ( document , text ) ; if ( items ) return items . map ( item => this . createCompleteItem ( item . kind , item . label , item . documentation , item . label , 'plsql.completion' ) ) ; return [ ] ; } }