Reputation: 317
Visual Studio Code Explorer pane is sorting my folders oddly. I want to validate this is truly an issue before reporting it as a bug. I have vscode 1.47.2. I'm fairly sure this wasn't always an issue. Here's an example:
I would expect that a folder named "aaa.xxx.iii" would be alphabetically sorted before the folder named "aaa.yyy". In fact, when I look at the list in File Explorer, it is indeed sorted correctly.
I am not using a workspace file. I have searched the entire directory structure and I have no files suffixed with .code-workspace. I know this can be an issue in multi-root workspaces. However, I am just using "Open Folder" to open this solution.
I have also checked the settings under Workspace Settings, Features, Explorer, Sort and it is set to default (Alphabetic, Folders before Files). I tried changing to Modified sort order and back with no luck.
Upvotes: 1
Views: 2744
Reputation: 5857
You may want to check out the "Sort Order Lexicographic Options" setting and set it to unicode
to get the desired results.
Upvotes: 1
Reputation: 317
It appears this is an outstanding issue. I changed my search terms on GitHub and found the original discussion. It seems there's no resolution as of this comment.
https://github.com/microsoft/vscode/issues/99955
Upvotes: 0
Reputation: 10592
I would expect that a folder named "aaa.xxx.iii" would be alphabetically sorted before the folder named "aaa.yyy"
It is alphabetically sorted, just ASCII sorted!
ASCII values:
a = 97
b = 98
i = 105
x = 120
y = 121
. = 46
Therefore:
aaa = 291
aaa.xxx = 697
aaa.yyy = 700
aaa.xxx.iii = 1,012
However, there seems to be some variation to their logic. They actually split filenames via a filename regex (and they use the same logic for comparing directories and filenames). They effectively compare against a filename first, before even considering the extension using the following regex:
const FileNameMatch = /^(.*?)(\.([^.]*))?$/;
And then it will only consider extensions when it returns 0
, for not greater than or less than.
Using that regex: in your example, aaa.xxx
, aaa
is the filename, .xxx
is the 'extension`.
With aaa.yyy
; aaa
is the filename and compared against aaa.xxx.iii
, you get it .iii
is the extension. Ergo, aaa.yyy
, or the name without the .yyy
extension: aaa
< aaa.xxx
or aaa.xxx.iii
with the extension
Here is their logic:
export function compareFileNamesNumeric(one: string | null, other: string | null): number {
const [oneName, oneExtension] = extractNameAndExtension(one, true);
const [otherName, otherExtension] = extractNameAndExtension(other, true);
const collatorNumeric = intlFileNameCollatorNumeric.value.collator;
const collatorNumericCaseInsensitive = intlFileNameCollatorNumericCaseInsenstive.value.collator;
let result;
// Check for name differences, comparing numbers numerically instead of alphabetically.
result = compareAndDisambiguateByLength(collatorNumeric, oneName, otherName);
if (result !== 0) {
return result;
}
// Check for case insensitive extension differences, comparing numbers numerically instead of alphabetically.
result = compareAndDisambiguateByLength(collatorNumericCaseInsensitive, oneExtension, otherExtension);
if (result !== 0) {
return result;
}
// Disambiguate the extension case if needed.
if (oneExtension !== otherExtension) {
return collatorNumeric.compare(oneExtension, otherExtension);
}
return 0;
}
So it appears, for the most part, they are just using Intl.Collator with basic name value a < b
logic, with some variations of course.
It also appears they disambiguate by length, meaning foo1
and foo01
are considered equal. line 169
The setting you described only affects 'how they are displayed', in a way sorted yes, but mostly how they are shown to the user, not really how they are sorted programmatically as I interpret it.
// Controls sorting order of files and folders in the explorer.
// - default: Files and folders are sorted by their names, in alphabetical order. Folders are displayed before files.
// - mixed: Files and folders are sorted by their names, in alphabetical order. Files are interwoven with folders.
// - filesFirst: Files and folders are sorted by their names, in alphabetical order. Files are displayed before folders.
// - type: Files and folders are sorted by their extensions, in alphabetical order. Folders are displayed before files.
// - modified: Files and folders are sorted by last modified date, in descending order. Folders are displayed before files.
"explorer.sortOrder": "default",
So it's more of a presentation setting for files/directories not the names themselves.
If you look at the explorerViewer.ts
control flow you will see:
switch (sortOrder) {
case 'type':
if (statA.isDirectory && !statB.isDirectory) {
return -1;
}
if (statB.isDirectory && !statA.isDirectory) {
return 1;
}
if (statA.isDirectory && statB.isDirectory) {
return compareFileNamesNumeric(statA.name, statB.name);
}
break;
And now we can visualize going back to how directories are sorted with the same function; re if (statA.isDirectory && statB.isDirectory)
Upvotes: 1