To: vim_dev@googlegroups.com Subject: Patch 8.2.4685 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.4685 Problem: When a swap file is found for a popup there is no dialog and the buffer is loaded anyway. Solution: Silently load the buffer read-only. (closes #10073) Files: runtime/doc/popup.txt, src/memline.c, src/popupwin.c, src/vim.h, src/buffer.c, src/testdir/test_popupwin.vim *** ../vim-8.2.4684/runtime/doc/popup.txt 2021-11-29 17:37:38.059265225 +0000 --- runtime/doc/popup.txt 2022-04-04 16:42:17.060508340 +0100 *************** *** 260,267 **** Can also be used as a |method|: > GetPopup()->popup_close() popup_create({what}, {options}) *popup_create()* ! Open a popup window showing {what}, which is either: - a buffer number - a string - a list of strings --- 260,268 ---- Can also be used as a |method|: > GetPopup()->popup_close() + popup_create({what}, {options}) *popup_create()* ! Open a popup window showing {what}, which is either: *E450* - a buffer number - a string - a list of strings *************** *** 270,275 **** --- 271,281 ---- 'buftype' set to "popup". That buffer will be wiped out once the popup closes. + if {what} is a buffer number and loading the buffer runs into + an existing swap file, it is silently opened read-only, as if + a |SwapExists| autocommand had set |v:swapchoice| to 'o'. + This is because we assume the buffer is only used for viewing. + {options} is a dictionary with many possible entries. See |popup_create-arguments| for details. *** ../vim-8.2.4684/src/memline.c 2022-03-23 13:54:47.968796508 +0000 --- src/memline.c 2022-04-04 16:29:37.610753055 +0100 *************** *** 4631,4649 **** --no_wait_return; } #if defined(FEAT_EVAL) /* * Trigger the SwapExists autocommands. ! * Returns 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_u *fname) { set_vim_var_string(VV_SWAPNAME, fname, -1); --- 4631,4652 ---- --no_wait_return; } + 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; + #if defined(FEAT_EVAL) /* * Trigger the SwapExists autocommands. ! * Returns a value for equivalent to do_dialog(). */ ! static sea_choice_T do_swapexists(buf_T *buf, char_u *fname) { set_vim_var_string(VV_SWAPNAME, fname, -1); *************** *** 4659,4673 **** switch (*get_vim_var_str(VV_SWAPCHOICE)) { ! case 'o': return 1; ! case 'e': return 2; ! case 'r': return 3; ! case 'd': return 4; ! case 'q': return 5; ! case 'a': return 6; } ! return 0; } #endif --- 4662,4676 ---- switch (*get_vim_var_str(VV_SWAPCHOICE)) { ! case 'o': return SEA_CHOICE_READONLY; ! case 'e': return SEA_CHOICE_EDIT; ! case 'r': return SEA_CHOICE_RECOVER; ! case 'd': return SEA_CHOICE_DELETE; ! case 'q': return SEA_CHOICE_QUIT; ! case 'a': return SEA_CHOICE_ABORT; } ! return SEA_CHOICE_NONE; } #endif *************** *** 4986,4995 **** if (differ == FALSE && !(curbuf->b_flags & BF_RECOVERED) && vim_strchr(p_shm, SHM_ATTENTION) == NULL) { ! int choice = 0; ! stat_T st; #ifdef CREATE_DUMMY_FILE ! int did_use_dummy = FALSE; // Avoid getting a warning for the file being created // outside of Vim, it was created at the start of this --- 4989,4998 ---- if (differ == FALSE && !(curbuf->b_flags & BF_RECOVERED) && vim_strchr(p_shm, SHM_ATTENTION) == NULL) { ! sea_choice_T choice = SEA_CHOICE_NONE; ! stat_T st; #ifdef CREATE_DUMMY_FILE ! int did_use_dummy = FALSE; // Avoid getting a warning for the file being created // outside of Vim, it was created at the start of this *************** *** 5013,5019 **** if (mch_stat((char *)buf->b_fname, &st) == 0 && swapfile_unchanged(fname)) { ! choice = 4; if (p_verbose > 0) verb_msg(_("Found a swap file that is not useful, deleting it")); } --- 5016,5022 ---- if (mch_stat((char *)buf->b_fname, &st) == 0 && swapfile_unchanged(fname)) { ! choice = SEA_CHOICE_DELETE; if (p_verbose > 0) verb_msg(_("Found a swap file that is not useful, deleting it")); } *************** *** 5024,5036 **** * the response, trigger it. It may return 0 to ask the * user anyway. */ ! if (choice == 0 && swap_exists_action != SEA_NONE && has_autocmd(EVENT_SWAPEXISTS, buf_fname, buf)) choice = do_swapexists(buf, fname); - - if (choice == 0) #endif { #ifdef FEAT_GUI // If we are supposed to start the GUI but it wasn't --- 5027,5046 ---- * the response, trigger it. It may return 0 to ask the * user anyway. */ ! if (choice == SEA_CHOICE_NONE && swap_exists_action != SEA_NONE && has_autocmd(EVENT_SWAPEXISTS, buf_fname, buf)) choice = do_swapexists(buf, fname); #endif + + if (choice == SEA_CHOICE_NONE + && swap_exists_action == SEA_READONLY) + { + // always open readonly. + choice = SEA_CHOICE_READONLY; + } + + if (choice == SEA_CHOICE_NONE) { #ifdef FEAT_GUI // If we are supposed to start the GUI but it wasn't *************** *** 5053,5061 **** } #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) ! if (swap_exists_action != SEA_NONE && choice == 0) { char_u *name; name = alloc(STRLEN(fname) + STRLEN(_("Swap file \"")) --- 5063,5073 ---- } #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) ! if (swap_exists_action != SEA_NONE ! && choice == SEA_CHOICE_NONE) { char_u *name; + int dialog_result; name = alloc(STRLEN(fname) + STRLEN(_("Swap file \"")) *************** *** 5067,5073 **** 1000, TRUE); STRCAT(name, _("\" already exists!")); } ! choice = do_dialog(VIM_WARNING, (char_u *)_("VIM - ATTENTION"), name == NULL ? (char_u *)_("Swap file already exists!") --- 5079,5085 ---- 1000, TRUE); STRCAT(name, _("\" already exists!")); } ! dialog_result = do_dialog(VIM_WARNING, (char_u *)_("VIM - ATTENTION"), name == NULL ? (char_u *)_("Swap file already exists!") *************** *** 5079,5087 **** (char_u *)_("&Open Read-Only\n&Edit anyway\n&Recover\n&Delete it\n&Quit\n&Abort"), 1, NULL, FALSE); # ifdef HAVE_PROCESS_STILL_RUNNING ! if (process_still_running && choice >= 4) ! choice++; // Skip missing "Delete it" button # endif vim_free(name); // pretend screen didn't scroll, need redraw anyway --- 5091,5101 ---- (char_u *)_("&Open Read-Only\n&Edit anyway\n&Recover\n&Delete it\n&Quit\n&Abort"), 1, NULL, FALSE); # ifdef HAVE_PROCESS_STILL_RUNNING ! if (process_still_running && dialog_result >= 4) ! // compensate for missing "Delete it" button ! dialog_result++; # endif + choice = dialog_result; vim_free(name); // pretend screen didn't scroll, need redraw anyway *************** *** 5090,5130 **** } #endif ! if (choice > 0) { ! switch (choice) ! { ! case 1: ! buf->b_p_ro = TRUE; ! break; ! case 2: ! break; ! case 3: ! swap_exists_action = SEA_RECOVER; ! break; ! case 4: ! mch_remove(fname); ! break; ! case 5: ! swap_exists_action = SEA_QUIT; ! break; ! case 6: ! swap_exists_action = SEA_QUIT; ! got_int = TRUE; ! break; ! } ! ! // If the file was deleted this fname can be used. ! if (mch_getperm(fname) < 0) break; } ! else ! { ! msg_puts("\n"); ! if (msg_silent == 0) ! // call wait_return() later ! need_wait_return = TRUE; ! } #ifdef CREATE_DUMMY_FILE // Going to try another name, need the dummy file again. --- 5104,5140 ---- } #endif ! switch (choice) { ! case SEA_CHOICE_READONLY: ! buf->b_p_ro = TRUE; ! break; ! case SEA_CHOICE_EDIT: ! break; ! case SEA_CHOICE_RECOVER: ! swap_exists_action = SEA_RECOVER; ! break; ! case SEA_CHOICE_DELETE: ! mch_remove(fname); ! break; ! case SEA_CHOICE_QUIT: ! swap_exists_action = SEA_QUIT; ! break; ! case SEA_CHOICE_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 file was deleted this fname can be used. ! if (choice != SEA_CHOICE_NONE && mch_getperm(fname) < 0) ! break; #ifdef CREATE_DUMMY_FILE // Going to try another name, need the dummy file again. *** ../vim-8.2.4684/src/popupwin.c 2022-04-04 15:16:50.738014123 +0100 --- src/popupwin.c 2022-04-04 16:22:28.453341176 +0100 *************** *** 1989,1995 **** --- 1989,1997 ---- new_buffer = FALSE; win_init_popup_win(wp, buf); set_local_options_default(wp, FALSE); + swap_exists_action = SEA_READONLY; buffer_ensure_loaded(buf); + swap_exists_action = SEA_NONE; } else { *** ../vim-8.2.4684/src/vim.h 2022-04-03 18:01:39.659574455 +0100 --- src/vim.h 2022-04-04 16:23:03.313062173 +0100 *************** *** 1250,1255 **** --- 1250,1256 ---- #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 /* * Minimal size for block 0 of a swap file. *** ../vim-8.2.4684/src/buffer.c 2022-04-03 11:22:33.524172298 +0100 --- src/buffer.c 2022-04-04 16:37:25.485185250 +0100 *************** *** 150,156 **** aco_save_T aco; aucmd_prepbuf(&aco, buf); ! swap_exists_action = SEA_NONE; open_buffer(FALSE, NULL, 0); aucmd_restbuf(&aco); } --- 150,157 ---- aco_save_T aco; aucmd_prepbuf(&aco, buf); ! if (swap_exists_action != SEA_READONLY) ! swap_exists_action = SEA_NONE; open_buffer(FALSE, NULL, 0); aucmd_restbuf(&aco); } *************** *** 1053,1062 **** int count) { bufref_T old_curbuf; set_bufref(&old_curbuf, curbuf); ! swap_exists_action = SEA_DIALOG; (void)do_buffer(*eap->cmd == 's' ? DOBUF_SPLIT : DOBUF_GOTO, start, dir, count, eap->forceit); if (swap_exists_action == SEA_QUIT && *eap->cmd == 's') --- 1054,1065 ---- int count) { bufref_T old_curbuf; + int save_sea = swap_exists_action; set_bufref(&old_curbuf, curbuf); ! 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); if (swap_exists_action == SEA_QUIT && *eap->cmd == 's') *************** *** 1071,1077 **** // Quitting means closing the split window, nothing else. win_close(curwin, TRUE); ! swap_exists_action = SEA_NONE; swap_exists_did_quit = TRUE; #if defined(FEAT_EVAL) --- 1074,1080 ---- // Quitting means closing the split window, nothing else. win_close(curwin, TRUE); ! swap_exists_action = save_sea; swap_exists_did_quit = TRUE; #if defined(FEAT_EVAL) *** ../vim-8.2.4684/src/testdir/test_popupwin.vim 2022-04-02 15:31:48.301003446 +0100 --- src/testdir/test_popupwin.vim 2022-04-04 16:48:55.207757192 +0100 *************** *** 2775,2780 **** --- 2775,2800 ---- call delete('XsomeFile') endfunc + func Test_popupwin_buffer_with_swapfile() + call writefile(['some text', 'in a buffer'], 'XopenFile') + call writefile([''], '.XopenFile.swp') + let g:ignoreSwapExists = 1 + + let bufnr = bufadd('XopenFile') + call assert_equal(0, bufloaded(bufnr)) + let winid = popup_create(bufnr, {'hidden': 1}) + call assert_equal(1, bufloaded(bufnr)) + call popup_close(winid) + + exe 'buffer ' .. bufnr + call assert_equal(1, &readonly) + bwipe! + + call delete('XopenFile') + call delete('.XopenFile.swp') + unlet g:ignoreSwapExists + endfunc + func Test_popupwin_terminal_buffer() CheckFeature terminal CheckUnix *** ../vim-8.2.4684/src/version.c 2022-04-04 15:46:37.606126838 +0100 --- src/version.c 2022-04-04 16:41:56.460551672 +0100 *************** *** 752,753 **** --- 752,755 ---- { /* Add new patch number below this line */ + /**/ + 4685, /**/ -- If an elephant is left tied to a parking meter, the parking fee has to be paid just as it would for a vehicle. [real standing law in Florida, United States of America] /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// \\\ \\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///