@@ -19,6 +19,7 @@ defmodule NextLS do
19
19
alias GenLSP.Requests.TextDocumentDefinition
20
20
alias GenLSP.Requests.TextDocumentDocumentSymbol
21
21
alias GenLSP.Requests.TextDocumentFormatting
22
+ alias GenLSP.Requests.TextDocumentReferences
22
23
alias GenLSP.Requests.WorkspaceSymbol
23
24
alias GenLSP.Structures.DidChangeWatchedFilesParams
24
25
alias GenLSP.Structures.DidChangeWorkspaceFoldersParams
@@ -108,6 +109,7 @@ defmodule NextLS do
108
109
document_formatting_provider: true ,
109
110
workspace_symbol_provider: true ,
110
111
document_symbol_provider: true ,
112
+ references_provider: true ,
111
113
definition_provider: true ,
112
114
workspace: % {
113
115
workspace_folders: % GenLSP.Structures.WorkspaceFoldersServerCapabilities {
@@ -171,6 +173,64 @@ defmodule NextLS do
171
173
{ :reply , symbols , lsp }
172
174
end
173
175
176
+ # TODO handle `context: %{includeDeclaration: true}` to include the current symbol definition among
177
+ # the results.
178
+ def handle_request ( % TextDocumentReferences { params: % { position: position , text_document: % { uri: uri } } } , lsp ) do
179
+ file = URI . parse ( uri ) . path
180
+ line = position . line + 1
181
+ col = position . character + 1
182
+
183
+ locations =
184
+ dispatch ( lsp . assigns . registry , :databases , fn databases ->
185
+ Enum . flat_map ( databases , fn { database , _ } ->
186
+ references =
187
+ case symbol_info ( file , line , col , database ) do
188
+ { :function , module , function } ->
189
+ DB . query (
190
+ database ,
191
+ ~Q"""
192
+ SELECT file, start_line, end_line, start_column, end_column
193
+ FROM "references" as refs
194
+ WHERE refs.identifier = ?
195
+ AND refs.type = ?
196
+ AND refs.module = ?
197
+ AND NOT like('/home/runner/work/elixir/%', refs.file)
198
+ """ ,
199
+ [ function , "function" , module ]
200
+ )
201
+
202
+ { :module , module } ->
203
+ DB . query (
204
+ database ,
205
+ ~Q"""
206
+ SELECT file, start_line, end_line, start_column, end_column
207
+ FROM "references" as refs
208
+ WHERE refs.module = ?
209
+ AND refs.type = ?
210
+ AND NOT like('/home/runner/work/elixir/%', refs.file)
211
+ """ ,
212
+ [ module , "alias" ]
213
+ )
214
+
215
+ :unknown ->
216
+ [ ]
217
+ end
218
+
219
+ for [ file , start_line , end_line , start_column , end_column ] <- references do
220
+ % Location {
221
+ uri: "file://#{ file } " ,
222
+ range: % Range {
223
+ start: % Position { line: clamp ( start_line - 1 ) , character: clamp ( start_column - 1 ) } ,
224
+ end: % Position { line: clamp ( end_line - 1 ) , character: clamp ( end_column - 1 ) }
225
+ }
226
+ }
227
+ end
228
+ end )
229
+ end )
230
+
231
+ { :reply , locations , lsp }
232
+ end
233
+
174
234
def handle_request ( % WorkspaceSymbol { params: % { query: query } } , lsp ) do
175
235
filter = fn sym ->
176
236
if query == "" do
@@ -603,4 +663,57 @@ defmodule NextLS do
603
663
{ ^ ref , result } -> result
604
664
end
605
665
end
666
+
667
+ defp symbol_info ( file , line , col , database ) do
668
+ definition_query =
669
+ ~Q"""
670
+ SELECT module, type, name
671
+ FROM "symbols" sym
672
+ WHERE sym.file = ?
673
+ AND sym.line = ?
674
+ ORDER BY sym.id ASC
675
+ LIMIT 1
676
+ """
677
+
678
+ reference_query = ~Q"""
679
+ SELECT identifier, type, module
680
+ FROM "references" refs
681
+ WHERE refs.file = ?
682
+ AND refs.start_line <= ? AND refs.end_line >= ?
683
+ AND refs.start_column <= ? AND refs.end_column >= ?
684
+ ORDER BY refs.id ASC
685
+ LIMIT 1
686
+ """
687
+
688
+ case DB . query ( database , definition_query , [ file , line ] ) do
689
+ [ [ module , "defmodule" , _ ] ] ->
690
+ { :module , module }
691
+
692
+ [ [ module , "defstruct" , _ ] ] ->
693
+ { :module , module }
694
+
695
+ [ [ module , "def" , function ] ] ->
696
+ { :function , module , function }
697
+
698
+ [ [ module , "defp" , function ] ] ->
699
+ { :function , module , function }
700
+
701
+ [ [ module , "defmacro" , function ] ] ->
702
+ { :function , module , function }
703
+
704
+ _unknown_definition ->
705
+ case DB . query ( database , reference_query , [ file , line , line , col , col ] ) do
706
+ [ [ function , "function" , module ] ] ->
707
+ { :function , module , function }
708
+
709
+ [ [ _alias , "alias" , module ] ] ->
710
+ { :module , module }
711
+
712
+ _unknown_reference ->
713
+ :unknown
714
+ end
715
+ end
716
+ end
717
+
718
+ defp clamp ( line ) , do: max ( line , 0 )
606
719
end
0 commit comments