circo

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

commit 15c1ada3aa95fa90c27d17bf60507ee0a6aa5bcd
parent 7e9805cdbbb66e0186e0242d4a456d51e200da73
Author: Claudio Alessi <smoppy@gmail.com>
Date:   Mon,  7 Feb 2022 21:53:50 +0100

Initial support for tab-completion

Diffstat:
Mcirco.c | 79+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
Mconfig.def.h | 1+
2 files changed, 76 insertions(+), 4 deletions(-)

diff --git a/circo.c b/circo.c @@ -10,6 +10,7 @@ * To understand everything else, start reading main(). */ +#define _GNU_SOURCE #include <ctype.h> #include <errno.h> #include <locale.h> @@ -50,7 +51,6 @@ char *argv0; #define CURPOS "\33[%d;%dH" #define CURSON "\33[?25h" #define CURSOFF "\33[?25l" -#define TTLSET "\33]0;%s\007" #if defined CTRL && defined _AIX #undef CTRL @@ -123,6 +123,7 @@ void cmd_topic(char *cmd, char *s); void cmdln_chldel(const Arg *arg); void cmdln_chrdel(const Arg *arg); void cmdln_clear(const Arg *arg); +void cmdln_complete(const Arg *arg); void cmdln_cursor(const Arg *arg); void cmdln_wdel(const Arg *arg); void detach(Buffer *b); @@ -173,6 +174,7 @@ void strip_ctrlseqs(char *s); void trim(char *s); void usage(void); void usrin(void); +char *wordleft(char *str, int offset, int *size); /* variables */ FILE *srv, *logp; @@ -391,7 +393,6 @@ cmd_server(char *cmd, char *s) { bprintf(status, "Cannot connect to %s on port %s.\n", host, port); return; } - printf(TTLSET, host); srv = fdopen(fd, "r+"); setbuf(srv, NULL); sout("NICK %s", nick); @@ -475,6 +476,61 @@ cmdln_clear(const Arg *arg) { } void +cmdln_complete(const Arg *arg) { + char word[200]; /* 200 is max chan length */ + char *ws, *we, *epos, *match; + int wlen, mlen, newlen, i; + + if(!sel->cmdlen) + return; + ws = wordleft(sel->cmdbuf, sel->cmdoff, &wlen); + if(!ws || wlen > sizeof word) + return; + memcpy(word, ws, wlen); + word[wlen] = '\0'; + + /* actual search */ + if(word[0] == '/') { + /* search in commands */ + for(i = 0; i < LENGTH(commands); ++i) + if((match = strcasestr(commands[i].name, &word[1]))) + break; + if(!match) + return; + mlen = strlen(match); + + /* preserve the slash */ + ++ws; + --wlen; + } + else if(ISCHANPFX(word[0])) { + /* search buffer name */ + if(!(match = strcasestr(sel->name, word))) + return; + mlen = strlen(match); + } + else { + /* TODO: match a nick in current buffer */ + } + + we = ws + wlen; + epos = &sel->cmdbuf[sel->cmdoff] > we ? &sel->cmdbuf[sel->cmdoff] : we; + + /* check if match exceed buffer size */ + newlen = sel->cmdlen - (epos - ws) + mlen; + if(newlen > sizeof sel->cmdbuf - 1) + return; + + memmove(ws+mlen, epos, sel->cmdlen - (epos - sel->cmdbuf)); + memcpy(ws, match, mlen); + + sel->cmdlen = newlen; + sel->cmdbuf[sel->cmdlen] = '\0'; + sel->cmdoff = ws - sel->cmdbuf + mlen; + sel->need_redraw |= REDRAW_CMDLN; +} + +void cmdln_cursor(const Arg *arg) { if(!arg->i) { sel->cmdoff = 0; @@ -1263,6 +1319,23 @@ usrin(void) { } while((key = getkey()) != -1); } +char * +wordleft(char *str, int offset, int *size) { + char *s = &str[offset], *e; + + while(s != str && (*s == ' ' || *s == '\0')) + --s; + if(!*s || *s == ' ') + return NULL; + while(s != str && *(s - 1) != ' ') + --s; + if(size) { + for(e = s + 1; *e != '\0' && *e != ' '; ++e); + *size = e - s; + } + return s; +} + int main(int argc, char *argv[]) { const char *user = getenv("USER"); @@ -1278,7 +1351,6 @@ main(int argc, char *argv[]) { if(!*nick) strncpy(nick, user ? user : "circo", sizeof nick); - printf(TTLSET, "circo"); setup(); if(*logfile) logp = fopen(logfile, "a"); @@ -1290,6 +1362,5 @@ main(int argc, char *argv[]) { run(); mvprintf(1, rows, "\n"); cleanup(); - printf(TTLSET, ""); return 0; } diff --git a/config.def.h b/config.def.h @@ -38,6 +38,7 @@ static Key keys[] = { { CTRL('u'), cmdln_clear, {0} }, { KeyBackspace, cmdln_chldel, {0} }, { CTRL('d'), cmdln_chrdel, {0} }, + { '\t', cmdln_complete, {0} }, { CTRL('a'), cmdln_cursor, {.i = 0}}, { CTRL('e'), cmdln_cursor, {.i = 999}}, { CTRL('h'), cmdln_cursor, {.i = -1}},