Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"1 of n" result for Emacs search

Tags:

search

emacs

When I use incremental search in emacs I can't know where I am in whole matches. In Chrome browser it says location using "2 of 30". How can I do that in Emacs?

like image 589
user150497 Avatar asked Feb 08 '13 01:02

user150497


2 Answers

Here's my first attempt to implement this.

It uses the lazy highlighting that isearch implements, and forces the highlighting to cover the entire buffer (not just the visible portions) - which can slow down the search on large buffers. It then updates the display to include a current position (of total) relative to the highlighted search results.

This has the drawback that it is dependent on the entire buffer being searched and highlighted. And, sometimes when you C-s to the next match, the display changes to (0 of 1) even though the highlights are clearly still present.

But, it seems to be a reasonable first cut.

Prepare for big cut/paste:

(require 'isearch)
(defun lazy-highlight-cleanup (&optional force)
  "Stop lazy highlighting and remove extra highlighting from current buffer.
FORCE non-nil means do it whether or not `lazy-highlight-cleanup'
is nil.  This function is called when exiting an incremental search if
`lazy-highlight-cleanup' is non-nil."
  (interactive '(t))
  (if (or force lazy-highlight-cleanup)
      (while isearch-lazy-highlight-overlays
        (delete-overlay (car isearch-lazy-highlight-overlays))
        (setq isearch-lazy-highlight-overlays
              (cdr isearch-lazy-highlight-overlays))))
  (when isearch-lazy-highlight-timer
    (cancel-timer isearch-lazy-highlight-timer)
    (setq isearch-message-suffix-add "")
    (setq isearch-lazy-highlight-timer nil)))

(defun isearch-lazy-highlight-search ()
  "Search ahead for the next or previous match, for lazy highlighting.
Attempt to do the search exactly the way the pending Isearch would."
  (condition-case nil
      (let ((case-fold-search isearch-lazy-highlight-case-fold-search)
            (isearch-regexp isearch-lazy-highlight-regexp)
            (search-spaces-regexp isearch-lazy-highlight-space-regexp)
            (isearch-word isearch-lazy-highlight-word)
            (search-invisible nil)  ; don't match invisible text
            (retry t)
            (success nil)
            (isearch-forward isearch-lazy-highlight-forward)
            (bound (if isearch-lazy-highlight-forward
                       (min (or isearch-lazy-highlight-end-limit (point-max))
                            (if isearch-lazy-highlight-wrapped
                                isearch-lazy-highlight-start
                              (isearch-window-end)))
                     (max (or isearch-lazy-highlight-start-limit (point-min))
                          (if isearch-lazy-highlight-wrapped
                              isearch-lazy-highlight-end
                            (isearch-window-start))))))
        ;; Use a loop like in `isearch-search'.
        (while retry
          (setq success (isearch-search-string
                         isearch-lazy-highlight-last-string bound t))

          ;; Clear RETRY unless the search predicate says
          ;; to skip this search hit.
          (if (or (not success)
                  (= (point) bound) ; like (bobp) (eobp) in `isearch-search'.
                  (= (match-beginning 0) (match-end 0))
                  (funcall isearch-filter-predicate
                           (match-beginning 0) (match-end 0)))
              (setq retry nil)))
        success)
    (error nil)))

(defun isearch-find-current-overlay ()
  (let ((total 0)
        (count 1)
        (olist isearch-lazy-highlight-overlays))
    (while olist
      (setq total (1+ total))
      (if (< (overlay-end (car olist)) (point))
          (setq count (1+ count)))
      (setq olist
            (cdr olist)))
    (cons count total)))

(add-hook 'isearch-update-post-hook 'isearch-count-message)

(defun isearch-count-message ()
  (let ((counts (isearch-find-current-overlay)))
    (setq isearch-message-suffix-add (format " (%d of %d)" (car counts) (cdr counts)))))

(defun isearch-window-start ()
  "force highlight entire buffer"
  (point-min))

(defun isearch-window-end ()
  "force highlight entire buffer"
  (point-max))

(defun isearch-lazy-highlight-update ()
  "Update highlighting of other matches for current search."
  (let ((max lazy-highlight-max-at-a-time)
        (looping t)
        nomore)
    (with-local-quit
      (save-selected-window
        (if (and (window-live-p isearch-lazy-highlight-window)
                 (not (eq (selected-window) isearch-lazy-highlight-window)))
            (select-window isearch-lazy-highlight-window))
        (save-excursion
          (save-match-data
            (goto-char (if isearch-lazy-highlight-forward
                           isearch-lazy-highlight-end
                         isearch-lazy-highlight-start))
            (while looping
              (let ((found (isearch-lazy-highlight-search)))
                (when max
                  (setq max (1- max))
                  (if (<= max 0)
                      (setq looping nil)))
                (if found
                    (let ((mb (match-beginning 0))
                          (me (match-end 0)))
                      (if (= mb me) ;zero-length match
                          (if isearch-lazy-highlight-forward
                              (if (= mb (if isearch-lazy-highlight-wrapped
                                            isearch-lazy-highlight-start
                                          (isearch-window-end)))
                                  (setq found nil)
                                (forward-char 1))
                            (if (= mb (if isearch-lazy-highlight-wrapped
                                          isearch-lazy-highlight-end
                                        (isearch-window-start)))
                                (setq found nil)
                              (forward-char -1)))

                        ;; non-zero-length match
                        (let ((ov (make-overlay mb me)))
                          (push ov isearch-lazy-highlight-overlays)
                          ;; 1000 is higher than ediff's 100+,
                          ;; but lower than isearch main overlay's 1001
                          (overlay-put ov 'priority 1000)
                          (overlay-put ov 'face lazy-highlight-face)
                          (overlay-put ov 'window (selected-window))))
                      (if isearch-lazy-highlight-forward
                          (setq isearch-lazy-highlight-end (point))
                        (setq isearch-lazy-highlight-start (point)))))

                ;; not found or zero-length match at the search bound
                (if (not found)
                    (if isearch-lazy-highlight-wrapped
                        (setq looping nil
                              nomore  t)
                      (setq isearch-lazy-highlight-wrapped t)
                      (if isearch-lazy-highlight-forward
                          (progn
                            (setq isearch-lazy-highlight-end (isearch-window-start))
                            (goto-char (max (or isearch-lazy-highlight-start-limit (point-min))
                                            (isearch-window-start))))
                        (setq isearch-lazy-highlight-start (isearch-window-end))
                        (goto-char (min (or isearch-lazy-highlight-end-limit (point-max))
                                        (isearch-window-end))))))))
            (unless nomore
              (setq isearch-lazy-highlight-timer
                    (run-at-time lazy-highlight-interval nil
                                 'isearch-lazy-highlight-update)))))))))
like image 91
Trey Jackson Avatar answered Sep 21 '22 13:09

Trey Jackson


I saw this the other day:

https://github.com/syohex/emacs-anzu

anzu.el is an Emacs port of anzu.vim. anzu.el provides a minor mode which displays current match and total matches information in the mode-line in various search modes.

The screenshot on the github page is a gif animation of its functionality.

like image 23
phils Avatar answered Sep 22 '22 13:09

phils