41 lines
1.7 KiB
Swift
41 lines
1.7 KiB
Swift
import MarkdownUI
|
|
import SwiftUI
|
|
|
|
/// Both roles and both workspaces use normal chat's readable, Dynamic Type-aware theme.
|
|
/// Literal input is built from text nodes, never passed through the Markdown parser.
|
|
struct SybilMessageText: View {
|
|
enum Format { case literal, markdown }
|
|
var content: String
|
|
var format: Format
|
|
var agentStyle = false
|
|
|
|
static func literalContent(_ text: String) -> MarkdownContent {
|
|
// Pasted CRLF/CR and blank lines containing spaces or tabs have the same
|
|
// paragraph boundaries as Markdown. Keep the newline count so deliberate
|
|
// extra blank lines survive; nonblank lines and Markdown syntax stay literal.
|
|
let normalized = text.replacingOccurrences(of: "\r\n", with: "\n")
|
|
.replacingOccurrences(of: "\r", with: "\n")
|
|
.components(separatedBy: "\n")
|
|
.map { line in line.allSatisfy { $0 == " " || $0 == "\t" } ? "" : line }
|
|
.joined(separator: "\n")
|
|
return MarkdownContent {
|
|
for paragraph in normalized.components(separatedBy: "\n\n") {
|
|
Paragraph {
|
|
// Keep extra blank paragraphs visible, including leading/trailing ones.
|
|
paragraph.isEmpty ? "\u{00a0}" : paragraph
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
var body: some View {
|
|
#if DEBUG
|
|
let _ = AgentRenderDiagnostics.record("messageTextBuild")
|
|
#endif
|
|
Markdown(format == .literal ? Self.literalContent(content) : agentStyle ? AgentMessageMarkdown.content(content) : MarkdownContent(content))
|
|
.tint(SybilTheme.primary)
|
|
.foregroundStyle(format == .literal ? SybilTheme.text : SybilTheme.text.opacity(0.95))
|
|
.markdownTheme(.sybilReadable)
|
|
}
|
|
}
|