diff --git a/components/console/linenoise/linenoise.c b/components/console/linenoise/linenoise.c index 842196f..e011b1a 100644 --- a/components/console/linenoise/linenoise.c +++ b/components/console/linenoise/linenoise.c @@ -122,6 +122,8 @@ static linenoiseCompletionCallback *completionCallback = NULL; static linenoiseHintsCallback *hintsCallback = NULL; static linenoiseFreeHintsCallback *freeHintsCallback = NULL; +static void refreshLineWithCompletion(struct linenoiseState *ls, linenoiseCompletions *lc, int flags); +static void refreshLineWithFlags(struct linenoiseState *l, int flags); static int maskmode = 0; /* Show "***" instead of input. For passwords. */ static int mlmode = 0; /* Multi line mode. Default is single line. */ @@ -251,6 +253,37 @@ static void freeCompletions(linenoiseCompletions *lc) { free(lc->cvec); } +/* Called by completeLine() and linenoiseShow() to render the current + * edited line with the proposed completion. If the current completion table + * is already available, it is passed as second argument, otherwise the + * function will use the callback to obtain it. + * + * Flags are the same as refreshLine*(), that is REFRESH_* macros. */ +static void refreshLineWithCompletion(struct linenoiseState *ls, linenoiseCompletions *lc, int flags) { + /* Obtain the table of completions if the caller didn't provide one. */ + linenoiseCompletions ctable = { 0, NULL }; + if (lc == NULL) { + completionCallback(ls->buf,&ctable); + lc = &ctable; + } + + /* Show the edited line with completion if possible, or just refresh. */ + if (ls->completion_idx < lc->len) { + struct linenoiseState saved = *ls; + ls->len = ls->pos = strlen(lc->cvec[ls->completion_idx]); + ls->buf = lc->cvec[ls->completion_idx]; + refreshLineWithFlags(ls,flags); + ls->len = saved.len; + ls->pos = saved.pos; + ls->buf = saved.buf; + } else { + refreshLineWithFlags(ls,flags); + } + + /* Free the completions table if needed. */ + if (lc != &ctable) freeCompletions(&ctable); +} + /* This is an helper function for linenoiseEdit*() and is called when the * user types the key in order to complete the string currently in the * input. @@ -299,7 +332,6 @@ static int completeLine(struct linenoiseState *ls, int keypressed) { nwritten = snprintf(ls->buf,ls->buflen,"%s", lc.cvec[ls->completion_idx]); ls->len = ls->pos = nwritten; - c = 0; } ls->in_completion = 0; break; @@ -307,13 +339,7 @@ static int completeLine(struct linenoiseState *ls, int keypressed) { /* Show completion or original buffer */ if (ls->in_completion && ls->completion_idx < lc.len) { - struct linenoiseState saved = *ls; - ls->len = ls->pos = strlen(lc.cvec[ls->completion_idx]); - ls->buf = lc.cvec[ls->completion_idx]; - refreshLine(ls); - ls->len = saved.len; - ls->pos = saved.pos; - ls->buf = saved.buf; + refreshLineWithCompletion(ls,&lc,REFRESH_ALL); } else { refreshLine(ls); } @@ -565,11 +591,16 @@ static void refreshMultiLine(struct linenoiseState *l, int flags) { /* Calls the two low level functions refreshSingleLine() or * refreshMultiLine() according to the selected mode. */ -static void refreshLine(struct linenoiseState *l) { +static void refreshLineWithFlags(struct linenoiseState *l, int flags) { if (mlmode) - refreshMultiLine(l,REFRESH_ALL); + refreshMultiLine(l,flags); else - refreshSingleLine(l,REFRESH_ALL); + refreshSingleLine(l,flags); +} + +/* Utility function to avoid specifying REFRESH_ALL all the times. */ +static void refreshLine(struct linenoiseState *l) { + refreshLineWithFlags(l,REFRESH_ALL); } /* Hide the current line, when using the multiplexing API. */ @@ -582,10 +613,11 @@ void linenoiseHide(struct linenoiseState *l) { /* Show the current line, when using the multiplexing API. */ void linenoiseShow(struct linenoiseState *l) { - if (mlmode) - refreshMultiLine(l,REFRESH_WRITE); - else - refreshSingleLine(l,REFRESH_WRITE); + if (l->in_completion) { + refreshLineWithCompletion(l,NULL,REFRESH_WRITE); + } else { + refreshLineWithFlags(l,REFRESH_WRITE); + } } /* Insert the character 'c' at cursor current position.