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.

Reply via email to