mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-02 21:33:26 +00:00
Fix inline code being rendered as blocks. (#5017)
* Fix inline code being rendered as blocks. And make blocks non-greedy as well as only scrolling when needed. * Rename the bubble layout priorities. * Add an InlineCode attribute so that the builder also strips links from these too. * Split up the snapshot tests into individual cases. This should make it much easier to see *what* has changed when regenerating.
This commit is contained in:
@@ -32,6 +32,7 @@ extension NSAttributedString.Key {
|
||||
static let MatrixEventOnRoomAlias: NSAttributedString.Key = .init(rawValue: EventOnRoomAliasAttribute.name)
|
||||
static let MatrixAllUsersMention: NSAttributedString.Key = .init(rawValue: AllUsersMentionAttribute.name)
|
||||
static let CodeBlock: NSAttributedString.Key = .init(rawValue: CodeBlockAttribute.name)
|
||||
static let InlineCode: NSAttributedString.Key = .init(rawValue: InlineCodeAttribute.name)
|
||||
}
|
||||
|
||||
struct AttributedStringBuilder: AttributedStringBuilderProtocol {
|
||||
@@ -197,15 +198,24 @@ struct AttributedStringBuilder: AttributedStringBuilderProtocol {
|
||||
content.addAttribute(.MatrixBlockquote, value: true, range: NSRange(location: 0, length: content.length))
|
||||
|
||||
case "code", "pre":
|
||||
let preserveFormatting = preserveFormatting || tag == "pre"
|
||||
let isCodeBlock = tag == "pre"
|
||||
|
||||
let preserveFormatting = preserveFormatting || isCodeBlock
|
||||
content = attributedString(element: childElement, documentBody: documentBody, preserveFormatting: preserveFormatting, listTag: listTag, listIndex: &childIndex, indentLevel: indentLevel)
|
||||
|
||||
let fontPointSize = fontPointSize * 0.9 // Intentionally shrink code blocks by 10%
|
||||
content.setFontPreservingSymbolicTraits(UIFont.monospacedSystemFont(ofSize: fontPointSize, weight: .regular))
|
||||
|
||||
content.addAttribute(.CodeBlock, value: true, range: NSRange(location: 0, length: content.length))
|
||||
if isCodeBlock {
|
||||
content.addAttribute(.CodeBlock, value: true, range: NSRange(location: 0, length: content.length))
|
||||
// The scroll view provides the background colour for code blocks.
|
||||
} else {
|
||||
content.addAttribute(.InlineCode, value: true, range: NSRange(location: 0, length: content.length))
|
||||
// But inline code is (obviously) inline so it's much easier to set the background colour here.
|
||||
content.addAttribute(.backgroundColor, value: UIColor.compound._bgCodeBlock as Any, range: NSRange(location: 0, length: content.length))
|
||||
}
|
||||
|
||||
// Don't allow identifiers or links in code blocks
|
||||
// Don't allow identifiers or links in code.
|
||||
content.removeAttribute(.MatrixRoomID, range: NSRange(location: 0, length: content.length))
|
||||
content.removeAttribute(.MatrixRoomAlias, range: NSRange(location: 0, length: content.length))
|
||||
content.removeAttribute(.MatrixUserID, range: NSRange(location: 0, length: content.length))
|
||||
@@ -353,14 +363,15 @@ struct AttributedStringBuilder: AttributedStringBuilderProtocol {
|
||||
// Sort the links by length so the longest one always takes priority
|
||||
matches.sorted { $0.range.length > $1.range.length }.forEach { [attributedString] match in
|
||||
// Don't highlight links within codeblocks
|
||||
let isInCodeBlock = attributedString.attribute(.CodeBlock, at: match.range.location, effectiveRange: nil) != nil
|
||||
if isInCodeBlock {
|
||||
let isCode = attributedString.attribute(.CodeBlock, at: match.range.location, effectiveRange: nil) != nil
|
||||
|| attributedString.attribute(.InlineCode, at: match.range.location, effectiveRange: nil) != nil
|
||||
if isCode {
|
||||
return
|
||||
}
|
||||
|
||||
var hasLink = false
|
||||
attributedString.enumerateAttribute(.link, in: match.range, options: []) { value, _, stop in
|
||||
if value != nil, !isInCodeBlock {
|
||||
if value != nil, !isCode {
|
||||
hasLink = true
|
||||
stop.pointee = true
|
||||
}
|
||||
|
||||
@@ -68,6 +68,11 @@ enum CodeBlockAttribute: AttributedStringKey {
|
||||
static let name = "MXCodeBlockAttribute"
|
||||
}
|
||||
|
||||
enum InlineCodeAttribute: AttributedStringKey {
|
||||
typealias Value = Bool
|
||||
static let name = "MXInlineCodeAttribute"
|
||||
}
|
||||
|
||||
// periphery: ignore - required to make NSAttributedString to AttributedString conversion even if not used directly
|
||||
extension AttributeScopes {
|
||||
struct ElementXAttributes: AttributeScope {
|
||||
@@ -84,6 +89,7 @@ extension AttributeScopes {
|
||||
let allUsersMention: AllUsersMentionAttribute
|
||||
|
||||
let codeBlock: CodeBlockAttribute
|
||||
let inlineCode: InlineCodeAttribute
|
||||
|
||||
let swiftUI: SwiftUIAttributes
|
||||
let uiKit: UIKitAttributes
|
||||
|
||||
@@ -15,7 +15,8 @@ enum HTMLFixtures: String, CaseIterable {
|
||||
case textFormatting
|
||||
case groupedBlockQuotes
|
||||
case separatedBlockQuotes
|
||||
case codeBlocks
|
||||
case code
|
||||
case wideCodeBlock
|
||||
case unorderedList
|
||||
case orderedList
|
||||
|
||||
@@ -74,9 +75,9 @@ enum HTMLFixtures: String, CaseIterable {
|
||||
<blockquote>Some other blockquote</blockquote>\
|
||||
Text after second blockquote
|
||||
"""
|
||||
case .codeBlocks:
|
||||
case .code:
|
||||
"""
|
||||
<pre>A preformatted code block
|
||||
<pre>A pre-formatted code block
|
||||
<code>struct ContentView: View {
|
||||
var body: some View {
|
||||
VStack {
|
||||
@@ -88,11 +89,17 @@ enum HTMLFixtures: String, CaseIterable {
|
||||
.padding()
|
||||
}
|
||||
}</code></pre></br>
|
||||
Followed by some plain code blocks</br>
|
||||
<code>Hello, world!</code>
|
||||
<code><b>Hello</b>, <i>world!</i></code>
|
||||
<code><a href="https://www.matrix.org">This link should not be interpreted as such</a></code>
|
||||
<code>And this https://www.matrix.org should be not highlighted</code>
|
||||
Followed by some inline code</br>
|
||||
<p>Plain text <code>code here</code> more text</p>
|
||||
<p><code>Hello, world!</code></p>
|
||||
<p><code><b>Hello</b>, <i>world!</i></code></p>
|
||||
<p><code><b>Hello</b>, <i>world!</i></code></p>
|
||||
<p><code><a href="https://www.matrix.org">This link should not be interpreted as such</a></code></p>
|
||||
<p><code>And this https://www.matrix.org should be not highlighted</code></p>
|
||||
"""
|
||||
case .wideCodeBlock:
|
||||
"""
|
||||
<pre><code>CHHapticPattern.mm:487 +[CHHapticPattern patternForKey:error:]: Failed to read pattern library data: Error Domain=NSCocoaErrorDomain Code=260 "The file “hapticpatternlibrary.plist” couldn’t be opened because there is no such file." UserInfo={NSFilePath=/Library/Audio/Tunings/Generic/Haptics/Library/hapticpatternlibrary.plist, NSURL=file:///Library/Audio/Tunings/Generic/Haptics/Library/hapticpatternlibrary.plist, NSUnderlyingError=0x600000da69d0 {Error Domain=NSPOSIXErrorDomain Code=2 "No such file or directory"}}</code></pre>
|
||||
"""
|
||||
case .unorderedList:
|
||||
"""
|
||||
|
||||
Reference in New Issue
Block a user