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