;;; doc-view.el --- View PDF/PostScript/DVI files in Emacs -*- lexical-binding: t -*-
-;; Copyright (C) 2007-2014 Free Software Foundation, Inc.
+;; Copyright (C) 2007-2016 Free Software Foundation, Inc.
;;
;; Author: Tassilo Horn <tsdh@gnu.org>
;; Maintainer: Tassilo Horn <tsdh@gnu.org>
(require 'dired)
(require 'image-mode)
(require 'jka-compr)
+(require 'subr-x)
;;;; Customization Options
;; Don't do it if there's a conversion is running, since in that case, it
;; will be done later.
(with-selected-window (car winprops)
- (doc-view-goto-page 1)))))
+ (doc-view-goto-page (image-mode-window-get 'page t))))))
(defvar-local doc-view--current-files nil
"Only used internally.")
(define-key map "H" 'doc-view-fit-height-to-window)
(define-key map "P" 'doc-view-fit-page-to-window)
;; Killing the buffer (and the process)
- (define-key map (kbd "k") 'doc-view-kill-proc-and-buffer)
(define-key map (kbd "K") 'doc-view-kill-proc)
;; Slicing the image
(define-key map (kbd "s s") 'doc-view-set-slice)
(defun doc-view-revert-buffer (&optional ignore-auto noconfirm)
"Like `revert-buffer', but preserves the buffer's current modes."
- ;; FIXME: this should probably be moved to files.el and used for
- ;; most/all "g" bindings to revert-buffer.
(interactive (list (not current-prefix-arg)))
- (revert-buffer ignore-auto noconfirm 'preserve-modes))
+ (cl-labels ((revert ()
+ (let (revert-buffer-function)
+ (revert-buffer ignore-auto noconfirm 'preserve-modes))))
+ (if (and (eq 'pdf doc-view-doc-type)
+ (executable-find "pdfinfo"))
+ ;; We don't want to revert if the PDF file is corrupted which
+ ;; might happen when it it currently recompiled from a tex
+ ;; file. (TODO: We'd like to have something like that also
+ ;; for other types, at least PS, but I don't know a good way
+ ;; to test if a PS file is complete.)
+ (if (= 0 (call-process (executable-find "pdfinfo") nil nil nil
+ doc-view--buffer-file-name))
+ (revert)
+ (when (called-interactively-p 'interactive)
+ (message "Can't revert right now because the file is corrupted.")))
+ (revert))))
(easy-menu-define doc-view-menu doc-view-mode-map
(image-bob)
(image-bol 1))
(set-window-hscroll (selected-window) hscroll)))
- (image-next-line 1)))
+ (image-next-line arg)))
(defun doc-view-previous-line-or-previous-page (&optional arg)
"Scroll downward by ARG lines if possible, else goto previous page.
(setq doc-view--current-timer nil))
(setq mode-line-process nil))
-(defun doc-view-kill-proc-and-buffer ()
- "Kill the current converter process and buffer."
- (interactive)
- (doc-view-kill-proc)
- (when (eq major-mode 'doc-view-mode)
- (kill-buffer (current-buffer))))
+(define-obsolete-function-alias 'doc-view-kill-proc-and-buffer
+ #'image-kill-buffer "25.1")
(defun doc-view-make-safe-dir (dir)
(condition-case nil
- (let ((umask (default-file-modes)))
- (unwind-protect
- (progn
- ;; Create temp files with strict access rights. It's easy to
- ;; loosen them later, whereas it's impossible to close the
- ;; time-window of loose permissions otherwise.
- (set-default-file-modes #o0700)
- (make-directory dir))
- ;; Reset the umask.
- (set-default-file-modes umask)))
+ ;; Create temp files with strict access rights. It's easy to
+ ;; loosen them later, whereas it's impossible to close the
+ ;; time-window of loose permissions otherwise.
+ (with-file-modes #o0700 (make-directory dir))
(file-already-exists
(when (file-symlink-p dir)
(error "Danger: %s points to a symbolic link" dir))
(setq doc-view--current-cache-dir
(file-name-as-directory
(expand-file-name
- (concat (subst-char-in-string ?% ?_ ;; bug#13679
- (file-name-nondirectory doc-view--buffer-file-name))
- "-"
- (let ((file doc-view--buffer-file-name))
- (with-temp-buffer
- (set-buffer-multibyte nil)
- (insert-file-contents-literally file)
- (md5 (current-buffer)))))
+ (concat (thread-last
+ (file-name-nondirectory doc-view--buffer-file-name)
+ ;; bug#13679
+ (subst-char-in-string ?% ?_)
+ ;; arc-mode concatenates archive name and file name
+ ;; with colon, which isn't allowed on MS-Windows.
+ (subst-char-in-string ?: ?_))
+ "-"
+ (let ((file doc-view--buffer-file-name))
+ (with-temp-buffer
+ (set-buffer-multibyte nil)
+ (insert-file-contents-literally file)
+ (md5 (current-buffer)))))
doc-view-cache-directory)))))
;;;###autoload
(doc-view-start-process "odf->pdf" doc-view-odf->pdf-converter-program
(list
(concat "-env:UserInstallation=file://"
+ ;; The URL must be
+ ;; file:///C:/tmp/dir on Windows.
+ ;; https://wiki.documentfoundation.org/UserProfile.
+ (when (eq system-type 'windows-nt)
+ "/")
tmp-user-install-dir)
"--headless" "--convert-to" "pdf"
"--outdir" (doc-view--current-cache-dir) odf)
(tooltip-show (doc-view-current-info)))
(defun doc-view-open-text ()
- "Open a buffer with the current doc's contents as text."
+ "Display the current doc's contents as text."
(interactive)
(if doc-view--current-converter-processes
(message "DocView: please wait till conversion finished.")
(let ((txt (expand-file-name "doc.txt" (doc-view--current-cache-dir))))
(if (file-readable-p txt)
- (let ((name (concat "Text contents of "
- (file-name-nondirectory buffer-file-name)))
- (dir (file-name-directory buffer-file-name)))
- (with-current-buffer (find-file txt)
- (rename-buffer name)
- (setq default-directory dir)))
+ (let ((inhibit-read-only t)
+ (buffer-undo-list t)
+ (dv-bfn doc-view--buffer-file-name))
+ (erase-buffer)
+ (set-buffer-multibyte t)
+ (insert-file-contents txt)
+ (text-mode)
+ (setq-local doc-view--buffer-file-name dv-bfn)
+ (set-buffer-modified-p nil)
+ (doc-view-minor-mode)
+ (add-hook 'write-file-functions
+ (lambda ()
+ (when (eq major-mode 'text-mode)
+ (error "Cannot save text contents of document %s"
+ buffer-file-name)))
+ nil t))
(doc-view-doc->txt txt 'doc-view-open-text)))))
;;;;; Toggle between editing and viewing
(defun doc-view-toggle-display ()
"Toggle between editing a document as text or viewing it."
(interactive)
- (if (eq major-mode 'doc-view-mode)
- ;; Switch to editing mode
- (progn
- (doc-view-kill-proc)
- (setq buffer-read-only nil)
- ;; Switch to the previously used major mode or fall back to
- ;; normal mode.
- (doc-view-fallback-mode)
- (doc-view-minor-mode 1))
+ (cond
+ ((eq major-mode 'doc-view-mode)
+ ;; Switch to editing mode
+ (doc-view-kill-proc)
+ (setq buffer-read-only nil)
+ ;; Switch to the previously used major mode or fall back to
+ ;; normal mode.
+ (doc-view-fallback-mode)
+ (doc-view-minor-mode 1))
+ ((eq major-mode 'text-mode)
+ (let ((buffer-undo-list t))
+ ;; We're currently viewing the document's text contents, so switch
+ ;; back to .
+ (setq buffer-read-only nil)
+ (insert-file-contents doc-view--buffer-file-name nil nil nil t)
+ (doc-view-fallback-mode)
+ (doc-view-minor-mode 1)
+ (set-buffer-modified-p nil)))
+ (t
;; Switch to doc-view-mode
(when (and (buffer-modified-p)
(y-or-n-p "The buffer has been modified. Save the changes? "))
(save-buffer))
- (doc-view-mode)))
+ (doc-view-mode))))
;;;; Searching
(concat "No PNG support is available, or some conversion utility for "
(file-name-extension doc-view--buffer-file-name)
" files is missing."))
- (when (and (executable-find doc-view-pdftotext-program)
- (y-or-n-p
- "Unable to render file. View extracted text instead? "))
- (doc-view-open-text))
- (doc-view-toggle-display)))
+ (if (and (executable-find doc-view-pdftotext-program)
+ (y-or-n-p
+ "Unable to render file. View extracted text instead? "))
+ (doc-view-open-text)
+ (doc-view-toggle-display))))
(defvar bookmark-make-record-function)
"Figure out the current document type (`doc-view-doc-type')."
(let ((name-types
(when buffer-file-name
- (cdr (assoc (file-name-extension buffer-file-name)
- '(
- ;; DVI
- ("dvi" dvi)
- ;; PDF
- ("pdf" pdf) ("epdf" pdf)
- ;; PostScript
- ("ps" ps) ("eps" ps)
- ;; DjVu
- ("djvu" djvu)
- ;; OpenDocument formats
- ("odt" odf) ("ods" odf) ("odp" odf) ("odg" odf)
- ("odc" odf) ("odi" odf) ("odm" odf) ("ott" odf)
- ("ots" odf) ("otp" odf) ("otg" odf)
- ;; Microsoft Office formats (also handled
- ;; by the odf conversion chain)
- ("doc" odf) ("docx" odf) ("xls" odf) ("xlsx" odf)
- ("ppt" odf) ("pptx" odf))))))
+ (cdr (assoc-string
+ (file-name-extension buffer-file-name)
+ '(
+ ;; DVI
+ ("dvi" dvi)
+ ;; PDF
+ ("pdf" pdf) ("epdf" pdf)
+ ;; PostScript
+ ("ps" ps) ("eps" ps)
+ ;; DjVu
+ ("djvu" djvu)
+ ;; OpenDocument formats.
+ ("odt" odf) ("ods" odf) ("odp" odf) ("odg" odf)
+ ("odc" odf) ("odi" odf) ("odm" odf) ("ott" odf)
+ ("ots" odf) ("otp" odf) ("otg" odf)
+ ;; Microsoft Office formats (also handled by the odf
+ ;; conversion chain).
+ ("doc" odf) ("docx" odf) ("xls" odf) ("xlsx" odf)
+ ("ppt" odf) ("pps" odf) ("pptx" odf) ("rtf" odf))
+ t))))
(content-types
(save-excursion
(goto-char (point-min))
;; desktop.el integration
(defun doc-view-desktop-save-buffer (_desktop-dirname)
+ ;; FIXME: This is wrong, since this info is per-window but we only do it once
+ ;; here for the buffer. IOW it should be saved via something like
+ ;; `window-persistent-parameters'.
`((page . ,(doc-view-current-page))
(slice . ,(doc-view-current-slice))))
(let ((page (cdr (assq 'page misc)))
(slice (cdr (assq 'slice misc))))
(desktop-restore-file-buffer file name misc)
+ ;; FIXME: We need to run this code after displaying the buffer.
(with-selected-window (or (get-buffer-window (current-buffer) 0)
(selected-window))
+ ;; FIXME: This should be done for all windows restored that show
+ ;; this buffer. Basically, the page/slice should be saved as
+ ;; window-parameters in the window-state(s) and then restoring this
+ ;; window-state should call us back (to interpret/use those parameters).
(doc-view-goto-page page)
- (when slice (apply 'doc-view-set-slice slice)))))
+ (when slice (apply 'doc-view-set-slice slice))
+ (current-buffer))))
(add-to-list 'desktop-buffer-mode-handlers
'(doc-view-mode . doc-view-restore-desktop-buffer))
(when (not (string= doc-view--buffer-file-name buffer-file-name))
(write-region nil nil doc-view--buffer-file-name))
+ (setq-local revert-buffer-function #'doc-view-revert-buffer)
+
(add-hook 'change-major-mode-hook
(lambda ()
(doc-view-kill-proc)
nil t)
(add-hook 'clone-indirect-buffer-hook 'doc-view-clone-buffer-hook nil t)
(add-hook 'kill-buffer-hook 'doc-view-kill-proc nil t)
- (when (and (boundp 'desktop-save-mode)
- desktop-save-mode)
- (setq-local desktop-save-buffer 'doc-view-desktop-save-buffer))
+ (setq-local desktop-save-buffer 'doc-view-desktop-save-buffer)
(remove-overlays (point-min) (point-max) 'doc-view t) ;Just in case.
;; Keep track of display info ([vh]scroll, page number, overlay,