Hi,

Currently, in mg dired mode, if you mark a file as deleted, if the
dired buffer is refreshed (using 'dired-revert' for example) the
marking of files is lost. This diff fixes that by saving the marked
files before they are lost, then remarking them once the buffer is
refreshed. Comments/oks?

-lum

Index: def.h
===================================================================
RCS file: /cvs/src/usr.bin/mg/def.h,v
retrieving revision 1.150
diff -u -p -u -p -r1.150 def.h
--- def.h       29 Sep 2015 02:07:49 -0000      1.150
+++ def.h       6 Oct 2015 20:08:30 -0000
@@ -288,7 +288,8 @@ struct buffer {
 #define BFOVERWRITE 0x08               /* overwrite mode                */
 #define BFREADONLY  0x10               /* read only mode                */
 #define BFDIRTY     0x20               /* Buffer was modified elsewhere */
-#define BFIGNDIRTY  0x40               /* Ignore modifications */
+#define BFIGNDIRTY  0x40               /* Ignore modifications          */
+#define BFDIREDDEL  0x80               /* Dired has a deleted 'D' file  */
 /*
  * This structure holds information about recent actions for the Undo command.
  */
Index: dired.c
===================================================================
RCS file: /cvs/src/usr.bin/mg/dired.c,v
retrieving revision 1.77
diff -u -p -u -p -r1.77 dired.c
--- dired.c     28 Sep 2015 11:56:17 -0000      1.77
+++ dired.c     6 Oct 2015 20:08:30 -0000
@@ -53,9 +53,24 @@ static int    d_killbuffer_cmd(int, int);
 static int      d_refreshbuffer(int, int);
 static void     reaper(int);
 static struct buffer   *refreshbuffer(struct buffer *);
+static void     createlist(struct buffer *);
+static void     redelete(struct buffer *);
+static char     *findfname(struct line *, char *);
 
 extern struct keymap_s helpmap, cXmap, metamap;
 
+const char DDELCHAR = 'D';
+
+/*
+ * Structure which holds a linked list of file names marked for
+ * deletion. Used to maintain dired buffer 'state' between refreshes.
+ */
+struct delentry {
+       SLIST_ENTRY(delentry) entry;
+       char   *fn;
+};
+SLIST_HEAD(slisthead, delentry) delhead = SLIST_HEAD_INITIALIZER(delhead);
+
 static PF dirednul[] = {
        setmark,                /* ^@ */
        gotobol,                /* ^A */
@@ -271,8 +286,10 @@ d_del(int f, int n)
        if (n < 0)
                return (FALSE);
        while (n--) {
-               if (llength(curwp->w_dotp) > 0)
-                       lputc(curwp->w_dotp, 0, 'D');
+               if (llength(curwp->w_dotp) > 0) {
+                       lputc(curwp->w_dotp, 0, DDELCHAR);
+                       curbp->b_flag |= BFDIREDDEL;
+               }
                if (lforw(curwp->w_dotp) != curbp->b_headp) {
                        curwp->w_dotp = lforw(curwp->w_dotp);
                        curwp->w_dotline++;
@@ -412,6 +429,8 @@ d_expunge(int f, int n)
                        curwp->w_rflag |= WFFULL;
                }
        }
+       /* we have deleted all items successfully, remove del flag */
+       bp->b_flag &= ~BFDIREDDEL       
        curwp->w_dotline = tmp;
        d_warpdot(curwp->w_dotp, &curwp->w_doto);
        return (TRUE);
@@ -692,26 +711,53 @@ d_refreshbuffer(int f, int n)
        return (showbuffer(bp, curwp, WFFULL | WFMODE));
 }
 
+/*
+ * Kill then re-open the requested dired buffer.
+ * If required, take a note of any files marked for deletion. Then once
+ * the buffer has been re-opened, remark the same files as deleted.
+ */
 struct buffer *
 refreshbuffer(struct buffer *bp)
 {
-       char    *tmp;
+       char            *tmp_b_fname;
+       int              i, tmp_w_dotline;
 
-       tmp = strdup(bp->b_fname);
-       if (tmp == NULL) {
+       /* remember directory path to open later */
+       tmp_b_fname = strdup(bp->b_fname);
+       if (tmp_b_fname == NULL) {
                dobeep();
                ewprintf("Out of memory");
                return (NULL);
        }
+       tmp_w_dotline = curwp->w_dotline;
+
+       /* create a list of files for deletion */
+       if (bp->b_flag & BFDIREDDEL)
+               createlist(bp);
 
        killbuffer(bp);
 
        /* dired_() uses findbuffer() to create new buffer */
-       if ((bp = dired_(tmp)) == NULL) {
-               free(tmp);
+       if ((bp = dired_(tmp_b_fname)) == NULL) {
+               free(tmp_b_fname);
                return (NULL);
        }
-       free(tmp);
+       free(tmp_b_fname);
+
+       /* remark any previously deleted files with a 'D' */
+       redelete(bp);           
+
+       /* find dot line */
+       bp->b_dotp = bfirstlp(bp);
+       if (tmp_w_dotline > bp->b_lines)
+               tmp_w_dotline = bp->b_lines - 1;
+       for (i = 1; i < tmp_w_dotline; i++)
+               bp->b_dotp = lforw(bp->b_dotp);
+
+       bp->b_dotline = i;
+       bp->b_doto = 0;
+       d_warpdot(bp->b_dotp, &bp->b_doto);
+
        curbp = bp;
 
        return (bp);
@@ -865,4 +911,118 @@ dired_(char *dname)
        (void)fupdstat(bp);
        bp->b_nmodes = 1;
        return (bp);
+}
+
+/*
+ * Iterate through the lines of the dired buffer looking for files
+ * collected in the linked list made in createlist(). If a line is found
+ * replace 'D' as first char in a line. As lines are found, remove the
+ * corresponding item from the linked list. Iterate for as long as there
+ * are items in the linked list.
+ */
+void
+redelete(struct buffer *bp)
+{
+       struct delentry *d1 = NULL;
+       struct line     *lp, *nlp;
+       char             fname[NFILEN];
+       char            *p = fname;
+       size_t           plen, fnlen;
+       int              finished = 0;
+
+       for (lp = bfirstlp(bp); lp != bp->b_headp; lp = nlp) {  
+               bp->b_dotp = lp;
+               if ((p = findfname(lp, p)) == NULL) {
+                       nlp = lforw(lp);
+                       continue;
+               }
+               plen = strlen(p);
+               SLIST_FOREACH(d1, &delhead, entry) {
+                       fnlen = strlen(d1->fn);
+                       if ((plen == fnlen) && 
+                           (strncmp(p, d1->fn, plen) == 0)) {
+                               lputc(bp->b_dotp, 0, DDELCHAR);
+                               bp->b_flag |= BFDIREDDEL;
+                               SLIST_REMOVE(&delhead, d1, delentry, entry);
+                               if (SLIST_EMPTY(&delhead)) {
+                                       finished = 1;
+                                       break;
+                               }       
+                       }
+               }
+               if (finished)
+                       break;
+               nlp = lforw(lp);
+       }
+       while (!SLIST_EMPTY(&delhead)) {
+               d1 = SLIST_FIRST(&delhead);
+               SLIST_REMOVE_HEAD(&delhead, entry);
+               free(d1->fn);
+               free(d1);
+       }
+
+       return;
+}
+
+/*
+ * Create a list of files marked for deletion.
+ */
+void
+createlist(struct buffer *bp)
+{
+       struct delentry *d1 = NULL, *d2;
+       struct line     *lp, *nlp;
+       char             fname[NFILEN];
+       char            *p = fname;
+
+       for (lp = bfirstlp(bp); lp != bp->b_headp; lp = nlp) {  
+               if (lp->l_text[0] == DDELCHAR) {
+                       if ((p = findfname(lp, p)) == NULL) {
+                               nlp = lforw(lp);
+                               continue;
+                       }
+                       if (SLIST_EMPTY(&delhead)) {
+                               if ((d1 = malloc(sizeof(struct delentry)))
+                                    == NULL)
+                                       return;
+                               if ((d1->fn = strdup(p)) == NULL) {
+                                       free(d1);
+                                       return;
+                               }
+                               SLIST_INSERT_HEAD(&delhead, d1, entry);
+                       } else {
+                               if ((d2 = malloc(sizeof(struct delentry)))
+                                    == NULL) {
+                                       free(d1->fn);
+                                       free(d1);
+                                       return;
+                               }
+                               if ((d2->fn = strdup(p)) == NULL) {
+                                       free(d1->fn);
+                                       free(d1);
+                                       free(d2);
+                                       return;
+                               }
+                               SLIST_INSERT_AFTER(d1, d2, entry);
+                               d1 = d2;                                
+                       }
+               }
+               nlp = lforw(lp);
+       }
+       return;
+}
+
+/*
+ * Look for and extract a file name on a dired buffer line.
+ */
+char *
+findfname(struct line *lp, char *fn)
+{
+       int start;
+
+       (void)d_warpdot(lp, &start);
+       if (start < 1)
+               return NULL;
+       fn = &lp->l_text[start];
+       return fn;
 }


Reply via email to