;;;; latexnfo-tex.el

;;; Latexinfo mode LaTeX and hardcopy printing commands.

;; These commands are for running LaTeX on a region of a Latexinfo file in
;; GNU Emacs, or on the whole buffer, and for printing the resulting
;; DVI file.

;;; Version 2.07    22 October 1991
;;; Robert J. Chassell      
;;; Converted to LaTeXinfo by Mike Clarkson
;;; Please send bug reports to:  mike@apl.ists.ca

;;; Copyright (C) 1989, 1990, 1991 Free Software Foundation, Inc.
;;; Copyleft  (C) 1988, 1989, 1990, 1991 Michael E. Clarkson


;;; This file is part of GNU Emacs.

;; GNU Emacs is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 1, or (at your option)
;; any later version.

;; GNU Emacs is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.

;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING.  If not, write to
;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.


;;; The Latexinfo mode LaTeX related commands are:

; latexinfo-latex-region        to run LaTeX on the current region.
; latexinfo-latex-buffer        to run LaTeX on the current buffer.
; latexinfo-latexindex          to sort unsorted index files.
; latexinfo-latex-print         to print the .dvi file made by LaTeX.
; latexinfo-kill-latex-job      to kill the currently running LaTeX job.
; latexinfo-recenter-latex-output-buffer    to redisplay LaTeX output buffer.
; latexinfo-show-latex-print-queue          to show the print queue.


;;; Keys common both to Latexinfo mode and to LaTeX shell.

;; Defined in `latexinfo-mde.el'
; (defun latexinfo-define-common-keys (keymap)
;   "Define the keys both in Latexinfo mode and in the latexinfo-latex-shell."
;   (define-key keymap "\C-c\C-t\C-k"    'latexinfo-kill-latex-job)
;   (define-key keymap "\C-c\C-t\C-x"    'latexinfo-quit-latex-job)
;   (define-key keymap "\C-c\C-t\C-l"    'latexinfo-recenter-latex-output-buffer)
;   (define-key keymap "\C-c\C-t\C-d"    'latexinfo-delete-from-latex-print-queue)
;   (define-key keymap "\C-c\C-t\C-q"    'latexinfo-show-latex-print-queue)
;   (define-key keymap "\C-c\C-t\C-p"    'latexinfo-latex-print)
;   (define-key keymap "\C-c\C-t\C-i"    'latexinfo-latexindex)
;   (define-key keymap "\C-c\C-t\C-r"    'latexinfo-latex-region)
;   (define-key keymap "\C-c\C-t\C-b"    'latexinfo-latex-buffer))

;; See also latexinfo-latex-start-shell. 
;; The following is executed in the `latexinfo.el' file
;(latexinfo-define-common-keys latexinfo-mode-map)


;;; Variable definitions:

(require 'shell)

(defvar latexinfo-latex-shell-cd-command "cd"
  "Command to give to shell running LaTeX to change directory.")

(defvar latexinfo-latex-command "latex"
  "*Command used by  latexinfo-latex-region  to run LaTeX on a region.")

(defvar latexinfo-latexindex-command "latexindex"
  "*Command used by  latexinfo-latexindex  to sort unsorted index files.")

(defvar latexinfo-latex-dvi-print-command "lpr -d"
  "*Command string used by \\[tex-print] to print a .dvi file.")

(defvar latexinfo-show-latex-queue-command "lpq"
  "*Command string used to show the Latexinfo LaTeX print queue.
Command is used by \\[latexinfo-show-latex-print-queue] and it
should show the queue that \\[latexinfo-latex-print] puts jobs on.")

(defvar latexinfo-delete-from-print-queue-command "lprm"
  "*Command string used to delete a job from the line printer queue.
Command is used by \\[latexinfo-delete-from-latex-print-queue] based on
number provided by a previous \\[latexinfo-show-latex-print-queue]
command.")

(defvar latexinfo-latex-trailer "\\end{document}"
  "String appended after a region sent to LaTeX by latexinfo-latex-region.")

(defvar latexinfo-latex-original-file ""
  "Original name of file on which to run LaTeX.")

(defvar latexinfo-latex-temp-file nil
  "Temporary file name used for text being sent as input to LaTeX.")

(defvar latexinfo-latex-root-temp-file nil
  "Temporary file name used for text being sent as input to LaTeX.")


;;; Latexinfo LaTeX main functions

(defun latexinfo-latex-region (beginning end)
  "Run LaTeX on the current region. 

A temporary file is written in the default directory, and LaTeX is run
in that directory.  The first line of the file is copied to the
temporary file; and if the buffer has a header, it is written to the
temporary file before the region itself.  The buffer's header is all
lines between the strings defined by latexinfo-start-of-header and
latexinfo-end-of-header inclusive.  The header must start in the first 100
lines.  The value of latexinfo-latex-trailer is appended to the temporary file
after the region."
  
  (interactive "r")
  (if (get-buffer "*latexinfo-latex-shell*")
      (quit-process (get-process "latexinfo-latex-shell") t)
    (latexinfo-latex-start-shell))
  
  (setq latexinfo-latex-root-temp-file
        (expand-file-name 
         (make-temp-name
          (prin1-to-string (read (buffer-name))))))
  
  (let ((latexinfo-latex-temp-file (concat latexinfo-latex-root-temp-file ".tex")))
    (save-excursion
      (save-restriction
        (widen)
        (goto-char (point-min))
        (forward-line 100)
        (let ((search-end (point))
              (header-beginning (point-min)) (header-end (point-min)))
          (goto-char (point-min))
          ;; Copy first line, the `\input latexinfo' line, to temp file
          (write-region (point) 
                        (save-excursion (forward-line 1) (point))
                        latexinfo-latex-temp-file nil nil)
          ;; Don't copy first line twice if region includes it.
          (forward-line 1)
          (if (< beginning  (point)) (setq beginning  (point)))
          ;; Initialize the temp file with either the header or nothing
          (if (search-forward latexinfo-start-of-header search-end t)
              (progn
                (beginning-of-line)
                (setq header-beginning (point)) ; Mark beginning of header.
                (if (search-forward latexinfo-end-of-header nil t)
                    (progn (forward-line 1)
                           (setq header-end (point)))   ; Mark end of header.
                  (setq header-beginning (point-min))))) ; Else no header.
          ;; Copy  header  to temp file.
          (write-region
           (min header-beginning beginning )
           header-end
           latexinfo-latex-temp-file t nil)
          ;; Copy  region  to temp file.
          (write-region
           (max beginning  header-end)
           end
           latexinfo-latex-temp-file t nil)
          ;; This is a kludge to insert the latexinfo-latex-trailer into the
          ;; latexinfo-latex-temp-file.  We have to create a special buffer
          ;; in which to insert the latexinfo-latex-trailer first because there is
          ;; no function with which to append a literal string directly
          ;; to a file.
          (let ((local-latex-trailer latexinfo-latex-trailer)
                (temp-buffer (get-buffer-create " latexinfo-trailer-buffer")))
            (set-buffer temp-buffer)
            (erase-buffer)
            ;; make sure trailer isn't hidden by a comment
            (insert-string "\n")
            (if local-latex-trailer (insert local-latex-trailer))
            (write-region (point-min) (point-max) 
                          latexinfo-latex-temp-file t nil)))
        (set-process-sentinel (get-process "latexinfo-latex-shell") 
                              'latexinfo-latex-shell-sentinel)
        (send-string "latexinfo-latex-shell"
                     (concat latexinfo-latex-shell-cd-command " "
                             default-directory "\n"))
        (send-string "latexinfo-latex-shell"
                     (concat latexinfo-latex-command " "
                             latexinfo-latex-temp-file "\n"))
        (latexinfo-recenter-latex-output-buffer 0)))))

(defun latexinfo-latex-buffer (buffer)
  "Run LaTeX on current buffer.
After running LaTeX the first time, you may have to run \\[latexinfo-latexindex]
and then \\[latexinfo-latex-buffer] again."
  (interactive 
   (list
    ;; Sometimes you put point into *latexinfo-latex-shell*; this prompts
    ;; you for the correct file regardless.
    (if (and 
         (string= (buffer-name (current-buffer)) "*latexinfo-latex-shell*")
         latexinfo-latex-root-temp-file)
        (read-string (format "Run LaTeX on: ")
                     latexinfo-latex-original-file)
      (read-string (format "Run LaTeX on: ") (buffer-name (current-buffer))))))
  
  ;; Set to original buffer if in *latexinfo-texj-shell*; otherwise,
  ;; record name of current buffer.
  (if (string= (buffer-name (current-buffer)) "*latexinfo-latex-shell*")
      (set-buffer buffer)
    (setq latexinfo-latex-original-file
           (buffer-name (current-buffer))))

  (if (get-buffer "*latexinfo-latex-shell*")
      (quit-process (get-process "latexinfo-latex-shell") t)
    (latexinfo-latex-start-shell))
  (cond ((null buffer-file-name)
         (error "Buffer not visiting any file!"))
        ((buffer-modified-p)
         (error "Buffer has been modified since last saved!"))
        (t (set-process-sentinel (get-process "latexinfo-latex-shell") 
                                 'latexinfo-latex-shell-sentinel)
           (send-string "latexinfo-latex-shell"
                        (concat latexinfo-latex-shell-cd-command 
                                " "
                                (file-name-directory
                                 (buffer-file-name
                                  (get-buffer buffer)))
                                "\n"))
           (send-string "latexinfo-latex-shell"
                        (concat latexinfo-latex-command " " buffer "\n"))
           
           ;; so the latexinfo-latex-print command works
           (setq latexinfo-latex-root-temp-file
                 (substring buffer 0
                            (or (string-match "\\.tex" buffer)
                                (length buffer))))
           
           (latexinfo-recenter-latex-output-buffer 0))))

(defun latexinfo-latexindex ()
  "Run latexindex on unsorted index files.
The index files are made by \\[latexinfo-latex-region] or \\[latexinfo-latex-buffer].
Runs the shell command defined by latexinfo-latexindex-command."
  (interactive)
  (send-string "latexinfo-latex-shell"
               (concat latexinfo-latexindex-command
                       " " latexinfo-latex-root-temp-file ".??" "\n"))
  (latexinfo-recenter-latex-output-buffer nil))

(defun latexinfo-latex-print ()
  "Print .dvi file made by \\[latexinfo-latex-region] or \\[latexinfo-latex-buffer].
Runs the shell command defined by latexinfo-latex-dvi-print-command."
  (interactive)
  (send-string "latexinfo-latex-shell"
               (concat latexinfo-latex-dvi-print-command
                       " " latexinfo-latex-root-temp-file ".dvi" "\n"))
  (latexinfo-recenter-latex-output-buffer nil))


;;; Latexinfo LaTeX utility functions

(defun latexinfo-latex-start-shell ()
  (save-excursion
    (if (not (fboundp 'latexinfo-mode)) (load "latexnfo-mde"))
    (set-buffer (make-shell "latexinfo-latex-shell" "/bin/sh" nil "-v"))
    (setq latexinfo-latex-shell-map (copy-keymap shell-mode-map))
    (latexinfo-define-common-keys latexinfo-latex-shell-map)
    (use-local-map latexinfo-latex-shell-map)
    (run-hooks 'latexinfo-latex-shell-hook)
    (if (zerop (buffer-size))
        (sleep-for 1))))

(defun latexinfo-quit-latex-job ()
  "Quit currently running LaTeX job, by sending an `x' to it."
  (interactive)
  (if (not (get-process "latexinfo-latex-shell"))
      (error "No LaTeX shell running."))
  (save-excursion
    (set-buffer (get-buffer "*latexinfo-latex-shell*"))
    (goto-char (point-max))
    (insert "x")
    (shell-send-input)))

(defun latexinfo-kill-latex-job ()
  "Kill the currently running LaTeX job."
  (interactive)
  (if (get-process "latexinfo-latex-shell")
        ;; Use `latexinfo-latex-shell-sentinel' to restart
        ;; latexinfo-latex-shell after it is killed.
        (kill-process (get-process "latexinfo-latex-shell"))))

(defun latexinfo-latex-shell-sentinel (process event)
  "Restart latexinfo-latex-shell after it is killed."
  (if (equal event "killed\n")
      (save-excursion
        (set-buffer  "*latexinfo-latex-shell*")
        (insert "\n")
        (latexinfo-latex-start-shell))))

(defun latexinfo-recenter-latex-output-buffer (linenum)
  "Redisplay buffer of LaTeX job output so that most recent output can be seen.
The last line of the buffer is displayed on
line LINE of the window, or centered if LINE is nil."
  (interactive "P")
  (let ((latexinfo-latex-shell (get-buffer "*latexinfo-latex-shell*"))
        (old-buffer (current-buffer)))
    (if (null latexinfo-latex-shell)
        (message "No LaTeX output buffer")
      (pop-to-buffer latexinfo-latex-shell)
      (bury-buffer latexinfo-latex-shell)
      (goto-char (point-max))
      (recenter (if linenum
                    (prefix-numeric-value linenum)
                  (/ (window-height) 2)))
      (pop-to-buffer old-buffer)
      )))

(defun latexinfo-show-latex-print-queue ()
  "Show the print queue that \\[latexinfo-latex-print] put your job on.
Runs the shell command defined by latexinfo-show-latex-queue-command."
  (interactive)
  (if (not (latexinfo-latex-shell-running-p))
      (latexinfo-latex-start-shell))
  (send-string "latexinfo-latex-shell"
               (concat latexinfo-show-latex-queue-command "\n"))
  (latexinfo-recenter-latex-output-buffer nil))

(defun latexinfo-delete-from-latex-print-queue (job-number)
  "Delete job from the line printer spooling queue.
You are prompted for the job number (shown by a previous
\\[latexinfo-show-latex-print-queue] command."
  (interactive "nPrinter job number for deletion: ")
  (if (latexinfo-latex-shell-running-p)
      (latexinfo-kill-latex-job)
    (latexinfo-latex-start-shell))
  (send-string "latexinfo-latex-shell"
               (concat 
                latexinfo-delete-from-print-queue-command
                " "
                job-number"\n"))
  (latexinfo-recenter-latex-output-buffer nil))

(defun latexinfo-latex-shell-running-p ()
  (and (get-process "latexinfo-latex-shell")
       (eq (process-status (get-process "latexinfo-latex-shell")) 'run)))


;;; Place `provide' at end of file.
(provide 'latexnfo-tex)
;;;;;;;;;;;;;;;; end latexnfo-tex.el ;;;;;;;;;;;;;;;;
