class ClangCompleter(Completer): def __init__(self, user_options): super(ClangCompleter, self).__init__(user_options) self._max_diagnostics_to_display = user_options[ 'max_diagnostics_to_display'] self._completer = ycm_core.ClangCompleter() self._flags = Flags() self._diagnostic_store = None self._files_being_compiled = EphemeralValuesSet() def SupportedFiletypes(self): return CLANG_FILETYPES def GetUnsavedFilesVector(self, request_data): files = ycm_core.UnsavedFileVector() for filename, file_data in request_data['file_data'].iteritems(): if not ClangAvailableForFiletypes(file_data['filetypes']): continue contents = file_data['contents'] if not contents or not filename: continue unsaved_file = ycm_core.UnsavedFile() utf8_contents = ToUtf8IfNeeded(contents) unsaved_file.contents_ = utf8_contents unsaved_file.length_ = len(utf8_contents) unsaved_file.filename_ = ToUtf8IfNeeded(filename) files.append(unsaved_file) return files def ComputeCandidatesInner(self, request_data): filename = request_data['filepath'] if not filename: return if self._completer.UpdatingTranslationUnit(ToUtf8IfNeeded(filename)): raise RuntimeError(PARSING_FILE_MESSAGE) flags = self._FlagsForRequest(request_data) if not flags: raise RuntimeError(NO_COMPILE_FLAGS_MESSAGE) files = self.GetUnsavedFilesVector(request_data) line = request_data['line_num'] column = request_data['start_column'] with self._files_being_compiled.GetExclusive(filename): results = self._completer.CandidatesForLocationInFile( ToUtf8IfNeeded(filename), line, column, files, flags) if not results: raise RuntimeError(NO_COMPLETIONS_MESSAGE) return [ConvertCompletionData(x) for x in results] def GetSubcommandsMap(self): return { 'GoToDefinition': (lambda self, request_data: self._GoToDefinition(request_data)), 'GoToDeclaration': (lambda self, request_data: self._GoToDeclaration(request_data)), 'GoTo': (lambda self, request_data: self._GoTo(request_data)), 'GoToImprecise': (lambda self, request_data: self._GoToImprecise(request_data)), 'GoToInclude': (lambda self, request_data: self._GoToInclude(request_data)), 'ClearCompilationFlagCache': (lambda self, request_data: self._ClearCompilationFlagCache()), 'GetType': (lambda self, request_data: self._GetSemanticInfo( request_data, func='GetTypeAtLocation')), 'GetParent': (lambda self, request_data: self._GetSemanticInfo( request_data, func='GetEnclosingFunctionAtLocation')), 'FixIt': (lambda self, request_data: self._FixIt(request_data)), 'GetDoc': (lambda self, request_data: self._GetSemanticInfo( request_data, reparse=True, func='GetDocsForLocationInFile', response_builder=_BuildGetDocResponse)), 'GetDocQuick': (lambda self, request_data: self._GetSemanticInfo( request_data, reparse=False, func='GetDocsForLocationInFile', response_builder=_BuildGetDocResponse)), } def _LocationForGoTo(self, goto_function, request_data, reparse=True): filename = request_data['filepath'] if not filename: raise ValueError(INVALID_FILE_MESSAGE) flags = self._FlagsForRequest(request_data) if not flags: raise ValueError(NO_COMPILE_FLAGS_MESSAGE) files = self.GetUnsavedFilesVector(request_data) line = request_data['line_num'] column = request_data['column_num'] return getattr(self._completer, goto_function)(ToUtf8IfNeeded(filename), line, column, files, flags, reparse) def _GoToDefinition(self, request_data): location = self._LocationForGoTo('GetDefinitionLocation', request_data) if not location or not location.IsValid(): raise RuntimeError('Can\'t jump to definition.') return _ResponseForLocation(location) def _GoToDeclaration(self, request_data): location = self._LocationForGoTo('GetDeclarationLocation', request_data) if not location or not location.IsValid(): raise RuntimeError('Can\'t jump to declaration.') return _ResponseForLocation(location) def _GoTo(self, request_data): include_response = self._ResponseForInclude(request_data) if include_response: return include_response location = self._LocationForGoTo('GetDefinitionLocation', request_data) if not location or not location.IsValid(): location = self._LocationForGoTo('GetDeclarationLocation', request_data) if not location or not location.IsValid(): raise RuntimeError('Can\'t jump to definition or declaration.') return _ResponseForLocation(location) def _GoToImprecise(self, request_data): include_response = self._ResponseForInclude(request_data) if include_response: return include_response location = self._LocationForGoTo('GetDefinitionLocation', request_data, reparse=False) if not location or not location.IsValid(): location = self._LocationForGoTo('GetDeclarationLocation', request_data, reparse=False) if not location or not location.IsValid(): raise RuntimeError('Can\'t jump to definition or declaration.') return _ResponseForLocation(location) def _ResponseForInclude(self, request_data): """Returns response for include file location if cursor is on the include statement, None otherwise. Throws RuntimeError if cursor is on include statement and corresponding include file not found.""" current_line = request_data['line_value'] include_file_name, quoted_include = GetIncludeStatementValue( current_line) if not include_file_name: return None current_file_path = ToUtf8IfNeeded(request_data['filepath']) client_data = request_data.get('extra_conf_data', None) quoted_include_paths, include_paths = (self._flags.UserIncludePaths( current_file_path, client_data)) if quoted_include: include_file_path = _GetAbsolutePath(include_file_name, quoted_include_paths) if include_file_path: return responses.BuildGoToResponse(include_file_path, line_num=1, column_num=1) include_file_path = _GetAbsolutePath(include_file_name, include_paths) if include_file_path: return responses.BuildGoToResponse(include_file_path, line_num=1, column_num=1) raise RuntimeError('Include file not found.') def _GoToInclude(self, request_data): include_response = self._ResponseForInclude(request_data) if not include_response: raise RuntimeError('Not an include/import line.') return include_response def _GetSemanticInfo( self, request_data, func, response_builder=responses.BuildDisplayMessageResponse, reparse=True): filename = request_data['filepath'] if not filename: raise ValueError(INVALID_FILE_MESSAGE) flags = self._FlagsForRequest(request_data) if not flags: raise ValueError(NO_COMPILE_FLAGS_MESSAGE) files = self.GetUnsavedFilesVector(request_data) line = request_data['line_num'] column = request_data['column_num'] message = getattr(self._completer, func)(ToUtf8IfNeeded(filename), line, column, files, flags, reparse) if not message: message = "No semantic information available" return response_builder(message) def _ClearCompilationFlagCache(self): self._flags.Clear() def _FixIt(self, request_data): filename = request_data['filepath'] if not filename: raise ValueError(INVALID_FILE_MESSAGE) flags = self._FlagsForRequest(request_data) if not flags: raise ValueError(NO_COMPILE_FLAGS_MESSAGE) files = self.GetUnsavedFilesVector(request_data) line = request_data['line_num'] column = request_data['column_num'] fixits = getattr(self._completer, "GetFixItsForLocationInFile")( ToUtf8IfNeeded(filename), line, column, files, flags, True) # don't raise an error if not fixits: - leave that to the client to respond # in a nice way return responses.BuildFixItResponse(fixits) def OnFileReadyToParse(self, request_data): filename = request_data['filepath'] if not filename: raise ValueError(INVALID_FILE_MESSAGE) flags = self._FlagsForRequest(request_data) if not flags: raise ValueError(NO_COMPILE_FLAGS_MESSAGE) with self._files_being_compiled.GetExclusive(filename): diagnostics = self._completer.UpdateTranslationUnit( ToUtf8IfNeeded(filename), self.GetUnsavedFilesVector(request_data), flags) diagnostics = _FilterDiagnostics(diagnostics) self._diagnostic_store = DiagnosticsToDiagStructure(diagnostics) return [ responses.BuildDiagnosticData(x) for x in diagnostics[:self._max_diagnostics_to_display] ] def OnBufferUnload(self, request_data): self._completer.DeleteCachesForFile( ToUtf8IfNeeded(request_data['unloaded_buffer'])) def GetDetailedDiagnostic(self, request_data): current_line = request_data['line_num'] current_column = request_data['column_num'] current_file = request_data['filepath'] if not self._diagnostic_store: raise ValueError(NO_DIAGNOSTIC_MESSAGE) diagnostics = self._diagnostic_store[current_file][current_line] if not diagnostics: raise ValueError(NO_DIAGNOSTIC_MESSAGE) closest_diagnostic = None distance_to_closest_diagnostic = 999 for diagnostic in diagnostics: distance = abs(current_column - diagnostic.location_.column_number_) if distance < distance_to_closest_diagnostic: distance_to_closest_diagnostic = distance closest_diagnostic = diagnostic return responses.BuildDisplayMessageResponse( closest_diagnostic.long_formatted_text_) def DebugInfo(self, request_data): filename = request_data['filepath'] if not filename: return '' flags = self._FlagsForRequest(request_data) or [] source = extra_conf_store.ModuleFileForSourceFile(filename) return 'Flags for {0} loaded from {1}:\n{2}'.format( filename, source, list(flags)) def _FlagsForRequest(self, request_data): filename = ToUtf8IfNeeded(request_data['filepath']) if 'compilation_flags' in request_data: return PrepareFlagsForClang(request_data['compilation_flags'], filename) client_data = request_data.get('extra_conf_data', None) return self._flags.FlagsForFile(filename, client_data=client_data)
class ClangCompleter( Completer ): def __init__( self, user_options ): super( ClangCompleter, self ).__init__( user_options ) self._max_diagnostics_to_display = user_options[ 'max_diagnostics_to_display' ] self._completer = ycm_core.ClangCompleter() self._flags = Flags() self._diagnostic_store = None self._files_being_compiled = EphemeralValuesSet() def SupportedFiletypes( self ): return CLANG_FILETYPES def GetUnsavedFilesVector( self, request_data ): files = ycm_core.UnsavedFileVector() for filename, file_data in iteritems( request_data[ 'file_data' ] ): if not ClangAvailableForFiletypes( file_data[ 'filetypes' ] ): continue contents = file_data[ 'contents' ] if not contents or not filename: continue unsaved_file = ycm_core.UnsavedFile() utf8_contents = ToCppStringCompatible( contents ) unsaved_file.contents_ = utf8_contents unsaved_file.length_ = len( utf8_contents ) unsaved_file.filename_ = ToCppStringCompatible( filename ) files.append( unsaved_file ) return files def ComputeCandidatesInner( self, request_data ): filename = request_data[ 'filepath' ] if not filename: return if self._completer.UpdatingTranslationUnit( ToCppStringCompatible( filename ) ): raise RuntimeError( PARSING_FILE_MESSAGE ) flags = self._FlagsForRequest( request_data ) if not flags: raise RuntimeError( NO_COMPILE_FLAGS_MESSAGE ) files = self.GetUnsavedFilesVector( request_data ) line = request_data[ 'line_num' ] column = request_data[ 'start_column' ] with self._files_being_compiled.GetExclusive( filename ): results = self._completer.CandidatesForLocationInFile( ToCppStringCompatible( filename ), line, column, files, flags ) if not results: raise RuntimeError( NO_COMPLETIONS_MESSAGE ) return [ ConvertCompletionData( x ) for x in results ] def GetSubcommandsMap( self ): return { 'GoToDefinition' : ( lambda self, request_data, args: self._GoToDefinition( request_data ) ), 'GoToDeclaration' : ( lambda self, request_data, args: self._GoToDeclaration( request_data ) ), 'GoTo' : ( lambda self, request_data, args: self._GoTo( request_data ) ), 'GoToImprecise' : ( lambda self, request_data, args: self._GoToImprecise( request_data ) ), 'GoToInclude' : ( lambda self, request_data, args: self._GoToInclude( request_data ) ), 'ClearCompilationFlagCache': ( lambda self, request_data, args: self._ClearCompilationFlagCache() ), 'GetType' : ( lambda self, request_data, args: self._GetSemanticInfo( request_data, func = 'GetTypeAtLocation' ) ), 'GetTypeImprecise' : ( lambda self, request_data, args: self._GetSemanticInfo( request_data, func = 'GetTypeAtLocation', reparse = False ) ), 'GetParent' : ( lambda self, request_data, args: self._GetSemanticInfo( request_data, func = 'GetEnclosingFunctionAtLocation' ) ), 'FixIt' : ( lambda self, request_data, args: self._FixIt( request_data ) ), 'GetDoc' : ( lambda self, request_data, args: self._GetSemanticInfo( request_data, reparse = True, func = 'GetDocsForLocationInFile', response_builder = _BuildGetDocResponse ) ), 'GetDocImprecise' : ( lambda self, request_data, args: self._GetSemanticInfo( request_data, reparse = False, func = 'GetDocsForLocationInFile', response_builder = _BuildGetDocResponse ) ), } def _LocationForGoTo( self, goto_function, request_data, reparse = True ): filename = request_data[ 'filepath' ] if not filename: raise ValueError( INVALID_FILE_MESSAGE ) flags = self._FlagsForRequest( request_data ) if not flags: raise ValueError( NO_COMPILE_FLAGS_MESSAGE ) files = self.GetUnsavedFilesVector( request_data ) line = request_data[ 'line_num' ] column = request_data[ 'column_num' ] return getattr( self._completer, goto_function )( ToCppStringCompatible( filename ), line, column, files, flags, reparse ) def _GoToDefinition( self, request_data ): location = self._LocationForGoTo( 'GetDefinitionLocation', request_data ) if not location or not location.IsValid(): raise RuntimeError( 'Can\'t jump to definition.' ) return _ResponseForLocation( location ) def _GoToDeclaration( self, request_data ): location = self._LocationForGoTo( 'GetDeclarationLocation', request_data ) if not location or not location.IsValid(): raise RuntimeError( 'Can\'t jump to declaration.' ) return _ResponseForLocation( location ) def _GoTo( self, request_data ): include_response = self._ResponseForInclude( request_data ) if include_response: return include_response location = self._LocationForGoTo( 'GetDefinitionLocation', request_data ) if not location or not location.IsValid(): location = self._LocationForGoTo( 'GetDeclarationLocation', request_data ) if not location or not location.IsValid(): raise RuntimeError( 'Can\'t jump to definition or declaration.' ) return _ResponseForLocation( location ) def _GoToImprecise( self, request_data ): include_response = self._ResponseForInclude( request_data ) if include_response: return include_response location = self._LocationForGoTo( 'GetDefinitionLocation', request_data, reparse = False ) if not location or not location.IsValid(): location = self._LocationForGoTo( 'GetDeclarationLocation', request_data, reparse = False ) if not location or not location.IsValid(): raise RuntimeError( 'Can\'t jump to definition or declaration.' ) return _ResponseForLocation( location ) def _ResponseForInclude( self, request_data ): """Returns response for include file location if cursor is on the include statement, None otherwise. Throws RuntimeError if cursor is on include statement and corresponding include file not found.""" current_line = request_data[ 'line_value' ] include_file_name, quoted_include = GetIncludeStatementValue( current_line ) if not include_file_name: return None current_file_path = request_data[ 'filepath' ] client_data = request_data.get( 'extra_conf_data', None ) quoted_include_paths, include_paths = ( self._flags.UserIncludePaths( current_file_path, client_data ) ) if quoted_include: include_file_path = _GetAbsolutePath( include_file_name, quoted_include_paths ) if include_file_path: return responses.BuildGoToResponse( include_file_path, line_num = 1, column_num = 1 ) include_file_path = _GetAbsolutePath( include_file_name, include_paths ) if include_file_path: return responses.BuildGoToResponse( include_file_path, line_num = 1, column_num = 1 ) raise RuntimeError( 'Include file not found.' ) def _GoToInclude( self, request_data ): include_response = self._ResponseForInclude( request_data ) if not include_response: raise RuntimeError( 'Not an include/import line.' ) return include_response def _GetSemanticInfo( self, request_data, func, response_builder = responses.BuildDisplayMessageResponse, reparse = True ): filename = request_data[ 'filepath' ] if not filename: raise ValueError( INVALID_FILE_MESSAGE ) flags = self._FlagsForRequest( request_data ) if not flags: raise ValueError( NO_COMPILE_FLAGS_MESSAGE ) files = self.GetUnsavedFilesVector( request_data ) line = request_data[ 'line_num' ] column = request_data[ 'column_num' ] message = getattr( self._completer, func )( ToCppStringCompatible( filename ), line, column, files, flags, reparse) if not message: message = "No semantic information available" return response_builder( message ) def _ClearCompilationFlagCache( self ): self._flags.Clear() def _FixIt( self, request_data ): filename = request_data[ 'filepath' ] if not filename: raise ValueError( INVALID_FILE_MESSAGE ) flags = self._FlagsForRequest( request_data ) if not flags: raise ValueError( NO_COMPILE_FLAGS_MESSAGE ) files = self.GetUnsavedFilesVector( request_data ) line = request_data[ 'line_num' ] column = request_data[ 'column_num' ] fixits = getattr( self._completer, "GetFixItsForLocationInFile" )( ToCppStringCompatible( filename ), line, column, files, flags, True ) # don't raise an error if not fixits: - leave that to the client to respond # in a nice way return responses.BuildFixItResponse( fixits ) def OnFileReadyToParse( self, request_data ): filename = request_data[ 'filepath' ] if not filename: raise ValueError( INVALID_FILE_MESSAGE ) flags = self._FlagsForRequest( request_data ) if not flags: raise ValueError( NO_COMPILE_FLAGS_MESSAGE ) with self._files_being_compiled.GetExclusive( filename ): diagnostics = self._completer.UpdateTranslationUnit( ToCppStringCompatible( filename ), self.GetUnsavedFilesVector( request_data ), flags ) diagnostics = _FilterDiagnostics( diagnostics ) self._diagnostic_store = DiagnosticsToDiagStructure( diagnostics ) return [ responses.BuildDiagnosticData( x ) for x in diagnostics[ : self._max_diagnostics_to_display ] ] def OnBufferUnload( self, request_data ): self._completer.DeleteCachesForFile( ToCppStringCompatible( request_data[ 'filepath' ] ) ) def GetDetailedDiagnostic( self, request_data ): current_line = request_data[ 'line_num' ] current_column = request_data[ 'column_num' ] current_file = request_data[ 'filepath' ] if not self._diagnostic_store: raise ValueError( NO_DIAGNOSTIC_MESSAGE ) diagnostics = self._diagnostic_store[ current_file ][ current_line ] if not diagnostics: raise ValueError( NO_DIAGNOSTIC_MESSAGE ) closest_diagnostic = None distance_to_closest_diagnostic = 999 # FIXME: all of these calculations are currently working with byte # offsets, which are technically incorrect. We should be working with # codepoint offsets, as we want the nearest character-wise diagnostic for diagnostic in diagnostics: distance = abs( current_column - diagnostic.location_.column_number_ ) if distance < distance_to_closest_diagnostic: distance_to_closest_diagnostic = distance closest_diagnostic = diagnostic return responses.BuildDisplayMessageResponse( closest_diagnostic.long_formatted_text_ ) def DebugInfo( self, request_data ): filename = request_data[ 'filepath' ] try: extra_conf = extra_conf_store.ModuleFileForSourceFile( filename ) except UnknownExtraConf as error: return ( 'C-family completer debug information:\n' ' Configuration file found but not loaded\n' ' Configuration path: {0}'.format( error.extra_conf_file ) ) try: # Note that it only raises NoExtraConfDetected: # - when extra_conf is None and, # - there is no compilation database flags = self._FlagsForRequest( request_data ) except NoExtraConfDetected: # No flags return ( 'C-family completer debug information:\n' ' No configuration file found\n' ' No compilation database found' ) # If _FlagsForRequest returns None or raises, we use an empty list in # practice. flags = flags or [] if extra_conf: # We got the flags from the extra conf file return ( 'C-family completer debug information:\n' ' Configuration file found and loaded\n' ' Configuration path: {0}\n' ' Flags: {1}'.format( extra_conf, list( flags ) ) ) try: database = self._flags.FindCompilationDatabase( os.path.dirname( filename ) ) except NoCompilationDatabase: # No flags return ( 'C-family completer debug information:\n' ' No configuration file found\n' ' No compilation database found' ) # We got the flags from the compilation database return ( 'C-family completer debug information:\n' ' No configuration file found\n' ' Using compilation database from: {0}\n' ' Flags: {1}'.format( database.database_directory, list( flags ) ) ) def _FlagsForRequest( self, request_data ): filename = request_data[ 'filepath' ] if 'compilation_flags' in request_data: return PrepareFlagsForClang( request_data[ 'compilation_flags' ], filename ) client_data = request_data.get( 'extra_conf_data', None ) return self._flags.FlagsForFile( filename, client_data = client_data )
class FilenameCompleter( Completer ): """ General completer that provides filename and filepath completions. """ def __init__( self, user_options ): super( FilenameCompleter, self ).__init__( user_options ) self._flags = Flags() # On Windows, backslashes are also valid path separators. self._triggers = [ '/', '\\' ] if OnWindows() else [ '/' ] self._path_regex = re.compile( """ # Head part (?: # 'D:/'-like token [A-z]+:[%(sep)s]| # '/', './', '../', or '~' \.{0,2}[%(sep)s]|~| # '$var/' \$[A-Za-z0-9{}_]+[%(sep)s] )+ # Tail part (?: # any alphanumeric, symbol or space literal [ %(sep)sa-zA-Z0-9(){}$+_~.\x80-\xff-\[\]]| # skip any special symbols [^\x20-\x7E]| # backslash and 1 char after it \\. )*$ """ % { 'sep': '/\\\\' if OnWindows() else '/' }, re.X ) def ShouldCompleteIncludeStatement( self, request_data ): start_column = request_data[ 'start_column' ] - 1 current_line = request_data[ 'line_value' ] filepath = request_data[ 'filepath' ] filetypes = request_data[ 'file_data' ][ filepath ][ 'filetypes' ] return ( InCFamilyFile( filetypes ) and AtIncludeStatementStart( current_line[ :start_column ] ) ) def ShouldUseNowInner( self, request_data ): start_column = request_data[ 'start_column' ] - 1 current_line = request_data[ 'line_value' ] return ( start_column and ( current_line[ start_column - 1 ] in self._triggers or self.ShouldCompleteIncludeStatement( request_data ) ) ) def SupportedFiletypes( self ): return [] def ComputeCandidatesInner( self, request_data ): current_line = request_data[ 'line_value' ] start_column = request_data[ 'start_column' ] - 1 orig_filepath = request_data[ 'filepath' ] filetypes = request_data[ 'file_data' ][ orig_filepath ][ 'filetypes' ] line = current_line[ :start_column ] utf8_filepath = ToUtf8IfNeeded( orig_filepath ) if InCFamilyFile( filetypes ): path_dir, quoted_include = ( GetIncludeStatementValue( line, check_closing = False ) ) if path_dir is not None: # We do what GCC does for <> versus "": # http://gcc.gnu.org/onlinedocs/cpp/Include-Syntax.html client_data = request_data.get( 'extra_conf_data', None ) return _GenerateCandidatesForPaths( self.GetPathsIncludeCase( path_dir, quoted_include, utf8_filepath, client_data ) ) path_match = self._path_regex.search( line ) path_dir = os.path.expanduser( os.path.expandvars( path_match.group() ) ) if path_match else '' # If the client supplied its working directory, use that instead of the # working directory of ycmd working_dir = request_data.get( 'working_dir' ) return _GenerateCandidatesForPaths( _GetPathsStandardCase( path_dir, self.user_options[ 'filepath_completion_use_working_dir' ], utf8_filepath, working_dir) ) def GetPathsIncludeCase( self, path_dir, quoted_include, filepath, client_data ): paths = [] quoted_include_paths, include_paths = ( self._flags.UserIncludePaths( filepath, client_data ) ) if quoted_include: include_paths.extend( quoted_include_paths ) for include_path in include_paths: unicode_path = ToUnicodeIfNeeded( os.path.join( include_path, path_dir ) ) try: # We need to pass a unicode string to get unicode strings out of # listdir. relative_paths = os.listdir( unicode_path ) except: relative_paths = [] paths.extend( os.path.join( include_path, path_dir, relative_path ) for relative_path in relative_paths ) return sorted( set( paths ) )
class FilenameCompleter(Completer): """ General completer that provides filename and filepath completions. """ def __init__(self, user_options): super(FilenameCompleter, self).__init__(user_options) self._flags = Flags() self._path_regex = re.compile( """ # 1 or more 'D:/'-like token or '/' or '~' or './' or '../' or '$var/' (?:[A-z]+:/|[/~]|\./|\.+/|\$[A-Za-z0-9{}_]+/)+ # any alphanumeric, symbol or space literal (?:[ /a-zA-Z0-9(){}$+_~.\x80-\xff-\[\]]| # skip any special symbols [^\x20-\x7E]| # backslash and 1 char after it. + matches 1 or more of whole group \\.)*$ """, re.X) include_regex_common = '^\s*#(?:include|import)\s*(?:"|<)' self._include_start_regex = re.compile(include_regex_common + '$') self._include_regex = re.compile(include_regex_common) def AtIncludeStatementStart(self, request_data): start_column = request_data['start_column'] - 1 current_line = request_data['line_value'] filepath = request_data['filepath'] filetypes = request_data['file_data'][filepath]['filetypes'] return (InCFamilyFile(filetypes) and self._include_start_regex.match( current_line[:start_column])) def ShouldUseNowInner(self, request_data): start_column = request_data['start_column'] - 1 current_line = request_data['line_value'] return (start_column and (current_line[start_column - 1] == '/' or self.AtIncludeStatementStart(request_data))) def SupportedFiletypes(self): return [] def ComputeCandidatesInner(self, request_data): current_line = request_data['line_value'] start_column = request_data['start_column'] - 1 orig_filepath = request_data['filepath'] filetypes = request_data['file_data'][orig_filepath]['filetypes'] line = current_line[:start_column] utf8_filepath = ToUtf8IfNeeded(orig_filepath) if InCFamilyFile(filetypes): include_match = self._include_regex.search(line) if include_match: path_dir = line[include_match.end():] # We do what GCC does for <> versus "": # http://gcc.gnu.org/onlinedocs/cpp/Include-Syntax.html include_current_file_dir = '<' not in include_match.group() return _GenerateCandidatesForPaths( self.GetPathsIncludeCase(path_dir, include_current_file_dir, utf8_filepath)) path_match = self._path_regex.search(line) path_dir = os.path.expanduser(os.path.expandvars( path_match.group())) if path_match else '' return _GenerateCandidatesForPaths( _GetPathsStandardCase( path_dir, self.user_options['filepath_completion_use_working_dir'], utf8_filepath)) def GetPathsIncludeCase(self, path_dir, include_current_file_dir, filepath): paths = [] include_paths = self._flags.UserIncludePaths(filepath) if include_current_file_dir: include_paths.append(os.path.dirname(filepath)) for include_path in include_paths: unicode_path = ToUnicodeIfNeeded( os.path.join(include_path, path_dir)) try: # We need to pass a unicode string to get unicode strings out of # listdir. relative_paths = os.listdir(unicode_path) except: relative_paths = [] paths.extend( os.path.join(include_path, path_dir, relative_path) for relative_path in relative_paths) return sorted(set(paths))