*sneak.txt*  motion improved

                    Sneak - the missing motion for Vim

==============================================================================
OVERVIEW                                                *sneak*

Sneak provides a way to move quickly and precisely to locations that would be
awkward to reach with built-in Vim motions.

To use Sneak, type "s" followed by exactly two characters:

    s{char}{char}

Thus you can often reach a target with 3 keystrokes. Sneak always moves
immediately to the first {char}{char} match. Additional matches are
highlighted, you can reach them by pressing ; (just like |f| and |t|).

Above all, the goal is to get out of your way. See |sneak-usage| for
a quick-start, and |sneak-features| for full description.

Sneak works with Vim 7.2+ (|sneak-label-mode| requires Vim 7.3+).

==============================================================================
USAGE                                                   *sneak-usage*

Example (cursor position indicated with brackets []): >
    [L]orem ipsum dolor sit amet, consectetur adipisicing elit
<
Type ssi to go to the beginning of the word "sit": >
    Lorem ipsum dolor [s]it amet, consectetur adipisicing elit
<
Type ; (or s again, if |sneak-clever-s| is enabled) to go to the next match: >
    Lorem ipsum dolor sit amet, consectetur adipi[s]icing elit
<
Type Sdo to go backwards to the beginning of the word "dolor": >
    Lorem ipsum [d]olor sit amet, consectetur adipisicing elit
<
Type dzad to delete from the cursor to the first instance of "ad": >
    Lorem ipsum [a]dipisicing elit
<
------------------------------------------------------------------------------
DEFAULT MAPPINGS                                        *sneak-mappings*

Full list of default mappings (see |sneak-custom-mappings| to change them):

NORMAL-MODE~
    Key Sequence             | Description
    -------------------------|----------------------------------------------
    s{char}{char}            | Go to the next occurrence of {char}{char}
    S{char}{char}            | Go to the previous occurrence of {char}{char}
    s{char}<Enter>           | Go to the next occurrence of {char}
    S{char}<Enter>           | Go to the previous occurrence of {char}
    s<Enter>                 | Repeat the last Sneak.
    S<Enter>                 | Repeat the last Sneak, in reverse direction.
    ;                        | Go to the [count]th next match
    , or \                   | Go to the [count]th previous match
    s                        | Go to the [count]th next match (see NOTE)
    S                        | Go to the [count]th previous match (see NOTE)
    [count]s{char}{char}     | Invoke |sneak-vertical-scope|
    [count]S{char}{char}     | Invoke backwards |sneak-vertical-scope|
    {operator}z{char}{char}  | Perform {operator} from the cursor to the next
                             | occurrence of {char}{char}
    {operator}Z{char}{char}  | Perform {operator} from the cursor to the 
                             | previous occurrence of {char}{char}

    NOTE: s and S go to the next/previous match immediately after invoking
    Sneak, if |sneak-clever-s| is enabled.

VISUAL-MODE~
    Key Sequence             | Description
    -------------------------|----------------------------------------------
    s{char}{char}            | Go to the next occurrence of {char}{char}
    Z{char}{char}            | Go to the previous occurrence of {char}{char}
    s{char}<Enter>           | Go to the next occurrence of {char}
    Z{char}<Enter>           | Go to the previous occurrence of {char}
    s<Enter>                 | Repeat the last Sneak.
    Z<Enter>                 | Repeat the last Sneak, in reverse direction.
    ;                        | Go to the [count]th next match
    , or \                   | Go to the [count]th previous match
    s                        | Go to the [count]th next match (NOTE above)
    S                        | Go to the [count]th previous match (NOTE above)

    NOTE: Z goes backwards in visual-mode because S is used by |surround|.

LABEL-MODE~
    Key Sequence             | Description
    -------------------------|----------------------------------------------
    <Space> or <Esc>         | Exit |sneak-label-mode| where the cursor is.
    <Tab>                    | Label the next set of matches.
    <BS> or <S-Tab>          | Label the previous set of matches.

------------------------------------------------------------------------------
CUSTOM MAPPINGS                                         *sneak-custom-mappings*

Sneak defines <Plug> keys so you can choose alternative mappings. But keep in
mind that motions should be the least-friction mappings, because motion is the
most common editor task.
                                                        *sneak-disable-mappings*
To "disable" Sneak default mappings, simply define any other mapping to the
relevant <Plug> key. For example to prevent Sneak from remapping "s" and "S",
just map to <Plug>Sneak_s and <Plug>Sneak_S as shown below.

Available <Plug> keys: >

    " 2-character Sneak (default)
    nmap ? <Plug>Sneak_s
    nmap ? <Plug>Sneak_S
    " visual-mode
    xmap ? <Plug>Sneak_s
    xmap ? <Plug>Sneak_S
    " operator-pending-mode
    omap ? <Plug>Sneak_s
    omap ? <Plug>Sneak_S

    " repeat motion
    map ? <Plug>Sneak_;
    map ? <Plug>Sneak_,

    " 1-character enhanced 'f'
    nmap ? <Plug>Sneak_f
    nmap ? <Plug>Sneak_F
    " visual-mode
    xmap ? <Plug>Sneak_f
    xmap ? <Plug>Sneak_F
    " operator-pending-mode
    omap ? <Plug>Sneak_f
    omap ? <Plug>Sneak_F

    " 1-character enhanced 't'
    nmap ? <Plug>Sneak_t
    nmap ? <Plug>Sneak_T
    " visual-mode
    xmap ? <Plug>Sneak_t
    xmap ? <Plug>Sneak_T
    " operator-pending-mode
    omap ? <Plug>Sneak_t
    omap ? <Plug>Sneak_T

    " label-mode
    nmap ? <Plug>SneakLabel_s
    nmap ? <Plug>SneakLabel_S

==============================================================================
FEATURES                                                *sneak-features*

------------------------------------------------------------------------------
NORMAL-MODE

`s` (and `S`) waits for two characters, then immediately moves to the next
(previous) match. Additional matches are highlighted until the cursor is
moved. Works across multiple lines.

If a |language-mapping| ('keymap') is active Sneak waits for keymapped
sequences as needed and searches for the keymapped result as expected. You
probably want to set |g:sneak#target_labels| to labels that make sense for
your preferred 'keymap'.

[count]s enters |sneak-vertical-scope| mode.

`;` and `,` repeat the last `s` and `S`. They also work correctly with `f` and `t`
(unless you or another plugin have mapped `f` or `t` to a custom mapping).
[count]; and [count], skip to the [count]th match, similar to the
behavior of [count]f and [count]t.

Note: If your mapleader is |,| then Sneak maps |\| instead of |,|. You can
override this by specifying some other mapping, e.g.: >

        map gS <Plug>Sneak_,
<
                                                        *sneak-clever-s*
Similar to clever-f[3], immediately after invoking Sneak you can move to the
next match by hitting `s` (or `S`) again. If you instead move the cursor or do
something else, then `s` starts a new Sneak. In that case, you can repeat the
most recent Sneak search by pressing "s<Enter>" (or whatever key, if any, you
mapped to <Plug>Sneak_;). To enable "clever s": >
    let g:sneak#s_next = 1
<
Sneak adds to the |jumplist| only on the initial invocation; so after moving
around with ; and , (or s/S) you can easily go back via |CTRL-O| or |``|.
    - Repeat invocations (;/,) do not add to the jumplist.
    - Consecutive invocations ("s" immediately after s/S/;/,)
      do not add to the jumplist.

s<Enter> ("s" followed by Enter) always repeats the last search, even if |;|
and |,| were reset by |f| or |t|. This is especially useful for re-invoking
|sneak-label-mode| (because |;| and |,| never invoke label-mode).

------------------------------------------------------------------------------
OPERATIONS

Use `z` for operations (or map to something else: |sneak-custom-mappings|).
For example, `dzab` deletes from the cursor to the next instance of "ab".
`dZab` deletes backwards to the previous instance. `czab` `cZab` `yzab` and
`yZab` also work as expected.

Repeat the operation with dot |.| (requires repeat.vim
https://github.com/tpope/vim-repeat).

Note: |.| repeat works correctly with vim-surround (requires Vim 7.4.786), but
if you undo followed by dot-repeat again, it waits for input.  This bug is not
related to Sneak, it happens with builtin motions also.

------------------------------------------------------------------------------
VERTICAL SCOPE                                          *sneak-vertical-scope*

Sneak has a unique feature called "vertical scope" search. This is invoked by
prefixing `s` or `S` with a [count]. Then the search is limited to a column of
width of 2×[count]. Vertical-scope never invokes |sneak-label-mode|.

Use-cases:
    - CSV file
    - man page (example: search for "-e" in `man bash`)
    - hex editing :%!xxd
    - any columnar layout

------------------------------------------------------------------------------
LABEL-MODE                              *sneak-label-mode* *sneak-streak-mode*

                                                        *g:sneak#label*
Label-mode minimizes the steps to jump to a location, using a clever interface
similar to EasyMotion. If enabled, Sneak overlays text with "labels" which can
be jumped-to by typing the label character. To enable label-mode: >

    let g:sneak#label = 1

Label-mode features:
- Jump to a label by typing its character.              *sneak-fallthrough*
- Non-label keys "fall through" to normal-mode, so you don't need to
  explicitly exit label-mode if the first match is correct.
- <Tab> skips to the next set of matches (<BS>, <S-Tab> go the other way).
  These actions are preserved with dot-repeat.
- <Space> or <Esc> exits label-mode. |g:sneak#label_esc|
- |folds| are skipped (not labeled). Use |;| and |,| to reach folded or
  off-screen matches.

Standard features behave as usual:
- If `s` is prefixed with [count] then |sneak-vertical-scope| is invoked, not
  label-mode.
- Skip to the next or previous match with |;| or |,|
- Return to your original location via |CTRL-O| or |``|
- Use any |operator|, including |surround|.
- Repeat operations with |.| (dot).

Sneak compared to EasyMotion:
- is faster and more predictable
- never modifies your data (EasyMotion uses edit-and-undo hacks)
- never adds extra "stages" or "groups", so it is predictable (common case is
  the highest priority)
- always visually separates target labels

==============================================================================
CONFIGURATION                                           *sneak-config*

Sneak is designed with sane, effective defaults, to avoid configuration as
much as possible. But you can change them as follows.

------------------------------------------------------------------------------
OPTIONS                                                 *sneak-options*

To change an option, add a |let| statement in your |vimrc|. Example: >
    let g:sneak#use_ic_scs = 0
<
g:sneak#f_reset = 1
g:sneak#t_reset = 1

    Note: Defaults to 0 if you mapped f (or t) to any |sneak-mappings|.

    0: Pressing |f| (or |t|) will NOT clear the last Sneak search. So you could
       define different maps for <Plug>Sneak_; or <Plug>Sneak_, and still
       use ; and , for |f| and |t| as usual.

    1: Pressing |f| (or |t|) causes Sneak to "reset" so that |;| and |,| will apply
       to the last f (or t) motion instead of the last s or S. This makes it
       possible to use ; and , for all three motions (f, t, and s).

       Note: if f (or t) was already mapped by you or a plugin, Sneak will
       not override the existing mapping unless you explicitly set f_reset
       (or t_reset). This means Sneak will not be able to reset ; or , when
       you invoke f or t. See the README.md FAQ regarding "f-enhancement"
       plugins.

g:sneak#s_next = 0

    0: Disable |sneak-clever-s|.

    1: Enable |sneak-clever-s|. It works like this: immediately after
       invoking Sneak, press "s" _again_ to go to the next match, or "S" for
       the previous match. This behavior persists until you move the cursor.
       Note: You can still use |;| and |,| as usual.

g:sneak#absolute_dir = 0

    0: Relative direction. |;| goes to the next match in the direction of the
       initial s/S invocation and |,| goes in the opposite direction.

    1: Absolute direction. Repeat via |;| or |,| always goes forwards or
       backwards respectively.
       Note: With |sneak-clever-s|, s and S behave the same as |;| and |,|.

g:sneak#use_ic_scs = 0

    0: Always case-sensitive

    1: Case sensitivity is determined by 'ignorecase' and 'smartcase'.

g:sneak#map_netrw = 1

    0: Don't do any special handling of "file manager" buffers (such as
       |netrw| or filebeagle).

    1: Set up Sneak mappings (s and S) in "file manager" buffers (|:Ex|,
       |:Vex|, filebeagle) and replace the default buffer-local s and
       S mappings with <leader>s and <leader>S.

g:sneak#label = 0

    0: Disable |sneak-label-mode|.

    1: Enable |sneak-label-mode| if the Vim |+conceal| feature is available.

g:sneak#label_esc = "\<Space>"                          *g:sneak#label_esc*

    Exit |sneak-label-mode| as if <Esc> were pressed.
        https://github.com/justinmk/vim-sneak/issues/122

g:sneak#target_labels = ";sftunq/SFGHLTUNRMQZ?0"        *g:sneak#target_labels*

    List of characters used to label the target locations. |sneak-label-mode|

    Labels should be keys that you never use after searching. E.g. it is
    unlikely that you will use "F" immediately after a Sneak, so "F" is in the
    label list. This removes a step if the first match is correct: instead,
    just type your next command. |sneak-fallthrough|

    Note: Any key mapped to <Plug>Sneak_; is moved to the first position
    (because it's semantically equivalent).

    Note: Invalid target labels are removed:
        - Any key mapped to <Plug>Sneak_,
        - Special keys: <Esc> <Tab> <BS>
        - Invisible keys: <Space> <Enter>

g:sneak#prompt = '>'

        Message displayed at the Sneak input prompt.

------------------------------------------------------------------------------
HIGHLIGHTING                                            *sneak-highlight*

Sneak uses these highlight groups:

    Sneak
        Highlights Sneak matches. Default color is hideous magenta :)
        Also used for |sneak-label-mode| unless "SneakLabel" group exists.

    SneakScope
        Highlights the "scope" for |sneak-vertical-scope|.
        Default color is white (or black if 'background' is "light").
        Also used to show the cursor placement during |sneak-label-mode|.

    SneakLabel
        Highlights |sneak-label-mode|.

To customize colors: >
    highlight Sneak guifg=black guibg=red ctermfg=black ctermbg=red
    highlight SneakScope guifg=red guibg=yellow ctermfg=red ctermbg=yellow

To disable highlighting: >
    highlight link Sneak None
    " Needed if a plugin sets the colorscheme dynamically:
    autocmd User SneakLeave highlight clear Sneak

------------------------------------------------------------------------------
FUNCTIONS                                               *sneak-functions*

These functions are provided if you want more control.

sneak#wrap(op, inputlen, reverse, inclusive, label)     *sneak#wrap()*
        Sneaks with exactly {inputlen} characters. For example with {inputlen}
        of 2 the search is performed when the second character is typed,
        without waiting for <Enter>.

        Parameters:
            {op}:           operator name: empty string "" for normal-mode,
                            otherwise |v:operator|, |visualmode()|, or custom.
            {inputlen}:     wait for this many input keys
            {reverse}:      0: forward motion
                            1: backward motion
            {inclusive}:    0: |t|-like motion
                            1: |f|-like motion
                            2: |exclusive| motion like |/|
            {label}:        0: never invoke |sneak-label-mode|
                            1: label-mode for >=2 matches
                            2: label-mode always

        Example: Configure "f" to trigger label-mode: >
          nnoremap <silent> f :<C-U>call sneak#wrap('',           1, 0, 1, 1)<CR>
          nnoremap <silent> F :<C-U>call sneak#wrap('',           1, 1, 1, 1)<CR>
          xnoremap <silent> f :<C-U>call sneak#wrap(visualmode(), 1, 0, 1, 1)<CR>
          xnoremap <silent> F :<C-U>call sneak#wrap(visualmode(), 1, 1, 1, 1)<CR>
          onoremap <silent> f :<C-U>call sneak#wrap(v:operator,   1, 0, 1, 1)<CR>
          onoremap <silent> F :<C-U>call sneak#wrap(v:operator,   1, 1, 1, 1)<CR>
<
        Example: Configure "s" to wait for 3 characters: >
          nnoremap <silent> s :<C-U>call sneak#wrap('',           3, 0, 2, 1)<CR>
          nnoremap <silent> S :<C-U>call sneak#wrap('',           3, 1, 2, 1)<CR>
          xnoremap <silent> s :<C-U>call sneak#wrap(visualmode(), 3, 0, 2, 1)<CR>
          xnoremap <silent> S :<C-U>call sneak#wrap(visualmode(), 3, 1, 2, 1)<CR>
          onoremap <silent> s :<C-U>call sneak#wrap(v:operator,   3, 0, 2, 1)<CR>
          onoremap <silent> S :<C-U>call sneak#wrap(v:operator,   3, 1, 2, 1)<CR>
<
sneak#is_sneaking()                                     *sneak#is_sneaking()*
        Returns 1 if Sneak is active, else 0. Sneak deactivates when the user
        chooses a target or moves the cursor. Useful for changing the behavior
        of a mapping.

        Example: <Tab> goes to the next match _only_ while Sneak is active: >
            nmap <expr> <Tab> sneak#is_sneaking() ? '<Plug>Sneak_;' : '<Tab>'
<
        Example: change the statusline: >
            set statusline=%{sneak#is_sneaking()?'SNEAKING':'RELAXING'}
<
            https://github.com/justinmk/vim-sneak/pull/93

sneak#cancel()                                          *sneak#cancel()*
        Deactivates Sneak: removes autocmds/highlighting and causes
        |sneak#is_sneaking()| to return 0.
            https://github.com/justinmk/vim-sneak/issues/106

sneak#reset(key)                                        *sneak#reset()*
        Prevents Sneak from hijacking |;| and |,| until the next invocation of
        Sneak. This is useful if you have remapped the Vim built-in |f| or
        |t| to another key and you still want to use |;| and |,| for both Sneak
        and your custom "f" mapping.
            https://github.com/justinmk/vim-sneak/issues/114

        For example, to use "a" as your "f":
>
            nnoremap <expr> a sneak#reset('f')
            nnoremap <expr> A sneak#reset('F')
            xnoremap <expr> a sneak#reset('f')
            xnoremap <expr> A sneak#reset('F')
            onoremap <expr> a sneak#reset('f')
            onoremap <expr> A sneak#reset('F')
<
            Note: The <expr> modifier is required!

sneak#state()                                           *sneak#state()*
        Returns a read-only dictionary representing the current behavior.

        Values set at invocation (_not_ for repeat):
            KEY             VALUE~
            bounds          [left,right] integer pair representing the current
                            |sneak-vertical-scope| or [0,0] if not scoped
            inclusive       0: |t|-like motion
                            1: |f|-like motion
                            2: |exclusive| motion like |/|
            input           current search string
            inputlen        length of the current search string
            reverse         0: invoked as forward motion `s`
                            1: invoked as backward motion `S`
            rst             0: |;| and |,| should repeat the most recent Sneak
                            1: after calling |sneak#reset()|

        Values updated on each repeat (|;| |,|):
            KEY             VALUE~
            rptreverse      0: repeat was effectively forward
                            1: repeat was effectively backward

        For example, to create a mapping that behaves differently depending
        on the current Sneak direction (`rptreverse` key):
>
        nmap <silent> <expr> <tab> sneak#is_sneaking()
              \ ? (sneak#state().rptreverse ? '<Plug>SneakLabel_S<cr>' : '<Plug>SneakLabel_s<cr>')
              \ : '<Plug>Sneak_s'
<
==============================================================================
EVENTS                                                  *sneak-events*

The |User| *SneakEnter* event is triggered when Sneak is invoked (including
dot-repeat invocations, but not motion-repeat).

Example: >
    autocmd User SneakEnter set nocursorcolumn nocursorline

The |User| *SneakLeave* event is triggered when Sneak is finished (including
dot-repeat invocations, but not motion-repeat).

Example: >
    autocmd User SneakLeave set cursorcolumn cursorline

==============================================================================
CONTRIBUTING                                            *sneak-contributing*

Bug reports, feature requests, and patches are welcome:
    https://github.com/justinmk/vim-sneak

To narrow down the issue, run Vim with a minimal configuration: >
    vim -u NORC -N +"let g:sneak#label=1" +":set runtimepath+=~/.vim/bundle/vim-sneak/" +":runtime plugin/sneak.vim"

or Nvim: >
    nvim -u NORC --cmd "let g:sneak#label=1" +":set runtimepath+=~/.local/share/nvim/bundle/vim-sneak/" +":runtime plugin/sneak.vim"

==============================================================================
CREDITS                                                 *sneak-credits*

Author: Justin M. Keyes <justinkz+vim@gmail.com>

Sneak was inspired by vim-seek, vim-easymotion, clever-f, and Tim Pope's
plugins.

    https://github.com/goldfeld/vim-seek
    https://github.com/Lokaltog/vim-easymotion
    https://github.com/rhysd/clever-f.vim

==============================================================================
vim:tw=78:sw=4:ts=8:ft=help:norl:
