mirror of
https://github.com/SpaceVim/SpaceVim.git
synced 2025-01-24 09:50:04 +08:00
548 lines
16 KiB
VimL
548 lines
16 KiB
VimL
"=============================================================================
|
|
" FILE: action.vim
|
|
" AUTHOR: Shougo Matsushita <Shougo.Matsu@gmail.com>
|
|
" License: MIT license
|
|
"=============================================================================
|
|
|
|
let s:save_cpo = &cpo
|
|
set cpo&vim
|
|
|
|
function! unite#action#get_action_table(source_name, kind, self_func, ...) abort "{{{
|
|
let is_parents_action = get(a:000, 0, 0)
|
|
let source_table = get(a:000, 1, {})
|
|
|
|
let action_table = {}
|
|
for kind_name in unite#util#convert2list(a:kind)
|
|
call extend(action_table,
|
|
\ s:get_action_table(a:source_name,
|
|
\ kind_name, a:self_func,
|
|
\ is_parents_action, source_table))
|
|
endfor
|
|
|
|
return action_table
|
|
endfunction"}}}
|
|
|
|
function! unite#action#get_alias_table(source_name, kind, ...) abort "{{{
|
|
let source_table = get(a:000, 0, {})
|
|
let alias_table = {}
|
|
for kind_name in unite#util#convert2list(a:kind)
|
|
call extend(alias_table,
|
|
\ s:get_alias_table(a:source_name, kind_name, source_table))
|
|
endfor
|
|
|
|
return alias_table
|
|
endfunction"}}}
|
|
|
|
function! unite#action#get_default_action(source_name, kind) abort "{{{
|
|
let kinds = unite#util#convert2list(a:kind)
|
|
|
|
return s:get_default_action(a:source_name, kinds[-1])
|
|
endfunction"}}}
|
|
|
|
function! s:get_action_table(source_name, kind_name, self_func, is_parents_action, source_table) abort "{{{
|
|
let kind = unite#get_kinds(a:kind_name)
|
|
let source = empty(a:source_table) ?
|
|
\ unite#get_sources(a:source_name) :
|
|
\ unite#util#get_name(a:source_table, a:source_name, {})
|
|
if empty(source)
|
|
call unite#print_error('source "' . a:source_name . '" is not found.')
|
|
return {}
|
|
endif
|
|
if empty(kind)
|
|
call unite#print_error('kind "' . a:kind_name . '" is not found.')
|
|
return {}
|
|
endif
|
|
|
|
let action_table = {}
|
|
|
|
let source_kind = 'source/'.a:source_name.'/'.a:kind_name
|
|
let source_kind_wild = 'source/'.a:source_name.'/*'
|
|
|
|
let custom = unite#custom#get()
|
|
|
|
if !a:is_parents_action
|
|
" Source/kind custom actions.
|
|
if has_key(custom.actions, source_kind)
|
|
let action_table = s:extend_actions(a:self_func, action_table,
|
|
\ custom.actions[source_kind], 'custom/'.source.name.'/'.kind.name)
|
|
endif
|
|
|
|
" Source/kind actions.
|
|
if has_key(source.action_table, a:kind_name)
|
|
let action_table = s:extend_actions(a:self_func, action_table,
|
|
\ source.action_table[a:kind_name], source.name.'/'.kind.name)
|
|
endif
|
|
|
|
" Source/* custom actions.
|
|
if has_key(custom.actions, source_kind_wild)
|
|
let action_table = s:extend_actions(a:self_func, action_table,
|
|
\ custom.actions[source_kind_wild], 'custom/source/'.source.name)
|
|
endif
|
|
|
|
" Source/* actions.
|
|
if has_key(source.action_table, '*')
|
|
let action_table = s:extend_actions(a:self_func, action_table,
|
|
\ source.action_table['*'], 'source/'.source.name)
|
|
endif
|
|
|
|
" Kind custom actions.
|
|
if has_key(custom.actions, a:kind_name)
|
|
let action_table = s:extend_actions(a:self_func, action_table,
|
|
\ custom.actions[a:kind_name], 'custom/'.kind.name)
|
|
endif
|
|
|
|
" Kind actions.
|
|
let action_table = s:extend_actions(a:self_func, action_table,
|
|
\ kind.action_table, kind.name)
|
|
endif
|
|
|
|
" Parents actions.
|
|
for parent in source.parents
|
|
let parent_kind = unite#get_kinds(parent)
|
|
let action_table = s:extend_actions(a:self_func, action_table,
|
|
\ parent_kind.action_table, parent)
|
|
endfor
|
|
for parent in kind.parents
|
|
let action_table = s:extend_actions(a:self_func, action_table,
|
|
\ unite#action#get_action_table(a:source_name, parent,
|
|
\ a:self_func, 0, a:source_table))
|
|
endfor
|
|
|
|
if !a:is_parents_action
|
|
" Kind aliases.
|
|
call s:filter_alias_action(action_table, kind.alias_table,
|
|
\ kind.name)
|
|
|
|
" Kind custom aliases.
|
|
if has_key(custom.aliases, a:kind_name)
|
|
call s:filter_alias_action(action_table, custom.aliases[a:kind_name],
|
|
\ 'custom/'.kind.name)
|
|
endif
|
|
|
|
" Source/* aliases.
|
|
if has_key(source.alias_table, '*')
|
|
call s:filter_alias_action(action_table, source.alias_table['*'],
|
|
\ 'source/'.source.name)
|
|
endif
|
|
|
|
" Source/* custom aliases.
|
|
if has_key(custom.aliases, source_kind_wild)
|
|
call s:filter_alias_action(action_table, custom.aliases[source_kind_wild],
|
|
\ 'custom/source/'.source.name)
|
|
endif
|
|
|
|
" Source/kind aliases.
|
|
if has_key(custom.aliases, source_kind)
|
|
call s:filter_alias_action(action_table, custom.aliases[source_kind],
|
|
\ 'source/'.source.name.'/'.kind.name)
|
|
endif
|
|
|
|
" Source/kind custom aliases.
|
|
if has_key(source.alias_table, a:kind_name)
|
|
call s:filter_alias_action(action_table, source.alias_table[a:kind_name],
|
|
\ 'custom/source/'.source.name.'/'.kind.name)
|
|
endif
|
|
endif
|
|
|
|
" Initialize action.
|
|
for [action_name, action] in items(action_table)
|
|
if !has_key(action, 'name')
|
|
let action.name = action_name
|
|
endif
|
|
if !has_key(action, 'from')
|
|
let action.from = ''
|
|
endif
|
|
if !has_key(action, 'description')
|
|
let action.description = ''
|
|
endif
|
|
if !has_key(action, 'is_quit')
|
|
let action.is_quit = 1
|
|
endif
|
|
if !has_key(action, 'is_start')
|
|
let action.is_start = 0
|
|
endif
|
|
if !has_key(action, 'is_tab')
|
|
let action.is_tab = 0
|
|
endif
|
|
if !has_key(action, 'is_selectable')
|
|
let action.is_selectable = 0
|
|
endif
|
|
if !has_key(action, 'is_invalidate_cache')
|
|
let action.is_invalidate_cache = 0
|
|
endif
|
|
if !has_key(action, 'is_listed')
|
|
let action.is_listed =
|
|
\ (action.name !~ '^unite__\|^vimfiler__')
|
|
endif
|
|
endfor
|
|
|
|
" Filtering nop action.
|
|
return filter(action_table, 'v:key !=# "nop"')
|
|
endfunction"}}}
|
|
|
|
function! s:get_alias_table(source_name, kind_name, source_table) abort "{{{
|
|
let kind = unite#get_kinds(a:kind_name)
|
|
let source = empty(a:source_table) ?
|
|
\ unite#get_sources(a:source_name) :
|
|
\ unite#util#get_name(a:source_table, a:source_name, {})
|
|
if empty(source)
|
|
call unite#print_error('source "' . a:source_name . '" is not found.')
|
|
return {}
|
|
endif
|
|
|
|
let table = kind.alias_table
|
|
|
|
let source_kind = 'source/'.a:source_name.'/'.a:kind_name
|
|
let source_kind_wild = 'source/'.a:source_name.'/*'
|
|
|
|
let custom = unite#custom#get()
|
|
|
|
" Kind custom aliases.
|
|
if has_key(custom.aliases, a:kind_name)
|
|
let table = extend(table, custom.aliases[a:kind_name])
|
|
endif
|
|
|
|
" Source/* aliases.
|
|
if has_key(source.alias_table, '*')
|
|
let table = extend(table, source.alias_table['*'])
|
|
endif
|
|
|
|
" Source/* custom aliases.
|
|
if has_key(custom.aliases, source_kind_wild)
|
|
let table = extend(table, custom.aliases[source_kind_wild])
|
|
endif
|
|
|
|
" Source/kind aliases.
|
|
if has_key(custom.aliases, source_kind)
|
|
let table = extend(table, custom.aliases[source_kind])
|
|
endif
|
|
|
|
" Source/kind custom aliases.
|
|
if has_key(source.alias_table, a:kind_name)
|
|
let table = extend(table, source.alias_table[a:kind_name])
|
|
endif
|
|
|
|
return table
|
|
endfunction"}}}
|
|
|
|
function! s:get_default_action(source_name, kind_name) abort "{{{
|
|
let source = unite#get_all_sources(a:source_name)
|
|
if empty(source)
|
|
return ''
|
|
endif
|
|
|
|
let source_kind = 'source/'.a:source_name.'/'.a:kind_name
|
|
let source_kind_wild = 'source/'.a:source_name.'/*'
|
|
|
|
let custom = unite#custom#get()
|
|
|
|
" Source/kind custom default actions.
|
|
if has_key(custom.default_actions, source_kind)
|
|
return custom.default_actions[source_kind]
|
|
endif
|
|
|
|
" Source custom default actions.
|
|
if has_key(source.default_action, a:kind_name)
|
|
return source.default_action[a:kind_name]
|
|
endif
|
|
|
|
" Source/* custom default actions.
|
|
if has_key(custom.default_actions, source_kind_wild)
|
|
return custom.default_actions[source_kind_wild]
|
|
endif
|
|
|
|
" Source/* default actions.
|
|
if has_key(source.default_action, '*')
|
|
return source.default_action['*']
|
|
endif
|
|
|
|
" Kind custom default actions.
|
|
if has_key(custom.default_actions, a:kind_name)
|
|
return custom.default_actions[a:kind_name]
|
|
endif
|
|
|
|
" Kind default actions.
|
|
let kind = unite#get_kinds(a:kind_name)
|
|
return get(kind, 'default_action', '')
|
|
endfunction"}}}
|
|
|
|
function! unite#action#take(action_name, candidate, is_parent_action) abort "{{{
|
|
let candidate_head = type(a:candidate) == type([]) ?
|
|
\ a:candidate[0] : a:candidate
|
|
|
|
let action_table = unite#action#get_action_table(
|
|
\ candidate_head.source, candidate_head.kind,
|
|
\ unite#get_self_functions()[-3], a:is_parent_action)
|
|
|
|
let action_name =
|
|
\ a:action_name ==# 'default' ?
|
|
\ unite#action#get_default_action(
|
|
\ candidate_head.source, candidate_head.kind)
|
|
\ : a:action_name
|
|
|
|
if !has_key(action_table, action_name)
|
|
" throw 'unite.vim: no such action ' . action_name
|
|
return 1
|
|
endif
|
|
|
|
let action = action_table[action_name]
|
|
" Convert candidates.
|
|
call action.func(
|
|
\ (action.is_selectable && type(a:candidate) != type([])) ?
|
|
\ [a:candidate] : a:candidate)
|
|
endfunction"}}}
|
|
|
|
function! unite#action#do(action_name, ...) abort "{{{
|
|
if &filetype == 'vimfiler' && has_key(b:vimfiler, 'unite')
|
|
" Restore unite condition in vimfiler.
|
|
call unite#set_current_unite(b:vimfiler.unite)
|
|
endif
|
|
|
|
call unite#redraw()
|
|
|
|
let candidates = empty(a:000) ?
|
|
\ unite#helper#get_marked_candidates() : a:1
|
|
let new_context = get(a:000, 1, {})
|
|
let sources = get(a:000, 2, {})
|
|
|
|
let unite = unite#get_current_unite()
|
|
if empty(candidates)
|
|
if empty(unite#helper#get_current_candidate())
|
|
" Ignore.
|
|
return []
|
|
endif
|
|
|
|
let candidates = [ unite#helper#get_current_candidate() ]
|
|
endif
|
|
|
|
let candidates = filter(copy(candidates),
|
|
\ "!empty(v:val) && !get(v:val, 'is_dummy', 0)")
|
|
if empty(candidates)
|
|
return []
|
|
endif
|
|
|
|
let action_tables = s:get_candidates_action_table(
|
|
\ a:action_name, candidates, sources)
|
|
|
|
let old_context = {}
|
|
if !empty(new_context)
|
|
" Set new context.
|
|
let new_context = extend(
|
|
\ deepcopy(unite#get_context()), new_context)
|
|
let old_context = unite#set_context(new_context)
|
|
let unite = unite#get_current_unite()
|
|
endif
|
|
|
|
" Execute action.
|
|
let is_quit = 0
|
|
let is_redraw = 0
|
|
let _ = []
|
|
for table in action_tables
|
|
if a:action_name !=# 'preview'
|
|
\ && !empty(unite#helper#get_marked_candidates())
|
|
call s:clear_marks(candidates)
|
|
call unite#force_redraw()
|
|
let is_redraw = 0
|
|
endif
|
|
|
|
" Check quit flag.
|
|
if table.action.is_quit && unite.profile_name !=# 'action'
|
|
\ && !table.action.is_start
|
|
\ && !(table.action.is_tab && !unite.context.quit)
|
|
call unite#all_quit_session(0)
|
|
if unite.context.file_quit && &buftype =~# 'nofile'
|
|
" Switch to file buffer.
|
|
let winnr = get(filter(range(1, winnr('$')),
|
|
\ "getwinvar(v:val, '&buftype') !~# 'nofile'"), 0, 0)
|
|
if winnr > 0
|
|
execute winnr.'wincmd w'
|
|
endif
|
|
endif
|
|
let is_quit = 1
|
|
endif
|
|
|
|
try
|
|
call add(_, table.action.func(table.candidates))
|
|
catch /^Vim\%((\a\+)\)\=:E325/
|
|
let save_shortmess = &shortmess
|
|
try
|
|
set shortmess+=A " Ignore 'SwapExists' and try again.
|
|
call add(_, table.action.func(table.candidates))
|
|
finally
|
|
let &shortmess = save_shortmess
|
|
endtry
|
|
catch
|
|
call unite#print_error(v:throwpoint)
|
|
call unite#print_error(v:exception)
|
|
call unite#print_error(
|
|
\ 'Error occurred while executing "'.table.action.name.'" action!')
|
|
endtry
|
|
|
|
" Executes command.
|
|
if unite.context.execute_command != ''
|
|
execute unite.context.execute_command
|
|
endif
|
|
|
|
" Check invalidate cache flag.
|
|
if table.action.is_invalidate_cache
|
|
for source_name in table.source_names
|
|
call unite#helper#invalidate_cache(source_name)
|
|
endfor
|
|
|
|
let is_redraw = 1
|
|
endif
|
|
endfor
|
|
|
|
if (!is_quit || !unite.context.quit) && unite.context.keep_focus
|
|
let winnr = bufwinnr(unite.bufnr)
|
|
|
|
if winnr > 0
|
|
" Restore focus.
|
|
execute winnr 'wincmd w'
|
|
endif
|
|
endif
|
|
|
|
if !empty(new_context)
|
|
" Restore context.
|
|
let unite.context = old_context
|
|
endif
|
|
|
|
if is_redraw && !empty(filter(range(1, winnr('$')),
|
|
\ "getwinvar(v:val, '&filetype') ==# 'vimfiler'"))
|
|
" Redraw vimfiler buffer.
|
|
call vimfiler#force_redraw_all_vimfiler(1)
|
|
endif
|
|
|
|
if !is_quit && is_redraw
|
|
call s:clear_marks(candidates)
|
|
call unite#force_redraw()
|
|
endif
|
|
|
|
if unite.context.unite__is_manual
|
|
call unite#sources#history_unite#add(unite)
|
|
endif
|
|
|
|
return _
|
|
endfunction"}}}
|
|
|
|
function! unite#action#do_candidates(action_name, candidates, ...) abort "{{{
|
|
let context = get(a:000, 0, {})
|
|
let sources = get(a:000, 1, [])
|
|
let context = unite#init#_context(context)
|
|
let context.unite__is_interactive = 0
|
|
let context.unite__disable_hooks = 1
|
|
call unite#init#_current_unite(sources, context)
|
|
|
|
return unite#action#do(
|
|
\ a:action_name, a:candidates, context,
|
|
\ values(unite#get_all_sources()))
|
|
endfunction"}}}
|
|
|
|
function! unite#action#_get_candidate_action_table(candidate, sources) abort "{{{
|
|
return unite#action#get_action_table(
|
|
\ a:candidate.source, a:candidate.kind,
|
|
\ unite#get_self_functions()[-1], 0, a:sources)
|
|
endfunction"}}}
|
|
|
|
function! s:get_candidates_action_table(action_name, candidates, sources) abort "{{{
|
|
let action_tables = []
|
|
for candidate in a:candidates
|
|
let action_table = unite#action#_get_candidate_action_table(
|
|
\ candidate, a:sources)
|
|
|
|
let action_name = a:action_name
|
|
if action_name ==# 'default'
|
|
" Get default action.
|
|
let action_name = unite#action#get_default_action(
|
|
\ candidate.source, candidate.kind)
|
|
endif
|
|
|
|
if action_name == ''
|
|
" Ignore.
|
|
return []
|
|
endif
|
|
|
|
if !has_key(action_table, action_name)
|
|
call unite#util#print_error(
|
|
\ candidate.unite__abbr . '(' . candidate.source . ')')
|
|
call unite#util#print_error(
|
|
\ 'No such action : ' . action_name)
|
|
|
|
return []
|
|
endif
|
|
|
|
let action = action_table[action_name]
|
|
|
|
" Check selectable flag.
|
|
if !action.is_selectable && len(a:candidates) > 1
|
|
call unite#util#print_error(
|
|
\ candidate.unite__abbr . '(' . candidate.source . ')')
|
|
call unite#util#print_error(
|
|
\ 'Not selectable action : ' . action_name)
|
|
return []
|
|
endif
|
|
|
|
let found = 0
|
|
for table in action_tables
|
|
if action == table.action
|
|
" Add list.
|
|
call add(table.candidates, candidate)
|
|
call add(table.source_names, candidate.source)
|
|
let found = 1
|
|
break
|
|
endif
|
|
endfor
|
|
|
|
if !found
|
|
" Add action table.
|
|
call add(action_tables, {
|
|
\ 'action' : action,
|
|
\ 'source_names' : [candidate.source],
|
|
\ 'candidates' : (!action.is_selectable ? candidate : [candidate]),
|
|
\ })
|
|
endif
|
|
endfor
|
|
|
|
return action_tables
|
|
endfunction"}}}
|
|
|
|
function! s:extend_actions(self_func, action_table1, action_table2, ...) abort "{{{
|
|
let filterd_table = s:filter_self_func(a:action_table2, a:self_func)
|
|
|
|
if a:0 > 0
|
|
for action in values(filterd_table)
|
|
let action.from = a:1
|
|
endfor
|
|
endif
|
|
|
|
return extend(a:action_table1, filterd_table, 'keep')
|
|
endfunction"}}}
|
|
function! s:filter_alias_action(action_table, alias_table, from) abort "{{{
|
|
for [alias_name, alias_action] in items(a:alias_table)
|
|
if alias_action ==# 'nop'
|
|
if has_key(a:action_table, alias_name)
|
|
" Delete nop action.
|
|
call remove(a:action_table, alias_name)
|
|
endif
|
|
elseif has_key(a:action_table, alias_action)
|
|
let a:action_table[alias_name] = copy(a:action_table[alias_action])
|
|
let a:action_table[alias_name].from = a:from
|
|
let a:action_table[alias_name].name = alias_name
|
|
endif
|
|
endfor
|
|
endfunction"}}}
|
|
function! s:filter_self_func(action_table, self_func) abort "{{{
|
|
return filter(copy(a:action_table),
|
|
\ printf("string(v:val.func) !=# \"function('%s')\"", a:self_func))
|
|
endfunction"}}}
|
|
function! s:clear_marks(candidates) abort "{{{
|
|
for candidate in a:candidates
|
|
let candidate.unite__is_marked = 0
|
|
endfor
|
|
endfunction"}}}
|
|
|
|
let &cpo = s:save_cpo
|
|
unlet s:save_cpo
|
|
|
|
" vim: foldmethod=marker
|