From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 11853 invoked from network); 11 May 1999 09:40:48 -0000 Received: from sunsite.auc.dk (130.225.51.30) by ns1.primenet.com.au with SMTP; 11 May 1999 09:40:48 -0000 Received: (qmail 10282 invoked by alias); 11 May 1999 09:40:26 -0000 Mailing-List: contact zsh-workers-help@sunsite.auc.dk; run by ezmlm Precedence: bulk X-No-Archive: yes X-Seq: 6255 Received: (qmail 10275 invoked from network); 11 May 1999 09:40:25 -0000 Message-Id: <199905110939.CAA29206@bebop.clari.net> To: Peter Stephenson Cc: zsh-workers@sunsite.auc.dk (Zsh hackers list) In-reply-to: pws's message of Mon, 10 May 1999 09:53:16 +0200. <9905100753.AA33639@ibmth.df.unipi.it> Subject: Re: PATCH: history improvements for 3.1.5-pws-17 Date: Tue, 11 May 1999 02:39:42 -0700 From: Wayne Davison 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---