2

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.

dotancohen
  • 30,064
  • 36
  • 138
  • 197

2 Answers2

3

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

Community
  • 1
  • 1
sehe
  • 374,641
  • 47
  • 450
  • 633
  • Thank you very much, this is 99% of the way to what I need! I did not realise the need for the `` characters. However, this mapping also selects the leading `<![CDATA[` text and one trailing `]`. Inserting a `8l` and `2h` in the appropriate places does not work if the CDATA delimiters are on their own lines. Is there any way to prevent the selection of these characters? – dotancohen Mar 26 '12 at 14:43
  • Thanks. It is still catching the `[` and `]` (even differently for multiline and singleline CDATA sections), this can be seen by `x`ing the selected text. I am reading about operator-pending type mapping now, I have never heard of it before. Thanks. – dotancohen Mar 26 '12 at 16:03
  • Does `space` (instead of `l`) and `backspace` (instead of `j`) work? They work across linebreaks IIRC – sehe Mar 26 '12 at 16:23
  • Thanks. With `` one character from the beginning of the single-line string is not copied! I'll try some creative ``ing and `h`ing to see if I can get the right result. – dotancohen Mar 26 '12 at 17:17
  • In retrospect, I really only need this function on multiline CDATA sections anyway. It works fine for that purpose, so I will leave it at that until I can learn operator-pending type mapping. Thank you very much for your assistance! – dotancohen Mar 26 '12 at 17:31
1

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
Tom Whittock
  • 4,081
  • 19
  • 24
  • Thank you. Like sese's code, it this mapping catches the `[` and `]` characters from `<![CDATA[` and `]]>`. I am trying to play with it to see if I can remove those characters reliably. Multiline CDATA sections are the trouble because `h` and `l` cannot be used to simply move the cursor. – dotancohen Mar 26 '12 at 16:05