mirror of
https://github.com/neovim/neovim.git
synced 2025-11-14 14:29:02 +00:00
fix(completion): complete drive-letter filepath on Windows #36353
Problem: On MSWIN, file completion (CTRL-X CTRL-F) only works for the current drive (so not for actual absolute paths), since drive letters are never included in the completion pattern. e.g. when completing "F:\Hello" Nvim currently completes "\Hello" which is relative to the current drive/volume. vim solves this by adding ':' to the default 'isfname' value on mswin, but that causes issues as ':' is not a valid windows path char anywhere _except_ after the drive letter. Solution: detect drive letters in front of the path when creating the completion pattern.
This commit is contained in:
@@ -1679,7 +1679,7 @@ char *file_name_in_line(char *line, int col, int options, int count, char *rel_f
|
||||
|
||||
// Search forward for the last char of the file name.
|
||||
// Also allow ":/" when ':' is not in 'isfname'.
|
||||
len = path_has_drive_letter(ptr) ? 2 : 0;
|
||||
len = path_has_drive_letter(ptr, strlen(ptr)) ? 2 : 0;
|
||||
while (vim_isfilec((uint8_t)ptr[len]) || (ptr[len] == '\\' && ptr[len + 1] == ' ')
|
||||
|| ((options & FNAME_HYP) && path_is_url(ptr + len))
|
||||
|| (is_url && vim_strchr(":?&=", (uint8_t)ptr[len]) != NULL)) {
|
||||
|
||||
@@ -5786,7 +5786,17 @@ static int get_filename_compl_info(char *line, int startcol, colnr_T curs_col)
|
||||
while (p > line && vim_isfilec(utf_ptr2char(p))) {
|
||||
MB_PTR_BACK(line, p);
|
||||
}
|
||||
if (p == line && vim_isfilec(utf_ptr2char(p))) {
|
||||
bool p_is_filec = false;
|
||||
#ifdef MSWIN
|
||||
// check for drive letters on mswin
|
||||
if (p > line && path_has_drive_letter(p - 1, line + startcol - (p - 1))) {
|
||||
p -= p == line + 1 ? 1 : 2;
|
||||
p_is_filec = true;
|
||||
}
|
||||
#endif
|
||||
p_is_filec = p_is_filec || vim_isfilec(utf_ptr2char(p));
|
||||
|
||||
if (p == line && p_is_filec) {
|
||||
startcol = 0;
|
||||
} else {
|
||||
startcol = (int)(p - line) + 1;
|
||||
|
||||
@@ -1715,13 +1715,13 @@ size_t simplify_filename(char *filename)
|
||||
/// Checks for a Windows drive letter ("C:/") at the start of the path.
|
||||
///
|
||||
/// @see https://url.spec.whatwg.org/#start-with-a-windows-drive-letter
|
||||
bool path_has_drive_letter(const char *p)
|
||||
bool path_has_drive_letter(const char *p, size_t path_len)
|
||||
FUNC_ATTR_NONNULL_ALL
|
||||
{
|
||||
return strlen(p) >= 2
|
||||
return path_len >= 2
|
||||
&& ASCII_ISALPHA(p[0])
|
||||
&& (p[1] == ':' || p[1] == '|')
|
||||
&& (strlen(p) == 2 || ((p[2] == '/') | (p[2] == '\\') | (p[2] == '?') | (p[2] == '#')));
|
||||
&& (path_len == 2 || ((p[2] == '/') | (p[2] == '\\') | (p[2] == '?') | (p[2] == '#')));
|
||||
}
|
||||
|
||||
// Check if the ":/" of a URL is at the pointer, return URL_SLASH.
|
||||
@@ -1758,7 +1758,7 @@ int path_with_url(const char *fname)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (path_has_drive_letter(fname)) {
|
||||
if (path_has_drive_letter(fname, strlen(fname))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -30,6 +30,16 @@ describe('completion', function()
|
||||
}
|
||||
end)
|
||||
|
||||
it('ctrl-x_ctrl-f completes Windows drive letter', function()
|
||||
if not t.is_os('win') then
|
||||
return
|
||||
end
|
||||
feed('iblablaC:/W<C-x><C-f>')
|
||||
screen:expect {
|
||||
any = [[C:\Windows\]],
|
||||
}
|
||||
end)
|
||||
|
||||
describe('v:completed_item', function()
|
||||
it('is empty dict until completion', function()
|
||||
eq({}, eval('v:completed_item'))
|
||||
|
||||
Reference in New Issue
Block a user