Files
ichmagmaus111andClaude Opus 5.5 0622057a4f Ghostgram: open-source release
Ghostgram for iOS, rebuilt from scratch on Telegram iOS 13.0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 17:57:09 +01:00

68 lines
2.2 KiB
Swift

import Foundation
import TelegramCore
import RichTextEditorCore
/// Map a single text run to inline `RichText`, applying its character attributes as nested wrappers.
func richText(from run: TextRun) -> RichText? {
let attributes = run.attributes
var result: RichText
// FIRST, before every other leaf: a button run's text is a bare `U+FFFC`, so without this arm it
// falls through to `.plain(run.text)` and the pill is emitted as an invisible placeholder. This is
// an if-let chain, not an exhaustive switch, so the compiler cannot catch a missing arm here.
if let button = attributes.button {
result = .textButton(InstantPageButton(
text: richText(from: button.label),
action: replyMarkupButtonAction(from: button.action),
color: replyMarkupColor(from: button.color),
isLink: button.isLink
))
} else if let formula = attributes.formula {
result = .formula(latex: formula)
} else if let emoji = attributes.emoji {
// v1: custom emoji has no backing file here — emit its alt text as plain text.
let alt = emoji.altText ?? ""
if alt.isEmpty {
return nil
}
result = .plain(alt)
} else if run.text.isEmpty {
return nil
} else {
result = .plain(run.text)
}
if attributes.inlineCode {
result = .fixed(result)
}
if attributes.strikethrough {
result = .strikethrough(result)
}
if attributes.underline {
result = .underline(result)
}
if attributes.italic {
result = .italic(result)
}
if attributes.bold {
result = .bold(result)
}
if attributes.highlight != nil {
result = .marked(result)
}
if let link = attributes.link {
result = .url(text: result, url: link, webpageId: nil)
}
return result
}
/// Map a run array to one `RichText` (`.concat` when multiple, `.empty` when none).
func richText(from runs: [TextRun]) -> RichText {
let parts = runs.compactMap(richText(from:))
if parts.isEmpty {
return .empty
}
if parts.count == 1 {
return parts[0]
}
return .concat(parts)
}