Skip to content

Commit b61dc56

Browse files
committed
improve rendering of docs in hover
Adapts changes from elixir-lsp/elixir_sense#280
1 parent 5efc5d8 commit b61dc56

File tree

8 files changed

+438
-141
lines changed

8 files changed

+438
-141
lines changed
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
defmodule ElixirLS.LanguageServer.DocLinks do
2+
@moduledoc """
3+
Provides links to hex docs
4+
"""
5+
6+
@hex_base_url "https://hexdocs.pm"
7+
8+
defp get_erts_modules do
9+
{:ok, [[erlang_lib_dir]]} = :init.get_argument(:root)
10+
erts_version = :erlang.system_info(:version)
11+
erts_app_path = Path.join([erlang_lib_dir, "lib", "erts-#{erts_version}", "ebin", "erts.app"])
12+
13+
{:ok, [{:application, _, props}]} = :file.consult(erts_app_path)
14+
modules = Keyword.get(props, :modules)
15+
for module <- modules, into: %{}, do: {module, {:erts, erts_version}}
16+
end
17+
18+
defp get_app(module) do
19+
module_to_app =
20+
for {app, _, vsn} <- Application.loaded_applications(),
21+
{:ok, app_modules} = :application.get_key(app, :modules),
22+
mod <- app_modules,
23+
into: %{},
24+
do: {mod, {app, vsn}}
25+
26+
module_to_app
27+
|> Map.merge(get_erts_modules())
28+
|> Map.get(module)
29+
end
30+
31+
def hex_docs_module_link(module) do
32+
{app, vsn} = get_app(module)
33+
"#{@hex_base_url}/#{app}/#{vsn}/#{inspect(module)}.html"
34+
end
35+
36+
def hex_docs_function_link(module, function, arity) do
37+
{app, vsn} = get_app(module)
38+
"#{@hex_base_url}/#{app}/#{vsn}/#{inspect(module)}.html##{function}/#{arity}"
39+
end
40+
41+
def hex_docs_type_link(module, type, arity) do
42+
{app, vsn} = get_app(module)
43+
"#{@hex_base_url}/#{app}/#{vsn}/#{inspect(module)}.html#t:#{type}/#{arity}"
44+
end
45+
end
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
defmodule ElixirLS.LanguageServer.MarkdownUtils do
2+
# Find the lowest heading level in the fragment
3+
defp lowest_heading_level(fragment) do
4+
case Regex.scan(~r/(#+)/, fragment) do
5+
[] ->
6+
nil
7+
8+
matches ->
9+
matches
10+
|> Enum.map(fn [_, heading] -> String.length(heading) end)
11+
|> Enum.min()
12+
end
13+
end
14+
15+
# Adjust heading levels of an embedded markdown fragment
16+
def adjust_headings(fragment, base_level) do
17+
min_level = lowest_heading_level(fragment)
18+
19+
if min_level do
20+
level_difference = base_level + 1 - min_level
21+
22+
Regex.replace(~r/(#+)/, fragment, fn _, capture ->
23+
adjusted_level = String.length(capture) + level_difference
24+
String.duplicate("#", adjusted_level)
25+
end)
26+
else
27+
fragment
28+
end
29+
end
30+
31+
def join_with_horizontal_rule(list) do
32+
Enum.map_join(list, "\n\n---\n\n", fn lines ->
33+
lines
34+
|> String.replace_leading("\r\n", "")
35+
|> String.replace_leading("\n", "")
36+
|> String.replace_trailing("\r\n", "")
37+
|> String.replace_trailing("\n", "")
38+
end) <> "\n"
39+
end
40+
end

0 commit comments

Comments
 (0)