Restore HTMLString link parsing (#1347)

This commit is contained in:
Chris Kolbu 2023-04-02 00:47:12 +11:00 committed by GitHub
parent 00ee8c2373
commit db81486f14
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -3,7 +3,7 @@ import SwiftSoup
import SwiftUI import SwiftUI
private enum CodingKeys: CodingKey { private enum CodingKeys: CodingKey {
case htmlValue, asMarkdown, asRawText, statusesURLs case htmlValue, asMarkdown, asRawText, statusesURLs, links
} }
public struct HTMLString: Codable, Equatable, Hashable, @unchecked Sendable { public struct HTMLString: Codable, Equatable, Hashable, @unchecked Sendable {
@ -11,7 +11,7 @@ public struct HTMLString: Codable, Equatable, Hashable, @unchecked Sendable {
public var asMarkdown: String = "" public var asMarkdown: String = ""
public var asRawText: String = "" public var asRawText: String = ""
public var statusesURLs = [URL]() public var statusesURLs = [URL]()
public var links = [Link]() private(set) public var links = [Link]()
public var asSafeMarkdownAttributedString: AttributedString = .init() public var asSafeMarkdownAttributedString: AttributedString = .init()
private var main_regex: NSRegularExpression? private var main_regex: NSRegularExpression?
@ -29,6 +29,7 @@ public struct HTMLString: Codable, Equatable, Hashable, @unchecked Sendable {
asMarkdown = try container.decode(String.self, forKey: .asMarkdown) asMarkdown = try container.decode(String.self, forKey: .asMarkdown)
asRawText = try container.decode(String.self, forKey: .asRawText) asRawText = try container.decode(String.self, forKey: .asRawText)
statusesURLs = try container.decode([URL].self, forKey: .statusesURLs) statusesURLs = try container.decode([URL].self, forKey: .statusesURLs)
links = try container.decode([Link].self, forKey: .links)
} catch { } catch {
htmlValue = "" htmlValue = ""
} }
@ -76,20 +77,6 @@ public struct HTMLString: Codable, Equatable, Hashable, @unchecked Sendable {
} catch { } catch {
asSafeMarkdownAttributedString = AttributedString(stringLiteral: htmlValue) asSafeMarkdownAttributedString = AttributedString(stringLiteral: htmlValue)
} }
/// This somehow crash in some cases.
/// Disabling for now
/// Could be related to this: https://github.com/apple/swift/issues/61532
/*
links = asSafeMarkdownAttributedString.runs
.compactMap { run in
guard let link = run.link else {
return nil
}
return Link(link, displayString: String(self.asSafeMarkdownAttributedString[run.range].characters))
}
*/
} }
public init(stringValue: String, parseMarkdown: Bool = false) { public init(stringValue: String, parseMarkdown: Bool = false) {
@ -109,17 +96,6 @@ public struct HTMLString: Codable, Equatable, Hashable, @unchecked Sendable {
} else { } else {
asSafeMarkdownAttributedString = AttributedString(stringLiteral: htmlValue) asSafeMarkdownAttributedString = AttributedString(stringLiteral: htmlValue)
} }
/*
links = asSafeMarkdownAttributedString.runs
.compactMap { run in
guard let link = run.link else {
return nil
}
return Link(link, displayString: String(self.asSafeMarkdownAttributedString[run.range].characters))
}
*/
} }
public func encode(to encoder: Encoder) throws { public func encode(to encoder: Encoder) throws {
@ -128,6 +104,7 @@ public struct HTMLString: Codable, Equatable, Hashable, @unchecked Sendable {
try container.encode(asMarkdown, forKey: .asMarkdown) try container.encode(asMarkdown, forKey: .asMarkdown)
try container.encode(asRawText, forKey: .asRawText) try container.encode(asRawText, forKey: .asRawText)
try container.encode(statusesURLs, forKey: .statusesURLs) try container.encode(statusesURLs, forKey: .statusesURLs)
try container.encode(links, forKey: .links)
} }
private mutating func handleNode(node: SwiftSoup.Node) { private mutating func handleNode(node: SwiftSoup.Node) {
@ -167,14 +144,21 @@ public struct HTMLString: Codable, Equatable, Hashable, @unchecked Sendable {
} }
} }
asMarkdown += "[" asMarkdown += "["
let start = asMarkdown.endIndex
// descend into this node now so we can wrap the // descend into this node now so we can wrap the
// inner part of the link in the right markup // inner part of the link in the right markup
for nn in node.getChildNodes() { for nn in node.getChildNodes() {
handleNode(node: nn) handleNode(node: nn)
} }
let finish = asMarkdown.endIndex
asMarkdown += "](" asMarkdown += "]("
asMarkdown += href asMarkdown += href
asMarkdown += ")" asMarkdown += ")"
if let url = URL(string: href) {
let displayString = asMarkdown[start..<finish]
links.append(Link(url, displayString: String(displayString)))
}
return return
} else if node.nodeName() == "#text" { } else if node.nodeName() == "#text" {
var txt = node.description var txt = node.description
@ -194,14 +178,14 @@ public struct HTMLString: Codable, Equatable, Hashable, @unchecked Sendable {
} catch {} } catch {}
} }
public struct Link: Hashable, Identifiable { public struct Link: Codable, Hashable, Identifiable {
public var id: Int { hashValue } public var id: Int { hashValue }
public let url: AttributeScopes.FoundationAttributes.LinkAttribute.Value public let url: URL
public let displayString: String public let displayString: String
public let type: LinkType public let type: LinkType
public let title: String public let title: String
init(_ url: AttributeScopes.FoundationAttributes.LinkAttribute.Value, displayString: String) { init(_ url: URL, displayString: String) {
self.url = url self.url = url
self.displayString = displayString self.displayString = displayString
@ -222,7 +206,7 @@ public struct HTMLString: Codable, Equatable, Hashable, @unchecked Sendable {
} }
} }
public enum LinkType { public enum LinkType: String, Codable {
case url case url
case mention case mention
case hashtag case hashtag