I'm editing a number of XML files now that have some kind of structure like:
我正在编辑一些XML文件,这些文件具有如下结构:
<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.
我想做的是在vim中一些关键序列映射到进入下一个(或之前)当我在父元素的子元素,和理想情况下能够前缀计数(这样我就能“去第五下一个孩子,例如)。理想情况下,我需要不在子元素的内容中,这样才能有意义,以便在子元素中,我可以使用相同的映射在子代元素之间跳转。我在网上找了插件/解决方案,但什么也没找到。
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:
我目前可以做的是vat
- I can't prefix this with a count; doing so before the mapping causes weird behaviour (see
:help v
, prefixingv
with count doesn't do what I'd like here); doing so inside the mapping (e.g. v2at) selects successively 'higher' enclosing elements. - 我不能用计数来给它加上前缀;在映射导致奇怪行为之前这样做(参见:help v,在v前面加上count,这不是我想要的);在映射(例如v2at)中这样做,将依次选择“更高”的包围元素。
- This won't work if the sequence of Child elements don't follow directly after each other, each opening tag following on the immediate next line from the preceding closing tag.
- 如果子元素的序列不直接跟随在一起,每个开始标记都跟随在前面结束标记的下一行,那么这将不起作用。
- If I do this on the last Child of a Parent, I'll go to the closing tag of the parent (or some of its text content if it exists, or whatever)
- 如果我在父进程的最后一个子节点上执行这个操作,那么我将访问父进程的结束标记(或者它的一些文本内容,如果它存在,或者其他什么)
- Clobbers the previously selected region
- 破坏先前选定的区域
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.
第2点不是非常关键——我可能可以对正在编辑的文件强制执行正确的格式,并且可以使用xmllint轻松实现这一点。如果可能的话,我还是希望采用更“语义化”的方法来实现优雅性和健壮性。第三个孩子并不是什么大问题,如果我可以呆在我现在的地方,或者在最后一个孩子的时候去找第一个孩子,那就更好了。对我来说,4号根本就不是问题。也许它会干扰一个插件,或者我将来的工作,但是无论如何,肯定不是关键。
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
第一个问题很关键,因为我经常发现自己想让这么多孩子失望。目前,我正在寻找我想要去的那个孩子,看了看我的亲戚,看了看那条线,然后往下(或向上)走了那么多行。这是
- Annoying, and not obvious to the way I think about the content of the XML
- 这很烦人,我对XML内容的理解也不明显
- Not easily scriptable/macroable, at least not robustly
- 不容易脚本化/宏化,至少不健壮
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:
另一种可能的解决办法是寻找孩子,然后去[count]n或[count]n。这也有一些问题:
- Either I have to think of and type the name
Child
myself, which is entirely not programmable; or I do something likevato<Esc>l*
which can't be prefixed by a count in the way I'd want -
要么我自己去想并输入名字子元素,这是完全不可编程的;或者我做一些像vato
l*的事情,它不能以我想要的方式以计数作为前缀 - Breaks when nesting
Child
elements inside each other (has use cases), splittingChild
elements across separateParent
elements, when the string"Child"
appears anywhere other than as aChild
element etc. - 当将子元素嵌套在彼此内部(有用例)时,当字符串“子”出现在除子元素之外的任何地方时(有用例),当将子元素分散到不同的父元素时,就会中断。
- Clobbers the previous search; this is a nuisance when I'm using the search to highlight something currently relevant, or still want to be able to jump to the next search item after jumping to the next element.
- 前面的搜索方法;当我使用搜索来突出显示当前相关的内容时,或者仍然想在跳转到下一个元素后跳转到下一个搜索项时,这是很麻烦的。
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.
理想情况下,我将创建某种函数+命令+映射,以一种健壮、智能的方式处理所有这些。然后,我就可以在编辑时随意地使用命令,并且不需要费力地记录一个可以在元素之间跳转的宏,等等。
3 个解决方案
#1
2
If you need this motion often, it makes sense to create a custom motion for it. With my CountJump plugin, this is very easy:
如果您经常需要这个动作,那么为它创建一个自定义动作是有意义的。使用我的CountJump插件,这很容易:
call CountJump#Motion#MakeBracketMotion('<buffer>', '', '', '<Child', '<Child.*\zs/>\|</Child>', 0)
This will modify the [[
[]
etc. motions (you can also choose other mappings), and supports a count, too. (Put this into e.g. ~/.vim/ftplugin/xml_motions.vim
.)
这将修改[[]等动作(您也可以选择其他映射),并支持计数。(把这个放到~/.vim/ftplugin/xml_motions.vim中)
#2
3
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.
在同一缩进级别上向前/向后跳转到下一个XML标记。
#3
1
I would probably just adjust the folding (you can turn on XML folding with let g:xml_syntax_folding = 1
and setlocal foldmethod=syntax
) so that the child elements are all folded (e.g. zMzr
). Then, navigation to childs is a simple "N line(s) up/down" with j
/ k
.
我可能只需要调整折叠(您可以使用let g: xml_syntax_折叠= 1和setlocal foldmethod=syntax来打开XML折叠),以便子元素都被折叠(例如zMzr)。然后,导航到childs是一个简单的“N行(s)向上/向下”,带有j / k。
#1
2
If you need this motion often, it makes sense to create a custom motion for it. With my CountJump plugin, this is very easy:
如果您经常需要这个动作,那么为它创建一个自定义动作是有意义的。使用我的CountJump插件,这很容易:
call CountJump#Motion#MakeBracketMotion('<buffer>', '', '', '<Child', '<Child.*\zs/>\|</Child>', 0)
This will modify the [[
[]
etc. motions (you can also choose other mappings), and supports a count, too. (Put this into e.g. ~/.vim/ftplugin/xml_motions.vim
.)
这将修改[[]等动作(您也可以选择其他映射),并支持计数。(把这个放到~/.vim/ftplugin/xml_motions.vim中)
#2
3
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.
在同一缩进级别上向前/向后跳转到下一个XML标记。
#3
1
I would probably just adjust the folding (you can turn on XML folding with let g:xml_syntax_folding = 1
and setlocal foldmethod=syntax
) so that the child elements are all folded (e.g. zMzr
). Then, navigation to childs is a simple "N line(s) up/down" with j
/ k
.
我可能只需要调整折叠(您可以使用let g: xml_syntax_折叠= 1和setlocal foldmethod=syntax来打开XML折叠),以便子元素都被折叠(例如zMzr)。然后,导航到childs是一个简单的“N行(s)向上/向下”,带有j / k。