aboutsummaryrefslogtreecommitdiff
path: root/core/mdv.c
diff options
context:
space:
mode:
Diffstat (limited to 'core/mdv.c')
-rw-r--r--core/mdv.c238
1 files changed, 238 insertions, 0 deletions
diff --git a/core/mdv.c b/core/mdv.c
new file mode 100644
index 0000000..25b7b28
--- /dev/null
+++ b/core/mdv.c
@@ -0,0 +1,238 @@
+#include "../lib/io/io.h"
+#include "../lib/sys/sizes.h"
+#include "../lib/tctl/tctl.h"
+#include "../lib/aec/aec.h"
+
+#define MAX_WIDTH 80
+
+#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;
+
+enum Style {
+ ITALIC = 1,
+ BOLD = 2,
+ STRIKETROUGH = 4,
+ MARKED = 8,
+};
+
+
+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("─");
+ wstd("┐\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;
+
+ wstd(" │\n│ ");
+ } else {
+ ++width;
+
+ if (width == MAX_WIDTH - 4) {
+ wstd(" │\n│ ");
+ width = 1;
+ }
+
+ putchar(c);
+ }
+ }
+
+ wstd(" │\n└");
+ for (int i = 0; i < MAX_WIDTH - 3; ++i) wstd("─");
+ wstd("┘\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;
+ wstd("\n ");
+ } else {
+ last_was_newline = 0;
+
+ if (c == leading)
+ wstd(replace);
+ else
+ putchar(c);
+ }
+ }
+
+ wstd("\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;
+ wstd("\n ");
+ } else {
+ last_was_newline = 0;
+ putchar(c);
+ }
+ }
+
+ wstd("\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) {
+ wstd("\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);
+}
+
+
+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);
+}
+
+int main(int argc, char **argv)
+{
+ if (argc != 1) {
+ wf(STDERR_FD, "mdv\n");
+ return -1;
+ }
+
+ ws = tctl_get_window_size();
+
+ char c;
+
+ 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();
+ }
+ }
+
+ return 0;
+}