VimのCTRL-X補完について
この記事はVim Advent Calendar 2015の5日目の記事です。
Vimで補完といえばShougo
さんのプラグインneocomplete
が有名ですが、プラグインを使わなくてもCTRL-X サブモード
で補完を行うことが可能です。
この機能はブログや書籍などでたびたび紹介されてはいますが、文字だけではイメージがつきにくいところもあるのでGIFアニメで紹介してみたいと思います。
行(全体)補完: CTRL-X CTRL-L
if から始まる行と l から始まる行を補完(go)
検索対象はcomplete
オプションで設定可能
局所キーワード補完: CTRL-X CTRL-N / CTRL-X CTRL-P
現在のファイルから T で始まるキーワードを補完(perl)
辞書補完: CTRL-X CTRL-K
dictionary
オプションで設定したファイルから twist で始まる単語を補完
dictionary
オプションに使用するファイルを設定する必要がある(デフォルトは未設定)
set dictionary=/usr/share/dict/words
シソーラス補完: CTRL-X CTRL-T
thesaurus
オプションで設定したファイルから twister の類語を補完
thesaurus
オプションに使用するファイルを設定する必要がある(デフォルトは未設定)
set thesaurus=/usr/share/mythes/th_en_US_v2.dat
パスパターン補完: CTRL-X CTRL-I
インクルードしているSocket.pmから getpr で始まるキーワードを補完(perl)
検索対象はinclude
オプションとpath
オプションで設定可能
タグ補完: CTRL-X CTRL-]
読み込むtagsファイルはtags
オプションで設定可能
ファイル名補完: CTRL-X CTRL-F
/etc/y から始まるファイル名を補完
定義補完: CTRL-X CTRL-D
mixinを補完(sass)
検索対象はdefine
オプションとinclude
オプションとpath
オプションで設定可能
コマンドライン補完: CTRL-X CTRL-V
vimのコマンドと関数を補完
ユーザー定義補完: CTRL-X CTRL-U
completefunc
オプションに設定したCompleteMonthsで月の名前を補完
fun! CompleteMonths(findstart, base) if a:findstart " 単語の始点を検索する let line = getline('.') let start = col('.') - 1 while start > 0 && line[start - 1] =~ '\a' let start -= 1 endwhile return start else " "a:base" にマッチする月を探す let res = [] for m in split("Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec") if m =~ '^' . a:base call add(res, m) endif endfor return res endif endfun
オムニ補完: CTRL-X CTRL-O
omnifunc
オプションに設定されたjavascriptcomplete#CompleteJSでDate型のメソッドを補完(javascript)
スペリング補完: CTRL-X s / CTRL-X CTRL-S
頭文字が大文字になっていない単語と綴りが間違っている単語の修正候補を補完
spell
オプションをオンにする必要がある
上記環境はDocker上のcentos6に以下のパッケージをインストールしたものです。
プラグインは一切インストールしておらず、vimrcも作成していません。
yum install vim-enhanced ctags words mythes-en
CTRL-X サブモード について
順序が逆転してしまいましたが、CTRL-X サブモード
は挿入モード
または置換モード
中にCTRL-X
キーで入ることができます。
ポップアップメニューの補完候補はCTRL-N
(次の候補)またはCTRL-P
(前の候補)キーで選択し、CTRL-Y
キーやスペース、エンターなどで挿入することができます。
また、CTRL-E
キーで補完を中止して元のテキストに戻すことができます。
最近neocomplete
が入っていないVimを触ることがちょこちょことあり、ここ1週間くらいはメインのVimでもneocomplete
を使わずに過ごしてみました。
昔は自動補完プラグインが無いとコーディングなんてできない...とか思っていましたがそこまで困らないくらいには成長していたようです。
ただ、CTRL-X
キーがイマイチ押しにくいと感じているのでこれさえなんとかなれば自動補完プラグインは使わなくなるかもしれません。
今はこんなマッピングを試してみています。
inoremap <expr><Tab> pumvisible() ? "\<C-n>" : MyInsCompl() function! MyInsCompl() let c = nr2char(getchar()) if c == "l" return "\<C-x>\<C-l>" elseif c == "n" return "\<C-x>\<C-n>" elseif c == "p" return "\<C-x>\<C-p>" elseif c == "k" return "\<C-x>\<C-k>" elseif c == "t" return "\<C-x>\<C-t>" elseif c == "i" return "\<C-x>\<C-i>" elseif c == "]" return "\<C-x>\<C-]>" elseif c == "f" return "\<C-x>\<C-f>" elseif c == "d" return "\<C-x>\<C-d>" elseif c == "v" return "\<C-x>\<C-v>" elseif c == "u" return "\<C-x>\<C-u>" elseif c == "o" return "\<C-x>\<C-o>" elseif c == "s" return "\<C-x>s" endif return "\<Tab>" endfunction
Goのパッケージをgit subtreeで管理する
Go 1.5からVendoring機能が使えるようになったので外部パッケージをgit subtree
で管理してみた。
以下のコマンドで対象のリポジトリにパッケージを追加することができる。
※ --squash
をつけると取り込むパッケージのコミットを一つにまとめることができる
# usage: git subtree add --prefix=<prefix> <repository> <ref> $ git subtree add --prefix=vendor/github.com/zenazn/goji https://github.com/zenazn/goji v0.8.3 --squash
GO15VENDOREXPERIMENT
はデフォルトでは無効なのでビルドするときに有効にする必要がある。
$ GO15VENDOREXPERIMENT=1 go build
パッケージを更新するときはpull
を使う。
$ git subtree pull --prefix=vendor/github.com/zenazn/goji https://github.com/zenazn/goji v0.9.0 --squash
gitとgoさえあれば誰でもどこでも(ネットワークが使えなくても)ビルドできるので仕事で開発する時なんかに良さげ。
例
ディレクトリ構成
$ tree . ├── main.go └── vendor └── github.com └── zenazn └── goji
main.go
package main import ( "fmt" "net/http" "github.com/zenazn/goji" "github.com/zenazn/goji/web" ) func hello(c web.C, w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Hello, %s!", c.URLParams["name"]) } func main() { goji.Get("/hello/:name", hello) goji.Serve() }
コミットグラフ
$ git log --graph --oneline * 2c05509 Merge commit '082b48ab2b6004bf43e3faa0bda84e9323a2cfce' |\ | * 082b48a Squashed 'vendor/github.com/zenazn/goji/' changes from 9a41ab2..ba6c4f2 * | b3823c4 Merge commit '7fed70cb0d2f008dfc30014f3f4829113b3c34e8' as 'vendor/github.com/zenazn/goji' |\ \ | |/ | * 7fed70c Squashed 'vendor/github.com/zenazn/goji/' content from commit 9a41ab2 * 0da4802 Initial commit
macvim-kaoriya or macvimをビルドする(2015/08)
vim 7.4.774で追加された v:completed_item
をmacvim-kaoriyaで使いたくなったけど今日の時点だとまだバージョン7.4.769なので使えない...
Homebrewからインストールできるらしいけど手元の環境ではエラーが出たのでコンソールからビルドしてみる。
2015/08/26追記
エラーの原因は古いrecipeを参照しているせいでした。
brew tap splhack/homebrew-splhack brew install --HEAD splhack/splhack/macvim-kaoriya
でHomebrewからインストールできたので以下は通常用途では使う必要なさそう。
- vim本体のソースを変更したい
- if_*を/usr/local以外のバージョンで使いたい
時くらいか。。。
ソースのダウンロード
- macvim-kaoriya
git clone https://github.com/splhack/macvim
or
- macvim
git clone https://github.com/b4winckler/macvim
ビルド
このビルドスクリプトを
macvimディレクトリで実行する。
cd macvim
./build-macvim.sh
実行
open src/MacVim/build/Release/MacVim.app
とりあえず動いた。
- macvim-kaoriya
:version VIM - Vi IMproved 7.4 (2013 Aug 10, compiled Aug 23 2015 20:28:09) MacOS X (unix) version Included patches: 1-826 Compiled by daisuzu <daisuzu@gmail.com> Huge version with MacVim GUI. Features included (+) or not (-): +acl +cmdline_info +emacs_tags -gettext +listcmds +mouse_netterm +persistent_undo +signs +termresponse +wildignore +arabic +comments +eval +guess_encode +localmap +mouse_sgr +postscript +smartindent +textobjects +wildmenu +autocmd +conceal +ex_extra -hangul_input +lua/dyn -mouse_sysmouse +printer -sniff +title +windows +balloon_eval +cryptv +extra_search +iconv +menu +mouse_urxvt +profile +startuptime +toolbar +writebackup +browse +cscope +farsi +insert_expand +migemo +mouse_xterm +python/dyn +statusline +transparency -X11 ++builtin_terms +cursorbind +file_in_path +jumplist +mksession +multi_byte +python3/dyn -sun_workshop +user_commands -xfontset +byte_offset +cursorshape +find_in_path +keymap +modify_fname +multi_lang +quickfix +syntax +vertsplit +xim +cindent +dialog_con_gui +float +kaoriya +mouse -mzscheme +reltime +tag_binary +virtualedit -xsmp +clientserver +diff +folding +langmap +mouseshape +netbeans_intg +rightleft +tag_old_static +visual -xterm_clipboard +clipboard +digraphs -footer +libcall +mouse_dec +odbeditor +ruby/dyn -tag_any_white +visualextra -xterm_save +cmdline_compl +dnd +fork() +linebreak -mouse_gpm +path_extra -ruby19 -tcl +viminfo -xpm +cmdline_hist -ebcdic +fullscreen +lispindent -mouse_jsbterm +perl/dyn +scrollbind +terminfo +vreplace system vimrc file: "$VIM/vimrc" user vimrc file: "$HOME/.vimrc" 2nd user vimrc file: "~/.vim/vimrc" user exrc file: "$HOME/.exrc" system gvimrc file: "$VIM/gvimrc" user gvimrc file: "$HOME/.gvimrc" 2nd user gvimrc file: "~/.vim/gvimrc" system menu file: "$VIMRUNTIME/menu.vim" fall-back for $VIM: "/Applications/MacVim.app/Contents/Resources/vim" Compilation: gcc -c -I. -Iproto -DHAVE_CONFIG_H -DFEAT_GUI_MACVIM -Wall -Wno-unknown-pragmas -pipe -DMACOS_X_UNIX -g -O2 -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1 Linking: gcc -L. -L/usr/local/lib -L. -L/usr/local/lib -L/usr/local/lib -o Vim -framework Cocoa -framework Carbon -lm -lncurses -liconv -lmigemo -framework Cocoa -pagezero_size 10000 -image_base 100000000 -pagezero_size 10000 -image_base 100000000 -fstack-protector -L/System/Library/Perl/5.18/darwin-thread-multi-2level/CORE
- macvim
:version VIM - Vi IMproved 7.4 (2013 Aug 10, compiled Aug 23 2015 20:37:09) MacOS X (unix) version Included patches: 1-383 Compiled by daisuzu <daisuzu@gmail.com> Huge version with MacVim GUI. Features included (+) or not (-): +acl +cmdline_info +emacs_tags -gettext +lua/dyn +mouse_urxvt +profile +statusline +transparency -X11 +arabic +comments +eval -hangul_input +menu +mouse_xterm +python/dyn -sun_workshop +user_commands -xfontset +autocmd +conceal +ex_extra +iconv +mksession +multi_byte +python3/dyn +syntax +vertsplit +xim +balloon_eval +cryptv +extra_search +insert_expand +modify_fname +multi_lang +quickfix +tag_binary +virtualedit -xsmp +browse +cscope +farsi +jumplist +mouse -mzscheme +reltime +tag_old_static +visual -xterm_clipboard ++builtin_terms +cursorbind +file_in_path +keymap +mouseshape +netbeans_intg +rightleft -tag_any_white +visualextra -xterm_save +byte_offset +cursorshape +find_in_path +langmap +mouse_dec +odbeditor +ruby/dyn -tcl +viminfo -xpm +cindent +dialog_con_gui +float +libcall -mouse_gpm +path_extra +scrollbind +terminfo +vreplace +clientserver +diff +folding +linebreak -mouse_jsbterm +perl/dyn +signs +termresponse +wildignore +clipboard +digraphs -footer +lispindent +mouse_netterm +persistent_undo +smartindent +textobjects +wildmenu +cmdline_compl +dnd +fork() +listcmds +mouse_sgr +postscript -sniff +title +windows +cmdline_hist -ebcdic +fullscreen +localmap -mouse_sysmouse +printer +startuptime +toolbar +writebackup system vimrc file: "$VIM/vimrc" user vimrc file: "$HOME/.vimrc" 2nd user vimrc file: "~/.vim/vimrc" user exrc file: "$HOME/.exrc" system gvimrc file: "$VIM/gvimrc" user gvimrc file: "$HOME/.gvimrc" 2nd user gvimrc file: "~/.vim/gvimrc" system menu file: "$VIMRUNTIME/menu.vim" fall-back for $VIM: "/Applications/MacVim.app/Contents/Resources/vim" Compilation: gcc -c -I. -Iproto -DHAVE_CONFIG_H -DFEAT_GUI_MACVIM -Wall -Wno-unknown-pragmas -pipe -DMACOS_X_UNIX -g -O2 -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1 Linking: gcc -L. -L/usr/local/lib -L. -L/usr/local/lib -L/usr/local/lib -o Vim -framework Cocoa -framework Carbon -lm -lncurses -liconv -framework Cocoa -pagezero_size 10000 -image_base 100000000 -fstack-protector -L/System/Library/Perl/5.18/darwin-thread-multi-2level/CORE
gettext-mkやif_*の言語は全部Homebrew経由でインストールした。
luaenv、pyenv、rbenvあたりが有効だと多分ビルドできないので無効にするか以下を正しく設定する。
Shibaで図を書いてTracで共有する
Shibaというマークダウンをプレビューしてくれるアプリがあるのですが、
@Linda_pp そのうち図を表示できるようになったりしますか?
— daisuzu (@dice_zu) 2015, 8月 12
と言ってみたところ
Shiba で mermaid.js 使えるようにした https://t.co/gdJB81t3tC CC: @dice_zu
— ドッグ (@Linda_pp) 2015, 8月 13
翌日にはmermaid.jsを利用した図が表示できるようになっていました。
これでちょっとした打ち合わせなどで図を見せつつ箇条書きでメモを書いていく、
なんて使い方ができそうです。
そうなると今度はその内容を共有したくなったりしますが、
毎回Shibaを起動して表示してもらうのは嫌がられそうだし、
そもそも全員がShibaをインストールしてくれるとは限らないのでWebに置けると良さそうです。
といっても専用のホストを用意するほどではないので今のチームで一番使われているTracで共有する方法を考えてみました。
- プラグインを作る
- Tracが稼働しているホストのHTMLを直接編集してmermaid.js(依存しているD3.jsやcssも含む)を追加する
- ThemeEnginePlugin をインストールして
Customize: Advanced
からmermaid.js(依存しているD3.jsやcssも含む)を直接埋め込む
1は正直面倒、2は権限が無くて不可能、消去法的に3でやってみましたが、 Shibaで次のように図を書き、
```mermaid
gantt
title A Gantt Diagram
section Section
A task :a1, 2014-01-01, 30d
Another task :after a1 , 20d
section Another
Task in sec :2014-01-12 , 12d
anther task : 24d
```
TracのWikiなどでhtmlプロセッサを利用して同じように図を表示させることができるようになりました。
{{{ #!html <div class="mermaid"> gantt title A Gantt Diagram section Section A task :a1, 2014-01-01, 30d Another task :after a1 , 20d section Another Task in sec :2014-01-12 , 12d anther task : 24d </div> }}}
コードブロックとdivの変換はvimで編集していればそんなに手間ではないでしょう。
ちなみにドキュメントには明示されていませんでしたがShibaでもガントチャートを表示させることが可能です。
Middleman(Slim) + Ractive.jsでWeb AppのUIを作る
JSONでバックエンドサーバとデータをやり取りするというごく普通のWeb Appを作るにあたり、 UIをどうするか悩みつつ Middleman と Ractive.js を使ってみることにした。
Middlemanを選んだのは
- 開発中のlivereload
- css, jsのconcat/minify
- ページの構造化
- 各種ライブラリの管理
がお手軽そうだったのと直接htmlを書かなくて済むから。
Ractive.jsはデータバインディングでMiddlemanと組み合わせても違和感無く使えそうな感じだったから。
そして一番の理由は
「htmlがよくわからない」
ってメンバーでもtracやredmineのwikiとかチケットはバリバリ使っていたので、
Slimで書かれているところは内容を理解してもらえそうだったから。
あわよくばUIや(フロント側が要求する)APIの修正なんかもやってくれるようになるかもと思い、ひと通りデモを見せたところ
「全然わかりませんでした」
と言われれるという残念な結果に...
そんなこんなで実際に作ったものはこのまま消えていってしまいそうなので 忘れないようにサンプルを残しておくことにする。
Goでhttp.ClientのテストをするときにProxyを書き換えてテストサーバにリクエストを投げる
Goで外部リクエストが関わる処理をテストする - Qiita
のfetch(url string)
と違って引数でURLを取れないような関数をテストする場合、
http.DefaultTransport.(*http.Transport).Proxyを書き換えるとテストサーバにリクエストを飛ばせる。
main.go
package main import ( "fmt" "io/ioutil" "log" "net/http" ) func fetch() []byte { res, err := http.Get("http://localhost:8000/test") if err != nil { log.Fatal(err) } defer res.Body.Close() body, err := ioutil.ReadAll(res.Body) if err != nil { log.Fatal(err) } return body } func main() { fmt.Printf("%s", fetch()) }
main_test.go
package main import ( "fmt" "net/http" "net/http/httptest" "net/url" "testing" ) func TestFetch(t *testing.T) { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, "test") })) defer ts.Close() defaultProxy := http.DefaultTransport.(*http.Transport).Proxy http.DefaultTransport.(*http.Transport).Proxy = func(req *http.Request) (*url.URL, error) { // テストサーバのURLをProxyに設定 return url.Parse(ts.URL) } // テストが終わったらProxyを元に戻す defer func() { http.DefaultTransport.(*http.Transport).Proxy = defaultProxy }() value := string(fetch()) expected := "test" if value != expected { t.Errorf("Expected %v, but %v:", expected, value) } }
参考
前にどこかで似たような記事を見たような気がしたんけど今探したら見つからず...
かわりに
なんてのがあることを知った。