all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
* RFC: [PATCH] isearch enhancements: symbol mode; syntactic filtering
@ 2011-07-07 14:20 Daniel Colascione
  2011-07-07 14:53 ` Lennart Borgman
                   ` (3 more replies)
  0 siblings, 4 replies; 13+ messages in thread
From: Daniel Colascione @ 2011-07-07 14:20 UTC (permalink / raw)
  To: emacs-devel

[-- Attachment #1: Type: text/plain, Size: 1184 bytes --]

New features
------------

- Syntactic filtering: control whether to match in comments, strings, 
and normal text.

- Symbol search: like word search, but looks only at symbol boundaries

- One ring: optionally share a search ring between normal and regular 
expression searches. The additional history storage described below 
allows this mode to work reliably.

Bugfixes
--------

- After an isearch settings change, we refresh the state stored at the 
to of the stack. This way, we don't lose track of settings after adding 
characters to the search string and removing them again.

The patch also changes some behavior:

- With the patch, we store isearch state in the history ring alongside 
the actual search strings.  This information allows us to exactly 
recreate searches when we pull them from history.

Other behavior changes
----------------------

- Case sensitivity is now displayed alongside other isearch settings in 
the isearch prompt.  Previously, the only indication we gave of case 
sensitivity was a fleeing message displayed briefly each time the user 
toggled the setting.

- isearch no longer prints "pending". I don't see why this message would 
be useful.

[-- Attachment #2: isearch-updates.patch --]
[-- Type: text/plain, Size: 32296 bytes --]

=== modified file 'lisp/isearch.el'
--- lisp/isearch.el	2011-07-04 12:15:16 +0000
+++ lisp/isearch.el	2011-07-07 14:17:08 +0000
@@ -57,6 +57,9 @@
 
 ;;; Code:
 
+(eval-when-compile
+  (require 'cl))
+
 \f
 ;; Some additional options and constants.
 
@@ -74,6 +77,11 @@
   :type 'boolean
   :group 'isearch)
 
+(defcustom search-one-ring nil
+  "Non-nil means to use one ring for both normal and regular expression searches."
+  :type 'boolean
+  :group 'isearch)
+
 (defcustom search-slow-window-lines 1
   "Number of lines in slow search display windows.
 These are the short windows used during incremental search on slow terminals.
@@ -399,6 +407,18 @@
 
 (defalias 'isearch-mode-help 'isearch-describe-mode)
 
+(defun* isearch-get-ring (&optional (regexp isearch-regexp))
+  "Return the symbol holding the appropriate search ring to use."
+  (if (and regexp (not search-one-ring))
+      'regexp-search-ring
+    'search-ring))
+
+(defun* isearch-get-yank-pointer (&optional (regexp isearch-regexp))
+  "Return the symbol holding the appropriate search ring yank pointer."
+  (if (and regexp (not search-one-ring))
+      'regexp-search-ring-yank-pointer
+    'search-ring-update))
+
 \f
 ;; Define isearch-mode keymap.
 
@@ -502,7 +522,15 @@
     (define-key map "\M-e" 'isearch-edit-string)
 
     (define-key map "\M-sr" 'isearch-toggle-regexp)
-    (define-key map "\M-sw" 'isearch-toggle-word)
+    (define-key map "\M-sw" 'isearch-cycle-word-mode)
+
+    ;; Shortcuts for useful programming language modes.
+    (define-key map "\M-_"  'isearch-toggle-identifier-mode)
+    (define-key map "\M-#"  'isearch-toggle-match-text)
+    
+    (define-key map "\M-sc" 'isearch-toggle-match-comments)
+    (define-key map "\M-ss" 'isearch-toggle-match-strings)
+    (define-key map "\M-st" 'isearch-toggle-match-text)
 
     (define-key map [?\M-%] 'isearch-query-replace)
     (define-key map [?\C-\M-%] 'isearch-query-replace-regexp)
@@ -530,14 +558,14 @@
 
 (defvar isearch-forward nil)	; Searching in the forward direction.
 (defvar isearch-regexp nil)	; Searching for a regexp.
-(defvar isearch-word nil)	; Searching for words.
-(defvar isearch-hidden nil) ; Non-nil if the string exists but is invisible.
+(defvar isearch-word nil)	; Searching for words or symbols.
+(defvar isearch-context-filter nil)    ; Where to find matches.
+(defvar isearch-hidden nil)     ; Non-nil if the string exists but is invisible.
 
 (defvar isearch-cmds nil
   "Stack of search status sets.
-Each set is a vector of the form:
- [STRING MESSAGE POINT SUCCESS FORWARD OTHER-END WORD
-  INVALID-REGEXP WRAPPED BARRIER WITHIN-BRACKETS CASE-FOLD-SEARCH]")
+Each set is a plist containg isearch variables to restore and
+miscellaneous other information.")
 
 (defvar isearch-string "")  ; The current search string.
 (defvar isearch-message "") ; text-char-description version of isearch-string
@@ -558,8 +586,6 @@
 ;;   case in the search string is ignored.
 (defvar isearch-case-fold-search nil)
 
-(defvar isearch-last-case-fold-search nil)
-
 ;; Used to save default value while isearch is active
 (defvar isearch-original-minibuffer-message-timeout nil)
 
@@ -651,7 +677,7 @@
 
 Type \\[isearch-toggle-case-fold] to toggle search case-sensitivity.
 Type \\[isearch-toggle-regexp] to toggle regular-expression mode.
-Type \\[isearch-toggle-word] to toggle word mode.
+Type \\[isearch-cycle-word-mode] to cycle between normal, word, and symbol mode.
 Type \\[isearch-edit-string] to edit the search string in the minibuffer.
 
 Also supported is a search ring of the previous 16 search strings.
@@ -660,6 +686,11 @@
  ring.
 Type \\[isearch-complete] to complete the search string using the search ring.
 
+Type \\[isearch-toggle-match-comments] to toggle matching inside comments.
+Type \\[isearch-toggle-match-strings] to toggle matching inside strings.
+Type \\[isearch-toggle-match-text] to toggle matching outside comments\
+ and strings.
+
 Type \\[isearch-query-replace] to run `query-replace' with string to\
  replace from last search string.
 Type \\[isearch-query-replace-regexp] to run `query-replace-regexp'\
@@ -746,7 +777,10 @@
 ;;  "List of commands for which isearch-mode does not recursive-edit.")
 
 
-(defun isearch-mode (forward &optional regexp op-fun recursive-edit word-p)
+(defun* isearch-mode (forward &optional regexp op-fun recursive-edit word-p
+                              &key (regexp regexp) (op-fun op-fun)
+                              (recursive-edit recursive-edit) (word-p word-p)
+                              context-filter)
   "Start Isearch minor mode.
 It is called by the function `isearch-forward' and other related functions."
 
@@ -754,8 +788,8 @@
   (setq isearch-forward forward
 	isearch-regexp regexp
 	isearch-word word-p
+        isearch-context-filter context-filter
 	isearch-op-fun op-fun
-	isearch-last-case-fold-search isearch-case-fold-search
 	isearch-case-fold-search case-fold-search
 	isearch-string ""
 	isearch-message ""
@@ -834,7 +868,8 @@
 ;; Some high level utilities.  Others below.
 
 (defun isearch-update ()
-  ;; Called after each command to update the display.
+  ;; Called after each command to update the display and save
+  ;; isearch settings to the top of the stack.
   (if (and (null unread-command-events)
 	   (null executing-kbd-macro))
       (progn
@@ -875,6 +910,8 @@
   (setq ;; quit-flag nil  not for isearch-mode
    isearch-adjusted nil
    isearch-yank-flag nil)
+  (pop isearch-cmds)
+  (isearch-push-state)
   (when isearch-lazy-highlight
     (isearch-lazy-highlight-new-loop))
   ;; We must prevent the point moving to the end of composition when a
@@ -890,10 +927,12 @@
 NOPUSH is t and EDIT is t."
 
   (if isearch-resume-in-command-history
-      (let ((command `(isearch-resume ,isearch-string ,isearch-regexp
-				      ,isearch-word ,isearch-forward
-				      ,isearch-message
-				      ',isearch-case-fold-search)))
+      (let ((command
+             `(isearch-resume ,isearch-string ,isearch-regexp
+                              ,isearch-word ,isearch-forward
+                              ,isearch-message
+                              ',isearch-case-fold-search
+                              :context-filter ',isearch-context-filter)))
 	(unless (equal (car command-history) command)
 	  (setq command-history (cons command command-history)))))
 
@@ -959,10 +998,28 @@
 (defun isearch-update-ring (string &optional regexp)
   "Add STRING to the beginning of the search ring.
 REGEXP if non-nil says use the regexp search ring."
-  (add-to-history
-   (if regexp 'regexp-search-ring 'search-ring)
-   string
-   (if regexp regexp-search-ring-max search-ring-max)))
+  (let ((ring (isearch-get-ring regexp)))
+    (unless (zerop (length string))
+      (setq string (copy-sequence string))
+      (set-text-properties
+       0 (length string)
+       (list 'isearch-saved-state
+             (loop for var in isearch-persistent-state-variables
+                   collect (cons var (symbol-value var))))
+       string)
+      (unless (and (symbol-value ring)
+                   (equal string (car (symbol-value ring)))
+                   (equal (isearch-saved-state-from-string string)
+                          (isearch-saved-state-from-string
+                           (car (symbol-value ring)))))
+        (let (history-delete-duplicates)
+          (add-to-history
+           ring
+           string
+           (if (and regexp (not search-one-ring))
+               regexp-search-ring-max
+             search-ring-max)
+           t))))))
 
 ;; Switching buffers should first terminate isearch-mode.
 ;; ;; For Emacs 19, the frame switch event is handled.
@@ -976,74 +1033,64 @@
 \f
 ;; The search status structure and stack.
 
-(defsubst isearch-string-state (frame)
-  "Return the search string in FRAME."
-  (aref frame 0))
-(defsubst isearch-message-state (frame)
-  "Return the search string to display to the user in FRAME."
-  (aref frame 1))
-(defsubst isearch-point-state (frame)
-  "Return the point in FRAME."
-  (aref frame 2))
-(defsubst isearch-success-state (frame)
-  "Return the success flag in FRAME."
-  (aref frame 3))
-(defsubst isearch-forward-state (frame)
-  "Return the searching-forward flag in FRAME."
-  (aref frame 4))
-(defsubst isearch-other-end-state (frame)
-  "Return the other end of the match in FRAME."
-  (aref frame 5))
-(defsubst isearch-word-state (frame)
-  "Return the search-by-word flag in FRAME."
-  (aref frame 6))
-(defsubst isearch-error-state (frame)
-  "Return the regexp error message in FRAME, or nil if its regexp is valid."
-  (aref frame 7))
-(defsubst isearch-wrapped-state (frame)
-  "Return the search-wrapped flag in FRAME."
-  (aref frame 8))
-(defsubst isearch-barrier-state (frame)
-  "Return the barrier value in FRAME."
-  (aref frame 9))
-(defsubst isearch-case-fold-search-state (frame)
-  "Return the case-folding flag in FRAME."
-  (aref frame 10))
-(defsubst isearch-pop-fun-state (frame)
-  "Return the function restoring the mode-specific Isearch state in FRAME."
-  (aref frame 11))
+(eval-and-compile
+  (defconst isearch-persistent-state-variables
+    '(isearch-word
+      isearch-context-filter
+      isearch-case-fold-search
+      isearch-regexp)
+    "List of isearch variables saved between searches.")
+  
+  (defconst isearch-state-variables
+    (append
+     isearch-persistent-state-variables
+     '(isearch-string
+       isearch-message
+       isearch-success
+       isearch-forward
+       isearch-other-end
+       isearch-word
+       isearch-error
+       isearch-wrapped
+       isearch-barrier
+       isearch-context-filter
+       isearch-case-fold-search))
+    "List of isearch variables saved during searches."))
+
+(eval-when-compile
+  (loop for var in (list*
+                    'isearch-pop-fun
+                    'isearch-point
+                    isearch-state-variables)
+        for accessor = (intern (format "%s-state" var))
+        do (eval
+            `(defun ,accessor (cmd)
+               (cdr (assq ',var cmd))))))
 
 (defun isearch-top-state ()
-  (let ((cmd (car isearch-cmds)))
-    (setq isearch-string (isearch-string-state cmd)
-	  isearch-message (isearch-message-state cmd)
-	  isearch-success (isearch-success-state cmd)
-	  isearch-forward (isearch-forward-state cmd)
-	  isearch-other-end (isearch-other-end-state cmd)
-	  isearch-word (isearch-word-state cmd)
-	  isearch-error (isearch-error-state cmd)
-	  isearch-wrapped (isearch-wrapped-state cmd)
-	  isearch-barrier (isearch-barrier-state cmd)
-	  isearch-case-fold-search (isearch-case-fold-search-state cmd))
-    (if (functionp (isearch-pop-fun-state cmd))
-	(funcall (isearch-pop-fun-state cmd) cmd))
-    (goto-char (isearch-point-state cmd))))
+  (loop for (var . value) in (car isearch-cmds)
+        do (cond ((memq var isearch-state-variables)
+                  (set var value))
+                 ((eq var 'isearch-point)
+                  (goto-char value))
+                 ((and (eq var 'isearch-pop-fun)
+                       (functionp value))
+                  (funcall value (car isearch-cmds))))))
+
+(defun isearch-push-state ()
+  (push (nreverse
+         (list*
+          (cons 'isearch-pop-fun (if isearch-push-state-function
+                                     (funcall isearch-push-state-function)))
+          (cons 'isearch-point (point))
+          (loop for var in isearch-state-variables
+               collect (cons var (symbol-value var)))))
+        isearch-cmds))
 
 (defun isearch-pop-state ()
-  (setq isearch-cmds (cdr isearch-cmds))
+  (pop isearch-cmds)
   (isearch-top-state))
 
-(defun isearch-push-state ()
-  (setq isearch-cmds
-	(cons (vector isearch-string isearch-message (point)
-		      isearch-success isearch-forward isearch-other-end
-		      isearch-word
-		      isearch-error isearch-wrapped isearch-barrier
-		      isearch-case-fold-search
-		      (if isearch-push-state-function
-			  (funcall isearch-push-state-function)))
-	      isearch-cmds)))
-
 \f
 ;; Commands active while inside of the isearch minor mode.
 
@@ -1110,6 +1157,7 @@
 	      (isearch-new-word isearch-word)
 
 	      (isearch-regexp isearch-regexp)
+              (isearch-context-filter isearch-context-filter)
 	      (isearch-op-fun isearch-op-fun)
 	      (isearch-cmds isearch-cmds)
 	      (isearch-success isearch-success)
@@ -1150,20 +1198,21 @@
 	  (setq old-point (point) old-other-end isearch-other-end)
 
 	  (unwind-protect
-	      (let* ((message-log-max nil)
+	      (let* (message-log-max
+                     history-add-new-input ; we'll add to history manually
+                     (minibuffer-allow-text-properties t)
 		     ;; Binding minibuffer-history-symbol to nil is a work-around
 		     ;; for some incompatibility with gmhist.
-		     (minibuffer-history-symbol))
+		     minibuffer-history-symbol
+                     (ring-name (isearch-get-ring))
+                     (yank-pointer-name (isearch-get-yank-pointer)))
 		(setq isearch-new-string
                       (read-from-minibuffer
                        (isearch-message-prefix nil nil isearch-nonincremental)
                         (cons isearch-string (1+ (isearch-fail-pos)))
                        minibuffer-local-isearch-map nil
-                       (if isearch-regexp
-			   (cons 'regexp-search-ring
-				 (1+ (or regexp-search-ring-yank-pointer -1)))
-			 (cons 'search-ring
-			       (1+ (or search-ring-yank-pointer -1))))
+                       (cons ring-name
+                             (1+ (or (symbol-value yank-pointer-name) -1)))
                        nil t)
 		      isearch-new-message
 		      (mapconcat 'isearch-text-char-description
@@ -1181,7 +1230,9 @@
 			  isearch-regexp
 			  isearch-op-fun
 			  nil
-			  isearch-word)
+			  isearch-word
+                          :context-filter isearch-context-filter
+                          )
 
 	    ;; Copy new local values to isearch globals
 	    (setq isearch-string isearch-new-string
@@ -1191,11 +1242,8 @@
 
 	  ;; Empty isearch-string means use default.
 	  (if (= 0 (length isearch-string))
-	      (setq isearch-string (or (car (if isearch-regexp
-						regexp-search-ring
-					      search-ring))
-				       "")
-
+	      (setq isearch-string (or (car (symbol-value (isearch-get-ring)))
+				       "")                    
 		    isearch-message
 		    (mapconcat 'isearch-text-char-description
 			       isearch-string ""))
@@ -1204,6 +1252,10 @@
 	    ;; Only the string actually used should be saved.
 	    ))
 
+        ;; Update isearch variables from the supplied string in case
+        ;; it came from history.
+        (isearch-update-state-from-string)
+
 	;; This used to push the state as of before this C-s, but it adds
 	;; an inconsistent state where part of variables are from the
 	;; previous search (e.g. `isearch-success'), and part of variables
@@ -1213,7 +1265,7 @@
 	;; Reinvoke the pending search.
 	(isearch-search)
 	(isearch-push-state)		; this pushes the correct state
-	(isearch-update)
+        (isearch-update)
 	(if isearch-nonincremental
 	    (progn
 	      ;; (sit-for 1) ;; needed if isearch-done does: (message "")
@@ -1274,22 +1326,40 @@
       (isearch-pop-state))
     (isearch-update)))
 
+(put 'isearch-saved-state 'front-sticky t)
+
+(defun isearch-saved-state-from-string (str)
+  (or (get-text-property 0 'isearch-saved-state str)
+      (get-text-property (next-property-change 0 str (1- (length str)))
+                         'isearch-saved-state str)))
+
+(defun isearch-update-state-from-string ()
+  "Update isearch state variables from text properties.  We set
+these properties when adding strings to isearch history.  By side
+effect, set isearch-string to a copy of the current value with
+all text properties removed."
+  (unless (zerop (length isearch-string))
+    (loop for (var . value) in (isearch-saved-state-from-string
+                                isearch-string)
+          do (set var value))
+    (setq isearch-string (copy-sequence isearch-string))
+    (set-text-properties 0 (length isearch-string) nil isearch-string)))
+
 (defun isearch-repeat (direction)
   ;; Utility for isearch-repeat-forward and -backward.
   (if (eq isearch-forward (eq direction 'forward))
       ;; C-s in forward or C-r in reverse.
       (if (equal isearch-string "")
 	  ;; If search string is empty, use last one.
-	  (if (null (if isearch-regexp regexp-search-ring search-ring))
+	  (if (null (symbol-value (isearch-get-ring)))
 	      (setq isearch-error "No previous search string")
-	    (setq isearch-string
-		  (if isearch-regexp
-		      (car regexp-search-ring)
-		    (car search-ring))
-		  isearch-message
-		  (mapconcat 'isearch-text-char-description
-			     isearch-string "")
-		  isearch-case-fold-search isearch-last-case-fold-search))
+	    (progn
+              (setq isearch-string
+                    (car (symbol-value (isearch-get-ring))))
+              (isearch-update-state-from-string)
+              (setq isearch-message
+                    (mapconcat 'isearch-text-char-description
+                               isearch-string ""))))
 	;; If already have what to search for, repeat it.
 	(or isearch-success
 	    (progn
@@ -1342,25 +1412,81 @@
   (setq isearch-success t isearch-adjusted t)
   (isearch-update))
 
-(defun isearch-toggle-word ()
-  "Toggle word searching on or off."
-  (interactive)
-  (setq isearch-word (not isearch-word))
-  (setq isearch-success t isearch-adjusted t)
-  (isearch-update))
+(defun* isearch-cycle-word-mode (&optional (mode nil mode-supplied-p))
+  "Cycle isearch through normal, word, and symbol searching.  If
+MODE is supplied, set the word mode directly to the mode.  MODE
+should be either the symbol `word' for word-matching mode,
+`symbol' for symbol-matching mode, or nil for normal mode."
+  (interactive)
+  (setq isearch-word (cond
+                      (mode-supplied-p mode)
+                      ((eq isearch-word 'symbol) nil)
+                      (isearch-word 'symbol)
+                      (t 'word)))
+  (setq isearch-success t isearch-adjusted t)
+  (isearch-update))
+
+(defalias 'isearch-toggle-word 'isearch-cycle-word-mode)
+
+(defun isearch-toggle-symbol-mode ()
+  (interactive)
+  (isearch-cycle-word-mode
+   (if (eq isearch-word 'symbol)
+       nil
+     'symbol)))
+
+(defun isearch-toggle-context-filter-flags (filter-flags)
+  "Toggle flags in `isearch-context-filter'.  If any flag in
+FILTER-FLAGS is present, remove all flags in FILTER-FLAGS.
+Otherwise, ensure all flags in FILTER-FLAGS are in
+`isearch-context-filter'"
+  (let ((flag-present (loop for flag in filter-flags
+                            thereis (memq flag isearch-context-filter)))
+        (stripped-filter (loop for old-flag in isearch-context-filter
+                               unless (memq old-flag filter-flags)
+                               collect old-flag)))
+    (setq isearch-context-filter
+          (if flag-present
+              stripped-filter
+            (append filter-flags stripped-filter))))
+  (setq isearch-success t isearch-adjusted t)
+  (isearch-update))
+
+(defun isearch-toggle-match-comments ()
+  "Toggle matching inside comments on or off."
+  (interactive)
+  (isearch-toggle-context-filter-flags '(comment)))
+
+(defun isearch-toggle-match-strings ()
+  "Toggle matching inside comments on or off."
+  (interactive)
+  (isearch-toggle-context-filter-flags '(string)))
+
+(defun isearch-toggle-match-text ()
+  "Toggle matching inside comments on or off."
+  (interactive)
+  (isearch-toggle-context-filter-flags '(text)))
+
+(defun isearch-toggle-match-comments-and-strings ()
+  "Toggle matching inside comments and strings on or off."
+  (interactive)
+  (isearch-toggle-context-filter-flags '(comment string)))
+
+(defun isearch-toggle-identifier-mode ()
+  "Toggle matching whole symbols outside comments and strings on or off."
+  (interactive)
+  (if (or isearch-word isearch-context-filter)
+      (setq isearch-word nil
+            isearch-context-filter nil)
+    (isearch-toggle-symbol-mode)
+    (isearch-toggle-match-comments-and-strings)))
 
 (defun isearch-toggle-case-fold ()
   "Toggle case folding in searching on or off."
   (interactive)
   (setq isearch-case-fold-search
 	(if isearch-case-fold-search nil 'yes))
-  (let ((message-log-max nil))
-    (message "%s%s [case %ssensitive]"
-	     (isearch-message-prefix nil nil isearch-nonincremental)
-	     isearch-message
-	     (if isearch-case-fold-search "in" "")))
   (setq isearch-success t isearch-adjusted t)
-  (sit-for 1)
   (isearch-update))
 
 (defun isearch-query-replace (&optional delimited regexp-flag)
@@ -1382,7 +1508,16 @@
 	;; `exit-recursive-edit' in `isearch-done' that terminates
 	;; the execution of this command when it is non-nil.
 	;; We call `exit-recursive-edit' explicitly at the end below.
-	(isearch-recursive-edit nil))
+	(isearch-recursive-edit nil)
+        ;; Make perform-replace respect our contextual filtering.
+        (replace-search-function
+         `(lambda (&rest args)
+            (apply #'isearch-context-filter-search-function
+                   ',replace-search-function args)))
+        (replace-re-search-function
+         `(lambda (&rest args)
+            (apply #'isearch-context-filter-search-function
+                   ',replace-re-search-function args))))
     (isearch-done nil t)
     (isearch-clean-overlays)
     (if (and isearch-other-end
@@ -1398,7 +1533,11 @@
      (query-replace-read-to
       isearch-string
       (concat "Query replace"
-	      (if (or delimited isearch-word) " word" "")
+              (cond ((eq isearch-word 'symbol)
+                     " symbol")
+                    ((or delimited isearch-word)
+                     " word ")
+                    (t ""))
 	      (if isearch-regexp " regexp" "")
 	      (if (and transient-mark-mode mark-active) " in region" ""))
       isearch-regexp)
@@ -1421,12 +1560,14 @@
   (interactive
    (list
     (cond
-     (isearch-word (concat "\\b" (replace-regexp-in-string
-				  "\\W+" "\\W+"
-				  (replace-regexp-in-string
-				   "^\\W+\\|\\W+$" "" isearch-string)
-				  nil t)
-			   "\\b"))
+     (isearch-word
+      (concat (if (eq isearch-word 'symbol) "\\_<" "\\b")
+              (replace-regexp-in-string
+               "\\W+" "\\W+"
+               (replace-regexp-in-string
+                "^\\W+\\|\\W+$" "" isearch-string)
+               nil t)
+              (if (eq isearch-word 'symbol) "\\_>" "\\b")))
      (isearch-regexp isearch-string)
      (t (regexp-quote isearch-string)))
     (if current-prefix-arg (prefix-numeric-value current-prefix-arg))))
@@ -2060,12 +2201,10 @@
 
 (defun isearch-ring-adjust1 (advance)
   ;; Helper for isearch-ring-adjust
-  (let* ((ring (if isearch-regexp regexp-search-ring search-ring))
+  (let* ((ring (isearch-get-ring))
 	 (length (length ring))
-	 (yank-pointer-name (if isearch-regexp
-				'regexp-search-ring-yank-pointer
-			      'search-ring-yank-pointer))
-	 (yank-pointer (eval yank-pointer-name)))
+	 (yank-pointer-name (isearch-get-yank-pointer))
+	 (yank-pointer (symbol-value yank-pointer-name)))
     (if (zerop length)
 	()
       (set yank-pointer-name
@@ -2082,6 +2221,7 @@
   (isearch-ring-adjust1 advance)
   (if search-ring-update
       (progn
+        (isearch-update-state-from-string)
 	(isearch-search)
 	(isearch-push-state)
 	(isearch-update))
@@ -2104,7 +2244,7 @@
 (defun isearch-complete1 ()
   ;; Helper for isearch-complete and isearch-complete-edit
   ;; Return t if completion OK, nil if no completion exists.
-  (let* ((ring (if isearch-regexp regexp-search-ring search-ring))
+  (let* ((ring (symbol-value (isearch-get-ring)))
          (completion-ignore-case case-fold-search)
          (completion (try-completion isearch-string ring)))
     (cond
@@ -2182,6 +2322,51 @@
 	     (isearch-message-suffix c-q-hack ellipsis)))
     (if c-q-hack m (let ((message-log-max nil)) (message "%s" m)))))
 
+(defun isearch-context-filter-match-p ()
+  "Return t if the current location satisfies `isearch-context-filter'."
+  ;; Compute the parse state only when we might not match it.  Use
+  ;; parse-partial-sexp, not syntax-ppss, to avoid confusing match
+  ;; highlighting.
+  (loop with parse-state = (if isearch-context-filter
+                               (parse-partial-sexp (point-min) (point)))
+        for condition in isearch-context-filter
+        never (case condition
+                (string   (nth 3 parse-state))
+                (comment  (nth 4 parse-state))
+                (text     (not (nth 8 parse-state))))))
+
+(defun isearch-context-filter-search-function (search-func pat bound noerror)
+  "Wrap SEARCH-FUNC so as to enforce `isearch-context-filter'. "
+
+  (let (found)
+    (while (and (setq found (funcall search-func pat bound noerror))
+                (not (isearch-context-filter-match-p))))
+    found))
+
+(defun isearch-describe-context-filter (context-filter)
+  "Return a string describing isearch context-filter CONTEXT-FILTER."
+  (let ((want-comments (not  (memq 'comment context-filter)))
+        (want-strings (not (memq 'string context-filter)))
+        (want-text (not (memq 'text context-filter))))
+    (cond ((null context-filter) "everywhere")
+          ((not (or want-comments want-strings want-text))
+           "[no match]")
+          (want-text
+           (concat "no-"
+                   (cond (want-strings
+                          "comment")
+                         (want-comments
+                          "string")
+                         (t
+                          "string-or-comment"))))
+          (t
+           (cond ((and want-strings want-comments)
+                  "string-and-comment")
+                 (want-strings
+                  "string")
+                 (want-comments
+                  "comment"))))))
+
 (defun isearch-message-prefix (&optional _c-q-hack ellipsis nonincremental)
   ;; If about to search, and previous search regexp was invalid,
   ;; check that it still is.  If it is valid now,
@@ -2194,16 +2379,33 @@
   ;; If currently failing, display no ellipsis.
   (or isearch-success (setq ellipsis nil))
   (let ((m (concat (if isearch-success "" "failing ")
-		   (if isearch-adjusted "pending " "")
-		   (if (and isearch-wrapped
+                   (if (and isearch-wrapped
 			    (not isearch-wrap-function)
 			    (if isearch-forward
 				(> (point) isearch-opoint)
 			      (< (point) isearch-opoint)))
 		       "over")
 		   (if isearch-wrapped "wrapped ")
-		   (if isearch-word "word " "")
+                   (cond ((eq isearch-word 'symbol) "symbol ")
+                         (isearch-word "word ")
+                         (t ""))
+
+                   ;; Display a message for whichever option isn't the
+                   ;; default.
+                   (cond ((and isearch-case-fold-search
+                               (not case-fold-search))
+                          "case-insensitive ")
+                         ((and case-fold-search
+                               (not isearch-case-fold-search))
+                          "case-sensitive ")
+                         (t ""))
+                   
 		   (if isearch-regexp "regexp " "")
+                   (if isearch-context-filter
+                       (concat (isearch-describe-context-filter
+                                isearch-context-filter)
+                               " ")
+                     "")
 		   (if multi-isearch-next-buffer-current-function "multi " "")
 		   (or isearch-message-prefix-add "")
 		   (if nonincremental "search" "I-search")
@@ -2234,12 +2436,24 @@
 This returned function will be used by `isearch-search-string' to
 search for the first occurrence of STRING or its translation.")
 
+(defun isearch-symbol-search-forward (string bound noerror)
+  (re-search-forward
+   (concat "\\_<" (regexp-quote string) "\\_>") bound noerror))
+
+(defun isearch-symbol-search-backward (string bound noerror)
+  (re-search-backward
+   (concat "\\_<" (regexp-quote string) "\\_>") bound noerror))
+
 (defun isearch-search-fun ()
   "Return the function to use for the search.
 Can be changed via `isearch-search-fun-function' for special needs."
   (if isearch-search-fun-function
       (funcall isearch-search-fun-function)
     (cond
+     ((eq isearch-word 'symbol)
+      (if isearch-forward
+          'isearch-symbol-search-forward
+        'isearch-symbol-search-backward))
      (isearch-word
       ;; Use lax versions to not fail at the end of the word while
       ;; the user adds and removes characters in the search string
@@ -2259,7 +2473,8 @@
 If found, move point to the end of the occurrence,
 update the match data, and return point."
   (let* ((func (isearch-search-fun))
-         (pos1 (save-excursion (funcall func string bound noerror)))
+         (pos1 (save-excursion (isearch-context-filter-search-function
+                                func string bound noerror)))
          pos2)
     (when (and
 	   ;; Avoid "obsolete" warnings for translation-table-for-input.
@@ -2282,7 +2497,8 @@
         (when translated
           (save-match-data
             (save-excursion
-              (if (setq pos2 (funcall func translated bound noerror))
+              (if (setq pos2 (isearch-context-filter-search-function
+                              func translated bound noerror))
                   (setq match-data (match-data t)))))
           (when (and pos2
                      (or (not pos1)
@@ -2323,8 +2539,8 @@
 	  (if (or (not isearch-success)
 		  (bobp) (eobp)
 		  (= (match-beginning 0) (match-end 0))
-		  (funcall isearch-filter-predicate
-			   (match-beginning 0) (match-end 0)))
+                  (funcall isearch-filter-predicate
+                           (match-beginning 0) (match-end 0)))
 	      (setq retry nil)))
 	(setq isearch-just-started nil)
 	(if isearch-success
@@ -2702,8 +2918,8 @@
 	  (if (or (not success)
 		  (= (point) bound) ; like (bobp) (eobp) in `isearch-search'.
 		  (= (match-beginning 0) (match-end 0))
-		  (funcall isearch-filter-predicate
-			   (match-beginning 0) (match-end 0)))
+                  (funcall isearch-filter-predicate
+                           (match-beginning 0) (match-end 0)))
 	      (setq retry nil)))
 	success)
     (error nil)))
@@ -2776,7 +2992,8 @@
 		    (run-at-time lazy-highlight-interval nil
 				 'isearch-lazy-highlight-update)))))))))
 
-(defun isearch-resume (string regexp word forward message case-fold)
+(defun* isearch-resume (string regexp word
+                        forward message case-fold &rest args)
   "Resume an incremental search.
 STRING is the string or regexp searched for.
 REGEXP non-nil means the resumed search was a regexp search.
@@ -2784,7 +3001,7 @@
 FORWARD non-nil means resume a forward search.
 MESSAGE is the echo-area message recorded for the search resumed.
 CASE-FOLD non-nil means the search was case-insensitive."
-  (isearch-mode forward regexp nil nil word)
+  (apply #'isearch-mode forward regexp nil nil word args)
   (setq isearch-string string
 	isearch-message message
 	isearch-case-fold-search case-fold)

=== modified file 'lisp/replace.el'
--- lisp/replace.el	2011-07-02 13:53:53 +0000
+++ lisp/replace.el	2011-07-07 05:55:54 +0000
@@ -1797,10 +1797,10 @@
 
     (if delimited-flag
 	(setq search-function 're-search-forward
-	      search-string (concat "\\b"
+	      search-string (concat (if (eq delimited-flag 'symbol) "\\_<" "\\b")
 				    (if regexp-flag from-string
 				      (regexp-quote from-string))
-				    "\\b")))
+                                    (if (eq delimited-flag 'symbol) "\\_>" "\\b"))))
     (when query-replace-lazy-highlight
       (setq isearch-lazy-highlight-last-string nil))
 
@@ -1926,7 +1926,9 @@
 			 (with-output-to-temp-buffer "*Help*"
 			   (princ
 			    (concat "Query replacing "
-				    (if delimited-flag "word " "")
+                                    (cond ((eq delimited-flag 'symbol) "symbol ")
+                                          (delimited-flag "word ")
+                                          (t ""))				    
 				    (if regexp-flag "regexp " "")
 				    from-string " with "
 				    next-replacement ".\n\n"


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: RFC: [PATCH] isearch enhancements: symbol mode; syntactic filtering
  2011-07-07 14:20 RFC: [PATCH] isearch enhancements: symbol mode; syntactic filtering Daniel Colascione
@ 2011-07-07 14:53 ` Lennart Borgman
  2011-07-07 20:51 ` Stefan Monnier
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 13+ messages in thread
From: Lennart Borgman @ 2011-07-07 14:53 UTC (permalink / raw)
  To: Daniel Colascione; +Cc: emacs-devel

On Thu, Jul 7, 2011 at 16:20, Daniel Colascione
<dan.colascione@gmail.com> wrote:
> New features
> ------------
>
> - Syntactic filtering: control whether to match in comments, strings, and
> normal text.
>
> - Symbol search: like word search, but looks only at symbol boundaries
>
> - One ring: optionally share a search ring between normal and regular
> expression searches. The additional history storage described below allows
> this mode to work reliably.
>
> Bugfixes
> --------
>
> - After an isearch settings change, we refresh the state stored at the to of
> the stack. This way, we don't lose track of settings after adding characters
> to the search string and removing them again.
>
> The patch also changes some behavior:
>
> - With the patch, we store isearch state in the history ring alongside the
> actual search strings.  This information allows us to exactly recreate
> searches when we pull them from history.
>
> Other behavior changes
> ----------------------
>
> - Case sensitivity is now displayed alongside other isearch settings in the
> isearch prompt.  Previously, the only indication we gave of case sensitivity
> was a fleeing message displayed briefly each time the user toggled the
> setting.
>
> - isearch no longer prints "pending". I don't see why this message would be
> useful.

Great.



^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: RFC: [PATCH] isearch enhancements: symbol mode; syntactic filtering
  2011-07-07 14:20 RFC: [PATCH] isearch enhancements: symbol mode; syntactic filtering Daniel Colascione
  2011-07-07 14:53 ` Lennart Borgman
@ 2011-07-07 20:51 ` Stefan Monnier
  2011-07-07 21:39   ` Daniel Colascione
  2011-07-08  0:20 ` Juri Linkov
  2011-07-08 21:05 ` Lennart Borgman
  3 siblings, 1 reply; 13+ messages in thread
From: Stefan Monnier @ 2011-07-07 20:51 UTC (permalink / raw)
  To: Daniel Colascione; +Cc: emacs-devel

We're in feature freeze, so it's not a good time to integrate
such changes.  I haven't had time to look at them, but have one comment
below:

> Bugfixes
> --------
> - After an isearch settings change, we refresh the state stored at the to of
> the stack. This way, we don't lose track of settings after adding characters
> to the search string and removing them again.

IIUC that's not a bug, it's a feature.  When I switch to regexp search
after starting a normal search, I don't want to revert to non-regexp
search just because I noticed that there was a typo and used backspace
a few times to go fixing that typo.


        Stefan



^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: RFC: [PATCH] isearch enhancements: symbol mode; syntactic filtering
  2011-07-07 20:51 ` Stefan Monnier
@ 2011-07-07 21:39   ` Daniel Colascione
  0 siblings, 0 replies; 13+ messages in thread
From: Daniel Colascione @ 2011-07-07 21:39 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: emacs-devel@gnu.org

[-- Attachment #1: Type: text/plain, Size: 1043 bytes --]

I don't have plans to merge this work before the feature freeze ends. I should have made that clear.

As for the behavior --- I strongly dislike it. It can lead to the same search string being interpreted two different ways.



Sent from my Palm Pre
On Jul 7, 2011 1:51 PM, Stefan Monnier &lt;monnier@iro.umontreal.ca&gt; wrote: 

We're in feature freeze, so it's not a good time to integrate

such changes.  I haven't had time to look at them, but have one comment

below:



&gt; Bugfixes

&gt; --------

&gt; - After an isearch settings change, we refresh the state stored at the to of

&gt; the stack. This way, we don't lose track of settings after adding characters

&gt; to the search string and removing them again.



IIUC that's not a bug, it's a feature.  When I switch to regexp search

after starting a normal search, I don't want to revert to non-regexp

search just because I noticed that there was a typo and used backspace

a few times to go fixing that typo.





        Stefan



[-- Attachment #2: Type: text/html, Size: 1378 bytes --]

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: RFC: [PATCH] isearch enhancements: symbol mode; syntactic filtering
  2011-07-07 14:20 RFC: [PATCH] isearch enhancements: symbol mode; syntactic filtering Daniel Colascione
  2011-07-07 14:53 ` Lennart Borgman
  2011-07-07 20:51 ` Stefan Monnier
@ 2011-07-08  0:20 ` Juri Linkov
  2011-07-08  0:49   ` Daniel Colascione
  2011-07-08  3:23   ` Drew Adams
  2011-07-08 21:05 ` Lennart Borgman
  3 siblings, 2 replies; 13+ messages in thread
From: Juri Linkov @ 2011-07-08  0:20 UTC (permalink / raw)
  To: Daniel Colascione; +Cc: emacs-devel

> - Syntactic filtering: control whether to match in comments, strings, and
> normal text.

This is easier to implement using `isearch-filter-predicate' as shown in
http://thread.gmane.org/gmane.emacs.devel/34742

Unfortunately, I failed to find a good keybinding for this feature,
so it sunk into obscurity.

> - Symbol search: like word search, but looks only at symbol boundaries

This is much needed.  But I think it should have a keybinding separate
from word search.  Currently, `M-s w' toggles word search,
so a new keybinding `M-s _' could toggle symbol search.

> - One ring: optionally share a search ring between normal and regular
> expression searches. The additional history storage described below allows
> this mode to work reliably.

Maybe sharing a search ring between normal and regexp searches
would be better to implement in the same way as sharing
`from' and `to' histories is implemented in `query-replace'?
Like two variables `query-replace-from-history-variable' and
`query-replace-to-history-variable', isearch could provide
two variables `isearch-ring-variable' and `isearch-regexp-ring-variable'.

> The patch also changes some behavior:
>
> - With the patch, we store isearch state in the history ring alongside the
> actual search strings.  This information allows us to exactly recreate
> searches when we pull them from history.

Yes, storing more information about searches is a good change.

> Other behavior changes
> ----------------------
>
> - Case sensitivity is now displayed alongside other isearch settings in the
> isearch prompt.  Previously, the only indication we gave of case
> sensitivity was a fleeing message displayed briefly each time the user
> toggled the setting.

This is a good change as well, but one possible problem is that
its message string "case-insensitive " (17 characters) is too long
for the isearch prompt.

> - isearch no longer prints "pending". I don't see why this message would
> be useful.

"pending" reminds the user that the actual search position doesn't
correspond to the search parameters displayed in the search prompt.
This happens after e.g. changing the search type to regexp or word.
Updating the search position might be more surprising for users.



^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: RFC: [PATCH] isearch enhancements: symbol mode; syntactic filtering
  2011-07-08  0:20 ` Juri Linkov
@ 2011-07-08  0:49   ` Daniel Colascione
  2011-07-08 19:27     ` Juri Linkov
  2011-07-08  3:23   ` Drew Adams
  1 sibling, 1 reply; 13+ messages in thread
From: Daniel Colascione @ 2011-07-08  0:49 UTC (permalink / raw)
  To: Juri Linkov; +Cc: emacs-devel

On 7/7/2011 5:20 PM, Juri Linkov wrote:
>> - Syntactic filtering: control whether to match in comments, strings, and
>> normal text.
>
> This is easier to implement using `isearch-filter-predicate' as shown in
> http://thread.gmane.org/gmane.emacs.devel/34742

It may be easier to implement that way, but the results aren't as good. 
Integrating the filtering mode into isearch allows it to be saved along 
with all other isearch state.  Also, my approach doesn't conflict with 
other uses of isearch-filter-predicate.

I do like the idea of displaying isearch state information in the 
modeline instead of the minibuffer, however.

> Unfortunately, I failed to find a good keybinding for this feature,
> so it sunk into obscurity.

The ones I proposed should be reasonably accessible, and they don't 
conflict with anything useful directly from isearch.

>> - Symbol search: like word search, but looks only at symbol boundaries
>
> This is much needed.  But I think it should have a keybinding separate
> from word search.  Currently, `M-s w' toggles word search,
> so a new keybinding `M-s _' could toggle symbol search.

Adding symbol search as a new kind of word search makes sense because 
the new search mode is conceptually similar to, and mutually exclusive 
with, classic word search; having accepted this idea, it naturally 
follows to allow users to cycle through normal, word, and symbol 
searches makes sense.  I have no objection to providing a way to go 
directly to symbol search, however: being able to cycle backwards with a 
prefix argument to M-s w would be sufficient, I think.

I like the idea of using M-_ to refer to something having to do with 
symbols; in my patch, I bind this key to a function that both sets 
symbol-search mode _and_ filters out matches in comments and strings; I 
call it identifier-mode.  I find myself wanting exactly this behavior 
fairly frequently.  We can certainly bikeshed a bit about the actual 
keybindings.

>> - One ring: optionally share a search ring between normal and regular
>> expression searches. The additional history storage described below allows
>> this mode to work reliably.
>
> Maybe sharing a search ring between normal and regexp searches
> would be better to implement in the same way as sharing
> `from' and `to' histories is implemented in `query-replace'?
> Like two variables `query-replace-from-history-variable' and
> `query-replace-to-history-variable', isearch could provide
> two variables `isearch-ring-variable' and `isearch-regexp-ring-variable'.

We can do it that way too.  I also considered using a variable alias, to 
point regexp-search-ring at search-ring, but your approach is cleaner.

Speaking of search rings: would anyone object (after feature freeze, of 
course) to allowing history functions to use something other than equal 
(e.g., equal-including-properties) as the comparison function for 
duplicate detection?

>> - Case sensitivity is now displayed alongside other isearch settings in the
>> isearch prompt.  Previously, the only indication we gave of case
>> sensitivity was a fleeing message displayed briefly each time the user
>> toggled the setting.
>
> This is a good change as well, but one possible problem is that
> its message string "case-insensitive " (17 characters) is too long
> for the isearch prompt.

"(CI)"? "nocase"? "case"? My isearch strings tend not to be long enough 
to actually cause problems this way.

>> - isearch no longer prints "pending". I don't see why this message would
>> be useful.
>
> "pending" reminds the user that the actual search position doesn't
> correspond to the search parameters displayed in the search prompt.
> This happens after e.g. changing the search type to regexp or word.
> Updating the search position might be more surprising for users.

I don't feel that the user needs to be reminded of the situation; I 
think the user will intuitively understand what's happening when the 
point fails to move.



^ permalink raw reply	[flat|nested] 13+ messages in thread

* RE: RFC: [PATCH] isearch enhancements: symbol mode; syntactic filtering
  2011-07-08  0:20 ` Juri Linkov
  2011-07-08  0:49   ` Daniel Colascione
@ 2011-07-08  3:23   ` Drew Adams
  2011-07-08 13:04     ` Stefan Monnier
  1 sibling, 1 reply; 13+ messages in thread
From: Drew Adams @ 2011-07-08  3:23 UTC (permalink / raw)
  To: 'Juri Linkov', 'Daniel Colascione'; +Cc: emacs-devel

> > - Case sensitivity is now displayed alongside other isearch 
> >   settings in the isearch prompt.
> 
> This is a good change as well, but one possible problem is that
> its message string "case-insensitive " (17 characters) is too long
> for the isearch prompt.

In Isearch+, I just change the case of the minor-mode lighter in the mode line
to indicate case-sensitivity: `Isearch' (case-sensitive) vs `ISEARCH'
(insensitive).  (I do the same thing in Icicles, for completion.)

That adds no chars to either the prompt or the minor-mode lighter, and I find it
is sufficiently noticeable (and always present during Isearch).

This is all that's needed:

1. Add this call to `isearch-toggle-case-fold':
(isearch-highlight-lighter)

2. Add this definition (or equivalent):

(defun isearch-highlight-lighter ()
  "Update minor-mode mode-line lighter to reflect case sensitivity."
  (let ((case-fold-search  isearch-case-fold-search))
    (when (and (eq case-fold-search t) search-upper-case)
      (setq case-fold-search
            (isearch-no-upper-case-p isearch-string isearch-regexp)))
    (setq minor-mode-alist
          (delete '(isearch-mode " ISEARCH") minor-mode-alist)
          minor-mode-alist
          (delete '(isearch-mode " Isearch") minor-mode-alist))
    (add-to-list
     'minor-mode-alist
     `(isearch-mode ,(if case-fold-search " ISEARCH" " Isearch"))))
  (condition-case nil (redisplay t) (error nil)))

3. (add-hook 'isearch-update-post-hook 'isearch-highlight-lighter)

For the Emacs source code you would not need to use the hook (#3).
You would just add the lighter change to function `isearch-update'.




^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: RFC: [PATCH] isearch enhancements: symbol mode; syntactic filtering
  2011-07-08  3:23   ` Drew Adams
@ 2011-07-08 13:04     ` Stefan Monnier
  0 siblings, 0 replies; 13+ messages in thread
From: Stefan Monnier @ 2011-07-08 13:04 UTC (permalink / raw)
  To: Drew Adams
  Cc: 'Juri Linkov', 'Daniel Colascione', emacs-devel

> In Isearch+, I just change the case of the minor-mode lighter in the
> mode line to indicate case-sensitivity: `Isearch' (case-sensitive) vs
> `ISEARCH' (insensitive).  (I do the same thing in Icicles,
> for completion.)

I'm not sure it's completely intuitive, but it's not a bad choice.
Another choice is to replace the "regexp", "word", and
"case-insensitive" qualifiers with single-letter shorthands.  An obvious
choice is to use the same letter as the one used for the corresponding
key-binding, e.g. "Isearch/r/c:".


        Stefan



^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: RFC: [PATCH] isearch enhancements: symbol mode; syntactic filtering
  2011-07-08  0:49   ` Daniel Colascione
@ 2011-07-08 19:27     ` Juri Linkov
  0 siblings, 0 replies; 13+ messages in thread
From: Juri Linkov @ 2011-07-08 19:27 UTC (permalink / raw)
  To: Daniel Colascione; +Cc: emacs-devel

>>> - Syntactic filtering: control whether to match in comments, strings, and
>>> normal text.
>>
>> This is easier to implement using `isearch-filter-predicate' as shown in
>> http://thread.gmane.org/gmane.emacs.devel/34742
>
> It may be easier to implement that way, but the results aren't as
> good. Integrating the filtering mode into isearch allows it to be saved
> along with all other isearch state.  Also, my approach doesn't conflict
> with other uses of isearch-filter-predicate.

It would be bad design to implement all particular filter types
in isearch.el.  `isearch-filter-predicate' was intended to provide
modular approach where additional filters can be defined only by
changing the value of `isearch-filter-predicate'.

But I agree with you that in its current state `isearch-filter-predicate'
can cause conflicts with other uses of `isearch-filter-predicate'.
It should be improved to allow adding more filters.  This can be
implemented by supporting a list of filters.

`isearch-filter-predicate' also makes it easier to be saved along with
all other isearch state - you can just save its value.

>> Unfortunately, I failed to find a good keybinding for this feature,
>> so it sunk into obscurity.
>
> The ones I proposed should be reasonably accessible, and they don't
> conflict with anything useful directly from isearch.

When choosing a keybinding we need to anticipate the possibility of
adding more keybindings in the future.  Adding a key prefix will help, e.g.

`M-s f c' isearch-toggle-filter-comments
`M-s f s' isearch-toggle-filter-strings
`M-s f t' isearch-toggle-filter-text

where `f' is short for "filter".

>>> - Symbol search: like word search, but looks only at symbol boundaries
>>
>> This is much needed.  But I think it should have a keybinding separate
>> from word search.  Currently, `M-s w' toggles word search,
>> so a new keybinding `M-s _' could toggle symbol search.
>
> Adding symbol search as a new kind of word search makes sense because the
> new search mode is conceptually similar to, and mutually exclusive with,
> classic word search; having accepted this idea, it naturally follows to
> allow users to cycle through normal, word, and symbol searches makes sense.
> I have no objection to providing a way to go directly to symbol search,
> however: being able to cycle backwards with a prefix argument to M-s
> w would be sufficient, I think.

I remember seeing exactly the same arguments in support for cycling
through normal, word, and regexp searches with the same key because they
are conceptually similar (word search is implemented by regexp search)
and mutually exclusive.

If it was decided to put them on one key, then now adding symbol search
to the same key would make cycling longer.  This suggests that it's
better to activate all different search types with separate keys.

> I like the idea of using M-_ to refer to something having to do with
> symbols; in my patch, I bind this key to a function that both sets
> symbol-search mode _and_ filters out matches in comments and strings;
> I call it identifier-mode.  I find myself wanting exactly this behavior
> fairly frequently.  We can certainly bikeshed a bit about the
> actual keybindings.

`identifier-mode' is another search type that suggests that using
a separate key to enable it (e.g. `M-s i') is better than cycling.



^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: RFC: [PATCH] isearch enhancements: symbol mode; syntactic filtering
  2011-07-07 14:20 RFC: [PATCH] isearch enhancements: symbol mode; syntactic filtering Daniel Colascione
                   ` (2 preceding siblings ...)
  2011-07-08  0:20 ` Juri Linkov
@ 2011-07-08 21:05 ` Lennart Borgman
  2011-07-08 21:19   ` Drew Adams
  3 siblings, 1 reply; 13+ messages in thread
From: Lennart Borgman @ 2011-07-08 21:05 UTC (permalink / raw)
  To: Daniel Colascione; +Cc: emacs-devel

On Thu, Jul 7, 2011 at 16:20, Daniel Colascione
<dan.colascione@gmail.com> wrote:
> New features
> ------------
>
> - Syntactic filtering: control whether to match in comments, strings, and
> normal text.

While we are thinking about this: I think sometimes it would be good
to search only visible text. (Especially in org-mode.)



^ permalink raw reply	[flat|nested] 13+ messages in thread

* RE: RFC: [PATCH] isearch enhancements: symbol mode; syntactic filtering
  2011-07-08 21:05 ` Lennart Borgman
@ 2011-07-08 21:19   ` Drew Adams
  2011-07-08 21:50     ` Juri Linkov
  0 siblings, 1 reply; 13+ messages in thread
From: Drew Adams @ 2011-07-08 21:19 UTC (permalink / raw)
  To: 'Lennart Borgman', 'Daniel Colascione'; +Cc: emacs-devel

> While we are thinking about this: I think sometimes it would be good
> to search only visible text. (Especially in org-mode.)

I thought Juri already mentioned that as one of the filtering possibilities.

Anyway, FWIW, in Isearch+, `C-+' toggles searching invisible text.  So yes, I
agree with you.  Trivial to do, and useful IMO.

(defun isearchp-toggle-invisible ()
  "Toggle `search-invisible'."
  (interactive)
  (when search-invisible
   (setq isearchp-last-non-nil-invisible  search-invisible))
  (setq search-invisible
        (if search-invisible nil isearchp-last-non-nil-invisible))
  (if search-invisible
      (message "Searching invisible text is now ON")
    (message "Searching invisible text is now OFF")))

http://www.emacswiki.org/emacs/download/isearch%2b.el




^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: RFC: [PATCH] isearch enhancements: symbol mode; syntactic filtering
  2011-07-08 21:19   ` Drew Adams
@ 2011-07-08 21:50     ` Juri Linkov
  2011-07-08 22:34       ` Drew Adams
  0 siblings, 1 reply; 13+ messages in thread
From: Juri Linkov @ 2011-07-08 21:50 UTC (permalink / raw)
  To: Drew Adams
  Cc: 'Daniel Colascione', 'Lennart Borgman',
	emacs-devel

>> While we are thinking about this: I think sometimes it would be good
>> to search only visible text. (Especially in org-mode.)
>
> I thought Juri already mentioned that as one of the filtering possibilities.

Yes, the default value of `isearch-filter-predicate' is `isearch-filter-visible'.
But to avoid conflicts with other possible filters, it should support a list
of filters and behave like e.g. `run-hook-with-args-until-success'.

> Anyway, FWIW, in Isearch+, `C-+' toggles searching invisible text.  So yes, I
> agree with you.  Trivial to do, and useful IMO.

Then `C-+' could just add/remove `isearch-filter-visible' to/from
`isearch-filter-predicate'.



^ permalink raw reply	[flat|nested] 13+ messages in thread

* RE: RFC: [PATCH] isearch enhancements: symbol mode; syntactic filtering
  2011-07-08 21:50     ` Juri Linkov
@ 2011-07-08 22:34       ` Drew Adams
  0 siblings, 0 replies; 13+ messages in thread
From: Drew Adams @ 2011-07-08 22:34 UTC (permalink / raw)
  To: 'Juri Linkov'
  Cc: 'Daniel Colascione', 'Lennart Borgman',
	emacs-devel

> the default value of `isearch-filter-predicate' is 
> `isearch-filter-visible'.  But to avoid conflicts with other
> possible filters, it should support a list of filters and
> behave like e.g. `run-hook-with-args-until-success'.
> 
> > in Isearch+, `C-+' toggles searching invisible text.
> > So yes, I agree with you.  Trivial to do, and useful IMO.
> 
> Then `C-+' could just add/remove `isearch-filter-visible' to/from
> `isearch-filter-predicate'.

Yes.  Sounds good to me.




^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2011-07-08 22:34 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-07-07 14:20 RFC: [PATCH] isearch enhancements: symbol mode; syntactic filtering Daniel Colascione
2011-07-07 14:53 ` Lennart Borgman
2011-07-07 20:51 ` Stefan Monnier
2011-07-07 21:39   ` Daniel Colascione
2011-07-08  0:20 ` Juri Linkov
2011-07-08  0:49   ` Daniel Colascione
2011-07-08 19:27     ` Juri Linkov
2011-07-08  3:23   ` Drew Adams
2011-07-08 13:04     ` Stefan Monnier
2011-07-08 21:05 ` Lennart Borgman
2011-07-08 21:19   ` Drew Adams
2011-07-08 21:50     ` Juri Linkov
2011-07-08 22:34       ` Drew Adams

Code repositories for project(s) associated with this external index

	https://git.savannah.gnu.org/cgit/emacs.git
	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.