mirror of
1
0
Fork 0

Updated plugins

This commit is contained in:
amix 2015-02-04 10:43:54 +00:00
parent e7a01094b6
commit a4b4587019
71 changed files with 2076 additions and 1112 deletions

View File

@ -0,0 +1,383 @@
" Copyright (c) 2015 Junegunn Choi
"
" MIT License
"
" Permission is hereby granted, free of charge, to any person obtaining
" a copy of this software and associated documentation files (the
" "Software"), to deal in the Software without restriction, including
" without limitation the rights to use, copy, modify, merge, publish,
" distribute, sublicense, and/or sell copies of the Software, and to
" permit persons to whom the Software is furnished to do so, subject to
" the following conditions:
"
" The above copyright notice and this permission notice shall be
" included in all copies or substantial portions of the Software.
"
" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
" EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
" NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
" LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
" OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
" WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
let s:cpo_save = &cpo
set cpo&vim
function! s:get_color(group, attr)
return synIDattr(synIDtrans(hlID(a:group)), a:attr)
endfunction
function! s:set_color(group, attr, color)
let gui = has('gui_running')
execute printf("hi %s %s%s=%s", a:group, gui ? 'gui' : 'cterm', a:attr, a:color)
endfunction
function! s:blank(repel)
if bufwinnr(t:goyo_pads.r) <= bufwinnr(t:goyo_pads.l) + 1
\ || bufwinnr(t:goyo_pads.b) <= bufwinnr(t:goyo_pads.t) + 3
call s:goyo_off()
endif
execute 'wincmd' a:repel
endfunction
function! s:init_pad(command)
execute a:command
setlocal buftype=nofile bufhidden=wipe nomodifiable nobuflisted noswapfile
\ nonu nocursorline nocursorcolumn winfixwidth winfixheight statusline=\
if exists('&rnu')
setlocal nornu
endif
if exists('&colorcolumn')
setlocal colorcolumn=
endif
let bufnr = winbufnr(0)
execute winnr('#') . 'wincmd w'
return bufnr
endfunction
function! s:setup_pad(bufnr, vert, size, repel)
let win = bufwinnr(a:bufnr)
execute win . 'wincmd w'
execute (a:vert ? 'vertical ' : '') . 'resize ' . max([0, a:size])
augroup goyop
execute 'autocmd WinEnter,CursorMoved <buffer> nested call s:blank("'.a:repel.'")'
autocmd WinLeave <buffer> call s:hide_statusline()
augroup END
" To hide scrollbars of pad windows in GVim
let diff = winheight(0) - line('$') - (has('gui_running') ? 2 : 0)
if diff > 0
setlocal modifiable
call append(0, map(range(1, diff), '""'))
normal! gg
setlocal nomodifiable
endif
execute winnr('#') . 'wincmd w'
endfunction
function! s:hmargin()
let nwidth = max([len(string(line('$'))) + 1, &numberwidth])
let width = t:goyo_width + (&number ? nwidth : 0)
return (&columns - width)
endfunction
function! s:resize_pads()
let t:goyo_width = max([2, t:goyo_width])
let t:goyo_margin_top = min([max([2, t:goyo_margin_top]), &lines / 2 - 1])
let t:goyo_margin_bottom = min([max([2, t:goyo_margin_bottom]), &lines / 2 - 1])
let hmargin = s:hmargin()
augroup goyop
autocmd!
augroup END
call s:setup_pad(t:goyo_pads.t, 0, t:goyo_margin_top - 1, 'j')
call s:setup_pad(t:goyo_pads.b, 0, t:goyo_margin_bottom - 2, 'k')
call s:setup_pad(t:goyo_pads.l, 1, hmargin / 2 - 1, 'l')
call s:setup_pad(t:goyo_pads.r, 1, hmargin / 2 - 1, 'h')
let t:goyo_width = winwidth(0)
endfunction
function! s:tranquilize()
let bg = s:get_color('Normal', 'bg')
for grp in ['NonText', 'FoldColumn', 'ColorColumn', 'VertSplit',
\ 'StatusLine', 'StatusLineNC', 'SignColumn']
" -1 on Vim / '' on GVim
if bg == -1 || empty(bg)
call s:set_color(grp, 'fg', get(g:, 'goyo_bg', 'black'))
call s:set_color(grp, 'bg', 'NONE')
else
call s:set_color(grp, 'fg', bg)
call s:set_color(grp, 'bg', bg)
endif
call s:set_color(grp, '', 'NONE')
endfor
endfunction
function! s:hide_statusline()
let &l:statusline = repeat(' ', winwidth(0))
endfunction
function! s:hide_linenr()
if !get(g:, 'goyo_linenr', 0)
setlocal nonu
if exists('&rnu')
setlocal nornu
endif
endif
if exists('&colorcolumn')
setlocal colorcolumn=
endif
endfunction
function! s:maps_nop()
let mapped = filter(['R', 'H', 'J', 'K', 'L', '|', '_'],
\ "empty(maparg(\"\<c-w>\".v:val, 'n'))")
for c in mapped
execute 'nnoremap <c-w>'.escape(c, '|').' <nop>'
endfor
return mapped
endfunction
function! s:maps_resize()
let commands = {
\ '=': ':<c-u>let [t:goyo_width, t:goyo_margin_top, t:goyo_margin_bottom] = t:goyo_initial_dim <bar> call <sid>resize_pads()<cr>',
\ '>': ':<c-u>let t:goyo_width = winwidth(0) + 2 * v:count1 <bar> call <sid>resize_pads()<cr>',
\ '<': ':<c-u>let t:goyo_width = winwidth(0) - 2 * v:count1 <bar> call <sid>resize_pads()<cr>',
\ '+': ':<c-u>let t:goyo_margin_top -= v:count1 <bar> let t:goyo_margin_bottom -= v:count1 <bar> call <sid>resize_pads()<cr>',
\ '-': ':<c-u>let t:goyo_margin_top += v:count1 <bar> let t:goyo_margin_bottom += v:count1 <bar> call <sid>resize_pads()<cr>'
\ }
let mapped = filter(keys(commands), "empty(maparg(\"\<c-w>\".v:val, 'n'))")
for c in mapped
execute 'nnoremap <silent> <c-w>'.c.' '.commands[c]
endfor
return mapped
endfunction
function! s:goyo_on(width)
let s:orig_tab = tabpagenr()
" New tab
tab split
let t:goyo_master = winbufnr(0)
let t:goyo_width = a:width
let t:goyo_margin_top = get(g:, 'goyo_margin_top', 4)
let t:goyo_margin_bottom = get(g:, 'goyo_margin_bottom', 4)
let t:goyo_initial_dim = [t:goyo_width, t:goyo_margin_top, t:goyo_margin_bottom]
let t:goyo_pads = {}
let t:goyo_revert =
\ { 'laststatus': &laststatus,
\ 'showtabline': &showtabline,
\ 'fillchars': &fillchars,
\ 'winminwidth': &winminwidth,
\ 'winwidth': &winwidth,
\ 'winminheight': &winminheight,
\ 'winheight': &winheight,
\ 'ruler': &ruler,
\ 'sidescroll': &sidescroll,
\ 'sidescrolloff': &sidescrolloff
\ }
let t:goyo_maps = extend(s:maps_nop(), s:maps_resize())
if has('gui_running')
let t:goyo_revert.guioptions = &guioptions
endif
" vim-gitgutter
let t:goyo_disabled_gitgutter = get(g:, 'gitgutter_enabled', 0)
if t:goyo_disabled_gitgutter
silent! GitGutterDisable
endif
" vim-signify
let t:goyo_disabled_signify = exists('b:sy') && b:sy.active
if t:goyo_disabled_signify
SignifyToggle
endif
" vim-airline
let t:goyo_disabled_airline = exists("#airline")
if t:goyo_disabled_airline
AirlineToggle
endif
" vim-powerline
let t:goyo_disabled_powerline = exists("#PowerlineMain")
if t:goyo_disabled_powerline
augroup PowerlineMain
autocmd!
augroup END
augroup! PowerlineMain
endif
" lightline.vim
let t:goyo_disabled_lightline = exists('#LightLine')
if t:goyo_disabled_lightline
silent! call lightline#disable()
endif
call s:hide_linenr()
" Global options
let &winheight = max([&winminheight, 1])
set winminheight=1
set winheight=1
set winminwidth=1 winwidth=1
set laststatus=0
set showtabline=0
set noruler
set fillchars+=vert:\
set fillchars+=stl:.
set fillchars+=stlnc:\
set sidescroll=1
set sidescrolloff=0
" Hide left-hand scrollbars
if has('gui_running')
set guioptions-=l
set guioptions-=L
endif
let t:goyo_pads.l = s:init_pad('vertical topleft new')
let t:goyo_pads.r = s:init_pad('vertical botright new')
let t:goyo_pads.t = s:init_pad('topleft new')
let t:goyo_pads.b = s:init_pad('botright new')
call s:resize_pads()
call s:tranquilize()
augroup goyo
autocmd!
autocmd TabLeave * call s:goyo_off()
autocmd VimResized * call s:resize_pads()
autocmd ColorScheme * call s:tranquilize()
autocmd BufWinEnter * call s:hide_linenr() | call s:hide_statusline()
autocmd WinEnter,WinLeave * call s:hide_statusline()
augroup END
call s:hide_statusline()
if exists('g:goyo_callbacks[0]')
call g:goyo_callbacks[0]()
endif
silent! doautocmd User GoyoEnter
endfunction
function! s:goyo_off()
if !exists('#goyo')
return
endif
" Oops, not this tab
if !exists('t:goyo_revert')
return
endif
" Clear auto commands
augroup goyo
autocmd!
augroup END
augroup! goyo
augroup goyop
autocmd!
augroup END
augroup! goyop
for c in t:goyo_maps
execute 'nunmap <c-w>'.escape(c, '|')
endfor
let goyo_revert = t:goyo_revert
let goyo_disabled_gitgutter = t:goyo_disabled_gitgutter
let goyo_disabled_signify = t:goyo_disabled_signify
let goyo_disabled_airline = t:goyo_disabled_airline
let goyo_disabled_powerline = t:goyo_disabled_powerline
let goyo_disabled_lightline = t:goyo_disabled_lightline
let goyo_orig_buffer = t:goyo_master
let [line, col] = [line('.'), col('.')]
if tabpagenr() == 1
tabnew
normal! gt
bd
endif
tabclose
execute 'normal! '.s:orig_tab.'gt'
if winbufnr(0) == goyo_orig_buffer
" Doesn't work if window closed with `q`
execute printf('normal! %dG%d|', line, col)
endif
let wmw = remove(goyo_revert, 'winminwidth')
let ww = remove(goyo_revert, 'winwidth')
let &winwidth = ww
let &winminwidth = wmw
let wmh = remove(goyo_revert, 'winminheight')
let wh = remove(goyo_revert, 'winheight')
let &winheight = max([wmh, 1])
let &winminheight = wmh
let &winheight = wh
for [k, v] in items(goyo_revert)
execute printf("let &%s = %s", k, string(v))
endfor
execute 'colo '. get(g:, 'colors_name', 'default')
if goyo_disabled_gitgutter
silent! GitGutterEnable
endif
if goyo_disabled_signify
silent! if !b:sy.active
SignifyToggle
endif
endif
if goyo_disabled_airline && !exists("#airline")
AirlineToggle
silent! AirlineRefresh
endif
if goyo_disabled_powerline && !exists("#PowerlineMain")
doautocmd PowerlineStartup VimEnter
silent! PowerlineReloadColorscheme
endif
if goyo_disabled_lightline
silent! call lightline#enable()
endif
if exists('#Powerline')
doautocmd Powerline ColorScheme
endif
if exists('g:goyo_callbacks[1]')
call g:goyo_callbacks[1]()
endif
silent! doautocmd User GoyoLeave
endfunction
function! goyo#execute(bang, ...)
let width = a:0 > 0 ? a:1 : get(g:, 'goyo_width', 80)
if a:bang
if exists('#goyo')
call s:goyo_off()
endif
else
if exists('#goyo') == 0
call s:goyo_on(width)
elseif a:0 > 0
let t:goyo_width = width
call s:resize_pads()
else
call s:goyo_off()
end
end
endfunction
let &cpo = s:cpo_save
unlet s:cpo_save

View File

@ -1,4 +1,4 @@
" Copyright (c) 2014 Junegunn Choi
" Copyright (c) 2015 Junegunn Choi
"
" MIT License
"
@ -21,363 +21,4 @@
" OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
" WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
let s:cpo_save = &cpo
set cpo&vim
function! s:get_color(group, attr)
return synIDattr(synIDtrans(hlID(a:group)), a:attr)
endfunction
function! s:set_color(group, attr, color)
let gui = has('gui_running')
execute printf("hi %s %s%s=%s", a:group, gui ? 'gui' : 'cterm', a:attr, a:color)
endfunction
function! s:blank(repel)
if bufwinnr(t:goyo_pads.r) <= bufwinnr(t:goyo_pads.l) + 1
\ || bufwinnr(t:goyo_pads.b) <= bufwinnr(t:goyo_pads.t) + 3
call s:goyo_off()
endif
execute 'wincmd' a:repel
endfunction
function! s:init_pad(command)
execute a:command
setlocal buftype=nofile bufhidden=wipe nomodifiable nobuflisted noswapfile
\ nonu nocursorline nocursorcolumn winfixwidth winfixheight statusline=\
if exists('&rnu')
setlocal nornu
endif
if exists('&colorcolumn')
setlocal colorcolumn=
endif
let bufnr = winbufnr(0)
execute winnr('#') . 'wincmd w'
return bufnr
endfunction
function! s:setup_pad(bufnr, vert, size, repel)
let win = bufwinnr(a:bufnr)
execute win . 'wincmd w'
execute (a:vert ? 'vertical ' : '') . 'resize ' . max([0, a:size])
augroup goyop
execute 'autocmd WinEnter,CursorMoved <buffer> nested call s:blank("'.a:repel.'")'
autocmd WinLeave <buffer> call s:hide_statusline()
augroup END
" To hide scrollbars of pad windows in GVim
let diff = winheight(0) - line('$') - (has('gui_running') ? 2 : 0)
if diff > 0
setlocal modifiable
call append(0, map(range(1, diff), '""'))
normal! gg
setlocal nomodifiable
endif
execute winnr('#') . 'wincmd w'
endfunction
function! s:hmargin()
let nwidth = max([len(string(line('$'))) + 1, &numberwidth])
let width = t:goyo_width + (&number ? nwidth : 0)
return (&columns - width)
endfunction
function! s:resize_pads()
let t:goyo_width = max([2, t:goyo_width])
let t:goyo_margin_top = min([max([2, t:goyo_margin_top]), &lines / 2 - 1])
let t:goyo_margin_bottom = min([max([2, t:goyo_margin_bottom]), &lines / 2 - 1])
let hmargin = s:hmargin()
augroup goyop
autocmd!
augroup END
call s:setup_pad(t:goyo_pads.t, 0, t:goyo_margin_top - 1, 'j')
call s:setup_pad(t:goyo_pads.b, 0, t:goyo_margin_bottom - 2, 'k')
call s:setup_pad(t:goyo_pads.l, 1, hmargin / 2 - 1, 'l')
call s:setup_pad(t:goyo_pads.r, 1, hmargin / 2 - 1, 'h')
let t:goyo_width = winwidth(0)
endfunction
function! s:tranquilize()
let bg = s:get_color('Normal', 'bg')
for grp in ['NonText', 'FoldColumn', 'ColorColumn', 'VertSplit',
\ 'StatusLine', 'StatusLineNC', 'SignColumn']
" -1 on Vim / '' on GVim
if bg == -1 || empty(bg)
call s:set_color(grp, 'fg', get(g:, 'goyo_bg', 'black'))
call s:set_color(grp, 'bg', 'NONE')
else
call s:set_color(grp, 'fg', bg)
call s:set_color(grp, 'bg', bg)
endif
call s:set_color(grp, '', 'NONE')
endfor
endfunction
function! s:hide_statusline()
let &l:statusline = repeat(' ', winwidth(0))
endfunction
function! s:hide_linenr()
if !get(g:, 'goyo_linenr', 0)
setlocal nonu
if exists('&rnu')
setlocal nornu
endif
endif
if exists('&colorcolumn')
setlocal colorcolumn=
endif
endfunction
function! s:maps_nop()
let mapped = filter(['R', 'H', 'J', 'K', 'L', '|', '_', '='],
\ "empty(maparg(\"\<c-w>\".v:val, 'n'))")
for c in mapped
execute 'nnoremap <c-w>'.escape(c, '|').' <nop>'
endfor
return mapped
endfunction
function! s:maps_resize()
let commands = {
\ '>': ':<c-u>let t:goyo_width = winwidth(0) + 2 * v:count1 <bar> call <sid>resize_pads()<cr>',
\ '<': ':<c-u>let t:goyo_width = winwidth(0) - 2 * v:count1 <bar> call <sid>resize_pads()<cr>',
\ '+': ':<c-u>let t:goyo_margin_top -= v:count1 <bar> let t:goyo_margin_bottom -= v:count1 <bar> call <sid>resize_pads()<cr>',
\ '-': ':<c-u>let t:goyo_margin_top += v:count1 <bar> let t:goyo_margin_bottom += v:count1 <bar> call <sid>resize_pads()<cr>'
\ }
let mapped = filter(keys(commands), "empty(maparg(\"\<c-w>\".v:val, 'n'))")
for c in mapped
execute 'nnoremap <silent> <c-w>'.c.' '.commands[c]
endfor
return mapped
endfunction
function! s:goyo_on(width)
let s:orig_tab = tabpagenr()
" New tab
tab split
let t:goyo_master = winbufnr(0)
let t:goyo_width = a:width
let t:goyo_margin_top = get(g:, 'goyo_margin_top', 4)
let t:goyo_margin_bottom = get(g:, 'goyo_margin_bottom', 4)
let t:goyo_pads = {}
let t:goyo_revert =
\ { 'laststatus': &laststatus,
\ 'showtabline': &showtabline,
\ 'fillchars': &fillchars,
\ 'winminwidth': &winminwidth,
\ 'winwidth': &winwidth,
\ 'winminheight': &winminheight,
\ 'winheight': &winheight,
\ 'ruler': &ruler,
\ 'sidescroll': &sidescroll,
\ 'sidescrolloff': &sidescrolloff
\ }
let t:goyo_maps = extend(s:maps_nop(), s:maps_resize())
if has('gui_running')
let t:goyo_revert.guioptions = &guioptions
endif
" vim-gitgutter
let t:goyo_disabled_gitgutter = get(g:, 'gitgutter_enabled', 0)
if t:goyo_disabled_gitgutter
silent! GitGutterDisable
endif
" vim-signify
let t:goyo_disabled_signify = exists('b:sy') && b:sy.active
if t:goyo_disabled_signify
SignifyToggle
endif
" vim-airline
let t:goyo_disabled_airline = exists("#airline")
if t:goyo_disabled_airline
AirlineToggle
endif
" vim-powerline
let t:goyo_disabled_powerline = exists("#PowerlineMain")
if t:goyo_disabled_powerline
augroup PowerlineMain
autocmd!
augroup END
augroup! PowerlineMain
endif
" lightline.vim
let t:goyo_disabled_lightline = exists('#LightLine')
if t:goyo_disabled_lightline
silent! call lightline#disable()
endif
call s:hide_linenr()
" Global options
let &winheight = max([&winminheight, 1])
set winminheight=1
set winheight=1
set winminwidth=1 winwidth=1
set laststatus=0
set showtabline=0
set noruler
set fillchars+=vert:\
set fillchars+=stl:.
set fillchars+=stlnc:\
set sidescroll=1
set sidescrolloff=0
" Hide left-hand scrollbars
if has('gui_running')
set guioptions-=l
set guioptions-=L
endif
let t:goyo_pads.l = s:init_pad('vertical topleft new')
let t:goyo_pads.r = s:init_pad('vertical botright new')
let t:goyo_pads.t = s:init_pad('topleft new')
let t:goyo_pads.b = s:init_pad('botright new')
call s:resize_pads()
call s:tranquilize()
augroup goyo
autocmd!
autocmd TabLeave * call s:goyo_off()
autocmd VimResized * call s:resize_pads()
autocmd ColorScheme * call s:tranquilize()
autocmd BufWinEnter * call s:hide_linenr() | call s:hide_statusline()
autocmd WinEnter,WinLeave * call s:hide_statusline()
augroup END
call s:hide_statusline()
if exists('g:goyo_callbacks[0]')
call g:goyo_callbacks[0]()
endif
silent! doautocmd User GoyoEnter
endfunction
function! s:goyo_off()
if !exists('#goyo')
return
endif
" Oops, not this tab
if !exists('t:goyo_revert')
return
endif
" Clear auto commands
augroup goyo
autocmd!
augroup END
augroup! goyo
augroup goyop
autocmd!
augroup END
augroup! goyop
for c in t:goyo_maps
execute 'nunmap <c-w>'.escape(c, '|')
endfor
let goyo_revert = t:goyo_revert
let goyo_disabled_gitgutter = t:goyo_disabled_gitgutter
let goyo_disabled_signify = t:goyo_disabled_signify
let goyo_disabled_airline = t:goyo_disabled_airline
let goyo_disabled_powerline = t:goyo_disabled_powerline
let goyo_disabled_lightline = t:goyo_disabled_lightline
let goyo_orig_buffer = t:goyo_master
let [line, col] = [line('.'), col('.')]
if tabpagenr() == 1
tabnew
normal! gt
bd
endif
tabclose
execute 'normal! '.s:orig_tab.'gt'
if winbufnr(0) == goyo_orig_buffer
" Doesn't work if window closed with `q`
execute printf('normal! %dG%d|', line, col)
endif
let wmw = remove(goyo_revert, 'winminwidth')
let ww = remove(goyo_revert, 'winwidth')
let &winwidth = ww
let &winminwidth = wmw
let wmh = remove(goyo_revert, 'winminheight')
let wh = remove(goyo_revert, 'winheight')
let &winheight = max([wmh, 1])
let &winminheight = wmh
let &winheight = wh
for [k, v] in items(goyo_revert)
execute printf("let &%s = %s", k, string(v))
endfor
execute 'colo '. get(g:, 'colors_name', 'default')
if goyo_disabled_gitgutter
silent! GitGutterEnable
endif
if goyo_disabled_signify
silent! if !b:sy.active
SignifyToggle
endif
endif
if goyo_disabled_airline && !exists("#airline")
AirlineToggle
silent! AirlineRefresh
endif
if goyo_disabled_powerline && !exists("#PowerlineMain")
doautocmd PowerlineStartup VimEnter
silent! PowerlineReloadColorscheme
endif
if goyo_disabled_lightline
silent! call lightline#enable()
endif
if exists('#Powerline')
doautocmd Powerline ColorScheme
endif
if exists('g:goyo_callbacks[1]')
call g:goyo_callbacks[1]()
endif
silent! doautocmd User GoyoLeave
endfunction
function! s:goyo(bang, ...)
let width = a:0 > 0 ? a:1 : get(g:, 'goyo_width', 80)
if a:bang
if exists('#goyo')
call s:goyo_off()
endif
else
if exists('#goyo') == 0
call s:goyo_on(width)
elseif a:0 > 0
let t:goyo_width = width
call s:resize_pads()
else
call s:goyo_off()
end
end
endfunction
command! -nargs=? -bar -bang Goyo call s:goyo('<bang>' == '!', <args>)
let &cpo = s:cpo_save
unlet s:cpo_save
command! -nargs=? -bar -bang Goyo call goyo#execute(<bang>0, <args>)

View File

@ -12,6 +12,19 @@ function! GotoFile(w)
let pos = ""
let fname = curword
endif
" check exists file.
if filereadable(fname)
let fullname = fname
else
" try find file with prefix by working directory
let fullname = getcwd() . '/' . fname
if ! filereadable(fullname)
" the last try, using current directory based on file opened.
let fullname = expand('%:h') . '/' . fname
endif
endif
" Open new window if requested
if a:w == "new"
new

View File

@ -59,10 +59,10 @@ Haxe, Handlebars, HSS, HTML, Java, JavaScript, JSON, JSX, LESS, Lex, Limbo,
LISP, LLVM intermediate language, Lua, Markdown, MATLAB, NASM, Objective-C,
Objective-C++, OCaml, Perl, Perl POD, PHP, gettext Portable Object, OS X and
iOS property lists, Puppet, Python, R, Racket, Relax NG, reStructuredText, RPM
spec, Ruby, SASS/SCSS, Scala, Slim, Tcl, TeX, Texinfo, Twig, TypeScript, Vala,
Verilog, VHDL, VimL, xHtml, XML, XSLT, YACC, YAML, z80, Zope page templates,
and zsh. See the [wiki][3] for details about the corresponding supported
checkers.
spec, Ruby, SASS/SCSS, Scala, Slim, Swift, Tcl, TeX, Texinfo, Twig, TypeScript,
Vala, Verilog, VHDL, VimL, xHtml, XML, XSLT, YACC, YAML, z80, Zope page
templates, and zsh. See the [wiki][3] for details about the corresponding
supported checkers.
Below is a screenshot showing the methods that Syntastic uses to display syntax
errors. Note that, in practise, you will only have a subset of these methods

View File

@ -121,12 +121,6 @@ function! syntastic#util#parseVersion(version) " {{{2
return map(split(matchstr( a:version, '\v^\D*\zs\d+(\.\d+)+\ze' ), '\m\.'), 'str2nr(v:val)')
endfunction " }}}2
" Run 'command' in a shell and parse output as a version string.
" Returns an array of version components.
function! syntastic#util#getVersion(command) " {{{2
return syntastic#util#parseVersion(system(a:command))
endfunction " }}}2
" Verify that the 'installed' version is at least the 'required' version.
"
" 'installed' and 'required' must be arrays. If they have different lengths,

View File

@ -19,7 +19,7 @@ if has('reltime')
lockvar! g:_SYNTASTIC_START
endif
let g:_SYNTASTIC_VERSION = '3.5.0-148'
let g:_SYNTASTIC_VERSION = '3.6.0-14'
lockvar g:_SYNTASTIC_VERSION
" Sanity checks {{{1

View File

@ -77,6 +77,27 @@ function! g:SyntasticChecker.getLocList() " {{{2
return g:SyntasticLoclist.New(self.getLocListRaw())
endfunction " }}}2
function! g:SyntasticChecker.getVersion(...) " {{{2
if !exists('self._version')
let command = a:0 ? a:1 : self.getExecEscaped() . ' --version'
let version_output = system(command)
call self.log('getVersion: ' . string(command) . ': ' .
\ string(split(version_output, "\n", 1)) .
\ (v:shell_error ? ' (exit code ' . v:shell_error . ')' : '') )
call self.setVersion(syntastic#util#parseVersion(version_output))
endif
return get(self, '_version', [])
endfunction " }}}2
function! g:SyntasticChecker.setVersion(version) " {{{2
if len(a:version)
let self._version = copy(a:version)
call self.log(self.getExec() . ' version =', a:version)
else
call syntastic#log#error("checker " . self._filetype . "/" . self._name . ": can't parse version string (abnormal termination?)")
endif
endfunction " }}}2
function! g:SyntasticChecker.log(msg, ...) " {{{2
let leader = self._filetype . '/' . self._name . ': '
if a:0 > 0

View File

@ -74,6 +74,7 @@ let s:_DEFAULT_CHECKERS = {
\ 'sh': ['sh', 'shellcheck'],
\ 'slim': ['slimrb'],
\ 'spec': ['rpmlint'],
\ 'swift': ['xcrun'],
\ 'tcl': ['nagelfar'],
\ 'tex': ['lacheck', 'chktex'],
\ 'texinfo': ['makeinfo'],

View File

@ -71,13 +71,13 @@ function! g:SyntasticSignsNotifier._setup() " {{{2
endif
" define the signs used to display syntax and style errors/warns
exe 'sign define SyntasticError text=' . g:syntastic_error_symbol .
execute 'sign define SyntasticError text=' . g:syntastic_error_symbol .
\ ' texthl=SyntasticErrorSign linehl=SyntasticErrorLine'
exe 'sign define SyntasticWarning text=' . g:syntastic_warning_symbol .
execute 'sign define SyntasticWarning text=' . g:syntastic_warning_symbol .
\ ' texthl=SyntasticWarningSign linehl=SyntasticWarningLine'
exe 'sign define SyntasticStyleError text=' . g:syntastic_style_error_symbol .
execute 'sign define SyntasticStyleError text=' . g:syntastic_style_error_symbol .
\ ' texthl=SyntasticStyleErrorSign linehl=SyntasticStyleErrorLine'
exe 'sign define SyntasticStyleWarning text=' . g:syntastic_style_warning_symbol .
execute 'sign define SyntasticStyleWarning text=' . g:syntastic_style_warning_symbol .
\ ' texthl=SyntasticStyleWarningSign linehl=SyntasticStyleWarningLine'
endif
endfunction " }}}2

View File

@ -25,10 +25,7 @@ function! SyntaxCheckers_coffee_coffee_IsAvailable() dict
if !executable(self.getExec())
return 0
endif
let ver = syntastic#util#getVersion(self.getExecEscaped() . ' --version 2>' . syntastic#util#DevNull())
call self.log(self.getExec() . ' version = ', ver)
let ver = self.getVersion(self.getExecEscaped() . ' --version 2>' . syntastic#util#DevNull())
return syntastic#util#versionIsAtLeast(ver, [1, 6, 2])
endfunction

View File

@ -20,9 +20,7 @@ set cpo&vim
function! SyntaxCheckers_coffee_coffeelint_GetLocList() dict
if !exists('s:coffeelint_new')
let ver = syntastic#util#getVersion(self.getExecEscaped() . ' --version')
call self.log(self.getExec() . ' version =', ver)
let s:coffeelint_new = syntastic#util#versionIsAtLeast(ver, [1, 4])
let s:coffeelint_new = syntastic#util#versionIsAtLeast(self.getVersion(), [1, 4])
endif
let makeprg = self.makeprgBuild({ 'args_after': (s:coffeelint_new ? '--reporter csv' : '--csv') })

View File

@ -27,10 +27,14 @@ function! SyntaxCheckers_eruby_ruby_IsAvailable() dict
endfunction
function! SyntaxCheckers_eruby_ruby_GetLocList() dict
if !exists('s:ruby_new')
let s:ruby_new = syntastic#util#versionIsAtLeast(self.getVersion(), [1, 9])
endif
let fname = "'" . escape(expand('%', 1), "\\'") . "'"
" TODO: encodings became useful in ruby 1.9 :)
if syntastic#util#versionIsAtLeast(syntastic#util#getVersion(self.getExecEscaped(). ' --version'), [1, 9])
if s:ruby_new
let enc = &fileencoding != '' ? &fileencoding : &encoding
let encoding_spec = ', :encoding => "' . (enc ==? 'utf-8' ? 'UTF-8' : 'BINARY') . '"'
else

View File

@ -41,7 +41,7 @@ function! SyntaxCheckers_haskell_ghc_mod_IsAvailable() dict
" need either a Vim that can handle NULs in system() output, or a
" ghc-mod that has the "--boundary" option.
let parsed_ver = syntastic#util#parseVersion(ver[0])
call self.log(self.getExec() . ' version =', parsed_ver)
call self.setVersion(parsed_ver)
let s:ghc_mod_new = syntastic#util#versionIsAtLeast(parsed_ver, [2, 1, 2])
else
call syntastic#log#error("checker haskell/ghc_mod: can't parse version string (abnormal termination?)")

View File

@ -22,11 +22,7 @@ function! SyntaxCheckers_html_jshint_IsAvailable() dict
if !executable(self.getExec())
return 0
endif
let ver = syntastic#util#getVersion(self.getExecEscaped() . ' --version')
call self.log(self.getExec() . ' version =', ver)
return syntastic#util#versionIsAtLeast(ver, [2, 4])
return syntastic#util#versionIsAtLeast(self.getVersion(), [2, 4])
endfunction
function! SyntaxCheckers_html_jshint_GetLocList() dict

View File

@ -204,7 +204,7 @@ endfunction " }}}2
function! s:LoadConfigFile() " {{{2
if filereadable(expand(g:syntastic_java_javac_config_file, 1))
exe 'source ' . fnameescape(expand(g:syntastic_java_javac_config_file, 1))
execute 'source ' . fnameescape(expand(g:syntastic_java_javac_config_file, 1))
endif
endfunction " }}}2

View File

@ -25,11 +25,7 @@ function! SyntaxCheckers_javascript_eslint_IsAvailable() dict
if !executable(self.getExec())
return 0
endif
let ver = syntastic#util#getVersion(self.getExecEscaped() . ' --version')
call self.log(self.getExec() . ' version =', ver)
return syntastic#util#versionIsAtLeast(ver, [0, 1])
return syntastic#util#versionIsAtLeast(self.getVersion(), [0, 1])
endfunction
function! SyntaxCheckers_javascript_eslint_GetLocList() dict

View File

@ -27,20 +27,16 @@ function! SyntaxCheckers_javascript_jshint_IsAvailable() dict
return 0
endif
let s:jshint_version = syntastic#util#getVersion(self.getExecEscaped() . ' --version')
call self.log(self.getExec() . ' version =', s:jshint_version)
let ver = self.getVersion()
let s:jshint_new = syntastic#util#versionIsAtLeast(ver, [1, 1])
return syntastic#util#versionIsAtLeast(s:jshint_version, [1])
return syntastic#util#versionIsAtLeast(ver, [1])
endfunction
function! SyntaxCheckers_javascript_jshint_GetLocList() dict
call syntastic#log#deprecationWarn('javascript_jshint_conf', 'javascript_jshint_args',
\ "'--config ' . syntastic#util#shexpand(OLD_VAR)")
if !exists('s:jshint_new')
let s:jshint_new = syntastic#util#versionIsAtLeast(s:jshint_version, [1, 1])
endif
let makeprg = self.makeprgBuild({ 'args_after': (s:jshint_new ? '--verbose ' : '') })
let errorformat = s:jshint_new ?

View File

@ -24,7 +24,7 @@ function! SyntaxCheckers_javascript_jsxhint_IsAvailable() dict
endif
let ver = syntastic#util#parseVersion(jsxhint_version)
call self.log(self.getExec() . ' version =', ver)
call self.setVersion(ver)
return syntastic#util#versionIsAtLeast(ver, [0, 4, 1])
endfunction

View File

@ -19,18 +19,12 @@ let s:save_cpo = &cpo
set cpo&vim
function! SyntaxCheckers_puppet_puppet_GetLocList() dict
if !exists('s:puppet_version')
let s:puppet_version = syntastic#util#getVersion(self.getExecEscaped() . ' --version 2>' . syntastic#util#DevNull())
call self.log(self.getExec() . ' version =', s:puppet_version)
if !exists('s:puppet_new')
let s:puppet_new = syntastic#util#versionIsAtLeast(self.getVersion(), [2, 7, 0])
endif
if syntastic#util#versionIsAtLeast(s:puppet_version, [2,7,0])
let args = 'parser validate --color=false'
else
let args = '--color=false --parseonly'
endif
let makeprg = self.makeprgBuild({ 'args_before': args })
let makeprg = self.makeprgBuild({
\ 'args_before': (s:puppet_new ? 'parser validate --color=false' : '--color=false --parseonly') })
let errorformat =
\ '%-Gerr: Try ''puppet help parser validate'' for usage,' .

View File

@ -24,10 +24,7 @@ function! SyntaxCheckers_puppet_puppetlint_IsAvailable() dict
if !executable('puppet') || !executable(self.getExec())
return 0
endif
let ver = syntastic#util#getVersion(self.getExecEscaped() . ' --version 2>' . syntastic#util#DevNull())
call self.log(self.getExec() . ' version =', ver)
let ver = self.getVersion(self.getExecEscaped() . ' --version 2>' . syntastic#util#DevNull())
return syntastic#util#versionIsAtLeast(ver, [0, 1, 10])
endfunction

View File

@ -13,9 +13,7 @@ set cpo&vim
function! SyntaxCheckers_python_pep257_GetLocList() dict
if !exists('s:pep257_new')
let ver = syntastic#util#getVersion(self.getExecEscaped() . ' --version')
call self.log(self.getExec() . ' version =', ver)
let s:pep257_new = syntastic#util#versionIsAtLeast(ver, [0, 3])
let s:pep257_new = syntastic#util#versionIsAtLeast(self.getVersion(), [0, 3])
endif
let makeprg = self.makeprgBuild({})

View File

@ -26,11 +26,7 @@ function! SyntaxCheckers_python_prospector_IsAvailable() dict
if !executable(self.getExec())
return 0
endif
let ver = syntastic#util#getVersion(self.getExecEscaped() . ' --version')
call self.log(self.getExec() . ' version =', ver)
return syntastic#util#versionIsAtLeast(ver, [0, 7])
return syntastic#util#versionIsAtLeast(self.getVersion(), [0, 7])
endfunction
function! SyntaxCheckers_python_prospector_GetLocList() dict

View File

@ -35,8 +35,7 @@ function! SyntaxCheckers_python_pylint_IsAvailable() dict
let pylint_version = filter( split(system(self.getExecEscaped() . ' --version'), '\m, \=\|\n'),
\ 'v:val =~# ''\m^\(python[-0-9]*-\|\.\)\=pylint[-0-9]*\>''' )[0]
let ver = syntastic#util#parseVersion(substitute(pylint_version, '\v^\S+\s+', '', ''))
call self.log(self.getExec() . ' version =', ver)
call self.setVersion(ver)
let s:pylint_new = syntastic#util#versionIsAtLeast(ver, [1])
catch /\m^Vim\%((\a\+)\)\=:E684/

View File

@ -28,11 +28,7 @@ function! SyntaxCheckers_python_python_IsAvailable() dict
if !executable(self.getExec())
return 0
endif
let ver = syntastic#util#getVersion(self.getExecEscaped() . ' --version')
call self.log(self.getExec() . ' version =', ver)
return syntastic#util#versionIsAtLeast(ver, [2, 6])
return syntastic#util#versionIsAtLeast(self.getVersion(), [2, 6])
endfunction
function! SyntaxCheckers_python_python_GetLocList() dict

View File

@ -22,11 +22,7 @@ function! SyntaxCheckers_ruby_reek_IsAvailable() dict
if !executable(self.getExec())
return 0
endif
let ver = syntastic#util#getVersion(self.getExecEscaped() . ' --version')
call self.log(self.getExec() . ' version =', ver)
return syntastic#util#versionIsAtLeast(ver, [1, 3, 0])
return syntastic#util#versionIsAtLeast(self.getVersion(), [1, 3, 0])
endfunction
function! SyntaxCheckers_ruby_reek_GetLocList() dict

View File

@ -22,11 +22,7 @@ function! SyntaxCheckers_ruby_rubocop_IsAvailable() dict
if !executable(self.getExec())
return 0
endif
let ver = syntastic#util#getVersion(self.getExecEscaped() . ' --version')
call self.log(self.getExec() . ' version =', ver)
return syntastic#util#versionIsAtLeast(ver, [0, 12, 0])
return syntastic#util#versionIsAtLeast(self.getVersion(), [0, 12, 0])
endfunction
function! SyntaxCheckers_ruby_rubocop_GetLocList() dict

View File

@ -21,9 +21,7 @@ set cpo&vim
function! SyntaxCheckers_ruby_rubylint_GetLocList() dict
if !exists('s:rubylint_new')
let ver = syntastic#util#getVersion(self.getExecEscaped() . ' --version')
call self.log(self.getExec() . ' version =', ver)
let s:rubylint_new = syntastic#util#versionIsAtLeast(ver, [2])
let s:rubylint_new = syntastic#util#versionIsAtLeast(self.getVersion(), [2])
endif
let makeprg = self.makeprgBuild({ 'args': (s:rubylint_new ? '' : 'analyze ') . '--presenter=syntastic' })

View File

@ -21,11 +21,7 @@ function! SyntaxCheckers_scss_scss_lint_IsAvailable() dict
if !executable(self.getExec())
return 0
endif
let ver = syntastic#util#getVersion(self.getExecEscaped() . ' --version')
call self.log(self.getExec() . ' version =', ver)
return syntastic#util#versionIsAtLeast(ver, [0, 12])
return syntastic#util#versionIsAtLeast(self.getVersion(), [0, 12])
endfunction
function! SyntaxCheckers_scss_scss_lint_GetLocList() dict

View File

@ -20,8 +20,7 @@ set cpo&vim
function! SyntaxCheckers_slim_slimrb_GetLocList() dict
if !exists('s:slimrb_new')
let ver = syntastic#util#getVersion(self.getExecEscaped() . ' --version 2>'. syntastic#util#DevNull())
call self.log(self.getExec() . ' version =', ver)
let ver = self.getVersion(self.getExecEscaped() . ' --version 2>'. syntastic#util#DevNull())
let s:slimrb_new = syntastic#util#versionIsAtLeast(ver, [1, 3, 1])
endif

View File

@ -0,0 +1,48 @@
"============================================================================
"File: xcrun.vim
"Description: swift syntax checker - using xcrun
"Maintainer: Tom Fogg <tom@canobe.com>
"License: This program is free software. It comes without any warranty,
" to the extent permitted by applicable law. You can redistribute
" it and/or modify it under the terms of the Do What The Fuck You
" Want To Public License, Version 2, as published by Sam Hocevar.
" See http://sam.zoy.org/wtfpl/COPYING for more details.
"============================================================================
if exists("g:loaded_syntastic_swift_xcrun_checker")
finish
endif
let g:loaded_syntastic_xcrun_checker = 1
let s:save_cpo = &cpo
set cpo&vim
function! SyntaxCheckers_swift_xcrun_GetLocList() dict
let makeprg = self.makeprgBuild({ 'args_after': 'swift' })
let errorformat=
\ '%f:%l:%c:{%*[^}]}: %trror: %m,'.
\ '%f:%l:%c:{%*[^}]}: fatal %trror: %m,'.
\ '%f:%l:%c:{%*[^}]}: %tarning: %m,'.
\ '%f:%l:%c: %trror: %m,'.
\ '%f:%l:%c: fatal %trror: %m,'.
\ '%f:%l:%c: %tarning: %m,'.
\ '%f:%l: %trror: %m,'.
\ '%f:%l: fatal %trror: %m,'.
\ '%f:%l: %tarning: %m,' .
\ '%-G%.%#'
return SyntasticMake({
\ 'makeprg': makeprg,
\ 'errorformat': errorformat })
endfunction
call g:SyntasticRegistry.CreateAndRegisterChecker({
\ 'filetype': 'swift',
\ 'name': 'xcrun'})
let &cpo = s:save_cpo
unlet s:save_cpo
" vim: set sw=4 sts=4 et fdm=marker:

View File

@ -20,9 +20,7 @@ set cpo&vim
function! SyntaxCheckers_yaml_jsyaml_GetLocList() dict
if !exists('s:js_yaml_new')
let ver = syntastic#util#getVersion(self.getExecEscaped() . ' --version')
call self.log(self.getExec() . ' version =', ver)
let s:js_yaml_new = syntastic#util#versionIsAtLeast(ver, [2])
let s:js_yaml_new = syntastic#util#versionIsAtLeast(self.getVersion(), [2])
endif
let makeprg = self.makeprgBuild({ 'args_after': (s:js_yaml_new ? '' : '--compact') })

View File

@ -89,6 +89,9 @@ endfunction
function! airline#update_statusline()
for nr in filter(range(1, winnr('$')), 'v:val != winnr()')
if airline#util#getwinvar(nr, 'airline_disabled', 0)
continue
endif
call setwinvar(nr, 'airline_active', 0)
let context = { 'winnr': nr, 'active': 0, 'bufnr': winbufnr(nr) }
call s:invoke_funcrefs(context, s:inactive_funcrefs)

View File

@ -105,7 +105,7 @@ function! airline#init#sections()
let g:airline_section_y = airline#section#create_right(['ffenc'])
endif
if !exists('g:airline_section_z')
let g:airline_section_z = airline#section#create(['windowswap', '%3p%%'.spc, 'linenr', ':%3c '])
let g:airline_section_z = airline#section#create(['windowswap', '%3p%%'.spc, 'linenr', ':%3v '])
endif
if !exists('g:airline_section_warning')
let g:airline_section_warning = airline#section#create(['syntastic', 'eclim', 'whitespace'])

View File

@ -126,6 +126,11 @@ values):
heavily) >
let g:airline_exclude_preview = 0
<
* disable the Airline customization for selective windows (this is a
window-local variable so you can disable it for only some windows) >
let w:airline_disabled = 1
<
==============================================================================
COMMANDS *airline-commands*

View File

@ -44,7 +44,7 @@ describe 'init sections'
it 'section z should be line numbers'
Expect g:airline_section_z =~ '%3p%%'
Expect g:airline_section_z =~ '%4l'
Expect g:airline_section_z =~ '%3c'
Expect g:airline_section_z =~ '%3v'
end
it 'should not redefine sections already defined'

View File

@ -1,6 +1,6 @@
" fugitive.vim - A Git wrapper so awesome, it should be illegal
" Maintainer: Tim Pope <http://tpo.pe/>
" Version: 2.1
" Version: 2.2
" GetLatestVimScripts: 2975 1 :AutoInstall: fugitive.vim
if exists('g:loaded_fugitive') || &cp
@ -1759,7 +1759,7 @@ function! s:Diff(vert,...) abort
let winnr = winnr()
if getwinvar('#', '&diff')
wincmd p
call feedkeys("\<C-W>p", 'n')
call feedkeys(winnr."\<C-W>w", 'n')
endif
return ''
catch /^fugitive:/

View File

@ -189,6 +189,22 @@ let g:go_highlight_structs = 1
## Troubleshooting
### Command not found
If trying to use `:GoDef`, `:GoInfo` and get a `command not found`, check that you have the binaries installed by using: `:GoInstallBinaries`
Before opening vim, check your current `$PATH`:
echo $PATH
after opening vim, run `:echo $PATH`, the output must be your current `$PATH` + `$PATH/bin` (the location where `:GoInstallBinaries` installed the binaries
If problem persists and you are using maybe 'csh' or other shell, try adding this to your .vimrc:
set shell=/bin/sh
### I'm using Fish shell but have some problems using Vim-go
First environment variables in Fish are applied differently, it should be like:
@ -202,13 +218,12 @@ too). To overcome this problem change the default shell by adding the following
into your .vimrc (on the top of the file):
if $SHELL =~ 'fish'
set shell='/bin/bash'
set shell='/bin/sh'
endif
or
set shell='/bin/bash'
set shell='/bin/sh'
## Why another plugin?
@ -221,6 +236,12 @@ months under heavy go development environment.
Give it a try. I hope you like it. Feel free to contribute to the project.
## Donations
Vim-go is an open source project and I'm working on it on my free times. I'm spending a lot of time and thoughts to make it stable, fixing bugs, adding new features, etc... If you like vim-go and find it helpful, you might give me a gift from some of the books (kindle) I have in my wish list:
[Amazon.com Fatih's Wish List](http://amzn.com/w/3RUTKZC0U30P6). Thanks!
## Credits
* Go Authors for official vim plugins

View File

@ -19,7 +19,12 @@ fu! s:gocodeCurrentBuffer()
return file
endf
let s:vim_system = get(g:, 'gocomplete#system_function', 'system')
if go#vimproc#has_vimproc()
let s:vim_system = get(g:, 'gocomplete#system_function', 'vimproc#system2')
else
let s:vim_system = get(g:, 'gocomplete#system_function', 'system')
endif
fu! s:system(str, ...)
return call(s:vim_system, [a:str] + a:000)

View File

@ -5,6 +5,10 @@ endif
function! go#errcheck#Run(...) abort
if a:0 == 0
let package = go#package#ImportPath(expand('%:p:h'))
if package == -1
echohl Error | echomsg "vim-go: package is not inside GOPATH src" | echohl None
return
endif
else
let package = a:1
end
@ -14,6 +18,7 @@ function! go#errcheck#Run(...) abort
return
endif
echon "vim-go: " | echohl Identifier | echon "errcheck analysing ..." | echohl None
let out = system(bin_path . ' ' . package)
if v:shell_error
let errors = []
@ -28,15 +33,21 @@ function! go#errcheck#Run(...) abort
\"text": tokens[4]})
endif
endfor
if empty(errors)
% | " Couldn't detect error format, output errors
echohl Error | echomsg "GoErrCheck returned error" | echohl None
echo out
endif
if !empty(errors)
redraw | echo
call setqflist(errors, 'r')
endif
echohl Error | echomsg "GoErrCheck returned error" | echohl None
else
call setqflist([])
endif
cwindow
endfunction
" vim:ts=4:sw=4:et

View File

@ -74,8 +74,15 @@ function! go#fmt#Format(withGoimport)
" get the command first so we can test it
let fmt_command = g:go_fmt_command
if a:withGoimport == 1
let fmt_command = g:go_goimports_bin
endif
" if it's something else than gofmt, we need to check the existing of that
" binary. For example if it's goimports, let us check if it's installed,
" if not the user get's a warning via go#tool#BinPath()
if fmt_command != "gofmt"
" check if the user has installed goimports
let bin_path = go#tool#BinPath(g:go_goimports_bin)
let bin_path = go#tool#BinPath(fmt_command)
if empty(bin_path)
return
endif

View File

@ -32,7 +32,8 @@ function! go#tool#Imports()
endif
for package_path in split(out, '\n')
let package_name = fnamemodify(package_path, ":t:r")
let cmd = "go list -f {{.Name}} " . package_path
let package_name = substitute(go#tool#ExecuteInDir(cmd), '\n$', '', '')
let imports[package_name] = package_path
endfor

View File

@ -0,0 +1,21 @@
"Check if has vimproc
function! go#vimproc#has_vimproc()
if !exists('g:go#use_vimproc')
if IsWin()
try
call vimproc#version()
let exists_vimproc = 1
catch
let exists_vimproc = 0
endtry
else
let exists_vimproc = 0
endif
let g:go#use_vimproc = exists_vimproc
endif
return g:go#use_vimproc
endfunction
" vim:ts=4:sw=4:et

View File

@ -558,6 +558,12 @@ Highlights method names. By default it's disabled. >
Highlights struct names. By default it's disabled. >
let g:go_highlight_structs = 0
<
*'g:go_highlight_build_constraints'*
Highlights build constraints. By default it's disabled. >
let g:go_highlight_build_constraints = 0
<
*'g:go_textobj_enabled'*

View File

@ -10,8 +10,9 @@ endsnippet
# anonymous function
snippet anon "fn := func() { ... }"
${1:fn} := func() {
${0}
${2:${VISUAL}}
}
${0}
endsnippet
# append
@ -192,7 +193,7 @@ endsnippet
# Fmt Printf debug
snippet ff "fmt.Printf(...)"
fmt.Printf("${1} = %+v\n", $1)
fmt.Printf("${1:${VISUAL}} = %+v\n", $1)
endsnippet
# Fmt Println debug
@ -294,8 +295,9 @@ endsnippet
# goroutine anonymous function
snippet gof "go func() { ... }()"
go func() {
${1}
${1:${VISUAL}}
}()
${0}
endsnippet
# test function

View File

@ -9,7 +9,7 @@ let g:go_loaded_install = 1
let s:packages = [
\ "github.com/nsf/gocode",
\ "golang.org/x/tools/cmd/goimports",
\ "code.google.com/p/rog-go/exp/cmd/godef",
\ "github.com/rogpeppe/godef",
\ "golang.org/x/tools/cmd/oracle",
\ "golang.org/x/tools/cmd/gorename",
\ "github.com/golang/lint/golint",
@ -166,11 +166,6 @@ function! s:CheckBinaries()
echohl Error | echomsg "vim-go: git executable not found." | echohl None
return -1
endif
if !executable('hg')
echohl Error | echomsg "vim.go: hg (mercurial) executable not found." | echohl None
return -1
endif
endfunction
" Autocommands

View File

@ -67,6 +67,10 @@ if !exists("g:go_highlight_structs")
let g:go_highlight_structs = 0
endif
if !exists("g:go_highlight_build_constraints")
let g:go_highlight_build_constraints = 0
endif
syn case match
syn keyword goDirective package import
@ -270,6 +274,21 @@ endif
hi def link goStruct Function
hi def link goStructDef Function
" Build Constraints
if g:go_highlight_build_constraints != 0
syn keyword goBuildOs contained ignore cgo android darwin dragonfly freebsd linux nacl netbsd openbsd plan9 solaris windows
syn keyword goBuildArch contained 386 amd64 amd64p32 arm
syn match goBuildDirective display contained "+build"
syn region goBuildComment start="//\s*+build" end="$" contains=goBuildDirective,goBuildOs,goBuildArch
syn region goBuildComment start="/\*\s*+build" end="\*/" contains=goBuildDirective,goBuildOs,goBuildArch
endif
hi def link goBuildComment Comment
hi def link goBuildOs Type
hi def link goBuildArch Type
hi def link goBuildDirective PreProc
" Search backwards for a global declaration to start processing the syntax.
"syn sync match goSync grouphere NONE /^\(const\|var\|type\|func\)\>/

View File

@ -69,7 +69,7 @@ By default, the 'next' key is also used to enter multicursor mode. If you want t
let g:multi_cursor_start_key='<F6>'
```
Note that when multicursor mode is started, it selects current word without boundaries, i.e. it behavies like `g*`. If you want to use word boundaries in Normal mode (as `*` does) but still have old behaviour up your sleeve, you can do the following:
Note that when multicursor mode is started, it selects current word without boundaries, i.e. it behaves like `g*`. If you want to use word boundaries in Normal mode (as `*` does) but still have old behaviour up your sleeve, you can do the following:
```
let g:multi_cursor_start_key='g<C-n>'
let g:multi_cursor_start_word_key='<C-n>'

View File

@ -236,6 +236,14 @@ function! multiple_cursors#find(start, end, pattern)
return
else
echohl Normal | echo 'Added '.s:cm.size().' cursor'.(s:cm.size()>1?'s':'') | echohl None
" If we've created any cursors, we need to call the before function, end
" function will be called via normal routes
if exists('*Multiple_cursors_before') && !s:before_function_called
exe "call Multiple_cursors_before()"
let s:before_function_called = 1
endif
call s:wait_for_user_input('v')
endif
endfunction
@ -458,8 +466,8 @@ function! s:CursorManager.update_current() dict
call cur.update_visual_selection(s:get_visual_region(s:pos('.')))
elseif s:from_mode ==# 'v' || s:from_mode ==# 'V'
call cur.remove_visual_selection()
elseif s:from_mode ==# 'i' && s:to_mode ==# 'n' && self.current_index == self.size() - 1
normal! `^
elseif s:from_mode ==# 'i' && s:to_mode ==# 'n' && self.current_index != self.size() - 1
normal! h
endif
let vdelta = line('$') - s:saved_linecount
" If the total number of lines changed in the buffer, we need to potentially
@ -985,7 +993,9 @@ endfunction
let s:retry_keys = ""
function! s:display_error()
if s:bad_input == s:cm.size() && has_key(g:multi_cursor_normal_maps, s:char[0])
if s:bad_input == s:cm.size()
\ && s:from_mode ==# 'n'
\ && has_key(g:multi_cursor_normal_maps, s:char[0])
" we couldn't replay it anywhere but we're told it's the beginning of a
" multi-character map like the `d` in `dw`
let s:retry_keys = s:char
@ -1037,14 +1047,14 @@ function! s:last_char()
endfunction
function! s:wait_for_user_input(mode)
call s:display_error()
let s:from_mode = a:mode
if empty(a:mode)
let s:from_mode = s:to_mode
endif
let s:to_mode = ''
call s:display_error()
" Right before redraw, apply the highlighting bug fix
call s:apply_highlight_fix()

View File

@ -110,7 +110,7 @@ mode than for selecting the next location, do like the following: >
*g:multi_cursor_start_word_key*
When multicursor mode is started, it selects current word without
boundaries, i.e. it behavies like `g*`. If you want to use word boundaries in
boundaries, i.e. it behaves like `g*`. If you want to use word boundaries in
Normal mode (as `*` does) but still have old behaviour up your sleeve, you can
do the following: >

View File

@ -89,10 +89,18 @@ function! repeat#run(count)
let c = g:repeat_count
let s = g:repeat_sequence
let cnt = c == -1 ? "" : (a:count ? a:count : (c ? c : ''))
call feedkeys(r . cnt, 'n')
call feedkeys(s)
if ((v:version == 703 && has('patch100')) || (v:version == 704 && !has('patch601')))
exe 'norm ' . r . cnt . s
else
call feedkeys((a:count ? a:count : '') . '.', 'n')
call feedkeys(r . cnt, 'ni')
call feedkeys(s, 'i')
endif
else
if ((v:version == 703 && has('patch100')) || (v:version == 704 && !has('patch601')))
exe 'norm! '.(a:count ? a:count : '') . '.'
else
call feedkeys((a:count ? a:count : '') . '.', 'ni')
endif
endif
endfunction

View File

@ -81,6 +81,23 @@ does `:SnipMateLoadScope rails` when editing a Rails project for example.
* Fix the use of the visual map at the end of a line
* Add `:SnipMateLoadScope` command and buffer-local scope aliases
* Load `<scope>_*.snippets` files
* Indent visual placeholder expansions and remove extraneous lines ([#177][177]
and [#178][178])
* The nested branch has been merged
* A new snippet parser has been added. The g:snipmate.version as well as
version lines in snippet files determines which is used
* The new parser supports tab stops placed within placeholders,
substitutions, non-consecutive stop numbers, and fewer ambiguities
* The stop jumping code has been updated
* Tests have been added for the jumping code and the new parser
* The override branch has been merged
* The g:snipMate.override option is added. When enabled, if two snippets
share the same name, the later-loaded one is kept and the other discarded
* Override behavior can be enabled on a per-snippet basis with a bang (!) in
the snippet file
* Otherwise, SnipMate tries to preserve all snippets loaded
### 0.87 - 2014-01-04 ###
@ -106,3 +123,5 @@ does `:SnipMateLoadScope rails` when editing a Rails project for example.
[vundle]: https://github.com/gmarik/vundle
[143]: https://github.com/garbas/vim-snipmate/issues/143
[177]: https://github.com/garbas/vim-snipmate/issues/177
[178]: https://github.com/garbas/vim-snipmate/issues/178

View File

@ -9,35 +9,39 @@ catch /.*/
echoe "you're missing tlib. See install instructions at ".expand('<sfile>:h:h').'/README.md'
endtry
" match $ which doesn't follow a \
let s:d = nr2char(31)
fun! Filename(...)
let filename = expand('%:t:r')
if filename == '' | return a:0 == 2 ? a:2 : '' | endif
return !a:0 || a:1 == '' ? filename : substitute(a:1, '$1', filename, 'g')
endf
let s:state_proto = {}
let s:cache = {}
fun! s:state_proto.remove()
unlet! b:snip_state
" Remove all buffer-local autocommands in the snipmate_changes group
au! snipmate_changes * <buffer>
endf
fun! snipMate#expandSnip(snip, col)
let lnum = line('.') | let col = a:col
let snippet = s:ProcessSnippet(a:snip)
" Avoid error if eval evaluates to nothing
if snippet == '' | return '' | endif
" Expand snippet onto current position with the tab stops removed
let snipLines = split(substitute(snippet, ''.s:d .'\d\+\|'.s:d .'{\d\+.\{-}}', '', 'g'), "\n", 1)
function! snipMate#expandSnip(snip, version, col)
let lnum = line('.')
let col = a:col
let line = getline(lnum)
let indent = match(line, '\S\|$') + 1
let b:snip_state = snipmate#jumping#state()
if a:version == 1
let [snippet, b:snip_state.stops] = snipmate#parse#snippet(a:snip)
" Build stop/mirror info
let b:snip_state.stop_count = s:build_stops(snippet, b:snip_state.stops, lnum, col, indent)
let snipLines = snipMate#sniplist_str(snippet, b:snip_state.stops)
else
let snippet = snipmate#legacy#process_snippet(a:snip)
let [b:snip_state.stops, b:snip_state.stop_count] = snipmate#legacy#build_stops(snippet, lnum, col - indent, indent)
let snipLines = split(substitute(snippet, printf('%s\d\+\|%s{\d\+.\{-}}',
\ g:snipmate#legacy#sigil, g:snipmate#legacy#sigil), '', 'g'), "\n", 1)
endif
" Abort if the snippet is empty
if empty(snippet)
return ''
endif
" Expand snippet onto current position
let afterCursor = strpart(line, col - 1)
" Keep text after the cursor
if afterCursor != "\t" && afterCursor != ' '
@ -52,17 +56,14 @@ fun! snipMate#expandSnip(snip, col)
endif
" Insert snippet with proper indentation
let indent = match(line, '\S\|$') + 1
call setline(lnum, line . snipLines[0])
call append(lnum, map(snipLines[1:], "empty(v:val) ? v:val : '" . strpart(line, 0, indent - 1) . "' . v:val"))
" Open any folds snippet expands into
if &fen | sil! exe lnum.','.(lnum + len(snipLines) - 1).'foldopen' | endif
if &foldenable
silent! exec lnum . ',' . (lnum + len(snipLines) - 1) . 'foldopen'
endif
let b:snip_state = copy(s:state_proto)
let [b:snip_state.stops, b:snip_state.stop_count] = s:BuildTabStops(snippet, lnum, col - indent, indent)
if b:snip_state.stop_count
aug snipmate_changes
au CursorMoved,CursorMovedI <buffer> if exists('b:snip_state') |
\ call b:snip_state.update_changes() |
@ -70,318 +71,128 @@ fun! snipMate#expandSnip(snip, col)
\ silent! au! snipmate_changes * <buffer> |
\ endif
aug END
call b:snip_state.set_stop(0)
let ret = b:snip_state.select_word()
if b:snip_state.stop_count == 1
call b:snip_state.remove()
endif
let b:snip_state.stop_no = 0
return b:snip_state.set_stop(0)
endfunction
return ret
function! snipMate#placeholder_str(num, stops)
return snipMate#sniplist_str(a:stops[a:num].placeholder, a:stops)[0]
endfunction
function! snipMate#sniplist_str(snippet, stops)
let lines = ['']
let pos = 0
let add_to = 1
let seen_stops = []
while pos < len(a:snippet)
let item = a:snippet[pos]
if type(item) == type('')
if add_to
let lines[-1] .= item
else
unlet b:snip_state
" Place cursor at end of snippet if no tab stop is given
let newlines = len(snipLines) - 1
call cursor(lnum + newlines, indent + len(snipLines[-1]) - len(afterCursor)
\ + (newlines ? 0: col - 1))
call add(lines, item)
endif
let add_to = 0
elseif type(item) == type([])
let lines[-1] .= snipMate#placeholder_str(item[0], a:stops)
let add_to = 1
endif
return ''
endf
" Update state information to correspond to the given tab stop
function! s:state_proto.set_stop(stop)
let self.stop_no = a:stop
let self.cur_stop = self.stops[self.stop_no]
let self.end_col = self.cur_stop[1] + self.cur_stop[2]
let self.start_col = self.cur_stop[1]
call cursor(self.cur_stop[0], self.cur_stop[1])
let self.prev_len = col('$')
let self.has_vars = exists('self.cur_stop[3]')
let self.old_vars = self.has_vars ? deepcopy(self.cur_stop[3]) : []
let pos += 1
unlet item " avoid E706
endwhile
return lines
endfunction
" Prepare snippet to be processed by s:BuildTabStops
fun! s:ProcessSnippet(snip)
let snippet = a:snip
let esc_bslash = '\%(\\\@<!\%(\\\\\)*\)\@<='
function! s:build_stops(snippet, stops, lnum, col, indent)
let stops = a:stops
let line = a:lnum
let col = a:col
if exists('b:snipmate_content_visual')
let visual = substitute(b:snipmate_content_visual, "\n$", '', '')
unlet b:snipmate_content_visual
for [id, dict] in items(stops)
for i in dict.instances
if len(i) > 1 && type(i[1]) != type({})
if !has_key(dict, 'placeholder')
let dict.placeholder = i[1:]
else
let visual = ''
unlet i[1:]
endif
let snippet = substitute(snippet, '\n\(\t\+\).\{-\}\zs{VISUAL}',
\ substitute(escape(visual, '%\'), "\n", "\n\\\\1", 'g'), 'g')
endif
endfor
if !has_key(dict, 'placeholder')
let dict.placeholder = []
let j = 0
while len(dict.instances[j]) > 1
let j += 1
endwhile
call add(dict.instances[j], '')
endif
unlet dict.instances
endfor
" Evaluate eval (`...`) expressions.
" Backquotes prefixed with a backslash "\" are ignored.
" And backslash can be escaped by doubling it.
" Using a loop here instead of a regex fixes a bug with nested "\=".
if stridx(snippet, '`') != -1
let new = []
let snip = split(snippet, esc_bslash . '`', 1)
let isexp = 0
for i in snip
if isexp
call add(new, substitute(eval(i), "\n\\%$", '', ''))
let [line, col] = s:build_loc_info(a:snippet, stops, line, col, a:indent)
" add zero tabstop if it doesn't exist and then link it to the highest stop
" number
let stops[0] = get(stops, 0,
\ { 'placeholder' : [], 'line' : line, 'col' : col })
let stop_count = max(keys(stops)) + 2
let stops[stop_count - 1] = stops[0]
return stop_count
endfunction
function! s:build_loc_info(snippet, stops, line, col, indent)
let stops = a:stops
let line = a:line
let col = a:col
let pos = 0
let in_text = 0
while pos < len(a:snippet)
let item = a:snippet[pos]
if type(item) == type('')
if in_text
let line += 1
let col = a:indent
endif
let col += len(item)
let in_text = 1
elseif type(item) == type([])
let id = item[0]
if len(item) > 1 && type(item[1]) != type({})
let stops[id].line = line
let stops[id].col = col
let [line, col] = s:build_loc_info(item[1:], stops, line, col, a:indent)
else
call add(new, i)
call s:add_mirror(stops, id, line, col, item)
let col += len(snipMate#placeholder_str(id, stops))
endif
let isexp = !isexp
endfor
let snippet = join(new, '')
let snippet = substitute(snippet, "\r", "\n", 'g')
let snippet = substitute(snippet, '\\`', "`", 'g')
let in_text = 0
endif
" Place all text after a colon in a tab stop after the tab stop
" (e.g. "${#:foo}" becomes "${:foo}foo").
" This helps tell the position of the tab stops later.
let snippet = substitute(snippet, esc_bslash . '\$\({\d\+:\(.\{-}\)}\|{\d\+}\)', s:d . '\1\2', 'g')
let snippet = substitute(snippet, esc_bslash . '\$\(\d\+\)', s:d . '\1', 'g')
let snippet = substitute(snippet, esc_bslash . '\\\$', '$', 'g')
let snippet = substitute(snippet, '\\\\', "\\", 'g')
let pos += 1
unlet item " avoid E706
endwhile
" Update the a:snip so that all the $# become the text after
" the colon in their associated ${#}.
" (e.g. "${1:foo}" turns all "$1"'s into "foo")
let i = 1
while snippet =~ s:d.'{'.i
let s = matchstr(snippet, s:d.'{'.i.':\zs.\{-}\ze}')
if s != ''
let snippet = substitute(snippet, s:d.i, s.'&', 'g')
endif
let i += 1
endw
" Add ${0} tab stop if found
if snippet =~ s:d . '{0'
let snippet = substitute(snippet, s:d.'{0', s:d . '{' . i, '')
let s = matchstr(snippet, s:d.'{'.i.':\zs.\{-}\ze}')
if s != ''
let snippet = substitute(snippet, s:d.'0', s:d . i, 'g')
let snippet = substitute(snippet, s:d.i, s.'&', 'g')
endif
else
let snippet .= s:d . '{'.i.'}'
endif
if &et " Expand tabs to spaces if 'expandtab' is set.
return substitute(snippet, '\t', repeat(' ', (&sts > 0) ? &sts : &sw), 'g')
endif
return snippet
endf
" Counts occurences of haystack in needle
fun! s:Count(haystack, needle)
let counter = 0
let index = stridx(a:haystack, a:needle)
while index != -1
let index = stridx(a:haystack, a:needle, index+1)
let counter += 1
endw
return counter
endf
" Builds a list of a list of each tab stop in the snippet containing:
" 1.) The tab stop's line number.
" 2.) The tab stop's column number
" (by getting the length of the string between the last "\n" and the
" tab stop).
" 3.) The length of the text after the colon for the current tab stop
" (e.g. "${1:foo}" would return 3).
" 4.) If the "${#:}" construct is given, another list containing all
" the matches of "$#", to be replaced with the placeholder. This list is
" composed the same way as the parent; the first item is the line number,
" and the second is the column.
fun! s:BuildTabStops(snip, lnum, col, indent)
let snipPos = []
let i = 1
let withoutVars = substitute(a:snip, s:d . '\d\+', '', 'g')
while a:snip =~ s:d.'{'.i
let beforeTabStop = matchstr(withoutVars, '^.*\ze'.s:d .'{'.i.'\D')
let withoutOthers = substitute(withoutVars, ''.s:d .'{\('.i.'\D\)\@!\d\+.\{-}}', '', 'g')
let j = i - 1
call add(snipPos, [0, 0, 0])
let snipPos[j][0] = a:lnum + s:Count(beforeTabStop, "\n")
let snipPos[j][1] = a:indent + len(matchstr(withoutOthers, '.*\(\n\|^\)\zs.*\ze'.s:d .'{'.i.'\D'))
if snipPos[j][0] == a:lnum | let snipPos[j][1] += a:col | endif
" Get all $# matches in another list, if ${#:name} is given
if withoutVars =~ ''.s:d .'{'.i.':'
let snipPos[j][2] = len(matchstr(withoutVars, ''.s:d .'{'.i.':\zs.\{-}\ze}'))
let dots = repeat('.', snipPos[j][2])
call add(snipPos[j], [])
let withoutOthers = substitute(a:snip, ''.s:d .'{\d\+.\{-}}\|'.s:d .''.i.'\@!\d\+', '', 'g')
while match(withoutOthers, ''.s:d .''.i.'\(\D\|$\)') != -1
let beforeMark = matchstr(withoutOthers, '^.\{-}\ze'.dots.''.s:d .''.i.'\(\D\|$\)')
call add(snipPos[j][3], [0, 0])
let snipPos[j][3][-1][0] = a:lnum + s:Count(beforeMark, "\n")
let snipPos[j][3][-1][1] = a:indent + (snipPos[j][3][-1][0] > a:lnum
\ ? len(matchstr(beforeMark, '.*\n\zs.*'))
\ : a:col + len(beforeMark))
let withoutOthers = substitute(withoutOthers, ''.s:d .''.i.'\ze\(\D\|$\)', '', '')
endw
endif
let i += 1
endw
return [snipPos, i - 1]
endf
function! s:state_proto.jump_stop(backwards)
" Update changes just in case
" This seems to be only needed because insert completion does not trigger
" the CursorMovedI event
call self.update_changes()
" Update stop and var locations
call self.update_stops()
" Store the changed col/length of the current stop
let self.cur_stop[1] = self.start_col
let self.cur_stop[2] = self.end_col - self.start_col
let self.stop_no += a:backwards ? -1 : 1
" Loop over the snippet when going backwards from the beginning
if self.stop_no < 0 | let self.stop_no = self.stop_count - 1 | endif
call self.set_stop(self.stop_no)
let ret = self.select_word()
if self.stop_no == self.stop_count - 1
call self.remove()
endif
return ret
return [line, col]
endfunction
" Updates tab stops/vars
function! s:state_proto.update_stops()
let changeLen = self.end_col - self.cur_stop[2] - self.start_col
" Update tab stops in snippet if text has been added via "$#"
" (e.g., in "${1:foo}bar$1${2}").
if changeLen != 0
let curLine = line('.')
for pos in self.stops
if pos == self.cur_stop | continue | endif
let changed = pos[0] == curLine && pos[1] > self.cur_stop[1]
let changedVars = 0
let endPlaceholder = pos[2] - 1 + pos[1]
" Subtract changeLen from each tab stop that was after any of
" the current tab stop's placeholders.
for [lnum, col] in self.old_vars
if lnum > pos[0] | break | endif
if pos[0] == lnum
if pos[1] > col || (pos[2] == -1 && pos[1] == col)
let changed += 1
elseif col < endPlaceholder
let changedVars += 1
endif
endif
endfor
let pos[1] += changeLen * changed
" Parse variables within placeholders, e.g., "${1:foo} ${2:$1bar}"
let pos[2] += changeLen * changedVars
" Do the same to any placeholders in the other tab stops.
if exists('pos[3]')
for nPos in pos[3]
let changed = nPos[0] == curLine && nPos[1] > self.start_col
if changed && nPos[1] < self.start_col + self.cur_stop[2]
call remove(pos, index(pos, nPos))
continue
endif
for [lnum, col] in self.old_vars
if lnum > nPos[0] | break | endif
if nPos[0] == lnum && nPos[1] > col
let changed += 1
endif
endfor
let nPos[1] += changeLen * changed
endfor
endif
endfor
endif
endfunction
" Select the placeholder for the current tab stop
function! s:state_proto.select_word()
let len = self.cur_stop[2]
if !len | return '' | endif
let l = col('.') != 1 ? 'l' : ''
if &sel == 'exclusive'
return "\<esc>".l.'v'.len."l\<c-g>"
endif
return len == 1 ? "\<esc>".l.'gh' : "\<esc>".l.'v'.(len - 1)."l\<c-g>"
endfunction
" Update the snippet as text is typed. The self.update_vars() function does
" the actual work.
" If the cursor moves outside of a placeholder, call self.remove()
function! s:state_proto.update_changes()
let change_len = col('$') - self.prev_len
let self.end_col += change_len
let col = col('.')
if mode() == 'i'
if line('.') != self.cur_stop[0]
\ || col < self.start_col || col > self.end_col
call self.remove()
elseif self.has_vars
call self.update_vars(change_len)
endif
endif
let self.prev_len = col('$')
endfunction
" Actually update the vars for any changed text
function! s:state_proto.update_vars(change)
let newWordLen = self.end_col - self.start_col
let newWord = strpart(getline('.'), self.start_col - 1, newWordLen)
let changeLen = a:change
let curLine = line('.')
let curCol = col('.')
let oldStartSnip = self.start_col
let updateTabStops = changeLen != 0
let i = 0
for [lnum, col] in self.cur_stop[3]
if updateTabStops
let start = self.start_col
if lnum == curLine && col <= start
let self.start_col += changeLen
let self.end_col += changeLen
endif
for nPos in self.cur_stop[3][(i):]
" This list is in ascending order, so quit if we've gone too far.
if nPos[0] > lnum | break | endif
if nPos[0] == lnum && nPos[1] > col
let nPos[1] += changeLen
endif
endfor
if lnum == curLine && col > start
let col += changeLen
let self.cur_stop[3][i][1] = col
endif
let i += 1
endif
" Split the line into three parts: the mirror, what's before it, and
" what's after it. Then combine them using the new mirror string.
" Subtract one to go from column index to byte index
let theline = getline(lnum)
let update = strpart(theline, 0, col - 1)
let update .= newWord
let update .= strpart(theline, col + self.end_col - self.start_col - a:change - 1)
call setline(lnum, update)
endfor
" Reposition the cursor in case a var updates on the same line but before
" the current tabstop
if oldStartSnip != self.start_col || mode() == 'i'
call cursor(0, curCol + self.start_col - oldStartSnip)
function! s:add_mirror(stops, id, line, col, item)
let stops = a:stops
let item = a:item
let stops[a:id].mirrors = get(stops[a:id], 'mirrors', [])
let mirror = get(a:item, 1, {})
let mirror.line = a:line
let mirror.col = a:col
call add(stops[a:id].mirrors, mirror)
if len(item) == 1
call add(item, mirror)
endif
endfunction
@ -396,6 +207,7 @@ fun! snipMate#ReadSnippetsFile(file)
if !filereadable(a:file) | return [result, new_scopes] | endif
let inSnip = 0
let line_no = 0
let snipversion = get(g:snipMate, 'snippet_version', 0)
for line in readfile(a:file) + ["\n"]
let line_no += 1
@ -403,13 +215,15 @@ fun! snipMate#ReadSnippetsFile(file)
let content .= strpart(line, 1)."\n"
continue
elseif inSnip
call add(result, [trigger, name == '' ? 'default' : name, content[:-2]])
call add(result, [trigger, name,
\ content[:-2], bang, snipversion])
let inSnip = 0
endif
if line[:6] == 'snippet'
let inSnip = 1
let trigger = strpart(line, 8)
let bang = (line[7] == '!')
let trigger = strpart(line, 8 + bang)
let name = ''
let space = stridx(trigger, ' ') + 1
if space " Process multi snip
@ -424,6 +238,8 @@ fun! snipMate#ReadSnippetsFile(file)
elseif line[:6] == 'extends'
call extend(new_scopes, map(split(strpart(line, 8)),
\ "substitute(v:val, ',*$', '', '')"))
elseif line[:6] == 'version'
let snipversion = +strpart(line, 8)
endif
endfor
return [result, new_scopes]
@ -464,80 +280,40 @@ fun! s:AddScopeAliases(list)
return keys(did)
endf
if v:version < 704 || has('win32')
function! s:Glob(path, expr)
let res = []
for p in split(a:path, ',')
let h = split(fnamemodify(a:expr, ':h'), '/')[0]
if isdirectory(p . '/' . h)
call extend(res, split(glob(p . '/' . a:expr), "\n"))
endif
endfor
return filter(res, 'filereadable(v:val)')
endfunction
else
function! s:Glob(path, expr)
return split(globpath(a:path, a:expr), "\n")
endfunction
endif
au SourceCmd *.snippet,*.snippets call s:source_snippet()
" returns dict of
" { path: { 'type': one of 'snippet' 'snippets',
" 'exists': 1 or 0
" " for single snippet files:
" 'name': name of snippet
" 'trigger': trigger of snippet
" }
" }
" use mustExist = 1 to return existing files only
"
" mustExist = 0 is used by OpenSnippetFiles
function! snipMate#GetSnippetFiles(mustExist, scopes, trigger)
let paths = join(funcref#Call(g:snipMate.snippet_dirs), ',')
let result = {}
let scopes = s:AddScopeAliases(a:scopes)
let trigger = escape(a:trigger, "*[]?{}`'$")
" collect existing files
for scope in scopes
for f in s:Glob(paths, 'snippets/' . scope . '.snippets') +
\ s:Glob(paths, 'snippets/' . scope . '_*.snippets') +
\ s:Glob(paths, 'snippets/' . scope . '/*.snippets')
let result[f] = { 'exists' : 1, 'type' : 'snippets',
\ 'name_prefix' : fnamemodify(f, ':t:r') }
endfor
" We check for trigger* in the next two loops. In the case of an exact
" match, that'll be handled in snipMate#GetSnippetsForWordBelowCursor.
for f in s:Glob(paths, 'snippets/' . scope . '/' . trigger . '*.snippet')
let result[f] = {'exists': 1, 'type': 'snippet', 'name': 'default',
\ 'trigger': fnamemodify(f, ':t:r'), 'name_prefix' : scope }
endfor
for f in s:Glob(paths, 'snippets/' . scope . '/' . trigger . '*/*.snippet')
let result[f] = {'exists': 1, 'type': 'snippet', 'name' : fnamemodify(f, ':t:r'),
\ 'trigger': fnamemodify(f, ':h:t'), 'name_prefix' : scope }
endfor
if !a:mustExist
for p in split(paths, ',')
let p .= '/snippets/' . scope . '.snippets'
let result[p] = get(result, p, {'exists': 0, 'type': 'snippets'})
endfor
endif
endfor
return result
function! s:info_from_filename(file)
let parts = split(fnamemodify(a:file, ':r'), '/')
let snipidx = len(parts) - index(reverse(copy(parts)), 'snippets') - 1
let rtp_prefix = join(parts[(snipidx -
\ (parts[snipidx - 1] == 'after' ? 3 : 2)):snipidx - 1], '/')
let trigger = get(parts, snipidx + 2, '')
let desc = get(parts, snipidx + 3, get(g:snipMate, 'override', 0) ?
\ '' : fnamemodify(a:file, ':t'))
return [rtp_prefix, trigger, desc]
endfunction
" should be moved to utils or such?
function! snipMate#SetByPath(dict, trigger, path, snippet) abort
let d = a:dict
if !has_key(d, a:trigger)
let d[a:trigger] = {}
function! s:source_snippet()
let file = expand('<afile>:p')
let [rtp_prefix, trigger, desc] = s:info_from_filename(file)
let new_snips = []
if fnamemodify(file, ':e') == 'snippet'
call add(new_snips, [trigger, desc, join(readfile(file), "\n"), 0,
\ get(g:snipMate, 'snippet_version', 0)])
else
let [snippets, extends] = s:CachedSnips(file)
let new_snips = deepcopy(snippets)
call extend(s:lookup_state.extends, extends)
endif
let d[a:trigger][a:path] = a:snippet
for snip in new_snips
if get(g:snipMate, 'override', 0)
let snip[1] = join([s:lookup_state.scope, snip[1]])
else
let snip[1] = join([s:lookup_state.scope, rtp_prefix,
\ empty(snip[1]) ? desc : snip[1]])
endif
endfor
call extend(s:lookup_state.snips, new_snips)
endfunction
function! s:CachedSnips(file)
@ -551,31 +327,50 @@ function! s:CachedSnips(file)
return s:cache[a:file].contents
endfunction
function! s:snippet_filenames(scope, trigger)
let mid = ['', '_*', '/*']
return join(map(extend(mid, map(filter(copy(mid), 'v:key != 1'),
\ "'/' . a:trigger . '*' . v:val")),
\ "'snippets/' . a:scope . v:val . '.snippet'"
\ . ". (v:key < 3 ? 's' : '')"))
endfunction
function! snipMate#SetByPath(dict, trigger, path, snippet, bang, snipversion)
let d = a:dict
if !has_key(d, a:trigger) || a:bang
let d[a:trigger] = {}
endif
let d[a:trigger][a:path] = [a:snippet, a:snipversion]
endfunction
" default triggers based on paths
function! snipMate#DefaultPool(scopes, trigger, result)
let extra_scopes = []
for [f,opts] in items(snipMate#GetSnippetFiles(1, a:scopes, a:trigger))
let opts.name_prefix = matchstr(f, '\v/\zs.{-}\ze/snippets') . ' ' . opts.name_prefix
if opts.type == 'snippets'
let [snippets, new_scopes] = s:CachedSnips(f)
call extend(extra_scopes, new_scopes)
for [trigger, name, contents] in snippets
let scopes = s:AddScopeAliases(a:scopes)
let scopes_done = []
let rtp_save = &rtp
let &rtp = join(g:snipMate.snippet_dirs, ',')
let s:lookup_state = {}
let s:lookup_state.snips = []
while !empty(scopes)
let scope = remove(scopes, 0)
let s:lookup_state.scope = scope
let s:lookup_state.extends = []
exec 'runtime!' s:snippet_filenames(scope, escape(a:trigger, "*[]?{}`'$|#%"))
call add(scopes_done, scope)
call extend(scopes, s:lookup_state.extends)
call filter(scopes, 'index(scopes_done, v:val) == -1')
endwhile
for [trigger, desc, contents, bang, snipversion] in s:lookup_state.snips
if trigger =~ '\V\^' . escape(a:trigger, '\')
call snipMate#SetByPath(a:result, trigger,
\ opts.name_prefix . ' ' . name, contents)
endif
endfor
elseif opts.type == 'snippet'
call snipMate#SetByPath(a:result, opts.trigger,
\ opts.name_prefix . ' ' . opts.name, readfile(f))
else
throw "unexpected"
call snipMate#SetByPath(a:result, trigger, desc, contents, bang, snipversion)
endif
endfor
if !empty(extra_scopes)
call snipMate#DefaultPool(extra_scopes, a:trigger, a:result)
endif
let &rtp = rtp_save
endfunction
" return a dict of snippets found in runtimepath matching trigger
@ -659,8 +454,15 @@ endf
fun! snipMate#GetSnippetsForWordBelowCursor(word, exact)
" Setup lookups: '1.2.3' becomes [1.2.3] + [3, 2.3]
let parts = split(a:word, '\W\zs')
if len(parts) > 2
let parts = parts[-2:] " max 2 additional items, this might become a setting
" Since '\W\zs' results in splitting *after* a non-keyword character, the
" first \W stays connected to whatever's before it, so split it off
if len(parts) > 1 && len(parts[0]) > 1
let parts = [ parts[0][:-2], strpart(parts[0], len(parts[0]) - 1) ]
\ + parts[1:]
endif
" Only look at the last few possibilities. Too many can be slow.
if len(parts) > 5
let parts = parts[-5:]
endif
let lookups = [a:word]
let lookup = ''
@ -671,11 +473,6 @@ fun! snipMate#GetSnippetsForWordBelowCursor(word, exact)
endif
endfor
" allow matching '.'
if a:word =~ '\.$'
call add(lookups, '.')
endif
" Remove empty lookup entries, but only if there are other nonempty lookups
if len(lookups) > 1
call filter(lookups, 'v:val != ""')
@ -795,19 +592,12 @@ function! snipMate#TriggerSnippet(...)
let snippet = ''
else
let [trigger, snippetD] = list[0]
let s = s:ChooseSnippet(snippetD)
if type(s) == type([])
let snippet = join(s, "\n")
else
let snippet = s
end
let snippet = s:ChooseSnippet(snippetD)
" Before expanding snippet, create new undo point |i_CTRL-G|
let &undolevels = &undolevels
let col = col('.') - len(trigger)
sil exe 's/\V'.escape(trigger, '/\.').'\%#//'
return snipMate#expandSnip(snippet, col)
return snipMate#expandSnip(snippet[0], snippet[1], col)
endif
" should allow other plugins to register hooks instead (duplicate code)

View File

@ -0,0 +1,205 @@
function! s:sfile()
return expand('<sfile>')
endfunction
let s:state_proto = {}
function! snipmate#jumping#state()
return copy(s:state_proto)
endfunction
function! s:listize_mirror(mirrors)
return map(copy(a:mirrors), '[v:val.line, v:val.col]')
endfunction
" Removes snippet state info
function! s:state_remove() dict
" Remove all autocmds in group snipmate_changes in the current buffer
unlet! b:snip_state
silent! au! snipmate_changes * <buffer>
endfunction
function! s:state_find_next_stop(backwards) dict
let self.stop_no += a:backwards? -1 : 1
while !has_key(self.stops, self.stop_no)
if self.stop_no == self.stop_count
let self.stop_no = 0
endif
if self.stop_no <= 0 && a:backwards
let self.stop_no = self.stop_count - 1
endif
let self.stop_no += a:backwards? -1 : 1
endwhile
endfunction
" Update state information to correspond to the given tab stop
function! s:state_set_stop(backwards) dict
call self.find_next_stop(a:backwards)
let self.cur_stop = self.stops[self.stop_no]
let self.stop_len = (type(self.cur_stop.placeholder) == type(0))
\ ? self.cur_stop.placeholder
\ : len(snipMate#placeholder_str(self.stop_no, self.stops))
let self.start_col = self.cur_stop.col
let self.end_col = self.start_col + self.stop_len
let self.mirrors = get(self.cur_stop, 'mirrors', [])
let self.old_mirrors = deepcopy(self.mirrors)
call cursor(self.cur_stop.line, self.cur_stop.col)
let self.prev_len = col('$')
let self.changed = 0
let ret = self.select_word()
if (self.stop_no == 0 || self.stop_no == self.stop_count - 1) && !a:backwards
call self.remove()
endif
return ret
endfunction
" Jump to the next/previous tab stop
function! s:state_jump_stop(backwards) dict
" Update changes just in case
" This seems to be only needed because insert completion does not trigger
" the CursorMovedI event
call self.update_changes()
" Store placeholder/location changes
let self.cur_stop.col = self.start_col
if self.changed
call self.remove_nested()
unlet! self.cur_stop.placeholder " avoid type error for old parsing version
let self.cur_stop.placeholder = [strpart(getline('.'),
\ self.start_col - 1, self.end_col - self.start_col)]
endif
return self.set_stop(a:backwards)
endfunction
function! s:state_remove_nested(...) dict
let id = a:0 ? a:1 : self.stop_no
if type(self.stops[id].placeholder) == type([])
for i in self.stops[id].placeholder
if type(i) == type([])
if type(i[1]) != type({})
call self.remove_nested(i[0])
call remove(self.stops, i[0])
else
call filter(self.stops[i[0]].mirrors, 'v:val isnot i[1]')
endif
endif
unlet i " Avoid E706
endfor
endif
endfunction
" Select the placeholder for the current tab stop
function! s:state_select_word() dict
let len = self.stop_len
if !len | return '' | endif
let l = col('.') != 1 ? 'l' : ''
if &sel == 'exclusive'
return "\<esc>".l.'v'.len."l\<c-g>"
endif
return len == 1 ? "\<esc>".l.'gh' : "\<esc>".l.'v'.(len - 1)."l\<c-g>"
endfunction
" Update the snippet as text is typed. The self.update_mirrors() function does
" the actual work.
" If the cursor moves outside of a placeholder, call self.remove()
function! s:state_update_changes() dict
let change_len = col('$') - self.prev_len
let self.changed = self.changed || change_len != 0
let self.end_col += change_len
let col = col('.')
if line('.') != self.cur_stop.line || col < self.start_col || col > self.end_col
return self.remove()
endif
call self.update(self.cur_stop, change_len)
if !empty(self.mirrors)
call self.update_mirrors(change_len)
endif
let self.prev_len = col('$')
endfunction
" Actually update the mirrors for any changed text
function! s:state_update_mirrors(change) dict
let newWordLen = self.end_col - self.start_col
let newWord = strpart(getline('.'), self.start_col - 1, newWordLen)
let changeLen = a:change
let curLine = line('.')
let curCol = col('.')
let oldStartSnip = self.start_col
let i = 0
for mirror in self.mirrors
for stop in values(filter(copy(self.stops), 'v:key != 0'))
if type(stop.placeholder) == type(0)
if mirror.line == stop.line && mirror.col > stop.col
\ && mirror.col < stop.col + stop.placeholder
let stop.placeholder += changeLen
endif
endif
endfor
call self.update(mirror, changeLen)
" Split the line into three parts: the mirror, what's before it, and
" what's after it. Then combine them using the new mirror string.
" Subtract one to go from column index to byte index
let theline = getline(mirror.line)
let update = strpart(theline, 0, mirror.col - 1)
let update .= substitute(newWord, get(mirror, 'pat', ''), get(mirror, 'sub', ''), get(mirror, 'flags', ''))
let update .= strpart(theline, mirror.col + self.end_col - self.start_col - a:change - 1)
call setline(mirror.line, update)
endfor
" Reposition the cursor in case a var updates on the same line but before
" the current tabstop
if oldStartSnip != self.start_col || mode() == 'i'
call cursor(0, curCol + self.start_col - oldStartSnip)
endif
endfunction
function! s:state_find_update_objects(item) dict
let item = a:item
let item.update_objects = []
" Filter the zeroth stop because it's duplicated as the last
for stop in values(filter(copy(self.stops), 'v:key != 0'))
if stop.line == item.line && stop.col > item.col
call add(item.update_objects, stop)
endif
for mirror in get(stop, 'mirrors', [])
if mirror.line == item.line && mirror.col > item.col
call add(item.update_objects, mirror)
endif
endfor
endfor
return item.update_objects
endfunction
function! s:state_update(item, change_len) dict
let item = a:item
if exists('item.update_objects')
let to_update = item.update_objects
else
let to_update = self.find_update_objects(a:item)
let item.update_objects = to_update
endif
for obj in to_update
let obj.col += a:change_len
if obj is self.cur_stop
let self.start_col += a:change_len
let self.end_col += a:change_len
endif
endfor
endfunction
call extend(s:state_proto, snipmate#util#add_methods(s:sfile(), 'state',
\ [ 'remove', 'set_stop', 'jump_stop', 'remove_nested',
\ 'select_word', 'update_changes', 'update_mirrors',
\ 'find_next_stop', 'find_update_objects', 'update' ]), 'error')
" vim:noet:sw=4:ts=4:ft=vim

View File

@ -0,0 +1,129 @@
let s:sigil = nr2char(31)
let snipmate#legacy#sigil = s:sigil
" Prepare snippet to be processed by s:BuildTabStops
function! snipmate#legacy#process_snippet(snip)
let snippet = a:snip
let esc_bslash = '\%(\\\@<!\%(\\\\\)*\)\@<='
if exists('b:snipmate_visual')
let visual = substitute(b:snipmate_visual, "\n$", '', '')
unlet b:snipmate_visual
else
let visual = ''
endif
let snippet = substitute(snippet, '\n\(\t\+\).\{-\}\zs{VISUAL}',
\ substitute(escape(visual, '%\'), "\n", "\n\\\\1", 'g'), 'g')
" Evaluate eval (`...`) expressions.
" Backquotes prefixed with a backslash "\" are ignored.
" And backslash can be escaped by doubling it.
" Using a loop here instead of a regex fixes a bug with nested "\=".
if stridx(snippet, '`') != -1
let new = []
let snip = split(snippet, esc_bslash . '`', 1)
let isexp = 0
for i in snip
if isexp
call add(new, substitute(eval(i), "\n\\%$", '', ''))
else
call add(new, i)
endif
let isexp = !isexp
endfor
let snippet = join(new, '')
let snippet = substitute(snippet, "\r", "\n", 'g')
let snippet = substitute(snippet, '\\`', "`", 'g')
endif
" Place all text after a colon in a tab stop after the tab stop
" (e.g. "${#:foo}" becomes "${:foo}foo").
" This helps tell the position of the tab stops later.
let snippet = substitute(snippet, esc_bslash . '\$\({\d\+:\(.\{-}\)}\|{\d\+}\)', s:sigil . '\1\2', 'g')
let snippet = substitute(snippet, esc_bslash . '\$\(\d\+\)', s:sigil . '\1', 'g')
let snippet = substitute(snippet, esc_bslash . '\\\$', '$', 'g')
let snippet = substitute(snippet, '\\\\', "\\", 'g')
" Update the a:snip so that all the $# become the text after
" the colon in their associated ${#}.
" (e.g. "${1:foo}" turns all "$1"'s into "foo")
let i = 0
if snippet !~ s:sigil . '{0'
let snippet .= s:sigil . '{0}'
endif
while snippet =~ s:sigil.'{'.i
let s = matchstr(snippet, s:sigil . '{' . i . ':\zs.\{-}\ze}')
if s != ''
let snippet = substitute(snippet, s:sigil . i, s.'&', 'g')
endif
let i += 1
endw
if &et " Expand tabs to spaces if 'expandtab' is set.
return substitute(snippet, '\t', repeat(' ', (&sts > 0) ? &sts : &sw), 'g')
endif
return snippet
endfunction
" Builds a list of a list of each tab stop in the snippet containing:
" 1.) The tab stop's line number.
" 2.) The tab stop's column number
" (by getting the length of the string between the last "\n" and the
" tab stop).
" 3.) The length of the text after the colon for the current tab stop
" (e.g. "${1:foo}" would return 3).
" 4.) If the "${#:}" construct is given, another list containing all
" the matches of "$#", to be replaced with the placeholder. This list is
" composed the same way as the parent; the first item is the line number,
" and the second is the column.
function! snipmate#legacy#build_stops(snip, lnum, col, indent)
let stops = {}
let i = 0
let withoutVars = substitute(a:snip, s:sigil . '\d\+', '', 'g')
while a:snip =~ s:sigil . '{' . i
let beforeTabStop = matchstr(withoutVars, '^.*\ze'.s:sigil .'{'.i.'\D')
let withoutOthers = substitute(withoutVars, ''.s:sigil .'{\('.i.'\D\)\@!\d\+.\{-}}', '', 'g')
let stops[i] = {}
let stops[i].line = a:lnum + s:count(beforeTabStop, "\n")
let stops[i].col = a:indent + len(matchstr(withoutOthers, '.*\(\n\|^\)\zs.*\ze'.s:sigil .'{'.i.'\D'))
let stops[i].placeholder = 0
let stops[i].mirrors = []
if stops[i].line == a:lnum
let stops[i].col += a:col
endif
" Get all $# matches in another list, if ${#:name} is given
if withoutVars =~ printf('%s{%d:', s:sigil, i)
let stops[i].placeholder = len(matchstr(withoutVars, ''.s:sigil .'{'.i.':\zs.\{-}\ze}'))
let withoutOthers = substitute(a:snip, ''.s:sigil .'{\d\+.\{-}}\|'.s:sigil .''.i.'\@!\d\+', '', 'g')
while match(withoutOthers, ''.s:sigil .''.i.'\(\D\|$\)') != -1
let stops[i].mirrors = get(stops[i], 'mirrors', [])
let beforeMark = matchstr(withoutOthers,
\ printf('^.\{-}\ze%s%s%d\(\D\|$\)',
\ repeat('.', stops[i].placeholder), s:sigil, i))
let line = a:lnum + s:count(beforeMark, "\n")
let col = a:indent + (line > a:lnum
\ ? len(matchstr(beforeMark, '.*\n\zs.*'))
\ : a:col + len(beforeMark))
call add(stops[i].mirrors, { 'line' : line, 'col' : col })
let withoutOthers = substitute(withoutOthers, ''.s:sigil .''.i.'\ze\(\D\|$\)', '', '')
endw
endif
let i += 1
endw
let stops[i] = stops[0]
return [stops, i + 1]
endfunction
" Counts occurences of haystack in needle
function! s:count(haystack, needle)
let counter = 0
let index = stridx(a:haystack, a:needle)
while index != -1
let index = stridx(a:haystack, a:needle, index+1)
let counter += 1
endw
return counter
endfunction

View File

@ -0,0 +1,220 @@
" Snippet definition parsing code
function! s:sfile()
return expand('<sfile>')
endfunction
let s:parser_proto = {}
function! s:new_parser(text)
let ret = copy(s:parser_proto)
let ret.input = a:text
let ret.len = strlen(ret.input)
let ret.pos = -1
let ret.indent = 0
let ret.value = []
let ret.vars = {}
call ret.advance()
return ret
endfunction
function! s:parser_advance(...) dict
let self.pos += a:0 ? a:1 : 1
let self.next = self.input[self.pos]
endfunction
function! s:parser_same(tok) dict
if self.next == a:tok
call self.advance()
return 1
else
return 0
endif
endfunction
function! s:parser_id() dict
if self.input[(self.pos):(self.pos+5)] == 'VISUAL'
call self.advance(6)
return 'VISUAL'
elseif self.next =~ '\d'
let end = matchend(self.input, '\d\+', self.pos)
let res = strpart(self.input, self.pos, end - self.pos)
call self.advance(end - self.pos)
return +res " force conversion to Number
endif
return -1
endfunction
function! s:parser_add_var(var) dict
let id = a:var[0]
if !has_key(self.vars, id)
let self.vars[id] = { 'instances' : [] }
endif
call add(self.vars[id].instances, a:var)
endfunction
function! s:parser_var() dict
let ret = []
if self.same('{')
let id = self.id()
if id >= 0
call add(ret, id)
call extend(ret, self.varend())
endif
else
let id = self.id()
if id >= 0
call add(ret, id)
endif
endif
return ret
endfunction
function! s:parser_varend() dict
let ret = []
if self.same(':')
call extend(ret, self.placeholder())
elseif self.same('/')
call add(ret, self.subst())
endif
call self.same('}')
return ret
endfunction
function! s:parser_placeholder() dict
return self.parse('}')
endfunction
function! s:parser_subst() dict
let ret = {}
let ret.pat = join(self.text('/', 1))
if self.same('/')
let ret.sub = join(self.text('/}'))
endif
if self.same('/')
let ret.flags = join(self.text('}', 1))
endif
return ret
endfunction
function! s:parser_expr() dict
let str = join(self.text('`', 1))
let ret = eval(str)
call self.same('`')
return type(ret) == type('') ? ret : string(ret)
endfunction
function! s:parser_text(...) dict
let res = []
let val = ''
if a:0 == 2 && a:2
let till = '\V' . escape(a:1, '\')
else
let till = '[`$' . (a:0 ? a:1 : '') . ']'
endif
while self.pos < self.len
if self.same('\')
if self.next != "\n"
let val .= self.next
endif
call self.advance()
elseif self.next =~# till
break
elseif self.next == "\n"
call add(res, val)
let val = ''
let self.indent = 0
call self.advance()
elseif self.next == "\t"
let self.indent += 1
let val .= s:indent(1)
call self.advance()
else
let val .= self.next
call self.advance()
endif
endwhile
call add(res, val)
return res
endfunction
function! s:parser_parse(...) dict
let ret = a:0 ? [] : self.value
while self.pos < self.len
if self.same('$')
let var = self.var()
if !empty(var)
if var[0] is# 'VISUAL'
let add_to = s:visual_placeholder(var, self.indent)
if !empty(ret) && type(ret[-1]) == type('')
let ret[-1] .= add_to[0]
else
call add(ret, add_to[0])
endif
call extend(ret, add_to[1:-1])
elseif var[0] >= 0
call add(ret, var)
call self.add_var(var)
endif
endif
elseif self.same('`')
let add_to = self.expr()
if !empty(ret) && type(ret[-1]) == type('')
let ret[-1] .= add_to
else
call add(ret, add_to)
endif
else
let text = a:0 ? self.text(a:1) : self.text()
if exists('add_to')
let ret[-1] .= text[0]
call remove(text, 0)
unlet add_to
endif
call extend(ret, text)
endif
if a:0 && self.next == a:1
break
endif
endwhile
return ret
endfunction
call extend(s:parser_proto, snipmate#util#add_methods(s:sfile(), 'parser',
\ [ 'advance', 'same', 'id', 'add_var', 'var', 'varend',
\ 'placeholder', 'subst', 'expr', 'text', 'parse' ]), 'error')
function! s:indent(count)
if &expandtab
let shift = repeat(' ', (&sts > 0) ? &sts : &sw)
else
let shift = "\t"
endif
return repeat(shift, a:count)
endfunction
function! s:visual_placeholder(var, indent)
let arg = get(a:var, 1, {})
if type(arg) == type({})
let pat = get(arg, 'pat', '')
let sub = get(arg, 'sub', '')
let flags = get(arg, 'flags', '')
let content = split(substitute(get(b:, 'snipmate_visual', ''), pat, sub, flags), "\n", 1)
else
let content = split(get(b:, 'snipmate_visual', arg), "\n", 1)
endif
let indent = s:indent(a:indent)
call map(content, '(v:key != 0) ? indent . v:val : v:val')
return content
endfunction
function! snipmate#parse#snippet(text)
let parser = s:new_parser(a:text)
call parser.parse()
unlet! b:snipmate_visual
return [parser.value, parser.vars]
endfunction

View File

@ -0,0 +1,10 @@
" The next function was based on s:function and s:add_methods in fugitive
" <https://github.com/tpope/vim-fugitive/blob/master/plugin/fugitive.vim>
function! snipmate#util#add_methods(sfile, namespace, methods)
let dict = {}
for name in a:methods
let dict[name] = function(join([matchstr(a:sfile, '<SNR>\d\+'),
\ a:namespace, name], '_'))
endfor
return dict
endfunction

View File

@ -6,7 +6,9 @@ Last Change: December 27, 2009
1. Description |SnipMate-description|
2. Usage |SnipMate-usage|
3. Interface and Settings |SnipMate-interface| |SnipMate-settings|
4. Snippet syntax |SnipMate-syntax|
4. Snippets |SnipMate-snippets|
- Snippet files |SnipMate-snippet-files|
- Snippet syntax |SnipMate-syntax|
5. Snippet sources |SnipMate-snippet-sources|
6. Disadvantages to TextMate |SnipMate-disadvantages|
7. Contact |SnipMate-contact|
@ -140,6 +142,24 @@ g:snipMate.no_default_aliases
the user or someone else will still be in
effect.
g:snipMate.snippet_version
The snippet parser version to use. The
possible values are:
0 Use the older parser
1 Use the newer parser
If unset, SnipMate defaults to version 0. The
value of this option is also used for all
.snippet files.
g:snipMate.override
As detailed below, when two snippets with the
same name and description are loaded, both are
kept and differentiated by the location of the
file they were in. When this option is enabled
(set to 1), the snippet originating in the
last loaded file is kept, similar to how Vim
maps and other settings work.
g:snipMate['no_match_completion_feedkeys_chars']
A string inserted when no match for a trigger
is found. By default a tab is inserted
@ -152,7 +172,7 @@ Mappings~
The mappings SnipMate uses can be customized with the |:map| commands. For
example, to change the key that triggers snippets and moves to the next
tabstop, >
tab stop, >
:imap <C-J> <Plug>snipMateNextOrTrigger
:smap <C-J> <Plug>snipMateNextOrTrigger
@ -186,12 +206,17 @@ Additionally, <CR> is mapped in visual mode in .snippets files for retabbing
snippets.
==============================================================================
SYNTAX *snippet-syntax* *SnipMate-syntax*
SNIPPETS *SnipMate-snippets*
*SnipMate-snippet-files*
Snippet Files ~
Note: SnipMate does not ship with any snippets.
SnipMate looks inside of each entry of 'rtp' (or |SnipMate-snippet-sources|)
for a directory named /snippets/. Based on the 'filetype' and 'syntax'
settings (taking into account the dotted syntax), the following files are read
for snippets: >
settings (dotted filetypes are parsed), the following files are read for
snippets: >
.../snippets/<scope>.snippets
.../snippets/<scope>_<name>.snippets
@ -199,7 +224,7 @@ for snippets: >
.../snippets/<scope>/<trigger>.snippet
.../snippets/<scope>/<trigger>/<description>.snippet
where <scope> is an entry in 'filetype' or 'syntax', <name> is an arbitrary
where <scope> is a scope or 'filetype' or 'syntax', <name> is an arbitrary
name, <trigger> is the trigger for a snippet, and <description> is
a description used for |SnipMate-multisnip|.
@ -215,14 +240,25 @@ looks something like: >
more expanded text
< *SnipMate-multisnip*
The description is optional. If it is left out and a second snippet inside the
same .snippets file uses the same trigger, the second one will overwrite the
first. Otherwise multisnip is used.
The description is optional. If it is left out, the description "default" is
used. When two snippets in the same scope have the same name and the same
description, SnipMate will try to preserve both. The g:snipMate.override
option disables this, in favor of keeping the last-loaded snippet. This can be
overridden on a per-snippet basis by defining the snippet with a bang (!): >
snippet! trigger optional description
expanded text
more expanded text
Note: Hard tabs in the expansion text are required. When the snippet is
expanded in the text and 'expandtab' is set, each tab will be replaced with
spaces based on 'softtabstop' if nonzero or 'shiftwidth' otherwise.
Which version parser the snippets in a file should be used with can be
specified with a version line, e.g.: >
version 1
Comments can be made in .snippets files by starting a line with a # character.
However these can't be used inside of snippet definitions: >
@ -243,74 +279,100 @@ directive, for example: >
will tell SnipMate to also read html, javascript, and css snippets.
SNIPPET SYNTAX *snippet-syntax* *SnipMate-syntax*
Anywhere in a snippet, a backslash escapes the character following it,
regardless of whether that character is special or not. That is, '\a' will
always result in an 'a' in the output. A single backslash can be output by
using '\\'.
*SnipMate-tabstops*
Tab stops~
A tab stop, specified by ${#} where # is a number, tells SnipMate where to
position the cursor next. The special tab stop ${0} denotes the last cursor
position; in its absence, the cursor is placed at the end of the snippet.
When triggering a snippet, SnipMate will by default jump to the very end of
the snippet text. This can be changed through the use of tab stops: $1, $2,
and so on. After expansion, SnipMate will jump to the first tab stop. From
then on, the <Plug>snipMateNextOrTrigger map will jump to the next higher
numbered tabs top.
For example, to place the cursor first on the id of a <div> tag, allow
the user to press <tab> to go to the middle of it, and finally end after
</div>: >
However, SnipMate will always stop at the zero tab stop $0. Once it jumps to
the zero tab stop, snippet expansion is finished. If the zero tab stop is not
present in a definition, it will be put at the end.
In the case of an ambiguity, for example if a stop occurs just before a literal
number, braces may be placed around the stop number to resolve it: ${3}79 is
the third tab stop followed by the string "79".
Note: In the version 0 snippet parser, the braces are mandatory.
For example, to place the cursor first on the id of a <div> tag, then on
its class, and finally end editing its contents: >
snippet div
<div id="${1}">
${2}
<div id="$1" class="$2">
$0
</div>
< *SnipMate-placeholders* *SnipMate-mirrors*
Placeholders and Mirrors~
< *SnipMate-placeholders*
In addition to being simply a location, each tab stop contains a placeholder,
or some default text. The placeholder can be specified for every tab stop
(including the zero tab stop) with a colon after the stop ID, as in
${1:default text}. The braces are required only when specifying a placeholder.
Once a tab stop with a placeholder is reached, the placeholder will be
selected in |Select-mode|. For example, >
Placeholder text can be supplied using "${#:text}", where # is the number of
the tab stop. This text then can be copied throughout the snippet using "$#",
given # is the same number as used before. So, to make a C for loop: >
snippet div
<div id="${1:id}" class="${2:class}">
$0
</div>
Finally, placeholders can contain mirrors and evaluations (detailed below) and
even entire other tab stops. If the placeholder is edited, then these nested
tab stops are removed and skipped entirely. For example, >
snippet div
<div${1: id="${2:id}"}${3: class="${4:class}"}>
$0
</div>
When expanded, this snippet selects the entirety of the id attribute. If this
stop is edited, then the second tab stop is removed and the third tab stop
becomes the next one. If the first tab stop is left unedited, then SnipMate
jumps to the second tab stop. This allows the user to use a single div snippet
that can be used for instances where the id or class attributes are desired
and those where they are not.
*SnipMate-mirrors*
Mirrors~
A mirror is simply a copy of a tab stop's text, updated as the tab stop is
edited. These look like a tab stop without a placeholder; $1 for example. In
the event that no placeholder is specified for a certain tab stop--say $1--the
first instance becomes the tab stop and the rest become mirrors.
Additionally substitutions similar to |:substitute| can be performed. For
instance ${1/foo/bar/g} will replace all instances of "foo" in the $1 mirror
with "bar". This uses |substitute()| behind the scenes.
Note: Just like with tab stops, braces can be used to avoid ambiguities: ${1}2
is a mirror of the first tab stop followed by a 2. Version 0 of the snippet
parser offers no way to resolve such ambiguities.
As an example, >
snippet for
for (${2:i}=0; $2 < ${1:count}; $2++) {
${4}
for ($1 = ${2:start}; ${1:i} < ${3:end}; $1${4:++}) {
${0:/* code */}
}
This will cause "count" to first be selected and change if the user starts
typing. When <tab> is pressed, the "i" in ${2}'s position will be selected;
all $2 variables will default to "i" and automatically be updated if the user
starts typing.
< *SnipMate-eval*
Expression Evaluation~
NOTE: "$#" syntax is used only for mirrors, not for tab stops as in TextMate.
Mirrors can also be used inside of placeholders. For instance: >
snippet opt
<option value="${1:option}">${2:$1}</option>
Will, as usual, cause "option" to first be selected and update all the $1
variables if the user starts typing. Since one of these variables is inside of
${2}, this text will then be used as a placeholder for the next tab stop,
allowing the user to change it if he wishes.
To copy a value throughout a snippet without supplying default text, simply
use the "${#:}" construct without the text, e.g.: >
snippet foo
${1:}bar$1
< *SnipMate-visual*
There is a special placeholder called {VISUAL}. If you visually select text,
then press <Tab> Vim switches to insert mode. The next snippet you'll expand
will replace {VISUAL} by the text which was selected previously.
*SnipMate-eval*
Interpolated Vim Script~
Snippets can also contain Vim script commands that are executed (via |eval()|)
when the snippet is inserted. Commands are given inside backticks (`...`); for
TextMates's functionality, use the |system()| function. E.g.: >
Snippets can contain Vim script expressions that are evaluated as the snippet
is expanded. Expressions are specified inside backticks: >
snippet date
`system("date +%Y-%m-%d")`
will insert the current date, assuming you are on a Unix system. Note that you
can also (and should) use |strftime()| for this example.
`strftime("%Y-%m-%d")`
Filename([{expr}] [, {defaultText}]) *SnipMate-Filename()*
@ -336,6 +398,26 @@ empty string if it hasn't. The second returns the filename if it's been named,
and "name" if it hasn't. The third returns the filename followed by "_foo" if
it has been named, and an empty string if it hasn't.
*SnipMate-visual*
The VISUAL Stop~
While tab stops have numeric IDs, a special one exists with the ID 'VISUAL'.
When a snippet is expanded, if any text had been grabbed with the
snipMateVisual mapping (see |SnipMate-mappings|), all instances of the VISUAL
stop will be replaced with it. Both transformations as well as a default
placeholder can be used with the VISUAL stop.
Note: Both $VISUAL and ${VISUAL} are valid in version 1 of the snippet parser.
In version 0, only {VISUAL} is valid (without the $), and neither
transformations nor a default placeholder can be used.
Example: >
snippet div
<div>
${0:${VISUAL:<!-- content -->}}
</div>
==============================================================================
SNIPPET SOURCES *SnipMate-snippet-sources*
@ -398,19 +480,13 @@ See |SnipMate-syntax| for more details about all possible relative locations
to 'rtp' can be found in.
==============================================================================
DISADVANTAGES *SnipMate-disadvantages*
KNOWN ISSUES *SnipMate-known-issues*
SnipMate.vim currently has the following disadvantages to TextMate's snippets:
- Nested placeholders are not currently possible. E.g.: >
'<div${1: id="${2:some_id}}">${3}</div>'
< In TextMate this would first highlight ' id="some_id"', and if
you hit delete it would automatically skip ${2} and go to ${3}
on the next <tab>, but if you didn't delete it it would highlight
"some_id" first. You cannot do this in SnipMate.vim.
- Regex cannot be performed on variables, such as "${1/.*/\U&}"
- Placeholders cannot span multiple lines.
- Activating snippets in different scopes of the same file is
not possible.
- Vim formatting with fo=t or fo=a can mess up SnipMate.
Perhaps some of these features will be added in a later release.

View File

@ -91,9 +91,11 @@ let g:snipMate['get_snippets'] = get(g:snipMate, 'get_snippets', funcref#Functio
" List of paths where snippets/ dirs are located, or a function returning such
" a list
let g:snipMate['snippet_dirs'] = get(g:snipMate, 'snippet_dirs', funcref#Function('return split(&runtimepath,",")'))
if type(g:snipMate['snippet_dirs']) == type([])
call map(g:snipMate['snippet_dirs'], 'expand(v:val)')
let g:snipMate['snippet_dirs'] = get(g:snipMate, 'snippet_dirs', split(&rtp, ','))
if type(g:snipMate['snippet_dirs']) != type([])
echohl WarningMsg
echom "g:snipMate['snippet_dirs'] must be a List"
echohl None
endif
" _ is default scope added always
@ -107,7 +109,7 @@ function! s:grab_visual()
let a_save = @a
try
normal! gv"ay
let b:snipmate_content_visual = @a
let b:snipmate_visual = @a
finally
let @a = a_save
endtry

View File

@ -0,0 +1,175 @@
function! Setup(snip)
return snipMate#expandSnip(join(a:snip, "\n"), 1)
endfunction
function! s:to_be_file(expected)
return a:expected == getline(1,'$')
endfunction
function! s:to_be_in(item, list)
return !empty(filter(copy(a:list), 'v:val is a:item'))
endfunction
call vspec#customize_matcher('to_be_file', function('s:to_be_file'))
call vspec#customize_matcher('to_be_in', function('s:to_be_in'))
describe 'snippet state'
before
enew
let b:snip_state = snipmate#jumping#state()
end
after
bwipeout!
end
describe '.remove()'
it 'removes the state object'
Expect exists('b:snip_state') to_be_true
call b:snip_state.remove()
Expect exists('b:snip_state') to_be_false
end
it 'removes snippet related autocommands'
function! ReadAutocmds()
redir => autocmds
0verbose au snipmate_changes * <buffer>
redir END
return split(autocmds, "\n")
endfunction
aug snipmate_changes
au CursorMoved,CursorMovedI <buffer> echo 'event'
aug END
Expect len(ReadAutocmds()) > 1
call b:snip_state.remove()
Expect len(ReadAutocmds()) == 1
end
end
describe '.find_next_stop()'
it 'increments/decrements the stop_no'
let b:snip_state.stops = { 1 : {}, 2 : {} }
let b:snip_state.stop_no = 1
let b:snip_state.stop_count = 4
call b:snip_state.find_next_stop(0)
Expect b:snip_state.stop_no == 2
call b:snip_state.find_next_stop(1)
Expect b:snip_state.stop_no == 1
end
it 'continues iterating if the next/previous stop does not exist'
let b:snip_state.stops = { 3 : {} }
let b:snip_state.stop_count = 6
let b:snip_state.stop_no = 1
call b:snip_state.find_next_stop(0)
Expect b:snip_state.stop_no == 3
let b:snip_state.stop_no = 5
call b:snip_state.find_next_stop(1)
Expect b:snip_state.stop_no == 3
end
it 'does something at the ends'
"
end
end
describe '.remove_nested()'
it 'removes nested mirrors and only nested mirrors'
let mirror = { 'line' : 0 }
let b:snip_state.stops = { 1 : { 'placeholder' : [[2, mirror]] },
\ 2 : { 'mirrors' : [mirror, {}] } }
call b:snip_state.remove_nested(1)
Expect len(b:snip_state.stops[2].mirrors) == 1
Expect b:snip_state.stops[2].mirrors[0] isnot mirror
end
it 'removes nested stops'
let stop = [2, 'abc']
let b:snip_state.stops = { 1 : { 'placeholder' : [stop] },
\ 2 : { 'placeholder' : stop[1:1] } }
call b:snip_state.remove_nested(1)
Expect len(b:snip_state.stops) == 1
Expect keys(b:snip_state.stops) == ['1']
end
end
describe '.find_update_objects()'
it 'finds mirrors/stops on the same line and after cur_stop'
let b:snip_state.stops = {
\ 1 : { 'line' : 1, 'col' : 5,
\ 'placeholder' : ['x'] },
\ 2 : { 'line' : 1, 'col' : 7,
\ 'mirrors' : [{ 'line' : 1, 'col' : 7 }] }
\ }
let stop = b:snip_state.stops[1]
call b:snip_state.find_update_objects(stop)
for obj in stop.update_objects
Expect obj to_be_in [ b:snip_state.stops[2],
\ b:snip_state.stops[2].mirrors[0] ]
endfor
end
it 'finds mirrors/stops on the same line and after cur_stop mirrors'
let b:snip_state.stops = {
\ 1 : { 'line' : 1, 'col' : 5,
\ 'mirrors' : [{ 'line' : 2, 'col' : 5 }],
\ 'placeholder' : ['x'] },
\ 2 : { 'line' : 2, 'col' : 7,
\ 'mirrors' : [{ 'line' : 2, 'col' : 7 }] }
\ }
let stop = b:snip_state.stops[1]
call b:snip_state.find_update_objects(stop)
for obj in stop.update_objects
Expect obj to_be_in [ b:snip_state.stops[2],
\ b:snip_state.stops[2].mirrors[0] ]
endfor
end
it 'ignores mirrors/stops on other lines'
let b:snip_state.stops = {
\ 1 : { 'line' : 2, 'col' : 5,
\ 'placeholder' : ['x'] },
\ 2 : { 'line' : 1, 'col' : 7,
\ 'mirrors' : [{ 'line' : 1, 'col' : 7 }] },
\ 3 : { 'line' : 3, 'col' : 7,
\ 'mirrors' : [{ 'line' : 3, 'col' : 7 }] }
\ }
let stop = b:snip_state.stops[1]
call b:snip_state.find_update_objects(stop)
Expect empty(stop.update_objects) to_be_true
end
it 'ignores mirrors/stops on the same line but before cur_stop/mirrors'
let b:snip_state.stops = {
\ 1 : { 'line' : 1, 'col' : 5,
\ 'mirrors' : [{ 'line' : 2, 'col' : 5 }],
\ 'placeholder' : ['x'] },
\ 2 : { 'line' : 1, 'col' : 1,
\ 'mirrors' : [{ 'line' : 2, 'col' : 1 }] },
\ 3 : { 'line' : 2, 'col' : 3,
\ 'mirrors' : [{ 'line' : 1, 'col' : 3 }] },
\ }
let stop = b:snip_state.stops[1]
call b:snip_state.find_update_objects(stop)
Expect empty(stop.update_objects) to_be_true
end
end
end

View File

@ -0,0 +1,116 @@
describe 'snippet parser'
before
function! Parse(snippet, ...)
let [snip, stops] = snipmate#parse#snippet(a:snippet)
return a:0 ? [snip, stops] : snip
endfunction
let b:snipmate_visual = 'testvisual'
end
it 'parses numeric $id and ${id} vars as [id] lists'
let expect = [[1234567890]]
Expect Parse('$1234567890') == expect
Expect Parse('${1234567890}') == expect
end
it 'disregards $ or ${ followed by a non-id'
Expect Parse('$x1') == ['x1']
Expect Parse('${x}1') == ['x}1']
Expect Parse('$VISUA1') == ['VISUA1']
Expect Parse('${VISUA}1') == ['VISUA}1']
end
it 'gathers references to each instance of each stop id'
let [snip, b:stops] = Parse('x$1x${2:x$1x}x$1x${1/a/b}x$VISUALx', 1)
function! InstanceFound(list)
return !empty(filter(copy(b:stops[a:list[0]].instances),
\ 'v:val is a:list'))
endfunction
function! CheckList(list)
for item in a:list
if type(item) == type([])
Expect InstanceFound(item) to_be_true
call CheckList(item)
endif
unlet item " E732
endfor
endfunction
call CheckList(snip)
end
it 'parses mirror substitutions ${n/pat/sub} as [n, {...}]'
let expect = [[1, { 'pat' : 'abc', 'sub' : 'def' }]]
Expect Parse('${1/abc/def}') == expect
let expect[0][1].flags = ''
Expect Parse('${1/abc/def/}') == expect
let expect[0][1].flags = 'g'
Expect Parse('${1/abc/def/g}') == expect
end
it 'parses vars with placeholders as [id, placeholder] lists'
Expect Parse('${1:abc}') == [[1, 'abc']]
end
it 'evaluates backtick expressions'
Expect Parse('`fnamemodify("x.y", ":r")`') == ['x']
end
it 'parses placeholders for vars and other specials'
let text = 'a `fnamemodify("x.y", ":r")` ${2:(${3/a/b})}'
let expect = ['a x ', [2, '(', [3, { 'pat' : 'a', 'sub' : 'b' }], ')']]
Expect Parse(text) == expect
Expect Parse(printf('${1:%s}', text)) == [[1] + expect]
end
it 'converts tabs according to &et, &sts, &sw'
" &noet -> leave tabs alone
setl noet
Expect Parse("abc\tdef\n\t\tghi") == ["abc\tdef", "\t\tghi"]
" &et -> &sts or &sw
setl et sts=2 sw=3
Expect Parse("abc\tdef\n\t\tghi") == ["abc def", " ghi"]
setl et sts=0 sw=3
Expect Parse("abc\tdef\n\t\tghi") == ["abc def", " ghi"]
setl et sts=-1 sw=3
Expect Parse("abc\tdef\n\t\tghi") == ["abc def", " ghi"]
end
it 'parses backslashes as escaping the next character or joining lines'
Expect Parse('x\x') == ['xx']
Expect Parse('x\\x') == ['x\x']
Expect Parse("x\\\nx") == ['xx']
Expect Parse('x\$1') == ['x$1']
Expect Parse('${1:\}}') == [[1, '}']]
Expect Parse('${1/\//\}}') == [[1, { 'pat' : '/', 'sub' : '}' }]]
Expect Parse('`fnamemodify("\`.x", ":r")`') == ['`']
Expect Parse('\`x\`') == ['`x`']
end
it 'splits text at newlines'
Expect Parse("x\nx") == ['x', 'x']
end
it 'joins evaluated expressions to surrounding text on the same line'
let g:foo = 'bar'
Expect Parse("x`g:foo`x") == ['xbarx']
Expect Parse("x`g:foo`\nx") == ['xbar', 'x']
Expect Parse("x\n`g:foo`x") == ['x', 'barx']
end
it 'adds empty strings before/after vars if at the start/end of a line'
Expect Parse("x$1\nx") == ['x', [1], '', 'x']
Expect Parse("x\n$1x") == ['x', '', [1], 'x']
end
it 'expands $VISUAL placeholders with any indents'
Expect Parse("x$VISUALx") == ['xtestvisualx']
let b:snipmate_visual = " foo\nbar\n baz"
setl noet
Expect Parse("\tx\n\t$VISUAL\nx") == ["\tx", "\t foo", "\tbar", "\t baz", "x"]
end
end

View File

@ -0,0 +1,20 @@
#!/bin/sh
tmp="$(mktemp || tmpfile)"
vim -Es $tmp <<- EOF
source ~/.vimrc
%delete _
call append(0, split(&rtp, ','))
delete _
wq
EOF
rtp="$(grep -iE 'vspec|snipmate|tlib|mw-utils' < $tmp | grep -v after)"
vspec="$(grep -iE 'vspec' < $tmp | grep -v after)"
test_files="${*:-parser jumping}"
for test in $test_files; do
$vspec/bin/vspec $rtp ${test%%.vim}.vim
done
rm $tmp

View File

@ -5,12 +5,12 @@
priority -50
snippet pat "Case:Receive:Try Clause"
${1:pattern}${2: when ${3:guard}} ->;
${1:pattern}${2: when ${3:guard}} ->
${4:body}
endsnippet
snippet beh "Behaviour Directive"
-behaviour (${1:behaviour}).
snippet beh "Behaviour Directive" b
-behaviour(${1:behaviour}).
endsnippet
snippet case "Case Expression"
@ -20,12 +20,12 @@ case ${1:expression} of
end
endsnippet
snippet def "Define Directive"
-define (${1:macro}${2: (${3:param})}, ${4:body}).
snippet def "Define Directive" b
-define(${1:macro}${2: (${3:param})}, ${4:body}).
endsnippet
snippet exp "Export Directive"
-export ([${1:function}/${2:arity}]).
snippet exp "Export Directive" b
-export([${1:function}/${2:arity}]).
endsnippet
snippet fun "Fun Expression"
@ -36,7 +36,7 @@ end
endsnippet
snippet fu "Function"
${1:function} (${2:param})${3: when ${4:guard}} ->
${1:function}(${2:param})${3: when ${4:guard}} ->
${5:body}
endsnippet
@ -47,24 +47,24 @@ if
end
endsnippet
snippet ifdef "Ifdef Directive"
-ifdef (${1:macro}).
snippet ifdef "Ifdef Directive" b
-ifdef(${1:macro}).
endsnippet
snippet ifndef "Ifndef Directive"
-ifndef (${1:macro}).
snippet ifndef "Ifndef Directive" b
-ifndef(${1:macro}).
endsnippet
snippet imp "Import Directive"
-import (${1:module}, [${2:function}/${3:arity}]).
snippet imp "Import Directive" b
-import(${1:module}, [${2:function}/${3:arity}]).
endsnippet
snippet inc "Include Directive"
-include ("${1:file}").
snippet inc "Include Directive" b
-include("${1:file}").
endsnippet
snippet mod "Module Directive"
-module (${1:`!p snip.rv = snip.basename or "module"`}).
snippet mod "Module Directive" b
-module(${1:`!p snip.rv = snip.basename or "module"`}).
endsnippet
snippet rcv "Receive Expression"
@ -77,8 +77,8 @@ ${6:after
end
endsnippet
snippet rec "Record Directive"
-record (${1:record}, {${2:field}${3: = ${4:value}}}).
snippet rec "Record Directive" b
-record(${1:record}, {${2:field}${3: = ${4:value}}}).
endsnippet
snippet try "Try Expression"
@ -93,8 +93,16 @@ ${13:after
end
endsnippet
snippet undef "Undef Directive"
-undef (${1:macro}).
snippet undef "Undef Directive" b
-undef(${1:macro}).
endsnippet
snippet || "List Comprehension"
[${1:X} || ${2:X} <- ${3:List}${4:, gen}]
endsnippet
snippet gen "Generator Expression"
${1:X} <- ${2:List}${3:, gen}
endsnippet
# vim:ft=snippets:

View File

@ -17,7 +17,7 @@ snippet label_and_input
endsnippet
snippet input
<input type="${1:text}" value="${2}" name="${3}"${4: id="${5:$3}}/>${7}
<input type="${1:text}" value="${2}" name="${3}"${4: id="${5:$3}"}/>${7}
endsnippet
snippet submit

View File

@ -102,44 +102,54 @@ var_export(${1});${2}
endsnippet
snippet getter "PHP Class Getter" b
/*
/**
* Getter for $1
*
* ${2:return string}
*/
public function get${1/\w+\s*/\u$0/}()
{
return $this->$1;$2
return $this->$1;$3
}
$4
$0
endsnippet
snippet setter "PHP Class Setter" b
/*
/**
* Setter for $1
*
* @param ${2:string} $$1
* @return ${3:`!p snip.rv=snip.basename`}
*/
public function set${1/\w+\s*/\u$0/}($$1)
public function set${1/\w+\s*/\u$0/}(${4:${2/(void|string|int|integer|double|float|object|boolear|null|mixed|number|resource)|(.*)/(?1::$2 )/}}$$1)
{
$this->$1 = $$1;$3
${4:return $this;}
$this->$1 = $$1;$5
${6:return $this;}
}
$0
endsnippet
snippet gs "PHP Class Getter Setter" b
/*
/**
* Getter for $1
*
* return ${2:string}
*/
public function get${1/\w+\s*/\u$0/}()
{
return $this->$1;$2
return $this->$1;$3
}
/*
/**
* Setter for $1
*
* @param $2 $$1
* @return ${4:`!p snip.rv=snip.basename`}
*/
public function set${1/\w+\s*/\u$0/}($$1)
public function set${1/\w+\s*/\u$0/}(${5:${2/(void|string|int|integer|double|float|object|boolear|null|mixed|number|resource)|(.*)/(?1::$2 )/}}$$1)
{
$this->$1 = $$1;$3
${4:return $this;}
$this->$1 = $$1;$6
${7:return $this;}
}
$0
endsnippet

View File

@ -7,33 +7,30 @@ snippet l_rsc "Laravel resource controller" b
* \date `!v strftime('%d-%m-%y')`
*/
class $1 {
public function index() {
${3}
}
public function create() {
class $1 extends ${3: BaseController} {
function __construct() {
${4}
}
public function index() {
}
public function create() {
}
public function store($id) {
${5}
}
public function show($id) {
${6}
}
public function edit($id) {
${7}
}
public function update($id) {
${8}
}
public function destroy($id) {
${9}
}
}
endsnippet
@ -117,7 +114,7 @@ namespace $1;
class $2 extends \Eloquent {
protected $table = '${4:`!p snip.rv = t[2].lower()`}';
public $timestamps = '${5:false}';
public $timestamps = ${5:false};
protected $hidden = array(${6});
@ -196,7 +193,7 @@ snippet l_r "Laravel Repository" b
/*!
* \namespace ${1:Repositories\\${2}}
* \class ${3:`!v expand('%:t:r')`}
* \implements ${4:BaseRepositoryInterface}
* \implements ${4:$3RepositoryInterface}
*
* \author ${5:`!v g:snips_author`}
* \date `!v strftime('%d-%m-%y')`
@ -204,8 +201,8 @@ snippet l_r "Laravel Repository" b
namespace $1;
class $3 extends \\$1 implements $4 {
${6}
class $3 extends \\${6} implements $4 {
${7}
}
endsnippet

View File

@ -29,7 +29,6 @@ snippet GPL2
You should have received a copy of the GNU General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
${0}
snippet LGPL2
${1:One line to give the program's name and a brief description.}
@ -47,7 +46,6 @@ snippet LGPL2
You should have received a copy of the GNU Lesser General Public License
along with this library; if not, see <http://www.gnu.org/licenses/>.
${0}
snippet GPL3
${1:one line to give the program's name and a brief description.}
@ -65,7 +63,6 @@ snippet GPL3
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
${0}
snippet LGPL3
${1:One line to give the program's name and a brief description.}
@ -83,7 +80,6 @@ snippet LGPL3
You should have received a copy of the GNU Lesser General Public License
along with this library; if not, see <http://www.gnu.org/licenses/>.
${0}
snippet AGPL3
${1:one line to give the program's name and a brief description.}
@ -101,7 +97,6 @@ snippet AGPL3
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
${0}
snippet GMGPL linking exception
As a special exception, if other files instantiate generics from
@ -140,7 +135,6 @@ snippet BSD2
The views and conclusions contained in the software and documentation
are those of the authors and should not be interpreted as representing
official policies, either expressedor implied, of $2.
${0}
snippet BSD3
${1:one line to give the program's name and a brief description}
@ -168,7 +162,6 @@ snippet BSD3
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
${0}
snippet BSD4
${1:one line to give the program's name and a brief description}
@ -199,7 +192,6 @@ snippet BSD4
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
${0}
snippet MIT
${1:one line to give the program's name and a brief description}
@ -222,7 +214,6 @@ snippet MIT
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
${0}
snippet APACHE
${1:one line to give the program's name and a brief description}
@ -239,7 +230,6 @@ snippet APACHE
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
${0}
snippet BEERWARE
${1:one line to give the program's name and a brief description}
@ -249,7 +239,6 @@ snippet BEERWARE
$2 wrote this file. As long as you retain this notice you
can do whatever you want with this stuff. If we meet some day, and you think
this stuff is worth it, you can buy me a beer or coffee in return
${0}
snippet WTFPL
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
@ -271,5 +260,4 @@ snippet MPL2
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.
${0}

View File

@ -75,6 +75,8 @@ snippet ===
`repeat('=', strlen(getline(line(".") - 1)) - strlen(getline('.')))`
${0}
snippet -
- ${0}
snippet ---
`repeat('-', strlen(getline(line(".") - 1)) - strlen(getline('.')))`

View File

@ -90,7 +90,7 @@ snippet class
${0}
}
snippet node
node '${1:`vim_snippets#Filename('', 'fqdn')`}' {
node "${1:`vim_snippets#Filename('', 'fqdn')`}" {
${0}
}
snippet case
@ -107,13 +107,21 @@ snippet if
if $${1:variable} {
${0}
}
snippet ifd
if defined(${1:Resource}["${2:name}"]) {
${0}
}
snippet ifnd
if !defined(${1:Resource}["${2:name}"]) {
${0}
}
snippet el
else {
${0}
}
snippet ?
? {
'${1}' => ${0}
"${1}" => ${0}
}
#
# blocks etc and general syntax sugar
@ -122,98 +130,98 @@ snippet [
snippet >
${1} => ${0}
snippet p:
'puppet://puppet/${1:module name}/${0:file name}'
"puppet://puppet/${1:module name}/${0:file name}"
#
# Functions
snippet alert
alert('${1:message}')
alert("${1:message}")
snippet crit
crit('${1:message}')
crit("${1:message}")
snippet debug
debug('${1:message}')
debug("${1:message}")
snippet defined
defined(${1:Resource}['${2:name}'])
defined(${1:Resource}["${2:name}"])
snippet emerg
emerg('${1:message}')
emerg("${1:message}")
snippet extlookup Simple extlookup
extlookup('${1:variable}')
extlookup("${1:variable}")
snippet extlookup Extlookup with defaults
extlookup('${1:variable}', '${2:default}')
extlookup("${1:variable}", "${2:default}")
snippet extlookup Extlookup with defaults and custom data file
extlookup('${1:variable}', '${2:default}', '${3:data source}')
extlookup("${1:variable}", "${2:default}", "${3:data source}")
snippet fail
fail('${1:message}')
fail("${1:message}")
snippet info
info('${1:message}')
info("${1:message}")
snippet inline_template
inline_template('<%= ${1} %>')
inline_template("<%= ${1} %>")
snippet notice
notice('${1:message}')
notice("${1:message}")
snippet realize
realize(${1:Resource}[${2:name}])
snippet regsubst
regsubst(${1:hay stack}, ${2:needle}, '${3:replacement}')
regsubst(${1:hay stack}, ${2:needle}, "${3:replacement}")
snippet inc
include ${1:classname}
snippet split
split(${1:hay stack}, '${2:patten}')
split(${1:hay stack}, "${2:patten}")
snippet versioncmp
versioncmp('${1:version}', '${2:version}')
versioncmp("${1:version}", "${2:version}")
snippet warning
warning('${1:message}')
warning("${1:message}")
#
# Types
snippet cron
cron { '${1:name}':
command => '${2}',
user => '${3:root}',
cron { "${1:name}":
command => "${2}",
user => "${3:root}",
${4} => ${0},
}
snippet exec
exec { '${1:name}':
command => '${2:$1}',
user => '${3:root}',
exec { "${1:name}":
command => "${2:$1}",
user => "${3:root}",
${4} => ${0},
}
snippet user
user { '${1:user}':
user { "${1:user}":
ensure => present,
comment => '${2:$1}',
comment => "${2:$1}",
managehome => true,
home => '${0:/home/$1}',
home => "${0:/home/$1}",
}
snippet group
group { '${1:group}':
group { "${1:group}":
ensure => ${0:present},
}
snippet host
host { '${1:hostname}':
host { "${1:hostname}":
ip => ${0:127.0.0.1},
}
snippet mailalias
mailalias { '${1:localpart}':
recipient => '${0:recipient}',
mailalias { "${1:localpart}":
recipient => "${0:recipient}",
}
snippet mount
mount { '${1:destination path}':
mount { "${1:destination path}":
ensure => ${2:mounted},
device => '${0:device name or path}',
device => "${0:device name or path}",
}
snippet package
package { '${1:package name}':
package { "${1:package name}":
ensure => ${0:present},
}
snippet yumrepo
yumrepo { '${1:repo name}':
Descr => '${2:$1}',
yumrepo { "${1:repo name}":
Descr => "${2:$1}",
enabled => ${0:1},
}
@ -223,22 +231,39 @@ snippet define
}
snippet service
service { '${1:service}' :
service { "${1:service}" :
ensure => running,
enable => true,
require => [ Package['${2:package}'], File['${3:file}'], ],
subscribe => [ File['${4:configfile1}'], File['${5:configfile2}'], Package['${6:package}'], ],
require => [ Package["${2:package}"], File["${3:file}"], ],
subscribe => [ File["${4:configfile1}"], File["${5:configfile2}"], Package["${6:package}"], ],
}
snippet file
file { '${1:filename}' :
file { "${1:filename}" :
ensure => ${2:present},
owner => '${3:root}',
group => '${4:root}',
mode => '${5:0644}',
source => 'puppet:///modules/${6:module}/${7:source}',
content => template('/etc/puppet/templates/${8:template}'),
alias => '${9:alias}',
require => [ Package['${10:package}'], File['${11:file}'], ],
owner => "${3:root}",
group => "${4:root}",
mode => "${5:0644}",
source => "puppet:///modules/${6:module}/${7:source}",
content => template("${8:module}/${9:template}"),
alias => "${10:alias}",
require => [ Package["${11:package}"], File["${12:file}"], ],
}
snippet archive
archive { "${1:filename}" :
ensure => ${2:present},
url => "http://${3:url}",
extension => "${4:tgz}",
target => "${5:target}",
checksum => ${6:false},
src_target => "${7:/tmp}",
}
snippet firewall
firewall { "${1:comment}" :
proto => ${2:tcp},
action => ${3:accept},
port => ${4},
}

View File

@ -135,6 +135,9 @@ snippet iem
# ipython debugger (pdbbb)
snippet pdbbb
import pdbpp; pdbpp.set_trace()
# remote python debugger (rpdb)
snippet rpdb
import rpdb; rpdb.set_trace()
# python_prompt_toolkit
snippet ppt
from prompt_toolkit.contrib.repl import embed

View File

@ -39,8 +39,9 @@ easiest to understand with some examples:
<div>Yo!*</div> dst Yo!
Change surroundings is *cs* . It takes two arguments, a target like with
|ds|, and a replacement. Details about the second argument can be found
below in |surround-replacements|. Once again, examples are in order.
|ds|, and a replacement. *cS* changes surroundings, placing the surrounded
text on its own line(s) like |yS|. Details about the second argument can be
found below in |surround-replacements|. Once again, examples are in order.
Old text Command New text ~
"Hello *world!" cs"' 'Hello world!'

View File

@ -441,7 +441,8 @@ function! s:dosurround(...) " {{{1
endif
call setreg('"',keeper,regtype)
if newchar != ""
call s:wrapreg('"',newchar)
let special = a:0 > 2 ? a:3 : 0
call s:wrapreg('"',newchar, special)
endif
silent exe 'norm! ""'.pcmd.'`['
if removed =~ '\n' || okeeper =~ '\n' || getreg('"') =~ '\n'
@ -456,11 +457,11 @@ function! s:dosurround(...) " {{{1
if newchar == ""
silent! call repeat#set("\<Plug>Dsurround".char,scount)
else
silent! call repeat#set("\<Plug>Csurround".char.newchar.s:input,scount)
silent! call repeat#set("\<Plug>C".(a:0 > 2 && a:3 ? "S" : "s")."urround".char.newchar.s:inpur,scount)
endif
endfunction " }}}1
function! s:changesurround() " {{{1
function! s:changesurround(...) " {{{1
let a = s:inputtarget()
if a == ""
return s:beep()
@ -469,7 +470,7 @@ function! s:changesurround() " {{{1
if b == ""
return s:beep()
endif
call s:dosurround(a,b)
call s:dosurround(a,b,a:0 && a:1)
endfunction " }}}1
function! s:opfunc(type,...) " {{{1
@ -558,6 +559,7 @@ endfunction " }}}1
nnoremap <silent> <Plug>SurroundRepeat .
nnoremap <silent> <Plug>Dsurround :<C-U>call <SID>dosurround(<SID>inputtarget())<CR>
nnoremap <silent> <Plug>Csurround :<C-U>call <SID>changesurround()<CR>
nnoremap <silent> <Plug>CSurround :<C-U>call <SID>changesurround(1)<CR>
nnoremap <silent> <Plug>Yssurround :<C-U>call <SID>opfunc(v:count1)<CR>
nnoremap <silent> <Plug>YSsurround :<C-U>call <SID>opfunc2(v:count1)<CR>
" <C-U> discards the numerical argument but there's not much we can do with it
@ -571,6 +573,7 @@ inoremap <silent> <Plug>ISurround <C-R>=<SID>insert(1)<CR>
if !exists("g:surround_no_mappings") || ! g:surround_no_mappings
nmap ds <Plug>Dsurround
nmap cs <Plug>Csurround
nmap cS <Plug>CSurround
nmap ys <Plug>Ysurround
nmap yS <Plug>YSurround
nmap yss <Plug>Yssurround