1
0
mirror of https://github.com/SpaceVim/SpaceVim.git synced 2025-01-24 09:50:04 +08:00
SpaceVim/bundle/unite.vim/autoload/unite/action.vim
2020-06-13 14:06:35 +08:00

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