Regenerate nvim config
This commit is contained in:
@ -0,0 +1,60 @@
|
||||
" clock object - measuring elapsed time in a operation
|
||||
|
||||
" variables "{{{
|
||||
" features
|
||||
let s:has_reltime_and_float = has('reltime') && has('float')
|
||||
"}}}
|
||||
|
||||
function! sandwich#clock#new() abort "{{{
|
||||
return deepcopy(s:clock)
|
||||
endfunction
|
||||
"}}}
|
||||
|
||||
" s:clock "{{{
|
||||
let s:clock = {
|
||||
\ 'started' : 0,
|
||||
\ 'paused' : 0,
|
||||
\ 'zerotime': reltime(),
|
||||
\ 'stoptime': reltime(),
|
||||
\ 'losstime': 0,
|
||||
\ }
|
||||
"}}}
|
||||
function! s:clock.start() dict abort "{{{
|
||||
if self.started
|
||||
if self.paused
|
||||
let self.losstime += str2float(reltimestr(reltime(self.stoptime)))
|
||||
let self.paused = 0
|
||||
endif
|
||||
else
|
||||
if s:has_reltime_and_float
|
||||
let self.zerotime = reltime()
|
||||
let self.started = 1
|
||||
endif
|
||||
endif
|
||||
endfunction
|
||||
"}}}
|
||||
function! s:clock.pause() dict abort "{{{
|
||||
let self.stoptime = reltime()
|
||||
let self.paused = 1
|
||||
endfunction
|
||||
"}}}
|
||||
function! s:clock.elapsed() dict abort "{{{
|
||||
if self.started
|
||||
let total = str2float(reltimestr(reltime(self.zerotime)))
|
||||
return floor((total - self.losstime)*1000)
|
||||
else
|
||||
return 0
|
||||
endif
|
||||
endfunction
|
||||
"}}}
|
||||
function! s:clock.stop() dict abort "{{{
|
||||
let self.started = 0
|
||||
let self.paused = 0
|
||||
let self.losstime = 0
|
||||
endfunction
|
||||
"}}}
|
||||
|
||||
|
||||
" vim:set foldmethod=marker:
|
||||
" vim:set commentstring="%s:
|
||||
" vim:set ts=2 sts=2 sw=2:
|
||||
@ -0,0 +1,42 @@
|
||||
" constants - storing essential constants
|
||||
|
||||
" variables "{{{
|
||||
" types
|
||||
let s:type_list = type([])
|
||||
"}}}
|
||||
|
||||
function! sandwich#constants#get(name) abort "{{{
|
||||
return type(a:name) == s:type_list
|
||||
\ ? map(copy(a:name), 's:constants[v:val]()')
|
||||
\ : s:constants[a:name]()
|
||||
endfunction
|
||||
"}}}
|
||||
|
||||
" s:constants "{{{
|
||||
let s:constants = {}
|
||||
"}}}
|
||||
" The maximum number of columns "{{{
|
||||
function! s:constants.colmax() dict abort
|
||||
return s:colmax_obtained ? s:colmax : s:colmax()
|
||||
endfunction
|
||||
|
||||
let s:colmax = 2147483647 " default value in many cases
|
||||
let s:colmax_obtained = 0
|
||||
function! s:colmax() abort
|
||||
let view = winsaveview()
|
||||
try
|
||||
normal! $
|
||||
let colmax = winsaveview().curswant
|
||||
call winrestview(view)
|
||||
let s:colmax_obtained = 1
|
||||
catch
|
||||
let colmax = s:colmax
|
||||
let s:colmax_obtained = 0
|
||||
endtry
|
||||
return colmax
|
||||
endfunction
|
||||
"}}}
|
||||
|
||||
" vim:set foldmethod=marker:
|
||||
" vim:set commentstring="%s:
|
||||
" vim:set ts=2 sts=2 sw=2:
|
||||
@ -0,0 +1,34 @@
|
||||
let g:sandwich#filetype#tex#environments = get(g:, 'sandwich#filetype#tex#environments', [
|
||||
\ 'array', 'center', 'description', 'enumerate', 'eqnarray', 'equation',
|
||||
\ 'equation*', 'figure', 'flushleft', 'flushright', 'itemize', 'list',
|
||||
\ 'minipage', 'picture', 'quotation', 'quote', 'tabbing', 'table',
|
||||
\ 'tabular', 'tabular*', 'thebibliography', 'theorem', 'titlepage',
|
||||
\ 'verbatim', 'verse'
|
||||
\ ])
|
||||
|
||||
function! sandwich#filetype#tex#EnvCompl(argread, cmdline, cursorpos) abort
|
||||
let n = strlen(a:argread)
|
||||
if exists('b:sandwich#filetype#tex#environments')
|
||||
let list = copy(b:sandwich#filetype#tex#environments)
|
||||
else
|
||||
let list = copy(g:sandwich#filetype#tex#environments)
|
||||
endif
|
||||
if n > 0
|
||||
let list = filter(list, 'v:val[: n-1] ==# a:argread')
|
||||
endif
|
||||
return list
|
||||
endfunction
|
||||
|
||||
function! sandwich#filetype#tex#EnvInput() abort
|
||||
echohl MoreMsg
|
||||
let env = input('Environment-name: ', '', 'customlist,sandwich#filetype#tex#EnvCompl')
|
||||
echohl NONE
|
||||
return [printf('\begin{%s}', env), printf('\end{%s}', env)]
|
||||
endfunction
|
||||
|
||||
function! sandwich#filetype#tex#CmdInput() abort
|
||||
echohl MoreMsg
|
||||
let cmd = input('Command: ', '')
|
||||
echohl NONE
|
||||
return [printf('\%s{', cmd), '}']
|
||||
endfunction
|
||||
@ -0,0 +1,514 @@
|
||||
" highlight object - managing highlight on a buffer
|
||||
|
||||
" variables "{{{
|
||||
" null valiables
|
||||
let s:null_pos = [0, 0, 0, 0]
|
||||
|
||||
" types
|
||||
let s:type_list = type([])
|
||||
|
||||
" patchs
|
||||
if v:version > 704 || (v:version == 704 && has('patch237'))
|
||||
let s:has_patch_7_4_362 = has('patch-7.4.362')
|
||||
let s:has_patch_7_4_392 = has('patch-7.4.392')
|
||||
else
|
||||
let s:has_patch_7_4_362 = v:version == 704 && has('patch362')
|
||||
let s:has_patch_7_4_392 = v:version == 704 && has('patch392')
|
||||
endif
|
||||
|
||||
" features
|
||||
let s:has_gui_running = has('gui_running')
|
||||
let s:has_window_ID = exists('*win_getid')
|
||||
|
||||
" SID
|
||||
function! s:SID() abort
|
||||
return matchstr(expand('<sfile>'), '<SNR>\zs\d\+\ze_SID$')
|
||||
endfunction
|
||||
let s:SID = printf("\<SNR>%s_", s:SID())
|
||||
delfunction s:SID
|
||||
"}}}
|
||||
|
||||
function! sandwich#highlight#new() abort "{{{
|
||||
return deepcopy(s:highlight)
|
||||
endfunction
|
||||
"}}}
|
||||
|
||||
" s:highlight "{{{
|
||||
let s:highlight = {
|
||||
\ 'status': 0,
|
||||
\ 'group' : '',
|
||||
\ 'id' : [],
|
||||
\ 'order_list': [],
|
||||
\ 'region': {},
|
||||
\ 'linewise': 0,
|
||||
\ 'bufnr': 0,
|
||||
\ 'winid': 0,
|
||||
\ }
|
||||
"}}}
|
||||
function! s:highlight.initialize() dict abort "{{{
|
||||
call self.quench()
|
||||
let self.status = 0
|
||||
let self.group = ''
|
||||
let self.id = []
|
||||
let self.order_list = []
|
||||
let self.region = {}
|
||||
let self.linewise = 0
|
||||
let self.bufnr = 0
|
||||
let self.winid = 0
|
||||
endfunction
|
||||
"}}}
|
||||
function! s:highlight.order(target, linewise) dict abort "{{{
|
||||
let order = []
|
||||
let order_list = []
|
||||
for [head, tail, linewise] in [[a:target.head1, a:target.tail1, a:linewise[0]],
|
||||
\ [a:target.head2, a:target.tail2, a:linewise[1]]]
|
||||
if linewise
|
||||
call s:highlight_order_linewise(order_list, order, head, tail)
|
||||
else
|
||||
call s:highlight_order_charwise(order_list, order, head, tail)
|
||||
endif
|
||||
endfor
|
||||
if order != []
|
||||
call add(order_list, order)
|
||||
endif
|
||||
let self.order_list += order_list
|
||||
let self.region = deepcopy(a:target)
|
||||
let self.linewise = a:linewise
|
||||
endfunction
|
||||
"}}}
|
||||
function! s:highlight.show(...) dict abort "{{{
|
||||
if self.order_list == []
|
||||
return 0
|
||||
endif
|
||||
|
||||
if a:0 < 1
|
||||
if self.group ==# ''
|
||||
return 0
|
||||
else
|
||||
let hi_group = self.group
|
||||
endif
|
||||
else
|
||||
let hi_group = a:1
|
||||
endif
|
||||
|
||||
if self.status
|
||||
if hi_group ==# self.group
|
||||
return 0
|
||||
else
|
||||
call self.quench()
|
||||
endif
|
||||
endif
|
||||
|
||||
for order in self.order_list
|
||||
let self.id += s:matchaddpos(hi_group, order)
|
||||
endfor
|
||||
call filter(self.id, 'v:val > 0')
|
||||
let self.status = 1
|
||||
let self.group = hi_group
|
||||
let self.bufnr = bufnr('%')
|
||||
if s:has_window_ID
|
||||
let self.winid = win_getid()
|
||||
endif
|
||||
return 1
|
||||
endfunction
|
||||
"}}}
|
||||
function! s:highlight.quench() dict abort "{{{
|
||||
if !self.status
|
||||
return 0
|
||||
endif
|
||||
|
||||
let tabnr = tabpagenr()
|
||||
let winnr = winnr()
|
||||
let view = winsaveview()
|
||||
if self.highlighted_window()
|
||||
call s:matchdelete_all(self.id)
|
||||
let self.status = 0
|
||||
return 1
|
||||
endif
|
||||
|
||||
if s:is_in_cmdline_window() || s:is_in_popup_terminal_window()
|
||||
let s:paused += [self]
|
||||
augroup sandwich-pause-quenching
|
||||
autocmd!
|
||||
autocmd WinEnter * call s:got_out_of_cmdwindow()
|
||||
augroup END
|
||||
return 0
|
||||
endif
|
||||
|
||||
if self.goto_highlighted_window()
|
||||
call s:matchdelete_all(self.id)
|
||||
else
|
||||
call filter(self.id, 0)
|
||||
endif
|
||||
let self.status = 0
|
||||
call s:goto_window(winnr, tabnr, view)
|
||||
return 1
|
||||
endfunction
|
||||
"}}}
|
||||
function! s:highlight.quench_timer(time) dict abort "{{{
|
||||
let id = timer_start(a:time, s:SID . 'quench')
|
||||
let s:quench_table[string(id)] = self
|
||||
" this is called when user gets control again
|
||||
call timer_start(1, {-> s:set_autocmds(id)})
|
||||
return id
|
||||
endfunction
|
||||
"}}}
|
||||
" function! s:highlight.highlighted_window() dict abort "{{{
|
||||
if s:has_window_ID
|
||||
function! s:highlight.highlighted_window() dict abort
|
||||
return self.winid == win_getid()
|
||||
endfunction
|
||||
else
|
||||
function! s:highlight.highlighted_window() dict abort
|
||||
if self.id == []
|
||||
return 0
|
||||
endif
|
||||
|
||||
let id = self.id[0]
|
||||
return filter(getmatches(), 'v:val.id == id') != [] ? 1 : 0
|
||||
endfunction
|
||||
endif
|
||||
"}}}
|
||||
" function! s:highlight.goto_highlighted_window() dict abort "{{{
|
||||
if s:has_window_ID
|
||||
function! s:highlight.goto_highlighted_window() dict abort
|
||||
noautocmd let reached = win_gotoid(self.winid)
|
||||
return reached
|
||||
endfunction
|
||||
else
|
||||
function! s:highlight.goto_highlighted_window() dict abort
|
||||
return s:search_highlighted_windows(self.id, tabpagenr()) != [0, 0]
|
||||
endfunction
|
||||
endif
|
||||
"}}}
|
||||
|
||||
" for delayed quenching "{{{
|
||||
let s:quench_table = {}
|
||||
let s:paused = []
|
||||
function! s:quench(id) abort "{{{
|
||||
let options = s:shift_options()
|
||||
let highlight = s:get(a:id)
|
||||
try
|
||||
if highlight != {}
|
||||
call highlight.quench()
|
||||
endif
|
||||
catch /^Vim\%((\a\+)\)\=:E523/
|
||||
" NOTE: For "textlock"
|
||||
if highlight != {}
|
||||
call highlight.quench_timer(50)
|
||||
endif
|
||||
return 1
|
||||
finally
|
||||
unlet s:quench_table[a:id]
|
||||
call timer_stop(a:id)
|
||||
call s:clear_autocmds()
|
||||
call s:restore_options(options)
|
||||
endtry
|
||||
endfunction
|
||||
"}}}
|
||||
function! s:get(id) abort "{{{
|
||||
return get(s:quench_table, string(a:id), {})
|
||||
endfunction
|
||||
"}}}
|
||||
function! sandwich#highlight#cancel(...) abort "{{{
|
||||
if a:0 > 0
|
||||
let id_list = type(a:1) == s:type_list ? a:1 : a:000
|
||||
else
|
||||
let id_list = map(keys(s:quench_table), 'str2nr(v:val)')
|
||||
endif
|
||||
|
||||
for id in id_list
|
||||
call s:quench(id)
|
||||
endfor
|
||||
endfunction
|
||||
"}}}
|
||||
function! s:quench_paused(...) abort "{{{
|
||||
if s:is_in_cmdline_window() || s:is_in_popup_terminal_window()
|
||||
return
|
||||
endif
|
||||
|
||||
augroup sandwich-pause-quenching
|
||||
autocmd!
|
||||
augroup END
|
||||
|
||||
for highlight in s:paused
|
||||
call highlight.quench()
|
||||
endfor
|
||||
let s:paused = []
|
||||
endfunction
|
||||
"}}}
|
||||
function! s:got_out_of_cmdwindow() abort "{{{
|
||||
augroup sandwich-pause-quenching
|
||||
autocmd!
|
||||
autocmd CursorMoved * call s:quench_paused()
|
||||
augroup END
|
||||
endfunction
|
||||
"}}}
|
||||
function! s:set_autocmds(id) abort "{{{
|
||||
augroup sandwich-highlight
|
||||
autocmd!
|
||||
execute printf('autocmd TextChanged,InsertEnter,BufUnload <buffer> call s:cancel_highlight(%s)', a:id)
|
||||
execute printf('autocmd BufEnter * call s:switch_highlight(%s)', a:id)
|
||||
augroup END
|
||||
endfunction
|
||||
"}}}
|
||||
function! s:clear_autocmds() abort "{{{
|
||||
augroup sandwich-highlight
|
||||
autocmd!
|
||||
augroup END
|
||||
endfunction
|
||||
"}}}
|
||||
function! s:cancel_highlight(id) abort "{{{
|
||||
call s:quench(a:id)
|
||||
endfunction
|
||||
"}}}
|
||||
function! s:switch_highlight(id) abort "{{{
|
||||
let highlight = s:get(a:id)
|
||||
if highlight == {} || !highlight.highlighted_window()
|
||||
return
|
||||
endif
|
||||
|
||||
if highlight.bufnr == bufnr('%')
|
||||
call highlight.show()
|
||||
else
|
||||
call highlight.quench()
|
||||
endif
|
||||
endfunction
|
||||
"}}}
|
||||
"}}}
|
||||
|
||||
" private functions
|
||||
function! s:highlight_order_charwise(order_list, order, head, tail) abort "{{{
|
||||
let n = len(a:order)
|
||||
if a:head != s:null_pos && a:tail != s:null_pos && s:is_equal_or_ahead(a:tail, a:head)
|
||||
if a:head[1] == a:tail[1]
|
||||
call add(a:order, a:head[1:2] + [a:tail[2] - a:head[2] + 1])
|
||||
let n += 1
|
||||
else
|
||||
for lnum in range(a:head[1], a:tail[1])
|
||||
if lnum == a:head[1]
|
||||
call add(a:order, a:head[1:2] + [col([a:head[1], '$']) - a:head[2] + 1])
|
||||
elseif lnum == a:tail[1]
|
||||
call add(a:order, [a:tail[1], 1] + [a:tail[2]])
|
||||
else
|
||||
call add(a:order, [lnum])
|
||||
endif
|
||||
|
||||
if n == 7
|
||||
call add(a:order_list, deepcopy(a:order))
|
||||
call filter(a:order, 0)
|
||||
let n = 0
|
||||
else
|
||||
let n += 1
|
||||
endif
|
||||
endfor
|
||||
endif
|
||||
endif
|
||||
endfunction
|
||||
"}}}
|
||||
function! s:highlight_order_linewise(order_list, order, head, tail) abort "{{{
|
||||
let n = len(a:order)
|
||||
if a:head != s:null_pos && a:tail != s:null_pos && a:head[1] <= a:tail[1]
|
||||
for lnum in range(a:head[1], a:tail[1])
|
||||
call add(a:order, [lnum])
|
||||
if n == 7
|
||||
call add(a:order_list, deepcopy(a:order))
|
||||
call filter(a:order, 0)
|
||||
let n = 0
|
||||
else
|
||||
let n += 1
|
||||
endif
|
||||
endfor
|
||||
endif
|
||||
endfunction
|
||||
"}}}
|
||||
" function! s:matchaddpos(group, pos) abort "{{{
|
||||
if s:has_patch_7_4_362
|
||||
function! s:matchaddpos(group, pos) abort
|
||||
return [matchaddpos(a:group, a:pos)]
|
||||
endfunction
|
||||
else
|
||||
function! s:matchaddpos(group, pos) abort
|
||||
let id_list = []
|
||||
for pos in a:pos
|
||||
if len(pos) == 1
|
||||
let id_list += [matchadd(a:group, printf('\%%%dl', pos[0]))]
|
||||
else
|
||||
let id_list += [matchadd(a:group, printf('\%%%dl\%%>%dc.*\%%<%dc', pos[0], pos[1]-1, pos[1]+pos[2]))]
|
||||
endif
|
||||
endfor
|
||||
return id_list
|
||||
endfunction
|
||||
endif
|
||||
"}}}
|
||||
function! s:matchdelete_all(ids) abort "{{{
|
||||
if empty(a:ids)
|
||||
return
|
||||
endif
|
||||
|
||||
let alive_ids = map(getmatches(), 'v:val.id')
|
||||
" Return if another plugin called clearmatches() which clears *ALL*
|
||||
" highlights including others set.
|
||||
if empty(alive_ids)
|
||||
return
|
||||
endif
|
||||
if !count(alive_ids, a:ids[0])
|
||||
return
|
||||
endif
|
||||
|
||||
for id in a:ids
|
||||
try
|
||||
call matchdelete(id)
|
||||
catch
|
||||
endtry
|
||||
endfor
|
||||
call filter(a:ids, 0)
|
||||
endfunction
|
||||
"}}}
|
||||
function! s:is_ahead(pos1, pos2) abort "{{{
|
||||
return a:pos1[1] > a:pos2[1] || (a:pos1[1] == a:pos2[1] && a:pos1[2] > a:pos2[2])
|
||||
endfunction
|
||||
"}}}
|
||||
function! s:is_equal_or_ahead(pos1, pos2) abort "{{{
|
||||
return a:pos1[1] > a:pos2[1] || (a:pos1[1] == a:pos2[1] && a:pos1[2] >= a:pos2[2])
|
||||
endfunction
|
||||
"}}}
|
||||
" function! s:is_in_cmdline_window() abort "{{{
|
||||
if s:has_patch_7_4_392
|
||||
function! s:is_in_cmdline_window() abort
|
||||
return getcmdwintype() !=# ''
|
||||
endfunction
|
||||
else
|
||||
function! s:is_in_cmdline_window() abort
|
||||
let is_in_cmdline_window = 0
|
||||
try
|
||||
execute 'tabnext ' . tabpagenr()
|
||||
catch /^Vim\%((\a\+)\)\=:E11/
|
||||
let is_in_cmdline_window = 1
|
||||
catch
|
||||
finally
|
||||
return is_in_cmdline_window
|
||||
endtry
|
||||
endfunction
|
||||
endif
|
||||
"}}}
|
||||
" function! s:is_in_popup_terminal_window() abort "{{{
|
||||
if exists('*popup_list')
|
||||
function! s:is_in_popup_terminal_window() abort
|
||||
return &buftype is# 'terminal' && count(popup_list(), win_getid())
|
||||
endfunction
|
||||
else
|
||||
function! s:is_in_popup_terminal_window() abort
|
||||
return 0
|
||||
endfunction
|
||||
endif
|
||||
" }}}
|
||||
function! s:shift_options() abort "{{{
|
||||
let options = {}
|
||||
|
||||
""" tweak appearance
|
||||
" hide_cursor
|
||||
if s:has_gui_running
|
||||
let options.cursor = &guicursor
|
||||
set guicursor+=a:block-NONE
|
||||
else
|
||||
let options.cursor = &t_ve
|
||||
set t_ve=
|
||||
endif
|
||||
|
||||
return options
|
||||
endfunction
|
||||
"}}}
|
||||
function! s:restore_options(options) abort "{{{
|
||||
if s:has_gui_running
|
||||
set guicursor&
|
||||
let &guicursor = a:options.cursor
|
||||
else
|
||||
let &t_ve = a:options.cursor
|
||||
endif
|
||||
endfunction
|
||||
"}}}
|
||||
function! s:search_highlighted_windows(id, ...) abort "{{{
|
||||
if a:id == []
|
||||
return 0
|
||||
endif
|
||||
|
||||
let original_winnr = winnr()
|
||||
let original_tabnr = tabpagenr()
|
||||
let original_view = winsaveview()
|
||||
let tablist = range(1, tabpagenr('$'))
|
||||
if a:0 > 0
|
||||
let tabnr = a:1
|
||||
let [tabnr, winnr] = s:scan_windows(a:id, tabnr)
|
||||
if tabnr != 0
|
||||
return [tabnr, winnr]
|
||||
endif
|
||||
call filter(tablist, 'v:val != tabnr')
|
||||
endif
|
||||
|
||||
for tabnr in tablist
|
||||
let [tabnr, winnr] = s:scan_windows(a:id, tabnr)
|
||||
if tabnr != 0
|
||||
return [tabnr, winnr]
|
||||
endif
|
||||
endfor
|
||||
call s:goto_window(original_winnr, original_tabnr, original_view)
|
||||
return [0, 0]
|
||||
endfunction
|
||||
"}}}
|
||||
function! s:scan_windows(id, tabnr) abort "{{{
|
||||
if s:goto_tab(a:tabnr)
|
||||
for winnr in range(1, winnr('$'))
|
||||
if s:goto_window(winnr) && s:is_highlighted_window(a:id)
|
||||
return [a:tabnr, winnr]
|
||||
endif
|
||||
endfor
|
||||
endif
|
||||
return [0, 0]
|
||||
endfunction
|
||||
"}}}
|
||||
function! s:is_highlighted_window(id) abort "{{{
|
||||
if a:id != []
|
||||
let id = a:id[0]
|
||||
if filter(getmatches(), 'v:val.id == id') != []
|
||||
return 1
|
||||
endif
|
||||
endif
|
||||
return 0
|
||||
endfunction
|
||||
"}}}
|
||||
function! s:goto_window(winnr, ...) abort "{{{
|
||||
if a:0 > 0
|
||||
if !s:goto_tab(a:1)
|
||||
return 0
|
||||
endif
|
||||
endif
|
||||
|
||||
|
||||
try
|
||||
if a:winnr != winnr()
|
||||
execute printf('noautocmd %swincmd w', a:winnr)
|
||||
endif
|
||||
catch /^Vim\%((\a\+)\)\=:E16/
|
||||
return 0
|
||||
endtry
|
||||
|
||||
if a:0 > 1
|
||||
noautocmd call winrestview(a:2)
|
||||
endif
|
||||
|
||||
return 1
|
||||
endfunction
|
||||
"}}}
|
||||
function! s:goto_tab(tabnr) abort "{{{
|
||||
if a:tabnr != tabpagenr()
|
||||
execute 'noautocmd tabnext ' . a:tabnr
|
||||
endif
|
||||
return tabpagenr() == a:tabnr ? 1 : 0
|
||||
endfunction
|
||||
"}}}
|
||||
|
||||
|
||||
" vim:set foldmethod=marker:
|
||||
" vim:set commentstring="%s:
|
||||
" vim:set ts=2 sts=2 sw=2:
|
||||
@ -0,0 +1,438 @@
|
||||
let s:save_cpo = &cpo
|
||||
set cpo&vim
|
||||
|
||||
" variables "{{{
|
||||
let s:FALSE = 0
|
||||
let s:TRUE = 1
|
||||
let s:null_pos = [0, 0]
|
||||
|
||||
" patchs
|
||||
if v:version > 704 || (v:version == 704 && has('patch237'))
|
||||
let s:has_patch_7_4_1685 = has('patch-7.4.1685')
|
||||
let s:has_patch_7_4_2011 = has('patch-7.4.2011')
|
||||
else
|
||||
let s:has_patch_7_4_1685 = v:version == 704 && has('patch1685')
|
||||
let s:has_patch_7_4_2011 = v:version == 704 && has('patch2011')
|
||||
endif
|
||||
"}}}
|
||||
|
||||
" default patterns
|
||||
let g:sandwich#magicchar#f#default_patterns = [
|
||||
\ {
|
||||
\ 'header' : '\<\h\k*',
|
||||
\ 'bra' : '(',
|
||||
\ 'ket' : ')',
|
||||
\ 'footer' : '',
|
||||
\ },
|
||||
\ ]
|
||||
|
||||
function! sandwich#magicchar#f#fname() abort "{{{
|
||||
call operator#sandwich#show()
|
||||
try
|
||||
echohl MoreMsg
|
||||
if &filetype ==# 'vim'
|
||||
let funcname = input('funcname: ', '', 'custom,sandwich#magicchar#f#fnamecompl_vim')
|
||||
else
|
||||
let funcname = input('funcname: ', '', 'custom,sandwich#magicchar#f#fnamecompl')
|
||||
endif
|
||||
" flash prompt
|
||||
echo ''
|
||||
finally
|
||||
echohl NONE
|
||||
call operator#sandwich#quench()
|
||||
endtry
|
||||
if funcname ==# ''
|
||||
throw 'OperatorSandwichCancel'
|
||||
endif
|
||||
return funcname . '('
|
||||
endfunction
|
||||
"}}}
|
||||
function! sandwich#magicchar#f#fnamecompl(ArgLead, CmdLine, CursorPos) abort "{{{
|
||||
return join(uniq(sort(s:buffer_completion())), "\n")
|
||||
endfunction
|
||||
"}}}
|
||||
function! sandwich#magicchar#f#fnamecompl_vim(ArgLead, CmdLine, CursorPos) abort "{{{
|
||||
if s:has_patch_7_4_2011
|
||||
let getcomp = map(filter(getcompletion(a:ArgLead, 'function'), 'v:val =~# ''\C^[a-z][a-zA-Z0-9_]*($'''), 'matchstr(v:val, ''\C^[a-z][a-zA-Z0-9_]*'')')
|
||||
else
|
||||
let getcomp = []
|
||||
endif
|
||||
let buffer = s:buffer_completion()
|
||||
return join(uniq(sort(getcomp + buffer)), "\n")
|
||||
endfunction
|
||||
"}}}
|
||||
function! s:buffer_completion() abort "{{{
|
||||
" NOTE: This func does neither sort nor uniq.
|
||||
let list = []
|
||||
let lines = getline(1, '$')
|
||||
let pattern_list = s:resolve_patterns()
|
||||
for func in pattern_list
|
||||
let pat = printf('%s\ze%s', func.header, func.bra)
|
||||
for line in lines
|
||||
let list += s:extract_pattern(line, pat)
|
||||
endfor
|
||||
endfor
|
||||
return list
|
||||
endfunction
|
||||
"}}}
|
||||
function! s:extract_pattern(string, pat) abort "{{{
|
||||
let list = []
|
||||
let end = 0
|
||||
while 1
|
||||
let [str, start, end] = s:matchstrpos(a:string, a:pat, end)
|
||||
if start < 0
|
||||
break
|
||||
endif
|
||||
let list += [str]
|
||||
endwhile
|
||||
return list
|
||||
endfunction
|
||||
"}}}
|
||||
" function! s:matchstrpos(expr, pat, ...) abort "{{{
|
||||
if s:has_patch_7_4_1685
|
||||
let s:matchstrpos = function('matchstrpos')
|
||||
else
|
||||
function! s:matchstrpos(expr, pat, ...) abort
|
||||
if a:0 == 0
|
||||
return [matchstr(a:expr, a:pat), match(a:expr, a:pat), matchend(a:expr, a:pat)]
|
||||
elseif a:0 == 1
|
||||
return [matchstr(a:expr, a:pat, a:1), match(a:expr, a:pat, a:1), matchend(a:expr, a:pat, a:1)]
|
||||
else
|
||||
return [matchstr(a:expr, a:pat, a:1, a:2), match(a:expr, a:pat, a:1, a:2), matchend(a:expr, a:pat, a:1, a:2)]
|
||||
endif
|
||||
endfunction
|
||||
endif
|
||||
"}}}
|
||||
|
||||
|
||||
|
||||
" textobj-functioncall (bundle version)
|
||||
" NOTE: https://github.com/machakann/vim-textobj-functioncall
|
||||
|
||||
function! sandwich#magicchar#f#i(mode) abort "{{{
|
||||
call sandwich#magicchar#f#textobj('i', a:mode)
|
||||
endfunction
|
||||
"}}}
|
||||
function! sandwich#magicchar#f#a(mode) abort "{{{
|
||||
call sandwich#magicchar#f#textobj('a', a:mode)
|
||||
endfunction
|
||||
"}}}
|
||||
function! sandwich#magicchar#f#ip(mode) abort "{{{
|
||||
call sandwich#magicchar#f#textobj('ip', a:mode)
|
||||
endfunction
|
||||
"}}}
|
||||
function! sandwich#magicchar#f#ap(mode) abort "{{{
|
||||
call sandwich#magicchar#f#textobj('ap', a:mode)
|
||||
endfunction
|
||||
"}}}
|
||||
function! sandwich#magicchar#f#textobj(kind, mode, ...) abort "{{{
|
||||
let l:count = v:count1
|
||||
if a:0
|
||||
let pattern_list = a:1
|
||||
else
|
||||
let pattern_list = s:resolve_patterns()
|
||||
endif
|
||||
let searchlines = s:get('textobj_sandwich_function_searchlines' , 30)
|
||||
let stopline = {}
|
||||
if searchlines < 0
|
||||
let stopline.upper = 1
|
||||
let stopline.lower = line('$')
|
||||
else
|
||||
let stopline.upper = max([1, line('.') - searchlines])
|
||||
let stopline.lower = min([line('.') + searchlines, line('$')])
|
||||
endif
|
||||
|
||||
let [start, end] = [s:null_pos, s:null_pos]
|
||||
let view = winsaveview()
|
||||
try
|
||||
let candidates = s:gather_candidates(a:kind, a:mode, l:count, pattern_list, stopline)
|
||||
let elected = s:elect(candidates, l:count)
|
||||
if elected != {}
|
||||
let [start, end] = s:to_range(a:kind, elected)
|
||||
endif
|
||||
finally
|
||||
call winrestview(view)
|
||||
endtry
|
||||
call s:select(start, end)
|
||||
endfunction
|
||||
"}}}
|
||||
|
||||
|
||||
function! s:Candidate(head, bra, ket, tail, pat, rank) abort
|
||||
return {
|
||||
\ 'head': a:head,
|
||||
\ 'bra': a:bra,
|
||||
\ 'ket': a:ket,
|
||||
\ 'tail': a:tail,
|
||||
\ 'rank': a:rank,
|
||||
\ 'pattern': a:pat,
|
||||
\ 'len': s:buflen(a:head, a:tail),
|
||||
\ }
|
||||
endfunction
|
||||
|
||||
|
||||
function! s:gather_candidates(kind, mode, count, pattern_list, stopline) abort "{{{
|
||||
let curpos = getpos('.')[1:2]
|
||||
let rank = 0
|
||||
let candidates = []
|
||||
for pattern in a:pattern_list
|
||||
let rank += 1
|
||||
let candidates += s:search_pattern(pattern, a:kind, a:mode, a:count, rank, curpos, a:stopline)
|
||||
call cursor(curpos)
|
||||
endfor
|
||||
return a:kind[0] is# 'a' && candidates == []
|
||||
\ ? s:gather_candidates('i', a:mode, a:count, a:pattern_list, a:stopline)
|
||||
\ : candidates
|
||||
endfunction
|
||||
"}}}
|
||||
function! s:search_pattern(pat, kind, mode, count, rank, curpos, stopline) abort "{{{
|
||||
let a:pat.head = a:pat.header . a:pat.bra
|
||||
let a:pat.tail = a:pat.ket . a:pat.footer
|
||||
|
||||
let brapos = s:search_key_bra(a:kind, a:curpos, a:pat, a:stopline)
|
||||
if brapos == s:null_pos | return [] | endif
|
||||
let is_string = s:is_string_syntax(brapos)
|
||||
|
||||
let candidates = []
|
||||
while len(candidates) < a:count
|
||||
let c = s:get_candidate(a:pat, a:kind, a:mode, a:rank, brapos, is_string, a:stopline)
|
||||
if c != {}
|
||||
call add(candidates, c)
|
||||
endif
|
||||
call cursor(brapos)
|
||||
|
||||
" move to the next 'bra'
|
||||
let brapos = searchpairpos(a:pat.bra, '', a:pat.ket, 'b', '', a:stopline.upper)
|
||||
if brapos == s:null_pos | break | endif
|
||||
let is_string = s:is_string_syntax(brapos)
|
||||
endwhile
|
||||
return candidates
|
||||
endfunction
|
||||
"}}}
|
||||
function! s:search_key_bra(kind, curpos, pat, stopline) abort "{{{
|
||||
let brapos = s:null_pos
|
||||
if a:kind[0] is# 'a'
|
||||
" search for the first 'bra'
|
||||
if searchpos(a:pat.tail, 'cn', a:stopline.lower) == a:curpos
|
||||
let brapos = searchpairpos(a:pat.bra, '', a:pat.ket, 'b', '', a:stopline.upper)
|
||||
endif
|
||||
let brapos = searchpairpos(a:pat.bra, '', a:pat.ket, 'b', '', a:stopline.upper)
|
||||
elseif a:kind[0] is# 'i'
|
||||
let head_start = searchpos(a:pat.head, 'bc', a:stopline.upper)
|
||||
let head_end = searchpos(a:pat.head, 'ce', a:stopline.lower)
|
||||
call cursor(a:curpos)
|
||||
let tail_start = searchpos(a:pat.tail, 'bc', a:stopline.upper)
|
||||
let tail_end = searchpos(a:pat.tail, 'ce', a:stopline.lower)
|
||||
|
||||
" check the initial position
|
||||
if s:is_in_between(a:curpos, head_start, head_end)
|
||||
" cursor is on a header
|
||||
call cursor(head_end)
|
||||
elseif s:is_in_between(a:curpos, tail_start, tail_end)
|
||||
" cursor is on a footer
|
||||
call cursor(tail_start)
|
||||
if tail_start[1] == 1
|
||||
normal! k$
|
||||
else
|
||||
normal! h
|
||||
endif
|
||||
else
|
||||
" cursor is in between a bra and a ket
|
||||
call cursor(a:curpos)
|
||||
endif
|
||||
|
||||
" move to the corresponded 'bra'
|
||||
let brapos = searchpairpos(a:pat.bra, '', a:pat.ket, 'bc', '', a:stopline.upper)
|
||||
endif
|
||||
return brapos
|
||||
endfunction
|
||||
"}}}
|
||||
function! s:get_candidate(pat, kind, mode, rank, brapos, is_string, stopline) abort "{{{
|
||||
" 'bra' should accompany with 'header'
|
||||
let headstart = searchpos(a:pat.head, 'bc', a:stopline.upper)
|
||||
let headend = searchpos(a:pat.head, 'ce', a:stopline.lower)
|
||||
call cursor(a:brapos)
|
||||
if !s:is_in_between(a:brapos, headstart, headend)
|
||||
return {}
|
||||
endif
|
||||
let headpos = headstart
|
||||
|
||||
" search for the paired 'ket'
|
||||
let skip = 's:is_string_syntax(getpos(".")[1:2]) != a:is_string'
|
||||
let ketpos = searchpairpos(a:pat.bra, '', a:pat.ket, '', skip, a:stopline.lower)
|
||||
if ketpos == s:null_pos
|
||||
return {}
|
||||
endif
|
||||
let tailpos = searchpos(a:pat.tail, 'ce', a:stopline.lower)
|
||||
|
||||
if searchpos(a:pat.tail, 'bcn', a:stopline.upper) != ketpos
|
||||
return {}
|
||||
endif
|
||||
|
||||
let c = s:Candidate(headpos, a:brapos, ketpos, tailpos, a:pat, a:rank)
|
||||
if !s:is_valid_candidate(c, a:kind, a:mode, a:is_string)
|
||||
return {}
|
||||
endif
|
||||
return c
|
||||
endfunction
|
||||
"}}}
|
||||
function! s:elect(candidates, count) abort "{{{
|
||||
if a:candidates == []
|
||||
return {}
|
||||
endif
|
||||
let filter = 'v:val.head != s:null_pos && v:val.bra != s:null_pos && v:val.ket != s:null_pos && v:val.tail != s:null_pos'
|
||||
call filter(a:candidates, filter)
|
||||
call sort(a:candidates, 's:compare')
|
||||
if len(a:candidates) < a:count
|
||||
return {}
|
||||
endif
|
||||
return a:candidates[a:count - 1]
|
||||
endfunction
|
||||
"}}}
|
||||
function! s:to_range(kind, candidate) abort "{{{
|
||||
if a:kind[1] is# 'p'
|
||||
let [start, end] = s:parameter_region(a:candidate)
|
||||
else
|
||||
let start = a:candidate.head
|
||||
let end = a:candidate.tail
|
||||
endif
|
||||
return [start, end]
|
||||
endfunction
|
||||
"}}}
|
||||
function! s:select(start, end) abort "{{{
|
||||
if a:start == s:null_pos || a:end == s:null_pos
|
||||
return
|
||||
endif
|
||||
normal! v
|
||||
call cursor(a:start)
|
||||
normal! o
|
||||
call cursor(a:end)
|
||||
if &selection is# 'exclusive'
|
||||
normal! l
|
||||
endif
|
||||
endfunction
|
||||
"}}}
|
||||
function! s:is_in_between(pos, start, end) abort "{{{
|
||||
return (a:pos != s:null_pos) && (a:start != s:null_pos) && (a:end != s:null_pos)
|
||||
\ && ((a:pos[0] > a:start[0]) || ((a:pos[0] == a:start[0]) && (a:pos[1] >= a:start[1])))
|
||||
\ && ((a:pos[0] < a:end[0]) || ((a:pos[0] == a:end[0]) && (a:pos[1] <= a:end[1])))
|
||||
endfunction
|
||||
"}}}
|
||||
function! s:is_string_syntax(pos) abort "{{{
|
||||
return match(map(synstack(a:pos[0], a:pos[1]), 'synIDattr(synIDtrans(v:val), "name")'), 'String') > -1
|
||||
endfunction
|
||||
"}}}
|
||||
function! s:is_continuous_syntax(brapos, ketpos) abort "{{{
|
||||
let start_col = a:brapos[1]
|
||||
for lnum in range(a:brapos[0], a:ketpos[0])
|
||||
if lnum == a:ketpos[0]
|
||||
let end_col= a:ketpos[1]
|
||||
else
|
||||
let end_col= col([lnum, '$'])
|
||||
endif
|
||||
for col in range(start_col, end_col)
|
||||
if match(map(synstack(lnum, col), 'synIDattr(synIDtrans(v:val), "name")'), 'String') < 0
|
||||
return 0
|
||||
endif
|
||||
endfor
|
||||
let start_col = 1
|
||||
endfor
|
||||
return 1
|
||||
endfunction
|
||||
"}}}
|
||||
function! s:is_valid_syntax(candidate, is_string) abort "{{{
|
||||
return !a:is_string || s:is_continuous_syntax(a:candidate.bra, a:candidate.ket)
|
||||
endfunction
|
||||
"}}}
|
||||
function! s:is_same_or_adjacent(p1, p2) abort "{{{
|
||||
return a:p1 == a:p2 || (a:p1[0] == a:p2[0] && a:p1[1]+1 == a:p2[1])
|
||||
endfunction
|
||||
"}}}
|
||||
function! s:is_wider(candidate, start, end) abort "{{{
|
||||
return (s:is_ahead(a:start, a:candidate.head) && s:is_same_or_ahead(a:candidate.tail, a:end)) ||
|
||||
\ (s:is_same_or_ahead(a:start, a:candidate.head) && s:is_ahead(a:candidate.tail, a:end))
|
||||
endfunction
|
||||
"}}}
|
||||
function! s:is_ahead(p1, p2) abort "{{{
|
||||
return (a:p1[0] > a:p2[0]) || (a:p1[0] == a:p2[0] && a:p1[1] > a:p2[1])
|
||||
endfunction
|
||||
"}}}
|
||||
function! s:is_same_or_ahead(p1, p2) abort "{{{
|
||||
return (a:p1[0] > a:p2[0]) || (a:p1[0] == a:p2[0] && a:p1[1] >= a:p2[1])
|
||||
endfunction
|
||||
"}}}
|
||||
function! s:is_valid_candidate(c, kind, mode, is_string) abort "{{{
|
||||
if a:kind[1] is# 'p' && s:is_same_or_adjacent(a:c.bra, a:c.ket)
|
||||
return s:FALSE
|
||||
endif
|
||||
if a:mode is# 'x' && !s:is_wider(a:c, getpos("'<")[1:2], getpos("'>")[1:2])
|
||||
return s:FALSE
|
||||
endif
|
||||
if !s:is_valid_syntax(a:c, a:is_string)
|
||||
return s:FALSE
|
||||
endif
|
||||
return s:TRUE
|
||||
endfunction
|
||||
"}}}
|
||||
function! s:resolve_patterns() abort "{{{
|
||||
return deepcopy(get(b:, 'sandwich_magicchar_f_patterns',
|
||||
\ get(g:, 'sandwich#magicchar#f#patterns',
|
||||
\ g:sandwich#magicchar#f#default_patterns)))
|
||||
endfunction
|
||||
"}}}
|
||||
function! s:parameter_region(candidate) abort "{{{
|
||||
let whichwrap = &whichwrap
|
||||
let &whichwrap = 'h,l'
|
||||
let [visualhead, visualtail] = [getpos("'<"), getpos("'>")]
|
||||
try
|
||||
normal! v
|
||||
call cursor(a:candidate.bra)
|
||||
call search(a:candidate.pattern.bra, 'ce', a:candidate.ket[0])
|
||||
normal! l
|
||||
let head = getpos('.')[1:2]
|
||||
normal! o
|
||||
call cursor(a:candidate.ket)
|
||||
normal! h
|
||||
let tail = getpos('.')[1:2]
|
||||
execute "normal! \<Esc>"
|
||||
finally
|
||||
let &whichwrap = whichwrap
|
||||
call setpos("'<", visualhead)
|
||||
call setpos("'>", visualtail)
|
||||
endtry
|
||||
return [head, tail]
|
||||
endfunction
|
||||
"}}}
|
||||
function! s:buflen(start, end) abort "{{{
|
||||
" start, end -> [lnum, col]
|
||||
if a:start[0] == a:end[0]
|
||||
let len = a:end[1] - a:start[1] + 1
|
||||
else
|
||||
let len = (line2byte(a:end[0]) + a:end[1]) - (line2byte(a:start[0]) + a:start[1]) + 1
|
||||
endif
|
||||
return len
|
||||
endfunction
|
||||
"}}}
|
||||
function! s:compare(i1, i2) abort "{{{
|
||||
" i1, i2 -> Candidate
|
||||
if a:i1.len < a:i2.len
|
||||
return -1
|
||||
elseif a:i1.len > a:i2.len
|
||||
return 1
|
||||
else
|
||||
return a:i2.rank - a:i1.rank
|
||||
endif
|
||||
endfunction
|
||||
"}}}
|
||||
function! s:get(name, default) abort "{{{
|
||||
return exists('b:' . a:name) ? b:[a:name]
|
||||
\ : exists('g:' . a:name) ? g:[a:name]
|
||||
\ : a:default
|
||||
endfunction
|
||||
"}}}
|
||||
|
||||
let &cpo = s:save_cpo
|
||||
unlet s:save_cpo
|
||||
|
||||
" vim:set foldmethod=marker:
|
||||
" vim:set commentstring="%s:
|
||||
@ -0,0 +1,102 @@
|
||||
let s:last_inserted = []
|
||||
let s:last_searched = []
|
||||
|
||||
" variables "{{{
|
||||
" patchs
|
||||
if v:version > 704 || (v:version == 704 && has('patch237'))
|
||||
let s:has_patch_7_4_1685 = has('patch-7.4.1685')
|
||||
else
|
||||
let s:has_patch_7_4_1685 = v:version == 704 && has('patch1685')
|
||||
endif
|
||||
"}}}
|
||||
|
||||
function! sandwich#magicchar#i#input(kind, ...) abort "{{{
|
||||
let storepoint = a:kind ==# 'operator' ? 'last_inserted' : 'last_searched'
|
||||
let former = s:input(a:kind . '-sandwich:head: ')
|
||||
let quit_if_empty = get(a:000, 0, 0)
|
||||
if quit_if_empty && former ==# ''
|
||||
let s:{storepoint} = []
|
||||
return ['', '']
|
||||
endif
|
||||
let latter = s:input(a:kind . '-sandwich:tail: ')
|
||||
let s:{storepoint} = [former, latter]
|
||||
return copy(s:{storepoint})
|
||||
endfunction
|
||||
"}}}
|
||||
function! sandwich#magicchar#i#lastinput(kind, ...) abort "{{{
|
||||
let storepoint = a:kind ==# 'operator' ? 'last_inserted' : 'last_searched'
|
||||
let cancel_if_invalid = get(a:000, 0, 0)
|
||||
if cancel_if_invalid && s:{storepoint} == []
|
||||
throw 'OperatorSandwichCancel'
|
||||
endif
|
||||
return s:{storepoint} != [] ? copy(s:{storepoint}) : ['', '']
|
||||
endfunction
|
||||
"}}}
|
||||
function! sandwich#magicchar#i#compl(ArgLead, CmdLine, CursorPos) abort "{{{
|
||||
let list = []
|
||||
let lines = getline(1, '$')
|
||||
if a:ArgLead ==# ''
|
||||
let list += s:extract_patterns_from_lines(lines, '\<\k\{3,}\>')
|
||||
else
|
||||
let list += s:extract_patterns_from_lines(lines, printf('\<%s.\{-}\>', a:ArgLead))
|
||||
if list == []
|
||||
let tail = matchstr(a:ArgLead, '\<\k\+$')
|
||||
if tail !=# '' && tail !=# a:ArgLead
|
||||
let list += s:extract_patterns_from_lines(lines, tail . '.\{-}\>')
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
return join(uniq(sort(list)), "\n")
|
||||
endfunction
|
||||
"}}}
|
||||
function! s:input(mes) abort "{{{
|
||||
echohl MoreMsg
|
||||
try
|
||||
let input = input(a:mes, '', 'custom,sandwich#magicchar#i#compl')
|
||||
" flash prompt
|
||||
echo ''
|
||||
finally
|
||||
echohl NONE
|
||||
endtry
|
||||
return input
|
||||
endfunction
|
||||
"}}}
|
||||
function! s:extract_patterns_from_lines(lines, pat) abort "{{{
|
||||
let list = []
|
||||
for line in a:lines
|
||||
let list += s:extract_pattern(line, a:pat)
|
||||
endfor
|
||||
return list
|
||||
endfunction
|
||||
"}}}
|
||||
function! s:extract_pattern(string, pat) abort "{{{
|
||||
let list = []
|
||||
let end = 0
|
||||
while 1
|
||||
let [str, start, end] = s:matchstrpos(a:string, a:pat, end)
|
||||
if start < 0
|
||||
break
|
||||
endif
|
||||
let list += [str]
|
||||
endwhile
|
||||
return list
|
||||
endfunction
|
||||
"}}}
|
||||
" function! s:matchstrpos(expr, pat, ...) abort "{{{
|
||||
if s:has_patch_7_4_1685
|
||||
let s:matchstrpos = function('matchstrpos')
|
||||
else
|
||||
function! s:matchstrpos(expr, pat, ...) abort
|
||||
if a:0 == 0
|
||||
return [matchstr(a:expr, a:pat), match(a:expr, a:pat), matchend(a:expr, a:pat)]
|
||||
elseif a:0 == 1
|
||||
return [matchstr(a:expr, a:pat, a:1), match(a:expr, a:pat, a:1), matchend(a:expr, a:pat, a:1)]
|
||||
else
|
||||
return [matchstr(a:expr, a:pat, a:1, a:2), match(a:expr, a:pat, a:1, a:2), matchend(a:expr, a:pat, a:1, a:2)]
|
||||
endif
|
||||
endfunction
|
||||
endif
|
||||
"}}}
|
||||
|
||||
" vim:set foldmethod=marker:
|
||||
" vim:set commentstring="%s:
|
||||
@ -0,0 +1,446 @@
|
||||
" variables "{{{
|
||||
let s:null_coord = [0, 0]
|
||||
|
||||
" types
|
||||
let s:type_num = type(0)
|
||||
let s:type_str = type('')
|
||||
let s:type_list = type([])
|
||||
"}}}
|
||||
|
||||
function! sandwich#magicchar#t#tag() abort "{{{
|
||||
call operator#sandwich#show()
|
||||
try
|
||||
echohl MoreMsg
|
||||
let old_imsearch = &l:imsearch
|
||||
let &l:imsearch = 0
|
||||
let tag = input('Input tag: ')
|
||||
let &l:imsearch = old_imsearch
|
||||
" flash prompt
|
||||
echo ''
|
||||
finally
|
||||
echohl NONE
|
||||
call operator#sandwich#quench()
|
||||
endtry
|
||||
if tag ==# ''
|
||||
throw 'OperatorSandwichCancel'
|
||||
endif
|
||||
let [open, close] = s:expand(tag)
|
||||
return [printf('<%s>', open), printf('</%s>', close)]
|
||||
endfunction
|
||||
"}}}
|
||||
function! sandwich#magicchar#t#tagname() abort "{{{
|
||||
call operator#sandwich#show()
|
||||
try
|
||||
echohl MoreMsg
|
||||
let old_imsearch = &l:imsearch
|
||||
let &l:imsearch = 0
|
||||
let tagname = input('Input tag name: ')
|
||||
let &l:imsearch = old_imsearch
|
||||
" flash prompt
|
||||
echo ''
|
||||
finally
|
||||
echohl NONE
|
||||
call operator#sandwich#quench()
|
||||
endtry
|
||||
if tagname ==# ''
|
||||
throw 'OperatorSandwichCancel'
|
||||
endif
|
||||
return s:expand(tagname)
|
||||
endfunction
|
||||
"}}}
|
||||
function! s:tokenize(text) abort "{{{
|
||||
let j = 0
|
||||
let n = strlen(a:text)
|
||||
let tokenlist = []
|
||||
while j >= 0 && j < n
|
||||
let i = j
|
||||
let j = match(a:text, '\m[[[:blank:]#.]', i)
|
||||
if i < j
|
||||
let tokenlist += [a:text[i : j-1]]
|
||||
elseif i == j
|
||||
let char = a:text[i]
|
||||
if char =~# '\m\s'
|
||||
" space is not allowed
|
||||
throw 'SandwichMagiccharTIncorrectSyntax'
|
||||
elseif char ==# '['
|
||||
" tokenize custom attributes
|
||||
let tokenlist += [char]
|
||||
let j += 1
|
||||
let [j, tokenlist] += s:tokenize_custom_attributes(a:text, j)
|
||||
else
|
||||
let tokenlist += [char]
|
||||
let j += 1
|
||||
endif
|
||||
endif
|
||||
endwhile
|
||||
|
||||
let i = j >= 0 ? j : i
|
||||
if i < n
|
||||
let tokenlist += [a:text[i :]]
|
||||
endif
|
||||
return tokenlist
|
||||
endfunction
|
||||
"}}}
|
||||
function! s:tokenize_custom_attributes(text, j) abort "{{{
|
||||
let j = a:j
|
||||
let n = strlen(a:text)
|
||||
let closed = 0
|
||||
let tokenlist = []
|
||||
while j >= 0 && j < n
|
||||
let i = j
|
||||
let j = match(a:text, '\m[][:blank:]="'']', i)
|
||||
if i < j
|
||||
let string = a:text[i : j-1]
|
||||
let tokenlist += [string]
|
||||
elseif i == j
|
||||
let char = a:text[i]
|
||||
if char =~# '\m\s'
|
||||
" skip space
|
||||
let j = matchend(a:text, '\m\s\+', i)
|
||||
if j > i
|
||||
let tokenlist += [a:text[i : j-1]]
|
||||
endif
|
||||
elseif char =~# '\m["'']'
|
||||
" skip string literal
|
||||
let j = match(a:text, char, i+1)
|
||||
if j > 0
|
||||
let tokenlist += [a:text[i : j]]
|
||||
let j += 1
|
||||
else
|
||||
" unclosed string literal
|
||||
throw 'SandwichMagiccharTIncorrectSyntax'
|
||||
endif
|
||||
elseif char ==# ']'
|
||||
" the end of custom attributes region
|
||||
let tokenlist += [char]
|
||||
let j += 1
|
||||
let closed = 1
|
||||
break
|
||||
else
|
||||
let tokenlist += [char]
|
||||
let j += 1
|
||||
endif
|
||||
endif
|
||||
endwhile
|
||||
if !closed
|
||||
" unclosed braket
|
||||
throw 'SandwichMagiccharTIncorrectSyntax'
|
||||
endif
|
||||
return [j - a:j, tokenlist]
|
||||
endfunction
|
||||
"}}}
|
||||
|
||||
|
||||
function! s:matches_filetype(filetype, list) abort "{{{
|
||||
return index(a:list, a:filetype) != -1
|
||||
endfunction
|
||||
" }}}
|
||||
|
||||
function! s:parse(tokenlist) abort "{{{
|
||||
let itemdict = deepcopy(s:itemdict)
|
||||
let itemlist = map(copy(a:tokenlist), '{"is_operator": v:val =~# ''^\%([][#.=]\|\s\+\)$'' ? 1 : 0, "string": v:val}')
|
||||
|
||||
let i = 0
|
||||
let n = len(itemlist)
|
||||
let item = itemlist[i]
|
||||
if item.is_operator
|
||||
call itemdict.queue_element('div')
|
||||
else
|
||||
call itemdict.queue_element(item.string)
|
||||
let i += 1
|
||||
endif
|
||||
while i < n
|
||||
let item = itemlist[i]
|
||||
if item.is_operator
|
||||
if item.string ==# '#'
|
||||
let i = s:handle_id(itemdict, itemlist, i)
|
||||
elseif item.string ==# '.'
|
||||
if s:matches_filetype(&filetype, g:sandwich#jsx_filetypes)
|
||||
let i = s:handle_className(itemdict, itemlist, i)
|
||||
else
|
||||
let i = s:handle_class(itemdict, itemlist, i)
|
||||
endif
|
||||
elseif item.string ==# '['
|
||||
let i = s:parse_custom_attributes(itemdict, itemlist, i)
|
||||
else
|
||||
" unanticipated operator (should not reach here)
|
||||
throw 'SandwichMagiccharTIncorrectSyntax'
|
||||
endif
|
||||
else
|
||||
" successive operand is not allowed here (should not reach here)
|
||||
throw 'SandwichMagiccharTIncorrectSyntax'
|
||||
endif
|
||||
endwhile
|
||||
|
||||
let parsed = deepcopy(itemdict.queue)
|
||||
for item in parsed
|
||||
call filter(item, 'v:key =~# ''\%(name\|value\)''')
|
||||
endfor
|
||||
return parsed
|
||||
endfunction
|
||||
"}}}
|
||||
function! s:parse_custom_attributes(itemdict, itemlist, i) abort "{{{
|
||||
" check ket
|
||||
let i_ket = s:check_ket(a:itemlist, a:i)
|
||||
if i_ket < 0
|
||||
" ket does not exist (should not reach here)
|
||||
throw 'SandwichMagiccharTIncorrectSyntax'
|
||||
endif
|
||||
|
||||
let i = a:i + 1
|
||||
while i < i_ket
|
||||
let item = a:itemlist[i]
|
||||
if item.is_operator
|
||||
if item.string ==# '='
|
||||
let i = s:handle_equal(a:itemdict, a:itemlist, i)
|
||||
else
|
||||
let i += 1
|
||||
endif
|
||||
else
|
||||
let i = s:handle_custom_attr_name(a:itemdict, a:itemlist, i)
|
||||
endif
|
||||
endwhile
|
||||
call a:itemdict.queue_custom_attr()
|
||||
return i_ket + 1
|
||||
endfunction
|
||||
"}}}
|
||||
function! s:handle_id(itemdict, itemlist, i) abort "{{{
|
||||
let i = a:i + 1
|
||||
let item = get(a:itemlist, i, {'is_operator': 1})
|
||||
if item.is_operator
|
||||
call a:itemdict.queue_id()
|
||||
else
|
||||
call a:itemdict.queue_id(item.string)
|
||||
let i += 1
|
||||
endif
|
||||
return i
|
||||
endfunction
|
||||
"}}}
|
||||
function! s:handle_class(itemdict, itemlist, i) abort "{{{
|
||||
let i = a:i + 1
|
||||
let item = get(a:itemlist, i, {'is_operator': 1})
|
||||
if item.is_operator
|
||||
call a:itemdict.queue_class()
|
||||
else
|
||||
call a:itemdict.queue_class(item.string)
|
||||
let i += 1
|
||||
endif
|
||||
return i
|
||||
endfunction
|
||||
"}}}
|
||||
function! s:handle_className(itemdict, itemlist, i) abort "{{{
|
||||
let i = a:i + 1
|
||||
let item = get(a:itemlist, i, {'is_operator': 1})
|
||||
if item.is_operator
|
||||
call a:itemdict.queue_className()
|
||||
else
|
||||
call a:itemdict.queue_className(item.string)
|
||||
let i += 1
|
||||
endif
|
||||
return i
|
||||
endfunction
|
||||
"}}}
|
||||
function! s:handle_equal(itemdict, itemlist, i, ...) abort "{{{
|
||||
let i = a:i + 1
|
||||
let item = a:itemlist[i]
|
||||
let name = get(a:000, 0, '')
|
||||
if item.is_operator
|
||||
if item.string ==# '='
|
||||
call a:itemdict.list_custom_attr(name)
|
||||
else
|
||||
call a:itemdict.list_custom_attr(name)
|
||||
let i += 1
|
||||
endif
|
||||
else
|
||||
call a:itemdict.list_custom_attr(name, item.string)
|
||||
let i += 1
|
||||
endif
|
||||
return i
|
||||
endfunction
|
||||
"}}}
|
||||
function! s:handle_custom_attr_name(itemdict, itemlist, i) abort "{{{
|
||||
let item = a:itemlist[a:i]
|
||||
let name = item.string
|
||||
let i = a:i + 1
|
||||
let item = a:itemlist[i]
|
||||
if item.is_operator
|
||||
if item.string ==# '='
|
||||
let i = s:handle_equal(a:itemdict, a:itemlist, i, name)
|
||||
else
|
||||
call a:itemdict.list_custom_attr(name)
|
||||
let i += 1
|
||||
endif
|
||||
else
|
||||
call a:itemdict.list_custom_attr(name)
|
||||
endif
|
||||
return i
|
||||
endfunction
|
||||
"}}}
|
||||
function! s:check_ket(itemlist, i) abort "{{{
|
||||
let i = a:i + 1
|
||||
let n = len(a:itemlist)
|
||||
let i_ket = -1
|
||||
while i < n
|
||||
let item = a:itemlist[i]
|
||||
if item.is_operator && item.string ==# ']'
|
||||
let i_ket = i
|
||||
break
|
||||
endif
|
||||
let i += 1
|
||||
endwhile
|
||||
return i_ket
|
||||
endfunction
|
||||
"}}}
|
||||
function! s:build(itemlist) abort "{{{
|
||||
let fragments = [a:itemlist[0]['value']]
|
||||
if len(a:itemlist) > 1
|
||||
for item in a:itemlist[1:]
|
||||
let name = item.name
|
||||
let value = type(item.value) == s:type_list ? join(filter(item.value, 'v:val !=# ""')) : item.value
|
||||
let value = value !~# '^\(["'']\).*\1$' ? printf('"%s"', value) : value
|
||||
let fragments += [printf('%s=%s', name, value)]
|
||||
endfor
|
||||
endif
|
||||
return join(fragments)
|
||||
endfunction
|
||||
"}}}
|
||||
function! s:expand(text) abort "{{{
|
||||
try
|
||||
let tokenlist = s:tokenize(a:text)
|
||||
let itemlist = s:parse(tokenlist)
|
||||
catch /^SandwichMagiccharTIncorrectSyntax$/
|
||||
return [a:text, matchstr(a:text, '^\s*\zs\a[^[:blank:]>/]*')]
|
||||
endtry
|
||||
let element = itemlist[0]['value']
|
||||
return [s:build(itemlist), element]
|
||||
endfunction
|
||||
"}}}
|
||||
|
||||
function! sandwich#magicchar#t#i() abort "{{{
|
||||
call s:prototype('i')
|
||||
endfunction
|
||||
"}}}
|
||||
function! sandwich#magicchar#t#a() abort "{{{
|
||||
call s:prototype('a')
|
||||
endfunction
|
||||
"}}}
|
||||
function! s:prototype(kind) abort "{{{
|
||||
let view = winsaveview()
|
||||
let visualhead = getpos("'<")
|
||||
let visualtail = getpos("'>")
|
||||
execute printf('silent! normal! v%dat', v:count1)
|
||||
execute "normal! \<Esc>"
|
||||
if getpos("'<") != getpos("'>")
|
||||
normal! gv
|
||||
let pat = a:kind ==# 'i' ? '</\ze\a[^[:blank:]>/]*' : '</\a[^[:blank:]>/]*\ze\s*>'
|
||||
call search(pat, 'be', line("'<"))
|
||||
normal! o
|
||||
let pat = a:kind ==# 'i' ? '<\a[^[:blank:]>/]*\zs\_.' : '<\zs\a[^[:blank:]>/]*'
|
||||
call search(pat, '', line("'>"))
|
||||
else
|
||||
call winrestview(view)
|
||||
call setpos("'<", visualhead)
|
||||
call setpos("'>", visualtail)
|
||||
endif
|
||||
endfunction
|
||||
"}}}
|
||||
function! sandwich#magicchar#t#it() abort "{{{
|
||||
call s:textobj('i')
|
||||
endfunction
|
||||
"}}}
|
||||
function! sandwich#magicchar#t#at() abort "{{{
|
||||
call s:textobj('a')
|
||||
endfunction
|
||||
"}}}
|
||||
function! s:textobj(a_or_i) abort "{{{
|
||||
let head = searchpos('<\a[^[:blank:]>/]*', 'bcn', 0, 50)
|
||||
if head != s:null_coord
|
||||
let tagname = matchstr(getline(head[0])[head[1]-1 :], '^<\zs\a[^[:blank:]>/]*')
|
||||
if search(printf('</%s>', s:escape(tagname)), 'cn', 0, 50)
|
||||
" add :silent! to suppress errorbell
|
||||
if a:a_or_i ==# 'i'
|
||||
silent! normal! vit
|
||||
else
|
||||
silent! normal! vat
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endfunction
|
||||
"}}}
|
||||
function! s:escape(string) abort "{{{
|
||||
return escape(a:string, '~"\.^$[]*')
|
||||
endfunction
|
||||
"}}}
|
||||
|
||||
" itemdict object "{{{
|
||||
let s:itemdict = {
|
||||
\ 'element': {'name': 'element', 'value': ''},
|
||||
\ 'id' : {'name': 'id', 'value': '', 'queued': 0},
|
||||
\ 'class' : {'name': 'class', 'value': [], 'queued': 0},
|
||||
\ 'className' : {'name': 'className', 'value': [], 'queued': 0},
|
||||
\ 'queue' : [],
|
||||
\ 'customlist': [],
|
||||
\ }
|
||||
|
||||
function! s:itemdict.queue_element(value) dict abort "{{{
|
||||
let self.element.value = a:value
|
||||
call add(self.queue, self.element)
|
||||
endfunction
|
||||
"}}}
|
||||
function! s:itemdict.queue_id(...) dict abort "{{{
|
||||
let self.id.value = get(a:000, 0, '')
|
||||
if !self.id.queued
|
||||
call add(self.queue, self.id)
|
||||
let self.id.queued = 1
|
||||
endif
|
||||
endfunction
|
||||
"}}}
|
||||
function! s:itemdict.queue_class(...) dict abort "{{{
|
||||
call add(self.class.value, get(a:000, 0, ''))
|
||||
if !self.class.queued
|
||||
call add(self.queue, self.class)
|
||||
let self.class.queued = 1
|
||||
endif
|
||||
endfunction
|
||||
"}}}
|
||||
function! s:itemdict.queue_className(...) dict abort "{{{
|
||||
call add(self.className.value, get(a:000, 0, ''))
|
||||
if !self.className.queued
|
||||
call add(self.queue, self.className)
|
||||
let self.className.queued = 1
|
||||
endif
|
||||
endfunction
|
||||
"}}}
|
||||
function! s:itemdict.queue_custom_attr() dict abort "{{{
|
||||
if self.customlist != []
|
||||
call extend(self.queue, remove(self.customlist, 0, -1))
|
||||
endif
|
||||
endfunction
|
||||
"}}}
|
||||
function! s:itemdict.list_custom_attr(name, ...) dict abort "{{{
|
||||
let value = get(a:000, 0, '')
|
||||
if a:name ==# 'id'
|
||||
call self.queue_id(value)
|
||||
elseif a:name ==# 'class'
|
||||
call self.queue_class(value)
|
||||
endif
|
||||
|
||||
if a:name ==# ''
|
||||
let custom_attr = {'kind': 'custom', 'name': a:name, 'value': value}
|
||||
call add(self.customlist, custom_attr)
|
||||
else
|
||||
if !has_key(self, a:name)
|
||||
let self[a:name] = {'kind': 'custom', 'name': a:name, 'value': value}
|
||||
call add(self.customlist, self[a:name])
|
||||
else
|
||||
let self[a:name]['value'] = value
|
||||
endif
|
||||
endif
|
||||
endfunction
|
||||
"}}}
|
||||
"}}}
|
||||
|
||||
|
||||
|
||||
" vim:set foldmethod=marker:
|
||||
" vim:set commentstring="%s:
|
||||
@ -0,0 +1,67 @@
|
||||
" messenger object - managing messages and errors.
|
||||
|
||||
function! sandwich#messenger#new() abort "{{{
|
||||
let s:messenger = deepcopy(s:messenger_prototype)
|
||||
return s:messenger
|
||||
endfunction
|
||||
"}}}
|
||||
function! sandwich#messenger#get() abort "{{{
|
||||
return s:messenger
|
||||
endfunction
|
||||
"}}}
|
||||
|
||||
" s:messenger_prototype "{{{
|
||||
let s:messenger_prototype = {
|
||||
\ 'error' : {'flag': 0, 'string': ''},
|
||||
\ 'notice': {'flag': 0, 'list': []},
|
||||
\ }
|
||||
"}}}
|
||||
function! s:messenger_prototype.initialize() dict abort "{{{
|
||||
let self.error.flag = 0
|
||||
let self.error.string = ''
|
||||
let self.notice.flag = 0
|
||||
let self.notice.list = []
|
||||
endfunction
|
||||
"}}}
|
||||
function! s:messenger_prototype.notify(prefix) dict abort "{{{
|
||||
if self.error.flag
|
||||
call self.error.echoerr(a:prefix)
|
||||
elseif self.notice.flag
|
||||
call self.notice.echo(a:prefix)
|
||||
endif
|
||||
endfunction
|
||||
"}}}
|
||||
function! s:messenger_prototype.error.echoerr(prefix) dict abort "{{{
|
||||
echoerr a:prefix . self.string
|
||||
endfunction
|
||||
"}}}
|
||||
function! s:messenger_prototype.notice.echo(prefix) dict abort "{{{
|
||||
let queue = []
|
||||
if self.list != []
|
||||
for line in self.list
|
||||
let queue += [[a:prefix, 'MoreMsg']]
|
||||
let queue += [line]
|
||||
let queue += [["\n", 'NONE']]
|
||||
endfor
|
||||
call remove(queue, -1)
|
||||
endif
|
||||
call sandwich#util#echo(queue)
|
||||
endfunction
|
||||
"}}}
|
||||
function! s:messenger_prototype.error.set(errmes) dict abort "{{{
|
||||
let self.flag = 1
|
||||
let self.string = a:errmes
|
||||
endfunction
|
||||
"}}}
|
||||
function! s:messenger_prototype.notice.queue(line) dict abort "{{{
|
||||
let self.flag = 1
|
||||
call add(self.list, a:line)
|
||||
endfunction
|
||||
"}}}
|
||||
|
||||
call sandwich#messenger#new()
|
||||
|
||||
|
||||
" vim:set foldmethod=marker:
|
||||
" vim:set commentstring="%s:
|
||||
" vim:set ts=2 sts=2 sw=2:
|
||||
@ -0,0 +1,346 @@
|
||||
" opt object - managing options
|
||||
|
||||
function! sandwich#opt#new(kind, defaultopt, argopt) abort "{{{
|
||||
let opt = deepcopy(s:opt)
|
||||
if a:kind ==# 'auto' || a:kind ==# 'query'
|
||||
let opt.recipe = {}
|
||||
let opt.of = function('s:of_for_textobj')
|
||||
let opt.filter = s:default_values['textobj']['filter']
|
||||
call opt.update('arg', a:argopt)
|
||||
call opt.update('default', a:defaultopt)
|
||||
else
|
||||
let opt.recipe_add = {}
|
||||
let opt.recipe_delete = {}
|
||||
let opt.of = function('s:of_for_' . a:kind)
|
||||
let opt.filter = s:default_values[a:kind]['filter']
|
||||
call opt.update('arg', a:argopt)
|
||||
endif
|
||||
return opt
|
||||
endfunction
|
||||
"}}}
|
||||
function! sandwich#opt#defaults(kind, ...) abort "{{{
|
||||
if a:kind ==# 'auto' || a:kind ==# 'query'
|
||||
return deepcopy(s:default_values['textobj'][a:kind])
|
||||
elseif a:kind ==# 'add' || a:kind ==# 'delete' || a:kind ==# 'replace'
|
||||
let motionwise = get(a:000, 0, 'char')
|
||||
return deepcopy(s:default_values[a:kind][motionwise])
|
||||
else
|
||||
return {}
|
||||
endif
|
||||
endfunction
|
||||
"}}}
|
||||
|
||||
" opt "{{{
|
||||
let s:opt = {
|
||||
\ 'default' : {},
|
||||
\ 'arg' : {},
|
||||
\ 'filter' : '',
|
||||
\ }
|
||||
"}}}
|
||||
function! s:opt.clear(target) dict abort "{{{
|
||||
call filter(self[a:target], 0)
|
||||
endfunction
|
||||
"}}}
|
||||
function! s:opt.update(target, dict) dict abort "{{{
|
||||
call self.clear(a:target)
|
||||
call extend(self[a:target], filter(deepcopy(a:dict), self.filter), 'force')
|
||||
endfunction
|
||||
"}}}
|
||||
function! s:opt.has(opt_name) dict abort "{{{
|
||||
return has_key(self.default, a:opt_name)
|
||||
endfunction
|
||||
"}}}
|
||||
function! s:opt.max(opt_name, ...) dict abort "{{{
|
||||
let minimum = get(a:000, 0, 0)
|
||||
let list = []
|
||||
if has_key(self['recipe_delete'], a:opt_name)
|
||||
let list += [self['recipe_delete'][a:opt_name]]
|
||||
endif
|
||||
if has_key(self['recipe_add'], a:opt_name)
|
||||
let list += [self['recipe_add'][a:opt_name]]
|
||||
endif
|
||||
if list == []
|
||||
let list += [self._of(a:opt_name)]
|
||||
endif
|
||||
return max([minimum] + list)
|
||||
endfunction
|
||||
"}}}
|
||||
function! s:opt.get(opt_name, kind, ...) dict abort "{{{
|
||||
return self.has(a:opt_name) ? self.of(a:opt_name, a:kind) : get(a:000, 0, 0)
|
||||
endfunction
|
||||
"}}}
|
||||
function! s:opt._of(opt_name, ...) dict abort "{{{
|
||||
let kind = get(a:000, 0, '')
|
||||
if kind !=# '' && has_key(self[kind], a:opt_name)
|
||||
return self[kind][a:opt_name]
|
||||
elseif has_key(self['arg'], a:opt_name)
|
||||
return self['arg'][a:opt_name]
|
||||
else
|
||||
return self['default'][a:opt_name]
|
||||
endif
|
||||
endfunction
|
||||
"}}}
|
||||
|
||||
function! s:of_for_add(opt_name, ...) dict abort "{{{
|
||||
return self._of(a:opt_name, 'recipe_add')
|
||||
endfunction
|
||||
"}}}
|
||||
function! s:of_for_delete(opt_name, ...) dict abort "{{{
|
||||
return self._of(a:opt_name, 'recipe_delete')
|
||||
endfunction
|
||||
"}}}
|
||||
function! s:of_for_replace(opt_name, ...) dict abort "{{{
|
||||
let kind = get(a:000, 0, '')
|
||||
if kind !=# ''
|
||||
return self._of(a:opt_name, kind)
|
||||
else
|
||||
if a:opt_name ==# 'cursor'
|
||||
" recipe_add > recipe_delete > arg > default
|
||||
if has_key(self.recipe_add, a:opt_name)
|
||||
return self.recipe_add[a:opt_name]
|
||||
else
|
||||
return self._of(a:opt_name, 'recipe_delete')
|
||||
endif
|
||||
elseif a:opt_name ==# 'query_once'
|
||||
return self._of(a:opt_name, 'recipe_add')
|
||||
elseif a:opt_name ==# 'regex'
|
||||
return self._of(a:opt_name, 'recipe_delete')
|
||||
elseif a:opt_name ==# 'expr'
|
||||
return self._of(a:opt_name, 'recipe_add')
|
||||
elseif a:opt_name ==# 'listexpr'
|
||||
return self._of(a:opt_name, 'recipe_add')
|
||||
elseif a:opt_name ==# 'noremap'
|
||||
return self._of(a:opt_name, '')
|
||||
elseif a:opt_name ==# 'skip_space'
|
||||
return self._of(a:opt_name, 'recipe_delete')
|
||||
elseif a:opt_name ==# 'skip_char'
|
||||
return self._of(a:opt_name, 'recipe_delete')
|
||||
elseif a:opt_name ==# 'highlight'
|
||||
return self._of(a:opt_name, '')
|
||||
elseif a:opt_name ==# 'hi_duration'
|
||||
return self._of(a:opt_name, '')
|
||||
elseif a:opt_name ==# 'command'
|
||||
let commands = []
|
||||
let commands += get(self.recipe_delete, a:opt_name, [])
|
||||
let commands += get(self.recipe_add, a:opt_name, [])
|
||||
if commands == []
|
||||
let commands += self._of(a:opt_name)
|
||||
endif
|
||||
return commands
|
||||
elseif a:opt_name ==# 'linewise'
|
||||
return self.max(a:opt_name)
|
||||
elseif a:opt_name ==# 'autoindent'
|
||||
return self._of(a:opt_name, 'recipe_add')
|
||||
elseif a:opt_name ==# 'indentkeys'
|
||||
return self._of(a:opt_name, 'recipe_add')
|
||||
elseif a:opt_name ==# 'indentkeys+'
|
||||
return self._of(a:opt_name, 'recipe_add')
|
||||
elseif a:opt_name ==# 'indentkeys-'
|
||||
return self._of(a:opt_name, 'recipe_add')
|
||||
else
|
||||
" should not reach here!
|
||||
throw 'OperatorSandwichError:Replace:InvalidOption:' . a:opt_name
|
||||
endif
|
||||
endif
|
||||
endfunction
|
||||
"}}}
|
||||
function! s:of_for_textobj(opt_name) dict abort "{{{
|
||||
if has_key(self['recipe'], a:opt_name)
|
||||
return self['recipe'][a:opt_name]
|
||||
elseif has_key(self['arg'], a:opt_name)
|
||||
return self['arg'][a:opt_name]
|
||||
else
|
||||
return self['default'][a:opt_name]
|
||||
endif
|
||||
endfunction
|
||||
"}}}
|
||||
|
||||
" default values "{{{
|
||||
let s:default_values = {}
|
||||
let s:default_values.add = {}
|
||||
let s:default_values.add.char = {
|
||||
\ 'cursor' : 'default',
|
||||
\ 'query_once' : 0,
|
||||
\ 'expr' : 0,
|
||||
\ 'listexpr' : 0,
|
||||
\ 'noremap' : 1,
|
||||
\ 'skip_space' : 0,
|
||||
\ 'highlight' : 3,
|
||||
\ 'hi_duration': 200,
|
||||
\ 'command' : [],
|
||||
\ 'linewise' : 0,
|
||||
\ 'autoindent' : -1,
|
||||
\ 'indentkeys' : 0,
|
||||
\ 'indentkeys+': 0,
|
||||
\ 'indentkeys-': 0,
|
||||
\ }
|
||||
let s:default_values.add.line = {
|
||||
\ 'cursor' : 'default',
|
||||
\ 'query_once' : 0,
|
||||
\ 'expr' : 0,
|
||||
\ 'listexpr' : 0,
|
||||
\ 'noremap' : 1,
|
||||
\ 'skip_space' : 1,
|
||||
\ 'highlight' : 3,
|
||||
\ 'hi_duration': 200,
|
||||
\ 'command' : [],
|
||||
\ 'linewise' : 1,
|
||||
\ 'autoindent' : -1,
|
||||
\ 'indentkeys' : 0,
|
||||
\ 'indentkeys+': 0,
|
||||
\ 'indentkeys-': 0,
|
||||
\ }
|
||||
let s:default_values.add.block = {
|
||||
\ 'cursor' : 'default',
|
||||
\ 'query_once' : 0,
|
||||
\ 'expr' : 0,
|
||||
\ 'listexpr' : 0,
|
||||
\ 'noremap' : 1,
|
||||
\ 'skip_space' : 1,
|
||||
\ 'highlight' : 3,
|
||||
\ 'hi_duration': 200,
|
||||
\ 'command' : [],
|
||||
\ 'linewise' : 0,
|
||||
\ 'autoindent' : -1,
|
||||
\ 'indentkeys' : 0,
|
||||
\ 'indentkeys+': 0,
|
||||
\ 'indentkeys-': 0,
|
||||
\ }
|
||||
let s:default_values.add.filter = printf('v:key =~# ''\%%(%s\)''', join(keys(s:default_values['add']['char']), '\|'))
|
||||
|
||||
let s:default_values.delete = {}
|
||||
let s:default_values.delete.char = {
|
||||
\ 'cursor' : 'default',
|
||||
\ 'noremap' : 1,
|
||||
\ 'regex' : 0,
|
||||
\ 'skip_space' : 1,
|
||||
\ 'skip_char' : 0,
|
||||
\ 'highlight' : 3,
|
||||
\ 'hi_duration': 200,
|
||||
\ 'command' : [],
|
||||
\ 'linewise' : 0,
|
||||
\ }
|
||||
let s:default_values.delete.line = {
|
||||
\ 'cursor' : 'default',
|
||||
\ 'noremap' : 1,
|
||||
\ 'regex' : 0,
|
||||
\ 'skip_space' : 2,
|
||||
\ 'skip_char' : 0,
|
||||
\ 'highlight' : 3,
|
||||
\ 'hi_duration': 200,
|
||||
\ 'command' : [],
|
||||
\ 'linewise' : 1,
|
||||
\ }
|
||||
let s:default_values.delete.block = {
|
||||
\ 'cursor' : 'default',
|
||||
\ 'noremap' : 1,
|
||||
\ 'regex' : 0,
|
||||
\ 'skip_space' : 1,
|
||||
\ 'skip_char' : 0,
|
||||
\ 'highlight' : 3,
|
||||
\ 'hi_duration': 200,
|
||||
\ 'command' : [],
|
||||
\ 'linewise' : 0,
|
||||
\ }
|
||||
let s:default_values.delete.filter = printf('v:key =~# ''\%%(%s\)''', join(keys(s:default_values['delete']['char']), '\|'))
|
||||
|
||||
let s:default_values.replace = {}
|
||||
let s:default_values.replace.char = {
|
||||
\ 'cursor' : 'default',
|
||||
\ 'query_once' : 0,
|
||||
\ 'regex' : 0,
|
||||
\ 'expr' : 0,
|
||||
\ 'listexpr' : 0,
|
||||
\ 'noremap' : 1,
|
||||
\ 'skip_space' : 1,
|
||||
\ 'skip_char' : 0,
|
||||
\ 'highlight' : 3,
|
||||
\ 'hi_duration': 200,
|
||||
\ 'command' : [],
|
||||
\ 'linewise' : 0,
|
||||
\ 'autoindent' : -1,
|
||||
\ 'indentkeys' : 0,
|
||||
\ 'indentkeys+': 0,
|
||||
\ 'indentkeys-': 0,
|
||||
\ }
|
||||
let s:default_values.replace.line = {
|
||||
\ 'cursor' : 'default',
|
||||
\ 'query_once' : 0,
|
||||
\ 'regex' : 0,
|
||||
\ 'expr' : 0,
|
||||
\ 'listexpr' : 0,
|
||||
\ 'noremap' : 1,
|
||||
\ 'skip_space' : 2,
|
||||
\ 'skip_char' : 0,
|
||||
\ 'highlight' : 3,
|
||||
\ 'hi_duration': 200,
|
||||
\ 'command' : [],
|
||||
\ 'linewise' : 0,
|
||||
\ 'autoindent' : -1,
|
||||
\ 'indentkeys' : 0,
|
||||
\ 'indentkeys+': 0,
|
||||
\ 'indentkeys-': 0,
|
||||
\ }
|
||||
let s:default_values.replace.block = {
|
||||
\ 'cursor' : 'default',
|
||||
\ 'query_once' : 0,
|
||||
\ 'regex' : 0,
|
||||
\ 'expr' : 0,
|
||||
\ 'listexpr' : 0,
|
||||
\ 'noremap' : 1,
|
||||
\ 'skip_space' : 1,
|
||||
\ 'skip_char' : 0,
|
||||
\ 'highlight' : 3,
|
||||
\ 'hi_duration': 200,
|
||||
\ 'command' : [],
|
||||
\ 'linewise' : 0,
|
||||
\ 'autoindent' : -1,
|
||||
\ 'indentkeys' : 0,
|
||||
\ 'indentkeys+': 0,
|
||||
\ 'indentkeys-': 0,
|
||||
\ }
|
||||
let s:default_values.replace.filter = printf('v:key =~# ''\%%(%s\)''', join(keys(s:default_values['replace']['char']), '\|'))
|
||||
|
||||
let s:default_values.textobj = {}
|
||||
let s:default_values.textobj.auto = {
|
||||
\ 'expr' : 0,
|
||||
\ 'listexpr' : 0,
|
||||
\ 'regex' : 0,
|
||||
\ 'skip_regex' : [],
|
||||
\ 'skip_regex_head': [],
|
||||
\ 'skip_regex_tail': [],
|
||||
\ 'quoteescape' : 0,
|
||||
\ 'expand_range' : -1,
|
||||
\ 'nesting' : 0,
|
||||
\ 'synchro' : 1,
|
||||
\ 'noremap' : 1,
|
||||
\ 'syntax' : [],
|
||||
\ 'inner_syntax' : [],
|
||||
\ 'match_syntax' : 0,
|
||||
\ 'skip_break' : 0,
|
||||
\ 'skip_expr' : [],
|
||||
\ }
|
||||
let s:default_values.textobj.query = {
|
||||
\ 'expr' : 0,
|
||||
\ 'listexpr' : 0,
|
||||
\ 'regex' : 0,
|
||||
\ 'skip_regex' : [],
|
||||
\ 'skip_regex_head': [],
|
||||
\ 'skip_regex_tail': [],
|
||||
\ 'quoteescape' : 0,
|
||||
\ 'expand_range' : -1,
|
||||
\ 'nesting' : 0,
|
||||
\ 'synchro' : 1,
|
||||
\ 'noremap' : 1,
|
||||
\ 'syntax' : [],
|
||||
\ 'inner_syntax' : [],
|
||||
\ 'match_syntax' : 0,
|
||||
\ 'skip_break' : 0,
|
||||
\ 'skip_expr' : [],
|
||||
\ }
|
||||
let s:default_values.textobj.filter = printf('v:key =~# ''\%%(%s\)''', join(keys(s:default_values.textobj.auto), '\|'))
|
||||
"}}}
|
||||
|
||||
" vim:set foldmethod=marker:
|
||||
" vim:set commentstring="%s:
|
||||
" vim:set ts=2 sts=2 sw=2:
|
||||
@ -0,0 +1,41 @@
|
||||
function! sandwich#util#echo(messages) abort "{{{
|
||||
echo ''
|
||||
for [mes, hi_group] in a:messages
|
||||
execute 'echohl ' . hi_group
|
||||
echon mes
|
||||
echohl NONE
|
||||
endfor
|
||||
endfunction
|
||||
"}}}
|
||||
function! sandwich#util#addlocal(recipes) abort "{{{
|
||||
return s:extend_local(a:recipes)
|
||||
endfunction
|
||||
"}}}
|
||||
function! sandwich#util#insertlocal(recipes) abort "{{{
|
||||
return s:extend_local(a:recipes, 0)
|
||||
endfunction
|
||||
"}}}
|
||||
function! sandwich#util#ftrevert(filetype) abort "{{{
|
||||
if exists('b:sandwich_recipes')
|
||||
call filter(b:sandwich_recipes, 'get(v:val, "__filetype__", "") !=# a:filetype')
|
||||
endif
|
||||
endfunction
|
||||
"}}}
|
||||
|
||||
|
||||
function! s:extend_local(recipes, ...) abort "{{{
|
||||
if !exists('b:sandwich_recipes')
|
||||
if exists('g:sandwich#recipes')
|
||||
let b:sandwich_recipes = deepcopy(g:sandwich#recipes)
|
||||
else
|
||||
let b:sandwich_recipes = deepcopy(g:sandwich#default_recipes)
|
||||
endif
|
||||
endif
|
||||
let i = get(a:000, 0, len(b:sandwich_recipes))
|
||||
call extend(b:sandwich_recipes, copy(a:recipes), i)
|
||||
return b:sandwich_recipes
|
||||
endfunction "}}}
|
||||
|
||||
" vim:set foldmethod=marker:
|
||||
" vim:set commentstring="%s:
|
||||
" vim:set ts=2 sts=2 sw=2:
|
||||
Reference in New Issue
Block a user