征服恐懼!用 Vim 寫 iOS App
我們都知道 Vim 和 Emacs 都是文字編輯器中的上古神器,你也許用 ctags,cscopes 配合 Vim 完成過大型 C 或者 C++ 的開發,你也許配合過其他外掛,完成過 JavaScript,python 程式碼的開發,但是很少有人試過 iOS app 的開發吧,畢竟 iOS 的框架包含了很多東西,以及 Objective-C 天生很長的 API 名字,讓我們沒辦法把此神器用起來,今天我就來給大家講下我是怎麼使用 Vim 開發 iOS App 的,當然 Emacs 也可以
begin
使用 Vim 開發 iOS App 並不是特殊的愛好,而是被 Xcode 8 活生生的逼的,剛開始更新了 Xcode 8 以後,Xcode 8 把第三方外掛給遮蔽了,導致沒有 XVim 給我用了,沒有 XVim 以後,發現異常不順手,於是嘗試用了一段時間的 AppCode,不得不說 AppCode 是一個非常好的 IDE,但是他有個很大的缺點,那就是 Java,JetBrain 家的東西都很不錯,唯一缺點就是基於 Java,整個平臺都略慢,然後我在不斷的 google 過程中,發現了有人竟不知何謂恐懼,竟然使用 Vim 開發 iOS App,最後我也學會了這個新姿勢 XDDDD
不過目前,只支援 Objective-C 程式碼的開發,swift 的話,沒有解決工程檔案自動補全的問題,因為目前大家使用的流行的 swift 自動補全工具 SourceKitten 並沒有支援 workspace 所以暫時還沒用起來
以及,目前不支援除錯,因為發現 Vim 對除錯的支援確實好糟糕...
準備活動
工欲善其事,必先利其器,主角是 Vim 或者 Emacs,少了其他配角和龍套們,也沒辦法正負恐懼,我們來看看用到了些什麼東西,讓我們的 Vim 成為利器的,這裡只是點下他們的名,文章後面會把連結奉上
首先我們來看主角隊的同學們,他們是征服恐懼的主力
- macOS,沒有神話,開發 iOS 還是隻能在 Mac 上
- 支援 python 的 Vim,可以用 Vim8 或是 neoVim 食用更佳,我就用的 neoVim
- YCMD,其實他是 YouCompleteMe + YouCompelteMeDeamon 的合體,自動補全、定義跳轉等功能,就依賴他了
接下來我們來看看其他龍套們
- Vbundle,裝外掛用的,沒他,龍套和主角都不用上場了
- unite + unite-outline + unite-outline-objc,提供了方法導航
- auto-pairs,自動補全右括號
- ctrlp,檔案搜尋跳轉
- Ag,字串搜尋工具
- syntastic,語法檢查工具
- vim-clang-format,程式碼格式工具
恩,需要的東西大概就是這些了,Vim 的配置檔案,我是基於好久以前 square 開源的 maximum-awesome 的,所以,配合這個食用風味更佳,我的 dot file 也放到了 github 上,歡迎大家 star
進入正題
龍套們,基本都可以通過配置 vbundle 來完成安裝,之後只用配置對應的快捷鍵就好了,這裡的正題,要搞定難搞的主 YCMD
難搞的主 YCMD
安裝 YCMD
YCMD 的安裝很簡單,主要是需要一定的配置
首先在 vim 的配置檔案中加入下面的內容,更新配置檔案並執行 BundleInstall
命令,讓 Vbundle 把 YouCompleteMe 外掛裝上
vim
Plugin 'Valloric/YouCompleteMe'
然後到這個路徑 ~/.vim/bundle/YouCompleteMe
這裡是 YouCompleteMe 安裝的位置,在這裡需要編譯 YCM,一條命令就可以搞定
bash
./install.py --clang-completer --system-libclang
--clang-completer
告訴指令碼我們需要 clang 的支援,--system-libclang
告訴編譯指令碼使用系統的 clang,因為之前 clang 升級 4.0 的時候,並沒有已經編譯好的包給我下載,所以這裡不用系統 clang 的話,編譯指令碼會下載一個 clang 3.0,這樣就無法支援 iOS 10.0 以後的 sdk 了,因為 iOS 10.0 以後的 sdk 為了支援 swift 引入了一些 clang 3.0 不支援的新語法,所以這裡要加上 --system-libclang
然後等他編譯完成,這樣 YCMD 就配置好了,似乎這裡看並不是很難搞,其實難搞的是如何在 iOS 專案中配置好自動提示
為 Xcode 專案配置 YCMD
這裡進入到了真正征服恐懼的地方了
YouCompleteMe 的原理
曾經有人說過,編輯器再怎麼神器是沒辦法超過 IDE 的,因為 IDE 是通過編譯、解析整個專案的所有檔案,來達到語法錯誤提示,自動補全,定義跳轉等高階功能的,而 YCMD 就是來彌補這一個差距的,YCMD 通過傳入完整的編譯引數,編譯需要提示的檔案,來實現自動補全,這樣沒辦法超過 IDE 的部分就被抹平了
配置一個專案
這裡我們配置一個複雜的專案來練練手,首先 YCMD 是不可能通過 Xcode 的專案檔案或是 workspace 檔案獲取到編譯引數的,所以這一步需要手來,當然,將來可以做成自動的,因為目前手動的做其實很方便,所以現在還沒有做成自動的
首先,YCMD 是通過每個專案路徑下的 .ycm_extra_conf.py
指令碼檔案來獲取編譯引數的,這個指令碼檔案中有一個叫做 FlagsForFile
的函式,我們通過這個函式返回某一個特定檔案需要的編譯引數,一般情況下大部分檔案的編譯引數是一樣的,我們來看一個配置的列子
```python import os import ycm_core
flags = [ '-resource-dir', '/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/clang/8.0.0', '-x objective-c', '-arch armv7', '-fmessage-length=0', # '-fmodules', # '-gmodules', '-fdiagnostics-show-note-include-stack', '-fmacro-backtrace-limit=0', '-D__arm__=1', '-D__IPHONE_OS_VERSION_MIN_REQUIRED=80000', '-std=gnu99', '-fobjc-arc', '-Wnon-modular-include-in-framework-module', '-Werror=non-modular-include-in-framework-module', '-Wno-trigraphs', '-fpascal-strings', '-Os', '-fno-common', '-Wno-missing-field-initializers', '-Wno-missing-prototypes', '-Werror=return-type', '-Wunreachable-code', '-Wno-implicit-atomic-properties', '-Werror=deprecated-objc-isa-usage', '-Werror=objc-root-class', '-Wno-arc-repeated-use-of-weak', '-Wduplicate-method-match', '-Wno-missing-braces', '-Wparentheses', '-Wswitch', '-Wunused-function', '-Wno-unused-label', '-Wno-unused-parameter', '-Wunused-variable', '-Wunused-value', '-Wempty-body', '-Wconditional-uninitialized', '-Wno-unknown-pragmas', '-Wno-shadow', '-Wno-four-char-constants', '-Wno-conversion', '-Wconstant-conversion', '-Wint-conversion', '-Wbool-conversion', '-Wenum-conversion', '-Wshorten-64-to-32', '-Wpointer-sign', '-Wno-newline-eof', '-Wno-selector', '-Wno-strict-selector-match', '-Wundeclared-selector', '-Wno-deprecated-implementations', '-DOBJC_OLD_DISPATCH_PROTOTYPES=0', '-isysroot', '/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk', '-fstrict-aliasing', '-Wprotocol', '-Wdeprecated-declarations', '-miphoneos-version-min=8.0', '-g', '-Wno-sign-conversion', '-Wno-infinite-recursion', '-fembed-bitcode-marker', '-I/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform', '-I/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/usr/include', '-I/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/System/Library/Frameworks', '-I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/clang/8.0.0/include', '-F/Users/apple/Documents/Developer/CloudLifeWorkspace/iOS/Develop/Project_iOS/project', '-MMD', '-MT', '-MF', ]
SOURCE_EXTENSIONS = [ '.cpp', '.cxx', '.cc', '.c', '.m', '.mm' ]
HEADER_EXTENSIONS = [ '.hpp', '.hxx', '.hh', '.h' ]
def FlagsForFile( filename, **kwargs ): staticFlags = flags return { 'flags': staticFlags, 'do_cache': True } ```
這裡上面的程式碼可以當作 .ycmd_extra_conf
檔案的一個最小模板,也就是如果我們的專案裡面沒有子目錄,沒有第三方庫,那麼使用這個已經可以為 iOS 專案提供自動提示了
顫抖吧凡人,如此這般的編譯條件,需要你能夠把 Xcode 專案配置中的編譯引數完完全全翻譯出來才行,但是我也是凡人,所以這個不是我寫的,而是有方法生成的,方法如下
把需要增加自動提示的專案用 Xcode 開啟,然後編譯,然後如下圖所示,找到編譯資訊然後隨便找專案中的一個檔案,注意不要是 Pod 中的檔案,最右邊,有個三條橫線的按鈕,點開他,沒錯,你看到了完整的編譯引數,下圖中 EXPORT PATH =....
下面的所有內容就是完整的編譯引數
- Report View
- 戳這個按鈕
- 我們要的編譯資訊
右鍵,copy,找到你熟悉的記事本,引數都是空格分隔的,所以,這裡我們把它轉換成上面程式碼中的形式,並把不需要的去掉,比如這裡我註釋了 -fmodules
和 -gmodules
因為這樣編譯沒辦法使用 module
把這些加入到配置檔案中後,再開啟 Vim 你就會發現自動提示變得非常好用了,不過這裡還會有一個問題,如果編譯的時候,有無法找到 UIKit
,這是因為 YCMD 預設引入了 macOS SDK 的路徑,導致了編譯時 clang 認為我們編譯目標是 macOS,所以如下圖需要修改 ~/.vim/bundle/YouCompleteMe/third_party/ycmd/ycmd/completers/cpp/flags.py
檔案,去掉預設引入 macOS sdk 的編譯引數,這樣就好了
效果圖們
至此,最主要的問題已經被我們解決了,接下來看下效果如何
- 首先是自動提示
- 查詢檔案
- 方法名稱大綱
- 搜尋字串
- 語法檢查
好處
這麼做自然不是為了花樣炫技,更多的是為了探索 Vim 的使用,以及更多瞭解 Xcode 專案
- 完整的 Vim 環境,寫程式碼再也不用碰滑鼠了
- Vim 外掛 + 不滿的地方自己動手豐衣足食
- 快速,跟 Vim 比速度,笑話
- 方便快接的字串搜尋,替換操作
- 學了點 Python
- 支援 cocoapod,畢竟 pod 也只是編譯引數而已
- 附贈一個 C/C++ 的開發環境
已知問題
雖然目前已經可以達到寫程式碼的程度了,但是還是有很多問題,如下:
- 沒辦法 debug
- 不支援 Xcode 中的 group 展示
- 標頭檔案的提示有問題
- 不能使用
@import
的匯入,會報語法錯誤 - xib,storyboard 自然是不行的,我的做法是 Xcode 裡面拖 UI + 關聯 Outlet + Debug,Vim 中做大量的程式碼編輯操作
[]
方括號的匹配沒有 Xcode 那麼智慧- delegate 或是全域性的自動提示,需要使用 ctrl + 空格開啟,並且有時候會有點慢
- delegate 的自動提示有時候需要輸入前面半部分的方法名才會有,比如上面截圖的 tableView,需要先輸入
- (void)tableView:(UITableView *)tableView
再使用 ctrl + 空格才會有非常好的自動提示,當然輸入前面這部分也會有一定的提示,整體上看能接受
上面的問題都是一直以來我沒有解決的問題,大家要是發現有破解的方法,歡迎聯絡
end
折騰這麼多,相信大家已經可以用 Vim 敲 iOS 的程式碼了,雖然雖然當初開始折騰的時候,踩了很多坑,比如 clang 3 升級 clang 4 後,原來的配置都不能用了,但是收穫挺多的也並不是這麼一篇文章能夠說完的,除了 Vim 大家也可以試試 Emacs 下的配置,我用的 Spacemacs,新增了 ycmd 的 layer,配置後也有了相同的效果
也歡迎大家丟磚
參考資料
- YouCompleteMe: 自動補全外掛
- Vbundle: 外掛管理外掛
- Unite: 一個通用的顯示外掛,可以用來顯示各種東西,比如檔案列表,buffer 列表,outline
- Unite-outline: Unite 外掛的 outline 外掛
- Unite-outline-objc: Unite-outline 外掛的 Objective-C 外掛
- auto-pairs: 自動補全括號的外掛
- ctrlp: 檔案查詢外掛
- Ag: 字串查詢外掛
- syntastic: 語法檢查外掛
- vim-clang-format: clang format 格式化外掛
- VimAwesome: 方便的 Vim 外掛導航網站
- maximum-awesome: 一個比較有名的 Vim 配置,包括了上面的 Vbundle,Ag,ctrlp,syntastic 等外掛,以及一些很方便的配置,我的配置檔案是基於這個配置的,使用前先安裝這個
- 我的配置檔案: 我的配置檔案,除了上文寫的內容,還加了些 php,python,js 等開發配置,以及一些自己覺得用起來方便的配置
相關文章
- 克服命令列恐懼症命令列
- 用無人機打點作畫,密集恐懼症患者慎入!無人機
- 《密特羅德 生存恐懼》Fami 通評測:完美駕馭恐懼與安心間的微妙平衡
- 一個程式設計師的恐懼程式設計師
- 擺脫面試恐懼症的六招面試
- 讓我們看破恐懼!解析恐怖類遊戲的慣用套路遊戲
- 在外企工作最大的恐懼是什麼?
- 一行程式碼引發的恐懼行程
- Bruce Tate:恐懼是我寫作《七週七語言》的初衷(圖靈訪談)圖靈
- 測試人員對程式設計天生“恐懼”麼?程式設計
- 如何克服解決Git衝突的恐懼症?(序)Git
- [英]Bruce Tate:恐懼是我寫作《七週七語言》的初衷(圖靈訪談)圖靈
- 《層層恐懼2》今日正式在多平臺發售!
- 還記得面試時被演算法支配的恐懼嗎?面試演算法
- 如何克服解決Git衝突的恐懼症?(Git分支策略)Git
- 選擇恐懼症的福音!教你認清MVC,MVP和MVVMMVCMVPMVVM
- 三星VR虛擬現實醫療應用 幫助克服人的恐懼心理VR
- 如何克服解決Git衝突的恐懼症?(Git高階篇)Git
- 恐懼、野心和迷茫,機器人公民背後的未來世界機器人
- BAT之痛:騰訊社交帝國的死裡逃生和未知恐懼BAT
- 如何克服解決Git衝突的恐懼症?(Git移交提交記錄)Git
- 你為什麼會恐懼人工智慧?它有什麼可怕之處?人工智慧
- 那一天,我被Redis主從架構支配的恐懼Redis架構
- 如何克服解決Git衝突的恐懼症?(Git基礎篇--下)Git
- 如何克服解決Git衝突的恐懼症?(Git基礎篇--上)Git
- 如何克服解決Git衝突的恐懼症?(Git入門介紹)Git
- 如何克服解決Git衝突的恐懼症?(Git高階話題)Git
- 查普曼大學:2017年美國民眾最恐懼的事情TOP 10
- 恐懼會讓你成為一個更糟糕的程式設計師程式設計師
- 我是怎樣克服對 React 的恐懼,然後愛上 React 的React
- 華爾街玩轉社交網路大資料:利用你的恐懼賺錢大資料
- 在玩恐怖遊戲時,到底是什麼讓你感到如此恐懼?遊戲
- 黑客利用人們對冠狀病毒的恐懼傳播惡意軟體黑客
- 如何克服解決Git衝突的恐懼症?(Git四大元件)Git元件
- Tata Communications :調查顯示網際網路使用會助長“失落恐懼”
- 用css動畫寫一個文字落下的背景動畫(密恐勿進)CSS動畫
- 從《層層恐懼》到《靈媒》,這支小團隊如何找到自己的賽道?
- 「讀懂原始碼系列1」還在恐懼讀原始碼?看完這篇就不怕了原始碼