"=============================================================================
" FILE: parser.vim
" AUTHOR: Shougo Matsushita <Shougo.Matsu@gmail.com>
" License: 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.
" }}}
"=============================================================================
" Saving 'cpoptions' {{{
let s:save_cpo = &cpo
set cpo&vim
" }}}
" For vimshell parser.
function! vimproc#parser#parse_pipe(statement) abort "{{{
let commands = []
for cmdline in vimproc#parser#split_pipe(a:statement)
" Split args.
let cmdline = s:parse_cmdline(cmdline)
" Parse redirection.
if cmdline =~ '[<>]'
let [fd, cmdline] = s:parse_redirection(cmdline)
else
let fd = { 'stdin' : '', 'stdout' : '', 'stderr' : '' }
endif
for key in ['stdout', 'stderr']
if fd[key] == '' || fd[key] =~ '^>'
continue
endif
if fd[key] ==# '/dev/clip'
" Clear.
let @+ = ''
elseif fd[key] ==# '/dev/quickfix'
" Clear quickfix.
call setqflist([])
endif
endfor
call add(commands, {
\ 'args' : vimproc#parser#split_args(cmdline),
\ 'fd' : fd
\})
endfor
return commands
endfunction"}}}
function! s:parse_cmdline(cmdline) abort "{{{
let cmdline = a:cmdline
" Expand block.
if cmdline =~ '{'
let cmdline = s:parse_block(cmdline)
endif
" Expand tilde.
if cmdline =~ '\~'
let cmdline = s:parse_tilde(cmdline)
endif
" Expand filename.
if cmdline =~ ' ='
let cmdline = s:parse_equal(cmdline)
endif
" Expand variables.
if cmdline =~ '\$'
let cmdline = s:parse_variables(cmdline)
endif
" Expand wildcard.
if cmdline =~ '[[*?]\|\\[()|]'
let cmdline = s:parse_wildcard(cmdline)
endif
return s:parse_tilde(cmdline)
endfunction"}}}
function! vimproc#parser#parse_statements(script) abort "{{{
if type(a:script) == type('') && a:script =~ '^\s*:'
return [ {
\ 'statement' : a:script,
\ 'condition' : 'always',
\ 'cwd' : getcwd(),
\ } ]
endif
let script = type(a:script) == type([]) ?
\ a:script : split(a:script, '\zs')
let max = len(script)
let statements = []
let statement = ''
let i = 0
while i < max
if script[i] == ';'
if statement != ''
call add(statements,
\ {
\ 'statement' : statement,
\ 'condition' : 'always',
\ 'cwd' : getcwd(),
\})
endif
let statement = ''
let i += 1
elseif script[i] == '&'
if i+1 < max && script[i+1] == '&'
if statement != ''
call add(statements,
\ {
\ 'statement' : statement,
\ 'condition' : 'true',
\ 'cwd' : getcwd(),
\})
endif
let statement = ''
let i += 2
else
let statement .= script[i]
let i += 1
endif
elseif script[i] == '|'
if i+1 < max && script[i+1] == '|'
if statement != ''
call add(statements,
\ {
\ 'statement' : statement,
\ 'condition' : 'false',
\ 'cwd' : getcwd(),
\})
endif
let statement = ''
let i += 2
else
let statement .= script[i]
let i += 1
endif
elseif script[i] == "'"
" Single quote.
let [string, i] = s:skip_single_quote(script, i)
let statement .= string
elseif script[i] == '"'
" Double quote.
let [string, i] = s:skip_double_quote(script, i)
let statement .= string
elseif script[i] == '`'
" Back quote.
let [string, i] = s:skip_back_quote(script, i)
let statement .= string
elseif script[i] == '\'
" Escape.
let i += 1
if i >= max
throw 'Exception: Join to next line (\).'
endif
let statement .= '\' . script[i]
let i += 1
elseif script[i] == '#' && statement == ''
" Comment.
break
else
let statement .= script[i]
let i += 1
endif
endwhile
if statement !~ '^\s*$'
call add(statements,
\ {
\ 'statement' : statement,
\ 'condition' : 'always',
\ 'cwd' : getcwd(),
\})
endif
return statements
endfunction"}}}
function! vimproc#parser#split_statements(script) abort "{{{
return map(vimproc#parser#parse_statements(a:script),
\ 'v:val.statement')
endfunction"}}}
function! vimproc#parser#split_args(script) abort "{{{
let script = type(a:script) == type([]) ?
\ a:script : split(a:script, '\zs')
let max = len(script)
let args = []
let arg = ''
let i = 0
while i < max
if script[i] == "'"
" Single quote.
let [arg_quote, i] = s:parse_single_quote(script, i)
let arg .= arg_quote
if arg == ''
call add(args, '')
endif
elseif script[i] == '"'
" Double quote.
let [arg_quote, i] = s:parse_double_quote(script, i)
let arg .= arg_quote
if arg == ''
call add(args, '')
endif
elseif script[i] == '`'
" Back quote.
let head = i > 0 ? script[: i-1] : []
let [arg_quote, i] = s:parse_back_quote(script, i)
" Re-parse script.
return vimproc#parser#split_args(
\ head + split(arg_quote, '\zs') + script[i :])
elseif script[i] == '\'
" Escape.
let i += 1
if i >= max
throw 'Exception: Join to next line (\).'
endif
let arg .= script[i]
let i += 1
elseif script[i] == '#' && arg == ''
" Comment.
break
elseif script[i] != ' '
let arg .= script[i]
let i += 1
else
" Space.
if arg != ''
call add(args, arg)
endif
let arg = ''
let i += 1
endif
endwhile
if arg != ''
call add(args, arg)
endif
return args
endfunction"}}}
function! vimproc#parser#split_args_through(script) abort "{{{
let script = type(a:script) == type([]) ?
\ a:script : split(a:script, '\zs')
let max = len(script)
let args = []
let arg = ''
let i = 0
while i < max
if script[i] == "'"
" Single quote.
let [string, i] = s:skip_single_quote(script, i)
let arg .= string
if arg == ''
call add(args, '')
endif
elseif script[i] == '"'
" Double quote.
let [string, i] = s:skip_double_quote(script, i)
let arg .= string
if arg == ''
call add(args, '')
endif
elseif script[i] == '`'
" Back quote.
let [string, i] = s:skip_back_quote(script, i)
let arg .= string
if arg == ''
call add(args, '')
endif
elseif script[i] == '\'
" Escape.
let i += 1
if i >= max
throw 'Exception: Join to next line (\).'
endif
let arg .= '\'.script[i]
let i += 1
elseif script[i] != ' '
let arg .= script[i]
let i += 1
else
" Space.
if arg != ''
call add(args, arg)
endif
let arg = ''
let i += 1
endif
endwhile
if arg != ''
call add(args, arg)
endif
return args
endfunction"}}}
function! vimproc#parser#split_pipe(script) abort "{{{
let script = type(a:script) == type([]) ?
\ a:script : split(a:script, '\zs')
let max = len(script)
let command = ''
let i = 0
let commands = []
while i < max
if script[i] == '|'
" Pipe.
call add(commands, command)
" Search next command.
let command = ''
let i += 1
elseif script[i] == "'"
" Single quote.
let [string, i] = s:skip_single_quote(script, i)
let command .= string
elseif script[i] == '"'
" Double quote.
let [string, i] = s:skip_double_quote(script, i)
let command .= string
elseif script[i] == '`'
" Back quote.
let [string, i] = s:skip_back_quote(script, i)
let command .= string
elseif script[i] == '\' && i + 1 < max
" Escape.
let command .= '\' . script[i+1]
let i += 2
else
let command .= script[i]
let i += 1
endif
endwhile
call add(commands, command)
return commands
endfunction"}}}
function! vimproc#parser#split_commands(script) abort "{{{
let script = type(a:script) == type([]) ?
\ a:script : split(a:script, '\zs')
let max = len(script)
let commands = []
let command = ''
let i = 0
while i < max
if script[i] == '\'
" Escape.
let command .= script[i]
let i += 1
if i >= max
throw 'Exception: Join to next line (\).'
endif
let command .= script[i]
let i += 1
elseif script[i] == '|'
if command != ''
call add(commands, command)
endif
let command = ''
let i += 1
else
let command .= script[i]
let i += 1
endif
endwhile
if command != ''
call add(commands, command)
endif
return commands
endfunction"}}}
function! vimproc#parser#expand_wildcard(wildcard) abort "{{{
" Check wildcard.
let i = 0
let max = len(a:wildcard)
let script = ''
let found = 0
while i < max
if a:wildcard[i] == '*' || a:wildcard[i] == '?' || a:wildcard[i] == '['
let found = 1
break
else
let [script, i] = s:skip_else(script, a:wildcard, i)
endif
endwhile
if !found
return [ a:wildcard ]
endif
let wildcard = a:wildcard
" Exclude wildcard.
let exclude = matchstr(wildcard, '\\\@<!\~\zs.\+$')
let exclude_wilde = []
if exclude != ''
" Truncate wildcard.
let wildcard = wildcard[: len(wildcard)-len(exclude)-2]
let exclude_wilde = vimproc#parser#expand_wildcard(exclude)
endif
" Modifier.
let modifier = matchstr(wildcard, '\\\@<!(\zs.\+\ze)$')
if modifier != ''
" Truncate wildcard.
let wildcard = wildcard[: len(wildcard)-len(modifier)-3]
endif
" Expand wildcard.
let expanded = split(escape(substitute(
\ glob(wildcard, 1), '\\', '/', 'g'), ' '), '\n')
if empty(expanded)
" Use original string.
return [ a:wildcard ]
else
" Check exclude wildcard.
let candidates = expanded
let expanded = []
for candidate in candidates
let found = 0
for ex in exclude_wilde
if candidate ==# ex
let found = 1
break
endif
endfor
if !found
call add(expanded, candidate)
endif
endfor
endif
if modifier != ''
" Check file modifier.
let i = 0
let max = len(modifier)
while i < max
if modifier[i] ==# '/'
" Directory.
let expr = 'getftype(v:val) ==# "dir"'
elseif modifier[i] ==# '.'
" Normal.
let expr = 'getftype(v:val) ==# "file"'
elseif modifier[i] ==# '@'
" Link.
let expr = 'getftype(v:val) ==# "link"'
elseif modifier[i] ==# '='
" Socket.
let expr = 'getftype(v:val) ==# "socket"'
elseif modifier[i] ==# 'p'
" FIFO Pipe.
let expr = 'getftype(v:val) ==# "pipe"'
elseif modifier[i] ==# '*'
" Executable.
let expr = 'getftype(v:val) ==# "pipe"'
elseif modifier[i] ==# '%'
" Device.
if modifier[i :] =~# '^%[bc]'
if modifier[i] ==# 'b'
" Block device.
let expr = 'getftype(v:val) ==# "bdev"'
else
" Character device.
let expr = 'getftype(v:val) ==# "cdev"'
endif
let i += 1
else
let expr = 'getftype(v:val) ==# "bdev" || getftype(v:val) ==# "cdev"'
endif
else
" Unknown.
return []
endif
call filter(expanded, expr)
let i += 1
endwhile
endif
return filter(expanded, 'v:val != "." && v:val != ".."')
endfunction"}}}
" Parse helper.
function! s:parse_block(script) abort "{{{
let script = ''
let i = 0
let max = len(a:script)
while i < max
if a:script[i] == '{'
" Block.
let block = matchstr(a:script, '^{\zs.\{-}\ze}', i)
let rest = a:script[matchend(a:script, '^{.\{-}}', i) :]
if block == ''
let [script, i] = s:skip_else(script, a:script, i)
continue
endif
let head = matchstr(a:script[: i-1], '[^[:blank:]]*$')
" Truncate script.
let script = script[: -len(head)-1]
let rest = (rest =~ '^\s\+' ? ' ' : '') .
\ join(vimproc#parser#split_args(s:parse_cmdline(rest)))
let foot = matchstr(rest, '^\S\+')
let rest = rest[len(foot):]
if block == ''
throw 'Exception: Block is not found.'
elseif block =~ '^\d\+\.\.\d\+$'
" Range block.
let start = matchstr(block, '^\d\+')
let end = matchstr(block, '\d\+$')
let zero = len(matchstr(block, '^0\+'))+1
let pattern = '%0' . zero . 'd'
for b in range(start, end)
" Concat.
let script .= head . printf(pattern, b) . foot . ' '
endfor
else
" Normal block.
let blocks = (stridx(block, ',') < 0) ?
\ split(block, '\zs') :
\ split(block, ',', 1)
for b in vimproc#util#uniq(blocks)
" Concat.
let script .= head . escape(b, ' ') . foot . ' '
endfor
endif
let script .= rest
return script
else
let [script, i] = s:skip_else(script, a:script, i)
endif
endwhile
return script
endfunction"}}}
function! s:parse_tilde(script) abort "{{{
let script = ''
let i = 0
let max = len(a:script)
while i < max
if a:script[i] == ' ' && a:script[i+1] == '~'
" Tilde.
" Expand home directory.
let script .= ' ' . escape(substitute($HOME, '\\', '/', 'g'), '\ ')
let i += 2
elseif i == 0 && a:script[i] == '~'
" Tilde.
" Expand home directory.
let script .= escape(substitute($HOME, '\\', '/', 'g'), '\ ')
let i += 1
else
let [script, i] = s:skip_else(script, a:script, i)
endif
endwhile
return script
endfunction"}}}
function! s:parse_equal(script) abort "{{{
let script = ''
let i = 0
let max = len(a:script)
while i < max
if a:script[i] == ' ' && a:script[i+1] == '='
" Expand filename.
let prog = matchstr(a:script, '^=\zs[^[:blank:]]*', i+1)
if prog == ''
let [script, i] = s:skip_else(script, a:script, i)
else
let filename = vimproc#get_command_name(prog)
if filename == ''
throw printf('Error: File "%s" is not found.', prog)
else
let script .= filename
endif
" Consume `a:script` until an end of `prog`.
" e.g.
" 'echo =ls hoge' -> 'echo =ls hoge'
" ^ ^
let i += strlen(a:script[i] . a:script[i+1] . prog)
endif
else
let [script, i] = s:skip_else(script, a:script, i)
endif
endwhile
return script
endfunction"}}}
function! s:parse_variables(script) abort "{{{
let script = ''
let i = 0
let max = len(a:script)
try
while i < max
if a:script[i] == '$' && a:script[i :] =~ '^$$\?\h'
" Eval variables.
let variable_name = matchstr(a:script, '^$$\?\zs\h\w*', i)
if exists('b:vimshell')
" For vimshell.
let script_head = a:script[i :]
if script_head =~ '^$\l' &&
\ has_key(b:vimshell.variables, variable_name)
let script .= b:vimshell.variables[variable_name]
elseif script_head =~ '^\$\$' &&
\ has_key(b:vimshell.system_variables, variable_name)
let script .= b:vimshell.system_variables[variable_name]
elseif script_head =~ '^$\h'
let script .= vimproc#util#substitute_path_separator(
\ eval('$' . variable_name))
endif
else
let script .= vimproc#util#substitute_path_separator(
\ eval(matchstr(a:script, '^$\h\w*', i)))
endif
let i = matchend(a:script, '^$$\?\h\w*', i)
else
let [script, i] = s:skip_else(script, a:script, i)
endif
endwhile
catch /^Vim\%((\a\+)\)\=:E15/
" Parse error.
return a:script
endtry
return script
endfunction"}}}
function! s:parse_wildcard(script) abort "{{{
let script = ''
for arg in vimproc#parser#split_args_through(a:script)
let script .= join(vimproc#parser#expand_wildcard(arg)) . ' '
endfor
return script
endfunction"}}}
function! s:parse_redirection(script) abort "{{{
let script = ''
let fd = { 'stdin' : '', 'stdout' : '', 'stderr' : '' }
let i = 0
let max = len(a:script)
while i < max
if a:script[i] == '<'
" Input redirection.
let i += 1
let fd.stdin = get(vimproc#parser#split_args(
\ matchstr(a:script, '^\s*\S\+', i)), 0, '')
let i = matchend(a:script, '^\s*\S\+', i)
elseif a:script[i] =~ '^[12]' && a:script[i :] =~ '^[12]>'
" Output redirection.
let i += 2
if a:script[i-2] == 1
let fd.stdout = get(vimproc#parser#split_args(
\ matchstr(a:script, '^\s*\S\+', i)), 0, '')
else
let fd.stderr = get(vimproc#parser#split_args(
\ matchstr(a:script, '^\s*\zs\(\S\+\|&\d\+\)', i)), 0, '')
if fd.stderr ==# '&1'
" Redirection to stdout.
let fd.stderr = '/dev/stdout'
endif
endif
let i = matchend(a:script, '^\s*\zs\(\S\+\|&\d\+\)', i)
elseif a:script[i] == '&' && a:script[i :] =~ '^&>'
" Output stderr.
let i += 2
let fd.stderr = get(vimproc#parser#split_args(
\ matchstr(a:script, '^\s*\S\+', i)), 0, '')
let i = matchend(a:script, '^\s*\S\+', i)
elseif a:script[i] == '>'
" Output redirection.
if a:script[i :] =~ '^>&'
" Output stderr.
let i += 2
let fd.stderr = get(vimproc#parser#split_args(
\ matchstr(a:script, '^\s*\S\+', i)), 0, '')
elseif a:script[i :] =~ '^>>'
" Append stdout.
let i += 2
let fd.stdout = '>' . get(vimproc#parser#split_args(
\ matchstr(a:script, '^\s*\S\+', i)), 0, '')
else
" Output stdout.
let i += 1
let fd.stdout = get(vimproc#parser#split_args(
\ matchstr(a:script, '^\s*\S\+', i)), 0, '')
endif
let i = matchend(a:script, '^\s*\zs\S*', i)
else
let [script, i] = s:skip_else(script, a:script, i)
endif
endwhile
return [fd, script]
endfunction"}}}
function! s:parse_single_quote(script, i) abort "{{{
if a:script[a:i] != "'"
return ['', a:i]
endif
let arg = ''
let i = a:i + 1
let max = len(a:script)
while i < max
if a:script[i] == "'"
if i+1 < max && a:script[i+1] == "'"
" Escape quote.
let arg .= "'"
let i += 2
else
" Quote end.
return [arg, i+1]
endif
else
let arg .= a:script[i]
let i += 1
endif
endwhile
throw 'Exception: Quote ('') is not found.'
endfunction"}}}
function! s:parse_double_quote(script, i) abort "{{{
if a:script[a:i] != '"'
return ['', a:i]
endif
let escape_sequences = {
\ 'a' : "\<C-g>", 'b' : "\<BS>",
\ 't' : "\<Tab>", 'r' : "\<CR>",
\ 'n' : "\<LF>", 'e' : "\<Esc>",
\ '\' : '\', '?' : '?',
\ '"' : '"', "'" : "'",
\ '`' : '`', '$' : '$',
\}
let arg = ''
let i = a:i + 1
let script = type(a:script) == type([]) ?
\ a:script : split(a:script, '\zs')
let max = len(script)
while i < max
if script[i] == '"'
" Quote end.
return [arg, i+1]
elseif script[i] == '$'
" Eval variables.
let var = matchstr(join(script[i :], ''), '^$\h\w*')
if var != ''
let arg .= s:parse_variables(var)
let i += len(var)
else
let arg .= '$'
let i += 1
endif
elseif script[i] == '`'
" Backquote.
let [arg_quote, i] = s:parse_back_quote(script, i)
let arg .= arg_quote
elseif script[i] == '\'
" Escape.
let i += 1
if i >= max
throw 'Exception: Join to next line (\).'
endif
if script[i] == 'x'
let num = matchstr(join(script[i+1 :], ''), '^\x\+')
let arg .= nr2char(str2nr(num, 16))
let i += len(num)
elseif has_key(escape_sequences, script[i])
let arg .= escape_sequences[script[i]]
else
let arg .= '\' . script[i]
endif
let i += 1
else
let arg .= script[i]
let i += 1
endif
endwhile
throw 'Exception: Quote (") is not found.'
endfunction"}}}
function! s:parse_back_quote(script, i) abort "{{{
if a:script[a:i] != '`'
return ['', a:i]
endif
let arg = ''
let max = len(a:script)
if a:i + 1 < max && a:script[a:i + 1] == '='
" Vim eval quote.
let i = a:i + 2
while i < max
if a:script[i] == '\'
" Escape.
let i += 1
if i >= max
throw 'Exception: Join to next line (\).'
endif
let arg .= '\' . a:script[i]
let i += 1
elseif a:script[i] == '`'
" Quote end.
return [eval(arg), i+1]
else
let arg .= a:script[i]
let i += 1
endif
endwhile
else
" Eval quote.
let i = a:i + 1
while i < max
if a:script[i] == '`'
" Quote end.
return [substitute(vimproc#system(arg), '\n$', '', ''), i+1]
else
let arg .= a:script[i]
let i += 1
endif
endwhile
endif
throw 'Exception: Quote (`) is not found.'
endfunction"}}}
" Skip helper.
function! s:skip_single_quote(script, i) abort "{{{
let max = len(a:script)
let string = ''
let i = a:i
" a:script[i] is always "'" when this function is called
if i >= max || a:script[i] != ''''
throw 'Exception: Quote ('') is not found.'
endif
let string .= a:script[i]
let i += 1
let ss = []
while i < max
if a:script[i] == ''''
if i+1 < max && a:script[i+1] == ''''
" Escape quote.
let ss += [a:script[i]]
let i += 1
else
break
endif
endif
let ss += [a:script[i]]
let i += 1
endwhile
let string .= join(ss, '')
if i < max
" must end with "'"
if a:script[i] != ''''
throw 'Exception: Quote ('') is not found.'
endif
let string .= a:script[i]
let i += 1
endif
return [string, i]
endfunction"}}}
function! s:skip_double_quote(script, i) abort "{{{
let max = len(a:script)
let string = ''
let i = a:i
" a:script[i] is always '"' when this function is called
if i >= max || a:script[i] != '"'
throw 'Exception: Quote (") is not found.'
endif
let string .= a:script[i]
let i += 1
let ss = []
while i < max
if a:script[i] == '\' && i+1 < max
" Escape quote.
let ss += [a:script[i]]
let i += 1
elseif a:script[i] == '"'
break
endif
let ss += [a:script[i]]
let i += 1
endwhile
let string .= join(ss, '')
if i < max
" must end with '"'
if a:script[i] != '"'
throw 'Exception: Quote (") is not found.'
endif
let string .= a:script[i]
let i += 1
endif
return [string, i]
endfunction"}}}
function! s:skip_back_quote(script, i) abort "{{{
let max = len(a:script)
let string = ''
let i = a:i
" a:script[i] is always '`' when this function is called
if a:script[i] != '`'
throw 'Exception: Quote (`) is not found.'
endif
let string .= a:script[i]
let i += 1
while i < max && a:script[i] != '`'
let string .= a:script[i]
let i += 1
endwhile
if i < max
" must end with "`"
if a:script[i] != '`'
throw 'Exception: Quote (`) is not found.'
endif
let string .= a:script[i]
let i += 1
endif
return [string, i]
endfunction"}}}
function! s:skip_else(args, script, i) abort "{{{
if a:script[a:i] == "'"
" Single quote.
let [string, i] = s:skip_single_quote(a:script, a:i)
let script = a:args . string
elseif a:script[a:i] == '"'
" Double quote.
let [string, i] = s:skip_double_quote(a:script, a:i)
let script = a:args . string
elseif a:script[a:i] == '`'
" Back quote.
let [string, i] = s:skip_back_quote(a:script, a:i)
let script = a:args . string
elseif a:script[a:i] == '\'
" Escape.
let script = a:args . '\' . a:script[a:i+1]
let i = a:i + 2
else
let script = a:args . a:script[a:i]
let i = a:i + 1
endif
return [script, i]
endfunction"}}}
" Restore 'cpoptions' {{{
let &cpo = s:save_cpo
" }}}
" vim:foldmethod=marker:fen:sw=2:sts=2