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

続 terminal-api について

続 terminal-api について

tennashi

June 13, 2019
Tweet

More Decks by tennashi

Other Decks in Technology

Transcript

  1. 続 terminal-api について
    ~ terminal-api でできなかったこと ~
    Gollira.vim #5

    View Slide

  2. 自己紹介
    職業プログラマ歴: 半年強
    Vim歴: 6年くらい
    普段は Go/TypeScript(Angular) を書いている
    その前はネットワークエンジニアをしていた
    GitHub: @tennashi
    Twitter: @tnnsh1

    View Slide

  3. 前回のお話

    View Slide

  4. terminal api
    Vim (not neovim) において、 :terminal で動いているジョブから vim へ
    JSON 形式のメッセージを送信する機能
    drop と call の二種類の命令があり、
    drop は vim に新しいウィンドウでファイルを開かせる
    call は Tapi_ から始まるユーザ定義関数を実行させる
    $ echo -e "\x1b]51;[\"drop\", \"hoge\"]\x07"

    View Slide

  5. vim-in-vim 問題
    URL

    View Slide

  6. termopen.vim (リリースしました!)
    vimalter

    View Slide

  7. 今日のお話

    View Slide

  8. git commit
    例えば git commit を実行したとき、 -m でコミットメッセージが指定さ
    れていなければエディタが起動して、コミットメッセージを入力するよ
    うに促される
    このときのエディタは $EDITOR 環境変数や git config core.editor で指
    定できる
    しかし、このときのエディタには "エディタっぽい" ことが期待されて
    おり、雑に echo で実装していると次のようになる

    View Slide

  9. git commit
    $ cat test.sh
    echo -e "\x1b]51;[\"drop\", \"$1\"]\x07"
    $ env EDITOR="./test.sh" git commit
    hint: Waiting for your editor to close the file... -e \x1b]51;["drop", "/home
    /yota/test/.git/COMMIT_EDITMSG"]\x07
    Aborting commit due to empty commit message.
    drop はファイルを開いた時点で実行完了となるため、このようになる
    そのため、terminal-api の実行を "いい感じに" 待つような仕組みを考
    える必要があった
    参考: EDITOR in :terminalを真面目に設定する

    View Slide

  10. while で待ち、 autocmd で通知する

    View Slide

  11. while で待ち、 autocmd で通知する
    function! Tapi_open_wait(bufnr, args)
    call s:open(args[0], args[1:])
    augroup TermOpen
    autocmd! *
    autocmd BufUnload :call leave()
    autocmd QuitPre :call leave()
    augroup END
    let b:is_leave = v:false
    while b:is_leave
    endwhile
    endfunction
    function! s:leave(cmd, files)
    let b:is_leave = v:true
    endfunction

    View Slide

  12. while で待ち、 autocmd で通知する
    だめ
    ちゃんと while で待ってはくれるが、一向にファイルが開かれない
    で処理を中断して、 :ls で見ると、どうやら buffer 自体は開かれ
    ているようだ
    このあと job を使って、非同期にファイルを開かせようとしてみたりも
    したがどうしてもウィンドウが開かれない

    View Slide

  13. ???

    View Slide

  14. とりあえずソースを見てみる

    View Slide

  15. とりあえずソースを見てみる
    src/terminal.c
    https://github.com/vim/vim/blob/260addf7955f3695d3daef9dcf84
    0952af9fd851/src/terminal.c#L3754-L3793

    View Slide

  16. とりあえずソースを見てみる
    src/terminal.c
    if (call_func(func, -1, &rettv,
    2, argvars, /* argv_func */ NULL,
    /* firstline */ 1, /* lastline */ 1,
    &doesrange, /* evaluate */ TRUE,
    /* partial */ NULL, /* selfdict */ NULL) == OK)
    {
    clear_tv(&rettv);
    ch_log(channel, "Function %s called", func);
    }

    View Slide

  17. call_func() ??
    src/userfunc.c
    https://github.com/vim/vim/blob/c07f67ad0e9c48a07d49f2d67eb6
    3e183a22386a/src/userfunc.c#L1473-L1699

    View Slide

  18. call_func() ??
    src/userfunc.c
    call_user_func(fp, argcount, argvars, rettv,
    firstline, lastline,
    (fp->uf_flags & FC_DICT) ? selfdict : NULL);

    View Slide

  19. call_user_func() ??
    https://github.com/vim/vim/blob/c07f67ad0e9c48a07d49f2d67eb63e
    183a22386a/src/userfunc.c#L758-L1166

    View Slide

  20. call_user_func() ??
    /* Don't redraw while executing the function. */
    ++RedrawingDisabled;

    View Slide

  21. /* Don't redraw while executing the function. */

    View Slide

  22. oh...

    View Slide

  23. というわけで...
    Vim はユーザ関数実行中は再描画をしないようにしていることが分かっ

    そのため Vim script の一つの関数のみで、ファイルを開いてその編集
    完了まで待つ、といったことは出来なそうである

    View Slide

  24. ならどうするの??
    編集完了を待ち受ける部分は call の終了後に terminal-api の実行側で
    上手く待つ必要がある
    結局 Vim Script だけで頑張るのは辛そう...
    私は大抵 Go で書くので Go から Vim 触るプラグイン書けばいいので
    は...?
    というわけで鋭意書いてます
    tennashi/tapiexec

    View Slide

  25. 参考資料
    :h terminal
    :terminal に関する小さい Tips
    Vim のレジスタに :terminal のシェル上からアクセスする
    EDITOR in :terminalを真面目に設定する
    Vim本体のソースコードの読みはじめかた(仮)

    View Slide