+ The universal argument tells a menu to use the last run command, if available. + If a last run command exists, preselect it in the menu.
122 lines
5.1 KiB
EmacsLisp
122 lines
5.1 KiB
EmacsLisp
;;; ../core/autoload/menu.el -*- lexical-binding: t; -*-
|
|
|
|
;; Command dispatchers: basically M-x, but context sensitive, customizable and
|
|
;; persistent across Emacs sessions.
|
|
|
|
(defvar doom-menu-display-fn #'doom-menu-read-default
|
|
"The method to use to prompt the user with the menu. This takes two arguments:
|
|
PROMPT (a string) and COMMAND (a list of command plists; see `def-menu!').")
|
|
|
|
(defvar-local doom-menu-last-command nil
|
|
"TODO")
|
|
|
|
(defun doom-menu-read-default (prompt commands)
|
|
"Default method for displaying a completion-select prompt."
|
|
(completing-read prompt (mapcar #'car commands) nil nil nil nil (car doom-menu-last-command)))
|
|
|
|
;;;###autoload
|
|
(defun doom--menu-read (prompt commands)
|
|
(if-let* ((choice (funcall doom-menu-display-fn prompt commands)))
|
|
(assoc choice commands)
|
|
(user-error "Aborted")))
|
|
|
|
;;;###autoload
|
|
(defun doom--menu-exec (plist)
|
|
(save-selected-window
|
|
(let ((command (plist-get plist :exec))
|
|
(cwd (plist-get plist :cwd)))
|
|
(let ((default-directory
|
|
(cond ((eq cwd t) (doom-project-root))
|
|
((stringp cwd) cwd)
|
|
((functionp cwd) (funcall cwd))
|
|
(t default-directory))))
|
|
(cond ((stringp command)
|
|
(let (buf)
|
|
(compile command)
|
|
(setq buf next-error-last-buffer)
|
|
(unless buf
|
|
(error "Couldn't create compilation buffer"))
|
|
(with-current-buffer buf
|
|
(setq header-line-format
|
|
(concat (propertize "$ " 'face 'font-lock-doc-face)
|
|
(propertize command 'face 'font-lock-preprocessor-face))))))
|
|
((or (symbolp command)
|
|
(functionp command))
|
|
(call-interactively command))
|
|
((and command (listp command))
|
|
(eval command t))
|
|
(t
|
|
(error "Not a valid command: %s" command)))))))
|
|
|
|
;;;###autoload
|
|
(defmacro def-menu! (name desc commands &rest plist)
|
|
"Defines a menu and returns a function symbol for invoking it.
|
|
|
|
A dispatcher is an interactive command named NAME (a symbol). When called, this
|
|
dispatcher prompts you to select a command to run. This list is filtered
|
|
depending on its properties. Each command is takes the form of:
|
|
|
|
(DESCRIPTION :exec COMMAND &rest PROPERTIES)
|
|
|
|
PROPERTIES accepts the following properties:
|
|
|
|
:when FORM
|
|
:unless FORM
|
|
:region BOOL
|
|
:cwd BOOL|PATH|FUNCTION
|
|
:project BOOL|PATH|FUNCTION
|
|
|
|
COMMAND can be a string (a shell command), a symbol (an elisp function) or a
|
|
lisp form.
|
|
|
|
`def-menu!'s PLIST supports the following properties:
|
|
|
|
:prompt STRING"
|
|
(declare (indent defun) (doc-string 2))
|
|
(let ((commands-var (intern (format "%s-commands" name)))
|
|
(prop-prompt (or (plist-get plist :prompt) "> "))
|
|
(prop-sort (plist-get plist :sort)))
|
|
`(progn
|
|
(defconst ,commands-var
|
|
,(if prop-sort
|
|
`(cl-sort ,commands #'string-lessp :key #'car)
|
|
commands)
|
|
,(format "Menu for %s" name))
|
|
(defun ,name (arg command)
|
|
,(concat
|
|
(if (stringp desc) (concat desc "\n\n"))
|
|
"This is a command dispatcher. It will rerun the last command on\n"
|
|
"consecutive executions. If ARG (universal argument) is non-nil\n"
|
|
"then it always prompt you.")
|
|
(declare (interactive-only t))
|
|
(interactive
|
|
(list current-prefix-arg
|
|
(progn
|
|
(unless ,commands-var
|
|
(user-error "The '%s' menu is empty" ',name))
|
|
(doom--menu-read
|
|
,prop-prompt
|
|
(or (cl-remove-if-not
|
|
(let ((project-root (doom-project-root)))
|
|
(lambda (cmd)
|
|
(let ((plist (cdr cmd)))
|
|
(and (cond ((not (plist-member plist :region)) t)
|
|
((plist-get plist :region) (use-region-p))
|
|
(t (not (use-region-p))))
|
|
(let ((when (plist-get plist :when))
|
|
(unless (plist-get plist :unless))
|
|
(project (plist-get plist :project)))
|
|
(when (functionp project)
|
|
(setq project (funcall project)))
|
|
(or (or (not when) (eval when))
|
|
(or (not unless) (not (eval unless)))
|
|
(and (stringp project)
|
|
(file-in-directory-p (or buffer-file-name default-directory)
|
|
project-root))))))))
|
|
,commands-var)
|
|
(user-error "No commands available here"))))))
|
|
(doom--menu-exec
|
|
(cdr (or (when arg doom-menu-last-command)
|
|
(setq doom-menu-last-command command)
|
|
(user-error "No command selected"))))))))
|
|
|