refactor(path): path_skip_sep() #40524

Problem:
Redundant code.

Solution:
Add path_skip_sep() and use it.

Dropping MB_PTR_ADV is safe: the loops only advance while `*p` is
a one-byte separator (`/`, `\`, `:`). MB_PTR_ADV was needed in legacy
Vim because it supported non-UTF-8 (DBCS) *internal* encodings.
This commit is contained in:
Justin M. Keyes
2026-07-01 09:48:54 -04:00
committed by GitHub
parent fa9b3381bc
commit 12ea9735f7
3 changed files with 33 additions and 40 deletions

View File

@@ -340,6 +340,7 @@ UI
VIMSCRIPT
• `fnamemodify(':h')` preserves logical roots for more path formats.
• |v:exitreason| is set before |QuitPre|.
• |v:startreason| indicates whether Nvim started normally or by |:restart|.
• |v:starttime| is the process start time (nanoseconds since UNIX epoch).
@@ -369,7 +370,6 @@ These existing features changed their behavior.
• Markdown inline highlighting now conceals the backslash in backslash escapes.
• Markdown inline backslash escapes and hard line breaks no longer use the
`@string.escape` capture.
• `fnamemodify(':h')` preserves logical roots for more path formats.
==============================================================================
REMOVED FEATURES *news-removed*

View File

@@ -1202,14 +1202,6 @@ bool os_fileinfo(const char *path, FileInfo *file_info)
return os_stat(path, &(file_info->stat)) == kLibuvSuccess;
}
static const char *path_skip_sep(const char *path)
{
while (*path != NUL && vim_ispathsep_nocolon(*path)) {
path++;
}
return path;
}
/// Parses `path` into a `FileInfo` structure.
///
/// TODO(ntdiary): Could be extended for path.c cleanup and path normalization
@@ -1223,15 +1215,15 @@ bool os_fileinfo2(const char *path, FileInfo *info)
if (path_with_url(path)) {
return true;
}
// Preserves the leading two "/"; runs of 3+ "/" collapse to a single "/" (IEEE 1003.1).
// The same rule applies to kPathUNC and kPathGeneric on Windows, but not to kPathDevice
// or kPathDeviceUNC, where the leading "//" is significant.
const char *p = path_skip_sep(path);
// Preserves the leading two "/"; 3+ "///…" collapse to a single "/" (IEEE 1003.1).
// Same rule applies to kPathUNC/kPathGeneric on Windows, but not to kPathDevice or
// kPathDeviceUNC, where the leading "//" is significant.
const char *p = path_skip_sep(path, false);
size_t leading_slashes = (size_t)(p - path);
#ifdef MSWIN
if (leading_slashes == 0 && ASCII_ISALPHA(p[0]) && p[1] == ':') {
info->type = kPathDrive;
p = path_skip_sep(p + 2);
p = path_skip_sep(p + 2, false);
info->rest_off = (size_t)(p - path);
return true;
}
@@ -1241,10 +1233,10 @@ bool os_fileinfo2(const char *path, FileInfo *info)
}
info->type = kPathDevice;
info->prefix_off = leading_slashes - 2;
p = path_skip_sep(p + 2);
p = path_skip_sep(p + 2, false);
if (vim_strnicmp_asc(p, "unc", 3) == 0 && vim_ispathsep_nocolon(p[3])) {
info->type = kPathDeviceUNC;
p = path_skip_sep(p + 4);
p = path_skip_sep(p + 4, false);
info->root_off = (size_t)(p - path);
goto server;
}
@@ -1252,15 +1244,15 @@ bool os_fileinfo2(const char *path, FileInfo *info)
if (ASCII_ISALPHA(p[0]) && p[1] == ':') {
p += 2;
}
p = path_skip_sep(path_next_component(p));
p = path_skip_sep(path_next_component(p), false);
info->rest_off = (size_t)(p - path);
return true;
}
if (leading_slashes == 2) {
info->type = kPathUNC;
server:
p = path_skip_sep(path_next_component(p));
p = path_skip_sep(path_next_component(p));
p = path_skip_sep(path_next_component(p), false);
p = path_skip_sep(path_next_component(p), false);
info->rest_off = (size_t)(p - path);
return true;
}

View File

@@ -188,7 +188,7 @@ const char *invocation_path_tail(const char *invocation, size_t *len)
return tail;
}
/// Get the next path component of a path name.
/// Get the next separator-delimited component of a path name.
///
/// @param fname A file path. (Must be != NULL.)
/// @return Pointer to first found path separator + 1.
@@ -205,6 +205,20 @@ const char *path_next_component(const char *fname)
return fname;
}
/// Advances past consecutive path separators.
///
/// @param path Position in a path.
/// @param colon Whether ':' counts as a separator on MS-Windows (see vim_ispathsep()).
/// @return Pointer to the first non-separator byte (or terminating NUL).
char *path_skip_sep(const char *path, bool colon)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET FUNC_ATTR_PURE
{
while (colon ? vim_ispathsep(*path) : vim_ispathsep_nocolon(*path)) {
path++;
}
return (char *)path;
}
/// Returns the length of the path head on the current platform.
/// @return
/// - 3 on windows
@@ -249,9 +263,7 @@ char *get_past_head(const char *path)
}
#endif
while (vim_ispathsep(*retval)) {
retval++;
}
retval = path_skip_sep(retval, true);
return (char *)retval;
}
@@ -1006,9 +1018,7 @@ static char *get_path_cutoff(char *fname, garray_T *gap)
// skip to the file or directory name
if (cutoff != NULL) {
while (vim_ispathsep(*cutoff)) {
MB_PTR_ADV(cutoff);
}
cutoff = path_skip_sep(cutoff, true);
}
return cutoff;
@@ -1642,9 +1652,7 @@ size_t simplify_filename(char *filename)
if (vim_ispathsep(*p)) {
relative = false;
do {
p++;
} while (vim_ispathsep(*p));
p = path_skip_sep(p, true);
}
char *start = p; // remember start after "c:/" or "/" or "///"
char *p_end = p + strlen(p); // point to NUL at end of string "p"
@@ -1674,9 +1682,7 @@ size_t simplify_filename(char *filename)
// of an absolute path name.
char *tail = p + 1;
if (p[1] != NUL) {
while (vim_ispathsep(*tail)) {
MB_PTR_ADV(tail);
}
tail = path_skip_sep(tail, true);
} else if (p > start) {
p--; // strip preceding path separator
}
@@ -1686,10 +1692,7 @@ size_t simplify_filename(char *filename)
} else if (p[0] == '.' && p[1] == '.'
&& (vim_ispathsep(p[2]) || p[2] == NUL)) {
// Skip to after ".." or "../" or "..///".
char *tail = p + 2;
while (vim_ispathsep(*tail)) {
MB_PTR_ADV(tail);
}
char *tail = path_skip_sep(p + 2, true);
if (components > 0) { // strip one preceding component
bool do_strip = false;
@@ -2175,10 +2178,8 @@ char *path_shorten_fname(char *full_path, char *dir_name)
return NULL;
}
do {
p++;
} while (vim_ispathsep_nocolon(*p));
return p;
// Skip the matched separator, then any following separators (but not a colon).
return path_skip_sep(p + 1, false);
}
/// Invoke expand_wildcards() for one pattern