ledger / vim-ledger

Vim plugin for Ledger
GNU General Public License v2.0
371 stars 55 forks source link

Still encountering issues with spacing in filename #144

Open mcexit opened 1 year ago

mcexit commented 1 year ago

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.

maltsev commented 1 year ago

I have the same issue.

alerque commented 1 year ago

Does the suggested fix in the issue work for you?

maltsev commented 1 year ago

Yes, it does.

maxnikulin commented 6 months ago

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