Windows installer: update Gnuplot
[maxima.git] / interfaces / emacs / imaxima / imaxima.el
blobd30255af855d76a217111b1262d37950faf962c7
1 ;;;; imaxima.el --- Maxima mode with images
3 ;; Copyright (C) 2001, 2002, 2003, 2004 Jesper Harder
5 ;; Author: Jesper Harder <harder@ifa.au.dk>
6 ;; Created: 14 Nov 2001
7 ;; Version: 1.0b
8 ;; Keywords: maxima
10 ;; Copyright (C) 2006 Stephen Eglen (imaxima-print-buffer)
11 ;; Copyright (C) 2007, 2008 Yasuaki Honda (imaxima-to-html, inline graph)
13 ;; $Id: imaxima.el,v 1.7 2009-02-22 09:18:27 yasu-honda Exp $
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., 59 Temple Place, Suite 330, Boston,
28 ;; MA 02111-1307 USA
31 ;;; Commentary:
33 ;; This file (and imaxima.lisp) provides image support for interacting
34 ;; with the computer algebra system Maxima
35 ;; <http://maxima.sourceforge.net/>
37 ;; The command `imaxima' (M-x imaxima) provides a simple comint
38 ;; derived CLI mode.
40 ;; To use imaxima with the Maxima mode from the Maxima distribution
41 ;; set `imaxima-use-maxima-mode-flag' to `t'.
43 ;; To turn off images, evaluate "display2d:true" in Maxima. To turn
44 ;; them on again, evaluate "display2d:imaxima".
46 ;; The command `imaxima-latex' prepares a LaTeX version of the Maxima
47 ;; buffer.
49 ;; The package requires Emacs 21 with image support.
51 ;; A fairly recent version of Ghostscript is recommended (at least
52 ;; newer than v. 8.56). If your version is too old, you can either set
53 ;; `imaxima-image-type' to 'ps or remove the options
54 ;; "-dTextAlphaBits=4" and "-dGraphicsAlphaBits=4" from
55 ;; `imaxima-gs-options'. The images won't look nearly as attractive,
56 ;; though -- the text looks ragged because it isn't anti aliased.
58 ;; The file "imaxima.lisp" is a slightly modified version of
59 ;; "texmacs.lisp" in the TeXmacs distribution. Several of the image
60 ;; routines are borrowed from David Kastrup's preview-latex.el.
62 ;; Version 1.0 beta and later supports inline graph. You can use
63 ;; the following six maxima commands.
64 ;; wxplot2d(), wxplot3d(), wxdraw2d(), wxdraw3d(), wximplicit_plot(),
65 ;; wxcontour_plot().
66 ;; GNUPLOT 4.2 or later is needed for this to work. The resulted image
67 ;; generated by gnuplot will be inserted as the output of the command.
70 ;; Installation:
71 ;; Take a look at the README file which comes with this file.
74 ;;; Code:
76 ;; modified to remove eval-when-compile form. Surrounding
77 ;; the eval-when-compile prevernts imaxima from running
78 ;; properly in the xemacs on cygwin environment.
79 (require 'imaxima-autoconf-variables)
80 (require 'advice)
82 (require 'comint)
83 (require 'cl)
85 ;; XEmacs stuff
87 (defalias 'imaxima-image-type-available-p
88 (if (fboundp 'image-type-available-p)
89 'image-type-available-p
90 'featurep))
92 (defalias 'imaxima-display-pixel-width
93 (if (fboundp 'display-pixel-width)
94 'display-pixel-width
95 'device-pixel-width))
97 (defalias 'imaxima-display-pixel-height
98 (if (fboundp 'display-pixel-height)
99 'display-pixel-height
100 'device-pixel-height))
102 (defalias 'imaxima-display-mm-width
103 (if (fboundp 'display-mm-width)
104 'display-mm-width
105 'device-mm-width))
107 (defalias 'imaxima-display-mm-height
108 (if (fboundp 'display-mm-height)
109 'display-mm-height
110 'device-mm-height))
112 (defalias 'imaxima-get-window-width
113 (if (featurep 'xemacs)
114 'imaxima-get-window-width-xemacs
115 'imaxima-get-window-width-emacs))
117 (defalias 'imaxima-color-values
118 (if (fboundp 'color-values)
119 'color-values
120 '(lambda (color) (color-rgb-components
121 (if (stringp color)
122 (make-color-specifier color)
123 color)))))
125 (defun imaxima-get-bg-color ()
126 (if (featurep 'xemacs)
127 (face-property 'default 'background)
128 (frame-parameter nil 'background-color)))
130 (defun imaxima-get-fg-color ()
131 (if (featurep 'xemacs)
132 (face-property 'default 'foreground)
133 (frame-parameter nil 'foreground-color)))
135 ;; XEmacs doesn't have subst-char-in-string (sigh!).
137 (defun imaxima-subst-char-in-string (fromchar tochar string &optional inplace)
138 "Replace FROMCHAR with TOCHAR in STRING each time it occurs.
139 Unless optional argument INPLACE is non-nil, return a new string."
140 (let ((i (length string))
141 (newstr (if inplace string (copy-sequence string))))
142 (while (> i 0)
143 (setq i (1- i))
144 (if (eq (aref newstr i) fromchar)
145 (aset newstr i tochar)))
146 newstr))
149 (defconst imaxima-mouse2 (if (featurep 'xemacs)
150 [button2]
151 [mouse-2]))
153 (defconst imaxima-mouse3 (if (featurep 'xemacs)
154 [button3]
155 [mouse-3]))
157 ;; Options
159 (defgroup imaxima nil
160 "Image support for Maxima."
161 :version "21.1"
162 :link '(url-link "http://purl.org/harder/imaxima.html")
163 :link '(custom-manual "(imaxima)")
164 :prefix "imaxima-"
165 :group 'maxima)
167 (defvar process-connection-type-flag
168 (if (eql system-type 'darwin) t nil))
170 (defvar imaxima-image-types '(png postscript jpeg tiff))
172 (defcustom imaxima-image-type 'png
173 "Image type to used in Maxima buffer."
174 :group 'imaxima
175 :type (cons 'choice
176 (mapcar (lambda (type) (list 'const type))
177 (remove-if-not 'imaxima-image-type-available-p
178 imaxima-image-types))))
180 (defcustom imaxima-pt-size 11
181 "*Point size used in LaTeX."
182 :group 'imaxima
183 :type '(choice (const 9)
184 (const 10)
185 (const 11)
186 (const 12)))
188 (defcustom imaxima-fnt-size "normalsize"
189 "*Default size of font."
190 :group 'imaxima
191 :type '(choice (const "small")
192 (const "normalsize")
193 (const "large")
194 (const "Large")
195 (const "LARGE")
196 (const "huge")
197 (const "Huge")))
199 (defcustom imaxima-scale-factor 1.0
200 "*All images are scaled by this factor."
201 :group 'imaxima
202 :type 'number)
204 (defcustom imaxima-label-color "red"
205 "*Color used in output labels."
206 :group 'imaxima
207 :type '(color))
209 (defcustom imaxima-equation-color (imaxima-get-fg-color)
210 "*Color used for equations."
211 :group 'imaxima
212 :type '(color))
214 (defcustom imaxima-bg-color nil
215 "Background color of imaxima buffer."
216 :group 'imaxima
217 :type '(choice (color)
218 (const :tag "None" nil)))
220 (defcustom imaxima-fg-color nil
221 "Foreground color of imaxima buffer."
222 :group 'imaxima
223 :type '(choice (color)
224 (const :tag "None" nil)))
226 (defcustom imaxima-latex-preamble ""
227 "*String inserted at the start of the document preamble.
228 This can be used to change, say, the document font.
229 E.g. `\\usepackage{concrete}' will use the Euler math fonts."
230 :group 'imaxima
231 :type '(string))
233 (defcustom imaxima-max-scale 0.85
234 "Maximum amount of scaling allowed to fit wide equations in the buffer.
235 nil means no scaling at all, t allows any scaling."
236 :group 'imaxima
237 :type 'number)
239 (defcustom imaxima-linearize-flag t
240 "Non-nil means that equations too wide to fit in the buffer are linearized."
241 :type '(boolean)
242 :group 'imaxima)
244 (defcustom imaxima-use-maxima-mode-flag nil
245 "Non-nil means that the major mode from `maxima.el' is used."
246 :type '(boolean)
247 :group 'imaxima)
249 (defcustom imaxima-maxima-program "maxima"
250 "Maxima executable."
251 :group 'imaxima
252 :type '(string))
255 (defcustom imaxima-initex-option "-ini"
256 "Option passed to TeX to start initex."
257 :group 'imaxima
258 :type '(string))
260 (defcustom imaxima-tex-program "latex"
261 "TeX executable."
262 :group 'imaxima
263 :type '(string))
265 (defcustom imaxima-gs-program "gs"
266 "Ghostscript executable."
267 :group 'imaxima
268 :type '(string))
270 (defcustom imaxima-gs-options '("-q" "-dNOPAUSE"
271 "-dSAFER"
272 "-dDELAYSAFER"
273 "-DNOPLATFONTS" "-dTextAlphaBits=4"
274 "-dGraphicsAlphaBits=4")
275 "Options passed to gs for conversion from EPS."
276 :group 'imaxima
277 :type '(repeat string))
279 (defcustom imaxima-dvips-program "dvips"
280 "Dvips executable."
281 :group 'imaxima
282 :type '(string))
284 (defcustom imaxima-cp-program "cp"
285 "cp executable."
286 :group 'imaxima
287 :type '(string))
289 (defcustom imaxima-dvips-options '("-E" "-R")
290 "Options passed to dvips for conversion from DVI to EPS."
291 :group 'imaxima
292 :type '(repeat string))
294 (defcustom imaxima-tmp-dir
295 (cond ((featurep 'xemacs)
296 (temp-directory))
297 ((eql system-type 'cygwin)
298 "/tmp/")
299 (t temporary-file-directory))
300 "*Directory used for temporary TeX and image files."
301 :type '(directory)
302 :group 'imaxima)
304 (defcustom imaxima-startup-hook nil
305 "A hook called at startup.
306 This hook is called after imaxima has started Maxima."
307 :group 'imaxima
308 :type 'hook)
310 (defcustom imaxima-exit-hook nil
311 "Hook called when exiting imaxima."
312 :group 'imaxima
313 :type 'hook)
315 (defvar imaxima-tmp-subdir ""
316 "Subdirectory for temporary files.")
318 (defcustom imaxima-lisp-file
319 (if (eq system-type 'windows-nt)
320 (imaxima-subst-char-in-string ?\\ ?/ (locate-library "imaxima.lisp"))
321 (locate-library "imaxima.lisp"))
322 "Location of `imaxima.lisp'."
323 :group 'imaxima
324 :type '(file))
326 (defcustom imaxima-maxima-options
327 (if (eq system-type 'windows-nt)
328 ;; in this case the appropriate value is the empty string.
330 (format "--preload-lisp=%s" imaxima-lisp-file))
331 "Arguments passed to Maxima."
332 :group 'imaxima
333 :type '(string))
335 (defface imaxima-latex-error-face
336 '((t (:foreground "Blue" :underline t)))
337 "Face used for LaTeX errors."
338 :group 'imaxima)
340 (defvar imaxima-image-creators
341 '((postscript nil)
342 (png ("-sDEVICE=png16m"))
343 (jpeg ("-sDEVICE=jpeg"))
344 (tiff ("-sDEVICE=tiffpack")))
345 "Define functions for generating images.
346 Argument list is passed to gs.")
348 (defvar imaxima-resolution nil
349 "Screen resolution where rendering started.
350 Cons-cell of x and y resolution, given in
351 dots per inch. Buffer-local to rendering buffer.")
352 (make-variable-buffer-local 'imaxima-resolution)
354 (defvar imaxima-output ""
355 "Accumulator for `imaxima-filter'.")
357 (defvar imaxima-gs-output ""
358 "Accumulator for `imaxima-gs-filter'.")
360 (defvar imaxima-process nil)
361 (defvar imaxima-gs-process nil)
362 (defvar imaxima-gs-computing-p nil)
363 (defvar imaxima-gs-7.05-is-broken nil)
365 (defvar imaxima-error-map (make-sparse-keymap)
366 "Keymap for mouse clicks on LaTeX errors.")
368 (defvar imaxima-old-bg-color nil
369 "Old background color.")
371 (defvar imaxima-old-fg-color nil
372 "Old foreground color.")
374 (defvar imaxima-file-counter 0
375 "Counter used for naming temp files.")
377 (defvar imaxima-html-dir "~/")
379 ;; This piece of TeX is `mylatex.ltx' by David Carlisle. The license is:
381 ;; "There are no restrictions on the distribution or modification of
382 ;; this file, except that other people should not attempt to alter
383 ;; the master copy on the ctan archives."
385 (defconst imaxima-mylatex
386 "\\makeatletter\\let\\MYLATEXdocument\\document
387 \\let\\MYLATEXopenout\\openout\\def\\document{\\endgroup
388 {\\setbox\\z@\\hbox{\\normalfont% normal
389 {\\ifx\\large\\@undefined\\else\\large\\fi
390 \\ifx\\footnotesize\\@undefined\\else\\footnotesize\\fi}%
391 {\\bfseries\\itshape}% bold and bold italic
392 {\\itshape}\\ttfamily\\sffamily}}%
393 \\let\\document\\MYLATEXdocument\\let\\openout\\MYLATEXopenout
394 \\makeatother\\everyjob\\expandafter{\\the\\everyjob
395 \\begingroup\\listfiles\\expandafter\\MYLATEXcustomised\\@dofilelist
396 \\endgroup}\\@addtofilelist{.}\\catcode`\\\\=13\\relax
397 \\catcode`\\#=12\\relax\\catcode`\\ =9\\relax\\dump}
398 \\def\\openout#1 {\\g@addto@macro\\MYLATEXopens{\\immediate\\openout#1 }}
399 \\let\\MYLATEXopens\\@empty\\def\\MYLATEXbegin{\\begin{document}}
400 \\def\\MYLATEXcomment{mylatex}\\def\\MYLATEXcustomised#1#2#3\\typeout#4{%
401 \\typeout{CUSTOMISED FORMAT. Preloaded files:^^J\\@spaces\\@spaces.}#3}
402 {\\catcode`\\^^M=\\active\\catcode`\\/=0 %
403 /catcode`\\\\=13 /gdef\\{/catcode`/\\=0 /catcode`/^^M=13 /catcode`/%=9 ^^M}%
404 /long/gdef^^M#1^^M{/def/MYLATEXline{#1}%
405 /ifx/MYLATEXline/MYLATEXcomment/let/MYLATEXbegin/relax%
406 /let/MYLATEXline/relax/fi/ifx/MYLATEXline/MYLATEXbegin%
407 /catcode`/^^M=5/relax/let^^M/par/catcode`/#=6/relax%
408 /catcode`/%=14/relax/catcode`/ =10/relax%
409 /expandafter/MYLATEXopens/expandafter/MYLATEXbegin%
410 /else/expandafter^^M/fi}}\\expandafter\\input\\endinput%"
411 "TeX code for dumping a format file.")
414 ;; Version
417 (defun imaxima-version ()
418 "Print the package name and the version in the mini buffer"
419 (interactive)
420 (message "%s %s" *imaxima-autoconf-package* *imaxima-autoconf-version*))
423 ;; Reset
426 (defun reinit-imaxima ()
427 "Re-initialize imaxima"
428 (interactive)
429 (setq imaxima-filter-running nil
430 imaxima-output nil
431 continuation nil))
434 ;; Geometry
437 (defun imaxima-get-geometry (buffer)
438 "Transfer display geometry parameters from current display.
439 Those are put in local variable `imaxima-resolution'. Calculation is done
440 in source buffer specified by BUFF."
441 (let (res)
442 (with-current-buffer buffer
443 (setq res (cons (/ (* 25.4 (imaxima-display-pixel-width))
444 (imaxima-display-mm-width))
445 (/ (* 25.4 (imaxima-display-pixel-height))
446 (imaxima-display-mm-height)))))
447 (setq imaxima-resolution res)))
449 (defun imaxima-get-window-width-xemacs ()
450 "Return window width in mm.
451 XEmacs verson."
452 (/ (* (window-text-area-pixel-width) (imaxima-display-mm-width))
453 (imaxima-display-pixel-width)))
455 (defun imaxima-get-window-width-emacs ()
456 "Return window width in mm.
457 Emacs version."
458 (/ (* (- (window-width) 1) (frame-char-width))
459 (/ (float (imaxima-display-pixel-width))
460 (imaxima-display-mm-width))))
462 (defun imaxima-bp-to-mm (bp)
463 "Convert PostScript big points to mm. BP is size in big points."
464 (* bp 0.352778))
466 (defun imaxima-color-to-rgb (str)
467 "Convert color name STR to rgb values understood by TeX."
468 (mapcar #'(lambda (x) (/ x 65535.0)) (imaxima-color-values str)))
470 (defmacro imaxima-with-temp-dir (dir &rest body)
471 "Change to DIR temporarily and execute BODY."
472 (let ((wd (make-symbol "wd")))
473 `(let ((,wd default-directory))
474 (cd ,dir)
475 (unwind-protect
476 (progn
477 ,@body)
478 (cd ,wd)))))
481 ;; Gs stuff
484 (defun imaxima-gs-filter (process str)
485 "Set `imaxima-gs-computing-p' to t when gs is done."
486 (setq imaxima-gs-output (concat imaxima-gs-output str))
487 (when (string-match "GS\\(<[0-9+]\\)?>" imaxima-gs-output)
488 (setq imaxima-gs-computing-p nil)
489 (setq imaxima-gs-output "")))
491 (defun imaxima-gs-wait ()
492 "Wait for gs to finish."
493 (while (and imaxima-gs-computing-p
494 (eq (process-status imaxima-gs-process) 'run))
495 (accept-process-output imaxima-gs-process 1)))
497 (defun imaxima-start-gs ()
498 "Start Ghostscript as an asynchronyous process."
499 ;; Are we using the broken GNU Ghostscript 7.05?
500 (setq imaxima-gs-7.05-is-broken
501 (string-match "\\(GNU\\|ESP\\) Ghostscript 7.05"
502 (shell-command-to-string
503 (concat imaxima-gs-program " --help"))))
504 (let* (output
505 (type (cadr (assq imaxima-image-type imaxima-image-creators)))
506 (gs-args (append imaxima-gs-options
507 type
508 (list (format "-r%gx%g" (car imaxima-resolution)
509 (cdr imaxima-resolution))))))
510 (when (and imaxima-gs-process
511 (processp imaxima-gs-process))
512 (delete-process imaxima-gs-process))
513 (setq imaxima-gs-computing-p t)
514 (condition-case nil
515 (setq imaxima-gs-process (apply 'start-process "imaxima-gs"
516 " *imaxima gs output*"
517 imaxima-gs-program gs-args))
518 (error (error
519 "Sorry, Ghostscript could not be started. Please check
520 that you have gs in your path or customize the value of
521 `imaxima-gs-program' (current values is \"%s\").
523 imaxima-gs-program
524 (if (imaxima-image-type-available-p 'postscript)
525 "If Ghostscript isn't installed you can set `imaxima-image-type' to `ps'."
526 ;; don't offer this advice in XEmacs, which doesn't support ps.
527 ""))))
528 (set-process-filter imaxima-gs-process 'imaxima-gs-filter)
529 (imaxima-gs-wait)
530 (set-process-query-on-exit-flag imaxima-gs-process nil)
531 (unless (eq (process-status imaxima-gs-process) 'run)
532 (setq output (shell-command-to-string (concat imaxima-gs-program " -h")))
533 (cond
534 ((null (string-match (car type) output))
535 (error
536 "Your version Ghostscript does not appear to support the image type %s.
537 The command \"gs -h\" lists the available devices.
538 You can change the image type in `imaxima-image-type' or the device name
539 associated with an image type in `imaxma-image-creators'" (car type)))
540 (t (error
541 "Some of the options passed to Ghostscript are probably not supported
542 by your version. In particular \"-dTextAlphaBits=4\" and \"-dGraphicsAlphaBits=4\"
543 are not supported by gs 5.5 or earlier. Please edit `imaxima-gs-options'"))))))
545 (defun imaxima-extract-bb (filename)
546 "Extract EPS bounding box vector from FILENAME.
547 Returns a list of bounding box, width, and height."
548 (with-temp-buffer
549 (insert-file-contents-literally filename nil 0 1024 t)
550 (goto-char (point-min))
551 (when (search-forward-regexp "%%BoundingBox:\
552 +\\([-+]?[0-9.]+\\)\
553 +\\([-+]?[0-9.]+\\)\
554 +\\([-+]?[0-9.]+\\)\
555 +\\([-+]?[0-9.]+\\)" nil t)
556 (let ((bb
557 (vector
558 (floor (string-to-number (match-string 1)))
559 (floor (string-to-number (match-string 2)))
560 (ceiling (string-to-number (match-string 3)))
561 (ceiling (string-to-number (match-string 4))))))
562 (list bb
563 (- (aref bb 2) (aref bb 0))
564 (- (aref bb 3) (aref bb 1)))))))
566 (defun imaxima-eps-scale (file bb scale)
567 "Scale the eps image in FILE with factor SCALE.
568 BB is the bounding box of the image. Returns a list of new bounding
569 box, width, and height."
570 (multiple-value-bind (llx lly urx ury) (append bb nil)
571 (let ((x (round (* (- urx llx) scale)))
572 (y (round (* (- ury lly) scale)))
573 (buff (find-file-noselect file)))
574 (unwind-protect
575 (with-current-buffer buff
576 (goto-char (point-min))
577 (search-forward "%%BoundingBox")
578 (delete-region (line-beginning-position) (line-end-position))
579 (insert (format "%%%%BoundingBox: 0 0 %d %d\n" x y))
580 (search-forward "%%EndComments")
581 (forward-line)
582 (insert "%%BeginProcSet: imaxima 1 0\ngsave\n")
583 (insert (format "%f %f translate\n"
584 (- (* llx scale))
585 (- (* lly scale))))
586 (insert (format "%f %f scale\n" scale scale))
587 (insert "%%EndProcSet\n")
588 (goto-char (point-max))
589 (insert "\ngrestore\n")
590 (save-buffer))
591 (kill-buffer buff))
592 (list (vector 0 0 x y) x y))))
594 (defun imaxima-latex ()
595 "Convert Maxima buffer to LaTeX.
596 This command does not work in XEmacs."
597 (interactive)
598 (let (pos2 label (pos (make-marker))
599 (buf (generate-new-buffer "*imaxima-latex*"))
600 (oldbuf (current-buffer)))
601 (set-buffer buf)
602 (insert-buffer oldbuf)
603 ;; ;; Remove copyright notice
604 ;; (goto-char (point-min))
605 ;; (search-forward "(%i1)" nil t 2)
606 ;; (search-backward "(%i1)" nil t)
607 ;; (delete-region (point-min) (point))
608 ;; (goto-char (point-min))
609 (insert "\\documentclass[leqno]{article}
610 \\usepackage{verbatim}
611 \\usepackage[cmbase]{flexisym}
612 \\usepackage{color}
613 \\usepackage{breqn}
614 \\setkeys{breqn}{compact}
616 \\setlength{\\textwidth}{180mm}
617 \\setlength{\\oddsidemargin}{15mm}
618 \\addtolength{\\oddsidemargin}{-1in}
619 \\setlength{\\evensidemargin}{15mm}
620 \\addtolength{\\evensidemargin}{-1in}
622 \\newcommand{\\ifrac}[2]{\\frac{#1}{#2}}
623 \\newcommand{\\ifracd}[2]{\\frac{#1}{#2}}
624 \\newcommand{\\ifracn}[2]{\\frac{#1}{#2}}
625 \\newcommand{\\isubscript}[2]{{#1}_{#2}}
626 \\newcommand{\\iexpt}[2]{{#1}^{#2}}
627 \\newcommand{\\isqrt}[1]{\\sqrt{#1}}
628 \\begin{document}\n")
629 ;; (while (and (not (eobp))
630 ;; (setq pos (next-single-property-change (point) 'display)))
631 ;; (goto-char pos)
632 ;; (insert "\\end{verbatim}\n\n")
633 ;; (setq pos (copy-marker (next-single-property-change (point) 'display)))
634 ;; (remove-text-properties (point) pos '(display nil))
635 ;; (setq pos2 (point))
636 ;; (re-search-forward "(\\([^)]*\\))")
637 ;; (setq label (match-string 1))
638 ;; (delete-region pos2 (point))
639 ;; (insert (format "\\begin{dmath}[number={%s}]\n" label))
640 ;; (goto-char pos)
641 ;; (insert "\\end{dmath}\n\n\\begin{verbatim}"))
642 ;; (goto-char (point-max))
643 ;; (insert "\n\\end{verbatim}\n\\end{document}")
644 (while (not (eobp))
645 (let* ((region-start (copy-marker (point)))
646 (region-end (copy-marker (next-single-property-change (point) 'display nil (point-max))))
647 (text-prop (get-text-property region-start 'display)))
648 (if text-prop
649 (progn
650 (goto-char region-start)
651 (remove-text-properties region-start region-end '(display nil))
652 (goto-char region-end)
653 (goto-char region-start)
654 (re-search-forward "(\\([^)]*\\))")
655 (setq label (match-string 1))
656 (delete-region region-start (point))
657 (goto-char region-start)
658 (insert (format "\\begin{dmath}[number={%s}]\n" label))
659 (goto-char region-end)
660 (insert "\\end{dmath}\n\n"))
661 (progn
662 (goto-char region-start)
663 (insert "\\begin{verbatim}")
664 (goto-char region-end)
665 (insert "\\end{verbatim}\n\n")))))
666 (insert "\n\\end{document}")
667 (switch-to-buffer-other-window buf)
668 (latex-mode)))
670 (defun imaxima-process-sentinel (process event)
671 "Process sentinel for Maxima process."
672 (message "Process %s %s" process event)
673 (unless (eq (process-status process) 'run)
674 (imaxima-clean-up)))
676 (defun imaxima-ps-to-image (psfilename filename bb width height)
677 "Convert eps file PSFILENAME to a bitmap image file FILENAME.
678 BB is the bounding box for eps image. WIDTH and HEIGHT are the
679 dimensions of the image."
680 (setq imaxima-gs-computing-p t)
681 (when (eq system-type 'windows-nt)
682 (setq psfilename (imaxima-subst-char-in-string ?\\ ?/ psfilename))
683 (setq filename (imaxima-subst-char-in-string ?\\ ?/ filename)))
684 (process-send-string imaxima-gs-process
685 (format
686 (if imaxima-gs-7.05-is-broken
687 "clear /imaxima-state save def \
688 << /PageSize [%d %d] /PageOffset [%d %d] /OutputFile (%s) >> \
689 setpagedevice (%s) run imaxima-state restore\n"
690 "clear \
691 << \
692 /PageSize [%d %d] /PageOffset [%d %d] /OutputFile (%s) \
693 >> setpagedevice [save] (%s) (r) file cvx \
694 systemdict /.runandhide known revision 700 ge and {.setsafe {.runandhide}} if \
695 stopped {handleerror quit} if count 1 ne {quit} if \
696 cleardictstack 0 get restore\n")
697 width
698 height
699 (- (aref bb 0))
700 (aref bb 1)
701 filename
702 psfilename))
703 (imaxima-gs-wait))
705 (defun imaxima-check-plot-output (str)
706 "If the str is in the form ^Wpompt^W\\verb|plotfile filename|, then
707 filename is returned. Else, nil is returned."
708 ;; (if (string-match "\x17[^\x17]*\x17\\\\mathrm{wxxmltag}\\\\left\(\\\\verb|\\([^|]*\\)|.*" str)
709 ;; (if (string-match "\x17[^\x17]*\x17\\\\mathrm{wxxmltag}\\\\left[^/]*\\(.*\.eps\\).*" str)
710 ;; (if (string-match "\x17[^\x17]*\x17\\\\mathrm{wxxmltag}\\\\left\(\\\\verb|*\\(.*\.eps\\).*" str)
711 (if (string-match "\x17[^\x17]*\x17\\\\mathrm{wxxmltag}\\\\left\(\\(\\\\verb|\\)*\\(.*\.eps\\).*" str)
712 (match-string 2 str)
713 nil))
715 (defun imaxima-make-image (str eps-or-latex &optional no-label-p)
716 "Make image from STR. If no-label-p is specified t,
717 label becomes nil and passed to imaxima-tex-to-dvi."
718 (let ((res (imaxima-check-plot-output str)))
719 (if res
720 (setq str res
721 eps-or-latex 'eps)))
723 (let* ((filename (expand-file-name
724 (number-to-string (incf imaxima-file-counter))
725 imaxima-tmp-subdir))
726 (psfilename (concat filename ".ps"))
727 (label "*"))
729 (cond ((eql eps-or-latex 'latex)
730 (when (string-match "\\(\x17\\([^\x17]*\\)\x17\\)" str)
731 (setq label (match-string 2 str))
732 (setq str (replace-match "" t t str 1)))
733 (if no-label-p (setq label nil)) ;; override label to nil if no-label-p
734 (imaxima-tex-to-dvi str label (concat filename ".tex"))
735 (imaxima-dvi-to-ps filename)
737 ((eql eps-or-latex 'eps)
738 (copy-file str psfilename)
739 (setq label nil)
742 (if (not (file-exists-p psfilename))
743 (imaxima-latex-error str filename)
744 (multiple-value-bind (bb width height)
745 (imaxima-extract-bb psfilename)
746 (let ((ratio (/ (imaxima-get-window-width)
747 (imaxima-bp-to-mm width))))
748 (when (< ratio 1.0)
749 ;; image is wider than the buffer
750 (if (or (eql eps-or-latex 'eps)
751 (and imaxima-max-scale
752 (or (eq imaxima-max-scale t)
753 (> ratio imaxima-max-scale))))
754 ;; scale image
755 (multiple-value-setq (bb width height)
756 (imaxima-eps-scale psfilename bb ratio))
757 (when imaxima-linearize-flag
758 ;; linearize image
759 (imaxima-tex-to-dvi str label (concat filename ".tex") t)
760 (imaxima-dvi-to-ps filename)
761 (multiple-value-setq (bb width height)
762 (imaxima-extract-bb psfilename))))))
763 (unless (eq imaxima-image-type 'postscript)
764 (imaxima-ps-to-image psfilename filename bb width height))
765 (cond ((featurep 'xemacs)
766 (when (eq system-type 'windows-nt)
767 ;;(setq filename (imaxima-subst-char-in-string ?\\ ?/ filename))
768 ;; FIXME:
769 ;; Ghostscript on Windows doesn't flush the image to the file.
770 ;; So we have to kill the process and restart. What a kludge!
771 (kill-process imaxima-gs-process)
772 (imaxima-start-gs))
773 (xemacs-set-imagefile-properties filename imaxima-image-type str))
775 (propertize (concat "(" label ") " str) 'display
776 (if (eq imaxima-image-type 'postscript)
777 (create-image psfilename
778 'postscript nil
779 :pt-width width :pt-height height
780 :bounding-box bb :ascent 'center
781 :mask '(heuristic (color-values imaxima-bg-color)))
782 (create-image filename
783 imaxima-image-type nil
784 :ascent 'center
785 :mask '(heuristic
786 (color-values imaxima-bg-color)))))))))))
789 (defun imaxima-latex-error (str filename)
790 "Make clickable error message.
791 STR is offending LaTeX expression. FILENAME is name of the LaTeX file."
792 (let* ((msg "LaTeX error in: ")
793 (delim (if (featurep 'xemacs)
794 "; " "\n"))
795 imaxima-error-2
796 imaxima-error-3
797 (error-text (concat "mouse-2: view LaTeX error log" delim
798 "mouse-3: view LaTeX source")))
799 (fset 'imaxima-error-2
800 `(lambda ()
801 (interactive)
802 (view-file-other-window (concat ,filename ".log"))))
803 (fset 'imaxima-error-3
804 `(lambda ()
805 (interactive)
806 (view-file-other-window (concat ,filename ".tex"))))
807 (define-key imaxima-error-map imaxima-mouse2 'imaxima-error-2)
808 (define-key imaxima-error-map [(return)] 'imaxima-error-2)
809 (define-key imaxima-error-map imaxima-mouse3 'imaxima-error-3)
810 (define-key imaxima-error-map [(meta return)] 'imaxima-error-3)
811 (set-text-properties 0 14 `(face imaxima-latex-error-face
812 mouse-face highlight
813 help-echo ,error-text
814 keymap ,imaxima-error-map)
815 msg)
816 (concat msg str)))
819 (defun imaxima-dump-tex ()
820 "Dump a TeX format file preloaded with the required packages."
821 (with-temp-file (expand-file-name "mylatex.ltx" imaxima-tmp-subdir)
822 (insert imaxima-mylatex))
823 (with-temp-file (expand-file-name "format.tex" imaxima-tmp-subdir)
824 (insert
825 ;;"\\batchmode\n"
826 (format "\\documentclass[%dpt,leqno]{article}\n" imaxima-pt-size)
827 imaxima-latex-preamble
828 "\\usepackage{color}\n"
829 "\\usepackage{exscale}\n"
830 "\\usepackage[cmbase]{flexisym}\n"
831 "\\usepackage{breqn}\n"
832 "\\setkeys{breqn}{compact}\n"
833 "\\setlength{\\textheight}{200cm}\n"
834 ;; define \boxed from amsmath.sty
835 "\\makeatletter
836 \\providecommand\\boxed{}
837 \\providecommand\\operatorname{}
838 \\renewcommand{\\boxed}[1]{\\fbox{\\m@th$\\displaystyle#1$}}
839 \\renewcommand{\\operatorname}[1]{%
840 \\mathop{\\relax\\kern\\z@\\operator@font{#1}}}
841 \\makeatother
842 \\newcommand{\\ifrac}[2]{\\frac{#1}{#2}}
843 \\newcommand{\\ifracd}[2]{\\frac{#1}{#2}}
844 \\newcommand{\\ifracn}[2]{\\frac{#1}{#2}}
845 \\newcommand{\\isubscript}[2]{{#1}_{#2}}
846 \\newcommand{\\iexpt}[2]{{#1}^{#2}}
847 \\newcommand{\\isqrt}[1]{\\sqrt{#1}}\n
848 \\nofiles
849 \\begin{document}
850 \\end{document}"))
851 (imaxima-with-temp-dir
852 imaxima-tmp-subdir
853 (apply 'call-process imaxima-tex-program nil nil nil
854 (list imaxima-initex-option "&latex" "mylatex.ltx" "format"))))
855 ;; (format "\\input{%s}" "format.tex")))))
857 (defun imaxima-tex-to-dvi (str label filename &optional linear)
858 "Run LaTeX on STR.
859 Argument LABEL is used as equation label. FILENAME is used for
860 temporary files. Use linearized form if LINEAR is non-nil."
861 (with-temp-file filename
862 (insert
863 ;;"\\batchmode\n"
864 (format "\\documentclass[%dpt,leqno]{article}\n" imaxima-pt-size)
865 "\n% mylatex\n"
866 (format "\\setlength{\\textwidth}{%dmm}\n"
867 (round (/ (imaxima-get-window-width)
868 imaxima-scale-factor)))
869 (if linear
870 (concat
871 ;; braces in both denominator and numerator
872 "\\renewcommand{\\ifrac}[2]{\\left(#1\\right)/\\left(#2\\right)}"
873 ;; only braces denominator
874 "\\renewcommand{\\ifracd}[2]{#1/\\left(#2\\right)}"
875 ;; only braces in numerator
876 "\\renewcommand{\\ifracn}[2]{\\left(#1\\right)/#2}"
877 "\\renewcommand{\\isubscript}[2]{\\mathrm{subscript}\\left(#1,#2\\right)}"
878 "\\renewcommand{\\iexpt}[2]{\\mathrm{expt}\\left(#1,#2\\right)}"
879 "\\renewcommand{\\isqrt}[1]{\\left(#1\\right)^{1/2}}\n")
881 "\\begin{document}\n"
882 (apply 'format "\\pagecolor[rgb]{%f,%f,%f}"
883 (imaxima-color-to-rgb (imaxima-get-bg-color)))
884 "\\pagestyle{empty}\n"
885 (format "\\begin{%s}\n" imaxima-fnt-size)
886 (apply 'format "\\color[rgb]{%f,%f,%f}"
887 (imaxima-color-to-rgb imaxima-label-color))
888 "\\tt"
889 (if label
890 (concat
891 (format "\\begin{dmath}[number={%s}]\n" label)
892 (apply 'format "\\color[rgb]{%f,%f,%f}"
893 (imaxima-color-to-rgb imaxima-equation-color))
894 str (format "\\end{dmath}\n"))
895 (concat
896 (apply 'format "\\color[rgb]{%f,%f,%f}"
897 (imaxima-color-to-rgb imaxima-equation-color))
898 "\\begin{math} \\displaystyle " str (format " \\end{math}\n")))
899 (format "\\end{%s}\n" imaxima-fnt-size)
900 "\\end{document}"))
901 (imaxima-with-temp-dir imaxima-tmp-subdir
902 (apply 'call-process imaxima-tex-program nil nil nil
903 (list "&mylatex" filename))))
905 (defun imaxima-dvi-to-ps (filename)
906 "Convert dvi file FILENAME to PostScript."
907 (let ((dvips-args (append
908 imaxima-dvips-options
909 (list "-x" (format "%s" (* imaxima-scale-factor 1000))
910 "-y" (format "%s" (* imaxima-scale-factor 1000))
911 (concat filename ".dvi") "-o"))))
912 (imaxima-with-temp-dir imaxima-tmp-subdir
913 (apply 'call-process imaxima-dvips-program nil nil nil dvips-args))))
915 (defun imaxima-clean-up ()
916 "Kill gs process, delete temporary files and restore colors if applicable."
917 (interactive)
918 (ignore-errors
919 (kill-process imaxima-gs-process))
920 (mapc 'delete-file (directory-files imaxima-tmp-subdir t "^[^.].*"))
921 (delete-directory imaxima-tmp-subdir)
922 (if (featurep 'xemacs)
923 (ad-deactivate 'comint-output-filter)
924 ;; restore frame colors in Emacs
925 (when imaxima-fg-color
926 (modify-frame-parameters
927 nil (list (cons 'foreground-color imaxima-old-fg-color))))
928 (when imaxima-bg-color
929 (modify-frame-parameters
930 nil (list (cons 'background-color imaxima-old-bg-color)))))
931 (run-hooks 'imaxima-exit-hook))
933 ;;; Continuation is used between maxima-to-latex function and
934 ;;; get-image-from-imaxima. The value is either nil or a list of
935 ;;; function, buffer, pos1, and pos2, where pos1 and pos2 are the beginning and
936 ;;; end of current maxima formula.
937 ;; (func buffer pos1 pos2)
939 (defvar continuation nil)
941 ;;; if *debug-imaxima-filter* is set to t, the str is
942 ;;; appended to the last of buffer *imaxima-work*.
943 (defvar *debug-imaxima-filter* nil)
945 (defun debug-imaxima-filter (str)
946 (if *debug-imaxima-filter*
947 (with-current-buffer (get-buffer-create "*imaxima-work*")
948 (insert str))))
950 (defvar imaxima-filter-running nil)
952 (defun* imaxima-filter (str)
953 "Parse output from Maxima and make image from TeX parts.
954 Argument STR contains output received from Maxima.
956 imaxima-filter needs to be written in re-entrant manner.
957 This is because during the creation of latex image, there
958 observed a reentrant call of imaxima-filter. yhonda"
959 (if imaxima-filter-running
960 (progn
961 (setq imaxima-output (concat imaxima-output str))
962 (debug-imaxima-filter "reenter")
963 (return-from imaxima-filter "")))
964 (setq imaxima-filter-running t)
965 (debug-imaxima-filter str)
966 (let* ((len (length str))
967 main-output)
968 (if (zerop len)
969 (progn
970 (setq imaxima-filter-running nil)
971 (return-from imaxima-filter ""))
972 (setq imaxima-output (concat imaxima-output str))
973 (let ((lastchar (aref str (1- len)))
974 (output ""))
975 (when (and (char-equal lastchar ?\n) (> len 1))
976 (setq lastchar (aref str (- len 2))))
978 (message "Processing Maxima output...")
979 (while (not (string= imaxima-output ""))
980 (let ((1stchar (substring imaxima-output 0 1)))
981 (cond ((string= 1stchar "\x03")
982 (if (string-match "\x03\\([^\x03\x04]*\\)\x04\\(\\(.\\|\n\\)*\\)" imaxima-output)
983 (let ((iprompt (match-string 1 imaxima-output))
984 (rest (match-string 2 imaxima-output)))
985 (setq imaxima-output rest)
986 (setq output (concat output iprompt))
987 ;; All the output for a maxima command are processed.
988 ;; We can call continuation if necessary.
989 (cond ((and continuation main-output)
990 (funcall (car continuation) main-output))
991 ((and continuation (null main-output))
992 (funcall (car continuation) ""))))
993 ;; imaxima-output is incomplete.
994 (setq imaxima-filter-running nil)
995 (return-from imaxima-filter output)))
996 ((string= 1stchar "\x02")
997 (if (string-match "\x02\\([^\x02\x05]*\\)\x05\\(\\(.\\|\n\\)*\\)" imaxima-output)
998 (let ((match (match-string 1 imaxima-output))
999 (rest (match-string 2 imaxima-output))
1000 image)
1001 (setq imaxima-output rest)
1002 (setq output (concat output (setq image (imaxima-make-image match 'latex))))
1003 ;; Remember the image into main-output if this is the first output.
1004 ;; This will be passed to continuation
1005 (if (null main-output)
1006 (setq main-output image)))
1007 ;; imaxima-output is incomplete.
1008 (setq imaxima-filter-running nil)
1009 (return-from imaxima-filter output)))
1010 ((string= 1stchar "\x15")
1011 (if (string-match "\x15\\([^\x15\x16]*\\)\x16\\(\\(.\\|\n\\)*\\)" imaxima-output)
1012 (let ((match (match-string 1 imaxima-output))
1013 (rest (match-string 2 imaxima-output)))
1014 (setq imaxima-output rest)
1015 (setq output (concat output (imaxima-make-image match 'latex))))
1016 ;; imaxima-output is incomplete.
1017 (setq imaxima-filter-running nil)
1018 (return-from imaxima-filter output)))
1019 (t (if (string-match "\\([^\x02\x03\x15]*\\)\\(\\(.\\|\n\\)*\\)" imaxima-output)
1020 (let ((match (match-string 1 imaxima-output))
1021 (rest (match-string 2 imaxima-output)))
1022 (setq imaxima-output rest)
1023 (setq output (concat output match)))
1024 ;; This should not happen.
1025 (message "Unexpected error encountered in imaxima-filter"))))))
1026 (message "Processing Maxima output...done")
1027 (setq imaxima-filter-running nil)
1028 (return-from imaxima-filter output)))))
1030 (defun imaxima-filter1 (str)
1031 "Parse output from Maxima and make image from TeX parts.
1032 Argument STR contains output received from Maxima."
1033 (if *debug-imaxima-filter*
1034 (with-current-buffer (get-buffer-create "*imaxima-work*")
1035 (insert "****new string****
1037 (insert str)))
1038 (let* ((len (length str)))
1039 (if (zerop len)
1041 (setq imaxima-output (concat imaxima-output str))
1042 (let ((lastchar (aref str (1- len))))
1043 (when (and (char-equal lastchar ?\n) (> len 1))
1044 (setq lastchar (aref str (- len 2))))
1045 (cond
1046 ;; Plain text
1047 ((string-match "\\`[^\x02\x05\x03\x04\x15\x16]+\\'" imaxima-output)
1048 (prog1 imaxima-output
1049 (setq imaxima-output "")))
1050 ((or (char-equal lastchar ?\x04) (char-equal lastchar ?\x05))
1051 (let ((prompt "")
1052 (newline-char "
1054 (output "")
1055 (rest imaxima-output)
1056 text match)
1057 (message "Processing Maxima output...")
1058 (if (string-match "\\([^\x03\x04]*\\)\x03\\([^\x03\x04]*\\)\x04$" imaxima-output)
1059 (setq prompt (concat "" (match-string 2 imaxima-output))
1060 rest (match-string 1 imaxima-output)))
1061 (while (string-match "\\(\\([^\x02\x05]*\\)\x02\\([^\x02\x05]*\\)\x05\\)"
1062 rest)
1063 (setq text (match-string 2 rest))
1064 (setq match (match-string 3 rest))
1065 (setq rest (replace-match "" t t rest 1))
1066 (setq output (concat output (if (equal output "") "" newline-char) text (imaxima-make-image match 'latex))))
1067 (setq imaxima-output "")
1068 (message "Processing Maxima output...done")
1069 (if continuation
1070 (funcall (car continuation) output))
1071 (concat output rest prompt)))
1072 ;; Special prompt for demo() function.
1073 ;; _ is prompted.
1074 ((char-equal lastchar ?_)
1075 (let ((newline-char "
1077 (output "")
1078 (rest (substring imaxima-output 0 -1))
1079 match text)
1080 (message "Processing Maxima output...")
1081 (while (string-match "\\(\\([^\x02\x05]*\\)\x02\\([^\x02\x05]*\\)\x05\\)"
1082 rest)
1083 (setq text (match-string 2 rest))
1084 (setq match (match-string 3 rest))
1085 (setq rest (replace-match "" t t rest 1))
1086 (setq output (concat output (if (equal output "") "" newline-char) text (imaxima-make-image match 'latex))))
1087 (setq imaxima-output "")
1088 (message "Processing Maxima output...done")
1089 (if continuation
1090 (funcall (car continuation) output))
1091 (concat " " output rest newline-char "_")))
1092 ;; Special prompt, question.
1093 ((char-equal lastchar ?\x16)
1094 (string-match "\x15\\([^\x16]*\\)\x16" imaxima-output)
1095 (prog1 (imaxima-make-image (match-string 1 imaxima-output) 'latex)
1096 (setq imaxima-output "")))
1097 (t ""))))))
1099 (defun xemacs-set-imagefile-properties (filename img-type str)
1100 (let ((ext (make-extent 0 (length str) str)))
1101 (set-extent-property ext 'duplicable t)
1102 (set-extent-end-glyph ext
1103 (make-glyph (vector img-type
1104 :file filename)))
1105 (set-extent-property ext 'invisible t)
1106 (set-extent-property ext 'atomic t))
1107 str)
1109 (eval-when-compile
1110 (ignore-errors
1111 (require 'maxima)))
1113 (defun imaxima-setup-preoutput-filter ()
1114 "Set up `comint-preoutput-filter-functions' or the equivalent."
1115 (cond ((featurep 'xemacs)
1116 ;; XEmacs does not have comint-preoutput-filter-functions, so
1117 ;; we have to advice comint-output-filter instead
1118 (defadvice comint-output-filter (before preoutput-filter)
1119 "Run comint-preoutput-filter-functions."
1120 (ad-set-arg 1 (imaxima-filter (ad-get-arg 1))))
1121 (ad-activate 'comint-output-filter))
1123 (make-local-variable 'comint-preoutput-filter-functions)
1124 ;; This doesn't work due to a bug in comint.el
1125 ;; (add-hook 'comint-preoutput-filter-functions 'imaxima-filter nil t)
1126 (add-hook 'comint-preoutput-filter-functions 'imaxima-filter t))))
1128 (defun imaxima-change-color (buf)
1129 "Change background and foreground color if applicable.
1130 BUF is imaxima buffer."
1131 (cond
1132 ((featurep 'xemacs)
1133 (when imaxima-bg-color
1134 (set-face-background 'default imaxima-bg-color buf))
1135 (when imaxima-fg-color
1136 (set-face-foreground 'default imaxima-fg-color buf)))
1138 (when imaxima-bg-color
1139 (setq imaxima-old-bg-color (frame-parameter nil 'background-color))
1140 (modify-frame-parameters
1141 nil (list (cons 'background-color imaxima-bg-color))))
1142 (when imaxima-fg-color
1143 (setq imaxima-old-fg-color (frame-parameter nil 'foreground-color))
1144 (modify-frame-parameters
1145 nil (list (cons 'foreground-color imaxima-fg-color)))))))
1147 (defun imaxima-setup ()
1148 "Image support for maxima.el."
1149 (let ((mbuf (process-buffer inferior-maxima-process)))
1150 (with-current-buffer mbuf
1151 (imaxima-change-color mbuf)
1152 (imaxima-get-geometry mbuf)
1153 (imaxima-dump-tex)
1154 (unless (eq imaxima-image-type 'postscript)
1155 (imaxima-start-gs))
1156 (add-hook 'kill-buffer-hook 'imaxima-clean-up t t)
1157 (imaxima-setup-preoutput-filter)
1158 (maxima-single-string
1159 ;; (format "?load(?subseq(?symbol\\-name(\"%s\"), 1));\n" imaxima-lisp-file))
1160 (format "block(load((\"%s\")), linenum:0)$\n" imaxima-lisp-file))
1161 ;; maxima mode tries to run inferior-maxima-mode-hook twice
1162 ;; due to changes made in 5.9.2 release. To prevent this,
1163 ;; the following hook must be removed earlier than before.
1164 ;; y.honda
1165 (remove-hook 'inferior-maxima-mode-hook 'imaxima-setup)
1166 (goto-char (point-max)))))
1168 (defun* imaxima-delete-maxima-hooks ()
1169 (remove-hook 'comint-output-filter-functions 'inferior-maxima-output-filter)
1170 (remove-hook 'comint-output-filter-functions 'inferior-maxima-remove-double-input-prompt)
1171 (remove-hook 'comint-output-filter-functions 'inferior-maxima-remove-double-prompt))
1173 (defun* imaxima ()
1174 "Image support for Maxima.
1175 \"display2d:true\" in Maxima turns images off, \"display2d:imaxima\"
1176 turns them on. Set `imaxima-use-maxima-mode-flag' to t to use
1177 `maxima.el'."
1178 (interactive)
1179 (if (not window-system)
1180 (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."))
1181 (let ((imaxima-buffer))
1182 (setq imaxima-buffer
1183 (get-buffer (if imaxima-use-maxima-mode-flag
1184 "*maxima*"
1185 "*imaxima*")))
1186 (when imaxima-buffer
1187 (if (interactive-p)
1188 (switch-to-buffer imaxima-buffer)
1189 (set-buffer imaxima-buffer))
1190 (return-from imaxima t)))
1191 (reinit-imaxima)
1192 (unless (imaxima-image-type-available-p imaxima-image-type)
1193 (error "Your version of Emacs does not support the image type %s"
1194 imaxima-image-type))
1195 (unless imaxima-lisp-file
1196 (error "The file imaxima.lisp could not be found.
1197 Please customize the option `imaxima-lisp-file'."))
1198 (setq imaxima-file-counter 0)
1199 (make-directory
1200 (setq imaxima-tmp-subdir
1201 (make-temp-name (expand-file-name "imaxima" imaxima-tmp-dir))) t)
1202 (set-file-modes imaxima-tmp-subdir 448) ; 700 in octal
1203 (let ((process-connection-type process-connection-type-flag))
1204 (if imaxima-use-maxima-mode-flag
1205 (progn
1206 (require 'maxima)
1207 (setq inferior-maxima-prompt
1208 (concat "\\(^ ?(" maxima-inchar
1209 "[0-9]*) \\)\\|\\(^MAXIMA>+\\)\\|\\(^(dbm:[0-9]*) \\)"))
1210 (add-hook 'inferior-maxima-mode-hook 'imaxima-setup t)
1211 (maxima)
1212 (remove-hook 'inferior-maxima-mode-hook 'imaxima-setup))
1213 (imaxima-delete-maxima-hooks)
1214 (setq imaxima-output "")
1215 (let ((mbuf
1216 (apply 'make-comint
1217 "imaxima"
1218 imaxima-maxima-program
1220 (split-string
1221 imaxima-maxima-options))))
1222 (save-excursion
1223 (set-buffer mbuf)
1224 (setq imaxima-process (get-buffer-process mbuf))
1225 (imaxima-get-geometry mbuf)
1226 (imaxima-change-color mbuf)
1227 (imaxima-dump-tex)
1228 (set-process-sentinel imaxima-process 'imaxima-process-sentinel)
1229 (imaxima-setup-preoutput-filter)
1230 (unless (eq imaxima-image-type 'postscript)
1231 (imaxima-start-gs)))
1232 (when (eq system-type 'windows-nt)
1233 (comint-send-string
1234 mbuf
1235 (format "block(load(\"%s\"), linenum:0)$\n" imaxima-lisp-file)))
1236 (switch-to-buffer mbuf))))
1237 (run-hooks 'imaxima-startup-hook))
1239 (defcustom imaxima-print-tex-file "imax"
1240 "Name of the LaTeX file name to be created by `imaxima-print-buffer'.
1241 Do not include \".tex\" suffix. This file will be stored in the
1242 directory `imaxima-temp-dir'."
1243 :group 'imaxima
1244 :type 'string)
1246 (defcustom imaxima-print-tex-command
1247 "latex %s; dvips -o imax.ps %s; gv imax.ps"
1248 ;;"latex %s; xdvi %s"
1249 ;;"latex %s; dvipdf %s.dvi imax.pdf; open imax.pdf" for Mac OS X users.
1250 "Command to run LaTeX on the file created by `imaxima-print-buffer'.
1251 In the string %s is replaced by the name of the tex file. e.g.
1252 \"latex %s; xdvi %s\"
1254 :group 'imaxima
1255 :type 'string)
1257 (defun imaxima-print-buffer ()
1258 "Run LaTeX on the current buffer and show output.
1259 See `imaxima-print-tex-command' for how latex is run on the latex output."
1260 (interactive "")
1261 (let (( tex-file (concat imaxima-tmp-dir
1262 imaxima-print-tex-file ".tex"))
1263 (buf)
1264 (cmd)
1267 (imaxima-latex)
1268 (write-file tex-file)
1269 (setq buf (current-buffer))
1271 ;; Convert all %s into the tex file name.
1272 (setq cmd imaxima-print-tex-command)
1273 (while (string-match "%s" cmd)
1274 (setq cmd (replace-match imaxima-print-tex-file t nil cmd)))
1276 (shell-command cmd)
1277 (kill-buffer buf) ;kill the temp tex buffer
1281 ;;; The following codes implements export imath text to HTML.
1283 (defvar html-template
1284 "<HTML>
1285 <HEAD>
1286 <META HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html; CHARSET=UTF-8\">
1287 <TITLE></TITLE>
1288 </HEAD>
1289 <BODY>
1292 </BODY>
1293 </HTML>
1296 (defun* prepare-for-translation ()
1297 "If error occurs inside this function, multiple values nil nil
1298 will be returned."
1299 (interactive "")
1300 (save-excursion
1301 (let (original-buffer text current-buffer-file-name filename image-folder html-buffer)
1302 (setq original-buffer (current-buffer))
1303 (setq text (buffer-substring (point-min) (point-max)))
1304 (if (or (string= (buffer-name original-buffer)
1305 "*maxima*")
1306 (string= (buffer-name original-buffer)
1307 "*imaxima*"))
1308 (progn
1309 (setq current-buffer-file-name "")
1310 (setq filename (concat imaxima-html-dir "session.html"))
1311 (setq image-folder "session-images"))
1312 (setq current-buffer-file-name
1313 (if (buffer-file-name)
1314 (buffer-file-name)
1315 (return-from prepare-for-translation (values nil nil))))
1316 (setq filename (concat (file-name-sans-extension
1317 (file-name-nondirectory current-buffer-file-name))
1318 ".html"))
1319 (setq image-folder (concat (file-name-sans-extension
1320 (file-name-nondirectory current-buffer-file-name))
1321 "-images")))
1322 ;; HTML buffer preparation
1323 (setq html-buffer (find-file filename))
1324 (set-buffer html-buffer)
1325 ;; create image folder
1326 (let (old-files)
1327 (if (file-exists-p image-folder)
1328 ;; since image-folder already exists, let's reuse it.
1329 (progn
1330 (condition-case err
1331 (progn
1332 (setq old-files (directory-files image-folder nil "\\.png$"))
1333 ;; we need to delete all the files already there.
1334 (dolist (f old-files)
1335 (delete-file (concat image-folder "/" f))))
1336 (file-error (return-from prepare-for-translation (values nil nil)))))
1337 ;; since image-folder doest not exist, let's create it.
1338 (condition-case err
1339 (make-directory image-folder)
1340 (file-error (return-from prepare-for-translation (values nil nil))))))
1341 ;; buffer preparation
1342 (if buffer-read-only
1343 (return-from prepare-for-translation (values nil nil)))
1344 (erase-buffer)
1345 (insert html-template)
1346 (goto-char (point-min))
1347 (search-forward "<BODY>")
1348 (next-line 1)
1349 (insert text)
1350 (values html-buffer image-folder))))
1352 (defun* imath-to-html()
1353 "Translate imath minor mode buffer contents into HTML format."
1354 (interactive "")
1355 (save-excursion
1356 (multiple-value-bind (html-buffer image-folder)
1357 (prepare-for-translation)
1358 (if (not (and html-buffer image-folder))
1359 (progn
1360 (message "Error during HTML buffer preparation.")
1361 (return-from imath-to-html)))
1362 (set-buffer html-buffer)
1363 (goto-char (point-min))
1364 (condition-case err
1365 (loop
1366 (multiple-value-bind (ftype start-pos end-pos)
1367 (find-next-formula)
1368 (if (not (and ftype start-pos end-pos))
1369 (return t)
1370 (let (filename dest-name)
1371 ;; copy image file to image sub folder
1372 (if (null (setq filename (get-image-filename (1- (point)))))
1373 (progn
1374 (message "Error: all formulas must be converted to images first.")
1375 (return-from imath-to-html)))
1376 (setq dest-name (concat
1377 image-folder "/"
1378 (file-name-sans-extension
1379 (file-name-nondirectory filename))
1380 ".png"))
1381 ;;))
1382 (copy-file filename dest-name)
1383 ;; replace imath formula with HTML IMG tag
1384 (delete-region start-pos end-pos)
1385 (insert (concat "<IMG SRC=\""
1386 dest-name
1387 "\" style=\"vertical-align:middle;\"> "))))))
1388 ;; "\" align=\"middle\"> "))))))
1389 (search-failed nil)
1390 (file-error
1391 (progn
1392 (message "Error: File manipulation failed during processing.")
1393 (return-from imath-to-html))))
1394 (condition-case err
1395 (let (start-mark end-mark)
1396 (goto-char (point-min))
1397 (search-forward "<BODY>")
1398 (next-line 1)
1399 (beginning-of-line)
1400 (setq start-mark (point-marker))
1401 (search-forward "</BODY>")
1402 (setq end-mark (point-marker))
1403 (goto-char start-mark)
1404 (loop
1405 (re-search-forward "$" end-mark)
1406 (replace-match "<br>\n")
1407 (next-line 1)))
1408 (search-failed nil)))))
1410 (defun* imaxima-to-html ()
1411 "Translate the imaxima buffer contents into HTML format."
1412 (interactive "")
1413 (imath-to-html))
1415 (defun* original-find-next-formula ()
1416 "Find next formula and return multiple values of
1417 formula type, start position and end position.
1418 If search failed, error search-failed is signaled."
1419 (interactive "")
1420 (let (start-pos end-pos tmp found-string ftype)
1421 (re-search-forward (concat maxima-start "\\|" latex-start))
1422 (setq found-string (match-string 0))
1423 (cond ((string= found-string latex-start)
1424 (setq start-pos (- (point) (length latex-start)))
1425 (search-forward latex-end)
1426 (setq end-pos (point) ftype 'latex))
1427 ((string= found-string maxima-start)
1428 (setq start-pos (- (point) (length maxima-start)))
1429 (search-forward maxima-end)
1430 (setq tmp (point))
1431 (if (string= (buffer-substring tmp
1432 (+ tmp 1
1433 (length latex-start)))
1434 (concat "&" latex-start))
1435 (progn
1436 (search-forward latex-end)
1437 (setq end-pos (point) ftype 'both))
1438 (setq end-pos tmp ftype 'maxima)))
1439 (t (error "Syntax Error in Imath buffer.")))
1440 (values ftype start-pos end-pos)))
1442 (defun* find-next-formula ()
1443 "Find next formula and return multiple values of
1444 formula type, start position and end position.
1445 If search failed, error search-failed is signaled."
1446 (interactive "")
1447 (if (equal (point) (point-max))
1448 (return-from find-next-formula (values nil nil nil)))
1449 (let* ((region-start (copy-marker (point)))
1450 (region-end (copy-marker (next-single-property-change (point) 'display nil (point-max))))
1451 (text-prop (get-text-property region-start 'display)))
1452 (goto-char region-end)
1453 (if text-prop
1454 (return-from find-next-formula (values 'any region-start region-end))
1455 (find-next-formula))))
1459 (defun* get-image-filename (pos)
1460 "If the pos of the buffer is associated with text a display property,
1461 it is obtained. Then image filename of the display property is
1462 extracted and returned."
1463 (interactive "")
1464 (if (null pos)
1465 (setq pos (point)))
1466 (let (filename)
1467 (if (setq filename (memq :file (get-text-property pos 'display)))
1468 (second filename))))
1470 (provide 'imaxima)
1472 ;;; imaxima.el ends here