4 /* (c) 2017 Workware Systems Pty Ltd -- All Rights Reserved */
11 * A stringbuf is a resizing, null terminated string buffer.
13 * The buffer is reallocated as necessary.
15 * In general it is *not* OK to call these functions with a NULL pointer
16 * unless stated otherwise.
18 * If USE_UTF8 is defined, supports utf8.
22 * The stringbuf structure should not be accessed directly.
23 * Use the functions below.
26 int remaining
; /**< Allocated, but unused space */
27 int last
; /**< Index of the null terminator (and thus the length of the string) */
29 int chars
; /**< Count of characters */
31 char *data
; /**< Allocated memory containing the string or NULL for empty */
35 * Allocates and returns a new stringbuf with no elements.
37 stringbuf
*sb_alloc(void);
41 * It is OK to call this with NULL.
43 void sb_free(stringbuf
*sb
);
46 * Returns an allocated copy of the stringbuf
48 stringbuf
*sb_copy(stringbuf
*sb
);
51 * Returns the length of the buffer.
53 * Returns 0 for both a NULL buffer and an empty buffer.
55 static inline int sb_len(stringbuf
*sb
) {
60 * Returns the utf8 character length of the buffer.
62 * Returns 0 for both a NULL buffer and an empty buffer.
64 static inline int sb_chars(stringbuf
*sb
) {
73 * Appends a null terminated string to the stringbuf
75 void sb_append(stringbuf
*sb
, const char *str
);
78 * Like sb_append() except does not require a null terminated string.
79 * The length of 'str' is given as 'len'
81 * Note that in utf8 mode, characters will *not* be counted correctly
82 * if a partial utf8 sequence is added with sb_append_len()
84 void sb_append_len(stringbuf
*sb
, const char *str
, int len
);
87 * Returns a pointer to the null terminated string in the buffer.
89 * Note this pointer only remains valid until the next modification to the
92 * The returned pointer can be used to update the buffer in-place
93 * as long as care is taken to not overwrite the end of the buffer.
95 static inline char *sb_str(const stringbuf
*sb
)
101 * Inserts the given string *before* (zero-based) 'index' in the stringbuf.
102 * If index is past the end of the buffer, the string is appended,
103 * just like sb_append()
105 void sb_insert(stringbuf
*sb
, int index
, const char *str
);
108 * Delete 'len' bytes in the string at the given index.
110 * Any bytes past the end of the buffer are ignored.
111 * The buffer remains null terminated.
113 * If len is -1, deletes to the end of the buffer.
115 void sb_delete(stringbuf
*sb
, int index
, int len
);
118 * Clear to an empty buffer.
120 void sb_clear(stringbuf
*sb
);
123 * Return an allocated copy of buffer and frees 'sb'.
125 * If 'sb' is empty, returns an allocated copy of "".
127 char *sb_to_string(stringbuf
*sb
);
141 #include "stringbuf.h"
147 #define SB_INCREMENT 200
149 stringbuf
*sb_alloc(void)
151 stringbuf
*sb
= (stringbuf
*)malloc(sizeof(*sb
));
162 void sb_free(stringbuf
*sb
)
170 void sb_realloc(stringbuf
*sb
, int newlen
)
172 sb
->data
= (char *)realloc(sb
->data
, newlen
);
173 sb
->remaining
= newlen
- sb
->last
;
176 void sb_append(stringbuf
*sb
, const char *str
)
178 sb_append_len(sb
, str
, strlen(str
));
181 void sb_append_len(stringbuf
*sb
, const char *str
, int len
)
183 if (sb
->remaining
< len
+ 1) {
184 sb_realloc(sb
, sb
->last
+ len
+ 1 + SB_INCREMENT
);
186 memcpy(sb
->data
+ sb
->last
, str
, len
);
187 sb
->data
[sb
->last
+ len
] = 0;
190 sb
->remaining
-= len
;
192 sb
->chars
+= utf8_strlen(str
, len
);
196 char *sb_to_string(stringbuf
*sb
)
198 if (sb
->data
== NULL
) {
199 /* Return an allocated empty string, not null */
203 /* Just return the data and free the stringbuf structure */
210 /* Insert and delete operations */
212 /* Moves up all the data at position 'pos' and beyond by 'len' bytes
213 * to make room for new data
215 * Note: Does *not* update sb->chars
217 static void sb_insert_space(stringbuf
*sb
, int pos
, int len
)
219 assert(pos
<= sb
->last
);
221 /* Make sure there is enough space */
222 if (sb
->remaining
< len
) {
223 sb_realloc(sb
, sb
->last
+ len
+ SB_INCREMENT
);
226 memmove(sb
->data
+ pos
+ len
, sb
->data
+ pos
, sb
->last
- pos
);
228 sb
->remaining
-= len
;
229 /* And null terminate */
230 sb
->data
[sb
->last
] = 0;
234 * Move down all the data from pos + len, effectively
235 * deleting the data at position 'pos' of length 'len'
237 static void sb_delete_space(stringbuf
*sb
, int pos
, int len
)
239 assert(pos
< sb
->last
);
240 assert(pos
+ len
<= sb
->last
);
243 sb
->chars
-= utf8_strlen(sb
->data
+ pos
, len
);
247 memmove(sb
->data
+ pos
, sb
->data
+ pos
+ len
, sb
->last
- pos
- len
);
249 sb
->remaining
+= len
;
250 /* And null terminate */
251 sb
->data
[sb
->last
] = 0;
254 void sb_insert(stringbuf
*sb
, int index
, const char *str
)
256 if (index
>= sb
->last
) {
257 /* Inserting after the end of the list appends. */
261 int len
= strlen(str
);
263 sb_insert_space(sb
, index
, len
);
264 memcpy(sb
->data
+ index
, str
, len
);
266 sb
->chars
+= utf8_strlen(str
, len
);
272 * Delete the bytes at index 'index' for length 'len'
273 * Has no effect if the index is past the end of the list.
275 void sb_delete(stringbuf
*sb
, int index
, int len
)
277 if (index
< sb
->last
) {
278 char *pos
= sb
->data
+ index
;
283 sb_delete_space(sb
, pos
- sb
->data
, len
);
287 void sb_clear(stringbuf
*sb
)
298 /* linenoise.c -- guerrilla line editing library against the idea that a
299 * line editing lib needs to be 20,000 lines of C code.
301 * You can find the latest source code at:
303 * http://github.com/msteveb/linenoise
304 * (forked from http://github.com/antirez/linenoise)
306 * Does a number of crazy assumptions that happen to be true in 99.9999% of
307 * the 2010 UNIX computers around.
309 * ------------------------------------------------------------------------
311 * Copyright (c) 2010, Salvatore Sanfilippo <antirez at gmail dot com>
312 * Copyright (c) 2010, Pieter Noordhuis <pcnoordhuis at gmail dot com>
313 * Copyright (c) 2011, Steve Bennett <steveb at workware dot net dot au>
315 * All rights reserved.
317 * Redistribution and use in source and binary forms, with or without
318 * modification, are permitted provided that the following conditions are
321 * * Redistributions of source code must retain the above copyright
322 * notice, this list of conditions and the following disclaimer.
324 * * Redistributions in binary form must reproduce the above copyright
325 * notice, this list of conditions and the following disclaimer in the
326 * documentation and/or other materials provided with the distribution.
328 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
329 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
330 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
331 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
332 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
333 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
334 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
335 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
336 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
337 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
338 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
340 * ------------------------------------------------------------------------
343 * - http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
344 * - http://www.3waylabs.com/nw/WWW/products/wizcon/vt220.html
351 * List of escape sequences used by this program, we do everything just
352 * a few sequences. In order to be so cheap we may have some
353 * flickering effect with some slow terminal, but the lesser sequences
354 * the more compatible.
357 * Sequence: ESC [ 0 K
358 * Effect: clear from cursor to end of line
360 * CUF (CUrsor Forward)
361 * Sequence: ESC [ n C
362 * Effect: moves cursor forward n chars
364 * CR (Carriage Return)
366 * Effect: moves cursor to column 1
368 * The following are used to clear the screen: ESC [ H ESC [ 2 J
369 * This is actually composed of two sequences:
373 * Effect: moves the cursor to upper left corner
375 * ED2 (Clear entire screen)
376 * Sequence: ESC [ 2 J
377 * Effect: clear the whole screen
379 * == For highlighting control characters, we also use the following two ==
380 * SO (enter StandOut)
381 * Sequence: ESC [ 7 m
382 * Effect: Uses some standout mode such as reverse video
385 * Sequence: ESC [ 0 m
386 * Effect: Exit standout mode
388 * == Only used if TIOCGWINSZ fails ==
389 * DSR/CPR (Report cursor position)
390 * Sequence: ESC [ 6 n
391 * Effect: reports current cursor position as ESC [ NNN ; MMM R
393 * == Only used in multiline mode ==
395 * Sequence: ESC [ n A
396 * Effect: moves cursor up n chars.
399 * Sequence: ESC [ n B
400 * Effect: moves cursor down n chars.
404 * If __MINGW32__ is defined, the win32 console API is used.
405 * This could probably be made to work for the msvc compiler too.
406 * This support based in part on work by Jon Griffiths.
409 #ifdef _WIN32 /* Windows platform, either MinGW or Visual Studio (MSVC) */
412 #define USE_WINCONSOLE
414 #define HAVE_UNISTD_H
416 /* Microsoft headers don't like old POSIX names */
417 #define strdup _strdup
418 #define snprintf _snprintf
422 #include <sys/ioctl.h>
425 #define HAVE_UNISTD_H
439 #include <sys/types.h>
441 #include "linenoise.h"
443 #include "stringbuf.h"
447 #define LINENOISE_DEFAULT_HISTORY_MAX_LEN 100
449 #define ctrl(C) ((C) - '@')
451 /* Use -ve numbers here to co-exist with normal unicode chars */
454 /* don't use -1 here since that indicates error */
459 SPECIAL_DELETE
= -24,
462 SPECIAL_INSERT
= -27,
463 SPECIAL_PAGE_UP
= -28,
464 SPECIAL_PAGE_DOWN
= -29,
466 /* Some handy names for other special keycodes */
471 static int history_max_len
= LINENOISE_DEFAULT_HISTORY_MAX_LEN
;
472 static int history_len
= 0;
473 static char **history
= NULL
;
475 /* Structure to contain the status of the current (being edited) line */
477 stringbuf
*buf
; /* Current buffer. Always null terminated */
478 int pos
; /* Cursor position, measured in chars */
479 int cols
; /* Size of the window, in chars */
480 int nrows
; /* How many rows are being used in multiline mode (>= 1) */
481 int rpos
; /* The current row containing the cursor - multiline mode only */
482 int colsright
; /* refreshLine() cached cols for insert_char() optimisation */
483 int colsleft
; /* refreshLine() cached cols for remove_char() optimisation */
485 stringbuf
*capture
; /* capture buffer, or NULL for none. Always null terminated */
486 stringbuf
*output
; /* used only during refreshLine() - output accumulator */
487 #if defined(USE_TERMIOS)
488 int fd
; /* Terminal fd */
489 #elif defined(USE_WINCONSOLE)
490 HANDLE outh
; /* Console output handle */
491 HANDLE inh
; /* Console input handle */
492 int rows
; /* Screen rows */
493 int x
; /* Current column during output */
494 int y
; /* Current row */
496 #define UBUF_MAX_CHARS 132
497 WORD ubuf
[UBUF_MAX_CHARS
+ 1]; /* Accumulates utf16 output - one extra for final surrogate pairs */
498 int ubuflen
; /* length used in ubuf */
499 int ubufcols
; /* how many columns are represented by the chars in ubuf? */
504 static int fd_read(struct current
*current
);
505 static int getWindowSize(struct current
*current
);
506 static void cursorDown(struct current
*current
, int n
);
507 static void cursorUp(struct current
*current
, int n
);
508 static void eraseEol(struct current
*current
);
509 static void refreshLine(struct current
*current
);
510 static void refreshLineAlt(struct current
*current
, const char *prompt
, const char *buf
, int cursor_pos
);
511 static void setCursorPos(struct current
*current
, int x
);
512 static void setOutputHighlight(struct current
*current
, const int *props
, int nprops
);
513 static void set_current(struct current
*current
, const char *str
);
515 void linenoiseHistoryFree(void) {
519 for (j
= 0; j
< history_len
; j
++)
529 EP_START
, /* looking for ESC */
530 EP_ESC
, /* looking for [ */
531 EP_DIGITS
, /* parsing digits */
532 EP_PROPS
, /* parsing digits or semicolons */
534 EP_ERROR
, /* error */
536 int props
[5]; /* properties are stored here */
537 int maxprops
; /* size of the props[] array */
538 int numprops
; /* number of properties found */
539 int termchar
; /* terminator char, or 0 for any alpha */
540 int current
; /* current (partial) property value */
544 * Initialise the escape sequence parser at *parser.
546 * If termchar is 0 any alpha char terminates ok. Otherwise only the given
547 * char terminates successfully.
548 * Run the parser state machine with calls to parseEscapeSequence() for each char.
550 static void initParseEscapeSeq(struct esc_parser
*parser
, int termchar
)
552 parser
->state
= EP_START
;
553 parser
->maxprops
= sizeof(parser
->props
) / sizeof(*parser
->props
);
554 parser
->numprops
= 0;
556 parser
->termchar
= termchar
;
560 * Pass character 'ch' into the state machine to parse:
561 * 'ESC' '[' <digits> (';' <digits>)* <termchar>
563 * The first character must be ESC.
564 * Returns the current state. The state machine is done when it returns either EP_END
567 * On EP_END, the "property/attribute" values can be read from parser->props[]
568 * of length parser->numprops.
570 static int parseEscapeSequence(struct esc_parser
*parser
, int ch
)
572 switch (parser
->state
) {
574 parser
->state
= (ch
== '\x1b') ? EP_ESC
: EP_ERROR
;
577 parser
->state
= (ch
== '[') ? EP_DIGITS
: EP_ERROR
;
581 parser
->state
= EP_DIGITS
;
583 if (parser
->numprops
+ 1 < parser
->maxprops
) {
584 parser
->props
[parser
->numprops
++] = parser
->current
;
591 if (ch
>= '0' && ch
<= '9') {
592 parser
->current
= parser
->current
* 10 + (ch
- '0');
593 parser
->state
= EP_PROPS
;
596 /* must be terminator */
597 if (parser
->termchar
!= ch
) {
598 if (parser
->termchar
!= 0 || !((ch
>= 'A' && ch
<= 'Z') || (ch
>= 'a' && ch
<= 'z'))) {
599 parser
->state
= EP_ERROR
;
603 parser
->state
= EP_END
;
606 parser
->state
= EP_ERROR
;
611 return parser
->state
;
614 /*#define DEBUG_REFRESHLINE*/
616 #ifdef DEBUG_REFRESHLINE
617 #define DRL(ARGS...) fprintf(dfh, ARGS)
620 static void DRL_CHAR(int ch
)
623 DRL("^%c", ch
+ '@');
632 static void DRL_STR(const char *str
)
636 int n
= utf8_tounicode(str
, &ch
);
647 #if defined(USE_WINCONSOLE)
648 #include "linenoise-win32.c"
651 #if defined(USE_TERMIOS)
652 static void linenoiseAtExit(void);
653 static struct termios orig_termios
; /* in order to restore at exit */
654 static int rawmode
= 0; /* for atexit() function to check if restore is needed*/
655 static int atexit_registered
= 0; /* register atexit just 1 time */
657 static const char *unsupported_term
[] = {"dumb","cons25","emacs",NULL
};
659 static int isUnsupportedTerm(void) {
660 char *term
= getenv("TERM");
664 for (j
= 0; unsupported_term
[j
]; j
++) {
665 if (strcmp(term
, unsupported_term
[j
]) == 0) {
673 static int enableRawMode(struct current
*current
) {
676 current
->fd
= STDIN_FILENO
;
679 if (!isatty(current
->fd
) || isUnsupportedTerm() ||
680 tcgetattr(current
->fd
, &orig_termios
) == -1) {
686 if (!atexit_registered
) {
687 atexit(linenoiseAtExit
);
688 atexit_registered
= 1;
691 raw
= orig_termios
; /* modify the original mode */
692 /* input modes: no break, no CR to NL, no parity check, no strip char,
693 * no start/stop output control. */
694 raw
.c_iflag
&= ~(BRKINT
| ICRNL
| INPCK
| ISTRIP
| IXON
);
695 /* output modes - actually, no need to disable post processing */
696 /*raw.c_oflag &= ~(OPOST);*/
697 /* control modes - set 8 bit chars */
698 raw
.c_cflag
|= (CS8
);
699 /* local modes - choing off, canonical off, no extended functions,
700 * no signal chars (^Z,^C) */
701 raw
.c_lflag
&= ~(ECHO
| ICANON
| IEXTEN
| ISIG
);
702 /* control chars - set return condition: min number of bytes and timer.
703 * We want read to return every single byte, without timeout. */
704 raw
.c_cc
[VMIN
] = 1; raw
.c_cc
[VTIME
] = 0; /* 1 byte, no timer */
706 /* put terminal in raw mode after flushing */
707 if (tcsetattr(current
->fd
,TCSADRAIN
,&raw
) < 0) {
714 static void disableRawMode(struct current
*current
) {
715 /* Don't even check the return value as it's too late. */
716 if (rawmode
&& tcsetattr(current
->fd
,TCSADRAIN
,&orig_termios
) != -1)
720 /* At exit we'll try to fix the terminal to the initial conditions. */
721 static void linenoiseAtExit(void) {
723 tcsetattr(STDIN_FILENO
, TCSADRAIN
, &orig_termios
);
725 linenoiseHistoryFree();
728 /* gcc/glibc insists that we care about the return code of write!
729 * Clarification: This means that a void-cast like "(void) (EXPR)"
732 #define IGNORE_RC(EXPR) if (EXPR) {}
735 * Output bytes directly, or accumulate output (if current->output is set)
737 static void outputChars(struct current
*current
, const char *buf
, int len
)
742 if (current
->output
) {
743 sb_append_len(current
->output
, buf
, len
);
746 IGNORE_RC(write(current
->fd
, buf
, len
));
750 /* Like outputChars, but using printf-style formatting
752 static void outputFormatted(struct current
*current
, const char *format
, ...)
758 va_start(args
, format
);
759 n
= vsnprintf(buf
, sizeof(buf
), format
, args
);
760 /* This will never happen because we are sure to use outputFormatted() only for short sequences */
761 assert(n
< (int)sizeof(buf
));
763 outputChars(current
, buf
, n
);
766 static void cursorToLeft(struct current
*current
)
768 outputChars(current
, "\r", -1);
771 static void setOutputHighlight(struct current
*current
, const int *props
, int nprops
)
773 outputChars(current
, "\x1b[", -1);
775 outputFormatted(current
, "%d%c", *props
, (nprops
== 0) ? 'm' : ';');
780 static void eraseEol(struct current
*current
)
782 outputChars(current
, "\x1b[0K", -1);
785 static void setCursorPos(struct current
*current
, int x
)
788 cursorToLeft(current
);
791 outputFormatted(current
, "\r\x1b[%dC", x
);
795 static void cursorUp(struct current
*current
, int n
)
798 outputFormatted(current
, "\x1b[%dA", n
);
802 static void cursorDown(struct current
*current
, int n
)
805 outputFormatted(current
, "\x1b[%dB", n
);
809 void linenoiseClearScreen(void)
811 IGNORE_RC(write(STDOUT_FILENO
, "\x1b[H\x1b[2J", 7));
815 * Reads a char from 'fd', waiting at most 'timeout' milliseconds.
817 * A timeout of -1 means to wait forever.
819 * Returns -1 if no char is received within the time or an error occurs.
821 static int fd_read_char(int fd
, int timeout
)
829 if (poll(&p
, 1, timeout
) == 0) {
833 if (read(fd
, &c
, 1) != 1) {
840 * Reads a complete utf-8 character
841 * and returns the unicode value, or -1 on error.
843 static int fd_read(struct current
*current
)
846 char buf
[MAX_UTF8_LEN
];
851 if (read(current
->fd
, &buf
[0], 1) != 1) {
854 n
= utf8_charlen(buf
[0]);
858 for (i
= 1; i
< n
; i
++) {
859 if (read(current
->fd
, &buf
[i
], 1) != 1) {
863 /* decode and return the character */
864 utf8_tounicode(buf
, &c
);
867 return fd_read_char(current
->fd
, -1);
873 * Stores the current cursor column in '*cols'.
874 * Returns 1 if OK, or 0 if failed to determine cursor pos.
876 static int queryCursor(struct current
*current
, int* cols
)
878 struct esc_parser parser
;
881 /* Should not be buffering this output, it needs to go immediately */
882 assert(current
->output
== NULL
);
884 /* control sequence - report cursor location */
885 outputChars(current
, "\x1b[6n", -1);
887 /* Parse the response: ESC [ rows ; cols R */
888 initParseEscapeSeq(&parser
, 'R');
889 while ((ch
= fd_read_char(current
->fd
, 100)) > 0) {
890 switch (parseEscapeSequence(&parser
, ch
)) {
894 if (parser
.numprops
== 2 && parser
.props
[1] < 1000) {
895 *cols
= parser
.props
[1];
909 * Updates current->cols with the current window size (width)
911 static int getWindowSize(struct current
*current
)
915 if (ioctl(STDOUT_FILENO
, TIOCGWINSZ
, &ws
) == 0 && ws
.ws_col
!= 0) {
916 current
->cols
= ws
.ws_col
;
920 /* Failed to query the window size. Perhaps we are on a serial terminal.
921 * Try to query the width by sending the cursor as far to the right
922 * and reading back the cursor position.
923 * Note that this is only done once per call to linenoise rather than
924 * every time the line is refreshed for efficiency reasons.
926 * In more detail, we:
927 * (a) request current cursor position,
928 * (b) move cursor far right,
929 * (c) request cursor position again,
930 * (d) at last move back to the old position.
931 * This gives us the width without messing with the externally
932 * visible cursor position.
935 if (current
->cols
== 0) {
938 /* If anything fails => default 80 */
942 if (queryCursor (current
, &here
)) {
944 setCursorPos(current
, 999);
946 /* (c). Note: If (a) succeeded, then (c) should as well.
947 * For paranoia we still check and have a fallback action
948 * for (d) in case of failure..
950 if (queryCursor (current
, ¤t
->cols
)) {
951 /* (d) Reset the cursor back to the original location. */
952 if (current
->cols
> here
) {
953 setCursorPos(current
, here
);
963 * If CHAR_ESCAPE was received, reads subsequent
964 * chars to determine if this is a known special key.
966 * Returns SPECIAL_NONE if unrecognised, or -1 if EOF.
968 * If no additional char is received within a short time,
969 * CHAR_ESCAPE is returned.
971 static int check_special(int fd
)
973 int c
= fd_read_char(fd
, 50);
980 c2
= fd_read_char(fd
, 50);
984 if (c
== '[' || c
== 'O') {
985 /* Potential arrow key */
992 return SPECIAL_RIGHT
;
1001 if (c
== '[' && c2
>= '1' && c2
<= '8') {
1002 /* extended escape */
1003 c
= fd_read_char(fd
, 50);
1007 return SPECIAL_INSERT
;
1009 return SPECIAL_DELETE
;
1011 return SPECIAL_PAGE_UP
;
1013 return SPECIAL_PAGE_DOWN
;
1015 return SPECIAL_HOME
;
1020 while (c
!= -1 && c
!= '~') {
1021 /* .e.g \e[12~ or '\e[11;2~ discard the complete sequence */
1022 c
= fd_read_char(fd
, 50);
1026 return SPECIAL_NONE
;
1030 static void clearOutputHighlight(struct current
*current
)
1032 int nohighlight
= 0;
1033 setOutputHighlight(current
, &nohighlight
, 1);
1036 static void outputControlChar(struct current
*current
, char ch
)
1039 setOutputHighlight(current
, &reverse
, 1);
1040 outputChars(current
, "^", 1);
1041 outputChars(current
, &ch
, 1);
1042 clearOutputHighlight(current
);
1045 #ifndef utf8_getchars
1046 static int utf8_getchars(char *buf
, int c
)
1049 return utf8_fromunicode(buf
, c
);
1058 * Returns the unicode character at the given offset,
1061 static int get_char(struct current
*current
, int pos
)
1063 if (pos
>= 0 && pos
< sb_chars(current
->buf
)) {
1065 int i
= utf8_index(sb_str(current
->buf
), pos
);
1066 (void)utf8_tounicode(sb_str(current
->buf
) + i
, &c
);
1072 static int char_display_width(int ch
)
1075 /* control chars take two positions */
1079 return utf8_width(ch
);
1083 #ifndef NO_COMPLETION
1084 static linenoiseCompletionCallback
*completionCallback
= NULL
;
1085 static void *completionUserdata
= NULL
;
1086 static int showhints
= 1;
1087 static linenoiseHintsCallback
*hintsCallback
= NULL
;
1088 static linenoiseFreeHintsCallback
*freeHintsCallback
= NULL
;
1089 static void *hintsUserdata
= NULL
;
1091 static void beep() {
1093 fprintf(stderr
, "\x7");
1098 static void freeCompletions(linenoiseCompletions
*lc
) {
1100 for (i
= 0; i
< lc
->len
; i
++)
1105 static int completeLine(struct current
*current
) {
1106 linenoiseCompletions lc
= { 0, NULL
};
1109 completionCallback(sb_str(current
->buf
),&lc
,completionUserdata
);
1113 size_t stop
= 0, i
= 0;
1116 /* Show completion or original buffer */
1118 int chars
= utf8_strlen(lc
.cvec
[i
], -1);
1119 refreshLineAlt(current
, current
->prompt
, lc
.cvec
[i
], chars
);
1121 refreshLine(current
);
1124 c
= fd_read(current
);
1130 case '\t': /* tab */
1131 i
= (i
+1) % (lc
.len
+1);
1132 if (i
== lc
.len
) beep();
1134 case CHAR_ESCAPE
: /* escape */
1135 /* Re-show original buffer */
1137 refreshLine(current
);
1142 /* Update buffer and return */
1144 set_current(current
,lc
.cvec
[i
]);
1152 freeCompletions(&lc
);
1153 return c
; /* Return last read character */
1156 /* Register a callback function to be called for tab-completion.
1157 Returns the prior callback so that the caller may (if needed)
1158 restore it when done. */
1159 linenoiseCompletionCallback
* linenoiseSetCompletionCallback(linenoiseCompletionCallback
*fn
, void *userdata
) {
1160 linenoiseCompletionCallback
* old
= completionCallback
;
1161 completionCallback
= fn
;
1162 completionUserdata
= userdata
;
1166 void linenoiseAddCompletion(linenoiseCompletions
*lc
, const char *str
) {
1167 lc
->cvec
= (char **)realloc(lc
->cvec
,sizeof(char*)*(lc
->len
+1));
1168 lc
->cvec
[lc
->len
++] = strdup(str
);
1171 void linenoiseSetHintsCallback(linenoiseHintsCallback
*callback
, void *userdata
)
1173 hintsCallback
= callback
;
1174 hintsUserdata
= userdata
;
1177 void linenoiseSetFreeHintsCallback(linenoiseFreeHintsCallback
*callback
)
1179 freeHintsCallback
= callback
;
1185 static const char *reduceSingleBuf(const char *buf
, int availcols
, int *cursor_pos
)
1187 /* We have availcols columns available.
1188 * If necessary, strip chars off the front of buf until *cursor_pos
1189 * fits within availcols
1193 int new_cursor_pos
= *cursor_pos
;
1194 const char *pt
= buf
;
1196 DRL("reduceSingleBuf: availcols=%d, cursor_pos=%d\n", availcols
, *cursor_pos
);
1200 int n
= utf8_tounicode(pt
, &ch
);
1203 needcols
+= char_display_width(ch
);
1205 /* If we need too many cols, strip
1206 * chars off the front of buf to make it fit.
1207 * We keep 3 extra cols to the right of the cursor.
1208 * 2 for possible wide chars, 1 for the last column that
1211 while (needcols
>= availcols
- 3) {
1212 n
= utf8_tounicode(buf
, &ch
);
1214 needcols
-= char_display_width(ch
);
1217 /* and adjust the apparent cursor position */
1221 /* can't remove more than this */
1226 if (pos
++ == *cursor_pos
) {
1233 DRL("\nafter reduce, needcols=%d, new_cursor_pos=%d\n", needcols
, new_cursor_pos
);
1235 /* Done, now new_cursor_pos contains the adjusted cursor position
1236 * and buf points to he adjusted start
1238 *cursor_pos
= new_cursor_pos
;
1242 static int mlmode
= 0;
1244 void linenoiseSetMultiLine(int enableml
)
1249 /* Helper of refreshSingleLine() and refreshMultiLine() to show hints
1250 * to the right of the prompt.
1251 * Returns 1 if a hint was shown, or 0 if not
1252 * If 'display' is 0, does no output. Just returns the appropriate return code.
1254 static int refreshShowHints(struct current
*current
, const char *buf
, int availcols
, int display
)
1257 if (showhints
&& hintsCallback
&& availcols
> 0) {
1260 char *hint
= hintsCallback(buf
, &color
, &bold
, hintsUserdata
);
1265 if (bold
== 1 && color
== -1) color
= 37;
1266 if (bold
|| color
> 0) {
1267 int props
[3] = { bold
, color
, 49 }; /* bold, color, fgnormal */
1268 setOutputHighlight(current
, props
, 3);
1270 DRL("<hint bold=%d,color=%d>", bold
, color
);
1274 int n
= utf8_tounicode(pt
, &ch
);
1275 int width
= char_display_width(ch
);
1277 if (width
>= availcols
) {
1284 outputChars(current
, pt
, n
);
1287 if (bold
|| color
> 0) {
1288 clearOutputHighlight(current
);
1290 /* Call the function to free the hint returned. */
1291 if (freeHintsCallback
) freeHintsCallback(hint
, hintsUserdata
);
1299 static void refreshStart(struct current
*current
)
1301 /* We accumulate all output here */
1302 assert(current
->output
== NULL
);
1303 current
->output
= sb_alloc();
1306 static void refreshEnd(struct current
*current
)
1308 /* Output everything at once */
1309 IGNORE_RC(write(current
->fd
, sb_str(current
->output
), sb_len(current
->output
)));
1310 sb_free(current
->output
);
1311 current
->output
= NULL
;
1314 static void refreshStartChars(struct current
*current
)
1318 static void refreshNewline(struct current
*current
)
1321 outputChars(current
, "\n", 1);
1324 static void refreshEndChars(struct current
*current
)
1329 static void refreshLineAlt(struct current
*current
, const char *prompt
, const char *buf
, int cursor_pos
)
1341 struct esc_parser parser
;
1343 #ifdef DEBUG_REFRESHLINE
1344 dfh
= fopen("linenoise.debuglog", "a");
1347 /* Should intercept SIGWINCH. For now, just get the size every time */
1348 getWindowSize(current
);
1350 refreshStart(current
);
1352 DRL("wincols=%d, cursor_pos=%d, nrows=%d, rpos=%d\n", current
->cols
, cursor_pos
, current
->nrows
, current
->rpos
);
1354 /* Here is the plan:
1355 * (a) move the the bottom row, going down the appropriate number of lines
1356 * (b) move to beginning of line and erase the current line
1357 * (c) go up one line and do the same, until we have erased up to the first row
1358 * (d) output the prompt, counting cols and rows, taking into account escape sequences
1359 * (e) output the buffer, counting cols and rows
1360 * (e') when we hit the current pos, save the cursor position
1361 * (f) move the cursor to the saved cursor position
1362 * (g) save the current cursor row and number of rows
1365 /* (a) - The cursor is currently at row rpos */
1366 cursorDown(current
, current
->nrows
- current
->rpos
- 1);
1367 DRL("<cud=%d>", current
->nrows
- current
->rpos
- 1);
1369 /* (b), (c) - Erase lines upwards until we get to the first row */
1370 for (i
= 0; i
< current
->nrows
; i
++) {
1373 cursorUp(current
, 1);
1376 cursorToLeft(current
);
1381 /* (d) First output the prompt. control sequences don't take up display space */
1383 displaycol
= 0; /* current display column */
1384 displayrow
= 0; /* current display row */
1387 refreshStartChars(current
);
1392 int n
= utf8_tounicode(pt
, &ch
);
1394 if (visible
&& ch
== CHAR_ESCAPE
) {
1395 /* The start of an escape sequence, so not visible */
1397 initParseEscapeSeq(&parser
, 'm');
1398 DRL("<esc-seq-start>");
1401 if (ch
== '\n' || ch
== '\r') {
1402 /* treat both CR and NL the same and force wrap */
1403 refreshNewline(current
);
1408 width
= visible
* utf8_width(ch
);
1410 displaycol
+= width
;
1411 if (displaycol
>= current
->cols
) {
1412 /* need to wrap to the next line because of newline or if it doesn't fit
1413 * XXX this is a problem in single line mode
1415 refreshNewline(current
);
1421 #ifdef USE_WINCONSOLE
1423 outputChars(current
, pt
, n
);
1426 outputChars(current
, pt
, n
);
1432 switch (parseEscapeSequence(&parser
, ch
)) {
1435 setOutputHighlight(current
, parser
.props
, parser
.numprops
);
1436 DRL("<esc-seq-end,numprops=%d>", parser
.numprops
);
1439 DRL("<esc-seq-err>");
1446 /* Now we are at the first line with all lines erased */
1447 DRL("\nafter prompt: displaycol=%d, displayrow=%d\n", displaycol
, displayrow
);
1450 /* (e) output the buffer, counting cols and rows */
1452 /* In this mode we may need to trim chars from the start of the buffer until the
1453 * cursor fits in the window.
1455 pt
= reduceSingleBuf(buf
, current
->cols
- displaycol
, &cursor_pos
);
1466 int n
= utf8_tounicode(pt
, &ch
);
1467 int width
= char_display_width(ch
);
1469 if (currentpos
== cursor_pos
) {
1470 /* (e') wherever we output this character is where we want the cursor */
1474 if (displaycol
+ width
>= current
->cols
) {
1476 /* In single line mode stop once we print as much as we can on one line */
1480 /* need to wrap to the next line since it doesn't fit */
1481 refreshNewline(current
);
1486 if (notecursor
== 1) {
1487 /* (e') Save this position as the current cursor position */
1488 cursorcol
= displaycol
;
1489 cursorrow
= displayrow
;
1494 displaycol
+= width
;
1497 outputControlChar(current
, ch
+ '@');
1500 outputChars(current
, pt
, n
);
1504 DRL("<w=%d>", width
);
1511 /* If we didn't see the cursor, it is at the current location */
1514 cursorcol
= displaycol
;
1515 cursorrow
= displayrow
;
1518 DRL("\nafter buf: displaycol=%d, displayrow=%d, cursorcol=%d, cursorrow=%d\n", displaycol
, displayrow
, cursorcol
, cursorrow
);
1520 /* (f) show hints */
1521 hint
= refreshShowHints(current
, buf
, current
->cols
- displaycol
, 1);
1523 /* Remember how many many cols are available for insert optimisation */
1524 if (prompt
== current
->prompt
&& hint
== 0) {
1525 current
->colsright
= current
->cols
- displaycol
;
1526 current
->colsleft
= displaycol
;
1529 /* Can't optimise */
1530 current
->colsright
= 0;
1531 current
->colsleft
= 0;
1533 DRL("\nafter hints: colsleft=%d, colsright=%d\n\n", current
->colsleft
, current
->colsright
);
1535 refreshEndChars(current
);
1537 /* (g) move the cursor to the correct place */
1538 cursorUp(current
, displayrow
- cursorrow
);
1539 setCursorPos(current
, cursorcol
);
1541 /* (h) Update the number of rows if larger, but never reduce this */
1542 if (displayrow
>= current
->nrows
) {
1543 current
->nrows
= displayrow
+ 1;
1545 /* And remember the row that the cursor is on */
1546 current
->rpos
= cursorrow
;
1548 refreshEnd(current
);
1550 #ifdef DEBUG_REFRESHLINE
1555 static void refreshLine(struct current
*current
)
1557 refreshLineAlt(current
, current
->prompt
, sb_str(current
->buf
), current
->pos
);
1560 static void set_current(struct current
*current
, const char *str
)
1562 sb_clear(current
->buf
);
1563 sb_append(current
->buf
, str
);
1564 current
->pos
= sb_chars(current
->buf
);
1568 * Removes the char at 'pos'.
1570 * Returns 1 if the line needs to be refreshed, 2 if not
1571 * and 0 if nothing was removed
1573 static int remove_char(struct current
*current
, int pos
)
1575 if (pos
>= 0 && pos
< sb_chars(current
->buf
)) {
1576 int offset
= utf8_index(sb_str(current
->buf
), pos
);
1577 int nbytes
= utf8_index(sb_str(current
->buf
) + offset
, 1);
1580 /* Now we try to optimise in the simple but very common case that:
1581 * - outputChars() can be used directly (not win32)
1582 * - we are removing the char at EOL
1583 * - the buffer is not empty
1584 * - there are columns available to the left
1585 * - the char being deleted is not a wide or utf-8 character
1586 * - no hints are being shown
1588 if (current
->output
&& current
->pos
== pos
+ 1 && current
->pos
== sb_chars(current
->buf
) && pos
> 0) {
1590 /* Could implement utf8_prev_len() but simplest just to not optimise this case */
1591 char last
= sb_str(current
->buf
)[offset
];
1595 if (current
->colsleft
> 0 && (last
& 0x80) == 0) {
1596 /* Have cols on the left and not a UTF-8 char or continuation */
1597 /* Yes, can optimise */
1598 current
->colsleft
--;
1599 current
->colsright
++;
1604 sb_delete(current
->buf
, offset
, nbytes
);
1606 if (current
->pos
> pos
) {
1610 if (refreshShowHints(current
, sb_str(current
->buf
), current
->colsright
, 0)) {
1611 /* A hint needs to be shown, so can't optimise after all */
1615 /* optimised output */
1616 outputChars(current
, "\b \b", 3);
1626 * Insert 'ch' at position 'pos'
1628 * Returns 1 if the line needs to be refreshed, 2 if not
1629 * and 0 if nothing was inserted (no room)
1631 static int insert_char(struct current
*current
, int pos
, int ch
)
1633 if (pos
>= 0 && pos
<= sb_chars(current
->buf
)) {
1634 char buf
[MAX_UTF8_LEN
+ 1];
1635 int offset
= utf8_index(sb_str(current
->buf
), pos
);
1636 int n
= utf8_getchars(buf
, ch
);
1639 /* null terminate since sb_insert() requires it */
1642 /* Now we try to optimise in the simple but very common case that:
1643 * - outputChars() can be used directly (not win32)
1644 * - we are inserting at EOL
1645 * - there are enough columns available
1646 * - no hints are being shown
1648 if (current
->output
&& pos
== current
->pos
&& pos
== sb_chars(current
->buf
)) {
1649 int width
= char_display_width(ch
);
1650 if (current
->colsright
> width
) {
1651 /* Yes, can optimise */
1652 current
->colsright
-= width
;
1653 current
->colsleft
-= width
;
1657 sb_insert(current
->buf
, offset
, buf
);
1658 if (current
->pos
>= pos
) {
1662 if (refreshShowHints(current
, sb_str(current
->buf
), current
->colsright
, 0)) {
1663 /* A hint needs to be shown, so can't optimise after all */
1667 /* optimised output */
1668 outputChars(current
, buf
, n
);
1677 * Captures up to 'n' characters starting at 'pos' for the cut buffer.
1679 * This replaces any existing characters in the cut buffer.
1681 static void capture_chars(struct current
*current
, int pos
, int nchars
)
1683 if (pos
>= 0 && (pos
+ nchars
- 1) < sb_chars(current
->buf
)) {
1684 int offset
= utf8_index(sb_str(current
->buf
), pos
);
1685 int nbytes
= utf8_index(sb_str(current
->buf
) + offset
, nchars
);
1688 if (current
->capture
) {
1689 sb_clear(current
->capture
);
1692 current
->capture
= sb_alloc();
1694 sb_append_len(current
->capture
, sb_str(current
->buf
) + offset
, nbytes
);
1700 * Removes up to 'n' characters at cursor position 'pos'.
1702 * Returns 0 if no chars were removed or non-zero otherwise.
1704 static int remove_chars(struct current
*current
, int pos
, int n
)
1708 /* First save any chars which will be removed */
1709 capture_chars(current
, pos
, n
);
1711 while (n
-- && remove_char(current
, pos
)) {
1717 * Inserts the characters (string) 'chars' at the cursor position 'pos'.
1719 * Returns 0 if no chars were inserted or non-zero otherwise.
1721 static int insert_chars(struct current
*current
, int pos
, const char *chars
)
1727 int n
= utf8_tounicode(chars
, &ch
);
1728 if (insert_char(current
, pos
, ch
) == 0) {
1739 * Returns the keycode to process, or 0 if none.
1741 static int reverseIncrementalSearch(struct current
*current
)
1743 /* Display the reverse-i-search prompt and process chars */
1748 int searchpos
= history_len
- 1;
1754 const char *p
= NULL
;
1758 snprintf(rprompt
, sizeof(rprompt
), "(reverse-i-search)'%s': ", rbuf
);
1759 refreshLineAlt(current
, rprompt
, sb_str(current
->buf
), current
->pos
);
1760 c
= fd_read(current
);
1761 if (c
== ctrl('H') || c
== CHAR_DELETE
) {
1763 int p
= utf8_index(rbuf
, --rchars
);
1765 rlen
= strlen(rbuf
);
1770 if (c
== CHAR_ESCAPE
) {
1771 c
= check_special(current
->fd
);
1774 if (c
== ctrl('P') || c
== SPECIAL_UP
) {
1775 /* Search for the previous (earlier) match */
1776 if (searchpos
> 0) {
1781 else if (c
== ctrl('N') || c
== SPECIAL_DOWN
) {
1782 /* Search for the next (later) match */
1783 if (searchpos
< history_len
) {
1789 else if (c
>= ' ') {
1790 /* >= here to allow for null terminator */
1791 if (rlen
>= (int)sizeof(rbuf
) - MAX_UTF8_LEN
) {
1795 n
= utf8_getchars(rbuf
+ rlen
, c
);
1800 /* Adding a new char resets the search location */
1801 searchpos
= history_len
- 1;
1804 /* Exit from incremental search mode */
1808 /* Now search through the history for a match */
1809 for (; searchpos
>= 0 && searchpos
< history_len
; searchpos
+= searchdir
) {
1810 p
= strstr(history
[searchpos
], rbuf
);
1813 if (skipsame
&& strcmp(history
[searchpos
], sb_str(current
->buf
)) == 0) {
1814 /* But it is identical, so skip it */
1817 /* Copy the matching line and set the cursor position */
1818 set_current(current
,history
[searchpos
]);
1819 current
->pos
= utf8_strlen(history
[searchpos
], p
- history
[searchpos
]);
1824 /* No match, so don't add it */
1830 if (c
== ctrl('G') || c
== ctrl('C')) {
1831 /* ctrl-g terminates the search with no effect */
1832 set_current(current
, "");
1835 else if (c
== ctrl('J')) {
1836 /* ctrl-j terminates the search leaving the buffer in place */
1840 /* Go process the char normally */
1841 refreshLine(current
);
1845 static int linenoiseEdit(struct current
*current
) {
1846 int history_index
= 0;
1848 /* The latest history entry is always our current buffer, that
1849 * initially is just an empty string. */
1850 linenoiseHistoryAdd("");
1852 set_current(current
, "");
1853 refreshLine(current
);
1857 int c
= fd_read(current
);
1859 #ifndef NO_COMPLETION
1860 /* Only autocomplete when the callback is set. It returns < 0 when
1861 * there was an error reading from fd. Otherwise it will return the
1862 * character that should be handled next. */
1863 if (c
== '\t' && current
->pos
== sb_chars(current
->buf
) && completionCallback
!= NULL
) {
1864 c
= completeLine(current
);
1867 if (c
== ctrl('R')) {
1868 /* reverse incremental search will provide an alternative keycode or 0 for none */
1869 c
= reverseIncrementalSearch(current
);
1870 /* go on to process the returned char normally */
1874 if (c
== CHAR_ESCAPE
) { /* escape sequence */
1875 c
= check_special(current
->fd
);
1879 /* Return on errors */
1880 return sb_len(current
->buf
);
1886 case '\r': /* enter/CR */
1889 free(history
[history_len
]);
1890 current
->pos
= sb_chars(current
->buf
);
1891 if (mlmode
|| hintsCallback
) {
1893 refreshLine(current
);
1896 return sb_len(current
->buf
);
1897 case ctrl('C'): /* ctrl-c */
1900 case ctrl('Z'): /* ctrl-z */
1902 /* send ourselves SIGSUSP */
1903 disableRawMode(current
);
1906 enableRawMode(current
);
1907 refreshLine(current
);
1910 case CHAR_DELETE
: /* backspace */
1912 if (remove_char(current
, current
->pos
- 1) == 1) {
1913 refreshLine(current
);
1916 case ctrl('D'): /* ctrl-d */
1917 if (sb_len(current
->buf
) == 0) {
1918 /* Empty line, so EOF */
1920 free(history
[history_len
]);
1923 /* Otherwise fall through to delete char to right of cursor */
1924 case SPECIAL_DELETE
:
1925 if (remove_char(current
, current
->pos
) == 1) {
1926 refreshLine(current
);
1929 case SPECIAL_INSERT
:
1930 /* Ignore. Expansion Hook.
1931 * Future possibility: Toggle Insert/Overwrite Modes
1934 case ctrl('W'): /* ctrl-w, delete word at left. save deleted chars */
1935 /* eat any spaces on the left */
1937 int pos
= current
->pos
;
1938 while (pos
> 0 && get_char(current
, pos
- 1) == ' ') {
1942 /* now eat any non-spaces on the left */
1943 while (pos
> 0 && get_char(current
, pos
- 1) != ' ') {
1947 if (remove_chars(current
, pos
, current
->pos
- pos
)) {
1948 refreshLine(current
);
1952 case ctrl('T'): /* ctrl-t */
1953 if (current
->pos
> 0 && current
->pos
<= sb_chars(current
->buf
)) {
1954 /* If cursor is at end, transpose the previous two chars */
1955 int fixer
= (current
->pos
== sb_chars(current
->buf
));
1956 c
= get_char(current
, current
->pos
- fixer
);
1957 remove_char(current
, current
->pos
- fixer
);
1958 insert_char(current
, current
->pos
- 1, c
);
1959 refreshLine(current
);
1962 case ctrl('V'): /* ctrl-v */
1963 /* Insert the ^V first */
1964 if (insert_char(current
, current
->pos
, c
)) {
1965 refreshLine(current
);
1966 /* Now wait for the next char. Can insert anything except \0 */
1967 c
= fd_read(current
);
1969 /* Remove the ^V first */
1970 remove_char(current
, current
->pos
- 1);
1972 /* Insert the actual char, can't be error or null */
1973 insert_char(current
, current
->pos
, c
);
1975 refreshLine(current
);
1980 if (current
->pos
> 0) {
1982 refreshLine(current
);
1987 if (current
->pos
< sb_chars(current
->buf
)) {
1989 refreshLine(current
);
1992 case SPECIAL_PAGE_UP
:
1993 dir
= history_len
- history_index
- 1; /* move to start of history */
1994 goto history_navigation
;
1995 case SPECIAL_PAGE_DOWN
:
1996 dir
= -history_index
; /* move to 0 == end of history, i.e. current */
1997 goto history_navigation
;
2001 goto history_navigation
;
2005 if (history_len
> 1) {
2006 /* Update the current history entry before to
2007 * overwrite it with tne next one. */
2008 free(history
[history_len
- 1 - history_index
]);
2009 history
[history_len
- 1 - history_index
] = strdup(sb_str(current
->buf
));
2010 /* Show the new entry */
2011 history_index
+= dir
;
2012 if (history_index
< 0) {
2015 } else if (history_index
>= history_len
) {
2016 history_index
= history_len
- 1;
2019 set_current(current
, history
[history_len
- 1 - history_index
]);
2020 refreshLine(current
);
2023 case ctrl('A'): /* Ctrl+a, go to the start of the line */
2026 refreshLine(current
);
2028 case ctrl('E'): /* ctrl+e, go to the end of the line */
2030 current
->pos
= sb_chars(current
->buf
);
2031 refreshLine(current
);
2033 case ctrl('U'): /* Ctrl+u, delete to beginning of line, save deleted chars. */
2034 if (remove_chars(current
, 0, current
->pos
)) {
2035 refreshLine(current
);
2038 case ctrl('K'): /* Ctrl+k, delete from current to end of line, save deleted chars. */
2039 if (remove_chars(current
, current
->pos
, sb_chars(current
->buf
) - current
->pos
)) {
2040 refreshLine(current
);
2043 case ctrl('Y'): /* Ctrl+y, insert saved chars at current position */
2044 if (current
->capture
&& insert_chars(current
, current
->pos
, sb_str(current
->capture
))) {
2045 refreshLine(current
);
2048 case ctrl('L'): /* Ctrl+L, clear screen */
2049 linenoiseClearScreen();
2050 /* Force recalc of window size for serial terminals */
2053 refreshLine(current
);
2056 /* Only tab is allowed without ^V */
2057 if (c
== '\t' || c
>= ' ') {
2058 if (insert_char(current
, current
->pos
, c
) == 1) {
2059 refreshLine(current
);
2065 return sb_len(current
->buf
);
2068 int linenoiseColumns(void)
2070 struct current current
;
2071 current
.output
= NULL
;
2072 enableRawMode (¤t
);
2073 getWindowSize (¤t
);
2074 disableRawMode (¤t
);
2075 return current
.cols
;
2079 * Reads a line from the file handle (without the trailing NL or CRNL)
2080 * and returns it in a stringbuf.
2081 * Returns NULL if no characters are read before EOF or error.
2083 * Note that the character count will *not* be correct for lines containing
2084 * utf8 sequences. Do not rely on the character count.
2086 static stringbuf
*sb_getline(FILE *fh
)
2088 stringbuf
*sb
= sb_alloc();
2092 while ((c
= getc(fh
)) != EOF
) {
2099 if (c
== '\n' || c
== '\r') {
2103 /* ignore the effect of character count for partial utf8 sequences */
2104 sb_append_len(sb
, &ch
, 1);
2113 char *linenoise(const char *prompt
)
2116 struct current current
;
2119 memset(¤t
, 0, sizeof(current
));
2121 if (enableRawMode(¤t
) == -1) {
2122 printf("%s", prompt
);
2124 sb
= sb_getline(stdin
);
2127 current
.buf
= sb_alloc();
2130 current
.prompt
= prompt
;
2132 count
= linenoiseEdit(¤t
);
2134 disableRawMode(¤t
);
2137 sb_free(current
.capture
);
2139 sb_free(current
.buf
);
2144 return sb
? sb_to_string(sb
) : NULL
;
2147 /* Using a circular buffer is smarter, but a bit more complex to handle. */
2148 int linenoiseHistoryAddAllocated(char *line
) {
2150 if (history_max_len
== 0) {
2155 if (history
== NULL
) {
2156 history
= (char **)calloc(sizeof(char*), history_max_len
);
2159 /* do not insert duplicate lines into history */
2160 if (history_len
> 0 && strcmp(line
, history
[history_len
- 1]) == 0) {
2164 if (history_len
== history_max_len
) {
2166 memmove(history
,history
+1,sizeof(char*)*(history_max_len
-1));
2169 history
[history_len
] = line
;
2174 int linenoiseHistoryAdd(const char *line
) {
2175 return linenoiseHistoryAddAllocated(strdup(line
));
2178 int linenoiseHistoryGetMaxLen(void) {
2179 return history_max_len
;
2182 int linenoiseHistorySetMaxLen(int len
) {
2185 if (len
< 1) return 0;
2187 int tocopy
= history_len
;
2189 newHistory
= (char **)calloc(sizeof(char*), len
);
2191 /* If we can't copy everything, free the elements we'll not use. */
2195 for (j
= 0; j
< tocopy
-len
; j
++) free(history
[j
]);
2198 memcpy(newHistory
,history
+(history_len
-tocopy
), sizeof(char*)*tocopy
);
2200 history
= newHistory
;
2202 history_max_len
= len
;
2203 if (history_len
> history_max_len
)
2204 history_len
= history_max_len
;
2208 /* Save the history in the specified file. On success 0 is returned
2209 * otherwise -1 is returned. */
2210 int linenoiseHistorySave(const char *filename
) {
2211 FILE *fp
= fopen(filename
,"w");
2214 if (fp
== NULL
) return -1;
2215 for (j
= 0; j
< history_len
; j
++) {
2216 const char *str
= history
[j
];
2217 /* Need to encode backslash, nl and cr */
2222 else if (*str
== '\n') {
2225 else if (*str
== '\r') {
2240 /* Load the history from the specified file.
2242 * If the file does not exist or can't be opened, no operation is performed
2243 * and -1 is returned.
2244 * Otherwise 0 is returned.
2246 int linenoiseHistoryLoad(const char *filename
) {
2247 FILE *fp
= fopen(filename
,"r");
2250 if (fp
== NULL
) return -1;
2252 while ((sb
= sb_getline(fp
)) != NULL
) {
2253 /* Take the stringbuf and decode backslash escaped values */
2254 char *buf
= sb_to_string(sb
);
2258 for (src
= buf
; *src
; src
++) {
2266 else if (*src
== 'r') {
2276 linenoiseHistoryAddAllocated(buf
);
2282 /* Provide access to the history buffer.
2284 * If 'len' is not NULL, the length is stored in *len.
2286 char **linenoiseHistory(int *len
) {