Hints WIP
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
diff --git a/README.markdown b/README.markdown
index a0661a0..a876428 100644
--- a/README.markdown
+++ b/README.markdown
@@ -6,6 +6,7 @@ MongoDB, and Android.
* Single and multi line editing mode with the usual key bindings implemented.
* History handling.
* Completion.
+* Hints (suggestions at the right of the prompt as you type).
* About 1,100 lines of BSD license source code.
* Only uses a subset of VT100 escapes (ANSI.SYS compatible).
@@ -51,3 +52,8 @@ Patches should be provided in the respect of linenoise sensibility for small
easy to understand code.
Send feedbacks to antirez at gmail
+
+## The API
+
+Linenoise is very easy to use, and reading the example shipped with the
+library will make it trivial.
diff --git a/example.c b/example.c
index a2f0936..3a544d3 100644
--- a/example.c
+++ b/example.c
@@ -11,6 +11,15 @@ void completion(const char *buf, linenoiseCompletions *lc) {
}
}
+char *hints(const char *buf, int *color, int *bold) {
+ if (!strcasecmp(buf,"hello")) {
+ *color = 35;
+ *bold = 0;
+ return " World";
+ }
+ return NULL;
+}
+
int main(int argc, char **argv) {
char *line;
char *prgname = argv[0];
@@ -34,6 +43,7 @@ int main(int argc, char **argv) {
/* Set the completion callback. This will be called every time the
* user uses the <tab> key. */
linenoiseSetCompletionCallback(completion);
+ linenoiseSetHintsCallback(hints);
/* Load history from file. The history file is just a plain text file
* where entries are separated by newlines. */
diff --git a/linenoise.c b/linenoise.c
index 30d64ec..193adff 100644
--- a/linenoise.c
+++ b/linenoise.c
@@ -120,6 +120,8 @@
#define LINENOISE_MAX_LINE 4096
static char *unsupported_term[] = {"dumb","cons25","emacs",NULL};
static linenoiseCompletionCallback *completionCallback = NULL;
+static linenoiseHintsCallback *hintsCallback = NULL;
+static linenoiseFreeHintsCallback *freeHintsCallback = NULL;
static struct termios orig_termios; /* In order to restore at exit.*/
static int rawmode = 0; /* For atexit() function to check if restore is needed*/
@@ -407,6 +409,18 @@ void linenoiseSetCompletionCallback(linenoiseCompletionCallback *fn) {
completionCallback = fn;
}
+/* Register a hits function to be called to show hits to the user at the
+ * right of the prompt. */
+void linenoiseSetHintsCallback(linenoiseHintsCallback *fn) {
+ hintsCallback = fn;
+}
+
+/* Register a function to free the hints returned by the hints callback
+ * registered with linenoiseSetHintsCallback(). */
+void linenoiseSetFreeHintsCallback(linenoiseFreeHintsCallback *fn) {
+ freeHintsCallback = 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
@@ -456,6 +470,27 @@ static void abFree(struct abuf *ab) {
free(ab->b);
}
+/* Helper of refreshSingleLine() and refreshMultiLine() to show hints
+ * to the right of the prompt. */
+void refreshShowHints(struct abuf *ab, struct linenoiseState *l, int plen) {
+ char seq[64];
+ if (hintsCallback && plen+l->len < l->cols) {
+ int color, bold;
+ char *hint = hintsCallback(l->buf,&color,&bold);
+ if (hint) {
+ int hintlen = strlen(hint);
+ int hintmaxlen = l->cols-(plen+l->len);
+ if (hintlen > hintmaxlen) hintlen = hintmaxlen;
+ snprintf(seq,64,"\033[%d;%d;49m",bold,color);
+ abAppend(ab,seq,strlen(seq));
+ abAppend(ab,hint,hintlen);
+ abAppend(ab,"\033[0m",4);
+ /* Call the function to free the hint returned. */
+ if (freeHintsCallback) freeHintsCallback(hint);
+ }
+ }
+}
+
/* Single line low level line refresh.
*
* Rewrite the currently edited line accordingly to the buffer content,
@@ -485,6 +520,8 @@ static void refreshSingleLine(struct linenoiseState *l) {
/* Write the prompt and the current buffer content */
abAppend(&ab,l->prompt,strlen(l->prompt));
abAppend(&ab,buf,len);
+ /* Show hits if any. */
+ refreshShowHints(&ab,l,plen);
/* Erase to right */
snprintf(seq,64,"\x1b[0K");
abAppend(&ab,seq,strlen(seq));
@@ -538,6 +575,9 @@ static void refreshMultiLine(struct linenoiseState *l) {
abAppend(&ab,l->prompt,strlen(l->prompt));
abAppend(&ab,l->buf,l->len);
+ /* Show hits if any. */
+ refreshShowHints(&ab,l,plen);
+
/* If we are at the very end of the screen with our prompt, we need to
* emit a newline and move the prompt to the first column. */
if (l->pos &&
@@ -598,7 +638,7 @@ int linenoiseEditInsert(struct linenoiseState *l, char c) {
l->pos++;
l->len++;
l->buf[l->len] = '\0';
- if ((!mlmode && l->plen+l->len < l->cols) /* || mlmode */) {
+ if ((!mlmode && l->plen+l->len < l->cols && !hintsCallback)) {
/* Avoid a full update of the line in the
* trivial case. */
if (write(l->ofd,&c,1) == -1) return -1;
diff --git a/linenoise.h b/linenoise.h
index fbb01cf..b1d0a80 100644
--- a/linenoise.h
+++ b/linenoise.h
@@ -49,7 +49,11 @@ typedef struct linenoiseCompletions {
} linenoiseCompletions;
typedef void(linenoiseCompletionCallback)(const char *, linenoiseCompletions *);
+typedef char*(linenoiseHintsCallback)(const char *, int *color, int *bold);
+typedef char*(linenoiseFreeHintsCallback)(char *);
void linenoiseSetCompletionCallback(linenoiseCompletionCallback *);
+void linenoiseSetHintsCallback(linenoiseHintsCallback *);
+void linenoiseSetFreeHintsCallback(linenoiseFreeHintsCallback *);
void linenoiseAddCompletion(linenoiseCompletions *, const char *);
char *linenoise(const char *prompt);