aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/autoload/xmlformat.vim65
1 files changed, 43 insertions, 22 deletions
diff --git a/runtime/autoload/xmlformat.vim b/runtime/autoload/xmlformat.vim
index a3098a1730..712e6f7351 100644
--- a/runtime/autoload/xmlformat.vim
+++ b/runtime/autoload/xmlformat.vim
@@ -1,6 +1,6 @@
" Vim plugin for formatting XML
-" Last Change: 2019 Oct 24
-" Version: 0.2
+" Last Change: 2020 Jan 06
+" Version: 0.3
" Author: Christian Brabandt <cb@256bit.org>
" Repository: https://github.com/chrisbra/vim-xml-ftplugin
" License: VIM License
@@ -15,7 +15,7 @@ let s:keepcpo = &cpo
set cpo&vim
" Main function: Format the input {{{1
-func! xmlformat#Format()
+func! xmlformat#Format() abort
" only allow reformatting through the gq command
" (e.g. Vim is in normal mode)
if mode() != 'n'
@@ -40,14 +40,16 @@ func! xmlformat#Format()
continue
elseif line !~# '<[/]\?[^>]*>'
let nextmatch = match(list, '<[/]\?[^>]*>', current)
- let line .= join(list[(current + 1):(nextmatch-1)], "\n")
- call remove(list, current+1, nextmatch-1)
+ if nextmatch > -1
+ let line .= ' '. join(list[(current + 1):(nextmatch-1)], " ")
+ call remove(list, current+1, nextmatch-1)
+ endif
endif
" split on `>`, but don't split on very first opening <
" this means, items can be like ['<tag>', 'tag content</tag>']
for item in split(line, '.\@<=[>]\zs')
if s:EndTag(item)
- let s:indent = s:DecreaseIndent()
+ call s:DecreaseIndent()
call add(result, s:Indent(item))
elseif s:EmptyTag(lastitem)
call add(result, s:Indent(item))
@@ -59,13 +61,23 @@ func! xmlformat#Format()
" Simply split on '<', if there is one,
" but reformat according to &textwidth
let t=split(item, '.<\@=\zs')
+
+ " if the content fits well within a single line, add it there
+ " so that the output looks like this:
+ "
+ " <foobar>1</foobar>
+ if s:TagContent(lastitem) is# s:TagContent(t[1]) && strlen(result[-1]) + strlen(item) <= s:Textwidth()
+ let result[-1] .= item
+ let lastitem = t[1]
+ continue
+ endif
" t should only contain 2 items, but just be safe here
if s:IsTag(lastitem)
let s:indent+=1
endif
let result+=s:FormatContent([t[0]])
if s:EndTag(t[1])
- let s:indent = s:DecreaseIndent()
+ call s:DecreaseIndent()
endif
"for y in t[1:]
let result+=s:FormatContent(t[1:])
@@ -97,15 +109,15 @@ func! xmlformat#Format()
return 0
endfunc
" Check if given tag is XML Declaration header {{{1
-func! s:IsXMLDecl(tag)
+func! s:IsXMLDecl(tag) abort
return a:tag =~? '^\s*<?xml\s\?\%(version="[^"]*"\)\?\s\?\%(encoding="[^"]*"\)\? ?>\s*$'
endfunc
" Return tag indented by current level {{{1
-func! s:Indent(item)
+func! s:Indent(item) abort
return repeat(' ', shiftwidth()*s:indent). s:Trim(a:item)
endfu
" Return item trimmed from leading whitespace {{{1
-func! s:Trim(item)
+func! s:Trim(item) abort
if exists('*trim')
return trim(a:item)
else
@@ -113,44 +125,53 @@ func! s:Trim(item)
endif
endfunc
" Check if tag is a new opening tag <tag> {{{1
-func! s:StartTag(tag)
+func! s:StartTag(tag) abort
let is_comment = s:IsComment(a:tag)
return a:tag =~? '^\s*<[^/?]' && !is_comment
endfunc
" Check if tag is a Comment start {{{1
-func! s:IsComment(tag)
+func! s:IsComment(tag) abort
return a:tag =~? '<!--'
endfunc
" Remove one level of indentation {{{1
-func! s:DecreaseIndent()
- return (s:indent > 0 ? s:indent - 1 : 0)
+func! s:DecreaseIndent() abort
+ let s:indent = (s:indent > 0 ? s:indent - 1 : 0)
endfunc
" Check if tag is a closing tag </tag> {{{1
-func! s:EndTag(tag)
+func! s:EndTag(tag) abort
return a:tag =~? '^\s*</'
endfunc
" Check that the tag is actually a tag and not {{{1
" something like "foobar</foobar>"
-func! s:IsTag(tag)
+func! s:IsTag(tag) abort
return s:Trim(a:tag)[0] == '<'
endfunc
" Check if tag is empty <tag/> {{{1
-func! s:EmptyTag(tag)
+func! s:EmptyTag(tag) abort
return a:tag =~ '/>\s*$'
endfunc
+func! s:TagContent(tag) abort "{{{1
+ " Return content of a tag
+ return substitute(a:tag, '^\s*<[/]\?\([^>]*\)>\s*$', '\1', '')
+endfunc
+func! s:Textwidth() abort "{{{1
+ " return textwidth (or 80 if not set)
+ return &textwidth == 0 ? 80 : &textwidth
+endfunc
" Format input line according to textwidth {{{1
-func! s:FormatContent(list)
+func! s:FormatContent(list) abort
let result=[]
- let limit = 80
- if &textwidth > 0
- let limit = &textwidth
- endif
+ let limit = s:Textwidth()
let column=0
let idx = -1
let add_indent = 0
let cnt = 0
for item in a:list
for word in split(item, '\s\+\S\+\zs')
+ if match(word, '^\s\+$') > -1
+ " skip empty words
+ continue
+ endif
let column += strdisplaywidth(word, column)
if match(word, "^\\s*\n\\+\\s*$") > -1
call add(result, '')