From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: Tassilo Horn Newsgroups: gmane.emacs.devel Subject: Re: Would someone please install doc-view.el? Date: Fri, 07 Sep 2007 15:30:44 +0200 Message-ID: <87ir6mvbzv.fsf@baldur.tsdh.de> References: <87myvyenxg.fsf@baldur.tsdh.de> <20070907123250.GB22265@saeurebad.de> NNTP-Posting-Host: lo.gmane.org Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Trace: sea.gmane.org 1189171871 24651 80.91.229.12 (7 Sep 2007 13:31:11 GMT) X-Complaints-To: usenet@sea.gmane.org NNTP-Posting-Date: Fri, 7 Sep 2007 13:31:11 +0000 (UTC) To: emacs-devel@gnu.org Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Fri Sep 07 15:31:11 2007 Return-path: Envelope-to: ged-emacs-devel@m.gmane.org Original-Received: from lists.gnu.org ([199.232.76.165]) by lo.gmane.org with esmtp (Exim 4.50) id 1ITdvG-0001VY-7Y for ged-emacs-devel@m.gmane.org; Fri, 07 Sep 2007 15:30:59 +0200 Original-Received: from localhost ([127.0.0.1] helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1ITdvE-0000RM-AP for ged-emacs-devel@m.gmane.org; Fri, 07 Sep 2007 09:30:56 -0400 Original-Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1ITdvB-0000QV-L5 for emacs-devel@gnu.org; Fri, 07 Sep 2007 09:30:53 -0400 Original-Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1ITdv8-0000LT-S6 for emacs-devel@gnu.org; Fri, 07 Sep 2007 09:30:53 -0400 Original-Received: from [199.232.76.173] (helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1ITdv8-0000LI-Ku for emacs-devel@gnu.org; Fri, 07 Sep 2007 09:30:50 -0400 Original-Received: from out2.smtp.messagingengine.com ([66.111.4.26]) by monty-python.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1ITdv7-0000kn-E5 for emacs-devel@gnu.org; Fri, 07 Sep 2007 09:30:49 -0400 Original-Received: from compute2.internal (compute2.internal [10.202.2.42]) by out1.messagingengine.com (Postfix) with ESMTP id 10CDA2A0F0 for ; Fri, 7 Sep 2007 09:30:49 -0400 (EDT) Original-Received: from heartbeat2.messagingengine.com ([10.202.2.161]) by compute2.internal (MEProxy); Fri, 07 Sep 2007 09:30:49 -0400 X-Sasl-enc: JrvoQy5KwU3hLT63t3F0HkLPfT82Oi0IhfzdFEKkI2YM 1189171847 Original-Received: from baldur.tsdh.de (dslb-084-063-044-077.pools.arcor-ip.net [84.63.44.77]) by mail.messagingengine.com (Postfix) with ESMTP id BA93522C74 for ; Fri, 7 Sep 2007 09:30:46 -0400 (EDT) Face: iVBORw0KGgoAAAANSUhEUgAAADAAAAAwBAMAAAClLOS0AAAAD1BMVEW2mhnYvEn26qD+/vbC t5CEWCLiAAAACXBIWXMAAAsSAAALEgHS3X78AAAATnRFWHRSYXcgcHJvZmlsZSB0eXBlIGV4aWYA CmV4aWYKICAgICAgMjAKNDU3ODY5NjYwMDAwNGQ0ZDAwMmEwMDAwMDAwODAwMDAwMDAwMDAwMAqJ uBZbAAAACXZwQWcAAAAwAAAAMADO7oxXAAABkElEQVQ4y3WTDZLCIAyFQ08A6AFK0gNowgG6de9/ pn2Bau22ZRyF+ZKXX8lOjqZs1K9i+gUmStKAxmzTsjlECtwBEUfKb1CJKDvQkfwEWUFZCsD0shpi I8MbZAWoQWNI+KS3S2VhACaolwSAXzGkUD0ok7q4liwID4vFJAGEG1DIorDV4pGmXBCKka7GJPb0 ItwlIMHsHkJQMftlPKQQIVDA+wmAXgi70pg5pTyiGwC5t2SCw0LBOHNJ3oDH2sQf2CciETXNMLKx A82IhtCtbV6kQsJfT+aYuJB8+jtIA/OQiK3QNpDUgZeMtDYA7QZQl0fsUn6rK4heE+I36+WFvnMH paVobYJ6l5Ztr0M+IlgQr0vMvlKRPj0X5R1oDuXmXnICpDV9B6ooeugX//oCs2ry8dlzDyCASd2O HtNg2CC/jbwDMybYd24PoMSx8HugG3gMUoZtIhuYuRV3ANXX8XUCvIBRjkDjDStgR1CD/PuDrmDM dg7i6xwclVZQDkoriHwB7nYBlgugcgXsSurk/AEJvb3wF7X09QAAABp6VFh0anBlZzpjb2xvcnNw YWNlAAB42jMCAAAzADOJOCM1AAAAJnpUWHRqcGVnOnNhbXBsaW5nLWZhY3RvcgAAeNozqjDSMaww BGEAEYMC6T2XL08AAAAASUVORK5CYII= Mail-Followup-To: emacs-devel@gnu.org In-Reply-To: <20070907123250.GB22265@saeurebad.de> (Johannes Weiner's message of "Fri, 7 Sep 2007 14:32:50 +0200") User-Agent: Gnus/5.110007 (No Gnus v0.7) Emacs/23.0.50 (gnu/linux) X-Detected-Kernel: Genre and OS details not recognized. X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Original-Sender: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Xref: news.gmane.org gmane.emacs.devel:78152 Archived-At: --=-=-= Johannes Weiner writes: Hi Johannes, > However, I want to ask you if it is possible to change the bindings of > doc-view-next-page and doc-view-previous-page. They are somehow > exchanged with scroll-up and scroll-down, at least I tried the keys > the other way round intuitively. Why? C-v/M-v is scroll-up/scroll-down almost everywhere in emacs, so I think it's the right thing to bind them in doc-view.el accordingly. > What do you think of > > C-v for scroll-down-or-next-page > M-v for scroll-up-or-previous-page These functions don't exist, you probably mean `doc-view-scroll-up-or-next-page' and `doc-view-scroll-down-or-previous-page'. These are bound to SPC and DEL because that's the same binding other pdf viewers like xpdf use. > C-n for next-line (bound by default) > C-p for previous-line (bound by default) Ok, for those I agree. Here's a changed version. --=-=-= Content-Type: application/emacs-lisp Content-Disposition: attachment; filename=doc-view.el Content-Transfer-Encoding: quoted-printable Content-Description: doc-view.el with adapted key bindings ;;; doc-view.el --- View PDF/PostScript/DVI files in Emacs ;; Copyright (C) 2007 Free Software Foundation, Inc. ;; ;; Author: Tassilo Horn ;; Maintainer: Tassilo Horn ;; Keywords: files, pdf, ps, dvi ;; Version: <2007-09-07 Fri 15:28> ;; This file is part of GNU Emacs. ;; GNU Emacs is free software; you can redistribute it and/or modify it und= er ;; the terms of the GNU General Public License as published by the Free ;; Software Foundation; either version 3, or (at your option) any later ;; version. ;; GNU Emacs is distributed in the hope that it will be useful, but WITHOUT= ANY ;; WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS ;; FOR A PARTICULAR PURPOSE. See the GNU General Public License for more ;; details. ;; You should have received a copy of the GNU General Public License along = with ;; GNU Emacs; see the file COPYING. If not, write to the Free Software ;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, ;; USA. ;;; Requirements: ;; doc-view.el requires GNU Emacs 22.1 or newer. You also need GhostScript, ;; `dvipdfm' which comes with TeTeX and `pdftotext', which comes with poppl= er ;; (http://poppler.freedesktop.org/). ;;; Commentary: ;; DocView is a document viewer for Emacs. It converts PDF, PS and DVI fil= es ;; to a set of PNG files, one PNG for each page, and displays the PNG images ;; inside an Emacs buffer. This buffer uses `doc-view-mode' which provides ;; convenient key bindings for browsing the document. ;; ;; To use it simply do ;; ;; M-x doc-view RET ;; ;; and you'll be queried for a document to open. ;; ;; Since conversion may take some time all the PNG images are cached in a ;; subdirectory of `doc-view-cache-directory' and reused when you want to v= iew ;; that file again. This reusing can be omitted if you provide a prefx ;; argument to `doc-view'. To delete all cached files use ;; `doc-view-clear-cache'. To open the cache with dired, so that you can t= idy ;; it out use `doc-view-dired-cache'. ;; ;; When conversion in underway the first page will be displayed as soon as = it ;; is available and the available pages are refreshed every ;; `doc-view-conversion-refresh-interval' seconds. If that variable is nil= the ;; pages won't be displayed before conversion of the document finished ;; completely. ;; ;; DocView lets you select a slice of the displayed pages. This slice will= be ;; remembered and applied to all pages of the current document. This enabl= es ;; you to cut away the margins of a document to save some space. To select= a ;; slice you can use `doc-view-set-slice' (bound to `s s') which will query= you ;; for the coordinates of the slice's top-left corner and its width and hei= ght. ;; A much more convenient way to do the same is offered by the command ;; `doc-view-set-slice-using-mouse' (bound to `s m'). After invokation you ;; only have to press mouse-1 at the top-left corner and drag it to the ;; bottom-right corner of the desired slice. To reset the slice use ;; `doc-view-reset-slice' (bound to `s r'). ;; ;; Dired users should have a look at `doc-view-dired'. ;; ;; You can also search within the document. The command `doc-view-search' ;; (bound to `C-s') queries for a search regexp and initializes a list of a= ll ;; matching pages and messages how many match-pages were found. After that= you ;; can jump to the next page containing a match with ;; `doc-view-search-next-match' (bound to `C-S-n') or to the previous match= ing ;; page with `doc-view-search-previous-match' (bound to `C-S-p'). This wor= ks ;; by searching a plain text representation of the document. If that doesn= 't ;; already exist the first invokation of `doc-view-search' starts the ;; conversion. When that finishes and you're still viewing the document ;; (i.e. you didn't switch to another buffer) you're queried for the regexp ;; then. ;;; Configuration: ;; Basically doc-view should be quite usable with its standard settings, so ;; putting ;; ;; (require 'doc-view) ;; ;; into your `user-init-file' should be enough. If the images are too smal= l or ;; too big you should set the "-rXXX" option in `doc-view-ghostscript-optio= ns' ;; to another value. (The bigger your screen, the higher the value.) ;; ;; This and all other options can be set with the customization interface. ;; Simply do ;; ;; M-x customize-group RET doc-view RET ;; ;; and modify them to your needs. ;;; Code: (require 'dired) (eval-when-compile (require 'cl)) ;;;; Customization Options (defgroup doc-view nil "In-buffer viewer for PDF, PostScript and DVI files." :link '(function-link doc-view) :version "22.2" :group 'applications :group 'multimedia :prefix "doc-view-") (defcustom doc-view-ghostscript-program "gs" "Program to convert PS and PDF files to PNG." :type '(file) :group 'doc-view) (defcustom doc-view-ghostscript-options '("-dNOPAUSE" "-sDEVICE=3Dpng16m" "-dTextAlphaBits=3D4" "-dBATCH" "-dGraphicsAlphaBits=3D4" "-dQUIET" "-r100") "A list of options to give to ghostview." :type '(sexp) :group 'doc-view) (defcustom doc-view-dvipdfm-program "dvipdfm" "Program to convert DVI files to PDF. DVI file will be converted to PDF before the resulting PDF is converted to PNG." :type '(file) :group 'doc-view) (defcustom doc-view-ps2pdf-program "ps2pdf" "Program to convert PS files to PDF. PS files will be converted to PDF before searching is possible." :type '(file) :group 'doc-view) (defcustom doc-view-pdftotext-program "pdftotext" "Program to convert PDF files to plain text. Needed for searching." :type '(file) :group 'doc-view) (defcustom doc-view-cache-directory (concat temporary-file-directory "doc-view") "The base directory, where the PNG images will be saved." :type '(directory) :group 'doc-view) (defcustom doc-view-conversion-buffer "*doc-view conversion output*" "The buffer where messages from the converter programs go to." :type '(string) :group 'doc-view) (defcustom doc-view-conversion-refresh-interval 3 "Every how much seconds the DocView buffer gets refreshed while conversio= n. After such an refresh newly converted pages will be available for viewing. If set to nil there won't be any refreshes and the pages won't be displayed before conversion of the whole document has finished." :type '(string) :group 'doc-view) ;;;; Internal Variables (defvar doc-view-current-files nil "Only used internally.") (defvar doc-view-current-page nil "Only used internally.") (defvar doc-view-current-doc nil "Only used internally.") (defvar doc-view-current-converter-process nil "Only used internally.") (defvar doc-view-current-timer nil "Only used internally.") (defvar doc-view-current-slice nil "Only used internally.") (defvar doc-view-current-cache-dir nil "Only used internally.") (defvar doc-view-current-search-matches nil "Only used internally.") (defvar doc-view-current-image nil "Only used internally.") (defvar doc-view-current-info nil "Only used internally.") ;;;; DocView Keymap (defvar doc-view-mode-map (let ((map (make-sparse-keymap))) ;; Navigation in the document (define-key map (kbd "n") 'doc-view-next-page) (define-key map (kbd "p") 'doc-view-previous-page) (define-key map (kbd "") 'doc-view-next-page) (define-key map (kbd "") 'doc-view-previous-page) (define-key map (kbd "SPC") 'doc-view-scroll-up-or-next-page) (define-key map (kbd "DEL") 'doc-view-scroll-down-or-previous-pag= e) (define-key map (kbd "M-<") 'doc-view-first-page) (define-key map (kbd "M->") 'doc-view-last-page) (define-key map (kbd "g") 'doc-view-goto-page) ;; Killing/burying the buffer (and the process) (define-key map (kbd "q") 'bury-buffer) (define-key map (kbd "k") 'doc-view-kill-proc-and-buffer) (define-key map (kbd "C-x k") 'doc-view-kill-proc-and-buffer) ;; Slicing the image (define-key map (kbd "s s") 'doc-view-set-slice) (define-key map (kbd "s m") 'doc-view-set-slice-using-mouse) (define-key map (kbd "s r") 'doc-view-reset-slice) ;; Searching (define-key map (kbd "C-s") 'doc-view-search) (define-key map (kbd "") 'doc-view-search) (define-key map (kbd "C-S-n") 'doc-view-search-next-match) (define-key map (kbd "C-S-p") 'doc-view-search-previous-match) ;; Scrolling (define-key map (kbd "C-v") 'scroll-up) (define-key map (kbd "") 'mwheel-scroll) (define-key map (kbd "") 'mwheel-scroll) (define-key map (kbd "M-v") 'scroll-down) ;; Show the tooltip (define-key map (kbd "C-t") 'doc-view-show-tooltip) (suppress-keymap map) map) "Keymap used by `doc-view-mode'.") ;;;; Navigation Commands (defun doc-view-goto-page (page) "View the page given by PAGE." (interactive "nPage: ") (let ((len (length doc-view-current-files))) (if (< page 1) (setq page 1) (when (> page len) (setq page len))) (setq doc-view-current-page page doc-view-current-info (concat (propertize (format "Page %d of %d." doc-view-current-page len) 'face 'bold) ;; Tell user if converting isn't finished yet (if doc-view-current-converter-process " (still converting...)\n" "\n") ;; Display context infos if this page matches the last search (when (and doc-view-current-search-matches (assq doc-view-current-page doc-view-current-search-matches)) (concat (propertize "Search matches:\n" 'face 'bold) (let ((contexts "")) (dolist (m (cdr (assq doc-view-current-page doc-view-current-search-matches))) (setq contexts (concat contexts " - \"" m "\"\n"))) contexts))))) ;; Update the buffer (setq inhibit-read-only t) (erase-buffer) (let ((beg (point))) (doc-view-insert-image (nth (1- page) doc-view-current-files) :pointer 'arrow) (put-text-property beg (point) 'help-echo doc-view-current-info)) (insert "\n" doc-view-current-info) (goto-char (point-min)) (forward-char) (setq inhibit-read-only nil))) (defun doc-view-next-page (&optional arg) "Browse ARG pages forward." (interactive "p") (doc-view-goto-page (+ doc-view-current-page (or arg 1)))) (defun doc-view-previous-page (&optional arg) "Browse ARG pages backward." (interactive "p") (doc-view-goto-page (- doc-view-current-page (or arg 1)))) (defun doc-view-first-page () "View the first page." (interactive) (doc-view-goto-page 1)) (defun doc-view-last-page () "View the last page." (interactive) (doc-view-goto-page (length doc-view-current-files))) (defun doc-view-scroll-up-or-next-page () "Scroll page up if possible, else goto next page." (interactive) (condition-case nil (scroll-up) (error (doc-view-next-page)))) (defun doc-view-scroll-down-or-previous-page () "Scroll page down if possible, else goto previous page." (interactive) (condition-case nil (scroll-down) (error (doc-view-previous-page) (goto-char (point-max))))) (defun doc-view-kill-proc-and-buffer () "Kill the current converter process and buffer." (interactive) (when (eq major-mode 'doc-view-mode) (when doc-view-current-converter-process (kill-process doc-view-current-converter-process)) (when doc-view-current-timer (cancel-timer doc-view-current-timer) (setq doc-view-current-timer nil)) (kill-buffer (current-buffer)))) ;;;; Conversion Functions (defun doc-view-file-name-to-directory-name (file) "Return the directory where the png files of FILE should be saved. It'a a subdirectory of `doc-view-cache-directory'." (if doc-view-current-cache-dir doc-view-current-cache-dir (file-name-as-directory (concat (file-name-as-directory doc-view-cache-directory) (with-temp-buffer (insert-file-contents-literally file) (md5 (current-buffer))))))) (defun doc-view-dvi->pdf-sentinel (proc event) "If DVI->PDF conversion was successful, convert the PDF to PNG now." (if (not (string-match "finished" event)) (message "DocView: dvi->pdf process changed status to %s." event) (set-buffer (process-get proc 'buffer)) (setq doc-view-current-converter-process nil) (message "DocView: finished conversion from DVI to PDF!") ;; Now go on converting this PDF to a set of PNG files. (let* ((pdf (process-get proc 'pdf-file)) (png (concat (doc-view-file-name-to-directory-name doc-view-current-doc) "page-%d.png"))) (doc-view-pdf/ps->png pdf png)))) (defun doc-view-dvi->pdf (dvi pdf) "Convert DVI to PDF asynchrounously." (message "DocView: converting DVI to PDF now!") (setq doc-view-current-converter-process (start-process "doc-view-dvi->pdf" doc-view-conversion-buffer doc-view-dvipdfm-program "-o" pdf dvi)) (set-process-sentinel doc-view-current-converter-process 'doc-view-dvi->pdf-sentinel) (process-put doc-view-current-converter-process 'buffer (current-buffer= )) (process-put doc-view-current-converter-process 'pdf-file pdf)) (defun doc-view-pdf/ps->png-sentinel (proc event) "If PDF/PS->PNG conversion was successful, update the display." (if (not (string-match "finished" event)) (message "DocView: converter process changed status to %s." event) (set-buffer (process-get proc 'buffer)) (setq doc-view-current-converter-process nil) (when doc-view-current-timer (cancel-timer doc-view-current-timer) (setq doc-view-current-timer nil)) (message "DocView: finished conversion from PDF/PS to PNG!") ;; Yippie, finished. Update the display! (doc-view-display doc-view-current-doc))) (defun doc-view-pdf/ps->png (pdf-ps png) "Convert PDF-PS to PNG asynchrounously." (message "DocView: converting PDF or PS to PNG now!") (setq doc-view-current-converter-process (apply 'start-process (append (list "doc-view-pdf/ps->png" doc-view-conversion-buffer doc-view-ghostscript-program) doc-view-ghostscript-options (list (concat "-sOutputFile=3D" png)) (list pdf-ps)))) (process-put doc-view-current-converter-process 'buffer (current-buffer)) (set-process-sentinel doc-view-current-converter-process 'doc-view-pdf/ps->png-sentinel) (when doc-view-conversion-refresh-interval (setq doc-view-current-timer (run-at-time "1 secs" doc-view-conversion-refresh-interval 'doc-view-display doc-view-current-doc)))) (defun doc-view-pdf->txt-sentinel (proc event) (if (not (string-match "finished" event)) (message "DocView: converter process changed status to %s." event) (let ((current-buffer (current-buffer)) (proc-buffer (process-get proc 'buffer))) (set-buffer proc-buffer) (setq doc-view-current-converter-process nil) (message "DocView: finished conversion from PDF to TXT!") ;; If the user looks at the DocView buffer where the conversion was ;; performed, search anew. This time it will be queried for a regexp. (when (eq current-buffer proc-buffer) (doc-view-search))))) (defun doc-view-pdf->txt (pdf txt) "Convert PDF to TXT asynchrounously." (message "DocView: converting PDF to TXT now!") (setq doc-view-current-converter-process (start-process "doc-view-pdf->txt" doc-view-conversion-buffer doc-view-pdftotext-program "-raw" pdf txt)) (set-process-sentinel doc-view-current-converter-process 'doc-view-pdf->txt-sentinel) (process-put doc-view-current-converter-process 'buffer (current-buffer))) (defun doc-view-ps->pdf-sentinel (proc event) (if (not (string-match "finished" event)) (message "DocView: converter process changed status to %s." event) (set-buffer (process-get proc 'buffer)) (setq doc-view-current-converter-process nil) (message "DocView: finished conversion from PS to PDF!") ;; Now we can transform to plain text. (doc-view-pdf->txt (process-get proc 'pdf-file) (concat (doc-view-file-name-to-directory-name doc-view-current-doc) "doc.txt")))) (defun doc-view-ps->pdf (ps pdf) "Convert PS to PDF asynchronously." (message "DocView: converting PS to PDF now!") (setq doc-view-current-converter-process (start-process "doc-view-ps->pdf" doc-view-conversion-buffer doc-view-ps2pdf-program ps pdf)) (set-process-sentinel doc-view-current-converter-process 'doc-view-ps->pdf-sentinel) (process-put doc-view-current-converter-process 'buffer (current-buffer= )) (process-put doc-view-current-converter-process 'pdf-file pdf)) (defun doc-view-convert-doc (doc) "Convert DOC to a set of png files, one file per page. Those files are saved in the directory given by `doc-view-file-name-to-directory-name'." (clear-image-cache) (let* ((dir (doc-view-file-name-to-directory-name doc)) (png-file (concat (file-name-as-directory dir) "page-%d.png"))) (when (file-exists-p dir) (dired-delete-file dir 'always)) (make-directory dir t) (if (not (string=3D (file-name-extension doc) "dvi")) ;; Convert to PNG images. (doc-view-pdf/ps->png doc png-file) ;; DVI files have to be converted to PDF before GhostScript can proce= ss ;; it. (doc-view-dvi->pdf doc (concat (file-name-as-directory dir) "doc.pdf"))))) ;;;; DocView Mode (define-derived-mode doc-view-mode nil "DocView" "Major mode in DocView buffers. \\{doc-view-mode-map}" :group 'doc-view (setq buffer-read-only t) (make-local-variable 'doc-view-current-files) (make-local-variable 'doc-view-current-doc) (make-local-variable 'doc-view-current-image) (make-local-variable 'doc-view-current-page) (make-local-variable 'doc-view-current-converter-process) (make-local-variable 'doc-view-current-timer) (make-local-variable 'doc-view-current-slice) (make-local-variable 'doc-view-current-cache-dir) (make-local-variable 'doc-view-current-info) (make-local-variable 'doc-view-current-search-matches)) ;;;; Slicing (defun doc-view-set-slice (x y width height) "Set the slice of the images that should be displayed. You can use this function to tell doc-view not to display the margins of the document. It prompts for the top-left corner (X and Y) of the slice to display and its WIDTH and HEIGHT. See `doc-view-set-slice-using-mouse' for a more convenient way to do that. To reset the slice use `doc-view-reset-slice'." (interactive (let* ((size (image-size doc-view-current-image t)) (a (read-number (format "Top-left X (0..%d): " (car size)))) (b (read-number (format "Top-left Y (0..%d): " (cdr size)))) (c (read-number (format "Width (0..%d): " (- (car size) a)))) (d (read-number (format "Height (0..%d): " (- (cdr size) b))))) (list a b c d))) (setq doc-view-current-slice (list x y width height)) ;; Redisplay (doc-view-goto-page doc-view-current-page)) (defun doc-view-set-slice-using-mouse () "Set the slice of the images that should be displayed. You set the slice by pressing mouse-1 at its top-left corner and dragging it to its bottom-right corner. See also `doc-view-set-slice' and `doc-view-reset-slice'." (interactive) (let (x y w h done) (while (not done) (let ((e (read-event (concat "Press mouse-1 at the top-left corner and " "drag it to the bottom-right corner!")))) (when (eq (car e) 'drag-mouse-1) (setq x (car (posn-object-x-y (event-start e)))) (setq y (cdr (posn-object-x-y (event-start e)))) (setq w (- (car (posn-object-x-y (event-end e))) x)) (setq h (- (cdr (posn-object-x-y (event-end e))) y)) (setq done t)))) (doc-view-set-slice x y w h))) (defun doc-view-reset-slice () "Resets the current slice. After calling this function the whole pages will be visible again." (interactive) (setq doc-view-current-slice nil) ;; Redisplay (doc-view-goto-page doc-view-current-page)) ;;;; Display (defun doc-view-insert-image (file &rest args) "Insert the given png FILE. ARGs is a list of image descriptors." (let ((image (apply 'create-image file 'png nil args))) (setq doc-view-current-image image) (insert-image image (concat "[" file "]") nil doc-view-current-slice))) (defun doc-view-sort (a b) "Return non-nil if A should be sorted before B. Predicate for sorting `doc-view-current-files'." (if (< (length a) (length b)) t (if (> (length a) (length b)) nil (string< a b)))) (defun doc-view-display (doc) "Start viewing the document DOC." (let ((dir (doc-view-file-name-to-directory-name doc))) (set-buffer (format "*DocView: %s*" doc)) (setq doc-view-current-files (sort (directory-files dir t "page-[0-9]+\\.png" t) 'doc-view-sort)) (when (> (length doc-view-current-files) 0) (doc-view-goto-page doc-view-current-page)))) (defun doc-view-buffer-message () (setq inhibit-read-only t) (erase-buffer) (insert (propertize "Welcome to DocView!" 'face 'bold) "\n" " If you see this buffer it means that the document you want to view gets converted to PNG now and the conversion of the first page hasn't finished yet or `doc-view-conversion-refresh-interval' is set to nil. For now these keys are useful: `q' : Bury this buffer. Conversion will go on in background. `k' : Kill the conversion process and this buffer.\n") (setq inhibit-read-only nil)) (defun doc-view-show-tooltip () (interactive) (tooltip-show doc-view-current-info)) ;;;; Searching (defun doc-view-search-internal (regexp file) "Return a list of FILE's pages that contain text matching REGEXP. The value is an alist of the form (PAGE CONTEXTS) where PAGE is the pagenumber and CONTEXTS are the lines containing the match." (with-temp-buffer (insert-file-contents file) (let ((page 1) (lastpage 1) matches) (while (re-search-forward (concat "\\(?:\\([ ]\\)\\|\\(" regexp "\\)\\)") nil t) (when (match-string 1) (incf page)) (when (match-string 2) (if (/=3D page lastpage) (setq matches (push (cons page (list (buffer-substring (line-beginning-position) (line-end-position)))) matches)) (setq matches (cons (append (or (car matches) ; this page already is a match (list page)) ; this is the first match on page (list (buffer-substring (line-beginning-position) (line-end-position)))) (cdr matches)))) (setq lastpage page))) (nreverse matches)))) (defun doc-view-search-no-of-matches (list) "Extract the number of matches from the search result LIST." (let ((no 0)) (dolist (p list) (setq no (+ no (1- (length p))))) no)) (defun doc-view-search () "Query for a regexp and search the current document. If the current document hasn't been transformed to plain text till now do that first. You should try searching anew when the conversion finished." (interactive) ;; New search, so forget the old results. (setq doc-view-current-search-matches nil) (let ((txt (concat (doc-view-file-name-to-directory-name doc-view-current-doc) "doc.txt"))) (if (file-readable-p txt) (progn (setq doc-view-current-search-matches (doc-view-search-internal (read-from-minibuffer "Regexp: ") txt)) (message "DocView: search yielded %d matches." (doc-view-search-no-of-matches doc-view-current-search-matches))) ;; We must convert to TXT first! (if doc-view-current-converter-process (message "DocView: please wait till conversion finished.") (let ((ext (file-name-extension doc-view-current-doc))) (cond ((string=3D ext "pdf") ;; Doc is a PDF, so convert it to TXT (doc-view-pdf->txt doc-view-current-doc txt)) ((string=3D ext "ps") ;; Doc is a PS, so convert it to PDF (which will be converted to ;; TXT thereafter). (doc-view-ps->pdf doc-view-current-doc (concat (doc-view-file-name-to-directory-name doc-view-current-doc) "doc.pdf"))) ((string=3D ext "dvi") ;; Doc is a DVI. This means that a doc.pdf already exists in its ;; cache subdirectory. (doc-view-pdf->txt (concat (doc-view-file-name-to-directory-name doc-view-current-doc) "doc.pdf") txt)) (t (error "DocView doesn't know what to do")))))))) (defun doc-view-search-next-match (arg) "Go to the ARGth next matching page." (interactive "p") (let* ((next-pages (remove-if (lambda (i) (<=3D (car i) doc-view-current-= page)) doc-view-current-search-matches)) (page (car (nth (1- arg) next-pages)))) (if page (doc-view-goto-page page) (when (and doc-view-current-search-matches (y-or-n-p "No more matches after current page. Wrap to first match? = ")) (doc-view-goto-page (caar doc-view-current-search-matches)))))) (defun doc-view-search-previous-match (arg) "Go to the ARGth previous matching page." (interactive "p") (let* ((prev-pages (remove-if (lambda (i) (>=3D (car i) doc-view-current-= page)) doc-view-current-search-matches)) (page (car (nth (1- arg) (nreverse prev-pages))))) (if page (doc-view-goto-page page) (when (and doc-view-current-search-matches (y-or-n-p "No more matches before current page. Wrap to last match? = ")) (doc-view-goto-page (caar (last doc-view-current-search-matches))))))) ;;;; User Interface Commands (defun doc-view (no-cache &optional file) "Convert FILE to png and start viewing it. If no FILE is given, query for on. If this FILE is still in the cache, don't convert and use the existing page files. With prefix arg NO-CACHE, don't use the cached files and convert anew." (interactive "P") (if (not (and (image-type-available-p 'png) (display-images-p))) (message "DocView: your emacs or display doesn't support png images.") (let* ((doc (or file (expand-file-name (read-file-name "File: " nil nil t)))) (buffer (get-buffer-create (format "*DocView: %s*" doc))) (dir (doc-view-file-name-to-directory-name doc))) (switch-to-buffer buffer) (doc-view-buffer-message) (doc-view-mode) (setq doc-view-current-doc doc) (setq doc-view-current-page 1) (if (not (and (file-exists-p dir) (not no-cache))) (progn (setq doc-view-current-cache-dir nil) (doc-view-convert-doc doc-view-current-doc)) (message "DocView: using cached files!") (doc-view-display doc-view-current-doc))))) (defun doc-view-dired (no-cache) "View the current dired file with doc-view. NO-CACHE is the same as in `doc-view'. You might want to bind this command to a dired key, e.g. (define-key dired-mode-map (kbd \"C-c d\") 'doc-view-dired)" (interactive "P") (doc-view no-cache (dired-get-file-for-visit))) (defun doc-view-clear-cache () "Delete the whole cache (`doc-view-cache-directory')." (interactive) (dired-delete-file doc-view-cache-directory 'always) (make-directory doc-view-cache-directory)) (defun doc-view-dired-cache () "Open `dired' in `doc-view-cache-directory'.." (interactive) (dired doc-view-cache-directory)) (provide 'doc-view) ;; Local Variables: ;; mode: outline-minor ;; End: ;;; doc-view.el ends here --=-=-= Bye, Tassilo --=-=-= Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: inline _______________________________________________ Emacs-devel mailing list Emacs-devel@gnu.org http://lists.gnu.org/mailman/listinfo/emacs-devel --=-=-=--