Yearly Archives: 2023

2023-08-06 ,

org-inline-image-fixのEmacs 29対応

先日も書いたように、Emacs 29に移行したらorg-modeで警告が繰り返し沢山出るようになった。

⛔ Warning (emacs): Redefining ‘file-exists-p’ might break native compilation of trampolines.
⛔ Warning (emacs): Redefining ‘expand-file-name’ might break native compilation of trampolines.

file-exists-pexpand-file-name を再定義? そんなことしてないだろう……と思ったが、ふと思い当たってorg-datauri-image.elorg-http-inline-image.elを無効化したら治まった。

これらはorg-inline-image-fixの中にあるEmacs Lispで、 [[data:[[http:[[https: で始まるリンクをインライン画像表示するためのものだ。それをorg-flyimage.elを使ってfont-lockのタイミングで自動的に即事画像化しているので、警告が繰り返し沢山出るというわけだ。

misohena/org-inline-image-fix: A collection of fixes related to the image display feature in org-mode

それらのEmacs Lispは、cl-letfを使ってインライン画像表示関数(org-display-inline-images)の中にいる間だけそこから呼び出される各種関数の挙動を変更し、無理矢理機能を実現している。その挙動を変更した関数の中にfile-exists-pやexpand-file-nameといったC言語で実装された関数があるため、何らかの理由でnative compilationと相性が悪いのだろう。

この方法はかなり強引だが、結果的にはうまく行った。過去何回かのorg-modeのバージョンアップに伴いorg-display-inline-images関数には度々変更が加えられたが、これらのEmacs Lispは何も変更せずに動作し続けた。もしorg-display-inline-imagesの一部をコピーした新しい関数を作成してそれに置き換えたりしていたら、org-modeのバージョンアップに伴い度々変更を取りこむ必要があったことだろう。もちろんこれはたまたま変更箇所が衝突しなかったということであり運が良かっただけとも言えるのだが、その賭けに私は勝ったわけだ。

しかし今、そのcl-letfを使う方法は封じられた。org-display-inline-images関数は一つの関数の中で多くのことをやり過ぎている。単純なadviceの追加ではどうにもならない。もはやorg-display-inline-images関数をコピーして、バラバラに切り刻み、よりカスタマイズしやすい形に再構成するしか道は無いように思える。

というわけで作成したのがorg-better-inline-images.elだ。これはorg-display-inline-images関数をよりカスタマイズしやすいものに置き換える。

そしてorg-datauri-image.elとorg-http-inline-image.elはそれを使うように書き替えた。

それによってEmacs 29でも警告が出ずにdata、http、httpsのリンクをインライン画像表示できるようになった。その代わり、org-modeのバージョンアップに伴うorg-display-inline-images関数の変化に注視し、必要な変更を取りこむ負担を負うことにもなったわけだ。

めでたしめでたし。

ちなみにorg-ytというパッケージがある。YouTubeリンクを実現するためのものだが、インライン画像表示にも対応している。ytリンクタイプのインライン画像表示は、org-display-inline-images関数に:after adviceを仕込むことで実現している。更新範囲の走査が二回になってしまうのが多少気になるところだ。また、結局はorg-display-inline-imagesの一部をコピーしたorg-image-update-overlayという関数を作成しているので、org-display-inline-imagesの変化に追従していく手間は避けられないだろう。一方で、ytリンクタイプに限らず任意のリンクタイプをサポートするための枠組みを提供しているのは興味深い点だ。org-modeが元々そのような仕組みを提供していたら皆ここまで悩まずに済んだことだろう(ただし、org-ytはdescription部分の画像リンクには対応していないように見える)。

2023-07-31

MS-Windows版 Emacs 29.1への移行作業

Emacs 29.1がリリースされたと聞いてファイル置き場を覗いてみたらまだWindows版が置いておらず、1日くらい待ってたまにはビルドしようかなーとソースコードを取りに行ったらすでにWindows版のバイナリが置いてありました。仕事が速いですね。

最近はIMEパッチも使っていないのでビルドする機会がほとんど無くなってしまいました。まぁ、自分でビルドしたら色々良いこともあるとは思いますが。細かい不具合を好きなだけ直せたりとかね!

それで一応移行作業をしたので以下その記録です。

(2025-02-24追記: Emacs 30.1の設定(MS-Windows)はこちら)

1.ダウンロード

https://ftp.gnu.org/gnu/emacs/

  • emacs-29.1.zip
  • emacs-29.1.tar.xz (展開してfind-function-C-source-directory変数に指定し、describe-functionからソースコードを追えるようにするため)

2.zipを展開して適当な場所に置く

3.起動してみる

パッと見問題無し。

4.補う必要のあるファイルを確認する

  • 相変わらずlibgccjit関連のファイルは含まれていないのでネイティブコンパイルはそのままでは出来ない。
  • gdk_pixbufのloadersもないので、SVG内のimage要素も表示されない。

5.MSYS2で必要なファイルを取り寄せる

あ、MSYS2はucrt64環境に移行してしまったのでmingw64環境のファイルは無いんだった。パッケージアーカイブから直接ダウンロードすることも出来るかもしれないけど、面倒なのでMSYS2環境からインストールしてしまう。

pacman -S mingw-w64-x86_64-libgccjit
pacman -S mingw-w64-x86_64-gdk-pixbuf2

6.SVG内の画像要素を表示できるようにする

まずは簡単な方から。 msys64/mingw64/lib/gdk-pixbuf-2.0 ディレクトリを emacs-29.1/lib/ へコピー。これでSVG内のimage要素は表示できた。 loaders.cache については何もしなくて大丈夫だった。画像形式によっては追加の依存ファイルがあるかも? とりあえずjpgとpngは問題なし。

(以前も書いたが、SVGの描画はlibrsvgが行っており、librsvgはlibgdk_pixbufのローダーライブラリを使用して画像を読み込むので、これらのファイルが無いとSVG内に画像が表示されない。Emacsがjpgやpngを描画する仕組みとSVG内にjpgやpngを描画する仕組みは全然別物なのだ。用途としてはel-easydrawの画像ツール)

7.ネイティブコンパイルできるようにする

次のファイルをコピー。

  • emacs-29.1/binへ
    • msys64/mingw64/binから
      • libgccjit-0.dll
      • libisl-23.dll
      • libmpc-3.dll
      • libmpfr-6.dll
  • emacs-29.1/lib/gccへ
    • msys64/mingw64/binから
      • as.exe
      • ld.exe
    • msys64/mingw64/libから
      • crtbegin.o
      • crtend.o
      • dllcrt2.o
      • libadvapi32.a
      • libgcc_s.a
      • libkernel32.a
      • libmingw32.a
      • libmingwex.a
      • libmoldname.a
      • libmsvcrt.a
      • libpthread.a
      • libshell32.a
      • libuser32.a
    • msys64/mingw64/lib/gcc/x86_64-w64-mingw32/13.1.0/から
      • libgcc.a

.aや.oは全部必要なのか、また、不足するものが無いのかは確認していない。

./emacs.d/early-init.el には次のように設定してあるが、あまり覚えていないので正しいかは知らない。

(when (and (fboundp #'native-comp-available-p) ;;emacs-28以降
           (native-comp-available-p) ;;libgccjitが使える
           (eq system-type 'windows-nt)) ;;Windowsの場合 (他必要に応じて条件を追加すること)

  ;; コンパイル用にemacsを起動する関数をラップし、
  ;; カレントディレクトリを一時的に変更する
  (defun my-comp-set-env-and-call (orig-fun &rest args)
    ;; 一時的にカレントディレクトリを emacs-28.1/bin にする
    ;; でないと emacs-28.1/lib/gcc/as.exe を見つけてくれない
    ;; また、emacs-async-comp-*.elというファイルをあちこちに生成してしまう。
    (let ((default-directory invocation-directory))
      ;; 元の関数を呼び出す
      (apply orig-fun args)))

  (advice-add #'comp-final :around #'my-comp-set-env-and-call)
  (advice-add #'comp-run-async-workers :around #'my-comp-set-env-and-call)

  ;; ライブラリの位置を指定する
  (setq native-comp-driver-options (list "-B" (expand-file-name (file-name-concat invocation-directory "../lib/gcc")) )))

8.org-datauri-image.elとorg-http-inline-image.elを無効化する

次のような警告が沢山出て何かと思ったら自分で書いたクソコードが火を噴いただけだった。

⛔ Warning (emacs): Redefining ‘file-exists-p’ might break native compilation of trampolines.
⛔ Warning (emacs): Redefining ‘expand-file-name’ might break native compilation of trampolines.

cl-letfで一時的にsymbol-function書き替えたから。

そのうち書き直したい。

2023-04-17

新しいマウスを購入(Logicool M750)

一昨日、昨日と新しいマウスを購入した。

これまで使っていたMX Anywhere 2の左ボタンが連打されるようになってしまったからだ。ウィンドウ移動時に最大化されてしまったりあちこちで誤操作して困っていた。ちょっと前にクッキークリッカーで高橋名人バリの連射をしたのが寿命を縮めたのだろうか?

順当に行けば代わりは後継機のMX Anywhere 3なのだろうけど、このマウスはちょっと高い(Amazonで11000円くらい)。それにこれまで2を使ってきて不満も無いわけでは無い。一番はバッテリー。バッテリーがすぐに切れてしまうのでしょっちゅう有線マウス状態で使っていた。ちなみに私は無線マウスにそれほど価値を感じていない。机の上で使っている分には線が付いていようがいまいが操作性に差は無いからだ。ただ、接続が楽なこととPCを引き出すときにケーブルが引っかからないのは良い所だろう。充電だけならテーブルの上に出してあるテーブルタップに繋げれば良いが、机の下のPCに繋げるとなると多少配線に苦労する。自宅のデスクトップ専用のマウスなのでマルチペアリングや軽量性は必要ない。あまりUSBポートにドングルばかり挿したくないのでBluetoothが良い。専用ドングルのみだと困る。左右チルトは使っていない。そう考えると何も後継機にこだわる必要は無いだろう。

そうしてWeb上で新しいマウスを探して目を付けたのがM650。安いマウスでも十分だとは思ったが変なものに当たって何度も買い直すようだと困る(結果的には買い直したがw)。信頼の置ける同じメーカーということでロジクールの中から一番無難そうなM650にした。近所の量販店に行ったついでに購入。意外なことに通販とほとんど変わらない値段だった。

ロジクール Signature M650MOW ワイヤレスマウス

単三乾電池一本で長期間動くのでバッテリー劣化で悩む心配は無い。握りやすさも問題ない。LサイズもあったがMサイズにした。手は大きい方だが、小さめなマウスを指先でちょこちょこ動かしたいので。そういう意味ではこれ以上大きいと困るギリギリのサイズ。モバイル用途ならもう少し小さいものを選びたいところ。ボタンは静音仕様だがクリック感に問題は無い。ホイールを回したときのクリック感も柔らかいがしっかりとある。接続性も問題なし。

しかし実際に使ってすぐに気がついたのが専用の中ボタンが無いということだ。私は中ボタンをよく使うのでMX Anywhere 2ではホイール下のジェスチャーボタンを中ボタンにして使っていた。しかしこのM650にはホイール下に独立したボタンが無い。もちろんホイールはクリックできて中ボタンとして機能する。しかし硬いので押しづらい。ホイールの回転は柔らかいので押そうとすると先にホイールが回ったりもする。長いことMX Anywhere 2を使っている間にこういう問題があったことをすっかり忘れてしまっていた。

el-easydrawにスクロール機能を付けたとき、私は中ボタンドラッグをスクロールに割り当てた。この手のソフトではよく見る操作体系だが私はあまり好きでは無くPhotoshopと同じSPACE+ドラッグが好きだったりする。しかしEmacsではSPACEをmodifierとして使う方法が無いので仕方なく中ドラッグにしたのだった(代わりにSPACEでスクロール・ズームモードになる機能も追加したがモード切替はやはり少々使いづらい)。試しにel-easydrawでスクロールしてみたが、やはりボタンが硬くてスクロールしづらい。ホイールも微妙に回ってしまうので何だか指先が気持ち悪い。

実はM650の上位機種であるM750にはホイールの下に中央ボタンがついているのだった。デフォルトでは速度切り替えボタンになっているが中ボタンに割り当てることも出来る。全体的な形はM650と同じで機能が増えてわずかに重くなっている程度だ。

Logicool Signature M750MOW ワイヤレスマウス

というわけで、かなり勿体ないような気もしたがM750を追加で購入した。中央ボタンの位置がMX Anywhere 2と比べてやや手前でわずかに押しづらくはあるが、まぁ、それほど大きな問題では無い。M650よりは大幅に楽に中ボタンが押せるようになった。ホイールのボタンの方はタブを閉じる操作に割り当てた。こりゃ便利だ。

ホイール(M650、M750で違いは無い)の回転は柔らかいクリック感がありMX Anywhere 2のようなフリースピン切り替えは無いが、フリーモードとクリックモードの中間といったところ。SmartWheelという機能でゆっくり回したときと高速に回したときに挙動が変わるが、かなり自然な動きになっている。ホイールをびゃーっとはじいたときはちゃんとそれらしい動きをする。中間くらいの動きで時々アレ?とわずかに違和感を覚えることもあるが、今のところ実用上特に問題は無い。

全体的にこれまでのMX Anywhere 2と比べて大きな問題は無く、コストパフォーマンスの高いマウスだと感じた。