diff options
author | Zeno Albisser <zeno.albisser@digia.com> | 2013-08-15 21:46:11 +0200 |
---|---|---|
committer | Zeno Albisser <zeno.albisser@digia.com> | 2013-08-15 21:46:11 +0200 |
commit | 679147eead574d186ebf3069647b4c23e8ccace6 (patch) | |
tree | fc247a0ac8ff119f7c8550879ebb6d3dd8d1ff69 /chromium/tools/vim | |
download | qtwebengine-chromium-679147eead574d186ebf3069647b4c23e8ccace6.tar.gz |
Initial import.
Diffstat (limited to 'chromium/tools/vim')
-rw-r--r-- | chromium/tools/vim/chromium.ycm_extra_conf.py | 203 | ||||
-rw-r--r-- | chromium/tools/vim/filetypes.vim | 9 | ||||
-rw-r--r-- | chromium/tools/vim/ninja-build.vim | 129 |
3 files changed, 341 insertions, 0 deletions
diff --git a/chromium/tools/vim/chromium.ycm_extra_conf.py b/chromium/tools/vim/chromium.ycm_extra_conf.py new file mode 100644 index 00000000000..ac9582d0b1c --- /dev/null +++ b/chromium/tools/vim/chromium.ycm_extra_conf.py @@ -0,0 +1,203 @@ +# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# 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 = [ +'-DUSE_CLANG_COMPLETER', +'-std=c++11', +'-x', +'c++', +] + + +def PathExists(*args): + return os.path.exists(os.path.join(*args)) + + +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 (PathExists(curdir, 'src') and PathExists(curdir, 'src', 'DEPS') + and (PathExists(curdir, '.gclient') + or PathExists(curdir, 'src', '.git'))): + nextdir = os.path.normpath(os.path.join(curdir, '..')) + if nextdir == curdir: + return None + curdir = nextdir + return os.path.join(curdir, 'src') + + +# Largely copied from ninja-build.vim (guess_configuration) +def GetNinjaOutputDirectory(chrome_root): + """Returns either <chrome_root>/out/Release or <chrome_root>/out/Debug. + + The configuration chosen is the one most recently generated/built.""" + root = os.path.join(chrome_root, 'out') + debug_path = os.path.join(root, 'Debug') + release_path = os.path.join(root, 'Release') + + def is_release_15s_newer(test_path): + try: + debug_mtime = os.path.getmtime(os.path.join(debug_path, test_path)) + except os.error: + debug_mtime = 0 + try: + rel_mtime = os.path.getmtime(os.path.join(release_path, test_path)) + except os.error: + rel_mtime = 0 + return rel_mtime - debug_mtime >= 15 + + if is_release_15s_newer('build.ninja') or is_release_15s_newer('protoc'): + return release_path + return debug_path + + +def GetClangCommandFromNinjaForFilename(chrome_root, filename): + """Returns the command line to build |filename|. + + Asks ninja how it would build the source file. If the specified file is a + header, tries to find its companion source file first. + + 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 [] + + # Generally, everyone benefits from including Chromium's src/, because all of + # Chromium's includes are relative to that. + chrome_flags = ['-I' + os.path.join(chrome_root)] + + # Header files can't be built. Instead, try to match a header file to its + # corresponding source file. + if filename.endswith('.h'): + alternates = ['.cc', '.cpp'] + for alt_extension in alternates: + alt_name = filename[:-2] + alt_extension + if os.path.exists(alt_name): + filename = alt_name + break + else: + # If this is a standalone .h file with no source, the best we can do is + # try to use the default flags. + return chrome_flags + + # 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) + + out_dir = GetNinjaOutputDirectory(chrome_root) + + # Ask ninja how it would build our source file. + p = subprocess.Popen(['ninja', '-v', '-C', out_dir, '-t', + 'commands', rel_filename + '^'], + stdout=subprocess.PIPE) + stdout, stderr = p.communicate() + if p.returncode: + return chrome_flags + + # 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 'clang' in line: + clang_line = line + break + else: + return chrome_flags + + # Parse out the -I and -D flags. These seem to be the only ones that are + # important for YCM's purposes. + 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(out_dir, flag[2:])) + chrome_flags.append('-I' + abs_path) + elif flag.startswith('-') and flag[1] in 'DWFfmO': + if flag == '-Wno-deprecated-register' or flag == '-Wno-header-guard': + # These flags causes libclang (3.3) to crash. Remove it until things + # are fixed. + continue + chrome_flags.append(flag) + + 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 + } diff --git a/chromium/tools/vim/filetypes.vim b/chromium/tools/vim/filetypes.vim new file mode 100644 index 00000000000..3e7c8f9eada --- /dev/null +++ b/chromium/tools/vim/filetypes.vim @@ -0,0 +1,9 @@ +" To get syntax highlighting and tab settings for gyp(i) and DEPS files, +" add the following to your .vimrc file: +" so /path/to/src/tools/vim/filetypes.vim + +augroup filetype + au! BufRead,BufNewFile *.gyp set filetype=python expandtab tabstop=2 shiftwidth=2 + au! BufRead,BufNewFile *.gypi set filetype=python expandtab tabstop=2 shiftwidth=2 + au! BufRead,BufNewFile DEPS set filetype=python expandtab tabstop=2 shiftwidth=2 +augroup END diff --git a/chromium/tools/vim/ninja-build.vim b/chromium/tools/vim/ninja-build.vim new file mode 100644 index 00000000000..f8b74191d82 --- /dev/null +++ b/chromium/tools/vim/ninja-build.vim @@ -0,0 +1,129 @@ +" Copyright (c) 2012 The Chromium Authors. All rights reserved. +" Use of this source code is governed by a BSD-style license that can be +" found in the LICENSE file. +" +" Adds a "Compile this file" function, using ninja. On Mac, binds Cmd-k to +" this command. On Windows, Ctrl-F7 (which is the same as the VS default). +" On Linux, <Leader>o, which is \o by default ("o"=creates .o files) +" +" Adds a "Build this target" function, using ninja. This is not bound +" to any key by default, but can be used via the :CrBuild command. +" It builds 'chrome' by default, but :CrBuild target1 target2 etc works as well. +" +" Requires that gyp has already generated build.ninja files, and that ninja is +" in your path (which it is automatically if depot_tools is in your path). +" +" Add the following to your .vimrc file: +" so /path/to/src/tools/vim/ninja-build.vim + +python << endpython +import os +import vim + + +def path_to_current_buffer(): + """Returns the absolute path of the current buffer.""" + return vim.current.buffer.name + + +def path_to_source_root(): + """Returns the absolute path to the chromium source root.""" + candidate = os.path.dirname(path_to_current_buffer()) + # This is a list of files that need to identify the src directory. The shorter + # it is, the more likely it's wrong (checking for just "build/common.gypi" + # would find "src/v8" for files below "src/v8", as "src/v8/build/common.gypi" + # exists). The longer it is, the more likely it is to break when we rename + # directories. + fingerprints = ['chrome', 'net', 'v8', 'build', 'skia'] + while candidate and not all( + [os.path.isdir(os.path.join(candidate, fp)) for fp in fingerprints]): + candidate = os.path.dirname(candidate) + return candidate + + +def guess_configuration(): + """Default to the configuration with either a newer build.ninja or a newer + protoc.""" + root = os.path.join(path_to_source_root(), 'out') + def is_release_15s_newer(test_path): + try: + debug_mtime = os.path.getmtime(os.path.join(root, 'Debug', test_path)) + except os.error: + debug_mtime = 0 + try: + rel_mtime = os.path.getmtime(os.path.join(root, 'Release', test_path)) + except os.error: + rel_mtime = 0 + return rel_mtime - debug_mtime >= 15 + configuration = 'Debug' + if is_release_15s_newer('build.ninja') or is_release_15s_newer('protoc'): + configuration = 'Release' + return configuration + + +def compute_ninja_command_for_current_buffer(configuration=None): + """Returns the shell command to compile the file in the current buffer.""" + if not configuration: configuration = guess_configuration() + build_dir = os.path.join(path_to_source_root(), 'out', configuration) + + # ninja needs filepaths for the ^ syntax to be relative to the + # build directory. + file_to_build = path_to_current_buffer() + file_to_build = os.path.relpath(file_to_build, build_dir) + + build_cmd = ' '.join(['ninja', '-C', build_dir, file_to_build + '^']) + if sys.platform == 'win32': + # Escape \ for Vim, and ^ for both Vim and shell. + build_cmd = build_cmd.replace('\\', '\\\\').replace('^', '^^^^') + vim.command('return "%s"' % build_cmd) + + +def compute_ninja_command_for_targets(targets='', configuration=None): + if not configuration: configuration = guess_configuration() + build_dir = os.path.join(path_to_source_root(), 'out', configuration) + build_cmd = ' '.join(['ninja', '-C', build_dir, targets]) + vim.command('return "%s"' % build_cmd) +endpython + +fun! s:MakeWithCustomCommand(build_cmd) + let l:oldmakepgr = &makeprg + let &makeprg=a:build_cmd + silent make | cwindow + if !has('gui_running') + redraw! + endif + let &makeprg = l:oldmakepgr +endfun + +fun! s:NinjaCommandForCurrentBuffer() + python compute_ninja_command_for_current_buffer() +endfun + +fun! s:NinjaCommandForTargets(targets) + python compute_ninja_command_for_targets(vim.eval('a:targets')) +endfun + +fun! CrCompileFile() + call s:MakeWithCustomCommand(s:NinjaCommandForCurrentBuffer()) +endfun + +fun! CrBuild(...) + let l:targets = a:0 > 0 ? join(a:000, ' ') : '' + if (l:targets !~ "\i") + let l:targets = 'chrome' + endif + call s:MakeWithCustomCommand(s:NinjaCommandForTargets(l:targets)) +endfun + +command! CrCompileFile call CrCompileFile() +command! -nargs=* CrBuild call CrBuild(<q-args>) + +if has('mac') + map <D-k> :CrCompileFile<cr> + imap <D-k> <esc>:CrCompileFile<cr> +elseif has('win32') + map <C-F7> :CrCompileFile<cr> + imap <C-F7> <esc>:CrCompileFile<cr> +elseif has('unix') + map <Leader>o :CrCompileFile<cr> +endif |