ledger/vim-ledger

Still encountering issues with spacing in filename

mcexit opened this issue · 4 comments

mcexit commented

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:

Error detected while processing BufRead Autocommands for "*.ledger"..FileType Autocommands for "*"..function <SNR>9_LoadFTPlugin[18]..script /home/user/.vim/pack/git-plugins/opt/vim-ledger/ftplugin/ledger.vim[206]../home/user/.vim/pack/git-plugins/opt/vim-ledger/compiler/ledger.vim
:
line   33:
E518: Unknown option: Bank

Quoting the global variable g:ledger_main in compiler/ledger.vim on line 33 appears to fix the issue:

	exe 'CompilerSet makeprg='.substitute(g:ledger_bin, ' ', '\\ ', 'g').'\ -f\ ' . substitute(shellescape(expand('g:ledger_main')), ' ', '\\ ', 'g') . '\ '.substitute(g:ledger_extra_options, ' ', '\\ ', 'g').'\ source\ ' . shellescape(expand('g:ledger_main'))

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.

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