I have implemented a mecanism for this in lh-dev (a library plugin dedicated to this kind of issues -- generic functions for generic plugins that can be specialized on filetype basis, which I abusively call "ft-polymorphism"). I use it in my generic refactoring plugin, and to automate the insertion of import
/#include
in mu-template snippets.
How does it works ?
- I usually have a generic front-end function, let's say
lh#dev#domain#verb()
when I follow something like the NVI pattern (from C++), but I may also not have this function and directly call the variation point from an unrelated function as I would do with the template method design pattern.
- I may have a default implementation (I don't remember the name I've chosen)
- and I have a few specialisations, for instance:
lh#dev#cpp#domain#verb()
, lh#dev#vim#domain#verb()
, and so on.
Then I call the right function, from lh#dev#domain#verb()
, thank to lh#dev#options#call('domain#verb', &ft, param1, param2...)
that looks like this:
" Function: lh#dev#option#call(name, filetype, [, parameters]) {{{2
" @return lh#dev#{ft}#{name}({parameters}) if it exists, or
" lh#dev#{name}({parameters}) otherwise
" If {name} is a |List|, then the function name used is: {name}[0]#{ft}#{name}[1]
function! lh#dev#option#call(name, ft, ...) abort
if type(a:name) == type([])
let prefix = a:name[0]
let name = a:name[1]
elseif type(a:name) == type('string')
let prefix = 'lh#dev'
let name = a:name
else
throw "Unexpected type (".type(a:name).") for name parameter"
endif
let fts = lh#dev#option#inherited_filetypes(a:ft)
call map(fts, 'v:val."#"')
let fts += ['']
for ft in fts
let fname = prefix.'#'.ft.name
if !exists('*'.fname)
let file = substitute(fname, '#', '/', 'g')
let file = substitute(file, '.*\zs/.*', '.vim', '')
exe 'runtime autoload/'.file
endif
if exists('*'.fname) | break | endif
endfor
call s:Verbose('Calling: %1(%2)', fname, a:000)
if s:verbose >= 2
debug return call (function(fname), a:000)
else
return call (function(fname), a:000)
endif
endfunction
The caveat? The :for
loop is a nightmare when I'm debugging.
For more explanations on the topic, see it's related documentation: https://github.com/LucHermitte/lh-dev#filetype-polymorphism . Notes: lh#def#option#get()
has been moved to lh#ft#option#get()
for dependency issues, it also supports my new project variables p:foobar
(which act as shared b:variables
).
Also note that if namespace#cpp#domain#funcname()
doesn't exist, this function will try to execute namespace#c#domain#funcname()
. A feature I've named filetype inheritance (I wasn't inspired ^^').
ftplugin/<filetype>.vim
?