about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorJames Booth <boothj5@gmail.com>2012-04-30 02:36:45 +0100
committerJames Booth <boothj5@gmail.com>2012-04-30 02:36:45 +0100
commitf21cb52ab025cfe1bc90226d7bb433fc775d390e (patch)
treec98e3f6a58c1e3a3f121800643cd70429d4dd2f5
parentb6c5fef45eaadce4463ee60e60eb0a0252b61255 (diff)
downloadprofani-tty-f21cb52ab025cfe1bc90226d7bb433fc775d390e.tar.gz
Create history session
-rw-r--r--prof_history.c108
-rw-r--r--prof_history.h4
-rw-r--r--test_prof_history.c64
3 files changed, 137 insertions, 39 deletions
diff --git a/prof_history.c b/prof_history.c
index 3aca0150..24213140 100644
--- a/prof_history.c
+++ b/prof_history.c
@@ -8,16 +8,23 @@
 
 struct p_history_t {
     GList *items; // the history
+    GList *items_curr; // pointer to the current line in the history
     GList *session; // a copy of the history for edits
-    GList *session_current; // pointer to the current item in the session
+    GList *sess_curr; // pointer to the current item in the session
+    GList *sess_new; // pointer to a possible new element in the session
     guint max_size;
 };
 
+static void _replace_history_with_session(PHistory history);
+
 PHistory p_history_new(unsigned int size)
 {
     PHistory new_history = malloc(sizeof(struct p_history_t));
     new_history->items = NULL;
+    new_history->items_curr = NULL;
     new_history->session = NULL;
+    new_history->sess_curr = NULL;
+    new_history->sess_new = NULL;
     new_history->max_size = size;
 
     return new_history;
@@ -26,66 +33,111 @@ PHistory p_history_new(unsigned int size)
 void p_history_append(PHistory history, char *item)
 {
     char *copied = strdup(item);
-    // if already at max size
-    if (g_list_length(history->items) == history->max_size) {
 
-        // remove first element
+    // if not editing history (no session)
+    if (history->session == NULL) {
+        
+        // if already at max size
+        if (g_list_length(history->items) == history->max_size) {
+
+            // remove first element
+            GList *first = g_list_first(history->items);
+            const char *first_item = (char *) first->data;
+            history->items = g_list_remove(history->items, first_item);
+        }
+    
+        // append the new item onto the history
+        history->items = g_list_append(history->items, copied);
+
+    // if editing history (session exists with possible changes)
+    } else {
+        
+        // if adding a new element, copy the session over the history
+        if (history->sess_curr == history->sess_new) {
+            _replace_history_with_session(history);
+
+        // otherwise, adding edited history item
+        } else {
+            // remove the new item, from the session
+            history->session = g_list_reverse(history->session);
+            GList *first = g_list_first(history->session);
+            const char *first_item = (char *) first->data;
+            history->session = g_list_remove(history->session, first_item);
+            history->session = g_list_reverse(history->session);
+
+            // copy sess_curr to the end of the session
+            char *new_data = strdup(history->sess_curr->data);
+            history->session = g_list_append(history->session, new_data);
+
+            // replace the edited version with the data from the history
+            history->sess_curr->data = strdup(history->items_curr->data);
+            
+            // rewrite history from the session
+            _replace_history_with_session(history);
+        }
+    }
+}
+
+static void _replace_history_with_session(PHistory history)
+{
+    g_list_free(history->items);
+    history->items = g_list_copy(history->session);
+    
+    // remove first if overrun max size
+    if (g_list_length(history->items) > history->max_size) {
         GList *first = g_list_first(history->items);
         const char *first_item = (char *) first->data;
         history->items = g_list_remove(history->items, first_item);
     }
     
-    // append the new item onto the history
-    history->items = g_list_append(history->items, copied);
-
-    // delete the current session
-    if (history->session != NULL) {
-        g_list_free(history->session);
-        history->session = NULL;
-    }
+    // reset the session
+    history->items_curr = NULL;
+    history->session = NULL;
+    history->sess_curr = NULL;
+    history->sess_new = NULL;
 }
 
-char * p_history_previous(PHistory history)
+char * p_history_previous(PHistory history, char *item)
 {
     if (history->items == NULL) {
-        return NULL;
+        return item;
     }
 
     if (history->session == NULL) {
         history->session = g_list_copy(history->items);
-        history->session_current = g_list_last(history->session);
+        history->sess_curr = g_list_last(history->session);
     } else {
-        history->session_current = g_list_previous(history->session_current);
+        history->sess_curr = g_list_previous(history->sess_curr);
     }
 
     // set to first if rolled over beginning
-    if (history->session_current == NULL) {
-        history->session_current = g_list_first(history->session);
+    if (history->sess_curr == NULL) {
+        history->sess_curr = g_list_first(history->session);
     }
 
-    char *item = (char *) history->session_current->data;
-    char *result = malloc((strlen(item) + 1) * sizeof(char));
-    strcpy(result, item);
+    char *curr = history->sess_curr->data;
+    char *result = malloc((strlen(curr) + 1) * sizeof(char));
+    strcpy(result, curr);
 
     return result;
 }
 
-char * p_history_next(PHistory history)
+char * p_history_next(PHistory history, char *item)
 {
     if (history->session == NULL) {
         return NULL;
     } else {
-        history->session_current = g_list_next(history->session_current);
+        history->sess_curr = g_list_next(history->sess_curr);
     }
 
     // set to last if rolled over end
-    if (history->session_current == NULL) {
-        history->session_current = g_list_last(history->session);
+    if (history->sess_curr == NULL) {
+        history->sess_curr = g_list_last(history->session);
     }
 
-    char *item = (char *) history->session_current->data;
-    char *result = malloc((strlen(item) + 1) * sizeof(char));
-    strcpy(result, item);
+    char *curr = history->sess_curr->data;
+    char *result = malloc((strlen(curr) + 1) * sizeof(char));
+    strcpy(result, curr);
 
     return result;
 }
diff --git a/prof_history.h b/prof_history.h
index 5c2acaaf..04c6fdaf 100644
--- a/prof_history.h
+++ b/prof_history.h
@@ -4,8 +4,8 @@
 typedef struct p_history_t  *PHistory;
 
 PHistory p_history_new(unsigned int size);
-char * p_history_previous(PHistory history);
-char * p_history_next(PHistory history);
+char * p_history_previous(PHistory history, char *item);
+char * p_history_next(PHistory history, char *item);
 void p_history_append(PHistory history, char *item);
 
 #endif
diff --git a/test_prof_history.c b/test_prof_history.c
index 5a9ae217..db4ef24b 100644
--- a/test_prof_history.c
+++ b/test_prof_history.c
@@ -2,18 +2,18 @@
 #include <head-unit.h>
 #include "prof_history.h"
 
-void previous_on_empty_returns_null(void)
+void previous_on_empty_returns_current(void)
 {
     PHistory history = p_history_new(10);
-    char *item = p_history_previous(history);
+    char *item = p_history_previous(history, "inp");
 
-    assert_is_null(item);
+    assert_string_equals("inp", item);
 }
 
 void next_on_empty_returns_null(void)
 {
     PHistory history = p_history_new(10);
-    char *item = p_history_next(history);
+    char *item = p_history_next(history, "inp");
 
     assert_is_null(item);
 }
@@ -23,7 +23,7 @@ void previous_once_returns_last(void)
     PHistory history = p_history_new(10);
     p_history_append(history, "Hello");
 
-    char *item = p_history_previous(history);
+    char *item = p_history_previous(history, "inp");
 
     assert_string_equals("Hello", item);
 }
@@ -33,17 +33,63 @@ void previous_twice_when_one_returns_first(void)
     PHistory history = p_history_new(10);
     p_history_append(history, "Hello");
 
-    p_history_previous(history);
-    char *item = p_history_previous(history);
+    char *item1 = p_history_previous(history, NULL);
+    char *item2 = p_history_previous(history, item1);
 
-    assert_string_equals("Hello", item);
+    assert_string_equals("Hello", item2);
+}
+
+void previous_always_stops_at_first(void)
+{
+    PHistory history = p_history_new(10);
+    p_history_append(history, "Hello");
+
+    char *item1 = p_history_previous(history, NULL);
+    char *item2 = p_history_previous(history, item1);
+    char *item3 = p_history_previous(history, item2);
+    char *item4 = p_history_previous(history, item3);
+    char *item5 = p_history_previous(history, item4);
+    char *item6 = p_history_previous(history, item5);
+
+    assert_string_equals("Hello", item6);
+}
+
+void previous_goes_to_correct_element(void)
+{
+    PHistory history = p_history_new(10);
+    p_history_append(history, "Hello");
+    p_history_append(history, "world");
+    p_history_append(history, "whats");
+    p_history_append(history, "going");
+    p_history_append(history, "on");
+    p_history_append(history, "here");
+
+    char *item1 = p_history_previous(history, NULL);
+    char *item2 = p_history_previous(history, item1);
+    char *item3 = p_history_previous(history, item2);
+    
+    assert_string_equals("going", item3); 
+}
+
+void prev_then_next_returns_null(void)
+{
+    PHistory history = p_history_new(10);
+    p_history_append(history, "Hello");
+
+    char *item1 = p_history_previous(history, NULL);
+    char *item2 = p_history_next(history, item1);
+
+    assert_is_null(item2);
 }
 
 void register_prof_history_tests(void)
 {
     TEST_MODULE("prof_history tests");
-    TEST(previous_on_empty_returns_null);
+    TEST(previous_on_empty_returns_current);
     TEST(next_on_empty_returns_null);
     TEST(previous_once_returns_last);
     TEST(previous_twice_when_one_returns_first);
+    TEST(previous_always_stops_at_first);
+    TEST(previous_goes_to_correct_element);
+    TEST(prev_then_next_returns_null);
 }