def _GetSemanticInfo( self, request_data, func, response_builder=responses.BuildDisplayMessageResponse, reparse=True): flags, filename = self._FlagsForRequest(request_data) if not flags: raise ValueError(NO_COMPILE_FLAGS_MESSAGE) if self._completer.UpdatingTranslationUnit( ToCppStringCompatible(filename)): raise RuntimeError(PARSING_FILE_MESSAGE) files = self.GetUnsavedFilesVector(request_data) line = request_data['line_num'] column = request_data['column_num'] message = getattr(self._completer, func)( ToCppStringCompatible(filename), ToCppStringCompatible(request_data['filepath']), line, column, files, flags, reparse) if not message: message = "No semantic information available" return response_builder(message)
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 _FixIt( self, request_data ): flags, filename = self._FlagsForRequest( request_data ) if not flags: raise ValueError( NO_COMPILE_FLAGS_MESSAGE ) if self._completer.UpdatingTranslationUnit( ToCppStringCompatible( filename ) ): raise RuntimeError( PARSING_FILE_MESSAGE ) files = self.GetUnsavedFilesVector( request_data ) line = request_data[ 'line_num' ] column = request_data[ 'column_num' ] fixits = getattr( self._completer, "GetFixItsForLocationInFile" )( ToCppStringCompatible( filename ), ToCppStringCompatible( request_data[ 'filepath' ] ), 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 _AddIdentifiersFromSyntax(self, keyword_list, filetype): keyword_vector = ycm_core.StringVector() for keyword in keyword_list: keyword_vector.append(ToCppStringCompatible(keyword)) filepath = SYNTAX_FILENAME + filetype self._completer.AddIdentifiersToDatabase( keyword_vector, ToCppStringCompatible(filetype), ToCppStringCompatible(filepath))
def _LocationForGoTo(self, goto_function, request_data, reparse=True): flags, filename = 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), ToCppStringCompatible(request_data['filepath']), line, column, files, flags, reparse)
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 FilterAndSortCandidatesWrap(candidates, sort_property, query): from ycm_core import FilterAndSortCandidates # The c++ interface we use only understands the (*native*) 'str' type (i.e. # not the 'str' type from python-future. If we pass it a 'unicode' or # 'bytes' instance then various things blow up, such as converting to # std::string. Therefore all strings passed into the c++ API must pass through # ToCppStringCompatible (or more strictly all strings which the C++ code # needs to use and convert. In this case, just the insertion text property) # For efficiency, the conversion of the insertion text property is done in the # C++ layer. return FilterAndSortCandidates(candidates, ToCppStringCompatible(sort_property), ToCppStringCompatible(query))
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'] self._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 FilterAndSortCandidatesWrap(candidates, sort_property, query, max_candidates): from ycm_core import FilterAndSortCandidates # The c++ interface we use only understands the 'str' type. If we pass it a # 'unicode' or 'bytes' instance then various things blow up, such as # converting to std::string. Therefore all strings passed into the c++ API # must pass through ToCppStringCompatible (or more strictly all strings which # the C++ code needs to use and convert. In this case, just the insertion # text property) For efficiency, the conversion of the insertion text # property is done in the C++ layer. return FilterAndSortCandidates(candidates, ToCppStringCompatible(sort_property), ToCppStringCompatible(query), max_candidates)
def PrepareFlagsForClang(flags, filename, add_extra_clang_flags=True, enable_windows_style_flags=False): flags = _AddLanguageFlagWhenAppropriate(flags, enable_windows_style_flags) flags = _RemoveXclangFlags(flags) flags = _RemoveUnusedFlags(flags, filename, enable_windows_style_flags) if add_extra_clang_flags: # This flag tells libclang where to find the builtin includes. flags.append('-resource-dir=' + CLANG_RESOURCE_DIR) # On Windows, parsing of templates is delayed until instantiation time. # This makes GetType and GetParent commands fail to return the expected # result when the cursor is in a template. # Using the -fno-delayed-template-parsing flag disables this behavior. See # http://clang.llvm.org/extra/PassByValueTransform.html#note-about-delayed-template-parsing # noqa # for an explanation of the flag and # https://code.google.com/p/include-what-you-use/source/detail?r=566 # for a similar issue. if OnWindows(): flags.append('-fno-delayed-template-parsing') if OnMac(): flags = _AddMacIncludePaths(flags) flags = _EnableTypoCorrection(flags) vector = ycm_core.StringVector() for flag in flags: vector.append(ToCppStringCompatible(flag)) return vector
def AddIdentifier(self, identifier, request_data): try: filetype = request_data['filetypes'][0] except KeyError: filetype = None filepath = request_data['filepath'] if not filetype or not filepath or not identifier: return vector = ycm_core.StringVector() vector.append(ToCppStringCompatible(identifier)) self._logger.info('Adding ONE buffer identifier for file: %s', filepath) self._completer.AddIdentifiersToDatabase( vector, ToCppStringCompatible(filetype), ToCppStringCompatible(filepath))
def _IdentifiersFromBuffer(text, filetype, collect_from_comments_and_strings): if not collect_from_comments_and_strings: text = identifier_utils.RemoveIdentifierFreeText(text) idents = identifier_utils.ExtractIdentifiersFromText(text, filetype) vector = ycm_core.StringVector() for ident in idents: vector.append(ToCppStringCompatible(ident)) return vector
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 ComputeCandidates(self, request_data): if not self.ShouldUseNow(request_data): return [] completions = self._completer.CandidatesForQueryAndType( ToCppStringCompatible(_SanitizeQuery(request_data['query'])), ToCppStringCompatible(request_data['first_filetype'])) completions = completions[:self._max_candidates] completions = _RemoveSmallCandidates( completions, self.user_options['min_num_identifier_candidate_chars']) def ConvertCompletionData(x): return responses.BuildCompletionData(insertion_text=x, extra_menu_info='[ID]') return [ConvertCompletionData(x) for x in completions]
def _AddIdentifiersFromTagFiles(self, tag_files): absolute_paths_to_tag_files = ycm_core.StringVector() for tag_file in self._FilterUnchangedTagFiles(tag_files): absolute_paths_to_tag_files.append(ToCppStringCompatible(tag_file)) if not absolute_paths_to_tag_files: return self._completer.AddIdentifiersToDatabaseFromTagFiles( absolute_paths_to_tag_files)
def PrepareFlagsForClang(flags, filename, add_extra_clang_flags=True): flags = _AddLanguageFlagWhenAppropriate(flags) flags = _RemoveXclangFlags(flags) flags = _RemoveUnusedFlags(flags, filename) if add_extra_clang_flags: flags = _EnableTypoCorrection(flags) vector = ycm_core.StringVector() for flag in flags: vector.append(ToCppStringCompatible(flag)) return vector
def OnBufferUnload(self, request_data): # FIXME: The filepath here is (possibly) wrong when overriding the # translation unit filename. If the buffer that the user closed is not the # "translation unit" filename, then we won't close the unit. It would # require the user to open the translation unit file, and close that. # Incidentally, doing so would flush the unit for any _other_ open files # which use that translation unit. # # Solving this would require remembering the graph of files to translation # units and only closing a unit when there are no files open which use it. self._completer.DeleteCachesForFile( ToCppStringCompatible(request_data['filepath']))
def PrepareFlagsForClang(flags, filename, add_extra_clang_flags=True): flags = _AddLanguageFlagWhenAppropriate(flags) flags = _RemoveXclangFlags(flags) flags = _RemoveUnusedFlags(flags, filename) if add_extra_clang_flags: if OnMac() and not _SysRootSpecifedIn(flags): for path in _MacIncludePaths(): flags.extend(['-isystem', path]) flags = _EnableTypoCorrection(flags) vector = ycm_core.StringVector() for flag in flags: vector.append(ToCppStringCompatible(flag)) return vector
def OnFileReadyToParse(self, request_data): flags, filename = 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.BuildDiagnosticResponse( diagnostics, request_data['filepath'], self.max_diagnostics_to_display)
def FilterAndSortCandidatesWrap(candidates, sort_property, query): from ycm_core import FilterAndSortCandidates # The c++ interface we use only understands the (*native*) 'str' type (i.e. # not the 'str' type from python-future. If we pass it a 'unicode' or # 'bytes' instance then various things blow up, such as converting to # std::string. Therefore all strings passed into the c++ API must pass through # ToCppStringCompatible (or more strictly all strings which the C++ code # needs to use and convert. In this case, just the insertion text property) # FIXME: This is actually quite inefficient in an area which is used # constantly and the key performance critical part of the system. There is # code in the C++ layer (see PythonSupport.cpp:GetUtf8String) which attempts # to work around this limitation. Unfortunately it has issues which cause the # above problems, and we work around it by converting here in the python # layer until we can come up with a better solution in the C++ layer. # Note: we must deep copy candidates because we do not want to clobber the # data that is passed in. It is actually used directly by the cache, so if # we change the data pointed to by the elements of candidates, then this will # be reflected in a subsequent response from the cache. This is particularly # important for those candidates which are *not* returned after the filter, as # they are not converted back to unicode. cpp_compatible_candidates = _ConvertCandidatesToCppCompatible( copy.deepcopy(candidates), sort_property) # However, the reset of the python layer expects all the candidates properties # to be some form of unicode string - a python-future str() instance. # So we need to convert the insertion text property back to a unicode string # before returning it. filtered_candidates = FilterAndSortCandidates( cpp_compatible_candidates, ToCppStringCompatible(sort_property), ToCppStringCompatible(query)) return _ConvertCandidatesToPythonCompatible(filtered_candidates, sort_property)
def _SanitizeFlags(flags): """Drops unsafe flags. Currently these are only -arch flags; they tend to crash libclang.""" sanitized_flags = [] saw_arch = False for i, flag in enumerate(flags): if flag == '-arch': saw_arch = True continue elif flag.startswith('-arch'): continue elif saw_arch: saw_arch = False continue sanitized_flags.append(flag) vector = ycm_core.StringVector() for flag in sanitized_flags: vector.append(ToCppStringCompatible(flag)) return vector
def AddIdentifiersFromTagFiles(self, tag_files): absolute_paths_to_tag_files = ycm_core.StringVector() for tag_file in tag_files: try: current_mtime = os.path.getmtime(tag_file) except: continue last_mtime = self._tags_file_last_mtime[tag_file] # We don't want to repeatedly process the same file over and over; we only # process if it's changed since the last time we looked at it if current_mtime <= last_mtime: continue self._tags_file_last_mtime[tag_file] = current_mtime absolute_paths_to_tag_files.append(ToCppStringCompatible(tag_file)) if not absolute_paths_to_tag_files: return self._completer.AddIdentifiersToDatabaseFromTagFiles( absolute_paths_to_tag_files)
def SetResponseHeader(name, value): name = ToCppStringCompatible(name) if PY2 else ToUnicode(name) value = ToCppStringCompatible(value) if PY2 else ToUnicode(value) bottle.response.set_header(name, value)
def OnBufferUnload( self, request_data ): self._completer.DeleteCachesForFile( ToCppStringCompatible( request_data[ 'filepath' ] ) )
def ComputeCandidates(self, request_data): if not self.ShouldUseNow(request_data): return [] completions = self._completer.CandidatesForQueryAndType( ToCppStringCompatible(_SanitizeQuery(request_data['query'])), ToCppStringCompatible(request_data['first_filetype']), self._max_candidates) completions = _RemoveSmallCandidates( completions, self.user_options['min_num_identifier_candidate_chars']) def ConvertCompletionData(x): return responses.BuildCompletionData(insertion_text=x, extra_menu_info='[ID]') # ==== Manual hack for customized autocomplete ==== # return [ ConvertCompletionData( x ) for x in completions ] # -- for DEBUG -- # from collections import defaultdict # mytest = [responses.BuildCompletionData( # insertion_text = str(v[0]()), # extra_menu_info = str(k), # '[SHORTCUT]', # detailed_info = 'pdb shortcut', # kind = None, # extra_data = defaultdict(lambda x: 'completion_extra_data_placeholder'), # ) for k, v in request_data._computed_key.items()] # -- DEBUG end -- # This part adds customized autocompletion for non-triggered # identifiers. For triggered identifiers (e.g. completion after # dot in python), customization should be added to the filetype- # specific completer. from collections import defaultdict insertion_text = None query = request_data['query'] if 'python' in request_data['filetypes']: if query == 'pdb': additional_identifier = insertion_text = 'import pdb; pdb.set_trace(); _ = 1' elif request_data['prefix'].endswith('import '): insertion_text = { 'np': 'numpy as np', 'numpy': 'numpy as np', 'pd': 'pandas as pd', 'pandas': 'pandas as pd', 'plt': 'matplotlib.pyplot as plt', 'pdb': 'pdb; pdb.set_trace(); _ = 1', }.get(query, None) if insertion_text: additional_identifier = [ responses.BuildCompletionData( insertion_text=insertion_text, extra_menu_info='[SHORTCUT]', detailed_info='oneliner shortcut', extra_data=defaultdict( lambda x: 'completion_extra_data_placeholder')) ] else: additional_identifier = [] converted_completions = [ConvertCompletionData(x) for x in completions] return converted_completions[: 1] + additional_identifier + converted_completions[ 1:]
def FilterAndSortCandidatesShim( candidates, sort_property, query ): return FilterAndSortCandidates( candidates, ToCppStringCompatible( sort_property ), ToCppStringCompatible( query ) )
def FilterAndSortCandidatesWrap(candidates, sort_property, query): from ycm_core import FilterAndSortCandidates return FilterAndSortCandidates(candidates, ToCppStringCompatible(sort_property), ToCppStringCompatible(query))