Chromium Code Reviews| Index: tools/vim/chromium.ycm_extra_conf.py |
| diff --git a/tools/vim/chromium.ycm_extra_conf.py b/tools/vim/chromium.ycm_extra_conf.py |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..18b7dc3ddb3277381d340db781bc4f85060376e1 |
| --- /dev/null |
| +++ b/tools/vim/chromium.ycm_extra_conf.py |
| @@ -0,0 +1,157 @@ |
| +# Autocompletion config for YouCompleteMe in Chromium. |
| +# |
| +# USAGE: |
| +# |
| +# 1. Install YCM [https://github.com/Valloric/YouCompleteMe] |
| +# (Googlers should check out [go/ycm]) |
| +# |
| +# 2. Point to this config file in your .vimrc: |
| +# let g:ycm_global_ycm_extra_conf = |
| +# '<chrome_depot>/src/tools/vim/chromium.ycm_extra_conf.py' |
| +# |
| +# 3. Profit |
| +# |
| +# |
| +# Usage notes: |
| +# |
| +# * You must use ninja & clang to build Chromium. |
| +# |
| +# * You must have run gyp_chromium and built Chromium recently. |
| +# |
| +# |
| +# Hacking notes: |
| +# |
| +# * The purpose of this script is to construct an accurate enough command line |
| +# for YCM to pass to clang so it can build and extract the symbols. |
| +# |
| +# * Right now, we only pull the -I and -D flags. That seems to be sufficient |
| +# for everything I've used it for. |
| +# |
| +# * That whole ninja & clang thing? We could support other configs if someone |
| +# were willing to write the correct commands and a parser. |
| +# |
| +# * This has only been tested on gPrecise. |
| + |
| + |
| +import os |
| +import subprocess |
| + |
| +# Flags from YCM's default config. |
| +flags = [ |
| +'-Wall', |
| +'-Wextra', |
| +'-Werror', |
| +'-Wno-long-long', |
| +'-Wno-variadic-macros', |
| +'-Wno-unused-parameter', |
| +'-fexceptions', |
| +'-DNDEBUG', |
| +'-DUSE_CLANG_COMPLETER', |
| +'-std=c++11', |
| +'-x', |
| +'c++', |
| +] |
| + |
| + |
| +def FindChromeSrcFromFilename(filename): |
| + """Searches for the root of the Chromium checkout. |
| + |
| + Simply checks parent directories until it finds .gclient and src/. |
| + |
| + Args: |
| + filename: (String) Path to source file being edited. |
| + |
| + Returns: |
| + (String) Path of 'src/', or None if unable to find. |
| + """ |
| + curdir = os.path.normpath(os.path.dirname(filename)) |
| + while not (os.path.exists(os.path.join(curdir, '.gclient')) |
| + and os.path.exists(os.path.join(curdir, 'src'))): |
| + nextdir = os.path.normpath(os.path.join(curdir, '..')) |
| + if nextdir == curdir: |
| + return None |
| + curdir = nextdir |
| + return os.path.join(curdir, 'src') |
|
Nico
2013/02/05 23:48:50
Something like this is in ninja_build.vim too. May
|
| + |
| + |
| +def GetClangCommandFromNinjaForFilename(chrome_root, filename): |
| + """Returns the command line to build |filename|. |
| + |
| + Figures out where the .o file for this source file will end up. Then asks |
| + ninja how it would build that object and parses the result. |
| + |
| + Args: |
| + chrome_root: (String) Path to src/. |
| + filename: (String) Path to source file being edited. |
| + |
| + Returns: |
| + (List of Strings) Command line arguments for clang. |
| + """ |
| + if not chrome_root: |
| + return [] |
| + |
| + # Ninja needs the path to the source file from the output build directory. |
| + # Cut off the common part and /. |
| + subdir_filename = filename[len(chrome_root)+1:] |
| + rel_filename = os.path.join('..', '..', subdir_filename) |
| + |
| + # Ask ninja how it would build our source file. |
| + p = subprocess.Popen(['ninja', '-v', '-C', chrome_root + '/out/Release', '-t', |
| + 'commands', rel_filename + '^'], |
| + stdout=subprocess.PIPE) |
| + stdout, stderr = p.communicate() |
| + if p.returncode: |
| + return [] |
| + |
| + # Ninja might execute several commands to build something. We want the last |
| + # clang command. |
| + clang_line = None |
| + for line in reversed(stdout.split('\n')): |
| + if line.startswith('clang'): |
| + clang_line = line |
| + break |
| + if not clang_line: |
| + return [] |
| + |
| + # Parse out the -I and -D flags. These seem to be the only ones that are |
| + # important for YCM's purposes. |
| + chrome_flags = [] |
| + for flag in clang_line.split(' '): |
| + if flag.startswith('-I'): |
| + # Relative paths need to be resolved, because they're relative to the |
| + # output dir, not the source. |
| + if flag[2] == '/': |
| + chrome_flags.append(flag) |
| + else: |
| + abs_path = os.path.normpath(os.path.join( |
| + chrome_root, 'out', 'Release', flag[2:])) |
| + chrome_flags.append('-I' + abs_path) |
| + elif flag.startswith('-D'): |
| + chrome_flags.append(flag) |
| + |
| + # Also include Chromium's src/, because all of Chromium's includes are |
| + # relative to that. |
| + chrome_flags.append('-I' + os.path.join(chrome_root)) |
| + return chrome_flags |
| + |
| + |
| +def FlagsForFile(filename): |
| + """This is the main entry point for YCM. Its interface is fixed. |
| + |
| + Args: |
| + filename: (String) Path to source file being edited. |
| + |
| + Returns: |
| + (Dictionary) |
| + 'flags': (List of Strings) Command line flags. |
| + 'do_cache': (Boolean) True if the result should be cached. |
| + """ |
| + chrome_root = FindChromeSrcFromFilename(filename) |
| + chrome_flags = GetClangCommandFromNinjaForFilename(chrome_root, |
| + filename) |
| + final_flags = flags + chrome_flags |
| + |
| + return { |
| + 'flags': final_flags, |
| + 'do_cache': True |
| + } |