rcmdnk's blog

使える!活かせる!マニュアルのつくり方 (実務入門)

Vimでmanを見る方法について。

manの表示を環境変数で設定

manコマンドでの表示はMANPAGERまたはPAGERという 環境変数を設定しておくとそれを使ってマニュアルを表示します 1

PAGERの方は他のプログラムも使うので、 manだけに対して使いたいものがある場合はMANPAGERに指定しておきます。

manの結果はパイプで渡される様な形で表示プログラムに渡される様で、 Vimで表示したい場合には単に

export MANPAGER=vim

としておいてもダメで、

$ man bash
Vim: Warning: Input is not from a terminal

みたいに表示されておかしくなります。

表示するためには

export MANPAGER="vim -"

の様に標準入力(stdin)を表示するように設定しておきます。

ただ、これをPAGERの方に設定しておくと git diffgit log等PAGERを使うコマンドがおかしくなるので注意。

また、manで表示されるマニュアルには表示用のシンタックス記号等が入ってる?らしく (manファイルをさらにmanコマンドが修正したもの)、 そのまま表示すると文字化けの様になる部分が出るため

export MANPAGER="col -b -x|vim -"

の様に、colコマンドをはさみます。 colは入力に色々フィルターをかけて出力しなおしてくれるコマンドで、 -bはバックスペースを消したり各word毎に余計な記号を消して?くれて、 -xでタブをスペースに変換します。

さらにもう一歩Vim側の設定を加えて

export MANPAGER="col -b -x|vim -R -c 'set ft=man nolist nomod noma' -"

こんな感じにしておくと良い感じになります。

-Rオプションで読み込み専用に。

-cでVimコマンドを実行して filetypemanにします。Vimには予めman用に シンタックスファイルも用意されてるので 2 filetypeを指定することで良い感じの色表示にしてくれます。

それから編集するわけではないのでnolistで余計な記号を映さないように。

nomodは指定する必要があるのがよく分かりませんが、 下に上げる参考ページ等大概の場所で設定してあるので取り敢えず 3

後はnoma(nomodifiable)を設定して編集そのものを禁止してしまいます。 (-Rと両方設定するのは冗長かも。)

下のページなんかだとGNUのmanだとMANPAGEにパイプを設定するのが うまくいかない、ということで

export MANPAGER="/bin/sh -c \"col -b -x|vim -R -c 'set ft=man nolist nonu noma' -\""

みたいにシェルをコマンドとして指定してその引数でパイプを使ったコマンド を呼ぶようにする必要があることもあるみたいです。

ただ、使える範囲のGNU manを使ってる様なRedHatやDebian GNU、Cygwin等では 最初の方法でそのまま上手く行きました。

Using Vim as $MANPAGER - Zameer Manji

Using vim as a man-page viewer under Unix - Vim Tips Wiki

Vimの中からHelpを開く

manで1つ開く分には上ので十分なのですが、 VimではさらにVimの中からManを呼ぶ機能が有ります。

:Manというコマンドでマニュアルが開けたりします。

が、このコマンドはVimデフォルトだと ftplugin/man.vim で定義されていて 4filetypemanの時のみに使える様になります。 使える主なコマンド/ショートカットは次の様なもの。

  • :Man <command>commandのマニュアルを表示。
  • :Man <n> <command>commandのセクションnのマニュアルを表示。
  • <C-]>でカーソル下の文字のコマンドのマニュアルを表示。
  • <C-t>で戻る。

参考: :help Man

また、コマンドに当たる文字列の上にカーソルを置いてK(または<Leader>K)を押すと :! man <command>を呼んで、外部コマンドでmanを呼びます。

参考: :help K

:Manコマンド等についてはftpluginで定義されてるので、 通常は有効化されていません。

man以外のファイルタイプでも有効にしたい場合は .vimrc

runtime ftplugin/man.vim

と書いて常に読み込む様にしておきます。 この場合でも<C-]>/<C-t>に関してはman以外のファイルタイプでは 通常のタグジャンプのマッピングになったままなので 挙動をおかしくしたりはしません。

また、K(<Leader>K)に関してはman.vimを改めて読み込まなくても 使える様になっています 5

しかし、これらのコマンドはMANPAGERPAGERが定義されていると

:! man 'bash'
sh: -c: line 0: syntax error near unexpected token `||'
sh: -c: line 0: `(cd '/usr/local/share/man' && /usr/bin/tbl '/usr/local/share/man/man1/bash.1' | /usr/bin/groff -Wall -mtty-char -Tascii -mandoc -c | ( || true))'
Error executing formatting or display command.
System command (cd '/usr/local/share/man' && /usr/bin/tbl '/usr/local/share/man/man1/bash.1' | /usr/bin/groff -Wall -mtty-char -Tascii -mandoc -c | ( || true)) exited with status 512.
sh: -c: line 0: syntax error near unexpected token `||'
sh: -c: line 0: `(cd '/usr/share/man' && /usr/bin/gunzip -c '/usr/share/man/man1/bash.1.gz' | /usr/bin/tbl | /usr/bin/groff -Wall -mtty-char -Tascii -mandoc -c | ( || true))'
Error executing formatting or display command.
System command (cd '/usr/share/man' && /usr/bin/gunzip -c '/usr/share/man/man1/bash.1.gz' | /usr/bin/tbl | /usr/bin/groff -Wall -mtty-char -Tascii -mandoc -c | ( || true)) exited with status 512.
No manual entry for bash

みたいなエラーを出したりします 6 。 定義されてるとダメなので、

$ export PAGER=

みたいに空文字にしておいても駄目。

$ unset PAGER

として変数を消して置く必要が有ります。 なので.vimrcの中で値を

let $PAGER = ''

みたいにして消しても駄目。

ということで、最初の環境変数を使った方法だと 中でさらに他のマニュアルを見たい時に上手く行きません。

ラッパー関数を作る

環境変数だけでやろうとすると不具合が出てくるので、 manコマンド自体を変更してしまいます。

こんな感じ:

.bashrc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
function man {
  local p
  local m
  if [ "$PAGER" != "" ];then
    p="$PAGER"
  fi
  if [ "$MANPAGER" != "" ];then
    m="$MNNPAGER"
  fi
  unset PAGER
  unset MANPAGER
  val=$(command man $* 2>&1)
  ret=$?
  if [ $ret -eq 0 ];then
    echo "$val"|col -bx|vim -R -c 'set ft=man' -
  else
    echo "$val"
  fi
  if [ "$p" != "" ];then
    export PAGER="$p"
  fi
  if [ "$m" != "" ];then
    export MANPAGER="$m"
  fi
  return $ret
}

vimに渡す引数の最後の-を忘れないように注意。

やってることはPAGERMANPAGERを一旦unsetした後に manを呼んであとで回復させてます。

また、manコマンドは直接vimには渡さず、 一度結果をみてエラーならそのままecho、 そうでないならvimに渡す、と言った形。

また、vimの引数にはft=manのみ指定していますが、 他のオプションは.vimrcの方で下の様に設定しています。

.vimrc
1
2
3
4
5
6
7
8
9
" Enable plugin
filetype plugin on

" Load Man command even for other file types than man.
runtime ftplugin/man.vim

" Close immediately by q, set non-modifiable settings
autocmd FileType man nn <buffer> q :q!<CR>
autocmd FileType man setlocal nospell ts=8 nolist ro nomod noma

.vimrcではpluginを有効にし、runtime ftplugin/man.vimとプラグインを読み込んで、 autocmdqのマップとsetlocalを行っています。

qの方はqだけで直ぐにファイルを閉じれる様にしているだけです。 (通常lessなどでマニュアルを開いたのと同じ様に。)

2つ目のautocmdの方でsetlocalを行っていて、ここで

  • nospell: スペルチェックを表示しない(編集するわけでもないのに特殊な用語とかをチェックしても仕方ないので)
  • ts=8: 内部から:Manした時にはcolを通して無いのでタブがVimで設定した幅になってしまうので、マニュアルで通常使われる8幅に。
  • nolist: 特殊文字を表示しない。
  • ro: readonly。内部で開いた時には-Rが渡されてないので。
  • nomod: nomodified状態に。
  • noma: nomodifiableに。

の設定に指定ます(上の環境変数の物に少し追加)。

こんな感じで設定しておくと、通常のmanコマンドで 開く時も、 Vimで何か編集中に:Manでマニュアルを開くことも、 マニュアルページで<C-]>でさらにカーソル下のマニュアルページに飛ぶことも、 Kで外部コマンドでmanを開くことも出来る様になります。

おまけ

上のautocmdについてはmanの場合だけじゃなくて、 他の場合にも有用で、 実際にはhelpqfrefなんかの場合にも設定しています。

1
2
autocmd FileType help,qf,man,ref nn <buffer> q :q!<CR>
autocmd FileType help,qf,man,ref setlocal nospell ts=8 nolist ro nomod noma

その他参考:

man ascii is misaligned when using vim as a pager - Unix & Linux Stack Exchange

Sponsored Links
  1. 使われるページャは

    • man -P <pager>で指定されたpager。
    • MANPAGERで指定されたプログラム。
    • PAGERで指定されたプログラム。

    の順で優先され使われます。 何も指定されてない場合は通常は/usr/bin/less -is

  2. syntax/man.vim

  3. nomod(nomodified)はバッファが編集されてない、という時に設定されてる値で、 :q<CR>とかで終了する時に保存してないよ、等の注意が出なくなります。 逆にバッファを編集するとmod(modified)が設定されて

    E37: No write since last change
    E162: No write since last change for buffer "a.txt"
    

    と出るようになるので:q!<CR>とする必要がでてくる、と。

    通常manで開いてる限りは最初はnomodifiedなので 必要無い気がするんですが、modifiedになってる場合もあるのかも。。。?

  4. これらのコマンドですが、 元々は manpageview というプラグインがあって、ここでも同じコマンドが定義されています。 manpageviewについて書いてあるページなどを見ると このプラグインを入れると上記のコマンドが使える、などと書いてあるので 上のftplugin/man.vimmanpageviewを元にして 入れたものな感じです。 (ftplugin/man.vimは2013年、manpageviewは2011年に最後の編集があります。)

    manpageview.vim : vimエディタ上でmanページを参照 — 名無しのvim使い

    ただ、manpageviewは古いVim用で、 含まれる manpageview/plugin/manpageview.vba を無理やり読み込もうとすると UseVimballがないといった感じのエラーが出たり、 さらに~/.vim/以下に~/.vim/autoload/等のディレクトリを作って その中にmanpageview.vim等のファイルを作ったりして邪魔な事になるので注意。

    manpageviewの方では g:manpageview_winopenというオプションがあり、 このオプションで:Manでマニュアルページを呼び出すときの Windowの表示方法を変える事が出来る様な設定があります。 hsplitとすると縦分割、vsplitとすると横分割で開けるような設定 があるのですが、ftplugin/man.vimにはありません。

    ftplugin/man.vimでは:Manコマンドでマニュアルページを開こうとすると、 filetypeがmanの場合にはその領域に新たにウィンドウを作り、 それ以外の場合にはhsplit的な縦分割をします。

    ただし、開いてるウィンドウの中にfiletypeがmanの物があると そこへ新たなウィンドウを作って開きます(2つ以上ある場合には左上の方から使う?)。

  5. <Leader>Kに関しては ftplugin/man.vim の中で定義されてる様に見えるし、 他で定義されてる様にも見えないし、 そもそもManなどは定義されてない状態ですが、 何故使えるのか良く理解できない。。。

  6. ただし、K(<Leader>K)に関しては、filetypeがmanでない場合には PAGERとかがless等に設定されてる場合は表示できます。

    この辺もちょっと謎。やはりftplugin/man.vim以外の場所い他に 設定がある?

Sponsored Links

« フォントを変更してみる(M+とかMiguとか) Vimで'ImportError: No module named site'みたいなエラーが出るようになった »

}