mirror of
https://github.com/SpaceVim/SpaceVim.git
synced 2025-02-03 18:00:05 +08:00
cd6ea298f2
* Add incsearch.vim into bundle dir * Fix java neoformat config close #3573 * Use echom instead in pull.vim
287 lines
7.9 KiB
VimL
287 lines
7.9 KiB
VimL
"=============================================================================
|
|
" FILE: autoload/incsearch/util.vim
|
|
" AUTHOR: haya14busa
|
|
" License: MIT license {{{
|
|
" Permission is hereby granted, free of charge, to any person obtaining
|
|
" a copy of this software and associated documentation files (the
|
|
" "Software"), to deal in the Software without restriction, including
|
|
" without limitation the rights to use, copy, modify, merge, publish,
|
|
" distribute, sublicense, and/or sell copies of the Software, and to
|
|
" permit persons to whom the Software is furnished to do so, subject to
|
|
" the following conditions:
|
|
"
|
|
" The above copyright notice and this permission notice shall be included
|
|
" in all copies or substantial portions of the Software.
|
|
"
|
|
" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
" OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
" IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
" CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
" TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
" SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
" }}}
|
|
"=============================================================================
|
|
scriptencoding utf-8
|
|
" Saving 'cpoptions' {{{
|
|
let s:save_cpo = &cpo
|
|
set cpo&vim
|
|
" }}}
|
|
|
|
let s:TRUE = !0
|
|
let s:FALSE = 0
|
|
|
|
" Public Utilities:
|
|
function! incsearch#util#deepextend(...) abort
|
|
return call(function('s:deepextend'), a:000)
|
|
endfunction
|
|
|
|
" Utilities:
|
|
|
|
function! incsearch#util#import() abort
|
|
let prefix = '<SNR>' . s:SID() . '_'
|
|
let module = {}
|
|
for func in s:functions
|
|
let module[func] = function(prefix . func)
|
|
endfor
|
|
return copy(module)
|
|
endfunction
|
|
|
|
function! s:SID() abort
|
|
return matchstr(expand('<sfile>'), '<SNR>\zs\d\+\ze_SID$')
|
|
endfunction
|
|
|
|
let s:functions = [
|
|
\ 'is_visual'
|
|
\ , 'get_max_col'
|
|
\ , 'is_pos_less_equal'
|
|
\ , 'is_pos_more_equal'
|
|
\ , 'sort_num'
|
|
\ , 'sort_pos'
|
|
\ , 'count_pattern'
|
|
\ , 'silent_feedkeys'
|
|
\ , 'deepextend'
|
|
\ , 'dictfunction'
|
|
\ , 'regexp_join'
|
|
\ ]
|
|
|
|
|
|
function! s:is_visual(mode) abort
|
|
return a:mode =~# "[vV\<C-v>]"
|
|
endfunction
|
|
|
|
" Return max column number of given line expression
|
|
" expr: similar to line(), col()
|
|
function! s:get_max_col(expr) abort
|
|
return strlen(getline(a:expr)) + 1
|
|
endfunction
|
|
|
|
" return (x <= y)
|
|
function! s:is_pos_less_equal(x, y) abort
|
|
return (a:x[0] == a:y[0]) ? a:x[1] <= a:y[1] : a:x[0] < a:y[0]
|
|
endfunction
|
|
|
|
" return (x > y)
|
|
function! s:is_pos_more_equal(x, y) abort
|
|
return ! s:is_pos_less_equal(a:x, a:y)
|
|
endfunction
|
|
|
|
" x < y -> -1
|
|
" x = y -> 0
|
|
" x > y -> 1
|
|
function! s:compare_pos(x, y) abort
|
|
return max([-1, min([1,(a:x[0] == a:y[0]) ? a:x[1] - a:y[1] : a:x[0] - a:y[0]])])
|
|
endfunction
|
|
|
|
function! s:sort_num(xs) abort
|
|
" 7.4.341
|
|
" http://ftp.vim.org/vim/patches/7.4/7.4.341
|
|
if v:version > 704 || v:version == 704 && has('patch341')
|
|
return sort(a:xs, 'n')
|
|
else
|
|
return sort(a:xs, 's:_sort_num_func')
|
|
endif
|
|
endfunction
|
|
|
|
function! s:_sort_num_func(x, y) abort
|
|
return a:x - a:y
|
|
endfunction
|
|
|
|
function! s:sort_pos(pos_list) abort
|
|
" pos_list: [ [x1, y1], [x2, y2] ]
|
|
return sort(a:pos_list, 's:compare_pos')
|
|
endfunction
|
|
|
|
" Return the number of matched patterns in the current buffer or the specified
|
|
" region with `from` and `to` positions
|
|
" parameter: pattern, from, to
|
|
function! s:count_pattern(pattern, ...) abort
|
|
let w = winsaveview()
|
|
let [from, to] = [
|
|
\ get(a:, 1, [1, 1]),
|
|
\ get(a:, 2, [line('$'), s:get_max_col('$')])
|
|
\ ]
|
|
let ignore_at_cursor_pos = get(a:, 3, 0)
|
|
" direction flag
|
|
let d_flag = s:compare_pos(from, to) > 0 ? 'b' : ''
|
|
call cursor(from)
|
|
let cnt = 0
|
|
let base_flag = d_flag . 'W'
|
|
try
|
|
" first: accept a match at the cursor position
|
|
let pos = searchpos(a:pattern, (ignore_at_cursor_pos ? '' : 'c' ) . base_flag)
|
|
while (pos != [0, 0] && s:compare_pos(pos, to) isnot# (d_flag is# 'b' ? -1 : 1))
|
|
let cnt += 1
|
|
let pos = searchpos(a:pattern, base_flag)
|
|
endwhile
|
|
finally
|
|
call winrestview(w)
|
|
endtry
|
|
return cnt
|
|
endfunction
|
|
|
|
" NOTE: support vmap?
|
|
" It doesn't handle feedkeys() on incsert or command-line mode
|
|
function! s:silent_feedkeys(expr, name, ...) abort
|
|
" Ref:
|
|
" https://github.com/osyo-manga/vim-over/blob/d51b028c29661d4a5f5b79438ad6d69266753711/autoload/over.vim#L6
|
|
let mode = get(a:, 1, 'm')
|
|
let name = 'incsearch-' . a:name
|
|
let map = printf('<Plug>(%s)', name)
|
|
if mode ==# 'n'
|
|
let command = 'nnoremap'
|
|
else
|
|
let command = 'nmap'
|
|
endif
|
|
execute command '<silent>' map printf('%s:nunmap %s<CR>', a:expr, map)
|
|
if mode(1) !=# 'ce'
|
|
" FIXME: mode(1) !=# 'ce' exists only for the test
|
|
" :h feedkeys() doesn't work while runnning a test script
|
|
" https://github.com/kana/vim-vspec/issues/27
|
|
call feedkeys(printf("\<Plug>(%s)", name))
|
|
endif
|
|
endfunction
|
|
|
|
" deepextend (nest: 1)
|
|
function! s:deepextend(expr1, expr2) abort
|
|
let expr2 = copy(a:expr2)
|
|
for [k, V] in items(a:expr1)
|
|
if (type(V) is type({}) || type(V) is type([])) && has_key(expr2, k)
|
|
let a:expr1[k] = extend(a:expr1[k], expr2[k])
|
|
unlet expr2[k]
|
|
endif
|
|
unlet V
|
|
endfor
|
|
return extend(a:expr1, expr2)
|
|
endfunction
|
|
|
|
let s:funcmanage = {}
|
|
function! s:funcmanage() abort
|
|
return s:funcmanage
|
|
endfunction
|
|
|
|
function! s:dictfunction(dictfunc, dict) abort
|
|
if has('patch-7.4.1842')
|
|
let funcname = '_' . get(a:dictfunc, 'name')
|
|
else
|
|
let funcname = '_' . matchstr(string(a:dictfunc), '\d\+')
|
|
endif
|
|
let s:funcmanage[funcname] = {
|
|
\ 'func': a:dictfunc,
|
|
\ 'dict': a:dict
|
|
\ }
|
|
let prefix = '<SNR>' . s:SID() . '_'
|
|
let fm = printf("%sfuncmanage()['%s']", prefix, funcname)
|
|
execute join([
|
|
\ printf('function! s:%s(...) abort', funcname),
|
|
\ printf(" return call(%s['func'], a:000, %s['dict'])", fm, fm),
|
|
\ 'endfunction'
|
|
\ ], "\n")
|
|
return function(printf('%s%s', prefix, funcname))
|
|
endfunction
|
|
|
|
|
|
"--- regexp
|
|
|
|
let s:escaped_backslash = '\m\%(^\|[^\\]\)\%(\\\\\)*\zs'
|
|
|
|
function! s:regexp_join(ps) abort
|
|
let rs = map(filter(copy(a:ps), 's:_is_valid_regexp(v:val)'), 's:escape_unbalanced_left_r(v:val)')
|
|
return printf('\m\%%(%s\m\)', join(rs, '\m\|'))
|
|
endfunction
|
|
|
|
function! s:_is_valid_regexp(pattern) abort
|
|
try
|
|
if '' =~# a:pattern
|
|
endif
|
|
return s:TRUE
|
|
catch
|
|
return s:FALSE
|
|
endtry
|
|
endfunction
|
|
|
|
" \m,\v: [ -> \[
|
|
" \M,\V: \[ -> [
|
|
function! s:escape_unbalanced_left_r(pattern) abort
|
|
let rs = []
|
|
let cs = split(a:pattern, '\zs')
|
|
" escape backslash (\, \\\, \\\\\, ...)
|
|
let escape_bs = s:FALSE
|
|
let flag = &magic ? 'm' : 'M'
|
|
let i = 0
|
|
while i < len(cs)
|
|
let c = cs[i]
|
|
" characters to add to rs
|
|
let addcs = [c]
|
|
if escape_bs && s:_is_flag(c)
|
|
let flag = c
|
|
elseif c is# '[' && s:_may_replace_left_r_cond(escape_bs, flag)
|
|
let idx = s:_find_right_r(cs, i)
|
|
if idx is# -1
|
|
if s:_is_flag(flag, 'MV')
|
|
" Remove `\` before unbalanced `[`
|
|
let rs = rs[:-2]
|
|
else
|
|
" Escape unbalanced `[`
|
|
let addcs = ['\' . c]
|
|
endif
|
|
else
|
|
let addcs = cs[(i):(i+idx)]
|
|
let i += idx
|
|
endif
|
|
endif
|
|
let escape_bs = (escape_bs || c isnot# '\') ? s:FALSE : s:TRUE
|
|
let rs += addcs
|
|
let i += 1
|
|
endwhile
|
|
return join(rs, '')
|
|
endfunction
|
|
|
|
" @ return boolean
|
|
function! s:_is_flag(flag, ...) abort
|
|
let chars = get(a:, 1, 'mMvV')
|
|
return a:flag =~# printf('\m[%s]', chars)
|
|
endfunction
|
|
|
|
" @ return boolean
|
|
function! s:_may_replace_left_r_cond(escape_bs, flag) abort
|
|
return (a:escape_bs && s:_is_flag(a:flag, 'MV')) || (!a:escape_bs && s:_is_flag(a:flag, 'mv'))
|
|
endfunction
|
|
|
|
" @return index
|
|
function! s:_find_right_r(cs, i) abort
|
|
return match(join(a:cs[(a:i+1):], ''), s:escaped_backslash . ']')
|
|
endfunction
|
|
|
|
"--- end of regexp
|
|
|
|
|
|
" Restore 'cpoptions' {{{
|
|
let &cpo = s:save_cpo
|
|
unlet s:save_cpo
|
|
" }}}
|
|
" __END__ {{{
|
|
" vim: expandtab softtabstop=2 shiftwidth=2
|
|
" vim: foldmethod=marker
|
|
" }}}
|