Subject: RE: bug#14729: 24.3.50; Isearch oddity

From: Drew Adams <[email-masked]>
Date: Sat, 29 Jun 2013 20:11:07 -0700 (PDT)

(There may be another way to approach this.  This is what I
have to offer.)

On way of looking at this has to do with the behavior of
`isearch-printing-char'.  If you change it to add the following
`while' sexp then the reported problem disappears:

(defun isearch-printing-char (&optional char count)
    "Append ordinary printing CHAR to the search string and search.
With a numeric prefix arg, append that many copies of CHAR."
    (interactive (list last-command-event
                       (prefix-numeric-value current-prefix-arg)))

    ;; ADDED THIS `while'.
    (while (or (not isearch-success)  isearch-error)
      (isearch-pop-state))

    (let ((char  (or char  last-command-event)))
      (when (= char ?\S-\ ) (setq char ?\  ))
      (if current-input-method
          (isearch-process-search-multibyte-characters char count)
        (isearch-process-search-char char count))))

However, that also changes the behavior in general, in this way:
Whenever there is a mismatch and you type something, what you type
replaces the mismatched part.  That is probably not the behavior
we want, in general.  It might be the behavior some people want
in general or the behavior that anyone might want some of the time.

FWIW, in Isearch+ the above `while' is conditional on the value
of a user option, `isearchp-drop-mismatch'.  Only when the option
value is `replace-last' is the `while' evaluated and thus the
state popped.

There are 3 possible values for the option.  Because you might
sometimes want different behavior, you can cycle among the
values during Isearch using `M-k' (command
`isearchp-cycle-mismatch-removal').  The values:

 nil            - Your current input is appended to the search
                  string, even if the string already has a
                  mismatched portion.

 `replace-last' - Your current input replaces the last mismatched
                  text.  You can always see your last input, even
                  if it is a mismatch.  And it is available for
                  editing using `M-e' (which puts point at the
                  mismatch position).

 anything else  - Your current input is ignored for searching
                  if it causes a mismatch: it is, in effect, not
                  added to the search string, which thus always
                  has only successful matches.

The default value is nil, which gives the same behavior as vanilla
Isearch (including the behavior that you reported): When the
search does not match and you type more text it is simply appended,
even though it does not help with matching (but in the case of a
regexp, it might). 

Value `replace-last' automatically replaces the mismatched portion
by what you type.  This also has the effect of fixing the scenario
you describe.

E.g., if you type `bufx' then the `x' is a mismatch for `buffer'.
If you then type `m', the `m' replaces the `x' (`bufm'), and the
`m' is now the mismatched portion.  If you then type `f' then the
match is extended to `buff' (there is no longer a mismatch).

Any other option value means you never see a mismatch in the
search string.  Anything you type that does not match is dropped,
as if you hadn't typed it.

As I say, there might well be another way to give you the behavior
you expect/prefer here.  The `replace-last' approach is really
designed for something other than your scenario.  It just happens
to take care of this case because what would be a (mistakenly)
highlighted `f' is immediately replaced by an unhighlighted `f'
(you never see it highlighted).

Presumably there is a way to prevent Isearch from recognizing the
reported scenario as a mismatch, rather than applying `replace-last'
as a bandaid.  Perhaps Juri has an idea.  He is more familiar with
the new Isearch state structure etc.