Skip to content

Commit

Permalink
refactoring (#303)
Browse files Browse the repository at this point in the history
* Fix crash : when hover on maps::iterator_order/1

* add is_path_exclude unit test

* add exclude filter for technical traces in config,
  • Loading branch information
pgourlain authored Jun 9, 2024
1 parent 096d1c9 commit 23ca59e
Show file tree
Hide file tree
Showing 8 changed files with 142 additions and 18 deletions.
21 changes: 19 additions & 2 deletions apps/erlangbridge/src/gen_lsp_config_server.erl
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@
-export([standard_modules/0, bifs/0]).
-export([update_config/2, root/0, tmpdir/0, codeLensEnabled/0, includePaths/0, linting/0,
verbose/0, autosave/0, proxy/0, search_files_exclude/0, search_exclude/0,
formatting_line_length/0, inlayHintsEnabled/0]).
formatting_line_length/0, inlayHintsEnabled/0, verbose_is_include/1]).

-include("lsp_log.hrl").
-define(SERVER, ?MODULE).

-record(state, {config, standard_modules, bifs}).
Expand All @@ -23,7 +24,19 @@ bifs() ->
gen_server:call(?SERVER, {bifs}).

update_config(Key, Value) ->
gen_server:call(?SERVER, {update_config, Key, Value}).
Res = gen_server:call(?SERVER, {update_config, Key, Value}),
compute_erlang_section(Key),
Res.

compute_erlang_section(Key) ->
if
Key =:= erlang ->
Excludes = get_config_entry(erlang, verboseExcludeFilter, ""),
Splitted = lists:map(fun(X) -> {lsp_utils:to_binary(X), false} end, lists:flatmap( fun(X) -> string:split(X, ",") end, string:split(Excludes, ";"))),
gen_server:call(?SERVER, {update_config, erlang_computed, #{ verboseExcludeFilter => maps:from_list(Splitted)}});
true -> ok
end.


get_config() ->
gen_server:call(?SERVER, get_config).
Expand All @@ -50,6 +63,10 @@ linting() ->
verbose() ->
get_config_entry(erlang, verbose, false).

verbose_is_include(Method) ->
M = get_config_entry(erlang_computed, verboseExcludeFilter, #{}),
lsp_utils:try_get(Method, M, true).

autosave() ->
get_config_entry(computed, autosave, true).

Expand Down
4 changes: 3 additions & 1 deletion apps/erlangbridge/src/gen_lsp_help_server.erl
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,9 @@ eep48_render_fun_doc(_Module, _Function, FnDoc, Docs) ->
list_to_binary(lists:flatten(render_function(FnDoc, Docs))).

render_function([], _D) ->
{error, function_missing};
%{error, function_missing};
% maps at (line:52, column:59), put cursor on iterator_order/0
["function_documentation_missing"];
render_function(FDocs, Docs) ->
Grouping =
lists:foldl(
Expand Down
18 changes: 13 additions & 5 deletions apps/erlangbridge/src/gen_lsp_server.erl
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,10 @@ handle_info(_Data, State) ->
lsp_log(Msg, Args) ->
gen_lsp_config_server:verbose() andalso error_logger:info_msg(Msg, Args).

lsp_log(Method, Msg, Args) ->
% Method can be excluded from verbose logging by adding it to verboseExcludeFilter in the config
gen_lsp_config_server:verbose() andalso gen_lsp_config_server:verbose_is_include(Method) andalso error_logger:info_msg(Msg, Args).

remove_text_for_logging(#{params := #{contentChanges := ChangesList} = Params} = Input) ->
Input#{params := Params#{contentChanges := lists:map(fun
(#{text := <<Text/binary>>} = Change) when byte_size(Text) > 20 ->
Expand All @@ -102,7 +106,7 @@ remove_text_for_logging(Input) ->
Input.

do_contents(Socket, #{method := Method} = Input) ->
lsp_log("LSP received ~p", [remove_text_for_logging(Input)]),
lsp_log(Method, "LSP received ~p", [remove_text_for_logging(Input)]),
case call_handler(Socket, Method, maps:get(params, Input, undefined)) of
{ok, Result} ->
send_response_with_id(Socket, Input, #{result => Result});
Expand Down Expand Up @@ -142,20 +146,24 @@ handler_name(<<"$/", Name/binary>>) ->
handler_name(Name) ->
list_to_atom(binary_to_list(binary:replace(Name, <<"/">>, <<"_">>))).

send_response_with_id(Socket, Input, Response) ->
send_response_with_id(Socket, #{method := Method} = Input, Response) ->
case maps:get(id, Input, undefined) of
undefined ->
ok;
Id ->
send_to_client(Socket, Response#{id => Id})
send_to_client(Socket, Method, Response#{id => Id})
end.

send_to_client(Socket, Body) ->
lsp_log("LSP sends ~p", [Body]),
send_to_client(Socket, Method, Body) ->
lsp_log(Method, "LSP sends ~p", [Body]),
{ok, Json} = vscode_jsone:encode(Body),
Header = iolist_to_binary(io_lib:fwrite("Content-Length: ~p", [byte_size(Json)])),
gen_tcp:send(Socket, <<Header/binary, "\r\n\r\n", Json/binary>>).

send_to_client(Socket, Body) ->
send_to_client(Socket, <<"unknown">>, Body).


handle_tcp_data(Socket, Contents, State) ->
StateWithContents = State#state{contents = <<(State#state.contents)/binary, Contents/binary>>},
StateWithLength = case StateWithContents#state.content_length of
Expand Down
13 changes: 13 additions & 0 deletions apps/erlangbridge/src/lsp_utils.erl
Original file line number Diff line number Diff line change
Expand Up @@ -17,31 +17,42 @@
index_of/2,
try_get/3]).

-export_type([lsp_position/0, lsp_range/0]).


-type lsp_position() :: #{ line => pos_integer(), character => pos_integer()}.
-type lsp_range() :: #{ 'start' => lsp_position(), 'end' => lsp_position()}.

-spec try_get(Key :: term(), Map :: map(), Default :: term()) -> term().
try_get(Key, Map, Default) ->
case maps:find(Key, Map) of
{ok, Value} -> Value;
_ -> Default
end.

-spec client_range(Line :: pos_integer(), StartChar :: pos_integer(), EndChar :: pos_integer()) -> lsp_range().
client_range(Line, StartChar, EndChar) ->
#{
<<"start">> => #{line => Line - 1, character => StartChar - 1},
<<"end">> => #{line => Line - 1, character => EndChar - 1}
}.


-spec client_range(Line :: pos_integer(), StartChar :: pos_integer(), LineEnd :: pos_integer(), EndChar :: pos_integer()) -> lsp_range().
client_range(Line, StartChar, LineEnd, EndChar) ->
#{
<<"start">> => #{line => Line - 1, character => StartChar - 1},
<<"end">> => #{line => LineEnd - 1, character => EndChar - 1}
}.

-spec client_position({Line :: pos_integer(), Column :: pos_integer()}) -> lsp_position().
client_position({Line, Column}) ->
#{
line => Line-1,
character => Column-1
}.

-spec file_uri_to_file(Uri :: binary()) -> binary().
file_uri_to_file(Uri) ->
NewUri = re:replace(case Uri of
<<"file:///", Drive, "%3A", Rest/binary>> -> <<Drive, ":", Rest/binary>>;
Expand All @@ -51,6 +62,7 @@ file_uri_to_file(Uri) ->
end, <<"\\\\">>, <<"/">>, [global, {return, list}]),
lists:flatten(string_replace(NewUri, "%20", " ")).

-spec file_uri_to_vscode_uri(Uri :: binary()) -> binary().
file_uri_to_vscode_uri(Uri) ->
UriWithOutSpace = lists:flatten(string_replace(to_string(Uri), " ", "%20")),
EncodeUri = if
Expand All @@ -62,6 +74,7 @@ file_uri_to_vscode_uri(Uri) ->
_ -> EncodeUri
end.

-spec file_to_file_uri(File :: binary()) -> binary().
file_to_file_uri(<<"//", BinFile/binary>>) ->
<<"file://", BinFile/binary>>;
file_to_file_uri("//" ++ File) ->
Expand Down
11 changes: 1 addition & 10 deletions apps/erlangbridge/test/lsp_navigation_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,7 @@

-compile([export_all, nowarn_export_all]).

-define(logMsg(S),
begin
ct:log(default, 50, "~w:~p", [self(), S], [])
end).

-define(writeConsole(Fmt, Args),
error_logger:info_msg(Msg, Args)).

-define(writeConsole(S),
error_logger:info_msg("~p\n", [S])).
-include("./testlog.hrl").

% Specify a list of all unit test functions
all() -> [testnavigation, test_macros].
Expand Down
78 changes: 78 additions & 0 deletions apps/erlangbridge/test/lsp_utils_SUITE.erl
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
-module(lsp_utils_SUITE).

-include_lib("common_test/include/ct.hrl").

-include_lib("eunit/include/eunit.hrl").

-compile([export_all, nowarn_export_all]).

-include("./testlog.hrl").

% Specify a list of all unit test functions
all() -> [do_is_path_excluded].

% required, but can just return Config. this is a suite level setup function.
init_per_suite(Config) ->
%tprof:start(#{type => call_memory}),
%tprof:enable_trace(all), tprof:set_pattern('_', '_' , '_'),
% do custom per suite setup here
StartResult = application:start(vscode_lsp, permanent),
?assertEqual(ok, StartResult),
% to intercept traces, set to true
ErlangSection = #{verbose => false},
gen_lsp_config_server:update_config(
erlang,
ErlangSection
),
Config.

% required, but can just return Config. this is a suite level tear down function.
end_per_suite(Config) ->
% do custom per suite cleanup here
application:stop(vscode_lsp),
%tprof:disable_trace(all), Sample = tprof:collect(),
%Inspected = tprof:inspect(Sample, process, measurement), Shell = maps:get(self(), Inspected),
%tprof:format(Shell),
Config.

otp_files() ->
% files list extracted from otp/erts/test/erlc_SUITE_data/src/
% returned by file:list_dir(...)
[
"otp/erts/test/erlc_SUITE_data/src/f_include_1.erl",
"otp/erts/test/erlc_SUITE_data/src/erl_test_bad.erl",
"otp/erts/test/erlc_SUITE_data/src/start_bad.script",
"otp/erts/test/erlc_SUITE_data/src/yecc_test_bad.yrl",
"otp/erts/test/erlc_SUITE_data/src/start_ok.script",
"otp/erts/test/erlc_SUITE_data/src/macro_enabled.hrl",
"otp/erts/test/erlc_SUITE_data/src/GOOD-MIB.mib",
[11,116,112,47,101,114,116,115,47,
116,101,115,116,47,101,114,108,99,95,83,85,73,84,69,95,100,
97,116,97,47,115,114,99,47,128512,47,101,114,108,95,116,101,
115,116,95,117,110,105,99,111,100,101,46,101,114,108], % unicode directory
"otp/erts/test/erlc_SUITE_data/src/CVS/older.erl",
"otp/erts/test/erlc_SUITE_data/src/older.beam"
].

otp_files_withresult() ->
% ensure that File converted to unicode:characters_to_binary before calling is_path_excludedand it works as expected
{
lists:zipwith(fun(X, Y) -> {unicode:characters_to_binary(X),Y} end, otp_files(), [false,false,false,false,false,false,false,false,true,false]),
exclude_map()
}.

exclude_map() ->
% #{'**/.git' => true,'**/.svn' => true,'**/.hg' => true,
% '**/CVS' => true,'**/.DS_Store' => true,
% '**/Thumbs.db' => true}.
#{ ".*/CVS(/.*)?$" => true }.

check_path_excluded({FilesAndResult, Map}) ->
lists:foreach(fun ({F, ExpectedResult}) ->
R = lsp_utils:is_path_excluded(F, Map),
?assertEqual(ExpectedResult, R)
end, FilesAndResult).

do_is_path_excluded(_Config) ->
check_path_excluded(otp_files_withresult()),
ok.
10 changes: 10 additions & 0 deletions apps/erlangbridge/test/testlog.hrl
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
-define(logMsg(S),
begin
ct:log(default, 50, "~w:~p", [self(), S], [])
end).

-define(writeConsole(Fmt, Args),
error_logger:info_msg(Msg, Args)).

-define(writeConsole(S),
error_logger:info_msg("~p\n", [S])).
5 changes: 5 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,11 @@
"description": "Enable/disable technical traces for use in the extension development.",
"default": false
},
"erlang.verboseExcludeFilter": {
"type": "string",
"default": "textDocument/inlayHints,textDocument/hover",
"description": "List of excluded methods (i.e: textDocument/hover,textDocument/inlayHints, ...) from technical traces in the extension development."
},
"erlang.debuggerRunMode": {
"type": "string",
"default": "external",
Expand Down

0 comments on commit 23ca59e

Please sign in to comment.