1 /*
2  * Arcan Text-Oriented User Interface Library, Extensions
3  * Copyright: 2019-2020, Bjorn Stahl
4  * License: 3-clause BSD
5  */
6 
7 #ifndef HAVE_TUI_READLINE
8 #define HAVE_TUI_READLINE
9 
10 #ifndef ARCAN_TUI_DYNAMIC
11 /*
12  * Description:
13  * This function partially assumes control over a provided window in
14  * order to provide libreadline/liblinenoise like input capabilities.
15  *
16  * Handlers/Allocations:
17  * This function chains/forwards all event handlers.
18  *
19  * Example:
20  * see the #ifdef EXAMPLE block at the bottom of tui_readline.c
21  */
22 
23 struct tui_readline_opts {
24  /*-n from bottom of context, clamps to window size
25  *  0 don't care, manually position with arcan_tui_readline_region
26  *  n from top of context, clamps to window size */
27 	ssize_t anchor_row;
28 	size_t n_rows;
29 	size_t margin_left;
30 	size_t margin_right;
31 
32 /* mouse clicks outside the input region or escape will have the _finished
33  * status marked as true and cursor moved to the click- point (mouse) or region
34  * start (escape) with no message result */
35 	bool allow_exit;
36 
37 /* provide to suggest an auto-completion string
38  *
39  * set [result] to point to the completion (if one exists)
40  *     you retain overship of [result] and is expected to be alive until
41  *     the context is released or the next call to autocomplete, the last
42  *     pointer will be provided in return.
43  *
44  * return true if [result] was set.
45  */
46 	bool (*autocomplete)(const char* message,
47 	                     const char** result, const char* last, void* T);
48 
49 /* Provide a way to mask out certain inputs or length (e.g. input that only
50  * accepts visible 7-bit set) or only allowing n- characters.
51  *
52  * Return true of the character is allowed to be added to the input buffer.
53  * Note that the codepoint is expressed in UCS-4 rather than UTF-8.
54  */
55 	bool (*filter_character)(uint32_t, size_t length, void* T);
56 
57 /* set a character that will be drawn in place of the real buffer, this
58  * is useful for password prompt like inputs */
59 	uint32_t mask_character;
60 
61 /* line-feeds are accepted into the buffer, and empty */
62 	bool multiline;
63 
64 /* check the contents (utf-8, NUL terminated) of [message].
65  * return -1 on success or the buffer offset where the content failed */
66 	ssize_t (*verify)(const char* message, void* T);
67 
68 /* based on [message] return a sorted list of possible candidates in [set]
69  * and the number of elements as function return value */
70 	size_t (*suggest)(const char* message, const char** set, void* T);
71 };
72 
73 void arcan_tui_readline_setup(
74 	struct tui_context*, struct tui_readline_opts*, size_t opt_sz);
75 
76 /* set the active history buffer that the user can navigate, the caller retains
77  * ownership and the contents are assumed to be valid until _readline_release
78  * has been called or replaced with another buffer */
79 void arcan_tui_readline_history(struct tui_context*, const char**, size_t count);
80 
81 /*
82  * Set prefix/prompt that will be drawn
83  * (assuming there is enough space for it to fit, or it will be drawn truncated).
84  *
85  * Ownership:
86  * Caller retains ownership of prompt, callee retains a refrence that may be used
87  * until next call to set_prompt or release on the tui context.
88  *
89  * Note:
90  * If the prompt uses custom coloring, set_prompt should be called again on recolor.
91  *
92  * Note:
93  * The length of prompt is NUL terminated based on the .ch field.
94  */
95 void arcan_tui_set_prompt(struct tui_context* T, const struct tui_cell* prompt);
96 
97 /*
98  * Restore event handler table and cancel any input operation
99  */
100 void arcan_tui_readline_release(struct tui_context*);
101 
102 /*
103  * Call as part of normal processing loop to retrieve a reference to the
104  * current input buffer.
105  *
106  * This buffer reference stored in [buffer(!=NULL)] is valid until the next
107  * readline_release, _finished or tui_refresh on the context.
108  *
109  * Values returned are from the set shwon in enum tui_readline_status
110  */
111 enum tui_readline_status {
112 	READLINE_STATUS_TERMINATE = -2,
113 	READLINE_STATUS_CANCELLED = -1,
114 	READLINE_STATUS_EDITED = 0,
115 	READLINE_STATUS_DONE = 1,
116 };
117 int arcan_tui_readline_finished(struct tui_context*, char** buffer);
118 
119 /*
120  * Clear input buffer state (similar to C-l)
121  */
122 void arcan_tui_readline_reset(struct tui_context*);
123 
124 #else
125 typedef bool(* PTUIRL_SETUP)(
126 	struct tui_context*, struct tui_readline_opts*, size_t opt_sz);
127 typedef bool(* PTUIRL_FINISHED)(struct tui_context*, char** buffer);
128 typedef void(* PTUIRL_RESET)(struct tui_context*);
129 typedef void(* PTUIRL_HISTORY)(struct tui_context*, const char**, size_t);
130 typedef void(* PTUIRL_PROMPT)(struct tui_context*, const struct tui_cell*);
131 
132 static PTUIRL_SETUP arcan_tui_readline_setup;
133 static PTUIRL_FINISHED arcan_tui_readline_finished;
134 static PTUIRL_RESET arcan_tui_readline_reset;
135 static PTUIRL_HISTORY arcan_tui_readline_history;
136 static PTUIRL_PROMPT arcan_tui_readline_prompt;
137 
arcan_tui_readline_dynload(void * (* lookup)(void *,const char *),void * tag)138 static bool arcan_tui_readline_dynload(
139 	void*(*lookup)(void*, const char*), void* tag)
140 {
141 #define M(TYPE, SYM) if (! (SYM = (TYPE) lookup(tag, #SYM)) ) return false
142 M(PTUIRL_SETUP, arcan_tui_readline_setup);
143 M(PTUIRL_FINISHED, arcan_tui_readline_finished);
144 M(PTUIRL_RESET, arcan_tui_readline_reset);
145 M(PTUIRL_HISTORY, arcan_tui_readline_history);
146 M(PTUIRL_PROMPT, arcan_tui_readline_prompt);
147 #undef M
148 }
149 
150 #endif
151 #endif
152