]> git.rmz.io Git - dotfiles.git/blob - vim/ycm_extra_conf.py
vim: import ycm_extra_conf from the internet
[dotfiles.git] / vim / ycm_extra_conf.py
1 # https://github.com/Valloric/ycmd/blob/master/cpp/ycm/.ycm_extra_conf.py
2 # https://jonasdevlieghere.com/a-better-youcompleteme-config/
3
4 import os
5 import os.path
6 import logging
7 import ycm_core
8
9 BASE_FLAGS = [
10 '-Wall',
11 '-std=c++1z',
12 '-xc++',
13 '-I/usr/lib/'
14 '-I/usr/include/'
15 ]
16
17 SOURCE_EXTENSIONS = [
18 '.cpp',
19 '.cxx',
20 '.cc',
21 '.c',
22 '.m',
23 '.mm'
24 ]
25
26 HEADER_EXTENSIONS = [
27 '.h',
28 '.hxx',
29 '.hpp',
30 '.hh'
31 ]
32
33 def find_similar_file_in_database(dbpath, filename):
34 import json
35 import Levenshtein
36 logging.info("Trying to find some file close to: " + filename)
37 db = json.load(open(dbpath))
38 best_filename = ''
39 best_distance = 1 << 31
40 for entry in db:
41 entry_filename = os.path.normpath(
42 os.path.join(entry["directory"], entry["file"]))
43 distance = Levenshtein.distance(str(filename), str(entry_filename))
44 if distance < best_distance:
45 best_filename = entry_filename
46 best_distance = distance
47 return best_filename
48
49 def ok_compilation_info(info):
50 return bool(info.compiler_flags_)
51
52 def get_compilation_info_for_file(dbpath, database, filename):
53 info = database.GetCompilationInfoForFile(filename)
54 if ok_compilation_info(info):
55 logging.info("Flags for file where found in database: " + filename)
56 return info
57 else:
58 logging.info("Flags for file not found in database: " + filename)
59 basename = os.path.splitext(filename)[0]
60 for extension in SOURCE_EXTENSIONS:
61 replacement_file = basename + extension
62 logging.info("Trying to replace extension with: " + extension)
63 info = database.GetCompilationInfoForFile(replacement_file)
64 if ok_compilation_info(info):
65 logging.info("Replacing header with: " + replacement_file)
66 return info
67 replacement_file = find_similar_file_in_database(dbpath, filename)
68 logging.info("Replacing header with: " + replacement_file)
69 return database.GetCompilationInfoForFile(replacement_file)
70
71 def find_nearest(path, target):
72 candidates = [
73 os.path.join(path, target),
74 os.path.join(path, 'build', target),
75 os.path.join(path, 'output', target),
76 ]
77 for candidate in candidates:
78 if os.path.isfile(candidate) or os.path.isdir(candidate):
79 logging.info("Found nearest " + target + " at " + candidate)
80 return candidate
81 parent = os.path.dirname(os.path.abspath(path))
82 if parent == path:
83 raise RuntimeError("Could not find " + target)
84 return find_nearest(parent, target)
85
86 def make_relative_paths_in_flags_absolute(flags, working_directory):
87 if not working_directory:
88 return list(flags)
89 new_flags = []
90 make_next_absolute = False
91 path_flags = [ '-isystem', '-I', '-iquote', '--sysroot=' ]
92 for flag in flags:
93 new_flag = flag
94 if make_next_absolute:
95 make_next_absolute = False
96 if not flag.startswith('/'):
97 new_flag = os.path.join(working_directory, flag)
98 for path_flag in path_flags:
99 if flag == path_flag:
100 make_next_absolute = True
101 break
102 if flag.startswith(path_flag):
103 path = flag[ len(path_flag): ]
104 new_flag = path_flag + os.path.join(working_directory, path)
105 break
106 if new_flag:
107 new_flags.append(new_flag)
108 return new_flags
109
110 def flags_for_clang_complete(root):
111 try:
112 clang_complete_path = find_nearest(root, '.clang_complete')
113 clang_complete_flags = open(clang_complete_path, 'r').read().splitlines()
114 return clang_complete_flags
115 except Exception, err:
116 logging.info("Error while looking flags for .clang_complete in root: " + root)
117 logging.error(err)
118 return None
119
120 def flags_for_include(root):
121 try:
122 include_path = find_nearest(root, 'include')
123 flags = []
124 for dirroot, dirnames, filenames in os.walk(include_path):
125 for dir_path in dirnames:
126 real_path = os.path.join(dirroot, dir_path)
127 flags = flags + ["-I" + real_path]
128 return flags
129 except Exception, err:
130 logging.info("Error while looking flags for includes in root: " + root)
131 logging.error(err)
132 return None
133
134 def flags_for_compilation_database(root, filename):
135 try:
136 compilation_db_path = find_nearest(root, 'compile_commands.json')
137 compilation_db_dir = os.path.dirname(compilation_db_path)
138 logging.info("Set compilation database directory to " + compilation_db_dir)
139 compilation_db = ycm_core.CompilationDatabase(compilation_db_dir)
140 if not compilation_db:
141 logging.info("Compilation database file found but unable to load")
142 return None
143 compilation_info = get_compilation_info_for_file(
144 compilation_db_path, compilation_db, filename)
145 if not compilation_info:
146 logging.info("No compilation info for " + filename + " in compilation database")
147 return None
148 return make_relative_paths_in_flags_absolute(
149 compilation_info.compiler_flags_,
150 compilation_info.compiler_working_dir_)
151 except Exception, err:
152 logging.info("Error while trying to get flags for " + filename + " in compilation database")
153 logging.error(err)
154 return None
155
156 def flags_for_file(filename):
157 root = os.path.realpath(filename)
158 compilation_db_flags = flags_for_compilation_database(root, filename)
159 if compilation_db_flags:
160 final_flags = compilation_db_flags
161 else:
162 final_flags = BASE_FLAGS
163 clang_flags = flags_for_clang_complete(root)
164 if clang_flags:
165 final_flags = final_flags + clang_flags
166 include_flags = flags_for_include(root)
167 if include_flags:
168 final_flags = final_flags + include_flags
169 return {
170 'flags': final_flags,
171 'do_cache': True
172 }
173
174 FlagsForFile = flags_for_file