branch: externals/literate-scratch commit 00b8f65effe4f2673e6450d70000644b266aa78a Author: Sean Whitton <spwhit...@spwhitton.name> Commit: Sean Whitton <spwhit...@spwhitton.name>
* literate-scratch: Import version 2.2. --- literate-scratch.el | 99 ++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 87 insertions(+), 12 deletions(-) diff --git a/literate-scratch.el b/literate-scratch.el index e869e0fd94..df0685c5b8 100644 --- a/literate-scratch.el +++ b/literate-scratch.el @@ -5,7 +5,7 @@ ;; Author: Sean Whitton <spwhit...@spwhitton.name> ;; Maintainer: Sean Whitton <spwhit...@spwhitton.name> ;; Package-Requires: ((emacs "29.1")) -;; Version: 2.1 +;; Version: 2.2 ;; URL: https://git.spwhitton.name/dotfiles/tree/.emacs.d/site-lisp/literate-scratch.el ;; Keywords: lisp text @@ -49,6 +49,13 @@ ;;; News: +;; Ver 2.2 2025/04/25 Sean Whitton +;; Bug fix: prevent \\`M-j' and \\`M-q' copying the first characters of +;; block comment lines to the beginnings of newly added lines. +;; Bug fix: prevent `comment-indent' indenting block comment lines as +;; though they were Lisp comments beginning with single semicolons. +;; Make \\`TAB' indent block comment lines, copying the preceding block +;; comment line's indentation downwards. ;; Ver 2.1 2025/04/19 Sean Whitton ;; Bug fix: before adding whitespace syntax to the newline character ;; following a block comment line, check we're not on the last line of a @@ -103,12 +110,71 @@ (elisp-mode-syntax-propertize start end)) (defun literate-scratch--indent-line () - ;; `lisp-indent-line' has hardcoded behaviour for lines starting with a - ;; single comment character, which includes the ones we've marked. - (or (save-excursion - (back-to-indentation) - (literate-scratch--comment-start-p (point))) - (lisp-indent-line))) + "`indent-line-function' for `literate-scratch-mode'. +If within a block comment, copy previous line's indentation, +unless at start of paragraph. +Otherwise defer to `lisp-indent-line'." + ;; `lisp-indent-line' has hardcoded behaviour to call `comment-indent' for + ;; lines starting with a single comment character, which includes the ones + ;; we've marked. This is fine for the first lines of block comments; + ;; `comment-search-forward' identifies the line as a comment line and so our + ;; `comment-indent-function' is used properly even in the absence of this + ;; custom `indent-line-function'. But since the fix for Emacs bug#78003, + ;; `comment-indent' will identify subsequent block comment lines as part of + ;; multiline constructs, and defer back to the mode to indent them. + ;; We require a custom `indent-line-function' to break the infinite loop. + (if (literate-scratch--comment-line-p) + (indent-line-to (save-excursion + (literate-scratch--calc-comment-indent))) + (lisp-indent-line))) + +(defun literate-scratch--comment-indent () + "`comment-indent-function' for `literate-scratch-mode'. +If within a block comment, copy previous line's indentation, +unless at start of paragraph. +Otherwise defer to `lisp-comment-indent'." + (if (literate-scratch--comment-line-p) + (literate-scratch--calc-comment-indent) + (lisp-comment-indent))) + +(defun literate-scratch--calc-comment-indent () + (let ((indent (current-indentation))) + (if (or (eq (line-number-at-pos) 1) + (progn (forward-line -1) + (looking-at paragraph-separate))) + indent + (current-indentation)))) + +(defun literate-scratch--fill-paragraph (&optional justify) + "`fill-paragraph-function' for `literate-scratch-mode'. +If within a block comment, perform a text paragraph fill. +Otherwise defer to `lisp-fill-paragraph'." + (if (literate-scratch--comment-line-p) + ;; Just fill as a text paragraph. + ;; M-q is usually bound to `prog-fill-reindent-defun', which calls + ;; `fill-paragraph', which calls us, and then if we simply return nil + ;; the paragraph will be filled as text. + ;; However, Paredit has its own binding for M-q. + ;; Calling `fill-paragraph' like this, instead of just returning nil, + ;; covers both `prog-fill-reindent-defun' and `paredit-reindent-defun'. + (let (fill-paragraph-function) + (fill-paragraph justify)) + (lisp-fill-paragraph justify))) + +(defun literate-scratch--comment-break (&optional soft) + "`comment-line-break-function' for `literate-scratch-mode'. +If within a block comment, perform a simple newline-and-indent. +Otherwise defer to `comment-indent-new-line'." + (if (literate-scratch--comment-line-p) + (let ((indent (current-indentation))) + ;; Insert the newline and clear horizontal space in the same manner as + ;; `default-indent-new-line' and `comment-indent-new-line', which see. + (if soft (insert-and-inherit ?\n) (newline 1)) + (save-excursion (forward-char -1) (delete-horizontal-space)) + (delete-horizontal-space) + ;; Indent to the same level as the previous line. + (indent-to indent)) + (comment-indent-new-line soft))) (defun literate-scratch--put-comment-start (pos &optional force) "Mark POS's line as a block comment line depending on the char(s) at POS. @@ -132,14 +198,20 @@ comment line. Moves point to POS if it is not already there." ;; the two newlines, i.e. at the beginning of an empty line right after ;; the text paragraph, `paredit-in-comment-p' still returns t, and so ;; \\`(' and \\`[' insert only single characters. - (unless (eq (pos-eol) (point-max)) - (put-text-property (pos-eol) (1+ (pos-eol)) 'syntax-table - (eval-when-compile (string-to-syntax "-")))))) + (let ((eol (pos-eol))) + (unless (eq eol (point-max)) + (put-text-property eol (1+ eol) 'syntax-table + (eval-when-compile (string-to-syntax "-"))))))) (defun literate-scratch--comment-start-p (pos) (equal (get-text-property pos 'syntax-table) (eval-when-compile (string-to-syntax "<")))) +(defun literate-scratch--comment-line-p () + (save-excursion + (back-to-indentation) + (literate-scratch--comment-start-p (point)))) + ;;;###autoload (define-derived-mode literate-scratch-mode lisp-interaction-mode "Lisp Interaction" @@ -149,8 +221,11 @@ This makes it easier to interleave paragraphs of plain text with Lisp. You can enable this mode by customising the variable `initial-major-mode' to `literate-scratch-mode'." - (setq-local syntax-propertize-function #'literate-scratch--propertize - indent-line-function #'literate-scratch--indent-line)) + (setq-local syntax-propertize-function #'literate-scratch--propertize + indent-line-function #'literate-scratch--indent-line + comment-indent-function #'literate-scratch--comment-indent + fill-paragraph-function #'literate-scratch--fill-paragraph + comment-line-break-function #'literate-scratch--comment-break)) (provide 'literate-scratch)