1 /*******************************************************************************
2 
3     A D wrapper around the GNU readline/readline file
4 
5     readline is a powerful library for reading the user input from the console.
6 
7     For example if an application frequently asks for user-input during its
8     operation then using readline provides the following benefits:
9        - User can browse previous submitted lines using up/down arrows.
10        - Terminal shortcuts (e.g ctrl+r, ctrl+w, ctrl+y) are enabled by default.
11        - Providing text auto-completion, by default it is enabled to complete
12          files and directories for the path that the application was run from.
13        - Make the application use the customized configuration that the user
14          defined for readline on his machine.
15 
16     There are much more functionalities that the readline library provides.
17     Please refer to the documentation for the more information:
18         - http://cnswww.cns.cwru.edu/php/chet/readline/rltop.html
19 
20     Notes:
21         Requires linking with -lreadline
22 
23     Copyright:
24         Copyright (c) 2009-2016 dunnhumby Germany GmbH.
25         All rights reserved.
26 
27     License:
28         Boost Software License Version 1.0. See LICENSE_BOOST.txt for details.
29         Alternatively, this file may be distributed under the terms of the Tango
30         3-Clause BSD License (see LICENSE_BSD.txt for details).
31 
32         Bear in mind this module provides bindings to an external library that
33         has its own license, which might be more restrictive. Please check the
34         external library license to see which conditions apply for linking.
35 
36 *******************************************************************************/
37 
38 module ocean.io.console.readline.Readline;
39 
40 
41 import C = ocean.io.console.readline.c.readline;
42 import ocean.core.Array : copy;
43 import ocean.text.util.StringC;
44 
45 import core.stdc.string: strlen;
46 import core.stdc.stdlib : free;
47 
48 import ocean.meta.types.Qualifiers;
49 
50 /*******************************************************************************
51 
52     Reads a line from the terminal and return it, using prompt as a prompt.
53     If prompt is NULL or the empty string, no prompt is issued.
54     The line returned has the final newline removed, so only the text of the
55     line remains.
56 
57     Except for the note below, the documentation is taken from the manpage of
58     readline. Refer to the readline manpage for more extensive documentation.
59 
60     Note:
61         If prompt isn't null-terminated and isn't null then it's converted to a
62         C null-terminated string before passing it to the C readline function.
63         Converting to C string might re-allocate the buffer. If you have tight
64         memory constraints, it is highly recommended to provide a null
65         terminated string or make sure that the GC block your buffer is stored
66         in has a spare byte at the end.
67 
68     Params:
69         prompt = the string to be prompted to the user (see note above)
70         buffer = optional buffer to store the user input, if the buffer is null
71         then it would be allocated only if the user provided an input.
72 
73     Returns:
74         Returns the text of the line read. A blank line returns empty string.
75         If EOF is encountered while reading a line, and the line is empty, null
76         is returned.  If an EOF  is  read  with  a non-empty line, it is treated
77         as a newline.
78 
79 *******************************************************************************/
80 
81 mstring readline(ref mstring prompt, ref mstring buffer)
82 {
83     char* prompt_ptr = null;
84     if (prompt != null)
85     {
86         prompt_ptr = StringC.toCString( prompt );
87     }
88 
89     char* c_buf = C.readline(prompt_ptr);
90     scope (exit) free(c_buf);
91     if (c_buf is null)
92     {
93         return null;
94     }
95 
96     auto c_buf_len = strlen(c_buf);
97     if (buffer is null && c_buf_len == 0)
98     {
99         buffer.length = 1; //Allocate the pointer so we wouldn't return null
100     }
101     buffer.copy( c_buf[0..c_buf_len] );
102     return buffer;
103 }
104 
105 /*******************************************************************************
106 
107     Function signature for functions used with the rl_bind_key functions and
108     various other functions.
109 
110 *******************************************************************************/
111 
112 alias C.rl_command_func_t CommandFunc;
113 
114 /*******************************************************************************
115 
116     Bind a keyboard key to a function.
117 
118     The function will be called when the user is prompted for input and he
119     presses the bound key.
120 
121     Note that by default the tab key is bound to auto-complete the file names
122     that exist in the directory the application was run from. To disable this
123     bind the tab key with the abort function defined in this module:
124         bindKey('\t', abort);
125 
126     Params:
127         key = ASCII int value of the key to be bound
128         func = the func triggered when they key is pressed
129 
130 *******************************************************************************/
131 
132 void bindKey(char key, CommandFunc* func)
133 {
134     C.rl_bind_key(cast(int)key, func);
135 }
136 
137 /*******************************************************************************
138 
139     Completion functions to be used with key bindings
140 
141 *******************************************************************************/
142 
143 alias C.rl_abort abort; // Binds a key do nothing (even not write itself)
144 alias C.rl_insert insert; // Binds a key to just write itself