circo

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

commit 0bee4b25bcfae98b03fd14c235e418901898259b
parent 033c83c06351e03802e03274184d74b2922410de
Author: Claudio Alessi <smoppy@gmail.com>
Date:   Sat, 22 Jul 2017 17:32:33 +0200

Implement in-buffer editing.
Command line is now a bit more comfortable. Needs for cleanup is becoming serious.

Diffstat:
MREADME.md | 3+--
Mcirco.c | 110++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------------
Mconfig.def.h | 12+++++++++---
3 files changed, 80 insertions(+), 45 deletions(-)

diff --git a/README.md b/README.md @@ -8,8 +8,7 @@ are always visible at the top. Status ====== Input editing is yet incomplete and parsing of server messages need some -cleanup. The code is working, I'm using it for a while and didn't notice any -issue. UTF-8 is not currently supported and I'm not sure it will ever be. +cleanup. UTF-8 is not currently supported and I'm not sure it will ever be. Despite it's minimal design, circo is definitely not a suckless piece of code. It don't even follows in all respect the UNIX philosophy but it provides a very diff --git a/circo.c b/circo.c @@ -57,8 +57,9 @@ struct Buffer { int len; int line; int nlines; - int offln; + int lnoff; int cmdlen; + int cmdoff; Buffer *next; }; @@ -74,12 +75,13 @@ typedef struct { } Key; void attach(Buffer *b); +int bufl2o(char *buf, int len, int line); +int bufnl(char *buf, int len); int bufpos(char *buf, int len, int *line, int *off); void cleanup(void); void cmd_msg(char *s); void cmd_quit(char *s); void cmd_server(char *s); -int countlines(char *buf, int len); void detach(Buffer *b); int dial(char *host, char *port); void die(const char *errstr, ...); @@ -90,11 +92,11 @@ void drawcmdln(void); void *ecalloc(size_t nmemb, size_t size); void editor_chdel(const Arg *arg); void editor_clear(const Arg *arg); +void editor_cursor(const Arg *arg); Buffer *getbuf(char *name); void focusnext(const Arg *arg); void focusprev(const Arg *arg); int getkey(void); -int lineoff(char *buf, int len, int line); void logw(char *txt); int mvprintf(int x, int y, char *fmt, ...); Buffer *newbuf(char *name); @@ -134,6 +136,19 @@ attach(Buffer *b) { buffers = b; } +int +bufl2o(char *buf, int len, int line) { + int off = -1; + + bufpos(buf, len, &line, &off); + return off; +} + +int +bufnl(char *buf, int len) { + return bufpos(buf, len, NULL, NULL); +} + /* * Note: this function is weird and will be removed. I wrote it to enforce DRY. * @@ -215,11 +230,6 @@ cmd_server(char *s) { sout("USER %s localhost %s :%s", nick, host, nick); } -int -countlines(char *buf, int len) { - return bufpos(buf, len, NULL, NULL); -} - void detach(Buffer *b) { Buffer **tb; @@ -284,8 +294,8 @@ drawbuf(void) { if(!sel->len) return; i = sel->line - ? sel->offln - : lineoff(sel->data, sel->len, 1 + (sel->nlines > rows - 2 ? sel->nlines - (rows - 2) : 0)); + ? sel->lnoff + : bufl2o(sel->data, sel->len, 1 + (sel->nlines > rows - 2 ? sel->nlines - (rows - 2) : 0)); x = 1; y = 2; printf(CURSOFF); @@ -315,11 +325,12 @@ drawbuf(void) { void drawcmdln(void) { - int pslen = 4 + strlen(sel->name); /* 1 for the cursor */ - int cmdsz = cols - pslen; + int pslen = 4 + strlen(sel->name); /* "[%s] " + 1 for the cursor */ + int cmdsz = cols - pslen; int i = sel->cmdlen > cmdsz ? sel->cmdlen - cmdsz : 0; mvprintf(1, rows, "[%s] %s%s", sel->name, &sel->cmd[i], CLEARRIGHT); + printf(CURPOS, rows, pslen + (sel->cmdoff - i)); } void * @@ -333,16 +344,39 @@ ecalloc(size_t nmemb, size_t size) { void editor_chdel(const Arg *arg) { - if(!sel->cmdlen) + if(!sel->cmdoff) return; + if(sel->cmdoff < sel->cmdlen) + memmove(&sel->cmd[sel->cmdoff - 1], &sel->cmd[sel->cmdoff], + sel->cmdlen - sel->cmdoff); sel->cmd[--sel->cmdlen] = '\0'; + --sel->cmdoff; drawcmdln(); } void editor_clear(const Arg *arg) { - sel->cmd[0] = '\0'; - sel->cmdlen = 0; + if(!sel->cmdoff) + return; + memmove(sel->cmd, &sel->cmd[sel->cmdoff], sel->cmdlen - sel->cmdoff); + sel->cmdlen -= sel->cmdoff; + sel->cmd[sel->cmdlen] = '\0'; + sel->cmdoff = 0; + drawcmdln(); +} + +void +editor_cursor(const Arg *arg) { + if(!arg->i) { + sel->cmdoff = 0; + } + else { + sel->cmdoff += arg->i; + if(sel->cmdoff < 0) + sel->cmdoff = 0; + else if(sel->cmdoff > sel->cmdlen) + sel->cmdoff = sel->cmdlen; + } drawcmdln(); } @@ -408,14 +442,6 @@ getkey(void) { return key; } -int -lineoff(char *buf, int len, int line) { - int off = -1; - - bufpos(buf, len, &line, &off); - return off; -} - void logw(char *txt) { if(!logp) @@ -602,7 +628,7 @@ printb(Buffer *b, char *fmt, ...) { die("cannot realloc\n"); memcpy(&b->data[b->len], buf, len); b->len += len; - b->nlines = countlines(b->data, b->len); + b->nlines = bufnl(b->data, b->len); logw(buf); return len; } @@ -612,9 +638,9 @@ resize(int x, int y) { rows = x; cols = y; if(sel) { - if(sel->line && sel->offln) - sel->offln = lineoff(sel->data, sel->len, sel->line); - sel->nlines = countlines(sel->data, sel->len); + if(sel->line && sel->lnoff) + sel->lnoff = bufl2o(sel->data, sel->len, sel->line); + sel->nlines = bufnl(sel->data, sel->len); draw(); } } @@ -625,7 +651,7 @@ scroll(const Arg *arg) { return; if(arg->i == 0) { sel->line = 0; - sel->offln = 0; + sel->lnoff = 0; draw(); return; } @@ -636,11 +662,11 @@ scroll(const Arg *arg) { sel->line = 1; else if(sel->line > sel->nlines) sel->line = sel->nlines; - sel->offln = lineoff(sel->data, sel->len, sel->line); - if(sel->offln == -1) { + sel->lnoff = bufl2o(sel->data, sel->len, sel->line); + if(sel->lnoff == -1) { die("This is a bug.\n" - "len=%d line=%d size=%d offln=%d char='%c' nlines=%d\n", - sel->len, sel->line, sel->size, sel->offln, sel->data[sel->offln], sel->nlines); + "len=%d line=%d size=%d lnoff=%d char='%c' nlines=%d\n", + sel->len, sel->line, sel->size, sel->lnoff, sel->data[sel->lnoff], sel->nlines); } draw(); } @@ -730,7 +756,6 @@ usrin(void) { logw(sel->cmd); if(sel->cmd[0] == '\0') return; - sel->cmd[sel->cmdlen] = '\0'; if(sel->cmd[0] == '/') { if(sel->cmdlen == 1) return; @@ -743,22 +768,27 @@ usrin(void) { else { if(!srv) { printb(sel, "You're not connected.\n"); - return; } - sout("PRIVMSG %s :%s", sel->name, sel->cmd); - printb(sel, "%s: %s\n", nick, sel->cmd); + else { + sout("PRIVMSG %s :%s", sel->name, sel->cmd); + printb(sel, "%s: %s\n", nick, sel->cmd); + } } } - sel->cmd[0] = '\0'; sel->cmdlen = 0; + sel->cmdoff = 0; draw(); } else if(isgraph(key) || (key == ' ' && sel->cmdlen)) { - if(sel->cmdlen >= sizeof sel->cmd - 1) + if(sel->cmdlen == sizeof sel->cmd) return; - sel->cmd[sel->cmdlen++] = key; - sel->cmd[sel->cmdlen] = '\0'; + memmove(&sel->cmd[sel->cmdoff+1], &sel->cmd[sel->cmdoff], + sel->cmdlen - sel->cmdoff); + sel->cmd[sel->cmdoff] = key; + sel->cmd[++sel->cmdlen] = '\0'; + if(sel->cmdoff < sizeof sel->cmd - 1) + ++sel->cmdoff; drawcmdln(); } } diff --git a/config.def.h b/config.def.h @@ -12,10 +12,16 @@ Command commands[] = { static Key keys[] = { /* key function argument */ { CTRL('u'), editor_clear, {0} }, - { KeyBackspace,editor_chdel, {0} }, + { KeyBackspace,editor_chdel, {.i = -1} }, + { CTRL('a'), editor_cursor, {.i = 0}}, + { CTRL('e'), editor_cursor, {.i = 999}}, + { CTRL('h'), editor_cursor, {.i = -1}}, + { KeyLeft, editor_cursor, {.i = -1}}, + { CTRL('l'), editor_cursor, {.i = +1}}, + { KeyRight, editor_cursor, {.i = +1}}, { CTRL('n'), focusnext, {0} }, { CTRL('p'), focusprev, {0} }, - { KeyPgUp, scroll, {.i = -20} }, - { KeyPgDw, scroll, {.i = +20} }, + { KeyPgUp, scroll, {.i = -1} }, + { KeyPgDw, scroll, {.i = +1} }, { KeyEnd, scroll, {.i = 0} }, };