Zsh Mailing List Archive
Messages sorted by:
Reverse Date,
Date,
Thread,
Author
Proposed history improvements
- X-seq: zsh-workers 14287
- From: Wayne Davison <wayned@xxxxxxxxxxxxxxxxxxxxx>
- To: Zsh Workers <zsh-workers@xxxxxxxxxxxxxx>
- Subject: Proposed history improvements
- Date: Wed, 9 May 2001 15:45:29 -0700 (PDT)
- Mailing-list: contact zsh-workers-help@xxxxxxxxxx; run by ezmlm
Back in the 3.0.x series I started a tradition of releasing a history
patch too close to the release date to be included. Here's my attempt
to continue this tradition. :-) Let me know if you think something
like this should be included in the upcoming release or not.
What I've done is (1) to slightly change the way HIST_IGNORE_SPACE,
HIST_NO_FUNCTIONS, and HIST_NO_STORE works, and (2) to add the option
HIST_DEPRECATE_SPACE.
1. I have gotten in the habit of prefixing certain commands with a space
that I don't want cluttering up my history. However, I have always been
annoyed when I mistype something and I have to retype or cut & paste to
try the command again. My change makes an ignored command stick around
just until the next command is typed. This allows me to use Ctrl-P or
!!$ or whatever for the next command, at which point the ignored command
vanishes from the internal history (and was never written to the history
file). You can type space-return to clear the previous command, if
you're feeling paranoid. What do folks think of this idea? Do you
think something like this should require a separate option?
2. I thought it would be cool if I could hint to the history system
about which lines I consider more important. With HIST_DEPRECATE_SPACE
set, lines that start with a space are considered to be local only
(never being written to the history file) and are expired before other
unique commands are removed (but after dups if HIST_EXPIRE_DUPS_FIRST is
set). If you also have the HIST_IGNORE_SPACE option set, you'll need to
type a second space to trigger that treatment. While these two options
are similar, you can have lots of deprecated history lines hanging
around in the local history, but only one last-typed-but-soon-to-be-lost
ignored line.
Also note that the space-prefixed-alias idiom continues to work, and has
the same rules as stated above for marking an entry as ignored or as
deprecated (depending on what options are set).
Comments? Any better ideas? I've appended a patch for the latest CVS
verion, but (of course) have not checked it in (nor created any doc
changes yet).
..wayne..
---8<------8<------8<------8<---cut here--->8------>8------>8------>8---
Index: Src/hashtable.c
@@ -1480,15 +1480,21 @@
HashNode oldnode = addhashnode2(ht, nam, nodeptr);
Histent he = (Histent)nodeptr;
if (oldnode && oldnode != (HashNode)nodeptr) {
- if (he->flags & HIST_MAKEUNIQUE
+ if (he->flags & (HIST_MAKEUNIQUE | HIST_TMPSTORE)
|| (he->flags & HIST_FOREIGN && (Histent)oldnode == he->up)) {
+ (void) addhashnode2(ht, oldnode->nam, oldnode); /* restore hash */
he->flags |= HIST_DUP;
- addhashnode(ht, oldnode->nam, oldnode); /* Remove the new dup */
+ he->flags &= ~HIST_MAKEUNIQUE;
}
else {
- oldnode->flags |= HIST_DUP;
+ oldnode->flags |= HIST_DUP | (he->flags & HIST_DEPRECATED);
if (hist_ignore_all_dups)
freehistnode(oldnode); /* Remove the old dup */
+ }
+ if (isset(HISTDEPRECATESPACE) && *nam == ' ') {
+ while (*nam == ' ') nam++;
+ if ((oldnode = gethashnode(ht, nam)) != NULL)
+ oldnode->flags |= HIST_DEPRECATED;
}
}
else
Index: Src/hist.c
@@ -794,16 +794,21 @@
void
histreduceblanks(void)
{
- int i, len, pos, needblank;
+ int i, len, pos, needblank, spacecount = 0;
- for (i = 0, len = 0; i < chwordpos; i += 2) {
+ if (isset(HISTIGNORESPACE))
+ for (spacecount = 0; chline[spacecount] == ' '; spacecount++) ;
+ else
+ spacecount = isset(HISTDEPRECATESPACE) && chline[0] == ' ';
+
+ for (i = 0, len = spacecount; i < chwordpos; i += 2) {
len += chwords[i+1] - chwords[i]
+ (i > 0 && chwords[i] > chwords[i-1]);
}
if (chline[len] == '\0')
return;
- for (i = 0, pos = 0; i < chwordpos; i += 2) {
+ for (i = 0, pos = spacecount; i < chwordpos; i += 2) {
len = chwords[i+1] - chwords[i];
needblank = (i < chwordpos-2 && chwords[i+2] > chwords[i+1]);
if (pos != chwords[i]) {
@@ -933,17 +938,24 @@
histlinect++;
}
else {
+ Histent del = NULL;
he = hist_ring->down;
- if (isset(HISTEXPIREDUPSFIRST) && !(he->flags & HIST_DUP)) {
+ if (isset(HISTEXPIREDUPSFIRST) || isset(HISTDEPRECATESPACE)) {
int max_unique_ct = getiparam("SAVEHIST");
do {
if (max_unique_ct-- <= 0) {
he = hist_ring->down;
break;
}
+ if (isset(HISTEXPIREDUPSFIRST) && he->flags & HIST_DUP) {
+ del = he;
+ break;
+ }
+ if (he->flags & HIST_DEPRECATED)
+ del = he;
he = he->down;
- } while (he != hist_ring->down && !(he->flags & HIST_DUP));
- if (he != hist_ring->down) {
+ } while (he != hist_ring->down);
+ if (del && (he = del) != hist_ring->down) {
he->up->down = he->down;
he->down->up = he->up;
he->up = hist_ring;
@@ -959,17 +971,25 @@
return he;
}
-/* A helper function for hend() */
+/* A helper function for hend(). The return is the "save" value:
+ * 0 = skip, 1 = save, 2 = deprecated save, 3 = temporary save. */
static int
should_ignore_line(Eprog prog)
{
+ int spacecount = aliasspacecount;
+
if (!prog)
- return 0;
+ return 1;
- if (isset(HISTIGNORESPACE)) {
- if (*chline == ' ' || aliasspaceflag)
- return 1;
+ if (*chline == ' ')
+ spacecount = 1 + (chline[1] == ' ');
+ if (spacecount) {
+ if (isset(HISTIGNORESPACE)
+ && (spacecount > 1 || !isset(HISTDEPRECATESPACE)))
+ return 3;
+ if (isset(HISTDEPRECATESPACE))
+ return 2;
}
if (isset(HISTNOFUNCTIONS)) {
@@ -977,7 +997,7 @@
wordcode code = *pc;
if (wc_code(code) == WC_LIST && WC_LIST_TYPE(code) & Z_SIMPLE
&& wc_code(pc[2]) == WC_FUNCDEF)
- return 1;
+ return 3;
}
if (isset(HISTNOSTORE)) {
@@ -986,17 +1006,17 @@
b += 8;
if (*b == 'h' && strncmp(b, "history", 7) == 0
&& (!b[7] || b[7] == ' '))
- return 1;
+ return 3;
if (*b == 'f' && b[1] == 'c' && b[2] == ' ' && b[3] == '-') {
b += 3;
do {
if (*++b == 'l')
- return 1;
+ return 3;
} while (ialpha(*b));
}
}
- return 0;
+ return 1;
}
/* say we're done using the history mechanism */
@@ -1044,8 +1064,13 @@
} else
save = 0;
}
- if (chwordpos <= 2 || should_ignore_line(prog))
+ if (chwordpos <= 2) {
+ if (*chline == ' ' && hist_ring->flags & HIST_TMPSTORE)
+ freehistnode((HashNode)hist_ring);
save = 0;
+ }
+ else
+ save = should_ignore_line(prog);
}
if (flag & (HISTFLAG_DONE | HISTFLAG_RECALL)) {
char *ptr;
@@ -1065,7 +1090,12 @@
}
if (save) {
Histent he;
- int keepflags;
+ int newflags;
+
+ for (he = hist_ring; he && he->flags & HIST_FOREIGN;
+ he = up_histent(he)) ;
+ if (he && he->flags & HIST_TMPSTORE)
+ freehistnode((HashNode)he);
for (he = hist_ring; he && he->flags & hist_skip_flags;
he = up_histent(he)) ;
@@ -1083,6 +1113,8 @@
if (isset(HISTREDUCEBLANKS))
histreduceblanks();
}
+ newflags = save == 1? 0
+ : HIST_OLD | HIST_DEPRECATED | (save > 2? HIST_TMPSTORE : 0);
if ((isset(HISTIGNOREDUPS) || isset(HISTIGNOREALLDUPS)) && he
&& histstrcmp(chline, he->text) == 0) {
/* This history entry compares the same as the previous.
@@ -1090,18 +1122,16 @@
* previous one with the current one. This also gets the
* timestamp right. Perhaps, preserve the HIST_OLD flag.
*/
- keepflags = he->flags & HIST_OLD; /* Avoid re-saving */
+ newflags |= he->flags & HIST_OLD; /* Avoid re-saving */
freehistdata(he, 0);
curline.histnum = curhist;
- } else {
- keepflags = 0;
+ } else
he = prepnexthistent();
- }
he->text = ztrdup(chline);
he->stim = time(NULL);
he->ftim = 0L;
- he->flags = keepflags;
+ he->flags = newflags;
if ((he->nwords = chwordpos/2)) {
he->words = (short *)zalloc(chwordpos * sizeof(short));
@@ -1894,8 +1924,10 @@
} else
he->words = (short *)NULL;
addhistnode(histtab, he->text, he);
- if (hist_ring != he)
- curhist--; /* We discarded a foreign duplicate */
+ if (he->flags & HIST_DUP) {
+ freehistnode((HashNode)he);
+ curhist--;
+ }
}
if (start && readflags & HFILE_USE_OPTIONS) {
zsfree(lasthist.text);
@@ -1963,7 +1995,8 @@
if (out) {
for (; he && he->histnum <= xcurhist; he = down_histent(he)) {
if ((writeflags & HFILE_SKIPDUPS && he->flags & HIST_DUP)
- || (writeflags & HFILE_SKIPFOREIGN && he->flags & HIST_FOREIGN))
+ || (writeflags & HFILE_SKIPFOREIGN && he->flags & HIST_FOREIGN)
+ || he->flags & HIST_DEPRECATED)
continue;
if (writeflags & HFILE_SKIPOLD) {
if (he->flags & HIST_OLD)
Index: Src/lex.c
@@ -1601,7 +1601,7 @@
inalmore)) {
inpush(an->text, INP_ALIAS, an);
if (an->text[0] == ' ')
- aliasspaceflag = 1;
+ aliasspacecount = 1 + (an->text[1] == ' ');
lexstop = 0;
if (yytext == copy)
yytext = tokstr;
Index: Src/options.c
@@ -125,6 +125,7 @@
{NULL, "hashlistall", OPT_ALL, HASHLISTALL},
{NULL, "histallowclobber", 0, HISTALLOWCLOBBER},
{NULL, "histbeep", OPT_ALL, HISTBEEP},
+{NULL, "histdeprecatespace", 0, HISTDEPRECATESPACE},
{NULL, "histexpiredupsfirst", 0, HISTEXPIREDUPSFIRST},
{NULL, "histfindnodups", 0, HISTFINDNODUPS},
{NULL, "histignorealldups", 0, HISTIGNOREALLDUPS},
Index: Src/parse.c
@@ -36,7 +36,7 @@
mod_export int incmdpos;
/**/
-int aliasspaceflag;
+int aliasspacecount;
/* != 0 if we are in the middle of a [[ ... ]] */
@@ -432,7 +432,7 @@
{
tok = ENDINPUT;
incmdpos = 1;
- aliasspaceflag = 0;
+ aliasspacecount = 0;
yylex();
init_parse();
return ((par_event()) ? bld_eprog() : NULL);
Index: Src/zsh.h
@@ -1252,6 +1252,8 @@
#define HIST_READ 0x00000004 /* Command was read back from disk*/
#define HIST_DUP 0x00000008 /* Command duplicates a later line */
#define HIST_FOREIGN 0x00000010 /* Command came from another shell */
+#define HIST_DEPRECATED 0x00000020 /* Killed before other unique entries */
+#define HIST_TMPSTORE 0x00000040 /* Kill when not the newest entry */
#define GETHIST_UPWARD (-1)
#define GETHIST_DOWNWARD 1
@@ -1362,6 +1364,7 @@
HASHLISTALL,
HISTALLOWCLOBBER,
HISTBEEP,
+ HISTDEPRECATESPACE,
HISTEXPIREDUPSFIRST,
HISTFINDNODUPS,
HISTIGNOREALLDUPS,
---8<------8<------8<------8<---cut here--->8------>8------>8------>8---
Messages sorted by:
Reverse Date,
Date,
Thread,
Author