Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
mhanberg committed Jun 28, 2023
1 parent 80d0679 commit defbe09
Show file tree
Hide file tree
Showing 3 changed files with 131 additions and 13 deletions.
19 changes: 17 additions & 2 deletions lib/next_ls.ex
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
defmodule NextLS do



@moduledoc false
use GenLSP

Expand All @@ -18,6 +21,7 @@ defmodule NextLS do
}

alias GenLSP.Requests.{
TextDocumentDocumentSymbol,
Initialize,
Shutdown,
TextDocumentFormatting,
Expand All @@ -38,7 +42,8 @@ defmodule NextLS do
TextEdit,
WorkDoneProgressBegin,
WorkDoneProgressEnd,
SymbolInformation
SymbolInformation,
DocumentSymbol
}

alias NextLS.Runtime
Expand Down Expand Up @@ -98,12 +103,22 @@ defmodule NextLS do
change: TextDocumentSyncKind.full()
},
document_formatting_provider: true,
workspace_symbol_provider: true
workspace_symbol_provider: true,
document_symbol_provider: true
},
server_info: %{name: "NextLS"}
}, assign(lsp, root_uri: root_uri)}
end

def handle_request(%TextDocumentDocumentSymbol{params: %{text_document: %{uri: uri}}}, lsp) do
file = URI.parse(uri).path

symbols = SymbolTable.symbols(lsp.assigns.symbol_table, file) |> List.wrap()
dbg symbols

{:reply, symbols, lsp}
end

def handle_request(%WorkspaceSymbol{params: %{query: query}}, lsp) do
filter = fn sym ->
if query == "" do
Expand Down
116 changes: 107 additions & 9 deletions lib/next_ls/symbol_table.ex
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
defmodule NextLS.SymbolTable do

@moduledoc false
use GenServer

alias GenLSP.Structures.DocumentSymbol
alias GenLSP.Structures.Range
alias GenLSP.Structures.Position

defmodule Symbol do
defstruct [:file, :module, :type, :name, :line, :col]
defstruct [:file, :module, :type, :name, :line, :col, :document]

def new(args) do
struct(__MODULE__, args)
Expand All @@ -20,6 +25,9 @@ defmodule NextLS.SymbolTable do
@spec symbols(pid() | atom()) :: list(struct())
def symbols(server), do: GenServer.call(server, :symbols)

@spec symbols(pid() | atom(), String.t()) :: list(struct())
def symbols(server, file), do: GenServer.call(server, {:symbols, file})

def close(server), do: GenServer.call(server, :close)

def init(args) do
Expand All @@ -36,10 +44,26 @@ defmodule NextLS.SymbolTable do
{:ok, %{table: name}}
end

def handle_call({:symbols, file}, _, state) do
symbols =
case :dets.lookup(state.table, file) do
[{_, symbols} | _rest] -> symbols
_ -> []
end

{:reply, symbols, state}
end

def handle_call(:symbols, _, state) do
symbols =
:dets.foldl(
fn {_key, symbol}, acc -> [symbol | acc] end,
fn {_key, symbol}, acc ->
if String.match?(to_string(symbol.name), ~r/__.*__/) do
acc
else
[symbol | acc]
end
end,
[],
state.table
)
Expand All @@ -59,10 +83,17 @@ defmodule NextLS.SymbolTable do
module_line: module_line,
struct: struct,
file: file,
defs: defs
defs: defs,
ast: ast
} = symbols

{_new_ast, acc} = Macro.prewalk(ast, nil, &walker/2)

document = File.read!(file)
:dets.delete(state.table, mod)
:dets.delete(state.table, file)

:dets.insert(state.table, {file, acc})

:dets.insert(
state.table,
Expand All @@ -73,7 +104,8 @@ defmodule NextLS.SymbolTable do
type: :defmodule,
name: Macro.to_string(mod),
line: module_line,
col: 1
col: 1,
document: document
}}
)

Expand All @@ -89,14 +121,13 @@ defmodule NextLS.SymbolTable do
type: :defstruct,
name: "%#{Macro.to_string(mod)}{}",
line: meta[:line],
col: 1
col: 1,
document: document
}}
)
end

for {name, {:v1, type, _meta, clauses}} <- defs,
not String.match?(to_string(name), ~r/__.*__/),
{meta, _, _, _} <- clauses do
for {name, {:v1, type, _meta, clauses}} <- defs, {meta, _, _, _} <- clauses do
:dets.insert(
state.table,
{mod,
Expand All @@ -106,11 +137,78 @@ defmodule NextLS.SymbolTable do
type: type,
name: name,
line: meta[:line],
col: meta[:column] || 1
col: meta[:column] || 1,
document: document
}}
)
end

{:noreply, state}
end

defp elixir_kind_to_lsp_kind(:defmodule), do: GenLSP.Enumerations.SymbolKind.module()
defp elixir_kind_to_lsp_kind(:defstruct), do: GenLSP.Enumerations.SymbolKind.struct()

defp elixir_kind_to_lsp_kind(kind) when kind in [:def, :defp, :defmacro, :defmacrop],
do: GenLSP.Enumerations.SymbolKind.function()

defp walker({:defmodule, meta, [name | _children]} = macro, nil) do
{macro,
%DocumentSymbol{
name: Macro.to_string(name) |> String.replace("\n", ""),
kind: GenLSP.Enumerations.SymbolKind.module(),
children: [],
range: %Range{
start: %Position{line: meta[:do][:line] - 1, character: meta[:do][:column] - 1},
end: %Position{line: meta[:end][:line] - 1, character: meta[:end][:column] - 1}
},
selection_range: %Range{
start: %Position{line: meta[:line] - 1, character: meta[:column] - 1},
end: %Position{line: meta[:line] - 1, character: meta[:column] - 1}
}
}}
end

# TODO: this needs to be a normal recursive function traversal, so that we don't walk
# these AST nodes anyway
defp walker({:defmodule, _meta, [_name | _children]} = macro, %DocumentSymbol{} = doc) do
{_, child} = Macro.prewalk(macro, nil, &walker/2)

dbg(child)
{macro, %DocumentSymbol{doc | children: doc.children ++ [child]}}
end

defp walker({type, meta, [name | _children]} = macro, %DocumentSymbol{} = root)
when type in [:def, :defp, :defmacro, :defmacro, :defstruct] do
{macro,
%DocumentSymbol{
root
| children:
root.children ++
[
%DocumentSymbol{
name: Macro.to_string(name) |> String.replace("\n", "") |> dbg(),
kind: elixir_kind_to_lsp_kind(type),
range: %Range{
start: %Position{
line: meta[:line] - 1,
character: meta[:column] - 1
},
end: %Position{
line: (meta[:end] || meta[:end_of_expression] || meta)[:line] - 1,
character: (meta[:end] || meta[:end_of_expression] || meta)[:column] - 1
}
},
selection_range: %Range{
start: %Position{line: meta[:line] - 1, character: meta[:column] - 1},
end: %Position{line: meta[:line] - 1, character: meta[:column] - 1}
}
}
]
}}
end

defp walker(other, acc) do
{other, acc}
end
end
9 changes: 7 additions & 2 deletions priv/monkey/_next_ls_private_compiler.ex
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,16 @@ defmodule NextLSPrivate.Tracer do

{:ok, {_, [{'Dbgi', bin}]}} = :beam_lib.chunks(bytecode, ['Dbgi'])

{:debug_info_v1, _, {_, %{line: line, struct: struct}, _}} = :erlang.binary_to_term(bin)
ast =
env.file
|> File.read!()
|> Code.string_to_quoted!(token_metadata: true, columns: true)

{:debug_info_v1, _, {_, %{line: line, struct: struct}, _} = foo} = :erlang.binary_to_term(bin)

Process.send(
parent,
{:tracer, %{file: env.file, module: env.module, module_line: line, struct: struct, defs: defs}},
{:tracer, %{file: env.file, module: env.module, module_line: line, struct: struct, defs: defs, ast: ast}},
[]
)

Expand Down

0 comments on commit defbe09

Please sign in to comment.