Vim script でメニューを追加&日本語化する際のノウハウ
restart.vim と open-browser.vim で 日本語化されたメニューを提供しているのですが、メニューは無効化していたり使わない人も多く、あまりノウハウが Web 上に無いのでここに記載しておきます。
目次
- メニューを追加するタイミング
- メニューを追加するかどうかのフラグ
- メニューを日本語化したい
- メニューを選んだ際に実行される Vim script の式とモード
- メニューにセパレーターを追加したい
- メニューを任意の位置に配置したい
- 実際のコード例
- オチ
1. メニューを追加するタイミング
plugin/*.vim
の GUIEnter でメニューを追加する処理を行っています。
理由は以下の通りです。
- メニューは CUI では使われない機能のため
2. メニューを追加するかどうかのフラグ
restart.vim では g:restart_no_default_menus
という変数が (.vimrc で定義される等して) すでに存在し、かつ0であれば読み込むようになっています。
(この変数はメニューを「追加させない」ための変数なので、0以外 (真) であればメニューを読み込みません)
しかし、そのデフォルト値をどうすべきかについてはよく考える必要があります。
というか実際によく考えずに読み込むようにしていたら thinca さんから
「set guioptions+=M
してメニューを無効化しているのにrestart.vim のメニューだけ出てきてしまう」
と膝に矢報告を受けてしまいました。
なので私見ですが、デフォルト値は
「'guioptions' オプションに "M" が含まれていたら1、そうでなければ0」
が良いと思われます。
Vim script の式で書くとこうでしょうか。
echo (&guioptions =~# 'M')
以下のいずれかの場合にメニューを読み込まないようにするには、 次のような Vim script になります。
g:restart_no_default_menus
という変数が存在しない- あるいは値が0である
- あるいは
'guioptions'
オプションに "M" が含まれる場合
if !get(g:, 'restart_no_default_menus', (&guioptions =~# 'M')) " File.Restart を選ぶと「:Restart<CR>」を実行する anoremenu File.Restart<Tab>:Restart :Restart<CR> endif
get({dict}, {key} [, {default}])
は {dict} に {key} があればそれを返し、なかったら {default} を返します。
3. メニューを日本語化したい
:menutrans
を使用します。
これも thinca さんに教えてもらった機能で、Vim ではデフォルトでメニューの翻訳機能を Vim script から使用することができます。
例として $VIMRUNTIME/menu_ja_jp*.vim
を参考にしました。KoRoN++
restart.vim は
g:restart_menu_lang
(存在するならこれ)'langmenu'
オプション (空文字じゃないならこれ)v:lang
(上記にマッチしないならこれ)
を順番に見て、それぞれ ja
で始まるならメニューを日本語化しています。
具体的には次のようなコードです。
if get(g:, 'restart_menu_lang', &langmenu !=# '' ? &langmenu : v:lang) =~# '^ja' runtime! lang/restart_menu_ja.vim endif
条件文で ja
で始まるかどうかを判定し、真であれば
'runtimepath'
オプション中の (lang
ディレクトリに入れるのが定石のようなので) lang/restart_menu_ja.vim
を読み込むようにしています。
また、ファイルを分ける場合はデフォルトのメニューの翻訳 ($VIMRUNTIME/lang/menu_*.vim
) と被らないようなファイル名が好ましいと思われます。
lang/restart_menu_ja.vim
の中身は以下の通りです。
if exists("did_restart_menu_trans") finish endif let did_restart_menu_trans = 1 let s:save_cpo = &cpo set cpo&vim scriptencoding utf-8 menutrans &Restart<Tab>:Restart 再起動(&R)<Tab>:Restart let &cpo = s:save_cpo unlet s:save_cpo
:menutrans
の引数の &Restart<Tab>:Restart
の部分は
:anoremenu
の第1引数から親のメニューの指定を取ったものと同じである必要があります。
(ちなみに <silent>
等も指定できるので、必ずしも第1引数になるとは限りません)
anoremenu File.Restart<Tab>:Restart :Restart<CR>
4. メニューを選んだ際に実行される Vim script の式とモード
今まで平然と :anoremenu
を使ってきましたが、
メニューを追加するにはマッピングと同じくモードを指定できます。
しかし、:anoremenu
を使えば概ねうまく動くメニューを作成してくれます。
例: > :amenu File.Next :next^M は以下と同じである: > :nmenu File.Next :next^M :vmenu File.Next ^C:next^M^\^G :imenu File.Next ^\^O:next^M :cmenu File.Next ^C:next^M^\^G :omenu File.Next ^C:next^M^\^G
ただし open-browser.vim では
- 実行しているキーマッピングはノーマルモードとビジュアルモードでのみ提供している
:amenu
はインサートモード等他の余計なモードについても定義してしまう
:amenu
ではビジュアルモードのマッピングに余計なマッピングが付加されてしまう- 上記の
:vmenu
のマッピング参照
- 上記の
という理由から :amenu
は使用していません。
詳しくは :help :amenu
を参照してください。
5. メニューにセパレーターを追加したい
-
で始めて -
で終わる項目を定義すれば良いです。
anoremenu File.-RestartSep- <Nop>
詳しくは :help menu-separator
を参照してください。
6. メニューを任意の位置に配置したい
それぞれのメニュー項目には優先度と言うものが設定されていて、
:amenu
等のExコマンドの引数に指定することができます。
anoremenu 10.601 File.Restart<Tab>:Restart :Restart<CR> anoremenu 10.602 File.-RestartSep- <Nop>
私はちょうどデフォルトメニューの以下画像の位置に追加したかったので上記のような優先度にしました。
デフォルトメニューの優先度については $VIMRUNTIME/menu.vim
を参照してください。
(ちなみに File.Restart<Tab>:Restart
のように <Tab>
で分けると、以下の画像のように右端に何のマッピングを実行するかの簡単な説明 (<Tab>
の右に来る文字列) を表示することができます)
詳しくは :help menu-priority
を参照してください。
7. 実際のコード例
8. オチ
thinca: こんだけ言っておいてアレだけど、私メニューは一切使っていない…