summaryrefslogtreecommitdiff
path: root/elpa/pdf-tools-20200512.1524/pdf-tools.el
diff options
context:
space:
mode:
Diffstat (limited to 'elpa/pdf-tools-20200512.1524/pdf-tools.el')
-rw-r--r--elpa/pdf-tools-20200512.1524/pdf-tools.el525
1 files changed, 525 insertions, 0 deletions
diff --git a/elpa/pdf-tools-20200512.1524/pdf-tools.el b/elpa/pdf-tools-20200512.1524/pdf-tools.el
new file mode 100644
index 0000000..7c9144c
--- /dev/null
+++ b/elpa/pdf-tools-20200512.1524/pdf-tools.el
@@ -0,0 +1,525 @@
+;;; pdf-tools.el --- Support library for PDF documents. -*- lexical-binding:t -*-
+
+;; Copyright (C) 2013, 2014 Andreas Politz
+
+;; Author: Andreas Politz <politza@fh-trier.de>
+;; Keywords: files, multimedia
+;; Package: pdf-tools
+;; Version: 1.0
+;; Package-Requires: ((emacs "24.3") (tablist "1.0") (let-alist "1.0.4"))
+
+;; 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 <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+;;
+;; PDF Tools is, among other things, a replacement of DocView for PDF
+;; files. The key difference is, that pages are not prerendered by
+;; e.g. ghostscript and stored in the file-system, but rather created
+;; on-demand and stored in memory.
+;;
+;; 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
+;;
+;; (pdf-tools-install)
+;;
+;; somewhere in your .emacs.el .
+;;
+;; M-x pdf-tools-help RET
+;;
+;; gives some help on using the package and
+;;
+;; M-x pdf-tools-customize RET
+;;
+;; offers some customization options.
+
+;; Features:
+;;
+;; * View
+;; View PDF documents in a buffer with DocView-like bindings.
+;;
+;; * 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.
+;; + Search for occurrences of a string.
+;; + Keep track of visited pages via a history.
+
+;;; Code:
+
+(require 'pdf-view)
+(require 'pdf-util)
+(require 'pdf-info)
+(require 'cus-edit)
+(require 'compile)
+(require 'cl-lib)
+(require 'package)
+
+
+
+;; * ================================================================== *
+;; * Customizables
+;; * ================================================================== *
+
+(defgroup pdf-tools nil
+ "Support library for PDF documents."
+ :group 'data)
+
+(defgroup pdf-tools-faces nil
+ "Faces determining the colors used in the pdf-tools package.
+
+In order to customize dark and light colors use
+`pdf-tools-customize-faces', or set `custom-face-default-form' to
+'all."
+ :group 'pdf-tools)
+
+(defconst pdf-tools-modes
+ '(pdf-history-minor-mode
+ pdf-isearch-minor-mode
+ pdf-links-minor-mode
+ pdf-misc-minor-mode
+ pdf-outline-minor-mode
+ pdf-misc-size-indication-minor-mode
+ pdf-misc-menu-bar-minor-mode
+ pdf-annot-minor-mode
+ pdf-sync-minor-mode
+ pdf-misc-context-menu-minor-mode
+ pdf-cache-prefetch-minor-mode
+ 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
+ pdf-links-minor-mode
+ pdf-misc-minor-mode
+ pdf-outline-minor-mode
+ pdf-misc-size-indication-minor-mode
+ pdf-misc-menu-bar-minor-mode
+ pdf-annot-minor-mode
+ pdf-sync-minor-mode
+ pdf-misc-context-menu-minor-mode
+ pdf-cache-prefetch-minor-mode
+ pdf-occur-global-minor-mode
+ ;; pdf-virtual-global-minor-mode
+ )
+ "A list of automatically enabled minor-modes.
+
+PDF Tools is build as a series of minor-modes. This variable and
+the function `pdf-tools-install' merely serve as a convenient
+wrapper in order to load these modes in current and newly created
+PDF buffers."
+ :group 'pdf-tools
+ :type `(set ,@(mapcar (lambda (mode)
+ `(function-item ,mode))
+ pdf-tools-modes)))
+
+(defcustom pdf-tools-enabled-hook nil
+ "A hook ran after PDF Tools is enabled in a buffer."
+ :group 'pdf-tools
+ :type 'hook)
+
+(defconst pdf-tools-auto-mode-alist-entry
+ '("\\.[pP][dD][fF]\\'" . pdf-view-mode)
+ "The entry to use for `auto-mode-alist'.")
+
+(defconst pdf-tools-magic-mode-alist-entry
+ '("%PDF" . pdf-view-mode)
+ "The entry to use for `magic-mode-alist'.")
+
+(defun pdf-tools-customize ()
+ "Customize Pdf Tools."
+ (interactive)
+ (customize-group 'pdf-tools))
+
+(defun pdf-tools-customize-faces ()
+ "Customize PDF Tool's faces."
+ (interactive)
+ (let ((buffer (format "*Customize Group: %s*"
+ (custom-unlispify-tag-name 'pdf-tools-faces))))
+ (when (buffer-live-p (get-buffer buffer))
+ (with-current-buffer (get-buffer buffer)
+ (rename-uniquely)))
+ (customize-group 'pdf-tools-faces)
+ (with-current-buffer buffer
+ (set (make-local-variable 'custom-face-default-form) 'all))))
+
+
+;; * ================================================================== *
+;; * Installation
+;; * ================================================================== *
+
+;;;###autoload
+(defcustom pdf-tools-handle-upgrades t
+ "Whether PDF Tools should handle upgrading itself."
+ :group 'pdf-tools
+ :type 'boolean)
+
+(make-obsolete-variable 'pdf-tools-handle-upgrades
+ "Not used anymore" "0.90")
+
+(defconst pdf-tools-directory
+ (or (and load-file-name
+ (file-name-directory load-file-name))
+ default-directory)
+ "The directory from where this library was first loaded.")
+
+(defvar pdf-tools-msys2-directory nil)
+
+(defcustom pdf-tools-installer-os nil
+ "Specifies which installer to use.
+
+If nil the installer is chosen automatically. This variable is
+useful if you have multiple installers present on your
+system (e.g. nix on arch linux)"
+ :group 'pdf-tools
+ :type 'string)
+
+(defun pdf-tools-identify-build-directory (directory)
+ "Return non-nil, if DIRECTORY appears to contain the epdfinfo source.
+
+Returns the expanded directory-name of DIRECTORY or nil."
+ (setq directory (file-name-as-directory
+ (expand-file-name directory)))
+ (and (file-exists-p (expand-file-name "autobuild" directory))
+ (file-exists-p (expand-file-name "epdfinfo.c" directory))
+ directory))
+
+(defun pdf-tools-locate-build-directory ()
+ "Attempt to locate a source directory.
+
+Returns a appropriate directory or nil. See also
+`pdf-tools-identify-build-directory'."
+ (cl-some #'pdf-tools-identify-build-directory
+ (list default-directory
+ (expand-file-name "build/server" pdf-tools-directory)
+ (expand-file-name "server")
+ (expand-file-name "../server" pdf-tools-directory))))
+
+(defun pdf-tools-msys2-directory (&optional noninteractive-p)
+ "Locate the Msys2 installation directory.
+
+Ask the user if necessary and NONINTERACTIVE-P is nil.
+Returns always nil, unless `system-type' equals windows-nt."
+ (cl-labels ((if-msys2-directory (directory)
+ (and (stringp directory)
+ (file-directory-p directory)
+ (file-exists-p
+ (expand-file-name "usr/bin/bash.exe" directory))
+ directory)))
+ (when (eq system-type 'windows-nt)
+ (setq pdf-tools-msys2-directory
+ (or pdf-tools-msys2-directory
+ (cl-some #'if-msys2-directory
+ (cl-mapcan
+ (lambda (drive)
+ (list (format "%c:/msys64" drive)
+ (format "%c:/msys32" drive)))
+ (number-sequence ?c ?z)))
+ (unless (or noninteractive-p
+ (not (y-or-n-p "Do you have Msys2 installed ? ")))
+ (if-msys2-directory
+ (read-directory-name
+ "Please enter Msys2 installation directory: " nil nil t))))))))
+
+(defun pdf-tools-msys2-mingw-bin ()
+ "Return the location of /mingw*/bin."
+ (when (pdf-tools-msys2-directory)
+ (let ((arch (intern (car (split-string system-configuration "-" t)))))
+ (expand-file-name
+ (format "./mingw%s/bin" (if (eq arch 'x86_64) "64" "32"))
+ (pdf-tools-msys2-directory)))))
+
+(defun pdf-tools-find-bourne-shell ()
+ "Locate a usable sh."
+ (or (and (eq system-type 'windows-nt)
+ (let* ((directory (pdf-tools-msys2-directory)))
+ (when directory
+ (expand-file-name "usr/bin/bash.exe" directory))))
+ (executable-find "sh")))
+
+(defun pdf-tools-build-server (target-directory
+ &optional
+ skip-dependencies-p
+ force-dependencies-p
+ callback
+ build-directory)
+ "Build the epdfinfo program in the background.
+
+Install into TARGET-DIRECTORY, which should be a directory.
+
+If CALLBACK is non-nil, it should be a function. It is called
+with the compiled executable as the single argument or nil, if
+the build failed.
+
+Expect sources to be in BUILD-DIRECTORY. If nil, search for it
+using `pdf-tools-locate-build-directory'.
+
+See `pdf-tools-install' for the SKIP-DEPENDENCIES-P and
+FORCE-DEPENDENCIES-P arguments.
+
+Returns the buffer of the compilation process."
+
+ (unless callback (setq callback #'ignore))
+ (unless build-directory
+ (setq build-directory (pdf-tools-locate-build-directory)))
+ (cl-check-type target-directory file-directory)
+ (setq target-directory (file-name-as-directory
+ (expand-file-name target-directory)))
+ (cl-check-type build-directory (and (not null) file-directory))
+ (when (and skip-dependencies-p force-dependencies-p)
+ (error "Can't simultaneously skip and force dependencies"))
+ (let* ((compilation-auto-jump-to-first-error nil)
+ (compilation-scroll-output t)
+ (shell-file-name (pdf-tools-find-bourne-shell))
+ (shell-command-switch "-c")
+ (process-environment process-environment)
+ (default-directory build-directory)
+ (autobuild (shell-quote-argument
+ (expand-file-name "autobuild" build-directory)))
+ (msys2-p (equal "bash.exe" (file-name-nondirectory shell-file-name))))
+ (unless shell-file-name
+ (error "No suitable shell found"))
+ (when msys2-p
+ (push "BASH_ENV=/etc/profile" process-environment))
+ (let ((executable
+ (expand-file-name
+ (concat "epdfinfo" (and (eq system-type 'windows-nt) ".exe"))
+ target-directory))
+ (compilation-buffer
+ (compilation-start
+ (format "%s -i %s%s%s"
+ autobuild
+ (shell-quote-argument target-directory)
+ (cond
+ (skip-dependencies-p " -D")
+ (force-dependencies-p " -d")
+ (t ""))
+ (if pdf-tools-installer-os (concat " --os " pdf-tools-installer-os) ""))
+ t)))
+ ;; In most cases user-input is required, so select the window.
+ (if (get-buffer-window compilation-buffer)
+ (select-window (get-buffer-window compilation-buffer))
+ (pop-to-buffer compilation-buffer))
+ (with-current-buffer compilation-buffer
+ (setq-local compilation-error-regexp-alist nil)
+ (add-hook 'compilation-finish-functions
+ (lambda (_buffer status)
+ (funcall callback
+ (and (equal status "finished\n")
+ executable)))
+ nil t)
+ (current-buffer)))))
+
+
+;; * ================================================================== *
+;; * Initialization
+;; * ================================================================== *
+
+;;;###autoload
+(defun pdf-tools-install (&optional no-query-p skip-dependencies-p
+ no-error-p force-dependencies-p)
+ "Install PDF-Tools in all current and future PDF buffers.
+
+If the `pdf-info-epdfinfo-program' is not running or does not
+appear to be working, attempt to rebuild it. If this build
+succeeded, continue with the activation of the package.
+Otherwise fail silently, i.e. no error is signaled.
+
+Build the program (if necessary) without asking first, if
+NO-QUERY-P is non-nil.
+
+Don't attempt to install system packages, if SKIP-DEPENDENCIES-P
+is non-nil.
+
+Do not signal an error in case the build failed, if NO-ERROR-P is
+non-nil.
+
+Attempt to install system packages (even if it is deemed
+unnecessary), if FORCE-DEPENDENCIES-P is non-nil.
+
+Note that SKIP-DEPENDENCIES-P and FORCE-DEPENDENCIES-P are
+mutually exclusive.
+
+Note further, that you can influence the installation directory
+by setting `pdf-info-epdfinfo-program' to an appropriate
+value (e.g. ~/bin/epdfinfo) before calling this function.
+
+See `pdf-view-mode' and `pdf-tools-enabled-modes'."
+ (interactive)
+ (if (or (pdf-info-running-p)
+ (ignore-errors (pdf-info-check-epdfinfo) t))
+ (pdf-tools-install-noverify)
+ (let ((target-directory
+ (or (and (stringp pdf-info-epdfinfo-program)
+ (file-name-directory
+ pdf-info-epdfinfo-program))
+ pdf-tools-directory)))
+ (if (or no-query-p
+ (y-or-n-p "Need to (re)build the epdfinfo program, do it now ?"))
+ (pdf-tools-build-server
+ target-directory
+ skip-dependencies-p
+ force-dependencies-p
+ (lambda (executable)
+ (let ((msg (format
+ "Building the PDF Tools server %s"
+ (if executable "succeeded" "failed"))))
+ (if (not executable)
+ (funcall (if no-error-p #'message #'error) "%s" msg)
+ (message "%s" msg)
+ (setq pdf-info-epdfinfo-program executable)
+ (let ((pdf-info-restart-process-p t))
+ (pdf-tools-install-noverify))))))
+ (message "PDF Tools not activated")))))
+
+(defun pdf-tools-install-noverify ()
+ "Like `pdf-tools-install', but skip checking `pdf-info-epdfinfo-program'."
+ (add-to-list 'auto-mode-alist pdf-tools-auto-mode-alist-entry)
+ (add-to-list 'magic-mode-alist pdf-tools-magic-mode-alist-entry)
+ ;; FIXME: Generalize this sometime.
+ (when (memq 'pdf-occur-global-minor-mode
+ pdf-tools-enabled-modes)
+ (pdf-occur-global-minor-mode 1))
+ (when (memq 'pdf-virtual-global-minor-mode
+ pdf-tools-enabled-modes)
+ (pdf-virtual-global-minor-mode 1))
+ (add-hook 'pdf-view-mode-hook 'pdf-tools-enable-minor-modes)
+ (dolist (buf (buffer-list))
+ (with-current-buffer buf
+ (when (and (not (derived-mode-p 'pdf-view-mode))
+ (pdf-tools-pdf-buffer-p)
+ (buffer-file-name))
+ (pdf-view-mode)))))
+
+(defun pdf-tools-uninstall ()
+ "Uninstall PDF-Tools in all current and future PDF buffers."
+ (interactive)
+ (pdf-info-quit)
+ (setq-default auto-mode-alist
+ (remove pdf-tools-auto-mode-alist-entry auto-mode-alist))
+ (setq-default magic-mode-alist
+ (remove pdf-tools-magic-mode-alist-entry magic-mode-alist))
+ (pdf-occur-global-minor-mode -1)
+ (pdf-virtual-global-minor-mode -1)
+ (remove-hook 'pdf-view-mode-hook 'pdf-tools-enable-minor-modes)
+ (dolist (buf (buffer-list))
+ (with-current-buffer buf
+ (when (pdf-util-pdf-buffer-p buf)
+ (pdf-tools-disable-minor-modes pdf-tools-modes)
+ (normal-mode)))))
+
+(defun pdf-tools-pdf-buffer-p (&optional buffer)
+ "Return non-nil if BUFFER contains a PDF document."
+ (save-current-buffer
+ (when buffer (set-buffer buffer))
+ (save-excursion
+ (save-restriction
+ (widen)
+ (goto-char 1)
+ (looking-at "%PDF")))))
+
+(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)
+ (symbol-value m))))
+ (unless (or (and enabled-p enable)
+ (and (not enabled-p) (not enable)))
+ (funcall m (if enable 1 -1))))))
+
+;;;###autoload
+(defun pdf-tools-enable-minor-modes (&optional modes)
+ "Enable MODES in the current buffer.
+
+MODES defaults to `pdf-tools-enabled-modes'."
+ (interactive)
+ (pdf-util-assert-pdf-buffer)
+ (pdf-tools-set-modes-enabled t modes)
+ (run-hooks 'pdf-tools-enabled-hook))
+
+(defun pdf-tools-disable-minor-modes (&optional modes)
+ "Disable MODES in the current buffer.
+
+MODES defaults to `pdf-tools-enabled-modes'."
+ (interactive)
+ (pdf-tools-set-modes-enabled nil modes))
+
+(declare-function pdf-occur-global-minor-mode "pdf-occur.el")
+(declare-function pdf-virtual-global-minor-mode "pdf-virtual.el")
+
+;;;###autoload
+(defun pdf-tools-help ()
+ (interactive)
+ (help-setup-xref (list #'pdf-tools-help)
+ (called-interactively-p 'interactive))
+ (with-help-window (help-buffer)
+ (princ "PDF Tools Help\n\n")
+ (princ " ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n")
+ (dolist (m (cons 'pdf-view-mode
+ (sort (copy-sequence pdf-tools-modes) 'string<)))
+ (princ (format "`%s' is " m))
+ (describe-function-1 m)
+ (terpri) (terpri)
+ (princ " ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n"))))
+
+
+;; * ================================================================== *
+;; * Debugging
+;; * ================================================================== *
+
+(defvar pdf-tools-debug nil
+ "Non-nil, if debugging PDF Tools.")
+
+(defun pdf-tools-toggle-debug ()
+ (interactive)
+ (setq pdf-tools-debug (not pdf-tools-debug))
+ (when (called-interactively-p 'any)
+ (message "Toggled debugging %s" (if pdf-tools-debug "on" "off"))))
+
+(provide 'pdf-tools)
+
+;;; pdf-tools.el ends here
Copyright 2019--2024 Marius PETER