diff options
Diffstat (limited to 'lisp/doc-view.el')
| -rw-r--r-- | lisp/doc-view.el | 203 |
1 files changed, 121 insertions, 82 deletions
diff --git a/lisp/doc-view.el b/lisp/doc-view.el index 9c153dc584f..aaa68bf6387 100644 --- a/lisp/doc-view.el +++ b/lisp/doc-view.el | |||
| @@ -99,11 +99,11 @@ | |||
| 99 | 99 | ||
| 100 | ;;; Todo: | 100 | ;;; Todo: |
| 101 | 101 | ||
| 102 | ;; - share more code with image-mode again. | ||
| 102 | ;; - better menu. | 103 | ;; - better menu. |
| 103 | ;; - don't use `find-file'. | ||
| 104 | ;; - Bind slicing to a drag event. | 104 | ;; - Bind slicing to a drag event. |
| 105 | ;; - doc-view-fit-doc-to-window and doc-view-fit-window-to-doc. | 105 | ;; - doc-view-fit-doc-to-window and doc-view-fit-window-to-doc. |
| 106 | ;; - zoom a the region around the cursor (like xdvi). | 106 | ;; - zoom the region around the cursor (like xdvi). |
| 107 | ;; - get rid of the silly arrow in the fringe. | 107 | ;; - get rid of the silly arrow in the fringe. |
| 108 | ;; - improve anti-aliasing (pdf-utils gets it better). | 108 | ;; - improve anti-aliasing (pdf-utils gets it better). |
| 109 | 109 | ||
| @@ -247,6 +247,14 @@ has finished." | |||
| 247 | (defvar doc-view-previous-major-mode nil | 247 | (defvar doc-view-previous-major-mode nil |
| 248 | "Only used internally.") | 248 | "Only used internally.") |
| 249 | 249 | ||
| 250 | (defvar doc-view-buffer-file-name nil | ||
| 251 | "Only used internally. | ||
| 252 | The file name used for conversion. Normally it's the same as | ||
| 253 | `buffer-file-name', but for remote files, compressed files and | ||
| 254 | files inside an archive it is a temporary copy of | ||
| 255 | the (uncompressed, extracted) file residing in | ||
| 256 | `doc-view-cache-directory'.") | ||
| 257 | |||
| 250 | ;;;; DocView Keymaps | 258 | ;;;; DocView Keymaps |
| 251 | 259 | ||
| 252 | (defvar doc-view-mode-map | 260 | (defvar doc-view-mode-map |
| @@ -349,12 +357,7 @@ has finished." | |||
| 349 | ;; Update the buffer | 357 | ;; Update the buffer |
| 350 | (doc-view-insert-image (nth (1- page) doc-view-current-files) | 358 | (doc-view-insert-image (nth (1- page) doc-view-current-files) |
| 351 | :pointer 'arrow) | 359 | :pointer 'arrow) |
| 352 | (overlay-put doc-view-current-overlay 'help-echo doc-view-current-info) | 360 | (overlay-put doc-view-current-overlay 'help-echo doc-view-current-info))) |
| 353 | (goto-char (point-min)) | ||
| 354 | ;; This seems to be needed for set-window-hscroll (in | ||
| 355 | ;; image-forward-hscroll) to do something useful, I don't have time to | ||
| 356 | ;; debug this now. :-( --Stef | ||
| 357 | (forward-char))) | ||
| 358 | 361 | ||
| 359 | (defun doc-view-next-page (&optional arg) | 362 | (defun doc-view-next-page (&optional arg) |
| 360 | "Browse ARG pages forward." | 363 | "Browse ARG pages forward." |
| @@ -450,12 +453,12 @@ It's a subdirectory of `doc-view-cache-directory'." | |||
| 450 | (setq doc-view-current-cache-dir | 453 | (setq doc-view-current-cache-dir |
| 451 | (file-name-as-directory | 454 | (file-name-as-directory |
| 452 | (expand-file-name | 455 | (expand-file-name |
| 453 | (let ((doc buffer-file-name)) | 456 | (concat (file-name-nondirectory buffer-file-name) |
| 454 | (concat (file-name-nondirectory doc) | 457 | "-" |
| 455 | "-" | 458 | (let ((file doc-view-buffer-file-name)) |
| 456 | (with-temp-buffer | 459 | (with-temp-buffer |
| 457 | (insert-file-contents-literally doc) | 460 | (insert-file-contents-literally file) |
| 458 | (md5 (current-buffer))))) | 461 | (md5 (current-buffer))))) |
| 459 | doc-view-cache-directory))))) | 462 | doc-view-cache-directory))))) |
| 460 | 463 | ||
| 461 | (defun doc-view-remove-if (predicate list) | 464 | (defun doc-view-remove-if (predicate list) |
| @@ -476,7 +479,7 @@ Image types are symbols like `dvi', `postscript' or `pdf'." | |||
| 476 | (and (doc-view-mode-p 'pdf) | 479 | (and (doc-view-mode-p 'pdf) |
| 477 | doc-view-dvipdfm-program | 480 | doc-view-dvipdfm-program |
| 478 | (executable-find doc-view-dvipdfm-program))) | 481 | (executable-find doc-view-dvipdfm-program))) |
| 479 | ((or (eq type 'postscript) (eq type 'ps) | 482 | ((or (eq type 'postscript) (eq type 'ps) (eq type 'eps) |
| 480 | (eq type 'pdf)) | 483 | (eq type 'pdf)) |
| 481 | (and doc-view-ghostscript-program | 484 | (and doc-view-ghostscript-program |
| 482 | (executable-find doc-view-ghostscript-program))) | 485 | (executable-find doc-view-ghostscript-program))) |
| @@ -550,13 +553,16 @@ Should be invoked when the cached images aren't up-to-date." | |||
| 550 | (defun doc-view-pdf/ps->png (pdf-ps png) | 553 | (defun doc-view-pdf/ps->png (pdf-ps png) |
| 551 | "Convert PDF-PS to PNG asynchronously." | 554 | "Convert PDF-PS to PNG asynchronously." |
| 552 | (setq doc-view-current-converter-process | 555 | (setq doc-view-current-converter-process |
| 553 | (apply 'start-process | 556 | ;; Make sure the process is started in an existing directory, |
| 554 | (append (list "pdf/ps->png" doc-view-conversion-buffer | 557 | ;; (rather than some file-name-handler-managed dir, for example). |
| 555 | doc-view-ghostscript-program) | 558 | (let ((default-directory (file-name-directory pdf-ps))) |
| 556 | doc-view-ghostscript-options | 559 | (apply 'start-process |
| 557 | (list (format "-r%d" (round doc-view-resolution))) | 560 | (append (list "pdf/ps->png" doc-view-conversion-buffer |
| 558 | (list (concat "-sOutputFile=" png)) | 561 | doc-view-ghostscript-program) |
| 559 | (list pdf-ps))) | 562 | doc-view-ghostscript-options |
| 563 | (list (format "-r%d" (round doc-view-resolution))) | ||
| 564 | (list (concat "-sOutputFile=" png)) | ||
| 565 | (list pdf-ps)))) | ||
| 560 | mode-line-process (list (format ":%s" doc-view-current-converter-process))) | 566 | mode-line-process (list (format ":%s" doc-view-current-converter-process))) |
| 561 | (process-put doc-view-current-converter-process | 567 | (process-put doc-view-current-converter-process |
| 562 | 'buffer (current-buffer)) | 568 | 'buffer (current-buffer)) |
| @@ -620,7 +626,7 @@ Should be invoked when the cached images aren't up-to-date." | |||
| 620 | (process-put doc-view-current-converter-process 'pdf-file pdf)) | 626 | (process-put doc-view-current-converter-process 'pdf-file pdf)) |
| 621 | 627 | ||
| 622 | (defun doc-view-convert-current-doc () | 628 | (defun doc-view-convert-current-doc () |
| 623 | "Convert `buffer-file-name' to a set of png files, one file per page. | 629 | "Convert `doc-view-buffer-file-name' to a set of png files, one file per page. |
| 624 | Those files are saved in the directory given by the function | 630 | Those files are saved in the directory given by the function |
| 625 | `doc-view-current-cache-dir'." | 631 | `doc-view-current-cache-dir'." |
| 626 | ;; Let stale files still display while we recompute the new ones, so only | 632 | ;; Let stale files still display while we recompute the new ones, so only |
| @@ -632,12 +638,12 @@ Those files are saved in the directory given by the function | |||
| 632 | (let ((png-file (expand-file-name "page-%d.png" | 638 | (let ((png-file (expand-file-name "page-%d.png" |
| 633 | (doc-view-current-cache-dir)))) | 639 | (doc-view-current-cache-dir)))) |
| 634 | (make-directory (doc-view-current-cache-dir)) | 640 | (make-directory (doc-view-current-cache-dir)) |
| 635 | (if (not (string= (file-name-extension buffer-file-name) "dvi")) | 641 | (if (not (string= (file-name-extension doc-view-buffer-file-name) "dvi")) |
| 636 | ;; Convert to PNG images. | 642 | ;; Convert to PNG images. |
| 637 | (doc-view-pdf/ps->png buffer-file-name png-file) | 643 | (doc-view-pdf/ps->png doc-view-buffer-file-name png-file) |
| 638 | ;; DVI files have to be converted to PDF before Ghostscript can process | 644 | ;; DVI files have to be converted to PDF before Ghostscript can process |
| 639 | ;; it. | 645 | ;; it. |
| 640 | (doc-view-dvi->pdf buffer-file-name | 646 | (doc-view-dvi->pdf doc-view-buffer-file-name |
| 641 | (expand-file-name "doc.pdf" | 647 | (expand-file-name "doc.pdf" |
| 642 | doc-view-current-cache-dir))))) | 648 | doc-view-current-cache-dir))))) |
| 643 | 649 | ||
| @@ -697,13 +703,23 @@ ARGS is a list of image descriptors." | |||
| 697 | (when doc-view-pending-cache-flush | 703 | (when doc-view-pending-cache-flush |
| 698 | (clear-image-cache) | 704 | (clear-image-cache) |
| 699 | (setq doc-view-pending-cache-flush nil)) | 705 | (setq doc-view-pending-cache-flush nil)) |
| 700 | (let ((image (apply 'create-image file 'png nil args))) | 706 | (if (null file) |
| 701 | (setq doc-view-current-image image) | 707 | ;; We're trying to display a page that doesn't exist. Typically happens |
| 702 | (move-overlay doc-view-current-overlay (point-min) (point-max)) | 708 | ;; if the conversion process somehow failed. Better not signal an |
| 703 | (overlay-put doc-view-current-overlay 'display | 709 | ;; error here because it could prevent a subsequent reconversion from |
| 704 | (if doc-view-current-slice | 710 | ;; fixing the problem. |
| 705 | (list (cons 'slice doc-view-current-slice) image) | 711 | (progn |
| 706 | image)))) | 712 | (setq doc-view-current-image nil) |
| 713 | (move-overlay doc-view-current-overlay (point-min) (point-max)) | ||
| 714 | (overlay-put doc-view-current-overlay 'display | ||
| 715 | "Cannot display this page! Probably a conversion failure!")) | ||
| 716 | (let ((image (apply 'create-image file 'png nil args))) | ||
| 717 | (setq doc-view-current-image image) | ||
| 718 | (move-overlay doc-view-current-overlay (point-min) (point-max)) | ||
| 719 | (overlay-put doc-view-current-overlay 'display | ||
| 720 | (if doc-view-current-slice | ||
| 721 | (list (cons 'slice doc-view-current-slice) image) | ||
| 722 | image))))) | ||
| 707 | 723 | ||
| 708 | (defun doc-view-sort (a b) | 724 | (defun doc-view-sort (a b) |
| 709 | "Return non-nil if A should be sorted before B. | 725 | "Return non-nil if A should be sorted before B. |
| @@ -847,15 +863,15 @@ If BACKWARD is non-nil, jump to the previous match." | |||
| 847 | ;; We must convert to TXT first! | 863 | ;; We must convert to TXT first! |
| 848 | (if doc-view-current-converter-process | 864 | (if doc-view-current-converter-process |
| 849 | (message "DocView: please wait till conversion finished.") | 865 | (message "DocView: please wait till conversion finished.") |
| 850 | (let ((ext (file-name-extension buffer-file-name))) | 866 | (let ((ext (file-name-extension doc-view-buffer-file-name))) |
| 851 | (cond | 867 | (cond |
| 852 | ((string= ext "pdf") | 868 | ((string= ext "pdf") |
| 853 | ;; Doc is a PDF, so convert it to TXT | 869 | ;; Doc is a PDF, so convert it to TXT |
| 854 | (doc-view-pdf->txt buffer-file-name txt)) | 870 | (doc-view-pdf->txt doc-view-buffer-file-name txt)) |
| 855 | ((string= ext "ps") | 871 | ((string= ext "ps") |
| 856 | ;; Doc is a PS, so convert it to PDF (which will be converted to | 872 | ;; Doc is a PS, so convert it to PDF (which will be converted to |
| 857 | ;; TXT thereafter). | 873 | ;; TXT thereafter). |
| 858 | (doc-view-ps->pdf buffer-file-name | 874 | (doc-view-ps->pdf doc-view-buffer-file-name |
| 859 | (expand-file-name "doc.pdf" | 875 | (expand-file-name "doc.pdf" |
| 860 | (doc-view-current-cache-dir)))) | 876 | (doc-view-current-cache-dir)))) |
| 861 | ((string= ext "dvi") | 877 | ((string= ext "dvi") |
| @@ -900,7 +916,7 @@ If BACKWARD is non-nil, jump to the previous match." | |||
| 900 | 916 | ||
| 901 | (defun doc-view-initiate-display () | 917 | (defun doc-view-initiate-display () |
| 902 | ;; Switch to image display if possible | 918 | ;; Switch to image display if possible |
| 903 | (if (doc-view-mode-p (intern (file-name-extension buffer-file-name))) | 919 | (if (doc-view-mode-p (intern (file-name-extension doc-view-buffer-file-name))) |
| 904 | (progn | 920 | (progn |
| 905 | (doc-view-buffer-message) | 921 | (doc-view-buffer-message) |
| 906 | (setq doc-view-current-page (or doc-view-current-page 1)) | 922 | (setq doc-view-current-page (or doc-view-current-page 1)) |
| @@ -918,7 +934,7 @@ If BACKWARD is non-nil, jump to the previous match." | |||
| 918 | "%s" | 934 | "%s" |
| 919 | (substitute-command-keys | 935 | (substitute-command-keys |
| 920 | (concat "No image (png) support available or some conversion utility for " | 936 | (concat "No image (png) support available or some conversion utility for " |
| 921 | (file-name-extension buffer-file-name)" files is missing. " | 937 | (file-name-extension doc-view-buffer-file-name)" files is missing. " |
| 922 | "Type \\[doc-view-toggle-display] to switch to an editing mode."))))) | 938 | "Type \\[doc-view-toggle-display] to switch to an editing mode."))))) |
| 923 | 939 | ||
| 924 | (defvar bookmark-make-cell-function) | 940 | (defvar bookmark-make-cell-function) |
| @@ -929,49 +945,72 @@ If BACKWARD is non-nil, jump to the previous match." | |||
| 929 | You can use \\<doc-view-mode-map>\\[doc-view-toggle-display] to | 945 | You can use \\<doc-view-mode-map>\\[doc-view-toggle-display] to |
| 930 | toggle between displaying the document or editing it as text." | 946 | toggle between displaying the document or editing it as text." |
| 931 | (interactive) | 947 | (interactive) |
| 932 | (if jka-compr-really-do-compress | 948 | |
| 933 | ;; This is a compressed file uncompressed by auto-compression-mode. | 949 | (let* ((prev-major-mode (if (eq major-mode 'doc-view-mode) |
| 934 | (when (y-or-n-p (concat "DocView: Cannot convert compressed file. " | 950 | doc-view-previous-major-mode |
| 935 | "Save it uncompressed first? ")) | 951 | major-mode))) |
| 936 | (let ((file (read-file-name | 952 | (kill-all-local-variables) |
| 937 | "File: " | 953 | (set (make-local-variable 'doc-view-previous-major-mode) prev-major-mode)) |
| 938 | (file-name-directory buffer-file-name)))) | 954 | |
| 939 | (write-region (point-min) (point-max) file) | 955 | ;; Handle compressed files, remote files, files inside archives |
| 940 | (kill-buffer nil) | 956 | (set (make-local-variable 'doc-view-buffer-file-name) |
| 941 | (find-file file) | 957 | (cond |
| 942 | (doc-view-mode))) | 958 | (jka-compr-really-do-compress |
| 943 | (let* ((prev-major-mode (if (eq major-mode 'doc-view-mode) | 959 | (expand-file-name |
| 944 | doc-view-previous-major-mode | 960 | (file-name-nondirectory |
| 945 | major-mode))) | 961 | (file-name-sans-extension buffer-file-name)) |
| 946 | (kill-all-local-variables) | 962 | doc-view-cache-directory)) |
| 947 | (set (make-local-variable 'doc-view-previous-major-mode) prev-major-mode)) | 963 | ;; Is the file readable by local processes? |
| 948 | (make-local-variable 'doc-view-current-files) | 964 | ;; We used to use `file-remote-p' but it's unclear what it's |
| 949 | (make-local-variable 'doc-view-current-image) | 965 | ;; supposed to return nil for things like local files accessed via |
| 950 | (make-local-variable 'doc-view-current-page) | 966 | ;; `su' or via file://... |
| 951 | (make-local-variable 'doc-view-current-converter-process) | 967 | ((let ((file-name-handler-alist nil)) |
| 952 | (make-local-variable 'doc-view-current-timer) | 968 | (not (file-readable-p buffer-file-name))) |
| 953 | (make-local-variable 'doc-view-current-slice) | 969 | (expand-file-name |
| 954 | (make-local-variable 'doc-view-current-cache-dir) | 970 | (file-name-nondirectory buffer-file-name) |
| 955 | (make-local-variable 'doc-view-current-info) | 971 | doc-view-cache-directory)) |
| 956 | (make-local-variable 'doc-view-current-search-matches) | 972 | (t buffer-file-name))) |
| 957 | (set (make-local-variable 'doc-view-current-overlay) | 973 | (when (not (string= doc-view-buffer-file-name buffer-file-name)) |
| 958 | (make-overlay (point-min) (point-max) nil t)) | 974 | (write-region nil nil doc-view-buffer-file-name)) |
| 959 | (add-hook 'change-major-mode-hook | 975 | |
| 960 | (lambda () (delete-overlay doc-view-current-overlay)) | 976 | (make-local-variable 'doc-view-current-files) |
| 961 | nil t) | 977 | (make-local-variable 'doc-view-current-image) |
| 962 | (set (make-local-variable 'mode-line-position) | 978 | (make-local-variable 'doc-view-current-page) |
| 963 | '(" P" (:eval (number-to-string doc-view-current-page)) | 979 | (make-local-variable 'doc-view-current-converter-process) |
| 964 | "/" (:eval (number-to-string (length doc-view-current-files))))) | 980 | (make-local-variable 'doc-view-current-timer) |
| 965 | (set (make-local-variable 'cursor-type) nil) | 981 | (make-local-variable 'doc-view-current-slice) |
| 966 | (use-local-map doc-view-mode-map) | 982 | (make-local-variable 'doc-view-current-cache-dir) |
| 967 | (set (make-local-variable 'after-revert-hook) 'doc-view-reconvert-doc) | 983 | (make-local-variable 'doc-view-current-info) |
| 968 | (set (make-local-variable 'bookmark-make-cell-function) | 984 | (make-local-variable 'doc-view-current-search-matches) |
| 969 | 'doc-view-bookmark-make-cell) | 985 | (set (make-local-variable 'doc-view-current-overlay) |
| 970 | (setq mode-name "DocView" | 986 | (make-overlay (point-min) (point-max) nil t)) |
| 971 | buffer-read-only t | 987 | (add-hook 'change-major-mode-hook |
| 972 | major-mode 'doc-view-mode) | 988 | (lambda () (delete-overlay doc-view-current-overlay)) |
| 973 | (doc-view-initiate-display) | 989 | nil t) |
| 974 | (run-mode-hooks 'doc-view-mode-hook))) | 990 | |
| 991 | ;; Keep track of [vh]scroll when switching buffers | ||
| 992 | (make-local-variable 'image-mode-current-hscroll) | ||
| 993 | (make-local-variable 'image-mode-current-vscroll) | ||
| 994 | (image-set-window-hscroll (selected-window) (window-hscroll)) | ||
| 995 | (image-set-window-vscroll (selected-window) (window-vscroll)) | ||
| 996 | (add-hook 'window-configuration-change-hook | ||
| 997 | 'image-reset-current-vhscroll nil t) | ||
| 998 | |||
| 999 | (set (make-local-variable 'mode-line-position) | ||
| 1000 | '(" P" (:eval (number-to-string doc-view-current-page)) | ||
| 1001 | "/" (:eval (number-to-string (length doc-view-current-files))))) | ||
| 1002 | ;; Don't scroll unless the user specifically asked for it. | ||
| 1003 | (set (make-local-variable 'auto-hscroll-mode) nil) | ||
| 1004 | (set (make-local-variable 'cursor-type) nil) | ||
| 1005 | (use-local-map doc-view-mode-map) | ||
| 1006 | (set (make-local-variable 'after-revert-hook) 'doc-view-reconvert-doc) | ||
| 1007 | (set (make-local-variable 'bookmark-make-cell-function) | ||
| 1008 | 'doc-view-bookmark-make-cell) | ||
| 1009 | (setq mode-name "DocView" | ||
| 1010 | buffer-read-only t | ||
| 1011 | major-mode 'doc-view-mode) | ||
| 1012 | (doc-view-initiate-display) | ||
| 1013 | (run-mode-hooks 'doc-view-mode-hook)) | ||
| 975 | 1014 | ||
| 976 | ;;;###autoload | 1015 | ;;;###autoload |
| 977 | (define-minor-mode doc-view-minor-mode | 1016 | (define-minor-mode doc-view-minor-mode |
| @@ -1003,7 +1042,7 @@ See the command `doc-view-mode' for more information on this mode." | |||
| 1003 | 1042 | ||
| 1004 | (defun doc-view-bookmark-make-cell (annotation &rest args) | 1043 | (defun doc-view-bookmark-make-cell (annotation &rest args) |
| 1005 | (let ((the-record | 1044 | (let ((the-record |
| 1006 | `((filename . ,(buffer-file-name)) | 1045 | `((filename . ,buffer-file-name) |
| 1007 | (page . ,doc-view-current-page) | 1046 | (page . ,doc-view-current-page) |
| 1008 | (handler . doc-view-bookmark-jump)))) | 1047 | (handler . doc-view-bookmark-jump)))) |
| 1009 | 1048 | ||