dotancohen
dotancohen

Reputation: 31491

VIM: Scripting a selection of the entire CDATA section

I am trying to select an entire XML CDATA section with VIM. For those unfamiliar with XML, a CDATA section looks like this:

<someTag><![CDATA[
This text is escaped in a Character Data section!
Look, I can use < and > characters freely!
]]></someTag>

<anotherTag><![CDATA[More escaped text!]]></anotherTag>

I tried this mapping to visually select and yank the text inside the CDATA section, but it appears that the call function disables visual selection:

inoremap <F9> <Esc>:call searchpair('<!\[CDATA\[', '', ']]>', 'b')v:call searchpair('<!\[CDATA\[', '', ']]>')y

Is there any way to select the entire CDATA section? This is what I use to select methods in C-based languages, for reference:

inoremap <F7> <Esc><C-V>aBy

Thank you.

Upvotes: 2

Views: 155

Answers (2)

sehe
sehe

Reputation: 393354

This fixed version works for me

 :inoremap <F9> <Esc>:call searchpair('<!\[CDATA\[', '', ']]>', 'b')<CR>
      v:<C-u>call searchpair('<!\[CDATA\[', '', ']]>')<CR>v`<o

(no linebreak in real life)

Tricks:

  • <CR> for the necessary Enter keys
  • <C-u> to clear the range on the commandline
  • v` to reselect to the start of the visual selection
  • o to move cursor to end of visual selection

I'm surprised that this would be an insert mode mapping, I'm assuming you have normal mode mappings too.

By the way, perhaps you'd be interested in operator pending mode mappings for 'proper' text-object semantics too:

Edit Update in response to comment:

The following appears to work (judicious use of \zs and \ze in the search pattern). You might want to back-track one position (add <BS> to the end of the mapping). Also, by now, the operator-pending type mapping seems to get more attractive.

:inoremap <F9> <Esc>:call searchpair('<!\[CDATA\[\zs', '', '\ze]]>', 'b')<CR>
    v:<C-u>call searchpair('<!\[CDATA\[\zs', '', '\ze]]>')<CR>v`<o

PS.: You may want to apply an explicit magic-level (e.g. \V) inside your search patterns as well

Upvotes: 3

Tom Whittock
Tom Whittock

Reputation: 4230

When you're making text objects it's important not to wrap around the file.

:call searchpair('<!\[CDATA\[', '', ']]>', 'bW')|call searchpair('<!\[CDATA\[', '', ']]>', 'sW')|norm v''o

Using the 's' flag sets the ' mark, which is nice.

Using the 'W' flag makes sure we don't do EOF wrapping, which is important.

Also, insert mode mappings generally benefit from <C-O>, although in this case not so much. Still, it's a good habit to get into. So:

:inoremap <F9> <C-O>:<C-U>call searchpair('<!\[CDATA\[', '', ']]>', 'bW')|call searchpair('<!\[CDATA\[', '', ']]>', 'sW')|norm v''o

Upvotes: 1

Related Questions