import * as path from 'path' ; import { workspace , ExtensionContext , FileType as VFileType , FileSystemProvider , Uri , Event , FileChangeEvent , EventEmitter , FileSystemError , commands , window } from 'vscode' ; import { LanguageClient , LanguageClientOptions , ServerOptions , TransportKind , Disposable , RequestType , } from 'vscode-languageclient/node' ; let client ; export function activate ( context ) { commands . registerCommand ( 'lsif.openDatabase' , ( ) => { window . showOpenDialog ( { openLabel : 'Select LSIF Database to open' , canSelectFiles : true , canSelectFolders : false , canSelectMany : true , filters : { 'LSIF' : [ 'db' , 'lsif' ] } } ) . then ( ( values ) => { if ( values === undefined || values . length === 0 ) { return ; } let toAdd = values . map ( ( uri ) => { return { uri : uri . with ( { scheme : 'lsif' } ) } ; } ) ; workspace . updateWorkspaceFolders ( workspace . workspaceFolders ? workspace . workspaceFolders . length : 0 , 0 , ... toAdd ) ; } ) ; } ) ; let serverModule = context . asAbsolutePath ( path . join ( 'server' , 'out' , 'lsifServer.js' ) ) ; let debugOptions = { execArgv : [ '--nolazy' , '--inspect=6029' ] } ; let serverOptions = { run : { module : serverModule , transport : TransportKind . ipc } , debug : { module : serverModule , transport : TransportKind . ipc , options : debugOptions } } ; let clientOptions = { } ; client = new LanguageClient ( 'lsif' , 'Language Server Index Format' , serverOptions , clientOptions ) ; client . start ( ) ; let clientPromise = new Promise < LanguageClient > ( ( resolve , reject ) => { client . onReady ( ) . then ( ( ) => { resolve ( client ) ; } , ( error ) => { reject ( error ) ; } ) ; } ) ; workspace . registerFileSystemProvider ( 'lsif' , new LsifFS ( clientPromise ) , { isCaseSensitive : true , isReadonly : true } ) ; } export function deactivate ( ) { if ( ! client ) { return undefined ; } return client . stop ( ) ; } namespace FileType { export const Unknown = 0 ; export const File = 1 ; export const Directory = 2 ; export const SymbolicLink = 64 ; } type FileType = 0 | 1 | 2 | 64 ; interface FileStat { type : FileType ; ctime : number ; mtime : number ; size : number ; } interface StatFileParams { uri : string ; } namespace StatFileRequest { export const type = new RequestType < StatFileParams , FileStat | null , void > ( 'lsif/statFile' ) ; } interface ReadFileParams { uri : string ; } namespace ReadFileRequest { export const type = new RequestType < ReadFileParams , string , void > ( 'lsif/readfile' ) ; } interface ReadDirectoryParams { uri : string ; } namespace ReadDirectoryRequest { export const type = new RequestType < ReadDirectoryParams , [ string , FileType ] [ ] , void > ( 'lsif/readDirectory' ) ; } class LsifFS implements FileSystemProvider { private readonly client : Promise < LanguageClient > ; private readonly emitter : EventEmitter < FileChangeEvent [ ] > ; public readonly onDidChangeFile : Event < FileChangeEvent [ ] > ; public constructor ( client ) { this . client = client ; this . emitter = new EventEmitter < FileChangeEvent [ ] > ( ) ; this . onDidChangeFile = this . emitter . event ; } watch ( uri , options ) { return Disposable . create ( ( ) : void => { } ) ; } async stat ( uri ) { let client = await this . client ; return client . sendRequest ( StatFileRequest . type , { uri : client . code2ProtocolConverter . asUri ( uri ) } ) . then ( ( value ) => { if ( ! value ) { throw FileSystemError . FileNotFound ( uri ) ; } return value ; } , ( error ) => { throw FileSystemError . FileNotFound ( uri ) ; } ) ; } async readDirectory ( uri ) { let client = await this . client ; let params = { uri : client . code2ProtocolConverter . asUri ( uri ) } ; return client . sendRequest ( ReadDirectoryRequest . type , params ) . then ( ( values ) => { return values ; } ) ; } async readFile ( uri ) { let client = await this . client ; let params = { uri : client . code2ProtocolConverter . asUri ( uri ) } ; return client . sendRequest ( ReadFileRequest . type , params ) . then ( ( value ) => { let result = new Uint8Array ( Buffer . from ( value , 'base64' ) ) ; return result ; } ) ; } createDirectory ( uri ) { throw new Error ( 'File system is readonly.' ) ; } writeFile ( uri , content , options ) { throw new Error ( 'File system is readonly.' ) ; } delete ( uri , options ) { throw new Error ( 'File system is readonly.' ) ; } rename ( oldUri , newUri , options ) { throw new Error ( 'File system is readonly.' ) ; } }