]> git.mdlowis.com Git - projs/tide.git/commitdiff
refactored undo/redo into editlog.c
authorMichael D. Lowis <mike@mdlowis.com>
Thu, 17 Oct 2019 01:11:15 +0000 (21:11 -0400)
committerMichael D. Lowis <mike@mdlowis.com>
Thu, 17 Oct 2019 01:11:15 +0000 (21:11 -0400)
inc/edit.h
src/lib/buf.c
src/lib/editlog.c [new file with mode: 0644]
src/lib/gapbuf.c

index d351f3cbb98e50d9eed618c4759aed4e3e0ba9a3..f8eaf5042c6d676c61863bc458ef2a9583d3ee12 100644 (file)
@@ -17,13 +17,20 @@ typedef struct {
 } Sel;
 
 typedef struct {
-    size_t bufsize;   /* size of the buffer in runes */
-    char* bufstart;   /* start of the data buffer */
-    char* bufend;     /* end of the data buffer */
-    char* gapstart;   /* start of the gap */
-    char* gapend;     /* end of the gap */
+    size_t bufsize; /* size of the buffer in runes */
+    char* bufstart; /* start of the data buffer */
+    char* bufend;   /* end of the data buffer */
+    char* gapstart; /* start of the gap */
+    char* gapend;   /* end of the gap */
 } GapBuf;
 
+typedef struct {
+    int transid; /* id number of the current transaction */
+    Log* undo;   /* undo list */
+    Log* redo;   /* redo list */
+    Log* save;   /* pointer to last save position */
+} EditLog;
+
 /* gap buffer main data structure */
 typedef struct {
     enum {
@@ -31,10 +38,13 @@ typedef struct {
     } status;
     char* path;       /* the path to the open file */
     GapBuf contents;  /* underlying sequence data structure */
-    Log* undo;        /* undo list */
-    Log* redo;        /* redo list */
-    Log* save;        /* pointer to last save position */
-    int transid;      /* id number of the current transaction */
+    EditLog log;      /* underlying log of edit operations */
+
+    int transid; /* id number of the current transaction */
+    Log* undo;   /* undo list */
+    Log* redo;   /* redo list */
+    Log* save;   /* pointer to last save position */
+
     Sel selection;    /* the currently selected text */
 } Buf;
 
@@ -46,6 +56,14 @@ char gapbuf_getb(GapBuf* buf, size_t off);
 void gapbuf_putb(GapBuf* buf, char b, Sel* p_sel);
 void gapbuf_del(GapBuf* buf, size_t off, size_t len);
 
+void editlog_seqstart(Buf* log);
+void editlog_seqstop(Buf* log);
+void editlog_clear(Buf* log);
+void editlog_lastins(Buf* buf, Sel* p_sel);
+void editlog_undo(Buf* log);
+void editlog_redo(Buf* log);
+void editlog_add(Buf* buf, size_t beg, size_t end, char* data);
+
 void buf_init(Buf* buf);
 void buf_setpath(Buf* buf, char* path);
 void buf_load(Buf* buf, char* path);
@@ -61,12 +79,12 @@ char* buf_gets(Buf* buf);
 char* buf_getsat(Buf* buf, size_t beg, size_t end);
 void buf_del(Buf* buf);
 
-void buf_undo(Buf* buf);
-void buf_redo(Buf* buf);
 void buf_logstart(Buf* buf);
 void buf_logstop(Buf* buf);
 void buf_logclear(Buf* buf);
 void buf_lastins(Buf* buf);
+void buf_undo(Buf* buf);
+void buf_redo(Buf* buf);
 
 bool buf_isbol(Buf* buf, size_t pos);
 bool buf_iseol(Buf* buf, size_t pos);
index 5402c6b3c96f94f2febebd0bc0213c3a555e939c..7ee3da5310dd1950b82771c213c0c73f5b74ac36 100644 (file)
@@ -187,213 +187,34 @@ int buf_save(Buf* buf, char* path)
 
 /* Undo/Redo Operations
  ******************************************************************************/
-static Log* mklog(Buf* buf, size_t beg, size_t end, char* data, Log* next)
-{
-    Log* log = calloc(1, sizeof(Log));
-    log->transid = (buf->transid < 0 ? 0 : buf->transid);
-    log->beg = beg;
-    log->end = end;
-    log->data = data;
-    log->next = next;
-    return log;
-}
-
-static void log_clear(Log** list)
-{
-    while (*list)
-    {
-        Log* deadite = *list;
-        *list = (*list)->next;
-        if (deadite->data)
-        {
-            free(deadite->data);
-        }
-        free(deadite);
-    }
-}
-
-static void dumplog(Buf* buf)
-{
-#ifdef LOG_DUMPING
-    printf("\nUndo:\n");
-    for (Log* log = buf->undo; log; log = log->next)
-    {
-        printf("    (%d) %lu-%lu '%s'\n", log->transid, log->beg, log->end, log->data);
-    }
-    printf("Redo:\n");
-    for (Log* log = buf->redo; log; log = log->next)
-    {
-        printf("    (%d) %lu-%lu '%s'\n", log->transid, log->beg, log->end, log->data);
-    }
-#else
-    (void)buf;
-#endif
-}
-
-static void log_add(Buf* buf, size_t beg, size_t end, char* data)
-{
-    Log* prev = buf->undo;
-    log_clear(&(buf->redo));
-
-    /* decide if this is an insert or delete */
-    if (!prev || (buf->transid > 0 && buf->transid != prev->transid))
-    {
-        buf->undo = mklog(buf, beg, end, data, prev);
-    }
-    else if (!data && !prev->data && prev->end == beg)
-    {
-        prev->end = end;
-    }
-    else if (prev->data && data && prev->beg == beg)
-    {
-        char* newdata = strmcat(prev->data, data, 0);
-        free(data);
-        free(prev->data);
-        prev->data = newdata;
-    }
-    else if (prev->data && data && prev->beg == beg+1)
-    {
-        char* newdata = strmcat(data, prev->data, 0);
-        free(data);
-        free(prev->data);
-        prev->data = newdata;
-        prev->end = --prev->beg;
-    }
-    else
-    {
-        buf->undo = mklog(buf, beg, end, data, prev);
-    }
-
-    dumplog(buf);
-}
-
-static void log_swap(Buf* buf, Log** src, Log** dest)
-{
-    Log* item = *src;
-    if (item)
-    {
-        *src = item->next;
-        buf->selection.beg = item->beg;
-        buf->selection.end = item->end;
-        if (item->data)
-        {
-            /* reinsert deleted bytes */
-            for (char* s = item->data; s && *s; s++, item->end++)
-            {
-                gapbuf_putb(&buf->contents, *s, &(buf->selection));
-                buf->status = MODIFIED;
-            }
-            free(item->data);
-            item->data = NULL;
-            buf->selection.beg = item->beg;
-            buf->selection.end = item->end;
-       }
-       else
-       {
-            /* delete the added bytes */
-            Sel sel = selget(buf);
-            item->data = buf_gets(buf);
-            gapbuf_del(&buf->contents, sel.beg, (item->end - item->beg));
-            sel.end = sel.beg;
-            buf->selection = sel;
-            item->beg = sel.beg;
-            item->end = sel.end;
-        }
-
-        /* push item onto destination stack */
-        item->next = *dest;
-        *dest = item;
-        /* undo recursively if this is part of a transaction */
-        if (*src && item->transid && item->transid == (*src)->transid)
-        {
-            log_swap(buf, src, dest);
-        }
-        else
-        {
-            dumplog(buf);
-        }
-
-        if (buf->save == buf->undo)
-        {
-            buf->status = NORMAL;
-        }
-    }
-}
-
 void buf_logstart(Buf* buf)
 {
-    require(buf != NULL);
-    buf->transid = abs(buf->transid);
+    editlog_seqstart(buf);
 }
 
 void buf_logstop(Buf* buf)
 {
-    require(buf != NULL);
-    if (buf->transid > 0)
-    {
-        buf->transid = -(buf->transid + 1);
-    }
+    editlog_seqstop(buf);
 }
 
-void buf_undo(Buf* buf)
+void buf_logclear(Buf* buf)
 {
-    require(buf != NULL);
-    log_swap(buf, &(buf->undo), &(buf->redo));
-    ensure(buf_valid(buf));
+    editlog_clear(buf);
 }
 
-void buf_redo(Buf* buf)
+void buf_lastins(Buf* buf)
 {
-    require(buf != NULL);
-    log_swap(buf, &(buf->redo), &(buf->undo));
-    ensure(buf_valid(buf));
+    editlog_lastins(buf, &(buf->selection));
 }
 
-void buf_logclear(Buf* buf)
+void buf_undo(Buf* buf)
 {
-    require(buf != NULL);
-    log_clear(&(buf->redo));
-    log_clear(&(buf->undo));
+    editlog_undo(buf);
 }
 
-void buf_lastins(Buf* buf)
+void buf_redo(Buf* buf)
 {
-    require(buf != NULL);
-    Log* log = buf->undo;
-    if (log)
-    {
-        Sel sel = {.beg = log->beg, .end = log->end };
-        size_t delsize = 0;
-        int transid = log->transid;
-
-        /* try and expand the selected region to encompass related inserts */
-        for (; log && (log->transid == transid); log = log->next)
-        {
-            if (!log->data)
-            {
-                size_t ibeg = log->beg, iend = log->end - delsize;
-                if (iend < ibeg || ibeg > sel.beg || iend < sel.beg)
-                {
-                    break;
-                }
-                if (ibeg < sel.beg && iend > sel.end)
-                {
-                    break;
-                }
-                sel.beg = ibeg, delsize = 0;
-            }
-            else
-            {
-                /* bail if the delete doesnt overlap */
-                if (log->beg != sel.beg)
-                {
-                    break;
-                }
-                delsize = strlen(log->data);
-            }
-        }
-        buf->selection = sel;
-    }
+    editlog_redo(buf);
 }
 
 /* Basic Operations and Accessors
@@ -441,7 +262,7 @@ void buf_puts(Buf* buf, char* s)
         {
             putch(buf, *(s++), &(buf->selection));
         }
-        log_add(buf, beg, buf_selend(buf), NULL);
+        editlog_add(buf, beg, buf_selend(buf), NULL);
     }
     ensure(buf_valid(buf));
 }
@@ -488,7 +309,7 @@ void buf_del(Buf* buf)
         gapbuf_del(&buf->contents, sel.beg, nbytes);
         sel.end = sel.beg = (sel.beg < sel.end ? sel.beg : sel.end);
         buf->selection = sel;
-        log_add(buf, sel.beg, sel.end, str);
+        editlog_add(buf, sel.beg, sel.end, str);
     }
     ensure(buf_valid(buf));
 }
diff --git a/src/lib/editlog.c b/src/lib/editlog.c
new file mode 100644 (file)
index 0000000..ae1467d
--- /dev/null
@@ -0,0 +1,191 @@
+#include <stdc.h>
+#include <dbc.h>
+#include <utf.h>
+#include <edit.h>
+#include "config.h"
+
+static Log* mklog(Buf* buf, size_t beg, size_t end, char* data, Log* next)
+{
+    Log* log = calloc(1, sizeof(Log));
+    log->transid = (buf->transid < 0 ? 0 : buf->transid);
+    log->beg = beg;
+    log->end = end;
+    log->data = data;
+    log->next = next;
+    return log;
+}
+
+static void log_swap(Buf* buf, Log** src, Log** dest)
+{
+    Log* item = *src;
+    if (item)
+    {
+        *src = item->next;
+        buf->selection.beg = item->beg;
+        buf->selection.end = item->end;
+        if (item->data)
+        {
+            /* reinsert deleted bytes */
+            for (char* s = item->data; s && *s; s++, item->end++)
+            {
+                gapbuf_putb(&buf->contents, *s, &(buf->selection));
+                buf->status = MODIFIED;
+            }
+            free(item->data);
+            item->data = NULL;
+            buf->selection.beg = item->beg;
+            buf->selection.end = item->end;
+       }
+       else
+       {
+            /* delete the added bytes */
+            Sel sel = buf->selection;
+            item->data = buf_gets(buf);
+            gapbuf_del(&buf->contents, sel.beg, (item->end - item->beg));
+            sel.end = sel.beg;
+            buf->selection = sel;
+            item->beg = sel.beg;
+            item->end = sel.end;
+        }
+
+        /* push item onto destination stack */
+        item->next = *dest;
+        *dest = item;
+        /* undo recursively if this is part of a transaction */
+        if (*src && item->transid && item->transid == (*src)->transid)
+        {
+            log_swap(buf, src, dest);
+        }
+
+        if (buf->save == buf->undo)
+        {
+            buf->status = NORMAL;
+        }
+    }
+}
+
+static void log_clear(Log** list)
+{
+    while (*list)
+    {
+        Log* deadite = *list;
+        *list = (*list)->next;
+        if (deadite->data)
+        {
+            free(deadite->data);
+        }
+        free(deadite);
+    }
+}
+
+void editlog_seqstart(Buf* buf)
+{
+    require(buf != NULL);
+    buf->transid = abs(buf->transid);
+}
+
+void editlog_seqstop(Buf* buf)
+{
+    require(buf != NULL);
+    if (buf->transid > 0)
+    {
+        buf->transid = -(buf->transid + 1);
+    }
+}
+
+void editlog_clear(Buf* buf)
+{
+    require(buf != NULL);
+    log_clear(&(buf->redo));
+    log_clear(&(buf->undo));
+}
+
+void editlog_lastins(Buf* buf, Sel* p_sel)
+{
+    require(buf != NULL);
+    Log* log = buf->undo;
+    if (log)
+    {
+        Sel sel = { .beg = log->beg, .end = log->end };
+        size_t delsize = 0;
+        int transid = log->transid;
+
+        /* try and expand the selected region to encompass related inserts */
+        for (; log && (log->transid == transid); log = log->next)
+        {
+            if (!log->data)
+            {
+                size_t ibeg = log->beg, iend = log->end - delsize;
+                if (iend < ibeg || ibeg > sel.beg || iend < sel.beg)
+                {
+                    break;
+                }
+                if (ibeg < sel.beg && iend > sel.end)
+                {
+                    break;
+                }
+                sel.beg = ibeg, delsize = 0;
+            }
+            else
+            {
+                /* bail if the delete doesnt overlap */
+                if (log->beg != sel.beg)
+                {
+                    break;
+                }
+                delsize = strlen(log->data);
+            }
+        }
+        *p_sel = sel;
+    }
+}
+
+void editlog_undo(Buf* buf)
+{
+    require(buf != NULL);
+    log_swap(buf, &(buf->undo), &(buf->redo));
+}
+
+void editlog_redo(Buf* buf)
+{
+    require(buf != NULL);
+    log_swap(buf, &(buf->redo), &(buf->undo));
+}
+
+void editlog_add(Buf* buf, size_t beg, size_t end, char* data)
+{
+    Log* prev = buf->undo;
+    log_clear(&(buf->redo));
+
+    /* decide if this is an insert or delete */
+    if (!prev || (buf->transid > 0 && buf->transid != prev->transid))
+    {
+        buf->undo = mklog(buf, beg, end, data, prev);
+    }
+    else if (!data && !prev->data && prev->end == beg)
+    {
+        prev->end = end;
+    }
+    else if (prev->data && data && prev->beg == beg)
+    {
+        char* newdata = strmcat(prev->data, data, 0);
+        free(data);
+        free(prev->data);
+        prev->data = newdata;
+    }
+    else if (prev->data && data && prev->beg == beg+1)
+    {
+        char* newdata = strmcat(data, prev->data, 0);
+        free(data);
+        free(prev->data);
+        prev->data = newdata;
+        prev->end = --prev->beg;
+    }
+    else
+    {
+        buf->undo = mklog(buf, beg, end, data, prev);
+    }
+}
+
+
+
index 869e69281af8cc0679698fb8e0dae5433fe67382..c188242d63627e137f20f4ceef6ff1eee049f96f 100644 (file)
@@ -81,6 +81,7 @@ static void syncgap(GapBuf* buf, size_t off)
 
 void gapbuf_init(GapBuf* buf)
 {
+    require(buf != NULL);
     buf->bufsize   = 8192;
     buf->bufstart  = malloc(buf->bufsize);
     buf->bufend    = buf->bufstart + buf->bufsize;
@@ -90,7 +91,8 @@ void gapbuf_init(GapBuf* buf)
 
 static long writefd(int fd, char* data, long towrite)
 {
-    long nwrite = 0;;
+    require(fd >= 0);
+    long nwrite = 0;
     while (towrite && ((nwrite = write(fd, data, towrite)) > 0))
     {
         data += nwrite;
@@ -101,11 +103,13 @@ static long writefd(int fd, char* data, long towrite)
 
 long gapbuf_save(GapBuf* buf, char* path)
 {
+    require(buf != NULL);
+    require(path != NULL);
     long fd;
-    long nwrite;
+    long nwrite = 0;
     if (path && (fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, 0644)) >= 0)
     {
-        long nwrite = writefd(fd, buf->bufstart, (buf->gapstart - buf->bufstart));
+        nwrite = writefd(fd, buf->bufstart, (buf->gapstart - buf->bufstart));
         if (nwrite >= 0)
         {
             nwrite = writefd(fd, buf->gapend, (buf->bufend - buf->gapend));
@@ -121,6 +125,8 @@ long gapbuf_save(GapBuf* buf, char* path)
 
 void gapbuf_load(GapBuf* buf, char* path)
 {
+    require(buf != NULL);
+    require(path != NULL);
     /* load the contents from the file */
     int fd, nread;
     struct stat sb = {0};
@@ -145,6 +151,7 @@ void gapbuf_load(GapBuf* buf, char* path)
 
 char gapbuf_getb(GapBuf* buf, size_t off)
 {
+    require(buf != NULL);
     int c = '\n'; // TODO: get rid of this hack
     if (off < gapbuf_end(buf))
     {
@@ -163,6 +170,8 @@ char gapbuf_getb(GapBuf* buf, size_t off)
 
 void gapbuf_putb(GapBuf* buf, char b, Sel* p_sel)
 {
+    require(buf != NULL);
+    require(p_sel != NULL);
     syncgap(buf, p_sel->end);
     *(buf->gapstart++) = b;
     p_sel->end = p_sel->end + 1u;
@@ -171,6 +180,7 @@ void gapbuf_putb(GapBuf* buf, char b, Sel* p_sel)
 
 void gapbuf_del(GapBuf* buf, size_t off, size_t len)
 {
+    require(buf != NULL);
     syncgap(buf, off);
     buf->gapend += len;
 }