Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Vim / vim-railsdm-2018-07

ujihisa
July 14, 2018

Vim / vim-railsdm-2018-07

Japanese. RailsDM https://techplay.jp/event/679666 2018-07-14

How does Vim control modes states, such as entering to insert mode from normal mode? How is the C implementation? How can we patch? This is a journey to learn about them.

ujihisa

July 14, 2018
Tweet

More Decks by ujihisa

Other Decks in Technology

Transcript

  1. View Slide

  2. Vim
    Tatsuhiro Ujihisa
    RailsDM 2018-07-14

    View Slide

  3. View Slide

  4. View Slide

  5. Topics
    ● オススメのVimの使い方
    ○ これを入れるだけで生産性7倍
    ○ EP, FPなどの重要なコンセプト
    ○ 目でみたとこにカーソルが移動し、入力を全く
    阻害しないなめらかなVimさばきの技法
    ● if_ruby完全活用方法
    ● vimのC実装のrestart_edit 変数

    View Slide

  6. src/main.c

    View Slide

  7. Topics
    ● オススメのVimの使い方
    ○ これを入れるだけで生産性7倍
    ○ EP, FPなどの重要なコンセプト
    ○ 目でみたとこにカーソルが移動し、入力を全く
    阻害しないなめらかなVimさばきの技法
    ● if_ruby完全活用方法
    ● vimのC実装のrestart_edit 変数

    View Slide

  8. Topic
    ● オススメのVimの使い方
    ○ これを入れるだけで生産性7倍
    ○ EP, FPなどの重要なコンセプト
    ○ 目でみたとこにカーソルが移動し、入力を全く
    阻害しないなめらかなVimさばきの技法
    ● if_ruby完全活用方法
    ● vimのC実装のrestart_edit 変数

    View Slide

  9. Topic
    ● オススメのVimの使い方
    ○ これを入れるだけで生産性7倍
    ○ EP, FPなどの重要なコンセプト
    ○ 目でみたとこにカーソルが移動し、入力を全く
    阻害しないなめらかなVimさばきの技法
    ● if_ruby完全活用方法
    ● vimのC実装のrestart_edit 変数
    ○ vimの挿入モード (Insert mode)の仕様
    ○ vimの挿入モードに入る実装

    View Slide

  10. View Slide

  11. View Slide

  12. Vimとは
    ● Text editor




    ● 人生

    View Slide

  13. Vimとは
    ● Text editor (not text inputter)




    ● 人生

    View Slide

  14. Vimとは
    ● Text editor (not text inputter)
    ○ モード遷移

    ○ Vim scriptランタイム
    ○ ファイル・バッファ操作
    ○ 画面レンダリング
    ● 人生

    View Slide

  15. Vimとは
    ● Text editor (not text inputter)
    ○ モード遷移
    ■ (ノーマルモード、挿入モードなど)
    ■ 有限状態機械
    ○ Vim scriptランタイム
    ○ ファイル・バッファ操作
    ○ 画面レンダリング
    ● 人生

    View Slide

  16. Vimのモード
    ● 起動時はNormal mode
    ● iとかaとかするとInsert modeに入る

    ● とかとかするとNormal modeに戻る

    View Slide

  17. Vimのモード
    ● 起動時はNormal mode
    ● iとかaとかするとInsert modeに入る
    ○ Q. Insert modeに入るキーは全部で何種類

    ● とかとかするとNormal modeに戻る

    View Slide

  18. Vimのモード
    ● 起動時はNormal mode
    ● iとかaとかするとInsert modeに入る
    ○ Q. Insert modeに入るキーは全部で何種類か
    ○ 9
    ○ a, A, , i, I, gI, gi, o, O
    ● とかとかするとNormal modeに戻る

    View Slide

  19. Normal modeからInsert modeに入る9つの四天王
    ● a カーソルの後に挿入
    ● A 行末に挿入 (:startinsert!)
    ● iと同じ
    ● i カーソルの前に挿入 (:startinsert)
    ● I (インデントのあとの)行先頭に挿入
    ● gI 行先頭に挿入
    ● gi 最後に入力あった場所に挿入
    ● o 下の行を作ってそこに挿入
    ● O 上の行を作ってそこに挿入

    View Slide

  20. Insert modeからnormal modeに入るには
    ● escと同じ
    ● はい
    ● abbrとかInsertLeaveイベントを無視
    ● 前回入力したものを入れて
    ○ と同じ
    ○ 互換性のためにあるっぽいので忘れていい
    ■ 現代人ならnormap modeで.でリピート
    ● normal modeの命令一つだけできる特
    殊状態に遷移 (後述)

    View Slide

  21. Insert modeのについて詳しく
    :h i_CTRL-o
    ● 何か一個だけコマンドできる
    ○ hjkl移動とか (1回だけ)
    ○ :からのex command実行とか
    ● 大抵の場合key mapping用
    ○ :call your_function()
    ○ とかをmapして
    挿入モードの関数呼び出しとか

    View Slide

  22. ドットリピート
    ● . で直前のテキスト編集を繰り返す
    ● Insert modeでの一連の入力を再現
    ○ 一連の、とは
    →デモ

    View Slide

  23. Vimのcountの概念
    ● countは至るところにある
    ● 任意の何かに付与可能
    ○ motion
    ○ operation
    ○ command
    ○ ex command
    ○ →デモ

    View Slide

  24. ここまでのまとめ
    ● Vimはいろんな方法でInsert modeに入れる
    ● いろんな方法でNormal modeに戻れる
    ● バッファ書き換えの単位の概念がある
    ○ .でリピートしたり、countで複数回同じのやった

    View Slide

  25. 突然のクイズ
    ● 3gihelloworld
    ● 結果どうなる?

    View Slide

  26. 突然のクイズ
    ● 3gihellohworld
    ● 結果どうなる?
    3gi 後続するgiからまでを3回やる
    gi 最後に挿入したとこからinsert mode突入
    一瞬normal modeに入り、あとでinsert mode
    に戻る
    h 左に1文字移動

    View Slide

  27. 正解
    helworldlo
    countの3は無視される
    :h i

    View Slide

  28. ここまで全部
    :h に載ってる
    :h inserting
    ↑ででてくる insert.txt はとりあえず通読した方がいいかも
    https://vim-jp.org/vimdoc-ja/insert.html

    View Slide

  29. ここから
    実装レベルに入る
    具体的なパッチとかも例に

    View Slide

  30. https://github.com/vim/vim

    View Slide

  31. src/main.c

    View Slide

  32. int main(int argc, char **argv)
    {
    return vim_main2();
    }
    int vim_main2(void)
    {
    main_loop(FALSE, FALSE);
    }
    void main_loop(int cmdwin, int noexmode)
    {
    oparg_T oa;
    while(...) { if(...) {
    normal_cmd(&oa, TRUE);
    }}
    }
    src/main.c (超要約バージョン)

    View Slide

  33. int main(int argc, char **argv)
    {
    return vim_main2();
    }
    int vim_main2(void)
    {
    main_loop(FALSE, FALSE);
    }
    void main_loop(int cmdwin, int noexmode)
    {
    oparg_T oa;
    while(...) { if(...) {
    normal_cmd(&oa, TRUE);
    }}
    }
    src/main.c (超要約バージョン)

    View Slide

  34. void normal_cmd(oparg_T *oap, int
    toplevel UNUSED)
    {
    cmdarg_T ca;
    int idx;
    if (...) {
    idx = find_command(ca.cmdchar);
    ca.arg = nv_cmds[idx].cmd_arg;
    (nv_cmds[idx].cmd_func)(&ca);
    }
    }
    src/normal.c (超要約バージョン)

    View Slide

  35. void normal_cmd(oparg_T *oap, int
    toplevel UNUSED)
    {
    cmdarg_T ca;
    int idx;
    if (...) {
    idx = find_command(ca.cmdchar);
    ca.arg = nv_cmds[idx].cmd_arg;
    (nv_cmds[idx].cmd_func)(&ca);
    }
    }
    src/normal.c (超要約バージョン)

    View Slide

  36. void normal_cmd(oparg_T *oap, int
    toplevel UNUSED)
    {
    cmdarg_T ca;
    int idx;
    if (...) {
    idx = find_command(ca.cmdchar);
    ca.arg = nv_cmds[idx].cmd_arg;
    (nv_cmds[idx].cmd_func)(&ca);
    }
    }
    src/normal.c (超要約バージョン)

    View Slide

  37. void normal_cmd(oparg_T *oap, int
    toplevel UNUSED)
    {
    cmdarg_T ca;
    int idx;
    if (...) {
    idx = find_command(ca.cmdchar);
    ca.arg = nv_cmds[idx].cmd_arg;
    (nv_cmds[idx].cmd_func)(&ca);
    }
    }
    src/normal.c

    View Slide

  38. void normal_cmd(oparg_T *oap, int
    toplevel UNUSED)
    {
    cmdarg_T ca;
    int idx;
    if (...) {
    idx = find_command(ca.cmdchar);
    ca.arg = nv_cmds[idx].cmd_arg;
    (nv_cmds[idx].cmd_func)(&ca);
    }
    }
    src/normal.c

    View Slide

  39. void normal_cmd(oparg_T *oap, int
    toplevel UNUSED)
    {
    cmdarg_T ca;
    int idx;
    if (...) {
    idx = find_command(ca.cmdchar);
    ca.arg = nv_cmds[idx].cmd_arg;
    (nv_cmds[idx].cmd_func)(&ca);
    }
    }
    src/normal.c
    {'A', nv_edit, 0, 0},
    {'I', nv_edit, 0, 0},
    {'a', nv_edit, NV_NCH, 0},
    {'i', nv_edit, NV_NCH, 0},
    {K_INS, nv_edit, 0, 0},
    {K_KINS, nv_edit, 0, 0},
    {K_PS, nv_edit, 0, 0},
    {'O', nv_open, 0, 0},
    {'o', nv_open, 0, 0},

    View Slide

  40. src/normal.c

    View Slide

  41. src/normal.c

    View Slide

  42. src/normal.c
    invoke_edit(
    cap, FALSE, cap->cmdchar, FALSE);
    // in invoke_edit()
    edit(
    cmd, startln, cap->count1)

    View Slide

  43. src/normal.c
    invoke_edit(
    cap, FALSE, cap->cmdchar, FALSE);
    // in invoke_edit()
    edit(
    cmd, startln, cap->count1)
    以下1300行くらい

    View Slide

  44. ここまでのまとめ
    ● Vimはモードがあってiとかとかで切替
    ● Vim起動したらまず初期化
    ● main_loop()内で無限ループ
    ● normal_cmd()内で
    ○ キー入力に対応する関数を探索
    ○ 探索には配列nv_cmdsを使用 (
    ● i とは、nv_edit() → invoke_edit() → edit()

    View Slide

  45. src/README.txt
    に書いてる
    このスライドできてから気づいた

    View Slide

  46. 本題
    ● restart_edit
    ● vim頻出単語
    ● $ git grep '\brestart_edit\b' | wc -l
    ○ 116
    ● undocumented (.txtに書かれてない)

    View Slide

  47. の前に
    ちょっとCM
    提供: VimConf準備会

    View Slide

  48. VimConf
    https://vimconf.org/2018

    View Slide

  49. https://vimconf.org/2018

    View Slide

  50. https://vimconf.org/2018
    VimConf 2018
    ● 2018-11-24
    ● 秋葉原
    ● 国際カンファレンス (英日も日英も全発表に対して
    同時通訳あり)
    ● スポンサー急募中
    ● 発表募集中

    View Slide

  51. https://vimconf.org/2018
    VimConf 2018
    ● 2018-11-24
    ● 秋葉原
    ● 国際カンファレンス (英日も日英も全発表に対して
    同時通訳あり)
    ● スポンサー急募中
    ● 発表募集中

    View Slide

  52. https://vimconf.org/2018
    VimConf 2018
    ● 2018-11-24
    ● 秋葉原
    ● 国際カンファレンス (英日も日英も全発表に対して
    同時通訳あり)
    ● スポンサー急募中
    ● 発表募集中
    https://vimconf.org/2018
    https://vimconf.org/2018
    https://vimconf.org/2018
    https://vimconf.org/2018
    https://vimconf.org/2018

    View Slide

  53. https://twitter.com/supermomonga/status/100887008
    3215613954

    View Slide

  54. 本題
    ● restart_edit
    ● vim頻出単語
    ● $ git grep '\brestart_edit\b' | wc -l
    ○ 116
    ● undocumented (.txtに書かれてない)

    View Slide

  55. src/edit.c

    View Slide

  56. src/edit.c

    View Slide

  57. src/edit.c

    View Slide

  58. View Slide

  59. EXTERN int restart_edit INIT(= 0);
    /* call edit when next cmd finished */
    (src/globals.h)
    // とかじゃなくて普通のNormal mode
    restart_edit = 0;
    // iの中でしたとき
    restart_edit = 'i';
    // 一欄
    0, 'i', 'I', 'a', 'A', 'R', 'V'

    View Slide

  60. https://github.com/vim-jp/issues/issues/1147

    View Slide

  61. https://vim-jp.slack.com/archives/C83UXKU86/p15
    28776532000106

    View Slide

  62. https://twitter.com/fatih/status/10072503322
    61519360

    View Slide

  63. Suggested solution
    ● mode(): 現在のモードを返す関数
    ○ mode(1) で詳細
    ● 現在、normal modeでも, insert modeからの
    、どちらもmode()返り値は"n"
    ● 提案: Insert modeからのは
    ○ mode() = "n" (互換性保つ)
    ○ mode(1) = "ni"

    View Slide

  64. https://github.com/vim/vim/pull/3000

    View Slide

  65. View Slide

  66. ujihisa
    ● https://twitter.com/ujm
    ● https://github.com/ujihisa
    ● VimConf主催者
    ● 元Hootsuiteソフトウェアエンジニア
    ○ Twitterクライアントのあれ
    ● 元Fablicソフトウェアエンジニア
    ○ FRILとかラクマのあれ

    View Slide

  67. ujihisa 最近の活動
    ● 明日: 友人宅で2~4kgの魚を捌く予定
    ● 明々後日: asakusa.rbで同上
    ● 再来週: 隅田川花火大会で同上
    ● 一ヶ月くらい就活中

    View Slide

  68. Vim
    Tatsuhiro Ujihisa
    RailsDM 2018-07-14

    View Slide

  69. ujihisa's past talks
    ● 2017
    ○ 「高濃度雑談」大江戸 Ruby会議
    ○ 「Vim」TokyuRuby会議11 (LT)
    ○ 「How to develop CRuby easily with Vim」RubyKaigi 2017 (LT)
    ● 2015
    ○ 「Vim + Clojure」VmConf 2015
    ● 2014
    ○ 「PM2」VimConf 2014
    ● 2013
    ○ 「vital.ProcessManager」VimConf 2013
    ● Older
    ○ RubyConf 2009
    ○ RubyKaigi 2009
    ○ RubyKaigi 2008

    View Slide