fix(export): escape backslashes in tag table cells
A backslash right before a pipe, as in the tag name a\|b, turned the escaped pipe into "\|": the table splitter reads "\\" as an escaped backslash and the pipe as a column separator, shifting the row. Cells now escape '\' before '|'. Recorded in PLAN 5.8.
This commit is contained in:
1 parent
b6e8e07d78
commit
9277e2a331
3 files changed
+29
-4
No files matched your search
@@ -204,6 +204,29 @@ public class MarkdownExporterTests
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void TagTableCellsEscapeBackslashesSoAPipeAfterOneStaysEscaped()
|
||||||
|
{
|
||||||
|
CultureInfo? original = Resources.Culture;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Resources.Culture = new CultureInfo("en");
|
||||||
|
var tag = new TagModel(1, @"a\|b", RgbColor.Parse("#112233"), @"C:\temp\");
|
||||||
|
string markdown = MarkdownExporter.Export(
|
||||||
|
"W",
|
||||||
|
[new ColumnModel(1, "C", string.Empty, 1, 1)],
|
||||||
|
[],
|
||||||
|
[(tag, 0L)],
|
||||||
|
ExportedAt);
|
||||||
|
|
||||||
|
StringAssert.Contains(markdown, @"| a\\\|b | #112233 | C:\\temp\\ | 0 |");
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Resources.Culture = original;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
[DataRow("plain", "`plain`")]
|
[DataRow("plain", "`plain`")]
|
||||||
[DataRow("a`b", "``a`b``")]
|
[DataRow("a`b", "``a`b``")]
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ namespace YKanBan.Export;
|
|||||||
/// uses that one per-language pattern. The whole document uses LF line endings
|
/// uses that one per-language pattern. The whole document uses LF line endings
|
||||||
/// on every platform. Card bodies and column descriptions are emitted verbatim
|
/// on every platform. Card bodies and column descriptions are emitted verbatim
|
||||||
/// apart from line endings; column and card titles are collapsed to one line;
|
/// apart from line endings; column and card titles are collapsed to one line;
|
||||||
/// tag names become inline code with a long enough backtick fence; tag table cells escape '|' and turn line breaks into <br>. The
|
/// tag names become inline code with a long enough backtick fence; tag table cells escape '\' and '|' and turn line breaks into <br>. The
|
||||||
/// output is meant for reading only — there is no re-import.
|
/// output is meant for reading only — there is no re-import.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class MarkdownExporter
|
public static class MarkdownExporter
|
||||||
@@ -130,12 +130,14 @@ public static class MarkdownExporter
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Formats a table cell: escaped pipe characters, line breaks as <br>.
|
/// Formats a table cell: escaped backslashes and pipe characters, line breaks as <br>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="text">The raw cell text.</param>
|
/// <param name="text">The raw cell text.</param>
|
||||||
/// <returns>The escaped single-line text.</returns>
|
/// <returns>The escaped single-line text.</returns>
|
||||||
private static string Cell(string text) =>
|
private static string Cell(string text) =>
|
||||||
text.Replace("|", "\\|").Replace("\r\n", "<br>").Replace("\r", "<br>").Replace("\n", "<br>");
|
// Backslashes first: the table splitter reads "\\" as an escaped backslash, so the
|
||||||
|
// '|' after a literal backslash would otherwise end the cell.
|
||||||
|
text.Replace("\\", "\\\\").Replace("|", "\\|").Replace("\r\n", "<br>").Replace("\r", "<br>").Replace("\n", "<br>");
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Renders text as an inline code span whose backtick fence is one longer than
|
/// Renders text as an inline code span whose backtick fence is one longer than
|
||||||
|
|||||||
+1
-1
@@ -246,7 +246,7 @@ card_tags: (card_id, tag_id) 复合主键,双向 ON DELETE CASCADE
|
|||||||
- 空列也保留(体现看板结构);无标题卡片以 `### #61` 呈现
|
- 空列也保留(体现看板结构);无标题卡片以 `### #61` 呈现
|
||||||
- 转义规则:
|
- 转义规则:
|
||||||
- 标签名以行内代码呈现,定界反引号数量 = 名称内最长连续反引号串长度 + 1(名称以反引号开头/结尾时两侧加空格)
|
- 标签名以行内代码呈现,定界反引号数量 = 名称内最长连续反引号串长度 + 1(名称以反引号开头/结尾时两侧加空格)
|
||||||
- 标签总表单元格内 `|` → `\|`,换行 → `<br>`
|
- 标签总表单元格内 `\` → `\\`(先于 `|` 处理,否则 `a\|b` 中的 `|` 会被当成列分隔符),`|` → `\|`,换行 → `<br>`
|
||||||
- 卡片正文与列 description **原样输出**(接受其中 Markdown 结构干扰文档层级,已接受)
|
- 卡片正文与列 description **原样输出**(接受其中 Markdown 结构干扰文档层级,已接受)
|
||||||
|
|
||||||
### 5.9 主题(亮 / 暗 / 跟随系统)
|
### 5.9 主题(亮 / 暗 / 跟随系统)
|
||||||
|
|||||||
Reference in new issue
Block a user