import Foundation /// What `mr list` is narrowed to. The command takes no `--assignee`, so /// this offers none. nonisolated struct MRFilter: Equatable, Sendable { enum State: String, CaseIterable, Identifiable, Sendable { case open, merged, closed case sourceGone = "source_gone" case all var id: String { rawValue } var label: String { stateLabel(rawValue) } } var state: State = .open var search = "" var label: String? var author: String? var milestone: String? func flags() -> [String] { var flags = ["--state", state.rawValue] flags += filterFlag("--search", search) flags += filterFlag("--label", label) flags += filterFlag("--author", author) flags += filterFlag("--milestone", milestone) return flags } var isNarrowed: Bool { flags().count > 2 } var emptyMessage: String { let noun = "merge requests" if isNarrowed { return state == .all ? "No \(noun) match these filters." : "No \(state.label.lowercased()) \(noun) match these filters." } return state == .all ? "No \(noun)." : "No \(state.label.lowercased()) \(noun)." } } /// A wire state (`open`, `source_gone`) as the app shows it: sentence /// case, underscores as spaces. nonisolated func stateLabel(_ state: String) -> String { let words = state.replacingOccurrences(of: "_", with: " ") return words.prefix(1).uppercased() + words.dropFirst() }