circo

claudio's IRC oasis
git clone git://git.bitsmanent.org/circo
Log | Files | Refs | README | LICENSE

commit 76c376f48cd317fdf2f4a4b6e8b9bb4b3127f075
parent 8a567100e6a0d6fc84d606c0ae529b1e8fefde86
Author: Claudio Alessi <smoppy@gmail.com>
Date:   Sun, 30 Jul 2017 17:07:55 +0200

Implement command line history.
Also fix two line overflows in usrin().

Diffstat:
MREADME.md | 4+---
Mcirco.c | 79++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
Mconfig.def.h | 2++
3 files changed, 75 insertions(+), 10 deletions(-)

diff --git a/README.md b/README.md @@ -17,11 +17,9 @@ one would expect from an IRC client for the console: - Command line - Infinite scrolling - Resize handling -- Command history* +- Command history - Raw IRC commands -*To be implemented. - None of the CTCP specification has been (nor will be) implemented, which means no DCC at all. In other words: direct chat and files sending are not allowed. diff --git a/circo.c b/circo.c @@ -57,6 +57,7 @@ struct Buffer { char *data; char name[256]; char cmd[BUFSZ]; + char *hist; int size; int len; int line; @@ -64,6 +65,9 @@ struct Buffer { int lnoff; int cmdlen; int cmdoff; + int histsz; + int histlen; + int histlnoff; int need_redraw; Buffer *next; }; @@ -111,6 +115,8 @@ void focusnext(const Arg *arg); void focusprev(const Arg *arg); void freebuf(Buffer *b); int getkey(void); +void history(const Arg *arg); +void histpush(char *buf, int len); void logw(char *txt); int mvprintf(int x, int y, char *fmt, ...); Buffer *newbuf(char *name); @@ -377,10 +383,14 @@ cmdln_cursor(const Arg *arg) { } else { sel->cmdoff += arg->i; - if(sel->cmdoff < 0) + if(sel->cmdoff < 0) { sel->cmdoff = 0; - else if(sel->cmdoff > sel->cmdlen) - sel->cmdoff = sel->cmdlen; + } + else if(sel->cmdoff > sel->cmdlen - 1) { + sel->cmdoff = sel->cmdlen - 1; + if(sel->cmdlen < sizeof sel->cmd - 1) + ++sel->cmdoff; + } } sel->need_redraw = 1; } @@ -605,6 +615,59 @@ getkey(void) { } void +history(const Arg *arg) { + int nl, n, i; + + if(!sel->histsz) + return; + for(i = nl = 0; i < sel->histsz; i += strlen(&sel->hist[i]) + 2, ++nl); + if(!sel->histlnoff) { + if(sel->cmdlen) { + histpush(sel->cmd, sel->cmdlen); + /* don't ++nl since the line has to be skipped */ + } + sel->histlnoff = nl+1; + } + n = sel->histlnoff + arg->i; + if(n < 1) + n = 1; + else if(n > nl) + n = 0; + sel->histlnoff = n; + if(sel->histlnoff) { + for(i = 0; i < sel->histsz && --n; i += strlen(&sel->hist[i]) + 2); + sel->cmdlen = strlen(&sel->hist[i]); + memcpy(sel->cmd, &sel->hist[i], sel->cmdlen); + } + else { + sel->cmdlen = 0; + } + sel->cmdoff = 0; + sel->cmd[sel->cmdlen] = '\0'; + drawcmdln(); +} + +void +histpush(char *buf, int len) { + int nl, i; + + /* do not clone unchanged lines */ + if(sel->histlnoff) { + for(i = 0, nl = 1; i < sel->histsz && nl != sel->histlnoff; i += strlen(&sel->hist[i]) + 2, ++nl); + if(!memcmp(&sel->hist[i], buf, len)) + return; + } + if((i = sel->histsz)) { + ++i; + ++sel->histsz; + } + if(!(sel->hist = realloc(sel->hist, (sel->histsz += len + 1)))) + die("Cannot realloc\n"); + memcpy(&sel->hist[i], buf, len); + sel->hist[i + len] = '\0'; +} + +void logw(char *txt) { if(!logp) return; @@ -711,7 +774,7 @@ printb(Buffer *b, char *fmt, ...) { va_end(ap); if(!b->size || b->len + len >= b->size) if(!(b->data = realloc(b->data, b->size += len + BUFSZ))) - die("cannot realloc\n"); + die("Cannot realloc\n"); memcpy(&b->data[b->len], buf, len); b->len += len; b->nlines = bufinfo(b->data, b->len, 0, TotalLines); @@ -953,9 +1016,11 @@ usrin(void) { if(sel->cmd[0] == '/') { if(sel->cmdlen == 1) return; + histpush(sel->cmd, sel->cmdlen); parsecmd(); } else { + histpush(sel->cmd, sel->cmdlen); if(sel == status) printb(sel, "Cannot send text here.\n"); else if(!srv) @@ -963,11 +1028,11 @@ usrin(void) { else privmsg(sel->name, sel->cmd); } - sel->cmd[sel->cmdlen = sel->cmdoff = 0] = '\0'; + sel->cmd[sel->cmdlen = sel->cmdoff = sel->histlnoff = 0] = '\0'; sel->need_redraw = 1; } else if(isgraph(key) || (key == ' ' && sel->cmdlen)) { - if(sel->cmdlen == sizeof sel->cmd) { + if(sel->cmdlen == sizeof sel->cmd - 1) { sel->cmd[sel->cmdoff] = key; sel->need_redraw = 1; return; @@ -976,7 +1041,7 @@ usrin(void) { sel->cmdlen - sel->cmdoff); sel->cmd[sel->cmdoff] = key; sel->cmd[++sel->cmdlen] = '\0'; - if(sel->cmdoff < sizeof sel->cmd - 1) + if(sel->cmdlen < sizeof sel->cmd - 1) ++sel->cmdoff; sel->need_redraw = 1; } diff --git a/config.def.h b/config.def.h @@ -34,4 +34,6 @@ static Key keys[] = { { KeyPgUp, scroll, {.i = -1} }, { KeyPgDw, scroll, {.i = +1} }, { KeyEnd, scroll, {.i = 0} }, + { KeyUp, history, {.i = -1} }, + { KeyDown, history, {.i = +1} }, };