From: Vincent Lefevre Date: Mon, 26 Feb 2007 17:17:13 +0000 (+0000) Subject: Add $history_file and $save_history, for saving command history across X-Git-Tag: mutt-1-5-15-rel~47^2~48 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=36677253ad25081ad3c4bf070d195d99170a90e8;p=mutt Add $history_file and $save_history, for saving command history across sessions. --- diff --git a/UPDATING b/UPDATING index fc1624f8..44a20281 100644 --- a/UPDATING +++ b/UPDATING @@ -4,6 +4,7 @@ mutt. Please read this file carefully when upgrading your installation. The keys used are: !: modified feature, -: deleted feature, +: new feature + + $save_history, $history_file (save history across sessions) + $assumed_charset, $file_charset, $strict_mime + $smtp_url (ESMTP relay support) + $crypt_use_pka (use GPGME PKA signature verification) diff --git a/enter.c b/enter.c index fd7da9d0..bfbbd3ca 100644 --- a/enter.c +++ b/enter.c @@ -562,7 +562,7 @@ int _mutt_enter_string (char *buf, size_t buflen, int y, int x, { mutt_pretty_mailbox (buf); if (!pass) - mutt_history_add (hclass, buf); + mutt_history_add (hclass, buf, 1); rv = 0; goto bye; } @@ -667,7 +667,7 @@ self_insert: /* Convert from wide characters */ my_wcstombs (buf, buflen, state->wbuf, state->lastchar); if (!pass) - mutt_history_add (hclass, buf); + mutt_history_add (hclass, buf, 1); if (multiple) { diff --git a/globals.h b/globals.h index d4c9b7c9..0b87488f 100644 --- a/globals.h +++ b/globals.h @@ -53,6 +53,7 @@ WHERE char *FolderFormat; WHERE char *ForwFmt; WHERE char *Fqdn; WHERE char *HdrFmt; +WHERE char *HistFile; WHERE char *Homedir; WHERE char *Hostname; #ifdef USE_IMAP @@ -195,6 +196,7 @@ WHERE short MenuContext; WHERE short PagerContext; WHERE short PagerIndexLines; WHERE short ReadInc; +WHERE short SaveHist; WHERE short SendmailWait; WHERE short SleepTime INITVAL (1); WHERE short Timeout; diff --git a/history.c b/history.c index 4bee9ab9..78c8f46d 100644 --- a/history.c +++ b/history.c @@ -56,6 +56,145 @@ static void init_history (struct history *h) h->last = 0; } +void mutt_read_histfile (void) +{ + FILE *f; + int line = 0, hclass, read; + char *linebuf = NULL, *p; + size_t buflen; + + if ((f = fopen (HistFile, "r")) == NULL) + return; + + while ((linebuf = mutt_read_line (linebuf, &buflen, f, &line)) != NULL) + { + read = 0; + if (sscanf (linebuf, "%d:%n", &hclass, &read) < 1 || read == 0 || + *(p = linebuf + strlen (linebuf) - 1) != '|') + { + mutt_error (_("Bad history file format (line %d)"), line); + break; + } + *p = '\0'; + p = safe_strdup (linebuf + read); + if (p) + { + mutt_convert_string (&p, "utf-8", Charset, 0); + mutt_history_add (hclass, p, 0); + FREE (&p); + } + } + + fclose (f); + FREE (&linebuf); +} + +static void shrink_histfile (void) +{ + char tmpfname[_POSIX_PATH_MAX]; + FILE *f, *tmp = NULL; + int n[HC_LAST] = { 0 }; + int line, hclass; + char *linebuf = NULL; + size_t buflen; + + if ((f = fopen (HistFile, "r")) == NULL) + return; + + line = 0; + while ((linebuf = mutt_read_line (linebuf, &buflen, f, &line)) != NULL) + { + if (sscanf (linebuf, "%d", &hclass) < 1) + { + mutt_error (_("Bad history file format (line %d)"), line); + goto cleanup; + } + n[hclass]++; + } + + for(hclass = HC_FIRST; hclass < HC_LAST; hclass++) + if (n[hclass] > SaveHist) + { + mutt_mktemp (tmpfname); + if ((tmp = safe_fopen (tmpfname, "w+")) == NULL) + mutt_perror (tmpfname); + break; + } + + if (tmp != NULL) + { + rewind (f); + line = 0; + while ((linebuf = mutt_read_line (linebuf, &buflen, f, &line)) != NULL) + { + if (sscanf (linebuf, "%d", &hclass) < 1) + { + mutt_error (_("Bad history file format (line %d)"), line); + goto cleanup; + } + if (n[hclass]-- <= SaveHist) + fprintf (tmp, "%s\n", linebuf); + } + } + +cleanup: + fclose (f); + FREE (&linebuf); + if (tmp != NULL) + { + if (fflush (tmp) == 0 && + (f = fopen (HistFile, "w")) != NULL) /* __FOPEN_CHECKED__ */ + { + rewind (tmp); + mutt_copy_stream (tmp, f); + fclose (f); + } + fclose (tmp); + unlink (tmpfname); + } +} + +static void save_history (history_class_t hclass, const char *s) +{ + static int n = 0; + FILE *f; + char *tmp, *p; + + if (!s || !*s) /* This shouldn't happen, but it's safer. */ + return; + + if ((f = fopen (HistFile, "a")) == NULL) + { + mutt_perror ("fopen"); + return; + } + + tmp = safe_strdup (s); + mutt_convert_string (&tmp, Charset, "utf-8", 0); + + /* Format of a history item (1 line): ":|". + We add a '|' in order to avoid lines ending with '\'. */ + fprintf (f, "%d:", (int) hclass); + for (p = tmp; *p; p++) + { + /* Don't copy \n as a history item must fit on one line. The string + shouldn't contain such a character anyway, but as this can happen + in practice, we must deal with that. */ + if (*p != '\n') + putc ((unsigned char) *p, f); + } + fputs ("|\n", f); + + fclose (f); + FREE (&tmp); + + if (--n < 0) + { + n = SaveHist; + shrink_histfile(); + } +} + void mutt_init_history(void) { history_class_t hclass; @@ -69,7 +208,7 @@ void mutt_init_history(void) OldSize = HistSize; } -void mutt_history_add (history_class_t hclass, const char *s) +void mutt_history_add (history_class_t hclass, const char *s, int save) { int prev; struct history *h = &History[hclass]; @@ -88,6 +227,8 @@ void mutt_history_add (history_class_t hclass, const char *s) */ if (*s != ' ' && (!h->hist[prev] || mutt_strcmp (h->hist[prev], s) != 0)) { + if (save && SaveHist) + save_history (hclass, s); mutt_str_replace (&h->hist[h->last++], s); if (h->last > HistSize - 1) h->last = 0; diff --git a/history.h b/history.h index bcb87a57..5c9220cb 100644 --- a/history.h +++ b/history.h @@ -35,7 +35,8 @@ enum history_class typedef enum history_class history_class_t; void mutt_init_history(void); -void mutt_history_add(history_class_t, const char *); +void mutt_read_histfile(void); +void mutt_history_add(history_class_t, const char *, int); char *mutt_history_next(history_class_t); char *mutt_history_prev(history_class_t); diff --git a/init.c b/init.c index 3cce5aaf..ce69d166 100644 --- a/init.c +++ b/init.c @@ -3012,6 +3012,8 @@ void mutt_init (int skip_sys_rc, LIST *commands) mutt_exit(1); } + mutt_read_histfile (); + #if 0 set_option (OPTWEED); /* turn weeding on by default */ #endif diff --git a/init.h b/init.h index f0280cac..f5e2057f 100644 --- a/init.h +++ b/init.h @@ -828,6 +828,11 @@ struct option_t MuttVars[] = { ** the string history buffer. The buffer is cleared each time the ** variable is set. */ + { "history_file", DT_PATH, R_NONE, UL &HistFile, UL "~/.mutthistory" }, + /* + ** .pp + ** The file in which Mutt will save its history. + */ { "honor_followup_to", DT_QUAD, R_NONE, OPT_MFUPTO, M_YES }, /* ** .pp @@ -2438,6 +2443,12 @@ struct option_t MuttVars[] = { ** \fBNote:\fP This only applies to mbox and MMDF folders, Mutt does not ** delete MH and Maildir directories. */ + { "save_history", DT_NUM, R_NONE, UL &SaveHist, 0 }, + /* + ** .pp + ** This variable controls the size of the history saved in the + ** ``$$history_file'' file. + */ { "save_name", DT_BOOL, R_NONE, OPTSAVENAME, 0 }, /* ** .pp