Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 21 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ pub enum CodeBlockKind {
/// This does not only allow introspection, but enables the user
/// to halt the serialization at any time, and resume it later.
#[derive(Clone, Default, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[non_exhaustive]
pub struct State<'a> {
/// The amount of newlines to insert after `Event::Start(...)`
pub newlines_before_start: usize,
Expand Down Expand Up @@ -79,6 +80,8 @@ pub struct State<'a> {
pub image_stack: Vec<ImageLink<'a>>,
/// Keeps track of the last seen heading's id, classes, and attributes
pub current_heading: Option<Heading<'a>>,
/// True whenever between `Start(TableCell)` and `End(TableCell)`
pub in_table_cell: bool,

/// Keeps track of the last seen shortcut/link
pub current_shortcut_text: Option<String>,
Expand Down Expand Up @@ -305,10 +308,25 @@ where
text_for_header.push_str(text);
text_for_header.push('`');
}

// (re)-escape `|` when it appears as part of inline code in the
// body of a table.
//
// NOTE: This does not do *general* escaped-character handling
// because the only character which *requires* this handling in this
// spot in earlier versions of `pulldown-cmark` is a pipe character
// in inline code in a table. Other escaping is handled when `Text`
// events are emitted.
let text = if state.in_table_cell {
Cow::Owned(text.replace('|', "\\|"))
} else {
Cow::Borrowed(text.as_ref())
};

if text.chars().all(|ch| ch == ' ') {
write!(formatter, "`{text}`")
} else {
let backticks = "`".repeat(count_consecutive(text, '`') + 1);
let backticks = "`".repeat(count_consecutive(&text, '`') + 1);
let space = match text.as_bytes() {
&[b'`', ..] | &[.., b'`'] => " ", // Space needed to separate backtick.
&[b' ', .., b' '] => " ", // Space needed to escape inner space.
Expand Down Expand Up @@ -355,6 +373,7 @@ where
TableRow => Ok(()),
TableCell => {
state.text_for_header = Some(String::new());
state.in_table_cell = true;
formatter.write_char('|')
}
Link {
Expand Down Expand Up @@ -689,6 +708,7 @@ where
state
.table_headers
.push(state.text_for_header.take().unwrap_or_default());
state.in_table_cell = false;
Ok(())
}
t @ (TagEnd::TableRow | TagEnd::TableHead) => {
Expand Down
6 changes: 6 additions & 0 deletions tests/cat.sh
Original file line number Diff line number Diff line change
Expand Up @@ -99,3 +99,9 @@ title "stupicat"
WITH_SNAPSHOT="$snapshot/stupicat-toml-frontmatter-output" \
expect_run_sh $SUCCESSFULLY "${exe[*]} $fixture/toml-frontmatter.md 2>/dev/null"
)

(with "table with escaped characters in cells"
it "succeeds in reproducing the escapes" && \
WITH_SNAPSHOT="$snapshot/stupicat-table-with-escapes-output" \
expect_run_sh $SUCCESSFULLY "${exe[*]} $fixture/table-with-escapes.md 2>/dev/null"
)
6 changes: 6 additions & 0 deletions tests/fixtures/snapshots/stupicat-table-with-escapes-output
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
|First|Second|Third|Fourth|
|-----|------|-----|------|
|`\|`|`\\`|`a\[b\]`|`>>`|

Normal inline code with pipes `|` should not be re-escaped, because it does not
cause a problem!
6 changes: 6 additions & 0 deletions tests/fixtures/table-with-escapes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
| First | Second | Third | Fourth |
| ----- | ------ | -------- | ------ |
| `\|` | `\\` | `a\[b\]` | `>>` |

Normal inline code with pipes `|` should not be re-escaped, because it does not
cause a problem!
Loading
Loading