forked from kythe/kythe
-
Notifications
You must be signed in to change notification settings - Fork 0
/
.ycm_extra_conf.py
133 lines (110 loc) · 3.86 KB
/
.ycm_extra_conf.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#!/usr/bin/python3
# Copyright 2017 Google Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
# This .ycm_extra_conf will be picked up automatically for code completion using
# YouCompleteMe.
#
# See https://valloric.github.io/YouCompleteMe/ for instructions on setting up
# YouCompleteMe using Vim. This .ycm_extra_conf file also works with any other
# completion engine that uses YCMD (https://github.com/Valloric/ycmd).
#
# Code completion uses `bazel print_action` for the file and pulls out the
# included command line flags.
# ==============================================================================
import logging
import os
import pathlib
import re
import subprocess
BAZEL_PRINT_FLAGS = [
# Run bazel.
'bazel',
# Dump the text proto action on STDOUT.
'print_action',
# Be quiet.
'--noshow_progress',
'--noshow_loading_progress',
'--show_result=0',
# Don't build anything and keep going.
'--nobuild',
'--keep_going',
'--workspace_status_command=/bin/true',
# Execute a single arbitrary action for the file.
'--compile_one_dependency',
]
FLAG_PATTERN = re.compile(r'^\s+compiler_option: "([^"]*)"')
# Workspace path.
WORKSPACE_PATH = None
# Execution root.
EXECUTION_ROOT = None
def InitBazelConfig():
"""Initialize globals based on Bazel configuration.
Initialize COMPILATION_DATABASE_PATH, WORKSPACE_PATH, and
CANONICAL_SOURCE_FILE based on Bazel. These values are not expected to change
during the session.
"""
global WORKSPACE_PATH
global EXECUTION_ROOT
EXECUTION_ROOT = pathlib.Path(
os.fsdecode(
subprocess.check_output(['bazel', 'info', 'execution_root']).strip()))
WORKSPACE_PATH = pathlib.Path(
os.fsdecode(
subprocess.check_output(['bazel', 'info', 'workspace']).strip()))
def ExpandAndNormalizePath(filepath, basepath=None):
"""Resolves |filepath| relative to |basepath| and expands symlinks."""
if basepath is None:
basepath = WORKSPACE_PATH
if not filepath.is_absolute() and basepath:
filepath = basepath.joinpath(filepath)
return filepath.resolve()
def RelativePath(filename, root=None):
"""Resolves |filename| and returns a path relative to |root| if possible."""
if root is None:
root = WORKSPACE_PATH
path = ExpandAndNormalizePath(filename, basepath=root)
try:
return path.relative_to(root)
except ValueError:
return path
# Entrypoint for YouCompleteMe.
def Settings(**kwargs):
if kwargs['language'] != 'cfamily':
return {}
if EXECUTION_ROOT is None:
InitBazelConfig()
filename = RelativePath(pathlib.Path(kwargs.pop('filename')))
logging.info('Calling bazel print_action for %s', filename)
try:
action = subprocess.check_output(
BAZEL_PRINT_FLAGS + [str(filename)], stderr=subprocess.STDOUT).decode()
except subprocess.CalledProcessError as err:
logging.error('Error calling bazel %s (%s)', err, err.output)
return {}
flags = [
FLAG_PATTERN.match(line).group(1)
for line in action.split('\n')
if FLAG_PATTERN.match(line)
]
logging.info('Found flags %s', flags)
return {
# Always indicate C++.
'flags': ['-x', 'c++'] + flags,
'include_paths_relative_to_dir': EXECUTION_ROOT,
}
# For testing.
if __name__ == '__main__':
import sys
print(Settings(filename=sys.argv[1]))