Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Inconstant List Indentation #616

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Changelog

* Correct an issue where list parsing would improperly handle
indentation, causing list elements to not correctly nest.

Fixes #615.

* Fix SmartyPants single quotes right after a link. For example:

~~~markdown
Expand Down
28 changes: 25 additions & 3 deletions ext/redcarpet/markdown.c
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,9 @@ parse_inline(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t siz
uint8_t action = 0;
struct buf work = { 0, 0, 0, 0 };

// JD: You can monitor the current nesting status here. If this exceeds max_nesting, there will be problems.
// fprintf(stderr, "\nMax Birds in Nest: %lu\n", rndr->work_bufs[BUFFER_SPAN].size + rndr->work_bufs[BUFFER_BLOCK].size);

if (rndr->work_bufs[BUFFER_SPAN].size +
rndr->work_bufs[BUFFER_BLOCK].size > rndr->max_nesting)
return;
Expand Down Expand Up @@ -1824,8 +1827,9 @@ parse_blockcode(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t
static size_t
parse_listitem(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size, int *flags)
{
// JD: pre has been defined with an initial indent of 4. This is used further down.
struct buf *work = 0, *inter = 0;
size_t beg = 0, end, pre, sublist = 0, orgpre = 0, i;
size_t beg = 0, end, pre = 4, sublist = 0, orgpre = 0, i;
int in_empty = 0, has_inside_empty = 0, in_fence = 0;

/* keeping track of the first indentation prefix */
Expand Down Expand Up @@ -1870,9 +1874,10 @@ parse_listitem(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t s

/* calculating the indentation */
i = 0;
while (i < 4 && beg + i < end && data[beg + i] == ' ')
// JD: We'll check indentation, up to whatever our current level of indentation is (or 4, if it's the first time).
while (i < pre && beg + i < end && data[beg + i] == ' ')
i++;

// JD: Once we stop our check, we'll update pre, and use it next time when walking through indentation.
pre = i;

if (rndr->ext_flags & MKDEXT_FENCED_CODE) {
Expand Down Expand Up @@ -1900,6 +1905,23 @@ parse_listitem(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t s
if (in_empty)
has_inside_empty = 1;

/*
JD: This is where I started observing the system. Placing this code in an otherwise non-modified version allows you to see the difference in handling indentation when the third level is hit.
JD: Since work is just a working buffer, and since most of our operations are size-limiting, I'm setting the very last byte to a null terminator to make this print-friendly.
JD: This avoids the need to copy to another place im memory during testing.
*/
/*
work->data[work->size] = '\0';
fprintf(stderr, "---BEGIN DATA---\n");
fprintf(stderr, "Orig. Indent: %lu\n", orgpre);
fprintf(stderr, "Curr. Indent: %lu\n", pre);
fprintf(stderr, "Curr. Sublist Status: %lu\n", sublist);
fprintf(stderr, "Has Next UL: %lu\n", has_next_uli);
fprintf(stderr, "Has Next OL: %lu\n", has_next_oli);
fprintf(stderr, "%s\n", work->data);
fprintf(stderr, "---END DATA---\n");
*/

if (pre == orgpre) /* the following item must have */
break; /* the same indentation */

Expand Down
16 changes: 16 additions & 0 deletions test/markdown_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -403,4 +403,20 @@ def test_single_dashes_on_table_headers

assert_match /<table>/, output
end

# https://github.com/vmg/redcarpet/issues/615
def test_inconsistent_indentation
markdown = <<-Markdown.strip_heredoc
- Item 1
- Item 2
- Item 3
- Item 4
- Item 5
Markdown

result = "<ul>\n<li>Item 1\n\n<ul>\n<li>Item 2\n\n<ul>\n<li>Item 3\n\n<ul>\n<li>Item 4\n\n<ul>\n<li>Item 5</li>\n</ul></li>\n</ul></li>\n</ul></li>\n</ul></li>\n</ul>"
output = render(markdown)

assert_equal result, output
end
end