From 472e53c35ac620ed6fbe324c209ff911eb316c48 Mon Sep 17 00:00:00 2001 From: Alan Zimmerman Date: Wed, 19 Feb 2020 09:10:40 +0000 Subject: [PATCH] [#440] global config Provide the ability to set config file location via the Initialize request. In javascript terms, this is expected to be erlang.config_path The value can be absolute or relative, and can include the name of the file to be loaded as well, otherwise is treated as a path. --- priv/rebar3_release/erlang_ls.config | 2 + src/els_config.erl | 13 +++- test/els_initialization_SUITE.erl | 103 +++++++++++++++++++++++++++ 3 files changed, 116 insertions(+), 2 deletions(-) create mode 100644 test/els_initialization_SUITE.erl diff --git a/priv/rebar3_release/erlang_ls.config b/priv/rebar3_release/erlang_ls.config index ae62fccee..934f3f12e 100644 --- a/priv/rebar3_release/erlang_ls.config +++ b/priv/rebar3_release/erlang_ls.config @@ -1,2 +1,4 @@ apps_dirs: - "apps/*" +macros: + - name: DEFINED_FOR_RELATIVE_TEST diff --git a/src/els_config.erl b/src/els_config.erl index b5b3da395..05fedeb87 100644 --- a/src/els_config.erl +++ b/src/els_config.erl @@ -149,8 +149,12 @@ handle_cast(_Msg, State) -> {noreply, State}. %%============================================================================== -spec config_paths(path(), map()) -> [path()]. -config_paths(RootPath, #{<<"erlang">> := #{<<"config_path">> := ConfigPath}}) -> - [filename:join([RootPath, ConfigPath]) | default_config_paths(RootPath)]; +config_paths( RootPath + , #{<<"erlang">> := #{<<"config_path">> := ConfigPath0}}) -> + ConfigPath = binary_to_list(ConfigPath0), + lists:append([ possible_config_paths(ConfigPath) + , possible_config_paths(filename:join([RootPath, ConfigPath])) + , default_config_paths(RootPath)]); config_paths(RootPath, _Config) -> default_config_paths(RootPath). @@ -161,6 +165,11 @@ default_config_paths(RootPath) -> , filename:join([GlobalConfigDir, ?DEFAULT_CONFIG_FILE]) ]. +%% @doc Bare `Path' as well as with default config file name suffix. +-spec possible_config_paths(path()) -> [path()]. +possible_config_paths(Path) -> + [ Path, filename:join([Path, ?DEFAULT_CONFIG_FILE]) ]. + -spec consult_config([path()]) -> map(). consult_config([]) -> #{}; consult_config([Path | Paths]) -> diff --git a/test/els_initialization_SUITE.erl b/test/els_initialization_SUITE.erl new file mode 100644 index 000000000..3be056ec4 --- /dev/null +++ b/test/els_initialization_SUITE.erl @@ -0,0 +1,103 @@ +-module(els_initialization_SUITE). + +-include("erlang_ls.hrl"). + +%% CT Callbacks +-export([ suite/0 + , init_per_suite/1 + , end_per_suite/1 + , init_per_testcase/2 + , end_per_testcase/2 + , groups/0 + , all/0 + ]). + +%% Test cases +-export([ initialize_default/1 + , initialize_custom_relative/1 + , initialize_custom_absolute/1 + ]). + +%%============================================================================== +%% Includes +%%============================================================================== +-include_lib("common_test/include/ct.hrl"). +-include_lib("stdlib/include/assert.hrl"). + +%%============================================================================== +%% Types +%%============================================================================== +-type config() :: [{atom(), any()}]. + +%%============================================================================== +%% CT Callbacks +%%============================================================================== +-spec suite() -> [tuple()]. +suite() -> + [{timetrap, {seconds, 30}}]. + +-spec all() -> [{group, stdio | tcp}]. +all() -> + [{group, tcp}, {group, stdio}]. + +-spec groups() -> [atom()]. +groups() -> + els_test_utils:groups(?MODULE). + +-spec init_per_suite(config()) -> config(). +init_per_suite(Config) -> + els_test_utils:init_per_suite(Config). + +-spec end_per_suite(config()) -> ok. +end_per_suite(Config) -> + els_test_utils:end_per_suite(Config). + +-spec init_per_testcase(atom(), config()) -> config(). +init_per_testcase(_TestCase, Config) -> + Transport = els_test_utils:get_group(Config), + Started = els_test_utils:start(Transport), + + [{started, Started} | Config]. + +-spec end_per_testcase(atom(), config()) -> ok. +end_per_testcase(TestCase, Config) -> + els_test_utils:end_per_testcase(TestCase, Config). + +%%============================================================================== +%% Testcases +%%============================================================================== + +-spec initialize_default(config()) -> ok. +initialize_default(Config) -> + RootUri = ?config(root_uri, Config), + els_client:initialize(RootUri, []), + Result = els_config:get(macros), + Expected = [#{"name" => "DEFINED_WITHOUT_VALUE"}, + #{"name" => "DEFINED_WITH_VALUE","value" => 1}], + ?assertEqual(Expected, Result), + ok. + +-spec initialize_custom_relative(config()) -> ok. +initialize_custom_relative(Config) -> + RootUri = ?config(root_uri, Config), + ConfigPath = <<"../rebar3_release/erlang_ls.config">>, + InitOpts = #{ <<"erlang">> + => #{ <<"config_path">> => ConfigPath }}, + els_client:initialize(RootUri, InitOpts), + Result = els_config:get(macros), + Expected = [#{"name" => "DEFINED_FOR_RELATIVE_TEST"}], + ?assertEqual(Expected, Result), + ok. + +-spec initialize_custom_absolute(config()) -> ok. +initialize_custom_absolute(Config) -> + RootUri = ?config(root_uri, Config), + ConfigPath = filename:join( els_uri:path(RootUri) + , "../rebar3_release/erlang_ls.config"), + InitOpts = #{ <<"erlang">> + => #{ <<"config_path">> => ConfigPath }}, + els_client:initialize(RootUri, InitOpts), + Result = els_config:get(macros), + Expected = [#{"name" => "DEFINED_FOR_RELATIVE_TEST"}], + ?assertEqual(Expected, Result), + ok.