iterator.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. #include <assert.h>
  2. #include <stdlib.h>
  3. #include "config.h"
  4. #include "node.h"
  5. #include "cmark.h"
  6. #include "iterator.h"
  7. static const int S_leaf_mask =
  8. (1 << CMARK_NODE_HTML_BLOCK) | (1 << CMARK_NODE_THEMATIC_BREAK) |
  9. (1 << CMARK_NODE_CODE_BLOCK) | (1 << CMARK_NODE_TEXT) |
  10. (1 << CMARK_NODE_SOFTBREAK) | (1 << CMARK_NODE_LINEBREAK) |
  11. (1 << CMARK_NODE_CODE) | (1 << CMARK_NODE_HTML_INLINE);
  12. cmark_iter *cmark_iter_new(cmark_node *root) {
  13. if (root == NULL) {
  14. return NULL;
  15. }
  16. cmark_mem *mem = root->content.mem;
  17. cmark_iter *iter = (cmark_iter *)mem->calloc(1, sizeof(cmark_iter));
  18. iter->mem = mem;
  19. iter->root = root;
  20. iter->cur.ev_type = CMARK_EVENT_NONE;
  21. iter->cur.node = NULL;
  22. iter->next.ev_type = CMARK_EVENT_ENTER;
  23. iter->next.node = root;
  24. return iter;
  25. }
  26. void cmark_iter_free(cmark_iter *iter) { iter->mem->free(iter); }
  27. static bool S_is_leaf(cmark_node *node) {
  28. return ((1 << node->type) & S_leaf_mask) != 0;
  29. }
  30. cmark_event_type cmark_iter_next(cmark_iter *iter) {
  31. cmark_event_type ev_type = iter->next.ev_type;
  32. cmark_node *node = iter->next.node;
  33. iter->cur.ev_type = ev_type;
  34. iter->cur.node = node;
  35. if (ev_type == CMARK_EVENT_DONE) {
  36. return ev_type;
  37. }
  38. /* roll forward to next item, setting both fields */
  39. if (ev_type == CMARK_EVENT_ENTER && !S_is_leaf(node)) {
  40. if (node->first_child == NULL) {
  41. /* stay on this node but exit */
  42. iter->next.ev_type = CMARK_EVENT_EXIT;
  43. } else {
  44. iter->next.ev_type = CMARK_EVENT_ENTER;
  45. iter->next.node = node->first_child;
  46. }
  47. } else if (node == iter->root) {
  48. /* don't move past root */
  49. iter->next.ev_type = CMARK_EVENT_DONE;
  50. iter->next.node = NULL;
  51. } else if (node->next) {
  52. iter->next.ev_type = CMARK_EVENT_ENTER;
  53. iter->next.node = node->next;
  54. } else if (node->parent) {
  55. iter->next.ev_type = CMARK_EVENT_EXIT;
  56. iter->next.node = node->parent;
  57. } else {
  58. assert(false);
  59. iter->next.ev_type = CMARK_EVENT_DONE;
  60. iter->next.node = NULL;
  61. }
  62. return ev_type;
  63. }
  64. void cmark_iter_reset(cmark_iter *iter, cmark_node *current,
  65. cmark_event_type event_type) {
  66. iter->next.ev_type = event_type;
  67. iter->next.node = current;
  68. cmark_iter_next(iter);
  69. }
  70. cmark_node *cmark_iter_get_node(cmark_iter *iter) { return iter->cur.node; }
  71. cmark_event_type cmark_iter_get_event_type(cmark_iter *iter) {
  72. return iter->cur.ev_type;
  73. }
  74. cmark_node *cmark_iter_get_root(cmark_iter *iter) { return iter->root; }
  75. void cmark_consolidate_text_nodes(cmark_node *root) {
  76. if (root == NULL) {
  77. return;
  78. }
  79. cmark_iter *iter = cmark_iter_new(root);
  80. cmark_strbuf buf = CMARK_BUF_INIT(iter->mem);
  81. cmark_event_type ev_type;
  82. cmark_node *cur, *tmp, *next;
  83. while ((ev_type = cmark_iter_next(iter)) != CMARK_EVENT_DONE) {
  84. cur = cmark_iter_get_node(iter);
  85. if (ev_type == CMARK_EVENT_ENTER && cur->type == CMARK_NODE_TEXT &&
  86. cur->next && cur->next->type == CMARK_NODE_TEXT) {
  87. cmark_strbuf_clear(&buf);
  88. cmark_strbuf_put(&buf, cur->as.literal.data, cur->as.literal.len);
  89. tmp = cur->next;
  90. while (tmp && tmp->type == CMARK_NODE_TEXT) {
  91. cmark_iter_next(iter); // advance pointer
  92. cmark_strbuf_put(&buf, tmp->as.literal.data, tmp->as.literal.len);
  93. cur->end_column = tmp->end_column;
  94. next = tmp->next;
  95. cmark_node_free(tmp);
  96. tmp = next;
  97. }
  98. cmark_chunk_free(iter->mem, &cur->as.literal);
  99. cur->as.literal = cmark_chunk_buf_detach(&buf);
  100. }
  101. }
  102. cmark_strbuf_free(&buf);
  103. cmark_iter_free(iter);
  104. }