diff --git a/ale_linters/openscad/sca2d.vim b/ale_linters/openscad/sca2d.vim new file mode 100644 index 00000000..60804a13 --- /dev/null +++ b/ale_linters/openscad/sca2d.vim @@ -0,0 +1,24 @@ +" Description: SCA2D linter for OpenSCAD files + +call ale#Set('openscad_sca2d_executable', 'sca2d') +call ale#Set('openscad_sca2d_options', '') + +function! ale_linters#openscad#sca2d#GetExecutable(buffer) abort + return ale#Var(a:buffer, 'openscad_sca2d_executable') +endfunction + +function! ale_linters#openscad#sca2d#GetCommand(buffer) abort + let l:executable = ale_linters#openscad#sca2d#GetExecutable(a:buffer) + let l:options = ale#Var(a:buffer, 'openscad_sca2d_options') + + return ale#Escape(l:executable) . ale#Pad(l:options) . ' %s' +endfunction + +call ale#linter#Define('openscad', { +\ 'name': 'SCA2D', +\ 'aliases': ['sca2d'], +\ 'executable': function('ale_linters#openscad#sca2d#GetExecutable'), +\ 'command': function('ale_linters#openscad#sca2d#GetCommand'), +\ 'callback': 'ale#handlers#openscad#SCA2D_callback', +\ 'lint_file': 1, +\ }) diff --git a/autoload/ale/handlers/openscad.vim b/autoload/ale/handlers/openscad.vim new file mode 100644 index 00000000..33eee31c --- /dev/null +++ b/autoload/ale/handlers/openscad.vim @@ -0,0 +1,73 @@ +scriptencoding utf-8LE +" Description: This file defines a handler function for linting OpenSCAD files +" with SCA2D + +function! ale#handlers#openscad#SCA2D_callback(buffer, lines) abort + " Example output:: + " foo.scad:3:1: W2001: Variable `unused` overwritten within scope. + " foo.scad:1:1: F0001: Cannot read file due to syntax error: + " - No terminal matches '}' in the current parser context, at line 1 col 36 + let l:filename_re = '^\([^:]*\):' + let l:linenum_re = '\([0-9]*\):' + let l:colnum_re = '\([0-9]*\):' + let l:err_id = '\([IWEFU][0-9]\+\):' + let l:err_msg = '\(.*\)' + let l:pattern = filename_re . + \ linenum_re . + \ colnum_re . + \ ' ' . + \ err_id . + \ ' ' . + \ err_msg + + let l:result = [] + let l:idx = 0 + + for l:line in a:lines + let l:matches = matchlist(line, pattern) + + if len(matches) > 0 + " option: Info, Warning, Error, Fatal, Unknown + if index(['I', 'W'], matches[4][0]) >= 0 + let l:type = 'W' + else + let l:type = 'E' + endif + + let l:lnum = matches[2] + let l:col = matches[3] + let l:text = matches[5] + + " Better locations for some syntax errors + if matches[4][0] is# 'F' + let l:syntax_error_re = '^\(.*\), at line \([0-9]\+\) col \([0-9]\+\)$' + let l:next_line = a:lines[idx+1] + let l:syn_err_matches = matchlist(l:next_line, l:syntax_error_re) + + if len(syn_err_matches) > 0 + let l:text = l:text . l:syn_err_matches[1] + let l:lnum = l:syn_err_matches[2] + let l:col = l:syn_err_matches[3] + else + let l:text = l:next_line + endif + endif + + let l:element = { + \ 'lnum': str2nr(l:lnum), + \ 'col': str2nr(l:col), + \ 'text': l:text, + \ 'detail': l:matches[4] . ': ' . l:text, + \ 'filename': fnamemodify(matches[1], ':p'), + \ 'type': l:type + \ } + + call add(l:result, l:element) + endif + + let l:idx += 1 + endfor + + return result + +endfun diff --git a/doc/ale-openscad.txt b/doc/ale-openscad.txt new file mode 100644 index 00000000..ac416bc3 --- /dev/null +++ b/doc/ale-openscad.txt @@ -0,0 +1,25 @@ +=============================================================================== +ALE OpenSCAD Integration *ale-openscad-options* + + +=============================================================================== +sca2d *ale-openscad-sca2d* + +g:ale_openscad_sca2d_executable *g:ale_openscad_sca2d_executable* + *b:ale_openscad_sca2d_executable* + Type: |String| + Default: `'sca2d'` + + See |ale-integrations-local-executables| + + +g:ale_openscad_sca2d_options *g:ale_openscad_sca2d_options* + *b:ale_openscad_sca2d_options* + Type: |String| + Default: `''` + + This variable can be set to pass options to sca2d. + + +=============================================================================== + vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: diff --git a/doc/ale-supported-languages-and-tools.txt b/doc/ale-supported-languages-and-tools.txt index a0a7fbd5..a0a20c7e 100644 --- a/doc/ale-supported-languages-and-tools.txt +++ b/doc/ale-supported-languages-and-tools.txt @@ -396,6 +396,8 @@ Notes: * `ibm_validator` * `prettier` * `yamllint` +* OpenSCAD + * `SCA2D` * Packer * `packer-fmt-fixer` * Pascal diff --git a/doc/ale.txt b/doc/ale.txt index 828d5e2d..ff1af720 100644 --- a/doc/ale.txt +++ b/doc/ale.txt @@ -3051,6 +3051,8 @@ documented in additional help files. ibm_validator.........................|ale-openapi-ibm-validator| prettier..............................|ale-openapi-prettier| yamllint..............................|ale-openapi-yamllint| + openscad................................|ale-openscad-options| + sca2d.................................|ale-openscad-sca2d| packer..................................|ale-packer-options| packer-fmt-fixer......................|ale-packer-fmt-fixer| pascal..................................|ale-pascal-options| diff --git a/supported-tools.md b/supported-tools.md index 7a71c14c..bdad2b3b 100644 --- a/supported-tools.md +++ b/supported-tools.md @@ -405,6 +405,8 @@ formatting. * [ibm_validator](https://github.com/IBM/openapi-validator) * [prettier](https://github.com/prettier/prettier) * [yamllint](https://yamllint.readthedocs.io/) +* OpenSCAD + * [SCA2D](https://gitlab.com/bath_open_instrumentation_group/sca2d) :floppy_disk: * Packer (HCL) * [packer-fmt-fixer](https://github.com/hashicorp/packer) * Pascal diff --git a/test/handler/test_openscad_handler.vader b/test/handler/test_openscad_handler.vader new file mode 100644 index 00000000..36071cc7 --- /dev/null +++ b/test/handler/test_openscad_handler.vader @@ -0,0 +1,76 @@ +Before: + call ale#test#SetDirectory('/testplugin/test/handler') + + " Load sca2d + runtime ale_linters/openscad/sca2d.vim + +After: + call ale#test#RestoreDirectory() + call ale#linter#Reset() + +Execute(The openscad handler should handle sca2d output): + AssertEqual + \ [ + \ { + \ 'filename': ale#path#Simplify(g:dir . '/awesome_project.scad'), + \ 'lnum': 7, + \ 'type': 'E', + \ 'col': 42, + \ 'text': 'Module `corcle` used but never defined.', + \ 'detail': 'E2002: Module `corcle` used but never defined.', + \ }, + \ ], + \ ale#handlers#openscad#SCA2D_callback(bufnr(''), [ + \ 'awesome_project.scad:7:42: E2002: Module `corcle` used but never defined.', + \ '', + \ 'SCA2D message summary', + \ '=====================', + \ 'Fatal errors: 0', + \ 'Errors: 1', + \ 'Warnings: 0', + \ 'Info: 0', + \ 'Depreciated 0', + \ ]) + + AssertEqual + \ [ + \ { + \ 'filename': ale#path#Simplify(g:dir . '/awesome_project.scad'), + \ 'lnum': 1, + \ 'type': 'E', + \ 'col': 37, + \ 'text': 'Cannot read file due to syntax error: - No terminal matches ''}'' in the current parser context', + \ 'detail': 'F0001: Cannot read file due to syntax error: - No terminal matches ''}'' in the current parser context', + \ }, + \ ], + \ ale#handlers#openscad#SCA2D_callback(bufnr(''), [ + \ 'awesome_project.scad:1:1: F0001: Cannot read file due to syntax error:', + \ ' - No terminal matches ''}'' in the current parser context, at line 1 col 37', + \ ' - ', + \ ' - translate([ 0, 0, 0 ]) { circle(10) }', + \ ' - ^', + \ ' - Expected one of: ', + \ ' - * IF', + \ ' - * LET', + \ ' - * FOR', + \ ' - * FUNC_CALL_NAME', + \ ' - * TERMINATION', + \ ' - * STAR', + \ ' - * LBRACE', + \ ' - * BANG', + \ ' - * ASSIGN', + \ ' - * PERCENT', + \ ' - * HASH', + \ ' - * INTERSECTION_FOR', + \ ' - ', + \ 'If you belive this is a bug in SCA2D please report it to us.', + \ '', + \ '', + \ 'SCA2D message summary', + \ '=====================', + \ 'Fatal errors: 1', + \ 'Errors: 0', + \ 'Warnings: 0', + \ 'Info: 0', + \ 'Depreciated 0', + \ ]) diff --git a/test/linter/test_openscad_sca2d.vader b/test/linter/test_openscad_sca2d.vader new file mode 100644 index 00000000..c2409f55 --- /dev/null +++ b/test/linter/test_openscad_sca2d.vader @@ -0,0 +1,12 @@ +Before: + call ale#assert#SetUpLinterTest('openscad', 'sca2d') + +After: + call ale#assert#TearDownLinterTest() + +Execute(The options should be used in the command): + AssertLinter 'sca2d', ale#Escape('sca2d') . ' %s' + + let b:ale_openscad_sca2d_options = '--foobar' + + AssertLinter 'sca2d', ale#Escape('sca2d') . ' --foobar %s'