This is a mess

I'm sorry.  I really wanted to improve my commit discipline.  I know.  I can't
be fucked to comb this diff and split it into 8 properly-ordered commits, like I
know I should.  I'm not having a good time right now.  We'll do better moving
forward.
This commit is contained in:
Madeleine Sydney
2025-01-31 16:45:37 -07:00
parent f247599853
commit d59c79a8d4
16 changed files with 721 additions and 33 deletions

View File

@@ -214,6 +214,32 @@ Disassemble project-ideas.org and reading-list.org into a individual roam nodes.
- variable-pitch: Overpass - variable-pitch: Overpass
- backup: Julia Mono - backup: Julia Mono
*** TODO Lisp editing
**** TODO [[https://github.com/promethial/paxedit][Paxedit]]
**** TODO Evil stuff
**** TODO Text objects
**** TODO [[https://github.com/Malabarba/speed-of-thought-lisp][speed-of-thought]]
**** TODO [[https://github.com/Lindydancer/lisp-extra-font-lock][lisp-extra-font-lock]]
**** TODO rainbow-delimiters
**** TODO [[https://github.com/Wilfred/emacs-refactor][emacs-refactor]]
**** TODO [[https://github.com/Malabarba/aggressive-indent-mode][aggressive-indent-mode]]
**** TODO [[https://github.com/riscy/elfmt][elfmt]]
**** TODO [[https://github.com/magnars/string-edit.el][string-edit]]
**** TODO [[https://github.com/Fuco1/elisp-docstring-mod][elisp-docstring]]
*** TODO [[https://github.com/purcell/page-break-lines][page-break-lines]]
*** DONE project.el *** DONE project.el
CLOSED: [2025-01-16 Thu 18:19] CLOSED: [2025-01-16 Thu 18:19]
@@ -225,9 +251,8 @@ CLOSED: [2025-01-16 Thu 18:19]
**** TODO Spell-checking **** TODO Spell-checking
*** TODO Sexp editing *** DONE Lookup handlers
CLOSED: [2025-02-01 Sat 16:56]
*** TODO Lookup handlers
*** DONE Repl-handling *** DONE Repl-handling
CLOSED: [2025-01-31 Fri] CLOSED: [2025-01-31 Fri]

View File

@@ -0,0 +1,3 @@
doge
soge
grep -r xref

View File

@@ -2,6 +2,8 @@
;; Initialise Straight.el ;; Initialise Straight.el
(+ 1 2)
(load (locate-user-emacs-file "init-straight")) (load (locate-user-emacs-file "init-straight"))
(syd-initialise-straight) (syd-initialise-straight)
@@ -52,6 +54,7 @@
(require 'syd-custom) (require 'syd-custom)
(require 'syd-display-startup-time) (require 'syd-display-startup-time)
(require 'syd-evil) (require 'syd-evil)
(require 'syd-eshell)
(require 'syd-keybinds) (require 'syd-keybinds)
(require 'syd-lang) (require 'syd-lang)
(require 'syd-org) (require 'syd-org)

View File

@@ -118,6 +118,15 @@ See `syd-real-buffer-p' for details on what that means."
(when (syd-unreal-buffer-p (window-buffer)) (when (syd-unreal-buffer-p (window-buffer))
(switch-to-buffer (syd-fallback-buffer))))))) (switch-to-buffer (syd-fallback-buffer)))))))
;;;###autoload
(defun syd-set-buffer-realness (buffer realness)
(with-current-buffer buffer
(setq syd-real-buffer-p realness)))
;;;###autoload
(defun syd-mark-buffer-as-real ()
(syd-set-buffer-realness (current-buffer) t))
(defun syd-kill-buffer-fixup-windows (buffer) (defun syd-kill-buffer-fixup-windows (buffer)
"Kill the BUFFER and ensure all the windows it was displayed in have switched "Kill the BUFFER and ensure all the windows it was displayed in have switched
to a real buffer or the fallback buffer." to a real buffer or the fallback buffer."

View File

@@ -0,0 +1,258 @@
;;; syd-handle-eval.el -*- lexical-binding: t; -*-
(defvar syd-eval-runners '())
;; Remove ellipsis when printing sexps in message buffer.
(setq eval-expression-print-length nil
eval-expression-print-level nil)
(set-popup-rule!
"*eval*"
:size 0.2)
;; Packages
(use-package quickrun
:defer t)
(use-package eros
:hook (emacs-lisp-mode . eros-mode))
;; (with-eval-after-load quickrun
;; (setq quickrun-focus-p nil)
;; (set-popup-rule! "^\\*quickrun" :size 0.3 :ttl 0)
;; (defadvice! +eval--quickrun-fix-evil-visual-region-a ()
;; "Make `quickrun-replace-region' recognize evil visual selections."
;; :override #'quickrun--outputter-replace-region
;; (let ((output (buffer-substring-no-properties (point-min) (point-max))))
;; (with-current-buffer quickrun--original-buffer
;; (cl-destructuring-bind (beg . end)
;; ;; Because `deactivate-mark', the function, was used in
;; ;; `quickrun--region-command-common' instead of `deactivate-mark',
;; ;; the variable, the selection is disabled by this point.
;; (if (bound-and-true-p evil-local-mode)
;; (cons evil-visual-beginning evil-visual-end)
;; (cons (region-beginning) (region-end)))
;; (delete-region beg end)
;; (insert output))
;; (setq quickrun-option-outputter quickrun--original-outputter))))
;; (defadvice! +eval--quickrun-auto-close-a (&rest _)
;; "Silently re-create the quickrun popup when re-evaluating."
;; :before '(quickrun quickrun-region)
;; (when-let (win (get-buffer-window quickrun--buffer-name))
;; (let ((inhibit-message t))
;; (quickrun--kill-running-process)
;; (message ""))
;; (delete-window win)))
;; (add-hook! 'quickrun-after-run-hook
;; (defun +eval-quickrun-shrink-window-h ()
;; "Shrink the quickrun output window once code evaluation is complete."
;; (when-let (win (get-buffer-window quickrun--buffer-name))
;; (with-selected-window (get-buffer-window quickrun--buffer-name)
;; (let ((ignore-window-parameters t))
;; (shrink-window-if-larger-than-buffer)))))
;; (defun +eval-quickrun-scroll-to-bof-h ()
;; "Ensures window is scrolled to BOF on invocation."
;; (when-let (win (get-buffer-window quickrun--buffer-name))
;; (with-selected-window win
;; (goto-char (point-min))))))
;; ;; Display evaluation results in an overlay at the end of the current line. If
;; ;; the output is more than `+eval-popup-min-lines' (4) lines long, it is
;; ;; displayed in a popup.
;; (when (modulep! +overlay)
;; (defadvice! +eval--show-output-in-overlay-a (fn)
;; :filter-return #'quickrun--make-sentinel
;; (lambda (process event)
;; (funcall fn process event)
;; (with-current-buffer quickrun--buffer-name
;; (when (> (buffer-size) 0)
;; (+eval-display-results
;; (string-trim (buffer-string))
;; quickrun--original-buffer)))))
;; ;; Suppress quickrun's popup window because we're using an overlay instead.
;; (defadvice! +eval--inhibit-quickrun-popup-a (buf cb)
;; :override #'quickrun--pop-to-buffer
;; (setq quickrun--original-buffer (current-buffer))
;; (save-window-excursion
;; (with-current-buffer (pop-to-buffer buf)
;; (setq quickrun-option-outputter #'ignore)
;; (funcall cb))))
;; ;; HACK Without this, `+eval--inhibit-quickrun-popup-a' throws a
;; ;; window-live-p error because no window exists to be recentered!
;; (advice-add #'quickrun--recenter :override #'ignore)))
;;;###autoload
(cl-defun syd-eval-region-as-major-mode
(beg end &key (runner-major-mode major-mode))
"Evaluate a region between BEG and END and display the output.
Evaluate as in RUNNER-MAJOR-MODE. If RUNNER-MAJOR-MODE is nil, use major-mode
of the buffer instead."
(if-let* ((runner (alist-get runner-major-mode syd-eval-runners)))
(funcall runner beg end)
(and (require 'quickrun nil t)
(let ((quickrun-option-cmdkey
(quickrun--command-key
(buffer-file-name (buffer-base-buffer)))))
(quickrun-region beg end)))))
;;;###autoload
(defun syd-eval-region (beg end)
(interactive "r")
;; (message "syd: %s" (pp-to-string
;; (buffer-substring-no-properties (syd-region-beginning)
;; (syd-region-end))))
;; (message "r: %s" (pp-to-string (buffer-substring-no-properties beg end)))
(syd-eval-region-as-major-mode beg end))
(with-eval-after-load 'evil
(evil-define-operator syd-eval-operator (beg end)
"Evaluate selection."
:move-point nil
(interactive "<r>")
(syd-eval-region beg end))
(general-def
:states 'normal
"gR" #'syd-eval-buffer)
(general-def
:states '(normal visual)
"gr" #'syd-eval-operator))
;;;###autoload
(defun set-eval-handler! (modes command)
"Define a code evaluator for major mode MODES with `quickrun'.
MODES can be list of major mode symbols, or a single one.
1. If MODE is a string and COMMAND is the string, MODE is a file regexp and
COMMAND is a string key for an entry in `quickrun-file-alist'.
2. If MODE is not a string and COMMAND is a string, MODE is a major-mode symbol
and COMMAND is a key (for `quickrun--language-alist'), and will be registered
in `quickrun--major-mode-alist'.
3. If MODE is not a string and COMMAND is an alist, see `quickrun-add-command':
(quickrun-add-command MODE COMMAND :mode MODE).
4. If MODE is not a string and COMMANd is a symbol, add it to
`syd-eval-runners', which is used by `syd-eval-region'."
(declare (indent defun))
(dolist (mode (ensure-list modes))
(cond ((symbolp command)
(push (cons mode command) syd-eval-runners))
((stringp command)
(with-eval-after-load 'quickrun
(push (cons mode command)
(if (stringp mode)
quickrun-file-alist
quickrun--major-mode-alist))))
((listp command)
(with-eval-after-load 'quickrun
(quickrun-add-command
(or (cdr (assq mode quickrun--major-mode-alist))
(string-remove-suffix "-mode" (symbol-name mode)))
command :mode mode))))))
(defvar syd-eval-overlay-max-lines 4
"The maximum number of lines allowed to be displayed in an eval overlay; any
more and a popup buffer will be used instead.")
;;;###autoload
(defun syd-eval-display-results-in-popup (output)
"Display OUTPUT in a popup buffer."
(let ((output-buffer (get-buffer-create "*eval*"))
(origin (selected-window)))
(with-current-buffer output-buffer
(setq-local scroll-margin 0)
(erase-buffer)
(insert output)
(goto-char (point-min))
;; (if (fboundp '+word-wrap-mode)
;; (+word-wrap-mode +1)
;; (visual-line-mode +1))
)
(when-let* ((win (display-buffer output-buffer)))
;; (fit-window-to-buffer
;; win (/ (frame-height) 2)
;; nil (/ (frame-width) 2))
)
(select-window origin)
output-buffer))
;;;###autoload
(defun syd-eval-buffer ()
"Evaluate the entire buffer."
(interactive)
(syd-eval-region (point-min) (point-max)))
;;;###autoload
(defun syd-eval-buffer-or-region ()
"Evaluate the region if it is active, or the entire buffer, or not."
(if (use-region-p)
(call-interactively #'syd-eval-region)
(call-interactively #'syd-eval-buffer)))
;;;###autoload
(cl-defun syd-eval-display-results-in-overlay (output &key source-buffer)
"Display OUTPUT in a floating overlay next to the cursor."
(require 'eros)
(with-current-buffer (or source-buffer (current-buffer))
(let* ((this-command #'syd-eval/buffer-or-region)
(prefix eros-eval-result-prefix)
(lines (split-string output "\n"))
(prefixlen (length prefix))
(len (+ (apply #'max (mapcar #'length lines))
prefixlen))
(next-line? (or (cdr lines)
(< (- (window-width)
(save-excursion (goto-char (line-end-position))
(- (current-column)
(window-hscroll))))
len)))
(pad (if next-line?
(+ (window-hscroll) prefixlen)
0))
eros-overlays-use-font-lock)
(eros--make-result-overlay
(concat (make-string (max 0 (- pad prefixlen)) ?\s)
prefix
(string-join lines (concat hard-newline (make-string pad ?\s))))
:where (if next-line?
(line-beginning-position 2)
(line-end-position))
:duration eros-eval-result-duration
:format "%s"))))
;;;###autoload
(cl-defun syd-eval-display-results (output &key source-buffer force-popup)
"Display OUTPUT in an overlay, or if it's too long, a popup buffer."
(if (or force-popup
;; EROS is used to display overlays. Without it, just use a popup.
(not (require 'eros nil t))
(with-temp-buffer
(insert output)
(or
;; Too tall!
(<= syd-eval-overlay-max-lines
(count-lines (point-min) (point-max)))
;; Too wide!
(<= (window-width)
(string-width
(buffer-substring (point-min)
(save-excursion
(goto-char (point-min))
(line-end-position))))))))
(syd-eval-display-results-in-popup output)
(syd-eval-display-results-in-overlay output :source-buffer source-buffer))
output)
(provide 'syd-handle-eval)

View File

@@ -6,11 +6,59 @@
(require 'better-jumper) (require 'better-jumper)
(defvar syd-lookup-documentation-handlers '() (defvar syd-lookup-online-documentation-backends
"An list of lookup handlers used to find documentation. A lookup handler `(("Kagi" . "https://kagi.com/search?q=%s")
("DuckDuckGo" . "https://duckduckgo.com/?q=%s")
("Nixpkgs" . "https://search.nixos.org/packages?query=%s")
("Hackage" . "https://hackage.haskell.org/packages/search?terms=%s"))
"A list of pairs (NAME . BACKEND) describing the various backends
`syd-lookup-online-documentation' may delegate to.
NAME is a string used when speaking to the user about BACKEND.
If BACKEND is an interactive command, it will be called interactively.
If BACKEND is a procedure, it will be called with the search string as the lone
argument.
If BACKEND is a string, the user's browser will be opened to the URL returned by
(format BACKEND QUERY), where QUERY is the appropriately-encoded search
string.")
(defvar syd-lookup-documentation-handlers '(syd-lookup-online-documentation)
"A list of lookup handlers used to find documentation. A lookup handler
receives an identifier, and is expected to return nil on failure, and non-nil on receives an identifier, and is expected to return nil on failure, and non-nil on
success. The specific return value is unused outside of the test for nil.") success. The specific return value is unused outside of the test for nil.")
(defun syd-lookup--prompt-for-online-backend ()
(assoc-string
(completing-read "Search with: "
(mapcar #'car syd-lookup-online-documentation-backends)
nil
t)
syd-lookup-online-documentation-backends))
(cl-defun syd-lookup--call-online-backend (backend &key query-string)
(pcase-let ((`(,name . ,backend-fn) backend))
(cond ((functionp backend-fn) (if (commandp backend-fn)
(call-interactively backend-fn)
(funcall backend-fn query-string)))
((stringp backend-fn)
(browse-url (format backend-fn
(url-encode-url
(read-string (format "Search for (on %s): "
name)
query-string)))))
(t (signal 'wrong-type-argument `("backend" ,backend-fn))))))
;;;###autoload
(cl-defun syd-lookup-online-documentation (backend &key query-string)
(interactive (list (syd-lookup--prompt-for-online-backend)
:query-string (when (use-region-p)
(syd-thing-at-point-or-region))))
(syd-lookup--call-online-backend (syd-lookup--prompt-for-online-backend)
:query-string query-string))
;;;###autoload ;;;###autoload
(defun syd-lookup-documentation (identifier) (defun syd-lookup-documentation (identifier)
"Try to find documentation on IDENTIFIER, and " "Try to find documentation on IDENTIFIER, and "
@@ -28,6 +76,8 @@ success. The specific return value is unused outside of the test for nil.")
(category identifier &key (display-fn #'switch-to-buffer)) (category identifier &key (display-fn #'switch-to-buffer))
(let* ((handlers (alist-get category syd-lookup--handlers-by-category)) (let* ((handlers (alist-get category syd-lookup--handlers-by-category))
(origin (point-marker)) (origin (point-marker))
;; TODO: If called with a prefix argument, prompt the user to select a
;; handler.
(result (run-hook-wrapped handlers #'syd-lookup--run-handler (result (run-hook-wrapped handlers #'syd-lookup--run-handler
identifier origin))) identifier origin)))
(message "result wrap hok: %S" result) (message "result wrap hok: %S" result)

View File

@@ -12,4 +12,52 @@
,todo ,todo
(error ,todo)))) (error ,todo))))
(cl-defun syd--lift-lambdas (forms &key with-each with-all)
;; 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))))
;; (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)))
(defmacro with-transient-after (hook-or-function &rest forms)
(let ((hook-name (gensym "transient-hook"))
(hook-or-function* (gensym "hook-or-function")))
`(let* ((,hook-or-function* ,hook-or-function))
(defun ,hook-name (&rest _)
"Transient hook defined by `with-transient-after'."
(cond ((functionp ,hook-or-function*)
(advice-remove ,hook-or-function* (function ,hook-name)))
((symbolp ,hook-or-function*)
(remove-hook ,hook-or-function* (function ,hook-name))))
,@forms)
(cond ((functionp ,hook-or-function*)
(advice-add ,hook-or-function* :before (function ,hook-name)))
((symbolp ,hook-or-function*)
(add-hook ,hook-or-function* (function ,hook-name)))))))
(provide 'syd-prelude) (provide 'syd-prelude)

View File

@@ -2,6 +2,7 @@
(require 'syd-handle-repl) (require 'syd-handle-repl)
(require 'syd-handle-lookup) (require 'syd-handle-lookup)
(require 'syd-handle-eval)
;; (require 'handle) ;; (require 'handle)
;; Don't `use-package' `ielm', since it's loaded by Emacs. You'll get weird ;; Don't `use-package' `ielm', since it's loaded by Emacs. You'll get weird
@@ -37,6 +38,31 @@
(set-repl-handler! 'emacs-lisp-mode (set-repl-handler! 'emacs-lisp-mode
#'syd/open-emacs-lisp-repl) #'syd/open-emacs-lisp-repl)
;;;###autoload
(defun syd-emacs-lisp-eval (beg end)
"Evaluate a region and print it to the echo area (if one line long), otherwise
to a pop up buffer."
(syd-eval-display-results
(string-trim-right
(let ((buffer (generate-new-buffer " *eval-output*"))
(debug-on-error t))
(unwind-protect
(condition-case-unless-debug e
(progn (eval-region beg end buffer load-read-function)
(with-current-buffer buffer
(let ((pp-max-width nil))
(require 'pp)
(pp-buffer)
(replace-regexp-in-string
"\\\\n" "\n" (string-trim-left (buffer-string))))))
(error (format "ERROR: %s" e)))
(kill-buffer buffer))))
:source-buffer (current-buffer)
:force-popup current-prefix-arg))
(set-eval-handler! 'emacs-lisp-mode
#'syd-emacs-lisp-eval)
(defun syd-emacs-set-handlers () (defun syd-emacs-set-handlers ()
(setq-local syd-lookup-documentation-handlers (setq-local syd-lookup-documentation-handlers
(list #'syd-emacs-lisp-lookup-documentation))) (list #'syd-emacs-lisp-lookup-documentation)))

View File

@@ -1,7 +1,5 @@
;;; syd-completion.el -*- lexical-binding: t; -*- ;;; syd-completion.el -*- lexical-binding: t; -*-
(require 'syd-general)
(use-package emacs (use-package emacs
:custom :custom
;; Allow the opening of new minibuffers from inside existing minibuffers. ;; Allow the opening of new minibuffers from inside existing minibuffers.

View File

@@ -0,0 +1,110 @@
;;; syd-eshell.el -*- lexical-binding: t; -*-
(defvar eshell-buffer-name "*eshell*")
(defvar syd-eshell-buffers (make-ring 25)
"List of open eshell buffers.")
(defun syd-eshell-buffers ()
"TODO"
(ring-elements syd-eshell-buffers))
;;;###autoload
(defun syd-eshell-run-command (command &optional buffer)
"TODO"
(let ((buffer
(or buffer
(if (eq major-mode 'eshell-mode)
(current-buffer)
(cl-find-if #'buffer-live-p (syd-eshell-buffers))))))
(unless buffer
(user-error "No living eshell buffers available"))
(unless (buffer-live-p buffer)
(user-error "Cannot operate on a dead buffer"))
(with-current-buffer buffer
(goto-char eshell-last-output-end)
(goto-char (line-end-position))
(insert command)
(eshell-send-input nil t))))
;;;###autoload
(defun syd-eshell/toggle (arg &optional command)
"Toggle eshell popup window."
(interactive "P")
(let ((eshell-buffer
(get-buffer-create
(format "*eshell-popup:%s*"
(if (bound-and-true-p persp-mode)
(safe-persp-name (get-current-persp))
"main"))))
confirm-kill-processes
current-prefix-arg)
(when arg
(when-let* ((win (get-buffer-window eshell-buffer)))
(delete-window win))
(when (buffer-live-p eshell-buffer)
(with-current-buffer eshell-buffer
(fundamental-mode)
(erase-buffer))))
(if-let* ((win (get-buffer-window eshell-buffer)))
(let (confirm-kill-processes)
(delete-window win)
(ignore-errors (kill-buffer eshell-buffer)))
(with-current-buffer eshell-buffer
(syd-mark-buffer-as-real)
(if (eq major-mode 'eshell-mode)
(run-hooks 'eshell-mode-hook)
(eshell-mode))
(when command
(syd-eshell-run-command command eshell-buffer)))
(pop-to-buffer eshell-buffer))))
(use-package eshell
:custom
((eshell-banner-message
'(format "🦌 %s %s }:3\n"
(propertize (format " %s " (string-trim (buffer-name)))
'face 'mode-line-highlight)
(propertize (current-time-string)
'face 'font-lock-keyword-face)))
(eshell-scroll-to-bottom-on-input 'all)
(eshell-scroll-to-bottom-on-output 'all)
(eshell-kill-processes-on-exit t)
(eshell-hist-ignoredups t)
(eshell-glob-case-insensitive t)
(eshell-error-if-no-glob t))
:general
(:keymaps 'syd-leader-open-map
"e" #'syd-eshell/toggle)
(:keymaps 'eshell-mode-map
:states '(normal insert)
"C-j" #'eshell-next-matching-input-from-input
"C-k" #'eshell-previous-matching-input-from-input)
:config
(require 'syd-buffers)
(add-hook 'eshell-mode-hook #'syd-mark-buffer-as-real)
;; UI enhancements.
(defun syd-eshell-remove-fringes-h ()
(set-window-fringes nil 0 0)
(set-window-margins nil 1 nil))
(defun syd-eshell-enable-text-wrapping-h ()
(visual-line-mode +1)
(set-display-table-slot standard-display-table 0 ?\ ))
(add-hook 'eshell-mode-hook #'syd-eshell-remove-fringes-h)
(add-hook 'eshell-mode-hook #'syd-eshell-enable-text-wrapping-h)
(with-eval-after-load 'hide-mode-line
(add-hook 'eshell-mode-hook #'hide-mode-line-mode))
;; Remove hscroll-margin in shells, otherwise you get jumpiness when the
;; cursor comes close to the left/right edges of the window.
(defun syd-eshell-disable-hscroll-margin ()
(setq hscroll-margin 0))
(add-hook 'eshell-mode-hook #'syd-eshell-disable-hscroll-margin))
(set-popup-rule! "^\\*eshell-popup"
:vslot -5 :size 0.35 :select t :modeline nil :quit nil :ttl nil)
(provide 'syd-eshell)

View File

@@ -33,24 +33,168 @@
;; These two are required for evil-collection. ;; These two are required for evil-collection.
(setq evil-want-keybinding nil (setq evil-want-keybinding nil
evil-want-integration t) evil-want-integration t)
:config :config
;; 'M-:' starts off in insert mode, yet initialises with the normal mode ;; 'M-:' starts off in insert mode, yet initialises with the normal mode
;; cursor. Quick fix! }:P ;; cursor. Quick fix! }:P
(add-hook 'minibuffer-setup-hook (add-hook 'minibuffer-setup-hook
#'evil-refresh-cursor) #'evil-refresh-cursor)
;; Unbind 'C-k'. Normally, it inserts digraphs; I have a compose key. It ;; Unbind 'C-k'. Normally, it inserts digraphs; I have a compose key. It
;; often gets in the way of buffers with navigation, e.g. scrolling through ;; often gets in the way of buffers with navigation, e.g. scrolling through
;; shell/REPL history, navigating Vertico completions, etc. ;; shell/REPL history, navigating Vertico completions, etc.
(keymap-set evil-insert-state-map "C-k" nil) (keymap-set evil-insert-state-map "C-k" nil)
;; In imitation of Vim's :mes[sages] command, define an Evil analogue to show
;; the echo area.
(evil-ex-define-cmd "mes[sages]"
#'view-echo-area-messages)
(evil-mode 1)) (evil-mode 1))
(defvar evil-collection-key-blacklist)
;; A large, community-sourced collection of preconfigured Evil-mode ;; A large, community-sourced collection of preconfigured Evil-mode
;; integrations. ;; integrations.
(use-package evil-collection (use-package evil-collection
:after evil :after evil
:defer t
:custom (evil-collection-setup-minibuffer t) :custom (evil-collection-setup-minibuffer t)
:config :config
(evil-collection-init)) (unless noninteractive
(defvar syd-evil-collection-disabled-list
'(anaconda-mode buff-menu calc comint company custom eldoc elisp-mode ert
free-keys helm help image indent kmacro kotlin-mode lispy outline
replace shortdoc simple slime tab-bar)
"A list of `evil-collection' modules to ignore. See
`evil-collection-mode-list' for a list of available options.")
;; We do this ourselves.
(defvar evil-collection-want-unimpaired-p nil)
;; We binds goto-reference on gD and goto-assignments on gA ourselves
(defvar evil-collection-want-find-usages-bindings-p nil)
;; Reduces keybind conflicts between outline-mode and org-mode (which is
;; derived from outline-mode).
(defvar evil-collection-outline-enable-in-minor-mode-p nil)
;; We handle loading evil-collection ourselves
(defvar evil-collection--supported-modes nil)
;; This has to be defined here since evil-collection doesn't autoload its own.
;; It must be updated whenever evil-collection updates theirs. Here's an easy
;; way to update it:
(defvar evil-collection-mode-list
`(2048-game ag alchemist anaconda-mode apropos arc-mode atomic-chrome
auto-package-update beginend bluetooth bm bookmark
(buff-menu "buff-menu") bufler calc calendar cider citre cmake-mode
color-rg comint company compile consult corfu crdt (csv "csv-mode")
(custom cus-edit) cus-theme dape dashboard daemons deadgrep debbugs
debug devdocs dictionary diff-hl diff-mode dired dired-sidebar
disk-usage distel doc-view docker eat ebib ebuku edbi edebug ediff eglot
elpaca ement explain-pause-mode eldoc elfeed elisp-mode elisp-refs
elisp-slime-nav embark emms ,@(if (> emacs-major-version 28) '(emoji))
epa ert eshell eval-sexp-fu evil-mc eww fanyi finder flycheck flymake
forge free-keys geiser ggtags git-timemachine gited gnus go-mode gptel
grep guix hackernews helm help helpful hg-histedit hungry-delete hyrolo
ibuffer (image image-mode) image-dired image+ imenu imenu-list
(indent "indent") indium info ivy js2-mode
,@(if (>= emacs-major-version 30) '(kmacro)) leetcode lispy lms log-edit
log-view lsp-ui-imenu lua-mode kotlin-mode macrostep man
(magit magit-repos magit-submodule) magit-repos magit-section
magit-todos markdown-mode monky mpc mpdel mu4e mu4e-conversation neotree
newsticker notmuch nov omnisharp org org-present org-roam osx-dictionary
outline p4 (package-menu package) pass (pdf pdf-tools) popup proced
prodigy profiler p-search python quickrun racer racket-describe realgud
reftex replace restclient rg ripgrep rjsx-mode robe rtags ruby-mode
scheme scroll-lock selectrum sh-script
,@(if (> emacs-major-version 27) '(shortdoc)) simple simple-mpc slime
sly smerge-mode snake so-long speedbar tab-bar tablist tar-mode telega
(term term ansi-term multi-term) tetris thread tide timer-list
transmission trashed tuareg typescript-mode vc-annotate vc-dir vc-git
vdiff vertico view vlf vterm vundo w3m wdired wgrep which-key
with-editor woman xref xwidget yaml-mode youtube-dl zmusic
(ztree ztree-diff)))
(cl-defun syd-evil-collection-init (module &key disabled-modules)
"Initialise evil-collection-MODULE.
A wrapper for `evil-collection-init' that respects a given list of disabled
modules."
(let ((module* (or (car-safe module) module)))
(unless (memq module* disabled-modules)
(message "Loading evil-collection-%s%s"
module*
(if after-init-time "" " too early! }:("))
(with-demoted-errors "error loading evil-collection: %s"
(evil-collection-init (list module))))))
(defun syd-evil-collection-disable-blacklist-a (fn)
(let (evil-collection-key-blacklist)
(funcall-interactively fn)))
;; Allow binding to ESC.
(advice-add #'evil-collection-vterm-toggle-send-escape
:around #'syd-evil-collection-disable-blacklist-a)
;; These modes belong to packages that Emacs always loads at startup, causing
;; evil-collection and it's co-packages to all load immediately. We avoid
;; this by loading them after evil-collection has first loaded...
(with-eval-after-load 'evil-collection
(require 'syd-prelude)
(require 'syd-keybinds)
;; Don't let evil-collection interfere with certain keys
(setq evil-collection-key-blacklist
(append (list syd-leader-key syd-localleader-key
syd-alt-leader-key)
evil-collection-key-blacklist
;; Reserved for goto definition; lookup docs; eval; eval
;; buffer; movement prefix; movement prefix; escaping };).
'("gd" "K" "gr" "gR" "[" "]" "<escape>")))
(mapc #'syd-evil-collection-init '(comint custom))
(with-eval-after-load 'evil
;; Emacs loads these two packages immediately, at startup, which needlessly
;; convolutes load order for evil-collection-help.
(with-transient-after 'help-mode
(syd-evil-collection-init 'help))
(with-transient-after 'Buffer-menu-mode
(syd-evil-collection-init '(buff-menu "buff-menu")))
(with-transient-after 'calc-mode
(syd-evil-collection-init 'calc))
(with-transient-after 'image-mode
(syd-evil-collection-init 'image))
(with-transient-after 'emacs-lisp-mode
(syd-evil-collection-init 'elisp-mode))
(with-transient-after 'occur-mode
(syd-evil-collection-init 'replace))
(with-transient-after 'indent-rigidly
(syd-evil-collection-init '(indent "indent")))
(when (>= emacs-major-version 30)
(with-transient-after 'kmacro-menu-mode
(syd-evil-collection-init 'kmacro)))
(with-transient-after 'minibuffer-setup-hook
(when evil-collection-setup-minibuffer
(syd-evil-collection-init 'minibuffer)
(evil-collection-minibuffer-insert)))
(with-transient-after 'process-menu-mode
(syd-evil-collection-init '(process-menu simple)))
(with-transient-after 'shortdoc-mode
(syd-evil-collection-init 'shortdoc))
(with-transient-after 'tabulated-list-mode
(syd-evil-collection-init 'tabulated-list))
(with-transient-after 'tab-bar-mode
(syd-evil-collection-init 'tab-bar))
;; HACK: Do this ourselves because evil-collection break's
;; `eval-after-load' load order by loading their target plugin before
;; applying keys. This makes it hard for end-users to overwrite these
;; keybinds with a simple `after!' or `with-eval-after-load'.
(dolist (mode evil-collection-mode-list)
(dolist (req (or (cdr-safe mode) (list mode)))
(with-eval-after-load req
(syd-evil-collection-init
mode
:disabled-modules syd-evil-collection-disabled-list))))))))
;; Tim Pope's famous `surround.vim' for Evil. ;; Tim Pope's famous `surround.vim' for Evil.
(use-package evil-surround (use-package evil-surround

View File

@@ -1,8 +0,0 @@
;;; syd-general.el -*- lexical-binding: t; -*-
(use-package general
:custom (general-use-package-emit-autoloads t))
(require 'general)
(provide 'syd-general)

View File

@@ -1,8 +1,6 @@
;;; syd-keybinds.el -*- lexical-binding: t; -*- ;;; syd-keybinds.el -*- lexical-binding: t; -*-
;;; Universal keybindings, not /too/ tied to any particular packages. ;;; Universal keybindings, not /too/ tied to any particular packages.
(require 'syd-general)
(defvar syd-leader-key "SPC" (defvar syd-leader-key "SPC"
"A prefix key akin to Vim's <Leader>.") "A prefix key akin to Vim's <Leader>.")
@@ -54,9 +52,9 @@ are active.")
(general-override-mode 1)) (general-override-mode 1))
(defvar syd-escape-hook nil (defvar syd-escape-hook nil
"A hook run when C-g is pressed (or ESC in normal mode, for evil users). "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, More specifically, when `syd/escape' is pressed. If any hook returns non-nil,
all hooks after it are ignored.") all hooks after it are ignored.")
;; ;;
@@ -111,6 +109,13 @@ all hooks after it are ignored.")
(global-set-key [remap keyboard-quit] #'syd/escape) (global-set-key [remap keyboard-quit] #'syd/escape)
(general-def
:states 'motion
"/" #'evil-ex-search-forward
"?" #'evil-ex-search-backward
"n" #'evil-ex-search-next
"N" #'evil-ex-search-previous)
;; Buffer ;; Buffer
(require 'syd-buffers) (require 'syd-buffers)
(general-def (general-def
@@ -138,7 +143,7 @@ all hooks after it are ignored.")
"D" `("Delete file" . ,#'syd/delete-this-file) "D" `("Delete file" . ,#'syd/delete-this-file)
"R" `("Move file" . ,#'syd/move-this-file) "R" `("Move file" . ,#'syd/move-this-file)
"C" `("Copy file" . ,#'syd/copy-this-file) "C" `("Copy file" . ,#'syd/copy-this-file)
;; "F" `("Find file under current" . ,#'syd/find-file-under-here) ;; "F" `("Find file under here" . ,#'syd/find-file-under-here)
;; "p" `("Find under Emacs config" . ,#'syd/find-file-under-emacs-user-directory) ;; "p" `("Find under Emacs config" . ,#'syd/find-file-under-emacs-user-directory)
"P" `("Browse Emacs config" . ,#'syd/find-file-in-emacs-user-directory) "P" `("Browse Emacs config" . ,#'syd/find-file-in-emacs-user-directory)
"u" `("Find file as root" . ,#'syd/find-file-as-root) "u" `("Find file as root" . ,#'syd/find-file-as-root)

View File

@@ -11,13 +11,8 @@
(popper-mode 1)) (popper-mode 1))
(use-package doom-popup (use-package doom-popup
;; :after popper :straight (:type git
;; :load-path "/persist/dots/users/crumb/programs/emacs/lib/doom-popup" :host gitlab
;; :straight nil :repo "crumbtoo/doom-popup"))
:straight
(:type git
:host gitlab
:repo "crumbtoo/doom-popup"))
(provide 'syd-popups) (provide 'syd-popups)
;;; syd-popups.el ends here

View File

@@ -7,6 +7,8 @@
;; activated. ;; activated.
(use-package smartparens (use-package smartparens
:hook (on-first-buffer . smartparens-global-mode) :hook (on-first-buffer . smartparens-global-mode)
:commands (sp-pair sp-local-pair sp-with-modes sp-point-in-comment
sp-point-in-string)
:custom :custom
;; Overlays are too distracting and not terribly helpful. show-parens does ;; Overlays are too distracting and not terribly helpful. show-parens does
;; this for us already (and is faster), so... ;; this for us already (and is faster), so...

View File

@@ -17,14 +17,34 @@
;; probably not what you want;" I personally don't see it, and it's ;; probably not what you want;" I personally don't see it, and it's
;; usually what I want. ;; usually what I want.
(vc-follow-symlinks t) (vc-follow-symlinks t)
;; Log native-compiler warnings, but don't display the ;; Log native-compiler warnings, but don't display the
;; buffer. Most of the warnings are "`X' is not known to ;; buffer. Most of the warnings are "`X' is not known to
;; be defined" which are typically nothing worth concerning. ;; be defined" which are typically nothing worth concerning.
(native-comp-async-report-warnings-errors 'silent)) (native-comp-async-report-warnings-errors 'silent)
;; Don't recenter the view unless >10 lines are scrolled off-screen
;; in a single movement.
(scroll-conservatively 10))
:config :config
;; Disable the menu bar, scroll bar, and tool bar. ;; Disable the menu bar, scroll bar, and tool bar.
(menu-bar-mode -1) (menu-bar-mode -1)
(scroll-bar-mode -1) (scroll-bar-mode -1)
(tool-bar-mode -1)) (tool-bar-mode -1))
(use-package persp-mode
:unless noninteractive
:commands persp-switch-to-buffer
:hook (on-init-ui . persp-mode)
:config
(setq persp-autokill-buffer-on-remove 'kill-weak
persp-reset-windows-on-nil-window-conf nil
persp-nil-hidden t
persp-auto-save-fname "autosave"
persp-save-dir (concat syd-data-dir "workspaces/")
persp-set-last-persp-for-new-frames t
persp-switch-to-added-buffer nil
persp-kill-foreign-buffer-behaviour 'kill
persp-remove-buffers-from-nil-persp-behaviour nil
persp-auto-resume-time -1 ; Don't auto-load on startup
persp-auto-save-opt (if noninteractive 0 1)))
(provide 'syd-ui) (provide 'syd-ui)