Commit 9334052613dcb8ad8c3b3ee319b70c83010ac39a

antirez 2013-02-05T19:51:03

Refactoring: code split into sections. Chars insertion as a function.

diff --git a/linenoise.c b/linenoise.c
index 8df5d77..ed0e5e7 100644
--- a/linenoise.c
+++ b/linenoise.c
@@ -50,7 +50,6 @@
  * - Win32 support
  *
  * Bloat:
- * - Completion?
  * - History search like Ctrl+r in readline?
  *
  * List of escape sequences used by this program, we do everything just
@@ -126,6 +125,11 @@ struct linenoiseState {
 
 static void linenoiseAtExit(void);
 int linenoiseHistoryAdd(const char *line);
+static void refreshLine(struct linenoiseState *l);
+static void refreshLineRaw(int fd, const char *prompt, char *buf, size_t len,
+                           size_t pos, size_t cols);
+
+/* ======================= Low level terminal handling ====================== */
 
 /* Return true if the terminal name is in the list of terminals we know are
  * not able to understand basic escape sequences. */
@@ -139,18 +143,6 @@ static int isUnsupportedTerm(void) {
     return 0;
 }
 
-/* Free the history, but does not reset it. Only used when we have to
- * exit() to avoid memory leaks are reported by valgrind & co. */
-static void freeHistory(void) {
-    if (history) {
-        int j;
-
-        for (j = 0; j < history_len; j++)
-            free(history[j]);
-        free(history);
-    }
-}
-
 /* Raw mode: 1960 magic shit. */
 static int enableRawMode(int fd) {
     struct termios raw;
@@ -193,12 +185,6 @@ static void disableRawMode(int fd) {
         rawmode = 0;
 }
 
-/* At exit we'll try to fix the terminal to the initial conditions. */
-static void linenoiseAtExit(void) {
-    disableRawMode(STDIN_FILENO);
-    freeHistory();
-}
-
 /* Try to get the number of columns in the current terminal, or assume 80
  * if it fails. */
 static int getColumns(void) {
@@ -208,50 +194,22 @@ static int getColumns(void) {
     return ws.ws_col;
 }
 
-/* Rewrite the currently edited line accordingly to the buffer content,
- * cursor position, and number of columns of the terminal. */
-static void refreshLineRaw(int fd, const char *prompt, char *buf, size_t len,
-                           size_t pos, size_t cols)
-{
-    char seq[64];
-    size_t plen = strlen(prompt);
-    
-    while((plen+pos) >= cols) {
-        buf++;
-        len--;
-        pos--;
-    }
-    while (plen+len > cols) {
-        len--;
+/* Clear the screen. Used to handle ctrl+l */
+void linenoiseClearScreen(void) {
+    if (write(STDIN_FILENO,"\x1b[H\x1b[2J",7) <= 0) {
+        /* nothing to do, just to avoid warning. */
     }
-
-    /* Cursor to left edge */
-    snprintf(seq,64,"\x1b[0G");
-    if (write(fd,seq,strlen(seq)) == -1) return;
-    /* Write the prompt and the current buffer content */
-    if (write(fd,prompt,strlen(prompt)) == -1) return;
-    if (write(fd,buf,len) == -1) return;
-    /* Erase to right */
-    snprintf(seq,64,"\x1b[0K");
-    if (write(fd,seq,strlen(seq)) == -1) return;
-    /* Move cursor to original position. */
-    snprintf(seq,64,"\x1b[0G\x1b[%dC", (int)(pos+plen));
-    if (write(fd,seq,strlen(seq)) == -1) return;
-}
-
-/* A wrapper for refreshLineRaw() that take a state struct instead of the
- * single arguments. */
-static void refreshLine(struct linenoiseState *l) {
-    refreshLineRaw(l->fd, l->prompt, l->buf, l->len, l->pos, l->cols);
 }
 
 /* Beep, used for completion when there is nothing to complete or when all
  * the choices were already shown. */
-static void beep() {
+static void linenoiseBeep(void) {
     fprintf(stderr, "\x7");
     fflush(stderr);
 }
 
+/* ============================== Completion ================================ */
+
 /* Free a list of completion option populated by linenoiseAddCompletion(). */
 static void freeCompletions(linenoiseCompletions *lc) {
     size_t i;
@@ -274,7 +232,7 @@ static int completeLine(struct linenoiseState *ls) {
 
     completionCallback(ls->buf,&lc);
     if (lc.len == 0) {
-        beep();
+        linenoiseBeep();
     } else {
         size_t stop = 0, i = 0;
         size_t clen;
@@ -297,7 +255,7 @@ static int completeLine(struct linenoiseState *ls) {
             switch(c) {
                 case 9: /* tab */
                     i = (i+1) % (lc.len+1);
-                    if (i == lc.len) beep();
+                    if (i == lc.len) linenoiseBeep();
                     break;
                 case 27: /* escape */
                     /* Re-show original buffer */
@@ -320,11 +278,89 @@ static int completeLine(struct linenoiseState *ls) {
     return c; /* Return last read character */
 }
 
-/* Clear the screen. Used to handle ctrl+l */
-void linenoiseClearScreen(void) {
-    if (write(STDIN_FILENO,"\x1b[H\x1b[2J",7) <= 0) {
-        /* nothing to do, just to avoid warning. */
+/* Register a callback function to be called for tab-completion. */
+void linenoiseSetCompletionCallback(linenoiseCompletionCallback *fn) {
+    completionCallback = fn;
+}
+
+/* This function is used by the callback function registered by the user
+ * in order to add completion options given the input string when the
+ * user typed <tab>. See the example.c source code for a very easy to
+ * understand example. */
+void linenoiseAddCompletion(linenoiseCompletions *lc, char *str) {
+    size_t len = strlen(str);
+    char *copy = malloc(len+1);
+    memcpy(copy,str,len+1);
+    lc->cvec = realloc(lc->cvec,sizeof(char*)*(lc->len+1));
+    lc->cvec[lc->len++] = copy;
+}
+
+/* =========================== Line editing ================================= */
+
+/* Rewrite the currently edited line accordingly to the buffer content,
+ * cursor position, and number of columns of the terminal. */
+static void refreshLineRaw(int fd, const char *prompt, char *buf, size_t len,
+                           size_t pos, size_t cols)
+{
+    char seq[64];
+    size_t plen = strlen(prompt);
+    
+    while((plen+pos) >= cols) {
+        buf++;
+        len--;
+        pos--;
+    }
+    while (plen+len > cols) {
+        len--;
     }
+
+    /* Cursor to left edge */
+    snprintf(seq,64,"\x1b[0G");
+    if (write(fd,seq,strlen(seq)) == -1) return;
+    /* Write the prompt and the current buffer content */
+    if (write(fd,prompt,strlen(prompt)) == -1) return;
+    if (write(fd,buf,len) == -1) return;
+    /* Erase to right */
+    snprintf(seq,64,"\x1b[0K");
+    if (write(fd,seq,strlen(seq)) == -1) return;
+    /* Move cursor to original position. */
+    snprintf(seq,64,"\x1b[0G\x1b[%dC", (int)(pos+plen));
+    if (write(fd,seq,strlen(seq)) == -1) return;
+}
+
+/* A wrapper for refreshLineRaw() that take a state struct instead of the
+ * single arguments. */
+static void refreshLine(struct linenoiseState *l) {
+    refreshLineRaw(l->fd, l->prompt, l->buf, l->len, l->pos, l->cols);
+}
+
+/* Insert the character 'c' at cursor current position.
+ *
+ * On error writing to the terminal -1 is returned, otherwise 0. */
+int linenoiseEditInsert(struct linenoiseState *l, int c) {
+    if (l->len < l->buflen) {
+        if (l->len == l->pos) {
+            l->buf[l->pos] = c;
+            l->pos++;
+            l->len++;
+            l->buf[l->len] = '\0';
+            if (l->plen+l->len < l->cols) {
+                /* Avoid a full update of the line in the
+                 * trivial case. */
+                if (write(l->fd,&c,1) == -1) return -1;
+            } else {
+                refreshLine(l);
+            }
+        } else {
+            memmove(l->buf+l->pos+1,l->buf+l->pos,l->len-l->pos);
+            l->buf[l->pos] = c;
+            l->len++;
+            l->pos++;
+            l->buf[l->len] = '\0';
+            refreshLine(l);
+        }
+    }
+    return 0;
 }
 
 /* This function is the core of the line editing capability of linenoise.
@@ -484,28 +520,7 @@ up_down_arrow:
             }
             break;
         default:
-            if (l.len < buflen) {
-                if (l.len == l.pos) {
-                    buf[l.pos] = c;
-                    l.pos++;
-                    l.len++;
-                    buf[l.len] = '\0';
-                    if (l.plen+l.len < l.cols) {
-                        /* Avoid a full update of the line in the
-                         * trivial case. */
-                        if (write(fd,&c,1) == -1) return -1;
-                    } else {
-                        refreshLine(&l);
-                    }
-                } else {
-                    memmove(buf+l.pos+1,buf+l.pos,l.len-l.pos);
-                    buf[l.pos] = c;
-                    l.len++;
-                    l.pos++;
-                    buf[l.len] = '\0';
-                    refreshLine(&l);
-                }
-            }
+            if (linenoiseEditInsert(&l,c)) return -1;
             break;
         case 21: /* Ctrl+u, delete the whole line. */
             buf[0] = '\0';
@@ -599,21 +614,24 @@ char *linenoise(const char *prompt) {
     }
 }
 
-/* Register a callback function to be called for tab-completion. */
-void linenoiseSetCompletionCallback(linenoiseCompletionCallback *fn) {
-    completionCallback = fn;
+/* ================================ History ================================= */
+
+/* Free the history, but does not reset it. Only used when we have to
+ * exit() to avoid memory leaks are reported by valgrind & co. */
+static void freeHistory(void) {
+    if (history) {
+        int j;
+
+        for (j = 0; j < history_len; j++)
+            free(history[j]);
+        free(history);
+    }
 }
 
-/* This function is used by the callback function registered by the user
- * in order to add completion options given the input string when the
- * user typed <tab>. See the example.c source code for a very easy to
- * understand example. */
-void linenoiseAddCompletion(linenoiseCompletions *lc, char *str) {
-    size_t len = strlen(str);
-    char *copy = malloc(len+1);
-    memcpy(copy,str,len+1);
-    lc->cvec = realloc(lc->cvec,sizeof(char*)*(lc->len+1));
-    lc->cvec[lc->len++] = copy;
+/* At exit we'll try to fix the terminal to the initial conditions. */
+static void linenoiseAtExit(void) {
+    disableRawMode(STDIN_FILENO);
+    freeHistory();
 }
 
 /* Using a circular buffer is smarter, but a bit more complex to handle. */