Lisp読み書きできないけどEmacs使いたい

Emacsのhelmを使いこなしてみる

僕自身はずっとanything使っててhelmに移行したくねぇ〜と思ってたけどついにmelpaからanythingが削除されてしまって、しぶしぶhelmを使っていた。

helmの基本機能しか使ってこなかったので、ここらで気合い入れて使いこなしてみる。

残念ながら、Emacs界隈はhelmよりivyの流れできてるよね。22世紀でもhelmかと言われたら厳しそうな雰囲気がプンプンしてる。

helmとはなんぞやと言うと、一言で言えばEmacsの対話型の処理を拡張するものと言える。具体的にはファイル検索やバッファーリスト、キリングリスト、M-xによるコマンド実行など。これら機能をhelmはより使いやすくしてくれる。

最後にhelmに関するelispの設定置いてある。

インストール

僕はel-getつかちゃってるんで~/.emacs.d/init.elにこれだけで記述すればインストールできちゃうが 、melpaやleafの人はそれに合わせてインストールして。

;; helm
(el-get-bundle helm)
(require 'helm-config)

プレフィックスを設定

helmのショートカットコマンドを実行する時に接頭辞としてC-c hを宣言する。これで多くのhelmに関するキーバインドC-c hから始まるものになる。言うても、よく使う奴は別にキーバインド割り振るからどうかなとも思う。

;; helmのキーバインドプレフィックスをC-c hで始まるように変更
(global-set-key (kbd "C-c h") 'helm-command-prefix)

このプレフィックスで利用できるキーバインド一覧をみるには少々難しいがこのキーバインドを実行すれば閲覧できる。

C-c h C-h

f:id:nuy:20200909224836j:plain

helmの設定

helmは多くの変数を持っていて、用途に合わせて設定することでより使いやすい環境を作れる。

とにかく多いので、何をどう設定したらどうなるのか全く分からんが、いろんなサイトを訪問してそれなりに良さげな設定を揃えた。

(setq helm-split-window-inside-p            t  ; 画面分割しても同じバッファ内にhelmのバッファを表示
      helm-move-to-line-cycle-in-source     t  ; helmバッファ内で候補の最後に到達したら上に戻る
      helm-ff-search-library-in-sexp        t  ; よく分からんがライブラリの中も検索するみたいな
      helm-echo-input-in-header-line        t)  ; helmのバッファの上部にコンソールの内容を表示

helm-split-window-inside-p

デフォルトは画面を分割した状態でhelmのバッファを開くと、アクティブでないフレームに表示される。

f:id:nuy:20200909225031j:plain

アクティブにすると各フレーム内で表示される。

f:id:nuy:20200912121823j:plain

helm-move-to-line-cycle-in-source

デフォルトではhelmバッファ内でカーソルが候補をループせず下まで移動する。実際にC-nで移動してみると分かりやすいと思う。

アクティブにすると、例えばmini-buffer内ではBuffersのセクションでカーソル移動がループする。

f:id:nuy:20200912121837j:plain

それじゃあその下のRecentfやCreate Bufferのセクションてどう行くの?って疑問に思う。これは、helmバッファ内でのセクション移動はC-oで行う。

helm-M-xでよく使うから覚えておいた方が良い。helm-M-xはcommand historyが無い時はコマンド候補をすぐに移動できるのだけど、履歴が作られると、Emacs Commands historyからEmacs CommandsC-oしないと飛べない。

f:id:nuy:20200912121849j:plain

helm-echo-input-in-header-line

これをアクティブにするとhelmミニバッファの一番上にエコーエリアで打ち込んでいる内容が表示される。

f:id:nuy:20200912121903j:plain

Helm M-x

EmacsM-xと言えばEmacsでコマンドを実行する時に利用するキーバインドである。

冒頭でも書いた様にhelmはEmacsの対話的な機能の拡張でこれもそれである。

;; Emacsのechoエリアをhelmで拡張
(global-set-key (kbd "M-x") 'helm-M-x)

M-xをタイプし、例えばforward-charと打ち込む。単語を全部打ち込みなくてもすぐに候補が出てくる。候補の移動はカーソルの移動と同じ様にC-nで下にC-pで上に移動する。目的のコマンドにハイライトを合わせてエンターを押せば実行される。

f:id:nuy:20200912121917j:plain

2回目以降はEmacs Commands historyセクションにカーソルが置かれていると思う。実行履歴から再びコマンドを実行したい場合はそこから選ぶ。

そうじゃなくて、新たに候補を探したい場合は上で説明した様にC-oでセクションを飛ぶ。

f:id:nuy:20200912121932j:plain

Helm kill ring

Emacs内でコピーまたはカットした内容を参照し、貼り付けすることができる。

C-kによる行の削除、リージョン選択中M-wC-wの内容が保存されている。

使い方は簡単M-yで起動して、貼り付けたい内容を選び、エンターを押す。

;; helmのkill ringを表示する
(global-set-key (kbd "M-y") 'helm-show-kill-ring)

f:id:nuy:20200912122006j:plain

Helm mini buffer

helmの最も魅力的な機能で、バッファーの一覧"Buffers"、最近開いたファイル一覧"Recentf"、あと殆ど使わないけど"Create buffer"がある。

;; 様々なソースへアクセスできるバッファ
(global-set-key (kbd "C-x C-a") 'helm-mini)

上のコードのキーバインドC-x C-aはhelmの元となったanythingで使われたもので、僕はすっかりこれに慣れちゃったので今もそうしている。他の人のコードの見るとC-x bとかしてるので好きな様にしてみて。

Buffers

バッファーでは今Emacsで開いているバッファを一覧で確認し移動できる。 カーソルの移動は他と同じくC-nで下にC-pで上にいく。移動したいファイルが見つかったから、エンターを押せばそのファイルのバッファが開く。

色々ファイルを開きまくると、バッファがものすごい量になるので、使わないバッファが出てきたらカーソルを当ててC-c dで削除できる。

f:id:nuy:20200912121948j:plain

Recentf

これは最近利用したファイルの履歴が出ている。最近使ったものなら、いちいちC-x C-fして探さなくてもこの候補から開くことができる。

ミニバッファを開くとカーソルはBuffersセクションにいるので、Recentfに移動するときはC-oで移動する。

Create buffer

ミニバッファから直接利用することはあまり無いが、エコーエリアでファイル名を入力した時に、BuffersにもRecentfにも候補がない場合Create bufferがアクティブになり、ファイルを作成できる。

f:id:nuy:20200912122043j:plain

helm-find-files

Emacsのファイル探索機能を拡張してくれる。検索機能やディレクトリ移動も便利になる。

下のコードではファイルとフォルダの候補の絞り込み、移動にタブを使う設定を加えている。

これhelmではアンチパターンである。helmではそういった操作をする時にタブを使うのではなく、ファイル名またはフォルダ名をタイプしてエンター、タイプしてエンターを繰り返して移動する事を推奨している。

しかしLinux系ではディレクトリの候補の表示と移動ではタブを使うことが多い。その使い方に慣れていると、helmの候補の絞り込みと移動はやりづらい。個人的にhelmの思想を無視してタブで候補に移動したり絞り込んだりできる様にしている。

もしも、helmの本来のやり方にしたい場合は下のコードのタブの記述をコメントアウトして使って欲しい。

;; ファイル探すのをhelmモードにする
(global-set-key (kbd "C-x C-f") 'helm-find-files)
;; ファイル探し候補をタブで補完
(define-key helm-read-file-map (kbd "TAB") 'helm-execute-persistent-action)
(define-key helm-find-files-map (kbd "TAB") 'helm-execute-persistent-action)

file-filesの使い方

候補の移動は他の場合と同じ様にC-nで下にC-pで上に移動する。

フォルダにカーソルを当てて、TABを押すとそのフォルダの中に入れる。1つ上の階層に戻るときはC-lで移動する。

エコーエリアにキーワードをタイプするとそれにマッチするファイルかフォルダだけが表示される。

目的のファイルが見つかったら、それにカーソルを合わせて、エンターを押すとファイルが開く。

f:id:nuy:20200912122107j:plain

helm-occur

helm-occurはファイル内のキーワード複数検索機能だ。

キーワードがあらかじめ複数あると分かっていて、その中のどれかを探す時にoccurは役に立つ。

;; ファイル内のキーワード検索と絞り込み移動
(global-set-key (kbd "C-c o") 'helm-occur)

例えば、Lispコードの中からざっくりsetqだけを表示できる。C-sで探すこともできるが、候補が多いと移動が大変なのでこれはありがたい。

f:id:nuy:20200912122120j:plain

helm-imenu

ファイル内の関数一覧を表示してくれる。しかし、jsのes6のクラス内関数とかちょっと複雑なものは表示してくれない。

;; 関数をざっくり一覧で表示
(global-set-key (kbd "C-c i") 'helm-imenu)

f:id:nuy:20200912122134j:plain

その他

バッファーとRecentf単体で表示できるキーバインドも用意しておく。ほとんどの場合helm mini-bufferで事足りるので滅多に使わない。

;; 最近利用したファイル一覧を表示
(global-set-key (kbd "C-x C-r") 'helm-recentf)

;; バッファーリストを表示
(global-set-key (kbd "C-x b")   'helm-buffers-list)

最後に

helmはあまりに変数と関数があるので、ここでは紹介しきれないものが多くあります。この記事で興味を持った方はgithubをみたりして、カスタマイズに挑戦してみて欲しい。