Hi Vimmers, The other day I felt the need for a command/function which did a :substitute on a *copy* of each line matching its search pattern and inserted that copy below the original, unmodified line. I soon realized that it would be much easier to first make a copy of each (unmodified) line, then execute the :substitute on the original line, and lastly insert the unmodified copy above the original line if the original line had been modified, as determined by comparing the possibly modified original line to the always unmodified copy.
I soon found that I also had a use case for getting the modified line above the unmodified one, so I needed a way to tell the command/function to do that -- obviously a bang on the command and an extra argument on the function. This is what I came up with after some experimentation: ```VimL " Insert a copy of the original unmodified line if " a line was affected by :substitute " Usage: [range]:AS[!] s/{pattern}/{replacement}/[flags] " With ! the unmodified line is inserted below, without it above func! s:appendAndSubst(subst, bang) range let nobang = empty(a:bang) " was :AS called without a bang? " We must handle the range ourselves, to prevent " already visited or inserted lines from being visited (again) let lnum = a:firstline " loop variable let last = a:lastline " we'll probably increment it! while lnum <= last " go to the current line exe ':normal ' . lnum . 'G' " get original text of line let origline = getline(lnum) " do the subst " I don't want to use substitute() because I want to " be able to use flags exe a:subst " was the current line modified? if origline !=# getline(lnum) " should we insert the original line " above (bang) " or below (no bang) " the current line " it will appear as if the modified line was inserted " below the original without a bang " and above the original with a bang " but in reality the unmodified line is a copy! let anum = nobang ? lnum - 1 : lnum " insert the line call append(anum,origline) " we added a line so let last += 1 " our range just became one line longer! let lnum += 2 " skip over the inserted/modified line else let lnum += 1 " no modification so just go to next line endif endwhile endfunc com! -range -bang -nargs=1 AS :<line1>,<line2>call <SID>appendAndSubst(<f-args>, '<bang>') ``` Originally I intended the command to behave similarly to :global, defaulting to operating on the whole buffer unless an explicit range was given, but I soon found that I sometimes wanted to find eligible lines using :global itself and a pattern different from the substitution pattern, and doing this with -nargs=% ended in disaster, as the range given to :global was invisible to my command, so my command operated on the whole file anyway (I should have realized that to begin with, I realize! :-) The solution was to use -range instead of -range=% and use an empty pattern on the :AS argument if I use :g and want to use the same pattern on :s I now have the following questions: * (How) can I make this simpler? (Obviously) * (How) can I restore the original :g-like default behavior and still be able to use an actual :g with a separate pattern when I want to? N.B. that the -nargs=1 is important to me: I don't want to have to do an extra level of escaping in the :s expression! * The fact that the function actually modifies the original line 'breaks' marks in terms of the desired apparent behavior, where the modification is made on a copy. How can I avoid that? * Obviously one could have any expression which modifies the line as argument, but I can't think up an example. Anyone who can? * Has someone had this idea before, or am I the lone loonie? * There is something builtin which does this, isn't there? ;-) -- -- You received this message from the "vim_use" 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_use" group. To unsubscribe from this group and stop receiving emails from it, send an email to vim_use+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.