Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: PATCH: history improvements for 3.1.5-pws-17



Peter Stephenson writes:
> I've applied both the other history patches, and it does exactly
> what I was hoping, thanks.

Unfortunately there's a problem with how the relocated
savehistfile() call interacts with remhist() in that 2-file tweak.
Fortunately, it's easy to fix.

> Hmmm, it might be a good idea to make `zle widget num' override the
> value of $NUMERIC with num when calling a widget.

I like this -- it makes writing an up-line-or-local-history function
much simpler.

Appended is a patch with the following changes (apply it over the
top of my previous 2-file tweak):

 + Added the zle command: set-local-history.  If called with a
   non-zero numeric argument, it enables the browsing of local-only
   history.  If called with a zero argument, it turns off local-only
   history.  If called with no argument, it toggles the current
   setting.  I didn't add a keybinding for this, but I've got it
   bound to Esc-/ in my .zshrc for the moment.

 + Made the history-browsing commands honor the setting of the set-
   local-history toggle (including the history up/down commands, and
   searching commands, but not ! references -- should they change
   too?)

 + Foreign lines no longer get UNmarked as foreign at any time.

 + The history command displays a '*' next to the history number of
   foreign lines.

 + You can now call "zle WIDGET NUM" to temporarily set the "zmult"
   value for that widget (the old value gets restored after the
   widget runs).  If you supply a non-numeric argument, the widget
   is called without the MOD_MULT flag set (which typically results
   in a zmult of '1', but there are other commands that have a
   different default).

 + Commands that call remhist() (like "history") once again remove
   the right line (this was broken in my 2-file tweak).

 + The sequence of load/save events is now:  load the shared history
   right before we store the current line, and then we write it out.
   This means that most of the time up-history will access the
   previous command even when a foreign-history command shows up.
   (Of course, if you enter an empty command then there's not current
   command to save, so the imported command(s) will be first when you
   press up-arrow.)

 + If you don't have hist_ignore_all_dups set, we import all shared
   history lines into the buffer, even lines that we already have.

 + The histfilelock() code waits a little longer before breaking a
   stale lock file (10 seconds rather than 5).  Is that long enough?

I didn't change any option names -- I figure I'll let you decide to
shorten them if you'd like to.

I'm currently using the following code to make Ctrl-P avoid foreign
history, while up-arrow (and other commands) include it:

up-line-or-local-history() {
    zle set-local-history 1
    zle up-line-or-history
    zle set-local-history 0
}
zle -N up-line-or-local-history

down-line-or-local-history() {
    zle set-local-history 1
    zle down-line-or-history
    zle set-local-history 0
}
zle -N down-line-or-local-history

..wayne..

---8<------8<------8<------8<---cut here--->8------>8------>8------>8---
Index: Doc/Zsh/options.yo
@@ -831,21 +831,20 @@
 cindex(share history)
 cindex(history, sharing)
 item(tt(SHARE_HISTORY))(
-This option both imports new commands from the history file (ones
-that are not already in your history list), and also causes your
-typed commands to be appended to the history file (like specifiying
-tt(INCREMENTAL_APPEND_HISTORY)).  The history lines are also output
-with timestamps (see tt(EXTENDED_HISTORY)) to make it easier to
-find where we were in the file after the file gets re-written.
 
-In an attempt to avoid confusing the user, most history commands
-avoid these "foreign" commands.  They can be found by using an
-incremental or line-prefix history search (not including `tt(^)' or
-`tt(!)').  You can also make them visible to all commands by using a
-command that shows the history (such as `history' or `fc -l') or
-a command that explicitly imports history lines (`fc -RI').
+This option both imports new commands from the history file, and also
+causes your typed commands to be appended to the history file (like
+specifiying tt(INCREMENTAL_APPEND_HISTORY)).  The history lines are also
+output with timestamps ala tt(EXTENDED_HISTORY) (which makes it easier to
+find the spot where we left off reading the file after it gets re-written).
 
-If you find that you want more control over when foreign commands
+By default, history movement commands visit the imported lines as well as
+the local lines, but you can toggle this on and off with the
+set-local-history zle binding.  It is also possible to create a zle
+widget that will make some commands ignore imported commands, and some
+include them.
+
+If you find that you want more control over when commands
 get imported, you may wish to turn tt(SHARE_HISTORY) off,
 tt(INCREMENTAL_APPEND_HISTORY) on, and then manually import
 commands whenever you need them using `fc -RI'.
Index: Src/Zle/iwidgets.list
@@ -91,6 +91,7 @@
 "send-break", sendbreak, 0
 "set-mark-command", setmarkcommand, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL
 "spell-word", spellword, 0
+"set-local-history", setlocalhistory, 0
 "transpose-chars", transposechars, 0
 "transpose-words", transposewords, 0
 "undefined-key", undefinedkey, 0
Index: Src/Zle/zle_hist.c
@@ -297,7 +297,8 @@
 	srch_str = zalloc(histpos);
 	memcpy(srch_str, line, histpos);
     }
-    for (he = up_histent(quietgethist(histline)); he; he = up_histent(he)) {
+    he = quietgethist(histline);
+    while ((he = movehistent(he, -1, hist_skip_flags))) {
 	if (isset(HISTFINDNODUPS) && he->flags & HIST_DUP)
 	    continue;
 	s = ZLETEXT(he);
@@ -337,7 +338,8 @@
 	srch_str = zalloc(histpos);
 	memcpy(srch_str, line, histpos);
     }
-    for (he=down_histent(quietgethist(histline)); he; he=down_histent(he)) {
+    he = quietgethist(histline);
+    while ((he = movehistent(he, 1, hist_skip_flags))) {
 	if (isset(HISTFINDNODUPS) && he->flags & HIST_DUP)
 	    continue;
 	s = ZLETEXT(he);
@@ -452,16 +454,27 @@
     mkundoent();
     histline = he->histnum;
     setline(ZLETEXT(he));
-    /*he->flags &= ~HIST_FOREIGN;*/
     setlastline();
     clearlist = 1;
 }
 
 /**/
+void
+setlocalhistory(void)
+{
+    if (zmod.flags & MOD_MULT) {
+	hist_skip_flags = zmult? HIST_FOREIGN : 0;
+    }
+    else {
+	hist_skip_flags ^= HIST_FOREIGN;
+    }
+}
+
+/**/
 int
 zle_goto_hist(int ev, int n)
 {
-    Histent he = movehistent(quietgethist(ev), n, 0);
+    Histent he = movehistent(quietgethist(ev), n, hist_skip_flags);
     if (!he)
 	return 0;
     zle_setline(he);
@@ -682,7 +695,7 @@
 		    statusline = ibuf + NORM_PROMPT_POS;
 		    break;
 		}
-		if (!(he = dir > 0? down_histent(he) : up_histent(he))) {
+		if (!(he = movehistent(he, dir, hist_skip_flags))) {
 		    if (sbptr == (int)isrch_spots[top_spot-1].len
 		     && (isrch_spots[top_spot-1].flags & ISS_FAILING))
 			top_spot--;
@@ -1024,7 +1037,7 @@
     }
     t0 = strlen(visrchstr);
     he = quietgethist(histline);
-    while ((he = (visrchsense < 0? up_histent(he) : down_histent(he)))) {
+    while ((he = movehistent(he, visrchsense, hist_skip_flags))) {
 	if (isset(HISTFINDNODUPS) && he->flags & HIST_DUP)
 	    continue;
 	s = ZLETEXT(he);
@@ -1068,7 +1081,8 @@
 	zmult = n;
 	return;
     }
-    for (he = up_histent(quietgethist(histline)); he; he = up_histent(he)) {
+    he = quietgethist(histline);
+    while ((he = movehistent(he, -1, hist_skip_flags))) {
 	if (isset(HISTFINDNODUPS) && he->flags & HIST_DUP)
 	    continue;
 	s = ZLETEXT(he);
@@ -1102,7 +1116,8 @@
 	zmult = n;
 	return;
     }
-    for (he=down_histent(quietgethist(histline)); he; he=down_histent(he)) {
+    he = quietgethist(histline);
+    while ((he = movehistent(he, 1, hist_skip_flags))) {
 	if (isset(HISTFINDNODUPS) && he->flags & HIST_DUP)
 	    continue;
 	s = ZLETEXT(he);
Index: Src/Zle/zle_thingy.c
@@ -357,7 +357,7 @@
 
     /* check number of arguments */
     for(n = 0; args[n]; n++) ;
-    if(!op->o && n != 1) {
+    if(!op->o && n != 1 && n != 2) {
 	zerrnam(name, "wrong number of arguments", NULL, 0);
 	return 1;
     }
@@ -516,17 +516,31 @@
 bin_zle_call(char *name, char **args, char *ops, char func)
 {
     Thingy t;
+    struct modifier modsave;
 
     if(!zleactive || incompctlfunc || incompfunc) {
 	zerrnam(name, "widgets can only be called when ZLE is active",
 	    NULL, 0);
 	return 1;
     }
+    if (args[1]) {
+	modsave = zmod;
+	if (isdigit(*args[1])) {
+	    zmod.mult = atoi(args[1]);
+	    zmod.flags |= MOD_MULT;
+	}
+	else {
+	    zmod.mult = 1;
+	    zmod.flags &= ~MOD_MULT;
+	}
+    }
     t = rthingy(args[0]);
     PERMALLOC {
       execzlefunc(t);
     } LASTALLOC;
     unrefthingy(t);
+    if (args[1])
+	zmod = modsave;
     return 0;
 }
 
Index: Src/builtin.c
@@ -1353,7 +1353,6 @@
     }
 
     for (;;) {
-	ent->flags &= ~HIST_FOREIGN;
 	s = dupstring(ent->text);
 	/* this if does the pattern matching, if required */
 	if (!com || domatch(s, com, 0)) {
@@ -1361,8 +1360,10 @@
 	    fclistdone |= fcsubs(&s, subs);
 
 	    /* do numbering */
-	    if (n)
-		fprintf(f, "%5d  ", ent->histnum);
+	    if (n) {
+		fprintf(f, "%5d%c ", ent->histnum,
+			ent->flags & HIST_FOREIGN? '*' : ' ');
+	    }
 	    /* output actual time (and possibly date) of execution of the
 	    command, if required */
 	    if (d) {
Index: Src/hashtable.c
@@ -1323,9 +1323,8 @@
     HashNode oldnode = addhashnode2(ht, nam, nodeptr);
     Histent he = (Histent)nodeptr;
     if (oldnode && oldnode != nodeptr) {
-	if (he->flags & HIST_MAKEUNIQUE) {
-	    if (!(he->flags & HIST_FOREIGN))
-		oldnode->flags &= ~HIST_FOREIGN;
+	if (he->flags & HIST_MAKEUNIQUE
+	 || (he->flags & HIST_FOREIGN && (Histent)oldnode == he->up)) {
 	    he->flags |= HIST_DUP;
 	    addhashnode(ht, oldnode->nam, oldnode); /* Remove the new dup */
 	}
Index: Src/hist.c
@@ -96,9 +96,17 @@
 /**/
 int histactive;
 
+/* Current setting of the associated option, but sometimes also includes
+ * the setting of the HIST_SAVE_NO_DUPS option. */
+
 /**/
 int hist_ignore_all_dups;
 
+/* What flags (if any) we should skip when moving through the history */
+
+/**/
+int hist_skip_flags;
+
 /* Bits of histactive variable */
 #define HA_ACTIVE	(1<<0)	/* History mechanism is active */
 #define HA_NOSTORE	(1<<1)	/* Don't store the line when finished */
@@ -854,6 +862,7 @@
 hend(void)
 {
     int flag, save = 1;
+    char *hf = getsparam("HISTFILE");
 
     DPUTS(!chline, "BUG: chline is NULL in hend()");
     if (histdone & HISTFLAG_SETTY)
@@ -879,6 +888,9 @@
     if (hist_ignore_all_dups != isset(HISTIGNOREALLDUPS)
      && (hist_ignore_all_dups = isset(HISTIGNOREALLDUPS)) != 0)
 	histremovedups();
+    /* For history sharing, lock history file once for both read and write */
+    if (isset(SHAREHISTORY) && lockhistfile(hf, 0))
+	readhistfile(hf, 0, HFILE_USE_OPTIONS | HFILE_FAST);
     flag = histdone;
     histdone = 0;
     if (hptr < chline + 1)
@@ -916,7 +928,7 @@
 	Histent he;
 	int keepflags;
 
-	for (he = hist_ring; he && he->flags & HIST_FOREIGN;
+	for (he = hist_ring; he && he->flags & hist_skip_flags;
 	     he = up_histent(he)) ;
 #ifdef DEBUG
 	/* debugging only */
@@ -961,7 +973,8 @@
     chline = NULL;
     histactive = 0;
     if (isset(SHAREHISTORY) || isset(INCREMENTALAPPENDHISTORY))
-	savehistfile(NULL, 1, HFILE_USE_OPTIONS | HFILE_FAST);
+	savehistfile(hf, 1, HFILE_USE_OPTIONS | HFILE_FAST);
+    unlockhistfile(hf); /* It's OK to call this even if we aren't locked */
     return !(flag & HISTFLAG_NOEXEC || errflag);
 }
 
@@ -973,9 +986,7 @@
 {
     if (!(histactive & HA_ACTIVE)) {
 	if (!(histactive & HA_JUNKED)) {
-	    /* make sure this doesn't show up when we do firsthist() */
-	    if (hist_ring->histnum == curhist)
-		freehistnode((HashNode)hist_ring);
+	    freehistnode((HashNode)hist_ring);
 	    histactive |= HA_JUNKED;
 	    /* curhist-- is delayed until the next hbegin() */
 	}
@@ -1589,7 +1600,6 @@
 	    return;
 	lasthist.fsiz = sb.st_size;
 	lasthist.mtim = sb.st_mtime;
-	readflags |= HFILE_SKIPOLD;
     }
     else if (!lockhistfile(fn, 1))
 	return;
@@ -1614,7 +1624,8 @@
 	newflags = HIST_OLD | HIST_READ;
 	if (readflags & HFILE_FAST)
 	    newflags |= HIST_FOREIGN;
-	if (readflags & HFILE_SKIPOLD)
+	if (readflags & HFILE_SKIPOLD
+	 || (hist_ignore_all_dups && newflags & hist_skip_flags))
 	    newflags |= HIST_MAKEUNIQUE;
 	while (fpos = ftell(in), fgets(buf, bufsiz, in)) {
 	    int l = strlen(buf);
@@ -1756,13 +1767,7 @@
 	    lasthist.next_write_ev = he->histnum + 1;
 	    he = down_histent(he);
 	}
-	/* If we have something to write, lock before the (potential)
-	 * read so that we don't lock twice. */
-	if (he && !lockhistfile(fn, 0))
-	    return;
-	if (isset(SHAREHISTORY))
-	    readhistfile(fn, 0, HFILE_USE_OPTIONS | HFILE_FAST);
-	if (!he)
+	if (!he || !lockhistfile(fn, 0))
 	    return;
 	if (histfile_linect > savehist + savehist / 5)
 	    writeflags &= ~HFILE_FAST;
@@ -1890,7 +1895,7 @@
 			continue;
 		}
 		else if (keep_trying) {
-		    if (time(NULL) - sb.st_mtime < 5)
+		    if (time(NULL) - sb.st_mtime < 10)
 			sleep(1);
 		    else
 			unlink(lockfile);
@@ -1906,6 +1911,10 @@
     }
     return ct != lockhistct;
 }
+
+/* Unlock the history file if this corresponds to the last nested lock
+ * request.  If we don't have the file locked, just return.
+ */
 
 /**/
 void
---8<------8<------8<------8<---cut here--->8------>8------>8------>8---



Messages sorted by: Reverse Date, Date, Thread, Author