こんにちは!エンジニアの宮川です。株式会社アカツキゲームスでクライアントエンジニアをやっています。
このエントリーは Akatsuki Games Advent Calendar 2023 の14日目の記事です。
昨日の記事は「最先端のライフゲーム(Particle Lenia)を作ったので眺める」でした。
コンピュータープログラムから生み出される有機的な挙動にはロマンを感じますね!この手のシミュレーションは永遠に見ていられます。
14日目のこの記事では、私が愛用しているwhich-keyという仕組みを紹介します!
時に皆さん、ショートカットキーは使っていますか?既存のショートカットキーをマスターしたり、新しいショートカットキーを登録したりして日々QoLを爆上げしているかと思います。
ですが、ショートカットキーの登録をするにあたってこんな悩みに直面したことはありませんか?
- 新しくショートカットキーを登録したいのに、既存のショートカットキーやmacosのショートカットキーとバッティングしてしまう
- ショートカットキーを登録し過ぎて新たに割り当てるキーが枯渇している
- 一生懸命ショートカットキーを設定しても、後でどのキーに割り当てたかどうか忘れてしまう
- 同時押しが複雑過ぎて指が混線する
which-keyはそんなあなたの悩みにそっと寄り添ってくれる、新しいショートカットキーの仕組みかもしれません。
which-keyとは
which-keyとは、特定のキー(Spaceキーなど)を基点とした任意長のキーシーケンスにコマンドを割り当てることができる仕組みです。Vimmer向けに言えば、リアルタイムガイド付きLeader-コマンドとも言えます。
イメージとしては、ウィンドウ上部のメニューバーの階層構造をキーボード操作のみで「たどる」ような感じです。
which-keyは、プラグインを入れることでEmacs, Vim/NeoVim, VSCode, Intellij IDEAといったJetbrains製IDEなどで使うことができます。
デモ
言葉だけで説明するのがなかなか難しい概念ですので、早速以下に簡単なデモを見せます。
(埋め込みで画質が荒い場合はYouTubeに移動して見て下さい)
このデモではSpaceキーがwhich-keyのトリガーとなっていて、Spaceを押すと画面下部にメニューが出現します。
メニューに書かれたキーを押す事で、登録されたコマンドを実行するか、もしくは別のメニューに移動することができます。
このデモではwキーに「Window...」メニューが登録されている他、fキーには「Find...」メニュー、gキーには「Goto...」メニュー等が登録されています。
「Window...」メニューには色々なコマンドが登録されていて、例えばvでウィンドウ縦分割、sでウィンドウ横分割、cで分割ウィンドウ削除ができます。また、トップメニューのqにはエディタの終了が登録されていて、これはデモの最後で使用されています。
このように、which-keyではコマンドをメニューの階層構造にして登録することができるのです。
これを「キーシーケンスとコマンドの対応関係」として見てみると次のようになります:
- <Space>wv → ウィンドウ縦分割
- <Space>wv → ウィンドウ横分割
- <Space>wc → 分割ウィンドウ削除
- <Space>q → エディタ終了
which-keyの特徴
which-keyがどういうものなのかデモをお見せした所で、次はwhich-keyの良いところを特徴ごとに説明していきます:
which-keyの仕組み自体がチートシートの役割を果たしている
同時押しによって発動する一般的なショートカットキーとは違い、which-keyではリアルタイムでメニューウィンドウが表示されます。
これはショートカットキーのチートシートの役割も果たしていて、登録したキーシーケンスを覚えていなくてもその場で登録されているコマンドを確認することができます。
階層構造でコマンドの割当ができるので、好きなだけ登録できる
ワンストロークでキーボードの組み合わせを定義するショートカットキーとは異なり、コマンドを階層構造で登録することができるので、何個でもコマンドを登録しておくことができます。
「which-keyを起動するキーボードショートカット」さえ確保できていれば、既存のキーボードショートカットと衝突することもありません。
キーシーケンスに意味をもたせやすくて覚えやすい
さらに、メニューが階層構造で登録できることの恩恵として、キーシーケンスが比較的覚えやすいという事も挙げられます。
キーボードショートカットの空きが枯渇している場合とかだと「Ctrl + Bは使われてるから隣のGを使うか...」「Ctrl + BもCtrl + Shift + Bも使われてるからAlt + Bにするか...」といったケースがあると思います(私はあります)。そして、そうやって適当に無理やり作ったショートカットキーは割りとすぐに忘れてしまいます。
例えばデモで挙げたようなコマンドは <Space>wvにウィンドウ縦分割、<Space>wc分割ウィンドウ削除が登録されていますが、それぞれ
- <Space>wv → Window Vertical split
- <Space>wc → Window Close
といった意味とセットで覚えられます。(こういうのはVimmerには馴染み深いと思います。)
まっさらな状態から作り込める
ショートカットキーには慣例的に定義されているもの(Ctrl-C, Ctrl-Vなど)もあれば、ツールに最初から定義されているものもあり、それらを避けながら自分好みのショートカットキーを構築するのは面倒だったりします。
which-keyにはそういったしがらみは無く、基本的に自分でゼロから作り込むことができます。たいていのwhich-keyプラグインにはデフォルトのシーケンスも用意されているのでそれを使って見るのも良いですが、ゼロから作り込むのも楽しいものです。
which-keyが使える環境
which-keyは元はEmacsのプラグインとして開発されたものなのですが、これにインスパイアされた様々なエディタ向けのwhich-keyプラグインが開発されています。
冒頭で軽く触れましたが、私が知る限りだとEmacsの他にVim/NeoVim, VSCode, Intellij IDEA向けのwhich-keyプラグインが公開されています。せっかくなのでいくつかリンクを貼っておきます:
Emacs向けプラグイン - https://github.com/justbur/emacs-which-key
NeoVim向けプラグイン - https://github.com/folke/which-key.nvim
VSCode向けプラグイン - https://vspacecode.github.io
Jetbrains製IDE向けプラグイン - https://github.com/TheBlob42/idea-which-key
また、NeoVimにはゴリゴリにプラグインを入れまくってパッケージ化されたものがあったりするのですが(LunarVim など)、こういったものにはwhich-keyが標準搭載されていたりします。
shell環境では使えないんですか!?
...と思ったそこのあなた、安心して下さい。
私が作っておきました。
結構前に作ったもので作りも雑なのですが、一応zsh環境で動くはずです。私は日頃愛用しています。例えば、
といったコマンドをいつも <Ctrl-G>gl で実行しています。
実装小話
which-key特有のメニューを実現するための要件として
- Returnキーを押さなくても即座に入力を受け取れるようにしたい(一般的なCLIアプリケーションとは異なる)
- できればプロンプトを「荒らす」ようなことはしたくない(which-keyモードを抜けた時に何も残らないで欲しい)
の2つがあったので、Cursesという仕組みを使ってレンダリングを行いました。
CursesはPythonから使うことができ、which-key-shellでもこれを使っています。
ただshellという環境上、Spaceキーをトリガーにするのは難しく、そこが難点です。
おわりに
Akatsuki Games Advent Calendar 2023 14日目のこの記事では、私が日頃愛用しているwhich-keyという仕組みについて解説を行ったり自作ツールを自慢したりしました。
この記事を通して、マイナーながら強力なwhich-keyというシステムが少しでも広まれば良いなと思います。目指せ脱マウス!!
明日、15日目は竹下さん(通称: ばじくん)の「RubyでTOTPのクライアントを自前実装してみた」です!日頃からお世話になっているTOTPの仕組みがどうなっているのか、とても気になる内容です!
最後に、アカツキゲームスでは一緒に働くエンジニアを募集しています。
カジュアル面談もやっていますので、気軽にご応募ください。
応募はここから!👉 https://herp.careers/v1/aktskgames/requisition-groups/47f46396-e08a-4b2f-8f9b-b2fc79e63b83