Repository: henrik/vim-indexed-search
Branch: master
Commit: 763fdd0eb818
Files: 5
Total size: 19.1 KB
Directory structure:
gitextract_ydkyj2o8/
├── .gitignore
├── README.md
├── autoload/
│ └── indexed_search.vim
├── doc/
│ └── indexed-search.txt
└── plugin/
└── indexed-search.vim
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
doc/tags
================================================
FILE: README.md
================================================
# IndexedSearch.vim
Requires vim7.4
Originally 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).
[See the original plugin page at vim.org.](http://www.vim.org/scripts/script.php?script_id=1682)
```
This plugin redefines 6 search commands (/,?,n,N,*,#). At every
search command, it automatically prints>
"At match #N out of M matches".
>
-- the total number of matches (M) and the number(index) of current
match (N). This helps to get oriented when searching forward and
backward.
There are no new commands and no new behavior to learn.
Just watch the bottom line when you do /,?,n,N,*,#.
```
[See full help file.](https://github.com/henrik/vim-indexed-search/blob/master/doc/indexed-search.txt)
## Alternatives
Is 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:
* On Vim 8.1.1270+, you can use [`:set shortmess-=S`](https://stackoverflow.com/a/4671112/6962)
* [google/vim-searchindex](https://github.com/google/vim-searchindex); very fast and unobtrusive
* [osyo-manga/vim-anzu](https://github.com/osyo-manga/vim-anzu); tons of features
* [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
* [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
================================================
FILE: autoload/indexed_search.vim
================================================
function! s:echohl(hl, msg)
exec 'echohl' a:hl
echo a:msg
echohl None
endfunction
function! s:old_search(force)
let winview = winsaveview()
let line = winview["lnum"]
let col = winview["col"] + 1
let [index, total, is_on_match, first_match_lnum, last_match_lnum] = [0, 0, 0, 0, 0]
call cursor(1, 1)
let [matchline, matchcol] = searchpos(@/, 'Wc')
let first_match_lnum = matchline
while matchline && (total <= g:indexed_search_max_hits || a:force)
let total += 1
let last_match_lnum = matchline
if matchline < line || (matchline == line && matchcol <= col)
let index = total
let is_on_match = matchline == line && matchcol == col
endif
let [matchline, matchcol] = searchpos(@/, 'W')
endwhile
let out_of_time = (!a:force && total > g:indexed_search_max_hits)
\ + (!a:force && index > g:indexed_search_max_hits)
call winrestview(winview)
return [index, total, is_on_match, out_of_time, first_match_lnum, last_match_lnum]
endfunction
function! s:search(force)
let [before, after, is_on_match, first_match_lnum, last_match_lnum] = [0, 0, 1, 0, 0]
let now = reltime()
let winview = winsaveview()
let [save_ws, save_fen] = [&wrapscan, &foldenable]
set nowrapscan nofoldenable
" If we're at the last line and the file contains no EOL there,
" `line2byte()` seems (to me) to give a wrong result.
let eolbug = line('.') == line('$') && !&eol && (&bin || !&fixeol)
" We need to find out whether the cursor is currently on a match or not
" since that'll affect our numbering. Naturally, there's no easy way to
" get such information. The hard way is to wiggle the cursor a bit and
" try to search back and check if we ended up where we started. There are
" two edge cases though.
let curpos = getpos('.')
if line2byte(line('$') + 1) <= 3
" The buffer is empty or has only one character.
" In this case, we can't wiggle the cursor, so we just search and
" check for the 'E486 Pattern not found' error.
set wrapscan
try
silent keepjumps normal! n
catch /^Vim[^)]\+):E486\D/
let is_on_match = 0
endtry
set nowrapscan
elseif line2byte('.') + col('.') - 1 <= 1
" We're at the very start of the buffer.
" We move the cursor forwards.
silent! keepjumps goto 2
silent! exec 'keepjumps normal!' (v:searchforward ? 'N' : 'n')
else
" In every other case, we move the cursor backwards. This works even
" if we're at the very edge of the buffer which is nice because I
" couldn't find any surefire way to check for that.
silent! exec 'keepjumps goto' (line2byte('.') + col('.') - (eolbug ? 0 : 2))
silent! exec 'keepjumps normal!' (v:searchforward ? 'n' : 'N')
endif
if getpos('.') != curpos | let is_on_match = 0 | endif
call winrestview(winview)
" This is the algorithm itself; we first count all the matches before the
" cursor and then all the ones after it. To count these, we first try
" moving in tens; running '10n' is (mostly) the same as running 'n' 10
" times but it's faster since it runs in C. If however there are only,
" say, 9 matches, Vim will internally run 'n' 9 times before announcing
" that the 10th found no match but with no way to see how many matched;
" other than counting them one-by-one. While this wastes some searches as
" a whole it ends up being far faster than doing it all one-by-one.
try
while before <= g:indexed_search_max_hits || a:force
" if reltimefloat(reltime(now)) > 0.1 | break | endif
try
silent keepjumps normal! 10N
let before += 10
catch /^Vim[^)]\+):E38[45]\D/
try
silent keepjumps normal! N
let before += 1
catch /^Vim[^)]\+):E38[45]\D/
let first_match_lnum = line('.')
break
endtry
endtry
endwhile
call winrestview(winview)
while before + after <= g:indexed_search_max_hits || a:force
" if reltimefloat(reltime(now)) > 0.1 | break | endif
try
silent keepjumps normal! 10n
let after += 10
catch /^Vim[^)]\+):E38[45]\D/
try
silent keepjumps normal! n
let after += 1
catch /^Vim[^)]\+):E38[45]\D/
let last_match_lnum = line('.')
break
endtry
endtry
endwhile
finally
let [&wrapscan, &foldenable] = [save_ws, save_fen]
call winrestview(winview)
endtry
if !v:searchforward
let [after, before] = [before, after]
let [first_match_lnum, last_match_lnum] = [last_match_lnum, first_match_lnum]
end
let out_of_time = (!a:force && before > g:indexed_search_max_hits)
\ + (!a:force && after + before > g:indexed_search_max_hits)
let index = before + is_on_match
let total = before + after + is_on_match
return [index, total, is_on_match, out_of_time, first_match_lnum, last_match_lnum]
endfunction
function! s:index_message(index, total, is_on_match, out_of_time, first_match_lnum, last_match_lnum)
let hl = 'Directory'
let msg = ''
let matches = a:total
if a:out_of_time
let matches = '> '. a:total
if !a:is_on_match || a:out_of_time > 1
return [hl, matches .' matches']
endif
endif
let line_info = ""
if g:indexed_search_line_info
let line_info = ' (FM:'. a:first_match_lnum .', LM:'. a:last_match_lnum .')'
endif
let shortmatch = matches . line_info . (g:indexed_search_shortmess ? '' : ' matches')
if a:total == 0
let hl = 'Error'
let msg = 'No matches'
elseif !a:is_on_match && a:index == 0
let hl = 'WarningMsg'
let msg = 'Before first match, of '. shortmatch
if a:total == 1 | let msg = 'Before single match' | endif
elseif !a:is_on_match && a:index == a:total
let hl = 'WarningMsg'
let msg = 'After last match of '. shortmatch
if a:total == 1 | let msg = 'After single match' | endif
elseif !a:is_on_match
" hl remains default
let msg = 'Between matches '. a:index .'-'. (a:index+1) .' of '. matches . line_info
elseif !g:indexed_search_numbered_only && a:index == 1 && a:total == 1
let hl = 'Search'
let msg = 'Single match'
elseif !g:indexed_search_numbered_only && a:index == 1
let hl = 'Search'
let msg = 'First of '. shortmatch
elseif !g:indexed_search_numbered_only && a:index == a:total
let hl = 'LineNr'
let msg = 'Last of '. shortmatch
else
" hl remains default
let msg = (g:indexed_search_shortmess ? '' : 'Match '). a:index .' of '. matches . line_info
endif
return [hl, msg.' /'.@/.'/']
endfunction
function! indexed_search#show_index(force)
if @/ == '' || (!a:force && line('$') >= g:indexed_search_max_lines)
return
endif
let results = s:search(a:force)
let [hl, msg] = call('s:index_message', results)
call s:echohl(g:indexed_search_colors ? hl : 'None', msg)
endfunction
================================================
FILE: doc/indexed-search.txt
================================================
*indexed-search.txt* Show match's count and index with search command
Author: Yakov Lerner
Otto Modinos
INTRODUCTION *indexed-search*
This plugin redefines 6 search commands (/,?,n,N,*,#). At every
search command, it automatically prints >
"At match #N out of M matches".
<
-- the total number of matches (M) and the number(index) of current match (N).
This helps to get oriented when searching forward and backward.
There's only one command and no new behavior to learn. Just watch the bottom
line when you do /,?,n,N,*,#.
Works on vim7. Won't cause slowdown on very large files (but then counters
are not displayed).
=============================================================================
COMMANDS *indexed-search-commands*
*:ShowSearchIndex*
:ShowSearchIndex Shows a message indicating your position relative to
the search matches in the file. The message's content
also depends on the value of the |g:indexed_search_shortmess|
|g:indexed_search_line_info| and |g:indexed_search_colors| options.
=============================================================================
OPTIONS *indexed-search-options*
*g:indexed_search_mappings*
g:indexed_search_mappings
If 0, does not create mappings. |indexed-search-mappings|
Default: 1
*g:indexed_search_dont_move*
g:indexed_search_dont_move
If 1, the mappings for * and # stay on the word under the
cursor. Basically, *N (or #N).
Default: 0
*g:indexed_search_center*
g:indexed_search_center
If 1, the mappings for n and N also center the cursor on the
match. Basically, nzz (or Nzz).
Default: 0
*g:indexed_search_max_lines*
g:indexed_search_max_lines
If a file has more lines than this, the plugin doesn't display
messages, for performance reasons. |indexed-search-performance|
Default: 3000
*g:indexed_search_max_hits*
g:indexed_search_max_hits
When there are more matches than this, the plugin doesn't try
to count all of them. Instead it says, e.g. "> 1000 matches"
Default: 1000 |indexed-search-performance|
*g:indexed_search_colors*
g:indexed_search_colors
If 0, the messages are not displayed in color
Default: 1
*g:indexed_search_line_info*
g:indexed_search_line_info
If 1, the messages also mention the first and the last match
line number in the following format:
FM:<first match line no.>, LM:<last match line no.>
Default: 0
*g:indexed_search_shortmess*
g:indexed_search_shortmess
If 1, the messages are (a bit) shorter.
Default: 0
*g:indexed_search_numbered_only*
g:indexed_search_numbered_only
If 1, the messages only contain the search count. No
"First of" and "Last of".
Default: 0
*g:indexed_search_n_always_searches_forward*
g:indexed_search_n_always_searches_forward
In vim, by default, the direction of n and N depends on
whether / or ? was used for searching forward or backward
respectively.
If 1, n always search forward and N backward
Default: 0
=============================================================================
MAPPINGS *indexed-search-mappings*
Indexed Search remaps the standard Vim keys /, ?, *, #, n and N, so that the
appropriate message is displayed afterwards. If you don't want that, you can
disable these mappings by letting |g:indexed_search_mappings| to 0.
=============================================================================
PERFORMANCE *indexed-search-performance*
Plugin bypasses the calculation of match index when it would take too much
time (too many matches, too large file). You can use |g:indexed_search_max_lines|
and |g:indexed_search_max_hits| to tune these performance limits.
vim:tw=78:ts=8:ft=help:norl:
================================================
FILE: plugin/indexed-search.vim
================================================
" Author: Yakov Lerner <iler.ml@gmail.com>
" URL: http://www.vim.org/scripts/script.php?script_id=1682
" Last change: 2018-03-21
" This script redefines 6 search commands (/,?,n,N,*,#). At each search, it
" shows at which match number you are, and the total number of matches, like
" this: "At nth match out of N". This is printed at the bottom line at every
" n,N,/,?,*,# search command, automatically.
"
" I am posting this plugin because I find it useful.
" :ShowSearchIndex - Checking your match index
" -----------------------------------------------------
" At any time, you can use :ShowSearchIndex to show at which match index you
" are without moving the cursor.
"
" If cursor is exactly on the match, the message is:
" At Nth match of M
" If cursor is between matches, following messages are displayed:
" Betwen matches 189-190 of 300
" Before first match, of 300
" After last match, of 300
" To disable colors for messages, set g:indexed_search_colors to 0.
"
" Performance
" ------------------------------------------------------
" Plugin bypasses match counting when it would take too much time, i.e. too
" many matches or too large a file. You can change these limits with
" g:indexed_search_max_lines and g:indexed_search_max_hits.
if exists("g:loaded_indexed_search") || &cp || v:version < 700
finish
endif
let g:loaded_indexed_search = 1
let s:save_cpo = &cpo
set cpo&vim
" Performance tuning limits
if !exists('g:indexed_search_max_lines')
" Max filesize (in lines) up to where the plugin works
let g:indexed_search_max_lines = 30000
endif
if !exists("g:indexed_search_max_hits")
" Max number of matches up to where the plugin stops counting
let g:indexed_search_max_hits = 1000
endif
" Appearance settings
if !exists('g:indexed_search_colors')
" Whether to use colors for messages
let g:indexed_search_colors = 1
endif
if !exists('g:indexed_search_shortmess')
" Make messages shorter
let g:indexed_search_shortmess = 0
endif
if !exists('g:indexed_search_numbered_only')
" Only show index number, no extra words
let g:indexed_search_numbered_only = 0
endif
if !exists('g:indexed_search_line_info')
let g:indexed_search_line_info = 0
endif
" Mappings
if !exists('g:indexed_search_mappings')
let g:indexed_search_mappings = 1
endif
if !exists('g:indexed_search_dont_move')
let g:indexed_search_dont_move = 0
endif
if !exists('g:indexed_search_center')
let g:indexed_search_center = 0
endif
if !exists('g:indexed_search_n_always_searches_forward')
let g:indexed_search_n_always_searches_forward = 0
endif
command! -bang ShowSearchIndex :call indexed_search#show_index(<bang>0)
function! s:should_unfold()
return has('folding') && &fdo =~ 'search\|all'
endfunction
function! s:has_mapping(name)
return !empty(maparg(a:name, mode()))
endfunction
function! s:restview()
call winrestview(s:winview)
endfunction
function! s:star(seq)
if g:indexed_search_dont_move
let s:winview = winsaveview()
return a:seq . "\<Plug>(indexed-search-restview)"
endif
return a:seq
endfunction
function! s:n(seq)
if g:indexed_search_n_always_searches_forward && !v:searchforward
return ["\<Plug>(indexed-search-n)", "\<Plug>(indexed-search-N)"][a:seq ==# 'n']
endif
return a:seq
endfunction
function! s:after()
return (s:should_unfold() ? 'zv' : '')
\ .(g:indexed_search_center ? 'zz' : '')
\ .(s:has_mapping('<Plug>(indexed-search-custom)') ? "\<Plug>(indexed-search-custom)" : '')
\ ."\<Plug>(indexed-search-index)"
endfunction
if g:indexed_search_mappings
noremap <Plug>(indexed-search-index) <Nop>
nnoremap <Plug>(indexed-search-index) :ShowSearchIndex<CR>
xnoremap <Plug>(indexed-search-index) :<C-u>ShowSearchIndex<CR>gv
noremap <Plug>(indexed-search-n) n
noremap <Plug>(indexed-search-N) N
noremap <Plug>(indexed-search-restview) :call <SID>restview()<CR>
xnoremap <Plug>(indexed-search-restview) :<C-u>call <SID>restview()<CR>gv
map <expr> <Plug>(indexed-search-after) <SID>after()
imap <Plug>(indexed-search-after) <Nop>
cmap <expr> <CR> "\<CR>" . (getcmdtype() =~ '[/?]' ? "\<Plug>(indexed-search-after)" : '')
" map <expr> gd 'gd' . "\<Plug>(indexed-search-after)"
" map <expr> gD 'gD' . "\<Plug>(indexed-search-after)"
map <expr> * <SID>star('*') . "\<Plug>(indexed-search-after)"
map <expr> # <SID>star('#') . "\<Plug>(indexed-search-after)"
map <expr> g* <SID>star('g*') . "\<Plug>(indexed-search-after)"
map <expr> g# <SID>star('g#') . "\<Plug>(indexed-search-after)"
map <expr> n <SID>n('n') . "\<Plug>(indexed-search-after)"
map <expr> N <SID>n('N') . "\<Plug>(indexed-search-after)"
endif
let &cpo = s:save_cpo
" Wishlist
" - using high-precision timer of vim7, count number of millisec
" to run the counters, and base auto-disabling on time it takes.
" very complex regexes can be terribly slow even of files like 'man bash'
" which is mere 5k lines long. Also when there are >10k matches in the file
" set limit to 200 millisec
" - implement CursorHold bg counting to which too_slow will resort
" - even on large files, we can show "At last match", "After last match"
" - define global vars for all highlights, with defaults
gitextract_ydkyj2o8/
├── .gitignore
├── README.md
├── autoload/
│ └── indexed_search.vim
├── doc/
│ └── indexed-search.txt
└── plugin/
└── indexed-search.vim
Condensed preview — 5 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (20K chars).
[
{
"path": ".gitignore",
"chars": 9,
"preview": "doc/tags\n"
},
{
"path": "README.md",
"chars": 1728,
"preview": "# IndexedSearch.vim\n\nRequires vim7.4\n\nOriginally by [Yakov Lerner](http://www.vim.org/account/profile.php?user_id=2342) "
},
{
"path": "autoload/indexed_search.vim",
"chars": 7480,
"preview": "function! s:echohl(hl, msg)\n exec 'echohl' a:hl\n echo a:msg\n echohl None\nendfunction\n\nfunction! s:old_search(fo"
},
{
"path": "doc/indexed-search.txt",
"chars": 4883,
"preview": "*indexed-search.txt* Show match's count and index with search command\n\nAuthor: Yakov Lerner\n Otto Modinos\n\nINTRO"
},
{
"path": "plugin/indexed-search.vim",
"chars": 5430,
"preview": "\" Author: Yakov Lerner <iler.ml@gmail.com>\n\" URL: http://www.vim.org/scripts/script.php?script_id=1682\n\" "
}
]
About this extraction
This page contains the full source code of the henrik/vim-indexed-search GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 5 files (19.1 KB), approximately 5.2k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.