]> git.lizzy.rs Git - linenoise.git/commitdiff
Re-add insert optimisation
authorSteve Bennett <steveb@workware.net.au>
Wed, 25 Jul 2018 06:51:26 +0000 (16:51 +1000)
committerSteve Bennett <steveb@workware.net.au>
Wed, 25 Jul 2018 06:58:22 +0000 (16:58 +1000)
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 <steveb@workware.net.au>
linenoise.c

index 92623a556a76851e8d4f149b579555b86f6cfeb9..127144558986725b3a17ae2baf91527e79067d77 100644 (file)
@@ -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("<hint bold=%d,color=%d>", bold, color);
-            pt = hint;
-            while (*pt) {
-                int ch;
-                int n = utf8_tounicode(pt, &ch);
-                int width = char_display_width(ch);
-
-                if (width >= availcols) {
-                    DRL("<hinteol>");
-                    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("<hint bold=%d,color=%d>", bold, color);
+                pt = hint;
+                while (*pt) {
+                    int ch;
+                    int n = utf8_tounicode(pt, &ch);
+                    int width = char_display_width(ch);
+
+                    if (width >= availcols) {
+                        DRL("<hinteol>");
+                        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;
 }