🐜

denops.vimを使ってポモドーロタイマーを実装してみた

2021/07/04に公開2

はじめに

denops.vimを使って、Vim/Neovim上でポモドーロテクニックを実践するためのプラグインを作成してみました。

https://github.com/uki00a/denops-pomodoro.vim/

この記事ではdenops-pomodoro.vimの使い方やdenops.vimを使ってプラグインを実装する上でのノウハウなどについて紹介します。

denops.vimとは?

denops.vimとはDenoを使ってVimやNeovimのプラグインを書くためのエコシステムです。

より詳しくは以下の記事を参照いただければと思います。

https://zenn.dev/lambdalisue/articles/b4a31fba0b1ce95104c9

denops-pomodoro.vimの使い方

必要なもの

コマンド

基本的な機能は以下の3つのコマンドによって提供されます。

  • PomodoroStart
  • PomodoroPause
  • PomodoroResume

PomodoroStartコマンドでタイマーを開始できます。

タイマーの残り時間が0になると、デスクトップ通知が行われます。

:PomodoroStart

タイマーを一時停止したいときはPomodoroPauseコマンドを実行します。

:PomodoroPause

一時停止したタイマーを再開したいときはPomodoroResumeコマンドを実行します。

:PomodoroResume

PomodoroResetコマンドを実行するとタイマーを初期状態にリセットできます。

:PomodoroReset

タイマーの残り時間の確認方法

現時点では、以下の2つの手段を用意しています。

PomodoroEchoコマンド

このコマンドを実行すると、Vimのエコーエリアに残り時間が表示されます。

:PomodoroEcho

vim-airlineとの統合

denops-pomodoro.vimはvim-airlineとの統合をサポートしています。

以下は設定例です。

init.vim
function! s:airline_after_init() abort
  let g:airline_section_c .= airline#section#create_right(['pomodoro'])
endfunction

autocmd User AirlineAfterInit call <SID>airline_after_init()

このように設定しておくと、以下の画像のようにタイマーが表示されます。("🍅 15:19"の部分)

vim-airlineとの統合

設定

Vimの変数によってタイマーなどの挙動をカスタマイズできます。

変数 説明 デフォルト値
g:pomodoro_work_minutes 作業時間を分単位で指定します 25
g:pomodoro_short_break_minutes 小休憩時間を分単位で指定します 5
g:pomodoro_long_break_minutes 休憩時間を分単位で指定します 25
g:pomodoro_work_sign 作業時間中にタイマーの横に表示される文字 "🍅"
g:pomodoro_short_break_sign 小休憩時間中にタイマーの横に表示される文字 "☕"
g:pomodoro_long_break_sign 休憩時間中にタイマーの横に表示される文字 "😴"
g:pomodoro_pause_sign タイマーの一時停止中に表示される文字 "⏸️"

デスクトップ通知

デスクトップ通知はdeno-notifier.tsというモジュールを作成して、実装しています。

現時点では、以下のプログラムがサポートされています (正直なところ、MacとWindowsではまだ十分にテストができていないです...😭)

  • Linux: notify-send
  • Mac: osascript
  • Windows: Snoretoast

denops.vimに関するノウハウ

プラグイン(main.ts)の型チェックについて

denopsのプラグインはデフォルトでは型チェックが行われません。

そのため、CIでdeno cacheコマンドを実行し、型チェックをしておくとよいのではないかと思います。

.github/workflows/ci.yml
# 省略...
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@master
    - uses: denoland/setup-deno@main
      with:
        deno-version: "1.11.0"
    - name: Type check
      run: |
        deno cache --unstable denops/pomodoro/main.ts

デバッグについて

プラグインをデバッグしたいときはdenops#server#restart()でdenopsのサーバプロセスを再起動すると便利です。

:call denops#server#restart()

この関数を実行すると各denopsプラグインがリロードされます。

長時間走る処理について

denops.vimではDispatcherで登録したハンドラが一定時間以内に応答を返さなかった場合、タイムアウトエラーが発生するようです。

そのため、長時間処理を走らせたい場合などは、匿名関数でラップする必要がありそうです。

例)

main.ts
  denops.dispatcher = {
    async start(): Promise<void> {
      if (pomodoro) {
        await pomodoro.pause();
      }
      pomodoro = await createPomodoro(vim);
      // 長時間走る処理は匿名関数でラップする!
      (async () => {
        do {
          await Promise.any([
            pomodoro.start(),
            disposed,
          ]);
        } while (!pomodoro.isPaused());
      })();
    },
    // ...省略...
  };

テストについて

denops.vimはDenoを使用しているため、Deno.testでテストコードを書けます。

そのため、プラグインのエントリポイントであるmain.tsからはできるだけ主要な処理を分離しておき、個別にテストコードを書けるようにしておくと便利だと思いました。

課題

  • デスクトップ通知周りがまだちょっと貧弱...😭
  • vim-airline以外のプラグインとも連携したい。

おわりに

今回、denops.vimでプラグインを作ってみて、以下の点がとてもよかったと感じました。

  • Denoでプラグインを書けること😍
    • 型チェックの安心感
    • テストランナ・リンタ・フォーマッタ・LSP等、開発に必要なものの大部分がDenoで提供されている。
    • 外部ライブラリの依存管理が楽
    • Denoとdenops.vimさえ入ってれば動くので、普通のVimプラグインと同じような感覚で配布できる。

denops.vimはとても便利だと思いますので、もし興味がありましたらぜひ使ってみてください!

Discussion