"Fossies" - the Fresh Open Source Software Archive

Member "auctex-12.3/preview.el.in" (18 Oct 2020, 152759 Bytes) of package /linux/misc/auctex-12.3.tar.gz:


As a special service "Fossies" has tried to format the requested text file into HTML format (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. See also the latest Fossies "Diffs" side-by-side code changes report for "preview.el.in": 12.2_vs_12.3.

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