mhinz/vim-startify

invalid back reference on MSYS2

Konfekt opened this issue · 5 comments

Hello,

the line

let absolute_path = glob(fnamemodify(fname, ":p"))

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?

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')

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

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

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

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