543 lines
18 KiB
VimL
543 lines
18 KiB
VimL
scriptencoding utf-8
|
||
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
|
||
" AutoClose.vim - Automatically close pair of characters: ( with ), [ with ], { with }, etc.
|
||
" Version: 2.0
|
||
" Author: Thiago Alves <talk@thiagoalves.com.br>
|
||
" Maintainer: Thiago Alves <talk@thiagoalves.com.br>
|
||
" URL: http://thiagoalves.com.br
|
||
" Licence: This script is released under the Vim License.
|
||
" Last modified: 02/02/2011
|
||
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
|
||
|
||
" check if script is already loaded
|
||
if !exists("g:debug_AutoClose") && exists("g:loaded_AutoClose")
|
||
finish "stop loading the script"
|
||
endif
|
||
let g:loaded_AutoClose = 1
|
||
|
||
let s:global_cpo = &cpo " store compatible-mode in local variable
|
||
set cpo&vim " go into nocompatible-mode
|
||
|
||
if !exists('g:AutoClosePreserveDotReg')
|
||
let g:AutoClosePreserveDotReg = 1
|
||
endif
|
||
|
||
if g:AutoClosePreserveDotReg
|
||
" Because dot register preservation code remaps escape we have to remap
|
||
" some terminal specific escape sequences first
|
||
if &term =~ 'xterm' || &term =~ 'rxvt' || &term =~ 'screen' || &term =~ 'linux' || &term =~ 'gnome'
|
||
imap <silent> <Esc>OA <Up>
|
||
imap <silent> <Esc>OB <Down>
|
||
imap <silent> <Esc>OC <Right>
|
||
imap <silent> <Esc>OD <Left>
|
||
imap <silent> <Esc>OH <Home>
|
||
imap <silent> <Esc>OF <End>
|
||
imap <silent> <Esc>[5~ <PageUp>
|
||
imap <silent> <Esc>[6~ <PageDown>
|
||
endif
|
||
endif
|
||
|
||
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
|
||
" Functions
|
||
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
|
||
function! s:GetCharAhead(len)
|
||
if col('$') == col('.')
|
||
return "\0"
|
||
endif
|
||
return strpart(getline('.'), col('.')-2 + a:len, 1)
|
||
endfunction
|
||
|
||
function! s:GetCharBehind(len)
|
||
if col('.') == 1
|
||
return "\0"
|
||
endif
|
||
return strpart(getline('.'), col('.') - (1 + a:len), 1)
|
||
endfunction
|
||
|
||
function! s:GetNextChar()
|
||
return s:GetCharAhead(1)
|
||
endfunction
|
||
|
||
function! s:GetPrevChar()
|
||
return s:GetCharBehind(1)
|
||
endfunction
|
||
|
||
" used to implement automatic deletion of closing character when opening
|
||
" counterpart is deleted and by space expansion
|
||
function! s:IsEmptyPair()
|
||
let l:prev = s:GetPrevChar()
|
||
let l:next = s:GetNextChar()
|
||
return (l:next != "\0") && (get(b:AutoClosePairs, l:prev, "\0") == l:next)
|
||
endfunction
|
||
|
||
function! s:GetCurrentSyntaxRegion()
|
||
return synIDattr(synIDtrans(synID(line('.'), col('.'), 1)), 'name')
|
||
endfunction
|
||
|
||
function! s:GetCurrentSyntaxRegionIf(char)
|
||
let l:origin_line = getline('.')
|
||
let l:changed_line = strpart(l:origin_line, 0, col('.')-1) . a:char . strpart(l:origin_line, col('.')-1)
|
||
call setline('.', l:changed_line)
|
||
let l:region = synIDattr(synIDtrans(synID(line('.'), col('.'), 1)), 'name')
|
||
call setline('.', l:origin_line)
|
||
return l:region
|
||
endfunction
|
||
|
||
function! s:IsForbidden(char)
|
||
let l:result = index(b:AutoCloseProtectedRegions, s:GetCurrentSyntaxRegion()) >= 0
|
||
if l:result
|
||
return l:result
|
||
endif
|
||
let l:region = s:GetCurrentSyntaxRegionIf(a:char)
|
||
let l:result = index(b:AutoCloseProtectedRegions, l:region) >= 0
|
||
return l:result || l:region == 'Comment'
|
||
endfunction
|
||
|
||
function! s:AllowQuote(char, isBS)
|
||
let l:result = 1
|
||
if b:AutoCloseSmartQuote
|
||
let l:initPos = 1 + (a:isBS ? 1 : 0)
|
||
let l:charBehind = s:GetCharBehind(l:initPos)
|
||
let l:prev = l:charBehind
|
||
let l:backSlashCount = 0
|
||
while l:charBehind == '\'
|
||
let l:backSlashCount = l:backSlashCount + 1
|
||
let l:charBehind = s:GetCharBehind(l:initPos + l:backSlashCount)
|
||
endwhile
|
||
|
||
if l:backSlashCount % 2
|
||
let l:result = 0
|
||
else
|
||
if a:char == "'" && l:prev =~ '[a-zA-Z0-9]'
|
||
let l:result = 0
|
||
endif
|
||
endif
|
||
endif
|
||
return l:result
|
||
endfunction
|
||
|
||
function! s:CountQuotes(char)
|
||
let l:currPos = col('.')-1
|
||
let l:line = strpart(getline('.'), 0, l:currPos)
|
||
let l:result = 0
|
||
|
||
if l:currPos >= 0
|
||
for [q,closer] in items(b:AutoClosePairs)
|
||
" only consider twin pairs
|
||
if q != closer | continue | endif
|
||
|
||
if b:AutoCloseSmartQuote != 0
|
||
let l:regex = q . '[ˆ\\' . q . ']*(\\.[ˆ\\' . q . ']*)*' . q
|
||
else
|
||
let l:regex = q . '[ˆ' . q . ']*' . q
|
||
endif
|
||
|
||
let l:closedQuoteIdx = match(l:line, l:regex)
|
||
while l:closedQuoteIdx >= 0
|
||
let l:matchedStr = matchstr(l:line, l:regex, l:closedQuoteIdx)
|
||
let l:line = strpart(l:line, 0, l:closedQuoteIdx) . strpart(l:line, l:closedQuoteIdx + strlen(l:matchedStr))
|
||
let l:closedQuoteIdx = match(l:line, l:regex)
|
||
endwhile
|
||
endfor
|
||
|
||
for c in split(l:line, '\zs')
|
||
if c == a:char
|
||
let l:result = l:result + 1
|
||
endif
|
||
endfor
|
||
endif
|
||
return l:result
|
||
endfunction
|
||
|
||
" The auto-close buffer is used in a fix of the redo functionality.
|
||
" As we insert characters after cursor, we remember them and at the moment
|
||
" that vim would normally collect the last entered string into dot register
|
||
" (:help ".) - i.e. when esc or a motion key is typed in insert mode - we
|
||
" erase the inserted symbols and pretend that we have just now typed them.
|
||
" This way vim picks them up into dot register as well and user can repeat the
|
||
" typed bit with . command.
|
||
function! s:PushBuffer(char)
|
||
if !exists("b:AutoCloseBuffer")
|
||
let b:AutoCloseBuffer = []
|
||
endif
|
||
call insert(b:AutoCloseBuffer, a:char)
|
||
endfunction
|
||
|
||
function! s:PopBuffer()
|
||
if exists("b:AutoCloseBuffer") && len(b:AutoCloseBuffer) > 0
|
||
call remove(b:AutoCloseBuffer, 0)
|
||
endif
|
||
endfunction
|
||
|
||
function! s:EmptyBuffer()
|
||
if exists("b:AutoCloseBuffer")
|
||
let b:AutoCloseBuffer = []
|
||
endif
|
||
endfunction
|
||
|
||
function! s:FlushBuffer()
|
||
let l:result = ''
|
||
if exists("b:AutoCloseBuffer")
|
||
let l:len = len(b:AutoCloseBuffer)
|
||
if l:len > 0
|
||
let l:result = join(b:AutoCloseBuffer, '') . repeat("\<Left>", l:len)
|
||
let b:AutoCloseBuffer = []
|
||
call s:EraseNCharsAtCursor(l:len)
|
||
endif
|
||
endif
|
||
return l:result
|
||
endfunction
|
||
|
||
function! s:InsertStringAtCursor(str)
|
||
let l:line = getline('.')
|
||
let l:column = col('.')-2
|
||
|
||
if l:column < 0
|
||
call setline('.', a:str . l:line)
|
||
else
|
||
call setline('.', l:line[:l:column] . a:str . l:line[l:column+1:])
|
||
endif
|
||
endfunction
|
||
|
||
function! s:EraseNCharsAtCursor(len)
|
||
let l:line = getline('.')
|
||
let l:column = col('.')-2
|
||
|
||
if l:column < 0
|
||
call setline('.', l:line[a:len + 1:])
|
||
else
|
||
call setline('.', l:line[:l:column] . l:line[l:column + a:len + 1:])
|
||
endif
|
||
endfunction
|
||
|
||
" returns the opener, after having inserted its closer if necessary
|
||
function! s:InsertPair(opener)
|
||
if ! b:AutoCloseOn || ! has_key(b:AutoClosePairs, a:opener) || s:IsForbidden(a:opener)
|
||
return a:opener
|
||
endif
|
||
|
||
let l:save_ve = &ve
|
||
set ve=all
|
||
|
||
let l:next = s:GetNextChar()
|
||
" only add closing pair before space or any of the closepair chars
|
||
let close_before = '\s\|\V\[,.;' . escape(join(keys(b:AutoClosePairs) + values(b:AutoClosePairs), ''), ']').']'
|
||
if (l:next == "\0" || l:next =~ close_before) && s:AllowQuote(a:opener, 0)
|
||
call s:InsertStringAtCursor(b:AutoClosePairs[a:opener])
|
||
call s:PushBuffer(b:AutoClosePairs[a:opener])
|
||
endif
|
||
|
||
exec "set ve=" . l:save_ve
|
||
return a:opener
|
||
endfunction
|
||
|
||
" returns the closer, after having eaten identical one if necessary
|
||
function! s:ClosePair(closer)
|
||
let l:save_ve = &ve
|
||
set ve=all
|
||
|
||
if b:AutoCloseOn && s:GetNextChar() == a:closer
|
||
call s:EraseNCharsAtCursor(1)
|
||
call s:PopBuffer()
|
||
endif
|
||
|
||
exec "set ve=" . l:save_ve
|
||
return a:closer
|
||
endfunction
|
||
|
||
" in case closer is identical with its opener - heuristically decide which one
|
||
" is being typed and act accordingly
|
||
function! s:OpenOrCloseTwinPair(char)
|
||
if s:CountQuotes(a:char) % 2 == 0
|
||
" act as opening char
|
||
return s:InsertPair(a:char)
|
||
else
|
||
" act as closing char
|
||
return s:ClosePair(a:char)
|
||
endif
|
||
endfunction
|
||
|
||
" maintain auto-close buffer when delete key is pressed
|
||
function! s:Delete()
|
||
let l:save_ve = &ve
|
||
set ve=all
|
||
|
||
if exists("b:AutoCloseBuffer") && len(b:AutoCloseBuffer) > 0 && b:AutoCloseBuffer[0] == s:GetNextChar()
|
||
call s:PopBuffer()
|
||
endif
|
||
|
||
exec "set ve=" . l:save_ve
|
||
return "\<Del>"
|
||
endfunction
|
||
|
||
" when backspace is pressed:
|
||
" - erase an empty pair if backspacing from inside one
|
||
" - maintain auto-close buffer
|
||
function! s:Backspace()
|
||
let l:save_ve = &ve
|
||
let l:prev = s:GetPrevChar()
|
||
let l:next = s:GetNextChar()
|
||
set ve=all
|
||
|
||
if b:AutoCloseOn && s:IsEmptyPair() && (l:prev != l:next || s:AllowQuote(l:prev, 1))
|
||
call s:EraseNCharsAtCursor(1)
|
||
call s:PopBuffer()
|
||
endif
|
||
|
||
exec "set ve=" . l:save_ve
|
||
return "\<BS>"
|
||
endfunction
|
||
|
||
function! s:Space()
|
||
if b:AutoCloseOn && s:IsEmptyPair()
|
||
call s:PushBuffer("\<Space>")
|
||
return "\<Space>\<Space>\<Left>"
|
||
else
|
||
return "\<Space>"
|
||
endif
|
||
endfunction
|
||
|
||
function! s:Enter()
|
||
if has_key(b:AutoClosePumvisible, 'ENTER') && pumvisible()
|
||
let b:snippet_chosen = 1
|
||
return b:AutoClosePumvisible['ENTER']
|
||
elseif b:AutoCloseOn && s:IsEmptyPair() && stridx( b:AutoCloseExpandEnterOn, s:GetPrevChar() ) >= 0
|
||
return "\<CR>\<Esc>O"
|
||
endif
|
||
return "\<CR>"
|
||
endfunction
|
||
|
||
function! s:ToggleAutoClose()
|
||
let b:AutoCloseOn = !b:AutoCloseOn
|
||
if b:AutoCloseOn
|
||
echo "AutoClose ON"
|
||
else
|
||
echo "AutoClose OFF"
|
||
endif
|
||
endfunction
|
||
|
||
" Parse a whitespace separated line of pairs
|
||
" single characters are assumed to be twin pairs (closer identical to
|
||
" opener)
|
||
function! AutoClose#ParsePairs(string)
|
||
if type(a:string) == type({})
|
||
return a:string
|
||
elseif type(a:string) != type("")
|
||
echoerr "AutoClose#ParsePairs(): Argument not a dictionary or a string"
|
||
return {}
|
||
endif
|
||
|
||
let l:dict = {}
|
||
for pair in split(a:string)
|
||
" strlen is length in bytes, we want in (wide) characters
|
||
let l:pairLen = strlen(substitute(pair,'.','x','g'))
|
||
if l:pairLen == 1
|
||
" assume a twin pair
|
||
let l:dict[pair] = pair
|
||
elseif l:pairLen == 2
|
||
let l:dict[pair[0]] = pair[1]
|
||
else
|
||
echoerr "AutoClose: Bad pair string - a pair longer then two character"
|
||
echoerr " `- String: " . a:sring
|
||
echoerr " `- Pair: " . pair . " Pair len: " . l:pairLen
|
||
endif
|
||
endfor
|
||
return l:dict
|
||
endfunction
|
||
|
||
" this function is made visible for the sake of users
|
||
function! AutoClose#DefaultPairs()
|
||
return AutoClose#ParsePairs(g:AutoClosePairs)
|
||
endfunction
|
||
|
||
function! s:ModifyPairsList(list, pairsToAdd, openersToRemove)
|
||
return filter(
|
||
\ extend(a:list, AutoClose#ParsePairs(a:pairsToAdd), "force"),
|
||
\ "stridx(a:openersToRemove,v:key)<0")
|
||
endfunction
|
||
|
||
function! AutoClose#DefaultPairsModified(pairsToAdd,openersToRemove)
|
||
return s:ModifyPairsList(AutoClose#DefaultPairs(), a:pairsToAdd, a:openersToRemove)
|
||
endfunction
|
||
|
||
" Define variables (in the buffer namespace).
|
||
function! s:DefineVariables()
|
||
" All the following variables can be set per buffer or global.
|
||
" The buffer namespace is used internally
|
||
let defaults = {
|
||
\ 'AutoClosePairs': AutoClose#DefaultPairs(),
|
||
\ 'AutoCloseProtectedRegions': ["Comment", "String", "Character"],
|
||
\ 'AutoCloseSmartQuote': 1,
|
||
\ 'AutoCloseOn': 1,
|
||
\ 'AutoCloseSelectionWrapPrefix': '<LEADER>a',
|
||
\ 'AutoClosePumvisible': {"ENTER": "\<C-Y>", "ESC": "\<C-E>"},
|
||
\ 'AutoCloseExpandEnterOn': "",
|
||
\ 'AutoCloseExpandSpace': 1,
|
||
\ }
|
||
|
||
" Let the user define if he/she wants the plugin to do special actions when the
|
||
" popup menu is visible and a movement key is pressed.
|
||
" Movement keys used in the menu get mapped to themselves
|
||
" (Up/Down/PageUp/PageDown).
|
||
for key in s:movementKeys
|
||
if key == 'ENTER' || key == 'ESC'
|
||
continue
|
||
endif
|
||
let defaults['AutoClosePumvisible'][key] = ''
|
||
endfor
|
||
for key in s:pumMovementKeys
|
||
if key == 'ENTER' || key == 'ESC'
|
||
continue
|
||
endif
|
||
let defaults['AutoClosePumvisible'][key] = '<'.key.'>'
|
||
endfor
|
||
|
||
if exists ('b:AutoClosePairs') && type('b:AutoClosePairs') == type("")
|
||
let tmp = AutoClose#ParsePairs(b:AutoClosePairs)
|
||
unlet b:AutoClosePairs
|
||
let b:AutoClosePairs = tmp
|
||
endif
|
||
|
||
" Now handle/assign values
|
||
for key in keys(defaults)
|
||
if key == 'AutoClosePumvisible'
|
||
let tempVisible = defaults['AutoClosePumvisible']
|
||
if exists('g:AutoClosePumvisible') && type(eval('g:AutoClosePumvisible')) == type(defaults['AutoClosePumvisible'])
|
||
for childKey in keys(g:AutoClosePumvisible)
|
||
let tempVisible[toupper(childKey)] = g:AutoClosePumvisible[childKey]
|
||
endfor
|
||
endif
|
||
if exists('b:AutoClosePumvisible') && type(eval('b:AutoClosePumvisible')) == type(defaults['AutoClosePumvisible'])
|
||
for childKey in keys(b:AutoClosePumvisible)
|
||
let tempVisible[toupper(childKey)] = b:AutoClosePumvisible[childKey]
|
||
endfor
|
||
endif
|
||
let b:AutoClosePumvisible = tempVisible
|
||
else
|
||
if exists('b:'.key) && type(eval('b:'.key)) == type(defaults[key])
|
||
continue
|
||
elseif exists('g:'.key) && type(eval('g:'.key)) == type(defaults[key])
|
||
exec 'let b:' . key . ' = g:' . key
|
||
else
|
||
exec 'let b:' . key . ' = ' . string(defaults[key])
|
||
endif
|
||
endif
|
||
endfor
|
||
endfunction
|
||
|
||
function! s:CreatePairsMaps()
|
||
" create appropriate maps to defined open/close characters
|
||
for key in keys(b:AutoClosePairs)
|
||
let opener = s:keyName(key)
|
||
let closer = s:keyName(b:AutoClosePairs[key])
|
||
let quoted_opener = s:quoteAndEscape(opener)
|
||
let quoted_closer = s:quoteAndEscape(closer)
|
||
|
||
exec "xnoremap <buffer> <silent> ". b:AutoCloseSelectionWrapPrefix
|
||
\ . opener . " <Esc>`>a" . closer . "<Esc>`<i" . opener . "<Esc>"
|
||
exec "xnoremap <buffer> <silent> ". b:AutoCloseSelectionWrapPrefix
|
||
\ . closer . " <Esc>`>a" . closer . "<Esc>`<i" . opener . "<Esc>"
|
||
if key == b:AutoClosePairs[key]
|
||
exec "inoremap <buffer> <silent> " . opener
|
||
\ . " <C-R>=<SID>OpenOrCloseTwinPair(" . quoted_opener . ")<CR>"
|
||
else
|
||
exec "inoremap <buffer> <silent> " . opener
|
||
\ . " <C-R>=<SID>InsertPair(" . quoted_opener . ")<CR>"
|
||
exec "inoremap <buffer> <silent> " . closer
|
||
\ . " <C-R>=<SID>ClosePair(" . quoted_closer . ")<CR>"
|
||
endif
|
||
endfor
|
||
endfunction
|
||
|
||
function! s:CreateExtraMaps()
|
||
" Extra mapping
|
||
inoremap <buffer> <silent> <BS> <C-R>=<SID>Backspace()<CR>
|
||
inoremap <buffer> <silent> <Del> <C-R>=<SID>Delete()<CR>
|
||
if b:AutoCloseExpandSpace
|
||
inoremap <buffer> <silent> <Space> <C-R>=<SID>Space()<CR>
|
||
endif
|
||
if len(b:AutoCloseExpandEnterOn) > 0
|
||
inoremap <buffer> <silent> <CR> <C-R>=<SID>Enter()<CR>
|
||
endif
|
||
|
||
if g:AutoClosePreserveDotReg
|
||
" Fix the re-do feature by flushing the char buffer on key movements (including Escape):
|
||
for key in s:movementKeys
|
||
let l:pvisiblemap = b:AutoClosePumvisible[key]
|
||
let key = "<".key.">"
|
||
let l:currentmap = maparg(key,"i")
|
||
if (l:currentmap=="")|let l:currentmap=key|endif
|
||
if len(l:pvisiblemap)
|
||
exec "inoremap <buffer> <silent> <expr> " . key . " pumvisible() ? '" . l:pvisiblemap . "' : '<C-R>=<SID>FlushBuffer()<CR>" . l:currentmap . "'"
|
||
else
|
||
exec "inoremap <buffer> <silent> " . key . " <C-R>=<SID>FlushBuffer()<CR>" . l:currentmap
|
||
endif
|
||
endfor
|
||
|
||
" Flush the char buffer on mouse click:
|
||
inoremap <buffer> <silent> <LeftMouse> <C-R>=<SID>FlushBuffer()<CR><LeftMouse>
|
||
inoremap <buffer> <silent> <RightMouse> <C-R>=<SID>FlushBuffer()<CR><RightMouse>
|
||
endif
|
||
endfunction
|
||
|
||
function! s:CreateMaps()
|
||
silent doautocmd FileType
|
||
call s:DefineVariables()
|
||
call s:CreatePairsMaps()
|
||
call s:CreateExtraMaps()
|
||
|
||
let b:loaded_AutoClose = 1
|
||
endfunction
|
||
|
||
function! s:IsLoadedOnBuffer()
|
||
return (exists("b:loaded_AutoClose") && b:loaded_AutoClose)
|
||
endfunction
|
||
|
||
" map some characters to their key names
|
||
function! s:keyName(char)
|
||
let s:keyNames = {'|': '<Bar>', ' ': '<Space>'}
|
||
return get(s:keyNames,a:char,a:char)
|
||
endfunction
|
||
|
||
" escape some characters for use in strings
|
||
function! s:quoteAndEscape(char)
|
||
let s:escapedChars = {'"': '\"'}
|
||
return '"' . get(s:escapedChars,a:char,a:char) . '"'
|
||
endfunction
|
||
|
||
|
||
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
|
||
" Configuration
|
||
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
|
||
let s:AutoClosePairs_FactoryDefaults = AutoClose#ParsePairs("() {} [] ` \" '")
|
||
if !exists("g:AutoClosePairs_add") | let g:AutoClosePairs_add = "" | endif
|
||
if !exists("g:AutoClosePairs_del") | let g:AutoClosePairs_del = "" | endif
|
||
if !exists("g:AutoClosePairs")
|
||
let g:AutoClosePairs = s:ModifyPairsList(
|
||
\ s:AutoClosePairs_FactoryDefaults,
|
||
\ g:AutoClosePairs_add,
|
||
\ g:AutoClosePairs_del )
|
||
endif
|
||
|
||
let s:movementKeys = split('ESC UP DOWN LEFT RIGHT HOME END PAGEUP PAGEDOWN')
|
||
" list of keys that get mapped to themselves for pumvisible()
|
||
let s:pumMovementKeys = split('UP DOWN PAGEUP PAGEDOWN')
|
||
|
||
|
||
if has("gui_macvim")
|
||
call extend(s:movementKeys, split("D-LEFT D-RIGHT D-UP D-DOWN M-LEFT M-RIGHT M-UP M-DOWN"))
|
||
endif
|
||
|
||
augroup <Plug>(autoclose)
|
||
autocmd!
|
||
autocmd BufNewFile,BufRead,BufEnter * if !<SID>IsLoadedOnBuffer() | call <SID>CreateMaps() | endif
|
||
autocmd InsertEnter * call <SID>EmptyBuffer()
|
||
autocmd BufEnter * if mode() == 'i' | call <SID>EmptyBuffer() | endif
|
||
augroup END
|
||
|
||
" Define convenient commands
|
||
command! AutoCloseOn :let b:AutoCloseOn = 1
|
||
command! AutoCloseOff :let b:AutoCloseOn = 0
|
||
command! AutoCloseToggle :call s:ToggleAutoClose()
|
||
" vim:sw=4:sts=4:
|