関数、変数にジャンプするdumb-jumpをemacsで使わないのはかなり損している

2023年4月16日
thumbnail
dumb-jumpはプログラムの変数や関数、クラスの定義へジャンプするパッケージであり、50以上のプログラミング言語をサポートしています。
dumb-jumpの利用シーンをイメージするとこのようになります。ReactもPythonもあらゆるプログラムは多くの自作モジュール、グローバル変数が至る所で使われています。
コードリーディングをしていて、使われている関数の中身がどのようなものかを把握しようとするのは骨が折れます。
  1. 使われている関数名をコピーする
  2. ファイルの上部を見て、どこからインポートされてるか確認
  3. 参照先のファイルを開き、関数名で検索
この手間を考えると、関数はブラックボックスでも良いかと思ってしまいます。 一方で、dumb-jumpを使えば、その問題は一発で解決します。 関数にカーソルを当てて、関数の定義場所へジャンプするコマンドを入力すれば、別のファイルにあろうが、同一ファイル上にあろうが、即座にジャンプできます。元いたところに戻る時も一瞬です
これが完成済みのコードです。
(use-package dumb-jump
  :ensure t
  :bind(
        ("C-c g" . dumb-jump-go)         ;; クラスや関数、変数の定義されている場所へ飛ぶ
        ("C-c b" . dumb-jump-back)       ;; 飛んできたら、元の場所に戻る
        ("C-M-q" . dumb-jump-quick-look) ;; 飛ぶ前にジャンプ先の候補を表示
        )
  :init
  ;; dumb-jumpを起動
  (dumb-jump-mode)
  :config
  (add-hook 'xref-backend-functions #'dumb-jump-xref-activate) ;; xrefを使うらしいので起動させる
  (setq dumb-jump-force-searcher 'rg).  ;; デフォルトだとgit grepが使われてエラーが出たのでrgコマンドを強制利用する
  (setq dumb-jump-prefer-searcher 'rg)  ;; rgコマンドを優先的に利用する
  (setq dumb-jump-default-project "")          ;; ホームディレクトリ以下が検索対象になるのを回避
  (setq dumb-jump-disable-obsolete-warnings t) ;; レガシーコマンドの警告を非表示
  )

定義されたものへジャンプとバック

サンプルコードはこちらを利用してみましょう。
def get_integer(prompt):
    while True:
        try:
            value = int(input(prompt))
            break
        except ValueError:
            print("Please enter an integer.")
    return value

def add_numbers():
    num_values = get_integer("How many numbers do you want to add? ")
    total = 0
    for i in range(num_values):
        num = get_integer("Enter a number: ")
        total += num
    print("The total is:", total)

if __name__ == '__main__':
    add_numbers()
get_integer関数は2箇所で利用されています。 get_integer("How many...")にカーソルを合わせて、定義された場所にジャンプしてみます。
article image
("C-c g" dumb-jump-go)を実行します。
article image
同じファイルの近いところにジャンプしているので、ありがたみは無いのですが、dumb-jumpは別のファイルに書かれていたとしても同様にジャンプできます。
元の場所に戻る時は、("C-c b" dumb-jump-back)でバックできます。
article image
dumb-jumpの使い方はこれだけです。

検索コマンドについて

dumb-jumpのリポジトリのREADMEを読むと、関数、変数のジャンプ先を探すコマンドはlispで書かれているのではなく、linuxコマンドを利用しています。Macの場合はわざわざコマンドをインストールしなくてもgrepが入っているので、それが使われます。
公式がお薦めしているのはagrgコマンドです。2つのコマンドはデフォルトでMacに入っているわけでは無いので、dumb-jumpの検索コマンドとして使いたい場合はインストールが必要です。
READMEのここに書かれているように、最適なパフォーマンスはagrgを使った方が良いとあります。
私は試しにrgコマンドを入れてみました。
brew install ripgrep
もしも、agコマンドを利用する場合はbrewでインストールした後、emacsのdump-jumpのlispの設定を変更してください。
  (setq dumb-jump-force-searcher 'ag).  ;; デフォルトだとgit grepが使われてエラーが出たのでagコマンドを強制利用する
  (setq dumb-jump-prefer-searcher 'ag)  ;; agコマンドを優先的に利用する

レガシーコマンド警告について

config:に記述した(setq dumb-jump-disable-obsolete-warnings t)dumb-jump-goがレガシーコマンドになるから使うなという警告を非表示にする設定です。
関数にジャンプするコマンドであるdumb-jump-goはどうやら2020年くらいからレガシーになるとあるのですが、なぜか代わりに提案されているコマンドxref-find-definitionsは全く別の挙動をするので謎です。
なので、dumb-jump-goを使うのですが、使うたびにメッセージに警告が表示されるのが邪魔なので、その警告を非表示にしています。
何かこの辺りのことが分かる方教えてください。

まとめ

短いサンプルコードだとありがたみがさほど感じられませんが、これが膨大なアプリケーションになると、途端にスーパヒーローになります。dumb-jumpがないと、もはやコーディングなど無理なのでは、と思うくらいには素晴らしいパッケージなのでぜひ利用してみてください。
profile image
Ted
大学でコンセンサスアルゴリズムを研究。卒業後ベンチャー企業に入社してフルスタックでWebサービスを開発。現在は大手IT企業に転職し、プログラミングを行っている。AIにプログラマーの仕事を奪って欲しいと願っている。