Skip to content

Commit daef56b

Browse files
authored
Merge pull request #90 from chriskrycho/escape-code-in-tables
Escape code in tables
2 parents f6fba5f + a85fe39 commit daef56b

File tree

5 files changed

+259
-464
lines changed

5 files changed

+259
-464
lines changed

src/lib.rs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ pub enum CodeBlockKind {
5151
/// This does not only allow introspection, but enables the user
5252
/// to halt the serialization at any time, and resume it later.
5353
#[derive(Clone, Default, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
54+
#[non_exhaustive]
5455
pub struct State<'a> {
5556
/// The amount of newlines to insert after `Event::Start(...)`
5657
pub newlines_before_start: usize,
@@ -79,6 +80,8 @@ pub struct State<'a> {
7980
pub image_stack: Vec<ImageLink<'a>>,
8081
/// Keeps track of the last seen heading's id, classes, and attributes
8182
pub current_heading: Option<Heading<'a>>,
83+
/// True whenever between `Start(TableCell)` and `End(TableCell)`
84+
pub in_table_cell: bool,
8285

8386
/// Keeps track of the last seen shortcut/link
8487
pub current_shortcut_text: Option<String>,
@@ -305,10 +308,25 @@ where
305308
text_for_header.push_str(text);
306309
text_for_header.push('`');
307310
}
311+
312+
// (re)-escape `|` when it appears as part of inline code in the
313+
// body of a table.
314+
//
315+
// NOTE: This does not do *general* escaped-character handling
316+
// because the only character which *requires* this handling in this
317+
// spot in earlier versions of `pulldown-cmark` is a pipe character
318+
// in inline code in a table. Other escaping is handled when `Text`
319+
// events are emitted.
320+
let text = if state.in_table_cell {
321+
Cow::Owned(text.replace('|', "\\|"))
322+
} else {
323+
Cow::Borrowed(text.as_ref())
324+
};
325+
308326
if text.chars().all(|ch| ch == ' ') {
309327
write!(formatter, "`{text}`")
310328
} else {
311-
let backticks = "`".repeat(count_consecutive(text, '`') + 1);
329+
let backticks = "`".repeat(count_consecutive(&text, '`') + 1);
312330
let space = match text.as_bytes() {
313331
&[b'`', ..] | &[.., b'`'] => " ", // Space needed to separate backtick.
314332
&[b' ', .., b' '] => " ", // Space needed to escape inner space.
@@ -355,6 +373,7 @@ where
355373
TableRow => Ok(()),
356374
TableCell => {
357375
state.text_for_header = Some(String::new());
376+
state.in_table_cell = true;
358377
formatter.write_char('|')
359378
}
360379
Link {
@@ -689,6 +708,7 @@ where
689708
state
690709
.table_headers
691710
.push(state.text_for_header.take().unwrap_or_default());
711+
state.in_table_cell = false;
692712
Ok(())
693713
}
694714
t @ (TagEnd::TableRow | TagEnd::TableHead) => {

tests/cat.sh

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,3 +99,9 @@ title "stupicat"
9999
WITH_SNAPSHOT="$snapshot/stupicat-toml-frontmatter-output" \
100100
expect_run_sh $SUCCESSFULLY "${exe[*]} $fixture/toml-frontmatter.md 2>/dev/null"
101101
)
102+
103+
(with "table with escaped characters in cells"
104+
it "succeeds in reproducing the escapes" && \
105+
WITH_SNAPSHOT="$snapshot/stupicat-table-with-escapes-output" \
106+
expect_run_sh $SUCCESSFULLY "${exe[*]} $fixture/table-with-escapes.md 2>/dev/null"
107+
)
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
|First|Second|Third|Fourth|
2+
|-----|------|-----|------|
3+
|`\|`|`\\`|`a\[b\]`|`>>`|
4+
5+
Normal inline code with pipes `|` should not be re-escaped, because it does not
6+
cause a problem!
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
| First | Second | Third | Fourth |
2+
| ----- | ------ | -------- | ------ |
3+
| `\|` | `\\` | `a\[b\]` | `>>` |
4+
5+
Normal inline code with pipes `|` should not be re-escaped, because it does not
6+
cause a problem!

0 commit comments

Comments
 (0)