I'm editing a number of XML files now that have some kind of structure like:
<Parent>
<Child name="Fred">
Some content
</Child>
<Child name="George" value="other content" />
...
</Parent>
In other words, the content of some parent element will be a sequence of child elements (with the same name in this case). As examples, think of a list of items for sale in a catalogue, or even a sequence of <xsl:template>
in an <xsl:stylesheet>
.
What I would like to do is map some key sequence in vim to go to the next (or previous) child element when I am within the parent element, and ideally to be able to prefix this with a count (so that I can "go to the fifth next child, for example). Ideally, I will need to be outside the content of the Child element for this to make sense, so that inside the Child element I can jump between Grandchildren with the same map. I looked online for plugins/solutions to this and haven't found anything.
What I can currently do is vat<Esc>j
in the case where the next Child is on the immediate next line after the close of this Child (similarly vato<Esc>k
for preceding Child). However, I have a few problems with this:
:help v
, prefixing v
with count doesn't do what I'd like here); doing so inside the mapping (e.g. v2at) selects successively 'higher' enclosing elements.Number 2 is not hugely critical - I can probably enforce correct formatting on the files I'm editing, and can use xmllint to do this easily. I still would prefer a more 'semantic' approach for elegance and robustness, if possible. Number 3 is really not a big deal, it would just be a nice bonus if I could either stay where I am, or go to the first Child, when on the last Child. Number 4 has yet to be an issue at all for me. Maybe it will interfere with a plugin, or my work in the future, but whatever, certainly not critical.
Number 1 is the critical one though, as I frequently find myself wanting to go so many Children down. Currently, I'm looking for the Child I want to go to, glancing at my relativenumber for that line, then going that many lines down (or up). This is
Another possible solution would be to do a search for Child
and then go [count]n
or [count]N
. This has a few issues as well:
Child
myself, which is entirely not programmable; or I do something like vato<Esc>l*
which can't be prefixed by a count in the way I'd wantChild
elements inside each other (has use cases), splitting Child
elements across separate Parent
elements, when the string "Child"
appears anywhere other than as a Child
element etc.Ideally I would create some kind of function+command+mapping that would handle all of this in a robust, intelligent manner. Then I could just mindlessly use my command while editing, and have no headaches trying to record a macro that works by jumping between elements, etc. However, I am still quite new to vimscripting and am not quite sure how to begin.
They obviously don't satisfy all your requirements but these crude commands may help…
/^\s\{<C-r>=indent(".")<CR>}<\w\+\s<CR>
?^\s\{<C-r>=indent(".")<CR>}<\w\+\s<CR>
Jump forward/backward to the next XML tag at the same indentation level.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With