summaryrefslogtreecommitdiff
path: root/.emacs.d
diff options
context:
space:
mode:
authorSean Whitton <spwhitton@spwhitton.name>2023-02-13 14:24:18 -0700
committerSean Whitton <spwhitton@spwhitton.name>2023-02-13 14:24:22 -0700
commitf660ee8a08a628635836a4cc376c66f24d24d317 (patch)
tree3b9515f06a79cefa5d00d3439ff8c50001acc20a /.emacs.d
parente39435faa5c4941f4f3b6a31ad433725a9c226d2 (diff)
downloaddotfiles-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.el140
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