44 lines
1.6 KiB
Swift
44 lines
1.6 KiB
Swift
//
|
|
// Markdown.swift
|
|
// damus
|
|
//
|
|
// Created by Lionello Lunesu on 2022-12-28.
|
|
//
|
|
|
|
import Foundation
|
|
|
|
public struct Markdown {
|
|
private let detector = try! NSDataDetector(types: NSTextCheckingResult.CheckingType.link.rawValue)
|
|
|
|
/// Ensure the specified URL has a scheme by prepending "https://" if it's absent.
|
|
static func withScheme(_ url: any StringProtocol) -> any StringProtocol {
|
|
return url.contains("://") ? url : "https://" + url
|
|
}
|
|
|
|
public static func parse(content: String) -> AttributedString {
|
|
// Similar to the parsing in NoteContentView
|
|
let md_opts: AttributedString.MarkdownParsingOptions =
|
|
.init(interpretedSyntax: .inlineOnlyPreservingWhitespace)
|
|
|
|
if let txt = try? AttributedString(markdown: content, options: md_opts) {
|
|
return txt
|
|
} else {
|
|
return AttributedString(stringLiteral: content)
|
|
}
|
|
}
|
|
|
|
/// Process the input text and add markdown for any embedded URLs.
|
|
public func process(_ input: String) -> AttributedString {
|
|
let matches = detector.matches(in: input, options: [], range: NSRange(location: 0, length: input.utf16.count))
|
|
var output = input
|
|
// Start with the last match, because replacing the first would invalidate all subsequent indices
|
|
for match in matches.reversed() {
|
|
guard let range = Range(match.range, in: input) else { continue }
|
|
let url = input[range]
|
|
output.replaceSubrange(range, with: "[\(url)](\(Markdown.withScheme(url)))")
|
|
}
|
|
// TODO: escape unintentional markdown
|
|
return Markdown.parse(content: output)
|
|
}
|
|
}
|