shithub: orca

Download patch

ref: 6489ad6faa5679bfd5847c65ba3d2077d5491c11
parent: 6d7bb8930001936708e7cb47abfaa130c8e87dfc
author: cancel <cancel@cancel.fm>
date: Sun Dec 2 14:15:19 EST 2018

Add undo to tui

--- a/tui_main.c
+++ b/tui_main.c
@@ -185,6 +185,96 @@
   waddchnstr(win, &ch, 1);
 }
 
+typedef struct Field_pool_node {
+  Field field;
+  struct Field_pool_node* next;
+} Field_pool_node;
+
+typedef struct {
+  Field_pool_node* head;
+  Usz count;
+} Field_pool;
+
+void field_pool_take(Field_pool* pool, Field* out) {
+  (void)pool;
+  (void)out;
+}
+void field_pool_give(Field_pool* pool, Field* given) {
+  (void)pool;
+  (void)given;
+}
+
+typedef struct Undo_node {
+  Field field;
+  Usz tick_num;
+  struct Undo_node* prev;
+  struct Undo_node* next;
+} Undo_node;
+
+typedef struct {
+  Undo_node* first;
+  Undo_node* last;
+  Usz count;
+} Undo_history;
+
+void undo_history_init(Undo_history* hist) {
+  hist->first = NULL;
+  hist->last = NULL;
+}
+void undo_history_deinit(Undo_history* hist) {
+  Undo_node* a = hist->first;
+  while (a) {
+    Undo_node* b = a->next;
+    field_deinit(&a->field);
+    free(a);
+    a = b;
+  }
+}
+
+void undo_history_push(Undo_history* hist, Field* field, Usz tick_num) {
+  Undo_node* new_node = malloc(sizeof(Undo_node));
+  field_init(&new_node->field);
+  field_resize_raw(&new_node->field, field->height, field->width);
+  field_copy_subrect(field, &new_node->field, 0, 0, 0, 0, field->height,
+                     field->width);
+  new_node->tick_num = tick_num;
+  if (hist->last) {
+    hist->last->next = new_node;
+    new_node->prev = hist->last;
+  } else {
+    hist->first = new_node;
+    hist->last = new_node;
+    new_node->prev = NULL;
+  }
+  new_node->next = NULL;
+  hist->last = new_node;
+}
+
+void undo_history_pop(Undo_history* hist, Field* out_field, Usz* out_tick_num) {
+  Undo_node* last = hist->last;
+  if (!last)
+    return;
+  Usz height = last->field.height;
+  Usz width = last->field.width;
+  if (out_field->height != height || out_field->width != width) {
+    field_resize_raw(out_field, height, width);
+  }
+  field_copy_subrect(&last->field, out_field, 0, 0, 0, 0, height, width);
+  *out_tick_num = last->tick_num;
+  if (hist->first == last) {
+    hist->first = NULL;
+    hist->last = NULL;
+  } else {
+    Undo_node* new_last = last->prev;
+    new_last->next = NULL;
+    hist->last = new_last;
+  }
+  field_deinit(&last->field);
+  free(last);
+}
+
+bool undo_history_count(Undo_history* hist) { return hist->count; }
+
 void draw_ui_bar(WINDOW* win, int win_y, int win_x, const char* filename,
                  Usz tick_num) {
   wmove(win, win_y, win_x);
@@ -287,6 +377,8 @@
   mbuffer_clear(markmap_r.buffer, field.height, field.width);
   Bank bank;
   bank_init(&bank);
+  Undo_history undo_hist;
+  undo_history_init(&undo_hist);
 
   // Enable UTF-8 by explicitly initializing our locale before initializing
   // ncurses.
@@ -382,18 +474,26 @@
     case KEY_RIGHT:
       tui_cursor_move_relative(&tui_cursor, field.height, field.width, 0, 1);
       break;
+    case AND_CTRL('u'):
+      if (undo_history_count(&undo_hist) > 0) {
+        undo_history_pop(&undo_hist, &field, &tick_num);
+      }
+      break;
     case ' ':
+      undo_history_push(&undo_hist, &field, tick_num);
       orca_run(field.buffer, markmap_r.buffer, field.height, field.width,
                tick_num, &bank);
       ++tick_num;
       break;
+    default:
+      if (key >= '!' && key <= '~') {
+        undo_history_push(&undo_hist, &field, tick_num);
+        gbuffer_poke(field.buffer, field.height, field.width, tui_cursor.y,
+                     tui_cursor.x, (char)key);
+      }
+      break;
     }
 
-    if (key >= '!' && key <= '~') {
-      gbuffer_poke(field.buffer, field.height, field.width, tui_cursor.y,
-                   tui_cursor.x, (char)key);
-    }
-
     // ncurses gives us the special value KEY_RESIZE if the user didn't
     // actually type anything, but the terminal resized.
     // bool ignored_input = ch < CHAR_MIN || ch > CHAR_MAX || ch == KEY_RESIZE;
@@ -403,5 +503,6 @@
   markmap_reusable_deinit(&markmap_r);
   bank_deinit(&bank);
   field_deinit(&field);
+  undo_history_deinit(&undo_hist);
   return 0;
 }