Mercurial > vim
comparison runtime/autoload/xmlformat.vim @ 19574:d4deb2e50667
Update runtime files
Commit: https://github.com/vim/vim/commit/eab6dff19f387469a200011bc6cf3508f5e43a4a
Author: Bram Moolenaar <Bram@vim.org>
Date: Sun Mar 1 19:06:45 2020 +0100
Update runtime files
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Sun, 01 Mar 2020 19:15:04 +0100 |
parents | 6d11fc4aa683 |
children |
comparison
equal
deleted
inserted
replaced
19573:9d0db06b6ad2 | 19574:d4deb2e50667 |
---|---|
1 " Vim plugin for formatting XML | 1 " Vim plugin for formatting XML |
2 " Last Change: 2019 Oct 24 | 2 " Last Change: 2020 Jan 06 |
3 " Version: 0.2 | 3 " Version: 0.3 |
4 " Author: Christian Brabandt <cb@256bit.org> | 4 " Author: Christian Brabandt <cb@256bit.org> |
5 " Repository: https://github.com/chrisbra/vim-xml-ftplugin | 5 " Repository: https://github.com/chrisbra/vim-xml-ftplugin |
6 " License: VIM License | 6 " License: VIM License |
7 " Documentation: see :h xmlformat.txt (TODO!) | 7 " Documentation: see :h xmlformat.txt (TODO!) |
8 " --------------------------------------------------------------------- | 8 " --------------------------------------------------------------------- |
13 let g:loaded_xmlformat = 1 | 13 let g:loaded_xmlformat = 1 |
14 let s:keepcpo = &cpo | 14 let s:keepcpo = &cpo |
15 set cpo&vim | 15 set cpo&vim |
16 | 16 |
17 " Main function: Format the input {{{1 | 17 " Main function: Format the input {{{1 |
18 func! xmlformat#Format() | 18 func! xmlformat#Format() abort |
19 " only allow reformatting through the gq command | 19 " only allow reformatting through the gq command |
20 " (e.g. Vim is in normal mode) | 20 " (e.g. Vim is in normal mode) |
21 if mode() != 'n' | 21 if mode() != 'n' |
22 " do not fall back to internal formatting | 22 " do not fall back to internal formatting |
23 return 0 | 23 return 0 |
38 if empty(line) | 38 if empty(line) |
39 call add(result, '') | 39 call add(result, '') |
40 continue | 40 continue |
41 elseif line !~# '<[/]\?[^>]*>' | 41 elseif line !~# '<[/]\?[^>]*>' |
42 let nextmatch = match(list, '<[/]\?[^>]*>', current) | 42 let nextmatch = match(list, '<[/]\?[^>]*>', current) |
43 let line .= join(list[(current + 1):(nextmatch-1)], "\n") | 43 if nextmatch > -1 |
44 call remove(list, current+1, nextmatch-1) | 44 let line .= ' '. join(list[(current + 1):(nextmatch-1)], " ") |
45 call remove(list, current+1, nextmatch-1) | |
46 endif | |
45 endif | 47 endif |
46 " split on `>`, but don't split on very first opening < | 48 " split on `>`, but don't split on very first opening < |
47 " this means, items can be like ['<tag>', 'tag content</tag>'] | 49 " this means, items can be like ['<tag>', 'tag content</tag>'] |
48 for item in split(line, '.\@<=[>]\zs') | 50 for item in split(line, '.\@<=[>]\zs') |
49 if s:EndTag(item) | 51 if s:EndTag(item) |
50 let s:indent = s:DecreaseIndent() | 52 call s:DecreaseIndent() |
51 call add(result, s:Indent(item)) | 53 call add(result, s:Indent(item)) |
52 elseif s:EmptyTag(lastitem) | 54 elseif s:EmptyTag(lastitem) |
53 call add(result, s:Indent(item)) | 55 call add(result, s:Indent(item)) |
54 elseif s:StartTag(lastitem) && s:IsTag(item) | 56 elseif s:StartTag(lastitem) && s:IsTag(item) |
55 let s:indent += 1 | 57 let s:indent += 1 |
57 else | 59 else |
58 if !s:IsTag(item) | 60 if !s:IsTag(item) |
59 " Simply split on '<', if there is one, | 61 " Simply split on '<', if there is one, |
60 " but reformat according to &textwidth | 62 " but reformat according to &textwidth |
61 let t=split(item, '.<\@=\zs') | 63 let t=split(item, '.<\@=\zs') |
64 | |
65 " if the content fits well within a single line, add it there | |
66 " so that the output looks like this: | |
67 " | |
68 " <foobar>1</foobar> | |
69 if s:TagContent(lastitem) is# s:TagContent(t[1]) && strlen(result[-1]) + strlen(item) <= s:Textwidth() | |
70 let result[-1] .= item | |
71 let lastitem = t[1] | |
72 continue | |
73 endif | |
62 " t should only contain 2 items, but just be safe here | 74 " t should only contain 2 items, but just be safe here |
63 if s:IsTag(lastitem) | 75 if s:IsTag(lastitem) |
64 let s:indent+=1 | 76 let s:indent+=1 |
65 endif | 77 endif |
66 let result+=s:FormatContent([t[0]]) | 78 let result+=s:FormatContent([t[0]]) |
67 if s:EndTag(t[1]) | 79 if s:EndTag(t[1]) |
68 let s:indent = s:DecreaseIndent() | 80 call s:DecreaseIndent() |
69 endif | 81 endif |
70 "for y in t[1:] | 82 "for y in t[1:] |
71 let result+=s:FormatContent(t[1:]) | 83 let result+=s:FormatContent(t[1:]) |
72 "endfor | 84 "endfor |
73 else | 85 else |
95 | 107 |
96 " do not run internal formatter! | 108 " do not run internal formatter! |
97 return 0 | 109 return 0 |
98 endfunc | 110 endfunc |
99 " Check if given tag is XML Declaration header {{{1 | 111 " Check if given tag is XML Declaration header {{{1 |
100 func! s:IsXMLDecl(tag) | 112 func! s:IsXMLDecl(tag) abort |
101 return a:tag =~? '^\s*<?xml\s\?\%(version="[^"]*"\)\?\s\?\%(encoding="[^"]*"\)\? ?>\s*$' | 113 return a:tag =~? '^\s*<?xml\s\?\%(version="[^"]*"\)\?\s\?\%(encoding="[^"]*"\)\? ?>\s*$' |
102 endfunc | 114 endfunc |
103 " Return tag indented by current level {{{1 | 115 " Return tag indented by current level {{{1 |
104 func! s:Indent(item) | 116 func! s:Indent(item) abort |
105 return repeat(' ', shiftwidth()*s:indent). s:Trim(a:item) | 117 return repeat(' ', shiftwidth()*s:indent). s:Trim(a:item) |
106 endfu | 118 endfu |
107 " Return item trimmed from leading whitespace {{{1 | 119 " Return item trimmed from leading whitespace {{{1 |
108 func! s:Trim(item) | 120 func! s:Trim(item) abort |
109 if exists('*trim') | 121 if exists('*trim') |
110 return trim(a:item) | 122 return trim(a:item) |
111 else | 123 else |
112 return matchstr(a:item, '\S\+.*') | 124 return matchstr(a:item, '\S\+.*') |
113 endif | 125 endif |
114 endfunc | 126 endfunc |
115 " Check if tag is a new opening tag <tag> {{{1 | 127 " Check if tag is a new opening tag <tag> {{{1 |
116 func! s:StartTag(tag) | 128 func! s:StartTag(tag) abort |
117 let is_comment = s:IsComment(a:tag) | 129 let is_comment = s:IsComment(a:tag) |
118 return a:tag =~? '^\s*<[^/?]' && !is_comment | 130 return a:tag =~? '^\s*<[^/?]' && !is_comment |
119 endfunc | 131 endfunc |
120 " Check if tag is a Comment start {{{1 | 132 " Check if tag is a Comment start {{{1 |
121 func! s:IsComment(tag) | 133 func! s:IsComment(tag) abort |
122 return a:tag =~? '<!--' | 134 return a:tag =~? '<!--' |
123 endfunc | 135 endfunc |
124 " Remove one level of indentation {{{1 | 136 " Remove one level of indentation {{{1 |
125 func! s:DecreaseIndent() | 137 func! s:DecreaseIndent() abort |
126 return (s:indent > 0 ? s:indent - 1 : 0) | 138 let s:indent = (s:indent > 0 ? s:indent - 1 : 0) |
127 endfunc | 139 endfunc |
128 " Check if tag is a closing tag </tag> {{{1 | 140 " Check if tag is a closing tag </tag> {{{1 |
129 func! s:EndTag(tag) | 141 func! s:EndTag(tag) abort |
130 return a:tag =~? '^\s*</' | 142 return a:tag =~? '^\s*</' |
131 endfunc | 143 endfunc |
132 " Check that the tag is actually a tag and not {{{1 | 144 " Check that the tag is actually a tag and not {{{1 |
133 " something like "foobar</foobar>" | 145 " something like "foobar</foobar>" |
134 func! s:IsTag(tag) | 146 func! s:IsTag(tag) abort |
135 return s:Trim(a:tag)[0] == '<' | 147 return s:Trim(a:tag)[0] == '<' |
136 endfunc | 148 endfunc |
137 " Check if tag is empty <tag/> {{{1 | 149 " Check if tag is empty <tag/> {{{1 |
138 func! s:EmptyTag(tag) | 150 func! s:EmptyTag(tag) abort |
139 return a:tag =~ '/>\s*$' | 151 return a:tag =~ '/>\s*$' |
140 endfunc | 152 endfunc |
153 func! s:TagContent(tag) abort "{{{1 | |
154 " Return content of a tag | |
155 return substitute(a:tag, '^\s*<[/]\?\([^>]*\)>\s*$', '\1', '') | |
156 endfunc | |
157 func! s:Textwidth() abort "{{{1 | |
158 " return textwidth (or 80 if not set) | |
159 return &textwidth == 0 ? 80 : &textwidth | |
160 endfunc | |
141 " Format input line according to textwidth {{{1 | 161 " Format input line according to textwidth {{{1 |
142 func! s:FormatContent(list) | 162 func! s:FormatContent(list) abort |
143 let result=[] | 163 let result=[] |
144 let limit = 80 | 164 let limit = s:Textwidth() |
145 if &textwidth > 0 | |
146 let limit = &textwidth | |
147 endif | |
148 let column=0 | 165 let column=0 |
149 let idx = -1 | 166 let idx = -1 |
150 let add_indent = 0 | 167 let add_indent = 0 |
151 let cnt = 0 | 168 let cnt = 0 |
152 for item in a:list | 169 for item in a:list |
153 for word in split(item, '\s\+\S\+\zs') | 170 for word in split(item, '\s\+\S\+\zs') |
171 if match(word, '^\s\+$') > -1 | |
172 " skip empty words | |
173 continue | |
174 endif | |
154 let column += strdisplaywidth(word, column) | 175 let column += strdisplaywidth(word, column) |
155 if match(word, "^\\s*\n\\+\\s*$") > -1 | 176 if match(word, "^\\s*\n\\+\\s*$") > -1 |
156 call add(result, '') | 177 call add(result, '') |
157 let idx += 1 | 178 let idx += 1 |
158 let column = 0 | 179 let column = 0 |