Commit dicipline fail
This commit is contained in:
@@ -5,4 +5,106 @@
|
||||
|
||||
(require 'general)
|
||||
|
||||
(defvar syd-leader-key "SPC"
|
||||
"A prefix key akin to Vim's <Leader>.")
|
||||
|
||||
(defvar syd-localleader-key "SPC m"
|
||||
"A prefix key akin to Vim's <LocalLeader>.")
|
||||
|
||||
(defvar syd-alt-leader-key "M-SPC"
|
||||
"`syd-leader', but for the states specified in `syd-alt-leader-key-states'.
|
||||
|
||||
Often, your \"usual\" leader key will be something unavailable in the Insert
|
||||
state. This key exists as a fallback for when you need your Leader, but must
|
||||
remain in the Insert state. Substitute \"Insert state\" for your states of
|
||||
choice with `syd-alt-leader-key-states'.")
|
||||
|
||||
(defvar syd-alt-localleader-key "M-SPC m"
|
||||
"`syd-localleader', but for the states specified in `syd-alt-leader-key-states'.
|
||||
|
||||
See `syd-alt-leader-key' for rationale.")
|
||||
|
||||
(defvar syd-leader-key-states '(normal visual motion)
|
||||
"States for which the Leader keys (`syd-leader-key', `syd-localleader-key')
|
||||
are active.")
|
||||
|
||||
(defvar syd-alt-leader-key-states '(emacs insert)
|
||||
"States for which the alternative Leader keys are active. See
|
||||
`syd-alt-leader-key' and `syd-alt-localleader-key'.")
|
||||
|
||||
(defvar-keymap syd-leader-map
|
||||
:doc "Leader-prefixed commands")
|
||||
|
||||
(defun syd-initialise-leader ()
|
||||
"Set up the (empty) keymap associated with `syd-leader-key',
|
||||
`syd-localleader-key', `syd-alt-leader-key', and `syd-alt-localleader-key'."
|
||||
(require 'evil)
|
||||
;; Define `syd/leader' as a command corresponding to the prefix map
|
||||
;; `syd-leader-map'.
|
||||
(define-prefix-command 'syd/leader 'syd-leader-map)
|
||||
;; This should help make the Leader key close to universally available.
|
||||
;; Ideally, *nothing* takes precedence over Leader — it's an incredibly
|
||||
;; important key!
|
||||
;; https://github.com/noctuid/evil-guide?tab=readme-ov-file#undoprevent-overridingintercept-maps
|
||||
;; See `evil-make-overriding-map'.
|
||||
(define-key syd-leader-map [override-state] 'all)
|
||||
;; Finally, we shall bind the damned keys. }:)
|
||||
(let ((map general-override-mode-map))
|
||||
(evil-define-key* syd-leader-key-states map (kbd syd-leader-key) 'syd/leader)
|
||||
(evil-define-key* syd-alt-leader-key-states map (kbd syd-alt-leader-key) 'syd/leader))
|
||||
(general-override-mode 1))
|
||||
|
||||
(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)))))))
|
||||
|
||||
(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-general)
|
||||
|
||||
@@ -124,6 +124,21 @@ comment, if there is one. Returns nil or a pair (BEG . END)."
|
||||
"When `syd-evil-a-defun' is used in combination with one of these operators,
|
||||
some cleanup will be performed.")
|
||||
|
||||
;; FIXME(#12): Comments should only attach to the *immediately* following sexp.
|
||||
;; Consider the following snippet:
|
||||
;;
|
||||
;; ;; Call the continuation if non-nil. Wraps the return value in a singleton
|
||||
;; ;; list for "affine" use with unquote-splicing.
|
||||
;; (let ((call-cont (lambda (cont arg)
|
||||
;; (if cont
|
||||
;; (list (funcall cont arg))
|
||||
;; nil)))
|
||||
;; names)
|
||||
;; ...)
|
||||
;;
|
||||
;; The curreny behaviour of `syd-sexp--backward-attached-comment' considers the
|
||||
;; comment to be attached to both the (let ...) form, as well as the ((call-cont
|
||||
;; ...)) form and the (call-cont ...) form. Not good!
|
||||
(defun syd-sexp--backward-attached-comment ()
|
||||
"Assuming point is on the opening delimiter of a sexp, move point backward to
|
||||
the beginning of the \"attached\" comment."
|
||||
@@ -155,7 +170,7 @@ to clean up whitespace following certain operators."
|
||||
(list beg-0 :end)))))
|
||||
|
||||
;; IDEA: How about the inner-defun text object selects the defun /without/ the
|
||||
;; comment? Is that more useful, or less? I can't think of the last time I've
|
||||
;; comment? Is that more useful, or less? I can't think of the last time Ive
|
||||
;; needed the top-level sexp without the brackets.
|
||||
|
||||
;;;###autoload
|
||||
@@ -189,6 +204,7 @@ delimiters."
|
||||
(sexp (syd-get-enclosing-sexp)))
|
||||
(if cleanup-p
|
||||
(save-excursion
|
||||
(goto-char (sp-get sexp :beg))
|
||||
(if (syd-sexp--looking-at-last-p)
|
||||
(progn (syd-sexp--backward-leading-whitespace sexp)
|
||||
(list (point) (sp-get sexp :end)))
|
||||
@@ -208,9 +224,9 @@ sexp-wise analogue to Evil's line-wise `evil-open-below'."
|
||||
:suppress-operator t
|
||||
(evil-with-single-undo
|
||||
;; We want to add an additional blank line when operating at the top level.
|
||||
;; Instead of parsing upward until we can no longer find an enclosing sexp, we
|
||||
;; simply check if the opening bracket is on the first column. This is not
|
||||
;; very correct, but it's way less work (for myself and the CPU). If we
|
||||
;; Instead of parsing upward until we can no longer find an enclosing sexp,
|
||||
;; we simply check if the opening bracket is on the first column. This is
|
||||
;; not very correct, but it's way less work (for myself and the CPU). If we
|
||||
;; switch to a tree-sitter–based parser, I'd love to switch to the correct
|
||||
;; algorithm.
|
||||
(-let* (((beg . end) (sp-get (syd-get-enclosing-sexp) (cons :beg :end)))
|
||||
|
||||
@@ -12,40 +12,70 @@
|
||||
,todo
|
||||
(error ,todo))))
|
||||
|
||||
(cl-defun syd--lift-lambdas (forms &key with-each with-all)
|
||||
;; FIXME: When `arg-list' contains nils, things break.
|
||||
(cl-defun syd-parse-rest-and-keys (arg-list)
|
||||
"The default behaviour of `cl-defun' makes combining &rest with &keys pretty
|
||||
useless. This function will partition ARG-LIST by returning a pair (REST
|
||||
. KEYS), where REST is the list of ARGS that belong to no key-value pair, and
|
||||
KEYS is an alist of the parsed keywords."
|
||||
;; Ugh.
|
||||
(let (parsed-rest parsed-keys)
|
||||
(cl-loop for (lead lag) on arg-list by (lambda (x) (-drop 2 x))
|
||||
do (if (keywordp lead)
|
||||
(push (cons lead lag) parsed-keys)
|
||||
;; Push in reverse order; we reverse the whole list as a
|
||||
;; post-processing step.
|
||||
(push lead parsed-rest)
|
||||
(when lag
|
||||
(push lag parsed-rest))))
|
||||
(cons (reverse parsed-rest) parsed-keys)))
|
||||
|
||||
(cl-defun syd-lift-lambdas (&rest args)
|
||||
;; Call the continuation if non-nil. Wraps the return value in a singleton
|
||||
;; list for "affine" use with unquote-splicing.
|
||||
(let ((call-cont (lambda (cont)
|
||||
(if cont
|
||||
(lambda (name) (list (funcall with-each name)))
|
||||
(lambda (_) nil))))
|
||||
names)
|
||||
`(progn ,@(mapconcat (lambda (form)
|
||||
(cond ((and (symbolp form) (functionp form))
|
||||
(push form names)
|
||||
(call-cont with-each form))
|
||||
((eq (car-safe form) 'defun)
|
||||
(let ((name (nth 1 form)))
|
||||
(push name names)
|
||||
`(,form
|
||||
,@(call-cont with-each))))
|
||||
((eq (car-safe form) 'lambda)
|
||||
(let ((name (gensym "lifted-lambda")))
|
||||
(push name names)
|
||||
`((defun ,name (&rest args)
|
||||
(,form args))
|
||||
,@(call-cont with-each))))))
|
||||
(ensure-list forms))
|
||||
,@(call-cont with-all names))))
|
||||
(-let (((forms . (&alist :with-each with-each
|
||||
:with-all with-all))
|
||||
(syd-parse-rest-and-keys args))
|
||||
(call-cont (lambda (cont arg)
|
||||
(if cont
|
||||
(list (funcall cont arg))
|
||||
nil)))
|
||||
names)
|
||||
`(progn
|
||||
,@(cl-loop
|
||||
for form in forms
|
||||
appending (cond ((and (symbolp form) (functionp form))
|
||||
(push form names)
|
||||
(funcall call-cont with-each form))
|
||||
((syd-hform-defun form)
|
||||
(let ((name (nth 1 form)))
|
||||
(push name names)
|
||||
`(,form
|
||||
,@(funcall call-cont with-each name))))
|
||||
((syd-hform-lambda form)
|
||||
(let ((name (gensym "lifted-lambda")))
|
||||
(push name names)
|
||||
`((defun ,name (&rest args)
|
||||
(,form args))
|
||||
,@(funcall call-cont with-each name))))
|
||||
(t (error "IDK!"))))
|
||||
,@(funcall call-cont with-all names))))
|
||||
|
||||
;; (defun syd-hform-defun (hform)
|
||||
;; "If HFORM is a defun form, return the defun's name. Otherwise, return nil"
|
||||
;; (and (listp hform)
|
||||
;; (<= 2 (length hform))
|
||||
;; (nth 1 hform)))
|
||||
(defun syd-hform-defun (hform)
|
||||
"If HFORM is a defun form, return the defun's name. Otherwise, return nil"
|
||||
(when-let* ((sym (car-safe hform)))
|
||||
(and (symbolp sym)
|
||||
(eq sym 'defun)
|
||||
(nth 1 hform))))
|
||||
|
||||
(defun syd-hform-lambda (hform)
|
||||
"If HFORM is a lambda, return non-nil."
|
||||
(when-let* ((sym (car-safe hform)))
|
||||
(and (symbolp sym)
|
||||
(eq sym 'lambda))))
|
||||
|
||||
(defmacro comment (&rest _)
|
||||
"Completely every argument, and expand to nil."
|
||||
"Ignore each argument, and expand to nil."
|
||||
nil)
|
||||
|
||||
(defmacro with-transient-after (hook-or-function &rest forms)
|
||||
@@ -74,4 +104,30 @@ not mutated; a new plist is returned."
|
||||
(list prop* new-val)
|
||||
(list prop* old-val))))
|
||||
|
||||
;; TODO: Support (syd-add-hook 'hook (defun my-hook () ...))
|
||||
(defun syd-add-hook (hooks &rest functions)
|
||||
(declare (indent defun))
|
||||
(dolist (hook (ensure-list hooks))
|
||||
(dolist (fn functions)
|
||||
(add-hook hook fn))))
|
||||
|
||||
(defmacro syd-silently (&rest body)
|
||||
`(error "TODO: syd-silently"))
|
||||
|
||||
(defmacro syd-quietly (&rest body)
|
||||
"Evaluate BODY without generating any output.
|
||||
|
||||
This silences calls to `message', `load', `write-region' and anything that
|
||||
writes to `standard-output'. In interactive sessions this inhibits output to
|
||||
the echo-area, but not to *Messages*. Return value is that of BODY's final
|
||||
form."
|
||||
`(if init-file-debug
|
||||
(progn ,@body)
|
||||
,(if noninteractive
|
||||
`(syd-silently ,@body)
|
||||
`(let ((inhibit-message t)
|
||||
(save-silently t))
|
||||
(prog1 (progn ,@body)
|
||||
(message ""))))))
|
||||
|
||||
(provide 'syd-prelude)
|
||||
|
||||
27
users/crumb/programs/emacs/lib/syd-prose.el
Normal file
27
users/crumb/programs/emacs/lib/syd-prose.el
Normal file
@@ -0,0 +1,27 @@
|
||||
;;; syd-prose.el -*- lexical-binding: t; -*-
|
||||
|
||||
(use-package visual-fill-column
|
||||
:defer t)
|
||||
|
||||
(defun syd-prose-disable-display-line-numbers-mode-h ()
|
||||
"Disable `display-line-numbers-mode'."
|
||||
(display-line-numbers-mode -1))
|
||||
|
||||
(defun syd-prose-set-visual-fill-column-center ()
|
||||
"Sets the buffer-local value for `visual-fill-column-center-text'."
|
||||
(setq-local visual-fill-column-center-text t))
|
||||
|
||||
(defvar syd-prose-mode-hook
|
||||
(list #'syd-prose-set-visual-fill-column-center
|
||||
#'visual-fill-column-mode
|
||||
#'visual-line-mode
|
||||
#'variable-pitch-mode
|
||||
#'syd-prose-disable-display-line-numbers-mode-h)
|
||||
"Hooks run for `syd-prose-mode'.")
|
||||
|
||||
;;;###autoload
|
||||
(define-minor-mode syd-prose-mode
|
||||
"A minor mode for writing prose."
|
||||
:lighter nil)
|
||||
|
||||
(provide 'syd-prose)
|
||||
Reference in New Issue
Block a user