Skip to content

Instantly share code, notes, and snippets.

@thinca
Created November 1, 2018 02:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save thinca/e4791ede2b8d870a7a07f06b955e3904 to your computer and use it in GitHub Desktop.
Save thinca/e4791ede2b8d870a7a07f06b955e3904 to your computer and use it in GitHub Desktop.

Vim の helpbot は裏で何をしているのか

2018-10-31 .vimconf.swp 2018 thinca

:help してますか?

  • Vim は help が充実していることで有名

  • 困ったらまずは :help

  • :help してると安心です

helpbot とは

  • チャット上で Vim の help が引ける bot

  • Vim のチャットルームにあることが多い

  • 複数の実装がある

    • 私(thinca)が作ったものもある

デモ

:help CTRM-M

:help a`

基本仕様

  • :help keyword に反応して対応する help を表示

  • タグから次のタグの直前までの範囲を表示

  • 細かい例外等もある

実装解説

  • bot 絡みの部分は省略

    • hubot で作っています
  • 与えられた keyword から help の文を出す部分

基本戦略

  1. 実際に Vim を起動する

  2. help を実行する

  3. 対象の範囲を探して出力

Vim の起動

$ vim -u NONE -i NONE -N -Z -X -R -e -s
  • -u NONE -i NONE ... 設定なし viminfo なし
  • -N ... .swp なし
  • -Z ... 制限モード
  • -X ... X なし
  • -R ... リードオンリー
  • -e -s ... バッチモード

バッチモード

  • -e -s

  • 標準入力に Ex コマンドを流し込む

  • :print など一部のコマンドの結果が標準出力に出る

実行コマンド

verbose silent help {keyword}
?\%(^\s*$\|[^*]$\)?/\*\S\+\*/;/^*\|[^*]$/-1/^\s*\*\S\+\*\|\*\S\+\*\s*\%(>\)\=$/?^[^=-].*[^=-]$?print
qall!
  • {keyword} に表示したい help のキーワード
  • 1 行目で該当の help ページにジャンプ
  • 2 行目でその内容を表示
  • 3 行目で Vim を終了

簡単でしょ?

2 行目が…

  • しかしよく見ると 2 行目が若干わかりづらい

  • 何をしているのかについて解説

2 行目の分割

  • 2 行目を意味のある単位で分割してみる
?\%(^\s*$\|[^*]$\)?
/\*\S\+\*/
;
/^*\|[^*]$/
-1
/^\s*\*\S\+\*\|\*\S\+\*\s*\%(>\)\=$/
?^[^=-].*[^=-]$?
print

全体の俯瞰

?\%(^\s*$\|[^*]$\)?
/\*\S\+\*/
;
/^*\|[^*]$/
-1
/^\s*\*\S\+\*\|\*\S\+\*\s*\%(>\)\=$/
?^[^=-].*[^=-]$?
print
  • :{開始行};{終了行}print

:print

  • :{range}print

    • {range} で指定した範囲を表示する
    • バッチモードでは標準出力へ
  • :{開始行};{終了行}print

    • {開始行};{終了行}{range}

{range}

{開始行};{終了行}
  • おなじみ {range} 指定の高度なバージョン
  • /? でパターンにマッチする行を指定
  • , の代わりに ; で区切る

{開始行}

?\%(^\s*$\|[^*]$\)?
/\*\S\+\*/
  • コマンド実行時でカーソルは help タグの行にある
  • 正規表現は複数書ける
    • 出てくる度にカーソルが移動する
  • 空行やタグの前の行へ移動
  • その直後のタグへ移動

区切り

;
  • , の代わりに ; で区切る
  • カーソル行の代わりに直前に指定した 行から次の行の探索を開始する

{終了行}

/^*\|[^*]$/
-1
/^\s*\*\S\+\*\|\*\S\+\*\s*\%(>\)\=$/
?^[^=-].*[^=-]$?

{終了行} 1 つ目

/^*\|[^*]$/
  • タグではない最初の行へ移動

{終了行} 2 つ目

-1
  • 1つ前の行に移動

{終了行} 3 つ目

/^\s*\*\S\+\*\|\*\S\+\*\s*\%(>\)\=$/
  • 次のタグまで移動
    • \*\S\+\* がタグ

{終了行} 4 つ目

?^[^=-].*[^=-]$?
  • 戻って余分な末尾を省く
  • 必ず 1 行は移動する
  • 空行や区切り行 (====) を飛ばす

完成!!

おしまい

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment