TypeVim is a plugin built to make object-oriented programming in VimL easier. It provides helper functions that allow users to more easily define their own types, define polymorphic types, and preserve class invariants within instances of those types.
It also includes some goodies, like a bind
function; a pretty-printer for
lists, dictionaries, and Partials (even when these objects are
self-referencing); an object-oriented wrapper
around vim buffers; and a roughly A+ compliant
implementation of Promises, all in pure VimL.
I wrote this plugin to cut down on boilerplate in my other plugins, not necessarily because I expect others to use it (though they're certainly free to do so, if they wish!). There do exist other plugins to fill this niche, but those I could find seem unmaintained and largely disused: the examples I've just linked haven't been updated in around a decade, as of the time of writing.
Be warned that TypeVim is still in alpha, and that I make no guarantees of API stability at this time.
TypeVim requires at least Vim 7.4.1842, or practically any recent version of neovim.
That said, it is strongly recommended that you use at least Vim 8.1.0039,
which is the earliest version of Vim that supports deletebufline()
. Without
this function, TypeVim's Buffer
object will use a crude fallback
implementation when modifying lines in the wrapped buffer.
TypeVim depends on vim-maktaba.
With vim-plug,
call plug#begin('~/.vim/bundle')
" ...
Plug 'Yilin-Yang/TypeVim'
" dependencies
Plug 'Google/vim-maktaba'
" ...
call plug#end()
TypeVim also includes an addon-info.json
file, allowing for dependency resolution (i.e. automatic installation of
vim-maktaba
) in compatible plugin managers.
If you have the time, read through all of :help TypeVim
.
If you want to get up to speed quickly, then:
If using TypeVim for class writing, skim :help TypeVim-summary
(for
a broad overview of TypeVim's class system) and :help TypeVim-make
(for info
on writing classes). Actual use would look something like:
"===================================
" myplugin/autoload/myplugin/Foo.vim
let s:typename = 'Foo'
function! myplugin#Foo#New(number) abort
call maktaba#ensure#IsNumber(a:number)
let l:prototype = {
\ '__number': a:number,
\ 'Func': typevim#make#Member('MemberFunc'),
\ }
return typevim#make#Class(
\ s:typename, l:prototype, typevim#make#Member('CleanUp'))
endfunction
function! s:CheckType(Obj) abort
call typevim#ensure#IsType(a:Obj, s:typename)
endfunction
function! myplugin#Foo#CleanUp() dict abort
call s:CheckType(l:self)
" delete all instances of the word 'trash' from the current buffer
%s/trash//ge
endfunction
function! myplugin#Foo#MemberFunc() dict abort
call s:CheckType(l:self)
echo l:self['__number']
endfunction
"=============================
" myplugin/plugin/myplugin.vim
let g:foo_instance = myplugin#Foo#New(3)
call g:foo_instance.Func() " prints 3
If using TypeVim for its object-oriented Buffer
wrapper, skim :help TypeVim.Buffer
. Actual use would look something like this:
" creating a new vim buffer 'NewlyMade.txt' and then wrapping it,
let buffer_obj = typevim#Buffer#New({'bufname': 'NewlyMade.txt'})
" OR, giving the object ownership of the buffer with |bufnr| 2 and renaming
" it 'Existing.txt',
let buffer_obj = typevim#Buffer#New({'bufname': 'Existing.txt', 'bufnr': 2})
call buffer_obj.InsertLines(0, ['foo', 'bar']) " prepend
" buffer now contains:
" foo
" bar
call buffer_obj.InsertLines('$', ['goo', 'gar']) " append
" buffer now contains:
" foo
" bar
" goo
" gar
call buffer_obj.ReplaceLines(1, -1, []) " note negative indexing on {endline}
" buffer is now empty
call buffer_obj.Open() " open buffer in current window
" OR,
call buffer_obj.Switch() " switch to a window that has this buffer open
call buffer_obj.CleanUp() " bwipeout the buffer object
Documentation is generated using vimdoc.
# from project root, after installing vimdoc,
vimdoc .
TypeVim uses vader.vim as its testing framework. To run tests,
# from project root, with `vader.vim` installed,
cd test
./run_tests.sh
Tests are either "regular" or "standalone." On a typical run, all regular tests will run in a single vim instance; after that instance exits, each standalone test will run sequentially, a new vim instance being started for each one. This is to help prevent side effects from altering the outcome of other tests.
See ./run_tests --help
for additional usage details.
# an example of ./run_tests.sh use that may be more useful during development:
# run all tests in "visible" interactive neovim instances, using the given
# neovim executable
./run_tests.sh -v --neovim -e /usr/local/bin/nvim
Issue reports are welcome and encouraged, despite the project's early development status. These can be feature requests, defect reports, or even spelling and grammar fixes, since I haven't proofread the docs as thoroughly as I might like.
Pull requests are also welcome, though I'd encourage you to open an Issue first, so that I can offer feedback. I might reject pull requests for arbitrary reasons (e.g. if the given feature doesn't align with (undocumented) "project goals," or is implemented in a way that I think is cumbersome), but I would hate to reject a PR after somebody's put major effort into making it work.
MIT