VimのMarkdownPreviewプラグイン「iamcco/markdown-preview」がグラフ、UML、Latexが描画できて色々やばい

「vim markdown」とか「vim plantuml」って調べると2015年とか古い記事が多く見つかる。
なんか直近で良い感じのないかな〜と探していたら素晴らしいプラグインを見つけた。

https://github.com/iamcco/markdown-preview.nvim

これ最高。PlantUML書けたらいいかなあと思っていたがそれ以上に色々描画できて、もうNumbersとかスプレッドシートとかいらずにこれ一本でいいんじゃねってなったので紹介したい。

これ一体何?

MarkdownのPreview用プラグイン。ただ内部でnodeが動いているので描画にJSが使えてとてもリッチに表示される。
他のPreviewプラグインと圧倒的に違うのは描画の種類が豊富なところ。いわゆる「テーブル」とか「チェックマーク」だけじゃなく、グラフ、Latex、シーケンス図など様々なものに対応している。
また、プレビュー用のCSSがGithubを強く意識されていて、READMEを書く時などpushしたあともほぼ見た目が変わらないのもGOOD。

インストール方法

deinでインストール

call dein#add('iamcco/markdown-preview.nvim', {'on_ft': ['markdown', 'pandoc.markdown', 'rmd'], 'build': 'cd app & yarn install' })

yarnがインストールされていないとエラーが出るのでインストールしておく

$ brew install yarn

使い方

markdownのファイル(.md)を開いて:MarkdownPreviewと打てば終了。
ブラウザが開いてプレビューされる。

グラフを表示

https://rasukarusan.github.io/blog-assets/markdown-preview/chart.gif

markdown中でchartでコードブロックを作成してその中に書く。 記法はchart.jsと同じ。
ただ一個気をつけるのはJSON形式で書いていくこと。

```chart
{
"type": "bar",
    "data": {
      "labels": ["8月1日", "8月2日", "8月3日", "8月4日", "8月5日", "8月6日", "8月7日"],
      "datasets": [
        {
          "label": "A店 来客数",
          "data": [62, 65, 93, 85, 51, 66, 47],
          "backgroundColor": "rgba(219,39,91,0.5)"
        },{
          "label": "B店 来客数",
          "data": [55, 45, 73, 75, 41, 45, 58],
          "backgroundColor": "rgba(130,201,169,0.5)"
        },{
          "label": "C店 来客数",
          "data": [33, 45, 62, 55, 31, 45, 38],
          "backgroundColor": "rgba(255,183,76,0.5)"
        }
      ]
    },
    "options": {}
}
```

勿論"type":"bar""type:"pie"に変えれば、円グラフで表示できる。

f:id:rasukarusan:20190825160717p:plain:w400
円グラフも表示可能

コードはこちらから拝借しました。

PlantUMLでUML図を書く

https://rasukarusan.github.io/blog-assets/markdown-preview/plantuml.gif

plantumlを書く場合はコードブロックで囲まずそのまま書く。

@startuml
title 家計簿アプリの家計簿取得シーケンス

participant "ユーザー"

box "家計簿システム" #LightBlue
    participant "Play"
    participant "Redis"
    participant "MySQL"
end box

"ユーザー" -> "Play" : 家計簿を取得
"Play" -> "Redis" : ユーザーID、今月という時間をキーに取得
    alt キャッシュヒット
        "Play" <-- "Redis" : 家計簿情報または家計簿がないという情報
    else キャッシュミス
        "Play" <-- "Redis" : キャッシュされていないという情報
        "Play" -> "MySQL" : 家計簿取得
        "Play" <-- "MySQL"
        alt 家計簿情報あり
            "Play" ->> "Redis" : 非同期に\n家計簿情報を格納
        else 家計簿情報なし
            "Play" ->> "Redis" : 非同期に\n家計簿がないという情報を格納
        end
    end
"ユーザー" <-- "Play" : 家計簿情報または家計簿がないという情報
@enduml

コードはこちらから拝借しました。

ガントチャートの表示

https://rasukarusan.github.io/blog-assets/markdown-preview/gantt.gif

ガントチャートはmermaidでコードブロックを作成してその中に書く。mermaid.jsを使用しているのでガントチャートの他にもシーケンス図やフローチャートも書ける。

```mermaid
gantt
      title ガントチャート
      dateFormat YYYY-MM-DD
      section 製品A開発セクション
      設計        : done,   task1, 2017-12-11,  2017-12-15
      実装        : active, task2, 2017-12-18,  5d
      単体テスト  :         task3, after task2, 5d
      結合テスト  :         task4, after task3, 5d
```

コードはこちらから拝借しました。

かわいいシーケンス図

f:id:rasukarusan:20190825160822p:plain:w400
かわいいシーケンス図

これ個人的に一番好きなんだけど、手書き風のシーケンス図が書ける。 どうやらsequence-diagramsというJSのライブラリがあるらしく、それで描画される。 sequence-diagramsでコードブロックを作成してその中に書いていけばOK。

```sequence-diagrams
Andrew->China: Says
Note right of China: China thinks\nabout it
China-->Andrew: How are you?
Andrew->>China: I am good thanks!
```

latex記法で数式を表示

f:id:rasukarusan:20190825160801p:plain
数式を美しく表示

Latexで美しく数式を表示したいときもイケる。 Latex記法でそのままmarkdown中に書いてしまえばOK。

$\sqrt{3x-1}+(1+x)^2$

$$\begin{array}{c}

\nabla \times \vec{\mathbf{B}} -\, \frac1c\, \frac{\partial\vec{\mathbf{E}}}{\partial t} &
= \frac{4\pi}{c}\vec{\mathbf{j}}    \nabla \cdot \vec{\mathbf{E}} & = 4 \pi \rho \\

\nabla \times \vec{\mathbf{E}}\, +\, \frac1c\, \frac{\partial\vec{\mathbf{B}}}{\partial t} & = \vec{\mathbf{0}} \\

\nabla \cdot \vec{\mathbf{B}} & = 0

\end{array}$$

終わり

markdownのプラグインは色々あるけどこれ一択で良いと思う。

Vimでカーソル位置下の単語をGoogle検索する

プログラムを書いていると「お、なんだこの関数?」と思いググることってよくあると思う。
そんな時一々単語をコピーし、ブラウザを開き、検索バーに打ち込んで検索している自分に腹が立った。なぜこんな無駄な動きをしているんだ。
プログラムに限らずREADMEなどドキュメントを読んでいるときも多々遭遇する。

息を吸うようにググりたい

私はエディタがVimなので本来ならターミナルから動くことは許されない。
唯一「ググる」という行為は許しているが、それでもブラウザに行くまでの動作は限りなく短いほうがよい。

今までのググるまでの道のりは以下の通り。

  1. 調べたい単語が見つかる
  2. 単語をコピーする
  3. ブラウザに移動する
  4. 検索バーにペーストする

長過ぎる...

理想は「調べたい単語が出てきた時点で既に検索が終了している」状態が望ましい。

関数作った

ということで理想に限りなく近い関数を作った。もちろんVimScriptだ。

f:id:rasukarusan:20190309011318g:plain
息を吸うように検索する

" カーソル下の単語をGoogleで検索する
function! s:search_by_google() 
    let line = line(".")
    let col  = col(".")
    let searchWord = expand("<cword>")
    if searchWord  != ''
        execute 'read !open https://www.google.co.jp/search\?q\=' . searchWord
        execute 'call cursor(' . line . ',' . col . ')'
    endif
endfunction
command! SearchByGoogle call s:search_by_google()
nnoremap <silent> <Space>g :SearchByGoogle<CR>

調べたい単語の上で<SPACE> gをタイプすれば検索された状態のブラウザを開く。 割と理想に近いと思う。

解説

特に難しいこともしていないが一応。
上の関数をシンプルに書くと以下。

" カーソル下の単語をGoogleで検索する
function! Search_by_google() 
    let searchWord = expand("<cword>")
    execute 'read !open https://www.google.co.jp/search\?q\=' . searchWord
endfunction

他の部分はエラー判定やキーバインドの設定なので無視して構わない。
調べたい単語の上で:call Search_by_google()と打てばググることができる。

やっていることは

  1. カーソル下の単語を取得
  2. Vimを開いたままシェルコマンドを実行

のみである。

1. カーソル下の単語を取得

これは

expand("<cword>>")

でゲットできる。他にもファイルパスとか取得できたりするので:help expandで調べてみると楽しいと思う。

2. Vimを開いたままシェルコマンドを実行

execute 'read !open https://www.google.co.jp/search\?q\=' . searchWord

肝はread。これを付けないで!open https://...と実行すると、

press enter or type command to continue

# もしくは

続けるにはENTERを押すかコマンドを入力してください

と出力され、VimからShellに操作を奪われてしまう。

これを回避するためにreadを使う。

readって何?

詳しくは:help readで調べてくれればいいが、ざっくりいえばコマンドの出力をVimにそのまま貼り付けるコマンド。

例えば

:read !ls

" もしくは
:r !ls

と実行すると、lsの結果がVimに出力される。

もしくはreadを使わなくても、Shift+V→:!lsのようにVisualモードに切り替えてから実行しても同じ結果が得られる。
shellコマンドのopenは出力を返すものではないので、Vim上に出力されるものがない=Shellに操作を奪われずVim上で実行したように見える。

ただ、readでコマンドを実行するとカーソル位置が行の最初に移動してしまうため、

let line = line(".")
let col  = col(".")
execute 'call cursor(' . line . ',' . col . ')'

でカーソル位置を実行したときの位置まで戻している。

終わり

:helpで調べてくれればいいが」と何回も言っているが、本当に:helpは有能なので騙されたと思って実行してみてほしい。きっと楽しいから。

でもVimで欲しい情報を得たい時、phpとかをググるより難しいな。欲しい情報が中々出てこない。
今回だったらshellに操作を奪われないためにどうするかに結構悩み、「"press enter or type command to continue" vim」でググっていたがわからなかったので、とりあえずvim.jpを読んでみた。偶然readを見つけることができたからいいが、もうちょっとググり力を上げたい。

まあでも道中で知らないVimのコマンド知ることできたし、こういう遠回りは積極的にしていきたい。

【Tips】Vimで先頭と末尾に文字を挿入する

コマンド一発で先頭と末尾に文字を挿入したいときってあるじゃん。
そんな時にどうするかって話。

方法

とりあえず結論から話すと以下のコマンドでいける。

:%s/^/先頭に入れたい文字/g | %s/$/行末に入れたい文字/g

パイプで繋げれば良かったんやな。 %sのところは'<,'>とか自由に変えてくれればいい。

どんなときに必要か

例えば以下のようなデータファイルがあるとする。

username.txt

Aaron
Adam
Adrian
Aidan
Alexander
Andrew
.....

これをプログラム中で配列に持ちたい時、例えばphpならこんな形にしたい。

<?php

$usernames = array(
    'Aaron',
    'Adam',
    'Adrian',
    'Aidan',
    'Alexander',
    'Andrew',
);

先頭と末尾にシングルクォートないしダブルクォートを挿入したい時って結構あると思うのですよ。

今まで

  1. Ctrl+Iで先頭に文字挿入
  2. gvで再度選択し$Aで行末に文字挿入

という流れでしていた。とっても面倒くさい。

全然思考のスピードでタイプできてないし、もっと長い行数の場合に一々最下行まで選択しに行かなければならないのがナンセンスだった。

f:id:rasukarusan:20190228214115g:plain
とっても面倒くさい

これから

シングルクォートを入れたい場合は以下で一撃だ。

:%s/^/'/g | %s/$/'/g

f:id:rasukarusan:20190228004427g:plain
コマンド版

ただこれだと打つのが面倒くさいし、全選択になってしまうので使い勝手が非常に悪い。

さらにこれから

範囲選択した時/しない時の両方に対応するため関数にした。

" 行頭と行末に文字列を挿入
" 範囲選択をしていない場合全範囲が対象となる
" ex.) InTH <div> <\/div>
function! s:insert_head_and_tail(...) range
    let head = a:1 " 行頭に入れたい文字列
    let tail = a:2 " 行末に入れたい文字列

    " 範囲選択中かで実行するコマンドが違うので分岐
    if a:firstline == a:lastline
        execute ':%s/^/'.head.'/g | %s/$/'.tail.'/g'
    else 
        execute ':'.a:firstline.','.a:lastline.'s/^/'.head.'/g | '.a:firstline.','.a:lastline."s/$/".tail.'/g'
    endif
endfunction
command! -nargs=+ -range InTH <line1>,<line2> call s:insert_head_and_tail(<f-args>)

f:id:rasukarusan:20190228213755g:plain
関数版

" 行頭に「"」、行末に「",」を挿入する時  
:InTH " ",

終わり

vim楽しいなあ。shell芸みたいに今回のも色々やり方あるんだろうなあ。
alias名が毎回適当になってしまうのが若干悩み。

vim-fzfで自作関数を実行する

vim-fzf超便利。vimを使っていてまだ入れてない人は今すぐ入れたほういい。

github.com

何ができるようになるかってvim内でfzfが使える。例えばファイルを開きたい場合にめちゃくちゃ早く開ける。
こんな感じ↓(私はCtrl-pにキーバインドして使っています)

f:id:rasukarusan:20181015152034g:plain

fzf-vimに標準で入っている関数だけでも十分便利だが、自分で作った関数にfzfで選択したものを食わせたいと思ったのでやってみる。

やりたいこと

現在開いているファイルの別ブランチ版を別タブで表示したい。例えば今のブランチがtestでhoge.phpを開いている時、masterのhoge.phpを見たい場合、今までは以下のような手順を踏んでやっていた。

  1. Ctrl-zでシェルに戻る(vimから抜ける)
  2. git checkout masterでmasterブランチに移動
  3. fgvimに戻ってLで開く

動作的にはこんな感じ。

f:id:rasukarusan:20181015151507g:plain

めちゃくちゃ面倒くせえ....ただmasterブランチのファイルを見たいだけなのに一々shellに戻るのが非常にナンセンス。
理想の動きは「shellに戻らず、vim内でブランチを選ぶだけ」。
ということで実現のために必要なことをまとめてみる。

  1. ブランチ名を指定したら今開いているファイルをそのブランチ版で開く自作関数を作る
  2. 任意のコマンドの結果をvim内のfzfで表示
  3. fzfで選択した結果をvim自作関数に突っ込む

1. ブランチ名を指定したら今開いているファイルをそのブランチ版で開く自作関数を作る

これはvimプラグインtpope/vim-fugitiveを入れてたら余裕でした。

:Gtabedit ブランチ名:%

で現在開いているファイルを別ブランチ版で開くことができます。
作った関数はこちら。

.vimrc

" Gtabeditを簡単に実行できるようにした関数 "
function! s:alias_Gtabedit(...)
    if a:0 == 0
        let branch_name = 'master'
    else
        let branch_name = a:1
    endif
    execute ':Gtabedit '.branch_name.':%'
endfunction

" :Co ブランチ名 でそのブランチのソースをタブ表示 "
command! -nargs=? Co call s:alias_Gtabedit(<f-args>)

これで:Co hoge_branchのようにブランチを指定するだけで現在開いているファイルを別ブランチ版で見ることが可能に。
ちなみにCocheckou-outの略です。masterブランチを参照することが多かったので引数に何も指定しない場合は自動でmasterブランチを指定するようにしました。

2. 任意のコマンドの結果をvim内のfzfで表示

さてここからが本番です。vim-fzfにどうやって任意のコマンド結果を食わせることができるのか調べてみました。

READMEを見た限り割とシンプルでした。 他にも色々とオプションがあるようですが、以下のものだけ知っておけばとりあえず実現できそうです。

  call fzf#run({
    \ 'source': '任意のshellコマンド',
    \ 'sink': '選択したものに対して行いたいvimコマンド',
    \ 'down': '40%'  " fzfを表示させる場所・幅。up / down / left / rightを指定可能。
    \ })

例えば:call fzf#run({ 'source': 'ls', 'sink': 'tabedit', 'down': '40%' })と打てばlsの結果がfzfで表示され、選択するとそのファイルを別タブで開くことができます。

3. fzfで選択した結果をvim自作関数に突っ込む

ということであとはsourceにブランチを表示するコマンドを指定し、sinkに1で作った自作関数を指定させてやればフィニッシュです。

  call fzf#run({
    \ 'source': 'git branch -a',
    \ 'sink': function('s:alias_Gtabedit'),
    \ 'down': '40%'
    \ })

さらに:Coで呼び出したいので以下のように設定。(1で書いたcommand! -nargs=? Co call s:alias_Gtabedit(<f-args>)は削除しておく)

function! s:fzf_alias_Gtabedit()
  call fzf#run({
    \ 'source': 'git branch -a',
    \ 'sink': function('s:alias_Gtabedit'),
    \ 'down': '40%'
    \ })
endfunction
command! Co call s:fzf_alias_Gtabedit()

実行画面

f:id:rasukarusan:20181015160339g:plain

まとめ

fzfになんでも食わせられるようになって一気に幅が広がった気がする。
vim-shellとかvim-fzfとか色々疎通ができるようになってくるとアイデアが湧き出てきて本当に楽しい。

Xcode9.2でXVim2を動くようにする

巷に転がっている方法ではなぜか動かなったが、苦戦しつつも解決できたので誰かの助けになればと思い書く。
結論から言うと

  1. XVim2のブランチがXcode9.2対応ブランチでなかった
  2. Xcode/Plug-ins/XVim2/XVim2/Info.plistの15〜19行目にUUIDが記述されているが、ここに筆者が使っているXcodeのUUIDがないこと

が原因だった。

手順

ざっくりすると以下の手順。

  1. Xcode9.2対応ブランチに切り替える
  2. Xcode9.2のUUIDを追加しているコミットを取り込む
  3. make、update_xcode_pluginsをしてインストール

コマンドまとめ

コミット番号とか変わるはずがないので以下のコマンドを打っていけば動作するはず。 急いでいる方はこちらをどうぞ。

# Xcodeのプラグイン置き場に移動
cd ~/Library/Application\ Support/Developer/Shared/Xcode/Plug-ins
# XVim2を落としてくる
git clone git://github.com/XVimProject/XVim2 XVim2
# ここからはXVim2ディレクトリの中で作業を行う
cd XVim2
# Xcode9.2対応ブランチを作成
git checkout -b xcode9.2 refs/tags/xcode9.2
# XCode9.2のUDIDを追加しているプルリクエストをローカルに持ってくる
git fetch origin pull/96/head:unchartedworks
# UDIDを追加したコミットを取り込む
git cherry-pick e85d3ed83018022d571474ce3bdaad3278a940f7
# XVim2をXcodeにインストール
make
update_xcode_plugins
defaults delete com.apple.dt.Xcode DVTPlugInManagerNonApplePlugIns-Xcode-9.2

以上で無事XVim2が動くはず。

詰まった箇所1:masterブランチはXcode9.2に対応していない

git logを見ていたら以下のコミットを発見

commit cca1fff54ed29798b54eb80a906260e88be4e366
Author: pebble8888 <pebble8888@gmail.com>
Date:   Sun Apr 1 15:01:47 2018 +0900

    support Xcode9.3 (not support Xcode9.2 and lower)

おやおやまさかな、、、と思い初心に帰ってREADMEを見る。

tags xcode9.2 xcode9.4 Please use appropriate tags or branches.

最初からREADME見ろよと言いたい。「適切なブランチを使ってね」と書いてある。

Xcode9.2対応ブランチに切り替える方法

git logをして「tag」で検索すると以下のような箇所が見つかるためコミット番号をコピーしてcheckoutする。 f:id:rasukarusan:20180908181637p:plain

Xcode9.2対応ブランチに切り替える

git checkout 66c6dc44edfca8a032b78294a03721ee7c51dd95 -b xcode9.2

もしくはシンプルにこっち。

git checkout -b xcode9.2 refs/tags/xcode9.2

Xcode9.2のUUIDを追加しているコミットを取り込む

ブランチを切り替えただけではXVim2は動かなかった。あとで気づいたがどうやら筆者のXcodeのUUIDがXVim2/Info.plistに記述されていないことが原因だった。
以下の記事を参考に該当のコミットを取り込む。

qiita.com

プルリクをローカルに引っ張ってくる

git chery-pickするために該当コミットをしているブランチをローカルに落とす必要がある。

git fetch origin pull/96/head:unchartedworks

コミットを取り込む

githubプルリクからコミット番号を確認してgit cherry-pickでコミットを取り込む

f:id:rasukarusan:20180908181811p:plain

git cherry-pick e85d3ed83018022d571474ce3bdaad3278a940f7

詰まった箇所2:update_xcode_plugins --unsignの罠にはまる

あとはmakeしてupdate_xcode_plugins --unsignを終了!と思いきや壁にぶつかる。 どこのページを見てもupdate_xcode_plugins --unsignのコマンドを実行しているが、以下のエラーが出る。

▶update_xcode_plugins --unsign
Looking for Xcode...

Didn't find any signed Xcode 8+ on your system.

念の為以下のコマンドでインストールしなおした。

sudo gem install update_xcode_plugins

しかし結果は変わらない。一度restoreした。

update_xcode_plugins --restore

ふとここでなんのためにupdate_xcode_plugins --unsignをするのか気になったので調べてみた。

medium.com

どうやらサードパーティプラグインXcodeで利用する場合、署名を変更しないと、Xcodeの起動がすごく遅くなる、とのこと。 それなら別にとりあえずXVim2を使いたいなら--unsignしなくてもいいんじゃね?と思ったので--unsignを外してみた。

▶update_xcode_plugins
Found:
- Xcode (9.2) [B395D63E-9166-4CD6-9287-6889D507AD6A]: /Applications/Xcode.app

Plugins:
- XVim2 (1.0)

Updating...

Finished! 🎉

It seems that you have Xcode 8+ installed!
Some plugins might not work on recent versions of Xcode because of library validation.
See https://github.com/alcatraz/Alcatraz/issues/475

Run `update_xcode_plugins --unsign` to fix this.

なんかうまくいっているっぽいのでこれで良しとした。

Xcode起動時にXVim2を読み込む

defaults delete com.apple.dt.Xcode DVTPlugInManagerNonApplePlugIns-Xcode-9.2

を打ち込みXcodeを起動する。すると以下のようなアラートが表示されるので「Load Bundle」をクリック。

f:id:rasukarusan:20180908214305p:plain

プロジェクトを開くと、、、

f:id:rasukarusan:20180908182048g:plain

感無量。 てかgit cherry-pickとか使わず普通にInfo.plistに書き込めばよかったんじゃね...

Vimでもデバッグできるんすわ(Vagrant+PHP+Vdebug)

Vimでもデバッグしたい

最近var_dumpやChrome.phpを使ったブラウザに変数を表示させるデバッグ方法に疲れてきたのでVimにデバッガ入れてみるかという話。 こんな感じでブレークポイント入れたり変数の確認とかのデバッグができます。

f:id:rasukarusan:20180729220611g:plain

環境

筆者の環境はVagrantPHPが動作しており、ソースはローカルとVagrantがマウントしている状態。 いわゆるリモートデバッグがしたいという状況です。

死ぬほど参考になったサイト

基本的には以下のサイトに従って導入したが、以下の記事ではうまくいかなかったこともあったのでそれも含めて記載します。

PHPでVim使って開発していてvar_dump()を唱えているならVim Plugin のvdebugを使ってみろって - Qiita

Vim + Vdebug + Xdebug でPHPのリモートデバッグ - Code Life

VagrantXdebugをインストール

$ vagrant ssh

# Xdebugをインストール
[vagrant@muscle ~]$ sudo pecl install xdebug-2.0.3

# Cannot find autoconf. Please check your autoconf installation and the $PHP_AUTOCONF
# ERROR: `phpize' failedと出たら以下を実行してください
[vagrant@muscle ~]$ sudo yum install autoconf

筆者の環境ではCentOSのバージョンが低く、普通にyumでインストールできなかったのでXdebugのバージョンを指定してインストールしました。 XdebugのHPから自分のPHPのバージョンに合っているXdebugのバージョンを確認。

php.iniにXdebugの設定を追加

# xdebug.soのパスを確認
[vagrant@muscle ~]$ sudo find / -name 'xdebug.so'

[vagrant@muscle ~]$ sudo vi /usr/local/lib/php.ini
# php.iniに以下を追加
[Xdebug]
zend_extension=/usr/local/lib/php/extensions/no-debug-non-zts-20192838/xdebug.so ; #<= ここはfindで見つかったxdebug.soのパス
xdebug.default_enable=1
xdebug.remote_enable=1
xdebug.remote_autostart=1
xdebug.remote_host=10.0.2.2 ; #<= Vagrantだとこのホストになるそうです。筆者の環境ではprivate_networkのIPを指定してもだめでした。
xdebug.remote_port=9001
xdebug.remote_log=/tmp/xdebug.log
xdebug.max_nesting_level=10000
xdebug.remote_connect_back=1

Xdebugを入れるとその分メモリを喰うのでphp.iniを編集してメモリの上限を上げておきます

[vagrant@muscle ~]$ sudo vi /usr/local/lib/php.ini
;memory_limit = 50M      ; Maximum amount of memory a script may consume (50MB)
memory_limit = 128M      ; Maximum amount of memory a script may consume (128MB) ; #<= Xdebugでメモリを喰うため

apacheを再起動

# vagrant reloadでも良い
[vagrant@muscle ~]$ sudo service httpd restart
httpd を停止中:                                            [  OK  ]
httpd を起動中:                                            [  OK  ]

インストールされているか確認

[vagrant@muscle ~]$ php -i | grep xdebug
xdebug
xdebug support => enabled
xdebug.auto_trace => Off => Off
xdebug.collect_includes => On => On
....
xdebug.remote_host => 10.0.2.2 => 10.0.2.2
xdebug.remote_log => /tmp/xdebug.log => /tmp/xdebug.log
xdebug.remote_mode => req => req
xdebug.remote_port => 9001 => 9001
xdebug.show_exception_trace => Off => Off
xdebug.show_local_vars => Off => Off
xdebug.show_mem_delta => Off => Off
xdebug.trace_format => 0 => 0
xdebug.trace_options => 0 => 0
xdebug.trace_output_dir => /tmp => /tmp
xdebug.trace_output_name => trace.%c => trace.%c
xdebug.var_display_max_children => 128 => 128
xdebug.var_display_max_data => 512 => 512
xdebug.var_display_max_depth => 3 => 3

上記が表示されていればインストールはOKです。
これでVagrant上の操作は終了です。ここからはローカルの設定です。

VimにVdebugをインストール

Vimデバッグするのには「Vdebug」というプラグインを使用。 github.com

deinでインストール

call dein#add('joonty/vdebug')

vimrcにVdebugの設定を追加

" ========Vdebug======== "
let g:vdebug_options= {
\    "port" : 9001,
\    "timeout" : 20,
\    "on_close" : 'detach',
\    "break_on_open" : 0,
\    "remote_path" : "",
\    "local_path" : "",
\    "debug_window_level" : 0,
\    "debug_file_level" : 0,
\    "debug_file" : "",
\    "path_maps" : {
\       '/home/yourpath/web' : '/Users/'.$USER.'/workspace/web',
\    },
\    "window_arrangement" : ["DebuggerWatch", "DebuggerStack"]
\}

上記のpath_mapsが重要です。これをVagrant上でマウントしている先のパスと合わせます。左側がVagrantのパス、右側がローカルPCのパスとなります。 また、上記では書かれていませんが"server":"127.0.0.1"という設定をよく見ます。ただ、筆者の環境ではこれを書いている限りVagrantと疎通が取れずデバッグができなかったので削除しました。(remote_pathも同じ理由で空白しています)

以下は筆者の好みでデフォルトから変更しているもの。

キー名 意味
break_on_open いきなりブレークポイントまで行くかどうか
デフォルトは1で行かないようになっている
window_arrangement デバッガ画面に表示する項目
デフォルトは"DebuggerWatch", "DebuggerStack","DebuggerStatus"の3つが指定。

Xdebug helperのインストール

ブラウザからデバッグするために以下のChrome拡張を入れます。 chrome.google.com 設定は特にありません。デバッグしたい画面で以下の画像のように「Debug」を選択するだけです。

いざ実行

F10ブレークポイントF5デバッグ開始です。 デバッガ中はF3でステップ実行、F6デバッグ終了、もう一度F6 を押すとデバッガ画面が閉じます。

F6二回押しで閉じずに:qとかで閉じるとvimが止まるか次回起動時にエラーが出るので注意してください。

vimrcでキーマップを変えることができます。デフォルトは以下になってます。

let g:vdebug_keymap = {
\    "run" : "<F5>",
\    "run_to_cursor" : "<F9>",
\    "step_over" : "<F2>",
\    "step_into" : "<F3>",
\    "step_out" : "<F4>",
\    "close" : "<F6>",
\    "detach" : "<F7>",
\    "set_breakpoint" : "<F10>",
\    "get_context" : "<F11>",
\    "eval_under_cursor" : "<F12>",
\    "eval_visual" : "<Leader>e"
\}

ちなみにこういうデフォルト値とか配列の指定どうやって見つけるの?という話だが、READMEに書いてあるのを見るのが一番だが書いていないときはソースを見に行くのが早道のときもある。 今回でいうなら.vim/dein/repos/github.com/joonty/vdebug/plugin/vdebug.vimを見てデフォルト値とか引数がわかった。vimプラグインだったらXXX.vimというのを見に行けば大体解決する(と思う)。

非常に快適だ。