Update packages/ Add org-ref
This commit is contained in:
371
elpa/pdf-tools-20180428.827/README
Normal file
371
elpa/pdf-tools-20180428.827/README
Normal file
@@ -0,0 +1,371 @@
|
||||
#+TITLE: PDF Tools README
|
||||
#+AUTHOR: Andreas Politz
|
||||
#+EMAIL: politza@fh-trier.de
|
||||
|
||||
[[https://travis-ci.org/politza/pdf-tools.svg?branch%3Dmaster][https://travis-ci.org/politza/pdf-tools.svg?branch=master]]
|
||||
[[http://stable.melpa.org/#/pdf-tools][http://stable.melpa.org/packages/pdf-tools-badge.svg]]
|
||||
[[http://melpa.org/#/pdf-tools][http://melpa.org/packages/pdf-tools-badge.svg]]
|
||||
|
||||
|
||||
|
||||
** About this package
|
||||
PDF Tools is, among other things, a replacement of DocView for PDF
|
||||
files. The key difference is that pages are not pre-rendered by
|
||||
e.g. ghostscript and stored in the file-system, but rather created
|
||||
on-demand and stored in memory.
|
||||
|
||||
This rendering is performed by a special library named, for
|
||||
whatever reason, poppler, running inside a server program. This
|
||||
program is called ~epdfinfo~ and its job is to successively
|
||||
read requests from Emacs and produce the proper results, i.e. the
|
||||
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 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 ::
|
||||
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 ::
|
||||
Use a collection of documents as if it were 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.
|
||||
|
||||
** 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 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][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~.
|
||||
|
||||
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 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~. 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
|
||||
PDF Tools depend on a more recent version of this library. See
|
||||
the following table for what they are and what version they
|
||||
require.
|
||||
|
||||
| You want to ... | Required version |
|
||||
|-------------------------------------------+------------------|
|
||||
| ... create and modify text annotations. | \ge 0.19.4 |
|
||||
| ... search case-sensitive. | \ge 0.22 |
|
||||
| ... create and modify markup annotations. | \ge 0.26 |
|
||||
|-------------------------------------------+------------------|
|
||||
|
||||
In case you decide to install libpoppler from source, make sure
|
||||
to run its configure script with the ~--enable-xpdf-headers~
|
||||
option.
|
||||
|
||||
Finally there is one feature (following links of a PDF document by
|
||||
plain keystrokes) which requires imagemagick's convert utility.
|
||||
This requirement is optional and you may install it like so:
|
||||
#+begin_src sh
|
||||
$ sudo aptitude install imagemagick
|
||||
#+end_src
|
||||
**** Compiling on OS X
|
||||
Although OS X is not officially supported, it has been reported
|
||||
to have been successfully compiled. You will need to install
|
||||
poppler which you can get with homebrew via
|
||||
#+BEGIN_SRC sh
|
||||
$ brew install poppler automake
|
||||
#+END_SRC
|
||||
|
||||
You will also have to help ~pkg-config~ find some libraries by
|
||||
setting ~PKG_CONFIG_PATH~, e.g.
|
||||
#+BEGIN_SRC sh
|
||||
$ 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.
|
||||
**** FreeBSD
|
||||
Although not officially supported, it has been reported that
|
||||
pdf-tools work well on FreeBSD. Instead of building pdf-tools, you
|
||||
can install one of the OS packages with, e.g.
|
||||
#+BEGIN_SRC sh
|
||||
$ pkg install pdf-tools-emacs25
|
||||
#+END_SRC
|
||||
To see the current list of pdf-tools packages for FreeBSD visit
|
||||
[[https://repology.org/metapackages/?search=pdf-tools&inrepo=freebsd][the Repology list]].
|
||||
|
||||
To build pdf-tools from either melpa or directly from the source
|
||||
repository, 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][Compilation and installation on Windows]], below.
|
||||
PDF Tools will successfully compile using Cygwin, but it will not be
|
||||
able to open PDFs properly due to the way binaries compiled with Cygwin
|
||||
handle file paths.
|
||||
|
||||
*** Compilation
|
||||
: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
|
||||
$ make -s
|
||||
#+end_src
|
||||
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 (*Note:* You must use mingw64.exe and not msys2.exe)
|
||||
|
||||
5. Compile pdf-tools
|
||||
#+BEGIN_SRC sh
|
||||
$ cd /path/to/pdf-tools
|
||||
$ 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
|
||||
fine. This package contains all the necessary files for Emacs
|
||||
and may be installed by either using
|
||||
#+begin_src sh
|
||||
$ make install-package
|
||||
#+end_src
|
||||
or executing the Emacs command
|
||||
#+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
|
||||
(pdf-tools-install)
|
||||
#+end_src
|
||||
somewhere in your ~.emacs~. Next you probably want to take a look at
|
||||
the various features of what you've just installed. The following
|
||||
two commands might be of help for doing so.
|
||||
#+begin_src elisp
|
||||
M-x pdf-tools-help RET
|
||||
M-x pdf-tools-customize RET
|
||||
#+end_src
|
||||
|
||||
*** Updating
|
||||
Some day you might want to update this package via ~git pull~ and
|
||||
then reinstall it. Sometimes this may fail, especially if
|
||||
Lisp-Macros are involved and the version hasn't changed. To avoid
|
||||
this kind of problems, you should delete the old package via
|
||||
~list-packages~, restart Emacs and then reinstall the package.
|
||||
|
||||
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 | |
|
||||
|--------------------------------------------+-----------------------|
|
||||
| Scroll Up / Down by page-full | ~space~ / ~backspace~ |
|
||||
| Scroll Up / Down by line | ~C-n~ / ~C-b~ |
|
||||
| Scroll Right / Left | ~C-f~ / ~C-b~ |
|
||||
| Top of Page / Bottom of Page | ~<~ / ~>~ |
|
||||
| Next Page / Previous Page | ~n~ / ~p~ |
|
||||
| First Page / Last Page | ~M-<~ / ~M->~ |
|
||||
| Incremental Search Forward / Backward | ~C-s~ / ~C-r~ |
|
||||
| Occur (list all lines containing a phrase) | ~M-s o~ |
|
||||
| Jump to Occur Line | ~RETURN~ |
|
||||
| Pick a Link and Jump | ~F~ |
|
||||
| Incremental Search in Links | ~f~ |
|
||||
| History Back / Forwards | ~B~ / ~F~ |
|
||||
| Display Outline | ~o~ |
|
||||
| Jump to Section from Outline | ~RETURN~ |
|
||||
| Jump to Page | ~M-g g~ |
|
||||
|
||||
| Display | |
|
||||
|------------------------------------------+-----------------|
|
||||
| Zoom in / Zoom out | ~+~ / ~-~ |
|
||||
| Fit Height / Fit Width / Fit Page | ~H~ / ~W~ / ~P~ |
|
||||
| Trim margins (set slice to bounding box) | ~s b~ |
|
||||
| Reset margins | ~s r~ |
|
||||
| Reset Zoom | 0 |
|
||||
|
||||
| Annotations | |
|
||||
|-------------------------------+-------------------------------------------------|
|
||||
| List Annotations | ~C-c C-a l~ |
|
||||
| Jump to Annotations from List | ~SPACE~ |
|
||||
| Mark Annotation for Deletion | ~d~ |
|
||||
| Delete Marked Annotations | ~x~ |
|
||||
| Unmark Annotations | ~u~ |
|
||||
| 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 | ~C-mouse-1~ |
|
||||
|
||||
| Miscellaneous | |
|
||||
|-----------------------------------------------+-----------|
|
||||
| Refresh File (e.g., after recompiling source) | ~g~ |
|
||||
| Print File | ~C-c C-p~ |
|
||||
|
||||
# Local Variables:
|
||||
# mode: org
|
||||
# End:
|
||||
96
elpa/pdf-tools-20180428.827/build/Makefile
Normal file
96
elpa/pdf-tools-20180428.827/build/Makefile
Normal file
@@ -0,0 +1,96 @@
|
||||
|
||||
EMACS ?= emacs
|
||||
# Handle the mess when inside Emacs.
|
||||
unexport INSIDE_EMACS #cask not like this.
|
||||
ifeq ($(EMACS), t)
|
||||
EMACS = emacs
|
||||
endif
|
||||
|
||||
emacs = $(EMACS)
|
||||
emacs_version = $(shell $(emacs) --batch --eval \
|
||||
'(princ (format "%s.%s" emacs-major-version emacs-minor-version))')
|
||||
$(info Using Emacs $(emacs_version))
|
||||
|
||||
version=$(shell sed -ne 's/^;\+ *Version: *\([0-9.]\)/\1/p' lisp/pdf-tools.el)
|
||||
pkgname=pdf-tools-$(version)
|
||||
pkgfile=$(pkgname).tar
|
||||
|
||||
.PHONY: all clean distclean bytecompile test check melpa cask-install
|
||||
|
||||
all: $(pkgfile)
|
||||
|
||||
# Create a elpa package including the server
|
||||
$(pkgfile): .cask/$(emacs_version) server/epdfinfo lisp/*.el
|
||||
cask package .
|
||||
|
||||
# Compile the Lisp sources
|
||||
bytecompile: .cask/$(emacs_version)
|
||||
cask exec $(emacs) --batch -L lisp -f batch-byte-compile lisp/*.el
|
||||
|
||||
# Run ERT tests
|
||||
test: all
|
||||
PACKAGE_TAR=$(pkgfile) cask exec ert-runner
|
||||
|
||||
check: test
|
||||
|
||||
# Run the autobuild script tests in docker
|
||||
test-autobuild: server-test
|
||||
|
||||
# Run all tests
|
||||
test-all: test test-autobuild
|
||||
|
||||
# Init cask
|
||||
.cask/$(emacs_version):
|
||||
cask install
|
||||
|
||||
# Run the autobuild script (installing depends and compiling)
|
||||
autobuild:
|
||||
cd server && ./autobuild
|
||||
|
||||
# Soon to be obsolete targets
|
||||
melpa-build: autobuild
|
||||
cp build/epdfinfo .
|
||||
install-server-deps: ;
|
||||
|
||||
# Create a package like melpa would.
|
||||
melpa-package: $(pkgfile)
|
||||
cp $(pkgfile) $(pkgname)-melpa.tar
|
||||
tar -u --transform='s/server/$(pkgname)\/build\/server/' \
|
||||
-f $(pkgname)-melpa.tar \
|
||||
$$(git ls-files server)
|
||||
tar -u --transform='s/Makefile/$(pkgname)\/build\/Makefile/' \
|
||||
-f $(pkgname)-melpa.tar \
|
||||
Makefile
|
||||
tar -u --transform='s/README\.org/$(pkgname)\/README/' \
|
||||
-f $(pkgname)-melpa.tar \
|
||||
README.org
|
||||
-tar --delete $(pkgname)/epdfinfo \
|
||||
-f $(pkgname)-melpa.tar
|
||||
|
||||
# Various clean targets
|
||||
clean: server-clean
|
||||
rm -f -- $(pkgfile)
|
||||
rm -f -- lisp/*.elc
|
||||
rm -f -- pdf-tools-readme.txt
|
||||
|
||||
distclean: clean server-distclean
|
||||
rm -rf -- .cask
|
||||
|
||||
# Server targets
|
||||
server/epdfinfo: server/Makefile server/*.[ch]
|
||||
$(MAKE) -C server
|
||||
|
||||
server/Makefile: server/configure
|
||||
cd server && ./configure -q
|
||||
|
||||
server/configure: server/configure.ac
|
||||
cd server && ./autogen.sh
|
||||
|
||||
server-test: server/Makefile
|
||||
$(MAKE) -C server check
|
||||
|
||||
server-clean:
|
||||
! [ -f server/Makefile ] || $(MAKE) -C server clean
|
||||
|
||||
server-distclean:
|
||||
! [ -f server/Makefile ] || $(MAKE) -C server distclean
|
||||
25
elpa/pdf-tools-20180428.827/build/server/.gitignore
vendored
Normal file
25
elpa/pdf-tools-20180428.827/build/server/.gitignore
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
*.o
|
||||
.deps/
|
||||
Makefile
|
||||
Makefile.in
|
||||
aclocal.m4
|
||||
autom4te.cache/
|
||||
config.h
|
||||
config.h.in
|
||||
config.log
|
||||
config.status
|
||||
configure
|
||||
depcomp
|
||||
epdfinfo
|
||||
install-sh
|
||||
libsynctex.a
|
||||
missing
|
||||
stamp-h1
|
||||
ar-lib
|
||||
compile
|
||||
config.h.in~
|
||||
.clang_complete
|
||||
callgrind.out.*
|
||||
config.guess
|
||||
config.sub
|
||||
TAGS
|
||||
43
elpa/pdf-tools-20180428.827/build/server/Makefile.am
Normal file
43
elpa/pdf-tools-20180428.827/build/server/Makefile.am
Normal file
@@ -0,0 +1,43 @@
|
||||
bin_PROGRAMS = epdfinfo
|
||||
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) \
|
||||
$(png_LIBS) libsynctex.a $(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 $(zlib_CFLAGS)
|
||||
|
||||
if HAVE_W32
|
||||
epdfinfo_LDADD += -lshlwapi
|
||||
endif
|
||||
|
||||
SYNCTEX_UPSTREAM = svn://tug.org/texlive/tags/texlive-2017.1/Build/source/texk/web2c/synctexdir
|
||||
SYNCTEX_FILES = synctex_parser.c \
|
||||
synctex_parser.h \
|
||||
synctex_parser_local.h \
|
||||
synctex_parser_readme.txt \
|
||||
synctex_parser_utils.c \
|
||||
synctex_parser_utils.h \
|
||||
synctex_parser_version.txt
|
||||
|
||||
|
||||
check-local:
|
||||
@if $(MAKE) --version 2>&1 | grep -q GNU; then \
|
||||
cd test && $(MAKE) $(AM_MAKEFLAGS); \
|
||||
else \
|
||||
echo "Skipping tests in server/test (requires GNU make)"; \
|
||||
fi
|
||||
|
||||
synctex-pull:
|
||||
@if [ -n "$$(git status --porcelain)" ]; then \
|
||||
git status; \
|
||||
echo "Not checking-out files into a dirty work-directory"; \
|
||||
false; \
|
||||
fi
|
||||
for file in $(SYNCTEX_FILES); do \
|
||||
svn export --force $(SYNCTEX_UPSTREAM)/$$file; \
|
||||
done
|
||||
503
elpa/pdf-tools-20180428.827/build/server/autobuild
Executable file
503
elpa/pdf-tools-20180428.827/build/server/autobuild
Executable file
@@ -0,0 +1,503 @@
|
||||
#!/bin/sh
|
||||
|
||||
##
|
||||
## Installs package dependencies and builds the application.
|
||||
##
|
||||
|
||||
# Don't exit if some command fails.
|
||||
set +e
|
||||
# Disalbe file globbing.
|
||||
set -f
|
||||
|
||||
# Boolean variables are true if non-empty and false otherwise.
|
||||
|
||||
# Command to install packages.
|
||||
PKGCMD=
|
||||
# Args to pass to $PKGCMD.
|
||||
PKGARGS=
|
||||
# Required packages.
|
||||
PACKAGES=
|
||||
# Whether package installation requires root permissions.
|
||||
PKG_INSTALL_AS_ROOT=true
|
||||
# Whether to skip package installation altogether.
|
||||
PKG_INSTALL_SKIP=
|
||||
# Whether to force package installation, even if it does not seem
|
||||
# necessary.
|
||||
PKG_INSTALL_FORCE=
|
||||
# Only test if the OS is handled by this script.
|
||||
DRY_RUN=
|
||||
# If and where to install the program.
|
||||
INSTALL_DIR=
|
||||
# Whether we can install packages.
|
||||
OS_IS_HANDLED=true
|
||||
|
||||
## +-----------------------------------------------------------+
|
||||
## * Utility Functions
|
||||
## +-----------------------------------------------------------+
|
||||
|
||||
usage()
|
||||
{
|
||||
cat <<EOF
|
||||
usage:$(basename "$0") [--help|-n|[-i DIR|-I]]
|
||||
|
||||
-n Don't do anything, but check if this OS is handled.
|
||||
|
||||
-i DIR Install the program in the given directory.
|
||||
|
||||
-d Force dependency installattion.
|
||||
|
||||
-D Skip dependency installattion.
|
||||
|
||||
--help Display this message.
|
||||
|
||||
EOF
|
||||
exit "$1"
|
||||
}
|
||||
|
||||
# Search for command $1 in PATH. Print its absolute filename.
|
||||
which()
|
||||
{
|
||||
if [ -z "$1" ]; then
|
||||
return 1
|
||||
fi
|
||||
IFS=:
|
||||
for dir in $PATH; do
|
||||
if [ -x "$dir/$1" ]; then
|
||||
printf "%s" "$dir/$1"
|
||||
unset IFS
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
unset IFS
|
||||
return 1
|
||||
}
|
||||
|
||||
# Quote $@ for the shell.
|
||||
quote()
|
||||
{
|
||||
quoted=
|
||||
for arg; do
|
||||
qarg=$(printf "%s" "$arg" | sed -e 's/[|&;<>()$\`"'\'' ]/\\&/g')
|
||||
if [ -z "$quoted" ]; then
|
||||
quoted=$qarg
|
||||
else
|
||||
quoted="$quoted $qarg"
|
||||
fi
|
||||
done
|
||||
printf "%s" "$quoted"
|
||||
}
|
||||
|
||||
# Attempt to exec $@ as root.
|
||||
exec_privileged() {
|
||||
if [ -z "$1" ]; then
|
||||
echo "internal error: command is empty"
|
||||
exit 2
|
||||
fi
|
||||
if [ -w / ]; then
|
||||
"$@"
|
||||
elif which sudo >/dev/null 2>&1; then
|
||||
sudo -- "$@"
|
||||
retval=$?
|
||||
sudo -k
|
||||
return $retval
|
||||
elif which su >/dev/null 2>&1; then
|
||||
su -c "$(quote "$@")"
|
||||
else
|
||||
echo "No such program: sudo or su"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Test if $1 is in PATH or exit with a failure status.
|
||||
assert_program()
|
||||
{
|
||||
if ! which "$1" >/dev/null 2>&1; then
|
||||
echo "No such program: $1"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Source filename $1 and echo variable $2.
|
||||
source_var()
|
||||
{
|
||||
if ! [ -f "$1" ] || ! [ -r "$1" ] || [ -z "$2" ]; then
|
||||
return 1
|
||||
fi
|
||||
# shellcheck source=/dev/null
|
||||
. "$1"
|
||||
eval "printf '%s\n' \$$2"
|
||||
return 0
|
||||
}
|
||||
|
||||
exit_success()
|
||||
{
|
||||
echo "==========================="
|
||||
echo " Build succeeded. :O) "
|
||||
echo "==========================="
|
||||
exit 0
|
||||
}
|
||||
|
||||
exit_fail()
|
||||
{
|
||||
echo "==========================="
|
||||
echo " Build failed. ;o( "
|
||||
echo "==========================="
|
||||
if [ -z "$PKG_INSTALL_FORCE" ]; then
|
||||
echo "Note: maybe try the '-d' option."
|
||||
fi
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Return 0, if all required packages seem to be installed.
|
||||
have_packages_installed()
|
||||
{
|
||||
{
|
||||
which pkg-config || return 1
|
||||
if ! [ -f configure ];then
|
||||
which autoreconf || return 1
|
||||
which automake || return 1
|
||||
fi
|
||||
for lib in libpng glib-2.0 poppler poppler-glib zlib; do
|
||||
pkg-config --exists $lib || return 1
|
||||
done
|
||||
which make || return 1
|
||||
which gcc || which cc || return 1
|
||||
which g++ || which c++ || return 1
|
||||
cc $(pkg-config --cflags poppler) -o /dev/null -E - 2>/dev/null <<EOF
|
||||
#include <PDFDocEncoding.h>
|
||||
EOF
|
||||
[ $? -eq 0 ] || return 1
|
||||
return 0
|
||||
} >/dev/null 2>&1
|
||||
}
|
||||
|
||||
handle_options()
|
||||
{
|
||||
while [ $# -gt 0 ]; do
|
||||
case $1 in
|
||||
--help) usage 0;;
|
||||
-n) DRY_RUN=true;;
|
||||
-d) PKG_INSTALL_FORCE=true ;;
|
||||
-D) PKG_INSTALL_SKIP=true ;;
|
||||
-i)
|
||||
shift
|
||||
[ $# -gt 0 ] || usage 1
|
||||
if [ "${1%%/}" != "${PWD%%/}" ]; then
|
||||
INSTALL_DIR=$1
|
||||
fi ;;
|
||||
*) usage 1 ;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
if [ -n "$PKG_INSTALL_SKIP" ] && [ -n "$PKG_INSTALL_FORCE" ]; then
|
||||
usage 1
|
||||
fi
|
||||
}
|
||||
|
||||
## +-----------------------------------------------------------+
|
||||
## * OS Functions
|
||||
## +-----------------------------------------------------------+
|
||||
|
||||
# Archlinux
|
||||
os_arch() {
|
||||
if ! [ -e "/etc/arch-release" ]; then
|
||||
return 1;
|
||||
fi
|
||||
PKGCMD=pacman
|
||||
PKGARGS="-S --needed"
|
||||
PACKAGES="base-devel libpng zlib poppler-glib"
|
||||
return 0;
|
||||
}
|
||||
|
||||
# CentOS
|
||||
os_centos() {
|
||||
if ! [ -e "/etc/centos-release" ]; then
|
||||
return 1
|
||||
fi
|
||||
PKGCMD=yum
|
||||
if yum help install-n >/dev/null 2>&1; then
|
||||
PKGARGS=install-n
|
||||
else
|
||||
PKGARGS=install
|
||||
fi
|
||||
PACKAGES="autoconf
|
||||
automake
|
||||
gcc
|
||||
gcc-c++
|
||||
libpng-devel
|
||||
make
|
||||
pkgconfig
|
||||
poppler-devel
|
||||
poppler-glib-devel
|
||||
zlib-devel"
|
||||
return 0
|
||||
}
|
||||
|
||||
# FreeBSD
|
||||
os_freebsd() {
|
||||
if ! which uname >/dev/null 2>&1 || [ "$(uname -s)" != "FreeBSD" ]; then
|
||||
return 1
|
||||
fi
|
||||
PKGCMD=pkg
|
||||
PKGARGS=install
|
||||
PACKAGES="autotools poppler-glib png pkgconf"
|
||||
return 0
|
||||
}
|
||||
|
||||
# OpenBSD
|
||||
os_openbsd() {
|
||||
if ! which uname >/dev/null 2>&1 || [ "$(uname -s)" != "OpenBSD" ]; then
|
||||
return 1
|
||||
fi
|
||||
PKGCMD=pkg_add
|
||||
PKGARGS="-uU"
|
||||
PACKAGES="autoconf-2.69p2 automake-1.15.1 poppler poppler-utils png"
|
||||
export AUTOCONF_VERSION=2.69
|
||||
export AUTOMAKE_VERSION=1.15
|
||||
if whereis clang++ ;then
|
||||
export CXX=clang++
|
||||
elif whereis eg++ ;then
|
||||
export CXX=eg++
|
||||
else
|
||||
export CXX=eg++
|
||||
PACKAGES="${PACKAGES} g++"
|
||||
fi
|
||||
export CXXFLAGS="-std=c++11 -I/usr/local/include/poppler -I/usr/local/include"
|
||||
return 0
|
||||
}
|
||||
|
||||
# Fedora
|
||||
os_fedora() {
|
||||
if ! [ -e "/etc/fedora-release" ]; then
|
||||
return 1
|
||||
fi
|
||||
PKGCMD=dnf
|
||||
PKGARGS=install
|
||||
PACKAGES="autoconf
|
||||
automake
|
||||
gcc
|
||||
gcc-c++
|
||||
libpng-devel
|
||||
make
|
||||
poppler-devel
|
||||
poppler-glib-devel
|
||||
zlib-devel"
|
||||
VERSION=$(source_var /etc/os-release VERSION_ID)
|
||||
if [ -n "$VERSION" ] && [ "$VERSION" -ge 26 ]; then
|
||||
PACKAGES="$PACKAGES pkgconf"
|
||||
else
|
||||
PACKAGES="$PACKAGES pkgconfig"
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# Debian/Ubuntu
|
||||
os_debian() {
|
||||
if ! [ -e "/etc/debian_version" ]; then
|
||||
return 1
|
||||
fi
|
||||
PACKAGES="autoconf
|
||||
automake
|
||||
g++
|
||||
gcc
|
||||
libpng-dev
|
||||
libpoppler-dev
|
||||
libpoppler-glib-dev
|
||||
libpoppler-private-dev
|
||||
libz-dev
|
||||
make
|
||||
pkg-config"
|
||||
PKGCMD=apt-get
|
||||
PKGARGS=install
|
||||
return 0
|
||||
}
|
||||
|
||||
# Msys2
|
||||
os_msys2() {
|
||||
if [ -z "$MSYSTEM" ] || ! [ -r "/etc/profile" ]; then
|
||||
return 1
|
||||
fi
|
||||
case $MSYSTEM in
|
||||
MINGW64)
|
||||
PACKAGES="base-devel
|
||||
mingw-w64-x86_64-libpng
|
||||
mingw-w64-x86_64-poppler
|
||||
mingw-w64-x86_64-toolchain
|
||||
mingw-w64-x86_64-zlib" ;;
|
||||
MINGW32)
|
||||
PACKAGES="base-devel
|
||||
mingw-w64-i686-libpng
|
||||
mingw-w64-i686-poppler
|
||||
mingw-w64-i686-toolchain
|
||||
mingw-w64-i686-zlib" ;;
|
||||
MSYS)
|
||||
case $(uname -m) in
|
||||
x86_64)
|
||||
MSYSTEM=MINGW64 ;;
|
||||
*)
|
||||
MSYSTEM=MINGW32 ;;
|
||||
esac
|
||||
export MSYSTEM
|
||||
# shellcheck source=/dev/null
|
||||
. /etc/profile
|
||||
eval "exec $(quote "$0" "$@")" ;;
|
||||
*)
|
||||
echo "Unrecognized MSYSTEM value: $MSYSTEM"
|
||||
exit 1 ;;
|
||||
esac
|
||||
PKGCMD=pacman
|
||||
PKGARGS="-S --needed"
|
||||
PKG_INSTALL_AS_ROOT=
|
||||
return 0
|
||||
}
|
||||
|
||||
# MacOS
|
||||
os_macos() {
|
||||
if ! which uname >/dev/null 2>&1 || [ "$(uname -s)" != "Darwin" ]; then
|
||||
return 1
|
||||
fi
|
||||
PKGCMD=brew
|
||||
PKGARGS=install
|
||||
PACKAGES="pkg-config poppler automake"
|
||||
PKG_INSTALL_AS_ROOT=
|
||||
return 0
|
||||
}
|
||||
|
||||
# NixOS
|
||||
os_nixos() {
|
||||
# Already in the nix-shell.
|
||||
if [ -n "$AUTOBUILD_NIX_SHELL" ]; then
|
||||
return 0
|
||||
fi
|
||||
if ! which nix-shell >/dev/null 2>&1; then
|
||||
return 1
|
||||
fi
|
||||
if [ -n "$DRY_RUN" ]; then
|
||||
return 0
|
||||
fi
|
||||
command="AUTOBUILD_NIX_SHELL=true"
|
||||
command="$command;export AUTOBUILD_NIX_SHELL"
|
||||
command="$command;$(quote "$0" "$@")"
|
||||
exec nix-shell --pure --command "$command" \
|
||||
-p gcc gnumake automake autoconf pkgconfig libpng zlib poppler
|
||||
}
|
||||
|
||||
# Gentoo
|
||||
os_gentoo() {
|
||||
if ! [ -e "/etc/gentoo-release" ]; then
|
||||
return 1
|
||||
fi
|
||||
PKGCMD=emerge
|
||||
PKGARGS=--noreplace
|
||||
PACKAGES="app-text/poppler
|
||||
dev-util/pkgconfig
|
||||
media-libs/libpng
|
||||
sys-devel/autoconf
|
||||
sys-devel/automake
|
||||
sys-devel/gcc
|
||||
sys-devel/make
|
||||
sys-libs/zlib"
|
||||
return 0
|
||||
}
|
||||
|
||||
## +-----------------------------------------------------------+
|
||||
## * Figure out were we are, install deps and build the program
|
||||
## +-----------------------------------------------------------+
|
||||
|
||||
handle_options "$@"
|
||||
|
||||
os_nixos "$@" || \
|
||||
os_macos "$@" || \
|
||||
os_freebsd "$@" || \
|
||||
os_arch "$@" || \
|
||||
os_centos "$@" || \
|
||||
os_openbsd "$@" || \
|
||||
os_fedora "$@" || \
|
||||
os_debian "$@" || \
|
||||
os_gentoo "$@" || \
|
||||
os_msys2 "$@" || \
|
||||
{
|
||||
OS_IS_HANDLED=
|
||||
if [ -z "$DRY_RUN" ]; then
|
||||
echo "Failed to recognize this system, trying to continue."
|
||||
fi
|
||||
}
|
||||
|
||||
if [ -n "$DRY_RUN" ]; then
|
||||
[ -n "$OS_IS_HANDLED" ]
|
||||
exit $?
|
||||
fi
|
||||
|
||||
if [ -n "$PKGCMD" ];then
|
||||
echo "---------------------------"
|
||||
echo " Installing packages "
|
||||
echo "---------------------------"
|
||||
if [ -n "$PKG_INSTALL_SKIP" ]; then
|
||||
echo "Skipping package installation (as requested)"
|
||||
elif [ -z "$PKG_INSTALL_FORCE" ] && have_packages_installed; then
|
||||
echo "Skipping package installation (already installed)"
|
||||
else
|
||||
assert_program "$PKGCMD"
|
||||
echo "$PKGCMD $PKGARGS $PACKAGES"
|
||||
if [ -n "$PKG_INSTALL_AS_ROOT" ]; then
|
||||
exec_privileged $PKGCMD $PKGARGS $PACKAGES
|
||||
else
|
||||
$PKGCMD $PKGARGS $PACKAGES
|
||||
fi
|
||||
fi
|
||||
echo
|
||||
fi
|
||||
|
||||
echo "---------------------------"
|
||||
echo " Configuring and compiling "
|
||||
echo "---------------------------"
|
||||
|
||||
# Try to be in the correct directory.
|
||||
if which dirname >/dev/null 2>&1; then
|
||||
cd "$(dirname "$0")" || {
|
||||
echo "Failed to change into the source directory"
|
||||
exit 1
|
||||
}
|
||||
fi
|
||||
|
||||
# Create the configure script.
|
||||
if ! [ -f ./configure ]; then
|
||||
assert_program autoreconf
|
||||
echo "autoreconf -i"
|
||||
autoreconf -i
|
||||
[ -f ./configure ] || exit_fail
|
||||
fi
|
||||
|
||||
# Build the program.
|
||||
if [ -n "$INSTALL_DIR" ]; then
|
||||
prefix=--bindir=$INSTALL_DIR
|
||||
fi
|
||||
|
||||
echo "./configure -q $prefix && make -s"
|
||||
eval "./configure -q $(quote "$prefix") && make -s || exit_fail"
|
||||
echo
|
||||
if [ -n "$INSTALL_DIR" ]; then
|
||||
echo "---------------------------"
|
||||
echo " Installing "
|
||||
echo "---------------------------"
|
||||
echo make -s install
|
||||
if mkdir -p -- "$INSTALL_DIR" && [ -w "$INSTALL_DIR" ]; then
|
||||
make install || exit_fail
|
||||
else
|
||||
exec_privileged make install || exit_fail
|
||||
fi
|
||||
# Copy dynamic libraries on windows.
|
||||
if [ -f epdfinfo.exe ]; then
|
||||
assert_program awk
|
||||
assert_program ldd
|
||||
for dll in $(ldd epdfinfo.exe | awk '/\/mingw/ {print $3}'); do
|
||||
cp -u "$dll" "$INSTALL_DIR"
|
||||
done
|
||||
fi
|
||||
echo
|
||||
fi
|
||||
exit_success
|
||||
|
||||
# Local Variables:
|
||||
# compile-command: "shellcheck autobuild"
|
||||
# End:
|
||||
5
elpa/pdf-tools-20180428.827/build/server/autogen.sh
Executable file
5
elpa/pdf-tools-20180428.827/build/server/autogen.sh
Executable file
@@ -0,0 +1,5 @@
|
||||
#!/bin/sh
|
||||
|
||||
echo "Running autoreconf..."
|
||||
|
||||
autoreconf -i
|
||||
113
elpa/pdf-tools-20180428.827/build/server/configure.ac
Normal file
113
elpa/pdf-tools-20180428.827/build/server/configure.ac
Normal file
@@ -0,0 +1,113 @@
|
||||
# -*- Autoconf -*-
|
||||
# Process this file with autoconf to produce a configure script.
|
||||
|
||||
AC_PREREQ([2.67])
|
||||
AC_INIT([epdfinfo], 0.90, [politza@fh-trier.de])
|
||||
AM_INIT_AUTOMAKE([-Wall -Wno-override foreign silent-rules])
|
||||
AC_CONFIG_SRCDIR([epdfinfo.h])
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
|
||||
# Checks for programs.
|
||||
AC_PROG_CC
|
||||
AM_PROG_CC_C_O
|
||||
AC_PROG_CXX
|
||||
AC_PROG_RANLIB
|
||||
AM_PROG_AR
|
||||
|
||||
# Checks for libraries.
|
||||
HAVE_POPPLER_FIND_OPTS="no (requires poppler-glib >= 0.22)"
|
||||
HAVE_POPPLER_ANNOT_WRITE="no (requires poppler-glib >= 0.19.4)"
|
||||
HAVE_POPPLER_ANNOT_MARKUP="no (requires poppler-glib >= 0.26)"
|
||||
|
||||
PKG_CHECK_MODULES([png], [libpng])
|
||||
PKG_CHECK_MODULES([glib], [glib-2.0])
|
||||
PKG_CHECK_MODULES([poppler], [poppler])
|
||||
PKG_CHECK_MODULES([poppler_glib], [poppler-glib >= 0.16.0])
|
||||
PKG_CHECK_EXISTS([poppler-glib >= 0.19.4], [HAVE_POPPLER_ANNOT_WRITE=yes])
|
||||
PKG_CHECK_EXISTS([poppler-glib >= 0.22], [HAVE_POPPLER_FIND_OPTS=yes])
|
||||
PKG_CHECK_EXISTS([poppler-glib >= 0.26], [HAVE_POPPLER_ANNOT_MARKUP=yes])
|
||||
PKG_CHECK_MODULES([zlib], [zlib])
|
||||
|
||||
AC_COMPILE_IFELSE(
|
||||
[AC_LANG_PROGRAM([[
|
||||
#ifndef _WIN32
|
||||
error
|
||||
#endif
|
||||
]])], [have_w32=true], [have_w32=false])
|
||||
AM_CONDITIONAL(HAVE_W32, [test "$have_w32" = true])
|
||||
|
||||
if test "$have_w32" = true; then
|
||||
if test "$MSYSTEM" = MINGW32 -o "$MSYSTEM" = MINGW64; then
|
||||
# glib won't work properly on msys2 without it.
|
||||
CFLAGS="-D__USE_MINGW_ANSI_STDIO=1 $CFLAGS"
|
||||
fi
|
||||
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++])
|
||||
CPPFLAGS=$SAVED_CPPFLAGS
|
||||
|
||||
# Setup compile time features.
|
||||
if test "$HAVE_POPPLER_FIND_OPTS" = yes; then
|
||||
AC_DEFINE([HAVE_POPPLER_FIND_OPTS],1,
|
||||
[Define to 1 to enable case sensitive searching (requires poppler-glib >= 0.22).])
|
||||
fi
|
||||
|
||||
if test "$HAVE_POPPLER_ANNOT_WRITE" = yes; then
|
||||
AC_DEFINE([HAVE_POPPLER_ANNOT_WRITE],1,
|
||||
[Define to 1 to enable writing of annotations (requires poppler-glib >= 0.19.4).])
|
||||
fi
|
||||
|
||||
if test "$HAVE_POPPLER_ANNOT_MARKUP" = yes; then
|
||||
AC_DEFINE([HAVE_POPPLER_ANNOT_MARKUP],1,
|
||||
[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 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.h>
|
||||
],[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
|
||||
|
||||
# Checks for typedefs, structures, and compiler characteristics.
|
||||
AC_TYPE_SIZE_T
|
||||
AC_TYPE_SSIZE_T
|
||||
AC_CHECK_TYPES([ptrdiff_t])
|
||||
AC_C_BIGENDIAN
|
||||
|
||||
# Checks for library functions.
|
||||
AC_FUNC_ERROR_AT_LINE
|
||||
AC_FUNC_STRTOD
|
||||
AC_CHECK_FUNCS([strcspn strtol getline])
|
||||
|
||||
AC_CONFIG_FILES([Makefile])
|
||||
AC_OUTPUT
|
||||
|
||||
echo
|
||||
echo "Is case-sensitive searching enabled ? ${HAVE_POPPLER_FIND_OPTS}"
|
||||
echo "Is modifying text annotations enabled ? ${HAVE_POPPLER_ANNOT_WRITE}"
|
||||
echo "Is modifying markup annotations enabled ? ${HAVE_POPPLER_ANNOT_MARKUP}"
|
||||
echo
|
||||
3718
elpa/pdf-tools-20180428.827/build/server/epdfinfo.c
Normal file
3718
elpa/pdf-tools-20180428.827/build/server/epdfinfo.c
Normal file
File diff suppressed because it is too large
Load Diff
252
elpa/pdf-tools-20180428.827/build/server/epdfinfo.h
Normal file
252
elpa/pdf-tools-20180428.827/build/server/epdfinfo.h
Normal file
@@ -0,0 +1,252 @@
|
||||
// Copyright (C) 2013, 2014 Andreas Politz
|
||||
|
||||
// Author: Andreas Politz <politza@fh-trier.de>
|
||||
|
||||
// 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/>.
|
||||
|
||||
#ifndef _EPDF_H_
|
||||
#define _EPDF_H_ _EPDF_H_
|
||||
#include "config.h"
|
||||
#include <glib.h>
|
||||
#include <poppler.h>
|
||||
#include <png.h>
|
||||
|
||||
/* Some library functions print warnings to stdout, inhibit it. */
|
||||
#define DISCARD_STDOUT(saved_fd) \
|
||||
do { \
|
||||
int __fd; \
|
||||
fflush(stdout); \
|
||||
saved_fd = dup(1); \
|
||||
__fd = open("/dev/null", O_WRONLY); \
|
||||
dup2(__fd, 1); \
|
||||
close(__fd); \
|
||||
} while (0)
|
||||
|
||||
#define UNDISCARD_STDOUT(saved_fd) \
|
||||
do { \
|
||||
fflush(stdout); \
|
||||
dup2(saved_fd, 1); \
|
||||
close(saved_fd); \
|
||||
} while (0)
|
||||
|
||||
/* Writing responses */
|
||||
#define OK_BEGIN() \
|
||||
do { \
|
||||
puts("OK"); \
|
||||
} while (0)
|
||||
|
||||
#define OK_END() \
|
||||
do { \
|
||||
puts("."); \
|
||||
fflush (stdout); \
|
||||
} while (0)
|
||||
|
||||
#define OK() \
|
||||
do { \
|
||||
puts ("OK\n."); \
|
||||
fflush (stdout); \
|
||||
} while (0)
|
||||
|
||||
/* Dealing with image data. */
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
#define ARGB_TO_RGB(rgb, argb) \
|
||||
do { \
|
||||
rgb[0] = argb[1]; \
|
||||
rgb[1] = argb[2]; \
|
||||
rgb[2] = argb[3]; \
|
||||
} while (0)
|
||||
|
||||
#define ARGB_EQUAL(argb1, argb2) \
|
||||
(argb1[1] == argb2[1] \
|
||||
&& argb1[2] == argb2[2] \
|
||||
&& argb1[3] == argb2[3])
|
||||
|
||||
#else
|
||||
#define ARGB_TO_RGB(rgb, argb) \
|
||||
do { \
|
||||
rgb[0] = argb[2]; \
|
||||
rgb[1] = argb[1]; \
|
||||
rgb[2] = argb[0]; \
|
||||
} while (0)
|
||||
|
||||
#define ARGB_EQUAL(argb1, argb2) \
|
||||
(argb1[0] == argb2[0] \
|
||||
&& argb1[1] == argb2[1] \
|
||||
&& argb1[2] == argb2[2])
|
||||
#endif
|
||||
|
||||
#define NORMALIZE_PAGE_ARG(doc, first, last) \
|
||||
*first = MAX(1, *first); \
|
||||
if (*last <= 0) \
|
||||
*last = poppler_document_get_n_pages (doc); \
|
||||
else \
|
||||
*last = MIN(*last, poppler_document_get_n_pages (doc));
|
||||
|
||||
/* png_jmpbuf is supposed to be not available in older versions of
|
||||
libpng. */
|
||||
#ifndef png_jmpbuf
|
||||
# define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf)
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_ERROR_H
|
||||
# define error(status, errno, fmt, args...) \
|
||||
do { \
|
||||
int error = (errno); \
|
||||
fflush (stdout); \
|
||||
fprintf (stderr, "%s: " fmt, PACKAGE_NAME, ## args); \
|
||||
if (error) \
|
||||
fprintf (stderr, ": %s", strerror (error)); \
|
||||
fprintf (stderr, "\n"); \
|
||||
exit (status); \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#define internal_error(fmt, args...) \
|
||||
error (2, 0, "internal error in %s: " fmt, __func__, ## args)
|
||||
|
||||
#define error_if_not(expr) \
|
||||
if (! (expr)) goto error;
|
||||
|
||||
#define perror_if_not(expr, fmt, args...) \
|
||||
do { \
|
||||
if (! (expr)) \
|
||||
{ \
|
||||
printf_error_response ((fmt), ## args); \
|
||||
goto error; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define cerror_if_not(expr, error_msg, fmt, args...) \
|
||||
do { \
|
||||
if (! (expr)) \
|
||||
{ \
|
||||
if (error_msg) \
|
||||
*(error_msg) = g_strdup_printf((fmt), ## args); \
|
||||
goto error; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/* Declare commands */
|
||||
#define DEC_CMD(name) \
|
||||
{#name, cmd_ ## name, cmd_ ## name ## _spec, \
|
||||
G_N_ELEMENTS (cmd_ ## name ## _spec)}
|
||||
|
||||
#define DEC_CMD2(command, name) \
|
||||
{name, cmd_ ## command, cmd_ ## command ## _spec, \
|
||||
G_N_ELEMENTS (cmd_ ## command ## _spec)}
|
||||
|
||||
/* Declare option */
|
||||
#define DEC_DOPT(name, type, sname) \
|
||||
{name, type, offsetof (document_options_t, sname)}
|
||||
|
||||
enum suffix_char { NONE, COLON, NEWLINE};
|
||||
|
||||
enum image_type { PPM, PNG };
|
||||
|
||||
typedef struct
|
||||
{
|
||||
PopplerAnnotMapping *amap;
|
||||
gchar *key;
|
||||
} annotation_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
ARG_INVALID = 0,
|
||||
ARG_DOC,
|
||||
ARG_BOOL,
|
||||
ARG_STRING,
|
||||
ARG_NONEMPTY_STRING,
|
||||
ARG_NATNUM,
|
||||
ARG_EDGE,
|
||||
ARG_EDGE_OR_NEGATIVE,
|
||||
ARG_EDGES,
|
||||
ARG_EDGES_OR_POSITION,
|
||||
ARG_COLOR,
|
||||
ARG_REST
|
||||
} command_arg_type_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const char *name;
|
||||
command_arg_type_t type;
|
||||
size_t offset;
|
||||
} document_option_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
PopplerColor bg, fg;
|
||||
gboolean usecolors;
|
||||
gboolean printed;
|
||||
} render_options_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
render_options_t render;
|
||||
} document_options_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
PopplerDocument *pdf;
|
||||
char *filename;
|
||||
char *passwd;
|
||||
struct
|
||||
{
|
||||
GHashTable *keys; /* key => page */
|
||||
GList **pages; /* page array */
|
||||
} annotations;
|
||||
document_options_t options;
|
||||
} document_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
command_arg_type_t type;
|
||||
union
|
||||
{
|
||||
gboolean flag;
|
||||
const char *string;
|
||||
long natnum;
|
||||
document_t *doc;
|
||||
gdouble edge;
|
||||
PopplerColor color;
|
||||
PopplerRectangle rectangle;
|
||||
#ifdef HAVE_POPPLER_ANNOT_MARKUP
|
||||
PopplerQuadrilateral quadrilateral;
|
||||
#endif
|
||||
struct
|
||||
{
|
||||
char * const *args;
|
||||
int nargs;
|
||||
} rest;
|
||||
} value;
|
||||
} command_arg_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GHashTable *documents;
|
||||
} epdfinfo_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const char *name;
|
||||
void (* execute) (const epdfinfo_t *ctxt, const command_arg_t *args);
|
||||
const command_arg_type_t *args_spec;
|
||||
int nargs;
|
||||
} command_t;
|
||||
|
||||
/* Defined in poppler-hack.cc */
|
||||
#ifdef HAVE_POPPLER_ANNOT_WRITE
|
||||
extern void xpoppler_annot_set_rectangle (PopplerAnnot*, PopplerRectangle*);
|
||||
#endif
|
||||
extern gchar *xpoppler_annot_markup_get_created (PopplerAnnotMarkup*);
|
||||
#endif /* _EPDF_H_ */
|
||||
@@ -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 <guidod@gmx.de>
|
||||
# Copyright (c) 2011 Maarten Bosmans <mkbosmans@gmail.com>
|
||||
#
|
||||
# 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 <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
# 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
|
||||
115
elpa/pdf-tools-20180428.827/build/server/poppler-hack.cc
Normal file
115
elpa/pdf-tools-20180428.827/build/server/poppler-hack.cc
Normal file
@@ -0,0 +1,115 @@
|
||||
// Copyright (C) 2013, 2014 Andreas Politz
|
||||
|
||||
// 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/>.
|
||||
|
||||
#include <config.h>
|
||||
#include <PDFDocEncoding.h>
|
||||
#include <Annot.h>
|
||||
#include <glib.h>
|
||||
#include <glib-object.h>
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
GType poppler_annot_get_type (void) G_GNUC_CONST;
|
||||
GType poppler_annot_markup_get_type (void) G_GNUC_CONST;
|
||||
|
||||
#define POPPLER_TYPE_ANNOT (poppler_annot_get_type ())
|
||||
#define POPPLER_ANNOT(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_CAST ((obj), POPPLER_TYPE_ANNOT, PopplerAnnot))
|
||||
#define POPPLER_IS_ANNOT_MARKUP(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), POPPLER_TYPE_ANNOT_MARKUP))
|
||||
#define POPPLER_TYPE_ANNOT_MARKUP (poppler_annot_markup_get_type ())
|
||||
|
||||
struct PopplerAnnot
|
||||
{
|
||||
GObject parent_instance;
|
||||
Annot *annot;
|
||||
};
|
||||
|
||||
struct PopplerAnnotMarkup
|
||||
{
|
||||
GObject parent_instance;
|
||||
};
|
||||
|
||||
struct PopplerRectangle
|
||||
{
|
||||
double x1;
|
||||
double y1;
|
||||
double x2;
|
||||
double y2;
|
||||
};
|
||||
|
||||
// This function does not modify its argument s, but for
|
||||
// compatibility reasons (e.g. getLength in GooString.h before 2015)
|
||||
// with older poppler code, it can't be declared as such.
|
||||
char *_xpoppler_goo_string_to_utf8(/* const */ GooString *s)
|
||||
{
|
||||
char *result;
|
||||
|
||||
if (! s)
|
||||
return NULL;
|
||||
|
||||
if (s->hasUnicodeMarker()) {
|
||||
result = g_convert (s->getCString () + 2,
|
||||
s->getLength () - 2,
|
||||
"UTF-8", "UTF-16BE", NULL, NULL, NULL);
|
||||
} else {
|
||||
int len;
|
||||
gunichar *ucs4_temp;
|
||||
int i;
|
||||
|
||||
len = s->getLength ();
|
||||
ucs4_temp = g_new (gunichar, len + 1);
|
||||
for (i = 0; i < len; ++i) {
|
||||
ucs4_temp[i] = pdfDocEncoding[(unsigned char)s->getChar(i)];
|
||||
}
|
||||
ucs4_temp[i] = 0;
|
||||
|
||||
result = g_ucs4_to_utf8 (ucs4_temp, -1, NULL, NULL, NULL);
|
||||
|
||||
g_free (ucs4_temp);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
#ifdef HAVE_POPPLER_ANNOT_WRITE
|
||||
// Set the rectangle of an annotation. It was first added in v0.26.
|
||||
void xpoppler_annot_set_rectangle (PopplerAnnot *a, PopplerRectangle *rectangle)
|
||||
{
|
||||
GooString *state = (GooString*) 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
|
||||
// This function is in the library, but the enforced date parsing is
|
||||
// incomplete (at least in some versions), because it ignores the
|
||||
// timezone.
|
||||
gchar *xpoppler_annot_markup_get_created (PopplerAnnotMarkup *poppler_annot)
|
||||
{
|
||||
AnnotMarkup *annot;
|
||||
GooString *text;
|
||||
|
||||
g_return_val_if_fail (POPPLER_IS_ANNOT_MARKUP (poppler_annot), NULL);
|
||||
|
||||
annot = static_cast<AnnotMarkup *>(POPPLER_ANNOT (poppler_annot)->annot);
|
||||
text = (GooString*) annot->getDate ();
|
||||
|
||||
return text ? _xpoppler_goo_string_to_utf8 (text) : NULL;
|
||||
}
|
||||
}
|
||||
12
elpa/pdf-tools-20180428.827/build/server/poppler-versions
Normal file
12
elpa/pdf-tools-20180428.827/build/server/poppler-versions
Normal file
@@ -0,0 +1,12 @@
|
||||
HAVE_POPPLER_ANNOT_WRITE
|
||||
0.19.4 solves bug 49080, which potentially corrupts PDF files.
|
||||
|
||||
HAVE_POPPLER_FIND_OPTS
|
||||
0.22 PopplerFindFlags
|
||||
0.22 poppler_page_find_text_with_options
|
||||
|
||||
HAVE_POPPLER_ANNOT_SET_RECT
|
||||
0.26 Adds function poppler_annot_set_rectangle
|
||||
|
||||
HAVE_POPPLER_ANNOT_MARKUP
|
||||
0.26 poppler_annot_text_markup_new_{highlight,squiggly,strikeout,underline}
|
||||
4414
elpa/pdf-tools-20180428.827/build/server/synctex_parser.c
Normal file
4414
elpa/pdf-tools-20180428.827/build/server/synctex_parser.c
Normal file
File diff suppressed because it is too large
Load Diff
363
elpa/pdf-tools-20180428.827/build/server/synctex_parser.h
Normal file
363
elpa/pdf-tools-20180428.827/build/server/synctex_parser.h
Normal file
@@ -0,0 +1,363 @@
|
||||
/*
|
||||
Copyright (c) 2008, 2009, 2010 , 2011 jerome DOT laurens AT u-bourgogne DOT fr
|
||||
|
||||
This file is part of the SyncTeX package.
|
||||
|
||||
Latest Revision: Tue Jun 14 08:23:30 UTC 2011
|
||||
|
||||
Version: 1.18
|
||||
|
||||
See synctex_parser_readme.txt for more details
|
||||
|
||||
License:
|
||||
--------
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
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
|
||||
authorization from the copyright holder.
|
||||
|
||||
Acknowledgments:
|
||||
----------------
|
||||
The author received useful remarks from the pdfTeX developers, especially Hahn The Thanh,
|
||||
and significant help from XeTeX developer Jonathan Kew
|
||||
|
||||
Nota Bene:
|
||||
----------
|
||||
If you include or use a significant part of the synctex package into a software,
|
||||
I would appreciate to be listed as contributor and see "SyncTeX" highlighted.
|
||||
|
||||
Version 1
|
||||
Thu Jun 19 09:39:21 UTC 2008
|
||||
|
||||
*/
|
||||
|
||||
#ifndef __SYNCTEX_PARSER__
|
||||
# define __SYNCTEX_PARSER__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
# define SYNCTEX_VERSION_STRING "1.18"
|
||||
|
||||
/* synctex_node_t is the type for all synctex nodes.
|
||||
* The synctex file is parsed into a tree of nodes, either sheet, boxes, math nodes... */
|
||||
typedef struct _synctex_node * synctex_node_t;
|
||||
|
||||
/* The main synctex object is a scanner
|
||||
* Its implementation is considered private.
|
||||
* The basic workflow is
|
||||
* - create a "synctex scanner" with the contents of a file
|
||||
* - perform actions on that scanner like display or edit queries
|
||||
* - free the scanner when the work is done
|
||||
*/
|
||||
typedef struct __synctex_scanner_t _synctex_scanner_t;
|
||||
typedef _synctex_scanner_t * synctex_scanner_t;
|
||||
|
||||
/* This is the designated method to create a new synctex scanner object.
|
||||
* output is the pdf/dvi/xdv file associated to the synctex file.
|
||||
* If necessary, it can be the tex file that originated the synctex file
|
||||
* but this might cause problems if the \jobname has a custom value.
|
||||
* Despite this method can accept a relative path in practice,
|
||||
* you should only pass a full path name.
|
||||
* The path should be encoded by the underlying file system,
|
||||
* assuming that it is based on 8 bits characters, including UTF8,
|
||||
* not 16 bits nor 32 bits.
|
||||
* The last file extension is removed and replaced by the proper extension.
|
||||
* Then the private method _synctex_scanner_new_with_contents_of_file is called.
|
||||
* NULL is returned in case of an error or non existent file.
|
||||
* Once you have a scanner, use the synctex_display_query and synctex_edit_query below.
|
||||
* The new "build_directory" argument is available since version 1.5.
|
||||
* It is the directory where all the auxiliary stuff is created.
|
||||
* Sometimes, the synctex output file and the pdf, dvi or xdv files are not created in the same directory.
|
||||
* This is the case in MikTeX (I will include this into TeX Live).
|
||||
* This directory path can be nil, it will be ignored then.
|
||||
* It can be either absolute or relative to the directory of the output pdf (dvi or xdv) file.
|
||||
* If no synctex file is found in the same directory as the output file, then we try to find one in the build directory.
|
||||
* Please note that this new "build_directory" is provided as a convenient argument but should not be used.
|
||||
* In fact, this is implempented as a work around of a bug in MikTeX where the synctex file does not follow the pdf file.
|
||||
* The new "parse" argument is available since version 1.5. In general, use 1.
|
||||
* Use 0 only if you do not want to parse the content but just check the existence.
|
||||
*/
|
||||
synctex_scanner_t synctex_scanner_new_with_output_file(const char * output, const char * build_directory, int parse);
|
||||
|
||||
/* This is the designated method to delete a synctex scanner object.
|
||||
* Frees all the memory, you must call it when you are finished with the scanner.
|
||||
*/
|
||||
void synctex_scanner_free(synctex_scanner_t scanner);
|
||||
|
||||
/* Send this message to force the scanner to parse the contents of the synctex output file.
|
||||
* Nothing is performed if the file was already parsed.
|
||||
* In each query below, this message is sent, but if you need to access information more directly,
|
||||
* you must be sure that the parsing did occur.
|
||||
* Usage:
|
||||
* if((my_scanner = synctex_scanner_parse(my_scanner))) {
|
||||
* continue with my_scanner...
|
||||
* } else {
|
||||
* there was a problem
|
||||
* }
|
||||
*/
|
||||
synctex_scanner_t synctex_scanner_parse(synctex_scanner_t scanner);
|
||||
|
||||
/* The main entry points.
|
||||
* Given the file name, a line and a column number, synctex_display_query returns the number of nodes
|
||||
* satisfying the contrain. Use code like
|
||||
*
|
||||
* if(synctex_display_query(scanner,name,line,column)>0) {
|
||||
* synctex_node_t node;
|
||||
* while((node = synctex_next_result(scanner))) {
|
||||
* // do something with node
|
||||
* ...
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* For example, one can
|
||||
* - highlight each resulting node in the output, using synctex_node_h and synctex_node_v
|
||||
* - highlight all the rectangles enclosing those nodes, using synctex_box_... functions
|
||||
* - highlight just the character using that information
|
||||
*
|
||||
* Given the page and the position in the page, synctex_edit_query returns the number of nodes
|
||||
* satisfying the contrain. Use code like
|
||||
*
|
||||
* if(synctex_edit_query(scanner,page,h,v)>0) {
|
||||
* synctex_node_t node;
|
||||
* while(node = synctex_next_result(scanner)) {
|
||||
* // do something with node
|
||||
* ...
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* For example, one can
|
||||
* - highlight each resulting line in the input,
|
||||
* - highlight just the character using that information
|
||||
*
|
||||
* page is 1 based
|
||||
* h and v are coordinates in 72 dpi unit, relative to the top left corner of the page.
|
||||
* If you make a new query, the result of the previous one is discarded.
|
||||
* If one of this function returns a non positive integer,
|
||||
* it means that an error occurred.
|
||||
*
|
||||
* Both methods are conservative, in the sense that matching is weak.
|
||||
* If the exact column number is not found, there will be an answer with the whole line.
|
||||
*
|
||||
* Sumatra-PDF, Skim, iTeXMac2 and Texworks are examples of open source software that use this library.
|
||||
* You can browse their code for a concrete implementation.
|
||||
*/
|
||||
typedef long synctex_status_t;
|
||||
synctex_status_t synctex_display_query(synctex_scanner_t scanner,const char * name,int line,int column);
|
||||
synctex_status_t synctex_edit_query(synctex_scanner_t scanner,int page,float h,float v);
|
||||
synctex_node_t synctex_next_result(synctex_scanner_t scanner);
|
||||
|
||||
/* Display all the information contained in the scanner object.
|
||||
* If the records are too numerous, only the first ones are displayed.
|
||||
* This is mainly for informatinal purpose to help developers.
|
||||
*/
|
||||
void synctex_scanner_display(synctex_scanner_t scanner);
|
||||
|
||||
/* The x and y offset of the origin in TeX coordinates. The magnification
|
||||
These are used by pdf viewers that want to display the real box size.
|
||||
For example, getting the horizontal coordinates of a node would require
|
||||
synctex_node_box_h(node)*synctex_scanner_magnification(scanner)+synctex_scanner_x_offset(scanner)
|
||||
Getting its TeX width would simply require
|
||||
synctex_node_box_width(node)*synctex_scanner_magnification(scanner)
|
||||
but direct methods are available for that below.
|
||||
*/
|
||||
int synctex_scanner_x_offset(synctex_scanner_t scanner);
|
||||
int synctex_scanner_y_offset(synctex_scanner_t scanner);
|
||||
float synctex_scanner_magnification(synctex_scanner_t scanner);
|
||||
|
||||
/* Managing the input file names.
|
||||
* Given a tag, synctex_scanner_get_name will return the corresponding file name.
|
||||
* Conversely, given a file name, synctex_scanner_get_tag will retur, the corresponding tag.
|
||||
* The file name must be the very same as understood by TeX.
|
||||
* For example, if you \input myDir/foo.tex, the file name is myDir/foo.tex.
|
||||
* No automatic path expansion is performed.
|
||||
* Finally, synctex_scanner_input is the first input node of the scanner.
|
||||
* To browse all the input node, use a loop like
|
||||
*
|
||||
* if((input_node = synctex_scanner_input(scanner))){
|
||||
* do {
|
||||
* blah
|
||||
* } while((input_node=synctex_node_sibling(input_node)));
|
||||
* }
|
||||
*
|
||||
* The output is the name that was used to create the scanner.
|
||||
* The synctex is the real name of the synctex file,
|
||||
* it was obtained from output by setting the proper file extension.
|
||||
*/
|
||||
const char * synctex_scanner_get_name(synctex_scanner_t scanner,int tag);
|
||||
int synctex_scanner_get_tag(synctex_scanner_t scanner,const char * name);
|
||||
synctex_node_t synctex_scanner_input(synctex_scanner_t scanner);
|
||||
const char * synctex_scanner_get_output(synctex_scanner_t scanner);
|
||||
const char * synctex_scanner_get_synctex(synctex_scanner_t scanner);
|
||||
|
||||
/* Browsing the nodes
|
||||
* parent, child and sibling are standard names for tree nodes.
|
||||
* The parent is one level higher, the child is one level deeper,
|
||||
* and the sibling is at the same level.
|
||||
* The sheet of a node is the first ancestor, it is of type sheet.
|
||||
* A node and its sibling have the same parent.
|
||||
* A node is the parent of its child.
|
||||
* A node is either the child of its parent,
|
||||
* or belongs to the sibling chain of its parent's child.
|
||||
* The next node is either the child, the sibling or the parent's sibling,
|
||||
* unless the parent is a sheet.
|
||||
* This allows to navigate through all the nodes of a given sheet node:
|
||||
*
|
||||
* synctex_node_t node = sheet;
|
||||
* while((node = synctex_node_next(node))) {
|
||||
* // do something with node
|
||||
* }
|
||||
*
|
||||
* With synctex_sheet_content, you can retrieve the sheet node given the page.
|
||||
* The page is 1 based, according to TeX standards.
|
||||
* Conversely synctex_node_sheet allows to retrieve the sheet containing a given node.
|
||||
*/
|
||||
synctex_node_t synctex_node_parent(synctex_node_t node);
|
||||
synctex_node_t synctex_node_sheet(synctex_node_t node);
|
||||
synctex_node_t synctex_node_child(synctex_node_t node);
|
||||
synctex_node_t synctex_node_sibling(synctex_node_t node);
|
||||
synctex_node_t synctex_node_next(synctex_node_t node);
|
||||
synctex_node_t synctex_sheet(synctex_scanner_t scanner,int page);
|
||||
synctex_node_t synctex_sheet_content(synctex_scanner_t scanner,int page);
|
||||
|
||||
/* These are the types of the synctex nodes */
|
||||
typedef enum {
|
||||
synctex_node_type_error = 0,
|
||||
synctex_node_type_input,
|
||||
synctex_node_type_sheet,
|
||||
synctex_node_type_vbox,
|
||||
synctex_node_type_void_vbox,
|
||||
synctex_node_type_hbox,
|
||||
synctex_node_type_void_hbox,
|
||||
synctex_node_type_kern,
|
||||
synctex_node_type_glue,
|
||||
synctex_node_type_math,
|
||||
synctex_node_type_boundary,
|
||||
synctex_node_number_of_types
|
||||
} synctex_node_type_t;
|
||||
|
||||
/* synctex_node_type gives the type of a given node,
|
||||
* synctex_node_isa gives the same information as a human readable text. */
|
||||
synctex_node_type_t synctex_node_type(synctex_node_t node);
|
||||
const char * synctex_node_isa(synctex_node_t node);
|
||||
|
||||
/* This is primarily used for debugging purpose.
|
||||
* The second one logs information for the node and recursively displays information for its next node */
|
||||
void synctex_node_log(synctex_node_t node);
|
||||
void synctex_node_display(synctex_node_t node);
|
||||
|
||||
/* Given a node, access to the location in the synctex file where it is defined.
|
||||
*/
|
||||
typedef unsigned int synctex_charindex_t;
|
||||
synctex_charindex_t synctex_node_charindex(synctex_node_t node);
|
||||
|
||||
/* Given a node, access to its tag, line and column.
|
||||
* The line and column numbers are 1 based.
|
||||
* The latter is not yet fully supported in TeX, the default implementation returns 0 which means the whole line.
|
||||
* When the tag is known, the scanner of the node will give the corresponding file name.
|
||||
* When the tag is known, the scanner of the node will give the name.
|
||||
*/
|
||||
int synctex_node_tag(synctex_node_t node);
|
||||
int synctex_node_line(synctex_node_t node);
|
||||
int synctex_node_column(synctex_node_t node);
|
||||
|
||||
/* In order to enhance forward synchronization,
|
||||
* non void horizontal boxes have supplemental cached information.
|
||||
* The mean line is the average of the line numbers of the included nodes.
|
||||
* The child count is the number of chidren.
|
||||
*/
|
||||
int synctex_node_mean_line(synctex_node_t node);
|
||||
int synctex_node_child_count(synctex_node_t node);
|
||||
|
||||
/* This is the page where the node appears.
|
||||
* This is a 1 based index as given by TeX.
|
||||
*/
|
||||
int synctex_node_page(synctex_node_t node);
|
||||
|
||||
/* For quite all nodes, horizontal, vertical coordinates, and width.
|
||||
* These are expressed in TeX small points coordinates, with origin at the top left corner.
|
||||
*/
|
||||
int synctex_node_h(synctex_node_t node);
|
||||
int synctex_node_v(synctex_node_t node);
|
||||
int synctex_node_width(synctex_node_t node);
|
||||
|
||||
/* For all nodes, dimensions of the enclosing box.
|
||||
* These are expressed in TeX small points coordinates, with origin at the top left corner.
|
||||
* A box is enclosing itself.
|
||||
*/
|
||||
int synctex_node_box_h(synctex_node_t node);
|
||||
int synctex_node_box_v(synctex_node_t node);
|
||||
int synctex_node_box_width(synctex_node_t node);
|
||||
int synctex_node_box_height(synctex_node_t node);
|
||||
int synctex_node_box_depth(synctex_node_t node);
|
||||
|
||||
/* For quite all nodes, horizontal, vertical coordinates, and width.
|
||||
* The visible dimensions are bigger than real ones to compensate 0 width boxes
|
||||
* that do contain nodes.
|
||||
* These are expressed in page coordinates, with origin at the top left corner.
|
||||
* A box is enclosing itself.
|
||||
*/
|
||||
float synctex_node_visible_h(synctex_node_t node);
|
||||
float synctex_node_visible_v(synctex_node_t node);
|
||||
float synctex_node_visible_width(synctex_node_t node);
|
||||
/* For all nodes, visible dimensions of the enclosing box.
|
||||
* A box is enclosing itself.
|
||||
* The visible dimensions are bigger than real ones to compensate 0 width boxes
|
||||
* that do contain nodes.
|
||||
*/
|
||||
float synctex_node_box_visible_h(synctex_node_t node);
|
||||
float synctex_node_box_visible_v(synctex_node_t node);
|
||||
float synctex_node_box_visible_width(synctex_node_t node);
|
||||
float synctex_node_box_visible_height(synctex_node_t node);
|
||||
float synctex_node_box_visible_depth(synctex_node_t node);
|
||||
|
||||
/* The main synctex updater object.
|
||||
* This object is used to append information to the synctex file.
|
||||
* Its implementation is considered private.
|
||||
* It is used by the synctex command line tool to take into account modifications
|
||||
* that could occur while postprocessing files by dvipdf like filters.
|
||||
*/
|
||||
typedef struct __synctex_updater_t _synctex_updater_t;
|
||||
typedef _synctex_updater_t * synctex_updater_t;
|
||||
|
||||
/* Designated initializer.
|
||||
* Once you are done with your whole job,
|
||||
* free the updater */
|
||||
synctex_updater_t synctex_updater_new_with_output_file(const char * output, const char * directory);
|
||||
|
||||
/* Use the next functions to append records to the synctex file,
|
||||
* no consistency tests made on the arguments */
|
||||
void synctex_updater_append_magnification(synctex_updater_t updater, char * magnification);
|
||||
void synctex_updater_append_x_offset(synctex_updater_t updater, char * x_offset);
|
||||
void synctex_updater_append_y_offset(synctex_updater_t updater, char * y_offset);
|
||||
|
||||
/* You MUST free the updater, once everything is properly appended */
|
||||
void synctex_updater_free(synctex_updater_t updater);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
Copyright (c) 2008, 2009, 2010 , 2011 jerome DOT laurens AT u-bourgogne DOT fr
|
||||
|
||||
This file is part of the SyncTeX package.
|
||||
|
||||
Latest Revision: Tue Jun 14 08:23:30 UTC 2011
|
||||
|
||||
Version: 1.18
|
||||
|
||||
See synctex_parser_readme.txt for more details
|
||||
|
||||
License:
|
||||
--------
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
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
|
||||
authorization from the copyright holder.
|
||||
|
||||
*/
|
||||
|
||||
/* This local header file is for TEXLIVE, use your own header to fit your system */
|
||||
# include <w2c/c-auto.h> /* for inline && HAVE_xxx */
|
||||
/* No inlining for synctex tool in texlive. */
|
||||
# define SYNCTEX_INLINE
|
||||
@@ -0,0 +1,182 @@
|
||||
This file is part of the SyncTeX package.
|
||||
|
||||
The Synchronization TeXnology named SyncTeX is a new feature
|
||||
of recent TeX engines designed by Jerome Laurens.
|
||||
It allows to synchronize between input and output, which means to
|
||||
navigate from the source document to the typeset material and vice versa.
|
||||
More informations on http://itexmac2.sourceforge.net/SyncTeX.html
|
||||
|
||||
This package is mainly for developers, it mainly contains the following files:
|
||||
|
||||
synctex_parser_readme.txt
|
||||
synctex_parser_version.txt
|
||||
synctex_parser_utils.c
|
||||
synctex_parser_utils.h
|
||||
synctex_parser_local.h
|
||||
synctex_parser.h
|
||||
synctex_parser.c
|
||||
|
||||
The file you are reading contains more informations about the SyncTeX parser history.
|
||||
|
||||
In order to support SyncTeX in a viewer, it is sufficient to include
|
||||
in the source the files synctex_parser.h and synctex_parser.c.
|
||||
The synctex parser usage is described in synctex_parser.h header file.
|
||||
|
||||
The other files are used by tex engines or by the synctex command line utility:
|
||||
|
||||
ChangeLog
|
||||
README.txt
|
||||
am
|
||||
man1
|
||||
man5
|
||||
synctex-common.h
|
||||
synctex-convert.sh
|
||||
synctex-e-mem.ch0
|
||||
synctex-e-mem.ch1
|
||||
synctex-e-rec.ch0
|
||||
synctex-e-rec.ch1
|
||||
synctex-etex.h
|
||||
synctex-mem.ch0
|
||||
synctex-mem.ch1
|
||||
synctex-mem.ch2
|
||||
synctex-pdf-rec.ch2
|
||||
synctex-pdftex.h
|
||||
synctex-rec.ch0
|
||||
synctex-rec.ch1
|
||||
synctex-rec.ch2
|
||||
synctex-tex.h
|
||||
synctex-xe-mem.ch2
|
||||
synctex-xe-rec.ch2
|
||||
synctex-xe-rec.ch3
|
||||
synctex-xetex.h
|
||||
synctex.c
|
||||
synctex.defines
|
||||
synctex.h
|
||||
synctex_main.c
|
||||
tests
|
||||
|
||||
|
||||
Version:
|
||||
--------
|
||||
This is version 1, which refers to the synctex output file format.
|
||||
The files are identified by a build number.
|
||||
In order to help developers to automatically manage the version and build numbers
|
||||
and download the parser only when necessary, the synctex_parser.version
|
||||
is an ASCII text file just containing the current version and build numbers.
|
||||
|
||||
History:
|
||||
--------
|
||||
1.1: Thu Jul 17 09:28:13 UTC 2008
|
||||
- First official version available in TeXLive 2008 DVD.
|
||||
Unfortunately, the backwards synchronization is not working properly mainly for ConTeXt users, see below.
|
||||
1.2: Tue Sep 2 10:28:32 UTC 2008
|
||||
- Correction for ConTeXt support in the edit query.
|
||||
The previous method was assuming that TeX boxes do not overlap,
|
||||
which is reasonable for LaTeX but not for ConTeXt.
|
||||
This assumption is no longer considered.
|
||||
1.3: Fri Sep 5 09:39:57 UTC 2008
|
||||
- Local variable "read" renamed to "already_read" to avoid conflicts.
|
||||
- "inline" compiler directive renamed to "SYNCTEX_INLINE" for code support and maintenance
|
||||
- _synctex_error cannot be inlined due to variable arguments (thanks Christiaan Hofman)
|
||||
- Correction in the display query, extra boundary nodes are used for a more precise forwards synchronization
|
||||
1.4: Fri Sep 12 08:12:34 UTC 2008
|
||||
- For an unknown reason, the previous version was not the real 1.3 (as used in iTeXMac2 build 747).
|
||||
As a consequence, a crash was observed.
|
||||
- Some typos are fixed.
|
||||
1.6: Mon Nov 3 20:20:02 UTC 2008
|
||||
- The bug that prevented synchronization with compressed files on windows has been fixed.
|
||||
- New interface to allow system specific customization.
|
||||
- Note that some APIs have changed.
|
||||
1.8: Mer 8 jul 2009 11:32:38 UTC
|
||||
Note that version 1.7 was delivered privately.
|
||||
- bug fix: synctex was causing a memory leak in pdftex and xetex, thus some processing speed degradation
|
||||
- bug fix: the synctex command line tool was broken when updating a .synctex file
|
||||
- enhancement: better accuracy of the synchronization process
|
||||
- enhancement: the pdf output file and the associated .synctex file no longer need to live in the same directory.
|
||||
The new -d option of the synctex command line tool manages this situation.
|
||||
This is handy when using something like tex -output-directory=DIR ...
|
||||
1.9: Wed Nov 4 11:52:35 UTC 2009
|
||||
- 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
|
||||
- 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
|
||||
- Bug fix in synctex_parser.c, function synctex_node_box_visible_v: 'x' replaced by 'y'.
|
||||
Only 3rd party tools are concerned.
|
||||
1.12: Mon Jul 19 21:52:10 UTC 2010
|
||||
- Bug fix in synctex_parser.c, function __synctex_open: the io_mode was modified even in case of a non zero return,
|
||||
causing a void .synctex.gz file to be created even if it was not expected. Reported by Marek Kasik concerning a bug on evince.
|
||||
1.13: Fri Mar 11 07:39:12 UTC 2011
|
||||
- Bug fix in synctex_parser.c, better synchronization as suggested by Jan Sundermeyer (near line 3388).
|
||||
- Stronger code design in synctex_parser_utils.c, function _synctex_get_name (really neutral behavior).
|
||||
Only 3rd party tools are concerned.
|
||||
1.14: Fri Apr 15 19:10:57 UTC 2011
|
||||
- taking output_directory into account
|
||||
- Replaced FOPEN_WBIN_MODE by FOPEN_W_MODE when opening the text version of the .synctex file.
|
||||
- Merging with LuaTeX's version of synctex.c
|
||||
1.15: Fri Jun 10 14:10:17 UTC 2011
|
||||
This concerns the synctex command line tool and 3rd party developers.
|
||||
TeX and friends are not concerned by these changes.
|
||||
- Bug fixed in _synctex_get_io_mode_name, sometimes the wrong mode was returned
|
||||
- Support for LuaTeX convention of './' file prefixing
|
||||
1.16: Tue Jun 14 08:23:30 UTC 2011
|
||||
This concerns the synctex command line tool and 3rd party developers.
|
||||
TeX and friends are not concerned by these changes.
|
||||
- Better forward search (thanks Jose Alliste)
|
||||
- Support for LuaTeX convention of './' file prefixing now for everyone, not only for Windows
|
||||
1.17: Fri Oct 14 08:15:16 UTC 2011
|
||||
This concerns the synctex command line tool and 3rd party developers.
|
||||
TeX and friends are not concerned by these changes.
|
||||
- synctex_parser.c: cosmetic changes to enhance code readability
|
||||
- Better forward synchronization.
|
||||
The problem occurs for example with LaTeX \item command.
|
||||
The fact is that this command creates nodes at parse time but these nodes are used only
|
||||
after the text material of the \item is displayed on the page. The consequence is that sometimes,
|
||||
forward synchronization spots an irrelevant point from the point of view of the editing process.
|
||||
This was due to some very basic filtering policy, where a somehow arbitrary choice was made when
|
||||
many different possibilities where offered for synchronisation.
|
||||
Now, forward synchronization prefers nodes inside an hbox with as many acceptable spots as possible.
|
||||
This is achieved with the notion of mean line and node weight.
|
||||
- Adding support for the new file naming convention with './'
|
||||
+ function synctex_ignore_leading_dot_slash_in_path replaces synctex_ignore_leading_dot_slash
|
||||
+ function _synctex_is_equivalent_file_name is more permissive
|
||||
Previously, the function synctex_scanner_get_tag would give an answer only when
|
||||
the given file name was EXACTLY one of the file names listed in the synctex file.
|
||||
The we added some changes accepting for example 'foo.tex' instead of './foo.tex'.
|
||||
Now we have an even looser policy for dealing with file names.
|
||||
If the given file name does not match exactly one the file names of the synctex file,
|
||||
then we try to match the base names. If there is only one match of the base names,
|
||||
then it is taken as a match for the whole names.
|
||||
The base name is defined as following:
|
||||
./foo => foo
|
||||
/my///.////foo => foo
|
||||
/foo => /foo
|
||||
/my//.foo => /my//.foo
|
||||
1.17: Tue Mar 13 10:10:03 UTC 2012
|
||||
- minor changes, no version changes
|
||||
- syntax man pages are fixed as suggested by M. Shimata
|
||||
see mail to tex-live@tug.org titled "syntax.5 has many warnings from groff" and "syntax.1 use invalid macro for mdoc"
|
||||
1.17: Tue Jan 14 09:55:00 UTC 2014
|
||||
- fixed a segfault, from Sebastian Ramacher
|
||||
1.17: Mon Aug 04
|
||||
- fixed a memory leak
|
||||
1.18: Thu Jun 25 11:36:05 UTC 2015
|
||||
- nested sheets now fully supported (does it make sense in TeX)
|
||||
- cosmetic changes: uniform indentation
|
||||
- suppression of warnings, mainly long/int ones. In short, zlib likes ints when size_t likes longs.
|
||||
- CLI synctex tool can build out of TeXLive (modulo appropriate options passed to the compiler)
|
||||
|
||||
Acknowledgments:
|
||||
----------------
|
||||
The author received useful remarks from the pdfTeX developers, especially Hahn The Thanh,
|
||||
and significant help from XeTeX developer Jonathan Kew
|
||||
|
||||
Nota Bene:
|
||||
----------
|
||||
If you include or use a significant part of the synctex package into a software,
|
||||
I would appreciate to be listed as contributor and see "SyncTeX" highlighted.
|
||||
|
||||
Copyright (c) 2008-2014 jerome DOT laurens AT u-bourgogne DOT fr
|
||||
|
||||
512
elpa/pdf-tools-20180428.827/build/server/synctex_parser_utils.c
Normal file
512
elpa/pdf-tools-20180428.827/build/server/synctex_parser_utils.c
Normal file
@@ -0,0 +1,512 @@
|
||||
/*
|
||||
Copyright (c) 2008, 2009, 2010 , 2011 jerome DOT laurens AT u-bourgogne DOT fr
|
||||
|
||||
This file is part of the SyncTeX package.
|
||||
|
||||
Latest Revision: Tue Jun 14 08:23:30 UTC 2011
|
||||
|
||||
Version: 1.18
|
||||
|
||||
See synctex_parser_readme.txt for more details
|
||||
|
||||
License:
|
||||
--------
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
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
|
||||
authorization from the copyright holder.
|
||||
|
||||
*/
|
||||
|
||||
/* In this file, we find all the functions that may depend on the operating system. */
|
||||
|
||||
#include <synctex_parser_utils.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <limits.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
#if defined(_WIN32) || defined(__WIN32__) || defined(__TOS_WIN__) || defined(__WINDOWS__)
|
||||
#define SYNCTEX_WINDOWS 1
|
||||
#endif
|
||||
|
||||
#if defined(__OS2__)
|
||||
#define SYNCTEX_OS2 1
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32_WINNT_WINXP
|
||||
#define SYNCTEX_RECENT_WINDOWS 1
|
||||
#endif
|
||||
|
||||
#ifdef SYNCTEX_WINDOWS
|
||||
#include <windows.h>
|
||||
#include <shlwapi.h> /* Use shlwapi.lib */
|
||||
#endif
|
||||
|
||||
void *_synctex_malloc(size_t size) {
|
||||
void * ptr = malloc(size);
|
||||
if(ptr) {
|
||||
/* There used to be a switch to use bzero because it is more secure. JL */
|
||||
memset(ptr,0, size);
|
||||
}
|
||||
return (void *)ptr;
|
||||
}
|
||||
|
||||
int _synctex_error(const char * reason,...) {
|
||||
va_list arg;
|
||||
int result;
|
||||
va_start (arg, reason);
|
||||
# ifdef SYNCTEX_RECENT_WINDOWS
|
||||
{/* This code is contributed by William Blum.
|
||||
As it does not work on some older computers,
|
||||
the _WIN32 conditional here is replaced with a SYNCTEX_RECENT_WINDOWS one.
|
||||
According to http://msdn.microsoft.com/en-us/library/aa363362(VS.85).aspx
|
||||
Minimum supported client Windows 2000 Professional
|
||||
Minimum supported server Windows 2000 Server
|
||||
People running Windows 2K standard edition will not have OutputDebugStringA.
|
||||
JL.*/
|
||||
char *buff;
|
||||
size_t len;
|
||||
OutputDebugStringA("SyncTeX ERROR: ");
|
||||
len = _vscprintf(reason, arg) + 1;
|
||||
buff = (char*)malloc( len * sizeof(char) );
|
||||
result = vsprintf(buff, reason, arg) +strlen("SyncTeX ERROR: ");
|
||||
OutputDebugStringA(buff);
|
||||
OutputDebugStringA("\n");
|
||||
free(buff);
|
||||
}
|
||||
# else
|
||||
result = fprintf(stderr,"SyncTeX ERROR: ");
|
||||
result += vfprintf(stderr, reason, arg);
|
||||
result += fprintf(stderr,"\n");
|
||||
# endif
|
||||
va_end (arg);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* strip the last extension of the given string, this string is modified! */
|
||||
void _synctex_strip_last_path_extension(char * string) {
|
||||
if(NULL != string){
|
||||
char * last_component = NULL;
|
||||
char * last_extension = NULL;
|
||||
# if defined(SYNCTEX_WINDOWS)
|
||||
last_component = PathFindFileName(string);
|
||||
last_extension = PathFindExtension(string);
|
||||
if(last_extension == NULL)return;
|
||||
if(last_component == NULL)last_component = string;
|
||||
if(last_extension>last_component){/* filter out paths like "my/dir/.hidden" */
|
||||
last_extension[0] = '\0';
|
||||
}
|
||||
# else
|
||||
char * next = NULL;
|
||||
/* first we find the last path component */
|
||||
if(NULL == (last_component = strstr(string,"/"))){
|
||||
last_component = string;
|
||||
} else {
|
||||
++last_component;
|
||||
while((next = strstr(last_component,"/"))){
|
||||
last_component = next+1;
|
||||
}
|
||||
}
|
||||
# if defined(SYNCTEX_OS2)
|
||||
/* On OS2, the '\' is also a path separator. */
|
||||
while((next = strstr(last_component,"\\"))){
|
||||
last_component = next+1;
|
||||
}
|
||||
# endif /* SYNCTEX_OS2 */
|
||||
/* then we find the last path extension */
|
||||
if((last_extension = strstr(last_component,"."))){
|
||||
++last_extension;
|
||||
while((next = strstr(last_extension,"."))){
|
||||
last_extension = next+1;
|
||||
}
|
||||
--last_extension;/* back to the "." */
|
||||
if(last_extension>last_component){/* filter out paths like ....my/dir/.hidden"*/
|
||||
last_extension[0] = '\0';
|
||||
}
|
||||
}
|
||||
# endif /* SYNCTEX_WINDOWS */
|
||||
}
|
||||
}
|
||||
|
||||
synctex_bool_t synctex_ignore_leading_dot_slash_in_path(const char ** name_ref)
|
||||
{
|
||||
if (SYNCTEX_IS_DOT((*name_ref)[0]) && SYNCTEX_IS_PATH_SEPARATOR((*name_ref)[1])) {
|
||||
do {
|
||||
(*name_ref) += 2;
|
||||
while (SYNCTEX_IS_PATH_SEPARATOR((*name_ref)[0])) {
|
||||
++(*name_ref);
|
||||
}
|
||||
} while(SYNCTEX_IS_DOT((*name_ref)[0]) && SYNCTEX_IS_PATH_SEPARATOR((*name_ref)[1]));
|
||||
return synctex_YES;
|
||||
}
|
||||
return synctex_NO;
|
||||
}
|
||||
|
||||
/* The base name is necessary to deal with the 2011 file naming convention...
|
||||
* path is a '\0' terminated string
|
||||
* The return value is the trailing part of the argument,
|
||||
* just following the first occurrence of the regexp pattern "[^|/|\].[\|/]+".*/
|
||||
const char * _synctex_base_name(const char *path) {
|
||||
const char * ptr = path;
|
||||
do {
|
||||
if (synctex_ignore_leading_dot_slash_in_path(&ptr)) {
|
||||
return ptr;
|
||||
}
|
||||
do {
|
||||
if (!*(++ptr)) {
|
||||
return path;
|
||||
}
|
||||
} while (!SYNCTEX_IS_PATH_SEPARATOR(*ptr));
|
||||
} while (*(++ptr));
|
||||
return path;
|
||||
}
|
||||
|
||||
/* Compare two file names, windows is sometimes case insensitive... */
|
||||
synctex_bool_t _synctex_is_equivalent_file_name(const char *lhs, const char *rhs) {
|
||||
/* Remove the leading regex '(\./+)*' in both rhs and lhs */
|
||||
synctex_ignore_leading_dot_slash_in_path(&lhs);
|
||||
synctex_ignore_leading_dot_slash_in_path(&rhs);
|
||||
next_character:
|
||||
if (SYNCTEX_IS_PATH_SEPARATOR(*lhs)) {/* lhs points to a path separator */
|
||||
if (!SYNCTEX_IS_PATH_SEPARATOR(*rhs)) {/* but not rhs */
|
||||
return synctex_NO;
|
||||
}
|
||||
++lhs;
|
||||
++rhs;
|
||||
synctex_ignore_leading_dot_slash_in_path(&lhs);
|
||||
synctex_ignore_leading_dot_slash_in_path(&rhs);
|
||||
goto next_character;
|
||||
} else if (SYNCTEX_IS_PATH_SEPARATOR(*rhs)) {/* rhs points to a path separator but not lhs */
|
||||
return synctex_NO;
|
||||
} else if (SYNCTEX_ARE_PATH_CHARACTERS_EQUAL(*lhs,*rhs)){/* uppercase do not match */
|
||||
return synctex_NO;
|
||||
} else if (!*lhs) {/* lhs is at the end of the string */
|
||||
return *rhs ? synctex_NO : synctex_YES;
|
||||
} else if(!*rhs) {/* rhs is at the end of the string but not lhs */
|
||||
return synctex_NO;
|
||||
}
|
||||
++lhs;
|
||||
++rhs;
|
||||
goto next_character;
|
||||
}
|
||||
|
||||
synctex_bool_t _synctex_path_is_absolute(const char * name) {
|
||||
if(!strlen(name)) {
|
||||
return synctex_NO;
|
||||
}
|
||||
# if defined(SYNCTEX_WINDOWS) || defined(SYNCTEX_OS2)
|
||||
if(strlen(name)>2) {
|
||||
return (name[1]==':' && SYNCTEX_IS_PATH_SEPARATOR(name[2]))?synctex_YES:synctex_NO;
|
||||
}
|
||||
return synctex_NO;
|
||||
# else
|
||||
return SYNCTEX_IS_PATH_SEPARATOR(name[0])?synctex_YES:synctex_NO;
|
||||
# endif
|
||||
}
|
||||
|
||||
/* We do not take care of UTF-8 */
|
||||
const char * _synctex_last_path_component(const char * name) {
|
||||
const char * c = name+strlen(name);
|
||||
if(c>name) {
|
||||
if(!SYNCTEX_IS_PATH_SEPARATOR(*c)) {
|
||||
do {
|
||||
--c;
|
||||
if(SYNCTEX_IS_PATH_SEPARATOR(*c)) {
|
||||
return c+1;
|
||||
}
|
||||
} while(c>name);
|
||||
}
|
||||
return c;/* the last path component is the void string*/
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
int _synctex_copy_with_quoting_last_path_component(const char * src, char ** dest_ref, size_t size) {
|
||||
const char * lpc;
|
||||
if(src && dest_ref) {
|
||||
# define dest (*dest_ref)
|
||||
dest = NULL; /* Default behavior: no change and sucess. */
|
||||
lpc = _synctex_last_path_component(src);
|
||||
if(strlen(lpc)) {
|
||||
if(strchr(lpc,' ') && lpc[0]!='"' && lpc[strlen(lpc)-1]!='"') {
|
||||
/* We are in the situation where adding the quotes is allowed. */
|
||||
/* Time to add the quotes. */
|
||||
/* Consistency test: we must have dest+size>dest+strlen(dest)+2
|
||||
* or equivalently: strlen(dest)+2<size (see below) */
|
||||
if(strlen(src)<size) {
|
||||
if((dest = (char *)malloc(size+2))) {
|
||||
char * dpc = dest + (lpc-src); /* dpc is the last path component of dest. */
|
||||
if(dest != strncpy(dest,src,size)) {
|
||||
_synctex_error("! _synctex_copy_with_quoting_last_path_component: Copy problem");
|
||||
free(dest);
|
||||
dest = NULL;/* Don't forget to reinitialize. */
|
||||
return -2;
|
||||
}
|
||||
memmove(dpc+1,dpc,strlen(dpc)+1); /* Also move the null terminating character. */
|
||||
dpc[0]='"';
|
||||
dpc[strlen(dpc)+1]='\0';/* Consistency test */
|
||||
dpc[strlen(dpc)]='"';
|
||||
return 0; /* Success. */
|
||||
}
|
||||
return -1; /* Memory allocation error. */
|
||||
}
|
||||
_synctex_error("! _synctex_copy_with_quoting_last_path_component: Internal inconsistency");
|
||||
return -3;
|
||||
}
|
||||
return 0; /* Success. */
|
||||
}
|
||||
return 0; /* No last path component. */
|
||||
# undef dest
|
||||
}
|
||||
return 1; /* Bad parameter, this value is subject to changes. */
|
||||
}
|
||||
|
||||
/* The client is responsible of the management of the returned string, if any. */
|
||||
char * _synctex_merge_strings(const char * first,...);
|
||||
|
||||
char * _synctex_merge_strings(const char * first,...) {
|
||||
va_list arg;
|
||||
size_t size = 0;
|
||||
const char * temp;
|
||||
/* First retrieve the size necessary to store the merged string */
|
||||
va_start (arg, first);
|
||||
temp = first;
|
||||
do {
|
||||
size_t len = strlen(temp);
|
||||
if(UINT_MAX-len<size) {
|
||||
_synctex_error("! _synctex_merge_strings: Capacity exceeded.");
|
||||
return NULL;
|
||||
}
|
||||
size+=len;
|
||||
} while( (temp = va_arg(arg, const char *)) != NULL);
|
||||
va_end(arg);
|
||||
if(size>0) {
|
||||
char * result = NULL;
|
||||
++size;
|
||||
/* Create the memory storage */
|
||||
if(NULL!=(result = (char *)malloc(size))) {
|
||||
char * dest = result;
|
||||
va_start (arg, first);
|
||||
temp = first;
|
||||
do {
|
||||
if((size = strlen(temp))>0) {
|
||||
/* There is something to merge */
|
||||
if(dest != strncpy(dest,temp,size)) {
|
||||
_synctex_error("! _synctex_merge_strings: Copy problem");
|
||||
free(result);
|
||||
result = NULL;
|
||||
return NULL;
|
||||
}
|
||||
dest += size;
|
||||
}
|
||||
} while( (temp = va_arg(arg, const char *)) != NULL);
|
||||
va_end(arg);
|
||||
dest[0]='\0';/* Terminate the merged string */
|
||||
return result;
|
||||
}
|
||||
_synctex_error("! _synctex_merge_strings: Memory problem");
|
||||
return NULL;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* The purpose of _synctex_get_name is to find the name of the synctex file.
|
||||
* There is a list of possible filenames from which we return the most recent one and try to remove all the others.
|
||||
* With two runs of pdftex or xetex we are sure the the synctex file is really the most appropriate.
|
||||
*/
|
||||
int _synctex_get_name(const char * output, const char * build_directory, char ** synctex_name_ref, synctex_io_mode_t * io_mode_ref)
|
||||
{
|
||||
if(output && synctex_name_ref && io_mode_ref) {
|
||||
/* If output is already absolute, we just have to manage the quotes and the compress mode */
|
||||
size_t size = 0;
|
||||
char * synctex_name = NULL;
|
||||
synctex_io_mode_t io_mode = *io_mode_ref;
|
||||
const char * base_name = _synctex_last_path_component(output); /* do not free, output is the owner. base name of output*/
|
||||
/* Do we have a real base name ? */
|
||||
if(strlen(base_name)>0) {
|
||||
/* Yes, we do. */
|
||||
const char * temp = NULL;
|
||||
char * core_name = NULL; /* base name of output without path extension. */
|
||||
char * dir_name = NULL; /* dir name of output */
|
||||
char * quoted_core_name = NULL;
|
||||
char * basic_name = NULL;
|
||||
char * gz_name = NULL;
|
||||
char * quoted_name = NULL;
|
||||
char * quoted_gz_name = NULL;
|
||||
char * build_name = NULL;
|
||||
char * build_gz_name = NULL;
|
||||
char * build_quoted_name = NULL;
|
||||
char * build_quoted_gz_name = NULL;
|
||||
struct stat buf;
|
||||
time_t the_time = 0;
|
||||
/* Create core_name: let temp point to the dot before the path extension of base_name;
|
||||
* We start form the \0 terminating character and scan the string upward until we find a dot.
|
||||
* The leading dot is not accepted. */
|
||||
if((temp = strrchr(base_name,'.')) && (size = temp - base_name)>0) {
|
||||
/* There is a dot and it is not at the leading position */
|
||||
if(NULL == (core_name = (char *)malloc(size+1))) {
|
||||
_synctex_error("! _synctex_get_name: Memory problem 1");
|
||||
return -1;
|
||||
}
|
||||
if(core_name != strncpy(core_name,base_name,size)) {
|
||||
_synctex_error("! _synctex_get_name: Copy problem 1");
|
||||
free(core_name);
|
||||
dir_name = NULL;
|
||||
return -2;
|
||||
}
|
||||
core_name[size] = '\0';
|
||||
} else {
|
||||
/* There is no path extension,
|
||||
* Just make a copy of base_name */
|
||||
core_name = _synctex_merge_strings(base_name);
|
||||
}
|
||||
/* core_name is properly set up, owned by "self". */
|
||||
/* creating dir_name. */
|
||||
size = strlen(output)-strlen(base_name);
|
||||
if(size>0) {
|
||||
/* output contains more than one path component */
|
||||
if(NULL == (dir_name = (char *)malloc(size+1))) {
|
||||
_synctex_error("! _synctex_get_name: Memory problem");
|
||||
free(core_name);
|
||||
dir_name = NULL;
|
||||
return -1;
|
||||
}
|
||||
if(dir_name != strncpy(dir_name,output,size)) {
|
||||
_synctex_error("! _synctex_get_name: Copy problem");
|
||||
free(dir_name);
|
||||
dir_name = NULL;
|
||||
free(core_name);
|
||||
dir_name = NULL;
|
||||
return -2;
|
||||
}
|
||||
dir_name[size] = '\0';
|
||||
}
|
||||
/* dir_name is properly set up. It ends with a path separator, if non void. */
|
||||
/* creating quoted_core_name. */
|
||||
if(strchr(core_name,' ')) {
|
||||
quoted_core_name = _synctex_merge_strings("\"",core_name,"\"");
|
||||
}
|
||||
/* quoted_core_name is properly set up. */
|
||||
if(dir_name &&strlen(dir_name)>0) {
|
||||
basic_name = _synctex_merge_strings(dir_name,core_name,synctex_suffix,NULL);
|
||||
if(quoted_core_name && strlen(quoted_core_name)>0) {
|
||||
quoted_name = _synctex_merge_strings(dir_name,quoted_core_name,synctex_suffix,NULL);
|
||||
}
|
||||
} else {
|
||||
basic_name = _synctex_merge_strings(core_name,synctex_suffix,NULL);
|
||||
if(quoted_core_name && strlen(quoted_core_name)>0) {
|
||||
quoted_name = _synctex_merge_strings(quoted_core_name,synctex_suffix,NULL);
|
||||
}
|
||||
}
|
||||
if(!_synctex_path_is_absolute(output) && build_directory && (size = strlen(build_directory))) {
|
||||
temp = build_directory + size - 1;
|
||||
if(_synctex_path_is_absolute(temp)) {
|
||||
build_name = _synctex_merge_strings(build_directory,basic_name,NULL);
|
||||
if(quoted_core_name && strlen(quoted_core_name)>0) {
|
||||
build_quoted_name = _synctex_merge_strings(build_directory,quoted_name,NULL);
|
||||
}
|
||||
} else {
|
||||
build_name = _synctex_merge_strings(build_directory,"/",basic_name,NULL);
|
||||
if(quoted_core_name && strlen(quoted_core_name)>0) {
|
||||
build_quoted_name = _synctex_merge_strings(build_directory,"/",quoted_name,NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(basic_name) {
|
||||
gz_name = _synctex_merge_strings(basic_name,synctex_suffix_gz,NULL);
|
||||
}
|
||||
if(quoted_name) {
|
||||
quoted_gz_name = _synctex_merge_strings(quoted_name,synctex_suffix_gz,NULL);
|
||||
}
|
||||
if(build_name) {
|
||||
build_gz_name = _synctex_merge_strings(build_name,synctex_suffix_gz,NULL);
|
||||
}
|
||||
if(build_quoted_name) {
|
||||
build_quoted_gz_name = _synctex_merge_strings(build_quoted_name,synctex_suffix_gz,NULL);
|
||||
}
|
||||
/* All the others names are properly set up... */
|
||||
/* retain the most recently modified file */
|
||||
# define TEST(FILENAME,COMPRESS_MODE) \
|
||||
if(FILENAME) {\
|
||||
if (stat(FILENAME, &buf)) { \
|
||||
free(FILENAME);\
|
||||
FILENAME = NULL;\
|
||||
} else if (buf.st_mtime>the_time) { \
|
||||
the_time=buf.st_mtime; \
|
||||
synctex_name = FILENAME; \
|
||||
if (COMPRESS_MODE) { \
|
||||
io_mode |= synctex_io_gz_mask; \
|
||||
} else { \
|
||||
io_mode &= ~synctex_io_gz_mask; \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
TEST(basic_name,synctex_DONT_COMPRESS);
|
||||
TEST(gz_name,synctex_COMPRESS);
|
||||
TEST(quoted_name,synctex_DONT_COMPRESS);
|
||||
TEST(quoted_gz_name,synctex_COMPRESS);
|
||||
TEST(build_name,synctex_DONT_COMPRESS);
|
||||
TEST(build_gz_name,synctex_COMPRESS);
|
||||
TEST(build_quoted_name,synctex_DONT_COMPRESS);
|
||||
TEST(build_quoted_gz_name,synctex_COMPRESS);
|
||||
# undef TEST
|
||||
/* Free all the intermediate filenames, except the one that will be used as returned value. */
|
||||
# define CLEAN_AND_REMOVE(FILENAME) \
|
||||
if(FILENAME && (FILENAME!=synctex_name)) {\
|
||||
remove(FILENAME);\
|
||||
printf("synctex tool info: %s removed\n",FILENAME);\
|
||||
free(FILENAME);\
|
||||
FILENAME = NULL;\
|
||||
}
|
||||
CLEAN_AND_REMOVE(basic_name);
|
||||
CLEAN_AND_REMOVE(gz_name);
|
||||
CLEAN_AND_REMOVE(quoted_name);
|
||||
CLEAN_AND_REMOVE(quoted_gz_name);
|
||||
CLEAN_AND_REMOVE(build_name);
|
||||
CLEAN_AND_REMOVE(build_gz_name);
|
||||
CLEAN_AND_REMOVE(build_quoted_name);
|
||||
CLEAN_AND_REMOVE(build_quoted_gz_name);
|
||||
# undef CLEAN_AND_REMOVE
|
||||
/* set up the returned values */
|
||||
* synctex_name_ref = synctex_name;
|
||||
* io_mode_ref = io_mode;
|
||||
return 0;
|
||||
}
|
||||
return -1;/* bad argument */
|
||||
}
|
||||
return -2;
|
||||
}
|
||||
|
||||
const char * _synctex_get_io_mode_name(synctex_io_mode_t io_mode) {
|
||||
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];
|
||||
}
|
||||
152
elpa/pdf-tools-20180428.827/build/server/synctex_parser_utils.h
Normal file
152
elpa/pdf-tools-20180428.827/build/server/synctex_parser_utils.h
Normal file
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
Copyright (c) 2008, 2009, 2010, 2011 jerome DOT laurens AT u-bourgogne DOT fr
|
||||
|
||||
This file is part of the SyncTeX package.
|
||||
|
||||
Latest Revision: Tue Jun 14 08:23:30 UTC 2011
|
||||
|
||||
Version: 1.18
|
||||
|
||||
See synctex_parser_readme.txt for more details
|
||||
|
||||
License:
|
||||
--------
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
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
|
||||
authorization from the copyright holder.
|
||||
|
||||
*/
|
||||
|
||||
/* The utilities declared here are subject to conditional implementation.
|
||||
* All the operating system special stuff goes here.
|
||||
* The problem mainly comes from file name management: path separator, encoding...
|
||||
*/
|
||||
|
||||
# define synctex_bool_t int
|
||||
# define synctex_YES -1
|
||||
# define synctex_ADD_QUOTES -1
|
||||
# define synctex_COMPRESS -1
|
||||
# define synctex_NO 0
|
||||
# define synctex_DONT_ADD_QUOTES 0
|
||||
# define synctex_DONT_COMPRESS 0
|
||||
|
||||
#ifndef __SYNCTEX_PARSER_UTILS__
|
||||
# define __SYNCTEX_PARSER_UTILS__
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
# if defined(_WIN32) || defined(__OS2__)
|
||||
# define SYNCTEX_CASE_SENSITIVE_PATH 0
|
||||
# define SYNCTEX_IS_PATH_SEPARATOR(c) ('/' == c || '\\' == c)
|
||||
# else
|
||||
# define SYNCTEX_CASE_SENSITIVE_PATH 1
|
||||
# define SYNCTEX_IS_PATH_SEPARATOR(c) ('/' == c)
|
||||
# endif
|
||||
|
||||
# if defined(_WIN32) || defined(__OS2__)
|
||||
# define SYNCTEX_IS_DOT(c) ('.' == c)
|
||||
# else
|
||||
# define SYNCTEX_IS_DOT(c) ('.' == c)
|
||||
# endif
|
||||
|
||||
# if SYNCTEX_CASE_SENSITIVE_PATH
|
||||
# define SYNCTEX_ARE_PATH_CHARACTERS_EQUAL(left,right) (left != right)
|
||||
# else
|
||||
# define SYNCTEX_ARE_PATH_CHARACTERS_EQUAL(left,right) (toupper(left) != toupper(right))
|
||||
# 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);
|
||||
|
||||
/* This is used to log some informational message to the standard error stream.
|
||||
* On Windows, the stderr stream is not exposed and another method is used.
|
||||
* The return value is the number of characters printed. */
|
||||
int _synctex_error(const char * reason,...);
|
||||
|
||||
/* strip the last extension of the given string, this string is modified!
|
||||
* This function depends on the OS because the path separator may differ.
|
||||
* This should be discussed more precisely. */
|
||||
void _synctex_strip_last_path_extension(char * string);
|
||||
|
||||
/* Compare two file names, windows is sometimes case insensitive...
|
||||
* The given strings may differ stricto sensu, but represent the same file name.
|
||||
* It might not be the real way of doing things.
|
||||
* The return value is an undefined non 0 value when the two file names are equivalent.
|
||||
* It is 0 otherwise. */
|
||||
synctex_bool_t _synctex_is_equivalent_file_name(const char *lhs, const char *rhs);
|
||||
|
||||
/* Description forthcoming.*/
|
||||
synctex_bool_t _synctex_path_is_absolute(const char * name);
|
||||
|
||||
/* Description forthcoming...*/
|
||||
const char * _synctex_last_path_component(const char * name);
|
||||
|
||||
/* Description forthcoming...*/
|
||||
const char * _synctex_base_name(const char *path);
|
||||
|
||||
/* If the core of the last path component of src is not already enclosed with double quotes ('"')
|
||||
* and contains a space character (' '), then a new buffer is created, the src is copied and quotes are added.
|
||||
* In all other cases, no destination buffer is created and the src is not copied.
|
||||
* 0 on success, which means no error, something non 0 means error, mainly due to memory allocation failure, or bad parameter.
|
||||
* This is used to fix a bug in the first version of pdftex with synctex (1.40.9) for which names with spaces
|
||||
* were not managed in a standard way.
|
||||
* On success, the caller owns the buffer pointed to by dest_ref (is any) and
|
||||
* is responsible of freeing the memory when done.
|
||||
* The size argument is the size of the src buffer. On return the dest_ref points to a buffer sized size+2.*/
|
||||
int _synctex_copy_with_quoting_last_path_component(const char * src, char ** dest_ref, size_t size);
|
||||
|
||||
/* These are the possible extensions of the synctex file */
|
||||
extern const char * synctex_suffix;
|
||||
extern const char * synctex_suffix_gz;
|
||||
|
||||
typedef unsigned int synctex_io_mode_t;
|
||||
|
||||
typedef enum {
|
||||
synctex_io_append_mask = 1,
|
||||
synctex_io_gz_mask = synctex_io_append_mask<<1
|
||||
} synctex_io_mode_masks_t;
|
||||
|
||||
typedef enum {
|
||||
synctex_compress_mode_none = 0,
|
||||
synctex_compress_mode_gz = 1
|
||||
} synctex_compress_mode_t;
|
||||
|
||||
int _synctex_get_name(const char * output, const char * build_directory, char ** synctex_name_ref, synctex_io_mode_t * io_mode_ref);
|
||||
|
||||
/* returns the correct mode required by fopen and gzopen from the given io_mode */
|
||||
const char * _synctex_get_io_mode_name(synctex_io_mode_t io_mode);
|
||||
|
||||
synctex_bool_t synctex_ignore_leading_dot_slash_in_path(const char ** name);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1 @@
|
||||
1.18
|
||||
2
elpa/pdf-tools-20180428.827/build/server/test/docker/.gitignore
vendored
Normal file
2
elpa/pdf-tools-20180428.827/build/server/test/docker/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
*.Dockerfile
|
||||
*.build
|
||||
9
elpa/pdf-tools-20180428.827/build/server/test/docker/lib/run-tests
Executable file
9
elpa/pdf-tools-20180428.827/build/server/test/docker/lib/run-tests
Executable file
@@ -0,0 +1,9 @@
|
||||
#!/bin/sh
|
||||
|
||||
PATH="$(dirname "$0")":$PATH
|
||||
|
||||
set -e
|
||||
|
||||
yes-or-enter | ./autobuild -i /bin
|
||||
yes-or-enter | ./autobuild -i /usr/bin | \
|
||||
grep -q "Skipping package installation (already installed)"
|
||||
9
elpa/pdf-tools-20180428.827/build/server/test/docker/lib/yes-or-enter
Executable file
9
elpa/pdf-tools-20180428.827/build/server/test/docker/lib/yes-or-enter
Executable file
@@ -0,0 +1,9 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Step over prompts from the package-manager.
|
||||
if [ -f /etc/arch-release ]; then
|
||||
yes ''
|
||||
else
|
||||
yes
|
||||
fi
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
ADD . /epdfinfo
|
||||
WORKDIR /epdfinfo
|
||||
RUN make -s distclean || true
|
||||
CMD ["sh", "./test/docker/lib/run-tests"]
|
||||
@@ -0,0 +1,6 @@
|
||||
# -*- dockerfile -*-
|
||||
FROM base/archlinux
|
||||
RUN pacman -Syu --noconfirm --noprogressbar && \
|
||||
pacman -S --noconfirm --noprogressbar poppler-glib base-devel
|
||||
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
# -*- dockerfile -*-
|
||||
FROM centos:7
|
||||
RUN yum update -y && yum install -y gcc gcc-c++ poppler-glib-devel
|
||||
@@ -0,0 +1,4 @@
|
||||
# -*- dockerfile -*-
|
||||
FROM debian:8
|
||||
RUN apt-get update -y && apt-get install -y gcc g++ libpoppler-glib-dev
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
# -*- dockerfile -*-
|
||||
FROM debian:9
|
||||
RUN apt-get update -y && apt-get install -y gcc g++ libpoppler-glib-dev
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
# -*- dockerfile -*-
|
||||
FROM fedora:24
|
||||
RUN dnf update -y && dnf install -y gcc gcc-c++ poppler-glib-devel
|
||||
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
# -*- dockerfile -*-
|
||||
FROM fedora:25
|
||||
RUN dnf update -y && dnf install -y gcc gcc-c++ poppler-glib-devel
|
||||
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
# -*- dockerfile -*-
|
||||
FROM fedora:26
|
||||
RUN dnf update -y && dnf install -y gcc gcc-c++ poppler-glib-devel
|
||||
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
# -*- dockerfile -*-
|
||||
FROM gentoo/stage3-amd64
|
||||
RUN emerge --sync && emerge sys-devel/gcc app-text/poppler
|
||||
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
# -*- dockerfile -*-
|
||||
FROM ubuntu:trusty
|
||||
RUN apt-get update -y && apt-get install -y gcc g++ libpoppler-glib-dev
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
# -*- dockerfile -*-
|
||||
FROM ubuntu:xenial
|
||||
RUN apt-get update -y && apt-get install -y gcc g++ libpoppler-glib-dev
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
# -*- dockerfile -*-
|
||||
FROM ubuntu:artful
|
||||
RUN apt-get update -y && apt-get install -y gcc g++ libpoppler-glib-dev
|
||||
|
||||
1657
elpa/pdf-tools-20180428.827/pdf-annot.el
Normal file
1657
elpa/pdf-tools-20180428.827/pdf-annot.el
Normal file
File diff suppressed because it is too large
Load Diff
461
elpa/pdf-tools-20180428.827/pdf-cache.el
Normal file
461
elpa/pdf-tools-20180428.827/pdf-cache.el
Normal file
@@ -0,0 +1,461 @@
|
||||
;;; pdf-cache.el --- Cache time-critical or frequent epdfinfo queries. -*- lexical-binding:t -*-
|
||||
|
||||
;; Copyright (C) 2013 Andreas Politz
|
||||
|
||||
;; Author: Andreas Politz <politza@fh-trier.de>
|
||||
;; Keywords: files, doc-view, pdf
|
||||
|
||||
;; 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:
|
||||
;;
|
||||
;;; Code:
|
||||
;;
|
||||
|
||||
(require 'pdf-info)
|
||||
(require 'pdf-util)
|
||||
|
||||
|
||||
;; * ================================================================== *
|
||||
;; * Customiazations
|
||||
;; * ================================================================== *
|
||||
|
||||
(defcustom pdf-cache-image-limit 64
|
||||
"Maximum number of cached PNG images per buffer."
|
||||
:type 'integer
|
||||
:group 'pdf-cache
|
||||
:group 'pdf-view)
|
||||
|
||||
(defcustom pdf-cache-prefetch-delay 0.5
|
||||
"Idle time in seconds before prefetching images starts."
|
||||
:group 'pdf-view
|
||||
:type 'number)
|
||||
|
||||
(defcustom pdf-cache-prefetch-pages-function
|
||||
'pdf-cache-prefetch-pages-function-default
|
||||
"A function returning a list of pages to be prefetched.
|
||||
|
||||
It is called with no arguments in the PDF window and should
|
||||
return a list of page-numbers, determining the pages that should
|
||||
be prefetched and their order."
|
||||
:group 'pdf-view
|
||||
:type 'function)
|
||||
|
||||
|
||||
;; * ================================================================== *
|
||||
;; * Simple Value cache
|
||||
;; * ================================================================== *
|
||||
|
||||
(defvar-local pdf-cache--data nil)
|
||||
|
||||
(defvar pdf-annot-modified-functions)
|
||||
|
||||
(defun pdf-cache--initialize ()
|
||||
(unless pdf-cache--data
|
||||
(setq pdf-cache--data (make-hash-table))
|
||||
(add-hook 'pdf-info-close-document-hook 'pdf-cache-clear-data nil t)
|
||||
(add-hook 'pdf-annot-modified-functions
|
||||
'pdf-cache--clear-data-of-annotations
|
||||
nil t)))
|
||||
|
||||
(defun pdf-cache--clear-data-of-annotations (fn)
|
||||
(apply 'pdf-cache-clear-data-of-pages
|
||||
(mapcar (lambda (a)
|
||||
(cdr (assq 'page a)))
|
||||
(funcall fn t))))
|
||||
|
||||
(defun pdf-cache--data-put (key value &optional page)
|
||||
"Put KEY with VALUE in the cache of PAGE, return value."
|
||||
(pdf-cache--initialize)
|
||||
(puthash page (cons (cons key value)
|
||||
(assq-delete-all
|
||||
key
|
||||
(gethash page pdf-cache--data)))
|
||||
pdf-cache--data)
|
||||
value)
|
||||
|
||||
(defun pdf-cache--data-get (key &optional page)
|
||||
"Get value of KEY in the cache of PAGE.
|
||||
|
||||
Returns a cons \(HIT . VALUE\), where HIT is non-nil if KEY was
|
||||
stored previously for PAGE and VALUE it's value. Otherwise HIT
|
||||
is nil and VALUE undefined."
|
||||
(pdf-cache--initialize)
|
||||
(let ((elt (assq key (gethash page pdf-cache--data))))
|
||||
(if elt
|
||||
(cons t (cdr elt))
|
||||
(cons nil nil))))
|
||||
|
||||
(defun pdf-cache--data-clear (key &optional page)
|
||||
(pdf-cache--initialize)
|
||||
(puthash page
|
||||
(assq-delete-all key (gethash page pdf-cache--data))
|
||||
pdf-cache--data)
|
||||
nil)
|
||||
|
||||
(defun pdf-cache-clear-data-of-pages (&rest pages)
|
||||
(when pdf-cache--data
|
||||
(dolist (page pages)
|
||||
(remhash page pdf-cache--data))))
|
||||
|
||||
(defun pdf-cache-clear-data ()
|
||||
(interactive)
|
||||
(when pdf-cache--data
|
||||
(clrhash pdf-cache--data)))
|
||||
|
||||
(defmacro define-pdf-cache-function (command &optional page-arg-p)
|
||||
"Define a simple data cache function.
|
||||
|
||||
COMMAND is the name of the command, e.g. number-of-pages. It
|
||||
should have a corresponding pdf-info function. If PAGE-ARG-P is
|
||||
non-nil, define a one-dimensional cache indexed by the page
|
||||
number. Otherwise the value is constant for each document, like
|
||||
e.g. number-of-pages.
|
||||
|
||||
Both args are unevaluated."
|
||||
|
||||
(let ((args (if page-arg-p (list 'page)))
|
||||
(fn (intern (format "pdf-cache-%s" command)))
|
||||
(ifn (intern (format "pdf-info-%s" command)))
|
||||
(doc (format "Cached version of `pdf-info-%s', which see.
|
||||
|
||||
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))))
|
||||
(if (car hit-value)
|
||||
(cdr hit-value)
|
||||
(pdf-cache--data-put
|
||||
',command
|
||||
,(if page-arg-p
|
||||
(list ifn 'page)
|
||||
(list ifn))
|
||||
,(if page-arg-p 'page)))))))
|
||||
|
||||
(define-pdf-cache-function pagelinks t)
|
||||
(define-pdf-cache-function number-of-pages)
|
||||
;; The boundingbox may change if annotations change.
|
||||
(define-pdf-cache-function boundingbox t)
|
||||
(define-pdf-cache-function textregions t)
|
||||
(define-pdf-cache-function pagesize t)
|
||||
|
||||
|
||||
;; * ================================================================== *
|
||||
;; * PNG image LRU cache
|
||||
;; * ================================================================== *
|
||||
|
||||
(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)
|
||||
`(list ,page ,width ,data ,hash))
|
||||
(defmacro pdf-cache--image/page (img) `(nth 0 ,img))
|
||||
(defmacro pdf-cache--image/width (img) `(nth 1 ,img))
|
||||
(defmacro pdf-cache--image/data (img) `(nth 2 ,img))
|
||||
(defmacro pdf-cache--image/hash (img) `(nth 3 ,img))
|
||||
|
||||
(defun pdf-cache--image-match (image page min-width &optional max-width hash)
|
||||
"Match IMAGE with specs.
|
||||
|
||||
IMAGE should be a list as created by `pdf-cache--make-image'.
|
||||
|
||||
Return non-nil, if IMAGE's page is the same as PAGE, it's width
|
||||
is at least MIN-WIDTH and at most MAX-WIDTH and it's stored
|
||||
hash-value is `eql' to HASH."
|
||||
(and (= (pdf-cache--image/page image)
|
||||
page)
|
||||
(or (null min-width)
|
||||
(>= (pdf-cache--image/width image)
|
||||
min-width))
|
||||
(or (null max-width)
|
||||
(<= (pdf-cache--image/width image)
|
||||
max-width))
|
||||
(eql (pdf-cache--image/hash image)
|
||||
hash)))
|
||||
|
||||
(defun pdf-cache-lookup-image (page min-width &optional max-width hash)
|
||||
"Return PAGE's cached PNG data as a string or nil.
|
||||
|
||||
Does not modify the cache. See also `pdf-cache-get-image'."
|
||||
(let ((image (car (cl-member
|
||||
(list page min-width max-width hash)
|
||||
pdf-cache--image-cache
|
||||
:test (lambda (spec image)
|
||||
(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.
|
||||
|
||||
Return an image of at least MIN-WIDTH and, if non-nil, maximum
|
||||
width MAX-WIDTH and `eql' hash value.
|
||||
|
||||
Remember that image was recently used.
|
||||
|
||||
Returns nil, if no matching image was found."
|
||||
(let ((cache (cons nil pdf-cache--image-cache))
|
||||
image)
|
||||
;; Find it in the cache and remove it. We need to find the
|
||||
;; element in front of it.
|
||||
(while (and (cdr cache)
|
||||
(not (pdf-cache--image-match
|
||||
(car (cdr cache))
|
||||
page min-width max-width hash)))
|
||||
(setq cache (cdr cache)))
|
||||
(setq image (cadr cache))
|
||||
(when (car cache)
|
||||
(setcdr cache (cddr cache)))
|
||||
;; Now push it at the front.
|
||||
(when image
|
||||
(push image pdf-cache--image-cache)
|
||||
(pdf-cache--image/data image))))
|
||||
|
||||
(defun pdf-cache-put-image (page width data &optional hash)
|
||||
"Cache image of PAGE with WIDTH, DATA and HASH.
|
||||
|
||||
DATA should the string of a PNG image of width WIDTH and from
|
||||
page PAGE in the current buffer. See `pdf-cache-get-image' for
|
||||
the HASH argument.
|
||||
|
||||
This function always returns nil."
|
||||
(unless pdf-cache--image-cache
|
||||
(add-hook 'pdf-info-close-document-hook 'pdf-cache-clear-images nil t)
|
||||
(add-hook 'pdf-annot-modified-functions
|
||||
'pdf-cache--clear-images-of-annotations nil t))
|
||||
(push (pdf-cache--make-image page width data hash)
|
||||
pdf-cache--image-cache)
|
||||
;; Forget old image(s).
|
||||
(when (> (length pdf-cache--image-cache)
|
||||
pdf-cache-image-limit)
|
||||
(if (> pdf-cache-image-limit 1)
|
||||
(setcdr (nthcdr (1- pdf-cache-image-limit)
|
||||
pdf-cache--image-cache)
|
||||
nil)
|
||||
(setq pdf-cache--image-cache nil)))
|
||||
nil)
|
||||
|
||||
(defun pdf-cache-clear-images ()
|
||||
"Clear the image cache."
|
||||
(setq pdf-cache--image-cache nil))
|
||||
|
||||
(defun pdf-cache-clear-images-if (fn)
|
||||
"Remove images from the cache according to FN.
|
||||
|
||||
FN should be function accepting 4 Arguments \(PAGE WIDTH DATA
|
||||
HASH\). It should return non-nil, if the image should be removed
|
||||
from the cache."
|
||||
(setq pdf-cache--image-cache
|
||||
(cl-remove-if
|
||||
(lambda (image)
|
||||
(funcall
|
||||
fn
|
||||
(pdf-cache--image/page image)
|
||||
(pdf-cache--image/width image)
|
||||
(pdf-cache--image/data image)
|
||||
(pdf-cache--image/hash image)))
|
||||
pdf-cache--image-cache)))
|
||||
|
||||
|
||||
(defun pdf-cache--clear-images-of-annotations (fn)
|
||||
(apply 'pdf-cache-clear-images-of-pages
|
||||
(mapcar (lambda (a)
|
||||
(cdr (assq 'page a)))
|
||||
(funcall fn t))))
|
||||
|
||||
(defun pdf-cache-clear-images-of-pages (&rest pages)
|
||||
(pdf-cache-clear-images-if
|
||||
(lambda (page &rest _) (memq page pages))))
|
||||
|
||||
(defun pdf-cache-renderpage (page min-width &optional max-width)
|
||||
"Render PAGE according to MIN-WIDTH and MAX-WIDTH.
|
||||
|
||||
Return the PNG data of an image as a string, such that it's width
|
||||
is at least MIN-WIDTH and, if non-nil, at most MAX-WIDTH.
|
||||
|
||||
If such an image is not available in the cache, call
|
||||
`pdf-info-renderpage' to create one."
|
||||
(if pdf-cache-image-inihibit
|
||||
(pdf-info-renderpage page min-width)
|
||||
(or (pdf-cache-get-image page min-width max-width)
|
||||
(let ((data (pdf-info-renderpage page min-width)))
|
||||
(pdf-cache-put-image page min-width data)
|
||||
data))))
|
||||
|
||||
(defun pdf-cache-renderpage-text-regions (page width single-line-p
|
||||
&rest selection)
|
||||
"Render PAGE according to WIDTH, SINGLE-LINE-P and SELECTION.
|
||||
|
||||
See also `pdf-info-renderpage-text-regions' and
|
||||
`pdf-cache-renderpage'."
|
||||
(if pdf-cache-image-inihibit
|
||||
(apply 'pdf-info-renderpage-text-regions
|
||||
page width single-line-p nil selection)
|
||||
(let ((hash (sxhash
|
||||
(format "%S" (cons 'renderpage-text-regions
|
||||
(cons single-line-p selection))))))
|
||||
(or (pdf-cache-get-image page width width hash)
|
||||
(let ((data (apply 'pdf-info-renderpage-text-regions
|
||||
page width single-line-p nil selection)))
|
||||
(pdf-cache-put-image page width data hash)
|
||||
data)))))
|
||||
|
||||
(defun pdf-cache-renderpage-highlight (page width &rest regions)
|
||||
"Highlight PAGE according to WIDTH and REGIONS.
|
||||
|
||||
See also `pdf-info-renderpage-highlight' and
|
||||
`pdf-cache-renderpage'."
|
||||
(if pdf-cache-image-inihibit
|
||||
(apply 'pdf-info-renderpage-highlight
|
||||
page width nil regions)
|
||||
(let ((hash (sxhash
|
||||
(format "%S" (cons 'renderpage-highlight
|
||||
regions)))))
|
||||
(or (pdf-cache-get-image page width width hash)
|
||||
(let ((data (apply 'pdf-info-renderpage-highlight
|
||||
page width nil regions)))
|
||||
(pdf-cache-put-image page width data hash)
|
||||
data)))))
|
||||
|
||||
|
||||
;; * ================================================================== *
|
||||
;; * Prefetching images
|
||||
;; * ================================================================== *
|
||||
|
||||
(defvar-local pdf-cache--prefetch-pages nil
|
||||
"Pages to be prefetched.")
|
||||
|
||||
(defvar-local pdf-cache--prefetch-timer nil
|
||||
"Timer used when prefetching images.")
|
||||
|
||||
(define-minor-mode pdf-cache-prefetch-minor-mode
|
||||
"Try to load images which will probably be needed in a while."
|
||||
nil nil t
|
||||
(pdf-cache--prefetch-cancel)
|
||||
(cond
|
||||
(pdf-cache-prefetch-minor-mode
|
||||
(pdf-util-assert-pdf-buffer)
|
||||
(add-hook 'pre-command-hook 'pdf-cache--prefetch-stop nil t)
|
||||
;; FIXME: Disable the time when the buffer is killed or it's
|
||||
;; major-mode changes.
|
||||
(setq pdf-cache--prefetch-timer
|
||||
(run-with-idle-timer (or pdf-cache-prefetch-delay 1)
|
||||
t 'pdf-cache--prefetch-start (current-buffer))))
|
||||
(t
|
||||
(remove-hook 'pre-command-hook 'pdf-cache--prefetch-stop t))))
|
||||
|
||||
(defun pdf-cache-prefetch-pages-function-default ()
|
||||
(let ((page (pdf-view-current-page)))
|
||||
(pdf-util-remove-duplicates
|
||||
(cl-remove-if-not
|
||||
(lambda (page)
|
||||
(and (>= page 1)
|
||||
(<= page (pdf-cache-number-of-pages))))
|
||||
(append
|
||||
;; +1, -1, +2, -2, ...
|
||||
(let ((sign 1)
|
||||
(incr 1))
|
||||
(mapcar (lambda (_)
|
||||
(setq page (+ page (* sign incr))
|
||||
sign (- sign)
|
||||
incr (1+ incr))
|
||||
page)
|
||||
(number-sequence 1 16)))
|
||||
;; First and last
|
||||
(list 1 (pdf-cache-number-of-pages))
|
||||
;; Links
|
||||
(mapcar
|
||||
(apply-partially 'alist-get 'page)
|
||||
(cl-remove-if-not
|
||||
(lambda (link) (eq (alist-get 'type link) 'goto-dest))
|
||||
(pdf-cache-pagelinks
|
||||
(pdf-view-current-page)))))))))
|
||||
|
||||
(defun pdf-cache--prefetch-pages (window image-width)
|
||||
(when (and (eq window (selected-window))
|
||||
(pdf-util-pdf-buffer-p))
|
||||
(let ((page (pop pdf-cache--prefetch-pages)))
|
||||
(while (and page
|
||||
(pdf-cache-lookup-image
|
||||
page
|
||||
image-width
|
||||
(if (not (pdf-view-use-scaling-p))
|
||||
image-width
|
||||
(* 2 image-width))))
|
||||
(setq page (pop pdf-cache--prefetch-pages)))
|
||||
(pdf-util-debug
|
||||
(when (null page)
|
||||
(message "Prefetching done.")))
|
||||
(when page
|
||||
(let* ((buffer (current-buffer))
|
||||
(pdf-info-asynchronous
|
||||
(lambda (status data)
|
||||
(when (and (null status)
|
||||
(eq window
|
||||
(selected-window))
|
||||
(eq buffer (window-buffer)))
|
||||
(with-current-buffer (window-buffer)
|
||||
(when (derived-mode-p 'pdf-view-mode)
|
||||
(pdf-cache-put-image
|
||||
page image-width data)
|
||||
(image-size (pdf-view-create-page page))
|
||||
(pdf-util-debug
|
||||
(message "Prefetched page %s." page))
|
||||
;; Avoid max-lisp-eval-depth
|
||||
(run-with-timer
|
||||
0.001 nil 'pdf-cache--prefetch-pages window image-width)))))))
|
||||
(condition-case err
|
||||
(pdf-info-renderpage page image-width)
|
||||
(error
|
||||
(pdf-cache-prefetch-minor-mode -1)
|
||||
(signal (car err) (cdr err)))))))))
|
||||
|
||||
(defvar pdf-cache--prefetch-started-p nil
|
||||
"Guard against multiple prefetch starts.
|
||||
|
||||
Used solely in `pdf-cache--prefetch-start'.")
|
||||
|
||||
(defun pdf-cache--prefetch-start (buffer)
|
||||
"Start prefetching images in BUFFER."
|
||||
(when (and pdf-cache-prefetch-minor-mode
|
||||
(not pdf-cache--prefetch-started-p)
|
||||
(pdf-util-pdf-buffer-p)
|
||||
(not isearch-mode)
|
||||
(null pdf-cache--prefetch-pages)
|
||||
(eq (window-buffer) buffer)
|
||||
(fboundp pdf-cache-prefetch-pages-function))
|
||||
(let* ((pdf-cache--prefetch-started-p t)
|
||||
(pages (funcall pdf-cache-prefetch-pages-function)))
|
||||
(setq pdf-cache--prefetch-pages
|
||||
(butlast pages (max 0 (- (length pages)
|
||||
pdf-cache-image-limit))))
|
||||
(pdf-cache--prefetch-pages
|
||||
(selected-window)
|
||||
(car (pdf-view-desired-image-size))))))
|
||||
|
||||
(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)
|
||||
(when pdf-cache--prefetch-timer
|
||||
(cancel-timer pdf-cache--prefetch-timer))
|
||||
(setq pdf-cache--prefetch-timer nil))
|
||||
|
||||
(provide 'pdf-cache)
|
||||
;;; pdf-cache.el ends here
|
||||
85
elpa/pdf-tools-20180428.827/pdf-dev.el
Normal file
85
elpa/pdf-tools-20180428.827/pdf-dev.el
Normal file
@@ -0,0 +1,85 @@
|
||||
;;; pdf-dev.el --- Mother's little development helper -*- lexical-binding: t; -*-
|
||||
|
||||
;; Copyright (C) 2015 Andreas Politz
|
||||
|
||||
;; Author: Andreas Politz <politza@hochschule-trier.de>
|
||||
;; 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
|
||||
;; 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:
|
||||
;;
|
||||
;; This file is only ment for developers. The entry point is
|
||||
;; pdf-dev-minor-mode, which see.
|
||||
|
||||
;;; Code:
|
||||
|
||||
(defvar pdf-dev-root-directory
|
||||
(file-name-directory
|
||||
(directory-file-name
|
||||
(file-name-directory load-file-name))))
|
||||
|
||||
(defun pdf-dev-reload ()
|
||||
"Reload lisp files from source."
|
||||
(interactive)
|
||||
(let ((default-directory (expand-file-name
|
||||
"lisp"
|
||||
pdf-dev-root-directory))
|
||||
loaded)
|
||||
(dolist (file (directory-files default-directory nil "\\`pdf-\\w*\\.el\\'"))
|
||||
(push file loaded)
|
||||
(load-file file))
|
||||
(message "Loaded %s" (mapconcat 'identity loaded " "))))
|
||||
|
||||
(define-minor-mode pdf-dev-minor-mode
|
||||
"Make developing pdf-tools easier.
|
||||
|
||||
It does the following:
|
||||
|
||||
Quits the server and sets `pdf-info-epdfinfo-program' to
|
||||
../server/epdfinfo.
|
||||
|
||||
Installs a `compilation-finish-functions' which will restart
|
||||
epdfinfo after a successful recompilation.
|
||||
|
||||
Sets up `load-path' and reloads all PDF Tools lisp files."
|
||||
nil nil nil
|
||||
(let ((lisp-dir (expand-file-name "lisp" pdf-dev-root-directory)))
|
||||
(setq load-path (remove lisp-dir load-path))
|
||||
(cond
|
||||
(pdf-dev-minor-mode
|
||||
(add-hook 'compilation-finish-functions 'pdf-dev-compilation-finished)
|
||||
(add-to-list 'load-path lisp-dir)
|
||||
(setq pdf-info-epdfinfo-program
|
||||
(expand-file-name
|
||||
"epdfinfo"
|
||||
(expand-file-name "server" pdf-dev-root-directory)))
|
||||
(pdf-info-quit)
|
||||
(pdf-dev-reload))
|
||||
(t
|
||||
(remove-hook 'compilation-finish-functions 'pdf-dev-compilation-finished)))))
|
||||
|
||||
(defun pdf-dev-compilation-finished (buffer status)
|
||||
(with-current-buffer buffer
|
||||
(when (and (equal status "finished\n")
|
||||
(file-equal-p
|
||||
(expand-file-name "server" pdf-dev-root-directory)
|
||||
default-directory))
|
||||
(message "Restarting epdfinfo server")
|
||||
(pdf-info-quit)
|
||||
(let ((pdf-info-restart-process-p t))
|
||||
(pdf-info-process-assert-running)))))
|
||||
|
||||
(provide 'pdf-dev)
|
||||
;;; pdf-dev.el ends here
|
||||
170
elpa/pdf-tools-20180428.827/pdf-history.el
Normal file
170
elpa/pdf-tools-20180428.827/pdf-history.el
Normal file
@@ -0,0 +1,170 @@
|
||||
;;; pdf-history.el --- A simple stack-based history in PDF buffers. -*- lexical-binding: t -*-
|
||||
|
||||
;; Copyright (C) 2013, 2014 Andreas Politz
|
||||
|
||||
;; Author: Andreas Politz <politza@fh-trier.de>
|
||||
;; Keywords: files, multimedia
|
||||
|
||||
;; 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:
|
||||
;;
|
||||
|
||||
(require 'pdf-view)
|
||||
(require 'pdf-util)
|
||||
|
||||
;;; Code:
|
||||
|
||||
(defgroup pdf-history nil
|
||||
"A simple stack-based history."
|
||||
:group 'pdf-tools)
|
||||
|
||||
(defvar-local pdf-history-stack nil
|
||||
"The stack of history items.")
|
||||
|
||||
(defvar-local pdf-history-index nil
|
||||
"The current index into the `pdf-history-stack'.")
|
||||
|
||||
(defvar pdf-history-minor-mode-map
|
||||
(let ((kmap (make-sparse-keymap)))
|
||||
(define-key kmap (kbd "B") 'pdf-history-backward)
|
||||
(define-key kmap (kbd "N") 'pdf-history-forward)
|
||||
kmap)
|
||||
"Keymap used in `pdf-history-minor-mode'.")
|
||||
|
||||
;;;###autoload
|
||||
(define-minor-mode pdf-history-minor-mode
|
||||
"Keep a history of previously visited pages.
|
||||
|
||||
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 navigated with the following keys.
|
||||
|
||||
\\{pdf-history-minor-mode-map}"
|
||||
nil nil nil
|
||||
(pdf-util-assert-pdf-buffer)
|
||||
(pdf-history-clear)
|
||||
(cond
|
||||
(pdf-history-minor-mode
|
||||
(pdf-history-push)
|
||||
(add-hook 'pdf-view-after-change-page-hook
|
||||
'pdf-history-before-change-page-hook nil t))
|
||||
(t
|
||||
(remove-hook 'pdf-view-after-change-page-hook
|
||||
'pdf-history-before-change-page-hook t))))
|
||||
|
||||
(defun pdf-history-before-change-page-hook ()
|
||||
"Push a history item, before leaving this page."
|
||||
(when (and pdf-history-minor-mode
|
||||
(not (bound-and-true-p pdf-isearch-active-mode))
|
||||
(pdf-view-current-page))
|
||||
(pdf-history-push)))
|
||||
|
||||
(defun pdf-history-push ()
|
||||
"Push the current page on the stack.
|
||||
|
||||
This function does nothing, if current stack item already
|
||||
represents the current page."
|
||||
(interactive)
|
||||
(let ((item (pdf-history-create-item)))
|
||||
(unless (and pdf-history-stack
|
||||
(equal (nth pdf-history-index
|
||||
pdf-history-stack) item))
|
||||
(setq pdf-history-stack
|
||||
(last pdf-history-stack
|
||||
(- (length pdf-history-stack)
|
||||
pdf-history-index))
|
||||
pdf-history-index 0)
|
||||
(push item pdf-history-stack))))
|
||||
|
||||
(defun pdf-history-clear ()
|
||||
"Remove all history items."
|
||||
(interactive)
|
||||
(setq pdf-history-stack nil
|
||||
pdf-history-index 0)
|
||||
(pdf-history-push))
|
||||
|
||||
(defun pdf-history-create-item ()
|
||||
"Create a history item representing the current page."
|
||||
(list
|
||||
(pdf-view-current-page)))
|
||||
|
||||
(defun pdf-history-beginning-of-history-p ()
|
||||
"Return t, if at the beginning of the history."
|
||||
(= pdf-history-index 0))
|
||||
|
||||
(defun pdf-history-end-of-history-p ()
|
||||
"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")
|
||||
(cond
|
||||
((and (> n 0)
|
||||
(pdf-history-end-of-history-p))
|
||||
(error "End of history"))
|
||||
((and (< n 0)
|
||||
(pdf-history-beginning-of-history-p))
|
||||
(error "Beginning of history"))
|
||||
((/= n 0)
|
||||
(let ((i (min (max 0 (+ pdf-history-index n))
|
||||
(1- (length pdf-history-stack)))))
|
||||
(prog1
|
||||
(- (+ pdf-history-index n) i)
|
||||
(pdf-history-goto i))))
|
||||
(t 0)))
|
||||
|
||||
(defun pdf-history-forward (n)
|
||||
"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")
|
||||
(when (null pdf-history-stack)
|
||||
(error "The history is empty"))
|
||||
(cond
|
||||
((>= n (length pdf-history-stack))
|
||||
(error "End of history"))
|
||||
((< n 0)
|
||||
(error "Beginning of history"))
|
||||
(t
|
||||
(setq pdf-history-index n)
|
||||
(pdf-view-goto-page
|
||||
(car (nth n pdf-history-stack))))))
|
||||
|
||||
(defun pdf-history-debug ()
|
||||
"Visualize the history in the header-line."
|
||||
(interactive)
|
||||
(setq header-line-format
|
||||
'(:eval
|
||||
(let ((pages (mapcar 'car pdf-history-stack))
|
||||
(index pdf-history-index)
|
||||
header)
|
||||
(dotimes (i (length pages))
|
||||
(push (propertize
|
||||
(format "%s" (nth i pages))
|
||||
'face
|
||||
(and (= i index) 'match))
|
||||
header))
|
||||
(concat
|
||||
"(" (format "%d" index) ") "
|
||||
(mapconcat 'identity (nreverse header) " | "))))))
|
||||
|
||||
(provide 'pdf-history)
|
||||
|
||||
;;; pdf-history.el ends here
|
||||
1743
elpa/pdf-tools-20180428.827/pdf-info.el
Normal file
1743
elpa/pdf-tools-20180428.827/pdf-info.el
Normal file
File diff suppressed because it is too large
Load Diff
831
elpa/pdf-tools-20180428.827/pdf-isearch.el
Normal file
831
elpa/pdf-tools-20180428.827/pdf-isearch.el
Normal file
@@ -0,0 +1,831 @@
|
||||
;;; pdf-isearch.el --- Isearch in pdf buffers. -*- lexical-binding: t -*-
|
||||
|
||||
;; Copyright (C) 2013, 2014 Andreas Politz
|
||||
|
||||
;; Author: Andreas Politz <politza@fh-trier.de>
|
||||
;; Keywords: files, multimedia
|
||||
|
||||
;; 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:
|
||||
;;
|
||||
;;; Todo:
|
||||
;;
|
||||
;; * Add the possibility to limit the search to a range of pages.
|
||||
|
||||
(require 'cl-lib)
|
||||
(require 'pdf-util)
|
||||
(require 'pdf-info)
|
||||
(require 'pdf-misc)
|
||||
(require 'pdf-view)
|
||||
(require 'pdf-cache)
|
||||
(require 'let-alist)
|
||||
|
||||
;;; Code:
|
||||
|
||||
|
||||
|
||||
;; * ================================================================== *
|
||||
;; * Customizations
|
||||
;; * ================================================================== *
|
||||
|
||||
(defgroup pdf-isearch nil
|
||||
"Isearch in pdf buffers."
|
||||
:group 'pdf-tools)
|
||||
|
||||
(defface pdf-isearch-match
|
||||
'((((background dark)) (:inherit isearch))
|
||||
(((background light)) (:inherit isearch)))
|
||||
"Face used to determine the colors of the current match."
|
||||
:group 'pdf-isearch
|
||||
:group 'pdf-tools-faces)
|
||||
|
||||
(defface pdf-isearch-lazy
|
||||
'((((background dark)) (:inherit lazy-highlight))
|
||||
(((background light)) (:inherit lazy-highlight)))
|
||||
"Face used to determine the colors of non-current matches."
|
||||
:group 'pdf-isearch
|
||||
:group 'pdf-tools-faces)
|
||||
|
||||
(defface pdf-isearch-batch
|
||||
'((((background dark)) (:inherit match))
|
||||
(((background light)) (:inherit match)))
|
||||
"Face used to determine the colors in `pdf-isearch-batch-mode'."
|
||||
:group 'pdf-isearch
|
||||
:group 'pdf-tools-faces)
|
||||
|
||||
(defcustom pdf-isearch-hyphenation-character "-"
|
||||
"Characters used as hyphens when word searching."
|
||||
:group 'pdf-isearch
|
||||
:type 'string)
|
||||
|
||||
(defvar pdf-isearch-search-fun-function nil
|
||||
"Search function used when searching.
|
||||
|
||||
Like `isearch-search-fun-function', though it should return a
|
||||
function \(FN STRING &optional PAGES\), which in turn should
|
||||
return a result like `pdf-info-search-regexp'.")
|
||||
|
||||
|
||||
;; * ================================================================== *
|
||||
;; * Internal Variables
|
||||
;; * ================================================================== *
|
||||
|
||||
(defvar-local pdf-isearch-current-page nil
|
||||
"The page that is currently searched.")
|
||||
|
||||
(defvar-local pdf-isearch-current-match nil
|
||||
"A list ((LEFT TOP RIGHT BOT) ...) of the current match or nil.
|
||||
|
||||
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.")
|
||||
|
||||
(defvar-local pdf-isearch-current-parameter nil
|
||||
"A list of search parameter \(search-string regex-p case-fold word-search\).")
|
||||
|
||||
|
||||
;; * ================================================================== *
|
||||
;; * Modes
|
||||
;; * ================================================================== *
|
||||
|
||||
(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)
|
||||
kmap)
|
||||
"Keymap used in `pdf-isearch-minor-mode'.")
|
||||
|
||||
(defvar pdf-isearch-active-mode-map
|
||||
(let ((kmap (make-sparse-keymap)))
|
||||
(set-keymap-parent kmap isearch-mode-map)
|
||||
(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. Its parent
|
||||
keymap is `isearch-mode-map'.")
|
||||
|
||||
(put 'image-scroll-up 'isearch-scroll t)
|
||||
(put 'image-scroll-down 'isearch-scroll t)
|
||||
|
||||
(define-minor-mode pdf-isearch-active-mode "" nil nil nil
|
||||
(cond
|
||||
(pdf-isearch-active-mode
|
||||
(set (make-local-variable 'isearch-mode-map)
|
||||
pdf-isearch-active-mode-map)
|
||||
(setq overriding-terminal-local-map
|
||||
isearch-mode-map))
|
||||
(t
|
||||
;;(setq overriding-terminal-local-map nil) ?
|
||||
(kill-local-variable 'isearch-mode-map))))
|
||||
|
||||
;;;###autoload
|
||||
(define-minor-mode pdf-isearch-minor-mode
|
||||
"Isearch mode for PDF buffer.
|
||||
|
||||
When this mode is enabled \\[isearch-forward], among other keys,
|
||||
starts an incremental search in this PDF document. Since this mode
|
||||
uses external programs to highlight found matches via
|
||||
image-processing, proceeding to the next match may be slow.
|
||||
|
||||
Therefore two isearch behaviours have been defined: Normal isearch and
|
||||
batch mode. The later one is a minor mode
|
||||
\(`pdf-isearch-batch-mode'\), which when activated inhibits isearch
|
||||
from stopping at and highlighting every single match, but rather
|
||||
display them batch-wise. Here a batch means a number of matches
|
||||
currently visible in the selected window.
|
||||
|
||||
The kind of highlighting is determined by three faces
|
||||
`pdf-isearch-match' \(for the current match\), `pdf-isearch-lazy'
|
||||
\(for all other matches\) and `pdf-isearch-batch' \(when in batch
|
||||
mode\), which see.
|
||||
|
||||
Colors may also be influenced by the minor-mode
|
||||
`pdf-view-dark-minor-mode'. If this is minor mode enabled, each face's
|
||||
dark colors, are used (see e.g. `frame-background-mode'), instead
|
||||
of the light ones.
|
||||
|
||||
\\{pdf-isearch-minor-mode-map}
|
||||
While in `isearch-mode' the following keys are available. Note
|
||||
that not every isearch command work as expected.
|
||||
|
||||
\\{pdf-isearch-active-mode-map}"
|
||||
:group 'pdf-isearch
|
||||
(pdf-util-assert-pdf-buffer)
|
||||
(cond
|
||||
(pdf-isearch-minor-mode
|
||||
(when (boundp 'character-fold-search)
|
||||
(setq-local character-fold-search nil))
|
||||
(set (make-local-variable 'isearch-search-fun-function)
|
||||
(lambda nil 'pdf-isearch-search-function))
|
||||
(set (make-local-variable 'isearch-push-state-function)
|
||||
'pdf-isearch-push-state-function)
|
||||
(set (make-local-variable 'isearch-wrap-function)
|
||||
'pdf-isearch-wrap-function)
|
||||
(set (make-local-variable 'isearch-lazy-highlight) nil)
|
||||
;; Make our commands work in isearch-mode.
|
||||
(set (make-local-variable 'isearch-allow-scroll) t)
|
||||
(set (make-local-variable 'search-exit-option)
|
||||
;; This maybe edit or t, but edit would suppress our cmds
|
||||
;; in isearch-other-meta-char.
|
||||
(not (not search-exit-option)))
|
||||
;; FIXME: Die Variable imagemagick-render-type entweder an anderer
|
||||
;; Stelle global setzen oder nur irgendwo auf den
|
||||
;; Performancegewinn hinweisen.
|
||||
(when (and (boundp 'imagemagick-render-type)
|
||||
(= 0 imagemagick-render-type))
|
||||
;; This enormously speeds up rendering.
|
||||
(setq imagemagick-render-type 1))
|
||||
(add-hook 'isearch-mode-hook 'pdf-isearch-mode-initialize nil t)
|
||||
(add-hook 'isearch-mode-end-hook 'pdf-isearch-mode-cleanup nil t)
|
||||
(add-hook 'isearch-update-post-hook 'pdf-isearch-update nil t))
|
||||
(t
|
||||
(when (boundp 'character-fold-search)
|
||||
(kill-local-variable 'character-fold-search))
|
||||
(kill-local-variable 'search-exit-option)
|
||||
(kill-local-variable 'isearch-allow-scroll)
|
||||
(kill-local-variable 'isearch-search-fun-function)
|
||||
(kill-local-variable 'isearch-push-state-function)
|
||||
(kill-local-variable 'isearch-wrap-function)
|
||||
(kill-local-variable 'isearch-lazy-highlight)
|
||||
(remove-hook 'isearch-update-post-hook 'pdf-isearch-update t)
|
||||
(remove-hook 'isearch-mode-hook 'pdf-isearch-mode-initialize t)
|
||||
(remove-hook 'isearch-mode-end-hook 'pdf-isearch-mode-cleanup t))))
|
||||
|
||||
(define-minor-mode pdf-isearch-batch-mode
|
||||
"Isearch PDF documents batch-wise.
|
||||
|
||||
If this mode is enabled, isearching does not stop at every match,
|
||||
but rather moves to the next one not currently visible. This
|
||||
behaviour is much faster than ordinary isearch, since far less
|
||||
different images have to be displayed."
|
||||
nil nil nil
|
||||
:group 'pdf-isearch
|
||||
(when isearch-mode
|
||||
(pdf-isearch-redisplay)
|
||||
(pdf-isearch-message
|
||||
(if pdf-isearch-batch-mode "batch mode" "isearch mode"))))
|
||||
|
||||
|
||||
|
||||
;; * ================================================================== *
|
||||
;; * Isearch interface
|
||||
;; * ================================================================== *
|
||||
|
||||
(defvar pdf-isearch-filter-matches-function nil
|
||||
"A function for filtering isearch matches.
|
||||
|
||||
The function receives one argument: a list of matches, each
|
||||
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
|
||||
"Non-nil, if the search should be limited to the current page.")
|
||||
|
||||
(defun pdf-isearch-search-function (string &rest _)
|
||||
"Search for STRING in the current PDF buffer.
|
||||
|
||||
This is a Isearch interface function."
|
||||
(when (> (length string) 0)
|
||||
(let ((same-search-p (pdf-isearch-same-search-p))
|
||||
(oldpage pdf-isearch-current-page)
|
||||
(matches (pdf-isearch-search-page string))
|
||||
next-match)
|
||||
;; matches is a list of list of edges ((x0 y1 x1 y2) ...),
|
||||
;; sorted top to bottom ,left to right. Coordinates are in image
|
||||
;; space.
|
||||
(unless isearch-forward
|
||||
(setq matches (reverse matches)))
|
||||
(when pdf-isearch-filter-matches-function
|
||||
(setq matches (funcall pdf-isearch-filter-matches-function matches)))
|
||||
;; Where to go next ?
|
||||
(setq pdf-isearch-current-page (pdf-view-current-page)
|
||||
pdf-isearch-current-matches matches
|
||||
next-match
|
||||
(pdf-isearch-next-match
|
||||
oldpage pdf-isearch-current-page
|
||||
pdf-isearch-current-match matches
|
||||
same-search-p
|
||||
isearch-forward)
|
||||
pdf-isearch-current-parameter
|
||||
(list string isearch-regexp
|
||||
isearch-case-fold-search isearch-word))
|
||||
(cond
|
||||
(next-match
|
||||
(setq pdf-isearch-current-match next-match)
|
||||
(pdf-isearch-hl-matches next-match matches)
|
||||
(pdf-isearch-focus-match next-match)
|
||||
;; Don't get off track.
|
||||
(when (or (and (bobp) (not isearch-forward))
|
||||
(and (eobp) isearch-forward))
|
||||
(goto-char (1+ (/ (buffer-size) 2))))
|
||||
;; Signal success to isearch.
|
||||
(if isearch-forward
|
||||
(re-search-forward ".")
|
||||
(re-search-backward ".")))
|
||||
((and (not pdf-isearch-narrow-to-page)
|
||||
(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
|
||||
(pdf-view-goto-page next-page)
|
||||
(pdf-isearch-search-function string))))))))
|
||||
|
||||
(defun pdf-isearch-push-state-function ()
|
||||
"Push the current search state.
|
||||
|
||||
This is a Isearch interface function."
|
||||
(let ((hscroll (window-hscroll))
|
||||
(vscroll (window-vscroll))
|
||||
(parms pdf-isearch-current-parameter)
|
||||
(matches pdf-isearch-current-matches)
|
||||
(match pdf-isearch-current-match)
|
||||
(page pdf-isearch-current-page))
|
||||
(lambda (_state)
|
||||
(setq pdf-isearch-current-parameter parms
|
||||
pdf-isearch-current-matches matches
|
||||
pdf-isearch-current-match match
|
||||
pdf-isearch-current-page page)
|
||||
|
||||
(pdf-view-goto-page pdf-isearch-current-page)
|
||||
(when pdf-isearch-current-match
|
||||
(pdf-isearch-hl-matches
|
||||
pdf-isearch-current-match
|
||||
pdf-isearch-current-matches))
|
||||
(image-set-window-hscroll hscroll)
|
||||
(image-set-window-vscroll vscroll))))
|
||||
|
||||
(defun pdf-isearch-wrap-function ()
|
||||
"Go to first or last page.
|
||||
|
||||
This is a Isearch interface function."
|
||||
(let ((page (if isearch-forward
|
||||
1
|
||||
(pdf-cache-number-of-pages))))
|
||||
(unless (or pdf-isearch-narrow-to-page
|
||||
(= page (pdf-view-current-page)))
|
||||
(pdf-view-goto-page page)
|
||||
(let ((next-screen-context-lines 0))
|
||||
(if (= page 1)
|
||||
(image-scroll-down)
|
||||
(image-scroll-up)))))
|
||||
(setq pdf-isearch-current-match nil))
|
||||
|
||||
(defun pdf-isearch-mode-cleanup ()
|
||||
"Cleanup after exiting Isearch.
|
||||
|
||||
This is a Isearch interface function."
|
||||
(pdf-isearch-active-mode -1)
|
||||
(pdf-view-redisplay))
|
||||
|
||||
(defun pdf-isearch-mode-initialize ()
|
||||
"Initialize isearching.
|
||||
|
||||
This is a Isearch interface function."
|
||||
(pdf-isearch-active-mode 1)
|
||||
(setq pdf-isearch-current-page (pdf-view-current-page)
|
||||
pdf-isearch-current-match nil
|
||||
pdf-isearch-current-matches nil
|
||||
pdf-isearch-current-parameter nil)
|
||||
(goto-char (1+ (/ (buffer-size) 2))))
|
||||
|
||||
(defun pdf-isearch-same-search-p (&optional ignore-search-string-p)
|
||||
"Return non-nil, if search parameter have not changed.
|
||||
|
||||
Parameter inspected are `isearch-string' (unless
|
||||
IGNORE-SEARCH-STRING-P is t) and `isearch-case-fold-search'. If
|
||||
there was no previous search, this function returns t."
|
||||
(or (null pdf-isearch-current-parameter)
|
||||
(let ((parameter (list isearch-string
|
||||
isearch-regexp
|
||||
isearch-case-fold-search
|
||||
isearch-word)))
|
||||
(if ignore-search-string-p
|
||||
(equal (cdr pdf-isearch-current-parameter)
|
||||
(cdr parameter))
|
||||
(equal pdf-isearch-current-parameter
|
||||
parameter)))))
|
||||
|
||||
(defun pdf-isearch-next-match (last-page this-page last-match
|
||||
all-matches continued-p
|
||||
forward-p)
|
||||
"Determine the next match."
|
||||
(funcall (if pdf-isearch-batch-mode
|
||||
'pdf-isearch-next-match-batch
|
||||
'pdf-isearch-next-match-isearch)
|
||||
last-page this-page last-match
|
||||
all-matches continued-p forward-p))
|
||||
|
||||
(defun pdf-isearch-focus-match (current-match)
|
||||
"Make the CURRENT-MATCH visible in the window."
|
||||
(funcall (if pdf-isearch-batch-mode
|
||||
'pdf-isearch-focus-match-batch
|
||||
'pdf-isearch-focus-match-isearch)
|
||||
current-match))
|
||||
|
||||
(defun pdf-isearch-redisplay ()
|
||||
"Redisplay the current highlighting."
|
||||
(pdf-isearch-hl-matches pdf-isearch-current-match
|
||||
pdf-isearch-current-matches))
|
||||
|
||||
(defun pdf-isearch-update ()
|
||||
"Update search and redisplay, if necessary."
|
||||
(unless (pdf-isearch-same-search-p t)
|
||||
(setq pdf-isearch-current-parameter
|
||||
(list isearch-string isearch-regexp
|
||||
isearch-case-fold-search isearch-word)
|
||||
pdf-isearch-current-matches
|
||||
(pdf-isearch-search-page isearch-string))
|
||||
(pdf-isearch-redisplay)))
|
||||
|
||||
(defun pdf-isearch-message (fmt &rest args)
|
||||
"Like `message', but Isearch friendly."
|
||||
(unless args (setq args (list fmt) fmt "%s"))
|
||||
(let ((msg (apply 'format fmt args)))
|
||||
(if (cl-some (lambda (buf)
|
||||
(buffer-local-value 'isearch-mode buf))
|
||||
(mapcar 'window-buffer (window-list)))
|
||||
(let ((isearch-message-suffix-add
|
||||
(format " [%s]" msg)))
|
||||
(isearch-message)
|
||||
(sit-for 1))
|
||||
(message "%s" msg))))
|
||||
|
||||
(defun pdf-isearch-empty-match-p (matches)
|
||||
(and matches
|
||||
(cl-every
|
||||
(lambda (match)
|
||||
(cl-every (lambda (edges)
|
||||
(cl-every 'zerop edges))
|
||||
match))
|
||||
matches)))
|
||||
|
||||
(defun pdf-isearch-occur ()
|
||||
"Run `occur' using the last search string or regexp."
|
||||
(interactive)
|
||||
(let ((case-fold-search isearch-case-fold-search)
|
||||
(regexp
|
||||
(cond
|
||||
((functionp isearch-word)
|
||||
(funcall isearch-word isearch-string))
|
||||
(isearch-word (pdf-isearch-word-search-regexp
|
||||
isearch-string nil
|
||||
pdf-isearch-hyphenation-character))
|
||||
(isearch-regexp isearch-string))))
|
||||
(save-selected-window
|
||||
(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
|
||||
;; * ================================================================== *
|
||||
|
||||
(defun pdf-isearch-search-page (string &optional page)
|
||||
"Search STRING on PAGE in the current window.
|
||||
|
||||
Returns a list of edges (LEFT TOP RIGHT BOTTOM) in PDF
|
||||
coordinates, sorted top to bottom, then left to right."
|
||||
|
||||
(unless page (setq page (pdf-view-current-page)))
|
||||
(mapcar (lambda (match)
|
||||
(let-alist match
|
||||
(pdf-util-scale-relative-to-pixel .edges 'round)))
|
||||
(let ((case-fold-search isearch-case-fold-search))
|
||||
(funcall (pdf-isearch-search-fun)
|
||||
string page))))
|
||||
|
||||
(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
|
||||
((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
|
||||
(car isearch-cmds))))))))
|
||||
(pdf-info-search-regexp
|
||||
(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)))
|
||||
(t
|
||||
'pdf-info-search-string)))
|
||||
|
||||
|
||||
(defun pdf-isearch-word-search-regexp (string &optional lax hyphenization-chars)
|
||||
"Return a PCRE which matches words, ignoring punctuation."
|
||||
(let ((hyphenization-regexp
|
||||
(and hyphenization-chars
|
||||
(format "(?:[%s]\\n)?"
|
||||
(replace-regexp-in-string
|
||||
"[]^\\\\-]" "\\\\\\&"
|
||||
hyphenization-chars t)))))
|
||||
(cond
|
||||
((equal string "") "")
|
||||
((string-match-p "\\`\\W+\\'" string) "\\W+")
|
||||
(t (concat
|
||||
(if (string-match-p "\\`\\W" string) "\\W+"
|
||||
(unless lax "\\b"))
|
||||
(mapconcat (lambda (word)
|
||||
(if hyphenization-regexp
|
||||
(mapconcat
|
||||
(lambda (ch)
|
||||
(pdf-util-pcre-quote (string ch)))
|
||||
(append word nil)
|
||||
hyphenization-regexp)
|
||||
(pdf-util-pcre-quote word)))
|
||||
(split-string string "\\W+" t) "\\W+")
|
||||
(if (string-match-p "\\W\\'" string) "\\W+"
|
||||
(unless lax "\\b")))))))
|
||||
|
||||
(defun pdf-isearch-find-next-matching-page (string page &optional interactive-p)
|
||||
"Find STRING after or before page PAGE, according to FORWARD-P.
|
||||
|
||||
If INTERACTIVE-P is non-nil, give some progress feedback.
|
||||
Returns the page number where STRING was found, or nil if there
|
||||
is no such page."
|
||||
;; Do a exponentially expanding search.
|
||||
(let* ((incr 1)
|
||||
(pages (if isearch-forward
|
||||
(cons (1+ page)
|
||||
(1+ page))
|
||||
(cons (1- page)
|
||||
(1- page))))
|
||||
(fn (pdf-isearch-search-fun))
|
||||
matched-page
|
||||
reporter)
|
||||
|
||||
(while (and (null matched-page)
|
||||
(or (and isearch-forward
|
||||
(<= (car pages)
|
||||
(pdf-cache-number-of-pages)))
|
||||
(and (not isearch-forward)
|
||||
(>= (cdr pages) 1))))
|
||||
(let* ((case-fold-search isearch-case-fold-search)
|
||||
(matches (funcall fn string pages)))
|
||||
(setq matched-page
|
||||
(alist-get 'page (if isearch-forward
|
||||
(car matches)
|
||||
(car (last matches))))))
|
||||
(setq incr (* incr 2))
|
||||
(cond (isearch-forward
|
||||
(setcar pages (1+ (cdr pages)))
|
||||
(setcdr pages (min (pdf-cache-number-of-pages)
|
||||
(+ (cdr pages) incr))))
|
||||
(t
|
||||
(setcdr pages (1- (car pages)))
|
||||
(setcar pages (max 1 (- (car pages)
|
||||
incr)))))
|
||||
(when interactive-p
|
||||
(when (and (not reporter)
|
||||
(= incr 8)) ;;Don't bother right away.
|
||||
(setq reporter
|
||||
(apply
|
||||
'make-progress-reporter "Searching"
|
||||
(if isearch-forward
|
||||
(list (car pages) (pdf-cache-number-of-pages) nil 0)
|
||||
(list 1 (cdr pages) nil 0)))))
|
||||
(when reporter
|
||||
(progress-reporter-update
|
||||
reporter (if isearch-forward
|
||||
(- (cdr pages) page)
|
||||
(- page (car pages)))))))
|
||||
matched-page))
|
||||
|
||||
|
||||
|
||||
;; * ================================================================== *
|
||||
;; * Isearch Behavior
|
||||
;; * ================================================================== *
|
||||
|
||||
(defun pdf-isearch-next-match-isearch (last-page this-page last-match
|
||||
matches same-search-p
|
||||
forward)
|
||||
"Default function for choosing the next match.
|
||||
|
||||
Implements default isearch behaviour, i.e. it stops at every
|
||||
match."
|
||||
(cond
|
||||
((null last-match)
|
||||
;; Goto first match from top or bottom of the window.
|
||||
(let* ((iedges (pdf-util-image-displayed-edges))
|
||||
(pos (pdf-util-with-edges (iedges)
|
||||
(if forward
|
||||
(list iedges-left iedges-top
|
||||
iedges-left iedges-top)
|
||||
(list iedges-right iedges-bot
|
||||
iedges-right iedges-bot)))))
|
||||
(pdf-isearch-closest-match (list pos) matches forward)))
|
||||
((not (eq last-page this-page))
|
||||
;; First match from top-left or bottom-right of the new
|
||||
;; page.
|
||||
(car matches))
|
||||
(same-search-p
|
||||
;; Next match after the last one.
|
||||
(if last-match
|
||||
(cadr (member last-match matches))))
|
||||
(matches
|
||||
;; 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)))
|
||||
|
||||
(defun pdf-isearch-next-match-batch (last-page this-page last-match
|
||||
matches same-search-p
|
||||
forward-p)
|
||||
"Select the next match, unseen in the current search direction."
|
||||
|
||||
(if (or (null last-match)
|
||||
(not same-search-p)
|
||||
(not (eq last-page this-page)))
|
||||
(pdf-isearch-next-match-isearch
|
||||
last-page this-page last-match matches same-search-p forward-p)
|
||||
(pdf-util-with-edges (match iedges)
|
||||
(let ((iedges (pdf-util-image-displayed-edges)))
|
||||
(car (cl-remove-if
|
||||
;; Filter matches visible on screen.
|
||||
(lambda (edges)
|
||||
(let ((match (apply 'pdf-util-edges-union edges)))
|
||||
(and (<= match-right iedges-right)
|
||||
(<= match-bot iedges-bot)
|
||||
(>= match-left iedges-left)
|
||||
(>= match-top iedges-top))))
|
||||
(cdr (member last-match matches))))))))
|
||||
|
||||
(defun pdf-isearch-focus-match-batch (match)
|
||||
"Make the image area in MATCH eagerly visible in the selected window."
|
||||
(pdf-util-scroll-to-edges (apply 'pdf-util-edges-union match) t))
|
||||
|
||||
(cl-deftype pdf-isearch-match ()
|
||||
`(satisfies
|
||||
(lambda (match)
|
||||
(cl-every (lambda (edges)
|
||||
(and (consp edges)
|
||||
(= (length edges) 4)
|
||||
(cl-every 'numberp edges)))
|
||||
match))))
|
||||
|
||||
(cl-deftype list-of (type)
|
||||
`(satisfies
|
||||
(lambda (l)
|
||||
(and (listp l)
|
||||
(cl-every (lambda (x)
|
||||
(cl-typep x ',type))
|
||||
l)))))
|
||||
|
||||
(defun pdf-isearch-closest-match (match matches
|
||||
&optional forward-p)
|
||||
"Find the nearest element to MATCH in MATCHES.
|
||||
|
||||
The direction in which to look is determined by FORWARD-P.
|
||||
|
||||
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)))
|
||||
(pdf-util-with-edges (matched)
|
||||
(cl-loop for next in matches do
|
||||
(let ((edges (apply 'pdf-util-edges-union next)))
|
||||
(pdf-util-with-edges (edges)
|
||||
(when (if forward-p
|
||||
(or (>= edges-top matched-bot)
|
||||
(and (or (>= edges-top matched-top)
|
||||
(>= edges-bot matched-bot))
|
||||
(>= edges-right matched-right)))
|
||||
(or (<= edges-bot matched-top)
|
||||
(and (or (<= edges-bot matched-bot)
|
||||
(<= edges-top matched-top))
|
||||
(<= edges-left matched-left))))
|
||||
(cl-return next))))))))
|
||||
|
||||
|
||||
|
||||
;; * ================================================================== *
|
||||
;; * Display
|
||||
;; * ================================================================== *
|
||||
|
||||
|
||||
(defun pdf-isearch-current-colors ()
|
||||
"Return the current color set.
|
||||
|
||||
The return value depends on `pdf-view-dark-minor-mode' and
|
||||
`pdf-isearch-batch-mode'. It is a list of four colors \(MATCH-FG
|
||||
MATCH-BG LAZY-FG LAZY-BG\)."
|
||||
(let ((dark-p pdf-view-dark-minor-mode))
|
||||
(cond
|
||||
(pdf-isearch-batch-mode
|
||||
(let ((colors (pdf-util-face-colors 'pdf-isearch-batch dark-p)))
|
||||
(list (car colors)
|
||||
(cdr colors)
|
||||
(car colors)
|
||||
(cdr colors))))
|
||||
(t
|
||||
(let ((match (pdf-util-face-colors 'pdf-isearch-match dark-p))
|
||||
(lazy (pdf-util-face-colors 'pdf-isearch-lazy dark-p)))
|
||||
(list (car match)
|
||||
(cdr match)
|
||||
(car lazy)
|
||||
(cdr lazy)))))))
|
||||
|
||||
(defvar pdf-isearch--hl-matches-tick 0)
|
||||
|
||||
(defun pdf-isearch-hl-matches (current matches &optional occur-hack-p)
|
||||
"Highlighting edges CURRENT and MATCHES."
|
||||
(cl-check-type current pdf-isearch-match)
|
||||
(cl-check-type matches (list-of pdf-isearch-match))
|
||||
(cl-destructuring-bind (fg1 bg1 fg2 bg2)
|
||||
(pdf-isearch-current-colors)
|
||||
(let* ((width (car (pdf-view-image-size)))
|
||||
(page (pdf-view-current-page))
|
||||
(window (selected-window))
|
||||
(buffer (current-buffer))
|
||||
(tick (cl-incf pdf-isearch--hl-matches-tick))
|
||||
(pdf-info-asynchronous
|
||||
(lambda (status data)
|
||||
(when (and (null status)
|
||||
(eq tick pdf-isearch--hl-matches-tick)
|
||||
(buffer-live-p buffer)
|
||||
(window-live-p window)
|
||||
(eq (window-buffer window)
|
||||
buffer))
|
||||
(with-selected-window window
|
||||
(when (and (derived-mode-p 'pdf-view-mode)
|
||||
(or isearch-mode
|
||||
occur-hack-p)
|
||||
(eq page (pdf-view-current-page)))
|
||||
(pdf-view-display-image
|
||||
(pdf-view-create-image data))))))))
|
||||
(pdf-info-renderpage-text-regions
|
||||
page width t nil
|
||||
`(,fg1 ,bg1 ,@(pdf-util-scale-pixel-to-relative
|
||||
current))
|
||||
`(,fg2 ,bg2 ,@(pdf-util-scale-pixel-to-relative
|
||||
(apply 'append
|
||||
(remove current matches))))))))
|
||||
|
||||
|
||||
;; * ================================================================== *
|
||||
;; * Debug
|
||||
;; * ================================================================== *
|
||||
|
||||
;; The following isearch-search function is debuggable.
|
||||
;;
|
||||
(when nil
|
||||
(defun isearch-search ()
|
||||
;; Do the search with the current search string.
|
||||
(if isearch-message-function
|
||||
(funcall isearch-message-function nil t)
|
||||
(isearch-message nil t))
|
||||
(if (and (eq isearch-case-fold-search t) search-upper-case)
|
||||
(setq isearch-case-fold-search
|
||||
(isearch-no-upper-case-p isearch-string isearch-regexp)))
|
||||
(condition-case lossage
|
||||
(let ((inhibit-point-motion-hooks
|
||||
;; FIXME: equality comparisons on functions is asking for trouble.
|
||||
(and (eq isearch-filter-predicate 'isearch-filter-visible)
|
||||
search-invisible))
|
||||
(inhibit-quit nil)
|
||||
(case-fold-search isearch-case-fold-search)
|
||||
(retry t))
|
||||
(setq isearch-error nil)
|
||||
(while retry
|
||||
(setq isearch-success
|
||||
(isearch-search-string isearch-string nil t))
|
||||
;; Clear RETRY unless the search predicate says
|
||||
;; to skip this search hit.
|
||||
(if (or (not isearch-success)
|
||||
(bobp) (eobp)
|
||||
(= (match-beginning 0) (match-end 0))
|
||||
(funcall isearch-filter-predicate
|
||||
(match-beginning 0) (match-end 0)))
|
||||
(setq retry nil)))
|
||||
(setq isearch-just-started nil)
|
||||
(if isearch-success
|
||||
(setq isearch-other-end
|
||||
(if isearch-forward (match-beginning 0) (match-end 0)))))
|
||||
|
||||
(quit (isearch-unread ?\C-g)
|
||||
(setq isearch-success nil))
|
||||
|
||||
(invalid-regexp
|
||||
(setq isearch-error (car (cdr lossage)))
|
||||
(if (string-match
|
||||
"\\`Premature \\|\\`Unmatched \\|\\`Invalid "
|
||||
isearch-error)
|
||||
(setq isearch-error "incomplete input")))
|
||||
|
||||
(search-failed
|
||||
(setq isearch-success nil)
|
||||
(setq isearch-error (nth 2 lossage)))
|
||||
|
||||
;; (error
|
||||
;; ;; stack overflow in regexp search.
|
||||
;; (setq isearch-error (format "%s" lossage)))
|
||||
)
|
||||
|
||||
(if isearch-success
|
||||
nil
|
||||
;; Ding if failed this time after succeeding last time.
|
||||
(and (isearch--state-success (car isearch-cmds))
|
||||
(ding))
|
||||
(if (functionp (isearch--state-pop-fun (car isearch-cmds)))
|
||||
(funcall (isearch--state-pop-fun (car isearch-cmds))
|
||||
(car isearch-cmds)))
|
||||
(goto-char (isearch--state-point (car isearch-cmds))))))
|
||||
|
||||
|
||||
(provide 'pdf-isearch)
|
||||
|
||||
;;; pdf-isearch.el ends here
|
||||
|
||||
;; Local Variables:
|
||||
;; byte-compile-warnings: (not obsolete)
|
||||
;; End:
|
||||
376
elpa/pdf-tools-20180428.827/pdf-links.el
Normal file
376
elpa/pdf-tools-20180428.827/pdf-links.el
Normal file
@@ -0,0 +1,376 @@
|
||||
;;; pdf-links.el --- Handle PDF links. -*- lexical-binding: t -*-
|
||||
|
||||
;; Copyright (C) 2013, 2014 Andreas Politz
|
||||
|
||||
;; Author: Andreas Politz <politza@fh-trier.de>
|
||||
;; Keywords: files, multimedia
|
||||
|
||||
;; 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:
|
||||
;;
|
||||
|
||||
(require 'pdf-info)
|
||||
(require 'pdf-util)
|
||||
(require 'pdf-misc)
|
||||
(require 'pdf-cache)
|
||||
(require 'pdf-isearch)
|
||||
(require 'let-alist)
|
||||
(require 'org)
|
||||
|
||||
;;; Code:
|
||||
|
||||
|
||||
|
||||
;; * ================================================================== *
|
||||
;; * Customizations
|
||||
;; * ================================================================== *
|
||||
|
||||
(defgroup pdf-links nil
|
||||
"Following links in PDF documents."
|
||||
:group 'pdf-tools)
|
||||
|
||||
(defface pdf-links-read-link
|
||||
'((((background dark)) (:background "red" :foreground "yellow"))
|
||||
(((background light)) (:background "red" :foreground "yellow")))
|
||||
"Face used to determine the colors when reading links."
|
||||
;; :group 'pdf-links
|
||||
:group 'pdf-tools-faces)
|
||||
|
||||
(defcustom pdf-links-read-link-convert-commands
|
||||
'(;;"-font" "FreeMono"
|
||||
"-pointsize" "%P"
|
||||
"-undercolor" "%f"
|
||||
"-fill" "%b"
|
||||
"-draw" "text %X,%Y '%c'")
|
||||
|
||||
"The commands for the convert program, when decorating links for reading.
|
||||
See `pdf-util-convert' for an explanation of the format.
|
||||
|
||||
Aside from the description there, two additional escape chars are
|
||||
available.
|
||||
|
||||
%P -- The scaled font pointsize, i.e. IMAGE-WIDTH * SCALE (See
|
||||
`pdf-links-convert-pointsize-scale').
|
||||
%c -- String describing the current link key (e.g. AA, AB,
|
||||
etc.)."
|
||||
:group 'pdf-links
|
||||
:type '(repeat string)
|
||||
:link '(variable-link pdf-isearch-convert-commands)
|
||||
:link '(url-link "http://www.imagemagick.org/script/convert.php"))
|
||||
|
||||
(defcustom pdf-links-convert-pointsize-scale 0.01
|
||||
"The scale factor for the -pointsize convert command.
|
||||
|
||||
This determines the relative size of the font, when interactively
|
||||
reading links."
|
||||
:group 'pdf-links
|
||||
:type '(restricted-sexp :match-alternatives
|
||||
((lambda (x) (and (numberp x)
|
||||
(<= x 1)
|
||||
(>= x 0))))))
|
||||
|
||||
(defcustom pdf-links-browse-uri-function
|
||||
'pdf-links-browse-uri-default
|
||||
"The function for handling uri links.
|
||||
|
||||
This function should accept one argument, the URI to follow, and
|
||||
do something with it."
|
||||
:group 'pdf-links
|
||||
:type 'function)
|
||||
|
||||
|
||||
;; * ================================================================== *
|
||||
;; * Minor Mode
|
||||
;; * ================================================================== *
|
||||
|
||||
(defvar pdf-links-minor-mode-map
|
||||
(let ((kmap (make-sparse-keymap)))
|
||||
(define-key kmap (kbd "f") 'pdf-links-isearch-link)
|
||||
(define-key kmap (kbd "F") 'pdf-links-action-perform)
|
||||
kmap))
|
||||
|
||||
;;;###autoload
|
||||
(define-minor-mode pdf-links-minor-mode
|
||||
"Handle links in PDF documents.\\<pdf-links-minor-mode-map>
|
||||
|
||||
If this mode is enabled, most links in the document may be
|
||||
activated by clicking on them or by pressing \\[pdf-links-action-perform] and selecting
|
||||
one of the displayed keys, or by using isearch limited to
|
||||
links via \\[pdf-links-isearch-link].
|
||||
|
||||
\\{pdf-links-minor-mode-map}"
|
||||
|
||||
nil nil nil
|
||||
:group 'pdf-links
|
||||
(pdf-util-assert-pdf-buffer)
|
||||
(cond
|
||||
(pdf-links-minor-mode
|
||||
(pdf-view-add-hotspot-function 'pdf-links-hotspots-function 0))
|
||||
(t
|
||||
(pdf-view-remove-hotspot-function 'pdf-links-hotspots-function)))
|
||||
(pdf-view-redisplay t))
|
||||
|
||||
(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)
|
||||
(pointer 'hand)
|
||||
hotspots)
|
||||
(dolist (l links)
|
||||
(let ((e (pdf-util-scale
|
||||
(cdr (assq 'edges l)) size 'round))
|
||||
(id (intern (format id-fmt page
|
||||
(cl-incf i)))))
|
||||
(push `((rect . ((,(nth 0 e) . ,(nth 1 e))
|
||||
. (,(nth 2 e) . ,(nth 3 e))))
|
||||
,id
|
||||
(pointer
|
||||
,pointer
|
||||
help-echo ,(pdf-links-action-to-string l)))
|
||||
hotspots)
|
||||
(local-set-key
|
||||
(vector id 'mouse-1)
|
||||
(lambda nil
|
||||
(interactive "@")
|
||||
(pdf-links-action-perform l)))
|
||||
(local-set-key
|
||||
(vector id t)
|
||||
'pdf-util-image-map-mouse-event-proxy)))
|
||||
(nreverse hotspots)))
|
||||
|
||||
(defun pdf-links-action-to-string (link)
|
||||
"Return a string representation of ACTION."
|
||||
(let-alist link
|
||||
(concat
|
||||
(cl-case .type
|
||||
(goto-dest
|
||||
(if (> .page 0)
|
||||
(format "Goto page %d" .page)
|
||||
"Destination not found"))
|
||||
(goto-remote
|
||||
(if (and .filename (file-exists-p .filename))
|
||||
(format "Goto %sfile '%s'"
|
||||
(if (> .page 0)
|
||||
(format "p.%d of " .page)
|
||||
"")
|
||||
.filename)
|
||||
(format "Link to nonexistent file '%s'" .filename)))
|
||||
(uri
|
||||
(if (> (length .uri) 0)
|
||||
(format "Link to uri '%s'" .uri)
|
||||
(format "Link to empty uri")))
|
||||
(t (format "Unrecognized link type: %s" .type)))
|
||||
(if (> (length .title) 0)
|
||||
(format " (%s)" .title)))))
|
||||
|
||||
;;;###autoload
|
||||
(defun pdf-links-action-perform (link)
|
||||
"Follow LINK, depending on its type.
|
||||
|
||||
This may turn to another page, switch to another PDF buffer or
|
||||
invoke `pdf-links-browse-uri-function'.
|
||||
|
||||
Interactively, link is read via `pdf-links-read-link-action'.
|
||||
This function displays characters around the links in the current
|
||||
page and starts reading characters (ignoring case). After a
|
||||
sufficient number of characters have been read, the corresponding
|
||||
link's link is invoked. Additionally, SPC may be used to
|
||||
scroll the current page."
|
||||
(interactive
|
||||
(list (or (pdf-links-read-link-action "Activate link (SPC scrolls): ")
|
||||
(error "No link selected"))))
|
||||
(let-alist link
|
||||
(cl-case .type
|
||||
((goto-dest goto-remote)
|
||||
(let ((window (selected-window)))
|
||||
(cl-case .type
|
||||
(goto-dest
|
||||
(unless (> .page 0)
|
||||
(error "Link points to nowhere")))
|
||||
(goto-remote
|
||||
(unless (and .filename (file-exists-p .filename))
|
||||
(error "Link points to nonexistent file %s" .filename))
|
||||
(setq window (display-buffer
|
||||
(or (find-buffer-visiting .filename)
|
||||
(find-file-noselect .filename))))))
|
||||
(with-selected-window window
|
||||
(when (derived-mode-p 'pdf-view-mode)
|
||||
(when (> .page 0)
|
||||
(pdf-view-goto-page .page))
|
||||
(when .top
|
||||
;; Showing the tooltip delays displaying the page for
|
||||
;; some reason (sit-for/redisplay don't help), do it
|
||||
;; later.
|
||||
(run-with-idle-timer 0.001 nil
|
||||
(lambda ()
|
||||
(when (window-live-p window)
|
||||
(with-selected-window window
|
||||
(when (derived-mode-p 'pdf-view-mode)
|
||||
(pdf-util-tooltip-arrow .top)))))))))))
|
||||
(uri
|
||||
(funcall pdf-links-browse-uri-function .uri))
|
||||
(t
|
||||
(error "Unrecognized link type: %s" .type)))
|
||||
nil))
|
||||
|
||||
(defun pdf-links-read-link-action (prompt)
|
||||
"Using PROMPT, interactively read a link-action.
|
||||
|
||||
See `pdf-links-action-perform' for the interface."
|
||||
|
||||
(pdf-util-assert-pdf-window)
|
||||
(let* ((links (pdf-cache-pagelinks
|
||||
(pdf-view-current-page)))
|
||||
(keys (pdf-links-read-link-action--create-keys
|
||||
(length links)))
|
||||
(key-strings (mapcar (apply-partially 'apply 'string)
|
||||
keys))
|
||||
(alist (cl-mapcar 'cons keys links))
|
||||
(size (pdf-view-image-size))
|
||||
(colors (pdf-util-face-colors
|
||||
'pdf-links-read-link pdf-view-dark-minor-mode))
|
||||
(args (list
|
||||
:foreground (car colors)
|
||||
:background (cdr colors)
|
||||
:formats
|
||||
`((?c . ,(lambda (_edges) (pop key-strings)))
|
||||
(?P . ,(number-to-string
|
||||
(max 1 (* (cdr size)
|
||||
pdf-links-convert-pointsize-scale)))))
|
||||
:commands pdf-links-read-link-convert-commands
|
||||
:apply (pdf-util-scale-relative-to-pixel
|
||||
(mapcar (lambda (l) (cdr (assq 'edges l)))
|
||||
links)))))
|
||||
(unless links
|
||||
(error "No links on this page"))
|
||||
(unwind-protect
|
||||
(let ((image-data
|
||||
(pdf-cache-get-image
|
||||
(pdf-view-current-page)
|
||||
(car size) (car size) 'pdf-links-read-link-action)))
|
||||
(unless image-data
|
||||
(setq image-data (apply 'pdf-util-convert-page args ))
|
||||
(pdf-cache-put-image
|
||||
(pdf-view-current-page)
|
||||
(car size) image-data 'pdf-links-read-link-action))
|
||||
(pdf-view-display-image
|
||||
(create-image image-data (pdf-view-image-type) t))
|
||||
(pdf-links-read-link-action--read-chars prompt alist))
|
||||
(pdf-view-redisplay))))
|
||||
|
||||
(defun pdf-links-read-link-action--read-chars (prompt alist)
|
||||
(catch 'done
|
||||
(let (key)
|
||||
(while t
|
||||
(let* ((chars (append (mapcar 'caar alist)
|
||||
(mapcar 'downcase (mapcar 'caar alist))
|
||||
(list ?\s)))
|
||||
(ch (read-char-choice prompt chars)))
|
||||
(setq ch (upcase ch))
|
||||
(cond
|
||||
((= ch ?\s)
|
||||
(when (= (window-vscroll) (image-scroll-up))
|
||||
(image-scroll-down (window-vscroll))))
|
||||
(t
|
||||
(setq alist (delq nil (mapcar (lambda (elt)
|
||||
(and (eq ch (caar elt))
|
||||
(cons (cdar elt)
|
||||
(cdr elt))))
|
||||
alist))
|
||||
key (append key (list ch))
|
||||
prompt (concat prompt (list ch)))
|
||||
(when (= (length alist) 1)
|
||||
(message nil)
|
||||
(throw 'done (cdar alist))))))))))
|
||||
|
||||
(defun pdf-links-read-link-action--create-keys (n)
|
||||
(when (> n 0)
|
||||
(let ((len (1+ (floor (log n 26))))
|
||||
keys)
|
||||
(dotimes (i n)
|
||||
(let (key)
|
||||
(dotimes (_x len)
|
||||
(push (+ (% i 26) ?A) key)
|
||||
(setq i (/ i 26)))
|
||||
(push key keys)))
|
||||
(nreverse keys))))
|
||||
|
||||
(defun pdf-links-isearch-link ()
|
||||
(interactive)
|
||||
(let* (quit-p
|
||||
(isearch-mode-end-hook
|
||||
(cons (lambda nil
|
||||
(setq quit-p isearch-mode-end-hook-quit))
|
||||
isearch-mode-end-hook))
|
||||
(pdf-isearch-filter-matches-function
|
||||
'pdf-links-isearch-link-filter-matches)
|
||||
(pdf-isearch-narrow-to-page t)
|
||||
(isearch-message-prefix-add "(Links)")
|
||||
pdf-isearch-batch-mode)
|
||||
(isearch-forward)
|
||||
(unless (or quit-p (null pdf-isearch-current-match))
|
||||
(let* ((page (pdf-view-current-page))
|
||||
(match (car pdf-isearch-current-match))
|
||||
(size (pdf-view-image-size))
|
||||
(links (sort (cl-remove-if
|
||||
(lambda (e)
|
||||
(= 0 (pdf-util-edges-intersection-area (car e) match)))
|
||||
(mapcar (lambda (l)
|
||||
(cons (pdf-util-scale (alist-get 'edges l) size)
|
||||
l))
|
||||
(pdf-cache-pagelinks page)))
|
||||
(lambda (e1 e2)
|
||||
(> (pdf-util-edges-intersection-area
|
||||
(alist-get 'edges e1) match)
|
||||
(pdf-util-edges-intersection-area
|
||||
(alist-get 'edges e2) match))))))
|
||||
(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)
|
||||
(pdf-cache-pagelinks
|
||||
(pdf-view-current-page)))
|
||||
(pdf-view-image-size))))
|
||||
(cl-remove-if-not
|
||||
(lambda (m)
|
||||
(cl-some
|
||||
(lambda (edges)
|
||||
(cl-some (lambda (link)
|
||||
(pdf-util-with-edges (link edges)
|
||||
(let ((area (min (* link-width link-height)
|
||||
(* edges-width edges-height))))
|
||||
(> (/ (pdf-util-edges-intersection-area edges link)
|
||||
(float area)) 0.5))))
|
||||
links))
|
||||
m))
|
||||
matches)))
|
||||
|
||||
(defun pdf-links-browse-uri-default (uri)
|
||||
"Open the string URI using Org.
|
||||
|
||||
Wraps the URI in \[\[ ... \]\] and calls `org-open-link-from-string'
|
||||
on the resulting string."
|
||||
(cl-check-type uri string)
|
||||
(message "Opening `%s' with Org" uri)
|
||||
(org-open-link-from-string (format "[[%s]]" uri)))
|
||||
|
||||
(provide 'pdf-links)
|
||||
|
||||
;;; pdf-links.el ends here
|
||||
283
elpa/pdf-tools-20180428.827/pdf-misc.el
Normal file
283
elpa/pdf-tools-20180428.827/pdf-misc.el
Normal file
@@ -0,0 +1,283 @@
|
||||
;;; pdf-misc.el --- Miscellaneous commands for PDF buffer.
|
||||
|
||||
;; Copyright (C) 2013, 2014 Andreas Politz
|
||||
|
||||
;; Author: Andreas Politz <politza@fh-trier.de>
|
||||
;; Keywords: files, multimedia
|
||||
|
||||
;; 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:
|
||||
;;
|
||||
|
||||
|
||||
(require 'pdf-view)
|
||||
(require 'pdf-util)
|
||||
(require 'imenu)
|
||||
|
||||
|
||||
|
||||
(defvar pdf-misc-minor-mode-map
|
||||
(let ((map (make-sparse-keymap)))
|
||||
(define-key map (kbd "I") 'pdf-misc-display-metadata)
|
||||
(define-key map (kbd "C-c C-p") 'pdf-misc-print-document)
|
||||
map)
|
||||
"Keymap used in `pdf-misc-minor-mode'.")
|
||||
|
||||
;;;###autoload
|
||||
(define-minor-mode pdf-misc-minor-mode
|
||||
"FIXME: Not documented."
|
||||
nil nil nil)
|
||||
|
||||
;;;###autoload
|
||||
(define-minor-mode pdf-misc-size-indication-minor-mode
|
||||
"Provide a working size indication in the mode-line."
|
||||
nil nil nil
|
||||
(pdf-util-assert-pdf-buffer)
|
||||
(cond
|
||||
(pdf-misc-size-indication-minor-mode
|
||||
(unless (assq 'pdf-misc-size-indication-minor-mode
|
||||
mode-line-position)
|
||||
(setq mode-line-position
|
||||
`((pdf-misc-size-indication-minor-mode
|
||||
(:eval (pdf-misc-size-indication)))
|
||||
,@mode-line-position))))
|
||||
(t
|
||||
(setq mode-line-position
|
||||
(cl-remove 'pdf-misc-size-indication-minor-mode
|
||||
mode-line-position :key 'car-safe)))))
|
||||
|
||||
(defun pdf-misc-size-indication ()
|
||||
"Return size indication string for the mode-line."
|
||||
(let ((top (= (window-vscroll nil t) 0))
|
||||
(bot (>= (+ (- (nth 3 (window-inside-pixel-edges))
|
||||
(nth 1 (window-inside-pixel-edges)))
|
||||
(window-vscroll nil t))
|
||||
(cdr (pdf-view-image-size t)))))
|
||||
(cond
|
||||
((and top bot) " All")
|
||||
(top " Top")
|
||||
(bot " Bot")
|
||||
(t (format
|
||||
" %d%%%%"
|
||||
(ceiling
|
||||
(* 100 (/ (float (window-vscroll nil t))
|
||||
(cdr (pdf-view-image-size t))))))))))
|
||||
|
||||
(defvar pdf-misc-menu-bar-minor-mode-map (make-sparse-keymap)
|
||||
"The keymap used in `pdf-misc-menu-bar-minor-mode'.")
|
||||
|
||||
(easy-menu-define nil pdf-misc-menu-bar-minor-mode-map
|
||||
"Menu for PDF Tools."
|
||||
`("PDF Tools"
|
||||
["Go Backward" pdf-history-backward
|
||||
:visible (bound-and-true-p pdf-history-minor-mode)
|
||||
:active (and (bound-and-true-p pdf-history-minor-mode)
|
||||
(not (pdf-history-end-of-history-p)))]
|
||||
["Go Forward" pdf-history-forward
|
||||
:visible (bound-and-true-p pdf-history-minor-mode)
|
||||
:active (not (pdf-history-end-of-history-p))]
|
||||
["--" nil
|
||||
:visible (derived-mode-p 'pdf-virtual-view-mode)]
|
||||
["Next file" pdf-virtual-buffer-forward-file
|
||||
:visible (derived-mode-p 'pdf-virtual-view-mode)
|
||||
:active (pdf-virtual-document-next-file
|
||||
(pdf-view-current-page))]
|
||||
["Previous file" pdf-virtual-buffer-backward-file
|
||||
:visible (derived-mode-p 'pdf-virtual-view-mode)
|
||||
:active (not (eq 1 (pdf-view-current-page)))]
|
||||
["--" nil
|
||||
:visible (bound-and-true-p pdf-history-minor-mode)]
|
||||
["Add text annotation" pdf-annot-mouse-add-text-annotation
|
||||
:visible (bound-and-true-p pdf-annot-minor-mode)
|
||||
:keys "\\[pdf-annot-add-text-annotation]"]
|
||||
("Add markup annotation"
|
||||
:active (pdf-view-active-region-p)
|
||||
:visible (and (bound-and-true-p pdf-annot-minor-mode)
|
||||
(pdf-info-markup-annotations-p))
|
||||
["highlight" pdf-annot-add-highlight-markup-annotation]
|
||||
["squiggly" pdf-annot-add-squiggly-markup-annotation]
|
||||
["underline" pdf-annot-add-underline-markup-annotation]
|
||||
["strikeout" pdf-annot-add-strikeout-markup-annotation])
|
||||
["--" nil :visible (bound-and-true-p pdf-annot-minor-mode)]
|
||||
["Display Annotations" pdf-annot-list-annotations
|
||||
:help "List all annotations"
|
||||
:visible (bound-and-true-p pdf-annot-minor-mode)]
|
||||
["Display Attachments" pdf-annot-attachment-dired
|
||||
:help "Display attachments in a dired buffer"
|
||||
:visible (featurep 'pdf-annot)]
|
||||
["Display Metadata" pdf-misc-display-metadata
|
||||
:help "Display information about the document"
|
||||
:visible (featurep 'pdf-misc)]
|
||||
["Display Outline" pdf-outline
|
||||
:help "Display documents outline"
|
||||
:visible (featurep 'pdf-outline)]
|
||||
"--"
|
||||
("Render Options"
|
||||
["Printed Mode" (lambda ()
|
||||
(interactive)
|
||||
(pdf-view-printer-minor-mode 'toggle))
|
||||
:style toggle
|
||||
:selected pdf-view-printer-minor-mode
|
||||
:help "Display the PDF as it would be printed."]
|
||||
["Midnight Mode" (lambda ()
|
||||
(interactive)
|
||||
(pdf-view-midnight-minor-mode 'toggle))
|
||||
:style toggle
|
||||
:selected pdf-view-midnight-minor-mode
|
||||
:help "Apply a color-filter appropriate for past midnight reading."])
|
||||
"--"
|
||||
["Copy region" pdf-view-kill-ring-save
|
||||
:keys "\\[kill-ring-save]"
|
||||
:active (pdf-view-active-region-p)]
|
||||
"--"
|
||||
["Isearch document" isearch-forward
|
||||
:visible (bound-and-true-p pdf-isearch-minor-mode)]
|
||||
["Occur document" pdf-occur
|
||||
:visible (featurep 'pdf-occur)]
|
||||
"--"
|
||||
["Locate TeX source" pdf-sync-backward-search-mouse
|
||||
:visible (and (featurep 'pdf-sync)
|
||||
(equal last-command-event
|
||||
last-nonmenu-event))]
|
||||
["--" nil :visible (and (featurep 'pdf-sync)
|
||||
(equal last-command-event
|
||||
last-nonmenu-event))]
|
||||
["Print" pdf-misc-print-document
|
||||
:active (and (pdf-view-buffer-file-name)
|
||||
(file-readable-p (pdf-view-buffer-file-name)))]
|
||||
["Create image" pdf-view-extract-region-image
|
||||
:help "Create an image of the page or the selected region(s)."]
|
||||
["Create virtual PDF" pdf-virtual-buffer-create
|
||||
:help "Create a PDF containing all documents in this directory."
|
||||
:visible (bound-and-true-p pdf-virtual-global-minor-mode)]
|
||||
"--"
|
||||
["Revert buffer" pdf-view-revert-buffer
|
||||
:visible (pdf-info-writable-annotations-p)]
|
||||
"--"
|
||||
["Customize" pdf-tools-customize]))
|
||||
|
||||
;;;###autoload
|
||||
(define-minor-mode pdf-misc-menu-bar-minor-mode
|
||||
"Display a PDF Tools menu in the menu-bar."
|
||||
nil nil nil
|
||||
(pdf-util-assert-pdf-buffer))
|
||||
|
||||
(defvar pdf-misc-context-menu-minor-mode-map
|
||||
(let ((kmap (make-sparse-keymap)))
|
||||
(define-key kmap [down-mouse-3] 'pdf-misc-popup-context-menu)
|
||||
kmap))
|
||||
|
||||
;;;###autoload
|
||||
(define-minor-mode pdf-misc-context-menu-minor-mode
|
||||
"Provide a right-click context menu in PDF buffers.
|
||||
|
||||
\\{pdf-misc-context-menu-minor-mode-map}"
|
||||
nil nil nil
|
||||
(pdf-util-assert-pdf-buffer))
|
||||
|
||||
(defun pdf-misc-popup-context-menu (event)
|
||||
"Popup a context menu at position determined by EVENT."
|
||||
(interactive "@e")
|
||||
(popup-menu
|
||||
(cons 'keymap
|
||||
(cddr (lookup-key pdf-misc-menu-bar-minor-mode-map
|
||||
[menu-bar PDF\ Tools])))))
|
||||
|
||||
(defun pdf-misc-display-metadata ()
|
||||
"Display all available metadata in a separate buffer."
|
||||
(interactive)
|
||||
(pdf-util-assert-pdf-buffer)
|
||||
(let* ((buffer (current-buffer))
|
||||
(md (pdf-info-metadata)))
|
||||
(with-current-buffer (get-buffer-create "*PDF-Metadata*")
|
||||
(let* ((inhibit-read-only t)
|
||||
(pad (apply' max (mapcar (lambda (d)
|
||||
(length (symbol-name (car d))))
|
||||
md)))
|
||||
(fmt (format "%%%ds:%%s\n" pad))
|
||||
window)
|
||||
(erase-buffer)
|
||||
(setq header-line-format (buffer-name buffer)
|
||||
buffer-read-only t)
|
||||
(font-lock-mode 1)
|
||||
(font-lock-add-keywords nil
|
||||
'(("^ *\\(\\(?:\\w\\|-\\)+\\):"
|
||||
(1 font-lock-keyword-face))))
|
||||
(dolist (d md)
|
||||
(let ((key (car d))
|
||||
(val (cdr d)))
|
||||
(cl-case key
|
||||
(keywords
|
||||
(setq val (mapconcat 'identity val ", "))))
|
||||
(let ((beg (+ (length (symbol-name key)) (point) 1))
|
||||
(fill-prefix
|
||||
(make-string (1+ pad) ?\s)))
|
||||
(insert (format fmt key val))
|
||||
(fill-region beg (point) )))))
|
||||
(goto-char 1)
|
||||
(display-buffer (current-buffer)))
|
||||
md))
|
||||
|
||||
(defgroup pdf-misc nil
|
||||
"Miscellaneous options for PDF documents."
|
||||
:group 'pdf-tools)
|
||||
|
||||
(defcustom pdf-misc-print-programm nil
|
||||
"The program used for printing.
|
||||
|
||||
It is called with one argument, the PDF file."
|
||||
:group 'pdf-misc
|
||||
:type 'file)
|
||||
|
||||
(defcustom pdf-misc-print-programm-args nil
|
||||
"List of additional arguments passed to `pdf-misc-print-program'."
|
||||
:group 'pdf-misc
|
||||
:type '(repeat string))
|
||||
|
||||
(defun pdf-misc-print-programm (&optional interactive-p)
|
||||
(or (and pdf-misc-print-programm
|
||||
(executable-find pdf-misc-print-programm))
|
||||
(when interactive-p
|
||||
(let* ((default (car (delq nil (mapcar
|
||||
'executable-find
|
||||
'("gtklp" "xpp" "gpr")))))
|
||||
buffer-file-name
|
||||
(programm
|
||||
(expand-file-name
|
||||
(read-file-name
|
||||
"Print with: " default nil t nil 'file-executable-p))))
|
||||
(when (and programm
|
||||
(executable-find programm))
|
||||
(when (y-or-n-p "Save choice using customize ?")
|
||||
(customize-save-variable
|
||||
'pdf-misc-print-programm programm))
|
||||
(setq pdf-misc-print-programm programm))))))
|
||||
|
||||
(defun pdf-misc-print-document (filename &optional interactive-p)
|
||||
(interactive
|
||||
(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))))
|
||||
(unless programm
|
||||
(error "No print program available"))
|
||||
(apply #'start-process "printing" nil programm args)
|
||||
(message "Print job started: %s %s"
|
||||
programm (mapconcat #'identity args " "))))
|
||||
|
||||
|
||||
(provide 'pdf-misc)
|
||||
|
||||
;;; pdf-misc.el ends here
|
||||
826
elpa/pdf-tools-20180428.827/pdf-occur.el
Normal file
826
elpa/pdf-tools-20180428.827/pdf-occur.el
Normal file
@@ -0,0 +1,826 @@
|
||||
;;; pdf-occur.el --- Display matching lines of PDF documents. -*- lexical-binding: t -*-
|
||||
|
||||
;; Copyright (C) 2013, 2014 Andreas Politz
|
||||
|
||||
;; Author: Andreas Politz <politza@fh-trier.de>
|
||||
;; Keywords: files, multimedia
|
||||
|
||||
;; 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:
|
||||
;;
|
||||
|
||||
(require 'pdf-tools)
|
||||
(require 'pdf-view)
|
||||
(require 'pdf-util)
|
||||
(require 'pdf-info)
|
||||
(require 'pdf-isearch)
|
||||
(require 'tablist)
|
||||
(require 'ibuf-ext)
|
||||
(require 'dired)
|
||||
(require 'let-alist)
|
||||
|
||||
;;; Code:
|
||||
|
||||
|
||||
|
||||
|
||||
;; * ================================================================== *
|
||||
;; * Custom & Variables
|
||||
;; * ================================================================== *
|
||||
|
||||
(defgroup pdf-occur nil
|
||||
"Display matching lines of PDF documents."
|
||||
:group 'pdf-tools)
|
||||
|
||||
(defface pdf-occur-document-face
|
||||
'((default (:inherit font-lock-string-face)))
|
||||
"Face used to highlight documents in the list buffer."
|
||||
:group 'pdf-occur)
|
||||
|
||||
(defface pdf-occur-page-face
|
||||
'((default (:inherit font-lock-type-face)))
|
||||
"Face used to highlight page numbers in the list buffer."
|
||||
:group 'pdf-occur)
|
||||
|
||||
(defcustom pdf-occur-search-batch-size 16
|
||||
"Maximum number of pages searched in one query.
|
||||
|
||||
Lower numbers will make Emacs more responsive when searching at
|
||||
the cost of slightly increased search time."
|
||||
:group 'pdf-occur
|
||||
:type 'integer)
|
||||
|
||||
(defcustom pdf-occur-prefer-string-search nil
|
||||
"If non-nil, reverse the meaning of the regexp-p prefix-arg."
|
||||
:group 'pdf-occur
|
||||
:type 'boolean)
|
||||
|
||||
(defvar pdf-occur-history nil
|
||||
"The history variable for search strings.")
|
||||
|
||||
(defvar pdf-occur-search-pages-left nil
|
||||
"The total number of pages left to search.")
|
||||
|
||||
(defvar pdf-occur-search-documents nil
|
||||
"The list of searched documents.
|
||||
|
||||
Each element should be either the filename of a PDF document or a
|
||||
cons \(FILENAME . PAGES\), where PAGES is the list of pages to
|
||||
search. See `pdf-info-normalize-page-range' for it's format.")
|
||||
|
||||
(defvar pdf-occur-number-of-matches 0
|
||||
"The number of matches in all searched documents.")
|
||||
|
||||
(defvar pdf-occur-search-string nil
|
||||
"The currently used search string, resp. regexp.")
|
||||
|
||||
(defvar pdf-occur-search-regexp-p nil
|
||||
"Non-nil, if searching for a regexp.")
|
||||
|
||||
(defvar pdf-occur-buffer-mode-map
|
||||
(let ((kmap (make-sparse-keymap)))
|
||||
(set-keymap-parent kmap tablist-mode-map)
|
||||
(define-key kmap (kbd "RET") 'pdf-occur-goto-occurrence)
|
||||
(define-key kmap (kbd "C-o") 'pdf-occur-view-occurrence)
|
||||
(define-key kmap (kbd "SPC") 'pdf-occur-view-occurrence)
|
||||
(define-key kmap (kbd "C-c C-f") 'next-error-follow-minor-mode)
|
||||
(define-key kmap (kbd "g") 'pdf-occur-revert-buffer-with-args)
|
||||
(define-key kmap (kbd "K") 'pdf-occur-abort-search)
|
||||
(define-key kmap (kbd "D") 'pdf-occur-tablist-do-delete)
|
||||
(define-key kmap (kbd "x") 'pdf-occur-tablist-do-flagged-delete)
|
||||
(define-key kmap (kbd "A") 'pdf-occur-tablist-gather-documents)
|
||||
kmap)
|
||||
"The keymap used for `pdf-occur-buffer-mode'.")
|
||||
|
||||
|
||||
;; * ================================================================== *
|
||||
;; * High level functions
|
||||
;; * ================================================================== *
|
||||
|
||||
(define-derived-mode pdf-occur-buffer-mode tablist-mode "PDFOccur"
|
||||
"Major mode for output from `pdf-occur`. \\<pdf-occur-buffer-mode-map>
|
||||
|
||||
Some useful keys are:
|
||||
|
||||
\\[pdf-occur-abort-search] - Abort the search.
|
||||
\\[pdf-occur-revert-buffer-with-args] - Restart the search.
|
||||
\\[universal-argument] \\[pdf-occur-revert-buffer-with-args] - Restart search with different regexp.
|
||||
\\[universal-argument] \\[universal-argument] \\[pdf-occur-revert-buffer-with-args] - Same, but do a plain string search.
|
||||
|
||||
\\[tablist-push-regexp-filter] - Filter matches by regexp on current or prefix-th column.
|
||||
\\[tablist-pop-filter] - Remove last added filter.
|
||||
|
||||
\\[pdf-occur-tablist-do-delete] - Remove the current file from the search.
|
||||
\\[pdf-occur-tablist-gather-documents] - Include marked files from displayed `dired'/`ibuffer' and
|
||||
`pdf-view-mode' buffers in the search.
|
||||
|
||||
\\{pdf-occur-buffer-mode-map}"
|
||||
(setq-local next-error-function 'pdf-occur-next-error)
|
||||
(setq-local revert-buffer-function
|
||||
'pdf-occur-revert-buffer)
|
||||
(setq next-error-last-buffer (current-buffer))
|
||||
(setq-local tabulated-list-sort-key nil)
|
||||
(setq-local tabulated-list-use-header-line t)
|
||||
(setq-local tablist-operations-function
|
||||
(lambda (op &rest _)
|
||||
(cl-case op
|
||||
(supported-operations '(find-entry))
|
||||
(find-entry
|
||||
(let ((display-buffer-overriding-action
|
||||
'(display-buffer-same-window)))
|
||||
(pdf-occur-goto-occurrence)))))))
|
||||
|
||||
;;;###autoload
|
||||
(defun pdf-occur (string &optional regexp-p)
|
||||
"List lines matching STRING or PCRE.
|
||||
|
||||
Interactively search for a regexp. Unless a prefix arg was given,
|
||||
in which case this functions performs a string search.
|
||||
|
||||
If `pdf-occur-prefer-string-search' is non-nil, the meaning of
|
||||
the prefix-arg is inverted."
|
||||
(interactive
|
||||
(progn
|
||||
(pdf-util-assert-pdf-buffer)
|
||||
(list
|
||||
(pdf-occur-read-string
|
||||
(pdf-occur-want-regexp-search-p))
|
||||
(pdf-occur-want-regexp-search-p))))
|
||||
(pdf-util-assert-pdf-buffer)
|
||||
(pdf-occur-search (list (current-buffer)) string regexp-p))
|
||||
|
||||
(defvar ibuffer-filtering-qualifiers)
|
||||
;;;###autoload
|
||||
(defun pdf-occur-multi-command ()
|
||||
"Perform `pdf-occur' on multiple buffer.
|
||||
|
||||
For a programmatic search of multiple documents see
|
||||
`pdf-occur-search'."
|
||||
(interactive)
|
||||
(ibuffer)
|
||||
(with-current-buffer "*Ibuffer*"
|
||||
(pdf-occur-ibuffer-minor-mode)
|
||||
(unless (member '(derived-mode . pdf-view-mode)
|
||||
ibuffer-filtering-qualifiers)
|
||||
(ibuffer-filter-by-derived-mode 'pdf-view-mode))
|
||||
(message
|
||||
"%s"
|
||||
(substitute-command-keys
|
||||
"Mark a bunch of PDF buffers and type \\[pdf-occur-ibuffer-do-occur]"))
|
||||
(sit-for 3)))
|
||||
|
||||
(defun pdf-occur-revert-buffer (&rest _)
|
||||
"Restart the search."
|
||||
(pdf-occur-assert-occur-buffer-p)
|
||||
(unless pdf-occur-search-documents
|
||||
(error "No documents to search"))
|
||||
(unless pdf-occur-search-string
|
||||
(error "Nothing to search for"))
|
||||
(let* ((2-columns-p (= 1 (length pdf-occur-search-documents)))
|
||||
(filename-width
|
||||
(min 24
|
||||
(apply 'max
|
||||
(mapcar 'length
|
||||
(mapcar 'pdf-occur-abbrev-document
|
||||
(mapcar 'car pdf-occur-search-documents))))))
|
||||
(page-sorter (tablist-generate-sorter
|
||||
(if 2-columns-p 0 1)
|
||||
'<
|
||||
'string-to-number)))
|
||||
(setq tabulated-list-format
|
||||
(if 2-columns-p
|
||||
`[("Page" 4 ,page-sorter :right-align t)
|
||||
("Line" 0 t)]
|
||||
`[("Document" ,filename-width t)
|
||||
("Page" 4 ,page-sorter :right-align t)
|
||||
("Line" 0 t)])
|
||||
tabulated-list-entries nil))
|
||||
(tabulated-list-revert)
|
||||
(pdf-occur-start-search
|
||||
pdf-occur-search-documents
|
||||
pdf-occur-search-string
|
||||
pdf-occur-search-regexp-p)
|
||||
(pdf-occur-update-header-line)
|
||||
(setq mode-line-process
|
||||
'(:propertize ":run" face compilation-mode-line-run)))
|
||||
|
||||
(defun pdf-occur-revert-buffer-with-args (string &optional regexp-p documents)
|
||||
"Restart the search with modified arguments.
|
||||
|
||||
Interactively just restart the search, unless a prefix was given.
|
||||
In this case read a new search string. With `C-u C-u' as prefix
|
||||
additionally invert the current state of
|
||||
`pdf-occur-search-regexp-p'."
|
||||
(interactive
|
||||
(progn
|
||||
(pdf-occur-assert-occur-buffer-p)
|
||||
(cond
|
||||
(current-prefix-arg
|
||||
(let ((regexp-p
|
||||
(if (equal current-prefix-arg '(16))
|
||||
(not pdf-occur-search-regexp-p)
|
||||
pdf-occur-search-regexp-p)))
|
||||
(list
|
||||
(pdf-occur-read-string regexp-p)
|
||||
regexp-p)))
|
||||
(t
|
||||
(list pdf-occur-search-string
|
||||
pdf-occur-search-regexp-p)))))
|
||||
(setq pdf-occur-search-string string
|
||||
pdf-occur-search-regexp-p regexp-p)
|
||||
(when documents
|
||||
(setq pdf-occur-search-documents
|
||||
(pdf-occur-normalize-documents documents)))
|
||||
(pdf-occur-revert-buffer))
|
||||
|
||||
(defun pdf-occur-abort-search ()
|
||||
"Abort the current search.
|
||||
|
||||
This immediately kills the search process."
|
||||
(interactive)
|
||||
(unless (pdf-occur-search-in-progress-p)
|
||||
(user-error "No search in progress"))
|
||||
(pdf-info-kill-local-server)
|
||||
(pdf-occur-search-finished t))
|
||||
|
||||
|
||||
;; * ================================================================== *
|
||||
;; * Finding occurrences
|
||||
;; * ================================================================== *
|
||||
|
||||
|
||||
(defun pdf-occur-goto-occurrence (&optional no-select-window-p)
|
||||
"Go to the occurrence at point.
|
||||
|
||||
If EVENT is nil, use occurrence at current line. Select the
|
||||
PDF's window, unless NO-SELECT-WINDOW-P is non-nil.
|
||||
|
||||
FIXME: EVENT not used at the moment."
|
||||
(interactive)
|
||||
(let ((item (tabulated-list-get-id)))
|
||||
(when item
|
||||
(let* ((doc (plist-get item :document))
|
||||
(page (plist-get item :page))
|
||||
(match (plist-get item :match-edges))
|
||||
(buffer (if (bufferp doc)
|
||||
doc
|
||||
(or (find-buffer-visiting doc)
|
||||
(find-file-noselect doc))))
|
||||
window)
|
||||
(if no-select-window-p
|
||||
(setq window (display-buffer buffer))
|
||||
(pop-to-buffer buffer)
|
||||
(setq window (selected-window)))
|
||||
(with-selected-window window
|
||||
(when page
|
||||
(pdf-view-goto-page page))
|
||||
;; Abuse isearch.
|
||||
(when match
|
||||
(let ((pixel-match
|
||||
(pdf-util-scale-relative-to-pixel match))
|
||||
(pdf-isearch-batch-mode t))
|
||||
(pdf-isearch-hl-matches pixel-match nil t)
|
||||
(pdf-isearch-focus-match-batch pixel-match))))))))
|
||||
|
||||
(defun pdf-occur-view-occurrence (&optional _event)
|
||||
"View the occurrence at EVENT.
|
||||
|
||||
If EVENT is nil, use occurrence at current line."
|
||||
(interactive (list last-nonmenu-event))
|
||||
(pdf-occur-goto-occurrence t))
|
||||
|
||||
(defun pdf-occur-next-error (&optional arg reset)
|
||||
"Move to the Nth (default 1) next match in an PDF Occur mode buffer.
|
||||
Compatibility function for \\[next-error] invocations."
|
||||
(interactive "p")
|
||||
;; we need to run pdf-occur-find-match from within the Occur buffer
|
||||
(with-current-buffer
|
||||
;; Choose the buffer and make it current.
|
||||
(if (next-error-buffer-p (current-buffer))
|
||||
(current-buffer)
|
||||
(next-error-find-buffer
|
||||
nil nil
|
||||
(lambda ()
|
||||
(eq major-mode 'pdf-occur-buffer-mode))))
|
||||
(when (bobp)
|
||||
(setq reset t))
|
||||
(if reset
|
||||
(goto-char (point-min))
|
||||
(beginning-of-line))
|
||||
(when (/= arg 0)
|
||||
(when (eobp)
|
||||
(forward-line -1))
|
||||
(when reset
|
||||
(cl-decf arg))
|
||||
(let ((line (line-number-at-pos))
|
||||
(limit (line-number-at-pos
|
||||
(if (>= arg 0)
|
||||
(1- (point-max))
|
||||
(point-min)))))
|
||||
(when (= line limit)
|
||||
(error "No more matches"))
|
||||
(forward-line
|
||||
(if (>= arg 0)
|
||||
(min arg (- limit line))
|
||||
(max arg (- limit line))))))
|
||||
;; In case the *Occur* buffer is visible in a nonselected window.
|
||||
(tablist-move-to-major-column)
|
||||
(let ((win (get-buffer-window (current-buffer) t)))
|
||||
(if win (set-window-point win (point))))
|
||||
(pdf-occur-goto-occurrence)))
|
||||
|
||||
|
||||
;; * ================================================================== *
|
||||
;; * Integration with other modes
|
||||
;; * ================================================================== *
|
||||
|
||||
;;;###autoload
|
||||
(define-minor-mode pdf-occur-global-minor-mode
|
||||
"Enable integration of Pdf Occur with other modes.
|
||||
|
||||
This global minor mode enables (or disables)
|
||||
`pdf-occur-ibuffer-minor-mode' and `pdf-occur-dired-minor-mode'
|
||||
in all current and future ibuffer/dired buffer." nil nil nil
|
||||
:global t
|
||||
(let ((arg (if pdf-occur-global-minor-mode 1 -1)))
|
||||
(dolist (buf (buffer-list))
|
||||
(with-current-buffer buf
|
||||
(cond
|
||||
((derived-mode-p 'dired-mode)
|
||||
(pdf-occur-dired-minor-mode arg))
|
||||
((derived-mode-p 'ibuffer-mode)
|
||||
(pdf-occur-ibuffer-minor-mode arg)))))
|
||||
(cond
|
||||
(pdf-occur-global-minor-mode
|
||||
(add-hook 'dired-mode-hook 'pdf-occur-dired-minor-mode)
|
||||
(add-hook 'ibuffer-mode-hook 'pdf-occur-ibuffer-minor-mode))
|
||||
(t
|
||||
(remove-hook 'dired-mode-hook 'pdf-occur-dired-minor-mode)
|
||||
(remove-hook 'ibuffer-mode-hook 'pdf-occur-ibuffer-minor-mode)))))
|
||||
|
||||
(defvar pdf-occur-ibuffer-minor-mode-map
|
||||
(let ((map (make-sparse-keymap)))
|
||||
(define-key map [remap ibuffer-do-occur] 'pdf-occur-ibuffer-do-occur)
|
||||
map)
|
||||
"Keymap used in `pdf-occur-ibuffer-minor-mode'.")
|
||||
|
||||
;;;###autoload
|
||||
(define-minor-mode pdf-occur-ibuffer-minor-mode
|
||||
"Hack into ibuffer's do-occur binding.
|
||||
|
||||
This mode remaps `ibuffer-do-occur' to
|
||||
`pdf-occur-ibuffer-do-occur', which will start the PDF Tools
|
||||
version of `occur', if all marked buffer's are in `pdf-view-mode'
|
||||
and otherwise fallback to `ibuffer-do-occur'."
|
||||
|
||||
nil nil nil)
|
||||
|
||||
(defun pdf-occur-ibuffer-do-occur (&optional regexp-p)
|
||||
"Uses `pdf-occur-search', if appropriate.
|
||||
|
||||
I.e. all marked buffers are in PDFView mode."
|
||||
(interactive
|
||||
(list (pdf-occur-want-regexp-search-p)))
|
||||
(let* ((buffer (or (ibuffer-get-marked-buffers)
|
||||
(and (ibuffer-current-buffer)
|
||||
(list (ibuffer-current-buffer)))))
|
||||
(pdf-only-p (cl-every
|
||||
(lambda (buf)
|
||||
(with-current-buffer buf
|
||||
(derived-mode-p 'pdf-view-mode)))
|
||||
buffer)))
|
||||
(if (not pdf-only-p)
|
||||
(call-interactively 'ibuffer-do-occur)
|
||||
(let ((regexp (pdf-occur-read-string regexp-p)))
|
||||
(pdf-occur-search buffer regexp regexp-p)))))
|
||||
|
||||
(defvar pdf-occur-dired-minor-mode-map
|
||||
(let ((map (make-sparse-keymap)))
|
||||
(define-key map [remap dired-do-search] 'pdf-occur-dired-do-search)
|
||||
map)
|
||||
"Keymap used in `pdf-occur-dired-minor-mode'.")
|
||||
|
||||
;;;###autoload
|
||||
(define-minor-mode pdf-occur-dired-minor-mode
|
||||
"Hack into dired's `dired-do-search' binding.
|
||||
|
||||
This mode remaps `dired-do-search' to
|
||||
`pdf-occur-dired-do-search', which will start the PDF Tools
|
||||
version of `occur', if all marked buffer's are in `pdf-view-mode'
|
||||
and otherwise fallback to `dired-do-search'."
|
||||
|
||||
nil nil nil)
|
||||
|
||||
(defun pdf-occur-dired-do-search ()
|
||||
"Uses `pdf-occur-search', if appropriate.
|
||||
|
||||
I.e. all marked files look like PDF documents."
|
||||
(interactive)
|
||||
(let ((files (dired-get-marked-files)))
|
||||
(if (not (cl-every (lambda (file)
|
||||
(string-match-p
|
||||
(car pdf-tools-auto-mode-alist-entry)
|
||||
file))
|
||||
files))
|
||||
(call-interactively 'dired-do-search)
|
||||
(let* ((regex-p (pdf-occur-want-regexp-search-p))
|
||||
(regexp (pdf-occur-read-string regex-p)))
|
||||
(pdf-occur-search files regexp regex-p)))))
|
||||
|
||||
|
||||
|
||||
;; * ================================================================== *
|
||||
;; * Search engine
|
||||
;; * ================================================================== *
|
||||
|
||||
|
||||
(defun pdf-occur-search (documents string &optional regexp-p)
|
||||
"Search DOCUMENTS for STRING.
|
||||
|
||||
DOCUMENTS should be a list of buffers (objects, not names),
|
||||
filenames or conses \(BUFFER-OR-FILENAME . PAGES\), where PAGES
|
||||
determines the scope of the search of the respective document.
|
||||
See `pdf-info-normalize-page-range' for it's format.
|
||||
|
||||
STRING is either the string to search for or, if REGEXP-P is
|
||||
non-nil, a Perl compatible regular expression (PCRE).
|
||||
|
||||
Display the occur buffer and start the search asynchronously.
|
||||
|
||||
Returns the window where the buffer is displayed."
|
||||
|
||||
(unless documents
|
||||
(error "No documents to search"))
|
||||
(when (or (null string) (= (length string) 0))
|
||||
(error "Not searching for the empty string"))
|
||||
(with-current-buffer (get-buffer-create "*PDF-Occur*")
|
||||
(pdf-occur-buffer-mode)
|
||||
(setq-local pdf-occur-search-documents
|
||||
(pdf-occur-normalize-documents documents))
|
||||
(setq-local pdf-occur-search-string string)
|
||||
(setq-local pdf-occur-search-regexp-p regexp-p)
|
||||
(setq-local pdf-occur-search-pages-left 0)
|
||||
(setq-local pdf-occur-number-of-matches 0)
|
||||
(pdf-occur-revert-buffer)
|
||||
(display-buffer
|
||||
(current-buffer))))
|
||||
|
||||
(defadvice tabulated-list-init-header (after update-header activate)
|
||||
"We want our own headers, thank you."
|
||||
(when (derived-mode-p 'pdf-occur-buffer-mode)
|
||||
(save-current-buffer
|
||||
(with-no-warnings (pdf-occur-update-header-line)))))
|
||||
|
||||
(defun pdf-occur-create-entry (filename page &optional match)
|
||||
"Create a `tabulated-list-entries' entry for a search result.
|
||||
|
||||
If match is nil, create a fake entry for documents w/o any
|
||||
matches linked with PAGE."
|
||||
(let* ((text (or (car match) "[No matches]"))
|
||||
(edges (cdr match))
|
||||
(displayed-text
|
||||
(if match
|
||||
(replace-regexp-in-string "\n" "\\n" text t t)
|
||||
(propertize text 'face 'font-lock-warning-face)))
|
||||
(displayed-page
|
||||
(if match
|
||||
(propertize (format "%d" page)
|
||||
'face 'pdf-occur-page-face)
|
||||
""))
|
||||
(displayed-document
|
||||
(propertize
|
||||
(pdf-occur-abbrev-document filename)
|
||||
'face 'pdf-occur-document-face))
|
||||
(id `(:document ,filename
|
||||
:page ,page
|
||||
:match-text ,(if match text)
|
||||
:match-edges ,(if match edges))))
|
||||
(list id
|
||||
(if (= (length pdf-occur-search-documents) 1)
|
||||
(vector displayed-page displayed-text)
|
||||
(vector displayed-document
|
||||
displayed-page
|
||||
displayed-text)))))
|
||||
|
||||
(defun pdf-occur-update-header-line ()
|
||||
(pdf-occur-assert-occur-buffer-p)
|
||||
(save-current-buffer
|
||||
;;force-mode-line-update seems to sometimes spuriously change the
|
||||
;;current buffer.
|
||||
(setq header-line-format
|
||||
`(:eval (concat
|
||||
(if (= (length pdf-occur-search-documents) 1)
|
||||
(format "%d match%s in document `%s'"
|
||||
pdf-occur-number-of-matches
|
||||
(if (/= 1 pdf-occur-number-of-matches) "es" "")
|
||||
(pdf-occur-abbrev-document
|
||||
(caar pdf-occur-search-documents)))
|
||||
(format "%d match%s in %d documents"
|
||||
pdf-occur-number-of-matches
|
||||
(if (/= 1 pdf-occur-number-of-matches) "es" "")
|
||||
(length pdf-occur-search-documents)))
|
||||
(if (pdf-occur-search-in-progress-p)
|
||||
(propertize
|
||||
(concat " ["
|
||||
(if (numberp pdf-occur-search-pages-left)
|
||||
(format "%d pages left"
|
||||
pdf-occur-search-pages-left)
|
||||
"Searching")
|
||||
"]")
|
||||
'face 'compilation-mode-line-run)))))
|
||||
(force-mode-line-update)))
|
||||
|
||||
(defun pdf-occur-search-finished (&optional abort-p)
|
||||
(setq pdf-occur-search-pages-left 0)
|
||||
(setq mode-line-process
|
||||
(if abort-p
|
||||
'(:propertize
|
||||
":aborted" face compilation-mode-line-fail)
|
||||
'(:propertize
|
||||
":exit" face compilation-mode-line-exit)))
|
||||
(let ((unmatched
|
||||
(mapcar (lambda (doc)
|
||||
(pdf-occur-create-entry doc 1))
|
||||
(cl-set-difference
|
||||
(mapcar 'car
|
||||
pdf-occur-search-documents)
|
||||
(mapcar (lambda (elt)
|
||||
(plist-get (car elt) :document))
|
||||
tabulated-list-entries)
|
||||
:test 'equal))))
|
||||
(when (and unmatched
|
||||
(> (length pdf-occur-search-documents) 1))
|
||||
(pdf-occur-insert-entries unmatched)))
|
||||
(tablist-apply-filter)
|
||||
(pdf-occur-update-header-line)
|
||||
(pdf-isearch-message
|
||||
(if abort-p
|
||||
"Search aborted."
|
||||
(format "Occur search finished with %d matches"
|
||||
pdf-occur-number-of-matches))))
|
||||
|
||||
(defun pdf-occur-add-matches (filename matches)
|
||||
(pdf-occur-assert-occur-buffer-p)
|
||||
(when matches
|
||||
(let (entries)
|
||||
(dolist (match matches)
|
||||
(let-alist match
|
||||
(push (pdf-occur-create-entry filename .page (cons .text .edges))
|
||||
entries)))
|
||||
(setq entries (nreverse entries))
|
||||
(pdf-occur-insert-entries entries))))
|
||||
|
||||
(defun pdf-occur-insert-entries (entries)
|
||||
"Insert tabulated-list ENTRIES at the end."
|
||||
(pdf-occur-assert-occur-buffer-p)
|
||||
(let ((inhibit-read-only t)
|
||||
(end-of-buffer (and (eobp) (not (bobp)))))
|
||||
(save-excursion
|
||||
(goto-char (point-max))
|
||||
(dolist (elt entries)
|
||||
(apply tabulated-list-printer elt))
|
||||
(set-buffer-modified-p nil))
|
||||
(when end-of-buffer
|
||||
(dolist (win (get-buffer-window-list))
|
||||
(set-window-point win (point-max))))
|
||||
(setq tabulated-list-entries
|
||||
(append tabulated-list-entries
|
||||
entries))))
|
||||
|
||||
(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)
|
||||
(pdf-info-make-local-server nil t)
|
||||
(let ((batches (pdf-occur-create-batches
|
||||
documents (or pdf-occur-search-batch-size 1))))
|
||||
(pdf-info-local-batch-query
|
||||
(lambda (document pages)
|
||||
(if regexp-p
|
||||
(pdf-info-search-regexp string pages nil document)
|
||||
(pdf-info-search-string string pages document)))
|
||||
(lambda (status response document pages)
|
||||
(if status
|
||||
(error "%s" response)
|
||||
(when (numberp pdf-occur-search-pages-left)
|
||||
(cl-decf pdf-occur-search-pages-left
|
||||
(1+ (- (cdr pages) (car pages)))))
|
||||
(when (cl-member document pdf-occur-search-documents
|
||||
:key 'car
|
||||
:test 'equal)
|
||||
(cl-incf pdf-occur-number-of-matches
|
||||
(length response))
|
||||
(pdf-occur-add-matches document response)
|
||||
(pdf-occur-update-header-line))))
|
||||
(lambda (status buffer)
|
||||
(when (buffer-live-p buffer)
|
||||
(with-current-buffer buffer
|
||||
(pdf-occur-search-finished (eq status 'killed)))))
|
||||
batches)
|
||||
(setq pdf-occur-number-of-matches 0)
|
||||
(setq pdf-occur-search-pages-left
|
||||
(apply '+ (mapcar (lambda (elt)
|
||||
(1+ (- (cdr (nth 1 elt))
|
||||
(car (nth 1 elt)))))
|
||||
batches)))))
|
||||
|
||||
|
||||
|
||||
;; * ================================================================== *
|
||||
;; * Editing searched documents
|
||||
;; * ================================================================== *
|
||||
|
||||
(defun pdf-occur-tablist-do-delete (&optional arg)
|
||||
"Delete ARG documents from the search list."
|
||||
(interactive "P")
|
||||
(when (pdf-occur-search-in-progress-p)
|
||||
(user-error "Can't delete while a search is in progress."))
|
||||
(let* ((items (tablist-get-marked-items arg))
|
||||
(documents (cl-remove-duplicates
|
||||
(mapcar (lambda (entry)
|
||||
(plist-get (car entry) :document))
|
||||
items)
|
||||
:test 'equal)))
|
||||
(unless documents
|
||||
(error "No documents selected"))
|
||||
(when (tablist-yes-or-no-p
|
||||
'Stop\ searching
|
||||
nil (mapcar (lambda (d) (cons nil (vector d)))
|
||||
documents))
|
||||
(setq pdf-occur-search-documents
|
||||
(cl-remove-if (lambda (elt)
|
||||
(member (car elt) documents))
|
||||
pdf-occur-search-documents)
|
||||
tabulated-list-entries
|
||||
(cl-remove-if (lambda (elt)
|
||||
(when (member (plist-get (car elt) :document)
|
||||
documents)
|
||||
(when (plist-get (car elt) :match-edges)
|
||||
(cl-decf pdf-occur-number-of-matches))
|
||||
t))
|
||||
tabulated-list-entries))
|
||||
(tablist-revert)
|
||||
(pdf-occur-update-header-line)
|
||||
(tablist-move-to-major-column))))
|
||||
|
||||
(defun pdf-occur-tablist-do-flagged-delete (&optional interactive)
|
||||
"Stop searching all documents 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))
|
||||
(pdf-occur-tablist-do-delete)
|
||||
(or (not interactive)
|
||||
(message "(No deletions requested)")))))
|
||||
|
||||
(defun pdf-occur-tablist-gather-documents ()
|
||||
"Gather marked documents in windows.
|
||||
|
||||
Examine all dired/ibuffer windows and offer to put marked files
|
||||
in the search list."
|
||||
(interactive)
|
||||
(let ((searched (mapcar 'car pdf-occur-search-documents))
|
||||
files)
|
||||
(dolist (win (window-list))
|
||||
(with-selected-window win
|
||||
(cond
|
||||
((derived-mode-p 'dired-mode)
|
||||
(let ((marked (dired-get-marked-files nil nil nil t)))
|
||||
(when (> (length marked) 1)
|
||||
(when (eq t (car marked))
|
||||
(setq marked (cdr marked)))
|
||||
(setq files
|
||||
(append files marked nil)))))
|
||||
((derived-mode-p 'ibuffer-mode)
|
||||
(dolist (fname (mapcar 'buffer-file-name
|
||||
(ibuffer-get-marked-buffers)))
|
||||
(when fname
|
||||
(push fname files))))
|
||||
((and (derived-mode-p 'pdf-view-mode)
|
||||
(buffer-file-name))
|
||||
(push (buffer-file-name) files)))))
|
||||
|
||||
(setq files
|
||||
(cl-sort ;Looks funny.
|
||||
(cl-set-difference
|
||||
(cl-remove-duplicates
|
||||
(cl-remove-if-not
|
||||
(lambda (file) (string-match-p
|
||||
(car pdf-tools-auto-mode-alist-entry)
|
||||
file))
|
||||
files)
|
||||
:test 'file-equal-p)
|
||||
searched
|
||||
:test 'file-equal-p)
|
||||
'string-lessp))
|
||||
(if (null files)
|
||||
(message "No marked, new PDF files found in windows")
|
||||
(when (tablist-yes-or-no-p
|
||||
'add nil (mapcar (lambda (file)
|
||||
(cons nil (vector file)))
|
||||
(cl-sort files 'string-lessp)))
|
||||
(setq pdf-occur-search-documents
|
||||
(append pdf-occur-search-documents
|
||||
(pdf-occur-normalize-documents files)))
|
||||
(message "Added %d file%s to the list of searched documents%s"
|
||||
(length files)
|
||||
(dired-plural-s (length files))
|
||||
(substitute-command-keys
|
||||
" - Hit \\[pdf-occur-revert-buffer-with-args]"))))))
|
||||
|
||||
|
||||
;; * ================================================================== *
|
||||
;; * Utilities
|
||||
;; * ================================================================== *
|
||||
|
||||
(defun pdf-occur-read-string (&optional regexp-p)
|
||||
(read-string
|
||||
(concat
|
||||
(format "List lines %s"
|
||||
(if regexp-p "matching PCRE" "containing string"))
|
||||
(if pdf-occur-search-string
|
||||
(format " (default %s)" pdf-occur-search-string))
|
||||
": ")
|
||||
nil 'pdf-occur-history pdf-occur-search-string))
|
||||
|
||||
(defun pdf-occur-assert-occur-buffer-p ()
|
||||
(unless (derived-mode-p 'pdf-occur-buffer-mode)
|
||||
(error "Not in PDF occur buffer")))
|
||||
|
||||
(defun pdf-occur-want-regexp-search-p ()
|
||||
(or (and current-prefix-arg
|
||||
pdf-occur-prefer-string-search)
|
||||
(and (null current-prefix-arg)
|
||||
(not pdf-occur-prefer-string-search))))
|
||||
|
||||
;; FIXME: This will be confusing when searching documents with the
|
||||
;; same base file-name.
|
||||
(defun pdf-occur-abbrev-document (file-or-buffer)
|
||||
(if (bufferp file-or-buffer)
|
||||
(buffer-name file-or-buffer)
|
||||
(let ((abbrev (file-name-nondirectory file-or-buffer)))
|
||||
(if (> (length abbrev) 0)
|
||||
abbrev
|
||||
file-or-buffer))))
|
||||
|
||||
(defun pdf-occur-create-batches (documents batch-size)
|
||||
(let (queries)
|
||||
(dolist (d documents)
|
||||
(let* ((file-or-buffer (car d))
|
||||
(pages (pdf-info-normalize-page-range (cdr d)))
|
||||
(first (car pages))
|
||||
(last (if (eq (cdr pages) 0)
|
||||
(pdf-info-number-of-pages file-or-buffer)
|
||||
(cdr pages)))
|
||||
(npages (1+ (- last first)))
|
||||
(nbatches (ceiling
|
||||
(/ (float npages) batch-size))))
|
||||
(dotimes (i nbatches)
|
||||
(push
|
||||
(list file-or-buffer
|
||||
(cons (+ first (* i batch-size))
|
||||
(min last (+ first (1- (* (1+ i) batch-size))))))
|
||||
queries))))
|
||||
(nreverse queries)))
|
||||
|
||||
(defun pdf-occur-normalize-documents (documents)
|
||||
"Normalize list of documents.
|
||||
|
||||
Replaces buffers with their associated filenames \(if
|
||||
applicable\) and ensures that every element looks like
|
||||
\(FILENAME-OR-BUFFER . PAGES\)."
|
||||
(cl-sort (mapcar (lambda (doc)
|
||||
(unless (consp doc)
|
||||
(setq doc (cons doc nil)))
|
||||
(when (and (bufferp (car doc))
|
||||
(buffer-file-name (car doc)))
|
||||
(setq doc (cons (buffer-file-name (car doc))
|
||||
(cdr doc))))
|
||||
(if (stringp (car doc))
|
||||
(cons (expand-file-name (car doc)) (cdr doc))
|
||||
doc))
|
||||
documents)
|
||||
(lambda (a b) (string-lessp
|
||||
(if (bufferp a) (buffer-name a) a)
|
||||
(if (bufferp b) (buffer-name b) b)))
|
||||
:key 'car))
|
||||
|
||||
(provide 'pdf-occur)
|
||||
|
||||
;;; pdf-occur.el ends here
|
||||
598
elpa/pdf-tools-20180428.827/pdf-outline.el
Normal file
598
elpa/pdf-tools-20180428.827/pdf-outline.el
Normal file
@@ -0,0 +1,598 @@
|
||||
;;; pdf-outline.el --- Outline for PDF buffer -*- lexical-binding: t -*-
|
||||
|
||||
;; Copyright (C) 2013, 2014 Andreas Politz
|
||||
|
||||
;; Author: Andreas Politz <politza@fh-trier.de>
|
||||
;; Keywords: files, multimedia
|
||||
|
||||
;; 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:
|
||||
;;
|
||||
|
||||
(require 'outline)
|
||||
(require 'pdf-links)
|
||||
(require 'pdf-view)
|
||||
(require 'pdf-util)
|
||||
(require 'cl-lib)
|
||||
(require 'imenu)
|
||||
(require 'let-alist)
|
||||
|
||||
;;; Code:
|
||||
|
||||
;;
|
||||
;; User options
|
||||
;;
|
||||
|
||||
(defgroup pdf-outline nil
|
||||
"Display a navigatable outline of a PDF document."
|
||||
:group 'pdf-tools)
|
||||
|
||||
(defcustom pdf-outline-buffer-indent 2
|
||||
"The level of indent in the Outline buffer."
|
||||
:type 'integer
|
||||
:group 'pdf-outline)
|
||||
|
||||
(defcustom pdf-outline-enable-imenu t
|
||||
"Whether `imenu' should be enabled in PDF documents."
|
||||
:group 'pdf-outline
|
||||
:type '(choice (const :tag "Yes" t)
|
||||
(const :tag "No" nil)))
|
||||
|
||||
(defcustom pdf-outline-imenu-keep-order t
|
||||
"Whether `imenu' should be advised not to reorder the outline."
|
||||
:group 'pdf-outline
|
||||
:type '(choice (const :tag "Yes" t)
|
||||
(const :tag "No" nil)))
|
||||
|
||||
(defcustom pdf-outline-imenu-use-flat-menus nil
|
||||
"Whether the constructed Imenu should be a list, rather than a tree."
|
||||
:group 'pdf-outline
|
||||
:type '(choice (const :tag "Yes" t)
|
||||
(const :tag "No" nil)))
|
||||
|
||||
(defcustom pdf-outline-display-buffer-action '(nil . nil)
|
||||
"The display action used, when displaying the outline buffer."
|
||||
:group 'pdf-outline
|
||||
:type display-buffer--action-custom-type)
|
||||
|
||||
(defcustom pdf-outline-display-labels nil
|
||||
"Whether the outline should display labels instead of page numbers.
|
||||
|
||||
Usually a page's label is it's displayed page number."
|
||||
:group 'pdf-outline
|
||||
:type 'boolean)
|
||||
|
||||
(defvar pdf-outline-minor-mode-map
|
||||
(let ((km (make-sparse-keymap)))
|
||||
(define-key km (kbd "o") 'pdf-outline)
|
||||
km)
|
||||
"Keymap used for `pdf-outline-minor-mode'.")
|
||||
|
||||
(defvar pdf-outline-buffer-mode-map
|
||||
(let ((kmap (make-sparse-keymap)))
|
||||
(dotimes (i 10)
|
||||
(define-key kmap (vector (+ i ?0)) 'digit-argument))
|
||||
(define-key kmap "-" 'negative-argument)
|
||||
(define-key kmap (kbd "p") 'previous-line)
|
||||
(define-key kmap (kbd "n") 'next-line)
|
||||
(define-key kmap (kbd "b") 'outline-backward-same-level)
|
||||
(define-key kmap (kbd "d") 'hide-subtree)
|
||||
(define-key kmap (kbd "a") 'show-all)
|
||||
(define-key kmap (kbd "s") 'show-subtree)
|
||||
(define-key kmap (kbd "f") 'outline-forward-same-level)
|
||||
(define-key kmap (kbd "u") 'pdf-outline-up-heading)
|
||||
(define-key kmap (kbd "Q") 'hide-sublevels)
|
||||
(define-key kmap (kbd "<") 'beginning-of-buffer)
|
||||
(define-key kmap (kbd ">") 'pdf-outline-end-of-buffer)
|
||||
(define-key kmap (kbd "TAB") 'outline-toggle-children)
|
||||
(define-key kmap (kbd "RET") 'pdf-outline-follow-link)
|
||||
(define-key kmap (kbd "C-o") 'pdf-outline-display-link)
|
||||
(define-key kmap (kbd "SPC") 'pdf-outline-display-link)
|
||||
(define-key kmap [mouse-1] 'pdf-outline-mouse-display-link)
|
||||
(define-key kmap (kbd "o") 'pdf-outline-select-pdf-window)
|
||||
(define-key kmap (kbd ".") 'pdf-outline-move-to-current-page)
|
||||
;; (define-key kmap (kbd "Q") 'pdf-outline-quit)
|
||||
(define-key kmap (kbd "C-c C-q") 'pdf-outline-quit-and-kill)
|
||||
(define-key kmap (kbd "q") 'quit-window)
|
||||
(define-key kmap (kbd "M-RET") 'pdf-outline-follow-link-and-quit)
|
||||
(define-key kmap (kbd "C-c C-f") 'pdf-outline-follow-mode)
|
||||
kmap)
|
||||
"Keymap used in `pdf-outline-buffer-mode'.")
|
||||
|
||||
;;
|
||||
;; Internal Variables
|
||||
;;
|
||||
|
||||
(define-button-type 'pdf-outline
|
||||
'face nil
|
||||
'keymap nil)
|
||||
|
||||
(defvar-local pdf-outline-pdf-window nil
|
||||
"The PDF window corresponding to this outline buffer.")
|
||||
|
||||
(defvar-local pdf-outline-pdf-document nil
|
||||
"The PDF filename or buffer corresponding to this outline
|
||||
buffer.")
|
||||
|
||||
(defvar-local pdf-outline-follow-mode-last-link nil)
|
||||
|
||||
;;
|
||||
;; Functions
|
||||
;;
|
||||
|
||||
;;;###autoload
|
||||
(define-minor-mode pdf-outline-minor-mode
|
||||
"Display an outline of a PDF document.
|
||||
|
||||
This provides a PDF's outline on the menu bar via imenu.
|
||||
Additionally the same outline may be viewed in a designated
|
||||
buffer.
|
||||
|
||||
\\{pdf-outline-minor-mode-map}"
|
||||
nil nil nil
|
||||
(pdf-util-assert-pdf-buffer)
|
||||
(cond
|
||||
(pdf-outline-minor-mode
|
||||
(when pdf-outline-enable-imenu
|
||||
(pdf-outline-imenu-enable)))
|
||||
(t
|
||||
(when pdf-outline-enable-imenu
|
||||
(pdf-outline-imenu-disable)))))
|
||||
|
||||
(define-derived-mode pdf-outline-buffer-mode outline-mode "PDF Outline"
|
||||
"View and traverse the outline of a PDF file.
|
||||
|
||||
Press \\[pdf-outline-display-link] to display the PDF document,
|
||||
\\[pdf-outline-select-pdf-window] to select it's window,
|
||||
\\[pdf-outline-move-to-current-page] to move to the outline item
|
||||
of the current page, \\[pdf-outline-follow-link] to goto the
|
||||
corresponding page or \\[pdf-outline-follow-link-and-quit] to
|
||||
additionally quit the Outline.
|
||||
|
||||
\\[pdf-outline-follow-mode] enters a variant of
|
||||
`next-error-follow-mode'. Most `outline-mode' commands are
|
||||
rebound to their respective last character.
|
||||
|
||||
\\{pdf-outline-buffer-mode-map}"
|
||||
(setq-local outline-regexp "\\( *\\).")
|
||||
(setq-local outline-level
|
||||
(lambda nil (1+ (/ (length (match-string 1))
|
||||
pdf-outline-buffer-indent))))
|
||||
|
||||
(toggle-truncate-lines 1)
|
||||
(setq buffer-read-only t)
|
||||
(when (> (count-lines 1 (point-max))
|
||||
(* 1.5 (frame-height)))
|
||||
(hide-sublevels 1))
|
||||
(message "%s"
|
||||
(substitute-command-keys
|
||||
(concat
|
||||
"Try \\[pdf-outline-display-link], "
|
||||
"\\[pdf-outline-select-pdf-window], "
|
||||
"\\[pdf-outline-move-to-current-page] or "
|
||||
"\\[pdf-outline-follow-link-and-quit]"))))
|
||||
|
||||
(define-minor-mode pdf-outline-follow-mode
|
||||
"Display links as point moves."
|
||||
nil nil nil
|
||||
(setq pdf-outline-follow-mode-last-link nil)
|
||||
(cond
|
||||
(pdf-outline-follow-mode
|
||||
(add-hook 'post-command-hook 'pdf-outline-follow-mode-pch nil t))
|
||||
(t
|
||||
(remove-hook 'post-command-hook 'pdf-outline-follow-mode-pch t))))
|
||||
|
||||
(defun pdf-outline-follow-mode-pch ()
|
||||
(let ((link (pdf-outline-link-at-pos (point))))
|
||||
(when (and link
|
||||
(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.
|
||||
|
||||
BUFFER defaults to the current buffer. Select the outline
|
||||
buffer, unless NO-SELECT-WINDOW-P is non-nil."
|
||||
(interactive (list nil (or current-prefix-arg
|
||||
(consp last-nonmenu-event))))
|
||||
(let ((win
|
||||
(display-buffer
|
||||
(pdf-outline-noselect buffer)
|
||||
pdf-outline-display-buffer-action)))
|
||||
(unless no-select-window-p
|
||||
(select-window win))))
|
||||
|
||||
(defun pdf-outline-noselect (&optional buffer)
|
||||
"Create an PDF outline of BUFFER, but don't display it."
|
||||
(save-current-buffer
|
||||
(and buffer (set-buffer buffer))
|
||||
(pdf-util-assert-pdf-buffer)
|
||||
(let* ((pdf-buffer (current-buffer))
|
||||
(pdf-file (pdf-view-buffer-file-name))
|
||||
(pdf-window (and (eq pdf-buffer (window-buffer))
|
||||
(selected-window)))
|
||||
(bname (pdf-outline-buffer-name))
|
||||
(buffer-exists-p (get-buffer bname))
|
||||
(buffer (get-buffer-create bname)))
|
||||
(with-current-buffer buffer
|
||||
(unless buffer-exists-p
|
||||
(when (= 0 (save-excursion
|
||||
(pdf-outline-insert-outline pdf-buffer)))
|
||||
(kill-buffer buffer)
|
||||
(error "PDF has no outline"))
|
||||
(pdf-outline-buffer-mode))
|
||||
(set (make-local-variable 'other-window-scroll-buffer)
|
||||
pdf-buffer)
|
||||
(setq pdf-outline-pdf-window pdf-window
|
||||
pdf-outline-pdf-document (or pdf-file pdf-buffer))
|
||||
(current-buffer)))))
|
||||
|
||||
(defun pdf-outline-buffer-name (&optional pdf-buffer)
|
||||
(unless pdf-buffer (setq pdf-buffer (current-buffer)))
|
||||
(let ((buf (format "*Outline %s*" (buffer-name pdf-buffer))))
|
||||
;; (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)))
|
||||
(nitems 0))
|
||||
(dolist (item (pdf-info-outline pdf-buffer))
|
||||
(let-alist item
|
||||
(when (eq .type 'goto-dest)
|
||||
(insert-text-button
|
||||
(concat
|
||||
(make-string (* (1- .depth) pdf-outline-buffer-indent) ?\s)
|
||||
.title
|
||||
(if (> .page 0)
|
||||
(format " (%s)"
|
||||
(if labels
|
||||
(nth (1- .page) labels)
|
||||
.page))
|
||||
"(invalid)"))
|
||||
'type 'pdf-outline
|
||||
'help-echo (pdf-links-action-to-string item)
|
||||
'pdf-outline-link item)
|
||||
(newline)
|
||||
(cl-incf nitems))))
|
||||
nitems))
|
||||
|
||||
(defun pdf-outline-get-pdf-window (&optional if-visible-p)
|
||||
(save-selected-window
|
||||
(let* ((buffer (cond
|
||||
((buffer-live-p pdf-outline-pdf-document)
|
||||
pdf-outline-pdf-document)
|
||||
((bufferp pdf-outline-pdf-document)
|
||||
(error "PDF buffer was killed"))
|
||||
(t
|
||||
(or
|
||||
(find-buffer-visiting
|
||||
pdf-outline-pdf-document)
|
||||
(find-file-noselect
|
||||
pdf-outline-pdf-document)))))
|
||||
(pdf-window
|
||||
(if (and (window-live-p pdf-outline-pdf-window)
|
||||
(eq buffer
|
||||
(window-buffer pdf-outline-pdf-window)))
|
||||
pdf-outline-pdf-window
|
||||
(or (get-buffer-window buffer)
|
||||
(and (null if-visible-p)
|
||||
(display-buffer
|
||||
buffer
|
||||
'(nil (inhibit-same-window . t))))))))
|
||||
(setq pdf-outline-pdf-window pdf-window))))
|
||||
|
||||
|
||||
;;
|
||||
;; Commands
|
||||
;;
|
||||
|
||||
(defun pdf-outline-move-to-current-page ()
|
||||
"Move to the item corresponding to the current page.
|
||||
|
||||
Open nodes as necessary."
|
||||
(interactive)
|
||||
(let (page)
|
||||
(with-selected-window (pdf-outline-get-pdf-window)
|
||||
(setq page (pdf-view-current-page)))
|
||||
(pdf-outline-move-to-page page)))
|
||||
|
||||
(defun pdf-outline-quit-and-kill ()
|
||||
"Quit browsing the outline and kill it's buffer."
|
||||
(interactive)
|
||||
(pdf-outline-quit t))
|
||||
|
||||
(defun pdf-outline-quit (&optional kill)
|
||||
"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")
|
||||
(let ((pos (point)))
|
||||
(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)
|
||||
(let ((pos (point)))
|
||||
(goto-char (point-max))
|
||||
(when (and (eobp)
|
||||
(not (bobp))
|
||||
(null (button-at (point))))
|
||||
(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)
|
||||
(button-at (1- pos)))))
|
||||
(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)
|
||||
(unless pos (setq pos (point)))
|
||||
(let ((link (pdf-outline-link-at-pos pos)))
|
||||
(unless link
|
||||
(error "Nothing to follow here"))
|
||||
(select-window (pdf-outline-get-pdf-window))
|
||||
(pdf-links-action-perform link)))
|
||||
|
||||
(defun pdf-outline-follow-link-and-quit (&optional pos)
|
||||
"Select PDF window and move to the page corresponding to POS.
|
||||
|
||||
Then quit the outline window."
|
||||
(interactive)
|
||||
(let ((link (pdf-outline-link-at-pos (or pos (point)))))
|
||||
(pdf-outline-quit)
|
||||
(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)
|
||||
(unless pos (setq pos (point)))
|
||||
(let ((inhibit-redisplay t)
|
||||
(link (pdf-outline-link-at-pos pos)))
|
||||
(unless link
|
||||
(error "Nothing to follow here"))
|
||||
(with-selected-window (pdf-outline-get-pdf-window)
|
||||
(pdf-links-action-perform link))
|
||||
(force-mode-line-update t)))
|
||||
|
||||
(defun pdf-outline-mouse-display-link (event)
|
||||
"Display the page corresponding to the position of EVENT."
|
||||
(interactive "@e")
|
||||
(pdf-outline-display-link
|
||||
(posn-point (event-start event))))
|
||||
|
||||
(defun pdf-outline-select-pdf-window (&optional no-create-p)
|
||||
"Display and select the PDF document window."
|
||||
(interactive)
|
||||
(let ((win (pdf-outline-get-pdf-window no-create-p)))
|
||||
(and (window-live-p win)
|
||||
(select-window win))))
|
||||
|
||||
(defun pdf-outline-toggle-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)
|
||||
(show-subtree))))
|
||||
|
||||
(defun pdf-outline-move-to-page (page)
|
||||
"Move to an outline item corresponding to PAGE."
|
||||
(interactive
|
||||
(list (or (and current-prefix-arg
|
||||
(prefix-numeric-value current-prefix-arg))
|
||||
(read-number "Page: "))))
|
||||
(goto-char (pdf-outline-position-of-page page))
|
||||
(save-excursion
|
||||
(while (outline-invisible-p)
|
||||
(outline-up-heading 1 t)
|
||||
(show-children)))
|
||||
(save-excursion
|
||||
(when (outline-invisible-p)
|
||||
(outline-up-heading 1 t)
|
||||
(show-children)))
|
||||
(back-to-indentation))
|
||||
|
||||
(defun pdf-outline-position-of-page (page)
|
||||
(let (curpage)
|
||||
(save-excursion
|
||||
(goto-char (point-min))
|
||||
(while (and (setq curpage (alist-get 'page (pdf-outline-link-at-pos)))
|
||||
(< curpage page))
|
||||
(forward-line))
|
||||
(point))))
|
||||
|
||||
|
||||
|
||||
;;
|
||||
;; Imenu Support
|
||||
;;
|
||||
|
||||
|
||||
;;;###autoload
|
||||
(defun pdf-outline-imenu-enable ()
|
||||
"Enable imenu in the current PDF buffer."
|
||||
(interactive)
|
||||
(pdf-util-assert-pdf-buffer)
|
||||
(setq-local imenu-create-index-function
|
||||
(if pdf-outline-imenu-use-flat-menus
|
||||
'pdf-outline-imenu-create-index-flat
|
||||
'pdf-outline-imenu-create-index-tree))
|
||||
(imenu-add-to-menubar "PDF Outline"))
|
||||
|
||||
(defun pdf-outline-imenu-disable ()
|
||||
"Disable imenu in the current PDF buffer."
|
||||
(interactive)
|
||||
(pdf-util-assert-pdf-buffer)
|
||||
(setq-local imenu-create-index-function nil)
|
||||
(local-set-key [menu-bar index] nil)
|
||||
(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
|
||||
(list (format "%s (%s)" .title (if labels
|
||||
(nth (1- .page) labels)
|
||||
.page))
|
||||
0
|
||||
'pdf-outline-imenu-activate-link
|
||||
link)))
|
||||
|
||||
(defun pdf-outline-imenu-create-index-flat ()
|
||||
(let ((labels (and pdf-outline-display-labels
|
||||
(pdf-info-pagelabels)))
|
||||
index)
|
||||
(dolist (item (pdf-info-outline))
|
||||
(let-alist item
|
||||
(when (eq .type 'goto-dest)
|
||||
(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
|
||||
(cl-remove-if-not
|
||||
(lambda (type)
|
||||
(eq type 'goto-dest))
|
||||
(pdf-info-outline)
|
||||
:key (apply-partially 'alist-get 'type)))
|
||||
(and pdf-outline-display-labels
|
||||
(pdf-info-pagelabels))))
|
||||
|
||||
(defun pdf-outline-imenu-create-index-tree-1 (nodes &optional labels)
|
||||
(mapcar (lambda (node)
|
||||
(let (children)
|
||||
(when (consp (caar node))
|
||||
(setq children (cdr node)
|
||||
node (car node)))
|
||||
(let ((item
|
||||
(pdf-outline-imenu-create-item node labels)))
|
||||
(if children
|
||||
(cons (alist-get 'title node)
|
||||
(cons item (pdf-outline-imenu-create-index-tree-1
|
||||
children labels)))
|
||||
item))))
|
||||
nodes))
|
||||
|
||||
(defun pdf-outline-treeify-outline-list (list)
|
||||
(when list
|
||||
(let ((depth (alist-get 'depth (car list)))
|
||||
result)
|
||||
(while (and list
|
||||
(>= (alist-get 'depth (car list))
|
||||
depth))
|
||||
(when (= (alist-get 'depth (car list)) depth)
|
||||
(let ((item (car list)))
|
||||
(when (and (cdr list)
|
||||
(> (alist-get 'depth (cadr list))
|
||||
depth))
|
||||
(setq item
|
||||
(cons
|
||||
item
|
||||
(pdf-outline-treeify-outline-list (cdr list)))))
|
||||
(push item result)))
|
||||
(setq list (cdr list)))
|
||||
(reverse result))))
|
||||
|
||||
(defun pdf-outline-imenu-activate-link (&rest args)
|
||||
;; bug #14029
|
||||
(when (eq (nth 2 args) 'pdf-outline-imenu-activate-link)
|
||||
(setq args (cdr args)))
|
||||
(pdf-links-action-perform (nth 2 args)))
|
||||
|
||||
(defadvice imenu--split-menu (around pdf-outline activate)
|
||||
"Advice to keep the original outline order.
|
||||
|
||||
Calls `pdf-outline-imenu--split-menu' instead, if in a PDF
|
||||
buffer and `pdf-outline-imenu-keep-order' is non-nil."
|
||||
(if (not (and (pdf-util-pdf-buffer-p)
|
||||
pdf-outline-imenu-keep-order))
|
||||
ad-do-it
|
||||
(setq ad-return-value
|
||||
(pdf-outline-imenu--split-menu menulist title))))
|
||||
|
||||
(defvar imenu--rescan-item)
|
||||
(defvar imenu-sort-function)
|
||||
(defvar imenu-create-index-function)
|
||||
(defvar imenu-max-items)
|
||||
|
||||
(defun pdf-outline-imenu--split-menu (menulist title)
|
||||
"Replacement function for `imenu--split-menu'.
|
||||
|
||||
This function does not move sub-menus to the top, therefore
|
||||
keeping the original outline order of the document. Also it does
|
||||
not call `imenu-sort-function'."
|
||||
(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)))
|
||||
(if (> (length 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))))
|
||||
|
||||
;; bugfix for imenu in Emacs 24.3 and below.
|
||||
(when (condition-case nil
|
||||
(progn (imenu--truncate-items '(("" 0))) nil)
|
||||
(error t))
|
||||
(eval-after-load "imenu"
|
||||
'(defun imenu--truncate-items (menulist)
|
||||
"Truncate all strings in MENULIST to `imenu-max-item-length'."
|
||||
(mapc (lambda (item)
|
||||
;; Truncate if necessary.
|
||||
(when (and (numberp imenu-max-item-length)
|
||||
(> (length (car item)) imenu-max-item-length))
|
||||
(setcar item (substring (car item) 0 imenu-max-item-length)))
|
||||
(when (imenu--subalist-p item)
|
||||
(imenu--truncate-items (cdr item))))
|
||||
menulist))))
|
||||
|
||||
|
||||
|
||||
(provide 'pdf-outline)
|
||||
|
||||
;;; pdf-outline.el ends here
|
||||
|
||||
;; Local Variables:
|
||||
;; byte-compile-warnings: (not obsolete)
|
||||
;; End:
|
||||
831
elpa/pdf-tools-20180428.827/pdf-sync.el
Normal file
831
elpa/pdf-tools-20180428.827/pdf-sync.el
Normal file
@@ -0,0 +1,831 @@
|
||||
;;; pdf-sync.el --- Use synctex to correlate LaTeX-Sources with PDF positions. -*- lexical-binding:t -*-
|
||||
;; Copyright (C) 2013, 2014 Andreas Politz
|
||||
|
||||
;; Author: Andreas Politz <politza@fh-trier.de>
|
||||
;; Keywords: files, doc-view, pdf
|
||||
|
||||
;; 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:
|
||||
;;
|
||||
;; 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
|
||||
;; character and translates certain other character into their latex
|
||||
;; equivalents. This transformed text is split into a series of
|
||||
;; token. A similar operation is performed on the source code around
|
||||
;; the position synctex points at. These two sequences of token are
|
||||
;; aligned with a standard sequence alignment algorithm, resulting in
|
||||
;; an alist of matched and unmatched tokens. This is then used to
|
||||
;; find the corresponding word from the PDF file in the LaTeX buffer.
|
||||
|
||||
|
||||
(require 'pdf-view)
|
||||
(require 'pdf-info)
|
||||
(require 'pdf-util)
|
||||
(require 'let-alist)
|
||||
|
||||
;;; Code:
|
||||
|
||||
(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.
|
||||
|
||||
This key is added to `TeX-source-correlate-method', when
|
||||
command `pdf-sync-minor-mode' is activated and this map is defined."
|
||||
:group 'pdf-sync
|
||||
:type 'key-sequence)
|
||||
|
||||
(defcustom pdf-sync-backward-hook nil
|
||||
"Hook ran after going to a source location.
|
||||
|
||||
The hook is run in the TeX buffer."
|
||||
:group 'pdf-sync
|
||||
:type 'hook
|
||||
:options '(pdf-sync-backward-beginning-of-word))
|
||||
|
||||
(defcustom pdf-sync-forward-hook nil
|
||||
"Hook ran after displaying the PDF buffer.
|
||||
|
||||
The hook is run in the PDF's buffer."
|
||||
:group 'pdf-sync
|
||||
:type 'hook)
|
||||
|
||||
(defcustom pdf-sync-forward-display-action nil
|
||||
"Display action used when displaying PDF buffers."
|
||||
:group 'pdf-sync
|
||||
:type 'display-buffer--action-custom-type)
|
||||
|
||||
(defcustom pdf-sync-backward-display-action nil
|
||||
"Display action used when displaying TeX buffers."
|
||||
:group 'pdf-sync
|
||||
:type 'display-buffer--action-custom-type)
|
||||
|
||||
(defcustom pdf-sync-locate-synctex-file-functions nil
|
||||
"A list of functions for locating the synctex database.
|
||||
|
||||
Each function on this hook should accept a single argument: The
|
||||
absolute path of a PDF file. It should return the absolute path
|
||||
of the corresponding synctex database or nil, if it was unable to
|
||||
locate it."
|
||||
:group 'pdf-sync
|
||||
:type 'hook)
|
||||
|
||||
(defvar pdf-sync-minor-mode-map
|
||||
(let ((kmap (make-sparse-keymap)))
|
||||
(define-key kmap [double-mouse-1] 'pdf-sync-backward-search-mouse)
|
||||
(define-key kmap [C-mouse-1] 'pdf-sync-backward-search-mouse)
|
||||
kmap))
|
||||
|
||||
(defcustom pdf-sync-backward-redirect-functions nil
|
||||
"List of functions which may redirect a backward search.
|
||||
|
||||
Functions on this hook should accept three arguments, namely
|
||||
SOURCE, LINE and COLUMN, where SOURCE is the absolute filename of
|
||||
the source file and LINE and COLUMN denote the position in the
|
||||
file. COLUMN may be negative, meaning unspecified.
|
||||
|
||||
These functions should either return nil, if no redirection is
|
||||
necessary. Or a list of the same structure, with some or all (or
|
||||
none) values modified.
|
||||
|
||||
AUCTeX installs a function here which changes the backward search
|
||||
location for synthetic `TeX-region' files back to the equivalent
|
||||
position in the original tex file."
|
||||
:group 'pdf-sync
|
||||
:type '(repeat function))
|
||||
|
||||
|
||||
;;;###autoload
|
||||
(define-minor-mode pdf-sync-minor-mode
|
||||
"Correlate a PDF position with the TeX file.
|
||||
\\<pdf-sync-minor-mode-map>
|
||||
This works via SyncTeX, which means the TeX sources need to have
|
||||
been compiled with `--synctex=1'. In AUCTeX this can be done by
|
||||
setting `TeX-source-correlate-method' to 'synctex \(before AUCTeX
|
||||
is loaded\) and enabling `TeX-source-correlate-mode'.
|
||||
|
||||
Then \\[pdf-sync-backward-search-mouse] in the PDF buffer will open the
|
||||
corresponding TeX location.
|
||||
|
||||
If AUCTeX is your preferred tex-mode, this library arranges to
|
||||
bind `pdf-sync-forward-display-pdf-key' \(the default is `C-c C-g'\)
|
||||
to `pdf-sync-forward-search' in `TeX-source-correlate-map'. This
|
||||
function displays the PDF page corresponding to the current
|
||||
position in the TeX buffer. This function only works together
|
||||
with AUCTeX."
|
||||
|
||||
nil nil nil
|
||||
(pdf-util-assert-pdf-buffer))
|
||||
|
||||
(eval-after-load "tex"
|
||||
'(when (and pdf-sync-forward-display-pdf-key
|
||||
(boundp 'TeX-source-correlate-map)
|
||||
(let ((key (lookup-key
|
||||
TeX-source-correlate-map
|
||||
(kbd pdf-sync-forward-display-pdf-key))))
|
||||
(or (null key)
|
||||
(numberp key))))
|
||||
(define-key TeX-source-correlate-map
|
||||
(kbd pdf-sync-forward-display-pdf-key)
|
||||
'pdf-sync-forward-search)))
|
||||
|
||||
|
||||
|
||||
;; * ================================================================== *
|
||||
;; * Backward search (PDF -> TeX)
|
||||
;; * ================================================================== *
|
||||
|
||||
(defcustom pdf-sync-backward-use-heuristic t
|
||||
"Whether to apply a heuristic when backward searching.
|
||||
|
||||
If nil, just go where Synctex tells us. Otherwise try to find
|
||||
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")
|
||||
(126 "textasciitilde")
|
||||
(169 "copyright" "textcopyright")
|
||||
(172 "neg" "textlnot")
|
||||
(174 "textregistered" "textregistered")
|
||||
(176 "textdegree")
|
||||
(177 "pm" "textpm")
|
||||
(181 "upmu" "mu")
|
||||
(182 "mathparagraph" "textparagraph" "P" "textparagraph")
|
||||
(215 "times")
|
||||
(240 "eth" "dh")
|
||||
(915 "Upgamma" "Gamma")
|
||||
(920 "Uptheta" "Theta")
|
||||
(923 "Uplambda" "Lambda")
|
||||
(926 "Upxi" "Xi")
|
||||
(928 "Uppi" "Pi")
|
||||
(931 "Upsigma" "Sigma")
|
||||
(933 "Upupsilon" "Upsilon")
|
||||
(934 "Upphi" "Phi")
|
||||
(936 "Uppsi" "Psi")
|
||||
(945 "upalpha" "alpha")
|
||||
(946 "upbeta" "beta")
|
||||
(947 "upgamma" "gamma")
|
||||
(948 "updelta" "delta")
|
||||
(949 "upvarepsilon" "varepsilon")
|
||||
(950 "upzeta" "zeta")
|
||||
(951 "upeta" "eta")
|
||||
(952 "uptheta" "theta")
|
||||
(953 "upiota" "iota")
|
||||
(954 "upkappa" "varkappa" "kappa")
|
||||
(955 "uplambda" "lambda")
|
||||
(957 "upnu" "nu")
|
||||
(958 "upxi" "xi")
|
||||
(960 "uppi" "pi")
|
||||
(961 "upvarrho" "uprho" "rho")
|
||||
(962 "varsigma")
|
||||
(963 "upvarsigma" "upsigma" "sigma")
|
||||
(964 "uptau" "tau")
|
||||
(965 "upupsilon" "upsilon")
|
||||
(966 "upphi" "phi")
|
||||
(967 "upchi" "chi")
|
||||
(968 "uppsi" "psi")
|
||||
(969 "upomega" "omega")
|
||||
(977 "upvartheta" "vartheta")
|
||||
(981 "upvarphi" "varphi")
|
||||
(8224 "dagger")
|
||||
(8225 "ddagger")
|
||||
(8226 "bullet")
|
||||
(8486 "Upomega" "Omega")
|
||||
(8501 "aleph")
|
||||
(8592 "mapsfrom" "leftarrow")
|
||||
(8593 "uparrow")
|
||||
(8594 "to" "mapsto" "rightarrow")
|
||||
(8595 "downarrow")
|
||||
(8596 "leftrightarrow")
|
||||
(8656 "shortleftarrow" "Leftarrow")
|
||||
(8657 "Uparrow")
|
||||
(8658 "Mapsto" "rightrightarrows" "Rightarrow")
|
||||
(8659 "Downarrow")
|
||||
(8660 "Leftrightarrow")
|
||||
(8704 "forall")
|
||||
(8706 "partial")
|
||||
(8707 "exists")
|
||||
(8709 "varnothing" "emptyset")
|
||||
(8710 "Updelta" "Delta")
|
||||
(8711 "nabla")
|
||||
(8712 "in")
|
||||
(8722 "-")
|
||||
(8725 "setminus")
|
||||
(8727 "*")
|
||||
(8734 "infty")
|
||||
(8743 "wedge")
|
||||
(8744 "vee")
|
||||
(8745 "cap")
|
||||
(8746 "cup")
|
||||
(8756 "therefore")
|
||||
(8757 "because")
|
||||
(8764 "thicksim" "sim")
|
||||
(8776 "thickapprox" "approx")
|
||||
(8801 "equiv")
|
||||
(8804 "leq")
|
||||
(8805 "geq")
|
||||
(8810 "lll")
|
||||
(8811 "ggg")
|
||||
(8814 "nless")
|
||||
(8815 "ngtr")
|
||||
(8822 "lessgtr")
|
||||
(8823 "gtrless")
|
||||
(8826 "prec")
|
||||
(8832 "nprec")
|
||||
(8834 "subset")
|
||||
(8835 "supset")
|
||||
(8838 "subseteq")
|
||||
(8839 "supseteq")
|
||||
(8853 "oplus")
|
||||
(8855 "otimes")
|
||||
(8869 "bot" "perp")
|
||||
(9702 "circ")
|
||||
(9792 "female" "venus")
|
||||
(9793 "earth")
|
||||
(9794 "male" "mars")
|
||||
(9824 "spadesuit")
|
||||
(9827 "clubsuit")
|
||||
(9829 "heartsuit")
|
||||
(9830 "diamondsuit"))
|
||||
"Alist mapping PDF character to a list of LaTeX macro names.
|
||||
|
||||
Adding a character here with it's LaTeX equivalent names allows
|
||||
the heuristic backward search to find it's location in the source
|
||||
file. These strings should not match
|
||||
`pdf-sync-backward-source-flush-regexp'.
|
||||
|
||||
Has no effect if `pdf-sync-backward-use-heuristic' is nil."
|
||||
: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.")
|
||||
|
||||
(defconst pdf-sync-backward-source-flush-regexp
|
||||
"\\(?:\\\\\\(?:begin\\|end\\|\\(?:eq\\)?ref\\|label\\|cite\\){[^}]*}\\)\\|[][\\&{}$_]"
|
||||
"Regexp of ignored source when backward searching.")
|
||||
|
||||
(defconst pdf-sync-backward-context-limit 64
|
||||
"Number of character to include in the backward search.")
|
||||
|
||||
(defun pdf-sync-backward-search-mouse (ev)
|
||||
"Go to the source corresponding to position at event EV."
|
||||
(interactive "@e")
|
||||
(let* ((posn (event-start ev))
|
||||
(image (posn-image posn))
|
||||
(xy (posn-object-x-y posn)))
|
||||
(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.
|
||||
|
||||
Try to find the exact position, if
|
||||
`pdf-sync-backward-use-heuristic' is non-nil."
|
||||
(cl-destructuring-bind (source finder)
|
||||
(pdf-sync-backward-correlate x y)
|
||||
(pop-to-buffer (or (find-buffer-visiting source)
|
||||
(find-file-noselect source))
|
||||
pdf-sync-backward-display-action)
|
||||
(push-mark)
|
||||
(funcall finder)
|
||||
(run-hooks 'pdf-sync-backward-hook)))
|
||||
|
||||
(defun pdf-sync-backward-correlate (x y)
|
||||
"Find the source corresponding to image coordinates X, Y.
|
||||
|
||||
Returns a list \(SOURCE FINDER\), where SOURCE is the name of the
|
||||
TeX file and FINDER a function of zero arguments which, when
|
||||
called in the buffer of the aforementioned file, will try to move
|
||||
point to the correct position."
|
||||
|
||||
(pdf-util-assert-pdf-window)
|
||||
(let ((size (pdf-view-image-size))
|
||||
(page (pdf-view-current-page)))
|
||||
(setq x (/ x (float (car size)))
|
||||
y (/ y (float (cdr size))))
|
||||
(let-alist (pdf-info-synctex-backward-search page x y)
|
||||
(let ((data (list (expand-file-name .filename)
|
||||
.line .column)))
|
||||
(cl-destructuring-bind (source line column)
|
||||
(or (save-selected-window
|
||||
(apply 'run-hook-with-args-until-success
|
||||
'pdf-sync-backward-redirect-functions data))
|
||||
data)
|
||||
(list source
|
||||
(if (not pdf-sync-backward-use-heuristic)
|
||||
(lambda nil
|
||||
(pdf-util-goto-position line column))
|
||||
(let ((context (pdf-sync-backward--get-text-context page x y)))
|
||||
(lambda nil
|
||||
(pdf-sync-backward--find-position line column context))))))))))
|
||||
|
||||
(defun pdf-sync-backward--find-position (line column context)
|
||||
(pdf-util-goto-position line column)
|
||||
(cl-destructuring-bind (windex chindex words)
|
||||
context
|
||||
(let* ((swords (pdf-sync-backward--get-source-context
|
||||
nil (* 6 pdf-sync-backward-context-limit)))
|
||||
(similarity-fn (lambda (text source)
|
||||
(if (if (consp text)
|
||||
(member source text)
|
||||
(equal text source))
|
||||
1024 -1024)))
|
||||
(alignment
|
||||
(pdf-util-seq-alignment
|
||||
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
|
||||
word (cdr (nth (1+ windex) alignment))))
|
||||
(unless word
|
||||
(setq word (cdr (nth (1- windex) alignment))
|
||||
chindex (length word)))
|
||||
(when word
|
||||
(cl-assert (get-text-property 0 'position word) t)
|
||||
(goto-char (get-text-property 0 'position word))
|
||||
(forward-char chindex))))))
|
||||
|
||||
(defun pdf-sync-backward--get-source-context (&optional position limit)
|
||||
(save-excursion
|
||||
(when position (goto-char position))
|
||||
(goto-char (line-beginning-position))
|
||||
(let* ((region
|
||||
(cond
|
||||
((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)
|
||||
(looking-at " *\\\\\\(end\\){"))
|
||||
(cons (or (ignore-errors
|
||||
(save-excursion
|
||||
(LaTeX-find-matching-begin)
|
||||
(forward-line 1)
|
||||
(point)))
|
||||
(point))
|
||||
(point)))
|
||||
((and (fboundp 'LaTeX-find-matching-end)
|
||||
(looking-at " *\\\\\\(begin\\){"))
|
||||
(goto-char (line-end-position))
|
||||
(cons (point)
|
||||
(or (ignore-errors
|
||||
(save-excursion
|
||||
(LaTeX-find-matching-end)
|
||||
(forward-line 0)
|
||||
(point)))
|
||||
(point))))
|
||||
(t (cons (point) (point)))))
|
||||
(begin (car region))
|
||||
(end (cdr region)))
|
||||
(when (numberp limit)
|
||||
(let ((delta (- limit (- end begin))))
|
||||
(when (> delta 0)
|
||||
(setq begin (max (point-min)
|
||||
(- begin (/ delta 2)))
|
||||
end (min (point-max)
|
||||
(+ end (/ delta 2)))))))
|
||||
(let ((string (buffer-substring-no-properties begin end)))
|
||||
(dotimes (i (length string))
|
||||
(put-text-property i (1+ i) 'position (+ begin i) string))
|
||||
(nth 2 (pdf-sync-backward--tokenize
|
||||
(pdf-sync-backward--source-strip-comments string)
|
||||
nil
|
||||
pdf-sync-backward-source-flush-regexp))))))
|
||||
|
||||
(defun pdf-sync-backward--source-strip-comments (string)
|
||||
"Strip all standard LaTeX comments from string."
|
||||
(with-temp-buffer
|
||||
(save-excursion (insert string))
|
||||
(while (re-search-forward
|
||||
"^\\(?:[^\\\n]\\|\\(?:\\\\\\\\\\)\\)*\\(%.*\\)" nil t)
|
||||
(delete-region (match-beginning 1) (match-end 1)))
|
||||
(buffer-string)))
|
||||
|
||||
(defun pdf-sync-backward--get-text-context (page x y)
|
||||
(cl-destructuring-bind (&optional char edges)
|
||||
(car (pdf-info-charlayout page (cons x y)))
|
||||
(when edges
|
||||
(setq x (nth 0 edges)
|
||||
y (nth 1 edges)))
|
||||
(let* ((prefix (pdf-info-gettext page (list 0 0 x y)))
|
||||
(suffix (pdf-info-gettext page (list x y 1 1)))
|
||||
(need-suffix-space-p (memq char '(?\s ?\n)))
|
||||
;; Figure out whether we missed a space by matching the
|
||||
;; prefix's suffix with the line's prefix. Due to the text
|
||||
;; extraction in poppler, spaces are only inserted
|
||||
;; inbetween words. This test may fail, if prefix and line
|
||||
;; do not overlap, which may happen in various cases, but
|
||||
;; we don't care.
|
||||
(need-prefix-space-p
|
||||
(and (not need-suffix-space-p)
|
||||
(memq
|
||||
(ignore-errors
|
||||
(aref (pdf-info-gettext page (list x y x y) 'line)
|
||||
(- (length prefix)
|
||||
(or (cl-position ?\n prefix :from-end t)
|
||||
-1)
|
||||
1)))
|
||||
'(?\s ?\n)))))
|
||||
(setq prefix
|
||||
(concat
|
||||
(substring
|
||||
prefix (max 0 (min (1- (length prefix))
|
||||
(- (length prefix)
|
||||
pdf-sync-backward-context-limit))))
|
||||
(if need-prefix-space-p " "))
|
||||
suffix
|
||||
(concat
|
||||
(if need-suffix-space-p " ")
|
||||
(substring
|
||||
suffix 0 (max 0 (min (1- (length suffix))
|
||||
pdf-sync-backward-context-limit)))))
|
||||
(pdf-sync-backward--tokenize
|
||||
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))
|
||||
(when suffix (insert suffix))
|
||||
(goto-char 1)
|
||||
;; Delete ignored text.
|
||||
(when flush-re
|
||||
(save-excursion
|
||||
(while (re-search-forward flush-re nil t)
|
||||
(replace-match " " t t))))
|
||||
;; Normalize whitespace.
|
||||
(save-excursion
|
||||
(while (re-search-forward "[ \t\f\n]+" nil t)
|
||||
(replace-match " " t t)))
|
||||
;; Split words and non-words
|
||||
(save-excursion
|
||||
(while (re-search-forward "[^ ]\\b\\|[^ [:alnum:]]" nil t)
|
||||
(insert-before-markers " ")))
|
||||
;; Replace character
|
||||
(let ((translate
|
||||
(lambda (string)
|
||||
(or (and (= (length string) 1)
|
||||
(cdr (assq (aref string 0)
|
||||
translation)))
|
||||
string)))
|
||||
words
|
||||
(windex -1)
|
||||
(chindex 0))
|
||||
(skip-chars-forward " ")
|
||||
(while (and (not (eobp))
|
||||
(<= (point) center))
|
||||
(cl-incf windex)
|
||||
(skip-chars-forward "^ ")
|
||||
(skip-chars-forward " "))
|
||||
(goto-char center)
|
||||
(when (eq ?\s (char-after))
|
||||
(skip-chars-backward " "))
|
||||
(setq chindex (- (skip-chars-backward "^ ")))
|
||||
(setq words (split-string (buffer-string)))
|
||||
(when translation
|
||||
(setq words (mapcar translate words)))
|
||||
(list windex chindex words)))))
|
||||
|
||||
(defun pdf-sync-backward-beginning-of-word ()
|
||||
"Maybe move to the beginning of the word.
|
||||
|
||||
Don't move if already at the beginning, or if not at a word
|
||||
character.
|
||||
|
||||
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")
|
||||
(not (looking-back "\\w" (1- (point)))))
|
||||
(backward-word)))
|
||||
|
||||
;; * ------------------------------------------------------------------ *
|
||||
;; * Debugging backward search
|
||||
;; * ------------------------------------------------------------------ *
|
||||
|
||||
(defvar pdf-sync-backward-debug-trace nil)
|
||||
|
||||
(defun pdf-sync-backward-debug-wrapper (fn-symbol fn &rest args)
|
||||
(cond
|
||||
((eq fn-symbol 'pdf-sync-backward-search)
|
||||
(setq pdf-sync-backward-debug-trace nil)
|
||||
(apply fn args))
|
||||
(t
|
||||
(let ((retval (apply fn args)))
|
||||
(push `(,args . ,retval)
|
||||
pdf-sync-backward-debug-trace)
|
||||
retval))))
|
||||
|
||||
(define-minor-mode pdf-sync-backward-debug-minor-mode
|
||||
"Aid in debugging the backward search."
|
||||
nil nil nil
|
||||
(if (and (fboundp 'advice-add)
|
||||
(fboundp 'advice-remove))
|
||||
(let ((functions
|
||||
'(pdf-sync-backward-search
|
||||
pdf-sync-backward--tokenize
|
||||
pdf-util-seq-alignment)))
|
||||
(cond
|
||||
(pdf-sync-backward-debug-minor-mode
|
||||
(dolist (fn functions)
|
||||
(advice-add fn :around (apply-partially 'pdf-sync-backward-debug-wrapper
|
||||
fn)
|
||||
`((name . ,(format "%s-debug" fn))))))
|
||||
(t
|
||||
(dolist (fn functions)
|
||||
(advice-remove fn (format "%s-debug" fn))))))
|
||||
(error "Need Emacs version >= 24.4")))
|
||||
|
||||
(defun pdf-sync-backward-debug-explain ()
|
||||
"Explain the last backward search.
|
||||
|
||||
Needs to have `pdf-sync-backward-debug-minor-mode' enabled."
|
||||
|
||||
(interactive)
|
||||
(unless pdf-sync-backward-debug-trace
|
||||
(error "No last search or `pdf-sync-backward-debug-minor-mode' not enabled."))
|
||||
|
||||
(with-current-buffer (get-buffer-create "*pdf-sync-backward trace*")
|
||||
(cl-destructuring-bind (text source alignment &rest ignored)
|
||||
(reverse pdf-sync-backward-debug-trace)
|
||||
(let* ((fill-column 68)
|
||||
(sep (format "\n%s\n" (make-string fill-column ?-)))
|
||||
(highlight '(:background "chartreuse" :foreground "black"))
|
||||
(or-sep "|")
|
||||
(inhibit-read-only t)
|
||||
(windex (nth 0 (cdr text)))
|
||||
(chindex (nth 1 (cdr text))))
|
||||
(erase-buffer)
|
||||
(font-lock-mode -1)
|
||||
(view-mode 1)
|
||||
(insert (propertize "Text Raw:" 'face 'font-lock-keyword-face))
|
||||
(insert sep)
|
||||
(insert (nth 0 (car text)))
|
||||
(insert (propertize "<|>" 'face highlight))
|
||||
(insert (nth 1 (car text)))
|
||||
(insert sep)
|
||||
(insert (propertize "Text Token:" 'face 'font-lock-keyword-face))
|
||||
(insert sep)
|
||||
(fill-region (point)
|
||||
(progn
|
||||
(insert
|
||||
(mapconcat (lambda (elt)
|
||||
(if (consp elt)
|
||||
(mapconcat 'identity elt or-sep)
|
||||
elt))
|
||||
(nth 2 (cdr text)) " "))
|
||||
(point)))
|
||||
(insert sep)
|
||||
|
||||
(insert (propertize "Source Raw:" 'face 'font-lock-keyword-face))
|
||||
(insert sep)
|
||||
(insert (nth 0 (car source)))
|
||||
(insert sep)
|
||||
(insert (propertize "Source Token:" 'face 'font-lock-keyword-face))
|
||||
(insert sep)
|
||||
(fill-region (point)
|
||||
(progn (insert (mapconcat 'identity (nth 2 (cdr source)) " "))
|
||||
(point)))
|
||||
(insert sep)
|
||||
|
||||
(insert (propertize "Alignment:" 'face 'font-lock-keyword-face))
|
||||
(insert (format " (windex=%d, chindex=%d" windex chindex))
|
||||
(insert sep)
|
||||
(save-excursion (newline 2))
|
||||
(let ((column 0)
|
||||
(index 0))
|
||||
(dolist (a (cdr (cdr alignment)))
|
||||
(let* ((source (cdr a))
|
||||
(text (if (consp (car a))
|
||||
(mapconcat 'identity (car a) or-sep)
|
||||
(car a)))
|
||||
(extend (max (length text)
|
||||
(length source))))
|
||||
(when (and (not (bolp))
|
||||
(> (+ column extend)
|
||||
fill-column))
|
||||
(forward-line 2)
|
||||
(newline 3)
|
||||
(forward-line -2)
|
||||
(setq column 0))
|
||||
(when text
|
||||
(insert (propertize text 'face
|
||||
(if (= index windex)
|
||||
highlight
|
||||
(if source 'match
|
||||
'lazy-highlight)))))
|
||||
(move-to-column (+ column extend) t)
|
||||
(insert " ")
|
||||
(save-excursion
|
||||
(forward-line)
|
||||
(move-to-column column t)
|
||||
(when source
|
||||
(insert (propertize source 'face (if text
|
||||
'match
|
||||
'lazy-highlight))))
|
||||
(move-to-column (+ column extend) t)
|
||||
(insert " "))
|
||||
(cl-incf column (+ 1 extend))
|
||||
(when text (cl-incf index)))))
|
||||
(goto-char (point-max))
|
||||
(insert sep)
|
||||
(goto-char 1)
|
||||
(pop-to-buffer (current-buffer))))))
|
||||
|
||||
|
||||
;; * ================================================================== *
|
||||
;; * Forward search (TeX -> PDF)
|
||||
;; * ================================================================== *
|
||||
|
||||
(defun pdf-sync-forward-search (&optional line column)
|
||||
"Display the PDF location corresponding to LINE, COLUMN."
|
||||
(interactive)
|
||||
(cl-destructuring-bind (pdf page _x1 y1 _x2 _y2)
|
||||
(pdf-sync-forward-correlate line column)
|
||||
(let ((buffer (or (find-buffer-visiting pdf)
|
||||
(find-file-noselect pdf))))
|
||||
(with-selected-window (display-buffer
|
||||
buffer pdf-sync-forward-display-action)
|
||||
(pdf-util-assert-pdf-window)
|
||||
(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\), 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)))
|
||||
(unless column (setq column (current-column)))
|
||||
|
||||
(let* ((pdf (expand-file-name
|
||||
(with-no-warnings (TeX-master-file "pdf"))))
|
||||
(sfilename (pdf-sync-synctex-file-name
|
||||
(buffer-file-name) pdf)))
|
||||
(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))))))
|
||||
|
||||
|
||||
|
||||
;; * ================================================================== *
|
||||
;; * Dealing with synctex files.
|
||||
;; * ================================================================== *
|
||||
|
||||
(defun pdf-sync-locate-synctex-file (pdffile)
|
||||
"Locate the synctex database corresponding to PDFFILE.
|
||||
|
||||
Returns either the absolute path of the database or nil.
|
||||
|
||||
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
|
||||
'pdf-sync-locate-synctex-file-functions pdffile)
|
||||
(pdf-sync-locate-synctex-file-default pdffile)))
|
||||
|
||||
(defun pdf-sync-locate-synctex-file-default (pdffile)
|
||||
"The default function for locating a synctex database for PDFFILE.
|
||||
|
||||
See also `pdf-sync-locate-synctex-file'."
|
||||
(let ((default-directory
|
||||
(file-name-directory pdffile))
|
||||
(basename (file-name-sans-extension
|
||||
(file-name-nondirectory pdffile))))
|
||||
(cl-labels ((file-if-exists-p (file)
|
||||
(and (file-exists-p file)
|
||||
file)))
|
||||
(or (file-if-exists-p
|
||||
(expand-file-name (concat basename ".synctex.gz")))
|
||||
(file-if-exists-p
|
||||
(expand-file-name (concat basename ".synctex")))
|
||||
;; Some pdftex quote the basename.
|
||||
(file-if-exists-p
|
||||
(expand-file-name (concat "\"" basename "\"" ".synctex.gz")))
|
||||
(file-if-exists-p
|
||||
(expand-file-name (concat "\"" basename "\"" ".synctex")))))))
|
||||
|
||||
(defun pdf-sync-synctex-file-name (filename pdffile)
|
||||
"Find SyncTeX filename corresponding to FILENAME in the context of PDFFILE.
|
||||
|
||||
This function consults the synctex.gz database of PDFFILE and
|
||||
searches for a filename, which is `file-equal-p' to FILENAME.
|
||||
The first such filename is returned, or nil if none was found."
|
||||
|
||||
(when (file-exists-p filename)
|
||||
(setq filename (expand-file-name filename))
|
||||
(let* ((synctex (pdf-sync-locate-synctex-file pdffile))
|
||||
(basename (file-name-nondirectory filename))
|
||||
(regexp (format "^ *Input *: *[^:\n]+ *:\\(.*%s\\)$"
|
||||
(regexp-quote basename))))
|
||||
(when (and synctex
|
||||
(file-readable-p synctex))
|
||||
(with-current-buffer (let ((revert-without-query (list "")))
|
||||
(find-file-noselect synctex))
|
||||
;; Keep point in front of the found filename. It will
|
||||
;; probably be queried for again next time.
|
||||
(let ((beg (point))
|
||||
(end (point-max)))
|
||||
(catch 'found
|
||||
(dotimes (_x 2)
|
||||
(while (re-search-forward regexp end t)
|
||||
(let ((syncname (match-string-no-properties 1)))
|
||||
(when (and (file-exists-p syncname)
|
||||
(file-equal-p filename syncname))
|
||||
(goto-char (point-at-bol))
|
||||
(throw 'found syncname))))
|
||||
(setq end beg
|
||||
beg (point-min))
|
||||
(goto-char beg)))))))))
|
||||
|
||||
|
||||
;; * ================================================================== *
|
||||
;; * Compatibility
|
||||
;; * ================================================================== *
|
||||
|
||||
;;;###autoload
|
||||
(define-obsolete-variable-alias
|
||||
'pdf-sync-tex-display-pdf-key
|
||||
'pdf-sync-forward-display-pdf-key nil)
|
||||
|
||||
;;;###autoload
|
||||
(define-obsolete-variable-alias
|
||||
'pdf-sync-goto-tex-hook
|
||||
'pdf-sync-backward-hook nil)
|
||||
|
||||
;;;###autoload
|
||||
(define-obsolete-variable-alias
|
||||
'pdf-sync-display-pdf-hook
|
||||
'pdf-sync-forward-hook nil)
|
||||
|
||||
;;;###autoload
|
||||
(define-obsolete-variable-alias
|
||||
'pdf-sync-display-pdf-action
|
||||
'pdf-sync-forward-display-action nil)
|
||||
|
||||
(define-obsolete-function-alias
|
||||
'pdf-sync-mouse-goto-tex
|
||||
'pdf-sync-backward-search-mouse)
|
||||
|
||||
(define-obsolete-function-alias
|
||||
'pdf-sync-goto-tex
|
||||
'pdf-sync-backward-search)
|
||||
|
||||
(define-obsolete-function-alias
|
||||
'pdf-sync-correlate-tex
|
||||
'pdf-sync-backward-correlate)
|
||||
|
||||
(define-obsolete-function-alias
|
||||
'pdf-sync-display-pdf
|
||||
'pdf-sync-forward-search)
|
||||
|
||||
(define-obsolete-function-alias
|
||||
'pdf-sync-correlate-pdf
|
||||
'pdf-sync-forward-correlate)
|
||||
|
||||
(provide 'pdf-sync)
|
||||
;;; pdf-sync.el ends here
|
||||
419
elpa/pdf-tools-20180428.827/pdf-tools-autoloads.el
Normal file
419
elpa/pdf-tools-20180428.827/pdf-tools-autoloads.el
Normal file
@@ -0,0 +1,419 @@
|
||||
;;; pdf-tools-autoloads.el --- automatically extracted autoloads
|
||||
;;
|
||||
;;; Code:
|
||||
|
||||
(add-to-list 'load-path (directory-file-name
|
||||
(or (file-name-directory #$) (car load-path))))
|
||||
|
||||
|
||||
;;;### (autoloads nil "pdf-annot" "pdf-annot.el" (0 0 0 0))
|
||||
;;; Generated autoloads from pdf-annot.el
|
||||
|
||||
(autoload 'pdf-annot-minor-mode "pdf-annot" "\
|
||||
Support for PDF Annotations.
|
||||
|
||||
\\{pdf-annot-minor-mode-map}
|
||||
|
||||
\(fn &optional ARG)" t nil)
|
||||
|
||||
(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "pdf-annot" '("pdf-annot-")))
|
||||
|
||||
;;;***
|
||||
|
||||
;;;### (autoloads nil "pdf-cache" "pdf-cache.el" (0 0 0 0))
|
||||
;;; Generated autoloads from pdf-cache.el
|
||||
|
||||
(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "pdf-cache" '("page" "pdf-cache-" "textregions" "boundingbox" "define-pdf-cache-function")))
|
||||
|
||||
;;;***
|
||||
|
||||
;;;### (autoloads nil "pdf-dev" "pdf-dev.el" (0 0 0 0))
|
||||
;;; Generated autoloads from pdf-dev.el
|
||||
|
||||
(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "pdf-dev" '("pdf-dev-")))
|
||||
|
||||
;;;***
|
||||
|
||||
;;;### (autoloads nil "pdf-history" "pdf-history.el" (0 0 0 0))
|
||||
;;; Generated autoloads from pdf-history.el
|
||||
|
||||
(autoload 'pdf-history-minor-mode "pdf-history" "\
|
||||
Keep a history of previously visited pages.
|
||||
|
||||
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 navigated with the following keys.
|
||||
|
||||
\\{pdf-history-minor-mode-map}
|
||||
|
||||
\(fn &optional ARG)" t nil)
|
||||
|
||||
(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "pdf-history" '("pdf-history-")))
|
||||
|
||||
;;;***
|
||||
|
||||
;;;### (autoloads nil "pdf-info" "pdf-info.el" (0 0 0 0))
|
||||
;;; Generated autoloads from pdf-info.el
|
||||
|
||||
(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "pdf-info" '("pdf-info-")))
|
||||
|
||||
;;;***
|
||||
|
||||
;;;### (autoloads nil "pdf-isearch" "pdf-isearch.el" (0 0 0 0))
|
||||
;;; Generated autoloads from pdf-isearch.el
|
||||
|
||||
(autoload 'pdf-isearch-minor-mode "pdf-isearch" "\
|
||||
Isearch mode for PDF buffer.
|
||||
|
||||
When this mode is enabled \\[isearch-forward], among other keys,
|
||||
starts an incremental search in this PDF document. Since this mode
|
||||
uses external programs to highlight found matches via
|
||||
image-processing, proceeding to the next match may be slow.
|
||||
|
||||
Therefore two isearch behaviours have been defined: Normal isearch and
|
||||
batch mode. The later one is a minor mode
|
||||
\(`pdf-isearch-batch-mode'), which when activated inhibits isearch
|
||||
from stopping at and highlighting every single match, but rather
|
||||
display them batch-wise. Here a batch means a number of matches
|
||||
currently visible in the selected window.
|
||||
|
||||
The kind of highlighting is determined by three faces
|
||||
`pdf-isearch-match' (for the current match), `pdf-isearch-lazy'
|
||||
\(for all other matches) and `pdf-isearch-batch' (when in batch
|
||||
mode), which see.
|
||||
|
||||
Colors may also be influenced by the minor-mode
|
||||
`pdf-view-dark-minor-mode'. If this is minor mode enabled, each face's
|
||||
dark colors, are used (see e.g. `frame-background-mode'), instead
|
||||
of the light ones.
|
||||
|
||||
\\{pdf-isearch-minor-mode-map}
|
||||
While in `isearch-mode' the following keys are available. Note
|
||||
that not every isearch command work as expected.
|
||||
|
||||
\\{pdf-isearch-active-mode-map}
|
||||
|
||||
\(fn &optional ARG)" t nil)
|
||||
|
||||
(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "pdf-isearch" '("pdf-isearch-")))
|
||||
|
||||
;;;***
|
||||
|
||||
;;;### (autoloads nil "pdf-links" "pdf-links.el" (0 0 0 0))
|
||||
;;; Generated autoloads from pdf-links.el
|
||||
|
||||
(autoload 'pdf-links-minor-mode "pdf-links" "\
|
||||
Handle links in PDF documents.\\<pdf-links-minor-mode-map>
|
||||
|
||||
If this mode is enabled, most links in the document may be
|
||||
activated by clicking on them or by pressing \\[pdf-links-action-perform] and selecting
|
||||
one of the displayed keys, or by using isearch limited to
|
||||
links via \\[pdf-links-isearch-link].
|
||||
|
||||
\\{pdf-links-minor-mode-map}
|
||||
|
||||
\(fn &optional ARG)" t nil)
|
||||
|
||||
(autoload 'pdf-links-action-perform "pdf-links" "\
|
||||
Follow LINK, depending on its type.
|
||||
|
||||
This may turn to another page, switch to another PDF buffer or
|
||||
invoke `pdf-links-browse-uri-function'.
|
||||
|
||||
Interactively, link is read via `pdf-links-read-link-action'.
|
||||
This function displays characters around the links in the current
|
||||
page and starts reading characters (ignoring case). After a
|
||||
sufficient number of characters have been read, the corresponding
|
||||
link's link is invoked. Additionally, SPC may be used to
|
||||
scroll the current page.
|
||||
|
||||
\(fn LINK)" t nil)
|
||||
|
||||
(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "pdf-links" '("pdf-links-")))
|
||||
|
||||
;;;***
|
||||
|
||||
;;;### (autoloads nil "pdf-misc" "pdf-misc.el" (0 0 0 0))
|
||||
;;; Generated autoloads from pdf-misc.el
|
||||
|
||||
(autoload 'pdf-misc-minor-mode "pdf-misc" "\
|
||||
FIXME: Not documented.
|
||||
|
||||
\(fn &optional ARG)" t nil)
|
||||
|
||||
(autoload 'pdf-misc-size-indication-minor-mode "pdf-misc" "\
|
||||
Provide a working size indication in the mode-line.
|
||||
|
||||
\(fn &optional ARG)" t nil)
|
||||
|
||||
(autoload 'pdf-misc-menu-bar-minor-mode "pdf-misc" "\
|
||||
Display a PDF Tools menu in the menu-bar.
|
||||
|
||||
\(fn &optional ARG)" t nil)
|
||||
|
||||
(autoload 'pdf-misc-context-menu-minor-mode "pdf-misc" "\
|
||||
Provide a right-click context menu in PDF buffers.
|
||||
|
||||
\\{pdf-misc-context-menu-minor-mode-map}
|
||||
|
||||
\(fn &optional ARG)" t nil)
|
||||
|
||||
(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "pdf-misc" '("pdf-misc-")))
|
||||
|
||||
;;;***
|
||||
|
||||
;;;### (autoloads nil "pdf-occur" "pdf-occur.el" (0 0 0 0))
|
||||
;;; Generated autoloads from pdf-occur.el
|
||||
|
||||
(autoload 'pdf-occur "pdf-occur" "\
|
||||
List lines matching STRING or PCRE.
|
||||
|
||||
Interactively search for a regexp. Unless a prefix arg was given,
|
||||
in which case this functions performs a string search.
|
||||
|
||||
If `pdf-occur-prefer-string-search' is non-nil, the meaning of
|
||||
the prefix-arg is inverted.
|
||||
|
||||
\(fn STRING &optional REGEXP-P)" t nil)
|
||||
|
||||
(autoload 'pdf-occur-multi-command "pdf-occur" "\
|
||||
Perform `pdf-occur' on multiple buffer.
|
||||
|
||||
For a programmatic search of multiple documents see
|
||||
`pdf-occur-search'.
|
||||
|
||||
\(fn)" t nil)
|
||||
|
||||
(defvar pdf-occur-global-minor-mode nil "\
|
||||
Non-nil if Pdf-Occur-Global minor mode is enabled.
|
||||
See the `pdf-occur-global-minor-mode' command
|
||||
for a description of this minor mode.
|
||||
Setting this variable directly does not take effect;
|
||||
either customize it (see the info node `Easy Customization')
|
||||
or call the function `pdf-occur-global-minor-mode'.")
|
||||
|
||||
(custom-autoload 'pdf-occur-global-minor-mode "pdf-occur" nil)
|
||||
|
||||
(autoload 'pdf-occur-global-minor-mode "pdf-occur" "\
|
||||
Enable integration of Pdf Occur with other modes.
|
||||
|
||||
This global minor mode enables (or disables)
|
||||
`pdf-occur-ibuffer-minor-mode' and `pdf-occur-dired-minor-mode'
|
||||
in all current and future ibuffer/dired buffer.
|
||||
|
||||
\(fn &optional ARG)" t nil)
|
||||
|
||||
(autoload 'pdf-occur-ibuffer-minor-mode "pdf-occur" "\
|
||||
Hack into ibuffer's do-occur binding.
|
||||
|
||||
This mode remaps `ibuffer-do-occur' to
|
||||
`pdf-occur-ibuffer-do-occur', which will start the PDF Tools
|
||||
version of `occur', if all marked buffer's are in `pdf-view-mode'
|
||||
and otherwise fallback to `ibuffer-do-occur'.
|
||||
|
||||
\(fn &optional ARG)" t nil)
|
||||
|
||||
(autoload 'pdf-occur-dired-minor-mode "pdf-occur" "\
|
||||
Hack into dired's `dired-do-search' binding.
|
||||
|
||||
This mode remaps `dired-do-search' to
|
||||
`pdf-occur-dired-do-search', which will start the PDF Tools
|
||||
version of `occur', if all marked buffer's are in `pdf-view-mode'
|
||||
and otherwise fallback to `dired-do-search'.
|
||||
|
||||
\(fn &optional ARG)" t nil)
|
||||
|
||||
(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "pdf-occur" '("pdf-occur-")))
|
||||
|
||||
;;;***
|
||||
|
||||
;;;### (autoloads nil "pdf-outline" "pdf-outline.el" (0 0 0 0))
|
||||
;;; Generated autoloads from pdf-outline.el
|
||||
|
||||
(autoload 'pdf-outline-minor-mode "pdf-outline" "\
|
||||
Display an outline of a PDF document.
|
||||
|
||||
This provides a PDF's outline on the menu bar via imenu.
|
||||
Additionally the same outline may be viewed in a designated
|
||||
buffer.
|
||||
|
||||
\\{pdf-outline-minor-mode-map}
|
||||
|
||||
\(fn &optional ARG)" t nil)
|
||||
|
||||
(autoload 'pdf-outline "pdf-outline" "\
|
||||
Display an PDF outline of BUFFER.
|
||||
|
||||
BUFFER defaults to the current buffer. Select the outline
|
||||
buffer, unless NO-SELECT-WINDOW-P is non-nil.
|
||||
|
||||
\(fn &optional BUFFER NO-SELECT-WINDOW-P)" t nil)
|
||||
|
||||
(autoload 'pdf-outline-imenu-enable "pdf-outline" "\
|
||||
Enable imenu in the current PDF buffer.
|
||||
|
||||
\(fn)" t nil)
|
||||
|
||||
(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "pdf-outline" '("pdf-outline")))
|
||||
|
||||
;;;***
|
||||
|
||||
;;;### (autoloads nil "pdf-sync" "pdf-sync.el" (0 0 0 0))
|
||||
;;; Generated autoloads from pdf-sync.el
|
||||
|
||||
(autoload 'pdf-sync-minor-mode "pdf-sync" "\
|
||||
Correlate a PDF position with the TeX file.
|
||||
\\<pdf-sync-minor-mode-map>
|
||||
This works via SyncTeX, which means the TeX sources need to have
|
||||
been compiled with `--synctex=1'. In AUCTeX this can be done by
|
||||
setting `TeX-source-correlate-method' to 'synctex (before AUCTeX
|
||||
is loaded) and enabling `TeX-source-correlate-mode'.
|
||||
|
||||
Then \\[pdf-sync-backward-search-mouse] in the PDF buffer will open the
|
||||
corresponding TeX location.
|
||||
|
||||
If AUCTeX is your preferred tex-mode, this library arranges to
|
||||
bind `pdf-sync-forward-display-pdf-key' (the default is `C-c C-g')
|
||||
to `pdf-sync-forward-search' in `TeX-source-correlate-map'. This
|
||||
function displays the PDF page corresponding to the current
|
||||
position in the TeX buffer. This function only works together
|
||||
with AUCTeX.
|
||||
|
||||
\(fn &optional ARG)" t nil)
|
||||
|
||||
(define-obsolete-variable-alias 'pdf-sync-tex-display-pdf-key 'pdf-sync-forward-display-pdf-key nil)
|
||||
|
||||
(define-obsolete-variable-alias 'pdf-sync-goto-tex-hook 'pdf-sync-backward-hook nil)
|
||||
|
||||
(define-obsolete-variable-alias 'pdf-sync-display-pdf-hook 'pdf-sync-forward-hook nil)
|
||||
|
||||
(define-obsolete-variable-alias 'pdf-sync-display-pdf-action 'pdf-sync-forward-display-action nil)
|
||||
|
||||
(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "pdf-sync" '("pdf-sync-")))
|
||||
|
||||
;;;***
|
||||
|
||||
;;;### (autoloads nil "pdf-tools" "pdf-tools.el" (0 0 0 0))
|
||||
;;; Generated autoloads from pdf-tools.el
|
||||
|
||||
(defvar pdf-tools-handle-upgrades t "\
|
||||
Whether PDF Tools should handle upgrading itself.")
|
||||
|
||||
(custom-autoload 'pdf-tools-handle-upgrades "pdf-tools" t)
|
||||
|
||||
(autoload 'pdf-tools-install "pdf-tools" "\
|
||||
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'.
|
||||
|
||||
\(fn &optional NO-QUERY-P SKIP-DEPENDENCIES-P NO-ERROR-P FORCE-DEPENDENCIES-P)" t nil)
|
||||
|
||||
(autoload 'pdf-tools-enable-minor-modes "pdf-tools" "\
|
||||
Enable MODES in the current buffer.
|
||||
|
||||
MODES defaults to `pdf-tools-enabled-modes'.
|
||||
|
||||
\(fn &optional MODES)" t nil)
|
||||
|
||||
(autoload 'pdf-tools-help "pdf-tools" "\
|
||||
|
||||
|
||||
\(fn)" t nil)
|
||||
|
||||
(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "pdf-tools" '("pdf-tools-")))
|
||||
|
||||
;;;***
|
||||
|
||||
;;;### (autoloads nil "pdf-util" "pdf-util.el" (0 0 0 0))
|
||||
;;; Generated autoloads from pdf-util.el
|
||||
|
||||
(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "pdf-util" '("pdf-util-" "display-buffer-split-below-and-attach")))
|
||||
|
||||
;;;***
|
||||
|
||||
;;;### (autoloads nil "pdf-view" "pdf-view.el" (0 0 0 0))
|
||||
;;; Generated autoloads from pdf-view.el
|
||||
|
||||
(autoload 'pdf-view-bookmark-jump-handler "pdf-view" "\
|
||||
The bookmark handler-function interface for bookmark BMK.
|
||||
|
||||
See also `pdf-view-bookmark-make-record'.
|
||||
|
||||
\(fn BMK)" nil nil)
|
||||
|
||||
(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "pdf-view" '("pdf-view-")))
|
||||
|
||||
;;;***
|
||||
|
||||
;;;### (autoloads nil "pdf-virtual" "pdf-virtual.el" (0 0 0 0))
|
||||
;;; Generated autoloads from pdf-virtual.el
|
||||
|
||||
(autoload 'pdf-virtual-edit-mode "pdf-virtual" "\
|
||||
Major mode when editing a virtual PDF buffer.
|
||||
|
||||
\(fn)" t nil)
|
||||
|
||||
(autoload 'pdf-virtual-view-mode "pdf-virtual" "\
|
||||
Major mode in virtual PDF buffers.
|
||||
|
||||
\(fn)" t nil)
|
||||
|
||||
(defvar pdf-virtual-global-minor-mode nil "\
|
||||
Non-nil if Pdf-Virtual-Global minor mode is enabled.
|
||||
See the `pdf-virtual-global-minor-mode' command
|
||||
for a description of this minor mode.
|
||||
Setting this variable directly does not take effect;
|
||||
either customize it (see the info node `Easy Customization')
|
||||
or call the function `pdf-virtual-global-minor-mode'.")
|
||||
|
||||
(custom-autoload 'pdf-virtual-global-minor-mode "pdf-virtual" nil)
|
||||
|
||||
(autoload 'pdf-virtual-global-minor-mode "pdf-virtual" "\
|
||||
Enable recognition and handling of VPDF files.
|
||||
|
||||
\(fn &optional ARG)" t nil)
|
||||
|
||||
(autoload 'pdf-virtual-buffer-create "pdf-virtual" "\
|
||||
|
||||
|
||||
\(fn &optional FILENAMES BUFFER-NAME DISPLAY-P)" t nil)
|
||||
|
||||
(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "pdf-virtual" '("pdf-virtual-")))
|
||||
|
||||
;;;***
|
||||
|
||||
;;;### (autoloads nil nil ("pdf-tools-pkg.el") (0 0 0 0))
|
||||
|
||||
;;;***
|
||||
|
||||
;; Local Variables:
|
||||
;; version-control: never
|
||||
;; no-byte-compile: t
|
||||
;; no-update-autoloads: t
|
||||
;; coding: utf-8
|
||||
;; End:
|
||||
;;; pdf-tools-autoloads.el ends here
|
||||
9
elpa/pdf-tools-20180428.827/pdf-tools-pkg.el
Normal file
9
elpa/pdf-tools-20180428.827/pdf-tools-pkg.el
Normal file
@@ -0,0 +1,9 @@
|
||||
(define-package "pdf-tools" "20180428.827" "Support library for PDF documents."
|
||||
'((emacs "24.3")
|
||||
(tablist "0.70")
|
||||
(let-alist "1.0.4"))
|
||||
:keywords
|
||||
'("files" "multimedia"))
|
||||
;; Local Variables:
|
||||
;; no-byte-compile: t
|
||||
;; End:
|
||||
515
elpa/pdf-tools-20180428.827/pdf-tools.el
Normal file
515
elpa/pdf-tools-20180428.827/pdf-tools.el
Normal file
@@ -0,0 +1,515 @@
|
||||
;;; 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: 0.90
|
||||
;; 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
|
||||
;; 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)
|
||||
|
||||
(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 falied.
|
||||
|
||||
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"
|
||||
autobuild
|
||||
(shell-quote-argument target-directory)
|
||||
(cond
|
||||
(skip-dependencies-p " -D")
|
||||
(force-dependencies-p " -d")
|
||||
(t "")))
|
||||
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
|
||||
1310
elpa/pdf-tools-20180428.827/pdf-util.el
Normal file
1310
elpa/pdf-tools-20180428.827/pdf-util.el
Normal file
File diff suppressed because it is too large
Load Diff
1603
elpa/pdf-tools-20180428.827/pdf-view.el
Normal file
1603
elpa/pdf-tools-20180428.827/pdf-view.el
Normal file
File diff suppressed because it is too large
Load Diff
1042
elpa/pdf-tools-20180428.827/pdf-virtual.el
Normal file
1042
elpa/pdf-tools-20180428.827/pdf-virtual.el
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user