summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorq12321q <q12321q@gmail.com>2017-05-18 10:31:12 +0200
committerw0rp <w0rp@users.noreply.github.com>2017-05-18 09:31:12 +0100
commitcdf0fb39e532b0e0ed67ac8dcd088b58d822b74e (patch)
tree912b27dfcf41db0f879d9f6ae214b2aca9ef2af0
parent3ca70cb841aa352eef56545e72188d0420cfa3f2 (diff)
downloadale-cdf0fb39e532b0e0ed67ac8dcd088b58d822b74e.zip
Add xmllint linter (#559)
* Add xmllint linter for xml
-rw-r--r--README.md1
-rw-r--r--ale_linters/xml/xmllint.vim69
-rw-r--r--doc/ale-xml.txt26
-rw-r--r--doc/ale.txt3
-rw-r--r--test/command_callback/test_xmllint_command_callback.vader25
-rw-r--r--test/handler/test_xmllint_handler.vader30
6 files changed, 154 insertions, 0 deletions
diff --git a/README.md b/README.md
index fc3d1d35..f0b382b9 100644
--- a/README.md
+++ b/README.md
@@ -115,6 +115,7 @@ name. That seems to be the fairest way to arrange this table.
| Vim | [vint](https://github.com/Kuniwak/vint) |
| Vim help^ | [proselint](http://proselint.com/)|
| XHTML | [proselint](http://proselint.com/)|
+| XML | [xmllint](http://xmlsoft.org/xmllint.html/)|
| YAML | [yamllint](https://yamllint.readthedocs.io/) |
* *^ No linters for text or Vim help filetypes are enabled by default.*
diff --git a/ale_linters/xml/xmllint.vim b/ale_linters/xml/xmllint.vim
new file mode 100644
index 00000000..63d7f768
--- /dev/null
+++ b/ale_linters/xml/xmllint.vim
@@ -0,0 +1,69 @@
+" Author: q12321q <q12321q@gmail.com>
+" Description: This file adds support for checking XML code with xmllint.
+
+" CLI options
+let g:ale_xml_xmllint_executable = get(g:, 'ale_xml_xmllint_executable', 'xmllint')
+let g:ale_xml_xmllint_options = get(g:, 'ale_xml_xmllint_options', '')
+
+function! ale_linters#xml#xmllint#GetExecutable(buffer) abort
+ return ale#Var(a:buffer, 'xml_xmllint_executable')
+endfunction
+
+function! ale_linters#xml#xmllint#GetCommand(buffer) abort
+ return ale#Escape(ale_linters#xml#xmllint#GetExecutable(a:buffer))
+ \ . ' ' . ale#Var(a:buffer, 'xml_xmllint_options')
+ \ . ' --noout -'
+endfunction
+
+function! ale_linters#xml#xmllint#Handle(buffer, lines) abort
+ " Matches patterns lines like the following:
+ " file/path:123: error level : error message
+ let l:pattern_message = '\v^([^:]+):(\d+):\s*(([^:]+)\s*:\s+.*)$'
+
+ " parse column token line like that:
+ " file/path:123: parser error : Opening and ending tag mismatch: foo line 1 and bar
+ " </bar>
+ " ^
+ let l:pattern_column_token = '\v^\s*\^$'
+
+ let l:output = []
+
+ for l:line in a:lines
+
+ " Parse error/warning lines
+ let l:match_message = matchlist(l:line, l:pattern_message)
+ if !empty(l:match_message)
+ let l:line = l:match_message[2] + 0
+ let l:type = l:match_message[4] =~? 'warning' ? 'W' : 'E'
+ let l:text = l:match_message[3]
+
+ call add(l:output, {
+ \ 'lnum': l:line,
+ \ 'text': l:text,
+ \ 'type': l:type,
+ \})
+
+ continue
+ endif
+
+ " Parse column position
+ let l:match_column_token = matchlist(l:line, l:pattern_column_token)
+ if !empty(l:output) && !empty(l:match_column_token)
+ let l:previous = l:output[len(l:output) - 1]
+ let l:previous['col'] = len(l:match_column_token[0])
+
+ continue
+ endif
+
+ endfor
+
+ return l:output
+endfunction
+
+call ale#linter#Define('xml', {
+\ 'name': 'xmllint',
+\ 'output_stream': 'stderr',
+\ 'executable_callback': 'ale_linters#xml#xmllint#GetExecutable',
+\ 'command_callback': 'ale_linters#xml#xmllint#GetCommand',
+\ 'callback': 'ale_linters#xml#xmllint#Handle',
+\ })
diff --git a/doc/ale-xml.txt b/doc/ale-xml.txt
new file mode 100644
index 00000000..ee10730f
--- /dev/null
+++ b/doc/ale-xml.txt
@@ -0,0 +1,26 @@
+===============================================================================
+ALE XML Integration *ale-xml-options*
+
+
+-------------------------------------------------------------------------------
+xmllint *ale-xml-xmllint*
+
+g:ale_xml_xmllint_executable *g:ale_xml_xmllint_executable*
+ *b:ale_xml_xmllint_executable*
+ Type: |String|
+ Default: `'xmllint'`
+
+ This variable can be set to change the path to xmllint.
+
+
+g:ale_xml_xmllint_options *g:ale_xml_xmllint_options*
+ *b:ale_xml_xmllint_options*
+ Type: |String|
+ Default: `''`
+
+ This variable can be set to pass additional options to xmllint.
+
+
+-------------------------------------------------------------------------------
+ vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:
+
diff --git a/doc/ale.txt b/doc/ale.txt
index 52a709bb..615fa271 100644
--- a/doc/ale.txt
+++ b/doc/ale.txt
@@ -85,6 +85,8 @@ CONTENTS *ale-contents*
tslint..............................|ale-typescript-tslint|
vim...................................|ale-vim-options|
vint................................|ale-vim-vint|
+ xml...................................|ale-xml-options|
+ xmllint.............................|ale-xml-xmllint|
yaml..................................|ale-yaml-options|
yamllint............................|ale-yaml-yamllint|
5. Commands/Keybinds....................|ale-commands|
@@ -177,6 +179,7 @@ The following languages and tools are supported.
* Vim: 'vint'
* Vim help: 'proselint'
* XHTML: 'proselint'
+* XML: 'xmllint'
* YAML: 'yamllint'
===============================================================================
diff --git a/test/command_callback/test_xmllint_command_callback.vader b/test/command_callback/test_xmllint_command_callback.vader
new file mode 100644
index 00000000..7c0b1963
--- /dev/null
+++ b/test/command_callback/test_xmllint_command_callback.vader
@@ -0,0 +1,25 @@
+Before:
+ runtime ale_linters/xml/xmllint.vim
+
+After:
+ call ale#linter#Reset()
+ let g:ale_xml_xmllint_options = ''
+ let g:ale_xml_xmllint_executable = 'xmllint'
+
+Execute(The xml xmllint command callback should return the correct default string):
+ AssertEqual '''xmllint'' --noout -',
+ \ join(split(ale_linters#xml#xmllint#GetCommand(1)))
+
+Execute(The xml xmllint command callback should let you set options):
+ let g:ale_xml_xmllint_options = '--xinclude --postvalid'
+
+ AssertEqual '''xmllint'' --xinclude --postvalid --noout -',
+ \ join(split(ale_linters#xml#xmllint#GetCommand(1)))
+
+Execute(The xmllint executable should be configurable):
+ let g:ale_xml_xmllint_executable = '~/.local/bin/xmllint'
+
+ AssertEqual '~/.local/bin/xmllint', ale_linters#xml#xmllint#GetExecutable(1)
+ AssertEqual '''~/.local/bin/xmllint'' --noout -',
+ \ join(split(ale_linters#xml#xmllint#GetCommand(1)))
+
diff --git a/test/handler/test_xmllint_handler.vader b/test/handler/test_xmllint_handler.vader
new file mode 100644
index 00000000..4a377ab3
--- /dev/null
+++ b/test/handler/test_xmllint_handler.vader
@@ -0,0 +1,30 @@
+Before:
+ runtime ale_linters/xml/xmllint.vim
+
+Execute(The xmllint handler should parse error messages correctly):
+ AssertEqual
+ \ [
+ \ {
+ \ 'lnum': 1,
+ \ 'col': 22,
+ \ 'type': 'W',
+ \ 'text': 'warning: Unsupported version ''dummy'''
+ \ },
+ \ {
+ \ 'lnum': 34,
+ \ 'col': 1,
+ \ 'type': 'E',
+ \ 'text': 'parser error : Start tag expected, ''<'' not found'
+ \ }
+ \ ],
+ \ ale_linters#xml#xmllint#Handle(1, [
+ \ 'path/to/file.xml:1: warning: Unsupported version ''dummy''',
+ \ '<?xml version="dummy"?>',
+ \ ' ^',
+ \ '-:34: parser error : Start tag expected, ''<'' not found',
+ \ 'blahblah>',
+ \ '^'
+ \ ])
+
+After:
+ call ale#linter#Reset()