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;
}