···11-# 1.5.1
22-33-- fix a deadlock from 1.5
44-55-# 1.5
66-77-- release runtime lock when calling `lnoise`
88-- fix potential memleaks and use of deprecate parts of
99- the OCaml C API
1010-- remove dependency on `result`
-19
vendor/ocaml-linenoise/Makefile
···11-22-all: build test
33-44-build:
55- @dune build @install
66-77-test:
88- @dune runtest --no-buffer --force
99-1010-example:
1111- @dune exec examples/show_off.exe
1212-1313-clean:
1414- @dune clean
1515-1616-doc:
1717- @dune build @doc
1818-1919-.PHONY: all build test example clean doc
-70
vendor/ocaml-linenoise/README.md
···11-Linenoise in OCaml
22---------------------
33-44-[](https://github.com/ocaml-community/ocaml-linenoise/actions/workflows/main.yml)
55-66-# Benefits
77-1. BSD licensed.
88-2. No system dependencies, no need for `readline` on your machine.
99-3. Related to 2, these bindings are self-contained, the source for
1010- `linenoise` is in this repo and compiled all together with the
1111- `OCaml`.
1212-4. Written in OCaml + C.
1313-5. Pretty cool hints feature, see the gif.
1414-6. Additional features compared to linenoise, such as history search
1515-1616-# Installation
1717-1818-It is easy with `opam`
1919-2020-```shell
2121-$ opam install linenoise
2222-```
2323-2424-See the pretty
2525-documentation [here](https://ocaml-community.github.io/ocaml-linenoise/)
2626-2727-# Example code
2828-This example is also included in the repo under examples:
2929-3030-<p align="center" style='min-width:100%'>
3131- <img style='min-width:100%' src='example.gif'/>
3232-</p>
3333-3434-3535-```ocaml
3636-let rec user_input prompt cb =
3737- match LNoise.linenoise prompt with
3838- | None -> ()
3939- | Some v ->
4040- cb v;
4141- user_input prompt cb
4242-4343-let () =
4444- (* LNoise.set_multiline true; *)
4545- LNoise.set_hints_callback (fun line ->
4646- if line <> "git remote add " then None
4747- else Some (" <this is the remote name> <this is the remote URL>",
4848- LNoise.Yellow,
4949- true)
5050- );
5151- LNoise.history_load ~filename:"history.txt" |> ignore;
5252- LNoise.history_set ~max_length:100 |> ignore;
5353- LNoise.set_completion_callback begin fun line_so_far ln_completions ->
5454- if line_so_far <> "" && line_so_far.[0] = 'h' then
5555- ["Hey"; "Howard"; "Hughes";"Hocus"]
5656- |> List.iter (LNoise.add_completion ln_completions);
5757- end;
5858- ["These are OCaml bindings to linenoise";
5959- "get tab completion with <TAB>, type h then hit <TAB>";
6060- "type quit to exit gracefully";
6161- "By Edgar Aroutiounian\n"]
6262- |> List.iter print_endline;
6363- (fun from_user ->
6464- if from_user = "quit" then exit 0;
6565- LNoise.history_add from_user |> ignore;
6666- LNoise.history_save ~filename:"history.txt" |> ignore;
6767- Printf.sprintf "Got: %s" from_user |> print_endline
6868- )
6969- |> user_input "test_program> "
7070-```
···11-22-type completions
33-44-external add_completion : completions -> string -> unit = "ml_add_completion"
55-66-external linenoise : string -> string option = "ml_linenoise"
77-88-external history_add_ : string -> int = "ml_history_add"
99-external history_set_ : max_length:int -> int = "ml_history_set_maxlen"
1010-external history_save_ : filename:string -> int = "ml_history_save"
1111-external history_load_ : filename:string -> int = "ml_history_load"
1212-1313-external catch_break : bool -> unit = "ml_catch_break"
1414-1515-external setup_bridges : unit -> unit = "ml_setup_bridges"
1616-1717-type hint_color = Red | Green | Yellow | Blue | Magenta | Cyan | White
1818-1919-let completion_cb = ref (fun _ _ -> ())
2020-let hints_cb = ref (fun _ -> None)
2121-2222-let set_completion_callback (f:string->completions->unit) : unit =
2323- completion_cb := f;
2424- Callback.register "lnoise_completion_cb" f
2525-2626-let set_hints_callback (f:string -> (string*hint_color*bool) option) : unit =
2727- hints_cb := f;
2828- Callback.register "lnoise_hints_cb" f
2929-3030-(* initialization: register [Sys.Break] and enable catch-break *)
3131-let () =
3232- setup_bridges();
3333- set_completion_callback !completion_cb;
3434- set_hints_callback !hints_cb;
3535- Callback.register_exception "sys_break" Sys.Break;
3636- catch_break true
3737-3838-let history_add h =
3939- if history_add_ h = 0 then Error "Couldn't add to history"
4040- else Ok ()
4141-4242-let history_set ~max_length =
4343- if history_set_ ~max_length = 0
4444- then Error "Couldn't set the max length of history"
4545- else Ok ()
4646-4747-let history_save ~filename =
4848- if history_save_ ~filename = 0 then Ok ()
4949- else Error "Couldn't save"
5050-5151-let history_load ~filename =
5252- if history_load_ ~filename = 0 then Ok ()
5353- else Error "Couldn't load the file"
5454-5555-external clear_screen : unit -> unit = "ml_clearscreen"
5656-external set_multiline : bool -> unit = "ml_set_multiline"
5757-external print_keycodes : unit -> unit = "ml_printkeycodes"
-65
vendor/ocaml-linenoise/src/lNoise.mli
···11-(** OCaml bindings to linenoise, functions that can fail use result
22- type *)
33-44-(** Abstract type of completions, given to your completion callback *)
55-type completions
66-77-(** This function is used by the callback function registered by the
88- user in order to add completion options given the input string
99- when the user typed <TAB>. *)
1010-val add_completion : completions -> string -> unit
1111-1212-(** Register the callback function that is called for upon
1313- tab-completion, aka when <TAB> is hit in the terminal *)
1414-val set_completion_callback : (string -> completions -> unit) -> unit
1515-1616-(** The high level function that is the main API of the linenoise
1717- library. This function checks if the terminal has basic
1818- capabilities, just checking for a blacklist of stupid terminals,
1919- and later either calls the line editing function or uses dummy
2020- fgets() so that you will be able to type something even in the
2121- most desperate of the conditions. *)
2222-val linenoise : string -> string option
2323-2424-(** Add a string to the history *)
2525-val history_add : string -> (unit, string) result
2626-2727-(** Set the maximum length for the history. This function can be
2828- called even if there is already some history, the function will
2929- make sure to retain just the latest 'len' elements if the new
3030- history length value is smaller than the amount of items already
3131- inside the history. *)
3232-val history_set : max_length:int -> (unit, string) result
3333-3434-(** Save the history in the specified file *)
3535-val history_save : filename:string -> (unit, string) result
3636-3737-(** Load the history from the specified file. *)
3838-val history_load : filename:string -> (unit, string) result
3939-4040-(** Clear the screen; used to handle CTRL+L *)
4141-val clear_screen : unit -> unit
4242-4343-(** If [true], [ctrl-c] during a call to {!linenoise}
4444- will raise [Sys.Break] instead of returning an empty string.
4545- @since 1.1 *)
4646-val catch_break : bool -> unit
4747-4848-(** Set if to use or not use the multi line mode. *)
4949-val set_multiline : bool -> unit
5050-5151-(** This special mode is used by linenoise in order to print scan
5252- codes on screen for debugging / development purposes. *)
5353-val print_keycodes : unit -> unit
5454-5555-(** What color you want the hints to be. *)
5656-type hint_color = Red | Green | Yellow | Blue | Magenta | Cyan | White
5757-5858-(** Set a hints callback, callback gets a string, aka the line input,
5959- and you get a chance to give a hint to the user. Example, imagine
6060- if user types git remote add, then you can give a hint of <this is
6161- where you add a remote name> <this is where you add the remote's
6262- URL>, see animated gif in source repo for clear example. Returned
6363- tuple represents the hint message, color, and whether it ought to
6464- be bold. *)
6565-val set_hints_callback : (string -> (string * hint_color * bool) option) -> unit
-1388
vendor/ocaml-linenoise/src/linenoise_src.c
···11-/* linenoise.c -- guerrilla line editing library against the idea that a
22- * line editing lib needs to be 20,000 lines of C code.
33- *
44- * You can find the latest source code at:
55- *
66- * http://github.com/antirez/linenoise
77- *
88- * Does a number of crazy assumptions that happen to be true in 99.9999% of
99- * the 2010 UNIX computers around.
1010- *
1111- * ------------------------------------------------------------------------
1212- *
1313- * Copyright (c) 2010-2016, Salvatore Sanfilippo <antirez at gmail dot com>
1414- * Copyright (c) 2010-2013, Pieter Noordhuis <pcnoordhuis at gmail dot com>
1515- *
1616- * All rights reserved.
1717- *
1818- * Redistribution and use in source and binary forms, with or without
1919- * modification, are permitted provided that the following conditions are
2020- * met:
2121- *
2222- * * Redistributions of source code must retain the above copyright
2323- * notice, this list of conditions and the following disclaimer.
2424- *
2525- * * Redistributions in binary form must reproduce the above copyright
2626- * notice, this list of conditions and the following disclaimer in the
2727- * documentation and/or other materials provided with the distribution.
2828- *
2929- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
3030- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
3131- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
3232- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
3333- * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
3434- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3535- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3636- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3737- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3838- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3939- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
4040- *
4141- * ------------------------------------------------------------------------
4242- *
4343- * References:
4444- * - http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
4545- * - http://www.3waylabs.com/nw/WWW/products/wizcon/vt220.html
4646- *
4747- * Todo list:
4848- * - Filter bogus Ctrl+<char> combinations.
4949- * - Win32 support
5050- *
5151- * List of escape sequences used by this program, we do everything just
5252- * with three sequences. In order to be so cheap we may have some
5353- * flickering effect with some slow terminal, but the lesser sequences
5454- * the more compatible.
5555- *
5656- * EL (Erase Line)
5757- * Sequence: ESC [ n K
5858- * Effect: if n is 0 or missing, clear from cursor to end of line
5959- * Effect: if n is 1, clear from beginning of line to cursor
6060- * Effect: if n is 2, clear entire line
6161- *
6262- * CUF (CUrsor Forward)
6363- * Sequence: ESC [ n C
6464- * Effect: moves cursor forward n chars
6565- *
6666- * CUB (CUrsor Backward)
6767- * Sequence: ESC [ n D
6868- * Effect: moves cursor backward n chars
6969- *
7070- * The following is used to get the terminal width if getting
7171- * the width with the TIOCGWINSZ ioctl fails
7272- *
7373- * DSR (Device Status Report)
7474- * Sequence: ESC [ 6 n
7575- * Effect: reports the current cusor position as ESC [ n ; m R
7676- * where n is the row and m is the column
7777- *
7878- * When multi line mode is enabled, we also use an additional escape
7979- * sequence. However multi line editing is disabled by default.
8080- *
8181- * CUU (Cursor Up)
8282- * Sequence: ESC [ n A
8383- * Effect: moves cursor up of n chars.
8484- *
8585- * CUD (Cursor Down)
8686- * Sequence: ESC [ n B
8787- * Effect: moves cursor down of n chars.
8888- *
8989- * When linenoiseClearScreen() is called, two additional escape sequences
9090- * are used in order to clear the screen and position the cursor at home
9191- * position.
9292- *
9393- * CUP (Cursor position)
9494- * Sequence: ESC [ H
9595- * Effect: moves the cursor to upper left corner
9696- *
9797- * ED (Erase display)
9898- * Sequence: ESC [ 2 J
9999- * Effect: clear the whole screen
100100- *
101101- */
102102-103103-#include <termios.h>
104104-#include <unistd.h>
105105-#include <stdlib.h>
106106-#include <stdio.h>
107107-#include <errno.h>
108108-#include <string.h>
109109-#include <stdlib.h>
110110-#include <ctype.h>
111111-#include <sys/stat.h>
112112-#include <sys/types.h>
113113-#include <sys/ioctl.h>
114114-#include <unistd.h>
115115-#include "linenoise_src.h"
116116-117117-#define LINENOISE_DEFAULT_HISTORY_MAX_LEN 100
118118-#define LINENOISE_MAX_LINE 4096
119119-static char *unsupported_term[] = {"dumb","cons25","emacs",NULL};
120120-static linenoiseCompletionCallback *completionCallback = NULL;
121121-static linenoiseHintsCallback *hintsCallback = NULL;
122122-static linenoiseFreeHintsCallback *freeHintsCallback = NULL;
123123-124124-static struct termios orig_termios; /* In order to restore at exit.*/
125125-static int rawmode = 0; /* For atexit() function to check if restore is needed*/
126126-static int mlmode = 0; /* Multi line mode. Default is single line. */
127127-static int atexit_registered = 0; /* Register atexit just 1 time. */
128128-static int history_max_len = LINENOISE_DEFAULT_HISTORY_MAX_LEN;
129129-static int history_len = 0;
130130-static char **history = NULL;
131131-132132-int linenoiseWasInterrupted = 0;
133133-134134-/* The linenoiseState structure represents the state during line editing.
135135- * We pass this state to functions implementing specific editing
136136- * functionalities. */
137137-struct linenoiseState {
138138- int ifd; /* Terminal stdin file descriptor. */
139139- int ofd; /* Terminal stdout file descriptor. */
140140- char *buf; /* Edited line buffer. */
141141- size_t buflen; /* Edited line buffer size. */
142142- const char *prompt; /* Prompt to display. */
143143- size_t plen; /* Prompt length. */
144144- size_t pos; /* Current cursor position. */
145145- size_t oldpos; /* Previous refresh cursor position. */
146146- size_t len; /* Current edited line length. */
147147- size_t cols; /* Number of columns in terminal. */
148148- size_t maxrows; /* Maximum num of rows used so far (multiline mode) */
149149- int history_index; /* The history index we are currently editing. */
150150-};
151151-152152-enum KEY_ACTION{
153153- KEY_NULL = 0, /* NULL */
154154- CTRL_A = 1, /* Ctrl+a */
155155- CTRL_B = 2, /* Ctrl-b */
156156- CTRL_C = 3, /* Ctrl-c */
157157- CTRL_D = 4, /* Ctrl-d */
158158- CTRL_E = 5, /* Ctrl-e */
159159- CTRL_F = 6, /* Ctrl-f */
160160- CTRL_G = 7, /* Ctrl-g */
161161- CTRL_H = 8, /* Ctrl-h */
162162- TAB = 9, /* Tab */
163163- CTRL_K = 11, /* Ctrl+k */
164164- CTRL_L = 12, /* Ctrl+l */
165165- ENTER = 13, /* Enter */
166166- CTRL_N = 14, /* Ctrl-n */
167167- CTRL_P = 16, /* Ctrl-p */
168168- CTRL_R = 18, /* Ctrl-r */
169169- CTRL_T = 20, /* Ctrl-t */
170170- CTRL_U = 21, /* Ctrl+u */
171171- CTRL_W = 23, /* Ctrl+w */
172172- ESC = 27, /* Escape */
173173- BACKSPACE = 127 /* Backspace */
174174-};
175175-176176-static void linenoiseAtExit(void);
177177-int linenoiseHistoryAdd(const char *line);
178178-static void refreshLine(struct linenoiseState *l);
179179-static void refreshLinePrompt(struct linenoiseState *l, const char *prompt);
180180-181181-/* Debugging macro. */
182182-#if 0
183183-FILE *lndebug_fp = NULL;
184184-#define lndebug(...) \
185185- do { \
186186- if (lndebug_fp == NULL) { \
187187- lndebug_fp = fopen("/tmp/lndebug.txt","a"); \
188188- fprintf(lndebug_fp, \
189189- "[%d %d %d] p: %d, rows: %d, rpos: %d, max: %d, oldmax: %d\n", \
190190- (int)l->len,(int)l->pos,(int)l->oldpos,plen,rows,rpos, \
191191- (int)l->maxrows,old_rows); \
192192- } \
193193- fprintf(lndebug_fp, ", " __VA_ARGS__); \
194194- fflush(lndebug_fp); \
195195- } while (0)
196196-#else
197197-#define lndebug(fmt, ...)
198198-#endif
199199-200200-/* ======================= Low level terminal handling ====================== */
201201-202202-/* Set if to use or not the multi line mode. */
203203-void linenoiseSetMultiLine(int ml) {
204204- mlmode = ml;
205205-}
206206-207207-/* Return true if the terminal name is in the list of terminals we know are
208208- * not able to understand basic escape sequences. */
209209-static int isUnsupportedTerm(void) {
210210- char *term = getenv("TERM");
211211- int j;
212212-213213- if (term == NULL) return 0;
214214- for (j = 0; unsupported_term[j]; j++)
215215- if (!strcasecmp(term,unsupported_term[j])) return 1;
216216- return 0;
217217-}
218218-219219-/* Raw mode: 1960 magic shit. */
220220-static int enableRawMode(int fd) {
221221- struct termios raw;
222222-223223- if (!isatty(STDIN_FILENO)) goto fatal;
224224- if (!atexit_registered) {
225225- atexit(linenoiseAtExit);
226226- atexit_registered = 1;
227227- }
228228- if (tcgetattr(fd,&orig_termios) == -1) goto fatal;
229229-230230- raw = orig_termios; /* modify the original mode */
231231- /* input modes: no break, no CR to NL, no parity check, no strip char,
232232- * no start/stop output control. */
233233- raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
234234- /* output modes - disable post processing */
235235- raw.c_oflag &= ~(OPOST);
236236- /* control modes - set 8 bit chars */
237237- raw.c_cflag |= (CS8);
238238- /* local modes - choing off, canonical off, no extended functions,
239239- * no signal chars (^Z,^C) */
240240- raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
241241- /* control chars - set return condition: min number of bytes and timer.
242242- * We want read to return every single byte, without timeout. */
243243- raw.c_cc[VMIN] = 1; raw.c_cc[VTIME] = 0; /* 1 byte, no timer */
244244-245245- /* put terminal in raw mode after flushing */
246246- if (tcsetattr(fd,TCSADRAIN,&raw) < 0) goto fatal;
247247- rawmode = 1;
248248- return 0;
249249-250250-fatal:
251251- errno = ENOTTY;
252252- return -1;
253253-}
254254-255255-static void disableRawMode(int fd) {
256256- /* Don't even check the return value as it's too late. */
257257- if (rawmode && tcsetattr(fd,TCSADRAIN,&orig_termios) != -1)
258258- rawmode = 0;
259259-}
260260-261261-/* Use the ESC [6n escape sequence to query the horizontal cursor position
262262- * and return it. On error -1 is returned, on success the position of the
263263- * cursor. */
264264-static int getCursorPosition(int ifd, int ofd) {
265265- char buf[32];
266266- int cols, rows;
267267- unsigned int i = 0;
268268-269269- /* Report cursor location */
270270- if (write(ofd, "\x1b[6n", 4) != 4) return -1;
271271-272272- /* Read the response: ESC [ rows ; cols R */
273273- while (i < sizeof(buf)-1) {
274274- if (read(ifd,buf+i,1) != 1) break;
275275- if (buf[i] == 'R') break;
276276- i++;
277277- }
278278- buf[i] = '\0';
279279-280280- /* Parse it. */
281281- if (buf[0] != ESC || buf[1] != '[') return -1;
282282- if (sscanf(buf+2,"%d;%d",&rows,&cols) != 2) return -1;
283283- return cols;
284284-}
285285-286286-/* Try to get the number of columns in the current terminal, or assume 80
287287- * if it fails. */
288288-static int getColumns(int ifd, int ofd) {
289289- struct winsize ws;
290290-291291- if (ioctl(1, TIOCGWINSZ, &ws) == -1 || ws.ws_col == 0) {
292292- /* ioctl() failed. Try to query the terminal itself. */
293293- int start, cols;
294294-295295- /* Get the initial position so we can restore it later. */
296296- start = getCursorPosition(ifd,ofd);
297297- if (start == -1) goto failed;
298298-299299- /* Go to right margin and get position. */
300300- if (write(ofd,"\x1b[999C",6) != 6) goto failed;
301301- cols = getCursorPosition(ifd,ofd);
302302- if (cols == -1) goto failed;
303303-304304- /* Restore position. */
305305- if (cols > start) {
306306- char seq[32];
307307- snprintf(seq,32,"\x1b[%dD",cols-start);
308308- if (write(ofd,seq,strlen(seq)) == -1) {
309309- /* Can't recover... */
310310- }
311311- }
312312- return cols;
313313- } else {
314314- return ws.ws_col;
315315- }
316316-317317-failed:
318318- return 80;
319319-}
320320-321321-/* Clear the screen. Used to handle ctrl+l */
322322-void linenoiseClearScreen(void) {
323323- if (write(STDOUT_FILENO,"\x1b[H\x1b[2J",7) <= 0) {
324324- /* nothing to do, just to avoid warning. */
325325- }
326326-}
327327-328328-/* Beep, used for completion when there is nothing to complete or when all
329329- * the choices were already shown. */
330330-static void linenoiseBeep(void) {
331331- fprintf(stderr, "\x7");
332332- fflush(stderr);
333333-}
334334-335335-/* ============================== Completion ================================ */
336336-337337-/* Free a list of completion option populated by linenoiseAddCompletion(). */
338338-static void freeCompletions(linenoiseCompletions *lc) {
339339- size_t i;
340340- for (i = 0; i < lc->len; i++)
341341- free(lc->cvec[i]);
342342- if (lc->cvec != NULL)
343343- free(lc->cvec);
344344-}
345345-346346-/* This is an helper function for linenoiseEdit() and is called when the
347347- * user types the <tab> key in order to complete the string currently in the
348348- * input.
349349- *
350350- * The state of the editing is encapsulated into the pointed linenoiseState
351351- * structure as described in the structure definition. */
352352-static int completeLine(struct linenoiseState *ls) {
353353- linenoiseCompletions lc = { 0, NULL };
354354- int nread, nwritten;
355355- char c = 0;
356356-357357- completionCallback(ls->buf,&lc);
358358- if (lc.len == 0) {
359359- linenoiseBeep();
360360- } else {
361361- size_t stop = 0, i = 0;
362362-363363- while(!stop) {
364364- /* Show completion or original buffer */
365365- if (i < lc.len) {
366366- struct linenoiseState saved = *ls;
367367-368368- ls->len = ls->pos = strlen(lc.cvec[i]);
369369- ls->buf = lc.cvec[i];
370370- refreshLine(ls);
371371- ls->len = saved.len;
372372- ls->pos = saved.pos;
373373- ls->buf = saved.buf;
374374- } else {
375375- refreshLine(ls);
376376- }
377377-378378- nread = read(ls->ifd,&c,1);
379379- if (nread <= 0) {
380380- freeCompletions(&lc);
381381- return -1;
382382- }
383383-384384- switch(c) {
385385- case 9: /* tab */
386386- i = (i+1) % (lc.len+1);
387387- if (i == lc.len) linenoiseBeep();
388388- break;
389389- case 27: /* escape */
390390- /* Re-show original buffer */
391391- if (i < lc.len) refreshLine(ls);
392392- stop = 1;
393393- break;
394394- default:
395395- /* Update buffer and return */
396396- if (i < lc.len) {
397397- nwritten = snprintf(ls->buf,ls->buflen,"%s",lc.cvec[i]);
398398- ls->len = ls->pos = nwritten;
399399- }
400400- stop = 1;
401401- break;
402402- }
403403- }
404404- }
405405-406406- freeCompletions(&lc);
407407- return c; /* Return last read character */
408408-}
409409-410410-/* Register a callback function to be called for tab-completion. */
411411-void linenoiseSetCompletionCallback(linenoiseCompletionCallback *fn) {
412412- completionCallback = fn;
413413-}
414414-415415-/* Register a hits function to be called to show hits to the user at the
416416- * right of the prompt. */
417417-void linenoiseSetHintsCallback(linenoiseHintsCallback *fn) {
418418- hintsCallback = fn;
419419-}
420420-421421-/* Register a function to free the hints returned by the hints callback
422422- * registered with linenoiseSetHintsCallback(). */
423423-void linenoiseSetFreeHintsCallback(linenoiseFreeHintsCallback *fn) {
424424- freeHintsCallback = fn;
425425-}
426426-427427-/* This function is used by the callback function registered by the user
428428- * in order to add completion options given the input string when the
429429- * user typed <tab>. See the example.c source code for a very easy to
430430- * understand example. */
431431-void linenoiseAddCompletion(linenoiseCompletions *lc, const char *str) {
432432- size_t len = strlen(str);
433433- char *copy, **cvec;
434434-435435- copy = malloc(len+1);
436436- if (copy == NULL) return;
437437- memcpy(copy,str,len+1);
438438- cvec = realloc(lc->cvec,sizeof(char*)*(lc->len+1));
439439- if (cvec == NULL) {
440440- free(copy);
441441- return;
442442- }
443443- lc->cvec = cvec;
444444- lc->cvec[lc->len++] = copy;
445445-}
446446-447447-/* =========================== Line editing ================================= */
448448-449449-/* We define a very simple "append buffer" structure, that is an heap
450450- * allocated string where we can append to. This is useful in order to
451451- * write all the escape sequences in a buffer and flush them to the standard
452452- * output in a single call, to avoid flickering effects. */
453453-struct abuf {
454454- char *b;
455455- int len;
456456-};
457457-458458-static void abInit(struct abuf *ab) {
459459- ab->b = NULL;
460460- ab->len = 0;
461461-}
462462-463463-static void abAppend(struct abuf *ab, const char *s, int len) {
464464- char *new = realloc(ab->b,ab->len+len);
465465-466466- if (new == NULL) return;
467467- memcpy(new+ab->len,s,len);
468468- ab->b = new;
469469- ab->len += len;
470470-}
471471-472472-static void abFree(struct abuf *ab) {
473473- free(ab->b);
474474-}
475475-476476-/* Helper of refreshSingleLine() and refreshMultiLine() to show hints
477477- * to the right of the prompt. */
478478-void refreshShowHints(struct abuf *ab, struct linenoiseState *l, int plen) {
479479- char seq[64];
480480- if (hintsCallback && plen+l->len < l->cols) {
481481- int color = -1, bold = 0;
482482- char *hint = hintsCallback(l->buf,&color,&bold);
483483- if (hint) {
484484- int hintlen = strlen(hint);
485485- int hintmaxlen = l->cols-(plen+l->len);
486486- if (hintlen > hintmaxlen) hintlen = hintmaxlen;
487487- if (bold == 1 && color == -1) color = 37;
488488- if (color != -1 || bold != 0)
489489- snprintf(seq,64,"\033[%d;%d;49m",bold,color);
490490- abAppend(ab,seq,strlen(seq));
491491- abAppend(ab,hint,hintlen);
492492- if (color != -1 || bold != 0)
493493- abAppend(ab,"\033[0m",4);
494494- /* Call the function to free the hint returned. */
495495- if (freeHintsCallback) freeHintsCallback(hint);
496496- }
497497- }
498498-}
499499-500500-/* Single line low level line refresh.
501501- *
502502- * Rewrite the currently edited line accordingly to the buffer content,
503503- * cursor position, and number of columns of the terminal. */
504504-static void refreshSingleLine(struct linenoiseState *l, const char *prompt) {
505505- char seq[64];
506506- size_t plen = strlen(prompt);
507507- int fd = l->ofd;
508508- char *buf = l->buf;
509509- size_t len = l->len;
510510- size_t pos = l->pos;
511511- struct abuf ab;
512512-513513- if (plen >= l->cols) {
514514- len=0; // not enough room
515515- plen = l->cols;
516516- }
517517-518518- while((plen+pos) >= l->cols && len>0) {
519519- buf++;
520520- len--;
521521- pos--;
522522- }
523523- while (plen+len > l->cols && len>0) {
524524- len--;
525525- }
526526-527527- abInit(&ab);
528528- /* Cursor to left edge */
529529- snprintf(seq,64,"\r");
530530- abAppend(&ab,seq,strlen(seq));
531531- /* Write the prompt and the current buffer content */
532532- abAppend(&ab,prompt,plen);
533533- if (len > 0)
534534- abAppend(&ab,buf,len);
535535- /* Show hits if any. */
536536- refreshShowHints(&ab,l,plen);
537537- /* Erase to right */
538538- snprintf(seq,64,"\x1b[0K");
539539- abAppend(&ab,seq,strlen(seq));
540540- /* Move cursor to original position. */
541541- snprintf(seq,64,"\r\x1b[%dC", (int)(pos+plen));
542542- abAppend(&ab,seq,strlen(seq));
543543- if (write(fd,ab.b,ab.len) == -1) {} /* Can't recover from write error. */
544544- abFree(&ab);
545545-}
546546-547547-/* Multi line low level line refresh.
548548- *
549549- * Rewrite the currently edited line accordingly to the buffer content,
550550- * cursor position, and number of columns of the terminal. */
551551-static void refreshMultiLine(struct linenoiseState *l, const char *prompt) {
552552- char seq[64];
553553- int plen = strlen(prompt);
554554- int rows = (plen+l->len+l->cols-1)/l->cols; /* rows used by current buf. */
555555- int rpos = (plen+l->oldpos+l->cols)/l->cols; /* cursor relative row. */
556556- int rpos2; /* rpos after refresh. */
557557- int col; /* colum position, zero-based. */
558558- int old_rows = l->maxrows;
559559- size_t pos = l->pos;
560560- int fd = l->ofd, j;
561561- struct abuf ab;
562562-563563- /* Update maxrows if needed. */
564564- if (rows > (int)l->maxrows) l->maxrows = rows;
565565-566566- /* First step: clear all the lines used before. To do so start by
567567- * going to the last row. */
568568- abInit(&ab);
569569- if (old_rows-rpos > 0) {
570570- lndebug("go down %d", old_rows-rpos);
571571- snprintf(seq,64,"\x1b[%dB", old_rows-rpos);
572572- abAppend(&ab,seq,strlen(seq));
573573- }
574574-575575- /* Now for every row clear it, go up. */
576576- for (j = 0; j < old_rows-1; j++) {
577577- lndebug("clear+up");
578578- snprintf(seq,64,"\r\x1b[0K\x1b[1A");
579579- abAppend(&ab,seq,strlen(seq));
580580- }
581581-582582- /* Clean the top line. */
583583- lndebug("clear");
584584- snprintf(seq,64,"\r\x1b[0K");
585585- abAppend(&ab,seq,strlen(seq));
586586-587587- /* Write the prompt and the current buffer content */
588588- abAppend(&ab,prompt,strlen(prompt));
589589- abAppend(&ab,l->buf,l->len);
590590-591591- /* Show hits if any. */
592592- refreshShowHints(&ab,l,plen);
593593-594594- /* If we are at the very end of the screen with our prompt, we need to
595595- * emit a newline and move the prompt to the first column. */
596596- if (pos &&
597597- pos == l->len &&
598598- (pos+plen) % l->cols == 0)
599599- {
600600- lndebug("<newline>");
601601- abAppend(&ab,"\n",1);
602602- snprintf(seq,64,"\r");
603603- abAppend(&ab,seq,strlen(seq));
604604- rows++;
605605- if (rows > (int)l->maxrows) l->maxrows = rows;
606606- }
607607-608608- /* Move cursor to right position. */
609609- rpos2 = (plen+pos+l->cols)/l->cols; /* current cursor relative row. */
610610- lndebug("rpos2 %d", rpos2);
611611-612612- /* Go up till we reach the expected positon. */
613613- if (rows-rpos2 > 0) {
614614- lndebug("go-up %d", rows-rpos2);
615615- snprintf(seq,64,"\x1b[%dA", rows-rpos2);
616616- abAppend(&ab,seq,strlen(seq));
617617- }
618618-619619- /* Set column. */
620620- col = (plen+(int)pos) % (int)l->cols;
621621- lndebug("set col %d", 1+col);
622622- if (col)
623623- snprintf(seq,64,"\r\x1b[%dC", col);
624624- else
625625- snprintf(seq,64,"\r");
626626- abAppend(&ab,seq,strlen(seq));
627627-628628- lndebug("\n");
629629- l->oldpos = pos;
630630-631631- if (write(fd,ab.b,ab.len) == -1) {} /* Can't recover from write error. */
632632- abFree(&ab);
633633-}
634634-635635-/* Calls the two low level functions refreshSingleLine() or
636636- * refreshMultiLine() according to the selected mode. */
637637-static void refreshLinePrompt(struct linenoiseState *l, const char *prompt) {
638638- if (mlmode)
639639- refreshMultiLine(l, prompt);
640640- else
641641- refreshSingleLine(l, prompt);
642642-}
643643-644644-static void refreshLine(struct linenoiseState *l) {
645645- refreshLinePrompt(l, l->prompt);
646646-}
647647-648648-/* Insert the character 'c' at cursor current position.
649649- *
650650- * On error writing to the terminal -1 is returned, otherwise 0. */
651651-int linenoiseEditInsert(struct linenoiseState *l, char c) {
652652- if (l->len < l->buflen) {
653653- if (l->len == l->pos) {
654654- l->buf[l->pos] = c;
655655- l->pos++;
656656- l->len++;
657657- l->buf[l->len] = '\0';
658658- if ((!mlmode && l->plen+l->len < l->cols && !hintsCallback)) {
659659- /* Avoid a full update of the line in the
660660- * trivial case. */
661661- if (write(l->ofd,&c,1) == -1) return -1;
662662- } else {
663663- refreshLine(l);
664664- }
665665- } else {
666666- memmove(l->buf+l->pos+1,l->buf+l->pos,l->len-l->pos);
667667- l->buf[l->pos] = c;
668668- l->len++;
669669- l->pos++;
670670- l->buf[l->len] = '\0';
671671- refreshLine(l);
672672- }
673673- }
674674- return 0;
675675-}
676676-677677-/* Move cursor on the left. */
678678-void linenoiseEditMoveLeft(struct linenoiseState *l) {
679679- if (l->pos > 0) {
680680- l->pos--;
681681- refreshLine(l);
682682- }
683683-}
684684-685685-/* Move cursor on the right. */
686686-void linenoiseEditMoveRight(struct linenoiseState *l) {
687687- if (l->pos != l->len) {
688688- l->pos++;
689689- refreshLine(l);
690690- }
691691-}
692692-693693-/* Move cursor on the left */
694694-void linenoiseEditMovePrevWord(struct linenoiseState *l) {
695695- while (l->pos > 0 && l->buf[l->pos-1] == ' ')
696696- l->pos--;
697697- while (l->pos > 0 && l->buf[l->pos-1] != ' ')
698698- l->pos--;
699699- refreshLine(l);
700700-}
701701-702702-/* Move cursor on the right. */
703703-void linenoiseEditMoveNextWord(struct linenoiseState *l) {
704704- while (l->pos < l->len && l->buf[l->pos-1] == ' ')
705705- l->pos++;
706706- while (l->pos < l->len && l->buf[l->pos-1] != ' ')
707707- l->pos++;
708708- refreshLine(l);
709709-}
710710-711711-/* Move cursor to the start of the line. */
712712-void linenoiseEditMoveHome(struct linenoiseState *l) {
713713- if (l->pos != 0) {
714714- l->pos = 0;
715715- refreshLine(l);
716716- }
717717-}
718718-719719-/* Move cursor to the end of the line. */
720720-void linenoiseEditMoveEnd(struct linenoiseState *l) {
721721- if (l->pos != l->len) {
722722- l->pos = l->len;
723723- refreshLine(l);
724724- }
725725-}
726726-727727-/* Substitute the currently edited line with the next or previous history
728728- * entry as specified by 'dir'. */
729729-#define LINENOISE_HISTORY_NEXT 0
730730-#define LINENOISE_HISTORY_PREV 1
731731-void linenoiseEditHistoryNext(struct linenoiseState *l, int dir) {
732732- if (history_len > 1) {
733733- /* Update the current history entry before to
734734- * overwrite it with the next one. */
735735- free(history[history_len - 1 - l->history_index]);
736736- history[history_len - 1 - l->history_index] = strdup(l->buf);
737737- /* Show the new entry */
738738- l->history_index += (dir == LINENOISE_HISTORY_PREV) ? 1 : -1;
739739- if (l->history_index < 0) {
740740- l->history_index = 0;
741741- return;
742742- } else if (l->history_index >= history_len) {
743743- l->history_index = history_len-1;
744744- return;
745745- }
746746- strncpy(l->buf,history[history_len - 1 - l->history_index],l->buflen);
747747- l->buf[l->buflen-1] = '\0';
748748- l->len = l->pos = strlen(l->buf);
749749- refreshLine(l);
750750- }
751751-}
752752-753753-/* Delete the character at the right of the cursor without altering the cursor
754754- * position. Basically this is what happens with the "Delete" keyboard key. */
755755-void linenoiseEditDelete(struct linenoiseState *l) {
756756- if (l->len > 0 && l->pos < l->len) {
757757- memmove(l->buf+l->pos,l->buf+l->pos+1,l->len-l->pos-1);
758758- l->len--;
759759- l->buf[l->len] = '\0';
760760- refreshLine(l);
761761- }
762762-}
763763-764764-/* Backspace implementation. */
765765-void linenoiseEditBackspace(struct linenoiseState *l) {
766766- if (l->pos > 0 && l->len > 0) {
767767- memmove(l->buf+l->pos-1,l->buf+l->pos,l->len-l->pos);
768768- l->pos--;
769769- l->len--;
770770- l->buf[l->len] = '\0';
771771- refreshLine(l);
772772- }
773773-}
774774-775775-/* Delete the previous word, maintaining the cursor at the start of the
776776- * current word. */
777777-void linenoiseEditDeletePrevWord(struct linenoiseState *l) {
778778- size_t old_pos = l->pos;
779779- size_t diff;
780780-781781- while (l->pos > 0 && l->buf[l->pos-1] == ' ')
782782- l->pos--;
783783- while (l->pos > 0 && l->buf[l->pos-1] != ' ')
784784- l->pos--;
785785- diff = old_pos - l->pos;
786786- memmove(l->buf+l->pos,l->buf+old_pos,l->len-old_pos+1);
787787- l->len -= diff;
788788- refreshLine(l);
789789-}
790790-791791-/* Delete the next word, maintaining the cursor at the same position */
792792-void linenoiseEditDeleteNextWord(struct linenoiseState *l) {
793793- size_t next_pos = l->pos;
794794- size_t diff;
795795-796796- while (next_pos < l->len && l->buf[next_pos] == ' ')
797797- next_pos++;
798798- while (next_pos < l->len && l->buf[next_pos] != ' ')
799799- next_pos++;
800800- diff = next_pos - l->pos;
801801- memmove(l->buf+l->pos,l->buf+next_pos,l->len-next_pos+1);
802802- l->len -= diff;
803803- refreshLine(l);
804804-}
805805-806806-void linenoiseReverseIncrementalSearch(struct linenoiseState *l) {
807807-808808- char search_buf[LINENOISE_MAX_LINE];
809809- char search_prompt[LINENOISE_MAX_LINE];
810810- int search_len = 0;
811811- int search_pos = history_len - 1;
812812- int search_dir = -1;
813813- char* prompt;
814814-815815- int has_match = 1;
816816-817817- // backup of current input
818818- char *buf;
819819- {
820820- size_t len = 1+ strlen(l->buf);
821821- buf = malloc(len);
822822- if (buf == NULL) return;
823823- memcpy(buf, l->buf, len);
824824- }
825825-826826- search_buf[0] = 0;
827827-828828- while (1) {
829829-830830- if (!has_match)
831831- prompt = "(failed-reverse-i-search)`%s': ";
832832- else
833833- prompt = "(reverse-i-search)`%s': ";
834834-835835- if (!snprintf(search_prompt, sizeof(search_prompt), prompt, search_buf)) {
836836- linenoiseBeep();
837837- break;
838838- } else {
839839- search_prompt[sizeof(search_prompt)-1] = 0; // crop
840840- }
841841-842842- l->pos = 0;
843843- refreshLinePrompt(l, search_prompt);
844844-845845- char c;
846846- int new_char = 0;
847847-848848- if (read(l->ifd, &c, 1) <= 0) {
849849- l->pos = l->len = snprintf(l->buf, l->buflen, "%s", buf);
850850- l->buf[l->buflen-1] = 0;
851851- refreshLine(l);
852852- free(buf);
853853- return;
854854- }
855855-856856- switch(c) {
857857- case BACKSPACE:
858858- case CTRL_H:
859859- if (search_len > 0) {
860860- search_buf[--search_len] = 0;
861861- search_pos = history_len - 1;
862862- } else
863863- linenoiseBeep();
864864- break;
865865- case CTRL_N:
866866- case CTRL_R:
867867- search_dir = -1;
868868- if (search_pos >= history_len)
869869- search_pos = history_len - 1;
870870- break;
871871- case CTRL_P:
872872- search_dir = 1;
873873- if (search_pos < 0)
874874- search_pos = 0;
875875- break;
876876- case ESC:
877877- case CTRL_G:
878878- l->pos = l->len = snprintf(l->buf, l->buflen, "%s", buf);
879879- l->buf[l->buflen-1] = 0;
880880- free(buf);
881881- refreshLine(l);
882882- return;
883883- case ENTER:
884884- free(buf);
885885- l->pos = l->len;
886886- refreshLine(l);
887887- return;
888888- default:
889889- new_char = 1;
890890- search_buf[search_len] = c;
891891- search_buf[++search_len] = 0;
892892- search_pos = history_len - 1;
893893- break;
894894- }
895895-896896- has_match = 0;
897897-898898- if (strlen(search_buf) > 0) {
899899- for (; search_pos >= 0 && search_pos < history_len; search_pos += search_dir) {
900900- if (strstr(history[search_pos], search_buf) && (new_char || strcmp(history[search_pos], l->buf))) {
901901- has_match = 1;
902902- l->len = snprintf(l->buf, l->buflen, "%s", history[search_pos]);
903903- break;
904904- }
905905- }
906906- if (!has_match) {
907907- linenoiseBeep();
908908- // forbid writes if the line is too long
909909- if (search_len > 0 && new_char && search_len+1 >= sizeof(search_buf))
910910- search_buf[--search_len] = 0;
911911- }
912912- }
913913- }
914914-}
915915-916916-/* This function is the core of the line editing capability of linenoise.
917917- * It expects 'fd' to be already in "raw mode" so that every key pressed
918918- * will be returned ASAP to read().
919919- *
920920- * The resulting string is put into 'buf' when the user type enter, or
921921- * when ctrl+d is typed.
922922- *
923923- * The function returns the length of the current buffer. */
924924-static int linenoiseEdit(int stdin_fd, int stdout_fd, char *buf, size_t buflen, const char *prompt)
925925-{
926926- struct linenoiseState l;
927927-928928- /* Populate the linenoise state that we pass to functions implementing
929929- * specific editing functionalities. */
930930- l.ifd = stdin_fd;
931931- l.ofd = stdout_fd;
932932- l.buf = buf;
933933- l.buflen = buflen;
934934- l.prompt = prompt;
935935- l.plen = strlen(prompt);
936936- l.oldpos = l.pos = 0;
937937- l.len = 0;
938938- l.cols = getColumns(stdin_fd, stdout_fd);
939939- l.maxrows = 0;
940940- l.history_index = 0;
941941-942942- /* Buffer starts empty. */
943943- l.buf[0] = '\0';
944944- l.buflen--; /* Make sure there is always space for the nulterm */
945945-946946- /* The latest history entry is always our current buffer, that
947947- * initially is just an empty string. */
948948- linenoiseHistoryAdd("");
949949-950950- if (write(l.ofd,prompt,l.plen) == -1) return -1;
951951- while(1) {
952952- char c;
953953- int nread;
954954- char seq[5];
955955-956956- nread = read(l.ifd,&c,1);
957957- if (nread <= 0) return l.len;
958958-959959- /* Only autocomplete when the callback is set. It returns < 0 when
960960- * there was an error reading from fd. Otherwise it will return the
961961- * character that should be handled next. */
962962- if (c == 9 && completionCallback != NULL) {
963963- c = completeLine(&l);
964964- /* Return on errors */
965965- if (c < 0) return l.len;
966966- /* Read next character when 0 */
967967- if (c == 0) continue;
968968- }
969969-970970- switch(c) {
971971- case ENTER: /* enter */
972972- history_len--;
973973- free(history[history_len]);
974974- if (mlmode) linenoiseEditMoveEnd(&l);
975975- if (hintsCallback) {
976976- /* Force a refresh without hints to leave the previous
977977- * line as the user typed it after a newline. */
978978- linenoiseHintsCallback *hc = hintsCallback;
979979- hintsCallback = NULL;
980980- refreshLine(&l);
981981- hintsCallback = hc;
982982- }
983983- return (int)l.len;
984984- case CTRL_C: /* ctrl-c */
985985- errno = EAGAIN;
986986- linenoiseWasInterrupted = 1;
987987- return -1;
988988- case BACKSPACE: /* backspace */
989989- case 8: /* ctrl-h */
990990- linenoiseEditBackspace(&l);
991991- break;
992992- case CTRL_D: /* ctrl-d, remove char at right of cursor, or if the
993993- line is empty, act as end-of-file. */
994994- if (l.len > 0) {
995995- linenoiseEditDelete(&l);
996996- } else {
997997- history_len--;
998998- free(history[history_len]);
999999- return -1;
10001000- }
10011001- break;
10021002- case CTRL_T: /* ctrl-t, swaps current character with previous. */
10031003- if (l.pos > 0 && l.pos < l.len) {
10041004- int aux = buf[l.pos-1];
10051005- buf[l.pos-1] = buf[l.pos];
10061006- buf[l.pos] = aux;
10071007- if (l.pos != l.len-1) l.pos++;
10081008- refreshLine(&l);
10091009- }
10101010- break;
10111011- case CTRL_B: /* ctrl-b */
10121012- linenoiseEditMoveLeft(&l);
10131013- break;
10141014- case CTRL_F: /* ctrl-f */
10151015- linenoiseEditMoveRight(&l);
10161016- break;
10171017- case CTRL_P: /* ctrl-p */
10181018- linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_PREV);
10191019- break;
10201020- case CTRL_R: /* ctrl-r */
10211021- linenoiseReverseIncrementalSearch(&l);
10221022- break;
10231023- case CTRL_N: /* ctrl-n */
10241024- linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_NEXT);
10251025- break;
10261026- case ESC: /* escape sequence */
10271027- /* Read the next byte representing the escape sequence */
10281028- if (read(l.ifd,seq,1) == -1) break;
10291029-10301030- /* alt-b, alt-f, alt-d, alt-backspace */
10311031- if (seq[0] == 'b') {
10321032- linenoiseEditMovePrevWord(&l);
10331033- break;
10341034- } else if (seq[0] == 'f') {
10351035- linenoiseEditMoveNextWord(&l);
10361036- break;
10371037- } else if (seq[0] == 'd') {
10381038- linenoiseEditDeleteNextWord(&l);
10391039- break;
10401040- } else if (seq[0] == 127) { /* backspace */
10411041- linenoiseEditDeletePrevWord(&l);
10421042- break;
10431043- }
10441044-10451045- /* Read a second byte */
10461046- if (read(l.ifd,seq+1,1) == -1) break;
10471047-10481048- /* ESC [ sequences. */
10491049- if (seq[0] == '[') {
10501050- if (seq[1] >= '0' && seq[1] <= '9') {
10511051- /* Extended escape, read additional byte. */
10521052- if (read(l.ifd,seq+2,1) == -1) break;
10531053- if (seq[2] == '~') {
10541054- switch(seq[1]) {
10551055- case '3': /* Delete key. */
10561056- linenoiseEditDelete(&l);
10571057- break;
10581058- }
10591059- } else if (seq[2] == ';') {
10601060- /* read additional 2 bytes */
10611061- if (read(l.ifd,seq+3,1) == -1) break;
10621062- if (read(l.ifd,seq+4,1) == -1) break;
10631063- if (seq[3] == '5') {
10641064- switch (seq[4]) {
10651065- case 'D': /* ctrl-left */
10661066- linenoiseEditMovePrevWord(&l);
10671067- break;
10681068- case 'C': /* ctrl-right */
10691069- linenoiseEditMoveNextWord(&l);
10701070- break;
10711071- }
10721072- }
10731073- }
10741074- } else {
10751075- switch(seq[1]) {
10761076- case 'A': /* Up */
10771077- linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_PREV);
10781078- break;
10791079- case 'B': /* Down */
10801080- linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_NEXT);
10811081- break;
10821082- case 'C': /* Right */
10831083- linenoiseEditMoveRight(&l);
10841084- break;
10851085- case 'D': /* Left */
10861086- linenoiseEditMoveLeft(&l);
10871087- break;
10881088- case 'H': /* Home */
10891089- linenoiseEditMoveHome(&l);
10901090- break;
10911091- case 'F': /* End*/
10921092- linenoiseEditMoveEnd(&l);
10931093- break;
10941094- }
10951095- }
10961096- }
10971097-10981098- /* ESC O sequences. */
10991099- else if (seq[0] == 'O') {
11001100- switch(seq[1]) {
11011101- case 'H': /* Home */
11021102- linenoiseEditMoveHome(&l);
11031103- break;
11041104- case 'F': /* End*/
11051105- linenoiseEditMoveEnd(&l);
11061106- break;
11071107- }
11081108- }
11091109- break;
11101110- default:
11111111- if (linenoiseEditInsert(&l,c)) return -1;
11121112- break;
11131113- case CTRL_U: /* Ctrl+u, delete the whole line. */
11141114- buf[0] = '\0';
11151115- l.pos = l.len = 0;
11161116- refreshLine(&l);
11171117- break;
11181118- case CTRL_K: /* Ctrl+k, delete from current to end of line. */
11191119- buf[l.pos] = '\0';
11201120- l.len = l.pos;
11211121- refreshLine(&l);
11221122- break;
11231123- case CTRL_A: /* Ctrl+a, go to the start of the line */
11241124- linenoiseEditMoveHome(&l);
11251125- break;
11261126- case CTRL_E: /* ctrl+e, go to the end of the line */
11271127- linenoiseEditMoveEnd(&l);
11281128- break;
11291129- case CTRL_L: /* ctrl+l, clear screen */
11301130- linenoiseClearScreen();
11311131- refreshLine(&l);
11321132- break;
11331133- case CTRL_W: /* ctrl+w, delete previous word */
11341134- linenoiseEditDeletePrevWord(&l);
11351135- break;
11361136- }
11371137- }
11381138- return l.len;
11391139-}
11401140-11411141-/* This special mode is used by linenoise in order to print scan codes
11421142- * on screen for debugging / development purposes. It is implemented
11431143- * by the linenoise_example program using the --keycodes option. */
11441144-void linenoisePrintKeyCodes(void) {
11451145- char quit[4];
11461146-11471147- printf("Linenoise key codes debugging mode.\n"
11481148- "Press keys to see scan codes. Type 'quit' at any time to exit.\n");
11491149- if (enableRawMode(STDIN_FILENO) == -1) return;
11501150- memset(quit,' ',4);
11511151- while(1) {
11521152- char c;
11531153- int nread;
11541154-11551155- nread = read(STDIN_FILENO,&c,1);
11561156- if (nread <= 0) continue;
11571157- memmove(quit,quit+1,sizeof(quit)-1); /* shift string to left. */
11581158- quit[sizeof(quit)-1] = c; /* Insert current char on the right. */
11591159- if (memcmp(quit,"quit",sizeof(quit)) == 0) break;
11601160-11611161- printf("'%c' %02x (%d) (type quit to exit)\n",
11621162- isprint(c) ? c : '?', (int)c, (int)c);
11631163- printf("\r"); /* Go left edge manually, we are in raw mode. */
11641164- fflush(stdout);
11651165- }
11661166- disableRawMode(STDIN_FILENO);
11671167-}
11681168-11691169-/* This function calls the line editing function linenoiseEdit() using
11701170- * the STDIN file descriptor set in raw mode. */
11711171-static int linenoiseRaw(char *buf, size_t buflen, const char *prompt) {
11721172- int count;
11731173-11741174- if (buflen == 0) {
11751175- errno = EINVAL;
11761176- return -1;
11771177- }
11781178-11791179- if (enableRawMode(STDIN_FILENO) == -1) return -1;
11801180- count = linenoiseEdit(STDIN_FILENO, STDOUT_FILENO, buf, buflen, prompt);
11811181- disableRawMode(STDIN_FILENO);
11821182- printf("\n");
11831183- return count;
11841184-}
11851185-11861186-/* This function is called when linenoise() is called with the standard
11871187- * input file descriptor not attached to a TTY. So for example when the
11881188- * program using linenoise is called in pipe or with a file redirected
11891189- * to its standard input. In this case, we want to be able to return the
11901190- * line regardless of its length (by default we are limited to 4k). */
11911191-static char *linenoiseNoTTY(void) {
11921192- char *line = NULL;
11931193- size_t len = 0, maxlen = 0;
11941194-11951195- while(1) {
11961196- if (len == maxlen) {
11971197- if (maxlen == 0) maxlen = 16;
11981198- maxlen *= 2;
11991199- char *oldval = line;
12001200- line = realloc(line,maxlen);
12011201- if (line == NULL) {
12021202- if (oldval) free(oldval);
12031203- return NULL;
12041204- }
12051205- }
12061206- int c = fgetc(stdin);
12071207- if (c == EOF || c == '\n') {
12081208- if (c == EOF && len == 0) {
12091209- free(line);
12101210- return NULL;
12111211- } else {
12121212- line[len] = '\0';
12131213- return line;
12141214- }
12151215- } else {
12161216- line[len] = c;
12171217- len++;
12181218- }
12191219- }
12201220-}
12211221-12221222-/* The high level function that is the main API of the linenoise library.
12231223- * This function checks if the terminal has basic capabilities, just checking
12241224- * for a blacklist of stupid terminals, and later either calls the line
12251225- * editing function or uses dummy fgets() so that you will be able to type
12261226- * something even in the most desperate of the conditions. */
12271227-char *linenoise(const char *prompt) {
12281228- char buf[LINENOISE_MAX_LINE];
12291229- int count;
12301230-12311231- if (!isatty(STDIN_FILENO)) {
12321232- /* Not a tty: read from file / pipe. In this mode we don't want any
12331233- * limit to the line size, so we call a function to handle that. */
12341234- return linenoiseNoTTY();
12351235- } else if (isUnsupportedTerm()) {
12361236- size_t len;
12371237-12381238- printf("%s",prompt);
12391239- fflush(stdout);
12401240- if (fgets(buf,LINENOISE_MAX_LINE,stdin) == NULL) return NULL;
12411241- len = strlen(buf);
12421242- while(len && (buf[len-1] == '\n' || buf[len-1] == '\r')) {
12431243- len--;
12441244- buf[len] = '\0';
12451245- }
12461246- return strdup(buf);
12471247- } else {
12481248- count = linenoiseRaw(buf,LINENOISE_MAX_LINE,prompt);
12491249- if (count == -1) return NULL;
12501250- return strdup(buf);
12511251- }
12521252-}
12531253-12541254-/* This is just a wrapper the user may want to call in order to make sure
12551255- * the linenoise returned buffer is freed with the same allocator it was
12561256- * created with. Useful when the main program is using an alternative
12571257- * allocator. */
12581258-void linenoiseFree(void *ptr) {
12591259- free(ptr);
12601260-}
12611261-12621262-/* ================================ History ================================= */
12631263-12641264-/* Free the history, but does not reset it. Only used when we have to
12651265- * exit() to avoid memory leaks are reported by valgrind & co. */
12661266-static void freeHistory(void) {
12671267- if (history) {
12681268- int j;
12691269-12701270- for (j = 0; j < history_len; j++)
12711271- free(history[j]);
12721272- free(history);
12731273- }
12741274-}
12751275-12761276-/* At exit we'll try to fix the terminal to the initial conditions. */
12771277-static void linenoiseAtExit(void) {
12781278- disableRawMode(STDIN_FILENO);
12791279- freeHistory();
12801280-}
12811281-12821282-/* This is the API call to add a new entry in the linenoise history.
12831283- * It uses a fixed array of char pointers that are shifted (memmoved)
12841284- * when the history max length is reached in order to remove the older
12851285- * entry and make room for the new one, so it is not exactly suitable for huge
12861286- * histories, but will work well for a few hundred of entries.
12871287- *
12881288- * Using a circular buffer is smarter, but a bit more complex to handle. */
12891289-int linenoiseHistoryAdd(const char *line) {
12901290- char *linecopy;
12911291-12921292- if (history_max_len == 0) return 0;
12931293-12941294- /* Initialization on first call. */
12951295- if (history == NULL) {
12961296- history = malloc(sizeof(char*)*history_max_len);
12971297- if (history == NULL) return 0;
12981298- memset(history,0,(sizeof(char*)*history_max_len));
12991299- }
13001300-13011301- /* Don't add duplicated lines. */
13021302- if (history_len && !strcmp(history[history_len-1], line)) return 0;
13031303-13041304- /* Add an heap allocated copy of the line in the history.
13051305- * If we reached the max length, remove the older line. */
13061306- linecopy = strdup(line);
13071307- if (!linecopy) return 0;
13081308- if (history_len == history_max_len) {
13091309- free(history[0]);
13101310- memmove(history,history+1,sizeof(char*)*(history_max_len-1));
13111311- history_len--;
13121312- }
13131313- history[history_len] = linecopy;
13141314- history_len++;
13151315- return 1;
13161316-}
13171317-13181318-/* Set the maximum length for the history. This function can be called even
13191319- * if there is already some history, the function will make sure to retain
13201320- * just the latest 'len' elements if the new history length value is smaller
13211321- * than the amount of items already inside the history. */
13221322-int linenoiseHistorySetMaxLen(int len) {
13231323- char **new;
13241324-13251325- if (len < 1) return 0;
13261326- if (history) {
13271327- int tocopy = history_len;
13281328-13291329- new = malloc(sizeof(char*)*len);
13301330- if (new == NULL) return 0;
13311331-13321332- /* If we can't copy everything, free the elements we'll not use. */
13331333- if (len < tocopy) {
13341334- int j;
13351335-13361336- for (j = 0; j < tocopy-len; j++) free(history[j]);
13371337- tocopy = len;
13381338- }
13391339- memset(new,0,sizeof(char*)*len);
13401340- memcpy(new,history+(history_len-tocopy), sizeof(char*)*tocopy);
13411341- free(history);
13421342- history = new;
13431343- }
13441344- history_max_len = len;
13451345- if (history_len > history_max_len)
13461346- history_len = history_max_len;
13471347- return 1;
13481348-}
13491349-13501350-/* Save the history in the specified file. On success 0 is returned
13511351- * otherwise -1 is returned. */
13521352-int linenoiseHistorySave(const char *filename) {
13531353- mode_t old_umask = umask(S_IXUSR|S_IRWXG|S_IRWXO);
13541354- FILE *fp;
13551355- int j;
13561356-13571357- fp = fopen(filename,"w");
13581358- umask(old_umask);
13591359- if (fp == NULL) return -1;
13601360- chmod(filename,S_IRUSR|S_IWUSR);
13611361- for (j = 0; j < history_len; j++)
13621362- fprintf(fp,"%s\n",history[j]);
13631363- fclose(fp);
13641364- return 0;
13651365-}
13661366-13671367-/* Load the history from the specified file. If the file does not exist
13681368- * zero is returned and no operation is performed.
13691369- *
13701370- * If the file exists and the operation succeeded 0 is returned, otherwise
13711371- * on error -1 is returned. */
13721372-int linenoiseHistoryLoad(const char *filename) {
13731373- FILE *fp = fopen(filename,"r");
13741374- char buf[LINENOISE_MAX_LINE];
13751375-13761376- if (fp == NULL) return -1;
13771377-13781378- while (fgets(buf,LINENOISE_MAX_LINE,fp) != NULL) {
13791379- char *p;
13801380-13811381- p = strchr(buf,'\r');
13821382- if (!p) p = strchr(buf,'\n');
13831383- if (p) *p = '\0';
13841384- linenoiseHistoryAdd(buf);
13851385- }
13861386- fclose(fp);
13871387- return 0;
13881388-}
-75
vendor/ocaml-linenoise/src/linenoise_src.h
···11-/* linenoise.h -- VERSION 1.0
22- *
33- * Guerrilla line editing library against the idea that a line editing lib
44- * needs to be 20,000 lines of C code.
55- *
66- * See linenoise.c for more information.
77- *
88- * ------------------------------------------------------------------------
99- *
1010- * Copyright (c) 2010-2014, Salvatore Sanfilippo <antirez at gmail dot com>
1111- * Copyright (c) 2010-2013, Pieter Noordhuis <pcnoordhuis at gmail dot com>
1212- *
1313- * All rights reserved.
1414- *
1515- * Redistribution and use in source and binary forms, with or without
1616- * modification, are permitted provided that the following conditions are
1717- * met:
1818- *
1919- * * Redistributions of source code must retain the above copyright
2020- * notice, this list of conditions and the following disclaimer.
2121- *
2222- * * Redistributions in binary form must reproduce the above copyright
2323- * notice, this list of conditions and the following disclaimer in the
2424- * documentation and/or other materials provided with the distribution.
2525- *
2626- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2727- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2828- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2929- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
3030- * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
3131- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3232- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3333- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3434- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3535- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3636- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3737- */
3838-3939-#ifndef __LINENOISE_H
4040-#define __LINENOISE_H
4141-4242-#ifdef __cplusplus
4343-extern "C" {
4444-#endif
4545-4646-extern int linenoiseWasInterrupted; /* boolean signalling if last call was ctrl-c */
4747-4848-typedef struct linenoiseCompletions {
4949- size_t len;
5050- char **cvec;
5151-} linenoiseCompletions;
5252-5353-typedef void(linenoiseCompletionCallback)(const char *, linenoiseCompletions *);
5454-typedef char*(linenoiseHintsCallback)(const char *, int *color, int *bold);
5555-typedef void(linenoiseFreeHintsCallback)(void *);
5656-void linenoiseSetCompletionCallback(linenoiseCompletionCallback *);
5757-void linenoiseSetHintsCallback(linenoiseHintsCallback *);
5858-void linenoiseSetFreeHintsCallback(linenoiseFreeHintsCallback *);
5959-void linenoiseAddCompletion(linenoiseCompletions *, const char *);
6060-6161-char *linenoise(const char *prompt);
6262-void linenoiseFree(void *ptr);
6363-int linenoiseHistoryAdd(const char *line);
6464-int linenoiseHistorySetMaxLen(int len);
6565-int linenoiseHistorySave(const char *filename);
6666-int linenoiseHistoryLoad(const char *filename);
6767-void linenoiseClearScreen(void);
6868-void linenoiseSetMultiLine(int ml);
6969-void linenoisePrintKeyCodes(void);
7070-7171-#ifdef __cplusplus
7272-}
7373-#endif
7474-7575-#endif /* __LINENOISE_H */
···11-/* encodings/utf8.h -- VERSION 1.0
22- *
33- * Guerrilla line editing library against the idea that a line editing lib
44- * needs to be 20,000 lines of C code.
55- *
66- * See linenoise.c for more information.
77- *
88- * ------------------------------------------------------------------------
99- *
1010- * Copyright (c) 2010-2014, Salvatore Sanfilippo <antirez at gmail dot com>
1111- * Copyright (c) 2010-2013, Pieter Noordhuis <pcnoordhuis at gmail dot com>
1212- *
1313- * All rights reserved.
1414- *
1515- * Redistribution and use in source and binary forms, with or without
1616- * modification, are permitted provided that the following conditions are
1717- * met:
1818- *
1919- * * Redistributions of source code must retain the above copyright
2020- * notice, this list of conditions and the following disclaimer.
2121- *
2222- * * Redistributions in binary form must reproduce the above copyright
2323- * notice, this list of conditions and the following disclaimer in the
2424- * documentation and/or other materials provided with the distribution.
2525- *
2626- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2727- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2828- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2929- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
3030- * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
3131- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3232- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3333- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3434- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3535- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3636- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3737- */
3838-3939-#ifndef __LINENOISE_ENCODINGS_UTF8_H
4040-#define __LINENOISE_ENCODINGS_UTF8_H
4141-4242-#ifdef __cplusplus
4343-extern "C" {
4444-#endif
4545-4646-size_t linenoiseUtf8PrevCharLen(const char* buf, size_t buf_len, size_t pos, size_t *col_len);
4747-size_t linenoiseUtf8NextCharLen(const char* buf, size_t buf_len, size_t pos, size_t *col_len);
4848-size_t linenoiseUtf8ReadCode(int fd, char* buf, size_t buf_len, int* cp);
4949-5050-#ifdef __cplusplus
5151-}
5252-#endif
5353-5454-#endif /* __LINENOISE_ENCODINGS_UTF8_H */
5555-