Skip to content

Instantly share code, notes, and snippets.

@podhmo
Last active April 14, 2025 19:46
Show Gist options
  • Save podhmo/ff90c6735f979c0a1e27e0b7b76f89da to your computer and use it in GitHub Desktop.
Save podhmo/ff90c6735f979c0a1e27e0b7b76f89da to your computer and use it in GitHub Desktop.
widgetパッケージを使ってみたい
(require 'widget)
(eval-when-compile (require 'wid-edit))
(defvar-keymap my:widget-field-keymap
:parent widget-field-keymap
:doc "個人的な拡張をしたwidget-keymap"
"C-c C-n" #'widget-forward
"C-c C-p" #'widget-backward
;; "q" #'kill-buffer
"RET" #'newline
"C-c n" #'my:widget-add-node
"C-c d" #'my:widget-remove-node
)
(setq my:node-list
`(
((:tag . "memo\n") (:value . "ここに\nメモを入力"))
((:tag . "memo2\n") (:value . "ここにメモを入力"))
))
(defvar my:widget-example-buffer-name "*Widget Example*")
(defun my:widget-example (&optional node-list)
(interactive "P")
(setq node-list (or node-list my:node-list))
(let ((buf (get-buffer-create my:widget-example-buffer-name)))
(pop-to-buffer buf '(display-buffer-in-side-window (side . right) (window-width . 60)))
(with-current-buffer buf
(kill-all-local-variables)
(let ((inhibit-read-only t))
(delete-all-overlays buf)
(erase-buffer))
(widget-insert "* example *\n\tTabとS-Tabで移動\n\n")
(dolist (node node-list)
(widget-create 'group
:indent 2
`(text
:tag ,(assoc-default :tag node)
:value ,(assoc-default :value node)
:keymap my:widget-field-keymap)
))
(use-local-map my:widget-field-keymap)
(widget-setup)
(widget-move 1))))
(defun my:widget-add-node ()
(interactive)
(save-excursion
;; widgetの範囲外に行く
(goto-char (+ 1 (next-overlay-change (point))))
(let ((inhibit-read-only t))
(widget-create 'group
:indent 2
`(text
:tag "new*\n"
:value "<new value>"
:keymap my:widget-field-keymap)
)
(widget-setup)))
(widget-move 1))
(defun my:widget-remove-node ()
(interactive)
(let* ((w (widget-at (point)))
(p (widget-get w :parent))) ; group
(widget-delete (and p w))
(widget-setup)
(widget-move 1)))
;; serialize/deseriaize
(defun my:widget-example-to-string ()
(with-current-buffer (get-buffer-create my:widget-example-buffer-name)
(save-excursion
(let ((prev (point-min))
(buf nil))
(goto-char (point-min))
(while (<= prev (progn (widget-move 1 t) (point))) ; widget-moveは終端に達したら開始地点に戻るので無限ループはしない
(push (widget-value (widget-at (point))) buf)
(setq prev (point)))
(mapconcat #'identity (nreverse buf) "\n\n---\n\n")))))
(defun my:widget-example-to-clipboard ()
(interactive)
(kill-new (my:widget-example-to-string)))
(defun my:widget-example-from-string (text)
(let ((node-list
(mapcar (lambda (section) `((:tag . "memo\n") (:value . ,section)))
(split-string text "\n\n---\n\n" t))))
(my:widget-example node-list)))
(defun my:widget-example-from-clipboard ()
(interactive)
(my:widget-example-from-string
(with-temp-buffer
(yank)
(buffer-substring-no-properties (point-min) (point-max)))))
@podhmo
Copy link
Author

podhmo commented Mar 28, 2025

Tab, S-Tabなどで上下に行ったり来たりできる。
x/twitterのthreadみたいな感じでtext widgetを繋げて出来るelispのメモ

@podhmo
Copy link
Author

podhmo commented Mar 28, 2025

なぜか自分の環境ではまっさらな環境とは異なり widget-field の が目立たなくなっていた。 M-x customize-face とかで雑に変えた。

(custom-set-faces
 ;; custom-set-faces was added by Custom.
 ;; If you edit it by hand, you could mess it up, so be careful.
 ;; Your init file should contain only one such instance.
 ;; If there is more than one, they won't work right.
 '(tab-bar-tab-inactive ((t (:strike-through t :inherit modus-themes-tab-inactive))))
 '(widget-field ((t (:extend nil :background "dim gray" :foreground "#ffffff")))))

@podhmo
Copy link
Author

podhmo commented Mar 28, 2025

image

@podhmo
Copy link
Author

podhmo commented Mar 28, 2025

https://www.gnu.org/software/emacs/manual/html_mono/widget.html#Programming-Example
このページのコードから始めたせいで定義した関数の名前が全部my:widgetでまるし、my:widget-exampleという名前のまま進めてしまった。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment