Reputation: 4029
I have files that look like the following:
>>Start-pattern
some text
some more text
>>Start-pattern
some other text
some more other text
>>Start-pattern
[and so on]
What I would like to have is a mapping that allows me to delete the current "block" of text. Where "block" is defined as all lines ranging from ">>Start-pattern" until before the next ">>Start-pattern" line.
What I have is the following:
nnoremap ,d $:?^>>Start-pattern?,/^>>Start-pattern/-1delete<CR>
that works unless I'm standing on the last "block" in a file.
How can I get this map (or a completely different one that does the same thing) to work on all "blocks" in the file?
Upvotes: 2
Views: 662
Reputation: 4029
Thanks a lot for the nice answers, guys!
In the end I went for the most maintainable/robust one. Building on Whaledawg's answer and taking Luc Hermitte's comment into account I ended up with:
fun! DelBlock(pat)
let startLine = search(a:pat, "nbcW")
let endLine = search(a:pat, "nW")
if startLine == 0
echo "Block '".a:pat."' not found"
return
end
if endLine == 0
let endLine = line("$")
else
let endLine = endLine-1
end
execute startLine.","endLine."delete"
endfunction
nmap ,d :call DelBlock("^>>Start-pattern")<CR>
Upvotes: 2
Reputation: 72926
You can do it with a single regex:
nnoremap ,d :1,.s/\v%(%(.*%#&(\>\>Start-pattern))%(\1@!\_.)+)\|%((\>\>Start-pattern)%(\2@!\_.)*%#%(\2@!\_.)+)//
Whether you should is another question...
Upvotes: 6
Reputation: 4286
I think, once again, we're pushing the boundaries of regular expressions past what they are good at. They are good at swapping one string with another, it's a side effect that you can delete text with them.
Instead why not take advantage of the charming scripting language vim provides. It's easier and like a trip on the way-back machine. If you add the following function to your .vimrc file, it will do what you want and be more reusable/flexible:
fun! DelBlock(thePattern)
let origLineNumber = line(".")
let lineNumber = origLineNumber
let lineString = getline(lineNumber)
while lineString !~ a:thePattern
let lineNumber = lineNumber - 1
if lineNumber < 0
echo "Function not found :/"
endif
let lineString = getline(lineNumber)
endwhile
let startLine = lineNumber
let lastLineInFile = line("$")
let lineNumber = origLineNumber + 1
let lineString = getline(lineNumber)
while lineNumber != lastLineInFile && lineString !~ a:thePattern
let lineNumber = lineNumber + 1
let lineString = getline(lineNumber)
endwhile
let endLine = lineNumber
if endLine != lastLineInFile
let endLine = endLine - 1
end
execute startLine.","endLine."d"
endfunction
map ,d :call DelBlock("^>>Start-pattern")<CR>
Upvotes: 7
Reputation: 89043
Here's a possible hack.
nnoremap ,d maGo>>Start-pattern<Esc>'a$?^>>Start-pattern<CR>dNmaGdd'a
ma - mark your current position
G - go to the end of the file
o>>Start-pattern<Esc> - append your pattern line
'a - go back to your prior position
$ - go to the end of the current line
?^>>Start-pattern<CR> - find the previous occurrence of the pattern
dN - delete until the next occurence
ma - mark your current position
G - go to the end of the file
dd - delete the last line of the file
'a - return to your previous position
I originally tried to get \%$
(end of file) to work, but I couldn't get the deletion
to include the last character in the file. So I tried this way instead.
I've done some testing, and it seems to work for me (intermediate blocks and last block).
Upvotes: 3