diff options
-rw-r--r-- | .github/ISSUE_TEMPLATE/bug_report.yml | 7 | ||||
-rw-r--r-- | src/nvim/buffer.c | 8 | ||||
-rw-r--r-- | src/nvim/eval/buffer.c | 4 | ||||
-rw-r--r-- | src/nvim/globals.h | 1 | ||||
-rw-r--r-- | src/nvim/memline.c | 127 | ||||
-rw-r--r-- | src/nvim/mouse.c | 28 | ||||
-rw-r--r-- | src/nvim/popupmenu.c | 2 | ||||
-rw-r--r-- | test/functional/ui/statuscolumn_spec.lua | 16 |
8 files changed, 111 insertions, 82 deletions
diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 48a450be36..c07ae66c6f 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -6,8 +6,13 @@ body: - type: markdown attributes: value: | - _Before reporting:_ run `make distclean` when encountering build issues, search [existing issues](https://github.com/neovim/neovim/issues?q=is%3Aissue+is%3Aopen+label%3Abug) and check the [FAQ](https://github.com/neovim/neovim/wiki/FAQ). Usage or "How to" questions belong on the [stackoverflow](https://vi.stackexchange.com/) and will be closed. + *Before reporting:* + - Confirm the problem is reproducible on [**master**](https://github.com/neovim/neovim/releases/nightly) or [**latest stable**](https://github.com/neovim/neovim/releases/stable) release + - run `make distclean` when encountering build issues + - search [existing issues](https://github.com/neovim/neovim/issues?q=is%3Aissue+is%3Aopen+label%3Abug) + - check the [FAQ](https://github.com/neovim/neovim/wiki/FAQ) + Usage or "How to" questions belong on the [stackoverflow](https://vi.stackexchange.com/) and will be closed. - type: textarea attributes: label: "Problem" diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index c89d4f667a..9df886ef9a 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -930,10 +930,14 @@ static void free_buffer_stuff(buf_T *buf, int free_flags) /// Go to another buffer. Handles the result of the ATTENTION dialog. void goto_buffer(exarg_T *eap, int start, int dir, int count) { + const int save_sea = swap_exists_action; + bufref_T old_curbuf; set_bufref(&old_curbuf, curbuf); - swap_exists_action = SEA_DIALOG; + if (swap_exists_action == SEA_NONE) { + swap_exists_action = SEA_DIALOG; + } (void)do_buffer(*eap->cmd == 's' ? DOBUF_SPLIT : DOBUF_GOTO, start, dir, count, eap->forceit); @@ -946,7 +950,7 @@ void goto_buffer(exarg_T *eap, int start, int dir, int count) // Quitting means closing the split window, nothing else. win_close(curwin, true, false); - swap_exists_action = SEA_NONE; + swap_exists_action = save_sea; swap_exists_did_quit = true; // Restore the error/interrupt/exception state if not discarded by a diff --git a/src/nvim/eval/buffer.c b/src/nvim/eval/buffer.c index 616c1e06fc..93e4f14980 100644 --- a/src/nvim/eval/buffer.c +++ b/src/nvim/eval/buffer.c @@ -298,7 +298,9 @@ void f_bufload(typval_T *argvars, typval_T *unused, EvalFuncData fptr) buf_T *buf = get_buf_arg(&argvars[0]); if (buf != NULL) { - swap_exists_action = SEA_NONE; + if (swap_exists_action != SEA_READONLY) { + swap_exists_action = SEA_NONE; + } buf_ensure_loaded(buf); } } diff --git a/src/nvim/globals.h b/src/nvim/globals.h index 077f48580c..cc66fac48f 100644 --- a/src/nvim/globals.h +++ b/src/nvim/globals.h @@ -684,6 +684,7 @@ EXTERN bool in_assert_fails INIT( = false); // assert_fails() active #define SEA_DIALOG 1 // use dialog when possible #define SEA_QUIT 2 // quit editing the file #define SEA_RECOVER 3 // recover the file +#define SEA_READONLY 4 // no dialog, mark buffer as read-only EXTERN int swap_exists_action INIT( = SEA_NONE); ///< For dialog when swap file already exists. EXTERN bool swap_exists_did_quit INIT( = false); ///< Selected "quit" at the dialog. diff --git a/src/nvim/memline.c b/src/nvim/memline.c index 26757d6ed1..ea7a61b8dd 100644 --- a/src/nvim/memline.c +++ b/src/nvim/memline.c @@ -235,6 +235,16 @@ typedef enum { UB_SAME_DIR, // update the B0_SAME_DIR flag } upd_block0_T; +typedef enum { + SEA_CHOICE_NONE = 0, + SEA_CHOICE_READONLY = 1, + SEA_CHOICE_EDIT = 2, + SEA_CHOICE_RECOVER = 3, + SEA_CHOICE_DELETE = 4, + SEA_CHOICE_QUIT = 5, + SEA_CHOICE_ABORT = 6, +} sea_choice_T; + #ifdef INCLUDE_GENERATED_DECLARATIONS # include "memline.c.generated.h" #endif @@ -3235,15 +3245,8 @@ static void attention_message(buf_T *buf, char *fname) /// Trigger the SwapExists autocommands. /// -/// @return a value for equivalent to do_dialog() (see below): -/// 0: still need to ask for a choice -/// 1: open read-only -/// 2: edit anyway -/// 3: recover -/// 4: delete it -/// 5: quit -/// 6: abort -static int do_swapexists(buf_T *buf, char *fname) +/// @return a value for equivalent to do_dialog(). +static sea_choice_T do_swapexists(buf_T *buf, char *fname) { set_vim_var_string(VV_SWAPNAME, fname, -1); set_vim_var_string(VV_SWAPCHOICE, NULL, -1); @@ -3258,20 +3261,20 @@ static int do_swapexists(buf_T *buf, char *fname) switch (*get_vim_var_str(VV_SWAPCHOICE)) { case 'o': - return 1; + return SEA_CHOICE_READONLY; case 'e': - return 2; + return SEA_CHOICE_EDIT; case 'r': - return 3; + return SEA_CHOICE_RECOVER; case 'd': - return 4; + return SEA_CHOICE_DELETE; case 'q': - return 5; + return SEA_CHOICE_QUIT; case 'a': - return 6; + return SEA_CHOICE_ABORT; } - return 0; + return SEA_CHOICE_NONE; } /// Find out what name to use for the swapfile for buffer 'buf'. @@ -3384,13 +3387,13 @@ static char *findswapname(buf_T *buf, char **dirp, char *old_fname, bool *found_ // - the buffer was not recovered if (differ == false && !(curbuf->b_flags & BF_RECOVERED) && vim_strchr(p_shm, SHM_ATTENTION) == NULL) { - int choice = 0; + sea_choice_T choice = SEA_CHOICE_NONE; // It's safe to delete the swapfile if all these are true: // - the edited file exists // - the swapfile has no changes and looks OK if (os_path_exists(buf->b_fname) && swapfile_unchanged(fname)) { - choice = 4; + choice = SEA_CHOICE_DELETE; if (p_verbose > 0) { verb_msg(_("Found a swap file that is not useful, deleting it")); } @@ -3398,14 +3401,19 @@ static char *findswapname(buf_T *buf, char **dirp, char *old_fname, bool *found_ // If there is a SwapExists autocommand and we can handle the // response, trigger it. It may return 0 to ask the user anyway. - if (choice == 0 + if (choice == SEA_CHOICE_NONE && swap_exists_action != SEA_NONE && has_autocmd(EVENT_SWAPEXISTS, buf_fname, buf)) { choice = do_swapexists(buf, fname); } + if (choice == SEA_CHOICE_NONE && swap_exists_action == SEA_READONLY) { + // always open readonly. + choice = SEA_CHOICE_READONLY; + } + process_running = 0; // Set by attention_message..swapfile_info. - if (choice == 0) { + if (choice == SEA_CHOICE_NONE) { // Show info about the existing swapfile. attention_message(buf, fname); @@ -3418,7 +3426,7 @@ static char *findswapname(buf_T *buf, char **dirp, char *old_fname, bool *found_ flush_buffers(FLUSH_TYPEAHEAD); } - if (swap_exists_action != SEA_NONE && choice == 0) { + if (swap_exists_action != SEA_NONE && choice == SEA_CHOICE_NONE) { const char *const sw_msg_1 = _("Swap file \""); const char *const sw_msg_2 = _("\" already exists!"); @@ -3432,56 +3440,57 @@ static char *findswapname(buf_T *buf, char **dirp, char *old_fname, bool *found_ memcpy(name, sw_msg_1, sw_msg_1_len + 1); home_replace(NULL, fname, &name[sw_msg_1_len], fname_len, true); xstrlcat(name, sw_msg_2, name_len); - choice = do_dialog(VIM_WARNING, _("VIM - ATTENTION"), - name, - process_running - ? _("&Open Read-Only\n&Edit anyway\n&Recover" - "\n&Quit\n&Abort") - : _("&Open Read-Only\n&Edit anyway\n&Recover" - "\n&Delete it\n&Quit\n&Abort"), - 1, NULL, false); - - if (process_running && choice >= 4) { - choice++; // Skip missing "Delete it" button. + int dialog_result + = do_dialog(VIM_WARNING, + _("VIM - ATTENTION"), + name, + process_running + ? _("&Open Read-Only\n&Edit anyway\n&Recover\n&Quit\n&Abort") + : _("&Open Read-Only\n&Edit anyway\n&Recover\n&Delete it\n&Quit\n&Abort"), + 1, NULL, false); + + if (process_running && dialog_result >= 4) { + // compensate for missing "Delete it" button + dialog_result++; } + choice = (sea_choice_T)dialog_result; xfree(name); // pretend screen didn't scroll, need redraw anyway msg_reset_scroll(); } - if (choice > 0) { - switch (choice) { - case 1: // "Open Read-Only" - buf->b_p_ro = true; - break; - case 2: // "Edit anyway" - break; - case 3: // "Recover" - swap_exists_action = SEA_RECOVER; - break; - case 4: // "Delete it" - os_remove(fname); - break; - case 5: // "Quit" - swap_exists_action = SEA_QUIT; - break; - case 6: // "Abort" - swap_exists_action = SEA_QUIT; - got_int = true; - break; - } - - // If the swapfile was deleted this `fname` can be used. - if (!os_path_exists(fname)) { - break; - } - } else { + switch (choice) { + case SEA_CHOICE_READONLY: // "Open Read-Only" + buf->b_p_ro = true; + break; + case SEA_CHOICE_EDIT: // "Edit anyway" + break; + case SEA_CHOICE_RECOVER: // "Recover" + swap_exists_action = SEA_RECOVER; + break; + case SEA_CHOICE_DELETE: // "Delete it" + os_remove(fname); + break; + case SEA_CHOICE_QUIT: // "Quit" + swap_exists_action = SEA_QUIT; + break; + case SEA_CHOICE_ABORT: // "Abort" + swap_exists_action = SEA_QUIT; + got_int = true; + break; + case SEA_CHOICE_NONE: msg_puts("\n"); if (msg_silent == 0) { // call wait_return() later need_wait_return = true; } + break; + } + + // If the swapfile was deleted this `fname` can be used. + if (choice != SEA_CHOICE_NONE && !os_path_exists(fname)) { + break; } } } diff --git a/src/nvim/mouse.c b/src/nvim/mouse.c index 368153cad6..0b4cd5dd14 100644 --- a/src/nvim/mouse.c +++ b/src/nvim/mouse.c @@ -132,6 +132,8 @@ static void move_tab_to_mouse(void) } } +static bool got_click = false; // got a click some time back + /// Call click definition function for column "col" in the "click_defs" array for button /// "which_button". static void call_click_def_func(StlClickDefinition *click_defs, int col, int which_button) @@ -187,6 +189,8 @@ static void call_click_def_func(StlClickDefinition *click_defs, int col, int whi typval_T rettv; (void)call_vim_function(click_defs[col].func, ARRAY_SIZE(argv), argv, &rettv); tv_clear(&rettv); + // Make sure next click does not register as drag when callback absorbs the release event. + got_click = false; } /// Translate window coordinates to buffer position without any side effects. @@ -241,14 +245,6 @@ static int get_fpos_of_mouse(pos_T *mpos) return IN_BUFFER; } -static bool mouse_got_click = false; ///< got a click some time back - -/// Reset the flag that a mouse click was seen. -void reset_mouse_got_click(void) -{ - mouse_got_click = false; -} - /// Do the appropriate action for the current mouse click in the current mode. /// Not used for Command-line mode. /// @@ -347,13 +343,13 @@ bool do_mouse(oparg_T *oap, int c, int dir, int count, bool fixindent) // Ignore drag and release events if we didn't get a click. if (is_click) { - mouse_got_click = true; + got_click = true; } else { - if (!mouse_got_click) { // didn't get click, ignore + if (!got_click) { // didn't get click, ignore return false; } if (!is_drag) { // release, reset got_click - mouse_got_click = false; + got_click = false; if (in_tab_line) { in_tab_line = false; return false; @@ -370,7 +366,7 @@ bool do_mouse(oparg_T *oap, int c, int dir, int count, bool fixindent) stuffnumReadbuff(count); } stuffcharReadbuff(Ctrl_T); - mouse_got_click = false; // ignore drag&release now + got_click = false; // ignore drag&release now return false; } @@ -594,7 +590,7 @@ bool do_mouse(oparg_T *oap, int c, int dir, int count, bool fixindent) ui_flush(); // Update before showing popup menu } show_popupmenu(); - mouse_got_click = false; // ignore release events + got_click = false; // ignore release events return (jump_flags & CURSOR_MOVED) != 0; } if (which_button == MOUSE_LEFT @@ -634,7 +630,7 @@ popupexit: // If an operator is pending, ignore all drags and releases until the next mouse click. if (!is_drag && oap != NULL && oap->op_type != OP_NOP) { - mouse_got_click = false; + got_click = false; oap->motion_type = kMTCharWise; } @@ -844,7 +840,7 @@ popupexit: } else { // location list window do_cmdline_cmd(".ll"); } - mouse_got_click = false; // ignore drag&release now + got_click = false; // ignore drag&release now } else if ((mod_mask & MOD_MASK_CTRL) || (curbuf->b_help && (mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_2CLICK)) { // Ctrl-Mouse click (or double click in a help window) jumps to the tag @@ -853,7 +849,7 @@ popupexit: stuffcharReadbuff(Ctrl_O); } stuffcharReadbuff(Ctrl_RSB); - mouse_got_click = false; // ignore drag&release now + got_click = false; // ignore drag&release now } else if ((mod_mask & MOD_MASK_SHIFT)) { // Shift-Mouse click searches for the next occurrence of the word under // the mouse pointer diff --git a/src/nvim/popupmenu.c b/src/nvim/popupmenu.c index e04d0c7acd..a6eb32ecb1 100644 --- a/src/nvim/popupmenu.c +++ b/src/nvim/popupmenu.c @@ -26,7 +26,6 @@ #include "nvim/memory.h" #include "nvim/menu.h" #include "nvim/message.h" -#include "nvim/mouse.h" #include "nvim/move.h" #include "nvim/option.h" #include "nvim/option_vars.h" @@ -1148,7 +1147,6 @@ void pum_show_popupmenu(vimmenu_T *menu) // right mouse release: select clicked item, close if any pum_select_mouse_pos(); if (pum_selected >= 0) { - reset_mouse_got_click(); pum_execute_menu(menu, mode); break; } diff --git a/test/functional/ui/statuscolumn_spec.lua b/test/functional/ui/statuscolumn_spec.lua index 73039701cd..6eaf15cfad 100644 --- a/test/functional/ui/statuscolumn_spec.lua +++ b/test/functional/ui/statuscolumn_spec.lua @@ -590,7 +590,7 @@ describe('statuscolumn', function() eq('0 1 l 11', eval("g:testvar")) end) - it('selecting popupmenu does not drag mouse', function() + it('popupmenu callback does not drag mouse on close', function() screen:try_resize(screen._width, 2) screen:set_default_attr_ids({ [0] = {foreground = Screen.colors.Brown}, @@ -604,6 +604,7 @@ describe('statuscolumn', function() popup PopupStc endfunction ]]) + -- clicking an item does not drag mouse meths.input_mouse('left', 'press', '', 0, 0, 0) screen:expect([[ {0:8 }^aaaaa | @@ -615,6 +616,19 @@ describe('statuscolumn', function() {0:8 }^aaaaa | 0 1 l 8 | ]]) + command('echo') + -- clicking outside to close the menu does not drag mouse + meths.input_mouse('left', 'press', '', 0, 0, 0) + screen:expect([[ + {0:8 }^aaaaa | + {1: Echo } | + ]]) + meths.input_mouse('left', 'press', '', 0, 0, 10) + meths.input_mouse('left', 'release', '', 0, 0, 10) + screen:expect([[ + {0:8 }^aaaaa | + | + ]]) end) end) end |