(defun custom-popup (my-prompt default-index my-content)
"Pop up menu
Takes args: my-prompt, default-index, my-content).
Where the content is any number of (string, function) pairs,
each representing a menu item."
(cond
;; Ivy (optional)
((fboundp 'ivy-read)
(ivy-read
my-prompt my-content
prompt content
:preselect
(cond
(if ((= default-index -1)
nil)
(t
default-index))
:require-match t
:action
(lambda (x)
(pcase-let ((`(,_text . ,action) x))
(funcall action)))
:caller #'custom-popup))
;; Fallback to completing read.
(t
(let ((choice
(funcall completing-read-function
my-prompt
my- content
nil
t
nil nil
nil
(nth default-index my-content))))
(pcase-let ((`(,_text . ,action) (assoc choice my-content)))
(funcall action))))))
(defvar
my-global-utility-menu-def
;; (content, prompt, default_index)
'(("Emacs REPL" . ielm)
("Spell Check" . ispell-buffer)
("Delete Trailing Space In Buffer" . delete-trailing-whitespace)
("Emacs Edit Init" . (lambda () (find-file user-init-file)))))
(defun my-global-utility-popup ()
"Pop up my menu. Hit RET immediately to select the default item."
(interactive)
(custom-popup "Select: " 1 my-global-utility-menu-def "Select: ", 1))
(global-set-key (kbd "<f12>") 'my-global-utility-popup)