Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sort command does not use the same sorting scheme as Xcode #615

Closed
barakwei opened this issue Oct 11, 2018 · 16 comments
Closed

Sort command does not use the same sorting scheme as Xcode #615

barakwei opened this issue Oct 11, 2018 · 16 comments

Comments

@barakwei
Copy link
Contributor

Xcode supports sorting group by right clicking on the group and choosing "Sort by Name".
If you have a group with two files - A10.h and A2.h, for example, Xcode will put A2.h first.
xcodeproj sort command will do the simple alphabetic sort and put A10.h first.

The scheme used by Xcode is weird (try sorting A1 and A01, or even better A1B01, and A01B1). If someone accidentally knows what's the exact sorting scheme it will be great, but fixing the most simple case is sufficient.

@segiddins
Copy link
Member

Pull requests improving the group sorting algorithm are very welcome!

@Coeur
Copy link
Contributor

Coeur commented Apr 24, 2019

Oh, good case with ["A1B001", "A01B1"], it's not even the same order as the Finder.
It seems to me that, if two strings are naturally equal (like "A1B001 and "A01B1"):

  • Xcode "Sort by name" logic is to do a second comparison where it sorts reverse-alphabetically (giving priority to values without leading zeros)
  • Finder logic in this situation is to first sort by total length, then reverse-alphabetically

I'll try to implement the Xcode rule in ruby.

@Coeur
Copy link
Contributor

Coeur commented Apr 24, 2019

OK, here is my ruby implementation:

[edit]

see pull request #677 now, and in particular file https://github.com/CocoaPods/Xcodeproj/blob/ca7b41deb38f43c14d066f62a55edcd53876cd07/lib/xcodeproj/project/object/helpers/sort_helper.rb

Coeur added a commit to Coeur/Xcodeproj that referenced this issue Apr 25, 2019
Coeur added a commit to Coeur/Xcodeproj that referenced this issue Apr 25, 2019
Coeur added a commit to Coeur/Xcodeproj that referenced this issue Apr 25, 2019
Coeur added a commit to Coeur/Xcodeproj that referenced this issue Apr 25, 2019
Coeur added a commit to Coeur/Xcodeproj that referenced this issue Apr 25, 2019
Coeur added a commit to Coeur/Xcodeproj that referenced this issue Apr 26, 2019
@Coeur
Copy link
Contributor

Coeur commented Apr 26, 2019

@barakwei Algorithm fixed in the PR #677. Can you test it on your own files?

@Coeur
Copy link
Contributor

Coeur commented May 14, 2019

@barakwei @segiddins Anything else to be solved, here?
In the mean time, I published my solution as a Stack Overflow answer with a few explanations on why it must be a lengthy piece of code: https://stackoverflow.com/questions/5480703/how-to-sort-an-alphanumeric-array-in-ruby/56000450#56000450

@barakwei
Copy link
Contributor Author

barakwei commented May 14, 2019

Sorry for missing the discussion, I only noticed it now.
Here is a list of file names that you can use for testing:
File1.h
File2.h
File01.h
File001.h
File01aa.h
File001bb.h
File01bbb.h

In addition, I suggest adding files with "multiple extensions" like File.h, File.aa.h, File.bb.h and File.aa.bb.h.

Mixing between the two lists is also a good idea, there are probably many edge cases.

Good luck!

@Coeur
Copy link
Contributor

Coeur commented May 14, 2019

@barakwei I mean: please look at my pull request #677: all those cases should pass already. Have a try from my branch https://github.com/Coeur/Xcodeproj/tree/xcode_sort.

@barakwei
Copy link
Contributor Author

barakwei commented May 15, 2019

I've tried it. Unfortunately, it doesn't match Xcode's sorting.

I suggest to add them to the test of this class in any case. This is how Xcode sorts them (just like Finder, at least on my machine):

[
"File.aa.bb.h",
"File.aa.h",
"File.bb.h",
"File.h",
"File1.h",
"File01.h",
"File001.h",
"File01aa.h",
"File001bb.h",
"File01bbb.h",
"File2.h",
"File10.h",
]

Your sorting produces a different result:

File1.h
File01.h
File001.h
File01aa.h
File001bb.h
File01bbb.h
File2.h
File10.h
File.aa.bb.h
File.aa.h
File.bb.h
File.h

From what I understand, Finder uses -[NSString compare:options:range:locale:], which calls the same method in CFString. You can look for the source of this method online, but it's quite complex.
You could theoretically call the CFString method from ruby and have the desired effect, but that would work only on mac.

@Coeur
Copy link
Contributor

Coeur commented May 15, 2019

Well, basically Xcode sorts a dot . before a digit like 0. That's the only diff and it's easily fixable.

@Coeur
Copy link
Contributor

Coeur commented May 15, 2019

Actually, I found more cases failing with my original sorting: notably unicode characters, and that's a bit more tricky. Ah, if only the Xcode sort behavior was documented!

[edit]
I found a piece of doc for Finder at https://support.apple.com/kb/TA22935?locale=en_US

And some useful test cases and discussion at https://discussions.apple.com/thread/7602542

@barakwei
Copy link
Contributor Author

From what I see, Xcode sorts like Finder. If you want to sort like finder you can call [NSString localizedStandardCompare:]. If we look at the source we can see which flags it uses.
You can see the sort is case insensitive and you can add that to the tests, and it also uses the current locale which makes things worse. In addition, it uses NSWidthInsensitiveSearch which affects Unicode characters which might explain what you see.

@Coeur
Copy link
Contributor

Coeur commented May 15, 2019

I figured that. But solving the unicode sort may require activesupport, with either transliterate or mb_chars.normalize(:kd).

@Coeur
Copy link
Contributor

Coeur commented May 15, 2019

And also, I just found that Xcode lists duplicate references at the end of everything else... that's yet another edge case that would need extra code to solve.

@Coeur
Copy link
Contributor

Coeur commented May 15, 2019

In the mean time, the problem with the dots should now be solved in the PR. And for any new case that we may discover, it'll be worth checking if it's a regression compared to the plain sort algorithm or just some feature-request. As you said in your original post: "fixing the most simple case is sufficient".

@barakwei
Copy link
Contributor Author

Looks like the latest code works on my use cases. Note that I provide the strings directly to the class and I do not separate the base name and extension, I guess the PR should do this as well.

Yes, I agree that the most important things are punctuations, numbers, spaces, and letters. If solving Unicode will be more complex, it can be done by demand as you say.
Also, the default behavior of the sort method doesn't have to change, you can provide a comparator and provide it to the sort method, which by default will not be used. That way existing users won't suffer any performance issues if there are any. It's up to the maintainers of the repo to decide.

Lastly, I want to thank you for taking the time to implement this feature. I'll surely use it.

@Coeur
Copy link
Contributor

Coeur commented May 16, 2019

I've just found out that Xcode sorting is broken (unpredictable, weak, not strict) and I've opened a radar regarding it: http://www.openradar.me/radar?id=5012044621283328

So it's currently undesirable to follow exactly Xcode sorting on some edge cases (a strong strict total sorting is preferable, unless there is a big performance hit for that).

Coeur added a commit to Coeur/Xcodeproj that referenced this issue May 16, 2019
Coeur added a commit to Coeur/Xcodeproj that referenced this issue May 16, 2019
@barakwei barakwei closed this as not planned Won't fix, can't repro, duplicate, stale Jun 19, 2022
Coeur added a commit to Coeur/Xcodeproj that referenced this issue Oct 4, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants