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 vim_use+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
No comments:
Post a Comment