summaryrefslogtreecommitdiffstats
path: root/linenoise/linenoise.c
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2015-09-12 10:02:56 -0700
committerKaz Kylheku <kaz@kylheku.com>2015-09-12 10:02:56 -0700
commitd3868fc92143ff9506606830b16c47051e4ea1e4 (patch)
tree4e848728702fecee6ed324b2caba209772a7306d /linenoise/linenoise.c
parentce937a42102cf549662678cd91026f6aa1b0a7cd (diff)
downloadtxr-d3868fc92143ff9506606830b16c47051e4ea1e4.tar.gz
txr-d3868fc92143ff9506606830b16c47051e4ea1e4.tar.bz2
txr-d3868fc92143ff9506606830b16c47051e4ea1e4.zip
linenoise: Ctrl-R search
* linenoise/linenoise.c (next_hist_match, history_search): New static function. (edit): New Ctrl-R case added to early switch that also handles Tab completion, and calls history_search. (lino_free): Adding null check, so we can safely call lino_free(0). history_search relies on this. * txr.1: Documented search.
Diffstat (limited to 'linenoise/linenoise.c')
-rw-r--r--linenoise/linenoise.c138
1 files changed, 135 insertions, 3 deletions
diff --git a/linenoise/linenoise.c b/linenoise/linenoise.c
index 404cf284..47d1754e 100644
--- a/linenoise/linenoise.c
+++ b/linenoise/linenoise.c
@@ -390,6 +390,133 @@ void lino_add_completion(lino_completions_t *lc, const char *str) {
lc->cvec[lc->len++] = copy;
}
+static int next_hist_match(lino_t *l, char *pat, int cur, size_t *offs)
+{
+ int i;
+
+ if (cur >= l->history_len)
+ cur = l->history_len - 1;
+
+ for (i = cur; i >= 0; i--) {
+ char *hline = l->history[i];
+ char *pmatch = strstr(hline, pat);
+ if (pmatch != 0) {
+ *offs = pmatch - hline;
+ return i;
+ }
+ }
+ return -1;
+}
+
+static int history_search(lino_t *l)
+{
+ char hpat[128] = "";
+ int hi = l->history_len - l->history_index - 2 + (l->history_index == 0);
+ int hp = hi, hl = 0, stop = 0;
+ size_t dp = l->dpos;
+ const char *fmt = "[%s]%s";
+ size_t ex = strlen(fmt) - 2*strlen("%s");
+ lino_t *lc = lino_copy(l), *ld = lino_copy(l);
+ int c = -1;
+
+ if (lc == 0 || ld == 0)
+ goto out;
+
+ lc->prompt = "search:";
+
+ while (!stop) {
+ size_t nw = snprintf(lc->data, sizeof lc->data, fmt, hpat, l->data);
+ int vb = 0;
+ lc->dlen = nw;
+ lc->dpos = dp + hl + ex;
+
+ if (lc->dpos > lc->dlen)
+ lc->dpos = lc->dlen;
+
+ refresh_line(lc);
+
+ for (;;) {
+ unsigned char byte;
+ int nread = read(lc->ifd, &byte, 1);
+
+ if (nread <= 0) {
+ c = nread;
+ stop = 1;
+ } else {
+ c = byte;
+
+ if (vb)
+ goto verbatim;
+
+ switch (c) {
+ default:
+ if (c < 32)
+ continue;
+ verbatim:
+ if (hl >= sizeof hpat)
+ break;
+ hpat[hl++] = c;
+ /* fallthrough */
+ if (0) {
+ case CTL('R'):
+ if (hl == 0) {
+ generate_beep(lc);
+ break;
+ }
+ hp = hi - 1;
+ }
+
+ {
+ int ni = next_hist_match(l, hpat, hp, &dp);
+
+ if (ni < 0)
+ break;
+
+ hi = ni;
+ strcpy(l->data, l->history[hi]);
+ l->dpos = l->dlen = strlen(l->data);
+ }
+ break;
+ case BACKSPACE: case CTL('H'):
+ if (hl == 0)
+ break;
+
+ hpat[--hl] = 0;
+ break;
+ case ENTER:
+ stop = 1;
+ break;
+ case CTL('C'):
+ strcpy(l->data, ld->data);
+ l->dpos = ld->dpos;
+ l->dlen = ld->dlen;
+ stop = 1;
+ c = 0;
+ break;
+ case CTL('F'): case CTL('B'):
+ case CTL('N'): case CTL('P'):
+ case ESC:
+ if (hi < l->history_len)
+ l->history_index = l->history_len - hi - 1;
+ l->dpos = dp;
+ stop = 1;
+ break;
+ case CTL('V'):
+ vb = 1;
+ continue;
+ }
+ }
+ break;
+ }
+ }
+
+out:
+ lino_free(lc);
+ lino_free(ld);
+ refresh_line(l);
+ return c;
+}
+
/* =========================== Line editing ================================= */
/* We define a very simple "append buffer" structure, that is an heap
@@ -786,6 +913,9 @@ static int edit(lino_t *l, const char *prompt)
if (l->completion_callback != NULL)
c = complete_line(l);
break;
+ case CTL('R'):
+ c = history_search(l);
+ break;
}
if (c < 0)
@@ -1048,9 +1178,11 @@ static void lino_cleanup(lino_t *ls)
void lino_free(lino_t *ls)
{
- unlink_from_list(ls);
- lino_cleanup(ls);
- free(ls);
+ if (ls != 0) {
+ unlink_from_list(ls);
+ lino_cleanup(ls);
+ free(ls);
+ }
}
lino_error_t lino_get_error(lino_t *l)