2022-02-20

Emacs on Windows: Markdown command *** is not found

先日、markdown-mode が更新(v2.5)されていることに気が付いた。今使っているのが v2.3。あれ、v2.4 リリースには気付かなかったっけ?と思いながら v2.5 にして暫くした後、markdown コマンドが動かなくなっていることに気が付いた。

Markdown command markdown is not found

あー、なんか思い出してきた。昔 v2.4 にした時、やはり markdown コマンドが動かなくて v2.3 に戻したような気がする。v2.5 になっても直っていないということは、直す気がないか、私の環境がニッチなのだろう。このままずっと v2.3 というのも嫌なので、面倒だが調べてみる。

私の環境は MSYS2 + NTEmacs。M-! (shell-command)では markdown コマンドを実行できる。しかし markdown-mode からだと見つけられない。

      (when (and (stringp command) (not (executable-find command)))
        (user-error "Markdown command %s is not found" command))

上記が問題の部分。

(executable-find "markdown")
nil

(locate-file "markdown" exec-path)
"c:/home/user/bin/markdown"

これだ。私の場合、markdown コマンドは Ruby スクリプトだ。MSYS2 からは実行できても、実行ビットを解さない NTEmacs には単なるファイルにしか見えない。幸い、markdown-command にはリストも設定できるので、下記のようにして解決した。

(when (executable-find "env")
  (setq markdown-command `("env" ,markdown-command)))

以上、結果からいうと、やはり私の環境のせいだった。しかし NTEmacs のことを考慮すれば、executable-find のチェックはやり過ぎのように感じる。単に locate-file にするか、そもそもチェックする必要があるのか?という気もする。困っているのが私だけなら良いのだが。

2022-02-12

Emacs: Manage packages specifying version

私は Elisp 管理に長らく SCM を使ってきた。Wanderlust を例にとると、本体と依存パッケージをソースコードごと SCM に登録し、チェックアウトするだけで使えるようにしている。もちろんこの方法だとパッケージのバージョンアップが面倒だし、ビルドが必要なものはチェックアウトするだけという訳にはいかない。それでも、私にはこの運用でうまくいっていた。

package.el (Emacs 24)リリース時、遂に Emacs もそんな時代になったか、と感動したものだ。しかし今となっては、私の中では最も期待外れの機能となってしまった。今時、最新版しかインストールできないものをパッケージマネージャーとは呼べない。そんなものはとうの昔に RubyGems が終わらせたと思っている。今まで package.el の更新を待っていたが、もう見限ろうと思う。さすがに 8 年も待って気が短いとは言わせない。

ということでパッケージ管理の方法を探したところ、私には El-Get が適当だろう、という結論に至った。straight.el の Lockfile は私が欲しかったものだが、肝心のバージョンを指定してインストールする方法がないように見えた。それに私は 10 年後も安心して使い続けられる方法を探している。その意味でも El-Get が安定してそうな気がする。

・・・というのが約 2 年前の話。幸い、今のところ El-Get でうまくいっている。メイン環境は MSYS2 + NTEmacs で、現在の設定は下記のようになっている。

(add-to-list 'load-path
	     (expand-file-name "el-get/el-get" user-emacs-directory))
(setq el-get-verbose t
      el-get-byte-compile nil
      el-get-bundle-byte-compile nil
      el-get-install-info nil)
(unless (require 'el-get nil 'noerror)
  (with-current-buffer
      (url-retrieve-synchronously
       "https://raw.githubusercontent.com/dimitri/el-get/master/el-get-install.el")
    (let ((el-get-install-shallow-clone)
	  (el-get-install-skip-emacswiki-recipes))
      (goto-char (point-max))
      (eval-print-last-sexp))))

;; Ex: install company-mode
(el-get-bundle company-mode/company-mode
  :branch "0.9.13"
  :shallow t
  (global-company-mode))

上記には私の我がままが詰まっている。

  1. リポジトリは shallow clone する。
  2. バイトコンパイルはしない。
  3. info も EmacsWiki レシピも、余計なものは要らない。

(2)について、私は Meadow 時代から Emacs を使っているが、今までバイトコンパイルしないと遅くて使えなかった Elisp は数個しか経験がない。なので基本、バイトコンパイルは不要だと思っている。

(3)は文字通りの意味の他に、MSYS2 に PATH が通った状態だと、MSYS2 の install-info が実行されてエラーになる、という理由もある。

install-info: No such file or directory for /home/user/.emacs.d/el-get/el-get/./el-get.info

リリース用タグが打たれているパッケージについては、以上の方法でとてもうまくいく。ただし、El-Get 自身のバージョンは管理できない(その時の master HEAD になる)。そこまでやろうとすると、El-Get を SCM に入れるしかない気がする。私はそこは妥協した。

後は、master ブランチしかない(リリース用タグがない)ようなパッケージの場合。

(el-get-bundle emacs-jp/japanese-holidays
  :branch "master"
  :checkout "324b6bf"
  ;; package configuration...
  )

この場合、shallow clone が使えない。といってもそれは Git の仕様(clone に commit ID を指定できない)によるもので、El-Get のせいではない。幸い、そのようなパッケージは小規模であることが殆どなので、そこも妥協した。嫌なら SCM に(略)。

以上は、各パッケージが Git リポジトリを持っていることが前提となる。しかし今はそれが問題になることはないだろう。良くも悪くも、Git (というか GitHub)でないプロジェクトは受け入れられない時代になってしまった。