Tuesday, October 22, 2013

Re: Place a sign on each line between two regexps

On Tuesday, October 22, 2013 8:04:19 AM UTC-5, esquifit wrote:
> My first attempt was something like this:
>
> g:/start/+1;/end/-1 exe 'sign place 1 name='.line('.').' file='.expand('%:p')
>
> But this yielded a E481. Apparently exe doesn't support address ranges.
>

You are correct, exe does not support ranges. But you're also using your
g command wrong. See below.

> Next thing I attempted was using macros:
>
> let @q=':sign place 1 name=CIInsert line= =line(".")^M file= =expand("%:p")^M^M'
>
>
>
> With this definition, echo @q yields:
>
> :sign place 1 name=Foo line=^R=line(".")^M file=^R=expand("%:p")^M^M
>
> and this produces the desired result when I @q on any line.
>
>
>
> Using this in combination with an address range:
>
> g:/start/+1;/end/-1 @q
>
> only puts a sign next to the last line of each region. This suggest
> I'm misinterpreting the way g://;// works.

I think you are very confused how the :g command works. In this last
command, I think you're also confused about the difference between
normal mode and command-line mode.

I THINK you are trying to execute your macro q as if in normal mode, on
all lines between a "start" and an "end".

The :g command takes a SINGLE pattern, and on all lines matching that
pattern, it will execute a SINGLE ex (command-line) command. The g,
pattern, and command are all separated with a delimiter. The delimiter
is the same between all of them.

So to start with, writing @q as the command does not do what you want.
If you want @q to act like you typed it in normal mode, you need to use
the ex command, :normal! @q

Next, you're trying to use a start and end pattern with the :g command.
But you can only use one pattern.

If you had ONE group you wanted to execute your code on, you could use a
range with the :g command. For example,

:/start/+1,/end/-1g#^#normal! @q

In this case, the start and end patterns make a range for the :g
command. This command will run on the next start...end group after the
cursor only, but will execute on all lines inside that group. I used the
'#' character as a delimiter in this case for the :g command, which will
match every line within the range, because I just used '^' as the
pattern which matches the beginning of any line. Finally, the normal!
command will run your q macro.

But you have multiple start...end blocks. So instead, I'd suggest
running the :g command on the entire buffer. You should run the command
on lines matching "start" and the command should be created in a way to
affect all lines of interest relative to that "start" line. In this
case, you could do it like this:

:g#start#+1,/end/-1normal! @q

Again I use # for the delimiter for the :g command. The :g command will
run a command on every line matching "start" because that is the pattern
I give it. The command it runs is the same :normal command, but it will
execute on every line in a range. The range is defined to run starting
from "+1": i.e. from the next line after the one the :g command is
currently running on; i.e. the first line below "start". The range is
defined to run ending at /end/-1, i.e. the last line above the next
occurrence of "end".

Note that so far I've been using your second approach, to run a recorded
macro. I don't actually like this approach, I think your :exe approach
is better. But as you discovered, :exe does not take a range so you
can't just drop it in as a replacement for :normal! above. My first try
was chaining together :g commands, but I guess that's not allowed. There
may be a better way, but at this point I would just do an explicit loop:

:g#start#let line=line('.')+1 | while getline(line)!~'end' | exe 'sign place 1 name=Foo line='.line.' file='.expand('%:p') | let line+=1 | endwhile

Or maybe a normal command with a range:

:g#start#+1,/end/-1normal! :exe 'sign place 1 name=Foo line='.line('.').' file='.expand('%:p')^M

Or, make a function:

function! PlaceSigns(linenum)
let line=a:linenum+1
while getline(line)!~'end'
exe 'sign place 1 name=Foo line='.line.' file='.expand('%:p')
let line+=1
endwhile
endfun

:g#start#call PlaceSigns(line('.'))

--
--
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/groups/opt_out.

No comments: