'use strict' ; import { IPCMessageReader , IPCMessageWriter , createConnection , IConnection , TextDocumentSyncKind , TextDocuments , TextDocument , Diagnostic , DiagnosticSeverity , InitializeParams , InitializeResult , TextDocumentPositionParams , CompletionItem , CompletionItemKind , Hover , SignatureHelp , Command , CodeActionParams , NotificationType } from 'vscode-languageserver' ; import Ycm , { Settings } from './ycm' ; import * as _ from 'lodash' ; import { logger , loggerInit , crossPlatformUri } from './utils' ; process . on ( 'uncaughtException' , err => { logger ( '!!!uncaughtException!!!' , err ) ; } ) ; let connection = createConnection ( new IPCMessageReader ( process ) , new IPCMessageWriter ( process ) ) ; let documents = new TextDocuments ( ) ; documents . listen ( connection ) ; let workspaceRoot ; let workspaceConfiguration ; connection . onInitialize ( ( params ) : InitializeResult => { workspaceRoot = crossPlatformUri ( params . rootUri ) ; return { capabilities : { textDocumentSync : documents . syncKind , completionProvider : { resolveProvider : true , triggerCharacters : [ '.' , ':' , '<' , '"' , '=' , '/' , '>' , '*' , '&' ] } , hoverProvider : true , definitionProvider : true , codeActionProvider : true } } ; } ) ; connection . onCodeAction ( async ( param ) => { logger ( 'onCodeAction' , JSON . stringify ( param ) ) ; try { const ycm = await getYcm ( ) ; const fixs = await ycm . fixIt ( param . textDocument . uri , param . range . start , documents ) ; return fixs . map ( it => { return { title : `Fix: ${ it . text }` , command : 'ycm.FixIt' , arguments : [ it ] } ; } ) as Command [ ] ; } catch ( e ) { logger ( 'onCodeAction' , e ) ; } return [ ] ; } ) ; connection . onNotification < YcmFixIt , string > ( new NotificationType < YcmFixIt , string > ( 'FixIt' ) , async ( args ) => { logger ( 'On FixIt' , JSON . stringify ( args ) ) ; } ) ; connection . onHover ( async ( event ) : Promise < Hover > => { const ycm = await getYcm ( ) ; try { return await ycm . getDocHover ( event . textDocument . uri , event . position , documents , workspaceConfiguration . ycmd . use_imprecise_get_type ) ; } catch ( getDocErr ) { try { let matchingCompletion = await ycm . getExactMatchingCompletion ( event . textDocument . uri , event . position , documents ) ; if ( matchingCompletion ) { return { contents : { language : documents . get ( event . textDocument . uri ) . languageId , value : matchingCompletion . documentation } } as Hover ; } else { return await ycm . getType ( event . textDocument . uri , event . position , documents , true ) ; } } catch ( err ) { logger ( `onHover error` , err ) ; } } } ) ; connection . onDefinition ( async ( event ) => { const ycm = await getYcm ( ) ; try { return await ycm . goTo ( event . textDocument . uri , event . position , documents ) ; } catch ( err ) { logger ( `onDefinition error` , err ) ; } } ) ; documents . onDidChangeContent ( async ( change ) => { logger ( `onDidChangeContent ${ JSON . stringify ( change . document . uri ) }` ) ; const ycm = await getYcm ( ) ; } ) ; async function getYcm ( ) { if ( ! workspaceRoot || ! workspaceConfiguration ) return await new Promise < Ycm > ( ( resolve , reject ) => setTimeout ( ( ) => getYcm ( ) , 100 ) ) ; try { return await Ycm . getInstance ( workspaceRoot , workspaceConfiguration , connection . window ) ; } catch ( err ) { logger ( 'getYcm error' , err ) ; connection . window . showErrorMessage ( `Ycm startup failed. Please check your ycmd or python path. Detail: ${ err . message || err }` ) ; } } async function getIssues ( document ) { const ycm = await getYcm ( ) ; connection . sendDiagnostics ( { uri : document . uri , diagnostics : await ycm . readyToParse ( document . uri , documents ) } ) ; } connection . onDidChangeConfiguration ( async ( change ) => { let settings = < Settings > change . settings ; loggerInit ( settings . ycmd . debug ) ; logger ( `onDidChangeConfiguration settings` , JSON . stringify ( settings ) ) ; try { ensureValidConfiguration ( settings ) ; workspaceConfiguration = settings ; } catch ( err ) { connection . window . showErrorMessage ( `[Ycm] ${ err . message || err }` ) ; } await getYcm ( ) ; } ) ; function ensureValidConfiguration ( settings ) { if ( ! settings . ycmd || ! settings . ycmd . path ) throw new Error ( 'Invalid ycm path' ) ; } documents . onDidOpen ( async ( event ) => { logger ( `onDidOpen` , event . document . uri ) ; const ycm = await getYcm ( ) ; try { await ycm . getReady ( event . document . uri , documents ) ; } catch ( err ) { logger ( 'onDidOpen error' , err ) ; } } ) ; connection . onCompletion ( async ( textDocumentPosition ) : Promise < CompletionItem [ ] > => { logger ( `onCompletion: ${ textDocumentPosition . textDocument . uri }` ) ; const ycm = await getYcm ( ) ; try { const latestCompletions = await ycm . completion ( textDocumentPosition . textDocument . uri , textDocumentPosition . position , documents ) ; return latestCompletions ; } catch ( err ) { return null ; } } ) ; connection . onShutdown ( async ( ) => { logger ( 'onShutdown' ) ; await Ycm . reset ( ) ; } ) ; connection . onCompletionResolve ( ( item ) : CompletionItem => { return item ; } ) ; connection . onNotification ( 'lint' , ( uri ) => { getIssues ( documents . get ( uri ) ) ; } ) ; connection . listen ( ) ;