#include "ecex.h" #define MD_TEXT_TITLE 1 typedef struct md_state { ecex_t *ed; } md_state_t; static int md_render(ecex_t *ed, buffer_t *buffer, ecex_draw_context_t *ctx, void *userdata) { md_state_t *state = (md_state_t *)userdata; int draw_count; int line_count; int scroll; int y; int h; int line_h; int in_code = 0; int i; if (!ed || !buffer || !ctx || !state) return 0; draw_count = ecex_var_i32(ed, state, "draw_count", 0) + 1; ecex_var_i32_set_scalar(ed, state, "draw_count", draw_count); if (draw_count <= 2 || (draw_count % 120) == 0) { ecex_log_int("markdown_plugin_draw: count=", draw_count); } line_count = ecex_buffer_line_count_i(buffer); ecex_log_int("markdown_plugin_draw: line_count=", line_count); if (line_count < 0) line_count = 0; ecex_text_set_buffer_title(ed, state, MD_TEXT_TITLE, buffer); ecex_draw_markdown_canvas_auto_i(ctx, state, MD_TEXT_TITLE); y = ecex_markdown_body_y_i(ctx); h = ecex_draw_context_height_i(ctx); line_h = ecex_draw_context_line_height_i(ctx); scroll = ecex_buffer_scroll_line(buffer); if (scroll < 0) scroll = 0; if (scroll > line_count) scroll = line_count; for (i = scroll; i < line_count && y < h - line_h; ++i) { int packed; int advance; if (i < scroll + 4) ecex_log_int("markdown_plugin_draw: host line=", i); packed = ecex_markdown_draw_line_from_buffer_i(ctx, state, buffer, i, y, in_code); in_code = (packed & 0x10000) ? 1 : 0; advance = packed & 0xffff; if (advance <= 0) advance = line_h; y += advance; } return 0; } static void md_free_state(void *userdata) { md_state_t *state = (md_state_t *)userdata; ecex_t *ed; if (!state) return; ed = state->ed; ecex_text_free_owner(ed, state); ecex_var_free_owner(ed, state); ecex_object_free(ed, state); } static int md_view_buffer(ecex_t *ed, buffer_t *buffer) { md_state_t *state; if (!ed || !buffer) return -1; if (ecex_buffer_has_renderer(buffer)) ecex_buffer_clear_renderer(buffer); state = (md_state_t *)ecex_object_calloc(ed, 1, sizeof(*state)); if (!state) return -1; state->ed = ed; if (ecex_buffer_set_renderer(buffer, md_render, state, md_free_state, ECEX_RENDER_REPLACE_CONTENT) != 0) { ecex_object_free(ed, state); return -1; } ecex_buffer_set_major_mode_by_name(ed, buffer, "markdown-mode"); return 0; } static int md_file_handler(ecex_t *ed, buffer_t *buffer) { if (!buffer) return -1; if (ecex_buffer_has_renderer(buffer)) return 0; return md_view_buffer(ed, buffer); } static int cmd_markdown_view(ecex_t *ed) { return md_view_buffer(ed, ecex_current_buffer(ed)); } static int cmd_markdown_source(ecex_t *ed) { buffer_t *buffer = ecex_current_buffer(ed); if (!buffer) return -1; if (ecex_buffer_has_renderer(buffer)) ecex_buffer_clear_renderer(buffer); ecex_buffer_set_major_mode_by_name(ed, buffer, "markdown-mode"); return 0; } static int cmd_markdown_toggle(ecex_t *ed) { buffer_t *buffer = ecex_current_buffer(ed); if (!buffer) return -1; if (ecex_buffer_has_renderer(buffer)) return cmd_markdown_source(ed); return md_view_buffer(ed, buffer); } int ecex_markdown_plugin(ecex_t *ed) { ECEX_CONFIG_MODE("markdown-mode"); ECEX_CONFIG_COMMAND("markdown-view", cmd_markdown_view); ECEX_CONFIG_COMMAND("markdown-source", cmd_markdown_source); ECEX_CONFIG_COMMAND("markdown-toggle", cmd_markdown_toggle); ECEX_CONFIG_MODE_BIND("markdown-mode", "C-c C-c", "markdown-toggle"); ECEX_CONFIG_MODE_BIND("markdown-mode", "C-c C-s", "markdown-source"); ecex_register_file_handler(ed, ".md", md_file_handler); ecex_register_file_handler(ed, ".markdown", md_file_handler); ecex_register_file_handler(ed, ".mdown", md_file_handler); ecex_register_file_handler(ed, ".mkd", md_file_handler); return 0; } #ifndef ECEX_NO_STANDALONE_CONFIG ECEX_CONFIG_BEGIN ECEX_CONFIG_INCLUDE(ecex_markdown_plugin); ECEX_CONFIG_END #endif