vim自動補全

第一次據說這個插件仍是在偶然的狀況下看到別人的博客,據說了這個插件的大名。原本打算在實訓期間來完成安裝的,無奈網實在不給力,也就拖到了回家的時候。在開始準備工做的時候就瞭解到這個插件不是很容易安裝,安裝的時候果真名不虛傳。(關於這方面的內容,請查看另外一篇文章)不過,有付出總有回報,安裝以後用上這個插件,真心爲這個插件的強大所折服。javascript

那這個插件有何不一樣?php

YouCompleteMe的特別之處

基於語義補全

總所周知,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

整合實現了多種插件

  • clang_complete
  • AutoComplPop
  • Supertab
  • neocomplcache
  • Syntastic(相似功能,僅僅針對c/c++/obj-c代碼)

支持語言

  • c
  • c++
  • obj-c
  • c#
  • python

對於其餘的語言,會調用vim設置的omnifunc來匹配,所以一樣支持php,ruby等語言。程序員

已知的有 * javascript —-tern_for_vim * ruby/java —-eclimgithub

使用效果圖

ycmsdfsdgeerg

使用感覺

  • 和IDE同樣,自動補全,
  • 根據include的文件進行補全
  • 不用再蹩腳的生成tags
  • 補全很是精準,並且速度很快,不會有延遲(之前在大項目上,acp用起來實在是很卡)
  • 支持相似tags的跳轉,跳到定義處以及使用處
  • 出錯提示很智能,而且用起來真的是如絲般柔滑,不用輸入:w進行強制檢測

安裝

說完了那麼多好處,就要說到安裝了。不一樣於以往其餘vim插件,YCM是一款編譯型的插件。在下載完後,須要手動編譯後才能使用。對應其餘的插件來講,僅僅就是把.vim的文件丟到相應文件夾下就能夠。而這也加大了使用YCM的難度。正則表達式

安裝準備

  • 最新版的Vim(7.3.584+),編譯時添加+python標誌(已經安裝的能夠經過vim --version查看)
  • cmake(mac能夠經過homebrew安裝,brew install cmake,ubuntu能夠經過sudo apt-get install cmake)
  • 安裝vundle插件,用於安裝管理vim的插件

mac下快速安裝

.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確認倉庫的完整性後,開始安裝流程。

  1. 下載最新的clang二進制文件 YCM要求clang版本 > 3.2,通常來講都是下載最新的
  2. 安裝python-dev.(ubuntu下使用sudo apt-get install python-dev,mac下默認提供,不然請安裝command line tools)
  3. 編譯
    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
    1. 這裏須要注意的是,~/ycm_temp/llvm_root_dir中包含的是根據第一步下載的壓縮包解壓出來的內容(包括includebin等等文件)。

    這樣就完成了,開始感覺YCM提供的徹底不遜色於大型IDE所提供的自動補全功能吧。

    配置

    不一樣於不少vim插件,YCM首先須要編譯,另外還須要有配置。在vim啓動後,YCM會找尋當前路徑以及上層路徑的.ycm_extra_conf.py.在~/.vim/bundle/YouCompleteMe/cpp/ycm/.ycm_extra_conf.py中提供了默認的模板。也能夠參考個人(就在模板上改改而已)。不過這個解決了標準庫提示找不到的問題。

    通常來講,我會在~目錄下放一個默認的模板,然後再根據不一樣的項目在當前目錄下再拷貝個.ycm_extra_conf.py。

  4.   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 }

    YouCompleteMe提供的其餘功能

    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纔是終極補全神器。

    在安裝過程當中,我也遇到了很多的坑。一會會發一篇解決這些坑的文章。

    最後祝你們碼年順利,一碼平川,碼到功成。

相關文章
相關標籤/搜索