QUOTE: Life is a journey, not a destination.

poet

A terminal-based blogging interface

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
     11char *POET_DB = NULL;
     12
     13bool 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
     41bool 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
     53int 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}