this repo has no description
at pr14-status-view 101 lines 4.3 kB view raw
1import Foundation 2 3public enum UsageFormatter { 4 public static func usageLine(remaining: Double, used: Double) -> String { 5 String(format: "%.0f%% left", remaining) 6 } 7 8 public static func resetDescription(from date: Date, now: Date = .init()) -> String { 9 // Human-friendly phrasing: today / tomorrow / date+time. 10 let calendar = Calendar.current 11 if calendar.isDate(date, inSameDayAs: now) { 12 return date.formatted(date: .omitted, time: .shortened) 13 } 14 if let tomorrow = calendar.date(byAdding: .day, value: 1, to: now), 15 calendar.isDate(date, inSameDayAs: tomorrow) 16 { 17 return "tomorrow, \(date.formatted(date: .omitted, time: .shortened))" 18 } 19 return date.formatted(date: .abbreviated, time: .shortened) 20 } 21 22 public static func updatedString(from date: Date, now: Date = .init()) -> String { 23 let delta = now.timeIntervalSince(date) 24 if abs(delta) < 60 { 25 return "Updated just now" 26 } 27 if let hours = Calendar.current.dateComponents([.hour], from: date, to: now).hour, hours < 24 { 28 let rel = RelativeDateTimeFormatter() 29 rel.unitsStyle = .abbreviated 30 return "Updated \(rel.localizedString(for: date, relativeTo: now))" 31 } else { 32 return "Updated \(date.formatted(date: .omitted, time: .shortened))" 33 } 34 } 35 36 public static func creditsString(from value: Double) -> String { 37 let number = NumberFormatter() 38 number.numberStyle = .decimal 39 number.maximumFractionDigits = 2 40 let formatted = number.string(from: NSNumber(value: value)) ?? String(Int(value)) 41 return "\(formatted) left" 42 } 43 44 public static func creditEventSummary(_ event: CreditEvent) -> String { 45 let formatter = DateFormatter() 46 formatter.dateStyle = .medium 47 let number = NumberFormatter() 48 number.numberStyle = .decimal 49 number.maximumFractionDigits = 2 50 let credits = number.string(from: NSNumber(value: event.creditsUsed)) ?? "0" 51 return "\(formatter.string(from: event.date)) · \(event.service) · \(credits) credits" 52 } 53 54 public static func creditEventCompact(_ event: CreditEvent) -> String { 55 let formatter = DateFormatter() 56 formatter.dateFormat = "MMM d" 57 let number = NumberFormatter() 58 number.numberStyle = .decimal 59 number.maximumFractionDigits = 2 60 let credits = number.string(from: NSNumber(value: event.creditsUsed)) ?? "0" 61 return "\(formatter.string(from: event.date))\(event.service): \(credits)" 62 } 63 64 public static func creditShort(_ value: Double) -> String { 65 if value >= 1000 { 66 let k = value / 1000 67 return String(format: "%.1fk", k) 68 } 69 return String(format: "%.0f", value) 70 } 71 72 public static func truncatedSingleLine(_ text: String, max: Int = 80) -> String { 73 let single = text 74 .replacingOccurrences(of: "\n", with: " ") 75 .trimmingCharacters(in: .whitespacesAndNewlines) 76 guard single.count > max else { return single } 77 let idx = single.index(single.startIndex, offsetBy: max) 78 return "\(single[..<idx])" 79 } 80 81 /// Cleans a provider plan string: strip ANSI/bracket noise, drop boilerplate words, collapse whitespace, and 82 /// ensure a leading capital if the result starts lowercase. 83 public static func cleanPlanName(_ text: String) -> String { 84 let stripped = TextParsing.stripANSICodes(text) 85 let withoutCodes = stripped.replacingOccurrences( 86 of: #"^\s*(?:\[\d{1,3}m\s*)+"#, 87 with: "", 88 options: [.regularExpression]) 89 let withoutBoilerplate = withoutCodes.replacingOccurrences( 90 of: #"(?i)\b(claude|codex|account|plan)\b"#, 91 with: "", 92 options: [.regularExpression]) 93 var cleaned = withoutBoilerplate 94 .replacingOccurrences(of: #"\s+"#, with: " ", options: .regularExpression) 95 .trimmingCharacters(in: .whitespacesAndNewlines) 96 if cleaned.isEmpty { 97 cleaned = stripped.trimmingCharacters(in: .whitespacesAndNewlines) 98 } 99 return cleaned.capitalized 100 } 101}