]> git.eshelyaron.com Git - sweep.git/commitdiff
ADDED: command for inserting example usage comments
authorEshel Yaron <me@eshelyaron.com>
Tue, 30 May 2023 19:29:34 +0000 (22:29 +0300)
committerEshel Yaron <me@eshelyaron.com>
Tue, 30 May 2023 19:29:34 +0000 (22:29 +0300)
* sweeprolog.el (sweeprolog-top-level-example-mode): New minor mode.
(sweeprolog-make-example-usage-comment): New command.
(sweeprolog-mode-map): Bind it.

* README.org (Example Usage Comments): New section.

README.org
sweeprolog.el

index 286463297a45ccb1e21baec8127fcb272bd0c5c4..6d43662cd542255561cd8fa2f50268ce9d5f135d 100644 (file)
@@ -1511,6 +1511,42 @@ documented in [[info:emacs#Text][Commands for Human Languages]], which see.
 For more information about =PlDoc= and source documentation in
 SWI-Prolog, see [[https://www.swi-prolog.org/pldoc/doc_for?object=section(%27packages/pldoc.html%27)][the PlDoc manual]].
 
+** Example Usage Comments
+:PROPERTIES:
+:CUSTOM_ID: usage-comments
+:DESCRIPTION: Commands for inserting comments that show example usage of your code
+:ALT_TITLE: Usage Comments
+:END:
+
+Beyond documenting your code with =PlDoc= comments as described in
+[[#sweeprolog-pldoc][Documenting Predicates]], you might want to have comments in your source
+code that shows example usage of some predicate.  Creating such
+comments usually involves posting queries in a Prolog top-level,
+copying the queries and their results into the relevant source code
+buffer, and formatting them as comments.  Sweep provides the following
+command to streamline this process:
+
+#+FINDEX: sweeprolog-make-example-usage-comment
+- Key: C-c C-% (sweeprolog-make-example-usage-comment) :: Start a
+  new top-level for recording example usage.  When you finish
+  interacting with the top-level its contents are formatted as a
+  comment in the buffer and position where you invoked this command.
+
+The command ~sweeprolog-make-example-usage-comment~, bound to ~C-c
+C-%~ in ~sweeprolog-mode~ buffers, creates and switches to a new
+top-level buffer for recording example usage that you want to
+demonstrate.  The /example usage top-level/ is a regular top-level
+buffer (see [[*The Prolog Top-Level][The Prolog Top-Level]]), except that it's tied to the
+specific position in the source buffer where you invoke this command.
+You can post queries in the example usage top-level and edit it
+freely, then type ~C-c C-q~ in to quit the top-level buffer and format
+its contents as a comment in the source buffer.
+
+You can have multiple example usage top-levels for different parts of
+your code at the same time.  To display the source position where you
+created a certain usage example top-level buffer by, type ~C-c C-b~ in
+that buffer.
+
 ** Displaying Predicate Documentation
 :PROPERTIES:
 :CUSTOM_ID: eldoc-integration
index c90c30da069fec81b57c63bbe4888da2ccf7a259..240d26404f68a307abd93c059da0e009d5f3eddc 100644 (file)
@@ -448,6 +448,7 @@ use `autoload/2' for all added directives."
                     #'sweeprolog-show-diagnostics
                   #'flymake-show-diagnostics-buffer))
     (define-key map (kbd "C-c C-&") #'sweeprolog-async-goal)
+    (define-key map (kbd "C-c C-%") #'sweeprolog-make-example-usage-comment)
     (define-key map (kbd "C-c C--") #'sweeprolog-decrement-numbered-variables)
     (define-key map (kbd "C-c C-+") #'sweeprolog-increment-numbered-variables)
     (define-key map (kbd "C-M-^")   #'kill-backward-up-list)
@@ -518,6 +519,13 @@ use `autoload/2' for all added directives."
     map)
   "Keymap for moving to next hole with TAB.")
 
+(defvar sweeprolog-top-level-example-mode-map
+  (let ((map (make-sparse-keymap)))
+    (define-key map (kbd "C-c C-b") #'sweeprolog-top-level-example-display-source)
+    (define-key map (kbd "C-c C-q") #'sweeprolog-top-level-example-done)
+    map)
+  "Keymap for example top-level buffer.")
+
 ;;;; Menu bar
 
 (easy-menu-define sweeprolog-menu (list sweeprolog-mode-map
@@ -605,6 +613,8 @@ use `autoload/2' for all added directives."
 (defvar-local sweeprolog-top-level-thread-id nil
   "Prolog top-level thread ID corresponding to this buffer.")
 
+(defvar-local sweeprolog-top-level-example-marker nil)
+
 (defvar-local sweeprolog--buffer-last-modified-time nil)
 
 (defvar-local sweeprolog--buffer-modified nil)
@@ -6433,6 +6443,75 @@ Return nil if POS is not the beginning of a macro invocation."
   (unless (sweeprolog-expand-macro-at-pos point)
     (user-error "No macro invocation at point")))
 
+(define-minor-mode sweeprolog-top-level-example-mode
+  "Minor mode for example top-level sessions.
+This mode is enabled in top-level buffers created by
+\\[sweeprolog-make-example-usage-comment]."
+  :lighter " Example"
+  :group 'sweeprolog)
+
+(defun sweeprolog-top-level-example-display-source ()
+  "Pop to the source position where this example session was started.
+This is the position where
+`sweeprolog-make-example-usage-comment' was invoked to create
+the current top-level buffer, and where
+\\[sweeprolog-top-level-example-done] inserts its contents of as
+a comment."
+  (interactive "" sweeprolog-top-level-mode)
+  (unless sweeprolog-top-level-example-mode
+    (user-error "Not in an example top-level session"))
+  (let ((source-buffer (marker-buffer sweeprolog-top-level-example-marker)))
+    (unless (buffer-live-p source-buffer)
+      (user-error "Source buffer for this example session no longer alive"))
+    (let ((marker sweeprolog-top-level-example-marker))
+      (display-buffer source-buffer)
+      (goto-char marker))))
+
+(defun sweeprolog-top-level-example-done ()
+  "Finalize the current example top-level session.
+This kills the current top-level buffer and inserts its contents
+as a comment in the source location where you invoked
+`sweeprolog-make-example-usage-comment' to create it."
+  (interactive "" sweeprolog-top-level-mode)
+  (unless sweeprolog-top-level-example-mode
+    (user-error "Not in an example top-level session"))
+  (let ((source-buffer (marker-buffer sweeprolog-top-level-example-marker)))
+    (unless (buffer-live-p source-buffer)
+      (user-error "Source buffer for this example session no longer alive"))
+    (let ((top-level-buffer (current-buffer))
+          (example (replace-regexp-in-string
+                    (rx "?- " eos) ""
+                    (string-replace
+                     "\n\n" "\n"
+                     (buffer-substring-no-properties (point-min)
+                                                     (point-max)))))
+          (marker sweeprolog-top-level-example-marker))
+      (pop-to-buffer source-buffer)
+      (unless (string-empty-p example)
+        (save-excursion
+          (goto-char marker)
+          (insert example)
+          (comment-region marker (point))))
+      (delete-process (get-buffer-process top-level-buffer))
+      (kill-buffer top-level-buffer))))
+
+(defun sweeprolog-make-example-usage-comment (point)
+  "Start a top-level and record it as a comment at POINT.
+This creates a new example top-level buffer where you can perform
+queries in this top-level as usual.  Use
+\\<sweeprolog-top-level-example-mode-map>\\[sweeprolog-top-level-example-done]
+in the example top-level buffer to finish and format the session
+as a comment in the source buffer at starting at POINT."
+  (interactive "d" sweeprolog-mode)
+  (let ((marker (copy-marker point))
+        (buffer (sweeprolog-top-level-buffer (generate-new-buffer-name
+                                              "*Example Session*"))))
+    (pop-to-buffer buffer)
+    (setq sweeprolog-top-level-example-marker marker
+          header-line-format (substitute-command-keys
+                              (format "`\\<sweeprolog-top-level-example-mode-map>\\[sweeprolog-top-level-example-done]' to quit and write contents as a comment in buffer %s" (buffer-name (marker-buffer marker)))))
+    (sweeprolog-top-level-example-mode)))
+
 ;;;; Footer
 
 (provide 'sweeprolog)