From 13ef7e0b82d684cb0c125aecdd4cf40b5374e0eb Mon Sep 17 00:00:00 2001 From: Steve Bennett Date: Wed, 25 Jul 2018 16:51:26 +1000 Subject: [PATCH] Re-add insert optimisation When inserting at the end of the line, if there is sufficient space and no hint to display, simply output the character directly This especially helps when running over a slow serial link Signed-off-by: Steve Bennett --- linenoise.c | 104 ++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 73 insertions(+), 31 deletions(-) diff --git a/linenoise.c b/linenoise.c index 92623a5..1271445 100644 --- a/linenoise.c +++ b/linenoise.c @@ -182,6 +182,7 @@ struct current { int cols; /* Size of the window, in chars */ int nrows; /* How many rows are being used in multiline mode (>= 1) */ int rpos; /* The current row containing the cursor - multiline mode only */ + int availcols; /* refreshLine() caches available cols after the prompt here */ const char *prompt; stringbuf *capture; /* capture buffer, or NULL for none. Always null terminated */ stringbuf *output; /* used only during refreshLine() - output accumulator */ @@ -948,43 +949,52 @@ void linenoiseSetMultiLine(int enableml) } /* Helper of refreshSingleLine() and refreshMultiLine() to show hints - * to the right of the prompt. */ -static void refreshShowHints(struct current *current, const char *buf, int availcols) { + * to the right of the prompt. + * Returns 1 if a hint was shown, or 0 if not + * If 'display' is 0, does no output. Just returns the appropriate return code. + */ +static int refreshShowHints(struct current *current, const char *buf, int availcols, int display) +{ + int rc = 0; if (showhints && hintsCallback && availcols > 0) { int bold = 0; int color = -1; char *hint = hintsCallback(buf, &color, &bold, hintsUserdata); if (hint) { - const char *pt; - if (bold == 1 && color == -1) color = 37; - if (bold || color > 0) { - int props[3] = { bold, color, 49 }; /* bold, color, fgnormal */ - setOutputHighlight(current, props, 3); - } - DRL("", bold, color); - pt = hint; - while (*pt) { - int ch; - int n = utf8_tounicode(pt, &ch); - int width = char_display_width(ch); - - if (width >= availcols) { - DRL(""); - break; + rc = 1; + if (display) { + const char *pt; + if (bold == 1 && color == -1) color = 37; + if (bold || color > 0) { + int props[3] = { bold, color, 49 }; /* bold, color, fgnormal */ + setOutputHighlight(current, props, 3); } - DRL_CHAR(ch); + DRL("", bold, color); + pt = hint; + while (*pt) { + int ch; + int n = utf8_tounicode(pt, &ch); + int width = char_display_width(ch); + + if (width >= availcols) { + DRL(""); + break; + } + DRL_CHAR(ch); - availcols -= width; - outputChars(current, pt, n); - pt += n; - } - if (bold || color > 0) { - clearOutputHighlight(current); + availcols -= width; + outputChars(current, pt, n); + pt += n; + } + if (bold || color > 0) { + clearOutputHighlight(current); + } + /* Call the function to free the hint returned. */ + if (freeHintsCallback) freeHintsCallback(hint, hintsUserdata); } - /* Call the function to free the hint returned. */ - if (freeHintsCallback) freeHintsCallback(hint, hintsUserdata); } } + return rc; } #ifdef USE_TERMIOS @@ -1029,6 +1039,7 @@ static void refreshLineAlt(struct current *current, const char *prompt, const ch int notecursor; int cursorcol = 0; int cursorrow = 0; + int hint; struct esc_parser parser; #ifdef DEBUG_REFRESHLINE @@ -1209,7 +1220,16 @@ static void refreshLineAlt(struct current *current, const char *prompt, const ch DRL("\nafter buf: displaycol=%d, displayrow=%d, cursorcol=%d, cursorrow=%d\n\n", displaycol, displayrow, cursorcol, cursorrow); /* (f) show hints */ - refreshShowHints(current, buf, current->cols - displaycol); + hint = refreshShowHints(current, buf, current->cols - displaycol, 1); + + /* Remember how many many cols are available for insert optimisation */ + if (prompt == current->prompt && hint == 0) { + current->availcols = current->cols - displaycol; + } + else { + /* Can't optimise */ + current->availcols = 0; + } refreshEndChars(current); @@ -1281,17 +1301,39 @@ static int insert_char(struct current *current, int pos, int ch) char buf[MAX_UTF8_LEN + 1]; int offset = utf8_index(sb_str(current->buf), pos); int n = utf8_getchars(buf, ch); + int rc = 1; /* null terminate since sb_insert() requires it */ buf[n] = 0; - /* Optimisation removed - see reason in remove_char() */ - + /* Now we try to optimise in the simple but very common case that: + * - we are inserting at EOL + * - there are enough columns available + * - no hints are being shown + */ + if (pos == current->pos && pos == sb_chars(current->buf)) { + int width = char_display_width(ch); + if (current->availcols > width) { + /* Yes, can optimise */ + current->availcols -= width; + rc = 2; + } + } sb_insert(current->buf, offset, buf); if (current->pos >= pos) { current->pos++; } - return 1; + if (rc == 2) { + if (refreshShowHints(current, sb_str(current->buf), current->availcols, 0)) { + /* A hint needs to be shown, so can't optimise after all */ + rc = 1; + } + else { + /* optimised output */ + outputChars(current, buf, n); + } + } + return rc; } return 0; } -- 2.44.0