]> code.delx.au - gnu-emacs-elpa/blob - packages/auctex/preview.el
* auctex: Shorten copyright year ranges.
[gnu-emacs-elpa] / packages / auctex / preview.el
1 ;;; preview.el --- embed preview LaTeX images in source buffer
2
3 ;; Copyright (C) 2001-2006, 2010, 2012 Free Software Foundation, Inc.
4
5 ;; Author: David Kastrup
6 ;; Keywords: tex, wp, convenience
7
8 ;; This file is free software; you can redistribute it and/or modify
9 ;; it under the terms of the GNU General Public License as published by
10 ;; the Free Software Foundation; either version 3, or (at your option)
11 ;; any later version.
12
13 ;; This file is distributed in the hope that it will be useful,
14 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
15 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 ;; GNU General Public License for more details.
17
18 ;; You should have received a copy of the GNU General Public License
19 ;; along with GNU Emacs; see the file COPYING. If not, write to
20 ;; the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
21 ;; Boston, MA 02110-1301, USA.
22
23 ;;; Commentary:
24
25 ;; $Id: preview.el,v 1.286 2011/01/23 18:53:55 angeli Exp $
26 ;;
27 ;; This style is for the "seamless" embedding of generated images
28 ;; into LaTeX source code. Please see the README and INSTALL files
29 ;; for further instruction.
30 ;;
31 ;; Please use the usual configure script for installation: more than
32 ;; just Elisp files are involved: a LaTeX style, icon files, startup
33 ;; code and so on.
34 ;;
35 ;; Quite a few things with regard to preview-latex's operation can be
36 ;; configured by using
37 ;; M-x customize-group RET preview RET
38 ;;
39 ;; Please report bugs with M-x preview-report-bug RET
40 ;;
41
42 ;;; Code:
43
44 (require 'tex-site)
45 (require 'tex)
46 (require 'tex-buf)
47 (require 'latex)
48
49 (eval-when-compile
50 (condition-case nil
51 (require 'desktop)
52 (file-error (message "Missing desktop package:
53 preview-latex buffers will not survive across sessions.")))
54 (condition-case nil
55 (require 'reporter)
56 (file-error (message "Missing reporter library, probably from the mail-lib package:
57 preview-latex's bug reporting commands will probably not work.")))
58 (require 'info)
59 (defvar error))
60
61 ;; we need the compatibility macros which do _not_ get byte-compiled.
62 (eval-when-compile
63 (if (featurep 'xemacs)
64 (load-library "prv-xemacs.el")))
65
66 ;; if the above load-library kicked in, this will not cause anything
67 ;; to get loaded.
68 (require (if (featurep 'xemacs)
69 'prv-xemacs 'prv-emacs))
70
71 (defgroup preview nil "Embed Preview images into LaTeX buffers."
72 :group 'AUCTeX
73 :prefix "preview-"
74 :link '(custom-manual "(preview-latex)Top")
75 :link '(info-link "(preview-latex)The Emacs interface")
76 :link '(url-link :tag "Homepage" "http://www.gnu.org/software/auctex/"))
77
78 (defgroup preview-gs nil "Preview's Ghostscript renderer."
79 :group 'preview
80 :prefix "preview-")
81
82 (defgroup preview-appearance nil "Preview image appearance."
83 :group 'preview
84 :prefix "preview-")
85
86 (defconst preview-specs-type
87 '(repeat
88 (list :tag "Image spec"
89 ;; Use an extra :value keyword to avoid a bug in
90 ;; `widget-convert' of XEmacs 21.4 and Emacs 21.
91 ;; Analogously for the following `const' statements.
92 (const :format "" :value :type)
93 (choice :tag "Image type"
94 (const xpm)
95 (const xbm)
96 (symbol :tag "Other"))
97 (set :inline t :tag "Minimum font size"
98 (list :inline t :tag ""
99 (const :format "" :value :min)
100 (integer :tag "pixels")))
101 (const :format "" :value :file) (string :tag "Filename")
102 (set :inline t :tag "Ascent ratio"
103 (list :inline t :tag ""
104 (const :format "" :value :ascent)
105 (integer :tag "percent of image"
106 :value 50))))))
107
108 (defun preview-specs-setter (symbol value)
109 "Set SYMBOL to VALUE and clear `preview-min-alist' property.
110 This is used in icon specs, so that customizing will
111 clear cached icons."
112 (put symbol 'preview-min-alist nil)
113 (set-default symbol value))
114
115 (defcustom preview-nonready-icon-specs
116 '((:type xpm :min 26 :file "prvwrk24.xpm" :ascent 90)
117 (:type xpm :min 22 :file "prvwrk20.xpm" :ascent 90)
118 (:type xpm :min 17 :file "prvwrk16.xpm" :ascent 90)
119 (:type xpm :min 15 :file "prvwrk14.xpm" :ascent 90)
120 (:type xpm :file "prvwrk12.xpm" :ascent 90)
121 (:type xbm :file "prvwrk24.xbm" :ascent 90))
122 "The icon used for previews to be generated.
123 The spec must begin with `:type'. File names are relative to
124 `load-path' and `data-directory', a spec `:min' requires a
125 minimal pixel height for `preview-reference-face' before the spec
126 will be considered. Since evaluating the `:file' spec takes
127 considerable time under XEmacs, it should come after the `:min'
128 spec to avoid unnecessary evaluation time."
129 :group 'preview-appearance
130 :type preview-specs-type
131 :set #'preview-specs-setter)
132
133 (defvar preview-nonready-icon)
134
135 (defcustom preview-error-icon-specs
136 '((:type xpm :min 22 :file "prverr24.xpm" :ascent 90)
137 (:type xpm :min 18 :file "prverr20.xpm" :ascent 90)
138 (:type xpm :file "prverr16.xpm" :ascent 90)
139 (:type xbm :file "prverr24.xbm" :ascent 90))
140 "The icon used for PostScript errors.
141 The spec must begin with `:type'. File names are relative to
142 `load-path' and `data-directory', a spec `:min' requires a
143 minimal pixel height for `preview-reference-face' before the spec
144 will be considered. Since evaluating the `:file' spec takes
145 considerable time under XEmacs, it should come after the `:min'
146 spec to avoid unnecessary evaluation time."
147 :group 'preview-appearance
148 :type preview-specs-type
149 :set #'preview-specs-setter
150 )
151
152 (defvar preview-error-icon)
153
154 (defcustom preview-icon-specs
155 '((:type xpm :min 24 :file "prvtex24.xpm" :ascent 75)
156 (:type xpm :min 20 :file "prvtex20.xpm" :ascent 75)
157 (:type xpm :min 16 :file "prvtex16.xpm" :ascent 75)
158 (:type xpm :file "prvtex12.xpm" :ascent 75)
159 (:type xbm :min 24 :file "prvtex24.xbm" :ascent 75)
160 (:type xbm :min 16 :file "prvtex16.xbm" :ascent 75)
161 (:type xbm :file "prvtex12.xbm" :ascent 75))
162 "The icon used for an open preview.
163 The spec must begin with `:type'. File names are relative to
164 `load-path' and `data-directory', a spec `:min' requires a
165 minimal pixel height for `preview-reference-face' before the spec
166 will be considered. Since evaluating the `:file' spec takes
167 considerable time under XEmacs, it should come after the `:min'
168 spec to avoid unnecessary evaluation time."
169 :group 'preview-appearance
170 :type preview-specs-type
171 :set #'preview-specs-setter)
172
173 (defvar preview-icon)
174
175 (defgroup preview-latex nil "LaTeX options for preview."
176 :group 'preview
177 :prefix "preview-")
178
179 (defcustom preview-image-creators
180 '((dvipng
181 (open preview-gs-open preview-dvipng-process-setup)
182 (place preview-gs-place)
183 (close preview-dvipng-close))
184 (png (open preview-gs-open)
185 (place preview-gs-place)
186 (close preview-gs-close))
187 (jpeg (open preview-gs-open)
188 (place preview-gs-place)
189 (close preview-gs-close))
190 (pnm (open preview-gs-open)
191 (place preview-gs-place)
192 (close preview-gs-close))
193 (tiff (open preview-gs-open)
194 (place preview-gs-place)
195 (close preview-gs-close)))
196 "Define functions for generating images.
197 These functions get called in the process of generating inline
198 images of the specified type. The open function is called
199 at the start of a rendering pass, the place function for
200 placing every image, the close function at the end of
201 the pass. Look at the documentation of the various
202 functions used here for the default settings, and at
203 the function `preview-call-hook' through which those are
204 called. Additional argument lists specified in here
205 are passed to the functions before any additional
206 arguments given to `preview-call-hook'.
207
208 Not all of these image types may be supported by your copy
209 of Ghostscript, or by your copy of Emacs."
210 :group 'preview-gs
211 :type '(alist :key-type (symbol :tag "Preview's image type")
212 :value-type
213 (alist :tag "Handler" :key-type (symbol :tag "Operation:")
214 :value-type (list :tag "Handler"
215 (function :tag "Handler function")
216 (repeat :tag "Additional \
217 function args" :inline t sexp))
218 :options (open place close))))
219
220 (defcustom preview-gs-image-type-alist
221 '((png png "-sDEVICE=png16m")
222 (dvipng png "-sDEVICE=png16m")
223 (jpeg jpeg "-sDEVICE=jpeg")
224 (pnm pbm "-sDEVICE=pnmraw")
225 (tiff tiff "-sDEVICE=tiff12nc"))
226 "*Alist of image types and corresponding Ghostscript options.
227 The `dvipng' and `postscript' (don't use) entries really specify
228 a fallback device when images can't be processed by the requested
229 method, like when PDFTeX was used."
230 :group 'preview-gs
231 :type '(repeat (list :tag nil (symbol :tag "preview image-type")
232 (symbol :tag "Emacs image-type")
233 (repeat :inline t :tag "Ghostscript options" string))))
234
235 (defcustom preview-image-type 'png
236 "*Image type to be used in images."
237 :group 'preview-gs
238 :type (append '(choice)
239 (mapcar (lambda (symbol) (list 'const (car symbol)))
240 preview-image-creators)
241 '((symbol :tag "Other"))))
242
243 (defun preview-call-hook (symbol &rest rest)
244 "Call a function from `preview-image-creators'.
245 This looks up SYMBOL in the `preview-image-creators' entry
246 for the image type `preview-image-type' and calls the
247 hook function given there with the arguments specified there
248 followed by REST. If such a function is specified in there,
249 that is."
250 (let ((hook (cdr (assq symbol
251 (cdr (assq preview-image-type
252 preview-image-creators))))))
253 (when hook
254 (apply (car hook) (append (cdr hook) rest)))))
255
256
257 (defvar TeX-active-tempdir nil
258 "List of directory name, top directory name and reference count.")
259 (make-variable-buffer-local 'TeX-active-tempdir)
260
261 (defcustom preview-bb-filesize 1024
262 "Size of file area scanned for bounding box information."
263 :group 'preview-gs :type 'integer)
264
265 (defcustom preview-preserve-indentation t
266 "*Whether to keep additional whitespace at the left of a line."
267 :group 'preview-appearance :type 'boolean)
268
269 (defun preview-extract-bb (filename)
270 "Extract EPS bounding box vector from FILENAME."
271 (with-temp-buffer
272 (insert-file-contents-literally filename nil 0 preview-bb-filesize
273 t)
274 (goto-char (point-min))
275 (when (search-forward-regexp "%%BoundingBox:\
276 +\\([-+]?[0-9.]+\\)\
277 +\\([-+]?[0-9.]+\\)\
278 +\\([-+]?[0-9.]+\\)\
279 +\\([-+]?[0-9.]+\\)" nil t)
280 (vector
281 (if preview-preserve-indentation
282 (min 72 (string-to-number (match-string 1)))
283 (string-to-number (match-string 1)))
284 (string-to-number (match-string 2))
285 (string-to-number (match-string 3))
286 (string-to-number (match-string 4))
287 ))))
288
289 (defcustom preview-prefer-TeX-bb nil
290 "*Prefer TeX bounding box to EPS one if available.
291 If `preview-fast-conversion' is set, this option is not
292 consulted since the TeX bounding box has to be used anyway."
293 :group 'preview-gs
294 :type 'boolean)
295
296 (defcustom preview-TeX-bb-border 0.5
297 "*Additional space in pt around Bounding Box from TeX."
298 :group 'preview-gs
299 :type 'number)
300
301 (defvar preview-coding-system nil
302 "Coding system used for LaTeX process.")
303 (make-variable-buffer-local 'preview-coding-system)
304 (defvar preview-parsed-font-size nil
305 "Font size as parsed from the log of LaTeX run.")
306 (make-variable-buffer-local 'preview-parsed-font-size)
307 (defvar preview-parsed-magnification nil
308 "Magnification as parsed from the log of LaTeX run.")
309 (make-variable-buffer-local 'preview-parsed-magnification)
310 (defvar preview-parsed-pdfoutput nil
311 "PDFoutput as parsed from the log of LaTeX run.")
312 (make-variable-buffer-local 'preview-parsed-pdfoutput)
313 (defvar preview-parsed-counters nil
314 "Counters as parsed from the log of LaTeX run.")
315 (make-variable-buffer-local 'preview-parsed-counters)
316 (defvar preview-parsed-tightpage nil
317 "Tightpage as parsed from the log of LaTeX run.")
318 (make-variable-buffer-local 'preview-parsed-tightpage)
319
320 (defun preview-get-magnification ()
321 "Get magnification from `preview-parsed-magnification'."
322 (if preview-parsed-magnification
323 (/ preview-parsed-magnification 1000.0) 1.0))
324
325 (defun preview-TeX-bb (list)
326 "Calculate bounding box from (ht dp wd).
327 LIST consists of TeX dimensions in sp (1/65536 TeX point)."
328 (and
329 (consp list)
330 (let* ((dims (vconcat (mapcar
331 #'(lambda (x)
332 (/ x 65781.76)) list)))
333 (box
334 (vector
335 (+ 72 (min 0 (aref dims 2)))
336 (+ 720 (min (aref dims 0) (- (aref dims 1)) 0))
337 (+ 72 (max 0 (aref dims 2)))
338 (+ 720 (max (aref dims 0) (- (aref dims 1)) 0))))
339 (border (if preview-parsed-tightpage
340 (vconcat (mapcar
341 #'(lambda(x)
342 (/ x 65781.76)) preview-parsed-tightpage))
343 (vector (- preview-TeX-bb-border)
344 (- preview-TeX-bb-border)
345 preview-TeX-bb-border
346 preview-TeX-bb-border))))
347 (dotimes (i 4 box)
348 (aset box i (+ (aref box i) (aref border i)))))))
349
350 (defcustom preview-gs-command (if (eq system-type 'windows-nt)
351 "GSWIN32C.EXE"
352 "gs")
353 "*How to call gs for conversion from EPS. See also `preview-gs-options'."
354 :group 'preview-gs
355 :type 'string)
356
357 (defcustom preview-gs-options '("-q" "-dDELAYSAFER" "-dNOPAUSE"
358 "-DNOPLATFONTS" "-dPrinted"
359 "-dTextAlphaBits=4"
360 "-dGraphicsAlphaBits=4")
361 "*Options with which to call gs for conversion from EPS.
362 See also `preview-gs-command'."
363 :group 'preview-gs
364 :type '(repeat string))
365
366 (defvar preview-gs-queue nil
367 "List of overlays to convert using gs.
368 Buffer-local to the appropriate TeX process buffer.")
369 (make-variable-buffer-local 'preview-gs-queue)
370
371 (defvar preview-gs-outstanding nil
372 "Overlays currently processed.")
373 (make-variable-buffer-local 'preview-gs-outstanding)
374
375 (defcustom preview-gs-outstanding-limit 2
376 "*Number of requests allowed to be outstanding.
377 This is the number of not-yet-completed requests we
378 might at any time have piped into Ghostscript. If
379 this number is larger, the probability of Ghostscript
380 working continuously is higher when Emacs is rather
381 busy. If this number is smaller, redisplay will
382 follow changes in the displayed buffer area faster."
383 :group 'preview-gs
384 :type '(restricted-sexp
385 :match-alternatives
386 ((lambda (value) (and
387 (integerp value)
388 (> value 0)
389 (< value 10))))
390 :tag "small number"))
391
392 (defvar preview-gs-answer nil
393 "Accumulated answer of Ghostscript process.")
394 (make-variable-buffer-local 'preview-gs-answer)
395
396 (defvar preview-gs-image-type nil
397 "Image type for gs produced images.")
398 (make-variable-buffer-local 'preview-gs-image-type)
399
400 (defvar preview-gs-sequence nil
401 "Pair of sequence numbers for gs produced images.")
402 (make-variable-buffer-local 'preview-gs-sequence)
403
404 (defvar preview-scale nil
405 "Screen scale of images.
406 Magnify by this factor to make images blend with other
407 screen content. Buffer-local to rendering buffer.")
408 (make-variable-buffer-local 'preview-scale)
409
410 (defvar preview-colors nil
411 "Color setup list.
412 An array with elements 0, 1 and 2 for background,
413 foreground and border colors, respectively. Each element
414 is a list of 3 real numbers between 0 and 1, or NIL
415 of nothing special should be done for the color")
416 (make-variable-buffer-local 'preview-colors)
417
418 (defvar preview-gs-init-string nil
419 "Ghostscript setup string.")
420 (make-variable-buffer-local 'preview-gs-init-string)
421
422 (defvar preview-ps-file nil
423 "PostScript file name for fast conversion.")
424 (make-variable-buffer-local 'preview-ps-file)
425
426 (defvar preview-gs-dsc nil
427 "Parsed DSC information.")
428 (make-variable-buffer-local 'preview-gs-dsc)
429
430 (defvar preview-resolution nil
431 "Screen resolution where rendering started.
432 Cons-cell of x and y resolution, given in
433 dots per inch. Buffer-local to rendering buffer.")
434 (make-variable-buffer-local 'preview-resolution)
435
436 (defun preview-gs-resolution (scale xres yres)
437 "Generate resolution argument for gs.
438 Calculated from real-life factor SCALE and XRES and
439 YRES, the screen resolution in dpi."
440 (format "-r%gx%g"
441 (/ (* scale xres) (preview-get-magnification))
442 (/ (* scale yres) (preview-get-magnification))))
443
444 (defun preview-gs-behead-outstanding (err)
445 "Remove leading element of outstanding queue after error.
446 Return element if non-nil. ERR is the error string to
447 show as response of Ghostscript."
448 (let ((ov (pop preview-gs-outstanding)))
449 (when ov
450 (preview-gs-flag-error ov err)
451 (overlay-put ov 'queued nil))
452 ov))
453
454 (defvar preview-gs-command-line nil)
455 (make-variable-buffer-local 'preview-gs-command-line)
456 (defvar preview-gs-file nil)
457 (make-variable-buffer-local 'preview-gs-file)
458
459 (defcustom preview-fast-conversion t
460 "*Set this for single-file PostScript conversion.
461 This will have no effect when `preview-image-type' is
462 set to `postscript'."
463 :group 'preview-latex
464 :type 'boolean)
465
466 (defun preview-string-expand (arg &optional separator)
467 "Expand ARG as a string.
468 It can already be a string. Or it can be a list, then it is
469 recursively evaluated using SEPARATOR as separator. If a list
470 element is in itself a CONS cell, the CAR of the list (after symbol
471 dereferencing) can evaluate to either a string, in which case it is
472 used as a separator for the rest of the list,
473 or a boolean (t or nil) in which case the rest of the list is
474 either evaluated and concatenated or ignored, respectively.
475 ARG can be a symbol, and so can be the CDR
476 of a cell used for string concatenation."
477 (cond
478 ((stringp arg) arg)
479 ((consp arg)
480 (mapconcat
481 #'identity
482 (delq nil
483 (mapcar
484 (lambda(x)
485 (if (consp x)
486 (let ((sep (car x)))
487 (while (and (symbolp sep)
488 (not (memq sep '(t nil))))
489 (setq sep (symbol-value sep)))
490 (if (stringp sep)
491 (preview-string-expand (cdr x) sep)
492 (and sep
493 (preview-string-expand (cdr x)))))
494 (preview-string-expand x)))
495 arg))
496 (or separator "")))
497 ((and (symbolp arg) (not (memq arg '(t nil))))
498 (preview-string-expand (symbol-value arg) separator))
499 (t (error "Bad string expansion"))))
500
501 (defconst preview-expandable-string
502 ((lambda (f) (funcall f (funcall f 'sexp)))
503 (lambda (x)
504 `(choice
505 string
506 (repeat :tag "Concatenate"
507 (choice
508 string
509 (cons :tag "Separated list"
510 (choice (string :tag "Separator")
511 (symbol :tag "Indirect separator or flag"))
512 ,x)
513 (symbol :tag "Indirect variable (no separator)")))
514 (symbol :tag "Indirect variable (with separator)"))))
515 "Type to be used for `preview-string-expand'.
516 Just a hack until we get to learn how to do this properly.
517 Recursive definitions are not popular with Emacs,
518 so we define this type just two levels deep. This
519 kind of expandible string can either be just a string, or a
520 cons cell with a separator string in the CAR, and either
521 an explicit list of elements in the CDR, or a symbol to
522 be consulted recursively.")
523
524 (defcustom preview-dvipng-command
525 "dvipng -picky -noghostscript %d -o \"%m/prev%%03d.png\""
526 "*Command used for converting to separate PNG images.
527
528 You might specify options for converting to other image types,
529 but then you'll need to adapt `preview-dvipng-image-type'."
530 :group 'preview-latex
531 :type 'string)
532
533 (defcustom preview-dvipng-image-type
534 'png
535 "*Image type that dvipng produces.
536
537 You'll need to change `preview-dvipng-command' too,
538 if you customize this."
539 :group 'preview-latex
540 :type '(choice (const png)
541 (const gif)
542 (symbol :tag "Other" :value png)))
543
544 (defcustom preview-dvips-command
545 "dvips -Pwww -i -E %d -o %m/preview.000"
546 "*Command used for converting to separate EPS images."
547 :group 'preview-latex
548 :type 'string)
549
550 (defcustom preview-fast-dvips-command
551 "dvips -Pwww %d -o %m/preview.ps"
552 "*Command used for converting to a single PS file."
553 :group 'preview-latex
554 :type 'string)
555
556 (defcustom preview-pdf2dsc-command
557 "pdf2dsc %s.pdf %m/preview.dsc"
558 "*Command used for generating dsc from a PDF file."
559 :group 'preview-latex
560 :type 'string)
561
562 (defun preview-gs-queue-empty ()
563 "Kill off everything remaining in `preview-gs-queue'."
564 (mapc #'preview-delete preview-gs-outstanding)
565 (dolist (ov preview-gs-queue)
566 (if (overlay-get ov 'queued)
567 (preview-delete ov)))
568 (setq preview-gs-outstanding nil)
569 (setq preview-gs-queue nil))
570
571 (defvar preview-error-condition nil
572 "Last error raised and to be reported.")
573
574 (defun preview-log-error (err context &optional process)
575 "Log an error message to run buffer.
576 ERR is the caught error syndrome, CONTEXT is where it
577 occured, PROCESS is the process for which the run-buffer
578 is to be used."
579 (when (or (null process) (buffer-name (process-buffer process)))
580 (with-current-buffer (or (and process
581 (process-buffer process))
582 (current-buffer))
583 (save-excursion
584 (goto-char (or (and process
585 (process-buffer process)
586 (marker-buffer (process-mark process))
587 (process-mark process))
588 (point-max)))
589 (insert-before-markers
590 (format "%s: %s\n"
591 context (error-message-string err)))
592 (display-buffer (current-buffer)))))
593 (setq preview-error-condition err))
594
595 (defun preview-reraise-error (&optional process)
596 "Raise an error that has been logged.
597 Makes sure that PROCESS is removed from the \"Compilation\"
598 tag in the mode line."
599 (when preview-error-condition
600 (unwind-protect
601 (signal (car preview-error-condition) (cdr preview-error-condition))
602 (setq preview-error-condition nil
603 compilation-in-progress (delq process compilation-in-progress)))))
604
605 (defun preview-gs-sentinel (process string)
606 "Sentinel function for rendering process.
607 Gets the default PROCESS and STRING arguments
608 and tries to restart Ghostscript if necessary."
609 (condition-case err
610 (let ((status (process-status process)))
611 (when (memq status '(exit signal))
612 (setq compilation-in-progress (delq process compilation-in-progress)))
613 (when (buffer-name (process-buffer process))
614 (with-current-buffer (process-buffer process)
615 (goto-char (point-max))
616 (insert-before-markers "\n" mode-name " " string)
617 (forward-char -1)
618 (insert " at "
619 (substring (current-time-string) 0 -5))
620 (forward-char 1)
621 (TeX-command-mode-line process)
622 (when (memq status '(exit signal))
623 ;; process died.
624 ;; Throw away culprit, go on.
625 (let* ((err (concat preview-gs-answer "\n"
626 (process-name process) " " string))
627 (ov (preview-gs-behead-outstanding err)))
628 (when (and (null ov) preview-gs-queue)
629 (save-excursion
630 (goto-char (if (marker-buffer (process-mark process))
631 (process-mark process)
632 (point-max)))
633 (insert-before-markers err)))
634 (delete-process process)
635 (if (or (null ov)
636 (eq status 'signal))
637 ;; if process was killed explicitly by signal, or if nothing
638 ;; was processed, we give up on the matter altogether.
639 (progn
640 (when preview-ps-file
641 (condition-case nil
642 (preview-delete-file preview-ps-file)
643 (file-error nil)))
644 (preview-gs-queue-empty))
645
646 ;; restart only if we made progress since last call
647 (let (filenames)
648 (dolist (ov preview-gs-outstanding)
649 (setq filenames (overlay-get ov 'filenames))
650 (condition-case nil
651 (preview-delete-file (nth 1 filenames))
652 (file-error nil))
653 (setcdr filenames nil)))
654 (setq preview-gs-queue (nconc preview-gs-outstanding
655 preview-gs-queue))
656 (setq preview-gs-outstanding nil)
657 (preview-gs-restart)))))))
658 (error (preview-log-error err "Ghostscript" process)))
659 (preview-reraise-error process))
660
661 (defun preview-gs-filter (process string)
662 "Filter function for processing Ghostscript output.
663 Gets the usual PROCESS and STRING parameters, see
664 `set-process-filter' for a description."
665 (with-current-buffer (process-buffer process)
666 (setq preview-gs-answer (concat preview-gs-answer string))
667 (while (string-match "GS\\(<[0-9]+\\)?>" preview-gs-answer)
668 (let* ((pos (match-end 0))
669 (answer (substring preview-gs-answer 0 pos)))
670 (setq preview-gs-answer (substring preview-gs-answer pos))
671 (condition-case err
672 (preview-gs-transact process answer)
673 (error (preview-log-error err "Ghostscript filter" process))))))
674 (preview-reraise-error))
675
676 (defun preview-gs-restart ()
677 "Start a new Ghostscript conversion process."
678 (when preview-gs-queue
679 (if preview-gs-sequence
680 (setcar preview-gs-sequence (1+ (car preview-gs-sequence)))
681 (setq preview-gs-sequence (list 1)))
682 (setcdr preview-gs-sequence 1)
683 (let* ((process-connection-type nil)
684 (outfile (format "-dOutputFile=%s"
685 (preview-ps-quote-filename
686 (format "%s/pr%d-%%d.%s"
687 (car TeX-active-tempdir)
688 (car preview-gs-sequence)
689 preview-gs-image-type))))
690 (process
691 (apply #'start-process
692 "Preview-Ghostscript"
693 (current-buffer)
694 preview-gs-command
695 outfile
696 preview-gs-command-line)))
697 (goto-char (point-max))
698 (insert-before-markers "Running `Preview-Ghostscript' with ``"
699 (mapconcat #'shell-quote-argument
700 (append
701 (list preview-gs-command
702 outfile)
703 preview-gs-command-line)
704 " ") "''\n")
705 (setq preview-gs-answer "")
706 (process-kill-without-query process)
707 (set-process-sentinel process #'preview-gs-sentinel)
708 (set-process-filter process #'preview-gs-filter)
709 (process-send-string process preview-gs-init-string)
710 (setq mode-name "Preview-Ghostscript")
711 (push process compilation-in-progress)
712 (TeX-command-mode-line process)
713 (set-buffer-modified-p (buffer-modified-p))
714 process)))
715
716 (defun preview-gs-open (&optional setup)
717 "Start a Ghostscript conversion pass.
718 SETUP may contain a parser setup function."
719 (let ((image-info (assq preview-image-type preview-gs-image-type-alist)))
720 (setq preview-gs-image-type (nth 1 image-info))
721 (setq preview-gs-sequence nil)
722 (setq preview-gs-command-line (append
723 preview-gs-options
724 (nthcdr 2 image-info))
725 preview-gs-init-string
726 (format "{DELAYSAFER{.setsafe}if}stopped pop\
727 /.preview-BP currentpagedevice/BeginPage get dup \
728 null eq{pop{pop}bind}if def\
729 <</BeginPage{currentpagedevice/PageSize get dup 0 get 1 ne exch 1 get 1 ne or\
730 {.preview-BP %s}{pop}ifelse}bind/PageSize[1 1]>>setpagedevice\
731 /preview-do{[count 3 roll save]3 1 roll dup length 0 eq\
732 {pop}{setpagedevice}{ifelse .runandhide}\
733 stopped{handleerror quit}if \
734 aload pop restore}bind def "
735 (preview-gs-color-string preview-colors)))
736 (preview-gs-queue-empty)
737 (preview-parse-messages (or setup #'preview-gs-dvips-process-setup))))
738
739 (defun preview-gs-color-value (value)
740 "Return string to be used as color value for an RGB component.
741 Conversion from Emacs color numbers (0 to 65535) in VALUE
742 to Ghostscript floats."
743 (format "%g" (/ value 65535.0)))
744
745 (defun preview-pdf-color-string (colors)
746 "Return a string that patches PDF foreground color to work properly."
747 ;; Actually, this is rather brutal. It will only be invoked in
748 ;; cases, however, where previously it was not expected that
749 ;; anything readable turned up, anyway.
750 (let ((fg (aref colors 1)))
751 (if fg
752 (concat
753 "/GS_PDF_ProcSet GS_PDF_ProcSet dup maxlength dict copy dup begin\
754 /graphicsbeginpage{//graphicsbeginpage exec "
755 (mapconcat #'preview-gs-color-value fg " ")
756 " 3 copy rg RG}bind store end readonly store "))))
757
758 (defun preview-gs-color-string (colors)
759 "Return a string setting up colors"
760 (let ((bg (aref colors 0))
761 (fg (aref colors 1))
762 (mask (aref colors 2))
763 (border (aref colors 3)))
764 (concat
765 (and (or (and mask border) (and bg (not fg)))
766 "gsave ")
767 (and bg
768 (concat
769 (mapconcat #'preview-gs-color-value bg " ")
770 " setrgbcolor clippath fill "))
771 (and mask border
772 (format "%s setrgbcolor false setstrokeadjust %g \
773 setlinewidth clippath strokepath \
774 matrix setmatrix true \
775 {2 index{newpath}if round exch round exch moveto pop false}\
776 {round exch round exch lineto}{curveto}{closepath}\
777 pathforall pop fill "
778 (mapconcat #'preview-gs-color-value mask " ")
779 (* 2 border)))
780 ;; I hate antialiasing. Warp border to integral coordinates.
781 (and (or (and mask border) (and bg (not fg)))
782 "grestore ")
783 (and fg
784 (concat
785 (mapconcat #'preview-gs-color-value fg " ")
786 " setrgbcolor")))))
787
788 (defun preview-dvipng-color-string (colors res)
789 "Return color setup tokens for dvipng.
790 Makes a string of options suitable for passing to dvipng.
791 Pure borderless black-on-white will return an empty string."
792 (let
793 ((bg (aref colors 0))
794 (fg (aref colors 1))
795 (mask (aref colors 2))
796 (border (aref colors 3)))
797 (concat
798 (and bg
799 (format "--bg 'rgb %s' "
800 (mapconcat #'preview-gs-color-value bg " ")))
801 (and fg
802 (format "--fg 'rgb %s' "
803 (mapconcat #'preview-gs-color-value fg " ")))
804 (and mask border
805 (format "--bd 'rgb %s' "
806 (mapconcat #'preview-gs-color-value mask " ")))
807 (and border
808 (format "--bd %d" (max 1 (round (/ (* res border) 72.0))))))))
809
810 (defun preview-gs-dvips-process-setup ()
811 "Set up Dvips process for conversions via gs."
812 (unless (preview-supports-image-type preview-gs-image-type)
813 (error "preview-image-type setting '%s unsupported by this Emacs"
814 preview-gs-image-type))
815 (setq preview-gs-command-line (append
816 preview-gs-command-line
817 (list (preview-gs-resolution
818 (preview-hook-enquiry preview-scale)
819 (car preview-resolution)
820 (cdr preview-resolution)))))
821 (if preview-parsed-pdfoutput
822 (preview-pdf2dsc-process-setup)
823 (let ((process (preview-start-dvips preview-fast-conversion)))
824 (setq TeX-sentinel-function #'preview-gs-dvips-sentinel)
825 (list process (current-buffer) TeX-active-tempdir preview-ps-file
826 preview-gs-image-type))))
827
828 (defun preview-dvipng-process-setup ()
829 "Set up dvipng process for conversion."
830 (setq preview-gs-command-line (append
831 preview-gs-command-line
832 (list (preview-gs-resolution
833 (preview-hook-enquiry preview-scale)
834 (car preview-resolution)
835 (cdr preview-resolution)))))
836 (if preview-parsed-pdfoutput
837 (if (preview-supports-image-type preview-gs-image-type)
838 (preview-pdf2dsc-process-setup)
839 (error "preview-image-type setting '%s unsupported by this Emacs"
840 preview-gs-image-type))
841 (unless (preview-supports-image-type preview-dvipng-image-type)
842 (error "preview-dvipng-image-type setting '%s unsupported by this Emacs"
843 preview-dvipng-image-type))
844 (let ((process (preview-start-dvipng)))
845 (setq TeX-sentinel-function #'preview-dvipng-sentinel)
846 (list process (current-buffer) TeX-active-tempdir t
847 preview-dvipng-image-type))))
848
849
850 (defun preview-pdf2dsc-process-setup ()
851 (let ((process (preview-start-pdf2dsc)))
852 (setq TeX-sentinel-function #'preview-pdf2dsc-sentinel)
853 (list process (current-buffer) TeX-active-tempdir preview-ps-file
854 preview-gs-image-type)))
855
856 (defun preview-dvips-abort ()
857 "Abort a Dvips run."
858 (preview-gs-queue-empty)
859 (condition-case nil
860 (delete-file
861 (let ((gsfile preview-gs-file))
862 (with-current-buffer TeX-command-buffer
863 (funcall (car gsfile) "dvi"))))
864 (file-error nil))
865 (when preview-ps-file
866 (condition-case nil
867 (preview-delete-file preview-ps-file)
868 (file-error nil)))
869 (setq TeX-sentinel-function nil))
870
871 (defalias 'preview-dvipng-abort 'preview-dvips-abort)
872 ; "Abort a DviPNG run.")
873
874 (defun preview-gs-dvips-sentinel (process command &optional gsstart)
875 "Sentinel function for indirect rendering DviPS process.
876 The usual PROCESS and COMMAND arguments for
877 `TeX-sentinel-function' apply. Starts gs if GSSTART is set."
878 (condition-case err
879 (let ((status (process-status process))
880 (gsfile preview-gs-file))
881 (cond ((eq status 'exit)
882 (delete-process process)
883 (setq TeX-sentinel-function nil)
884 (condition-case nil
885 (delete-file
886 (with-current-buffer TeX-command-buffer
887 (funcall (car gsfile) "dvi")))
888 (file-error nil))
889 (if preview-ps-file
890 (preview-prepare-fast-conversion))
891 (when gsstart
892 (if preview-gs-queue
893 (preview-gs-restart)
894 (when preview-ps-file
895 (condition-case nil
896 (preview-delete-file preview-ps-file)
897 (file-error nil))))))
898 ((eq status 'signal)
899 (delete-process process)
900 (preview-dvips-abort))))
901 (error (preview-log-error err "DviPS sentinel" process)))
902 (preview-reraise-error process))
903
904 (defun preview-pdf2dsc-sentinel (process command &optional gsstart)
905 "Sentinel function for indirect rendering PDF process.
906 The usual PROCESS and COMMAND arguments for
907 `TeX-sentinel-function' apply. Starts gs if GSSTART is set."
908 (condition-case err
909 (let ((status (process-status process)))
910 (cond ((eq status 'exit)
911 (delete-process process)
912 (setq TeX-sentinel-function nil)
913 (setq preview-gs-init-string
914 (concat preview-gs-init-string
915 (preview-pdf-color-string preview-colors)))
916 (preview-prepare-fast-conversion)
917 (when gsstart
918 (if preview-gs-queue
919 (preview-gs-restart)
920 (when preview-ps-file
921 (condition-case nil
922 (preview-delete-file preview-ps-file)
923 (file-error nil))))))
924 ((eq status 'signal)
925 (delete-process process)
926 (preview-dvips-abort))))
927 (error (preview-log-error err "PDF2DSC sentinel" process)))
928 (preview-reraise-error process))
929
930 (defun preview-gs-close (process closedata)
931 "Clean up after PROCESS and set up queue accumulated in CLOSEDATA."
932 (setq preview-gs-queue (nconc preview-gs-queue closedata))
933 (if process
934 (if preview-gs-queue
935 (if TeX-process-asynchronous
936 (if (and (eq (process-status process) 'exit)
937 (null TeX-sentinel-function))
938 ;; Process has already finished and run sentinel
939 (progn
940 (when preview-ps-file
941 (condition-case nil
942 (preview-delete-file preview-ps-file)
943 (file-error nil)))
944 (preview-gs-restart))
945 (setq TeX-sentinel-function
946 `(lambda (process command)
947 (,(if preview-parsed-pdfoutput
948 'preview-pdf2dsc-sentinel
949 'preview-gs-dvips-sentinel)
950 process
951 command
952 t))))
953 (TeX-synchronous-sentinel "Preview-DviPS" (cdr preview-gs-file)
954 process))
955 ;; pathological case: no previews although we sure thought so.
956 (delete-process process)
957 (unless (eq (process-status process) 'signal)
958 (preview-dvips-abort)))))
959
960 (defun preview-dvipng-sentinel (process command &optional placeall)
961 "Sentinel function for indirect rendering DviPNG process.
962 The usual PROCESS and COMMAND arguments for
963 `TeX-sentinel-function' apply. Places all snippets if PLACEALL is set."
964 (condition-case err
965 (let ((status (process-status process)))
966 (cond ((eq status 'exit)
967 (delete-process process)
968 (setq TeX-sentinel-function nil)
969 (when placeall
970 (preview-dvipng-place-all)))
971 ((eq status 'signal)
972 (delete-process process)
973 (preview-dvipng-abort))))
974 (error (preview-log-error err "DviPNG sentinel" process)))
975 (preview-reraise-error process))
976
977 (defun preview-dvipng-close (process closedata)
978 "Clean up after PROCESS and set up queue accumulated in CLOSEDATA."
979 (if preview-parsed-pdfoutput
980 (preview-gs-close process closedata)
981 (setq preview-gs-queue (nconc preview-gs-queue closedata))
982 (if process
983 (if preview-gs-queue
984 (if TeX-process-asynchronous
985 (if (and (eq (process-status process) 'exit)
986 (null TeX-sentinel-function))
987 ;; Process has already finished and run sentinel
988 (preview-dvipng-place-all)
989 (setq TeX-sentinel-function (lambda (process command)
990 (preview-dvipng-sentinel
991 process
992 command
993 t))))
994 (TeX-synchronous-sentinel "Preview-DviPNG" (cdr preview-gs-file)
995 process))
996 ;; pathological case: no previews although we sure thought so.
997 (delete-process process)
998 (unless (eq (process-status process) 'signal)
999 (preview-dvipng-abort))))))
1000
1001 (defun preview-dsc-parse (file)
1002 "Parse DSC comments of FILE.
1003 Returns a vector with offset/length pairs corresponding to
1004 the pages. Page 0 corresponds to the initialization section."
1005 (with-temp-buffer
1006 (set-buffer-multibyte nil)
1007 (insert-file-contents-literally file)
1008 (let ((last-pt (point-min))
1009 trailer
1010 pagelist
1011 lastbegin
1012 pt
1013 case-fold-search
1014 (level 0))
1015 (while (search-forward-regexp "\
1016 %%\\(?:\\(BeginDocument:\\)\\|\
1017 \\(EndDocument[\n\r]\\)\\|\
1018 \\(Page:\\)\\|\
1019 \\(Trailer[\n\r]\\)\\)" nil t)
1020 (setq pt (match-beginning 0))
1021 (cond ((null (memq (char-before pt) '(?\C-j ?\C-m nil))))
1022 (trailer (error "Premature %%%%Trailer in `%s' at offsets %d/%d"
1023 file trailer pt))
1024 ((match-beginning 1)
1025 (if (zerop level)
1026 (setq lastbegin pt))
1027 (setq level (1+ level)))
1028 ((match-beginning 2)
1029 (if (zerop level)
1030 (error "Unmatched %%%%EndDocument in `%s' at offset %d"
1031 file pt)
1032 (setq level (1- level))))
1033 ((> level 0))
1034 ((match-beginning 3)
1035 (push (list last-pt (- pt last-pt)) pagelist)
1036 (setq last-pt pt))
1037 ((match-beginning 4)
1038 (setq trailer pt))))
1039 (unless (zerop level)
1040 (error "Unmatched %%%%BeginDocument in `%s' at offset %d"
1041 file lastbegin))
1042 (push (list last-pt
1043 (- (or trailer (point-max)) last-pt)) pagelist)
1044 (vconcat (nreverse pagelist)))))
1045
1046 (defun preview-gs-dsc-cvx (page dsc)
1047 "Generate PostScript code accessing PAGE in the DSC object.
1048 The returned PostScript code will need the file on
1049 top of the stack, and will replace it with an executable
1050 object corresponding to the wanted page."
1051 (let ((curpage (aref dsc page)))
1052 (format "dup %d setfileposition %d()/SubFileDecode filter cvx"
1053 (1- (car curpage)) (nth 1 curpage))))
1054
1055 (defun preview-ps-quote-filename (str &optional nonrel)
1056 "Make a PostScript string from filename STR.
1057 The file name is first made relative unless
1058 NONREL is not NIL."
1059 (unless nonrel (setq str (file-relative-name str)))
1060 (let ((index 0))
1061 (while (setq index (string-match "[\\()]" str index))
1062 (setq str (replace-match "\\\\\\&" t nil str)
1063 index (+ 2 index)))
1064 (concat "(" str ")")))
1065
1066 (defun preview-prepare-fast-conversion ()
1067 "This fixes up all parameters for fast conversion."
1068 (let* ((file (if (consp (car preview-ps-file))
1069 (if (consp (caar preview-ps-file))
1070 (car (last (caar preview-ps-file)))
1071 (caar preview-ps-file))
1072 (car preview-ps-file)))
1073 (all-files (if (and (consp (car preview-ps-file))
1074 (consp (caar preview-ps-file)))
1075 (caar preview-ps-file)
1076 (list file))))
1077 (setq preview-gs-dsc (preview-dsc-parse file))
1078 (setq preview-gs-init-string
1079 (concat (format "{<</PermitFileReading[%s]>> setuserparams \
1080 .locksafe} stopped pop "
1081 (mapconcat 'preview-ps-quote-filename all-files ""))
1082 preview-gs-init-string
1083 (format "[%s(r)file]aload exch %s .runandhide aload pop "
1084 (preview-ps-quote-filename file)
1085 (preview-gs-dsc-cvx 0 preview-gs-dsc))))))
1086
1087 (defun preview-gs-urgentize (ov buff)
1088 "Make a displayed overlay render with higher priority.
1089 This function is used in fake conditional display properties
1090 for reordering the conversion order to prioritize on-screen
1091 images. OV is the overlay in question, and BUFF is the
1092 Ghostscript process buffer where the buffer-local queue
1093 is located."
1094 ;; It does not matter that ov gets queued twice in that process: the
1095 ;; first version to get rendered will clear the 'queued property.
1096 ;; It cannot get queued more than twice since we remove the
1097 ;; conditional display property responsible for requeuing here.
1098 ;; We don't requeue if the overlay has been killed (its buffer made
1099 ;; nil). Not necessary, but while we are checking...
1100 ;; We must return t.
1101 (preview-remove-urgentization ov)
1102 (when (and (overlay-get ov 'queued)
1103 (overlay-buffer ov))
1104 (with-current-buffer buff
1105 (push ov preview-gs-queue)))
1106 t)
1107
1108
1109 (defun preview-gs-place (ov snippet box run-buffer tempdir ps-file imagetype)
1110 "Generate an image placeholder rendered over by Ghostscript.
1111 This enters OV into all proper queues in order to make it render
1112 this image for real later, and returns the overlay after setting
1113 a placeholder image. SNIPPET gives the number of the
1114 snippet in question for the file to be generated.
1115 BOX is a bounding box if we already know one via TeX.
1116 RUN-BUFFER is the buffer of the TeX process,
1117 TEMPDIR is the correct copy of `TeX-active-tempdir',
1118 PS-FILE is a copy of `preview-ps-file', IMAGETYPE is the image type
1119 for the file extension."
1120 (overlay-put ov 'filenames
1121 (unless (eq ps-file t)
1122 (list
1123 (preview-make-filename
1124 (or ps-file
1125 (format "preview.%03d" snippet))
1126 tempdir))))
1127 (overlay-put ov 'queued
1128 (vector box nil snippet))
1129 (overlay-put ov 'preview-image
1130 (list (preview-icon-copy preview-nonready-icon)))
1131 (preview-add-urgentization #'preview-gs-urgentize ov run-buffer)
1132 (list ov))
1133
1134 (defun preview-mouse-open-error (string)
1135 "Display STRING in a new view buffer on click."
1136 (let ((buff (get-buffer-create
1137 "*Preview-Ghostscript-Error*")))
1138 (with-current-buffer buff
1139 (kill-all-local-variables)
1140 (set (make-local-variable 'view-exit-action) #'kill-buffer)
1141 (setq buffer-undo-list t)
1142 (erase-buffer)
1143 (insert string)
1144 (goto-char (point-min)))
1145 (view-buffer-other-window buff)))
1146
1147 (defun preview-mouse-open-eps (file &optional position)
1148 "Display eps FILE in a view buffer on click.
1149 Place point at POSITION, else beginning of file."
1150 (let ((default-major-mode
1151 (or
1152 (assoc-default "x.ps" auto-mode-alist #'string-match)
1153 default-major-mode))
1154 (buff (get-file-buffer file)))
1155 (save-excursion
1156 (if buff
1157 (pop-to-buffer buff)
1158 (view-file-other-window file))
1159 (goto-char (or position (point-min)))
1160 (if (eq major-mode 'ps-mode) ; Bundled with GNU Emacs
1161 (message "%s" (substitute-command-keys "\
1162 Try \\[ps-run-start] \\[ps-run-buffer] and \
1163 \\<ps-run-mode-map>\\[ps-run-mouse-goto-error] on error offset." )))
1164 (if (eq major-mode 'postscript-mode) ; Bundled with XEmacs, limited
1165 (message "%s" (substitute-command-keys "\
1166 Try \\[ps-shell] and \\[ps-execute-buffer]."))))))
1167
1168 (defun preview-gs-flag-error (ov err)
1169 "Make an eps error flag in overlay OV for ERR string."
1170 (let* ((filenames (overlay-get ov 'filenames))
1171 (file (car (nth 0 filenames)))
1172 (outfile (format "-dOutputFile=%s"
1173 (preview-ps-quote-filename
1174 (car (nth 1 filenames)))))
1175 (ps-open
1176 `(lambda() (interactive "@")
1177 (preview-mouse-open-error
1178 ,(concat
1179 (mapconcat #'shell-quote-argument
1180 (append (list
1181 preview-gs-command
1182 outfile)
1183 preview-gs-command-line)
1184 " ")
1185 "\nGS>"
1186 preview-gs-init-string
1187 (aref (overlay-get ov 'queued) 1)
1188 err))))
1189 (str
1190 (preview-make-clickable
1191 nil
1192 preview-error-icon
1193 "%s views error message
1194 %s more options"
1195 ps-open
1196 `(lambda() (interactive)
1197 (popup-menu
1198 '("PostScript error"
1199 ["View error" ,ps-open]
1200 ["View source"
1201 (lambda () (interactive "@")
1202 ,(if preview-ps-file
1203 `(preview-mouse-open-eps
1204 ,(if (consp (car file))
1205 (nth 1 (car file))
1206 (car file))
1207 ,(nth 0 (aref preview-gs-dsc
1208 (aref (overlay-get ov 'queued) 2))))
1209 `(preview-mouse-open-eps ,file)))]))))))
1210 (overlay-put ov 'strings (cons str str))
1211 (preview-toggle ov)))
1212
1213 (defun preview-gs-transact (process answer)
1214 "Work off Ghostscript transaction.
1215 This routine is the action routine called via the process filter.
1216 The Ghostscript process buffer of PROCESS will already be selected, and
1217 and the standard output of Ghostscript up to the next prompt will be
1218 given as ANSWER."
1219 (let ((ov (pop preview-gs-outstanding))
1220 (have-error (not
1221 (string-match "\\`GS\\(<[0-9]+\\)?>\\'" answer ))))
1222 (when (and ov (overlay-buffer ov))
1223 (let ((queued (overlay-get ov 'queued)))
1224 (when queued
1225 (let* ((bbox (aref queued 0))
1226 (filenames (overlay-get ov 'filenames))
1227 (oldfile (nth 0 filenames))
1228 (newfile (nth 1 filenames)))
1229 (if have-error
1230 (preview-gs-flag-error ov answer)
1231 (condition-case nil
1232 (preview-delete-file oldfile)
1233 (file-error nil))
1234 (overlay-put ov 'filenames (cdr filenames))
1235 (preview-replace-active-icon
1236 ov
1237 (preview-create-icon (car newfile)
1238 preview-gs-image-type
1239 (preview-ascent-from-bb
1240 bbox)
1241 (aref preview-colors 2))))
1242 (overlay-put ov 'queued nil)))))
1243 (while (and (< (length preview-gs-outstanding)
1244 preview-gs-outstanding-limit)
1245 (setq ov (pop preview-gs-queue)))
1246 (let ((queued (overlay-get ov 'queued)))
1247 (when (and queued
1248 (not (memq ov preview-gs-outstanding))
1249 (overlay-buffer ov))
1250 (let* ((filenames (overlay-get ov 'filenames))
1251 (oldfile (car (nth 0
1252 (nconc filenames
1253 (list
1254 (preview-make-filename
1255 (format "pr%d-%d.%s"
1256 (car preview-gs-sequence)
1257 (cdr preview-gs-sequence)
1258 preview-gs-image-type)
1259 TeX-active-tempdir))))))
1260 (bbox (aset queued 0
1261 (or (and preview-prefer-TeX-bb
1262 (aref queued 0))
1263 (and (stringp oldfile)
1264 (preview-extract-bb
1265 oldfile))
1266 (aref queued 0)
1267 (error "No bounding box"))))
1268 (snippet (aref queued 2))
1269 (gs-line
1270 (format
1271 "%s<<%s>>preview-do\n"
1272 (if preview-ps-file
1273 (concat "dup "
1274 (preview-gs-dsc-cvx
1275 snippet
1276 preview-gs-dsc))
1277 (format "%s(r)file cvx"
1278 (preview-ps-quote-filename
1279 (if (listp oldfile)
1280 (car (last oldfile))
1281 oldfile))))
1282 (if preview-parsed-tightpage
1283 ""
1284 (format "/PageSize[%g %g]/PageOffset[%g \
1285 %g[1 1 dtransform exch]{0 ge{neg}if exch}forall]"
1286 (- (aref bbox 2) (aref bbox 0))
1287 (- (aref bbox 3) (aref bbox 1))
1288 (aref bbox 0) (aref bbox 1))))))
1289 (setcdr preview-gs-sequence (1+ (cdr preview-gs-sequence)))
1290 (setq preview-gs-outstanding
1291 (nconc preview-gs-outstanding
1292 (list ov)))
1293 (aset queued 1 gs-line)
1294 ;; ignore errors because of dying processes: they will get
1295 ;; caught by the sentinel, anyway.
1296 (condition-case nil
1297 (process-send-string
1298 process
1299 gs-line)
1300 (error nil))))))
1301 (unless preview-gs-outstanding
1302 (condition-case nil
1303 (process-send-eof process)
1304 (error nil)))))
1305
1306 (defun preview-hook-enquiry (hook)
1307 "Gets a value from a configured hook.
1308 HOOK is a list or single item, for which the first resolving to
1309 non-nil counts. Entries can be a callable function, or
1310 a symbol that is consulted, or a value. Lists are evaluated
1311 recursively."
1312 (cond ((functionp hook)
1313 (funcall hook))
1314 ((consp hook)
1315 (let (res)
1316 (while (and (not res) hook)
1317 (setq res (preview-hook-enquiry (car hook))
1318 hook (cdr hook)))
1319 res))
1320 ((and (symbolp hook) (boundp hook))
1321 (symbol-value hook))
1322 (t hook)))
1323
1324 (defcustom preview-scale-function #'preview-scale-from-face
1325 "*Scale factor for included previews.
1326 This can be either a function to calculate the scale, or
1327 a fixed number."
1328 :group 'preview-appearance
1329 :type '(choice (function-item preview-scale-from-face)
1330 (const 1.0)
1331 (number :value 1.0)
1332 (function :value preview-scale-from-face)))
1333
1334 (defcustom preview-default-document-pt 10
1335 "*Assumed document point size for `preview-scale-from-face'.
1336 If the point size (such as 11pt) of the document cannot be
1337 determined from the document options itself, assume this size.
1338 This is for matching screen font size and previews."
1339 :group 'preview-appearance
1340 :type
1341 '(choice (const :tag "10pt" 10)
1342 (const :tag "11pt" 11)
1343 (const :tag "12pt" 12)
1344 (number :tag "Other" :value 11.0))
1345 )
1346
1347 (defcustom preview-document-pt-list '(preview-parsed-font-size
1348 preview-auctex-font-size
1349 preview-default-document-pt)
1350 "*How `preview-document-pt' figures out the document size."
1351 :group 'preview-appearance
1352 :type
1353 '(repeat (choice
1354 ;; This is a bug: type function seems to match variables, too.
1355 (restricted-sexp :match-alternatives (functionp)
1356 :tag "Function" :value preview-auctex-font-size)
1357 (variable :value preview-parsed-font-size)
1358 (number :value 11))))
1359
1360 (defun preview-auctex-font-size ()
1361 "Calculate the default font size of document.
1362 If packages, classes or styles were called with an option
1363 like 10pt, size is taken from the first such option if you
1364 had let your document be parsed by AucTeX."
1365 (catch 'return (dolist (option (TeX-style-list))
1366 (if (string-match "\\`\\([0-9]+\\)pt\\'" option)
1367 (throw 'return
1368 (string-to-number
1369 (match-string 1 option)))))))
1370
1371 (defsubst preview-document-pt ()
1372 "Calculate the default font size of document."
1373 (preview-hook-enquiry preview-document-pt-list))
1374
1375 (defun preview-scale-from-face ()
1376 "Calculate preview scale from `preview-reference-face'.
1377 This calculates the scale of EPS images from a document assumed
1378 to have a default font size given by function `preview-document-pt'
1379 so that they match the reference face in height."
1380 `(lambda nil
1381 (/ ,(/ (preview-inherited-face-attribute 'preview-reference-face :height
1382 'default) 10.0)
1383 (preview-document-pt))))
1384
1385 (defvar preview-min-spec)
1386
1387 (defun preview-make-image (symbol)
1388 "Make an image from a preview spec list.
1389 The first spec that is workable (given the current setting of
1390 `preview-min-spec') from the given symbol is used here. The
1391 icon is cached in the property list of the symbol."
1392 (let ((alist (get 'preview-min-alist symbol)))
1393 (cdr (or
1394 (assq preview-min-spec alist)
1395 (car (put symbol 'preview-min-alist
1396 (cons
1397 (cons preview-min-spec
1398 (preview-filter-specs
1399 (symbol-value symbol)))
1400 alist)))))))
1401
1402 (defun preview-filter-specs (spec-list)
1403 "Find the first of the fitting specs and make an image."
1404 (let (image)
1405 (while (and spec-list
1406 (not (setq image
1407 (catch 'preview-filter-specs
1408 (preview-filter-specs-1 (car spec-list))))))
1409 (setq spec-list (cdr spec-list)))
1410 image))
1411
1412 (defun preview-filter-specs-1 (specs)
1413 (and specs
1414 (if (get 'preview-filter-specs (car specs))
1415 (apply (get 'preview-filter-specs (car specs)) specs)
1416 `(,(nth 0 specs) ,(nth 1 specs)
1417 ,@(preview-filter-specs-1 (nthcdr 2 specs))))))
1418
1419 (put 'preview-filter-specs :min
1420 #'(lambda (keyword value &rest args)
1421 (if (> value preview-min-spec)
1422 (throw 'preview-filter-specs nil)
1423 (preview-filter-specs-1 args))))
1424
1425 (defvar preview-datadir (file-name-directory load-file-name)
1426 "The directory relative to which package data may be found.
1427 This should be hardwired into the startup file containing the
1428 autoloads for preview-latex.")
1429
1430 (put 'preview-filter-specs :file
1431 #'(lambda (keyword value &rest args)
1432 `(:file ,(expand-file-name value (expand-file-name "images"
1433 preview-datadir))
1434 ,@(preview-filter-specs-1 args))))
1435
1436 (defun preview-ascent-from-bb (bb)
1437 "This calculates the image ascent from its bounding box.
1438 The bounding box BB needs to be a 4-component vector of
1439 numbers (can be float if available)."
1440 ;; baseline is at 1in from the top of letter paper (11in), so it is
1441 ;; at 10in from the bottom precisely, which is 720 in PostScript
1442 ;; coordinates. If our bounding box has its bottom not above this
1443 ;; line, and its top above, we can calculate a useful ascent value.
1444 ;; If not, something is amiss. We just use 100 in that case.
1445
1446 (let ((bottom (aref bb 1))
1447 (top (aref bb 3)))
1448 (if (and (<= bottom 720)
1449 (> top 720))
1450 (round (* 100.0 (/ (- top 720.0) (- top bottom))))
1451 100)))
1452
1453 (defface preview-face '((((background dark))
1454 (:background "dark slate gray"))
1455 (t
1456 (:background "beige")))
1457 "Face to use for the preview source."
1458 :group 'preview-appearance)
1459
1460 (defface preview-reference-face '((t nil))
1461 "Face consulted for colors and scale of active previews.
1462 Fallback to :inherit and 'default implemented."
1463 :group 'preview-appearance)
1464
1465 (defcustom preview-auto-reveal
1466 '(eval (preview-arrived-via (key-binding [left]) (key-binding [right])
1467 'backward-char 'forward-char))
1468 "*Cause previews to open automatically when entered.
1469 Possibilities are:
1470 T autoopens,
1471 NIL doesn't,
1472 a symbol will have its value consulted if it exists,
1473 defaulting to NIL if it doesn't.
1474 An integer will specify a maximum cursor movement distance.
1475 Larger movements won't open the preview.
1476 A CONS-cell means to call a function for determining the value.
1477 The CAR of the cell is the function to call which receives
1478 the CDR of the CONS-cell in the rest of the arguments, while
1479 point and current buffer point to the position in question.
1480 All of the options show reasonable defaults."
1481 :group 'preview-appearance
1482 :type '(choice (const :tag "Off" nil)
1483 (const :tag "On" t)
1484 (symbol :tag "Indirect variable" :value reveal-mode)
1485 (integer :tag "Maximum distance" :value 1)
1486 (cons :tag "Function call"
1487 :value (eval (preview-arrived-via
1488 (key-binding [left])
1489 (key-binding [right])))
1490 function (list :tag "Argument list"
1491 (repeat :inline t sexp)))))
1492
1493 (defun preview-auto-reveal-p (mode distance)
1494 "Decide whether to auto-reveal.
1495 Returns non-NIL if region should be auto-opened.
1496 See `preview-auto-reveal' for definitions of MODE, which gets
1497 set to `preview-auto-reveal'. DISTANCE specifies the movement
1498 distance with which point has been reached in case it has been
1499 a movement starting in the current buffer."
1500 (cond ((symbolp mode)
1501 (and (boundp mode)
1502 (symbol-value mode)))
1503 ((integerp mode)
1504 (and distance (/= 0 distance) (<= (abs distance) mode)))
1505 ((consp mode)
1506 (apply (car mode) (cdr mode)))
1507 (t mode)))
1508
1509 (defun preview-arrived-via (&rest list)
1510 "Indicate auto-opening.
1511 Returns non-NIL if called by one of the commands in LIST."
1512 (memq this-command list))
1513
1514 (defcustom preview-equality-transforms '(identity
1515 preview-canonical-spaces)
1516 "Transformation functions for region changes.
1517 These functions are tried in turn on the strings from the
1518 regions of a preview to decide whether a preview is to be considered
1519 changed. If any transform leads to equal results, the preview is
1520 considered unchanged."
1521 :group 'preview-appearance
1522 :type '(repeat function))
1523
1524 (defun preview-relaxed-string= (&rest args)
1525 "Check for functional equality of arguments.
1526 The arguments ARGS are checked for equality by using
1527 `preview-equality-transforms' on them until it is exhausted
1528 or one transform returns equality."
1529 (let ((lst preview-equality-transforms))
1530 (while (and lst (not (apply #'string= (mapcar (car lst) args))))
1531 (setq lst (cdr lst)))
1532 lst))
1533
1534 (defun preview-canonical-spaces (arg)
1535 "Convert ARG into canonical form.
1536 Removes comments and collapses white space, except for multiple newlines."
1537 (let (pos)
1538 (while (setq pos (string-match "\\s<.*[\n\r][ \t]*" arg pos))
1539 (setq arg (replace-match "" t t arg 0)))
1540 (while (setq pos (string-match "[ \t]*\\(\\([ \t]\\)\\|[\n\r][ \t]*\\)"
1541 arg pos))
1542 (setq arg (replace-match (if (match-beginning 2) " " "\n") t t arg 0)
1543 pos (1+ pos)))
1544 (while (setq pos (string-match "\n+" arg pos))
1545 (if (string= "\n" (match-string 0 arg))
1546 (setq arg (replace-match " " t t arg 0)
1547 pos (1+ pos))
1548 (setq pos (match-end 0)))))
1549 arg)
1550
1551 (defun preview-regenerate (ovr)
1552 "Pass the modified region in OVR again through LaTeX."
1553 (let ((begin (overlay-start ovr))
1554 (end (overlay-end ovr)))
1555 (with-current-buffer (overlay-buffer ovr)
1556 (preview-delete ovr)
1557 (preview-region begin end))))
1558
1559 (defcustom preview-inner-environments '("Bmatrix" "Vmatrix" "aligned"
1560 "array" "bmatrix" "cases"
1561 "gathered" "matrix" "pmatrix"
1562 "smallmatrix" "split"
1563 "subarray" "vmatrix")
1564 "Environments not to be previewed on their own."
1565 :group 'preview-latex
1566 :type '(repeat string))
1567
1568
1569 (defun preview-next-border (backwards)
1570 "Search for the next interesting border for `preview-at-point'.
1571 Searches backwards if BACKWARDS is non-nil."
1572 (let (history preview-state (pt (point)))
1573 (catch 'exit
1574 (while
1575 (null
1576 (memq
1577 (setq preview-state
1578 (if backwards
1579 (if (> (setq pt
1580 (previous-single-char-property-change
1581 pt 'preview-state)) (point-min))
1582 (get-char-property (1- pt) 'preview-state)
1583 (throw 'exit (or history (point-min))))
1584 (if (< (setq pt
1585 (next-single-char-property-change
1586 pt 'preview-state)) (point-max))
1587 (get-char-property pt 'preview-state)
1588 (throw 'exit (or history (point-max))))))
1589 '(active inactive)))
1590 (setq history (and (not preview-state) pt)))
1591 (or history pt))))
1592
1593 (defun preview-at-point ()
1594 "Do the appropriate preview thing at point.
1595 If point is positioned on or inside of an unmodified preview area,
1596 its visibility is toggled.
1597
1598 If not, the surroundings are run through preview. The
1599 surroundings don't extend into unmodified previews or past
1600 contiguous previews invalidated by modifications.
1601
1602 Overriding any other action, if a region is
1603 active (`transient-mark-mode' or `zmacs-regions'), it is run
1604 through `preview-region'."
1605 (interactive)
1606 (if (TeX-active-mark)
1607 (preview-region (region-beginning) (region-end))
1608 (catch 'exit
1609 (dolist (ovr (overlays-in (max (point-min) (1- (point)))
1610 (min (point-max) (1+ (point)))))
1611 (let ((preview-state (overlay-get ovr 'preview-state)))
1612 (when preview-state
1613 (unless (eq preview-state 'disabled)
1614 (preview-toggle ovr 'toggle (selected-window))
1615 (throw 'exit t)))))
1616 (preview-region (preview-next-border t)
1617 (preview-next-border nil)))))
1618
1619 (defun preview-disabled-string (ov)
1620 "Generate a before-string for disabled preview overlay OV."
1621 (concat (preview-make-clickable
1622 (overlay-get ov 'preview-map)
1623 preview-icon
1624 "\
1625 %s regenerates preview
1626 %s more options"
1627 `(lambda() (interactive) (preview-regenerate ,ov)))
1628 ;; icon on separate line only for stuff starting on its own line
1629 (with-current-buffer (overlay-buffer ov)
1630 (save-excursion
1631 (save-restriction
1632 (widen)
1633 (goto-char (overlay-start ov))
1634 (if (bolp) "\n" ""))))))
1635
1636 (defun preview-disable (ovr)
1637 "Change overlay behaviour of OVR after source edits."
1638 (overlay-put ovr 'queued nil)
1639 (preview-remove-urgentization ovr)
1640 (overlay-put ovr 'preview-image nil)
1641 (overlay-put ovr 'timestamp nil)
1642 (setcdr (overlay-get ovr 'strings) (preview-disabled-string ovr))
1643 (preview-toggle ovr)
1644 (overlay-put ovr 'preview-state 'disabled)
1645 (dolist (filename (overlay-get ovr 'filenames))
1646 (condition-case nil
1647 (preview-delete-file filename)
1648 (file-error nil))
1649 (overlay-put ovr 'filenames nil)))
1650
1651 (defun preview-delete (ovr &rest ignored)
1652 "Delete preview overlay OVR, taking any associated file along.
1653 IGNORED arguments are ignored, making this function usable as
1654 a hook in some cases"
1655 (let ((filenames (overlay-get ovr 'filenames)))
1656 (overlay-put ovr 'filenames nil)
1657 (delete-overlay ovr)
1658 (dolist (filename filenames)
1659 (condition-case nil
1660 (preview-delete-file filename)
1661 (file-error nil)))))
1662
1663 (defun preview-clearout (&optional start end timestamp)
1664 "Clear out all previews in the current region.
1665 When called interactively, the current region is used.
1666 Non-interactively, the region between START and END is
1667 affected. Those two values default to the borders of
1668 the entire buffer. If TIMESTAMP is non-nil, previews
1669 with a `timestamp' property of it are kept."
1670 (interactive "r")
1671 (dolist (ov (overlays-in (or start (point-min))
1672 (or end (point-max))))
1673 (and (overlay-get ov 'preview-state)
1674 (not (and timestamp
1675 (equal timestamp (overlay-get ov 'timestamp))))
1676 (preview-delete ov))))
1677
1678 (defun preview-clearout-buffer (&optional buffer)
1679 "Clearout BUFFER from previews, current buffer if nil."
1680 (interactive)
1681 (if buffer
1682 (with-current-buffer buffer (preview-clearout))
1683 (preview-clearout)))
1684
1685 (defun preview-clearout-section ()
1686 "Clearout previews from LaTeX section."
1687 (interactive)
1688 (save-excursion
1689 (LaTeX-mark-section)
1690 (preview-clearout (region-beginning) (region-end))))
1691
1692 (defun preview-clearout-at-point ()
1693 "Clearout any preview at point."
1694 (interactive)
1695 (preview-clearout (max (point-min) (1- (point)))
1696 (min (point-max) (1+ (point)))))
1697
1698 (defun preview-walk-document (func)
1699 "Cycle through all buffers belonging to current document.
1700 Each buffer having the same master file as the current file
1701 has FUNC called with its current buffer being set to it."
1702 (let* ((buffers (buffer-list))
1703 (master (expand-file-name (TeX-master-file t)))
1704 (default-buffers (list (current-buffer)
1705 (find-buffer-visiting master))))
1706 (while buffers
1707 (with-current-buffer (pop buffers)
1708 (when
1709 (or (memq (current-buffer) default-buffers)
1710 (and (memq major-mode '(plain-tex-mode latex-mode))
1711 (or (stringp TeX-master)
1712 (eq TeX-master t))
1713 (string= (expand-file-name (TeX-master-file t))
1714 master)))
1715 (funcall func))))))
1716
1717 (defun preview-clearout-document ()
1718 "Clear out all previews in current document.
1719 The document consists of all buffers that have the same master file
1720 as the current buffer. This makes the current document lose
1721 all previews."
1722 (interactive)
1723 (preview-walk-document #'preview-clearout-buffer))
1724
1725 (defun preview-kill-buffer-cleanup (&optional buf)
1726 "This is a cleanup function just for use in hooks.
1727 Cleans BUF or current buffer. The difference to
1728 `preview-clearout-buffer' is that previews
1729 associated with the last buffer modification time are
1730 kept."
1731 (with-current-buffer (or buf (current-buffer))
1732 (save-restriction
1733 (widen)
1734 (preview-clearout (point-min) (point-max) (visited-file-modtime)))))
1735
1736 (add-hook 'kill-buffer-hook #'preview-kill-buffer-cleanup)
1737 (add-hook 'before-revert-hook #'preview-kill-buffer-cleanup)
1738
1739 (defvar preview-last-counter)
1740
1741 (defun preview-extract-counters (ctr)
1742 (setq preview-last-counter
1743 (prog1 (copy-sequence ctr)
1744 (dolist (elt preview-last-counter)
1745 (setq ctr (delete elt ctr)))))
1746 (apply #'concat ctr))
1747
1748 (defun desktop-buffer-preview-misc-data (&rest ignored)
1749 "Hook function that extracts previews for persistent sessions."
1750 (unless (buffer-modified-p)
1751 (setq preview-last-counter nil)
1752 (save-restriction
1753 (widen)
1754 (let (save-info (timestamp (visited-file-modtime)))
1755 (dolist (ov (sort (overlays-in (point-min) (point-max))
1756 (lambda (x y) (< (overlay-start x)
1757 (overlay-start y)))))
1758 (when (and (memq (overlay-get ov 'preview-state) '(active inactive))
1759 (null (overlay-get ov 'queued))
1760 (cdr (overlay-get ov 'preview-image)))
1761 (push (preview-dissect ov timestamp) save-info)))
1762 (and save-info
1763 (cons 'preview (cons timestamp (nreverse save-info))))))))
1764
1765 (eval-after-load "desktop"
1766 '(add-hook
1767 'desktop-buffer-misc-functions
1768 #'desktop-buffer-preview-misc-data))
1769
1770 (defvar preview-temp-dirs nil
1771 "List of top level temporary directories in use from preview.
1772 Any directory not in this list will be cleared out by preview
1773 on first use.")
1774
1775 (defun preview-dissect (ov timestamp)
1776 "Extract all persistent data from OV and TIMESTAMP it."
1777 (let ((filenames (butlast (nth 0 (overlay-get ov 'filenames)))))
1778 (overlay-put ov 'timestamp timestamp)
1779 (list (overlay-start ov)
1780 (overlay-end ov)
1781 (cdr (overlay-get ov 'preview-image))
1782 filenames
1783 (let ((ctr (overlay-get ov 'preview-counters)))
1784 (and ctr
1785 (cons (preview-extract-counters (car ctr))
1786 (preview-extract-counters (cdr ctr))))))))
1787
1788 (defun preview-buffer-restore-internal (buffer-misc)
1789 "Restore previews from BUFFER-MISC if proper.
1790 Remove them if they have expired."
1791 (let ((timestamp (visited-file-modtime)) tempdirlist files)
1792 (setq preview-parsed-counters nil)
1793 (when (eq 'preview (pop buffer-misc))
1794 (preview-get-geometry)
1795 (if (equal (pop buffer-misc) timestamp)
1796 (dolist (ovdata buffer-misc)
1797 (setq tempdirlist
1798 (apply #'preview-reinstate-preview tempdirlist
1799 timestamp ovdata)))
1800 (dolist (ovdata buffer-misc)
1801 (setq files (nth 3 ovdata))
1802 (condition-case nil
1803 (delete-file (nth 0 files))
1804 (file-error nil))
1805 (unless (member (nth 1 files) tempdirlist)
1806 (push (nth 1 files) tempdirlist)))
1807 (dolist (dir tempdirlist)
1808 (condition-case nil
1809 (delete-directory dir)
1810 (file-error nil)))))))
1811
1812
1813 (defun preview-buffer-restore (buffer-misc)
1814 "At end of desktop load, reinstate previews.
1815 This delay is so that minor modes changing buffer positions
1816 \(like `x-symbol-mode' does) will not wreak havoc.
1817 BUFFER-MISC is the appropriate data to be used."
1818 (add-hook 'desktop-delay-hook `(lambda ()
1819 (with-current-buffer ,(current-buffer)
1820 (preview-buffer-restore-internal
1821 ',buffer-misc)))))
1822
1823 (defun desktop-buffer-preview (desktop-buffer-file-name
1824 desktop-buffer-name
1825 desktop-buffer-misc)
1826 "Hook function for restoring persistent previews into a buffer."
1827 (when (and desktop-buffer-file-name
1828 (file-readable-p desktop-buffer-file-name))
1829 (let ((buf (find-file-noselect desktop-buffer-file-name)))
1830 (if (eq (car desktop-buffer-misc) 'preview)
1831 (with-current-buffer buf
1832 (preview-buffer-restore desktop-buffer-misc)
1833 buf)
1834 buf))))
1835
1836 (eval-after-load "desktop"
1837 '(if (boundp 'desktop-buffer-mode-handlers)
1838 (add-to-list 'desktop-buffer-mode-handlers
1839 '(latex-mode . desktop-buffer-preview))
1840 (add-hook 'desktop-buffer-handlers '(lambda ()
1841 (desktop-buffer-preview
1842 desktop-buffer-file-name
1843 desktop-buffer-name
1844 desktop-buffer-misc)))))
1845
1846 (defcustom preview-auto-cache-preamble 'ask
1847 "*Whether to generate a preamble cache format automatically.
1848 Possible values are nil, t, and `ask'."
1849 :group 'preview-latex
1850 :type '(choice (const :tag "Cache" t)
1851 (const :tag "Don't cache" nil)
1852 (const :tag "Ask" ask)))
1853
1854 (defvar preview-dumped-alist nil
1855 "Alist of dumped masters.
1856 The elements are (NAME . ASSOC). NAME is the master file name
1857 \(without extension), ASSOC is what to do with regard to this
1858 format. Possible values: NIL means no format is available
1859 and none should be generated. T means no format is available,
1860 it should be generated on demand. If the value is a cons cell,
1861 the CAR of the cons cell is the command with which the format
1862 has been generated, and the CDR is some Emacs-flavor specific
1863 value used for maintaining a watch on possible changes of the
1864 preamble.")
1865
1866 (defun preview-cleanout-tempfiles ()
1867 "Clean out all directories and files with non-persistent data.
1868 This is called as a hook when exiting Emacs."
1869 (mapc #'preview-kill-buffer-cleanup (buffer-list))
1870 (mapc #'preview-format-kill preview-dumped-alist))
1871
1872 (defun preview-inactive-string (ov)
1873 "Generate before-string for an inactive preview overlay OV.
1874 This is for overlays where the source text has been clicked
1875 visible. For efficiency reasons it is expected that the buffer
1876 is already selected and unnarrowed."
1877 (concat
1878 (preview-make-clickable (overlay-get ov 'preview-map)
1879 preview-icon
1880 "\
1881 %s redisplays preview
1882 %s more options")
1883 ;; icon on separate line only for stuff starting on its own line
1884 (with-current-buffer (overlay-buffer ov)
1885 (save-excursion
1886 (save-restriction
1887 (widen)
1888 (goto-char (overlay-start ov))
1889 (if (bolp) "\n" ""))))))
1890
1891 (defun preview-dvipng-place-all ()
1892 "Place all images dvipng has created, if any.
1893 Deletes the dvi file when finished."
1894 (let (filename queued oldfiles snippet)
1895 (dolist (ov (prog1 preview-gs-queue (setq preview-gs-queue nil)))
1896 (when (and (setq queued (overlay-get ov 'queued))
1897 (setq snippet (aref (overlay-get ov 'queued) 2))
1898 (setq filename (preview-make-filename
1899 (format "prev%03d.%s"
1900 snippet preview-dvipng-image-type)
1901 TeX-active-tempdir)))
1902 (if (file-exists-p (car filename))
1903 (progn
1904 (overlay-put ov 'filenames (list filename))
1905 (preview-replace-active-icon
1906 ov
1907 (preview-create-icon (car filename)
1908 preview-dvipng-image-type
1909 (preview-ascent-from-bb
1910 (aref queued 0))
1911 (aref preview-colors 2)))
1912 (overlay-put ov 'queued nil))
1913 (push filename oldfiles)
1914 (overlay-put ov 'filenames nil)
1915 (push ov preview-gs-queue))))
1916 (if (setq preview-gs-queue (nreverse preview-gs-queue))
1917 (progn
1918 (preview-start-dvips preview-fast-conversion)
1919 (setq TeX-sentinel-function (lambda (process command)
1920 (preview-gs-dvips-sentinel
1921 process
1922 command
1923 t)))
1924 (dolist (ov preview-gs-queue)
1925 (setq snippet (aref (overlay-get ov 'queued) 2))
1926 (overlay-put ov 'filenames
1927 (list
1928 (preview-make-filename
1929 (or preview-ps-file
1930 (format "preview.%03d" snippet))
1931 TeX-active-tempdir))))
1932 (while (setq filename (pop oldfiles))
1933 (condition-case nil
1934 (preview-delete-file filename)
1935 (file-error nil))))
1936 (condition-case nil
1937 (let ((gsfile preview-gs-file))
1938 (delete-file
1939 (with-current-buffer TeX-command-buffer
1940 (funcall (car gsfile) "dvi"))))
1941 (file-error nil)))))
1942
1943 (defun preview-active-string (ov)
1944 "Generate before-string for active image overlay OV."
1945 (preview-make-clickable
1946 (overlay-get ov 'preview-map)
1947 (car (overlay-get ov 'preview-image))
1948 "%s opens text
1949 %s more options"))
1950
1951 (defun preview-make-filename (file tempdir)
1952 "Generate a preview filename from FILE and TEMPDIR.
1953 Filenames consist of a CONS-cell with absolute file name as CAR
1954 and TEMPDIR as CDR. TEMPDIR is a copy of `TeX-active-tempdir'
1955 with the directory name, the reference count and its top directory
1956 name elements. If FILE is already in that form, the file name itself
1957 gets converted into a CONS-cell with a name and a reference count."
1958 (if (consp file)
1959 (progn
1960 (if (consp (car file))
1961 (setcdr (car file) (1+ (cdr (car file))))
1962 (setcar file (cons (car file) 1)))
1963 file)
1964 (setcar (nthcdr 2 tempdir) (1+ (nth 2 tempdir)))
1965 (cons (expand-file-name file (nth 0 tempdir))
1966 tempdir)))
1967
1968 (defun preview-attach-filename (attached file)
1969 "Attaches the absolute file name ATTACHED to FILE."
1970 (if (listp (caar file))
1971 (setcar (car file) (cons attached (caar file)))
1972 (setcar (car file) (list attached (caar file))))
1973 file)
1974
1975 (defun preview-delete-file (file)
1976 "Delete a preview FILE.
1977 See `preview-make-filename' for a description of the data
1978 structure. If the containing directory becomes empty,
1979 it gets deleted as well."
1980 (let ((filename
1981 (if (consp (car file))
1982 (and (zerop
1983 (setcdr (car file) (1- (cdr (car file)))))
1984 (car (car file)))
1985 (car file))))
1986 (if filename
1987 (unwind-protect
1988 (if (listp filename)
1989 (dolist (elt filename) (delete-file elt))
1990 (delete-file filename))
1991 (let ((tempdir (cdr file)))
1992 (when tempdir
1993 (if (> (nth 2 tempdir) 1)
1994 (setcar (nthcdr 2 tempdir) (1- (nth 2 tempdir)))
1995 (setcdr file nil)
1996 (delete-directory (nth 0 tempdir)))))))))
1997
1998 (defvar preview-buffer-has-counters nil)
1999 (make-variable-buffer-local 'preview-buffer-has-counters)
2000
2001 (defun preview-place-preview (snippet start end
2002 box counters tempdir place-opts)
2003 "Generate and place an overlay preview image.
2004 This generates the filename for the preview
2005 snippet SNIPPET in the current buffer, and uses it for the
2006 region between START and END. BOX is an optional preparsed
2007 TeX bounding BOX passed on to the `place' hook.
2008 COUNTERS is the info about saved counter structures.
2009 TEMPDIR is a copy of `TeX-active-tempdir'.
2010 PLACE-OPTS are additional arguments passed into
2011 `preview-parse-messages'. Returns
2012 a list with additional info from the placement hook.
2013 Those lists get concatenated together and get passed
2014 to the close hook."
2015 (preview-clearout start end tempdir)
2016 (let ((ov (make-overlay start end nil nil nil)))
2017 (when (fboundp 'TeX-overlay-prioritize)
2018 (overlay-put ov 'priority (TeX-overlay-prioritize start end)))
2019 (overlay-put ov 'preview-map
2020 (preview-make-clickable
2021 nil nil nil
2022 `(lambda(event) (interactive "e")
2023 (preview-toggle ,ov 'toggle event))
2024 `(lambda(event) (interactive "e")
2025 (preview-context-menu ,ov event))))
2026 (overlay-put ov 'timestamp tempdir)
2027 (when (cdr counters)
2028 (overlay-put ov 'preview-counters counters)
2029 (setq preview-buffer-has-counters t))
2030 (prog1 (apply #'preview-call-hook 'place ov snippet box
2031 place-opts)
2032 (overlay-put ov 'strings
2033 (list (preview-active-string ov)))
2034 (preview-toggle ov t))))
2035
2036 ;; The following is a brutal hack. It relies on `begin' being let to
2037 ;; the start of the interesting area when TeX-region-create is being
2038 ;; called.
2039
2040 (defun preview-counter-find (begin)
2041 "Fetch the next preceding or next preview-counters property.
2042 Factored out because of compatibility macros XEmacs would
2043 not use in advice."
2044 ;; The following two lines are bug workaround for Emacs < 22.1.
2045 (if (markerp begin)
2046 (setq begin (marker-position begin)))
2047 (or (car (get-char-property begin 'preview-counters))
2048 (cdr (get-char-property (max (point-min)
2049 (1- begin))
2050 'preview-counters))
2051 (cdr (get-char-property
2052 (max (point-min)
2053 (1- (previous-single-char-property-change
2054 begin
2055 'preview-counters)))
2056 'preview-counters))
2057 (car (get-char-property
2058 (next-single-char-property-change begin 'preview-counters)
2059 'preview-counters))))
2060
2061 (defadvice TeX-region-create (around preview-counters)
2062 "Write out counter information to region."
2063 (let ((TeX-region-extra
2064 (concat
2065 (and (boundp 'begin)
2066 preview-buffer-has-counters
2067 (mapconcat
2068 #'identity
2069 (cons
2070 ""
2071 (preview-counter-find (symbol-value 'begin)))
2072 "\\setcounter"))
2073 TeX-region-extra)))
2074 ad-do-it))
2075
2076 (defun preview-reinstate-preview (tempdirlist timestamp start end
2077 image filename &optional counters)
2078 "Reinstate a single preview.
2079 This gets passed TEMPDIRLIST, a list consisting of the kind
2080 of entries used in `TeX-active-tempdir', and TIMESTAMP, the
2081 time stamp under which the file got read in. It returns an augmented
2082 list. START and END give the buffer location where the preview
2083 is to be situated, IMAGE the image to place there, and FILENAME
2084 the file to use: a triple consisting of filename, its temp directory
2085 and the corresponding topdir. COUNTERS is saved counter information,
2086 if any."
2087 (when
2088 (or (null filename) (file-readable-p (car filename)))
2089 (when filename
2090 (unless (equal (nth 1 filename) (car TeX-active-tempdir))
2091 (setq TeX-active-tempdir
2092 (or (assoc (nth 1 filename) tempdirlist)
2093 (car (push (append (cdr filename) (list 0))
2094 tempdirlist))))
2095 (setcar (cdr TeX-active-tempdir)
2096 (car (or (member (nth 1 TeX-active-tempdir)
2097 preview-temp-dirs)
2098 (progn
2099 (add-hook 'kill-emacs-hook
2100 #'preview-cleanout-tempfiles t)
2101 (push (nth 1 TeX-active-tempdir)
2102 preview-temp-dirs))))))
2103 (setcar (nthcdr 2 TeX-active-tempdir)
2104 (1+ (nth 2 TeX-active-tempdir)))
2105 (setcdr filename TeX-active-tempdir)
2106 (setq filename (list filename)))
2107 (let ((ov (make-overlay start end nil nil nil)))
2108 (when (fboundp 'TeX-overlay-prioritize)
2109 (overlay-put ov 'priority (TeX-overlay-prioritize start end)))
2110 (overlay-put ov 'preview-map
2111 (preview-make-clickable
2112 nil nil nil
2113 `(lambda(event) (interactive "e")
2114 (preview-toggle ,ov 'toggle event))
2115 `(lambda(event) (interactive "e")
2116 (preview-context-menu ,ov event))))
2117 (when counters
2118 (overlay-put
2119 ov 'preview-counters
2120 (cons
2121 (mapcar #'cdr
2122 (if (string= (car counters) "")
2123 preview-parsed-counters
2124 (setq preview-parsed-counters
2125 (preview-parse-counters (car counters)))))
2126 (mapcar #'cdr
2127 (if (string= (cdr counters) "")
2128 preview-parsed-counters
2129 (setq preview-parsed-counters
2130 (preview-parse-counters (cdr counters)))))))
2131 (setq preview-buffer-has-counters t))
2132 (overlay-put ov 'filenames filename)
2133 (overlay-put ov 'preview-image (cons (preview-import-image image)
2134 image))
2135 (overlay-put ov 'strings
2136 (list (preview-active-string ov)))
2137 (overlay-put ov 'timestamp timestamp)
2138 (preview-toggle ov t)))
2139 tempdirlist)
2140
2141 (defun preview-back-command (&optional nocomplex)
2142 "Move backward a TeX token.
2143 If NOCOMPLEX is set, only basic tokens and no argument sequences
2144 will be skipped over backwards."
2145 (let ((oldpos (point)) oldpoint)
2146 (condition-case nil
2147 (or (search-backward-regexp "\\(\\$\\$?\
2148 \\|\\\\[^a-zA-Z@]\
2149 \\|\\\\[a-zA-Z@]+\
2150 \\|\\\\begin[ \t]*{[^}]+}\
2151 \\)\\=" (line-beginning-position) t)
2152 nocomplex
2153 (if (eq ?\) (char-syntax (char-before)))
2154 (while
2155 (progn
2156 (setq oldpoint (point))
2157 (backward-sexp)
2158 (and (not (eq oldpoint (point)))
2159 (eq ?\( (char-syntax (char-after))))))
2160 (backward-char)))
2161 (error (goto-char oldpos)))))
2162
2163 (defcustom preview-required-option-list '("active" "tightpage" "auctex"
2164 (preview-preserve-counters
2165 "counters"))
2166 "Specifies required options passed to the preview package.
2167 These are passed regardless of whether there is an explicit
2168 \\usepackage of that package present."
2169 :group 'preview-latex
2170 :type preview-expandable-string)
2171
2172 (defcustom preview-preserve-counters nil
2173 "Try preserving counters for partial runs if set."
2174 :group 'preview-latex
2175 :type 'boolean)
2176
2177 (defcustom preview-default-option-list '("displaymath" "floats"
2178 "graphics" "textmath" "sections"
2179 "footnotes")
2180 "*Specifies default options to pass to preview package.
2181 These options are only used when the LaTeX document in question does
2182 not itself load the preview package, namely when you use preview
2183 on a document not configured for preview. \"auctex\", \"active\",
2184 \"dvips\" and \"delayed\" need not be specified here."
2185 :group 'preview-latex
2186 :type '(list (set :inline t :tag "Options known to work"
2187 :format "%t:\n%v%h" :doc
2188 "The above options are all the useful ones
2189 at the time of the release of this package.
2190 You should not need \"Other options\" unless you
2191 upgraded to a fancier version of just the LaTeX style.
2192 Please also note that `psfixbb' fails to have an effect if
2193 `preview-fast-conversion' or `preview-prefer-TeX-bb'
2194 are selected."
2195 (const "displaymath")
2196 (const "floats")
2197 (const "graphics")
2198 (const "textmath")
2199 (const "sections")
2200 (const "footnotes")
2201 (const "showlabels")
2202 (const "psfixbb"))
2203 (set :tag "Expert options" :inline t
2204 :format "%t:\n%v%h" :doc
2205 "Expert options should not be enabled permanently."
2206 (const "noconfig")
2207 (const "showbox")
2208 (const "tracingall"))
2209 (repeat :inline t :tag "Other options" (string))))
2210
2211 (defcustom preview-default-preamble
2212 '("\\RequirePackage[" ("," . preview-default-option-list)
2213 "]{preview}[2004/11/05]")
2214 "*Specifies default preamble code to add to a LaTeX document.
2215 If the document does not itself load the preview package, that is,
2216 when you use preview on a document not configured for preview, this
2217 list of LaTeX commands is inserted just before \\begin{document}."
2218 :group 'preview-latex
2219 :type preview-expandable-string)
2220
2221 (defcustom preview-LaTeX-command '("%`%l \"\\nonstopmode\\nofiles\
2222 \\PassOptionsToPackage{" ("," . preview-required-option-list) "}{preview}\
2223 \\AtBeginDocument{\\ifx\\ifPreview\\undefined"
2224 preview-default-preamble "\\fi}\"%' %t")
2225 "*Command used for starting a preview.
2226 See description of `TeX-command-list' for details."
2227 :group 'preview-latex
2228 :type preview-expandable-string)
2229
2230 (defun preview-goto-info-page ()
2231 "Read documentation for preview-latex in the info system."
2232 (interactive)
2233 (info "(preview-latex)"))
2234
2235 (eval-after-load 'info '(add-to-list 'Info-file-list-for-emacs
2236 '("preview" . "preview-latex")))
2237
2238 (defvar preview-map
2239 (let ((map (make-sparse-keymap)))
2240 (define-key map "\C-p" #'preview-at-point)
2241 (define-key map "\C-r" #'preview-region)
2242 (define-key map "\C-b" #'preview-buffer)
2243 (define-key map "\C-d" #'preview-document)
2244 (define-key map "\C-f" #'preview-cache-preamble)
2245 (define-key map "\C-c\C-f" #'preview-cache-preamble-off)
2246 (define-key map "\C-i" #'preview-goto-info-page)
2247 ;; (define-key map "\C-q" #'preview-paragraph)
2248 (define-key map "\C-e" #'preview-environment)
2249 (define-key map "\C-s" #'preview-section)
2250 (define-key map "\C-w" #'preview-copy-region-as-mml)
2251 (define-key map "\C-c\C-p" #'preview-clearout-at-point)
2252 (define-key map "\C-c\C-r" #'preview-clearout)
2253 (define-key map "\C-c\C-s" #'preview-clearout-section)
2254 (define-key map "\C-c\C-b" #'preview-clearout-buffer)
2255 (define-key map "\C-c\C-d" #'preview-clearout-document)
2256 map))
2257
2258 (defun preview-copy-text (ov)
2259 "Copy the text of OV into the kill buffer."
2260 (save-excursion
2261 (set-buffer (overlay-buffer ov))
2262 (copy-region-as-kill (overlay-start ov) (overlay-end ov))))
2263
2264 (defun preview-copy-mml (ov)
2265 "Copy an MML representation of OV into the kill buffer.
2266 This can be used to send inline images in mail and news when
2267 using MML mode."
2268 (when (catch 'badcolor
2269 (let ((str (car (preview-format-mml ov))))
2270 (if str
2271 (if (eq last-command 'kill-region)
2272 (kill-append str nil)
2273 (kill-new str))
2274 (error "No image file available")))
2275 nil)
2276 (let (preview-transparent-border)
2277 (preview-regenerate ov))))
2278
2279 (defun preview-copy-region-as-mml (start end)
2280 (interactive "r")
2281 (when (catch 'badcolor
2282 (let (str lst dont-ask)
2283 (dolist (ov (overlays-in start end))
2284 (when (setq str (preview-format-mml ov dont-ask))
2285 (setq dont-ask (cdr str))
2286 (and
2287 (>= (overlay-start ov) start)
2288 (<= (overlay-end ov) end)
2289 (push (list (- (overlay-start ov) start)
2290 (- (overlay-end ov) start)
2291 (car str)) lst))))
2292 (setq str (buffer-substring start end))
2293 (dolist (elt (nreverse (sort lst #'car-less-than-car)))
2294 (setq str (concat (substring str 0 (nth 0 elt))
2295 (nth 2 elt)
2296 (substring str (nth 1 elt)))))
2297 (if (eq last-command 'kill-region)
2298 (kill-append str nil)
2299 (kill-new str)))
2300 nil)
2301 (let (preview-transparent-border)
2302 (preview-region start end))))
2303
2304 (autoload 'mailcap-extension-to-mime "mailcap")
2305
2306 (defun preview-format-mml (ov &optional dont-ask)
2307 "Return an MML representation of OV as string.
2308 This can be used to send inline images in mail and news when
2309 using MML mode. If there is nothing current available,
2310 NIL is returned. If the image has a colored border and the
2311 user wants it removed when asked (unless DONT-ASK is set),
2312 'badcolor is thrown a t. The MML is returned in the car of the
2313 result, DONT-ASK in the cdr."
2314 (and (memq (overlay-get ov 'preview-state) '(active inactive))
2315 (not (overlay-get ov 'queued))
2316 (let* ((text (with-current-buffer (overlay-buffer ov)
2317 (buffer-substring (overlay-start ov)
2318 (overlay-end ov))))
2319 (image (cdr (overlay-get ov 'preview-image)))
2320 file type)
2321 (cond ((consp image)
2322 (and (not dont-ask)
2323 (nth 3 image)
2324 (if (y-or-n-p "Replace colored borders? ")
2325 (throw 'badcolor t)
2326 (setq dont-ask t)))
2327 (setq file (car (car (last (overlay-get ov 'filenames))))
2328 type (mailcap-extension-to-mime
2329 (file-name-extension file)))
2330 (cons
2331 (format "<#part %s
2332 description=\"%s\"
2333 filename=%s>
2334 <#/part>"
2335 (if type
2336 (format "type=\"%s\" disposition=inline" type)
2337 "disposition=attachment")
2338 (if (string-match "[\n\"]" text)
2339 "preview-latex image"
2340 text)
2341 (if (string-match "[ \n<>]" file)
2342 (concat "\"" file "\"")
2343 file))
2344 dont-ask))
2345 ((stringp image)
2346 (cons image dont-ask))))))
2347
2348 (defun preview-active-contents (ov)
2349 "Check whether we have a valid image associated with OV."
2350 (and (memq (overlay-get ov 'preview-state) '(active inactive)) t))
2351
2352 (defun preview-context-menu (ov ev)
2353 "Pop up a menu for OV at position EV."
2354 (popup-menu
2355 `("Preview"
2356 ["Toggle" (preview-toggle ,ov 'toggle ',ev)
2357 (preview-active-contents ,ov)]
2358 ["Regenerate" (preview-regenerate ,ov)]
2359 ["Remove" (preview-delete ,ov)]
2360 ["Copy text" (preview-copy-text ,ov)]
2361 ["Copy MIME" (preview-copy-mml ,ov)
2362 (preview-active-contents ,ov)])
2363 ev))
2364
2365 (defvar preview-TeX-style-dir)
2366
2367 (defun preview-TeX-style-cooked ()
2368 "Return `preview-TeX-style-dir' in cooked form.
2369 This will be fine for prepending to a `TEXINPUT' style
2370 environment variable, including an initial `.' at the front."
2371 (if (or (zerop (length preview-TeX-style-dir))
2372 (member (substring preview-TeX-style-dir -1) '(";" ":")))
2373 preview-TeX-style-dir
2374 (let ((sep
2375 (cond
2376 ((stringp TeX-kpathsea-path-delimiter)
2377 TeX-kpathsea-path-delimiter)
2378 ((string-match
2379 "\\`.[:]"
2380 (if (file-name-absolute-p preview-TeX-style-dir)
2381 preview-TeX-style-dir
2382 (expand-file-name preview-TeX-style-dir)))
2383 ";")
2384 (t ":"))))
2385 (concat "." sep preview-TeX-style-dir sep))))
2386
2387 (defun preview-set-texinputs (&optional remove)
2388 "Add `preview-TeX-style-dir' into `TEXINPUTS' variables.
2389 With prefix argument REMOVE, remove it again."
2390 (interactive "P")
2391 (let ((case-fold-search nil)
2392 (preview-TeX-style-dir (preview-TeX-style-cooked))
2393 pattern)
2394 (if remove
2395 (progn
2396 (setq pattern (concat "\\`\\(TEXINPUTS[^=]*\\)=\\(.*\\)"
2397 (regexp-quote preview-TeX-style-dir)))
2398 (dolist (env (copy-sequence process-environment))
2399 (if (string-match pattern env)
2400 (setenv (match-string 1 env)
2401 (and (or (< (match-beginning 2) (match-end 2))
2402 (< (match-end 0) (length env)))
2403 (concat (match-string 2 env)
2404 (substring env (match-end 0))))))))
2405 (setq pattern (regexp-quote preview-TeX-style-dir))
2406 (dolist (env (cons "TEXINPUTS=" (copy-sequence process-environment)))
2407 (if (string-match "\\`\\(TEXINPUTS[^=]*\\)=" env)
2408 (unless (string-match pattern env)
2409 (setenv (match-string 1 env)
2410 (concat preview-TeX-style-dir
2411 (substring env (match-end 0))))))))))
2412
2413 (defcustom preview-TeX-style-dir nil
2414 "This variable contains the location of uninstalled TeX styles.
2415 If this is nil, the preview styles are considered to be part of
2416 the installed TeX system.
2417
2418 Otherwise, it can either just specify an absolute directory, or
2419 it can be a complete TEXINPUTS specification. If it is the
2420 latter, it has to be followed by the character with which
2421 kpathsea separates path components, either `:' on Unix-like
2422 systems, or `;' on Windows-like systems. And it should be
2423 preceded with .: or .; accordingly in order to have . first in
2424 the search path.
2425
2426 The `TEXINPUT' environment type variables will get this prepended
2427 at load time calling \\[preview-set-texinputs] to reflect this.
2428 You can permanently install the style files using
2429 \\[preview-install-styles].
2430
2431 Don't set this variable other than with customize so that its
2432 changes get properly reflected in the environment."
2433 :group 'preview-latex
2434 :set (lambda (var value)
2435 (and (boundp var)
2436 (symbol-value var)
2437 (preview-set-texinputs t))
2438 (set var value)
2439 (and (symbol-value var)
2440 (preview-set-texinputs)))
2441 :type '(choice (const :tag "Installed" nil)
2442 (string :tag "Style directory or TEXINPUTS path")))
2443
2444 ;;;###autoload
2445 (defun preview-install-styles (dir &optional force-overwrite
2446 force-save)
2447 "Installs the TeX style files into a permanent location.
2448 This must be in the TeX search path. If FORCE-OVERWRITE is greater
2449 than 1, files will get overwritten without query, if it is less
2450 than 1 or nil, the operation will fail. The default of 1 for interactive
2451 use will query.
2452
2453 Similarly FORCE-SAVE can be used for saving
2454 `preview-TeX-style-dir' to record the fact that the uninstalled
2455 files are no longer needed in the search path."
2456 (interactive "DPermanent location for preview TeX styles
2457 pp")
2458 (unless preview-TeX-style-dir
2459 (error "Styles are already installed"))
2460 (dolist (file (or
2461 (condition-case nil
2462 (directory-files
2463 (progn
2464 (string-match
2465 "\\`\\(\\.[:;]\\)?\\(.*?\\)\\([:;]\\)?\\'"
2466 preview-TeX-style-dir)
2467 (match-string 2 preview-TeX-style-dir))
2468 t "\\.\\(sty\\|def\\|cfg\\)\\'")
2469 (error nil))
2470 (error "Can't find files to install")))
2471 (copy-file file dir (cond ((eq force-overwrite 1) 1)
2472 ((numberp force-overwrite)
2473 (> force-overwrite 1))
2474 (t force-overwrite))))
2475 (if (cond ((eq force-save 1)
2476 (y-or-n-p "Stop using non-installed styles permanently "))
2477 ((numberp force-save)
2478 (> force-save 1))
2479 (t force-save))
2480 (customize-save-variable 'preview-TeX-style-dir nil)
2481 (customize-set-variable 'preview-TeX-style-dir nil)))
2482
2483 ;;;###autoload
2484 (defun LaTeX-preview-setup ()
2485 "Hook function for embedding the preview package into AUCTeX.
2486 This is called by `LaTeX-mode-hook' and changes AUCTeX variables
2487 to add the preview functionality."
2488 (remove-hook 'LaTeX-mode-hook #'LaTeX-preview-setup)
2489 (add-hook 'LaTeX-mode-hook #'preview-mode-setup)
2490 (define-key LaTeX-mode-map "\C-c\C-p" preview-map)
2491 (easy-menu-define preview-menu LaTeX-mode-map
2492 "This is the menu for preview-latex."
2493 '("Preview"
2494 "Generate previews"
2495 ["(or toggle) at point" preview-at-point]
2496 ["for environment" preview-environment]
2497 ["for section" preview-section]
2498 ["for region" preview-region (preview-mark-active)]
2499 ["for buffer" preview-buffer]
2500 ["for document" preview-document]
2501 "---"
2502 "Remove previews"
2503 ["at point" preview-clearout-at-point]
2504 ["from section" preview-clearout-section]
2505 ["from region" preview-clearout (preview-mark-active)]
2506 ["from buffer" preview-clearout-buffer]
2507 ["from document" preview-clearout-document]
2508 "---"
2509 "Turn preamble cache"
2510 ["on" preview-cache-preamble]
2511 ["off" preview-cache-preamble-off]
2512 "---"
2513 ("Customize"
2514 ["Browse options"
2515 (customize-group 'preview)]
2516 ["Extend this menu"
2517 (easy-menu-add-item
2518 nil '("Preview")
2519 (customize-menu-create 'preview))])
2520 ["Read documentation" preview-goto-info-page]
2521 ["Report Bug" preview-report-bug]))
2522 (if (eq major-mode 'latex-mode)
2523 (preview-mode-setup))
2524 (if (boundp 'desktop-buffer-misc)
2525 (preview-buffer-restore desktop-buffer-misc)))
2526
2527 (defun preview-clean-subdir (dir)
2528 "Cleans out a temporary DIR with preview image files."
2529 (condition-case err
2530 (progn
2531 (mapc #'delete-file
2532 (directory-files dir t "\\`pr" t))
2533 (delete-directory dir))
2534 (error (message "Deletion of `%s' failed: %s" dir
2535 (error-message-string err)))))
2536
2537 (defun preview-clean-topdir (topdir)
2538 "Cleans out TOPDIR from temporary directories.
2539 This does not erase the directory itself since its permissions
2540 might be needed for colloborative work on common files."
2541 (mapc #'preview-clean-subdir
2542 (condition-case nil
2543 (directory-files topdir t "\\`tmp" t)
2544 (file-error nil))))
2545
2546 (defun preview-create-subdirectory ()
2547 "Create a temporary subdir for the current TeX process.
2548 If necessary, generates a fitting top
2549 directory or cleans out an existing one (if not yet
2550 visited in this session), then returns the name of
2551 the created subdirectory relative to the master directory,
2552 in shell-quoted form. `TeX-active-tempdir' is
2553 set to the corresponding TEMPDIR descriptor as described
2554 in `preview-make-filename'. The directory is registered
2555 in `preview-temp-dirs' in order not to be cleaned out
2556 later while in use."
2557 (let ((topdir (expand-file-name (TeX-active-master "prv"))))
2558 (if (file-directory-p topdir)
2559 (unless (member topdir preview-temp-dirs)
2560 ;; Cleans out the top preview directory by
2561 ;; removing subdirs possibly left from a previous session.
2562 (preview-clean-topdir topdir)
2563 (push topdir preview-temp-dirs))
2564 (make-directory topdir)
2565 (add-to-list 'preview-temp-dirs topdir))
2566 (add-hook 'kill-emacs-hook #'preview-cleanout-tempfiles t)
2567 (setq TeX-active-tempdir
2568 (list (make-temp-file (expand-file-name
2569 "tmp" (file-name-as-directory topdir)) t)
2570 topdir
2571 0))
2572 (shell-quote-argument
2573 (concat (file-name-as-directory (file-name-nondirectory topdir))
2574 (file-name-nondirectory (nth 0 TeX-active-tempdir))))))
2575
2576 ;; Hook into TeX immediately if it's loaded, use LaTeX-mode-hook if not.
2577 (if (featurep 'latex)
2578 (LaTeX-preview-setup)
2579 (add-hook 'LaTeX-mode-hook #'LaTeX-preview-setup))
2580
2581 ;;;###autoload (add-hook 'LaTeX-mode-hook #'LaTeX-preview-setup)
2582
2583 (defun preview-parse-counters (string)
2584 "Extract counter information from STRING."
2585 (let ((list preview-parsed-counters) (pos 0))
2586 (while (eq pos (string-match " *\\({\\([^{}]+\\)}{[-0-9]+}\\)" string pos))
2587 (setcdr (or (assoc (match-string 2 string) list)
2588 (car (push (list (match-string 2 string)) list)))
2589 (match-string 1 string))
2590 (setq pos (match-end 1)))
2591 list))
2592
2593 (defun preview-parse-tightpage (string)
2594 "Build tightpage vector from STRING,"
2595 (read (concat "[" string "]")))
2596
2597 (defvar preview-parse-variables
2598 '(("Fontsize" preview-parsed-font-size
2599 "\\` *\\([0-9.]+\\)pt\\'" 1 string-to-number)
2600 ("Magnification" preview-parsed-magnification
2601 "\\` *\\([0-9]+\\)\\'" 1 string-to-number)
2602 ("PDFoutput" preview-parsed-pdfoutput
2603 "" 0 stringp)
2604 ("Counters" preview-parsed-counters
2605 ".*" 0 preview-parse-counters)
2606 ("Tightpage" preview-parsed-tightpage
2607 "\\` *\\(-?[0-9]+ *\\)\\{4\\}\\'" 0 preview-parse-tightpage)))
2608
2609 (defun preview-error-quote (string run-coding-system)
2610 "Turn STRING with potential ^^ sequences into a regexp.
2611 To preserve sanity, additional ^ prefixes are matched literally,
2612 so the character represented by ^^^ preceding extended characters
2613 will not get matched, usually."
2614 (let (output case-fold-search)
2615 (when (featurep 'mule)
2616 (setq string (encode-coding-string string run-coding-system)))
2617 (while (string-match "\\^\\{2,\\}\\(\\([@-_?]\\)\\|[8-9a-f][0-9a-f]\\)"
2618 string)
2619 (setq output
2620 (concat output
2621 (regexp-quote (substring string
2622 0
2623 (- (match-beginning 1) 2)))
2624 (if (match-beginning 2)
2625 (concat
2626 "\\(?:" (regexp-quote
2627 (substring string
2628 (- (match-beginning 1) 2)
2629 (match-end 0)))
2630 "\\|"
2631 (char-to-string
2632 (logxor (aref string (match-beginning 2)) 64))
2633 "\\)")
2634 (char-to-string
2635 (string-to-number (match-string 1 string) 16))))
2636 string (substring string (match-end 0))))
2637 (setq output (concat output (regexp-quote string)))
2638 (if (featurep 'mule)
2639 (decode-coding-string output
2640 (or (and (boundp 'TeX-japanese-process-output-coding-system)
2641 TeX-japanese-process-output-coding-system)
2642 buffer-file-coding-system))
2643 output)))
2644
2645 (defun preview-parse-messages (open-closure)
2646 "Turn all preview snippets into overlays.
2647 This parses the pseudo error messages from the preview
2648 document style for LaTeX. OPEN-CLOSURE is called once
2649 it is certain that we have a valid output file, and it has
2650 to return in its CAR the PROCESS parameter for the CLOSE
2651 call, and in its CDR the final stuff for the placement hook."
2652 (with-temp-message "locating previews..."
2653 (let (TeX-error-file TeX-error-offset snippet box counters
2654 file line
2655 (lsnippet 0) lstart (lfile "") lline lbuffer lpoint
2656 lcounters
2657 string after-string error context-start
2658 context offset
2659 parsestate (case-fold-search nil)
2660 (run-buffer (current-buffer))
2661 (run-coding-system preview-coding-system)
2662 (run-directory default-directory)
2663 tempdir
2664 close-data
2665 open-data
2666 fast-hook
2667 slow-hook)
2668 ;; clear parsing variables
2669 (dolist (var preview-parse-variables)
2670 (set (nth 1 var) nil))
2671 (goto-char (point-min))
2672 (unwind-protect
2673 (progn
2674 (while
2675 (re-search-forward "\
2676 ^\\(!\\|\\(.*?\\):[0-9]+:\\) \\|\
2677 \(\\(/*\
2678 \\(?:\\.+[^()\r\n{} /]*\\|[^()\r\n{} ./]+\
2679 \\(?: [^()\r\n{} ./]+\\)*\\(?:\\.[-0-9a-zA-Z_.]*\\)?\\)\
2680 \\(?:/+\\(?:\\.+[^()\r\n{} /]*\\|[^()\r\n{} ./]+\
2681 \\(?: [^()\r\n{} ./]+\\)*\\(?:\\.[-0-9a-zA-Z_.]*\\)?\\)?\\)*\\)\
2682 )*\\(?: \\|\r?$\\)\\|\
2683 \\()+\\)\\|\
2684 !\\(?:offset(\\([---0-9]+\\))\\|\
2685 name(\\([^)]+\\))\\)\\|\
2686 ^Preview: \\([a-zA-Z]+\\) \\([^\n\r]*\\)\r?$" nil t)
2687 ;;; Ok, here is a line by line breakdown:
2688 ;;; match-alternative 1:
2689 ;;; error indicator for TeX error, either style.
2690 ;;; match-alternative 2:
2691 ;;; The same, but file-line-error-style, matching on file name.
2692 ;;; match-alternative 3:
2693 ;;; Too ugly to describe in detail. In short, we try to catch file
2694 ;;; names built from path components that don't contain spaces or
2695 ;;; other special characters once the file extension has started.
2696 ;;;
2697 ;;; Position for searching immediately after the file name so as to
2698 ;;; not miss closing parens or something.
2699 ;;; (match-string 3) is the file name.
2700 ;;; match-alternative 4:
2701 ;;; )+\( \|$\)
2702 ;;; a closing paren followed by the end of line or a space: a just
2703 ;;; closed file.
2704 ;;; match-alternative 5 (wrapped into one shy group with
2705 ;;; match-alternative 6, so that the match on first char is slightly
2706 ;;; faster):
2707 ;;; !offset(\([---0-9]+\))
2708 ;;; an AUCTeX offset message. (match-string 5) is the offset itself
2709 ;;; !name(\([^)]+\))
2710 ;;; an AUCTeX file name message. (match-string 6) is the file name
2711 ;;; TODO: Actually, the latter two should probably again match only
2712 ;;; after a space or newline, since that it what \message produces.
2713 ;;;disabled in prauctex.def:
2714 ;;;\(?:Ov\|Und\)erfull \\.*[0-9]*--[0-9]*
2715 ;;;\(?:.\{79\}
2716 ;;;\)*.*$\)\|
2717 ;;; This would have caught overfull box messages that consist of
2718 ;;; several lines of context all with 79 characters in length except
2719 ;;; of the last one. prauctex.def kills all such messages.
2720 (setq file (match-string-no-properties 2))
2721 (cond
2722 ((match-beginning 1)
2723 (if (looking-at "\
2724 \\(?:Preview\\|Package Preview Error\\): Snippet \\([---0-9]+\\) \\(started\\|ended\\(\
2725 \\.? *(\\([---0-9]+\\)\\+\\([---0-9]+\\)x\\([---0-9]+\\))\\)?\\)\\.")
2726 (progn
2727 (when file
2728 (unless TeX-error-file
2729 (push nil TeX-error-file)
2730 (push nil TeX-error-offset))
2731 (unless (car TeX-error-offset)
2732 (rplaca TeX-error-file file)))
2733 (setq snippet (string-to-number (match-string 1))
2734 box (unless
2735 (string= (match-string 2) "started")
2736 (if (match-string 4)
2737 (mapcar #'(lambda (x)
2738 (* (preview-get-magnification)
2739 (string-to-number x)))
2740 (list
2741 (match-string 4)
2742 (match-string 5)
2743 (match-string 6)))
2744 t))
2745 counters (mapcar #'cdr preview-parsed-counters)
2746 error (progn
2747 (setq lpoint (point))
2748 (end-of-line)
2749 (buffer-substring lpoint (point)))
2750
2751 ;; And the context for the help window.
2752 context-start (point)
2753
2754 ;; And the line number to position the cursor.
2755 ;;; variant 1: profiling seems to indicate the regexp-heavy solution
2756 ;;; to be favorable. Removing incomplete characters from the error
2757 ;;; context is an absolute nuisance.
2758 line (and (re-search-forward "\
2759 ^l\\.\\([0-9]+\\) \\(\\.\\.\\.\\(?:\\^*\\(?:[89a-f][0-9a-f]\\|[]@-\\_?]\\)\\|\
2760 \[0-9a-f]?\\)\\)?\\([^\n\r]*?\\)\r?
2761 \\([^\n\r]*?\\)\\(\\(?:\\^+[89a-f]?\\)?\\.\\.\\.\\)?\r?$" nil t)
2762 (string-to-number (match-string 1)))
2763 ;; And a string of the context to search for.
2764 string (and line (match-string 3))
2765 after-string (and line (buffer-substring
2766 (+ (match-beginning 4)
2767 (- (match-end 3)
2768 (match-beginning 0)))
2769 (match-end 4)))
2770
2771 ;; And we have now found to the end of the context.
2772 context (buffer-substring context-start (point))
2773 ;; We may use these in another buffer.
2774 offset (or (car TeX-error-offset) 0)
2775 file (car TeX-error-file))
2776 (when (and (stringp file)
2777 (or (string= file "<none>")
2778 (TeX-match-extension file)))
2779 ;; if we are the first time round, check for fast hooks:
2780 (when (null parsestate)
2781 (setq open-data
2782 (save-excursion (funcall open-closure))
2783 tempdir TeX-active-tempdir)
2784 (dolist
2785 (lst (if (listp TeX-translate-location-hook)
2786 TeX-translate-location-hook
2787 (list TeX-translate-location-hook)))
2788 (let ((fast
2789 (and (symbolp lst)
2790 (get lst 'TeX-translate-via-list))))
2791 (if fast
2792 (setq fast-hook
2793 (nconc fast-hook (list fast)))
2794 (setq slow-hook
2795 (nconc slow-hook (list lst)))))))
2796 (condition-case err
2797 (save-excursion (run-hooks 'slow-hook))
2798 (error (preview-log-error err "Translation hook")))
2799 (push (vector file (+ line offset)
2800 string after-string
2801 snippet box counters) parsestate)))
2802 ;; else normal error message
2803 (forward-line)
2804 (re-search-forward "^l\\.[0-9]" nil t)
2805 (forward-line 2)))
2806 ((match-beginning 3)
2807 ;; New file -- Push on stack
2808 (push (match-string-no-properties 3) TeX-error-file)
2809 (push nil TeX-error-offset)
2810 (goto-char (match-end 3)))
2811 ((match-beginning 4)
2812 ;; End of file -- Pop from stack
2813 (when (> (length TeX-error-file) 1)
2814 (pop TeX-error-file)
2815 (pop TeX-error-offset))
2816 (goto-char (1+ (match-beginning 0))))
2817 ((match-beginning 5)
2818 ;; Hook to change line numbers
2819 (setq TeX-error-offset
2820 (list (string-to-number (match-string 5)))))
2821 ((match-beginning 6)
2822 ;; Hook to change file name
2823 (setq TeX-error-file (list (match-string-no-properties 6))))
2824 ((match-beginning 7)
2825 (let ((var
2826 (assoc (match-string-no-properties 7)
2827 preview-parse-variables))
2828 (offset (- (match-beginning 0) (match-beginning 8)))
2829 (str (match-string-no-properties 8)))
2830 ;; paste together continuation lines:
2831 (while (= (- (length str) offset) 79)
2832 (search-forward-regexp "^\\([^\n\r]*\\)\r?$")
2833 (setq offset (- (length str))
2834 str (concat str (match-string-no-properties 1))))
2835 (when (and var
2836 (string-match (nth 2 var) str))
2837 (set (nth 1 var)
2838 (funcall (nth 4 var)
2839 (match-string-no-properties
2840 (nth 3 var)
2841 str))))))))
2842 (when (null parsestate)
2843 (error "LaTeX found no preview images")))
2844 (unwind-protect
2845 (save-excursion
2846 (setq parsestate (nreverse parsestate))
2847 (condition-case err
2848 (dolist (fun fast-hook)
2849 (setq parsestate
2850 (save-excursion (funcall fun parsestate))))
2851 (error (preview-log-error err "Fast translation hook")))
2852 (setq snippet 0)
2853 (dolist (state parsestate)
2854 (setq lsnippet snippet
2855 file (aref state 0)
2856 line (aref state 1)
2857 string (aref state 2)
2858 after-string (aref state 3)
2859 snippet (aref state 4)
2860 box (aref state 5)
2861 counters (aref state 6))
2862 (unless (string= lfile file)
2863 (set-buffer (if (string= file "<none>")
2864 (with-current-buffer run-buffer
2865 TeX-command-buffer)
2866 (find-file-noselect
2867 (expand-file-name file run-directory))))
2868 (setq lfile file))
2869 (save-excursion
2870 (save-restriction
2871 (widen)
2872 ;; a fast hook might have positioned us already:
2873 (if (number-or-marker-p string)
2874 (progn
2875 (goto-char string)
2876 (setq lpoint
2877 (if (number-or-marker-p after-string)
2878 after-string
2879 (line-beginning-position))))
2880 (if (and (eq (current-buffer) lbuffer)
2881 (<= lline line))
2882 ;; while Emacs does the perfectly correct
2883 ;; thing even when when the line differences
2884 ;; get zero or negative, I don't trust this
2885 ;; to be universally the case across other
2886 ;; implementations. Besides, if the line
2887 ;; number gets smaller again, we are probably
2888 ;; rereading the file, and restarting from
2889 ;; the beginning will probably be faster.
2890 (progn
2891 (goto-char lpoint)
2892 (if (/= lline line)
2893 (if (eq selective-display t)
2894 (re-search-forward "[\n\C-m]" nil
2895 'end
2896 (- line lline))
2897 (forward-line (- line lline)))))
2898 (goto-line line))
2899 (setq lpoint (point))
2900 (cond
2901 ((search-forward (concat string after-string)
2902 (line-end-position) t)
2903 (backward-char (length after-string)))
2904 ;;ok, transform ^^ sequences
2905 ((search-forward-regexp
2906 (concat "\\("
2907 (setq string
2908 (preview-error-quote
2909 string
2910 run-coding-system))
2911 "\\)"
2912 (setq after-string
2913 (preview-error-quote
2914 after-string
2915 run-coding-system)))
2916 (line-end-position) t)
2917 (goto-char (match-end 1)))
2918 ((search-forward-regexp
2919 (concat "\\("
2920 (if (string-match
2921 "^[^\0-\177]\\{1,6\\}" string)
2922 (setq string
2923 (substring string (match-end 0)))
2924 string)
2925 "\\)"
2926 (if (string-match
2927 "[^\0-\177]\\{1,6\\}$" after-string)
2928 (setq after-string
2929 (substring after-string
2930 0 (match-beginning 0)))))
2931 (line-end-position) t)
2932 (goto-char (match-end 1)))
2933 (t (search-forward-regexp
2934 string
2935 (line-end-position) t))))
2936 (setq lline line
2937 lbuffer (current-buffer))
2938 (if box
2939 (progn
2940 (if (and lstart (= snippet lsnippet))
2941 (setq close-data
2942 (nconc
2943 (preview-place-preview
2944 snippet
2945 (save-excursion
2946 (preview-back-command
2947 (= (prog1 (point)
2948 (goto-char lstart))
2949 lstart))
2950 (point))
2951 (point)
2952 (preview-TeX-bb box)
2953 (cons lcounters counters)
2954 tempdir
2955 (cdr open-data))
2956 close-data))
2957 (with-current-buffer run-buffer
2958 (preview-log-error
2959 (list 'error
2960 (format
2961 "End of Preview snippet %d unexpected"
2962 snippet)) "Parser")))
2963 (setq lstart nil))
2964 ;; else-part of if box
2965 (setq lstart (point) lcounters counters)
2966 ;; >= because snippets in between might have
2967 ;; been ignored because of TeX-default-extension
2968 (unless (>= snippet (1+ lsnippet))
2969 (with-current-buffer run-buffer
2970 (preview-log-error
2971 (list 'error
2972 (format
2973 "Preview snippet %d out of sequence"
2974 snippet)) "Parser"))))))))
2975 (preview-call-hook 'close (car open-data) close-data))))))
2976
2977 (defun preview-get-geometry ()
2978 "Transfer display geometry parameters from current display.
2979 Returns list of scale, resolution and colors. Calculation
2980 is done in current buffer."
2981 (condition-case err
2982 (let* ((geometry
2983 (list (preview-hook-enquiry preview-scale-function)
2984 (cons (/ (* 25.4 (display-pixel-width))
2985 (display-mm-width))
2986 (/ (* 25.4 (display-pixel-height))
2987 (display-mm-height)))
2988 (preview-get-colors)))
2989 (preview-min-spec
2990 (* (cdr (nth 1 geometry))
2991 (/
2992 (preview-inherited-face-attribute
2993 'preview-reference-face :height 'default)
2994 720.0))))
2995 (setq preview-icon (preview-make-image 'preview-icon-specs)
2996 preview-error-icon (preview-make-image
2997 'preview-error-icon-specs)
2998 preview-nonready-icon (preview-make-image
2999 'preview-nonready-icon-specs))
3000 geometry)
3001 (error (error "Display geometry unavailable: %s"
3002 (error-message-string err)))))
3003
3004 (defun preview-set-geometry (geometry)
3005 "Set geometry variables from GEOMETRY.
3006 Buffer-local `preview-scale', `preview-resolution',
3007 and `preview-colors' are set as given."
3008 (setq preview-scale (nth 0 geometry)
3009 preview-resolution (nth 1 geometry)
3010 preview-colors (nth 2 geometry)))
3011
3012 (defun preview-start-dvipng ()
3013 "Start a DviPNG process.."
3014 (let* ((file preview-gs-file)
3015 tempdir
3016 (res (/ (* (car preview-resolution)
3017 (preview-hook-enquiry preview-scale))
3018 (preview-get-magnification)))
3019 (resolution (format " -D%d " res))
3020 (colors (preview-dvipng-color-string preview-colors res))
3021 (command (with-current-buffer TeX-command-buffer
3022 (prog1
3023 (concat (TeX-command-expand preview-dvipng-command
3024 (car file))
3025 " " colors resolution)
3026 (setq tempdir TeX-active-tempdir))))
3027 (name "Preview-DviPNG"))
3028 (setq TeX-active-tempdir tempdir)
3029 (goto-char (point-max))
3030 (insert-before-markers "Running `" name "' with ``" command "''\n")
3031 (setq mode-name name)
3032 (setq TeX-sentinel-function
3033 (lambda (process name) (message "%s: done." name)))
3034 (if TeX-process-asynchronous
3035 (let ((process (start-process name (current-buffer) TeX-shell
3036 TeX-shell-command-option
3037 command)))
3038 (if TeX-after-start-process-function
3039 (funcall TeX-after-start-process-function process))
3040 (TeX-command-mode-line process)
3041 (set-process-filter process 'TeX-command-filter)
3042 (set-process-sentinel process 'TeX-command-sentinel)
3043 (set-marker (process-mark process) (point-max))
3044 (push process compilation-in-progress)
3045 (sit-for 0)
3046 process)
3047 (setq mode-line-process ": run")
3048 (set-buffer-modified-p (buffer-modified-p))
3049 (sit-for 0) ; redisplay
3050 (call-process TeX-shell nil (current-buffer) nil
3051 TeX-shell-command-option
3052 command))))
3053
3054 (defun preview-start-dvips (&optional fast)
3055 "Start a DviPS process.
3056 If FAST is set, do a fast conversion."
3057 (let* ((file preview-gs-file)
3058 tempdir
3059 (command (with-current-buffer TeX-command-buffer
3060 (prog1
3061 (TeX-command-expand (if fast
3062 preview-fast-dvips-command
3063 preview-dvips-command)
3064 (car file))
3065 (setq tempdir TeX-active-tempdir))))
3066 (name "Preview-DviPS"))
3067 (setq TeX-active-tempdir tempdir)
3068 (setq preview-ps-file (and fast
3069 (preview-make-filename
3070 (preview-make-filename
3071 "preview.ps" tempdir) tempdir)))
3072 (goto-char (point-max))
3073 (insert-before-markers "Running `" name "' with ``" command "''\n")
3074 (setq mode-name name)
3075 (setq TeX-sentinel-function
3076 (lambda (process name) (message "%s: done." name)))
3077 (if TeX-process-asynchronous
3078 (let ((process (start-process name (current-buffer) TeX-shell
3079 TeX-shell-command-option
3080 command)))
3081 (if TeX-after-start-process-function
3082 (funcall TeX-after-start-process-function process))
3083 (TeX-command-mode-line process)
3084 (set-process-filter process 'TeX-command-filter)
3085 (set-process-sentinel process 'TeX-command-sentinel)
3086 (set-marker (process-mark process) (point-max))
3087 (push process compilation-in-progress)
3088 (sit-for 0)
3089 process)
3090 (setq mode-line-process ": run")
3091 (set-buffer-modified-p (buffer-modified-p))
3092 (sit-for 0) ; redisplay
3093 (call-process TeX-shell nil (current-buffer) nil
3094 TeX-shell-command-option
3095 command))))
3096
3097 (defun preview-start-pdf2dsc ()
3098 "Start a PDF2DSC process."
3099 (let* ((file preview-gs-file)
3100 tempdir
3101 pdfsource
3102 (command (with-current-buffer TeX-command-buffer
3103 (prog1
3104 (TeX-command-expand preview-pdf2dsc-command
3105 (car file))
3106 (setq tempdir TeX-active-tempdir
3107 pdfsource (funcall `,(car file) "pdf")))))
3108 (name "Preview-PDF2DSC"))
3109 (setq TeX-active-tempdir tempdir)
3110 (setq preview-ps-file (preview-attach-filename
3111 pdfsource
3112 (preview-make-filename
3113 (preview-make-filename
3114 "preview.dsc" tempdir) tempdir)))
3115 (goto-char (point-max))
3116 (insert-before-markers "Running `" name "' with ``" command "''\n")
3117 (setq mode-name name)
3118 (setq TeX-sentinel-function
3119 (lambda (process name) (message "%s: done." name)))
3120 (if TeX-process-asynchronous
3121 (let ((process (start-process name (current-buffer) TeX-shell
3122 TeX-shell-command-option
3123 command)))
3124 (if TeX-after-start-process-function
3125 (funcall TeX-after-start-process-function process))
3126 (TeX-command-mode-line process)
3127 (set-process-filter process 'TeX-command-filter)
3128 (set-process-sentinel process 'TeX-command-sentinel)
3129 (set-marker (process-mark process) (point-max))
3130 (push process compilation-in-progress)
3131 (sit-for 0)
3132 process)
3133 (setq mode-line-process ": run")
3134 (set-buffer-modified-p (buffer-modified-p))
3135 (sit-for 0) ; redisplay
3136 (call-process TeX-shell nil (current-buffer) nil
3137 TeX-shell-command-option
3138 command))))
3139
3140 (defun preview-TeX-inline-sentinel (process name)
3141 "Sentinel function for preview.
3142 See `TeX-sentinel-function' and `set-process-sentinel'
3143 for definition of PROCESS and NAME."
3144 (if process (TeX-format-mode-line process))
3145 (let ((status (process-status process)))
3146 (if (memq status '(signal exit))
3147 (delete-process process))
3148 (when (eq status 'exit)
3149 (save-excursion
3150 (goto-char (point-max))
3151 (forward-line -1)
3152 (if (search-forward "abnormally with code 1" nil t)
3153 (replace-match "as expected with code 1" t t)
3154 (if (search-forward "finished" nil t)
3155 (insert " with nothing to show"))))
3156 (condition-case err
3157 (preview-call-hook 'open)
3158 (error (preview-log-error err "LaTeX" process)))
3159 (preview-reraise-error process))))
3160
3161 (defcustom preview-format-extensions '(".fmt" ".efmt")
3162 "Possible extensions for format files.
3163 Those are just needed for cleanup."
3164 :group 'preview-latex
3165 :type '(repeat string))
3166
3167 (defun preview-format-kill (format-cons)
3168 "Kill a cached format.
3169 FORMAT-CONS is intended to be an element of `preview-dumped-alist'.
3170 Tries through `preview-format-extensions'."
3171 (dolist (ext preview-format-extensions)
3172 (condition-case nil
3173 (delete-file (preview-dump-file-name (concat (car format-cons) ext)))
3174 (file-error nil))))
3175
3176 (defun preview-dump-file-name (file)
3177 "Make a file name suitable for dumping from FILE."
3178 (if file
3179 (concat (file-name-directory file)
3180 "prv_"
3181 (progn
3182 (setq file (file-name-nondirectory file))
3183 (while (string-match " " file)
3184 (setq file (replace-match "_" t t file)))
3185 file))
3186 "prv_texput"))
3187
3188 (defun preview-do-replacements (string replacements)
3189 "Perform replacements in string.
3190 STRING is the input string, REPLACEMENTS is a list of replacements.
3191 A replacement is a cons-cell, where the car is the match string,
3192 and the cdr is a list of strings or symbols. Symbols get dereferenced,
3193 and strings get evaluated as replacement strings."
3194 (let (rep case-fold-search)
3195 (while replacements
3196 (setq rep (pop replacements))
3197 (cond ((symbolp rep)
3198 (setq string (preview-do-replacements
3199 string (symbol-value rep))))
3200 ((string-match (car rep) string)
3201 (setq string
3202 (mapconcat (lambda(x)
3203 (if (symbolp x)
3204 (symbol-value x)
3205 (replace-match x t nil string)))
3206 (cdr rep) ""))))))
3207 string)
3208
3209 (defconst preview-LaTeX-disable-pdfoutput
3210 '(("\\`\\(pdf[^ ]*\\)\
3211 \\(\\( [-&]\\([^ \"]\\|\"[^\"]*\"\\)*\\|\
3212 \"[-&][^\"]*\"\\)*\\)\\(.*\\)\\'"
3213 . ("\\1\\2 \"\\\\pdfoutput=0 \" \\5")))
3214 "This replacement places `\"\\pdfoutput=0 \"' after the options
3215 of any command starting with `pdf'.")
3216
3217 (defcustom preview-LaTeX-command-replacements
3218 nil
3219 "Replacement for `preview-LaTeX-command'.
3220 This is passed through `preview-do-replacements'."
3221 :group 'preview-latex
3222 :type '(repeat
3223 (choice
3224 (symbol :tag "Named replacement" :value preview-LaTeX-disable-pdfoutput)
3225 (cons (string :tag "Matched string")
3226 (repeat :tag "Concatenated elements for replacement"
3227 (choice (symbol :tag "Variable with literal string")
3228 (string :tag "non-literal regexp replacement")))))))
3229
3230 (defvar preview-format-name)
3231
3232 (defcustom preview-dump-replacements
3233 '(preview-LaTeX-command-replacements
3234 ("\\`\\([^ ]+\\)\
3235 \\(\\( +-\\([^ \\\\\"]\\|\\\\\\.\\|\"[^\"]*\"\\)*\\)*\\)\\(.*\\)\\'"
3236 . ("\\1 -ini -interaction=nonstopmode \"&\\1\" " preview-format-name ".ini \\5")))
3237 "Generate a dump command from the usual preview command."
3238 :group 'preview-latex
3239 :type '(repeat
3240 (choice (symbol :tag "Named replacement")
3241 (cons string (repeat (choice symbol string))))))
3242
3243 (defcustom preview-undump-replacements
3244 '(("\\`\\([^ ]+\\)\
3245 .*? \"\\\\input\" \\(.*\\)\\'"
3246 . ("\\1 -interaction=nonstopmode \"&" preview-format-name "\" \\2")))
3247 "Use a dumped format for reading preamble."
3248 :group 'preview-latex
3249 :type '(repeat
3250 (choice (symbol :tag "Named replacement")
3251 (cons string (repeat (choice symbol string))))))
3252
3253
3254 (defun preview-cache-preamble (&optional format-cons)
3255 "Dump a pregenerated format file.
3256 For the rest of the session, this file is used when running
3257 on the same master file.
3258
3259 Returns the process for dumping, nil if there is still a valid
3260 format available.
3261
3262 If FORMAT-CONS is non-nil, a previous format may get reused."
3263 (interactive)
3264 (let* ((dump-file
3265 (expand-file-name (preview-dump-file-name (TeX-master-file "ini"))))
3266 (master (TeX-master-file))
3267 (format-name (expand-file-name master))
3268 (preview-format-name (shell-quote-argument
3269 (preview-dump-file-name (file-name-nondirectory
3270 master))))
3271 (master-file (expand-file-name (TeX-master-file t)))
3272 (command (preview-do-replacements
3273 (TeX-command-expand
3274 (preview-string-expand preview-LaTeX-command)
3275 'TeX-master-file)
3276 preview-dump-replacements))
3277 (preview-auto-cache-preamble nil))
3278 (unless (and (consp (cdr format-cons))
3279 (string= command (cadr format-cons)))
3280 (unless format-cons
3281 (setq format-cons (assoc format-name preview-dumped-alist)))
3282 (if format-cons
3283 (preview-cache-preamble-off format-cons)
3284 (setq format-cons (list format-name))
3285 (push format-cons preview-dumped-alist))
3286 ;; mylatex.ltx expects a file name to follow. Bad. `.tex'
3287 ;; in the tools bundle is an empty file.
3288 (write-region "\\ifx\\pdfoutput\\undefined\\else\
3289 \\let\\PREVIEWdump\\dump\\def\\dump{%
3290 \\edef\\next{{\\catcode`\\ 9 \\pdfoutput=\\the\\pdfoutput\\relax\
3291 \\the\\everyjob}}\\everyjob\\next\\catcode`\\ 10 \\let\\dump\\PREVIEWdump\\dump}\\fi\\input mylatex.ltx \\relax\n" nil dump-file)
3292 (TeX-save-document master)
3293 (prog1
3294 (preview-generate-preview
3295 nil (file-name-nondirectory master)
3296 command)
3297 (add-hook 'kill-emacs-hook #'preview-cleanout-tempfiles t)
3298 (setq TeX-sentinel-function
3299 `(lambda (process string)
3300 (condition-case err
3301 (progn
3302 (if (and (eq (process-status process) 'exit)
3303 (zerop (process-exit-status process)))
3304 (preview-watch-preamble
3305 ',master-file
3306 ',command
3307 ',format-cons)
3308 (preview-format-kill ',format-cons))
3309 (delete-file ',dump-file))
3310 (error (preview-log-error err "Dumping" process)))
3311 (preview-reraise-error process)))))))
3312
3313 (defun preview-cache-preamble-off (&optional old-format)
3314 "Clear the pregenerated format file.
3315 The use of the format file is discontinued.
3316 OLD-FORMAT may already contain a format-cons as
3317 stored in `preview-dumped-alist'."
3318 (interactive)
3319 (unless old-format
3320 (setq old-format
3321 (let ((master-file (expand-file-name (TeX-master-file))))
3322 (or (assoc master-file preview-dumped-alist)
3323 (car (push (list master-file) preview-dumped-alist))))))
3324 (preview-unwatch-preamble old-format)
3325 (preview-format-kill old-format)
3326 (setcdr old-format nil))
3327
3328 (defun preview-region (begin end)
3329 "Run preview on region between BEGIN and END."
3330 (interactive "r")
3331 (TeX-region-create (TeX-region-file TeX-default-extension)
3332 (buffer-substring begin end)
3333 (if buffer-file-name
3334 (file-name-nondirectory buffer-file-name)
3335 "<none>")
3336 (save-restriction
3337 (widen)
3338 (let ((inhibit-point-motion-hooks t)
3339 (inhibit-field-text-motion t))
3340 (+ (count-lines (point-min) begin)
3341 (save-excursion
3342 (goto-char begin)
3343 (if (bolp) 0 -1))))))
3344 (preview-generate-preview t (TeX-region-file nil t)
3345 (preview-do-replacements
3346 (TeX-command-expand
3347 (preview-string-expand preview-LaTeX-command)
3348 'TeX-region-file)
3349 preview-LaTeX-command-replacements)))
3350
3351 (defun preview-buffer ()
3352 "Run preview on current buffer."
3353 (interactive)
3354 (preview-region (point-min) (point-max)))
3355
3356 ;; We have a big problem: When we are dumping preambles, diagnostics
3357 ;; issued in later runs will not make it to the output when the
3358 ;; predumped format skips the preamble. So we have to place those
3359 ;; after \begin{document}. This we can only do if regions never
3360 ;; include the preamble. We could do this in our own functions, but
3361 ;; that would not extend to the operation of C-c C-r g RET. So we
3362 ;; make this preamble skipping business part of TeX-region-create.
3363 ;; This will fail if the region is to contain just part of the
3364 ;; preamble -- a bad idea anyhow.
3365
3366 (defadvice TeX-region-create (before preview-preamble preactivate activate)
3367 "Skip preamble for the sake of predumped formats."
3368 (when (string-match TeX-header-end (ad-get-arg 1))
3369 (ad-set-arg 1
3370 (prog1 (substring (ad-get-arg 1) (match-end 0))
3371 (ad-set-arg 3
3372 (with-temp-buffer
3373 (insert (substring (ad-get-arg 1)
3374 0 (match-end 0)))
3375 (+ (ad-get-arg 3)
3376 (count-lines (point-min) (point-max))
3377 (if (bolp) 0 -1))))))))
3378
3379 (defun preview-document ()
3380 "Run preview on master document."
3381 (interactive)
3382 (TeX-save-document (TeX-master-file))
3383 (preview-generate-preview
3384 nil (TeX-master-file nil t)
3385 (preview-do-replacements
3386 (TeX-command-expand
3387 (preview-string-expand preview-LaTeX-command)
3388 'TeX-master-file)
3389 preview-LaTeX-command-replacements)))
3390
3391 (defun preview-environment (count)
3392 "Run preview on LaTeX environment.
3393 This avoids running environments through preview that are
3394 indicated in `preview-inner-environments'. If you use a prefix
3395 argument COUNT, the corresponding level of outward nested
3396 environments is selected."
3397 (interactive "p")
3398 (save-excursion
3399 (let (currenv)
3400 (dotimes (i (1- count))
3401 (setq currenv (LaTeX-current-environment))
3402 (if (string= currenv "document")
3403 (error "No enclosing outer environment found"))
3404 (LaTeX-find-matching-begin))
3405 (while (member (setq currenv (LaTeX-current-environment))
3406 preview-inner-environments)
3407 (LaTeX-find-matching-begin))
3408 (if (string= currenv "document")
3409 (error "No enclosing outer environment found"))
3410 (preview-region
3411 (save-excursion (LaTeX-find-matching-begin) (point))
3412 (save-excursion (LaTeX-find-matching-end) (point))))))
3413
3414 (defun preview-section ()
3415 "Run preview on LaTeX section." (interactive)
3416 (save-excursion
3417 (LaTeX-mark-section)
3418 (preview-region (region-beginning) (region-end))))
3419
3420
3421 (defun preview-generate-preview (region-p file command)
3422 "Generate a preview.
3423 REGION-P is the region flag, FILE the file (without default
3424 extension and directory), COMMAND is the command to use.
3425
3426 It returns the started process."
3427 (setq TeX-current-process-region-p region-p)
3428 (let* ((geometry (preview-get-geometry))
3429 (commandbuff (current-buffer))
3430 (pr-file (cons
3431 (if TeX-current-process-region-p
3432 'TeX-region-file
3433 'TeX-master-file)
3434 file))
3435 (master (TeX-master-file))
3436 (master-file (expand-file-name master))
3437 (dumped-cons (assoc master-file
3438 preview-dumped-alist))
3439 process)
3440 (unless dumped-cons
3441 (push (setq dumped-cons (cons master-file
3442 (if (eq preview-auto-cache-preamble 'ask)
3443 (y-or-n-p "Cache preamble? ")
3444 preview-auto-cache-preamble)))
3445 preview-dumped-alist))
3446 (when (cdr dumped-cons)
3447 (let* (TeX-current-process-region-p)
3448 (setq process (preview-cache-preamble dumped-cons))
3449 (if process
3450 (setq TeX-sentinel-function
3451 `(lambda (process string)
3452 (funcall ,TeX-sentinel-function process string)
3453 (TeX-inline-preview-internal
3454 ,command ,file
3455 ',pr-file ,commandbuff
3456 ',dumped-cons
3457 ',master
3458 ',geometry
3459 (buffer-string)))))))
3460 (or process
3461 (TeX-inline-preview-internal command file
3462 pr-file commandbuff
3463 dumped-cons master
3464 geometry))))
3465
3466 (defun TeX-inline-preview-internal (command file pr-file
3467 commandbuff dumped-cons master
3468 geometry
3469 &optional str)
3470 "Internal stuff for previewing.
3471 COMMAND and FILE should be explained in `TeX-command-list'.
3472 PR-FILE is the target file name in the form for `preview-gs-file'.
3473 COMMANDBUFF, DUMPED-CONS, MASTER, and GEOMETRY are
3474 internal parameters, STR may be a log to insert into the current log."
3475 (set-buffer commandbuff)
3476 (let*
3477 ((preview-format-name (shell-quote-argument
3478 (preview-dump-file-name
3479 (file-name-nondirectory master))))
3480 (process
3481 (TeX-run-command
3482 "Preview-LaTeX"
3483 (if (consp (cdr dumped-cons))
3484 (preview-do-replacements
3485 command preview-undump-replacements)
3486 command) file)))
3487 (condition-case err
3488 (progn
3489 (when str
3490 (save-excursion
3491 (goto-char (point-min))
3492 (insert str)
3493 (when (= (process-mark process) (point-min))
3494 (set-marker (process-mark process) (point)))))
3495 (preview-set-geometry geometry)
3496 (setq preview-gs-file pr-file)
3497 (setq TeX-sentinel-function 'preview-TeX-inline-sentinel)
3498 (when (featurep 'mule)
3499 (setq preview-coding-system
3500 (or (and (boundp 'TeX-japanese-process-output-coding-system)
3501 TeX-japanese-process-output-coding-system)
3502 (with-current-buffer commandbuff
3503 buffer-file-coding-system)))
3504 (when preview-coding-system
3505 (setq preview-coding-system
3506 (preview-buffer-recode-system
3507 (coding-system-base preview-coding-system))))
3508 (set-process-coding-system
3509 process preview-coding-system))
3510 (TeX-parse-reset)
3511 (setq TeX-parse-function 'TeX-parse-TeX)
3512 (if TeX-process-asynchronous
3513 process
3514 (TeX-synchronous-sentinel "Preview-LaTeX" file process)))
3515 (error (preview-log-error err "Preview" process)
3516 (delete-process process)
3517 (preview-reraise-error process)))))
3518
3519 (defconst preview-version (eval-when-compile
3520 (let ((name "$Name: release_11_87 $")
3521 (rev "$Revision: 1.286 $"))
3522 (or (when (string-match "\\`[$]Name: *release_\\([^ ]+\\) *[$]\\'" name)
3523 (setq name (match-string 1 name))
3524 (while (string-match "_" name)
3525 (setq name (replace-match "." t t name)))
3526 name)
3527 (if (string-match "\\`[$]Revision: *\\([^ ]+\\) *[$]\\'" rev)
3528 (format "CVS-%s" (match-string 1 rev)))
3529 "unknown")))
3530 "Preview version.
3531 If not a regular release, CVS revision of `preview.el'.")
3532
3533 (defconst preview-release-date
3534 (eval-when-compile
3535 (let ((date "$Date: 2011/01/23 18:53:55 $"))
3536 (string-match
3537 "\\`[$]Date: *\\([0-9]+\\)/\\([0-9]+\\)/\\([0-9]+\\)"
3538 date)
3539 (format "%s.%s%s" (match-string 1 date) (match-string 2 date)
3540 (match-string 3 date))))
3541 "Preview release date.
3542 In the form of yyyy.mmdd")
3543
3544 (defun preview-dump-state (buffer)
3545 (condition-case nil
3546 (progn
3547 (unless (local-variable-p 'TeX-command-buffer)
3548 (setq buffer (with-current-buffer buffer (TeX-active-buffer))))
3549 (when (bufferp buffer)
3550 (insert "\nRun buffer contents:\n\n")
3551 (if (< (buffer-size buffer) 5000)
3552 (insert-buffer-substring buffer)
3553 (insert-buffer-substring buffer 1 2500)
3554 (insert "...\n\n[...]\n\n\t...")
3555 (insert-buffer-substring buffer
3556 (- (buffer-size buffer) 2500)
3557 (buffer-size buffer)))
3558 (insert "\n")))
3559 (error nil)))
3560
3561 ;;;###autoload
3562 (defun preview-report-bug () "Report a bug in the preview-latex package."
3563 (interactive)
3564 (let ((reporter-prompt-for-summary-p "Bug report subject: "))
3565 (reporter-submit-bug-report
3566 "bug-auctex@gnu.org"
3567 (if (string-match "^CVS-" preview-version)
3568 (concat "preview-" (substring preview-version 4))
3569 preview-version)
3570 '(AUCTeX-version
3571 LaTeX-command-style
3572 image-types
3573 preview-image-type
3574 preview-image-creators
3575 preview-dvipng-image-type
3576 preview-dvipng-command
3577 preview-pdf2dsc-command
3578 preview-gs-command
3579 preview-gs-options
3580 preview-gs-image-type-alist
3581 preview-fast-conversion
3582 preview-prefer-TeX-bb
3583 preview-dvips-command
3584 preview-fast-dvips-command
3585 preview-scale-function
3586 preview-LaTeX-command
3587 preview-required-option-list
3588 preview-preserve-counters
3589 preview-default-option-list
3590 preview-default-preamble
3591 preview-LaTeX-command-replacements
3592 preview-dump-replacements
3593 preview-undump-replacements
3594 preview-auto-cache-preamble
3595 preview-TeX-style-dir)
3596 `(lambda () (preview-dump-state ,(current-buffer)))
3597 (lambda ()
3598 (insert (format "\nOutput from running `%s -h':\n"
3599 preview-gs-command))
3600 (call-process preview-gs-command nil t nil "-h")
3601 (insert "\n"))
3602 "Remember to cover the basics. Including a minimal LaTeX example
3603 file exhibiting the problem might help."
3604 )))
3605
3606 (eval-when-compile
3607 (when (boundp 'preview-compatibility-macros)
3608 (dolist (elt preview-compatibility-macros)
3609 (if (consp elt)
3610 (fset (car elt) (cdr elt))
3611 (fmakunbound elt)))))
3612
3613 (makunbound 'preview-compatibility-macros)
3614
3615 (provide 'preview)
3616 ;;; preview.el ends here