Skip to content

Commit a0fc8ab

Browse files
graycreateclaude
andcommitted
fix: address Copilot review comments for HTML tag support
- Preserve <u> HTML tags for underline instead of converting to _text_ to avoid conflict with italic styling - Preserve <sup>/<sub> HTML tags for superscript/subscript instead of ^/~ markers to avoid conflicts with regular text - Use regex pattern for table separator detection to avoid false positives when cell content contains "---" - Escape pipe characters in table cells to prevent markdown table structure breakage - Remove unused headerRowCount variable and related code - Update tests to reflect new behavior - Add test for pipe escaping in table cells 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
1 parent c8b1c9d commit a0fc8ab

File tree

3 files changed

+24
-18
lines changed

3 files changed

+24
-18
lines changed

V2er/Sources/RichView/Converters/HTMLToMarkdownConverter.swift

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -190,19 +190,19 @@ public class HTMLToMarkdownConverter {
190190
let content = try convertElement(childElement)
191191
result += "~~\(content)~~"
192192

193-
// Underline - no standard markdown, render as emphasized text
193+
// Underline - no standard markdown, preserve as HTML for custom renderer
194194
case "u", "ins":
195195
let content = try convertElement(childElement)
196-
result += "_\(content)_"
196+
result += "<u>\(content)</u>"
197197

198-
// Superscript/subscript - render with markers
198+
// Superscript/subscript - preserve as HTML for custom renderer
199199
case "sup":
200200
let content = try convertElement(childElement)
201-
result += "^\(content)"
201+
result += "<sup>\(content)</sup>"
202202

203203
case "sub":
204204
let content = try convertElement(childElement)
205-
result += "~\(content)"
205+
result += "<sub>\(content)</sub>"
206206

207207
// Mark/highlight - render with markers
208208
case "mark":
@@ -325,33 +325,27 @@ public class HTMLToMarkdownConverter {
325325
private func convertTable(_ element: Element) throws -> String {
326326
var result = "\n"
327327
var rows: [[String]] = []
328-
var headerRowCount = 0
329328

330329
// Get all rows from thead and tbody
331330
let allRows = try element.select("tr")
332331

333332
for row in allRows {
334333
var cells: [String] = []
335-
let thCells = try row.select("th")
336-
let isHeaderRow = row.parent()?.tagName().lowercased() == "thead"
337-
|| !thCells.isEmpty()
338334

339335
// Get th and td cells
340336
for cell in row.children() {
341337
let tagName = cell.tagName().lowercased()
342338
if tagName == "th" || tagName == "td" {
343339
let content = try convertElement(cell)
344340
.replacingOccurrences(of: "\n", with: " ")
341+
.replacingOccurrences(of: "|", with: "\\|") // Escape pipes for Markdown tables
345342
.trimmingCharacters(in: .whitespaces)
346343
cells.append(content)
347344
}
348345
}
349346

350347
if !cells.isEmpty {
351348
rows.append(cells)
352-
if isHeaderRow && headerRowCount == 0 {
353-
headerRowCount = 1
354-
}
355349
}
356350
}
357351

V2er/Sources/RichView/Renderers/MarkdownRenderer.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -384,8 +384,8 @@ public class MarkdownRenderer {
384384
break
385385
}
386386

387-
// Skip separator row (| --- | --- |)
388-
if line.contains("---") {
387+
// Skip separator row (| --- | --- | or with colons for alignment)
388+
if line.range(of: #"^\|\s*(:?-+:?)\s*(\|\s*(:?-+:?)\s*)*\|$"#, options: .regularExpression) != nil {
389389
index += 1
390390
continue
391391
}

V2erTests/RichView/HTMLToMarkdownConverterTests.swift

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,18 @@ class HTMLToMarkdownConverterTests: XCTestCase {
274274
XCTAssertTrue(markdown.contains("数据同步"))
275275
}
276276

277+
func testTableWithPipeInContent() throws {
278+
let html = """
279+
<table>
280+
<tr><th>Option</th><th>Description</th></tr>
281+
<tr><td>A | B</td><td>Choose A or B</td></tr>
282+
</table>
283+
"""
284+
let markdown = try converter.convert(html)
285+
// Pipes should be escaped in cell content
286+
XCTAssertTrue(markdown.contains("A \\| B"))
287+
}
288+
277289
// MARK: - Strikethrough Tests
278290

279291
func testDelTagConversion() throws {
@@ -299,27 +311,27 @@ class HTMLToMarkdownConverterTests: XCTestCase {
299311
func testUnderlineTagConversion() throws {
300312
let html = "<u>Underlined text</u>"
301313
let markdown = try converter.convert(html)
302-
XCTAssertTrue(markdown.contains("_Underlined text_"))
314+
XCTAssertTrue(markdown.contains("<u>Underlined text</u>"))
303315
}
304316

305317
func testInsTagConversion() throws {
306318
let html = "<ins>Inserted text</ins>"
307319
let markdown = try converter.convert(html)
308-
XCTAssertTrue(markdown.contains("_Inserted text_"))
320+
XCTAssertTrue(markdown.contains("<u>Inserted text</u>"))
309321
}
310322

311323
// MARK: - Superscript/Subscript Tests
312324

313325
func testSuperscriptConversion() throws {
314326
let html = "x<sup>2</sup>"
315327
let markdown = try converter.convert(html)
316-
XCTAssertTrue(markdown.contains("^2"))
328+
XCTAssertTrue(markdown.contains("<sup>2</sup>"))
317329
}
318330

319331
func testSubscriptConversion() throws {
320332
let html = "H<sub>2</sub>O"
321333
let markdown = try converter.convert(html)
322-
XCTAssertTrue(markdown.contains("~2"))
334+
XCTAssertTrue(markdown.contains("<sub>2</sub>"))
323335
}
324336

325337
// MARK: - Mark/Highlight Tests

0 commit comments

Comments
 (0)