Open mcexit opened 1 year ago
I have the same issue.
Does the suggested fix in the issue work for you?
Yes, it does.
Escaping arguments for makeprg
is tricky. Vim should provide convenience functions in addition to hints scattered over various help files. Having no experience with vim scripting I have come to the following:
let s:ledger_main = ledger#escape_compiler_word(expand(
\ exists('b:ledger_main') ? b:ledger_main : ledger_main))
" It is assumed that if g:ledger_extra_options contains some shell
" or makeprg specials then they are added consciously.
let s:set_makeprg = join([
\ ledger#escape_compiler_word(exists('b:ledger_bin') ? b:ledger_bin : ledger_bin),
\ '-f', s:ledger_main,
\ exists('b:ledger_extra_options')
\ ? b:ledger_extra_options : ledger_extra_options,
\ 'source', s:ledger_main])
exe 'CompilerSet makeprg=' .. ledger#escape_compiler_command(s:set_makeprg)
function! ledger#escape_compiler_word(arg)
" Finally every word will be passed to shell,
" so it is necessary to escape spaces and special characters.
" On Linux single quotes are added around.
let l:word = shellescape(a:arg)
" Protect some specials that are expanded in makeprg value
" before the command is executed, see |'makeprg'|.
" Can not use fnameescape here since spaces.
" are protected by shellescape as well and would be escaped twice.
" Protect %, # buffer references and variations of <cword>.
let l:word = escape(l:word, '#%<')
" Optional list of :make command arguments ($*)
" and environment variables expansion
" performed by :set is a more tricky case.
" It is impossible to protect it by adding backslashes since
" they would be passed to shell literally instead of been stripped.
" An additional argument against escaping by backslashes
" is that $ENV_VAR is passed literally
" if ENV_VAR does not exist, see |expand-env|.
" FIXME Add some trick for Windows, single quotes is suitable for Linux.
if '''''' == shellescape('')
" Add two single quote characters between them
" since shellescape uses single quotes.
" It relies on shellescape implementation details, so it is fragile.
" "'$*'" => "'$''*'"
let l:word = substitute(l:word, '\$\([^'']\)', '$''''\1', 'g')
endif
return l:word
endfunction
function! ledger#escape_compiler_command(command)
" When makeprg is executed, '|' is considered as a separator
" between shell and following vim commands, see |'makeprg'|.
let l:cmd = escape(a:command, '|')
" Command "set" requires escaping of comments, command separators,
" spaces, and backslashes. See |option-backslash|.
" Expanding $ENV_VAR (see |'makeprg'|)
" should be prevented by ledger#escape_compiler_word.
return escape(l:cmd, '|"\ ')
endfunction
However treatment of ledger_bin
becomes different from s:ledger_cmd()
in autoload/ledger.vim
. Perhaps expand()
should be used in both cases and shellescape()
should be added in s:ledger_cmd()
.
I tested it with %
or
let g:ledger_main= '~/examples/ledger/l ''"|e<cword>d$*g%:r\\-\$USER-sp#cial.ledger'
and a test file names as
ln -s test.ledger l\ \'\"\|e\<cword\>d\$\*g%\:r\\-\$USER-sp#cial.ledger
I see #121 was supposed to resolve this, but I'm still having the same issue with ledger 3.3.1 and Vim 9.0.1420. The error looks like this:
Quoting the global variable
g:ledger_main
incompiler/ledger.vim
on line 33 appears to fix the issue:Unfortunately I don't have the knowledge to check if this causes unintended consequences (e.g. NeoVim). I also want to make that this isn't a "me" issue.