]> git.lizzy.rs Git - linenoise.git/blob - linenoise.c
Re-add insert optimisation
[linenoise.git] / linenoise.c
1 /* linenoise.c -- guerrilla line editing library against the idea that a
2  * line editing lib needs to be 20,000 lines of C code.
3  *
4  * You can find the latest source code at:
5  *
6  *   http://github.com/msteveb/linenoise
7  *   (forked from http://github.com/antirez/linenoise)
8  *
9  * Does a number of crazy assumptions that happen to be true in 99.9999% of
10  * the 2010 UNIX computers around.
11  *
12  * ------------------------------------------------------------------------
13  *
14  * Copyright (c) 2010, Salvatore Sanfilippo <antirez at gmail dot com>
15  * Copyright (c) 2010, Pieter Noordhuis <pcnoordhuis at gmail dot com>
16  * Copyright (c) 2011, Steve Bennett <steveb at workware dot net dot au>
17  *
18  * All rights reserved.
19  *
20  * Redistribution and use in source and binary forms, with or without
21  * modification, are permitted provided that the following conditions are
22  * met:
23  *
24  *  *  Redistributions of source code must retain the above copyright
25  *     notice, this list of conditions and the following disclaimer.
26  *
27  *  *  Redistributions in binary form must reproduce the above copyright
28  *     notice, this list of conditions and the following disclaimer in the
29  *     documentation and/or other materials provided with the distribution.
30  *
31  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
34  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
36  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
37  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
38  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
39  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
40  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
41  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42  *
43  * ------------------------------------------------------------------------
44  *
45  * References:
46  * - http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
47  * - http://www.3waylabs.com/nw/WWW/products/wizcon/vt220.html
48  *
49  * Bloat:
50  * - Completion?
51  *
52  * Unix/termios
53  * ------------
54  * List of escape sequences used by this program, we do everything just
55  * a few sequences. In order to be so cheap we may have some
56  * flickering effect with some slow terminal, but the lesser sequences
57  * the more compatible.
58  *
59  * EL (Erase Line)
60  *    Sequence: ESC [ 0 K
61  *    Effect: clear from cursor to end of line
62  *
63  * CUF (CUrsor Forward)
64  *    Sequence: ESC [ n C
65  *    Effect: moves cursor forward n chars
66  *
67  * CR (Carriage Return)
68  *    Sequence: \r
69  *    Effect: moves cursor to column 1
70  *
71  * The following are used to clear the screen: ESC [ H ESC [ 2 J
72  * This is actually composed of two sequences:
73  *
74  * cursorhome
75  *    Sequence: ESC [ H
76  *    Effect: moves the cursor to upper left corner
77  *
78  * ED2 (Clear entire screen)
79  *    Sequence: ESC [ 2 J
80  *    Effect: clear the whole screen
81  *
82  * == For highlighting control characters, we also use the following two ==
83  * SO (enter StandOut)
84  *    Sequence: ESC [ 7 m
85  *    Effect: Uses some standout mode such as reverse video
86  *
87  * SE (Standout End)
88  *    Sequence: ESC [ 0 m
89  *    Effect: Exit standout mode
90  *
91  * == Only used if TIOCGWINSZ fails ==
92  * DSR/CPR (Report cursor position)
93  *    Sequence: ESC [ 6 n
94  *    Effect: reports current cursor position as ESC [ NNN ; MMM R
95  *
96  * == Only used in multiline mode ==
97  * CUU (Cursor Up)
98  *    Sequence: ESC [ n A
99  *    Effect: moves cursor up n chars.
100  *
101  * CUD (Cursor Down)
102  *    Sequence: ESC [ n B
103  *    Effect: moves cursor down n chars.
104  *
105  * win32/console
106  * -------------
107  * If __MINGW32__ is defined, the win32 console API is used.
108  * This could probably be made to work for the msvc compiler too.
109  * This support based in part on work by Jon Griffiths.
110  */
111
112 #ifdef _WIN32 /* Windows platform, either MinGW or Visual Studio (MSVC) */
113 #include <windows.h>
114 #include <fcntl.h>
115 #define USE_WINCONSOLE
116 #ifdef __MINGW32__
117 #define HAVE_UNISTD_H
118 #else
119 /* Microsoft headers don't like old POSIX names */
120 #define strdup _strdup
121 #define snprintf _snprintf
122 #endif
123 #else
124 #include <termios.h>
125 #include <sys/ioctl.h>
126 #include <poll.h>
127 #define USE_TERMIOS
128 #define HAVE_UNISTD_H
129 #endif
130
131 #ifdef HAVE_UNISTD_H
132 #include <unistd.h>
133 #endif
134 #include <stdlib.h>
135 #include <stdarg.h>
136 #include <stdio.h>
137 #include <assert.h>
138 #include <errno.h>
139 #include <string.h>
140 #include <signal.h>
141 #include <stdlib.h>
142 #include <sys/types.h>
143
144 #include "linenoise.h"
145 #ifndef STRINGBUF_H
146 #include "stringbuf.h"
147 #endif
148 #include "utf8.h"
149
150 #define LINENOISE_DEFAULT_HISTORY_MAX_LEN 100
151
152 #define ctrl(C) ((C) - '@')
153
154 /* Use -ve numbers here to co-exist with normal unicode chars */
155 enum {
156     SPECIAL_NONE,
157     /* don't use -1 here since that indicates error */
158     SPECIAL_UP = -20,
159     SPECIAL_DOWN = -21,
160     SPECIAL_LEFT = -22,
161     SPECIAL_RIGHT = -23,
162     SPECIAL_DELETE = -24,
163     SPECIAL_HOME = -25,
164     SPECIAL_END = -26,
165     SPECIAL_INSERT = -27,
166     SPECIAL_PAGE_UP = -28,
167     SPECIAL_PAGE_DOWN = -29,
168
169     /* Some handy names for other special keycodes */
170     CHAR_ESCAPE = 27,
171     CHAR_DELETE = 127,
172 };
173
174 static int history_max_len = LINENOISE_DEFAULT_HISTORY_MAX_LEN;
175 static int history_len = 0;
176 static char **history = NULL;
177
178 /* Structure to contain the status of the current (being edited) line */
179 struct current {
180     stringbuf *buf; /* Current buffer. Always null terminated */
181     int pos;    /* Cursor position, measured in chars */
182     int cols;   /* Size of the window, in chars */
183     int nrows;  /* How many rows are being used in multiline mode (>= 1) */
184     int rpos;   /* The current row containing the cursor - multiline mode only */
185     int availcols;  /* refreshLine() caches available cols after the prompt here */
186     const char *prompt;
187     stringbuf *capture; /* capture buffer, or NULL for none. Always null terminated */
188     stringbuf *output;  /* used only during refreshLine() - output accumulator */
189 #if defined(USE_TERMIOS)
190     int fd;     /* Terminal fd */
191 #elif defined(USE_WINCONSOLE)
192     HANDLE outh; /* Console output handle */
193     HANDLE inh; /* Console input handle */
194     int rows;   /* Screen rows */
195     int x;      /* Current column during output */
196     int y;      /* Current row */
197 #ifdef USE_UTF8
198     #define UBUF_MAX_CHARS 132
199     WORD ubuf[UBUF_MAX_CHARS + 1];  /* Accumulates utf16 output - one extra for final surrogate pairs */
200     int ubuflen;      /* length used in ubuf */
201     int ubufcols;     /* how many columns are represented by the chars in ubuf? */
202 #endif
203 #endif
204 };
205
206 static int fd_read(struct current *current);
207 static int getWindowSize(struct current *current);
208 static void cursorDown(struct current *current, int n);
209 static void cursorUp(struct current *current, int n);
210 static void eraseEol(struct current *current);
211 static void refreshLine(struct current *current);
212 static void refreshLineAlt(struct current *current, const char *prompt, const char *buf, int cursor_pos);
213 static void setCursorPos(struct current *current, int x);
214 static void setOutputHighlight(struct current *current, const int *props, int nprops);
215 static void set_current(struct current *current, const char *str);
216
217 void linenoiseHistoryFree(void) {
218     if (history) {
219         int j;
220
221         for (j = 0; j < history_len; j++)
222             free(history[j]);
223         free(history);
224         history = NULL;
225         history_len = 0;
226     }
227 }
228
229 struct esc_parser {
230     enum {
231         EP_START,   /* looking for ESC */
232         EP_ESC,     /* looking for [ */
233         EP_DIGITS,  /* parsing digits */
234         EP_PROPS,   /* parsing digits or semicolons */
235         EP_END,     /* ok */
236         EP_ERROR,   /* error */
237     } state;
238     int props[5];   /* properties are stored here */
239     int maxprops;   /* size of the props[] array */
240     int numprops;   /* number of properties found */
241     int termchar;   /* terminator char, or 0 for any alpha */
242     int current;    /* current (partial) property value */
243 };
244
245 /**
246  * Initialise the escape sequence parser at *parser.
247  *
248  * If termchar is 0 any alpha char terminates ok. Otherwise only the given
249  * char terminates successfully.
250  * Run the parser state machine with calls to parseEscapeSequence() for each char.
251  */
252 static void initParseEscapeSeq(struct esc_parser *parser, int termchar)
253 {
254     parser->state = EP_START;
255     parser->maxprops = sizeof(parser->props) / sizeof(*parser->props);
256     parser->numprops = 0;
257     parser->current = 0;
258     parser->termchar = termchar;
259 }
260
261 /**
262  * Pass character 'ch' into the state machine to parse:
263  *   'ESC' '[' <digits> (';' <digits>)* <termchar>
264  *
265  * The first character must be ESC.
266  * Returns the current state. The state machine is done when it returns either EP_END
267  * or EP_ERROR.
268  *
269  * On EP_END, the "property/attribute" values can be read from parser->props[]
270  * of length parser->numprops.
271  */
272 static int parseEscapeSequence(struct esc_parser *parser, int ch)
273 {
274     switch (parser->state) {
275         case EP_START:
276             parser->state = (ch == '\x1b') ? EP_ESC : EP_ERROR;
277             break;
278         case EP_ESC:
279             parser->state = (ch == '[') ? EP_DIGITS : EP_ERROR;
280             break;
281         case EP_PROPS:
282             if (ch == ';') {
283                 parser->state = EP_DIGITS;
284 donedigits:
285                 if (parser->numprops + 1 < parser->maxprops) {
286                     parser->props[parser->numprops++] = parser->current;
287                     parser->current = 0;
288                 }
289                 break;
290             }
291             /* fall through */
292         case EP_DIGITS:
293             if (ch >= '0' && ch <= '9') {
294                 parser->current = parser->current * 10 + (ch - '0');
295                 parser->state = EP_PROPS;
296                 break;
297             }
298             /* must be terminator */
299             if (parser->termchar != ch) {
300                 if (parser->termchar != 0 || !((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z'))) {
301                     parser->state = EP_ERROR;
302                     break;
303                 }
304             }
305             parser->state = EP_END;
306             goto donedigits;
307         case EP_END:
308             parser->state = EP_ERROR;
309             break;
310         case EP_ERROR:
311             break;
312     }
313     return parser->state;
314 }
315
316 /*#define DEBUG_REFRESHLINE*/
317
318 #ifdef DEBUG_REFRESHLINE
319 #define DRL(ARGS...) fprintf(dfh, ARGS)
320 static FILE *dfh;
321
322 static void DRL_CHAR(int ch)
323 {
324     if (ch < ' ') {
325         DRL("^%c", ch + '@');
326     }
327     else if (ch > 127) {
328         DRL("\\u%04x", ch);
329     }
330     else {
331         DRL("%c", ch);
332     }
333 }
334 static void DRL_STR(const char *str)
335 {
336     while (*str) {
337         int ch;
338         int n = utf8_tounicode(str, &ch);
339         str += n;
340         DRL_CHAR(ch);
341     }
342 }
343 #else
344 #define DRL(ARGS...)
345 #define DRL_CHAR(ch)
346 #define DRL_STR(str)
347 #endif
348
349 #if defined(USE_WINCONSOLE)
350 #include "linenoise-win32.c"
351 #endif
352
353 #if defined(USE_TERMIOS)
354 static void linenoiseAtExit(void);
355 static struct termios orig_termios; /* in order to restore at exit */
356 static int rawmode = 0; /* for atexit() function to check if restore is needed*/
357 static int atexit_registered = 0; /* register atexit just 1 time */
358
359 static const char *unsupported_term[] = {"dumb","cons25","emacs",NULL};
360
361 static int isUnsupportedTerm(void) {
362     char *term = getenv("TERM");
363
364     if (term) {
365         int j;
366         for (j = 0; unsupported_term[j]; j++) {
367             if (strcmp(term, unsupported_term[j]) == 0) {
368                 return 1;
369             }
370         }
371     }
372     return 0;
373 }
374
375 static int enableRawMode(struct current *current) {
376     struct termios raw;
377
378     current->fd = STDIN_FILENO;
379     current->cols = 0;
380
381     if (!isatty(current->fd) || isUnsupportedTerm() ||
382         tcgetattr(current->fd, &orig_termios) == -1) {
383 fatal:
384         errno = ENOTTY;
385         return -1;
386     }
387
388     if (!atexit_registered) {
389         atexit(linenoiseAtExit);
390         atexit_registered = 1;
391     }
392
393     raw = orig_termios;  /* modify the original mode */
394     /* input modes: no break, no CR to NL, no parity check, no strip char,
395      * no start/stop output control. */
396     raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
397     /* output modes - actually, no need to disable post processing */
398     /*raw.c_oflag &= ~(OPOST);*/
399     /* control modes - set 8 bit chars */
400     raw.c_cflag |= (CS8);
401     /* local modes - choing off, canonical off, no extended functions,
402      * no signal chars (^Z,^C) */
403     raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
404     /* control chars - set return condition: min number of bytes and timer.
405      * We want read to return every single byte, without timeout. */
406     raw.c_cc[VMIN] = 1; raw.c_cc[VTIME] = 0; /* 1 byte, no timer */
407
408     /* put terminal in raw mode after flushing */
409     if (tcsetattr(current->fd,TCSADRAIN,&raw) < 0) {
410         goto fatal;
411     }
412     rawmode = 1;
413     return 0;
414 }
415
416 static void disableRawMode(struct current *current) {
417     /* Don't even check the return value as it's too late. */
418     if (rawmode && tcsetattr(current->fd,TCSADRAIN,&orig_termios) != -1)
419         rawmode = 0;
420 }
421
422 /* At exit we'll try to fix the terminal to the initial conditions. */
423 static void linenoiseAtExit(void) {
424     if (rawmode) {
425         tcsetattr(STDIN_FILENO, TCSADRAIN, &orig_termios);
426     }
427     linenoiseHistoryFree();
428 }
429
430 /* gcc/glibc insists that we care about the return code of write!
431  * Clarification: This means that a void-cast like "(void) (EXPR)"
432  * does not work.
433  */
434 #define IGNORE_RC(EXPR) if (EXPR) {}
435
436 /**
437  * Output bytes directly, or accumulate output (if current->output is set)
438  */
439 static void outputChars(struct current *current, const char *buf, int len)
440 {
441     if (len < 0) {
442         len = strlen(buf);
443     }
444     if (current->output) {
445         sb_append_len(current->output, buf, len);
446     }
447     else {
448         IGNORE_RC(write(current->fd, buf, len));
449     }
450 }
451
452 /* Like outputChars, but using printf-style formatting
453  */
454 static void outputFormatted(struct current *current, const char *format, ...)
455 {
456     va_list args;
457     char buf[64];
458     int n;
459
460     va_start(args, format);
461     n = vsnprintf(buf, sizeof(buf), format, args);
462     /* This will never happen because we are sure to use outputFormatted() only for short sequences */
463     assert(n < (int)sizeof(buf));
464     va_end(args);
465     outputChars(current, buf, n);
466 }
467
468 static void cursorToLeft(struct current *current)
469 {
470     outputChars(current, "\r", -1);
471 }
472
473 static void setOutputHighlight(struct current *current, const int *props, int nprops)
474 {
475     outputChars(current, "\x1b[", -1);
476     while (nprops--) {
477         outputFormatted(current, "%d%c", *props, (nprops == 0) ? 'm' : ';');
478         props++;
479     }
480 }
481
482 static void eraseEol(struct current *current)
483 {
484     outputChars(current, "\x1b[0K", -1);
485 }
486
487 static void setCursorPos(struct current *current, int x)
488 {
489     if (x == 0) {
490         cursorToLeft(current);
491     }
492     else {
493         outputFormatted(current, "\r\x1b[%dC", x);
494     }
495 }
496
497 static void cursorUp(struct current *current, int n)
498 {
499     if (n) {
500         outputFormatted(current, "\x1b[%dA", n);
501     }
502 }
503
504 static void cursorDown(struct current *current, int n)
505 {
506     if (n) {
507         outputFormatted(current, "\x1b[%dB", n);
508     }
509 }
510
511 void linenoiseClearScreen(void)
512 {
513     IGNORE_RC(write(STDOUT_FILENO, "\x1b[H\x1b[2J", 7));
514 }
515
516 /**
517  * Reads a char from 'fd', waiting at most 'timeout' milliseconds.
518  *
519  * A timeout of -1 means to wait forever.
520  *
521  * Returns -1 if no char is received within the time or an error occurs.
522  */
523 static int fd_read_char(int fd, int timeout)
524 {
525     struct pollfd p;
526     unsigned char c;
527
528     p.fd = fd;
529     p.events = POLLIN;
530
531     if (poll(&p, 1, timeout) == 0) {
532         /* timeout */
533         return -1;
534     }
535     if (read(fd, &c, 1) != 1) {
536         return -1;
537     }
538     return c;
539 }
540
541 /**
542  * Reads a complete utf-8 character
543  * and returns the unicode value, or -1 on error.
544  */
545 static int fd_read(struct current *current)
546 {
547 #ifdef USE_UTF8
548     char buf[MAX_UTF8_LEN];
549     int n;
550     int i;
551     int c;
552
553     if (read(current->fd, &buf[0], 1) != 1) {
554         return -1;
555     }
556     n = utf8_charlen(buf[0]);
557     if (n < 1) {
558         return -1;
559     }
560     for (i = 1; i < n; i++) {
561         if (read(current->fd, &buf[i], 1) != 1) {
562             return -1;
563         }
564     }
565     /* decode and return the character */
566     utf8_tounicode(buf, &c);
567     return c;
568 #else
569     return fd_read_char(current->fd, -1);
570 #endif
571 }
572
573
574 /**
575  * Stores the current cursor column in '*cols'.
576  * Returns 1 if OK, or 0 if failed to determine cursor pos.
577  */
578 static int queryCursor(struct current *current, int* cols)
579 {
580     struct esc_parser parser;
581     int ch;
582
583     /* Should not be buffering this output, it needs to go immediately */
584     assert(current->output == NULL);
585
586     /* control sequence - report cursor location */
587     outputChars(current, "\x1b[6n", -1);
588
589     /* Parse the response: ESC [ rows ; cols R */
590     initParseEscapeSeq(&parser, 'R');
591     while ((ch = fd_read_char(current->fd, 100)) > 0) {
592         switch (parseEscapeSequence(&parser, ch)) {
593             default:
594                 continue;
595             case EP_END:
596                 if (parser.numprops == 2 && parser.props[1] < 1000) {
597                     *cols = parser.props[1];
598                     return 1;
599                 }
600                 break;
601             case EP_ERROR:
602                 break;
603         }
604         /* failed */
605         break;
606     }
607     return 0;
608 }
609
610 /**
611  * Updates current->cols with the current window size (width)
612  */
613 static int getWindowSize(struct current *current)
614 {
615     struct winsize ws;
616
617     if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == 0 && ws.ws_col != 0) {
618         current->cols = ws.ws_col;
619         return 0;
620     }
621
622     /* Failed to query the window size. Perhaps we are on a serial terminal.
623      * Try to query the width by sending the cursor as far to the right
624      * and reading back the cursor position.
625      * Note that this is only done once per call to linenoise rather than
626      * every time the line is refreshed for efficiency reasons.
627      *
628      * In more detail, we:
629      * (a) request current cursor position,
630      * (b) move cursor far right,
631      * (c) request cursor position again,
632      * (d) at last move back to the old position.
633      * This gives us the width without messing with the externally
634      * visible cursor position.
635      */
636
637     if (current->cols == 0) {
638         int here;
639
640         /* If anything fails => default 80 */
641         current->cols = 80;
642
643         /* (a) */
644         if (queryCursor (current, &here)) {
645             /* (b) */
646             setCursorPos(current, 999);
647
648             /* (c). Note: If (a) succeeded, then (c) should as well.
649              * For paranoia we still check and have a fallback action
650              * for (d) in case of failure..
651              */
652             if (queryCursor (current, &current->cols)) {
653                 /* (d) Reset the cursor back to the original location. */
654                 if (current->cols > here) {
655                     setCursorPos(current, here);
656                 }
657             }
658         }
659     }
660
661     return 0;
662 }
663
664 /**
665  * If CHAR_ESCAPE was received, reads subsequent
666  * chars to determine if this is a known special key.
667  *
668  * Returns SPECIAL_NONE if unrecognised, or -1 if EOF.
669  *
670  * If no additional char is received within a short time,
671  * CHAR_ESCAPE is returned.
672  */
673 static int check_special(int fd)
674 {
675     int c = fd_read_char(fd, 50);
676     int c2;
677
678     if (c < 0) {
679         return CHAR_ESCAPE;
680     }
681
682     c2 = fd_read_char(fd, 50);
683     if (c2 < 0) {
684         return c2;
685     }
686     if (c == '[' || c == 'O') {
687         /* Potential arrow key */
688         switch (c2) {
689             case 'A':
690                 return SPECIAL_UP;
691             case 'B':
692                 return SPECIAL_DOWN;
693             case 'C':
694                 return SPECIAL_RIGHT;
695             case 'D':
696                 return SPECIAL_LEFT;
697             case 'F':
698                 return SPECIAL_END;
699             case 'H':
700                 return SPECIAL_HOME;
701         }
702     }
703     if (c == '[' && c2 >= '1' && c2 <= '8') {
704         /* extended escape */
705         c = fd_read_char(fd, 50);
706         if (c == '~') {
707             switch (c2) {
708                 case '2':
709                     return SPECIAL_INSERT;
710                 case '3':
711                     return SPECIAL_DELETE;
712                 case '5':
713                     return SPECIAL_PAGE_UP;
714                 case '6':
715                     return SPECIAL_PAGE_DOWN;
716                 case '7':
717                     return SPECIAL_HOME;
718                 case '8':
719                     return SPECIAL_END;
720             }
721         }
722         while (c != -1 && c != '~') {
723             /* .e.g \e[12~ or '\e[11;2~   discard the complete sequence */
724             c = fd_read_char(fd, 50);
725         }
726     }
727
728     return SPECIAL_NONE;
729 }
730 #endif
731
732 static void clearOutputHighlight(struct current *current)
733 {
734     int nohighlight = 0;
735     setOutputHighlight(current, &nohighlight, 1);
736 }
737
738 static void outputControlChar(struct current *current, char ch)
739 {
740     int reverse = 7;
741     setOutputHighlight(current, &reverse, 1);
742     outputChars(current, "^", 1);
743     outputChars(current, &ch, 1);
744     clearOutputHighlight(current);
745 }
746
747 #ifndef utf8_getchars
748 static int utf8_getchars(char *buf, int c)
749 {
750 #ifdef USE_UTF8
751     return utf8_fromunicode(buf, c);
752 #else
753     *buf = c;
754     return 1;
755 #endif
756 }
757 #endif
758
759 /**
760  * Returns the unicode character at the given offset,
761  * or -1 if none.
762  */
763 static int get_char(struct current *current, int pos)
764 {
765     if (pos >= 0 && pos < sb_chars(current->buf)) {
766         int c;
767         int i = utf8_index(sb_str(current->buf), pos);
768         (void)utf8_tounicode(sb_str(current->buf) + i, &c);
769         return c;
770     }
771     return -1;
772 }
773
774 static int char_display_width(int ch)
775 {
776     if (ch < ' ') {
777         /* control chars take two positions */
778         return 2;
779     }
780     else {
781         return utf8_width(ch);
782     }
783 }
784
785 #ifndef NO_COMPLETION
786 static linenoiseCompletionCallback *completionCallback = NULL;
787 static void *completionUserdata = NULL;
788 static int showhints = 1;
789 static linenoiseHintsCallback *hintsCallback = NULL;
790 static linenoiseFreeHintsCallback *freeHintsCallback = NULL;
791 static void *hintsUserdata = NULL;
792
793 static void beep() {
794 #ifdef USE_TERMIOS
795     fprintf(stderr, "\x7");
796     fflush(stderr);
797 #endif
798 }
799
800 static void freeCompletions(linenoiseCompletions *lc) {
801     size_t i;
802     for (i = 0; i < lc->len; i++)
803         free(lc->cvec[i]);
804     free(lc->cvec);
805 }
806
807 static int completeLine(struct current *current) {
808     linenoiseCompletions lc = { 0, NULL };
809     int c = 0;
810
811     completionCallback(sb_str(current->buf),&lc,completionUserdata);
812     if (lc.len == 0) {
813         beep();
814     } else {
815         size_t stop = 0, i = 0;
816
817         while(!stop) {
818             /* Show completion or original buffer */
819             if (i < lc.len) {
820                 int chars = utf8_strlen(lc.cvec[i], -1);
821                 refreshLineAlt(current, current->prompt, lc.cvec[i], chars);
822             } else {
823                 refreshLine(current);
824             }
825
826             c = fd_read(current);
827             if (c == -1) {
828                 break;
829             }
830
831             switch(c) {
832                 case '\t': /* tab */
833                     i = (i+1) % (lc.len+1);
834                     if (i == lc.len) beep();
835                     break;
836                 case CHAR_ESCAPE: /* escape */
837                     /* Re-show original buffer */
838                     if (i < lc.len) {
839                         refreshLine(current);
840                     }
841                     stop = 1;
842                     break;
843                 default:
844                     /* Update buffer and return */
845                     if (i < lc.len) {
846                         set_current(current,lc.cvec[i]);
847                     }
848                     stop = 1;
849                     break;
850             }
851         }
852     }
853
854     freeCompletions(&lc);
855     return c; /* Return last read character */
856 }
857
858 /* Register a callback function to be called for tab-completion.
859    Returns the prior callback so that the caller may (if needed)
860    restore it when done. */
861 linenoiseCompletionCallback * linenoiseSetCompletionCallback(linenoiseCompletionCallback *fn, void *userdata) {
862     linenoiseCompletionCallback * old = completionCallback;
863     completionCallback = fn;
864     completionUserdata = userdata;
865     return old;
866 }
867
868 void linenoiseAddCompletion(linenoiseCompletions *lc, const char *str) {
869     lc->cvec = (char **)realloc(lc->cvec,sizeof(char*)*(lc->len+1));
870     lc->cvec[lc->len++] = strdup(str);
871 }
872
873 void linenoiseSetHintsCallback(linenoiseHintsCallback *callback, void *userdata)
874 {
875     hintsCallback = callback;
876     hintsUserdata = userdata;
877 }
878
879 void linenoiseSetFreeHintsCallback(linenoiseFreeHintsCallback *callback)
880 {
881     freeHintsCallback = callback;
882 }
883
884 #endif
885
886
887 static const char *reduceSingleBuf(const char *buf, int availcols, int *cursor_pos)
888 {
889     /* We have availcols columns available.
890      * If necessary, strip chars off the front of buf until *cursor_pos
891      * fits within availcols
892      */
893     int needcols = 0;
894     int pos = 0;
895     int new_cursor_pos = *cursor_pos;
896     const char *pt = buf;
897
898     DRL("reduceSingleBuf: availcols=%d, cursor_pos=%d\n", availcols, *cursor_pos);
899
900     while (*pt) {
901         int ch;
902         int n = utf8_tounicode(pt, &ch);
903         pt += n;
904
905         needcols += char_display_width(ch);
906
907         /* If we need too many cols, strip
908          * chars off the front of buf to make it fit.
909          * We keep 3 extra cols to the right of the cursor.
910          * 2 for possible wide chars, 1 for the last column that
911          * can't be used.
912          */
913         while (needcols >= availcols - 3) {
914             n = utf8_tounicode(buf, &ch);
915             buf += n;
916             needcols -= char_display_width(ch);
917             DRL_CHAR(ch);
918
919             /* and adjust the apparent cursor position */
920             new_cursor_pos--;
921
922             if (buf == pt) {
923                 /* can't remove more than this */
924                 break;
925             }
926         }
927
928         if (pos++ == *cursor_pos) {
929             break;
930         }
931
932     }
933     DRL("<snip>");
934     DRL_STR(buf);
935     DRL("\nafter reduce, needcols=%d, new_cursor_pos=%d\n", needcols, new_cursor_pos);
936
937     /* Done, now new_cursor_pos contains the adjusted cursor position
938      * and buf points to he adjusted start
939      */
940     *cursor_pos = new_cursor_pos;
941     return buf;
942 }
943
944 static int mlmode = 0;
945
946 void linenoiseSetMultiLine(int enableml)
947 {
948     mlmode = enableml;
949 }
950
951 /* Helper of refreshSingleLine() and refreshMultiLine() to show hints
952  * to the right of the prompt.
953  * Returns 1 if a hint was shown, or 0 if not
954  * If 'display' is 0, does no output. Just returns the appropriate return code.
955  */
956 static int refreshShowHints(struct current *current, const char *buf, int availcols, int display)
957 {
958     int rc = 0;
959     if (showhints && hintsCallback && availcols > 0) {
960         int bold = 0;
961         int color = -1;
962         char *hint = hintsCallback(buf, &color, &bold, hintsUserdata);
963         if (hint) {
964             rc = 1;
965             if (display) {
966                 const char *pt;
967                 if (bold == 1 && color == -1) color = 37;
968                 if (bold || color > 0) {
969                     int props[3] = { bold, color, 49 }; /* bold, color, fgnormal */
970                     setOutputHighlight(current, props, 3);
971                 }
972                 DRL("<hint bold=%d,color=%d>", bold, color);
973                 pt = hint;
974                 while (*pt) {
975                     int ch;
976                     int n = utf8_tounicode(pt, &ch);
977                     int width = char_display_width(ch);
978
979                     if (width >= availcols) {
980                         DRL("<hinteol>");
981                         break;
982                     }
983                     DRL_CHAR(ch);
984
985                     availcols -= width;
986                     outputChars(current, pt, n);
987                     pt += n;
988                 }
989                 if (bold || color > 0) {
990                     clearOutputHighlight(current);
991                 }
992                 /* Call the function to free the hint returned. */
993                 if (freeHintsCallback) freeHintsCallback(hint, hintsUserdata);
994             }
995         }
996     }
997     return rc;
998 }
999
1000 #ifdef USE_TERMIOS
1001 static void refreshStart(struct current *current)
1002 {
1003     /* We accumulate all output here */
1004     assert(current->output == NULL);
1005     current->output = sb_alloc();
1006 }
1007
1008 static void refreshEnd(struct current *current)
1009 {
1010     /* Output everything at once */
1011     IGNORE_RC(write(current->fd, sb_str(current->output), sb_len(current->output)));
1012     sb_free(current->output);
1013     current->output = NULL;
1014 }
1015
1016 static void refreshStartChars(struct current *current)
1017 {
1018 }
1019
1020 static void refreshNewline(struct current *current)
1021 {
1022     DRL("<nl>");
1023     outputChars(current, "\n", 1);
1024 }
1025
1026 static void refreshEndChars(struct current *current)
1027 {
1028 }
1029 #endif
1030
1031 static void refreshLineAlt(struct current *current, const char *prompt, const char *buf, int cursor_pos)
1032 {
1033     int i;
1034     const char *pt;
1035     int displaycol;
1036     int displayrow;
1037     int visible;
1038     int currentpos;
1039     int notecursor;
1040     int cursorcol = 0;
1041     int cursorrow = 0;
1042     int hint;
1043     struct esc_parser parser;
1044
1045 #ifdef DEBUG_REFRESHLINE
1046     dfh = fopen("linenoise.debuglog", "a");
1047 #endif
1048
1049     /* Should intercept SIGWINCH. For now, just get the size every time */
1050     getWindowSize(current);
1051
1052     refreshStart(current);
1053
1054     DRL("wincols=%d, cursor_pos=%d, nrows=%d, rpos=%d\n", current->cols, cursor_pos, current->nrows, current->rpos);
1055
1056     /* Here is the plan:
1057      * (a) move the the bottom row, going down the appropriate number of lines
1058      * (b) move to beginning of line and erase the current line
1059      * (c) go up one line and do the same, until we have erased up to the first row
1060      * (d) output the prompt, counting cols and rows, taking into account escape sequences
1061      * (e) output the buffer, counting cols and rows
1062      *   (e') when we hit the current pos, save the cursor position
1063      * (f) move the cursor to the saved cursor position
1064      * (g) save the current cursor row and number of rows
1065      */
1066
1067     /* (a) - The cursor is currently at row rpos */
1068     cursorDown(current, current->nrows - current->rpos - 1);
1069     DRL("<cud=%d>", current->nrows - current->rpos - 1);
1070
1071     /* (b), (c) - Erase lines upwards until we get to the first row */
1072     for (i = 0; i < current->nrows; i++) {
1073         if (i) {
1074             DRL("<cup>");
1075             cursorUp(current, 1);
1076         }
1077         DRL("<clearline>");
1078         cursorToLeft(current);
1079         eraseEol(current);
1080     }
1081     DRL("\n");
1082
1083     /* (d) First output the prompt. control sequences don't take up display space */
1084     pt = prompt;
1085     displaycol = 0; /* current display column */
1086     displayrow = 0; /* current display row */
1087     visible = 1;
1088
1089     refreshStartChars(current);
1090
1091     while (*pt) {
1092         int width;
1093         int ch;
1094         int n = utf8_tounicode(pt, &ch);
1095
1096         if (visible && ch == CHAR_ESCAPE) {
1097             /* The start of an escape sequence, so not visible */
1098             visible = 0;
1099             initParseEscapeSeq(&parser, 'm');
1100             DRL("<esc-seq-start>");
1101         }
1102
1103         if (ch == '\n' || ch == '\r') {
1104             /* treat both CR and NL the same and force wrap */
1105             refreshNewline(current);
1106             displaycol = 0;
1107             displayrow++;
1108         }
1109         else {
1110             width = visible * utf8_width(ch);
1111
1112             displaycol += width;
1113             if (displaycol >= current->cols) {
1114                 /* need to wrap to the next line because of newline or if it doesn't fit
1115                  * XXX this is a problem in single line mode
1116                  */
1117                 refreshNewline(current);
1118                 displaycol = width;
1119                 displayrow++;
1120             }
1121
1122             DRL_CHAR(ch);
1123 #ifdef USE_WINCONSOLE
1124             if (visible) {
1125                 outputChars(current, pt, n);
1126             }
1127 #else
1128             outputChars(current, pt, n);
1129 #endif
1130         }
1131         pt += n;
1132
1133         if (!visible) {
1134             switch (parseEscapeSequence(&parser, ch)) {
1135                 case EP_END:
1136                     visible = 1;
1137                     setOutputHighlight(current, parser.props, parser.numprops);
1138                     DRL("<esc-seq-end,numprops=%d>", parser.numprops);
1139                     break;
1140                 case EP_ERROR:
1141                     DRL("<esc-seq-err>");
1142                     visible = 1;
1143                     break;
1144             }
1145         }
1146     }
1147
1148     /* Now we are at the first line with all lines erased */
1149     DRL("\nafter prompt: displaycol=%d, displayrow=%d\n", displaycol, displayrow);
1150
1151
1152     /* (e) output the buffer, counting cols and rows */
1153     if (mlmode == 0) {
1154         /* In this mode we may need to trim chars from the start of the buffer until the
1155          * cursor fits in the window.
1156          */
1157         pt = reduceSingleBuf(buf, current->cols - displaycol, &cursor_pos);
1158     }
1159     else {
1160         pt = buf;
1161     }
1162
1163     currentpos = 0;
1164     notecursor = -1;
1165
1166     while (*pt) {
1167         int ch;
1168         int n = utf8_tounicode(pt, &ch);
1169         int width = char_display_width(ch);
1170
1171         if (currentpos == cursor_pos) {
1172             /* (e') wherever we output this character is where we want the cursor */
1173             notecursor = 1;
1174         }
1175
1176         if (displaycol + width >= current->cols) {
1177             if (mlmode == 0) {
1178                 /* In single line mode stop once we print as much as we can on one line */
1179                 DRL("<slmode>");
1180                 break;
1181             }
1182             /* need to wrap to the next line since it doesn't fit */
1183             refreshNewline(current);
1184             displaycol = 0;
1185             displayrow++;
1186         }
1187
1188         if (notecursor == 1) {
1189             /* (e') Save this position as the current cursor position */
1190             cursorcol = displaycol;
1191             cursorrow = displayrow;
1192             notecursor = 0;
1193             DRL("<cursor>");
1194         }
1195
1196         displaycol += width;
1197
1198         if (ch < ' ') {
1199             outputControlChar(current, ch + '@');
1200         }
1201         else {
1202             outputChars(current, pt, n);
1203         }
1204         DRL_CHAR(ch);
1205         if (width != 1) {
1206             DRL("<w=%d>", width);
1207         }
1208
1209         pt += n;
1210         currentpos++;
1211     }
1212
1213     /* If we didn't see the cursor, it is at the current location */
1214     if (notecursor) {
1215         DRL("<cursor>");
1216         cursorcol = displaycol;
1217         cursorrow = displayrow;
1218     }
1219
1220     DRL("\nafter buf: displaycol=%d, displayrow=%d, cursorcol=%d, cursorrow=%d\n\n", displaycol, displayrow, cursorcol, cursorrow);
1221
1222     /* (f) show hints */
1223     hint = refreshShowHints(current, buf, current->cols - displaycol, 1);
1224
1225     /* Remember how many many cols are available for insert optimisation */
1226     if (prompt == current->prompt && hint == 0) {
1227         current->availcols = current->cols - displaycol;
1228     }
1229     else {
1230         /* Can't optimise */
1231         current->availcols = 0;
1232     }
1233
1234     refreshEndChars(current);
1235
1236     /* (g) move the cursor to the correct place */
1237     cursorUp(current, displayrow - cursorrow);
1238     setCursorPos(current, cursorcol);
1239
1240     /* (h) Update the number of rows if larger, but never reduce this */
1241     if (displayrow >= current->nrows) {
1242         current->nrows = displayrow + 1;
1243     }
1244     /* And remember the row that the cursor is on */
1245     current->rpos = cursorrow;
1246
1247     refreshEnd(current);
1248
1249 #ifdef DEBUG_REFRESHLINE
1250     fclose(dfh);
1251 #endif
1252 }
1253
1254 static void refreshLine(struct current *current)
1255 {
1256     refreshLineAlt(current, current->prompt, sb_str(current->buf), current->pos);
1257 }
1258
1259 static void set_current(struct current *current, const char *str)
1260 {
1261     sb_clear(current->buf);
1262     sb_append(current->buf, str);
1263     current->pos = sb_chars(current->buf);
1264 }
1265
1266 /**
1267  * Removes the char at 'pos'.
1268  *
1269  * Returns 1 if the line needs to be refreshed, 2 if not
1270  * and 0 if nothing was removed
1271  */
1272 static int remove_char(struct current *current, int pos)
1273 {
1274     if (pos >= 0 && pos < sb_chars(current->buf)) {
1275         int offset = utf8_index(sb_str(current->buf), pos);
1276         int nbytes = utf8_index(sb_str(current->buf) + offset, 1);
1277
1278         /* Note that we no longer try to optimise the remove-at-end case
1279          * since control characters and wide characters mess
1280          * up the simple count
1281          */
1282         sb_delete(current->buf, offset, nbytes);
1283
1284         if (current->pos > pos) {
1285             current->pos--;
1286         }
1287         return 1;
1288     }
1289     return 0;
1290 }
1291
1292 /**
1293  * Insert 'ch' at position 'pos'
1294  *
1295  * Returns 1 if the line needs to be refreshed, 2 if not
1296  * and 0 if nothing was inserted (no room)
1297  */
1298 static int insert_char(struct current *current, int pos, int ch)
1299 {
1300     if (pos >= 0 && pos <= sb_chars(current->buf)) {
1301         char buf[MAX_UTF8_LEN + 1];
1302         int offset = utf8_index(sb_str(current->buf), pos);
1303         int n = utf8_getchars(buf, ch);
1304         int rc = 1;
1305
1306         /* null terminate since sb_insert() requires it */
1307         buf[n] = 0;
1308
1309         /* Now we try to optimise in the simple but very common case that:
1310          * - we are inserting at EOL
1311          * - there are enough columns available
1312          * - no hints are being shown
1313          */
1314         if (pos == current->pos && pos == sb_chars(current->buf)) {
1315             int width = char_display_width(ch);
1316             if (current->availcols > width) {
1317                 /* Yes, can optimise */
1318                 current->availcols -= width;
1319                 rc = 2;
1320             }
1321         }
1322         sb_insert(current->buf, offset, buf);
1323         if (current->pos >= pos) {
1324             current->pos++;
1325         }
1326         if (rc == 2) {
1327             if (refreshShowHints(current, sb_str(current->buf), current->availcols, 0)) {
1328                 /* A hint needs to be shown, so can't optimise after all */
1329                 rc = 1;
1330             }
1331             else {
1332                 /* optimised output */
1333                 outputChars(current, buf, n);
1334             }
1335         }
1336         return rc;
1337     }
1338     return 0;
1339 }
1340
1341 /**
1342  * Captures up to 'n' characters starting at 'pos' for the cut buffer.
1343  *
1344  * This replaces any existing characters in the cut buffer.
1345  */
1346 static void capture_chars(struct current *current, int pos, int nchars)
1347 {
1348     if (pos >= 0 && (pos + nchars - 1) < sb_chars(current->buf)) {
1349         int offset = utf8_index(sb_str(current->buf), pos);
1350         int nbytes = utf8_index(sb_str(current->buf) + offset, nchars);
1351
1352         if (nbytes) {
1353             if (current->capture) {
1354                 sb_clear(current->capture);
1355             }
1356             else {
1357                 current->capture = sb_alloc();
1358             }
1359             sb_append_len(current->capture, sb_str(current->buf) + offset, nbytes);
1360         }
1361     }
1362 }
1363
1364 /**
1365  * Removes up to 'n' characters at cursor position 'pos'.
1366  *
1367  * Returns 0 if no chars were removed or non-zero otherwise.
1368  */
1369 static int remove_chars(struct current *current, int pos, int n)
1370 {
1371     int removed = 0;
1372
1373     /* First save any chars which will be removed */
1374     capture_chars(current, pos, n);
1375
1376     while (n-- && remove_char(current, pos)) {
1377         removed++;
1378     }
1379     return removed;
1380 }
1381 /**
1382  * Inserts the characters (string) 'chars' at the cursor position 'pos'.
1383  *
1384  * Returns 0 if no chars were inserted or non-zero otherwise.
1385  */
1386 static int insert_chars(struct current *current, int pos, const char *chars)
1387 {
1388     int inserted = 0;
1389
1390     while (*chars) {
1391         int ch;
1392         int n = utf8_tounicode(chars, &ch);
1393         if (insert_char(current, pos, ch) == 0) {
1394             break;
1395         }
1396         inserted++;
1397         pos++;
1398         chars += n;
1399     }
1400     return inserted;
1401 }
1402
1403 /**
1404  * Returns the keycode to process, or 0 if none.
1405  */
1406 static int reverseIncrementalSearch(struct current *current)
1407 {
1408     /* Display the reverse-i-search prompt and process chars */
1409     char rbuf[50];
1410     char rprompt[80];
1411     int rchars = 0;
1412     int rlen = 0;
1413     int searchpos = history_len - 1;
1414     int c;
1415
1416     rbuf[0] = 0;
1417     while (1) {
1418         int n = 0;
1419         const char *p = NULL;
1420         int skipsame = 0;
1421         int searchdir = -1;
1422
1423         snprintf(rprompt, sizeof(rprompt), "(reverse-i-search)'%s': ", rbuf);
1424         refreshLineAlt(current, rprompt, sb_str(current->buf), current->pos);
1425         c = fd_read(current);
1426         if (c == ctrl('H') || c == CHAR_DELETE) {
1427             if (rchars) {
1428                 int p = utf8_index(rbuf, --rchars);
1429                 rbuf[p] = 0;
1430                 rlen = strlen(rbuf);
1431             }
1432             continue;
1433         }
1434 #ifdef USE_TERMIOS
1435         if (c == CHAR_ESCAPE) {
1436             c = check_special(current->fd);
1437         }
1438 #endif
1439         if (c == ctrl('P') || c == SPECIAL_UP) {
1440             /* Search for the previous (earlier) match */
1441             if (searchpos > 0) {
1442                 searchpos--;
1443             }
1444             skipsame = 1;
1445         }
1446         else if (c == ctrl('N') || c == SPECIAL_DOWN) {
1447             /* Search for the next (later) match */
1448             if (searchpos < history_len) {
1449                 searchpos++;
1450             }
1451             searchdir = 1;
1452             skipsame = 1;
1453         }
1454         else if (c >= ' ') {
1455             /* >= here to allow for null terminator */
1456             if (rlen >= (int)sizeof(rbuf) - MAX_UTF8_LEN) {
1457                 continue;
1458             }
1459
1460             n = utf8_getchars(rbuf + rlen, c);
1461             rlen += n;
1462             rchars++;
1463             rbuf[rlen] = 0;
1464
1465             /* Adding a new char resets the search location */
1466             searchpos = history_len - 1;
1467         }
1468         else {
1469             /* Exit from incremental search mode */
1470             break;
1471         }
1472
1473         /* Now search through the history for a match */
1474         for (; searchpos >= 0 && searchpos < history_len; searchpos += searchdir) {
1475             p = strstr(history[searchpos], rbuf);
1476             if (p) {
1477                 /* Found a match */
1478                 if (skipsame && strcmp(history[searchpos], sb_str(current->buf)) == 0) {
1479                     /* But it is identical, so skip it */
1480                     continue;
1481                 }
1482                 /* Copy the matching line and set the cursor position */
1483                 set_current(current,history[searchpos]);
1484                 current->pos = utf8_strlen(history[searchpos], p - history[searchpos]);
1485                 break;
1486             }
1487         }
1488         if (!p && n) {
1489             /* No match, so don't add it */
1490             rchars--;
1491             rlen -= n;
1492             rbuf[rlen] = 0;
1493         }
1494     }
1495     if (c == ctrl('G') || c == ctrl('C')) {
1496         /* ctrl-g terminates the search with no effect */
1497         set_current(current, "");
1498         c = 0;
1499     }
1500     else if (c == ctrl('J')) {
1501         /* ctrl-j terminates the search leaving the buffer in place */
1502         c = 0;
1503     }
1504
1505     /* Go process the char normally */
1506     refreshLine(current);
1507     return c;
1508 }
1509
1510 static int linenoiseEdit(struct current *current) {
1511     int history_index = 0;
1512
1513     /* The latest history entry is always our current buffer, that
1514      * initially is just an empty string. */
1515     linenoiseHistoryAdd("");
1516
1517     set_current(current, "");
1518     refreshLine(current);
1519
1520     while(1) {
1521         int dir = -1;
1522         int c = fd_read(current);
1523
1524 #ifndef NO_COMPLETION
1525         /* Only autocomplete when the callback is set. It returns < 0 when
1526          * there was an error reading from fd. Otherwise it will return the
1527          * character that should be handled next. */
1528         if (c == '\t' && current->pos == sb_chars(current->buf) && completionCallback != NULL) {
1529             c = completeLine(current);
1530         }
1531 #endif
1532         if (c == ctrl('R')) {
1533             /* reverse incremental search will provide an alternative keycode or 0 for none */
1534             c = reverseIncrementalSearch(current);
1535             /* go on to process the returned char normally */
1536         }
1537
1538 #ifdef USE_TERMIOS
1539         if (c == CHAR_ESCAPE) {   /* escape sequence */
1540             c = check_special(current->fd);
1541         }
1542 #endif
1543         if (c == -1) {
1544             /* Return on errors */
1545             return sb_len(current->buf);
1546         }
1547
1548         switch(c) {
1549         case SPECIAL_NONE:
1550             break;
1551         case '\r':    /* enter */
1552             history_len--;
1553             free(history[history_len]);
1554             current->pos = sb_chars(current->buf);
1555             if (mlmode || hintsCallback) {
1556                 showhints = 0;
1557                 refreshLine(current);
1558                 showhints = 1;
1559             }
1560             return sb_len(current->buf);
1561         case ctrl('C'):     /* ctrl-c */
1562             errno = EAGAIN;
1563             return -1;
1564         case ctrl('Z'):     /* ctrl-z */
1565 #ifdef SIGTSTP
1566             /* send ourselves SIGSUSP */
1567             disableRawMode(current);
1568             raise(SIGTSTP);
1569             /* and resume */
1570             enableRawMode(current);
1571             refreshLine(current);
1572 #endif
1573             continue;
1574         case CHAR_DELETE:   /* backspace */
1575         case ctrl('H'):
1576             if (remove_char(current, current->pos - 1) == 1) {
1577                 refreshLine(current);
1578             }
1579             break;
1580         case ctrl('D'):     /* ctrl-d */
1581             if (sb_len(current->buf) == 0) {
1582                 /* Empty line, so EOF */
1583                 history_len--;
1584                 free(history[history_len]);
1585                 return -1;
1586             }
1587             /* Otherwise fall through to delete char to right of cursor */
1588         case SPECIAL_DELETE:
1589             if (remove_char(current, current->pos) == 1) {
1590                 refreshLine(current);
1591             }
1592             break;
1593         case SPECIAL_INSERT:
1594             /* Ignore. Expansion Hook.
1595              * Future possibility: Toggle Insert/Overwrite Modes
1596              */
1597             break;
1598         case ctrl('W'):    /* ctrl-w, delete word at left. save deleted chars */
1599             /* eat any spaces on the left */
1600             {
1601                 int pos = current->pos;
1602                 while (pos > 0 && get_char(current, pos - 1) == ' ') {
1603                     pos--;
1604                 }
1605
1606                 /* now eat any non-spaces on the left */
1607                 while (pos > 0 && get_char(current, pos - 1) != ' ') {
1608                     pos--;
1609                 }
1610
1611                 if (remove_chars(current, pos, current->pos - pos)) {
1612                     refreshLine(current);
1613                 }
1614             }
1615             break;
1616         case ctrl('T'):    /* ctrl-t */
1617             if (current->pos > 0 && current->pos <= sb_chars(current->buf)) {
1618                 /* If cursor is at end, transpose the previous two chars */
1619                 int fixer = (current->pos == sb_chars(current->buf));
1620                 c = get_char(current, current->pos - fixer);
1621                 remove_char(current, current->pos - fixer);
1622                 insert_char(current, current->pos - 1, c);
1623                 refreshLine(current);
1624             }
1625             break;
1626         case ctrl('V'):    /* ctrl-v */
1627             /* Insert the ^V first */
1628             if (insert_char(current, current->pos, c)) {
1629                 refreshLine(current);
1630                 /* Now wait for the next char. Can insert anything except \0 */
1631                 c = fd_read(current);
1632
1633                 /* Remove the ^V first */
1634                 remove_char(current, current->pos - 1);
1635                 if (c > 0) {
1636                     /* Insert the actual char, can't be error or null */
1637                     insert_char(current, current->pos, c);
1638                 }
1639                 refreshLine(current);
1640             }
1641             break;
1642         case ctrl('B'):
1643         case SPECIAL_LEFT:
1644             if (current->pos > 0) {
1645                 current->pos--;
1646                 refreshLine(current);
1647             }
1648             break;
1649         case ctrl('F'):
1650         case SPECIAL_RIGHT:
1651             if (current->pos < sb_chars(current->buf)) {
1652                 current->pos++;
1653                 refreshLine(current);
1654             }
1655             break;
1656         case SPECIAL_PAGE_UP:
1657           dir = history_len - history_index - 1; /* move to start of history */
1658           goto history_navigation;
1659         case SPECIAL_PAGE_DOWN:
1660           dir = -history_index; /* move to 0 == end of history, i.e. current */
1661           goto history_navigation;
1662         case ctrl('P'):
1663         case SPECIAL_UP:
1664             dir = 1;
1665           goto history_navigation;
1666         case ctrl('N'):
1667         case SPECIAL_DOWN:
1668 history_navigation:
1669             if (history_len > 1) {
1670                 /* Update the current history entry before to
1671                  * overwrite it with tne next one. */
1672                 free(history[history_len - 1 - history_index]);
1673                 history[history_len - 1 - history_index] = strdup(sb_str(current->buf));
1674                 /* Show the new entry */
1675                 history_index += dir;
1676                 if (history_index < 0) {
1677                     history_index = 0;
1678                     break;
1679                 } else if (history_index >= history_len) {
1680                     history_index = history_len - 1;
1681                     break;
1682                 }
1683                 set_current(current, history[history_len - 1 - history_index]);
1684                 refreshLine(current);
1685             }
1686             break;
1687         case ctrl('A'): /* Ctrl+a, go to the start of the line */
1688         case SPECIAL_HOME:
1689             current->pos = 0;
1690             refreshLine(current);
1691             break;
1692         case ctrl('E'): /* ctrl+e, go to the end of the line */
1693         case SPECIAL_END:
1694             current->pos = sb_chars(current->buf);
1695             refreshLine(current);
1696             break;
1697         case ctrl('U'): /* Ctrl+u, delete to beginning of line, save deleted chars. */
1698             if (remove_chars(current, 0, current->pos)) {
1699                 refreshLine(current);
1700             }
1701             break;
1702         case ctrl('K'): /* Ctrl+k, delete from current to end of line, save deleted chars. */
1703             if (remove_chars(current, current->pos, sb_chars(current->buf) - current->pos)) {
1704                 refreshLine(current);
1705             }
1706             break;
1707         case ctrl('Y'): /* Ctrl+y, insert saved chars at current position */
1708             if (current->capture && insert_chars(current, current->pos, sb_str(current->capture))) {
1709                 refreshLine(current);
1710             }
1711             break;
1712         case ctrl('L'): /* Ctrl+L, clear screen */
1713             linenoiseClearScreen();
1714             /* Force recalc of window size for serial terminals */
1715             current->cols = 0;
1716             current->rpos = 0;
1717             refreshLine(current);
1718             break;
1719         default:
1720             /* Only tab is allowed without ^V */
1721             if (c == '\t' || c >= ' ') {
1722                 if (insert_char(current, current->pos, c) == 1) {
1723                     refreshLine(current);
1724                 }
1725             }
1726             break;
1727         }
1728     }
1729     return sb_len(current->buf);
1730 }
1731
1732 int linenoiseColumns(void)
1733 {
1734     struct current current;
1735     enableRawMode (&current);
1736     getWindowSize (&current);
1737     disableRawMode (&current);
1738     return current.cols;
1739 }
1740
1741 /**
1742  * Reads a line from the file handle (without the trailing NL or CRNL)
1743  * and returns it in a stringbuf.
1744  * Returns NULL if no characters are read before EOF or error.
1745  *
1746  * Note that the character count will *not* be correct for lines containing
1747  * utf8 sequences. Do not rely on the character count.
1748  */
1749 static stringbuf *sb_getline(FILE *fh)
1750 {
1751     stringbuf *sb = sb_alloc();
1752     int c;
1753     int n = 0;
1754
1755     while ((c = getc(fh)) != EOF) {
1756         char ch;
1757         n++;
1758         if (c == '\r') {
1759             /* CRLF -> LF */
1760             continue;
1761         }
1762         if (c == '\n' || c == '\r') {
1763             break;
1764         }
1765         ch = c;
1766         /* ignore the effect of character count for partial utf8 sequences */
1767         sb_append_len(sb, &ch, 1);
1768     }
1769     if (n == 0) {
1770         sb_free(sb);
1771         return NULL;
1772     }
1773     return sb;
1774 }
1775
1776 char *linenoise(const char *prompt)
1777 {
1778     int count;
1779     struct current current;
1780     stringbuf *sb;
1781
1782     memset(&current, 0, sizeof(current));
1783
1784     if (enableRawMode(&current) == -1) {
1785         printf("%s", prompt);
1786         fflush(stdout);
1787         sb = sb_getline(stdin);
1788     }
1789     else {
1790         current.buf = sb_alloc();
1791         current.pos = 0;
1792         current.nrows = 1;
1793         current.prompt = prompt;
1794
1795         count = linenoiseEdit(&current);
1796
1797         disableRawMode(&current);
1798         printf("\n");
1799
1800         sb_free(current.capture);
1801         if (count == -1) {
1802             sb_free(current.buf);
1803             return NULL;
1804         }
1805         sb = current.buf;
1806     }
1807     return sb ? sb_to_string(sb) : NULL;
1808 }
1809
1810 /* Using a circular buffer is smarter, but a bit more complex to handle. */
1811 int linenoiseHistoryAddAllocated(char *line) {
1812
1813     if (history_max_len == 0) {
1814 notinserted:
1815         free(line);
1816         return 0;
1817     }
1818     if (history == NULL) {
1819         history = (char **)calloc(sizeof(char*), history_max_len);
1820     }
1821
1822     /* do not insert duplicate lines into history */
1823     if (history_len > 0 && strcmp(line, history[history_len - 1]) == 0) {
1824         goto notinserted;
1825     }
1826
1827     if (history_len == history_max_len) {
1828         free(history[0]);
1829         memmove(history,history+1,sizeof(char*)*(history_max_len-1));
1830         history_len--;
1831     }
1832     history[history_len] = line;
1833     history_len++;
1834     return 1;
1835 }
1836
1837 int linenoiseHistoryAdd(const char *line) {
1838     return linenoiseHistoryAddAllocated(strdup(line));
1839 }
1840
1841 int linenoiseHistoryGetMaxLen(void) {
1842     return history_max_len;
1843 }
1844
1845 int linenoiseHistorySetMaxLen(int len) {
1846     char **newHistory;
1847
1848     if (len < 1) return 0;
1849     if (history) {
1850         int tocopy = history_len;
1851
1852         newHistory = (char **)calloc(sizeof(char*), len);
1853
1854         /* If we can't copy everything, free the elements we'll not use. */
1855         if (len < tocopy) {
1856             int j;
1857
1858             for (j = 0; j < tocopy-len; j++) free(history[j]);
1859             tocopy = len;
1860         }
1861         memcpy(newHistory,history+(history_len-tocopy), sizeof(char*)*tocopy);
1862         free(history);
1863         history = newHistory;
1864     }
1865     history_max_len = len;
1866     if (history_len > history_max_len)
1867         history_len = history_max_len;
1868     return 1;
1869 }
1870
1871 /* Save the history in the specified file. On success 0 is returned
1872  * otherwise -1 is returned. */
1873 int linenoiseHistorySave(const char *filename) {
1874     FILE *fp = fopen(filename,"w");
1875     int j;
1876
1877     if (fp == NULL) return -1;
1878     for (j = 0; j < history_len; j++) {
1879         const char *str = history[j];
1880         /* Need to encode backslash, nl and cr */
1881         while (*str) {
1882             if (*str == '\\') {
1883                 fputs("\\\\", fp);
1884             }
1885             else if (*str == '\n') {
1886                 fputs("\\n", fp);
1887             }
1888             else if (*str == '\r') {
1889                 fputs("\\r", fp);
1890             }
1891             else {
1892                 fputc(*str, fp);
1893             }
1894             str++;
1895         }
1896         fputc('\n', fp);
1897     }
1898
1899     fclose(fp);
1900     return 0;
1901 }
1902
1903 /* Load the history from the specified file.
1904  *
1905  * If the file does not exist or can't be opened, no operation is performed
1906  * and -1 is returned.
1907  * Otherwise 0 is returned.
1908  */
1909 int linenoiseHistoryLoad(const char *filename) {
1910     FILE *fp = fopen(filename,"r");
1911     stringbuf *sb;
1912
1913     if (fp == NULL) return -1;
1914
1915     while ((sb = sb_getline(fp)) != NULL) {
1916         /* Take the stringbuf and decode backslash escaped values */
1917         char *buf = sb_to_string(sb);
1918         char *dest = buf;
1919         const char *src;
1920
1921         for (src = buf; *src; src++) {
1922             char ch = *src;
1923
1924             if (ch == '\\') {
1925                 src++;
1926                 if (*src == 'n') {
1927                     ch = '\n';
1928                 }
1929                 else if (*src == 'r') {
1930                     ch = '\r';
1931                 } else {
1932                     ch = *src;
1933                 }
1934             }
1935             *dest++ = ch;
1936         }
1937         *dest = 0;
1938
1939         linenoiseHistoryAddAllocated(buf);
1940     }
1941     fclose(fp);
1942     return 0;
1943 }
1944
1945 /* Provide access to the history buffer.
1946  *
1947  * If 'len' is not NULL, the length is stored in *len.
1948  */
1949 char **linenoiseHistory(int *len) {
1950     if (len) {
1951         *len = history_len;
1952     }
1953     return history;
1954 }