Add cmd!, cmd!!, cmds! convenience macros

It's kind of silly that our command lambda macros (λ! and λ!!) need a
snippet, special key sequence or copy-paste to insert, so in the spirit
of fn! -- and to make sure they take up less space than `lambda!` --
I've added `cmd!` and `cmd!!` aliases. `lambda!` and `lambda!!` are now
deprecated. λ! and λ!! will remain.

I've also added `cmds!` as a convenience wrapper around
general-predicate-dispatch.
This commit is contained in:
Henrik Lissner 2020-05-27 16:12:45 -04:00
parent d4d8c48265
commit a9bf0b8985
No known key found for this signature in database
GPG key ID: 5F6C0EA160557395
5 changed files with 68 additions and 62 deletions

View file

@ -341,10 +341,10 @@ Some items are not supported by the `nsm.el' module."
(delete-file file) (delete-file file)
(signal (car e) (cdr e))))))) (signal (car e) (cdr e)))))))
(fset 'doom--run-vanilla-emacs (lambda! (doom--run-sandbox 'vanilla))) (fset 'doom--run-vanilla-emacs (cmd! (doom--run-sandbox 'vanilla)))
(fset 'doom--run-vanilla-doom (lambda! (doom--run-sandbox 'vanilla-doom))) (fset 'doom--run-vanilla-doom (cmd! (doom--run-sandbox 'vanilla-doom)))
(fset 'doom--run-vanilla-doom+ (lambda! (doom--run-sandbox 'vanilla-doom+))) (fset 'doom--run-vanilla-doom+ (cmd! (doom--run-sandbox 'vanilla-doom+)))
(fset 'doom--run-full-doom (lambda! (doom--run-sandbox 'doom))) (fset 'doom--run-full-doom (cmd! (doom--run-sandbox 'doom)))
(defvar doom-sandbox-emacs-lisp-mode-map (defvar doom-sandbox-emacs-lisp-mode-map
(let ((map (make-sparse-keymap))) (let ((map (make-sparse-keymap)))

View file

@ -139,24 +139,6 @@ at the values with which this function was called."
;; ;;
;;; Sugars ;;; Sugars
(defmacro λ! (&rest body)
"Expands to (lambda () (interactive) ,@body).
A factory for quickly producing interaction commands, particularly for keybinds
or aliases."
(declare (doc-string 1) (pure t) (side-effect-free t))
`(lambda (&rest _) (interactive) ,@body))
(defalias 'lambda! 'λ!)
(defun λ!! (command &optional arg)
"Expands to a command that interactively calls COMMAND with prefix ARG.
A factory for quickly producing interactive, prefixed commands for keybinds or
aliases."
(declare (doc-string 1) (pure t) (side-effect-free t))
(lambda (&rest _) (interactive)
(let ((current-prefix-arg arg))
(call-interactively command))))
(defalias 'lambda!! 'λ!!)
(defun dir! () (defun dir! ()
"Returns the directory of the emacs lisp file this macro is called from." "Returns the directory of the emacs lisp file this macro is called from."
(when-let (path (file!)) (when-let (path (file!))
@ -256,6 +238,40 @@ See `if!' for details on this macro's purpose."
(declare (indent defun) (doc-string 1) (pure t) (side-effect-free t)) (declare (indent defun) (doc-string 1) (pure t) (side-effect-free t))
`(cl-function (lambda ,arglist ,@body))) `(cl-function (lambda ,arglist ,@body)))
(defmacro cmd! (&rest body)
"Expands to (lambda () (interactive) ,@body).
A factory for quickly producing interaction commands, particularly for keybinds
or aliases."
(declare (doc-string 1) (pure t) (side-effect-free t))
`(lambda (&rest _) (interactive) ,@body))
(defmacro cmd!! (command &rest args)
"Expands to a closure that interactively calls COMMAND with ARGS.
A factory for quickly producing interactive, prefixed commands for keybinds or
aliases."
(declare (doc-string 1) (pure t) (side-effect-free t))
`(lambda (&rest _) (interactive)
(funcall-interactively ,command ,@args)))
(defmacro cmds! (&rest branches)
"Expands to a `menu-item' dispatcher for keybinds."
(declare (doc-string 1))
(let ((docstring (if (stringp (car branches)) (pop branches) ""))
fallback)
(when (cl-oddp (length branches))
(setq fallback (car (last branches))
branches (butlast branches)))
`(general-predicate-dispatch ,fallback
:docstring ,docstring
,@branches)))
;; For backwards compatibility
(defalias 'λ! 'cmd!)
(defalias 'λ!! 'cmd!!)
;; DEPRECATED These have been superseded by `cmd!' and `cmd!!'
(define-obsolete-function-alias 'lambda! 'cmd! "3.0.0")
(define-obsolete-function-alias 'lambda!! 'cmd!! "3.0.0")
;;; Mutation ;;; Mutation
(defmacro appendq! (sym &rest lists) (defmacro appendq! (sym &rest lists)

View file

@ -18,8 +18,8 @@ It is integrated into Helpful, in Doom.
- [[#disable-packages][disable-packages!]] - [[#disable-packages][disable-packages!]]
- [[#doom][doom!]] - [[#doom][doom!]]
- [[#file-exists-p][file-exists-p!]] - [[#file-exists-p][file-exists-p!]]
- [[#lambda][lambda!]] - [[#cmd][cmd!]]
- [[#lambda-1][lambda!!]] - [[#cmd-1][cmd!!]]
- [[#letenv][letenv!]] - [[#letenv][letenv!]]
- [[#load][load!]] - [[#load][load!]]
- [[#map][map!]] - [[#map][map!]]
@ -238,38 +238,30 @@ It is integrated into Helpful, in Doom.
#+RESULTS: #+RESULTS:
: /home/hlissner/.emacs.d/LICENSE : /home/hlissner/.emacs.d/LICENSE
*** lambda! *** cmd!
#+BEGIN_SRC elisp :eval no #+BEGIN_SRC elisp :eval no
(map! "C-j" (lambda! (newline) (indent-according-to-mode))) (map! "C-j" (cmd! (newline) (indent-according-to-mode)))
;; The `λ!' short-form alias exists. If you have the snippets module enabled and
;; Doom's default snippets, the 'lam' snippet will expand into 'λ!'. Otherwise,
;; you can use `lambda!'.
(map! "C-j" (λ! (newline) (indent-according-to-mode)))
#+END_SRC #+END_SRC
*** lambda!!
*** cmd!!
When ~newline~ is passed a numerical prefix argument (=C-u 5 M-x newline=), it When ~newline~ is passed a numerical prefix argument (=C-u 5 M-x newline=), it
inserts N newlines. We can use ~lambda!!~ to easily create a keybinds that bakes inserts N newlines. We can use ~cmd!!~ to easily create a keybinds that bakes in
in the prefix arg into the command call: the prefix arg into the command call:
#+BEGIN_SRC elisp :eval no #+BEGIN_SRC elisp :eval no
(map! "C-j" (lambda!! #'newline 5)) (map! "C-j" (cmd!! #'newline 5))
;; The `λ!!' short-form alias exists. If you have the snippets module enabled
;; and Doom's default snippets, a 'lam' snippet is available to expand into
;; 'λ!'. Otherwise, you can use `lambda!!'.
(map! "C-j" (λ!! #'newline 5))
#+END_SRC #+END_SRC
Or to create aliases for functions that behave differently: Or to create aliases for functions that behave differently:
#+BEGIN_SRC elisp :eval no #+BEGIN_SRC elisp :eval no
(fset 'insert-5-newlines (lambda!! #'newline 5)) (fset 'insert-5-newlines (cmd!! #'newline 5))
;; The equivalent of C-u M-x org-global-cycle, which resets the org document to ;; The equivalent of C-u M-x org-global-cycle, which resets the org document to
;; its startup visibility settings. ;; its startup visibility settings.
(fset 'org-reset-global-visibility (lambda!! #'org-global-cycle '(4)) (fset 'org-reset-global-visibility (cmd!! #'org-global-cycle '(4))
#+END_SRC #+END_SRC
*** letenv! *** letenv!
#+BEGIN_SRC elisp #+BEGIN_SRC elisp
(letenv! (("SHELL" "/bin/sh")) (letenv! (("SHELL" "/bin/sh"))

View file

@ -120,7 +120,7 @@
;;; <leader> i --- insert ;;; <leader> i --- insert
(:prefix-map ("i" . "insert") (:prefix-map ("i" . "insert")
:desc "Current file name" "f" #'+default/insert-file-path :desc "Current file name" "f" #'+default/insert-file-path
:desc "Current file path" "F" (λ!! #'+default/insert-file-path t) :desc "Current file path" "F" (cmd!! #'+default/insert-file-path t)
:desc "Snippet" "s" #'yas-insert-snippet :desc "Snippet" "s" #'yas-insert-snippet
:desc "Unicode" "u" #'unicode-chars-list-chars :desc "Unicode" "u" #'unicode-chars-list-chars
:desc "From clipboard" "y" #'+default/yank-pop) :desc "From clipboard" "y" #'+default/yank-pop)
@ -412,7 +412,7 @@
;;; Text scaling ;;; Text scaling
[C-mouse-4] #'text-scale-increase [C-mouse-4] #'text-scale-increase
[C-mouse-5] #'text-scale-decrease [C-mouse-5] #'text-scale-decrease
[C-down-mouse-2] (λ! (text-scale-set 0)) [C-down-mouse-2] (cmd! (text-scale-set 0))
"M-+" #'doom/reset-font-size "M-+" #'doom/reset-font-size
"M-=" #'doom/increase-font-size "M-=" #'doom/increase-font-size
"M--" #'doom/decrease-font-size "M--" #'doom/decrease-font-size
@ -463,7 +463,7 @@
:map company-search-map :map company-search-map
"C-n" #'company-search-repeat-forward "C-n" #'company-search-repeat-forward
"C-p" #'company-search-repeat-backward "C-p" #'company-search-repeat-backward
"C-s" (λ! (company-search-abort) (company-filter-candidates))) "C-s" (cmd! (company-search-abort) (company-filter-candidates)))
;;; ein notebooks ;;; ein notebooks
(:after ein:notebook-multilang (:after ein:notebook-multilang

View file

@ -18,7 +18,7 @@
"C-u" #'evil-delete-back-to-indentation "C-u" #'evil-delete-back-to-indentation
"C-v" #'yank "C-v" #'yank
"C-w" #'doom/delete-backward-word "C-w" #'doom/delete-backward-word
"C-z" (λ! (ignore-errors (call-interactively #'undo)))) "C-z" (cmd! (ignore-errors (call-interactively #'undo))))
(when (featurep! :editor evil +everywhere) (when (featurep! :editor evil +everywhere)
(define-key! :keymaps +default-minibuffer-maps (define-key! :keymaps +default-minibuffer-maps
@ -39,16 +39,14 @@
;;; Global keybindings ;;; Global keybindings
;; Smart tab, these will only work in GUI Emacs ;; Smart tab, these will only work in GUI Emacs
(map! :i [tab] (general-predicate-dispatch nil ; fall back to nearest keymap (map! :i [tab] (cmds! (and (featurep! :editor snippets)
(and (featurep! :editor snippets)
(bound-and-true-p yas-minor-mode) (bound-and-true-p yas-minor-mode)
(yas-maybe-expand-abbrev-key-filter 'yas-expand)) (yas-maybe-expand-abbrev-key-filter 'yas-expand))
#'yas-expand #'yas-expand
(and (featurep! :completion company +tng) (and (featurep! :completion company +tng)
(+company-has-completion-p)) (+company-has-completion-p))
#'+company/complete) #'+company/complete)
:v [tab] (general-predicate-dispatch nil :v [tab] (cmds! (and (bound-and-true-p yas-minor-mode)
(and (bound-and-true-p yas-minor-mode)
(or (eq evil-visual-selection 'line) (or (eq evil-visual-selection 'line)
(not (memq (char-after) (list ?\( ?\[ ?\{ ?\} ?\] ?\)))))) (not (memq (char-after) (list ?\( ?\[ ?\{ ?\} ?\] ?\))))))
#'yas-insert-snippet) #'yas-insert-snippet)
@ -136,7 +134,7 @@
"C-p" #'company-select-previous-or-abort "C-p" #'company-select-previous-or-abort
"C-j" #'company-select-next-or-abort "C-j" #'company-select-next-or-abort
"C-k" #'company-select-previous-or-abort "C-k" #'company-select-previous-or-abort
"C-s" (λ! (company-search-abort) (company-filter-candidates)) "C-s" (cmd! (company-search-abort) (company-filter-candidates))
[escape] #'company-search-abort)) [escape] #'company-search-abort))
;; TAB auto-completion in term buffers ;; TAB auto-completion in term buffers
(:after comint :map comint-mode-map (:after comint :map comint-mode-map
@ -456,8 +454,8 @@
;;; <leader> i --- insert ;;; <leader> i --- insert
(:prefix-map ("i" . "insert") (:prefix-map ("i" . "insert")
:desc "Current file name" "f" #'+default/insert-file-path :desc "Current file name" "f" #'+default/insert-file-path
:desc "Current file path" "F" (λ!! #'+default/insert-file-path t) :desc "Current file path" "F" (cmd!! #'+default/insert-file-path t)
:desc "Evil ex path" "p" (λ! (evil-ex "R!echo ")) :desc "Evil ex path" "p" (cmd! (evil-ex "R!echo "))
:desc "From evil register" "r" #'evil-ex-registers :desc "From evil register" "r" #'evil-ex-registers
:desc "Snippet" "s" #'yas-insert-snippet :desc "Snippet" "s" #'yas-insert-snippet
:desc "Unicode" "u" #'unicode-chars-list-chars :desc "Unicode" "u" #'unicode-chars-list-chars