master: sb-manual: automatically USE-PAX

melisgl via Sbcl-commits <[email protected]> Mon, 29 Jun 2026 12:19:59 +0000
Newsgroups gmane.lisp.steel-bank.cvs
Message-ID <[email protected]>
The branch "master" has been updated in SBCL:
       via  4499dc643029f4a1ad7386937d5a245019251c1f (commit)
      from  98d37dc3e3ac015e4e28747dbce279f137d78a6c (commit)

- Log -----------------------------------------------------------------
commit 4499dc643029f4a1ad7386937d5a245019251c1f
Author: Gabor Melis <[email protected]>
Date:   Mon Jun 8 18:15:37 2026 +0200

    sb-manual: automatically USE-PAX
    
    Put a magic marker on the value of the variable holding the dummy
    section. Variables with these markers are recognized by PAX (from
    v0.4.12) as lazy sections. So, (DREF @FAKE 'SECTION) works. Then,
    whenever such a reference is RESOLVEd, the function following the
    magic marker is called. That function is USE-PAX in this case.
    
    The net effect of this hack is that PAX:DOCUMENTing a fake section
    will unfake it.
    
    Export USE-PAX for the remaining cases.
---
 contrib/sb-manual/TODO.md           |  2 --
 contrib/sb-manual/docstring.lisp    |  1 +
 contrib/sb-manual/manual.lisp       | 45 +++++++++++++++++--------------
 contrib/sb-manual/markdown.lisp     |  3 ++-
 contrib/sb-manual/package.lisp      |  3 ++-
 contrib/sb-manual/pax.lisp          | 41 +++++++++++++++++++---------
 contrib/sb-manual/sb-manual.texinfo | 53 +++++++++++++++++++++++++++----------
 contrib/sb-manual/texinfo.lisp      |  7 +++--
 8 files changed, 103 insertions(+), 52 deletions(-)

diff --git a/contrib/sb-manual/TODO.md b/contrib/sb-manual/TODO.md
index 21037d0eb..0759ce6d1 100644
--- a/contrib/sb-manual/TODO.md
+++ b/contrib/sb-manual/TODO.md
@@ -16,8 +16,6 @@ image.
 Alternatively, we could have `sb-bsd-sockets/manual.lisp` as a new
 `SB-BSD-SOCKETS-MANUAL` module. Eh.
 
-# SWITCH-TO-PAX automatically?
-
 # How to deal with repetitive package names?
 
 For example, `SB-ALIEN` is `:USE`d by `SB-MANUAL` so that the section
diff --git a/contrib/sb-manual/docstring.lisp b/contrib/sb-manual/docstring.lisp
index 5ad06fb6d..455a38b53 100644
--- a/contrib/sb-manual/docstring.lisp
+++ b/contrib/sb-manual/docstring.lisp
@@ -85,6 +85,7 @@
     ("SB-GRAY" "SB-GRAY")
     ("SB-GROVEL" "SB-GROVEL")
     ("SB-INTROSPECT" "SB-INTROSPECT")
+    ("SB-MANUAL" "SB-MANUAL")
     ("SB-MD5" "SB-MD5")
     ("SB-POSIX" "SB-POSIX")
     ("SB-SEQUENCE" "SB-IMPL")
diff --git a/contrib/sb-manual/manual.lisp b/contrib/sb-manual/manual.lisp
index b3b023296..61e1f549d 100644
--- a/contrib/sb-manual/manual.lisp
+++ b/contrib/sb-manual/manual.lisp
@@ -1,36 +1,41 @@
 (in-package :sb-manual)
 
 (defsection @sb-manual (:title "sb-manual")
-  "The `SB-MANUAL` module has the sections of the SBCL user manual in
-  Lisp variables. The names of the variables (all start with the
-  character `@`) are exported from the `SB-MANUAL` package. Sections
-  are defined with the `DEFSECTION` macro:
+  "The `SB-MANUAL` module has the SBCL user manual in forms
+  mimicking `PAX:DEFSECTION`:
 
       (defsection @example (:title \"Example\")
         \"This is an example, but see the real @SB-MANUAL.\"
         (print function)
         (@subexample section))
 
-  where `DEFSECTION` is a dummy implementation of
-  `PAX:DEFSECTION` (see <https://github.com/melisgl/mgl-pax/>).
-
-  In Slime, `\\\\M-.` on `\"@SB-MANUAL\"`, `\"print\"`, or on
-  `\"@subexample\"` will take you to the respective definition. This
-  makes it easy to navigate the documentation. Normal Lisp definition
-  docstrings and section docstrings reference sections following the
-  usual convention of uppercasing the name. Docstrings are in a subset
-  of Markdown and use very little markup in general, so they are easy
-  to read directly in the source.
+  The names of the variables holding the documentation are exported
+  from the `SB-MANUAL` package. Since sections are basically
+  variables, in Slime, `\\\\M-.` on `\"@SB-MANUAL\"`, `\"print\"`, or
+  on `\"@subexample\"` will take you to the respective definition.
+  This makes it easy to navigate the documentation. Normal Lisp
+  definition docstrings and section docstrings reference sections
+  following the usual convention of uppercasing the name. Docstrings
+  are in a subset of Markdown and use very little markup in general,
+  so they are easy to read directly in the source.
 
   The official manual in Info, HTML and PDF formats is generated via
-  Texinfo generated from these definitions.
-
-  When \\PAX is loaded, the dummy `DEFSECTION` definitions are made
-  real, so that \\PAX can work with them."
+  Texinfo generated from these definitions."
+  (@using-pax section)
   (@browsing-live-with-pax section)
   (@fancy-documentation-with-pax section))
 
-(defsection @browsing-live-with-pax (:title "Browsing Live with PAX")
+(defsection @using-pax (:title "Using \\PAX")
+  "However, `SB-MANUAL::DEFSECTION` is but a dummy implementation of
+  `PAX:DEFSECTION` to avoid a hard dependency on \\PAX.
+
+  See the `MGL-PAX` ASDF:SYSTEM or <https://github.com/melisgl/mgl-pax/>.
+
+  When \\PAX is loaded, the dummy `DEFSECTION` definitions are made
+  real, so that \\PAX can work with them."
+  (use-pax function))
+
+(defsection @browsing-live-with-pax (:title "Browsing Live with \\PAX")
   "With \\PAX, you can browse the manual live. The documentation of this
   feature is available at
   <https://melisgl.github.io/mgl-pax-world/pax-manual.html#MGL-PAX:@BROWSING-LIVE-DOCUMENTATION%20MGL-PAX:SECTION>.
@@ -65,7 +70,7 @@
   Loop, when working on documentation.")
 
 (defsection @fancy-documentation-with-pax
-    (:title "Fancy Documentation with PAX")
+    (:title "Fancy Documentation with \\PAX")
   "\\PAX can generate dead documentation, too. In the SBCL sources,
   `contrib/sb-manual/make-pax-docs.sh` generates the manual in plain
   text, Markdown, PDF, and HTML formats. These differ from those
diff --git a/contrib/sb-manual/markdown.lisp b/contrib/sb-manual/markdown.lisp
index 34ae013a7..1959d1082 100644
--- a/contrib/sb-manual/markdown.lisp
+++ b/contrib/sb-manual/markdown.lisp
@@ -457,7 +457,8 @@
         (typep (symbol-value symbol) (dummy 'section))
         (let ((value (symbol-value symbol)))
           (and (listp value)
-               (eq (first value) 'defsection))))))
+               (listp (first value))
+               (eq (caar value) :%pax-lazy-section))))))
 
 (when (and (not *using-pax*)
            *downcase-uppercase-code*)
diff --git a/contrib/sb-manual/package.lisp b/contrib/sb-manual/package.lisp
index 200fdd96b..02a7fadc0 100644
--- a/contrib/sb-manual/package.lisp
+++ b/contrib/sb-manual/package.lisp
@@ -1,4 +1,5 @@
 (locally (declare (sb-ext:muffle-conditions sb-int:package-at-variance))
   (handler-bind ((sb-int:package-at-variance #'muffle-warning))
     (defpackage :sb-manual
-      (:use :cl :sb-alien))))
+      (:use :cl :sb-alien)
+      (:export #:use-pax))))
diff --git a/contrib/sb-manual/pax.lisp b/contrib/sb-manual/pax.lisp
index d7408632a..aaa292328 100644
--- a/contrib/sb-manual/pax.lisp
+++ b/contrib/sb-manual/pax.lisp
@@ -52,7 +52,24 @@
 (defvar *definition-to-docstring-package*)
 (defvar *package-to-docstring-package*)
 
+(defun resolve-lazy-section (&rest args)
+  (declare (ignore args))
+  (use-pax))
+
 (defun use-pax ()
+  "Ensure that exported variables are `PAX:SECTION`s.
+  It is an error if the `MGL-PAX` library is not loaded.
+
+  Calling this function explicitly is rarely necessary because it is
+  called automatically:
+
+  - when `SB-MANUAL` is loaded, if PAX is present;
+
+  - when `PAX:DOCUMENT` (more precisely, `DREF:LOCATE`) is called on
+    an `SB-MANUAL` section.
+
+  The latter feature requires v0.4.12 of PAX. See the `MGL-PAX`
+  asdf:system."
   (unless *using-pax*
     (assert (find-package '#:mgl-pax))
     ;; Replace dummies with the real symbols.
@@ -75,13 +92,12 @@
       (when (and (char= #\@ (aref (symbol-name symbol) 0))
                  (boundp symbol))
         (let ((value (symbol-value symbol)))
-          (assert (listp value))
-          (assert (eq (first value) 'defsection))
-          (assert (eq (second value) symbol))
+          (assert (and (consp value) (consp (car value ))
+                       (eq (caar value) :%pax-lazy-section)))
           (let ((source-location
                   (sb-int:info :source-location :variable symbol)))
             (eval `(,(read-from-string "pax:defsection")
-                    ,@(subst-extras (rest value))))
+                    ,@(subst-extras (rest (second value)))))
             (setf (sb-int:info :source-location :variable symbol)
                   source-location)))))
     (convert-docstring-package-overrides-to-pax)
@@ -127,26 +143,27 @@
 (defmacro-dummy (defsection pax)
                 (name (&key (package *package*) (export t) title)
                       &body entries)
-  (let ((defsection-form
-          `(defsection ,name (:package ,package :export ,export :title ,title)
-             ,@entries)))
+  (let ((value
+          `((:%pax-lazy-section ,name resolve-lazy-section)
+            (defsection ,name (:package ,package :export ,export :title ,title)
+              ,@entries))))
     `(progn
-       (defparameter ,name ',defsection-form)
+       (defparameter ,name ',value)
        ,@(when export
            `((export ',name :sb-manual))))))
 
 (defun-dummy (section-name :pax) (section)
-  (second section))
+  (second (second section)))
 
 (defun-dummy (section-title :pax) (section)
-  (getf (third section) :title))
+  (getf (third (second section)) :title))
 
 (defun-dummy (section-package :pax) (section)
-  (find-package (getf (third section) :package)))
+  (find-package (getf (third (second section)) :package)))
 
 ;;; This is a list of (NAME LOCATIVE) elements with our dummy DEFSECTION.
 (defun-dummy (section-entries :pax) (section)
-  (nthcdr 3 section))
+  (nthcdr 3 (second section)))
 
 (defun-dummy (xref-name :dref) (xref)
   (first xref))
diff --git a/contrib/sb-manual/sb-manual.texinfo b/contrib/sb-manual/sb-manual.texinfo
index 278f90b04..dc0b27f8d 100644
--- a/contrib/sb-manual/sb-manual.texinfo
+++ b/contrib/sb-manual/sb-manual.texinfo
@@ -4,14 +4,13 @@
 @section sb-manual
 
 @menu
+* Using PAX: using pax.
 * Browsing Live with PAX: browsing live with pax.
 * Fancy Documentation with PAX: fancy documentation with pax.
 @end menu
 
-The @code{sb-manual} module has the sections of the SBCL user manual in
-Lisp variables. The names of the variables (all start with the
-character @code{@@}) are exported from the @code{sb-manual} package. Sections
-are defined with the @code{defsection} macro:
+The @code{sb-manual} module has the SBCL user manual in forms
+mimicking @code{pax:defsection}:
 
 @example
 (defsection @@example (:title "Example")
@@ -20,23 +19,49 @@ are defined with the @code{defsection} macro:
   (@@subexample section))
 @end example
 
-where @code{defsection} is a dummy implementation of
-@code{pax:defsection} (see @url{https://github.com/melisgl/mgl-pax/}).
-
-In Slime, @code{M-.} on @code{"@@SB-MANUAL"}, @code{"print"}, or on
-@code{"@@subexample"} will take you to the respective definition. This
-makes it easy to navigate the documentation. Normal Lisp definition
-docstrings and section docstrings reference sections following the
-usual convention of uppercasing the name. Docstrings are in a subset
-of Markdown and use very little markup in general, so they are easy
-to read directly in the source.
+The names of the variables holding the documentation are exported
+from the @code{sb-manual} package. Since sections are basically
+variables, in Slime, @code{M-.} on @code{"@@SB-MANUAL"}, @code{"print"}, or
+on @code{"@@subexample"} will take you to the respective definition.
+This makes it easy to navigate the documentation. Normal Lisp
+definition docstrings and section docstrings reference sections
+following the usual convention of uppercasing the name. Docstrings
+are in a subset of Markdown and use very little markup in general,
+so they are easy to read directly in the source.
 
 The official manual in Info, HTML and PDF formats is generated via
 Texinfo generated from these definitions.
 
+@node using pax
+@subsection Using PAX
+
+However, @code{sb-manual::defsection} is but a dummy implementation of
+@code{pax:defsection} to avoid a hard dependency on PAX.
+
+See the @code{mgl-pax} @code{asdf:system} or @url{https://github.com/melisgl/mgl-pax/}.
+
 When PAX is loaded, the dummy @code{defsection} definitions are made
 real, so that PAX can work with them.
 
+@anchor{Function sb-manual use-pax}
+@ffindex @sortas{use-pax sb-manual} use-pax [sb-manual]
+@deffn{Function} sb-manual:use-pax
+Ensure that exported variables are @code{pax:section}s.
+It is an error if the @code{mgl-pax} library is not loaded.
+
+Calling this function explicitly is rarely necessary because it is
+called automatically:
+
+@itemize
+@item when @code{sb-manual} is loaded, if @code{pax} is present;
+
+@item when @code{pax:document} (more precisely, @code{dref:locate}) is called on
+  an @code{sb-manual} section.
+@end itemize
+
+The latter feature requires v0.4.12 of @code{pax}. See the @code{mgl-pax}
+asdf:system.
+@end deffn
 @node browsing live with pax
 @subsection Browsing Live with PAX
 
diff --git a/contrib/sb-manual/texinfo.lisp b/contrib/sb-manual/texinfo.lisp
index 0b782cf87..e4575d8de 100644
--- a/contrib/sb-manual/texinfo.lisp
+++ b/contrib/sb-manual/texinfo.lisp
@@ -116,13 +116,16 @@
         (funcall fn))
       (funcall fn)))
 
+(defun remove-markup (string)
+  (remove #\\ string))
+
 ;;; Write the Texinfo for SECTION to *STANDARD-OUTPUT*. When recursing
 ;;; into child sections, if a section is in PAGES, then emit an
 ;;; @include and open a new a file for output.
 (defun emit-texinfo-for-section (section &key pages (depth 0)
                                  top-level-menus-to-file
                                  top-level-contents-to-file)
-  (let ((title (section-title section))
+  (let ((title (remove-markup (section-title section)))
         (entries (section-entries section)))
     (format t "@node ~A~%" (texinfo-node-id section))
     (format t "~A ~A~%~%"
@@ -144,7 +147,7 @@
           (format t "@menu~%"))
         (with-texinfo-to-file top-level-menus-to-file
           (dolist (child-section child-sections)
-            (format t "* ~A: ~A.~%" (section-title child-section)
+            (format t "* ~A: ~A.~%" (remove-markup (section-title child-section))
                     (texinfo-node-id child-section))))
         (unless top-level-menus-to-file
           (format t "@end menu~%~%"))))

-----------------------------------------------------------------------


hooks/post-receive
-- 
SBCL