diff options
author | Kaz Kyheku <kaz@kylheku.com> | 2020-02-18 06:40:15 -0800 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2020-02-18 06:40:15 -0800 |
commit | e41669c53b57fa19f614e22a328fdf181d9c8f46 (patch) | |
tree | ab774f89fafa02a26ae4cacddde504fa85962fbd /linenoise | |
parent | 3080fb5f28e0337b5859f4d6eb19bda9207a65fa (diff) | |
download | txr-e41669c53b57fa19f614e22a328fdf181d9c8f46.tar.gz txr-e41669c53b57fa19f614e22a328fdf181d9c8f46.tar.bz2 txr-e41669c53b57fa19f614e22a328fdf181d9c8f46.zip |
listener: append to .txr_history instead of clobbering.
This patch addresses the problem of history loss that
occurs when a user juggles multiple TXR sessions that
all clobber the same history file.
* linenoise/linenoise.c (struct lino_state): New member,
loaded_lines, keeping track of how many of the lines in the
history came from loading the history file. Lines between
[0] and [loaded_lines - 1] are loaded lines. New lines
occur between [loaded_lines] and [history_len - 1].
(lino_hist_add): Reset loaded_lines to zero when creating
history for the first time. Not really necessary since the
structure starts zero-filled. When a line of history is
erased, then it must be a loaded line, unless loaded_lines
is zero. Thus, then decrement loaded_lines to account for a
loss of a loaded line, but don't decrement below zero.
(lino_hist_set_max_len): Setting the max length can cause
history to be trimmed, so we must adjust loaded_lines to
account for any loaded lines that get discarded.
(lino_hist_save): Takes a new parameter which indicates
whether to just save the new history by appending it to the
given file, or to overwrite the file with the entire history.
In either case, once we save the history, we assume that all
of our lines are loaded lines and set loaded_lines to
hist_len. In the future, this last step will help implement
incremental saving mid-way through a sesssion.
(lino_hist_load): Error out if there is already a history.
With this loaded_lines logic, it really wouldn't make sense to
read history more than once. After loading, set loaded_lines
to hist_len.
* linenoise/linenoise.h (enum lino_file_mode): New enumeration
lino_append.
(lino_hist_save): Declaration updated.
* parser.c (repl): Implement new history saving protocol.
The history file is read using a temporary instance of
linenoise, which has the effect of trimming it to the required
number of lines. This is written to a temporary file, to which
the newly entered lines are appended, and which is finally
renamed to replace the history file.
(lino_mode_str): Add "a" entry corresponding to lino_append.
(lino_open): Do the fchmod in the lino_append case also.
* txr.1: Documented the new handling of the history file.
Diffstat (limited to 'linenoise')
-rw-r--r-- | linenoise/linenoise.c | 25 | ||||
-rw-r--r-- | linenoise/linenoise.h | 3 |
2 files changed, 24 insertions, 4 deletions
diff --git a/linenoise/linenoise.c b/linenoise/linenoise.c index bdb0fedc..92a5b0e7 100644 --- a/linenoise/linenoise.c +++ b/linenoise/linenoise.c @@ -106,6 +106,7 @@ struct lino_state { int mlmode; /* Multi line mode. Default is single line. */ int history_max_len; int history_len; + int loaded_lines; /* How many lines come from load. */ wchar_t **history; wchar_t *clip; /* Selection */ wchar_t *result; /* Previous command result. */ @@ -2680,6 +2681,7 @@ int lino_hist_add(lino_t *ls, const wchar_t *line) { ls->history = coerce(wchar_t **, lino_os.alloc_fn(size)); if (ls->history == NULL) return 0; memset(ls->history, 0, size); + ls->loaded_lines = 0; } /* Don't add duplicated lines, unless we are resubmitting historic lines. */ @@ -2695,6 +2697,8 @@ int lino_hist_add(lino_t *ls, const wchar_t *line) { lino_os.free_fn(ls->history[0]); memmove(ls->history,ls->history+1,(ls->history_max_len-1)*sizeof *ls->history); ls->history_len--; + if (ls->loaded_lines > 0) + ls->loaded_lines--; } ls->history[ls->history_len] = linecopy; ls->history_len++; @@ -2723,6 +2727,10 @@ int lino_hist_set_max_len(lino_t *ls, int len) { for (j = 0; j < tocopy-len; j++) lino_os.free_fn(ls->history[j]); tocopy = len; + + ls->loaded_lines -= (tocopy - len); + if (ls->loaded_lines < 0) + ls->loaded_lines = 0; } memset(nsv, 0, sizeof *nsv * len); memcpy(nsv, ls->history+(ls->history_len-tocopy), sizeof *ls->history * tocopy); @@ -2736,8 +2744,10 @@ int lino_hist_set_max_len(lino_t *ls, int len) { /* Save the history in the specified file. On success 0 is returned * otherwise -1 is returned. */ -int lino_hist_save(lino_t *ls, const wchar_t *filename) { - mem_t *fp = lino_os.open_fn(filename, lino_overwrite); +int lino_hist_save(lino_t *ls, const wchar_t *filename, int new_only) { + int from = new_only ? ls->loaded_lines : 0; + mem_t *fp = lino_os.open_fn(filename, + new_only ? lino_append : lino_overwrite); int j; if (fp == NULL) { @@ -2745,11 +2755,13 @@ int lino_hist_save(lino_t *ls, const wchar_t *filename) { return -1; } - for (j = 0; j < ls->history_len; j++) { + for (j = from; j < ls->history_len; j++) { lino_os.puts_file_fn(fp, ls->history[j]); lino_os.puts_file_fn(fp, L"\n"); } + ls->loaded_lines = ls->history_len; + lino_os.close_fn(fp); return 0; } @@ -2768,6 +2780,12 @@ int lino_hist_load(lino_t *ls, const wchar_t *filename) { return -1; } + if (ls->history) { + ls->error = lino_error; + lino_os.close_fn(fp); + return -1; + } + while (lino_os.getl_fn(fp, buf, LINENOISE_MAX_LINE) != NULL) { wchar_t *p = wcschr(buf, '\n'); if (p) @@ -2776,6 +2794,7 @@ int lino_hist_load(lino_t *ls, const wchar_t *filename) { } lino_os.close_fn(fp); + ls->loaded_lines = ls->history_len; return 0; } diff --git a/linenoise/linenoise.h b/linenoise/linenoise.h index 178df11c..05f66632 100644 --- a/linenoise/linenoise.h +++ b/linenoise/linenoise.h @@ -58,6 +58,7 @@ typedef unsigned char mem_t; typedef enum lino_file_mode { lino_read, lino_overwrite, + lino_append, } lino_file_mode_t; typedef struct lino_os { @@ -112,7 +113,7 @@ lino_error_t lino_get_error(lino_t *); lino_error_t lino_set_error(lino_t *, lino_error_t); /* returns old */ int lino_hist_add(lino_t *, const wchar_t *line); int lino_hist_set_max_len(lino_t *, int len); -int lino_hist_save(lino_t *, const wchar_t *filename); +int lino_hist_save(lino_t *, const wchar_t *filename, int new_only); int lino_hist_load(lino_t *, const wchar_t *filename); void lino_set_result(lino_t *, wchar_t *); /* takes ownership of malloced mem; modifies it */ int lino_clear_screen(lino_t *); |