NeoMutt  2022-04-29-178-g3b62e6
Teaching an old dog new tricks
DOXYGEN
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 "complete/lib.h"
40#include "enter/lib.h"
41#include "history/lib.h"
42#include "menu/lib.h"
43#include "color/color.h"
44#include "functions.h"
45#include "keymap.h"
46#include "mutt_globals.h"
47#include "muttlib.h"
48#include "opcodes.h"
49#include "options.h"
50#include "state.h" // IWYU pragma: keep
51#include "wdata.h"
52
54static const struct Mapping EditorHelp[] = {
55 // clang-format off
56 { N_("Complete"), OP_EDITOR_COMPLETE },
57 { N_("Hist Up"), OP_EDITOR_HISTORY_UP },
58 { N_("Hist Down"), OP_EDITOR_HISTORY_DOWN },
59 { N_("Hist Search"), OP_EDITOR_HISTORY_SEARCH },
60 { N_("Begin Line"), OP_EDITOR_BOL },
61 { N_("End Line"), OP_EDITOR_EOL },
62 { N_("Kill Line"), OP_EDITOR_KILL_LINE },
63 { N_("Kill Word"), OP_EDITOR_KILL_WORD },
64 { NULL, 0 },
65 // clang-format on
66};
67
75static int my_addwch(struct MuttWindow *win, wchar_t wc)
76{
77 int n = wcwidth(wc);
78 if (IsWPrint(wc) && (n > 0))
79 return mutt_addwch(win, wc);
80 if (!(wc & ~0x7f))
81 return mutt_window_printf(win, "^%c", ((int) wc + 0x40) & 0x7f);
82 if (!(wc & ~0xffff))
83 return mutt_window_printf(win, "\\u%04x", (int) wc);
84 return mutt_window_printf(win, "\\u%08x", (int) wc);
85}
86
93bool self_insert(struct EnterWindowData *wdata, int ch)
94{
95 if (!wdata)
96 return true;
97
98 wdata->tabs = 0;
99 wchar_t wc = 0;
100
101 /* quietly ignore all other function keys */
102 if (ch & ~0xff)
103 return false;
104
105 /* gather the octets into a wide character */
106 {
107 char c = ch;
108 size_t k = mbrtowc(&wc, &c, 1, wdata->mbstate);
109 if (k == (size_t) (-2))
110 return false;
111 else if ((k != 0) && (k != 1))
112 {
113 memset(wdata->mbstate, 0, sizeof(*wdata->mbstate));
114 return false;
115 }
116 }
117
118 if (wdata->first && (wdata->flags & MUTT_COMP_CLEAR))
119 {
120 wdata->first = false;
121 if (IsWPrint(wc)) /* why? */
122 {
123 wdata->state->curpos = 0;
124 wdata->state->lastchar = 0;
125 }
126 }
127
128 if ((wc == '\r') || (wc == '\n'))
129 {
130 /* Convert from wide characters */
131 mutt_mb_wcstombs(wdata->buf, wdata->buflen, wdata->state->wbuf, wdata->state->lastchar);
132 if (!wdata->pass)
133 mutt_hist_add(wdata->hclass, wdata->buf, true);
134
135 if (wdata->multiple)
136 {
137 char **tfiles = NULL;
138 *wdata->numfiles = 1;
139 tfiles = mutt_mem_calloc(*wdata->numfiles, sizeof(char *));
140 mutt_expand_path(wdata->buf, wdata->buflen);
141 tfiles[0] = mutt_str_dup(wdata->buf);
142 *wdata->files = tfiles;
143 }
144 return true;
145 }
146 else if (wc && ((wc < ' ') || IsWPrint(wc))) /* why? */
147 {
148 if (wdata->state->lastchar >= wdata->state->wbuflen)
149 {
150 wdata->state->wbuflen = wdata->state->lastchar + 20;
151 mutt_mem_realloc(&wdata->state->wbuf, wdata->state->wbuflen * sizeof(wchar_t));
152 }
153 memmove(wdata->state->wbuf + wdata->state->curpos + 1,
154 wdata->state->wbuf + wdata->state->curpos,
155 (wdata->state->lastchar - wdata->state->curpos) * sizeof(wchar_t));
156 wdata->state->wbuf[wdata->state->curpos++] = wc;
157 wdata->state->lastchar++;
158 }
159 else
160 {
162 mutt_beep(false);
163 }
164
165 return false;
166}
167
180int mutt_buffer_get_field(const char *field, struct Buffer *buf, CompletionFlags complete,
181 bool multiple, struct Mailbox *m, char ***files, int *numfiles)
182{
185 // win->recalc = enter_window_recalc;
186 // win->repaint = enter_window_repaint;
187 win->actions |= WA_RECALC;
188
190
191 const bool old_oime = OptIgnoreMacroEvents;
192 if (complete & MUTT_COMP_UNBUFFERED)
194
195 int rc = 0;
196 int col = 0;
197
198 struct EnterState *state = enter_state_new();
199
200 const struct Mapping *old_help = win->help_data;
201 int old_menu = win->help_menu;
202
203 win->help_data = EditorHelp;
204 win->help_menu = MENU_EDITOR;
205 struct MuttWindow *old_focus = window_set_focus(win);
206
208 window_redraw(win);
209 do
210 {
211 if (SigWinch)
212 {
213 SigWinch = false;
215 clearok(stdscr, true);
216 window_redraw(NULL);
217 }
218 mutt_window_clearline(win, 0);
220 mutt_window_addstr(win, field);
222 mutt_refresh();
223 mutt_window_get_coords(win, &col, NULL);
224
225 int width = win->state.cols - col - 1;
226 mbstate_t mbstate = { 0 };
227
228 // clang-format off
229 struct EnterWindowData wdata = { buf->data, buf->dsize, col, complete,
231 (complete & MUTT_COMP_PASS), true, 0, NULL, 0, &mbstate, 0, false, NULL };
232 // clang-format on
233 win->wdata = &wdata;
234
235 if (state->wbuf[0] == L'\0')
236 {
237 /* Initialise wbuf from buf */
238 wdata.state->wbuflen = 0;
239 wdata.state->lastchar = mutt_mb_mbstowcs(&wdata.state->wbuf,
240 &wdata.state->wbuflen, 0, wdata.buf);
242 }
243 else
244 {
246 wdata.first = false;
247 }
248
249 if (wdata.flags & MUTT_COMP_FILE)
250 wdata.hclass = HC_FILE;
251 else if (wdata.flags & MUTT_COMP_FILE_MBOX)
252 wdata.hclass = HC_MBOX;
253 else if (wdata.flags & MUTT_COMP_FILE_SIMPLE)
254 wdata.hclass = HC_CMD;
255 else if (wdata.flags & MUTT_COMP_ALIAS)
256 wdata.hclass = HC_ALIAS;
257 else if (wdata.flags & MUTT_COMP_COMMAND)
258 wdata.hclass = HC_COMMAND;
259 else if (wdata.flags & MUTT_COMP_PATTERN)
260 wdata.hclass = HC_PATTERN;
261 else
262 wdata.hclass = HC_OTHER;
263
264 do
265 {
266 window_set_focus(win);
267 if (!wdata.pass)
268 {
269 if (wdata.redraw == ENTER_REDRAW_INIT)
270 {
271 /* Go to end of line */
272 wdata.state->curpos = wdata.state->lastchar;
274 wdata.state->wbuf, wdata.state->lastchar,
275 mutt_mb_wcswidth(wdata.state->wbuf, wdata.state->lastchar) - width + 1);
276 }
277 if ((wdata.state->curpos < wdata.state->begin) ||
278 (mutt_mb_wcswidth(wdata.state->wbuf + wdata.state->begin,
279 wdata.state->curpos - wdata.state->begin) >= width))
280 {
282 wdata.state->wbuf, wdata.state->lastchar,
283 mutt_mb_wcswidth(wdata.state->wbuf, wdata.state->curpos) - (width / 2));
284 }
285 mutt_window_move(win, wdata.col, 0);
286 int w = 0;
287 for (size_t i = wdata.state->begin; i < wdata.state->lastchar; i++)
288 {
289 w += mutt_mb_wcwidth(wdata.state->wbuf[i]);
290 if (w > width)
291 break;
292 my_addwch(win, wdata.state->wbuf[i]);
293 }
296 wdata.col +
297 mutt_mb_wcswidth(wdata.state->wbuf + wdata.state->begin,
298 wdata.state->curpos - wdata.state->begin),
299 0);
300 }
301
302 // Restore the cursor position after drawing the screen
303 int r = 0, c = 0;
304 mutt_window_get_coords(win, &c, &r);
305 window_redraw(NULL);
306 mutt_window_move(win, c, r);
307
308 struct KeyEvent event = km_dokey_event(MENU_EDITOR);
309 if (event.op < 0)
310 {
311 rc = (SigWinch && (event.op == OP_TIMEOUT)) ? 1 : -1;
312 goto bye;
313 }
314
315 if (event.op == OP_NULL)
316 {
317 if (complete & MUTT_COMP_PASS)
318 mutt_debug(LL_DEBUG1, "Got char *\n");
319 else
320 mutt_debug(LL_DEBUG1, "Got char %c (0x%02x)\n", event.ch, event.ch);
321 if (self_insert(&wdata, event.ch))
322 {
323 rc = 0;
324 goto bye;
325 }
326 continue;
327 }
328 else
329 {
330 mutt_debug(LL_DEBUG1, "Got op %s (%d)\n", opcodes_get_name(event.op),
331 event.op);
332 }
333
334 wdata.first = false;
335 if ((event.op != OP_EDITOR_COMPLETE) && (event.op != OP_EDITOR_COMPLETE_QUERY))
336 wdata.tabs = 0;
338 int rc_disp = enter_function_dispatcher(win, event.op);
339 switch (rc_disp)
340 {
341 case FR_NO_ACTION:
342 {
343 if (self_insert(&wdata, event.ch))
344 {
345 rc = 0;
346 goto bye;
347 }
348 break;
349 }
350 case FR_CONTINUE: // repaint
351 rc = 1;
352 goto bye;
353
354 case FR_SUCCESS:
355 break;
356
357 case FR_UNKNOWN:
358 case FR_ERROR:
359 default:
360 mutt_beep(false);
361 }
362 } while (!wdata.done);
363
364 bye:
366 FREE(&wdata.tempbuf);
367 completion_data_free(&wdata.cd);
368 } while (rc == 1);
370
372
373 win->help_data = old_help;
374 win->help_menu = old_menu;
375 mutt_window_move(win, 0, 0);
376 mutt_window_clearline(win, 0);
377 window_set_focus(old_focus);
378 mutt_window_free(&win);
379
380 if (rc == 0)
382 else
384
385 enter_state_free(&state);
386
387 OptIgnoreMacroEvents = old_oime;
388 return rc;
389}
void mutt_buffer_fix_dptr(struct Buffer *buf)
Move the dptr to end of the Buffer.
Definition: buffer.c:179
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:81
Color and attribute parsing.
@ MT_COLOR_NORMAL
Plain text.
Definition: color.h:54
@ MT_COLOR_PROMPT
Question/user input.
Definition: color.h:57
Auto-completion.
Convenience wrapper for the core headers.
void mutt_flushinp(void)
Empty all the keyboard buffers.
Definition: curs_lib.c:593
void mutt_refresh(void)
Force a refresh of the screen.
Definition: curs_lib.c:140
int mutt_addwch(struct MuttWindow *win, wchar_t wc)
Addwch would be provided by an up-to-date curses library.
Definition: curs_lib.c:607
void mutt_beep(bool force)
Irritate the user.
Definition: curs_lib.c:130
void completion_data_free(struct CompletionData **ptr)
Free the Completion Data.
Definition: data.c:52
@ 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
Enter a string.
struct EnterState * enter_state_new(void)
Create a new EnterState.
Definition: state.c:73
void enter_state_free(struct EnterState **ptr)
Free an EnterState.
Definition: state.c:37
@ ENTER_REDRAW_NONE
Nothing to redraw.
Definition: wdata.h:41
@ ENTER_REDRAW_LINE
Redraw entire line.
Definition: wdata.h:43
@ ENTER_REDRAW_INIT
Go to end of line and redraw.
Definition: wdata.h:42
static const struct Mapping EditorHelp[]
Help Bar for the Command Line Editor.
Definition: window.c:54
static int my_addwch(struct MuttWindow *win, wchar_t wc)
Display one wide character on screen.
Definition: window.c:75
int mutt_buffer_get_field(const char *field, struct Buffer *buf, CompletionFlags complete, bool multiple, struct Mailbox *m, char ***files, int *numfiles)
Ask the user for a string.
Definition: window.c:180
bool self_insert(struct EnterWindowData *wdata, int ch)
Insert a normal character.
Definition: window.c:93
int enter_function_dispatcher(struct MuttWindow *win, int op)
Perform an Enter function - Implements function_dispatcher_t -.
Definition: functions.c:704
#define mutt_debug(LEVEL,...)
Definition: logging.h:84
Convenience wrapper for the gui headers.
Read/write command history from/to a file.
@ HC_MBOX
Mailboxes.
Definition: lib.h:55
@ HC_FILE
Files.
Definition: lib.h:52
@ HC_COMMAND
NeoMutt commands.
Definition: lib.h:51
@ HC_ALIAS
Aliases.
Definition: lib.h:50
@ HC_PATTERN
Patterns.
Definition: lib.h:53
@ HC_OTHER
Miscellaneous strings.
Definition: lib.h:54
@ HC_CMD
External commands.
Definition: lib.h:49
void mutt_hist_add(enum HistoryClass hclass, const char *str, bool save)
Add a string to a history.
Definition: history.c:483
void mutt_hist_reset_state(enum HistoryClass hclass)
Move the 'current' position to the end of the History.
Definition: history.c:579
struct KeyEvent km_dokey_event(enum MenuType mtype)
Determine what a keypress should do.
Definition: keymap.c:637
Manage keymappings.
@ LL_DEBUG1
Log at debug level 1.
Definition: logging.h:40
void mutt_mb_wcstombs(char *dest, size_t dlen, const wchar_t *src, size_t slen)
Convert a string from wide to multibyte characters.
Definition: mbyte.c:235
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:215
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:292
int mutt_mb_wcswidth(const wchar_t *s, size_t n)
Measure the screen width of a string.
Definition: mbyte.c:194
int mutt_mb_wcwidth(wchar_t wc)
Measure the screen width of a character.
Definition: mbyte.c:176
#define IsWPrint(wc)
Definition: mbyte.h:39
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:43
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:87
struct MuttWindow * msgcont_pop_window(void)
Remove the last Window from the Container Stack.
Definition: msgcont.c:56
Convenience wrapper for the library headers.
#define N_(a)
Definition: message.h:32
Keep track when processing files.
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:250
Many unsorted constants and some structs.
#define MUTT_COMP_ALIAS
Alias completion (in alias dialog)
Definition: mutt.h:53
#define MUTT_COMP_PASS
Password mode (no echo)
Definition: mutt.h:63
#define MUTT_COMP_UNBUFFERED
Ignore macro buffer.
Definition: mutt.h:64
#define MUTT_COMP_PATTERN
Pattern mode (in pattern dialog)
Definition: mutt.h:61
#define MUTT_COMP_FILE
File completion (in browser)
Definition: mutt.h:55
#define MUTT_COMP_COMMAND
Complete a NeoMutt command.
Definition: mutt.h:54
uint16_t CompletionFlags
Flags for mutt_enter_string_full(), e.g. MUTT_COMP_ALIAS.
Definition: mutt.h:51
#define MUTT_COMP_FILE_SIMPLE
File completion (no browser)
Definition: mutt.h:57
#define MUTT_COMP_FILE_MBOX
File completion, plus incoming folders (in browser)
Definition: mutt.h:56
#define MUTT_COMP_CLEAR
Clear input if printable character is pressed.
Definition: mutt.h:62
enum MuttCursorState mutt_curses_set_cursor(enum MuttCursorState state)
Set the cursor state.
Definition: mutt_curses.c:96
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
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
void mutt_resize_screen(void)
Update NeoMutt's opinion about the window size (CURSES)
Definition: resize.c:73
MuttCursorState
Cursor states for mutt_curses_set_cursor()
Definition: mutt_curses.h:52
@ MUTT_CURSOR_VISIBLE
Display a normal cursor.
Definition: mutt_curses.h:54
Hundreds of global variables to back the user variables.
SIG_ATOMIC_VOLATILE_T SigWinch
true after SIGWINCH is received
Definition: mutt_globals.h:70
void window_redraw(struct MuttWindow *win)
Reflow, recalc and repaint a tree of Windows.
Definition: mutt_window.c:604
void mutt_window_free(struct MuttWindow **ptr)
Free a Window and its children.
Definition: mutt_window.c:201
int mutt_window_printf(struct MuttWindow *win, const char *fmt,...)
Write a formatted string to a Window.
Definition: mutt_window.c:424
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:181
int mutt_window_move(struct MuttWindow *win, int col, int row)
Move the cursor in a Window.
Definition: mutt_window.c:293
struct MuttWindow * window_set_focus(struct MuttWindow *win)
Set the Window focus.
Definition: mutt_window.c:659
void mutt_window_get_coords(struct MuttWindow *win, int *col, int *row)
Get the cursor position in the Window.
Definition: mutt_window.c:273
void mutt_window_clearline(struct MuttWindow *win, int row)
Clear a row of a Window.
Definition: mutt_window.c:230
int mutt_window_addstr(struct MuttWindow *win, const char *str)
Write a string to a Window.
Definition: mutt_window.c:409
void mutt_window_clrtoeol(struct MuttWindow *win)
Clear to the end of the line.
Definition: mutt_window.c:242
#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 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
char * mutt_expand_path(char *buf, size_t buflen)
Create the canonical path.
Definition: muttlib.c:123
Some miscellaneous functions.
const char * opcodes_get_name(int op)
Get the name of an opcode.
Definition: opcodes.c:46
All user-callable functions.
#define OP_TIMEOUT
Definition: opcodes.h:32
Handling of global boolean variables.
bool OptIgnoreMacroEvents
(pseudo) don't process macro/push/exec events while set
Definition: options.h:43
Progress Bar Window Data.
Sidebar functions.
String manipulation buffer.
Definition: buffer.h:34
Keep our place when entering a string.
Definition: state.h:33
size_t curpos
Position of the cursor.
Definition: state.h:37
size_t wbuflen
Length of buffer.
Definition: state.h:35
size_t begin
Position of the start.
Definition: state.h:38
wchar_t * wbuf
Buffer for the string being entered.
Definition: state.h:34
size_t lastchar
Position of the last character.
Definition: state.h:36
Data to fill the Enter Window.
Definition: wdata.h:50
bool pass
Password mode, conceal characters.
Definition: wdata.h:64
int tabs
Number of times the user has hit tab.
Definition: wdata.h:70
int * numfiles
Number of files selected.
Definition: wdata.h:59
CompletionFlags flags
Flags, see CompletionFlags.
Definition: wdata.h:55
size_t buflen
Length of result buffer.
Definition: wdata.h:53
struct CompletionData * cd
Auto-completion state data.
Definition: wdata.h:74
bool done
Is text-entry done?
Definition: wdata.h:72
bool first
First time through, no input yet.
Definition: wdata.h:65
bool multiple
Allow multiple matches.
Definition: wdata.h:56
int col
Initial cursor positions.
Definition: wdata.h:54
char *** files
List of files selected.
Definition: wdata.h:58
wchar_t * tempbuf
Buffer used by completion.
Definition: wdata.h:67
char * buf
Buffer for the result.
Definition: wdata.h:52
struct EnterState * state
Current state of text entry.
Definition: wdata.h:60
enum EnterRedrawFlags redraw
What needs redrawing? See EnterRedrawFlags.
Definition: wdata.h:63
mbstate_t * mbstate
Multi-byte state.
Definition: wdata.h:69
struct Mailbox * m
Mailbox.
Definition: wdata.h:57
enum HistoryClass hclass
History to use, e.g. HC_COMMAND.
Definition: wdata.h:66
An event such as a keypress.
Definition: keymap.h:65
int op
Function opcode, e.g. OP_HELP.
Definition: keymap.h:67
int ch
Raw key pressed.
Definition: keymap.h:66
A mailbox.
Definition: mailbox.h:79
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
struct WindowState state
Current state of the Window.
Definition: mutt_window.h:127
void * wdata
Private data.
Definition: mutt_window.h:145
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
short cols
Number of columns, can be MUTT_WIN_SIZE_UNLIMITED.
Definition: mutt_window.h:60
@ MENU_EDITOR
Text entry area.
Definition: type.h:43