Esempio n. 1
0
static void remove_trailing_blank_lines(strbuf *ln)
{
	int i;

	for (i = ln->size - 1; i >= 0; --i) {
		unsigned char c = ln->ptr[i];

		if (c != ' ' && c != '\t' && c != '\r' && c != '\n')
			break;
	}

	if (i < 0) {
		strbuf_clear(ln);
		return;
	}

	i = strbuf_strchr(ln, '\n', i);
	if (i >= 0)
		strbuf_truncate(ln, i);
}
Esempio n. 2
0
static void finalize(cmark_doc_parser *parser, cmark_node* b, int line_number)
{
	int firstlinelen;
	int pos;
	cmark_node* item;
	cmark_node* subitem;

	if (!b->open)
		return; // don't do anything if the cmark_node is already closed

	b->open = false;
	if (line_number > b->start_line) {
		b->end_line = line_number - 1;
	} else {
		b->end_line = line_number;
	}

	switch (b->type) {
		case NODE_PARAGRAPH:
			pos = 0;
			while (strbuf_at(&b->string_content, 0) == '[' &&
					(pos = parse_reference_inline(&b->string_content, parser->refmap))) {

				strbuf_drop(&b->string_content, pos);
			}
			if (is_blank(&b->string_content, 0)) {
				b->type = NODE_REFERENCE_DEF;
			}
			break;

		case NODE_INDENTED_CODE:
			remove_trailing_blank_lines(&b->string_content);
			strbuf_putc(&b->string_content, '\n');
			break;

		case NODE_FENCED_CODE:
			// first line of contents becomes info
			firstlinelen = strbuf_strchr(&b->string_content, '\n', 0);

			strbuf_init(&b->as.code.info, 0);
			houdini_unescape_html_f(
					&b->as.code.info,
					b->string_content.ptr,
					firstlinelen
					);

			strbuf_drop(&b->string_content, firstlinelen + 1);

			strbuf_trim(&b->as.code.info);
			strbuf_unescape(&b->as.code.info);
			break;

		case NODE_LIST: // determine tight/loose status
			b->as.list.tight = true; // tight by default
			item = b->first_child;

			while (item) {
				// check for non-final non-empty list item ending with blank line:
				if (item->last_line_blank && item->next) {
					b->as.list.tight = false;
					break;
				}
				// recurse into children of list item, to see if there are
				// spaces between them:
				subitem = item->first_child;
				while (subitem) {
					if (ends_with_blank_line(subitem) &&
							(item->next || subitem->next)) {
						b->as.list.tight = false;
						break;
					}
					subitem = subitem->next;
				}
				if (!(b->as.list.tight)) {
					break;
				}
				item = item->next;
			}

			break;

		default:
			break;
	}
}
Esempio n. 3
0
// Convert a node_block list to HTML.  Returns 0 on success, and sets result.
static void blocks_to_html(strbuf *html, node_block *b)
{
	struct ListData *data;
	render_stack* rstack = NULL;
	bool visit_children = false;
	bool tight = false;

	while(b != NULL) {
		visit_children = false;
		switch(b->tag) {
		case BLOCK_DOCUMENT:
			rstack = push_block(rstack, b->next, "", false, false);
			visit_children = true;
			break;

		case BLOCK_PARAGRAPH:
			if (tight) {
				inlines_to_html(html, b->inline_content);
			} else {
				cr(html);
				strbuf_puts(html, "<p>");
				inlines_to_html(html, b->inline_content);
				strbuf_puts(html, "</p>\n");
			}
			break;

		case BLOCK_BQUOTE:
			cr(html);
			strbuf_puts(html, "<blockquote>\n");
			rstack = push_block(rstack, b->next, "</blockquote>\n", tight, false);
			tight = false;
			visit_children = true;
			break;

		case BLOCK_LIST_ITEM:
			cr(html);
			strbuf_puts(html, "<li>");
			rstack = push_block(rstack, b->next, "</li>\n", tight, true);
			visit_children = true;
			break;

		case BLOCK_LIST:
			// make sure a list starts at the beginning of the line:
			cr(html);
			data = &(b->as.list);

			if (data->start > 1) {
				strbuf_printf(html, "<%s start=\"%d\">\n",
					      data->list_type == bullet ? "ul" : "ol",
					      data->start);
			} else {
				strbuf_puts(html, data->list_type == bullet ? "<ul>\n" : "<ol>\n");
			}

			rstack = push_block(rstack, b->next,
					    data->list_type == bullet ?
					    "\n</ul>\n" : "\n</ol>\n", tight, false);
			tight = data->tight;
			visit_children = true;
			break;

		case BLOCK_ATX_HEADER:
		case BLOCK_SETEXT_HEADER:
			cr(html);
			strbuf_printf(html, "<h%d>", b->as.header.level);
			inlines_to_html(html, b->inline_content);
			strbuf_printf(html, "</h%d>\n", b->as.header.level);
			break;

		case BLOCK_INDENTED_CODE:
		case BLOCK_FENCED_CODE:
			cr(html);

			strbuf_puts(html, "<pre><code");

			if (b->tag == BLOCK_FENCED_CODE) {
				strbuf *info = &b->as.code.info;

				if (strbuf_len(info) > 0) {
					int first_tag = strbuf_strchr(info, ' ', 0);
					if (first_tag < 0)
						first_tag = strbuf_len(info);

					strbuf_puts(html, " class=\"language-");
					escape_html(html, info->ptr, first_tag);
					strbuf_putc(html, '"');
				}
			}

			strbuf_putc(html, '>');
			escape_html(html, b->string_content.ptr, b->string_content.size);
			strbuf_puts(html, "</code></pre>\n");
			break;

		case BLOCK_HTML:
			strbuf_put(html, b->string_content.ptr, b->string_content.size);
			break;

		case BLOCK_HRULE:
			strbuf_puts(html, "<hr />\n");
			break;

		case BLOCK_REFERENCE_DEF:
			break;

		default:
			assert(false);
		}
		if (visit_children) {
			b = b->children;
		} else {
			b = b->next;
		}
		while (b == NULL && rstack != NULL) {
			strbuf_puts(html, rstack->literal);
			if (rstack->trim) {
				strbuf_rtrim(html);
			}
			tight = rstack->tight;
			b = rstack->next_sibling.block;
			rstack = pop_render_stack(rstack);
		}
	}

	free_render_stack(rstack);
}