|
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: