-
-
Save h-east/4360424 to your computer and use it in GitHub Desktop.
Vimのソースコードを調査して分かったことをコメントしていく。 |
src/testdir で make test する時の端末(PuTTY)の高さでテストが失敗する。
80x24の場合
Test results:
ALL DONE
80x20の場合
Test results:
ALL DONE
80x15の場合
Test results:
test37 FAILED
test47 FAILED
TEST FAILURE
80x10の場合
Test results:
test37 FAILED
test47 FAILED
TEST FAILURE
※途中でコマンドラインに「-- 継続 --」と2回表示されたので、その都度キーを押した。
80x5の場合
Test results:
test13 FAILED
test31 FAILED
test37 FAILED
test47 FAILED
test62 FAILED
test84 FAILED
test88 FAILED
TEST FAILURE
※途中でコマンドラインに「-- 継続 --」と8回ほど表示されたので、その都度キーを押した。
:new
や :split
の処理関数は ex_splitview()
からの win_split()
である。
仕様として :split
の場合はwindowローカルなオプション(wp->w_onebuf_opt)は前カレントwindowのものが引き継がれる。 :new
の場合は引き継がない。
しかし、win_split()
を抜けた時点ではどちらのコマンドもwindowローカルオプション値は前カレントwinowのものを引き継いでいる。(win_init()
が呼ばれている)
ということは、:new
の場合、以降の処理のどこかでクリアされているはずである。
以下がそのコールスタックである。
(gdb) bt
#0 clear_string_option (pp=0xd494d8) at option.c:5426
#1 0x0000000000515ad6 in clear_winopt (wop=0xd49430) at option.c:10065
#2 0x000000000041182f in get_winopts (buf=0xd4d1f0) at buffer.c:2567
#3 0x000000000045b652 in do_ecmd (fnum=0, ffname=0x0, sfname=0x0, eap=
0x7fff5ac9f890, newlnum=1, flags=1, oldwin=0x0) at ex_cmds.c:3437
#4 0x0000000000474497 in do_exedit (eap=0x7fff5ac9f890, old_curwin=0xd0a0b0)
at ex_docmd.c:7838
#5 0x0000000000473a96 in ex_splitview (eap=0x7fff5ac9f890) at ex_docmd.c:7477
#6 0x000000000046bad4 in do_one_cmd (cmdlinep=0x7fff5ac9ff08, sourcing=0,
cstack=0x7fff5ac9fa60, fgetline=0x480e8c <getexline>, cookie=0x0)
at ex_docmd.c:2681
#7 0x000000000046919f in do_cmdline (cmdline=0x0, fgetline=
0x480e8c <getexline>, cookie=0x0, flags=0) at ex_docmd.c:1122
#8 0x00000000004f58c5 in nv_colon (cap=0x7fff5aca0030) at normal.c:5417
#9 0x00000000004ee4b3 in normal_cmd (oap=0x7fff5aca0100, toplevel=1)
at normal.c:1198
#10 0x00000000005c94e4 in main_loop (cmdwin=0, noexmode=0) at main.c:1306
#11 0x00000000005c8ec2 in main (argc=6, argv=0x7fff5aca0438) at main.c:1010
インサートモードで <C-X><C-O>
してオムニ補完した場合のコールスタック(バックトレース)
(gdb) bt
#0 expand_by_function (type=13, base=0x1d3a400 "frame") at edit.c:3961
#1 0x0000000000428974 in ins_compl_get_exp (ini=0x853ae0) at edit.c:4341
#2 0x0000000000429523 in ins_compl_next (allow_get_expansion=1, count=1,
insert_match=1) at edit.c:4695
#3 0x000000000042aa68 in ins_complete (c=15) at edit.c:5366
#4 0x0000000000423b87 in edit (cmdchar=111, startln=1, count=1) at edit.c:1402
#5 0x00000000004fc485 in invoke_edit (cap=0x7fff44ffafd0, repl=0, cmd=111,
startln=1) at normal.c:9182
#6 0x00000000004fb470 in n_opencmd (cap=0x7fff44ffafd0) at normal.c:8494
#7 0x00000000004fcdd4 in nv_open (cap=0x7fff44ffafd0) at normal.c:9528
#8 0x00000000004ee7b7 in normal_cmd (oap=0x7fff44ffb0a0, toplevel=1)
at normal.c:1198
#9 0x00000000005c9144 in main_loop (cmdwin=0, noexmode=0) at main.c:1306
#10 0x00000000005c8b22 in main (argc=2, argv=0x7fff44ffb3d8) at main.c:1010
オムニ補完のpopup menu 選択表示処理のコールスタック(バックトレース)
(gdb) bt
#0 pum_set_selected (n=0, repeat=0) at popupmnu.c:490
#1 0x000000000051ff76 in pum_display (array=0x26d0a60, size=56, selected=0)
at popupmnu.c:258
#2 0x00000000004263f9 in ins_compl_show_pum () at edit.c:2982
#3 0x00000000004296b2 in ins_compl_next (allow_get_expansion=0, count=1,
insert_match=1) at edit.c:4757
#4 0x000000000042991f in ins_compl_check_keys (frequency=0) at edit.c:4855
#5 0x000000000042900b in ins_compl_get_exp (ini=0x853ae0) at edit.c:4513
#6 0x0000000000429523 in ins_compl_next (allow_get_expansion=1, count=1,
insert_match=1) at edit.c:4695
#7 0x000000000042aa68 in ins_complete (c=15) at edit.c:5366
#8 0x0000000000423b87 in edit (cmdchar=111, startln=1, count=1) at edit.c:1402
#9 0x00000000004fc485 in invoke_edit (cap=0x7fffa4207a00, repl=0, cmd=111,
startln=1) at normal.c:9182
#10 0x00000000004fb470 in n_opencmd (cap=0x7fffa4207a00) at normal.c:8494
#11 0x00000000004fcdd4 in nv_open (cap=0x7fffa4207a00) at normal.c:9528
#12 0x00000000004ee7b7 in normal_cmd (oap=0x7fffa4207ad0, toplevel=1)
at normal.c:1198
#13 0x00000000005c9144 in main_loop (cmdwin=0, noexmode=0) at main.c:1306
#14 0x00000000005c8b22 in main (argc=2, argv=0x7fffa4207e08) at main.c:1010
80x24の端末で s して _ した後のtopframeの情報(struct frame_S)
./vim -N -u NONE -c "set ls=2"
(gdb) p *topframe
$8 = {fr_layout = 2 '\002', fr_width = 80, fr_newwidth = 0, fr_height = 23,
fr_newheight = 0, fr_parent = 0x0, fr_next = 0x0, fr_prev = 0x0, fr_child =
0x1aad960, fr_win = 0x0}
(gdb) p *topframe->fr_child
$10 = {fr_layout = 0 '\000', fr_width = 80, fr_newwidth = 0, fr_height = 21,
fr_newheight = 0, fr_parent = 0x1a9b740, fr_next = 0x1ad86f0, fr_prev = 0x0,
fr_child = 0x0, fr_win = 0x1ad6f80}
(gdb) p topframe->fr_child->fr_win->w_height
$14 = 20
(gdb) p *topframe->fr_child->fr_next
$11 = {fr_layout = 0 '\000', fr_width = 80, fr_newwidth = 0, fr_height = 2,
fr_newheight = 0, fr_parent = 0x1a9b740, fr_next = 0x0, fr_prev = 0x1aad960,
fr_child = 0x0, fr_win = 0x1a980b0}
(gdb) p topframe->fr_child->fr_next->fr_win->w_height
$16 = 1
- fr_layout = 2 (FR_COL) ということはそのframe自体はwindowを持たず、子frameに上下分割されたframeを持っていることを表している。(FR_ROWの場合は左右分割)
- 各子frameの fr_layout = 0 (FR_LEAF) というのはwindow情報を持っているframeだということ。
インサートモードで してファイル名補完を処理した時の動作デバックする時の取っ掛かりbreakpoint
ins_complete() [edit.c:5180] 辺りにbreakpointをセットする。
5176 else if (ctrl_x_mode == CTRL_X_FILES)
5177 {
5178 while (--startcol >= 0 && vim_isfilec(line[startcol]))
5179 ;
5180 compl_col += ++startcol;
5181 compl_length = (int)curs_col - startcol;
5182 compl_pattern = addstar(line + compl_col, compl_length,
5183 EXPAND_FILES);
b pathcmp
してインサートモードで ファイル名補完を開始してbreakした時のバックトレース
(gdb) bt
#0 pathcmp (p=0x23e4ba0 "J4.txt", q=0x23e4bc0 "I1.txt", maxlen=-1)
at misc2.c:6102
#1 0x00000000004d9758 in pstrcmp (a=0x23e4aa8, b=0x23e4ab0) at misc1.c:9787
#2 0x0000003346637d72 in msort_with_tmp.part.0 () from /lib64/libc.so.6
#3 0x0000003346637b5a in msort_with_tmp.part.0 () from /lib64/libc.so.6
#4 0x0000003346637b44 in msort_with_tmp.part.0 () from /lib64/libc.so.6
#5 0x00000033466380ac in qsort_r () from /lib64/libc.so.6
#6 0x00000000004d9eb9 in unix_expandpath (gap=0x7fff0da465a0, path=
0x23e46a0 "*", wildoff=0, flags=43, didstar=0) at misc1.c:10001
#7 0x000000000051de2a in mch_expandpath (gap=0x7fff0da465a0, path=
0x23e46a0 "*", flags=43) at os_unix.c:5471
#8 0x00000000004db08e in gen_expand_wildcards (num_pat=1, pat=0x855008,
num_file=0x7fff0da46674, file=0x7fff0da46678, flags=43) at misc1.c:10577
#9 0x00000000004d9427 in expand_wildcards (num_pat=1, pat=0x855008, num_file=
0x7fff0da46674, file=0x7fff0da46678, flags=43) at misc1.c:9323
#10 0x0000000000428ae8 in ins_compl_get_exp (ini=0x855020) at edit.c:4333
#11 0x0000000000429759 in ins_compl_next (allow_get_expansion=1, count=1,
insert_match=1) at edit.c:4707
#12 0x000000000042ac9e in ins_complete (c=6) at edit.c:5378
#13 0x0000000000423cfb in edit (cmdchar=105, startln=0, count=1) at edit.c:1402
#14 0x00000000004fcc69 in invoke_edit (cap=0x7fff0da46980, repl=0, cmd=105,
startln=0) at normal.c:9218
#15 0x00000000004fcc02 in nv_edit (cap=0x7fff0da46980) at normal.c:9191
#16 0x00000000004eeed7 in normal_cmd (oap=0x7fff0da46a50, toplevel=1)
at normal.c:1199
#17 0x00000000005ca166 in main_loop (cmdwin=0, noexmode=0) at main.c:1322
#18 0x00000000005c9ac3 in main (argc=11, argv=0x7fff0da46d88) at main.c:1013
7.3.1004で nfa_regcomp_start()
にbreak張って
/\_.*
したときのback trace.
(gdb) bt
#0 nfa_regcomp_start (expr=0xfbad00 "\\_.*", re_flags=1) at regexp_nfa.c:229
#1 0x0000000000543e07 in nfa_regcomp (expr=0xfbad00 "\\_.*", re_flags=1)
at regexp_nfa.c:3664
#2 0x0000000000544217 in vim_regcomp (expr_arg=0xfbad00 "\\_.*", re_flags=1)
at regexp.c:7827
#3 0x0000000000556fb5 in search_regcomp (pat=0xfbad00 "\\_.*", pat_save=0,
pat_use=2, options=0, regmatch=0x7fff7ddfab40) at search.c:216
#4 0x0000000000557925 in searchit (win=0xfa40c0, buf=0xfa59b0, pos=
0x7fff7ddfad80, dir=1, pat=0xfbad00 "\\_.*", count=1, options=12, pat_use=
2, stop_lnum=0, tm=0x0) at search.c:560
#5 0x0000000000558f68 in do_search (oap=0x7fff7ddfaf70, dirc=47, pat=
0xfbad04 "", count=1, options=542, tm=0x0) at search.c:1356
#6 0x00000000004fa4bc in normal_search (cap=0x7fff7ddfaea0, dir=47, pat=
0xfbad00 "\\_.*", opt=512) at normal.c:6433
#7 0x00000000004fa40b in nv_search (cap=0x7fff7ddfaea0) at normal.c:6400
#8 0x00000000004f13e1 in normal_cmd (oap=0x7fff7ddfaf70, toplevel=1)
at normal.c:1200
#9 0x00000000005d7652 in main_loop (cmdwin=0, noexmode=0) at main.c:1329
#10 0x00000000005d6faf in main (argc=7, argv=0x7fff7ddfb2a8) at main.c:1020
↑の続き。gdbでcして無限ループに陥った状態で ctrl-c で止めた時の back trace
(gdb) bt
#0 0x0000000000541c2a in nfa_regmatch (start=0xfef2f0, submatch=
0x7fff7ddfa810, m=0x7fff7ddfa630) at regexp_nfa.c:2989
#1 0x00000000005439ad in nfa_regtry (start=0xfef2f0, col=0)
at regexp_nfa.c:3528
#2 0x0000000000543dc4 in nfa_regexec_both (line=0xfe064f "", col=0)
at regexp_nfa.c:3636
#3 0x0000000000544145 in nfa_regexec_multi (rmp=0x7fff7ddfab40, win=0xfa40c0,
buf=0xfa59b0, lnum=1, col=0, tm=0x0) at regexp_nfa.c:3843
#4 0x000000000054431e in vim_regexec_multi (rmp=0x7fff7ddfab40, win=0xfa40c0,
buf=0xfa59b0, lnum=1, col=0, tm=0x0) at regexp.c:7918
#5 0x0000000000557b7c in searchit (win=0xfa40c0, buf=0xfa59b0, pos=
0x7fff7ddfad80, dir=1, pat=0xfbad00 "\\_.*", count=1, options=12, pat_use=
2, stop_lnum=0, tm=0x0) at search.c:639
#6 0x0000000000558f68 in do_search (oap=0x7fff7ddfaf70, dirc=47, pat=
0xfbad04 "", count=1, options=542, tm=0x0) at search.c:1356
#7 0x00000000004fa4bc in normal_search (cap=0x7fff7ddfaea0, dir=47, pat=
0xfbad00 "\\_.*", opt=512) at normal.c:6433
#8 0x00000000004fa40b in nv_search (cap=0x7fff7ddfaea0) at normal.c:6400
#9 0x00000000004f13e1 in normal_cmd (oap=0x7fff7ddfaf70, toplevel=1)
at normal.c:1200
#10 0x00000000005d7652 in main_loop (cmdwin=0, noexmode=0) at main.c:1329
#11 0x00000000005d6faf in main (argc=7, argv=0x7fff7ddfb2a8) at main.c:1020
Vimのデータ構造は以下のようになっている。
tabpage -> frame -> window -> buffer
タブページはtopframeの代替手段である。
片方向リンクリストになっている。
先頭は
first_tabpage
である。現在のタブページは
curtab
でアクセスできる。タブページが内包しているウィンドウのポインタを各種保持している。(curwin/prevwin/firstwin/lastwin)
ウィンドウが所属しているフレームのポインタを持っている。
フレーム自体はtree構造になっている。(parent/child/next/prev)
ウィンドウの縦/横分割のレイアウト情報を保持している。
現在のタブページの 先頭フレームは
topframe
でアクセスできる。:tabnext
等により現在のタブページが変更された場合はtopframe
も更新される。ウィンドウ自体は双方向リストになっている。
所属しているフレームのポインタを持っている。
参照しているバッファのポインタを持っている。
バッファは双方向リストになっている。
割り当てられているファイルの情報等を持っている。
先頭は
firstbuf
である。タブページに関係なくfirstbuf
から全てのバッファを辿ることが出来る。最後は
lastbuf
である。現在のバッファは
curbuf
である。ウィンドウループ処理について
※ウィンドウがぶら下がっているフレームは fr_layoutメンバの値が FR_LEAF である。
(例) frame_new_width()、last_status()