summaryrefslogtreecommitdiff
path: root/autoload
diff options
context:
space:
mode:
authorw0rp <devw0rp@gmail.com>2018-04-22 19:49:24 +0100
committerw0rp <devw0rp@gmail.com>2018-04-22 19:49:30 +0100
commit286abd12d3adf3fdb3ed90a71b9dd8e8af4bf841 (patch)
tree07f032fb2e48d6054eb933bc4261d4bcea7950f0 /autoload
parent5a365e792693373413984a7eae2d64f7d92c1238 (diff)
downloadale-286abd12d3adf3fdb3ed90a71b9dd8e8af4bf841.zip
Add support for finding references using LSP servers or tsserver
Diffstat (limited to 'autoload')
-rw-r--r--autoload/ale/lsp/message.vim10
-rw-r--r--autoload/ale/lsp/tsserver_message.vim8
-rw-r--r--autoload/ale/references.vim111
3 files changed, 129 insertions, 0 deletions
diff --git a/autoload/ale/lsp/message.vim b/autoload/ale/lsp/message.vim
index 0b73cfc2..037e6ce2 100644
--- a/autoload/ale/lsp/message.vim
+++ b/autoload/ale/lsp/message.vim
@@ -116,3 +116,13 @@ function! ale#lsp#message#Definition(buffer, line, column) abort
\ 'position': {'line': a:line - 1, 'character': a:column},
\}]
endfunction
+
+function! ale#lsp#message#References(buffer, line, column) abort
+ return [0, 'textDocument/references', {
+ \ 'textDocument': {
+ \ 'uri': ale#path#ToURI(expand('#' . a:buffer . ':p')),
+ \ },
+ \ 'position': {'line': a:line - 1, 'character': a:column},
+ \ 'context': {'includeDeclaration': v:false},
+ \}]
+endfunction
diff --git a/autoload/ale/lsp/tsserver_message.vim b/autoload/ale/lsp/tsserver_message.vim
index b9bd7a01..415fde95 100644
--- a/autoload/ale/lsp/tsserver_message.vim
+++ b/autoload/ale/lsp/tsserver_message.vim
@@ -61,3 +61,11 @@ function! ale#lsp#tsserver_message#Definition(buffer, line, column) abort
\ 'file': expand('#' . a:buffer . ':p'),
\}]
endfunction
+
+function! ale#lsp#tsserver_message#References(buffer, line, column) abort
+ return [0, 'ts@references', {
+ \ 'line': a:line,
+ \ 'offset': a:column,
+ \ 'file': expand('#' . a:buffer . ':p'),
+ \}]
+endfunction
diff --git a/autoload/ale/references.vim b/autoload/ale/references.vim
new file mode 100644
index 00000000..9777519d
--- /dev/null
+++ b/autoload/ale/references.vim
@@ -0,0 +1,111 @@
+let s:references_map = {}
+
+" Used to get the references map in tests.
+function! ale#references#GetMap() abort
+ return deepcopy(s:references_map)
+endfunction
+
+" Used to set the references map in tests.
+function! ale#references#SetMap(map) abort
+ let s:references_map = a:map
+endfunction
+
+function! ale#references#ClearLSPData() abort
+ let s:references_map = {}
+endfunction
+
+function! ale#references#HandleTSServerResponse(conn_id, response) abort
+ if get(a:response, 'command', '') is# 'references'
+ \&& has_key(s:references_map, a:response.request_seq)
+ call remove(s:references_map, a:response.request_seq)
+
+ if get(a:response, 'success', v:false) is v:true
+ let l:item_list = []
+
+ for l:response_item in a:response.body.refs
+ call add(l:item_list, {
+ \ 'filename': l:response_item.file,
+ \ 'line': l:response_item.start.line,
+ \ 'column': l:response_item.start.offset,
+ \})
+ endfor
+
+ if empty(l:item_list)
+ call ale#util#Execute('echom ''No references found.''')
+ else
+ call ale#preview#ShowSelection(l:item_list)
+ endif
+ endif
+ endif
+endfunction
+
+function! ale#references#HandleLSPResponse(conn_id, response) abort
+ if has_key(a:response, 'id')
+ \&& has_key(s:references_map, a:response.id)
+ call remove(s:references_map, a:response.id)
+
+ " The result can be a Dictionary item, a List of the same, or null.
+ let l:result = get(a:response, 'result', [])
+ let l:item_list = []
+
+ for l:response_item in l:result
+ call add(l:item_list, {
+ \ 'filename': ale#path#FromURI(l:response_item.uri),
+ \ 'line': l:response_item.range.start.line + 1,
+ \ 'column': l:response_item.range.start.character + 1,
+ \})
+ endfor
+
+ if empty(l:item_list)
+ call ale#util#Execute('echom ''No references found.''')
+ else
+ call ale#preview#ShowSelection(l:item_list)
+ endif
+ endif
+endfunction
+
+function! s:FindReferences(linter) abort
+ let l:buffer = bufnr('')
+ let [l:line, l:column] = getcurpos()[1:2]
+
+ let l:Callback = a:linter.lsp is# 'tsserver'
+ \ ? function('ale#references#HandleTSServerResponse')
+ \ : function('ale#references#HandleLSPResponse')
+
+ let l:lsp_details = ale#linter#StartLSP(l:buffer, a:linter, l:Callback)
+
+ if empty(l:lsp_details)
+ return 0
+ endif
+
+ let l:id = l:lsp_details.connection_id
+ let l:root = l:lsp_details.project_root
+
+ if a:linter.lsp is# 'tsserver'
+ let l:message = ale#lsp#tsserver_message#References(
+ \ l:buffer,
+ \ l:line,
+ \ l:column
+ \)
+ else
+ " Send a message saying the buffer has changed first, or the
+ " references position probably won't make sense.
+ call ale#lsp#Send(l:id, ale#lsp#message#DidChange(l:buffer), l:root)
+
+ let l:column = min([l:column, len(getline(l:line))])
+
+ let l:message = ale#lsp#message#References(l:buffer, l:line, l:column)
+ endif
+
+ let l:request_id = ale#lsp#Send(l:id, l:message, l:root)
+
+ let s:references_map[l:request_id] = {}
+endfunction
+
+function! ale#references#Find() abort
+ for l:linter in ale#linter#Get(&filetype)
+ if !empty(l:linter.lsp)
+ call s:FindReferences(l:linter)
+ endif
+ endfor
+endfunction