def GetReady(): LOGGER.info( 'Received ready request' ) if request.query.subserver: filetype = request.query.subserver completer = _server_state.GetFiletypeCompleter( [ filetype ] ) return _JsonResponse( completer.ServerIsReady() ) return _JsonResponse( True )
def _ChooseOmnisharpPort( self ): if not self._omnisharp_port: if self._desired_omnisharp_port: self._omnisharp_port = int( self._desired_omnisharp_port ) else: self._omnisharp_port = utils.GetUnusedLocalhostPort() LOGGER.info( 'using port %s', self._omnisharp_port )
def StartServer( self, request_data ): with self._server_state_mutex: LOGGER.info( 'Starting %s: %s', self.GetServerName(), self.GetCommandLine() ) self._stderr_file = utils.CreateLogfile( '{}_stderr'.format( utils.MakeSafeFileNameString( self.GetServerName() ) ) ) with utils.OpenForStdHandle( self._stderr_file ) as stderr: self._server_handle = utils.SafePopen( self.GetCommandLine(), stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = stderr ) self._connection = ( lsc.StandardIOLanguageServerConnection( self._server_handle.stdin, self._server_handle.stdout, self.GetDefaultNotificationHandler() ) ) self._connection.Start() try: self._connection.AwaitServerConnection() except lsc.LanguageServerConnectionTimeout: LOGGER.error( '%s failed to start, or did not connect successfully', self.GetServerName() ) self.Shutdown() return False LOGGER.info( '%s started', self.GetServerName() ) return True
def __init__(self, user_options): self.user_options = user_options self.min_num_chars = user_options['min_num_of_chars_for_completion'] self.max_diagnostics_to_display = user_options[ 'max_diagnostics_to_display'] self.completion_triggers = (completer_utils.PreparedTriggers( user_trigger_map=user_options['semantic_triggers'], filetype_set=set(self.SupportedFiletypes())) if user_options['auto_trigger'] else None) self._signature_triggers = ( completer_utils.PreparedTriggers( user_trigger_map= {}, # user triggers not supported for signature help filetype_set=set(self.SupportedFiletypes()), default_triggers={}) if not user_options['disable_signature_help'] else None) self._completions_cache = CompletionsCache() self._max_candidates = user_options['max_num_candidates'] self._max_candidates_to_detail = user_options[ 'max_num_candidates_to_detail'] LOGGER.info(f"Completion config: { self._max_candidates }, detailing " f"{ self._max_candidates_to_detail } candiates")
def ShouldEnableCsCompleter(user_options): roslyn = FindExecutableWithFallback(user_options['roslyn_binary_path'], PATH_TO_OMNISHARP_ROSLYN_BINARY) if roslyn: return True LOGGER.info('No omnisharp-roslyn executable at %s', roslyn) return False
def StartServer(self, request_data): with self._server_state_mutex: if self.ServerIsHealthy(): return # Ensure we cleanup all states. self._Reset() LOGGER.info('Starting clangd: %s', self._clangd_command) self._stderr_file = utils.CreateLogfile('clangd_stderr') with utils.OpenForStdHandle(self._stderr_file) as stderr: self._server_handle = utils.SafePopen(self._clangd_command, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=stderr) self._connection = ( language_server_completer.StandardIOLanguageServerConnection( self._server_handle.stdin, self._server_handle.stdout, self.GetDefaultNotificationHandler())) self._connection.Start() try: self._connection.AwaitServerConnection() except language_server_completer.LanguageServerConnectionTimeout: LOGGER.error('clangd failed to start, or did not connect ' 'successfully') self.Shutdown() return LOGGER.info('clangd started') self.SendInitialize(request_data)
def _CallGlobalExtraConfMethod( function_name ): global_ycm_extra_conf = _GlobalYcmExtraConfFileLocation() if not ( global_ycm_extra_conf and os.path.exists( global_ycm_extra_conf ) ): LOGGER.debug( 'No global extra conf, not calling method %s', function_name ) return try: module = Load( global_ycm_extra_conf, force = True ) except Exception: LOGGER.exception( 'Error occurred while loading global extra conf %s', global_ycm_extra_conf ) return if not module or not hasattr( module, function_name ): LOGGER.debug( 'Global extra conf not loaded or no function %s', function_name ) return try: LOGGER.info( 'Calling global extra conf method %s on conf file %s', function_name, global_ycm_extra_conf ) getattr( module, function_name )() except Exception: LOGGER.exception( 'Error occurred while calling global extra conf method %s ' 'on conf file %s', function_name, global_ycm_extra_conf )
def PollModule(module, filepath): """ Try to use passed module in the selection process by calling CSharpSolutionFile on it """ path_to_solutionfile = None module_hint = None if module: try: module_hint = module.CSharpSolutionFile(filepath) LOGGER.info('extra_conf_store suggests %s as solution file', module_hint) if module_hint: # received a full path or one relative to the config's location? candidates = [ module_hint, os.path.join(os.path.dirname(getfile(module)), module_hint) ] # try the assumptions for path in candidates: if os.path.isfile(path): # path seems to point to a solution path_to_solutionfile = path LOGGER.info( 'Using solution file %s selected by extra_conf_store', path_to_solutionfile) break except AttributeError: # the config script might not provide solution file locations LOGGER.exception( 'Could not retrieve solution for %s' 'from extra_conf_store', filepath) return path_to_solutionfile
def GetClangdExecutableAndResourceDir(user_options): """Return the Clangd binary from the path specified in the 'clangd_binary_path' option. Let the binary find its resource directory in that case. If no binary is found or if it's out-of-date, return nothing. If 'clangd_binary_path' is empty, return the third-party Clangd and its resource directory if the user downloaded it and if it's up to date. Otherwise, return nothing.""" clangd = user_options['clangd_binary_path'] resource_dir = None if clangd: clangd = FindExecutable(ExpandVariablesInPath(clangd)) if not clangd: LOGGER.error('No Clangd executable found at %s', user_options['clangd_binary_path']) return None, None if not CheckClangdVersion(clangd): LOGGER.error('Clangd at %s is out-of-date', clangd) return None, None # Try looking for the pre-built binary. else: third_party_clangd = GetThirdPartyClangd() if not third_party_clangd: return None, None clangd = third_party_clangd resource_dir = CLANG_RESOURCE_DIR LOGGER.info('Using Clangd from %s', clangd) return clangd, resource_dir
def _StartServerNoLock(self): if self._ServerIsRunning(): return self._logfile = utils.CreateLogfile(LOGFILE_FORMAT) tsserver_log = f'-file { self._logfile } -level {_LogLevel()}' # TSServer gets the configuration for the log file through the # environment variable 'TSS_LOG'. This seems to be undocumented but # looking at the source code it seems like this is the way: # https://github.com/Microsoft/TypeScript/blob/8a93b489454fdcbdf544edef05f73a913449be1d/src/server/server.ts#L136 environ = os.environ.copy() environ['TSS_LOG'] = tsserver_log # TSServer runs out of memory on larger projects. This is the value that # VSCode uses. environ['NODE_OPTIONS'] = '--max_old_space_size=3072' LOGGER.info('TSServer log file: %s', self._logfile) # We need to redirect the error stream to the output one on Windows. self._tsserver_handle = utils.SafePopen(self._tsserver_executable, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, env=environ) LOGGER.info("TSServer started with PID %s", self._tsserver_handle.pid) self._tsserver_is_running.set() utils.StartThread(self._SetServerVersion)
def GetClangdCommand(user_options): global CLANGD_COMMAND # None stands for we tried to fetch command and failed, therefore it is not # the default. if CLANGD_COMMAND != NOT_CACHED: LOGGER.info('Returning cached Clangd command: %s', CLANGD_COMMAND) return CLANGD_COMMAND CLANGD_COMMAND = None installed_clangd, resource_dir = GetClangdExecutableAndResourceDir( user_options) if not installed_clangd: return None CLANGD_COMMAND = [installed_clangd] clangd_args = user_options['clangd_args'] put_resource_dir = False put_limit_results = False put_header_insertion_decorators = False for arg in clangd_args: CLANGD_COMMAND.append(arg) put_resource_dir = put_resource_dir or arg.startswith('-resource-dir') put_limit_results = put_limit_results or arg.startswith( '-limit-results') put_header_insertion_decorators = ( put_header_insertion_decorators or arg.startswith('-header-insertion-decorators')) if not put_header_insertion_decorators: CLANGD_COMMAND.append('-header-insertion-decorators=0') if resource_dir and not put_resource_dir: CLANGD_COMMAND.append('-resource-dir=' + resource_dir) if user_options['clangd_uses_ycmd_caching'] and not put_limit_results: CLANGD_COMMAND.append('-limit-results=500') return CLANGD_COMMAND
def _ReaderLoop( self ): """ Read responses from TSServer and use them to resolve the DeferredResponse instances. """ while True: self._tsserver_is_running.wait() try: message = self._ReadMessage() except ( RuntimeError, ValueError ): LOGGER.exception( 'Error while reading message from server' ) if not self._ServerIsRunning(): self._tsserver_is_running.clear() continue # We ignore events for now since we don't have a use for them. msgtype = message[ 'type' ] if msgtype == 'event': eventname = message[ 'event' ] LOGGER.info( 'Received %s event from TSServer', eventname ) continue if msgtype != 'response': LOGGER.error( 'Unsupported message type', msgtype ) continue seq = message[ 'request_seq' ] with self._pending_lock: if seq in self._pending: self._pending[ seq ].resolve( message ) del self._pending[ seq ]
def _StartServer(self): """Start the Gocode server.""" with self._gocode_lock: LOGGER.info('Starting Gocode server') self._gocode_port = utils.GetUnusedLocalhostPort() self._gocode_host = '127.0.0.1:{0}'.format(self._gocode_port) command = [ self._gocode_binary_path, '-s', '-sock', 'tcp', '-addr', self._gocode_host ] if LOGGER.isEnabledFor(logging.DEBUG): command.append('-debug') self._gocode_stdout = utils.CreateLogfile( LOGFILE_FORMAT.format(port=self._gocode_port, std='stdout')) self._gocode_stderr = utils.CreateLogfile( LOGFILE_FORMAT.format(port=self._gocode_port, std='stderr')) with utils.OpenForStdHandle(self._gocode_stdout) as stdout: with utils.OpenForStdHandle(self._gocode_stderr) as stderr: self._gocode_handle = utils.SafePopen(command, stdout=stdout, stderr=stderr)
def StartServer(self, request_data): with self._server_state_mutex: LOGGER.info('Starting %s: %s', self.GetServerName(), self.GetCommandLine()) self._stderr_file = utils.CreateLogfile('{}_stderr'.format( utils.MakeSafeFileNameString(self.GetServerName()))) with utils.OpenForStdHandle(self._stderr_file) as stderr: self._server_handle = utils.SafePopen(self.GetCommandLine(), stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=stderr) self._connection = (lsc.StandardIOLanguageServerConnection( self._server_handle.stdin, self._server_handle.stdout, self.GetDefaultNotificationHandler())) self._connection.Start() try: self._connection.AwaitServerConnection() except lsc.LanguageServerConnectionTimeout: LOGGER.error( '%s failed to start, or did not connect successfully', self.GetServerName()) self.Shutdown() return False LOGGER.info('%s started', self.GetServerName()) return True
def _StartServer( self ): with self._tsserver_lock: if self._ServerIsRunning(): return self._logfile = utils.CreateLogfile( LOGFILE_FORMAT ) tsserver_log = '-file {path} -level {level}'.format( path = self._logfile, level = _LogLevel() ) # TSServer gets the configuration for the log file through the # environment variable 'TSS_LOG'. This seems to be undocumented but # looking at the source code it seems like this is the way: # https://github.com/Microsoft/TypeScript/blob/8a93b489454fdcbdf544edef05f73a913449be1d/src/server/server.ts#L136 environ = os.environ.copy() utils.SetEnviron( environ, 'TSS_LOG', tsserver_log ) LOGGER.info( 'TSServer log file: %s', self._logfile ) # We need to redirect the error stream to the output one on Windows. self._tsserver_handle = utils.SafePopen( self._tsserver_executable, stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.STDOUT, env = environ ) self._tsserver_is_running.set() utils.StartThread( self._SetServerVersion )
def PollModule( module, filepath ): """ Try to use passed module in the selection process by calling CSharpSolutionFile on it """ path_to_solutionfile = None module_hint = None if module: try: module_hint = module.CSharpSolutionFile( filepath ) LOGGER.info( 'extra_conf_store suggests %s as solution file', module_hint ) if module_hint: # received a full path or one relative to the config's location? candidates = [ module_hint, os.path.join( os.path.dirname( getfile( module ) ), module_hint ) ] # try the assumptions for path in candidates: if os.path.isfile( path ): # path seems to point to a solution path_to_solutionfile = path LOGGER.info( 'Using solution file %s selected by extra_conf_store', path_to_solutionfile ) break except AttributeError: # the config script might not provide solution file locations LOGGER.exception( 'Could not retrieve solution for %s' 'from extra_conf_store', filepath ) return path_to_solutionfile
def _ReaderLoop(self): """ Read responses from TSServer and use them to resolve the DeferredResponse instances. """ while True: self._tsserver_is_running.wait() try: message = self._ReadMessage() except (RuntimeError, ValueError): LOGGER.exception('Error while reading message from server') if not self._ServerIsRunning(): self._tsserver_is_running.clear() continue # We ignore events for now since we don't have a use for them. msgtype = message['type'] if msgtype == 'event': eventname = message['event'] LOGGER.info('Received %s event from TSServer', eventname) continue if msgtype != 'response': LOGGER.error('Unsupported message type', msgtype) continue seq = message['request_seq'] with self._pending_lock: if seq in self._pending: self._pending[seq].resolve(message) del self._pending[seq]
def GetSemanticTokens(): LOGGER.info('Received semantic tokens request') request_data = RequestWrap(request.json) if not _server_state.FiletypeCompletionUsable(request_data['filetypes'], silent=True): return _JsonResponse(BuildSemanticTokensResponse(None)) errors = None semantic_tokens = None try: filetype_completer = _server_state.GetFiletypeCompleter( request_data['filetypes']) semantic_tokens = filetype_completer.ComputeSemanticTokens( request_data) except Exception as exception: LOGGER.exception( 'Exception from semantic completer during tokens request') errors = [BuildExceptionResponse(exception, traceback.format_exc())] # No fallback for signature help. The general completer is unlikely to be able # to offer anything of for that here. return _JsonResponse( BuildSemanticTokensResponse(semantic_tokens, errors=errors))
def _StartServer(self): with self._tsserver_lock: if self._ServerIsRunning(): return self._logfile = utils.CreateLogfile(LOGFILE_FORMAT) tsserver_log = '-file {path} -level {level}'.format( path=self._logfile, level=_LogLevel()) # TSServer gets the configuration for the log file through the # environment variable 'TSS_LOG'. This seems to be undocumented but # looking at the source code it seems like this is the way: # https://github.com/Microsoft/TypeScript/blob/8a93b489454fdcbdf544edef05f73a913449be1d/src/server/server.ts#L136 environ = os.environ.copy() environ['TSS_LOG'] = tsserver_log LOGGER.info('TSServer log file: %s', self._logfile) # We need to redirect the error stream to the output one on Windows. self._tsserver_handle = utils.SafePopen(self._tsserver_executable, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, env=environ) self._tsserver_is_running.set() utils.StartThread(self._SetServerVersion)
def ShouldEnableRustCompleter(): if not RLS_EXECUTABLE: LOGGER.error('Not using Rust completer: no RLS executable found at %s', RLS_EXECUTABLE) return False LOGGER.info('Using Rust completer') return True
def _CallGlobalExtraConfMethod(function_name): global_ycm_extra_conf = _GlobalYcmExtraConfFileLocation() if not (global_ycm_extra_conf and os.path.exists(global_ycm_extra_conf)): LOGGER.debug('No global extra conf, not calling method %s', function_name) return try: module = Load(global_ycm_extra_conf, force=True) except Exception: LOGGER.exception('Error occurred while loading global extra conf %s', global_ycm_extra_conf) return if not module or not hasattr(module, function_name): LOGGER.debug('Global extra conf not loaded or no function %s', function_name) return try: LOGGER.info('Calling global extra conf method %s on conf file %s', function_name, global_ycm_extra_conf) getattr(module, function_name)() except Exception: LOGGER.exception( 'Error occurred while calling global extra conf method %s ' 'on conf file %s', function_name, global_ycm_extra_conf)
def GetClangdExecutableAndResourceDir( user_options ): """Return the Clangd binary from the path specified in the 'clangd_binary_path' option. Let the binary find its resource directory in that case. If no binary is found or if it's out-of-date, return nothing. If 'clangd_binary_path' is empty, return the third-party Clangd and its resource directory if the user downloaded it and if it's up to date. Otherwise, return nothing.""" clangd = user_options[ 'clangd_binary_path' ] resource_dir = None if clangd: clangd = FindExecutable( ExpandVariablesInPath( clangd ) ) if not clangd: LOGGER.error( 'No Clangd executable found at %s', user_options[ 'clangd_binary_path' ] ) return None, None if not CheckClangdVersion( clangd ): LOGGER.error( 'Clangd at %s is out-of-date', clangd ) return None, None # Try looking for the pre-built binary. else: third_party_clangd = GetThirdPartyClangd() if not third_party_clangd: return None, None clangd = third_party_clangd resource_dir = CLANG_RESOURCE_DIR LOGGER.info( 'Using Clangd from %s', clangd ) return clangd, resource_dir
def GetReady(): LOGGER.info('Received ready request') if request.query.subserver: filetype = request.query.subserver completer = _server_state.GetFiletypeCompleter([filetype]) return _JsonResponse(completer.ServerIsReady()) return _JsonResponse(True)
def RunCompleterCommand(): LOGGER.info( 'Received command request' ) request_data = RequestWrap( request.json ) completer = _GetCompleterForRequestData( request_data ) return _JsonResponse( completer.OnUserCommand( request_data[ 'command_arguments' ], request_data ) )
def RunCompleterCommand(): LOGGER.info('Received command request') request_data = RequestWrap(request.json) completer = _GetCompleterForRequestData(request_data) return _JsonResponse( completer.OnUserCommand(request_data['command_arguments'], request_data))
def ShouldEnableTypeScriptCompleter(): tsserver = FindTSServer() if not tsserver: LOGGER.error( 'Not using TypeScript completer: TSServer not installed ' 'in %s', TSSERVER_DIR ) return False LOGGER.info( 'Using TypeScript completer with %s', tsserver ) return True
def ShouldEnableTypeScriptCompleter( user_options ): tsserver = FindTSServer( user_options[ 'tsserver_binary_path' ] ) if not tsserver: LOGGER.error( 'Not using TypeScript completer: TSServer not installed ' 'in %s', TSSERVER_DIR ) return False LOGGER.info( 'Using TypeScript completer with %s', tsserver ) return True
def StartServer(self, request_data, project_directory=None): with self._server_state_mutex: LOGGER.info('Starting jdt.ls Language Server...') if project_directory: self._java_project_dir = project_directory else: self._java_project_dir = _FindProjectDir( os.path.dirname(request_data['filepath'])) self._workspace_path = _WorkspaceDirForProject( self._java_project_dir, self._use_clean_workspace) command = [ PATH_TO_JAVA, '-Dfile.encoding=UTF-8', '-Declipse.application=org.eclipse.jdt.ls.core.id1', '-Dosgi.bundles.defaultStartLevel=4', '-Declipse.product=org.eclipse.jdt.ls.core.product', '-Dlog.level=ALL', '-jar', self._launcher_path, '-configuration', self._launcher_config, '-data', self._workspace_path, ] LOGGER.debug('Starting java-server with the following command: %s', command) self._server_stderr = utils.CreateLogfile('jdt.ls_stderr_') with utils.OpenForStdHandle(self._server_stderr) as stderr: self._server_handle = utils.SafePopen(command, stdin=PIPE, stdout=PIPE, stderr=stderr) self._connection = ( language_server_completer.StandardIOLanguageServerConnection( self._server_handle.stdin, self._server_handle.stdout, self.GetDefaultNotificationHandler())) self._connection.Start() try: self._connection.AwaitServerConnection() except language_server_completer.LanguageServerConnectionTimeout: LOGGER.error('jdt.ls failed to start, or did not connect ' 'successfully') self.Shutdown() return False LOGGER.info('jdt.ls Language Server started') return True
def StartServer( self, request_data, project_directory = None ): with self._server_state_mutex: LOGGER.info( 'Starting jdt.ls Language Server...' ) if project_directory: self._java_project_dir = project_directory else: self._java_project_dir = _FindProjectDir( os.path.dirname( request_data[ 'filepath' ] ) ) self._workspace_path = _WorkspaceDirForProject( self._java_project_dir, self._use_clean_workspace ) command = [ PATH_TO_JAVA, '-Dfile.encoding=UTF-8', '-Declipse.application=org.eclipse.jdt.ls.core.id1', '-Dosgi.bundles.defaultStartLevel=4', '-Declipse.product=org.eclipse.jdt.ls.core.product', '-Dlog.level=ALL', '-jar', self._launcher_path, '-configuration', self._launcher_config, '-data', self._workspace_path, ] LOGGER.debug( 'Starting java-server with the following command: %s', command ) self._server_stderr = utils.CreateLogfile( 'jdt.ls_stderr_' ) with utils.OpenForStdHandle( self._server_stderr ) as stderr: self._server_handle = utils.SafePopen( command, stdin = PIPE, stdout = PIPE, stderr = stderr ) self._connection = ( language_server_completer.StandardIOLanguageServerConnection( self._server_handle.stdin, self._server_handle.stdout, self.GetDefaultNotificationHandler() ) ) self._connection.Start() try: self._connection.AwaitServerConnection() except language_server_completer.LanguageServerConnectionTimeout: LOGGER.error( 'jdt.ls failed to start, or did not connect ' 'successfully' ) self.Shutdown() return False LOGGER.info( 'jdt.ls Language Server started' ) return True
def _AddIdentifier(self, identifier, request_data): filetype = request_data['first_filetype'] filepath = request_data['filepath'] if not filetype or not filepath or not identifier: return LOGGER.info('Adding ONE buffer identifier for file: %s', filepath) self._completer.AddSingleIdentifierToDatabase(identifier, filetype, filepath)
def _AddIdentifier(self, identifier, request_data): filetype = request_data['first_filetype'] filepath = request_data['filepath'] if not filetype or not filepath or not identifier: return LOGGER.info('Adding ONE buffer identifier for file: %s', filepath) self._completer.AddIdentifiersToDatabase( ycm_core.StringVector([identifier]), filetype, filepath)
def StartServer(self, request_data, project_directory=None, wipe_workspace=False, wipe_config=False): try: with self._server_info_mutex: LOGGER.info('Starting jdt.ls Language Server...') if project_directory: self._java_project_dir = project_directory elif 'project_directory' in self._settings: self._java_project_dir = utils.AbsolutePath( self._settings['project_directory'], self._extra_conf_dir) else: self._java_project_dir = _FindProjectDir( os.path.dirname(request_data['filepath'])) self._workspace_path = _WorkspaceDirForProject( self._workspace_root_path, self._java_project_dir, self._use_clean_workspace) if not self._use_clean_workspace and wipe_workspace: if os.path.isdir(self._workspace_path): LOGGER.info( f'Wiping out workspace { self._workspace_path }') shutil.rmtree(self._workspace_path) self._launcher_config = _LauncherConfiguration( self._workspace_root_path, wipe_config) self._command = [ PATH_TO_JAVA ] + self._GetJvmArgs(request_data) + [ '-Dfile.encoding=UTF-8', '-Declipse.application=org.eclipse.jdt.ls.core.id1', '-Dosgi.bundles.defaultStartLevel=4', '-Declipse.product=org.eclipse.jdt.ls.core.product', '-Dlog.level=ALL', '-jar', self._launcher_path, '-configuration', self._launcher_config, '-data', self._workspace_path, ] return super(JavaCompleter, self)._StartServerNoLock(request_data) except language_server_completer.LanguageServerConnectionTimeout: LOGGER.error('%s failed to start, or did not connect successfully', self.GetServerName()) self.Shutdown() return False
def FilterAndSortCandidates(): LOGGER.info('Received filter & sort request') # Not using RequestWrap because no need and the requests coming in aren't like # the usual requests we handle. request_data = request.json return _JsonResponse( FilterAndSortCandidatesWrap( request_data['candidates'], request_data['sort_property'], request_data['query'], _server_state.user_options['max_num_candidates']))
def GetThirdPartyClangd(): pre_built_clangd = GetExecutable( PRE_BUILT_CLANDG_PATH ) if not pre_built_clangd: LOGGER.info( 'No Clangd executable found in %s', PRE_BUILT_CLANGD_DIR ) return None if not CheckClangdVersion( pre_built_clangd ): LOGGER.error( 'Clangd executable at %s is out-of-date', pre_built_clangd ) return None LOGGER.info( 'Clangd executable found at %s and up to date', PRE_BUILT_CLANGD_DIR ) return pre_built_clangd
def FilterAndSortCandidates(): LOGGER.info( 'Received filter & sort request' ) # Not using RequestWrap because no need and the requests coming in aren't like # the usual requests we handle. request_data = request.json return _JsonResponse( FilterAndSortCandidatesWrap( request_data[ 'candidates' ], request_data[ 'sort_property' ], request_data[ 'query' ], _server_state.user_options[ 'max_num_candidates' ] ) )
def HandleNotificationInPollThread( self, notification ): if notification[ 'method' ] == 'language/status': message_type = notification[ 'params' ][ 'type' ] if message_type == 'Started': LOGGER.info( 'jdt.ls initialized successfully' ) self._received_ready_message.set() self._server_init_status = notification[ 'params' ][ 'message' ] super( JavaCompleter, self ).HandleNotificationInPollThread( notification )
def HandleNotificationInPollThread( self, notification ): if notification[ 'method' ] == 'language/status': message_type = notification[ 'params' ][ 'type' ] if message_type == 'Started': LOGGER.info( 'jdt.ls initialized successfully' ) self._server_init_status = notification[ 'params' ][ 'message' ] self._received_ready_message.set() elif not self._received_ready_message.is_set(): self._server_init_status = notification[ 'params' ][ 'message' ] super( JavaCompleter, self ).HandleNotificationInPollThread( notification )
def _StopServer( self ): with self._server_state_lock: if self._racerd_phandle: LOGGER.info( 'Stopping Racerd with PID %s', self._racerd_phandle.pid ) self._racerd_phandle.terminate() try: utils.WaitUntilProcessIsTerminated( self._racerd_phandle, timeout = 5 ) LOGGER.info( 'Racerd stopped' ) except RuntimeError: LOGGER.exception( 'Error while stopping Racerd' ) self._CleanUp()
def _AddIdentifier(self, identifier, request_data): filetype = request_data['first_filetype'] filepath = request_data['filepath'] if not filetype or not filepath or not identifier: return vector = ycm_core.StringVector() vector.append(ToCppStringCompatible(identifier)) LOGGER.info('Adding ONE buffer identifier for file: %s', filepath) self._completer.AddIdentifiersToDatabase( vector, ToCppStringCompatible(filetype), ToCppStringCompatible(filepath))
def _StopServerNoLock(self): if self._ServerIsRunning(): LOGGER.info('Stopping Tern server with PID %s', self._server_handle.pid) self._server_handle.terminate() try: utils.WaitUntilProcessIsTerminated(self._server_handle, timeout=5) LOGGER.info('Tern server stopped') except RuntimeError: LOGGER.exception('Error while stopping Tern server') self._CleanUp()
def ResolveCompletionItem(): LOGGER.info("Received resolve request") request_data = RequestWrap(request.json) completer = _GetCompleterForRequestData(request_data) errors = None completion = None try: completion = completer.ResolveCompletionItem(request_data) except Exception as e: errors = [BuildExceptionResponse(e, traceback.format_exc())] return _JsonResponse(BuildResolveCompletionResponse(completion, errors))
def _StopServerNoLock( self ): if self._ServerIsRunning(): LOGGER.info( 'Stopping TSServer with PID %s', self._tsserver_handle.pid ) try: self._SendCommand( 'exit' ) utils.WaitUntilProcessIsTerminated( self._tsserver_handle, timeout = 5 ) LOGGER.info( 'TSServer stopped' ) except Exception: LOGGER.exception( 'Error while stopping TSServer' ) self._CleanUp()
def ShouldEnableRustCompleter(user_options): if GetExecutable(user_options['rls_binary_path']): if GetExecutable(user_options['rustc_binary_path']): return True else: LOGGER.error( 'rustc_binary_path not specified, rls_binary_path ignored') if not RLS_EXECUTABLE: LOGGER.error('Not using Rust completer: no RLS executable found at %s', RLS_EXECUTABLE) return False LOGGER.info('Using Rust completer') return True
def _StopServer( self ): with self._tsserver_lock: if self._ServerIsRunning(): LOGGER.info( 'Stopping TSServer with PID %s', self._tsserver_handle.pid ) try: self._SendCommand( 'exit' ) utils.WaitUntilProcessIsTerminated( self._tsserver_handle, timeout = 5 ) LOGGER.info( 'TSServer stopped' ) except Exception: LOGGER.exception( 'Error while stopping TSServer' ) self._CleanUp()
def _AddIdentifier( self, identifier, request_data ): filetype = request_data[ 'first_filetype' ] filepath = request_data[ 'filepath' ] if not filetype or not filepath or not identifier: return vector = ycm_core.StringVector() vector.append( ToCppStringCompatible( identifier ) ) LOGGER.info( 'Adding ONE buffer identifier for file: %s', filepath ) self._completer.AddIdentifiersToDatabase( vector, ToCppStringCompatible( filetype ), ToCppStringCompatible( filepath ) )
def _StopServer( self ): with self._server_state_mutex: if self._ServerIsRunning(): LOGGER.info( 'Stopping Tern server with PID %s', self._server_handle.pid ) self._server_handle.terminate() try: utils.WaitUntilProcessIsTerminated( self._server_handle, timeout = 5 ) LOGGER.info( 'Tern server stopped' ) except RuntimeError: LOGGER.exception( 'Error while stopping Tern server' ) self._CleanUp()
def _WatchdogMain( self ): while True: time.sleep( self._check_interval_seconds ) # We make sure we don't terminate if we skipped a wakeup time. If we # skipped a check, that means the machine probably went to sleep and the # client might still actually be up. In such cases, we give it one more # wait interval to contact us before we die. if ( self._TimeSinceLastRequest() > self._idle_suicide_seconds and self._TimeSinceLastWakeup() < 2 * self._check_interval_seconds ): LOGGER.info( 'Shutting down server due to inactivity' ) ServerShutdown() self._UpdateLastWakeupTime()
def ShouldEnableClangdCompleter( user_options ): """Checks whether clangd should be enabled or not. - Returns True iff an up-to-date binary exists either in `clangd_binary_path` or in third party folder and `use_clangd` is not set to `0`. """ # User disabled clangd explicitly. if not user_options[ 'use_clangd' ]: return False clangd_command = GetClangdCommand( user_options ) if not clangd_command: return False LOGGER.info( 'Computed Clangd command: %s', clangd_command ) return True
def _SetServerProjectFileAndWorkingDirectory( self, request_data ): filepath = request_data[ 'filepath' ] self._server_project_file, is_project = FindTernProjectFile( filepath ) working_dir = request_data.get( 'working_dir', utils.GetCurrentDirectory() ) if not self._server_project_file: LOGGER.warning( 'No .tern-project file detected: %s', filepath ) self._server_working_dir = working_dir else: LOGGER.info( 'Detected Tern configuration file at: %s', self._server_project_file ) self._server_working_dir = ( os.path.dirname( self._server_project_file ) if is_project else working_dir ) LOGGER.info( 'Tern paths are relative to: %s', self._server_working_dir )
def ShouldEnableClangdCompleter( user_options ): third_party_clangd = Get3rdPartyClangd() # User disabled clangd explicitly. if user_options[ 'use_clangd' ].lower() == 'never': return False # User haven't downloaded clangd and use_clangd is in auto mode. if not third_party_clangd and user_options[ 'use_clangd' ].lower() == 'auto': return False clangd_command = GetClangdCommand( user_options, third_party_clangd ) if not clangd_command: LOGGER.warning( 'Not using clangd: unable to find clangd binary' ) return False LOGGER.info( 'Using clangd from %s', clangd_command ) return True
def ShouldEnableJavaCompleter(): LOGGER.info( 'Looking for jdt.ls' ) if not PATH_TO_JAVA: LOGGER.warning( "Not enabling java completion: Couldn't find java" ) return False if not os.path.exists( LANGUAGE_SERVER_HOME ): LOGGER.warning( 'Not using java completion: jdt.ls is not installed' ) return False if not _PathToLauncherJar(): LOGGER.warning( 'Not using java completion: jdt.ls is not built' ) return False return True
def _StopServer( self ): """ Stop the OmniSharp server using a lock. """ with self._server_state_lock: if self._ServerIsRunning(): LOGGER.info( 'Stopping OmniSharp server with PID %s', self._omnisharp_phandle.pid ) try: self._GetResponse( '/stopserver' ) utils.WaitUntilProcessIsTerminated( self._omnisharp_phandle, timeout = 5 ) LOGGER.info( 'OmniSharp server stopped' ) except Exception: LOGGER.exception( 'Error while stopping OmniSharp server' ) self._CleanUp()
def wrapper( *args, **kwargs ): if not HostHeaderCorrect( request ): LOGGER.info( 'Dropping request with bad Host header' ) abort( requests.codes.unauthorized, 'Unauthorized, received bad Host header.' ) return body = ToBytes( request.body.read() ) if not RequestAuthenticated( request.method, request.path, body, self._hmac_secret ): LOGGER.info( 'Dropping request with bad HMAC' ) abort( requests.codes.unauthorized, 'Unauthorized, received bad HMAC.' ) return body = callback( *args, **kwargs ) SetHmacHeader( body, self._hmac_secret ) return body
def _AddBufferIdentifiers( self, request_data ): filetype = request_data[ 'first_filetype' ] filepath = request_data[ 'filepath' ] if not filetype or not filepath: return collect_from_comments_and_strings = bool( self.user_options[ 'collect_identifiers_from_comments_and_strings' ] ) text = request_data[ 'file_data' ][ filepath ][ 'contents' ] LOGGER.info( 'Adding buffer identifiers for file: %s', filepath ) self._completer.ClearForFileAndAddIdentifiersToDatabase( _IdentifiersFromBuffer( text, filetype, collect_from_comments_and_strings ), ToCppStringCompatible( filetype ), ToCppStringCompatible( filepath ) )
def GetClangdCommand( user_options, third_party_clangd ): """Get commands to run clangd. Look through binaries reachable through PATH or pre-built ones. Return None if no binary exists or it is out of date. """ global CLANGD_COMMAND # None stands for we tried to fetch command and failed, therefore it is not # the default. if CLANGD_COMMAND != NOT_CACHED: LOGGER.info( 'Returning cached clangd: %s', CLANGD_COMMAND ) return CLANGD_COMMAND CLANGD_COMMAND = None resource_dir = None installed_clangd = user_options[ 'clangd_binary_path' ] if not CheckClangdVersion( installed_clangd ): if installed_clangd: LOGGER.warning( 'Clangd at %s is out-of-date, trying to use pre-built ' 'version', installed_clangd ) # Try looking for the pre-built binary. if not third_party_clangd: return None installed_clangd = third_party_clangd resource_dir = CLANG_RESOURCE_DIR # We have a clangd binary that is executable and up-to-date at this point. CLANGD_COMMAND = [ installed_clangd ] clangd_args = user_options[ 'clangd_args' ] put_resource_dir = False put_limit_results = False put_header_insertion_decorators = False for arg in clangd_args: CLANGD_COMMAND.append( arg ) put_resource_dir = put_resource_dir or arg.startswith( '-resource-dir' ) put_limit_results = put_limit_results or arg.startswith( '-limit-results' ) put_header_insertion_decorators = ( put_header_insertion_decorators or arg.startswith( '-header-insertion-decorators' ) ) if not put_header_insertion_decorators: CLANGD_COMMAND.append( '-header-insertion-decorators=0' ) if resource_dir and not put_resource_dir: CLANGD_COMMAND.append( '-resource-dir=' + resource_dir ) if user_options[ 'clangd_uses_ycmd_caching' ] and not put_limit_results: CLANGD_COMMAND.append( '-limit-results=500' ) return CLANGD_COMMAND
def EventNotification(): LOGGER.info( 'Received event notification' ) request_data = RequestWrap( request.json ) event_name = request_data[ 'event_name' ] LOGGER.debug( 'Event name: %s', event_name ) event_handler = 'On' + event_name getattr( _server_state.GetGeneralCompleter(), event_handler )( request_data ) filetypes = request_data[ 'filetypes' ] response_data = None if _server_state.FiletypeCompletionUsable( filetypes ): response_data = getattr( _server_state.GetFiletypeCompleter( filetypes ), event_handler )( request_data ) if response_data: return _JsonResponse( response_data ) return _JsonResponse( {} )
def _StartServer( self ): """ Start the OmniSharp server if not already running. Use a lock to avoid starting the server multiple times for the same solution. """ with self._server_state_lock: if self._ServerIsRunning(): return LOGGER.info( 'Starting OmniSharp server' ) path_to_solutionfile = self._solution_path LOGGER.info( 'Loading solution file %s', path_to_solutionfile ) self._ChooseOmnisharpPort() command = [ PATH_TO_OMNISHARP_BINARY, '-p', str( self._omnisharp_port ), '-s', u'{0}'.format( path_to_solutionfile ) ] if not utils.OnWindows() and not utils.OnCygwin(): command.insert( 0, 'mono' ) if utils.OnCygwin(): command.extend( [ '--client-path-mode', 'Cygwin' ] ) solutionfile = os.path.basename( path_to_solutionfile ) self._filename_stdout = utils.CreateLogfile( LOGFILE_FORMAT.format( port = self._omnisharp_port, sln = solutionfile, std = 'stdout' ) ) self._filename_stderr = utils.CreateLogfile( LOGFILE_FORMAT.format( port = self._omnisharp_port, sln = solutionfile, std = 'stderr' ) ) with utils.OpenForStdHandle( self._filename_stderr ) as fstderr: with utils.OpenForStdHandle( self._filename_stdout ) as fstdout: self._omnisharp_phandle = utils.SafePopen( command, stdout = fstdout, stderr = fstderr ) self._solution_path = path_to_solutionfile
def ShouldEnableTernCompleter(): """Returns whether or not the tern completer is 'installed'. That is whether or not the tern submodule has a 'node_modules' directory. This is pretty much the only way we can know if the user added '--js-completer' on install or manually ran 'npm install' in the tern submodule directory.""" if not PATH_TO_NODE: LOGGER.warning( 'Not using Tern completer: unable to find node' ) return False LOGGER.info( 'Using node binary from: %s', PATH_TO_NODE ) installed = os.path.exists( PATH_TO_TERN_BINARY ) if not installed: LOGGER.info( 'Not using Tern completer: not installed at %s', PATH_TO_TERN_BINARY ) return False return True