1 ;; -*- mode: emacs-lisp; lexical-binding: t; -*-
2 ;;;; imaxima.el --- Maxima mode with images
4 ;; Created: 14 Nov 2001
5 ;; Version: See version.texi
8 ;; Copyright (C) 2001, 2002, 2003, 2004 Jesper Harder
9 ;; Copyright (C) 2006 Stephen Eglen (imaxima-print-buffer)
10 ;; Copyright (C) 2007, 2008 Yasuaki Honda (imaxima-to-html, inline graph)
11 ;; Copyright (C) 2020, 2021, 2022 Leo Butler (imaxima-gnuplot-replot, various improvements)
13 ;; Time-stamp: <16-01-2024 11:38:28 Leo Butler>
15 ;; This program is free software; you can redistribute it and/or
16 ;; modify it under the terms of the GNU General Public License as
17 ;; published by the Free Software Foundation; either version 2 of
18 ;; the License, or (at your option) any later version.
20 ;; This program is distributed in the hope that it will be
21 ;; useful, but WITHOUT ANY WARRANTY; without even the implied
22 ;; warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
23 ;; PURPOSE. See the GNU General Public License for more details.
25 ;; You should have received a copy of the GNU General Public
26 ;; License along with this program; if not, write to the Free
27 ;; Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
32 ;; This file (and imaxima.lisp) provides image support for interacting
33 ;; with the computer algebra system Maxima
34 ;; <http://maxima.sourceforge.net/>
36 ;; The command `imaxima' (M-x imaxima) provides a simple comint
39 ;; To use imaxima with the Maxima mode from the Maxima distribution
40 ;; set `imaxima-use-maxima-mode-flag' to `t'.
42 ;; To turn off images, evaluate "display2d:true" in Maxima. To turn
43 ;; them on again, evaluate "display2d:imaxima".
45 ;; The command `imaxima-latex' prepares a LaTeX version of the Maxima
48 ;; The package requires Emacs 21 with image support.
50 ;; A fairly recent version of Ghostscript is recommended (at least
51 ;; newer than v. 8.56). If your version is too old, you can either set
52 ;; `imaxima-image-type' to 'ps or remove the options
53 ;; "-dTextAlphaBits=4" and "-dGraphicsAlphaBits=4" from
54 ;; `imaxima-gs-options'. The images won't look nearly as attractive,
55 ;; though -- the text looks ragged because it isn't anti aliased.
57 ;; The file "imaxima.lisp" is a slightly modified version of
58 ;; "texmacs.lisp" in the TeXmacs distribution. Several of the image
59 ;; routines are borrowed from David Kastrup's preview-latex.el.
61 ;; Version 1.0 beta and later supports inline graph. You can use
62 ;; the following six maxima commands.
63 ;; wxplot2d(), wxplot3d(), wxdraw2d(), wxdraw3d(), wximplicit_plot(),
65 ;; GNUPLOT 4.2 or later is needed for this to work. The resulted image
66 ;; generated by gnuplot will be inserted as the output of the command.
70 ;; Take a look at the README file which comes with this file.
75 ;; modified to remove eval-when-compile form. Surrounding
76 ;; the eval-when-compile prevernts imaxima from running
77 ;; properly in the xemacs on cygwin environment.
78 (require 'imaxima-autoconf-variables
)
84 (require 'mylatex.ltx
)
88 (defalias 'imaxima-image-type-available-p
89 (if (fboundp 'image-type-available-p
)
90 'image-type-available-p
93 (defalias 'imaxima-display-pixel-width
94 (if (fboundp 'display-pixel-width
)
98 (defalias 'imaxima-display-pixel-height
99 (if (fboundp 'display-pixel-height
)
100 'display-pixel-height
101 'device-pixel-height
))
103 (defalias 'imaxima-display-mm-width
104 (if (fboundp 'display-mm-width
)
108 (defalias 'imaxima-display-mm-height
109 (if (fboundp 'display-mm-height
)
113 (defalias 'imaxima-get-window-width
114 (if (featurep 'xemacs
)
115 'imaxima-get-window-width-xemacs
116 'imaxima-get-window-width-emacs
))
118 (defalias 'imaxima-color-values
119 (if (fboundp 'color-values
)
121 '(lambda (color) (color-rgb-components
123 (make-color-specifier color
)
126 (defun imaxima-get-bg-color ()
127 (if (featurep 'xemacs
)
128 (face-property 'default
'background
)
129 (frame-parameter nil
'background-color
)))
131 (defun imaxima-get-fg-color ()
132 (if (featurep 'xemacs
)
133 (face-property 'default
'foreground
)
134 (frame-parameter nil
'foreground-color
)))
136 ;; XEmacs doesn't have subst-char-in-string (sigh!).
138 (defun imaxima-subst-char-in-string (fromchar tochar string
&optional inplace
)
139 "Replace FROMCHAR with TOCHAR in STRING each time it occurs.
140 Unless optional argument INPLACE is non-nil, return a new string."
141 (let ((i (length string
))
142 (newstr (if inplace string
(copy-sequence string
))))
145 (if (eq (aref newstr i
) fromchar
)
146 (aset newstr i tochar
)))
150 (defconst imaxima-mouse2
(if (featurep 'xemacs
)
154 (defconst imaxima-mouse3 (if (featurep 'xemacs)
160 (defgroup imaxima nil
161 "Image support for Maxima."
163 :link '(url-link "https://maxima.sourceforge.net/")
164 :link '(custom-manual "(imaxima)")
168 (defvar process-connection-type-flag
169 (if (eql system-type 'darwin) t nil))
171 (defvar imaxima-image-types '(png postscript jpeg tiff))
173 (defcustom imaxima-image-type 'png
174 "Image type to used in Maxima buffer."
177 (mapcar (lambda (type) (list 'const type))
178 (cl-remove-if-not 'imaxima-image-type-available-p
179 imaxima-image-types))))
181 (defcustom imaxima-pt-size 11
182 "*Point size used in LaTeX."
184 :type '(choice (const 9)
189 (defcustom imaxima-fnt-size "normalsize"
190 "*Default size of font."
192 :type '(choice (const "small")
200 (defcustom imaxima-scale-factor 1.0
201 "*All images are scaled by this factor."
205 (defcustom imaxima-label-color "red"
206 "*Color used in output labels."
210 (defcustom imaxima-equation-color (imaxima-get-fg-color)
211 "*Color used for equations."
215 (defcustom imaxima-bg-color nil
216 "Background color of imaxima buffer."
218 :type '(choice (color)
219 (const :tag "None" nil)))
221 (defcustom imaxima-fg-color nil
222 "Foreground color of imaxima buffer."
224 :type '(choice (color)
225 (const :tag "None" nil)))
227 (defcustom imaxima-latex-preamble ""
228 "*String inserted at the start of the document preamble.
229 This can be used to change, say, the document font.
230 E.g. `\\usepackage{concrete}' will use the Euler math fonts."
234 (defcustom imaxima-max-scale 0.85
235 "Maximum amount of scaling allowed to fit wide equations in the buffer.
236 nil means no scaling at all, t allows any scaling."
240 (defcustom imaxima-linearize-flag t
241 "Non-nil means that equations too wide to fit in the buffer are linearized."
245 (defcustom imaxima-use-maxima-mode-flag nil
246 "Non-nil means that the major mode from `maxima.el' is used."
250 (defcustom imaxima-maxima-program "maxima"
256 (defcustom imaxima-initex-option "-ini"
257 "Option passed to TeX to start initex."
261 (defcustom imaxima-tex-program "latex"
266 (defcustom imaxima-gs-program "gs"
267 "Ghostscript executable."
271 (defcustom imaxima-gs-options '("-q" "-dNOPAUSE"
274 "-DNOPLATFONTS" "-dTextAlphaBits=4"
275 "-dGraphicsAlphaBits=4")
276 "Options passed to gs for conversion from EPS."
278 :type '(repeat string))
280 (defcustom imaxima-dvips-program "dvips"
285 (defcustom imaxima-cp-program "cp"
290 (defcustom imaxima-dvips-options '("-E" "-R")
291 "Options passed to dvips for conversion from DVI to EPS."
293 :type '(repeat string))
295 (defcustom imaxima-tmp-dir
296 (cond ((featurep 'xemacs)
298 ((eql system-type 'cygwin)
300 (t temporary-file-directory))
301 "*Directory used for temporary TeX and image files."
305 (defcustom imaxima-startup-hook nil
306 "A hook called at startup.
307 This hook is called after imaxima has started Maxima."
311 (defcustom imaxima-exit-hook nil
312 "Hook called when exiting imaxima."
316 (defvar imaxima-tmp-subdir ""
317 "Subdirectory for temporary files.")
319 (defcustom imaxima-lisp-file
320 (if (eq system-type 'windows-nt)
321 (imaxima-subst-char-in-string ?\\ ?/ (locate-library "imaxima.lisp"))
322 (locate-library "imaxima.lisp"))
323 "Location of `imaxima.lisp'."
327 (defcustom imaxima-maxima-options
328 (format "--preload-lisp=%s" imaxima-lisp-file)
329 "Arguments passed to Maxima."
333 (defcustom imaxima-latex-buffer-name
335 "Default name of buffer created by `imaxima-latex'."
339 (defcustom imaxima-latex-document-class
340 '("\\documentclass[%dpt,leqno]{article}" imaxima-pt-size)
341 "Default documentclass used by `imaxima-latex'. It should be a
342 valid argument to `format'."
346 (defcustom imaxima-latex-use-packages
348 \\usepackage{verbatim}
350 \\usepackage{exscale}
351 \\usepackage{amsmath}
352 \\usepackage[cmbase]{flexisym}
354 \\setkeys{breqn}{compact}
356 "Default latex packages and configuration used by `imaxima-latex'."
360 (defcustom imaxima-latex-document-dimensions
362 \\setlength{\\textwidth}{180mm}
363 \\setlength{\\oddsidemargin}{15mm}
364 \\addtolength{\\oddsidemargin}{-1in}
365 \\setlength{\\evensidemargin}{15mm}
366 \\addtolength{\\evensidemargin}{-1in}
368 "Default dimensions of document created by `imaxima-latex'."
372 (defcustom imaxima-latex-macros
374 \\newcommand{\\ifrac}[2]{\\frac{#1}{#2}}
375 \\newcommand{\\ifracd}[2]{\\frac{#1}{#2}}
376 \\newcommand{\\ifracn}[2]{\\frac{#1}{#2}}
377 \\newcommand{\\isubscript}[2]{{#1}_{#2}}
378 \\newcommand{\\iexpt}[2]{{#1}^{#2}}
379 \\newcommand{\\isqrt}[1]{\\sqrt{#1}}
381 "Default macros used by `imaxima-latex'."
385 (defcustom imaxima-latex-macros-linear
387 ;; braces in both denominator and numerator
388 "\\renewcommand{\\ifrac}[2]{\\left(#1\\right)/\\left(#2\\right)}"
389 ;; only braces denominator
390 "\\renewcommand{\\ifracd}[2]{#1/\\left(#2\\right)}"
391 ;; only braces in numerator
392 "\\renewcommand{\\ifracn}[2]{\\left(#1\\right)/#2}"
393 "\\renewcommand{\\isubscript}[2]{\\mathrm{subscript}\\left(#1,#2\\right)}"
394 "\\renewcommand{\\iexpt}[2]{\\mathrm{expt}\\left(#1,#2\\right)}"
395 "\\renewcommand{\\isqrt}[1]{\\left(#1\\right)^{1/2}}\n")
396 "Default linear macros used by `imaxima-latex'."
400 (defcustom imaxima-latex-macros-format-file
403 \\setlength{\\textheight}{200cm}
404 %% define \\boxed from amsmath.sty
406 \\providecommand\\boxed{}
407 \\providecommand\\operatorname{}
408 \\renewcommand{\\boxed}[1]{\\fbox{\\m@th$\\displaystyle#1$}}
409 \\renewcommand{\\operatorname}[1]{%
410 \\mathop{\\relax\\kern\\z@\\operator@font{#1}}}
413 "Default macros used by `imaxima-dump-tex'."
417 (defcustom imaxima-create-image-options
418 '(:ascent center :mask (heuristic (color-values imaxima-bg-color)))
419 "Optional arguments passed to `imaxima-create-image'"
423 (defcustom imaxima-latex-includegraphics
424 "\\includegraphics{%s}\n"
425 "Includegraphics command."
429 (defface imaxima-latex-error-face
430 '((t (:foreground "Blue" :underline t)))
431 "Face used for LaTeX errors."
434 (defvar imaxima-image-creators
436 (png ("-sDEVICE=png16m"))
437 (jpeg ("-sDEVICE=jpeg"))
438 (tiff ("-sDEVICE=tiffpack")))
439 "Define functions for generating images.
440 Argument list is passed to gs.")
442 (defvar imaxima-resolution nil
443 "Screen resolution where rendering started.
444 Cons-cell of x and y resolution, given in
445 dots per inch. Buffer-local to rendering buffer.")
446 (make-variable-buffer-local 'imaxima-resolution)
448 (defvar imaxima-output ""
449 "Accumulator for `imaxima-filter'.")
451 (defvar imaxima-gs-output ""
452 "Accumulator for `imaxima-gs-filter'.")
454 (defvar imaxima-process nil)
455 (defvar imaxima-gs-process nil)
456 (defvar imaxima-gs-computing-p nil)
457 (defvar imaxima-gs-7.05-is-broken nil)
459 (defvar imaxima-error-map (make-sparse-keymap)
460 "Keymap for mouse clicks on LaTeX errors.")
462 (defvar imaxima-old-bg-color nil
463 "Old background color.")
465 (defvar imaxima-old-fg-color nil
466 "Old foreground color.")
468 (defvar imaxima-file-counter 0
469 "Counter used for naming temp files.")
471 (defvar imaxima-html-dir "~/")
473 (defvar imaxima-image-map
474 (let ((map (make-sparse-keymap)))
475 (set-keymap-parent map image-map)
476 (define-key map "l" #'imaxima-get-latex-src)
477 (define-key map "g" #'imaxima-gnuplot-replot)
478 (define-key map "s" #'imaxima-gnuplot-restart)
480 "Keymap for images in the `imaxima' buffer. The `image-map' is
483 (defcustom imaxima-latex-src-register ?l
484 "The register used by `imaxima-get-latex-src' to save the latex
485 source code for the image under point."
489 (defcustom imaxima-gnuplot-replot-term nil
490 "The default gnuplot terminal used by `imaxima-gnuplot-replot'
491 to replot a figure in an external window."
493 :type '(choice (string :tag "Terminal") (symbol :tag "nil" nil)))
499 (defun imaxima-version ()
500 "Print the package name and the version in the mini buffer"
502 (message "%s %s" *imaxima-autoconf-package* *imaxima-autoconf-version*))
508 (defvar imaxima-filter-running nil)
509 (defvar imaxima-continuation nil
510 "The variable is used between `maxima-to-image' and `get-image-from-imaxima' in `imath-mode'.
511 It is used in `imaxima-filter' and `imaxima-filter1' in `imaxima'.
513 The value is either nil or a list of (function buffer pos1 pos2),
514 where pos1 and pos2 are the beginning and end of current maxima
518 (defun reinit-imaxima ()
519 "Re-initialize imaxima"
521 (setq imaxima-filter-running nil
523 imaxima-continuation nil))
529 (defun imaxima-get-geometry (buffer)
530 "Transfer display geometry parameters from current display.
531 Those are put in local variable `imaxima-resolution'. Calculation is done
532 in source buffer specified by BUFF."
534 (with-current-buffer buffer
535 (setq res (cons (/ (* 25.4 (imaxima-display-pixel-width))
536 (imaxima-display-mm-width))
537 (/ (* 25.4 (imaxima-display-pixel-height))
538 (imaxima-display-mm-height)))))
539 (setq imaxima-resolution res)))
541 (defun imaxima-get-window-width-xemacs ()
542 "Return window width in mm.
544 (/ (* (window-text-area-pixel-width) (imaxima-display-mm-width))
545 (imaxima-display-pixel-width)))
547 (defun imaxima-get-window-width-emacs ()
548 "Return window width in mm.
550 (/ (* (- (window-width) 1) (frame-char-width))
551 (/ (float (imaxima-display-pixel-width))
552 (imaxima-display-mm-width))))
554 (defun imaxima-bp-to-mm (bp)
555 "Convert PostScript big points to mm. BP is size in big points."
558 (defun imaxima-color-to-rgb (str)
559 "Convert color name STR to rgb values understood by TeX."
560 (mapcar #'(lambda (x) (/ x 65535.0)) (imaxima-color-values str)))
562 (defmacro imaxima-with-temp-dir (dir &rest body)
563 "Change to DIR temporarily and execute BODY."
564 (let ((wd (make-symbol "wd")))
565 `(let ((,wd default-directory))
572 (defvar imaxima-silence-filter nil)
573 (defmacro imaxima-with-no-new-input-prompt (&rest body)
574 "Set `imaxima-silence-filter' to t to silence any output
575 through `imaxima-filter'."
576 `(progn (setq imaxima-silence-filter t) ,@body))
582 (defun imaxima-gs-filter (process str)
583 "Set `imaxima-gs-computing-p' to t when gs is done."
584 (setq imaxima-gs-output (concat imaxima-gs-output str))
585 (when (string-match "GS\\(<[0-9+]\\)?>" imaxima-gs-output)
586 (setq imaxima-gs-computing-p nil)
587 (setq imaxima-gs-output "")))
589 (defun imaxima-gs-wait ()
590 "Wait for gs to finish."
591 (while (and imaxima-gs-computing-p
592 (eq (process-status imaxima-gs-process) 'run))
593 (accept-process-output imaxima-gs-process 1)))
595 (defun imaxima-start-gs ()
596 "Start Ghostscript as an asynchronyous process."
597 ;; Are we using the broken GNU Ghostscript 7.05?
598 (setq imaxima-gs-7.05-is-broken
599 (string-match "\\(GNU\\|ESP\\) Ghostscript 7.05"
600 (shell-command-to-string
601 (concat imaxima-gs-program " --help"))))
603 (type (cadr (assq imaxima-image-type imaxima-image-creators)))
604 (gs-args (append imaxima-gs-options
606 (list (format "-r%gx%g" (car imaxima-resolution)
607 (cdr imaxima-resolution))))))
608 (when (and imaxima-gs-process
609 (processp imaxima-gs-process))
610 (delete-process imaxima-gs-process))
611 (setq imaxima-gs-computing-p t)
613 (setq imaxima-gs-process (apply 'start-process "imaxima-gs"
614 " *imaxima gs output*"
615 imaxima-gs-program gs-args))
617 "Sorry, Ghostscript could not be started. Please check
618 that you have gs in your path or customize the value of
619 `imaxima-gs-program' (current values is \"%s\").
622 (if (imaxima-image-type-available-p 'postscript)
623 "If Ghostscript isn't installed you can set `imaxima-image-type' to `ps'."
624 ;; don't offer this advice in XEmacs, which doesn't support ps.
626 (set-process-filter imaxima-gs-process 'imaxima-gs-filter)
628 (set-process-query-on-exit-flag imaxima-gs-process nil)
629 (unless (eq (process-status imaxima-gs-process) 'run)
630 (setq output (shell-command-to-string (concat imaxima-gs-program " -h")))
632 ((null (string-match (car type) output))
634 "Your version Ghostscript does not appear to support the image type %s.
635 The command \"gs -h\" lists the available devices.
636 You can change the image type in `imaxima-image-type' or the device name
637 associated with an image type in `imaxma-image-creators'" (car type)))
639 "Some of the options passed to Ghostscript are probably not supported
640 by your version. In particular \"-dTextAlphaBits=4\" and \"-dGraphicsAlphaBits=4\"
641 are not supported by gs 5.5 or earlier. Please edit `imaxima-gs-options'"))))))
643 (defun imaxima-extract-bb (filename)
644 "Extract EPS bounding box vector from FILENAME.
645 Returns a list of bounding box, width, and height."
647 (insert-file-contents-literally filename nil 0 1024 t)
648 (goto-char (point-min))
649 (when (search-forward-regexp "%%BoundingBox:\
653 +\\([-+]?[0-9.]+\\)" nil t)
656 (floor (string-to-number (match-string 1)))
657 (floor (string-to-number (match-string 2)))
658 (ceiling (string-to-number (match-string 3)))
659 (ceiling (string-to-number (match-string 4))))))
661 (- (aref bb 2) (aref bb 0))
662 (- (aref bb 3) (aref bb 1)))))))
664 (defun imaxima-eps-scale (file bb scale)
665 "Scale the eps image in FILE with factor SCALE.
666 BB is the bounding box of the image. Returns a list of new bounding
667 box, width, and height."
668 (cl-multiple-value-bind (llx lly urx ury) (append bb nil)
669 (let ((x (round (* (- urx llx) scale)))
670 (y (round (* (- ury lly) scale)))
671 (buff (find-file-noselect file)))
673 (with-current-buffer buff
674 (goto-char (point-min))
675 (search-forward "%%BoundingBox")
676 (delete-region (line-beginning-position) (line-end-position))
677 (insert (format "%%%%BoundingBox: 0 0 %d %d\n" x y))
678 (search-forward "%%EndComments")
680 (insert "%%BeginProcSet: imaxima 1 0\ngsave\n")
681 (insert (format "%f %f translate\n"
684 (insert (format "%f %f scale\n" scale scale))
685 (insert "%%EndProcSet\n")
686 (goto-char (point-max))
687 (insert "\ngrestore\n")
690 (list (vector 0 0 x y) x y))))
692 (defun imaxima-latex-document-class ()
693 (apply #'format (mapcar #'eval imaxima-latex-document-class)))
695 (defun imaxima-latex ()
696 "Convert Maxima buffer to LaTeX.
697 This command does not work in XEmacs."
699 (let (pos2 label (pos (make-marker))
700 (buf (generate-new-buffer imaxima-latex-buffer-name))
701 (oldbuf (current-buffer)))
703 (insert (imaxima-latex-document-class) "\n"
704 imaxima-latex-use-packages "\n"
705 imaxima-latex-document-dimensions "\n"
706 imaxima-latex-macros "\n"
707 "\\begin{document}\n"
710 (insert-buffer-substring oldbuf))
712 (let* ((region-start (copy-marker (point)))
713 (region-end (copy-marker (next-single-property-change (point) 'display nil (point-max))))
714 (text-prop (get-text-property region-start 'display))
715 (latex-prop (get-text-property region-start 'latex)))
718 (delete-region region-start region-end)
719 (goto-char region-start)
720 (insert (concat latex-prop "\n\n")))
722 (goto-char region-start)
723 (insert "\n\\begin{verbatim}\n")
724 (goto-char region-end)
725 (insert "\n\\end{verbatim}\n\n")))))
726 (insert "\n\\end{document}")
727 (switch-to-buffer-other-window buf)
730 (defun imaxima-process-sentinel (process event)
731 "Process sentinel for Maxima process."
732 (message "Process %s %s" process event)
733 (unless (eq (process-status process) 'run)
736 (defun imaxima-restart-gs ()
737 "Kill Ghostscript process and start a new one."
738 (kill-process imaxima-gs-process)
741 (defun imaxima-maybe-restart-gs ()
742 "Unless `imaxima-gs-process' is running, call
743 `imaxima-start-gs' to (re)start GS."
744 (unless (and (processp imaxima-gs-process)
745 (eq (process-status imaxima-gs-process) 'run))
748 (defun imaxima-ps-to-image (psfilename filename bb width height)
749 "Convert eps file PSFILENAME to a bitmap image file FILENAME.
750 BB is the bounding box for eps image. WIDTH and HEIGHT are the
751 dimensions of the image."
752 (imaxima-maybe-restart-gs)
753 (setq imaxima-gs-computing-p t)
754 (when (eq system-type 'windows-nt)
755 (setq psfilename (imaxima-subst-char-in-string ?\\ ?/ psfilename))
756 (setq filename (imaxima-subst-char-in-string ?\\ ?/ filename)))
757 (process-send-string imaxima-gs-process
759 (if imaxima-gs-7.05-is-broken
760 "clear /imaxima-state save def \
761 << /PageSize [%d %d] /PageOffset [%d %d] /OutputFile (%s) >> \
762 setpagedevice (%s) run imaxima-state restore\n"
765 /PageSize [%d %d] /PageOffset [%d %d] /OutputFile (%s) \
766 >> setpagedevice [save] (%s) (r) file cvx \
767 systemdict /.runandhide known revision 700 ge and {.setsafe {.runandhide}} if \
768 stopped {handleerror quit} if count 1 ne {quit} if \
769 cleardictstack 0 get restore\n")
778 (defvar imaxima-latex-src nil)
780 (defun imaxima-check-plot-output (str)
781 "If the str is in the form ^Wpompt^W\\verb|plotfile filename|, then
782 filename is returned. Else, nil is returned."
783 ;; (if (string-match "\x17[^\x17]*\x17\\\\mathrm{wxxmltag}\\\\left\(\\\\verb|\\([^|]*\\)|.*" str)
784 ;; (if (string-match "\x17[^\x17]*\x17\\\\mathrm{wxxmltag}\\\\left[^/]*\\(.*\.eps\\).*" str)
785 ;; (if (string-match "\x17[^\x17]*\x17\\\\mathrm{wxxmltag}\\\\left\(\\\\verb|*\\(.*\.eps\\).*" str)
786 (when (string-match "\x17[^\x17]*\x17\\\\mathrm{wxxmltag}\\\\left\(\\(\\\\verb|\\)*\\(.*\.eps\\).*" str)
787 (let ((plot-file (match-string 2 str)))
788 (setq imaxima-latex-src (format imaxima-latex-includegraphics plot-file))
791 (defun imaxima-create-image (filename type &rest options)
792 (apply #'create-image (append (list filename type) options imaxima-create-image-options)))
794 (defun imaxima-make-image (str eps-or-latex &optional no-label-p)
795 "Make image from STR. If no-label-p is specified t,
796 label becomes nil and passed to imaxima-tex-to-dvi."
797 (let ((res (imaxima-check-plot-output str)))
802 (let* ((filename (expand-file-name
803 (number-to-string (cl-incf imaxima-file-counter))
805 (psfilename (concat filename ".ps"))
808 (cond ((eql eps-or-latex 'latex)
809 (when (string-match "\\(\x17\\([^\x17]*\\)\x17\\)" str)
810 (setq label (match-string 2 str))
811 (setq str (replace-match "" t t str 1)))
812 (if no-label-p (setq label nil)) ;; override label to nil if no-label-p
813 (imaxima-tex-to-dvi str label (concat filename ".tex"))
814 (imaxima-dvi-to-ps filename)
816 ((eql eps-or-latex 'eps)
817 (copy-file str psfilename)
821 (if (not (file-exists-p psfilename))
822 (imaxima-latex-error str filename)
823 (cl-multiple-value-bind (bb width height)
824 (imaxima-extract-bb psfilename)
825 (let ((ratio (/ (imaxima-get-window-width)
826 (imaxima-bp-to-mm width))))
828 ;; image is wider than the buffer
829 (if (or (eql eps-or-latex 'eps)
830 (and imaxima-max-scale
831 (or (eq imaxima-max-scale t)
832 (> ratio imaxima-max-scale))))
834 (cl-multiple-value-setq (bb width height)
835 (imaxima-eps-scale psfilename bb ratio))
836 (when imaxima-linearize-flag
838 (imaxima-tex-to-dvi str label (concat filename ".tex") t)
839 (imaxima-dvi-to-ps filename)
840 (cl-multiple-value-setq (bb width height)
841 (imaxima-extract-bb psfilename))))))
842 (unless (eq imaxima-image-type 'postscript)
843 (imaxima-ps-to-image psfilename filename bb width height)
845 ;; Ghostscript on Windows doesn't flush the image to the file.
846 ;; So we have to kill the process and restart. What a kludge!
847 (when (eq system-type 'windows-nt)
848 (imaxima-restart-gs)))
849 (cond ((featurep 'xemacs)
851 (when (eq system-type 'windows-nt)
852 (imaxima-restart-gs))
853 (xemacs-set-imagefile-properties filename imaxima-image-type str))
856 (propertize (concat "(" label ") " str) 'display
857 (apply #'imaxima-create-image
858 (if (eq imaxima-image-type 'postscript)
859 (list psfilename imaxima-image-type nil (list :pt-width width :pt-height height :bounding-box bb))
860 (list filename imaxima-image-type nil)))
861 'keymap imaxima-image-map
862 'help-echo "o: save to file\ng: replot in window\nl: get latex source\nr: rotate by 90° clockwise\ns: restart gnuplot\n+: increase size by 20%\n-: decrease size by 20%"
863 'latex imaxima-latex-src)
864 (setq imaxima-latex-src nil))))))))
867 (defun imaxima-latex-error (str filename)
868 "Make clickable error message.
869 STR is offending LaTeX expression. FILENAME is name of the LaTeX file."
870 (let* ((msg "LaTeX error in: ")
871 (delim (if (featurep 'xemacs)
875 (error-text (concat "mouse-2: view LaTeX error log" delim
876 "mouse-3: view LaTeX source")))
877 (fset 'imaxima-error-2
880 (view-file-other-window (concat ,filename ".log"))))
881 (fset 'imaxima-error-3
884 (view-file-other-window (concat ,filename ".tex"))))
885 (define-key imaxima-error-map imaxima-mouse2 'imaxima-error-2)
886 (define-key imaxima-error-map [(return)] 'imaxima-error-2)
887 (define-key imaxima-error-map imaxima-mouse3 'imaxima-error-3)
888 (define-key imaxima-error-map [(meta return)] 'imaxima-error-3)
889 (set-text-properties 0 14 `(face imaxima-latex-error-face
891 help-echo ,error-text
892 keymap ,imaxima-error-map)
896 (defun imaxima-dump-tex ()
897 "Dump a TeX format file preloaded with the required packages."
899 (with-temp-file (expand-file-name "mylatex.ltx" imaxima-tmp-subdir)
900 (insert imaxima-mylatex)))
901 (with-temp-file (expand-file-name "format.tex" imaxima-tmp-subdir)
903 (imaxima-latex-document-class)
904 imaxima-latex-preamble "\n"
905 imaxima-latex-use-packages "\n"
906 imaxima-latex-macros-format-file "\n"
907 imaxima-latex-macros "\n"
908 "\\begin{document}\n"
910 (imaxima-with-temp-dir
912 (apply #'call-process imaxima-tex-program nil nil nil
913 (list imaxima-initex-option "&latex" "mylatex.ltx" "format"))))
915 (defun imaxima-latex-set-textwidth ()
916 (format "\\setlength{\\textwidth}{%dmm}\n"
917 (round (/ (imaxima-get-window-width)
918 imaxima-scale-factor))))
919 (defun imaxima-latex-set-pagecolor ()
920 (apply #'format "\\pagecolor[rgb]{%f,%f,%f}\n"
921 (imaxima-color-to-rgb (imaxima-get-bg-color))))
922 (defun imaxima-latex-set-labelcolor ()
923 (apply #'format "\\color[rgb]{%f,%f,%f}\n"
924 (imaxima-color-to-rgb imaxima-label-color)))
925 (defun imaxima-latex-format-label (str label)
927 (format "\\begin{dmath}[number={%s}]\n" label)
928 (apply #'format "\\color[rgb]{%f,%f,%f}\n"
929 (imaxima-color-to-rgb imaxima-equation-color))
930 str (format "\n\\end{dmath}\n")))
931 (defun imaxima-latex-format-output (str)
933 (apply #'format "\\color[rgb]{%f,%f,%f}\n"
934 (imaxima-color-to-rgb imaxima-equation-color))
935 "\\begin{math} \\displaystyle \n" str (format "\n\\end{math}\n")))
936 (defun imaxima-get-latex-src ()
938 (set-register imaxima-latex-src-register (get-text-property (point) 'latex)))
940 ;;;;;;;;;;;;;;;;;;;; GNUPLOT Support ;;;;;;;;;;;;;;;;;;;;
941 (defun imaxima-get-gnuplot-file ()
943 (let ((src (get-text-property (point) 'latex)))
944 (if (string-match (format "\\(%s/maxout_[0-9]+\\)" imaxima-tmp-subdir) src)
945 (concat (match-string 1 src) ".gnuplot"))))
947 (defcustom imaxima-gnuplot-buffer "*imaxima-gnuplot*"
948 "Name of the buffer created by `imaxima-start-gnuplot' and used by `imaxima-gnuplot-replot'. The sentinel `imaxima-gnuplot-sentinel' monitors the `gnuplot' process in this buffer.")
949 (defcustom imaxima-gnuplot-command "gnuplot"
950 "Name, or complete pathname, of the `gnuplot' binary. Used by `imaxima-start-gnuplot'.")
951 (defcustom imaxima-gnuplot-args ""
952 "Optional arguments passed to the `gnuplot' binary when started by `imaxima-start-gnuplot'.")
953 (defvar imaxima-gnuplot-process nil
954 "A holder for the `gnuplot' process started in `imaxima-start-gnuplot'.")
956 (defun imaxima-gnuplot-sentinel (process desc)
957 (let ((state (process-status process)))
958 (message "imaxima-gnuplot-sentinel: state: %s\ndescription: %s" state desc)))
959 (defun imaxima-start-gnuplot ()
960 (save-mark-and-excursion
961 (let* ((gbuf (get-buffer-create imaxima-gnuplot-buffer))
962 (proc (and gbuf (get-buffer-process gbuf)))
963 (state (and proc (process-status proc))))
964 (cond ((and gbuf (eq state 'run))
965 (message "Gnuplot running."))
967 (message "Re-starting gnuplot...")
968 (setq imaxima-gnuplot-process (start-process (buffer-name gbuf) gbuf imaxima-gnuplot-command "-" imaxima-gnuplot-args)))
970 ;; gbuf does not exist
971 (error "Failed to create buffer %s to run %s. Stop." imaxima-gnuplot-buffer imaxima-gnuplot-command)))
972 (if (and gbuf imaxima-gnuplot-process)
973 (set-process-sentinel imaxima-gnuplot-process #'imaxima-gnuplot-sentinel)
974 (error "imaxima-start-gnuplot failed.")))))
976 (defun imaxima-gnuplot-restart ()
977 "Forcibly restart `gnuplot' process."
979 (let ((kill-buffer-query-functions '())
980 (kill-buffer-hook '()))
981 (if (get-buffer imaxima-gnuplot-buffer) (kill-buffer imaxima-gnuplot-buffer)))
982 (imaxima-start-gnuplot))
984 (defun imaxima-gnuplot-replot ()
985 "Replot the Gnuplot graph under point in an external
986 window. Suppress a new input prompt."
988 (imaxima-start-gnuplot)
989 (let ((term (or imaxima-gnuplot-replot-term (read-from-minibuffer "Terminal? "))))
990 (when (and (null imaxima-gnuplot-replot-term) (y-or-n-p "Save this as the session default? "))
991 (setq imaxima-gnuplot-replot-term term))
992 (let ((gplt-src (imaxima-get-gnuplot-file)))
994 (message "file=%s" gplt-src)
995 (save-mark-and-excursion
996 (with-temp-file gplt-src
997 (insert-file-contents gplt-src)
998 (goto-char (point-min))
999 (while (re-search-forward "^set term.+" nil t)
1000 (replace-match "# \\&")
1001 (insert (concat "\nset terminal " term)))
1002 (goto-char (point-min))
1003 (while (re-search-forward "^set out.+" nil t)
1004 (replace-match "# \\&")))
1005 (with-current-buffer imaxima-gnuplot-buffer
1006 (comint-send-string imaxima-gnuplot-process (concat "load \"" (shell-quote-argument gplt-src) "\"\n")))
1009 (defvar imaxima-latex-src nil "The LaTeX code to generate the
1010 current image. Used by `imaxima-make-image' to set the `latex'
1011 property of the inserted text/image.")
1013 (defun imaxima-tex-to-dvi (str label filename &optional linear)
1015 Argument LABEL is used as equation label. FILENAME is used for
1016 temporary files. Use linearized form if LINEAR is non-nil."
1019 (imaxima-latex-set-pagecolor)
1020 "\\pagestyle{empty}\n"
1021 (format "\\begin{%s}\n" imaxima-fnt-size)
1022 (imaxima-latex-set-labelcolor)
1024 (imaxima-latex-format-label str label)
1025 (imaxima-latex-format-output str))
1026 (format "\\end{%s}\n" imaxima-fnt-size))))
1027 (setq imaxima-latex-src latex-src)
1028 (with-temp-file filename
1030 (imaxima-latex-document-class)
1031 "\n% mylatex\n" ; magic string
1032 (imaxima-latex-set-textwidth)
1033 (if linear imaxima-latex-macros-linear "")
1034 "\\begin{document}\n"
1037 (imaxima-with-temp-dir imaxima-tmp-subdir
1038 (apply 'call-process imaxima-tex-program nil nil nil
1039 (list "&mylatex" filename)))))
1041 (defun imaxima-dvi-to-ps (filename)
1042 "Convert dvi file FILENAME to PostScript."
1043 (let ((dvips-args (append
1044 imaxima-dvips-options
1045 (list "-x" (format "%s" (* imaxima-scale-factor 1000))
1046 "-y" (format "%s" (* imaxima-scale-factor 1000))
1047 (concat filename ".dvi") "-o"))))
1048 (imaxima-with-temp-dir imaxima-tmp-subdir
1049 (apply 'call-process imaxima-dvips-program nil nil nil dvips-args))))
1051 (defun imaxima-clean-up ()
1052 "Kill gs process, delete temporary files and restore colors if applicable."
1055 (kill-process imaxima-gs-process))
1056 (mapc 'delete-file (directory-files imaxima-tmp-subdir t "^[^.].*"))
1057 (delete-directory imaxima-tmp-subdir)
1058 (if (featurep 'xemacs)
1059 (ad-deactivate 'comint-output-filter)
1060 ;; restore frame colors in Emacs
1061 (when imaxima-fg-color
1062 (modify-frame-parameters
1063 nil (list (cons 'foreground-color imaxima-old-fg-color))))
1064 (when imaxima-bg-color
1065 (modify-frame-parameters
1066 nil (list (cons 'background-color imaxima-old-bg-color)))))
1067 (run-hooks 'imaxima-exit-hook))
1069 (defvar *debug-imaxima-filter* nil
1070 "If `*debug-imaxima-filter*' is set to t, the string is
1071 appended to the end of the buffer *imaxima-work*. Used in
1072 `imaxima-filter1' and `debug-imaxima-filter'.")
1074 (defun debug-imaxima-filter (str)
1075 (if *debug-imaxima-filter*
1076 (with-current-buffer (get-buffer-create "*imaxima-work*")
1079 (cl-defun imaxima-filter (str)
1080 "Parse output from Maxima and make image from TeX parts.
1081 Argument STR contains output received from Maxima.
1083 imaxima-filter needs to be written in re-entrant manner.
1084 This is because during the creation of latex image, there
1085 observed a reentrant call of imaxima-filter. yhonda"
1086 (if imaxima-filter-running
1088 (setq imaxima-output (concat imaxima-output str))
1089 (debug-imaxima-filter "reenter")
1090 (cl-return-from imaxima-filter "")))
1091 (setq imaxima-filter-running t)
1092 (debug-imaxima-filter str)
1093 (let* ((len (length str))
1097 (setq imaxima-filter-running nil)
1098 (cl-return-from imaxima-filter ""))
1099 (setq imaxima-output (concat imaxima-output str))
1100 (let ((lastchar (aref str (1- len)))
1102 (when (and (char-equal lastchar ?\n) (> len 1))
1103 (setq lastchar (aref str (- len 2))))
1105 (message "Processing Maxima output...")
1106 (while (not (string= imaxima-output ""))
1107 (let ((1stchar (substring imaxima-output 0 1)))
1108 (cond ((string= 1stchar "\x03")
1109 (if (string-match "\x03\\([^\x03\x04]*\\)\x04\\(\\(.\\|\n\\)*\\)" imaxima-output)
1110 (let ((iprompt (match-string 1 imaxima-output))
1111 (rest (match-string 2 imaxima-output)))
1112 (setq imaxima-output rest)
1113 (setq output (concat output iprompt))
1114 ;; All the output for a maxima command are processed.
1115 ;; We can call imaxima-continuation if necessary.
1116 (cond ((and imaxima-continuation main-output)
1117 (funcall (car imaxima-continuation) main-output))
1118 ((and imaxima-continuation (null main-output))
1119 (funcall (car imaxima-continuation) ""))))
1120 ;; imaxima-output is incomplete.
1121 (setq imaxima-filter-running nil)
1122 (cl-return-from imaxima-filter output)))
1123 ((string= 1stchar "\x02")
1124 (if (string-match "\x02\\([^\x02\x05]*\\)\x05\\(\\(.\\|\n\\)*\\)" imaxima-output)
1125 (let ((match (match-string 1 imaxima-output))
1126 (rest (match-string 2 imaxima-output))
1128 (setq imaxima-output rest)
1129 (setq output (concat output (setq image (imaxima-make-image match 'latex)) "\n"))
1130 ;; Remember the image into main-output if this is the first output.
1131 ;; This will be passed to imaxima-continuation
1132 (if (null main-output)
1133 (setq main-output image)))
1134 ;; imaxima-output is incomplete.
1135 (setq imaxima-filter-running nil)
1136 (cl-return-from imaxima-filter output)))
1137 ((string= 1stchar "\x15")
1138 (if (string-match "\x15\\([^\x15\x16]*\\)\x16\\(\\(.\\|\n\\)*\\)" imaxima-output)
1139 (let ((match (match-string 1 imaxima-output))
1140 (rest (match-string 2 imaxima-output)))
1141 (setq imaxima-output rest)
1142 (setq output (concat output (imaxima-make-image match 'latex) "\n")))
1143 ;; imaxima-output is incomplete.
1144 (setq imaxima-filter-running nil)
1145 (cl-return-from imaxima-filter output)))
1146 (t (if (string-match "\\([^\x02\x03\x15]*\\)\\(\\(.\\|\n\\)*\\)" imaxima-output)
1147 (let ((match (match-string 1 imaxima-output))
1148 (rest (match-string 2 imaxima-output)))
1149 (setq imaxima-output rest)
1150 (setq output (concat output match)))
1151 ;; This should not happen.
1152 (message "Unexpected error encountered in imaxima-filter"))))))
1153 (message "Processing Maxima output...done")
1154 (if imaxima-silence-filter (setq output "" imaxima-silence-filter nil))
1155 (setq imaxima-filter-running nil)
1156 (cl-return-from imaxima-filter output)))))
1158 (defun imaxima-filter1 (str)
1159 "Parse output from Maxima and make image from TeX parts.
1160 Argument STR contains output received from Maxima."
1161 (if *debug-imaxima-filter*
1162 (with-current-buffer (get-buffer-create "*imaxima-work*")
1163 (insert "****new string****
1166 (let* ((len (length str)))
1169 (setq imaxima-output (concat imaxima-output str))
1170 (let ((lastchar (aref str (1- len))))
1171 (when (and (char-equal lastchar ?\n) (> len 1))
1172 (setq lastchar (aref str (- len 2))))
1175 ((string-match "\\`[^\x02\x05\x03\x04\x15\x16]+\\'" imaxima-output)
1176 (prog1 imaxima-output
1177 (setq imaxima-output "")))
1178 ((or (char-equal lastchar ?\x04) (char-equal lastchar ?\x05))
1183 (rest imaxima-output)
1185 (message "Processing Maxima output...")
1186 (if (string-match "\\([^\x03\x04]*\\)\x03\\([^\x03\x04]*\\)\x04$" imaxima-output)
1187 (setq prompt (concat "" (match-string 2 imaxima-output))
1188 rest (match-string 1 imaxima-output)))
1189 (while (string-match "\\(\\([^\x02\x05]*\\)\x02\\([^\x02\x05]*\\)\x05\\)"
1191 (setq text (match-string 2 rest))
1192 (setq match (match-string 3 rest))
1193 (setq rest (replace-match "" t t rest 1))
1194 (setq output (concat output (if (equal output "") "" newline-char) text (imaxima-make-image match 'latex))))
1195 (setq imaxima-output "")
1196 (message "Processing Maxima output...done")
1197 (if imaxima-continuation
1198 (funcall (car imaxima-continuation) output))
1199 (concat output rest prompt)))
1200 ;; Special prompt for demo() function.
1202 ((char-equal lastchar ?_)
1203 (let ((newline-char "
1206 (rest (substring imaxima-output 0 -1))
1208 (message "Processing Maxima output...")
1209 (while (string-match "\\(\\([^\x02\x05]*\\)\x02\\([^\x02\x05]*\\)\x05\\)"
1211 (setq text (match-string 2 rest))
1212 (setq match (match-string 3 rest))
1213 (setq rest (replace-match "" t t rest 1))
1214 (setq output (concat output (if (equal output "") "" newline-char) text (imaxima-make-image match 'latex))))
1215 (setq imaxima-output "")
1216 (message "Processing Maxima output...done")
1217 (if imaxima-continuation
1218 (funcall (car imaxima-continuation) output))
1219 (concat " " output rest newline-char "_")))
1220 ;; Special prompt, question.
1221 ((char-equal lastchar ?\x16)
1222 (string-match "\x15\\([^\x16]*\\)\x16" imaxima-output)
1223 (prog1 (imaxima-make-image (match-string 1 imaxima-output) 'latex)
1224 (setq imaxima-output "")))
1227 (defun xemacs-set-imagefile-properties (filename img-type str)
1228 (let ((ext (make-extent 0 (length str) str)))
1229 (set-extent-property ext 'duplicable t)
1230 (set-extent-end-glyph ext
1231 (make-glyph (vector img-type
1233 (set-extent-property ext 'invisible t)
1234 (set-extent-property ext 'atomic t))
1241 (defun imaxima-setup-preoutput-filter ()
1242 "Set up `comint-preoutput-filter-functions' or the equivalent."
1243 (cond ((featurep 'xemacs)
1244 ;; XEmacs does not have comint-preoutput-filter-functions, so
1245 ;; we have to advice comint-output-filter instead
1246 (defadvice comint-output-filter (before preoutput-filter)
1247 "Run comint-preoutput-filter-functions."
1248 (ad-set-arg 1 (imaxima-filter (ad-get-arg 1))))
1249 (ad-activate 'comint-output-filter))
1251 (make-local-variable 'comint-preoutput-filter-functions)
1252 ;; This doesn't work due to a bug in comint.el
1253 ;; (add-hook 'comint-preoutput-filter-functions 'imaxima-filter nil t)
1254 (add-hook 'comint-preoutput-filter-functions 'imaxima-filter t))))
1256 (defun imaxima-change-color (buf)
1257 "Change background and foreground color if applicable.
1258 BUF is imaxima buffer."
1261 (when imaxima-bg-color
1262 (set-face-background 'default imaxima-bg-color buf))
1263 (when imaxima-fg-color
1264 (set-face-foreground 'default imaxima-fg-color buf)))
1266 (when imaxima-bg-color
1267 (setq imaxima-old-bg-color (frame-parameter nil 'background-color))
1268 (modify-frame-parameters
1269 nil (list (cons 'background-color imaxima-bg-color))))
1270 (when imaxima-fg-color
1271 (setq imaxima-old-fg-color (frame-parameter nil 'foreground-color))
1272 (modify-frame-parameters
1273 nil (list (cons 'foreground-color imaxima-fg-color)))))))
1275 (defun imaxima-setup ()
1276 "Image support for maxima.el."
1277 (let ((mbuf (process-buffer inferior-maxima-process)))
1278 (with-current-buffer mbuf
1279 (imaxima-change-color mbuf)
1280 (imaxima-get-geometry mbuf)
1282 (unless (eq imaxima-image-type 'postscript)
1284 (add-hook 'kill-buffer-hook 'imaxima-clean-up t t)
1285 (imaxima-setup-preoutput-filter)
1286 (imaxima-with-no-new-input-prompt
1287 (comint-send-string mbuf (format ":lisp (progn ($load \"%s\") (msetq $imaxima_tmp_subdir \"%s\"))\n" imaxima-lisp-file imaxima-tmp-subdir)))
1288 ;; maxima mode tries to run inferior-maxima-mode-hook twice
1289 ;; due to changes made in 5.9.2 release. To prevent this,
1290 ;; the following hook must be removed earlier than before.
1292 (remove-hook 'inferior-maxima-mode-hook 'imaxima-setup)
1293 (goto-char (point-max)))))
1295 (cl-defun imaxima-delete-maxima-hooks ()
1296 (remove-hook 'comint-output-filter-functions 'inferior-maxima-output-filter)
1297 (remove-hook 'comint-output-filter-functions 'inferior-maxima-remove-double-input-prompt)
1298 (remove-hook 'comint-output-filter-functions 'inferior-maxima-remove-double-prompt))
1300 (cl-defun imaxima ()
1301 "Image support for Maxima.
1302 \"display2d:true\" in Maxima turns images off, \"display2d:imaxima\"
1303 turns them on. Set `imaxima-use-maxima-mode-flag' to t to use
1306 (if (not window-system)
1307 (error "Emacs in terminal is not supported by Imaxima. You need to run Emacs in a window system, such as X window, Mac OS X, and Microsoft Windows OS."))
1308 (let ((imaxima-buffer))
1309 (setq imaxima-buffer
1310 (get-buffer (if imaxima-use-maxima-mode-flag
1313 (when imaxima-buffer
1314 (if (called-interactively-p 'any)
1315 (switch-to-buffer imaxima-buffer)
1316 (set-buffer imaxima-buffer))
1317 (cl-return-from imaxima t)))
1319 (unless (imaxima-image-type-available-p imaxima-image-type)
1320 (error "Your version of Emacs does not support the image type %s"
1321 imaxima-image-type))
1322 (unless imaxima-lisp-file
1323 (error "The file imaxima.lisp could not be found.
1324 Please customize the option `imaxima-lisp-file'."))
1325 (setq imaxima-file-counter 0)
1327 (setq imaxima-tmp-subdir
1328 (make-temp-name (expand-file-name "imaxima" imaxima-tmp-dir))) t)
1329 (set-file-modes imaxima-tmp-subdir 448) ; 700 in octal
1330 (let ((process-connection-type process-connection-type-flag))
1331 (if imaxima-use-maxima-mode-flag
1334 (setq inferior-maxima-prompt
1335 (concat "\\(^ ?(" maxima-inchar
1336 "[0-9]*) \\)\\|\\(^MAXIMA>+\\)\\|\\(^(dbm:[0-9]*) \\)"))
1337 (add-hook 'inferior-maxima-mode-hook 'imaxima-setup t)
1339 (remove-hook 'inferior-maxima-mode-hook 'imaxima-setup))
1340 (imaxima-delete-maxima-hooks)
1341 (setq imaxima-output "")
1345 imaxima-maxima-program
1348 imaxima-maxima-options))))
1349 (with-current-buffer mbuf
1350 (setq imaxima-process (get-buffer-process mbuf))
1351 (imaxima-get-geometry mbuf)
1352 (imaxima-change-color mbuf)
1354 (set-process-sentinel imaxima-process 'imaxima-process-sentinel)
1355 (imaxima-setup-preoutput-filter)
1356 (unless (eq imaxima-image-type 'postscript)
1357 (imaxima-start-gs)))
1358 (imaxima-with-no-new-input-prompt
1359 (let ((maxima-set-up (list 'progn (list 'msetq '$imaxima_tmp_subdir imaxima-tmp-subdir) "")))
1360 (comint-send-string mbuf (format ":lisp %S\n" maxima-set-up))))
1361 (switch-to-buffer mbuf))))
1362 (run-hooks 'imaxima-startup-hook))
1364 (defcustom imaxima-print-tex-file "imax"
1365 "Name of the LaTeX file name to be created by `imaxima-print-buffer'.
1366 Do not include \".tex\" suffix. This file will be stored in the
1367 directory `imaxima-tmp-dir'."
1371 (defcustom imaxima-print-tex-command
1372 "latex %s; dvips -o imax.ps %s; gv imax.ps"
1373 ;;"latex %s; xdvi %s"
1374 ;;"latex %s; dvipdf %s.dvi imax.pdf; open imax.pdf" for Mac OS X users.
1375 "Command to run LaTeX on the file created by `imaxima-print-buffer'.
1376 In the string %s is replaced by the name of the tex file. e.g.
1377 \"latex %s; xdvi %s\"
1382 (defun imaxima-print-buffer ()
1383 "Run LaTeX on the current buffer and show output.
1384 See `imaxima-print-tex-command' for how latex is run on the latex output."
1386 (let (( tex-file (concat imaxima-tmp-dir
1387 imaxima-print-tex-file ".tex"))
1393 (write-file tex-file)
1394 (setq buf (current-buffer))
1396 ;; Convert all %s into the tex file name.
1397 (setq cmd imaxima-print-tex-command)
1398 (while (string-match "%s" cmd)
1399 (setq cmd (replace-match imaxima-print-tex-file t nil cmd)))
1402 (kill-buffer buf) ;kill the temp tex buffer
1406 ;;; The following codes implements export imath text to HTML.
1408 (defvar html-template
1411 <META HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html; CHARSET=UTF-8\">
1421 (cl-defun prepare-for-translation ()
1422 "If error occurs inside this function, multiple values nil nil
1426 (let (original-buffer text current-buffer-file-name filename image-folder html-buffer)
1427 (setq original-buffer (current-buffer))
1428 (setq text (buffer-substring (point-min) (point-max)))
1429 (if (or (string= (buffer-name original-buffer)
1431 (string= (buffer-name original-buffer)
1434 (setq current-buffer-file-name "")
1435 (setq filename (concat imaxima-html-dir "session.html"))
1436 (setq image-folder "session-images"))
1437 (setq current-buffer-file-name
1438 (if (buffer-file-name)
1440 (cl-return-from prepare-for-translation (cl-values nil nil))))
1441 (setq filename (concat (file-name-sans-extension
1442 (file-name-nondirectory current-buffer-file-name))
1444 (setq image-folder (concat (file-name-sans-extension
1445 (file-name-nondirectory current-buffer-file-name))
1447 ;; HTML buffer preparation
1448 (setq html-buffer (find-file filename))
1449 (set-buffer html-buffer)
1450 ;; create image folder
1452 (if (file-exists-p image-folder)
1453 ;; since image-folder already exists, let's reuse it.
1457 (setq old-files (directory-files image-folder nil "\\.png$"))
1458 ;; we need to delete all the files already there.
1459 (dolist (f old-files)
1460 (delete-file (concat image-folder "/" f))))
1461 (file-error (cl-return-from prepare-for-translation (cl-values nil nil)))))
1462 ;; since image-folder doest not exist, let's create it.
1464 (make-directory image-folder)
1465 (file-error (cl-return-from prepare-for-translation (cl-values nil nil))))))
1466 ;; buffer preparation
1467 (if buffer-read-only
1468 (cl-return-from prepare-for-translation (cl-values nil nil)))
1470 (insert html-template)
1471 (goto-char (point-min))
1472 (search-forward "<BODY>")
1475 (cl-values html-buffer image-folder))))
1477 (cl-defun imath-to-html()
1478 "Translate imath minor mode buffer contents into HTML format."
1481 (cl-multiple-value-bind (html-buffer image-folder)
1482 (prepare-for-translation)
1483 (if (not (and html-buffer image-folder))
1485 (message "Error during HTML buffer preparation.")
1486 (cl-return-from imath-to-html)))
1487 (set-buffer html-buffer)
1488 (goto-char (point-min))
1491 (cl-multiple-value-bind (ftype start-pos end-pos)
1493 (if (not (and ftype start-pos end-pos))
1495 (let (filename dest-name)
1496 ;; copy image file to image sub folder
1497 (if (null (setq filename (get-image-filename (1- (point)))))
1499 (message "Error: all formulas must be converted to images first.")
1500 (cl-return-from imath-to-html)))
1501 (setq dest-name (concat
1503 (file-name-sans-extension
1504 (file-name-nondirectory filename))
1507 (copy-file filename dest-name)
1508 ;; replace imath formula with HTML IMG tag
1509 (delete-region start-pos end-pos)
1510 (insert (concat "<IMG SRC=\""
1512 "\" style=\"vertical-align:middle;\"> "))))))
1513 ;; "\" align=\"middle\"> "))))))
1517 (message "Error: File manipulation failed during processing.")
1518 (cl-return-from imath-to-html))))
1520 (let (start-mark end-mark)
1521 (goto-char (point-min))
1522 (search-forward "<BODY>")
1525 (setq start-mark (point-marker))
1526 (search-forward "</BODY>")
1527 (setq end-mark (point-marker))
1528 (goto-char start-mark)
1530 (re-search-forward "$" end-mark)
1531 (replace-match "<br>\n")
1533 (search-failed nil)))))
1535 (cl-defun imaxima-to-html ()
1536 "Translate the imaxima buffer contents into HTML format."
1540 (cl-defun find-next-formula ()
1541 "Find next formula and return multiple values of
1542 formula type, start position and end position.
1543 If search failed, error search-failed is signaled."
1545 (if (equal (point) (point-max))
1546 (cl-return-from find-next-formula (cl-values nil nil nil)))
1547 (let* ((region-start (copy-marker (point)))
1548 (region-end (copy-marker (next-single-property-change (point) 'display nil (point-max))))
1549 (text-prop (get-text-property region-start 'display)))
1550 (goto-char region-end)
1552 (cl-return-from find-next-formula (cl-values 'any region-start region-end))
1553 (find-next-formula))))
1557 (cl-defun get-image-filename (pos)
1558 "If the pos of the buffer is associated with text a display property,
1559 it is obtained. Then image filename of the display property is
1560 extracted and returned."
1565 (if (setq filename (memq :file (get-text-property pos 'display)))
1566 (second filename))))
1570 ;;; imaxima.el ends here