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

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

[elpa] master 45c83e9: Improve quit/error handling in el-search-query-re


From: Michael Heerdegen
Subject: [elpa] master 45c83e9: Improve quit/error handling in el-search-query-replace
Date: Sat, 17 Feb 2018 13:06:45 -0500 (EST)

branch: master
commit 45c83e9615a4e5c7faa46568b78e588589d9ee7c
Author: Michael Heerdegen <address@hidden>
Commit: Michael Heerdegen <address@hidden>

    Improve quit/error handling in el-search-query-replace
    
    * packages/el-search/el-search.el
    (el-search--search-and-replace-pattern): Use catch and throw to
    implement user quit.  Allow hitting `q' to quit also from the "There
    are matches in this replacement" prompt.  Optimize control flow in
    case of an error.
---
 packages/el-search/el-search.el | 441 ++++++++++++++++++++--------------------
 1 file changed, 222 insertions(+), 219 deletions(-)

diff --git a/packages/el-search/el-search.el b/packages/el-search/el-search.el
index 3b60774..483b899 100644
--- a/packages/el-search/el-search.el
+++ b/packages/el-search/el-search.el
@@ -3172,230 +3172,233 @@ Thanks!"))))
                                       t)
                                 (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-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)
-        (matcher (el-search--matcher pattern))
-        (heuristic-matcher (el-search--current-heuristic-matcher))
-        (save-all-answered nil)
-        (user-quit nil))
-    (let ((replace-in-current-buffer
-           (lambda ()
-             (setq nbr-replaced 0)
-             (setq nbr-skipped  0)
-             (condition-case nil
-                 (progn
-
-                   (unless replace-all
-                     (el-search-hl-other-matches matcher)
-                     (add-hook 'window-scroll-functions 
#'el-search--after-scroll t t)
-                     (let ((head (el-search-object-head 
el-search--current-search)))
-                       (el-search--message-no-log "%s..."
-                                                  (or (el-search-head-file 
head)
-                                                      (el-search-head-buffer 
head)))
-                       (sit-for 1.)))
-
-                   (while (and (not done)
-                               (el-search--search-pattern-1 matcher t nil 
heuristic-matcher))
-                     (setq opoint (point))
-                     (setf (el-search-head-position
-                            (el-search-object-head el-search--current-search))
-                           (copy-marker (point)))
-                     (setf (el-search-object-last-match 
el-search--current-search)
-                           (copy-marker (point)))
+  (catch 'done
+    (let ((replace-all nil) (replace-all-and-following nil)
+          nbr-replaced nbr-skipped (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)
+          (matcher (el-search--matcher pattern))
+          (heuristic-matcher (el-search--current-heuristic-matcher))
+          (save-all-answered nil)
+          (should-quit nil))
+      (let ((replace-in-current-buffer
+             (lambda ()
+               (setq nbr-replaced 0)
+               (setq nbr-skipped  0)
+               (condition-case err
+                   (progn
+
                      (unless replace-all
-                       (el-search-hl-sexp))
-                     (let* ((region (list (point) (el-search--end-of-sexp)))
-                            (original-text (apply 
#'buffer-substring-no-properties region))
-                            (expr      (el-search-read original-text))
-                            (replaced-this nil)
-                            (new-expr  (funcall get-replacement expr))
-                            (get-replacement-string
-                             (lambda () (el-search--format-replacement
-                                    new-expr original-text to-input-string 
splice)))
-                            (to-insert (funcall get-replacement-string))
-                            (replacement-contains-another-match
-                             (with-temp-buffer
-                               (emacs-lisp-mode)
-                               (insert to-insert)
-                               (goto-char 1)
-                               (el-search--skip-expression new-expr)
-                               (condition-case nil
-                                   (progn (el-search--ensure-sexp-start)
-                                          (el-search--search-pattern-1 matcher 
'noerror))
-                                 (end-of-buffer nil))))
-                            (do-replace
-                             (lambda ()
-                               (save-excursion
-                                 (save-restriction
-                                   (widen)
-                                   (el-search--replace-hunk (list (point) 
(el-search--end-of-sexp)) to-insert)))
-                               (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-total)
-                               (setq replaced-this t)))
-                            (query
-                             (lambda ()
-                               (car
-                                (read-multiple-choice
-                                 (let ((nbr-done  (+ nbr-replaced nbr-skipped))
-                                       (nbr-to-do (el-search-count-matches 
pattern)))
-                                   (format "[%d/%d]"
-                                           (if replaced-this nbr-done (1+ 
nbr-done))
-                                           (+ nbr-done nbr-to-do)))
-                                 (delq nil
-                                       (list
-                                        (and (not replaced-this)
-                                             '(?y "y" "Replace this match and 
move to the next"))
-                                        (list ?n
-                                              (if replaced-this "next" "n")
-                                              "Go to the next match")
-                                        (and (not replaced-this)
-                                             '(?r "r" "Replace this match but 
don't move"))
-                                        '(?! "all" "Replace all remaining 
matches in this buffer")
-                                        (and multiple
-                                             '(?A "All" "Replace all remaining 
matches in all buffers"))
-                                        '(?b "skip buf"
-                                             "Skip this buffer and any 
remaining matches in it")
-                                        (and buffer-file-name
-                                             '(?d "skip dir"
-                                                  "Skip a parent directory of 
current file"))
-                                        (and (not replaced-this)
-                                             (list ?s (concat (if splice 
"disable" "enable")
-                                                              " splice")
-                                                   (substitute-command-keys "\
+                       (el-search-hl-other-matches matcher)
+                       (add-hook 'window-scroll-functions 
#'el-search--after-scroll t t)
+                       (let ((head (el-search-object-head 
el-search--current-search)))
+                         (el-search--message-no-log "%s..."
+                                                    (or (el-search-head-file 
head)
+                                                        (el-search-head-buffer 
head)))
+                         (sit-for 1.)))
+
+                     (while (el-search--search-pattern-1 matcher t nil 
heuristic-matcher)
+                       (setq opoint (point))
+                       (setf (el-search-head-position
+                              (el-search-object-head 
el-search--current-search))
+                             (copy-marker (point)))
+                       (setf (el-search-object-last-match 
el-search--current-search)
+                             (copy-marker (point)))
+                       (unless replace-all
+                         (el-search-hl-sexp))
+                       (let* ((region (list (point) (el-search--end-of-sexp)))
+                              (original-text (apply 
#'buffer-substring-no-properties region))
+                              (expr      (el-search-read original-text))
+                              (replaced-this nil)
+                              (new-expr  (funcall get-replacement expr))
+                              (get-replacement-string
+                               (lambda () (el-search--format-replacement
+                                      new-expr original-text to-input-string 
splice)))
+                              (to-insert (funcall get-replacement-string))
+                              (replacement-contains-another-match
+                               (with-temp-buffer
+                                 (emacs-lisp-mode)
+                                 (insert to-insert)
+                                 (goto-char 1)
+                                 (el-search--skip-expression new-expr)
+                                 (condition-case nil
+                                     (progn (el-search--ensure-sexp-start)
+                                            (el-search--search-pattern-1 
matcher 'noerror))
+                                   (end-of-buffer nil))))
+                              (do-replace
+                               (lambda ()
+                                 (save-excursion
+                                   (save-restriction
+                                     (widen)
+                                     (el-search--replace-hunk (list (point) 
(el-search--end-of-sexp)) to-insert)))
+                                 (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-total)
+                                 (setq replaced-this t)))
+                              (query
+                               (lambda ()
+                                 (car
+                                  (read-multiple-choice
+                                   (let ((nbr-done  (+ nbr-replaced 
nbr-skipped))
+                                         (nbr-to-do (el-search-count-matches 
pattern)))
+                                     (format "[%d/%d]"
+                                             (if replaced-this nbr-done (1+ 
nbr-done))
+                                             (+ nbr-done nbr-to-do)))
+                                   (delq nil
+                                         (list
+                                          (and (not replaced-this)
+                                               '(?y "y" "Replace this match 
and move to the next"))
+                                          (list ?n
+                                                (if replaced-this "next" "n")
+                                                "Go to the next match")
+                                          (and (not replaced-this)
+                                               '(?r "r" "Replace this match 
but don't move"))
+                                          '(?! "all" "Replace all remaining 
matches in this buffer")
+                                          (and multiple
+                                               '(?A "All" "Replace all 
remaining matches in all buffers"))
+                                          '(?b "skip buf"
+                                               "Skip this buffer and any 
remaining matches in it")
+                                          (and buffer-file-name
+                                               '(?d "skip dir"
+                                                    "Skip a parent directory 
of current file"))
+                                          (and (not replaced-this)
+                                               (list ?s (concat (if splice 
"disable" "enable")
+                                                                " splice")
+                                                     (substitute-command-keys 
"\
 Toggle splicing mode (\\[describe-function] el-search-query-replace for 
details).")))
-                                        '(?o "show" "Show replacement in a 
buffer")
-                                        '(?q "quit"))))))))
-                       (if replace-all
-                           (funcall do-replace)
-                         (while (not (pcase (funcall query)
-                                       (?r (funcall do-replace)
-                                           nil)
-                                       (?y (funcall do-replace)
-                                           t)
-                                       (?n
-                                        (unless replaced-this (cl-incf 
nbr-skipped))
-                                        t)
-                                       (?! (unless replaced-this
-                                             (funcall do-replace))
-                                           (setq replace-all t)
-                                           t)
-                                       (?A (unless replaced-this
-                                             (funcall do-replace))
-                                           (setq replace-all t)
-                                           (setq replace-all-and-following t)
-                                           t)
-                                       (?b (goto-char (point-max))
-                                           (message "Skipping this buffer")
-                                           (sit-for 1)
-                                           ;; FIXME: add #skipped matches to 
nbr-skipped?
-                                           t)
-                                       (?d (call-interactively 
#'el-search-skip-directory)
-                                           t)
-                                       (?s (cl-callf not splice)
-                                           (setq to-insert (funcall 
get-replacement-string))
-                                           nil)
-                                       (?o
-                                        ;; FIXME: Should we allow to edit the 
replacement?
-                                        (let* ((buffer (get-buffer-create
-                                                        
(generate-new-buffer-name "*Replacement*")))
-                                               (window (display-buffer 
buffer)))
-                                          (with-selected-window window
-                                            (emacs-lisp-mode)
-                                            (save-excursion
-                                              (insert
-                                               "\
+                                          '(?o "show" "Show replacement in a 
buffer")
+                                          '(?q "quit"))))))))
+                         (if replace-all
+                             (funcall do-replace)
+                           (while (not (pcase (funcall query)
+                                         (?r (funcall do-replace)
+                                             nil)
+                                         (?y (funcall do-replace)
+                                             t)
+                                         (?n
+                                          (unless replaced-this (cl-incf 
nbr-skipped))
+                                          t)
+                                         (?! (unless replaced-this
+                                               (funcall do-replace))
+                                             (setq replace-all t)
+                                             t)
+                                         (?A (unless replaced-this
+                                               (funcall do-replace))
+                                             (setq replace-all t)
+                                             (setq replace-all-and-following t)
+                                             t)
+                                         (?b (goto-char (point-max))
+                                             (message "Skipping this buffer")
+                                             (sit-for 1)
+                                             ;; FIXME: add #skipped matches to 
nbr-skipped?
+                                             t)
+                                         (?d (call-interactively 
#'el-search-skip-directory)
+                                             t)
+                                         (?s (cl-callf not splice)
+                                             (setq to-insert (funcall 
get-replacement-string))
+                                             nil)
+                                         (?o
+                                          ;; FIXME: Should we allow to edit 
the replacement?
+                                          (let* ((buffer (get-buffer-create
+                                                          
(generate-new-buffer-name "*Replacement*")))
+                                                 (window (display-buffer 
buffer)))
+                                            (with-selected-window window
+                                              (emacs-lisp-mode)
+                                              (save-excursion
+                                                (insert
+                                                 "\
 ;; This buffer shows the replacement for the current match.
 ;; Please hit any key to proceed.\n\n"
-                                               (funcall 
get-replacement-string)))
-                                            (read-char " "))
-                                          (delete-window window)
-                                          (kill-buffer buffer)
-                                          (el-search--after-scroll 
(selected-window) (window-start))
-                                          nil))
-                                       ((or ?q ?\C-g) (signal 'quit t))))))
-                       (when replacement-contains-another-match
-                         (el-search-hl-other-matches matcher))
-                       (unless (or done (eobp))
-                         (cond
-                          ((not (and replaced-this
-                                     replacement-contains-another-match
-                                     skip-matches-in-replacement))
-                           (el-search--skip-expression nil t))
-                          ((eq skip-matches-in-replacement 'ask)
-                           (pcase (car (read-multiple-choice
-                                        (propertize
-                                         "There are matches in this 
replacement - skip them? "
-                                         'face 
'el-search-highlight-in-prompt-face)
-                                        '((?y "yes")
-                                          (?n "no")
-                                          (?Y "always Yes")
-                                          (?N "always No"))))
-                             ((and (or ?y ?Y) answer)
-                              (when (= answer ?Y) (setq 
skip-matches-in-replacement t))
-                              (forward-sexp))
-                             (answer
-                              (when (= answer ?N) (setq 
skip-matches-in-replacement nil))
-                              (el-search--skip-expression nil t)
-                              (when replace-all
-                                (setq replace-all nil) ;FIXME: can this be 
annoying?  Problem: we need
-                                                       ;to catch possibly 
infinite loops
-                                (message "Falling back to interactive mode")
-                                (sit-for 2.)))))
-                          (t (forward-sexp)))))))
-               (quit (setq user-quit t)
-                     (setq done t)))
-             (el-search-hl-remove)
-             (unless user-quit
+                                                 (funcall 
get-replacement-string)))
+                                              (read-char " "))
+                                            (delete-window window)
+                                            (kill-buffer buffer)
+                                            (el-search--after-scroll 
(selected-window) (window-start))
+                                            nil))
+                                         ((or ?q ?\C-g) (signal 'quit t))))))
+                         (when replacement-contains-another-match
+                           (el-search-hl-other-matches matcher))
+                         (unless (eobp)
+                           (cond
+                            ((not (and replaced-this
+                                       replacement-contains-another-match
+                                       skip-matches-in-replacement))
+                             (el-search--skip-expression nil t))
+                            ((eq skip-matches-in-replacement 'ask)
+                             (pcase (car (read-multiple-choice
+                                          (propertize
+                                           "There are matches in this 
replacement - skip them? "
+                                           'face 
'el-search-highlight-in-prompt-face)
+                                          '((?y "yes")
+                                            (?n "no")
+                                            (?Y "always Yes")
+                                            (?N "always No")
+                                            (?q "quit"))))
+                               ((and (or ?y ?Y) answer)
+                                (when (= answer ?Y) (setq 
skip-matches-in-replacement t))
+                                (forward-sexp))
+                               (?q (signal 'quit t))
+                               (answer
+                                (when (= answer ?N) (setq 
skip-matches-in-replacement nil))
+                                (el-search--skip-expression nil t)
+                                (when replace-all
+                                  (setq replace-all nil) ;FIXME: can this be 
annoying?  Problem: we need
+                                                         ;to catch possibly 
infinite loops
+                                  (message "Falling back to interactive mode")
+                                  (sit-for 2.)))))
+                            (t (forward-sexp)))))))
+                 (quit  (setq should-quit t))
+                 ((error debug) (setq should-quit (lambda () (error "%s" 
(error-message-string err))))))
+               (el-search-hl-remove)
+               (when should-quit
+                 (remove-hook 'post-command-hook 
'el-search-hl-post-command-fun t)
+                 (if (functionp should-quit) (funcall should-quit) (throw 
'done t)))
                (setf (el-search-head-position (el-search-object-head 
el-search--current-search))
-                     (point-max)))
-             (goto-char opoint)
-             (if (> nbr-replaced 0)
-                 (progn
-                   (cl-incf nbr-changed-buffers)
-                   (when (pcase el-search-auto-save-buffers
-                           ((or 'nil
-                                (guard (not buffer-file-name)))
-                            nil)
-                           ((and 'ask-multi
-                                 (guard (alist-get 'is-single-buffer
-                                                   (el-search-object-properties
-                                                    
el-search--current-search))))
-                            nil)
-                           ((or 'ask 'ask-multi)
-                            (if save-all-answered
-                                (cdr save-all-answered)
-                              (pcase (car (read-multiple-choice
-                                           (format
-                                            "Replaced %d matches%s - save this 
buffer? "
-                                            nbr-replaced
-                                            (if (zerop nbr-skipped)  ""
-                                              (format "   (%d skipped)" 
nbr-skipped)))
-                                           '((?y "yes")
-                                             (?n "no")
-                                             (?Y "Yes to all")
-                                             (?N "No to all"))))
-                                (?y t)
-                                (?n nil)
-                                (?Y (cdr (setq save-all-answered (cons t t))))
-                                (?N (cdr (setq save-all-answered (cons t 
nil)))))))
-                           (_ t))
-                     (save-buffer)))
-               (unless multiple
-                 (message "Replaced %d matches%s"
-                          nbr-replaced
-                          (if (zerop nbr-skipped)  ""
-                            (format "   (%d skipped)" nbr-skipped))))))))
-      (while (and (not done)
-                  (progn (el-search-continue-search)
-                         (and el-search--success (not el-search--wrap-flag))))
-        (funcall replace-in-current-buffer)
-        (unless replace-all-and-following (setq replace-all nil)))
-      (message "Replaced %d matches in %d buffers" nbr-replaced-total 
nbr-changed-buffers))))
+                     (point-max))
+               (goto-char opoint)
+               (if (> nbr-replaced 0)
+                   (progn
+                     (cl-incf nbr-changed-buffers)
+                     (when (pcase el-search-auto-save-buffers
+                             ((or 'nil
+                                  (guard (not buffer-file-name)))
+                              nil)
+                             ((and 'ask-multi
+                                   (guard (alist-get 'is-single-buffer
+                                                     
(el-search-object-properties
+                                                      
el-search--current-search))))
+                              nil)
+                             ((or 'ask 'ask-multi)
+                              (if save-all-answered
+                                  (cdr save-all-answered)
+                                (pcase (car (read-multiple-choice
+                                             (format
+                                              "Replaced %d matches%s - save 
this buffer? "
+                                              nbr-replaced
+                                              (if (zerop nbr-skipped)  ""
+                                                (format "   (%d skipped)" 
nbr-skipped)))
+                                             '((?y "yes")
+                                               (?n "no")
+                                               (?Y "Yes to all")
+                                               (?N "No to all"))))
+                                  (?y t)
+                                  (?n nil)
+                                  (?Y (cdr (setq save-all-answered (cons t 
t))))
+                                  (?N (cdr (setq save-all-answered (cons t 
nil)))))))
+                             (_ t))
+                       (save-buffer)))
+                 (unless multiple
+                   (message "Replaced %d matches%s"
+                            nbr-replaced
+                            (if (zerop nbr-skipped)  ""
+                              (format "   (%d skipped)" nbr-skipped))))))))
+        (while (progn (el-search-continue-search)
+                      (and el-search--success (not el-search--wrap-flag)))
+          (funcall replace-in-current-buffer)
+          (unless replace-all-and-following (setq replace-all nil)))
+        (message "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]