···1010 *
1111 * ------------------------------------------------------------------------
1212 *
1313- * Copyright (c) 2010-2023, Salvatore Sanfilippo <antirez at gmail dot com>
1313+ * Copyright (c) 2010-2016, Salvatore Sanfilippo <antirez at gmail dot com>
1414 * Copyright (c) 2010-2013, Pieter Noordhuis <pcnoordhuis at gmail dot com>
1515 *
1616 * All rights reserved.
···4747 * Todo list:
4848 * - Filter bogus Ctrl+<char> combinations.
4949 * - Win32 support
5050- *
5151- * Bloat:
5252- * - History search like Ctrl+r in readline?
5350 *
5451 * List of escape sequences used by this program, we do everything just
5552 * with three sequences. In order to be so cheap we may have some
···119116120117#define LINENOISE_DEFAULT_HISTORY_MAX_LEN 100
121118#define LINENOISE_MAX_LINE 4096
122122-#define UNUSED(x) (void)(x)
123119static char *unsupported_term[] = {"dumb","cons25","emacs",NULL};
124120static linenoiseCompletionCallback *completionCallback = NULL;
125121static linenoiseHintsCallback *hintsCallback = NULL;
126122static linenoiseFreeHintsCallback *freeHintsCallback = NULL;
127127-static char *linenoiseNoTTY(void);
128128-static void refreshLineWithCompletion(struct linenoiseState *ls, linenoiseCompletions *lc, int flags);
129129-static void refreshLineWithFlags(struct linenoiseState *l, int flags);
130123131124static struct termios orig_termios; /* In order to restore at exit.*/
132132-static int maskmode = 0; /* Show "***" instead of input. For passwords. */
133125static int rawmode = 0; /* For atexit() function to check if restore is needed*/
134126static int mlmode = 0; /* Multi line mode. Default is single line. */
135127static int atexit_registered = 0; /* Register atexit just 1 time. */
···139131140132int linenoiseWasInterrupted = 0;
141133134134+/* The linenoiseState structure represents the state during line editing.
135135+ * We pass this state to functions implementing specific editing
136136+ * functionalities. */
137137+struct linenoiseState {
138138+ int ifd; /* Terminal stdin file descriptor. */
139139+ int ofd; /* Terminal stdout file descriptor. */
140140+ char *buf; /* Edited line buffer. */
141141+ size_t buflen; /* Edited line buffer size. */
142142+ const char *prompt; /* Prompt to display. */
143143+ size_t plen; /* Prompt length. */
144144+ size_t pos; /* Current cursor position. */
145145+ size_t oldpos; /* Previous refresh cursor position. */
146146+ size_t len; /* Current edited line length. */
147147+ size_t cols; /* Number of columns in terminal. */
148148+ size_t maxrows; /* Maximum num of rows used so far (multiline mode) */
149149+ int history_index; /* The history index we are currently editing. */
150150+};
151151+142152enum KEY_ACTION{
143153 KEY_NULL = 0, /* NULL */
144154 CTRL_A = 1, /* Ctrl+a */
···147157 CTRL_D = 4, /* Ctrl-d */
148158 CTRL_E = 5, /* Ctrl-e */
149159 CTRL_F = 6, /* Ctrl-f */
160160+ CTRL_G = 7, /* Ctrl-g */
150161 CTRL_H = 8, /* Ctrl-h */
151162 TAB = 9, /* Tab */
152163 CTRL_K = 11, /* Ctrl+k */
···154165 ENTER = 13, /* Enter */
155166 CTRL_N = 14, /* Ctrl-n */
156167 CTRL_P = 16, /* Ctrl-p */
168168+ CTRL_R = 18, /* Ctrl-r */
157169 CTRL_T = 20, /* Ctrl-t */
158170 CTRL_U = 21, /* Ctrl+u */
159171 CTRL_W = 23, /* Ctrl+w */
···163175164176static void linenoiseAtExit(void);
165177int linenoiseHistoryAdd(const char *line);
166166-#define REFRESH_CLEAN (1<<0) // Clean the old prompt from the screen
167167-#define REFRESH_WRITE (1<<1) // Rewrite the prompt on the screen.
168168-#define REFRESH_ALL (REFRESH_CLEAN|REFRESH_WRITE) // Do both.
169178static void refreshLine(struct linenoiseState *l);
179179+static void refreshLinePrompt(struct linenoiseState *l, const char *prompt);
170180171181/* Debugging macro. */
172182#if 0
···177187 lndebug_fp = fopen("/tmp/lndebug.txt","a"); \
178188 fprintf(lndebug_fp, \
179189 "[%d %d %d] p: %d, rows: %d, rpos: %d, max: %d, oldmax: %d\n", \
180180- (int)l->len,(int)l->pos,(int)l->oldcolpos,plen,rows,rpos, \
181181- (int)l->oldrows,old_rows); \
190190+ (int)l->len,(int)l->pos,(int)l->oldpos,plen,rows,rpos, \
191191+ (int)l->maxrows,old_rows); \
182192 } \
183193 fprintf(lndebug_fp, ", " __VA_ARGS__); \
184194 fflush(lndebug_fp); \
···187197#define lndebug(fmt, ...)
188198#endif
189199190190-/* ========================== Encoding functions ============================= */
191191-192192-/* Get byte length and column length of the previous character */
193193-static size_t defaultPrevCharLen(const char *buf, size_t buf_len, size_t pos, size_t *col_len) {
194194- UNUSED(buf); UNUSED(buf_len); UNUSED(pos);
195195- if (col_len != NULL) *col_len = 1;
196196- return 1;
197197-}
198198-199199-/* Get byte length and column length of the next character */
200200-static size_t defaultNextCharLen(const char *buf, size_t buf_len, size_t pos, size_t *col_len) {
201201- UNUSED(buf); UNUSED(buf_len); UNUSED(pos);
202202- if (col_len != NULL) *col_len = 1;
203203- return 1;
204204-}
205205-206206-/* Read bytes of the next character */
207207-static size_t defaultReadCode(int fd, char *buf, size_t buf_len, int* c) {
208208- if (buf_len < 1) return -1;
209209- int nread = read(fd,&buf[0],1);
210210- if (nread == 1) *c = buf[0];
211211- return nread;
212212-}
213213-214214-/* Set default encoding functions */
215215-static linenoisePrevCharLen *prevCharLen = defaultPrevCharLen;
216216-static linenoiseNextCharLen *nextCharLen = defaultNextCharLen;
217217-static linenoiseReadCode *readCode = defaultReadCode;
218218-219219-/* Set used defined encoding functions */
220220-void linenoiseSetEncodingFunctions(
221221- linenoisePrevCharLen *prevCharLenFunc,
222222- linenoiseNextCharLen *nextCharLenFunc,
223223- linenoiseReadCode *readCodeFunc) {
224224- prevCharLen = prevCharLenFunc;
225225- nextCharLen = nextCharLenFunc;
226226- readCode = readCodeFunc;
227227-}
228228-229229-/* Get column length from begining of buffer to current byte position */
230230-static size_t columnPos(const char *buf, size_t buf_len, size_t pos) {
231231- size_t ret = 0;
232232- size_t off = 0;
233233- while (off < pos) {
234234- size_t col_len;
235235- size_t len = nextCharLen(buf,buf_len,off,&col_len);
236236- off += len;
237237- ret += col_len;
238238- }
239239- return ret;
240240-}
241241-242242-/* Get column length from begining of buffer to current byte position for multiline mode*/
243243-static size_t columnPosForMultiLine(const char *buf, size_t buf_len, size_t pos, size_t cols, size_t ini_pos) {
244244- size_t ret = 0;
245245- size_t colwid = ini_pos;
246246-247247- size_t off = 0;
248248- while (off < buf_len) {
249249- size_t col_len;
250250- size_t len = nextCharLen(buf,buf_len,off,&col_len);
251251-252252- int dif = (int)(colwid + col_len) - (int)cols;
253253- if (dif > 0) {
254254- ret += dif;
255255- colwid = col_len;
256256- } else if (dif == 0) {
257257- colwid = 0;
258258- } else {
259259- colwid += col_len;
260260- }
261261-262262- if (off >= pos) break;
263263- off += len;
264264- ret += col_len;
265265- }
266266-267267- return ret;
268268-}
269269-270200/* ======================= Low level terminal handling ====================== */
271201272272-/* Enable "mask mode". When it is enabled, instead of the input that
273273- * the user is typing, the terminal will just display a corresponding
274274- * number of asterisks, like "****". This is useful for passwords and other
275275- * secrets that should not be displayed. */
276276-void linenoiseMaskModeEnable(void) {
277277- maskmode = 1;
278278-}
279279-280280-/* Disable mask mode. */
281281-void linenoiseMaskModeDisable(void) {
282282- maskmode = 0;
283283-}
284284-285202/* Set if to use or not the multi line mode. */
286203void linenoiseSetMultiLine(int ml) {
287204 mlmode = ml;
···326243 raw.c_cc[VMIN] = 1; raw.c_cc[VTIME] = 0; /* 1 byte, no timer */
327244328245 /* put terminal in raw mode after flushing */
329329- if (tcsetattr(fd,TCSAFLUSH,&raw) < 0) goto fatal;
246246+ if (tcsetattr(fd,TCSADRAIN,&raw) < 0) goto fatal;
330247 rawmode = 1;
331248 return 0;
332249···337254338255static void disableRawMode(int fd) {
339256 /* Don't even check the return value as it's too late. */
340340- if (rawmode && tcsetattr(fd,TCSAFLUSH,&orig_termios) != -1)
257257+ if (rawmode && tcsetattr(fd,TCSADRAIN,&orig_termios) != -1)
341258 rawmode = 0;
342259}
343260···426343 free(lc->cvec);
427344}
428345429429-/* Called by completeLine() and linenoiseShow() to render the current
430430- * edited line with the proposed completion. If the current completion table
431431- * is already available, it is passed as second argument, otherwise the
432432- * function will use the callback to obtain it.
433433- *
434434- * Flags are the same as refreshLine*(), that is REFRESH_* macros. */
435435-static void refreshLineWithCompletion(struct linenoiseState *ls, linenoiseCompletions *lc, int flags) {
436436- /* Obtain the table of completions if the caller didn't provide one. */
437437- linenoiseCompletions ctable = { 0, NULL };
438438- if (lc == NULL) {
439439- completionCallback(ls->buf,&ctable);
440440- lc = &ctable;
441441- }
442442-443443- /* Show the edited line with completion if possible, or just refresh. */
444444- if (ls->completion_idx < lc->len) {
445445- struct linenoiseState saved = *ls;
446446- ls->len = ls->pos = strlen(lc->cvec[ls->completion_idx]);
447447- ls->buf = lc->cvec[ls->completion_idx];
448448- refreshLineWithFlags(ls,flags);
449449- ls->len = saved.len;
450450- ls->pos = saved.pos;
451451- ls->buf = saved.buf;
452452- } else {
453453- refreshLineWithFlags(ls,flags);
454454- }
455455-456456- /* Free the completions table if needed. */
457457- if (lc != &ctable) freeCompletions(&ctable);
458458-}
459459-460460-/* This is an helper function for linenoiseEdit*() and is called when the
346346+/* This is an helper function for linenoiseEdit() and is called when the
461347 * user types the <tab> key in order to complete the string currently in the
462348 * input.
463349 *
464350 * The state of the editing is encapsulated into the pointed linenoiseState
465465- * structure as described in the structure definition.
466466- *
467467- * If the function returns non-zero, the caller should handle the
468468- * returned value as a byte read from the standard input, and process
469469- * it as usually: this basically means that the function may return a byte
470470- * read from the termianl but not processed. Otherwise, if zero is returned,
471471- * the input was consumed by the completeLine() function to navigate the
472472- * possible completions, and the caller should read for the next characters
473473- * from stdin. */
474474-static int completeLine(struct linenoiseState *ls, int keypressed) {
351351+ * structure as described in the structure definition. */
352352+static int completeLine(struct linenoiseState *ls) {
475353 linenoiseCompletions lc = { 0, NULL };
476476- int nwritten;
477477- char c = keypressed;
354354+ int nread, nwritten;
355355+ char c = 0;
478356479357 completionCallback(ls->buf,&lc);
480358 if (lc.len == 0) {
481359 linenoiseBeep();
482482- ls->in_completion = 0;
483360 } else {
484484- switch(c) {
485485- case 9: /* tab */
486486- if (ls->in_completion == 0) {
487487- ls->in_completion = 1;
488488- ls->completion_idx = 0;
489489- } else {
490490- ls->completion_idx = (ls->completion_idx+1) % (lc.len+1);
491491- if (ls->completion_idx == lc.len) linenoiseBeep();
492492- }
493493- c = 0;
494494- break;
495495- case 27: /* escape */
496496- /* Re-show original buffer */
497497- if (ls->completion_idx < lc.len) refreshLine(ls);
498498- ls->in_completion = 0;
499499- c = 0;
500500- break;
501501- default:
502502- /* Update buffer and return */
503503- if (ls->completion_idx < lc.len) {
504504- nwritten = snprintf(ls->buf,ls->buflen,"%s",
505505- lc.cvec[ls->completion_idx]);
506506- ls->len = ls->pos = nwritten;
507507- }
508508- ls->in_completion = 0;
509509- break;
510510- }
361361+ size_t stop = 0, i = 0;
511362512512- /* Show completion or original buffer */
513513- if (ls->in_completion && ls->completion_idx < lc.len) {
514514- refreshLineWithCompletion(ls,&lc,REFRESH_ALL);
515515- } else {
516516- refreshLine(ls);
363363+ while(!stop) {
364364+ /* Show completion or original buffer */
365365+ if (i < lc.len) {
366366+ struct linenoiseState saved = *ls;
367367+368368+ ls->len = ls->pos = strlen(lc.cvec[i]);
369369+ ls->buf = lc.cvec[i];
370370+ refreshLine(ls);
371371+ ls->len = saved.len;
372372+ ls->pos = saved.pos;
373373+ ls->buf = saved.buf;
374374+ } else {
375375+ refreshLine(ls);
376376+ }
377377+378378+ nread = read(ls->ifd,&c,1);
379379+ if (nread <= 0) {
380380+ freeCompletions(&lc);
381381+ return -1;
382382+ }
383383+384384+ switch(c) {
385385+ case 9: /* tab */
386386+ i = (i+1) % (lc.len+1);
387387+ if (i == lc.len) linenoiseBeep();
388388+ break;
389389+ case 27: /* escape */
390390+ /* Re-show original buffer */
391391+ if (i < lc.len) refreshLine(ls);
392392+ stop = 1;
393393+ break;
394394+ default:
395395+ /* Update buffer and return */
396396+ if (i < lc.len) {
397397+ nwritten = snprintf(ls->buf,ls->buflen,"%s",lc.cvec[i]);
398398+ ls->len = ls->pos = nwritten;
399399+ }
400400+ stop = 1;
401401+ break;
402402+ }
517403 }
518404 }
519405···589475590476/* Helper of refreshSingleLine() and refreshMultiLine() to show hints
591477 * to the right of the prompt. */
592592-void refreshShowHints(struct abuf *ab, struct linenoiseState *l, int pcollen) {
478478+void refreshShowHints(struct abuf *ab, struct linenoiseState *l, int plen) {
593479 char seq[64];
594594- size_t collen = pcollen+columnPos(l->buf,l->len,l->len);
595595- if (hintsCallback && collen < l->cols) {
480480+ if (hintsCallback && plen+l->len < l->cols) {
596481 int color = -1, bold = 0;
597482 char *hint = hintsCallback(l->buf,&color,&bold);
598483 if (hint) {
599484 int hintlen = strlen(hint);
600600- int hintmaxlen = l->cols-collen;
485485+ int hintmaxlen = l->cols-(plen+l->len);
601486 if (hintlen > hintmaxlen) hintlen = hintmaxlen;
602487 if (bold == 1 && color == -1) color = 37;
603488 if (color != -1 || bold != 0)
604489 snprintf(seq,64,"\033[%d;%d;49m",bold,color);
605605- else
606606- seq[0] = '\0';
607490 abAppend(ab,seq,strlen(seq));
608491 abAppend(ab,hint,hintlen);
609492 if (color != -1 || bold != 0)
···614497 }
615498}
616499617617-/* Check if text is an ANSI escape sequence
618618- */
619619-static int isAnsiEscape(const char *buf, size_t buf_len, size_t* len) {
620620- if (buf_len > 2 && !memcmp("\033[", buf, 2)) {
621621- size_t off = 2;
622622- while (off < buf_len) {
623623- switch (buf[off++]) {
624624- case 'A': case 'B': case 'C': case 'D': case 'E':
625625- case 'F': case 'G': case 'H': case 'J': case 'K':
626626- case 'S': case 'T': case 'f': case 'm':
627627- *len = off;
628628- return 1;
629629- }
630630- }
631631- }
632632- return 0;
633633-}
634634-635635-/* Get column length of prompt text
636636- */
637637-static size_t promptTextColumnLen(const char *prompt, size_t plen) {
638638- char buf[LINENOISE_MAX_LINE];
639639- size_t buf_len = 0;
640640- size_t off = 0;
641641- while (off < plen) {
642642- size_t len;
643643- if (isAnsiEscape(prompt + off, plen - off, &len)) {
644644- off += len;
645645- continue;
646646- }
647647- buf[buf_len++] = prompt[off++];
648648- }
649649- return columnPos(buf,buf_len,buf_len);
650650-}
651651-652500/* Single line low level line refresh.
653501 *
654502 * Rewrite the currently edited line accordingly to the buffer content,
655655- * cursor position, and number of columns of the terminal.
656656- *
657657- * Flags is REFRESH_* macros. The function can just remove the old
658658- * prompt, just write it, or both. */
659659-static void refreshSingleLine(struct linenoiseState *l, int flags) {
503503+ * cursor position, and number of columns of the terminal. */
504504+static void refreshSingleLine(struct linenoiseState *l, const char *prompt) {
660505 char seq[64];
661661- size_t pcollen = promptTextColumnLen(l->prompt,strlen(l->prompt));
506506+ size_t plen = strlen(prompt);
662507 int fd = l->ofd;
663508 char *buf = l->buf;
664509 size_t len = l->len;
665510 size_t pos = l->pos;
666511 struct abuf ab;
667512668668- while((pcollen+columnPos(buf,len,pos)) >= l->cols) {
669669- int chlen = nextCharLen(buf,len,0,NULL);
670670- buf += chlen;
671671- len -= chlen;
672672- pos -= chlen;
513513+ if (plen >= l->cols) {
514514+ len=0; // not enough room
515515+ plen = l->cols;
673516 }
674674- while (pcollen+columnPos(buf,len,len) > l->cols) {
675675- len -= prevCharLen(buf,len,len,NULL);
517517+518518+ while((plen+pos) >= l->cols && len>0) {
519519+ buf++;
520520+ len--;
521521+ pos--;
522522+ }
523523+ while (plen+len > l->cols && len>0) {
524524+ len--;
676525 }
677526678527 abInit(&ab);
679528 /* Cursor to left edge */
680680- snprintf(seq,sizeof(seq),"\r");
529529+ snprintf(seq,64,"\r");
681530 abAppend(&ab,seq,strlen(seq));
682682-683683- if (flags & REFRESH_WRITE) {
684684- /* Write the prompt and the current buffer content */
685685- abAppend(&ab,l->prompt,strlen(l->prompt));
686686- if (maskmode == 1) {
687687- while (len--) abAppend(&ab,"*",1);
688688- } else {
689689- abAppend(&ab,buf,len);
690690- }
691691- /* Show hits if any. */
692692- refreshShowHints(&ab,l,pcollen);
693693- }
694694-531531+ /* Write the prompt and the current buffer content */
532532+ abAppend(&ab,prompt,plen);
533533+ if (len > 0)
534534+ abAppend(&ab,buf,len);
535535+ /* Show hits if any. */
536536+ refreshShowHints(&ab,l,plen);
695537 /* Erase to right */
696696- snprintf(seq,sizeof(seq),"\x1b[0K");
538538+ snprintf(seq,64,"\x1b[0K");
697539 abAppend(&ab,seq,strlen(seq));
698698-699699- if (flags & REFRESH_WRITE) {
700700- /* Move cursor to original position. */
701701- snprintf(seq,sizeof(seq),"\r\x1b[%dC", (int)(columnPos(buf,len,pos)+pcollen));
702702- abAppend(&ab,seq,strlen(seq));
703703- }
704704-540540+ /* Move cursor to original position. */
541541+ snprintf(seq,64,"\r\x1b[%dC", (int)(pos+plen));
542542+ abAppend(&ab,seq,strlen(seq));
705543 if (write(fd,ab.b,ab.len) == -1) {} /* Can't recover from write error. */
706544 abFree(&ab);
707545}
···709547/* Multi line low level line refresh.
710548 *
711549 * Rewrite the currently edited line accordingly to the buffer content,
712712- * cursor position, and number of columns of the terminal.
713713- *
714714- * Flags is REFRESH_* macros. The function can just remove the old
715715- * prompt, just write it, or both. */
716716-static void refreshMultiLine(struct linenoiseState *l, int flags) {
550550+ * cursor position, and number of columns of the terminal. */
551551+static void refreshMultiLine(struct linenoiseState *l, const char *prompt) {
717552 char seq[64];
718718- size_t pcollen = promptTextColumnLen(l->prompt,strlen(l->prompt));
719719- int colpos = columnPosForMultiLine(l->buf, l->len, l->len, l->cols, pcollen);
720720- int colpos2; /* cursor column position. */
721721- int rows = (pcollen+colpos+l->cols-1)/l->cols; /* rows used by current buf. */
722722- int rpos = (pcollen+l->oldcolpos+l->cols)/l->cols; /* cursor relative row. */
553553+ int plen = strlen(prompt);
554554+ int rows = (plen+l->len+l->cols-1)/l->cols; /* rows used by current buf. */
555555+ int rpos = (plen+l->oldpos+l->cols)/l->cols; /* cursor relative row. */
723556 int rpos2; /* rpos after refresh. */
724557 int col; /* colum position, zero-based. */
725725- int old_rows = l->oldrows;
558558+ int old_rows = l->maxrows;
559559+ size_t pos = l->pos;
726560 int fd = l->ofd, j;
727561 struct abuf ab;
728562729729- l->oldrows = rows;
563563+ /* Update maxrows if needed. */
564564+ if (rows > (int)l->maxrows) l->maxrows = rows;
730565731566 /* First step: clear all the lines used before. To do so start by
732567 * going to the last row. */
733568 abInit(&ab);
734734-735735- if (flags & REFRESH_CLEAN) {
736736- if (old_rows-rpos > 0) {
737737- lndebug("go down %d", old_rows-rpos);
738738- snprintf(seq,64,"\x1b[%dB", old_rows-rpos);
739739- abAppend(&ab,seq,strlen(seq));
740740- }
741741-742742- /* Now for every row clear it, go up. */
743743- for (j = 0; j < old_rows-1; j++) {
744744- lndebug("clear+up");
745745- snprintf(seq,64,"\r\x1b[0K\x1b[1A");
746746- abAppend(&ab,seq,strlen(seq));
747747- }
569569+ if (old_rows-rpos > 0) {
570570+ lndebug("go down %d", old_rows-rpos);
571571+ snprintf(seq,64,"\x1b[%dB", old_rows-rpos);
572572+ abAppend(&ab,seq,strlen(seq));
748573 }
749574750750- if (flags & REFRESH_ALL) {
751751- /* Clean the top line. */
752752- lndebug("clear");
753753- snprintf(seq,64,"\r\x1b[0K");
575575+ /* Now for every row clear it, go up. */
576576+ for (j = 0; j < old_rows-1; j++) {
577577+ lndebug("clear+up");
578578+ snprintf(seq,64,"\r\x1b[0K\x1b[1A");
754579 abAppend(&ab,seq,strlen(seq));
755580 }
756581757757- /* Get column length to cursor position */
758758- colpos2 = columnPosForMultiLine(l->buf,l->len,l->pos,l->cols,pcollen);
582582+ /* Clean the top line. */
583583+ lndebug("clear");
584584+ snprintf(seq,64,"\r\x1b[0K");
585585+ abAppend(&ab,seq,strlen(seq));
759586760760- if (flags & REFRESH_WRITE) {
761761- /* Write the prompt and the current buffer content */
762762- abAppend(&ab,l->prompt,strlen(l->prompt));
763763- if (maskmode == 1) {
764764- unsigned int i;
765765- for (i = 0; i < l->len; i++) abAppend(&ab,"*",1);
766766- } else {
767767- abAppend(&ab,l->buf,l->len);
768768- }
587587+ /* Write the prompt and the current buffer content */
588588+ abAppend(&ab,prompt,strlen(prompt));
589589+ abAppend(&ab,l->buf,l->len);
769590770770- /* Show hits if any. */
771771- refreshShowHints(&ab,l,pcollen);
591591+ /* Show hits if any. */
592592+ refreshShowHints(&ab,l,plen);
772593773773- /* If we are at the very end of the screen with our prompt, we need to
774774- * emit a newline and move the prompt to the first column. */
775775- if (l->pos &&
776776- l->pos == l->len &&
777777- (colpos2+pcollen) % l->cols == 0)
778778- {
779779- lndebug("<newline>");
780780- abAppend(&ab,"\n",1);
781781- snprintf(seq,64,"\r");
782782- abAppend(&ab,seq,strlen(seq));
783783- rows++;
784784- if (rows > (int)l->oldrows) l->oldrows = rows;
785785- }
594594+ /* If we are at the very end of the screen with our prompt, we need to
595595+ * emit a newline and move the prompt to the first column. */
596596+ if (pos &&
597597+ pos == l->len &&
598598+ (pos+plen) % l->cols == 0)
599599+ {
600600+ lndebug("<newline>");
601601+ abAppend(&ab,"\n",1);
602602+ snprintf(seq,64,"\r");
603603+ abAppend(&ab,seq,strlen(seq));
604604+ rows++;
605605+ if (rows > (int)l->maxrows) l->maxrows = rows;
606606+ }
786607787787- /* Move cursor to right position. */
788788- rpos2 = (pcollen+colpos2+l->cols)/l->cols; /* Current cursor relative row */
789789- lndebug("rpos2 %d", rpos2);
790790-791791- /* Go up till we reach the expected positon. */
792792- if (rows-rpos2 > 0) {
793793- lndebug("go-up %d", rows-rpos2);
794794- snprintf(seq,64,"\x1b[%dA", rows-rpos2);
795795- abAppend(&ab,seq,strlen(seq));
796796- }
608608+ /* Move cursor to right position. */
609609+ rpos2 = (plen+pos+l->cols)/l->cols; /* current cursor relative row. */
610610+ lndebug("rpos2 %d", rpos2);
797611798798- /* Set column. */
799799- col = (pcollen+colpos2) % l->cols;
800800- lndebug("set col %d", 1+col);
801801- if (col)
802802- snprintf(seq,64,"\r\x1b[%dC", col);
803803- else
804804- snprintf(seq,64,"\r");
612612+ /* Go up till we reach the expected positon. */
613613+ if (rows-rpos2 > 0) {
614614+ lndebug("go-up %d", rows-rpos2);
615615+ snprintf(seq,64,"\x1b[%dA", rows-rpos2);
805616 abAppend(&ab,seq,strlen(seq));
806617 }
807618619619+ /* Set column. */
620620+ col = (plen+(int)pos) % (int)l->cols;
621621+ lndebug("set col %d", 1+col);
622622+ if (col)
623623+ snprintf(seq,64,"\r\x1b[%dC", col);
624624+ else
625625+ snprintf(seq,64,"\r");
626626+ abAppend(&ab,seq,strlen(seq));
627627+808628 lndebug("\n");
809809- l->oldcolpos = colpos2;
629629+ l->oldpos = pos;
810630811631 if (write(fd,ab.b,ab.len) == -1) {} /* Can't recover from write error. */
812632 abFree(&ab);
···814634815635/* Calls the two low level functions refreshSingleLine() or
816636 * refreshMultiLine() according to the selected mode. */
817817-static void refreshLineWithFlags(struct linenoiseState *l, int flags) {
637637+static void refreshLinePrompt(struct linenoiseState *l, const char *prompt) {
818638 if (mlmode)
819819- refreshMultiLine(l,flags);
639639+ refreshMultiLine(l, prompt);
820640 else
821821- refreshSingleLine(l,flags);
641641+ refreshSingleLine(l, prompt);
822642}
823643824824-/* Utility function to avoid specifying REFRESH_ALL all the times. */
825644static void refreshLine(struct linenoiseState *l) {
826826- refreshLineWithFlags(l,REFRESH_ALL);
827827-}
828828-829829-/* Hide the current line, when using the multiplexing API. */
830830-void linenoiseHide(struct linenoiseState *l) {
831831- if (mlmode)
832832- refreshMultiLine(l,REFRESH_CLEAN);
833833- else
834834- refreshSingleLine(l,REFRESH_CLEAN);
835835-}
836836-837837-/* Show the current line, when using the multiplexing API. */
838838-void linenoiseShow(struct linenoiseState *l) {
839839- if (l->in_completion) {
840840- refreshLineWithCompletion(l,NULL,REFRESH_WRITE);
841841- } else {
842842- refreshLineWithFlags(l,REFRESH_WRITE);
843843- }
645645+ refreshLinePrompt(l, l->prompt);
844646}
845647846648/* Insert the character 'c' at cursor current position.
847649 *
848650 * On error writing to the terminal -1 is returned, otherwise 0. */
849849-int linenoiseEditInsert(struct linenoiseState *l, const char *cbuf, int clen) {
850850- if (l->len+clen <= l->buflen) {
651651+int linenoiseEditInsert(struct linenoiseState *l, char c) {
652652+ if (l->len < l->buflen) {
851653 if (l->len == l->pos) {
852852- memcpy(&l->buf[l->pos],cbuf,clen);
853853- l->pos+=clen;
854854- l->len+=clen;;
654654+ l->buf[l->pos] = c;
655655+ l->pos++;
656656+ l->len++;
855657 l->buf[l->len] = '\0';
856856- if ((!mlmode && promptTextColumnLen(l->prompt,l->plen)+columnPos(l->buf,l->len,l->len) < l->cols && !hintsCallback)) {
658658+ if ((!mlmode && l->plen+l->len < l->cols && !hintsCallback)) {
857659 /* Avoid a full update of the line in the
858660 * trivial case. */
859859- if (maskmode == 1) {
860860- static const char d = '*';
861861- if (write(l->ofd,&d,1) == -1) return -1;
862862- } else {
863863- if (write(l->ofd,cbuf,clen) == -1) return -1;
864864- }
661661+ if (write(l->ofd,&c,1) == -1) return -1;
865662 } else {
866663 refreshLine(l);
867664 }
868665 } else {
869869- memmove(l->buf+l->pos+clen,l->buf+l->pos,l->len-l->pos);
870870- memcpy(&l->buf[l->pos],cbuf,clen);
871871- l->pos+=clen;
872872- l->len+=clen;
666666+ memmove(l->buf+l->pos+1,l->buf+l->pos,l->len-l->pos);
667667+ l->buf[l->pos] = c;
668668+ l->len++;
669669+ l->pos++;
873670 l->buf[l->len] = '\0';
874671 refreshLine(l);
875672 }
···880677/* Move cursor on the left. */
881678void linenoiseEditMoveLeft(struct linenoiseState *l) {
882679 if (l->pos > 0) {
883883- l->pos -= prevCharLen(l->buf,l->len,l->pos,NULL);
680680+ l->pos--;
884681 refreshLine(l);
885682 }
886683}
···888685/* Move cursor on the right. */
889686void linenoiseEditMoveRight(struct linenoiseState *l) {
890687 if (l->pos != l->len) {
891891- l->pos += nextCharLen(l->buf,l->len,l->pos,NULL);
688688+ l->pos++;
892689 refreshLine(l);
893690 }
894691}
895692693693+/* Move cursor on the left */
694694+void linenoiseEditMovePrevWord(struct linenoiseState *l) {
695695+ while (l->pos > 0 && l->buf[l->pos-1] == ' ')
696696+ l->pos--;
697697+ while (l->pos > 0 && l->buf[l->pos-1] != ' ')
698698+ l->pos--;
699699+ refreshLine(l);
700700+}
701701+702702+/* Move cursor on the right. */
703703+void linenoiseEditMoveNextWord(struct linenoiseState *l) {
704704+ while (l->pos < l->len && l->buf[l->pos-1] == ' ')
705705+ l->pos++;
706706+ while (l->pos < l->len && l->buf[l->pos-1] != ' ')
707707+ l->pos++;
708708+ refreshLine(l);
709709+}
710710+896711/* Move cursor to the start of the line. */
897712void linenoiseEditMoveHome(struct linenoiseState *l) {
898713 if (l->pos != 0) {
···939754 * position. Basically this is what happens with the "Delete" keyboard key. */
940755void linenoiseEditDelete(struct linenoiseState *l) {
941756 if (l->len > 0 && l->pos < l->len) {
942942- int chlen = nextCharLen(l->buf,l->len,l->pos,NULL);
943943- memmove(l->buf+l->pos,l->buf+l->pos+chlen,l->len-l->pos-chlen);
944944- l->len-=chlen;
757757+ memmove(l->buf+l->pos,l->buf+l->pos+1,l->len-l->pos-1);
758758+ l->len--;
945759 l->buf[l->len] = '\0';
946760 refreshLine(l);
947761 }
···950764/* Backspace implementation. */
951765void linenoiseEditBackspace(struct linenoiseState *l) {
952766 if (l->pos > 0 && l->len > 0) {
953953- int chlen = prevCharLen(l->buf,l->len,l->pos,NULL);
954954- memmove(l->buf+l->pos-chlen,l->buf+l->pos,l->len-l->pos);
955955- l->pos-=chlen;
956956- l->len-=chlen;
767767+ memmove(l->buf+l->pos-1,l->buf+l->pos,l->len-l->pos);
768768+ l->pos--;
769769+ l->len--;
957770 l->buf[l->len] = '\0';
958771 refreshLine(l);
959772 }
960773}
961774962962-/* Delete the previosu word, maintaining the cursor at the start of the
775775+/* Delete the previous word, maintaining the cursor at the start of the
963776 * current word. */
964777void linenoiseEditDeletePrevWord(struct linenoiseState *l) {
965778 size_t old_pos = l->pos;
···975788 refreshLine(l);
976789}
977790978978-/* This function is part of the multiplexed API of Linenoise, that is used
979979- * in order to implement the blocking variant of the API but can also be
980980- * called by the user directly in an event driven program. It will:
981981- *
982982- * 1. Initialize the linenoise state passed by the user.
983983- * 2. Put the terminal in RAW mode.
984984- * 3. Show the prompt.
985985- * 4. Return control to the user, that will have to call linenoiseEditFeed()
986986- * each time there is some data arriving in the standard input.
987987- *
988988- * The user can also call linenoiseEditHide() and linenoiseEditShow() if it
989989- * is required to show some input arriving asyncronously, without mixing
990990- * it with the currently edited line.
991991- *
992992- * When linenoiseEditFeed() returns non-NULL, the user finished with the
993993- * line editing session (pressed enter CTRL-D/C): in this case the caller
994994- * needs to call linenoiseEditStop() to put back the terminal in normal
995995- * mode. This will not destroy the buffer, as long as the linenoiseState
996996- * is still valid in the context of the caller.
997997- *
998998- * The function returns 0 on success, or -1 if writing to standard output
999999- * fails. If stdin_fd or stdout_fd are set to -1, the default is to use
10001000- * STDIN_FILENO and STDOUT_FILENO.
10011001- */
10021002-int linenoiseEditStart(struct linenoiseState *l, int stdin_fd, int stdout_fd, char *buf, size_t buflen, const char *prompt) {
10031003- /* Populate the linenoise state that we pass to functions implementing
10041004- * specific editing functionalities. */
10051005- l->in_completion = 0;
10061006- l->ifd = stdin_fd != -1 ? stdin_fd : STDIN_FILENO;
10071007- l->ofd = stdout_fd != -1 ? stdout_fd : STDOUT_FILENO;
10081008- l->buf = buf;
10091009- l->buflen = buflen;
10101010- l->prompt = prompt;
10111011- l->plen = strlen(prompt);
10121012- l->oldcolpos = l->pos = 0;
10131013- l->len = 0;
791791+/* Delete the next word, maintaining the cursor at the same position */
792792+void linenoiseEditDeleteNextWord(struct linenoiseState *l) {
793793+ size_t next_pos = l->pos;
794794+ size_t diff;
101479510151015- /* Enter raw mode. */
10161016- if (enableRawMode(l->ifd) == -1) return -1;
796796+ while (next_pos < l->len && l->buf[next_pos] == ' ')
797797+ next_pos++;
798798+ while (next_pos < l->len && l->buf[next_pos] != ' ')
799799+ next_pos++;
800800+ diff = next_pos - l->pos;
801801+ memmove(l->buf+l->pos,l->buf+next_pos,l->len-next_pos+1);
802802+ l->len -= diff;
803803+ refreshLine(l);
804804+}
101780510181018- l->cols = getColumns(stdin_fd, stdout_fd);
10191019- l->oldrows = 0;
10201020- l->history_index = 0;
806806+void linenoiseReverseIncrementalSearch(struct linenoiseState *l) {
102180710221022- /* Buffer starts empty. */
10231023- l->buf[0] = '\0';
10241024- l->buflen--; /* Make sure there is always space for the nulterm */
808808+ char search_buf[LINENOISE_MAX_LINE];
809809+ char search_prompt[LINENOISE_MAX_LINE];
810810+ int search_len = 0;
811811+ int search_pos = history_len - 1;
812812+ int search_dir = -1;
813813+ char* prompt;
102581410261026- /* If stdin is not a tty, stop here with the initialization. We
10271027- * will actually just read a line from standard input in blocking
10281028- * mode later, in linenoiseEditFeed(). */
10291029- if (!isatty(l->ifd)) return 0;
815815+ int has_match = 1;
103081610311031- /* The latest history entry is always our current buffer, that
10321032- * initially is just an empty string. */
10331033- linenoiseHistoryAdd("");
817817+ // backup of current input
818818+ char *buf;
819819+ {
820820+ size_t len = 1+ strlen(l->buf);
821821+ buf = malloc(len);
822822+ if (buf == NULL) return;
823823+ memcpy(buf, l->buf, len);
824824+ }
103482510351035- if (write(l->ofd,prompt,l->plen) == -1) return -1;
10361036- return 0;
10371037-}
826826+ search_buf[0] = 0;
827827+828828+ while (1) {
103882910391039-char *linenoiseEditMore = "If you see this, you are misusing the API: when linenoiseEditFeed() is called, if it returns linenoiseEditMore the user is yet editing the line. See the README file for more information.";
830830+ if (!has_match)
831831+ prompt = "(failed-reverse-i-search)`%s': ";
832832+ else
833833+ prompt = "(reverse-i-search)`%s': ";
104083410411041-/* This function is part of the multiplexed API of linenoise, see the top
10421042- * comment on linenoiseEditStart() for more information. Call this function
10431043- * each time there is some data to read from the standard input file
10441044- * descriptor. In the case of blocking operations, this function can just be
10451045- * called in a loop, and block.
10461046- *
10471047- * The function returns linenoiseEditMore to signal that line editing is still
10481048- * in progress, that is, the user didn't yet pressed enter / CTRL-D. Otherwise
10491049- * the function returns the pointer to the heap-allocated buffer with the
10501050- * edited line, that the user should free with linenoiseFree().
10511051- *
10521052- * On special conditions, NULL is returned and errno is populated:
10531053- *
10541054- * EAGAIN if the user pressed Ctrl-C
10551055- * ENOENT if the user pressed Ctrl-D
10561056- *
10571057- * Some other errno: I/O error.
10581058- */
10591059-char *linenoiseEditFeed(struct linenoiseState *l) {
10601060- /* Not a TTY, pass control to line reading without character
10611061- * count limits. */
10621062- if (!isatty(l->ifd)) return linenoiseNoTTY();
835835+ if (!snprintf(search_prompt, sizeof(search_prompt), prompt, search_buf)) {
836836+ linenoiseBeep();
837837+ break;
838838+ } else {
839839+ search_prompt[sizeof(search_prompt)-1] = 0; // crop
840840+ }
106384110641064- int c;
10651065- int nread;
10661066- char cbuf[32]; // large enough for any encoding?
10671067- char seq[3];
842842+ l->pos = 0;
843843+ refreshLinePrompt(l, search_prompt);
106884410691069- nread = readCode(l->ifd,cbuf,sizeof(cbuf),&c);
10701070- if (nread <= 0) return NULL;
845845+ char c;
846846+ int new_char = 0;
107184710721072- /* Only autocomplete when the callback is set. It returns < 0 when
10731073- * there was an error reading from fd. Otherwise it will return the
10741074- * character that should be handled next. */
10751075- if ((l->in_completion || c == 9) && completionCallback != NULL) {
10761076- c = completeLine(l,c);
10771077- /* Return on errors */
10781078- if (c < 0) return NULL;
10791079- /* Read next character when 0 */
10801080- if (c == 0) return linenoiseEditMore;
848848+ if (read(l->ifd, &c, 1) <= 0) {
849849+ l->pos = l->len = snprintf(l->buf, l->buflen, "%s", buf);
850850+ l->buf[l->buflen-1] = 0;
851851+ refreshLine(l);
852852+ free(buf);
853853+ return;
1081854 }
10828551083856 switch(c) {
10841084- case ENTER: /* enter */
10851085- history_len--;
10861086- free(history[history_len]);
10871087- if (mlmode) linenoiseEditMoveEnd(l);
10881088- if (hintsCallback) {
10891089- /* Force a refresh without hints to leave the previous
10901090- * line as the user typed it after a newline. */
10911091- linenoiseHintsCallback *hc = hintsCallback;
10921092- hintsCallback = NULL;
10931093- refreshLine(l);
10941094- hintsCallback = hc;
857857+ case BACKSPACE:
858858+ case CTRL_H:
859859+ if (search_len > 0) {
860860+ search_buf[--search_len] = 0;
861861+ search_pos = history_len - 1;
862862+ } else
863863+ linenoiseBeep();
864864+ break;
865865+ case CTRL_N:
866866+ case CTRL_R:
867867+ search_dir = -1;
868868+ if (search_pos >= history_len)
869869+ search_pos = history_len - 1;
870870+ break;
871871+ case CTRL_P:
872872+ search_dir = 1;
873873+ if (search_pos < 0)
874874+ search_pos = 0;
875875+ break;
876876+ case ESC:
877877+ case CTRL_G:
878878+ l->pos = l->len = snprintf(l->buf, l->buflen, "%s", buf);
879879+ l->buf[l->buflen-1] = 0;
880880+ free(buf);
881881+ refreshLine(l);
882882+ return;
883883+ case ENTER:
884884+ free(buf);
885885+ l->pos = l->len;
886886+ refreshLine(l);
887887+ return;
888888+ default:
889889+ new_char = 1;
890890+ search_buf[search_len] = c;
891891+ search_buf[++search_len] = 0;
892892+ search_pos = history_len - 1;
893893+ break;
894894+ }
895895+896896+ has_match = 0;
897897+898898+ if (strlen(search_buf) > 0) {
899899+ for (; search_pos >= 0 && search_pos < history_len; search_pos += search_dir) {
900900+ if (strstr(history[search_pos], search_buf) && (new_char || strcmp(history[search_pos], l->buf))) {
901901+ has_match = 1;
902902+ l->len = snprintf(l->buf, l->buflen, "%s", history[search_pos]);
903903+ break;
1095904 }
10961096- return strdup(l->buf);
10971097- case CTRL_C: /* ctrl-c */
10981098- errno = EAGAIN;
10991099- linenoiseWasInterrupted = 1;
11001100- return NULL;
11011101- case BACKSPACE: /* backspace */
11021102- case 8: /* ctrl-h */
11031103- linenoiseEditBackspace(l);
11041104- break;
11051105- case CTRL_D: /* ctrl-d, remove char at right of cursor, or if the
11061106- line is empty, act as end-of-file. */
11071107- if (l->len > 0) {
11081108- linenoiseEditDelete(l);
11091109- } else {
905905+ }
906906+ if (!has_match) {
907907+ linenoiseBeep();
908908+ // forbid writes if the line is too long
909909+ if (search_len > 0 && new_char && search_len+1 >= sizeof(search_buf))
910910+ search_buf[--search_len] = 0;
911911+ }
912912+ }
913913+ }
914914+}
915915+916916+/* This function is the core of the line editing capability of linenoise.
917917+ * It expects 'fd' to be already in "raw mode" so that every key pressed
918918+ * will be returned ASAP to read().
919919+ *
920920+ * The resulting string is put into 'buf' when the user type enter, or
921921+ * when ctrl+d is typed.
922922+ *
923923+ * The function returns the length of the current buffer. */
924924+static int linenoiseEdit(int stdin_fd, int stdout_fd, char *buf, size_t buflen, const char *prompt)
925925+{
926926+ struct linenoiseState l;
927927+928928+ /* Populate the linenoise state that we pass to functions implementing
929929+ * specific editing functionalities. */
930930+ l.ifd = stdin_fd;
931931+ l.ofd = stdout_fd;
932932+ l.buf = buf;
933933+ l.buflen = buflen;
934934+ l.prompt = prompt;
935935+ l.plen = strlen(prompt);
936936+ l.oldpos = l.pos = 0;
937937+ l.len = 0;
938938+ l.cols = getColumns(stdin_fd, stdout_fd);
939939+ l.maxrows = 0;
940940+ l.history_index = 0;
941941+942942+ /* Buffer starts empty. */
943943+ l.buf[0] = '\0';
944944+ l.buflen--; /* Make sure there is always space for the nulterm */
945945+946946+ /* The latest history entry is always our current buffer, that
947947+ * initially is just an empty string. */
948948+ linenoiseHistoryAdd("");
949949+950950+ if (write(l.ofd,prompt,l.plen) == -1) return -1;
951951+ while(1) {
952952+ char c;
953953+ int nread;
954954+ char seq[5];
955955+956956+ nread = read(l.ifd,&c,1);
957957+ if (nread <= 0) return l.len;
958958+959959+ /* Only autocomplete when the callback is set. It returns < 0 when
960960+ * there was an error reading from fd. Otherwise it will return the
961961+ * character that should be handled next. */
962962+ if (c == 9 && completionCallback != NULL) {
963963+ c = completeLine(&l);
964964+ /* Return on errors */
965965+ if (c < 0) return l.len;
966966+ /* Read next character when 0 */
967967+ if (c == 0) continue;
968968+ }
969969+970970+ switch(c) {
971971+ case ENTER: /* enter */
1110972 history_len--;
1111973 free(history[history_len]);
11121112- errno = ENOENT;
11131113- return NULL;
11141114- }
11151115- break;
11161116- case CTRL_T: /* ctrl-t, swaps current character with previous. */
11171117- if (l->pos > 0 && l->pos < l->len) {
11181118- int aux = l->buf[l->pos-1];
11191119- l->buf[l->pos-1] = l->buf[l->pos];
11201120- l->buf[l->pos] = aux;
11211121- if (l->pos != l->len-1) l->pos++;
11221122- refreshLine(l);
11231123- }
11241124- break;
11251125- case CTRL_B: /* ctrl-b */
11261126- linenoiseEditMoveLeft(l);
11271127- break;
11281128- case CTRL_F: /* ctrl-f */
11291129- linenoiseEditMoveRight(l);
11301130- break;
11311131- case CTRL_P: /* ctrl-p */
11321132- linenoiseEditHistoryNext(l, LINENOISE_HISTORY_PREV);
11331133- break;
11341134- case CTRL_N: /* ctrl-n */
11351135- linenoiseEditHistoryNext(l, LINENOISE_HISTORY_NEXT);
11361136- break;
11371137- case ESC: /* escape sequence */
11381138- /* Read the next two bytes representing the escape sequence.
11391139- * Use two calls to handle slow terminals returning the two
11401140- * chars at different times. */
11411141- if (read(l->ifd,seq,1) == -1) break;
11421142- if (read(l->ifd,seq+1,1) == -1) break;
974974+ if (mlmode) linenoiseEditMoveEnd(&l);
975975+ if (hintsCallback) {
976976+ /* Force a refresh without hints to leave the previous
977977+ * line as the user typed it after a newline. */
978978+ linenoiseHintsCallback *hc = hintsCallback;
979979+ hintsCallback = NULL;
980980+ refreshLine(&l);
981981+ hintsCallback = hc;
982982+ }
983983+ return (int)l.len;
984984+ case CTRL_C: /* ctrl-c */
985985+ errno = EAGAIN;
986986+ linenoiseWasInterrupted = 1;
987987+ return -1;
988988+ case BACKSPACE: /* backspace */
989989+ case 8: /* ctrl-h */
990990+ linenoiseEditBackspace(&l);
991991+ break;
992992+ case CTRL_D: /* ctrl-d, remove char at right of cursor, or if the
993993+ line is empty, act as end-of-file. */
994994+ if (l.len > 0) {
995995+ linenoiseEditDelete(&l);
996996+ } else {
997997+ history_len--;
998998+ free(history[history_len]);
999999+ return -1;
10001000+ }
10011001+ break;
10021002+ case CTRL_T: /* ctrl-t, swaps current character with previous. */
10031003+ if (l.pos > 0 && l.pos < l.len) {
10041004+ int aux = buf[l.pos-1];
10051005+ buf[l.pos-1] = buf[l.pos];
10061006+ buf[l.pos] = aux;
10071007+ if (l.pos != l.len-1) l.pos++;
10081008+ refreshLine(&l);
10091009+ }
10101010+ break;
10111011+ case CTRL_B: /* ctrl-b */
10121012+ linenoiseEditMoveLeft(&l);
10131013+ break;
10141014+ case CTRL_F: /* ctrl-f */
10151015+ linenoiseEditMoveRight(&l);
10161016+ break;
10171017+ case CTRL_P: /* ctrl-p */
10181018+ linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_PREV);
10191019+ break;
10201020+ case CTRL_R: /* ctrl-r */
10211021+ linenoiseReverseIncrementalSearch(&l);
10221022+ break;
10231023+ case CTRL_N: /* ctrl-n */
10241024+ linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_NEXT);
10251025+ break;
10261026+ case ESC: /* escape sequence */
10271027+ /* Read the next byte representing the escape sequence */
10281028+ if (read(l.ifd,seq,1) == -1) break;
1143102911441144- /* ESC [ sequences. */
11451145- if (seq[0] == '[') {
11461146- if (seq[1] >= '0' && seq[1] <= '9') {
11471147- /* Extended escape, read additional byte. */
11481148- if (read(l->ifd,seq+2,1) == -1) break;
11491149- if (seq[2] == '~') {
10301030+ /* alt-b, alt-f, alt-d, alt-backspace */
10311031+ if (seq[0] == 'b') {
10321032+ linenoiseEditMovePrevWord(&l);
10331033+ break;
10341034+ } else if (seq[0] == 'f') {
10351035+ linenoiseEditMoveNextWord(&l);
10361036+ break;
10371037+ } else if (seq[0] == 'd') {
10381038+ linenoiseEditDeleteNextWord(&l);
10391039+ break;
10401040+ } else if (seq[0] == 127) { /* backspace */
10411041+ linenoiseEditDeletePrevWord(&l);
10421042+ break;
10431043+ }
10441044+10451045+ /* Read a second byte */
10461046+ if (read(l.ifd,seq+1,1) == -1) break;
10471047+10481048+ /* ESC [ sequences. */
10491049+ if (seq[0] == '[') {
10501050+ if (seq[1] >= '0' && seq[1] <= '9') {
10511051+ /* Extended escape, read additional byte. */
10521052+ if (read(l.ifd,seq+2,1) == -1) break;
10531053+ if (seq[2] == '~') {
10541054+ switch(seq[1]) {
10551055+ case '3': /* Delete key. */
10561056+ linenoiseEditDelete(&l);
10571057+ break;
10581058+ }
10591059+ } else if (seq[2] == ';') {
10601060+ /* read additional 2 bytes */
10611061+ if (read(l.ifd,seq+3,1) == -1) break;
10621062+ if (read(l.ifd,seq+4,1) == -1) break;
10631063+ if (seq[3] == '5') {
10641064+ switch (seq[4]) {
10651065+ case 'D': /* ctrl-left */
10661066+ linenoiseEditMovePrevWord(&l);
10671067+ break;
10681068+ case 'C': /* ctrl-right */
10691069+ linenoiseEditMoveNextWord(&l);
10701070+ break;
10711071+ }
10721072+ }
10731073+ }
10741074+ } else {
11501075 switch(seq[1]) {
11511151- case '3': /* Delete key. */
11521152- linenoiseEditDelete(l);
10761076+ case 'A': /* Up */
10771077+ linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_PREV);
10781078+ break;
10791079+ case 'B': /* Down */
10801080+ linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_NEXT);
10811081+ break;
10821082+ case 'C': /* Right */
10831083+ linenoiseEditMoveRight(&l);
10841084+ break;
10851085+ case 'D': /* Left */
10861086+ linenoiseEditMoveLeft(&l);
10871087+ break;
10881088+ case 'H': /* Home */
10891089+ linenoiseEditMoveHome(&l);
10901090+ break;
10911091+ case 'F': /* End*/
10921092+ linenoiseEditMoveEnd(&l);
11531093 break;
11541094 }
11551095 }
11561156- } else {
10961096+ }
10971097+10981098+ /* ESC O sequences. */
10991099+ else if (seq[0] == 'O') {
11571100 switch(seq[1]) {
11581158- case 'A': /* Up */
11591159- linenoiseEditHistoryNext(l, LINENOISE_HISTORY_PREV);
11601160- break;
11611161- case 'B': /* Down */
11621162- linenoiseEditHistoryNext(l, LINENOISE_HISTORY_NEXT);
11631163- break;
11641164- case 'C': /* Right */
11651165- linenoiseEditMoveRight(l);
11661166- break;
11671167- case 'D': /* Left */
11681168- linenoiseEditMoveLeft(l);
11691169- break;
11701101 case 'H': /* Home */
11711171- linenoiseEditMoveHome(l);
11021102+ linenoiseEditMoveHome(&l);
11721103 break;
11731104 case 'F': /* End*/
11741174- linenoiseEditMoveEnd(l);
11051105+ linenoiseEditMoveEnd(&l);
11751106 break;
11761107 }
11771108 }
11781178- }
11791179-11801180- /* ESC O sequences. */
11811181- else if (seq[0] == 'O') {
11821182- switch(seq[1]) {
11831183- case 'H': /* Home */
11841184- linenoiseEditMoveHome(l);
11851185- break;
11861186- case 'F': /* End*/
11871187- linenoiseEditMoveEnd(l);
11881188- break;
11891189- }
11091109+ break;
11101110+ default:
11111111+ if (linenoiseEditInsert(&l,c)) return -1;
11121112+ break;
11131113+ case CTRL_U: /* Ctrl+u, delete the whole line. */
11141114+ buf[0] = '\0';
11151115+ l.pos = l.len = 0;
11161116+ refreshLine(&l);
11171117+ break;
11181118+ case CTRL_K: /* Ctrl+k, delete from current to end of line. */
11191119+ buf[l.pos] = '\0';
11201120+ l.len = l.pos;
11211121+ refreshLine(&l);
11221122+ break;
11231123+ case CTRL_A: /* Ctrl+a, go to the start of the line */
11241124+ linenoiseEditMoveHome(&l);
11251125+ break;
11261126+ case CTRL_E: /* ctrl+e, go to the end of the line */
11271127+ linenoiseEditMoveEnd(&l);
11281128+ break;
11291129+ case CTRL_L: /* ctrl+l, clear screen */
11301130+ linenoiseClearScreen();
11311131+ refreshLine(&l);
11321132+ break;
11331133+ case CTRL_W: /* ctrl+w, delete previous word */
11341134+ linenoiseEditDeletePrevWord(&l);
11351135+ break;
11901136 }
11911191- break;
11921192- default:
11931193- if (linenoiseEditInsert(l,cbuf,nread)) return NULL;
11941194- break;
11951195- case CTRL_U: /* Ctrl+u, delete the whole line. */
11961196- l->buf[0] = '\0';
11971197- l->pos = l->len = 0;
11981198- refreshLine(l);
11991199- break;
12001200- case CTRL_K: /* Ctrl+k, delete from current to end of line. */
12011201- l->buf[l->pos] = '\0';
12021202- l->len = l->pos;
12031203- refreshLine(l);
12041204- break;
12051205- case CTRL_A: /* Ctrl+a, go to the start of the line */
12061206- linenoiseEditMoveHome(l);
12071207- break;
12081208- case CTRL_E: /* ctrl+e, go to the end of the line */
12091209- linenoiseEditMoveEnd(l);
12101210- break;
12111211- case CTRL_L: /* ctrl+l, clear screen */
12121212- linenoiseClearScreen();
12131213- refreshLine(l);
12141214- break;
12151215- case CTRL_W: /* ctrl+w, delete previous word */
12161216- linenoiseEditDeletePrevWord(l);
12171217- break;
12181137 }
12191219- return linenoiseEditMore;
12201220-}
12211221-12221222-/* This is part of the multiplexed linenoise API. See linenoiseEditStart()
12231223- * for more information. This function is called when linenoiseEditFeed()
12241224- * returns something different than NULL. At this point the user input
12251225- * is in the buffer, and we can restore the terminal in normal mode. */
12261226-void linenoiseEditStop(struct linenoiseState *l) {
12271227- if (!isatty(l->ifd)) return;
12281228- disableRawMode(l->ifd);
12291229- printf("\n");
12301230-}
12311231-12321232-/* This just implements a blocking loop for the multiplexed API.
12331233- * In many applications that are not event-drivern, we can just call
12341234- * the blocking linenoise API, wait for the user to complete the editing
12351235- * and return the buffer. */
12361236-static char *linenoiseBlockingEdit(int stdin_fd, int stdout_fd, char *buf, size_t buflen, const char *prompt)
12371237-{
12381238- struct linenoiseState l;
12391239-12401240- /* Editing without a buffer is invalid. */
12411241- if (buflen == 0) {
12421242- errno = EINVAL;
12431243- return NULL;
12441244- }
12451245-12461246- linenoiseEditStart(&l,stdin_fd,stdout_fd,buf,buflen,prompt);
12471247- char *res;
12481248- while((res = linenoiseEditFeed(&l)) == linenoiseEditMore);
12491249- linenoiseEditStop(&l);
12501250- return res;
11381138+ return l.len;
12511139}
1252114012531141/* This special mode is used by linenoise in order to print scan codes
···12711159 if (memcmp(quit,"quit",sizeof(quit)) == 0) break;
1272116012731161 printf("'%c' %02x (%d) (type quit to exit)\n",
12741274- isprint((int)c) ? c : '?', (int)c, (int)c);
11621162+ isprint(c) ? c : '?', (int)c, (int)c);
12751163 printf("\r"); /* Go left edge manually, we are in raw mode. */
12761164 fflush(stdout);
12771165 }
12781166 disableRawMode(STDIN_FILENO);
12791167}
1280116811691169+/* This function calls the line editing function linenoiseEdit() using
11701170+ * the STDIN file descriptor set in raw mode. */
11711171+static int linenoiseRaw(char *buf, size_t buflen, const char *prompt) {
11721172+ int count;
11731173+11741174+ if (buflen == 0) {
11751175+ errno = EINVAL;
11761176+ return -1;
11771177+ }
11781178+11791179+ if (enableRawMode(STDIN_FILENO) == -1) return -1;
11801180+ count = linenoiseEdit(STDIN_FILENO, STDOUT_FILENO, buf, buflen, prompt);
11811181+ disableRawMode(STDIN_FILENO);
11821182+ printf("\n");
11831183+ return count;
11841184+}
11851185+12811186/* This function is called when linenoise() is called with the standard
12821187 * input file descriptor not attached to a TTY. So for example when the
12831188 * program using linenoise is called in pipe or with a file redirected
···13211226 * something even in the most desperate of the conditions. */
13221227char *linenoise(const char *prompt) {
13231228 char buf[LINENOISE_MAX_LINE];
12291229+ int count;
1324123013251231 if (!isatty(STDIN_FILENO)) {
13261232 /* Not a tty: read from file / pipe. In this mode we don't want any
···13391245 }
13401246 return strdup(buf);
13411247 } else {
13421342- char *retval = linenoiseBlockingEdit(STDIN_FILENO,STDOUT_FILENO,buf,LINENOISE_MAX_LINE,prompt);
13431343- return retval;
12481248+ count = linenoiseRaw(buf,LINENOISE_MAX_LINE,prompt);
12491249+ if (count == -1) return NULL;
12501250+ return strdup(buf);
13441251 }
13451252}
13461253···13491256 * created with. Useful when the main program is using an alternative
13501257 * allocator. */
13511258void linenoiseFree(void *ptr) {
13521352- if (ptr == linenoiseEditMore) return; // Protect from API misuse.
13531259 free(ptr);
13541260}
13551261
+3-51
vendor/ocaml-linenoise/src/linenoise_src.h
···77 *
88 * ------------------------------------------------------------------------
99 *
1010- * Copyright (c) 2010-2023, Salvatore Sanfilippo <antirez at gmail dot com>
1010+ * Copyright (c) 2010-2014, Salvatore Sanfilippo <antirez at gmail dot com>
1111 * Copyright (c) 2010-2013, Pieter Noordhuis <pcnoordhuis at gmail dot com>
1212 *
1313 * All rights reserved.
···4343extern "C" {
4444#endif
45454646-#include <stddef.h> /* For size_t. */
4747-4846extern int linenoiseWasInterrupted; /* boolean signalling if last call was ctrl-c */
4949-extern char *linenoiseEditMore;
5050-5151-/* The linenoiseState structure represents the state during line editing.
5252- * We pass this state to functions implementing specific editing
5353- * functionalities. */
5454-struct linenoiseState {
5555- int in_completion; /* The user pressed TAB and we are now in completion
5656- * mode, so input is handled by completeLine(). */
5757- size_t completion_idx; /* Index of next completion to propose. */
5858- int ifd; /* Terminal stdin file descriptor. */
5959- int ofd; /* Terminal stdout file descriptor. */
6060- char *buf; /* Edited line buffer. */
6161- size_t buflen; /* Edited line buffer size. */
6262- const char *prompt; /* Prompt to display. */
6363- size_t plen; /* Prompt length. */
6464- size_t pos; /* Current cursor position. */
6565- size_t oldcolpos; /* Previous refresh cursor column position. */
6666- size_t len; /* Current edited line length. */
6767- size_t cols; /* Number of columns in terminal. */
6868- size_t oldrows; /* Rows used by last refrehsed line (multiline mode) */
6969- int history_index; /* The history index we are currently editing. */
7070-};
71477248typedef struct linenoiseCompletions {
7349 size_t len;
7450 char **cvec;
7551} linenoiseCompletions;
76527777-/* Non blocking API. */
7878-int linenoiseEditStart(struct linenoiseState *l, int stdin_fd, int stdout_fd, char *buf, size_t buflen, const char *prompt);
7979-char *linenoiseEditFeed(struct linenoiseState *l);
8080-void linenoiseEditStop(struct linenoiseState *l);
8181-void linenoiseHide(struct linenoiseState *l);
8282-void linenoiseShow(struct linenoiseState *l);
8383-8484-/* Blocking API. */
8585-char *linenoise(const char *prompt);
8686-void linenoiseFree(void *ptr);
8787-8888-/* Completion API. */
8953typedef void(linenoiseCompletionCallback)(const char *, linenoiseCompletions *);
9054typedef char*(linenoiseHintsCallback)(const char *, int *color, int *bold);
9155typedef void(linenoiseFreeHintsCallback)(void *);
···9458void linenoiseSetFreeHintsCallback(linenoiseFreeHintsCallback *);
9559void linenoiseAddCompletion(linenoiseCompletions *, const char *);
96609797-/* History API. */
6161+char *linenoise(const char *prompt);
6262+void linenoiseFree(void *ptr);
9863int linenoiseHistoryAdd(const char *line);
9964int linenoiseHistorySetMaxLen(int len);
10065int linenoiseHistorySave(const char *filename);
10166int linenoiseHistoryLoad(const char *filename);
102102-103103-/* Other utilities. */
10467void linenoiseClearScreen(void);
10568void linenoiseSetMultiLine(int ml);
10669void linenoisePrintKeyCodes(void);
107107-void linenoiseMaskModeEnable(void);
108108-void linenoiseMaskModeDisable(void);
109109-110110-typedef size_t (linenoisePrevCharLen)(const char *buf, size_t buf_len, size_t pos, size_t *col_len);
111111-typedef size_t (linenoiseNextCharLen)(const char *buf, size_t buf_len, size_t pos, size_t *col_len);
112112-typedef size_t (linenoiseReadCode)(int fd, char *buf, size_t buf_len, int* c);
113113-114114-void linenoiseSetEncodingFunctions(
115115- linenoisePrevCharLen *prevCharLenFunc,
116116- linenoiseNextCharLen *nextCharLenFunc,
117117- linenoiseReadCode *readCodeFunc);
1187011971#ifdef __cplusplus
12072}