LoginSignup
16
9

More than 3 years have passed since last update.

Emacsのperspective.elワークスペースをもっと使いやすく

Last updated at Posted at 2019-12-21

この記事はEmacs Advent Calendar 2019 21日目の記事です。

20日目@tachiyamaさんの記事
最強エディタEmacsならマトリックス(っぽいこと)もできる
から引き継いで記事を書いていきます。

始めに

Emacsは万を超える組み込みコマンドと、多くのパッケージを利用することができるエディタです。我々Emacsユーザは、他のプログラマに馬鹿にされても、自分のEmacsを自分好みに改良し続けて行かなければならないのです。

冗談はここまでにしておいて(冗談じゃない?)

皆さんは超有能Emacs LispパッケージEXWM(Emacs X Window Manager) を知っているでしょうか。このパッケージはEmacsをタイル型ウィンドウマネージャとして動作されるためのパッケージです。

個人の意見ですが、EXWMには大きく2つのメリットがあると思っています。
まず、X Windowアプリケーションをバッファとして扱える機能。そして、ワークスペースの概念です。

EXWMのメリット

X WindowアプリケーションがEmacsのバッファとして扱えるため、C-x bでバッファリスト表示・切り替え・キルなどが瞬時にできます。EXWMはEmacsを使うメリットの一つである、統一されたインターフェイスでの操作を体現するパッケージなのです。

次にワークスペースの概念ですが、s-n(nには0 - 9の数字)のキーバインドでワークスペースを切り替えることができます。これが非常に便利で、ワークスペース1はプログラム用、ワークスペース2はシェル、ワークスペース3はウェブブラウザというように、脳内で整理ができて、スッキリします。

EXWMの問題点

もちろん、メリットばかりではなく、不便なところもあります。

そもそも、EXWMタイル型ウィンドウマネージャなので、フローティングウィンドウの扱いに関しては、普通に使いにくいです。(フローティングしたい場面はあまりない?)

加えて、EXWMはまだ不安定な部分があります。環境によっては起動することができなかったり、キー入力が行えない場合があります。
筆者は1年程、Debian testing上で利用していましたが、ある日突然キー入力を受け付けなくなってしまいました。

暗いGNOME生活

 後で直そうと思いながらGNOMEに避難していたんですが、いつの間にか半年以上もGNOMEを使っていました。ですが常に、GNOME上のEmacs使いづらいなあと思っていました。特に、バッファリストが1つのみなので、大量にバッファを開く私にとっては、その切り替えが面倒で仕方がありませんでした。また、ウィンドウが一つなので、大量のバッファを一度に開くこともできず、本当に使いづらいなあと。(Vから始まるエディタよりかは、はるかに便利ですが)

perspective.elを使い始めた

そこで、バッファをグループ化し、その切り替えができるperspective.elを使い始めました。これは、ワークスペースを作り出すことができ、自由に名前をつけることができます。そして、その行き来もC-c p s <名前>で切り替えることができます。しかし、このパッケージはあまり定着しませんでした。まず、キーバインドが長いですし、名前を打つのも面倒で、結局一つのワークスペースでことを済ましてしまいがちでした。そこで、次のように考えました。

切り替えのキーバインドが単純で、名前を打つ必要がなく、perspective.elのワークスペースを移動できないものか。

そこで、ひらめいたわけです。EXWMのようにs-nで簡単にperspective.elのワークスペースを切り替えることができるようにすれば良いやと。

ようやく本題

まず、やりたいことを決めます。

s-n(nには0 - 9の数字)でperspective.elのワークスペースを切り替えられるようにしたい。

方法

これを実現するための方法を適当に考えます。

  • 起動時にperspective.elのワークスペースを0 - 9の名前で作る。
  • s-nのキーバインドを(persp-switch (int-to-string n))に割り当てる。

こんな感じでできそうです。簡単です。ちなみに、筆者のEmacs Lispスキルは、読めば分かる程度で、ほとんど書けません。なので、今回書いてみたコードはEmacs Lisp流の書き方には程遠いかと思われます・・・。アドバイスがあれば是非コメント欄にお願いします。

書いてみる

完成状態

一応、考えた通りの動作をするEmacs Lispのコードを最初に書いておきます。いいから早く見せろっていう人は、このコードをinit.elに書いてみてください。ちなみに、キーバインドはs-nではなく、M-nで登録しているので、注意してください。

※追記※
先日リリースされた、Emacs 27.0.91からclライブラリが標準で廃止になり、lexical-letが使えなくなってしまったので、
それに対応するように以下のコードを変更しました。

(require 'perspective)
(persp-mode 1)

;; ワークスペース生成
(mapc (lambda (i)
        (persp-switch (int-to-string i)))
      (number-sequence 0 9))

;;;; キーに登録する関数を返す関数
;;(defun local-switch-workspace (i)
;;  (lexical-let ((index i))
;;    (lambda ()
;;      (interactive)
;;      (persp-switch (int-to-string index)))))

;;
;; 更新 2020/04/28
;;
(defun local-switch-workspace (index)
  `(lambda ()
     (interactive)
     (persp-switch (int-to-string ,index))))

;; キーバインドの登録を行う
(mapc (lambda (i)
        (global-set-key (kbd (format "M-%d" i)) (local-switch-workspace i)));;
      (number-sequence 0 9))

; 最初のワークスペースは"1"に設定
(persp-switch "1")

ワークスペースの作成

起動時にワークスペースを生成したいので、ワークスペースを作成する処理をinit.elに直接書きます。

;; ワークスペース生成
(mapc (lambda (i)
        (persp-switch (int-to-string i)))
      (number-sequence 0 9))

mapcにワークスペースを生成する関数をラムダ式と、number-sequenceで生成した0 ~ 9のリストを渡して、ワークスペースの生成を行っています。mapcは、第2引数のリストから値を一つづつ取り出し、第1引数に渡された関数に渡して実行するという関数です。この関数は非常に便利で結構多用しています。

;; キーに登録する関数を返す関数
;;(defun local-switch-workspace (i)
;;  (lexical-let ((index i))
;;    (lambda ()
;;      (interactive)
;;      (persp-switch (int-to-string index)))))

;;
;; 更新 2020/04/28
;;
(defun local-switch-workspace (index)
  `(lambda ()
     (interactive)
     (persp-switch (int-to-string ,index))))

この関数はワークスペースを切り替える関数を返します。この関数の返り値はglobal-set-keyに渡されることを前提にしています。例えば、この関数に1を渡して実行すると、(persp-switch "1")を実行する関数が帰ってくることになります。その関数をglobal-set-keyに渡すわけです。
最初は、global-set-keyにlambda式を直接渡そうとしていたんですが、どうもうまく行かなくて、このような形に落ち着きました。Google先生もとい、歴戦のEmacs Lispプログラマたちの知恵の結晶を拝見した結果、lexical-letを使う関数になりました。このlexical-letはクロージャを作るために必要になっていますが、この機能はEmacs 24.1以降で利用可能なため、それ以前のEmacsを利用している方は注意が必要です。まあ、2019年の今、Emacs 24.1より前のバージョンを使っている人は珍しいでしょうが。(筆者はEmacs 26.3を使っています)

;; キーバインドの登録を行う
(mapc (lambda (i)
        (global-set-key (kbd (format "M-%d" i)) (local-switch-workspace i)))
      (number-sequence 0 9))

ここで、実際にM-n(nは0 ~ 9の数字)にキーバインドを登録しています。内容は簡単で、mapcを使って0 ~ 9のキーにlocal-switch-workspaceの返り値の関数を登録しています。

あれ、おかしいですね

s-nに登録するはずがM-nに登録しています。すみません。Super-NumberのキーバインドはGNOMEに登録されていて、Emacsに渡すことができませんでした。なので、Altキー(Metaキー)で妥協しました。

; 最初のワークスペースは"1"に設定
(persp-switch "1")

最後にデフォルトのワークスペースを1にして終わりです。

使ってみて

大体1週間ほど使っていますが、めちゃくちゃ捗ってます。EXWMのワークスペース切り替えに関してはほぼ完全に再現できていると思います。また、裏ではperspective.elが動いているので、perspective.elが提供する機能をそのまま利用できるという利点もあります。
あと、ちょうどアドベントカレンダーのネタにできてよかったなと。

構成の紹介

最後に筆者に定着した使い方を紹介したいと思います。

WS1 ~ 4 WS5 ~ 7 WS8 ~ 9
プログラム + シェル 文章や簡単なスクリプト 空き

おわりに

ワークスペース切り替えをもっとスムーズに行いたい人は是非、init.elに書いてみてください。もしかしたらハマるかもしれませんよ(`ェ´)ピャー

16
9
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
16
9