summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorw0rp <devw0rp@gmail.com>2021-03-14 21:10:05 +0000
committerw0rp <devw0rp@gmail.com>2021-03-14 21:10:20 +0000
commitb45ee8ec6c760089c68fb28a5436ec8275ca5381 (patch)
treeb37f356b016f3c09ac7a706ed22fa0d852b32969
parent80a48d01be663205b92902ca3fa137706e3e88c6 (diff)
downloadale-b45ee8ec6c760089c68fb28a5436ec8275ca5381.zip
Close #2102 - Add support for the Angular language server
-rw-r--r--ale_linters/html/angular.vim52
-rw-r--r--autoload/ale/assert.vim15
-rw-r--r--autoload/ale/definition.vim14
-rw-r--r--autoload/ale/lsp_linter.vim5
-rw-r--r--autoload/ale/test.vim17
-rw-r--r--doc/ale-html.txt99
-rw-r--r--doc/ale-supported-languages-and-tools.txt3
-rw-r--r--doc/ale.txt3
-rw-r--r--supported-tools.md3
-rw-r--r--test/command_callback/test_angular_command_callback.vader44
-rw-r--r--test/test-projects/angular/node_modules/@angular/language-server/bin/ngserver0
-rw-r--r--test/test-projects/angular/node_modules/@angular/language-service/dummy0
-rw-r--r--test/test_go_to_definition.vader23
13 files changed, 230 insertions, 48 deletions
diff --git a/ale_linters/html/angular.vim b/ale_linters/html/angular.vim
new file mode 100644
index 00000000..f550d665
--- /dev/null
+++ b/ale_linters/html/angular.vim
@@ -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'),
+\})
diff --git a/autoload/ale/assert.vim b/autoload/ale/assert.vim
index 8c7a5461..8200a3bf 100644
--- a/autoload/ale/assert.vim
+++ b/autoload/ale/assert.vim
@@ -169,8 +169,21 @@ function! ale#assert#LinterNotExecuted() abort
let l:buffer = bufnr('')
let l:linter = s:GetLinter()
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
function! ale#assert#LSPOptions(expected_options) abort
diff --git a/autoload/ale/definition.vim b/autoload/ale/definition.vim
index a5a9271e..9574017b 100644
--- a/autoload/ale/definition.vim
+++ b/autoload/ale/definition.vim
@@ -66,9 +66,17 @@ function! ale#definition#HandleLSPResponse(conn_id, response) abort
endif
for l:item in l:result
- 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
+ if has_key(l:item, 'targetUri')
+ " LocationLink items use targetUri
+ 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#util#Open(l:filename, l:line, l:column, l:options)
diff --git a/autoload/ale/lsp_linter.vim b/autoload/ale/lsp_linter.vim
index 0d039198..b8885f31 100644
--- a/autoload/ale/lsp_linter.vim
+++ b/autoload/ale/lsp_linter.vim
@@ -294,14 +294,15 @@ function! s:StartLSP(options, address, executable, command) abort
call ale#lsp#MarkConnectionAsTsserver(l:conn_id)
endif
+ let l:cwd = ale#linter#GetCwd(l:buffer, l:linter)
let l:command = ale#command#FormatCommand(
\ l:buffer,
\ a:executable,
\ a:command,
\ 0,
\ v:false,
- \ v:null,
- \ [],
+ \ l:cwd,
+ \ ale#GetFilenameMappings(l:buffer, l:linter.name),
\)[1]
let l:command = ale#job#PrepareCommand(l:buffer, l:command)
let l:ready = ale#lsp#StartProgram(l:conn_id, a:executable, l:command)
diff --git a/autoload/ale/test.vim b/autoload/ale/test.vim
index 6fcbf35e..4d75d515 100644
--- a/autoload/ale/test.vim
+++ b/autoload/ale/test.vim
@@ -34,12 +34,11 @@ function! ale#test#RestoreDirectory() abort
unlet! g:dir
endfunction
-" Change the filename for the current buffer using a relative path to
-" the script without running autocmd commands.
+" Get a filename for the current buffer using a relative path to the script.
"
" 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
+function! ale#test#GetFilename(path) abort
let l:dir = get(g:, 'dir', '')
if empty(l:dir)
@@ -50,7 +49,17 @@ function! ale#test#SetFilename(path) abort
\ ? 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
function! s:RemoveModule(results) abort
diff --git a/doc/ale-html.txt b/doc/ale-html.txt
index c78dc4cd..2c048148 100644
--- a/doc/ale-html.txt
+++ b/doc/ale-html.txt
@@ -3,12 +3,40 @@ 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` options for HTMl is the same as the options for JavaScript,
-and both of them reads `./.fecsrc` as the default configuration file.
+`fecs` options for HTML are the same as the options for JavaScript, and both
+of them read `./.fecsrc` as the default configuration file.
+
See: |ale-javascript-fecs|.
+
===============================================================================
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|
+
+===============================================================================
+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*
@@ -98,39 +160,6 @@ g:ale_html_tidy_use_global *g:html_tidy_use_global*
===============================================================================
-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*
See |ale-write-good-options|
diff --git a/doc/ale-supported-languages-and-tools.txt b/doc/ale-supported-languages-and-tools.txt
index e6764144..cc25ca95 100644
--- a/doc/ale-supported-languages-and-tools.txt
+++ b/doc/ale-supported-languages-and-tools.txt
@@ -216,10 +216,11 @@ Notes:
* HCL
* `terraform-fmt`
* HTML
- * `HTMLHint`
* `alex`!!
+ * `angular`
* `fecs`
* `html-beautify`
+ * `htmlhint`
* `prettier`
* `proselint`
* `tidy`
diff --git a/doc/ale.txt b/doc/ale.txt
index 0fc95ae0..66b2e4ce 100644
--- a/doc/ale.txt
+++ b/doc/ale.txt
@@ -2777,12 +2777,13 @@ documented in additional help files.
hcl.....................................|ale-hcl-options|
terraform-fmt.........................|ale-hcl-terraform-fmt|
html....................................|ale-html-options|
+ angular...............................|ale-html-angular|
fecs..................................|ale-html-fecs|
html-beautify.........................|ale-html-beautify|
htmlhint..............................|ale-html-htmlhint|
- tidy..................................|ale-html-tidy|
prettier..............................|ale-html-prettier|
stylelint.............................|ale-html-stylelint|
+ tidy..................................|ale-html-tidy|
write-good............................|ale-html-write-good|
idris...................................|ale-idris-options|
idris.................................|ale-idris-idris|
diff --git a/supported-tools.md b/supported-tools.md
index a522d748..616008cc 100644
--- a/supported-tools.md
+++ b/supported-tools.md
@@ -225,10 +225,11 @@ formatting.
* HCL
* [terraform-fmt](https://github.com/hashicorp/terraform)
* HTML
- * [HTMLHint](http://htmlhint.com/)
* [alex](https://github.com/wooorm/alex) :floppy_disk:
+ * [angular](https://www.npmjs.com/package/@angular/language-server)
* [fecs](http://fecs.baidu.com/)
* [html-beautify](https://beautifier.io/)
+ * [htmlhint](http://htmlhint.com/)
* [prettier](https://github.com/prettier/prettier)
* [proselint](http://proselint.com/)
* [tidy](http://www.html-tidy.org/)
diff --git a/test/command_callback/test_angular_command_callback.vader b/test/command_callback/test_angular_command_callback.vader
new file mode 100644
index 00000000..c5de3d87
--- /dev/null
+++ b/test/command_callback/test_angular_command_callback.vader
@@ -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'
diff --git a/test/test-projects/angular/node_modules/@angular/language-server/bin/ngserver b/test/test-projects/angular/node_modules/@angular/language-server/bin/ngserver
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/test-projects/angular/node_modules/@angular/language-server/bin/ngserver
diff --git a/test/test-projects/angular/node_modules/@angular/language-service/dummy b/test/test-projects/angular/node_modules/@angular/language-service/dummy
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/test-projects/angular/node_modules/@angular/language-service/dummy
diff --git a/test/test_go_to_definition.vader b/test/test_go_to_definition.vader
index c7805932..3807bb05 100644
--- a/test/test_go_to_definition.vader
+++ b/test/test_go_to_definition.vader
@@ -343,6 +343,29 @@ Execute(Other files should be jumped to for LSP definition responses):
AssertEqual [3, 8], getpos('.')[1:2]
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):
call ale#definition#SetMap({3: {'open_in': 'current-buffer'}})
call ale#definition#HandleLSPResponse(