krz/hutch

an ios client for sourcehut

clone: git clone https://gitbay.org/krz/hutch.git

v2: Hutch/App/DeepLink.swift · raw

 1import Foundation
 2
 3/// Represents a parsed `hutch://` deep link.
 4enum DeepLink: Equatable {
 5    /// hutch://git/<owner>/<repo>
 6    case repository(owner: String, repo: String)
 7    /// hutch://todo/<owner>/<tracker>/<ticketId>
 8    case ticket(owner: String, tracker: String, ticketId: Int)
 9    /// hutch://builds/<jobId>
10    case build(jobId: Int)
11
12    /// Attempt to parse a URL into a DeepLink.
13    /// Expected format: hutch://<path>
14    init?(url: URL) {
15        guard url.scheme == "hutch" else { return nil }
16
17        // url.host gives the first path component for opaque URLs;
18        // use standardized path components from the full string.
19        let components = url.pathComponents(fromScheme: "hutch")
20
21        switch components.first {
22        case "git" where components.count >= 3:
23            let owner = components[1]
24            let repo = components[2]
25            self = .repository(owner: owner, repo: repo)
26
27        case "todo" where components.count >= 4:
28            let owner = components[1]
29            let tracker = components[2]
30            guard let ticketId = Int(components[3]) else { return nil }
31            self = .ticket(owner: owner, tracker: tracker, ticketId: ticketId)
32
33        case "builds" where components.count >= 2:
34            guard let jobId = Int(components[1]) else { return nil }
35            self = .build(jobId: jobId)
36
37        default:
38            return nil
39        }
40    }
41}
42
43private extension URL {
44    /// Parse path components from a custom-scheme URL.
45    /// For `hutch://git/~user/repo`, returns `["git", "~user", "repo"]`.
46    func pathComponents(fromScheme scheme: String) -> [String] {
47        // Remove scheme prefix and split by "/"
48        var str = absoluteString
49        if str.hasPrefix("\(scheme)://") {
50            str = String(str.dropFirst("\(scheme)://".count))
51        }
52        return str.split(separator: "/").map(String.init)
53    }
54}