emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[elpa] master 6790ce1 2/2: Some details


From: Michael Heerdegen
Subject: [elpa] master 6790ce1 2/2: Some details
Date: Wed, 2 Aug 2017 18:12:28 -0400 (EDT)

branch: master
commit 6790ce1e29a1f384f8a97e8ab585bcff10e666a7
Author: Michael Heerdegen <address@hidden>
Commit: Michael Heerdegen <address@hidden>

    Some details
---
 packages/el-search/el-search-x.el |  71 +++---
 packages/el-search/el-search.el   | 446 ++++++++++++++++++++------------------
 2 files changed, 275 insertions(+), 242 deletions(-)

diff --git a/packages/el-search/el-search-x.el 
b/packages/el-search/el-search-x.el
index 8e96682..2838535 100644
--- a/packages/el-search/el-search-x.el
+++ b/packages/el-search/el-search-x.el
@@ -120,14 +120,14 @@ SYMBOL  Matches any symbol S matched by SYMBOL's name 
interpreted
 'SYMBOL Matches SYMBOL, 'SYMBOL and #'SYMBOL (so it's like the above
         without regexp matching).
 STRING  Matches any string matched by STRING interpreted as a
-        regexp
-_       Matches any list element
-__      Matches any number of list elements (including zero)
+        regexp.
+_       Matches any list element.
+__      Matches any number of list elements (including zero).
 ^       Matches zero elements, but only at the beginning of a list.
         Only allowed as the first of the LPATS.
 $       Matches zero elements, but only at the end of a list.
         Only allowed as the last of the LPATS.
-PAT     Anything else is interpreted as a standard pattern, and
+PAT     Anything else is interpreted as a standard pattern and
         matches one list element matched by it.  Note: If matching
         PAT binds any symbols, occurrences in any following PATs
         are not turned into equivalence tests; the scope of symbol
@@ -182,17 +182,17 @@ could use this pattern:
 (defcustom el-search-change-revision-transformer-function nil
   "Transformer function for the REVISION argument of `change' and `changed'.
 
-When specified, this function is called with two arguments: the
-REVISION argument passed to `change' or `changed', and the
-current file name, and the returned value is used instead of
-REVISION.
+When specified, this function is called with two arguments - the
+REVISION argument passed to `change' or `changed' and the current
+file name - and the return value is used as REVISION argument for
+these patterns.
 
 The default value is nil."
   :group 'el-search
   :type '(choice (const :tag "No transformer" nil)
                  (function :tag "User specified function")))
 
-(defalias 'el-search--file-truename
+(defalias 'el-search--file-truename-wstm
   ;; We call `file-truename' very often and it's quite slow
   (el-search-with-short-term-memory #'file-truename))
 
@@ -207,10 +207,27 @@ COMMIT defaults to HEAD."
               (format "git diff -z --name-only %s --" (shell-quote-argument 
commit)))
              "\0" t))))
 
+(defvar vc-git-diff-switches)
+(defun el-search--file-changed-p (file revision)
+  "Return non-nil when FILE has changed relative to REVISION."
+  (cl-callf el-search--file-truename-wstm file)
+  (when-let ((backend (vc-backend file)))
+    (ignore-errors
+      (let ((default-directory (file-name-directory file))
+            (vc-git-diff-switches nil)) ;FIXME: necessary e.g. for my init 
file -- why?
+        (and
+         (with-temp-buffer
+           (= 1 (vc-call-backend backend 'diff (list file) nil revision 
(current-buffer))))
+         (with-temp-buffer
+           (= 1 (vc-call-backend backend 'diff (list file) revision nil 
(current-buffer)))))))))
+
 (defun el-search--changes-from-diff-hl (revision)
-  "Return a list of changed regions (as conses of positions) since REVISION.
-Use variable `el-search--cached-changes' for caching."
-  (let ((buffer-file-name (el-search--file-truename buffer-file-name))) 
;shouldn't be necessary, but it is...
+  "Return the changed regions in the current buffer's file.
+The return value is a list of conses (START . END) of all changes
+relative to REVISION.
+
+Uses variable `el-search--cached-changes' for caching."
+  (let ((buffer-file-name (el-search--file-truename-wstm buffer-file-name))) 
;shouldn't be necessary, but it is...
     (if (and (consp el-search--cached-changes)
              (equal (car el-search--cached-changes)
                     (list revision (visited-file-modtime))))
@@ -246,8 +263,10 @@ Use variable `el-search--cached-changes' for caching."
                                                       (let ((default-directory 
(file-name-directory buffer-file-name)))
                                                         
(diff-hl-changes)))))))))))))))
 
-(defun el-search--change-p (posn &optional revision)
+(defun el-search--change-p (posn revision)
   ;; Non-nil when sexp after POSN is part of a change
+  (when (buffer-modified-p)
+    (user-error "Buffer is modified - please save"))
   (save-restriction
     (widen)
     (let ((changes (el-search--changes-from-diff-hl revision))
@@ -266,7 +285,7 @@ Use variable `el-search--cached-changes' for caching."
                        (and (thunk-force atomic?)
                             (<= (caar changes) sexp-end)))))))
 
-(defun el-search--changed-p (posn &optional revision)
+(defun el-search--changed-p (posn revision)
   ;; Non-nil when sexp after POSN contains a change
   (when (buffer-modified-p)
     (user-error "Buffer is modified - please save"))
@@ -278,23 +297,9 @@ Use variable `el-search--cached-changes' for caching."
       (and changes
            (< (caar changes) (scan-sexps posn 1))))))
 
-(defvar vc-git-diff-switches)
-(defun el-search--file-changed-p (file rev)
-  ;; FIXME: it would be better to calculate once a list of all changed
-  ;; files in the repository
-  (cl-callf el-search--file-truename file)
-  (when-let ((backend (vc-backend file)))
-    (ignore-errors
-      (let ((default-directory (file-name-directory file))
-            (vc-git-diff-switches nil)) ;FIXME: necessary e.g. for my init 
file -- why?
-        (and
-         (with-temp-buffer
-           (= 1 (vc-call-backend backend 'diff (list file) nil rev 
(current-buffer))))
-         (with-temp-buffer
-           (= 1 (vc-call-backend backend 'diff (list file) rev nil 
(current-buffer)))))))))
-
 (defun el-search-change--heuristic-matcher (&optional revision)
-  (let* ((get-changed-files-in-repo
+  (let* ((revision (or revision "HEAD"))
+         (get-changed-files-in-repo
           (el-search-with-short-term-memory 
#'el-search--changed-files-in-repo))
          (file-changed-p (el-search-with-short-term-memory
                           (lambda (file-name-or-buffer)
@@ -302,12 +307,13 @@ Use variable `el-search--cached-changes' for caching."
                             (when-let ((file (if (stringp file-name-or-buffer)
                                                  file-name-or-buffer
                                                (buffer-file-name 
file-name-or-buffer))))
-                              (cl-callf el-search--file-truename file)
+                              (cl-callf el-search--file-truename-wstm file)
                               (let ((default-directory (file-name-directory 
file)))
                                 (when-let ((backend (vc-backend file))
                                            (root-dir
                                             (condition-case err
                                                 (vc-call-backend backend 'root 
default-directory)
+                                              ;; Same handler as in 
`vc-root-dir'
                                               (vc-not-supported
                                                (unless (eq (cadr err) 'root)
                                                  (signal (car err) (cdr err)))
@@ -318,8 +324,7 @@ Use variable `el-search--cached-changes' for caching."
                                             root-dir
                                             (funcall (or 
el-search-change-revision-transformer-function
                                                          (lambda (rev _) rev))
-                                                     (or revision "HEAD")
-                                                     file))))))))))
+                                                     revision file))))))))))
     (lambda (file-name-or-buffer _) (funcall file-changed-p 
file-name-or-buffer))))
 
 (el-search-defpattern change (&optional revision)
diff --git a/packages/el-search/el-search.el b/packages/el-search/el-search.el
index 898c0ba..837aedf 100644
--- a/packages/el-search/el-search.el
+++ b/packages/el-search/el-search.el
@@ -414,9 +414,12 @@ tested.  "
 (defcustom el-search-replace-auto-save-buffers 'ask
   "Whether to automatically save modified buffers.
 When non-nil, save modified file buffers when query-replace is
-finished there.  If the non-nil value is the symbol ask, ask for
-confirmation for each buffer.  You can still let all following
-buffers automatically be saved or left modified from the prompt.
+finished there.
+
+If the non-nil value is the symbol ask, ask for confirmation for
+each buffer.  You can still let all following buffers
+automatically be saved or left unsaved from the prompt.
+
 Save automatically for any other non-nil value.
 
 The default value is ask."
@@ -773,14 +776,20 @@ for details.
                      el-search--pcase-macros)
      ,@body))
 
-(defun el-search--macroexpand-1 (pattern)
+(defun el-search--macroexpand-1 (pattern &optional n)
   "Expand el-search PATTERN.
 This is like `pcase--macroexpand' but expands only patterns
 defined with `el-search-defpattern' and performs only one
 expansion step.  If no entry for this pattern type exists in
-`el-search--pcase-macros', PATTERN is returned."
+`el-search--pcase-macros', PATTERN is returned.
+
+With optional integer argument N given, successively macroexpand
+N times."
+  (cl-callf or n 1)
   (if-let ((expander (alist-get (car-safe pattern) el-search--pcase-macros)))
-      (apply expander (cdr pattern))
+      (let ((expanded (apply expander (cdr pattern))))
+        (if (<= n 1) expanded
+          (el-search--macroexpand-1 expanded (1- n))))
     pattern))
 
 (defun el-search--macroexpand (pattern)
@@ -841,7 +850,9 @@ be specified as third optional argument."
                                      (save-excursion
                                        (prog1 (read (current-buffer))
                                          (setq end-of-defun (point)))))))))
-                (goto-char (or end-of-defun (scan-lists (point) 1 0))))
+                (goto-char (or end-of-defun
+                               ;; The thunk hasn't been forced
+                               (scan-lists (point) 1 0))))
                ((el-search--match-p matcher current-expr)
                 (setq match-beg (point)
                       opoint (point)))
@@ -1365,7 +1376,7 @@ that contain a file named \".nosearch\" are excluded as 
well."
 
 ;;;; Additional pattern type definitions
 
-(defun el-search-regexp-like (thing)
+(defun el-search-regexp-like-p (thing)
   "Return non-nil when THING is regexp like.
 
 In el-search, a regexp-like is either a normal regexp (i.e. a
@@ -1391,7 +1402,7 @@ currently enabled."
 (defun el-search--string-matcher (regexp-like)
   "Return a compiled match predicate for REGEXP-LIKE.
 That's a predicate returning non-nil when the
-`el-search-regexp-like' REGEXP-LIKE matches the (only)
+`el-search-regexp-like-p' REGEXP-LIKE matches the (only)
 argument (that should be a string)."
   (let ((match-bindings ()) regexp)
     (pcase regexp-like
@@ -1409,7 +1420,7 @@ argument (that should be a string)."
 
 (el-search-defpattern string (&rest regexps)
   "Matches any string that is matched by all REGEXPS.
-Any of the REGEXPS is an `el-search-regexp-like'."
+Any of the REGEXPS is `el-search-regexp-like-p'."
   (declare (heuristic-matcher
             (lambda (&rest regexps)
               (let ((matchers (mapcar #'el-search--string-matcher regexps)))
@@ -1419,14 +1430,14 @@ Any of the REGEXPS is an `el-search-regexp-like'."
                      (and (stringp atom)
                           (cl-every (lambda (matcher) (funcall matcher atom)) 
matchers)))
                    (thunk-force atoms-thunk)))))))
-  (el-search-defpattern--check-args "string" regexps #'el-search-regexp-like)
+  (el-search-defpattern--check-args "string" regexps #'el-search-regexp-like-p)
   `(and (pred stringp)
         ,@(mapcar (lambda (regexp) `(pred ,(el-search--string-matcher regexp)))
                   regexps)))
 
 (el-search-defpattern symbol (&rest regexps)
   "Matches any symbol whose name is matched by all REGEXPS.
-Any of the REGEXPS is an `el-search-regexp-like'."
+Any of the REGEXPS is `el-search-regexp-like-p'."
   (declare (heuristic-matcher
             (lambda (&rest regexps)
               (let ((matchers (mapcar #'el-search--string-matcher regexps)))
@@ -1436,7 +1447,7 @@ Any of the REGEXPS is an `el-search-regexp-like'."
                      (when-let ((symbol-name (and (symbolp atom) (symbol-name 
atom))))
                        (cl-every (lambda (matcher) (funcall matcher 
symbol-name)) matchers)))
                    (thunk-force atoms-thunk)))))))
-  (el-search-defpattern--check-args "symbol" regexps #'el-search-regexp-like)
+  (el-search-defpattern--check-args "symbol" regexps #'el-search-regexp-like-p)
   `(and (pred symbolp) (app symbol-name (string ,@regexps))))
 
 (defun el-search--contains-p (matcher expr)
@@ -1511,10 +1522,10 @@ never matches."
   (el-search-defpattern--check-args
    "in-buffer" atoms
    (lambda (arg)
-     (cl-flet ((atom-or-string-p (arg) (or (atom arg) (stringp arg))))
-       (pcase arg
-         ((or (pred atom-or-string-p) `',(pred atom-or-string-p) ``,(pred 
atom-or-string-p)) t))))
-   "argument not an atom or string")
+     (pcase arg
+       ((or (pred el-search--atomic-p) `',(pred el-search--atomic-p) ``,(pred 
el-search--atomic-p))
+        t)))
+   "argument not atomic")
   (let ((in-buffer-matcher (apply #'el-search--in-buffer-matcher atoms)))
     `(guard (funcall ',in-buffer-matcher (current-buffer) nil))))
 
@@ -1575,7 +1586,7 @@ This pattern type matches when the object is a symbol for 
that
 
    (file-name-sans-extension (file-name-nondirectory FILENAME)))
 
-is matched by the `el-search-regexp-like' REGEXP."
+is matched by the `el-search-regexp-like-p' REGEXP."
   (declare
    (heuristic-matcher
     (lambda (regexp)
@@ -1584,7 +1595,7 @@ is matched by the `el-search-regexp-like' REGEXP."
                   (copy-sequence load-history)
                   regexp)
                  (thunk-force atoms-thunk))))))
-  (el-search-defpattern--check-args "symbol-file" (list regexp) 
#'el-search-regexp-like)
+  (el-search-defpattern--check-args "symbol-file" (list regexp) 
#'el-search-regexp-like-p)
   (let ((this (make-symbol "this")))
     `(and ,this
           (guard (funcall (el-search--symbol-file-matcher (copy-sequence 
load-history)
@@ -1595,7 +1606,7 @@ is matched by the `el-search-regexp-like' REGEXP."
   ;; Return a file name matcher for the REGEXPS.  This is a predicate
   ;; accepting two arguments that returns non-nil when the first
   ;; argument is a file name (i.e. a string) that is matched by all
-  ;; `el-search-regexp-like' REGEXPS, or a buffer whose associated file
+  ;; `el-search-regexp-like-p' REGEXPS, or a buffer whose associated file
   ;; name matches accordingly.  It ignores the second argument.
   (let ((get-file-name (lambda (file-name-or-buffer)
                          (if (bufferp file-name-or-buffer)
@@ -1614,13 +1625,13 @@ is matched by the `el-search-regexp-like' REGEXP."
 (el-search-defpattern filename (&rest regexps)
   "Matches anything when the searched buffer has an associated file.
 
-With any `el-search-regexp-like' REGEXPS given, the file's
+With any `el-search-regexp-like-p' REGEXPS given, the file's
 absolute name must be matched by all of them."
   ;;FIXME: should we also allow to match the f-n-nondirectory and
   ;;f-n-sans-extension?  Maybe it could become a new pattern type named 
`feature'?
   (declare (heuristic-matcher #'el-search--filename-matcher)
            (inverse-heuristic-matcher t))
-  (el-search-defpattern--check-args "filename" regexps #'el-search-regexp-like)
+  (el-search-defpattern--check-args "filename" regexps 
#'el-search-regexp-like-p)
   (let ((file-name-matcher (apply #'el-search--filename-matcher regexps)))
     ;; We can't expand to just t because this would not work with `not'.
     ;; `el-search--filename-matcher' caches the result, so this is still a
@@ -1660,23 +1671,25 @@ removal only once.")
       (unless (pos-visible-in-window-p
                (save-excursion (goto-char (cadr bounds))
                                (line-end-position (max +3 (/ wheight 25)))))
-        (scroll-up (min
-                    (max
-                     ;; make at least sexp end + a small margin visible
-                     (- (line-number-at-pos (cadr bounds))
-                        (line-number-at-pos (window-end))
-                        (- (max 2 (/ wheight 4))))
-                     ;; also try to center current sexp
-                     (- (/ ( + (line-number-at-pos (car bounds))
-                               (line-number-at-pos (cadr bounds)))
-                           2)
-                        (/ (+ (line-number-at-pos (window-start))
-                              (line-number-at-pos (window-end)))
-                           2)))
-                    ;; but also ensure at least a small margin is left between 
point and window start
-                    (- (line-number-at-pos (car  bounds))
-                       (line-number-at-pos (window-start))
-                       3))))))
+        (condition-case nil
+            (scroll-up (min
+                        (max
+                         ;; make at least sexp end + a small margin visible
+                         (- (line-number-at-pos (cadr bounds))
+                            (line-number-at-pos (window-end))
+                            (- (max 2 (/ wheight 4))))
+                         ;; also try to center current sexp
+                         (- (/ ( + (line-number-at-pos (car bounds))
+                                   (line-number-at-pos (cadr bounds)))
+                               2)
+                            (/ (+ (line-number-at-pos (window-start))
+                                  (line-number-at-pos (window-end)))
+                               2)))
+                        ;; but also ensure at least a small margin is left 
between point and window start
+                        (- (line-number-at-pos (car  bounds))
+                           (line-number-at-pos (window-start))
+                           3)))
+          ((beginning-of-buffer end-of-buffer) nil)))))
 
   (add-hook 'post-command-hook #'el-search-hl-post-command-fun t t))
 
@@ -1788,6 +1801,8 @@ that the current search."
       (setq el-search--success t)
       (el-search--set-wrap-flag nil)))
   (el-search-compile-pattern-in-search el-search--current-search)
+  (el-search--message-no-log
+   "%s" (el-search--get-search-description-string el-search--current-search))
   (if-let ((search el-search--current-search)
            (current-head (el-search-object-head search))
            (current-search-buffer (el-search-head-buffer current-head)))
@@ -1906,6 +1921,15 @@ continued."
          ;; file-truename on both args what we don't want, so we use this:
          (string-match-p "\\`\\.\\." (file-relative-name buffer-or-file-name 
directory))))))
 
+(defun el-search-pattern--interactive ()
+  (list (if (or
+             ;;Hack to make a pop-up buffer search from occur "stay active"
+             (memq #'el-search-hl-post-command-fun post-command-hook)
+             (and (eq this-command last-command)
+                  (or el-search--success el-search--wrap-flag)))
+            (el-search--current-pattern)
+          (el-search--read-pattern-for-interactive))))
+
 ;;;###autoload
 (defun el-search-pattern (pattern)
   "Start new or resume last elisp buffer search.
@@ -1927,14 +1951,7 @@ PATTERN is an \"el-search\" pattern - which means, 
either a
 types defined with `el-search-defpattern'.  The following
 additional pattern types are currently defined:"
   (declare (interactive-only el-search-forward))
-  (interactive (list (if (or
-                           ;FIXME: ugh!  Needed for a pop-up buffer from occur
-                          (memq #'el-search-hl-post-command-fun 
post-command-hook)
-
-                          (and (eq this-command last-command)
-                               (or el-search--success el-search--wrap-flag)))
-                         (el-search--current-pattern)
-                       (el-search--read-pattern-for-interactive))))
+  (interactive (el-search-pattern--interactive))
   (cond
    ((eq el-search--wrap-flag 'forward)
     (progn
@@ -1975,10 +1992,7 @@ With prefix arg, restart the current search."
 (defun el-search-pattern-backwards (pattern)
   "Search the current buffer backwards for matches of PATTERN."
   (declare (interactive-only t))
-  (interactive (list (if (and (eq last-command 'el-search-pattern)
-                              (or el-search--success el-search--wrap-flag))
-                         (el-search--current-pattern)
-                       (el-search--read-pattern-for-interactive))))
+  (interactive (el-search-pattern--interactive))
   (if (eq pattern (el-search--current-pattern))
       (el-search-compile-pattern-in-search el-search--current-search)
     (el-search-setup-search-1
@@ -2155,163 +2169,177 @@ Use the normal search commands to seize the search."
 
 (put 'el-search-occur-mode 'mode-class 'special)
 
-
+(declare-function which-func-ff-hook which-func)
 (defun el-search--occur (search &optional buffer)
-  (let ((occur-buffer (or buffer (generate-new-buffer "*El Occur*"))))
-    (setq this-command 'el-search-pattern)
-    (setq-local el-search--temp-buffer-flag nil)
-    (with-selected-window (if buffer (selected-window)
-                            (display-buffer
-                             occur-buffer
-                             '((display-buffer-pop-up-window 
display-buffer-use-some-window))))
-      (let ((inhibit-read-only t))
-        (if el-search-occur-search-object
-            (progn
-              (erase-buffer)
-              (delete-all-overlays))
-          (el-search-occur-mode)
-          (setq el-search-occur-search-object search))
-        (insert (format ";;; * %s   -*- mode: el-search-occur -*-\n\n;; %s\n\n"
-                        (current-time-string)
-                        (el-search--get-search-description-string search)))
-        (condition-case-unless-debug err
-            (let ((stream-of-matches
-                   (el-search--stream-partition
-                    (funcall (el-search-object-get-matches search))
-                    (lambda (this prev) (and (eq (car this) (car prev)) (equal 
(nth 2 this) (nth 2 prev))))))
-                  stream-of-buffer-matches  buffer-matches
-                  (matching-files 0) (matching-buffers 0) (overall-matches 0))
-              (while (setq stream-of-buffer-matches (stream-pop 
stream-of-matches))
-                (setq buffer-matches (seq-length stream-of-buffer-matches))
-                (cl-incf overall-matches buffer-matches)
-                (pcase-let ((`(,buffer ,_ ,file) (stream-first 
stream-of-buffer-matches)))
-                  (if file (cl-incf matching-files) (cl-incf matching-buffers))
-                  (insert "\n;;; ** ")
-                  (insert-button
-                   (or file (format "%S" buffer))
-                   'action
-                   (let ((pattern (el-search--current-pattern)))
-                     (lambda (_)
-                       (pop-to-buffer
-                        (if file (find-file-noselect file) buffer)
-                        el-search-display-buffer-popup-action)
-                       (widen)
-                       (goto-char (point-min))
-                       (let ((el-search-history (ring-copy el-search-history)))
-                         (funcall-interactively #'el-search-pattern pattern))
-                       (el-search--message-no-log "This is the first match in 
%S" (or file buffer)))))
-                  (insert (format "  (%d matches)\n" buffer-matches))
-                  (let* ((get-context
-                          (lambda (match-beg)
-                            (let ((context-beg nil)
-                                  (need-more-context-p
-                                   (lambda (start)
-                                     (let (end)
-                                       (pcase (save-excursion
-                                                (goto-char start)
-                                                (prog1 (read (current-buffer))
-                                                  (setq end (point))))
-                                         ((or (pred atom) `(,(pred atom))) t)
-                                         ((guard (< (- end start) 100))     
t)))))
-                                  (try-go-upwards (lambda (pos) 
(condition-case nil (scan-lists pos -1 1)
-                                                             (scan-error)))))
-                              (with-current-buffer buffer
-                                (when (funcall need-more-context-p match-beg)
-                                  (setq context-beg (funcall try-go-upwards 
match-beg))
-                                  (when (and context-beg (funcall 
need-more-context-p context-beg))
-                                    (setq context-beg (or (funcall 
try-go-upwards context-beg)
-                                                          context-beg))))
-                                (cons (or context-beg match-beg)
-                                      (if context-beg (scan-lists context-beg 
1 0)
-                                        (scan-sexps match-beg 1)))))))
-                         (buffer-matches+contexts
-                          (seq-map (pcase-lambda ((and match `(,_ ,match-beg 
,_)))
-                                     (cons match (funcall get-context 
match-beg)))
-                                   stream-of-buffer-matches)))
-                    (while (not (stream-empty-p buffer-matches+contexts))
-                      (pcase-let ((`((,_ ,match-beg ,_) . (,context-beg . 
,context-end))
-                                   (stream-first buffer-matches+contexts)))
-                        (let ((insertion-point (point)) matches
-                              (end-of-defun (with-current-buffer buffer
-                                              (goto-char match-beg)
-                                              (let ((paren-depth (car 
(syntax-ppss))))
-                                                (if (< 0 paren-depth)
-                                                    (scan-lists match-beg 1 
paren-depth)
-                                                  (el-search--end-of-sexp))))))
-                          (let ((rest buffer-matches+contexts)
-                                (remaining-buffer-matches-+contexts 
buffer-matches+contexts))
-                            (with-current-buffer buffer
-                              (while (pcase (stream-first rest)
-                                       (`(,_ . (,(and cbeg (pred (> 
end-of-defun))) . ,_))
-                                        (prog1 t
-                                          (stream-pop rest)
-                                          (when (< cbeg context-end)
-                                            (setq 
remaining-buffer-matches-+contexts rest)
-                                            (when (< cbeg context-beg)
-                                              (setq context-beg cbeg)
-                                              (setq context-end
-                                                    (or (scan-sexps cbeg 1) 
context-end)))))))))
-                            (setq matches
-                                  (car (el-search--stream-divide
-                                        buffer-matches+contexts
-                                        (lambda (_ rest)
-                                          (not (eq rest 
remaining-buffer-matches-+contexts))))))
-                            (setq buffer-matches+contexts 
remaining-buffer-matches-+contexts))
-                          (cl-flet ((insert-match-and-advance
-                                     (match-beg)
-                                     (let ((insertion-point (point)))
-                                       (insert (propertize
-                                                (with-current-buffer buffer
-                                                  
(buffer-substring-no-properties
-                                                   (goto-char match-beg)
-                                                   (goto-char (scan-sexps 
(point) 1))))
-                                                'match-data `(,buffer 
,match-beg ,file)))
-                                       (let ((ov (make-overlay insertion-point 
(point) nil t)))
-                                         (overlay-put ov 'face 
'el-search-match))
-                                       (with-current-buffer buffer (point)))))
-                            (let ((working-position context-beg))
-                              (while (not (stream-empty-p matches))
-                                (pcase-let ((`((,_ ,match-beg ,_) . ,_) 
(stream-pop matches)))
-                                  (insert-buffer-substring buffer 
working-position match-beg)
-                                  (setq working-position 
(insert-match-and-advance match-beg))
-                                  ;; Drop any matches inside the printed area.
-                                  ;; FIXME: Should we highlight matches inside 
matches specially?
-                                  ;; Should we display the number of matches 
included in a context?
-                                  (while (pcase (stream-first matches)
-                                           (`((,_ ,(pred (> working-position)) 
,_) . ,_) t))
-                                    (stream-pop matches))))
-                              (insert
-                               (with-current-buffer buffer
-                                 (buffer-substring-no-properties (point) 
(scan-sexps context-beg 1))))))
-
-                          (let ((inhibit-message t) (message-log-max nil))
-                            (indent-region insertion-point (point))
-                            (save-excursion
-                              (goto-char insertion-point)
-                              (ignore-errors
-                                ;; This can error...
-                                (if nil ;if need-context
-                                    (hs-hide-level 1)
-                                  (hs-hide-block)))))
-                          (insert "\n")))))))
-
-              (insert
-               (if (zerop overall-matches)
-                   ";;; * No matches"
-                 (concat
-                  (format "\n\n;;; * %d matches in " overall-matches)
-                  (unless (zerop matching-files) (format "%d files" 
matching-files))
-                  (unless (or (zerop matching-files) (zerop matching-buffers)) 
" and ")
-                  (unless (zerop matching-buffers)  (format "%d buffers" 
matching-buffers))
-                  ".")))
-              (goto-char (point-min)))
-          (quit  (insert "\n\n;;; * Aborted"))
-          (error (insert "\n\n;;; * Error: " (error-message-string err)
-                         "\n;;; Please make a bug report to the maintainer.  
Yes, really.
+  (unwind-protect
+      (let ((occur-buffer (or buffer (generate-new-buffer "*El Occur*"))))
+        (setq this-command 'el-search-pattern)
+        (setq-local el-search--temp-buffer-flag nil)
+        (with-selected-window (if buffer (selected-window)
+                                (display-buffer
+                                 occur-buffer
+                                 '((display-buffer-pop-up-window 
display-buffer-use-some-window))))
+          (let ((inhibit-read-only t))
+            (if el-search-occur-search-object
+                (progn
+                  (erase-buffer)
+                  (delete-all-overlays))
+              (el-search-occur-mode)
+              (setq el-search-occur-search-object search))
+            (insert (format ";;; * %s   -*- mode: el-search-occur -*-\n\n;; 
%s\n\n"
+                            (current-time-string)
+                            (el-search--get-search-description-string search)))
+            (condition-case-unless-debug err
+                (let ((stream-of-matches
+                       (el-search--stream-partition
+                        (funcall (el-search-object-get-matches search))
+                        (lambda (this prev) (and (eq (car this) (car prev)) 
(equal (nth 2 this) (nth 2 prev))))))
+                      stream-of-buffer-matches  buffer-matches
+                      (matching-files 0) (matching-buffers 0) (overall-matches 
0))
+                  (while (setq stream-of-buffer-matches (stream-pop 
stream-of-matches))
+                    (setq buffer-matches (seq-length stream-of-buffer-matches))
+                    (cl-incf overall-matches buffer-matches)
+                    (pcase-let ((`(,buffer ,_ ,file) (stream-first 
stream-of-buffer-matches)))
+                      (if file (cl-incf matching-files) (cl-incf 
matching-buffers))
+                      (insert "\n;;; ** ")
+                      (insert-button
+                       (or file (format "%S" buffer))
+                       'action
+                       (let ((pattern (el-search--current-pattern)))
+                         (lambda (_)
+                           (pop-to-buffer
+                            (if file (find-file-noselect file) buffer)
+                            el-search-display-buffer-popup-action)
+                           (widen)
+                           (goto-char (point-min))
+                           (el-search-setup-search-1
+                            pattern
+                            (let ((buf (current-buffer)))
+                              (lambda () (stream (list buf))))
+                            'from-here)
+                           (el-search--next-buffer el-search--current-search)
+                           (setq this-command 'el-search-pattern
+                                 el-search--success t)
+                           (el-search-hl-other-matches 
(el-search--current-matcher))
+                           (add-hook 'post-command-hook 
#'el-search-hl-post-command-fun t t)
+                           (el-search--message-no-log
+                            (substitute-command-keys "Hit 
\\[el-search-pattern] for local search")))))
+                      (insert (format "  (%d match%s)\n"
+                                      buffer-matches
+                                      (if (> buffer-matches 1) "es" "")))
+                      (let* ((get-context
+                              (lambda (match-beg)
+                                (let ((context-beg nil)
+                                      (need-more-context-p
+                                       (lambda (start)
+                                         (let (end)
+                                           (pcase (save-excursion
+                                                    (goto-char start)
+                                                    (prog1 (read 
(current-buffer))
+                                                      (setq end (point))))
+                                             ((or (pred atom) `(,(pred atom))) 
t)
+                                             ((guard (< (- end start) 100))    
 t)))))
+                                      (try-go-upwards (lambda (pos) 
(condition-case nil (scan-lists pos -1 1)
+                                                                 
(scan-error)))))
+                                  (with-current-buffer buffer
+                                    (when (funcall need-more-context-p 
match-beg)
+                                      (setq context-beg (funcall 
try-go-upwards match-beg))
+                                      (when (and context-beg (funcall 
need-more-context-p context-beg))
+                                        (setq context-beg (or (funcall 
try-go-upwards context-beg)
+                                                              context-beg))))
+                                    (cons (or context-beg match-beg)
+                                          (if context-beg (scan-lists 
context-beg 1 0)
+                                            (scan-sexps match-beg 1)))))))
+                             (buffer-matches+contexts
+                              (seq-map (pcase-lambda ((and match `(,_ 
,match-beg ,_)))
+                                         (cons match (funcall get-context 
match-beg)))
+                                       stream-of-buffer-matches)))
+                        (while (not (stream-empty-p buffer-matches+contexts))
+                          (pcase-let ((`((,_ ,match-beg ,_) . (,context-beg . 
,context-end))
+                                       (stream-first buffer-matches+contexts)))
+                            (let ((insertion-point (point)) matches
+                                  (end-of-defun (with-current-buffer buffer
+                                                  (goto-char match-beg)
+                                                  (let ((paren-depth (car 
(syntax-ppss))))
+                                                    (if (< 0 paren-depth)
+                                                        (scan-lists match-beg 
1 paren-depth)
+                                                      
(el-search--end-of-sexp))))))
+                              (let ((rest buffer-matches+contexts)
+                                    (remaining-buffer-matches-+contexts 
buffer-matches+contexts))
+                                (with-current-buffer buffer
+                                  (while (pcase (stream-first rest)
+                                           (`(,_ . (,(and cbeg (pred (> 
end-of-defun))) . ,_))
+                                            (prog1 t
+                                              (stream-pop rest)
+                                              (when (< cbeg context-end)
+                                                (setq 
remaining-buffer-matches-+contexts rest)
+                                                (when (< cbeg context-beg)
+                                                  (setq context-beg cbeg)
+                                                  (setq context-end
+                                                        (or (scan-sexps cbeg 
1) context-end)))))))))
+                                (setq matches
+                                      (car (el-search--stream-divide
+                                            buffer-matches+contexts
+                                            (lambda (_ rest)
+                                              (not (eq rest 
remaining-buffer-matches-+contexts))))))
+                                (setq buffer-matches+contexts 
remaining-buffer-matches-+contexts))
+                              (cl-flet ((insert-match-and-advance
+                                         (match-beg)
+                                         (let ((insertion-point (point)))
+                                           (insert (propertize
+                                                    (with-current-buffer buffer
+                                                      
(buffer-substring-no-properties
+                                                       (goto-char match-beg)
+                                                       (goto-char (scan-sexps 
(point) 1))))
+                                                    'match-data `(,buffer 
,match-beg ,file)))
+                                           (let ((ov (make-overlay 
insertion-point (point) nil t)))
+                                             (overlay-put ov 'face 
'el-search-match))
+                                           (with-current-buffer buffer 
(point)))))
+                                (let ((working-position context-beg))
+                                  (while (not (stream-empty-p matches))
+                                    (pcase-let ((`((,_ ,match-beg ,_) . ,_) 
(stream-pop matches)))
+                                      (insert-buffer-substring buffer 
working-position match-beg)
+                                      (setq working-position 
(insert-match-and-advance match-beg))
+                                      ;; Drop any matches inside the printed 
area.
+                                      ;; FIXME: Should we highlight matches 
inside matches specially?
+                                      ;; Should we display the number of 
matches included in a context?
+                                      (while (pcase (stream-first matches)
+                                               (`((,_ ,(pred (> 
working-position)) ,_) . ,_) t))
+                                        (stream-pop matches))))
+                                  (insert
+                                   (with-current-buffer buffer
+                                     (buffer-substring-no-properties (point) 
(scan-sexps context-beg 1))))))
+
+                              (let ((inhibit-message t) (message-log-max nil))
+                                (indent-region insertion-point (point))
+                                (save-excursion
+                                  (goto-char insertion-point)
+                                  (ignore-errors
+                                    ;; This can error...
+                                    (if nil ;if need-context
+                                        (hs-hide-level 1)
+                                      (hs-hide-block)))))
+                              (insert "\n")))))))
+
+                  (insert
+                   (if (zerop overall-matches)
+                       ";;; * No matches"
+                     (concat
+                      (format "\n\n;;; * %d matches in " overall-matches)
+                      (unless (zerop matching-files) (format "%d files" 
matching-files))
+                      (unless (or (zerop matching-files) (zerop 
matching-buffers)) " and ")
+                      (unless (zerop matching-buffers)  (format "%d buffers" 
matching-buffers))
+                      ".")))
+                  (goto-char (point-min))
+                  (when (bound-and-true-p which-function-mode)
+                    (which-func-ff-hook)))
+              (quit  (insert "\n\n;;; * Aborted"))
+              (error (insert "\n\n;;; * Error: " (error-message-string err)
+                             "\n;;; Please make a bug report to the maintainer.
 ;;; Thanks in advance!")))
-        (el-search--message-no-log "")
-        (set-buffer-modified-p nil))))
-  (el-search-kill-left-over-search-buffers))
+            (el-search--message-no-log "")
+            (set-buffer-modified-p nil))))
+    (el-search-kill-left-over-search-buffers)))
 
 (defun el-search-occur ()
   "Display an occur-like overview of matches of the current search.
@@ -2566,7 +2594,7 @@ reindent."
                                 (setf (alist-get 'description 
(el-search-object-properties search))
                                       "Search created by 
`el-search-query-replace'"))))
   (let ((replace-all nil) (replace-all-and-following nil)
-        nbr-replaced nbr-skipped (done nil) (nbr-replaced-multi 0) 
(nbr-changed-buffers 0)
+        nbr-replaced nbr-skipped (done nil) (nbr-replaced-total 0) 
(nbr-changed-buffers 0)
         (el-search-keep-hl t) (opoint (point))
         (get-replacement (el-search--matcher pattern replacement))
         (skip-matches-in-replacement 'ask)
@@ -2621,7 +2649,7 @@ reindent."
                                (el-search--ensure-sexp-start) ;skip 
potentially newly added whitespace
                                (unless replace-all (el-search-hl-sexp (list 
opoint (point))))
                                (cl-incf nbr-replaced)
-                               (cl-incf nbr-replaced-multi)
+                               (cl-incf nbr-replaced-total)
                                (setq replaced-this t)))
                             (query
                              (lambda ()
@@ -2758,7 +2786,7 @@ Quit.  To resume, use e.g. 
`repeat-complex-command'."))))))))
                        (and el-search--success (not el-search--wrap-flag))))
           (funcall replace-in-current-buffer)
           (unless replace-all-and-following (setq replace-all nil)))
-        (message "Done.  Replaced %d matches in %d buffers." 
nbr-replaced-multi nbr-changed-buffers)))))
+        (message "Done.  Replaced %d matches in %d buffers." 
nbr-replaced-total nbr-changed-buffers)))))
 
 (defun el-search-query-replace--read-args ()
   (barf-if-buffer-read-only)



reply via email to

[Prev in Thread] Current Thread [Next in Thread]