cmark

My personal build of CMark ✏️

Commit
cb32c56abbc1e085025da1cd55b151ffb5a006cc
Parent
dfe48b48179c7779b39da9ba868fa182f8368e38
Author
John MacFarlane <jgm@berkeley.edu>
Date

commonmark rendere: more fine-grained control over escaping.

Diffstat

1 file changed, 39 insertions, 25 deletions

Status File Name N° Changes Insertions Deletions
Modified src/commonmark.c 64 39 25
diff --git a/src/commonmark.c b/src/commonmark.c
@@ -39,24 +39,39 @@ static inline void blankline(struct render_state *state)
 	}
 }
 
+typedef enum  {
+	NO_ESCAPING,
+	NORMAL_ESCAPING,
+	QUOTE_ESCAPING
+} escaping;
+
 static inline bool
-needs_escaping(int32_t c, unsigned char next_c, struct render_state *state)
+needs_escaping(escaping escape,
+	       int32_t c,
+	       unsigned char next_c,
+	       struct render_state *state)
 {
-	return (c == '*' || c == '_' || c == '[' || c == ']' ||
-		c == '<' || c == '>' || c == '\\' ||
-		(c == '&' && isalpha(next_c)) ||
-		(c == '!' && next_c == '[') ||
-		(state->begin_line &&
-		 (c == '-' || c == '+' || c == '#' || c == '=')) ||
-		(c == '#' && (isspace(next_c) || next_c == '\0')) ||
-		((c == '.' || c == ')') &&
-		 isdigit(state->buffer->ptr[state->buffer->size - 1])));
+	if (escape == NORMAL_ESCAPING) {
+		return (c == '*' || c == '_' || c == '[' || c == ']' ||
+			c == '<' || c == '>' || c == '\\' ||
+			(c == '&' && isalpha(next_c)) ||
+			(c == '!' && next_c == '[') ||
+			(state->begin_line &&
+			 (c == '-' || c == '+' || c == '#' || c == '=')) ||
+			(c == '#' && (isspace(next_c) || next_c == '\0')) ||
+			((c == '.' || c == ')') &&
+			 isdigit(state->buffer->ptr[state->buffer->size - 1])));
+	} else if (escape == QUOTE_ESCAPING) {
+		return (c == '"' || c == '\\');
+	} else {
+		return false;
+	}
 }
 
 static inline void out(struct render_state *state,
 		       cmark_chunk str,
 		       bool wrap,
-		       bool escape)
+		       escaping escape)
 {
 	unsigned char* source = str.data;
 	int length = str.len;
@@ -115,8 +130,7 @@ static inline void out(struct render_state *state,
 			state->column = 0;
 			state->begin_line = true;
 			state->last_breakable = 0;
-		} else if (escape &&
-			   needs_escaping(c, nextc, state)) {
+		} else if (needs_escaping(escape, c, nextc, state)) {
 			cmark_strbuf_putc(state->buffer, '\\');
 			utf8proc_encode_char(c, state->buffer);
 			state->column += 2;
@@ -156,7 +170,7 @@ static inline void out(struct render_state *state,
 static void lit(struct render_state *state, char *s, bool wrap)
 {
 	cmark_chunk str = cmark_chunk_literal(s);
-	out(state, str, wrap, false);
+	out(state, str, wrap, NO_ESCAPING);
 }
 
 static int
@@ -282,7 +296,7 @@ S_render_node(cmark_node *node, cmark_event_type ev_type,
 			// use indented form if no info
 			lit(state, "    ", false);
 			cmark_strbuf_puts(state->prefix, "    ");
-			out(state, node->as.code.literal, false, false);
+			out(state, node->as.code.literal, false, NO_ESCAPING);
 			cmark_strbuf_truncate(state->prefix,
 					      state->prefix->size - 4);
 		} else {
@@ -295,9 +309,9 @@ S_render_node(cmark_node *node, cmark_event_type ev_type,
 				lit(state, "`", false);
 			}
 			lit(state, " ", false);
-			out(state, cmark_chunk_literal(info), false, false);
+			out(state, cmark_chunk_literal(info), false, NO_ESCAPING);
 			cr(state);
-			out(state, node->as.code.literal, false, true);
+			out(state, node->as.code.literal, false, NORMAL_ESCAPING);
 			cr(state);
 			for (i = 0; i < numticks; i++) {
 				lit(state, "`", false);
@@ -308,7 +322,7 @@ S_render_node(cmark_node *node, cmark_event_type ev_type,
 
 	case CMARK_NODE_HTML:
 		blankline(state);
-		out(state, node->as.literal, false, false);
+		out(state, node->as.literal, false, NO_ESCAPING);
 		blankline(state);
 		break;
 
@@ -325,7 +339,7 @@ S_render_node(cmark_node *node, cmark_event_type ev_type,
 		break;
 
 	case CMARK_NODE_TEXT:
-		out(state, node->as.literal, true, true);
+		out(state, node->as.literal, true, NORMAL_ESCAPING);
 		break;
 
 	case CMARK_NODE_LINEBREAK:
@@ -347,7 +361,7 @@ S_render_node(cmark_node *node, cmark_event_type ev_type,
 		if (numticks > 1) {
 			lit(state, " ", false);
 		}
-		out(state, node->as.literal, true, false);
+		out(state, node->as.literal, true, NO_ESCAPING);
 		if (numticks > 1) {
 			lit(state, " ", false);
 		}
@@ -357,7 +371,7 @@ S_render_node(cmark_node *node, cmark_event_type ev_type,
 		break;
 
 	case CMARK_NODE_INLINE_HTML:
-		out(state, node->as.literal, true, false);
+		out(state, node->as.literal, true, NO_ESCAPING);
 		break;
 
 	case CMARK_NODE_STRONG:
@@ -384,11 +398,11 @@ S_render_node(cmark_node *node, cmark_event_type ev_type,
 			// TODO - backslash-escape " and \ inside url, title
 			// for both links and images
 			lit(state, "](", false);
-			out(state, cmark_chunk_literal(cmark_node_get_url(node)), false, true);
+			out(state, cmark_chunk_literal(cmark_node_get_url(node)), false, QUOTE_ESCAPING);
 			title = cmark_node_get_title(node);
 			if (title && strlen(title) > 0) {
 				lit(state, " \"", true);
-				out(state, cmark_chunk_literal(title), false, true);
+				out(state, cmark_chunk_literal(title), false, QUOTE_ESCAPING);
 				lit(state, "\"", false);
 			}
 			lit(state, ")", false);
@@ -400,11 +414,11 @@ S_render_node(cmark_node *node, cmark_event_type ev_type,
 			lit(state, "![", false);
 		} else {
 			lit(state, "](", false);
-			out(state, cmark_chunk_literal(cmark_node_get_url(node)), false, true);
+			out(state, cmark_chunk_literal(cmark_node_get_url(node)), false, QUOTE_ESCAPING);
 			title = cmark_node_get_title(node);
 			if (title && strlen(title) > 0) {
 				lit(state, " \"", true);
-				out(state, cmark_chunk_literal(title), false, true);
+				out(state, cmark_chunk_literal(title), false, QUOTE_ESCAPING);
 				lit(state, "\"", false);
 			}
 			lit(state, ")", false);