2019/12/31


はじめに

以下の記事では、僕の Vim の構成について記述しています。本来はこの記事で vim-lsp の導入方法と私的 Go 編集環境について書こうと思っていましたが、あまりにも長くなってしまったので別途書く事にしました。僕は Windows と Linux しか使わないので、皆さんの環境で使うとうまく動かない可能性があります。また僕は最新の Vim 8 しか使いません。古めの Vim を使いません。neovim も使いません。それらをお使いの方はうまく動かない可能性があります。ご了承下さい。なお設定ファイルの配置スタイルは完全に僕個人の趣味ですので必ずしも僕の構成が正しい訳ではありません。

ぼくのかんがえたさいきょうの Vim こうせい

Vim の設定は vimrc に記述するのですが、その設定方法には「汚くさせない」ための工夫が必要だと思っています。以下は僕が行っている「vimrc を綺麗に保つ方法」です。

vimrc に記述する内容は大きく分けて以下の物があります。

  1. Vim 本体の機能のデフォルト値を変更する設定
  2. プラグインの読み込み
  3. ユーザ固有のマッピングやコマンドの定義
  4. プラグイン固有の設定
これは上記の順で書くのが良いと思います。幾らか例外はありますが、おおよそ上記の流れで書くのが良いと思います。今回、僕の vimrc を公開はしませんが、おおよそこの流れに沿っていると思って下さい。なぜ公開しないのかというと、日々スタイルを模索してどんどん変わっていく為、今回ここで紹介した物が僕の vimrc だと広まって欲しくないからです。また好き嫌いはあると思うのですが、僕は最近は分割 vimrc 形式を使っています。 vimfiles
├─vimrc
├─gvimrc
├─autoload/
├─plugged/
└─_config/

autoload には後で述べる vim-plug の plug.vim しか入っていません。上記のリストの内、1と2は vimrc および gvimrc に記述しています。残りは全て _config というフォルダ内に、各機能毎に分けて記述しています。以下は僕の vimrc の概要です。

" Vim 本体の機能のデフォルト値を経項する設定
setglobal cmdheight=2
setglobal laststatus=2

... 略 ...

setglobal fileformat=unix
setglobal formatoptions+=mb

if !has('win32') && !has('win64')
  setglobal shell=/bin/bash
endif

if exists('&termguicolors')
  setglobal termguicolors
endif

if exists('&completeslash')
  setglobal completeslash=slash
endif

let g:no_gvimrc_example=1
let g:no_vimrc_example=1

let g:loaded_gzip               = 1
let g:loaded_tar                = 1
let g:loaded_tarPlugin          = 1
let g:loaded_zip                = 1
let g:loaded_zipPlugin          = 1
let g:loaded_rrhelper           = 1
let g:loaded_vimball            = 1
let g:loaded_vimballPlugin      = 1
let g:loaded_getscript          = 1
let g:loaded_getscriptPlugin    = 1
let g:loaded_netrw              = 1
let g:loaded_netrwPlugin        = 1
let g:loaded_netrwSettings      = 1
let g:loaded_netrwFileHandlers  = 1
let g:did_install_default_menus = 1
let g:skip_loading_mswin        = 1
let g:did_install_syntax_menu   = 1
"let g:loaded_2html_plugin       = 1

let g:mapleader = '\'
let g:maplocalleader = ','

" git commit 時にはプラグインは読み込まない
if $HOME != $USERPROFILE && $GIT_EXEC_PATH != ''
  finish
end

" Windows の場合は必要なパスを追加しておく
if has('win32')
  let $PATH='c:\dev\vim;c:\msys64\mingw64\bin;c:\msys64\usr\bin;'
  \ .'c:\Program Files\Java\jdk1.8.0_221\bin;'.$PATH
endif

" プラグインの読み込み
let g:plug_shallow = 0

call plug#begin('~/.vim/plugged')

Plug 'thinca/vim-ambicmd'
Plug 'thinca/vim-openbuf'
Plug 'thinca/vim-quickrun'

... 略 ...

call plug#end()

" 各種設定の読み込み
call map(sort(split(globpath(&runtimepath, '_config/*.vim'))){->[execute('exec "so" v:val')]})

これを $HOME/.vim、Windows であれば %USERPROFILE%\vimfiles の中に vimrc というファイル名で置いています。便宜上、vimfiles を Windows のシンボリックリンクを使って .vim にリンクさせています。

気を付けるべきはこの状態を常に保つ事です。これは vimrc だけでなく .emacs.el 等にも言える事ですが、「ちょっと今だけ」と vimrc に手を加えた設定は、おそらく数か月後もそのままになってしまう可能性があるからです。綺麗な vimrc を保ち続けたいのであれば、この形は崩さない事です。

またなぜ僕がこの形にしているかというと、機能単位またはプラグイン単位で設定ファイルを消せるからです。必要なくなったプラグインの設定が vimrc に残ったままだと、どんどん汚くなってしまいます。必要に応じて消していくのも、vimrc を綺麗に保つ秘訣です。これは僕が2015年から SoftwareDesign の連載「Vim の細道」を書く上で毎月 vimrc を継ぎ足ししているうちに、どうしても vimrc が汚くなってしまった問題を解決する為に行き着いた方法です。

Vim 本体の機能のデフォルト値を変更する設定

ここで僕が言える事は「これらの設定をばらまかない事」。これらの設定は今後どんな新しいプラグインが出てきたとしても変わらない設定であるはずです。

プラグインの読み込み

僕は vim-plug というプラグインマネージャを使っています。他のプラグインマネージャを使っている方もいると思います。ちなみに僕も vim-plug に満足している訳ではなく、現在は minpac に移行しようか検討中です。

ユーザ固有のマッピングやコマンド定義

これ以降は、ユーザ固有のマッピングやコマンド定義、プラグイン固有の設定、の2つとなりますが、これらは個別の設定ファイルに書いています。例えば僕は _config ディレクトリの下に以下の様に配置しています。 000-mappings.vim
001-filetype.vim
002-commands.vim
003-path.vim
102-autofmt.vim
104-conda.vim
105-ctrlp.vim
106-emmet.vim
107-lightline.vim
200-lsp.vim
201-languageclient-nvim.vim
202-vsnip.vim
204-quickrun.vim
300-vim.vim
301-java.vim
400-memolist.vim
401-openbrowser.vim
402-previm.vim
403-termdebug.vim
404-tohtml.vim
405-twitvim.vim

おおよそ番号体系があって、000番台が Vim 本体に関する物、100番台が全体に関わるプラグインの設定、200番台以降がプラグインの設定ですがその中でもグローバルに適用される物、300番台がファイルタイプに関連する物、400番台がアプリケーションに関する物、となっています。この番号体系は完全に守れている訳ではないです。

ユーザ固有のコマンド定義では、コマンドの実行可否を利用するのが良いと思います。例えば外部コマンド foo が存在しない場合にユーザ定義コマンドを定義したくない場合には以下の様にファイルの先頭に書きます。

if !executable('foo')
  finish
endif

プラグイン固有の設定

上記のリストで、番号が飛んでいるのに気付いたかもしれません。以前は使っていたけれど不要になったので消した為です。これにより、プラグインを足したり消したりする際にゴミが残ってしまう問題を解決しました。

これらの設定で注意する事は、プラグインの有無をチェックする事です。プラグインをチェックする為には、globpath 関数を使ってスクリプトの存在を確認する方法を使います。

例えば vim-lsp の設定ファイル 200-lsp.vim の先頭には以下の様に書いています。

if empty(globpath(&rtp, 'autoload/lsp.vim'))
  finish
endif

こうする事で、vimrc の Plug 行をコメントアウトしても正常に Vim が起動できる様になります。例えば何かの拍子に環境が変わり、プラグインが正常に動作しなくなった場合には、そのプラグインを読み込みを停止してしまえば合わせて設定も無効になってくれる、という仕組みです。

おわりに

以上が、次第に汚くなりがちな vimrc を綺麗に保つために僕が行き着いた方法です。個人的な趣味ですので、皆さんには合わないかもしれませんが、幾らかは盗んで頂ける物があるかもしれません。
Posted at by



2019/11/04


はじめに

今年も Vim の国際会議 VimConf 2019 に参加してきました。本格的に国際会議という位置づけに移ってからほぼ4年目、その内3年をスタッフとして参加させて頂きました。

昨年、Vim の作者 Bram Moolenaar 氏を呼べたのはもちろん素晴らしい事ですが、今年も vim-lsp の作者である Prabir Shrestha 氏、neovim のメインメンテナである Justin M. Keyes 氏に登壇頂けたのは、企業スポンサー様の皆さま、個人スポンサーの皆さま、そして当日会場を盛り上げて頂いた皆さまのおかげです。ありがとうございました。

参加したいと思いながらもなんとなく尻込みして来れなかった方、非常に残念です。良い話が沢山聞けました。スライドが後から公開されると思いますが、これだけは言っておきます。熱量やそれを見ている会場の皆さんの期待、懇親会で Vim と関係ない話で盛り上がったり、二次会で Ruby on Ralis のコミッタから OSS とは、英語とは、について聞けるチャンスは、参加しないと得られません。

とまぁ Twitter のタイムラインで「#vimconf」を検索して沢山の感想を頂いているのを見るとスタッフとして関わってきて良かったなぁと毎度思います。

スタッフ業

今年は我々スタッフがこれまで作りたかった物がようやく形として出来上がり始めている感じがしました。

ここ数年、我々は VimConf の敷居をグッと上げました。意図的にではなく我々自身、中途半端な物は出せないだろうと無意識に敷居を上げたのだと思います。発表者の選定、ゲストの選定、パンフレット、色々な物に気を使い、悪くなる可能性を排除し、誰もが納得する最良を目指しました。

一部選定に漏れた方、本当に申し訳ないです。皆さんから数百文字(多い人だと数千字)ある様な熱のこもった プロポーザルを送って頂きました。スタッフも深夜まで何回も読み、議論し、情け容赦なしに決めさせて頂いた結果です。ご了承下さい。

そしてスタッフの皆さんも結構な私生活の時間を割いて VimConf 業に力を注いでくれました。司会者、スタッフ、発表者の3役を担当した mopp さん、ドラ係や懇親会の司会、その他裏で皆を取りまとめ「自分から動く事」を常に忘れなかった aomoriringo さん、そしてそれをサポートし続けた guyon さん、kaoriya さん、ujihisa さん、okuramasafumi さん、tihnca さん、aiya さん、本当に皆さん頑張ったと思います。開催を終えた翌日の今朝、スタッフの一部とアイスコーヒーを飲みながら反省会をしていました。若干燃え尽き症候群ぽかったですが、皆「成功してよかったね」と思っていたに違いないです。

ただ規模が大きくなるにつれ、誰かに負担が偏ってしまいがちになるので、それは今後の課題としなければなりません。落ち着いた頃にスタッフで話し合わないといけないですね。

トークの内容

さて内容ですが、とにかく vim-lsp と Go が沢山出てくる VimConf でした。中には Go を使う為に Vim を触りだしたという方もいらっしゃいました。スタッフとしてウロウロしていたので全ての発表は聞けなかったのが残念ですが、個人的に3つ挙げるとすると以下の様になります。

Prabir Shrestha 氏

vim-lsp の作者としてどの様に vim を複数の言語をシームレスに扱えるエディタにするか、その工夫等をお話頂きました。僕も vim-lsp のメンテナとして興味深く聞かせて頂きました。懇親会でも少しお話させて頂きましたが、編集中にも補完候補がシャカシャカと表示され、間違ったコードにマーカーが付く、こんな事が数年前だと実現できなかった Vim を今の操作感に持って行ったのは vim-lsp による貢献が大きいと個人的には思っています。

Justin M. Keys 氏

Vim に限らずソフトウェアという物を fork する場合、それは既に揺るぎない基本設計が出来上がった物であり、それに乗っかる事のメリットは大きいという話をして頂きました。neovim のメンテナとして、vim 色を残しつつ違う vim を作っていく意気込みが聞けて良かったです。

daisuzu 氏

毎年、安定した発表をされていてそれだけでも凄い事だと思いますが、タグジャンプという Vim 特有の機能を分かりやすく会場にいる多くの皆さん沢山届く発表をして頂いたと思います。タグジャンプは Vimmer の基本です。使った事が無かったのであれば、ぜひ習得してみて欲しいです。

その他にも熱のこもった発表が沢山あり「Vimmer っていっぱいいるんだなぁ」と感じさせて頂ける内容ばかりでした。

懇親会でLTをさせて頂き「RESTサーバを5分で作れる、そう Vim ならね」と題して sqlite3 を使って JSON を返す echo を使ったサーバを5分で作るデモをお見せしました。お酒が入っていたので rows.Close() を呼びだすのを忘れていましたが、普段僕がどんな感じにコーディングしているのかをお伝え出来たと思います。

おわりに

我々スタッフは、こういった素晴らしい発表を皆さんが聞き、また次の回にも参加したい、そう思ってくれる事を願ってスタッフ業をやっています。ブログで VimConf の内容を語って頂くのもよし、会社で「VimConf 楽しかったよ」と同僚にお伝え頂くのもよし、懇親会で Vim にまったく関係ない話で盛り上がって頂くのもよし、今回の VimConf をきっかけにどこかに転職/就職が決まるもよし、すべての Vim をトリガにした動きが我々スタッフの望みです。

個人的には僕の GitHub Sponsors をして頂いている数名の方にご挨拶できた事、古くから Vim の活動をされている kana さんと挨拶だけでもできた事、Go のユーザが沢山いるのを知れた事は、とても良かったです。

これも Vim をトリガにした「人と人が繋がれるキッカケ」ですよね。次の回、どういう風になるのかは分かりませんが、また「人と人が繋がれるキッカケ」が提供される VimConf になる事を願っています。

そして Vim に関してどんどん新しい人が入ってきていて、僕もそろそろアウトプットではなくインプットをしないといけないな、そう感じる VimConf でした。

Posted at by



2018/12/25


先日、Go Advent Calendar の記事の中で Language Server について書きました。

Big Sky :: gocode やめます(そして Language Server へ)

はじめに まず始めに言っておかなければなりません。 gocode 今まで本当にありがとう この記事は、Go 言語歴10年になる僕がこれまで愛用してきた Go 言語のコード補完ソフトウェア gocode...

https://mattn.kaoriya.net/software/lang/go/20181217000056.htm

僕は Vim を使っていて、幾らかの言語の開発環境は vim-lsp に移行できたのですが C/C++ を扱うケースだけ vim-lsp に移行できず vim-clang を使ってきました。C/C++ は clangd という Language Server を使うのだけど何故か clangd サーバがうまく補完候補を出してくれませんでした。調べてみると clangd は vim-clang の様に .clang ファイルを読み取ってくれず、compile_commands.json というファイルを読み取っているらしいのです。フォーマットは以下の様になっています。

[
 {
  "directory": "C:/dev/foo",
  "arguments": [
   "gcc",
   "-c",
   "-I.",
   "-DWIN32",
   "-s",
   "foo.c",
   "-o",
   "foo.o"
  ],
  "file": "foo.c"
 }
]

一つ二つなら自分で書く事も出来るのですが、ソースファイルが沢山ある場合にこんなの作ってられません。cmake を使っているプロジェクトであればこれを自動で生成してくれる方法があるらしいのですが、Makefile からは作ってくれません。これを自動で作る方法無いかなと調べていたら compiledb というコマンドがある事に気付きました。

GitHub - nickdiego/compiledb: Tool for generating Clang's JSON Compilation Database files for make-based build systems.

Compilation Database Generator Tool for generating Clang's JSON Compilation Database file for GNU ma...

https://github.com/nickdiego/compiledb

このコマンドを以下の様にインストールします。

pip3 install compiledb

インストールしたらいつもの make の手順に compiledb を付けて以下の様に実行します。

compiledb make

すると全てのビルドが終わったタイミングで compile_commands.json が生成されます。後は vim-lsp から補完を行えば vim-clang よりも高速に入力補完が行える様になります。

快適~

Posted at by