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

続 terminal-api について

続 terminal-api について

A232c8c1162873c06145ecb41ed2662b?s=128

tennashi

June 13, 2019
Tweet

Transcript

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

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

    @tennashi Twitter: @tnnsh1
  3. 前回のお話

  4. terminal api Vim (not neovim) において、 :terminal で動いているジョブから vim へ

    JSON 形式のメッセージを送信する機能 drop と call の二種類の命令があり、 drop は vim に新しいウィンドウでファイルを開かせる call は Tapi_ から始まるユーザ定義関数を実行させる $ echo -e "\x1b]51;[\"drop\", \"hoge\"]\x07"
  5. vim-in-vim 問題 URL

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

  7. 今日のお話

  8. git commit 例えば git commit を実行したとき、 -m でコミットメッセージが指定さ れていなければエディタが起動して、コミットメッセージを入力するよ うに促される

    このときのエディタは $EDITOR 環境変数や git config core.editor で指 定できる しかし、このときのエディタには "エディタっぽい" ことが期待されて おり、雑に echo で実装していると次のようになる
  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を真面目に設定する
  10. while で待ち、 autocmd で通知する

  11. while で待ち、 autocmd で通知する function! Tapi_open_wait(bufnr, args) call s:open(args[0], args[1:])

    augroup TermOpen autocmd! * <buffer> autocmd BufUnload <buffer> :call <SID>leave() autocmd QuitPre <buffer> :call <SID>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
  12. while で待ち、 autocmd で通知する だめ ちゃんと while で待ってはくれるが、一向にファイルが開かれない <C-c> で処理を中断して、

    :ls で見ると、どうやら buffer 自体は開かれ ているようだ このあと job を使って、非同期にファイルを開かせようとしてみたりも したがどうしてもウィンドウが開かれない
  13. ???

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

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

  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); }
  17. call_func() ?? src/userfunc.c https://github.com/vim/vim/blob/c07f67ad0e9c48a07d49f2d67eb6 3e183a22386a/src/userfunc.c#L1473-L1699

  18. call_func() ?? src/userfunc.c call_user_func(fp, argcount, argvars, rettv, firstline, lastline, (fp->uf_flags

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

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

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

  22. oh...

  23. というわけで... Vim はユーザ関数実行中は再描画をしないようにしていることが分かっ た そのため Vim script の一つの関数のみで、ファイルを開いてその編集 完了まで待つ、といったことは出来なそうである

  24. ならどうするの?? 編集完了を待ち受ける部分は call の終了後に terminal-api の実行側で 上手く待つ必要がある 結局 Vim Script

    だけで頑張るのは辛そう... 私は大抵 Go で書くので Go から Vim 触るプラグイン書けばいいので は...? というわけで鋭意書いてます tennashi/tapiexec
  25. 参考資料 :h terminal :terminal に関する小さい Tips Vim のレジスタに :terminal のシェル上からアクセスする

    EDITOR in :terminalを真面目に設定する Vim本体のソースコードの読みはじめかた(仮)