emacs/lisp/calc/calccomp.el
2024-01-02 09:47:10 +08:00

1774 lines
62 KiB
EmacsLisp
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

;;; calccomp.el --- composition functions for Calc -*- lexical-binding:t -*-
;; Copyright (C) 1990-1993, 2001-2024 Free Software Foundation, Inc.
;; Author: David Gillespie <daveg@synaptics.com>
;; This file is part of GNU Emacs.
;; GNU Emacs 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.
;; GNU Emacs 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
;;; Commentary:
;;; Code:
;; This file is autoloaded from calc-ext.el.
(require 'calc-ext)
(require 'calc-macs)
;;; A "composition" has one of the following forms:
;;;
;;; "string" A literal string
;;;
;;; (horiz C1 C2 ...) Horizontally abutted sub-compositions
;;;
;;; (set LEVEL OFF) Set left margin + offset for line-break level
;;; (break LEVEL) A potential line-break point
;;;
;;; (vleft N C1 C2 ...) Vertically stacked, left-justified sub-comps
;;; (vcent N C1 C2 ...) Vertically stacked, centered sub-comps
;;; (vright N C1 C2 ...) Vertically stacked, right-justified sub-comps
;;; N specifies baseline of the stack, 0=top line.
;;;
;;; (supscr C1 C2) Composition C1 with superscript C2
;;; (subscr C1 C2) Composition C1 with subscript C2
;;; (rule X) Horizontal line of X, full width of enclosing comp
;;;
;;; (tag X C) Composition C corresponds to sub-expression X
;; math-comp-just and math-comp-comma-spc are local to
;; math-compose-expr, but are used by math-compose-matrix, which is
;; called by math-compose-expr
(defvar math-comp-just)
(defvar math-comp-comma-spc)
;; math-comp-vector-prec is local to math-compose-expr, but is used by
;; math-compose-matrix and math-compose-rows, which are called by
;; math-compose-expr.
(defvar math-comp-vector-prec)
;; math-comp-left-bracket, math-comp-right-bracket and math-comp-comma are
;; local to math-compose-expr, but are used by math-compose-rows, which is
;; called by math-compose-expr.
(defvar math-comp-left-bracket)
(defvar math-comp-right-bracket)
(defvar math-comp-comma)
(defun math-compose-var (a)
(let (v sn)
(if (and math-compose-hash-args
(let ((p calc-arg-values))
(setq v 1)
(while (and p (not (equal (car p) a)))
(setq p (and (eq math-compose-hash-args t) (cdr p))
v (1+ v)))
p))
(if (eq math-compose-hash-args 1)
"#"
(format "#%d" v))
(setq sn (symbol-name (nth 1 a)))
(if (memq calc-language calc-lang-allow-percentsigns)
(setq sn (math-to-percentsigns sn)))
(if (memq calc-language calc-lang-allow-underscores)
(setq sn (math-to-underscores sn)))
sn)))
;;; Give multiplication precedence when composing to avoid
;;; writing a*(b c) instead of a b c
(defun math-compose-expr (a prec &optional div)
(let ((calc-multiplication-has-precedence t)
(math-compose-level (1+ math-compose-level))
(math-expr-opers (math-expr-ops))
spfn)
(cond
((or (and (eq a math-comp-selected) a)
(and math-comp-tagged
(not (eq math-comp-tagged a))))
(let ((math-comp-selected nil))
(and math-comp-tagged (setq math-comp-tagged a))
(list 'tag a (math-compose-expr a prec))))
((and (not (consp a)) (not (integerp a)))
(concat "'" (prin1-to-string a)))
((setq spfn (assq (car-safe a)
(get calc-language 'math-special-function-table)))
(setq spfn (cdr spfn))
(if (consp spfn)
(funcall (car spfn) a spfn)
(funcall spfn a)))
((math-scalarp a)
(if (or (eq (car-safe a) 'frac)
(and (nth 1 calc-frac-format) (Math-integerp a)))
(if (and
calc-language
(not (memq calc-language
'(flat big unform))))
(let ((aa (math-adjust-fraction a))
(calc-frac-format nil))
(math-compose-expr (list '/
(if (memq calc-language
calc-lang-slash-idiv)
(math-float (nth 1 aa))
(nth 1 aa))
(nth 2 aa))
prec))
(if (and (eq calc-language 'big)
(= (length (car calc-frac-format)) 1))
(let* ((aa (math-adjust-fraction a))
(calc-frac-format nil)
(math-radix-explicit-format nil)
(c (list 'horiz
(if (math-negp (nth 1 aa))
"- " "")
(list 'vcent 1
(math-format-number
(math-abs (nth 1 aa)))
'(rule ?-)
(math-format-number (nth 2 aa))))))
(if (= calc-number-radix 10)
c
(list 'subscr (math--comp-round-bracket c)
(int-to-string calc-number-radix))))
(math-format-number a)))
(if (not (eq calc-language 'big))
(math-format-number a prec)
(if (memq (car-safe a) '(cplx polar))
(if (math-zerop (nth 2 a))
(math-compose-expr (nth 1 a) prec)
(math--comp-round-bracket
(list 'horiz
(math-compose-expr (nth 1 a) 0)
(if (eq (car a) 'cplx) ", " "; ")
(math-compose-expr (nth 2 a) 0))))
(if (or (= calc-number-radix 10)
(not (Math-realp a))
(and calc-group-digits
(not (assoc calc-group-char '((",") (" "))))))
(math-format-number a prec)
(let ((s (math-format-number a prec))
(c nil))
(while (string-match (if (> calc-number-radix 14)
"\\([0-9]+\\)#\\([0-9a-zA-Z., ]+\\)"
"\\([0-9]+\\)#\\([0-9a-dA-D., ]+\\)")
s)
(setq c (nconc c (list (substring s 0 (match-beginning 0))
(list 'subscr
(math-match-substring s 2)
(math-match-substring s 1))))
s (substring s (match-end 0))))
(if (string-match
"\\*\\([0-9.]+\\)\\^\\(-?[0-9]+\\)\\()?\\)\\'" s)
(setq s (list 'horiz
(substring s 0 (match-beginning 0)) " "
(list 'supscr
(math-match-substring s 1)
(math-match-substring s 2))
(math-match-substring s 3))))
(if c (cons 'horiz (nconc c (list s))) s)))))))
((and (get (car a) 'math-compose-forms)
(not (eq calc-language 'unform))
(let ((comps (get (car a) 'math-compose-forms))
temp temp2)
(or (and (setq temp (assq calc-language comps))
(or (and (setq temp2 (assq (1- (length a)) (cdr temp)))
(setq temp (apply (cdr temp2) (cdr a)))
(math-compose-expr temp prec))
(and (setq temp2 (assq nil (cdr temp)))
(funcall (cdr temp2) a))))
(and (setq temp (assq nil comps))
(or (and (setq temp2 (assq (1- (length a)) (cdr temp)))
(setq temp (apply (cdr temp2) (cdr a)))
(math-compose-expr temp prec))
(and (setq temp2 (assq nil (cdr temp)))
(funcall (cdr temp2) a))))))))
((eq (car a) 'vec)
(let* ((math-comp-left-bracket (if calc-vector-brackets
(substring calc-vector-brackets 0 1) ""))
(math-comp-right-bracket (if calc-vector-brackets
(substring calc-vector-brackets 1 2) ""))
(inner-brackets (memq 'R calc-matrix-brackets))
(outer-brackets (memq 'O calc-matrix-brackets))
(row-commas (memq 'C calc-matrix-brackets))
(math-comp-comma-spc (or calc-vector-commas " "))
(math-comp-comma (or calc-vector-commas ""))
(math-comp-vector-prec (if (or (and calc-vector-commas
(math-vector-no-parens a))
(memq 'P calc-matrix-brackets))
0 1000))
(math-comp-just (cond ((eq calc-matrix-just 'right) 'vright)
((eq calc-matrix-just 'center) 'vcent)
(t 'vleft)))
(break calc-break-vectors))
(if (and (memq calc-language '(nil big))
(not calc-break-vectors)
(math-matrixp a) (not (math-matrixp (nth 1 a)))
(or calc-full-vectors
(and (< (length a) 7) (< (length (nth 1 a)) 7))
(progn (setq break t) nil)))
(if (progn
(setq math-comp-vector-prec (if (or (and calc-vector-commas
(math-vector-no-parens
(nth 1 a)))
(memq 'P calc-matrix-brackets))
0 1000))
(= (length a) 2))
(list 'horiz
(concat math-comp-left-bracket math-comp-left-bracket " ")
(math-compose-vector (cdr (nth 1 a)) (concat math-comp-comma " ")
math-comp-vector-prec)
(concat " " math-comp-right-bracket math-comp-right-bracket))
(let* ((rows (1- (length a)))
(cols (1- (length (nth 1 a))))
(base (/ (1- rows) 2))
(calc-language 'flat))
(append '(horiz)
(list (append '(vleft)
(list base)
(list (concat (and outer-brackets
(concat math-comp-left-bracket
" "))
(and inner-brackets
(concat math-comp-left-bracket
" "))))
(make-list (1- rows)
(concat (and outer-brackets
" ")
(and inner-brackets
(concat
math-comp-left-bracket
" "))))))
(math-compose-matrix (cdr a) 1 cols base)
(list (append '(vleft)
(list base)
(make-list (1- rows)
(if inner-brackets
(concat " "
math-comp-right-bracket
(and row-commas
math-comp-comma))
(if (and outer-brackets
row-commas)
";" "")))
(list (concat
(and inner-brackets
(concat " "
math-comp-right-bracket))
(and outer-brackets
(concat
" "
math-comp-right-bracket)))))))))
(if (and calc-display-strings
(cdr a)
(math-vector-is-string a))
(math-vector-to-string a t)
(if (and break (cdr a)
(not (eq calc-language 'flat)))
(let* ((full (or calc-full-vectors (< (length a) 7)))
(rows (if full (1- (length a)) 5))
(base (/ (1- rows) 2))
(calc-break-vectors nil))
(list 'horiz
(cons 'vleft (cons base
(math-compose-rows
(cdr a)
(if full rows 3) t)))))
(if (or calc-full-vectors (< (length a) 7))
(if (and
(setq spfn (get calc-language 'math-matrix-formatter))
(math-matrixp a))
(funcall spfn a)
(list 'horiz
math-comp-left-bracket
(math-compose-vector (cdr a)
(concat math-comp-comma " ")
math-comp-vector-prec)
math-comp-right-bracket))
(list 'horiz
math-comp-left-bracket
(math-compose-vector (list (nth 1 a) (nth 2 a) (nth 3 a))
(concat math-comp-comma " ")
math-comp-vector-prec)
math-comp-comma
(if (setq spfn (get calc-language 'math-dots))
(concat " " spfn)
" ...")
math-comp-comma " "
(list 'break math-compose-level)
(math-compose-expr (nth (1- (length a)) a)
(if (equal math-comp-comma "") 1000 0))
math-comp-right-bracket)))))))
((eq (car a) 'incomplete)
(if (cdr (cdr a))
(cond ((eq (nth 1 a) 'vec)
(list 'horiz "["
(math-compose-vector (cdr (cdr a)) ", " 0)
" ..."))
((eq (nth 1 a) 'cplx)
(list 'horiz "("
(math-compose-vector (cdr (cdr a)) ", " 0)
", ..."))
((eq (nth 1 a) 'polar)
(list 'horiz "("
(math-compose-vector (cdr (cdr a)) "; " 0)
"; ..."))
((eq (nth 1 a) 'intv)
(list 'horiz
(if (memq (nth 2 a) '(0 1)) "(" "[")
(math-compose-vector (cdr (cdr (cdr a))) " .. " 0)
" .. ..."))
(t (format "%s" a)))
(cond ((eq (nth 1 a) 'vec) "[ ...")
((eq (nth 1 a) 'intv)
(if (memq (nth 2 a) '(0 1)) "( ..." "[ ..."))
(t "( ..."))))
((eq (car a) 'var)
(let ((v (rassq (nth 2 a) math-expr-variable-mapping)))
(if v
(symbol-name (car v))
(if (setq spfn (get calc-language 'math-var-formatter))
(funcall spfn a prec)
(math-compose-var a)))))
((eq (car a) 'intv)
(math--comp-bracket
(if (memq (nth 1 a) '(0 1)) ?\( ?\[)
(if (memq (nth 1 a) '(0 2)) ?\) ?\])
(list 'horiz
(math-compose-expr (nth 2 a) 0)
" .. "
(math-compose-expr (nth 3 a) 0))))
((eq (car a) 'date)
(if (eq (car calc-date-format) 'X)
(math-format-date a)
(concat "<" (math-format-date a) ">")))
((and (eq (car a) 'calcFunc-subscr)
(setq spfn (get calc-language 'math-compose-subscr)))
(funcall spfn a))
((and (eq (car a) 'calcFunc-subscr) (= (length a) 3)
(eq calc-language 'big))
(let* ((a1 (math-compose-expr (nth 1 a) 1000))
(calc-language 'flat)
(a2 (math-compose-expr (nth 2 a) 0)))
(if (or (eq (car-safe a1) 'subscr)
(and (eq (car-safe a1) 'tag)
(eq (car-safe (nth 2 a1)) 'subscr)
(setq a1 (nth 2 a1))))
(list 'subscr
(nth 1 a1)
(list 'horiz
(nth 2 a1)
", "
a2))
(list 'subscr a1 a2))))
((and (eq (car a) '^)
(eq calc-language 'big))
(list 'supscr
(if (or (math-looks-negp (nth 1 a))
(memq (car-safe (nth 1 a)) '(^ / frac calcFunc-sqrt))
(and (eq (car-safe (nth 1 a)) 'cplx)
(math-negp (nth 1 (nth 1 a)))
(eq (nth 2 (nth 1 a)) 0)))
(math--comp-round-bracket (math-compose-expr (nth 1 a) 0))
(math-compose-expr (nth 1 a) 201))
(let ((calc-language 'flat)
(calc-number-radix 10)
(calc-twos-complement-mode nil))
(math-compose-expr (nth 2 a) 0))))
((and (eq (car a) '/)
(eq calc-language 'big))
(let ((a1 (let ((calc-language (if (memq (car-safe (nth 1 a)) '(/ frac))
'flat 'big)))
(math-compose-expr (nth 1 a) 0)))
(a2 (let ((calc-language (if (memq (car-safe (nth 2 a)) '(/ frac))
'flat 'big)))
(math-compose-expr (nth 2 a) 0))))
(list 'vcent
(math-comp-height a1)
a1 '(rule ?-) a2)))
((and (eq (car a) 'calcFunc-lambda)
(> (length a) 2)
(memq calc-language '(nil flat big)))
(let ((p (cdr a))
(ap calc-arg-values)
(math-compose-hash-args (if (= (length a) 3) 1 t)))
(while (and (cdr p) (equal (car p) (car ap)))
(setq p (cdr p) ap (cdr ap)))
(append '(horiz "<")
(if (cdr p)
(list (math-compose-vector
(nreverse (cdr (reverse (cdr a)))) ", " 0)
" : ")
nil)
(list (math-compose-expr (nth (1- (length a)) a) 0)
">"))))
((and (eq (car a) 'calcFunc-string)
(= (length a) 2)
(math-vectorp (nth 1 a))
(math-vector-is-string (nth 1 a)))
(if (eq calc-language 'unform)
(concat "string(" (math-vector-to-string (nth 1 a) t) ")")
(math-vector-to-string (nth 1 a) nil)))
((and (eq (car a) 'calcFunc-bstring)
(= (length a) 2)
(math-vectorp (nth 1 a))
(math-vector-is-string (nth 1 a)))
(if (eq calc-language 'unform)
(concat "bstring(" (math-vector-to-string (nth 1 a) t) ")")
(let ((c nil)
(s (math-vector-to-string (nth 1 a) nil))
p)
(while (string-match "[^ ] +[^ ]" s)
(setq p (1- (match-end 0))
c (cons (list 'break math-compose-level)
(cons (substring s 0 p)
c))
s (substring s p)))
(setq c (nreverse (cons s c)))
(or (= prec -123)
(setq c (cons (list 'set math-compose-level 2) c)))
(cons 'horiz c))))
((and (eq (car a) 'calcFunc-cprec)
(not (eq calc-language 'unform))
(= (length a) 3)
(integerp (nth 2 a)))
(let ((c (math-compose-expr (nth 1 a) -1)))
(if (> prec (nth 2 a))
(if (setq spfn (get calc-language 'math-big-parens))
(list 'horiz (car spfn) c (cdr spfn))
(math--comp-round-bracket c))
c)))
((and (eq (car a) 'calcFunc-choriz)
(not (eq calc-language 'unform))
(memq (length a) '(2 3 4))
(math-vectorp (nth 1 a))
(if (integerp (nth 2 a))
(or (null (nth 3 a))
(and (math-vectorp (nth 3 a))
(math-vector-is-string (nth 3 a))))
(or (null (nth 2 a))
(and (math-vectorp (nth 2 a))
(math-vector-is-string (nth 2 a))))))
(let* ((cprec (and (integerp (nth 2 a)) (nth 2 a)))
(sep (nth (if cprec 3 2) a))
(bprec nil))
(if sep
(math-compose-vector (cdr (nth 1 a))
(math-vector-to-string sep nil)
(or cprec prec))
(cons 'horiz (mapcar (lambda (x)
(if (eq (car-safe x) 'calcFunc-bstring)
(prog1
(math-compose-expr
x (or bprec cprec prec))
(setq bprec -123))
(math-compose-expr x (or cprec prec))))
(cdr (nth 1 a)))))))
((and (memq (car a) '(calcFunc-cvert calcFunc-clvert calcFunc-crvert))
(not (eq calc-language 'unform))
(memq (length a) '(2 3))
(math-vectorp (nth 1 a))
(or (null (nth 2 a))
(integerp (nth 2 a))))
(let* ((base 0)
(v 0)
(prec (or (nth 2 a) prec))
(c (mapcar (lambda (x)
(let ((b nil) (cc nil) a d)
(if (and (memq (car-safe x) '(calcFunc-cbase
calcFunc-ctbase
calcFunc-cbbase))
(memq (length x) '(1 2)))
(setq b (car x)
x (nth 1 x)))
(if (and (eq (car-safe x) 'calcFunc-crule)
(memq (length x) '(1 2))
(or (null (nth 1 x))
(and (math-vectorp (nth 1 x))
(= (length (nth 1 x)) 2)
(math-vector-is-string
(nth 1 x)))
(and (natnump (nth 1 x))
(<= (nth 1 x) 255))))
(setq cc (list
'rule
(if (math-vectorp (nth 1 x))
(aref (math-vector-to-string
(nth 1 x) nil) 0)
(or (nth 1 x) ?-))))
(or (and (memq (car-safe x) '(calcFunc-cvspace
calcFunc-ctspace
calcFunc-cbspace))
(memq (length x) '(2 3))
(eq (nth 1 x) 0))
(null x)
(setq cc (math-compose-expr x prec))))
(setq a (if cc (math-comp-ascent cc) 0)
d (if cc (math-comp-descent cc) 0))
(if (eq b 'calcFunc-cbase)
(setq base (+ v a -1))
(if (eq b 'calcFunc-ctbase)
(setq base v)
(if (eq b 'calcFunc-cbbase)
(setq base (+ v a d -1)))))
(setq v (+ v a d))
cc))
(cdr (nth 1 a)))))
(setq c (delq nil c))
(if c
(cons (if (eq (car a) 'calcFunc-cvert) 'vcent
(if (eq (car a) 'calcFunc-clvert) 'vleft 'vright))
(cons base c))
" ")))
((and (memq (car a) '(calcFunc-csup calcFunc-csub))
(not (eq calc-language 'unform))
(memq (length a) '(3 4))
(or (null (nth 3 a))
(integerp (nth 3 a))))
(list (if (eq (car a) 'calcFunc-csup) 'supscr 'subscr)
(math-compose-expr (nth 1 a) (or (nth 3 a) 0))
(math-compose-expr (nth 2 a) 0)))
((and (eq (car a) 'calcFunc-cflat)
(not (eq calc-language 'unform))
(memq (length a) '(2 3))
(or (null (nth 2 a))
(integerp (nth 2 a))))
(let ((calc-language (if (memq calc-language '(nil big))
'flat calc-language)))
(math-compose-expr (nth 1 a) (or (nth 2 a) 0))))
((and (eq (car a) 'calcFunc-cspace)
(memq (length a) '(2 3))
(natnump (nth 1 a)))
(if (nth 2 a)
(cons 'horiz (make-list (nth 1 a)
(if (and (math-vectorp (nth 2 a))
(math-vector-is-string (nth 2 a)))
(math-vector-to-string (nth 2 a) nil)
(math-compose-expr (nth 2 a) 0))))
(make-string (nth 1 a) ?\ )))
((and (memq (car a) '(calcFunc-cvspace calcFunc-ctspace calcFunc-cbspace))
(memq (length a) '(2 3))
(natnump (nth 1 a)))
(if (= (nth 1 a) 0)
""
(let* ((c (if (nth 2 a)
(if (and (math-vectorp (nth 2 a))
(math-vector-is-string (nth 2 a)))
(math-vector-to-string (nth 2 a) nil)
(math-compose-expr (nth 2 a) 0))
" "))
(ca (math-comp-ascent c))
(cd (math-comp-descent c)))
(cons 'vleft
(cons (if (eq (car a) 'calcFunc-ctspace)
(1- ca)
(if (eq (car a) 'calcFunc-cbspace)
(+ (* (1- (nth 1 a)) (+ ca cd)) (1- ca))
(/ (1- (* (nth 1 a) (+ ca cd))) 2)))
(make-list (nth 1 a) c))))))
((and (eq (car a) 'calcFunc-evalto)
(setq calc-any-evaltos t)
(setq spfn (get calc-language 'math-evalto))
(= math-compose-level (if math-comp-tagged 2 1))
(= (length a) 3))
(list 'horiz
(car spfn)
(math-compose-expr (nth 1 a) 0)
(cdr spfn)
(math-compose-expr (nth 2 a) 0)))
(t
(let ((op (and (not (eq calc-language 'unform))
(if (and (eq (car a) 'calcFunc-if) (= (length a) 4))
(assoc "?" math-expr-opers)
(math-assq2 (car a) math-expr-opers)))))
(cond ((and op
(or (= (length a) 3) (eq (car a) 'calcFunc-if))
(/= (nth 3 op) -1))
(cond
((or
(> prec (or (nth 4 op) (min (nth 2 op) (nth 3 op))))
(and div (eq (car a) '*)))
(if (and (memq calc-language '(tex latex))
(not (math-tex-expr-is-flat a)))
(if (eq (car-safe a) '/)
(list 'horiz "{" (math-compose-expr a -1) "}")
(list 'horiz "\\left( "
(math-compose-expr a -1)
" \\right)"))
(if (eq calc-language 'eqn)
(if (or (eq (car-safe a) '/)
(= (/ prec 100) 9))
(list 'horiz "{" (math-compose-expr a -1) "}")
(if (math-tex-expr-is-flat a)
(list 'horiz "( " (math-compose-expr a -1) " )")
(list 'horiz "{left ( "
(math-compose-expr a -1)
" right )}")))
(math--comp-round-bracket (math-compose-expr a 0)))))
((and (memq calc-language '(tex latex))
(memq (car a) '(/ calcFunc-choose calcFunc-evalto))
(>= prec 0))
(list 'horiz "{" (math-compose-expr a -1) "}"))
((eq (car a) 'calcFunc-if)
(list 'horiz
(math-compose-expr (nth 1 a) (nth 2 op))
" ? "
(math-compose-expr (nth 2 a) 0)
" : "
(math-compose-expr (nth 3 a) (nth 3 op))))
(t
(let* ((math-comp-tagged (and math-comp-tagged
(not (math-primp a))
math-comp-tagged))
(setlev (if (= prec (min (nth 2 op) (nth 3 op)))
(progn
(setq math-compose-level
(1- math-compose-level))
nil)
math-compose-level))
(lhs (math-compose-expr (nth 1 a) (nth 2 op)))
(rhs (math-compose-expr (nth 2 a) (nth 3 op) (eq (nth 1 op) '/))))
(and (equal (car op) "^")
(eq (math-comp-first-char lhs) ?-)
(setq lhs (math--comp-round-bracket lhs)))
(and (memq calc-language '(tex latex))
(or (equal (car op) "^") (equal (car op) "_"))
(not (and (stringp rhs) (= (length rhs) 1)))
(setq rhs (list 'horiz "{" rhs "}")))
(or (and (eq (car a) '*)
(or (null calc-language)
(assoc "2x" math-expr-opers))
(let* ((prevt (math-prod-last-term (nth 1 a)))
(nextt (math-prod-first-term (nth 2 a)))
(prevc (or (math-comp-last-char lhs)
(and (memq (car-safe prevt)
'(^ calcFunc-subscr
calcFunc-sqrt
frac))
(eq calc-language 'big)
?0)))
(nextc (or (math-comp-first-char rhs)
(and (memq (car-safe nextt)
'(calcFunc-sqrt
calcFunc-sum
calcFunc-prod
calcFunc-integ))
(eq calc-language 'big)
?0))))
(and prevc nextc
(or (and (>= nextc ?a) (<= nextc ?z))
(and (>= nextc ?A) (<= nextc ?Z))
(and (>= nextc ?α) (<= nextc ))
(and (>= nextc ?Α) (<= nextc ))
(and (>= nextc ?0) (<= nextc ?9))
(memq nextc '(?. ?_ ?#
?\( ?\[ ?\{))
(and (eq nextc ?\\)
(not (string-match
"\\`\\\\left("
(math-comp-first-string
rhs)))))
(not (and (eq (car-safe prevt) 'var)
(eq nextc ?\()))
(list 'horiz
(list 'set setlev 1)
lhs
(list 'break math-compose-level)
" "
rhs))))
(list 'horiz
(list 'set setlev 1)
lhs
(list 'break math-compose-level)
(if (or (equal (car op) "^")
(equal (car op) "_")
(equal (car op) "**")
(and (equal (car op) "*")
(math-comp-last-char lhs)
(math-comp-first-char rhs))
(and (equal (car op) "/")
(math-num-integerp (nth 1 a))
(math-integerp (nth 2 a))))
(car op)
(if (and (eq calc-language 'big)
(equal (car op) "=>"))
" => "
(concat " " (car op) " ")))
rhs))))))
((and op (= (length a) 2) (= (nth 3 op) -1))
(cond
((or (> prec (or (nth 4 op) (nth 2 op)))
(and (not (eq (assoc (car op) math-expr-opers) op))
(> prec 0))) ; don't write x% + y
(if (and (memq calc-language '(tex latex))
(not (math-tex-expr-is-flat a)))
(list 'horiz "\\left( "
(math-compose-expr a -1)
" \\right)")
(if (eq calc-language 'eqn)
(if (= (/ prec 100) 9)
(list 'horiz "{" (math-compose-expr a -1) "}")
(if (math-tex-expr-is-flat a)
(list 'horiz "{( " (math-compose-expr a -1) " )}")
(list 'horiz "{left ( "
(math-compose-expr a -1)
" right )}")))
(math--comp-round-bracket (math-compose-expr a 0)))))
(t
(let ((lhs (math-compose-expr (nth 1 a) (nth 2 op))))
(list 'horiz
lhs
(if (or (> (length (car op)) 1)
(not (math-comp-is-flat lhs)))
(concat " " (car op))
(car op)))))))
((and op (= (length a) 2) (= (nth 2 op) -1))
(cond
((eq (nth 3 op) 0)
(let ((lr (and (memq calc-language '(tex latex))
(not (math-tex-expr-is-flat (nth 1 a))))))
(list 'horiz
(if lr "\\left" "")
(if (string-match "\\`u\\([^a-zA-Zα-ωΑ-Ω]\\)\\'" (car op))
(substring (car op) 1)
(car op))
(if (or lr (> (length (car op)) 2)) " " "")
(math-compose-expr (nth 1 a) -1)
(if (or lr (> (length (car op)) 2)) " " "")
(if lr "\\right" "")
(car (nth 1 (memq op math-expr-opers))))))
((> prec (or (nth 4 op) (nth 3 op)))
(if (and (memq calc-language '(tex latex))
(not (math-tex-expr-is-flat a)))
(list 'horiz "\\left( "
(math-compose-expr a -1)
" \\right)")
(if (eq calc-language 'eqn)
(if (= (/ prec 100) 9)
(list 'horiz "{" (math-compose-expr a -1) "}")
(if (math-tex-expr-is-flat a)
(list 'horiz "{( " (math-compose-expr a -1) " )}")
(list 'horiz "{left ( "
(math-compose-expr a -1)
" right )}")))
(math--comp-round-bracket (math-compose-expr a 0)))))
(t
(let ((rhs (math-compose-expr (nth 1 a) (nth 3 op))))
(list 'horiz
(let ((ops (if (string-match "\\`u\\([^a-zA-Zα-ωΑ-Ω]\\)\\'"
(car op))
(substring (car op) 1)
(car op))))
(if (or (> (length ops) 1)
(not (math-comp-is-flat rhs)))
(concat ops " ")
ops))
rhs)))))
((and (eq calc-language 'big)
(setq op (get (car a) 'math-compose-big))
(funcall op a prec)))
((and (setq op (assq calc-language
'( ( nil . math-compose-normal )
( flat . math-compose-normal )
( big . math-compose-normal )
( c . math-compose-c )
( pascal . math-compose-pascal )
( fortran . math-compose-fortran )
( tex . math-compose-tex )
( latex . math-compose-latex )
( eqn . math-compose-eqn )
( yacas . math-compose-yacas )
( maxima . math-compose-maxima )
( giac . math-compose-giac )
( math . math-compose-math )
( maple . math-compose-maple ))))
(setq op (get (car a) (cdr op)))
(funcall op a prec)))
(t
(let* ((func (car a))
(func2 (assq func '(( mod . calcFunc-makemod )
( sdev . calcFunc-sdev )
( + . calcFunc-add )
( - . calcFunc-sub )
( * . calcFunc-mul )
( / . calcFunc-div )
( % . calcFunc-mod )
( ^ . calcFunc-pow )
( neg . calcFunc-neg )
( | . calcFunc-vconcat )))))
(if func2
(setq func (cdr func2)))
(if (setq func2 (rassq func math-expr-function-mapping))
(setq func (car func2)))
(setq func (math-remove-dashes
(if (string-match
"\\`calcFunc-\\([a-zA-Zα-ωΑ-Ω0-9']+\\)\\'"
(symbol-name func))
(math-match-substring (symbol-name func) 1)
(symbol-name func))))
(if (memq calc-language calc-lang-allow-percentsigns)
(setq func (math-to-percentsigns func)))
(if (memq calc-language calc-lang-allow-underscores)
(setq func (math-to-underscores func)))
(if (setq spfn (get calc-language 'math-func-formatter))
(funcall spfn func a)
(let ((args (math-compose-vector (cdr a) ", " 0)))
(if (and (member calc-function-open '("(" "[" "{"))
(member calc-function-close '(")" "]" "}")))
(list 'horiz func
(math--comp-bracket
(string-to-char calc-function-open)
(string-to-char calc-function-close)
args))
(list 'horiz func calc-function-open
args calc-function-close))))))))))))
(defun math-prod-first-term (x)
(while (eq (car-safe x) '*)
(setq x (nth 1 x)))
x)
(defun math-prod-last-term (x)
(while (eq (car-safe x) '*)
(setq x (nth 2 x)))
x)
(defun math-compose-vector (a sep prec)
(if a
(cons 'horiz
(cons (list 'set math-compose-level)
(let ((c (list (math-compose-expr (car a) prec))))
(while (setq a (cdr a))
(setq c (cons (if (eq (car-safe (car a))
'calcFunc-bstring)
(let ((math-compose-level
(1- math-compose-level)))
(math-compose-expr (car a) -123))
(math-compose-expr (car a) prec))
(cons (list 'break math-compose-level)
(cons sep c)))))
(nreverse c))))
""))
(defun math-vector-no-parens (a)
(or (cdr (cdr a))
(not (eq (car-safe (nth 1 a)) '*))))
(defun math-compose-matrix (a _col cols base)
(let ((col 0)
(res nil))
(while (<= (setq col (1+ col)) cols)
(setq res (cons (cons math-comp-just
(cons base
(mapcar (lambda (r)
(list 'horiz
(math-compose-expr
(nth col r)
math-comp-vector-prec)
(if (= col cols)
""
(concat
math-comp-comma-spc " "))))
a)))
res)))
(nreverse res)))
(defun math-compose-rows (a count first)
(if (cdr a)
(if (<= count 0)
(if (< count 0)
(math-compose-rows (cdr a) -1 nil)
(cons (concat
(let ((mdots (get calc-language 'math-dots)))
(if mdots
(concat " " mdots)
" ..."))
math-comp-comma)
(math-compose-rows (cdr a) -1 nil)))
(cons (list 'horiz
(if first (concat math-comp-left-bracket " ") " ")
(math-compose-expr (car a) math-comp-vector-prec)
math-comp-comma)
(math-compose-rows (cdr a) (1- count) nil)))
(list (list 'horiz
(if first (concat math-comp-left-bracket " ") " ")
(math-compose-expr (car a) math-comp-vector-prec)
(concat " " math-comp-right-bracket)))))
(defun math-vector-is-string (a)
(while (and (setq a (cdr a))
(or (and (natnump (car a))
(<= (car a) 255))
(and (eq (car-safe (car a)) 'cplx)
(natnump (nth 1 (car a)))
(eq (nth 2 (car a)) 0)
(<= (nth 1 (car a)) 255)))))
(null a))
(defconst math-vector-to-string-chars '( ( ?\" . "\\\"" )
( ?\\ . "\\\\" )
( ?\a . "\\a" )
( ?\b . "\\b" )
( ?\e . "\\e" )
( ?\f . "\\f" )
( ?\n . "\\n" )
( ?\r . "\\r" )
( ?\t . "\\t" )
( ?\^? . "\\^?" )))
(defun math-vector-to-string (a &optional quoted)
(setq a (concat (mapcar (lambda (x) (if (consp x) (nth 1 x) x))
(cdr a))))
(if (string-match "[\000-\037\177\\\"]" a)
(let ((p 0)
(pat (if quoted "[\000-\037\177\\\"]" "[\000-\037\177]"))
(codes (if quoted math-vector-to-string-chars '((?\^? . "^?"))))
(fmt (if quoted "\\^%c" "^%c"))
new)
(while (setq p (string-match pat a p))
(if (setq new (assq (aref a p) codes))
(setq a (concat (substring a 0 p)
(cdr new)
(substring a (1+ p)))
p (+ p (length (cdr new))))
(setq a (concat (substring a 0 p)
(format fmt (+ (aref a p) 64))
(substring a (1+ p)))
p (+ p 2))))))
(if quoted
(concat "\"" a "\"")
a))
(defun math-to-underscores (x)
(if (string-match "\\`\\(.*\\)#\\(.*\\)\\'" x)
(math-to-underscores
(concat (math-match-substring x 1) "_" (math-match-substring x 2)))
x))
(defun math-to-percentsigns (x)
(if (string-match "\\`\\(.*\\)o'o\\(.*\\)\\'" x)
(math-to-underscores
(concat (math-match-substring x 1) "%" (math-match-substring x 2)))
x))
(defun math-tex-expr-is-flat (a)
(or (Math-integerp a)
(memq (car a) '(float var))
(and (memq (car a) '(+ - * neg))
(progn
(while (and (setq a (cdr a))
(math-tex-expr-is-flat (car a))))
(null a)))
(and (memq (car a) '(^ calcFunc-subscr))
(math-tex-expr-is-flat (nth 1 a)))))
;; FIXME: maybe try box drawing chars if big bracket chars are unavailable,
;; like ┌ ┐n
;; │a + b│ ┌ a + b ┐n
;; │-----│ or │ ----- │ ?
;; │ c │ └ c ┘
;; └ ┘
;; They are more common than the chars below, but look a bit square.
;; Rounded corners exist but are less commonly available.
(defconst math--big-bracket-alist
'((?\( . (?⎛ ?⎝ ?⎜))
(?\) . (?⎞ ?⎠ ?⎟))
(?\[ . (?⎡ ?⎣ ?⎢))
(?\] . (?⎤ ?⎦ ?⎥))
(?\{ . (?⎧ ?⎩ ?⎪ ?⎨))
(?\} . (?⎫ ?⎭ ?⎪ ?⎬)))
"Alist mapping bracket chars to (UPPER LOWER EXTENSION MIDPIECE).
Not all brackets have midpieces.")
(defun math--big-bracket (bracket-char height baseline)
"Composition for BRACKET-CHAR of HEIGHT with BASELINE."
(if (<= height 1)
(char-to-string bracket-char)
(let ((pieces (cdr (assq bracket-char math--big-bracket-alist))))
(if (memq nil (mapcar #'char-displayable-p pieces))
(char-to-string bracket-char)
(let* ((upper (nth 0 pieces))
(lower (nth 1 pieces))
(extension (nth 2 pieces))
(midpiece (nth 3 pieces)))
(cons 'vleft ; alignment doesn't matter; width is 1 char
(cons baseline
(mapcar
#'char-to-string
(append
(list upper)
(if midpiece
(let ((lower-ext (/ (- height 3) 2)))
(append
(make-list (- height 3 lower-ext) extension)
(list midpiece)
(make-list lower-ext extension)))
(make-list (- height 2) extension))
(list lower))))))))))
(defun math--comp-bracket (left-bracket right-bracket comp)
"Put the composition COMP inside LEFT-BRACKET and RIGHT-BRACKET."
(if (eq calc-language 'big)
(let ((height (math-comp-height comp))
(baseline (1- (math-comp-ascent comp))))
(list 'horiz
(math--big-bracket left-bracket height baseline)
comp
(math--big-bracket right-bracket height baseline)))
(list 'horiz
(char-to-string left-bracket)
comp
(char-to-string right-bracket))))
(defun math--comp-round-bracket (comp)
"Put the composition COMP inside plain brackets."
(math--comp-bracket ?\( ?\) comp))
(put 'calcFunc-log 'math-compose-big #'math-compose-log)
(defun math-compose-log (a _prec)
(and (= (length a) 3)
(list 'horiz
(list 'subscr "log"
(let ((calc-language 'flat))
(math-compose-expr (nth 2 a) 1000)))
(math--comp-round-bracket (math-compose-expr (nth 1 a) 1000)))))
(put 'calcFunc-log10 'math-compose-big #'math-compose-log10)
(defun math-compose-log10 (a _prec)
(and (= (length a) 2)
(list 'horiz
(list 'subscr "log" "10")
(math--comp-round-bracket (math-compose-expr (nth 1 a) 1000)))))
(put 'calcFunc-deriv 'math-compose-big #'math-compose-deriv)
(put 'calcFunc-tderiv 'math-compose-big #'math-compose-deriv)
(defun math-compose-deriv (a prec)
(when (= (length a) 3)
(math-compose-expr (list '/
(list 'calcFunc-choriz
(list 'vec
'(calcFunc-string (vec ?d))
(nth 1 a)))
(list 'calcFunc-choriz
(list 'vec
'(calcFunc-string (vec ?d))
(nth 2 a))))
prec)))
(put 'calcFunc-sqrt 'math-compose-big #'math-compose-sqrt)
(defun math-compose-sqrt (a _prec)
(when (= (length a) 2)
(let* ((c (math-compose-expr (nth 1 a) 0))
(a (math-comp-ascent c))
(d (math-comp-descent c))
(h (+ a d))
(w (math-comp-width c)))
(list 'vleft
a
(concat (if (= h 1) " " " ")
(make-string (+ w 2) ?\_))
(list 'horiz
(if (= h 1)
(if (char-displayable-p ?√)
"" "V")
(append (list 'vleft (1- a))
(make-list (1- h) " |")
'("\\|")))
" "
c)))))
(put 'calcFunc-choose 'math-compose-big #'math-compose-choose)
(defun math-compose-choose (a _prec)
(let ((a1 (math-compose-expr (nth 1 a) 0))
(a2 (math-compose-expr (nth 2 a) 0)))
(math--comp-round-bracket (list 'vcent
(+ (math-comp-height a1))
a1 " " a2))))
(put 'calcFunc-integ 'math-compose-big #'math-compose-integ)
(defun math-compose-integ (a prec)
(and (memq (length a) '(3 5))
(eq (car-safe (nth 2 a)) 'var)
(let* ((parens (and (>= prec 196) (/= prec 1000)))
(var (math-compose-expr (nth 2 a) 0))
(over (and (eq (car-safe (nth 2 a)) 'var)
(or (and (eq (car-safe (nth 1 a)) '/)
(math-numberp (nth 1 (nth 1 a))))
(and (eq (car-safe (nth 1 a)) '^)
(math-looks-negp (nth 2 (nth 1 a)))))))
(expr (math-compose-expr (if over
(math-mul (nth 1 a)
(math-build-var-name
(format
"d%s"
(nth 1 (nth 2 a)))))
(nth 1 a)) 185))
(low (and (nth 3 a)
(let ((calc-language 'flat))
(math-compose-expr (nth 3 a) 0))))
(high (and (nth 4 a)
(let ((calc-language 'flat))
(math-compose-expr (nth 4 a) 0))))
;; Check if we have Unicode integral top/bottom parts.
(fancy (and (char-displayable-p ?⌠)
(char-displayable-p ?⌡)))
;; If we do, find the most suitable middle part.
(fancy-stem (cond ((not fancy))
;; U+23AE INTEGRAL EXTENSION
((char-displayable-p ?⎮) "")
;; U+2502 BOX DRAWINGS LIGHT VERTICAL
((char-displayable-p ?│) "")
;; U+007C VERTICAL LINE
(t "| "))))
(let ((comp
(list 'horiz
(append (list 'vcent (if fancy
(if high 2 1)
(if high 3 2)))
(and high (list (if fancy
(list 'horiz high " ")
(list 'horiz " " high))))
(if fancy
(list "" fancy-stem "")
'(" /"
" | "
" | "
" | "
"/ "))
(and low (list (if fancy
(list 'horiz low " ")
(list 'horiz low " ")))))
expr
(if over
""
(list 'horiz " d" var)))))
(if parens
(math--comp-round-bracket comp)
comp)))))
(put 'calcFunc-sum 'math-compose-big #'math-compose-sum)
(defun math-compose-sum (a prec)
(and (memq (length a) '(3 5 6))
(let* ((expr (math-compose-expr (nth 1 a) 185))
(var
(let ((calc-language 'flat))
(math-compose-expr (nth 2 a) 0)))
(low (and (nth 3 a)
(let ((calc-language 'flat))
(math-compose-expr (nth 3 a) 0))))
(high (and (nth 4 a)
(let ((calc-language 'flat))
(math-compose-vector (nthcdr 4 a) ", " 0))))
(comp
(list 'horiz
(append (list 'vcent (if high 3 2))
(and high (list high))
'("---- "
"\\ "
" > "
"/ "
"---- ")
(if low
(list (list 'horiz var " = " low))
(list var)))
(if (memq (car-safe (nth 1 a)) '(calcFunc-sum calcFunc-prod))
" " "")
expr)))
(if (memq prec '(180 201))
(math--comp-round-bracket comp)
comp))))
(put 'calcFunc-prod 'math-compose-big #'math-compose-prod)
(defun math-compose-prod (a prec)
(and (memq (length a) '(3 5 6))
(let* ((expr (math-compose-expr (nth 1 a) 198))
(var
(let ((calc-language 'flat))
(math-compose-expr (nth 2 a) 0)))
(low (and (nth 3 a)
(let ((calc-language 'flat))
(math-compose-expr (nth 3 a) 0))))
(high (and (nth 4 a)
(let ((calc-language 'flat))
(math-compose-vector (nthcdr 4 a) ", " 0))))
(comp
(list 'horiz
(append (list 'vcent (if high 3 2))
(and high (list high))
'("----- "
" | | "
" | | "
" | | ")
(if low
(list (list 'horiz var " = " low))
(list var)))
(if (memq (car-safe (nth 1 a))
'(calcFunc-sum calcFunc-prod))
" " "")
expr)))
(if (memq prec '(196 201))
(math--comp-round-bracket comp)
comp))))
;; The variables math-svo-c, math-svo-wid and math-svo-off are local
;; to math-stack-value-offset in calc.el, but are used by
;; math-stack-value-offset-fancy, which is called by math-stack-value-offset..
(defvar math-svo-wid)
(defvar math-svo-off)
(defun math-stack-value-offset-fancy (c)
(let ((cwid (+ (math-comp-width c))))
(cond ((eq calc-display-just 'right)
(if calc-display-origin
(setq math-svo-wid (max calc-display-origin 5))
(if (integerp calc-line-breaking)
(setq math-svo-wid calc-line-breaking)))
(setq math-svo-off (- math-svo-wid cwid
(max (- (length calc-right-label)
(if (and (integerp calc-line-breaking)
calc-display-origin)
(max (- calc-line-breaking
calc-display-origin)
0)
0))
0))))
(t
(if calc-display-origin
(progn
(setq math-svo-off (- calc-display-origin (/ cwid 2)))
(if (integerp calc-line-breaking)
(setq math-svo-off (min math-svo-off (- calc-line-breaking cwid
(length calc-right-label)))))
(if (>= math-svo-off 0)
(setq math-svo-wid (max math-svo-wid (+ math-svo-off cwid)))))
(if (integerp calc-line-breaking)
(setq math-svo-wid calc-line-breaking))
(setq math-svo-off (/ (- math-svo-wid cwid) 2)))))
(and (integerp calc-line-breaking)
(or (< math-svo-off 0)
(and calc-display-origin
(> calc-line-breaking calc-display-origin)))
(setq math-svo-wid calc-line-breaking))))
;;; Convert a composition to string form, with embedded \n's if necessary.
(defun math-composition-to-string (c &optional width)
(or width (setq width (calc-window-width)))
(if calc-display-raw
(math-comp-to-string-raw c 0)
(if (math-comp-is-flat c)
(math-comp-to-string-flat c width)
(math-vert-comp-to-string
(math-comp-simplify c width)))))
(defvar math-comp-buf-string (make-vector 10 ""))
(defvar math-comp-buf-margin (make-vector 10 0))
(defvar math-comp-buf-level (make-vector 10 0))
(defun math-comp-is-flat (c) ; check if c's height is 1.
(cond ((not (consp c)) t)
((memq (car c) '(set break)) t)
((eq (car c) 'horiz)
(while (and (setq c (cdr c))
(math-comp-is-flat (car c))))
(null c))
((memq (car c) '(vleft vcent vright))
(and (= (length c) 3)
(= (nth 1 c) 0)
(math-comp-is-flat (nth 2 c))))
((eq (car c) 'tag)
(math-comp-is-flat (nth 2 c)))
(t nil)))
;;; Convert a one-line composition to a string. Break into multiple
;;; lines if necessary, choosing break points according to the structure
;;; of the formula.
;; The variables math-comp-full-width, math-comp-highlight, math-comp-word,
;; math-comp-level, math-comp-margin and math-comp-buf are local to
;; math-comp-to-string-flat, but are used by math-comp-to-string-flat-term,
;; which is called by math-comp-to-string-flat.
;; math-comp-highlight and math-comp-buf are also local to
;; math-comp-simplify-term and math-comp-simplify respectively, but are used
;; by math-comp-add-string.
(defvar math-comp-full-width)
(defvar math-comp-highlight)
(defvar math-comp-word)
(defvar math-comp-level)
(defvar math-comp-margin)
(defvar math-comp-buf)
;; The variable math-comp-pos is local to math-comp-to-string-flat, but
;; is used by math-comp-to-string-flat-term and math-comp-sel-first-term,
;; which are called by math-comp-to-string-flat.
(defvar math-comp-pos)
(defun math-comp-to-string-flat (c full-width)
(if math-comp-sel-hpos
(let ((math-comp-pos 0))
(math-comp-sel-flat-term c))
(let ((math-comp-buf "")
(math-comp-word "")
(math-comp-pos 0)
(math-comp-margin 0)
(math-comp-highlight (and math-comp-selected calc-show-selections))
(math-comp-full-width full-width)
(math-comp-level -1))
(math-comp-to-string-flat-term '(set -1 0))
(math-comp-to-string-flat-term c)
(math-comp-to-string-flat-term '(break -1))
(let ((str (aref math-comp-buf-string 0))
(prefix ""))
(and (> (length str) 0) (= (aref str 0) ? )
(> (length math-comp-buf) 0)
(let ((k (length math-comp-buf)))
(while (not (= (aref math-comp-buf (setq k (1- k))) ?\n)))
(aset math-comp-buf k ? )
(if (and (< (1+ k) (length math-comp-buf))
(= (aref math-comp-buf (1+ k)) ? ))
(progn
(aset math-comp-buf (1+ k) ?\n)
(setq prefix " "))
(setq prefix "\n"))))
(concat math-comp-buf prefix str)))))
(defun math-comp-to-string-flat-term (c)
(cond ((not (consp c))
(if math-comp-highlight
(setq c (math-comp-highlight-string c)))
(setq math-comp-word (if (= (length math-comp-word) 0) c
(concat math-comp-word c))
math-comp-pos (+ math-comp-pos (length c))))
((eq (car c) 'horiz)
(while (setq c (cdr c))
(math-comp-to-string-flat-term (car c))))
((eq (car c) 'set)
(if (nth 1 c)
(progn
(setq math-comp-level (1+ math-comp-level))
(if (>= math-comp-level (length math-comp-buf-string))
(setq math-comp-buf-string (vconcat math-comp-buf-string
math-comp-buf-string)
math-comp-buf-margin (vconcat math-comp-buf-margin
math-comp-buf-margin)
math-comp-buf-level (vconcat math-comp-buf-level
math-comp-buf-level)))
(aset math-comp-buf-string math-comp-level "")
(aset math-comp-buf-margin math-comp-level (+ math-comp-pos
(or (nth 2 c) 0)))
(aset math-comp-buf-level math-comp-level (nth 1 c)))))
((eq (car c) 'break)
(if (not calc-line-breaking)
(setq math-comp-buf (concat math-comp-buf math-comp-word)
math-comp-word "")
(let ((i 0) str)
(if (and (> math-comp-pos math-comp-full-width)
(progn
(while (progn
(setq str (aref math-comp-buf-string i))
(and (= (length str) 0) (< i math-comp-level)))
(setq i (1+ i)))
(or (> (length str) 0) (> (length math-comp-buf) 0))))
(let ((prefix "") mrg wid)
(setq mrg (aref math-comp-buf-margin i))
(if (> mrg 12) ; indenting too far, go back to far left
(setq mrg (if calc-line-numbering 5 1)))
(setq wid (+ (length str) math-comp-margin))
(and (> (length str) 0) (= (aref str 0) ? )
(> (length math-comp-buf) 0)
(let ((k (length math-comp-buf)))
(while (not (= (aref math-comp-buf (setq k (1- k))) ?\n)))
(aset math-comp-buf k ? )
(if (and (< (1+ k) (length math-comp-buf))
(= (aref math-comp-buf (1+ k)) ? ))
(progn
(aset math-comp-buf (1+ k) ?\n)
(setq prefix " "))
(setq prefix "\n"))))
(setq math-comp-buf (concat math-comp-buf prefix str "\n"
(make-string mrg ? ))
math-comp-pos (+ math-comp-pos (- mrg wid))
math-comp-margin mrg)
(aset math-comp-buf-string i "")
(while (<= (setq i (1+ i)) math-comp-level)
(if (> (aref math-comp-buf-margin i) wid)
(aset math-comp-buf-margin i
(+ (aref math-comp-buf-margin i)
(- mrg wid))))))))
(if (and (= (nth 1 c) (aref math-comp-buf-level math-comp-level))
(< math-comp-pos (+ (aref math-comp-buf-margin math-comp-level) 2)))
() ; avoid stupid breaks, e.g., "1 +\n really_long_expr"
(let ((str (aref math-comp-buf-string math-comp-level)))
(setq str (if (= (length str) 0)
math-comp-word
(concat str math-comp-word))
math-comp-word "")
(while (< (nth 1 c) (aref math-comp-buf-level math-comp-level))
(setq math-comp-level (1- math-comp-level))
(or (= (length (aref math-comp-buf-string math-comp-level)) 0)
(setq str (concat (aref math-comp-buf-string math-comp-level)
str))))
(aset math-comp-buf-string math-comp-level str)))))
((eq (car c) 'tag)
(cond ((eq (nth 1 c) math-comp-selected)
(let ((math-comp-highlight (not calc-show-selections)))
(math-comp-to-string-flat-term (nth 2 c))))
((eq (nth 1 c) t)
(let ((math-comp-highlight nil))
(math-comp-to-string-flat-term (nth 2 c))))
(t (math-comp-to-string-flat-term (nth 2 c)))))
(t (math-comp-to-string-flat-term (nth 2 c)))))
(defun math-comp-highlight-string (s)
(setq s (copy-sequence s))
(if calc-highlight-selections-with-faces
(if (not calc-show-selections)
(propertize s 'face 'calc-selected-face)
(propertize s 'face 'calc-nonselected-face))
(let ((i (length s)))
(while (>= (setq i (1- i)) 0)
(or (memq (aref s i) '(32 ?\n))
(aset s i (if calc-show-selections ?\. ?\#)))))
s))
;; The variable math-comp-sel-tag is local to calc-find-selected-part
;; in calc-sel.el, but is used by math-comp-sel-flat-term and
;; math-comp-add-string-sel, which are called (indirectly) by
;; calc-find-selected-part.
(defvar math-comp-sel-tag)
(defun math-comp-sel-flat-term (c)
(cond ((not (consp c))
(setq math-comp-pos (+ math-comp-pos (length c))))
((memq (car c) '(set break)))
((eq (car c) 'horiz)
(while (and (setq c (cdr c)) (< math-comp-sel-cpos 1000000))
(math-comp-sel-flat-term (car c))))
((eq (car c) 'tag)
(if (<= math-comp-pos math-comp-sel-cpos)
(progn
(math-comp-sel-flat-term (nth 2 c))
(if (> math-comp-pos math-comp-sel-cpos)
(setq math-comp-sel-tag c
math-comp-sel-cpos 1000000)))
(math-comp-sel-flat-term (nth 2 c))))
(t (math-comp-sel-flat-term (nth 2 c)))))
;;; Simplify a composition to a canonical form consisting of
;;; (vleft n "string" "string" "string" ...)
;;; where 0 <= n < number-of-strings.
;; The variables math-comp-base, math-comp-hgt, math-comp-tag,
;; math-comp-hpos and math-comp-vpos are local to math-comp-simplify,
;; but are used by math-comp-add-string (math-comp-base, math-comp-hgt),
;; math-comp-add-string-sel (math-comp-tag) and math-comp-simplify-term
;; (math-comp-tag, math-comp-vpos, math-comp-hpos), which are called by
;; math-comp-simplify.
(defvar math-comp-base)
(defvar math-comp-hgt)
(defvar math-comp-tag)
(defvar math-comp-hpos)
(defvar math-comp-vpos)
(defun math-comp-simplify (c _full-width)
(let ((math-comp-buf (list ""))
(math-comp-base 0)
(math-comp-hgt 1)
(math-comp-hpos 0)
(math-comp-vpos 0)
(math-comp-highlight (and math-comp-selected calc-show-selections))
(math-comp-tag nil))
(math-comp-simplify-term c)
(cons 'vleft (cons math-comp-base math-comp-buf))))
(defun math-comp-add-string (s h v)
(and (> (length s) 0)
(let ((vv (+ v math-comp-base)))
(if math-comp-sel-hpos
(math-comp-add-string-sel h vv (length s) 1)
(if (< vv 0)
(setq math-comp-buf (nconc (make-list (- vv) "") math-comp-buf)
math-comp-base (- v)
math-comp-hgt (- math-comp-hgt vv)
vv 0)
(if (>= vv math-comp-hgt)
(setq math-comp-buf (nconc math-comp-buf
(make-list (1+ (- vv math-comp-hgt)) ""))
math-comp-hgt (1+ vv))))
(let ((str (nthcdr vv math-comp-buf)))
(setcar str (concat (car str)
(make-string (- h (length (car str))) 32)
(if math-comp-highlight
(math-comp-highlight-string s)
s))))))))
(defun math-comp-add-string-sel (x y w h)
(if (and (<= y math-comp-sel-vpos)
(> (+ y h) math-comp-sel-vpos)
(<= x math-comp-sel-hpos)
(> (+ x w) math-comp-sel-hpos))
(setq math-comp-sel-tag math-comp-tag
math-comp-sel-vpos 10000)))
(defun math-comp-simplify-term (c)
(cond ((stringp c)
(math-comp-add-string c math-comp-hpos math-comp-vpos)
(setq math-comp-hpos (+ math-comp-hpos (length c))))
((memq (car c) '(set break))
nil)
((eq (car c) 'horiz)
(while (setq c (cdr c))
(math-comp-simplify-term (car c))))
((memq (car c) '(vleft vcent vright))
(let* ((math-comp-vpos (+ (- math-comp-vpos (nth 1 c))
(1- (math-comp-ascent (nth 2 c)))))
(widths (mapcar 'math-comp-width (cdr (cdr c))))
(maxwid (apply 'max widths))
(bias (cond ((eq (car c) 'vleft) 0)
((eq (car c) 'vcent) 1)
(t 2))))
(setq c (cdr c))
(while (setq c (cdr c))
(if (eq (car-safe (car c)) 'rule)
(math-comp-add-string (make-string maxwid (nth 1 (car c)))
math-comp-hpos math-comp-vpos)
(let ((math-comp-hpos (+ math-comp-hpos (/ (* bias (- maxwid
(car widths)))
2))))
(math-comp-simplify-term (car c))))
(and (cdr c)
(setq math-comp-vpos (+ math-comp-vpos
(+ (math-comp-descent (car c))
(math-comp-ascent (nth 1 c))))
widths (cdr widths))))
(setq math-comp-hpos (+ math-comp-hpos maxwid))))
((eq (car c) 'supscr)
(let* ((asc (or 1 (math-comp-ascent (nth 1 c))))
(desc (math-comp-descent (nth 2 c)))
(oldh (prog1
math-comp-hpos
(math-comp-simplify-term (nth 1 c))))
(math-comp-vpos (- math-comp-vpos (+ asc desc))))
(math-comp-simplify-term (nth 2 c))
(if math-comp-sel-hpos
(math-comp-add-string-sel oldh
(- math-comp-vpos
-1
(math-comp-ascent (nth 2 c)))
(- math-comp-hpos oldh)
(math-comp-height c)))))
((eq (car c) 'subscr)
(let* ((asc (math-comp-ascent (nth 2 c)))
(desc (math-comp-descent (nth 1 c)))
(oldv math-comp-vpos)
(oldh (prog1
math-comp-hpos
(math-comp-simplify-term (nth 1 c))))
(math-comp-vpos (+ math-comp-vpos (+ asc desc))))
(math-comp-simplify-term (nth 2 c))
(if math-comp-sel-hpos
(math-comp-add-string-sel oldh oldv
(- math-comp-hpos oldh)
(math-comp-height c)))))
((eq (car c) 'tag)
(cond ((eq (nth 1 c) math-comp-selected)
(let ((math-comp-highlight (not calc-show-selections)))
(math-comp-simplify-term (nth 2 c))))
((eq (nth 1 c) t)
(let ((math-comp-highlight nil))
(math-comp-simplify-term (nth 2 c))))
(t (let ((math-comp-tag c))
(math-comp-simplify-term (nth 2 c))))))))
;;; Measuring a composition.
(defun math-comp-first-char (c)
(cond ((stringp c)
(and (> (length c) 0)
(elt c 0)))
((memq (car c) '(horiz subscr supscr))
(while (and (setq c (cdr c))
(math-comp-is-null (car c))))
(and c (math-comp-first-char (car c))))
((eq (car c) 'tag)
(math-comp-first-char (nth 2 c)))))
(defun math-comp-first-string (c)
(cond ((stringp c)
(and (> (length c) 0)
c))
((eq (car c) 'horiz)
(while (and (setq c (cdr c))
(math-comp-is-null (car c))))
(and c (math-comp-first-string (car c))))
((eq (car c) 'tag)
(math-comp-first-string (nth 2 c)))))
(defun math-comp-last-char (c)
(cond ((stringp c)
(and (> (length c) 0)
(elt c (1- (length c)))))
((eq (car c) 'horiz)
(let ((c (reverse (cdr c))))
(while (and c (math-comp-is-null (car c)))
(setq c (cdr c)))
(and c (math-comp-last-char (car c)))))
((eq (car c) 'tag)
(math-comp-last-char (nth 2 c)))))
(defun math-comp-is-null (c)
(cond ((stringp c) (= (length c) 0))
((memq (car c) '(horiz subscr supscr))
(while (and (setq c (cdr c))
(math-comp-is-null (car c))))
(null c))
((eq (car c) 'tag)
(math-comp-is-null (nth 2 c)))
((memq (car c) '(set break)) t)))
(defun math-comp-width (c)
(cond ((not (consp c)) (length c))
((memq (car c) '(horiz subscr supscr))
(let ((accum 0))
(while (setq c (cdr c))
(setq accum (+ accum (math-comp-width (car c)))))
accum))
((memq (car c) '(vcent vleft vright))
(setq c (cdr c))
(let ((accum 0))
(while (setq c (cdr c))
(setq accum (max accum (math-comp-width (car c)))))
accum))
((eq (car c) 'tag)
(math-comp-width (nth 2 c)))
(t 0)))
(defun math-comp-height (c)
(if (stringp c)
1
(+ (math-comp-ascent c) (math-comp-descent c))))
(defun math-comp-ascent (c)
(cond ((not (consp c)) 1)
((eq (car c) 'horiz)
(let ((accum 0))
(while (setq c (cdr c))
(setq accum (max accum (math-comp-ascent (car c)))))
accum))
((memq (car c) '(vcent vleft vright))
(if (> (nth 1 c) 0) (1+ (nth 1 c)) 1))
((eq (car c) 'supscr)
(max (math-comp-ascent (nth 1 c)) (1+ (math-comp-height (nth 2 c)))))
((eq (car c) 'subscr)
(math-comp-ascent (nth 1 c)))
((eq (car c) 'tag)
(math-comp-ascent (nth 2 c)))
(t 1)))
(defun math-comp-descent (c)
(cond ((not (consp c)) 0)
((eq (car c) 'horiz)
(let ((accum 0))
(while (setq c (cdr c))
(setq accum (max accum (math-comp-descent (car c)))))
accum))
((memq (car c) '(vcent vleft vright))
(let ((accum (- (nth 1 c))))
(setq c (cdr c))
(while (setq c (cdr c))
(setq accum (+ accum (math-comp-height (car c)))))
(max (1- accum) 0)))
((eq (car c) 'supscr)
(math-comp-descent (nth 1 c)))
((eq (car c) 'subscr)
(+ (math-comp-descent (nth 1 c)) (math-comp-height (nth 2 c))))
((eq (car c) 'tag)
(math-comp-descent (nth 2 c)))
(t 0)))
(defun calcFunc-cwidth (a &optional prec)
(if (and prec (not (integerp prec))) (math-reject-arg prec 'fixnump))
(math-comp-width (math-compose-expr a (or prec 0))))
(defun calcFunc-cheight (a &optional prec)
(if (and prec (not (integerp prec))) (math-reject-arg prec 'fixnump))
(if (and (memq (car a) '(calcFunc-cvspace calcFunc-ctspace calcFunc-cbspace))
(memq (length a) '(2 3))
(eq (nth 1 a) 0))
0
(math-comp-height (math-compose-expr a (or prec 0)))))
(defun calcFunc-cascent (a &optional prec)
(if (and prec (not (integerp prec))) (math-reject-arg prec 'fixnump))
(if (and (memq (car a) '(calcFunc-cvspace calcFunc-ctspace calcFunc-cbspace))
(memq (length a) '(2 3))
(eq (nth 1 a) 0))
0
(math-comp-ascent (math-compose-expr a (or prec 0)))))
(defun calcFunc-cdescent (a &optional prec)
(if (and prec (not (integerp prec))) (math-reject-arg prec 'fixnump))
(math-comp-descent (math-compose-expr a (or prec 0))))
;;; Convert a simplified composition into string form.
(defun math-vert-comp-to-string (c)
(if (stringp c)
c
(math-vert-comp-to-string-step (cdr (cdr c)))))
(defun math-vert-comp-to-string-step (c)
(if (cdr c)
(concat (car c) "\n" (math-vert-comp-to-string-step (cdr c)))
(car c)))
;;; Convert a composition to a string in "raw" form (for debugging).
(defun math-comp-to-string-raw (c indent)
(cond ((or (not (consp c)) (eq (car c) 'set))
(prin1-to-string c))
((null (cdr c))
(concat "(" (symbol-name (car c)) ")"))
(t
(let ((next-indent (+ indent 2 (length (symbol-name (car c))))))
(concat "("
(symbol-name (car c))
" "
(math-comp-to-string-raw (nth 1 c) next-indent)
(math-comp-to-string-raw-step (cdr (cdr c))
next-indent)
")")))))
(defun math-comp-to-string-raw-step (cl indent)
(if cl
(concat "\n"
(make-string indent 32)
(math-comp-to-string-raw (car cl) indent)
(math-comp-to-string-raw-step (cdr cl) indent))
""))
(provide 'calccomp)
;;; calccomp.el ends here