Skip to content

Commit d6e7d43

Browse files
committed
fix: theme regression
1 parent 9ea8136 commit d6e7d43

2 files changed

Lines changed: 92 additions & 117 deletions

File tree

Sources/MarkdownView/Components/DiffView/DiffView.swift

Lines changed: 32 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -149,15 +149,24 @@ private func makeDiffAttributes(
149149
private func diffRowRect(
150150
index: Int,
151151
rowCount: Int,
152-
contentHeight: CGFloat,
153-
bounds: CGRect
152+
bounds: CGRect,
153+
theme: MarkdownTheme
154154
) -> CGRect {
155-
let lineHeight = contentHeight / CGFloat(max(rowCount, 1))
155+
#if canImport(UIKit)
156+
let lineHeight = theme.fonts.code.lineHeight
157+
#elseif canImport(AppKit)
158+
let font = theme.fonts.code
159+
let lineHeight = font.ascender + abs(font.descender) + font.leading
160+
#endif
161+
162+
let lineSpacing = CodeViewConfiguration.codeLineSpacing
163+
let rowAdvance = lineHeight + lineSpacing
164+
let isLastRow = index == max(rowCount - 1, 0)
156165
return CGRect(
157166
x: bounds.minX,
158-
y: DiffViewConfiguration.verticalPadding + CGFloat(index) * lineHeight,
167+
y: DiffViewConfiguration.verticalPadding + CGFloat(index) * rowAdvance,
159168
width: bounds.width,
160-
height: lineHeight
169+
height: lineHeight + (isLastRow ? 0 : lineSpacing)
161170
)
162171
}
163172

@@ -264,12 +273,7 @@ private func unifiedContentRowBackgroundColor(
264273
for kind: DiffPresentation.UnifiedRow.Kind,
265274
theme: MarkdownTheme
266275
) -> PlatformColor? {
267-
switch kind {
268-
case .removed, .added:
269-
return nil
270-
case .fileHeader, .fileMetadata, .hunkHeader, .context, .annotation, .collapsedContext:
271-
return unifiedRowBackgroundColor(for: kind, theme: theme)
272-
}
276+
unifiedRowBackgroundColor(for: kind, theme: theme)
273277
}
274278

275279
private func unifiedEmphasisColor(
@@ -287,46 +291,6 @@ private func unifiedEmphasisColor(
287291
}
288292
}
289293

290-
private func unifiedLineBackgroundColor(
291-
for kind: DiffPresentation.UnifiedRow.Kind,
292-
theme: MarkdownTheme
293-
) -> PlatformColor? {
294-
guard showsLineChangeHighlights(in: theme) else { return nil }
295-
switch kind {
296-
case .removed:
297-
return theme.diff.removedLineBackground
298-
case .added:
299-
return theme.diff.addedLineBackground
300-
case .fileHeader, .fileMetadata, .hunkHeader, .context, .annotation, .collapsedContext:
301-
return nil
302-
}
303-
}
304-
305-
private func makeFullWidthLineBackgroundAction(
306-
color: PlatformColor
307-
) -> LTXLineDrawingAction {
308-
LTXLineDrawingAction { context, line, lineOrigin in
309-
var ascent: CGFloat = 0
310-
var descent: CGFloat = 0
311-
var leading: CGFloat = 0
312-
CTLineGetTypographicBounds(line, &ascent, &descent, &leading)
313-
314-
let lineSpacing = CodeViewConfiguration.codeLineSpacing
315-
let clipBounds = context.boundingBoxOfClipPath
316-
let rect = CGRect(
317-
x: clipBounds.minX,
318-
y: lineOrigin.y - descent - lineSpacing / 2,
319-
width: clipBounds.width,
320-
height: ascent + descent + leading + lineSpacing
321-
)
322-
323-
context.saveGState()
324-
context.setFillColor(color.cgColor)
325-
context.fill(rect)
326-
context.restoreGState()
327-
}
328-
}
329-
330294
private func sideBySideRowTextColor(
331295
for kind: DiffPresentation.SideBySideRow.Kind,
332296
theme: MarkdownTheme
@@ -633,16 +597,11 @@ private func makeUnifiedAttributedText(
633597

634598
for (index, row) in rows.enumerated() {
635599
let rowStart = result.length
636-
var attributes = makeDiffAttributes(
600+
let attributes = makeDiffAttributes(
637601
font: font,
638602
color: unifiedTextColor(for: row.kind, theme: theme),
639603
paragraphStyle: paragraphStyle
640604
)
641-
if let lineBackgroundColor = unifiedLineBackgroundColor(for: row.kind, theme: theme) {
642-
attributes[.ltxLineDrawingCallback] = makeFullWidthLineBackgroundAction(
643-
color: lineBackgroundColor
644-
)
645-
}
646605
result.append(.init(string: row.text, attributes: attributes))
647606

648607
let rowLength = row.text.utf16.count
@@ -1125,8 +1084,8 @@ private func makeSideBySideAttributedText(
11251084
let rect = diffRowRect(
11261085
index: index,
11271086
rowCount: rows.count,
1128-
contentHeight: contentHeight,
1129-
bounds: bounds
1087+
bounds: bounds,
1088+
theme: theme
11301089
)
11311090

11321091
if let fillColor = unifiedContentRowBackgroundColor(for: row.kind, theme: theme) {
@@ -1151,8 +1110,8 @@ private func makeSideBySideAttributedText(
11511110
let rect = diffRowRect(
11521111
index: index,
11531112
rowCount: rows.count,
1154-
contentHeight: contentHeight,
1155-
bounds: bounds
1113+
bounds: bounds,
1114+
theme: theme
11561115
)
11571116

11581117
switch row.kind {
@@ -1256,8 +1215,8 @@ private func makeSideBySideAttributedText(
12561215
let rect = diffRowRect(
12571216
index: index,
12581217
rowCount: rows.count,
1259-
contentHeight: contentHeight,
1260-
bounds: bounds
1218+
bounds: bounds,
1219+
theme: theme
12611220
)
12621221

12631222
if let fillColor = unifiedRowBackgroundColor(for: row.kind, theme: theme) {
@@ -1296,8 +1255,8 @@ private func makeSideBySideAttributedText(
12961255
let rect = diffRowRect(
12971256
index: index,
12981257
rowCount: rows.count,
1299-
contentHeight: contentHeight,
1300-
bounds: bounds
1258+
bounds: bounds,
1259+
theme: theme
13011260
)
13021261

13031262
let rowRects = diffGutterRowRects(for: metrics, rowRect: rect)
@@ -1814,8 +1773,8 @@ private func makeSideBySideAttributedText(
18141773
let rect = diffRowRect(
18151774
index: index,
18161775
rowCount: rows.count,
1817-
contentHeight: contentHeight,
1818-
bounds: bounds
1776+
bounds: bounds,
1777+
theme: theme
18191778
)
18201779

18211780
if let fillColor = unifiedContentRowBackgroundColor(for: row.kind, theme: theme) {
@@ -1840,8 +1799,8 @@ private func makeSideBySideAttributedText(
18401799
let rect = diffRowRect(
18411800
index: index,
18421801
rowCount: rows.count,
1843-
contentHeight: contentHeight,
1844-
bounds: bounds
1802+
bounds: bounds,
1803+
theme: theme
18451804
)
18461805

18471806
switch row.kind {
@@ -1938,8 +1897,8 @@ private func makeSideBySideAttributedText(
19381897
let rect = diffRowRect(
19391898
index: index,
19401899
rowCount: rows.count,
1941-
contentHeight: contentHeight,
1942-
bounds: bounds
1900+
bounds: bounds,
1901+
theme: theme
19431902
)
19441903

19451904
if let fillColor = unifiedRowBackgroundColor(for: row.kind, theme: theme) {
@@ -1978,8 +1937,8 @@ private func makeSideBySideAttributedText(
19781937
let rect = diffRowRect(
19791938
index: index,
19801939
rowCount: rows.count,
1981-
contentHeight: contentHeight,
1982-
bounds: bounds
1940+
bounds: bounds,
1941+
theme: theme
19831942
)
19841943

19851944
let rowRects = diffGutterRowRects(for: metrics, rowRect: rect)

Tests/MarkdownViewTests/DiffViewTests.swift

Lines changed: 60 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,32 @@ import XCTest
1010
final class DiffViewTests: XCTestCase {
1111

1212
private let parser = MarkdownParser()
13+
private let userProvidedMixedDiff = """
14+
```diff
15+
@@ -3,9 +3,12 @@ import { useState } from 'react';
16+
export default function App() {
17+
+ const [count, setCount] = useState<number>(0);
18+
+ const [name, setName] = useState<string>('');
19+
20+
return (
21+
<div>
22+
- <button onClick={() => setCount(count + 1)}>
23+
+ <input value={name} onChange={(e) => setName(e.target.value)} />
24+
+ <button onClick={() => setCount((prev) => prev + 1)}>
25+
Count: {count}
26+
</button>
27+
</div>
28+
```
29+
"""
30+
private let userProvidedSingleReplacementDiff = """
31+
```diff
32+
@@ -11,7 +11,7 @@ export default function Home() {
33+
<div>
34+
- <h2>Design Engineer</h2>
35+
+ <h2>Designer</h2>
36+
</div>
37+
```
38+
"""
1339

1440
func testPreprocessedContentBuildsDiffRenderBlock() {
1541
let content = makeContent(
@@ -1014,16 +1040,39 @@ final class DiffViewTests: XCTestCase {
10141040
XCTAssertEqual(MarkdownTheme.default.diff.changeHighlightStyle, .both)
10151041
}
10161042

1043+
func testUserProvidedMixedUnifiedDiffPreservesBlankContextAndChangedRows() {
1044+
let content = makeContent(from: userProvidedMixedDiff)
1045+
1046+
guard let renderBlock = content.diffRenderBlocks.values.first else {
1047+
return XCTFail("Expected diff render block")
1048+
}
1049+
1050+
XCTAssertEqual(renderBlock.rows.first?.kind, .hunkHeader)
1051+
XCTAssertTrue(renderBlock.rows.contains { $0.kind == .added && $0.text.contains("const [count, setCount]") })
1052+
XCTAssertTrue(renderBlock.rows.contains { $0.kind == .added && $0.text.contains("const [name, setName]") })
1053+
XCTAssertTrue(renderBlock.rows.contains { $0.kind == .removed && $0.text.contains("setCount(count + 1)") })
1054+
XCTAssertTrue(renderBlock.rows.contains { $0.kind == .added && $0.text.contains("setCount((prev) => prev + 1)") })
1055+
XCTAssertTrue(renderBlock.rows.contains { $0.kind == .added && $0.text.contains("<input value={name}") })
1056+
XCTAssertTrue(renderBlock.rows.contains { $0.kind == .context && $0.text.isEmpty })
1057+
}
1058+
1059+
func testUserProvidedSingleReplacementDiffBuildsExpectedRows() {
1060+
let content = makeContent(from: userProvidedSingleReplacementDiff)
1061+
1062+
guard let renderBlock = content.diffRenderBlocks.values.first else {
1063+
return XCTFail("Expected diff render block")
1064+
}
1065+
1066+
XCTAssertEqual(renderBlock.rows.count, 5)
1067+
XCTAssertEqual(renderBlock.rows[0].kind, .hunkHeader)
1068+
XCTAssertEqual(renderBlock.rows[1].kind, .context)
1069+
XCTAssertEqual(renderBlock.rows[2].kind, .removed)
1070+
XCTAssertEqual(renderBlock.rows[3].kind, .added)
1071+
XCTAssertEqual(renderBlock.rows[4].kind, .context)
1072+
}
1073+
10171074
func testDiffViewLineOnlyStyleSuppressesInlineBackgroundAttributes() {
1018-
let content = makeContent(
1019-
from: """
1020-
```diff swift
1021-
@@ -1 +1 @@
1022-
-let title = "Design Engineer"
1023-
+let title = "Designer"
1024-
```
1025-
"""
1026-
)
1075+
let content = makeContent(from: userProvidedSingleReplacementDiff)
10271076

10281077
guard let renderBlock = content.diffRenderBlocks.values.first else {
10291078
return XCTFail("Expected diff render block")
@@ -1044,20 +1093,11 @@ final class DiffViewTests: XCTestCase {
10441093
#endif
10451094

10461095
XCTAssertEqual(self.countBackgroundAttributes(in: view.textView.attributedText), 0)
1047-
XCTAssertGreaterThan(self.countLineDrawingCallbacks(in: view.textView.attributedText), 0)
10481096
}
10491097
}
10501098

10511099
func testDiffViewInlineOnlyStyleAppliesInlineBackgroundAttributes() {
1052-
let content = makeContent(
1053-
from: """
1054-
```diff swift
1055-
@@ -1 +1 @@
1056-
-let title = "Design Engineer"
1057-
+let title = "Designer"
1058-
```
1059-
"""
1060-
)
1100+
let content = makeContent(from: userProvidedSingleReplacementDiff)
10611101

10621102
guard let renderBlock = content.diffRenderBlocks.values.first else {
10631103
return XCTFail("Expected diff render block")
@@ -1078,20 +1118,11 @@ final class DiffViewTests: XCTestCase {
10781118
#endif
10791119

10801120
XCTAssertGreaterThan(self.countBackgroundAttributes(in: view.textView.attributedText), 0)
1081-
XCTAssertEqual(self.countLineDrawingCallbacks(in: view.textView.attributedText), 0)
10821121
}
10831122
}
10841123

10851124
func testDiffViewBothStyleRetainsInlineBackgroundAttributes() {
1086-
let content = makeContent(
1087-
from: """
1088-
```diff swift
1089-
@@ -1 +1 @@
1090-
-let title = "Design Engineer"
1091-
+let title = "Designer"
1092-
```
1093-
"""
1094-
)
1125+
let content = makeContent(from: userProvidedSingleReplacementDiff)
10951126

10961127
guard let renderBlock = content.diffRenderBlocks.values.first else {
10971128
return XCTFail("Expected diff render block")
@@ -1112,7 +1143,6 @@ final class DiffViewTests: XCTestCase {
11121143
#endif
11131144

11141145
XCTAssertGreaterThan(self.countBackgroundAttributes(in: view.textView.attributedText), 0)
1115-
XCTAssertGreaterThan(self.countLineDrawingCallbacks(in: view.textView.attributedText), 0)
11161146
}
11171147
}
11181148

@@ -1320,20 +1350,6 @@ final class DiffViewTests: XCTestCase {
13201350
return count
13211351
}
13221352

1323-
private func countLineDrawingCallbacks(in attributedString: NSAttributedString) -> Int {
1324-
var count = 0
1325-
attributedString.enumerateAttribute(
1326-
.ltxLineDrawingCallback,
1327-
in: NSRange(location: 0, length: attributedString.length),
1328-
options: []
1329-
) { value, _, _ in
1330-
if value != nil {
1331-
count += 1
1332-
}
1333-
}
1334-
return count
1335-
}
1336-
13371353
#if canImport(UIKit)
13381354
private func assertEqualColor(
13391355
_ lhs: UIColor?,

0 commit comments

Comments
 (0)