Skip to content

Commit

Permalink
improve docs handling
Browse files Browse the repository at this point in the history
  • Loading branch information
mhanberg committed May 2, 2024
1 parent 3aa90ec commit fcfc15f
Show file tree
Hide file tree
Showing 5 changed files with 211 additions and 149 deletions.
122 changes: 49 additions & 73 deletions lib/next_ls.ex
Original file line number Diff line number Diff line change
Expand Up @@ -402,32 +402,16 @@ defmodule NextLS do
end)

value =
with {:ok, {:docs_v1, _, _lang, content_type, %{"en" => mod_doc}, _, fdocs}} <- result do
with {:ok, result} <- result,
%NextLS.Docs{} = doc <- NextLS.Docs.new(result, reference.module) do
case reference.type do
"alias" ->
"""
## #{reference.module}
#{NextLS.HoverHelpers.to_markdown(content_type, mod_doc)}
"""
NextLS.Docs.module(doc)

"function" ->
doc =
Enum.find(fdocs, fn {{type, name, _a}, _, _, _doc, _} ->
type in [:function, :macro] and to_string(name) == reference.identifier
end)

case doc do
{_, _, _, %{"en" => fdoc}, _} ->
"""
## #{Macro.to_string(mod)}.#{reference.identifier}/#{reference.arity}
#{NextLS.HoverHelpers.to_markdown(content_type, fdoc)}
"""

_ ->
nil
end
NextLS.Docs.function(doc, fn name, a, documentation, _other ->
to_string(name) == reference.identifier and documentation != :hidden and a >= reference.arity
end)

_ ->
nil
Expand Down Expand Up @@ -590,62 +574,33 @@ defmodule NextLS do
completion_item
else
%{"uri" => uri, "data" => data} ->
docs =
case data |> Base.decode64!() |> :erlang.binary_to_term() do
{mod, function, arity} ->
result =
dispatch(lsp.assigns.registry, :runtimes, fn entries ->
[result] =
for {runtime, %{uri: wuri}} <- entries, String.starts_with?(uri, wuri) do
Runtime.call(runtime, {Code, :fetch_docs, [mod]})
end

result
end)

with {:ok, {:docs_v1, _, _lang, content_type, %{"en" => _mod_doc}, _, fdocs}} <- result do
doc =
Enum.find(fdocs, fn {{type, name, a}, _some_number, _signature, doc, _other} ->
type in [:function, :macro] and to_string(name) == function and doc != :hidden and a >= arity
end)

case doc do
{_, _, [signature], %{"en" => fdoc}, _} ->
"""
## #{Macro.to_string(mod)}.#{function}/#{arity}
`#{signature}`
data = data |> Base.decode64!() |> :erlang.binary_to_term()

#{NextLS.HoverHelpers.to_markdown(content_type, fdoc)}
"""

_ ->
nil
end
else
_ -> nil
end
module =
case data do
{mod, _function, _arity} -> mod
mod -> mod
end

mod ->
result =
dispatch(lsp.assigns.registry, :runtimes, fn entries ->
[result] =
for {runtime, %{uri: wuri}} <- entries, String.starts_with?(uri, wuri) do
Runtime.call(runtime, {Code, :fetch_docs, [mod]})
end
result =
dispatch_to_workspace(lsp.assigns.registry, uri, fn runtime ->
Runtime.call(runtime, {Code, :fetch_docs, [module]})
end)

result
docs =
with {:ok, doc} <- result,
%NextLS.Docs{} = doc <- NextLS.Docs.new(doc, module) do
case data do
{_mod, function, arity} ->
NextLS.Docs.function(doc, fn name, a, documentation, _other ->
to_string(name) == function and documentation != :hidden and a >= arity
end)

with {:ok, {:docs_v1, _, _lang, content_type, %{"en" => doc}, _, _fdocs}} <- result do
"""
## #{Macro.to_string(mod)}
#{NextLS.HoverHelpers.to_markdown(content_type, doc)}
"""
else
_ -> nil
end
mod when is_atom(mod) ->
NextLS.Docs.module(doc)
end
else
_ -> nil
end

%{completion_item | documentation: docs}
Expand Down Expand Up @@ -1438,6 +1393,27 @@ defmodule NextLS do
end
end

defp dispatch_to_workspace(registry, uri, callback) do
ref = make_ref()
me = self()

Registry.dispatch(registry, :runtimes, fn entries ->
[result] =
for {runtime, %{uri: wuri}} <- entries, String.starts_with?(uri, wuri) do
callback.(runtime)
end

send(me, {ref, result})
end)

receive do
{^ref, result} -> result
after
1000 ->
:timeout
end
end

defp symbol_info(file, line, col, database) do
definition_query = ~Q"""
SELECT module, type, name
Expand Down
2 changes: 1 addition & 1 deletion lib/next_ls/autocomplete.ex
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@ defmodule NextLS.Autocomplete do
%{
kind: :module,
name: mod,
data: mod
data: String.to_atom(mod)
# docs: """
### #{Macro.to_string(mod)}

Expand Down
154 changes: 154 additions & 0 deletions lib/next_ls/docs.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
defmodule NextLS.Docs do
@moduledoc false

defstruct module: nil, mdoc: nil, functions: [], content_type: nil

def new({:docs_v1, _, _lang, content_type, mdoc, _, fdocs}, module) do
mdoc =
case mdoc do
%{"en" => mdoc} -> mdoc
_ -> nil
end

%__MODULE__{
content_type: content_type,
module: module,
mdoc: mdoc,
functions: fdocs
}
end

def new(_, _) do
nil
end

def module(%__MODULE__{} = doc) do
"""
## #{Macro.to_string(doc.module)}
#{to_markdown(doc.content_type, doc.mdoc)}
"""
end

def function(%__MODULE__{} = doc, callback) do
result =
Enum.find(doc.functions, fn {{type, name, arity}, _some_number, _signature, doc, other} ->
type in [:function, :macro] and callback.(name, arity, doc, other)
end)

case result do
{{_, name, arity}, _some_number, signature, %{"en" => fdoc}, _other} ->
"""
## #{Macro.to_string(doc.module)}.#{name}/#{arity}
`#{signature}`
#{to_markdown(doc.content_type, fdoc)}
"""

_ ->
nil
end
end

@spec to_markdown(String.t(), String.t() | list()) :: String.t()
def to_markdown(type, docs)
def to_markdown("text/markdown", docs), do: docs

def to_markdown("application/erlang+html" = type, [{:p, _, children} | rest]) do
String.trim(to_markdown(type, children) <> "\n\n" <> to_markdown(type, rest))
end

def to_markdown("application/erlang+html" = type, [{:div, attrs, children} | rest]) do
prefix =
if attrs[:class] in ~w<warning note do dont quote> do
"> "
else
""
end

prefix <> to_markdown(type, children) <> "\n\n" <> to_markdown(type, rest)
end

def to_markdown("application/erlang+html" = type, [{:a, attrs, children} | rest]) do
space = if List.last(children) == " ", do: " ", else: ""

"[#{String.trim(to_markdown(type, children))}](#{attrs[:href]})" <> space <> to_markdown(type, rest)
end

def to_markdown("application/erlang+html" = type, [doc | rest]) when is_binary(doc) do
doc <> to_markdown(type, rest)
end

def to_markdown("application/erlang+html" = type, [{:h1, _, children} | rest]) do
"# #{to_markdown(type, children)}\n" <> to_markdown(type, rest)
end

def to_markdown("application/erlang+html" = type, [{:h2, _, children} | rest]) do
"## #{to_markdown(type, children)}\n" <> to_markdown(type, rest)
end

def to_markdown("application/erlang+html" = type, [{:h3, _, children} | rest]) do
"### #{to_markdown(type, children)}\n" <> to_markdown(type, rest)
end

def to_markdown("application/erlang+html" = type, [{:h4, _, children} | rest]) do
"#### #{to_markdown(type, children)}\n" <> to_markdown(type, rest)
end

def to_markdown("application/erlang+html" = type, [{:h5, _, children} | rest]) do
"##### #{to_markdown(type, children)}\n" <> to_markdown(type, rest)
end

def to_markdown("application/erlang+html" = type, [{:pre, _, [{:code, _, children}]} | rest]) do
"```erlang\n#{to_markdown(type, children)}\n```\n\n" <> to_markdown(type, rest)
end

def to_markdown("application/erlang+html" = type, [{:ul, [class: "types"], lis} | rest]) do
"### Types\n\n#{to_markdown(type, lis)}\n" <> to_markdown(type, rest)
end

def to_markdown("application/erlang+html" = type, [{:ul, _, lis} | rest]) do
"#{to_markdown(type, lis)}\n" <> to_markdown(type, rest)
end

def to_markdown("application/erlang+html" = type, [{:li, [name: text], _} | rest]) do
"* #{text}\n" <> to_markdown(type, rest)
end

def to_markdown("application/erlang+html" = type, [{:li, _, children} | rest]) do
"* #{to_markdown(type, children)}\n" <> to_markdown(type, rest)
end

def to_markdown("application/erlang+html" = type, [{:code, _, bins} | rest]) do
"`#{IO.iodata_to_binary(bins)}`" <> to_markdown(type, rest)
end

def to_markdown("application/erlang+html" = type, [{:em, _, bins} | rest]) do
"_#{IO.iodata_to_binary(bins)}_" <> to_markdown(type, rest)
end

def to_markdown("application/erlang+html" = type, [{:dl, _, lis} | rest]) do
"#{to_markdown(type, lis)}\n" <> to_markdown(type, rest)
end

def to_markdown("application/erlang+html" = type, [{:dt, _, children} | rest]) do
"* #{to_markdown(type, children)}\n" <> to_markdown(type, rest)
end

def to_markdown("application/erlang+html" = type, [{:dd, _, children} | rest]) do
"#{to_markdown(type, children)}\n" <> to_markdown(type, rest)
end

def to_markdown("application/erlang+html" = type, [{:i, _, children} | rest]) do
"_#{IO.iodata_to_binary(children)}_" <> to_markdown(type, rest)
end

def to_markdown("application/erlang+html", []) do
""
end

def to_markdown("application/erlang+html", nil) do
""
end
end
68 changes: 0 additions & 68 deletions lib/next_ls/helpers/hover_helpers.ex

This file was deleted.

Loading

0 comments on commit fcfc15f

Please sign in to comment.