#include "../lib/io/io.h" #include "../lib/sys/sizes.h" #include "../lib/tctl/tctl.h" #include "../lib/aec/aec.h" #define TOGGLE(mask, type, sgron, sgroff) \ if (mask & type) { \ mask ^= type; \ wstdf("%S", sgroff); \ } else { \ mask |= type; \ wstdf("%S", sgron); \ } u16 heading_numbers[6] = { 0 }; window_size_t ws; u8 left_padding; u8 MAX_WIDTH = 80; enum Style { ITALIC = 1, BOLD = 2, STRIKETROUGH = 4, MARKED = 8, }; void put_leftpadding() { for (int i = 0; i < left_padding; ++i) { putchar(' '); } } void wstdp(const char *buf) { for (; *buf; ++buf) { putchar(*buf); if (*buf == '\n') put_leftpadding(); } } void next_heading(int type) { heading_numbers[type]++; for (int i = type + 1; i < 5; ++i) heading_numbers[i] = 0; } void show_box() { char c; u8 width = 0; read(STDIN_FD, &c, 1); read(STDIN_FD, &c, 1); read(STDIN_FD, &c, 1); u8 use_backup = 0; char backup[3]; wstd("┌"); for (int i = 0; i < MAX_WIDTH - 3; ++i) wstd("─"); wstdp("┐\n│ "); while (use_backup || read(STDIN_FD, &c, 1)) { if (use_backup) { c = backup[3 - use_backup]; use_backup--; } if (c == '\n') { for (int i = width + 1; i < MAX_WIDTH - 4; ++i) wstd(" "); width = 0; read(STDIN_FD, backup, 3); if (backup[0] == '`' && backup[1] == '`' && backup[2] == '`') break; use_backup = 3; wstdp(" │\n│ "); } else { ++width; if (width == MAX_WIDTH - 4) { wstdp(" │\n│ "); width = 1; } putchar(c); } } wstdp(" │\n└"); for (int i = 0; i < MAX_WIDTH - 3; ++i) wstd("─"); wstdp("┘\n\n"); } void show_and_replace_leading_char(char leading, char *replace) { char c; u8 last_was_newline = 0; wstdf(" %s", replace); while (read(STDIN_FD, &c, 1)) { if (c == '\n') { if (last_was_newline) break; last_was_newline = 1; wstdp("\n "); } else { last_was_newline = 0; if (c == leading) wstd(replace); else putchar(c); } } wstdp("\n"); } void show_numbered_list() { char c; u8 last_was_newline = 0; read(STDIN_FD, &c, 1); wstd(" 1."); while (read(STDIN_FD, &c, 1)) { if (c == '\n') { if (last_was_newline) break; last_was_newline = 1; wstdp("\n "); } else { last_was_newline = 0; putchar(c); } } wstdp("\n"); } void show_paragraph() { u8 last_was_newline = 0; char c; u8 width = 1; u8 markup_mask = 0; while (read(STDIN_FD, &c, 1)) { if (c == '\n') { if (last_was_newline) break; last_was_newline = 1; } else { last_was_newline = 0; if (width == MAX_WIDTH) { wstdp("\n"); width = 0; } switch (c) { case '*': read(STDIN_FD, &c, 1); if (c == '*') { TOGGLE(markup_mask, BOLD, SGR_BOLD, SGR_INTENSITY_OFF); } else { TOGGLE(markup_mask, ITALIC, SGR_ITALIC, SGR_ITALIC_OFF); if (c == '\n') { last_was_newline = 1; } else { putchar(c); } } break; case '~': TOGGLE(markup_mask, STRIKETROUGH, SGR_CROSSED_OUT, SGR_CROSSED_OUT_OFF); break; case '`': TOGGLE(markup_mask, MARKED, SGR_REVERSE, SGR_REVERSE_OFF); break; default: putchar(c); break; } ++width; } } wstdf("\n\n%S", SGR_RESET); put_leftpadding(); } void show_heading() { u8 heading_type = 1; char c; while (read(STDIN_FD, &c, 1) && c == '#') heading_type++; if (heading_type > 5) heading_type = 5; next_heading(heading_type - 1); wstdf("%S%i", SGR_FAINT, heading_numbers[0]); for (int i = 1; heading_numbers[i]; ++i) wstdf(".%i", heading_numbers[i]); wstdf("%S ", SGR_RESET); wstdf("%S", SGR_BOLD); if (c != ' ') putchar(c); while (read(STDIN_FD, &c, 1) && c != '\n') putchar(c); wstdf("\n\n%S", SGR_RESET); put_leftpadding(); } int main(int argc, char **argv) { if (argc != 1) { wf(STDERR_FD, "mdv\n"); return -1; } ws = tctl_get_fd_window_size(STDERR_FD); if (ws.width < MAX_WIDTH) MAX_WIDTH = ws.width; left_padding = (ws.width - MAX_WIDTH) / 2; char c; put_leftpadding(); while (read(STDIN_FD, &c, 1)) { switch(c) { case '\n': break; case '#': show_heading(); break; case '1': show_numbered_list(); break; case '`': show_box(); break; case '-': show_and_replace_leading_char('-', "•"); break; case '>': show_and_replace_leading_char('>', "│"); break; default: putchar(c); show_paragraph(); } } putchar('\n'); return 0; }