世界を動かす技術を、日本語で。

Show HN: Hardtime.nvim – 悪習を断ち切り、Vimの動作をマスターする

概要

  • hardtime.nvim はVim操作の悪習慣を防止し、効率的な移動を習得するためのNeovimプラグインです。
  • キーの連打制限や、より良い操作方法のヒント表示、行動レポート機能を提供します。
  • 推奨ワークフローや主な機能、インストール・設定方法について解説します。
  • カスタマイズ性が高く、ユーザー独自の設定やヒント追加も可能です。
  • プラグインの有効・無効切り替えや、レポート閲覧方法も紹介します。

hardtime.nvim:Vim操作の悪習慣を断ち切るNeovimプラグイン

主な特徴

  • 短時間内のキー連打をブロック し、無駄な操作を防止すること
  • より効率的なVimモーションのヒント を表示すること
  • よくある悪習慣のレポート を確認すること

推奨ワークフロー

  • hjklや矢印キー、マウスだけに頼るのではなく、以下の操作を推奨すること
    • 画面内の垂直移動: 相対ジャンプ (例: 5j, 12-)を使うこと
    • 画面外の垂直移動: CTRL-U, CTRL-D, CTRL-B, CTRL-F, gg, G を活用すること
    • 短距離の水平移動: 単語移動(w, W, b, B, e, E, ge, gE) を使うこと
    • 中・長距離の水平移動: f, F, t, T, ,, ;, 0, ^, $ を使うこと
    • operator + motion/text-object(例: ci{, y5j, dap)を多用すること
    • 括弧間のジャンプ: %や角括弧コマンド(:h [) を活用すること
  • 詳細は公式ブログ記事で確認すること

必要要件

  • Neovim v0.10.0以上 をインストールすること

インストール方法

  • お好みのパッケージマネージャーでインストールすること
    • 例:
      { "m4xshen/hardtime.nvim", lazy = false, dependencies = { "MunifTanjim/nui.nvim" }, opts = {}, },
      
  • init.luaでプラグインをセットアップすること
    • lazy.nvimを使い、optsを指定している場合は不要
      • 例: require("hardtime").setup()

ヒント表示設定

  • 挿入モードやビジュアルモードでヒントを表示したい場合、'showmode'をfalseに設定すること
  • モード表示も同時に見たい場合、以下の方法を検討すること
    • ステータスラインプラグイン(例: lualine.nvim)でモード表示し、'showmode'をfalseにすること
    • 'cmdheight'を2に設定し、ヒントとモード両方を表示すること
    • nvim-notifyでヒントを右上に通知として表示すること

使い方

  • Hardtimeは デフォルトで有効
  • 状態変更コマンド
    • :Hardtime enable:有効化すること
    • :Hardtime disable:無効化すること
    • :Hardtime toggle:切り替えること
  • よく表示されたヒントは:Hardtime reportで確認すること
    • ログファイル:~/.local/state/nvim/hardtime.nvim.log

設定例と主なオプション

  • 設定テーブルをsetup()またはoptsに渡してカスタマイズすること
  • デフォルト値を無効化したい場合、値をfalseに設定すること
    • 例:
      disabled_keys = { ["<Up>"] = false, ["<Space>"] = { "n", "x" }, },
      disabled_filetypes = { lazy = false, ["dapui*"] = false, },
      
  • 主なオプション一覧
    • max_time:連打とみなす最大時間(ms)を指定すること
    • max_count:最大連打回数を指定すること
    • disable_mouse:マウスサポートを無効化すること
    • hint:ヒント表示を有効化すること
    • notification:通知メッセージを有効化すること
    • timeout:通知表示時間(ms)またはfalseで無効化すること
    • allow_different_key:異なるキーでカウントをリセットすること
    • enabled:デフォルト有効・無効を切り替えること
    • resetting_keys:カウントをリセットするモードを指定すること
    • restricted_keys:カウント機構を発動するキーとモードを指定すること
    • restriction_mode:制限発動時の挙動("block"または"hint")を選択すること
    • disabled_keys:無効化するキーとモードを指定すること
    • disabled_filetypes:無効にするファイルタイプを指定すること
    • hints:ヒントパターンとメッセージを指定すること
    • callback:通知動作をカスタマイズする関数を指定すること
    • force_exit_insert_mode:挿入モードでの無操作時に強制終了すること
    • max_insert_idle_ms:挿入モードで許容する最大無操作時間(ms)を指定すること
    • ui:Hardtimeレポート用のポップアップUIをカスタマイズすること

ヒントカスタマイズ例

  • デフォルトヒント例
    • ["k%^"] = { message = function() return "Use - instead of k^" end, length = 2, }
    • ["d[tTfF].i"] = { message = function(keys) return "Use " .. "c" .. keys:sub(2, 3) .. " instead of " .. keys end, length = 4, }
  • 独自ヒントの追加方法は公式ディスカッションを参照すること

貢献・コントリビューション

  • 詳細は CONTRIBUTING.md を参照すること
  • コントリビューター一覧は公式リポジトリで確認すること

このプラグインを活用し、Vim操作の効率化と悪習慣の改善を実現すること。

Hackerたちの意見

これめっちゃいいね!こんなのが一般的な最適化エンジンにできるかな?つまり、使われているコマンドに対して利用可能な動きのコマンドのセットを一般化できれば、どんなプラットフォームにも適用できるってことだよね。ヘリックスでこれが見られたら最高だな。俺もカスタムエディタをいじってるんだけど、利用可能なコマンドの可視性は俺にとって優先事項だから、ここでの一般的な解決策はすごくエレガントだと思う。新しい機能にもスムーズに適応できそうだし。

ちょっと「完全」な解決策で、ヒントをくれない(だからvimの膨大な機能のプラグインサポートに頼らない)けど、直感を鍛えてくれるやつだね:全体のターミナルのレイテンシを上げる(参照:https://unix.stackexchange.com/questions/778196/how-to-add-d...)(コメントも見てね)っていうのを、ProxyCommandを使って自分のマシンにsshセッションでターミナルセッションを実行することで実現する。

ほら、同じ効果を得るためにemacsを使ってるだけだよ。

これ使っててめっちゃ助かってる!まとめてくれてありがとう。いくつかの小さな点で、悪い習慣だと思うことには同意できないな。例えば、Home/Endは編集モードの時は使えるべきだと思う。他のテキスト入力(エディタだけじゃなくて、ウェブサイトのテキスト入力エリアも)と調和するからね。

ありがとう!実はHardtimeのデフォルト設定ではHome/Endは許可されてるよ。君が使ってるのはAstroNvimだと思うけど、そのコミュニティのデフォルト設定ではそれが無効になってるんだよね:https://github.com/AstroNvim/astrocommunity/blob/main/lua/as...

これすごい!これがあれば、恐竜みたいな使い方をやめてneovimに切り替えられるかも。

vimとneovimを20年以上使ってるけど、ナビゲーションに関してはまだまだ原始人みたいだ。これが俺の悪い習慣を指摘してくるのは好きでもあり嫌いでもある。「Hardtime Report」は素晴らしい機能で、俺の悪い習慣がどれだけ根深いかを見せてくれる。これが改善の手助けになるか、怒ってアンインストールする羽目になるかのどっちかだな。

10年以上vimを使ってるけど、正直言ってhやjを繰り返して上下に移動することのデメリットが見えないんだよね(キーリピートの遅延を小さく調整すれば)。15jみたいに画面の数字を認識して、それからキーボードを見て打つよりも直感的だと思うし、上の数字の列は簡単にタッチタイピングできないからね。

これにはずっと悩まされてきたよ。タッチタイピングできるテンキーがあるけど、ホームポジションから手を離すなら、その時点でマウスを使った方がいいかもね。

へぇ、数字の列をタッチタイピングするのはそんなに難しくないと思うけど。まぁ、私の指が長いからかな。

テキストを移動するのに実用的な良いツールがあるのはいいよね。画面上をジャンプするのには、'easymotion'(「2文字押すだけで画面のどこにでもジャンプ」)やそのバリエーションが、使いやすさに対して素早くナビゲートできるから一番だと思う。

同意だね。これがクリエイターの思考プロセスを少し表しているのかなって思う。私にとって、カーソルが別の行から数行離れているとき、そこに行く一番簡単な方法はhやjを数回使うか、絶対行番号を見てggで行くことなんだ。相対的なジャンプはマクロの中でしか役に立たない。自分で相対的なジャンプを計算するのは、ただ数行上下したいだけの流れから完全に引き離されると思う。証拠はないけど、このパターンのクリエイターは同じようには感じていなかったんじゃないかな。

そこに着いたら何をするか計画する時間もできるし、途中でバグや関連するコードスニペットを見つけることもある。

相対行番号を使い始めるまでは全く同じだったよ。そうすると、行を見て「N行下だな」ってすぐにジャンプできるから。jやkを繰り返すとオーバーシュートしちゃって戻らなきゃいけなくなるのがちょっと面倒なんだよね。

上の段を使う必要はないよ。右親指の修飾キー + 数字キーのようにuio jkl m,.に数字をバインドすればいい。15jの代わりに、そういう文字を数字として受け付ける別のジャンプコマンドを使ったり、a-zのラベルを1行ずつ真ん中に表示するジャンプタイプのコマンドを作って、数字なしで、ガターに焦点を移さずにジャンプできるようにするのもアリ。でも、基本的な動きはやっぱり「直感的」になるよね。

上下にナビゲートするために使える便利なキーは数えきれないほどあるよ。基本的なものは /, *, n, N, H, M, L, {, }, %, ctrl-]、diffバッファにいるときやGitプラグインを使ってるときは ]c, [cも使える。 ]d, [d, [q, ]q, ]l, [lはネオビムを使ってるならね。

その通り。hやjを繰り返すのは非効率だって広く言われてるけど、2つの重要なことを無視してるよね。まず、hやjを押しっぱなしにして、視覚的な手がかりを使っていつ止めるかを知ることができるってこと。一つのキーを押すだけで、ホームローにいるからキーボードを見る必要もない。モニターに目を向けることで、集中力が上がるしね。一回のキーストロークで済む。次に、行番号で考えるのは脳にもう一つの文脈を追加することになる(行番号を見つける)、それから行動に移す(呪文をタイプする)、そして元の作業に戻るために文脈を切り替える。対照的に、jを押しっぱなしにしてその場所に到達するのは、ほとんど作業メモリを使わないんだ。起こっている間に考えることができる!小さくて微妙な違いだけど、その200msの思考プロセスの停止が本当に積み重なるんだよね。壁の時間ではなく(行を飛ばすのは「速い」かもしれないけど)、連続した集中時間において。複数のコマンドを呼び出す必要があるのは、コアな作業からの気を散らす要因になる。再度言うけど、即時の視覚フィードバックがある一つの怠惰なキーストロークの方が、複雑なキーストロークの組み合わせよりも優れてる。あと、treesitterを使うことをちょっと提案したいんだけど、行でナビゲートするためにj/kを使う代わりに、treesitterの要素(関数やメソッドなど)でジャンプするためのキー割り当てを設定してみて。俺は+/-に設定してる。これで、行ごとにではなく、意味的に関連する部分に自動的にジャンプする「ダムスクロール」のように動けるよ。

C-d、C-u、{}、()、そして検索の方がいいよ。gも使うべきだし、例えば関数を定義していて、それがmainでどこで使われるかを確認する必要があるときにね。最適な使い方をするためには、常にmainに何かしらのマークを付けておくべきだから、挿入モードを抜けて、gmでmainを見回して、giで最後にタイプしていたところに戻るといいよ。

横移動にh-lやw-Wキーを繰り返すなって言う人を見るといつも面白いなって思う。カーソルの前に何文字あるか数えるなんて絶対にやらないよ、「31-l」って打つために満足感を得るためにね… 目標の位置に達するまで2w 3w llllを連打するつもりだよ。

f-F、t-T、A、Iに慣れることが大事だと思うし、特にコードではそれが早くなることもあるよね。easymotionやそれに似たプラグインを追加して、パワーアップしたバージョンにすることもできるよ。

このプラグインのポイントは、"wwwwwwww..."を押し続けるのは悪い習慣だってことだよ。そこに行くための客観的に良い方法がある可能性が高いからね。必ずしも「142l」ってわけじゃなくて、「/」や「f,;;」でもいいんだ。

文字数を数え始めるなんて無理だよ。数える必要はないよ。数えずにジャンプする方法はいろいろあるから。いくつかはflash.nvimみたいなプラグインが必要だけど、を何回も押す必要があるものもあるよ。

set relativenumberを使って、どこにジャンプしてるかを確認してね。

最初は文字を数えなきゃいけなかったけど、時間が経つにつれて直感的になってくるよ。誰かが3本の指を立てたら、「1、2、3」って数えずに、すぐに3本だってわかるのと同じ感じ。10未満の数字なら、だいたい正しい数を押せるし、30前後の数字だと1から5くらいずれることもあるけど、そこから先に進むよ。似たような接頭辞を複数の非連続行から削除したいときは、31xみたいなことを使って、次のインスタンスに行って(nで検索を続けたりして)、ピリオドを押すこともある。正直、31文字進むときは、4w(3単語進む)みたいな簡単な方法があることが多いけどね。最初はどの組み合わせを使うかを意識的に考えなきゃいけなかったけど、時間が経つにつれて自然にできるようになるよ。今でも時々jjjjを使うことがあるけど、完璧じゃないけど、少なくとも制限要因は人間であって、ソフトウェアじゃないからね。

同意するよ。vim-sneakがこの問題の答えで、最大3回のキー押しでどこにでも到達できるんだ。すごく直感的で、すぐに使えるようになるよ。もし1つだけVimプラグインを選ぶなら、スニークだね。 https://github.com/justinmk/vim-sneak

%を使って()[]{}のマッチングをナビゲートすることってある?関数のシグネチャから直接エンドに飛ぶのとか、リスピーなパラノードのネストとか、結構便利だよね。

俺はいつもf-F、t-Tを使って行を移動してるんだけど、それが一番早いと思う。

相対行番号はjとkの助けになるよ。

「スクラブルタイル」移動について言及しているガイドがあったよ。fjfeよりも早いんだ、なぜならJはEよりもずっと一般的じゃないから。一度「近く」に行ったら、ターゲットに絞り込む(例えば、fjFaで「隣接」)のが、行きたい場所に最も早く正確に行ける方法かもしれないね。

何年も前にVimを使い始めたとき、矢印キーをノーオプにマッピングしたんだ。それが一番大きな違いを生んだよ。他の何よりもね。hjklを使うことを強制されて、矢印キーは一切使わなくなった。それ以外は後から自然についてくるボーナスみたいなもんだよ。

いいスタートだけど、5jの代わりにjjjjjを打つみたいな同じアンチパターンができちゃうよね。それがhardtimeが解決することなんだ。

これがネオビムのプラグインで、ほんとに続けるきっかけになったんだ。最初の短いフラストレーション期間を経て、もう1年以上このプラグインを使ってるけど、今ではビムの動きで本当にスムーズに作業できるようになった。普通のテキストエディタに戻るなんて考えられないよ。

ビムを初めて使う人に説明するときは、「内側から外側へ」って感じでQWERTYキーボードを想定して、ほとんどの人が右利きだと考えるんだ。つまり、hjklのナビゲーションキーが最初に使いたいナビゲーションで、右手でホームポジションで簡単に打てるってこと。次に、よく使う編集コマンドは左手のホームポジションキーに関連付けられてる; asdで、f(後ろに行くためのF)で現在の行のキャラクターを見つけるのが関連してる。その後は、あまり使わないけど、まだとても便利なコマンドが「ホームロウ」の上と下の行に関連付けられてる。最後に、これらを繰り返すのは、もちろんQWERTYキーボードの「ホームロウ」の2行上にある接頭辞付きの数字にバインドされてる。ShiftやCtrlなどの修飾キーは、数値行とほぼ同じ距離にあるけど、最近のキーボードではCapsLockをCtrlにバインドすることが多い(サンのキーボードは正しくて、今のほとんどのキーボードがCapsLockの位置にCtrlがあった)。面白いことに、ビムを学ぶときは、hjklからの距離を意識することで良い結果が得られることが多いよ。

面白いことに、PCの多くのゲームは移動用にWASDキーを標準化したけど、これは「左利き」と見なされるかもしれない。しかし、タッチタイピングをするときは、左手と右手の違いはあまりないんだよね。