]> pd.if.org Git - pd_readline/blobdiff - mg/undo.c
Getting close to a basic working readline now.
[pd_readline] / mg / undo.c
diff --git a/mg/undo.c b/mg/undo.c
deleted file mode 100644 (file)
index 1efd2a1..0000000
--- a/mg/undo.c
+++ /dev/null
@@ -1,585 +0,0 @@
-/* $OpenBSD: undo.c,v 1.50 2010/06/30 19:12:54 oga Exp $ */
-/*
- * This file is in the public domain
- */
-
-#include "def.h"
-#include "kbd.h"
-
-#define MAX_FREE_RECORDS       32
-
-/*
- * Local variables
- */
-static struct undoq             undo_free;
-static int                      undo_free_num;
-static int                      boundary_flag = TRUE;
-static int                      undo_enable_flag = TRUE;
-
-/*
- * Local functions
- */
-static int find_dot(struct line *, int);
-static int find_lo(int, struct line **, int *, int *);
-static struct undo_rec *new_undo_record(void);
-static int drop_oldest_undo_record(void);
-
-/*
- * find_dot, find_lo()
- *
- * Find an absolute dot in the buffer from a line/offset pair, and vice-versa.
- *
- * Since lines can be deleted while they are referenced by undo record, we
- * need to have an absolute dot to have something reliable.
- */
-static int
-find_dot(struct line *lp, int off)
-{
-       int      count = 0;
-       struct line     *p;
-
-       for (p = curbp->b_headp; p != lp; p = lforw(p)) {
-               if (count != 0) {
-                       if (p == curbp->b_headp) {
-                               ewprintf("Error: Undo stuff called with a"
-                                   "nonexistent line");
-                               return (FALSE);
-                       }
-               }
-               count += llength(p) + 1;
-       }
-       count += off;
-
-       return (count);
-}
-
-static int
-find_lo(int pos, struct line **olp, int *offset, int *lnum)
-{
-       struct line *p;
-       int lineno;
-
-       p = curbp->b_headp;
-       lineno = 0;
-       while (pos > llength(p)) {
-               pos -= llength(p) + 1;
-               if ((p = lforw(p)) == curbp->b_headp) {
-                       *olp = NULL;
-                       *offset = 0;
-                       return (FALSE);
-               }
-               lineno++;
-       }
-       *olp = p;
-       *offset = pos;
-       *lnum = lineno;
-
-       return (TRUE);
-}
-
-static struct undo_rec *
-new_undo_record(void)
-{
-       struct undo_rec *rec;
-
-       rec = TAILQ_FIRST(&undo_free);
-       if (rec != NULL) {
-               /* Remove it from the free-list */
-               TAILQ_REMOVE(&undo_free, rec, next);
-               undo_free_num--;
-       } else {
-               if ((rec = malloc(sizeof(*rec))) == NULL)
-                       panic("Out of memory in undo code (record)");
-       }
-       memset(rec, 0, sizeof(struct undo_rec));
-
-       return (rec);
-}
-
-void
-free_undo_record(struct undo_rec *rec)
-{
-       static int initialised = 0;
-
-       /*
-        * On the first run, do initialisation of the free list.
-        */
-       if (initialised == 0) {
-               TAILQ_INIT(&undo_free);
-               initialised = 1;
-       }
-       if (rec->content != NULL) {
-               free(rec->content);
-               rec->content = NULL;
-       }
-       if (undo_free_num >= MAX_FREE_RECORDS) {
-               free(rec);
-               return;
-       }
-       undo_free_num++;
-
-       TAILQ_INSERT_HEAD(&undo_free, rec, next);
-}
-
-/*
- * Drop the oldest undo record in our list. Return 1 if we could remove it,
- * 0 if the undo list was empty.
- */
-static int
-drop_oldest_undo_record(void)
-{
-       struct undo_rec *rec;
-
-       rec = TAILQ_LAST(&curbp->b_undo, undoq);
-       if (rec != NULL) {
-               undo_free_num--;
-               TAILQ_REMOVE(&curbp->b_undo, rec, next);
-               free_undo_record(rec);
-               return (1);
-       }
-       return (0);
-}
-
-static int
-lastrectype(void)
-{
-       struct undo_rec *rec;
-
-       if ((rec = TAILQ_FIRST(&curbp->b_undo)) != NULL)
-               return (rec->type);
-       return (0);
-}
-
-/*
- * Returns TRUE if undo is enabled, FALSE otherwise.
- */
-int
-undo_enabled(void)
-{
-       return (undo_enable_flag);
-}
-
-/*
- * undo_enable: toggle undo_enable.
- * Returns the previous value of the flag.
- */
-int
-undo_enable(int f, int n)
-{
-       int pon = undo_enable_flag;
-
-       if (f & (FFARG | FFRAND))
-               undo_enable_flag = n > 0;
-       else
-               undo_enable_flag = !undo_enable_flag;
-
-       if (!(f & FFRAND))
-               ewprintf("Undo %sabled", undo_enable_flag ? "en" : "dis");
-
-       return (pon);
-}
-
-/*
- * If undo is enabled, then:
- *  Toggle undo boundary recording.
- *  If called with an argument, (n > 0) => enable. Otherwise disable.
- * In either case, add an undo boundary
- * If undo is disabled, this function has no effect.
- */
-int
-undo_boundary_enable(int f, int n)
-{
-       int bon = boundary_flag;
-
-       if (!undo_enable_flag)
-               return (FALSE);
-
-       undo_add_boundary(FFRAND, 1);
-
-       if (f & (FFARG | FFRAND))
-               boundary_flag = n > 0;
-       else
-               boundary_flag = !boundary_flag;
-
-       if (!(f & FFRAND))
-               ewprintf("Undo boundaries %sabled",
-                   boundary_flag ? "en" : "dis");
-
-       return (bon);
-}
-
-/*
- * Record an undo boundary, unless boundary_flag == FALSE.
- * Does nothing if previous undo entry is already a boundary or 'modified' flag.
- */
-int
-undo_add_boundary(int f, int n)
-{
-       struct undo_rec *rec;
-       int last;
-
-       if (boundary_flag == FALSE)
-               return (FALSE);
-
-       last = lastrectype();
-       if (last == BOUNDARY || last == MODIFIED)
-               return (TRUE);
-
-       rec = new_undo_record();
-       rec->type = BOUNDARY;
-
-       TAILQ_INSERT_HEAD(&curbp->b_undo, rec, next);
-
-       return (TRUE);
-}
-
-/*
- * Record an undo "modified" boundary
- */
-void
-undo_add_modified(void)
-{
-       struct undo_rec *rec;
-
-       rec = new_undo_record();
-       rec->type = MODIFIED;
-
-       TAILQ_INSERT_HEAD(&curbp->b_undo, rec, next);
-
-       return;
-}
-
-int
-undo_add_insert(struct line *lp, int offset, int size)
-{
-       struct region   reg;
-       struct  undo_rec *rec;
-       int     pos;
-
-       if (!undo_enable_flag)
-               return (TRUE);
-       reg.r_linep = lp;
-       reg.r_offset = offset;
-       reg.r_size = size;
-
-       pos = find_dot(lp, offset);
-
-       /*
-        * We try to reuse the last undo record to `compress' things.
-        */
-       rec = TAILQ_FIRST(&curbp->b_undo);
-       if (rec != NULL && rec->type == INSERT) {
-               if (rec->pos + rec->region.r_size == pos) {
-                       rec->region.r_size += reg.r_size;
-                       return (TRUE);
-               }
-       }
-
-       /*
-        * We couldn't reuse the last undo record, so prepare a new one.
-        */
-       rec = new_undo_record();
-       rec->pos = pos;
-       rec->type = INSERT;
-       memmove(&rec->region, &reg, sizeof(struct region));
-       rec->content = NULL;
-
-       undo_add_boundary(FFRAND, 1);
-
-       TAILQ_INSERT_HEAD(&curbp->b_undo, rec, next);
-
-       return (TRUE);
-}
-
-/*
- * This of course must be done _before_ the actual deletion is done.
- */
-int
-undo_add_delete(struct line *lp, int offset, int size, int isreg)
-{
-       struct region   reg;
-       struct  undo_rec *rec;
-       int     pos;
-
-       if (!undo_enable_flag)
-               return (TRUE);
-
-       reg.r_linep = lp;
-       reg.r_offset = offset;
-       reg.r_size = size;
-
-       pos = find_dot(lp, offset);
-
-       if (offset == llength(lp))      /* if it's a newline... */
-               undo_add_boundary(FFRAND, 1);
-       else if ((rec = TAILQ_FIRST(&curbp->b_undo)) != NULL) {
-               /*
-                * Separate this command from the previous one if we're not
-                * just before the previous record...
-                */
-               if (!isreg && rec->type == DELETE) {
-                       if (rec->pos - rec->region.r_size != pos)
-                               undo_add_boundary(FFRAND, 1);
-               }
-       }
-       rec = new_undo_record();
-       rec->pos = pos;
-       if (isreg)
-               rec->type = DELREG;
-       else
-               rec->type = DELETE;
-       memmove(&rec->region, &reg, sizeof(struct region));
-       do {
-               rec->content = malloc(reg.r_size + 1);
-       } while ((rec->content == NULL) && drop_oldest_undo_record());
-
-       if (rec->content == NULL)
-               panic("Out of memory");
-
-       region_get_data(&reg, rec->content, reg.r_size);
-
-       if (isreg || lastrectype() != DELETE)
-               undo_add_boundary(FFRAND, 1);
-
-       TAILQ_INSERT_HEAD(&curbp->b_undo, rec, next);
-
-       return (TRUE);
-}
-
-/*
- * This of course must be called before the change takes place.
- */
-int
-undo_add_change(struct line *lp, int offset, int size)
-{
-       if (!undo_enable_flag)
-               return (TRUE);
-       undo_add_boundary(FFRAND, 1);
-       boundary_flag = FALSE;
-       undo_add_delete(lp, offset, size, 0);
-       undo_add_insert(lp, offset, size);
-       boundary_flag = TRUE;
-       undo_add_boundary(FFRAND, 1);
-
-       return (TRUE);
-}
-
-/*
- * Show the undo records for the current buffer in a new buffer.
- */
-/* ARGSUSED */
-int
-undo_dump(int f, int n)
-{
-       struct   undo_rec *rec;
-       struct buffer   *bp;
-       struct mgwin    *wp;
-       char     buf[4096], tmp[1024];
-       int      num;
-
-       /*
-        * Prepare the buffer for insertion.
-        */
-       if ((bp = bfind("*undo*", TRUE)) == NULL)
-               return (FALSE);
-       bp->b_flag |= BFREADONLY;
-       bclear(bp);
-       popbuf(bp, WNONE);
-
-       for (wp = wheadp; wp != NULL; wp = wp->w_wndp) {
-               if (wp->w_bufp == bp) {
-                       wp->w_dotp = bp->b_headp;
-                       wp->w_doto = 0;
-               }
-       }
-
-       num = 0;
-       TAILQ_FOREACH(rec, &curbp->b_undo, next) {
-               num++;
-               snprintf(buf, sizeof(buf),
-                   "%d:\t %s at %d ", num,
-                   (rec->type == DELETE) ? "DELETE":
-                   (rec->type == DELREG) ? "DELREGION":
-                   (rec->type == INSERT) ? "INSERT":
-                   (rec->type == BOUNDARY) ? "----" :
-                   (rec->type == MODIFIED) ? "MODIFIED": "UNKNOWN",
-                   rec->pos);
-
-               if (rec->content) {
-                       (void)strlcat(buf, "\"", sizeof(buf));
-                       snprintf(tmp, sizeof(tmp), "%.*s", rec->region.r_size,
-                           rec->content);
-                       (void)strlcat(buf, tmp, sizeof(buf));
-                       (void)strlcat(buf, "\"", sizeof(buf));
-               }
-               snprintf(tmp, sizeof(tmp), " [%d]", rec->region.r_size);
-               if (strlcat(buf, tmp, sizeof(buf)) >= sizeof(buf)) {
-                       ewprintf("Undo record too large. Aborted.");
-                       return (FALSE);
-               }
-               addlinef(bp, "%s", buf);
-       }
-       return (TRUE);
-}
-
-/*
- * After the user did action1, then action2, then action3:
- *
- *     [action3] <--- Undoptr
- *     [action2]
- *     [action1]
- *      ------
- *      [undo]
- *
- * After undo:
- *
- *     [undo of action3]
- *     [action2] <--- Undoptr
- *     [action1]
- *      ------
- *      [undo]
- *
- * After another undo:
- *
- *
- *     [undo of action2]
- *     [undo of action3]
- *     [action1]  <--- Undoptr
- *      ------
- *      [undo]
- *
- * Note that the "undo of actionX" have no special meaning. Only when
- * we undo a deletion, the insertion will be recorded just as if it
- * was typed on the keyboard. Resulting in the inverse operation being
- * saved in the list.
- *
- * If undoptr reaches the bottom of the list, or if we moved between
- * two undo actions, we make it point back at the topmost record. This is
- * how we handle redoing.
- */
-/* ARGSUSED */
-int
-undo(int f, int n)
-{
-       struct undo_rec *ptr, *nptr;
-       int              done, rval;
-       struct line     *lp;
-       int              offset, save, dot;
-       static int       nulled = FALSE;
-       int              lineno;
-
-       if (n < 0)
-               return (FALSE);
-
-       dot = find_dot(curwp->w_dotp, curwp->w_doto);
-
-       ptr = curbp->b_undoptr;
-
-       /* first invocation, make ptr point back to the top of the list */
-       if ((ptr == NULL && nulled == TRUE) ||  rptcount == 0) {
-               ptr = TAILQ_FIRST(&curbp->b_undo);
-               nulled = TRUE;
-       }
-
-       rval = TRUE;
-       while (n--) {
-               /* if we have a spurious boundary, free it and move on.... */
-               while (ptr && ptr->type == BOUNDARY) {
-                       nptr = TAILQ_NEXT(ptr, next);
-                       TAILQ_REMOVE(&curbp->b_undo, ptr, next);
-                       free_undo_record(ptr);
-                       ptr = nptr;
-               }
-               /*
-                * Ptr is NULL, but on the next run, it will point to the
-                * top again, redoing all stuff done in the buffer since
-                * its creation.
-                */
-               if (ptr == NULL) {
-                       ewprintf("No further undo information");
-                       rval = FALSE;
-                       nulled = TRUE;
-                       break;
-               }
-               nulled = FALSE;
-
-               /*
-                * Loop while we don't get a boundary specifying we've
-                * finished the current action...
-                */
-
-               undo_add_boundary(FFRAND, 1);
-
-               save = boundary_flag;
-               boundary_flag = FALSE;
-
-               done = 0;
-               do {
-                       /*
-                        * Move to where this has to apply
-                        *
-                        * Boundaries (and the modified flag)  are put as
-                        * position 0 (to save lookup time in find_dot)
-                        * so we must not move there...
-                        */
-                       if (ptr->type != BOUNDARY && ptr->type != MODIFIED) {
-                               if (find_lo(ptr->pos, &lp,
-                                   &offset, &lineno) == FALSE) {
-                                       ewprintf("Internal error in Undo!");
-                                       rval = FALSE;
-                                       break;
-                               }
-                               curwp->w_dotp = lp;
-                               curwp->w_doto = offset;
-                               curwp->w_markline = curwp->w_dotline;
-                               curwp->w_dotline = lineno;
-                       }
-
-                       /*
-                        * Do operation^-1
-                        */
-                       switch (ptr->type) {
-                       case INSERT:
-                               ldelete(ptr->region.r_size, KNONE);
-                               break;
-                       case DELETE:
-                               lp = curwp->w_dotp;
-                               offset = curwp->w_doto;
-                               region_put_data(ptr->content,
-                                   ptr->region.r_size);
-                               curwp->w_dotp = lp;
-                               curwp->w_doto = offset;
-                               break;
-                       case DELREG:
-                               region_put_data(ptr->content,
-                                   ptr->region.r_size);
-                               break;
-                       case BOUNDARY:
-                               done = 1;
-                               break;
-                       case MODIFIED:
-                               curbp->b_flag &= ~BFCHG;
-                               break;
-                       default:
-                               break;
-                       }
-
-                       /* And move to next record */
-                       ptr = TAILQ_NEXT(ptr, next);
-               } while (ptr != NULL && !done);
-
-               boundary_flag = save;
-               undo_add_boundary(FFRAND, 1);
-
-               ewprintf("Undo!");
-       }
-       /*
-        * Record where we are. (we have to save our new position at the end
-        * since we change the dot when undoing....)
-        */
-       curbp->b_undoptr = ptr;
-
-       curbp->b_undopos = find_dot(curwp->w_dotp, curwp->w_doto);
-
-       return (rval);
-}