Как я могу перейти к следующему родному элементу XML с помощью Vim?
Теперь я редактирую несколько XML файлов, которые имеют некоторую структуру вроде:
<Parent>
<Child name="Fred">
Some content
</Child>
<Child name="George" value="other content" />
...
</Parent>
Другими словами, содержимое некоторого родительского элемента будет представлять собой последовательность дочерних элементов (с таким же именем в этом случае). В качестве примера подумайте о списке предметов для продажи в каталоге или даже о последовательности <xsl:template>
в <xsl:stylesheet>
.
То, что я хотел бы сделать, это сопоставить некоторую последовательность клавиш в vim, чтобы перейти к следующему (или предыдущему) дочернему элементу, когда я вхожу в родительский элемент, и в идеале, чтобы иметь возможность префикс этого с подсчетом (чтобы я может, например, "перейти к пятому следующему ребенку" ). В идеале мне нужно будет находиться вне содержимого элемента Child, чтобы это имело смысл, так что внутри элемента Child я могу прыгать между внуками с той же картой. смотрел онлайн для плагинов/решений для этого и ничего не нашел.
В настоящее время я могу сделать vat<Esc>j
в том случае, когда следующий ребенок находится на следующей следующей строке после закрытия этого Ребенка (аналогично vato<Esc>k
для предыдущего ребенка). Однако у меня есть несколько проблем с этим:
- Я не могу префикс это с помощью count; делая это до того, как отображение вызывает странное поведение (см.
:help v
, префикс v
с подсчетом не делает то, что я хотел бы здесь); делая это внутри отображения (например, v2at) последовательно выбирает "более высокие" окружающие элементы.
- Это не будет работать, если последовательность дочерних элементов не будет следовать сразу друг за другом, каждый из которых будет открываться в следующей следующей строке из предыдущего закрывающего тега.
- Если я делаю это на последнем дочернем элементе родителя, я перейду к закрывающему тегу родителя (или некоторого его текстового содержимого, если он существует, или что-то еще)
- Снимает ранее выбранную область
Номер 2 не имеет особого значения - я могу, вероятно, обеспечить правильное форматирование файлов, которые я редактирую, и могу использовать xmllint для этого легко. Я по-прежнему предпочитаю более "семантический" подход к элегантности и надежности, если это возможно.
Номер 3 действительно не имеет большого значения, это было бы просто отличным бонусом, если бы я мог остаться там, где я есть, или пойти к первому Ребенку, когда на последнем Ребенке.
Номер 4 все еще должен быть проблемой для меня. Возможно, это будет мешать плагину или моей работе в будущем, но что угодно, конечно, не критично.
Номер 1 является критическим, хотя, как я часто нахожу, что хочу пойти так много детей вниз. В настоящее время я ищу Ребенка, к которому я хочу пойти, взглянув на мой релятивируемый номер для этой линии, затем перейдя к этому множеству строк (или вверх). Это
- Раздражающе, и не очевидно, как я думаю о содержании XML
- Нелегко записывать сценарии/макросъемки, по крайней мере, не надежно
Другим возможным решением было бы выполнить поиск Child
, а затем перейти [count]n
или [count]n
. Это также имеет несколько проблем:
- Либо я должен думать, и называть имя
Child
сам, что полностью не программируется; или я делаю что-то вроде vato<Esc>l*
, которое не может быть префиксным счетчиком так, как хотелось бы
- Разрывы при вложении элементов
Child
внутри друг друга (имеют прецеденты), разделение элементов Child
на отдельные элементы Parent
, когда строка "Child"
появляется где угодно, кроме как Child
и т.д.
- Скрывает предыдущий поиск; это неприятность, когда я использую поиск, чтобы выделить что-то актуальное в данный момент, или все же хочу, чтобы можно было перейти к следующему элементу поиска после перехода к следующему элементу.
В идеале я бы создал какую-то функцию + команду + сопоставление, которая бы справлялась со всем этим надежным, интеллектуальным образом. Тогда я мог просто бездумно использовать мою команду во время редактирования и не имею головных болей, пытающихся записать макрос, который работает, перепрыгивая между элементами и т.д. Однако я все еще совершенно новичок в vimscripting и не совсем уверен, как начать.
Ответы
Ответ 1
Если вам нужно это движение часто, имеет смысл создать для него настраиваемое движение. С моим плагином CountJump это очень просто:
call CountJump#Motion#MakeBracketMotion('<buffer>', '', '', '<Child', '<Child.*\zs/>\|</Child>', 0)
Это изменит движение [[
[]
и т.д. (вы также можете выбрать другие сопоставления) и также поддерживает подсчет. (Поместите это, например, ~/.vim/ftplugin/xml_motions.vim
.)
Ответ 2
Они явно не удовлетворяют всем вашим требованиям, но эти грубые команды могут помочь...
/^\s\{<C-r>=indent(".")<CR>}<\w\+\s<CR>
?^\s\{<C-r>=indent(".")<CR>}<\w\+\s<CR>
Переход вперед/назад к следующему тегу XML на том же уровне отступов.
Ответ 3
Я бы, скорее всего, просто отрегулировал складку (вы можете включить фальцовку XML с помощью let g:xml_syntax_folding = 1
и setlocal foldmethod=syntax
), чтобы дочерние элементы были свернуты (например, zMzr
). Затем навигация по дочерним элементам является простой "нитью (вверх)" с помощью j
/k
.