vim 自動提示、自動補齊外掛 YouCompleteMe for windows Gvim 安裝及使用效果
YouCompleteMe is a fast, as-you-type, fuzzy-search(親~~支援模糊匹配哦) code completion engine for Vim. It has two completion engines: an identifier-based engine that works with every programming language and a semantic, Clang-based engine that provides semantic code completion for C/C++/Objective-C/Objective-C++ (from now on referred to as “the C-family languages”).
特色:
Auto-triggers as you type. 自動觸發,鍵入即提示,無需快捷鍵(對C函式的補全需要快捷鍵)
Uses subsequence-based completion filtering.(模糊匹配)
Uses smart heuristics to intelligently rank whatever candidates survive the filtering step.(詞頻調整的策略)
Offers semantic completions.(語法層面的補全)
Fast, fast, fast!(號稱比clang那個外掛更快)
另外,這個外掛還支援跳轉到函式、變數的定義處
YouCompleteMe 外掛官方網站 http://val.markovic.io/blog/youcompleteme-a-fast-as-you-type-fuzzy-search-code-completion-engine-for-vim
github地址 https://github.com/Valloric/YouCompleteMe
效果演示
實際使用效果圖1,來自官網
至今為止,其官方網站還沒有說支援windows(mac和linux環境下都可以直接下載編譯使用),但已經被別人在windows下搞定並使用了。我安裝的過程也是參照老外的文章,直接下載老外編譯好的檔案並下載配置各種環境,花了一天才搞定的。
搞定之後試用了一下效果確實很不錯,支援語義級別的自動補齊,無論是c++的stl庫,還是普通的C函式,還是自己定義的結構體,類,都可以實時識別。
支援類中的成員變數:
支援C++ stl庫
支援系統函式
並且再加上syntastic外掛,就連你出錯的語法、寫錯的變數都可以給你提示出來。
安裝 YouCompleteMe for Windows
請注意:我安裝在的vim版本是7.4,官方是說要7.3以上的版本。
首先根據這個帖子回覆的地址,去下載YouCompleteMe for Windows外掛、 LLVM for Windows。
這個都是別人在windows上編譯好的,兩者是配套的,如果不用這個版本的外掛而用官方最新版的會匹配不上,功能用不了。
下載上面的兩個包,前者放到vim的外掛目錄或者vundle目錄下(我是用vim bundle下載了最新的YouCompleteMe外掛然後用上面這個版本替換的),後者(LLVM)只需要裡面的libclang.dll檔案,把libclang.dll檔案放到YouCompleteMe目錄下的python資料夾中(和ycm_core.pyd檔案一起)。
然後要保證你的機器上安裝了python2.7(我試了python2.6不行),並且python.exe所在目錄在系統的環境變數path中。
這時候啟動vim可以測試一下外掛安裝成功了沒有。輸入命令
:YcmDiags
如果vim說找不到命令那就是外掛沒有被vim找到,如果有出來新的視窗,提示錯誤,那就說明外掛安裝好了,接下來還需要繼續配置。
如果你安裝完了啟動vim出現這樣的彈出框:
Runtime Error!
Program: <vim-dir>\gvim.exe
R6034
An application has made an attempt to load the C runtime
library incorrectly.
Please contact the application's support team for more
information.
請按照
這裡的說法解決。
YouCompleteMe這個外掛對C/C++能提供基於語法的自動補全功能,依靠的是clang的語法解析。按照其官方文件的說明,我們還需要配置一個.ycm_extra_conf.py檔案,該檔案即可以在vimrc檔案中指定,也可以放置在程式碼工程的根目錄。
官方給出的示例在這裡。
我修改的檔案如下:
import os
import ycm_core
flags = [
'-std=c++11',
'-stdlib=libc++',
'-Wno-deprecated-declarations',
'-Wno-disabled-macro-expansion',
'-Wno-float-equal',
'-Wno-c++98-compat',
'-Wno-c++98-compat-pedantic',
'-Wno-global-constructors',
'-Wno-exit-time-destructors',
'-Wno-missing-prototypes',
'-Wno-padded',
'-x',
'c++',
'-I',
'.',
'-isystem',
'D:/android-ndk-r9c/platforms/android-19/arch-arm/usr/include/sys',
'-isystem',
'D:/android-ndk-r9c/platforms/android-19/arch-arm/usr/include',
'-isystem',
'D:/android-ndk-r9c/sources/cxx-stl/llvm-libc++/libcxx/include',
'-I',
'D:/work/jni/inc',
'-I',
'D:/work/jni/common',
]
compilation_database_folder = ''
if compilation_database_folder:
database = ycm_core.CompilationDatabase( compilation_database_folder )
else:
database = None
SOURCE_EXTENSIONS = [ '.cpp', '.cxx', '.cc', '.c', '.m', '.mm' ]
def DirectoryOfThisScript():
return os.path.dirname( os.path.abspath( __file__ ) )
def MakeRelativePathsInFlagsAbsolute( flags, working_directory ):
if not working_directory:
return list( flags )
new_flags = []
make_next_absolute = False
path_flags = [ '-isystem', '-I', '-iquote', '--sysroot=' ]
for flag in flags:
new_flag = flag
if make_next_absolute:
make_next_absolute = False
if not flag.startswith( '/' ):
new_flag = os.path.join( working_directory, flag )
for path_flag in path_flags:
if flag == path_flag:
make_next_absolute = True
break
if flag.startswith( path_flag ):
path = flag[ len( path_flag ): ]
new_flag = path_flag + os.path.join( working_directory, path )
break
if new_flag:
new_flags.append( new_flag )
return new_flags
def IsHeaderFile( filename ):
extension = os.path.splitext( filename )[ 1 ]
return extension in [ '.h', '.hxx', '.hpp', '.hh' ]
def GetCompilationInfoForFile( filename ):
if IsHeaderFile( filename ):
basename = os.path.splitext( filename )[ 0 ]
for extension in SOURCE_EXTENSIONS:
replacement_file = basename + extension
if os.path.exists( replacement_file ):
compilation_info = database.GetCompilationInfoForFile( replacement_file )
if compilation_info.compiler_flags_:
return compilation_info
return None
return database.GetCompilationInfoForFile( filename )
def FlagsForFile( filename, **kwargs ):
if database:
compilation_info = GetCompilationInfoForFile( filename )
if not compilation_info:
return None
final_flags = MakeRelativePathsInFlagsAbsolute(
compilation_info.compiler_flags_,
compilation_info.compiler_working_dir_ )
else:
relative_to = DirectoryOfThisScript()
final_flags = MakeRelativePathsInFlagsAbsolute( flags, relative_to )
return {
'flags': final_flags,
'do_cache': True
}
這其實是一個python指令碼, 這個檔案是每個人的設定/每個工程都不一樣的,當然絕大多數情況(官方上寫的是99%)只需要修改 flags 陣列中的編譯相關引數。裡面最重要的引數就是‘-I’和‘-isystem’下面指定的標頭檔案所在目錄。
libclang.dll基於語法檢查、自動補全/提示的時候就會到這些目錄下去找標頭檔案中的函式定義。
有一點特別要強調:如果首次編譯不能通過的話,外掛的自動提示就會顯示很多不相關的全域性變數和函式,這時候你會誤以為這個外掛的自動補全功能好垃圾啊,其實……
這裡的編譯通過是指YouCompleteMe外掛呼叫libclang.dll在語法上能不能編譯通過,而不是你的程式碼最終是否能夠在你指定的環境下編譯連結出二進位制檔案。
最後要說一下,我這裡只是針對C/C++程式碼的,python的自動補齊功能我還沒有用過,如果有其他問題應該可以從官方文件那1000多行說明中找到答案。
寫的倉促,不能保證中間沒有漏掉的細節,如果有哪位朋友按照我的步驟,最後沒有搞定的,請閱讀官方文件或者給我留言。
PS:該外掛對C函式不自動提示,需要按快捷鍵顯示,但是官方的快捷鍵設定的CTRL + SPACE,所以中文輸入法環境下要改,參加下面的vimrc片段。
另外,現在YouCompleteMe外掛在我的vim裡面有個問題,只要被編輯的檔案中有中文就會報python的解碼錯誤,還不知道怎麼解決。如果大家有解決辦法,麻煩指點一下,謝謝!
最後貼上vimrc中對該外掛的設定:參照了這篇文章
" YouCompleteMe 功能
" 補全功能在註釋中同樣有效
let g:ycm_complete_in_comments=1
" 允許 vim 載入 .ycm_extra_conf.py 檔案,不再提示
let g:ycm_confirm_extra_conf=0
" 開啟 YCM 基於標籤引擎
let g:ycm_collect_identifiers_from_tags_files=1
" 引入 C++ 標準庫tags,這個沒有也沒關係,只要.ycm_extra_conf.py檔案中指定了正確的標準庫路徑
set tags+=/data/misc/software/misc./vim/stdcpp.tags
" YCM 整合 OmniCppComplete 補全引擎,設定其快捷鍵
inoremap <leader>; <C-x><C-o>
" 補全內容不以分割子視窗形式出現,只顯示補全列表
set completeopt-=preview
" 從第一個鍵入字元就開始羅列匹配項
let g:ycm_min_num_of_chars_for_completion=1
" 禁止快取匹配項,每次都重新生成匹配項
let g:ycm_cache_omnifunc=0
" 語法關鍵字補全
let g:ycm_seed_identifiers_with_syntax=1
" 修改對C函式的補全快捷鍵,預設是CTRL + space,修改為ALT + ;
let g:ycm_key_invoke_completion = '<M-;>'
" 設定轉到定義處的快捷鍵為ALT + G,這個功能非常贊
nmap <M-g> :YcmCompleter GoToDefinitionElseDeclaration <C-R>=expand("<cword>")<CR><CR>