Skip to content

Commit

Permalink
Fixes for help in OTP 27 and for go to definition (#306)
Browse files Browse the repository at this point in the history
* Help docs OTP 27 fixes

* Do not search for definition in _build if found elsewhere
  • Loading branch information
wojteksurowka authored Jun 16, 2024
1 parent 23ca59e commit 8003b21
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 37 deletions.
52 changes: 24 additions & 28 deletions apps/erlangbridge/src/gen_lsp_help_server.erl
Original file line number Diff line number Diff line change
Expand Up @@ -102,32 +102,28 @@ render_function([], _D) ->
% maps at (line:52, column:59), put cursor on iterator_order/0
["function_documentation_missing"];
render_function(FDocs, Docs) ->
Grouping =
lists:foldl(
fun({_Group,_Anno,_Sig,_Doc,#{ equiv := Group }} = Func,Acc) ->
Members = maps:get(Group, Acc, []),
Acc#{ Group => [Func|Members] };
({Group, _Anno, _Sig, _Doc, _Meta} = Func, Acc) ->
Members = maps:get(Group, Acc, []),
Acc#{ Group => [Func|Members] }
end, #{}, lists:sort(FDocs)),
lists:map(
fun({{_,F,A} = Group,Members}) ->
Signatures = lists:flatmap(fun render_signature/1,lists:reverse(Members)),
case lists:search(fun({_,_,_,Doc,_}) ->
Doc =/= #{}
end, Members) of
{value, {_,_,_,Doc,_Meta}} ->
render_headers_and_docs(Signatures, get_local_doc({F,A},Doc));
false ->
case lists:keyfind(Group, 1, Docs) of
false ->
render_headers_and_docs(Signatures, get_local_doc({F,A},none));
{_,_,_,Doc,_} ->
render_headers_and_docs(Signatures, get_local_doc({F,A},Doc))
end
end
end, maps:to_list(Grouping)).
Grouping = lists:foldl(fun
({_Group,_Anno,_Sig,_Doc,#{ equiv := Group = {_,_,_}}} = Func,Acc) ->
Members = maps:get(Group, Acc, []),
Acc#{ Group => [Func|Members] };
({Group, _Anno, _Sig, _Doc, _Meta} = Func, Acc) ->
Members = maps:get(Group, Acc, []),
Acc#{ Group => [Func|Members] }
end, #{}, lists:sort(FDocs)),
lists:map(fun ({{_,F,A} = Group, Members}) ->
Signatures = lists:flatmap(fun render_signature/1,lists:reverse(Members)),
case lists:search(fun({_,_,_,Doc,_}) -> Doc =/= #{} end, Members) of
{value, {_,_,_,Doc,_Meta}} ->
render_headers_and_docs(Signatures, get_local_doc({F,A},Doc));
false ->
case lists:keyfind(Group, 1, Docs) of
false ->
render_headers_and_docs(Signatures, get_local_doc({F,A},none));
{_,_,_,Doc,_} ->
render_headers_and_docs(Signatures, get_local_doc({F,A},Doc))
end
end
end, maps:to_list(Grouping)).

render_signature({{_Type,_F,_A},_Anno,_Sigs,_Docs,#{ signature := Specs } = Meta}) ->
lists:flatmap(
Expand Down Expand Up @@ -273,10 +269,10 @@ get_local_doc({F,A}, Docs) ->
get_local_doc(unicode:characters_to_binary(io_lib:format("~tp/~p",[F,A])), Docs);
get_local_doc(_Missing, #{ <<"en">> := Docs }) ->
%% English if it exists
shell_docs:normalize(Docs);
Docs;
get_local_doc(_Missing, ModuleDoc) when map_size(ModuleDoc) > 0 ->
%% Otherwise take first alternative found
shell_docs:normalize(maps:get(hd(maps:keys(ModuleDoc)), ModuleDoc));
maps:get(hd(maps:keys(ModuleDoc)), ModuleDoc);
get_local_doc(Missing, hidden) ->
[{p,[],[<<"The documentation for ">>,Missing,
<<" is hidden. This probably means that it is internal "
Expand Down
23 changes: 15 additions & 8 deletions apps/erlangbridge/src/lsp_navigation.erl
Original file line number Diff line number Diff line change
Expand Up @@ -621,36 +621,43 @@ variablelc_to_clauselc(VarLC2ClauseLC, Line, Column) ->
-> [lsp_location()]
when Type :: macro | record | field.
find_definitions(Type, Name, File) ->
find_definitions_in_files(Type, Name, [File], #{}).
case find_definitions_in_files(Type, Name, [File], #{}, false) of
[] -> find_definitions_in_files(Type, Name, [File], #{}, true);
Found -> Found
end.

-spec find_definitions_in_files(Type, Name, FilesToVisit, VisitedFiles)
-spec find_definitions_in_files(Type, Name, FilesToVisit, VisitedFiles, IncludeBuild)
-> [lsp_location()]
when Type :: macro | record | field,
Name :: atom(),
FilesToVisit :: [file:filename()],
VisitedFiles :: #{file:filename() => 1}.
find_definitions_in_files(_Type, _Name, [], _VisitedFiles) ->
VisitedFiles :: #{file:filename() => 1},
IncludeBuild :: boolean.
find_definitions_in_files(_Type, _Name, [], _VisitedFiles, _IncludeBuild) ->
[];
find_definitions_in_files(Type, Name, [File | Files], VisitedFiles) ->
find_definitions_in_files(Type, Name, [File | Files], VisitedFiles, IncludeBuild) ->
Forms = gen_lsp_doc_server:get_dodged_syntax_tree(File),
case find_definition_in_file(Type, Name, File, Forms) of
undefined ->
%% Go deeper (check included files on the next level)
IncludedRelFiles = lists:reverse(find_included_files(Forms, [])),
IncludeDirs = lsp_parse:get_include_path(File),
IncludeDirs = case IncludeBuild of
true -> lsp_parse:get_include_path(File);
false -> lsp_parse:get_include_path_no_build(File)
end,
PossibleIncludeFiles = [filename:join(Dir, IncludedRelFile)
|| IncludedRelFile <- IncludedRelFiles,
Dir <- IncludeDirs] ++ Files,
IncludeFilesToVisit = [IncFile
|| IncFile <- PossibleIncludeFiles,
not maps:is_key(IncFile, VisitedFiles)],
find_definitions_in_files(Type, Name, IncludeFilesToVisit,
VisitedFiles#{File => 1});
VisitedFiles#{File => 1}, IncludeBuild);
Result ->
%% Don't go deeper (ignore included files on the next level) but
%% go sideway (check e.g. build target dependent alternative files)
[Result | find_definitions_in_files(Type, Name, Files,
VisitedFiles#{File => 1})]
VisitedFiles#{File => 1}, IncludeBuild)]
end.

%% @doc Find macro, record or record field definition in a dodged AST
Expand Down
18 changes: 17 additions & 1 deletion apps/erlangbridge/src/lsp_parse.erl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
-module(lsp_parse).
-export([parse_source_file/2, parse_config_file/2, get_include_path/1, scan_source_file/2]).
-export([parse_source_file/2, parse_config_file/2, get_include_path/1, get_include_path_no_build/1, scan_source_file/2]).

%% @doc
%% @param File is a reference to the real file (file opened by editor)
Expand Down Expand Up @@ -69,6 +69,22 @@ get_standard_include_paths() ->
filename:join([RootDir, "_build", "default", "plugins"])
].

get_include_path_no_build(File) ->
RootDir = gen_lsp_config_server:root(),
StandardIncludePathsNoBuild =
[
filename:join([RootDir, "apps"]),
filename:join([RootDir, "lib"])
],
Candidates = get_file_include_paths(File) ++
get_settings_include_paths() ++
get_include_paths_from_rebar_config(File) ++
StandardIncludePathsNoBuild,
Paths = lists:filter(fun filelib:is_dir/1, Candidates),
% activate it only for debugging, on big projects it can generate a lot of logs
%gen_lsp_server:lsp_log("get_include_path: ~p", [Paths]),
Paths.

get_settings_include_paths() ->
SettingPaths = gen_lsp_config_server:includePaths(),
RootDir = gen_lsp_config_server:root(),
Expand Down

0 comments on commit 8003b21

Please sign in to comment.