If I type
M-x customize in Emacs I am taken to customize-group for the
Emacs group. At the top of the screen is a search entry dialogue box where I would normally search for a given string. Is there a way of saving searches typed in this dialogue box?
If I type
The following Elisp code adapts the history mechanism for text fields of
elgrep-menu to Custom-menu.
The code is self-contained. You can copy-paste it into your init file.
After installing and running the code the search field of customization buffers has a history.
If you are in the text field for the search you can move backwards in history with M-up and forwards in history with M-down.
(require 'subr-x) ;; for `when-let' (defun my-Custom-widget-update-hist (widget) "Update the :prompt-history variable of WIDGET. Return the value of WIDGET." (when-let ((ret (widget-value widget)) (hist-var (widget-get widget :prompt-history)) (hist-length (or (get hist-var 'history-length) history-length))) (unless (string-equal ret (car-safe (symbol-value hist-var))) (set hist-var (cons ret (symbol-value hist-var))) (when (> (length (symbol-value hist-var)) hist-length) (setf (nthcdr hist-length (symbol-value hist-var)) nil))) ret)) (defun my-Custom-widget-hist-action (widget) "Add `my-Custom-widget-update-hist' to the :action of WIDGET." (let ((action (widget-get widget :action))) (widget-put widget :action `(lambda (wid &optional event) (my-Custom-widget-update-hist wid) (funcall ,action wid event))))) (defvar my-Custom-menu-search-history nil) (require 'wid-edit) ;; for `widget-field-keymap' (defvar my-Custom-menu-hist-map (let ((map (copy-keymap widget-field-keymap))) (define-key map (kbd "<M-up>") #'my-Custom-menu-hist-up) (define-key map (kbd "ESC <up>") #'my-Custom-menu-hist-up) (define-key map (kbd "<M-down>") #'my-Custom-menu-hist-down) (define-key map (kbd "ESC <down>") #'my-Custom-menu-hist-down) map) "Widget menu used for text widgets with history. Binds M-up and M-down to one step in history up and down, respectively.") (defvar my-Custom-menu-hist-pos nil "Current position in text widget history. Used in `my-Custom-menu-hist-up' and `my-Custom-menu-hist-down'.") (defvar my-Custom-menu-hist-list nil) (defun my-Custom-menu-hist-move (dir) "Move in :prompt-history of widget at point in direction DIR which can be -1 or +1." (when-let ((wid (widget-at)) (histvar (widget-get wid :prompt-history))) (unless my-Custom-menu-hist-list (setq my-Custom-menu-hist-list (cons (widget-value wid) (symbol-value histvar)))) (unless (memq last-command '(my-Custom-menu-hist-up my-Custom-menu-hist-down)) (setq my-Custom-menu-hist-list (cons (widget-value wid) (symbol-value histvar))) (setq my-Custom-menu-hist-pos 0)) (let ((start my-Custom-menu-hist-pos)) (while (progn (setq my-Custom-menu-hist-pos (mod (+ my-Custom-menu-hist-pos dir) (length my-Custom-menu-hist-list))) (condition-case nil (progn (widget-value-set wid (nth my-Custom-menu-hist-pos my-Custom-menu-hist-list)) nil) (error (/= my-Custom-menu-hist-pos start)))))))) (defun my-Custom-menu-hist-up () "Choose next item in :prompt-history of widget at point." (interactive) (my-Custom-menu-hist-move 1)) (defun my-Custom-menu-hist-down () "Choose next item in :prompt-history of widget at point." (interactive) (my-Custom-menu-hist-move -1)) (defmacro my-Custom-find-widget (widget type &rest conditions) "Find widget of type TYPE, assign it to WIDGET and test CONDITIONS. WIDGET and TYPE are unquoted symbols and CONDITIONS is a list of conditions. The WIDGET symbol can be used in the CONDITIONS. TYPE identifies the widget type." (declare (debug (symbolp symbolp body)) (indent 2)) (let ((pos (make-symbol "pos")) (found (make-symbol "found"))) `(let ((,pos (goto-char (point-min))) ,found ,widget) (while (and (progn (widget-forward 1) (<= ,pos (point))) (setq ,pos (point) ,widget (widget-at)) (null (and (eq (widget-type ,widget) (quote ,type)) ,@conditions (setq ,found ,widget))))) ,found))) (defun my-Custom-menu-search-history-ad (&rest _) "Install search history for cus-edit. Put this function into `Custom-mode-hook'." (let ((search-field-widget (my-Custom-find-widget widget editable-field (when-let (help-echo (widget-get widget :help-echo)) (string-match "\\`Search for custom items\\.$" help-echo))))) (when search-field-widget (my-Custom-widget-hist-action search-field-widget) (let* ((search-button-widget (my-Custom-find-widget widget push-button (when-let (tag (widget-get widget :tag)) (string-match "\\` Search \\'" tag)))) (b (widget-field-start search-field-widget)) (search-field-widget (prog1 (widget-copy search-field-widget) (widget-delete search-field-widget)))) (when search-button-widget (widget-put search-button-widget :parent search-field-widget) (widget-put search-button-widget :action #'widget-parent-action)) (widget-put search-field-widget :prompt-history 'my-Custom-menu-search-history) (widget-put search-field-widget :keymap my-Custom-menu-hist-map) (goto-char b) (widget-apply search-field-widget :create) ;; delegating the propertizing of the input field to the widget (widget-setup) (goto-char (point-min)))))) (advice-add 'custom-buffer-create-internal :after #'my-Custom-menu-search-history-ad)
The code is tested with:
GNU Emacs 26.1 (build 2, i686-pc-linux-gnu, GTK+ Version 3.22.30) of 2018-05-29