[
  {
    "path": ".gitignore",
    "content": "doc/tags\n"
  },
  {
    "path": "README.md",
    "content": "# IndexedSearch.vim\n\nRequires vim7.4\n\nOriginally by [Yakov Lerner](http://www.vim.org/account/profile.php?user_id=2342) and put on GitHub by [Henrik Nyh](https://github.com/henrik) to have it there in a [Pathogen](http://www.vim.org/scripts/script.php?script_id=2332)-friendly format.  Majorly rewritten by [Otto Modinos](https://github.com/otommod).\n\n[See the original plugin page at vim.org.](http://www.vim.org/scripts/script.php?script_id=1682)\n\n```\nThis plugin redefines 6 search commands (/,?,n,N,*,#). At every \nsearch command, it automatically prints>\n       \"At match #N out of M matches\". \n>\n-- the total number of matches (M) and the number(index) of current \nmatch (N). This helps to get oriented when searching forward and \nbackward. \n\nThere are no new commands and no new behavior to learn. \nJust watch the bottom line when you do /,?,n,N,*,#. \n```\n\n[See full help file.](https://github.com/henrik/vim-indexed-search/blob/master/doc/indexed-search.txt)\n\n## Alternatives\n\nIs this plugin too slow for you?  Do you want more (or less) features?  Here're some other plugins that do (or can do) the same thing:\n\n  * On Vim 8.1.1270+, you can use [`:set shortmess-=S`](https://stackoverflow.com/a/4671112/6962)\n  * [google/vim-searchindex](https://github.com/google/vim-searchindex); very fast and unobtrusive\n  * [osyo-manga/vim-anzu](https://github.com/osyo-manga/vim-anzu); tons of features\n  * [romainl/vim-cool](https://github.com/romainl/vim-cool); initally just for disabling the highlighting of matches after a seach, now also show an index\n  * [lacygoill/vim-search](https://github.com/lacygoill/vim-search); meant for [personal use](https://github.com/junegunn/vim-slash/issues/7) but can be used by everyone\n\n"
  },
  {
    "path": "autoload/indexed_search.vim",
    "content": "function! s:echohl(hl, msg)\n    exec 'echohl' a:hl\n    echo a:msg\n    echohl None\nendfunction\n\nfunction! s:old_search(force)\n    let winview = winsaveview()\n    let line = winview[\"lnum\"]\n    let col = winview[\"col\"] + 1\n    let [index, total, is_on_match, first_match_lnum, last_match_lnum] = [0, 0, 0, 0, 0]\n\n    call cursor(1, 1)\n    let [matchline, matchcol] = searchpos(@/, 'Wc')\n    let first_match_lnum = matchline\n    while matchline && (total <= g:indexed_search_max_hits || a:force)\n        let total += 1\n        let last_match_lnum = matchline\n        if matchline < line || (matchline == line && matchcol <= col)\n            let index = total\n            let is_on_match = matchline == line && matchcol == col\n        endif\n        let [matchline, matchcol] = searchpos(@/, 'W')\n    endwhile\n    let out_of_time = (!a:force && total > g:indexed_search_max_hits)\n                \\ + (!a:force && index > g:indexed_search_max_hits)\n\n    call winrestview(winview)\n    return [index, total, is_on_match, out_of_time, first_match_lnum, last_match_lnum]\nendfunction\n\nfunction! s:search(force)\n    let [before, after, is_on_match, first_match_lnum, last_match_lnum] = [0, 0, 1, 0, 0]\n\n    let now = reltime()\n    let winview = winsaveview()\n    let [save_ws, save_fen] = [&wrapscan, &foldenable]\n    set nowrapscan nofoldenable\n\n    \" If we're at the last line and the file contains no EOL there,\n    \" `line2byte()` seems (to me) to give a wrong result.\n    let eolbug = line('.') == line('$') && !&eol && (&bin || !&fixeol)\n\n    \" We need to find out whether the cursor is currently on a match or not\n    \" since that'll affect our numbering.  Naturally, there's no easy way to\n    \" get such information.  The hard way is to wiggle the cursor a bit and\n    \" try to search back and check if we ended up where we started.  There are\n    \" two edge cases though.\n    let curpos = getpos('.')\n    if line2byte(line('$') + 1) <= 3\n        \" The buffer is empty or has only one character.\n        \" In this case, we can't wiggle the cursor, so we just search and\n        \" check for the 'E486 Pattern not found' error.\n        set wrapscan\n        try\n            silent keepjumps normal! n\n        catch /^Vim[^)]\\+):E486\\D/\n            let is_on_match = 0\n        endtry\n        set nowrapscan\n    elseif line2byte('.') + col('.') - 1 <= 1\n        \" We're at the very start of the buffer.\n        \" We move the cursor forwards.\n        silent! keepjumps goto 2\n        silent! exec 'keepjumps normal!' (v:searchforward ? 'N' : 'n')\n    else\n        \" In every other case, we move the cursor backwards.  This works even\n        \" if we're at the very edge of the buffer which is nice because I\n        \" couldn't find any surefire way to check for that.\n        silent! exec 'keepjumps goto' (line2byte('.') + col('.') - (eolbug ? 0 : 2))\n        silent! exec 'keepjumps normal!' (v:searchforward ? 'n' : 'N')\n    endif\n    if getpos('.') != curpos | let is_on_match = 0 | endif\n    call winrestview(winview)\n\n    \" This is the algorithm itself; we first count all the matches before the\n    \" cursor and then all the ones after it.  To count these, we first try\n    \" moving in tens; running '10n' is (mostly) the same as running 'n' 10\n    \" times but it's faster since it runs in C.  If however there are only,\n    \" say, 9 matches, Vim will internally run 'n' 9 times before announcing\n    \" that the 10th found no match but with no way to see how many matched;\n    \" other than counting them one-by-one.  While this wastes some searches as\n    \" a whole it ends up being far faster than doing it all one-by-one.\n    try\n        while before <= g:indexed_search_max_hits || a:force\n            \" if reltimefloat(reltime(now)) > 0.1 | break | endif\n            try\n                silent keepjumps normal! 10N\n                let before += 10\n            catch /^Vim[^)]\\+):E38[45]\\D/\n                try\n                    silent keepjumps normal! N\n                    let before += 1\n                catch /^Vim[^)]\\+):E38[45]\\D/\n                    let first_match_lnum = line('.')\n                    break\n                endtry\n            endtry\n        endwhile\n        call winrestview(winview)\n        while before + after <= g:indexed_search_max_hits || a:force\n            \" if reltimefloat(reltime(now)) > 0.1 | break | endif\n            try\n                silent keepjumps normal! 10n\n                let after += 10\n            catch /^Vim[^)]\\+):E38[45]\\D/\n                try\n                    silent keepjumps normal! n\n                    let after += 1\n                catch /^Vim[^)]\\+):E38[45]\\D/\n                    let last_match_lnum = line('.')\n                    break\n                endtry\n            endtry\n        endwhile\n    finally\n        let [&wrapscan, &foldenable] = [save_ws, save_fen]\n        call winrestview(winview)\n    endtry\n    if !v:searchforward\n        let [after, before] = [before, after]\n        let [first_match_lnum, last_match_lnum] = [last_match_lnum, first_match_lnum]\n    end\n\n    let out_of_time = (!a:force && before > g:indexed_search_max_hits)\n                \\ + (!a:force && after + before > g:indexed_search_max_hits)\n\n    let index = before + is_on_match\n    let total = before + after + is_on_match\n    return [index, total, is_on_match, out_of_time, first_match_lnum, last_match_lnum]\nendfunction\n\nfunction! s:index_message(index, total, is_on_match, out_of_time, first_match_lnum, last_match_lnum)\n    let hl = 'Directory'\n    let msg = ''\n\n    let matches = a:total\n    if a:out_of_time\n        let matches = '> '. a:total\n        if !a:is_on_match || a:out_of_time > 1\n            return [hl, matches .' matches']\n        endif\n    endif\n\n    let line_info = \"\"\n    if g:indexed_search_line_info\n        let line_info = ' (FM:'. a:first_match_lnum .', LM:'. a:last_match_lnum .')'\n    endif\n    let shortmatch = matches . line_info . (g:indexed_search_shortmess ? '' : ' matches')\n\n    if a:total == 0\n        let hl = 'Error'\n        let msg = 'No matches'\n\n    elseif !a:is_on_match && a:index == 0\n        let hl = 'WarningMsg'\n        let msg = 'Before first match, of '. shortmatch\n        if a:total == 1 | let msg = 'Before single match' | endif\n    elseif !a:is_on_match && a:index == a:total\n        let hl = 'WarningMsg'\n        let msg = 'After last match of '. shortmatch\n        if a:total == 1 | let msg = 'After single match' | endif\n    elseif !a:is_on_match\n        \" hl remains default\n        let msg = 'Between matches '. a:index .'-'. (a:index+1) .' of '. matches . line_info\n\n    elseif !g:indexed_search_numbered_only && a:index == 1 && a:total == 1\n        let hl = 'Search'\n        let msg = 'Single match'\n    elseif !g:indexed_search_numbered_only && a:index == 1\n        let hl = 'Search'\n        let msg = 'First of '. shortmatch\n    elseif !g:indexed_search_numbered_only && a:index == a:total\n        let hl = 'LineNr'\n        let msg = 'Last of '. shortmatch\n    else\n        \" hl remains default\n        let msg = (g:indexed_search_shortmess ? '' : 'Match '). a:index .' of '. matches . line_info\n    endif\n\n    return [hl, msg.'  /'.@/.'/']\nendfunction\n\n\nfunction! indexed_search#show_index(force)\n    if @/ == '' || (!a:force && line('$') >= g:indexed_search_max_lines)\n        return\n    endif\n\n    let results = s:search(a:force)\n    let [hl, msg] = call('s:index_message', results)\n    call s:echohl(g:indexed_search_colors ? hl : 'None', msg)\nendfunction\n"
  },
  {
    "path": "doc/indexed-search.txt",
    "content": "*indexed-search.txt*  Show match's count and index with search command\n\nAuthor: Yakov Lerner\n        Otto Modinos\n\nINTRODUCTION                                    *indexed-search*\n\nThis plugin redefines 6 search commands (/,?,n,N,*,#). At every \nsearch command, it automatically prints >\n       \"At match #N out of M matches\".\n<\n-- the total number of matches (M) and the number(index) of current match (N).\nThis helps to get oriented when searching forward and backward.\n\nThere's only one command and no new behavior to learn.  Just watch the bottom\nline when you do /,?,n,N,*,#. \n\nWorks on vim7.  Won't cause slowdown on very large files (but then counters\nare not displayed). \n\n=============================================================================\nCOMMANDS                                        *indexed-search-commands*\n\n                                                    *:ShowSearchIndex*\n:ShowSearchIndex        Shows a message indicating your position relative to\n                        the search matches in the file.  The message's content\n                        also depends on the value of the |g:indexed_search_shortmess|\n                        |g:indexed_search_line_info| and |g:indexed_search_colors| options.\n\n=============================================================================\nOPTIONS                                         *indexed-search-options*\n\n                                                *g:indexed_search_mappings*\ng:indexed_search_mappings\n                If 0, does not create mappings.  |indexed-search-mappings|\n                Default: 1\n\n                                                *g:indexed_search_dont_move*\ng:indexed_search_dont_move\n                If 1, the mappings for * and # stay on the word under the\n                cursor.  Basically, *N (or #N).\n                Default: 0\n\n                                                *g:indexed_search_center*\ng:indexed_search_center\n                If 1, the mappings for n and N also center the cursor on the\n                match.  Basically, nzz (or Nzz).\n                Default: 0\n\n                                                *g:indexed_search_max_lines*\ng:indexed_search_max_lines\n                If a file has more lines than this, the plugin doesn't display\n                messages,  for performance reasons. |indexed-search-performance|\n                Default: 3000\n\n                                                *g:indexed_search_max_hits*\ng:indexed_search_max_hits\n                When there are more matches than this, the plugin doesn't try\n                to count all of them.  Instead it says, e.g. \"> 1000 matches\"\n                Default: 1000                       |indexed-search-performance|\n\n                                                *g:indexed_search_colors*\ng:indexed_search_colors\n                If 0, the messages are not displayed in color\n                Default: 1\n                                                *g:indexed_search_line_info*\ng:indexed_search_line_info\n                If 1, the messages also mention the first and the last match \n                line number in the following format:\n                FM:<first match line no.>, LM:<last match line no.>\n                Default: 0\n\n                                                *g:indexed_search_shortmess*\ng:indexed_search_shortmess\n                If 1, the messages are (a bit) shorter.\n                Default: 0\n\n                                                *g:indexed_search_numbered_only*\ng:indexed_search_numbered_only\n                If 1, the messages only contain the search count.  No\n                \"First of\" and \"Last of\".\n                Default: 0\n\n                                                *g:indexed_search_n_always_searches_forward*\ng:indexed_search_n_always_searches_forward\n                In vim, by default, the direction of n and N depends on\n                whether / or ? was used for searching forward or backward\n                respectively.\n                If 1, n always search forward and N backward\n                Default: 0\n\n=============================================================================\nMAPPINGS                                        *indexed-search-mappings*\n\nIndexed Search remaps the standard Vim keys /, ?, *, #, n and N, so that the\nappropriate message is displayed afterwards. If you don't want that, you can\ndisable these mappings by letting |g:indexed_search_mappings| to 0.\n\n=============================================================================\nPERFORMANCE                                     *indexed-search-performance*\n\nPlugin bypasses the calculation of match index when it would take too much\ntime (too many matches, too large file).  You can use |g:indexed_search_max_lines|\nand |g:indexed_search_max_hits| to tune these performance limits.\n\nvim:tw=78:ts=8:ft=help:norl:\n"
  },
  {
    "path": "plugin/indexed-search.vim",
    "content": "\" Author:       Yakov Lerner <iler.ml@gmail.com>\n\" URL:          http://www.vim.org/scripts/script.php?script_id=1682\n\" Last change:  2018-03-21\n\n\" This script redefines 6 search commands (/,?,n,N,*,#). At each search, it\n\" shows at which match number you are, and the total number of matches, like\n\" this: \"At nth match out of N\". This is printed at the bottom line at every\n\" n,N,/,?,*,# search command, automatically.\n\"\n\" I am posting this plugin because I find it useful.\n\n\" :ShowSearchIndex - Checking your match index\n\" -----------------------------------------------------\n\" At any time, you can use :ShowSearchIndex to show at which match index you\n\" are without moving the cursor.\n\"\n\" If cursor is exactly on the match, the message is:\n\"     At Nth match of M\n\" If cursor is between matches, following messages are displayed:\n\"     Betwen matches 189-190 of 300\n\"     Before first match, of 300\n\"     After last match, of 300\n\n\" To disable colors for messages, set g:indexed_search_colors to 0.\n\"\n\" Performance\n\" ------------------------------------------------------\n\" Plugin bypasses match counting when it would take too much time, i.e. too\n\" many matches or too large a file.  You can change these limits with\n\" g:indexed_search_max_lines and g:indexed_search_max_hits.\n\n\nif exists(\"g:loaded_indexed_search\") || &cp || v:version < 700\n    finish\nendif\nlet g:loaded_indexed_search = 1\n\nlet s:save_cpo = &cpo\nset cpo&vim\n\n\n\" Performance tuning limits\nif !exists('g:indexed_search_max_lines')\n    \" Max filesize (in lines) up to where the plugin works\n    let g:indexed_search_max_lines = 30000\nendif\n\nif !exists(\"g:indexed_search_max_hits\")\n    \" Max number of matches up to where the plugin stops counting\n    let g:indexed_search_max_hits = 1000\nendif\n\n\" Appearance settings\nif !exists('g:indexed_search_colors')\n    \" Whether to use colors for messages\n    let g:indexed_search_colors = 1\nendif\n\nif !exists('g:indexed_search_shortmess')\n    \" Make messages shorter\n    let g:indexed_search_shortmess = 0\nendif\n\nif !exists('g:indexed_search_numbered_only')\n    \" Only show index number, no extra words\n    let g:indexed_search_numbered_only = 0\nendif\n\nif !exists('g:indexed_search_line_info')\n    let g:indexed_search_line_info = 0\nendif\n\n\" Mappings\nif !exists('g:indexed_search_mappings')\n    let g:indexed_search_mappings = 1\nendif\n\nif !exists('g:indexed_search_dont_move')\n    let g:indexed_search_dont_move = 0\nendif\n\nif !exists('g:indexed_search_center')\n    let g:indexed_search_center = 0\nendif\n\nif !exists('g:indexed_search_n_always_searches_forward')\n    let g:indexed_search_n_always_searches_forward = 0\nendif\n\n\ncommand! -bang ShowSearchIndex :call indexed_search#show_index(<bang>0)\n\n\nfunction! s:should_unfold()\n    return has('folding') && &fdo =~ 'search\\|all'\nendfunction\n\nfunction! s:has_mapping(name)\n    return !empty(maparg(a:name, mode()))\nendfunction\n\nfunction! s:restview()\n    call winrestview(s:winview)\nendfunction\n\nfunction! s:star(seq)\n    if g:indexed_search_dont_move\n        let s:winview = winsaveview()\n        return a:seq . \"\\<Plug>(indexed-search-restview)\"\n    endif\n    return a:seq\nendfunction\n\nfunction! s:n(seq)\n    if g:indexed_search_n_always_searches_forward && !v:searchforward\n        return [\"\\<Plug>(indexed-search-n)\", \"\\<Plug>(indexed-search-N)\"][a:seq ==# 'n']\n    endif\n    return a:seq\nendfunction\n\nfunction! s:after()\n    return (s:should_unfold() ? 'zv' : '')\n                \\ .(g:indexed_search_center ? 'zz' : '')\n                \\ .(s:has_mapping('<Plug>(indexed-search-custom)') ? \"\\<Plug>(indexed-search-custom)\" : '')\n                \\ .\"\\<Plug>(indexed-search-index)\"\nendfunction\n\n\nif g:indexed_search_mappings\n    noremap  <Plug>(indexed-search-index)  <Nop>\n    nnoremap <Plug>(indexed-search-index)  :ShowSearchIndex<CR>\n    xnoremap <Plug>(indexed-search-index)  :<C-u>ShowSearchIndex<CR>gv\n\n    noremap  <Plug>(indexed-search-n)  n\n    noremap  <Plug>(indexed-search-N)  N\n\n    noremap  <Plug>(indexed-search-restview)  :call <SID>restview()<CR>\n    xnoremap <Plug>(indexed-search-restview)  :<C-u>call <SID>restview()<CR>gv\n\n    map  <expr> <Plug>(indexed-search-after)  <SID>after()\n    imap        <Plug>(indexed-search-after)  <Nop>\n\n    cmap <expr> <CR> \"\\<CR>\" . (getcmdtype() =~ '[/?]' ? \"\\<Plug>(indexed-search-after)\" : '')\n    \" map  <expr> gd   'gd'    . \"\\<Plug>(indexed-search-after)\"\n    \" map  <expr> gD   'gD'    . \"\\<Plug>(indexed-search-after)\"\n    map  <expr> *    <SID>star('*')  . \"\\<Plug>(indexed-search-after)\"\n    map  <expr> #    <SID>star('#')  . \"\\<Plug>(indexed-search-after)\"\n    map  <expr> g*   <SID>star('g*') . \"\\<Plug>(indexed-search-after)\"\n    map  <expr> g#   <SID>star('g#') . \"\\<Plug>(indexed-search-after)\"\n    map  <expr> n    <SID>n('n')     . \"\\<Plug>(indexed-search-after)\"\n    map  <expr> N    <SID>n('N')     . \"\\<Plug>(indexed-search-after)\"\nendif\n\n\nlet &cpo = s:save_cpo\n\n\" Wishlist\n\" -  using high-precision timer of vim7, count number of millisec\n\"    to run the counters, and base auto-disabling on time it takes.\n\"    very complex regexes can be terribly slow even of files like 'man bash'\n\"    which is mere 5k lines long. Also when there are >10k matches in the file\n\"    set limit to 200 millisec\n\" - implement CursorHold bg counting to which too_slow will resort\n\" - even on large files, we can show \"At last match\", \"After last match\"\n\" - define global vars for all highlights, with defaults\n"
  }
]