From f53f58df5a4778d4056f73f393ad2653c3b98731 Mon Sep 17 00:00:00 2001 From: Madeleine Sydney Date: Tue, 11 Feb 2025 11:36:20 -0700 Subject: [PATCH] Commit dicipline fail --- README.org | 2 + users/crumb/files.nix | 1 + users/crumb/programs/emacs/lib/syd-general.el | 102 +++++++++++ .../crumb/programs/emacs/lib/syd-lisp-lib.el | 24 ++- users/crumb/programs/emacs/lib/syd-prelude.el | 114 +++++++++---- users/crumb/programs/emacs/lib/syd-prose.el | 27 +++ .../emacs/modules/lang/syd-lang-emacs-lisp.el | 11 ++ .../crumb/programs/emacs/modules/syd-evil.el | 1 + .../programs/emacs/modules/syd-keybinds.el | 104 +----------- users/crumb/programs/emacs/modules/syd-org.el | 160 +++++++++++++++++- users/crumb/programs/emacs/projects | 2 + 11 files changed, 412 insertions(+), 136 deletions(-) create mode 100644 users/crumb/programs/emacs/lib/syd-prose.el create mode 100644 users/crumb/programs/emacs/projects diff --git a/README.org b/README.org index b3394e0..c8901af 100755 --- a/README.org +++ b/README.org @@ -639,6 +639,8 @@ Beloved Faye's Wishsys is an incredibly impressive 3-kloc NixOS config with seve - [cite:@ayats2024dropping] - [cite:@zaynetdinov2024you] - [cite:@schafer2017advanced] +- [cite:@bosio2023beautifying] +- [cite:@zamboni2018beautifying] - [[https://prelude.emacsredux.com/en/stable/][Emacs Prelude]] - [[https://github.com/doomemacs/doomemacs][Doom Emacs]] - [[https://cce.whatthefuck.computer/cce][Ryan Rix's Complete Computing Environment]] diff --git a/users/crumb/files.nix b/users/crumb/files.nix index f52952f..ab10e9c 100755 --- a/users/crumb/files.nix +++ b/users/crumb/files.nix @@ -16,6 +16,7 @@ in { "Pictures" "Documents" "Videos" + "src" ".ssh" { directory = ".local/share/Steam"; diff --git a/users/crumb/programs/emacs/lib/syd-general.el b/users/crumb/programs/emacs/lib/syd-general.el index 17d266d..e4cd031 100644 --- a/users/crumb/programs/emacs/lib/syd-general.el +++ b/users/crumb/programs/emacs/lib/syd-general.el @@ -5,4 +5,106 @@ (require 'general) +(defvar syd-leader-key "SPC" + "A prefix key akin to Vim's .") + +(defvar syd-localleader-key "SPC m" + "A prefix key akin to Vim's .") + +(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) diff --git a/users/crumb/programs/emacs/lib/syd-lisp-lib.el b/users/crumb/programs/emacs/lib/syd-lisp-lib.el index 17f2165..93aa03e 100644 --- a/users/crumb/programs/emacs/lib/syd-lisp-lib.el +++ b/users/crumb/programs/emacs/lib/syd-lisp-lib.el @@ -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))) diff --git a/users/crumb/programs/emacs/lib/syd-prelude.el b/users/crumb/programs/emacs/lib/syd-prelude.el index 01dcc66..8b4cd81 100644 --- a/users/crumb/programs/emacs/lib/syd-prelude.el +++ b/users/crumb/programs/emacs/lib/syd-prelude.el @@ -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) diff --git a/users/crumb/programs/emacs/lib/syd-prose.el b/users/crumb/programs/emacs/lib/syd-prose.el new file mode 100644 index 0000000..967d627 --- /dev/null +++ b/users/crumb/programs/emacs/lib/syd-prose.el @@ -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) diff --git a/users/crumb/programs/emacs/modules/lang/syd-lang-emacs-lisp.el b/users/crumb/programs/emacs/modules/lang/syd-lang-emacs-lisp.el index 1dbcff3..f0aee6d 100644 --- a/users/crumb/programs/emacs/modules/lang/syd-lang-emacs-lisp.el +++ b/users/crumb/programs/emacs/modules/lang/syd-lang-emacs-lisp.el @@ -91,4 +91,15 @@ to a pop up buffer." (use-package rainbow-delimiters :hook (emacs-lisp-mode . rainbow-delimiters-mode)) +(use-package macrostep + :commands (macrostep-expand) + :init + (general-define-key + :keymaps 'emacs-lisp-mode-map + :states '(normal visual motion emacs insert) + :major-modes t + :prefix syd-localleader-key + :non-normal-prefix syd-alt-localleader-key + "m" #'macrostep-expand)) + (provide 'syd-lang-emacs-lisp) diff --git a/users/crumb/programs/emacs/modules/syd-evil.el b/users/crumb/programs/emacs/modules/syd-evil.el index 03bd8ce..e111436 100755 --- a/users/crumb/programs/emacs/modules/syd-evil.el +++ b/users/crumb/programs/emacs/modules/syd-evil.el @@ -9,6 +9,7 @@ :preface (setq evil-want-minibuffer t evil-move-beyond-eol t + evil-respect-visual-line-mode t evil-vsplit-window-right t evil-ex-search-vim-style-regexp t evil-want-Y-yank-to-eol t diff --git a/users/crumb/programs/emacs/modules/syd-keybinds.el b/users/crumb/programs/emacs/modules/syd-keybinds.el index 12f8aff..40f1be6 100755 --- a/users/crumb/programs/emacs/modules/syd-keybinds.el +++ b/users/crumb/programs/emacs/modules/syd-keybinds.el @@ -1,110 +1,10 @@ ;;; syd-keybinds.el -*- lexical-binding: t; -*- ;;; Universal keybindings, not /too/ tied to any particular packages. -(defvar syd-leader-key "SPC" - "A prefix key akin to Vim's .") - -(defvar syd-localleader-key "SPC m" - "A prefix key akin to Vim's .") - -(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)) +(require 'syd-general) (defun syd-keybinds-initialise () - (syd--initialise-leader) + (syd-initialise-leader) (global-set-key [remap keyboard-quit] #'syd/escape) diff --git a/users/crumb/programs/emacs/modules/syd-org.el b/users/crumb/programs/emacs/modules/syd-org.el index 9f74d39..e474dfa 100755 --- a/users/crumb/programs/emacs/modules/syd-org.el +++ b/users/crumb/programs/emacs/modules/syd-org.el @@ -1,10 +1,127 @@ ;;; syd-org.el -*- lexical-binding: t; -*- +(require 'syd-prose) + +(defun syd-org--init-hacks-h () + ;; Open file links in current window, rather than new ones + (setf (alist-get 'file org-link-frame-setup) #'find-file) + ;; Open directory links in dired + (add-to-list 'org-file-apps '(directory . emacs)) + (add-to-list 'org-file-apps '(remote . emacs)) + + (defun syd-org--restart-mode-h () + "Restart `org-mode', but only once." + (syd-quietly (org-mode-restart)) + (setq org-agenda-new-buffers + (delq (current-buffer) + org-agenda-new-buffers)) + (run-hooks 'find-file-hook)) + + (defun syd-org-exclude-agenda-buffers-from-workspace-h () + "Don't associate temporary agenda buffers with current workspace." + (when (and org-agenda-new-buffers + (bound-and-true-p persp-mode) + (not org-agenda-sticky)) + (let (persp-autokill-buffer-on-remove) + (persp-remove-buffer org-agenda-new-buffers + (get-current-persp) + nil)))) + (add-hook 'org-agenda-finalize-hook + #'syd-org-exclude-agenda-buffers-from-workspace-h) + + (defun syd-org--restart-mode-before-indirect-buffer-a (&optional buffer _) + "Restart `org-mode' in buffers in which the mode has been deferred (see +`syd-org-defer-mode-in-agenda-buffers-h') before they become the base buffer for an +indirect org-cpature buffer. This ensures that the buffer is fully functional +not only when the *user* visits it, but also when org-capture interacts with it +via an indirect buffer." + (with-current-buffer (or buffer (current-buffer)) + (when (memq #'syd-org--restart-mode-h on-switch-buffer-hook) + (syd-org--restart-mode-h)))) + (advice-add #'org-capture-get-indirect-buffer + :before #'syd-org--restart-mode-before-indirect-buffer-a) + + (defvar recentf-exclude) + (defun syd-org--optimize-backgrounded-agenda-buffers-a (fn file) + "Disable `org-mode's startup processes for temporary agenda buffers. + +Prevents recentf pollution as well. However, if the user tries to visit one of +these buffers they'll see a gimped, half-broken org buffer, so to avoid that, +install a hook to restart `org-mode' when they're switched to so they can grow +up to be fully-fledged org-mode buffers." + (if-let* ((buf (org-find-base-buffer-visiting file))) + buf + (let ((recentf-exclude '(always)) + ;; (doom-inhibit-large-file-detection t) + ;; (doom-inhibit-local-var-hooks t) + (org-inhibit-startup t) + vc-handled-backends + enable-local-variables + find-file-hook) + (when-let ((buf (delay-mode-hooks (funcall fn file)))) + (with-current-buffer buf + (add-hook 'on-switch-buffer-hook #'syd-org--restart-mode-h + nil 'local)) + buf)))) + (advice-add #'org-get-agenda-file-buffer + :around #'syd-org--optimize-backgrounded-agenda-buffers-a) + + (defun syd-org--fix-inconsistent-uuidgen-case-a (uuid) + "Ensure uuidgen is always lowercase (consistent) regardless of system. +See https://lists.gnu.org/archive/html/emacs-orgmode/2019-07/msg00081.html." + :filter-return #'org-id-new + (if (eq org-id-method 'uuid) + (downcase uuid) + uuid)) + (advice-add #'org-id-new + :filter-return #'syd-org--fix-inconsistent-uuidgen-case-a)) + +(defun syd-org-init-faces () + (let ((headline `(:weight bold))) + (custom-theme-set-faces + 'user + ;; It is important that the `org-indent' face uses a fixed-pitch font, lest + ;; e.g. multi-line bullets appear misaligned. + '(org-indent ((t (:inherit (org-hide fixed-pitch))))) + ;; Must be fixed-pitch; `[ ]` and `[X]' should be the same width. + '(org-checkbox ((t (:inherit fixed-pitch)))) + '(org-drawer ((t (:inherit (font-lock-comment-face fixed-pitch))))) + '(org-property-value ((t (:inherit fixed-pitch))))))) + +(defun syd-org-init-keybinds () + (general-def + :keymaps 'org-mode-map + :states '(insert emacs) + [tab] #'org-cycle + [C-M-return] #'org-insert-subheading) + (general-def + :prefix-map 'syd-org-mode-links-map + "l" #'org-insert-link) + (general-define-key + :keymaps 'org-mode-map + :states '(normal visual motion emacs insert) + :major-modes t + :prefix syd-localleader-key + :non-normal-prefix syd-alt-localleader-key + "m" `("Org-roam" . ,org-roam-mode-map) + "." #'consult-org-heading + "/" #'consult-org-agenda + "@" #'org-cite-insert + "e" #'org-export-dispatch + "f" #'org-footnote-action + "h" #'org-toggle-heading + "i" #'org-toggle-item + "I" #'org-id-get-create + "k" #'org-babel-remove-result + "l" `("Links" . ,syd-org-mode-links-map))) + (use-package org :defer-incrementally calendar find-func format-spec org-macs org-compat org-faces org-entities org-list org-pcomplete org-src org-footnote org-macro ob org org-agenda org-capture + :custom ((org-startup-folded 'content) + (org-directory "~/org")) :preface (defvar org-modules '(;; ol-w3m @@ -17,7 +134,48 @@ ;; ol-mhe ;; ol-rmail ;; ol-eww - ))) + )) + :config + (syd-add-hook 'org-mode-hook + #'org-indent-mode + #'syd-prose-mode) + (syd-org-init-faces) + (syd-org-init-keybinds)) + +(defun syd-org--init-roam-keybinds () + ) + +(use-package org-roam + :hook (org-load . syd-org-init-roam-h) + :commands (org-roam-buffer-toggle-display + org-roam-dailies-find-date + org-roam-dailies-find-today + org-roam-dailies-find-tomorrow + org-roam-dailies-find-yesterday) + :init (progn (syd-org--init-roam-keybinds) + (syd-load-packages-incrementally + '(ansi-color dash f rx seq magit-section emacsql))) + :custom ((org-roam-directory org-directory) + (org-roam-db-location (file-name-concat syd-data-dir + "org-roam.db")) + ;; Make org-roam buffer sticky; i.e. don't replace it when opening a + ;; file with an *-other-window command. + (org-roam-buffer-window-parameters '((no-delete-other-windows . t))) + (org-roam-completion-everywhere t)) + :config + (defun syd-org-init-roam-h () + "Setup `org-roam' but don't immediately initialize its database. +Instead, initialize it when it will be actually needed." + (cl-letf (((symbol-function #'org-roam-db-sync) #'ignore)) + (org-roam-db-autosync-enable))) + (defun syd-org-roam-try-init-db-a (&rest _) + "Try to initialize org-roam database at the last possible safe moment. +In case of failure, fail gracefully." + (message "Initializing org-roam database...") + (advice-remove 'org-roam-db-query #'syd-org-roam-try-init-db-a) + (org-roam-db-sync)) + (advice-add #'org-roam-db-query + :before #'syd-org-roam-try-init-db-a)) (provide 'syd-org) ;;; syd-org.el ends here diff --git a/users/crumb/programs/emacs/projects b/users/crumb/programs/emacs/projects new file mode 100644 index 0000000..518f296 --- /dev/null +++ b/users/crumb/programs/emacs/projects @@ -0,0 +1,2 @@ +;;; -*- lisp-data -*- +(("/persist/dots/"))