mirror of
https://github.com/dense-analysis/ale.git
synced 2025-12-06 20:54:26 +08:00
Close #2102 - Add support for the Angular language server
This commit is contained in:
52
ale_linters/html/angular.vim
Normal file
52
ale_linters/html/angular.vim
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
" Author: w0rp <devw0rp@gmail.com>
|
||||||
|
" Description: tsserver integration for ALE
|
||||||
|
|
||||||
|
call ale#Set('html_angular_executable', 'ngserver')
|
||||||
|
call ale#Set('html_angular_use_global', get(g:, 'ale_use_global_executables', 0))
|
||||||
|
|
||||||
|
function! ale_linters#html#angular#GetProjectRoot(buffer) abort
|
||||||
|
return ale#path#Dirname(
|
||||||
|
\ ale#path#FindNearestDirectory(a:buffer, 'node_modules')
|
||||||
|
\)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! ale_linters#html#angular#GetExecutable(buffer) abort
|
||||||
|
return ale#node#FindExecutable(a:buffer, 'html_angular', [
|
||||||
|
\ 'node_modules/@angular/language-server/bin/ngserver',
|
||||||
|
\ 'node_modules/@angular/language-server/index.js',
|
||||||
|
\])
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! ale_linters#html#angular#GetCommand(buffer) abort
|
||||||
|
let l:language_service_dir = ale#path#Simplify(
|
||||||
|
\ ale#path#FindNearestDirectory(
|
||||||
|
\ a:buffer,
|
||||||
|
\ 'node_modules/@angular/language-service'
|
||||||
|
\ )
|
||||||
|
\)
|
||||||
|
|
||||||
|
if empty(l:language_service_dir)
|
||||||
|
return ''
|
||||||
|
endif
|
||||||
|
|
||||||
|
let l:language_service_dir = fnamemodify(l:language_service_dir, ':h')
|
||||||
|
let l:typescript_dir = ale#path#Simplify(
|
||||||
|
\ fnamemodify(l:language_service_dir, ':h:h')
|
||||||
|
\ . '/typescript'
|
||||||
|
\)
|
||||||
|
let l:executable = ale_linters#html#angular#GetExecutable(a:buffer)
|
||||||
|
|
||||||
|
return ale#node#Executable(a:buffer, l:executable)
|
||||||
|
\ . ' --ngProbeLocations ' . ale#Escape(l:language_service_dir)
|
||||||
|
\ . ' --tsProbeLocations ' . ale#Escape(l:typescript_dir)
|
||||||
|
\ . ' --stdio'
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
call ale#linter#Define('html', {
|
||||||
|
\ 'name': 'angular',
|
||||||
|
\ 'aliases': ['angular-language-server'],
|
||||||
|
\ 'lsp': 'stdio',
|
||||||
|
\ 'executable': function('ale_linters#html#angular#GetExecutable'),
|
||||||
|
\ 'command': function('ale_linters#html#angular#GetCommand'),
|
||||||
|
\ 'project_root': function('ale_linters#html#angular#GetProjectRoot'),
|
||||||
|
\})
|
||||||
@@ -169,8 +169,21 @@ function! ale#assert#LinterNotExecuted() abort
|
|||||||
let l:buffer = bufnr('')
|
let l:buffer = bufnr('')
|
||||||
let l:linter = s:GetLinter()
|
let l:linter = s:GetLinter()
|
||||||
let l:executable = ale#linter#GetExecutable(l:buffer, l:linter)
|
let l:executable = ale#linter#GetExecutable(l:buffer, l:linter)
|
||||||
|
let l:executed = 1
|
||||||
|
|
||||||
Assert empty(l:executable), "The linter will be executed when it shouldn't be"
|
if !empty(l:executable)
|
||||||
|
let l:command = ale#linter#GetCommand(l:buffer, l:linter)
|
||||||
|
|
||||||
|
if type(l:command) is v:t_list
|
||||||
|
let l:command = l:command[-1]
|
||||||
|
endif
|
||||||
|
|
||||||
|
let l:executed = !empty(l:command)
|
||||||
|
else
|
||||||
|
let l:executed = 0
|
||||||
|
endif
|
||||||
|
|
||||||
|
Assert !l:executed, "The linter will be executed when it shouldn't be"
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! ale#assert#LSPOptions(expected_options) abort
|
function! ale#assert#LSPOptions(expected_options) abort
|
||||||
|
|||||||
@@ -66,9 +66,17 @@ function! ale#definition#HandleLSPResponse(conn_id, response) abort
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
for l:item in l:result
|
for l:item in l:result
|
||||||
let l:filename = ale#path#FromURI(l:item.uri)
|
if has_key(l:item, 'targetUri')
|
||||||
let l:line = l:item.range.start.line + 1
|
" LocationLink items use targetUri
|
||||||
let l:column = l:item.range.start.character + 1
|
let l:filename = ale#path#FromURI(l:item.targetUri)
|
||||||
|
let l:line = l:item.targetRange.start.line + 1
|
||||||
|
let l:column = l:item.targetRange.start.character + 1
|
||||||
|
else
|
||||||
|
" LocationLink items use uri
|
||||||
|
let l:filename = ale#path#FromURI(l:item.uri)
|
||||||
|
let l:line = l:item.range.start.line + 1
|
||||||
|
let l:column = l:item.range.start.character + 1
|
||||||
|
endif
|
||||||
|
|
||||||
call ale#definition#UpdateTagStack()
|
call ale#definition#UpdateTagStack()
|
||||||
call ale#util#Open(l:filename, l:line, l:column, l:options)
|
call ale#util#Open(l:filename, l:line, l:column, l:options)
|
||||||
|
|||||||
@@ -294,14 +294,15 @@ function! s:StartLSP(options, address, executable, command) abort
|
|||||||
call ale#lsp#MarkConnectionAsTsserver(l:conn_id)
|
call ale#lsp#MarkConnectionAsTsserver(l:conn_id)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
let l:cwd = ale#linter#GetCwd(l:buffer, l:linter)
|
||||||
let l:command = ale#command#FormatCommand(
|
let l:command = ale#command#FormatCommand(
|
||||||
\ l:buffer,
|
\ l:buffer,
|
||||||
\ a:executable,
|
\ a:executable,
|
||||||
\ a:command,
|
\ a:command,
|
||||||
\ 0,
|
\ 0,
|
||||||
\ v:false,
|
\ v:false,
|
||||||
\ v:null,
|
\ l:cwd,
|
||||||
\ [],
|
\ ale#GetFilenameMappings(l:buffer, l:linter.name),
|
||||||
\)[1]
|
\)[1]
|
||||||
let l:command = ale#job#PrepareCommand(l:buffer, l:command)
|
let l:command = ale#job#PrepareCommand(l:buffer, l:command)
|
||||||
let l:ready = ale#lsp#StartProgram(l:conn_id, a:executable, l:command)
|
let l:ready = ale#lsp#StartProgram(l:conn_id, a:executable, l:command)
|
||||||
|
|||||||
@@ -34,12 +34,11 @@ function! ale#test#RestoreDirectory() abort
|
|||||||
unlet! g:dir
|
unlet! g:dir
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
" Change the filename for the current buffer using a relative path to
|
" Get a filename for the current buffer using a relative path to the script.
|
||||||
" the script without running autocmd commands.
|
|
||||||
"
|
"
|
||||||
" If a g:dir variable is set, it will be used as the path to the directory
|
" If a g:dir variable is set, it will be used as the path to the directory
|
||||||
" containing the test file.
|
" containing the test file.
|
||||||
function! ale#test#SetFilename(path) abort
|
function! ale#test#GetFilename(path) abort
|
||||||
let l:dir = get(g:, 'dir', '')
|
let l:dir = get(g:, 'dir', '')
|
||||||
|
|
||||||
if empty(l:dir)
|
if empty(l:dir)
|
||||||
@@ -50,7 +49,17 @@ function! ale#test#SetFilename(path) abort
|
|||||||
\ ? a:path
|
\ ? a:path
|
||||||
\ : l:dir . '/' . a:path
|
\ : l:dir . '/' . a:path
|
||||||
|
|
||||||
silent! noautocmd execute 'file ' . fnameescape(ale#path#Simplify(l:full_path))
|
return ale#path#Simplify(l:full_path)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" Change the filename for the current buffer using a relative path to
|
||||||
|
" the script without running autocmd commands.
|
||||||
|
"
|
||||||
|
" If a g:dir variable is set, it will be used as the path to the directory
|
||||||
|
" containing the test file.
|
||||||
|
function! ale#test#SetFilename(path) abort
|
||||||
|
let l:full_path = ale#test#GetFilename(a:path)
|
||||||
|
silent! noautocmd execute 'file ' . fnameescape(l:full_path)
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! s:RemoveModule(results) abort
|
function! s:RemoveModule(results) abort
|
||||||
|
|||||||
@@ -2,13 +2,41 @@
|
|||||||
ALE HTML Integration *ale-html-options*
|
ALE HTML Integration *ale-html-options*
|
||||||
|
|
||||||
|
|
||||||
|
===============================================================================
|
||||||
|
angular *ale-html-angular*
|
||||||
|
|
||||||
|
ALE supports language server features for Angular. You can install it via `npm`: >
|
||||||
|
|
||||||
|
$ npm install --save-dev @angular/language-server
|
||||||
|
<
|
||||||
|
Angular 11 and up are supported.
|
||||||
|
|
||||||
|
|
||||||
|
g:ale_html_angular_executable *g:ale_html_angular_executable*
|
||||||
|
*b:ale_html_angular_executable*
|
||||||
|
Type: |String|
|
||||||
|
Default: `'ngserver'`
|
||||||
|
|
||||||
|
See |ale-integrations-local-executables|
|
||||||
|
|
||||||
|
|
||||||
|
g:ale_html_angular_use_global *g:ale_html_angular_use_global*
|
||||||
|
*b:ale_html_angular_use_global*
|
||||||
|
Type: |String|
|
||||||
|
Default: `get(g:, 'ale_use_global_executables', 0)`
|
||||||
|
|
||||||
|
See |ale-integrations-local-executables|
|
||||||
|
|
||||||
|
|
||||||
===============================================================================
|
===============================================================================
|
||||||
fecs *ale-html-fecs*
|
fecs *ale-html-fecs*
|
||||||
|
|
||||||
`fecs` options for HTMl is the same as the options for JavaScript,
|
`fecs` options for HTML are the same as the options for JavaScript, and both
|
||||||
and both of them reads `./.fecsrc` as the default configuration file.
|
of them read `./.fecsrc` as the default configuration file.
|
||||||
|
|
||||||
See: |ale-javascript-fecs|.
|
See: |ale-javascript-fecs|.
|
||||||
|
|
||||||
|
|
||||||
===============================================================================
|
===============================================================================
|
||||||
html-beautify *ale-html-beautify*
|
html-beautify *ale-html-beautify*
|
||||||
|
|
||||||
@@ -47,6 +75,40 @@ g:ale_html_htmlhint_use_global *g:ale_html_htmlhint_use_global*
|
|||||||
See |ale-integrations-local-executables|
|
See |ale-integrations-local-executables|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
===============================================================================
|
||||||
|
prettier *ale-html-prettier*
|
||||||
|
|
||||||
|
See |ale-javascript-prettier| for information about the available options.
|
||||||
|
|
||||||
|
|
||||||
|
===============================================================================
|
||||||
|
stylelint *ale-html-stylelint*
|
||||||
|
|
||||||
|
g:ale_html_stylelint_executable *g:ale_html_stylelint_executable*
|
||||||
|
*b:ale_html_stylelint_executable*
|
||||||
|
Type: |String|
|
||||||
|
Default: `'stylelint'`
|
||||||
|
|
||||||
|
See |ale-integrations-local-executables|
|
||||||
|
|
||||||
|
|
||||||
|
g:ale_html_stylelint_options *g:ale_html_stylelint_options*
|
||||||
|
*b:ale_html_stylelint_options*
|
||||||
|
Type: |String|
|
||||||
|
Default: `''`
|
||||||
|
|
||||||
|
This variable can be set to pass additional options to stylelint.
|
||||||
|
|
||||||
|
|
||||||
|
g:ale_html_stylelint_use_global *g:ale_html_stylelint_use_global*
|
||||||
|
*b:ale_html_stylelint_use_global*
|
||||||
|
Type: |String|
|
||||||
|
Default: `0`
|
||||||
|
|
||||||
|
See |ale-integrations-local-executables|
|
||||||
|
|
||||||
|
|
||||||
===============================================================================
|
===============================================================================
|
||||||
tidy *ale-html-tidy*
|
tidy *ale-html-tidy*
|
||||||
|
|
||||||
@@ -97,39 +159,6 @@ g:ale_html_tidy_use_global *g:html_tidy_use_global*
|
|||||||
See |ale-integrations-local-executables|
|
See |ale-integrations-local-executables|
|
||||||
|
|
||||||
|
|
||||||
===============================================================================
|
|
||||||
prettier *ale-html-prettier*
|
|
||||||
|
|
||||||
See |ale-javascript-prettier| for information about the available options.
|
|
||||||
|
|
||||||
|
|
||||||
===============================================================================
|
|
||||||
stylelint *ale-html-stylelint*
|
|
||||||
|
|
||||||
g:ale_html_stylelint_executable *g:ale_html_stylelint_executable*
|
|
||||||
*b:ale_html_stylelint_executable*
|
|
||||||
Type: |String|
|
|
||||||
Default: `'stylelint'`
|
|
||||||
|
|
||||||
See |ale-integrations-local-executables|
|
|
||||||
|
|
||||||
|
|
||||||
g:ale_html_stylelint_options *g:ale_html_stylelint_options*
|
|
||||||
*b:ale_html_stylelint_options*
|
|
||||||
Type: |String|
|
|
||||||
Default: `''`
|
|
||||||
|
|
||||||
This variable can be set to pass additional options to stylelint.
|
|
||||||
|
|
||||||
|
|
||||||
g:ale_html_stylelint_use_global *g:ale_html_stylelint_use_global*
|
|
||||||
*b:ale_html_stylelint_use_global*
|
|
||||||
Type: |String|
|
|
||||||
Default: `0`
|
|
||||||
|
|
||||||
See |ale-integrations-local-executables|
|
|
||||||
|
|
||||||
|
|
||||||
===============================================================================
|
===============================================================================
|
||||||
write-good *ale-html-write-good*
|
write-good *ale-html-write-good*
|
||||||
|
|
||||||
|
|||||||
@@ -216,10 +216,11 @@ Notes:
|
|||||||
* HCL
|
* HCL
|
||||||
* `terraform-fmt`
|
* `terraform-fmt`
|
||||||
* HTML
|
* HTML
|
||||||
* `HTMLHint`
|
|
||||||
* `alex`!!
|
* `alex`!!
|
||||||
|
* `angular`
|
||||||
* `fecs`
|
* `fecs`
|
||||||
* `html-beautify`
|
* `html-beautify`
|
||||||
|
* `htmlhint`
|
||||||
* `prettier`
|
* `prettier`
|
||||||
* `proselint`
|
* `proselint`
|
||||||
* `tidy`
|
* `tidy`
|
||||||
|
|||||||
@@ -2777,12 +2777,13 @@ documented in additional help files.
|
|||||||
hcl.....................................|ale-hcl-options|
|
hcl.....................................|ale-hcl-options|
|
||||||
terraform-fmt.........................|ale-hcl-terraform-fmt|
|
terraform-fmt.........................|ale-hcl-terraform-fmt|
|
||||||
html....................................|ale-html-options|
|
html....................................|ale-html-options|
|
||||||
|
angular...............................|ale-html-angular|
|
||||||
fecs..................................|ale-html-fecs|
|
fecs..................................|ale-html-fecs|
|
||||||
html-beautify.........................|ale-html-beautify|
|
html-beautify.........................|ale-html-beautify|
|
||||||
htmlhint..............................|ale-html-htmlhint|
|
htmlhint..............................|ale-html-htmlhint|
|
||||||
tidy..................................|ale-html-tidy|
|
|
||||||
prettier..............................|ale-html-prettier|
|
prettier..............................|ale-html-prettier|
|
||||||
stylelint.............................|ale-html-stylelint|
|
stylelint.............................|ale-html-stylelint|
|
||||||
|
tidy..................................|ale-html-tidy|
|
||||||
write-good............................|ale-html-write-good|
|
write-good............................|ale-html-write-good|
|
||||||
idris...................................|ale-idris-options|
|
idris...................................|ale-idris-options|
|
||||||
idris.................................|ale-idris-idris|
|
idris.................................|ale-idris-idris|
|
||||||
|
|||||||
@@ -225,10 +225,11 @@ formatting.
|
|||||||
* HCL
|
* HCL
|
||||||
* [terraform-fmt](https://github.com/hashicorp/terraform)
|
* [terraform-fmt](https://github.com/hashicorp/terraform)
|
||||||
* HTML
|
* HTML
|
||||||
* [HTMLHint](http://htmlhint.com/)
|
|
||||||
* [alex](https://github.com/wooorm/alex) :floppy_disk:
|
* [alex](https://github.com/wooorm/alex) :floppy_disk:
|
||||||
|
* [angular](https://www.npmjs.com/package/@angular/language-server)
|
||||||
* [fecs](http://fecs.baidu.com/)
|
* [fecs](http://fecs.baidu.com/)
|
||||||
* [html-beautify](https://beautifier.io/)
|
* [html-beautify](https://beautifier.io/)
|
||||||
|
* [htmlhint](http://htmlhint.com/)
|
||||||
* [prettier](https://github.com/prettier/prettier)
|
* [prettier](https://github.com/prettier/prettier)
|
||||||
* [proselint](http://proselint.com/)
|
* [proselint](http://proselint.com/)
|
||||||
* [tidy](http://www.html-tidy.org/)
|
* [tidy](http://www.html-tidy.org/)
|
||||||
|
|||||||
44
test/command_callback/test_angular_command_callback.vader
Normal file
44
test/command_callback/test_angular_command_callback.vader
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
Before:
|
||||||
|
call ale#assert#SetUpLinterTest('html', 'angular')
|
||||||
|
let g:paths = {}
|
||||||
|
|
||||||
|
After:
|
||||||
|
call ale#assert#TearDownLinterTest()
|
||||||
|
unlet g:paths
|
||||||
|
|
||||||
|
Execute(The Angular LSP connection shouldn't be created outside of Angular projects):
|
||||||
|
AssertLSPLanguage 'html'
|
||||||
|
AssertLSPConfig {}
|
||||||
|
AssertLSPProject ''
|
||||||
|
AssertLinterNotExecuted
|
||||||
|
|
||||||
|
Execute(The default command for Angular should be correct):
|
||||||
|
call ale#test#SetFilename('../test-projects/angular/test.html')
|
||||||
|
let g:paths = {
|
||||||
|
\ 'ngserver': ale#test#GetFilename('../test-projects/angular/node_modules/@angular/language-server/bin/ngserver'),
|
||||||
|
\ 'service': ale#test#GetFilename('../test-projects/angular/node_modules/@angular/language-service'),
|
||||||
|
\ 'typescript': ale#test#GetFilename('../test-projects/angular/node_modules/typescript'),
|
||||||
|
\}
|
||||||
|
|
||||||
|
AssertLSPLanguage 'html'
|
||||||
|
AssertLSPProject ale#test#GetFilename('../test-projects/angular')
|
||||||
|
AssertLinter g:paths.ngserver, ale#Escape(g:paths.ngserver)
|
||||||
|
\ . ' --ngProbeLocations ' . ale#Escape(g:paths.service)
|
||||||
|
\ . ' --tsProbeLocations ' . ale#Escape(g:paths.typescript)
|
||||||
|
\ . ' --stdio'
|
||||||
|
|
||||||
|
Execute(It should be possible to use the global ngserver):
|
||||||
|
let b:ale_html_angular_use_global = 1
|
||||||
|
|
||||||
|
call ale#test#SetFilename('../test-projects/angular/test.html')
|
||||||
|
let g:paths = {
|
||||||
|
\ 'service': ale#test#GetFilename('../test-projects/angular/node_modules/@angular/language-service'),
|
||||||
|
\ 'typescript': ale#test#GetFilename('../test-projects/angular/node_modules/typescript'),
|
||||||
|
\}
|
||||||
|
|
||||||
|
AssertLSPLanguage 'html'
|
||||||
|
AssertLSPProject ale#test#GetFilename('../test-projects/angular')
|
||||||
|
AssertLinter 'ngserver', ale#Escape('ngserver')
|
||||||
|
\ . ' --ngProbeLocations ' . ale#Escape(g:paths.service)
|
||||||
|
\ . ' --tsProbeLocations ' . ale#Escape(g:paths.typescript)
|
||||||
|
\ . ' --stdio'
|
||||||
0
test/test-projects/angular/node_modules/@angular/language-server/bin/ngserver
generated
vendored
Normal file
0
test/test-projects/angular/node_modules/@angular/language-server/bin/ngserver
generated
vendored
Normal file
0
test/test-projects/angular/node_modules/@angular/language-service/dummy
generated
vendored
Normal file
0
test/test-projects/angular/node_modules/@angular/language-service/dummy
generated
vendored
Normal file
@@ -343,6 +343,29 @@ Execute(Other files should be jumped to for LSP definition responses):
|
|||||||
AssertEqual [3, 8], getpos('.')[1:2]
|
AssertEqual [3, 8], getpos('.')[1:2]
|
||||||
AssertEqual {}, ale#definition#GetMap()
|
AssertEqual {}, ale#definition#GetMap()
|
||||||
|
|
||||||
|
Execute(Newer LocationLink items should be supported):
|
||||||
|
call ale#definition#SetMap({3: {'open_in': 'current-buffer'}})
|
||||||
|
call ale#definition#HandleLSPResponse(
|
||||||
|
\ 1,
|
||||||
|
\ {
|
||||||
|
\ 'id': 3,
|
||||||
|
\ 'result': {
|
||||||
|
\ 'targetUri': ale#path#ToURI(ale#path#Simplify(g:dir . '/completion_dummy_file')),
|
||||||
|
\ 'targetRange': {
|
||||||
|
\ 'start': {'line': 2, 'character': 7},
|
||||||
|
\ },
|
||||||
|
\ },
|
||||||
|
\ }
|
||||||
|
\)
|
||||||
|
|
||||||
|
AssertEqual
|
||||||
|
\ [
|
||||||
|
\ 'edit +3 ' . fnameescape(ale#path#Simplify(g:dir . '/completion_dummy_file')),
|
||||||
|
\ ],
|
||||||
|
\ g:expr_list
|
||||||
|
AssertEqual [3, 8], getpos('.')[1:2]
|
||||||
|
AssertEqual {}, ale#definition#GetMap()
|
||||||
|
|
||||||
Execute(Locations inside the same file should be jumped to without using :edit):
|
Execute(Locations inside the same file should be jumped to without using :edit):
|
||||||
call ale#definition#SetMap({3: {'open_in': 'current-buffer'}})
|
call ale#definition#SetMap({3: {'open_in': 'current-buffer'}})
|
||||||
call ale#definition#HandleLSPResponse(
|
call ale#definition#HandleLSPResponse(
|
||||||
|
|||||||
Reference in New Issue
Block a user