aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lisp/doc-view.el230
1 files changed, 123 insertions, 107 deletions
diff --git a/lisp/doc-view.el b/lisp/doc-view.el
index b6d8235a02b..d35bf04b3d8 100644
--- a/lisp/doc-view.el
+++ b/lisp/doc-view.el
@@ -102,7 +102,6 @@
102 102
103(require 'dired) 103(require 'dired)
104(require 'image-mode) 104(require 'image-mode)
105(eval-when-compile (require 'cl))
106 105
107;;;; Customization Options 106;;;; Customization Options
108 107
@@ -202,13 +201,14 @@ has finished."
202(defvar doc-view-current-info nil 201(defvar doc-view-current-info nil
203 "Only used internally.") 202 "Only used internally.")
204 203
205(defvar doc-view-current-display nil 204(defvar doc-view-previous-major-mode nil
206 "Only used internally.") 205 "Only used internally.")
207 206
208;;;; DocView Keymaps 207;;;; DocView Keymaps
209 208
210(defvar doc-view-mode-map 209(defvar doc-view-mode-map
211 (let ((map (make-sparse-keymap))) 210 (let ((map (make-sparse-keymap)))
211 (suppress-keymap map)
212 ;; Navigation in the document 212 ;; Navigation in the document
213 (define-key map (kbd "n") 'doc-view-next-page) 213 (define-key map (kbd "n") 'doc-view-next-page)
214 (define-key map (kbd "p") 'doc-view-previous-page) 214 (define-key map (kbd "p") 'doc-view-previous-page)
@@ -224,6 +224,7 @@ has finished."
224 ;; Killing/burying the buffer (and the process) 224 ;; Killing/burying the buffer (and the process)
225 (define-key map (kbd "q") 'bury-buffer) 225 (define-key map (kbd "q") 'bury-buffer)
226 (define-key map (kbd "k") 'doc-view-kill-proc-and-buffer) 226 (define-key map (kbd "k") 'doc-view-kill-proc-and-buffer)
227 (define-key map (kbd "K") 'doc-view-kill-proc)
227 ;; Slicing the image 228 ;; Slicing the image
228 (define-key map (kbd "s s") 'doc-view-set-slice) 229 (define-key map (kbd "s s") 'doc-view-set-slice)
229 (define-key map (kbd "s m") 'doc-view-set-slice-using-mouse) 230 (define-key map (kbd "s m") 'doc-view-set-slice-using-mouse)
@@ -242,24 +243,17 @@ has finished."
242 (define-key map (kbd "C-t") 'doc-view-show-tooltip) 243 (define-key map (kbd "C-t") 'doc-view-show-tooltip)
243 ;; Toggle between text and image display or editing 244 ;; Toggle between text and image display or editing
244 (define-key map (kbd "C-c C-c") 'doc-view-toggle-display) 245 (define-key map (kbd "C-c C-c") 'doc-view-toggle-display)
245 (define-key map (kbd "C-c C-e") 'doc-view-edit-doc)
246 ;; Reconvert the current document 246 ;; Reconvert the current document
247 (define-key map (kbd "g") 'doc-view-reconvert-doc) 247 (define-key map (kbd "g") 'doc-view-reconvert-doc)
248 (suppress-keymap map)
249 map) 248 map)
250 "Keymap used by `doc-view-mode' when displaying a doc as a set of images.") 249 "Keymap used by `doc-view-mode' when displaying a doc as a set of images.")
251 250
252(defvar doc-view-mode-text-map 251(defvar doc-view-minor-mode-map
253 (let ((map (make-sparse-keymap))) 252 (let ((map (make-sparse-keymap)))
254 ;; Toggle between text and image display or editing 253 ;; Toggle between text and image display or editing
255 (define-key map (kbd "C-c C-c") 'doc-view-toggle-display) 254 (define-key map (kbd "C-c C-c") 'doc-view-toggle-display)
256 (define-key map (kbd "C-c C-e") 'doc-view-edit-doc)
257 ;; Killing/burying the buffer (and the process)
258 (define-key map (kbd "q") 'bury-buffer)
259 (define-key map (kbd "k") 'doc-view-kill-proc-and-buffer)
260 (define-key map (kbd "C-x k") 'doc-view-kill-proc-and-buffer)
261 map) 255 map)
262 "Keymap used by `doc-view-mode' when displaying a document as text.") 256 "Keymap used by `doc-minor-view-mode'.")
263 257
264;;;; Navigation Commands 258;;;; Navigation Commands
265 259
@@ -339,11 +333,14 @@ has finished."
339 (error (doc-view-previous-page) 333 (error (doc-view-previous-page)
340 (goto-char (point-max))))) 334 (goto-char (point-max)))))
341 335
336;;;; Utility Functions
337
342(defun doc-view-kill-proc () 338(defun doc-view-kill-proc ()
343 "Kill the current converter process." 339 "Kill the current converter process."
344 (interactive) 340 (interactive)
345 (when doc-view-current-converter-process 341 (when doc-view-current-converter-process
346 (kill-process doc-view-current-converter-process)) 342 (kill-process doc-view-current-converter-process)
343 (setq doc-view-current-converter-process nil))
347 (when doc-view-current-timer 344 (when doc-view-current-timer
348 (cancel-timer doc-view-current-timer) 345 (cancel-timer doc-view-current-timer)
349 (setq doc-view-current-timer nil)) 346 (setq doc-view-current-timer nil))
@@ -356,6 +353,28 @@ has finished."
356 (when (eq major-mode 'doc-view-mode) 353 (when (eq major-mode 'doc-view-mode)
357 (kill-buffer (current-buffer)))) 354 (kill-buffer (current-buffer))))
358 355
356(defun doc-view-current-cache-dir ()
357 "Return the directory where the png files of the current doc should be saved.
358It's a subdirectory of `doc-view-cache-directory'."
359 (if doc-view-current-cache-dir
360 doc-view-current-cache-dir
361 (setq doc-view-current-cache-dir
362 (file-name-as-directory
363 (concat (file-name-as-directory doc-view-cache-directory)
364 (let ((doc doc-view-current-doc))
365 (concat (file-name-nondirectory doc)
366 "-"
367 (with-temp-buffer
368 (insert-file-contents-literally doc)
369 (md5 (current-buffer))))))))))
370
371(defun doc-view-remove-if (predicate list)
372 "Return LIST with all items removed that satisfy PREDICATE."
373 (let (new-list)
374 (dolist (item list (nreverse new-list))
375 (when (not (funcall predicate item))
376 (setq new-list (cons item new-list))))))
377
359;;;; Conversion Functions 378;;;; Conversion Functions
360 379
361(defun doc-view-reconvert-doc (&rest args) 380(defun doc-view-reconvert-doc (&rest args)
@@ -368,21 +387,7 @@ Should be invoked when the cached images aren't up-to-date."
368 ;; Clear the old cached files 387 ;; Clear the old cached files
369 (when (file-exists-p (doc-view-current-cache-dir)) 388 (when (file-exists-p (doc-view-current-cache-dir))
370 (dired-delete-file (doc-view-current-cache-dir) 'always)) 389 (dired-delete-file (doc-view-current-cache-dir) 'always))
371 (doc-view-kill-proc-and-buffer) 390 (doc-view-mode)))
372 (find-file doc)))
373
374(defun doc-view-current-cache-dir ()
375 "Return the directory where the png files of the current doc should be saved.
376It's a subdirectory of `doc-view-cache-directory'."
377 (if doc-view-current-cache-dir
378 doc-view-current-cache-dir
379 (setq doc-view-current-cache-dir
380 (file-name-as-directory
381 (concat (file-name-as-directory doc-view-cache-directory)
382 (let ((doc doc-view-current-doc))
383 (with-temp-buffer
384 (insert-file-contents-literally doc)
385 (md5 (current-buffer)))))))))
386 391
387(defun doc-view-dvi->pdf-sentinel (proc event) 392(defun doc-view-dvi->pdf-sentinel (proc event)
388 "If DVI->PDF conversion was successful, convert the PDF to PNG now." 393 "If DVI->PDF conversion was successful, convert the PDF to PNG now."
@@ -439,7 +444,7 @@ It's a subdirectory of `doc-view-cache-directory'."
439 (when doc-view-conversion-refresh-interval 444 (when doc-view-conversion-refresh-interval
440 (setq doc-view-current-timer 445 (setq doc-view-current-timer
441 (run-at-time "1 secs" doc-view-conversion-refresh-interval 446 (run-at-time "1 secs" doc-view-conversion-refresh-interval
442 'doc-view-display-maybe 447 'doc-view-display
443 doc-view-current-doc)))) 448 doc-view-current-doc))))
444 449
445(defun doc-view-pdf->txt-sentinel (proc event) 450(defun doc-view-pdf->txt-sentinel (proc event)
@@ -482,10 +487,11 @@ It's a subdirectory of `doc-view-cache-directory'."
482 (setq doc-view-current-converter-process 487 (setq doc-view-current-converter-process
483 (start-process "ps->pdf" doc-view-conversion-buffer 488 (start-process "ps->pdf" doc-view-conversion-buffer
484 doc-view-ps2pdf-program 489 doc-view-ps2pdf-program
485 ps pdf
486 ;; Avoid security problems when rendering files from 490 ;; Avoid security problems when rendering files from
487 ;; untrusted sources. 491 ;; untrusted sources.
488 "-dSAFER") 492 "-dSAFER"
493 ;; in-file and out-file
494 ps pdf)
489 mode-line-process (list (format ":%s" doc-view-current-converter-process))) 495 mode-line-process (list (format ":%s" doc-view-current-converter-process)))
490 (set-process-sentinel doc-view-current-converter-process 496 (set-process-sentinel doc-view-current-converter-process
491 'doc-view-ps->pdf-sentinel) 497 'doc-view-ps->pdf-sentinel)
@@ -499,7 +505,7 @@ Those files are saved in the directory given by the function
499 (clear-image-cache) 505 (clear-image-cache)
500 (let ((png-file (concat (doc-view-current-cache-dir) 506 (let ((png-file (concat (doc-view-current-cache-dir)
501 "page-%d.png"))) 507 "page-%d.png")))
502 (make-directory doc-view-current-cache-dir t) 508 (make-directory (doc-view-current-cache-dir) t)
503 (if (not (string= (file-name-extension doc-view-current-doc) "dvi")) 509 (if (not (string= (file-name-extension doc-view-current-doc) "dvi"))
504 ;; Convert to PNG images. 510 ;; Convert to PNG images.
505 (doc-view-pdf/ps->png doc-view-current-doc png-file) 511 (doc-view-pdf/ps->png doc-view-current-doc png-file)
@@ -576,11 +582,6 @@ Predicate for sorting `doc-view-current-files'."
576 nil 582 nil
577 (string< a b)))) 583 (string< a b))))
578 584
579(defun doc-view-display-maybe (doc)
580 "Call `doc-view-display' iff we're in the image display."
581 (when (eq doc-view-current-display 'image)
582 (doc-view-display doc)))
583
584(defun doc-view-display (doc) 585(defun doc-view-display (doc)
585 "Start viewing the document DOC." 586 "Start viewing the document DOC."
586 (set-buffer (get-file-buffer doc)) 587 (set-buffer (get-file-buffer doc))
@@ -603,58 +604,39 @@ page hasn't finished yet or
603For now these keys are useful: 604For now these keys are useful:
604 605
605`q' : Bury this buffer. Conversion will go on in background. 606`q' : Bury this buffer. Conversion will go on in background.
606`k' : Kill the conversion process and this buffer.\n") 607`k' : Kill the conversion process and this buffer.
608`K' : Kill the conversion process.\n")
607 (set-buffer-modified-p nil)) 609 (set-buffer-modified-p nil))
608 610
609(defun doc-view-show-tooltip () 611(defun doc-view-show-tooltip ()
610 (interactive) 612 (interactive)
611 (tooltip-show doc-view-current-info)) 613 (tooltip-show doc-view-current-info))
612 614
613;;;;; Toggle between text and image display 615;;;;; Toggle between editing and viewing
614 616
615(defun doc-view-toggle-display () 617(defun doc-view-toggle-display ()
616 "Start or stop displaying a document file as a set of images. 618 "Toggle between editing a document as text or viewing it."
617This command toggles between showing the text of the document
618file and showing the document as a set of images."
619 (interactive) 619 (interactive)
620 (if (get-text-property (point-min) 'display) 620 (if (eq major-mode 'doc-view-mode)
621 ;; Switch to text display 621 ;; Switch to editing mode
622 (let ((inhibit-read-only t)) 622 (progn
623 (doc-view-kill-proc)
624 (setq buffer-read-only nil)
623 (erase-buffer) 625 (erase-buffer)
624 (insert-file-contents doc-view-current-doc) 626 (insert-file-contents buffer-file-name)
625 (use-local-map doc-view-mode-text-map) 627 ;; Switch to the previously used major mode or fall back to fundamental
626 (setq mode-name "DocView[text]" 628 ;; mode.
627 doc-view-current-display 'text) 629 (if doc-view-previous-major-mode
628 (if (called-interactively-p) 630 (funcall doc-view-previous-major-mode)
629 (message "Repeat this command to go back to displaying the file as images"))) 631 (fundamental-mode))
630 ;; Switch to image display 632 (doc-view-minor-mode 1)
631 (let ((inhibit-read-only t)) 633 (set-buffer-modified-p nil))
632 (erase-buffer) 634 ;; Switch to doc-view-mode
633 (doc-view-buffer-message) 635 (when (and (buffer-modified-p)
634 (setq doc-view-current-page (or doc-view-current-page 1)) 636 (y-or-n-p "The buffer has been modified. Save the changes? "))
635 (if (file-exists-p (doc-view-current-cache-dir)) 637 (save-buffer))
636 (progn 638 (erase-buffer)
637 (message "DocView: using cached files!") 639 (doc-view-mode)))
638 (doc-view-display doc-view-current-doc))
639 (doc-view-convert-current-doc))
640 (use-local-map doc-view-mode-map)
641 (setq mode-name (format "DocView")
642 doc-view-current-display 'image)
643 (if (called-interactively-p)
644 (message "Repeat this command to go back to displaying the file as text"))))
645 (set-buffer-modified-p nil))
646
647;;;;; Leave doc-view-mode and open the file for edit
648
649(defun doc-view-edit-doc ()
650 "Leave `doc-view-mode' and open the current doc with an appropriate editing mode."
651 (interactive)
652 (let ((filename doc-view-current-doc)
653 (auto-mode-alist (append '(("\\.[eE]?[pP][sS]\\'" . ps-mode)
654 ("\\.\\(pdf\\|PDF\\|dvi\\|DVI\\)$" . fundamental-mode))
655 auto-mode-alist)))
656 (kill-buffer (current-buffer))
657 (find-file filename)))
658 640
659;;;; Searching 641;;;; Searching
660 642
@@ -742,8 +724,9 @@ conversion finished."
742(defun doc-view-search-next-match (arg) 724(defun doc-view-search-next-match (arg)
743 "Go to the ARGth next matching page." 725 "Go to the ARGth next matching page."
744 (interactive "p") 726 (interactive "p")
745 (let* ((next-pages (remove-if (lambda (i) (<= (car i) doc-view-current-page)) 727 (let* ((next-pages (doc-view-remove-if
746 doc-view-current-search-matches)) 728 (lambda (i) (<= (car i) doc-view-current-page))
729 doc-view-current-search-matches))
747 (page (car (nth (1- arg) next-pages)))) 730 (page (car (nth (1- arg) next-pages))))
748 (if page 731 (if page
749 (doc-view-goto-page page) 732 (doc-view-goto-page page)
@@ -755,8 +738,9 @@ conversion finished."
755(defun doc-view-search-previous-match (arg) 738(defun doc-view-search-previous-match (arg)
756 "Go to the ARGth previous matching page." 739 "Go to the ARGth previous matching page."
757 (interactive "p") 740 (interactive "p")
758 (let* ((prev-pages (remove-if (lambda (i) (>= (car i) doc-view-current-page)) 741 (let* ((prev-pages (doc-view-remove-if
759 doc-view-current-search-matches)) 742 (lambda (i) (>= (car i) doc-view-current-page))
743 doc-view-current-search-matches))
760 (page (car (nth (1- arg) (nreverse prev-pages))))) 744 (page (car (nth (1- arg) (nreverse prev-pages)))))
761 (if page 745 (if page
762 (doc-view-goto-page page) 746 (doc-view-goto-page page)
@@ -770,37 +754,69 @@ conversion finished."
770(put 'doc-view-mode 'mode-class 'special) 754(put 'doc-view-mode 'mode-class 'special)
771 755
772;;;###autoload 756;;;###autoload
773(define-derived-mode doc-view-mode nil "DocView" 757(defun doc-view-mode ()
774 "Major mode in DocView buffers. 758 "Major mode in DocView buffers.
775You can use \\<doc-view-mode-map>\\[doc-view-toggle-display] to 759You can use \\<doc-view-mode-map>\\[doc-view-toggle-display] to
776toggle between display as a set of images and display as text." 760toggle between displaying the document or editing it as text."
777 :group 'doc-view 761 (interactive)
778 (make-local-variable 'doc-view-current-files) 762 (let* ((prev-major-mode (if (eq major-mode 'doc-view-mode)
779 (make-local-variable 'doc-view-current-doc) 763 doc-view-previous-major-mode
780 (make-local-variable 'doc-view-current-image) 764 major-mode)))
781 (make-local-variable 'doc-view-current-page) 765 (kill-all-local-variables)
782 (make-local-variable 'doc-view-current-converter-process) 766 (make-local-variable 'doc-view-current-files)
783 (make-local-variable 'doc-view-current-timer) 767 (make-local-variable 'doc-view-current-image)
784 (make-local-variable 'doc-view-current-slice) 768 (make-local-variable 'doc-view-current-page)
785 (make-local-variable 'doc-view-current-cache-dir) 769 (make-local-variable 'doc-view-current-converter-process)
786 (make-local-variable 'doc-view-current-info) 770 (make-local-variable 'doc-view-current-timer)
787 (make-local-variable 'doc-view-current-search-matches) 771 (make-local-variable 'doc-view-current-slice)
788 (setq doc-view-current-doc (buffer-file-name)) 772 (make-local-variable 'doc-view-current-cache-dir)
773 (make-local-variable 'doc-view-current-info)
774 (make-local-variable 'doc-view-current-search-matches)
775 (set (make-local-variable 'doc-view-current-doc) buffer-file-name)
776 (set (make-local-variable 'doc-view-previous-major-mode) prev-major-mode))
789 (insert-file-contents doc-view-current-doc) 777 (insert-file-contents doc-view-current-doc)
790 (use-local-map doc-view-mode-text-map) 778 (use-local-map doc-view-mode-map)
791 (setq mode-name "DocView[text]" 779 (setq mode-name "DocView"
792 doc-view-current-display 'text
793 buffer-read-only t 780 buffer-read-only t
794 revert-buffer-function 'doc-view-reconvert-doc) 781 revert-buffer-function 'doc-view-reconvert-doc
782 major-mode 'doc-view-mode)
795 ;; Switch to image display if possible 783 ;; Switch to image display if possible
796 (if (and (display-images-p) 784 (if (and (display-images-p)
797 (image-type-available-p 'png) 785 (image-type-available-p 'png))
798 (not (get-text-property (point-min) 'display))) 786 (let ((inhibit-read-only t))
799 (doc-view-toggle-display)) 787 (erase-buffer)
800 (message 788 (doc-view-buffer-message)
801 "%s" 789 (setq doc-view-current-page (or doc-view-current-page 1))
802 (substitute-command-keys 790 (if (file-exists-p (doc-view-current-cache-dir))
803 "Type \\[doc-view-toggle-display] to toggle between image and text display."))) 791 (progn
792 (message "DocView: using cached files!")
793 (doc-view-display doc-view-current-doc))
794 (doc-view-convert-current-doc))
795 (use-local-map doc-view-mode-map)
796 (message
797 "%s"
798 (substitute-command-keys
799 (concat "Type \\[doc-view-toggle-display] to toggle between "
800 "editing or viewing the document."))))
801 (message
802 "%s"
803 (substitute-command-keys
804 (concat "No image (png) support available. Type \\[doc-view-toggle-display] "
805 "to switch to an editing mode.")))))
806
807;;;###autoload
808(define-minor-mode doc-view-minor-mode
809 "Toggle Doc view minor mode.
810With arg, turn Doc view minor mode on if arg is positive, off otherwise.
811See the command `doc-view-mode' for more information on this mode."
812 nil " DocView" doc-view-minor-mode-map
813 :group 'doc-view
814 (when doc-view-minor-mode
815 (add-hook 'change-major-mode-hook (lambda () (doc-view-minor-mode -1)) nil t)
816 (message
817 "%s"
818 (substitute-command-keys
819 "Type \\[doc-view-toggle-display] to toggle between editing or viewing the document."))))
804 820
805(defun doc-view-clear-cache () 821(defun doc-view-clear-cache ()
806 "Delete the whole cache (`doc-view-cache-directory')." 822 "Delete the whole cache (`doc-view-cache-directory')."