mhinz / vim-startify

:link: The fancy start screen for Vim.
MIT License
5.3k stars 186 forks source link

invalid back reference on MSYS2 #538

Open Konfekt opened 1 year ago

Konfekt commented 1 year ago

Hello,

the line

https://github.com/mhinz/vim-startify/blob/81e36c352a8deea54df5ec1e2f4348685569bed2/autoload/startify.vim#L662

leads to an error message

line    4:
/c/\12
line    5:
E65: Illegal back reference

as shown by

let fname = '/c/\12'
let fname = fnamemodify(fname, ":p")
let fname = glob(fname)

if v:oldfiles contains file paths with back and forward slashes (as happens when using Vim in MSYS2 and Windows).

Maybe the slashes should be all converted to \

if exists('+shellslash') && !&shellslash

and to / otherwise?

FocusedWolf commented 1 year ago

Just experienced an issue with this same line in s:filter_oldfiles_unsafe(...). Turned on s:filter_oldfiles_unsafe = 1 and now i see: E944: Reverse range in character class when i start gvim. The same issue i think, special characters in fname cause errors.

Example of my issue with this line caused by [ ] in fname:

let fname = 'D:\test\.vimrc [automatic-backup].vimrc'
let absolute_path = glob(fnamemodify(fname, ":p"))
E944: Reverse range in character class

Doing this before fnamemodify(...) will fix my issue but more robust special-character escaping is needed for all cases:

let fname = substitute(fname, '\[', '\\\[', 'g')
let fname = substitute(fname, '\]', '\\\]', 'g')

EDIT: No the above fix only stops the error from occurring. This is correct (for windows only): let fname = substitute(fname, '\[', '\[[]', 'g')

Konfekt commented 1 year ago

By :help wildcards,

    ?   matches one character
    *   matches anything, including nothing
    **  matches anything, including nothing, recurses into directories
    [abc]   match 'a', 'b' or 'c'

therefore something like

if exists('+shellslash') && !&shellslash
  " win32
  let fname = substitute(fname, '\([[\]*?]\)', '\\[\1]', 'g')
else
  let fname = substitute(fname, '\([[\]*?\\]\)', '\\\1', 'g')
endif

should work

FocusedWolf commented 1 year ago

The win32 section needs some changes. Its causing files like D:\[test].txt to be filtered out of the recent file list.

let fname = 'D:\test\.vimrc [automatic-backup].vimrc'
" win32
let fname = substitute(fname, '\([[\]*?]\)', '\\[\1]', 'g')
echo fname
" D:\test\.vimrc \[[]automatic-backup\[]].vimrc

I think it should be: D:\test\.vimrc [[]automatic-backup].vimrc according to :help wildcards

The following fixes the win32 side:

if exists('+shellslash') && !&shellslash
  " win32
  let fname = substitute(fname, '\[', '\[[]', 'g')

  " Don't think this line is needed. Windows paths can't contain '*' and '?' (well there are exceptions to this, like DOS device paths can contain '?', https://learn.microsoft.com/en-us/dotnet/standard/io/file-path-formats but i don't think they need to be escaped.
  let fname = substitute(fname, '\([*?]\)', '\\\1', 'g')
else
  let fname = substitute(fname, '\([[\]*?\\]\)', '\\\1', 'g')
endif
Konfekt commented 1 year ago

Updated accordingly, though in let fname = substitute(fname, '\[', '\[[]', 'g') I wonder why \[[] instead of [[]

FocusedWolf commented 1 year ago

Good question. I copied the let fname = substitute(fname, '\[', '\[[]', 'g') line from the s:show_sessions() function. From what i can tell let fname = substitute(fname, '\[', '[[]', 'g') works identically, i.e. \[[] and [[] both insert [[]. Not sure why '[' is escaped? Help indicates some characters have special meaning in the {sub} argument (but nothing related to '[' that i could see).

:h substitute() :h sub-replace-special