オプションの追加方法(とおまけ)
@KSuzukiiさんがおもしろいこと始めたようでブログに載ってました。set nuの数字との区切り文字を変更できるようにするという壮大な計画!
自由に設定出来るようにするにはどうすればいいんだろう?
Vim:行数と文字との間を空白文字以外にしたい - LSI設計雑記帳 http://lsifrontend.blog100.fc2.com/blog-entry-231.html
とのことだったので、ちょうど昨日やったやつと共にちょっとした説明など。
何してたのか?
実は随分前に set nu のナンバリングを特定の位置からの相対値にする(http://d.hatena.ne.jp/tkuro/20081219/1229676014)、というのをやったのですが、あのあとしばらくなにもせずに放置していたら、vimのほうでいつの間にか 'relativenumber' というのが追加されていたみたいです。これを使うと、「現在のカーソルの位置」からの相対値表示ができます(カーソルを動かすとグリグリうごくw)。値は abs() してあって上方向も正の値になってます。すなわち、あくまでvim的に「上 14k」とか「うりゃっ 14dd」のように華麗に行移動するためのものであって、僕の目的である「行数えてよ。」とはちっと違います。
とっとと弄ってしまいましょ。と。
#source は hg clone https://vim.googlecode.com/hg/ vim で最新版拾って来ました。
どこいじるのか?
とりあえずまずはオプションをつけるとこまでやります。
src/option.cを見ると最初の方にコメントにて
/* * Code to handle user-settable options. This is all pretty much table- * driven. Checklist for adding a new option: (1)- Put it in the options array below (copy an existing entry). * - For a global option: Add a variable for it in option.h. * - For a buffer or window local option: (2) - Add a PV_XX entry to the enum below. (3) - Add a variable to the window or buffer struct in structs.h. (4) - For a window option, add some code to copy_winopt(). * - For a buffer option, add some code to buf_copy_options(). * - For a buffer string option, add code to check_buf_options(). (-)- If it's a numeric option, add any necessary bounds checks to do_set(). * - If it's a list of flags, add some code in do_set(), search for WW_ALL. * - When adding an option with expansion (P_EXPAND), but with a different * default for Vi and Vim (no P_VI_DEF), add some code at VIMEXP. (-)- Add documentation! One line in doc/help.txt, full description in * options.txt, and any other related places. (-)- Add an entry in runtime/optwin.vim. * When making changes: (-)- Adjust the help for the option in doc/option.txt. (-)- When an entry has the P_VIM flag, or is lacking the P_VI_DEF flag, add a * comment at the help for the 'compatible' option. */
と全てやり方が書いてあります*1。
今回やってみようかなーというものに番号を振って見ました。do_set()での範囲チェックとか必要無いのでカットです。。。
ドキュメントどうしようかなー。
さてさて、まずは(1)。src/option.c に options[] というvimoption 構造体の配列があります。ここに追加するようです。
どんなふうに?
順番に
{ "オプション名", "短縮名", フラグ, オプション変数へのポインタ, ローカルインデックス(グローバルな場合PV_NONE), { vi 向けの初期値, vim 向けの初期値 }, SCRIPT_INIT(ここはvimが面倒みてくれます) }
今回みたいに window-local なオプションの場合、少し注意が必要ですが、まあまあ直感的(?)。
以下順番に。
- 名前を決めます
- 今回は 'numbertop', 'nbt' としました
- フラグを決定
- P_NUM|P_VIM|P_RWIN (数値、vim専用フラグ、変更されたら即画面更新) で
- オプション変数へのポインタ
- これはwindow-localの場合 VAR_WIN で(詳しくはoption.cの該当コメントを参照してください)
- ローカルインデックス
- ここでは PV_NBT としました。
- 初期値
- 両方 0
てな感じ。
(2) ローカルインデックス
ローカルインデックスはwindow-local(またはbuffer-local)な変数を取得するためのインデックスですね。'number'のエントリWV_NU を真似して、WV_NBTエントリをつくり、そこからOPT_WIN(WV_NBT)でPV_NBTエントリを作りました。
(3) ウィンドウ構造体に変数追加
structs.h にwinopt_Tな構造体があります。ここに追加します。今回は負の数も使いたかったのでlongにしました。
(4) copy_winoptにコピーコード追加
他の真似して追加するだけですね。
さてやってみよう(まずはオプション動作確認だけ)
実際に上記の作業をしてみます。diffがわかりやすいのかどうかわかりませんが、とりあえずhg diffにて、
diff -r 54d621a3b561 src/option.c --- a/src/option.c Thu Jan 26 20:58:26 2012 +0100 +++ b/src/option.c Fri Jan 27 18:32:21 2012 +0900 @@ -209,6 +209,7 @@ #endif #define PV_NU OPT_WIN(WV_NU) #define PV_RNU OPT_WIN(WV_RNU) +#define PV_NBT OPT_WIN(WV_NBT) #ifdef FEAT_LINEBREAK # define PV_NUW OPT_WIN(WV_NUW) #endif @@ -1868,6 +1869,9 @@ {"number", "nu", P_BOOL|P_VI_DEF|P_RWIN, (char_u *)VAR_WIN, PV_NU, {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT}, + {"numbertop", "nbt", P_NUM|P_RWIN|P_VIM, + (char_u *)VAR_WIN, PV_NBT, + {(char_u *)0L, (char_u *)0L} SCRIPTID_INIT}, {"numberwidth", "nuw", P_NUM|P_RWIN|P_VIM, #ifdef FEAT_LINEBREAK (char_u *)VAR_WIN, PV_NUW, @@ -9610,6 +9614,7 @@ case PV_FMR: return (char_u *)&(curwin->w_p_fmr); #endif case PV_NU: return (char_u *)&(curwin->w_p_nu); + case PV_NBT: return (char_u *)&(curwin->w_p_nbt); case PV_RNU: return (char_u *)&(curwin->w_p_rnu); #ifdef FEAT_LINEBREAK case PV_NUW: return (char_u *)&(curwin->w_p_nuw); @@ -9804,6 +9809,7 @@ to->wo_list = from->wo_list; to->wo_nu = from->wo_nu; to->wo_rnu = from->wo_rnu; + to->wo_nbt = from->wo_nbt; #ifdef FEAT_LINEBREAK to->wo_nuw = from->wo_nuw; #endif diff -r 54d621a3b561 src/option.h --- a/src/option.h Thu Jan 26 20:58:26 2012 +0100 +++ b/src/option.h Fri Jan 27 18:32:21 2012 +0900 @@ -1067,6 +1067,7 @@ #endif , WV_NU , WV_RNU + , WV_NBT #ifdef FEAT_LINEBREAK , WV_NUW #endif diff -r 54d621a3b561 src/structs.h --- a/src/structs.h Thu Jan 26 20:58:26 2012 +0100 +++ b/src/structs.h Fri Jan 27 18:32:21 2012 +0900 @@ -169,6 +169,8 @@ #define w_p_list w_onebuf_opt.wo_list /* 'list' */ int wo_nu; #define w_p_nu w_onebuf_opt.wo_nu /* 'number' */ + long wo_nbt; +#define w_p_nbt w_onebuf_opt.wo_nbt /* 'numbertop' */ int wo_rnu; #define w_p_rnu w_onebuf_opt.wo_rnu /* 'relativenumber' */ #ifdef FEAT_LINEBREAK
実行してみて各windowで異なる値が設定できることを確認します。おー、できてる。
良さげなので一回commit。
行番号のところを弄る
仕様としては
- numbertop = 0 の時
- 通常動作。カーソル位置が原点。
- numbertop > 0 の時
- 設定した値の行を原点として固定。原点より上もプラス表示(abs)
- numbertop < 0 の時
- 設定した値の行を原点として固定。原点より上はマイナス表示
とします。
ちらと見るとmisc2.c のget_cursor_rel_lnum()をいじれば良いことがわかります。
んで、オプションの値にはMAGICALな変数 curwin からアクセスできます。 curwin->w_p_nbtですね。
つわけで、おもむろに。
diff -r adff37f40674 src/misc2.c --- a/src/misc2.c Fri Jan 27 18:36:17 2012 +0900 +++ b/src/misc2.c Fri Jan 27 18:55:25 2012 +0900 @@ -515,6 +515,15 @@ #endif retval = lnum - cursor; + if (curwin->w_p_nbt > 0) { + retval -= curwin->w_p_nbt - cursor; + } else if (curwin->w_p_nbt < 0) { + retval += curwin->w_p_nbt + cursor; + return retval; + } + + retval = labs(retval); + return retval; } diff -r adff37f40674 src/screen.c --- a/src/screen.c Fri Jan 27 18:36:17 2012 +0900 +++ b/src/screen.c Fri Jan 27 18:55:25 2012 +0900 @@ -2321,7 +2321,7 @@ num = (long)lnum; else /* 'relativenumber', don't use negative numbers */ - num = labs((long)get_cursor_rel_lnum(wp, lnum)); + num = (long)get_cursor_rel_lnum(wp, lnum); sprintf((char *)buf, "%*ld ", w, num); #ifdef FEAT_RIGHTLEFT @@ -3481,7 +3481,7 @@ num = (long)lnum; else /* 'relativenumber', don't use negative numbers */ - num = labs((long)get_cursor_rel_lnum(wp, lnum)); + num = (long)get_cursor_rel_lnum(wp, lnum); sprintf((char *)extra, "%*ld ", number_width(wp), num);
あとがき
マイナスの場合widthが足りなくなるので補正しなければ、なのとか、get_cursor_rel_lnum()がfoldの計算を変なふうにやってるので(実際に順に追っかけて見てる)微妙にカーソル位置によっておかしくなったりするんだけど、とりあえずはおっけー。
そのうち治そう。
結論
以上、参考になるでしょうか?
わかりにくかったらツッコミお願いしますー
*1:実は僕は読まずにやってしまった ,,,,,