Warning: this is an htmlized version!
The original is here, and
the conversion rules are here.
;; This file:
;;   https://anggtwu.net/MAXIMA/dim-verbatimbox.lisp.html
;;   https://anggtwu.net/MAXIMA/dim-verbatimbox.lisp
;;           (find-angg "MAXIMA/dim-verbatimbox.lisp")
;; Author: Eduardo Ochs <eduardoochs@gmail.com>
;; Version: 2025dec04
;; License: Public Domain
;;
;; The functions in this file are used _MAINLY_ by Lisptree.
;; This is the version with lots of comments.
;; There are versions with fewer comments in these places:
;;   (find-lisptree "lisptree-middle.lisp" "barematrix")
;;   (find-lisptree "lisptree-middle.lisp" "verbatimbox")
;;   (find-lisptree "lisptree-middle.lisp" "verbatimmatrix")
;;   (find-angg "MAXIMA/2025-displa-tex.lisp" "barematrix")
;;   (find-angg "MAXIMA/2025-displa-tex.lisp" "verbatimbox")
;;   (find-angg "MAXIMA/2025-displa-tex.lisp" "verbatimmatrix")



;; Introduction: `barematrix'
;; ==========================
;; Consider these ways of drawing f(a,b) as a tree:
#|
* (eepitch-maxima)
* (eepitch-kill)
* (eepitch-maxima)
load("dim-verbatimbox.lisp");
o0 : f(a,b);
o1 : matrix        (["f__."], ["|  |"], ["a  b"]);
o2 : barematrix    (["f__."], ["|  |"], ["a  b"]);
o3 : verbatimbox   ( "f__.",   "|  |",   "a  b" );
o4 : verbatimmatrix(["f__."], ["|  |"], ["a  b"]);
[o0, o1, o2, o3, o4];

|#
;; The output of the last line above is:
;;
;; (%i7) [o0, o1, o2, o3, o4];
;;                              ┌      ┐
;;                              │ f__. │   f__.
;;                              │      │                 f__.
;; (%o7)              [f(a, b), │ |  | │,  |  | , f__.,  |  | ]
;;                              │      │          |  |   a  b
;;                              │ a  b │   a  b   a  b
;;                              └      ┘
;;
;; The easiest way to draw `o0' as a tree is to use a one-column
;; matrix in which each line contains a single string - that's `o1'
;; above, and it is ugly because a) it has the outer brackets and b)
;; it has interline spacings. If we're on a recent version of Maxima
;; we can get rid of the outer brackets by using a `barematrix', that
;; uses a trick with `display_matrix_brackets', that was implemented
;; by Robert Dodier and announced in 2025oct12, in this post:
;;
;;   (find-maximamsg "59245670 202510 12" "RDodier: display_matrix_brackets")
;;
;; The code that defines how `barematrix'es are displayed is just this
;; - note that this doesn'tinclude that code that defines how
;; `barematrix'es are LaTeXed:

(setf (get '$barematrix 'dimension) 'dim-$barematrix)

(defun dim-$barematrix (form result)
  (let (($display_matrix_brackets nil))
    (dim-$matrix form result)))



;; `verbatimbox'
;; =============
;; To display the lines without the interline spacings - `o3' above -
;; we can use a `verbatimbox'. The core of `verbatimbox' is the
;; function `verbatimbox-body', defined below, that generates display
;; instructions in the DSL that is described in the comments just
;; about the "defun output" in "displa.lisp". Let me copy them here:
;;
;;   <dimension string> ::= () | (<string element> . <dimension string>)
;;   <string element> ::= character |
;;                     (<column-relative> <row-relative> . <dimension string>) |
;;                     (<drawing function> . args)
;;   <column-relative> ::= <fixnum>
;;   <row-relative>    ::= <fixnum>
;;   <drawing function> ::= D-HBAR | D-VBAR | D-INTEGRALSIGN | ...
;;
;;   When a character appears in a dimension string, it is printed and
;;   the cursor moves forward a single position.  (The variable OLDCOL is
;;   incremented)  When a form with a fixnum car is encountered, the
;;   first two elements of the form are taken to be relative displacements
;;   for OLDCOL and OLDROW.  *** NOTE *** After drawing the cddr of the form,
;;   OLDROW is reset to its original value, but OLDCOL is left in the new
;;   position.  Why this is done is beyond me.  It only appears to complicate
;;   things.
;;
;; Here is a link to the source:
;; (find-maximagitfile "src/displa.lisp" "(defun output ")
;;
;; The result of
#|
* (eepitch-maxima)
* (eepitch-kill)
* (eepitch-maxima)
to_lisp();
  (load "dim-verbatimbox.lisp")
  (verbatimbox-body '("abcd" "ef" "g"))
  (to-maxima)

|#
;; is this list, in which many things look reversed:
;;
;;   ((3 0)
;;    (-2 -2 #\g)
;;    (-4 -1 #\f #\e)
;;    (0 0 #\d #\c #\b #\a))
;;
;; Here's what that list means.
;;
;;   Start at (x,y)=(0,0). Typeset "abcd". Now (x,y)=(4,0).
;;   Move by x+=-4, y=-1. Now (x,y)=(0,-1). Typeset "ef". Now (x,y)=(2,-1).
;;   Move by x+=-2, y=-2. Now (x,y)=(0,-2). Typeset "g". Now (x,y)=(1,-2).
;;   Move by x+=3, y=0. Now (x,y)=(4,0), and we're after the "d" of the "abcd".
;;
;; The function `dim-$verbatimbox' prepends that list to "result",
;; sets the variables `width', `height' and `depth', that are declared
;; "special" in the beginning of "displm.lisp",
;;
;;   (find-maximagitfile "src/displm.lisp")
;;
;; and calls `update-heights'.

(defun verbatimbox-restrings (strings)
  (loop for string in strings
	collect (reverse (exploden string))))

(defun verbatimbox-widths (strings)
  (map 'list #'length (verbatimbox-restrings strings)))

(defun verbatimbox-maxwidth (strings)
  (apply #'max (verbatimbox-widths strings)))

(defun verbatimbox-body (strings &optional (moveup 0))
  (let* ((restrings (verbatimbox-restrings strings))
	 (widths    (verbatimbox-widths strings))
	 (result    `((0 ,moveup ,@(nth 0 restrings))))
	 (maxk      (1- (length strings)))
	 (maxwidth  (verbatimbox-maxwidth strings))
	 (lastwidth (car (last widths))))
    (flet ((restring  (k) (nth k restrings))
	   (prevwidth (k) (nth (1- k) widths)))
      (loop for k from 1 to maxk
	    do (push `(,(- (prevwidth k)) ,(- moveup k) ,@(restring k))
		     result))
      (push `(,(- maxwidth lastwidth) ,moveup) result)
      result)))

(defun dim-$verbatimbox (form result)
  (let* ((strings (rest form)))
    (setq width (verbatimbox-maxwidth strings)
	  height 1
	  depth (1- (length strings))
	  result `(,@(verbatimbox-body strings) ,@result))
    (update-heights height depth)
    result))

(setf (get '$verbatimbox 'dimension)
      'dim-$verbatimbox)



;; `verbatimmatrix'
;; ================
;; Look at the main example again - I added another copy of it below.
;; The "baseline" of a `verbatimbox' is its top line - as in `\vtop'
;; in TeX, and as in `\begin{array}[t]{rcl}...\end{matrix}' in LateX.
;; Sometimes I want something that is centered vertically.
;; Note that here only `verbatimbox' is not centered:
#|
* (eepitch-maxima)
* (eepitch-kill)
* (eepitch-maxima)
load("dim-verbatimbox.lisp");
o0 : f(a,b);
o1 : matrix        (["f__."], ["|  |"], ["a  b"]);
o2 : barematrix    (["f__."], ["|  |"], ["a  b"]);
o3 : verbatimbox   ( "f__.",   "|  |",   "a  b" );
o4 : verbatimmatrix(["f__."], ["|  |"], ["a  b"]);
[o0, o1, o2, o3, o4];

|#
;; (%i7) [o0, o1, o2, o3, o4];
;;                              ┌      ┐
;;                              │ f__. │   f__.
;;                              │      │                 f__.
;; (%o7)              [f(a, b), │ |  | │,  |  | , f__.,  |  | ]
;;                              │      │          |  |   a  b
;;                              │ a  b │   a  b   a  b
;;                              └      ┘
;;
;; `matrix', `barematrix' and `verbatimmatrix' take similar arguments;
;; a `barematrix' is a `matrix' without the outer brackets, and a
;; `verbatimmatrix' is a `barematrix' without the interline spacings.
;; How is `verbatimmatrix' implemented?
;;
;; Instead of implementing `verbatimmatrix'es "in the right way I was
;; super-lazy, and made `dim-$verbatimmatrix' translate its input form
;; in this way,
;;
;;                verbatimmatrix(["f__."], ["|  |"], ["a  b"]);
;;   --> barematrix([verbatimbox( "f__.",   "|  |",   "a  b" )])
;;
;; and display the result. The code is just this:

(defun dim-$verbatimmatrix (form result)
  (let* ((lines (rest form))
	 (strings (map 'list #'second lines))
	 (verbatimbox `(($verbatimbox) ,@strings))
	 (barematrix `(($barematrix) ((mlist) ,verbatimbox))))
    (dim-$barematrix barematrix result)))

(setf (get '$verbatimmatrix 'dimension)
      'dim-$verbatimmatrix)

;; There is no error handling - only the first element in each line is
;; considered, and all the other elements are dropped.



;; LaTeXing
;; ========
;; I decided to not include the code for (La)TeXing `barematrix'es and
;; `verbatimmatrix'es in this file. See:
;;
;;   (find-angg "MAXIMA/2025-displa-tex.lisp" "matrix")
;;   (find-angg "MAXIMA/2025-displa-tex.lisp" "bmatrix")
;;   (find-angg "MAXIMA/2025-displa-tex.lisp" "barematrix")
;;   (find-lisptree "vbtbox.mac")
;;   (find-lisptree "vbtbox.lisp")
;;   (find-lisptree "vbtbox.lua")
;;
;; My code for LaTeXing `barematrix'es and `verbatimmatrix'es is quite
;; simple, but the current version of my code that LaTeXes
;; `verbatimmatrix'es uses CFFI to call Lua (blergh). =(





;; Local Variables:
;; coding:  utf-8-unix
;; End: