Files
sydnix/modules/home/users/msyds/emacs/lisp/syd/escape.el
T
2025-11-23 04:06:39 -07:00

64 lines
2.1 KiB
EmacsLisp
Executable File

;;; -*- lexical-binding: t; -*-
(defvar syd-escape-hook nil
"A hook run when C-g is pressed (or ESC in Evil's normal state).
More specifically, when `syd/escape' is pressed. If any hook returns non-nil,
all hooks after it are ignored.")
;;; Universal, non-nuclear escape
;; `keyboard-quit' is too much of a nuclear option. I want ESC/C-g to
;; do-what-I-mean. It serves four purposes (in order):
;;
;; 1. Quit active states; e.g. highlights, searches, snippets, iedit,
;; multiple-cursors, recording macros, etc.
;; 2. Close popup windows remotely (if it is allowed to)
;; 3. Refresh buffer indicators, like diff-hl and flycheck
;; 4. Or fall back to `keyboard-quit'
;;
;; And it should do these things incrementally, rather than all at once. And it
;; shouldn't interfere with recording macros or the minibuffer. This may
;; require you press ESC/C-g two or three times on some occasions to reach
;; `keyboard-quit', but this is much more intuitive.
(defun syd-escape (&optional interactive)
"Run `syd-escape-hook'."
(interactive (list 'interactive))
(let ((inhibit-quit t))
(cond ((minibuffer-window-active-p (minibuffer-window))
;; quit the minibuffer if open.
(when interactive
(setq this-command 'abort-recursive-edit))
(abort-recursive-edit))
;; Run all escape hooks. If any returns non-nil, then stop there.
((run-hook-with-args-until-success 'syd-escape-hook))
;; don't abort macros
((or defining-kbd-macro executing-kbd-macro) nil)
;; Back to the default
((unwind-protect (keyboard-quit)
(when interactive
(setq this-command 'keyboard-quit)))))))
;;; Hacks
(with-eval-after-load 'eldoc
(eldoc-add-command 'syd-escape))
;; In normal state, pressing escape should run `syd-escape-hook'.
(with-eval-after-load 'evil
(defun evil-syd-escape-a (&rest _)
"Call `syd-escape' if `evil-force-normal-state' is called interactively."
(when (called-interactively-p 'any)
(call-interactively #'syd-escape)))
(advice-add #'evil-force-normal-state
:after #'evil-syd-escape-a))
(provide 'syd/escape)