'use strict' ; import * as vscode from 'vscode' ; import * as fs from 'fs' ; import * as path from 'path' ; import * as JSON5 from 'json5' ; let _snippets = Object . create ( null ) ; let _registeredProviders = Object . create ( null ) ; class CompletionProvider implements vscode . CompletionItemProvider { public provideCompletionItems ( document , position , token ) { return _snippets [ document . languageId ] ; } public resolveCompletionItem ( item , token ) { return item ; } } export function parseSnippetFile ( snippetFileContent ) { try { if ( snippetFileContent === '' ) { return [ ] ; } let snippetsObj = JSON5 . parse ( snippetFileContent ) ; if ( ! snippetsObj || typeof snippetsObj !== 'object' ) { return [ ] ; } let topLevelProperties = Object . keys ( snippetsObj ) ; let result = [ ] ; let processSnippet = ( snippet , name ) => { let prefix = snippet [ 'prefix' ] ; let bodyStringOrArray = snippet [ 'body' ] ; if ( Array . isArray ( bodyStringOrArray ) ) { bodyStringOrArray = bodyStringOrArray . join ( '\n' ) ; } if ( typeof prefix === 'string' && typeof bodyStringOrArray === 'string' ) { let newSnippet = new vscode . CompletionItem ( prefix ) ; newSnippet . kind = vscode . CompletionItemKind . Snippet ; newSnippet . detail = snippet [ 'description' ] || name , newSnippet . documentation = snippet [ 'description' ] || name , newSnippet . insertText = new vscode . SnippetString ( bodyStringOrArray ) ; result . push ( newSnippet ) ; } } ; topLevelProperties . forEach ( topLevelProperty => { let scopeOrTemplate = snippetsObj [ topLevelProperty ] ; if ( scopeOrTemplate [ 'body' ] && scopeOrTemplate [ 'prefix' ] ) { processSnippet ( scopeOrTemplate , topLevelProperty ) ; } else { let snippetNames = Object . keys ( scopeOrTemplate ) ; snippetNames . forEach ( name => { processSnippet ( scopeOrTemplate [ name ] , name ) ; } ) ; } } ) ; return result ; } catch ( err ) { return [ ] ; } } async function readAndRegisterSnippets ( filePath ) { return new Promise < vscode . CompletionItem [ ] > ( ( resolve , reject ) => { fs . readFile ( filePath . fsPath , { encoding : 'utf8' } , ( err , data ) => { if ( err ) { reject ( err ) ; } let snippets = parseSnippetFile ( data . toString ( ) ) ; resolve ( snippets ) ; } ) ; } ) ; } export async function activate ( context ) { let completionItemProvider = new CompletionProvider ( ) ; let snippetFiles = await vscode . workspace . findFiles ( ".vscode/snippets/*.json" , "" ) ; if ( snippetFiles ) { for ( let i = 0 ; i < snippetFiles . length ; i ++ ) { let modeId = path . basename ( snippetFiles [ i ] . path ) . split ( '\.' ) [ 0 ] ; let snippets = await readAndRegisterSnippets ( snippetFiles [ i ] ) ; _snippets [ modeId ] = snippets ; } for ( const modeId in _snippets ) { let disposable = vscode . languages . registerCompletionItemProvider ( modeId , completionItemProvider ) ; _registeredProviders [ modeId ] = disposable ; } } let snippetFilesWatcher = vscode . workspace . createFileSystemWatcher ( "**/.vscode/snippets/*.json" ) ; let snippetUpdate = async ( e ) => { let modeId = path . basename ( e . path ) . split ( '\.' ) [ 0 ] ; let snippets = await readAndRegisterSnippets ( e ) ; _snippets [ modeId ] = snippets ; if ( _registeredProviders [ modeId ] ) { _registeredProviders [ modeId ] . dispose ( ) ; } let disposable = vscode . languages . registerCompletionItemProvider ( modeId , completionItemProvider ) ; _registeredProviders [ modeId ] = disposable ; } ; snippetFilesWatcher . onDidCreate ( snippetUpdate ) ; snippetFilesWatcher . onDidChange ( snippetUpdate ) ; snippetFilesWatcher . onDidDelete ( async ( e ) => { let modeId = path . basename ( e . path ) . split ( '\.' ) [ 0 ] ; if ( _registeredProviders [ modeId ] ) { _registeredProviders [ modeId ] . dispose ( ) ; } } ) ; } export function deactivate ( ) { for ( let modeId in _registeredProviders ) { _registeredProviders [ modeId ] . dispose ( ) ; } }