Skip to content

Instantly share code, notes, and snippets.

@ncfavier
Last active June 8, 2023 15:58
Show Gist options
  • Save ncfavier/12646d02987fab214a76f0cdb04a3349 to your computer and use it in GitHub Desktop.
Save ncfavier/12646d02987fab214a76f0cdb04a3349 to your computer and use it in GitHub Desktop.
shellwords in vimscript
function! s:unbackslash(str)
return substitute(a:str, '\\\(.\)', '\1', 'g')
endfunction
" Parse a shell command line into a list of words, à la Perl's shellwords or
" Python's shlex.split.
function! s:shellwords(str)
let l:args = []
let l:len = len(a:str)
let l:i = 0
let l:new = 1 " does a new word need to be created?
while l:i < l:len
let [l:match, l:start, l:end] = matchstrpos(a:str, '^\s\+', l:i) " whitespace
if l:end >= 0
let l:i = l:end
let l:new = 1
continue
endif
if l:new " there are more words to come
call add(l:args, '')
let l:new = 0
endif
let [l:match, l:start, l:end] = matchstrpos(a:str, '^\([^''"\\[:space:]]\|\\.\)\+', l:i) " unquoted text
if l:end >= 0
let l:args[-1] ..= s:unbackslash(l:match)
let l:i = l:end
continue
endif
let [l:match, l:start, l:end] = matchstrpos(a:str, "^'[^']*'", l:i) " single quotes
if l:end >= 0
let l:args[-1] ..= l:match[1:-2]
let l:i = l:end
continue
endif
let [l:match, l:start, l:end] = matchstrpos(a:str, '^"\([^"\\]\|\\.\)*"', l:i) " double quotes
if l:end >= 0
let l:args[-1] ..= s:unbackslash(l:match[1:-2])
let l:i = l:end
continue
endif
throw "shellwords: failed to parse arguments"
endwhile
return l:args
endfunction
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment