vimsuite/vimfiles/autoload/MultipleSearch.vim
stefan 5919dd2bca + MultipleSearch
GetLatestVimScripts
+ wget.exe

git-svn-id: https://vimsuite.svn.sourceforge.net/svnroot/vimsuite/trunk@170 eb2d0018-73a3-4aeb-bfe9-1def61c9ec69
2008-09-26 13:18:32 +00:00

344 lines
11 KiB
VimL

" File: MultipleSearch.vim (global plugin)
" Last Changed: 13 Aug 2008
" Maintainer: Dan Sharp <dwsharp at hotmail dot com>
" Version: 1.3
" License: Vim License
"-----------------------------------------------------------------------------
" MultipleSearch allows you to have the results of multiple searches displayed
" on the screen at the same time. Each search highlights its results in a
" different color, and all searches are displayed at once. After the maximum
" number of colors is used, the script starts over with the first color.
"
" The command syntax is:
" :Search <pattern1>
" which will highlight all occurrences of <pattern1> in the current buffer. A
" subsequent :Search <pattern2> will highlight all occurrences of <pattern2>
" in the current buffer, retaining the highlighting of <pattern1> as well.
" <pattern1> and <pattern2> are any search pattern like you would use in a
" normal /<pattern> search.
"
" The :Search command honors Vim's 'ignorecase' and 'smartcase' settings for
" its own search. You can use the \c and \C flags in the search pattern to
" force case matching no matter the setting of 'ignorecase' and 'smartcase'.
"
" The :SearchBuffers command works just like :Search, but the search occurs in
" all currently listed buffers (i.e., those that appear in the output of :ls).
" The match in all buffers will have the same color. This is different than
" :bufdo Search <pattern> because in that case, each buffer will highlight the
" match in a different color.
"
" To clear the highlighting, issue the command :SearchReset (for the current
" buffer) or :SearchBuffersReset (for all buffers).
"
" You can specify the maximum number of different colors to use by setting the
" g:MultipleSearchMaxColors variable in your .vimrc. The default setting is
" four, but the script should handle as much as your terminal / GUI can
" display. The g:MultipleSearchColorSequence variable lets you list the
" colors you want displayed, and in what order. To make the text more
" readable, you can set the g:MultipleSearchTextColorSequence variable to a
" list of colors for the text, each position corresponding to the color in the
" same position in g:MultipleSearchColorSequence.
" If you change one of the preference variables, you can issue the command
" :SearchReinit
" to update the script with your new selections.
" Supporters:
" Thanks to Peter Valach for suggestions and testing!
" Thanks to Jeff Mei for the suggestion and testing of the :SearchBuffers
" command.
" Thanks to Amber Hassan for fixing a problem with a search pattern containing
" quote characters!
" Thanks to Manuel Picaza for the mapping to :Search the word under the
" cursor.
" ----------------------------------------------------------------------------
" This script uses continuation lines, so make sure it runs using
" Vim-default 'cpoptions'.
let s:save_cpo = &cpo
set cpo&vim
" FUNCTIONS
" --------------------------------------------------
" -----
" Strntok: Utility function to implement C-like strntok() by Michael Geddes
" and Benji Fisher at http://groups.yahoo.com/group/vimdev/message/26788
" -----
function! s:Strntok( s, tok, n)
return matchstr( a:s.a:tok[0], '\v(\zs([^'.a:tok.']*)\ze['.a:tok.']){'.a:n.'}')
endfun
" -----
" MultipleSearchInit: Initialize the higlight groups. This function will add
" highlighting groups if g:MultipSearchMaxColors has increased since the
" plugin was first loaded.
" -----
function! s:MultipleSearchInit()
" Specify a maximum number of colors to use.
if exists('g:MultipleSearchMaxColors')
let s:MaxColors = g:MultipleSearchMaxColors
else
let s:MaxColors = 4
endif
" Define the sequence of colors to use for searches.
if exists('g:MultipleSearchColorSequence')
let s:ColorSequence = g:MultipleSearchColorSequence
else
let s:ColorSequence = "red,yellow,blue,green,magenta,cyan,gray,brown"
endif
" Define the text color for searches, so that it can still be read against the
" colored background.
if exists('g:MultipleSearchTextColorSequence')
let s:TextColorSequence = g:MultipleSearchTextColorSequence
else
let s:TextColorSequence = "white,black,white,black,white,black,black,white"
endif
" Start off with the first color
let s:colorToUse = 0
let s:colorsInUse = 0
" Sanity check: make sure MaxColors is not larger than the number of
" colors in ColorSequence or the corresponding TextColorSequence.
let s:MaxColors = s:Min(s:MaxColors, s:ItemCount(s:ColorSequence . ','),
\ s:ItemCount(s:TextColorSequence . ','))
let loopCount = 0
while loopCount < s:MaxColors
" Define the colors to use
let bgColor = s:Strntok(s:ColorSequence, ',', loopCount + 1)
let fgColor = s:Strntok(s:TextColorSequence, ',', loopCount + 1)
execute 'highlight MultipleSearch' . loopCount
\ . ' ctermbg=' . bgColor . ' guibg=' . bgColor
\ . ' ctermfg=' . fgColor . ' guifg=' . fgColor
let loopCount = loopCount + 1
endwhile
endfunction
" -----
" ItemCount: Returns the number of items in the given string.
" -----
function! s:ItemCount(string)
let itemCount = 0
let newstring = a:string
let pos = stridx(newstring, ',')
while pos > -1
let itemCount = itemCount + 1
let newstring = strpart(newstring, pos + 1)
let pos = stridx(newstring, ',')
endwhile
return itemCount
endfunction
" -----
" Min: Returns the minimum of the given parameters.
" -----
function! s:Min(...)
let min = a:1
let index = 2
while index <= a:0
execute "if min > a:" . index . " | let min = a:" . index . " | endif"
let index = index + 1
endwhile
return min
endfunction
" -----
" GetNextSequenceNumber: Determine the next Search color to use.
" -----
function! s:GetNextSequenceNumber()
let sequenceNumber = s:colorToUse % s:MaxColors
let s:colorToUse = s:colorToUse + 1
if s:colorToUse >= s:MaxColors
let s:colorToUse = 0
endif
return sequenceNumber
endfunction
" -----
" DoSearch: The main searching function that highlights all matches in the
" current buffer.
" -----
function! s:DoSearch(useSearch, forwhat)
" Clear the previous highlighting for this color
execute 'silent syntax clear ' . a:useSearch
" Should it be a case-sensitive match or case-insensitive?
if &ignorecase == 1
" If 'smartcase' is on and our search pattern has an upper-case
" character, do a case sensitive match.
if &smartcase == 1
" match() respects 'ignorecase', so turn it off for now
set noignorecase
if match(a:forwhat, '\u') > -1
syntax case match
else
syntax case ignore
endif
" Be sure to turn 'ignorecase' back on!
set ignorecase
else
syntax case ignore
endif
else
syntax case match
endif
" Highlight the new search
execute 'syntax match ' . a:useSearch . ' "' . a:forwhat . '" containedin=ALL'
let @/ = a:forwhat
endfunction
" -----
" MultipleSearch: Highlight the given pattern in the next available color.
" Vim versions prior to 7.0 don't support the autoload mechanism, so define
" the main function without the autoload prefix.
" -----
if v:version < 700
function! MultipleSearch(allBuffers, forwhat)
call s:MultipleSearchCommon(a:allBuffers, a:forwhat)
endfunction
else
function! MultipleSearch#MultipleSearch(allBuffers, forwhat)
call s:MultipleSearchCommon(a:allBuffers, a:forwhat)
endfunction
endif
" -----
" MultipleSearchCommon: Highlight the given pattern in the next available color.
" -----
function! s:MultipleSearchCommon(allBuffers, forwhat)
let patt = a:forwhat
if( l:patt =~ "[^\\\\]'" ) " if single quote not escaped
let l:patt = escape(l:patt,"'") " escape single quotes with a \ char
endif
if( l:patt =~ '[^\\]"' ) " if double quote not escaped
let l:patt = escape(l:patt, '"') " escape double quotes with a \ char
endif
"let patt = escape(a:forwhat,"'") " escape single quotes with a \ char
"let l:patt = escape(l:patt, '"') " escape double quotes with a \ char
" Determine which search color to use.
let s:curr_sequence = s:GetNextSequenceNumber()
let s:patterns{s:curr_sequence} = l:patt
let s:searchSequence = s:curr_sequence
if s:colorsInUse < s:MaxColors
let s:colorsInUse += 1
endif
let useSearch = "MultipleSearch" . s:curr_sequence
if a:allBuffers
" If a:allBuffers is on, we want to show the match in all currently
" listed buffers.
let counter = 1
let bufCount = bufnr("$")
let current = bufnr("%")
let lz_save = &lazyredraw
" Loop through all the buffers and perform the search in each one.
while counter <= bufCount
if buflisted(counter)
exec "buffer " . counter
call s:DoSearch(useSearch, l:patt)
endif
let counter = counter + 1
endwhile
exec "buffer " . current
let &lazyredraw = lz_save
else
" Otherwise, just search in the current buffer.
call s:DoSearch(useSearch, l:patt)
endif
endfunction
" ---
" DoReset: Clear the highlighting
" ---
function! s:DoReset()
let seq = 0
while seq < s:MaxColors
execute 'syntax clear MultipleSearch' . seq
let seq = seq + 1
endwhile
endfunction
" -----
" MultipleSearchReset: Clear all the current search selections.
" -----
function! s:MultipleSearchReset(allBuffers)
let s:colorToUse = 0
let s:colorsInUse = 0
if a:allBuffers == 1
" If a:allBuffers is on, we want to clear the match in all
" currently listed buffers.
let current = bufnr("%")
bufdo call s:DoReset()
execute "buffer " . current
else
" Otherwise, just clear the current buffer.
call s:DoReset()
endif
endfunction
" -----
" SearchNext: Switch to the next search item to cycle through with n and N
" -----
function! s:SearchNext(direction)
if a:direction == 0
let s:searchSequence += 1
if s:searchSequence >= s:colorsInUse
let s:searchSequence = 0
endif
else
let s:searchSequence -= 1
if s:searchSequence < 0
let s:searchSequence = s:colorsInUse - 1
endif
endif
let @/ = s:patterns{s:searchSequence}
call search(s:patterns{s:searchSequence})
endfunction
" Initialize the script the first time through.
call <SID>MultipleSearchInit()
let &cpo = s:save_cpo
" COMMANDS
" ------------------------------------------------
" Clear the current search selections and start over with the first color in
" the sequence.
if !(exists(":SearchReset") == 2)
command -nargs=0 SearchReset :silent call <SID>MultipleSearchReset(0)
endif
" Clear the current search selections and start over with the first color in
" the sequence.
if !(exists(":SearchBuffersReset") == 2)
command -nargs=0 SearchBuffersReset :silent call <SID>MultipleSearchReset(1)
endif
" Reinitialize the script after changing one of the global preferences.
if !(exists(":SearchReinit") == 2)
command -nargs=0 SearchReinit :silent call <SID>MultipleSearchInit()
endif
" Set the current search pattern to the next one in the list
nnoremap <silent> <Leader>n :call <SID>SearchNext(0)<CR>
"
" Set the current search pattern to the previous one in the list
nnoremap <silent> <Leader>N :call <SID>SearchNext(1)<CR>