VSCode Folders Not Sorting Alphabetically - visual-studio-code

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.

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:
explorerViewer.ts
comparers.ts:
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
Settings
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)

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

Related

Grouping file names in clusters

I am using this line to read all Images in a file:
imagefiles = dir('Images\*.jpg');
Suppose I have the names: a1.jpg,a11.jpg,b13.JPG,b5.JPG,c1.jpg.
How do I group together all images with no more than 2 different characters (the number) in their name. for the given example group together all a and all b and atheired group for c.
By grouping I mean form some kind of data structure or order that will enable me to access each group separately for later processing?
I am assuming the file type is always 'jpg' and the numbers will always be smaller then 100 and positive. I am assuming a not case sensitive code regarding file type, that is jpg and JPG may appear (I don't know regular expression but will be happy to learn from a good link as well)
You could capture the initial non-number part of the file name using regexp, group them with unique and put them in a struct.
% Some test data
files = {'a11','a1','b2','a32','ca3','b45','c1','ca2'};
files = strcat(files, '.jpg');
% Capture and group
tag = regexp(files,'^\D+','match','once');
[unTag, ~, unIdx] = unique(tag);
for idx = 1:length(unTag)
fileGroups.(unTag{idx}) = files(unIdx == idx);
end
% The result
>> fileGroups =
a: {'a11.jpg' 'a1.jpg' 'a32.jpg'}
b: {'b2.jpg' 'b45.jpg'}
c: {'c1.jpg'}
ca: {'ca3.jpg' 'ca2.jpg'}
Depending on how your filenames you might have to update to a more detailed regular expression. You could use \D+(?=\d+\.(JPG|jpg)) to caputure a non-digit char before some number and the .jpg extension.
So if your file names are something like:
>> files
'dummyStr_a11.jpg'
'dummyStr_a1.jpg'
'dummyStr_b2.jpg'
'dummyStr_a32.jpg'
'dummyStr_ca3.jpg'
'dummyStr_b45.jpg'
'dummyStr_c1.jpg'
'dummyStr_ca2.jpg'
Capture with something like
tag = regexp(files,'[a-z]+(?=\d+\.(JPG|jpg))','match','once');
>> tag =
'a' 'a' 'b' 'a' 'ca' 'b' 'c' 'ca'

Matlab | How to load/use files with consecutive names (abc1, abc2, abc3) and then pass on to the next series (cba1, cba2, cba3)?

I have a folder containing a series of data with file names like this:
abc1
abc2
abc3
bca1
bca2
bca3
bca4
bca5
cba1
... etc
My goal is to load all the relevant files for each file name, so all the "abc" files, and plot them in one graph. Then move on to the next file name, and do the same, and so forth. Is there a way to do this?
This is what I currently have to load and run through all the files, grab the data in them and get their name (without the .mat extension) to be able to save the graph with the same filename.
dirName = 'C:\DataDirectory';
files = dir( fullfile(dirName,'*.mat') );
files = {files.name}';
data = cell(numel(files),1);
for i=1:numel(files)
fname = fullfile(dirName,files{i});
disp(fname);
files{i} = files{i}(1:length(files{i})-4);
disp(files{i});
[Rest of script]
end
You already found out about the cool features of dir, and have a cell array files, which contains all file names, e.g.
files =
'37abc1.mat'
'37abc2.mat'
'50bca1.mat'
'50bca2.mat'
'1cba1.mat'
'1cba2.mat'
The main task now is to find all prefixes, 37abc, 50bca, 1cba, ... which are present in files. This can be done using a regular expression (regexp). The Regexp Pattern can look like this:
'([\d]*[\D]*)[\d]*.mat'
i.e. take any number of numbers ([\d]*), then any number of non-numeric characters ([\D]*) and keep those (by putting that in brackets). Next, there will be any number of numeric characters ([\d]*), followed by the text .mat.
We call the regexp function with that pattern:
pre = regexp(files,'([\d]*[\D]*)[\d]*.mat','tokens');
resulting in a cell array (one cell for each entry in files), where each cell contains another cell array with the prefix of that file. To convert this to a simple not-nested cell array, we call
pre = [pre{:}];
pre = [pre{:}];
resulting in
pre =
'37abc' '37abc' '50bca' '50bca' '1cba' '1cba'
To remove duplicate entries, we use the unique function:
pre = unique(pre);
pre =
'37abc' '50bca' '1cba'
which leaves us with all prefixes, that are present. Now you can loop through each of these prefixes and apply your stuff. Everything put together is:
% Find all files
dirName = 'C:\DataDirectory';
files = dir( fullfile(dirName,'*.mat') );
files = {files.name}';
% Find unique prefixes
pre = regexp(files,'([\d]*[\D]*)[\d]*.mat','tokens');
pre = [pre{:}]; pre = [pre{:}];
pre = unique(pre);
% Loop through prefixes
for ii=1:numel(pre)
% Get files with this prefix
curFiles = dir(fullfile(dirName,[pre{ii},'*.mat']));
curFiles = {curFiles.name}';
% Loop through all files with this prefix
for jj=1:numel(curFiles)
% Here the magic happens
end
end
Sorry, I misunderstood your question, I found this solution:
file = dir('*.mat')
matching = regexp({file.name}, '^[a-zA-Z_]+[0-9]+\.mat$', 'match', 'once'); %// Match once on file name, must be a series of A-Z a-z chars followed by numbers.
matching = matching(~cellfun('isempty', matching));
str = unique(regexp(matching, '^[a-zA-Z_]*', 'match', 'once'));
str = str(~cellfun('isempty', str));
group = cell(size(str));
for is = 1:length(str)
ismatch = strncmp(str{is}, matching, length(str{is}));
group{is} = matching(ismatch);
end
Answer came from this source: Matlab Central

how to make gulp.dest dynamic

I am learning to use gulp.I took a eg scenario in which I tried to copy the files based on the name if it is odd move it to odd folder otherwise move it to even. But some where destination folder is messed up. here is the folder structure and code.
1
--my
----new
-----2.txt
----1.txt
----2.txt
g = gulp.src '**/*.txt', cwd: '1'
g.pipe map (file,cb)->
filename = path.basename file.path, path.extname(file.path)
if filename % 2
dest = 'odd'
else
dest = 'even'
debugger
console.log 'destination ',dest
g.pipe gulp.dest dest
cb null,file
It is copying the even file names to odd folder.It is about the destination folder being remembered(closure I think)
If you literally only have two output destinations, the simplest solution might be to use the gulp-if plugin, like so (I don't use CoffeeScript, so you'll have to convert it yourself):
var _if = require('gulp-if');
function fileIsOdd(file) {
return path.basename(file.path, path.extname(file.path)) % 2;
}
// in your task
gulp.src('**/*.txt', {cwd: '1'})
.pipe(_if(fileIsOdd, gulp.dest('odd'), gulp.dest('even')))
What this does is process the individual file with the fileIsOdd function. If the function returns a truthy value, then the first argument is processed, otherwise the second argument is processed.

Separating an array based on whether it contains a phrase or not

I am really just a noob at Matlab, so please don't get upset if I use wrong syntax. I am currently writing a small program in which I put all .xlsx file names from a certain directory into an array. I now want to separate the files into two different arrays based on their name. This is what I tried:
files = dir('My_directory\*.xlsx')
file_number = 1;
file_amount = length(files);
while file_number <= file_amount;
file_name = files(file_number).name;
filescs = [];
filescwf = [];
if strcmp(file_name,'*cs.xlsx') == 1;
filescs = [filescs,file_name];
else
filescwf = [filescwf,file_name];
end
file_number = file_number + 1
end
The idea here is that strcmp(file_name,'*cs.xlsx') checks if file_name contains 'cs' at the end. If it does, it is put into filescs, if it doesn't it is put into filescwf. However, this does not seem to work...
Any thoughts?
strcmp(file_name,'*cs.xlsx') checks whether file_name is identical to *cs.xlsx. If there is no file by that name (hint: few file systems allow '*' as part of a file name), it will always be false. (btw: there is no need for the '==1' comparison or the semicolon on the respective line)
You can use array indexing here to extract the relevant part of the filename you want to compare. file_name(1:5), will give you the first 5 characters, file_name(end-5:end) will give you the last 6, for example.
strcmp doesn't work with wildcards such as *cs.xlsx. See this question for an alternative approach.
You can use regexp to check the final letters of each of your files, then cellfun to apply regexp to all your filenames.
Here, getIndex will have 1's for all the files ending with cs.xlsx. The (?=$) part make sure that cs.xlsx is at the end.
files = dir('*.xlsx')
filenames = {files.name}'; %get filenames
getIndex = cellfun(#isempty,regexp(filenames, 'cs.xlsx(?=$)'));
list1 = filenames(getIndex);
list2 = filenames(~getIndex);

loop within loop - detecting end of loop in autohotkey

Let's say I have a bunch of filenames with the names of fruits in them. I want to auto-rename them based upon a folder full of reference files (dummy txt files which contain the names of fruits, a period, then the name of a dessert).
apple.tart, grape.jelly, kiwi.cake, mango.icecream, banana.pudding, cherry.cobbler, etc
I want to select all the files to be renamed, and drag them onto my script.
If a file in the loop already contains a certain combo, such as "cherry.cobbler", I simply want the dummyfile to be discarded, and the file should NOT be renamed "cherry.cobbler.cobbler"
If a file in the loop contains the word "kiwi", I want it to be changed so that it contains "kiwi.cake".
If a file in the loop contains a fruit not listed, I want a catchall string to be added. So "kumquat" would become "kumquat.nodessert"
It is condition #3 which is causing me trouble. I can't seem to come up with the right syntax to specify when the last dummyfile has been checked.
here's some pseudo code
Loop %0%
{
Path := %A_Index%
Loop %Path%, 1
LongPath = %A_LoopFileLongPath%
SplitPath LongPath, OutFileName, OutDir, OutExtension, OutNameNoExt, OutDrive
Loop thru folder of fruit combos
{
Stringsplit filenames from fruit-combos folder into %fruit% and %dessert%
If OutNameNoExt contains %fruit%.%dessert%
{
FileDelete fruit.combo dummyfile
continue; skip to next file to rename
)
If OutNameNoExt contains %fruit%
{
FileDelete fruit.combo dummyfile
StringReplace %fruit% with %fruit%.%dessert%
continue; skip to next file to rename
)
If OutNameNoExt not contains fruit.combo AND all dummy files have been checked
{
StringReplace %fruit% with %fruit%.nodessert
)
}
; proceed with next selected file
}
put condition 3 outside the inner loop and it seems to work