From: Štěpán Balážik Date: Wed, 18 Jan 2017 13:35:02 +0000 (+0100) Subject: kresc: add basic tab-completion X-Git-Tag: v1.3.0~23^2~86^2~7 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=4aad4e532c35b7f91435adcbfa81046bbf978dbd;p=thirdparty%2Fknot-resolver.git kresc: add basic tab-completion --- diff --git a/daemon/daemon.mk b/daemon/daemon.mk index ca0e39083..8fe117f1b 100644 --- a/daemon/daemon.mk +++ b/daemon/daemon.mk @@ -63,6 +63,7 @@ ifeq ($(HAS_libedit), yes) kresc_SOURCES := daemon/kresc.c kresc_CFLAGS += -fPIE $(libedit_CFLAGS) kresc_LIBS += $(libedit_LIBS) +kresc_DEPEND := $(libkres) $(contrib) $(eval $(call make_sbin,kresc,daemon,yes)) client: $(kresc) client-install: kresc-install diff --git a/daemon/kresc.c b/daemon/kresc.c index 9c36ec985..b56959e2e 100644 --- a/daemon/kresc.c +++ b/daemon/kresc.c @@ -14,16 +14,102 @@ along with this program. If not, see . */ #include +#include +#include #include #include #include #include +#include #include #include #include +#define HISTORY_FILE ".kresc_history" +#define PROGRAM_NAME "kresc" + FILE *g_tty = NULL; //!< connection to the daemon +static char *run_cmd(const char *cmd, uint32_t * msg_len); + +char *prompt(EditLine * e) +{ + return PROGRAM_NAME "> "; +} + +bool starts_with(const char *a, const char *b) +{ + if (strncmp(a, b, strlen(b)) == 0) + return 1; + return 0; +} + +static unsigned char complete(EditLine * el, int ch) +{ + int argc, pos; + const char **argv; + const LineInfo *li = el_line(el); + Tokenizer *tok = tok_init(NULL); + // Parse the line. + int ret = tok_line(tok, li, &argc, &argv, NULL, &pos); + + uint32_t msg_len; + + char *help = run_cmd("help()", &msg_len); + if (!help) { + perror("While communication with daemon"); + goto complete_exit; + } + + if (ret != 0) { + goto complete_exit; + } + + if (argc == 0) { + printf("\n%s", help); + } + + char *lines; + lines = strtok(help, "\n"); + int matches = 0; + bool exactmatch = 0; + char *lastmatch; + int i = 0; + while (lines != NULL) { + if (!(i % 2)) + if (argv[0] && starts_with(lines, argv[0])) { + printf("\n%s", lines); + lastmatch = lines; + matches++; + if (!strcmp(lines, argv[0])) + exactmatch = 1; + } + lines = strtok(NULL, "\n"); + i++; + } + printf("\n"); + if (matches == 1) { + char *brace = strchr(lastmatch, '('); + if (brace != NULL) + *(brace + 1) = '\0'; + el_deletestr(el, pos); + el_insertstr(el, lastmatch); + pos = strlen(lastmatch); + if (exactmatch && brace == NULL) { + char *prettyprint = run_cmd(lastmatch, &msg_len); + printf("%s", prettyprint); + el_insertstr(el, "."); + free(prettyprint); + } + } + +complete_exit: + free(help); + tok_reset(tok); + tok_end(tok); + return CC_REDISPLAY; +} + //! Initialize connection to the daemon; return 0 on success. static int init_tty(const char *path) { @@ -61,45 +147,83 @@ static int init_tty(const char *path) } //! Run a command on the daemon; return the answer or NULL on failure. -static char *run_cmd(const char *cmd) +static char *run_cmd(const char *cmd, uint32_t * msg_len) { if (!g_tty || !cmd) { assert(false); return NULL; } + printf("cmd: %s\n", cmd); + if (fprintf(g_tty, "%s", cmd) < 0 || fflush(g_tty)) return NULL; uint32_t len; if (!fread(&len, sizeof(len), 1, g_tty)) return NULL; - char *msg = malloc(len); + char *msg = malloc(1 + (size_t) len); if (!msg) return NULL; - if (!fread(msg, len, 1, g_tty)) { + if (len && !fread(msg, len, 1, g_tty)) { free(msg); return NULL; } + msg[len] = '\0'; + *msg_len = len; return msg; } -//! Prototype; TODO: editline. static int interact() { - char *buf = NULL; - size_t buf_len = 0; - ssize_t len; - while (getline(&buf, &buf_len, stdin) >= 0) { - char *msg = run_cmd(buf); - if (!msg) { - perror("While communication with daemon"); - free(buf); - return 1; + + EditLine *el; + History *hist; + int count; + const char *line; + int keepreading = 1; + HistEvent ev; + el = el_init(PROGRAM_NAME, stdin, stdout, stderr); + el_set(el, EL_PROMPT, &prompt); + el_set(el, EL_EDITOR, "emacs"); + el_set(el, EL_ADDFN, PROGRAM_NAME "-complete", + "Perform " PROGRAM_NAME " completion.", complete); + el_set(el, EL_BIND, "^I", PROGRAM_NAME "-complete", NULL); + + hist = history_init(); + if (hist == 0) { + perror("While initializing command history"); + return 1; + } + history(hist, &ev, H_SETSIZE, 800); + el_set(el, EL_HIST, history, hist); + + const char hist_file[] = HISTORY_FILE; + history(hist, &ev, H_LOAD, hist_file); + + while (keepreading) { + line = el_gets(el, &count); + if (count > 0) { + history(hist, &ev, H_ENTER, line); + uint32_t msg_len; + char *msg = run_cmd(line, &msg_len); + if (!msg) { + perror("While communication with daemon"); + history_end(hist); + el_end(el); + free(msg); + return 1; + } + printf("%s", msg); + if (msg_len == 0 || msg[msg_len - 1] != '\n') { + printf("\n"); + } + printf("%d\n", msg_len); + history(hist, &ev, H_SAVE, hist_file); + + free(msg); } - printf("%s", msg); - free(msg); } - free(buf); - + history_end(hist); + el_end(el); if (feof(stdin)) return 0; perror("While reading input");