def run(self): log.warn('io thread starts') try: self._RunEventLoop() except: log.exception('fatal error, io thread') self.shutdown()
def exit(self): try: self._SendNotification(Exit_NOTIFICATION) except OSError: log.exception('failed to send exception request') self._rpcclient.stop() self._is_alive = False
def startServer(self, confirmed=False): if self._client: vimsupport.EchoMessage( 'clangd is connected, please stop it first!') return if confirmed or vimsupport.PresentYesOrNoDialog( 'Should we start clangd?'): clangd_executable = str(GetVariableValue('g:clangd#clangd_executable')) if not clangd_executable: vim_script_folder_path = str(GetVariableValue('s:script_folder_path')) clangd_executable = join(vim_script_folder_path, '..', 'script', 'bin', 'clangd') clangd_executable = expanduser(clangd_executable) clangd_log_path = expanduser( GetVariableValue('g:clangd#log_path') + '/clangd.log') try: self._client = LSPClient(clangd_executable, clangd_log_path, self) rr = self._client.initialize() capabilities = rr['capabilities'] if 'completionProvider' in capabilities and 'triggerCharacters' in capabilities['completionProvider']: self._triggerCharacters = set(capabilities['completionProvider']['triggerCharacters']) except: if self._client: client = self._client client.CleanUp() self._client = None if confirmed: raise else: log.exception('failed to start backend') vimsupport.EchoMessage('failed to start backend executable')
def CloseAllFiles(self): if not self.isAlive(): return try: for uri in list(self._documents.keys()): self._client.didCloseTestDocument(uri) except TimedOutError: log.exception('failed to close all files')
def UpdateCurrentBuffer(self): if not self.isAlive(): return buf = vimsupport.CurrentBuffer() try: self.UpdateSpecifiedBuffer(buf) except TimedOutError: log.exception('failed to update curent buffer') vimsupport.EchoTruncatedText('unable to update curent buffer')
def _SendNotification(self, method, params={}): try: return self._rpcclient.sendNotification(method, params) except OSError as e: if isinstance(e, TimedOutError): self._client_timeouts += 1 else: self._client_errs += 1 log.exception("send notification %s with params %s" % (method, params)) raise
def SaveFile(self, file_name): if not self.isAlive(): return True uri = GetUriFromFilePath(file_name) try: self._client.didSaveTestDocument(uri) except TimedOutError: log.exception('unable to save %s' % file_name) return False log.debug('file %s saved' % file_name) return True
def PlaceSignForErrorMessage(buffer_num, index, diagnostic): if diagnostic['severity'] >= 3: sign_name = 'clangdError' else: sign_name = 'clangdWarning' try: vim.command('sign place %d line=%d name=%s buffer=%d' % (index, diagnostic['lnum'], sign_name, buffer_num)) except: log.exception('sign place %d line=%d name=%s buffer=%d' % (index, diagnostic['lnum'], sign_name, buffer_num))
def OpenFile(self, file_name): if not self.isAlive(): return True uri = GetUriFromFilePath(file_name) try: buf = vimsupport.GetBufferByName(file_name) self.didOpenFile(buf) except TimedOutError: log.exception('failed to open %s' % file_name) vimsupport.EchoTruncatedText('unable to open %s' % file_name) return False return True
def StartServer(self): if self._loaded: return self._manager = ClangdManager() self._InitTimer() if self._timer: self._timer.start() try: self._manager.startServer(confirmed=True) except: log.exception('failed to start backend') return log.warn('vim-clangd backend fully loaded') self._loaded = True
def _FormatBuffer(self, buf): uri = GetUriFromFilePath(buf.name) try: # synchronize before format self.didChangeFile(buf) # actual format rpc textedits = self._client.format(uri) except TimedOutError: log.exception('code format timed out') vimsupport.EchoMessage('backend refuses to perform code format') return self._UpdateBufferByTextEdits(buf, textedits)
def CloseFile(self, file_name): if not self.isAlive(): return True uri = GetUriFromFilePath(file_name) if not uri in self._documents: return version = self._documents.pop(uri)['version'] try: self._client.didCloseTestDocument(uri) except TimedOutError: log.exception('failed to close file %s' % file_name) return False log.debug('file %s closed' % file_name) return True
def _SendRequest(self, method, params={}, nullResponse=False, timeout_ms=None): try: return self._rpcclient.sendRequest(method, params, nullResponse, timeout_ms) except OSError as e: if isinstance(e, TimedOutError): self._client_timeouts += 1 else: self._client_errs += 1 log.exception("send request %s with params %s" % (method, params)) raise
def stopServer(self, confirmed=False, in_shutdown=False): if in_shutdown: self._in_shutdown = True if confirmed or vimsupport.PresentYesOrNoDialog( 'Should we stop backend?'): try: if self._client: client = self._client client.shutdown() client.exit() self._client = None except OSError: if self._client: client = self._client client.CleanUp() self._client = None log.exception('failed to stop backend') return
def GetDiagnostics(self, buf): if not self.isAlive(): return [] file_name = buf.name uri = GetUriFromFilePath(file_name) needReopen = False if not self.OpenFile(file_name): return [] try: self._client.handleClientRequests() except TimedOutError: log.exception('failed to get diagnostics %s' % file_name) return [] if not uri in self._documents or not 'diagnostics' in self._documents[uri]: return [] response = self._documents[uri]['diagnostics'] return vimsupport.ConvertDiagnosticsToQfList(file_name, response)
def StopServer(self): if self._timer: self._timer.stop() self._timer = None self._manager.in_shutdown = True try: # BufUnload won't be called at exit, you need to call it yourself self._manager.CloseAllFiles() log.warn('vim-clangd closed all files') except TimedOutError: # safe to ignore log.exception("close all files timeout") try: self._manager.stopServer(confirmed=True, in_shutdown=True) except OSError: log.exception("clangd refused to shutdown") log.warn('vim-clangd backend fully unloaded') self._loaded = False self._manager = None
def initialize(self): try: rr = self._SendRequest(Initialize_REQUEST, { 'processId': os.getpid(), 'rootUri': 'file://' + os.getcwd(), 'capabilities': {}, 'trace': 'off' }, timeout_ms=5000) except TimedOutError as e: log.exception('initialize timedout') # ignore timedout rr = {} pass if not 'capabilities' in rr: rr['capabilities'] = {} log.debug('clangd connected with backend server') for k in rr['capabilities']: v = rr['capabilities'][k] if v: log.info('clangd server capability: %s' % k) self._manager.on_server_connected() return rr
def _FormatOnRange(self, buf, start, end): (start_line, start_column) = start start_column = min( len(buf[start_line - 1]) - 1 if len(buf[start_line - 1]) > 0 else 0, start_column) (end_line, end_column) = end end_column = min( len(buf[end_line - 1]) - 1 if len(buf[end_line - 1]) > 0 else 0, end_column) uri = GetUriFromFilePath(vimsupport.CurrentBufferFileName()) try: # synchronize before format self.didChangeFile(buf) # actual format rpc textedits = self._client.rangeFormat(uri, start_line - 1, start_column, end_line - 1, end_column) except TimedOutError: log.exception('code format') vimsupport.EchoMessage("clangd refuse to perform code format") return self._UpdateBufferByTextEdits(buf, textedits)
def shutdown(self): try: return self._SendRequest(Shutdown_REQUEST, nullResponse=True) except OSError: log.exception('failed to send shutdown request')