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.

Reply via email to