import SwiftUI struct SearchSuggestionsView: View { private struct CachedTag { let original: Either let names: [String] } var items: [Either] @Binding var searchText: String private var lastSearchTag: String { String(searchText.split(separator: " ").last ?? "").lowercased() } private var cachedTags: [CachedTag] { items.map { item in switch item { case .left(let tag): return CachedTag(original: item, names: [tag.name.lowercased()]) case .right(let query): return CachedTag(original: item, names: query.tags.map { $0.lowercased() }) } } } private var filteredItems: [Either] { let matchCandidateTag = lastSearchTag let matchingTagsLimit = 50 guard !matchCandidateTag.isEmpty else { return [] } var seenTags = Set() var matchingTags: [Either] = [] matchingTags.reserveCapacity(matchingTagsLimit) for tag in cachedTags { if matchingTags.count >= matchingTagsLimit { break } for name in tag.names { if name.contains(matchCandidateTag), seenTags.insert(name).inserted { matchingTags.append(tag.original) break } } } return matchingTags } var body: some View { ForEach(filteredItems, id: \.self) { item in switch item { case .left(let tag): Button { if let range = searchText.range(of: lastSearchTag, options: .backwards) { searchText.replaceSubrange(range, with: tag.name) } } label: { Text(tag.name) } case .right(let query): Button { if let range = searchText.range(of: lastSearchTag, options: .backwards), let matchingTag = query.tags.first(where: { $0.lowercased().contains(lastSearchTag) }) { searchText.replaceSubrange(range, with: matchingTag) } } label: { if let matchingTag = query.tags.first(where: { $0.lowercased().contains(lastSearchTag) }) { Text(matchingTag) } else { Text(query.tags.first ?? "") } } } } } }