mirror of
https://github.com/gryf/.vim.git
synced 2026-02-15 07:15:49 +01:00
Moja prawie współczesna konfiguracja. Dużo rzeczy :)
This commit is contained in:
471
autoload/mark.vim
Normal file
471
autoload/mark.vim
Normal file
@@ -0,0 +1,471 @@
|
||||
" Script Name: mark.vim
|
||||
" Description: Highlight several words in different colors simultaneously.
|
||||
"
|
||||
" Copyright: (C) 2005-2008 by Yuheng Xie
|
||||
" (C) 2008-2010 by Ingo Karkat
|
||||
" The VIM LICENSE applies to this script; see ':help copyright'.
|
||||
"
|
||||
" Maintainer: Ingo Karkat <ingo@karkat.de>
|
||||
"
|
||||
" Dependencies:
|
||||
" - SearchSpecial.vim autoload script (optional, for improved search messages).
|
||||
"
|
||||
" Version: 2.3.3
|
||||
" Changes:
|
||||
" 19-Feb-2010, Andy Wokula
|
||||
" - BUG: Clearing of an accidental zero-width match (e.g. via :Mark \zs) results
|
||||
" in endless loop. Thanks to Andy Wokula for the patch.
|
||||
"
|
||||
" 17-Nov-2009, Ingo Karkat + Andy Wokula
|
||||
" - BUG: Creation of literal pattern via '\V' in {Visual}<Leader>m mapping
|
||||
" collided with individual escaping done in <Leader>m mapping so that an
|
||||
" escaped '\*' would be interpreted as a multi item when both modes are used
|
||||
" for marking. Replaced \V with s:EscapeText() to be consistent. Replaced the
|
||||
" (overly) generic mark#GetVisualSelectionEscaped() with
|
||||
" mark#GetVisualSelectionAsRegexp() and
|
||||
" mark#GetVisualSelectionAsLiteralPattern(). Thanks to Andy Wokula for the
|
||||
" patch.
|
||||
"
|
||||
" 06-Jul-2009, Ingo Karkat
|
||||
" - Re-wrote s:AnyMark() in functional programming style.
|
||||
" - Now resetting 'smartcase' before the search, this setting should not be
|
||||
" considered for *-command-alike searches and cannot be supported because all
|
||||
" mark patterns are concatenated into one large regexp, anyway.
|
||||
"
|
||||
" 04-Jul-2009, Ingo Karkat
|
||||
" - Re-wrote s:Search() to handle v:count:
|
||||
" - Obsoleted s:current_mark_position; mark#CurrentMark() now returns both the
|
||||
" mark text and start position.
|
||||
" - s:Search() now checks for a jump to the current mark during a backward
|
||||
" search; this eliminates a lot of logic at its calling sites.
|
||||
" - Reverted negative logic at calling sites; using empty() instead of != "".
|
||||
" - Now passing a:isBackward instead of optional flags into s:Search() and
|
||||
" around its callers.
|
||||
" - ':normal! zv' moved from callers into s:Search().
|
||||
" - Removed delegation to SearchSpecial#ErrorMessage(), because the fallback
|
||||
" implementation is perfectly fine and the SearchSpecial routine changed its
|
||||
" output format into something unsuitable anyway.
|
||||
" - Using descriptive text instead of "@" (and appropriate highlighting) when
|
||||
" querying for the pattern to mark.
|
||||
"
|
||||
" 02-Jul-2009, Ingo Karkat
|
||||
" - Split off functions into autoload script.
|
||||
|
||||
"- functions ------------------------------------------------------------------
|
||||
function! s:EscapeText( text )
|
||||
return substitute( escape(a:text, '\' . '^$.*[~'), "\n", '\\n', 'ge' )
|
||||
endfunction
|
||||
" Mark the current word, like the built-in star command.
|
||||
" If the cursor is on an existing mark, remove it.
|
||||
function! mark#MarkCurrentWord()
|
||||
let l:regexp = mark#CurrentMark()[0]
|
||||
if empty(l:regexp)
|
||||
let l:cword = expand("<cword>")
|
||||
|
||||
" The star command only creates a \<whole word\> search pattern if the
|
||||
" <cword> actually only consists of keyword characters.
|
||||
if l:cword =~# '^\k\+$'
|
||||
let l:regexp = '\<' . s:EscapeText(l:cword) . '\>'
|
||||
elseif l:cword != ''
|
||||
let l:regexp = s:EscapeText(l:cword)
|
||||
endif
|
||||
endif
|
||||
|
||||
if ! empty(l:regexp)
|
||||
call mark#DoMark(l:regexp)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:GetVisualSelection()
|
||||
let save_a = @a
|
||||
silent normal! gv"ay
|
||||
let res = @a
|
||||
let @a = save_a
|
||||
return res
|
||||
endfunction
|
||||
function! mark#GetVisualSelectionAsLiteralPattern()
|
||||
return s:EscapeText(s:GetVisualSelection())
|
||||
endfunction
|
||||
function! mark#GetVisualSelectionAsRegexp()
|
||||
return substitute(s:GetVisualSelection(), '\n', '', 'g')
|
||||
endfunction
|
||||
|
||||
" Manually input a regular expression.
|
||||
function! mark#MarkRegex( regexpPreset )
|
||||
call inputsave()
|
||||
echohl Question
|
||||
let l:regexp = input('Input pattern to mark: ', a:regexpPreset)
|
||||
echohl None
|
||||
call inputrestore()
|
||||
if ! empty(l:regexp)
|
||||
call mark#DoMark(l:regexp)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:Cycle( ... )
|
||||
let l:currentCycle = g:mwCycle
|
||||
let l:newCycle = (a:0 ? a:1 : g:mwCycle) + 1
|
||||
let g:mwCycle = (l:newCycle < g:mwCycleMax ? l:newCycle : 0)
|
||||
return l:currentCycle
|
||||
endfunction
|
||||
|
||||
" Set / clear matches in the current window.
|
||||
function! s:MarkMatch( indices, expr )
|
||||
for l:index in a:indices
|
||||
if w:mwMatch[l:index] > 0
|
||||
silent! call matchdelete(w:mwMatch[l:index])
|
||||
let w:mwMatch[l:index] = 0
|
||||
endif
|
||||
endfor
|
||||
|
||||
if ! empty(a:expr)
|
||||
" Make the match according to the 'ignorecase' setting, like the star command.
|
||||
" (But honor an explicit case-sensitive regexp via the /\C/ atom.)
|
||||
let l:expr = ((&ignorecase && a:expr !~# '\\\@<!\\C') ? '\c' . a:expr : a:expr)
|
||||
|
||||
" Info: matchadd() does not consider the 'magic' (it's always on),
|
||||
" 'ignorecase' and 'smartcase' settings.
|
||||
let w:mwMatch[a:indices[0]] = matchadd('MarkWord' . (a:indices[0] + 1), l:expr, -10)
|
||||
endif
|
||||
endfunction
|
||||
" Set / clear matches in all windows.
|
||||
function! s:MarkScope( indices, expr )
|
||||
let l:currentWinNr = winnr()
|
||||
|
||||
" By entering a window, its height is potentially increased from 0 to 1 (the
|
||||
" minimum for the current window). To avoid any modification, save the window
|
||||
" sizes and restore them after visiting all windows.
|
||||
let l:originalWindowLayout = winrestcmd()
|
||||
|
||||
noautocmd windo call s:MarkMatch(a:indices, a:expr)
|
||||
execute l:currentWinNr . 'wincmd w'
|
||||
silent! execute l:originalWindowLayout
|
||||
endfunction
|
||||
" Update matches in all windows.
|
||||
function! mark#UpdateScope()
|
||||
let l:currentWinNr = winnr()
|
||||
|
||||
" By entering a window, its height is potentially increased from 0 to 1 (the
|
||||
" minimum for the current window). To avoid any modification, save the window
|
||||
" sizes and restore them after visiting all windows.
|
||||
let l:originalWindowLayout = winrestcmd()
|
||||
|
||||
noautocmd windo call mark#UpdateMark()
|
||||
execute l:currentWinNr . 'wincmd w'
|
||||
silent! execute l:originalWindowLayout
|
||||
endfunction
|
||||
" Mark or unmark a regular expression.
|
||||
function! mark#DoMark(...) " DoMark(regexp)
|
||||
let regexp = (a:0 ? a:1 : '')
|
||||
|
||||
" clear all marks if regexp is null
|
||||
if empty(regexp)
|
||||
let i = 0
|
||||
let indices = []
|
||||
while i < g:mwCycleMax
|
||||
if !empty(g:mwWord[i])
|
||||
let g:mwWord[i] = ''
|
||||
call add(indices, i)
|
||||
endif
|
||||
let i += 1
|
||||
endwhile
|
||||
let g:mwLastSearched = ""
|
||||
call s:MarkScope(l:indices, '')
|
||||
return
|
||||
endif
|
||||
|
||||
" clear the mark if it has been marked
|
||||
let i = 0
|
||||
while i < g:mwCycleMax
|
||||
if regexp == g:mwWord[i]
|
||||
if g:mwLastSearched == g:mwWord[i]
|
||||
let g:mwLastSearched = ''
|
||||
endif
|
||||
let g:mwWord[i] = ''
|
||||
call s:MarkScope([i], '')
|
||||
return
|
||||
endif
|
||||
let i += 1
|
||||
endwhile
|
||||
|
||||
" add to history
|
||||
if stridx(g:mwHistAdd, "/") >= 0
|
||||
call histadd("/", regexp)
|
||||
endif
|
||||
if stridx(g:mwHistAdd, "@") >= 0
|
||||
call histadd("@", regexp)
|
||||
endif
|
||||
|
||||
" choose an unused mark group
|
||||
let i = 0
|
||||
while i < g:mwCycleMax
|
||||
if empty(g:mwWord[i])
|
||||
let g:mwWord[i] = regexp
|
||||
call s:Cycle(i)
|
||||
call s:MarkScope([i], regexp)
|
||||
return
|
||||
endif
|
||||
let i += 1
|
||||
endwhile
|
||||
|
||||
" choose a mark group by cycle
|
||||
let i = s:Cycle()
|
||||
if g:mwLastSearched == g:mwWord[i]
|
||||
let g:mwLastSearched = ''
|
||||
endif
|
||||
let g:mwWord[i] = regexp
|
||||
call s:MarkScope([i], regexp)
|
||||
endfunction
|
||||
" Initialize mark colors in a (new) window.
|
||||
function! mark#UpdateMark()
|
||||
if ! exists('w:mwMatch')
|
||||
let w:mwMatch = repeat([0], g:mwCycleMax)
|
||||
endif
|
||||
|
||||
let i = 0
|
||||
while i < g:mwCycleMax
|
||||
if empty(g:mwWord[i])
|
||||
call s:MarkMatch([i], '')
|
||||
else
|
||||
call s:MarkMatch([i], g:mwWord[i])
|
||||
endif
|
||||
let i += 1
|
||||
endwhile
|
||||
endfunction
|
||||
|
||||
" Return [mark text, mark start position] of the mark under the cursor (or
|
||||
" ['', []] if there is no mark); multi-lines marks not supported.
|
||||
function! mark#CurrentMark()
|
||||
let line = getline(".")
|
||||
let i = 0
|
||||
while i < g:mwCycleMax
|
||||
if !empty(g:mwWord[i])
|
||||
" Note: col() is 1-based, all other indexes zero-based!
|
||||
let start = 0
|
||||
while start >= 0 && start < strlen(line) && start < col(".")
|
||||
let b = match(line, g:mwWord[i], start)
|
||||
let e = matchend(line, g:mwWord[i], start)
|
||||
if b < col(".") && col(".") <= e
|
||||
return [g:mwWord[i], [line("."), (b + 1)]]
|
||||
endif
|
||||
if b == e
|
||||
break
|
||||
endif
|
||||
let start = e
|
||||
endwhile
|
||||
endif
|
||||
let i += 1
|
||||
endwhile
|
||||
return ['', []]
|
||||
endfunction
|
||||
|
||||
" Search current mark.
|
||||
function! mark#SearchCurrentMark( isBackward )
|
||||
let [l:markText, l:markPosition] = mark#CurrentMark()
|
||||
if empty(l:markText)
|
||||
if empty(g:mwLastSearched)
|
||||
call mark#SearchAnyMark(a:isBackward)
|
||||
let g:mwLastSearched = mark#CurrentMark()[0]
|
||||
else
|
||||
call s:Search(g:mwLastSearched, a:isBackward, [], 'same-mark')
|
||||
endif
|
||||
else
|
||||
call s:Search(l:markText, a:isBackward, l:markPosition, (l:markText ==# g:mwLastSearched ? 'same-mark' : 'new-mark'))
|
||||
let g:mwLastSearched = l:markText
|
||||
endif
|
||||
endfunction
|
||||
|
||||
silent! call SearchSpecial#DoesNotExist() " Execute a function to force autoload.
|
||||
if exists('*SearchSpecial#WrapMessage')
|
||||
function! s:WrapMessage( searchType, searchPattern, isBackward )
|
||||
redraw
|
||||
call SearchSpecial#WrapMessage(a:searchType, a:searchPattern, a:isBackward)
|
||||
endfunction
|
||||
function! s:EchoSearchPattern( searchType, searchPattern, isBackward )
|
||||
call SearchSpecial#EchoSearchPattern(a:searchType, a:searchPattern, a:isBackward)
|
||||
endfunction
|
||||
else
|
||||
function! s:Trim( message )
|
||||
" Limit length to avoid "Hit ENTER" prompt.
|
||||
return strpart(a:message, 0, (&columns / 2)) . (len(a:message) > (&columns / 2) ? "..." : "")
|
||||
endfunction
|
||||
function! s:WrapMessage( searchType, searchPattern, isBackward )
|
||||
redraw
|
||||
let v:warningmsg = printf('%s search hit %s, continuing at %s', a:searchType, (a:isBackward ? 'TOP' : 'BOTTOM'), (a:isBackward ? 'BOTTOM' : 'TOP'))
|
||||
echohl WarningMsg
|
||||
echo s:Trim(v:warningmsg)
|
||||
echohl None
|
||||
endfunction
|
||||
function! s:EchoSearchPattern( searchType, searchPattern, isBackward )
|
||||
let l:message = (a:isBackward ? '?' : '/') . a:searchPattern
|
||||
echohl SearchSpecialSearchType
|
||||
echo a:searchType
|
||||
echohl None
|
||||
echon s:Trim(l:message)
|
||||
endfunction
|
||||
endif
|
||||
function! s:ErrorMessage( searchType, searchPattern, isBackward )
|
||||
if &wrapscan
|
||||
let v:errmsg = a:searchType . ' not found: ' . a:searchPattern
|
||||
else
|
||||
let v:errmsg = printf('%s search hit %s without match for: %s', a:searchType, (a:isBackward ? 'TOP' : 'BOTTOM'), a:searchPattern)
|
||||
endif
|
||||
echohl ErrorMsg
|
||||
echomsg v:errmsg
|
||||
echohl None
|
||||
endfunction
|
||||
|
||||
" Wrapper around search() with additonal search and error messages and "wrapscan" warning.
|
||||
function! s:Search( pattern, isBackward, currentMarkPosition, searchType )
|
||||
let l:save_view = winsaveview()
|
||||
|
||||
" searchpos() obeys the 'smartcase' setting; however, this setting doesn't
|
||||
" make sense for the mark search, because all patterns for the marks are
|
||||
" concatenated as branches in one large regexp, and because patterns that
|
||||
" result from the *-command-alike mappings should not obey 'smartcase' (like
|
||||
" the * command itself), anyway. If the :Mark command wants to support
|
||||
" 'smartcase', it'd have to emulate that into the regular expression.
|
||||
let l:save_smartcase = &smartcase
|
||||
set nosmartcase
|
||||
|
||||
let l:count = v:count1
|
||||
let [l:startLine, l:startCol] = [line('.'), col('.')]
|
||||
let l:isWrapped = 0
|
||||
let l:isMatch = 0
|
||||
let l:line = 0
|
||||
while l:count > 0
|
||||
" Search for next match, 'wrapscan' applies.
|
||||
let [l:line, l:col] = searchpos( a:pattern, (a:isBackward ? 'b' : '') )
|
||||
|
||||
"****D echomsg '****' a:isBackward string([l:line, l:col]) string(a:currentMarkPosition) l:count
|
||||
if a:isBackward && l:line > 0 && [l:line, l:col] == a:currentMarkPosition && l:count == v:count1
|
||||
" On a search in backward direction, the first match is the start of the
|
||||
" current mark (if the cursor was positioned on the current mark text, and
|
||||
" not at the start of the mark text).
|
||||
" In contrast to the normal search, this is not considered the first
|
||||
" match. The mark text is one entity; if the cursor is positioned anywhere
|
||||
" inside the mark text, the mark text is considered the current mark. The
|
||||
" built-in '*' and '#' commands behave in the same way; the entire <cword>
|
||||
" text is considered the current match, and jumps move outside that text.
|
||||
" In normal search, the cursor can be positioned anywhere (via offsets)
|
||||
" around the search, and only that single cursor position is considered
|
||||
" the current match.
|
||||
" Thus, the search is retried without a decrease of l:count, but only if
|
||||
" this was the first match; repeat visits during wrapping around count as
|
||||
" a regular match. The search also must not be retried when this is the
|
||||
" first match, but we've been here before (i.e. l:isMatch is set): This
|
||||
" means that there is only the current mark in the buffer, and we must
|
||||
" break out of the loop and indicate that no other mark was found.
|
||||
if l:isMatch
|
||||
let l:line = 0
|
||||
break
|
||||
endif
|
||||
|
||||
" The l:isMatch flag is set so if the final mark cannot be reached, the
|
||||
" original cursor position is restored. This flag also allows us to detect
|
||||
" whether we've been here before, which is checked above.
|
||||
let l:isMatch = 1
|
||||
elseif l:line > 0
|
||||
let l:isMatch = 1
|
||||
let l:count -= 1
|
||||
|
||||
" Note: No need to check 'wrapscan'; the wrapping can only occur if
|
||||
" 'wrapscan' is actually on.
|
||||
if ! a:isBackward && (l:startLine > l:line || l:startLine == l:line && l:startCol >= l:col)
|
||||
let l:isWrapped = 1
|
||||
elseif a:isBackward && (l:startLine < l:line || l:startLine == l:line && l:startCol <= l:col)
|
||||
let l:isWrapped = 1
|
||||
endif
|
||||
else
|
||||
break
|
||||
endif
|
||||
endwhile
|
||||
let &smartcase = l:save_smartcase
|
||||
|
||||
" We're not stuck when the search wrapped around and landed on the current
|
||||
" mark; that's why we exclude a possible wrap-around via v:count1 == 1.
|
||||
let l:isStuckAtCurrentMark = ([l:line, l:col] == a:currentMarkPosition && v:count1 == 1)
|
||||
if l:line > 0 && ! l:isStuckAtCurrentMark
|
||||
normal! zv
|
||||
|
||||
if l:isWrapped
|
||||
call s:WrapMessage(a:searchType, a:pattern, a:isBackward)
|
||||
else
|
||||
call s:EchoSearchPattern(a:searchType, a:pattern, a:isBackward)
|
||||
endif
|
||||
return 1
|
||||
else
|
||||
if l:isMatch
|
||||
" The view has been changed by moving through matches until the end /
|
||||
" start of file, when 'nowrapscan' forced a stop of searching before the
|
||||
" l:count'th match was found.
|
||||
" Restore the view to the state before the search.
|
||||
call winrestview(l:save_view)
|
||||
endif
|
||||
call s:ErrorMessage(a:searchType, a:pattern, a:isBackward)
|
||||
return 0
|
||||
endif
|
||||
endfunction
|
||||
|
||||
" Combine all marks into one regexp.
|
||||
function! s:AnyMark()
|
||||
return join(filter(copy(g:mwWord), '! empty(v:val)'), '\|')
|
||||
endfunction
|
||||
|
||||
" Search any mark.
|
||||
function! mark#SearchAnyMark( isBackward )
|
||||
let l:markPosition = mark#CurrentMark()[1]
|
||||
let l:markText = s:AnyMark()
|
||||
call s:Search(l:markText, a:isBackward, l:markPosition, 'any-mark')
|
||||
let g:mwLastSearched = ""
|
||||
endfunction
|
||||
|
||||
" Search last searched mark.
|
||||
function! mark#SearchNext( isBackward )
|
||||
let l:markText = mark#CurrentMark()[0]
|
||||
if empty(l:markText)
|
||||
return 0
|
||||
else
|
||||
if empty(g:mwLastSearched)
|
||||
call mark#SearchAnyMark(a:isBackward)
|
||||
else
|
||||
call mark#SearchCurrentMark(a:isBackward)
|
||||
endif
|
||||
return 1
|
||||
endif
|
||||
endfunction
|
||||
|
||||
"- initializations ------------------------------------------------------------
|
||||
augroup Mark
|
||||
autocmd!
|
||||
autocmd VimEnter * if ! exists('w:mwMatch') | call mark#UpdateMark() | endif
|
||||
autocmd WinEnter * if ! exists('w:mwMatch') | call mark#UpdateMark() | endif
|
||||
autocmd TabEnter * call mark#UpdateScope()
|
||||
augroup END
|
||||
|
||||
" Define global variables and initialize current scope.
|
||||
function! s:InitMarkVariables()
|
||||
if !exists("g:mwHistAdd")
|
||||
let g:mwHistAdd = "/@"
|
||||
endif
|
||||
if !exists("g:mwCycleMax")
|
||||
let i = 1
|
||||
while hlexists("MarkWord" . i)
|
||||
let i = i + 1
|
||||
endwhile
|
||||
let g:mwCycleMax = i - 1
|
||||
endif
|
||||
if !exists("g:mwCycle")
|
||||
let g:mwCycle = 0
|
||||
endif
|
||||
if !exists("g:mwWord")
|
||||
let g:mwWord = repeat([''], g:mwCycleMax)
|
||||
endif
|
||||
if !exists("g:mwLastSearched")
|
||||
let g:mwLastSearched = ""
|
||||
endif
|
||||
endfunction
|
||||
call s:InitMarkVariables()
|
||||
call mark#UpdateScope()
|
||||
|
||||
" vim: ts=2 sw=2
|
||||
Reference in New Issue
Block a user