emacs-devel
[Top][All Lists]
Advanced

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

Search minibuffer history


From: Juri Linkov
Subject: Search minibuffer history
Date: Mon, 09 Jul 2007 23:59:33 +0300
User-agent: Gnus/5.11 (Gnus v5.11) Emacs/22.1.50 (gnu/linux)

Two years ago I implemented a feature that allows isearch to search
elements in the minibuffer history.  It works exactly as the incremental
search implemented in the GNU readline library used in shells like bash etc.
After typing C-r it displays the isearch prompt to show that isearch is
active and to indicate the state of the search.  After reaching the first
history element (when searching in the backward direction) the search wraps
to the last history element and vice versa.  When the search fails it
displays the error message and the failed search string.  I tried many
different implementations and now I am completely satisfied by the
described above.

This feature was warmly welcomed but its installation was postponed
due to the feature freeze.  Now I submit it again:

Index: lisp/simple.el
===================================================================
RCS file: /sources/emacs/emacs/lisp/simple.el,v
retrieving revision 1.865
diff -c -r1.865 simple.el
*** lisp/simple.el      7 Jul 2007 11:17:51 -0000       1.865
--- lisp/simple.el      9 Jul 2007 20:57:33 -0000
***************
*** 1300,1311 ****
  
  (defvar minibuffer-temporary-goal-position nil)
  
! (defun next-history-element (n)
    "Puts next element of the minibuffer history in the minibuffer.
! With argument N, it uses the Nth following element."
    (interactive "p")
!   (or (zerop n)
!       (let ((narg (- minibuffer-history-position n))
            (minimum (if minibuffer-default -1 0))
            elt minibuffer-returned-to-present)
        (if (and (zerop minibuffer-history-position)
--- 1300,1313 ----
  
  (defvar minibuffer-temporary-goal-position nil)
  
! (defun next-history-element (n &optional narg)
    "Puts next element of the minibuffer history in the minibuffer.
! With argument N, it uses the Nth following element.
! The optional argument NARG overrides the argument N and specifies the
! absolute history position instead of relative position specified by N."
    (interactive "p")
!   (or (and (zerop n) (not narg))
!       (let ((narg (or narg (- minibuffer-history-position n)))
            (minimum (if minibuffer-default -1 0))
            elt minibuffer-returned-to-present)
        (if (and (zerop minibuffer-history-position)
***************
*** 1344,1354 ****
           elt))
        (goto-char (or minibuffer-temporary-goal-position (point-max))))))
  
! (defun previous-history-element (n)
    "Puts previous element of the minibuffer history in the minibuffer.
! With argument N, it uses the Nth previous element."
    (interactive "p")
!   (next-history-element (- n)))
  
  (defun next-complete-history-element (n)
    "Get next history element which completes the minibuffer before the point.
--- 1346,1358 ----
           elt))
        (goto-char (or minibuffer-temporary-goal-position (point-max))))))
  
! (defun previous-history-element (n &optional narg)
    "Puts previous element of the minibuffer history in the minibuffer.
! With argument N, it uses the Nth previous element.
! The optional argument NARG overrides the argument N and specifies the
! absolute history position instead of relative position specified by N."
    (interactive "p")
!   (next-history-element (- n) narg))
  
  (defun next-complete-history-element (n)
    "Get next history element which completes the minibuffer before the point.
***************
*** 1380,1385 ****
--- 1384,1471 ----
    ;; Return the width of everything before the field at the end of
    ;; the buffer; this should be 0 for normal buffers.
    (1- (minibuffer-prompt-end)))
+ 
+ ;; isearch the minibuffer history
+ (add-hook 'minibuffer-setup-hook 'minibuffer-history-isearch-setup)
+ 
+ (defvar minibuffer-history-isearch-prefix-overlay)
+ (make-variable-buffer-local 'minibuffer-history-isearch-prefix-overlay)
+ 
+ (defun minibuffer-history-isearch-setup ()
+   (add-hook 'isearch-mode-hook 'minibuffer-history-isearch-start nil t)
+   (add-hook 'isearch-mode-end-hook 'minibuffer-history-isearch-end nil t)
+   (set (make-local-variable 'isearch-search-fun-function)
+        'minibuffer-history-isearch-search)
+   (set (make-local-variable 'isearch-wrap-function)
+        'minibuffer-history-isearch-wrap)
+   (set (make-local-variable 'isearch-push-state-function)
+        'minibuffer-history-isearch-push-state))
+ 
+ (defun minibuffer-history-isearch-start ()
+   (setq minibuffer-history-isearch-prefix-overlay
+       (make-overlay (point-min) (minibuffer-prompt-end)))
+   (overlay-put minibuffer-history-isearch-prefix-overlay
+              'display (isearch-message-prefix))
+   (overlay-put minibuffer-history-isearch-prefix-overlay 'evaporate t))
+ 
+ (defun minibuffer-history-isearch-end ()
+   (delete-overlay minibuffer-history-isearch-prefix-overlay))
+ 
+ (defun minibuffer-history-isearch-search ()
+   (cond
+    (isearch-word
+     (if isearch-forward 'word-search-forward 'word-search-backward))
+    (t
+     (lambda (string bound noerror)
+       (let ((search-fun
+              (cond
+               (isearch-regexp
+                (if isearch-forward 're-search-forward 're-search-backward))
+               (t
+                (if isearch-forward 'search-forward 'search-backward))))
+           found)
+       ;; Avoid lazy-highlighting prompt
+       (if (and bound isearch-forward (< (point) (minibuffer-prompt-end)))
+           (goto-char (minibuffer-prompt-end)))
+         (or (funcall search-fun string
+                    (if isearch-forward bound (minibuffer-prompt-end))
+                      noerror)
+           ;; Search history unless lazy-highlighting
+             (unless bound
+               (condition-case nil
+                   (progn
+                     (while (not found)
+                       (cond (isearch-forward
+                            (next-history-element 1)
+                            (goto-char (minibuffer-prompt-end)))
+                           (t
+                            (previous-history-element 1)
+                            (goto-char (point-max))))
+                     (setq isearch-barrier (point) isearch-opoint (point))
+                     (setq found (funcall search-fun string
+                                          (unless isearch-forward
+                                            (minibuffer-prompt-end))
+                                          noerror)))
+                   (overlay-put minibuffer-history-isearch-prefix-overlay
+                                'display (isearch-message-prefix))
+                     (point))
+                 (error nil)))))))))
+ 
+ (defun minibuffer-history-isearch-wrap ()
+   (unless isearch-word
+     (if isearch-forward
+       (next-history-element 0 (length (symbol-value 
minibuffer-history-variable)))
+       (next-history-element 0 0))
+     (setq isearch-success t))
+   (goto-char (if isearch-forward (minibuffer-prompt-end) (point-max))))
+ 
+ (defun minibuffer-history-isearch-push-state ()
+   `(lambda (cmd)
+      (minibuffer-history-isearch-pop-state cmd ,minibuffer-history-position)))
+ 
+ (defun minibuffer-history-isearch-pop-state (cmd hist-pos)
+   (next-history-element 0 hist-pos))
+ 
  
  ;Put this on C-x u, so we can force that rather than C-_ into startup msg
  (defalias 'advertised-undo 'undo)

Index: lisp/isearch.el
===================================================================
RCS file: /sources/emacs/emacs/lisp/isearch.el,v
retrieving revision 1.298
diff -c -r1.298 isearch.el
*** lisp/isearch.el     9 Jul 2007 14:45:01 -0000       1.298
--- lisp/isearch.el     9 Jul 2007 20:55:11 -0000
***************
*** 1924,1930 ****
                isearch-message)
            (isearch-message-suffix c-q-hack ellipsis)
            )))
!     (if c-q-hack
        m
        (let ((message-log-max nil))
        (message "%s" m)))))
--- 1928,1934 ----
                isearch-message)
            (isearch-message-suffix c-q-hack ellipsis)
            )))
!     (if (or c-q-hack (and (minibufferp) isearch-success (not isearch-error)))
        m
        (let ((message-log-max nil))
        (message "%s" m)))))
***************
*** 1944,1949 ****
--- 1948,1954 ----
                   (if isearch-adjusted "pending " "")
                   (if (and isearch-wrapped
                            (not isearch-wrap-function)
+                           (not isearch-search-fun-function)
                            (if isearch-forward
                                (> (point) isearch-opoint)
                              (< (point) isearch-opoint)))

-- 
Juri Linkov
http://www.jurta.org/emacs/




reply via email to

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