Adds hdl_checker LSP support (#2804)
* Added hdl_checker support * Added hdl_checker tests HDL Checker searches for files when no config file is found, which could lead to very long searches when the user is not really on a project setting
This commit is contained in:
parent
711c90c523
commit
5b3da60cea
13 changed files with 250 additions and 7 deletions
5
ale_linters/verilog/hdl_checker.vim
Normal file
5
ale_linters/verilog/hdl_checker.vim
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
" Author: suoto <andre820@gmail.com>
|
||||||
|
" Description: Adds support for HDL Code Checker, which wraps vcom/vlog, ghdl
|
||||||
|
" or xvhdl. More info on https://github.com/suoto/hdl_checker
|
||||||
|
|
||||||
|
call ale#handlers#hdl_checker#DefineLinter('verilog')
|
5
ale_linters/vhdl/hdl_checker.vim
Normal file
5
ale_linters/vhdl/hdl_checker.vim
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
" Author: suoto <andre820@gmail.com>
|
||||||
|
" Description: Adds support for HDL Code Checker, which wraps vcom/vlog, ghdl
|
||||||
|
" or xvhdl. More info on https://github.com/suoto/hdl_checker
|
||||||
|
|
||||||
|
call ale#handlers#hdl_checker#DefineLinter('vhdl')
|
71
autoload/ale/handlers/hdl_checker.vim
Normal file
71
autoload/ale/handlers/hdl_checker.vim
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
" Author: suoto <andre820@gmail.com>
|
||||||
|
" Description: Adds support for HDL Code Checker, which wraps vcom/vlog, ghdl
|
||||||
|
" or xvhdl. More info on https://github.com/suoto/hdl_checker
|
||||||
|
|
||||||
|
call ale#Set('hdl_checker_executable', 'hdl_checker')
|
||||||
|
call ale#Set('hdl_checker_config_file', has('unix') ? '.hdl_checker.config' : '_hdl_checker.config')
|
||||||
|
call ale#Set('hdl_checker_options', '')
|
||||||
|
|
||||||
|
" Use this as a function so we can mock it on testing. Need to do this because
|
||||||
|
" test files are inside /testplugin (which refers to the ale repo), which will
|
||||||
|
" always have a .git folder
|
||||||
|
function! ale#handlers#hdl_checker#IsDotGit(path) abort
|
||||||
|
return ! empty(a:path) && isdirectory(a:path)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" Sould return (in order of preference)
|
||||||
|
" 1. Nearest config file
|
||||||
|
" 2. Nearest .git directory
|
||||||
|
" 3. The current path
|
||||||
|
function! ale#handlers#hdl_checker#GetProjectRoot(buffer) abort
|
||||||
|
let l:project_root = ale#path#FindNearestFile(
|
||||||
|
\ a:buffer,
|
||||||
|
\ ale#Var(a:buffer, 'hdl_checker_config_file'))
|
||||||
|
|
||||||
|
if !empty(l:project_root)
|
||||||
|
return fnamemodify(l:project_root, ':h')
|
||||||
|
endif
|
||||||
|
|
||||||
|
" Search for .git to use as root
|
||||||
|
let l:project_root = ale#path#FindNearestDirectory(a:buffer, '.git')
|
||||||
|
|
||||||
|
if ale#handlers#hdl_checker#IsDotGit(l:project_root)
|
||||||
|
return fnamemodify(l:project_root, ':h:h')
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! ale#handlers#hdl_checker#GetExecutable(buffer) abort
|
||||||
|
return ale#Var(a:buffer, 'hdl_checker_executable')
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! ale#handlers#hdl_checker#GetCommand(buffer) abort
|
||||||
|
let l:command = ale#Escape(ale#handlers#hdl_checker#GetExecutable(a:buffer)) . ' --lsp'
|
||||||
|
|
||||||
|
" Add extra parameters only if config has been set
|
||||||
|
let l:options = ale#Var(a:buffer, 'hdl_checker_options')
|
||||||
|
|
||||||
|
if ! empty(l:options)
|
||||||
|
let l:command = l:command . ' ' . l:options
|
||||||
|
endif
|
||||||
|
|
||||||
|
return l:command
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" To allow testing
|
||||||
|
function! ale#handlers#hdl_checker#GetInitOptions(buffer) abort
|
||||||
|
return {'project_file': ale#Var(a:buffer, 'hdl_checker_config_file')}
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" Define the hdl_checker linter for a given filetype.
|
||||||
|
function! ale#handlers#hdl_checker#DefineLinter(filetype) abort
|
||||||
|
call ale#linter#Define(a:filetype, {
|
||||||
|
\ 'name': 'hdl-checker',
|
||||||
|
\ 'lsp': 'stdio',
|
||||||
|
\ 'language': a:filetype,
|
||||||
|
\ 'executable': function('ale#handlers#hdl_checker#GetExecutable'),
|
||||||
|
\ 'command': function('ale#handlers#hdl_checker#GetCommand'),
|
||||||
|
\ 'project_root': function('ale#handlers#hdl_checker#GetProjectRoot'),
|
||||||
|
\ 'initialization_options': function('ale#handlers#hdl_checker#GetInitOptions'),
|
||||||
|
\ })
|
||||||
|
endfunction
|
||||||
|
|
|
@ -3,7 +3,10 @@ ALE Verilog/SystemVerilog Integration *ale-verilog-options*
|
||||||
|
|
||||||
|
|
||||||
===============================================================================
|
===============================================================================
|
||||||
ALE can use four different linters for Verilog HDL:
|
ALE can use five different linters for Verilog HDL:
|
||||||
|
|
||||||
|
HDL Checker
|
||||||
|
Using `hdl_checker --lsp`
|
||||||
|
|
||||||
iverilog:
|
iverilog:
|
||||||
Using `iverilog -t null -Wall`
|
Using `iverilog -t null -Wall`
|
||||||
|
@ -26,6 +29,9 @@ defining 'g:ale_linters' variable:
|
||||||
\ let g:ale_linters = {'systemverilog' : ['verilator'],}
|
\ let g:ale_linters = {'systemverilog' : ['verilator'],}
|
||||||
<
|
<
|
||||||
|
|
||||||
|
===============================================================================
|
||||||
|
General notes
|
||||||
|
|
||||||
Linters/compilers that utilize a "work" directory for analyzing designs- such
|
Linters/compilers that utilize a "work" directory for analyzing designs- such
|
||||||
as ModelSim and Vivado- can be passed the location of these directories as
|
as ModelSim and Vivado- can be passed the location of these directories as
|
||||||
part of their respective option strings listed below. This is useful for
|
part of their respective option strings listed below. This is useful for
|
||||||
|
@ -40,6 +46,16 @@ changing. This can happen in the form of hangs or crashes. To help prevent
|
||||||
this when using these linters, it may help to run linting less frequently; for
|
this when using these linters, it may help to run linting less frequently; for
|
||||||
example, only when a file is saved.
|
example, only when a file is saved.
|
||||||
|
|
||||||
|
HDL Checker is an alternative for some of the issues described above. It wraps
|
||||||
|
around ghdl, Vivado and ModelSim/Questa and, when using the latter, it can
|
||||||
|
handle mixed language (VHDL, Verilog, SystemVerilog) designs.
|
||||||
|
|
||||||
|
===============================================================================
|
||||||
|
hdl-checker *ale-verilog-hdl-checker*
|
||||||
|
|
||||||
|
See |ale-vhdl-hdl-checker|
|
||||||
|
|
||||||
|
|
||||||
===============================================================================
|
===============================================================================
|
||||||
iverilog *ale-verilog-iverilog*
|
iverilog *ale-verilog-iverilog*
|
||||||
|
|
||||||
|
|
|
@ -3,10 +3,10 @@ ALE VHDL Integration *ale-vhdl-options*
|
||||||
|
|
||||||
|
|
||||||
===============================================================================
|
===============================================================================
|
||||||
ALE can use three different linters for VHDL:
|
ALE can use four different linters for VHDL:
|
||||||
|
|
||||||
iverilog:
|
ghdl:
|
||||||
Using `iverilog -t null -Wall`
|
Using `ghdl --std=08`
|
||||||
|
|
||||||
ModelSim/Questa
|
ModelSim/Questa
|
||||||
Using `vcom -2008 -quiet -lint`
|
Using `vcom -2008 -quiet -lint`
|
||||||
|
@ -14,8 +14,15 @@ ALE can use three different linters for VHDL:
|
||||||
Vivado
|
Vivado
|
||||||
Using `xvhdl --2008`
|
Using `xvhdl --2008`
|
||||||
|
|
||||||
Note all linters default to VHDL-2008 support. This, and other options, can be
|
HDL Checker
|
||||||
changed with each linter's respective option variable.
|
Using `hdl_checker --lsp`
|
||||||
|
|
||||||
|
===============================================================================
|
||||||
|
General notes
|
||||||
|
|
||||||
|
ghdl, ModelSim/Questa and Vivado linters default to VHDL-2008 support. This,
|
||||||
|
and other options, can be changed with each linter's respective option
|
||||||
|
variable.
|
||||||
|
|
||||||
Linters/compilers that utilize a "work" directory for analyzing designs- such
|
Linters/compilers that utilize a "work" directory for analyzing designs- such
|
||||||
as ModelSim and Vivado- can be passed the location of these directories as
|
as ModelSim and Vivado- can be passed the location of these directories as
|
||||||
|
@ -31,6 +38,10 @@ changing. This can happen in the form of hangs or crashes. To help prevent
|
||||||
this when using these linters, it may help to run linting less frequently; for
|
this when using these linters, it may help to run linting less frequently; for
|
||||||
example, only when a file is saved.
|
example, only when a file is saved.
|
||||||
|
|
||||||
|
HDL Checker is an alternative for some of the issues described above. It wraps
|
||||||
|
around ghdl, Vivado and ModelSim/Questa and, when using the latter, it can
|
||||||
|
handle mixed language (VHDL, Verilog, SystemVerilog) designs.
|
||||||
|
|
||||||
===============================================================================
|
===============================================================================
|
||||||
ghdl *ale-vhdl-ghdl*
|
ghdl *ale-vhdl-ghdl*
|
||||||
|
|
||||||
|
@ -50,6 +61,60 @@ g:ale_vhdl_ghdl_options *g:ale_vhdl_ghdl_options*
|
||||||
This variable can be changed to modify the flags/options passed to 'ghdl'.
|
This variable can be changed to modify the flags/options passed to 'ghdl'.
|
||||||
|
|
||||||
|
|
||||||
|
===============================================================================
|
||||||
|
hdl-checker *ale-vhdl-hdl-checker*
|
||||||
|
|
||||||
|
HDL Checker is a wrapper for VHDL/Verilg/SystemVerilog tools that aims to
|
||||||
|
reduce the boilerplate code needed to set things up. It can automatically
|
||||||
|
infer libraries for VHDL sources, determine the compilation order and provide
|
||||||
|
some static checks.
|
||||||
|
|
||||||
|
You can install it using pip:
|
||||||
|
>
|
||||||
|
$ pip install hdl-checker
|
||||||
|
|
||||||
|
`hdl-checker` will be run from a detected project root, determined by the
|
||||||
|
following methods, in order:
|
||||||
|
|
||||||
|
1. Find the first directory containing a configuration file (see
|
||||||
|
|g:ale_hdl_checker_config_file|)
|
||||||
|
2. If no configuration file can be found, find the first directory containing
|
||||||
|
a folder named `'.git'
|
||||||
|
3. If no such folder is found, use the directory of the current buffer
|
||||||
|
|
||||||
|
|
||||||
|
g:ale_hdl_checker_executable
|
||||||
|
*g:ale_hdl_checker_executable*
|
||||||
|
*b:ale_hdl_checker_executable*
|
||||||
|
Type: |String|
|
||||||
|
Default: `'hdl_checker'`
|
||||||
|
|
||||||
|
This variable can be changed to the path to the 'hdl_checker' executable.
|
||||||
|
|
||||||
|
|
||||||
|
g:ale_hdl_checker_options *g:ale_hdl_checker_options*
|
||||||
|
*b:ale_hdl_checker_options*
|
||||||
|
Type: |String|
|
||||||
|
Default: `''`
|
||||||
|
|
||||||
|
This variable can be changed to modify the flags/options passed to the
|
||||||
|
'hdl_checker' server startup command.
|
||||||
|
|
||||||
|
|
||||||
|
g:ale_hdl_checker_config_file *g:ale_hdl_checker_config_file*
|
||||||
|
*b:ale_hdl_checker_config_file*
|
||||||
|
Type: |String|
|
||||||
|
Default: `'.hdl_checker.config'` (Unix),
|
||||||
|
`'_hdl_checker.config'` (Windows)
|
||||||
|
|
||||||
|
This variable can be changed to modify the config file HDL Checker will try
|
||||||
|
to look for. It will also affect how the project's root directory is
|
||||||
|
determined (see |ale-vhdl-hdl-checker|).
|
||||||
|
|
||||||
|
More info on the configuration file format can be found at:
|
||||||
|
https://github.com/suoto/hdl_checker/wiki/Setting-up-a-project
|
||||||
|
|
||||||
|
|
||||||
===============================================================================
|
===============================================================================
|
||||||
vcom *ale-vhdl-vcom*
|
vcom *ale-vhdl-vcom*
|
||||||
|
|
||||||
|
|
|
@ -2675,12 +2675,14 @@ documented in additional help files.
|
||||||
vala....................................|ale-vala-options|
|
vala....................................|ale-vala-options|
|
||||||
uncrustify............................|ale-vala-uncrustify|
|
uncrustify............................|ale-vala-uncrustify|
|
||||||
verilog/systemverilog...................|ale-verilog-options|
|
verilog/systemverilog...................|ale-verilog-options|
|
||||||
|
hdl-checker...........................|ale-verilog-hdl-checker|
|
||||||
iverilog..............................|ale-verilog-iverilog|
|
iverilog..............................|ale-verilog-iverilog|
|
||||||
verilator.............................|ale-verilog-verilator|
|
verilator.............................|ale-verilog-verilator|
|
||||||
vlog..................................|ale-verilog-vlog|
|
vlog..................................|ale-verilog-vlog|
|
||||||
xvlog.................................|ale-verilog-xvlog|
|
xvlog.................................|ale-verilog-xvlog|
|
||||||
vhdl....................................|ale-vhdl-options|
|
vhdl....................................|ale-vhdl-options|
|
||||||
ghdl..................................|ale-vhdl-ghdl|
|
ghdl..................................|ale-vhdl-ghdl|
|
||||||
|
hdl-checker...........................|ale-vhdl-hdl-checker|
|
||||||
vcom..................................|ale-vhdl-vcom|
|
vcom..................................|ale-vhdl-vcom|
|
||||||
xvhdl.................................|ale-vhdl-xvhdl|
|
xvhdl.................................|ale-vhdl-xvhdl|
|
||||||
vim.....................................|ale-vim-options|
|
vim.....................................|ale-vim-options|
|
||||||
|
|
0
test/command_callback/hdl_server/foo.vhd
Normal file
0
test/command_callback/hdl_server/foo.vhd
Normal file
1
test/command_callback/hdl_server/with_git/files/foo.vhd
Normal file
1
test/command_callback/hdl_server/with_git/files/foo.vhd
Normal file
|
@ -0,0 +1 @@
|
||||||
|
|
|
@ -61,7 +61,7 @@ Execute(The defaults for the zsh filetype should be correct):
|
||||||
Execute(The defaults for the verilog filetype should be correct):
|
Execute(The defaults for the verilog filetype should be correct):
|
||||||
" This filetype isn't configured with default, so we can test loading all
|
" This filetype isn't configured with default, so we can test loading all
|
||||||
" available linters with this.
|
" available linters with this.
|
||||||
AssertEqual ['iverilog', 'verilator', 'vlog', 'xvlog'], GetLinterNames('verilog')
|
AssertEqual ['hdl-checker', 'iverilog', 'verilator', 'vlog', 'xvlog'], GetLinterNames('verilog')
|
||||||
|
|
||||||
let g:ale_linters_explicit = 1
|
let g:ale_linters_explicit = 1
|
||||||
|
|
||||||
|
|
78
test/test_hdl_checker_options.vader
Normal file
78
test/test_hdl_checker_options.vader
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
Before:
|
||||||
|
call ale#assert#SetUpLinterTest('vhdl', 'hdl_checker')
|
||||||
|
|
||||||
|
Save g:ale_hdl_checker_config_file
|
||||||
|
Save g:ale_hdl_checker_options
|
||||||
|
|
||||||
|
let g:default_config_file = has('unix') ? '.hdl_checker.config' : '_hdl_checker.config'
|
||||||
|
|
||||||
|
After:
|
||||||
|
Restore
|
||||||
|
call ale#assert#TearDownLinterTest()
|
||||||
|
unlet! g:default_config_file
|
||||||
|
|
||||||
|
Execute(Get default initialization dict):
|
||||||
|
AssertEqual
|
||||||
|
\ {'project_file': g:default_config_file},
|
||||||
|
\ ale#handlers#hdl_checker#GetInitOptions(bufnr(''))
|
||||||
|
|
||||||
|
Execute(Get custom initialization dict):
|
||||||
|
let g:ale_hdl_checker_config_file = 'some_file_name'
|
||||||
|
|
||||||
|
AssertEqual
|
||||||
|
\ {'project_file': 'some_file_name'},
|
||||||
|
\ ale#handlers#hdl_checker#GetInitOptions(bufnr(''))
|
||||||
|
|
||||||
|
Execute(Get the checker command without extra user parameters):
|
||||||
|
AssertEqual
|
||||||
|
\ ale#Escape('hdl_checker') . ' --lsp',
|
||||||
|
\ ale#handlers#hdl_checker#GetCommand(bufnr(''))
|
||||||
|
|
||||||
|
Execute(Get the checker command with user configured parameters):
|
||||||
|
let g:ale_hdl_checker_options = '--log-level DEBUG'
|
||||||
|
|
||||||
|
AssertEqual
|
||||||
|
\ ale#Escape('hdl_checker') . ' --lsp --log-level DEBUG',
|
||||||
|
\ ale#handlers#hdl_checker#GetCommand(bufnr(''))
|
||||||
|
|
||||||
|
Execute(Customize executable):
|
||||||
|
let g:ale_hdl_checker_executable = '/some/other/path'
|
||||||
|
AssertEqual
|
||||||
|
\ ale#Escape('/some/other/path') . ' --lsp',
|
||||||
|
\ ale#handlers#hdl_checker#GetCommand(bufnr(''))
|
||||||
|
|
||||||
|
Execute(Get project root based on .git):
|
||||||
|
call ale#test#SetFilename('hdl_server/with_git/files/foo.vhd')
|
||||||
|
" Create .git file
|
||||||
|
silent! call mkdir(g:dir . '/hdl_server/with_git/.git')
|
||||||
|
AssertNotEqual '', glob(g:dir . '/hdl_server/with_git/.git')
|
||||||
|
|
||||||
|
AssertEqual
|
||||||
|
\ ale#path#Simplify(g:dir . '/hdl_server/with_git'),
|
||||||
|
\ ale#handlers#hdl_checker#GetProjectRoot(bufnr(''))
|
||||||
|
|
||||||
|
Execute(Get project root based on config file):
|
||||||
|
call ale#test#SetFilename('hdl_server/with_config_file/foo.vhd')
|
||||||
|
|
||||||
|
AssertEqual
|
||||||
|
\ ale#path#Simplify(g:dir . '/hdl_server/with_config_file'),
|
||||||
|
\ ale#handlers#hdl_checker#GetProjectRoot(bufnr(''))
|
||||||
|
|
||||||
|
Execute(Return no project root if neither .git or config file are found):
|
||||||
|
let g:call_count = 0
|
||||||
|
|
||||||
|
" Mock this command to avoid the test to find ale's own .git folder
|
||||||
|
function! ale#handlers#hdl_checker#IsDotGit(path) abort
|
||||||
|
let g:call_count += 1
|
||||||
|
return 0
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
call ale#test#SetFilename('hdl_server/foo.vhd')
|
||||||
|
|
||||||
|
AssertEqual
|
||||||
|
\ '',
|
||||||
|
\ ale#handlers#hdl_checker#GetProjectRoot(bufnr(''))
|
||||||
|
|
||||||
|
AssertEqual g:call_count, 1
|
||||||
|
|
||||||
|
unlet! g:call_count
|
Reference in a new issue