diff options
author | Sean Whitton <spwhitton@spwhitton.name> | 2023-02-13 14:24:18 -0700 |
---|---|---|
committer | Sean Whitton <spwhitton@spwhitton.name> | 2023-02-13 14:24:22 -0700 |
commit | f660ee8a08a628635836a4cc376c66f24d24d317 (patch) | |
tree | 3b9515f06a79cefa5d00d3439ff8c50001acc20a /.emacs.d | |
parent | e39435faa5c4941f4f3b6a31ad433725a9c226d2 (diff) | |
download | dotfiles-f660ee8a08a628635836a4cc376c66f24d24d317.tar.gz |
use *scratch* for text notes too, enabling us to drop *notes*
Diffstat (limited to '.emacs.d')
-rw-r--r-- | .emacs.d/init.el | 140 |
1 files changed, 120 insertions, 20 deletions
diff --git a/.emacs.d/init.el b/.emacs.d/init.el index 040a2d36..fbad25e6 100644 --- a/.emacs.d/init.el +++ b/.emacs.d/init.el @@ -408,8 +408,8 @@ windows side-by-side in the frame." '(rcirc-track-minor-mode t) '(read-mail-command 'gnus) '(read-minibuffer-restore-windows nil) - '(remember-data-file "~/local/tmp/emacs-notes") - '(remember-notes-initial-major-mode 'text-mode) + '(remember-data-file "~/local/tmp/scratch") + '(remember-notes-buffer-name "*scratch*") '(require-final-newline t) '(save-interprogram-paste-before-kill nil nil nil "See <https://debbugs.gnu.org/53728>.") '(save-place-mode t nil nil "If quitting Emacs is slow, set `save-place-forget-unreadable-files' to nil.") @@ -613,24 +613,9 @@ that's something we can determine.") (cons macro (if (listp item) item (list item))))))) -;;;; The *scratch* and *notes* buffers +;;;; The *scratch* buffer -;; We want Paredit in *scratch* but then it is not practical to use it for -;; temporarily holding other plain text. So drop "notes you don't want to -;; save" from `initial-scratch-message' (using the Emacs 20 text as a base). -;; -;; We have C-x g or just creating new buffers for holding other plain text. -;; The main difference between these is that the former starts in `text-mode'. -(setq initial-scratch-message - ";; This buffer is for Lisp evaluation. -;; If you want to create a file, visit that file with \\[find-file], -;; then enter the text in that file\\='s own buffer.\n\n") - -;; These use `pop-to-buffer-same-window', so obey `display-buffer-alist'. -;; -;; Unlike ~/doc/howm/refile.org and C-c c c, *notes* does not require ~/doc/ -;; checked out. And we get one per machine, which can be convenient. -(global-set-key "\C-xg" #'remember-notes) +;; This uses `pop-to-buffer-same-window' and so obeys `display-buffer-alist'. (global-set-key "\C-xl" #'scratch-buffer) (defun spw/eval-print-last-sexp (orig-fun &rest args) @@ -653,6 +638,35 @@ that's something we can determine.") xscheme-send-previous-expression)) (advice-add cmd :around #'spw/eval-print-last-sexp)) +;;; Persistent *scratch*, for the primary daemon only, to avoid conflicts. +;;; Unlike ~/doc/howm/refile.org and C-c c c, this does not require ~/doc/ +;;; checked out. And we get one per machine, which can be convenient. +;;; +;;; We used to have a separate *notes* without Paredit and in `text-mode'. +;;; But using one buffer for both Lisp evaluation and rough notes means that +;;; we can have a single i3/Sway binding for both purposes. +;;; If another major mode is really required, can just create a new buffer. +;;; This relies for its usability on `spw/scratch-paredit-mode'. + +(defun spw/remember-notes-setup () + (when (zerop (buffer-size)) + ;; `after-init-hook' is early enough that `initial-scratch-message' would + ;; be inserted for us by `command-line-1', but this is simpler given that + ;; we have to advise `get-scratch-buffer-create' too. + (insert (substitute-command-keys initial-scratch-message)) + (set-buffer-modified-p nil)) + (setq default-directory (expand-file-name "~/"))) +(spw/feature-add-hook spw/remember-notes-setup + (remember remember-notes-mode-hook)) + +(defun spw/hijack-scratch () + ;; Switch such that right after startup 'q' takes us to *scratch*, as usual. + (switch-to-buffer (remember-notes))) + +(unless (stringp (daemonp)) + (add-hook 'after-init-hook #'spw/hijack-scratch) + (advice-add 'get-scratch-buffer-create :override #'remember-notes)) + ;;; Something like IELM's `ielm-change-working-buffer', the key feature which ;;; distinguishes IELM from both `lisp-interaction-mode' and Eshell. Thanks ;;; to this, and Eshell, I don't ever need IELM. @@ -4429,7 +4443,7 @@ likely to keep parentheses balanced." (spw/feature-add-hook enable-paredit-mode (nil lisp-data-mode-hook) (nil emacs-lisp-mode-hook) - (nil lisp-interaction-mode-hook) (nil eval-expression-minibuffer-setup-hook) + (nil eval-expression-minibuffer-setup-hook) scheme (xscheme xscheme-start-hook) slime-repl) (diminish 'paredit-mode) @@ -4517,6 +4531,92 @@ likely to keep parentheses balanced." (advice-add 'paredit-insert-comment :after #'spw/paredit-insert-comment-before-defun) +;;; Spw/Scratch-Paredit + +(defun spw/scratch-paredit-in-lisp-p () + "Does point's paragraph look to be within a defun?" + (or + ;; Is point at an empty paragraph, ready to start typing it? Assume Lisp. + (save-excursion + (goto-char (pos-bol 0)) + (looking-at (rx (| (: buffer-start (= 2 (* blank) ?\n)) + (: (= 2 (* blank) ?\n) (* blank) (| ?\n buffer-end)) + (: (* blank) ?\n (* blank) buffer-end))))) + ;; This code attempts to classify non-empty paragraphs. + (save-excursion + ;; Unless we're already right before a paragraph, skip backwards into the + ;; previous paragraph. + (unless (looking-at "[[:space:]]*\n[[:space:]]*[^[:space:]\n]+") + (skip-chars-backward "[:space:]\n")) + (catch 'done + (while t + ;; Go back to the start of the paragraph. + (re-search-backward "\\`\\|^\\s-*$" nil t) + ;; Examine the syntax of the first character of the paragraph. + ;; If it's whitespace, we need to go back and check the previous + ;; paragraph, to handle multiple paragraphs within a defun. + (let ((syn + (char-syntax + (char-after + ;; (1+ point) unless at end of buffer or on first line of a + ;; paragraph beginning right at the beginning of the buffer. + (and (not (eobp)) + (not (and (bobp) + (looking-at "[[:space:]]*[^[:space:]\n]"))) + (1+ (point))))))) + (cond ((bobp) (throw 'done (eq syn ?\())) + ((eq syn ?\() (throw 'done t)) + ((not (eq syn ?\s)) (throw 'done nil)))) + (skip-chars-backward "[:space:]\n")))))) + +;; This must come after I've made all my modifications to `paredit-mode-map'. +(defvar spw/scratch-paredit-mode-map + (cl-labels + ((define-keys (keymap into prefix) + (map-keymap + (lambda (event paredit-binding) + ;; `paredit-mode-map' has no parents; otherwise, we should + ;; conditionalise on (eq (lookup-key keymap key) paredit-binding). + (let* ((key (vector event)) + (prefixed (vconcat prefix key))) + (cond ((keymapp paredit-binding) + (let ((map (make-sparse-keymap))) + (define-key into key map) + (define-keys paredit-binding map prefixed))) + ((commandp paredit-binding) + (define-key + into key + (if-let* ((normal-binding (key-binding prefixed)) + (new-binding + (intern + (format "spw/scratch-%s" paredit-binding)))) + (prog1 new-binding + (defalias new-binding + (lambda () + (interactive) + (call-interactively + (if (spw/scratch-paredit-in-lisp-p) + paredit-binding + normal-binding))) + (format + "Like `%s' but for `spw/scratch-paredit-mode'." + paredit-binding))) + paredit-binding)))))) + keymap) + into)) + (with-current-buffer (get-buffer-create "*scratch*") + ;; Handle situation in which Paredit is somehow turned on too. + ;; So long as we are earlier in `minor-mode-map-alist', we can ignore + ;; that, because we bind every key `paredit-mode-map' binds. + (let (paredit-mode spw/scratch-paredit-mode) + (define-keys paredit-mode-map (make-sparse-keymap) [])))) + "Keymap for `spw/scratch-paredit-mode'.") + +(define-minor-mode spw/scratch-paredit-mode + "Less strict Paredit for the *scratch* buffer. +Paredit commands are invoked only when point's paragraph is within a defun.") +(add-hook 'lisp-interaction-mode-hook #'spw/scratch-paredit-mode) + ;;;; Text mode |