こちらの記事より新しい記事があります:
最新版の xprint.el は以下のGitHubリポジトリからダウンロードできます。
インストール方法 (xprint.el)
とりあえず使ってみたい(または最新の変更に追随したい)方は、.emacs または init.el に以下を追加しておくと自動的にロードされます。.emacs 内で xprint 等を呼びたい場合は、呼び出す前の時点で以下のコードを記述しておいてください。
(unless (featurep 'get-feature)
(defun get-feature (feature-name &optional url file-name)
(if (featurep feature-name) t
(unless url (setq url (format "https://github.com/emacs-pkg/%s/raw/main/%s.el"
feature-name feature-name)))
(unless file-name (setq file-name (format "%s.el" feature-name)))
(let ((make-backup-files nil)
(file-path (expand-file-name file-name user-emacs-directory)))
(ignore-errors
(url-copy-file url file-path 'ok-if-already-exists))
(ignore-errors
(load file-path nil 'nomessage))
(featurep feature-name))))
(get-feature 'get-feature))
(get-feature 'xprint)
straight.el でロードしたい場合は以下を .emacs または init.el に入れてください(但し git のインストールが必要です):
(defvar bootstrap-version)
(let ((bootstrap-file
(expand-file-name "straight/repos/straight.el/bootstrap.el" user-emacs-directory))
(bootstrap-version 6))
(unless (file-exists-p bootstrap-file)
(with-current-buffer
(url-retrieve-synchronously
"https://raw.githubusercontent.com/radian-software/straight.el/develop/install.el"
'silent 'inhibit-cookies)
(goto-char (point-max))
(eval-print-last-sexp)))
(load bootstrap-file nil 'nomessage))
(straight-use-package '(xprint :type git :host github :repo "emacs-pkg/xprint"))
(require 'xprint)
Emacs Lisp のコード(マクロ)を開発する際に、プリント文を使ってデバッグしたい時があると思います。
(message "文字列")
でミニバッファに文字列を表示させることができますが。リアルタイムで印字履歴をモニターできると便利そうなので xprint という関数を作ってみました。
(global-set-key (kbd "C-n")
(lambda ()
(interactive)
(next-line)
(xprint (point))
))
*scratch*
バッファで上記のようなマクロを評価し、Ctrl-n を入力し続けると、自動的に *xprint*
というバッファが表れて印字履歴を表示してくれます。(xprint (point))
という行から表示されています。
- また、xprint 関数には複数の引数を指定できます。それぞれの値が空白で区切られて
*xprint*
バッファに出力されます。 - xprint を使うと、まるでコンソールプログラムを作っているかのように動作を確認できます。
ソース添付
;;;; xprint.el v1.2.1 ;;;;
;;;; Last Modified: 2023/01/02 00:00 ;;;;
(require 'cl-lib)
(require 'cl-extra)
(defun xprint (&rest args)
(let ((raw nil))
(when (eq (car args) :raw)
(setq raw t)
(setq args (cdr args))
)
(prog1 args
(let ((msg ""))
(dotimes (i (length args))
(if (zerop i) nil
(setq msg (concat msg " "))
)
(setq msg (concat msg (format (if raw "%s" "%S") (nth i args))))
)
(if noninteractive (message "%s" msg)
(let ((cb (current-buffer))
(cw (selected-window)))
(if (equal (buffer-name) "*xprint*") nil
(switch-to-buffer-other-window "*xprint*")
)
;;(emacs-lisp-mode)
(lisp-interaction-mode)
(goto-char (point-max))
(insert msg)
(insert "\n")
(let ((wins (window-list)))
(dolist (win wins)
(select-window win)
(when (equal (buffer-name) "*xprint*")
(goto-char (point-max))
(cond
((pos-visible-in-window-p (point)) nil)
((< (point) (window-start)) (recenter 0))
(t (recenter -1)))
)
)
)
(select-window cw)
(switch-to-buffer cb)
)
)
)
)
)
)
(defmacro xdump (&rest list)
(let ((exp '(xprint)))
(dolist (x list)
(if (and (not (consp x)) (not (and (symbolp x) (not (keywordp x))))) (push x exp)
(push (list 'quote x) exp)
(push := exp)
(push x exp)
)
)
(reverse exp)
)
)
(defun xclear ()
(interactive)
(let ((cb (current-buffer))
(cw (selected-window)))
(let ((wins (window-list)))
(dolist (win wins)
(select-window win)
(when (equal (buffer-name) "*xprint*")
(ignore-errors (delete-window win))
)
)
)
(ignore-errors (kill-buffer "*xprint*"))
(ignore-errors (select-window cw))
nil)
)
(defun xsleep (millisec)
(when millisec
(sit-for 0)
(sleep-for 0 millisec)
)
)
(defmacro xmessage (&rest list)
(let ((sleep nil))
(if (and (not (integerp (nth 0 list))) (not (symbolp (nth 0 list)))) nil
(setq sleep (pop list))
)
(if (not sleep)
`(message ,@list)
`(progn (message ,@list) (xsleep ,sleep))
)
)
)
(defmacro xformat (&rest list)
`(xprint :raw (format ,@list))
)
(defun xpp (x)
(xprint :raw (xpp-to-string x))
)
(defun xpp-to-string (form)
(with-temp-buffer
(cl-prettyprint form)
(let ((str (buffer-string)))
(replace-regexp-in-string "\\`[ \t\n\r]*\\|[ \t\n\r]*\\'" "" str)
)
)
)
(defun xpand-macro-scan (form callback data)
(cond
((symbolp form) (funcall callback form data))
((consp form)
(cons
(xpand-macro-scan (car form) callback data)
(xpand-macro-scan (cdr form) callback data)))
(t form)
)
)
(defun xpand-macro (form)
(let ((result (macroexpand-all form))
(hash (make-hash-table :test #'equal)))
(xprint :raw "")
(xprint :raw ";;; Expanding Macro:")
(xprint
:raw
(xpp-to-string form)
)
(xprint :raw " |")
(xprint :raw " |")
(xprint :raw " v")
(xpand-macro-scan
result
#'(lambda (sym data)
(let ((lst (gethash (symbol-name sym) data)))
(when (not (member sym lst))
(push sym lst)
(puthash (symbol-name sym) lst data)
)
)
)
hash
)
(setq result
(xpand-macro-scan
result
#'(lambda (sym data)
(let ((lst (gethash (symbol-name sym) data)))
(if (= 1 (length lst)) sym
(intern (format "%s_%d" sym (length (member sym lst))))
)
)
)
hash
)
)
(xprint
:raw
(xpp-to-string result)
)
result
)
)
(defmacro xpand (form)
`(xpand-macro (quote ,form))
)
(provide 'xprint)
問題などにお気づきの場合は、コメントでお知らせください。
以上です。