diff options
author | Blendoit <blendoit@gmail.com> | 2020-08-01 15:18:40 -0700 |
---|---|---|
committer | Blendoit <blendoit@gmail.com> | 2020-08-01 15:18:40 -0700 |
commit | 374ae3de24187512adddf01a56e5eb52c79db65f (patch) | |
tree | 847adf6824b56394f5a040ba45863e2dbdceac70 /elpa/pdf-tools-20200512.1524/pdf-isearch.el | |
parent | 54fbf6576cf2dd94ef5af332a6075723a9dfa8b3 (diff) |
Include contents of elpa/ sources + theme update.
Diffstat (limited to 'elpa/pdf-tools-20200512.1524/pdf-isearch.el')
-rw-r--r-- | elpa/pdf-tools-20200512.1524/pdf-isearch.el | 831 |
1 files changed, 831 insertions, 0 deletions
diff --git a/elpa/pdf-tools-20200512.1524/pdf-isearch.el b/elpa/pdf-tools-20200512.1524/pdf-isearch.el new file mode 100644 index 0000000..563e721 --- /dev/null +++ b/elpa/pdf-tools-20200512.1524/pdf-isearch.el @@ -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: |