Skip to content

Commit 2dca096

Browse files
nwellnhofjgm
authored andcommitted
Fix quadratic behavior involving get_containing_block
Fix quadratic behavior in the Commonmark renderer when determining the tight list status in deeply nested inlines. Instead of searching for the containing block, update the tight list status when - entering a child of a list item - exiting a list Fixes #431.
1 parent 99b4896 commit 2dca096

File tree

2 files changed

+15
-24
lines changed

2 files changed

+15
-24
lines changed

src/commonmark.c

+12-24
Original file line numberDiff line numberDiff line change
@@ -150,21 +150,6 @@ static bool is_autolink(cmark_node *node) {
150150
strcmp((const char *)url, (char *)link_text->data) == 0;
151151
}
152152

153-
// if node is a block node, returns node.
154-
// otherwise returns first block-level node that is an ancestor of node.
155-
// if there is no block-level ancestor, returns NULL.
156-
static cmark_node *get_containing_block(cmark_node *node) {
157-
while (node) {
158-
if (node->type >= CMARK_NODE_FIRST_BLOCK &&
159-
node->type <= CMARK_NODE_LAST_BLOCK) {
160-
return node;
161-
} else {
162-
node = node->parent;
163-
}
164-
}
165-
return NULL;
166-
}
167-
168153
static int S_render_node(cmark_renderer *renderer, cmark_node *node,
169154
cmark_event_type ev_type, int options) {
170155
cmark_node *tmp;
@@ -186,16 +171,19 @@ static int S_render_node(cmark_renderer *renderer, cmark_node *node,
186171
!(CMARK_OPT_HARDBREAKS & options);
187172

188173
// Don't adjust tight list status til we've started the list.
189-
// Otherwise we loose the blank line between a paragraph and
174+
// Otherwise we lose the blank line between a paragraph and
190175
// a following list.
191-
if (!(node->type == CMARK_NODE_ITEM && node->prev == NULL && entering)) {
192-
tmp = get_containing_block(node);
193-
renderer->in_tight_list_item =
194-
tmp && // tmp might be NULL if there is no containing block
195-
((tmp->type == CMARK_NODE_ITEM &&
196-
cmark_node_get_list_tight(tmp->parent)) ||
197-
(tmp && tmp->parent && tmp->parent->type == CMARK_NODE_ITEM &&
198-
cmark_node_get_list_tight(tmp->parent->parent)));
176+
if (entering) {
177+
if (node->parent && node->parent->type == CMARK_NODE_ITEM) {
178+
renderer->in_tight_list_item = node->parent->parent->as.list.tight;
179+
}
180+
} else {
181+
if (node->type == CMARK_NODE_LIST) {
182+
renderer->in_tight_list_item =
183+
node->parent &&
184+
node->parent->type == CMARK_NODE_ITEM &&
185+
node->parent->parent->as.list.tight;
186+
}
199187
}
200188

201189
switch (node->type) {

test/pathological_tests.py

+3
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,9 @@ def badhash(ref):
111111
}
112112

113113
pathological_cmark = {
114+
"nested inlines":
115+
("*" * 40000 + "a" + "*" * 40000,
116+
re.compile("^\*+a\*+$")),
114117
}
115118

116119
whitespace_re = re.compile('/s+/')

0 commit comments

Comments
 (0)