On 2014-10-02 16:17, BPJ wrote: > 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. [snip] > 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!
These two can be combined into one answer. For your initial case, I'd use :g/^/t.|s/foo/bar/ge (the "e" flag suppresses the error in the event the line doesn't contain "foo") which can of course be limited by range: :'<,'>g/^/t.|s/foo/bar/ge or to a subset of lines containing "baz" :g/baz/t.|s/foo/bar/ge And if you want to change the destination to the line *above* rather than the line below, just tell it where to copy the line to: :g/^/t-2|s/foo/bar/g You could even gather the modified lines at the bottom of your file: :g/^/t$|s/foo/bar/g > * 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? The "t." command should leave the original line untouched, so it shouldn't mess with marks/folds. > * 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? While not *frequently*, I do use this fairly regularly. > * There is something builtin which does this, isn't there? ;-) All the parts are in the box, you just have to assemble them in the right order. :-) -tim -- -- 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 [email protected]. For more options, visit https://groups.google.com/d/optout.
