NEWS: Welcome to my new homepage! <3

main.c - poet - A terminal-based blogging interface

poet

A terminal-based blogging interface
git clone git://192.168.2.2/poet
Log | Files | Refs | README

main.c (4846B)


      1 #include <stdio.h>
      2 #include <stdlib.h>
      3 #include <libterm.h>
      4 
      5 #include "util.h"
      6 #include "post.h"
      7 #include "edit.h"
      8 
      9 #define UNUSED(x) (void)(x)
     10 
     11 char *POET_DB = NULL;
     12 
     13 bool do_edit_post(int id) {
     14   post_t *post = db_post_get(POET_DB, id);
     15   char filename[100];
     16   snprintf(filename, 100, "poet-%d.md", post->id);
     17   edit_write(filename, post);
     18   term_write("\x1b[?25h");
     19   term_flush();
     20   char *editor = getenv("EDITOR");
     21   if (editor == NULL) {
     22     editor = "vim";
     23   }
     24   char command[200];
     25   snprintf(command, 200, "%s %s", editor, filename);
     26   system(command);
     27   term_write("\x1b[?25l");
     28   term_write("\x1b[?1049h");
     29   term_flush();
     30   post_t *changes = NULL;
     31   edit_read(filename, &changes);
     32   bool changed = post_changed(post, changes);
     33   if (changed) {
     34     db_post_update(POET_DB, id, post, changes);
     35   }
     36   post_free(changes);
     37   post_free(post);
     38   return changed;
     39 }
     40 
     41 bool do_toggle_post(int id) {
     42   post_t *post = db_post_get(POET_DB, id);
     43   post_t *changes = malloc(sizeof(post_t));
     44   post_init(changes);
     45   changes->is_public = malloc(sizeof(bool));
     46   *changes->is_public = !*post->is_public;
     47   db_post_update(POET_DB, post->id, post, changes);
     48   post_free(changes);
     49   post_free(post);
     50   return true;
     51 }
     52 
     53 int main(void) {
     54   POET_DB = getenv("POET_DB");
     55   if (POET_DB == NULL) {
     56     printf("Environment variable 'POET_DB' needs to be set!\n");
     57     return 1;
     58   }
     59   term_enable_raw_mode();
     60   term_write("\x1b[?25l");
     61   term_write("\x1b[?1049h");
     62   bool quit = false;
     63   bool update = true;
     64   bool render = true;
     65   int index = 0;
     66   int offset = 0;
     67   int height = 0;
     68   post_result_t *post_result = NULL;
     69   while (!quit) {
     70     int rows = 0;
     71     int cols = 0;
     72     term_read_window_size(&rows, &cols);
     73     if (rows - 4 != height) {
     74       if (index > rows - 4) {
     75         offset = index - (rows - 4) + 1;
     76       }
     77       else {
     78         offset = 0;
     79       }
     80       render = true;
     81     }
     82     height = rows - 4;
     83     if (update) {
     84       post_result = db_post_search(POET_DB, "");
     85       update = false;
     86     }
     87     if (render) {
     88       term_write("\x1b[H");
     89       term_write("\x1b[K\r\n    q = quit, j/k = move, g = goto, n = create, i = edit, d = delete, x = public/private\x1b[K\r\n\x1b[K\r\n");
     90       for (int i = 0; i < post_result->len; i++) {
     91         if (i == height) {
     92           break;
     93         }
     94         post_t *post = &post_result->result[i + offset];
     95         if (i + offset == index) {
     96           term_write(" \x1b[38;2;255;221;71m>>\x1b[39m ");
     97         }
     98         else {
     99           term_write("    ");
    100         }
    101         if (*post->is_public) {
    102           term_writef("\x1b[38;2;255;255;255m%s\x1b[39m", post->title);
    103         }
    104         else {
    105           term_writef("%s", post->title);
    106         }
    107         char *date = util_format_json_date(post->date, "%Y-%m-%d");
    108         term_writef(" \x1b[38;2;124;182;84m(%s)\x1b[39m\x1b[K\r\n", date);
    109         free(date);
    110       }
    111       term_write("\x1b[J");
    112       term_flush();
    113       render = false;
    114     }
    115     int c = term_poll_key(500);
    116     switch (c) {
    117       case 'q': {
    118         quit = true;
    119         break;
    120       }
    121       case 'j': {
    122         if (index + 1 < post_result->len) {
    123           index++;
    124           if (index - offset == height) {
    125             offset++;
    126           }
    127           render = true;
    128         }
    129         break;
    130       }
    131       case 'k': {
    132         if (index > 0) {
    133           index--;
    134           if (index < offset) {
    135             offset--;
    136           }
    137           render = true;
    138         }
    139         break;
    140       }
    141       case 'i': {
    142         if (do_edit_post(post_result->result[index].id)) {
    143           update = true;
    144         }
    145         render = true;
    146         break;
    147       }
    148       case 'd': {
    149         // TODO delete
    150         break;
    151       }
    152       case 'n': {
    153         // TODO create
    154         break;
    155       }
    156       case '/': {
    157         // TODO search
    158         break;
    159       }
    160       case 'x': {
    161         if (do_toggle_post(post_result->result[index].id)) {
    162           update = true;
    163           render = true;
    164         }
    165         break;
    166       }
    167       case 'g': {
    168         int c = term_read_key();
    169         switch (c) {
    170           case 'e': {
    171             if (post_result->len > 1) {
    172               index = post_result->len - 1;
    173               if (index > height) {
    174                 offset = index - height + 1;
    175               }
    176             }
    177             else {
    178               index = 0;
    179               offset = 0;
    180             }
    181             render = true;
    182             break;
    183           }
    184           case 'g': {
    185             index = 0;
    186             offset = 0;
    187             render = true;
    188             break;
    189           }
    190           default:
    191             break;
    192         }
    193         break;
    194       }
    195       default:
    196         break;
    197     }
    198   }
    199   if (post_result != NULL) {
    200     post_result_free(post_result);
    201   }
    202   term_write("\x1b[3J");
    203   term_write("\x1b[2J");
    204   term_write("\x1b[?25h");
    205   term_write("\x1b[H");
    206   term_write("\x1b[?1049l");
    207   term_flush();
    208   return 0;
    209 }