Emacs Lisp 超初心者がコマンドを作ってみる 〜 別Ediffセッション実行中なら処理しない 〜

# はじめに
前回までで、 別フレームに表示できるようになっていました。


# Processing difference regions ... と警告が出て結果がおかしい

一度実行してから Ediff セッションを終了していない(q)とか、別で Ediff 実行して Ediff セッション終了してない場合に

Processing difference regions ... 

と警告が出て、 Ediff の表示もおかしくなります。

## AI さんに聞いてみる
Bing Microsoft Copilot (無料のやつ) に聞くと、何をどう聞いてもこの結果出てきます... 手元では使えませんでしたorz
課金するとマトモな結果が返ってくるんだろうか…


> ediff-regions-wordwise を実行中かどうかを判定する方法

> `ediff-regions-wordwise`は、Emacs Lispで異なるリージョンを単語単位で比較するための関数ですね。これを実行中かどうかを判定する方法については、以下のコードスニペットが役立つかもしれません。

````common_lisp:
(defun my-ediff-wordwise-active-p ()
  "Check if `ediff-regions-wordwise' is currently running."
  (and (boundp 'ediff-buffer-A) 
       (boundp 'ediff-buffer-B) 
       (not (null ediff-buffer-A)) 
       (not (null ediff-buffer-B))
       (eq major-mode 'ediff-mode)))
````
## 泣く泣く Ediff のソースを追う

Ediff の ドキュメント https://www.gnu.org/software/emacs/manual/html_mono/ediff.html

とか、 ソース(手元では 
 /usr/share/emacs/29.3/elisp/vc/ediff-*.el.gz )
 を追って調べた所、見つけました。 M-x eregistry の処理を行っている一部。

````common_lisp:vc/ediff-mult.el.gz(抜粋)
defun ediff-redraw-registry-buffer 内
(前略)
(if (null ediff-session-registry)
	  (insert "       ******* No active Ediff sessions *******\n"))
(後略)
````


たぶん ediff-session-registry というリストをチェックすればよいらしい。 非nil だと何かしら他で走ってる。

ということで追記箇所
````common_lisp
;; nothing previous msgid then exit
(if (not untranslated-regions)
(error "Nothing previous msgid"))
(if (not (null ediff-session-registry))    ; ←追記
; already exist ediff session              ; ←追記
(error "Please quit other Ediff session")) ; ←追記
;; source buffer for buffer-A
(save-current-buffer
    (set-buffer (get-buffer-create
````

今の所意図通り動いていはいます。既に処理中の Ediff セッションがあればエラーメッセージを出して処理せずに終了します。

# プログラム
````common_lisp:po-ediff-previous-msgid.el
;;; po-ediff-previous-msgid.el --- ediff previous-msgid & msgid.
;;; Author: kuma35
;;; Created: 2024/12/18
;;; Commentary:
;; In po-mode,
;; previous msgid is  '#|' marked in comment.
;; msgid is soruce sentence.
;; (msgstr is translated sentence.)
;; PEPM is my generate word.  PoEdiffPreviousMsgid.
;; Ediff-ing previous-msgid and msgid.
;;; 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-pepm-buf-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-pepm-buf-b-name "*pepm-now-msgid*"
  "BUFFER B name for `po-ediff-previous-msgid` .
PEPM is PoEdiffPreviousMsgid."
  :type 'string
  :require 'po-mode
  :group 'po)

(defcustom po-pepm-frame-name "*pepm-frame*"
  "Frame name for `po-ediff-previous-msgid` .
PEPM is PoEdiffPreviousMsgid."
  :type 'string
  :require 'po-mode
  :group 'po)


(defun po-popm-frame-named-list (name)
  "List if a frame with the given NAME exists."
  (let ((frames (frame-list))
        (result '())
	)
    (dolist (frame frames)
      (when (string= (frame-parameter frame 'name) name)
        (push frame result)
	)
      )
    result
    )
  )

(defun po-pepm-get-frame-create (name)
  "If NAME's frame is exist then return exists list.
Else is not exist then create frame by NAME."
  (let ((frames (po-popm-frame-named-list name))
	)
    (if frames
        frames
      (list (make-frame
	     `(
	       (name . ,name)
	       (fullscreen . maximized)
	       )
	     )
	    )
      )
    )
  )

(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)  ; BUF-A for ediff-regions-internal
	(beg-B) (end-B)  ; BUF-B for ediff-regions-internal
	(frames          ; ediff target frames
	 (po-pepm-get-frame-create po-pepm-frame-name))
	(frame)
	)
    ;; nothing previous msgid then exit
    (if (not untranslated-regions)
	(error "Nothing previous msgid"))
    (if (not (null ediff-session-registry))
	; already exist ediff session
	(error "Please quit other Ediff session"))
    ;; source buffer for buffer-A
    (save-current-buffer
      (set-buffer (get-buffer-create
		   po-pepm-buf-a-name))
      (setq buffer-read-only nil)
      (erase-buffer)
      (dolist (region untranslated-regions)
	(insert (po-extract-previous-msgid
		 oldbuf (car region) (cdr region)))
	)
      (goto-char (setq beg-A (point-min)))
      (push-mark (setq end-A (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-pepm-buf-b-name))
      (setq buffer-read-only nil)
      (erase-buffer)
      (insert msgid)
      (goto-char (setq beg-B (point-min)))
      (push-mark (setq end-B (point-max)) t t)
      (setq buffer-read-only t)
      (restore-buffer-modified-p nil))
    ;; chek frames and get a frame
    (if (> (length frame) 1)
      (progn
	(ding)
	(message "Multiple %s frames exist!"
		 po-pepm-frame-name)
	)
      )
    (with-selected-frame (car frames)
      ;; run ediff
      (ediff-regions-internal
       (get-buffer po-pepm-buf-a-name) beg-A end-A
       (get-buffer po-pepm-buf-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
````

今回はここまで。