Subject: Re: Implementing search / reverse search in vi mode on input
From: Bart Schaefer <[email-masked]>
To: Zsh hackers list <[email-masked]>
Date: Mon, 18 Jan 2016 11:29:30 -0800
List-Id: Zsh Workers List <zsh-workers.zsh.org>

On Jan 18,  6:45pm, Krzysztof wrote:
}
} The same way I can jump between words (normal mode + w, see:
} http://vim.wikia.com/wiki/Moving_around) I would like to jump to search
} phrase (normal mode + / word).

Oh, I see, you want the search to include the current input buffer, not
begin with the preceding history entry.  I don't know why vi-* widgets
don't already work that way when emacs widgets do.

It might be sufficient to use one of the existing emacs builtin widgets
such as history-incremental-search-backward.  For more vi-like behavior,
you can wrap those up with something like this (untested):

    autoload -Uz read-from-minibuffer
    vi-search-buffer-or-history() {
      emulate -L zsh
      local mbprompt REPLY
      if [[ $WIDGET = *-backward ]]
      then mbprompt='?'
      else mbprompt='/'
      fi
      # May want to install a custom keymap here
      zle read-from-minibuffer $mbprompt
      if [[ $WIDGET = *-backward ]]
      then
        zle .incremental-history-search-backward $REPLY
      else
        zle .incremental-history-search-forward $REPLY
      fi
      # Handle $? as appropriate here:
      # 0 the search succeeded
      # 1 the search failed
      # 2 the search term was a bad pattern
      # 3 the search was aborted by send-break
    }

If you want even more control you can search the buffer yourself (this
is also untested but should be a reasonable outline):

    vi-search-buffer-or-history() {
      emulate -L zsh
      local mbprompt REPLY found
      if [[ $WIDGET = *-backward ]]
      then mbprompt='?'
      else mbprompt='/'
      fi
      # May want to install a custom keymap here
      zle read-from-minibuffer $mbprompt
      if [[ $WIDGET = *-backward ]]
      then
        found=${(MS)LBUFFER%$~REPLY*}
	# (m) for multibyte characters here, may not be needed
        if [[ -n $found ]]
        then (( CURSOR -= ${(m)#found} ))
        else zle vi-history-search-backward $REPLY
        fi
      else
        found=${(MS)RBUFFER#*$~REPLY}
	# (m) for multibyte characters here, may not be needed
        if [[ -n $found ]]
        then (( CURSOR += ${(m)#found} ))
        # Theoretically there is no "forward" from the current buffer
        # else zle vi-history-search-forward $REPLY
        fi
      fi
    }

Both of these would need handling of the LASTSEARCH parameter to allow
repeated calls, I haven't gone into that detail.