From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: Juri Linkov Newsgroups: gmane.emacs.devel Subject: Search minibuffer history Date: Mon, 09 Jul 2007 23:59:33 +0300 Organization: JURTA Message-ID: <87myy5thsa.fsf@jurta.org> NNTP-Posting-Host: lo.gmane.org Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii X-Trace: sea.gmane.org 1184015645 29943 80.91.229.12 (9 Jul 2007 21:14:05 GMT) X-Complaints-To: usenet@sea.gmane.org NNTP-Posting-Date: Mon, 9 Jul 2007 21:14:05 +0000 (UTC) To: emacs-devel@gnu.org Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Mon Jul 09 23:14:00 2007 Return-path: Envelope-to: ged-emacs-devel@m.gmane.org Original-Received: from lists.gnu.org ([199.232.76.165]) by lo.gmane.org with esmtp (Exim 4.50) id 1I80YR-0000uy-84 for ged-emacs-devel@m.gmane.org; Mon, 09 Jul 2007 23:13:59 +0200 Original-Received: from localhost ([127.0.0.1] helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1I80YP-0008Bk-Ti for ged-emacs-devel@m.gmane.org; Mon, 09 Jul 2007 17:13:57 -0400 Original-Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1I80YM-0008BU-BH for emacs-devel@gnu.org; Mon, 09 Jul 2007 17:13:54 -0400 Original-Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1I80YL-0008As-13 for emacs-devel@gnu.org; Mon, 09 Jul 2007 17:13:53 -0400 Original-Received: from [199.232.76.173] (helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1I80YK-0008Ap-ST for emacs-devel@gnu.org; Mon, 09 Jul 2007 17:13:52 -0400 Original-Received: from relay02.kiev.sovam.com ([62.64.120.197]) by monty-python.gnu.org with esmtps (TLS-1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.60) (envelope-from ) id 1I80Wa-0003uM-RT for emacs-devel@gnu.org; Mon, 09 Jul 2007 17:12:05 -0400 Original-Received: from [83.170.232.243] (helo=smtp.svitonline.com) by relay02.kiev.sovam.com with esmtp (Exim 4.67) (envelope-from ) id 1I80WI-000KWf-LB for emacs-devel@gnu.org; Tue, 10 Jul 2007 00:11:47 +0300 User-Agent: Gnus/5.11 (Gnus v5.11) Emacs/22.1.50 (gnu/linux) X-Scanner-Signature: eefe18913497c4710da32e717a56928d X-DrWeb-checked: yes X-SpamTest-Envelope-From: juri@jurta.org X-SpamTest-Group-ID: 00000000 X-SpamTest-Header: Not Detected X-SpamTest-Info: Profiles 1200 [July 09 2007] X-SpamTest-Info: helo_type=3 X-SpamTest-Method: none X-SpamTest-Rate: 0 X-SpamTest-Status: Not detected X-SpamTest-Status-Extended: not_detected X-SpamTest-Version: SMTP-Filter Version 3.0.0 [0255], KAS30/Release X-detected-kernel: HP-UX B.10.20 X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Original-Sender: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Xref: news.gmane.org gmane.emacs.devel:74527 Archived-At: 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/