Category Archives: 未分類

2024-09-12

最近Emacs関連でやったカスタマイズ

tramp-default-methodをplinkにする

久しぶりにMSYS2をアップグレードしたせいか分からないけれど、なぜか突然trampがscpxで繋がらなくなった。少しだけ原因を調べてみたけどよく分からなかったので諦めてplinkを使うことに。これまで頑なにplinkを使うことを避けていたのだけど、使ってみたら超快適! なぜいままで使っていなかったのかと。パスフレーズの記憶がssh-agentと一緒にならないのは良くないところだけど。

暇があったらなぜ動かなくなったのか調べてみたい。そもそもtrampはどうやって動いているのかよく知らない。

Emacsの標準機能でメールを送れるようにする

これまでメールと言えばWanderlustばっかり使っていたんだけど、Emacsの標準機能だけでメールを送れるようにしてみた(Sending Mail (GNU Emacs Manual (Japanese Translation)))。

(setq smtpmail-default-smtp-server "smtp.gmail.com"
      smtpmail-smtp-server "smtp.gmail.com"
      smtpmail-smtp-service 587
      smtpmail-stream-type 'starttls
      smtpmail-local-domain nil
      smtpmail-smtp-user "<username>")

後は.authinfoにごにょごにょと。面倒だからアプリパスワードも使っちゃう。この辺りは人によってセキュリティ的に許容できないだろう。

ちなみにEmacsに標準で組み込まれているメール作成のためのパッケージ(MUA)には次のものがある(define-mail-user-agentで検索):

また、メールを送信する方法には次のものがある:

上の設定はsmtpmailで送るためのもの。

image-diredでサムネイルが横になるのを直す

ExifのOrientationで回転させている写真が回転していないので直した。

image-dired-cmd-create-thumbnail-options に "-auto-orient" オプションを追加しただけ。

image-diredのサムネイルサイズを変更

前々からどのくらいのサムネイルサイズが最適なんだろうかと疑問に思っていた。小さすぎると内容が分からないし、大きすぎると一度に沢山の画像を並べられない。私が普段使っているテキスト領域の幅は640pxなので、横に3つ並ぶサイズということで image-dired-thumb-size を 196 にした。サムネイル毎の余白に案外スペースを取られる。

縦画像のサムネイルが左寄せで表示されるので、そのうち中央寄せされるように直したい。

image-diredのキー割り当てを変更

サムネイルを表示するバッファ( *image-dired* バッファ)のキーマップがdiredと違っていて戸惑うことがよくあるので、できるだけdiredに近づけるようにした。特に外部ビューアで開くキー。

次表示(SPC)、前表示(DEL)は良くある操作方法だけど、DEL(私はC-hをDELにしている)が押しづらいのでnとpに割り当ててしまった。fとbの方が良いのかもしれないけれど、dired上でファイルを移動するのがnとpだし、next-lineではなくnext-imageだと考えればそこまでおかしくもない気がする。いや、やっぱりfとbの方が使いやすいだろうか。そもそもC-f C-m、C-b C-mと押すのがそんなに面倒だろうか。SPCはそれほど苦では無いのだから、bだけ割り当てれば良いのかもしれない。

image-diredは使えば使うほど直したいところが出てくるのでまたそのうち。

2024-06-22 ,

org-gotoで日本語で検索(インクリメンタルサーチ)できない不具合を修正

org-modeで C-c C-j (org-goto) を実行し、日本語(マルチバイト文字)を入力すると次のようなエラーが出てインクリメンタルサーチできない(Org9.7.3時点)。

funcall-interactively: Wrong type argument: stringp, [12375]

consult-org-heading なり consult-outline なりを使えば良いような気もするけど気持ち悪いので一応直しておく(org-goto-local-auto-isearchに対する修正)。

;; org-gotoで日本語検索が出来ない問題を修正
(with-eval-after-load "org-goto"
  ;; 関数を置き換える。
  (defun org-goto-local-auto-isearch ()
    "Start isearch."
    (interactive)
    (let ((keys (this-command-keys)))
      (when (eq (lookup-key isearch-mode-map keys) 'isearch-printing-char)
        (isearch-mode t)
        ;; ここから修正
        ;; 元: (isearch-process-search-char (string-to-char keys))
        (cond
         ((vectorp keys)
          (when (< 0 (length keys))
            (let ((ch (aref keys 0)))
              (when (integerp ch)
                (isearch-process-search-char ch)))))
         ((stringp keys)
          (isearch-process-search-char (string-to-char keys))))
        ;; ここまで修正
        (font-lock-ensure)))))

this-command-keys はキーシーケンスを文字列で返すこともあればvectorで返すこともあるのだとか(Strings of Events (GNU Emacs Lisp Reference Manual))。

2024-06-19

xrefでメソッドへジャンプできなくなる問題に対処する

Emacs Lispをいじっているときに、cl-defmethodで定義したメソッドへM-.(xref-find-definitions)でジャンプできなくなることがたまにあったので次のように対処しました。(Emacs29時点)

;; xrefでメソッドに飛べなくなるのを回避するハック。
;; defgenericを使わずにdefmethodをloadし直すと起きる問題に対処する。
;; `elisp--xref-find-definitions:around'から`find-lisp-object-file-name'を
;; 呼び出したときの挙動を変更する。
(defun my-elisp--xref-find-definitions:around (old-fun &rest args)
  (cl-letf* ((flofn-old (symbol-function 'find-lisp-object-file-name))
             ((symbol-function 'find-lisp-object-file-name)
              (lambda (object &rest flofn-args)
                (or (apply flofn-old object flofn-args)
                    ;; 本来のfind-lisp-object-file-nameの結果がnullでかつ
                    ;; OBJECTがgeneric関数シンボルなら
                    ;; 空のファイル名を返すことで
                    ;; elisp--xref-find-definitions内の
                    ;; メソッド列挙部に到達させるハック。
                    ;; 本来ならその部分のFIXMEにも書いてある通り
                    ;; その部分を`elisp-xref-find-def-functions'に分離
                    ;; すべきだと思われる。
                    (when (and (symbolp object) (cl--generic object))
                      "")))))
    (apply old-fun args)))
(advice-add 'elisp--xref-find-definitions :around
            'my-elisp--xref-find-definitions:around)

根本的な原因は私がcl-defgenericせずにcl-defmethodしているからなのですが、まぁ、そこは良いんです。かったるくてやってられないから省いているだけので。それがダメというならmy-defmethodでも作らにゃなりません。しかし、まぁ、そのツケが回ってきたというだけの話ではあります。

xref等はsymbol-file関数を使ってシンボルを定義したファイルを特定しますが、そのsymbol-fileload-history変数に記録されたファイルとシンボル定義の対応表(alist)を参照します。elファイルをloadするとその過程で定義されたシンボルがこの変数に記録されるわけですが、cl-defmethodは既にgeneric関数が定義されているときには新たにgeneric関数を定義しないので、同じelファイルを2回ロードすると暗黙的に作成されたgeneric関数のファイル名が消えてしまいます。elisp--xref-find-definitionsはgeneric関数のファイル名が取得できないとメソッドのファイル名も列挙しないので、結果定義されているはずのメソッドに飛べなくなるわけです。

上の変更では、generic関数のファイル名が特定できなかった場合に空文字列のファイル名を返すことで特定できたことにして、メソッドの列挙部分に無理矢理処理を通します。幸いなことにxrefは空文字列のファイル名を無視してくれる(ジャンプ先候補に出さない)ようです。

ろくなもんじゃありませんけど、とりあえずはこれで。

ちゃんとやるならelisp--xref-find-definitionsのFIXMEコメントに書かれているようにgeneric&method列挙部分をelisp-xref-find-def-functions変数に登録する関数としてくくりだした上で、その中でgeneric関数のファイル名が特定できなくてもメソッドのファイル名を列挙するようにするのが良さそうです。

今回はシンボルと定義ファイル名の割り出し方法に関するお勉強でした。