1 ;;; tinylpr.el --- Easy Emacs lpr command handling, pop-up, completions
3 ;; This file is not part of Emacs
7 ;; Copyright (C) 1996-2007 Jari Aalto
8 ;; Keywords: extensions
10 ;; Maintainer: Jari Aalto
12 ;; To get information on this program, call M-x tinylpr-version.
13 ;; Look at the code with folding.el
17 ;; This program is free software; you can redistribute it and/or modify it
18 ;; under the terms of the GNU General Public License as published by the Free
19 ;; Software Foundation; either version 2 of the License, or (at your option)
22 ;; This program is distributed in the hope that it will be useful, but
23 ;; WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
24 ;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
27 ;; You should have received a copy of the GNU General Public License
28 ;; along with program; see the file COPYING. If not, write to the
29 ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
30 ;; Boston, MA 02110-1301, USA.
32 ;; Visit <http://www.gnu.org/copyleft/gpl.html> for more information
39 ;; ....................................................... &t-install ...
40 ;; Put this file on your Emacs-Lisp load path, add following into your
41 ;; ~/.emacs startup file
45 ;; Suggested key binding. The commands are available via echo-menu, but
46 ;; you can bind each command individually too. The echo menu:
48 ;; (ti::use-prefix-key "\C-z") ;; Free C-z for us.
49 ;; (global-set-key "\C-zp" (ti::definteractive (ti::menu-menu 'tinylpr-:menu)))
51 ;; Notice, that loading this file changes your `lpr-command' immediately
52 ;; to "sh". This is essential and if you want to use this package,
53 ;; leave it there or choose some compatible shell that accepts "-c"
56 ;; CHANGE THE VARIABLES !
58 ;; You must copy the user variables and put your own definitions
59 ;; there. The ones that ship with this module are only examples
61 ;; If you have any questions, use this function
63 ;; M-x tinylpr-submit-feedback
68 ;; ..................................................... &t-commentary ...
72 ;; Overview of features
74 ;; o Managing printers or print styles easily
75 ;; o Queue information
76 ;; o Has ready X-popup example to select print styles etc.
77 ;; o Echo menu provided to select printing advice:
79 ;; TinyLpr: 01c2 r)egion b)uffer l)ine numbers d)printer
82 ;; o Ps print support in another `P' echo-menu:
84 ;; TinyLpr: 01c2(ps) rR)egion bB)uffer sS)Spool d)espool
88 ;; Unix environment offers numerous utilizes to format printing
89 ;; the user wants, not to mention the numerous printers that can be set.
90 ;; you may find these command in your system:
92 ;; mmpage multi-page 1-8, like sunOS enscript
96 ;; squeeze.awk my own empty line squeezer. Ever run CPP on C/C++ ?
97 ;; groff I make some nroff files...
100 ;; col -bx remove ctrl codes from man pages
101 ;; pps pretty printer for PostScript -- jau@tut.fi
103 ;; fold fold long lines for finite width output device
104 ;; adjust for filling, centering, ..justifying
106 ;; If you want to print the file in some other format, i.e. combining
107 ;; some of the commands above, you have change `lpr-switches'
108 ;; every time. This is tedious. Instead this package offers a pop up menu
109 ;; where you can select lpstatus, select print command, cancel print
114 ;; (defun my-x-menu (event)
115 ;; "Pop up an X window of user defined commands. "
118 ;; (replace-regexp-in-string ;remove directory name
121 ;; (or (my-print-status) "")))
131 ;; ;; This first one is header, not selection
132 ;; (cons (concat ":: " pstat) 'ignore)
133 ;; ;; these are selections
134 ;; '("* Print region" . print-region)
135 ;; '("* Print buffer" . print-buffer)
136 ;; '("Destination" . tinylpr-select-printer)
137 ;; '("Print style" . tinylpr-print-style-select)
138 ;; '("Queue status" . tinylpr-queue)))))
140 ;; (item ;direct command
141 ;; (call-interactively item)))))
156 (autoload 'ps-print-buffer "ps-print" nil t)
157 (autoload 'ps-print-buffer-with-faces "ps-print" nil t)
158 (autoload 'ps-print-region "ps-print" nil t)
159 (autoload 'ps-print-region-with-faces "ps-print" nil t)
160 (autoload 'ps-spool-buffer "ps-print" nil t)
161 (autoload 'ps-spool-buffer-with-faces "ps-print" nil t)
162 (autoload 'ps-spool-region "ps-print" nil t)
163 (autoload 'ps-spool-region-with-faces "ps-print" nil t)
165 (defvar ps-lpr-switches) ;to quiet ByteCompiler
166 (defvar lpr-switches)
167 (defvar lpr-command))
169 (eval-when-compile (ti::package-use-dynamic-compilation))
171 (ti::package-defgroup-tiny TinyLpr tinylpr-: extensions
172 "Easy Emacs lpr command handling, popup, completions
173 o Managing printers or print styles easily
175 o Has ready X-popup example to select print styles etc.")
178 ;;{{{ setup: variables
180 ;;; ......................................................... &v-hooks ...
182 (defcustom tinylpr-:load-hook nil
183 "Hook run when file is loaded."
187 ;;; .......................................................... &v-vars ...
188 ;;; *** important ***
190 ;;; These are just examples. Copy the variables into your ~/.emacs
191 ;;; and make changes to reflect your system.
195 (defcustom tinylpr-:set-ps-lpr-switches t
196 "If non-nil, set also ps-lpr-switches from ps-print.el when
201 (defcustom tinylpr-:queue-cmd
202 (or (executable-find "lpstat")
203 (let ((function (if (ti::win32-p)
207 "TinyLpr: can't use default [lpstat] for tinylpr-:queue-cmd")))
208 "*Shell Command to return queue status"
209 :type '(string :tag "Shell Command")
213 (defcustom tinylpr-:printer-list
217 (if (ti::win32-p) "lpt1:")
218 (if (ti::win32-p) "prn:")))
219 "*List of available printers, like '(\"PRINTER1\" \"PRINTER2\")."
220 :type '(repeat (string :tag "printer"))
223 (defcustom tinylpr-:print-style-list
224 (let* ((mp (executable-find "mpage")) ;HP-UX multipage
225 (lp (executable-find "lp"))
226 (lpr (executable-find "lpr"))
227 (nl (executable-find "nl"))
228 (ens (executable-find "enscript"))
229 (gs (executable-find "gs"))
230 (gs32 (executable-find "gs386"))) ;; Ghostscript in Win32
232 nil ;Remove empty entries
236 ;; Select the first string so, that it's easy to complete.
237 "lp, straight lp" (concat lp " -d#")))
240 "lpr straight" (concat lpr " -d#")))
243 "nl, numbered lp" "nl | lp -d#"))
246 "2 mpage" (concat mp " -A -2 -P#")))
249 "4 mpage" (concat mp " -A -4 -P#")))
252 "8 mpage" (concat mp " -A -8 -P#")))
255 "2l mpage landscape" (concat mp " -A -l -2 -P#")))
258 "enscript" (concat ens " -d#")))
261 "et enscript TOC" (concat ens " --toc -d#")))
264 "2l enscript landscape" (concat ens " -r -2 -d#")))
268 (concat gs "-q -dNOPAUSE -sDEVICE=SomeDevice"
269 "-r600 -sPAPERSIZE=a4 "
272 "*Available print styles.
273 The # char tells where to install printer in command.
277 '((COMPLETION-STRING PRINTER-COMMAND-STRING) ..)
281 '((\"2 pages\" \"mpage -A -2 -P#\"))"
283 (list (string :tag "Completion name")
284 (string :tag "Shell Command.")))
288 ) ;; eval-and-compile
290 ;;; ....................................................... &v-private ...
292 (defvar tinylpr-:current-printer (car-safe tinylpr-:printer-list)
293 "Private. Current printer.")
295 (defvar tinylpr-:current-print-style (car-safe (car-safe tinylpr-:print-style-list))
296 "Private. Current print style.")
298 (defvar tinylpr-:printer-list-history nil
299 "Private. History list for `tinylpr-:printer-list'.")
301 (defvar tinylpr-:print-style-history nil
302 "Private. History list for tinylpr-print-style-completions.")
304 ;;; ....................................................... &v-version ...
307 (ti::macrof-version-bug-report
311 "$Id: tinylpr.el,v 2.42 2007/05/01 17:20:49 jaalto Exp $"
312 '(tinylpr-:version-id
314 tinylpr-:set-ps-lpr-switches
316 tinylpr-:printer-list
317 tinylpr-:print-style-list
318 tinylpr-:current-printer
319 tinylpr-:current-print-style
320 tinylpr-:printer-list-history
321 tinylpr-:print-style-history)))
323 (defvar tinylpr-:menu
325 "TinyLpr: %s r)egion b)uffer l)ine numbers d)printer Q)ueue s)tyle >P"
326 tinylpr-:current-printer)
327 ((?d . (t (call-interactively 'tinylpr-select-printer)))
328 (?Q . ( (call-interactively 'tinylpr-queue)))
329 (?s . (t (call-interactively 'tinylpr-print-style-select)))
330 (?r . ( (call-interactively 'print-region)))
331 (?b . ( (call-interactively 'print-buffer)))
332 (?l . ( (call-interactively 'tinylpr-print-with-line-numbers)))
333 (?P . tinylpr-:ps-print-menu)))
334 "*Echo menu to access printer commands. Select `P' for ps-print.el commands.")
336 (defvar tinylpr-:ps-print-menu
338 TinyLpr: %s(ps) rR)egion bB)uffer sS)Spool d)espool "
339 tinylpr-:current-printer)
340 ((?r . ( (call-interactively 'ps-print-region)))
341 (?R . ( (call-interactively 'ps-print-region-with-faces)))
342 (?b . ( (call-interactively 'ps-print-buffer)))
343 (?B . ( (call-interactively 'ps-print-buffer-with-faces)))
344 (?s . ( (call-interactively 'ps-spool-buffer)))
345 (?S . ( (call-interactively 'ps-spool-buffer-with-faces)))
346 (?w . ( (call-interactively 'ps-spool-region)))
347 (?W . ( (call-interactively 'ps-spool-region-with-faces)))
348 (?d . ( (call-interactively 'ps-despool)))))
349 "*Echo menu to access ps-print commands.
352 R Print region with faces.
354 B rint buffer with faces.
357 S Spool buffer with faces.
359 W Spool region with faces.
361 d Despool (send spooled items)")
365 ;;; ########################################################### &Funcs ###
369 ;;; ----------------------------------------------------------------------
371 (defun tinylpr-install-lpr-command ()
372 "Set correct shell for `lpr-command'."
375 (unless (string-match "sh\\|bash\\|cmd.exe\\|command.exe"
377 ;; NT Cygnus users get served too by putting sh,bash test first.
379 ((setq sh (or (executable-find "sh")
380 (executable-find "bash")))
381 (setq lpr-command sh))
383 (setq sh (or (executable-find "cmd")
384 (executable-find "command"))))
385 (setq lpr-command sh))
388 TinyLpr: sh, bash or cmd.exe not available. Can't set lpr-command." ))))))
390 ;;; ----------------------------------------------------------------------
392 (defun tinylpr-set-command (template printer)
393 "Substitutes possible # n TEMPLATE with PRINTER name in."
394 (if (string-match "\\(#\\)" template)
395 (setq template (ti::replace-match 1 printer template)))
397 ;; We know the lpr-command is "sh", so just put the "-c" as
401 ((string-match "\\(sh\\|bash\\)$" lpr-command)
402 (setq lpr-switches (list "-c" template)))
403 ((string-match "\\(command\\|cmd\\)\\.exe$" lpr-command) ;Win32
404 (setq lpr-switches (list "/c" template)))))
406 ;;; ----------------------------------------------------------------------
408 (defun tinylpr-print-with-line-numbers ()
409 "Adds line numbers to buffer and prints it. After printing,
410 removes line numbers."
412 (let* (buffer-read-only
415 (with-buffer-modified
418 ;; Set dynamic format according to biggest line number
419 (setq len (ti::digit-length (ti::current-line-number))
420 fmt (concat "%0" len "d: %s"))
423 (ti::buffer-insert-line-numbers (point-min) (point-max) 1 1 fmt)
425 (ti::buffer-remove-line-numbers
430 ;;; ----------------------------------------------------------------------
432 (defun tinylpr-print-style-completions ()
433 "Build up the completion array."
434 (let* ((list tinylpr-:print-style-list)
441 (setq completions (cons (cons (car x) i) completions))))
445 ;;; ----------------------------------------------------------------------
447 (defun tinylpr-setting-status ()
448 "Return current settings."
450 (let* ((stat (nth 1 lpr-switches)))
455 ;;; ----------------------------------------------------------------------
457 (defun tinylpr-queue ()
458 "Return queue status."
460 (let* ((cmd tinylpr-:queue-cmd)
461 (buffer (ti::temp-buffer "*tmp*" 'clear)))
462 (display-buffer buffer)
463 (shell-command cmd buffer)))
465 ;;; ----------------------------------------------------------------------
467 (defun tinylpr-select-printer (printer)
468 "Select PRINTER printer."
472 (concat "Printer [" tinylpr-:current-printer "]: ")
473 (ti::list-to-assoc-menu tinylpr-:printer-list)
476 'tinylpr-:printer-list-history)))
477 (when (not (ti::nil-p printer))
478 (setq tinylpr-:current-printer printer)
479 (if tinylpr-:set-ps-lpr-switches
480 (setq ps-lpr-switches (list (concat "-P" printer))))
481 (tinylpr-print-style-select tinylpr-:current-print-style)))
483 ;;; ----------------------------------------------------------------------
485 (defun tinylpr-print-style-select (arg)
486 "Select print output style with ARG."
490 (format "Print style [%s: %s ]: "
491 (or tinylpr-:current-print-style "<style unknown>")
492 (tinylpr-setting-status))
493 (tinylpr-print-style-completions)
497 (let* ((printer (or tinylpr-:current-printer ""))
500 ;; Try to find the style in assoc array
501 (if (not (and arg (setq elt (assoc arg tinylpr-:print-style-list))))
502 (message "No such style")
503 ;; replace # with printer name
504 (setq tinylpr-:current-print-style arg)
505 (setq args (nth 1 elt))
506 (tinylpr-set-command args printer)
507 (message "Print <%s> on %s" arg (tinylpr-setting-status)))))
512 ;;; .................................................... &auto-install ...
514 ;; Install package, reset lpr variables
516 (tinylpr-install-lpr-command)
518 (let* ((template (nth 1 (car tinylpr-:print-style-list))))
519 (if (and template tinylpr-:current-printer)
520 (tinylpr-set-command template tinylpr-:current-printer)
522 TinyLpr: ** Auto setup failure, please define tinylpr-:print-style-list and
523 TinyLpr: ** tinylpr-:current-printer")))
528 (run-hooks 'tinylpr-:load-hook)
530 ;;; tinylpr.el ends here