shivers@centro.soar.cs.cmu.edu (Olin Shivers) (02/15/89)
-----
Someone was asking about printer packages. I enclose the package I use
to print buffers and regions. It has a couple of nice properties:
- It supports print programs besides lpr (like enscript, cz, empress, et al.).
- It's very configurable. You can change the printer, change printer
programs, change options to the programs, all on the fly. There are
reasonable defaults.
- When you print out a buffer, if the buffer is a file buffer, and the
buffer is identical to the file, it just prints the file directly.
This makes page headers come out right: instead of "stdin" or
"emacs buffer foo.c," they come out "/usr/jqr/foo.c".
The basics of the package is:
(print-using-lpr) ; For your .emacs
(print-using-enscript) ; Sets up the options.
M-x print-buffer ; prints the buffer (prints the file, if possible).
M-x print-region ; prints the region
M-x print-file ; print a file
Package follows.
-Olin
------
;;; Modified PRINT-BUFFER
;;; If the buffer belongs to a file, and the file is up to date,
;;; just print the file itself.
;;; Support for different printing programs, other than lpr.
;;; These hacks brought to you by Olin Shivers (Olin.Shivers@CS.CMU.EDU)
;;; 11/11/87
(defvar printer nil
"*If non-nil, specifies the printer to send files to.")
(defvar printer-program nil
"*The program to use to send text to the printer. If nil, lpr is used.
Set by calling PRINT-USING-LPR, PRINT-USING-ENSCRIPT.
If you change this another way, be sure to change also: PRINT-TITLE-HOOK,
PRINT-DEST-HOOK, and PRINT-JOB-HOOK")
(defvar printer-switches '("-p")
"*List of extra switches to pass to printer program.")
;;; Basic user interface:
;;; PRINT-BUFFER PRINT-REGION
;;;============================================================================
;;;
(defun print-buffer ()
"Send buffer contents to the printer. See variables PRINTER, PRINTER-PROGRAM,
and PRINTER-SWITCHES for customisation."
(interactive)
(if (or (buffer-modified-p) (not buffer-file-name))
(print-region-1 (point-min) (point-max))
(print-file buffer-file-name)))
(defun print-region (start end)
"Send region to the printer. See variables PRINTER, PRINTER-PROGRAM,
and PRINTER-SWITCHES for customisation."
(interactive "r")
(print-region-1 start end))
;;; Simple printer-choosers:
;;; PRINT-USING-LPR PRINT-USING-ENSCRIPT
;;;============================================================================
;;;
;;; Feel free to customise the functions yourself. In particular, you
;;; might like to make them set the value of PRINTER-SWITCHES. Also,
;;; note that when you are printing a non-file (buffer or region), and
;;; PRINT-TITLE-HOOK is used to set the header of the printout to
;;; be "foo.c Emacs buffer", there is a small problem. Setting the header
;;; to get the buffer name can cause page numbers to go away. Cz, and enscript
;;; without the -G option have this problem. There's no way to set the
;;; filename part of the header without setting the entire header, thus
;;; blasting the page numbers. Lpr -p doesn't have this problem, because
;;; the -T switch just sets the filename part of the header. But if you
;;; are using cz or enscript without -G, you have to choose for headers:
;;; 1. no buffername: "11/9/87 stdin page 3"
;;; 2. only buffername: " foo.c Emacs buffer "
;;; You get option 2 by specifying a real PRINT-TITLE-HOOK, or by default.
;;; You get option 1 by setting the PRINT-TITLE-HOOK to be a no-op,
;;; i.e. '(LAMBDA (TITL) '()).
;;; There's nothing that can be done to fix this problem, since it's
;;; a problem with the printing programs, not with the emacs end of things.
;;;
;;; For all printing programs, however, you avoid all this mess when you use
;;; the PRINT-BUFFER command to print out saved buffers. In this case,
;;; PRINT-BUFFER cleverly just prints the file itself, and the retarded
;;; print program has a chance to get the headers right.
(defun print-using-enscript ()
"Causes enscript to be the print program. Sets PRINTER-SWITCHES to (\"-G\")"
(interactive)
(setq print-dest-hook nil)
(setq print-title-hook '(lambda (titl) (list (concat "-b" titl))))
(setq print-job-hook nil)
(setq printer-program "enscript")
(setq printer-switches '("-G")))
(defun print-using-lpr ()
"Causes lpr to be the print program. Sets PRINTER-SWITCHES to (\"-p\")"
(interactive)
(setq print-dest-hook nil)
(setq print-title-hook nil)
(setq print-job-hook nil)
(setq printer-program nil)
(setq printer-switches '("-p")))
;Dovers are no more...
;(defun print-using-cz ()
; "Causes cz to be the print program. Clears printer-switches."
; (interactive)
; (setq print-dest-hook '(lambda (dest) (list "-d" dest)))
; (setq print-title-hook '(lambda (titl) (list "-h" titl)))
; (setq print-job-hook '(lambda (jname) (list "-b" jname)))
; (setq printer-program "cz")
; (setq printer-switches nil))
;;; Printer interface functions and hooks:
;;; PRINT-DEST-HOOK PRINT-TITLE-HOOK PRINT-JOB-HOOK
;;;============================================================================
;;;
(defvar print-dest-hook nil
"*If non-nil, a function mapping a printer name to the appropriate
list of arguments for the print program. E.g.,
(lambda (pr) (list \"-P\" pr))")
(defun print-dest (printer)
"Takes the name of a printer, and turns it into a list of arguments
for the print program. Defaults to (\"-P\" printer)."
(if print-dest-hook
(funcall print-dest-hook printer)
(list "-P" printer)))
(defvar print-title-hook nil
"*If non-nil, a function mapping a print title to the appropriate
list of arguments for the print program. E.g.,
(lambda (titl) (list \"-T\" titl))")
(defun print-title (titl)
"Takes the print title for a print job, and turns into a list of arguments
for the print program. Defaults to (\"-T\" titl)."
(if print-title-hook
(funcall print-title-hook titl)
(list "-T" titl)))
(defvar print-job-hook nil
"*If non-nil, a function mapping a job name to the appropriate
list of arguments for the print program. E.g.,
(lambda (jname) (list \"-J\" jname))")
(defun print-job (jname)
"Takes the job name of a print job, and turns it into a list of arguments
for the print program. Defaults to (\"-J\" jname)."
(if print-job-hook
(funcall print-job-hook jname)
(list "-J" jname)))
;;; Programs that really do it:
;;; PRINT-FILE PRINT-REGION-1
;;;============================================================================
;;;
(defun print-file (filename)
(interactive "ffile: ")
; Check to see if the file should be saved before printed.
(let ((buff (get-file-buffer filename)))
(if (and buff
(buffer-modified-p buff)
(y-or-n-p (format "Save buffer %s first? "
(buffer-name buff))))
;; save BUFF.
(let ((old-buffer (current-buffer)))
(set-buffer buff)
(save-buffer)
(set-buffer old-buffer))))
(message "Spooling file...")
(apply 'call-process (or printer-program "lpr")
nil 0 nil
(append (and printer (print-dest printer))
printer-switches
(list filename)))
(message "Spooling file...done"))
(defun print-region-1 (start end)
(save-excursion
(message "Spooling...")
(if (/= tab-width 8)
(let ((oldbuf (current-buffer)))
(set-buffer (get-buffer-create " *spool temp*"))
(widen) (erase-buffer)
(insert-buffer-substring oldbuf)
(call-process-region start end "expand"
t t nil
(format "-%d" tab-width))))
(let ((title (concat (buffer-name) " Emacs buffer")))
(apply 'call-process-region start end
(or printer-program "lpr")
nil nil nil
(append (print-title title)
(and printer (print-dest printer))
(print-job title)
printer-switches)))
(message "Spooling...done")))
--