branch: externals/literate-scratch
commit c22a15e86acf28da716532c26ba1371574c8e979
Author: Sean Whitton <spwhit...@spwhitton.name>
Commit: Sean Whitton <spwhit...@spwhitton.name>

    * literate-scratch: Import version 1.0
---
 literate-scratch.el | 134 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 134 insertions(+)

diff --git a/literate-scratch.el b/literate-scratch.el
new file mode 100644
index 0000000000..e3ac223bbb
--- /dev/null
+++ b/literate-scratch.el
@@ -0,0 +1,134 @@
+;;; literate-scratch.el --- Lisp Interaction w/ text paragraphs  -*- 
lexical-binding: t -*-
+
+;; Copyright (C) 2023-2024  Free Software Foundation, Inc.
+
+;; Author: Sean Whitton <spwhit...@spwhitton.name>
+;; Maintainer: Sean Whitton <spwhit...@spwhitton.name>
+;; Package-Requires: ((emacs "29.1"))
+;; Version: 1.0
+;; URL: 
https://git.spwhitton.name/dotfiles/tree/.emacs.d/site-lisp/literate-scratch.el
+;; Keywords: lisp text
+
+;; This file is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This file is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this file.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Variant Lisp Interaction mode for easier interleaving of paragraphs of
+;; plain text with Lisp code.  This means you can have
+;;
+;;     ;; This buffer is for text that is not saved ...
+;;     ;; To create a file, visit it with C-x C-f and ...
+;;
+;;     (here is some Lisp)
+;;
+;;     Here is a plain text paragraph )( including some unmatched parentheses.
+;;     Uh oh!  Paredit won't like that.
+;;
+;;     (here is some more Lisp)
+;;
+;; but (e.g.) Paredit won't complain about the unmatched parentheses.
+;; Indeed, the whole plain text paragraph is font-locked as a comment.
+;;
+;; If you use Paredit but want to be able to use *scratch* for both Lisp
+;; interaction and blocks of plain text, then this mode is for you.
+;; Also compatible with the `orgalist-mode' and `orgtbl-mode' minor modes.
+;;
+;; To enable this mode after installing this file, simply customise
+;; `initial-major-mode' to `literate-scratch-mode'.
+
+;;; News:
+
+;; Ver 1.0 2024/06/21 Sean Whitton
+;;     Initial release.
+;;     Thanks to Philip Kaludercic for review.
+
+;;; Code:
+
+(defun literate-scratch--extend (start end)
+  (save-excursion
+    (let ((res1
+          (and (goto-char start)
+               (not (looking-at paragraph-separate))
+               (and-let* ((new (car (bounds-of-thing-at-point 'paragraph))))
+                 (and (< new start)
+                      (setq start new)))))
+         (res2
+          (and (goto-char end)
+               (not (looking-at paragraph-separate))
+               (and-let* ((new (cdr (bounds-of-thing-at-point 'paragraph))))
+                 (and (> new end)
+                      (setq end new))))))
+      (and (or res1 res2)
+          (cons start end)))))
+
+(defun literate-scratch--propertize (start end)
+  (goto-char start)
+  (let ((start (1- start)))
+    (catch 'finish
+      (while t
+       (when-let* ((comment-start (nth 8 (syntax-ppss))))
+         (put-text-property (1- (point)) (point) 'syntax-table
+                            (eval-when-compile
+                              (string-to-syntax "!")))
+         (put-text-property comment-start (point) 'syntax-multiline t))
+       (forward-paragraph 1)
+       (backward-paragraph 1)
+       (unless (> end (point) start)
+         (throw 'finish nil))
+       (setq start (point))
+       (unless
+           (save-excursion
+             (catch 'done
+               (while t
+                 ;; Examine the syntax of the paragraph's first char.
+                 ;; If it's whitespace, we need to check the previous
+                 ;; paragraph, to handle multiple paragraphs within a defun.
+                 (let ((syn
+                        (char-syntax
+                         (char-after
+                          ;; (1+ point) unless at end-of-buf or on first line
+                          ;; of a paragraph beginning right at beg-of-buf.
+                          (if (looking-at "\\`[[:space:]]*[^[:space:]\n]")
+                              (point)
+                            (1+ (point)))))))
+                   (cond ((bobp) (throw 'done (memq syn '(?\( ?<))))
+                         ((memq syn '(?\( ?<)) (throw 'done t))
+                         ((not (eq syn ?\s)) (throw 'done nil))))
+                 (backward-paragraph 1))))
+         (put-text-property (point) (1+ (point)) 'syntax-table
+                            (eval-when-compile
+                              (string-to-syntax "!"))))
+       (forward-paragraph 1))))
+  ;; Now also call the usual `syntax-propertize-function' for this mode.
+  (elisp-mode-syntax-propertize start end))
+
+;;;###autoload
+(define-derived-mode literate-scratch-mode lisp-interaction-mode
+  "Lisp Interaction"
+  "Variant `lisp-interaction-mode' designed for the *scratch* buffer.
+
+Paragraphs that don't start with `(' or `;' are treated as block comments.
+This makes it easier to interleave paragraphs of plain text with Lisp.
+
+You can enable this mode by customizing the variable `initial-major-mode'
+to `literate-scratch-mode'."
+  (add-hook 'syntax-propertize-extend-region-functions
+           #'syntax-propertize-multiline t t)
+  (add-hook 'syntax-propertize-extend-region-functions
+           #'literate-scratch--extend t t)
+  (setq-local syntax-propertize-function #'literate-scratch--propertize))
+
+(provide 'literate-scratch)
+
+;;; literate-scratch.el ends here

Reply via email to