🦬

[Emacs] M-; の連続タイプで => を入力する方法

に公開
6

はじめに

開発効率が65536倍になると言われているるびきち先生の lispxmp や rcodetools の、Rust 版を自分用に作ったのだけど M-; の連続タイプで => を入力する方法がわからなかったので先生のコードを参考にしながらコピペ改造してみる。

lispxmp

(defmacro lispxmp-comment-advice (func)
  `(defadvice ,func (around lispxmp-hack activate)
     ,(format "If `%s' is successively called, add => mark." func)
     (if (and (eq major-mode 'emacs-lisp-mode)
              (eq last-command ',func)
              (not (member "=>" (list (ignore-errors (buffer-substring (- (point) 2) (point)))
                                      (ignore-errors (buffer-substring (point) (+ (point) 2)))))))
         (insert " =>")
       ad-do-it)))
(lispxmp-comment-advice comment-dwim)
(lispxmp-comment-advice paredit-comment-dwim)

よくわからないけど major-modeemacs-lisp-mode のときに last-command が指定のコマンドと同じ、つまり2連続のときに insert を実行していることだけはわかる。

rcodetools

(defadvice comment-dwim (around rct-hack activate)
  "If comment-dwim is successively called, add => mark."
  (if (and (eq major-mode 'ruby-mode)
           (eq last-command 'comment-dwim)
           ;; TODO =>check
           )
      (insert "=>")
    ad-do-it))
;; To remove this advice.
;; (progn (ad-disable-advice 'comment-dwim 'around 'rct-hack) (ad-update 'comment-dwim))

こちらは comment-dwim だけに反応するようにしている。
lispxmp の方と比べると TODO のところは M-; を3連続でタイプしたときに insert を実行しないようにする処理だったことがわかる。
とりあえず => がさくっと入力できればよいのでここは省いてよい。

あと自分で advice を書くといつも解除できなくなって困っていたので advice を解除する方法がわかってよかった。

rust-mode 版

完成
(defadvice comment-dwim (around rustxmp-hack activate)
  "If comment-dwim is successively called, add => mark."
  (if (and (eq major-mode 'rust-mode)
           (eq last-command 'comment-dwim)
           ;; TODO =>check
           )
      (insert "=>")
    ad-do-it))
;; To remove this advice.
;; (progn (ad-disable-advice 'comment-dwim 'around 'rustxmp-hack) (ad-update 'comment-dwim))

rcodetools 版をコピペ&一部置換しただけだけどこれで問題なく動いた。

応用

コメントを書くときに TODO:FIXME: などのマークを必ず入れるようにしている場合は => のかわりに入力するようにしても良さそう。

Discussion

oberkoberk

vscodeからEmacsに移行しているのですが、EmacsでおすすめのRustの補完するelがありましたら教えてください。

megetonmegeton

教えてあげれるほど詳しくないんですけど、とりあえずボクはこちらを参考にさせてもらいました。
https://emacs-jp.github.io/env/rust
この記事の通りにやるといろいろ補完やエラーが出るようになりましたよ。
ただ始めたばかりだと、そのありがた味がわからない上にEmacsがもっさりするのでリアルタイムに動く機能はいったん無効にしてしまいました。

oberkoberk

どうもありがとうございます!
ぜひ使ってみます

rilril

Rust 版めちゃくちゃ便利そうでよいですね。この機能は任意の原語で欲しくなります。

さて、Emacs 24.4以降ではnadvice.elが導入されており、私は以下のように書いています。本家にもmerge提案したいのですが(Emacs 30以降ではdefadviceが非推奨になるので)、るびきちさん消息不明なのですよね……。

(defcustom lispxmp-comment-dwim-enable-modes (list 'emacs-lisp-mode 'lisp-mode)
  "List of major modes where lispxmp-hack-comment-dwim is enabled."
  :type 'list
  :group 'lispxmp)

(defun lispxmp-hack-comment-dwim (orig-fun &rest args)
  "If comment-dwim is successively called, add => mark."
  (if (and (apply 'derived-mode-p lispxmp-comment-dwim-enable-modes)
           (eq last-command this-command)
           (not (member "=>" (list (ignore-errors (buffer-substring (- (point) 2) (point)))
                                   (ignore-errors (buffer-substring (point) (+ (point) 2)))))))
      (insert " =>"))
  (apply orig-fun args))

(advice-add 'comment-dwim :around #'lispxmp-hack-comment-dwim)
megetonmegeton

情報ありがとうございます!
defadvice に比べて普通に defun で定義したのをひっかける方法は分かりやすくていいですね。

るびきち先生は燃え尽きてしまったんでしょうか。
真相はわかりません。

rilril

ちなみに、

(add-to-list 'lispxmp-comment-dwim-enable-modes 'rust-mode)

とすればこれだけでrust-modeでも動くと思います。この変数の調整で任意のモードで可能なはず。

advice自体のremoveは

(advice-remove 'comment-dwim #'lispxmp-hack-comment-dwim)

です。defadviceに比べるとだいぶわかりやすいですよね。