aboutsummaryrefslogtreecommitdiff
path: root/src/print.c
blob: d2dfe8c36ee6b41d720b3ad3d3cf26ba7fb4edc4 (plain)
  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include "cmark.h"
  5. #include "buffer.h"
  6. #include "node.h"
  7. #define INDENT 2
  8. static void print_str(strbuf* buffer, const unsigned char *s, int len)
  9. {
  10. int i;
  11. if (len < 0)
  12. len = strlen((char *)s);
  13. strbuf_putc(buffer, '"');
  14. for (i = 0; i < len; ++i) {
  15. unsigned char c = s[i];
  16. switch (c) {
  17. case '\n':
  18. strbuf_printf(buffer, "\\n");
  19. break;
  20. case '"':
  21. strbuf_printf(buffer, "\\\"");
  22. break;
  23. case '\\':
  24. strbuf_printf(buffer, "\\\\");
  25. break;
  26. default:
  27. strbuf_putc(buffer, (int)c);
  28. }
  29. }
  30. strbuf_putc(buffer, '"');
  31. }
  32. // Prettyprint an inline list, for debugging.
  33. static void render_nodes(strbuf* buffer, cmark_node* node, int indent)
  34. {
  35. int i;
  36. cmark_list *data;
  37. while(node != NULL) {
  38. for (i=0; i < indent; i++) {
  39. strbuf_putc(buffer, ' ');
  40. }
  41. switch(node->type) {
  42. case NODE_DOCUMENT:
  43. break;
  44. case NODE_BLOCK_QUOTE:
  45. strbuf_printf(buffer, "block_quote\n");
  46. break;
  47. case NODE_LIST_ITEM:
  48. strbuf_printf(buffer, "list_item\n");
  49. break;
  50. case NODE_LIST:
  51. data = &(node->as.list);
  52. if (data->list_type == CMARK_ORDERED_LIST) {
  53. strbuf_printf(buffer, "list (type=ordered tight=%s start=%d delim=%s)\n",
  54. (data->tight ? "true" : "false"),
  55. data->start,
  56. (data->delimiter == CMARK_PAREN_DELIM ? "parens" : "period"));
  57. } else {
  58. strbuf_printf(buffer, "list (type=bullet tight=%s bullet_char=%c)\n",
  59. (data->tight ? "true" : "false"),
  60. data->bullet_char);
  61. }
  62. break;
  63. case NODE_HEADER:
  64. strbuf_printf(buffer, "header (level=%d)\n", node->as.header.level);
  65. break;
  66. case NODE_PARAGRAPH:
  67. strbuf_printf(buffer, "paragraph\n");
  68. break;
  69. case NODE_HRULE:
  70. strbuf_printf(buffer, "hrule\n");
  71. break;
  72. case NODE_CODE_BLOCK:
  73. strbuf_printf(buffer, "code_block info=");
  74. print_str(buffer, node->as.code.info.ptr, -1);
  75. strbuf_putc(buffer, ' ');
  76. print_str(buffer, node->string_content.ptr, -1);
  77. strbuf_putc(buffer, '\n');
  78. break;
  79. case NODE_HTML:
  80. strbuf_printf(buffer, "html ");
  81. print_str(buffer, node->string_content.ptr, -1);
  82. strbuf_putc(buffer, '\n');
  83. break;
  84. case NODE_REFERENCE_DEF:
  85. // skip
  86. // strbuf_printf(buffer, "reference_def\n");
  87. break;
  88. case NODE_TEXT:
  89. strbuf_printf(buffer, "text ");
  90. print_str(buffer, node->as.literal.data, node->as.literal.len);
  91. strbuf_putc(buffer, '\n');
  92. break;
  93. case NODE_LINEBREAK:
  94. strbuf_printf(buffer, "linebreak\n");
  95. break;
  96. case NODE_SOFTBREAK:
  97. strbuf_printf(buffer, "softbreak\n");
  98. break;
  99. case NODE_INLINE_CODE:
  100. strbuf_printf(buffer, "code ");
  101. print_str(buffer, node->as.literal.data, node->as.literal.len);
  102. strbuf_putc(buffer, '\n');
  103. break;
  104. case NODE_INLINE_HTML:
  105. strbuf_printf(buffer, "inline_html ");
  106. print_str(buffer, node->as.literal.data, node->as.literal.len);
  107. strbuf_putc(buffer, '\n');
  108. break;
  109. case NODE_LINK:
  110. case NODE_IMAGE:
  111. strbuf_printf(buffer, "%s url=", node->type == NODE_LINK ? "link" : "image");
  112. if (node->as.link.url)
  113. print_str(buffer, node->as.link.url, -1);
  114. if (node->as.link.title) {
  115. strbuf_printf(buffer, " title=");
  116. print_str(buffer, node->as.link.title, -1);
  117. }
  118. strbuf_putc(buffer, '\n');
  119. break;
  120. case NODE_STRONG:
  121. strbuf_printf(buffer, "strong\n");
  122. break;
  123. case NODE_EMPH:
  124. strbuf_printf(buffer, "emph\n");
  125. break;
  126. default:
  127. break;
  128. }
  129. if (node->first_child) { // render children if any
  130. indent += INDENT;
  131. node = node->first_child;
  132. } else if (node->next) { // otherwise render next sibling
  133. node = node->next;
  134. } else {
  135. node = node->parent; // back up to parent
  136. while (node) {
  137. indent -= INDENT;
  138. if (node->next) {
  139. node = node->next;
  140. break;
  141. } else {
  142. node = node->parent;
  143. }
  144. if (!node) {
  145. break;
  146. }
  147. }
  148. }
  149. }
  150. }
  151. char *cmark_render_ast(cmark_node *root)
  152. {
  153. char* result;
  154. strbuf buffer = GH_BUF_INIT;
  155. render_nodes(&buffer, root, -2);
  156. result = (char *)strbuf_detach(&buffer);
  157. strbuf_free(&buffer);
  158. return result;
  159. }