Vim developers maillist, Patch: The patch "vim_option_protectncwcleol.patch" (~177.143 KB) referenced throughout this message is posted at
===== [https://gist.github.com/alexkulungowski/4cadb5450c9c4bdf03309155fd30611c][Vim option "protectncwcleol"/"pncwcleol" patch · GitHub] ===== . I recommend reading all of this message before viewing the patch. Preamble: I suspect proposals similar to the present one have been made before. If so, please consider this message and the posted patch my vote for the addition of equivalent functionality, with the patch in particular standing as a measure of the earnestness of my vote. The vague formulation "equivalent functionality" in the previous sentence refers to something that somehow in most of the likely cases circumvents the irritating problem I describe below. I view this patch as entirely provisional: it is merely one of the less painful of the many possible solutions I've considered over the years. I have been using variations of this patch in production contexts for weeks without any obvious problems. Before I started developing this patch, I read the entirety of ===== [https://github.com/vim/vim/blob/master/runtime/doc/todo.txt][vim/todo.txt at master · vim/vim · GitHub] ===== and did not see anything analogous to what I need. I did not find much of use through online searches, either, though that might be because I searched for the wrong thing. If there are other solutions to the problem I describe below, please inform me of them. I haven't yet used Neovim, but if it provides a solution please let me know. Problem: For years now I have been using large (and steadily increasing) numbers of windows and tabs in conjunction with ":mksession" and "vim -S". I cannot remember precisely when I began developing these habits, but for as long as I have been relying on the relevant features, I have kept the following selection from ":help tab-page-intro" well in mind: ===== :help tab-page-intro ... ... ... Tabs are also a nice way to edit a buffer temporarily without changing the current window layout. Open a new tab page, do whatever you want to do and close the tab page. ... ... ... ===== . This technique is quite useful, but I have frequently been irked when an unintentional, mistyped, or otherwise malformed command --- in short, a mistake --- disrupts multiple windows in a manner that is often not conveniently recoverable. The type of accidental multi-window disruption I wish to avoid is best demonstrated by an executable example. Starting with a single window open on an empty unnamed buffer, execute the following commands: ===== :call append(0, split("Line 1.\nLine 2.\nLine 3.\nLine 4.\nLine 5.\nLine 6.\nLine 7.\nLine 8.\nLine 9.\nLine 10.\n", '\n')) :execute "normal! Gdd" | redraw! :silent execute "1 | split | resize 1 | wincmd j | 4 | split | resize 1 | wincmd j | 7 | split | resize 1 | wincmd j | 10 | 2wincmd k | resize" ===== . Note the line number of each of the four windows, which, to be explicit, is the buffer line number of the associated window's cursor. I will refer to the buffer line number of a window's cursor as that window's "wcl_lnum", which is an abbreviation of "window current line line number". (One might wonder why I don't reference a/the window's cursor or cursor position in this identifier or throughout the rest of this message, for that matter. I promise I have reasons.) Now execute the following commands: ===== :tab split :normal! 7G0dG ===== . Assume that at this point you realize that you've made a mistake and should have deleted only the eighth line. Execute the following commands: ===== :undo :quit ===== . The screen position, height, and width of each window, i.e., layout without regard to contents, in the first tab are unchanged, as are the "wcl_lnum"s of the first and second windows from the top of the screen; the "wcl_lnum"s of the third and fourth windows, however, are now both "6", their ordering lost. This example is simple and contrived, but imagine a much more complex arrangement of windows and tabs viewing a single large file. Then consider making a single hasty mistake --- deleting the wrong section, for example --- that silently obliterates the "wcl_lnum" ordering of tens or even hundreds of windows distributed among the non-current (and therefore non-visible at the time the mistake is made) tabs. Note that there are critical cases where I _expect_ "wcl_lnum" ordering to be invalidated and/or lost, particularly those involving a file that is altered outside of the current Vim process (say, by Git) and subsequently reloaded (after a helpful warning) via ":edit". I have developed ways of recovering from the "wcl_lnum" disruptions produced in such situations, but these techniques, which can still be somewhat time consuming, depend on preparation, and the only way I know of to prepare for a silent multiple-"wcl_lnum"-flattening mistake is to regularly back up the file produced by ":mksession". Proposal: I propose adding the global/buffer-local boolean option "protectncwcleol"/"pncwcleol", where "ncwcl" stands for "non-current window current line" and "eol", as you may have guessed, "end of line". According to ":help 'protectncwcleol'" (from "vim_option_protectncwcleol.patch:runtime/doc/options.txt"): ===== :help 'protectncwcleol' ... ... ... 'protectncwcleol' 'pncwcleol' boolean (default off) global or local to buffer |global-local| {not in Vi} {only available when compiled with the |+protectncwcleol| feature} When on, prevent deletion of non-current window current line EOLs. A non-current window current line is a line in the current buffer that is the current line of at least one window other than the current window. If this option has a local value, use this command to switch back to using the global value: > :setlocal protectncwcleol< < ... ... ... ===== . In the example provided in the problem statement above, executing ":set protectncwcleol" before the ":normal! 7G0dG" command would result in the latter deleting the entire seventh line up to but not including the E.O.L. and producing the "semsg()" message "EXXX: is_ncwcl_lnum(): 7". The posted patch referenced at the beginning of this message contains the "protectncwcleol"(/"pncwcleol")-related modifications I have made to ===== [https://github.com/vim/vim/commit/de19b745eee06a8a204988ae9989d97143caece9][patch 8.2.1093: Python: double free when adding item to dict fails · vim/vim@de19b74 · GitHub] ===== (this is the most recent "master" branch commit according to "git merge-base", anyway, and is dated "Mon Jun 29 23:07:44 2020 +0200"). In addition to changes to existing files, this patch includes the new file "vim_option_protectncwcleol.patch:src/testdir/test_option_protectncwcleol.vim" containing a testing framework developed in parallel with the "protectncwcleol" option. The "protectncwcleol" testing framework is currently the most comprehensive documentation of the "protectncwcleol" option's expected behaviour. Describing this expected behaviour in prose would take some effort, and before I do that I'd like to see if anyone on this maillist has any suggestions. To give you a rough idea of the command coverage involved in implementing the current version of the "protectncwcleol" option, the "protectncwcleol" testing framework currently includes over fifty tests. As stated in the preamble, I have been using (variations of) this patch in production contexts (almost) every day for weeks now without any issues. If you decide to try out this patch, please be aware of the following: --- More testing can always be done. There could be gaping holes in coverage, paths to mass "wcl_lnum" collapse that I've overlooked. There could be catastrophic bugs that have yet to emerge. Some "protectncwcleol" command restrictions might be too severe. --- To be clear, the line number of a "ncwcl" is not protected when "protectncwcleol" is on and neither is the line number delta between any two "ncwcl"s (unless the "ncwcl"s are the same line). --- The emphasis is on protecting a "ncwcl"'s E.O.L., not the pre-E.O.L. contents of a "ncwcl". When "protectncwcleol" is on, altering the pre-E.O.L. contents of a "ncwcl" is allowed except for the insertion of another E.O.L. (e.g., by pressing [ENTER] in insert mode) or the joining of a "ncwcl" with the preceding line (e.g., by issuing [BACKSPACE] in insert mode at the start of a "ncwcl" with "lnum > 1"). --- All undo and redo command variants (should...) respect the relevant "protectncwcleol" setting. I find this _extremely_ useful. --- Because of the implementation details of certain commands, the protection of "ncwcleol"s from these commands produces somewhat counterintuitive results. Provided that the current window does not become a non-current window and no further edits are made, all such changes are (read "should be") immediately (and safely with respect to any "ncwcleol"s) undoable. --- I don't use the mouse terminal features or the GUI (in fact, I usually execute "vim" with the "-X" option). I don't foresee any conflicts between those features and this patch, but I haven't done anything to confirm this hunch, either. --- I use a grand total of one Vim plugin that isn't prepackaged: "linediff.vim" ( ===== [https://www.vim.org/scripts/script.php?script_id=3745][linediff.vim - Perform an interactive diff on two blocks of text : vim online] ===== ). I rely on "linediff.vim" rather heavily (it's wonderful... but if there's anything else out there that's better, please let me know) and am reasonably certain that it functions correctly with the (effectively buffer-local) option setting "noprotectncwcleol". --- The "protectncwcleol" testing framework is integrated into Vim's "make test" framework but its source code does not conform to any of the coding styles of any of the other tests. From the perspective of Vim's "make test" framework, the fifty-plus tests contained within the "protectncwcleol" testing framework function as a single pass/fail test. One way to execute the "protectncwcleol" testing framework directly is to start a new Vim instance with a single window open on an empty unnamed buffer and then issue the (equivalent of the) following command: ===== :source src/testdir/test_option_protectncwcleol.vim | call Test_ExecuteVimOptionProtectncwcleolPncwcleolTester() ===== . . Alex -- -- You received this message from the "vim_dev" maillist. Do not top-post! Type your reply below the text you are replying to. For more information, visit http://www.vim.org/maillist.php --- You received this message because you are subscribed to the Google Groups "vim_dev" group. To unsubscribe from this group and stop receiving emails from it, send an email to vim_dev+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/vim_dev/CADt82rrp60arCvU8FidQyrx477cZNjbnZC5O%2BVw5ki%3DNXT_7-w%40mail.gmail.com.