Emacsはテキストエディタであり、以前はViに並んで一時代を築いていた。現 在は、Visutal Studio Codeに押され、NeoVimに押され、その他のIDEに押され、 一時期の勢いはないように感じるかもしれない。ただまだまだ根強い人気があ り開発も活発だ。最近ではEmacs 28がリリースされた。しばらく前からEmacs はWebkitを飲み込んだため、ブラウザとして完全なるWebブラウザとしても使 用できるようになった。きっとこれからも、ますますいろんなものを飲み込ん で進化していくと思われる。少なくとも私が死ぬまでにEmacsが死ぬ 1ことはないだろう。

今回はそんなEmacsとその拡張言語であるEmacs LispのちょっとしたTipsを説 明しながら、Emacsについて考えることにする。

Emacsの柔軟さ

Emacsは他のエディタとは比較にならない程、柔軟で拡張性の高いエディタだ。 その性質をもたらしている理由の一つは、なんと言ってもEmacs Lispの柔軟性 だろう。なかなか上手くこの自由さや開放感を文章で伝えることは難しいが、 さまざまな利用方法を記述することでその一端でも感じとってもらえると嬉し い。

もちろん多くのエディタが同様の機能を実装できる。ただその機能を実装 するまでに辿る過程を考えると、ファイルに記述する必要もなく、ただ単純に 関数を書いてそれを評価すれば挙動が変更されるというのは他のエディタにも なかなかないだろう。Emacs Lispには厳密な名前空間もない。それは一見デメ リットのようにも感じられるかもしれない。似たようなものとして挙げるとす るとCSSもそうだろう。きちんとした名前空間がないと、パッケージの仕組み が上手く機能せず、グローバルな領域に様々なシンボルがごちゃまぜの状態で 定義されるようにも思える。CSSはそのためにBEMやSMACSSといった命名規則で その問題を解消しようとした。Emacs Lispもそれと良くにている。Emacs Lisp には requireprovidedefgroup といった関数やマクロが用意さ れ、命名規則のみではないパッケージ機構を導入している。ただし定義された 関数や多くの変数はあらゆるところから参照でき、また様々な形で上書きでき る。この一見カオスなように感じる状況も、Emacsの挙動を柔軟に変更したい 場合にはとても重宝する。気に入らない関数があれば、その関数をスクラッチ バッファにコピーし書き換えて評価することで、上書きしてしまえばよい。

Emacs Lispよりも名前空間をはっきりさせているPythonのような言語でEmacs が記述されていて、拡張のためにPythonを用いるようなことがあるとすると、 きっとこのようにはいかない。名前空間の下に存在する関数を書き換えるのは 結構手間だ。Emacsの柔軟さはこのEmacs Lispの仕様によって支えられている と思う。

マークしたリージョンの文字列になんらかの処理を行う

(interactive "r") を用いるとリージョンに指定したポジションをコマンド 実行時に取得できる。選択した領域の文字列に対して、何らかの処理を行いた い状況にしばしば出会う。そんな時にこの機能を使って即席のコマンドを定義 すると、自由度が増す。

以下では例として選択した領域の文字列をprintする。

(defun testing-region (&optional beg end)
  (interactive "r")
  (print (buffer-substring-no-properties beg end)))

この文字列をbase64でエンコードしたければ次のようになる。

(require 'base64)

(defun testing-region (&optional beg end)
  (interactive "r")
  (print (base64-encode-string (buffer-substring-no-properties beg end))))

他にもさまざまな使い方ができるだろう。

マシンをスリープ状態にする

Emacs上からマシンをスリープ状態にする。現状ではmacOS10.9以降のみ対応している。

(defun sleep-machine-system-command ()
  (pcase system-type
    ('darwin '("pmset" "sleepnow"))
    (t nil)))

(defun sleep-machine ()
  (interactive)
  (if-let ((cmds (sleep-machine-system-command)))
      (apply #'call-process (car cmds) nil nil nil (cdr cmds))
    (error "Failed to sleep machine: Not support sysmte type")))

Emacsでtimestampを取得する

(float-time)
1641478725.882611

少数を切り捨てる

(truncate (float-time))
1641478716

日付のフォーマットをUNIXタイムスタンプに変換する

(truncate
 (float-time (date-to-time
	      "2020-10-11T21:36:21+0900")))
1602419781

package-selected-packagesへの要素の追加と削除

package-selected-packagesはpackage.elで管理している値で、 package-installなどでパッケージをインストールすると パッケージのシンボルが追加される。 通常その値はcustom-set-variablesなどに自動で設定される。 以下のように直接操作することは基本的にはない。

(package--save-selected-packages
 (cons 'testing package-selected-packages))
追加
(package--save-selected-packages
 (remove 'testing package-selected-packages))
削除

脚注


1

Emacsはこれまで何度も死んだという内容のWeb記事が投稿されている。人気のある(もしくはあった)技術トピックはそういうものから逃げられないのかもしれない。あくまでネタであり、真に受けたり、目くじら立てて怒ったりせず、エンタメとして楽しむと良いと思う。夏の風物詩のようなものだ。私もそのようなと記事がとっても好きだ。くだらなくて、面白くて、少しノスタルジーを感じ、そしてちょっと考えさせられる。そんな文章がもっとたくさん生産される世の中になれば良いと思っている。少なくとも、飢餓や戦争で苦しんだりする世の中よりよっぽどマシで正気な世界だと思う。