aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Monnier2007-10-30 21:53:05 +0000
committerStefan Monnier2007-10-30 21:53:05 +0000
commitc17587fe124eb408ca1761023f0f6a339932e875 (patch)
treeb30af5d482f2c368e28de1556cd6fe35a4b2fc2a
parent36d4b1454480775205a664c0d5f3677db9296649 (diff)
downloademacs-c17587fe124eb408ca1761023f0f6a339932e875.tar.gz
emacs-c17587fe124eb408ca1761023f0f6a339932e875.zip
Use expand-file-name rather than concat.
(doc-view-cache-directory): Add the UID so multiple users won't clash. (doc-view-current-overlay, doc-view-pending-cache-flush): New vars. (doc-view-goto-page, doc-view-insert-image, doc-view-buffer-message) (doc-view-toggle-display): Use an overlay over the whole buffer so as not to have to touch the buffer's content. (doc-view-initiate-display): New function, extracted from doc-view-mode. (doc-view-mode): Use it. Don't mark as a special mode. Put the page numbers in the modeline. Set up the overlay. Hide the cursor. Run the mode hook. Use after-revert-hook rather than revert-buffer-function. (doc-view-search-internal): Fix typo. (doc-view-convert-current-doc, doc-view-insert-image): Delay the image-cache flush. (doc-view-reconvert-doc): Don't reset the whole mode. (doc-view-make-safe-dir): New function. (doc-view-current-cache-dir): Use it.
-rw-r--r--lisp/ChangeLog20
-rw-r--r--lisp/doc-view.el216
2 files changed, 154 insertions, 82 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog
index 6c5a112b854..e5ace8aae86 100644
--- a/lisp/ChangeLog
+++ b/lisp/ChangeLog
@@ -1,3 +1,23 @@
12007-10-30 Stefan Monnier <monnier@iro.umontreal.ca>
2
3 * doc-view.el: Use expand-file-name rather than concat.
4 (doc-view-cache-directory): Add the UID so multiple users won't clash.
5 (doc-view-current-overlay, doc-view-pending-cache-flush): New vars.
6 (doc-view-goto-page, doc-view-insert-image, doc-view-buffer-message)
7 (doc-view-toggle-display): Use an overlay over the whole buffer so as
8 not to have to touch the buffer's content.
9 (doc-view-initiate-display): New function, extracted from doc-view-mode.
10 (doc-view-mode): Use it. Don't mark as a special mode.
11 Put the page numbers in the modeline.
12 Set up the overlay. Hide the cursor. Run the mode hook.
13 Use after-revert-hook rather than revert-buffer-function.
14 (doc-view-search-internal): Fix typo.
15 (doc-view-convert-current-doc, doc-view-insert-image): Delay the
16 image-cache flush.
17 (doc-view-reconvert-doc): Don't reset the whole mode.
18 (doc-view-make-safe-dir): New function.
19 (doc-view-current-cache-dir): Use it.
20
12007-10-30 Jason Rumney <jasonr@gnu.org> 212007-10-30 Jason Rumney <jasonr@gnu.org>
2 22
3 * time.el (display-time-world-list): Test for zoneinfo support. 23 * time.el (display-time-world-list): Test for zoneinfo support.
diff --git a/lisp/doc-view.el b/lisp/doc-view.el
index e2f94ddd8d5..7f31f842e0e 100644
--- a/lisp/doc-view.el
+++ b/lisp/doc-view.el
@@ -103,9 +103,10 @@
103;; Todo: 103;; Todo:
104;; - better menu. 104;; - better menu.
105;; - don't use `find-file'. 105;; - don't use `find-file'.
106;; - `reload' without changing the slicing.
107;; - Bind slicing to a drag event. 106;; - Bind slicing to a drag event.
108;; - zoom 107;; - zoom (the whole document and/or just the region around the cursor).
108;; - get rid of the silly arrow in the fringe.
109;; - improve anti-aliasing (pdf-utils gets it better).
109 110
110(require 'dired) 111(require 'dired)
111(require 'image-mode) 112(require 'image-mode)
@@ -156,8 +157,8 @@ Needed for searching."
156 :type 'file 157 :type 'file
157 :group 'doc-view) 158 :group 'doc-view)
158 159
159(defcustom doc-view-cache-directory (concat temporary-file-directory 160(defcustom doc-view-cache-directory
160 "doc-view") 161 (expand-file-name (concat "docview" (user-uid)) temporary-file-directory)
161 "The base directory, where the PNG images will be saved." 162 "The base directory, where the PNG images will be saved."
162 :type 'directory 163 :type 'directory
163 :group 'doc-view) 164 :group 'doc-view)
@@ -201,6 +202,8 @@ has finished."
201 202
202(defvar doc-view-current-image nil 203(defvar doc-view-current-image nil
203 "Only used internally.") 204 "Only used internally.")
205(defvar doc-view-current-overlay)
206(defvar doc-view-pending-cache-flush nil)
204 207
205(defvar doc-view-current-info nil 208(defvar doc-view-current-info nil
206 "Only used internally.") 209 "Only used internally.")
@@ -303,16 +306,14 @@ has finished."
303 (setq contexts (concat contexts " - \"" m "\"\n"))) 306 (setq contexts (concat contexts " - \"" m "\"\n")))
304 contexts))))) 307 contexts)))))
305 ;; Update the buffer 308 ;; Update the buffer
306 (let ((inhibit-read-only t)) 309 (doc-view-insert-image (nth (1- page) doc-view-current-files)
307 (erase-buffer) 310 :pointer 'arrow)
308 (let ((beg (point))) 311 (overlay-put doc-view-current-overlay 'help-echo doc-view-current-info)
309 (doc-view-insert-image (nth (1- page) doc-view-current-files) 312 (goto-char (point-min))
310 :pointer 'arrow) 313 ;; This seems to be needed for set-window-hscroll (in
311 (put-text-property beg (point) 'help-echo doc-view-current-info)) 314 ;; image-forward-hscroll) to do something useful, I don't have time to
312 (insert "\n" doc-view-current-info) 315 ;; debug this now. :-( --Stef
313 (goto-char (point-min)) 316 (forward-char)))
314 (forward-char))
315 (set-buffer-modified-p nil)))
316 317
317(defun doc-view-next-page (&optional arg) 318(defun doc-view-next-page (&optional arg)
318 "Browse ARG pages forward." 319 "Browse ARG pages forward."
@@ -369,20 +370,49 @@ has finished."
369 (when (eq major-mode 'doc-view-mode) 370 (when (eq major-mode 'doc-view-mode)
370 (kill-buffer (current-buffer)))) 371 (kill-buffer (current-buffer))))
371 372
373(defun doc-view-make-safe-dir (dir)
374 (condition-case nil
375 (let ((umask (default-file-modes)))
376 (unwind-protect
377 (progn
378 ;; Create temp files with strict access rights. It's easy to
379 ;; loosen them later, whereas it's impossible to close the
380 ;; time-window of loose permissions otherwise.
381 (set-default-file-modes #o0700)
382 (make-directory dir))
383 ;; Reset the umask.
384 (set-default-file-modes umask)))
385 (file-already-exists
386 (if (file-symlink-p dir)
387 (error "Danger: %s points to a symbolic link" dir))
388 ;; In case it was created earlier with looser rights.
389 ;; We could check the mode info returned by file-attributes, but it's
390 ;; a pain to parse and it may not tell you what we want under
391 ;; non-standard file-systems. So let's just say what we want and let
392 ;; the underlying C code and file-system figure it out.
393 ;; This also ends up checking a bunch of useful conditions: it makes
394 ;; sure we have write-access to the directory and that we own it, thus
395 ;; closing a bunch of security holes.
396 (set-file-modes dir #o0700))))
397
372(defun doc-view-current-cache-dir () 398(defun doc-view-current-cache-dir ()
373 "Return the directory where the png files of the current doc should be saved. 399 "Return the directory where the png files of the current doc should be saved.
374It's a subdirectory of `doc-view-cache-directory'." 400It's a subdirectory of `doc-view-cache-directory'."
375 (if doc-view-current-cache-dir 401 (if doc-view-current-cache-dir
376 doc-view-current-cache-dir 402 doc-view-current-cache-dir
403 ;; Try and make sure doc-view-cache-directory exists and is safe.
404 (doc-view-make-safe-dir doc-view-cache-directory)
405 ;; Now compute the subdirectory to use.
377 (setq doc-view-current-cache-dir 406 (setq doc-view-current-cache-dir
378 (file-name-as-directory 407 (file-name-as-directory
379 (concat (file-name-as-directory doc-view-cache-directory) 408 (expand-file-name
380 (let ((doc buffer-file-name)) 409 (let ((doc buffer-file-name))
381 (concat (file-name-nondirectory doc) 410 (concat (file-name-nondirectory doc)
382 "-" 411 "-"
383 (with-temp-buffer 412 (with-temp-buffer
384 (insert-file-contents-literally doc) 413 (insert-file-contents-literally doc)
385 (md5 (current-buffer)))))))))) 414 (md5 (current-buffer)))))
415 doc-view-cache-directory)))))
386 416
387(defun doc-view-remove-if (predicate list) 417(defun doc-view-remove-if (predicate list)
388 "Return LIST with all items removed that satisfy PREDICATE." 418 "Return LIST with all items removed that satisfy PREDICATE."
@@ -393,7 +423,7 @@ It's a subdirectory of `doc-view-cache-directory'."
393 423
394;;;; Conversion Functions 424;;;; Conversion Functions
395 425
396(defun doc-view-reconvert-doc (&rest args) 426(defun doc-view-reconvert-doc ()
397 "Reconvert the current document. 427 "Reconvert the current document.
398Should be invoked when the cached images aren't up-to-date." 428Should be invoked when the cached images aren't up-to-date."
399 (interactive) 429 (interactive)
@@ -401,7 +431,7 @@ Should be invoked when the cached images aren't up-to-date."
401 ;; Clear the old cached files 431 ;; Clear the old cached files
402 (when (file-exists-p (doc-view-current-cache-dir)) 432 (when (file-exists-p (doc-view-current-cache-dir))
403 (dired-delete-file (doc-view-current-cache-dir) 'always)) 433 (dired-delete-file (doc-view-current-cache-dir) 'always))
404 (doc-view-mode)) 434 (doc-view-initiate-display))
405 435
406(defun doc-view-dvi->pdf-sentinel (proc event) 436(defun doc-view-dvi->pdf-sentinel (proc event)
407 "If DVI->PDF conversion was successful, convert the PDF to PNG now." 437 "If DVI->PDF conversion was successful, convert the PDF to PNG now."
@@ -412,8 +442,8 @@ Should be invoked when the cached images aren't up-to-date."
412 mode-line-process nil) 442 mode-line-process nil)
413 ;; Now go on converting this PDF to a set of PNG files. 443 ;; Now go on converting this PDF to a set of PNG files.
414 (let* ((pdf (process-get proc 'pdf-file)) 444 (let* ((pdf (process-get proc 'pdf-file))
415 (png (concat (doc-view-current-cache-dir) 445 (png (expand-file-name "page-%d.png"
416 "page-%d.png"))) 446 (doc-view-current-cache-dir))))
417 (doc-view-pdf/ps->png pdf png)))) 447 (doc-view-pdf/ps->png pdf png))))
418 448
419(defun doc-view-dvi->pdf (dvi pdf) 449(defun doc-view-dvi->pdf (dvi pdf)
@@ -493,8 +523,8 @@ Should be invoked when the cached images aren't up-to-date."
493 mode-line-process nil) 523 mode-line-process nil)
494 ;; Now we can transform to plain text. 524 ;; Now we can transform to plain text.
495 (doc-view-pdf->txt (process-get proc 'pdf-file) 525 (doc-view-pdf->txt (process-get proc 'pdf-file)
496 (concat (doc-view-current-cache-dir) 526 (expand-file-name "doc.txt"
497 "doc.txt")))) 527 (doc-view-current-cache-dir)))))
498 528
499(defun doc-view-ps->pdf (ps pdf) 529(defun doc-view-ps->pdf (ps pdf)
500 "Convert PS to PDF asynchronously." 530 "Convert PS to PDF asynchronously."
@@ -516,18 +546,23 @@ Should be invoked when the cached images aren't up-to-date."
516 "Convert `buffer-file-name' to a set of png files, one file per page. 546 "Convert `buffer-file-name' to a set of png files, one file per page.
517Those files are saved in the directory given by the function 547Those files are saved in the directory given by the function
518`doc-view-current-cache-dir'." 548`doc-view-current-cache-dir'."
519 (clear-image-cache) 549 ;; Let stale files still display while we recompute the new ones, so only
520 (let ((png-file (concat (doc-view-current-cache-dir) 550 ;; flush the cache when the conversion is over. One of the reasons why it
521 "page-%d.png"))) 551 ;; is important to keep displaying the stale page is so that revert-buffer
522 (make-directory (doc-view-current-cache-dir) t) 552 ;; preserves the horizontal/vertical scroll settings (which are otherwise
553 ;; resets during the redisplay).
554 (setq doc-view-pending-cache-flush t)
555 (let ((png-file (expand-file-name "page-%d.png"
556 (doc-view-current-cache-dir))))
557 (make-directory (doc-view-current-cache-dir))
523 (if (not (string= (file-name-extension buffer-file-name) "dvi")) 558 (if (not (string= (file-name-extension buffer-file-name) "dvi"))
524 ;; Convert to PNG images. 559 ;; Convert to PNG images.
525 (doc-view-pdf/ps->png buffer-file-name png-file) 560 (doc-view-pdf/ps->png buffer-file-name png-file)
526 ;; DVI files have to be converted to PDF before Ghostscript can process 561 ;; DVI files have to be converted to PDF before Ghostscript can process
527 ;; it. 562 ;; it.
528 (doc-view-dvi->pdf buffer-file-name 563 (doc-view-dvi->pdf buffer-file-name
529 (concat (file-name-as-directory doc-view-current-cache-dir) 564 (expand-file-name "doc.pdf"
530 "doc.pdf"))))) 565 doc-view-current-cache-dir)))))
531 566
532;;;; Slicing 567;;;; Slicing
533 568
@@ -583,9 +618,16 @@ again."
583(defun doc-view-insert-image (file &rest args) 618(defun doc-view-insert-image (file &rest args)
584 "Insert the given png FILE. 619 "Insert the given png FILE.
585ARGS is a list of image descriptors." 620ARGS is a list of image descriptors."
621 (when doc-view-pending-cache-flush
622 (clear-image-cache)
623 (setq doc-view-pending-cache-flush nil))
586 (let ((image (apply 'create-image file 'png nil args))) 624 (let ((image (apply 'create-image file 'png nil args)))
587 (setq doc-view-current-image image) 625 (setq doc-view-current-image image)
588 (insert-image image (concat "[" file "]") nil doc-view-current-slice))) 626 (move-overlay doc-view-current-overlay (point-min) (point-max))
627 (overlay-put doc-view-current-overlay 'display
628 (if doc-view-current-slice
629 (list (cons 'slice doc-view-current-slice) image)
630 image))))
589 631
590(defun doc-view-sort (a b) 632(defun doc-view-sort (a b)
591 "Return non-nil if A should be sorted before B. 633 "Return non-nil if A should be sorted before B.
@@ -605,9 +647,14 @@ Predicate for sorting `doc-view-current-files'."
605 (doc-view-goto-page doc-view-current-page))) 647 (doc-view-goto-page doc-view-current-page)))
606 648
607(defun doc-view-buffer-message () 649(defun doc-view-buffer-message ()
608 (insert (propertize "Welcome to DocView!" 'face 'bold) 650 ;; Only show this message initially, not when refreshing the buffer (in which
609 "\n" 651 ;; case it's better to keep displaying the "stale" page while computing
610 " 652 ;; the fresh new ones).
653 (unless (overlay-get doc-view-current-overlay 'display)
654 (overlay-put doc-view-current-overlay 'display
655 (concat (propertize "Welcome to DocView!" 'face 'bold)
656 "\n"
657 "
611If you see this buffer it means that the document you want to view is being 658If you see this buffer it means that the document you want to view is being
612converted to PNG and the conversion of the first page hasn't finished yet or 659converted to PNG and the conversion of the first page hasn't finished yet or
613`doc-view-conversion-refresh-interval' is set to nil. 660`doc-view-conversion-refresh-interval' is set to nil.
@@ -616,7 +663,7 @@ For now these keys are useful:
616 663
617`q' : Bury this buffer. Conversion will go on in background. 664`q' : Bury this buffer. Conversion will go on in background.
618`k' : Kill the conversion process and this buffer. 665`k' : Kill the conversion process and this buffer.
619`K' : Kill the conversion process.\n")) 666`K' : Kill the conversion process.\n"))))
620 667
621(defun doc-view-show-tooltip () 668(defun doc-view-show-tooltip ()
622 (interactive) 669 (interactive)
@@ -632,20 +679,17 @@ For now these keys are useful:
632 (progn 679 (progn
633 (doc-view-kill-proc) 680 (doc-view-kill-proc)
634 (setq buffer-read-only nil) 681 (setq buffer-read-only nil)
635 (erase-buffer) 682 (delete-overlay doc-view-current-overlay)
636 (insert-file-contents buffer-file-name)
637 ;; Switch to the previously used major mode or fall back to fundamental 683 ;; Switch to the previously used major mode or fall back to fundamental
638 ;; mode. 684 ;; mode.
639 (if doc-view-previous-major-mode 685 (if doc-view-previous-major-mode
640 (funcall doc-view-previous-major-mode) 686 (funcall doc-view-previous-major-mode)
641 (fundamental-mode)) 687 (fundamental-mode))
642 (doc-view-minor-mode 1) 688 (doc-view-minor-mode 1))
643 (set-buffer-modified-p nil))
644 ;; Switch to doc-view-mode 689 ;; Switch to doc-view-mode
645 (when (and (buffer-modified-p) 690 (when (and (buffer-modified-p)
646 (y-or-n-p "The buffer has been modified. Save the changes? ")) 691 (y-or-n-p "The buffer has been modified. Save the changes? "))
647 (save-buffer)) 692 (save-buffer))
648 (erase-buffer)
649 (doc-view-mode))) 693 (doc-view-mode)))
650 694
651;;;; Searching 695;;;; Searching
@@ -664,11 +708,11 @@ the pagenumber and CONTEXTS are all lines of text containing a match."
664 (when (match-string 1) (incf page)) 708 (when (match-string 1) (incf page))
665 (when (match-string 2) 709 (when (match-string 2)
666 (if (/= page lastpage) 710 (if (/= page lastpage)
667 (setq matches (push (cons page 711 (push (cons page
668 (list (buffer-substring 712 (list (buffer-substring
669 (line-beginning-position) 713 (line-beginning-position)
670 (line-end-position)))) 714 (line-end-position))))
671 matches)) 715 matches)
672 (setq matches (cons 716 (setq matches (cons
673 (append 717 (append
674 (or 718 (or
@@ -698,8 +742,8 @@ conversion finished."
698 (interactive) 742 (interactive)
699 ;; New search, so forget the old results. 743 ;; New search, so forget the old results.
700 (setq doc-view-current-search-matches nil) 744 (setq doc-view-current-search-matches nil)
701 (let ((txt (concat (doc-view-current-cache-dir) 745 (let ((txt (expand-file-name "doc.txt"
702 "doc.txt"))) 746 (doc-view-current-cache-dir))))
703 (if (file-readable-p txt) 747 (if (file-readable-p txt)
704 (progn 748 (progn
705 (setq doc-view-current-search-matches 749 (setq doc-view-current-search-matches
@@ -721,13 +765,13 @@ conversion finished."
721 ;; Doc is a PS, so convert it to PDF (which will be converted to 765 ;; Doc is a PS, so convert it to PDF (which will be converted to
722 ;; TXT thereafter). 766 ;; TXT thereafter).
723 (doc-view-ps->pdf buffer-file-name 767 (doc-view-ps->pdf buffer-file-name
724 (concat (doc-view-current-cache-dir) 768 (expand-file-name "doc.pdf"
725 "doc.pdf"))) 769 (doc-view-current-cache-dir))))
726 ((string= ext "dvi") 770 ((string= ext "dvi")
727 ;; Doc is a DVI. This means that a doc.pdf already exists in its 771 ;; Doc is a DVI. This means that a doc.pdf already exists in its
728 ;; cache subdirectory. 772 ;; cache subdirectory.
729 (doc-view-pdf->txt (concat (doc-view-current-cache-dir) 773 (doc-view-pdf->txt (expand-file-name "doc.pdf"
730 "doc.pdf") 774 (doc-view-current-cache-dir))
731 txt)) 775 txt))
732 (t (error "DocView doesn't know what to do")))))))) 776 (t (error "DocView doesn't know what to do"))))))))
733 777
@@ -761,7 +805,30 @@ conversion finished."
761 805
762;;;; User interface commands and the mode 806;;;; User interface commands and the mode
763 807
764(put 'doc-view-mode 'mode-class 'special) 808;; (put 'doc-view-mode 'mode-class 'special)
809
810(defun doc-view-initiate-display ()
811 ;; Switch to image display if possible
812 (if (and (display-images-p)
813 (image-type-available-p 'png))
814 (progn
815 (doc-view-buffer-message)
816 (setq doc-view-current-page (or doc-view-current-page 1))
817 (if (file-exists-p (doc-view-current-cache-dir))
818 (progn
819 (message "DocView: using cached files!")
820 (doc-view-display buffer-file-name))
821 (doc-view-convert-current-doc))
822 (message
823 "%s"
824 (substitute-command-keys
825 (concat "Type \\[doc-view-toggle-display] to toggle between "
826 "editing or viewing the document."))))
827 (message
828 "%s"
829 (substitute-command-keys
830 (concat "No image (png) support available. Type \\[doc-view-toggle-display] "
831 "to switch to an editing mode.")))))
765 832
766;;;###autoload 833;;;###autoload
767(defun doc-view-mode () 834(defun doc-view-mode ()
@@ -783,37 +850,22 @@ toggle between displaying the document or editing it as text."
783 (make-local-variable 'doc-view-current-cache-dir) 850 (make-local-variable 'doc-view-current-cache-dir)
784 (make-local-variable 'doc-view-current-info) 851 (make-local-variable 'doc-view-current-info)
785 (make-local-variable 'doc-view-current-search-matches) 852 (make-local-variable 'doc-view-current-search-matches)
786 ;; The file should already be in the current buffer. --Stef 853 (set (make-local-variable 'doc-view-current-overlay)
787 ;; (insert-file-contents buffer-file-name) 854 (make-overlay (point-min) (point-max) nil t))
855 (add-hook 'change-major-mode-hook
856 (lambda () (delete-overlay doc-view-current-overlay))
857 nil t)
858 (set (make-local-variable 'mode-line-position)
859 '(" P" (:eval (number-to-string doc-view-current-page))
860 "/" (:eval (number-to-string (length doc-view-current-files)))))
861 (set (make-local-variable 'cursor-type) nil)
788 (use-local-map doc-view-mode-map) 862 (use-local-map doc-view-mode-map)
789 (set (make-local-variable 'revert-buffer-function) 'doc-view-reconvert-doc) 863 (set (make-local-variable 'after-revert-hook) 'doc-view-reconvert-doc)
790 (setq mode-name "DocView" 864 (setq mode-name "DocView"
791 buffer-read-only t 865 buffer-read-only t
792 major-mode 'doc-view-mode) 866 major-mode 'doc-view-mode)
793 ;; Switch to image display if possible 867 (doc-view-initiate-display)
794 (if (and (display-images-p) 868 (run-mode-hooks 'doc-view-mode-hook))
795 (image-type-available-p 'png))
796 (let ((inhibit-read-only t))
797 (erase-buffer)
798 (doc-view-buffer-message)
799 (set-buffer-modified-p nil)
800 (setq doc-view-current-page (or doc-view-current-page 1))
801 (if (file-exists-p (doc-view-current-cache-dir))
802 (progn
803 (message "DocView: using cached files!")
804 (doc-view-display buffer-file-name))
805 (doc-view-convert-current-doc))
806 (use-local-map doc-view-mode-map)
807 (message
808 "%s"
809 (substitute-command-keys
810 (concat "Type \\[doc-view-toggle-display] to toggle between "
811 "editing or viewing the document."))))
812 (message
813 "%s"
814 (substitute-command-keys
815 (concat "No image (png) support available. Type \\[doc-view-toggle-display] "
816 "to switch to an editing mode.")))))
817 869
818;;;###autoload 870;;;###autoload
819(define-minor-mode doc-view-minor-mode 871(define-minor-mode doc-view-minor-mode