From: Samir Benmendil Date: Sun, 14 May 2017 21:23:21 +0000 (+0100) Subject: vim: import ycm_extra_conf from the internet X-Git-Url: https://git.rmz.io/dotfiles.git/commitdiff_plain/de55c1c46e484a81bed3730f7773d6745ef4405c vim: import ycm_extra_conf from the internet https://github.com/arximboldi/dotfiles/blob/master/emacs/.ycm_extra_conf.py --- diff --git a/vim/ycm_extra_conf.py b/vim/ycm_extra_conf.py index b4202ef..f02f017 100644 --- a/vim/ycm_extra_conf.py +++ b/vim/ycm_extra_conf.py @@ -1,86 +1,174 @@ -from glob import glob -from os import path +# https://github.com/Valloric/ycmd/blob/master/cpp/ycm/.ycm_extra_conf.py +# https://jonasdevlieghere.com/a-better-youcompleteme-config/ +import os +import os.path +import logging import ycm_core +BASE_FLAGS = [ + '-Wall', + '-std=c++1z', + '-xc++', + '-I/usr/lib/' + '-I/usr/include/' +] -def findCompilationDatabaseFolder(dir='.'): - dirs = [path.dirname(f) for f in glob(dir + '/**/compile_commands.json', - recursive=True)] - return dirs +SOURCE_EXTENSIONS = [ + '.cpp', + '.cxx', + '.cc', + '.c', + '.m', + '.mm' +] +HEADER_EXTENSIONS = [ + '.h', + '.hxx', + '.hpp', + '.hh' +] -def generateQtFlags(): - flags = ['-isystem', '/usr/include/qt/'] - for p in glob('/usr/include/qt/*/'): - flags += ['-isystem', p] - return flags +def find_similar_file_in_database(dbpath, filename): + import json + import Levenshtein + logging.info("Trying to find some file close to: " + filename) + db = json.load(open(dbpath)) + best_filename = '' + best_distance = 1 << 31 + for entry in db: + entry_filename = os.path.normpath( + os.path.join(entry["directory"], entry["file"])) + distance = Levenshtein.distance(str(filename), str(entry_filename)) + if distance < best_distance: + best_filename = entry_filename + best_distance = distance + return best_filename +def ok_compilation_info(info): + return bool(info.compiler_flags_) -def isHeader(filename): - ext = path.splitext(filename)[1] - return ext in ['.hpp', '.h'] - - -def GetCompilationInfoForFile(database, filename): - if isHeader(filename): - basename = path.splitext(filename)[0] - for ext in ['.cpp', '.c']: - cpp_file = basename + ext - if path.exists(cpp_file): - compilation_info = database.GetCompilationInfoForFile( - cpp_file) - if compilation_info.compiler_flags_: - return compilation_info - return None - return database.GetCompilationInfoForFile(filename) +def get_compilation_info_for_file(dbpath, database, filename): + info = database.GetCompilationInfoForFile(filename) + if ok_compilation_info(info): + logging.info("Flags for file where found in database: " + filename) + return info + else: + logging.info("Flags for file not found in database: " + filename) + basename = os.path.splitext(filename)[0] + for extension in SOURCE_EXTENSIONS: + replacement_file = basename + extension + logging.info("Trying to replace extension with: " + extension) + info = database.GetCompilationInfoForFile(replacement_file) + if ok_compilation_info(info): + logging.info("Replacing header with: " + replacement_file) + return info + replacement_file = find_similar_file_in_database(dbpath, filename) + logging.info("Replacing header with: " + replacement_file) + return database.GetCompilationInfoForFile(replacement_file) +def find_nearest(path, target): + candidates = [ + os.path.join(path, target), + os.path.join(path, 'build', target), + os.path.join(path, 'output', target), + ] + for candidate in candidates: + if os.path.isfile(candidate) or os.path.isdir(candidate): + logging.info("Found nearest " + target + " at " + candidate) + return candidate + parent = os.path.dirname(os.path.abspath(path)) + if parent == path: + raise RuntimeError("Could not find " + target) + return find_nearest(parent, target) -def FlagsForFile(filename, **kwargs): - client_data = kwargs['client_data'] - cwd = client_data['getcwd()'] +def make_relative_paths_in_flags_absolute(flags, working_directory): + if not working_directory: + return list(flags) + new_flags = [] + make_next_absolute = False + path_flags = [ '-isystem', '-I', '-iquote', '--sysroot=' ] + for flag in flags: + new_flag = flag + if make_next_absolute: + make_next_absolute = False + if not flag.startswith('/'): + new_flag = os.path.join(working_directory, flag) + for path_flag in path_flags: + if flag == path_flag: + make_next_absolute = True + break + if flag.startswith(path_flag): + path = flag[ len(path_flag): ] + new_flag = path_flag + os.path.join(working_directory, path) + break + if new_flag: + new_flags.append(new_flag) + return new_flags - extra_flags = [ - '-Wall', - '-Wextra', - # '-Wshadow', - # '-Werror', - # '-Wc++98-compat', - # '-Wno-long-long', - # '-Wno-variadic-macros', - # '-fexceptions', - # '-DNDEBUG', - ] +def flags_for_clang_complete(root): + try: + clang_complete_path = find_nearest(root, '.clang_complete') + clang_complete_flags = open(clang_complete_path, 'r').read().splitlines() + return clang_complete_flags + except Exception, err: + logging.info("Error while looking flags for .clang_complete in root: " + root) + logging.error(err) + return None - folders = findCompilationDatabaseFolder(cwd) - if not folders: - folder = None - else: - folder = folders[0] - if len(folders) > 1: - print("Multiple compilation databases found!") - print(folders) - print("Selecting first: %s" % (folder)) +def flags_for_include(root): + try: + include_path = find_nearest(root, 'include') + flags = [] + for dirroot, dirnames, filenames in os.walk(include_path): + for dir_path in dirnames: + real_path = os.path.join(dirroot, dir_path) + flags = flags + ["-I" + real_path] + return flags + except Exception, err: + logging.info("Error while looking flags for includes in root: " + root) + logging.error(err) + return None - if folder: - database = ycm_core.CompilationDatabase(folder) - compilation_info = GetCompilationInfoForFile(database, filename) +def flags_for_compilation_database(root, filename): + try: + compilation_db_path = find_nearest(root, 'compile_commands.json') + compilation_db_dir = os.path.dirname(compilation_db_path) + logging.info("Set compilation database directory to " + compilation_db_dir) + compilation_db = ycm_core.CompilationDatabase(compilation_db_dir) + if not compilation_db: + logging.info("Compilation database file found but unable to load") + return None + compilation_info = get_compilation_info_for_file( + compilation_db_path, compilation_db, filename) if not compilation_info: + logging.info("No compilation info for " + filename + " in compilation database") return None - flags = list(compilation_info.compiler_flags_) - else: - flags = [ - '-std=c++14', - '-stdlib=libstdc++', - '-x', 'c++', - '-isystem', '/usr/include', - '-isystem', '/usr/local/include', - '-I', cwd, - '-I', cwd + '/include', - ] - flags += generateQtFlags() + return make_relative_paths_in_flags_absolute( + compilation_info.compiler_flags_, + compilation_info.compiler_working_dir_) + except Exception, err: + logging.info("Error while trying to get flags for " + filename + " in compilation database") + logging.error(err) + return None +def flags_for_file(filename): + root = os.path.realpath(filename) + compilation_db_flags = flags_for_compilation_database(root, filename) + if compilation_db_flags: + final_flags = compilation_db_flags + else: + final_flags = BASE_FLAGS + clang_flags = flags_for_clang_complete(root) + if clang_flags: + final_flags = final_flags + clang_flags + include_flags = flags_for_include(root) + if include_flags: + final_flags = final_flags + include_flags return { - 'flags': flags + extra_flags, + 'flags': final_flags, 'do_cache': True } + +FlagsForFile = flags_for_file