import * as fs from 'fs' ; import * as util from 'util' ; import * as vscode from 'vscode' ; import { ABL_MODE } from '../ablMode' ; import { ABLTableDefinition } from '../misc/definition' ; import { getText , replaceSnippetTableName , updateTableCompletionList } from '../misc/utils' ; import { ABLDocumentController , getDocumentController } from '../parser/documentController' ; let watcher = null ; const _tableCollection = new vscode . CompletionList ( ) ; const readFileAsync = util . promisify ( fs . readFile ) ; export class ABLCompletionItemProvider implements vscode . CompletionItemProvider { private _ablDocumentController : ABLDocumentController ; constructor ( context ) { this . _ablDocumentController = getDocumentController ( ) ; context . subscriptions . push ( vscode . languages . registerCompletionItemProvider ( ABL_MODE . language , this , '.' ) ) ; } public provideCompletionItems ( document , position , token ) { return new Promise ( ( resolve , reject ) => { try { const completionItemResult = [ ] ; const doc = this . _ablDocumentController . getDocument ( document ) ; const p = new vscode . Position ( position . line , position . character - 1 ) ; const textSelection = getText ( document , p , true ) ; const tsParts = textSelection . statement . split ( '.' ) ; if ( tsParts . length === 2 ) { let originalName = tsParts [ 0 ] ; tsParts [ 0 ] = ( doc . searchBuffer ( tsParts [ 0 ] , position ) || tsParts [ 0 ] ) ; if ( originalName === tsParts [ 0 ] ) { originalName = null ; } let result = this . getCompletionFields ( tsParts [ 0 ] , originalName ) ; if ( ( result ) && ( result . length > 0 ) ) { resolve ( result ) ; return ; } result = doc . getCompletionTempTableFields ( tsParts [ 0 ] , originalName ) ; if ( ( result ) && ( result . length > 0 ) ) { resolve ( result ) ; return ; } doc . externalDocument . forEach ( ( external ) => { if ( ( ! result ) || ( result . length === 0 ) ) { const extDoc = this . _ablDocumentController . getDocument ( external ) ; if ( ( extDoc ) && ( extDoc . processed ) ) { result = extDoc . getCompletionTempTableFields ( tsParts [ 0 ] , originalName ) ; } } } ) ; if ( ( result ) && ( result . length > 0 ) ) { resolve ( result ) ; return ; } } else if ( tsParts . length === 1 ) { const tb = _tableCollection . items ; const docSym = doc . getCompletionSymbols ( position ) ; let extSym = [ ] ; doc . externalDocument . forEach ( ( external ) => { const extDoc = this . _ablDocumentController . getDocument ( external ) ; if ( ( extDoc ) && ( extDoc . processed ) ) { extSym = [ ... extSym , ... extDoc . getCompletionSymbols ( position ) ] ; } } ) ; resolve ( [ ... tb , ... docSym , ... extSym ] ) ; return ; } resolve ( completionItemResult ) ; } catch { reject ( ) ; } } ) ; } private getCompletionFields ( prefix , replacement ? ) { const tb = _tableCollection . items . find ( ( item ) => item . label . toLowerCase ( ) === prefix ) ; if ( tb ) { let result = tb [ 'completion' ] . items ; if ( ! util . isNullOrUndefined ( replacement ) ) { result = replaceSnippetTableName ( result , prefix , replacement ) ; } return result ; } return [ ] ; } } export function loadDumpFile ( filename ) { if ( ! filename ) { return Promise . resolve ( { } ) ; } return readFileAsync ( filename , { encoding : 'utf8' } ) . then ( ( text ) => { return JSON . parse ( text ) ; } ) ; } export function getTableCollection ( ) { return _tableCollection ; } function findDumpFiles ( ) { return vscode . workspace . findFiles ( '**/.openedge.db.*' ) ; } function loadAndSetDumpFile ( filename ) { unloadDumpFile ( filename ) ; return readFileAsync ( filename , { encoding : 'utf8' } ) . then ( ( text ) => { const fileDataResult = JSON . parse ( text ) ; if ( fileDataResult ) { fileDataResult . map ( ( tb ) => { const obj = new ABLTableDefinition ( ) ; Object . assign ( obj , tb ) ; obj . filename = filename ; obj . fields . map ( ( fd ) => fd . name = fd [ 'label' ] ) ; updateTableCompletionList ( obj ) ; return obj ; } ) . forEach ( ( tb ) => { _tableCollection . items . push ( tb ) ; } ) ; } } ) ; } function unloadDumpFile ( filename ) { _tableCollection . items = _tableCollection . items . filter ( ( item ) => item [ 'filename' ] !== filename ) ; } export function watchDictDumpFiles ( ) { return new Promise < null > ( ( resolve , reject ) => { watcher = vscode . workspace . createFileSystemWatcher ( '**/.openedge.db.*' ) ; watcher . onDidChange ( ( uri ) => loadAndSetDumpFile ( uri . fsPath ) ) ; watcher . onDidDelete ( ( uri ) => unloadDumpFile ( uri . fsPath ) ) ; findDumpFiles ( ) . then ( ( filename ) => { filename . forEach ( ( f ) => { loadAndSetDumpFile ( f . fsPath ) ; } ) ; } ) ; resolve ( ) ; } ) ; }