branch: externals/isearch-mb commit 9f11fda34f46afe95192ed280f21245f280c947d Author: Augusto Stoffel <arstof...@gmail.com> Commit: Augusto Stoffel <arstof...@gmail.com>
Several improvements, reorganization --- isearch-mb.el | 237 ++++++++++++++++++++++++++++++++++------------------------ 1 file changed, 140 insertions(+), 97 deletions(-) diff --git a/isearch-mb.el b/isearch-mb.el index fd64795..43b74d9 100644 --- a/isearch-mb.el +++ b/isearch-mb.el @@ -26,30 +26,53 @@ (eval-when-compile (require 'subr-x)) -(put 'next-history-element 'isearch-mb-no-search t) -(put 'previous-history-element 'isearch-mb-no-search t) - (defvar isearch-mb--prompt-overlay nil "Overlay for minibuffer prompt updates.") +(defvar isearch-mb-minibuffer-map + (let ((map (make-sparse-keymap))) + (set-keymap-parent map minibuffer-local-map) + (define-key map (kbd "C-s") 'isearch-repeat-forward) + (define-key map (kbd "<down>") 'isearch-repeat-forward) + (define-key map (kbd "C-r") 'isearch-repeat-backward) + (define-key map (kbd "<up>") 'isearch-repeat-backward) + (define-key map (kbd "M-%") 'isearch-query-replace) + (define-key map (kbd "C-M-%") 'isearch-query-replace-regexp) + (define-key map (kbd "M-<") 'isearch-beginning-of-buffer) + (define-key map (kbd "M->") 'isearch-end-of-buffer) + (define-key map (kbd "M-s '") 'isearch-toggle-char-fold) + (define-key map (kbd "M-s SPC") 'isearch-toggle-lax-whitespace) + (define-key map (kbd "M-s _") 'isearch-toggle-symbol) + (define-key map (kbd "M-s c") 'isearch-toggle-case-fold) + (define-key map (kbd "M-s h r") 'isearch-highlight-regexp) + (define-key map (kbd "M-s h l") 'isearch-highlight-lines-matching-regexp) + (define-key map (kbd "M-s i") 'isearch-toggle-invisible) + (define-key map (kbd "M-s o") 'isearch-occur) + (define-key map (kbd "M-s r") 'isearch-toggle-regexp) + (define-key map (kbd "M-s w") 'isearch-toggle-word) + map) + "Minibuffer keymap used by Isearch-Mb.") + (defun isearch-mb--post-command-hook () - (let ((inhibit-redisplay t) - (new-string (minibuffer-contents))) + "Hook to run from the minibuffer to update the Isearch state." + (let ((text (minibuffer-contents))) ;; We never update isearch-message. If it's not empty, then ;; Isearch itself changed the search string, and we update it. (unless (string-empty-p isearch-message) - (setq isearch-message "" new-string isearch-string) + (setq isearch-message "" + text isearch-string) (delete-minibuffer-contents) (insert isearch-string)) - (unless (string= new-string isearch-string) - (with-minibuffer-selected-window - (setq isearch-string new-string) - (isearch-update-from-string-properties new-string) - (if (get this-command 'isearch-mb-no-search) - (isearch-update) - (goto-char isearch-barrier) - (setq isearch-adjusted t isearch-yank-flag t) - (isearch-search-and-update))))) + (unless (string-equal text isearch-string) + (let ((inhibit-redisplay t)) + (with-minibuffer-selected-window + (setq isearch-string (substring-no-properties text)) + (isearch-update-from-string-properties text) + (if (get this-command 'isearch-mb--no-search) + (isearch-update) + (goto-char isearch-barrier) + (setq isearch-adjusted t isearch-yank-flag t) + (isearch-search-and-update)))))) (set-text-properties (minibuffer-prompt-end) (point-max) nil) (when-let ((fail-pos (isearch-fail-pos))) (add-text-properties (+ (minibuffer-prompt-end) fail-pos) @@ -58,94 +81,115 @@ (when isearch-error (isearch-mb--message isearch-error))) -(defun isearch-mb--minibuffer-setup () - (setq isearch-mb--prompt-overlay (make-overlay (point-min) (point-min) - (current-buffer) t t)) - (isearch-mb--prompt) - (add-hook 'post-command-hook 'isearch-mb--post-command-hook nil 'local)) - -(defun isearch-mb--message (message &rest _) - (message (propertize (concat " [" message "]") - 'face 'minibuffer-prompt))) +(defun isearch-mb--message (message) + "Display a momentary MESSAGE." + (when isearch-mb-mode + (message (propertize (concat " [" message "]") + 'face 'minibuffer-prompt)))) (defun isearch-mb--prompt (&rest _) - (when isearch-mb--prompt-overlay - (overlay-put isearch-mb--prompt-overlay - 'before-string - (concat - (isearch-lazy-count-format) - (capitalize - (isearch--describe-regexp-mode isearch-regexp-function)))))) - -(defvar isearch-mb-minibuffer-map - (let ((map (make-sparse-keymap))) - (set-keymap-parent map minibuffer-local-map) - (define-key map (kbd "C-s") 'isearch-repeat-forward) - (define-key map (kbd "C-r") 'isearch-repeat-backward) - (define-key map (kbd "<down>") 'isearch-repeat-forward) - (define-key map (kbd "<up>") 'isearch-repeat-backward) - (define-key map (kbd "M-s r") 'isearch-toggle-regexp) - (define-key map (kbd "M-s c") 'isearch-toggle-case-fold) - (define-key map (kbd "M-s w") 'isearch-toggle-word) - (define-key map (kbd "M-<") 'isearch-beginning-of-buffer) - (define-key map (kbd "M->") 'isearch-end-of-buffer) - map)) - -(defun isearch-mb--command-advice (fn &rest args) - (if (eq (current-buffer) isearch--current-buffer) - (apply fn args) - (let ((inhibit-redisplay t)) - (with-minibuffer-selected-window - (apply fn args))))) - -(defun isearch-mb--activate (&rest _) - "Activate `isearch-mode' read from the minibuffer." + "Update the minibuffer prompt according to search status." + (prog1 isearch-mb-mode + (when isearch-mb--prompt-overlay + (overlay-put isearch-mb--prompt-overlay + 'before-string + (concat + (when isearch-lazy-count + (format "%-6s" (isearch-lazy-count-format))) + (capitalize + (isearch--describe-regexp-mode + isearch-regexp-function))))))) + +(defun isearch-mb--with-buffer (fn &rest args) + "Call FN with ARGS in the search buffer. +Intended as an advice for Isearch commands." + (if (and (minibufferp) + (not (eq (current-buffer) isearch--current-buffer))) + (let ((enable-recursive-minibuffers t) + (inhibit-redisplay t)) + (with-minibuffer-selected-window + (apply fn args) + (unless isearch-mode + (throw 'isearch-mb--after-exit '(ignore))))) + (apply fn args))) + +(defun isearch-mb--after-exit (fn &rest args) + "Call FN with ARGS, after quitting Isearch-Mb. +Intended as an advice for commands that quit Isearch." + (if (and (minibufferp) + (not (eq (current-buffer) isearch--current-buffer))) + (throw 'isearch-mb--after-exit (cons fn args)) + (apply fn args))) + +(defun isearch-mb--session () + "Read search string from the minibuffer." + (when isearch-mode + (condition-case nil + (apply + (catch 'isearch-mb--after-exit + (let (;; Hack to render `isearch-pre-command-hook' without effect. + (isearch--saved-overriding-local-map t) + ;; We need to set `inhibit-redisplay' at certain points to + ;; avoid flicker. As a side effect, window-start/end in + ;; `isearch-lazy-highlight-update' will have incorrect values, + ;; so we need to lazy-highlight the whole buffer. + (lazy-highlight-buffer (not (null isearch-lazy-highlight)))) + (minibuffer-with-setup-hook + (lambda () + (add-hook 'post-command-hook 'isearch-mb--post-command-hook nil 'local) + (setq isearch-mb--prompt-overlay (make-overlay (point-min) (point-min) + (current-buffer) t t)) + (isearch-mb--prompt)) + (read-from-minibuffer + "I-search: " + isearch-string + isearch-mb-minibuffer-map + nil + (if isearch-regexp 'regexp-search-ring 'search-ring) + (when-let (thing (thing-at-point 'symbol)) + (if isearch-regexp (regexp-quote thing) thing)) + t)) + (if isearch-mode '(isearch-done) '(ignore))))) + (quit (if isearch-mode (isearch-cancel) (signal 'quit nil)))))) + +(defun isearch-mb--setup () + "Arrange to start Isearch-Mb after this command, if applicable." (when isearch-mb-mode (setq overriding-terminal-local-map nil) - (advice-add 'isearch-message :override 'isearch-mb--prompt) - (advice-add 'isearch--momentary-message :override 'isearch-mb--message) - (let ((history-add-new-input nil) - ;; We need to set `inhibit-redisplay' at certain points to - ;; avoid flicker. As a side effect, window-start/end in - ;; `isearch-lazy-highlight-update' will have incorrect values, - ;; so we need to lazy-highlight the whole buffer. - (lazy-highlight-buffer (not (null isearch-lazy-highlight)))) - (unwind-protect - (progn - (minibuffer-with-setup-hook 'isearch-mb--minibuffer-setup - (read-from-minibuffer - "I-search: " - isearch-string - isearch-mb-minibuffer-map - nil - (if isearch-regexp 'regexp-search-ring 'search-ring) - (when-let (thing (thing-at-point 'symbol)) - (if isearch-regexp (regexp-quote thing) thing)) - t)) - (isearch-done)) - (when isearch-mode (ignore-error quit (isearch-cancel))) - (advice-remove 'isearch-message 'isearch-mb--prompt) - (advice-remove 'isearch--momentary-message 'isearch-mb--message))))) - -(advice-add 'isearch-forward :after 'isearch-mb--activate) -(advice-add 'isearch-backward :after 'isearch-mb--activate) -(advice-add 'isearch-forward-regexp :after 'isearch-mb--activate) -(advice-add 'isearch-backward-regexp :after 'isearch-mb--activate) -(advice-add 'isearch-forward-word :after 'isearch-mb--activate) -;(advice-add 'isearch-forward-symbol :after 'isearch-mb--activate) -(advice-add 'isearch-forward-symbol-at-point :after 'isearch-mb--activate) - -(advice-add 'isearch-toggle-regexp :around 'isearch-mb--command-advice) -(advice-add 'isearch-toggle-case-fold :around 'isearch-mb--command-advice) -(advice-add 'isearch-toggle-word :around 'isearch-mb--command-advice) -(advice-add 'isearch-repeat-forward :around 'isearch-mb--command-advice) -(advice-add 'isearch-repeat-backward :around 'isearch-mb--command-advice) -(advice-add 'isearch-beginning-of-buffer :around 'isearch-mb--command-advice) -(advice-add 'isearch-end-of-buffer :around 'isearch-mb--command-advice) + (run-with-idle-timer 0 nil 'isearch-mb--session))) + +(add-hook 'isearch-mode-hook 'isearch-mb--setup) + +(put 'next-history-element 'isearch-mb--no-search t) +(put 'previous-history-element 'isearch-mb--no-search t) + +(advice-add 'isearch-message :before-until 'isearch-mb--prompt) +(advice-add 'isearch--momentary-message :before-until 'isearch-mb--message) + +(advice-add 'isearch-beginning-of-buffer :around 'isearch-mb--with-buffer) +(advice-add 'isearch-end-of-buffer :around 'isearch-mb--with-buffer) +(advice-add 'isearch-occur :around 'isearch-mb--with-buffer) +(advice-add 'isearch-repeat-backward :around 'isearch-mb--with-buffer) +(advice-add 'isearch-repeat-forward :around 'isearch-mb--with-buffer) +(advice-add 'isearch-toggle-case-fold :around 'isearch-mb--with-buffer) +(advice-add 'isearch-toggle-char-fold :around 'isearch-mb--with-buffer) +(advice-add 'isearch-toggle-invisible :around 'isearch-mb--with-buffer) +(advice-add 'isearch-toggle-lax-whitespace :around 'isearch-mb--with-buffer) +(advice-add 'isearch-toggle-regexp :around 'isearch-mb--with-buffer) +(advice-add 'isearch-toggle-symbol :around 'isearch-mb--with-buffer) +(advice-add 'isearch-toggle-word :around 'isearch-mb--with-buffer) + +(advice-add 'isearch-query-replace :around 'isearch-mb--after-exit) +(advice-add 'isearch-query-replace-regexp :around 'isearch-mb--after-exit) +(advice-add 'isearch-highlight-regexp :around 'isearch-mb--after-exit) +(advice-add 'isearch-highlight-lines-matching-regexp :around 'isearch-mb--after-exit) ;;;###autoload (define-minor-mode isearch-mb-mode - "Control Isearch from minibuffer.") + "Control Isearch from the minibuffer. + +During an Isearch-Mb session, the following keys are available: +\\{isearch-mb-minibuffer-map}") ;;;###autoload (define-globalized-minor-mode isearch-mb-global-mode @@ -153,5 +197,4 @@ (lambda () (unless (minibufferp) (isearch-mb-mode)))) (provide 'isearch-mb) - ;;; isearch-mb.el ends here