diff options
author | luukvbaal <luukvbaal@gmail.com> | 2025-01-02 14:51:03 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-01-02 05:51:03 -0800 |
commit | 48e2a73610ca5639408f79b3d8eebd3e5f57a327 (patch) | |
tree | e84d5ab3decc765d7532c172d961fcd554d5b23a /src | |
parent | 9d9ee3476e6478850ce8822c85154f0c98570371 (diff) | |
download | rneovim-48e2a73610ca5639408f79b3d8eebd3e5f57a327.tar.gz rneovim-48e2a73610ca5639408f79b3d8eebd3e5f57a327.tar.bz2 rneovim-48e2a73610ca5639408f79b3d8eebd3e5f57a327.zip |
feat(ui)!: emit prompt "messages" as cmdline events #31525
Problem: Prompts are emitted as messages events, where cmdline events
are more appropriate. The user input is also emitted as
message events in fast context, so cannot be displayed with
vim.ui_attach().
Solution: Prompt for user input through cmdline prompts.
Diffstat (limited to 'src')
-rw-r--r-- | src/nvim/bufwrite.c | 2 | ||||
-rw-r--r-- | src/nvim/debugger.c | 3 | ||||
-rw-r--r-- | src/nvim/eval/funcs.c | 6 | ||||
-rw-r--r-- | src/nvim/ex_cmds.c | 43 | ||||
-rw-r--r-- | src/nvim/ex_docmd.c | 2 | ||||
-rw-r--r-- | src/nvim/ex_getln.c | 49 | ||||
-rw-r--r-- | src/nvim/ex_getln_defs.h | 2 | ||||
-rw-r--r-- | src/nvim/input.c | 146 | ||||
-rw-r--r-- | src/nvim/memline.c | 3 | ||||
-rw-r--r-- | src/nvim/message.c | 56 | ||||
-rw-r--r-- | src/nvim/spellsuggest.c | 12 | ||||
-rw-r--r-- | src/nvim/tag.c | 2 | ||||
-rw-r--r-- | src/nvim/ui.c | 6 |
13 files changed, 130 insertions, 202 deletions
diff --git a/src/nvim/bufwrite.c b/src/nvim/bufwrite.c index ced806e524..1afa10df63 100644 --- a/src/nvim/bufwrite.c +++ b/src/nvim/bufwrite.c @@ -350,7 +350,7 @@ static int check_mtime(buf_T *buf, FileInfo *file_info) msg_silent = 0; // Must give this prompt. // Don't use emsg() here, don't want to flush the buffers. msg(_("WARNING: The file has been changed since reading it!!!"), HLF_E); - if (ask_yesno(_("Do you really want to write to it"), true) == 'n') { + if (ask_yesno(_("Do you really want to write to it")) == 'n') { return FAIL; } msg_scroll = false; // Always overwrite the file message now. diff --git a/src/nvim/debugger.c b/src/nvim/debugger.c index b71ff23f57..f3e4ef0698 100644 --- a/src/nvim/debugger.c +++ b/src/nvim/debugger.c @@ -153,8 +153,7 @@ void do_debug(char *cmd) debug_break_level = -1; xfree(cmdline); - cmdline = getcmdline_prompt('>', NULL, 0, EXPAND_NOTHING, NULL, - CALLBACK_NONE); + cmdline = getcmdline_prompt('>', NULL, 0, EXPAND_NOTHING, NULL, CALLBACK_NONE, false, NULL); debug_break_level = n; if (typeahead_saved) { diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index fbaa6e679f..ed3efca0d7 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -3557,10 +3557,10 @@ static void f_inputlist(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) }); // Ask for choice. - bool mouse_used; - int selected = prompt_for_number(&mouse_used); + bool mouse_used = false; + int selected = prompt_for_input(NULL, 0, false, &mouse_used); if (mouse_used) { - selected -= lines_left; + selected = tv_list_len(argvars[0].vval.v_list) - (cmdline_row - mouse_row); } rettv->vval.v_number = selected; diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index a1a6f13023..0510619825 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -3707,12 +3707,9 @@ static int do_sub(exarg_T *eap, const proftime_T timeout, const int cmdpreview_n // Loop until 'y', 'n', 'q', CTRL-E or CTRL-Y typed. while (subflags.do_ask) { if (exmode_active) { - char *prompt; - char *resp; - colnr_T sc, ec; - print_line_no_prefix(lnum, subflags.do_number, subflags.do_list); + colnr_T sc, ec; getvcol(curwin, &curwin->w_cursor, &sc, NULL, NULL); curwin->w_cursor.col = MAX(regmatch.endpos[0].col - 1, 0); @@ -3724,10 +3721,11 @@ static int do_sub(exarg_T *eap, const proftime_T timeout, const int cmdpreview_n ec += numw; } - prompt = xmallocz((size_t)ec + 1); + char *prompt = xmallocz((size_t)ec + 1); memset(prompt, ' ', (size_t)sc); memset(prompt + sc, '^', (size_t)(ec - sc) + 1); - resp = getcmdline_prompt(-1, prompt, 0, EXPAND_NOTHING, NULL, CALLBACK_NONE); + char *resp = getcmdline_prompt(-1, prompt, 0, EXPAND_NOTHING, NULL, + CALLBACK_NONE, false, NULL); msg_putchar('\n'); xfree(prompt); if (resp != NULL) { @@ -3794,35 +3792,14 @@ static int do_sub(exarg_T *eap, const proftime_T timeout, const int cmdpreview_n redraw_later(curwin, UPD_SOME_VALID); curwin->w_p_fen = save_p_fen; - if (msg_row == Rows - 1) { - msg_didout = false; // avoid a scroll-up - } - msg_starthere(); - i = msg_scroll; - msg_scroll = 0; // truncate msg when - // needed - msg_no_more = true; - msg_ext_set_kind("confirm_sub"); - // Same highlight as wait_return(). - smsg(HLF_R, _("replace with %s (y/n/a/q/l/^E/^Y)?"), sub); - msg_no_more = false; - msg_scroll = i; - if (!ui_has(kUIMessages)) { - ui_cursor_goto(msg_row, msg_col); - } - RedrawingDisabled = temp; - no_mapping++; // don't map this key - allow_keys++; // allow special keys - typed = plain_vgetc(); - no_mapping--; - allow_keys--; + snprintf(IObuff, IOSIZE, _("replace with %s (y/n/a/q/l/^E/^Y)?"), sub); + char *prompt = xstrdup(IObuff); + typed = prompt_for_input(prompt, HLF_R, true, NULL); + xfree(prompt); - // clear the question - msg_didout = false; // don't scroll up - msg_col = 0; - gotocmdline(true); p_lz = save_p_lz; + RedrawingDisabled = temp; // restore the line if (orig_line != NULL) { @@ -4808,7 +4785,7 @@ void ex_oldfiles(exarg_T *eap) // File selection prompt on ":browse oldfiles" if (cmdmod.cmod_flags & CMOD_BROWSE) { quit_more = false; - nr = prompt_for_number(false); + nr = prompt_for_input(NULL, 0, false, NULL); msg_starthere(); if (nr > 0 && nr <= tv_list_len(l)) { const char *const p = tv_list_find_str(l, nr - 1); diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 551e8fcb1d..6f9f0f07c9 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -2201,7 +2201,7 @@ static char *do_one_cmd(char **cmdlinep, int flags, cstack_T *cstack, LineGetter errormsg = _("E493: Backwards range given"); goto doend; } - if (ask_yesno(_("Backwards range given, OK to swap"), false) != 'y') { + if (ask_yesno(_("Backwards range given, OK to swap")) != 'y') { goto doend; } } diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 7f2f739e00..09006484ca 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -120,7 +120,7 @@ typedef struct { int indent; int c; bool gotesc; // true when <ESC> just typed - int do_abbr; // when true check for abbr. + bool do_abbr; // when true check for abbr. char *lookfor; // string to match int lookforlen; int hiscnt; // current history line in use @@ -128,17 +128,17 @@ typedef struct { // to jump to next match int histype; // history type to be used incsearch_state_T is_state; - int did_wild_list; // did wild_list() recently + bool did_wild_list; // did wild_list() recently int wim_index; // index in wim_flags[] int save_msg_scroll; int save_State; // remember State when called int prev_cmdpos; char *save_p_icm; - int some_key_typed; // one of the keys was typed + bool some_key_typed; // one of the keys was typed // mouse drag and release events are ignored, unless they are // preceded with a mouse down event - int ignore_drag_release; - int break_ctrl_c; + bool ignore_drag_release; + bool break_ctrl_c; expand_T xpc; OptInt *b_im_ptr; buf_T *b_im_ptr_buf; ///< buffer where b_im_ptr is valid @@ -1848,6 +1848,12 @@ static int command_line_browse_history(CommandLineState *s) static int command_line_handle_key(CommandLineState *s) { + // For one key prompt, avoid putting ESC and Ctrl_C onto cmdline. + // For all other keys, just put onto cmdline and exit. + if (ccline.one_key && s->c != ESC && s->c != Ctrl_C) { + goto end; + } + // Big switch for a typed command line character. switch (s->c) { case K_BS: @@ -1998,6 +2004,12 @@ static int command_line_handle_key(CommandLineState *s) } FALLTHROUGH; case K_LEFTMOUSE: + // Return on left click above number prompt + if (ccline.mouse_used && mouse_row < cmdline_row) { + *ccline.mouse_used = true; + return 0; + } + FALLTHROUGH; case K_RIGHTMOUSE: command_line_left_right_mouse(s); return command_line_not_changed(s); @@ -2155,6 +2167,14 @@ static int command_line_handle_key(CommandLineState *s) } return command_line_not_changed(s); + case 'q': + // Number prompts use the mouse and return on 'q' press + if (ccline.mouse_used) { + *ccline.cmdbuff = NUL; + return 0; + } + FALLTHROUGH; + default: // Normal character with no special meaning. Just set mod_mask // to 0x0 so that typing Shift-Space in the GUI doesn't enter @@ -2175,6 +2195,7 @@ static int command_line_handle_key(CommandLineState *s) return command_line_changed(s); } +end: // put the character in the command line if (IS_SPECIAL(s->c) || mod_mask != 0) { put_on_cmdline(get_special_key_name(s->c, mod_mask), -1, true); @@ -2183,7 +2204,7 @@ static int command_line_handle_key(CommandLineState *s) IObuff[j] = NUL; // exclude composing chars put_on_cmdline(IObuff, j, true); } - return command_line_changed(s); + return ccline.one_key ? 0 : command_line_changed(s); } static int command_line_not_changed(CommandLineState *s) @@ -2721,8 +2742,11 @@ static void abandon_cmdline(void) if (msg_scrolled == 0) { compute_cmdrow(); } - msg("", 0); - redraw_cmdline = true; + // Avoid overwriting key prompt + if (!ccline.one_key) { + msg("", 0); + redraw_cmdline = true; + } } /// getcmdline() - accept a command line starting with firstc. @@ -2761,11 +2785,13 @@ char *getcmdline(int firstc, int count, int indent, bool do_concat FUNC_ATTR_UNU /// @param[in] xp_context Type of expansion. /// @param[in] xp_arg User-defined expansion argument. /// @param[in] highlight_callback Callback used for highlighting user input. +/// @param[in] one_key Return after one key press for button prompt. +/// @param[in] mouse_used Set to true when returning after right mouse click. /// /// @return [allocated] Command line or NULL. char *getcmdline_prompt(const int firstc, const char *const prompt, const int hl_id, const int xp_context, const char *const xp_arg, - const Callback highlight_callback) + const Callback highlight_callback, bool one_key, bool *mouse_used) FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_MALLOC { const int msg_col_save = msg_col; @@ -2786,11 +2812,14 @@ char *getcmdline_prompt(const int firstc, const char *const prompt, const int hl ccline.xp_arg = (char *)xp_arg; ccline.input_fn = (firstc == '@'); ccline.highlight_callback = highlight_callback; + ccline.one_key = one_key; + ccline.mouse_used = mouse_used; int msg_silent_saved = msg_silent; msg_silent = 0; char *const ret = (char *)command_line_enter(firstc, 1, 0, false); + ccline.redraw_state = kCmdRedrawNone; if (did_save_ccline) { restore_cmdline(&save_ccline); @@ -4787,7 +4816,7 @@ void get_user_input(const typval_T *const argvars, typval_T *const rettv, const const int save_ex_normal_busy = ex_normal_busy; ex_normal_busy = 0; rettv->vval.v_string = getcmdline_prompt(secret ? NUL : '@', p, get_echo_hl_id(), - xp_type, xp_arg, input_callback); + xp_type, xp_arg, input_callback, false, NULL); ex_normal_busy = save_ex_normal_busy; callback_free(&input_callback); diff --git a/src/nvim/ex_getln_defs.h b/src/nvim/ex_getln_defs.h index 584c360450..e05d8f27db 100644 --- a/src/nvim/ex_getln_defs.h +++ b/src/nvim/ex_getln_defs.h @@ -65,4 +65,6 @@ struct cmdline_info { char special_char; ///< last putcmdline char (used for redraws) bool special_shift; ///< shift of last putcmdline char CmdRedraw redraw_state; ///< needed redraw for external cmdline + bool one_key; ///< return after one key press for button prompt + bool *mouse_used; ///< mouse clicked in prompt }; diff --git a/src/nvim/input.c b/src/nvim/input.c index 5a3a791de4..ca2a13e016 100644 --- a/src/nvim/input.c +++ b/src/nvim/input.c @@ -6,6 +6,7 @@ #include <string.h> #include "nvim/ascii_defs.h" +#include "nvim/ex_getln.h" #include "nvim/getchar.h" #include "nvim/gettext_defs.h" #include "nvim/globals.h" @@ -32,44 +33,36 @@ /// No other characters are accepted, the message is repeated until a valid /// reply is entered or <C-c> is hit. /// -/// @param[in] str Prompt: question to ask user. Is always followed by -/// " (y/n)?". -/// @param[in] direct Determines what function to use to get user input. If -/// true then input_get() will be used, otherwise vgetc(). -/// I.e. when direct is true then characters are obtained -/// directly from the user without buffers involved. +/// @param[in] str Prompt: question to ask user. Is always followed by " (y/n)?". /// /// @return 'y' or 'n'. Last is also what will be returned in case of interrupt. -int ask_yesno(const char *const str, const bool direct) +int ask_yesno(const char *const str) { const int save_State = State; no_wait_return++; State = MODE_CONFIRM; // Mouse behaves like with :confirm. setmouse(); // Disable mouse in xterm. - no_mapping++; - allow_keys++; // no mapping here, but recognize keys + snprintf(IObuff, IOSIZE, _("%s (y/n)?"), str); + char *prompt = xstrdup(IObuff); int r = ' '; while (r != 'y' && r != 'n') { // same highlighting as for wait_return() - smsg(HLF_R, "%s (y/n)?", str); - if (direct) { - r = get_keystroke(NULL); - } else { - r = plain_vgetc(); - } + r = prompt_for_input(prompt, HLF_R, true, NULL); if (r == Ctrl_C || r == ESC) { r = 'n'; + if (!ui_has(kUIMessages)) { + msg_putchar(r); + } } - msg_putchar(r); // Show what you typed. - ui_flush(); } + + need_wait_return = msg_scrolled; no_wait_return--; State = save_State; setmouse(); - no_mapping--; - allow_keys--; + xfree(prompt); return r; } @@ -155,105 +148,42 @@ int get_keystroke(MultiQueue *events) return n; } -/// Get a number from the user. -/// When "mouse_used" is not NULL allow using the mouse. +/// Ask the user for input through a cmdline prompt. /// -/// @param colon allow colon to abort -int get_number(int colon, bool *mouse_used) +/// @param one_key Return from cmdline after one key press. +/// @param mouse_used When not NULL, allow using the mouse to press a number. +int prompt_for_input(char *prompt, int hl_id, bool one_key, bool *mouse_used) { - int n = 0; - int typed = 0; + int ret = one_key ? ESC : 0; + char *kmsg = keep_msg ? xstrdup(keep_msg) : NULL; - if (mouse_used != NULL) { - *mouse_used = false; + if (prompt == NULL) { + if (mouse_used != NULL) { + prompt = _("Type number and <Enter> or click with the mouse (q or empty cancels):"); + } else { + prompt = _("Type number and <Enter> (q or empty cancels):"); + } } - // When not printing messages, the user won't know what to type, return a - // zero (as if CR was hit). - if (msg_silent != 0) { - return 0; - } + cmdline_row = msg_row; + ui_flush(); - no_mapping++; - allow_keys++; // no mapping here, but recognize keys - while (true) { - ui_cursor_goto(msg_row, msg_col); - int c = safe_vgetc(); - if (ascii_isdigit(c)) { - if (vim_append_digit_int(&n, c - '0') == FAIL) { - return 0; - } - msg_putchar(c); - typed++; - } else if (c == K_DEL || c == K_KDEL || c == K_BS || c == Ctrl_H) { - if (typed > 0) { - msg_puts("\b \b"); - typed--; - } - n /= 10; - } else if (mouse_used != NULL && c == K_LEFTMOUSE) { - *mouse_used = true; - n = mouse_row + 1; - break; - } else if (n == 0 && c == ':' && colon) { - stuffcharReadbuff(':'); - if (!exmode_active) { - cmdline_row = msg_row; - } - skip_redraw = true; // skip redraw once - do_redraw = false; - break; - } else if (c == Ctrl_C || c == ESC || c == 'q') { - n = 0; - break; - } else if (c == CAR || c == NL) { - break; - } - } - no_mapping--; + no_mapping++; // don't map prompt input + allow_keys++; // allow special keys + char *resp = getcmdline_prompt(-1, prompt, hl_id, EXPAND_NOTHING, NULL, + CALLBACK_NONE, one_key, mouse_used); allow_keys--; - return n; -} + no_mapping--; -/// Ask the user to enter a number. -/// -/// When "mouse_used" is not NULL allow using the mouse and in that case return -/// the line number. -int prompt_for_number(bool *mouse_used) -{ - msg_ext_set_kind("number_prompt"); - // When using ":silent" assume that <CR> was entered. - if (mouse_used != NULL) { - msg_puts(_("Type number and <Enter> or click with the mouse " - "(q or empty cancels): ")); - } else { - msg_puts(_("Type number and <Enter> (q or empty cancels): ")); + if (resp) { + ret = one_key ? (int)(*resp) : atoi(resp); + xfree(resp); } - // Set the state such that text can be selected/copied/pasted and we still - // get mouse events. - int save_cmdline_row = cmdline_row; - cmdline_row = 0; - int save_State = State; - State = MODE_ASKMORE; // prevents a screen update when using a timer - // May show different mouse shape. - setmouse(); - - int i = get_number(true, mouse_used); - if (KeyTyped) { - // don't call wait_return() now - if (msg_row > 0) { - cmdline_row = msg_row - 1; - } - need_wait_return = false; - msg_didany = false; - msg_didout = false; - } else { - cmdline_row = save_cmdline_row; + if (kmsg != NULL) { + set_keep_msg(kmsg, keep_msg_hl_id); + xfree(kmsg); } - State = save_State; - // May need to restore mouse shape. - setmouse(); - return i; + return ret; } diff --git a/src/nvim/memline.c b/src/nvim/memline.c index a2b8aa34ef..ce04362a3e 100644 --- a/src/nvim/memline.c +++ b/src/nvim/memline.c @@ -804,8 +804,7 @@ void ml_recover(bool checkext) // list the names of the swapfiles recover_names(fname, true, NULL, 0, NULL); msg_putchar('\n'); - msg_puts(_("Enter number of swap file to use (0 to quit): ")); - i = get_number(false, NULL); + i = prompt_for_input(_("Enter number of swap file to use (0 to quit): "), 0, false, NULL); if (i < 1 || i > len) { goto theend; } diff --git a/src/nvim/message.c b/src/nvim/message.c index f86f0feca5..69e8f66bbe 100644 --- a/src/nvim/message.c +++ b/src/nvim/message.c @@ -92,7 +92,7 @@ static int confirm_msg_used = false; // displaying confirm_msg # include "message.c.generated.h" #endif static char *confirm_msg = NULL; // ":confirm" message -static char *confirm_msg_tail; // tail of confirm_msg +static char *confirm_buttons; // ":confirm" buttons sent to cmdline as prompt MessageHistoryEntry *first_msg_hist = NULL; MessageHistoryEntry *last_msg_hist = NULL; @@ -2286,7 +2286,7 @@ static void msg_puts_display(const char *str, int maxlen, int hl_id, int recurse if (p_more && lines_left == 0 && State != MODE_HITRETURN && !msg_no_more && !exmode_active) { if (do_more_prompt(NUL)) { - s = confirm_msg_tail; + s = confirm_buttons; } if (quit_more) { return; @@ -2778,7 +2778,7 @@ static void msg_puts_printf(const char *str, const ptrdiff_t maxlen) /// When at hit-enter prompt "typed_char" is the already typed character, /// otherwise it's NUL. /// -/// @return true when jumping ahead to "confirm_msg_tail". +/// @return true when jumping ahead to "confirm_buttons". static bool do_more_prompt(int typed_char) { static bool entered = false; @@ -3502,10 +3502,10 @@ int do_dialog(int type, const char *title, const char *message, const char *butt } // Get a typed character directly from the user. - int c = get_keystroke(NULL); + int c = prompt_for_input(confirm_buttons, HLF_M, true, NULL); switch (c) { case CAR: // User accepts default option - case NL: + case NUL: retval = dfltbutton; break; case Ctrl_C: // User aborts/cancels @@ -3514,6 +3514,7 @@ int do_dialog(int type, const char *title, const char *message, const char *butt break; default: // Could be a hotkey? if (c < 0) { // special keys are ignored here + msg_didout = msg_didany = false; continue; } if (c == ':' && ex_cmd) { @@ -3536,6 +3537,7 @@ int do_dialog(int type, const char *title, const char *message, const char *butt break; } // No hotkey match, so keep waiting + msg_didout = msg_didany = false; continue; } break; @@ -3589,19 +3591,20 @@ static char *console_dialog_alloc(const char *message, const char *buttons, bool has_hotkey[0] = false; // Compute the size of memory to allocate. - int len = 0; + int msg_len = 0; + int button_len = 0; int idx = 0; const char *r = buttons; while (*r) { if (*r == DLG_BUTTON_SEP) { - len += 3; // '\n' -> ', '; 'x' -> '(x)' + button_len += 3; // '\n' -> ', '; 'x' -> '(x)' lenhotkey += HOTK_LEN; // each button needs a hotkey if (idx < HAS_HOTKEY_LEN - 1) { has_hotkey[++idx] = false; } } else if (*r == DLG_HOTKEY_CHAR) { r++; - len++; // '&a' -> '[a]' + button_len++; // '&a' -> '[a]' if (idx < HAS_HOTKEY_LEN - 1) { has_hotkey[idx] = true; } @@ -3611,21 +3614,22 @@ static char *console_dialog_alloc(const char *message, const char *buttons, bool MB_PTR_ADV(r); } - len += (int)(strlen(message) - + 2 // for the NL's - + strlen(buttons) - + 3); // for the ": " and NUL - lenhotkey++; // for the NUL + msg_len += (int)strlen(message) + 3; // for the NL's and NUL + button_len += (int)strlen(buttons) + 3; // for the ": " and NUL + lenhotkey++; // for the NUL // If no hotkey is specified, first char is used. if (!has_hotkey[0]) { - len += 2; // "x" -> "[x]" + button_len += 2; // "x" -> "[x]" } // Now allocate space for the strings xfree(confirm_msg); - confirm_msg = xmalloc((size_t)len); - *confirm_msg = NUL; + confirm_msg = xmalloc((size_t)msg_len); + snprintf(confirm_msg, (size_t)msg_len, "\n%s\n", message); + + xfree(confirm_buttons); + confirm_buttons = xmalloc((size_t)button_len); return xmalloc((size_t)lenhotkey); } @@ -3643,42 +3647,34 @@ static char *msg_show_console_dialog(const char *message, const char *buttons, i bool has_hotkey[HAS_HOTKEY_LEN] = { false }; char *hotk = console_dialog_alloc(message, buttons, has_hotkey); - copy_hotkeys_and_msg(message, buttons, dfltbutton, has_hotkey, hotk); + copy_confirm_hotkeys(buttons, dfltbutton, has_hotkey, hotk); display_confirm_msg(); return hotk; } -/// Copies hotkeys & dialog message into the memory allocated for it +/// Copies hotkeys into the memory allocated for it /// -/// @param message Message which will be part of the confirm_msg /// @param buttons String containing button names /// @param default_button_idx Number of default button /// @param has_hotkey An element in this array is true if corresponding button /// has a hotkey /// @param[out] hotkeys_ptr Pointer to the memory location where hotkeys will be copied -static void copy_hotkeys_and_msg(const char *message, const char *buttons, int default_button_idx, +static void copy_confirm_hotkeys(const char *buttons, int default_button_idx, const bool has_hotkey[], char *hotkeys_ptr) { - *confirm_msg = '\n'; - STRCPY(confirm_msg + 1, message); - - char *msgp = confirm_msg + 1 + strlen(message); - // Define first default hotkey. Keep the hotkey string NUL // terminated to avoid reading past the end. hotkeys_ptr[copy_char(buttons, hotkeys_ptr, true)] = NUL; - // Remember where the choices start, displaying starts here when - // "hotkeys_ptr" typed at the more prompt. - confirm_msg_tail = msgp; - *msgp++ = '\n'; - bool first_hotkey = false; // Is the first char of button a hotkey if (!has_hotkey[0]) { first_hotkey = true; // If no hotkey is specified, first char is used } + // Remember where the choices start, sent as prompt to cmdline. + char *msgp = confirm_buttons; + int idx = 0; const char *r = buttons; while (*r) { diff --git a/src/nvim/spellsuggest.c b/src/nvim/spellsuggest.c index 3a985ab004..21bfa367bf 100644 --- a/src/nvim/spellsuggest.c +++ b/src/nvim/spellsuggest.c @@ -444,7 +444,7 @@ void spell_suggest(int count) char wcopy[MAXWLEN + 2]; suginfo_T sug; suggest_T *stp; - bool mouse_used; + bool mouse_used = false; int selected = count; int badlen = 0; int msg_scroll_save = msg_scroll; @@ -594,15 +594,11 @@ void spell_suggest(int count) cmdmsg_rl = false; msg_col = 0; // Ask for choice. - selected = prompt_for_number(&mouse_used); - - if (ui_has(kUIMessages)) { - ui_call_msg_clear(); - } - + selected = prompt_for_input(NULL, 0, false, &mouse_used); if (mouse_used) { - selected -= lines_left; + selected = sug.su_ga.ga_len + 1 - (cmdline_row - mouse_row); } + lines_left = Rows; // avoid more prompt // don't delay for 'smd' in normal_cmd() msg_scroll = msg_scroll_save; diff --git a/src/nvim/tag.c b/src/nvim/tag.c index cdce97fc01..c676b00986 100644 --- a/src/nvim/tag.c +++ b/src/nvim/tag.c @@ -668,7 +668,7 @@ void do_tag(char *tag, int type, int count, int forceit, bool verbose) if (ask_for_selection) { // Ask to select a tag from the list. - int i = prompt_for_number(NULL); + int i = prompt_for_input(NULL, 0, false, NULL); if (i <= 0 || i > num_matches || got_int) { // no valid choice: don't change anything if (use_tagstack) { diff --git a/src/nvim/ui.c b/src/nvim/ui.c index 4f443028b3..d242baf83b 100644 --- a/src/nvim/ui.c +++ b/src/nvim/ui.c @@ -717,10 +717,10 @@ void ui_call_event(char *name, bool fast, Array args) bool handled = false; UIEventCallback *event_cb; - // Prompt messages should be shown immediately so must be safe + // Return prompt is still a non-fast event, other prompt messages are + // followed by a "cmdline_show" event. if (strcmp(name, "msg_show") == 0) { - char *kind = args.items[0].data.string.data; - fast = !kind || ((strncmp(kind, "confirm", 7) != 0 && strstr(kind, "_prompt") == NULL)); + fast = !strequal(args.items[0].data.string.data, "return_prompt"); } map_foreach(&ui_event_cbs, ui_event_ns_id, event_cb, { |