1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Emacs LispAdvent Calendar 2024

Day 12

Emacs Lisp 超初心者がコマンドを作ってみる 〜バイトコンパイル〜

Last updated at Posted at 2024-12-20

ちゃんと動くようになった Emacs Lisp コマンド(のファイル)はバイトコンパイルすると実行速度の向上が期待できます。

python でいうと .pyc みたいなものでしょうか。ただし、 python とは違って自動で作成・更新してくれる訳ではなくて、手動で byte-compile-file 等実行する必要があります。 更新も自動で行われる訳ではないので、 .el を変更したら都度バイトコンパイルするようにしてください。

バイトコンパイルすると拡張子 .elc のファイルができます。

バイトコンパイルするとワーニングが出る

po-ediff-previous-msgid.el:79:6: Warning: the function
    ‘ediff-regions-internal’ is not known to be defined.

無視してEmacsを起動すると

⛔ Warning (comp): po-ediff-previous-msgid.el:79:6: Warning: the function ‘ediff-regions-internal’ is not known to be defined.
⛔ Warning (comp): po-ediff-previous-msgid.el:44:32: Warning: the function ‘po-previous-untranslated-regions’ is not known to be defined.
⛔ Warning (comp): po-ediff-previous-msgid.el:43:17: Warning: the function ‘po-get-msgid’ is not known to be defined.
⛔ Warning (comp): po-ediff-previous-msgid.el:40:4: Warning: the function ‘po-find-span-of-entry’ is not known to be defined.
⛔ Warning (comp): po-ediff-previous-msgid.el:31:6: Warning: the function ‘po-extract-unquoted’ is not known to be defined.

バイトコンパイルした .elc のロード時に
po-mode や ediff の関数を呼び出している部分でワーニングが発生します。

バイトコンパイルしていない .el のロードの場合は発生しません。

調べましたら、 declare-function すると良いようです。 C言語でいう extern 宣言みたいな感じでしょうか。

C言語の extern 宣言と違うのはどこのファイルにあるかも記述することです(下記 declare-function の "po-mode" とか "ediff" の部分)。

また、引数を、関数を定義しているところからコピって持ってきます。 これまた C言語のプロトタイプ宣言のようなものです。この引数宣言を見て当該関数を使っているシーンで引数の数が合っているかどうかチェックします。

手元では引数の数合ってない、 と警告が出ました。 原因は decleare-function に記述した引数の数の方が誤っていた訳ですけども、 ともかくも、 ちゃんとチェックしてくれているようです。

declare-function を追加したら、再度バイトコンパイルしましょう。今度はバイトコンパイル時にも、Emacs起動時にもワーニング無しで起動します。

プログラム

declare-function を追記したもの。 .el ファイルの先頭にまとめて書いてしまえばいいようです。

po-ediff-previous-msgid.el
;;; po-ediff-previous-msgid.el --- ediff previous-msgid and msgid.
;;; Author: kuma35
;;; Created: 2024/12/18
;;; Commentary:
;; previous msgid is  '#|' marked in comment.
;;; Code:

(declare-function po-extract-unquoted "po-mode" (buffer start end))
(declare-function po-find-span-of-entry "po-mode" ())
(declare-function po-get-msgid "po-mode" ())
(declare-function po-previous-untranslated-regions "po-mode" ())
(declare-function ediff-regions-internal "ediff"
		  (buffer-A beg-A end-A buffer-B beg-B end-B
			    startup-hooks job-name word-mode setup-parameters))

(defcustom po-ediff-previous-msgid-buffer-a-name "*pepm-previous-msgid*"
  "BUFFER A name for `po-ediff-previous-msgid`.  pepm is PoEdiffPreviousMsgid."
  :type 'string
  :require 'po-mode
  :group 'po)

(defcustom po-ediff-previous-msgid-buffer-b-name "*pepm-now-msgid*"
  "BUFFER B name for `po-ediff-previous-msgid` .  pepm is PoEdiffPreviousMsgid."
  :type 'string
  :require 'po-mode
  :group 'po)


(defun po-extract-previous-msgid (buffer start end)
  "Delete '#|' marker and unquote text from BUFFER START END.
delete '^#| ' each line.  then unquote.
return is String with property."
  (require 'po-mode)
  (with-temp-buffer
    (insert-buffer-substring buffer start end)
    (goto-char (point-min))
    (while (re-search-forward "^#\\(~\\)?|[ \t]*" nil t)
      (replace-match "" t t))
    (po-extract-unquoted (current-buffer) (point-min) (point-max))
    )
  )

(defun po-ediff-previous-msgid ()
  "Ediff previous msgid (marked #| ) and msgid."
  (interactive)
  (require 'po-mode)
  (require 'ediff)
  (po-find-span-of-entry)
  (let (
	(oldbuf (current-buffer))
	(msgid (po-get-msgid))
	(untranslated-regions (po-previous-untranslated-regions))
        (beg-A)
	(end-A)
	(beg-B)
	(end-B)
	)
    ;; source buffer for buffer-A
    (save-current-buffer
      (set-buffer (get-buffer-create
		   po-ediff-previous-msgid-buffer-a-name))
      (setq buffer-read-only nil)
      (erase-buffer)
      (dolist (region untranslated-regions)
	(insert (po-extract-previous-msgid oldbuf (car region) (cdr region)))
	)
      (setq beg-A (point-min))
      (setq end-A (point-max))
      (goto-char (point-min))
      (push-mark (point-max) t t)
      (setq buffer-read-only t)
      (restore-buffer-modified-p nil))
    ;; source buffer for buffer-B
    (save-current-buffer
      (set-buffer (get-buffer-create
		   po-ediff-previous-msgid-buffer-b-name))
      (setq buffer-read-only nil)
      (erase-buffer)
      (insert msgid)
      (setq beg-B (point-min))
      (setq end-B (point-max))
      (goto-char (point-min))
      (push-mark (point-max) t t)
      (setq buffer-read-only t)
      (restore-buffer-modified-p nil))
    ;; run ediff
    (ediff-regions-internal
     (get-buffer po-ediff-previous-msgid-buffer-a-name)
     beg-A end-A
     (get-buffer po-ediff-previous-msgid-buffer-b-name)
     beg-B end-B
     nil 'ediff-regions-wordwise 'word-mode nil)
    )  ; end of let
  )

(provide 'po-ediff-previous-msgid)
;;; po-ediff-previous-msgid.el ends here

注意点

(古い) .elc に注意

ロード時は .el よりも .elc の方が優先されます。

バイトコンパイルあるあるですけども、 .el を更新したら必ずバイトコンパイルも行うか、一旦 .elc を削除してください。そうしないといつまでも(古い) .elc をロードしてきて「修正したハズなのに反映されない。なんでだろ?」と悩む事になります…

詳しくは

Emacs Lisp マニュアルの

16 ロード

こちらさんを参考にさせてもらってます

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?