Пример #1
0
void cmark_strbuf_trim(cmark_strbuf *buf) {
  bufsize_t i = 0;

  if (!buf->size)
    return;

  while (i < buf->size && cmark_isspace(buf->ptr[i]))
    i++;

  cmark_strbuf_drop(buf, i);

  cmark_strbuf_rtrim(buf);
}
Пример #2
0
static cmark_node*
finalize(cmark_parser *parser, cmark_node* b)
{
	int pos;
	cmark_node* item;
	cmark_node* subitem;
	cmark_node* parent;

	parent = b->parent;

	assert(b->open);  // shouldn't call finalize on closed blocks
	b->open = false;

	if (parser->curline->size == 0) {
		// end of input - line number has not been incremented
		b->end_line = parser->line_number;
		b->end_column = parser->last_line_length;
	} else if (b->type == NODE_DOCUMENT ||
	           (b->type == NODE_CODE_BLOCK && b->as.code.fenced) ||
	           (b->type == NODE_HEADER && b->as.header.setext)) {
		b->end_line = parser->line_number;
		b->end_column = parser->curline->size;
		if (b->end_column && parser->curline->ptr[b->end_column - 1] == '\n')
			b->end_column--;
		if (b->end_column && parser->curline->ptr[b->end_column - 1] == '\r')
			b->end_column--;
	} else {
		b->end_line = parser->line_number - 1;
		b->end_column = parser->last_line_length;
	}

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

			cmark_strbuf_drop(&b->string_content, pos);
		}
		if (is_blank(&b->string_content, 0)) {
			// remove blank node (former reference def)
			cmark_node_free(b);
		}
		break;

	case NODE_CODE_BLOCK:
		if (!b->as.code.fenced) { // indented code
			remove_trailing_blank_lines(&b->string_content);
			cmark_strbuf_putc(&b->string_content, '\n');
		} else {

			// first line of contents becomes info
			for (pos = 0; pos < b->string_content.size; ++pos) {
				if (b->string_content.ptr[pos] == '\r' ||
				    b->string_content.ptr[pos] == '\n')
					break;
			}
			assert(pos < b->string_content.size);

			cmark_strbuf tmp = GH_BUF_INIT;
			houdini_unescape_html_f(
			    &tmp,
			    b->string_content.ptr,
			    pos
			);
			cmark_strbuf_trim(&tmp);
			cmark_strbuf_unescape(&tmp);
			b->as.code.info = cmark_chunk_buf_detach(&tmp);

			if (b->string_content.ptr[pos] == '\r')
				pos += 1;
			if (b->string_content.ptr[pos] == '\n')
				pos += 1;
			cmark_strbuf_drop(&b->string_content, pos);
		}
		b->as.code.literal = cmark_chunk_buf_detach(&b->string_content);
		break;

	case NODE_HTML:
		b->as.literal = cmark_chunk_buf_detach(&b->string_content);
		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;
	}
	return parent;
}
Пример #3
0
static cmark_node*
finalize(cmark_parser *parser, cmark_node* b, int line_number)
{
	int firstlinelen;
	int pos;
	cmark_node* item;
	cmark_node* subitem;
	cmark_node* parent;

	parent = b->parent;

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

	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:
			while (cmark_strbuf_at(&b->string_content, 0) == '[' &&
					(pos = cmark_parse_reference_inline(&b->string_content, parser->refmap))) {

				cmark_strbuf_drop(&b->string_content, pos);
			}
			if (is_blank(&b->string_content, 0)) {
				// remove blank node (former reference def)
				cmark_node_free(b);
			}
			break;

		case NODE_CODE_BLOCK:
			if (!b->as.code.fenced) { // indented code
				remove_trailing_blank_lines(&b->string_content);
				cmark_strbuf_putc(&b->string_content, '\n');
			} else {

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

				cmark_strbuf tmp = GH_BUF_INIT;
				houdini_unescape_html_f(
					&tmp,
					b->string_content.ptr,
					firstlinelen
					);
				cmark_strbuf_trim(&tmp);
				cmark_strbuf_unescape(&tmp);
				b->as.code.info = cmark_chunk_buf_detach(&tmp);

				cmark_strbuf_drop(&b->string_content, firstlinelen + 1);
			}
			b->as.code.literal = cmark_chunk_buf_detach(&b->string_content);
			break;

	        case NODE_HTML:
			b->as.literal = cmark_chunk_buf_detach(&b->string_content);
			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;
	}
	return parent;
}