NeoMutt  2023-11-03-85-g512e01
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
window.c
Go to the documentation of this file.
1
30#include "config.h"
31#include <stddef.h>
32#include <stdbool.h>
33#include <string.h>
34#include <wchar.h>
35#include "mutt/lib.h"
36#include "core/lib.h"
37#include "gui/lib.h"
38#include "mutt.h"
39#include "color/lib.h"
40#include "complete/lib.h"
41#include "history/lib.h"
42#include "key/lib.h"
43#include "menu/lib.h"
44#include "functions.h"
45#include "muttlib.h"
46#include "state.h"
47#include "wdata.h"
48
50static const struct Mapping EditorHelp[] = {
51 // clang-format off
52 { N_("Help"), OP_HELP },
53 { N_("Complete"), OP_EDITOR_COMPLETE },
54 { N_("Hist Up"), OP_EDITOR_HISTORY_UP },
55 { N_("Hist Down"), OP_EDITOR_HISTORY_DOWN },
56 { N_("Hist Search"), OP_EDITOR_HISTORY_SEARCH },
57 { N_("Begin Line"), OP_EDITOR_BOL },
58 { N_("End Line"), OP_EDITOR_EOL },
59 { N_("Kill Line"), OP_EDITOR_KILL_LINE },
60 { N_("Kill Word"), OP_EDITOR_KILL_WORD },
61 { NULL, 0 },
62 // clang-format on
63};
64
72static int my_addwch(struct MuttWindow *win, wchar_t wc)
73{
74 int n = wcwidth(wc);
75 if (IsWPrint(wc) && (n > 0))
76 return mutt_addwch(win, wc);
77 if (!(wc & ~0x7f))
78 return mutt_window_printf(win, "^%c", ((int) wc + 0x40) & 0x7f);
79 if (!(wc & ~0xffff))
80 return mutt_window_printf(win, "\\u%04x", (int) wc);
81 return mutt_window_printf(win, "\\u%08x", (int) wc);
82}
83
90bool self_insert(struct EnterWindowData *wdata, int ch)
91{
92 if (!wdata)
93 return true;
94
95 wdata->tabs = 0;
96 wchar_t wc = 0;
97
98 /* quietly ignore all other function keys */
99 if (ch & ~0xff)
100 return false;
101
102 /* gather the bytes into a wide character */
103 {
104 char c = ch;
105 size_t k = mbrtowc(&wc, &c, 1, wdata->mbstate);
106 if (k == ICONV_BUF_TOO_SMALL)
107 {
108 return false;
109 }
110 else if ((k != 0) && (k != 1))
111 {
112 memset(wdata->mbstate, 0, sizeof(*wdata->mbstate));
113 return false;
114 }
115 }
116
117 if (wdata->first && (wdata->flags & MUTT_COMP_CLEAR))
118 {
119 wdata->first = false;
120 if (IsWPrint(wc)) /* why? */
121 {
122 wdata->state->curpos = 0;
123 wdata->state->lastchar = 0;
124 }
125 }
126
127 if ((wc == '\r') || (wc == '\n'))
128 {
129 /* Convert from wide characters */
130 buf_mb_wcstombs(wdata->buffer, wdata->state->wbuf, wdata->state->lastchar);
131 if (!wdata->pass)
132 mutt_hist_add(wdata->hclass, buf_string(wdata->buffer), true);
133
134 if (wdata->cdata)
135 {
136 struct FileCompletionData *cdata = wdata->cdata;
137 if (cdata->multiple)
138 {
139 char **tfiles = NULL;
140 *cdata->numfiles = 1;
141 tfiles = mutt_mem_calloc(*cdata->numfiles, sizeof(char *));
142 buf_expand_path_regex(wdata->buffer, false);
143 tfiles[0] = buf_strdup(wdata->buffer);
144 *cdata->files = tfiles;
145 }
146 }
147 return true;
148 }
149 else if (wc && ((wc < ' ') || IsWPrint(wc))) /* why? */
150 {
151 if (wdata->state->lastchar >= wdata->state->wbuflen)
152 {
153 wdata->state->wbuflen = wdata->state->lastchar + 20;
154 mutt_mem_realloc(&wdata->state->wbuf, wdata->state->wbuflen * sizeof(wchar_t));
155 }
156 memmove(wdata->state->wbuf + wdata->state->curpos + 1,
157 wdata->state->wbuf + wdata->state->curpos,
158 (wdata->state->lastchar - wdata->state->curpos) * sizeof(wchar_t));
159 wdata->state->wbuf[wdata->state->curpos++] = wc;
160 wdata->state->lastchar++;
161 }
162 else
163 {
165 mutt_beep(false);
166 }
167
168 return false;
169}
170
176static int enter_recalc(struct MuttWindow *win)
177{
178 win->actions |= WA_REPAINT;
179 mutt_debug(LL_DEBUG5, "recalc done, request WA_REPAINT\n");
180
181 return 0;
182}
183
187static int enter_repaint(struct MuttWindow *win)
188{
189 if (!mutt_window_is_visible(win))
190 return 0;
191
192 struct EnterWindowData *wdata = win->wdata;
193
194 mutt_window_clearline(win, 0);
196 mutt_window_addstr(win, wdata->prompt);
198
199 int prompt_length = 0;
200 mutt_window_get_coords(win, &prompt_length, NULL);
201
202 int width = win->state.cols - prompt_length - 1;
203
204 if (!wdata->pass)
205 {
206 if (wdata->redraw == ENTER_REDRAW_INIT)
207 {
208 /* Go to end of line */
209 wdata->state->curpos = wdata->state->lastchar;
211 wdata->state->wbuf, wdata->state->lastchar,
212 mutt_mb_wcswidth(wdata->state->wbuf, wdata->state->lastchar) - width + 1);
213 }
214 if ((wdata->state->curpos < wdata->state->begin) ||
215 (mutt_mb_wcswidth(wdata->state->wbuf + wdata->state->begin,
216 wdata->state->curpos - wdata->state->begin) >= width))
217 {
219 wdata->state->wbuf, wdata->state->lastchar,
220 mutt_mb_wcswidth(wdata->state->wbuf, wdata->state->curpos) - (width / 2));
221 }
222 mutt_window_move(win, prompt_length, 0);
223 int w = 0;
224 for (size_t i = wdata->state->begin; i < wdata->state->lastchar; i++)
225 {
226 w += mutt_mb_wcwidth(wdata->state->wbuf[i]);
227 if (w > width)
228 break;
229 my_addwch(win, wdata->state->wbuf[i]);
230 }
233 prompt_length +
234 mutt_mb_wcswidth(wdata->state->wbuf + wdata->state->begin,
235 wdata->state->curpos - wdata->state->begin),
236 0);
237 }
238
239 mutt_window_get_coords(win, &wdata->col, &wdata->row);
240 mutt_debug(LL_DEBUG5, "repaint done\n");
241
242 return 0;
243}
244
248static bool enter_recursor(struct MuttWindow *win)
249{
250 struct EnterWindowData *wdata = win->wdata;
251 mutt_window_move(win, wdata->col, wdata->row);
253 return true;
254}
255
275int mw_get_field(const char *prompt, struct Buffer *buf, CompletionFlags complete,
276 enum HistoryClass hclass, const struct CompleteOps *comp_api, void *cdata)
277{
280
282 if (complete & MUTT_COMP_UNBUFFERED)
283 flags = GETCH_IGNORE_MACRO;
284
285 int rc = 0;
286
287 struct EnterState *es = enter_state_new();
288
289 win->help_data = EditorHelp;
290 win->help_menu = MENU_EDITOR;
291
293 struct MuttWindow *old_focus = window_set_focus(win);
294
295 mbstate_t mbstate = { 0 };
296 // clang-format off
297 struct EnterWindowData wdata = { buf, complete, es, hclass, comp_api, cdata, prompt, ENTER_REDRAW_NONE, (complete & MUTT_COMP_PASS), true, NULL, 0, &mbstate, 0, false, NULL, 0, 0 };
298 // clang-format on
299
300 win->wdata = &wdata;
301 win->wdata_free = NULL; // No need, we hold the data
302 win->actions |= WA_RECALC;
303 win->recalc = enter_recalc;
304 win->repaint = enter_repaint;
306
307 window_redraw(win);
308
309 if (es->wbuf[0] == L'\0')
310 {
311 /* Initialise wbuf from buf */
312 wdata.state->wbuflen = 0;
313 wdata.state->lastchar = mutt_mb_mbstowcs(&wdata.state->wbuf, &wdata.state->wbuflen,
314 0, buf_string(wdata.buffer));
316 }
317 else
318 {
320 wdata.first = false;
321 }
322
323 do
324 {
325 memset(&mbstate, 0, sizeof(mbstate));
326
327 do
328 {
329 if (wdata.redraw != ENTER_REDRAW_NONE)
330 win->actions |= WA_REPAINT;
331
332 window_redraw(NULL);
333 struct KeyEvent event = km_dokey_event(MENU_EDITOR, flags);
334 if ((event.op == OP_TIMEOUT) || (event.op == OP_REPAINT))
335 {
336 continue;
337 }
338
339 if (event.op == OP_ABORT)
340 {
341 rc = -1;
342 goto bye;
343 }
344
345 if (event.op == OP_NULL)
346 {
347 if (complete & MUTT_COMP_PASS)
348 mutt_debug(LL_DEBUG5, "Got char *\n");
349 else
350 mutt_debug(LL_DEBUG5, "Got char %c (0x%02x)\n", event.ch, event.ch);
351
352 if (self_insert(&wdata, event.ch))
353 {
354 rc = 0;
355 goto bye;
356 }
357 win->actions |= WA_REPAINT;
358 continue;
359 }
360 else
361 {
362 mutt_debug(LL_DEBUG1, "Got op %s (%d)\n", opcodes_get_name(event.op),
363 event.op);
364 }
365
366 wdata.first = false;
367 if ((event.op != OP_EDITOR_COMPLETE) && (event.op != OP_EDITOR_COMPLETE_QUERY))
368 wdata.tabs = 0;
370 int rc_disp = enter_function_dispatcher(win, event.op);
371 switch (rc_disp)
372 {
373 case FR_NO_ACTION:
374 {
375 if (self_insert(&wdata, event.ch))
376 {
377 rc = 0;
378 goto bye;
379 }
380 break;
381 }
382 case FR_CONTINUE: // repaint
383 rc = 1;
384 goto bye;
385
386 case FR_SUCCESS:
387 break;
388
389 case FR_UNKNOWN:
390 case FR_ERROR:
391 default:
392 mutt_beep(false);
393 }
394 } while (!wdata.done);
395
396 bye:
398 FREE(&wdata.tempbuf);
399 completion_data_free(&wdata.cd);
400 } while (rc == 1);
401
403 window_set_focus(old_focus);
404 mutt_window_free(&win);
405
406 if (rc == 0)
407 buf_fix_dptr(buf);
408 else
409 buf_reset(buf);
410
411 enter_state_free(&es);
412
413 return rc;
414}
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:88
void buf_fix_dptr(struct Buffer *buf)
Move the dptr to end of the Buffer.
Definition: buffer.c:194
char * buf_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition: buffer.c:542
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:93
Color and attribute parsing.
@ MT_COLOR_NORMAL
Plain text.
Definition: color.h:58
@ MT_COLOR_PROMPT
Question/user input.
Definition: color.h:61
Auto-completion.
Convenience wrapper for the core headers.
int mutt_addwch(struct MuttWindow *win, wchar_t wc)
Addwch would be provided by an up-to-date curses library.
Definition: curs_lib.c:329
void mutt_beep(bool force)
Irritate the user.
Definition: curs_lib.c:65
void mutt_flushinp(void)
Empty all the keyboard buffers.
Definition: get.c:57
void completion_data_free(struct CompletionData **ptr)
Free the Completion Data.
Definition: data.c:53
@ FR_SUCCESS
Valid function - successfully performed.
Definition: dispatcher.h:39
@ FR_UNKNOWN
Unknown function.
Definition: dispatcher.h:33
@ FR_ERROR
Valid function - error occurred.
Definition: dispatcher.h:38
@ FR_CONTINUE
Remain in the Dialog.
Definition: dispatcher.h:34
@ FR_NO_ACTION
Valid function - no action performed.
Definition: dispatcher.h:37
struct EnterState * enter_state_new(void)
Create a new EnterState.
Definition: state.c:74
void enter_state_free(struct EnterState **ptr)
Free an EnterState.
Definition: state.c:38
@ ENTER_REDRAW_NONE
Nothing to redraw.
Definition: wdata.h:37
@ ENTER_REDRAW_LINE
Redraw entire line.
Definition: wdata.h:39
@ ENTER_REDRAW_INIT
Go to end of line and redraw.
Definition: wdata.h:38
static const struct Mapping EditorHelp[]
Help Bar for the Command Line Editor.
Definition: window.c:50
static int my_addwch(struct MuttWindow *win, wchar_t wc)
Display one wide character on screen.
Definition: window.c:72
bool self_insert(struct EnterWindowData *wdata, int ch)
Insert a normal character.
Definition: window.c:90
struct KeyEvent km_dokey_event(enum MenuType mtype, GetChFlags flags)
Determine what a keypress should do.
Definition: get.c:357
int enter_function_dispatcher(struct MuttWindow *win, int op)
Perform an Enter function - Implements function_dispatcher_t -.
Definition: functions.c:482
int mw_get_field(const char *prompt, struct Buffer *buf, CompletionFlags complete, enum HistoryClass hclass, const struct CompleteOps *comp_api, void *cdata)
Ask the user for a string -.
Definition: window.c:275
#define mutt_debug(LEVEL,...)
Definition: logging2.h:89
static int enter_recalc(struct MuttWindow *win)
Recalculate the Window data - Implements MuttWindow::recalc() -.
Definition: window.c:176
static bool enter_recursor(struct MuttWindow *win)
Recursor the Window - Implements MuttWindow::recursor() -.
Definition: window.c:248
static int enter_repaint(struct MuttWindow *win)
Repaint the Window - Implements MuttWindow::repaint() -.
Definition: window.c:187
Convenience wrapper for the gui headers.
Read/write command history from/to a file.
HistoryClass
Type to differentiate different histories.
Definition: lib.h:50
void mutt_hist_add(enum HistoryClass hclass, const char *str, bool save)
Add a string to a history.
Definition: history.c:485
void mutt_hist_reset_state(enum HistoryClass hclass)
Move the 'current' position to the end of the History.
Definition: history.c:581
Manage keymappings.
uint8_t GetChFlags
Flags for mutt_getch(), e.g. GETCH_NO_FLAGS.
Definition: lib.h:51
#define GETCH_IGNORE_MACRO
Don't use MacroEvents.
Definition: lib.h:53
#define GETCH_NO_FLAGS
No flags are set.
Definition: lib.h:52
@ LL_DEBUG5
Log at debug level 5.
Definition: logging2.h:47
@ LL_DEBUG1
Log at debug level 1.
Definition: logging2.h:43
size_t mutt_mb_width_ceiling(const wchar_t *s, size_t n, int w1)
Keep the end of the string on-screen.
Definition: mbyte.c:236
size_t mutt_mb_mbstowcs(wchar_t **pwbuf, size_t *pwbuflen, size_t i, const char *buf)
Convert a string from multibyte to wide characters.
Definition: mbyte.c:290
int mutt_mb_wcswidth(const wchar_t *s, size_t n)
Measure the screen width of a string.
Definition: mbyte.c:215
void buf_mb_wcstombs(struct Buffer *dest, const wchar_t *wstr, size_t wlen)
Convert a string from wide to multibyte characters.
Definition: mbyte.c:255
int mutt_mb_wcwidth(wchar_t wc)
Measure the screen width of a character.
Definition: mbyte.c:197
#define IsWPrint(wc)
Definition: mbyte.h:41
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:114
#define FREE(x)
Definition: memory.h:45
GUI present the user with a selectable list.
void msgcont_push_window(struct MuttWindow *win)
Add a window to the Container Stack.
Definition: msgcont.c:93
struct MuttWindow * msgcont_pop_window(void)
Remove the last Window from the Container Stack.
Definition: msgcont.c:57
#define ICONV_BUF_TOO_SMALL
Error value for iconv() - Buffer too small.
Definition: charset.h:105
Convenience wrapper for the library headers.
#define N_(a)
Definition: message.h:32
Keep track when processing files.
Many unsorted constants and some structs.
uint8_t CompletionFlags
Flags for mutt_enter_string_full(), e.g. MUTT_COMP_NO_FLAGS.
Definition: mutt.h:54
#define MUTT_COMP_PASS
Password mode (no echo)
Definition: mutt.h:57
#define MUTT_COMP_UNBUFFERED
Ignore macro buffer.
Definition: mutt.h:58
#define MUTT_COMP_CLEAR
Clear input if printable character is pressed.
Definition: mutt.h:56
const struct AttrColor * mutt_curses_set_normal_backed_color_by_id(enum ColorId cid)
Set the colour and attributes by the colour id.
Definition: mutt_curses.c:65
enum MuttCursorState mutt_curses_set_cursor(enum MuttCursorState state)
Set the cursor state.
Definition: mutt_curses.c:96
const struct AttrColor * mutt_curses_set_color_by_id(enum ColorId cid)
Set the colour and attributes by the colour id.
Definition: mutt_curses.c:81
@ MUTT_CURSOR_VISIBLE
Display a normal cursor.
Definition: mutt_curses.h:60
bool mutt_window_is_visible(struct MuttWindow *win)
Is the Window visible?
Definition: mutt_window.c:512
void window_redraw(struct MuttWindow *win)
Reflow, recalc and repaint a tree of Windows.
Definition: mutt_window.c:634
void mutt_window_free(struct MuttWindow **ptr)
Free a Window and its children.
Definition: mutt_window.c:202
int mutt_window_printf(struct MuttWindow *win, const char *fmt,...)
Write a formatted string to a Window.
Definition: mutt_window.c:431
struct MuttWindow * mutt_window_new(enum WindowType type, enum MuttWindowOrientation orient, enum MuttWindowSize size, int cols, int rows)
Create a new Window.
Definition: mutt_window.c:182
int mutt_window_move(struct MuttWindow *win, int col, int row)
Move the cursor in a Window.
Definition: mutt_window.c:297
struct MuttWindow * window_set_focus(struct MuttWindow *win)
Set the Window focus.
Definition: mutt_window.c:684
void mutt_window_get_coords(struct MuttWindow *win, int *col, int *row)
Get the cursor position in the Window.
Definition: mutt_window.c:277
void mutt_window_clearline(struct MuttWindow *win, int row)
Clear a row of a Window.
Definition: mutt_window.c:232
int mutt_window_addstr(struct MuttWindow *win, const char *str)
Write a string to a Window.
Definition: mutt_window.c:416
void mutt_window_clrtoeol(struct MuttWindow *win)
Clear to the end of the line.
Definition: mutt_window.c:244
#define WA_RECALC
Recalculate the contents of the Window.
Definition: mutt_window.h:110
@ WT_CUSTOM
Window with a custom drawing function.
Definition: mutt_window.h:95
@ MUTT_WIN_ORIENT_VERTICAL
Window uses all available vertical space.
Definition: mutt_window.h:38
#define WA_REPAINT
Redraw the contents of the Window.
Definition: mutt_window.h:111
#define MUTT_WIN_SIZE_UNLIMITED
Use as much space as possible.
Definition: mutt_window.h:52
@ MUTT_WIN_SIZE_FIXED
Window has a fixed size.
Definition: mutt_window.h:47
void buf_expand_path_regex(struct Buffer *buf, bool regex)
Create the canonical path (with regex char escaping)
Definition: muttlib.c:136
Some miscellaneous functions.
const char * opcodes_get_name(int op)
Get the name of an opcode.
Definition: opcodes.c:48
#define OP_TIMEOUT
1 second with no events
Definition: opcodes.h:34
#define OP_REPAINT
Repaint is needed.
Definition: opcodes.h:32
#define OP_ABORT
$abort_key pressed (Ctrl-G)
Definition: opcodes.h:35
Progress Bar Window Data.
Sidebar functions.
String manipulation buffer.
Definition: buffer.h:34
Keep our place when entering a string.
Definition: state.h:32
size_t curpos
Position of the cursor.
Definition: state.h:36
size_t wbuflen
Length of buffer.
Definition: state.h:34
size_t begin
Position of the start.
Definition: state.h:37
wchar_t * wbuf
Buffer for the string being entered.
Definition: state.h:33
size_t lastchar
Position of the last character.
Definition: state.h:35
Data to fill the Enter Window.
Definition: wdata.h:46
bool pass
Password mode, conceal characters.
Definition: wdata.h:58
int tabs
Number of times the user has hit tab.
Definition: wdata.h:63
void * cdata
Auto-Completion private data.
Definition: wdata.h:53
CompletionFlags flags
Flags, see CompletionFlags.
Definition: wdata.h:49
int row
Cursor row.
Definition: wdata.h:69
struct CompletionData * cd
Auto-completion state data.
Definition: wdata.h:67
struct Buffer * buffer
struct Buffer for the result
Definition: wdata.h:48
bool done
Is text-entry done?
Definition: wdata.h:65
bool first
First time through, no input yet.
Definition: wdata.h:59
int col
Cursor column.
Definition: wdata.h:70
wchar_t * tempbuf
Buffer used by completion.
Definition: wdata.h:60
const struct CompleteOps * comp_api
Auto-Completion API.
Definition: wdata.h:52
const char * prompt
Prompt.
Definition: wdata.h:56
struct EnterState * state
Current state of text entry.
Definition: wdata.h:50
enum EnterRedrawFlags redraw
What needs redrawing? See EnterRedrawFlags.
Definition: wdata.h:57
mbstate_t * mbstate
Multi-byte state.
Definition: wdata.h:62
enum HistoryClass hclass
History to use, e.g. HC_NEO_COMMAND.
Definition: wdata.h:51
Input for the file completion function.
Definition: curs_lib.h:39
char *** files
List of files selected.
Definition: curs_lib.h:42
bool multiple
Allow multiple selections.
Definition: curs_lib.h:40
int * numfiles
Number of files selected.
Definition: curs_lib.h:43
An event such as a keypress.
Definition: lib.h:82
int op
Function opcode, e.g. OP_HELP.
Definition: lib.h:84
int ch
Raw key pressed.
Definition: lib.h:83
Mapping between user-readable string and a constant.
Definition: mapping.h:32
const struct Mapping * help_data
Data for the Help Bar.
Definition: mutt_window.h:142
int(* repaint)(struct MuttWindow *win)
Definition: mutt_window.h:187
struct WindowState state
Current state of the Window.
Definition: mutt_window.h:127
void * wdata
Private data.
Definition: mutt_window.h:145
int(* recalc)(struct MuttWindow *win)
Definition: mutt_window.h:173
void(* wdata_free)(struct MuttWindow *win, void **ptr)
Definition: mutt_window.h:159
int help_menu
Menu for key bindings, e.g. MENU_PAGER.
Definition: mutt_window.h:141
WindowActionFlags actions
Actions to be performed, e.g. WA_RECALC.
Definition: mutt_window.h:132
bool(* recursor)(struct MuttWindow *win)
Definition: mutt_window.h:205
short cols
Number of columns, can be MUTT_WIN_SIZE_UNLIMITED.
Definition: mutt_window.h:60
@ MENU_EDITOR
Text entry area.
Definition: type.h:44