1 # https://github.com/Valloric/ycmd/blob/master/cpp/ycm/.ycm_extra_conf.py
2 # https://jonasdevlieghere.com/a-better-youcompleteme-config/
3 # https://github.com/arximboldi/dotfiles/blob/master/emacs/.ycm_extra_conf.py
12 # flags used when no compilation_db is found
18 # flags are always added
24 '-Wno-c++98-compat-pedantic',
29 # '-Wno-variadic-macros',
44 def generate_qt_flags():
45 flags
= ['-isystem', '/usr/include/qt/']
46 for p
in glob('/usr/include/qt/*/'):
47 flags
+= ['-isystem', p
]
51 def similarity_ratio(s
, t
):
52 return difflib
.SequenceMatcher(a
=s
.lower(), b
=t
.lower()).ratio()
55 def find_similar_file_in_database(dbpath
, filename
):
57 logging
.info("Trying to find some file close to: " + filename
)
58 db
= json
.load(open(dbpath
+ "/compile_commands.json"))
63 entry_filename
= os
.path
.normpath(os
.path
.join(entry
["directory"],
66 if filename
== entry_filename
:
67 logging
.info("Found exact match: " + entry_filename
)
70 basename
= os
.path
.splitext(filename
)[0]
71 for extension
in SOURCE_EXTENSIONS
:
72 replacement_file
= basename
+ extension
73 if entry_filename
== replacement_file
:
74 logging
.info("Found match: " + replacement_file
)
77 ratio
= similarity_ratio(str(filename
), str(entry_filename
))
78 if ratio
> best_ratio
:
79 best_filename
= entry_filename
82 logging
.info("Found closest match: " + best_filename
)
86 def find_nearest_compilation_database(root
='.'):
87 dirs
= glob(root
+ '/*/compile_commands.json', recursive
=True)
92 logging
.info("Multiple compilation databases found!")
94 dirs
.sort(key
=lambda x
: os
.stat(x
).st_mtime
, reverse
=True)
95 logging
.info("Selecting newest: %s" % (dirs
[0]))
98 parent
= os
.path
.dirname(os
.path
.abspath(root
))
100 raise RuntimeError("Could not find compile_commands.json")
101 return find_nearest_compilation_database(parent
)
104 def find_nearest(path
, target
):
106 os
.path
.join(path
, target
),
107 os
.path
.join(path
, 'build', target
),
108 os
.path
.join(path
, 'output', target
),
110 for candidate
in candidates
:
111 if os
.path
.isfile(candidate
) or os
.path
.isdir(candidate
):
112 logging
.info("Found nearest " + target
+ " at " + candidate
)
114 parent
= os
.path
.dirname(os
.path
.abspath(path
))
116 raise RuntimeError("Could not find " + target
)
117 return find_nearest(parent
, target
)
120 def flags_for_include(root
):
122 include_path
= find_nearest(root
, 'include')
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
]
129 except Exception as err
:
130 logging
.info("Error while looking flags for includes in root: " + root
)
135 def get_compilation_database(root
):
137 compilation_db_path
= find_nearest_compilation_database(root
)
138 compilation_db_dir
= os
.path
.dirname(compilation_db_path
)
139 logging
.info("Set compilation database directory to " + compilation_db_dir
)
140 db
= ycm_core
.CompilationDatabase(compilation_db_dir
)
142 logging
.info("Compilation database file found but unable to load")
145 except Exception as err
:
146 logging
.info("Error while trying to find compilation database: " + root
)
151 def Settings(**kwargs
):
152 if kwargs
['language'] != 'cfamily':
156 client_data
= kwargs
['client_data']
157 root
= client_data
.get('getcwd()', '.')
158 filename
= kwargs
['filename']
160 database
= get_compilation_database(root
)
162 filename
= find_similar_file_in_database(database
.database_directory
,
164 compilation_info
= database
.GetCompilationInfoForFile(filename
)
165 print(compilation_info
)
166 if not compilation_info
.compiler_flags_
:
167 return {} #TODO use default flags
168 final_flags
= list(compilation_info
.compiler_flags_
)
169 include_path_relative_to_dir
= compilation_info
.compiler_working_dir_
171 final_flags
= BASE_FLAGS
172 include_flags
= flags_for_include(root
)
174 final_flags
+= include_flags
175 final_flags
+= generate_qt_flags()
176 final_flags
+= ['-I', root
,
177 '-I', root
+ '/include']
178 include_path_relative_to_dir
= root
181 'flags': final_flags
+ EXTRA_FLAGS
,
182 'include_paths_relative_to_dir': include_path_relative_to_dir
,
183 'override_filename': filename
,