第一次据说这个插件仍是在偶然的状况下看到别人的博客,据说了这个插件的大名。原本打算在实训期间来完成安装的,无奈网实在不给力,也就拖到了回家的时候。在开始准备工做的时候就了解到这个插件不是很容易安装,安装的时候果真名不虚传。(关于这方面的内容,请查看另外一篇文章)不过,有付出总有回报,安装以后用上这个插件,真心为这个插件的强大所折服。javascript
那这个插件有何不一样?php
总所周知,Vim
是一款文本编辑器。也就是说,其最基础的工做就是编辑文本,而无论该文本的内容是什么。在Vim
被程序员所使用后,其慢慢的被肩负了与IDE同样的工做,文本自动补全(ie.acp
,omnicppcompleter
),代码检查(Syntastic
)等等工做。html
针对文本自动补全这个功能来讲,主要有两种实现方式。java
咱们经常使用的omnicppcompleter
,acp
,vim自带的c-x, c-n
的实现方式就是基于文本。更通俗的说法,其实就是一个字:python
其经过文本进行一些正则表达式的匹配,再根据生成的tags(利用ctags
生成)来实现自动补全的效果。c++
顾名思义,其是经过分析源文件,通过语法分析之后进行补全。因为对源文件进行分析,基于语义的补全能够作到很精确。可是这显然是vim所不可能支持的。并且通过这么多年发展,因为语法分析有很高的难度,也一直没有合适的工具出现。直到,由apple支持的clang/llvm
横空出世。YouCompleteMe
也正是在clang/llvm
的基础上进行构建的。git
对于其余的语言,会调用vim设置的omnifunc
来匹配,所以一样支持php
,ruby
等语言。程序员
已知的有 * javascript —-tern_for_vim * ruby/java —-eclimgithub
include
的文件进行补全:w
进行强制检测说完了那么多好处,就要说到安装了。不一样于以往其余vim插件,YCM是一款编译型的插件。在下载完后,须要手动编译后才能使用。对应其余的插件来讲,仅仅就是把.vim的文件丢到相应文件夹下就能够。而这也加大了使用YCM的难度。正则表达式
vim --version
查看)brew install cmake
,ubuntu能够经过sudo apt-get install cmake
)在.vimrc
中添加下列代码
Bundle 'Valloric/YouCompleteMe'
保存退出后打开vim,在正常模式下输入
BundleInstall
等待vundle
将YouCompleteMe安装完成
然后进行编译安装:
cd ~/.vim/bundle/YouCompleteMe
./install --clang-completer
若是不须要c-family的补全,能够去掉--clang-completer。
若是须要c#
的补全,请加上--omnisharp-completer。
正常来讲,YCM会去下载clang的包,若是已经有,也能够用系统--system-libclang。
就这样,安装结束。打开vim,若是没有提示YCM未编译,则说明安装已经成功了。
安装的脚本并非何时都好用,至少对我来讲是这样的。安装完以后出现了问题,参考issue#809。
在用:BundleInstall
安装完成或者使用
git clone --recursive https://github.com/Valloric/YouCompleteMe.git
获取最新的仓库,然后使用git submodule update --init --recursive
确认仓库的完整性后,开始安装流程。
clang
版本 > 3.2,通常来讲都是下载最新的。sudo apt-get install python-dev
,mac下默认提供,不然请安装command line tools)1 cd ~
2 mkdir ycm_build 3 cd ycm_build 4 cmake -G “Unix Makefiles” -DPATH_TO_LLVM_ROOT=~/ycm_temp/llvm_root_dir . ~/.vim/bundle/YouCompleteMe/cpp make ycm_support_libs
这里须要注意的是,~/ycm_temp/llvm_root_dir中包含的是根据第一步下载的压缩包解压出来的内容(包括include
, bin
等等文件)。
这样就完成了,开始感觉YCM提供的彻底不逊色于大型IDE所提供的自动补全功能吧。
不一样于不少vim插件,YCM首先须要编译,另外还须要有配置。在vim启动后,YCM会找寻当前路径以及上层路径的.ycm_extra_conf.py
.在~/.vim/bundle/YouCompleteMe/cpp/ycm/.ycm_extra_conf.py
中提供了默认的模板。也能够参考个人(就在模板上改改而已)。不过这个解决了标准库提示找不到的问题。
通常来讲,我会在~
目录下放一个默认的模板,然后再根据不一样的项目在当前目录下再拷贝个.ycm_extra_conf.py。
1 # This file is NOT licensed under the GPLv3, which is the license for the rest 2 # of YouCompleteMe. 3 # 4 # Here's the license text for this file: 5 # 6 # This is free and unencumbered software released into the public domain. 7 # 8 # Anyone is free to copy, modify, publish, use, compile, sell, or 9 # distribute this software, either in source code form or as a compiled 10 # binary, for any purpose, commercial or non-commercial, and by any 11 # means. 12 # 13 # In jurisdictions that recognize copyright laws, the author or authors 14 # of this software dedicate any and all copyright interest in the 15 # software to the public domain. We make this dedication for the benefit 16 # of the public at large and to the detriment of our heirs and 17 # successors. We intend this dedication to be an overt act of 18 # relinquishment in perpetuity of all present and future rights to this 19 # software under copyright law. 20 # 21 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 22 # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 23 # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 24 # IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 25 # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 26 # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 27 # OTHER DEALINGS IN THE SOFTWARE. 28 # 29 # For more information, please refer to <http://unlicense.org/> 30 31 import os 32 import ycm_core 33 34 # These are the compilation flags that will be used in case there's no 35 # compilation database set (by default, one is not set). 36 # CHANGE THIS LIST OF FLAGS. YES, THIS IS THE DROID YOU HAVE BEEN LOOKING FOR. 37 flags = [ 38 '-Wall', 39 '-Wextra', 40 #'-Werror', 41 #'-Wc++98-compat', 42 '-Wno-long-long', 43 '-Wno-variadic-macros', 44 '-fexceptions', 45 '-stdlib=libc++', 46 # THIS IS IMPORTANT! Without a "-std=<something>" flag, clang won't know which 47 # language to use when compiling headers. So it will guess. Badly. So C++ 48 # headers will be compiled as C headers. You don't want that so ALWAYS specify 49 # a "-std=<something>". 50 # For a C project, you would set this to something like 'c99' instead of 51 # 'c++11'. 52 '-std=c++11', 53 # ...and the same thing goes for the magic -x option which specifies the 54 # language that the files to be compiled are written in. This is mostly 55 # relevant for c++ headers. 56 # For a C project, you would set this to 'c' instead of 'c++'. 57 '-x', 58 'c++', 59 '-I', 60 '.', 61 '-isystem', 62 '/usr/include', 63 '-isystem', 64 '/usr/local/include', 65 '-isystem', 66 '/Library/Developer/CommandLineTools/usr/include', 67 '-isystem', 68 '/Library/Developer/CommandLineTools/usr/bin/../lib/c++/v1', 69 ] 70 71 # Set this to the absolute path to the folder (NOT the file!) containing the 72 # compile_commands.json file to use that instead of 'flags'. See here for 73 # more details: http://clang.llvm.org/docs/JSONCompilationDatabase.html 74 # 75 # Most projects will NOT need to set this to anything; you can just change the 76 # 'flags' list of compilation flags. Notice that YCM itself uses that approach. 77 compilation_database_folder = '' 78 79 if os.path.exists( compilation_database_folder ): 80 database = ycm_core.CompilationDatabase( compilation_database_folder ) 81 else: 82 database = None 83 84 SOURCE_EXTENSIONS = [ '.cpp', '.cxx', '.cc', '.c', '.m', '.mm' ] 85 86 def DirectoryOfThisScript(): 87 return os.path.dirname( os.path.abspath( __file__ ) ) 88 89 def MakeRelativePathsInFlagsAbsolute( flags, working_directory ): 90 if not working_directory: 91 return list( flags ) 92 new_flags = [] 93 make_next_absolute = False 94 path_flags = [ '-isystem', '-I', '-iquote', '--sysroot=' ] 95 for flag in flags: 96 new_flag = flag 97 98 if make_next_absolute: 99 make_next_absolute = False 100 if not flag.startswith( '/' ): 101 new_flag = os.path.join( working_directory, flag ) 102 103 for path_flag in path_flags: 104 if flag == path_flag: 105 make_next_absolute = True 106 break 107 108 if flag.startswith( path_flag ): 109 path = flag[ len( path_flag ): ] 110 new_flag = path_flag + os.path.join( working_directory, path ) 111 break 112 113 if new_flag: 114 new_flags.append( new_flag ) 115 return new_flags 116 117 def IsHeaderFile( filename ): 118 extension = os.path.splitext( filename )[ 1 ] 119 return extension in [ '.h', '.hxx', '.hpp', '.hh' ] 120 121 def GetCompilationInfoForFile( filename ): 122 # The compilation_commands.json file generated by CMake does not have entries 123 # for header files. So we do our best by asking the db for flags for a 124 # corresponding source file, if any. If one exists, the flags for that file 125 # should be good enough. 126 if IsHeaderFile( filename ): 127 basename = os.path.splitext( filename )[ 0 ] 128 for extension in SOURCE_EXTENSIONS: 129 replacement_file = basename + extension 130 if os.path.exists( replacement_file ): 131 compilation_info = database.GetCompilationInfoForFile( 132 replacement_file ) 133 if compilation_info.compiler_flags_: 134 return compilation_info 135 return None 136 return database.GetCompilationInfoForFile( filename ) 137 138 def FlagsForFile( filename, **kwargs ): 139 if database: 140 # Bear in mind that compilation_info.compiler_flags_ does NOT return a 141 # python list, but a "list-like" StringVec object 142 compilation_info = GetCompilationInfoForFile( filename ) 143 if not compilation_info: 144 return None 145 146 final_flags = MakeRelativePathsInFlagsAbsolute( 147 compilation_info.compiler_flags_, 148 compilation_info.compiler_working_dir_ ) 149 150 # NOTE: This is just for YouCompleteMe; it's highly likely that your project 151 # does NOT need to remove the stdlib flag. DO NOT USE THIS IN YOUR 152 # ycm_extra_conf IF YOU'RE NOT 100% SURE YOU NEED IT. 153 #try: 154 # final_flags.remove( '-stdlib=libc++' ) 155 #except ValueError: 156 # pass 157 else: 158 relative_to = DirectoryOfThisScript() 159 final_flags = MakeRelativePathsInFlagsAbsolute( flags, relative_to ) 160 161 return { 162 'flags': final_flags, 163 'do_cache': True 164 }
YCM除了提供了基本的补全功能,自动提示错误的功能外,还提供了相似tags的功能:
GoToDefinition
GoToDeclaration
GoToDefinitionElseDeclaration
能够在.vimrc中配置相应的快捷键。
1 nnoremap <leader>gl :YcmCompleter GoToDeclaration<CR>
2 nnoremap <leader>gf :YcmCompleter GoToDefinition<CR> 3 nnoremap <leader>gg :YcmCompleter GoToDefinitionElseDeclaration<CR>
另外,YCM也提供了丰富的配置选项,一样在.vimrc中配置。具体请参考
1 let g:ycm_error_symbol = '>>' 2 let g:ycm_warning_symbol = '>*'
同时,YCM能够打开location-list来显示警告和错误的信息:YcmDiags。
我的关于ycm的配置以下:
1 " for ycm 2 let g:ycm_error_symbol = '>>' 3 let g:ycm_warning_symbol = '>*' 4 nnoremap <leader>gl :YcmCompleter GoToDeclaration<CR> 5 nnoremap <leader>gf :YcmCompleter GoToDefinition<CR> 6 nnoremap <leader>gg :YcmCompleter GoToDefinitionElseDeclaration<CR> 7 nmap <F4> :YcmDiags<CR>
YCM提供的跳跃功能采用了vim的jumplist,
往前跳和日后跳的快捷键为Ctrl+O
以及Ctrl+I。
YouCompleteMe
是我用过的最爽的一个自动补全的插件了。以前使用acp时,遇到大文件基本上就卡死了,以致于都不怎么敢使用。因为YCM使用的时C/S结构,部分使用vim脚本编写,部分认为原生代码,使得跑起来速度飞快。
抛弃Vim自带的坑爹的补全吧,抛弃ctags
吧,抛弃cscope
吧,YCM才是终极的补全神器。
在安装过程当中,我也遇到了很多的坑。一会会发一篇解决这些坑的文章。
最后祝你们码年顺利,一码平川,码到功成。