Files
ghostgram/submodules/TextFormat/Sources/InstantPageSyntaxHighlightSpecs.swift
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

61 lines
2.5 KiB
Swift

import Foundation
import TelegramCore
/// A code block's language, trimmed and lowercased, or nil when it carries none usable. Both the spec
/// extractor and every apply site must run a language through THIS before keying the cache, or a page
/// whose language is "Swift" stores under "swift" and looks up under "Swift" and never hits.
public func normalizedCodeBlockLanguage(_ language: String?) -> String? {
guard let language else {
return nil
}
let normalized = language.trimmingCharacters(in: .whitespacesAndNewlines).lowercased()
return normalized.isEmpty ? nil : normalized
}
/// Every distinct (language, code) pair in a page, in document order, for the syntax-highlight cache.
/// Recurses every block that nests blocks — INCLUDING `blockQuote`, which the private BrowserUI copy this
/// replaces did not, so code inside a quote was highlighted nowhere. `pullQuote` carries `RichText` rather
/// than blocks, so it correctly stays in `default`.
public func instantPageSyntaxHighlightSpecs(for blocks: [InstantPageBlock]) -> [CachedMessageSyntaxHighlight.Spec] {
var specs: [CachedMessageSyntaxHighlight.Spec] = []
var seen = Set<CachedMessageSyntaxHighlight.Spec>()
func collect(blocks: [InstantPageBlock]) {
for block in blocks {
switch block {
case let .preformatted(text, language):
guard let language = normalizedCodeBlockLanguage(language), !text.plainText.isEmpty else {
continue
}
let spec = CachedMessageSyntaxHighlight.Spec(language: language, text: text.plainText)
if seen.insert(spec).inserted {
specs.append(spec)
}
case let .cover(block):
collect(blocks: [block])
case let .postEmbed(_, _, _, _, _, blocks, _):
collect(blocks: blocks)
case let .collage(items, _):
collect(blocks: items)
case let .slideshow(items, _):
collect(blocks: items)
case let .details(_, blocks, _):
collect(blocks: blocks)
case let .list(items, _):
for item in items {
if case let .blocks(blocks, _, _) = item {
collect(blocks: blocks)
}
}
case let .blockQuote(blocks, _, _):
collect(blocks: blocks)
default:
break
}
}
}
collect(blocks: blocks)
return specs
}