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/msteveb/linenoise
7 * (forked from http://github.com/antirez/linenoise)
9 * Does a number of crazy assumptions that happen to be true in 99.9999% of
10 * the 2010 UNIX computers around.
12 * ------------------------------------------------------------------------
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>
18 * All rights reserved.
20 * Redistribution and use in source and binary forms, with or without
21 * modification, are permitted provided that the following conditions are
24 * * Redistributions of source code must retain the above copyright
25 * notice, this list of conditions and the following disclaimer.
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.
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.
43 * ------------------------------------------------------------------------
46 * - http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
47 * - http://www.3waylabs.com/nw/WWW/products/wizcon/vt220.html
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.
61 * Effect: if n is 0 or missing, clear from cursor to end of line
62 * Effect: if n is 1, clear from beginning of line to cursor
63 * Effect: if n is 2, clear entire line
65 * CUF (CUrsor Forward)
67 * Effect: moves cursor forward of n chars
69 * CR (Carriage Return)
71 * Effect: moves cursor to column 1
73 * The following are used to clear the screen: ESC [ H ESC [ 2 J
74 * This is actually composed of two sequences:
78 * Effect: moves the cursor to upper left corner
80 * ED2 (Clear entire screen)
82 * Effect: clear the whole screen
84 * == For highlighting control characters, we also use the following two ==
87 * Effect: Uses some standout mode such as reverse video
91 * Effect: Exit standout mode
93 * == Only used if TIOCGWINSZ fails ==
94 * DSR/CPR (Report cursor position)
96 * Effect: reports current cursor position as ESC [ NNN ; MMM R
100 * If __MINGW32__ is defined, the win32 console API is used.
101 * This could probably be made to work for the msvc compiler too.
102 * This support based in part on work by Jon Griffiths.
105 #ifdef _WIN32 /* Windows platform, either MinGW or Visual Studio (MSVC) */
108 #define USE_WINCONSOLE
110 #define HAVE_UNISTD_H
112 /* Microsoft headers don't like old POSIX names */
113 #define strdup _strdup
114 #define snprintf _snprintf
118 #include <sys/ioctl.h>
119 #include <sys/poll.h>
121 #define HAVE_UNISTD_H
133 #include <sys/types.h>
135 #include "linenoise.h"
138 #define LINENOISE_DEFAULT_HISTORY_MAX_LEN 100
139 #define LINENOISE_MAX_LINE 4096
141 #define ctrl(C) ((C) - '@')
143 /* Use -ve numbers here to co-exist with normal unicode chars */
150 SPECIAL_DELETE
= -24,
153 SPECIAL_INSERT
= -27,
154 SPECIAL_PAGE_UP
= -28,
155 SPECIAL_PAGE_DOWN
= -29
158 static int history_max_len
= LINENOISE_DEFAULT_HISTORY_MAX_LEN
;
159 static int history_len
= 0;
160 static char **history
= NULL
;
162 /* Structure to contain the status of the current (being edited) line */
164 char *buf
; /* Current buffer. Always null terminated */
165 int bufmax
; /* Size of the buffer, including space for the null termination */
166 int len
; /* Number of bytes in 'buf' */
167 int chars
; /* Number of chars in 'buf' (utf-8 chars) */
168 int pos
; /* Cursor position, measured in chars */
169 int cols
; /* Size of the window, in chars */
171 char *capture
; /* Allocated capture buffer, or NULL for none. Always null terminated */
172 #if defined(USE_TERMIOS)
173 int fd
; /* Terminal fd */
174 #elif defined(USE_WINCONSOLE)
175 HANDLE outh
; /* Console output handle */
176 HANDLE inh
; /* Console input handle */
177 int rows
; /* Screen rows */
178 int x
; /* Current column during output */
179 int y
; /* Current row */
183 static int fd_read(struct current
*current
);
184 static int getWindowSize(struct current
*current
);
186 void linenoiseHistoryFree(void) {
190 for (j
= 0; j
< history_len
; j
++)
198 #if defined(USE_TERMIOS)
199 static void linenoiseAtExit(void);
200 static struct termios orig_termios
; /* in order to restore at exit */
201 static int rawmode
= 0; /* for atexit() function to check if restore is needed*/
202 static int atexit_registered
= 0; /* register atexit just 1 time */
204 static const char *unsupported_term
[] = {"dumb","cons25",NULL
};
206 static int isUnsupportedTerm(void) {
207 char *term
= getenv("TERM");
211 for (j
= 0; unsupported_term
[j
]; j
++) {
212 if (strcmp(term
, unsupported_term
[j
]) == 0) {
220 static int enableRawMode(struct current
*current
) {
223 current
->fd
= STDIN_FILENO
;
226 if (!isatty(current
->fd
) || isUnsupportedTerm() ||
227 tcgetattr(current
->fd
, &orig_termios
) == -1) {
233 if (!atexit_registered
) {
234 atexit(linenoiseAtExit
);
235 atexit_registered
= 1;
238 raw
= orig_termios
; /* modify the original mode */
239 /* input modes: no break, no CR to NL, no parity check, no strip char,
240 * no start/stop output control. */
241 raw
.c_iflag
&= ~(BRKINT
| ICRNL
| INPCK
| ISTRIP
| IXON
);
242 /* output modes - actually, no need to disable post processing */
243 /*raw.c_oflag &= ~(OPOST);*/
244 /* control modes - set 8 bit chars */
245 raw
.c_cflag
|= (CS8
);
246 /* local modes - choing off, canonical off, no extended functions,
247 * no signal chars (^Z,^C) */
248 raw
.c_lflag
&= ~(ECHO
| ICANON
| IEXTEN
| ISIG
);
249 /* control chars - set return condition: min number of bytes and timer.
250 * We want read to return every single byte, without timeout. */
251 raw
.c_cc
[VMIN
] = 1; raw
.c_cc
[VTIME
] = 0; /* 1 byte, no timer */
253 /* put terminal in raw mode after flushing */
254 if (tcsetattr(current
->fd
,TCSADRAIN
,&raw
) < 0) {
261 static void disableRawMode(struct current
*current
) {
262 /* Don't even check the return value as it's too late. */
263 if (rawmode
&& tcsetattr(current
->fd
,TCSADRAIN
,&orig_termios
) != -1)
267 /* At exit we'll try to fix the terminal to the initial conditions. */
268 static void linenoiseAtExit(void) {
270 tcsetattr(STDIN_FILENO
, TCSADRAIN
, &orig_termios
);
272 linenoiseHistoryFree();
275 /* gcc/glibc insists that we care about the return code of write!
276 * Clarification: This means that a void-cast like "(void) (EXPR)"
279 #define IGNORE_RC(EXPR) if (EXPR) {}
281 /* This is fdprintf() on some systems, but use a different
282 * name to avoid conflicts
284 static void fd_printf(int fd
, const char *format
, ...)
290 va_start(args
, format
);
291 n
= vsnprintf(buf
, sizeof(buf
), format
, args
);
293 IGNORE_RC(write(fd
, buf
, n
));
296 void linenoiseClearScreen(void)
298 fd_printf(STDOUT_FILENO
, "\x1b[H\x1b[2J");
301 static void cursorToLeft(struct current
*current
)
303 fd_printf(current
->fd
, "\r");
306 static int outputChars(struct current
*current
, const char *buf
, int len
)
308 return write(current
->fd
, buf
, len
);
311 static void outputControlChar(struct current
*current
, char ch
)
313 fd_printf(current
->fd
, "\x1b[7m^%c\x1b[0m", ch
);
316 static void eraseEol(struct current
*current
)
318 fd_printf(current
->fd
, "\x1b[0K");
321 static void setCursorPos(struct current
*current
, int x
)
324 cursorToLeft(current
);
327 fd_printf(current
->fd
, "\r\x1b[%dC", x
);
332 * Reads a char from 'fd', waiting at most 'timeout' milliseconds.
334 * A timeout of -1 means to wait forever.
336 * Returns -1 if no char is received within the time or an error occurs.
338 static int fd_read_char(int fd
, int timeout
)
346 if (poll(&p
, 1, timeout
) == 0) {
350 if (read(fd
, &c
, 1) != 1) {
357 * Reads a complete utf-8 character
358 * and returns the unicode value, or -1 on error.
360 static int fd_read(struct current
*current
)
368 if (read(current
->fd
, &buf
[0], 1) != 1) {
371 n
= utf8_charlen(buf
[0]);
372 if (n
< 1 || n
> 3) {
375 for (i
= 1; i
< n
; i
++) {
376 if (read(current
->fd
, &buf
[i
], 1) != 1) {
381 /* decode and return the character */
382 utf8_tounicode(buf
, &c
);
385 return fd_read_char(current
->fd
, -1);
389 static int countColorControlChars(const char* prompt
)
391 /* ANSI color control sequences have the form:
392 * "\x1b" "[" [0-9;]* "m"
393 * We parse them with a simple state machine.
400 } state
= search_esc
;
401 int len
= 0, found
= 0;
404 /* XXX: Strictly we should be checking utf8 chars rather than
405 * bytes in case of the extremely unlikely scenario where
406 * an ANSI sequence is part of a utf8 sequence.
408 while ((ch
= *prompt
++) != 0) {
412 state
= expect_bracket
;
417 state
= expect_trail
;
418 /* 3 for "\e[ ... m" */
425 if ((ch
== ';') || ((ch
>= '0' && ch
<= '9'))) {
426 /* 0-9, or semicolon */
442 * Stores the current cursor column in '*cols'.
443 * Returns 1 if OK, or 0 if failed to determine cursor pos.
445 static int queryCursor(int fd
, int* cols
)
447 /* control sequence - report cursor location */
448 fd_printf(fd
, "\x1b[6n");
450 /* Parse the response: ESC [ rows ; cols R */
451 if (fd_read_char(fd
, 100) == 0x1b &&
452 fd_read_char(fd
, 100) == '[') {
456 int ch
= fd_read_char(fd
, 100);
461 else if (ch
== 'R') {
463 if (n
!= 0 && n
< 1000) {
468 else if (ch
>= 0 && ch
<= '9') {
469 n
= n
* 10 + ch
- '0';
482 * Updates current->cols with the current window size (width)
484 static int getWindowSize(struct current
*current
)
488 if (ioctl(STDOUT_FILENO
, TIOCGWINSZ
, &ws
) == 0 && ws
.ws_col
!= 0) {
489 current
->cols
= ws
.ws_col
;
493 /* Failed to query the window size. Perhaps we are on a serial terminal.
494 * Try to query the width by sending the cursor as far to the right
495 * and reading back the cursor position.
496 * Note that this is only done once per call to linenoise rather than
497 * every time the line is refreshed for efficiency reasons.
499 * In more detail, we:
500 * (a) request current cursor position,
501 * (b) move cursor far right,
502 * (c) request cursor position again,
503 * (d) at last move back to the old position.
504 * This gives us the width without messing with the externally
505 * visible cursor position.
508 if (current
->cols
== 0) {
514 if (queryCursor (current
->fd
, &here
)) {
516 fd_printf(current
->fd
, "\x1b[999C");
518 /* (c). Note: If (a) succeeded, then (c) should as well.
519 * For paranoia we still check and have a fallback action
520 * for (d) in case of failure..
522 if (!queryCursor (current
->fd
, ¤t
->cols
)) {
523 /* (d') Unable to get accurate position data, reset
524 * the cursor to the far left. While this may not
525 * restore the exact original position it should not
528 fd_printf(current
->fd
, "\r");
530 /* (d) Reset the cursor back to the original location. */
531 if (current
->cols
> here
) {
532 fd_printf(current
->fd
, "\x1b[%dD", current
->cols
- here
);
535 } /* 1st query failed, doing nothing => default 80 */
542 * If escape (27) was received, reads subsequent
543 * chars to determine if this is a known special key.
545 * Returns SPECIAL_NONE if unrecognised, or -1 if EOF.
547 * If no additional char is received within a short time,
550 static int check_special(int fd
)
552 int c
= fd_read_char(fd
, 50);
559 c2
= fd_read_char(fd
, 50);
563 if (c
== '[' || c
== 'O') {
564 /* Potential arrow key */
571 return SPECIAL_RIGHT
;
580 if (c
== '[' && c2
>= '1' && c2
<= '8') {
581 /* extended escape */
582 c
= fd_read_char(fd
, 50);
586 return SPECIAL_INSERT
;
588 return SPECIAL_DELETE
;
590 return SPECIAL_PAGE_UP
;
592 return SPECIAL_PAGE_DOWN
;
599 while (c
!= -1 && c
!= '~') {
600 /* .e.g \e[12~ or '\e[11;2~ discard the complete sequence */
601 c
= fd_read_char(fd
, 50);
607 #elif defined(USE_WINCONSOLE)
609 static DWORD orig_consolemode
= 0;
611 static int enableRawMode(struct current
*current
) {
615 current
->outh
= GetStdHandle(STD_OUTPUT_HANDLE
);
616 current
->inh
= GetStdHandle(STD_INPUT_HANDLE
);
618 if (!PeekConsoleInput(current
->inh
, &irec
, 1, &n
)) {
621 if (getWindowSize(current
) != 0) {
624 if (GetConsoleMode(current
->inh
, &orig_consolemode
)) {
625 SetConsoleMode(current
->inh
, ENABLE_PROCESSED_INPUT
);
630 static void disableRawMode(struct current
*current
)
632 SetConsoleMode(current
->inh
, orig_consolemode
);
635 void linenoiseClearScreen(void)
637 /* XXX: This is ugly. Should just have the caller pass a handle */
638 struct current current
;
640 current
.outh
= GetStdHandle(STD_OUTPUT_HANDLE
);
642 if (getWindowSize(¤t
) == 0) {
643 COORD topleft
= { 0, 0 };
646 FillConsoleOutputCharacter(current
.outh
, ' ',
647 current
.cols
* current
.rows
, topleft
, &n
);
648 FillConsoleOutputAttribute(current
.outh
,
649 FOREGROUND_RED
| FOREGROUND_BLUE
| FOREGROUND_GREEN
,
650 current
.cols
* current
.rows
, topleft
, &n
);
651 SetConsoleCursorPosition(current
.outh
, topleft
);
655 static void cursorToLeft(struct current
*current
)
661 pos
.Y
= (SHORT
)current
->y
;
663 FillConsoleOutputAttribute(current
->outh
,
664 FOREGROUND_RED
| FOREGROUND_BLUE
| FOREGROUND_GREEN
, current
->cols
, pos
, &n
);
668 static int outputChars(struct current
*current
, const char *buf
, int len
)
673 pos
.Y
= (SHORT
)current
->y
;
680 s
= utf8_tounicode(buf
, &c
);
687 pos
.X
= (SHORT
)current
->x
;
689 /* fixed display utf8 character */
690 WriteConsoleOutputCharacterW(current
->outh
, &wc
, 1, pos
, &n
);
692 current
->x
+= utf8_width(c
);
695 pos
.X
= (SHORT
)current
->x
;
697 WriteConsoleOutputCharacterA(current
->outh
, buf
, len
, pos
, &n
);
704 static void outputControlChar(struct current
*current
, char ch
)
709 pos
.X
= (SHORT
) current
->x
;
710 pos
.Y
= (SHORT
) current
->y
;
712 FillConsoleOutputAttribute(current
->outh
, BACKGROUND_INTENSITY
, 2, pos
, &n
);
713 outputChars(current
, "^", 1);
714 outputChars(current
, &ch
, 1);
717 static void eraseEol(struct current
*current
)
722 pos
.X
= (SHORT
) current
->x
;
723 pos
.Y
= (SHORT
) current
->y
;
725 FillConsoleOutputCharacter(current
->outh
, ' ', current
->cols
- current
->x
, pos
, &n
);
728 static void setCursorPos(struct current
*current
, int x
)
733 pos
.Y
= (SHORT
) current
->y
;
735 SetConsoleCursorPosition(current
->outh
, pos
);
739 static int fd_read(struct current
*current
)
744 if (WaitForSingleObject(current
->inh
, INFINITE
) != WAIT_OBJECT_0
) {
747 if (!ReadConsoleInput (current
->inh
, &irec
, 1, &n
)) {
750 if (irec
.EventType
== KEY_EVENT
&& irec
.Event
.KeyEvent
.bKeyDown
) {
751 KEY_EVENT_RECORD
*k
= &irec
.Event
.KeyEvent
;
752 if (k
->dwControlKeyState
& ENHANCED_KEY
) {
753 switch (k
->wVirtualKeyCode
) {
757 return SPECIAL_RIGHT
;
763 return SPECIAL_INSERT
;
765 return SPECIAL_DELETE
;
771 return SPECIAL_PAGE_UP
;
773 return SPECIAL_PAGE_DOWN
;
776 /* Note that control characters are already translated in AsciiChar */
777 else if (k
->wVirtualKeyCode
== VK_CONTROL
)
781 return k
->uChar
.UnicodeChar
;
783 return k
->uChar
.AsciiChar
;
791 static int countColorControlChars(const char* prompt
)
793 /* For windows we assume that there are no embedded ansi color
799 static int getWindowSize(struct current
*current
)
801 CONSOLE_SCREEN_BUFFER_INFO info
;
802 if (!GetConsoleScreenBufferInfo(current
->outh
, &info
)) {
805 current
->cols
= info
.dwSize
.X
;
806 current
->rows
= info
.dwSize
.Y
;
807 if (current
->cols
<= 0 || current
->rows
<= 0) {
811 current
->y
= info
.dwCursorPosition
.Y
;
812 current
->x
= info
.dwCursorPosition
.X
;
817 #ifndef utf8_getchars
818 static int utf8_getchars(char *buf
, int c
)
821 return utf8_fromunicode(buf
, c
);
830 * Returns the unicode character at the given offset,
833 static int get_char(struct current
*current
, int pos
)
835 if (pos
>= 0 && pos
< current
->chars
) {
837 int i
= utf8_index(current
->buf
, pos
);
838 (void)utf8_tounicode(current
->buf
+ i
, &c
);
844 static void refreshLine(const char *prompt
, struct current
*current
)
850 const char *buf
= current
->buf
;
851 int chars
= current
->chars
;
852 int pos
= current
->pos
;
859 /* Should intercept SIGWINCH. For now, just get the size every time */
860 getWindowSize(current
);
862 plen
= strlen(prompt
);
863 pchars
= utf8_strwidth(prompt
, utf8_strlen(prompt
, plen
));
865 /* Scan the prompt for embedded ansi color control sequences and
866 * discount them as characters/columns.
868 pchars
-= countColorControlChars(prompt
);
870 /* Account for a line which is too long to fit in the window.
871 * Note that control chars require an extra column
874 /* How many cols are required to the left of 'pos'?
875 * The prompt, plus one extra for each control char
877 n
= pchars
+ utf8_strwidth(buf
, utf8_strlen(buf
, current
->len
));
879 for (i
= 0; i
< pos
; i
++) {
880 b
+= utf8_tounicode(buf
+ b
, &ch
);
886 /* Pluse one if the current char is a control character */
887 if (current
->pos
< current
->chars
&& get_char(current
, current
->pos
) < ' ') {
891 /* If too many are needed, strip chars off the front of 'buf'
892 * until it fits. Note that if the current char is a control character,
893 * we need one extra col.
895 while (n
>= current
->cols
&& pos
> 0) {
896 b
= utf8_tounicode(buf
, &ch
);
906 /* Cursor to left edge, then the prompt */
907 cursorToLeft(current
);
908 outputChars(current
, prompt
, plen
);
910 /* Now the current buffer content */
912 /* Need special handling for control characters.
913 * If we hit 'cols', stop.
915 b
= 0; /* unwritted bytes */
916 n
= 0; /* How many control chars were written */
917 width
= 0; /* current display width */
918 bufwidth
= utf8_strwidth(buf
, pos
);
920 for (i
= 0; i
< chars
; i
++) {
922 int w
= utf8_tounicode(buf
+ b
, &ch
);
927 width
+= utf8_width(ch
);
929 if (pchars
+ width
+ n
>= current
->cols
) {
933 /* A control character, so write the buffer so far */
934 outputChars(current
, buf
, b
);
937 outputControlChar(current
, ch
+ '@');
946 outputChars(current
, buf
, b
);
948 /* Erase to right, move cursor to original position */
950 setCursorPos(current
, bufwidth
+ pchars
+ backup
);
953 static void set_current(struct current
*current
, const char *str
)
955 strncpy(current
->buf
, str
, current
->bufmax
);
956 current
->buf
[current
->bufmax
- 1] = 0;
957 current
->len
= strlen(current
->buf
);
958 current
->pos
= current
->chars
= utf8_strlen(current
->buf
, current
->len
);
961 static int has_room(struct current
*current
, int bytes
)
963 return current
->len
+ bytes
< current
->bufmax
- 1;
967 * Removes the char at 'pos'.
969 * Returns 1 if the line needs to be refreshed, 2 if not
970 * and 0 if nothing was removed
972 static int remove_char(struct current
*current
, int pos
)
974 if (pos
>= 0 && pos
< current
->chars
) {
977 p1
= utf8_index(current
->buf
, pos
);
978 p2
= p1
+ utf8_index(current
->buf
+ p1
, 1);
981 /* optimise remove char in the case of removing the last char */
982 if (current
->pos
== pos
+ 1 && current
->pos
== current
->chars
) {
983 if (current
->buf
[pos
] >= ' ' && utf8_strlen(current
->prompt
, -1) + utf8_strlen(current
->buf
, current
->len
) < current
->cols
- 1) {
985 fd_printf(current
->fd
, "\b \b");
990 /* Move the null char too */
991 memmove(current
->buf
+ p1
, current
->buf
+ p2
, current
->len
- p2
+ 1);
992 current
->len
-= (p2
- p1
);
995 if (current
->pos
> pos
) {
1004 * Insert 'ch' at position 'pos'
1006 * Returns 1 if the line needs to be refreshed, 2 if not
1007 * and 0 if nothing was inserted (no room)
1009 static int insert_char(struct current
*current
, int pos
, int ch
)
1012 int n
= utf8_getchars(buf
, ch
);
1014 if (has_room(current
, n
) && pos
>= 0 && pos
<= current
->chars
) {
1017 p1
= utf8_index(current
->buf
, pos
);
1021 /* optimise the case where adding a single char to the end and no scrolling is needed */
1022 if (current
->pos
== pos
&& current
->chars
== pos
) {
1023 if (ch
>= ' ' && utf8_strlen(current
->prompt
, -1) + utf8_strlen(current
->buf
, current
->len
) < current
->cols
- 1) {
1024 IGNORE_RC(write(current
->fd
, buf
, n
));
1030 memmove(current
->buf
+ p2
, current
->buf
+ p1
, current
->len
- p1
);
1031 memcpy(current
->buf
+ p1
, buf
, n
);
1035 if (current
->pos
>= pos
) {
1044 * Captures up to 'n' characters starting at 'pos' for the cut buffer.
1046 * This replaces any existing characters in the cut buffer.
1048 static void capture_chars(struct current
*current
, int pos
, int n
)
1050 if (pos
>= 0 && (pos
+ n
- 1) < current
->chars
) {
1051 int p1
= utf8_index(current
->buf
, pos
);
1052 int nbytes
= utf8_index(current
->buf
+ p1
, n
);
1055 free(current
->capture
);
1056 /* Include space for the null terminator */
1057 current
->capture
= (char *)malloc(nbytes
+ 1);
1058 memcpy(current
->capture
, current
->buf
+ p1
, nbytes
);
1059 current
->capture
[nbytes
] = '\0';
1065 * Removes up to 'n' characters at cursor position 'pos'.
1067 * Returns 0 if no chars were removed or non-zero otherwise.
1069 static int remove_chars(struct current
*current
, int pos
, int n
)
1073 /* First save any chars which will be removed */
1074 capture_chars(current
, pos
, n
);
1076 while (n
-- && remove_char(current
, pos
)) {
1082 * Inserts the characters (string) 'chars' at the cursor position 'pos'.
1084 * Returns 0 if no chars were inserted or non-zero otherwise.
1086 static int insert_chars(struct current
*current
, int pos
, const char *chars
)
1092 int n
= utf8_tounicode(chars
, &ch
);
1093 if (insert_char(current
, pos
, ch
) == 0) {
1103 #ifndef NO_COMPLETION
1104 static linenoiseCompletionCallback
*completionCallback
= NULL
;
1105 static void *completionUserdata
= NULL
;
1107 static void beep() {
1109 fprintf(stderr
, "\x7");
1114 static void freeCompletions(linenoiseCompletions
*lc
) {
1116 for (i
= 0; i
< lc
->len
; i
++)
1121 static int completeLine(struct current
*current
) {
1122 linenoiseCompletions lc
= { 0, NULL
};
1125 completionCallback(current
->buf
,&lc
,completionUserdata
);
1129 size_t stop
= 0, i
= 0;
1132 /* Show completion or original buffer */
1134 struct current tmp
= *current
;
1135 tmp
.buf
= lc
.cvec
[i
];
1136 tmp
.pos
= tmp
.len
= strlen(tmp
.buf
);
1137 tmp
.chars
= utf8_strlen(tmp
.buf
, tmp
.len
);
1138 refreshLine(current
->prompt
, &tmp
);
1140 refreshLine(current
->prompt
, current
);
1143 c
= fd_read(current
);
1149 case '\t': /* tab */
1150 i
= (i
+1) % (lc
.len
+1);
1151 if (i
== lc
.len
) beep();
1153 case 27: /* escape */
1154 /* Re-show original buffer */
1156 refreshLine(current
->prompt
, current
);
1161 /* Update buffer and return */
1163 set_current(current
,lc
.cvec
[i
]);
1171 freeCompletions(&lc
);
1172 return c
; /* Return last read character */
1175 /* Register a callback function to be called for tab-completion.
1176 Returns the prior callback so that the caller may (if needed)
1177 restore it when done. */
1178 linenoiseCompletionCallback
* linenoiseSetCompletionCallback(linenoiseCompletionCallback
*fn
, void *userdata
) {
1179 linenoiseCompletionCallback
* old
= completionCallback
;
1180 completionCallback
= fn
;
1181 completionUserdata
= userdata
;
1185 void linenoiseAddCompletion(linenoiseCompletions
*lc
, const char *str
) {
1186 lc
->cvec
= (char **)realloc(lc
->cvec
,sizeof(char*)*(lc
->len
+1));
1187 lc
->cvec
[lc
->len
++] = strdup(str
);
1192 static int linenoiseEdit(struct current
*current
) {
1193 int history_index
= 0;
1195 /* The latest history entry is always our current buffer, that
1196 * initially is just an empty string. */
1197 linenoiseHistoryAdd("");
1199 set_current(current
, "");
1200 refreshLine(current
->prompt
, current
);
1204 int c
= fd_read(current
);
1206 #ifndef NO_COMPLETION
1207 /* Only autocomplete when the callback is set. It returns < 0 when
1208 * there was an error reading from fd. Otherwise it will return the
1209 * character that should be handled next. */
1210 if (c
== '\t' && current
->pos
== current
->chars
&& completionCallback
!= NULL
) {
1211 c
= completeLine(current
);
1212 /* Return on errors */
1213 if (c
< 0) return current
->len
;
1214 /* Read next character when 0 */
1215 if (c
== 0) continue;
1220 if (c
== -1) return current
->len
;
1222 if (c
== 27) { /* escape sequence */
1223 c
= check_special(current
->fd
);
1227 case '\r': /* enter */
1229 free(history
[history_len
]);
1230 return current
->len
;
1231 case ctrl('C'): /* ctrl-c */
1234 case 127: /* backspace */
1236 if (remove_char(current
, current
->pos
- 1) == 1) {
1237 refreshLine(current
->prompt
, current
);
1240 case ctrl('D'): /* ctrl-d */
1241 if (current
->len
== 0) {
1242 /* Empty line, so EOF */
1244 free(history
[history_len
]);
1247 /* Otherwise fall through to delete char to right of cursor */
1248 case SPECIAL_DELETE
:
1249 if (remove_char(current
, current
->pos
) == 1) {
1250 refreshLine(current
->prompt
, current
);
1253 case SPECIAL_INSERT
:
1254 /* Ignore. Expansion Hook.
1255 * Future possibility: Toggle Insert/Overwrite Modes
1258 case ctrl('W'): /* ctrl-w, delete word at left. save deleted chars */
1259 /* eat any spaces on the left */
1261 int pos
= current
->pos
;
1262 while (pos
> 0 && get_char(current
, pos
- 1) == ' ') {
1266 /* now eat any non-spaces on the left */
1267 while (pos
> 0 && get_char(current
, pos
- 1) != ' ') {
1271 if (remove_chars(current
, pos
, current
->pos
- pos
)) {
1272 refreshLine(current
->prompt
, current
);
1276 case ctrl('R'): /* ctrl-r */
1278 /* Display the reverse-i-search prompt and process chars */
1283 int searchpos
= history_len
- 1;
1288 const char *p
= NULL
;
1292 snprintf(rprompt
, sizeof(rprompt
), "(reverse-i-search)'%s': ", rbuf
);
1293 refreshLine(rprompt
, current
);
1294 c
= fd_read(current
);
1295 if (c
== ctrl('H') || c
== 127) {
1297 int p
= utf8_index(rbuf
, --rchars
);
1299 rlen
= strlen(rbuf
);
1305 c
= check_special(current
->fd
);
1308 if (c
== ctrl('P') || c
== SPECIAL_UP
) {
1309 /* Search for the previous (earlier) match */
1310 if (searchpos
> 0) {
1315 else if (c
== ctrl('N') || c
== SPECIAL_DOWN
) {
1316 /* Search for the next (later) match */
1317 if (searchpos
< history_len
) {
1323 else if (c
>= ' ') {
1324 if (rlen
>= (int)sizeof(rbuf
) + 3) {
1328 n
= utf8_getchars(rbuf
+ rlen
, c
);
1333 /* Adding a new char resets the search location */
1334 searchpos
= history_len
- 1;
1337 /* Exit from incremental search mode */
1341 /* Now search through the history for a match */
1342 for (; searchpos
>= 0 && searchpos
< history_len
; searchpos
+= searchdir
) {
1343 p
= strstr(history
[searchpos
], rbuf
);
1346 if (skipsame
&& strcmp(history
[searchpos
], current
->buf
) == 0) {
1347 /* But it is identical, so skip it */
1350 /* Copy the matching line and set the cursor position */
1351 set_current(current
,history
[searchpos
]);
1352 current
->pos
= utf8_strlen(history
[searchpos
], p
- history
[searchpos
]);
1357 /* No match, so don't add it */
1363 if (c
== ctrl('G') || c
== ctrl('C')) {
1364 /* ctrl-g terminates the search with no effect */
1365 set_current(current
, "");
1368 else if (c
== ctrl('J')) {
1369 /* ctrl-j terminates the search leaving the buffer in place */
1372 /* Go process the char normally */
1373 refreshLine(current
->prompt
, current
);
1377 case ctrl('T'): /* ctrl-t */
1378 if (current
->pos
> 0 && current
->pos
<= current
->chars
) {
1379 /* If cursor is at end, transpose the previous two chars */
1380 int fixer
= (current
->pos
== current
->chars
);
1381 c
= get_char(current
, current
->pos
- fixer
);
1382 remove_char(current
, current
->pos
- fixer
);
1383 insert_char(current
, current
->pos
- 1, c
);
1384 refreshLine(current
->prompt
, current
);
1387 case ctrl('V'): /* ctrl-v */
1388 if (has_room(current
, 3)) {
1389 /* Insert the ^V first */
1390 if (insert_char(current
, current
->pos
, c
)) {
1391 refreshLine(current
->prompt
, current
);
1392 /* Now wait for the next char. Can insert anything except \0 */
1393 c
= fd_read(current
);
1395 /* Remove the ^V first */
1396 remove_char(current
, current
->pos
- 1);
1398 /* Insert the actual char */
1399 insert_char(current
, current
->pos
, c
);
1401 refreshLine(current
->prompt
, current
);
1407 if (current
->pos
> 0) {
1409 refreshLine(current
->prompt
, current
);
1414 if (current
->pos
< current
->chars
) {
1416 refreshLine(current
->prompt
, current
);
1419 case SPECIAL_PAGE_UP
:
1420 dir
= history_len
- history_index
- 1; /* move to start of history */
1421 goto history_navigation
;
1422 case SPECIAL_PAGE_DOWN
:
1423 dir
= -history_index
; /* move to 0 == end of history, i.e. current */
1424 goto history_navigation
;
1428 goto history_navigation
;
1432 if (history_len
> 1) {
1433 /* Update the current history entry before to
1434 * overwrite it with tne next one. */
1435 free(history
[history_len
- 1 - history_index
]);
1436 history
[history_len
- 1 - history_index
] = strdup(current
->buf
);
1437 /* Show the new entry */
1438 history_index
+= dir
;
1439 if (history_index
< 0) {
1442 } else if (history_index
>= history_len
) {
1443 history_index
= history_len
- 1;
1446 set_current(current
, history
[history_len
- 1 - history_index
]);
1447 refreshLine(current
->prompt
, current
);
1450 case ctrl('A'): /* Ctrl+a, go to the start of the line */
1453 refreshLine(current
->prompt
, current
);
1455 case ctrl('E'): /* ctrl+e, go to the end of the line */
1457 current
->pos
= current
->chars
;
1458 refreshLine(current
->prompt
, current
);
1460 case ctrl('U'): /* Ctrl+u, delete to beginning of line, save deleted chars. */
1461 if (remove_chars(current
, 0, current
->pos
)) {
1462 refreshLine(current
->prompt
, current
);
1465 case ctrl('K'): /* Ctrl+k, delete from current to end of line, save deleted chars. */
1466 if (remove_chars(current
, current
->pos
, current
->chars
- current
->pos
)) {
1467 refreshLine(current
->prompt
, current
);
1470 case ctrl('Y'): /* Ctrl+y, insert saved chars at current position */
1471 if (current
->capture
&& insert_chars(current
, current
->pos
, current
->capture
)) {
1472 refreshLine(current
->prompt
, current
);
1475 case ctrl('L'): /* Ctrl+L, clear screen */
1476 linenoiseClearScreen();
1477 /* Force recalc of window size for serial terminals */
1479 refreshLine(current
->prompt
, current
);
1482 /* Only tab is allowed without ^V */
1483 if (c
== '\t' || c
>= ' ') {
1484 if (insert_char(current
, current
->pos
, c
) == 1) {
1485 refreshLine(current
->prompt
, current
);
1491 return current
->len
;
1494 int linenoiseColumns(void)
1496 struct current current
;
1497 enableRawMode (¤t
);
1498 getWindowSize (¤t
);
1499 disableRawMode (¤t
);
1500 return current
.cols
;
1503 char *linenoise(const char *prompt
)
1506 struct current current
;
1507 char buf
[LINENOISE_MAX_LINE
];
1509 if (enableRawMode(¤t
) == -1) {
1510 printf("%s", prompt
);
1512 if (fgets(buf
, sizeof(buf
), stdin
) == NULL
) {
1515 count
= strlen(buf
);
1516 if (count
&& buf
[count
-1] == '\n') {
1524 current
.bufmax
= sizeof(buf
);
1528 current
.prompt
= prompt
;
1529 current
.capture
= NULL
;
1531 count
= linenoiseEdit(¤t
);
1533 disableRawMode(¤t
);
1536 free(current
.capture
);
1544 /* Using a circular buffer is smarter, but a bit more complex to handle. */
1545 int linenoiseHistoryAdd(const char *line
) {
1548 if (history_max_len
== 0) return 0;
1549 if (history
== NULL
) {
1550 history
= (char **)malloc(sizeof(char*)*history_max_len
);
1551 if (history
== NULL
) return 0;
1552 memset(history
,0,(sizeof(char*)*history_max_len
));
1555 /* do not insert duplicate lines into history */
1556 if (history_len
> 0 && strcmp(line
, history
[history_len
- 1]) == 0) {
1560 linecopy
= strdup(line
);
1561 if (!linecopy
) return 0;
1562 if (history_len
== history_max_len
) {
1564 memmove(history
,history
+1,sizeof(char*)*(history_max_len
-1));
1567 history
[history_len
] = linecopy
;
1572 int linenoiseHistoryGetMaxLen(void) {
1573 return history_max_len
;
1576 int linenoiseHistorySetMaxLen(int len
) {
1579 if (len
< 1) return 0;
1581 int tocopy
= history_len
;
1583 newHistory
= (char **)malloc(sizeof(char*)*len
);
1584 if (newHistory
== NULL
) return 0;
1586 /* If we can't copy everything, free the elements we'll not use. */
1590 for (j
= 0; j
< tocopy
-len
; j
++) free(history
[j
]);
1593 memset(newHistory
,0,sizeof(char*)*len
);
1594 memcpy(newHistory
,history
+(history_len
-tocopy
), sizeof(char*)*tocopy
);
1596 history
= newHistory
;
1598 history_max_len
= len
;
1599 if (history_len
> history_max_len
)
1600 history_len
= history_max_len
;
1604 /* Save the history in the specified file. On success 0 is returned
1605 * otherwise -1 is returned. */
1606 int linenoiseHistorySave(const char *filename
) {
1607 FILE *fp
= fopen(filename
,"w");
1610 if (fp
== NULL
) return -1;
1611 for (j
= 0; j
< history_len
; j
++) {
1612 const char *str
= history
[j
];
1613 /* Need to encode backslash, nl and cr */
1618 else if (*str
== '\n') {
1621 else if (*str
== '\r') {
1636 /* Load the history from the specified file. If the file does not exist
1637 * zero is returned and no operation is performed.
1639 * If the file exists and the operation succeeded 0 is returned, otherwise
1640 * on error -1 is returned. */
1641 int linenoiseHistoryLoad(const char *filename
) {
1642 FILE *fp
= fopen(filename
,"r");
1643 char buf
[LINENOISE_MAX_LINE
];
1645 if (fp
== NULL
) return -1;
1647 while (fgets(buf
,LINENOISE_MAX_LINE
,fp
) != NULL
) {
1650 /* Decode backslash escaped values */
1651 for (src
= dest
= buf
; *src
; src
++) {
1659 else if (*src
== 'r') {
1667 /* Remove trailing newline */
1668 if (dest
!= buf
&& (dest
[-1] == '\n' || dest
[-1] == '\r')) {
1673 linenoiseHistoryAdd(buf
);
1679 /* Provide access to the history buffer.
1681 * If 'len' is not NULL, the length is stored in *len.
1683 char **linenoiseHistory(int *len
) {