diff -Nru emacs-pdf-tools-0.70/COPYING.SYNCTEX emacs-pdf-tools-0.80/COPYING.SYNCTEX --- emacs-pdf-tools-0.70/COPYING.SYNCTEX 2016-06-05 12:32:19.000000000 +0000 +++ emacs-pdf-tools-0.80/COPYING.SYNCTEX 2017-09-10 03:47:50.000000000 +0000 @@ -21,7 +21,7 @@ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE -Except as contained in this notice, the name of the copyright holder -shall not be used in advertising or otherwise to promote the sale, -use or other dealings in this Software without prior written +Except as contained in this notice, the name of the copyright holder +shall not be used in advertising or otherwise to promote the sale, +use or other dealings in this Software without prior written authorization from the copyright holder. diff -Nru emacs-pdf-tools-0.70/debian/changelog emacs-pdf-tools-0.80/debian/changelog --- emacs-pdf-tools-0.70/debian/changelog 2017-08-10 22:42:23.000000000 +0000 +++ emacs-pdf-tools-0.80/debian/changelog 2018-01-20 22:10:33.000000000 +0000 @@ -1,8 +1,15 @@ -emacs-pdf-tools (0.70-3build1) artful; urgency=medium +emacs-pdf-tools (0.80-1~ubuntu17.10.1~c42.ppa1) artful; urgency=medium - * No-change rebuild against latest poppler + * No-change backport to artful - -- Jeremy Bicha Thu, 10 Aug 2017 18:42:23 -0400 + -- H.-Dirk Schmitt Sat, 20 Jan 2018 23:10:33 +0100 + +emacs-pdf-tools (0.80-1) unstable; urgency=medium + + * New upstream released + * drop 0002-Look-for-epdfinfo-where-it-is.patch + + -- Rémi Vanicat Sat, 16 Sep 2017 23:01:41 +0200 emacs-pdf-tools (0.70-3) unstable; urgency=medium diff -Nru emacs-pdf-tools-0.70/debian/patches/0001-Use-debian-libsynctex-dev.patch emacs-pdf-tools-0.80/debian/patches/0001-Use-debian-libsynctex-dev.patch --- emacs-pdf-tools-0.70/debian/patches/0001-Use-debian-libsynctex-dev.patch 2016-10-18 15:41:48.000000000 +0000 +++ emacs-pdf-tools-0.80/debian/patches/0001-Use-debian-libsynctex-dev.patch 2017-09-16 21:00:44.000000000 +0000 @@ -3,15 +3,15 @@ Subject: Use debian libsynctex-dev --- - server/Makefile.am | 7 +------ + server/Makefile.am | 2 +- server/epdfinfo.c | 2 +- - 2 files changed, 2 insertions(+), 7 deletions(-) + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/server/Makefile.am b/server/Makefile.am -index 43984a7..17dc02f 100644 +index 2321571..0452257 100644 --- a/server/Makefile.am +++ b/server/Makefile.am -@@ -3,14 +3,9 @@ epdfinfo_CFLAGS = -Wall $(glib_CFLAGS) $(poppler_glib_CFLAGS) $(poppler_CFLAGS) +@@ -3,7 +3,7 @@ epdfinfo_CFLAGS = -Wall $(glib_CFLAGS) $(poppler_glib_CFLAGS) $(poppler_CFLAGS) $(png_CFLAGS) epdfinfo_CXXFLAGS = -Wall $(epdfinfo_CFLAGS) epdfinfo_LDADD = $(glib_LIBS) $(poppler_glib_LIBS) $(poppler_LIBS) \ @@ -19,19 +19,12 @@ + $(png_LIBS) -lsynctex $(zlib_LIBS) epdfinfo_SOURCES = epdfinfo.c epdfinfo.h poppler-hack.cc --noinst_LIBRARIES = libsynctex.a --libsynctex_a_SOURCES = synctex_parser.c synctex_parser_utils.c synctex_parser.h \ -- synctex_parser_local.h synctex_parser_utils.h --libsynctex_a_CFLAGS = -w -- - GITCLEANFILES = Makefile.in aclocal.m4 config.h.in \ - configure depcomp install-sh missing autom4te.cache \ - $(PACKAGE_NAME)-$(PACKAGE_VERSION).tar.gz + noinst_LIBRARIES = libsynctex.a diff --git a/server/epdfinfo.c b/server/epdfinfo.c -index 54377a5..6d8fddf 100644 +index 86d9200..5bee3dc 100644 --- a/server/epdfinfo.c +++ b/server/epdfinfo.c -@@ -37,7 +37,7 @@ +@@ -39,7 +39,7 @@ #include #include #include diff -Nru emacs-pdf-tools-0.70/debian/patches/0002-Look-for-epdfinfo-where-it-is.patch emacs-pdf-tools-0.80/debian/patches/0002-Look-for-epdfinfo-where-it-is.patch --- emacs-pdf-tools-0.70/debian/patches/0002-Look-for-epdfinfo-where-it-is.patch 2016-10-18 15:41:48.000000000 +0000 +++ emacs-pdf-tools-0.80/debian/patches/0002-Look-for-epdfinfo-where-it-is.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,23 +0,0 @@ -From: =?utf-8?q?R=C3=A9mi_Vanicat?= -Date: Tue, 18 Oct 2016 17:40:49 +0200 -Subject: Look for epdfinfo where it is. - ---- - lisp/pdf-info.el | 4 +--- - 1 file changed, 1 insertion(+), 3 deletions(-) - -diff --git a/lisp/pdf-info.el b/lisp/pdf-info.el -index 2eea21f..da48192 100644 ---- a/lisp/pdf-info.el -+++ b/lisp/pdf-info.el -@@ -62,9 +62,7 @@ - :group 'pdf-tools) - - (defcustom pdf-info-epdfinfo-program -- (expand-file-name "epdfinfo" -- (file-name-directory -- (or load-file-name default-directory))) -+ "/usr/bin/epdfinfo" - "Filename of the epdfinfo executable." - :group 'pdf-info - :type '(file :must-match t)) diff -Nru emacs-pdf-tools-0.70/debian/patches/series emacs-pdf-tools-0.80/debian/patches/series --- emacs-pdf-tools-0.70/debian/patches/series 2016-10-18 15:41:48.000000000 +0000 +++ emacs-pdf-tools-0.80/debian/patches/series 2017-09-16 21:00:44.000000000 +0000 @@ -1,2 +1 @@ 0001-Use-debian-libsynctex-dev.patch -0002-Look-for-epdfinfo-where-it-is.patch diff -Nru emacs-pdf-tools-0.70/lisp/pdf-annot.el emacs-pdf-tools-0.80/lisp/pdf-annot.el --- emacs-pdf-tools-0.70/lisp/pdf-annot.el 2016-06-05 12:32:19.000000000 +0000 +++ emacs-pdf-tools-0.80/lisp/pdf-annot.el 2017-09-10 03:47:50.000000000 +0000 @@ -3,7 +3,7 @@ ;; Copyright (C) 2013, 2014 Andreas Politz ;; Author: Andreas Politz -;; Keywords: +;; Keywords: ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by @@ -39,7 +39,7 @@ ;; * ================================================================== * (defgroup pdf-annot nil - "Annoatation support for PDF documents." + "Annotation support for PDF documents." :group 'pdf-tools) (defcustom pdf-annot-activate-handler-functions nil @@ -52,7 +52,7 @@ default handler `pdf-annot-default-handler' will be called. -This hook is ment to allow for custom annotations. FIXME: +This hook is meant to allow for custom annotations. FIXME: Implement and describe basic org example." :group 'pdf-annot :type 'hook) @@ -116,7 +116,7 @@ `x-gtk-use-system-tooltips' is set to nil if appropriate, in order to display text properties; -`tooltip-hide-delay' is set to infinity, in order to not beeing +`tooltip-hide-delay' is set to infinity, in order to not being annoyed while reading the annotations." :group 'pdf-annot) @@ -234,7 +234,7 @@ :group 'pdf-annot :type 'key-sequence) -(defvar pdf-annot-minor-mode-map +(defvar pdf-annot-minor-mode-map (let ((kmap (make-sparse-keymap)) (smap (make-sparse-keymap))) (define-key kmap pdf-annot-minor-mode-map-prefix smap) @@ -281,7 +281,7 @@ (defun pdf-annot-create-context-menu (a) "Create a appropriate context menu for annotation A." - (let ((menu (make-sparse-keymap))) + (let ((menu (make-sparse-keymap))) ;; (when (and (bound-and-true-p pdf-misc-menu-bar-minor-mode) ;; (bound-and-true-p pdf-misc-install-popup-menu)) ;; (set-keymap-parent menu @@ -370,7 +370,7 @@ ALIST should be a property list as returned by `pdf-cache-getannots'. BUFFER should be the buffer of the corresponding PDF document. It defaults to the current buffer." - + (cons `(buffer . ,(or buffer (current-buffer))) alist)) @@ -390,7 +390,7 @@ (setq types (list types))) (with-current-buffer buffer (let (result) - (dolist (a (pdf-info-getannots pages)) + (dolist (a (pdf-info-getannots pages)) (when (or (null types) (memq (pdf-annot-get a 'type) types)) (push (pdf-annot-create a) result))) @@ -416,7 +416,7 @@ Signals an error, if PROPERTY is not modifiable. Returns the modified annotation." - + (declare (indent 2)) (unless (equal value (pdf-annot-get a property)) (unless (pdf-annot-property-modifiable-p a property) @@ -442,12 +442,12 @@ If `pdf-annot-inhibit-modification-hooks' in non-nil, this just saves ANNOTATIONS and does not call the hooks until later, when the variable is nil and this function is called again." - + (unless (memq operation '(nil :insert :change :delete)) (error "Invalid operation: %s" operation)) (when (and (null operation) annotations) (error "Missing operation argument")) - + (when operation (let ((list (plist-get pdf-annot-delayed-modified-annotations operation))) (dolist (a annotations) @@ -472,7 +472,7 @@ (t (copy-sequence union)) (nil nil)))) (pages (mapcar (lambda (a) (pdf-annot-get a 'page)) union))) - (when union + (when union (unwind-protect (run-hook-with-args 'pdf-annot-modified-functions closure) @@ -488,7 +488,7 @@ (pdf-annot-get-buffer a2)) (eq (pdf-annot-get-id a1) (pdf-annot-get-id a2)))) - + (defun pdf-annot-get-buffer (a) "Return annotation A's buffer." (pdf-annot-get a 'buffer)) @@ -516,7 +516,7 @@ Sets A's buffer's modified flag and runs the hook `pdf-annot-modified-functions'. -This function alwasy returns nil." +This function always returns nil." (interactive (list (pdf-annot-read-annotation "Click on the annotation you wish to delete"))) @@ -587,8 +587,8 @@ (defun pdf-annot-attachment-delete-base-directory () "Delete all saved attachment files of the current buffer." (setq pdf-annot--attachment-file-alist nil) - (delete-directory (pdf-annot-attachment-base-directory) t)) - + (delete-directory (pdf-annot-attachment-base-directory) t)) + (defun pdf-annot-attachment-unique-filename (attachment) "Return a unique absolute filename for ATTACHMENT." (let* ((filename (or (cdr (assq 'filename attachment)) @@ -612,12 +612,12 @@ (unless (file-exists-p directory) (make-directory directory t)) unique)) - -(defun pdf-annot-attachment-save (attachment &optional regenrate-p) + +(defun pdf-annot-attachment-save (attachment &optional regenerate-p) "Save ATTACHMENT's data to a unique filename and return it's name. -If REGENRATE-P is non-nil, copy attachment's file even if the +If REGENERATE-P is non-nil, copy attachment's file even if the copy already exists. Signal an error, if ATTACHMENT has no, or a non-existing, `file' @@ -630,7 +630,7 @@ (error "Attachment's file property is invalid")) (let* ((filename (pdf-annot-attachment-unique-filename attachment))) - (when (or regenrate-p + (when (or regenerate-p (not (file-exists-p filename))) (copy-file datafile filename nil nil t t)) filename))) @@ -711,7 +711,7 @@ IMAGE-SIZE should be a cons \(WIDTH . HEIGHT\) and defaults to the page-image of the selected window." - + (unless image-size (pdf-util-assert-pdf-window) (setq image-size (pdf-view-image-size))) @@ -725,7 +725,7 @@ "Set annotation A's position to X,Y in image coordinates. See `pdf-annot-image-position' for IMAGE-SIZE." - + (unless image-size (pdf-util-assert-pdf-window) (setq image-size (pdf-view-image-size))) @@ -790,11 +790,8 @@ (when window (select-window window)) (let* ((annots (pdf-annot-getannots (pdf-view-current-page))) (size (pdf-view-image-size)) - (offset (pdf-view-image-offset)) - (rx (+ (/ (car pos) (float (car size))) - (car offset))) - (ry (+ (/ (cdr pos) (float (cdr size))) - (cdr offset))) + (rx (/ (car pos) (float (car size)))) + (ry (/ (cdr pos) (float (cdr size)))) (rpos (cons rx ry))) (or (cl-some (lambda (a) (and (cl-some @@ -843,7 +840,7 @@ (pdf-view-redisplay)))) (pdf-annot-run-modified-hooks))) nil)) - + (defun pdf-annot-hotspot-function (page size) "Create image hotspots for page PAGE of size SIZE." (apply 'nconc (mapcar (lambda (a) @@ -851,8 +848,8 @@ 'link) (pdf-annot-create-hotspots a size))) (pdf-annot-getannots page)))) - -(defun pdf-annot-create-hotspots (a size) + +(defun pdf-annot-create-hotspots (a size) "Return a list of image hotspots for annotation A." (let ((id (pdf-annot-get-id a)) (edges (pdf-util-scale @@ -872,7 +869,7 @@ hotspots))) (pdf-annot-create-hotspot-binding id moveable-p a) hotspots)) - + ;; FIXME: Define a keymap as a template for this. Much cleaner. (defun pdf-annot-create-hotspot-binding (id moveable-p annotation) ;; Activating @@ -906,7 +903,7 @@ If HIGHLIGHT-P is non-nil, visually distinguish annotation A from other annotations." - + (save-selected-window (when window (select-window window)) (pdf-util-assert-pdf-window) @@ -976,7 +973,7 @@ (setq edges (list edges))) (when (and (eq type 'text) (> (length edges) 1)) - (error "Edges argument should be a single edge-list for text annotations")) + (error "Edges argument should be a single edge-list for text annotations")) (let* ((a (apply 'pdf-info-addannot page (if (eq type 'text) @@ -1003,7 +1000,7 @@ "Add a new text annotation at POS in the selected window. POS should be a image position object or a cons \(X . Y\), both -beeing image coordinates. +being image coordinates. ICON determines how the annotation is displayed and should be listed in `pdf-annot-standard-text-icons'. Any other value is ok @@ -1063,7 +1060,7 @@ (pdf-util-read-image-position "Click where a new text annotation should be added ...")) (event-start ev)))) - + (defun pdf-annot-add-markup-annotation (list-of-edges type &optional color property-alist) "Add a new markup annotation in the selected window. @@ -1084,7 +1081,7 @@ (interactive (list (pdf-view-active-region t) (let ((type (completing-read "Markup type (default highlight): " - '(squiggly highlight underline strike-out) + '("squiggly" "highlight" "underline" "strike-out") nil t))) (if (equal type "") 'highlight (intern type))) (pdf-annot-read-color))) @@ -1158,21 +1155,21 @@ initial-input 'pdf-annot-color-history defaults inherit-input-method)))) - (read-color prompt))) - + (read-color prompt))) + (defun pdf-annot-merge-alists (&rest alists) "Merge ALISTS into a single one. Suppresses successive duplicate entries of keys after the first -occurence in ALISTS." +occurrence in ALISTS." (let (merged) (dolist (elt (apply 'append alists)) (unless (assq (car elt) merged) (push elt merged))) (nreverse merged))) - - + + ;; * ================================================================== * ;; * Displaying annotation contents @@ -1225,7 +1222,7 @@ (format "File attachment `%s' of %s" (or (cdr (assq 'filename att)) "unnamed") (if (cdr (assq 'size att)) - (format "size %d" (file-size-human-readable + (format "size %s" (file-size-human-readable (cdr (assq 'size att)))) "unknown size")))) (t @@ -1279,13 +1276,9 @@ (make-directory temporary-file-directory)) (unless data (setq tempfile (make-temp-file "pdf-annot" nil ".png")) + ;; FIXME: Why is this with-temp-buffer needed (which it is) ? (with-temp-buffer - (funcall - (cl-case org-latex-create-formula-image-program - (dvipng 'org-create-formula-image-with-dvipng) - (imagemagick 'org-create-formula-image-with-imagemagick) - (t (error - "Invalid value of `org-latex-create-formula-image-program'"))) + (org-create-formula-image contents tempfile org-format-latex-options t)) (setq data (pdf-util-munch-file tempfile)) (if (and (> (length data) 3) @@ -1325,7 +1318,7 @@ (pdf-annot-get a 'contents)) 'latex-mode 'text-mode))) - (unless (derived-mode-p mode) + (unless (derived-mode-p mode) (funcall mode)))) "A function for setting up, e.g. the major-mode, of the edit buffer. @@ -1378,7 +1371,7 @@ (set-buffer-modified-p nil)) (dolist (win (get-buffer-window-list)) (quit-window do-kill win))) - + (defun pdf-annot-edit-contents-save-annotation () (when pdf-annot-edit-contents--annotation (pdf-annot-put pdf-annot-edit-contents--annotation @@ -1421,7 +1414,7 @@ (display-buffer (pdf-annot-edit-contents-noselect a) pdf-annot-edit-contents-display-buffer-action))) - + (defun pdf-annot-edit-contents-mouse (ev) (interactive "@e") (let* ((pos (posn-object-x-y (event-start ev))) @@ -1454,7 +1447,7 @@ km)) (defun pdf-annot-property-completions (property) - "Return a list of completion candidats for annotation property PROPERTY. + "Return a list of completion candidates for annotation property PROPERTY. Return nil, if not available." (cl-case property @@ -1503,7 +1496,7 @@ (if (pdf-annot-get a 'created) (pdf-annot-print-property a 'created) "Unknown date"))))) - + (define-derived-mode pdf-annot-list-mode tablist-mode "Annots" (setq tabulated-list-entries 'pdf-annot-list-entries tabulated-list-format (vector @@ -1565,15 +1558,15 @@ (when (invisible-p (point)) (tablist-suspend-filter t)) (tablist-move-to-major-column))))) - - + + (defun pdf-annot-list-update (&optional _fn) (when (buffer-live-p pdf-annot-list-buffer) (with-current-buffer pdf-annot-list-buffer (unless tablist-edit-column-minor-mode (tablist-revert)) (tablist-context-window-update)))) - + (defun pdf-annot-list-context-function (id buffer) (with-current-buffer (get-buffer-create "*Contents*") (set-window-buffer nil (current-buffer)) diff -Nru emacs-pdf-tools-0.70/lisp/pdf-cache.el emacs-pdf-tools-0.80/lisp/pdf-cache.el --- emacs-pdf-tools-0.70/lisp/pdf-cache.el 2016-06-05 12:32:19.000000000 +0000 +++ emacs-pdf-tools-0.80/lisp/pdf-cache.el 2017-09-10 03:47:50.000000000 +0000 @@ -19,9 +19,9 @@ ;; along with this program. If not, see . ;;; Commentary: -;; +;; ;;; Code: -;; +;; (require 'pdf-info) (require 'pdf-util) @@ -108,7 +108,7 @@ (when pdf-cache--data (dolist (page pages) (remhash page pdf-cache--data)))) - + (defun pdf-cache-clear-data () (interactive) (when pdf-cache--data @@ -130,7 +130,7 @@ (ifn (intern (format "pdf-info-%s" command))) (doc (format "Cached version of `pdf-info-%s', which see. -Make shure, not to modify it's return value." command))) +Make sure, not to modify it's return value." command))) `(defun ,fn ,args ,doc (let ((hit-value (pdf-cache--data-get ',command ,(if page-arg-p 'page)))) @@ -149,7 +149,7 @@ (define-pdf-cache-function boundingbox t) (define-pdf-cache-function textregions t) (define-pdf-cache-function pagesize t) - + ;; * ================================================================== * ;; * PNG image LRU cache @@ -157,7 +157,7 @@ (defvar pdf-cache-image-inihibit nil "Non-nil, if the image cache should be bypassed.") - + (defvar-local pdf-cache--image-cache nil) (defmacro pdf-cache--make-image (page width data hash) @@ -197,7 +197,7 @@ (apply 'pdf-cache--image-match image spec)))))) (and image (pdf-cache--image/data image)))) - + (defun pdf-cache-get-image (page min-width &optional max-width hash) "Return PAGE's PNG data as a string. @@ -214,7 +214,7 @@ (while (and (cdr cache) (not (pdf-cache--image-match (car (cdr cache)) - page min-width max-width hash))) + page min-width max-width hash))) (setq cache (cdr cache))) (setq image (cadr cache)) (when (car cache) @@ -447,7 +447,7 @@ (defun pdf-cache--prefetch-stop () "Stop prefetching images in current buffer." (setq pdf-cache--prefetch-pages nil)) - + (defun pdf-cache--prefetch-cancel () "Cancel prefetching images in current buffer." (pdf-cache--prefetch-stop) diff -Nru emacs-pdf-tools-0.70/lisp/pdf-dev.el emacs-pdf-tools-0.80/lisp/pdf-dev.el --- emacs-pdf-tools-0.70/lisp/pdf-dev.el 2016-06-05 12:32:19.000000000 +0000 +++ emacs-pdf-tools-0.80/lisp/pdf-dev.el 2017-09-10 03:47:50.000000000 +0000 @@ -3,7 +3,7 @@ ;; Copyright (C) 2015 Andreas Politz ;; Author: Andreas Politz -;; Keywords: +;; Keywords: ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by @@ -19,7 +19,7 @@ ;; along with this program. If not, see . ;;; Commentary: -;; +;; ;; This file is only ment for developers. The entry point is ;; pdf-dev-minor-mode, which see. @@ -41,7 +41,7 @@ (push file loaded) (load-file file)) (message "Loaded %s" (mapconcat 'identity loaded " ")))) - + (define-minor-mode pdf-dev-minor-mode "Make developing pdf-tools easier. @@ -51,7 +51,7 @@ ../server/epdfinfo. Installs a `compilation-finish-functions' which will restart -epdfinfo after a succesful recompilation. +epdfinfo after a successful recompilation. Sets up `load-path' and reloads all PDF Tools lisp files." nil nil nil diff -Nru emacs-pdf-tools-0.70/lisp/pdf-history.el emacs-pdf-tools-0.80/lisp/pdf-history.el --- emacs-pdf-tools-0.70/lisp/pdf-history.el 2016-06-05 12:32:19.000000000 +0000 +++ emacs-pdf-tools-0.80/lisp/pdf-history.el 2017-09-10 03:47:50.000000000 +0000 @@ -19,7 +19,7 @@ ;; along with this program. If not, see . ;;; Commentary: -;; +;; (require 'pdf-view) (require 'pdf-util) @@ -49,7 +49,7 @@ This is a simple stack-based history. Turning the page or following a link pushes the left-behind page on the stack, which -may be naviagted with the following keys. +may be navigated with the following keys. \\{pdf-history-minor-mode-map}" nil nil nil @@ -108,7 +108,7 @@ "Return t, if at the end of the history." (= pdf-history-index (1- (length pdf-history-stack)))) - + (defun pdf-history-backward (n) "Go N-times backward in the history." (interactive "p") @@ -131,7 +131,7 @@ "Go N-times forward in the history." (interactive "p") (pdf-history-backward (- n))) - + (defun pdf-history-goto (n) "Go to item N in the history." (interactive "p") diff -Nru emacs-pdf-tools-0.70/lisp/pdf-info.el emacs-pdf-tools-0.80/lisp/pdf-info.el --- emacs-pdf-tools-0.70/lisp/pdf-info.el 2016-06-05 12:32:19.000000000 +0000 +++ emacs-pdf-tools-0.80/lisp/pdf-info.el 2017-09-10 03:47:50.000000000 +0000 @@ -1,4 +1,4 @@ -;;; pdf-info.el --- Extract infos from pdf-files via a helper process. -*- lexical-binding: t -*- +;;; pdf-info.el --- Extract info from pdf-files via a helper process. -*- lexical-binding: t -*- ;; Copyright (C) 2013, 2014 Andreas Politz @@ -40,11 +40,11 @@ ;; to realize, annotations retrieved or created are referenced by a ;; unique symbol. Saving these changes creates a new file, the ;; original document is never touched. - + ;;; Todo: ;; ;; + Close documents at some time (e.g. when the buffer is killed) -;; +;; ;;; Code: @@ -60,19 +60,36 @@ (defgroup pdf-info nil "Extract infos from pdf-files via a helper process." :group 'pdf-tools) - + (defcustom pdf-info-epdfinfo-program - (expand-file-name "epdfinfo" - (file-name-directory - (or load-file-name default-directory))) + (let ((executable (if (eq system-type 'windows-nt) + "epdfinfo.exe" + "epdfinfo"))) + (or (executable-find executable) + (expand-file-name + executable + (let ((directory (file-name-directory (or load-file-name default-directory)))) + (cl-find-if 'file-exists-p + `(,(expand-file-name "../server" directory) + ,directory)))))) "Filename of the epdfinfo executable." :group 'pdf-info :type '(file :must-match t)) +(defcustom pdf-info-epdfinfo-error-filename nil + "Filename for error output of the epdfinfo executable. + +If nil, discard any error messages. Useful for debugging." + :group 'pdf-info + :type `(choice (const :tag "None" nil) + ,@(when (file-directory-p "/tmp/") + '((const "/tmp/epdfinfo.log"))) + (file))) + (defcustom pdf-info-log nil "Whether to log the communication with the server. -If this is non-nil, all communication with the epdfinfo programm +If this is non-nil, all communication with the epdfinfo program will be logged to the buffer \"*pdf-info-log*\"." :group 'pdf-info :type 'boolean) @@ -184,23 +201,28 @@ (error "pdf-info-epdfinfo-program is unset or not a string")) (unless (file-executable-p executable) (error "pdf-info-epdfinfo-program is not executable")) + (when pdf-info-epdfinfo-error-filename + (unless (file-writable-p pdf-info-epdfinfo-error-filename) + (error "pdf-info-epdfinfo-error-filename should be nil or a writable filename"))) (let ((tempfile (make-temp-file "pdf-info-check-epdfinfo")) (default-directory "~")) - (unwind-protect + (unwind-protect (with-temp-buffer (with-temp-file tempfile (insert "quit\n")) - (unless (= 0 (call-process - executable tempfile (current-buffer))) + (unless (= 0 (apply #'call-process + executable tempfile (current-buffer) + nil (when pdf-info-epdfinfo-error-filename + (list pdf-info-epdfinfo-error-filename)))) (error "Error running `%s': %s" pdf-info-epdfinfo-program - (buffer-string)))) + (buffer-string)))) (when (file-exists-p tempfile) (delete-file tempfile))))) (when interactive-p - (message "The epdfinfo programm appears to be working.")) + (message "The epdfinfo program appears to be working.")) nil) - + (defun pdf-info-process-assert-running (&optional force) "Assert a running process. @@ -227,15 +249,17 @@ (y-or-n-p "The epdfinfo server quit, restart it ? ")) (and pdf-info-restart-process-p (not (eq pdf-info-restart-process-p 'ask)))) - + (when (eq pdf-info-restart-process-p 'ask) (setq pdf-info-restart-process-p nil)) (error "The epdfinfo server quit")) (pdf-info-check-epdfinfo) (let* ((process-connection-type) ;Avoid 4096 Byte bug #12440. (default-directory "~") - (proc (start-process - "epdfinfo" " *epdfinfo*" pdf-info-epdfinfo-program))) + (proc (apply #'start-process + "epdfinfo" " *epdfinfo*" pdf-info-epdfinfo-program + (when pdf-info-epdfinfo-error-filename + (list pdf-info-epdfinfo-error-filename))))) (with-current-buffer " *epdfinfo*" (erase-buffer)) (set-process-query-on-exit-flag proc nil) @@ -318,7 +342,7 @@ (error "The epdfinfo server quit unexpectedly.")) (cond ((null status) response) - ((eq status 'error) + ((eq status 'error) (error "epdfinfo: %s" response)) ((eq status 'interrupted) (error "epdfinfo: Command was interrupted")) @@ -331,9 +355,9 @@ (eq (process-status (pdf-info-process)) 'run)) (signal-process (pdf-info-process) 'SIGUSR1))) - + (defun pdf-info-query--escape (arg) - "Escape ARG for transmision to the server." + "Escape ARG for transmission to the server." (if (null arg) (string) (with-current-buffer (get-buffer-create " *pdf-info-query--escape*") @@ -350,7 +374,7 @@ (backward-char))) (forward-char)) (buffer-substring-no-properties 1 (point-max))))) - + (defmacro pdf-info-query--read-record () "Read a single record of the response in current buffer." `(let (records done (beg (point))) @@ -722,12 +746,12 @@ All queries in each QUERIES form are run by the server in the order they appear and the results collected in a list, which is -bound to VAR. Then BODY is evaluated and it's value becomes the +bound to VAR. Then BODY is evaluated and its value becomes the final result of all queries, unless at least one of them provoked an error. In this case BODY is ignored and the error is the result. -This macro handles synchrounus and asynchronous calls, +This macro handles synchronous and asynchronous calls, i.e. `pdf-info-asynchronous' is non-nil, transparently. \(FN \(\(VAR QUERIES\)...\) BODY\)" @@ -744,21 +768,21 @@ (listp (cdr form)))) let-forms) (error "Invalid let-form: %s" let-forms)) - + (setq let-forms (mapcar (lambda (form) (if (symbolp form) (list form) form)) let-forms)) (let* ((status (make-symbol "status")) - (response (make-symbol "response")) + (response (make-symbol "response")) (first-error (make-symbol "first-error")) (done (make-symbol "done")) (callback (make-symbol "callback")) (results (make-symbol "results")) (push-fn (make-symbol "push-fn")) (terminal-fn (make-symbol "terminal-fn")) - (buffer (make-symbol "buffer"))) + (buffer (make-symbol "buffer"))) `(let* (,status ,response ,first-error ,done (,buffer (current-buffer)) @@ -797,7 +821,7 @@ (funcall ,callback ,status ,response) (apply (car ,callback) ,status ,response (cdr ,callback)))))))) - ;; Wrap each query in an asynchronous call, with it's VAR as + ;; Wrap each query in an asynchronous call, with its VAR as ;; callback argument, so the PUSH-FN can put it in the alist ;; RESULTS. ,@(mapcar (lambda (form) @@ -810,7 +834,7 @@ (let ((pdf-info-asynchronous ,terminal-fn)) (pdf-info-ping)) ;; CALLBACK is the original value of pdf-info-asynchronous. If - ;; nil, this is a synchrounus query. + ;; nil, this is a synchronous query. (unless ,callback (while (and (not ,done) (eq (process-status (pdf-info-process)) @@ -823,7 +847,7 @@ (when ,status (error "epdfinfo: %s" ,response)) ,response)))) - + ;; * ================================================================== * ;; * Buffer local server instances @@ -840,7 +864,7 @@ (unless buffer (setq buffer (current-buffer))) (with-current-buffer buffer - (unless (and + (unless (and (not force-restart-p) (local-variable-p 'pdf-info--queue) (processp (pdf-info-process)) @@ -923,7 +947,7 @@ (setq pdf-info-features (let (pdf-info-asynchronous) (pdf-info-query 'features))))) - + (defun pdf-info-writable-annotations-p () (not (null (memq 'writable-annotations (pdf-info-features))))) @@ -947,13 +971,13 @@ (t (list 'text))))) (defun pdf-info-open (&optional file-or-buffer password) - "Open the docüment FILE-OR-BUFFER using PASSWORD. + "Open the document FILE-OR-BUFFER using PASSWORD. -Generally, docüments are opened and closed automatically on +Generally, documents are opened and closed automatically on demand, so this function is rarely needed, unless a PASSWORD is -set on the docüment. +set on the document. -Manually opened docüments are never closed automatically." +Manually opened documents are never closed automatically." (pdf-info-query 'open (pdf-info--normalize-file-or-buffer file-or-buffer) @@ -973,7 +997,20 @@ (run-hooks 'pdf-info-close-document-hook)) (with-temp-buffer (run-hooks 'pdf-info-close-document-hook)))))) - + +(defun pdf-info-encrypted-p (&optional file-or-buffer) + "Return non-nil if FILE-OR-BUFFER requires a password. + +Note: This function returns nil, if the document is encrypted, +but was already opened (presumably using a password)." + + (condition-case err + (pdf-info-open + (pdf-info--normalize-file-or-buffer file-or-buffer)) + (error (or (string-match-p + ":Document is encrypted\\'" (cadr err)) + (signal (car err) (cdr err)))))) + (defun pdf-info-metadata (&optional file-or-buffer) "Extract the metadata from the document FILE-OR-BUFFER. @@ -982,7 +1019,7 @@ (pdf-info-query 'metadata (pdf-info--normalize-file-or-buffer file-or-buffer))) - + (defun pdf-info-search-string (string &optional pages file-or-buffer) "Search for STRING in PAGES of document FILE-OR-BUFFER. @@ -1048,7 +1085,7 @@ You should not change this directly, but rather `let'-bind it around a call to `pdf-info-search-regexp'. -Valid compile-flags are: +Valid compile-flags are: newline-crlf, newline-lf, newline-cr, dupnames, optimize, no-auto-capture, raw, ungreedy, dollar-endonly, anchored, @@ -1057,7 +1094,7 @@ Note that the last one, caseless, is handled special, as it is always added if `case-fold-search' is non-nil. -And valid match-flags: +And valid match-flags: match-anchored, match-notbol, match-noteol, match-notempty, match-partial, match-newline-cr, match-newline-lf, @@ -1066,13 +1103,13 @@ See the glib documentation at url `https://developer.gnome.org/glib/stable/glib-Perl-compatible-regular-expressions.html'.") -(defun pdf-info-search-regexp (pcre &optional pages +(defun pdf-info-search-regexp (pcre &optional pages no-error file-or-buffer) - "Search for a PCRE on PAGES of docüment FILE-OR-BUFFER. + "Search for a PCRE on PAGES of document FILE-OR-BUFFER. See `pdf-info-normalize-page-range' for valid PAGES formats and -`pdf-info-search-string' for it's return value. +`pdf-info-search-string' for its return value. Uses the flags in `pdf-info-regexp-flags', which see. If `case-fold-search' is non-nil, the caseless flag is added. @@ -1080,7 +1117,7 @@ If NO-ERROR is non-nil, catch errors due to invalid regexps and return nil. If it is the symbol `invalid-regexp', then re-signal this kind of error as a `invalid-regexp' error." - + (cl-labels ((orflags (flags alist) (cl-reduce (lambda (v flag) @@ -1096,7 +1133,7 @@ (car pages) (cdr pages) pcre - (orflags `(,(if case-fold-search + (orflags `(,(if case-fold-search 'caseless) ,@pdf-info-regexp-flags) (pdf-info-regexp-compile-flags)) @@ -1118,7 +1155,7 @@ (list (match-string 1 (cadr err)))))))))))) (defun pdf-info-pagelinks (page &optional file-or-buffer) - "Return a list of links on PAGE in docüment FILE-OR-BUFFER. + "Return a list of links on PAGE in document FILE-OR-BUFFER. This function returns a list of alists with the following keys. EDGES represents the relative bounding-box of the link , TYPE is @@ -1129,7 +1166,7 @@ goto-dest -- This is a internal link to some page. Each element contains additional keys PAGE and TOP, where PAGE is the page of -the link and TOP it's vertical position. +the link and TOP its vertical position. goto-remote -- This a external link to some document. Same as goto-dest, with an additional FILENAME of the external PDF. @@ -1241,7 +1278,7 @@ (pdf-info-query 'pagesize (pdf-info--normalize-file-or-buffer file-or-buffer) - page)) + page)) (defun pdf-info-running-p () "Return non-nil, if the server is running." @@ -1288,12 +1325,12 @@ alists. Each element of this list describes one annotation and contains the following keys. -page - It's page number. -edges - It's area. +page - Its page number. +edges - Its area. type - A symbol describing the annotation's type. id - A document-wide unique symbol referencing this annotation. -flags - It's flags, binary encoded. -color - It's color in standard Emacs notation. +flags - Its flags, binary encoded. +color - Its color in standard Emacs notation. contents - The text of this annotation. modified - The last modification date of this annotation. @@ -1312,7 +1349,7 @@ text-icon - A string describing the purpose of this annotation. text-state - A string, e.g. accepted or rejected." ;FIXME: Use symbols ? - + (let ((pages (pdf-info-normalize-page-range pages))) (pdf-info-query 'getannots @@ -1378,13 +1415,13 @@ EDGES should be a list \(LEFT TOP RIGHT BOT\). RIGHT and/or BOT may also be negative, which means to keep the width resp. height." - (pdf-info-editannot id `((edges . ,edges)) file-or-buffer)) + (pdf-info-editannot id `((edges . ,edges)) file-or-buffer)) (defun pdf-info-editannot (id modifications &optional file-or-buffer) "Edit annotation ID, applying MODIFICATIONS. ID should be a symbol, which was previously returned in a -`pdf-info-getannots' query. +`pdf-info-getannots' query. MODIFICATIONS is an alist of properties and their new values. @@ -1420,14 +1457,14 @@ (pdf-info-assert-writable-annotations) (pdf-info-query 'save - (pdf-info--normalize-file-or-buffer file-or-buffer))) + (pdf-info--normalize-file-or-buffer file-or-buffer))) (defun pdf-info-getattachment-from-annot (id &optional do-save file-or-buffer) "Return the attachment associated with annotation ID. ID should be a symbol which was previously returned in a `pdf-info-getannots' query, and referencing an attachment of type -`file', otherwise an error is signalled. +`file', otherwise an error is signaled. See `pdf-info-getattachments' for the kind of return value of this function and the meaning of DO-SAVE." @@ -1474,7 +1511,7 @@ Returns an alist with entries PAGE and relative EDGES describing the position in the PDF document corresponding to the SOURCE location." - + (let ((source (if (buffer-live-p (get-buffer source)) (buffer-file-name (get-buffer source)) source))) @@ -1484,7 +1521,7 @@ source (or line 1) (or column 1)))) - + (defun pdf-info-synctex-backward-search (page &optional x y file-or-buffer) "Perform a backward search with synctex. @@ -1507,7 +1544,7 @@ Return the data of the corresponding PNG image." (when (keywordp file-or-buffer) (push file-or-buffer commands) - (setq file-or-buffer nil)) + (setq file-or-buffer nil)) (apply 'pdf-info-query 'renderpage (pdf-info--normalize-file-or-buffer file-or-buffer) @@ -1540,7 +1577,7 @@ REGIONS is a list determining foreground and background color and the regions to render. So each element should look like \(FG BG \(LEFT TOP RIGHT BOT\) \(LEFT TOP RIGHT BOT\) ... \) . The -rendering is text-aware. +rendering is text-aware. If SINGLE-LINE-P is non-nil, the edges in REGIONS are each supposed to be limited to a single line in the document. Setting @@ -1549,11 +1586,11 @@ For the other args see `pdf-info-renderpage'. Return the data of the corresponding PNG image." - + (when (consp file-or-buffer) (push file-or-buffer regions) (setq file-or-buffer nil)) - + (apply 'pdf-info-renderpage page width file-or-buffer (apply 'append @@ -1568,7 +1605,7 @@ elt))) regions)))) -(defun pdf-info-renderpage-highlight (page width +(defun pdf-info-renderpage-highlight (page width &optional file-or-buffer &rest regions) "Highlight regions on PAGE with width WIDTH using REGIONS. @@ -1581,11 +1618,11 @@ For the other args see `pdf-info-renderpage'. Return the data of the corresponding PNG image." - + (when (consp file-or-buffer) (push file-or-buffer regions) (setq file-or-buffer nil)) - + (apply 'pdf-info-renderpage page width file-or-buffer (apply 'append @@ -1602,7 +1639,7 @@ "Return a bounding-box for PAGE. Returns a list \(LEFT TOP RIGHT BOT\)." - + (pdf-info-query 'boundingbox (pdf-info--normalize-file-or-buffer file-or-buffer) @@ -1618,7 +1655,7 @@ (push file-or-buffer options) (setq file-or-buffer nil)) (unless (= (% (length options) 2) 0) - (error "Missing a option value")) + (error "Missing a option value")) (apply 'pdf-info-query 'setoptions (pdf-info--normalize-file-or-buffer file-or-buffer) @@ -1638,15 +1675,15 @@ (t (push value soptions))) (push key soptions))) soptions))) - - + + (defun pdf-info-pagelabels (&optional file-or-buffer) "Return a list of pagelabels. Returns a list of strings corresponding to the labels of the pages in FILE-OR-BUFFER." - + (pdf-info-query 'pagelabels (pdf-info--normalize-file-or-buffer file-or-buffer))) diff -Nru emacs-pdf-tools-0.70/lisp/pdf-isearch.el emacs-pdf-tools-0.80/lisp/pdf-isearch.el --- emacs-pdf-tools-0.70/lisp/pdf-isearch.el 2016-06-05 12:32:19.000000000 +0000 +++ emacs-pdf-tools-0.80/lisp/pdf-isearch.el 2017-09-10 03:47:50.000000000 +0000 @@ -21,7 +21,7 @@ ;;; Commentary: ;; ;;; Todo: -;; +;; ;; * Add the possibility to limit the search to a range of pages. (require 'cl-lib) @@ -43,7 +43,7 @@ (defgroup pdf-isearch nil "Isearch in pdf buffers." :group 'pdf-tools) - + (defface pdf-isearch-match '((((background dark)) (:inherit isearch)) (((background light)) (:inherit isearch))) @@ -90,7 +90,7 @@ A match may contain more than one edges-element, e.g. when regexp searching across multiple lines.") - + (defvar-local pdf-isearch-current-matches nil "A list of matches of the last search.") @@ -103,7 +103,8 @@ ;; * ================================================================== * (declare-function pdf-occur "pdf-occur.el") - +(declare-function pdf-sync-backward-search "pdf-sync.el") + (defvar pdf-isearch-minor-mode-map (let ((kmap (make-sparse-keymap))) (define-key kmap [remap occur] 'pdf-occur) @@ -116,10 +117,11 @@ (define-key kmap (kbd "C-d") 'pdf-view-dark-minor-mode) (define-key kmap (kbd "C-b") 'pdf-isearch-batch-mode) (define-key kmap (kbd "M-s o") 'pdf-isearch-occur) + (define-key kmap (kbd "M-s s") 'pdf-isearch-sync-backward) kmap) "Keymap used in `pdf-isearch-active-mode'. -This keymap is used, when isearching in PDF buffers. It's parent +This keymap is used, when isearching in PDF buffers. Its parent keymap is `isearch-mode-map'.") (put 'image-scroll-up 'isearch-scroll t) @@ -233,7 +235,7 @@ "A function for filtering isearch matches. The function receives one argument: a list of matches, each -beeing a list of edges. It should return a subset of this list. +being a list of edges. It should return a subset of this list. Edge coordinates are in image-space.") (defvar pdf-isearch-narrow-to-page nil @@ -281,7 +283,7 @@ (re-search-forward ".") (re-search-backward "."))) ((and (not pdf-isearch-narrow-to-page) - (not (pdf-isearch-empty-match-p matches))) + (not (pdf-isearch-empty-match-p matches))) (let ((next-page (pdf-isearch-find-next-matching-page string pdf-isearch-current-page t))) (when next-page @@ -433,6 +435,18 @@ (pdf-occur (or regexp isearch-string) regexp)) (isearch-message))) +(defun pdf-isearch-sync-backward () + "Visit the source of the beginning of the current match." + (interactive) + (pdf-util-assert-pdf-window) + (unless pdf-isearch-current-match + (user-error "No current or recent match")) + (when isearch-mode + (isearch-exit)) + (cl-destructuring-bind (left top _right _bot) + (car pdf-isearch-current-match) + (pdf-sync-backward-search left top))) + ;; * ================================================================== * ;; * Interface to epdfinfo @@ -455,38 +469,27 @@ (defun pdf-isearch-search-fun () (funcall (or pdf-isearch-search-fun-function 'pdf-isearch-search-fun-default))) - + (defun pdf-isearch-search-fun-default () "Return default functions to use for the search." (cond - (isearch-word + ((eq isearch-word t) (lambda (string &optional pages) ;; Use lax versions to not fail at the end of the word while ;; the user adds and removes characters in the search string ;; (or when using nonincremental word isearch) (let ((lax (not (or isearch-nonincremental - (null (car isearch-cmds)) - (eq (length isearch-string) - (length (isearch--state-string + (null (car isearch-cmds)) + (eq (length isearch-string) + (length (isearch--state-string (car isearch-cmds)))))))) (pdf-info-search-regexp - (if (functionp isearch-word) - (funcall isearch-word string lax) - (pdf-isearch-word-search-regexp - string lax pdf-isearch-hyphenation-character)) - pages 'invalid-regexp)))) - ;; ((and isearch-regexp isearch-regexp-lax-whitespace - ;; search-whitespace-regexp) - ;; (if isearch-forward - ;; 're-search-forward-lax-whitespace - ;; 're-search-backward-lax-whitespace)) + (pdf-isearch-word-search-regexp + string lax pdf-isearch-hyphenation-character) + pages 'invalid-regexp)))) (isearch-regexp (lambda (string &optional pages) (pdf-info-search-regexp string pages 'invalid-regexp))) - ;; ((and isearch-lax-whitespace search-whitespace-regexp) - ;; (if isearch-forward - ;; 'search-forward-lax-whitespace - ;; 'search-backward-lax-whitespace)) (t 'pdf-info-search-string))) @@ -607,7 +610,7 @@ ;; Next match of new search closest to the last one. (pdf-isearch-closest-match last-match matches forward)))) - + (defun pdf-isearch-focus-match-isearch (match) "Make the image area in MATCH visible in the selected window." (pdf-util-scroll-to-edges (apply 'pdf-util-edges-union match))) @@ -664,7 +667,7 @@ MATCH should be a list of edges, MATCHES a list of such element; it is assumed to be ordered with respect to FORWARD-P." - + (cl-check-type match pdf-isearch-match) (cl-check-type matches (list-of pdf-isearch-match)) (let ((matched (apply 'pdf-util-edges-union match))) @@ -753,8 +756,8 @@ ;; * Debug ;; * ================================================================== * -;; The following isearch-search function is debugable. -;; +;; The following isearch-search function is debuggable. +;; (when nil (defun isearch-search () ;; Do the search with the current search string. @@ -822,3 +825,7 @@ (provide 'pdf-isearch) ;;; pdf-isearch.el ends here + +;; Local Variables: +;; byte-compile-warnings: (not obsolete) +;; End: diff -Nru emacs-pdf-tools-0.70/lisp/pdf-links.el emacs-pdf-tools-0.80/lisp/pdf-links.el --- emacs-pdf-tools-0.70/lisp/pdf-links.el 2016-06-05 12:32:19.000000000 +0000 +++ emacs-pdf-tools-0.80/lisp/pdf-links.el 2017-09-10 03:47:50.000000000 +0000 @@ -19,7 +19,7 @@ ;; along with this program. If not, see . ;;; Commentary: -;; +;; (require 'pdf-info) (require 'pdf-util) @@ -123,7 +123,7 @@ (defun pdf-links-hotspots-function (page size) "Create hotspots for links on PAGE using SIZE." - + (let ((links (pdf-cache-pagelinks page)) (id-fmt "link-%d-%d") (i 0) @@ -148,7 +148,7 @@ (pdf-links-action-perform l))) (local-set-key (vector id t) - 'pdf-util-image-map-mouse-event-proxy))) + 'pdf-util-image-map-mouse-event-proxy))) (nreverse hotspots))) (defun pdf-links-action-to-string (link) @@ -178,7 +178,7 @@ ;;;###autoload (defun pdf-links-action-perform (link) - "Follow LINK, depending on it's type. + "Follow LINK, depending on its type. This may turn to another page, switch to another PDF buffer or invoke `pdf-links-browse-uri-function'. @@ -225,7 +225,7 @@ (t (error "Unrecognized link type: %s" .type))) nil)) - + (defun pdf-links-read-link-action (prompt) "Using PROMPT, interactively read a link-action. @@ -258,7 +258,7 @@ (error "No links on this page")) (unwind-protect (let ((image-data - (pdf-cache-get-image + (pdf-cache-get-image (pdf-view-current-page) (car size) (car size) 'pdf-links-read-link-action))) (unless image-data @@ -340,7 +340,7 @@ (unless links (error "No link found at this position")) (pdf-links-action-perform (car links)))))) - + (defun pdf-links-isearch-link-filter-matches (matches) (let ((links (pdf-util-scale (mapcar (apply-partially 'alist-get 'edges) diff -Nru emacs-pdf-tools-0.70/lisp/pdf-misc.el emacs-pdf-tools-0.80/lisp/pdf-misc.el --- emacs-pdf-tools-0.70/lisp/pdf-misc.el 2016-06-05 12:32:19.000000000 +0000 +++ emacs-pdf-tools-0.80/lisp/pdf-misc.el 2017-09-10 03:47:50.000000000 +0000 @@ -1,4 +1,4 @@ -;;; pdf-misc.el --- Miscellanous commands for PDF buffer. +;;; pdf-misc.el --- Miscellaneous commands for PDF buffer. ;; Copyright (C) 2013, 2014 Andreas Politz @@ -19,7 +19,7 @@ ;; along with this program. If not, see . ;;; Commentary: -;; +;; (require 'pdf-view) @@ -38,7 +38,7 @@ ;;;###autoload (define-minor-mode pdf-misc-minor-mode "FIXME: Not documented." - nil nil nil) + nil nil nil) ;;;###autoload (define-minor-mode pdf-misc-size-indication-minor-mode @@ -50,7 +50,7 @@ (unless (assq 'pdf-misc-size-indication-minor-mode mode-line-position) (setq mode-line-position - `((pdf-misc-size-indication-minor-mode + `((pdf-misc-size-indication-minor-mode (:eval (pdf-misc-size-indication))) ,@mode-line-position)))) (t @@ -242,9 +242,8 @@ :type 'file) (defcustom pdf-misc-print-programm-args nil - "List of additional arguments passed to `pdf-misc-print-programm'." + "List of additional arguments passed to `pdf-misc-print-program'." :group 'pdf-misc - :type 'file :type '(repeat string)) (defun pdf-misc-print-programm (&optional interactive-p) @@ -255,7 +254,7 @@ 'executable-find '("gtklp" "xpp" "gpr"))))) buffer-file-name - (programm + (programm (expand-file-name (read-file-name "Print with: " default nil t nil 'file-executable-p)))) @@ -271,13 +270,13 @@ (list (pdf-view-buffer-file-name) t)) (cl-check-type filename (and string file-readable)) (let ((programm (pdf-misc-print-programm interactive-p)) - (args (append pdf-misc-print-programm-args (list filename)))) + (args (append pdf-misc-print-programm-args (list filename)))) (unless programm - (error "No print programm available")) + (error "No print program available")) (apply #'start-process "printing" nil programm args) (message "Print job started: %s %s" - programm (mapconcat #'identity args " ")))) - + programm (mapconcat #'identity args " ")))) + (provide 'pdf-misc) diff -Nru emacs-pdf-tools-0.70/lisp/pdf-occur.el emacs-pdf-tools-0.80/lisp/pdf-occur.el --- emacs-pdf-tools-0.70/lisp/pdf-occur.el 2016-06-05 12:32:19.000000000 +0000 +++ emacs-pdf-tools-0.80/lisp/pdf-occur.el 2017-09-10 03:47:50.000000000 +0000 @@ -71,7 +71,7 @@ "The history variable for search strings.") (defvar pdf-occur-search-pages-left nil - "The toatl number of pages left to search.") + "The total number of pages left to search.") (defvar pdf-occur-search-documents nil "The list of searched documents. @@ -257,7 +257,7 @@ ;; * ================================================================== * -;; * Finding occurences +;; * Finding occurrences ;; * ================================================================== * @@ -602,7 +602,7 @@ (defun pdf-occur-search-in-progress-p () (and (numberp pdf-occur-search-pages-left) (> pdf-occur-search-pages-left 0))) - + (defun pdf-occur-start-search (documents string &optional regexp-p) (pdf-occur-assert-occur-buffer-p) @@ -715,7 +715,7 @@ ((and (derived-mode-p 'pdf-view-mode) (buffer-file-name)) (push (buffer-file-name) files))))) - + (setq files (cl-sort ;Looks funny. (cl-set-difference diff -Nru emacs-pdf-tools-0.70/lisp/pdf-outline.el emacs-pdf-tools-0.80/lisp/pdf-outline.el --- emacs-pdf-tools-0.70/lisp/pdf-outline.el 2016-06-05 12:32:19.000000000 +0000 +++ emacs-pdf-tools-0.80/lisp/pdf-outline.el 2017-09-10 03:47:50.000000000 +0000 @@ -19,7 +19,7 @@ ;; along with this program. If not, see . ;;; Commentary: -;; +;; (require 'outline) (require 'pdf-links) @@ -33,7 +33,7 @@ ;; ;; User options -;; +;; (defgroup pdf-outline nil "Display a navigatable outline of a PDF document." @@ -113,7 +113,7 @@ ;; ;; Internal Variables -;; +;; (define-button-type 'pdf-outline 'face nil @@ -130,7 +130,7 @@ ;; ;; Functions -;; +;; ;;;###autoload (define-minor-mode pdf-outline-minor-mode @@ -200,7 +200,7 @@ (not (eq link pdf-outline-follow-mode-last-link))) (setq pdf-outline-follow-mode-last-link link) (pdf-outline-display-link (point))))) - + ;;;###autoload (defun pdf-outline (&optional buffer no-select-window-p) "Display an PDF outline of BUFFER. @@ -247,7 +247,7 @@ ;; (when (buffer-live-p (get-buffer buf)) ;; (kill-buffer buf)) buf)) - + (defun pdf-outline-insert-outline (pdf-buffer) (let ((labels (and pdf-outline-display-labels (pdf-info-pagelabels pdf-buffer))) @@ -300,7 +300,7 @@ ;; ;; Commands -;; +;; (defun pdf-outline-move-to-current-page () "Move to the item corresponding to the current page. @@ -313,17 +313,17 @@ (pdf-outline-move-to-page page))) (defun pdf-outline-quit-and-kill () - "Quit browing the outline and kill it's buffer." + "Quit browsing the outline and kill it's buffer." (interactive) (pdf-outline-quit t)) (defun pdf-outline-quit (&optional kill) - "Quit browing the outline buffer." + "Quit browsing the outline buffer." (interactive "P") (let ((win (selected-window))) (pdf-outline-select-pdf-window t) (quit-window kill win))) - + (defun pdf-outline-up-heading (arg &optional invisible-ok) "Like `outline-up-heading', but `push-mark' first." (interactive "p") @@ -331,7 +331,7 @@ (outline-up-heading arg invisible-ok) (unless (= pos (point)) (push-mark pos)))) - + (defun pdf-outline-end-of-buffer () "Move to the end of the outline buffer." (interactive) @@ -343,7 +343,7 @@ (forward-line -1)) (unless (= pos (point)) (push-mark pos)))) - + (defun pdf-outline-link-at-pos (&optional pos) (unless pos (setq pos (point))) (let ((button (or (button-at pos) @@ -351,7 +351,7 @@ (and button (button-get button 'pdf-outline-link)))) - + (defun pdf-outline-follow-link (&optional pos) "Select PDF window and move to the page corresponding to POS." (interactive) @@ -372,7 +372,7 @@ (unless link (error "Nothing to follow here")) (pdf-links-action-perform link))) - + (defun pdf-outline-display-link (&optional pos) "Display the page corresponding to the link at POS." (interactive) @@ -399,12 +399,12 @@ (select-window win)))) (defun pdf-outline-toggle-subtree () - "Toggel hidden state of the current complete subtree." + "Toggle hidden state of the current complete subtree." (interactive) (save-excursion (outline-back-to-heading) (if (not (outline-invisible-p (line-end-position))) - (hide-subtree) + (hide-subtree) (show-subtree)))) (defun pdf-outline-move-to-page (page) @@ -423,7 +423,7 @@ (outline-up-heading 1 t) (show-children))) (back-to-indentation)) - + (defun pdf-outline-position-of-page (page) (let (curpage) (save-excursion @@ -432,13 +432,13 @@ (< curpage page)) (forward-line)) (point)))) - - + + ;; ;; Imenu Support -;; - +;; + ;;;###autoload (defun pdf-outline-imenu-enable () @@ -460,7 +460,7 @@ (when (eq pdf-view-mode-map (keymap-parent (current-local-map))) (use-local-map (keymap-parent (current-local-map))))) - + (defun pdf-outline-imenu-create-item (link &optional labels) (let-alist link @@ -470,7 +470,7 @@ 0 'pdf-outline-imenu-activate-link link))) - + (defun pdf-outline-imenu-create-index-flat () (let ((labels (and pdf-outline-display-labels (pdf-info-pagelabels))) @@ -481,8 +481,8 @@ (push (pdf-outline-imenu-create-item item labels) index)))) (nreverse index))) - - + + (defun pdf-outline-imenu-create-index-tree () (pdf-outline-imenu-create-index-tree-1 (pdf-outline-treeify-outline-list @@ -560,16 +560,16 @@ (let ((menulist (copy-sequence menulist)) keep-at-top) (if (memq imenu--rescan-item menulist) - (setq keep-at-top (list imenu--rescan-item) - menulist (delq imenu--rescan-item menulist))) + (setq keep-at-top (list imenu--rescan-item) + menulist (delq imenu--rescan-item menulist))) (if (> (length menulist) imenu-max-items) - (setq menulist - (mapcar - (lambda (menu) - (cons (format "From: %s" (caar menu)) menu)) - (imenu--split menulist imenu-max-items)))) + (setq menulist + (mapcar + (lambda (menu) + (cons (format "From: %s" (caar menu)) menu)) + (imenu--split menulist imenu-max-items)))) (cons title - (nconc (nreverse keep-at-top) menulist)))) + (nconc (nreverse keep-at-top) menulist)))) ;; bugfix for imenu in Emacs 24.3 and below. (when (condition-case nil @@ -592,3 +592,7 @@ (provide 'pdf-outline) ;;; pdf-outline.el ends here + +;; Local Variables: +;; byte-compile-warnings: (not obsolete) +;; End: diff -Nru emacs-pdf-tools-0.70/lisp/pdf-sync.el emacs-pdf-tools-0.80/lisp/pdf-sync.el --- emacs-pdf-tools-0.70/lisp/pdf-sync.el 2016-06-05 12:32:19.000000000 +0000 +++ emacs-pdf-tools-0.80/lisp/pdf-sync.el 2017-09-10 03:47:50.000000000 +0000 @@ -18,7 +18,7 @@ ;; along with this program. If not, see . ;;; Commentary: -;; +;; ;; The backward search uses a heuristic, which is pretty simple, but ;; effective: It extracts the text around the click-position in the ;; PDF, normalizes it's whitespace, deletes certain notorious @@ -41,7 +41,7 @@ (defgroup pdf-sync nil "Jump from TeX sources to PDF pages and back." :group 'pdf-tools) - + (defcustom pdf-sync-forward-display-pdf-key "C-c C-g" "Key to jump from a TeX buffer to it's PDF file. @@ -156,7 +156,7 @@ the exact location of the clicked-upon text in the PDF." :group 'pdf-sync :type 'boolean) - + (defcustom pdf-sync-backward-text-translations '((88 "X" "sum") (94 "textasciicircum") @@ -275,7 +275,7 @@ :group 'pdf-sync :type '(alist :key-type character :value-type (repeat string))) - + (defconst pdf-sync-backward-text-flush-regexp "[][.·{}|\\]\\|\\C.\\|-\n+" "Regexp of ignored text when backward searching.") @@ -296,7 +296,7 @@ (unless image (error "Outside of image area")) (pdf-sync-backward-search (car xy) (cdr xy)))) - + (defun pdf-sync-backward-search (x y) "Go to the source corresponding to image coordinates X, Y. @@ -334,7 +334,7 @@ data) (list source (if (not pdf-sync-backward-use-heuristic) - (lambda nil + (lambda nil (pdf-util-goto-position line column)) (let ((context (pdf-sync-backward--get-text-context page x y))) (lambda nil @@ -356,7 +356,7 @@ words swords similarity-fn 'infix))) (setq alignment (cl-remove-if-not 'car (cdr alignment))) (cl-assert (< windex (length alignment))) - + (let ((word (cdr (nth windex alignment)))) (unless word (setq chindex 0 @@ -378,7 +378,7 @@ ((eq limit 'line) (cons (line-beginning-position) (line-end-position))) - + ;; Synctex usually jumps to the end macro, in case it ;; does not understand the environment. ((and (fboundp 'LaTeX-find-matching-begin) @@ -469,12 +469,12 @@ prefix suffix pdf-sync-backward-text-flush-regexp pdf-sync-backward-text-translations)))) - + (defun pdf-sync-backward--tokenize (prefix &optional suffix flush-re translation) (with-temp-buffer (when prefix (insert prefix)) (let* ((center (copy-marker (point))) - (case-fold-search nil)) + (case-fold-search nil)) (when suffix (insert suffix)) (goto-char 1) ;; Delete ignored text. @@ -521,7 +521,7 @@ Don't move if already at the beginning, or if not at a word character. -This function is ment to be put on `pdf-sync-backward-hook', when +This function is meant to be put on `pdf-sync-backward-hook', when word-level searching is desired." (interactive) (unless (or (looking-at "\\b\\w") @@ -553,7 +553,7 @@ (let ((functions '(pdf-sync-backward-search pdf-sync-backward--tokenize - pdf-util-seq-alignment))) + pdf-util-seq-alignment))) (cond (pdf-sync-backward-debug-minor-mode (dolist (fn functions) @@ -591,7 +591,7 @@ (insert sep) (insert (nth 0 (car text))) (insert (propertize "<|>" 'face highlight)) - (insert (nth 1 (car text))) + (insert (nth 1 (car text))) (insert sep) (insert (propertize "Text Token:" 'face 'font-lock-keyword-face)) (insert sep) @@ -660,7 +660,7 @@ (insert sep) (goto-char 1) (pop-to-buffer (current-buffer)))))) - + ;; * ================================================================== * ;; * Forward search (TeX -> PDF) @@ -676,16 +676,19 @@ (with-selected-window (display-buffer buffer pdf-sync-forward-display-action) (pdf-util-assert-pdf-window) - (pdf-view-goto-page page) - (let ((top (* y1 (cdr (pdf-view-image-size))))) - (pdf-util-tooltip-arrow (round top)))) + (when page + (pdf-view-goto-page page) + (when y1 + (let ((top (* y1 (cdr (pdf-view-image-size))))) + (pdf-util-tooltip-arrow (round top)))))) (with-current-buffer buffer (run-hooks 'pdf-sync-forward-hook))))) (defun pdf-sync-forward-correlate (&optional line column) "Find the PDF location corresponding to LINE, COLUMN. -Returns a list \(PDF PAGE X1 Y1 X2 Y2\)." +Returns a list \(PDF PAGE X1 Y1 X2 Y2\), where PAGE, X1, Y1, X2 +and Y2 may be nil, if the destination could not be found." (unless (fboundp 'TeX-master-file) (error "This function works only with AUCTeX")) (unless line (setq line (line-number-at-pos))) @@ -695,24 +698,16 @@ (with-no-warnings (TeX-master-file "pdf")))) (sfilename (pdf-sync-synctex-file-name (buffer-file-name) pdf))) - (condition-case err - (cons pdf - (let-alist (pdf-info-synctex-forward-search - (or sfilename - (buffer-file-name)) - line column pdf) - (cons .page .edges))) - (error - (if (null sfilename) - (signal (car err) (cdr err)) - ;; It would be embarassing, if the unmodified buffer-file-name - ;; would actually work for some reason. - (condition-case nil - (cons pdf - (let-alist (pdf-info-synctex-forward-search - (buffer-file-name) line column pdf) - (cons .page .edges))) - (error (signal (car err) (cdr err))))))))) + (cons pdf + (condition-case error + (let-alist (pdf-info-synctex-forward-search + (or sfilename + (buffer-file-name)) + line column pdf) + (cons .page .edges)) + (error + (message "%s" (error-message-string error)) + (list nil nil nil nil nil)))))) @@ -725,7 +720,7 @@ Returns either the absolute path of the database or nil. -See als `pdf-sync-locate-synctex-file-functions'." +See also `pdf-sync-locate-synctex-file-functions'." (cl-check-type pdffile string) (setq pdffile (expand-file-name pdffile)) (or (run-hook-with-args-until-success @@ -785,7 +780,7 @@ (setq end beg beg (point-min)) (goto-char beg))))))))) - + ;; * ================================================================== * ;; * Compatibility diff -Nru emacs-pdf-tools-0.70/lisp/pdf-tools.el emacs-pdf-tools-0.80/lisp/pdf-tools.el --- emacs-pdf-tools-0.70/lisp/pdf-tools.el 2016-06-05 12:32:19.000000000 +0000 +++ emacs-pdf-tools-0.80/lisp/pdf-tools.el 2017-09-10 03:47:50.000000000 +0000 @@ -5,7 +5,7 @@ ;; Author: Andreas Politz ;; Keywords: files, multimedia ;; Package: pdf-tools -;; Version: 0.70 +;; Version: 0.80 ;; Package-Requires: ((emacs "24.3") (tablist "0.70") (let-alist "1.0.4")) ;; This program is free software; you can redistribute it and/or modify @@ -30,7 +30,7 @@ ;; ;; Note: This package requires external libraries and works currently ;; only on GNU/Linux systems. -;; +;; ;; Note: If you ever update it, you need to restart Emacs afterwards. ;; ;; To activate the package put @@ -48,36 +48,36 @@ ;; offers some customization options. ;; Features: -;; +;; ;; * View ;; View PDF documents in a buffer with DocView-like bindings. -;; -;; * Isearch +;; +;; * Isearch ;; Interactively search PDF documents like any other buffer. (Though ;; there is currently no regexp support.) -;; +;; ;; * Follow links ;; Click on highlighted links, moving to some part of a different ;; page, some external file, a website or any other URI. Links may ;; also be followed by keyboard commands. -;; +;; ;; * Annotations ;; Display and list text and markup annotations (like underline), ;; edit their contents and attributes (e.g. color), move them around, ;; delete them or create new ones and then save the modifications ;; back to the PDF file. -;; +;; ;; * Attachments ;; Save files attached to the PDF-file or list them in a dired buffer. -;; +;; ;; * Outline ;; Use imenu or a special buffer to examine and navigate the PDF's ;; outline. -;; +;; ;; * SyncTeX ;; Jump from a position on a page directly to the TeX source and ;; vice-versa. -;; +;; ;; * Misc ;; + Display PDF's metadata. ;; + Mark a region and kill the text from the PDF. @@ -125,7 +125,7 @@ pdf-view-auto-slice-minor-mode pdf-occur-global-minor-mode pdf-virtual-global-minor-mode)) - + (defcustom pdf-tools-enabled-modes '(pdf-history-minor-mode pdf-isearch-minor-mode @@ -160,7 +160,7 @@ (defconst pdf-tools-auto-mode-alist-entry '("\\.[pP][dD][fF]\\'" . pdf-view-mode) "The entry to use for `auto-mode-alist'.") - + (defun pdf-tools-customize () "Customize Pdf Tools." (interactive) @@ -188,7 +188,7 @@ "Whether PDF Tools should handle upgrading itself." :group 'pdf-tools :type 'boolean) - + ;;;###autoload (when (and pdf-tools-handle-upgrades (boundp 'pdf-info-epdfinfo-program) @@ -247,8 +247,8 @@ ;;;###autoload (defun pdf-tools--melpa-build-server (&optional build-directory - skip-dependencies-p - callback) + skip-dependencies-p + callback) "Compile the epdfinfo program in BUILD-DIRECTORY. This is a helper function when installing via melpa. @@ -257,18 +257,12 @@ CALLBACK may be a function, which will be locally put on `compilation-finish-functions', which see." + (if (file-executable-p pdf-info-epdfinfo-program) (message "%s" "Server already build.") - (unless (executable-find "make") - (error "Executable `make' command not found")) - (unless build-directory - (setq build-directory - (expand-file-name - "build" - (file-name-directory pdf-info-epdfinfo-program)))) - (unless (file-directory-p build-directory) - (error "No such directory: %s" build-directory)) - (let* ((have-apt-and-sudo + (let* ((make-cmd + (if (eq system-type 'berkeley-unix) "gmake" "make")) + (have-apt-and-sudo (and (executable-find "apt-get") (executable-find "sudo"))) (install-server-deps @@ -282,11 +276,33 @@ (lambda (&rest _) (setq compilation-buffer (generate-new-buffer-name "*compile pdf-tools*"))))) - (compile - (format "make V=0 -kC '%s' %smelpa-build" - build-directory - (if install-server-deps "install-server-deps " " ")) - install-server-deps) + (unless (eq system-type 'windows-nt) + (unless (executable-find make-cmd) + (error "Executable `%s' command not found" + make-cmd))) + (unless build-directory + (setq build-directory + (expand-file-name + "build" + (file-name-directory pdf-info-epdfinfo-program)))) + (unless (file-directory-p build-directory) + (error "No such directory: %s" build-directory)) + (if (not (eq system-type 'windows-nt)) + (compile + (format "%s V=0 -kC '%s' %smelpa-build" + make-cmd + build-directory + (if install-server-deps "install-server-deps " " ")) + install-server-deps) + (let* ((arch (if (equal "X86_64" + (upcase (car (split-string system-configuration "-")))) + "MINGW64" "MINGW32")) + (msys2-install-directory + (file-name-directory (read-file-name "Path to msys2_shell.bat: ")))) + (compile (format "%susr/bin/bash.exe --login -c 'MSYSTEM=%s source /etc/profile; LANG=C make V=0 -kC \"%s\" melpa-build'" + msys2-install-directory + arch + build-directory)))) (when (and compilation-buffer (buffer-live-p (get-buffer compilation-buffer))) (when callback @@ -308,7 +324,7 @@ (defun pdf-tools-assert-pdf-buffer (&optional buffer) (unless (pdf-tools-pdf-buffer-p buffer) (error "Buffer does not contain a PDF document"))) - + (defun pdf-tools-set-modes-enabled (enable &optional modes) (dolist (m (or modes pdf-tools-enabled-modes)) (let ((enabled-p (and (boundp m) diff -Nru emacs-pdf-tools-0.70/lisp/pdf-util.el emacs-pdf-tools-0.80/lisp/pdf-util.el --- emacs-pdf-tools-0.70/lisp/pdf-util.el 2016-06-05 12:32:19.000000000 +0000 +++ emacs-pdf-tools-0.80/lisp/pdf-util.el 2017-09-10 03:47:50.000000000 +0000 @@ -21,7 +21,7 @@ ;;; Commentary: ;; ;;; Todo: -;; +;; ;;; Code: @@ -127,7 +127,7 @@ ;; * ================================================================== * -;; * Transforming coordinates +;; * Transforming coordinates ;; * ================================================================== * @@ -467,7 +467,7 @@ Return the required vscroll in lines or nil, if scrolling is not needed." - + (pdf-util-assert-pdf-window) (let* ((win (window-inside-pixel-edges)) (image-height (cdr (pdf-view-image-size t))) @@ -501,7 +501,7 @@ Scroll as little as necessary. Unless EAGER-P is non-nil, in which case scroll as much as possible." - + (let ((vscroll (pdf-util-required-vscroll edges eager-p)) (hscroll (pdf-util-required-hscroll edges eager-p))) (when vscroll @@ -560,7 +560,7 @@ (defun pdf-util-delete-dedicated-directory () "Delete current buffer's dedicated directory." (delete-directory (pdf-util-dedicated-directory) t)) - + (defun pdf-util-expand-file-name (name) "Expand filename against current buffer's dedicated directory." (expand-file-name name (pdf-util-dedicated-directory))) @@ -575,7 +575,7 @@ ;; * ================================================================== * -;; * Various +;; * Various ;; * ================================================================== * (defmacro pdf-util-debug (&rest body) @@ -603,7 +603,7 @@ (and (window-live-p window) (with-selected-window window (pdf-util-pdf-buffer-p)))) - + (defun pdf-util-assert-pdf-window (&optional window) (unless (pdf-util-pdf-window-p window) (error "Window's buffer is not in PdfView mode"))) @@ -627,7 +627,7 @@ (defun pdf-util-hexcolor (color) "Return COLOR in hex-format. -Singal an error, if color is invalid." +Singal an error, if color is invalid." (if (string-match "\\`#[[:xdigit:]]\\{6\\}\\'" color) color (let ((values (color-values color))) @@ -705,9 +705,9 @@ (pdf-util-tooltip-in-window (propertize " " 'display (propertize - "\u2192" ;;right arrow - 'display '(height 2) - 'face `(:foreground + "\u2192" ;;right arrow + 'display '(height 2) + 'face `(:foreground "orange red" :background ,(if (bound-and-true-p pdf-view-midnight-minor-mode) @@ -719,7 +719,7 @@ (defadvice enable-theme (after pdf-util-clear-faces-cache activate) (clrhash pdf-util--face-colors-cache)) - + (defun pdf-util-face-colors (face &optional dark-p) "Return both colors of FACE as a cons. @@ -798,7 +798,7 @@ COLUMN defaults to 0. Widen the buffer, if the position is outside the current limits." - (let ((pos + (let ((pos (when (> line 0) (save-excursion (save-restriction @@ -825,7 +825,7 @@ ALIGNMENT-TYPE may be one of the symbols `prefix', `suffix', `infix' or nil. If it is `prefix', trailing elements in SEQ2 may -be ignored. For example the alignment of +be ignored. For example the alignment of \(0 1\) and \(0 1 2\) @@ -907,7 +907,7 @@ "Escape STRING for use as a PCRE. See also `regexp-quote'." - + (let ((to-escape (eval-when-compile (append "\0\\|()[]{}^$*+?." nil))) (chars (append string nil)) @@ -979,7 +979,7 @@ `:commands' A list of strings representing arguments to convert for image manipulations. It may contain %-escape characters, as -follows. +follows. %f -- Expands to the foreground color. %b -- Expands to the background color. @@ -1077,7 +1077,7 @@ (delete-file in-file)) (when (file-exists-p out-file) (delete-file out-file))))) - + (defun pdf-util-convert--create-commands (spec) (let ((fg "red") @@ -1134,10 +1134,10 @@ (>= x 0) (or (null relative-p) (<= x 1)))) - obj))) + obj))) (defun pdf-util-edges-empty-p (edges) - "Return non-nil, if EDGES area is empty." + "Return non-nil, if EDGES area is empty." (pdf-util-with-edges (edges) (or (<= edges-width 0) (<= edges-height 0)))) diff -Nru emacs-pdf-tools-0.70/lisp/pdf-view.el emacs-pdf-tools-0.80/lisp/pdf-view.el --- emacs-pdf-tools-0.70/lisp/pdf-view.el 2016-06-05 12:32:19.000000000 +0000 +++ emacs-pdf-tools-0.80/lisp/pdf-view.el 2017-09-10 03:47:50.000000000 +0000 @@ -19,9 +19,10 @@ ;; along with this program. If not, see . ;;; Commentary: -;; + +;; Functions related to viewing PDF documents. + ;;; Code: -;; (require 'image-mode) (require 'pdf-util) @@ -29,6 +30,7 @@ (require 'pdf-cache) (require 'jka-compr) (require 'bookmark) +(require 'password-cache) ;; * ================================================================== * @@ -57,7 +59,7 @@ "Fractional amount of resizing of one resize command." :group 'pdf-view :type 'number) - + (defcustom pdf-view-continuous t "In Continuous mode reaching the page edge advances to next/previous page. @@ -152,7 +154,7 @@ See :relief property in Info node `(elisp) Image Descriptors'." :group 'pdf-view - :type '(integer :tag "Pixel") + :type '(integer :tag "Pixel") :link '(info-link "(elisp) Image Descriptors")) (defcustom pdf-view-max-image-width 4800 @@ -160,6 +162,28 @@ :group 'pdf-view :type '(integer :tag "Pixel")) +(defcustom pdf-view-use-unicode-ligther t + "Whether to use unicode symbols in the mode-line + +On some systems finding a font which supports those symbols can +take some time. If you don't want to spend that time waiting and +don't care for a nicer looking mode-line, set this variable to +nil. + +Note, that this option has only an effect when this library is +loaded." + :group 'pdf-view + :type 'boolean) + +(defcustom pdf-view-incompatible-modes + '(linum-mode linum-relative-mode helm-linum-relative-mode + nlinum-mode nlinum-hl-mode nlinum-relative-mode yalinum-mode) + "A list of modes incompatible with `pdf-view-mode'. + +Issue a warning, if one of them is active in a PDF buffer." + :group 'pdf-view + :type '(repeat symbol)) + ;; * ================================================================== * ;; * Internal variables and macros @@ -193,20 +217,31 @@ "Local, dedicated register for PDF positions.") (defmacro pdf-view-current-page (&optional window) + ;;TODO: write documentation! `(image-mode-window-get 'page ,window)) + (defmacro pdf-view-current-overlay (&optional window) + ;;TODO: write documentation! `(image-mode-window-get 'overlay ,window)) + (defmacro pdf-view-current-image (&optional window) + ;;TODO: write documentation! `(image-mode-window-get 'image ,window)) + (defmacro pdf-view-current-slice (&optional window) + ;;TODO: write documentation! `(image-mode-window-get 'slice ,window)) + (defmacro pdf-view-current-window-size (&optional window) + ;;TODO: write documentation! `(image-mode-window-get 'window-size ,window)) (defun pdf-view-active-region-p nil + "Return t if there are active regions." (not (null pdf-view-active-region))) (defmacro pdf-view-assert-active-region () + "Signal an error if there are no active regions." `(unless (pdf-view-active-region-p) (error "The region is not active"))) @@ -266,7 +301,7 @@ (define-key map (kbd "C-c C-d") 'pdf-view-dark-minor-mode) (define-key map (kbd "m") 'pdf-view-position-to-register) (define-key map (kbd "'") 'pdf-view-jump-to-register) - + (define-key map (kbd "C-c C-i") 'pdf-view-extract-region-image) ;; Rendering (define-key map (kbd "C-c C-r m") 'pdf-view-midnight-minor-mode) @@ -287,7 +322,7 @@ (let ((file-name-handler-alist nil)) (not (and buffer-file-name (file-readable-p buffer-file-name))))) - (pdf-tools-pdf-buffer-p)) + (pdf-tools-pdf-buffer-p)) (let ((tempfile (pdf-util-make-temp-file (concat (if buffer-file-name (file-name-nondirectory @@ -344,20 +379,62 @@ (add-hook 'kill-buffer-hook 'pdf-view-close-document nil t) (pdf-view-add-hotspot-function 'pdf-view-text-regions-hotspots-function -9) - + ;; Keep track of display info (add-hook 'image-mode-new-window-functions 'pdf-view-new-window-function nil t) (image-mode-setup-winprops) + ;; Decryption needs to be done before any other function calls into + ;; pdf-info.el . + (pdf-view-decrypt-document) + ;; Issue a warning in the future about incompatible modes. + (run-with-timer 1 nil #'pdf-view-check-incompatible-modes + (current-buffer)) ;; Setup initial page and start display (pdf-view-goto-page (or (pdf-view-current-page) 1))) +(defun pdf-view-check-incompatible-modes (&optional buffer) + "Check BUFFER for incompatible modes, maybe issue a warning." + (with-current-buffer (or buffer (current-buffer)) + (let ((modes + (cl-remove-if-not + (lambda (mode) (and (symbolp mode) + (boundp mode) + (symbol-value mode))) + pdf-view-incompatible-modes))) + (when modes + (display-warning + 'pdf-view + (format "These modes are incompatible with `pdf-view-mode', + please deactivate them (or customize pdf-view-incompatible-modes): %s" + (mapconcat #'symbol-name modes ","))))))) + +(defun pdf-view-decrypt-document () + "Read a password, if the document is encrypted and open it." + (interactive) + (when (pdf-info-encrypted-p) + (let ((prompt (format "Enter password for `%s': " + (abbreviate-file-name + (buffer-file-name)))) + (key (concat "/pdf-tools" (buffer-file-name))) + (i 3) + password) + (while (and (> i 0) + (pdf-info-encrypted-p)) + (setq i (1- i)) + (setq password (password-read prompt key)) + (setq prompt "Invalid password, try again: ") + (ignore-errors (pdf-info-open nil password))) + (pdf-info-open nil password) + (password-cache-add key password))) + nil) + (defun pdf-view-buffer-file-name () "Return the local filename of the PDF in the current buffer. -This may be different from `buffer-file-name', when operating on -a local copy of a remote file." +This may be different from variable `buffer-file-name' when +operating on a local copy of a remote file." (or pdf-view--buffer-file-name (buffer-file-name))) @@ -367,8 +444,15 @@ (let ((tempfile (pdf-info-save pdf-view--server-file-name))) (unwind-protect (progn - (pdf-info-close pdf-view--server-file-name) + ;; Order matters here: We need to first copy the new + ;; content (tempfile) to the PDF, and then close the PDF. + ;; Since while closing the file (and freeing its resources + ;; in the process), it may be immediately reopened due to + ;; redisplay happening inside the pdf-info-close function + ;; (while waiting for a response from the process.). (copy-file tempfile (buffer-file-name) t) + (pdf-info-close pdf-view--server-file-name) + (when pdf-view--buffer-file-name (copy-file tempfile pdf-view--buffer-file-name t)) (clear-visited-file-modtime) @@ -380,14 +464,17 @@ (delete-file tempfile)))))) (defun pdf-view-revert-buffer (&optional ignore-auto noconfirm) - "Like `revert-buffer', but preserves the buffer's current modes." + "Revert buffer while preseving current modes. + +Optional parameters IGNORE-AUTO and NOCONFIRM are defined as in +`revert-buffer'." (interactive (list (not current-prefix-arg))) ;; Bind to default so that we can use pdf-view-revert-buffer as ;; revert-buffer-function. A binding of nil is needed in Emacs 24.3, but in ;; later versions the semantics that nil means the default function should ;; not relied upon. (let ((revert-buffer-function (when (fboundp #'revert-buffer--default) - #'revert-buffer--default)) + #'revert-buffer--default)) (after-revert-hook (cons #'pdf-info-close after-revert-hook))) @@ -396,7 +483,9 @@ (pdf-view-redisplay t)))) (defun pdf-view-close-document () - "Like `pdf-info-close', but returns immediately." + "Return immediately after closing document. + +See also `pdf-info-close', which does not return immediately." (when (pdf-info-running-p) (let ((pdf-info-asynchronous 'ignore)) (pdf-info-close)))) @@ -407,6 +496,10 @@ ;; * ================================================================== * (defun pdf-view-fit-page-to-window () + "Fit PDF to window. + +Choose the larger of PDF's height and width, and fits that +dimension to window." (interactive) (setq pdf-view-display-size 'fit-page) (image-set-window-vscroll 0) @@ -414,18 +507,26 @@ (pdf-view-redisplay t)) (defun pdf-view-fit-height-to-window () + "Fit PDF height to window." (interactive) (setq pdf-view-display-size 'fit-height) (image-set-window-vscroll 0) (pdf-view-redisplay t)) (defun pdf-view-fit-width-to-window () + "Fit PDF size to window." (interactive) (setq pdf-view-display-size 'fit-width) (image-set-window-hscroll 0) (pdf-view-redisplay t)) (defun pdf-view-enlarge (factor) + "Enlarge PDF by FACTOR. + +When called interactively, uses the value of +`pdf-view-resize-factor'. + +For example, (pdf-view-enlarge 1.25) increases size by 25%." (interactive (list (float pdf-view-resize-factor))) (let* ((size (pdf-view-image-size)) @@ -438,11 +539,18 @@ (pdf-view-redisplay t))) (defun pdf-view-shrink (factor) + "Shrink PDF by FACTOR. + +When called interactively, uses the value of +`pdf-view-resize-factor'. + +For example, (pdf-view-shrink 1.25) decreases size by 20%." (interactive (list (float pdf-view-resize-factor))) (pdf-view-enlarge (/ 1.0 factor))) (defun pdf-view-scale-reset () + "Reset PDF to its default set." (interactive) (setq pdf-view-display-size 1.0) (pdf-view-redisplay t)) @@ -454,6 +562,10 @@ ;; * ================================================================== * (defun pdf-view-goto-page (page &optional window) + "Go to PAGE in PDF. + +If optional parameter WINDOW, go to PAGE in all `pdf-view' +windows." (interactive (list (if current-prefix-arg (prefix-numeric-value current-prefix-arg) @@ -485,15 +597,27 @@ nil) (defun pdf-view-next-page (&optional n) + "View the next page in the PDF. + +Optional parameter N moves N pages forward." (interactive "p") (pdf-view-goto-page (+ (pdf-view-current-page) (or n 1)))) (defun pdf-view-previous-page (&optional n) + "View the previous page in the PDF. + +Optional parameter N moves N pages backward." (interactive "p") (pdf-view-next-page (- (or n 1)))) (defun pdf-view-next-page-command (&optional n) + "View the next page in the PDF. + +Optional parameter N moves N pages forward. + +This command is a wrapper for `pdf-view-next-page' that will +indicate to the user if they are on the last page and more." (declare (interactive-only pdf-view-next-page)) (interactive "p") (unless n (setq n 1)) @@ -521,6 +645,11 @@ (run-with-idle-timer 0.001 nil 'pdf-view-redisplay (selected-window))))) (defun pdf-view-previous-page-command (&optional n) + "View the previous page in the PDF. + +Optional parameter N moves N pages backward. + +This command is a wrapper for `pdf-view-previous-page'." (declare (interactive-only pdf-view-previous-page)) (interactive "p") (with-no-warnings @@ -537,81 +666,85 @@ (pdf-view-goto-page (pdf-cache-number-of-pages))) (defun pdf-view-scroll-up-or-next-page (&optional arg) - "Scroll page up ARG lines if possible, else goto next page. -When `pdf-view-continuous' is non-nil, scrolling upward -at the bottom edge of the page moves to the next page. -Otherwise, goto next page only on typing SPC (ARG is nil)." + "Scroll page up ARG lines if possible, else go to the next page. + +When `pdf-view-continuous' is non-nil, scrolling upward at the +bottom edge of the page moves to the next page. Otherwise, go to +next page only on typing SPC (ARG is nil)." (interactive "P") (if (or pdf-view-continuous (null arg)) (let ((hscroll (window-hscroll)) - (cur-page (pdf-view-current-page))) - (when (or (= (window-vscroll) (image-scroll-up arg)) + (cur-page (pdf-view-current-page))) + (when (or (= (window-vscroll) (image-scroll-up arg)) ;; Workaround rounding/off-by-one issues. (memq pdf-view-display-size '(fit-height fit-page))) - (pdf-view-next-page) - (when (/= cur-page (pdf-view-current-page)) - (image-bob) - (image-bol 1)) - (set-window-hscroll (selected-window) hscroll))) + (pdf-view-next-page) + (when (/= cur-page (pdf-view-current-page)) + (image-bob) + (image-bol 1)) + (set-window-hscroll (selected-window) hscroll))) (image-scroll-up arg))) (defun pdf-view-scroll-down-or-previous-page (&optional arg) - "Scroll page down ARG lines if possible, else goto previous page. -When `pdf-view-continuous' is non-nil, scrolling downward -at the top edge of the page moves to the previous page. -Otherwise, goto previous page only on typing DEL (ARG is nil)." + "Scroll page down ARG lines if possible, else go to the previous page. + +When `pdf-view-continuous' is non-nil, scrolling downward at the +top edge of the page moves to the previous page. Otherwise, go +to previous page only on typing DEL (ARG is nil)." (interactive "P") (if (or pdf-view-continuous (null arg)) (let ((hscroll (window-hscroll)) - (cur-page (pdf-view-current-page))) - (when (or (= (window-vscroll) (image-scroll-down arg)) + (cur-page (pdf-view-current-page))) + (when (or (= (window-vscroll) (image-scroll-down arg)) ;; Workaround rounding/off-by-one issues. (memq pdf-view-display-size '(fit-height fit-page))) - (pdf-view-previous-page) - (when (/= cur-page (pdf-view-current-page)) - (image-eob) - (image-bol 1)) - (set-window-hscroll (selected-window) hscroll))) + (pdf-view-previous-page) + (when (/= cur-page (pdf-view-current-page)) + (image-eob) + (image-bol 1)) + (set-window-hscroll (selected-window) hscroll))) (image-scroll-down arg))) (defun pdf-view-next-line-or-next-page (&optional arg) - "Scroll upward by ARG lines if possible, else goto next page. + "Scroll upward by ARG lines if possible, else go to the next page. + When `pdf-view-continuous' is non-nil, scrolling a line upward at the bottom edge of the page moves to the next page." (interactive "p") (if pdf-view-continuous (let ((hscroll (window-hscroll)) - (cur-page (pdf-view-current-page))) - (when (= (window-vscroll) (image-next-line arg)) - (pdf-view-next-page) - (when (/= cur-page (pdf-view-current-page)) - (image-bob) - (image-bol 1)) - (set-window-hscroll (selected-window) hscroll))) + (cur-page (pdf-view-current-page))) + (when (= (window-vscroll) (image-next-line arg)) + (pdf-view-next-page) + (when (/= cur-page (pdf-view-current-page)) + (image-bob) + (image-bol 1)) + (set-window-hscroll (selected-window) hscroll))) (image-next-line 1))) (defun pdf-view-previous-line-or-previous-page (&optional arg) - "Scroll downward by ARG lines if possible, else goto previous page. + "Scroll downward by ARG lines if possible, else go to the previous page. + When `pdf-view-continuous' is non-nil, scrolling a line downward at the top edge of the page moves to the previous page." (interactive "p") (if pdf-view-continuous (let ((hscroll (window-hscroll)) - (cur-page (pdf-view-current-page))) - (when (= (window-vscroll) (image-previous-line arg)) - (pdf-view-previous-page) - (when (/= cur-page (pdf-view-current-page)) - (image-eob) - (image-bol 1)) - (set-window-hscroll (selected-window) hscroll))) + (cur-page (pdf-view-current-page))) + (when (= (window-vscroll) (image-previous-line arg)) + (pdf-view-previous-page) + (when (/= cur-page (pdf-view-current-page)) + (image-eob) + (image-bol 1)) + (set-window-hscroll (selected-window) hscroll))) (image-previous-line arg))) (defun pdf-view-goto-label (label) - "Goto the page corresponding to LABEL. + "Go to the page corresponding to LABEL. -Usually the label of a document's page is the same as it's +Usually, the label of a document's page is the same as its displayed page number." (interactive (list (let ((labels (pdf-info-pagelabels))) @@ -619,7 +752,7 @@ (let ((index (cl-position label (pdf-info-pagelabels) :test 'equal))) (unless index (error "No such label: %s" label)) - (pdf-view-goto-page (1+ index)))) + (pdf-view-goto-page (1+ index)))) ;; * ================================================================== * @@ -627,6 +760,7 @@ ;; * ================================================================== * (defun pdf-view-set-slice (x y width height &optional window) + ;; TODO: add WINDOW to docstring. "Set the slice of the pages that should be displayed. X, Y, WIDTH and HEIGHT should be relative coordinates, i.e. in @@ -641,7 +775,8 @@ (defun pdf-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 + +Set the slice by pressing `mouse-1' at its top-left corner and dragging it to its bottom-right corner. See also `pdf-view-set-slice' and `pdf-view-reset-slice'." (interactive) @@ -649,14 +784,14 @@ 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)))) + (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)))) (apply 'pdf-view-set-slice (pdf-util-scale (list x y w h) @@ -664,6 +799,7 @@ (/ 1.0 (float (cdr size)))))))) (defun pdf-view-set-slice-from-bounding-box (&optional window) + ;; TODO: add WINDOW to docstring. "Set the slice from the page's bounding-box. The result is that the margins are almost completely cropped, @@ -686,6 +822,7 @@ (append slice (and window (list window)))))) (defun pdf-view-reset-slice (&optional window) + ;; TODO: add WINDOW to doctring. "Reset the current slice. After calling this function the whole page will be visible @@ -722,12 +859,12 @@ (defvar pdf-view-inhibit-hotspots nil) (defun pdf-view-image-type () - "Return the image-type which should be used. + "Return the image type that should be used. -The return value is either imagemagick (if available and wanted -or if png is not available) or png. +The return value is either `imagemagick' (if available and wanted +or if png is not available) or `png'. -Signal an error, if neither imagemagick nor png is available. +Signal an error, if neither `imagemagick' nor `png' is available. See also `pdf-view-use-imagemagick'." (cond ((and pdf-view-use-imagemagick @@ -741,11 +878,13 @@ (error "PNG image supported not compiled into Emacs")))) (defun pdf-view-use-scaling-p () + "Return t if scaling should be used." (and (eq 'imagemagick (pdf-view-image-type)) pdf-view-use-scaling)) (defmacro pdf-view-create-image (data &rest props) + ;; TODO: add DATA and PROPS to docstring. "Like `create-image', but with set DATA-P and TYPE arguments." (declare (indent 1) (debug t)) `(create-image ,data (pdf-view-image-type) t ,@props @@ -761,12 +900,13 @@ (* 2 (car size))))) (hotspots (pdf-view-apply-hotspot-functions window page size))) - (pdf-view-create-image data + (pdf-view-create-image data :width (car size) :map hotspots :pointer 'arrow))) (defun pdf-view-image-size (&optional displayed-p window) + ;; TODO: add WINDOW to docstring. "Return the size in pixel of the current image. If DISPLAYED-P is non-nil, return the size of the displayed @@ -778,10 +918,10 @@ (image-size (pdf-view-current-image window) t))) (defun pdf-view-image-offset (&optional window) + ;; TODO: add WINDOW to docstring. "Return the offset of the current image. It is equal to \(LEFT . TOP\) of the current slice in pixel." - (let* ((slice (pdf-view-current-slice window))) (cond (slice @@ -798,6 +938,7 @@ window)) (defun pdf-view-display-image (image &optional window inhibit-slice-p) + ;; TODO: write documentation! (let ((ol (pdf-view-current-overlay window))) (when (window-live-p (overlay-get ol 'window)) (let* ((size (image-size image t)) @@ -848,6 +989,7 @@ (force-mode-line-update))) (defun pdf-view-redisplay-pages (&rest pages) + "Redisplay PAGES in all windows." (pdf-util-assert-pdf-buffer) (dolist (window (get-buffer-window-list nil nil t)) (when (memq (pdf-view-current-page window) @@ -873,6 +1015,7 @@ (pdf-view-redisplay window))))))) (defun pdf-view-new-window-function (winprops) + ;; TODO: write documentation! ;; (message "New window %s for buf %s" (car winprops) (current-buffer)) (cl-assert (or (eq t (car winprops)) (eq (window-buffer (car winprops)) (current-buffer)))) @@ -905,6 +1048,7 @@ (or (image-mode-window-get 'page t) 1)))))) (defun pdf-view-desired-image-size (&optional page window) + ;; TODO: write documentation! (let* ((pagesize (pdf-cache-pagesize (or page (pdf-view-current-page window)))) (slice (pdf-view-current-slice window)) @@ -928,10 +1072,10 @@ (t (setq scale width-scale)))) (let ((width (floor (* (car pagesize) scale))) - (height (floor (* (cdr pagesize) scale)))) + (height (floor (* (cdr pagesize) scale)))) (when (> width (max 1 (or pdf-view-max-image-width width))) - (setq width pdf-view-max-image-width - height (* height (/ (float pdf-view-max-image-width) width)))) + (setq width pdf-view-max-image-width + height (* height (/ (float pdf-view-max-image-width) width)))) (cons (max 1 width) (max 1 height))))) (defun pdf-view-text-regions-hotspots-function (page size) @@ -975,7 +1119,7 @@ (remove-hook 'after-save-hook enable t) (remove-hook 'after-revert-hook enable t)))) (pdf-info-setoptions :render/printed pdf-view-printer-minor-mode) - (pdf-cache-clear-images) + (pdf-cache-clear-images) (pdf-view-redisplay t)) (define-minor-mode pdf-view-midnight-minor-mode @@ -1004,12 +1148,15 @@ (pdf-cache-clear-images) (pdf-view-redisplay t)) -(and (char-displayable-p ?⎙) - (setcdr (assq 'pdf-view-printer-minor-mode minor-mode-alist) - (list " ⎙" ))) -(and (char-displayable-p ?🌙) - (setcdr (assq 'pdf-view-midnight-minor-mode minor-mode-alist) - (list " 🌙" ))) +(when pdf-view-use-unicode-ligther + ;; This check uses an implementation detail, which hopefully gets the + ;; right answer. + (and (fontp (char-displayable-p ?⎙)) + (setcdr (assq 'pdf-view-printer-minor-mode minor-mode-alist) + (list " ⎙" ))) + (and (fontp (char-displayable-p ?🌙)) + (setcdr (assq 'pdf-view-midnight-minor-mode minor-mode-alist) + (list " 🌙" )))) ;; * ================================================================== * @@ -1035,10 +1182,12 @@ :key 'cdr))) (defun pdf-view-sorted-hotspot-functions () + ;; TODO: write documentation! (mapcar 'cdr (cl-sort (copy-sequence pdf-view--hotspot-functions) '> :key 'car))) (defun pdf-view-apply-hotspot-functions (window page image-size) + ;; TODO: write documentation! (unless pdf-view-inhibit-hotspots (save-selected-window (when window (select-window window)) @@ -1053,6 +1202,7 @@ ;; * ================================================================== * (defun pdf-view--push-mark () + ;; TODO: write documentation! (let (mark-ring) (push-mark-command nil)) (setq deactivate-mark nil)) @@ -1061,7 +1211,6 @@ "Return the active region, a list of edges. Deactivate the region if DEACTIVATE-P is non-nil." - (pdf-view-assert-active-region) (prog1 pdf-view-active-region @@ -1078,7 +1227,7 @@ (defun pdf-view-mouse-set-region (event &optional allow-extend-p rectangle-p) - "Selects a region of text using the mouse. + "Select a region of text using the mouse with mouse event EVENT. Allow for stacking of regions, if ALLOW-EXTEND-P is non-nil. @@ -1147,12 +1296,12 @@ (max 0 (min (cdr size) (+ (cdr begin) (cdr dxy))))))))) (let ((iregion (if rectangle-p - (list (min (car begin) (car end)) - (min (cdr begin) (cdr end)) - (max (car begin) (car end)) - (max (cdr begin) (cdr end))) - (list (car begin) (cdr begin) - (car end) (cdr end))))) + (list (min (car begin) (car end)) + (min (cdr begin) (cdr end)) + (max (car begin) (car end)) + (max (cdr begin) (cdr end))) + (list (car begin) (cdr begin) + (car end) (cdr end))))) (setq region (pdf-util-scale-pixel-to-relative iregion)) (pdf-view-display-region @@ -1165,7 +1314,7 @@ (pdf-view--push-mark)))) (defun pdf-view-mouse-extend-region (event) - "Extend the currently active region." + "Extend the currently active region with mouse event EVENT." (interactive "@e") (pdf-view-mouse-set-region event t pdf-view--have-rectangle-region)) @@ -1173,12 +1322,15 @@ (defun pdf-view-mouse-set-region-rectangle (event) "Like `pdf-view-mouse-set-region' but displays as a rectangle. +EVENT is the mouse event. + This is more useful for commands like `pdf-view-extract-region-image'." (interactive "@e") (pdf-view-mouse-set-region event nil t)) (defun pdf-view-display-region (&optional region rectangle-p) + ;; TODO: write documentation! (unless region (pdf-view-assert-active-region) (setq region pdf-view-active-region)) @@ -1196,7 +1348,7 @@ (pdf-info-renderpage-text-regions page width nil nil `(,(car colors) ,(cdr colors) ,@region))))))) - + (defun pdf-view-kill-ring-save () "Copy the region to the `kill-ring'." (interactive) @@ -1223,10 +1375,11 @@ (defun pdf-view-extract-region-image (regions &optional page size output-buffer no-display-p) + ;; TODO: what is "resp."? Avoid contractions. "Create a PNG image of REGIONS. REGIONS should have the same form as `pdf-view-active-region', -which see. PAGE and size are the page resp. base-size of the +which see. PAGE and SIZE are the page resp. base-size of the image from which the image-regions will be created; they default to `pdf-view-current-page' resp. `pdf-view-image-size'. @@ -1235,7 +1388,7 @@ In case of multiple regions, the resulting image is constructed by joining them horizontally. For this operation (and this only) -the `convert' programm is used. " +the `convert' programm is used." (interactive (list (if (pdf-view-active-region-p) @@ -1275,7 +1428,7 @@ "-gravity" "Center" "-append" "+gravity" - "-chop" "0x10+0+0") + "-chop" "0x10+0+0") :apply '((0 0 0 0)))) (with-current-buffer output-buffer (let ((inhibit-read-only t)) @@ -1294,6 +1447,7 @@ ;; * ================================================================== * (defun pdf-view-bookmark-make-record (&optional no-page no-slice no-size no-origin) + ;; TODO: add NO-PAGE, NO-SLICE, NO-SIZE, NO-ORIGIN to the docstring. "Create a bookmark PDF record. The optional, boolean args exclude certain attributes." @@ -1318,28 +1472,28 @@ ;;;###autoload (defun pdf-view-bookmark-jump-handler (bmk) - "The bookmark handler-function interface for PDF bookmarks. + "The bookmark handler-function interface for bookmark BMK. See also `pdf-view-bookmark-make-record'." (let ((page (bookmark-prop-get bmk 'page)) - (slice (bookmark-prop-get bmk 'slice)) + (slice (bookmark-prop-get bmk 'slice)) (size (bookmark-prop-get bmk 'size)) (origin (bookmark-prop-get bmk 'origin)) - (file (bookmark-prop-get bmk 'filename)) - (show-fn-sym (make-symbol "pdf-view-bookmark-after-jump-hook"))) + (file (bookmark-prop-get bmk 'filename)) + (show-fn-sym (make-symbol "pdf-view-bookmark-after-jump-hook"))) (fset show-fn-sym - (lambda () - (remove-hook 'bookmark-after-jump-hook show-fn-sym) - (unless (derived-mode-p 'pdf-view-mode) - (pdf-view-mode)) - (with-selected-window - (or (get-buffer-window (current-buffer) 0) - (selected-window)) - (when size + (lambda () + (remove-hook 'bookmark-after-jump-hook show-fn-sym) + (unless (derived-mode-p 'pdf-view-mode) + (pdf-view-mode)) + (with-selected-window + (or (get-buffer-window (current-buffer) 0) + (selected-window)) + (when size (setq-local pdf-view-display-size size)) (when slice (apply 'pdf-view-set-slice slice)) - (when (numberp page) + (when (numberp page) (pdf-view-goto-page page)) (when origin (let ((size (pdf-view-image-size t))) @@ -1368,7 +1522,7 @@ (let (bookmark-after-jump-hook) (pdf-view-bookmark-jump-handler bmk) (run-hooks 'bookmark-after-jump-hook)))) - + (defun pdf-view-registerv-make () "Create a PDF register entry of the current position." (registerv-make @@ -1397,7 +1551,7 @@ 0))))) (defmacro pdf-view-with-register-alist (&rest body) - "Setup the proper binding for `register-alist' in body. + "Setup the proper binding for `register-alist' in BODY. This macro may not work as desired when it is nested. See also `pdf-view-use-dedicated-register'." @@ -1412,7 +1566,7 @@ (progn ,@body) (when ,dedicated-p (setq pdf-view-register-alist register-alist)))))) - + (defun pdf-view-position-to-register (register) "Store current PDF position in register REGISTER. @@ -1424,10 +1578,13 @@ (set-register register (pdf-view-registerv-make)))) (defun pdf-view-jump-to-register (register &optional delete return-register) - "Move point to a position stored in a REGISTER." + ;; TODO: add RETURN-REGISTER to the docstring. + "Move point to a position stored in a REGISTER. + +Optional parameter DELETE is defined as in `jump-to-register'." (interactive (pdf-view-with-register-alist - (list + (list (register-read-with-preview "Jump to register: ") current-prefix-arg (and (or pdf-view-use-dedicated-register diff -Nru emacs-pdf-tools-0.70/lisp/pdf-virtual.el emacs-pdf-tools-0.80/lisp/pdf-virtual.el --- emacs-pdf-tools-0.70/lisp/pdf-virtual.el 2016-06-05 12:32:19.000000000 +0000 +++ emacs-pdf-tools-0.80/lisp/pdf-virtual.el 2017-09-10 03:47:50.000000000 +0000 @@ -28,7 +28,7 @@ ;; ;; The trickiest part is to make theses intermediate functions behave ;; like the pdf-info-* equivalents in both the synchronous and -;; asynchronous case. +;; asynchronous case. ;;; Code: (eval-when-compile @@ -316,7 +316,7 @@ \(FILENAME \(FILE-FIRT-PAGE . FILE-LAST-PAGE\) REGION\) . " - + (let ((begin (car pages)) (end (cdr pages))) (unless (<= begin end) @@ -328,7 +328,7 @@ (signal 'args-out-of-range (list 'pages pages))) (while (<= begin end) (let* ((page (aref arr (1- begin))) - (filename (pdf-virtual-range-filename page)) + (filename (pdf-virtual-range-filename page)) (offset (- (1- begin) (pdf-virtual-range-index-start page))) (first (+ (pdf-virtual-range-first page) @@ -337,7 +337,7 @@ (pdf-virtual-range-last page))) (region (pdf-virtual-range-region page))) (push `(,filename (,first . ,last) ,region) result) - (cl-incf begin (1+ (- last first))))) + (cl-incf begin (1+ (- last first))))) (nreverse result)))) (pdf-virtual-document-defun number-of-pages (doc) @@ -435,7 +435,7 @@ (pdf-virtual-range-filename other))))))) (when page (1+ (pdf-virtual-range-index-start page))))) - + ;; * ================================================================== * ;; * Modes @@ -449,7 +449,7 @@ ;;;###autoload -(define-derived-mode pdf-virtual-edit-mode emacs-lisp-mode "VPDF-Edit" +(define-derived-mode pdf-virtual-edit-mode emacs-lisp-mode "VPDF-Edit" "Major mode when editing a virtual PDF buffer." (buffer-enable-undo) (setq-local buffer-read-only nil) @@ -498,7 +498,7 @@ (advice-add 'pdf-virtual-view-mode :around 'pdf-virtual-view-mode-prepare) -;; This needs to run before pdf-view-mode does it's thing. +;; This needs to run before pdf-view-mode does its thing. (defun pdf-virtual-view-mode-prepare (fn) (let (list unreadable) (save-excursion @@ -539,7 +539,7 @@ (with-current-buffer (generate-new-buffer buffer-name) (insert ";; %VPDF 1.0\n\n") (insert ";; File Format -;; +;; ;; FORMAT ::= ( FILES* ) ;; FILES ::= ( FILE . PAGE-SPEC* ) ;; PAGE-SPEC ::= PAGE | ( PAGE . REGION ) @@ -602,7 +602,7 @@ pdf-virtual-document)) (page (aref pages (1- pn))) (first-filepage (1+ (pdf-virtual-range-index-start page)))) - + (when (and (< n 0) (not (= first-filepage pn))) (cl-incf n)) @@ -1035,5 +1035,8 @@ (pdf-virtual-define-adapter getoptions (&optional file-or-buffer) (signal 'pdf-virtual-unsupported-operation (list 'getoptions))) +(pdf-virtual-define-adapter encrypted-p (&optional file-or-buffer) + nil) + (provide 'pdf-virtual) ;;; pdf-virtual.el ends here diff -Nru emacs-pdf-tools-0.70/lisp/tablist.el emacs-pdf-tools-0.80/lisp/tablist.el --- emacs-pdf-tools-0.70/lisp/tablist.el 2016-06-05 12:32:19.000000000 +0000 +++ emacs-pdf-tools-0.80/lisp/tablist.el 1970-01-01 00:00:00.000000000 +0000 @@ -1,1949 +0,0 @@ -;;; tablist.el --- Extended tabulated-list-mode -*- lexical-binding: t -*- - -;; Copyright (C) 2013, 2014 Andreas Politz - -;; Author: Andreas Politz -;; Keywords: extensions, lisp -;; Package: tablist -;; Version: 0.70 -;; Package-Requires: ((emacs "24.3")) - -;; This program is free software; you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation, either version 3 of the License, or -;; (at your option) any later version. - -;; This program 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 this program. If not, see . - -;;; Commentary: -;; -;; This package adds marks and filters to tabulated-list-mode. It -;; also kind of puts a dired face on tabulated list buffers. -;; -;; It can be used by deriving from tablist-mode and some features by -;; using tablist-minor-mode inside a tabulated-list-mode buffer. -;; - -(require 'cl-lib) -(require 'ring) -(require 'tabulated-list) -(require 'dired) -(require 'tablist-filter) - -;; -;; *Macros -;; - -(defmacro tablist-save-marks (&rest body) - "Eval body, while preserving all marks." - (let ((marks (make-symbol "marks"))) - `(let (,marks) - (save-excursion - (goto-char (point-min)) - (let ((re "^\\([^ ]\\)")) - (while (re-search-forward re nil t) - (push (cons (tabulated-list-get-id) - (tablist-get-mark-state)) - ,marks)))) - (unwind-protect - (progn ,@body) - (save-excursion - (dolist (m ,marks) - (let ((id (pop m))) - (goto-char (point-min)) - (while (and id (not (eobp))) - (when (equal id (tabulated-list-get-id)) - (tablist-put-mark-state m) - (setq id nil)) - (forward-line))))))))) - -(defmacro tablist-with-remembering-entry (&rest body) - "Remember where body left of and restore previous position. - -If the current entry is still visible, move to it. Otherwise move -to the next visible one after it. If that also fails, goto to -the beginning of the buffer. Finally move point to the major -column." - (declare (indent 0) (debug t)) - (let ((re (make-symbol "re")) - (id (make-symbol "id")) - (col (make-symbol "col"))) - `(let ((,re - (replace-regexp-in-string - "[\t ]+" "[\t ]*" (regexp-quote - (or (thing-at-point 'line) "")) - t t)) - (,id (tabulated-list-get-id)) - (,col (tablist-current-column))) - (progn - ,@body - (let (success pos) - (goto-char (point-min)) - (setq pos (point)) - (while (and (setq success (re-search-forward ,re nil t)) - (> (point) (prog1 pos (setq pos (point)))) - (forward-line -1) - (not (equal ,id (tabulated-list-get-id)))) - (forward-line)) - (unless success - (goto-char (point-min)) - (while (and (not (eobp)) - (not success)) - (if (equal (tabulated-list-get-id) ,id) - (setq success t) - (forward-line)))) - (unless (and success (not (invisible-p (point)))) - (goto-char (point-min))) - (tablist-skip-invisible-entries) - (tablist-move-to-column - (or ,col (car (tablist-major-columns)))) - (dolist (win (get-buffer-window-list)) - (set-window-point win (point)))))))) - -(defmacro tablist-with-filter-displayed (&rest body) - "Display the current filter in the mode while evalling BODY." - (let ((state (make-symbol "state"))) - `(let ((,state (tablist-display-filter 'state))) - (tablist-display-filter t) - (unwind-protect - (progn ,@body) - (tablist-display-filter ,state))))) - -;; -;; *Mode Maps -;; - -(defvar tablist-mode-filter-map - (let ((kmap (make-sparse-keymap))) - (define-key kmap "p" 'tablist-pop-filter) - (define-key kmap "r" 'tablist-push-regexp-filter) - (define-key kmap "=" 'tablist-push-equal-filter) - (define-key kmap "n" 'tablist-push-numeric-filter) - (define-key kmap "!" 'tablist-negate-filter) - (define-key kmap "t" 'tablist-toggle-first-filter-logic) - (define-key kmap "/" 'tablist-display-filter) - (define-key kmap "z" 'tablist-suspend-filter) - - (define-key kmap "a" 'tablist-push-named-filter) - (define-key kmap "s" 'tablist-name-current-filter) - (define-key kmap "D" 'tablist-delete-named-filter) - (define-key kmap "d" 'tablist-deconstruct-named-filter) - (define-key kmap "e" 'tablist-edit-filter) - (define-key kmap "C" 'tablist-clear-filter) - kmap)) - -(defvar tablist-mode-mark-map - (let ((kmap (make-sparse-keymap))) - (define-key kmap "c" 'tablist-change-marks) - (define-key kmap "!" 'tablist-unmark-all-marks) - (define-key kmap "r" 'tablist-mark-items-regexp) - (define-key kmap "n" 'tablist-mark-items-numeric) - (define-key kmap "m" 'tablist-mark-forward) - kmap)) - -(defvar tablist-mode-regexp-map - (let ((kmap (make-sparse-keymap))) - ;; (define-key kmap "&" 'tablist-flag-gargabe-items) - (define-key kmap "m" 'tablist-mark-items-regexp) - kmap)) - -(defvar tablist-minor-mode-map - (let ((kmap (make-sparse-keymap))) - (define-key kmap "m" 'tablist-mark-forward) - (define-key kmap (kbd "DEL") 'tablist-unmark-backward) - (define-key kmap "k" 'tablist-do-kill-lines) - (define-key kmap "U" 'tablist-unmark-all-marks) - (define-key kmap "u" 'tablist-unmark-forward) - (define-key kmap "t" 'tablist-toggle-marks) - - (define-key kmap (kbd "TAB") 'tablist-forward-column) - (define-key kmap "\t" 'tablist-forward-column) - (define-key kmap [backtab] 'tablist-backward-column) - - (define-key kmap "%" tablist-mode-regexp-map) - (define-key kmap "*" tablist-mode-mark-map) - (define-key kmap "/" tablist-mode-filter-map) - - ;; (define-key kmap "e" 'tablist-edit-column) - ;; (define-key kmap "i" 'tablist-insert-entry) - (define-key kmap "s" 'tablist-sort) - (define-key kmap [remap back-to-indentation] 'tablist-move-to-major-column) - (define-key kmap [remap next-line] 'tablist-next-line) - (define-key kmap [remap previous-line] 'tablist-previous-line) - (define-key kmap "<" 'tablist-shrink-column) - (define-key kmap ">" 'tablist-enlarge-column) - (define-key kmap "q" 'tablist-quit) - (define-key kmap "G" 'tablist-revert) - (define-key kmap (kbd "C-c C-e") 'tablist-export-csv) - kmap)) - -(defvar tablist-mode-map - (let ((kmap (copy-keymap tablist-minor-mode-map))) - (set-keymap-parent kmap tabulated-list-mode-map) - (define-key kmap "d" 'tablist-flag-forward) - (define-key kmap (kbd "RET") 'tablist-find-entry) - (define-key kmap "f" 'tablist-find-entry) - ;; (define-key kmap "~" 'tablist-flag-gargabe-items) - (define-key kmap "D" 'tablist-do-delete) - (define-key kmap "C" 'tablist-do-copy) - (define-key kmap "R" 'tablist-do-rename) - (define-key kmap "x" 'tablist-do-flagged-delete) - ;; (define-key kmap "F" 'tablist-find-marked-items) - ;; (define-key kmap (kbd "C-o") 'tablist-display-item) - kmap)) - - -;; -;; *Variables -;; - -;; Marking -(defvar tablist-umark-filtered-entries t) -(defvar tablist-marker-char dired-marker-char - "The character used for marking.") -(defvar tablist-marker-face 'dired-mark - "The face used for the mark character.") -(defvar tablist-marked-face 'dired-marked - "The face used for marked major columns.") - -;; Operations -(defvar-local tablist-operations-function nil - "A function for handling operations on the entries. - -The function is called with varying number of arguments, while -the first one is always a symbol describing one of the following -operations. - -`supported-operations' - -This is the only mandatory operation. There are no other -arguments and the function should return a list of symbols of -supported operations. - -`delete' - -The 2nd argument will be a list of entry ID's. The function -should somehow delete these entries and update -`tabulated-list-entries'. - -`find-entry' - -The 2nd argument is the ID of an entry. The function should -somehow find/display this entry, i.e. a kind of default -operation. - -`edit-column' - -The function is called with 3 further arguments: ID, INDEX and -NEW-COLUMN, where ID represents the entry to edit, INDEX is the index -of the column and NEW-COLUMN is the proposed new value for this -column. It should either - -i. return a new edited complete entry and update -`tabulated-list-entries', or - -ii. throw an error, if NEW-COLUMN is not a valid value for this -column. - -`complete' - -The function is called with 4 further arguments: ID, INDEX, -STRING and POS, where ID represents an entry, INDEX is the index -of the column to complete, STRING it's current value and POS an -offset of the current position of point into STRING. - -The function should return a collection for this column, suitable -as argument for the function `completion-in-region'.") - -;; Differentiating columns -(defvar-local tablist-major-columns nil - "Columns used to mark and when querying.") - -;; Filter -(defvar-local tablist-current-filter nil) -(defvar-local tablist-filter-suspended nil) -(defvar tablist-named-filter nil) - -;; History variables -(defvar tablist-column-name-history nil) - -;; Hooks -(defvar tablist-selection-changed-functions nil - "A hook run when ever point moves to a different entry.") - -;; Context Window -(defvar-local tablist-context-window nil) -(defvar-local tablist-context-window-function nil) -(defvar tablist-context-window-display-action - `((display-buffer-reuse-window - tablist-display-buffer-split-below-and-attach) - (window-height . 0.25) - (inhibit-same-window . t))) - -;; -;; *Setup -;; - -(defvar savehist-additional-variables) -(add-hook 'savehist-save-hook - (lambda nil - (add-to-list 'savehist-additional-variables 'tablist-named-filter))) - -;;;###autoload -(define-minor-mode tablist-minor-mode - nil nil nil nil - (unless (derived-mode-p 'tabulated-list-mode) - (error "Buffer is not in Tabulated List Mode")) - (tablist-init (not tablist-minor-mode))) - -;;;###autoload -(define-derived-mode tablist-mode tabulated-list-mode "TL" - (tablist-init)) - -(defun tablist-init (&optional disable) - (let ((cleaned-misc (cl-remove 'tablist-current-filter - mode-line-misc-info :key 'car))) - (cond - ((not disable) - (set (make-local-variable 'mode-line-misc-info) - (append - (list - (list 'tablist-current-filter - '(:eval (format " [%s]" - (if tablist-filter-suspended - "suspended" - "filtered"))))))) - (add-hook 'post-command-hook - 'tablist-selection-changed-handler nil t) - (add-hook 'tablist-selection-changed-functions - 'tablist-context-window-update nil t)) - (t - (setq mode-line-misc-info cleaned-misc) - (remove-hook 'post-command-hook - 'tablist-selection-changed-handler t) - (remove-hook 'tablist-selection-changed-functions - 'tablist-context-window-update t))))) - -(defun tablist-quit () - (interactive) - (tablist-hide-context-window) - (quit-window)) - -(defvar-local tablist-selected-id nil) -(defvar tablist-edit-column-minor-mode) - -(defun tablist-selection-changed-handler () - (unless tablist-edit-column-minor-mode - (let ((id tablist-selected-id) - (selected (tabulated-list-get-id))) - (unless (eq selected id) - (setq tablist-selected-id selected) - (run-hook-with-args - 'tablist-selection-changed-functions - tablist-selected-id))))) - -(defvar tablist-context-window-update--timer nil) - -(defun tablist-context-window-update (&optional id) - (when (and tablist-context-window-function - (window-live-p tablist-context-window) - (not tablist-edit-column-minor-mode)) - (unless id - (setq id (tabulated-list-get-id))) - (when (timerp tablist-context-window-update--timer) - (cancel-timer tablist-context-window-update--timer)) - (setq tablist-context-window-update--timer - (run-with-idle-timer 0.1 nil - (lambda (fn window) - (when (window-live-p window) - (with-selected-window window - (set-window-dedicated-p nil nil) - (save-selected-window - (funcall fn id)) - (when (window-live-p (selected-window)) - (set-window-dedicated-p nil t))))) - tablist-context-window-function - tablist-context-window)))) - -(defun tablist-display-context-window () - (interactive) - (unless tablist-context-window-function - (error "No function for handling a context is defined")) - (unless (window-live-p tablist-context-window) - (setq tablist-context-window - (display-buffer - (current-buffer) - tablist-context-window-display-action))) - (prog1 - tablist-context-window - (tablist-context-window-update))) - -(defun tablist-hide-context-window () - (interactive) - (when (window-live-p tablist-context-window) - (let ((ignore-window-parameters t)) - (delete-window tablist-context-window))) - (setq tablist-context-window nil)) - -(defun tablist-toggle-context-window () - (interactive) - (if (window-live-p tablist-context-window) - (tablist-hide-context-window) - (tablist-display-context-window))) - - -;; -;; *Marking -;; - -(defun tablist-revert () - "Revert the list with marks preserved, position kept." - (interactive) - (tablist-save-marks - (tablist-with-remembering-entry - (tabulated-list-revert)))) - -(defun tablist-major-columns () - (if (null tablist-major-columns) - (number-sequence 0 (1- (length tabulated-list-format))) - (if (numberp tablist-major-columns) - (list tablist-major-columns) - tablist-major-columns))) - -(defun tablist-put-mark (&optional pos) - "Put a mark before the entry at POS. - -POS defaults to point. Use `tablist-marker-char', -`tablist-marker-face', `tablist-marked-face' and -`tablist-major-columns' to determine how to mark and what to put -a face on." - (when (or (null tabulated-list-padding) - (< tabulated-list-padding 1)) - (setq tabulated-list-padding 1) - (tabulated-list-revert)) - (save-excursion - (and pos (goto-char pos)) - (unless (tabulated-list-get-id) - (error "No entry at this position")) - (let ((inhibit-read-only t)) - (tabulated-list-put-tag - (string tablist-marker-char)) - (put-text-property - (point-at-bol) - (1+ (point-at-bol)) - 'face tablist-marker-face) - (let ((columns (tablist-column-offsets))) - (dolist (c (tablist-major-columns)) - (when (and (>= c 0) - (< c (length columns))) - (let ((beg (+ (point-at-bol) - (nth c columns))) - (end (if (= c (1- (length columns))) - (point-at-eol) - (+ (point-at-bol) - (nth (1+ c) columns))))) - (cond - ((and tablist-marked-face - (not (eq tablist-marker-char ?\s))) - (tablist--save-face-property beg end) - (put-text-property - beg end 'face tablist-marked-face)) - (t (tablist--restore-face-property beg end)))))))))) - -(defun tablist-mark-forward (&optional arg interactive) - "Mark ARG entries forward. - -ARG is interpreted as a prefix-arg. If interactive is non-nil, -maybe use the active region instead of ARG. - -See `tablist-put-mark' for how entries are marked." - (interactive (list current-prefix-arg t)) - (cond - ;; Mark files in the active region. - ((and interactive (use-region-p)) - (save-excursion - (goto-char (region-beginning)) - (beginning-of-line) - (tablist-repeat-over-lines - (1+ (count-lines - (point) - (save-excursion - (goto-char (region-end)) - (beginning-of-line) - (point)))) - 'tablist-put-mark))) - ;; Mark the current (or next ARG) files. - (t - (tablist-repeat-over-lines - (prefix-numeric-value arg) - 'tablist-put-mark)))) - -(defun tablist-mark-backward (&optional arg interactive) - "Mark ARG entries backward. - -See `tablist-mark-forward'." - (interactive (list current-prefix-arg t)) - (tablist-mark-forward (- (prefix-numeric-value arg)) - interactive)) - -(defun tablist-unmark-forward (&optional arg interactive) - "Unmark ARG entries forward. - -See `tablist-mark-forward'." - (interactive (list current-prefix-arg t)) - (let ((tablist-marker-char ?\s) - tablist-marked-face) - (tablist-mark-forward arg interactive))) - -(defun tablist-unmark-backward (&optional arg interactive) - "Unmark ARG entries backward. - -See `tablist-mark-forward'." - (interactive (list current-prefix-arg t)) - (let ((tablist-marker-char ?\s) - tablist-marked-face) - (tablist-mark-backward arg interactive))) - -(defun tablist-flag-forward (&optional arg interactive) - "Flag ARG entries forward. - -See `tablist-mark-forward'." - (interactive (list current-prefix-arg t)) - (let ((tablist-marker-char ?D) - (tablist-marked-face 'dired-flagged)) - (tablist-mark-forward arg interactive))) - -(defun tablist-change-marks (old new) - "Change all OLD marks to NEW marks. - -OLD and NEW are both characters used to mark files." - (interactive - (let* ((cursor-in-echo-area t) - (old (progn (message "Change (old mark): ") (read-char))) - (new (progn (message "Change %c marks to (new mark): " old) - (read-char)))) - (list old new))) - (when (eq new ?\n) - (error "Mark character \\n is not allowed")) - (let ((default-mark-p (equal tablist-marker-char new)) - (tablist-marker-char old)) - (save-excursion - (tablist-map-over-marks - (lambda nil - (pcase new - (?D - (tablist-flag-forward 1)) - (t - (let ((tablist-marker-char new) - (tablist-marked-face - (and default-mark-p - tablist-marked-face))) - (tablist-put-mark))))))))) - -(defun tablist-unmark-all-marks (&optional marks interactive) - "Remove alls marks in MARKS. - -MARKS should be a string of mark characters to match and defaults -to all marks. Interactively, remove all marks, unless a prefix -arg was given, in which case ask about which ones to remove. -Give a message, if interactive is non-nil. - -Returns the number of unmarked marks." - (interactive - (list (if current-prefix-arg - (read-string "Remove marks: ")) t)) - (let ((re (if marks - (tablist-marker-regexp marks) - "^[^ ]")) - (removed 0)) - (save-excursion - (goto-char (point-min)) - (while (re-search-forward re nil t) - (let ((tablist-marker-char ?\s) - tablist-marker-face - tablist-marked-face) - (tablist-put-mark)) - (cl-incf removed))) - (when interactive - (message "Removed %d marks" removed)) - removed)) - -(defun tablist-toggle-marks () - "Unmark all marked and mark all unmarked entries. - -See `tablist-put-mark'." - (interactive) - (let ((marked-re (tablist-marker-regexp)) - (not-marked-re - (let ((tablist-marker-char ?\s)) - (tablist-marker-regexp)))) - (save-excursion - (goto-char (point-min)) - (tablist-skip-invisible-entries) - (while (not (eobp)) - (cond - ((looking-at marked-re) - (save-excursion (tablist-unmark-backward -1))) - ((looking-at not-marked-re) - (tablist-put-mark))) - (tablist-forward-entry))) - (tablist-move-to-major-column))) - -(defun tablist-get-marked-items (&optional arg distinguish-one-marked) - "Return marked or ARG entries." - (let ((items (save-excursion - (tablist-map-over-marks - (lambda () (cons (tabulated-list-get-id) - (tabulated-list-get-entry))) - arg nil distinguish-one-marked)))) - (if (and distinguish-one-marked - (eq (car items) t)) - items - (nreverse items)))) - -(defun tablist-mark-items-regexp (column-name regexp) - "Mark entries matching REGEXP in column COLUMN-NAME." - (interactive - (tablist-read-regexp-filter "Mark" current-prefix-arg )) - (tablist-map-with-filter - 'tablist-put-mark - `(=~ ,column-name ,regexp))) - -(defun tablist-mark-items-numeric (binop column-name operand) - "Mark items fulfilling BINOP with arg OPERAND in column COLUMN-NAME. - -First the column's value is coerced to a number N. Then the test -proceeds as \(BINOP N OPERAND\)." - (interactive - (tablist-read-numeric-filter "Mark" current-prefix-arg)) - (tablist-map-with-filter - 'tablist-put-mark - `(,binop ,column-name ,operand))) - -(defun tablist-map-over-marks (fn &optional arg show-progress - distinguish-one-marked) - (prog1 - (cond - ((and arg (integerp arg)) - (let (results) - (tablist-repeat-over-lines - arg - (lambda () - (if show-progress (sit-for 0)) - (push (funcall fn) results))) - (if (< arg 0) - (nreverse results) - results))) - (arg - ;; non-nil, non-integer ARG means use current item: - (tablist-skip-invisible-entries) - (unless (eobp) - (list (funcall fn)))) - (t - (cl-labels ((search (re) - (let (sucess) - (tablist-skip-invisible-entries) - (while (and (setq sucess - (re-search-forward re nil t)) - (invisible-p (point))) - (tablist-forward-entry)) - sucess))) - (let ((regexp (tablist-marker-regexp)) - next-position results found) - (save-excursion - (goto-char (point-min)) - ;; remember position of next marked file before BODY - ;; can insert lines before the just found file, - ;; confusing us by finding the same marked file again - ;; and again and... - (setq next-position (and (search regexp) - (point-marker)) - found (not (null next-position))) - (while next-position - (goto-char next-position) - (if show-progress (sit-for 0)) - (push (funcall fn) results) - ;; move after last match - (goto-char next-position) - (forward-line 1) - (set-marker next-position nil) - (setq next-position (and (search regexp) - (point-marker))))) - (if (and distinguish-one-marked (= (length results) 1)) - (setq results (cons t results))) - (if found - results - (unless (or (eobp) (invisible-p (point))) - (list (funcall fn)))))))) - (tablist-move-to-major-column))) - -(defun tablist-marker-regexp (&optional marks) - "Return a regexp matching marks in MARKS. - -MARKS should be a string of mark characters to match and defaults -to the current value of `tablist-marker-char' as a string." - (concat (format "^[%s]" - (or marks (string tablist-marker-char))))) - -(defun tablist-get-mark-state () - "Return the mark state of the entry at point." - (save-excursion - (beginning-of-line) - (when (looking-at "^\\([^ ]\\)") - (let ((mark (buffer-substring - (match-beginning 1) - (match-end 1)))) - (tablist-move-to-major-column) - (list (aref mark 0) - (get-text-property 0 'face mark) - (get-text-property (point) 'face)))))) - -(defun tablist-put-mark-state (state) - "Set the mark of the entry at point according to STATE. - -STATE is a return value of `tablist-get-mark-state'." - (cl-destructuring-bind (tablist-marker-char - tablist-marker-face - tablist-marked-face) - state - (tablist-put-mark))) - -(defun tablist-mark-prompt (arg items) - "Return a string suitable for use in a tablist prompt." - ;; distinguish-one-marked can cause the first element to be just t. - (if (eq (car items) t) (setq items (cdr items))) - (let ((count (length items))) - (if (= count 1) - (car items) - ;; more than 1 item: - (if (integerp arg) - ;; abs(arg) = count - ;; Perhaps this is nicer, but it also takes more screen space: - ;;(format "[%s %d items]" (if (> arg 0) "next" "previous") - ;; count) - (format "[next %d item%s]" - arg (dired-plural-s arg)) - (format "%c [%d item%s]" dired-marker-char count - (dired-plural-s count)))))) - -;; -;; *Movement -;; - -(defun tablist-forward-entry (&optional n) - "Move past the next N unfiltered entries." - (unless n (setq n 1)) - (while (and (> n 0) - (not (eobp))) - (forward-line) - (when (invisible-p (point)) - (tablist-skip-invisible-entries)) - (cl-decf n)) - (while (and (< n 0) - (not (bobp))) - (forward-line -1) - (when (invisible-p (point)) - (tablist-skip-invisible-entries t)) - (cl-incf n)) - n) - -(defun tablist-next-line (&optional n) - (interactive "p") - (when (and (< n 0) - (save-excursion - (end-of-line 0) - (tablist-skip-invisible-entries t) - (bobp))) - (signal 'beginning-of-buffer nil)) - (when (and (> n 0) - (save-excursion - (tablist-forward-entry) - (eobp))) - (signal 'end-of-buffer nil)) - - (let ((col (tablist-current-column))) - (tablist-forward-entry (or n 1)) - (if col - (tablist-move-to-column col) - (tablist-move-to-major-column)))) - -(defun tablist-previous-line (&optional n) - (interactive "p") - (tablist-next-line (- (or n 1)))) - -(defun tablist-repeat-over-lines (arg function) - "Call FUNCTION for the next ARG entries." - ;; Move out of potentially invisble area. - (tablist-skip-invisible-entries) - (let ((pos (make-marker))) - (while (and (> arg 0) - (not (eobp))) - (cl-decf arg) - (save-excursion - (tablist-forward-entry) - (move-marker pos (1+ (point)))) - (unless (eobp) - (save-excursion (funcall function))) - ;; Advance to the next line--actually, to the line that *was* next. - ;; (If FUNCTION inserted some new lines in between, skip them.) - (goto-char pos)) - (while (and (< arg 0) (not (bobp))) - (cl-incf arg) - (tablist-forward-entry -1) - (save-excursion (funcall function))) - (move-marker pos nil) - (tablist-move-to-major-column))) - -(defun tablist-move-to-column (n) - "Move to the N'th list column." - (interactive "p") - (when (tabulated-list-get-id) - (let ((columns (tablist-column-offsets))) - (when (or (< n 0) - (>= n (length columns))) - (error "No such column: %s" n)) - (beginning-of-line) - (forward-char (nth n columns)) - (when (and (plist-get (nthcdr 3 (elt tabulated-list-format n)) - :right-align) - (not (= n (1- (length columns))))) - (forward-char (1- (car (cdr (elt tabulated-list-format n))))))))) - - - -(defun tablist-move-to-major-column (&optional first-skip-invisible-p) - "Move to the first major column." - (interactive (list t)) - (when first-skip-invisible-p - (tablist-skip-invisible-entries)) - (tablist-move-to-column (car (tablist-major-columns)))) - -(defun tablist-forward-column (n) - "Move n columns forward, while wrapping around." - (interactive "p") - (unless (tabulated-list-get-id) - (error "No entry on this line")) - (let* ((columns (tablist-column-offsets)) - (current (1- (length columns)))) - ;; find current column - (while (and (>= current 0) - (> (nth current columns) - (current-column))) - (cl-decf current)) - ;; there may be an invisible spec here - (when (bolp) - (forward-char)) - ;; before any columns - (when (< current 0) - (goto-char (+ (point-at-bol) (if (> n 0) - (car columns) - (car (last columns))))) - (setq n (* (cl-signum n) (1- (abs n))))) - (when (/= n 0) - (tablist-move-to-column - (mod (+ current n) (length columns)))))) - -(defun tablist-backward-column (n) - "Move n columns backward, while wrapping around." - (interactive "p") - (tablist-forward-column (- n))) - -;; -(defun tablist-skip-invisible-entries (&optional backward) - "Skip invisible entries BACKWARD or forward. - -Do nothing, if the entry at point is visible. Otherwise move to -the beginning of the next visible entry in the direction -determined by BACKWARD. - -Return t, if point is now in a visible area." - - (cond - ((and backward - (not (bobp)) - (get-text-property (point) 'invisible)) - (when (get-text-property (1- (point)) 'invisible) - (goto-char (previous-single-property-change - (point) - 'invisible nil (point-min)))) - (forward-line -1)) - ((and (not backward) - (not (eobp)) - (get-text-property (point) 'invisible)) - (goto-char (next-single-property-change - (point) - 'invisible nil (point-max))))) - (not (invisible-p (point)))) - -;; -;; *Operations -;; - -(defun tablist-yes-or-no-p (operation arg items) - "Query the user whether to proceed with some operation. - -Operation should be a symbol or string describing the operation, -ARG the prefix-arg of the command used in -`tablist-get-marked-items' or elsewhere, to get the ITEMS." - - (let ((pp-items (mapcar 'tablist-pretty-print-entry - (mapcar 'cdr items))) - dired-no-confirm - (op-str (upcase-initials - (if (stringp operation) - operation - (symbol-name operation))))) - (dired-mark-pop-up - (format " *%s*" op-str) nil - pp-items - dired-deletion-confirmer - (format "%s %s " - op-str - (tablist-mark-prompt arg pp-items))))) - - -(defun tablist-operation-available-p (op) - (and (functionp tablist-operations-function) - (memq op (funcall tablist-operations-function - 'supported-operations)))) - -(defun tablist-do-delete (&optional arg) - "Delete ARG entries." - (interactive "P") - (unless (tablist-operation-available-p 'delete) - (error "Deleting entries is not available in this buffer")) - (let ((items (tablist-get-marked-items arg))) - (when (tablist-yes-or-no-p 'delete arg items) - (tablist-do-kill-lines arg) - (funcall tablist-operations-function - 'delete (mapcar 'car items)) - (tablist-move-to-major-column)))) - -(defun tablist-do-flagged-delete (&optional interactive) - "Delete all entries marked with a D." - (interactive "p") - (let* ((tablist-marker-char ?D)) - (if (save-excursion - (goto-char (point-min)) - (re-search-forward (tablist-marker-regexp) nil t)) - (tablist-do-delete) - (or (not interactive) - (message "(No deletions requested)"))))) - -(defun tablist-do-kill-lines (&optional arg interactive) - "Remove ARG lines from the display." - (interactive (list current-prefix-arg t)) - (save-excursion - (let ((positions - (tablist-map-over-marks 'point arg)) - (inhibit-read-only t)) - (dolist (pos positions) - (goto-char pos) - (tabulated-list-delete-entry)) - (when interactive - (message (format "Killed %d line%s" - (length positions) - (dired-plural-s (length positions)))))))) - -(defun tablist-do-operation (arg fn operation &optional delete-p revert-p) - "Operate on marked items. - -ARG should be the `current-prefix-arg', FN is a function of two -arguments \(ID ENTRY\) handling the operation. It gets called -repeatly with all marked items. OPERATION is a symbol or string -describing the operation, it is used for display. - -Optional non-nil DELETE-P means, remove the items from the display. -Optional REVERT-P means, revert the display afterwards." - (let ((items (tablist-get-marked-items arg))) - (unless items - (error "No items marked")) - (when (tablist-yes-or-no-p operation arg items) - (when delete-p - (tablist-do-kill-lines arg)) - (dolist (item items) - (funcall fn (car item))) - (when revert-p - (tablist-revert)) - (tablist-move-to-major-column)))) - -;; -;; *Editing -;; -(defvar tablist-edit-column-minor-mode-map - (let ((kmap (make-sparse-keymap))) - (set-keymap-parent kmap (current-global-map)) - (define-key kmap [remap self-insert-command] 'self-insert-command) - (define-key kmap "\r" 'tablist-edit-column-commit) - (define-key kmap (kbd "C-g") 'tablist-edit-column-quit) - (define-key kmap (kbd "C-c C-c") 'tablist-edit-column-commit) - (define-key kmap (kbd "C-c C-q") 'tablist-edit-column-quit) - (define-key kmap "\t" 'tablist-edit-column-complete) - (define-key kmap (kbd "TAB") 'tablist-edit-column-complete) - (define-key kmap [remap end-of-buffer] 'end-of-line) - (define-key kmap [remap beginning-of-buffer] 'beginning-of-line) - (define-key kmap [remap mark-whole-buffer] 'tablist-edit-column-mark-field) - kmap)) - -(define-minor-mode tablist-edit-column-minor-mode - "" nil nil nil - (unless (or tablist-minor-mode - (derived-mode-p 'tablist-mode)) - (error "Not in a tablist buffer")) - (cond - (tablist-edit-column-minor-mode - (add-to-list 'mode-line-misc-info - '(tablist-edit-column-minor-mode "[edit]")) - (add-hook 'post-command-hook 'tablist-edit-column-constrain-point nil t) - (read-only-mode -1)) - (t - (remove-hook 'post-command-hook 'tablist-edit-column-constrain-point t) - (read-only-mode 1)))) - - -(defun tablist-edit-column (&optional n) - (interactive "P") - (unless n (setq n (tablist-current-column))) - (tablist-assert-column-editable n) - (let* ((offsets (append (tablist-column-offsets) - (list (- (point-at-eol) - (point-at-bol))))) - (beg (+ (point-at-bol) - (nth n offsets))) - (end (+ (point-at-bol) - (nth (1+ n) offsets))) - (entry (tabulated-list-get-entry beg)) - (inhibit-read-only t) - (inhibit-field-text-motion t) - (alist `((entry . ,entry) - (column . ,n) - (id . ,(tabulated-list-get-id beg)))) - ov) - (goto-char beg) - (delete-region beg end) - (add-text-properties - (point-at-bol) (point-at-eol) - '(read-only t field t)) - (unless (= beg (point-at-bol)) - (put-text-property (1- beg) beg 'rear-nonsticky t)) - (save-excursion - ;; Keep one read-only space at the end for keeping text - ;; properties. - (insert - (propertize - (concat - (tablist-nth-entry n entry) - (propertize " " - 'display `(space :align-to ,(- end (point-at-bol))))) - 'field nil - 'front-sticky '(tablist-edit) - 'rear-nonsticky '(read-only field) - 'tablist-edit alist)) - (setq end (point))) - (add-text-properties - (1- end) end '(read-only t field 'tablist-edit-end)) - (setq ov (make-overlay beg end)) - (overlay-put ov 'priority 9999) - (overlay-put ov 'face '(:background "deep sky blue" :foreground "white")) - (overlay-put ov 'evaporate t) - (overlay-put ov 'tablist-edit t) - (tablist-edit-column-minor-mode 1))) - -(defun tablist-edit-column-quit () - (interactive) - (tablist-edit-column-commit t)) - -(defun tablist-edit-column-commit (&optional abandon-edit) - (interactive (list current-prefix-arg)) - (let ((inhibit-read-only t) - (inhibit-field-text-motion t) - bounds) - (condition-case nil - (setq bounds (tablist-edit-column-bounds)) - (error - (tablist-edit-column-minor-mode -1) - (tabulated-list-revert) - (put-text-property (point-min) (point-max) - 'tablist-edit nil) - (error "Unable to complete the edit"))) - (let* ((beg (car bounds)) - (end (cdr bounds)) - (alist (get-text-property beg 'tablist-edit)) - (column (cdr (assq 'column alist))) - (id (cdr (assq 'id alist))) - (entry (cdr (assq 'entry alist))) - (item (buffer-substring-no-properties beg (1- end)))) - - (unless abandon-edit - ;; Throws an error, if item is invalid. - (setq entry (funcall tablist-operations-function - 'edit-column id column item))) - (tablist-edit-column-minor-mode -1) - (remove-overlays beg end 'tablist-edit t) - (put-text-property beg end 'tablist-edit nil) - (delete-region (point-at-bol) (1+ (point-at-eol))) - (save-excursion - (tabulated-list-print-entry id entry)) - (forward-char (nth column (tablist-column-offsets)))))) - -(defun tablist-edit-column-complete () - (interactive) - (unless (tablist-operation-available-p 'complete) - (error "Completion not available")) - (cl-destructuring-bind (beg &rest end) - (tablist-edit-column-bounds t) - (let* ((string (buffer-substring-no-properties - beg end)) - (alist (get-text-property beg 'tablist-edit)) - (completions (funcall tablist-operations-function - 'complete - (cdr (assq 'id alist)) - (cdr (assq 'column alist)) - string - (- (point) beg)))) - (unless completions - (error "No completions available")) - (completion-in-region beg end completions)))) - -(defun tablist-column-editable (n) - (and (tablist-operation-available-p 'edit-column) - (not (tablist-column-property n :read-only)))) - -(defun tablist-assert-column-editable (n) - (unless (and (>= n 0) - (< n (length tabulated-list-format))) - (error "Invalid column number: %s" n)) - (unless (tablist-operation-available-p 'edit-column) - (error "Editing columns not enabled in this buffer")) - (when (tablist-column-property n :read-only) - (error "This column is read-only"))) - -(defun tablist-edit-column-constrain-point () - (unless tablist-edit-column-minor-mode - (error "Not editing a column")) - (unless (get-text-property (point) 'tablist-edit) - (let ((bounds (tablist-edit-column-bounds))) - (when bounds - (if (> (point) (cdr bounds)) - (goto-char (1- (cdr bounds))) - (goto-char (car bounds))) - (point))))) - -(defun tablist-edit-column-bounds (&optional skip-final-space) - (unless tablist-edit-column-minor-mode - (error "Not editing a column")) - (let ((pos (next-single-property-change - (point) 'tablist-edit)) - beg end) - (cond - ((null pos) - (setq end (previous-single-property-change - (point-max) 'tablist-edit) - beg (previous-single-property-change - end 'tablist-edit))) - ((get-text-property pos 'tablist-edit) - (setq beg pos - end (next-single-property-change - pos 'tablist-edit))) - (pos - (setq end pos - beg (previous-single-property-change - pos 'tablist-edit)))) - - (unless (and beg end (get-text-property beg 'tablist-edit)) - (error "Unable to locate edited text")) - (cons beg (if skip-final-space (1- end) end)))) - -(defun tablist-edit-column-mark-field () - (interactive) - (push-mark (field-beginning)) - (push-mark (field-end) nil t) - (goto-char (field-beginning))) - -(defun tablist-find-entry (&optional id) - (interactive) - (unless (tablist-operation-available-p 'find-entry) - (error "Finding entries not supported in this buffer")) - (funcall tablist-operations-function - 'find-entry - (or id (tabulated-list-get-id)))) - -;; -;; *Utility -;; - -(defun tablist-column-property (n prop) - (plist-get - (nthcdr 3 (aref tabulated-list-format n)) - prop)) - -(defun tablist-current-column () - "Return the column number at point. - -Returns nil, if point is before the first column." - (let ((column - (1- (cl-position - (current-column) - (append (tablist-column-offsets) - (list most-positive-fixnum)) - :test (lambda (column offset) (> offset column)))))) - (when (>= column 0) - column))) - -(defun tablist-column-offsets () - "Return a list of column positions. - -This is a list of offsets from the beginning of the line." - (let ((cc tabulated-list-padding) - columns) - (dotimes (i (length tabulated-list-format)) - (let* ((c (aref tabulated-list-format i)) - (len (nth 1 c)) - (pad (or (plist-get (nthcdr 3 c) :pad-right) - 1))) - (push cc columns) - (when (numberp len) - (cl-incf cc len)) - (when pad - (cl-incf cc pad)))) - (nreverse columns))) - -(defun tablist-pretty-print-entry (item) - (mapconcat (lambda (i) - (tablist-nth-entry i item)) - (tablist-major-columns) " ")) - -(defun tablist--save-face-property (beg end) - ;; We need to distinguish ,,not set'' from ''no face''. - (unless (and (text-property-not-all beg end 'face nil) - (< beg end)) - (put-text-property beg (1+ beg) 'face 'default)) - (unless (text-property-not-all beg end 'tablist-saved-face nil) - (tablist-copy-text-property beg end 'face 'tablist-saved-face))) - -(defun tablist--restore-face-property (beg end) - (when (text-property-not-all beg end 'tablist-saved-face nil) - (tablist-copy-text-property beg end 'tablist-saved-face 'face))) - -(defun tablist-copy-text-property (beg end from to) - "Copy text property FROM to TO in region BEG to END." - (let ((inhibit-read-only t)) - (save-excursion - (while (< beg end) - (goto-char beg) - (put-text-property - (point) - (setq beg (next-single-property-change - (point) from nil end)) - to - (get-text-property (point) from)))))) - -;; -(defun tablist-read-column-name (arg &optional prompt default) - "Read the name of a column using ARG. - -If ARG is a number, return column ARG. -If ARG is nil, return DEFAULT or the current column. -Else ask the user, using PROMPT and DEFAULT." - (cond - ((numberp arg) - (or (tablist-column-name - (prefix-numeric-value arg)) - (error "No such column: %d" (prefix-numeric-value arg)))) - ((null arg) - (or default - (tablist-column-name - (or (tablist-current-column) - (car (tablist-major-columns)) - 0)))) - (t - (let* ((default (or default - (tablist-column-name - (car (tablist-major-columns))))) - (result - (completing-read - (format "%s %s: " - (or prompt "Use column") - (if default - (format "(default %s)" - default) - "")) - (tablist-column-names) - nil t nil 'tablist-column-name-history))) - (if (> (length result) 0) - result - (if (not default) - (error "No column selected") - default)))))) - -(defun tablist-column-name (n) - "Return the name of column N." - (when (and n - (>= n 0) - (< n (length tabulated-list-format))) - (substring-no-properties - (car (elt tabulated-list-format n)) 0))) - -(defun tablist-column-names () - "Return a list of all column-names." - (mapcar 'tablist-column-name - (number-sequence 0 (1- (length tabulated-list-format))))) - -(defun tablist-nth-entry (n &optional entry) - (unless entry (setq entry (tabulated-list-get-entry))) - (when (and entry - (>= n 0) - (< n (length entry))) - (let ((str (elt entry n))) - (if (stringp str) - str - (car str))))) - -(defun tablist-major-column-name () - "Return a list of the major column names." - (tablist-column-name (car (tablist-major-columns)))) - -(defun tablist-export-csv (&optional separator always-quote-p - invisible-p out-buffer display-p) - "Export a tabulated list to a CSV format. - -Use SEPARATOR (or ;) and quote if necessary (or always if -ALWAYS-QUOTE-P is non-nil). Only consider non-filtered entries, -unless invisible-p is non-nil. Create a buffer for the output or -insert it after point in OUT-BUFFER. Finally if DISPLAY-P is -non-nil, display this buffer. - -Return the output buffer." - - (interactive (list nil t nil nil t)) - (unless (derived-mode-p 'tabulated-list-mode) - (error "Not in Tabulated List Mode")) - (unless (stringp separator) - (setq separator (string (or separator ?\;)))) - (let* ((outb (or out-buffer - (get-buffer-create - (format "%s.csv" (buffer-name))))) - (escape-re (format "[%s\"\n]" separator)) - (header (tablist-column-names))) - (unless (buffer-live-p outb) - (error "Expected a live buffer: %s" outb)) - (cl-labels - ((printit (entry) - (insert - (mapconcat - (lambda (e) - (unless (stringp e) - (setq e (car e))) - (if (or always-quote-p - (string-match escape-re e)) - (concat "\"" - (replace-regexp-in-string "\"" "\"\"" e t t) - "\"") - e)) - entry separator)) - (insert ?\n))) - (with-current-buffer outb - (let ((inhibit-read-only t)) - (erase-buffer) - (printit header))) - (save-excursion - (goto-char (point-min)) - (unless invisible-p - (tablist-skip-invisible-entries)) - (while (not (eobp)) - (let* ((entry (tabulated-list-get-entry))) - (with-current-buffer outb - (let ((inhibit-read-only t)) - (printit entry))) - (if invisible-p - (forward-line) - (tablist-forward-entry))))) - (if display-p - (display-buffer outb)) - outb))) - -;; - -(defun tablist-enlarge-column (&optional column width) - "Enlarge column COLUMN by WIDTH. - -This function is lazy and therfore pretty slow." - (interactive - (list nil (* (prefix-numeric-value current-prefix-arg) - 3))) - (unless column (setq column (tablist-current-column))) - (unless column - (error "No column given and no entry at point")) - (unless width (setq width 1)) - (when (or (not (numberp column)) - (< column 0) - (>= column (length tabulated-list-format))) - (error "No such column: %d" column)) - (when (= column (1- (length tabulated-list-format))) - (error "Can't resize last column")) - - (let* ((cur-width (cadr (elt tabulated-list-format column)))) - (setcar (cdr (elt tabulated-list-format column)) - (max 3 (+ cur-width width))) - (tablist-with-remembering-entry - (tablist-save-marks - (tabulated-list-init-header) - (tabulated-list-print))))) - - -(defun tablist-shrink-column (&optional column width) - (interactive - (list nil (* (prefix-numeric-value current-prefix-arg) - 3))) - (tablist-enlarge-column column (- (or width 1)))) - - -;; *Sorting -;; - -(defun tablist-sort (&optional column) - "Sort the tabulated-list by COLUMN. - -COLUMN may be either a name or an index. The default compare -function is given by the `tabulated-list-format', which see. - -This function saves the current sort column and the inverse -sort-direction in the variable `tabulated-list-sort-key', which -also determines the default COLUMN and direction. - -The main difference to `tabulated-list-sort' is, that this -function sorts the buffer in-place and it ignores a nil sort -entry in `tabulated-list-format' and sorts on the column -anyway (why not ?)." - - (interactive - (list - (if (null current-prefix-arg) - (tablist-column-name - (or (tablist-current-column) - (car (tablist-major-columns)) - 0)) - (tablist-read-column-name - '(4) "Sort by column" - (tablist-column-name (car (tablist-major-columns))))))) - - (unless column - (setq column (or (car tabulated-list-sort-key) - (tablist-column-name (car (tablist-major-columns))) - (tablist-column-name 0)))) - (when (numberp column) - (let ((column-name (tablist-column-name column))) - (unless column-name - (error "No such column: %d" column)) - (setq column column-name))) - - (setq tabulated-list-sort-key - (cons column - (if (equal column (car tabulated-list-sort-key)) - (cdr tabulated-list-sort-key)))) - - (let* ((entries (if (functionp tabulated-list-entries) - (funcall tabulated-list-entries) - tabulated-list-entries)) - (reverse (cdr tabulated-list-sort-key)) - (n (tabulated-list--column-number ;;errors if column is n/a - (car tabulated-list-sort-key))) - (compare-fn (nth 2 (aref tabulated-list-format n)))) - - (when (or (null compare-fn) - (eq compare-fn t)) - (setq compare-fn - (lambda (a b) - (setq a (aref (cadr a) n)) - (setq b (aref (cadr b) n)) - (string< (if (stringp a) a (car a)) - (if (stringp b) b (car b)))))) - - (unless compare-fn - (error "This column cannot be sorted: %s" column)) - - (setcdr tabulated-list-sort-key (not reverse)) - ;; Presort the entries and hash the result and sort the buffer. - (setq entries (sort (copy-sequence entries) compare-fn)) - (let ((hash (make-hash-table :test 'equal))) - (dotimes (i (length entries)) - (puthash (caar entries) i hash) - (setq entries (cdr entries))) - (tablist-with-remembering-entry - (goto-char (point-min)) - (tablist-skip-invisible-entries) - (let ((inhibit-read-only t)) - (sort-subr - nil 'tablist-forward-entry 'end-of-line - (lambda () - (gethash (tabulated-list-get-id) hash 0)) - nil (if reverse '< '>)))) - (tablist-move-to-column n) - ;; Make the sort arrows display. - (tabulated-list-init-header)))) - -;; -;; *Filter -;; - -(defun tablist-read-filter-name (prompt) - (let ((filter (cdr (assq major-mode tablist-named-filter)))) - (unless filter - (error "No filter defined for %s mode" mode-name)) - (let ((name (completing-read - (format "%s: " prompt) - filter - nil t))) - (unless (> (length name) 0) - (error "No filter selected")) - name))) - -(defun tablist-apply-filter (&optional filter) - "Apply FILTER to the current tabulated list. - -FILTER defaults to `tablist-current-filter'." - (unless filter (setq filter tablist-current-filter)) - (tablist-filter-unhide-buffer) - (when (and filter - (null tablist-filter-suspended)) - (tablist-with-remembering-entry - (tablist-map-with-filter - (lambda nil - (if tablist-umark-filtered-entries - (save-excursion (tablist-unmark-forward))) - (tablist-filter-hide-entry)) - (tablist-filter-negate filter)))) - (force-mode-line-update)) - -(defadvice tabulated-list-print (after tabulated-list activate) - "Reapply the filter." - (when (or tablist-minor-mode - (derived-mode-p 'tablist-mode)) - (tablist-apply-filter))) - -(defun tablist-eval-filter (filter) - (tablist-filter-eval - filter - (tabulated-list-get-id) - (tabulated-list-get-entry) - (cdr (assq major-mode tablist-named-filter)))) - -(defun tablist-map-with-filter (fn filter &optional show-progress - distinguish-one-marked) - "Call FN for every unfiltered entry matching FILTER." - (prog1 - (cl-labels ((search () - (tablist-skip-invisible-entries) - (while (and (not (eobp)) - (not (tablist-eval-filter filter))) - (tablist-forward-entry)) - (unless (eobp) - (point-marker)))) - (let (next-position results) - (save-excursion - (goto-char (point-min)) - (setq next-position (search)) - (while next-position - (goto-char next-position) - (if show-progress (sit-for 0)) - (push (funcall fn) results) - ;; move after last match - (goto-char next-position) - (forward-line 1) - (set-marker next-position nil) - (setq next-position (search))) - (if (and distinguish-one-marked (= (length results) 1)) - (setq results (cons t results)))))))) - -;; -;; **Filter Commands -;; -(defun tablist-push-filter (filter &optional interactive or-p) - (setq tablist-current-filter - (tablist-filter-push - tablist-current-filter - filter or-p)) - (tablist-apply-filter) - (when interactive - (tablist-display-filter-temporarily))) - -(defun tablist-pop-filter (&optional n interactive) - "Remove the first N filter components." - (interactive (list (prefix-numeric-value current-prefix-arg) t)) - (while (and tablist-current-filter - (> n 0)) - (setq tablist-current-filter - (tablist-filter-pop - tablist-current-filter)) - (cl-decf n)) - (tablist-apply-filter) - (when interactive - (when (> n 0) - (message "The filter is empty.")) - (tablist-display-filter-temporarily)) - n) - -(defun tablist-negate-filter (&optional interactive) - "Negate the current filter." - (interactive (list t)) - (setq tablist-current-filter - (tablist-filter-negate - tablist-current-filter)) - (tablist-apply-filter) - (when interactive - (tablist-display-filter-temporarily))) - -(defun tablist-toggle-first-filter-logic () - "Toggle between and/or for the first filter operand." - (interactive) - (setq tablist-current-filter - (pcase tablist-current-filter - (`(or ,x1 ,x2) - `(and ,x1 ,x2)) - (`(and ,x1 ,x2) - `(or ,x1 ,x2)) - (`(not ,x) x) - (x `(not ,x)))) - (tablist-apply-filter) - (tablist-display-filter-temporarily)) - -(defun tablist-suspend-filter (&optional flag) - "Temporarily disable filtering according to FLAG. - -Interactively, this command toggles filtering." - (interactive - (list (not tablist-filter-suspended))) - (let ((state tablist-filter-suspended)) - (unless (eq (not (not state)) - (not (not flag))) - (set (make-local-variable 'tablist-filter-suspended) flag) - (tablist-apply-filter)))) - -(defun tablist-read-regexp-filter (operation arg) - (let ((column-name (tablist-read-column-name arg))) - (list - column-name - (let ((re - (read-regexp (format "%s where %s matches: " operation column-name)))) - (unless (> (length re) 0) - (error "No regexp given")) - re)))) - -(defun tablist-read-equal-filter (operation arg) - (let ((column-name (tablist-read-column-name arg))) - (list - column-name - (read-string (format "%s where %s equals: " operation column-name))))) - -(defun tablist-read-numeric-filter (operation arg) - (let* ((entry (tabulated-list-get-entry 1)) - (default (cl-some - (lambda (idx) - (let ((value (tablist-nth-entry idx entry))) - (when (or (not (eq 0 (string-to-number value))) - (equal "0" value)) - (tablist-column-name idx)))) - (number-sequence 0 (length entry)))) - (column-name (tablist-read-column-name arg nil default)) - (op (completing-read - (format "%s %s matching binary op: " operation column-name) - '("=" "<" ">" "<=" ">=") nil t)) - oper) - - (when (equal "" op) - (error "No operation selected")) - (setq op (intern op)) - (setq oper (number-to-string - (read-number - (format "%s where %s %s " operation column-name op)))) - - (list op column-name oper))) - -(defun tablist-push-regexp-filter (column-name regexp) - "Add a new filter matching REGEXP in COLUMN-NAME. - -The filter is and'ed with the current filter. Use -`tablist-toggle-first-filter-logic' to change this." - (interactive - (tablist-with-filter-displayed - (tablist-read-regexp-filter "Filter" current-prefix-arg))) - (tablist-push-filter - `(=~ ,column-name ,regexp) - (called-interactively-p 'any))) - -(defun tablist-push-equal-filter (column-name string) - "Add a new filter whre string equals COLUMN-NAME's value. - -The filter is and'ed with the current filter. Use -`tablist-toggle-first-filter-logic' to change this." - (interactive - (tablist-with-filter-displayed - (tablist-read-equal-filter "Filter" current-prefix-arg))) - (tablist-push-filter - `(== ,column-name ,string) - (called-interactively-p 'any))) - -(defun tablist-push-numeric-filter (op column-name 2nd-arg) - "Add a new filter matching a numeric predicate. - -The filter is and'ed with the current filter. Use -`tablist-toggle-first-filter-logic' to change this." - (interactive - (tablist-with-filter-displayed - (tablist-read-numeric-filter "Filter" current-prefix-arg))) - (tablist-push-filter - `(,op ,column-name ,2nd-arg) - (called-interactively-p 'any))) - -(defun tablist-push-named-filter (name) - "Add a named filter called NAME. - -Named filter are saved in the variable `tablist-named-filter'." - (interactive - (tablist-with-filter-displayed - (list - (tablist-read-filter-name "Add filter")))) - (when (and name (symbolp name)) - (setq name (symbol-name name))) - (tablist-push-filter name (called-interactively-p 'any))) - -(defun tablist-delete-named-filter (name &optional mode) - (interactive - (tablist-with-filter-displayed - (list - (tablist-read-filter-name "Delete filter")))) - (setq tablist-current-filter - (tablist-filter-map - (lambda (f) - (when (equal f name) - (setq f (tablist-get-named-filter f))) - f) - tablist-current-filter)) - (unless mode (setq mode major-mode)) - (let ((mode-filter - (assq mode tablist-named-filter))) - (when mode-filter - (setcdr mode-filter - (cl-remove name (cdr mode-filter) - :test 'equal :key 'car))))) - -(defun tablist-name-current-filter (name) - (interactive - (list (tablist-with-filter-displayed - (read-string - "Add name for current filter: ")))) - (unless tablist-current-filter - (error "Filter is empty")) - (unless (> (length name) 0) - (error "No name given")) - (tablist-put-named-filter - name (if (stringp tablist-current-filter) - (tablist-get-named-filter - tablist-current-filter) - tablist-current-filter)) - (setq tablist-current-filter name) - (force-mode-line-update)) - -(defun tablist-deconstruct-named-filter () - (interactive) - (let (found) - (setq tablist-current-filter - (tablist-filter-map - (lambda (f) - (when (and (not found) - (stringp f)) - (setq found t) - (let ((df (tablist-get-named-filter f))) - (unless df - (error "Filter is not defined: %s" f)) - (setq f df))) - f) - tablist-current-filter)) - (unless found - (error "No named filter found")) - (force-mode-line-update))) - - -(defun tablist-filter-names (&optional mode) - (mapcar 'car (cdr (assq (or mode major-mode) - tablist-named-filter)))) - -(defun tablist-get-named-filter (name &optional mode) - (cdr (assoc name - (cdr (assq (or mode major-mode) - tablist-named-filter))))) - -(defun tablist-put-named-filter (name filter &optional mode) - (unless mode (setq mode major-mode)) - (let ((mode-filter - (assq mode tablist-named-filter))) - (unless mode-filter - (setq mode-filter (cons mode nil)) - (push mode-filter tablist-named-filter)) - (let ((entry (assoc name mode-filter))) - (if entry - (setcdr entry filter) - (setcdr mode-filter - (list (cons name filter))))))) - -(defun tablist-validate-named-filter (filter) - (tablist-filter-map - (lambda (f) - (when (and (stringp f) - (null (tablist-get-named-filter f))) - (error "Undefined named filter: %s (defined: %s)" f - (mapconcat 'identity (tablist-filter-names) ",")))) - filter)) - -(defun tablist-edit-filter () - (interactive) - (setq tablist-current-filter - (tablist-with-filter-displayed - (tablist-filter-edit-filter - "Edit filter: " - tablist-current-filter - nil - 'tablist-validate-named-filter))) - (tablist-apply-filter)) - -(defun tablist-clear-filter () - (interactive) - (setq tablist-current-filter nil) - (tablist-apply-filter)) - -;; **Displaying filter -;; - -(defconst tablist-display-filter-mode-line-tag nil) - -(defun tablist-display-filter (&optional flag) - "Display the current filter according to FLAG. - -If FLAG has the value 'toggle, toggle it's visibility. -If FLAG has the 'state, then do nothing but return the current -visibility." - (interactive (list 'toggle)) - (let* ((tag 'tablist-display-filter-mode-line-tag) - (displayed-p (not (not (assq tag mode-line-format))))) - (if (eq flag 'state) - displayed-p - (let ((display-p (not (not (if (eq flag 'toggle) - (not displayed-p) - flag))))) - (unless (eq displayed-p display-p) - (setq mode-line-format - (if display-p - (list (cons tag mode-line-format) - '(:eval - (replace-regexp-in-string - "%" "%%" - (concat - (propertize "Filter: " 'face 'minibuffer-prompt) - (and tablist-filter-suspended - "[suspended] ") - (if tablist-current-filter - (tablist-filter-unparse - tablist-current-filter t) - "[none]"))))) - (cdr (assq tag mode-line-format))))) - (force-mode-line-update) - display-p)))) - -(defun tablist-display-filter-temporarily () - (tablist-with-filter-displayed - (sit-for 9999))) - -;; -;; **Hiding/Unhiding Entries -;; -(defun tablist-filter-set-entry-hidden (flag &optional pos) - (save-excursion - (when pos (goto-char pos)) - (beginning-of-line) - (let ((inhibit-read-only t)) - (add-text-properties - (point-at-bol) - (1+ (point-at-eol)) - `(invisible ,flag))))) - -(defun tablist-filter-hide-entry (&optional pos) - (interactive) - (tablist-filter-set-entry-hidden t pos)) - -(defun tablist-filter-unhide-entry (&optional pos) - (tablist-filter-set-entry-hidden nil pos)) - -(defun tablist-filter-unhide-buffer () - (let ((inhibit-read-only t)) - (remove-text-properties - (point-min) (point-max) - '(invisible)))) - - -(defun tablist-window-attach (awindow &optional window) - "Attach AWINDOW to WINDOW. - -This has the following effect. Whenever WINDOW, defaulting to -the selected window, stops displaying the buffer it currently -displays (e.g., by switching buffers or because it was deleted) -AWINDOW is deleted." - (unless window (setq window (selected-window))) - (let ((buffer (window-buffer window)) - (hook (make-symbol "window-attach-hook"))) - (fset hook - (lambda () - (when (or (not (window-live-p window)) - (not (eq buffer (window-buffer window)))) - (remove-hook 'window-configuration-change-hook - hook) - ;; Deleting windows inside wcch may cause errors in - ;; windows.el . - (run-with-timer - 0 nil (lambda (win) - (when (and (window-live-p win) - (not (eq win (selected-window)))) - (delete-window win))) - awindow)))) - (add-hook 'window-configuration-change-hook hook))) - -(defun tablist-display-buffer-split-below-and-attach (buf alist) - "Display buffer action using `tablist-window-attach'." - (let ((window (selected-window)) - (height (cdr (assq 'window-height alist))) - newwin) - (when height - (when (floatp height) - (setq height (round (* height (frame-height))))) - (setq height (- (max height window-min-height)))) - (setq newwin (window--display-buffer - buf - (split-window-below height) - 'window alist display-buffer-mark-dedicated)) - (tablist-window-attach newwin window) - newwin)) - -(defun tablist-generate-sorter (column compare-fn &optional read-fn) - "Generate a sort function for `tabulated-list' entries. - -Example: - - \(tablist-generate-sorter 0 '< 'string-to-number\) - -would create a sort function sorting `tabulated-list-entries' on -the 0-th column as numbers by the less-than relation." - - (lambda (e1 e2) - (funcall compare-fn - (funcall (or read-fn 'identity) - (aref (cadr e1) column)) - (funcall read-fn - (aref (cadr e2) column))))) - -(provide 'tablist) -;;; tablist.el ends here diff -Nru emacs-pdf-tools-0.70/lisp/tablist-filter.el emacs-pdf-tools-0.80/lisp/tablist-filter.el --- emacs-pdf-tools-0.70/lisp/tablist-filter.el 2016-06-05 12:32:19.000000000 +0000 +++ emacs-pdf-tools-0.80/lisp/tablist-filter.el 1970-01-01 00:00:00.000000000 +0000 @@ -1,449 +0,0 @@ -;;; tablist-filter.el --- Filter expressions for tablists. - -;; Copyright (C) 2013, 2014 Andreas Politz - -;; Author: Andreas Politz -;; Keywords: extensions, lisp - -;; This program is free software; you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation, either version 3 of the License, or -;; (at your option) any later version. - -;; This program 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 this program. If not, see . - -;;; Commentary: - -;; - -(let (python-mode-hook) -(require 'semantic/wisent/comp) -(require 'semantic/wisent/wisent)) - -;;; Code: - -(defvar wisent-eoi-term) -(declare-function wisent-parse "semantic/wisent/wisent.el") - -(defvar tablist-filter-binary-operator - '((== . tablist-filter-op-equal) - (=~ . tablist-filter-op-regexp) - (< . tablist-filter-op-<) - (> . tablist-filter-op->) - (<= . tablist-filter-op-<=) - (>= . tablist-filter-op->=) - (= . tablist-filter-op-=))) - -(defvar tablist-filter-unary-operator nil) - -(defvar tablist-filter-wisent-parser nil) - -(defvar tablist-filter-lexer-regexps nil) - -(defvar tablist-filter-wisent-grammar - '( - ;; terminals - ;; Use lowercase for better looking error messages. - (operand unary-operator binary-operator or and not) - - ;; terminal associativity & precedence - ((left binary-operator) - (left unary-operator) - (left or) - (left and) - (left not)) - - ;; rules - (filter-or-empty - ((nil)) - ((?\( ?\)) nil) - ((filter) $1)) - (filter - ((operand) $1) ;;Named filter - ((operand binary-operator operand) `(,(intern $2) ,$1 ,$3)) - ((unary-operator operand) `(,(intern $1) ,$2)) - ((not filter) `(not ,$2)) - ((filter and filter) `(and ,$1 ,$3)) - ((filter or filter) `(or ,$1 ,$3)) - ((?( filter ?)) $2)))) - -(defun tablist-filter-parser-init (&optional reinitialize interactive) - (interactive (list t t)) - (unless (and tablist-filter-lexer-regexps - (not reinitialize)) - (let ((re (mapcar - (lambda (l) - (let ((re (regexp-opt - (mapcar 'symbol-name - (mapcar 'car l)) t))) - (if (= (length re) 0) - ".\\`" ;;matches nothing - re))) - (list tablist-filter-binary-operator - tablist-filter-unary-operator)))) - (setq tablist-filter-lexer-regexps - (nreverse - (cons (concat "\\(?:" (car re) "\\|" (cadr re) - "\\|[ \t\f\r\n\"!()]\\|&&\\|||\\)") - re))))) - (unless (and tablist-filter-wisent-parser - (not reinitialize)) - (let ((wisent-compile-grammar* - (symbol-function - 'wisent-compile-grammar))) - (setq tablist-filter-wisent-parser - ;; Trick the byte-compile into not using the byte-compile - ;; handler in semantic/wisent/comp.el, since it does not - ;; always work (wisent-context-compile-grammar n/a). - (funcall wisent-compile-grammar* - tablist-filter-wisent-grammar)))) - (when interactive - (message "Parser reinitialized.")) - nil) - -(defun tablist-filter-wisent-lexer () - (cl-destructuring-bind (unary-op binary-op keywords) - tablist-filter-lexer-regexps - (skip-chars-forward " \t\f\r\n") - (cond - ((eobp) (list wisent-eoi-term)) - ((= ?\" (char-after)) - `(operand , (condition-case err - (read (current-buffer)) - (error (signal (car err) (cons - "invalid lisp string" - (cdr err))))))) - ((looking-at unary-op) - (goto-char (match-end 0)) - `(unary-operator ,(match-string-no-properties 0))) - ((looking-at binary-op) - (goto-char (match-end 0)) - `(binary-operator ,(match-string-no-properties 0))) - ((looking-at "&&") - (forward-char 2) - `(and "&&")) - ((looking-at "||") - (forward-char 2) - `(or "||")) - ((= ?! (char-after)) - (forward-char) - `(not "!")) - ((= ?\( (char-after)) - (forward-char) - `(?\( "(")) - ((= ?\) (char-after)) - (forward-char) - `(?\) ")")) - (t - (let ((beg (point))) - (when (re-search-forward keywords nil 'move) - (goto-char (match-beginning 0))) - `(operand ,(buffer-substring-no-properties - beg - (point)))))))) - -(defun tablist-filter-parse (filter) - (interactive "sFilter: ") - (tablist-filter-parser-init) - (with-temp-buffer - (save-excursion (insert filter)) - (condition-case error - (wisent-parse tablist-filter-wisent-parser - 'tablist-filter-wisent-lexer - (lambda (msg) - (signal 'error - (replace-regexp-in-string - "\\$EOI" "end of input" - msg t t)))) - (error - (signal 'error - (append (if (consp (cdr error)) - (cdr error) - (list (cdr error))) - (list (point)))))))) - -(defun tablist-filter-unparse (filter &optional noerror) - (cl-labels - ((unparse (filter &optional noerror) - (cond - ((stringp filter) - (if (or (string-match (nth 2 tablist-filter-lexer-regexps) - filter) - (= 0 (length filter))) - (format "%S" filter) - filter)) - ((and (eq (car-safe filter) 'not) - (= (length filter) 2)) - (let ((paren (memq (car-safe (nth 1 filter)) '(or and)))) - (format "!%s%s%s" - (if paren "(" "") - (unparse (cadr filter) noerror) - (if paren ")" "")))) - ((and (memq (car-safe filter) '(and or)) - (= (length filter) 3)) - (let ((lparen (and (eq (car filter) 'and) - (eq 'or (car-safe (car-safe (cdr filter)))))) - (rparen (and (eq (car filter) 'and) - (eq 'or (car-safe (car-safe (cddr filter))))))) - (format "%s%s%s %s %s%s%s" - (if lparen "(" "") - (unparse (cadr filter) noerror) - (if lparen ")" "") - (cl-case (car filter) - (and "&&") (or "||")) - (if rparen "(" "") - (unparse (car (cddr filter)) noerror) - (if rparen ")" "")))) - ((and (assq (car-safe filter) tablist-filter-binary-operator) - (= (length filter) 3)) - (format "%s %s %s" - (unparse (cadr filter) noerror) - (car filter) - (unparse (car (cddr filter)) noerror))) - ((and (assq (car-safe filter) tablist-filter-unary-operator) - (= (length filter) 2)) - (format "%s %s" - (car filter) - (unparse (cadr filter) noerror))) - ((not filter) "") - (t (funcall (if noerror 'format 'error) - "Invalid filter: %s" filter))))) - (tablist-filter-parser-init) - (unparse filter noerror))) - - -(defun tablist-filter-eval (filter id entry &optional named-alist) - (cl-labels - ((feval (filter) - (pcase filter - (`(not . ,(and operand (guard (not (cdr operand))))) - (not (feval (car operand)))) - (`(and . ,(and operands (guard (= 2 (length operands))))) - (and - (feval (nth 0 operands)) - (feval (nth 1 operands)))) - (`(or . ,(and operands (guard (= 2 (length operands))))) - (or - (feval (nth 0 operands)) - (feval (nth 1 operands)))) - (`(,op . ,(and operands (guard (= (length operands) 1)))) - (let ((fn (assq op tablist-filter-unary-operator))) - (unless fn - (error "Undefined unary operator: %s" op)) - (funcall fn id entry (car operands)))) - (`(,op . ,(and operands (guard (= (length operands) 2)))) - (let ((fn (cdr (assq op tablist-filter-binary-operator)))) - (unless fn - (error "Undefined binary operator: %s" op)) - (funcall fn id entry (car operands) - (cadr operands)))) - ((guard (stringp filter)) - (let ((fn (cdr (assoc filter named-alist)))) - (unless fn - (error "Undefined named filter: %s" filter)) - (if (functionp fn) - (funcall fn id entry)) - (feval - (if (stringp fn) (tablist-filter-unparse fn) fn)))) - (`nil t) - (_ (error "Invalid filter: %s" filter))))) - (feval filter))) - -(defun tablist-filter-get-item-by-name (entry col-name) - (let* ((col (cl-position col-name tabulated-list-format - :key 'car - :test - (lambda (s1 s2) - (eq t (compare-strings - s1 nil nil s2 nil nil t))))) - (item (and col (elt entry col)))) - (unless col - (error "No such column: %s" col-name)) - (if (consp item) ;(LABEL . PROPS) - (car item) - item))) - -(defun tablist-filter-op-equal (id entry op1 op2) - "COLUMN == STRING : Matches if COLUMN's entry is equal to STRING." - (let ((item (tablist-filter-get-item-by-name entry op1))) - (string= item op2))) - -(defun tablist-filter-op-regexp (id entry op1 op2) - "COLUMN =~ REGEXP : Matches if COLUMN's entry matches REGEXP." - (let ((item (tablist-filter-get-item-by-name entry op1))) - (string-match op2 item))) - -(defun tablist-filter-op-< (id entry op1 op2) - "COLUMN < NUMBER : Matches if COLUMN's entry is less than NUMBER." - (tablist-filter-op-numeric '< id entry op1 op2)) - -(defun tablist-filter-op-> (id entry op1 op2) - "COLUMN > NUMBER : Matches if COLUMN's entry is greater than NUMBER." - (tablist-filter-op-numeric '> id entry op1 op2)) - -(defun tablist-filter-op-<= (id entry op1 op2) - "COLUMN <= NUMBER : Matches if COLUMN's entry is less than or equal to NUMBER." - (tablist-filter-op-numeric '<= id entry op1 op2)) - -(defun tablist-filter-op->= (id entry op1 op2) - "COLUMN >= NUMBER : Matches if COLUMN's entry is greater than or equal to NUMBER." - (tablist-filter-op-numeric '>= id entry op1 op2)) - -(defun tablist-filter-op-= (id entry op1 op2) - "COLUMN = NUMBER : Matches if COLUMN's entry as a number is equal to NUMBER." - (tablist-filter-op-numeric '= id entry op1 op2)) - -(defun tablist-filter-op-numeric (op id entry op1 op2) - (let ((item (tablist-filter-get-item-by-name entry op1))) - (funcall op (string-to-number item) - (string-to-number op2)))) - -(defun tablist-filter-help (&optional temporary) - (interactive) - (cl-labels - ((princ-op (op) - (princ (car op)) - (princ (concat (make-string (max 0 (- 4 (length (symbol-name (car op))))) - ?\s) - "- " - (car (split-string - (or (documentation (cdr op)) - (format "FIXME: Not documented: %s" - (cdr op))) - "\n" t)) - "\n")))) - (with-temp-buffer-window - "*Help*" - (if temporary - '((lambda (buf alist) - (let ((win - (or (display-buffer-reuse-window buf alist) - (display-buffer-in-side-window buf alist)))) - (fit-window-to-buffer win) - win)) - (side . bottom))) - nil - (princ "Filter entries with the following operators.\n\n") - (princ "&& - FILTER1 && FILTER2 : Locical and.\n") - (princ "|| - FILTER1 || FILTER2 : Locical or.\n") - (dolist (op tablist-filter-binary-operator) - (princ-op op)) - (princ "! - ! FILTER : Locical not.\n\n") - (dolist (op tablist-filter-unary-operator) - (princ-op op)) - (princ "\"...\" may be used to quote names and values if necessary, -and \(...\) to group expressions.") - (with-current-buffer standard-output - (help-mode))))) - -;; -;; **Filter Functions -;; - -;; filter ::= nil | named | fn | (OP OP1 [OP2]) - -(defun tablist-filter-negate (filter) - "Return a filter not matching filter." - (cond - ((eq (car-safe filter) 'not) - (cadr filter)) - (filter - (list 'not filter)))) - -(defun tablist-filter-push (filter new-filter &optional or-p) - "Return a filter combining FILTER and NEW-FILTER. - -By default the filters are and'ed, unless OR-P is non-nil." - (if (or (null filter) - (null new-filter)) - (or filter - new-filter) - (list (if or-p 'or 'and) - filter new-filter))) - -(defun tablist-filter-pop (filter) - "Remove the first operator or operand from filter. - -If filter starts with a negation, return filter unnegated, -if filter starts with a dis- or conjuction, remove the first operand, -if filter is nil, raise an error, -else return nil." - (pcase filter - (`(,(or `and `or) . ,tail) - (car (cdr tail))) - (`(not . ,op1) - (car op1)) - (_ (unless filter - (error "Filter is empty"))))) - -(defun tablist-filter-map (fn filter) - (pcase filter - (`(,(or `and `or `not) . ,tail) - (cons (car filter) - (mapcar (lambda (f) - (tablist-filter-map fn f)) - tail))) - (_ (funcall fn filter)))) - - -;; -;; Reading filter -;; - -(defvar tablist-filter-edit-history nil) -(defvar tablist-filter-edit-display-help t) - -(defun tablist-filter-edit-filter (prompt &optional - initial-filter history - validate-fn) - (let* ((str (tablist-filter-unparse initial-filter)) - (filter initial-filter) - (validate-fn (or validate-fn 'identity)) - error done) - (save-window-excursion - (when tablist-filter-edit-display-help - (tablist-filter-help t)) - (while (not done) - (minibuffer-with-setup-hook - (lambda () - (when error - (when (car error) - (goto-char (+ (field-beginning) - (car error))) - (skip-chars-backward " \t\n")) - (minibuffer-message "%s" (cdr error)) - (setq error nil))) - (setq str (propertize - (read-string prompt str - (or history 'tablist-filter-edit-history))) - done t)) - (condition-case err - (progn - (setq filter (tablist-filter-parse str)) - (funcall validate-fn filter)) - (error - (setq done nil) - (setq error (cons (car-safe (cddr err)) nil)) - (when (car error) - (setq str (with-temp-buffer - (insert str) - (goto-char (car error)) - (set-text-properties - (progn - (skip-chars-backward " \t\n") - (backward-char) - (point)) - (min (car error) (point-max)) - '(face error rear-nonsticky t)) - (buffer-string)))) - (setcdr error (error-message-string err))))) - filter))) - -(provide 'tablist-filter) -;;; tablist-filter.el ends here diff -Nru emacs-pdf-tools-0.70/Makefile emacs-pdf-tools-0.80/Makefile --- emacs-pdf-tools-0.70/Makefile 2016-06-05 12:32:19.000000000 +0000 +++ emacs-pdf-tools-0.80/Makefile 2017-09-10 03:47:50.000000000 +0000 @@ -11,10 +11,11 @@ # Note: If you change this, also change it in lisp/pdf-tools.el and # server/configure.ac . -PACKAGE_VERSION = 0.70 +PACKAGE_VERSION = 0.80 PKGFILE_CONTENT = (define-package "pdf-tools" "$(PACKAGE_VERSION)" \ "Support library for PDF documents." \ - (quote ((emacs "24.3") (let-alist "1.0.1"))) \ + (quote ((emacs "24.3") (let-alist "1.0.4") \ + (tablist "0.70"))) \ :keywords \ (quote ("files" "multimedia"))) @@ -25,7 +26,7 @@ all: package -clean: +clean: rm -rf -- $(PACKAGE_DIR) rm -f -- $(PACKAGE_NAME).tar rm -f -- lisp/*.elc @@ -43,7 +44,7 @@ echo '$(PKGFILE_CONTENT)' > '$(PACKAGE_DIR)/pdf-tools-pkg.el' tar cf '$(PACKAGE_NAME).tar' '$(PACKAGE_DIR)' -melpa-package: +melpa-package: $(MAKE) distclean mkdir -p '$(PACKAGE_DIR)/build' cp lisp/*.el README '$(PACKAGE_DIR)' @@ -88,6 +89,11 @@ melpa-build: server/epdfinfo -cp -p server/epdfinfo .. + @if [ "$(shell uname -o)" = "Msys" ]; then \ + for f in $(shell ldd server/epdfinfo | awk '/mingw/ {print $$3}'); do \ + cp $$f ..; \ + done; \ + fi $(MAKE) distclean @if [ -x ../epdfinfo ]; then \ echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~"; \ diff -Nru emacs-pdf-tools-0.70/NEWS emacs-pdf-tools-0.80/NEWS --- emacs-pdf-tools-0.70/NEWS 2016-06-05 12:32:19.000000000 +0000 +++ emacs-pdf-tools-0.80/NEWS 2017-09-10 03:47:50.000000000 +0000 @@ -1,9 +1,23 @@ -*- org -*- +* Version 0.80 +** Tablist package + The files tablist.el and tablist-filter.el are no longer part of + pdf-tools, but continue to live on in the tablist package, on which + pdf-tools now depends on. +** View +*** Encrypted files + When encountering an encrypted file, query for a password and + attempt to decrypt it. +*** Backward sync from isearch + In isearch, press M-s s to visit the source of the current match. +*** Disable unicode in mode-line + New variable pdf-view-use-unicode-lighter which allows for + disabling the use of unicode in the mode-line. * Version 0.70 ** View *** Register integration - The keys m and ' now set resp. jump to a register corresponging to + The keys m and ' now set resp. jump to a register corresponding to a position in the PDF. Also '' is handled special: It jumps to the position before the last register-jump. *** Export parts of a page as an image @@ -16,7 +30,7 @@ A virtual PDF is a collection of pages (or parts thereof) of arbitrary documents, which appear to the rest of pdf-tools as one big PDF, though they are always read-only. - + * Version 0.60 ** Regexp support You may now search for perl-compatible regular expressions (PCRE) @@ -65,7 +79,7 @@ ** Compatible with Emacs 24.3 ** Integrate with bookmark.el ** Compiling on OSX - PDF Tools should now compile on OSX, though tis is unsupported. + PDF Tools should now compile on OSX, though it is unsupported. ** MELPA Try to handle an update via MELPA by package.el by shutting down the server, recompiling and restarting it. This may be deactivated diff -Nru emacs-pdf-tools-0.70/README emacs-pdf-tools-0.80/README --- emacs-pdf-tools-0.70/README 2016-06-05 12:32:19.000000000 +0000 +++ emacs-pdf-tools-0.80/README 2017-09-10 03:47:50.000000000 +0000 @@ -12,62 +12,63 @@ This rendering is performed by a special library named, for whatever reason, poppler, running inside a server program. This - program is called ~epdfinfo~ and it's job is it to successively + program is called ~epdfinfo~ and its job is it to successively read requests from Emacs and produce the proper results, i.e. the - PNG image of a PDF page. - + PNG image of a PDF page. + Actually, displaying PDF files is just one part of PDF Tools. - Since poppler can provide us with all kinds of informations about a + Since poppler can provide us with all kinds of information about a document and is also able to modify it, there is a lot more we can do with it. [[http://www.dailymotion.com/video/x2bc1is_pdf-tools-tourdeforce_tech?forcedQuality%3Dhd720][Watch]] + Please read also about [[#known-problems][known problems.]] + ** Features -*** View - View PDF documents in a buffer with DocView-like bindings. -*** Isearch - Interactively search PDF documents like any other buffer, either - for a string or a PCRE. -*** Occur - List lines matching a string or regexp in one or more PDF - documents. -*** Follow links + + View :: View PDF documents in a buffer with DocView-like + bindings. + + Isearch :: Interactively search PDF documents like any other + buffer, either for a string or a PCRE. + + Occur :: List lines matching a string or regexp in one or more + PDF documents. + + Follow :: Click on highlighted links, moving to some part of a different page, some external file, a website or any other URI. Links may also be followed by keyboard commands. -*** Annotations - Display and list text and markup annotations (like underline), - edit their contents and attributes (e.g. color), move them around, - delete them or create new ones and then save the modifications - back to the PDF file. -*** Attachments - Save files attached to the PDF-file or list them in a dired buffer. -*** Outline - Use imenu or a special buffer to examine and navigate the PDF's - outline. -*** SyncTeX - Jump from a position on a page directly to the TeX source and - vice versa. -*** Virtual PDF + + Annotations :: Display and list text and markup annotations (like + underline), edit their contents and attributes + (e.g. color), move them around, delete them or + create new ones and then save the modifications + back to the PDF file. + + Attachments :: Save files attached to the PDF-file or list them + in a dired buffer. + + Outline :: Use imenu or a special buffer to examine and navigate + the PDF's outline. + + SyncTeX :: Jump from a position on a page directly to the TeX + source and vice versa. + + Virtual :: Use a collection of documents as if it where one, big single PDF. - -*** Misc - + Display PDF's metadata. - + Mark a region and kill the text from the PDF. - + Keep track of visited pages via a history. - + Apply a color filter for reading in low light conditions. + + + Misc :: + - Display PDF's metadata. + - Mark a region and kill the text from the PDF. + - Keep track of visited pages via a history. + - Apply a color filter for reading in low light conditions. ** Installation The package may be installed via melpa and it will try to build the - server part when it is activated the first time, though the next - section is still relevant. - + server part when it is activated the first time. Though the next + section regarding build-prerequisites is still relevant, the rest + of the installation instructions assume a build from within a git + repository. (The melpa package has a different directory + structure.) + *** Server Prerequisites You'll need GNU Emacs \ge 24.3 and some form of a GNU/Linux OS. Other operating systems are currently not supported (patches welcome). The following instructions assume a Debian-based system. (The prerequisites may be installed automatically on this - kind of systems, see [[Compilation]] .) - + kind of systems, see [[#compilation][Compilation]] .) + First make sure a suitable build-system is installed. We need at least a C/C++ compiler (both ~gcc~ and ~g++~), ~make~, ~automake~ and ~autoconf~. @@ -75,13 +76,15 @@ Next we need to install a few libraries PDF Tools depends on, some of which are probably already on your system. #+begin_src sh - $ sudo aptitude install libpng-dev libz-dev - $ sudo aptitude install libpoppler-glib-dev - $ sudo aptitude install libpoppler-private-dev + $ sudo aptitude install libpng-dev zlib1g-dev + $ sudo aptitude install libpoppler-glib-dev + $ sudo aptitude install libpoppler-private-dev #+end_src On some older Ubuntu systems, the final command will possibly give an error. This should be no problem, since in some versions this - package was contained in the main package ~libpoppler-dev~. + package was contained in the main package ~libpoppler-dev~. Also + note, that ~zlib1g-dev~ was for a long time called ~libz-dev~, + which it still may be on your system. Debian wheezy comes with libpoppler version 0.18, which is pretty old. The minimally required version is 0.16, but some features of @@ -111,7 +114,7 @@ to have been successfully compiled. You will need to install poppler which you can get with homebrew via #+BEGIN_SRC sh - $ brew install poppler + $ brew install poppler automake #+END_SRC You will also have to help ~pkg-config~ find some libraries by @@ -120,10 +123,54 @@ $ export PKG_CONFIG_PATH=/usr/local/Cellar/zlib/1.2.8/lib/pkgconfig:/usr/local/lib/pkgconfig:/opt/X11/lib/pkgconfig #+END_SRC or likewise within Emacs using `setenv`. - + After that, compilation should proceed as normal. +**** Compiling on FreeBSD + Although not officially suppported, it has been reported that + pdf-tools work well on FreeBSD. Install the dependencies with +#+BEGIN_SRC sh + $ pkg install autotools gmake poppler-glib +#+END_SRC + + If you choose not to install from melpa, you must substitute + ~gmake~ for ~make~ in the instructions below. +**** Compiling on Centos + It is possible to compile pdf-tools on Centos. Install poppler the dependencies with: +#+BEGIN_SRC sh + $ yum install poppler-devel poppler-glib-devel +#+END_SRC + +**** Compiling on Fedora +#+BEGIN_SRC sh + $ sudo dnf install make automake autoconf gcc gcc-c++ ImageMagick libpng-devel zlib-devel poppler-glib-devel +#+END_SRC + +**** Compiling on Windows + PDF Tools can be built and used on Windows using the MSYS2 + compiler. This will work with native (not cygwin) Windows builds of + emacs. This includes the standard binaries provided by the GNU + project, those available as MSYS2 packages and numerous third-party + binaries. It has been tested with emacs 25.1. Instructions are + provided under [[Compilation and installation on Windows]], below. +**** Compiling on Cygwin + On [[https://www.cygwin.com/][Cygwin]] the following dependencies are needed. + + - libpoppler-devel (*Lib* category) + - libpoppler-glib-devel (*Lib* category) + - libpng-devel (*Devel* category) + - make (*Devel* category) + - gcc-core (*Devel* category) + - gcc-g++ (*Devel* category) + - autoconf (*Devel* category) + - automake (*Devel* category) + - perl (*Perl* category) + - emacs-w32 (*Editors* category) + *** Compilation - Now it's time to compile the source. + :PROPERTIES: + :CUSTOM_ID: compilation + :END: + Now it's time to compile the source. #+begin_src sh $ cd /path/to/pdf-tools $ make install-server-deps # optional @@ -132,12 +179,83 @@ The ~make install-server-deps~ command will try to install all necessary programs and libraries to build the package, though it'll only work, if ~sudo~ and ~apt-get~ are available. - + This should compile the source code and create a Emacs Lisp Package in the root directory of the project. The configure script also tells you at the very end, which features, depending on the libpoppler version, will be available. These commands should give no error, otherwise you are in trouble. +**** Compilation and installation on Windows + If using the GNU binaries for Windows, support for PNG and zlib + must first be installed by copying the appropriate dlls into + emacs' ~bin/~ directory. Most third-party binaries come with this + already done. + + First, install [[http://www.msys2.org/][install MSYS2]] and update + the package database and core packages using the instructions + provided. Then, to compile PDF tools itself: + + 1. Open msys2 shell + + 2. Update and install dependencies, skipping any you already have + #+BEGIN_SRC sh + pacman -Syu + pacman -S base-devel + pacman -S mingw-w64-x86_64-toolchain + pacman -S mingw-w64-x86_64-zlib + pacman -S mingw-w64-x86_64-libpng + pacman -S mingw-w64-x86_64-poppler + pacman -S mingw-w64-x86_64-imagemagick + #+END_SRC + + 3. Install PDF tools in Emacs, but do not try to compile the + server. Instead, get a separate copy of the source somewhere + else. + #+BEGIN_SRC sh + git clone https://github.com/politza/pdf-tools + #+END_SRC + + 4. Open mingw64 shell + + 5. Compile pdf-tools + #+BEGIN_SRC sh + cd pdf-tools/build + make -s + #+END_SRC + + 6. This should produce a file ~server/epdfinfo.exe~. Copy this file + into the ~pdf-tools/~ installation directory in your Emacs. + + 7. Start Emacs and activate the package. + #+BEGIN_SRC + M-x pdf-tools-install RET + #+END_SRC + + 8. Test. + #+BEGIN_SRC + M-x pdf-info-check-epdfinfo RET + #+END_SRC + + If this is successful, ~(pdf-tools-install)~ can be added to Emacs' + config. Note that libraries from other GNU utilities, such as Git + for Windows, may interfere with those needed by PDF Tools. + ~pdf-info-check-epdinfo~ will succeed, but errors occur when trying + to view a PDF file. This can be fixed by ensuring that the MSYS + libraries are always preferred in emacs: + + #+BEGIN_SRC emacs-lisp + (setenv "PATH" (concat "C:\\msys64\\mingw64\\bin;" (getenv "PATH"))) + #+END_SRC + +*** ELisp Prerequisites + This package depends on the following Elisp packages, which should + be installed before installing the Pdf Tools package. + + | Package | Required version | + |-----------+----------------------------------| + | [[https://elpa.gnu.org/packages/let-alist.html][let-alist]] | >= 1.0.4 (comes with Emacs 25.2) | + | [[http://melpa.org/#/tablist][tablist]] | >= 0.70 | + |-----------+----------------------------------| *** Installing If ~make~ produced the ELP file ~pdf-tools-${VERSION}.tar~ you are @@ -150,7 +268,7 @@ #+begin_src elisp M-x package-install-file RET pdf-tools-${VERSION}.tar RET #+end_src - + To complete the installation process, you need to activate the package by putting #+begin_src elisp @@ -173,6 +291,30 @@ This also applies when updating via package and melpa. +** Known problems + :PROPERTIES: + :CUSTOM_ID: known-problems + :END: + +*** linum-mode + PDF Tools does not work well together with ~linum-mode~ and + activating it in a ~pdf-view-mode~, e.g. via ~global-linum-mode~, + might make Emacs choke. + +*** auto-revert + Autorevert works by polling the file-system every + ~auto-revert-interval~ seconds, optionally combined with some + event-based reverting via [[https://www.gnu.org/software/emacs/manual/html_node/elisp/File-Notifications.html][file notification]]. But this currently + does not work reliably, such that Emacs may revert the PDF-buffer + while the corresponding file is still being written to (e.g. by + LaTeX), leading to a potential error. + + With a recent [[https://www.gnu.org/software/auctex/][auctex]] installation, you might want to put the + following somewhere in your dotemacs, which will revert the PDF-buffer + *after* the TeX compilation has finished. +#+BEGIN_SRC emacs-lisp + (add-hook 'TeX-after-compilation-finished-functions #'TeX-revert-document-buffer) +#+END_SRC ** Some keybindings | Navigation | | @@ -211,10 +353,10 @@ | Close Annotation List | ~q~ | | Add and edit annotations | via Mouse selection and left-click context menu | -| Syncing with Auctex | | -|----------------------------------+----------------| -| jump to PDF location from source | ~C-c C-g~ | -| jump source location from PDF | ~double-click~ | +| Syncing with Auctex | | +|----------------------------------+-------------| +| jump to PDF location from source | ~C-c C-g~ | +| jump source location from PDF | ~C-mouse-1~ | | Miscellaneous | | |-----------------------------------------------+-----------| diff -Nru emacs-pdf-tools-0.70/README.org emacs-pdf-tools-0.80/README.org --- emacs-pdf-tools-0.70/README.org 2016-06-05 12:32:19.000000000 +0000 +++ emacs-pdf-tools-0.80/README.org 2017-09-10 03:47:50.000000000 +0000 @@ -12,62 +12,63 @@ This rendering is performed by a special library named, for whatever reason, poppler, running inside a server program. This - program is called ~epdfinfo~ and it's job is it to successively + program is called ~epdfinfo~ and its job is it to successively read requests from Emacs and produce the proper results, i.e. the - PNG image of a PDF page. - + PNG image of a PDF page. + Actually, displaying PDF files is just one part of PDF Tools. - Since poppler can provide us with all kinds of informations about a + Since poppler can provide us with all kinds of information about a document and is also able to modify it, there is a lot more we can do with it. [[http://www.dailymotion.com/video/x2bc1is_pdf-tools-tourdeforce_tech?forcedQuality%3Dhd720][Watch]] + Please read also about [[#known-problems][known problems.]] + ** Features -*** View - View PDF documents in a buffer with DocView-like bindings. -*** Isearch - Interactively search PDF documents like any other buffer, either - for a string or a PCRE. -*** Occur - List lines matching a string or regexp in one or more PDF - documents. -*** Follow links + + View :: View PDF documents in a buffer with DocView-like + bindings. + + Isearch :: Interactively search PDF documents like any other + buffer, either for a string or a PCRE. + + Occur :: List lines matching a string or regexp in one or more + PDF documents. + + Follow :: Click on highlighted links, moving to some part of a different page, some external file, a website or any other URI. Links may also be followed by keyboard commands. -*** Annotations - Display and list text and markup annotations (like underline), - edit their contents and attributes (e.g. color), move them around, - delete them or create new ones and then save the modifications - back to the PDF file. -*** Attachments - Save files attached to the PDF-file or list them in a dired buffer. -*** Outline - Use imenu or a special buffer to examine and navigate the PDF's - outline. -*** SyncTeX - Jump from a position on a page directly to the TeX source and - vice versa. -*** Virtual PDF + + Annotations :: Display and list text and markup annotations (like + underline), edit their contents and attributes + (e.g. color), move them around, delete them or + create new ones and then save the modifications + back to the PDF file. + + Attachments :: Save files attached to the PDF-file or list them + in a dired buffer. + + Outline :: Use imenu or a special buffer to examine and navigate + the PDF's outline. + + SyncTeX :: Jump from a position on a page directly to the TeX + source and vice versa. + + Virtual :: Use a collection of documents as if it where one, big single PDF. - -*** Misc - + Display PDF's metadata. - + Mark a region and kill the text from the PDF. - + Keep track of visited pages via a history. - + Apply a color filter for reading in low light conditions. + + + Misc :: + - Display PDF's metadata. + - Mark a region and kill the text from the PDF. + - Keep track of visited pages via a history. + - Apply a color filter for reading in low light conditions. ** Installation The package may be installed via melpa and it will try to build the - server part when it is activated the first time, though the next - section is still relevant. - + server part when it is activated the first time. Though the next + section regarding build-prerequisites is still relevant, the rest + of the installation instructions assume a build from within a git + repository. (The melpa package has a different directory + structure.) + *** Server Prerequisites You'll need GNU Emacs \ge 24.3 and some form of a GNU/Linux OS. Other operating systems are currently not supported (patches welcome). The following instructions assume a Debian-based system. (The prerequisites may be installed automatically on this - kind of systems, see [[Compilation]] .) - + kind of systems, see [[#compilation][Compilation]] .) + First make sure a suitable build-system is installed. We need at least a C/C++ compiler (both ~gcc~ and ~g++~), ~make~, ~automake~ and ~autoconf~. @@ -75,13 +76,15 @@ Next we need to install a few libraries PDF Tools depends on, some of which are probably already on your system. #+begin_src sh - $ sudo aptitude install libpng-dev libz-dev - $ sudo aptitude install libpoppler-glib-dev - $ sudo aptitude install libpoppler-private-dev + $ sudo aptitude install libpng-dev zlib1g-dev + $ sudo aptitude install libpoppler-glib-dev + $ sudo aptitude install libpoppler-private-dev #+end_src On some older Ubuntu systems, the final command will possibly give an error. This should be no problem, since in some versions this - package was contained in the main package ~libpoppler-dev~. + package was contained in the main package ~libpoppler-dev~. Also + note, that ~zlib1g-dev~ was for a long time called ~libz-dev~, + which it still may be on your system. Debian wheezy comes with libpoppler version 0.18, which is pretty old. The minimally required version is 0.16, but some features of @@ -111,7 +114,7 @@ to have been successfully compiled. You will need to install poppler which you can get with homebrew via #+BEGIN_SRC sh - $ brew install poppler + $ brew install poppler automake #+END_SRC You will also have to help ~pkg-config~ find some libraries by @@ -120,10 +123,54 @@ $ export PKG_CONFIG_PATH=/usr/local/Cellar/zlib/1.2.8/lib/pkgconfig:/usr/local/lib/pkgconfig:/opt/X11/lib/pkgconfig #+END_SRC or likewise within Emacs using `setenv`. - + After that, compilation should proceed as normal. +**** Compiling on FreeBSD + Although not officially suppported, it has been reported that + pdf-tools work well on FreeBSD. Install the dependencies with +#+BEGIN_SRC sh + $ pkg install autotools gmake poppler-glib +#+END_SRC + + If you choose not to install from melpa, you must substitute + ~gmake~ for ~make~ in the instructions below. +**** Compiling on Centos + It is possible to compile pdf-tools on Centos. Install poppler the dependencies with: +#+BEGIN_SRC sh + $ yum install poppler-devel poppler-glib-devel +#+END_SRC + +**** Compiling on Fedora +#+BEGIN_SRC sh + $ sudo dnf install make automake autoconf gcc gcc-c++ ImageMagick libpng-devel zlib-devel poppler-glib-devel +#+END_SRC + +**** Compiling on Windows + PDF Tools can be built and used on Windows using the MSYS2 + compiler. This will work with native (not cygwin) Windows builds of + emacs. This includes the standard binaries provided by the GNU + project, those available as MSYS2 packages and numerous third-party + binaries. It has been tested with emacs 25.1. Instructions are + provided under [[Compilation and installation on Windows]], below. +**** Compiling on Cygwin + On [[https://www.cygwin.com/][Cygwin]] the following dependencies are needed. + + - libpoppler-devel (*Lib* category) + - libpoppler-glib-devel (*Lib* category) + - libpng-devel (*Devel* category) + - make (*Devel* category) + - gcc-core (*Devel* category) + - gcc-g++ (*Devel* category) + - autoconf (*Devel* category) + - automake (*Devel* category) + - perl (*Perl* category) + - emacs-w32 (*Editors* category) + *** Compilation - Now it's time to compile the source. + :PROPERTIES: + :CUSTOM_ID: compilation + :END: + Now it's time to compile the source. #+begin_src sh $ cd /path/to/pdf-tools $ make install-server-deps # optional @@ -132,12 +179,83 @@ The ~make install-server-deps~ command will try to install all necessary programs and libraries to build the package, though it'll only work, if ~sudo~ and ~apt-get~ are available. - + This should compile the source code and create a Emacs Lisp Package in the root directory of the project. The configure script also tells you at the very end, which features, depending on the libpoppler version, will be available. These commands should give no error, otherwise you are in trouble. +**** Compilation and installation on Windows + If using the GNU binaries for Windows, support for PNG and zlib + must first be installed by copying the appropriate dlls into + emacs' ~bin/~ directory. Most third-party binaries come with this + already done. + + First, install [[http://www.msys2.org/][install MSYS2]] and update + the package database and core packages using the instructions + provided. Then, to compile PDF tools itself: + + 1. Open msys2 shell + + 2. Update and install dependencies, skipping any you already have + #+BEGIN_SRC sh + pacman -Syu + pacman -S base-devel + pacman -S mingw-w64-x86_64-toolchain + pacman -S mingw-w64-x86_64-zlib + pacman -S mingw-w64-x86_64-libpng + pacman -S mingw-w64-x86_64-poppler + pacman -S mingw-w64-x86_64-imagemagick + #+END_SRC + + 3. Install PDF tools in Emacs, but do not try to compile the + server. Instead, get a separate copy of the source somewhere + else. + #+BEGIN_SRC sh + git clone https://github.com/politza/pdf-tools + #+END_SRC + + 4. Open mingw64 shell + + 5. Compile pdf-tools + #+BEGIN_SRC sh + cd pdf-tools/build + make -s + #+END_SRC + + 6. This should produce a file ~server/epdfinfo.exe~. Copy this file + into the ~pdf-tools/~ installation directory in your Emacs. + + 7. Start Emacs and activate the package. + #+BEGIN_SRC + M-x pdf-tools-install RET + #+END_SRC + + 8. Test. + #+BEGIN_SRC + M-x pdf-info-check-epdfinfo RET + #+END_SRC + + If this is successful, ~(pdf-tools-install)~ can be added to Emacs' + config. Note that libraries from other GNU utilities, such as Git + for Windows, may interfere with those needed by PDF Tools. + ~pdf-info-check-epdinfo~ will succeed, but errors occur when trying + to view a PDF file. This can be fixed by ensuring that the MSYS + libraries are always preferred in emacs: + + #+BEGIN_SRC emacs-lisp + (setenv "PATH" (concat "C:\\msys64\\mingw64\\bin;" (getenv "PATH"))) + #+END_SRC + +*** ELisp Prerequisites + This package depends on the following Elisp packages, which should + be installed before installing the Pdf Tools package. + + | Package | Required version | + |-----------+----------------------------------| + | [[https://elpa.gnu.org/packages/let-alist.html][let-alist]] | >= 1.0.4 (comes with Emacs 25.2) | + | [[http://melpa.org/#/tablist][tablist]] | >= 0.70 | + |-----------+----------------------------------| *** Installing If ~make~ produced the ELP file ~pdf-tools-${VERSION}.tar~ you are @@ -150,7 +268,7 @@ #+begin_src elisp M-x package-install-file RET pdf-tools-${VERSION}.tar RET #+end_src - + To complete the installation process, you need to activate the package by putting #+begin_src elisp @@ -173,6 +291,30 @@ This also applies when updating via package and melpa. +** Known problems + :PROPERTIES: + :CUSTOM_ID: known-problems + :END: + +*** linum-mode + PDF Tools does not work well together with ~linum-mode~ and + activating it in a ~pdf-view-mode~, e.g. via ~global-linum-mode~, + might make Emacs choke. + +*** auto-revert + Autorevert works by polling the file-system every + ~auto-revert-interval~ seconds, optionally combined with some + event-based reverting via [[https://www.gnu.org/software/emacs/manual/html_node/elisp/File-Notifications.html][file notification]]. But this currently + does not work reliably, such that Emacs may revert the PDF-buffer + while the corresponding file is still being written to (e.g. by + LaTeX), leading to a potential error. + + With a recent [[https://www.gnu.org/software/auctex/][auctex]] installation, you might want to put the + following somewhere in your dotemacs, which will revert the PDF-buffer + *after* the TeX compilation has finished. +#+BEGIN_SRC emacs-lisp + (add-hook 'TeX-after-compilation-finished-functions #'TeX-revert-document-buffer) +#+END_SRC ** Some keybindings | Navigation | | @@ -211,10 +353,10 @@ | Close Annotation List | ~q~ | | Add and edit annotations | via Mouse selection and left-click context menu | -| Syncing with Auctex | | -|----------------------------------+----------------| -| jump to PDF location from source | ~C-c C-g~ | -| jump source location from PDF | ~double-click~ | +| Syncing with Auctex | | +|----------------------------------+-------------| +| jump to PDF location from source | ~C-c C-g~ | +| jump source location from PDF | ~C-mouse-1~ | | Miscellaneous | | |-----------------------------------------------+-----------| diff -Nru emacs-pdf-tools-0.70/server/configure.ac emacs-pdf-tools-0.80/server/configure.ac --- emacs-pdf-tools-0.70/server/configure.ac 2016-06-05 12:32:19.000000000 +0000 +++ emacs-pdf-tools-0.80/server/configure.ac 2017-09-10 03:47:50.000000000 +0000 @@ -2,7 +2,7 @@ # Process this file with autoconf to produce a configure script. AC_PREREQ([2.67]) -AC_INIT([epdfinfo], 0.70, [politza@fh-trier.de]) +AC_INIT([epdfinfo], 0.80, [politza@fh-trier.de]) AM_INIT_AUTOMAKE([-Wall -Wno-override foreign silent-rules]) AC_CONFIG_SRCDIR([epdfinfo.h]) AC_CONFIG_HEADERS([config.h]) @@ -28,10 +28,22 @@ PKG_CHECK_EXISTS([poppler-glib >= 0.26], [HAVE_POPPLER_ANNOT_MARKUP=yes]) PKG_CHECK_MODULES([zlib], [zlib]) -# Check for private poppler header. +# glib won't work properly on msys2 without it. +if test "$MSYSTEM" = MINGW32 -o "$MSYSTEM" = MINGW64; then + CFLAGS="-D__USE_MINGW_ANSI_STDIO=1 $CFLAGS" +fi + SAVED_CPPFLAGS=$CPPFLAGS CPPFLAGS=$poppler_CFLAGS AC_LANG_PUSH([C++]) +# Check if we can use the -std=c++11 option. +m4_include([m4/ax_check_compile_flag.m4]) +AX_CHECK_COMPILE_FLAG([-std=c++11], [HAVE_STD_CXX11=yes]) + +if test "$HAVE_STD_CXX11" = yes; then + CXXFLAGS="-std=c++11 $CXXFLAGS" +fi +# Check for private poppler header. AC_CHECK_HEADERS([Annot.h PDFDocEncoding.h], [], AC_MSG_ERROR([cannot find necessary poppler-private header (see README.org)])) AC_LANG_POP([C++]) @@ -53,17 +65,20 @@ [Define to 1 to enable adding of markup annotations (requires poppler-glib >= 0.26).]) fi +AC_CANONICAL_HOST # Checks for header files. -AC_CHECK_HEADERS([stdlib.h string.h strings.h]) +AC_CHECK_HEADERS([stdlib.h string.h strings.h err.h]) AC_MSG_CHECKING([for error.h]) SAVED_CFLAGS=$CFLAGS CFLAGS="$poppler_CFLAGS $poppler_glib_CFLAGS" AC_LANG_PUSH([C]) -AC_COMPILE_IFELSE([AC_LANG_PROGRAM([#include ],[error (0, 0, "");])], - [AC_DEFINE([HAVE_ERROR_H],1, [Define to 1 if error.h is useable.]) - AC_MSG_RESULT([yes])], - AC_MSG_RESULT([no])) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([ + #include + ],[error (0, 0, "");])], + [AC_DEFINE([HAVE_ERROR_H],1, [Define to 1 if error.h is useable.]) + AC_MSG_RESULT([yes])], + AC_MSG_RESULT([no])) AC_LANG_POP([C]) CFLAGS=$SAVED_CFLAGS @@ -76,7 +91,7 @@ # Checks for library functions. AC_FUNC_ERROR_AT_LINE AC_FUNC_STRTOD -AC_CHECK_FUNCS([strcspn strtol]) +AC_CHECK_FUNCS([strcspn strtol getline]) AC_CONFIG_FILES([Makefile]) AC_OUTPUT diff -Nru emacs-pdf-tools-0.70/server/epdfinfo.c emacs-pdf-tools-0.80/server/epdfinfo.c --- emacs-pdf-tools-0.70/server/epdfinfo.c 2016-06-05 12:32:19.000000000 +0000 +++ emacs-pdf-tools-0.80/server/epdfinfo.c 2017-09-10 03:47:50.000000000 +0000 @@ -18,7 +18,9 @@ #include #include -#include +#ifdef HAVE_ERR_H +# include +#endif #ifdef HAVE_ERROR_H # include #endif @@ -45,6 +47,86 @@ * Helper Functions * ================================================================== */ +#ifndef HAVE_ERR_H +/** + * Print error message and quit. + * + * @param eval Return code + * @param fmt Formatting string + */ +static void +err(int eval, const char *fmt, ...) +{ + va_list args; + + fprintf (stderr, "epdfinfo: "); + if (fmt != NULL) + { + va_start (args, fmt); + vfprintf (stderr, fmt, args); + va_end (args); + fprintf (stderr, ": %s\n", strerror(errno)); + } + else + { + fprintf (stderr, "\n"); + } + + fflush (stderr); + exit (eval); +} +#endif + +#ifndef HAVE_GETLINE +/** + * Read one line from a file. + * + * @param lineptr Pointer to malloc() allocated buffer + * @param n Pointer to size of buffer + * @param stream File pointer to read from + */ +static ssize_t +getline(char **lineptr, size_t *n, FILE *stream) +{ + size_t len = 0; + int ch; + + if ((lineptr == NULL) || (n == NULL)) + { + errno = EINVAL; + return -1; + } + + if (*lineptr == NULL) + { + *lineptr = malloc (128); + *n = 128; + } + + while ((ch = fgetc (stream)) != EOF) + { + (*lineptr)[len] = ch; + + if (++len >= *n) + { + *n += 128; + *lineptr = realloc (*lineptr, *n); + } + + if (ch == '\n') + break; + } + (*lineptr)[len] = '\0'; + + if (!len) + { + len = -1; + } + + return len; +} +#endif + /** * Free a list of command arguments. * @@ -421,7 +503,7 @@ if (options && options->usecolors) image_recolor (surface, &options->fg, &options->bg); - + cairo_destroy (cr); return surface; @@ -477,7 +559,7 @@ { unsigned char *buffer = g_malloc (width * height * 3); unsigned char *buffer_p = buffer; - + fprintf (file, "P6\n%d %d\n255\n", width, height); for (i = 0; i < width * height; ++i, data += 4, buffer_p += 3) ARGB_TO_RGB (buffer_p, data); @@ -1236,7 +1318,7 @@ poppler_page_get_crop_box (page, &cbox); xs = MIN (cbox.x1, cbox.x2); ys = MIN (cbox.y1, cbox.y2); - + if (inverse) { xs = -xs; ys = -ys; @@ -1823,7 +1905,7 @@ re = g_regex_new (regexp, cflags, mflags, &gerror); perror_if_not (NULL == gerror, "Invalid regexp: %s", gerror->message); - + OK_BEGIN (); for (pn = first; pn <= last; ++pn) { @@ -1840,7 +1922,7 @@ poppler_page_get_text_layout (page, &rectangles, &nrectangles); poppler_page_get_size (page, &width, &height); g_regex_match (re, text, 0, &match); - + while (g_match_info_matches (match)) { const double scale = 100.0; @@ -1852,7 +1934,7 @@ /* Does this ever happen ? */ if (! g_match_info_fetch_pos (match, 0, &start, &end)) continue; - + string = g_match_info_fetch (match, 0); ustart = g_utf8_strlen (text, start); ulen = g_utf8_strlen (string, -1); @@ -1872,11 +1954,11 @@ PopplerRectangle *r = rectangles + i; cairo_rectangle_int_t c; - c.x = (int) (scale * r->x1 + 0.5); - c.y = (int) (scale * r->y1 + 0.5); - c.width = (int) (scale * (r->x2 - r->x1) + 0.5); - c.height = (int) (scale * (r->y2 - r->y1) + 0.5); - + c.x = (int) (scale * r->x1 + 0.5); + c.y = (int) (scale * r->y1 + 0.5); + c.width = (int) (scale * (r->x2 - r->x1) + 0.5); + c.height = (int) (scale * (r->y2 - r->y1) + 0.5); + cairo_region_union_rectangle (region, &c); } @@ -1912,11 +1994,11 @@ cmd_regexp_flags (const epdfinfo_t *ctx, const command_arg_t *args) { OK_BEGIN (); - printf ("caseless:%d\n", G_REGEX_CASELESS); - printf ("multiline:%d\n", G_REGEX_MULTILINE); - printf ("dotall:%d\n", G_REGEX_DOTALL); - printf ("extended:%d\n", G_REGEX_EXTENDED); - printf ("anchored:%d\n", G_REGEX_ANCHORED); + printf ("caseless:%d\n", G_REGEX_CASELESS); + printf ("multiline:%d\n", G_REGEX_MULTILINE); + printf ("dotall:%d\n", G_REGEX_DOTALL); + printf ("extended:%d\n", G_REGEX_EXTENDED); + printf ("anchored:%d\n", G_REGEX_ANCHORED); printf ("dollar-endonly:%d\n", G_REGEX_DOLLAR_ENDONLY); printf ("ungreedy:%d\n", G_REGEX_UNGREEDY); printf ("raw:%d\n", G_REGEX_RAW); @@ -2906,7 +2988,7 @@ pn = synctex_node_page (node); page = poppler_document_get_page(doc->pdf, pn - 1); - perror_if_not (page, "Destination not found"); + perror_if_not (page, "Page not found"); x1 = synctex_node_box_visible_h (node); y1 = synctex_node_box_visible_v (node) - synctex_node_box_visible_height (node); @@ -2956,7 +3038,7 @@ did you run latex with `--synctex=1' ?"); page = poppler_document_get_page(doc->pdf, pn - 1); - perror_if_not (page, "Destination not found"); + perror_if_not (page, "Page not found"); poppler_page_get_size (page, &width, &height); x = x * width; y = y * height; @@ -2974,7 +3056,8 @@ column = synctex_node_column (node); OK_BEGIN (); - printf("%s:%d:%d\n", filename, line, column); + print_response_string (filename, COLON); + printf("%d:%d\n", line, column); OK_END (); error: @@ -3020,14 +3103,14 @@ if (! nrest_args) goto theend; - + cr = cairo_create (surface); cairo_scale (cr, width / pt_width, width / pt_width); while (i < nrest_args) { const char* keyword; - + perror_if_not (command_arg_parse_arg (ctx, rest_args[i], &rest_arg, ARG_STRING, &error_msg), "%s", error_msg); @@ -3059,7 +3142,7 @@ alpha = rest_arg.value.edge; } else if (! strcmp (keyword, ":crop-to") - || ! strcmp (keyword, ":highlight-region") + || ! strcmp (keyword, ":highlight-region") || ! strcmp (keyword, ":highlight-text") || ! strcmp (keyword, ":highlight-line")) { @@ -3070,14 +3153,14 @@ ++i; r = &rest_arg.value.rectangle; - + if (! strcmp (keyword, ":crop-to")) { gdouble w = (cb.x2 - cb.x1); gdouble h = (cb.y2 - cb.y1); gdouble x1 = cb.x1; gdouble y1 = cb.y1; - + cb.x1 = r->x1 * w + x1; cb.x2 = r->x2 * w + x1; cb.y1 = r->y1 * h + y1; @@ -3090,7 +3173,7 @@ r->x2 = pt_width * r->x2 * (cb.x2 - cb.x1) + pt_width * cb.x1; r->y1 = pt_height * r->y1 * (cb.y2 - cb.y1) + pt_height * cb.y1; r->y2 = pt_height * r->y2 * (cb.y2 - cb.y1) + pt_height * cb.y1; - + if (! strcmp (keyword, ":highlight-region")) { const double deg = M_PI / 180.0; @@ -3122,10 +3205,10 @@ cairo_set_line_width (cr, line_width); cairo_stroke (cr); } - else + else { gboolean is_single_line = ! strcmp (keyword, ":highlight-line"); - + if (is_single_line) { gdouble m = r->y1 + (r->y2 - r->y1) / 2; @@ -3162,9 +3245,9 @@ cairo_set_source_surface (cr, surface, -r.x, -r.y); cairo_paint (cr); cairo_surface_destroy (surface); - surface = nsurface; + surface = nsurface; } - + theend: image_write_print_response (surface, PNG); @@ -3303,9 +3386,9 @@ guint nrectangles; int i; gboolean have_position = region.y2 < 0; - + perror_if_not (page, "No such page %d", pn); - + text = poppler_page_get_text (page); text_p = text; poppler_page_get_text_layout (page, &rectangles, &nrectangles); @@ -3313,14 +3396,14 @@ region.x1 *= width; region.x2 *= width; region.y1 *= height; - region.y2 *= height; + region.y2 *= height; OK_BEGIN (); for (i = 0; i < nrectangles && *text_p; ++i) { PopplerRectangle *r = &rectangles[i]; char *nextc = g_utf8_offset_to_pointer (text_p, 1); - + if ((have_position && region.x1 >= r->x1 && region.x1 <= r->x2 @@ -3375,7 +3458,7 @@ for (i = 0; i < G_N_ELEMENTS (document_options); ++i) { command_arg_t arg; - + arg.type = document_options[i].type; memcpy (&arg.value, ((char*) &doc->options) + document_options[i].offset, @@ -3403,9 +3486,9 @@ gchar *error_msg = NULL; document_options_t opts = doc->options; const size_t nopts = G_N_ELEMENTS (document_options); - + perror_if_not (nrest % 2 == 0, "Even number of key/value pairs expected"); - + while (i < nrest) { int j; @@ -3520,7 +3603,7 @@ DEC_CMD (boundingbox), DEC_CMD (charlayout), DEC_CMD (pagelabels), - + /* Annotations */ DEC_CMD (getannots), DEC_CMD (getannot), @@ -3551,6 +3634,12 @@ size_t line_size; const char *error_log = "/dev/null"; +#ifdef __MINGW32__ + error_log = "NUL"; + _setmode(_fileno(stdin), _O_BINARY); + _setmode(_fileno(stdout), _O_BINARY); +#endif + if (argc > 2) { fprintf(stderr, "usage: epdfinfo [ERROR-LOGFILE]\n"); @@ -3627,4 +3716,3 @@ err (2, NULL); exit (EXIT_SUCCESS); } - diff -Nru emacs-pdf-tools-0.70/server/epdfinfo.h emacs-pdf-tools-0.80/server/epdfinfo.h --- emacs-pdf-tools-0.70/server/epdfinfo.h 2016-06-05 12:32:19.000000000 +0000 +++ emacs-pdf-tools-0.80/server/epdfinfo.h 2017-09-10 03:47:50.000000000 +0000 @@ -178,7 +178,7 @@ typedef struct { - const char *name; + const char *name; command_arg_type_t type; size_t offset; } document_option_t; diff -Nru emacs-pdf-tools-0.70/server/.gitignore emacs-pdf-tools-0.80/server/.gitignore --- emacs-pdf-tools-0.70/server/.gitignore 2016-06-05 12:32:19.000000000 +0000 +++ emacs-pdf-tools-0.80/server/.gitignore 2017-09-10 03:47:50.000000000 +0000 @@ -20,3 +20,6 @@ config.h.in~ .clang_complete callgrind.out.* +config.guess +config.sub +TAGS diff -Nru emacs-pdf-tools-0.70/server/m4/ax_check_compile_flag.m4 emacs-pdf-tools-0.80/server/m4/ax_check_compile_flag.m4 --- emacs-pdf-tools-0.70/server/m4/ax_check_compile_flag.m4 1970-01-01 00:00:00.000000000 +0000 +++ emacs-pdf-tools-0.80/server/m4/ax_check_compile_flag.m4 2017-09-10 03:47:50.000000000 +0000 @@ -0,0 +1,74 @@ +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_check_compile_flag.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT]) +# +# DESCRIPTION +# +# Check whether the given FLAG works with the current language's compiler +# or gives an error. (Warnings, however, are ignored) +# +# ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on +# success/failure. +# +# If EXTRA-FLAGS is defined, it is added to the current language's default +# flags (e.g. CFLAGS) when the check is done. The check is thus made with +# the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to +# force the compiler to issue an error when a bad flag is given. +# +# INPUT gives an alternative input source to AC_COMPILE_IFELSE. +# +# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this +# macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG. +# +# LICENSE +# +# Copyright (c) 2008 Guido U. Draheim +# Copyright (c) 2011 Maarten Bosmans +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# This program 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 this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +#serial 5 + +AC_DEFUN([AX_CHECK_COMPILE_FLAG], +[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF +AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl +AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [ + ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS + _AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1" + AC_COMPILE_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])], + [AS_VAR_SET(CACHEVAR,[yes])], + [AS_VAR_SET(CACHEVAR,[no])]) + _AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags]) +AS_VAR_IF(CACHEVAR,yes, + [m4_default([$2], :)], + [m4_default([$3], :)]) +AS_VAR_POPDEF([CACHEVAR])dnl +])dnl AX_CHECK_COMPILE_FLAGS diff -Nru emacs-pdf-tools-0.70/server/Makefile.am emacs-pdf-tools-0.80/server/Makefile.am --- emacs-pdf-tools-0.70/server/Makefile.am 2016-06-05 12:32:19.000000000 +0000 +++ emacs-pdf-tools-0.80/server/Makefile.am 2017-09-10 03:47:50.000000000 +0000 @@ -9,7 +9,7 @@ noinst_LIBRARIES = libsynctex.a libsynctex_a_SOURCES = synctex_parser.c synctex_parser_utils.c synctex_parser.h \ synctex_parser_local.h synctex_parser_utils.h -libsynctex_a_CFLAGS = -w +libsynctex_a_CFLAGS = -w $(zlib_CFLAGS) GITCLEANFILES = Makefile.in aclocal.m4 config.h.in \ configure depcomp install-sh missing autom4te.cache \ diff -Nru emacs-pdf-tools-0.70/server/poppler-hack.cc emacs-pdf-tools-0.80/server/poppler-hack.cc --- emacs-pdf-tools-0.70/server/poppler-hack.cc 2016-06-05 12:32:19.000000000 +0000 +++ emacs-pdf-tools-0.80/server/poppler-hack.cc 2017-09-10 03:47:50.000000000 +0000 @@ -21,7 +21,7 @@ extern "C" { - + GType poppler_annot_get_type (void) G_GNUC_CONST; GType poppler_annot_markup_get_type (void) G_GNUC_CONST; @@ -57,7 +57,7 @@ if (! s) return NULL; - + if (s->hasUnicodeMarker()) { result = g_convert (s->getCString () + 2, s->getLength () - 2, @@ -66,7 +66,7 @@ int len; gunichar *ucs4_temp; int i; - + len = s->getLength (); ucs4_temp = g_new (gunichar, len + 1); for (i = 0; i < len; ++i) { @@ -87,13 +87,13 @@ { GooString *state = a->annot->getAppearState (); char *ustate = _xpoppler_goo_string_to_utf8 (state); - + a->annot->setRect (rectangle->x1, rectangle->y1, rectangle->x2, rectangle->y2); a->annot->setAppearanceState (ustate); g_free (ustate); } -#endif +#endif // This function is in the library, but the enforced date parsing is // incomplete (at least in some versions), because it ignores the // timezone. diff -Nru emacs-pdf-tools-0.70/server/synctex_parser.c emacs-pdf-tools-0.80/server/synctex_parser.c --- emacs-pdf-tools-0.70/server/synctex_parser.c 2016-06-05 12:32:19.000000000 +0000 +++ emacs-pdf-tools-0.80/server/synctex_parser.c 2017-09-10 03:47:50.000000000 +0000 @@ -1,4 +1,4 @@ -/* +/* Copyright (c) 2008, 2009, 2010 , 2011 jerome DOT laurens AT u-bourgogne DOT fr This file is part of the SyncTeX package. @@ -32,9 +32,9 @@ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE -Except as contained in this notice, the name of the copyright holder -shall not be used in advertising or otherwise to promote the sale, -use or other dealings in this Software without prior written +Except as contained in this notice, the name of the copyright holder +shall not be used in advertising or otherwise to promote the sale, +use or other dealings in this Software without prior written authorization from the copyright holder. Acknowledgments: @@ -64,7 +64,7 @@ # else # define HAVE_LOCALE_H 1 # define HAVE_SETLOCALE 1 -# if defined(_MSC_VER) +# if defined(_MSC_VER) # define SYNCTEX_INLINE __inline # else # define SYNCTEX_INLINE inline @@ -568,9 +568,9 @@ || (NODE->class->type == synctex_node_type_void_vbox)\ || (NODE->class->type == synctex_node_type_hbox)\ || (NODE->class->type == synctex_node_type_void_hbox)) - + #define SYNCTEX_HAS_CHILDREN(NODE) (NODE && SYNCTEX_CHILD(NODE)) - + void _synctex_log_medium_node(synctex_node_t node); /* math node creator */ @@ -1357,7 +1357,7 @@ * value_ref = result; } return SYNCTEX_STATUS_OK;/* Successfully scanned an int */ - } + } return SYNCTEX_STATUS_NOT_OK;/* Could not scan an int */ } @@ -1916,7 +1916,7 @@ } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_BEGIN_SHEET) { ++SYNCTEX_CUR; goto deeper; - + } else if (_synctex_next_line(scanner)left = bestDistancesRef->right = 0; bestNodesRef->left = node; bestNodesRef->right = NULL; @@ -3990,19 +3990,19 @@ /* the left node is new, try to narrow the result */ if ((node = _synctex_eq_deepest_container(hitPoint,bestNodesRef->left,visible))) { bestNodesRef->left = node; - } + } if ((node = _synctex_eq_closest_child(hitPoint,bestNodesRef->left,visible))) { bestNodesRef->left = node; - } + } } if (result & SYNCTEX_MASK_RIGHT) { /* the right node is new, try to narrow the result */ if ((node = _synctex_eq_deepest_container(hitPoint,bestNodesRef->right,visible))) { bestNodesRef->right = node; - } + } if ((node = _synctex_eq_closest_child(hitPoint,bestNodesRef->right,visible))) { bestNodesRef->right = node; - } + } } } return result; @@ -4057,19 +4057,19 @@ /* the left node is new, try to narrow the result */ if ((node = _synctex_eq_deepest_container(hitPoint,bestNodesRef->left,visible))) { bestNodesRef->left = node; - } + } if ((node = _synctex_eq_closest_child(hitPoint,bestNodesRef->left,visible))) { bestNodesRef->left = node; - } + } } if (result & SYNCTEX_MASK_RIGHT) { /* the right node is new, try to narrow the result */ if ((node = _synctex_eq_deepest_container(hitPoint,bestNodesRef->right,visible))) { bestNodesRef->right = node; - } + } if ((node = _synctex_eq_closest_child(hitPoint,bestNodesRef->right,visible))) { bestNodesRef->right = node; - } + } } } return result; diff -Nru emacs-pdf-tools-0.70/server/synctex_parser.h emacs-pdf-tools-0.80/server/synctex_parser.h --- emacs-pdf-tools-0.70/server/synctex_parser.h 2016-06-05 12:32:19.000000000 +0000 +++ emacs-pdf-tools-0.80/server/synctex_parser.h 2017-09-10 03:47:50.000000000 +0000 @@ -1,4 +1,4 @@ -/* +/* Copyright (c) 2008, 2009, 2010 , 2011 jerome DOT laurens AT u-bourgogne DOT fr This file is part of the SyncTeX package. @@ -32,9 +32,9 @@ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE -Except as contained in this notice, the name of the copyright holder -shall not be used in advertising or otherwise to promote the sale, -use or other dealings in this Software without prior written +Except as contained in this notice, the name of the copyright holder +shall not be used in advertising or otherwise to promote the sale, +use or other dealings in this Software without prior written authorization from the copyright holder. Acknowledgments: diff -Nru emacs-pdf-tools-0.70/server/synctex_parser_local.h emacs-pdf-tools-0.80/server/synctex_parser_local.h --- emacs-pdf-tools-0.70/server/synctex_parser_local.h 2016-06-05 12:32:19.000000000 +0000 +++ emacs-pdf-tools-0.80/server/synctex_parser_local.h 2017-09-10 03:47:50.000000000 +0000 @@ -1,4 +1,4 @@ -/* +/* Copyright (c) 2008, 2009, 2010 , 2011 jerome DOT laurens AT u-bourgogne DOT fr This file is part of the SyncTeX package. @@ -32,9 +32,9 @@ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE -Except as contained in this notice, the name of the copyright holder -shall not be used in advertising or otherwise to promote the sale, -use or other dealings in this Software without prior written +Except as contained in this notice, the name of the copyright holder +shall not be used in advertising or otherwise to promote the sale, +use or other dealings in this Software without prior written authorization from the copyright holder. */ diff -Nru emacs-pdf-tools-0.70/server/synctex_parser_readme.txt emacs-pdf-tools-0.80/server/synctex_parser_readme.txt --- emacs-pdf-tools-0.70/server/synctex_parser_readme.txt 2016-06-05 12:32:19.000000000 +0000 +++ emacs-pdf-tools-0.80/server/synctex_parser_readme.txt 2017-09-10 03:47:50.000000000 +0000 @@ -99,7 +99,7 @@ - Various typo fixed - OutputDebugString replaced by OutputDebugStringA to deliberately disable unicode preprocessing - New conditional created because OutputDebugStringA is only available since Windows 2K professional -1.10: Sun Jan 10 10:12:32 UTC 2010 +1.10: Sun Jan 10 10:12:32 UTC 2010 - Bug fix in synctex_parser.c to solve a synchronization problem with amsmath's gather environment. Concerns the synctex tool. 1.11: Sun Jan 17 09:12:31 UTC 2010 @@ -138,4 +138,3 @@ I would appreciate to be listed as contributor and see "SyncTeX" highlighted. Copyright (c) 2008-2011 jerome DOT laurens AT u-bourgogne DOT fr - diff -Nru emacs-pdf-tools-0.70/server/synctex_parser_utils.c emacs-pdf-tools-0.80/server/synctex_parser_utils.c --- emacs-pdf-tools-0.70/server/synctex_parser_utils.c 2016-06-05 12:32:19.000000000 +0000 +++ emacs-pdf-tools-0.80/server/synctex_parser_utils.c 2017-09-10 03:47:50.000000000 +0000 @@ -1,4 +1,4 @@ -/* +/* Copyright (c) 2008, 2009, 2010 , 2011 jerome DOT laurens AT u-bourgogne DOT fr This file is part of the SyncTeX package. @@ -32,9 +32,9 @@ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE -Except as contained in this notice, the name of the copyright holder -shall not be used in advertising or otherwise to promote the sale, -use or other dealings in this Software without prior written +Except as contained in this notice, the name of the copyright holder +shall not be used in advertising or otherwise to promote the sale, +use or other dealings in this Software without prior written authorization from the copyright holder. */ @@ -302,7 +302,7 @@ _synctex_error("! _synctex_merge_strings: Memory problem"); return NULL; } - return NULL; + return NULL; } /* The purpose of _synctex_get_name is to find the name of the synctex file. @@ -473,7 +473,7 @@ } const char * _synctex_get_io_mode_name(synctex_io_mode_t io_mode) { - static const char * synctex_io_modes[4] = {"r","rb","a","ab"}; + static const char * synctex_io_modes[4] = {"r","rb","a","ab"}; unsigned index = ((io_mode & synctex_io_gz_mask)?1:0) + ((io_mode & synctex_io_append_mask)?2:0);// bug pointed out by Jose Alliste return synctex_io_modes[index]; } diff -Nru emacs-pdf-tools-0.70/server/synctex_parser_utils.h emacs-pdf-tools-0.80/server/synctex_parser_utils.h --- emacs-pdf-tools-0.70/server/synctex_parser_utils.h 2016-06-05 12:32:19.000000000 +0000 +++ emacs-pdf-tools-0.80/server/synctex_parser_utils.h 2017-09-10 03:47:50.000000000 +0000 @@ -1,4 +1,4 @@ -/* +/* Copyright (c) 2008, 2009, 2010, 2011 jerome DOT laurens AT u-bourgogne DOT fr This file is part of the SyncTeX package. @@ -32,9 +32,9 @@ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE -Except as contained in this notice, the name of the copyright holder -shall not be used in advertising or otherwise to promote the sale, -use or other dealings in this Software without prior written +Except as contained in this notice, the name of the copyright holder +shall not be used in advertising or otherwise to promote the sale, +use or other dealings in this Software without prior written authorization from the copyright holder. */ @@ -66,13 +66,13 @@ # else # define SYNCTEX_IS_PATH_SEPARATOR(c) ('/' == c) # endif - + # if _WIN32 # define SYNCTEX_IS_DOT(c) ('.' == c) # else # define SYNCTEX_IS_DOT(c) ('.' == c) # endif - + /* This custom malloc functions initializes to 0 the newly allocated memory. * There is no bzero function on windows. */ void *_synctex_malloc(size_t size); @@ -133,7 +133,7 @@ const char * _synctex_get_io_mode_name(synctex_io_mode_t io_mode); const char * synctex_ignore_leading_dot_slash(const char * name); - + #ifdef __cplusplus } #endif Binary files /tmp/tmpbKKGL4/B0xd0rIisv/emacs-pdf-tools-0.70/test/encrypted.pdf and /tmp/tmpbKKGL4/V22S3iZWPW/emacs-pdf-tools-0.80/test/encrypted.pdf differ diff -Nru emacs-pdf-tools-0.70/test/pdf-info.ert emacs-pdf-tools-0.80/test/pdf-info.ert --- emacs-pdf-tools-0.70/test/pdf-info.ert 2016-06-05 12:32:19.000000000 +0000 +++ emacs-pdf-tools-0.80/test/pdf-info.ert 2017-09-10 03:47:50.000000000 +0000 @@ -6,8 +6,11 @@ (ert-deftest pdf-info-open/close () (pdf-test-with-test-pdf - (should-not (pdf-info-open)) - (should (pdf-info-close)))) + (should-not (pdf-info-open)) + (should (pdf-info-close))) + (pdf-test-with-encrypted-pdf + (should-error (pdf-info-open nil "Invalid Password")) + (should-not (pdf-info-open nil "pdftool")))) (ert-deftest pdf-info-metadata () (pdf-test-with-test-pdf @@ -18,7 +21,7 @@ (ert-deftest pdf-info-search-string () (pdf-test-with-test-pdf - (let (matches) + (let (matches) (should (setq matches (pdf-info-search-string "PDF Tools"))) (should (= 2 (length matches))) (should (cl-every (lambda (m) @@ -27,11 +30,11 @@ (cl-every 'pdf-test-relative-edges-p .edges) (= 1 .page)))) matches))))) - + (ert-deftest pdf-info-search-regexp () (pdf-test-with-test-pdf - (let (case-fold-search matches) + (let (case-fold-search matches) (should (setq matches (pdf-info-search-regexp "PDF Tools"))) (should (= 2 (length matches))) (should (cl-every (lambda (m) @@ -174,7 +177,7 @@ (should (= nannots (length (pdf-info-getannots))))))) (ert-deftest pdf-info-mvannot () - (skip-unless (pdf-info-writable-annotations-p)) + (skip-unless (pdf-info-writable-annotations-p)) (pdf-test-with-test-pdf (let ((edges '(0.25 0.25 1.0 1.0)) (id (cdr (assq 'id (car (pdf-info-getannots)))))) @@ -253,4 +256,3 @@ ;; (ert-deftest pdf-info-boundingbox () ;; (pdf-test-with-test-pdf ;; )) - diff -Nru emacs-pdf-tools-0.70/test/pdf-util.ert emacs-pdf-tools-0.80/test/pdf-util.ert --- emacs-pdf-tools-0.70/test/pdf-util.ert 2016-06-05 12:32:19.000000000 +0000 +++ emacs-pdf-tools-0.80/test/pdf-util.ert 2017-09-10 03:47:50.000000000 +0000 @@ -27,7 +27,7 @@ (should (equal '(1 . ((nil . ?a) (?b . ?b) (nil . ?c))) (pdf-util-seq-alignment s6 s1 nil 'infix))) - + (should (equal '(-3 . ((?a . ?e) (?b . ?f) (?c . ?g))) (pdf-util-seq-alignment s1 s4 nil))) @@ -41,4 +41,3 @@ (downcase b)) 1 -1))))))) - diff -Nru emacs-pdf-tools-0.70/test/pdf-virtual.ert emacs-pdf-tools-0.80/test/pdf-virtual.ert --- emacs-pdf-tools-0.70/test/pdf-virtual.ert 2016-06-05 12:32:19.000000000 +0000 +++ emacs-pdf-tools-0.80/test/pdf-virtual.ert 2017-09-10 03:47:50.000000000 +0000 @@ -120,7 +120,7 @@ (ert-deftest pdf-virtual-gettext () (with-pdf-virtual-test-buffer (let ((text (pdf-info-gettext 2 '(0 0 1 1)))) - (should + (should (= 2 (with-temp-buffer (insert text) (count-matches "PDF" 1 (point)))))))) diff -Nru emacs-pdf-tools-0.70/test/run-tests.el emacs-pdf-tools-0.80/test/run-tests.el --- emacs-pdf-tools-0.70/test/run-tests.el 2016-06-05 12:32:19.000000000 +0000 +++ emacs-pdf-tools-0.80/test/run-tests.el 2017-09-10 03:47:50.000000000 +0000 @@ -1,6 +1,7 @@ (require 'package) (require 'ert) +(require 'cl-lib) (unless (= 1 (length command-line-args-left)) (error "Missing package tar or too many arguments")) @@ -17,12 +18,18 @@ (cd (file-name-directory load-file-name)) (setq package-user-dir (expand-file-name "elpa" (make-temp-file "package" t))) -(defvar cask-elpa (format "../.cask/%s/elpa" emacs-version)) +(defvar cask-elpa + (cl-labels ((directory-if-exists-p (directory) + (and (file-directory-p directory) + directory))) + (or (directory-if-exists-p + (format "../.cask/%s/elpa" emacs-version)) + (directory-if-exists-p + (format "../.cask/%d.%d/elpa" + emacs-major-version emacs-minor-version)) + (error "Do `cask install' first")))) -(unless (file-directory-p cask-elpa) - (error "Do `cask install' first")) -(add-to-list 'package-directory-list - (format "../.cask/%s/elpa" emacs-version)) +(add-to-list 'package-directory-list cask-elpa) (add-hook 'kill-emacs-hook (lambda nil (when (file-exists-p package-user-dir) (delete-directory package-user-dir t)))) @@ -47,22 +54,36 @@ (>= x 0))) edges))) -(defmacro pdf-test-with-test-pdf (&rest body) +(defmacro pdf-test-with-pdf (pdf-filename &rest body) (declare (indent 0) (debug t)) (let ((buffer (make-symbol "buffer"))) `(let ((,buffer (find-file-noselect - (expand-file-name "test.pdf")))) - (pdf-info-quit) - (pdf-info-process-assert-running t) + (expand-file-name ,pdf-filename))) + (pdf-info-epdfinfo-error-filename (make-temp-file "epdfinfo.log"))) (unwind-protect - (with-current-buffer ,buffer ,@body) + (progn + (pdf-info-quit) + (pdf-info-process-assert-running t) + (with-current-buffer ,buffer ,@body)) (when (buffer-live-p ,buffer) - (set-buffer-modified-p nil) - (kill-buffer)) + (with-current-buffer ,buffer + (set-buffer-modified-p nil) + (let (kill-buffer-hook) + (kill-buffer)))) + (when (file-exists-p pdf-info-epdfinfo-error-filename) + (with-temp-buffer + (insert-file-contents pdf-info-epdfinfo-error-filename) + (unless (= 1 (point-max)) + (message ">>> %s <<<" (buffer-string)))) + (delete-file pdf-info-epdfinfo-error-filename)) (pdf-info-quit))))) +(defmacro pdf-test-with-test-pdf (&rest body) + `(pdf-test-with-pdf "test.pdf" ,@body)) + +(defmacro pdf-test-with-encrypted-pdf (&rest body) + `(pdf-test-with-pdf "encrypted.pdf" ,@body)) + (dolist (file (directory-files "." t "\\.ert\\'")) (load-file file)) - (ert-run-tests-batch-and-exit t) - diff -Nru emacs-pdf-tools-0.70/TODO emacs-pdf-tools-0.80/TODO --- emacs-pdf-tools-0.70/TODO 2016-06-05 12:32:19.000000000 +0000 +++ emacs-pdf-tools-0.80/TODO 2017-09-10 03:47:50.000000000 +0000 @@ -15,7 +15,7 @@ * epdfinfo ** Maybe split the code up in several files. * pdf-view -** Provide some kind of multi-page view +** Provide some kind of multi-page view ** Make persistent scrolling relative Currently the scrolling is kept when changing the image's size (in pdf-view-display-image), which is actually not so desirable, since diff -Nru emacs-pdf-tools-0.70/.travis.yml emacs-pdf-tools-0.80/.travis.yml --- emacs-pdf-tools-0.70/.travis.yml 2016-06-05 12:32:19.000000000 +0000 +++ emacs-pdf-tools-0.80/.travis.yml 2017-09-10 03:47:50.000000000 +0000 @@ -1,9 +1,13 @@ language: cpp env: - matrix: - - EMACS=emacs24 - - EMACS=emacs-snapshot + - EMACS=emacs24 + - EMACS=emacs-snapshot + +matrix: + fast_finish: true + allow_failures: + - env: EMACS=emacs-snapshot compiler: - gcc @@ -20,7 +24,7 @@ sudo apt-get install -qq emacs-snapshot; fi - sudo apt-get install -qq make automake autoconf libpng-dev libz-dev - - sudo apt-get install libcairo2-dev libglib2.0-dev + - sudo apt-get install libcairo2-dev libglib2.0-dev - POPPLER=poppler-0.28.1 - wget http://poppler.freedesktop.org/$POPPLER.tar.xz - unxz $POPPLER.tar.xz