diff --git a/CodeEdit/Utils/Extensions/Array/Array+SortURLs.swift b/CodeEdit/Utils/Extensions/Array/Array+SortURLs.swift index 45b97437d..fb31a4c55 100644 --- a/CodeEdit/Utils/Extensions/Array/Array+SortURLs.swift +++ b/CodeEdit/Utils/Extensions/Array/Array+SortURLs.swift @@ -18,19 +18,39 @@ extension Array where Element == URL { /// Sorts the elements in alphabetical order. /// - Parameter foldersOnTop: if set to `true` folders will always be on top of files. /// - Returns: A sorted array of `URL` - func sortItems(foldersOnTop: Bool) -> Self { - var alphabetically = sorted { $0.lastPathComponent < $1.lastPathComponent } + func sortItems(foldersOnTop: Bool) -> [URL] { + return self.sorted { lhs, rhs in + let lhsIsDir = (try? lhs.resourceValues(forKeys: [.isDirectoryKey]).isDirectory) ?? false + let rhsIsDir = (try? rhs.resourceValues(forKeys: [.isDirectoryKey]).isDirectory) ?? false - if foldersOnTop { - var foldersOnTop = alphabetically.filter { $0.isFolder } - alphabetically.removeAll { $0.isFolder } + if foldersOnTop { + if lhsIsDir != rhsIsDir { + return lhsIsDir + } + } - foldersOnTop.append(contentsOf: alphabetically) + return compareNaturally(lhs.lastPathComponent, rhs.lastPathComponent) + } + } - return foldersOnTop - } else { - return alphabetically + /// Compare two strings using natural sorting. + /// - Parameters: + /// - lhs: The left-hand string. + /// - rhs: The right-hand string. + /// - Returns: `true` if `lhs` should be ordered before `rhs`. + private func compareNaturally(_ lhs: String, _ rhs: String) -> Bool { + let lhsComponents = lhs.components(separatedBy: CharacterSet.decimalDigits.inverted) + let rhsComponents = rhs.components(separatedBy: CharacterSet.decimalDigits.inverted) + + for (lhsPart, rhsPart) in zip(lhsComponents, rhsComponents) where lhsPart != rhsPart { + if let lhsNum = Int(lhsPart), let rhsNum = Int(rhsPart) { + return lhsNum < rhsNum + } else { + return lhsPart < rhsPart + } } + + return lhs < rhs } }