debug show should not force object to 'string'
[jimtcl.git] / linenoise.c
blobe0cc7a8047c315b1c738bceb3eb56ad724b3e1a1
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.
4 * You can find the latest source code at:
6 * http://github.com/antirez/linenoise
8 * Does a number of crazy assumptions that happen to be true in 99.9999% of
9 * the 2010 UNIX computers around.
11 * ------------------------------------------------------------------------
13 * Copyright (c) 2010, Salvatore Sanfilippo <antirez at gmail dot com>
14 * Copyright (c) 2010, Pieter Noordhuis <pcnoordhuis at gmail dot com>
16 * All rights reserved.
18 * Redistribution and use in source and binary forms, with or without
19 * modification, are permitted provided that the following conditions are
20 * met:
22 * * Redistributions of source code must retain the above copyright
23 * notice, this list of conditions and the following disclaimer.
25 * * Redistributions in binary form must reproduce the above copyright
26 * notice, this list of conditions and the following disclaimer in the
27 * documentation and/or other materials provided with the distribution.
29 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
30 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
31 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
32 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
33 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
34 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
35 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
36 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
37 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
38 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
39 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
41 * ------------------------------------------------------------------------
43 * References:
44 * - http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
45 * - http://www.3waylabs.com/nw/WWW/products/wizcon/vt220.html
47 * Todo list:
48 * - Win32 support
49 * - Save and load history containing newlines
51 * Bloat:
52 * - Completion?
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.
59 * CHA (Cursor Horizontal Absolute)
60 * Sequence: ESC [ n G
61 * Effect: moves cursor to column n
63 * EL (Erase Line)
64 * Sequence: ESC [ n K
65 * Effect: if n is 0 or missing, clear from cursor to end of line
66 * Effect: if n is 1, clear from beginning of line to cursor
67 * Effect: if n is 2, clear entire line
69 * CUF (CUrsor Forward)
70 * Sequence: ESC [ n C
71 * Effect: moves cursor forward of n chars
73 * The following are used to clear the screen: ESC [ H ESC [ 2 J
74 * This is actually composed of two sequences:
76 * cursorhome
77 * Sequence: ESC [ H
78 * Effect: moves the cursor to upper left corner
80 * ED2 (Clear entire screen)
81 * Sequence: ESC [ 2 J
82 * Effect: clear the whole screen
84 * == For highlighting control characters, we also use the following two ==
85 * SO (enter StandOut)
86 * Sequence: ESC [ 7 m
87 * Effect: Uses some standout mode such as reverse video
89 * SE (Standout End)
90 * Sequence: ESC [ 0 m
91 * Effect: Exit standout mode
93 * == Only used if TIOCGWINSZ fails ==
94 * DSR/CPR (Report cursor position)
95 * Sequence: ESC [ 6 n
96 * Effect: reports current cursor position as ESC [ NNN ; MMM R
99 #include <termios.h>
100 #include <unistd.h>
101 #include <stdlib.h>
102 #include <stdarg.h>
103 #include <stdio.h>
104 #include <errno.h>
105 #include <string.h>
106 #include <stdlib.h>
107 #include <sys/types.h>
108 #include <sys/ioctl.h>
109 #include <sys/poll.h>
110 #include <unistd.h>
111 #include "linenoise.h"
113 #include "jim-config.h"
114 #ifdef JIM_UTF8
115 #define USE_UTF8
116 #endif
117 #include "utf8.h"
119 #define LINENOISE_DEFAULT_HISTORY_MAX_LEN 100
120 #define LINENOISE_MAX_LINE 4096
121 static char *unsupported_term[] = {"dumb","cons25",NULL};
123 static struct termios orig_termios; /* in order to restore at exit */
124 static int rawmode = 0; /* for atexit() function to check if restore is needed*/
125 static int atexit_registered = 0; /* register atexit just 1 time */
126 static int history_max_len = LINENOISE_DEFAULT_HISTORY_MAX_LEN;
127 static int history_len = 0;
128 static char **history = NULL;
130 static void linenoiseAtExit(void);
131 static int fd_read(int fd);
132 static void getColumns(int fd, int *cols);
134 static int isUnsupportedTerm(void) {
135 char *term = getenv("TERM");
136 int j;
138 if (term == NULL) return 0;
139 for (j = 0; unsupported_term[j]; j++)
140 if (!strcasecmp(term,unsupported_term[j])) return 1;
141 return 0;
144 static void freeHistory(void) {
145 if (history) {
146 int j;
148 for (j = 0; j < history_len; j++)
149 free(history[j]);
150 free(history);
151 history = NULL;
155 static int enableRawMode(int fd) {
156 struct termios raw;
158 if (!isatty(STDIN_FILENO)) goto fatal;
159 if (!atexit_registered) {
160 atexit(linenoiseAtExit);
161 atexit_registered = 1;
163 if (tcgetattr(fd,&orig_termios) == -1) goto fatal;
165 raw = orig_termios; /* modify the original mode */
166 /* input modes: no break, no CR to NL, no parity check, no strip char,
167 * no start/stop output control. */
168 raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
169 /* output modes - disable post processing */
170 raw.c_oflag &= ~(OPOST);
171 /* control modes - set 8 bit chars */
172 raw.c_cflag |= (CS8);
173 /* local modes - choing off, canonical off, no extended functions,
174 * no signal chars (^Z,^C) */
175 raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
176 /* control chars - set return condition: min number of bytes and timer.
177 * We want read to return every single byte, without timeout. */
178 raw.c_cc[VMIN] = 1; raw.c_cc[VTIME] = 0; /* 1 byte, no timer */
180 /* put terminal in raw mode after flushing */
181 if (tcsetattr(fd,TCSADRAIN,&raw) < 0) goto fatal;
182 rawmode = 1;
183 return 0;
185 fatal:
186 errno = ENOTTY;
187 return -1;
190 static void disableRawMode(int fd) {
191 /* Don't even check the return value as it's too late. */
192 if (rawmode && tcsetattr(fd,TCSADRAIN,&orig_termios) != -1)
193 rawmode = 0;
196 /* At exit we'll try to fix the terminal to the initial conditions. */
197 static void linenoiseAtExit(void) {
198 disableRawMode(STDIN_FILENO);
199 freeHistory();
202 /* Structure to contain the status of the current (being edited) line */
203 struct current {
204 int fd; /* Terminal fd */
205 char *buf; /* Current buffer. Always null terminated */
206 int bufmax; /* Size of the buffer, including space for the null termination */
207 int len; /* Number of bytes in 'buf' */
208 int chars; /* Number of chars in 'buf' (utf-8 chars) */
209 int pos; /* Cursor position, measured in chars */
210 int cols; /* Size of the window, in chars */
211 const char *prompt;
214 /* gcc/glibc insists that we care about the return code of write! */
215 #if defined(__GNUC__) && !defined(__clang__)
216 #define IGNORE_RC(EXPR) ((EXPR) < 0 ? -1 : 0)
217 #else
218 #define IGNORE_RC(EXPR) EXPR
219 #endif
221 /* This is fd_printf() on some systems, but use a different
222 * name to avoid conflicts
224 static void fd_printf(int fd, const char *format, ...)
226 va_list args;
227 char buf[64];
228 int n;
230 va_start(args, format);
231 n = vsnprintf(buf, sizeof(buf), format, args);
232 va_end(args);
233 IGNORE_RC(write(fd, buf, n));
236 static int utf8_getchars(char *buf, int c)
238 #ifdef USE_UTF8
239 return utf8_fromunicode(buf, c);
240 #else
241 *buf = c;
242 return 1;
243 #endif
247 * Returns the unicode character at the given offset,
248 * or -1 if none.
250 static int get_char(struct current *current, int pos)
252 if (pos >= 0 && pos < current->chars) {
253 int c;
254 int i = utf8_index(current->buf, pos);
255 (void)utf8_tounicode(current->buf + i, &c);
256 return c;
258 return -1;
261 static void refreshLine(const char *prompt, struct current *current) {
262 int plen;
263 int pchars;
264 int backup = 0;
265 int i;
266 const char *buf = current->buf;
267 int chars = current->chars;
268 int pos = current->pos;
269 int b;
270 int ch;
271 int n;
273 /* Should intercept SIGWINCH. For now, just get the size every time */
274 getColumns(current->fd, &current->cols);
276 plen = strlen(prompt);
277 pchars = utf8_strlen(prompt, plen);
279 /* Account for a line which is too long to fit in the window.
280 * Note that control chars require an extra column
283 /* How many cols are required to the left of 'pos'?
284 * The prompt, plus one extra for each control char
286 n = pchars + utf8_strlen(buf, current->len);
287 b = 0;
288 for (i = 0; i < pos; i++) {
289 b += utf8_tounicode(buf + b, &ch);
290 if (ch < ' ') {
291 n++;
295 /* If too many are need, strip chars off the front of 'buf'
296 * until it fits. Note that if the current char is a control character,
297 * we need one extra col.
299 if (current->pos < current->chars && get_char(current, current->pos) < ' ') {
300 n++;
303 while (n >= current->cols) {
304 b = utf8_tounicode(buf, &ch);
305 if (ch < ' ') {
306 n--;
308 n--;
309 buf += b;
310 pos--;
311 chars--;
314 /* Cursor to left edge, then the prompt */
315 fd_printf(current->fd, "\x1b[0G");
316 IGNORE_RC(write(current->fd, prompt, plen));
318 /* Now the current buffer content */
320 /* Need special handling for control characters.
321 * If we hit 'cols', stop.
323 b = 0; /* unwritted bytes */
324 n = 0; /* How many control chars were written */
325 for (i = 0; i < chars; i++) {
326 int ch;
327 int w = utf8_tounicode(buf + b, &ch);
328 if (ch < ' ') {
329 n++;
331 if (pchars + i + n >= current->cols) {
332 break;
334 if (ch < ' ') {
335 /* A control character, so write the buffer so far */
336 IGNORE_RC(write(current->fd, buf, b));
337 buf += b + w;
338 b = 0;
339 fd_printf(current->fd, "\033[7m^%c\033[0m", ch + '@');
340 if (i < pos) {
341 backup++;
344 else {
345 b += w;
348 IGNORE_RC(write(current->fd, buf, b));
350 /* Erase to right, move cursor to original position */
351 fd_printf(current->fd, "\x1b[0K" "\x1b[0G\x1b[%dC", pos + pchars + backup);
354 static void set_current(struct current *current, const char *str)
356 strncpy(current->buf, str, current->bufmax);
357 current->buf[current->bufmax - 1] = 0;
358 current->len = strlen(current->buf);
359 current->pos = current->chars = utf8_strlen(current->buf, current->len);
362 static int has_room(struct current *current, int bytes)
364 return current->len + bytes < current->bufmax - 1;
368 * Removes the char at 'pos'.
370 * Returns 1 if the line needs to be refreshed, 2 if not
371 * and 0 if nothing was removed
373 static int remove_char(struct current *current, int pos)
375 if (pos >= 0 && pos < current->chars) {
376 int p1, p2;
377 int ret = 1;
378 p1 = utf8_index(current->buf, pos);
379 p2 = p1 + utf8_index(current->buf + p1, 1);
381 /* optimise remove char in the case of removing the last char */
382 if (current->pos == pos + 1 && current->pos == current->chars) {
383 if (current->buf[pos] >= ' ' && utf8_strlen(current->prompt, -1) + utf8_strlen(current->buf, current->len) < current->cols - 1) {
384 ret = 2;
385 fd_printf(current->fd, "\b \b");
389 /* Move the null char too */
390 memmove(current->buf + p1, current->buf + p2, current->len - p2 + 1);
391 current->len -= (p2 - p1);
392 current->chars--;
394 if (current->pos > pos) {
395 current->pos--;
397 return ret;
399 return 0;
403 * Insert 'ch' at position 'pos'
405 * Returns 1 if the line needs to be refreshed, 2 if not
406 * and 0 if nothing was inserted (no room)
408 static int insert_char(struct current *current, int pos, int ch)
410 char buf[3];
411 int n = utf8_getchars(buf, ch);
413 if (has_room(current, n) && pos >= 0 && pos <= current->chars) {
414 int p1, p2;
415 int ret = 1;
416 p1 = utf8_index(current->buf, pos);
417 p2 = p1 + n;
419 /* optimise the case where adding a single char to the end and no scrolling is needed */
420 if (current->pos == pos && current->chars == pos) {
421 if (ch >= ' ' && utf8_strlen(current->prompt, -1) + utf8_strlen(current->buf, current->len) < current->cols - 1) {
422 IGNORE_RC(write(current->fd, buf, n));
423 ret = 2;
427 memmove(current->buf + p2, current->buf + p1, current->len - p1);
428 memcpy(current->buf + p1, buf, n);
429 current->len += n;
431 current->chars++;
432 if (current->pos >= pos) {
433 current->pos++;
435 return ret;
437 return 0;
440 #ifndef NO_COMPLETION
441 static linenoiseCompletionCallback *completionCallback = NULL;
443 static void beep() {
444 fprintf(stderr, "\x7");
445 fflush(stderr);
448 static void freeCompletions(linenoiseCompletions *lc) {
449 size_t i;
450 for (i = 0; i < lc->len; i++)
451 free(lc->cvec[i]);
452 free(lc->cvec);
455 static int completeLine(struct current *current) {
456 linenoiseCompletions lc = { 0, NULL };
457 int c = 0;
459 completionCallback(current->buf,&lc);
460 if (lc.len == 0) {
461 beep();
462 } else {
463 size_t stop = 0, i = 0;
465 while(!stop) {
466 /* Show completion or original buffer */
467 if (i < lc.len) {
468 struct current tmp = *current;
469 tmp.buf = lc.cvec[i];
470 tmp.pos = tmp.len = strlen(tmp.buf);
471 tmp.chars = utf8_strlen(tmp.buf, tmp.len);
472 refreshLine(current->prompt, &tmp);
473 } else {
474 refreshLine(current->prompt, current);
477 c = fd_read(current->fd);
478 if (c < 0) {
479 break;
482 switch(c) {
483 case '\t': /* tab */
484 i = (i+1) % (lc.len+1);
485 if (i == lc.len) beep();
486 break;
487 case 27: /* escape */
488 /* Re-show original buffer */
489 if (i < lc.len) {
490 refreshLine(current->prompt, current);
492 stop = 1;
493 break;
494 default:
495 /* Update buffer and return */
496 if (i < lc.len) {
497 set_current(current,lc.cvec[i]);
499 stop = 1;
500 break;
505 freeCompletions(&lc);
506 return c; /* Return last read character */
509 /* Register a callback function to be called for tab-completion. */
510 void linenoiseSetCompletionCallback(linenoiseCompletionCallback *fn) {
511 completionCallback = fn;
514 void linenoiseAddCompletion(linenoiseCompletions *lc, const char *str) {
515 lc->cvec = realloc(lc->cvec,sizeof(char*)*(lc->len+1));
516 lc->cvec[lc->len++] = strdup(str);
519 #endif
522 * Returns 0 if no chars were removed or non-zero otherwise.
524 static int remove_chars(struct current *current, int pos, int n)
526 int removed = 0;
527 while (n-- && remove_char(current, pos)) {
528 removed++;
530 return removed;
534 * Reads a char from 'fd', waiting at most 'timeout' milliseconds.
536 * A timeout of -1 means to wait forever.
538 * Returns -1 if no char is received within the time or an error occurs.
540 static int fd_read_char(int fd, int timeout)
542 struct pollfd p;
543 unsigned char c;
545 p.fd = fd;
546 p.events = POLLIN;
548 if (poll(&p, 1, timeout) == 0) {
549 /* timeout */
550 return -1;
552 if (read(fd, &c, 1) != 1) {
553 return -1;
555 return c;
559 * Reads a complete utf-8 character
560 * and returns the unicode value, or -1 on error.
562 static int fd_read(int fd)
564 #ifdef USE_UTF8
565 char buf[4];
566 int n;
567 int i;
568 int c;
570 if (read(fd, &buf[0], 1) != 1) {
571 return -1;
573 n = utf8_charlen(buf[0]);
574 if (n < 1 || n > 3) {
575 return -1;
577 for (i = 1; i < n; i++) {
578 if (read(fd, &buf[i], 1) != 1) {
579 return -1;
582 buf[n] = 0;
583 /* decode and return the character */
584 utf8_tounicode(buf, &c);
585 return c;
586 #else
587 return fd_read_char(fd, -1);
588 #endif
591 static void getColumns(int fd, int *cols) {
592 struct winsize ws;
594 if (ioctl(1, TIOCGWINSZ, &ws) == 0 && ws.ws_col != 0) {
595 *cols = ws.ws_col;
596 return;
598 /* Failed to query the window size. Perhaps we are on a serial terminal.
599 * Try to query the width by sending the cursor as far to the right
600 * and reading back the cursor position.
601 * Note that this is only done once per call to linenoise rather than
602 * every time the line is refreshed for efficiency reasons.
604 if (*cols == 0) {
605 *cols = 80;
607 /* Move cursor far right and report cursor position */
608 fd_printf(fd, "\x1b[999G" "\x1b[6n");
610 /* Parse the response: ESC [ rows ; cols R */
611 if (fd_read_char(fd, 100) == 0x1b && fd_read_char(fd, 100) == '[') {
612 int n = 0;
613 while (1) {
614 int ch = fd_read_char(fd, 100);
615 if (ch == ';') {
616 /* Ignore rows */
617 n = 0;
619 else if (ch == 'R') {
620 /* Got cols */
621 if (n != 0 && n < 1000) {
622 *cols = n;
624 break;
626 else if (ch >= 0 && ch <= '9') {
627 n = n * 10 + ch - '0';
629 else {
630 break;
637 /* Use -ve numbers here to co-exist with normal unicode chars */
638 enum {
639 SPECIAL_NONE,
640 SPECIAL_UP = -20,
641 SPECIAL_DOWN = -21,
642 SPECIAL_LEFT = -22,
643 SPECIAL_RIGHT = -23,
644 SPECIAL_DELETE = -24,
645 SPECIAL_HOME = -25,
646 SPECIAL_END = -26,
650 * If escape (27) was received, reads subsequent
651 * chars to determine if this is a known special key.
653 * Returns SPECIAL_NONE if unrecognised, or -1 if EOF.
655 * If no additional char is received within a short time,
656 * 27 is returned.
658 static int check_special(int fd)
660 int c = fd_read_char(fd, 50);
661 int c2;
663 if (c < 0) {
664 return 27;
667 c2 = fd_read_char(fd, 50);
668 if (c2 < 0) {
669 return c2;
671 if (c == '[' || c == 'O') {
672 /* Potential arrow key */
673 switch (c2) {
674 case 'A':
675 return SPECIAL_UP;
676 case 'B':
677 return SPECIAL_DOWN;
678 case 'C':
679 return SPECIAL_RIGHT;
680 case 'D':
681 return SPECIAL_LEFT;
682 case 'F':
683 return SPECIAL_END;
684 case 'H':
685 return SPECIAL_HOME;
688 if (c == '[' && c2 >= '1' && c2 <= '6') {
689 /* extended escape */
690 int c3 = fd_read_char(fd, 50);
691 if (c2 == '3' && c3 == '~') {
692 /* delete char under cursor */
693 return SPECIAL_DELETE;
695 while (c3 != -1 && c3 != '~') {
696 /* .e.g \e[12~ or '\e[11;2~ discard the complete sequence */
697 c3 = fd_read_char(fd, 50);
701 return SPECIAL_NONE;
704 #define ctrl(C) ((C) - '@')
706 static int linenoisePrompt(struct current *current) {
707 int history_index = 0;
709 /* The latest history entry is always our current buffer, that
710 * initially is just an empty string. */
711 linenoiseHistoryAdd("");
713 set_current(current, "");
714 refreshLine(current->prompt, current);
716 while(1) {
717 int c = fd_read(current->fd);
719 #ifndef NO_COMPLETION
720 /* Only autocomplete when the callback is set. It returns < 0 when
721 * there was an error reading from fd. Otherwise it will return the
722 * character that should be handled next. */
723 if (c == 9 && completionCallback != NULL) {
724 c = completeLine(current);
725 /* Return on errors */
726 if (c < 0) return current->len;
727 /* Read next character when 0 */
728 if (c == 0) continue;
730 #endif
732 process_char:
733 if (c == -1) return current->len;
734 switch(c) {
735 case '\r': /* enter */
736 history_len--;
737 free(history[history_len]);
738 return current->len;
739 case ctrl('C'): /* ctrl-c */
740 errno = EAGAIN;
741 return -1;
742 case 127: /* backspace */
743 case ctrl('H'):
744 if (remove_char(current, current->pos - 1) == 1) {
745 refreshLine(current->prompt, current);
747 break;
748 case ctrl('D'): /* ctrl-d */
749 if (current->len == 0) {
750 /* Empty line, so EOF */
751 history_len--;
752 free(history[history_len]);
753 return -1;
755 /* Otherwise delete char to right of cursor */
756 if (remove_char(current, current->pos)) {
757 refreshLine(current->prompt, current);
759 break;
760 case ctrl('W'): /* ctrl-w */
761 /* eat any spaces on the left */
763 int pos = current->pos;
764 while (pos > 0 && get_char(current, pos - 1) == ' ') {
765 pos--;
768 /* now eat any non-spaces on the left */
769 while (pos > 0 && get_char(current, pos - 1) != ' ') {
770 pos--;
773 if (remove_chars(current, pos, current->pos - pos)) {
774 refreshLine(current->prompt, current);
777 break;
778 case ctrl('R'): /* ctrl-r */
780 /* Display the reverse-i-search prompt and process chars */
781 char rbuf[50];
782 char rprompt[80];
783 int rchars = 0;
784 int rlen = 0;
785 int searchpos = history_len - 1;
787 rbuf[0] = 0;
788 while (1) {
789 int n = 0;
790 const char *p = NULL;
791 int skipsame = 0;
792 int searchdir = -1;
794 snprintf(rprompt, sizeof(rprompt), "(reverse-i-search)'%s': ", rbuf);
795 refreshLine(rprompt, current);
796 c = fd_read(current->fd);
797 if (c == ctrl('H') || c == 127) {
798 if (rchars) {
799 int p = utf8_index(rbuf, --rchars);
800 rbuf[p] = 0;
801 rlen = strlen(rbuf);
803 continue;
805 if (c == 27) {
806 c = check_special(current->fd);
808 if (c == ctrl('P') || c == SPECIAL_UP) {
809 /* Search for the previous (earlier) match */
810 if (searchpos > 0) {
811 searchpos--;
813 skipsame = 1;
815 else if (c == ctrl('N') || c == SPECIAL_DOWN) {
816 /* Search for the next (later) match */
817 if (searchpos < history_len) {
818 searchpos++;
820 searchdir = 1;
821 skipsame = 1;
823 else if (c >= ' ') {
824 if (rlen >= (int)sizeof(rbuf) + 3) {
825 continue;
828 n = utf8_getchars(rbuf + rlen, c);
829 rlen += n;
830 rchars++;
831 rbuf[rlen] = 0;
833 /* Adding a new char resets the search location */
834 searchpos = history_len - 1;
836 else {
837 /* Exit from incremental search mode */
838 break;
841 /* Now search through the history for a match */
842 for (; searchpos >= 0 && searchpos < history_len; searchpos += searchdir) {
843 p = strstr(history[searchpos], rbuf);
844 if (p) {
845 /* Found a match */
846 if (skipsame && strcmp(history[searchpos], current->buf) == 0) {
847 /* But it is identical, so skip it */
848 continue;
850 /* Copy the matching line and set the cursor position */
851 set_current(current,history[searchpos]);
852 current->pos = utf8_strlen(history[searchpos], p - history[searchpos]);
853 break;
856 if (!p && n) {
857 /* No match, so don't add it */
858 rchars--;
859 rlen -= n;
860 rbuf[rlen] = 0;
863 if (c == ctrl('G') || c == ctrl('C')) {
864 /* ctrl-g terminates the search with no effect */
865 set_current(current, "");
866 c = 0;
868 else if (c == ctrl('J')) {
869 /* ctrl-j terminates the search leaving the buffer in place */
870 c = 0;
872 /* Go process the char normally */
873 refreshLine(current->prompt, current);
874 goto process_char;
876 break;
877 case ctrl('T'): /* ctrl-t */
878 if (current->pos > 0 && current->pos < current->chars) {
879 c = get_char(current, current->pos);
880 remove_char(current, current->pos);
881 insert_char(current, current->pos - 1, c);
882 refreshLine(current->prompt, current);
884 break;
885 case ctrl('V'): /* ctrl-v */
886 if (has_room(current, 3)) {
887 /* Insert the ^V first */
888 if (insert_char(current, current->pos, c)) {
889 refreshLine(current->prompt, current);
890 /* Now wait for the next char. Can insert anything except \0 */
891 c = fd_read(current->fd);
893 /* Remove the ^V first */
894 remove_char(current, current->pos - 1);
895 if (c != -1) {
896 /* Insert the actual char */
897 insert_char(current, current->pos, c);
899 refreshLine(current->prompt, current);
902 break;
903 case ctrl('B'): /* ctrl-b */
904 case ctrl('F'): /* ctrl-f */
905 case ctrl('P'): /* ctrl-p */
906 case ctrl('N'): /* ctrl-n */
907 case 27: { /* escape sequence */
908 int dir = -1;
909 if (c == 27) {
910 c = check_special(current->fd);
912 switch (c) {
913 case ctrl('B'):
914 case SPECIAL_LEFT:
915 if (current->pos > 0) {
916 current->pos--;
917 refreshLine(current->prompt, current);
919 break;
920 case ctrl('F'):
921 case SPECIAL_RIGHT:
922 if (current->pos < current->chars) {
923 current->pos++;
924 refreshLine(current->prompt, current);
926 break;
927 case ctrl('P'):
928 case SPECIAL_UP:
929 dir = 1;
930 case ctrl('N'):
931 case SPECIAL_DOWN:
932 if (history_len > 1) {
933 /* Update the current history entry before to
934 * overwrite it with tne next one. */
935 free(history[history_len-1-history_index]);
936 history[history_len-1-history_index] = strdup(current->buf);
937 /* Show the new entry */
938 history_index += dir;
939 if (history_index < 0) {
940 history_index = 0;
941 break;
942 } else if (history_index >= history_len) {
943 history_index = history_len-1;
944 break;
946 set_current(current, history[history_len-1-history_index]);
947 refreshLine(current->prompt, current);
949 break;
951 case SPECIAL_DELETE:
952 if (remove_char(current, current->pos) == 1) {
953 refreshLine(current->prompt, current);
955 break;
956 case SPECIAL_HOME:
957 current->pos = 0;
958 refreshLine(current->prompt, current);
959 break;
960 case SPECIAL_END:
961 current->pos = current->chars;
962 refreshLine(current->prompt, current);
963 break;
966 break;
967 default:
968 /* Only tab is allowed without ^V */
969 if (c == '\t' || c >= ' ') {
970 if (insert_char(current, current->pos, c) == 1) {
971 refreshLine(current->prompt, current);
974 break;
975 case ctrl('U'): /* Ctrl+u, delete to beginning of line. */
976 if (remove_chars(current, 0, current->pos)) {
977 refreshLine(current->prompt, current);
979 break;
980 case ctrl('K'): /* Ctrl+k, delete from current to end of line. */
981 if (remove_chars(current, current->pos, current->chars - current->pos)) {
982 refreshLine(current->prompt, current);
984 break;
985 case ctrl('A'): /* Ctrl+a, go to the start of the line */
986 current->pos = 0;
987 refreshLine(current->prompt, current);
988 break;
989 case ctrl('E'): /* ctrl+e, go to the end of the line */
990 current->pos = current->chars;
991 refreshLine(current->prompt, current);
992 break;
993 case ctrl('L'): /* Ctrl+L, clear screen */
994 /* clear screen */
995 fd_printf(current->fd, "\x1b[H\x1b[2J");
996 /* Force recalc of window size for serial terminals */
997 current->cols = 0;
998 refreshLine(current->prompt, current);
999 break;
1002 return current->len;
1005 static int linenoiseRaw(char *buf, size_t buflen, const char *prompt) {
1006 int fd = STDIN_FILENO;
1007 int count;
1009 if (buflen == 0) {
1010 errno = EINVAL;
1011 return -1;
1013 if (!isatty(STDIN_FILENO)) {
1014 if (fgets(buf, buflen, stdin) == NULL) return -1;
1015 count = strlen(buf);
1016 if (count && buf[count-1] == '\n') {
1017 count--;
1018 buf[count] = '\0';
1020 } else {
1021 struct current current;
1023 if (enableRawMode(fd) == -1) return -1;
1025 current.fd = fd;
1026 current.buf = buf;
1027 current.bufmax = buflen;
1028 current.len = 0;
1029 current.chars = 0;
1030 current.pos = 0;
1031 current.cols = 0;
1032 current.prompt = prompt;
1034 count = linenoisePrompt(&current);
1035 disableRawMode(fd);
1037 printf("\n");
1039 return count;
1042 char *linenoise(const char *prompt) {
1043 char buf[LINENOISE_MAX_LINE];
1044 int count;
1046 if (isUnsupportedTerm()) {
1047 size_t len;
1049 printf("%s",prompt);
1050 fflush(stdout);
1051 if (fgets(buf,LINENOISE_MAX_LINE,stdin) == NULL) return NULL;
1052 len = strlen(buf);
1053 while(len && (buf[len-1] == '\n' || buf[len-1] == '\r')) {
1054 len--;
1055 buf[len] = '\0';
1057 return strdup(buf);
1058 } else {
1059 count = linenoiseRaw(buf,LINENOISE_MAX_LINE,prompt);
1060 if (count == -1) return NULL;
1061 return strdup(buf);
1065 /* Using a circular buffer is smarter, but a bit more complex to handle. */
1066 int linenoiseHistoryAdd(const char *line) {
1067 char *linecopy;
1069 if (history_max_len == 0) return 0;
1070 if (history == NULL) {
1071 history = malloc(sizeof(char*)*history_max_len);
1072 if (history == NULL) return 0;
1073 memset(history,0,(sizeof(char*)*history_max_len));
1075 linecopy = strdup(line);
1076 if (!linecopy) return 0;
1077 if (history_len == history_max_len) {
1078 free(history[0]);
1079 memmove(history,history+1,sizeof(char*)*(history_max_len-1));
1080 history_len--;
1082 history[history_len] = linecopy;
1083 history_len++;
1084 return 1;
1087 int linenoiseHistorySetMaxLen(int len) {
1088 char **new;
1090 if (len < 1) return 0;
1091 if (history) {
1092 int tocopy = history_len;
1094 new = malloc(sizeof(char*)*len);
1095 if (new == NULL) return 0;
1096 if (len < tocopy) tocopy = len;
1097 memcpy(new,history+(history_max_len-tocopy), sizeof(char*)*tocopy);
1098 free(history);
1099 history = new;
1101 history_max_len = len;
1102 if (history_len > history_max_len)
1103 history_len = history_max_len;
1104 return 1;
1107 /* Save the history in the specified file. On success 0 is returned
1108 * otherwise -1 is returned. */
1109 int linenoiseHistorySave(char *filename) {
1110 FILE *fp = fopen(filename,"w");
1111 int j;
1113 if (fp == NULL) return -1;
1114 for (j = 0; j < history_len; j++) {
1115 const char *str = history[j];
1116 /* Need to encode backslash, nl and cr */
1117 while (*str) {
1118 if (*str == '\\') {
1119 fputs("\\\\", fp);
1121 else if (*str == '\n') {
1122 fputs("\\n", fp);
1124 else if (*str == '\r') {
1125 fputs("\\r", fp);
1127 else {
1128 fputc(*str, fp);
1130 str++;
1132 fputc('\n', fp);
1135 fclose(fp);
1136 return 0;
1139 /* Load the history from the specified file. If the file does not exist
1140 * zero is returned and no operation is performed.
1142 * If the file exists and the operation succeeded 0 is returned, otherwise
1143 * on error -1 is returned. */
1144 int linenoiseHistoryLoad(char *filename) {
1145 FILE *fp = fopen(filename,"r");
1146 char buf[LINENOISE_MAX_LINE];
1148 if (fp == NULL) return -1;
1150 while (fgets(buf,LINENOISE_MAX_LINE,fp) != NULL) {
1151 char *src, *dest;
1153 /* Decode backslash escaped values */
1154 for (src = dest = buf; *src; src++) {
1155 char ch = *src;
1157 if (ch == '\\') {
1158 src++;
1159 if (*src == 'n') {
1160 ch = '\n';
1162 else if (*src == 'r') {
1163 ch = '\r';
1164 } else {
1165 ch = *src;
1168 *dest++ = ch;
1170 /* Remove trailing newline */
1171 if (dest != buf && (dest[-1] == '\n' || dest[-1] == '\r')) {
1172 dest--;
1174 *dest = 0;
1176 linenoiseHistoryAdd(buf);
1178 fclose(fp);
1179 return 0;
1182 /* Provide access to the history buffer.
1184 * If 'len' is not NULL, the length is stored in *len.
1186 char **linenoiseHistory(int *len) {
1187 if (len) {
1188 *len = history_len;
1190 return history;