Den 2014-10-02 16:33, Tim Chase skrev:
> 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
> 

[Back from a rather bad cold...]

Thanks for the reply!

I had tried the `:g/something/t.|s/foo/bar/ge` trick, but it does what I want 
only when the `:g` pattern and the `:s` pattern are the same; otherwise it 
copies all lines which match the `:g` pattern, whether the `:s` does anything 
to that line or not, the whole point of my function being to avoid just that 
and copy only lines which are actually affected by the `:s` -- i.e where the 
`:s` pattern matches, so there is an ecological niche for my function anyway. I 
guess the only way to preserve marks on the original line is to always copy it, 
apply the `:s` to the copy and then delete the copy again if it is still 
identical to the original line, which seems terribly wasteful even if it makes 
the function simpler:



```VimL
" Copy each line in range, apply :subst to the copy 
"   and delete it again if it was unaltered!
"   :[range]GS[!] s/{search}/{replacement}/[flags]
" without ! the copy is pasted with p (below original)
" with ! the copy is pasted with P (above the original)
func! s:copy_on_subst(subst, bang) range
    let p = empty(a:bang) ? 'p' : 'P' " insert copy below or above?
    let curline = a:firstline
    let lastline = a:lastline
    while curline <= lastline
        " make a copy of the current line, and end up on the copy
        exe ':norm ' . curline . 'Gyy' . p 
        " apply the :subst (or whatever) to the copy
        exe a:subst
        " if the copy and the original are still identical
        " i.e. if the :subst didn't match anything
        if getline(curline) == getline(curline+1)
            " the two interesting lines are always the one at the
            " current line number and the one below, regardless of which
            " of them is the copy or the original!
            "
            " delete the copy if it was unaltered
            exe ':norm dd'
            " jump to the next line
            let curline+=1
        else    " if the copy line was altered by the :subst
            let lastline+=1 " our range just got one line longer
            let curline+=   " jump past the original/copy line
        endif
    endwhile
endfunc
:com! -nargs=1 -bang -range GS :<line1>,<line2>call 
<SID>copy_on_subst(<f-args>, '<bang>')
```

-- 
-- 
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.

Reply via email to