on master help sign in
Merge pull request #16 from replit/mc-betterline

ditch linenoise for chzyer/readline

commit879cc6d29ff7930faf0b6d62d76aae59f60ab633 authorMason Clayton <mason@turb.io> dateTue 5 Mar 2019, 22:10 (8 years ago) parentb5d13088c6fa14
49 files changed+5120−1541
Gopkg.lock+15 Gopkg.toml+34 Makefile+1−1 linenoise/linenoise-helper.c−10 linenoise/linenoise.c−1201 linenoise/linenoise.go−79 linenoise/linenoise.h−73 tests/lua/own_eval.exp−51 tests/tcl/1_plus_1.exp+11−11 tests/tcl/a_few_outputs.exp+44−40 tests/tcl/from_file.exp+15−15 tests/tcl/input_output.exp+38−38 tests/tcl/status_line.exp−6 tests/tcl/unknown_command.exp+9−9 utils/language.go+3−3 utils/utils.go−4 vendor/github.com/chzyer/readline/.gitignore+2 vendor/github.com/chzyer/readline/.travis.yml+10 vendor/github.com/chzyer/readline/CHANGELOG.md+58 vendor/github.com/chzyer/readline/LICENSE+22 vendor/github.com/chzyer/readline/README.md+306 vendor/github.com/chzyer/readline/ansi_windows.go+246 vendor/github.com/chzyer/readline/char.go+36 vendor/github.com/chzyer/readline/complete.go+273 vendor/github.com/chzyer/readline/complete_helper.go+165 vendor/github.com/chzyer/readline/complete_segment.go+82 vendor/github.com/chzyer/readline/debug.go+29 vendor/github.com/chzyer/readline/doc.go+20 vendor/github.com/chzyer/readline/history.go+296 vendor/github.com/chzyer/readline/operation.go+479 vendor/github.com/chzyer/readline/password.go+32 vendor/github.com/chzyer/readline/rawreader_windows.go+125 vendor/github.com/chzyer/readline/readline.go+257 vendor/github.com/chzyer/readline/remote.go+474 vendor/github.com/chzyer/readline/runebuf.go+500 vendor/github.com/chzyer/readline/runes.go+167 vendor/github.com/chzyer/readline/search.go+160 vendor/github.com/chzyer/readline/std.go+66 vendor/github.com/chzyer/readline/std_windows.go+9 vendor/github.com/chzyer/readline/term.go+134 vendor/github.com/chzyer/readline/term_bsd.go+12 vendor/github.com/chzyer/readline/term_linux.go+11 vendor/github.com/chzyer/readline/term_windows.go+171 vendor/github.com/chzyer/readline/terminal.go+175 vendor/github.com/chzyer/readline/utils.go+176 vendor/github.com/chzyer/readline/utils_unix.go+90 vendor/github.com/chzyer/readline/utils_windows.go+41 vendor/github.com/chzyer/readline/vim.go+174 vendor/github.com/chzyer/readline/windows_api.go+152
Gopkg.locknew file+15
@@ -0,0 +1,15 @@
1+# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
2+
3+
4+[[projects]]
5+ name = "github.com/chzyer/readline"
6+ packages = ["."]
7+ revision = "62c6fe6193755f722b8b8788aa7357be55a50ff1"
8+ version = "v1.4"
9+
10+[solve-meta]
11+ analyzer-name = "dep"
12+ analyzer-version = 1
13+ inputs-digest = "134182782113b3aa4d31f698080384b3df68b854832f1c2ba862015a17b52654"
14+ solver-name = "gps-cdcl"
15+ solver-version = 1
Gopkg.tomlnew file+34
@@ -0,0 +1,34 @@
1+# Gopkg.toml example
2+#
3+# Refer to https://golang.github.io/dep/docs/Gopkg.toml.html
4+# for detailed Gopkg.toml documentation.
5+#
6+# required = ["github.com/user/thing/cmd/thing"]
7+# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
8+#
9+# [[constraint]]
10+# name = "github.com/user/project"
11+# version = "1.0.0"
12+#
13+# [[constraint]]
14+# name = "github.com/user/project2"
15+# branch = "dev"
16+# source = "github.com/myfork/project2"
17+#
18+# [[override]]
19+# name = "github.com/x/y"
20+# version = "2.4.0"
21+#
22+# [prune]
23+# non-go = false
24+# go-tests = true
25+# unused-packages = true
26+
27+
28+[[constraint]]
29+ name = "github.com/chzyer/readline"
30+ version = "1.4.0"
31+
32+[prune]
33+ go-tests = true
34+ unused-packages = true
Makefile+1−1
@@ -6,7 +6,7 @@ BINS := $(addprefix prybar-,$(LANGS))
66
77all: $(BINS)
88
9−prybar-%: ./languages/$(*) ./utils/* ./linenoise/* ./languages/$(*)/*
9+prybar-%: ./languages/$(*) ./utils/* ./languages/$(*)/*
1010 ./scripts/inject.sh $(*)
1111 go generate ./languages/$(*)/main.go
1212 go build -o prybar-$(*) ./languages/$(*)
linenoise/linenoise-helper.cdeleted−10
@@ -1,10 +0,0 @@
1−#include <stdlib.h>
2−#include <linenoise.h>
3−
4−void linenoiseCompletionStub(const char *, linenoiseCompletions *);
5−void linenoiseHintsStub(const char *, int *color, int *bold);
6−
7−void linenoise_setup() {
8− linenoiseSetCompletionCallback(linenoiseCompletionStub);
9− linenoiseSetHintsCallback(linenoiseHintsStub);
10−}
linenoise/linenoise.cdeleted−1201
@@ -1,1201 +0,0 @@
1−/* linenoise.c -- guerrilla line editing library against the idea that a
2− * line editing lib needs to be 20,000 lines of C code.
3− *
4− * You can find the latest source code at:
5− *
6− * http://github.com/antirez/linenoise
7− *
8− * Does a number of crazy assumptions that happen to be true in 99.9999% of
9− * the 2010 UNIX computers around.
10− *
11− * ------------------------------------------------------------------------
12− *
13− * Copyright (c) 2010-2016, Salvatore Sanfilippo <antirez at gmail dot com>
14− * Copyright (c) 2010-2013, Pieter Noordhuis <pcnoordhuis at gmail dot com>
15− *
16− * All rights reserved.
17− *
18− * Redistribution and use in source and binary forms, with or without
19− * modification, are permitted provided that the following conditions are
20− * met:
21− *
22− * * Redistributions of source code must retain the above copyright
23− * notice, this list of conditions and the following disclaimer.
24− *
25− * * Redistributions in binary form must reproduce the above copyright
26− * notice, this list of conditions and the following disclaimer in the
27− * documentation and/or other materials provided with the distribution.
28− *
29− * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
30− * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
31− * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
32− * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
33− * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
34− * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
35− * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
36− * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
37− * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
38− * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
39− * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40− *
41− * ------------------------------------------------------------------------
42− *
43− * References:
44− * - http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
45− * - http://www.3waylabs.com/nw/WWW/products/wizcon/vt220.html
46− *
47− * Todo list:
48− * - Filter bogus Ctrl+<char> combinations.
49− * - Win32 support
50− *
51− * Bloat:
52− * - History search like Ctrl+r in readline?
53− *
54− * List of escape sequences used by this program, we do everything just
55− * with three sequences. In order to be so cheap we may have some
56− * flickering effect with some slow terminal, but the lesser sequences
57− * the more compatible.
58− *
59− * EL (Erase Line)
60− * Sequence: ESC [ n K
61− * Effect: if n is 0 or missing, clear from cursor to end of line
62− * Effect: if n is 1, clear from beginning of line to cursor
63− * Effect: if n is 2, clear entire line
64− *
65− * CUF (CUrsor Forward)
66− * Sequence: ESC [ n C
67− * Effect: moves cursor forward n chars
68− *
69− * CUB (CUrsor Backward)
70− * Sequence: ESC [ n D
71− * Effect: moves cursor backward n chars
72− *
73− * The following is used to get the terminal width if getting
74− * the width with the TIOCGWINSZ ioctl fails
75− *
76− * DSR (Device Status Report)
77− * Sequence: ESC [ 6 n
78− * Effect: reports the current cusor position as ESC [ n ; m R
79− * where n is the row and m is the column
80− *
81− * When multi line mode is enabled, we also use an additional escape
82− * sequence. However multi line editing is disabled by default.
83− *
84− * CUU (Cursor Up)
85− * Sequence: ESC [ n A
86− * Effect: moves cursor up of n chars.
87− *
88− * CUD (Cursor Down)
89− * Sequence: ESC [ n B
90− * Effect: moves cursor down of n chars.
91− *
92− * When linenoiseClearScreen() is called, two additional escape sequences
93− * are used in order to clear the screen and position the cursor at home
94− * position.
95− *
96− * CUP (Cursor position)
97− * Sequence: ESC [ H
98− * Effect: moves the cursor to upper left corner
99− *
100− * ED (Erase display)
101− * Sequence: ESC [ 2 J
102− * Effect: clear the whole screen
103− *
104− */
105−
106−#include <termios.h>
107−#include <unistd.h>
108−#include <stdlib.h>
109−#include <stdio.h>
110−#include <errno.h>
111−#include <string.h>
112−#include <stdlib.h>
113−#include <ctype.h>
114−#include <sys/stat.h>
115−#include <sys/types.h>
116−#include <sys/ioctl.h>
117−#include <unistd.h>
118−#include "linenoise.h"
119−
120−#define LINENOISE_DEFAULT_HISTORY_MAX_LEN 100
121−#define LINENOISE_MAX_LINE 4096
122−static char *unsupported_term[] = {"dumb","cons25","emacs",NULL};
123−static linenoiseCompletionCallback *completionCallback = NULL;
124−static linenoiseHintsCallback *hintsCallback = NULL;
125−static linenoiseFreeHintsCallback *freeHintsCallback = NULL;
126−
127−static struct termios orig_termios; /* In order to restore at exit.*/
128−static int rawmode = 0; /* For atexit() function to check if restore is needed*/
129−static int mlmode = 0; /* Multi line mode. Default is single line. */
130−static int atexit_registered = 0; /* Register atexit just 1 time. */
131−static int history_max_len = LINENOISE_DEFAULT_HISTORY_MAX_LEN;
132−static int history_len = 0;
133−static char **history = NULL;
134−
135−/* The linenoiseState structure represents the state during line editing.
136− * We pass this state to functions implementing specific editing
137− * functionalities. */
138−struct linenoiseState {
139− int ifd; /* Terminal stdin file descriptor. */
140− int ofd; /* Terminal stdout file descriptor. */
141− char *buf; /* Edited line buffer. */
142− size_t buflen; /* Edited line buffer size. */
143− const char *prompt; /* Prompt to display. */
144− size_t plen; /* Prompt length. */
145− size_t pos; /* Current cursor position. */
146− size_t oldpos; /* Previous refresh cursor position. */
147− size_t len; /* Current edited line length. */
148− size_t cols; /* Number of columns in terminal. */
149− size_t maxrows; /* Maximum num of rows used so far (multiline mode) */
150− int history_index; /* The history index we are currently editing. */
151−};
152−
153−enum KEY_ACTION{
154− KEY_NULL = 0, /* NULL */
155− CTRL_A = 1, /* Ctrl+a */
156− CTRL_B = 2, /* Ctrl-b */
157− CTRL_C = 3, /* Ctrl-c */
158− CTRL_D = 4, /* Ctrl-d */
159− CTRL_E = 5, /* Ctrl-e */
160− CTRL_F = 6, /* Ctrl-f */
161− CTRL_H = 8, /* Ctrl-h */
162− TAB = 9, /* Tab */
163− CTRL_K = 11, /* Ctrl+k */
164− CTRL_L = 12, /* Ctrl+l */
165− ENTER = 13, /* Enter */
166− CTRL_N = 14, /* Ctrl-n */
167− CTRL_P = 16, /* Ctrl-p */
168− CTRL_T = 20, /* Ctrl-t */
169− CTRL_U = 21, /* Ctrl+u */
170− CTRL_W = 23, /* Ctrl+w */
171− ESC = 27, /* Escape */
172− BACKSPACE = 127 /* Backspace */
173−};
174−
175−static void linenoiseAtExit(void);
176−int linenoiseHistoryAdd(const char *line);
177−static void refreshLine(struct linenoiseState *l);
178−
179−/* Debugging macro. */
180−#if 0
181−FILE *lndebug_fp = NULL;
182−#define lndebug(...) \
183− do { \
184− if (lndebug_fp == NULL) { \
185− lndebug_fp = fopen("/tmp/lndebug.txt","a"); \
186− fprintf(lndebug_fp, \
187− "[%d %d %d] p: %d, rows: %d, rpos: %d, max: %d, oldmax: %d\n", \
188− (int)l->len,(int)l->pos,(int)l->oldpos,plen,rows,rpos, \
189− (int)l->maxrows,old_rows); \
190− } \
191− fprintf(lndebug_fp, ", " __VA_ARGS__); \
192− fflush(lndebug_fp); \
193− } while (0)
194−#else
195−#define lndebug(fmt, ...)
196−#endif
197−
198−/* ======================= Low level terminal handling ====================== */
199−
200−/* Set if to use or not the multi line mode. */
201−void linenoiseSetMultiLine(int ml) {
202− mlmode = ml;
203−}
204−
205−/* Return true if the terminal name is in the list of terminals we know are
206− * not able to understand basic escape sequences. */
207−static int isUnsupportedTerm(void) {
208− char *term = getenv("TERM");
209− int j;
210−
211− if (term == NULL) return 0;
212− for (j = 0; unsupported_term[j]; j++)
213− if (!strcasecmp(term,unsupported_term[j])) return 1;
214− return 0;
215−}
216−
217−/* Raw mode: 1960 magic shit. */
218−static int enableRawMode(int fd) {
219− struct termios raw;
220−
221− if (!isatty(STDIN_FILENO)) goto fatal;
222− if (!atexit_registered) {
223− atexit(linenoiseAtExit);
224− atexit_registered = 1;
225− }
226− if (tcgetattr(fd,&orig_termios) == -1) goto fatal;
227−
228− raw = orig_termios; /* modify the original mode */
229− /* input modes: no break, no CR to NL, no parity check, no strip char,
230− * no start/stop output control. */
231− raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
232− /* output modes - disable post processing */
233− raw.c_oflag &= ~(OPOST);
234− /* control modes - set 8 bit chars */
235− raw.c_cflag |= (CS8);
236− /* local modes - choing off, canonical off, no extended functions,
237− * no signal chars (^Z,^C) */
238− raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
239− /* control chars - set return condition: min number of bytes and timer.
240− * We want read to return every single byte, without timeout. */
241− raw.c_cc[VMIN] = 1; raw.c_cc[VTIME] = 0; /* 1 byte, no timer */
242−
243− /* put terminal in raw mode after flushing */
244− if (tcsetattr(fd,TCSAFLUSH,&raw) < 0) goto fatal;
245− rawmode = 1;
246− return 0;
247−
248−fatal:
249− errno = ENOTTY;
250− return -1;
251−}
252−
253−static void disableRawMode(int fd) {
254− /* Don't even check the return value as it's too late. */
255− if (rawmode && tcsetattr(fd,TCSAFLUSH,&orig_termios) != -1)
256− rawmode = 0;
257−}
258−
259−/* Use the ESC [6n escape sequence to query the horizontal cursor position
260− * and return it. On error -1 is returned, on success the position of the
261− * cursor. */
262−static int getCursorPosition(int ifd, int ofd) {
263− char buf[32];
264− int cols, rows;
265− unsigned int i = 0;
266−
267− /* Report cursor location */
268− if (write(ofd, "\x1b[6n", 4) != 4) return -1;
269−
270− /* Read the response: ESC [ rows ; cols R */
271− while (i < sizeof(buf)-1) {
272− if (read(ifd,buf+i,1) != 1) break;
273− if (buf[i] == 'R') break;
274− i++;
275− }
276− buf[i] = '\0';
277−
278− /* Parse it. */
279− if (buf[0] != ESC || buf[1] != '[') return -1;
280− if (sscanf(buf+2,"%d;%d",&rows,&cols) != 2) return -1;
281− return cols;
282−}
283−
284−/* Try to get the number of columns in the current terminal, or assume 80
285− * if it fails. */
286−static int getColumns(int ifd, int ofd) {
287− struct winsize ws;
288−
289− if (ioctl(1, TIOCGWINSZ, &ws) == -1 || ws.ws_col == 0) {
290− /* ioctl() failed. Try to query the terminal itself. */
291− int start, cols;
292−
293− /* Get the initial position so we can restore it later. */
294− start = getCursorPosition(ifd,ofd);
295− if (start == -1) goto failed;
296−
297− /* Go to right margin and get position. */
298− if (write(ofd,"\x1b[999C",6) != 6) goto failed;
299− cols = getCursorPosition(ifd,ofd);
300− if (cols == -1) goto failed;
301−
302− /* Restore position. */
303− if (cols > start) {
304− char seq[32];
305− snprintf(seq,32,"\x1b[%dD",cols-start);
306− if (write(ofd,seq,strlen(seq)) == -1) {
307− /* Can't recover... */
308− }
309− }
310− return cols;
311− } else {
312− return ws.ws_col;
313− }
314−
315−failed:
316− return 80;
317−}
318−
319−/* Clear the screen. Used to handle ctrl+l */
320−void linenoiseClearScreen(void) {
321− if (write(STDOUT_FILENO,"\x1b[H\x1b[2J",7) <= 0) {
322− /* nothing to do, just to avoid warning. */
323− }
324−}
325−
326−/* Beep, used for completion when there is nothing to complete or when all
327− * the choices were already shown. */
328−static void linenoiseBeep(void) {
329− fprintf(stderr, "\x7");
330− fflush(stderr);
331−}
332−
333−/* ============================== Completion ================================ */
334−
335−/* Free a list of completion option populated by linenoiseAddCompletion(). */
336−static void freeCompletions(linenoiseCompletions *lc) {
337− size_t i;
338− for (i = 0; i < lc->len; i++)
339− free(lc->cvec[i]);
340− if (lc->cvec != NULL)
341− free(lc->cvec);
342−}
343−
344−/* This is an helper function for linenoiseEdit() and is called when the
345− * user types the <tab> key in order to complete the string currently in the
346− * input.
347− *
348− * The state of the editing is encapsulated into the pointed linenoiseState
349− * structure as described in the structure definition. */
350−static int completeLine(struct linenoiseState *ls) {
351− linenoiseCompletions lc = { 0, NULL };
352− int nread, nwritten;
353− char c = 0;
354−
355− completionCallback(ls->buf,&lc);
356− if (lc.len == 0) {
357− linenoiseBeep();
358− } else {
359− size_t stop = 0, i = 0;
360−
361− while(!stop) {
362− /* Show completion or original buffer */
363− if (i < lc.len) {
364− struct linenoiseState saved = *ls;
365−
366− ls->len = ls->pos = strlen(lc.cvec[i]);
367− ls->buf = lc.cvec[i];
368− refreshLine(ls);
369− ls->len = saved.len;
370− ls->pos = saved.pos;
371− ls->buf = saved.buf;
372− } else {
373− refreshLine(ls);
374− }
375−
376− nread = read(ls->ifd,&c,1);
377− if (nread <= 0) {
378− freeCompletions(&lc);
379− return -1;
380− }
381−
382− switch(c) {
383− case 9: /* tab */
384− i = (i+1) % (lc.len+1);
385− if (i == lc.len) linenoiseBeep();
386− break;
387− case 27: /* escape */
388− /* Re-show original buffer */
389− if (i < lc.len) refreshLine(ls);
390− stop = 1;
391− break;
392− default:
393− /* Update buffer and return */
394− if (i < lc.len) {
395− nwritten = snprintf(ls->buf,ls->buflen,"%s",lc.cvec[i]);
396− ls->len = ls->pos = nwritten;
397− }
398− stop = 1;
399− break;
400− }
401− }
402− }
403−
404− freeCompletions(&lc);
405− return c; /* Return last read character */
406−}
407−
408−/* Register a callback function to be called for tab-completion. */
409−void linenoiseSetCompletionCallback(linenoiseCompletionCallback *fn) {
410− completionCallback = fn;
411−}
412−
413−/* Register a hits function to be called to show hits to the user at the
414− * right of the prompt. */
415−void linenoiseSetHintsCallback(linenoiseHintsCallback *fn) {
416− hintsCallback = fn;
417−}
418−
419−/* Register a function to free the hints returned by the hints callback
420− * registered with linenoiseSetHintsCallback(). */
421−void linenoiseSetFreeHintsCallback(linenoiseFreeHintsCallback *fn) {
422− freeHintsCallback = fn;
423−}
424−
425−/* This function is used by the callback function registered by the user
426− * in order to add completion options given the input string when the
427− * user typed <tab>. See the example.c source code for a very easy to
428− * understand example. */
429−void linenoiseAddCompletion(linenoiseCompletions *lc, const char *str) {
430− size_t len = strlen(str);
431− char *copy, **cvec;
432−
433− copy = malloc(len+1);
434− if (copy == NULL) return;
435− memcpy(copy,str,len+1);
436− cvec = realloc(lc->cvec,sizeof(char*)*(lc->len+1));
437− if (cvec == NULL) {
438− free(copy);
439− return;
440− }
441− lc->cvec = cvec;
442− lc->cvec[lc->len++] = copy;
443−}
444−
445−/* =========================== Line editing ================================= */
446−
447−/* We define a very simple "append buffer" structure, that is an heap
448− * allocated string where we can append to. This is useful in order to
449− * write all the escape sequences in a buffer and flush them to the standard
450− * output in a single call, to avoid flickering effects. */
451−struct abuf {
452− char *b;
453− int len;
454−};
455−
456−static void abInit(struct abuf *ab) {
457− ab->b = NULL;
458− ab->len = 0;
459−}
460−
461−static void abAppend(struct abuf *ab, const char *s, int len) {
462− char *new = realloc(ab->b,ab->len+len);
463−
464− if (new == NULL) return;
465− memcpy(new+ab->len,s,len);
466− ab->b = new;
467− ab->len += len;
468−}
469−
470−static void abFree(struct abuf *ab) {
471− free(ab->b);
472−}
473−
474−/* Helper of refreshSingleLine() and refreshMultiLine() to show hints
475− * to the right of the prompt. */
476−void refreshShowHints(struct abuf *ab, struct linenoiseState *l, int plen) {
477− char seq[64];
478− if (hintsCallback && plen+l->len < l->cols) {
479− int color = -1, bold = 0;
480− char *hint = hintsCallback(l->buf,&color,&bold);
481− if (hint) {
482− int hintlen = strlen(hint);
483− int hintmaxlen = l->cols-(plen+l->len);
484− if (hintlen > hintmaxlen) hintlen = hintmaxlen;
485− if (bold == 1 && color == -1) color = 37;
486− if (color != -1 || bold != 0)
487− snprintf(seq,64,"\033[%d;%d;49m",bold,color);
488− else
489− seq[0] = '\0';
490− abAppend(ab,seq,strlen(seq));
491− abAppend(ab,hint,hintlen);
492− if (color != -1 || bold != 0)
493− abAppend(ab,"\033[0m",4);
494− /* Call the function to free the hint returned. */
495− if (freeHintsCallback) freeHintsCallback(hint);
496− }
497− }
498−}
499−
500−/* Single line low level line refresh.
501− *
502− * Rewrite the currently edited line accordingly to the buffer content,
503− * cursor position, and number of columns of the terminal. */
504−static void refreshSingleLine(struct linenoiseState *l) {
505− char seq[64];
506− size_t plen = strlen(l->prompt);
507− int fd = l->ofd;
508− char *buf = l->buf;
509− size_t len = l->len;
510− size_t pos = l->pos;
511− struct abuf ab;
512−
513− while((plen+pos) >= l->cols) {
514− buf++;
515− len--;
516− pos--;
517− }
518− while (plen+len > l->cols) {
519− len--;
520− }
521−
522− abInit(&ab);
523− /* Cursor to left edge */
524− snprintf(seq,64,"\r");
525− abAppend(&ab,seq,strlen(seq));
526− /* Write the prompt and the current buffer content */
527− abAppend(&ab,l->prompt,strlen(l->prompt));
528− abAppend(&ab,buf,len);
529− /* Show hits if any. */
530− refreshShowHints(&ab,l,plen);
531− /* Erase to right */
532− snprintf(seq,64,"\x1b[0K");
533− abAppend(&ab,seq,strlen(seq));
534− /* Move cursor to original position. */
535− snprintf(seq,64,"\r\x1b[%dC", (int)(pos+plen));
536− abAppend(&ab,seq,strlen(seq));
537− if (write(fd,ab.b,ab.len) == -1) {} /* Can't recover from write error. */
538− abFree(&ab);
539−}
540−
541−/* Multi line low level line refresh.
542− *
543− * Rewrite the currently edited line accordingly to the buffer content,
544− * cursor position, and number of columns of the terminal. */
545−static void refreshMultiLine(struct linenoiseState *l) {
546− char seq[64];
547− int plen = strlen(l->prompt);
548− int rows = (plen+l->len+l->cols-1)/l->cols; /* rows used by current buf. */
549− int rpos = (plen+l->oldpos+l->cols)/l->cols; /* cursor relative row. */
550− int rpos2; /* rpos after refresh. */
551− int col; /* colum position, zero-based. */
552− int old_rows = l->maxrows;
553− int fd = l->ofd, j;
554− struct abuf ab;
555−
556− /* Update maxrows if needed. */
557− if (rows > (int)l->maxrows) l->maxrows = rows;
558−
559− /* First step: clear all the lines used before. To do so start by
560− * going to the last row. */
561− abInit(&ab);
562− if (old_rows-rpos > 0) {
563− lndebug("go down %d", old_rows-rpos);
564− snprintf(seq,64,"\x1b[%dB", old_rows-rpos);
565− abAppend(&ab,seq,strlen(seq));
566− }
567−
568− /* Now for every row clear it, go up. */
569− for (j = 0; j < old_rows-1; j++) {
570− lndebug("clear+up");
571− snprintf(seq,64,"\r\x1b[0K\x1b[1A");
572− abAppend(&ab,seq,strlen(seq));
573− }
574−
575− /* Clean the top line. */
576− lndebug("clear");
577− snprintf(seq,64,"\r\x1b[0K");
578− abAppend(&ab,seq,strlen(seq));
579−
580− /* Write the prompt and the current buffer content */
581− abAppend(&ab,l->prompt,strlen(l->prompt));
582− abAppend(&ab,l->buf,l->len);
583−
584− /* Show hits if any. */
585− refreshShowHints(&ab,l,plen);
586−
587− /* If we are at the very end of the screen with our prompt, we need to
588− * emit a newline and move the prompt to the first column. */
589− if (l->pos &&
590− l->pos == l->len &&
591− (l->pos+plen) % l->cols == 0)
592− {
593− lndebug("<newline>");
594− abAppend(&ab,"\n",1);
595− snprintf(seq,64,"\r");
596− abAppend(&ab,seq,strlen(seq));
597− rows++;
598− if (rows > (int)l->maxrows) l->maxrows = rows;
599− }
600−
601− /* Move cursor to right position. */
602− rpos2 = (plen+l->pos+l->cols)/l->cols; /* current cursor relative row. */
603− lndebug("rpos2 %d", rpos2);
604−
605− /* Go up till we reach the expected positon. */
606− if (rows-rpos2 > 0) {
607− lndebug("go-up %d", rows-rpos2);
608− snprintf(seq,64,"\x1b[%dA", rows-rpos2);
609− abAppend(&ab,seq,strlen(seq));
610− }
611−
612− /* Set column. */
613− col = (plen+(int)l->pos) % (int)l->cols;
614− lndebug("set col %d", 1+col);
615− if (col)
616− snprintf(seq,64,"\r\x1b[%dC", col);
617− else
618− snprintf(seq,64,"\r");
619− abAppend(&ab,seq,strlen(seq));
620−
621− lndebug("\n");
622− l->oldpos = l->pos;
623−
624− if (write(fd,ab.b,ab.len) == -1) {} /* Can't recover from write error. */
625− abFree(&ab);
626−}
627−
628−/* Calls the two low level functions refreshSingleLine() or
629− * refreshMultiLine() according to the selected mode. */
630−static void refreshLine(struct linenoiseState *l) {
631− if (mlmode)
632− refreshMultiLine(l);
633− else
634− refreshSingleLine(l);
635−}
636−
637−/* Insert the character 'c' at cursor current position.
638− *
639− * On error writing to the terminal -1 is returned, otherwise 0. */
640−int linenoiseEditInsert(struct linenoiseState *l, char c) {
641− if (l->len < l->buflen) {
642− if (l->len == l->pos) {
643− l->buf[l->pos] = c;
644− l->pos++;
645− l->len++;
646− l->buf[l->len] = '\0';
647− if ((!mlmode && l->plen+l->len < l->cols && !hintsCallback)) {
648− /* Avoid a full update of the line in the
649− * trivial case. */
650− if (write(l->ofd,&c,1) == -1) return -1;
651− } else {
652− refreshLine(l);
653− }
654− } else {
655− memmove(l->buf+l->pos+1,l->buf+l->pos,l->len-l->pos);
656− l->buf[l->pos] = c;
657− l->len++;
658− l->pos++;
659− l->buf[l->len] = '\0';
660− refreshLine(l);
661− }
662− }
663− return 0;
664−}
665−
666−/* Move cursor on the left. */
667−void linenoiseEditMoveLeft(struct linenoiseState *l) {
668− if (l->pos > 0) {
669− l->pos--;
670− refreshLine(l);
671− }
672−}
673−
674−/* Move cursor on the right. */
675−void linenoiseEditMoveRight(struct linenoiseState *l) {
676− if (l->pos != l->len) {
677− l->pos++;
678− refreshLine(l);
679− }
680−}
681−
682−/* Move cursor to the start of the line. */
683−void linenoiseEditMoveHome(struct linenoiseState *l) {
684− if (l->pos != 0) {
685− l->pos = 0;
686− refreshLine(l);
687− }
688−}
689−
690−/* Move cursor to the end of the line. */
691−void linenoiseEditMoveEnd(struct linenoiseState *l) {
692− if (l->pos != l->len) {
693− l->pos = l->len;
694− refreshLine(l);
695− }
696−}
697−
698−/* Substitute the currently edited line with the next or previous history
699− * entry as specified by 'dir'. */
700−#define LINENOISE_HISTORY_NEXT 0
701−#define LINENOISE_HISTORY_PREV 1
702−void linenoiseEditHistoryNext(struct linenoiseState *l, int dir) {
703− if (history_len > 1) {
704− /* Update the current history entry before to
705− * overwrite it with the next one. */
706− free(history[history_len - 1 - l->history_index]);
707− history[history_len - 1 - l->history_index] = strdup(l->buf);
708− /* Show the new entry */
709− l->history_index += (dir == LINENOISE_HISTORY_PREV) ? 1 : -1;
710− if (l->history_index < 0) {
711− l->history_index = 0;
712− return;
713− } else if (l->history_index >= history_len) {
714− l->history_index = history_len-1;
715− return;
716− }
717− strncpy(l->buf,history[history_len - 1 - l->history_index],l->buflen);
718− l->buf[l->buflen-1] = '\0';
719− l->len = l->pos = strlen(l->buf);
720− refreshLine(l);
721− }
722−}
723−
724−/* Delete the character at the right of the cursor without altering the cursor
725− * position. Basically this is what happens with the "Delete" keyboard key. */
726−void linenoiseEditDelete(struct linenoiseState *l) {
727− if (l->len > 0 && l->pos < l->len) {
728− memmove(l->buf+l->pos,l->buf+l->pos+1,l->len-l->pos-1);
729− l->len--;
730− l->buf[l->len] = '\0';
731− refreshLine(l);
732− }
733−}
734−
735−/* Backspace implementation. */
736−void linenoiseEditBackspace(struct linenoiseState *l) {
737− if (l->pos > 0 && l->len > 0) {
738− memmove(l->buf+l->pos-1,l->buf+l->pos,l->len-l->pos);
739− l->pos--;
740− l->len--;
741− l->buf[l->len] = '\0';
742− refreshLine(l);
743− }
744−}
745−
746−/* Delete the previosu word, maintaining the cursor at the start of the
747− * current word. */
748−void linenoiseEditDeletePrevWord(struct linenoiseState *l) {
749− size_t old_pos = l->pos;
750− size_t diff;
751−
752− while (l->pos > 0 && l->buf[l->pos-1] == ' ')
753− l->pos--;
754− while (l->pos > 0 && l->buf[l->pos-1] != ' ')
755− l->pos--;
756− diff = old_pos - l->pos;
757− memmove(l->buf+l->pos,l->buf+old_pos,l->len-old_pos+1);
758− l->len -= diff;
759− refreshLine(l);
760−}
761−
762−/* This function is the core of the line editing capability of linenoise.
763− * It expects 'fd' to be already in "raw mode" so that every key pressed
764− * will be returned ASAP to read().
765− *
766− * The resulting string is put into 'buf' when the user type enter, or
767− * when ctrl+d is typed.
768− *
769− * The function returns the length of the current buffer. */
770−static int linenoiseEdit(int stdin_fd, int stdout_fd, char *buf, size_t buflen, const char *prompt)
771−{
772− struct linenoiseState l;
773−
774− /* Populate the linenoise state that we pass to functions implementing
775− * specific editing functionalities. */
776− l.ifd = stdin_fd;
777− l.ofd = stdout_fd;
778− l.buf = buf;
779− l.buflen = buflen;
780− l.prompt = prompt;
781− l.plen = strlen(prompt);
782− l.oldpos = l.pos = 0;
783− l.len = 0;
784− l.cols = getColumns(stdin_fd, stdout_fd);
785− l.maxrows = 0;
786− l.history_index = 0;
787−
788− /* Buffer starts empty. */
789− l.buf[0] = '\0';
790− l.buflen--; /* Make sure there is always space for the nulterm */
791−
792− /* The latest history entry is always our current buffer, that
793− * initially is just an empty string. */
794− linenoiseHistoryAdd("");
795−
796− if (write(l.ofd,prompt,l.plen) == -1) return -1;
797− while(1) {
798− char c;
799− int nread;
800− char seq[3];
801−
802− nread = read(l.ifd,&c,1);
803− if (nread <= 0) return l.len;
804−
805− /* Only autocomplete when the callback is set. It returns < 0 when
806− * there was an error reading from fd. Otherwise it will return the
807− * character that should be handled next. */
808− if (c == 9 && completionCallback != NULL) {
809− c = completeLine(&l);
810− /* Return on errors */
811− if (c < 0) return l.len;
812− /* Read next character when 0 */
813− if (c == 0) continue;
814− }
815−
816− switch(c) {
817− case ENTER: /* enter */
818− history_len--;
819− free(history[history_len]);
820− if (mlmode) linenoiseEditMoveEnd(&l);
821− if (hintsCallback) {
822− /* Force a refresh without hints to leave the previous
823− * line as the user typed it after a newline. */
824− linenoiseHintsCallback *hc = hintsCallback;
825− hintsCallback = NULL;
826− refreshLine(&l);
827− hintsCallback = hc;
828− }
829− return (int)l.len;
830− case CTRL_C: /* ctrl-c */
831− errno = EAGAIN;
832− return -1;
833− case BACKSPACE: /* backspace */
834− case 8: /* ctrl-h */
835− linenoiseEditBackspace(&l);
836− break;
837− case CTRL_D: /* ctrl-d, remove char at right of cursor, or if the
838− line is empty, act as end-of-file. */
839− if (l.len > 0) {
840− linenoiseEditDelete(&l);
841− } else {
842− history_len--;
843− free(history[history_len]);
844− return -1;
845− }
846− break;
847− case CTRL_T: /* ctrl-t, swaps current character with previous. */
848− if (l.pos > 0 && l.pos < l.len) {
849− int aux = buf[l.pos-1];
850− buf[l.pos-1] = buf[l.pos];
851− buf[l.pos] = aux;
852− if (l.pos != l.len-1) l.pos++;
853− refreshLine(&l);
854− }
855− break;
856− case CTRL_B: /* ctrl-b */
857− linenoiseEditMoveLeft(&l);
858− break;
859− case CTRL_F: /* ctrl-f */
860− linenoiseEditMoveRight(&l);
861− break;
862− case CTRL_P: /* ctrl-p */
863− linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_PREV);
864− break;
865− case CTRL_N: /* ctrl-n */
866− linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_NEXT);
867− break;
868− case ESC: /* escape sequence */
869− /* Read the next two bytes representing the escape sequence.
870− * Use two calls to handle slow terminals returning the two
871− * chars at different times. */
872− if (read(l.ifd,seq,1) == -1) break;
873− if (read(l.ifd,seq+1,1) == -1) break;
874−
875− /* ESC [ sequences. */
876− if (seq[0] == '[') {
877− if (seq[1] >= '0' && seq[1] <= '9') {
878− /* Extended escape, read additional byte. */
879− if (read(l.ifd,seq+2,1) == -1) break;
880− if (seq[2] == '~') {
881− switch(seq[1]) {
882− case '3': /* Delete key. */
883− linenoiseEditDelete(&l);
884− break;
885− }
886− }
887− } else {
888− switch(seq[1]) {
889− case 'A': /* Up */
890− linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_PREV);
891− break;
892− case 'B': /* Down */
893− linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_NEXT);
894− break;
895− case 'C': /* Right */
896− linenoiseEditMoveRight(&l);
897− break;
898− case 'D': /* Left */
899− linenoiseEditMoveLeft(&l);
900− break;
901− case 'H': /* Home */
902− linenoiseEditMoveHome(&l);
903− break;
904− case 'F': /* End*/
905− linenoiseEditMoveEnd(&l);
906− break;
907− }
908− }
909− }
910−
911− /* ESC O sequences. */
912− else if (seq[0] == 'O') {
913− switch(seq[1]) {
914− case 'H': /* Home */
915− linenoiseEditMoveHome(&l);
916− break;
917− case 'F': /* End*/
918− linenoiseEditMoveEnd(&l);
919− break;
920− }
921− }
922− break;
923− default:
924− if (linenoiseEditInsert(&l,c)) return -1;
925− break;
926− case CTRL_U: /* Ctrl+u, delete the whole line. */
927− buf[0] = '\0';
928− l.pos = l.len = 0;
929− refreshLine(&l);
930− break;
931− case CTRL_K: /* Ctrl+k, delete from current to end of line. */
932− buf[l.pos] = '\0';
933− l.len = l.pos;
934− refreshLine(&l);
935− break;
936− case CTRL_A: /* Ctrl+a, go to the start of the line */
937− linenoiseEditMoveHome(&l);
938− break;
939− case CTRL_E: /* ctrl+e, go to the end of the line */
940− linenoiseEditMoveEnd(&l);
941− break;
942− case CTRL_L: /* ctrl+l, clear screen */
943− linenoiseClearScreen();
944− refreshLine(&l);
945− break;
946− case CTRL_W: /* ctrl+w, delete previous word */
947− linenoiseEditDeletePrevWord(&l);
948− break;
949− }
950− }
951− return l.len;
952−}
953−
954−/* This special mode is used by linenoise in order to print scan codes
955− * on screen for debugging / development purposes. It is implemented
956− * by the linenoise_example program using the --keycodes option. */
957−void linenoisePrintKeyCodes(void) {
958− char quit[4];
959−
960− printf("Linenoise key codes debugging mode.\n"
961− "Press keys to see scan codes. Type 'quit' at any time to exit.\n");
962− if (enableRawMode(STDIN_FILENO) == -1) return;
963− memset(quit,' ',4);
964− while(1) {
965− char c;
966− int nread;
967−
968− nread = read(STDIN_FILENO,&c,1);
969− if (nread <= 0) continue;
970− memmove(quit,quit+1,sizeof(quit)-1); /* shift string to left. */
971− quit[sizeof(quit)-1] = c; /* Insert current char on the right. */
972− if (memcmp(quit,"quit",sizeof(quit)) == 0) break;
973−
974− printf("'%c' %02x (%d) (type quit to exit)\n",
975− isprint(c) ? c : '?', (int)c, (int)c);
976− printf("\r"); /* Go left edge manually, we are in raw mode. */
977− fflush(stdout);
978− }
979− disableRawMode(STDIN_FILENO);
980−}
981−
982−/* This function calls the line editing function linenoiseEdit() using
983− * the STDIN file descriptor set in raw mode. */
984−static int linenoiseRaw(char *buf, size_t buflen, const char *prompt) {
985− int count;
986−
987− if (buflen == 0) {
988− errno = EINVAL;
989− return -1;
990− }
991−
992− if (enableRawMode(STDIN_FILENO) == -1) return -1;
993− count = linenoiseEdit(STDIN_FILENO, STDOUT_FILENO, buf, buflen, prompt);
994− disableRawMode(STDIN_FILENO);
995− printf("\n");
996− return count;
997−}
998−
999−/* This function is called when linenoise() is called with the standard
1000− * input file descriptor not attached to a TTY. So for example when the
1001− * program using linenoise is called in pipe or with a file redirected
1002− * to its standard input. In this case, we want to be able to return the
1003− * line regardless of its length (by default we are limited to 4k). */
1004−static char *linenoiseNoTTY(void) {
1005− char *line = NULL;
1006− size_t len = 0, maxlen = 0;
1007−
1008− while(1) {
1009− if (len == maxlen) {
1010− if (maxlen == 0) maxlen = 16;
1011− maxlen *= 2;
1012− char *oldval = line;
1013− line = realloc(line,maxlen);
1014− if (line == NULL) {
1015− if (oldval) free(oldval);
1016− return NULL;
1017− }
1018− }
1019− int c = fgetc(stdin);
1020− if (c == EOF || c == '\n') {
1021− if (c == EOF && len == 0) {
1022− free(line);
1023− return NULL;
1024− } else {
1025− line[len] = '\0';
1026− return line;
1027− }
1028− } else {
1029− line[len] = c;
1030− len++;
1031− }
1032− }
1033−}
1034−
1035−/* The high level function that is the main API of the linenoise library.
1036− * This function checks if the terminal has basic capabilities, just checking
1037− * for a blacklist of stupid terminals, and later either calls the line
1038− * editing function or uses dummy fgets() so that you will be able to type
1039− * something even in the most desperate of the conditions. */
1040−char *linenoise(const char *prompt) {
1041− char buf[LINENOISE_MAX_LINE];
1042− int count;
1043−
1044− if (!isatty(STDIN_FILENO)) {
1045− /* Not a tty: read from file / pipe. In this mode we don't want any
1046− * limit to the line size, so we call a function to handle that. */
1047− return linenoiseNoTTY();
1048− } else if (isUnsupportedTerm()) {
1049− size_t len;
1050−
1051− printf("%s",prompt);
1052− fflush(stdout);
1053− if (fgets(buf,LINENOISE_MAX_LINE,stdin) == NULL) return NULL;
1054− len = strlen(buf);
1055− while(len && (buf[len-1] == '\n' || buf[len-1] == '\r')) {
1056− len--;
1057− buf[len] = '\0';
1058− }
1059− return strdup(buf);
1060− } else {
1061− count = linenoiseRaw(buf,LINENOISE_MAX_LINE,prompt);
1062− if (count == -1) return NULL;
1063− return strdup(buf);
1064− }
1065−}
1066−
1067−/* This is just a wrapper the user may want to call in order to make sure
1068− * the linenoise returned buffer is freed with the same allocator it was
1069− * created with. Useful when the main program is using an alternative
1070− * allocator. */
1071−void linenoiseFree(void *ptr) {
1072− free(ptr);
1073−}
1074−
1075−/* ================================ History ================================= */
1076−
1077−/* Free the history, but does not reset it. Only used when we have to
1078− * exit() to avoid memory leaks are reported by valgrind & co. */
1079−static void freeHistory(void) {
1080− if (history) {
1081− int j;
1082−
1083− for (j = 0; j < history_len; j++)
1084− free(history[j]);
1085− free(history);
1086− }
1087−}
1088−
1089−/* At exit we'll try to fix the terminal to the initial conditions. */
1090−static void linenoiseAtExit(void) {
1091− disableRawMode(STDIN_FILENO);
1092− freeHistory();
1093−}
1094−
1095−/* This is the API call to add a new entry in the linenoise history.
1096− * It uses a fixed array of char pointers that are shifted (memmoved)
1097− * when the history max length is reached in order to remove the older
1098− * entry and make room for the new one, so it is not exactly suitable for huge
1099− * histories, but will work well for a few hundred of entries.
1100− *
1101− * Using a circular buffer is smarter, but a bit more complex to handle. */
1102−int linenoiseHistoryAdd(const char *line) {
1103− char *linecopy;
1104−
1105− if (history_max_len == 0) return 0;
1106−
1107− /* Initialization on first call. */
1108− if (history == NULL) {
1109− history = malloc(sizeof(char*)*history_max_len);
1110− if (history == NULL) return 0;
1111− memset(history,0,(sizeof(char*)*history_max_len));
1112− }
1113−
1114− /* Don't add duplicated lines. */
1115− if (history_len && !strcmp(history[history_len-1], line)) return 0;
1116−
1117− /* Add an heap allocated copy of the line in the history.
1118− * If we reached the max length, remove the older line. */
1119− linecopy = strdup(line);
1120− if (!linecopy) return 0;
1121− if (history_len == history_max_len) {
1122− free(history[0]);
1123− memmove(history,history+1,sizeof(char*)*(history_max_len-1));
1124− history_len--;
1125− }
1126− history[history_len] = linecopy;
1127− history_len++;
1128− return 1;
1129−}
1130−
1131−/* Set the maximum length for the history. This function can be called even
1132− * if there is already some history, the function will make sure to retain
1133− * just the latest 'len' elements if the new history length value is smaller
1134− * than the amount of items already inside the history. */
1135−int linenoiseHistorySetMaxLen(int len) {
1136− char **new;
1137−
1138− if (len < 1) return 0;
1139− if (history) {
1140− int tocopy = history_len;
1141−
1142− new = malloc(sizeof(char*)*len);
1143− if (new == NULL) return 0;
1144−
1145− /* If we can't copy everything, free the elements we'll not use. */
1146− if (len < tocopy) {
1147− int j;
1148−
1149− for (j = 0; j < tocopy-len; j++) free(history[j]);
1150− tocopy = len;
1151− }
1152− memset(new,0,sizeof(char*)*len);
1153− memcpy(new,history+(history_len-tocopy), sizeof(char*)*tocopy);
1154− free(history);
1155− history = new;
1156− }
1157− history_max_len = len;
1158− if (history_len > history_max_len)
1159− history_len = history_max_len;
1160− return 1;
1161−}
1162−
1163−/* Save the history in the specified file. On success 0 is returned
1164− * otherwise -1 is returned. */
1165−int linenoiseHistorySave(const char *filename) {
1166− mode_t old_umask = umask(S_IXUSR|S_IRWXG|S_IRWXO);
1167− FILE *fp;
1168− int j;
1169−
1170− fp = fopen(filename,"w");
1171− umask(old_umask);
1172− if (fp == NULL) return -1;
1173− chmod(filename,S_IRUSR|S_IWUSR);
1174− for (j = 0; j < history_len; j++)
1175− fprintf(fp,"%s\n",history[j]);
1176− fclose(fp);
1177− return 0;
1178−}
1179−
1180−/* Load the history from the specified file. If the file does not exist
1181− * zero is returned and no operation is performed.
1182− *
1183− * If the file exists and the operation succeeded 0 is returned, otherwise
1184− * on error -1 is returned. */
1185−int linenoiseHistoryLoad(const char *filename) {
1186− FILE *fp = fopen(filename,"r");
1187− char buf[LINENOISE_MAX_LINE];
1188−
1189− if (fp == NULL) return -1;
1190−
1191− while (fgets(buf,LINENOISE_MAX_LINE,fp) != NULL) {
1192− char *p;
1193−
1194− p = strchr(buf,'\r');
1195− if (!p) p = strchr(buf,'\n');
1196− if (p) *p = '\0';
1197− linenoiseHistoryAdd(buf);
1198− }
1199− fclose(fp);
1200− return 0;
1201−}
linenoise/linenoise.godeleted−79
@@ -1,79 +0,0 @@
1−package linenoise
2−
3−/*
4−#include <linenoise.h>
5−#include <stdlib.h>
6−
7−void linenoise_setup();
8−
9−
10−*/
11−import "C"
12−
13−import (
14− "fmt"
15− "unsafe"
16−)
17−
18−type Completer func(line string) []string
19−type Hinter func(line string) string
20−
21−var completer Completer
22−var hinter Hinter
23−
24−//export linenoiseCompletionStub
25−func linenoiseCompletionStub(input *C.char, completions *C.linenoiseCompletions) {
26− if completer == nil {
27− return
28− }
29− completionsSlice := completer(C.GoString(input))
30− completionsLen := len(completionsSlice)
31− completions.len = C.size_t(completionsLen)
32−
33− if completionsLen > 0 {
34− cvec := C.malloc(C.size_t(int(unsafe.Sizeof(*(**C.char)(nil))) * completionsLen))
35− cvecSlice := (*(*[999999]*C.char)(cvec))[:completionsLen]
36−
37− for i, str := range completionsSlice {
38− cvecSlice[i] = C.CString(str)
39− }
40− completions.cvec = (**C.char)(cvec)
41− }
42−}
43−
44−//export linenoiseHintsStub
45−func linenoiseHintsStub(input *C.char, color *C.int, bold *C.int) *C.char {
46− if hinter == nil {
47− return nil
48− }
49− *color = 37
50− *bold = 0
51− return C.CString(hinter(C.GoString(input)))
52−}
53−
54−func Linenoise(prompt string) (string, error) {
55− C.linenoise_setup()
56− cprompt := C.CString(prompt)
57− defer C.free(unsafe.Pointer(cprompt))
58− cresult := C.linenoise(cprompt)
59− if cresult == nil {
60− return "", fmt.Errorf("No input")
61− }
62− result := C.GoString(cresult)
63− C.linenoiseFree(unsafe.Pointer(cresult))
64− return result, nil
65−}
66−
67−func LinenoiseHistoryAdd(line string) {
68− data := C.CString(line)
69− defer C.free(unsafe.Pointer(data))
70− C.linenoiseHistoryAdd(data)
71−}
72−
73−func LinenoiseSetCompleter(newCompleter Completer) {
74− completer = newCompleter
75−}
76−
77−func LinenoiseSetHinter(newHinter Hinter) {
78− hinter = newHinter
79−}
linenoise/linenoise.hdeleted−73
@@ -1,73 +0,0 @@
1−/* linenoise.h -- VERSION 1.0
2− *
3− * Guerrilla line editing library against the idea that a line editing lib
4− * needs to be 20,000 lines of C code.
5− *
6− * See linenoise.c for more information.
7− *
8− * ------------------------------------------------------------------------
9− *
10− * Copyright (c) 2010-2014, Salvatore Sanfilippo <antirez at gmail dot com>
11− * Copyright (c) 2010-2013, Pieter Noordhuis <pcnoordhuis at gmail dot com>
12− *
13− * All rights reserved.
14− *
15− * Redistribution and use in source and binary forms, with or without
16− * modification, are permitted provided that the following conditions are
17− * met:
18− *
19− * * Redistributions of source code must retain the above copyright
20− * notice, this list of conditions and the following disclaimer.
21− *
22− * * Redistributions in binary form must reproduce the above copyright
23− * notice, this list of conditions and the following disclaimer in the
24− * documentation and/or other materials provided with the distribution.
25− *
26− * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27− * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28− * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
29− * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
30− * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
31− * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
32− * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
33− * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
34− * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
35− * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
36− * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37− */
38−
39−#ifndef __LINENOISE_H
40−#define __LINENOISE_H
41−
42−#ifdef __cplusplus
43−extern "C" {
44−#endif
45−
46−typedef struct linenoiseCompletions {
47− size_t len;
48− char **cvec;
49−} linenoiseCompletions;
50−
51−typedef void(linenoiseCompletionCallback)(const char *, linenoiseCompletions *);
52−typedef char*(linenoiseHintsCallback)(const char *, int *color, int *bold);
53−typedef void(linenoiseFreeHintsCallback)(void *);
54−void linenoiseSetCompletionCallback(linenoiseCompletionCallback *);
55−void linenoiseSetHintsCallback(linenoiseHintsCallback *);
56−void linenoiseSetFreeHintsCallback(linenoiseFreeHintsCallback *);
57−void linenoiseAddCompletion(linenoiseCompletions *, const char *);
58−
59−char *linenoise(const char *prompt);
60−void linenoiseFree(void *ptr);
61−int linenoiseHistoryAdd(const char *line);
62−int linenoiseHistorySetMaxLen(int len);
63−int linenoiseHistorySave(const char *filename);
64−int linenoiseHistoryLoad(const char *filename);
65−void linenoiseClearScreen(void);
66−void linenoiseSetMultiLine(int ml);
67−void linenoisePrintKeyCodes(void);
68−
69−#ifdef __cplusplus
70−}
71−#endif
72−
73−#endif /* __LINENOISE_H */
tests/lua/own_eval.expdeleted−51
@@ -1,51 +0,0 @@
1−#!/usr/bin/expect -f
2−
3−set timeout -1
4−spawn ./prybar-lua -I
5−match_max 100000
6−expect -exact "Lua 5.1.5 Copyright (C) 1994-2012 Lua.org, PUC-Rio\r
7−--> "
8−send -- "1"
9−expect -exact "\r--> 1\[0K\r\[5C"
10−send -- "+"
11−expect -exact "\r--> 1+\[0K\r\[6C"
12−send -- "1"
13−expect -exact "\r--> 1+1\[0K\r\[7C"
14−send -- "\r"
15−expect -exact "\r--> 1+1\[0K\r\[7C\r
16−lua: \[string \"<eval>\"\]:1: unexpected symbol near '1'\r
17−--> "
18−send -- "r"
19−expect -exact "\r--> r\[0K\r\[5C"
20−send -- "e"
21−expect -exact "\r--> re\[0K\r\[6C"
22−send -- "t"
23−expect -exact "\r--> ret\[0K\r\[7C"
24−send -- "u"
25−expect -exact "\r--> retu\[0K\r\[8C"
26−send -- "r"
27−expect -exact "\r--> retur\[0K\r\[9C"
28−send -- "n"
29−expect -exact "\r--> return\[0K\r\[10C"
30−send -- " "
31−expect -exact "\r--> return \[0K\r\[11C"
32−send -- "1"
33−expect -exact "\r--> return 1\[0K\r\[12C"
34−send -- "\r"
35−expect -exact "\r--> return 1\[0K\r\[12C\r
36−--> "
37−send -- "a"
38−expect -exact "\r--> a\[0K\r\[5C"
39−send -- " "
40−expect -exact "\r--> a \[0K\r\[6C"
41−send -- ""
42−expect -exact "\r--> a\[0K\r\[5C"
43−send -- "="
44−expect -exact "\r--> a=\[0K\r\[6C"
45−send -- "1"
46−expect -exact "\r--> a=1\[0K\r\[7C"
47−send -- "\r"
48−expect -exact "\r--> a=1\[0K\r\[7C\r
49−--> "
50−send -- ""
51−expect eof
tests/tcl/1_plus_1.exp+11−11
@@ -3,26 +3,26 @@
33set timeout -1
44spawn ./prybar-tcl -q -i
55match_max 100000
6−expect -exact "--> "
6+expect -exact "\[J\[2K\r--> "
77send -- "e"
8−expect -exact "\r--> e\[0K\r\[5C"
8+expect -exact "\[J\[2K\r--> e"
99send -- "x"
10−expect -exact "\r--> ex\[0K\r\[6C"
10+expect -exact "\[J\[2K\r--> ex"
1111send -- "p"
12−expect -exact "\r--> exp\[0K\r\[7C"
12+expect -exact "\[J\[2K\r--> exp"
1313send -- "r"
14−expect -exact "\r--> expr\[0K\r\[8C"
14+expect -exact "\[J\[2K\r--> expr"
1515send -- " "
16−expect -exact "\r--> expr \[0K\r\[9C"
16+expect -exact "\[J\[2K\r--> expr "
1717send -- "1"
18−expect -exact "\r--> expr 1\[0K\r\[10C"
18+expect -exact "\[J\[2K\r--> expr 1"
1919send -- "+"
20−expect -exact "\r--> expr 1+\[0K\r\[11C"
20+expect -exact "\[J\[2K\r--> expr 1+"
2121send -- "1"
22−expect -exact "\r--> expr 1+1\[0K\r\[12C"
22+expect -exact "\[J\[2K\r--> expr 1+1"
2323send -- "\r"
24−expect -exact "\r--> expr 1+1\[0K\r\[12C\r
24+expect -exact "\[J\[2K\r--> expr 1+1\[J\[2K\r--> expr 1+1\r
25252\r
26−--> "
26+\[J\[2K\r--> "
2727send -- ""
2828expect eof
tests/tcl/a_few_outputs.exp+44−40
@@ -3,87 +3,91 @@
33set timeout -1
44spawn ./prybar-tcl -q -i
55match_max 100000
6−expect -exact "--> "
6+expect -exact "\[J\[2K\r--> "
77send -- "p"
8−expect -exact "\r--> p\[0K\r\[5C"
8+expect -exact "\[J\[2K\r--> p"
99send -- "u"
10−expect -exact "\r--> pu\[0K\r\[6C"
10+expect -exact "\[J\[2K\r--> pu"
1111send -- "t"
12−expect -exact "\r--> put\[0K\r\[7C"
12+expect -exact "\[J\[2K\r--> put"
1313send -- "s"
14−expect -exact "\r--> puts\[0K\r\[8C"
14+expect -exact "\[J\[2K\r--> puts"
1515send -- " "
16−expect -exact "\r--> puts \[0K\r\[9C"
16+expect -exact "\[J\[2K\r--> puts "
1717send -- "\""
18−expect -exact "\r--> puts \"\[0K\r\[10C"
18+expect -exact "\[J\[2K\r--> puts \""
1919send -- "h"
20−expect -exact "\r--> puts \"h\[0K\r\[11C"
20+expect -exact "\[J\[2K\r--> puts \"h"
2121send -- "e"
22−expect -exact "\r--> puts \"he\[0K\r\[12C"
22+expect -exact "\[J\[2K\r--> puts \"he"
2323send -- "y"
24−expect -exact "\r--> puts \"hey\[0K\r\[13C"
24+expect -exact "\[J\[2K\r--> puts \"hey"
2525send -- "\""
26−expect -exact "\r--> puts \"hey\"\[0K\r\[14C"
26+expect -exact "\[J\[2K\r--> puts \"hey\""
2727send -- "\r"
28−expect -exact "\r--> puts \"hey\"\[0K\r\[14C\r
28+expect -exact "\[J\[2K\r--> puts \"hey\"\[J\[2K\r--> puts \"hey\"\r
2929hey\r\r
3030\r
31−--> "
31+\[J\[2K\r--> "
3232send -- "p"
33−expect -exact "\r--> p\[0K\r\[5C"
33+expect -exact "\[J\[2K\r--> p"
3434send -- "u"
35−expect -exact "\r--> pu\[0K\r\[6C"
35+expect -exact "\[J\[2K\r--> pu"
3636send -- "t"
37−expect -exact "\r--> put\[0K\r\[7C"
37+expect -exact "\[J\[2K\r--> put"
3838send -- "s"
39−expect -exact "\r--> puts\[0K\r\[8C"
39+expect -exact "\[J\[2K\r--> puts"
4040send -- " "
41−expect -exact "\r--> puts \[0K\r\[9C"
41+expect -exact "\[J\[2K\r--> puts "
4242send -- "\""
43−expect -exact "\r--> puts \"\[0K\r\[10C"
43+expect -exact "\[J\[2K\r--> puts \""
4444send -- "h"
45−expect -exact "\r--> puts \"h\[0K\r\[11C"
45+expect -exact "\[J\[2K\r--> puts \"h"
4646send -- "e"
47−expect -exact "\r--> puts \"he\[0K\r\[12C"
47+expect -exact "\[J\[2K\r--> puts \"he"
4848send -- "y"
49−expect -exact "\r--> puts \"hey\[0K\r\[13C"
49+expect -exact "\[J\[2K\r--> puts \"hey"
5050send -- "\""
51−expect -exact "\r--> puts \"hey\"\[0K\r\[14C"
51+expect -exact "\[J\[2K\r--> puts \"hey\""
5252send -- "\r"
53−expect -exact "\r--> puts \"hey\"\[0K\r\[14C\r
53+expect -exact "\[J\[2K\r--> puts \"hey\"\[J\[2K\r--> puts \"hey\"\r
5454hey\r\r
5555\r
56−--> "
56+\[J\[2K\r--> "
5757send -- "p"
58−expect -exact "\r--> p\[0K\r\[5C"
58+expect -exact "\[J\[2K\r--> p"
5959send -- "u"
60−expect -exact "\r--> pu\[0K\r\[6C"
60+expect -exact "\[J\[2K\r--> pu"
6161send -- "t"
62−expect -exact "\r--> put\[0K\r\[7C"
62+expect -exact "\[J\[2K\r--> put"
6363send -- "s"
64−expect -exact "\r--> puts\[0K\r\[8C"
64+expect -exact "\[J\[2K\r--> puts"
6565send -- " "
66−expect -exact "\r--> puts \[0K\r\[9C"
66+expect -exact "\[J\[2K\r--> puts "
67+send -- "\""
68+expect -exact "\[J\[2K\r--> puts \""
6769send -- "h"
68−expect -exact "\r--> puts h\[0K\r\[10C"
70+expect -exact "\[J\[2K\r--> puts \"h"
6971send -- "e"
70−expect -exact "\r--> puts he\[0K\r\[11C"
72+expect -exact "\[J\[2K\r--> puts \"he"
7173send -- "e"
72−expect -exact "\r--> puts hee\[0K\r\[12C"
74+expect -exact "\[J\[2K\r--> puts \"hee"
7375send -- "e"
74−expect -exact "\r--> puts heee\[0K\r\[13C"
76+expect -exact "\[J\[2K\r--> puts \"heee"
7577send -- "e"
76−expect -exact "\r--> puts heeee\[0K\r\[14C"
78+expect -exact "\[J\[2K\r--> puts \"heeee"
7779send -- "e"
78−expect -exact "\r--> puts heeeee\[0K\r\[15C"
80+expect -exact "\[J\[2K\r--> puts \"heeeee"
7981send -- "e"
80−expect -exact "\r--> puts heeeeee\[0K\r\[16C"
82+expect -exact "\[J\[2K\r--> puts \"heeeeee"
8183send -- "y"
82−expect -exact "\r--> puts heeeeeey\[0K\r\[17C"
84+expect -exact "\[J\[2K\r--> puts \"heeeeeey"
85+send -- "\""
86+expect -exact "\[J\[2K\r--> puts \"heeeeeey\""
8387send -- "\r"
84−expect -exact "\r--> puts heeeeeey\[0K\r\[17C\r
88+expect -exact "\[J\[2K\r--> puts \"heeeeeey\"\[J\[2K\r--> puts \"heeeeeey\"\r
8589heeeeeey\r\r
8690\r
87−--> "
91+\[J\[2K\r--> "
8892send -- ""
8993expect eof
tests/tcl/from_file.exp+15−15
@@ -4,35 +4,35 @@ set timeout -1
44spawn ./prybar-tcl -q -i ./test_files/hello_tcl.tcl
55match_max 100000
66expect -exact "Hello, Tcl!\r\r
7−--> "
7+\[J\[2K\r--> "
88send -- "p"
9−expect -exact "\r--> p\[0K\r\[5C"
9+expect -exact "\[J\[2K\r--> p"
1010send -- "u"
11−expect -exact "\r--> pu\[0K\r\[6C"
11+expect -exact "\[J\[2K\r--> pu"
1212send -- "t"
13−expect -exact "\r--> put\[0K\r\[7C"
13+expect -exact "\[J\[2K\r--> put"
1414send -- "s"
15−expect -exact "\r--> puts\[0K\r\[8C"
15+expect -exact "\[J\[2K\r--> puts"
1616send -- " "
17−expect -exact "\r--> puts \[0K\r\[9C"
17+expect -exact "\[J\[2K\r--> puts "
1818send -- "\$"
19−expect -exact "\r--> puts \$\[0K\r\[10C"
19+expect -exact "\[J\[2K\r--> puts \$"
2020send -- "m"
21−expect -exact "\r--> puts \$m\[0K\r\[11C"
21+expect -exact "\[J\[2K\r--> puts \$m"
2222send -- "y"
23−expect -exact "\r--> puts \$my\[0K\r\[12C"
23+expect -exact "\[J\[2K\r--> puts \$my"
2424send -- "_"
25−expect -exact "\r--> puts \$my_\[0K\r\[13C"
25+expect -exact "\[J\[2K\r--> puts \$my_"
2626send -- "n"
27−expect -exact "\r--> puts \$my_n\[0K\r\[14C"
27+expect -exact "\[J\[2K\r--> puts \$my_n"
2828send -- "u"
29−expect -exact "\r--> puts \$my_nu\[0K\r\[15C"
29+expect -exact "\[J\[2K\r--> puts \$my_nu"
3030send -- "m"
31−expect -exact "\r--> puts \$my_num\[0K\r\[16C"
31+expect -exact "\[J\[2K\r--> puts \$my_num"
3232send -- "\r"
33−expect -exact "\r--> puts \$my_num\[0K\r\[16C\r
33+expect -exact "\[J\[2K\r--> puts \$my_num\[J\[2K\r--> puts \$my_num\r
34341000\r\r
3535\r
36−--> "
36+\[J\[2K\r--> "
3737send -- ""
3838expect eof
tests/tcl/input_output.exp+38−38
@@ -3,76 +3,76 @@
33set timeout -1
44spawn ./prybar-tcl -q -i
55match_max 100000
6−expect -exact "--> "
6+expect -exact "\[J\[2K\r--> "
77send -- "s"
8−expect -exact "\r--> s\[0K\r\[5C"
8+expect -exact "\[J\[2K\r--> s"
99send -- "e"
10−expect -exact "\r--> se\[0K\r\[6C"
10+expect -exact "\[J\[2K\r--> se"
1111send -- "t"
12−expect -exact "\r--> set\[0K\r\[7C"
12+expect -exact "\[J\[2K\r--> set"
1313send -- " "
14−expect -exact "\r--> set \[0K\r\[8C"
14+expect -exact "\[J\[2K\r--> set "
1515send -- "i"
16−expect -exact "\r--> set i\[0K\r\[9C"
16+expect -exact "\[J\[2K\r--> set i"
1717send -- "n"
18−expect -exact "\r--> set in\[0K\r\[10C"
18+expect -exact "\[J\[2K\r--> set in"
1919send -- "p"
20−expect -exact "\r--> set inp\[0K\r\[11C"
20+expect -exact "\[J\[2K\r--> set inp"
2121send -- " "
22−expect -exact "\r--> set inp \[0K\r\[12C"
22+expect -exact "\[J\[2K\r--> set inp "
2323send -- "\["
24−expect -exact "\r--> set inp \[\[0K\r\[13C"
24+expect -exact "\[J\[2K\r--> set inp \["
2525send -- "g"
26−expect -exact "\r--> set inp \[g\[0K\r\[14C"
26+expect -exact "\[J\[2K\r--> set inp \[g"
2727send -- "e"
28−expect -exact "\r--> set inp \[ge\[0K\r\[15C"
28+expect -exact "\[J\[2K\r--> set inp \[ge"
2929send -- "t"
30−expect -exact "\r--> set inp \[get\[0K\r\[16C"
30+expect -exact "\[J\[2K\r--> set inp \[get"
3131send -- "s"
32−expect -exact "\r--> set inp \[gets\[0K\r\[17C"
32+expect -exact "\[J\[2K\r--> set inp \[gets"
3333send -- " "
34−expect -exact "\r--> set inp \[gets \[0K\r\[18C"
34+expect -exact "\[J\[2K\r--> set inp \[gets "
3535send -- "s"
36−expect -exact "\r--> set inp \[gets s\[0K\r\[19C"
36+expect -exact "\[J\[2K\r--> set inp \[gets s"
3737send -- "t"
38−expect -exact "\r--> set inp \[gets st\[0K\r\[20C"
38+expect -exact "\[J\[2K\r--> set inp \[gets st"
3939send -- "d"
40−expect -exact "\r--> set inp \[gets std\[0K\r\[21C"
40+expect -exact "\[J\[2K\r--> set inp \[gets std"
4141send -- "i"
42−expect -exact "\r--> set inp \[gets stdi\[0K\r\[22C"
42+expect -exact "\[J\[2K\r--> set inp \[gets stdi"
4343send -- "n"
44−expect -exact "\r--> set inp \[gets stdin\[0K\r\[23C"
44+expect -exact "\[J\[2K\r--> set inp \[gets stdin"
4545send -- "\]"
46−expect -exact "\r--> set inp \[gets stdin\]\[0K\r\[24C"
46+expect -exact "\[J\[2K\r--> set inp \[gets stdin\]"
4747send -- "\r"
48−expect -exact "\r--> set inp \[gets stdin\]\[0K\r\[24C\r
48+expect -exact "\[J\[2K\r--> set inp \[gets stdin\]\[J\[2K\r--> set inp \[gets stdin\]\r
4949"
50−send -- "hellooooooo\r"
51−expect -exact "hellooooooo\r
52−hellooooooo\r
53−--> "
50+send -- "helloooooo\r"
51+expect -exact "helloooooo\r
52+helloooooo\r
53+\[J\[2K\r--> "
5454send -- "p"
55−expect -exact "\r--> p\[0K\r\[5C"
55+expect -exact "\[J\[2K\r--> p"
5656send -- "u"
57−expect -exact "\r--> pu\[0K\r\[6C"
57+expect -exact "\[J\[2K\r--> pu"
5858send -- "t"
59−expect -exact "\r--> put\[0K\r\[7C"
59+expect -exact "\[J\[2K\r--> put"
6060send -- "s"
61−expect -exact "\r--> puts\[0K\r\[8C"
61+expect -exact "\[J\[2K\r--> puts"
6262send -- " "
63−expect -exact "\r--> puts \[0K\r\[9C"
63+expect -exact "\[J\[2K\r--> puts "
6464send -- "\$"
65−expect -exact "\r--> puts \$\[0K\r\[10C"
65+expect -exact "\[J\[2K\r--> puts \$"
6666send -- "i"
67−expect -exact "\r--> puts \$i\[0K\r\[11C"
67+expect -exact "\[J\[2K\r--> puts \$i"
6868send -- "n"
69−expect -exact "\r--> puts \$in\[0K\r\[12C"
69+expect -exact "\[J\[2K\r--> puts \$in"
7070send -- "p"
71−expect -exact "\r--> puts \$inp\[0K\r\[13C"
71+expect -exact "\[J\[2K\r--> puts \$inp"
7272send -- "\r"
73−expect -exact "\r--> puts \$inp\[0K\r\[13C\r
74−hellooooooo\r\r
73+expect -exact "\[J\[2K\r--> puts \$inp\[J\[2K\r--> puts \$inp\r
74+helloooooo\r\r
7575\r
76−--> "
76+\[J\[2K\r--> "
7777send -- ""
7878expect eof
tests/tcl/status_line.expdeleted−6
@@ -1,6 +0,0 @@
1−#!/usr/bin/expect -f
2−
3−set timeout -1
4−spawn ./prybar-tcl
5−match_max 100000
6−expect eof
tests/tcl/unknown_command.exp+9−9
@@ -3,23 +3,23 @@
33set timeout -1
44spawn ./prybar-tcl -q -i
55match_max 100000
6−expect -exact "--> "
6+expect -exact "\[J\[2K\r--> "
77send -- "h"
8−expect -exact "\r--> h\[0K\r\[5C"
8+expect -exact "\[J\[2K\r--> h"
99send -- "m"
10−expect -exact "\r--> hm\[0K\r\[6C"
10+expect -exact "\[J\[2K\r--> hm"
1111send -- "m"
12−expect -exact "\r--> hmm\[0K\r\[7C"
12+expect -exact "\[J\[2K\r--> hmm"
1313send -- "m"
14−expect -exact "\r--> hmmm\[0K\r\[8C"
14+expect -exact "\[J\[2K\r--> hmmm"
1515send -- "m"
16−expect -exact "\r--> hmmmm\[0K\r\[9C"
16+expect -exact "\[J\[2K\r--> hmmmm"
1717send -- "m"
18−expect -exact "\r--> hmmmmm\[0K\r\[10C"
18+expect -exact "\[J\[2K\r--> hmmmmm"
1919send -- "\r"
20−expect -exact "\r--> hmmmmm\[0K\r\[10C\r
20+expect -exact "\[J\[2K\r--> hmmmmm\[J\[2K\r--> hmmmmm\r
2121error: invalid command name \"hmmmmm\"\r
2222\r
23−--> "
23+\[J\[2K\r--> "
2424send -- ""
2525expect eof
utils/language.go+3−3
@@ -4,7 +4,7 @@ import (
44 "fmt"
55 "io/ioutil"
66
7− "github.com/replit/prybar/linenoise"
7+ "github.com/chzyer/readline"
88)
99
1010type PluginBase interface {
@@ -104,12 +104,12 @@ func (lang Language) REPL() {
104104
105105func (lang Language) InternalREPL() {
106106 for {
107− line, err := linenoise.Linenoise(lang.ps1)
107+ line, err := readline.Line(lang.ps1)
108108 if err != nil {
109109 break
110110 }
111111 lang.REPLLikeEval(line)
112− linenoise.LinenoiseHistoryAdd(line)
112+ readline.AddHistory(line)
113113 }
114114}
115115
utils/utils.go−4
@@ -66,10 +66,6 @@ func DoCli(p PluginBase) {
6666 lang.SetPrompts(config.Ps1, config.Ps2)
6767 lang.REPL()
6868 } else if config.OurInteractive {
69− //LinenoiseSetCompleter(func(s string) []string {
70− // return []string{s + "A", s + "B", s + "B"}
71− //})
7269 lang.InternalREPL()
7370 }
74−
7571}
vendor/github.com/chzyer/readline/.gitignorenew file+2
@@ -0,0 +1,2 @@
1+*.exe
2+*.tmp
vendor/github.com/chzyer/readline/.travis.ymlnew file+10
@@ -0,0 +1,10 @@
1+language: go
2+go:
3+ - 1.5
4+before_install:
5+ - go get golang.org/x/crypto/ssh/terminal
6+script:
7+ - GOOS=windows go install github.com/chzyer/readline/example/...
8+ - GOOS=linux go install github.com/chzyer/readline/example/...
9+ - GOOS=darwin go install github.com/chzyer/readline/example/...
10+ - go test -v
vendor/github.com/chzyer/readline/CHANGELOG.mdnew file+58
@@ -0,0 +1,58 @@
1+# ChangeLog
2+
3+### 1.4 - 2016-07-25
4+
5+* [#60][60] Support dynamic autocompletion
6+* Fix ANSI parser on Windows
7+* Fix wrong column width in complete mode on Windows
8+* Remove dependent package "golang.org/x/crypto/ssh/terminal"
9+
10+### 1.3 - 2016-05-09
11+
12+* [#38][38] add SetChildren for prefix completer interface
13+* [#42][42] improve multiple lines compatibility
14+* [#43][43] remove sub-package(runes) for gopkg compatiblity
15+* [#46][46] Auto complete with space prefixed line
16+* [#48][48] support suspend process (ctrl+Z)
17+* [#49][49] fix bug that check equals with previous command
18+* [#53][53] Fix bug which causes integer divide by zero panicking when input buffer is empty
19+
20+### 1.2 - 2016-03-05
21+
22+* Add a demo for checking password strength [example/readline-pass-strength](https://github.com/chzyer/readline/blob/master/example/readline-pass-strength/readline-pass-strength.go), , written by [@sahib](https://github.com/sahib)
23+* [#23][23], support stdin remapping
24+* [#27][27], add a `UniqueEditLine` to `Config`, which will erase the editing line after user submited it, usually use in IM.
25+* Add a demo for multiline [example/readline-multiline](https://github.com/chzyer/readline/blob/master/example/readline-multiline/readline-multiline.go) which can submit one SQL by multiple lines.
26+* Supports performs even stdin/stdout is not a tty.
27+* Add a new simple apis for single instance, check by [here](https://github.com/chzyer/readline/blob/master/std.go). It need to save history manually if using this api.
28+* [#28][28], fixes the history is not working as expected.
29+* [#33][33], vim mode now support `c`, `d`, `x (delete character)`, `r (replace character)`
30+
31+### 1.1 - 2015-11-20
32+
33+* [#12][12] Add support for key `<Delete>`/`<Home>`/`<End>`
34+* Only enter raw mode as needed (calling `Readline()`), program will receive signal(e.g. Ctrl+C) if not interact with `readline`.
35+* Bugs fixed for `PrefixCompleter`
36+* Press `Ctrl+D` in empty line will cause `io.EOF` in error, Press `Ctrl+C` in anytime will cause `ErrInterrupt` instead of `io.EOF`, this will privodes a shell-like user experience.
37+* Customable Interrupt/EOF prompt in `Config`
38+* [#17][17] Change atomic package to use 32bit function to let it runnable on arm 32bit devices
39+* Provides a new password user experience(`readline.ReadPasswordEx()`).
40+
41+### 1.0 - 2015-10-14
42+
43+* Initial public release.
44+
45+[12]: https://github.com/chzyer/readline/pull/12
46+[17]: https://github.com/chzyer/readline/pull/17
47+[23]: https://github.com/chzyer/readline/pull/23
48+[27]: https://github.com/chzyer/readline/pull/27
49+[28]: https://github.com/chzyer/readline/pull/28
50+[33]: https://github.com/chzyer/readline/pull/33
51+[38]: https://github.com/chzyer/readline/pull/38
52+[42]: https://github.com/chzyer/readline/pull/42
53+[43]: https://github.com/chzyer/readline/pull/43
54+[46]: https://github.com/chzyer/readline/pull/46
55+[48]: https://github.com/chzyer/readline/pull/48
56+[49]: https://github.com/chzyer/readline/pull/49
57+[53]: https://github.com/chzyer/readline/pull/53
58+[60]: https://github.com/chzyer/readline/pull/60
vendor/github.com/chzyer/readline/LICENSEnew file+22
@@ -0,0 +1,22 @@
1+The MIT License (MIT)
2+
3+Copyright (c) 2015 Chzyer
4+
5+Permission is hereby granted, free of charge, to any person obtaining a copy
6+of this software and associated documentation files (the "Software"), to deal
7+in the Software without restriction, including without limitation the rights
8+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+copies of the Software, and to permit persons to whom the Software is
10+furnished to do so, subject to the following conditions:
11+
12+The above copyright notice and this permission notice shall be included in all
13+copies or substantial portions of the Software.
14+
15+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+SOFTWARE.
22+
vendor/github.com/chzyer/readline/README.mdnew file+306
@@ -0,0 +1,306 @@
1+# readline
2+
3+[![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg)](LICENSE.md)
4+[![Build Status](https://travis-ci.org/chzyer/readline.svg?branch=master)](https://travis-ci.org/chzyer/readline)
5+[![GoDoc](https://godoc.org/github.com/chzyer/readline?status.svg)](https://godoc.org/github.com/chzyer/readline)
6+[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/chzyer/readline?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
7+[![OpenCollective](https://opencollective.com/readline/badge/backers.svg)](#backers)
8+[![OpenCollective](https://opencollective.com/readline/badge/sponsors.svg)](#sponsors)
9+
10+Readline is A Pure Go Implementation of a libreadline-style Library.
11+The goal is to be a powerful alternater for GNU-Readline.
12+
13+
14+**WHY:**
15+Readline will support most of features which GNU Readline is supported, and provide a pure go environment and a MIT license.
16+
17+It can also provides shell-like interactives by using [flagly](https://github.com/chzyer/flagly) (demo: [flagly-shell](https://github.com/chzyer/flagly/blob/master/demo/flagly-shell/flagly-shell.go))
18+
19+# Demo
20+
21+![demo](https://raw.githubusercontent.com/chzyer/readline/assets/demo.gif)
22+
23+Also works fine in windows
24+
25+![demo windows](https://raw.githubusercontent.com/chzyer/readline/assets/windows.gif)
26+
27+
28+* [example/readline-demo](https://github.com/chzyer/readline/blob/master/example/readline-demo/readline-demo.go) The source code about the demo above
29+
30+* [example/readline-im](https://github.com/chzyer/readline/blob/master/example/readline-im/readline-im.go) Example for how to write a IM program.
31+
32+* [example/readline-multiline](https://github.com/chzyer/readline/blob/master/example/readline-multiline/readline-multiline.go) Example for how to parse command which can submit by multiple time.
33+
34+* [example/readline-pass-strength](https://github.com/chzyer/readline/blob/master/example/readline-pass-strength/readline-pass-strength.go) A example about checking password strength, written by [@sahib](https://github.com/sahib)
35+
36+# Todo
37+* Vi Mode is not completely finish
38+* More funny examples
39+* Support dumb/eterm-color terminal in emacs
40+
41+# Features
42+* Support emacs/vi mode, almost all basic features that GNU-Readline is supported
43+* zsh-style backward/forward history search
44+* zsh-style completion
45+* Readline auto refresh when others write to Stdout while editing (it needs specify the Stdout/Stderr provided by *readline.Instance to others).
46+* Support colourful prompt in all platforms.
47+
48+# Usage
49+
50+* Import package
51+
52+```
53+go get gopkg.in/readline.v1
54+```
55+
56+or
57+
58+```
59+go get github.com/chzyer/readline
60+```
61+
62+* Simplest example
63+
64+```go
65+import "gopkg.in/readline.v1"
66+
67+rl, err := readline.New("> ")
68+if err != nil {
69+ panic(err)
70+}
71+defer rl.Close()
72+
73+for {
74+ line, err := rl.Readline()
75+ if err != nil { // io.EOF, readline.ErrInterrupt
76+ break
77+ }
78+ println(line)
79+}
80+```
81+
82+* Example with durable history
83+
84+```go
85+rl, err := readline.NewEx(&readline.Config{
86+ Prompt: "> ",
87+ HistoryFile: "/tmp/readline.tmp",
88+})
89+if err != nil {
90+ panic(err)
91+}
92+defer rl.Close()
93+
94+for {
95+ line, err := rl.Readline()
96+ if err != nil { // io.EOF, readline.ErrInterrupt
97+ break
98+ }
99+ println(line)
100+}
101+```
102+
103+* Example with auto completion
104+
105+```go
106+import (
107+ "gopkg.in/readline.v1"
108+)
109+
110+var completer = readline.NewPrefixCompleter(
111+ readline.PcItem("say",
112+ readline.PcItem("hello"),
113+ readline.PcItem("bye"),
114+ ),
115+ readline.PcItem("help"),
116+)
117+
118+rl, err := readline.NewEx(&readline.Config{
119+ Prompt: "> ",
120+ AutoComplete: completer,
121+})
122+if err != nil {
123+ panic(err)
124+}
125+defer rl.Close()
126+
127+for {
128+ line, err := rl.Readline()
129+ if err != nil { // io.EOF, readline.ErrInterrupt
130+ break
131+ }
132+ println(line)
133+}
134+```
135+
136+
137+# Shortcut
138+
139+`Meta`+`B` means press `Esc` and `n` separately.
140+Users can change that in terminal simulator(i.e. iTerm2) to `Alt`+`B`
141+Notice: `Meta`+`B` is equals with `Alt`+`B` in windows.
142+
143+* Shortcut in normal mode
144+
145+| Shortcut | Comment |
146+|--------------------|------------------------------------------|
147+| `Ctrl`+`A` | Beginning of line |
148+| `Ctrl`+`B` / `←` | Backward one character |
149+| `Meta`+`B` | Backward one word |
150+| `Ctrl`+`C` | Send io.EOF |
151+| `Ctrl`+`D` | Delete one character |
152+| `Meta`+`D` | Delete one word |
153+| `Ctrl`+`E` | End of line |
154+| `Ctrl`+`F` / `→` | Forward one character |
155+| `Meta`+`F` | Forward one word |
156+| `Ctrl`+`G` | Cancel |
157+| `Ctrl`+`H` | Delete previous character |
158+| `Ctrl`+`I` / `Tab` | Command line completion |
159+| `Ctrl`+`J` | Line feed |
160+| `Ctrl`+`K` | Cut text to the end of line |
161+| `Ctrl`+`L` | Clear screen |
162+| `Ctrl`+`M` | Same as Enter key |
163+| `Ctrl`+`N` / `↓` | Next line (in history) |
164+| `Ctrl`+`P` / `↑` | Prev line (in history) |
165+| `Ctrl`+`R` | Search backwards in history |
166+| `Ctrl`+`S` | Search forwards in history |
167+| `Ctrl`+`T` | Transpose characters |
168+| `Meta`+`T` | Transpose words (TODO) |
169+| `Ctrl`+`U` | Cut text to the beginning of line |
170+| `Ctrl`+`W` | Cut previous word |
171+| `Backspace` | Delete previous character |
172+| `Meta`+`Backspace` | Cut previous word |
173+| `Enter` | Line feed |
174+
175+
176+* Shortcut in Search Mode (`Ctrl`+`S` or `Ctrl`+`r` to enter this mode)
177+
178+| Shortcut | Comment |
179+|-------------------------|---------------------------------------------|
180+| `Ctrl`+`S` | Search forwards in history |
181+| `Ctrl`+`R` | Search backwards in history |
182+| `Ctrl`+`C` / `Ctrl`+`G` | Exit Search Mode and revert the history |
183+| `Backspace` | Delete previous character |
184+| Other | Exit Search Mode |
185+
186+* Shortcut in Complete Select Mode (double `Tab` to enter this mode)
187+
188+| Shortcut | Comment |
189+|-------------------------|---------------------------------------------|
190+| `Ctrl`+`F` | Move Forward |
191+| `Ctrl`+`B` | Move Backward |
192+| `Ctrl`+`N` | Move to next line |
193+| `Ctrl`+`P` | Move to previous line |
194+| `Ctrl`+`A` | Move to the first candicate in current line |
195+| `Ctrl`+`E` | Move to the last candicate in current line |
196+| `Tab` / `Enter` | Use the word on cursor to complete |
197+| `Ctrl`+`C` / `Ctrl`+`G` | Exit Complete Select Mode |
198+| Other | Exit Complete Select Mode |
199+
200+# Tested with
201+
202+| Environment | $TERM |
203+|-------------------------------|--------|
204+| Mac OS X iTerm2 | xterm |
205+| Mac OS X default Terminal.app | xterm |
206+| Mac OS X iTerm2 Screen | screen |
207+| Mac OS X iTerm2 Tmux | screen |
208+| Ubuntu Server 14.04 LTS | linux |
209+| Centos 7 | linux |
210+| Windows 10 | - |
211+
212+### Notice:
213+* `Ctrl`+`A` is not working in `screen` because it used as a control command by default
214+
215+If you test it otherwhere, whether it works fine or not, please let me know!
216+
217+## Who is using Readline
218+
219+* [cockroachdb/cockroach](https://github.com/cockroachdb/cockroach)
220+* [youtube/doorman](https://github.com/youtube/doorman)
221+* [bom-d-van/harp](https://github.com/bom-d-van/harp)
222+* [abiosoft/ishell](https://github.com/abiosoft/ishell)
223+* [robertkrimen/otto](https://github.com/robertkrimen/otto)
224+* [Netflix/hal-9001](https://github.com/Netflix/hal-9001)
225+* [docker/go-p9p](https://github.com/docker/go-p9p)
226+
227+# Feedback
228+
229+If you have any questions, please submit a github issue and any pull requests is welcomed :)
230+
231+* [https://twitter.com/chzyer](https://twitter.com/chzyer)
232+* [http://weibo.com/2145262190](http://weibo.com/2145262190)
233+
234+
235+# Backers
236+
237+Love Readline? Help me keep it alive by donating funds to cover project expenses!<br />
238+[[Become a backer](https://opencollective.com/readline#backer)]
239+
240+<a href="https://opencollective.com/readline/backer/0/website" target="_blank"><img src="https://opencollective.com/readline/backer/0/avatar.svg"></a>
241+<a href="https://opencollective.com/readline/backer/1/website" target="_blank"><img src="https://opencollective.com/readline/backer/1/avatar.svg"></a>
242+<a href="https://opencollective.com/readline/backer/2/website" target="_blank"><img src="https://opencollective.com/readline/backer/2/avatar.svg"></a>
243+<a href="https://opencollective.com/readline/backer/3/website" target="_blank"><img src="https://opencollective.com/readline/backer/3/avatar.svg"></a>
244+<a href="https://opencollective.com/readline/backer/4/website" target="_blank"><img src="https://opencollective.com/readline/backer/4/avatar.svg"></a>
245+<a href="https://opencollective.com/readline/backer/5/website" target="_blank"><img src="https://opencollective.com/readline/backer/5/avatar.svg"></a>
246+<a href="https://opencollective.com/readline/backer/6/website" target="_blank"><img src="https://opencollective.com/readline/backer/6/avatar.svg"></a>
247+<a href="https://opencollective.com/readline/backer/7/website" target="_blank"><img src="https://opencollective.com/readline/backer/7/avatar.svg"></a>
248+<a href="https://opencollective.com/readline/backer/8/website" target="_blank"><img src="https://opencollective.com/readline/backer/8/avatar.svg"></a>
249+<a href="https://opencollective.com/readline/backer/9/website" target="_blank"><img src="https://opencollective.com/readline/backer/9/avatar.svg"></a>
250+<a href="https://opencollective.com/readline/backer/10/website" target="_blank"><img src="https://opencollective.com/readline/backer/10/avatar.svg"></a>
251+<a href="https://opencollective.com/readline/backer/11/website" target="_blank"><img src="https://opencollective.com/readline/backer/11/avatar.svg"></a>
252+<a href="https://opencollective.com/readline/backer/12/website" target="_blank"><img src="https://opencollective.com/readline/backer/12/avatar.svg"></a>
253+<a href="https://opencollective.com/readline/backer/13/website" target="_blank"><img src="https://opencollective.com/readline/backer/13/avatar.svg"></a>
254+<a href="https://opencollective.com/readline/backer/14/website" target="_blank"><img src="https://opencollective.com/readline/backer/14/avatar.svg"></a>
255+<a href="https://opencollective.com/readline/backer/15/website" target="_blank"><img src="https://opencollective.com/readline/backer/15/avatar.svg"></a>
256+<a href="https://opencollective.com/readline/backer/16/website" target="_blank"><img src="https://opencollective.com/readline/backer/16/avatar.svg"></a>
257+<a href="https://opencollective.com/readline/backer/17/website" target="_blank"><img src="https://opencollective.com/readline/backer/17/avatar.svg"></a>
258+<a href="https://opencollective.com/readline/backer/18/website" target="_blank"><img src="https://opencollective.com/readline/backer/18/avatar.svg"></a>
259+<a href="https://opencollective.com/readline/backer/19/website" target="_blank"><img src="https://opencollective.com/readline/backer/19/avatar.svg"></a>
260+<a href="https://opencollective.com/readline/backer/20/website" target="_blank"><img src="https://opencollective.com/readline/backer/20/avatar.svg"></a>
261+<a href="https://opencollective.com/readline/backer/21/website" target="_blank"><img src="https://opencollective.com/readline/backer/21/avatar.svg"></a>
262+<a href="https://opencollective.com/readline/backer/22/website" target="_blank"><img src="https://opencollective.com/readline/backer/22/avatar.svg"></a>
263+<a href="https://opencollective.com/readline/backer/23/website" target="_blank"><img src="https://opencollective.com/readline/backer/23/avatar.svg"></a>
264+<a href="https://opencollective.com/readline/backer/24/website" target="_blank"><img src="https://opencollective.com/readline/backer/24/avatar.svg"></a>
265+<a href="https://opencollective.com/readline/backer/25/website" target="_blank"><img src="https://opencollective.com/readline/backer/25/avatar.svg"></a>
266+<a href="https://opencollective.com/readline/backer/26/website" target="_blank"><img src="https://opencollective.com/readline/backer/26/avatar.svg"></a>
267+<a href="https://opencollective.com/readline/backer/27/website" target="_blank"><img src="https://opencollective.com/readline/backer/27/avatar.svg"></a>
268+<a href="https://opencollective.com/readline/backer/28/website" target="_blank"><img src="https://opencollective.com/readline/backer/28/avatar.svg"></a>
269+<a href="https://opencollective.com/readline/backer/29/website" target="_blank"><img src="https://opencollective.com/readline/backer/29/avatar.svg"></a>
270+
271+
272+# Sponsors
273+
274+Become a sponsor and get your logo here on our Github page. [[Become a sponsor](https://opencollective.com/readline#sponsor)]
275+
276+<a href="https://opencollective.com/readline/sponsor/0/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/0/avatar.svg"></a>
277+<a href="https://opencollective.com/readline/sponsor/1/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/1/avatar.svg"></a>
278+<a href="https://opencollective.com/readline/sponsor/2/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/2/avatar.svg"></a>
279+<a href="https://opencollective.com/readline/sponsor/3/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/3/avatar.svg"></a>
280+<a href="https://opencollective.com/readline/sponsor/4/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/4/avatar.svg"></a>
281+<a href="https://opencollective.com/readline/sponsor/5/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/5/avatar.svg"></a>
282+<a href="https://opencollective.com/readline/sponsor/6/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/6/avatar.svg"></a>
283+<a href="https://opencollective.com/readline/sponsor/7/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/7/avatar.svg"></a>
284+<a href="https://opencollective.com/readline/sponsor/8/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/8/avatar.svg"></a>
285+<a href="https://opencollective.com/readline/sponsor/9/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/9/avatar.svg"></a>
286+<a href="https://opencollective.com/readline/sponsor/10/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/10/avatar.svg"></a>
287+<a href="https://opencollective.com/readline/sponsor/11/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/11/avatar.svg"></a>
288+<a href="https://opencollective.com/readline/sponsor/12/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/12/avatar.svg"></a>
289+<a href="https://opencollective.com/readline/sponsor/13/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/13/avatar.svg"></a>
290+<a href="https://opencollective.com/readline/sponsor/14/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/14/avatar.svg"></a>
291+<a href="https://opencollective.com/readline/sponsor/15/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/15/avatar.svg"></a>
292+<a href="https://opencollective.com/readline/sponsor/16/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/16/avatar.svg"></a>
293+<a href="https://opencollective.com/readline/sponsor/17/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/17/avatar.svg"></a>
294+<a href="https://opencollective.com/readline/sponsor/18/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/18/avatar.svg"></a>
295+<a href="https://opencollective.com/readline/sponsor/19/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/19/avatar.svg"></a>
296+<a href="https://opencollective.com/readline/sponsor/20/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/20/avatar.svg"></a>
297+<a href="https://opencollective.com/readline/sponsor/21/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/21/avatar.svg"></a>
298+<a href="https://opencollective.com/readline/sponsor/22/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/22/avatar.svg"></a>
299+<a href="https://opencollective.com/readline/sponsor/23/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/23/avatar.svg"></a>
300+<a href="https://opencollective.com/readline/sponsor/24/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/24/avatar.svg"></a>
301+<a href="https://opencollective.com/readline/sponsor/25/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/25/avatar.svg"></a>
302+<a href="https://opencollective.com/readline/sponsor/26/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/26/avatar.svg"></a>
303+<a href="https://opencollective.com/readline/sponsor/27/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/27/avatar.svg"></a>
304+<a href="https://opencollective.com/readline/sponsor/28/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/28/avatar.svg"></a>
305+<a href="https://opencollective.com/readline/sponsor/29/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/29/avatar.svg"></a>
306+
vendor/github.com/chzyer/readline/ansi_windows.gonew file+246
@@ -0,0 +1,246 @@
1+// +build windows
2+
3+package readline
4+
5+import (
6+ "bufio"
7+ "io"
8+ "strconv"
9+ "strings"
10+ "sync"
11+ "unicode/utf8"
12+ "unsafe"
13+)
14+
15+const (
16+ _ = uint16(0)
17+ COLOR_FBLUE = 0x0001
18+ COLOR_FGREEN = 0x0002
19+ COLOR_FRED = 0x0004
20+ COLOR_FINTENSITY = 0x0008
21+
22+ COLOR_BBLUE = 0x0010
23+ COLOR_BGREEN = 0x0020
24+ COLOR_BRED = 0x0040
25+ COLOR_BINTENSITY = 0x0080
26+
27+ COMMON_LVB_UNDERSCORE = 0x8000
28+)
29+
30+var ColorTableFg = []word{
31+ 0, // 30: Black
32+ COLOR_FRED, // 31: Red
33+ COLOR_FGREEN, // 32: Green
34+ COLOR_FRED | COLOR_FGREEN, // 33: Yellow
35+ COLOR_FBLUE, // 34: Blue
36+ COLOR_FRED | COLOR_FBLUE, // 35: Magenta
37+ COLOR_FGREEN | COLOR_FBLUE, // 36: Cyan
38+ COLOR_FRED | COLOR_FBLUE | COLOR_FGREEN, // 37: White
39+}
40+
41+var ColorTableBg = []word{
42+ 0, // 40: Black
43+ COLOR_BRED, // 41: Red
44+ COLOR_BGREEN, // 42: Green
45+ COLOR_BRED | COLOR_BGREEN, // 43: Yellow
46+ COLOR_BBLUE, // 44: Blue
47+ COLOR_BRED | COLOR_BBLUE, // 45: Magenta
48+ COLOR_BGREEN | COLOR_BBLUE, // 46: Cyan
49+ COLOR_BRED | COLOR_BBLUE | COLOR_BGREEN, // 47: White
50+}
51+
52+type ANSIWriter struct {
53+ target io.Writer
54+ wg sync.WaitGroup
55+ ctx *ANSIWriterCtx
56+ sync.Mutex
57+}
58+
59+func NewANSIWriter(w io.Writer) *ANSIWriter {
60+ a := &ANSIWriter{
61+ target: w,
62+ ctx: NewANSIWriterCtx(w),
63+ }
64+ return a
65+}
66+
67+func (a *ANSIWriter) Close() error {
68+ a.wg.Wait()
69+ return nil
70+}
71+
72+type ANSIWriterCtx struct {
73+ isEsc bool
74+ isEscSeq bool
75+ arg []string
76+ target *bufio.Writer
77+ wantFlush bool
78+}
79+
80+func NewANSIWriterCtx(target io.Writer) *ANSIWriterCtx {
81+ return &ANSIWriterCtx{
82+ target: bufio.NewWriter(target),
83+ }
84+}
85+
86+func (a *ANSIWriterCtx) Flush() {
87+ a.target.Flush()
88+}
89+
90+func (a *ANSIWriterCtx) process(r rune) bool {
91+ if a.wantFlush {
92+ if r == 0 || r == CharEsc {
93+ a.wantFlush = false
94+ a.target.Flush()
95+ }
96+ }
97+ if a.isEscSeq {
98+ a.isEscSeq = a.ioloopEscSeq(a.target, r, &a.arg)
99+ return true
100+ }
101+
102+ switch r {
103+ case CharEsc:
104+ a.isEsc = true
105+ case '[':
106+ if a.isEsc {
107+ a.arg = nil
108+ a.isEscSeq = true
109+ a.isEsc = false
110+ break
111+ }
112+ fallthrough
113+ default:
114+ a.target.WriteRune(r)
115+ a.wantFlush = true
116+ }
117+ return true
118+}
119+
120+func (a *ANSIWriterCtx) ioloopEscSeq(w *bufio.Writer, r rune, argptr *[]string) bool {
121+ arg := *argptr
122+ var err error
123+
124+ if r >= 'A' && r <= 'D' {
125+ count := short(GetInt(arg, 1))
126+ info, err := GetConsoleScreenBufferInfo()
127+ if err != nil {
128+ return false
129+ }
130+ switch r {
131+ case 'A': // up
132+ info.dwCursorPosition.y -= count
133+ case 'B': // down
134+ info.dwCursorPosition.y += count
135+ case 'C': // right
136+ info.dwCursorPosition.x += count
137+ case 'D': // left
138+ info.dwCursorPosition.x -= count
139+ }
140+ SetConsoleCursorPosition(&info.dwCursorPosition)
141+ return false
142+ }
143+
144+ switch r {
145+ case 'J':
146+ killLines()
147+ case 'K':
148+ eraseLine()
149+ case 'm':
150+ color := word(0)
151+ for _, item := range arg {
152+ var c int
153+ c, err = strconv.Atoi(item)
154+ if err != nil {
155+ w.WriteString("[" + strings.Join(arg, ";") + "m")
156+ break
157+ }
158+ if c >= 30 && c < 40 {
159+ color ^= COLOR_FINTENSITY
160+ color |= ColorTableFg[c-30]
161+ } else if c >= 40 && c < 50 {
162+ color ^= COLOR_BINTENSITY
163+ color |= ColorTableBg[c-40]
164+ } else if c == 4 {
165+ color |= COMMON_LVB_UNDERSCORE | ColorTableFg[7]
166+ } else { // unknown code treat as reset
167+ color = ColorTableFg[7]
168+ }
169+ }
170+ if err != nil {
171+ break
172+ }
173+ kernel.SetConsoleTextAttribute(stdout, uintptr(color))
174+ case '\007': // set title
175+ case ';':
176+ if len(arg) == 0 || arg[len(arg)-1] != "" {
177+ arg = append(arg, "")
178+ *argptr = arg
179+ }
180+ return true
181+ default:
182+ if len(arg) == 0 {
183+ arg = append(arg, "")
184+ }
185+ arg[len(arg)-1] += string(r)
186+ *argptr = arg
187+ return true
188+ }
189+ *argptr = nil
190+ return false
191+}
192+
193+func (a *ANSIWriter) Write(b []byte) (int, error) {
194+ a.Lock()
195+ defer a.Unlock()
196+
197+ off := 0
198+ for len(b) > off {
199+ r, size := utf8.DecodeRune(b[off:])
200+ if size == 0 {
201+ return off, io.ErrShortWrite
202+ }
203+ off += size
204+ a.ctx.process(r)
205+ }
206+ a.ctx.Flush()
207+ return off, nil
208+}
209+
210+func killLines() error {
211+ sbi, err := GetConsoleScreenBufferInfo()
212+ if err != nil {
213+ return err
214+ }
215+
216+ size := (sbi.dwCursorPosition.y - sbi.dwSize.y) * sbi.dwSize.x
217+ size += sbi.dwCursorPosition.x
218+
219+ var written int
220+ kernel.FillConsoleOutputAttribute(stdout, uintptr(ColorTableFg[7]),
221+ uintptr(size),
222+ sbi.dwCursorPosition.ptr(),
223+ uintptr(unsafe.Pointer(&written)),
224+ )
225+ return kernel.FillConsoleOutputCharacterW(stdout, uintptr(' '),
226+ uintptr(size),
227+ sbi.dwCursorPosition.ptr(),
228+ uintptr(unsafe.Pointer(&written)),
229+ )
230+}
231+
232+func eraseLine() error {
233+ sbi, err := GetConsoleScreenBufferInfo()
234+ if err != nil {
235+ return err
236+ }
237+
238+ size := sbi.dwSize.x
239+ sbi.dwCursorPosition.x = 0
240+ var written int
241+ return kernel.FillConsoleOutputCharacterW(stdout, uintptr(' '),
242+ uintptr(size),
243+ sbi.dwCursorPosition.ptr(),
244+ uintptr(unsafe.Pointer(&written)),
245+ )
246+}
vendor/github.com/chzyer/readline/char.gonew file+36
@@ -0,0 +1,36 @@
1+package readline
2+
3+const (
4+ CharLineStart = 1
5+ CharBackward = 2
6+ CharInterrupt = 3
7+ CharDelete = 4
8+ CharLineEnd = 5
9+ CharForward = 6
10+ CharBell = 7
11+ CharCtrlH = 8
12+ CharTab = 9
13+ CharCtrlJ = 10
14+ CharKill = 11
15+ CharCtrlL = 12
16+ CharEnter = 13
17+ CharNext = 14
18+ CharPrev = 16
19+ CharBckSearch = 18
20+ CharFwdSearch = 19
21+ CharTranspose = 20
22+ CharCtrlU = 21
23+ CharCtrlW = 23
24+ CharCtrlZ = 26
25+ CharEsc = 27
26+ CharEscapeEx = 91
27+ CharBackspace = 127
28+)
29+
30+const (
31+ MetaBackward rune = -iota - 1
32+ MetaForward
33+ MetaDelete
34+ MetaBackspace
35+ MetaTranspose
36+)
vendor/github.com/chzyer/readline/complete.gonew file+273
@@ -0,0 +1,273 @@
1+package readline
2+
3+import (
4+ "bufio"
5+ "bytes"
6+ "fmt"
7+ "io"
8+)
9+
10+type AutoCompleter interface {
11+ // Readline will pass the whole line and current offset to it
12+ // Completer need to pass all the candidates, and how long they shared the same characters in line
13+ // Example:
14+ // [go, git, git-shell, grep]
15+ // Do("g", 1) => ["o", "it", "it-shell", "rep"], 1
16+ // Do("gi", 2) => ["t", "t-shell"], 2
17+ // Do("git", 3) => ["", "-shell"], 3
18+ Do(line []rune, pos int) (newLine [][]rune, length int)
19+}
20+
21+type opCompleter struct {
22+ w io.Writer
23+ op *Operation
24+ width int
25+
26+ inCompleteMode bool
27+ inSelectMode bool
28+ candidate [][]rune
29+ candidateSource []rune
30+ candidateOff int
31+ candidateChoise int
32+ candidateColNum int
33+}
34+
35+func newOpCompleter(w io.Writer, op *Operation, width int) *opCompleter {
36+ return &opCompleter{
37+ w: w,
38+ op: op,
39+ width: width,
40+ }
41+}
42+
43+func (o *opCompleter) doSelect() {
44+ if len(o.candidate) == 1 {
45+ o.op.buf.WriteRunes(o.candidate[0])
46+ o.ExitCompleteMode(false)
47+ return
48+ }
49+ o.nextCandidate(1)
50+ o.CompleteRefresh()
51+}
52+
53+func (o *opCompleter) nextCandidate(i int) {
54+ o.candidateChoise += i
55+ o.candidateChoise = o.candidateChoise % len(o.candidate)
56+ if o.candidateChoise < 0 {
57+ o.candidateChoise = len(o.candidate) + o.candidateChoise
58+ }
59+}
60+
61+func (o *opCompleter) OnComplete() {
62+ if o.IsInCompleteSelectMode() {
63+ o.doSelect()
64+ return
65+ }
66+
67+ buf := o.op.buf
68+ rs := buf.Runes()
69+
70+ if o.IsInCompleteMode() && o.candidateSource != nil && runes.Equal(rs, o.candidateSource) {
71+ o.EnterCompleteSelectMode()
72+ o.doSelect()
73+ return
74+ }
75+
76+ o.ExitCompleteSelectMode()
77+ o.candidateSource = rs
78+ newLines, offset := o.op.cfg.AutoComplete.Do(rs, buf.idx)
79+ if len(newLines) == 0 {
80+ o.ExitCompleteMode(false)
81+ return
82+ }
83+
84+ // only Aggregate candidates in non-complete mode
85+ if !o.IsInCompleteMode() {
86+ if len(newLines) == 1 {
87+ buf.WriteRunes(newLines[0])
88+ o.ExitCompleteMode(false)
89+ return
90+ }
91+
92+ same, size := runes.Aggregate(newLines)
93+ if size > 0 {
94+ buf.WriteRunes(same)
95+ o.ExitCompleteMode(false)
96+ return
97+ }
98+ }
99+
100+ o.EnterCompleteMode(offset, newLines)
101+}
102+
103+func (o *opCompleter) IsInCompleteSelectMode() bool {
104+ return o.inSelectMode
105+}
106+
107+func (o *opCompleter) IsInCompleteMode() bool {
108+ return o.inCompleteMode
109+}
110+
111+func (o *opCompleter) HandleCompleteSelect(r rune) bool {
112+ next := true
113+ switch r {
114+ case CharEnter, CharCtrlJ:
115+ next = false
116+ o.op.buf.WriteRunes(o.op.candidate[o.op.candidateChoise])
117+ o.ExitCompleteMode(false)
118+ case CharLineStart:
119+ num := o.candidateChoise % o.candidateColNum
120+ o.nextCandidate(-num)
121+ case CharLineEnd:
122+ num := o.candidateColNum - o.candidateChoise%o.candidateColNum - 1
123+ o.candidateChoise += num
124+ if o.candidateChoise >= len(o.candidate) {
125+ o.candidateChoise = len(o.candidate) - 1
126+ }
127+ case CharBackspace:
128+ o.ExitCompleteSelectMode()
129+ next = false
130+ case CharTab, CharForward:
131+ o.doSelect()
132+ case CharBell, CharInterrupt:
133+ o.ExitCompleteMode(true)
134+ next = false
135+ case CharNext:
136+ tmpChoise := o.candidateChoise + o.candidateColNum
137+ if tmpChoise >= o.getMatrixSize() {
138+ tmpChoise -= o.getMatrixSize()
139+ } else if tmpChoise >= len(o.candidate) {
140+ tmpChoise += o.candidateColNum
141+ tmpChoise -= o.getMatrixSize()
142+ }
143+ o.candidateChoise = tmpChoise
144+ case CharBackward:
145+ o.nextCandidate(-1)
146+ case CharPrev:
147+ tmpChoise := o.candidateChoise - o.candidateColNum
148+ if tmpChoise < 0 {
149+ tmpChoise += o.getMatrixSize()
150+ if tmpChoise >= len(o.candidate) {
151+ tmpChoise -= o.candidateColNum
152+ }
153+ }
154+ o.candidateChoise = tmpChoise
155+ default:
156+ next = false
157+ o.ExitCompleteSelectMode()
158+ }
159+ if next {
160+ o.CompleteRefresh()
161+ return true
162+ }
163+ return false
164+}
165+
166+func (o *opCompleter) getMatrixSize() int {
167+ line := len(o.candidate) / o.candidateColNum
168+ if len(o.candidate)%o.candidateColNum != 0 {
169+ line++
170+ }
171+ return line * o.candidateColNum
172+}
173+
174+func (o *opCompleter) OnWidthChange(newWidth int) {
175+ o.width = newWidth
176+}
177+
178+func (o *opCompleter) CompleteRefresh() {
179+ if !o.inCompleteMode {
180+ return
181+ }
182+ lineCnt := o.op.buf.CursorLineCount()
183+ colWidth := 0
184+ for _, c := range o.candidate {
185+ w := runes.WidthAll(c)
186+ if w > colWidth {
187+ colWidth = w
188+ }
189+ }
190+ colWidth += o.candidateOff + 1
191+ same := o.op.buf.RuneSlice(-o.candidateOff)
192+
193+ // -1 to avoid reach the end of line
194+ width := o.width - 1
195+ colNum := width / colWidth
196+ colWidth += (width - (colWidth * colNum)) / colNum
197+
198+ o.candidateColNum = colNum
199+ buf := bufio.NewWriter(o.w)
200+ buf.Write(bytes.Repeat([]byte("\n"), lineCnt))
201+
202+ colIdx := 0
203+ lines := 1
204+ buf.WriteString("\033[J")
205+ for idx, c := range o.candidate {
206+ inSelect := idx == o.candidateChoise && o.IsInCompleteSelectMode()
207+ if inSelect {
208+ buf.WriteString("\033[30;47m")
209+ }
210+ buf.WriteString(string(same))
211+ buf.WriteString(string(c))
212+ buf.Write(bytes.Repeat([]byte(" "), colWidth-len(c)))
213+
214+ if inSelect {
215+ buf.WriteString("\033[0m")
216+ }
217+
218+ colIdx++
219+ if colIdx == colNum {
220+ buf.WriteString("\n")
221+ lines++
222+ colIdx = 0
223+ }
224+ }
225+
226+ // move back
227+ fmt.Fprintf(buf, "\033[%dA\r", lineCnt-1+lines)
228+ fmt.Fprintf(buf, "\033[%dC", o.op.buf.idx+o.op.buf.PromptLen())
229+ buf.Flush()
230+}
231+
232+func (o *opCompleter) aggCandidate(candidate [][]rune) int {
233+ offset := 0
234+ for i := 0; i < len(candidate[0]); i++ {
235+ for j := 0; j < len(candidate)-1; j++ {
236+ if i > len(candidate[j]) {
237+ goto aggregate
238+ }
239+ if candidate[j][i] != candidate[j+1][i] {
240+ goto aggregate
241+ }
242+ }
243+ offset = i
244+ }
245+aggregate:
246+ return offset
247+}
248+
249+func (o *opCompleter) EnterCompleteSelectMode() {
250+ o.inSelectMode = true
251+ o.candidateChoise = -1
252+ o.CompleteRefresh()
253+}
254+
255+func (o *opCompleter) EnterCompleteMode(offset int, candidate [][]rune) {
256+ o.inCompleteMode = true
257+ o.candidate = candidate
258+ o.candidateOff = offset
259+ o.CompleteRefresh()
260+}
261+
262+func (o *opCompleter) ExitCompleteSelectMode() {
263+ o.inSelectMode = false
264+ o.candidate = nil
265+ o.candidateChoise = -1
266+ o.candidateOff = -1
267+ o.candidateSource = nil
268+}
269+
270+func (o *opCompleter) ExitCompleteMode(revent bool) {
271+ o.inCompleteMode = false
272+ o.ExitCompleteSelectMode()
273+}
vendor/github.com/chzyer/readline/complete_helper.gonew file+165
@@ -0,0 +1,165 @@
1+package readline
2+
3+import (
4+ "bytes"
5+ "strings"
6+)
7+
8+// Caller type for dynamic completion
9+type DynamicCompleteFunc func(string) []string
10+
11+type PrefixCompleterInterface interface {
12+ Print(prefix string, level int, buf *bytes.Buffer)
13+ Do(line []rune, pos int) (newLine [][]rune, length int)
14+ GetName() []rune
15+ GetChildren() []PrefixCompleterInterface
16+ SetChildren(children []PrefixCompleterInterface)
17+}
18+
19+type DynamicPrefixCompleterInterface interface {
20+ PrefixCompleterInterface
21+ IsDynamic() bool
22+ GetDynamicNames(line []rune) [][]rune
23+}
24+
25+type PrefixCompleter struct {
26+ Name []rune
27+ Dynamic bool
28+ Callback DynamicCompleteFunc
29+ Children []PrefixCompleterInterface
30+}
31+
32+func (p *PrefixCompleter) Tree(prefix string) string {
33+ buf := bytes.NewBuffer(nil)
34+ p.Print(prefix, 0, buf)
35+ return buf.String()
36+}
37+
38+func Print(p PrefixCompleterInterface, prefix string, level int, buf *bytes.Buffer) {
39+ if strings.TrimSpace(string(p.GetName())) != "" {
40+ buf.WriteString(prefix)
41+ if level > 0 {
42+ buf.WriteString("├")
43+ buf.WriteString(strings.Repeat("─", (level*4)-2))
44+ buf.WriteString(" ")
45+ }
46+ buf.WriteString(string(p.GetName()) + "\n")
47+ level++
48+ }
49+ for _, ch := range p.GetChildren() {
50+ ch.Print(prefix, level, buf)
51+ }
52+}
53+
54+func (p *PrefixCompleter) Print(prefix string, level int, buf *bytes.Buffer) {
55+ Print(p, prefix, level, buf)
56+}
57+
58+func (p *PrefixCompleter) IsDynamic() bool {
59+ return p.Dynamic
60+}
61+
62+func (p *PrefixCompleter) GetName() []rune {
63+ return p.Name
64+}
65+
66+func (p *PrefixCompleter) GetDynamicNames(line []rune) [][]rune {
67+ var names = [][]rune{}
68+ for _, name := range p.Callback(string(line)) {
69+ names = append(names, []rune(name+" "))
70+ }
71+ return names
72+}
73+
74+func (p *PrefixCompleter) GetChildren() []PrefixCompleterInterface {
75+ return p.Children
76+}
77+
78+func (p *PrefixCompleter) SetChildren(children []PrefixCompleterInterface) {
79+ p.Children = children
80+}
81+
82+func NewPrefixCompleter(pc ...PrefixCompleterInterface) *PrefixCompleter {
83+ return PcItem("", pc...)
84+}
85+
86+func PcItem(name string, pc ...PrefixCompleterInterface) *PrefixCompleter {
87+ name += " "
88+ return &PrefixCompleter{
89+ Name: []rune(name),
90+ Dynamic: false,
91+ Children: pc,
92+ }
93+}
94+
95+func PcItemDynamic(callback DynamicCompleteFunc, pc ...PrefixCompleterInterface) *PrefixCompleter {
96+ return &PrefixCompleter{
97+ Callback: callback,
98+ Dynamic: true,
99+ Children: pc,
100+ }
101+}
102+
103+func (p *PrefixCompleter) Do(line []rune, pos int) (newLine [][]rune, offset int) {
104+ return doInternal(p, line, pos, line)
105+}
106+
107+func Do(p PrefixCompleterInterface, line []rune, pos int) (newLine [][]rune, offset int) {
108+ return doInternal(p, line, pos, line)
109+}
110+
111+func doInternal(p PrefixCompleterInterface, line []rune, pos int, origLine []rune) (newLine [][]rune, offset int) {
112+ line = runes.TrimSpaceLeft(line[:pos])
113+ goNext := false
114+ var lineCompleter PrefixCompleterInterface
115+ for _, child := range p.GetChildren() {
116+ childNames := make([][]rune, 1)
117+
118+ childDynamic, ok := child.(DynamicPrefixCompleterInterface)
119+ if ok && childDynamic.IsDynamic() {
120+ childNames = childDynamic.GetDynamicNames(origLine)
121+ } else {
122+ childNames[0] = child.GetName()
123+ }
124+
125+ for _, childName := range childNames {
126+ if len(line) >= len(childName) {
127+ if runes.HasPrefix(line, childName) {
128+ if len(line) == len(childName) {
129+ newLine = append(newLine, []rune{' '})
130+ } else {
131+ newLine = append(newLine, childName)
132+ }
133+ offset = len(childName)
134+ lineCompleter = child
135+ goNext = true
136+ }
137+ } else {
138+ if runes.HasPrefix(childName, line) {
139+ newLine = append(newLine, childName[len(line):])
140+ offset = len(line)
141+ lineCompleter = child
142+ }
143+ }
144+ }
145+ }
146+
147+ if len(newLine) != 1 {
148+ return
149+ }
150+
151+ tmpLine := make([]rune, 0, len(line))
152+ for i := offset; i < len(line); i++ {
153+ if line[i] == ' ' {
154+ continue
155+ }
156+
157+ tmpLine = append(tmpLine, line[i:]...)
158+ return doInternal(lineCompleter, tmpLine, len(tmpLine), origLine)
159+ }
160+
161+ if goNext {
162+ return doInternal(lineCompleter, nil, 0, origLine)
163+ }
164+ return
165+}
vendor/github.com/chzyer/readline/complete_segment.gonew file+82
@@ -0,0 +1,82 @@
1+package readline
2+
3+type SegmentCompleter interface {
4+ // a
5+ // |- a1
6+ // |--- a11
7+ // |- a2
8+ // b
9+ // input:
10+ // DoTree([], 0) [a, b]
11+ // DoTree([a], 1) [a]
12+ // DoTree([a, ], 0) [a1, a2]
13+ // DoTree([a, a], 1) [a1, a2]
14+ // DoTree([a, a1], 2) [a1]
15+ // DoTree([a, a1, ], 0) [a11]
16+ // DoTree([a, a1, a], 1) [a11]
17+ DoSegment([][]rune, int) [][]rune
18+}
19+
20+type dumpSegmentCompleter struct {
21+ f func([][]rune, int) [][]rune
22+}
23+
24+func (d *dumpSegmentCompleter) DoSegment(segment [][]rune, n int) [][]rune {
25+ return d.f(segment, n)
26+}
27+
28+func SegmentFunc(f func([][]rune, int) [][]rune) AutoCompleter {
29+ return &SegmentComplete{&dumpSegmentCompleter{f}}
30+}
31+
32+func SegmentAutoComplete(completer SegmentCompleter) *SegmentComplete {
33+ return &SegmentComplete{
34+ SegmentCompleter: completer,
35+ }
36+}
37+
38+type SegmentComplete struct {
39+ SegmentCompleter
40+}
41+
42+func RetSegment(segments [][]rune, cands [][]rune, idx int) ([][]rune, int) {
43+ ret := make([][]rune, 0, len(cands))
44+ lastSegment := segments[len(segments)-1]
45+ for _, cand := range cands {
46+ if !runes.HasPrefix(cand, lastSegment) {
47+ continue
48+ }
49+ ret = append(ret, cand[len(lastSegment):])
50+ }
51+ return ret, idx
52+}
53+
54+func SplitSegment(line []rune, pos int) ([][]rune, int) {
55+ segs := [][]rune{}
56+ lastIdx := -1
57+ line = line[:pos]
58+ pos = 0
59+ for idx, l := range line {
60+ if l == ' ' {
61+ pos = 0
62+ segs = append(segs, line[lastIdx+1:idx])
63+ lastIdx = idx
64+ } else {
65+ pos++
66+ }
67+ }
68+ segs = append(segs, line[lastIdx+1:])
69+ return segs, pos
70+}
71+
72+func (c *SegmentComplete) Do(line []rune, pos int) (newLine [][]rune, offset int) {
73+
74+ segment, idx := SplitSegment(line, pos)
75+
76+ cands := c.DoSegment(segment, idx)
77+ newLine, offset = RetSegment(segment, cands, idx)
78+ for idx := range newLine {
79+ newLine[idx] = append(newLine[idx], ' ')
80+ }
81+ return newLine, offset
82+}
vendor/github.com/chzyer/readline/debug.gonew file+29
@@ -0,0 +1,29 @@
1+package readline
2+
3+import (
4+ "container/list"
5+ "fmt"
6+ "os"
7+ "time"
8+)
9+
10+func sleep(n int) {
11+ Debug(n)
12+ time.Sleep(2000 * time.Millisecond)
13+}
14+
15+// print a linked list to Debug()
16+func debugList(l *list.List) {
17+ idx := 0
18+ for e := l.Front(); e != nil; e = e.Next() {
19+ Debug(idx, fmt.Sprintf("%+v", e.Value))
20+ idx++
21+ }
22+}
23+
24+// append log info to another file
25+func Debug(o ...interface{}) {
26+ f, _ := os.OpenFile("debug.tmp", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
27+ fmt.Fprintln(f, o...)
28+ f.Close()
29+}
vendor/github.com/chzyer/readline/doc.gonew file+20
@@ -0,0 +1,20 @@
1+// Readline is a pure go implementation for GNU-Readline kind library.
2+//
3+// WHY: Readline will support most of features which GNU Readline is supported, and provide a pure go environment and a MIT license.
4+//
5+// example:
6+// rl, err := readline.New("> ")
7+// if err != nil {
8+// panic(err)
9+// }
10+// defer rl.Close()
11+//
12+// for {
13+// line, err := rl.Readline()
14+// if err != nil { // io.EOF
15+// break
16+// }
17+// println(line)
18+// }
19+//
20+package readline
vendor/github.com/chzyer/readline/history.gonew file+296
@@ -0,0 +1,296 @@
1+package readline
2+
3+import (
4+ "bufio"
5+ "container/list"
6+ "fmt"
7+ "os"
8+ "strings"
9+)
10+
11+type hisItem struct {
12+ Source []rune
13+ Version int64
14+ Tmp []rune
15+}
16+
17+func (h *hisItem) Clean() {
18+ h.Source = nil
19+ h.Tmp = nil
20+}
21+
22+type opHistory struct {
23+ cfg *Config
24+ history *list.List
25+ historyVer int64
26+ current *list.Element
27+ fd *os.File
28+}
29+
30+func newOpHistory(cfg *Config) (o *opHistory) {
31+ o = &opHistory{
32+ cfg: cfg,
33+ history: list.New(),
34+ }
35+ return o
36+}
37+
38+func (o *opHistory) Reset() {
39+ o.history = list.New()
40+ o.current = nil
41+}
42+
43+func (o *opHistory) IsHistoryClosed() bool {
44+ return o.fd.Fd() == ^(uintptr(0))
45+}
46+
47+func (o *opHistory) Init() {
48+ if o.IsHistoryClosed() {
49+ o.initHistory()
50+ }
51+}
52+
53+func (o *opHistory) initHistory() {
54+ if o.cfg.HistoryFile != "" {
55+ o.historyUpdatePath(o.cfg.HistoryFile)
56+ }
57+}
58+
59+// only called by newOpHistory
60+func (o *opHistory) historyUpdatePath(path string) {
61+ f, err := os.OpenFile(path, os.O_APPEND|os.O_CREATE|os.O_RDWR, 0666)
62+ if err != nil {
63+ return
64+ }
65+ o.fd = f
66+ r := bufio.NewReader(o.fd)
67+ total := 0
68+ for ; ; total++ {
69+ line, err := r.ReadString('\n')
70+ if err != nil {
71+ break
72+ }
73+ // ignore the empty line
74+ line = strings.TrimSpace(line)
75+ if len(line) == 0 {
76+ continue
77+ }
78+ o.Push([]rune(line))
79+ o.Compact()
80+ }
81+ if total > o.cfg.HistoryLimit {
82+ o.Rewrite()
83+ }
84+ o.historyVer++
85+ o.Push(nil)
86+ return
87+}
88+
89+func (o *opHistory) Compact() {
90+ for o.history.Len() > o.cfg.HistoryLimit && o.history.Len() > 0 {
91+ o.history.Remove(o.history.Front())
92+ }
93+}
94+
95+func (o *opHistory) Rewrite() {
96+ if o.cfg.HistoryFile == "" {
97+ return
98+ }
99+
100+ tmpFile := o.cfg.HistoryFile + ".tmp"
101+ fd, err := os.OpenFile(tmpFile, os.O_CREATE|os.O_WRONLY|os.O_TRUNC|os.O_APPEND, 0666)
102+ if err != nil {
103+ return
104+ }
105+
106+ buf := bufio.NewWriter(fd)
107+ for elem := o.history.Front(); elem != nil; elem = elem.Next() {
108+ buf.WriteString(string(elem.Value.(*hisItem).Source))
109+ }
110+ buf.Flush()
111+
112+ // replace history file
113+ if err = os.Rename(tmpFile, o.cfg.HistoryFile); err != nil {
114+ fd.Close()
115+ return
116+ }
117+
118+ if o.fd != nil {
119+ o.fd.Close()
120+ }
121+ // fd is write only, just satisfy what we need.
122+ o.fd = fd
123+}
124+
125+func (o *opHistory) Close() {
126+ if o.fd != nil {
127+ o.fd.Close()
128+ }
129+}
130+
131+func (o *opHistory) FindBck(isNewSearch bool, rs []rune, start int) (int, *list.Element) {
132+ for elem := o.current; elem != nil; elem = elem.Prev() {
133+ item := o.showItem(elem.Value)
134+ if isNewSearch {
135+ start += len(rs)
136+ }
137+ if elem == o.current {
138+ if len(item) >= start {
139+ item = item[:start]
140+ }
141+ }
142+ idx := runes.IndexAllBck(item, rs)
143+ if idx < 0 {
144+ continue
145+ }
146+ return idx, elem
147+ }
148+ return -1, nil
149+}
150+
151+func (o *opHistory) FindFwd(isNewSearch bool, rs []rune, start int) (int, *list.Element) {
152+ for elem := o.current; elem != nil; elem = elem.Next() {
153+ item := o.showItem(elem.Value)
154+ if isNewSearch {
155+ start -= len(rs)
156+ if start < 0 {
157+ start = 0
158+ }
159+ }
160+ if elem == o.current {
161+ if len(item)-1 >= start {
162+ item = item[start:]
163+ } else {
164+ continue
165+ }
166+ }
167+ idx := runes.IndexAll(item, rs)
168+ if idx < 0 {
169+ continue
170+ }
171+ if elem == o.current {
172+ idx += start
173+ }
174+ return idx, elem
175+ }
176+ return -1, nil
177+}
178+
179+func (o *opHistory) showItem(obj interface{}) []rune {
180+ item := obj.(*hisItem)
181+ if item.Version == o.historyVer {
182+ return item.Tmp
183+ }
184+ return item.Source
185+}
186+
187+func (o *opHistory) Prev() []rune {
188+ if o.current == nil {
189+ return nil
190+ }
191+ current := o.current.Prev()
192+ if current == nil {
193+ return nil
194+ }
195+ o.current = current
196+ return runes.Copy(o.showItem(current.Value))
197+}
198+
199+func (o *opHistory) Next() ([]rune, bool) {
200+ if o.current == nil {
201+ return nil, false
202+ }
203+ current := o.current.Next()
204+ if current == nil {
205+ return nil, false
206+ }
207+
208+ o.current = current
209+ return runes.Copy(o.showItem(current.Value)), true
210+}
211+
212+func (o *opHistory) debug() {
213+ Debug("-------")
214+ for item := o.history.Front(); item != nil; item = item.Next() {
215+ Debug(fmt.Sprintf("%+v", item.Value))
216+ }
217+}
218+
219+// save history
220+func (o *opHistory) New(current []rune) (err error) {
221+ current = runes.Copy(current)
222+
223+ // if just use last command without modify
224+ // just clean lastest history
225+ if back := o.history.Back(); back != nil {
226+ prev := back.Prev()
227+ if prev != nil {
228+ if runes.Equal(current, prev.Value.(*hisItem).Source) {
229+ o.current = o.history.Back()
230+ o.current.Value.(*hisItem).Clean()
231+ o.historyVer++
232+ return nil
233+ }
234+ }
235+ }
236+
237+ if len(current) == 0 {
238+ o.current = o.history.Back()
239+ if o.current != nil {
240+ o.current.Value.(*hisItem).Clean()
241+ o.historyVer++
242+ return nil
243+ }
244+ }
245+
246+ if o.current != o.history.Back() {
247+ // move history item to current command
248+ currentItem := o.current.Value.(*hisItem)
249+ // set current to last item
250+ o.current = o.history.Back()
251+
252+ current = runes.Copy(currentItem.Tmp)
253+ }
254+
255+ // err only can be a IO error, just report
256+ err = o.Update(current, true)
257+
258+ // push a new one to commit current command
259+ o.historyVer++
260+ o.Push(nil)
261+ return
262+}
263+
264+func (o *opHistory) Revert() {
265+ o.historyVer++
266+ o.current = o.history.Back()
267+}
268+
269+func (o *opHistory) Update(s []rune, commit bool) (err error) {
270+ s = runes.Copy(s)
271+ if o.current == nil {
272+ o.Push(s)
273+ o.Compact()
274+ return
275+ }
276+ r := o.current.Value.(*hisItem)
277+ r.Version = o.historyVer
278+ if commit {
279+ r.Source = s
280+ if o.fd != nil {
281+ // just report the error
282+ _, err = o.fd.Write([]byte(string(r.Source) + "\n"))
283+ }
284+ } else {
285+ r.Tmp = append(r.Tmp[:0], s...)
286+ }
287+ o.current.Value = r
288+ o.Compact()
289+ return
290+}
291+
292+func (o *opHistory) Push(s []rune) {
293+ s = runes.Copy(s)
294+ elem := o.history.PushBack(&hisItem{Source: s})
295+ o.current = elem
296+}
vendor/github.com/chzyer/readline/operation.gonew file+479
@@ -0,0 +1,479 @@
1+package readline
2+
3+import (
4+ "errors"
5+ "io"
6+)
7+
8+var (
9+ ErrInterrupt = errors.New("Interrupt")
10+)
11+
12+type InterruptError struct {
13+ Line []rune
14+}
15+
16+func (*InterruptError) Error() string {
17+ return "Interrupted"
18+}
19+
20+type Operation struct {
21+ cfg *Config
22+ t *Terminal
23+ buf *RuneBuffer
24+ outchan chan []rune
25+ errchan chan error
26+ w io.Writer
27+
28+ history *opHistory
29+ *opSearch
30+ *opCompleter
31+ *opPassword
32+ *opVim
33+}
34+
35+type wrapWriter struct {
36+ r *Operation
37+ t *Terminal
38+ target io.Writer
39+}
40+
41+func (w *wrapWriter) Write(b []byte) (int, error) {
42+ if !w.t.IsReading() {
43+ return w.target.Write(b)
44+ }
45+
46+ var (
47+ n int
48+ err error
49+ )
50+ w.r.buf.Refresh(func() {
51+ n, err = w.target.Write(b)
52+ })
53+
54+ if w.r.IsSearchMode() {
55+ w.r.SearchRefresh(-1)
56+ }
57+ if w.r.IsInCompleteMode() {
58+ w.r.CompleteRefresh()
59+ }
60+ return n, err
61+}
62+
63+func NewOperation(t *Terminal, cfg *Config) *Operation {
64+ width := cfg.FuncGetWidth()
65+ op := &Operation{
66+ t: t,
67+ buf: NewRuneBuffer(t, cfg.Prompt, cfg, width),
68+ outchan: make(chan []rune),
69+ errchan: make(chan error),
70+ }
71+ op.w = op.buf.w
72+ op.SetConfig(cfg)
73+ op.opVim = newVimMode(op)
74+ op.opCompleter = newOpCompleter(op.buf.w, op, width)
75+ op.opPassword = newOpPassword(op)
76+ op.cfg.FuncOnWidthChanged(func() {
77+ newWidth := cfg.FuncGetWidth()
78+ op.opCompleter.OnWidthChange(newWidth)
79+ op.opSearch.OnWidthChange(newWidth)
80+ op.buf.OnWidthChange(newWidth)
81+ })
82+ go op.ioloop()
83+ return op
84+}
85+
86+func (o *Operation) SetPrompt(s string) {
87+ o.buf.SetPrompt(s)
88+}
89+
90+func (o *Operation) SetMaskRune(r rune) {
91+ o.buf.SetMask(r)
92+}
93+
94+func (o *Operation) ioloop() {
95+ for {
96+ keepInSearchMode := false
97+ keepInCompleteMode := false
98+ r := o.t.ReadRune()
99+ if r == 0 { // io.EOF
100+ if o.buf.Len() == 0 {
101+ o.buf.Clean()
102+ select {
103+ case o.errchan <- io.EOF:
104+ }
105+ break
106+ } else {
107+ // if stdin got io.EOF and there is something left in buffer,
108+ // let's flush them by sending CharEnter.
109+ // And we will got io.EOF int next loop.
110+ r = CharEnter
111+ }
112+ }
113+ isUpdateHistory := true
114+
115+ if o.IsInCompleteSelectMode() {
116+ keepInCompleteMode = o.HandleCompleteSelect(r)
117+ if keepInCompleteMode {
118+ continue
119+ }
120+
121+ o.buf.Refresh(nil)
122+ switch r {
123+ case CharEnter, CharCtrlJ:
124+ o.history.Update(o.buf.Runes(), false)
125+ fallthrough
126+ case CharInterrupt:
127+ o.t.KickRead()
128+ fallthrough
129+ case CharBell:
130+ continue
131+ }
132+ }
133+
134+ if o.IsEnableVimMode() {
135+ r = o.HandleVim(r, o.t.ReadRune)
136+ if r == 0 {
137+ continue
138+ }
139+ }
140+
141+ switch r {
142+ case CharBell:
143+ if o.IsSearchMode() {
144+ o.ExitSearchMode(true)
145+ o.buf.Refresh(nil)
146+ }
147+ if o.IsInCompleteMode() {
148+ o.ExitCompleteMode(true)
149+ o.buf.Refresh(nil)
150+ }
151+ case CharTab:
152+ if o.cfg.AutoComplete == nil {
153+ o.t.Bell()
154+ break
155+ }
156+ o.OnComplete()
157+ keepInCompleteMode = true
158+ case CharBckSearch:
159+ o.SearchMode(S_DIR_BCK)
160+ keepInSearchMode = true
161+ case CharCtrlU:
162+ o.buf.KillFront()
163+ case CharFwdSearch:
164+ o.SearchMode(S_DIR_FWD)
165+ keepInSearchMode = true
166+ case CharKill:
167+ o.buf.Kill()
168+ keepInCompleteMode = true
169+ case MetaForward:
170+ o.buf.MoveToNextWord()
171+ case CharTranspose:
172+ o.buf.Transpose()
173+ case MetaBackward:
174+ o.buf.MoveToPrevWord()
175+ case MetaDelete:
176+ o.buf.DeleteWord()
177+ case CharLineStart:
178+ o.buf.MoveToLineStart()
179+ case CharLineEnd:
180+ o.buf.MoveToLineEnd()
181+ case CharBackspace, CharCtrlH:
182+ if o.IsSearchMode() {
183+ o.SearchBackspace()
184+ keepInSearchMode = true
185+ break
186+ }
187+
188+ if o.buf.Len() == 0 {
189+ o.t.Bell()
190+ break
191+ }
192+ o.buf.Backspace()
193+ if o.IsInCompleteMode() {
194+ o.OnComplete()
195+ }
196+ case CharCtrlZ:
197+ o.buf.Clean()
198+ o.t.SleepToResume()
199+ o.Refresh()
200+ case CharCtrlL:
201+ ClearScreen(o.w)
202+ o.Refresh()
203+ case MetaBackspace, CharCtrlW:
204+ o.buf.BackEscapeWord()
205+ case CharEnter, CharCtrlJ:
206+ if o.IsSearchMode() {
207+ o.ExitSearchMode(false)
208+ }
209+ o.buf.MoveToLineEnd()
210+ var data []rune
211+ if !o.cfg.UniqueEditLine {
212+ o.buf.WriteRune('\n')
213+ data = o.buf.Reset()
214+ data = data[:len(data)-1] // trim \n
215+ } else {
216+ o.buf.Clean()
217+ data = o.buf.Reset()
218+ }
219+ o.outchan <- data
220+ if !o.cfg.DisableAutoSaveHistory {
221+ // ignore IO error
222+ _ = o.history.New(data)
223+ } else {
224+ isUpdateHistory = false
225+ }
226+ case CharBackward:
227+ o.buf.MoveBackward()
228+ case CharForward:
229+ o.buf.MoveForward()
230+ case CharPrev:
231+ buf := o.history.Prev()
232+ if buf != nil {
233+ o.buf.Set(buf)
234+ } else {
235+ o.t.Bell()
236+ }
237+ case CharNext:
238+ buf, ok := o.history.Next()
239+ if ok {
240+ o.buf.Set(buf)
241+ } else {
242+ o.t.Bell()
243+ }
244+ case CharDelete:
245+ if o.buf.Len() > 0 || !o.IsNormalMode() {
246+ o.t.KickRead()
247+ if !o.buf.Delete() {
248+ o.t.Bell()
249+ }
250+ break
251+ }
252+
253+ // treat as EOF
254+ if !o.cfg.UniqueEditLine {
255+ o.buf.WriteString(o.cfg.EOFPrompt + "\n")
256+ }
257+ o.buf.Reset()
258+ isUpdateHistory = false
259+ o.history.Revert()
260+ o.errchan <- io.EOF
261+ if o.cfg.UniqueEditLine {
262+ o.buf.Clean()
263+ }
264+ case CharInterrupt:
265+ if o.IsSearchMode() {
266+ o.t.KickRead()
267+ o.ExitSearchMode(true)
268+ break
269+ }
270+ if o.IsInCompleteMode() {
271+ o.t.KickRead()
272+ o.ExitCompleteMode(true)
273+ o.buf.Refresh(nil)
274+ break
275+ }
276+ o.buf.MoveToLineEnd()
277+ o.buf.Refresh(nil)
278+ hint := o.cfg.InterruptPrompt + "\n"
279+ if !o.cfg.UniqueEditLine {
280+ o.buf.WriteString(hint)
281+ }
282+ remain := o.buf.Reset()
283+ if !o.cfg.UniqueEditLine {
284+ remain = remain[:len(remain)-len([]rune(hint))]
285+ }
286+ isUpdateHistory = false
287+ o.history.Revert()
288+ o.errchan <- &InterruptError{remain}
289+ default:
290+ if o.IsSearchMode() {
291+ o.SearchChar(r)
292+ keepInSearchMode = true
293+ break
294+ }
295+ o.buf.WriteRune(r)
296+ if o.IsInCompleteMode() {
297+ o.OnComplete()
298+ keepInCompleteMode = true
299+ }
300+ }
301+
302+ if o.cfg.Listener != nil {
303+ newLine, newPos, ok := o.cfg.Listener.OnChange(o.buf.Runes(), o.buf.Pos(), r)
304+ if ok {
305+ o.buf.SetWithIdx(newPos, newLine)
306+ }
307+ }
308+
309+ if !keepInSearchMode && o.IsSearchMode() {
310+ o.ExitSearchMode(false)
311+ o.buf.Refresh(nil)
312+ } else if o.IsInCompleteMode() {
313+ if !keepInCompleteMode {
314+ o.ExitCompleteMode(false)
315+ o.Refresh()
316+ } else {
317+ o.buf.Refresh(nil)
318+ o.CompleteRefresh()
319+ }
320+ }
321+ if isUpdateHistory && !o.IsSearchMode() {
322+ // it will cause null history
323+ o.history.Update(o.buf.Runes(), false)
324+ }
325+ }
326+}
327+
328+func (o *Operation) Stderr() io.Writer {
329+ return &wrapWriter{target: o.cfg.Stderr, r: o, t: o.t}
330+}
331+
332+func (o *Operation) Stdout() io.Writer {
333+ return &wrapWriter{target: o.cfg.Stdout, r: o, t: o.t}
334+}
335+
336+func (o *Operation) String() (string, error) {
337+ r, err := o.Runes()
338+ return string(r), err
339+}
340+
341+func (o *Operation) Runes() ([]rune, error) {
342+ o.t.EnterRawMode()
343+ defer o.t.ExitRawMode()
344+
345+ if o.cfg.Listener != nil {
346+ o.cfg.Listener.OnChange(nil, 0, 0)
347+ }
348+ o.buf.Refresh(nil) // print prompt
349+ o.t.KickRead()
350+ select {
351+ case r := <-o.outchan:
352+ return r, nil
353+ case err := <-o.errchan:
354+ if e, ok := err.(*InterruptError); ok {
355+ return e.Line, ErrInterrupt
356+ }
357+ return nil, err
358+ }
359+}
360+
361+func (o *Operation) PasswordEx(prompt string, l Listener) ([]byte, error) {
362+ cfg := o.GenPasswordConfig()
363+ cfg.Prompt = prompt
364+ cfg.Listener = l
365+ return o.PasswordWithConfig(cfg)
366+}
367+
368+func (o *Operation) GenPasswordConfig() *Config {
369+ return o.opPassword.PasswordConfig()
370+}
371+
372+func (o *Operation) PasswordWithConfig(cfg *Config) ([]byte, error) {
373+ if err := o.opPassword.EnterPasswordMode(cfg); err != nil {
374+ return nil, err
375+ }
376+ defer o.opPassword.ExitPasswordMode()
377+ return o.Slice()
378+}
379+
380+func (o *Operation) Password(prompt string) ([]byte, error) {
381+ return o.PasswordEx(prompt, nil)
382+}
383+
384+func (o *Operation) SetTitle(t string) {
385+ o.w.Write([]byte("\033[2;" + t + "\007"))
386+}
387+
388+func (o *Operation) Slice() ([]byte, error) {
389+ r, err := o.Runes()
390+ if err != nil {
391+ return nil, err
392+ }
393+ return []byte(string(r)), nil
394+}
395+
396+func (o *Operation) Close() {
397+ o.history.Close()
398+}
399+
400+func (o *Operation) SetHistoryPath(path string) {
401+ if o.history != nil {
402+ o.history.Close()
403+ }
404+ o.cfg.HistoryFile = path
405+ o.history = newOpHistory(o.cfg)
406+}
407+
408+func (o *Operation) IsNormalMode() bool {
409+ return !o.IsInCompleteMode() && !o.IsSearchMode()
410+}
411+
412+func (op *Operation) SetConfig(cfg *Config) (*Config, error) {
413+ if op.cfg == cfg {
414+ return op.cfg, nil
415+ }
416+ if err := cfg.Init(); err != nil {
417+ return op.cfg, err
418+ }
419+ old := op.cfg
420+ op.cfg = cfg
421+ op.SetPrompt(cfg.Prompt)
422+ op.SetMaskRune(cfg.MaskRune)
423+ op.buf.SetConfig(cfg)
424+ width := op.cfg.FuncGetWidth()
425+
426+ if cfg.opHistory == nil {
427+ op.SetHistoryPath(cfg.HistoryFile)
428+ cfg.opHistory = op.history
429+ cfg.opSearch = newOpSearch(op.buf.w, op.buf, op.history, cfg, width)
430+ }
431+ op.history = cfg.opHistory
432+
433+ // SetHistoryPath will close opHistory which already exists
434+ // so if we use it next time, we need to reopen it by `InitHistory()`
435+ op.history.Init()
436+
437+ if op.cfg.AutoComplete != nil {
438+ op.opCompleter = newOpCompleter(op.buf.w, op, width)
439+ }
440+
441+ op.opSearch = cfg.opSearch
442+ return old, nil
443+}
444+
445+func (o *Operation) ResetHistory() {
446+ o.history.Reset()
447+}
448+
449+// if err is not nil, it just mean it fail to write to file
450+// other things goes fine.
451+func (o *Operation) SaveHistory(content string) error {
452+ return o.history.New([]rune(content))
453+}
454+
455+func (o *Operation) Refresh() {
456+ if o.t.IsReading() {
457+ o.buf.Refresh(nil)
458+ }
459+}
460+
461+func (o *Operation) Clean() {
462+ o.buf.Clean()
463+}
464+
465+func FuncListener(f func(line []rune, pos int, key rune) (newLine []rune, newPos int, ok bool)) Listener {
466+ return &DumpListener{f: f}
467+}
468+
469+type DumpListener struct {
470+ f func(line []rune, pos int, key rune) (newLine []rune, newPos int, ok bool)
471+}
472+
473+func (d *DumpListener) OnChange(line []rune, pos int, key rune) (newLine []rune, newPos int, ok bool) {
474+ return d.f(line, pos, key)
475+}
476+
477+type Listener interface {
478+ OnChange(line []rune, pos int, key rune) (newLine []rune, newPos int, ok bool)
479+}
vendor/github.com/chzyer/readline/password.gonew file+32
@@ -0,0 +1,32 @@
1+package readline
2+
3+type opPassword struct {
4+ o *Operation
5+ backupCfg *Config
6+}
7+
8+func newOpPassword(o *Operation) *opPassword {
9+ return &opPassword{o: o}
10+}
11+
12+func (o *opPassword) ExitPasswordMode() {
13+ o.o.SetConfig(o.backupCfg)
14+ o.backupCfg = nil
15+}
16+
17+func (o *opPassword) EnterPasswordMode(cfg *Config) (err error) {
18+ o.backupCfg, err = o.o.SetConfig(cfg)
19+ return
20+}
21+
22+func (o *opPassword) PasswordConfig() *Config {
23+ return &Config{
24+ EnableMask: true,
25+ InterruptPrompt: "\n",
26+ EOFPrompt: "\n",
27+ HistoryLimit: -1,
28+
29+ Stdout: o.o.cfg.Stdout,
30+ Stderr: o.o.cfg.Stderr,
31+ }
32+}
vendor/github.com/chzyer/readline/rawreader_windows.gonew file+125
@@ -0,0 +1,125 @@
1+// +build windows
2+
3+package readline
4+
5+import "unsafe"
6+
7+const (
8+ VK_CANCEL = 0x03
9+ VK_BACK = 0x08
10+ VK_TAB = 0x09
11+ VK_RETURN = 0x0D
12+ VK_SHIFT = 0x10
13+ VK_CONTROL = 0x11
14+ VK_MENU = 0x12
15+ VK_ESCAPE = 0x1B
16+ VK_LEFT = 0x25
17+ VK_UP = 0x26
18+ VK_RIGHT = 0x27
19+ VK_DOWN = 0x28
20+ VK_DELETE = 0x2E
21+ VK_LSHIFT = 0xA0
22+ VK_RSHIFT = 0xA1
23+ VK_LCONTROL = 0xA2
24+ VK_RCONTROL = 0xA3
25+)
26+
27+// RawReader translate input record to ANSI escape sequence.
28+// To provides same behavior as unix terminal.
29+type RawReader struct {
30+ ctrlKey bool
31+ altKey bool
32+}
33+
34+func NewRawReader() *RawReader {
35+ r := new(RawReader)
36+ return r
37+}
38+
39+// only process one action in one read
40+func (r *RawReader) Read(buf []byte) (int, error) {
41+ ir := new(_INPUT_RECORD)
42+ var read int
43+ var err error
44+next:
45+ err = kernel.ReadConsoleInputW(stdin,
46+ uintptr(unsafe.Pointer(ir)),
47+ 1,
48+ uintptr(unsafe.Pointer(&read)),
49+ )
50+ if err != nil {
51+ return 0, err
52+ }
53+ if ir.EventType != EVENT_KEY {
54+ goto next
55+ }
56+ ker := (*_KEY_EVENT_RECORD)(unsafe.Pointer(&ir.Event[0]))
57+ if ker.bKeyDown == 0 { // keyup
58+ if r.ctrlKey || r.altKey {
59+ switch ker.wVirtualKeyCode {
60+ case VK_RCONTROL, VK_LCONTROL:
61+ r.ctrlKey = false
62+ case VK_MENU: //alt
63+ r.altKey = false
64+ }
65+ }
66+ goto next
67+ }
68+
69+ if ker.unicodeChar == 0 {
70+ var target rune
71+ switch ker.wVirtualKeyCode {
72+ case VK_RCONTROL, VK_LCONTROL:
73+ r.ctrlKey = true
74+ case VK_MENU: //alt
75+ r.altKey = true
76+ case VK_LEFT:
77+ target = CharBackward
78+ case VK_RIGHT:
79+ target = CharForward
80+ case VK_UP:
81+ target = CharPrev
82+ case VK_DOWN:
83+ target = CharNext
84+ }
85+ if target != 0 {
86+ return r.write(buf, target)
87+ }
88+ goto next
89+ }
90+ char := rune(ker.unicodeChar)
91+ if r.ctrlKey {
92+ switch char {
93+ case 'A':
94+ char = CharLineStart
95+ case 'E':
96+ char = CharLineEnd
97+ case 'R':
98+ char = CharBckSearch
99+ case 'S':
100+ char = CharFwdSearch
101+ }
102+ } else if r.altKey {
103+ switch char {
104+ case VK_BACK:
105+ char = CharBackspace
106+ }
107+ return r.writeEsc(buf, char)
108+ }
109+ return r.write(buf, char)
110+}
111+
112+func (r *RawReader) writeEsc(b []byte, char rune) (int, error) {
113+ b[0] = '\033'
114+ n := copy(b[1:], []byte(string(char)))
115+ return n + 1, nil
116+}
117+
118+func (r *RawReader) write(b []byte, char rune) (int, error) {
119+ n := copy(b, []byte(string(char)))
120+ return n, nil
121+}
122+
123+func (r *RawReader) Close() error {
124+ return nil
125+}
vendor/github.com/chzyer/readline/readline.gonew file+257
@@ -0,0 +1,257 @@
1+package readline
2+
3+import "io"
4+
5+type Instance struct {
6+ Config *Config
7+ Terminal *Terminal
8+ Operation *Operation
9+}
10+
11+type Config struct {
12+ // prompt supports ANSI escape sequence, so we can color some characters even in windows
13+ Prompt string
14+
15+ // readline will persist historys to file where HistoryFile specified
16+ HistoryFile string
17+ // specify the max length of historys, it's 500 by default, set it to -1 to disable history
18+ HistoryLimit int
19+ DisableAutoSaveHistory bool
20+
21+ // AutoCompleter will called once user press TAB
22+ AutoComplete AutoCompleter
23+
24+ // Any key press will pass to Listener
25+ // NOTE: Listener will be triggered by (nil, 0, 0) immediately
26+ Listener Listener
27+
28+ // If VimMode is true, readline will in vim.insert mode by default
29+ VimMode bool
30+
31+ InterruptPrompt string
32+ EOFPrompt string
33+
34+ FuncGetWidth func() int
35+
36+ Stdin io.Reader
37+ Stdout io.Writer
38+ Stderr io.Writer
39+
40+ EnableMask bool
41+ MaskRune rune
42+
43+ // erase the editing line after user submited it
44+ // it use in IM usually.
45+ UniqueEditLine bool
46+
47+ // force use interactive even stdout is not a tty
48+ FuncIsTerminal func() bool
49+ FuncMakeRaw func() error
50+ FuncExitRaw func() error
51+ FuncOnWidthChanged func(func())
52+ ForceUseInteractive bool
53+
54+ // private fields
55+ inited bool
56+ opHistory *opHistory
57+ opSearch *opSearch
58+}
59+
60+func (c *Config) useInteractive() bool {
61+ if c.ForceUseInteractive {
62+ return true
63+ }
64+ return c.FuncIsTerminal()
65+}
66+
67+func (c *Config) Init() error {
68+ if c.inited {
69+ return nil
70+ }
71+ c.inited = true
72+ if c.Stdin == nil {
73+ c.Stdin = Stdin
74+ }
75+ if c.Stdout == nil {
76+ c.Stdout = Stdout
77+ }
78+ if c.Stderr == nil {
79+ c.Stderr = Stderr
80+ }
81+ if c.HistoryLimit == 0 {
82+ c.HistoryLimit = 500
83+ }
84+
85+ if c.InterruptPrompt == "" {
86+ c.InterruptPrompt = "^C"
87+ } else if c.InterruptPrompt == "\n" {
88+ c.InterruptPrompt = ""
89+ }
90+ if c.EOFPrompt == "" {
91+ c.EOFPrompt = "^D"
92+ } else if c.EOFPrompt == "\n" {
93+ c.EOFPrompt = ""
94+ }
95+
96+ if c.FuncGetWidth == nil {
97+ c.FuncGetWidth = GetScreenWidth
98+ }
99+ if c.FuncIsTerminal == nil {
100+ c.FuncIsTerminal = DefaultIsTerminal
101+ }
102+ rm := new(RawMode)
103+ if c.FuncMakeRaw == nil {
104+ c.FuncMakeRaw = rm.Enter
105+ }
106+ if c.FuncExitRaw == nil {
107+ c.FuncExitRaw = rm.Exit
108+ }
109+ if c.FuncOnWidthChanged == nil {
110+ c.FuncOnWidthChanged = DefaultOnWidthChanged
111+ }
112+
113+ return nil
114+}
115+
116+func (c Config) Clone() *Config {
117+ c.opHistory = nil
118+ c.opSearch = nil
119+ return &c
120+}
121+
122+func (c *Config) SetListener(f func(line []rune, pos int, key rune) (newLine []rune, newPos int, ok bool)) {
123+ c.Listener = FuncListener(f)
124+}
125+
126+func NewEx(cfg *Config) (*Instance, error) {
127+ t, err := NewTerminal(cfg)
128+ if err != nil {
129+ return nil, err
130+ }
131+ rl := t.Readline()
132+ return &Instance{
133+ Config: cfg,
134+ Terminal: t,
135+ Operation: rl,
136+ }, nil
137+}
138+
139+func New(prompt string) (*Instance, error) {
140+ return NewEx(&Config{Prompt: prompt})
141+}
142+
143+func (i *Instance) ResetHistory() {
144+ i.Operation.ResetHistory()
145+}
146+
147+func (i *Instance) SetPrompt(s string) {
148+ i.Operation.SetPrompt(s)
149+}
150+
151+func (i *Instance) SetMaskRune(r rune) {
152+ i.Operation.SetMaskRune(r)
153+}
154+
155+// change history persistence in runtime
156+func (i *Instance) SetHistoryPath(p string) {
157+ i.Operation.SetHistoryPath(p)
158+}
159+
160+// readline will refresh automatic when write through Stdout()
161+func (i *Instance) Stdout() io.Writer {
162+ return i.Operation.Stdout()
163+}
164+
165+// readline will refresh automatic when write through Stdout()
166+func (i *Instance) Stderr() io.Writer {
167+ return i.Operation.Stderr()
168+}
169+
170+// switch VimMode in runtime
171+func (i *Instance) SetVimMode(on bool) {
172+ i.Operation.SetVimMode(on)
173+}
174+
175+func (i *Instance) IsVimMode() bool {
176+ return i.Operation.IsEnableVimMode()
177+}
178+
179+func (i *Instance) GenPasswordConfig() *Config {
180+ return i.Operation.GenPasswordConfig()
181+}
182+
183+// we can generate a config by `i.GenPasswordConfig()`
184+func (i *Instance) ReadPasswordWithConfig(cfg *Config) ([]byte, error) {
185+ return i.Operation.PasswordWithConfig(cfg)
186+}
187+
188+func (i *Instance) ReadPasswordEx(prompt string, l Listener) ([]byte, error) {
189+ return i.Operation.PasswordEx(prompt, l)
190+}
191+
192+func (i *Instance) ReadPassword(prompt string) ([]byte, error) {
193+ return i.Operation.Password(prompt)
194+}
195+
196+type Result struct {
197+ Line string
198+ Error error
199+}
200+
201+func (l *Result) CanContinue() bool {
202+ return len(l.Line) != 0 && l.Error == ErrInterrupt
203+}
204+
205+func (l *Result) CanBreak() bool {
206+ return !l.CanContinue() && l.Error != nil
207+}
208+
209+func (i *Instance) Line() *Result {
210+ ret, err := i.Readline()
211+ return &Result{ret, err}
212+}
213+
214+// err is one of (nil, io.EOF, readline.ErrInterrupt)
215+func (i *Instance) Readline() (string, error) {
216+ return i.Operation.String()
217+}
218+
219+func (i *Instance) SaveHistory(content string) error {
220+ return i.Operation.SaveHistory(content)
221+}
222+
223+// same as readline
224+func (i *Instance) ReadSlice() ([]byte, error) {
225+ return i.Operation.Slice()
226+}
227+
228+// we must make sure that call Close() before process exit.
229+func (i *Instance) Close() error {
230+ if err := i.Terminal.Close(); err != nil {
231+ return err
232+ }
233+ i.Operation.Close()
234+ return nil
235+}
236+func (i *Instance) Clean() {
237+ i.Operation.Clean()
238+}
239+
240+func (i *Instance) Write(b []byte) (int, error) {
241+ return i.Stdout().Write(b)
242+}
243+
244+func (i *Instance) SetConfig(cfg *Config) *Config {
245+ if i.Config == cfg {
246+ return cfg
247+ }
248+ old := i.Config
249+ i.Config = cfg
250+ i.Operation.SetConfig(cfg)
251+ i.Terminal.SetConfig(cfg)
252+ return old
253+}
254+
255+func (i *Instance) Refresh() {
256+ i.Operation.Refresh()
257+}
vendor/github.com/chzyer/readline/remote.gonew file+474
@@ -0,0 +1,474 @@
1+package readline
2+
3+import (
4+ "bufio"
5+ "bytes"
6+ "encoding/binary"
7+ "fmt"
8+ "io"
9+ "net"
10+ "os"
11+ "sync"
12+ "sync/atomic"
13+)
14+
15+type MsgType int16
16+
17+const (
18+ T_DATA = MsgType(iota)
19+ T_WIDTH
20+ T_WIDTH_REPORT
21+ T_ISTTY_REPORT
22+ T_RAW
23+ T_ERAW // exit raw
24+ T_EOF
25+)
26+
27+type RemoteSvr struct {
28+ eof int32
29+ closed int32
30+ width int32
31+ reciveChan chan struct{}
32+ writeChan chan *writeCtx
33+ conn net.Conn
34+ isTerminal bool
35+ funcWidthChan func()
36+ stopChan chan struct{}
37+
38+ dataBufM sync.Mutex
39+ dataBuf bytes.Buffer
40+}
41+
42+type writeReply struct {
43+ n int
44+ err error
45+}
46+
47+type writeCtx struct {
48+ msg *Message
49+ reply chan *writeReply
50+}
51+
52+func newWriteCtx(msg *Message) *writeCtx {
53+ return &writeCtx{
54+ msg: msg,
55+ reply: make(chan *writeReply),
56+ }
57+}
58+
59+func NewRemoteSvr(conn net.Conn) (*RemoteSvr, error) {
60+ rs := &RemoteSvr{
61+ width: -1,
62+ conn: conn,
63+ writeChan: make(chan *writeCtx),
64+ reciveChan: make(chan struct{}),
65+ stopChan: make(chan struct{}),
66+ }
67+ buf := bufio.NewReader(rs.conn)
68+
69+ if err := rs.init(buf); err != nil {
70+ return nil, err
71+ }
72+
73+ go rs.readLoop(buf)
74+ go rs.writeLoop()
75+ return rs, nil
76+}
77+
78+func (r *RemoteSvr) init(buf *bufio.Reader) error {
79+ m, err := ReadMessage(buf)
80+ if err != nil {
81+ return err
82+ }
83+ // receive isTerminal
84+ if m.Type != T_ISTTY_REPORT {
85+ return fmt.Errorf("unexpected init message")
86+ }
87+ r.GotIsTerminal(m.Data)
88+
89+ // receive width
90+ m, err = ReadMessage(buf)
91+ if err != nil {
92+ return err
93+ }
94+ if m.Type != T_WIDTH_REPORT {
95+ return fmt.Errorf("unexpected init message")
96+ }
97+ r.GotReportWidth(m.Data)
98+
99+ return nil
100+}
101+
102+func (r *RemoteSvr) HandleConfig(cfg *Config) {
103+ cfg.Stderr = r
104+ cfg.Stdout = r
105+ cfg.Stdin = r
106+ cfg.FuncExitRaw = r.ExitRawMode
107+ cfg.FuncIsTerminal = r.IsTerminal
108+ cfg.FuncMakeRaw = r.EnterRawMode
109+ cfg.FuncExitRaw = r.ExitRawMode
110+ cfg.FuncGetWidth = r.GetWidth
111+ cfg.FuncOnWidthChanged = func(f func()) {
112+ r.funcWidthChan = f
113+ }
114+}
115+
116+func (r *RemoteSvr) IsTerminal() bool {
117+ return r.isTerminal
118+}
119+
120+func (r *RemoteSvr) checkEOF() error {
121+ if atomic.LoadInt32(&r.eof) == 1 {
122+ return io.EOF
123+ }
124+ return nil
125+}
126+
127+func (r *RemoteSvr) Read(b []byte) (int, error) {
128+ r.dataBufM.Lock()
129+ n, err := r.dataBuf.Read(b)
130+ r.dataBufM.Unlock()
131+ if n == 0 {
132+ if err := r.checkEOF(); err != nil {
133+ return 0, err
134+ }
135+ }
136+
137+ if n == 0 && err == io.EOF {
138+ <-r.reciveChan
139+ r.dataBufM.Lock()
140+ n, err = r.dataBuf.Read(b)
141+ r.dataBufM.Unlock()
142+ }
143+ if n == 0 {
144+ if err := r.checkEOF(); err != nil {
145+ return 0, err
146+ }
147+ }
148+
149+ return n, err
150+}
151+
152+func (r *RemoteSvr) writeMsg(m *Message) error {
153+ ctx := newWriteCtx(m)
154+ r.writeChan <- ctx
155+ reply := <-ctx.reply
156+ return reply.err
157+}
158+
159+func (r *RemoteSvr) Write(b []byte) (int, error) {
160+ ctx := newWriteCtx(NewMessage(T_DATA, b))
161+ r.writeChan <- ctx
162+ reply := <-ctx.reply
163+ return reply.n, reply.err
164+}
165+
166+func (r *RemoteSvr) EnterRawMode() error {
167+ return r.writeMsg(NewMessage(T_RAW, nil))
168+}
169+
170+func (r *RemoteSvr) ExitRawMode() error {
171+ return r.writeMsg(NewMessage(T_ERAW, nil))
172+}
173+
174+func (r *RemoteSvr) writeLoop() {
175+ defer r.Close()
176+
177+loop:
178+ for {
179+ select {
180+ case ctx, ok := <-r.writeChan:
181+ if !ok {
182+ break
183+ }
184+ n, err := ctx.msg.WriteTo(r.conn)
185+ ctx.reply <- &writeReply{n, err}
186+ case <-r.stopChan:
187+ break loop
188+ }
189+ }
190+}
191+
192+func (r *RemoteSvr) Close() {
193+ if atomic.CompareAndSwapInt32(&r.closed, 0, 1) {
194+ close(r.stopChan)
195+ r.conn.Close()
196+ }
197+}
198+
199+func (r *RemoteSvr) readLoop(buf *bufio.Reader) {
200+ defer r.Close()
201+ for {
202+ m, err := ReadMessage(buf)
203+ if err != nil {
204+ break
205+ }
206+ switch m.Type {
207+ case T_EOF:
208+ atomic.StoreInt32(&r.eof, 1)
209+ select {
210+ case r.reciveChan <- struct{}{}:
211+ default:
212+ }
213+ case T_DATA:
214+ r.dataBufM.Lock()
215+ r.dataBuf.Write(m.Data)
216+ r.dataBufM.Unlock()
217+ select {
218+ case r.reciveChan <- struct{}{}:
219+ default:
220+ }
221+ case T_WIDTH_REPORT:
222+ r.GotReportWidth(m.Data)
223+ case T_ISTTY_REPORT:
224+ r.GotIsTerminal(m.Data)
225+ }
226+ }
227+}
228+
229+func (r *RemoteSvr) GotIsTerminal(data []byte) {
230+ if binary.BigEndian.Uint16(data) == 0 {
231+ r.isTerminal = false
232+ } else {
233+ r.isTerminal = true
234+ }
235+}
236+
237+func (r *RemoteSvr) GotReportWidth(data []byte) {
238+ atomic.StoreInt32(&r.width, int32(binary.BigEndian.Uint16(data)))
239+ if r.funcWidthChan != nil {
240+ r.funcWidthChan()
241+ }
242+}
243+
244+func (r *RemoteSvr) GetWidth() int {
245+ return int(atomic.LoadInt32(&r.width))
246+}
247+
248+// -----------------------------------------------------------------------------
249+
250+type Message struct {
251+ Type MsgType
252+ Data []byte
253+}
254+
255+func ReadMessage(r io.Reader) (*Message, error) {
256+ m := new(Message)
257+ var length int32
258+ if err := binary.Read(r, binary.BigEndian, &length); err != nil {
259+ return nil, err
260+ }
261+ if err := binary.Read(r, binary.BigEndian, &m.Type); err != nil {
262+ return nil, err
263+ }
264+ m.Data = make([]byte, int(length)-2)
265+ if _, err := io.ReadFull(r, m.Data); err != nil {
266+ return nil, err
267+ }
268+ return m, nil
269+}
270+
271+func NewMessage(t MsgType, data []byte) *Message {
272+ return &Message{t, data}
273+}
274+
275+func (m *Message) WriteTo(w io.Writer) (int, error) {
276+ buf := bytes.NewBuffer(make([]byte, 0, len(m.Data)+2+4))
277+ binary.Write(buf, binary.BigEndian, int32(len(m.Data)+2))
278+ binary.Write(buf, binary.BigEndian, m.Type)
279+ buf.Write(m.Data)
280+ n, err := buf.WriteTo(w)
281+ return int(n), err
282+}
283+
284+// -----------------------------------------------------------------------------
285+
286+type RemoteCli struct {
287+ conn net.Conn
288+ raw RawMode
289+ receiveChan chan struct{}
290+ inited int32
291+ isTerminal *bool
292+
293+ data bytes.Buffer
294+ dataM sync.Mutex
295+}
296+
297+func NewRemoteCli(conn net.Conn) (*RemoteCli, error) {
298+ r := &RemoteCli{
299+ conn: conn,
300+ receiveChan: make(chan struct{}),
301+ }
302+ return r, nil
303+}
304+
305+func (r *RemoteCli) MarkIsTerminal(is bool) {
306+ r.isTerminal = &is
307+}
308+
309+func (r *RemoteCli) init() error {
310+ if !atomic.CompareAndSwapInt32(&r.inited, 0, 1) {
311+ return nil
312+ }
313+
314+ if err := r.reportIsTerminal(); err != nil {
315+ return err
316+ }
317+
318+ if err := r.reportWidth(); err != nil {
319+ return err
320+ }
321+
322+ // register sig for width changed
323+ DefaultOnWidthChanged(func() {
324+ r.reportWidth()
325+ })
326+ return nil
327+}
328+
329+func (r *RemoteCli) writeMsg(m *Message) error {
330+ r.dataM.Lock()
331+ _, err := m.WriteTo(r.conn)
332+ r.dataM.Unlock()
333+ return err
334+}
335+
336+func (r *RemoteCli) Write(b []byte) (int, error) {
337+ m := NewMessage(T_DATA, b)
338+ r.dataM.Lock()
339+ _, err := m.WriteTo(r.conn)
340+ r.dataM.Unlock()
341+ return len(b), err
342+}
343+
344+func (r *RemoteCli) reportWidth() error {
345+ screenWidth := GetScreenWidth()
346+ data := make([]byte, 2)
347+ binary.BigEndian.PutUint16(data, uint16(screenWidth))
348+ msg := NewMessage(T_WIDTH_REPORT, data)
349+
350+ if err := r.writeMsg(msg); err != nil {
351+ return err
352+ }
353+ return nil
354+}
355+
356+func (r *RemoteCli) reportIsTerminal() error {
357+ var isTerminal bool
358+ if r.isTerminal != nil {
359+ isTerminal = *r.isTerminal
360+ } else {
361+ isTerminal = DefaultIsTerminal()
362+ }
363+ data := make([]byte, 2)
364+ if isTerminal {
365+ binary.BigEndian.PutUint16(data, 1)
366+ } else {
367+ binary.BigEndian.PutUint16(data, 0)
368+ }
369+ msg := NewMessage(T_ISTTY_REPORT, data)
370+ if err := r.writeMsg(msg); err != nil {
371+ return err
372+ }
373+ return nil
374+}
375+
376+func (r *RemoteCli) readLoop() {
377+ buf := bufio.NewReader(r.conn)
378+ for {
379+ msg, err := ReadMessage(buf)
380+ if err != nil {
381+ break
382+ }
383+ switch msg.Type {
384+ case T_ERAW:
385+ r.raw.Exit()
386+ case T_RAW:
387+ r.raw.Enter()
388+ case T_DATA:
389+ os.Stdout.Write(msg.Data)
390+ }
391+ }
392+}
393+
394+func (r *RemoteCli) ServeBy(source io.Reader) error {
395+ if err := r.init(); err != nil {
396+ return err
397+ }
398+
399+ go func() {
400+ defer r.Close()
401+ for {
402+ n, _ := io.Copy(r, source)
403+ if n == 0 {
404+ break
405+ }
406+ }
407+ }()
408+ defer r.raw.Exit()
409+ r.readLoop()
410+ return nil
411+}
412+
413+func (r *RemoteCli) Close() {
414+ r.writeMsg(NewMessage(T_EOF, nil))
415+}
416+
417+func (r *RemoteCli) Serve() error {
418+ return r.ServeBy(os.Stdin)
419+}
420+
421+func ListenRemote(n, addr string, cfg *Config, h func(*Instance), onListen ...func(net.Listener) error) error {
422+ ln, err := net.Listen(n, addr)
423+ if err != nil {
424+ return err
425+ }
426+ if len(onListen) > 0 {
427+ if err := onListen[0](ln); err != nil {
428+ return err
429+ }
430+ }
431+ for {
432+ conn, err := ln.Accept()
433+ if err != nil {
434+ break
435+ }
436+ go func() {
437+ defer conn.Close()
438+ rl, err := HandleConn(*cfg, conn)
439+ if err != nil {
440+ return
441+ }
442+ h(rl)
443+ }()
444+ }
445+ return nil
446+}
447+
448+func HandleConn(cfg Config, conn net.Conn) (*Instance, error) {
449+ r, err := NewRemoteSvr(conn)
450+ if err != nil {
451+ return nil, err
452+ }
453+ r.HandleConfig(&cfg)
454+
455+ rl, err := NewEx(&cfg)
456+ if err != nil {
457+ return nil, err
458+ }
459+ return rl, nil
460+}
461+
462+func DialRemote(n, addr string) error {
463+ conn, err := net.Dial(n, addr)
464+ if err != nil {
465+ return err
466+ }
467+ defer conn.Close()
468+
469+ cli, err := NewRemoteCli(conn)
470+ if err != nil {
471+ return err
472+ }
473+ return cli.Serve()
474+}
vendor/github.com/chzyer/readline/runebuf.gonew file+500
@@ -0,0 +1,500 @@
1+package readline
2+
3+import (
4+ "bufio"
5+ "bytes"
6+ "io"
7+ "strings"
8+)
9+
10+type runeBufferBck struct {
11+ buf []rune
12+ idx int
13+}
14+
15+type RuneBuffer struct {
16+ buf []rune
17+ idx int
18+ prompt []rune
19+ w io.Writer
20+
21+ hadClean bool
22+ interactive bool
23+ cfg *Config
24+
25+ width int
26+
27+ bck *runeBufferBck
28+}
29+
30+func (r *RuneBuffer) OnWidthChange(newWidth int) {
31+ r.width = newWidth
32+}
33+
34+func (r *RuneBuffer) Backup() {
35+ r.bck = &runeBufferBck{r.buf, r.idx}
36+}
37+
38+func (r *RuneBuffer) Restore() {
39+ r.Refresh(func() {
40+ if r.bck == nil {
41+ return
42+ }
43+ r.buf = r.bck.buf
44+ r.idx = r.bck.idx
45+ })
46+}
47+
48+func NewRuneBuffer(w io.Writer, prompt string, cfg *Config, width int) *RuneBuffer {
49+ rb := &RuneBuffer{
50+ w: w,
51+ interactive: cfg.useInteractive(),
52+ cfg: cfg,
53+ width: width,
54+ }
55+ rb.SetPrompt(prompt)
56+ return rb
57+}
58+
59+func (r *RuneBuffer) SetConfig(cfg *Config) {
60+ r.cfg = cfg
61+ r.interactive = cfg.useInteractive()
62+}
63+
64+func (r *RuneBuffer) SetMask(m rune) {
65+ r.cfg.MaskRune = m
66+}
67+
68+func (r *RuneBuffer) CurrentWidth(x int) int {
69+ return runes.WidthAll(r.buf[:x])
70+}
71+
72+func (r *RuneBuffer) PromptLen() int {
73+ return runes.WidthAll(runes.ColorFilter(r.prompt))
74+}
75+
76+func (r *RuneBuffer) RuneSlice(i int) []rune {
77+ if i > 0 {
78+ rs := make([]rune, i)
79+ copy(rs, r.buf[r.idx:r.idx+i])
80+ return rs
81+ }
82+ rs := make([]rune, -i)
83+ copy(rs, r.buf[r.idx+i:r.idx])
84+ return rs
85+}
86+
87+func (r *RuneBuffer) Runes() []rune {
88+ newr := make([]rune, len(r.buf))
89+ copy(newr, r.buf)
90+ return newr
91+}
92+
93+func (r *RuneBuffer) Pos() int {
94+ return r.idx
95+}
96+
97+func (r *RuneBuffer) Len() int {
98+ return len(r.buf)
99+}
100+
101+func (r *RuneBuffer) MoveToLineStart() {
102+ r.Refresh(func() {
103+ if r.idx == 0 {
104+ return
105+ }
106+ r.idx = 0
107+ })
108+}
109+
110+func (r *RuneBuffer) MoveBackward() {
111+ r.Refresh(func() {
112+ if r.idx == 0 {
113+ return
114+ }
115+ r.idx--
116+ })
117+}
118+
119+func (r *RuneBuffer) WriteString(s string) {
120+ r.WriteRunes([]rune(s))
121+}
122+
123+func (r *RuneBuffer) WriteRune(s rune) {
124+ r.WriteRunes([]rune{s})
125+}
126+
127+func (r *RuneBuffer) WriteRunes(s []rune) {
128+ r.Refresh(func() {
129+ tail := append(s, r.buf[r.idx:]...)
130+ r.buf = append(r.buf[:r.idx], tail...)
131+ r.idx += len(s)
132+ })
133+}
134+
135+func (r *RuneBuffer) MoveForward() {
136+ r.Refresh(func() {
137+ if r.idx == len(r.buf) {
138+ return
139+ }
140+ r.idx++
141+ })
142+}
143+
144+func (r *RuneBuffer) IsCursorInEnd() bool {
145+ return r.idx == len(r.buf)
146+}
147+
148+func (r *RuneBuffer) Replace(ch rune) {
149+ r.Refresh(func() {
150+ r.buf[r.idx] = ch
151+ })
152+}
153+
154+func (r *RuneBuffer) Erase() {
155+ r.Refresh(func() {
156+ r.idx = 0
157+ r.buf = r.buf[:0]
158+ })
159+}
160+
161+func (r *RuneBuffer) Delete() (success bool) {
162+ r.Refresh(func() {
163+ if r.idx == len(r.buf) {
164+ return
165+ }
166+ r.buf = append(r.buf[:r.idx], r.buf[r.idx+1:]...)
167+ success = true
168+ })
169+ return
170+}
171+
172+func (r *RuneBuffer) DeleteWord() {
173+ if r.idx == len(r.buf) {
174+ return
175+ }
176+ init := r.idx
177+ for init < len(r.buf) && IsWordBreak(r.buf[init]) {
178+ init++
179+ }
180+ for i := init + 1; i < len(r.buf); i++ {
181+ if !IsWordBreak(r.buf[i]) && IsWordBreak(r.buf[i-1]) {
182+ r.Refresh(func() {
183+ r.buf = append(r.buf[:r.idx], r.buf[i-1:]...)
184+ })
185+ return
186+ }
187+ }
188+ r.Kill()
189+}
190+
191+func (r *RuneBuffer) MoveToPrevWord() (success bool) {
192+ r.Refresh(func() {
193+ if r.idx == 0 {
194+ return
195+ }
196+
197+ for i := r.idx - 1; i > 0; i-- {
198+ if !IsWordBreak(r.buf[i]) && IsWordBreak(r.buf[i-1]) {
199+ r.idx = i
200+ success = true
201+ return
202+ }
203+ }
204+ r.idx = 0
205+ success = true
206+ })
207+ return
208+}
209+
210+func (r *RuneBuffer) KillFront() {
211+ r.Refresh(func() {
212+ if r.idx == 0 {
213+ return
214+ }
215+
216+ length := len(r.buf) - r.idx
217+ copy(r.buf[:length], r.buf[r.idx:])
218+ r.idx = 0
219+ r.buf = r.buf[:length]
220+ })
221+}
222+
223+func (r *RuneBuffer) Kill() {
224+ r.Refresh(func() {
225+ r.buf = r.buf[:r.idx]
226+ })
227+}
228+
229+func (r *RuneBuffer) Transpose() {
230+ r.Refresh(func() {
231+ if len(r.buf) == 1 {
232+ r.idx++
233+ }
234+
235+ if len(r.buf) < 2 {
236+ return
237+ }
238+
239+ if r.idx == 0 {
240+ r.idx = 1
241+ } else if r.idx >= len(r.buf) {
242+ r.idx = len(r.buf) - 1
243+ }
244+ r.buf[r.idx], r.buf[r.idx-1] = r.buf[r.idx-1], r.buf[r.idx]
245+ r.idx++
246+ })
247+}
248+
249+func (r *RuneBuffer) MoveToNextWord() {
250+ r.Refresh(func() {
251+ for i := r.idx + 1; i < len(r.buf); i++ {
252+ if !IsWordBreak(r.buf[i]) && IsWordBreak(r.buf[i-1]) {
253+ r.idx = i
254+ return
255+ }
256+ }
257+
258+ r.idx = len(r.buf)
259+ })
260+}
261+
262+func (r *RuneBuffer) MoveToEndWord() {
263+ r.Refresh(func() {
264+ // already at the end, so do nothing
265+ if r.idx == len(r.buf) {
266+ return
267+ }
268+ // if we are at the end of a word already, go to next
269+ if !IsWordBreak(r.buf[r.idx]) && IsWordBreak(r.buf[r.idx+1]) {
270+ r.idx++
271+ }
272+
273+ // keep going until at the end of a word
274+ for i := r.idx + 1; i < len(r.buf); i++ {
275+ if IsWordBreak(r.buf[i]) && !IsWordBreak(r.buf[i-1]) {
276+ r.idx = i - 1
277+ return
278+ }
279+ }
280+ r.idx = len(r.buf)
281+ })
282+}
283+
284+func (r *RuneBuffer) BackEscapeWord() {
285+ r.Refresh(func() {
286+ if r.idx == 0 {
287+ return
288+ }
289+ for i := r.idx - 1; i > 0; i-- {
290+ if !IsWordBreak(r.buf[i]) && IsWordBreak(r.buf[i-1]) {
291+ r.buf = append(r.buf[:i], r.buf[r.idx:]...)
292+ r.idx = i
293+ return
294+ }
295+ }
296+
297+ r.buf = r.buf[:0]
298+ r.idx = 0
299+ })
300+}
301+
302+func (r *RuneBuffer) Backspace() {
303+ r.Refresh(func() {
304+ if r.idx == 0 {
305+ return
306+ }
307+
308+ r.idx--
309+ r.buf = append(r.buf[:r.idx], r.buf[r.idx+1:]...)
310+ })
311+}
312+
313+func (r *RuneBuffer) MoveToLineEnd() {
314+ r.Refresh(func() {
315+ if r.idx == len(r.buf) {
316+ return
317+ }
318+
319+ r.idx = len(r.buf)
320+ })
321+}
322+
323+func (r *RuneBuffer) LineCount(width int) int {
324+ if width == -1 {
325+ width = r.width
326+ }
327+ return LineCount(width,
328+ runes.WidthAll(r.buf)+r.PromptLen())
329+}
330+
331+func (r *RuneBuffer) MoveTo(ch rune, prevChar, reverse bool) (success bool) {
332+ r.Refresh(func() {
333+ if reverse {
334+ for i := r.idx - 1; i >= 0; i-- {
335+ if r.buf[i] == ch {
336+ r.idx = i
337+ if prevChar {
338+ r.idx++
339+ }
340+ success = true
341+ return
342+ }
343+ }
344+ return
345+ }
346+ for i := r.idx + 1; i < len(r.buf); i++ {
347+ if r.buf[i] == ch {
348+ r.idx = i
349+ if prevChar {
350+ r.idx--
351+ }
352+ success = true
353+ return
354+ }
355+ }
356+ })
357+ return
358+}
359+
360+func (r *RuneBuffer) isInLineEdge() bool {
361+ if isWindows {
362+ return false
363+ }
364+ sp := r.getSplitByLine(r.buf)
365+ return len(sp[len(sp)-1]) == 0
366+}
367+
368+func (r *RuneBuffer) getSplitByLine(rs []rune) []string {
369+ return SplitByLine(r.PromptLen(), r.width, rs)
370+}
371+
372+func (r *RuneBuffer) IdxLine(width int) int {
373+ sp := r.getSplitByLine(r.buf[:r.idx])
374+ return len(sp) - 1
375+}
376+
377+func (r *RuneBuffer) CursorLineCount() int {
378+ return r.LineCount(r.width) - r.IdxLine(r.width)
379+}
380+
381+func (r *RuneBuffer) Refresh(f func()) {
382+ if !r.interactive {
383+ if f != nil {
384+ f()
385+ }
386+ return
387+ }
388+ r.Clean()
389+ if f != nil {
390+ f()
391+ }
392+ r.print()
393+}
394+
395+func (r *RuneBuffer) print() {
396+ r.w.Write(r.output())
397+ r.hadClean = false
398+}
399+
400+func (r *RuneBuffer) output() []byte {
401+ buf := bytes.NewBuffer(nil)
402+ buf.WriteString(string(r.prompt))
403+ if r.cfg.EnableMask && len(r.buf) > 0 {
404+ buf.Write([]byte(strings.Repeat(string(r.cfg.MaskRune), len(r.buf)-1)))
405+ if r.buf[len(r.buf)-1] == '\n' {
406+ buf.Write([]byte{'\n'})
407+ } else {
408+ buf.Write([]byte(string(r.cfg.MaskRune)))
409+ }
410+ if len(r.buf) > r.idx {
411+ buf.Write(runes.Backspace(r.buf[r.idx:]))
412+ }
413+
414+ } else {
415+ buf.Write([]byte(string(r.buf)))
416+ if r.isInLineEdge() {
417+ buf.Write([]byte(" \b"))
418+ }
419+ }
420+
421+ if len(r.buf) > r.idx {
422+ buf.Write(runes.Backspace(r.buf[r.idx:]))
423+ }
424+ return buf.Bytes()
425+}
426+
427+func (r *RuneBuffer) Reset() []rune {
428+ ret := runes.Copy(r.buf)
429+ r.buf = r.buf[:0]
430+ r.idx = 0
431+ return ret
432+}
433+
434+func (r *RuneBuffer) calWidth(m int) int {
435+ if m > 0 {
436+ return runes.WidthAll(r.buf[r.idx : r.idx+m])
437+ }
438+ return runes.WidthAll(r.buf[r.idx+m : r.idx])
439+}
440+
441+func (r *RuneBuffer) SetStyle(start, end int, style string) {
442+ if end < start {
443+ panic("end < start")
444+ }
445+
446+ // goto start
447+ move := start - r.idx
448+ if move > 0 {
449+ r.w.Write([]byte(string(r.buf[r.idx : r.idx+move])))
450+ } else {
451+ r.w.Write(bytes.Repeat([]byte("\b"), r.calWidth(move)))
452+ }
453+ r.w.Write([]byte("\033[" + style + "m"))
454+ r.w.Write([]byte(string(r.buf[start:end])))
455+ r.w.Write([]byte("\033[0m"))
456+ // TODO: move back
457+}
458+
459+func (r *RuneBuffer) SetWithIdx(idx int, buf []rune) {
460+ r.Refresh(func() {
461+ r.buf = buf
462+ r.idx = idx
463+ })
464+}
465+
466+func (r *RuneBuffer) Set(buf []rune) {
467+ r.SetWithIdx(len(buf), buf)
468+}
469+
470+func (r *RuneBuffer) SetPrompt(prompt string) {
471+ r.prompt = []rune(prompt)
472+}
473+
474+func (r *RuneBuffer) cleanOutput(w io.Writer, idxLine int) {
475+ buf := bufio.NewWriter(w)
476+ buf.Write([]byte("\033[J")) // just like ^k :)
477+
478+ if idxLine == 0 {
479+ io.WriteString(buf, "\033[2K\r")
480+ } else {
481+ for i := 0; i < idxLine; i++ {
482+ io.WriteString(buf, "\033[2K\r\033[A")
483+ }
484+ io.WriteString(buf, "\033[2K\r")
485+ }
486+ buf.Flush()
487+ return
488+}
489+
490+func (r *RuneBuffer) Clean() {
491+ r.clean(r.IdxLine(r.width))
492+}
493+
494+func (r *RuneBuffer) clean(idxLine int) {
495+ if r.hadClean || !r.interactive {
496+ return
497+ }
498+ r.hadClean = true
499+ r.cleanOutput(r.w, idxLine)
500+}
vendor/github.com/chzyer/readline/runes.gonew file+167
@@ -0,0 +1,167 @@
1+package readline
2+
3+import (
4+ "bytes"
5+ "unicode"
6+)
7+
8+var runes = Runes{}
9+
10+type Runes struct{}
11+
12+func (Runes) Equal(a, b []rune) bool {
13+ if len(a) != len(b) {
14+ return false
15+ }
16+ for i := 0; i < len(a); i++ {
17+ if a[i] != b[i] {
18+ return false
19+ }
20+ }
21+ return true
22+}
23+
24+// Search in runes from end to front
25+func (Runes) IndexAllBck(r, sub []rune) int {
26+ for i := len(r) - len(sub); i >= 0; i-- {
27+ found := true
28+ for j := 0; j < len(sub); j++ {
29+ if r[i+j] != sub[j] {
30+ found = false
31+ break
32+ }
33+ }
34+ if found {
35+ return i
36+ }
37+ }
38+ return -1
39+}
40+
41+// Search in runes from front to end
42+func (Runes) IndexAll(r, sub []rune) int {
43+ for i := 0; i < len(r); i++ {
44+ found := true
45+ if len(r[i:]) < len(sub) {
46+ return -1
47+ }
48+ for j := 0; j < len(sub); j++ {
49+ if r[i+j] != sub[j] {
50+ found = false
51+ break
52+ }
53+ }
54+ if found {
55+ return i
56+ }
57+ }
58+ return -1
59+}
60+
61+func (Runes) Index(r rune, rs []rune) int {
62+ for i := 0; i < len(rs); i++ {
63+ if rs[i] == r {
64+ return i
65+ }
66+ }
67+ return -1
68+}
69+
70+func (Runes) ColorFilter(r []rune) []rune {
71+ newr := make([]rune, 0, len(r))
72+ for pos := 0; pos < len(r); pos++ {
73+ if r[pos] == '\033' && r[pos+1] == '[' {
74+ idx := runes.Index('m', r[pos+2:])
75+ if idx == -1 {
76+ continue
77+ }
78+ pos += idx + 2
79+ continue
80+ }
81+ newr = append(newr, r[pos])
82+ }
83+ return newr
84+}
85+
86+var zeroWidth = []*unicode.RangeTable{
87+ unicode.Mn,
88+ unicode.Me,
89+ unicode.Cc,
90+ unicode.Cf,
91+}
92+
93+var doubleWidth = []*unicode.RangeTable{
94+ unicode.Han,
95+ unicode.Hangul,
96+ unicode.Hiragana,
97+ unicode.Katakana,
98+}
99+
100+func (Runes) Width(r rune) int {
101+ if unicode.IsOneOf(zeroWidth, r) {
102+ return 0
103+ }
104+ if unicode.IsOneOf(doubleWidth, r) {
105+ return 2
106+ }
107+ return 1
108+}
109+
110+func (Runes) WidthAll(r []rune) (length int) {
111+ for i := 0; i < len(r); i++ {
112+ length += runes.Width(r[i])
113+ }
114+ return
115+}
116+
117+func (Runes) Backspace(r []rune) []byte {
118+ return bytes.Repeat([]byte{'\b'}, runes.WidthAll(r))
119+}
120+
121+func (Runes) Copy(r []rune) []rune {
122+ n := make([]rune, len(r))
123+ copy(n, r)
124+ return n
125+}
126+
127+func (Runes) HasPrefix(r, prefix []rune) bool {
128+ if len(r) < len(prefix) {
129+ return false
130+ }
131+ return runes.Equal(r[:len(prefix)], prefix)
132+}
133+
134+func (Runes) Aggregate(candicate [][]rune) (same []rune, size int) {
135+ for i := 0; i < len(candicate[0]); i++ {
136+ for j := 0; j < len(candicate)-1; j++ {
137+ if i >= len(candicate[j]) || i >= len(candicate[j+1]) {
138+ goto aggregate
139+ }
140+ if candicate[j][i] != candicate[j+1][i] {
141+ goto aggregate
142+ }
143+ }
144+ size = i + 1
145+ }
146+aggregate:
147+ if size > 0 {
148+ same = runes.Copy(candicate[0][:size])
149+ for i := 0; i < len(candicate); i++ {
150+ n := runes.Copy(candicate[i])
151+ copy(n, n[size:])
152+ candicate[i] = n[:len(n)-size]
153+ }
154+ }
155+ return
156+}
157+
158+func (Runes) TrimSpaceLeft(in []rune) []rune {
159+ firstIndex := len(in)
160+ for i, r := range in {
161+ if unicode.IsSpace(r) == false {
162+ firstIndex = i
163+ break
164+ }
165+ }
166+ return in[firstIndex:]
167+}
vendor/github.com/chzyer/readline/search.gonew file+160
@@ -0,0 +1,160 @@
1+package readline
2+
3+import (
4+ "bytes"
5+ "container/list"
6+ "fmt"
7+ "io"
8+)
9+
10+const (
11+ S_STATE_FOUND = iota
12+ S_STATE_FAILING
13+)
14+
15+const (
16+ S_DIR_BCK = iota
17+ S_DIR_FWD
18+)
19+
20+type opSearch struct {
21+ inMode bool
22+ state int
23+ dir int
24+ source *list.Element
25+ w io.Writer
26+ buf *RuneBuffer
27+ data []rune
28+ history *opHistory
29+ cfg *Config
30+ markStart int
31+ markEnd int
32+ width int
33+}
34+
35+func newOpSearch(w io.Writer, buf *RuneBuffer, history *opHistory, cfg *Config, width int) *opSearch {
36+ return &opSearch{
37+ w: w,
38+ buf: buf,
39+ cfg: cfg,
40+ history: history,
41+ width: width,
42+ }
43+}
44+
45+func (o *opSearch) OnWidthChange(newWidth int) {
46+ o.width = newWidth
47+}
48+
49+func (o *opSearch) IsSearchMode() bool {
50+ return o.inMode
51+}
52+
53+func (o *opSearch) SearchBackspace() {
54+ if len(o.data) > 0 {
55+ o.data = o.data[:len(o.data)-1]
56+ o.search(true)
57+ }
58+}
59+
60+func (o *opSearch) findHistoryBy(isNewSearch bool) (int, *list.Element) {
61+ if o.dir == S_DIR_BCK {
62+ return o.history.FindBck(isNewSearch, o.data, o.buf.idx)
63+ }
64+ return o.history.FindFwd(isNewSearch, o.data, o.buf.idx)
65+}
66+
67+func (o *opSearch) search(isChange bool) bool {
68+ if len(o.data) == 0 {
69+ o.state = S_STATE_FOUND
70+ o.SearchRefresh(-1)
71+ return true
72+ }
73+ idx, elem := o.findHistoryBy(isChange)
74+ if elem == nil {
75+ o.SearchRefresh(-2)
76+ return false
77+ }
78+ o.history.current = elem
79+
80+ item := o.history.showItem(o.history.current.Value)
81+ start, end := 0, 0
82+ if o.dir == S_DIR_BCK {
83+ start, end = idx, idx+len(o.data)
84+ } else {
85+ start, end = idx, idx+len(o.data)
86+ idx += len(o.data)
87+ }
88+ o.buf.SetWithIdx(idx, item)
89+ o.markStart, o.markEnd = start, end
90+ o.SearchRefresh(idx)
91+ return true
92+}
93+
94+func (o *opSearch) SearchChar(r rune) {
95+ o.data = append(o.data, r)
96+ o.search(true)
97+}
98+
99+func (o *opSearch) SearchMode(dir int) {
100+ alreadyInMode := o.inMode
101+ o.inMode = true
102+ o.dir = dir
103+ o.source = o.history.current
104+ if alreadyInMode {
105+ o.search(false)
106+ } else {
107+ o.SearchRefresh(-1)
108+ }
109+}
110+
111+func (o *opSearch) ExitSearchMode(revert bool) {
112+ if revert {
113+ o.history.current = o.source
114+ o.buf.Set(o.history.showItem(o.history.current.Value))
115+ }
116+ o.markStart, o.markEnd = 0, 0
117+ o.state = S_STATE_FOUND
118+ o.inMode = false
119+ o.source = nil
120+ o.data = nil
121+}
122+
123+func (o *opSearch) SearchRefresh(x int) {
124+ if x == -2 {
125+ o.state = S_STATE_FAILING
126+ } else if x >= 0 {
127+ o.state = S_STATE_FOUND
128+ }
129+ if x < 0 {
130+ x = o.buf.idx
131+ }
132+ x = o.buf.CurrentWidth(x)
133+ x += o.buf.PromptLen()
134+ x = x % o.width
135+
136+ if o.markStart > 0 {
137+ o.buf.SetStyle(o.markStart, o.markEnd, "4")
138+ }
139+
140+ lineCnt := o.buf.CursorLineCount()
141+ buf := bytes.NewBuffer(nil)
142+ buf.Write(bytes.Repeat([]byte("\n"), lineCnt))
143+ buf.WriteString("\033[J")
144+ if o.state == S_STATE_FAILING {
145+ buf.WriteString("failing ")
146+ }
147+ if o.dir == S_DIR_BCK {
148+ buf.WriteString("bck")
149+ } else if o.dir == S_DIR_FWD {
150+ buf.WriteString("fwd")
151+ }
152+ buf.WriteString("-i-search: ")
153+ buf.WriteString(string(o.data)) // keyword
154+ buf.WriteString("\033[4m \033[0m") // _
155+ fmt.Fprintf(buf, "\r\033[%dA", lineCnt) // move prev
156+ if x > 0 {
157+ fmt.Fprintf(buf, "\033[%dC", x) // move forward
158+ }
159+ o.w.Write(buf.Bytes())
160+}
vendor/github.com/chzyer/readline/std.gonew file+66
@@ -0,0 +1,66 @@
1+package readline
2+
3+import (
4+ "io"
5+ "os"
6+ "sync"
7+)
8+
9+var (
10+ Stdin io.ReadCloser = os.Stdin
11+ Stdout io.WriteCloser = os.Stdout
12+ Stderr io.WriteCloser = os.Stderr
13+)
14+
15+var (
16+ std *Instance
17+ stdOnce sync.Once
18+)
19+
20+// global instance will not submit history automatic
21+func getInstance() *Instance {
22+ stdOnce.Do(func() {
23+ std, _ = NewEx(&Config{
24+ DisableAutoSaveHistory: true,
25+ })
26+ })
27+ return std
28+}
29+
30+// let readline load history from filepath
31+// and try to persist history into disk
32+// set fp to "" to prevent readline persisting history to disk
33+// so the `AddHistory` will return nil error forever.
34+func SetHistoryPath(fp string) {
35+ ins := getInstance()
36+ cfg := ins.Config.Clone()
37+ cfg.HistoryFile = fp
38+ ins.SetConfig(cfg)
39+}
40+
41+// set auto completer to global instance
42+func SetAutoComplete(completer AutoCompleter) {
43+ ins := getInstance()
44+ cfg := ins.Config.Clone()
45+ cfg.AutoComplete = completer
46+ ins.SetConfig(cfg)
47+}
48+
49+// add history to global instance manually
50+// raise error only if `SetHistoryPath` is set with a non-empty path
51+func AddHistory(content string) error {
52+ ins := getInstance()
53+ return ins.SaveHistory(content)
54+}
55+
56+func Password(prompt string) ([]byte, error) {
57+ ins := getInstance()
58+ return ins.ReadPassword(prompt)
59+}
60+
61+// readline with global configs
62+func Line(prompt string) (string, error) {
63+ ins := getInstance()
64+ ins.SetPrompt(prompt)
65+ return ins.Readline()
66+}
vendor/github.com/chzyer/readline/std_windows.gonew file+9
@@ -0,0 +1,9 @@
1+// +build windows
2+
3+package readline
4+
5+func init() {
6+ Stdin = NewRawReader()
7+ Stdout = NewANSIWriter(Stdout)
8+ Stderr = NewANSIWriter(Stderr)
9+}
vendor/github.com/chzyer/readline/term.gonew file+134
@@ -0,0 +1,134 @@
1+// Copyright 2011 The Go Authors. All rights reserved.
2+// Use of this source code is governed by a BSD-style
3+// license that can be found in the LICENSE file.
4+
5+// +build darwin dragonfly freebsd linux,!appengine netbsd openbsd
6+
7+// Package terminal provides support functions for dealing with terminals, as
8+// commonly found on UNIX systems.
9+//
10+// Putting a terminal into raw mode is the most common requirement:
11+//
12+// oldState, err := terminal.MakeRaw(0)
13+// if err != nil {
14+// panic(err)
15+// }
16+// defer terminal.Restore(0, oldState)
17+package readline
18+
19+import (
20+ "io"
21+ "syscall"
22+ "unsafe"
23+)
24+
25+// State contains the state of a terminal.
26+type State struct {
27+ termios syscall.Termios
28+}
29+
30+// IsTerminal returns true if the given file descriptor is a terminal.
31+func IsTerminal(fd int) bool {
32+ var termios syscall.Termios
33+ _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
34+ return err == 0
35+}
36+
37+// MakeRaw put the terminal connected to the given file descriptor into raw
38+// mode and returns the previous state of the terminal so that it can be
39+// restored.
40+func MakeRaw(fd int) (*State, error) {
41+ var oldState State
42+ if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(&oldState.termios)), 0, 0, 0); err != 0 {
43+ return nil, err
44+ }
45+
46+ newState := oldState.termios
47+ // This attempts to replicate the behaviour documented for cfmakeraw in
48+ // the termios(3) manpage.
49+ newState.Iflag &^= syscall.IGNBRK | syscall.BRKINT | syscall.PARMRK | syscall.ISTRIP | syscall.INLCR | syscall.IGNCR | syscall.ICRNL | syscall.IXON
50+ // newState.Oflag &^= syscall.OPOST
51+ newState.Lflag &^= syscall.ECHO | syscall.ECHONL | syscall.ICANON | syscall.ISIG | syscall.IEXTEN
52+ newState.Cflag &^= syscall.CSIZE | syscall.PARENB
53+ newState.Cflag |= syscall.CS8
54+
55+ if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlWriteTermios, uintptr(unsafe.Pointer(&newState)), 0, 0, 0); err != 0 {
56+ return nil, err
57+ }
58+
59+ return &oldState, nil
60+}
61+
62+// GetState returns the current state of a terminal which may be useful to
63+// restore the terminal after a signal.
64+func GetState(fd int) (*State, error) {
65+ var oldState State
66+ if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(&oldState.termios)), 0, 0, 0); err != 0 {
67+ return nil, err
68+ }
69+
70+ return &oldState, nil
71+}
72+
73+// Restore restores the terminal connected to the given file descriptor to a
74+// previous state.
75+func restoreTerm(fd int, state *State) error {
76+ _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlWriteTermios, uintptr(unsafe.Pointer(&state.termios)), 0, 0, 0)
77+ return err
78+}
79+
80+// GetSize returns the dimensions of the given terminal.
81+func GetSize(fd int) (width, height int, err error) {
82+ var dimensions [4]uint16
83+
84+ if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), uintptr(syscall.TIOCGWINSZ), uintptr(unsafe.Pointer(&dimensions)), 0, 0, 0); err != 0 {
85+ return -1, -1, err
86+ }
87+ return int(dimensions[1]), int(dimensions[0]), nil
88+}
89+
90+// ReadPassword reads a line of input from a terminal without local echo. This
91+// is commonly used for inputting passwords and other sensitive data. The slice
92+// returned does not include the \n.
93+func ReadPassword(fd int) ([]byte, error) {
94+ var oldState syscall.Termios
95+ if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(&oldState)), 0, 0, 0); err != 0 {
96+ return nil, err
97+ }
98+
99+ newState := oldState
100+ newState.Lflag &^= syscall.ECHO
101+ newState.Lflag |= syscall.ICANON | syscall.ISIG
102+ newState.Iflag |= syscall.ICRNL
103+ if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlWriteTermios, uintptr(unsafe.Pointer(&newState)), 0, 0, 0); err != 0 {
104+ return nil, err
105+ }
106+
107+ defer func() {
108+ syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlWriteTermios, uintptr(unsafe.Pointer(&oldState)), 0, 0, 0)
109+ }()
110+
111+ var buf [16]byte
112+ var ret []byte
113+ for {
114+ n, err := syscall.Read(fd, buf[:])
115+ if err != nil {
116+ return nil, err
117+ }
118+ if n == 0 {
119+ if len(ret) == 0 {
120+ return nil, io.EOF
121+ }
122+ break
123+ }
124+ if buf[n-1] == '\n' {
125+ n--
126+ }
127+ ret = append(ret, buf[:n]...)
128+ if n < len(buf) {
129+ break
130+ }
131+ }
132+
133+ return ret, nil
134+}
vendor/github.com/chzyer/readline/term_bsd.gonew file+12
@@ -0,0 +1,12 @@
1+// Copyright 2013 The Go Authors. All rights reserved.
2+// Use of this source code is governed by a BSD-style
3+// license that can be found in the LICENSE file.
4+
5+// +build darwin dragonfly freebsd netbsd openbsd
6+
7+package readline
8+
9+import "syscall"
10+
11+const ioctlReadTermios = syscall.TIOCGETA
12+const ioctlWriteTermios = syscall.TIOCSETA
vendor/github.com/chzyer/readline/term_linux.gonew file+11
@@ -0,0 +1,11 @@
1+// Copyright 2013 The Go Authors. All rights reserved.
2+// Use of this source code is governed by a BSD-style
3+// license that can be found in the LICENSE file.
4+
5+package readline
6+
7+// These constants are declared here, rather than importing
8+// them from the syscall package as some syscall packages, even
9+// on linux, for example gccgo, do not declare them.
10+const ioctlReadTermios = 0x5401 // syscall.TCGETS
11+const ioctlWriteTermios = 0x5402 // syscall.TCSETS
vendor/github.com/chzyer/readline/term_windows.gonew file+171
@@ -0,0 +1,171 @@
1+// Copyright 2011 The Go Authors. All rights reserved.
2+// Use of this source code is governed by a BSD-style
3+// license that can be found in the LICENSE file.
4+
5+// +build windows
6+
7+// Package terminal provides support functions for dealing with terminals, as
8+// commonly found on UNIX systems.
9+//
10+// Putting a terminal into raw mode is the most common requirement:
11+//
12+// oldState, err := terminal.MakeRaw(0)
13+// if err != nil {
14+// panic(err)
15+// }
16+// defer terminal.Restore(0, oldState)
17+package readline
18+
19+import (
20+ "io"
21+ "syscall"
22+ "unsafe"
23+)
24+
25+const (
26+ enableLineInput = 2
27+ enableEchoInput = 4
28+ enableProcessedInput = 1
29+ enableWindowInput = 8
30+ enableMouseInput = 16
31+ enableInsertMode = 32
32+ enableQuickEditMode = 64
33+ enableExtendedFlags = 128
34+ enableAutoPosition = 256
35+ enableProcessedOutput = 1
36+ enableWrapAtEolOutput = 2
37+)
38+
39+var kernel32 = syscall.NewLazyDLL("kernel32.dll")
40+
41+var (
42+ procGetConsoleMode = kernel32.NewProc("GetConsoleMode")
43+ procSetConsoleMode = kernel32.NewProc("SetConsoleMode")
44+ procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo")
45+)
46+
47+type (
48+ coord struct {
49+ x short
50+ y short
51+ }
52+ smallRect struct {
53+ left short
54+ top short
55+ right short
56+ bottom short
57+ }
58+ consoleScreenBufferInfo struct {
59+ size coord
60+ cursorPosition coord
61+ attributes word
62+ window smallRect
63+ maximumWindowSize coord
64+ }
65+)
66+
67+type State struct {
68+ mode uint32
69+}
70+
71+// IsTerminal returns true if the given file descriptor is a terminal.
72+func IsTerminal(fd int) bool {
73+ var st uint32
74+ r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0)
75+ return r != 0 && e == 0
76+}
77+
78+// MakeRaw put the terminal connected to the given file descriptor into raw
79+// mode and returns the previous state of the terminal so that it can be
80+// restored.
81+func MakeRaw(fd int) (*State, error) {
82+ var st uint32
83+ _, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0)
84+ if e != 0 {
85+ return nil, error(e)
86+ }
87+ raw := st &^ (enableEchoInput | enableProcessedInput | enableLineInput | enableProcessedOutput)
88+ _, _, e = syscall.Syscall(procSetConsoleMode.Addr(), 2, uintptr(fd), uintptr(raw), 0)
89+ if e != 0 {
90+ return nil, error(e)
91+ }
92+ return &State{st}, nil
93+}
94+
95+// GetState returns the current state of a terminal which may be useful to
96+// restore the terminal after a signal.
97+func GetState(fd int) (*State, error) {
98+ var st uint32
99+ _, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0)
100+ if e != 0 {
101+ return nil, error(e)
102+ }
103+ return &State{st}, nil
104+}
105+
106+// Restore restores the terminal connected to the given file descriptor to a
107+// previous state.
108+func restoreTerm(fd int, state *State) error {
109+ _, _, err := syscall.Syscall(procSetConsoleMode.Addr(), 2, uintptr(fd), uintptr(state.mode), 0)
110+ return err
111+}
112+
113+// GetSize returns the dimensions of the given terminal.
114+func GetSize(fd int) (width, height int, err error) {
115+ var info consoleScreenBufferInfo
116+ _, _, e := syscall.Syscall(procGetConsoleScreenBufferInfo.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&info)), 0)
117+ if e != 0 {
118+ return 0, 0, error(e)
119+ }
120+ return int(info.size.x), int(info.size.y), nil
121+}
122+
123+// ReadPassword reads a line of input from a terminal without local echo. This
124+// is commonly used for inputting passwords and other sensitive data. The slice
125+// returned does not include the \n.
126+func ReadPassword(fd int) ([]byte, error) {
127+ var st uint32
128+ _, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0)
129+ if e != 0 {
130+ return nil, error(e)
131+ }
132+ old := st
133+
134+ st &^= (enableEchoInput)
135+ st |= (enableProcessedInput | enableLineInput | enableProcessedOutput)
136+ _, _, e = syscall.Syscall(procSetConsoleMode.Addr(), 2, uintptr(fd), uintptr(st), 0)
137+ if e != 0 {
138+ return nil, error(e)
139+ }
140+
141+ defer func() {
142+ syscall.Syscall(procSetConsoleMode.Addr(), 2, uintptr(fd), uintptr(old), 0)
143+ }()
144+
145+ var buf [16]byte
146+ var ret []byte
147+ for {
148+ n, err := syscall.Read(syscall.Handle(fd), buf[:])
149+ if err != nil {
150+ return nil, err
151+ }
152+ if n == 0 {
153+ if len(ret) == 0 {
154+ return nil, io.EOF
155+ }
156+ break
157+ }
158+ if buf[n-1] == '\n' {
159+ n--
160+ }
161+ if n > 0 && buf[n-1] == '\r' {
162+ n--
163+ }
164+ ret = append(ret, buf[:n]...)
165+ if n < len(buf) {
166+ break
167+ }
168+ }
169+
170+ return ret, nil
171+}
vendor/github.com/chzyer/readline/terminal.gonew file+175
@@ -0,0 +1,175 @@
1+package readline
2+
3+import (
4+ "bufio"
5+ "fmt"
6+ "strings"
7+ "sync"
8+ "sync/atomic"
9+)
10+
11+type Terminal struct {
12+ cfg *Config
13+ outchan chan rune
14+ closed int32
15+ stopChan chan struct{}
16+ kickChan chan struct{}
17+ wg sync.WaitGroup
18+ isReading int32
19+ sleeping int32
20+}
21+
22+func NewTerminal(cfg *Config) (*Terminal, error) {
23+ if err := cfg.Init(); err != nil {
24+ return nil, err
25+ }
26+ t := &Terminal{
27+ cfg: cfg,
28+ kickChan: make(chan struct{}, 1),
29+ outchan: make(chan rune),
30+ stopChan: make(chan struct{}, 1),
31+ }
32+
33+ go t.ioloop()
34+ return t, nil
35+}
36+
37+// SleepToResume will sleep myself, and return only if I'm resumed.
38+func (t *Terminal) SleepToResume() {
39+ if !atomic.CompareAndSwapInt32(&t.sleeping, 0, 1) {
40+ return
41+ }
42+ defer atomic.StoreInt32(&t.sleeping, 0)
43+
44+ t.ExitRawMode()
45+ ch := WaitForResume()
46+ SuspendMe()
47+ <-ch
48+ t.EnterRawMode()
49+}
50+
51+func (t *Terminal) EnterRawMode() (err error) {
52+ return t.cfg.FuncMakeRaw()
53+}
54+
55+func (t *Terminal) ExitRawMode() (err error) {
56+ return t.cfg.FuncExitRaw()
57+}
58+
59+func (t *Terminal) Write(b []byte) (int, error) {
60+ return t.cfg.Stdout.Write(b)
61+}
62+
63+func (t *Terminal) Print(s string) {
64+ fmt.Fprintf(t.cfg.Stdout, "%s", s)
65+}
66+
67+func (t *Terminal) PrintRune(r rune) {
68+ fmt.Fprintf(t.cfg.Stdout, "%c", r)
69+}
70+
71+func (t *Terminal) Readline() *Operation {
72+ return NewOperation(t, t.cfg)
73+}
74+
75+// return rune(0) if meet EOF
76+func (t *Terminal) ReadRune() rune {
77+ ch, ok := <-t.outchan
78+ if !ok {
79+ return rune(0)
80+ }
81+ return ch
82+}
83+
84+func (t *Terminal) IsReading() bool {
85+ return atomic.LoadInt32(&t.isReading) == 1
86+}
87+
88+func (t *Terminal) KickRead() {
89+ select {
90+ case t.kickChan <- struct{}{}:
91+ default:
92+ }
93+}
94+
95+func (t *Terminal) ioloop() {
96+ t.wg.Add(1)
97+ defer t.wg.Done()
98+ var (
99+ isEscape bool
100+ isEscapeEx bool
101+ expectNextChar bool
102+ )
103+
104+ buf := bufio.NewReader(t.cfg.Stdin)
105+ for {
106+ if !expectNextChar {
107+ atomic.StoreInt32(&t.isReading, 0)
108+ select {
109+ case <-t.kickChan:
110+ atomic.StoreInt32(&t.isReading, 1)
111+ case <-t.stopChan:
112+ return
113+ }
114+ }
115+ expectNextChar = false
116+ r, _, err := buf.ReadRune()
117+ if err != nil {
118+ if strings.Contains(err.Error(), "interrupted system call") {
119+ expectNextChar = true
120+ continue
121+ }
122+ break
123+ }
124+
125+ if isEscape {
126+ isEscape = false
127+ if r == CharEscapeEx {
128+ expectNextChar = true
129+ isEscapeEx = true
130+ continue
131+ }
132+ r = escapeKey(r, buf)
133+ } else if isEscapeEx {
134+ isEscapeEx = false
135+ r = escapeExKey(r, buf)
136+ }
137+
138+ expectNextChar = true
139+ switch r {
140+ case CharEsc:
141+ if t.cfg.VimMode {
142+ t.outchan <- r
143+ break
144+ }
145+ isEscape = true
146+ case CharInterrupt, CharEnter, CharCtrlJ, CharDelete:
147+ expectNextChar = false
148+ fallthrough
149+ default:
150+ t.outchan <- r
151+ }
152+ }
153+ close(t.outchan)
154+}
155+
156+func (t *Terminal) Bell() {
157+ fmt.Fprintf(t, "%c", CharBell)
158+}
159+
160+func (t *Terminal) Close() error {
161+ if atomic.SwapInt32(&t.closed, 1) != 0 {
162+ return nil
163+ }
164+ t.stopChan <- struct{}{}
165+ t.wg.Wait()
166+ return t.ExitRawMode()
167+}
168+
169+func (t *Terminal) SetConfig(c *Config) error {
170+ if err := c.Init(); err != nil {
171+ return err
172+ }
173+ t.cfg = c
174+ return nil
175+}
vendor/github.com/chzyer/readline/utils.gonew file+176
@@ -0,0 +1,176 @@
1+package readline
2+
3+import (
4+ "bufio"
5+ "bytes"
6+ "strconv"
7+ "sync"
8+ "time"
9+)
10+
11+var (
12+ isWindows = false
13+)
14+
15+// WaitForResume need to call before current process got suspend.
16+// It will run a ticker until a long duration is occurs,
17+// which means this process is resumed.
18+func WaitForResume() chan struct{} {
19+ ch := make(chan struct{})
20+ var wg sync.WaitGroup
21+ wg.Add(1)
22+ go func() {
23+ ticker := time.NewTicker(10 * time.Millisecond)
24+ t := time.Now()
25+ wg.Done()
26+ for {
27+ now := <-ticker.C
28+ if now.Sub(t) > 100*time.Millisecond {
29+ break
30+ }
31+ t = now
32+ }
33+ ticker.Stop()
34+ ch <- struct{}{}
35+ }()
36+ wg.Wait()
37+ return ch
38+}
39+
40+func Restore(fd int, state *State) error {
41+ err := restoreTerm(fd, state)
42+ if err != nil {
43+ // errno 0 means everything is ok :)
44+ if err.Error() == "errno 0" {
45+ err = nil
46+ }
47+ }
48+ return nil
49+}
50+
51+func IsPrintable(key rune) bool {
52+ isInSurrogateArea := key >= 0xd800 && key <= 0xdbff
53+ return key >= 32 && !isInSurrogateArea
54+}
55+
56+// translate Esc[X
57+func escapeExKey(r rune, reader *bufio.Reader) rune {
58+ switch r {
59+ case 'D':
60+ r = CharBackward
61+ case 'C':
62+ r = CharForward
63+ case 'A':
64+ r = CharPrev
65+ case 'B':
66+ r = CharNext
67+ case 'H':
68+ r = CharLineStart
69+ case 'F':
70+ r = CharLineEnd
71+ default:
72+ if r == '3' && reader != nil {
73+ d, _, _ := reader.ReadRune()
74+ if d == '~' {
75+ r = CharDelete
76+ } else {
77+ reader.UnreadRune()
78+ }
79+ }
80+ }
81+ return r
82+}
83+
84+// translate EscX to Meta+X
85+func escapeKey(r rune, reader *bufio.Reader) rune {
86+ switch r {
87+ case 'b':
88+ r = MetaBackward
89+ case 'f':
90+ r = MetaForward
91+ case 'd':
92+ r = MetaDelete
93+ case CharTranspose:
94+ r = MetaTranspose
95+ case CharBackspace:
96+ r = MetaBackspace
97+ case 'O':
98+ d, _, _ := reader.ReadRune()
99+ switch d {
100+ case 'H':
101+ r = CharLineStart
102+ case 'F':
103+ r = CharLineEnd
104+ default:
105+ reader.UnreadRune()
106+ }
107+ case CharEsc:
108+
109+ }
110+ return r
111+}
112+
113+func SplitByLine(start, screenWidth int, rs []rune) []string {
114+ var ret []string
115+ buf := bytes.NewBuffer(nil)
116+ currentWidth := start
117+ for _, r := range rs {
118+ w := runes.Width(r)
119+ currentWidth += w
120+ buf.WriteRune(r)
121+ if currentWidth >= screenWidth {
122+ ret = append(ret, buf.String())
123+ buf.Reset()
124+ currentWidth = 0
125+ }
126+ }
127+ ret = append(ret, buf.String())
128+ return ret
129+}
130+
131+// calculate how many lines for N character
132+func LineCount(screenWidth, w int) int {
133+ r := w / screenWidth
134+ if w%screenWidth != 0 {
135+ r++
136+ }
137+ return r
138+}
139+
140+func IsWordBreak(i rune) bool {
141+ switch {
142+ case i >= 'a' && i <= 'z':
143+ case i >= 'A' && i <= 'Z':
144+ case i >= '0' && i <= '9':
145+ default:
146+ return true
147+ }
148+ return false
149+}
150+
151+func GetInt(s []string, def int) int {
152+ if len(s) == 0 {
153+ return def
154+ }
155+ c, err := strconv.Atoi(s[0])
156+ if err != nil {
157+ return def
158+ }
159+ return c
160+}
161+
162+type RawMode struct {
163+ state *State
164+}
165+
166+func (r *RawMode) Enter() (err error) {
167+ r.state, err = MakeRaw(GetStdin())
168+ return err
169+}
170+
171+func (r *RawMode) Exit() error {
172+ if r.state == nil {
173+ return nil
174+ }
175+ return Restore(GetStdin(), r.state)
176+}
vendor/github.com/chzyer/readline/utils_unix.gonew file+90
@@ -0,0 +1,90 @@
1+// +build darwin dragonfly freebsd linux,!appengine netbsd openbsd
2+
3+package readline
4+
5+import (
6+ "io"
7+ "os"
8+ "os/signal"
9+ "sync"
10+ "syscall"
11+ "unsafe"
12+)
13+
14+type winsize struct {
15+ Row uint16
16+ Col uint16
17+ Xpixel uint16
18+ Ypixel uint16
19+}
20+
21+// SuspendMe use to send suspend signal to myself, when we in the raw mode.
22+// For OSX it need to send to parent's pid
23+// For Linux it need to send to myself
24+func SuspendMe() {
25+ p, _ := os.FindProcess(os.Getppid())
26+ p.Signal(syscall.SIGTSTP)
27+ p, _ = os.FindProcess(os.Getpid())
28+ p.Signal(syscall.SIGTSTP)
29+}
30+
31+// get width of the terminal
32+func getWidth(stdoutFd int) int {
33+ ws := &winsize{}
34+ retCode, _, errno := syscall.Syscall(syscall.SYS_IOCTL,
35+ uintptr(stdoutFd),
36+ uintptr(syscall.TIOCGWINSZ),
37+ uintptr(unsafe.Pointer(ws)))
38+
39+ if int(retCode) == -1 {
40+ _ = errno
41+ return -1
42+ }
43+ return int(ws.Col)
44+}
45+
46+func GetScreenWidth() int {
47+ w := getWidth(syscall.Stdout)
48+ if w < 0 {
49+ w = getWidth(syscall.Stderr)
50+ }
51+ return w
52+}
53+
54+// ClearScreen clears the console screen
55+func ClearScreen(w io.Writer) (int, error) {
56+ return w.Write([]byte("\033[H"))
57+}
58+
59+func DefaultIsTerminal() bool {
60+ return IsTerminal(syscall.Stdin) && (IsTerminal(syscall.Stdout) || IsTerminal(syscall.Stderr))
61+}
62+
63+func GetStdin() int {
64+ return syscall.Stdin
65+}
66+
67+// -----------------------------------------------------------------------------
68+
69+var (
70+ widthChange sync.Once
71+ widthChangeCallback func()
72+)
73+
74+func DefaultOnWidthChanged(f func()) {
75+ widthChangeCallback = f
76+ widthChange.Do(func() {
77+ ch := make(chan os.Signal, 1)
78+ signal.Notify(ch, syscall.SIGWINCH)
79+
80+ go func() {
81+ for {
82+ _, ok := <-ch
83+ if !ok {
84+ break
85+ }
86+ widthChangeCallback()
87+ }
88+ }()
89+ })
90+}
vendor/github.com/chzyer/readline/utils_windows.gonew file+41
@@ -0,0 +1,41 @@
1+// +build windows
2+
3+package readline
4+
5+import (
6+ "io"
7+ "syscall"
8+)
9+
10+func SuspendMe() {
11+}
12+
13+func GetStdin() int {
14+ return int(syscall.Stdin)
15+}
16+
17+func init() {
18+ isWindows = true
19+}
20+
21+// get width of the terminal
22+func GetScreenWidth() int {
23+ info, _ := GetConsoleScreenBufferInfo()
24+ if info == nil {
25+ return -1
26+ }
27+ return int(info.dwSize.x)
28+}
29+
30+// ClearScreen clears the console screen
31+func ClearScreen(_ io.Writer) error {
32+ return SetConsoleCursorPosition(&_COORD{0, 0})
33+}
34+
35+func DefaultIsTerminal() bool {
36+ return true
37+}
38+
39+func DefaultOnWidthChanged(func()) {
40+
41+}
vendor/github.com/chzyer/readline/vim.gonew file+174
@@ -0,0 +1,174 @@
1+package readline
2+
3+const (
4+ VIM_NORMAL = iota
5+ VIM_INSERT
6+ VIM_VISUAL
7+)
8+
9+type opVim struct {
10+ cfg *Config
11+ op *Operation
12+ vimMode int
13+}
14+
15+func newVimMode(op *Operation) *opVim {
16+ ov := &opVim{
17+ cfg: op.cfg,
18+ op: op,
19+ }
20+ ov.SetVimMode(ov.cfg.VimMode)
21+ return ov
22+}
23+
24+func (o *opVim) SetVimMode(on bool) {
25+ if o.cfg.VimMode && !on { // turn off
26+ o.ExitVimMode()
27+ }
28+ o.cfg.VimMode = on
29+ o.vimMode = VIM_INSERT
30+}
31+
32+func (o *opVim) ExitVimMode() {
33+ o.vimMode = VIM_INSERT
34+}
35+
36+func (o *opVim) IsEnableVimMode() bool {
37+ return o.cfg.VimMode
38+}
39+
40+func (o *opVim) handleVimNormalMovement(r rune, readNext func() rune) (t rune, handled bool) {
41+ rb := o.op.buf
42+ handled = true
43+ switch r {
44+ case 'h':
45+ t = CharBackward
46+ case 'j':
47+ t = CharNext
48+ case 'k':
49+ t = CharPrev
50+ case 'l':
51+ t = CharForward
52+ case '0', '^':
53+ rb.MoveToLineStart()
54+ case '$':
55+ rb.MoveToLineEnd()
56+ case 'x':
57+ rb.Delete()
58+ if rb.IsCursorInEnd() {
59+ rb.MoveBackward()
60+ }
61+ case 'r':
62+ rb.Replace(readNext())
63+ case 'd':
64+ next := readNext()
65+ switch next {
66+ case 'd':
67+ rb.Erase()
68+ case 'w':
69+ rb.DeleteWord()
70+ case 'h':
71+ rb.Backspace()
72+ case 'l':
73+ rb.Delete()
74+ }
75+ case 'b', 'B':
76+ rb.MoveToPrevWord()
77+ case 'w', 'W':
78+ rb.MoveToNextWord()
79+ case 'e', 'E':
80+ rb.MoveToEndWord()
81+ case 'f', 'F', 't', 'T':
82+ next := readNext()
83+ prevChar := r == 't' || r == 'T'
84+ reverse := r == 'F' || r == 'T'
85+ switch next {
86+ case CharEsc:
87+ default:
88+ rb.MoveTo(next, prevChar, reverse)
89+ }
90+ default:
91+ return r, false
92+ }
93+ return t, true
94+}
95+
96+func (o *opVim) handleVimNormalEnterInsert(r rune, readNext func() rune) (t rune, handled bool) {
97+ rb := o.op.buf
98+ handled = true
99+ switch r {
100+ case 'i':
101+ case 'I':
102+ rb.MoveToLineStart()
103+ case 'a':
104+ rb.MoveForward()
105+ case 'A':
106+ rb.MoveToLineEnd()
107+ case 's':
108+ rb.Delete()
109+ case 'S':
110+ rb.Erase()
111+ case 'c':
112+ next := readNext()
113+ switch next {
114+ case 'c':
115+ rb.Erase()
116+ case 'w':
117+ rb.DeleteWord()
118+ case 'h':
119+ rb.Backspace()
120+ case 'l':
121+ rb.Delete()
122+ }
123+ default:
124+ return r, false
125+ }
126+
127+ o.EnterVimInsertMode()
128+ return
129+}
130+
131+func (o *opVim) HandleVimNormal(r rune, readNext func() rune) (t rune) {
132+ switch r {
133+ case CharEnter, CharInterrupt:
134+ o.ExitVimMode()
135+ return r
136+ }
137+
138+ if r, handled := o.handleVimNormalMovement(r, readNext); handled {
139+ return r
140+ }
141+
142+ if r, handled := o.handleVimNormalEnterInsert(r, readNext); handled {
143+ return r
144+ }
145+
146+ // invalid operation
147+ o.op.t.Bell()
148+ return 0
149+}
150+
151+func (o *opVim) EnterVimInsertMode() {
152+ o.vimMode = VIM_INSERT
153+}
154+
155+func (o *opVim) ExitVimInsertMode() {
156+ o.vimMode = VIM_NORMAL
157+}
158+
159+func (o *opVim) HandleVim(r rune, readNext func() rune) rune {
160+ if o.vimMode == VIM_NORMAL {
161+ return o.HandleVimNormal(r, readNext)
162+ }
163+ if r == CharEsc {
164+ o.ExitVimInsertMode()
165+ return 0
166+ }
167+
168+ switch o.vimMode {
169+ case VIM_INSERT:
170+ return r
171+ case VIM_VISUAL:
172+ }
173+ return r
174+}
vendor/github.com/chzyer/readline/windows_api.gonew file+152
@@ -0,0 +1,152 @@
1+// +build windows
2+
3+package readline
4+
5+import (
6+ "reflect"
7+ "syscall"
8+ "unsafe"
9+)
10+
11+var (
12+ kernel = NewKernel()
13+ stdout = uintptr(syscall.Stdout)
14+ stdin = uintptr(syscall.Stdin)
15+)
16+
17+type Kernel struct {
18+ SetConsoleCursorPosition,
19+ SetConsoleTextAttribute,
20+ FillConsoleOutputCharacterW,
21+ FillConsoleOutputAttribute,
22+ ReadConsoleInputW,
23+ GetConsoleScreenBufferInfo,
24+ GetConsoleCursorInfo,
25+ GetStdHandle CallFunc
26+}
27+
28+type short int16
29+type word uint16
30+type dword uint32
31+type wchar uint16
32+
33+type _COORD struct {
34+ x short
35+ y short
36+}
37+
38+func (c *_COORD) ptr() uintptr {
39+ return uintptr(*(*int32)(unsafe.Pointer(c)))
40+}
41+
42+const (
43+ EVENT_KEY = 0x0001
44+ EVENT_MOUSE = 0x0002
45+ EVENT_WINDOW_BUFFER_SIZE = 0x0004
46+ EVENT_MENU = 0x0008
47+ EVENT_FOCUS = 0x0010
48+)
49+
50+type _KEY_EVENT_RECORD struct {
51+ bKeyDown int32
52+ wRepeatCount word
53+ wVirtualKeyCode word
54+ wVirtualScanCode word
55+ unicodeChar wchar
56+ dwControlKeyState dword
57+}
58+
59+// KEY_EVENT_RECORD KeyEvent;
60+// MOUSE_EVENT_RECORD MouseEvent;
61+// WINDOW_BUFFER_SIZE_RECORD WindowBufferSizeEvent;
62+// MENU_EVENT_RECORD MenuEvent;
63+// FOCUS_EVENT_RECORD FocusEvent;
64+type _INPUT_RECORD struct {
65+ EventType word
66+ Padding uint16
67+ Event [16]byte
68+}
69+
70+type _CONSOLE_SCREEN_BUFFER_INFO struct {
71+ dwSize _COORD
72+ dwCursorPosition _COORD
73+ wAttributes word
74+ srWindow _SMALL_RECT
75+ dwMaximumWindowSize _COORD
76+}
77+
78+type _SMALL_RECT struct {
79+ left short
80+ top short
81+ right short
82+ bottom short
83+}
84+
85+type _CONSOLE_CURSOR_INFO struct {
86+ dwSize dword
87+ bVisible bool
88+}
89+
90+type CallFunc func(u ...uintptr) error
91+
92+func NewKernel() *Kernel {
93+ k := &Kernel{}
94+ kernel32 := syscall.NewLazyDLL("kernel32.dll")
95+ v := reflect.ValueOf(k).Elem()
96+ t := v.Type()
97+ for i := 0; i < t.NumField(); i++ {
98+ name := t.Field(i).Name
99+ f := kernel32.NewProc(name)
100+ v.Field(i).Set(reflect.ValueOf(k.Wrap(f)))
101+ }
102+ return k
103+}
104+
105+func (k *Kernel) Wrap(p *syscall.LazyProc) CallFunc {
106+ return func(args ...uintptr) error {
107+ var r0 uintptr
108+ var e1 syscall.Errno
109+ size := uintptr(len(args))
110+ if len(args) <= 3 {
111+ buf := make([]uintptr, 3)
112+ copy(buf, args)
113+ r0, _, e1 = syscall.Syscall(p.Addr(), size,
114+ buf[0], buf[1], buf[2])
115+ } else {
116+ buf := make([]uintptr, 6)
117+ copy(buf, args)
118+ r0, _, e1 = syscall.Syscall6(p.Addr(), size,
119+ buf[0], buf[1], buf[2], buf[3], buf[4], buf[5],
120+ )
121+ }
122+
123+ if int(r0) == 0 {
124+ if e1 != 0 {
125+ return error(e1)
126+ } else {
127+ return syscall.EINVAL
128+ }
129+ }
130+ return nil
131+ }
132+
133+}
134+
135+func GetConsoleScreenBufferInfo() (*_CONSOLE_SCREEN_BUFFER_INFO, error) {
136+ t := new(_CONSOLE_SCREEN_BUFFER_INFO)
137+ err := kernel.GetConsoleScreenBufferInfo(
138+ stdout,
139+ uintptr(unsafe.Pointer(t)),
140+ )
141+ return t, err
142+}
143+
144+func GetConsoleCursorInfo() (*_CONSOLE_CURSOR_INFO, error) {
145+ t := new(_CONSOLE_CURSOR_INFO)
146+ err := kernel.GetConsoleCursorInfo(stdout, uintptr(unsafe.Pointer(t)))
147+ return t, err
148+}
149+
150+func SetConsoleCursorPosition(c *_COORD) error {
151+ return kernel.SetConsoleCursorPosition(stdout, c.ptr())
152+}