Skip to content

Commit fe841ed

Browse files
committed
config: some implementation refactoring
1 parent b2925cc commit fe841ed

File tree

6 files changed

+84
-77
lines changed

6 files changed

+84
-77
lines changed

src/config.jl

Lines changed: 51 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,42 @@ end
5858
on_difference(callback, old_val, new_val, path::Tuple{Vararg{Symbol}}) =
5959
old_val !== new_val ? callback(old_val, new_val, path) : old_val
6060

61+
function parse_config_dict(config_dict::AbstractDict{String}, filepath::Union{Nothing,AbstractString} = nothing)
62+
try
63+
return Configurations.from_dict(JETLSConfig, config_dict)
64+
catch e
65+
# TODO: remove this when Configurations.jl support to report
66+
# full path of unknown key.
67+
if e isa Configurations.InvalidKeyError
68+
unknown_keys = collect_unmatched_keys(to_untyped_config_dict(config_dict))
69+
if !isempty(unknown_keys)
70+
if isnothing(filepath)
71+
return unmatched_keys_in_config_file_msg(unknown_keys)
72+
else
73+
return unmatched_keys_in_config_file_msg(filepath, unknown_keys)
74+
end
75+
end
76+
elseif e isa DiagnosticConfigError
77+
if isnothing(filepath)
78+
return "Invalid diagnostic configuration: $(e.msg)"
79+
else
80+
return """
81+
Invalid diagnostic configuration in $filepath:
82+
$(e.msg)
83+
"""
84+
end
85+
end
86+
if isnothing(filepath)
87+
return "Failed to parse LSP configuration: $(e)"
88+
else
89+
return """
90+
Failed to load configuration file at $filepath:
91+
$(e)
92+
"""
93+
end
94+
end
95+
end
96+
6197
"""
6298
merge_setting(base::T, overlay::T) where {T<:ConfigSection} -> T
6399
@@ -69,36 +105,37 @@ merge_setting(base::T, overlay::T) where {T<:ConfigSection} =
69105

70106
# TODO: remove this.
71107
# (now this is used for `collect_unmatched_keys` only. see that's comment)
72-
const ConfigDict = Base.PersistentDict{String, Any}
73-
to_config_dict(dict::AbstractDict) = ConfigDict((k => (v isa AbstractDict ? to_config_dict(v) : v) for (k, v) in dict)...)
108+
const UntypedConfigDict = Base.PersistentDict{String, Any}
109+
to_untyped_config_dict(dict::AbstractDict) =
110+
UntypedConfigDict((k => (v isa AbstractDict ? to_untyped_config_dict(v) : v) for (k, v) in dict)...)
74111

75-
const DEFAULT_CONFIG_DICT = to_config_dict(Configurations.to_dict(DEFAULT_CONFIG))
112+
const DEFAULT_UNTYPED_CONFIG_DICT = to_untyped_config_dict(Configurations.to_dict(DEFAULT_CONFIG))
76113

77114
"""
78-
collect_unmatched_keys(this::ConfigDict, ref::ConfigDict) -> Vector{Vector{String}}
115+
collect_unmatched_keys(this::UntypedConfigDict, ref::UntypedConfigDict) -> Vector{Vector{String}}
79116
80117
Traverses the keys of `this` and returns a list of key paths that are not present in `ref`.
81118
Note that this function does *not* perform deep structural comparison for keys whose values are dictionaries.
82119
83120
# Examples
84121
```julia-repl
85122
julia> collect_unmatched_keys(
86-
ConfigDict("key1" => ConfigDict("key2" => 0, "key3" => 0, "key4" => 0)),
87-
ConfigDict("key1" => ConfigDict("key2" => 0, "diff1" => 0, "diff2" => 0))
123+
UntypedConfigDict("key1" => UntypedConfigDict("key2" => 0, "key3" => 0, "key4" => 0)),
124+
UntypedConfigDict("key1" => UntypedConfigDict("key2" => 0, "diff1" => 0, "diff2" => 0))
88125
)
89126
2-element Vector{Vector{String}}:
90127
["key1", "key3"]
91128
["key1", "key4"]
92129
93130
julia> collect_unmatched_keys(
94-
ConfigDict("key1" => 0, "key2" => 0),
95-
ConfigDict("key1" => 1, "key2" => 1)
131+
UntypedConfigDict("key1" => 0, "key2" => 0),
132+
UntypedConfigDict("key1" => 1, "key2" => 1)
96133
)
97134
Vector{String}[]
98135
99136
julia> collect_unmatched_keys(
100-
ConfigDict("key1" => ConfigDict("key2" => 0, "key3" => 0)),
101-
ConfigDict("diff" => ConfigDict("diff" => 0, "key3" => 0))
137+
UntypedConfigDict("key1" => UntypedConfigDict("key2" => 0, "key3" => 0)),
138+
UntypedConfigDict("diff" => UntypedConfigDict("diff" => 0, "key3" => 0))
102139
)
103140
1-element Vector{Vector{String}}:
104141
["key1"]
@@ -107,15 +144,15 @@ julia> collect_unmatched_keys(
107144
TODO: remove this. This is a temporary workaround to report unknown keys in the config file
108145
until Configurations.jl supports reporting full path of unknown keys.
109146
"""
110-
function collect_unmatched_keys(this::ConfigDict, ref::ConfigDict=DEFAULT_CONFIG_DICT)
147+
function collect_unmatched_keys(this::UntypedConfigDict, ref::UntypedConfigDict=DEFAULT_UNTYPED_CONFIG_DICT)
111148
unknown_keys = Vector{String}[]
112149
collect_unmatched_keys!(unknown_keys, this, ref, String[])
113150
return unknown_keys
114151
end
115152

116153
function collect_unmatched_keys!(
117154
unknown_keys::Vector{Vector{String}},
118-
this::ConfigDict, ref::ConfigDict, key_path::Vector{String}
155+
this::UntypedConfigDict, ref::UntypedConfigDict, key_path::Vector{String}
119156
)
120157
for (k, v) in this
121158
current_path = [key_path; k]
@@ -144,9 +181,9 @@ so `config` is guaranteed to not be `nothing`.
144181
Base.@constprop :aggressive function get_config(manager::ConfigManager, key_path::Symbol...)
145182
data = load(manager)
146183
config = if is_static_setting(key_path...)
147-
getobjpath(merge_setting(DEFAULT_CONFIG, data.static_settings), key_path...)
184+
getobjpath(data.__filled_static_settings__, key_path...)
148185
else
149-
getobjpath(merge_setting(DEFAULT_CONFIG, get_settings(data)), key_path...)
186+
getobjpath(data.__filled_settings__, key_path...)
150187
end
151188
@assert !isnothing(config) "Invalid default configuration values"
152189
return config

src/diagnostics.jl

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ function calculate_match_specificity(
153153
return specificity
154154
end
155155

156-
function _apply_diagnostic_config(diagnostic::Diagnostic, diagnostic_config::DiagnosticConfig)
156+
function _apply_diagnostic_config(diagnostic::Diagnostic, manager::ConfigManager)
157157
code = diagnostic.code
158158
if !(code isa String)
159159
if JETLS_DEV_MODE
@@ -171,7 +171,8 @@ function _apply_diagnostic_config(diagnostic::Diagnostic, diagnostic_config::Dia
171171
return diagnostic
172172
end
173173

174-
patterns = @something diagnostic_config.patterns return diagnostic
174+
patterns = get_config(manager, :diagnostic, :patterns)
175+
isempty(patterns) && return diagnostic
175176

176177
message = diagnostic.message
177178
severity = nothing
@@ -199,14 +200,10 @@ function _apply_diagnostic_config(diagnostic::Diagnostic, diagnostic_config::Dia
199200
end
200201

201202
function apply_diagnostic_config!(diagnostics::Vector{Diagnostic}, manager::ConfigManager)
202-
settings = get_settings(load(manager))
203-
diagnostic_config = @something settings.diagnostic default_config(DiagnosticConfig)
204-
if diagnostic_config.enabled === false
205-
return empty!(diagnostics)
206-
end
203+
get_config(manager, :diagnostic, :enabled) || return empty!(diagnostics)
207204
i = 1
208205
while i <= length(diagnostics)
209-
applied = _apply_diagnostic_config(diagnostics[i], diagnostic_config)
206+
applied = _apply_diagnostic_config(diagnostics[i], manager)
210207
if applied === missing
211208
deleteat!(diagnostics, i)
212209
continue

src/did-change-watched-files.jl

Lines changed: 3 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -65,32 +65,11 @@ function load_file_config!(callback, server::Server, filepath::AbstractString;
6565
parsed = TOML.tryparsefile(filepath)
6666
parsed isa TOML.ParserError && return old_data, nothing
6767

68-
new_file_config = try
69-
Configurations.from_dict(JETLSConfig, parsed)
70-
catch e
71-
# TODO: remove this when Configurations.jl support to report
72-
# full path of unknown key.
73-
if e isa Configurations.InvalidKeyError
74-
config_dict = to_config_dict(parsed)
75-
unknown_keys = collect_unmatched_keys(config_dict)
76-
if !isempty(unknown_keys)
77-
show_error_message(server, unmatched_keys_in_config_file_msg(filepath, unknown_keys))
78-
return old_data, nothing
79-
end
80-
elseif e isa DiagnosticConfigError
81-
show_error_message(server, """
82-
Invalid diagnostic configuration in $filepath:
83-
$(e.msg)
84-
""")
85-
return old_data, nothing
86-
end
87-
show_error_message(server, """
88-
Failed to load configuration file at $filepath:
89-
$(e)
90-
""")
68+
new_file_config = parse_config_dict(parsed, filepath)
69+
if new_file_config isa AbstractString
70+
show_error_message(server, new_file_config)
9171
return old_data, nothing
9272
end
93-
9473
new_data = ConfigManagerData(old_data;
9574
file_config=new_file_config,
9675
file_config_path=filepath

src/types.jl

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -359,13 +359,13 @@ end
359359

360360
const DIAGNOSTIC_SOURCE = "JETLS"
361361

362-
const VALID_DIAGNOSTIC_CATEGORIES = Set{String}([
362+
const VALID_DIAGNOSTIC_CATEGORIES = Set{String}((
363363
"syntax",
364364
"lowering",
365365
"toplevel",
366366
"inference",
367367
"testrunner",
368-
])
368+
))
369369

370370
const SYNTAX_DIAGNOSTIC_CODE = "syntax/parse-error"
371371
const LOWERING_UNUSED_ARGUMENT_CODE = "lowering/unused-argument"
@@ -409,7 +409,7 @@ Base.convert(::Type{DiagnosticPattern}, x::AbstractDict{String}) =
409409
end
410410

411411
is_static_setting(::Type{DiagnosticConfig}, ::Symbol) = false
412-
default_config(::Type{DiagnosticConfig}) = DiagnosticConfig(true, nothing)
412+
default_config(::Type{DiagnosticConfig}) = DiagnosticConfig(true, DiagnosticPattern[])
413413

414414
# configuration item for test purpose
415415
@option struct InternalConfig <: ConfigSection
@@ -456,6 +456,8 @@ struct ConfigManagerData
456456
lsp_config::JETLSConfig
457457
file_config_path::Union{Nothing,String}
458458
__settings__::JETLSConfig
459+
__filled_static_settings__::JETLSConfig
460+
__filled_settings__::JETLSConfig
459461
function ConfigManagerData(
460462
static_settings::JETLSConfig,
461463
file_config::JETLSConfig,
@@ -470,10 +472,14 @@ struct ConfigManagerData
470472
# - Limited to project root scope only
471473
# - Takes precedence since clients don't properly support
472474
# hierarchical configuration via scopeUri
473-
settings = DEFAULT_CONFIG
474-
settings = merge_setting(settings, lsp_config)
475-
settings = merge_setting(settings, file_config)
476-
return new(static_settings, file_config, lsp_config, file_config_path, settings)
475+
__settings__ = DEFAULT_CONFIG
476+
__settings__ = merge_setting(__settings__, lsp_config)
477+
__settings__ = merge_setting(__settings__, file_config)
478+
# Create setting structs without `nothing` values for use by `get_config`
479+
__filled_static_settings__ = merge_setting(DEFAULT_CONFIG, static_settings)
480+
__filled_settings__ = merge_setting(DEFAULT_CONFIG, __settings__)
481+
return new(static_settings, file_config, lsp_config, file_config_path,
482+
__settings__, __filled_static_settings__, __filled_settings__)
477483
end
478484
end
479485

src/workspace-configuration.jl

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -75,23 +75,11 @@ function store_lsp_config!(tracker::ConfigChangeTracker, server::Server, @nospec
7575
return delete_lsp_config!(tracker, server)
7676
end
7777
store!(server.state.config_manager) do old_data::ConfigManagerData
78-
new_lsp_config = try
79-
Configurations.from_dict(JETLSConfig, config_dict)
80-
catch e
81-
if e isa Configurations.InvalidKeyError
82-
unknown_keys = collect_unmatched_keys(to_config_dict(config_dict))
83-
if !isempty(unknown_keys)
84-
show_error_message(server, unmatched_keys_in_lsp_config_msg(unknown_keys))
85-
return old_data, nothing
86-
end
87-
elseif e isa DiagnosticConfigError
88-
show_error_message(server, "Invalid diagnostic configuration: $(e.msg)")
89-
return old_data, nothing
90-
end
91-
show_error_message(server, "Failed to parse LSP configuration: $(e)")
78+
new_lsp_config = parse_config_dict(config_dict)
79+
if new_lsp_config isa AbstractString
80+
show_error_message(server, new_lsp_config)
9281
return old_data, nothing
9382
end
94-
9583
new_data = ConfigManagerData(old_data; lsp_config=new_lsp_config)
9684
on_difference(tracker, get_settings(old_data), get_settings(new_data))
9785
return new_data, nothing

test/test_config.jl

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -69,23 +69,23 @@ using JETLS
6969
end
7070
end
7171

72-
@testset "ConfigDict utilities" begin
73-
TEST_DICT = JETLS.ConfigDict(
72+
@testset "UntypedConfigDict utilities" begin
73+
TEST_DICT = JETLS.UntypedConfigDict(
7474
"test_key1" => "test_value1",
75-
"test_key2" => JETLS.ConfigDict(
75+
"test_key2" => JETLS.UntypedConfigDict(
7676
"nested_key1" => "nested_value1",
77-
"nested_key2" => JETLS.ConfigDict(
77+
"nested_key2" => JETLS.UntypedConfigDict(
7878
"deep_nested_key1" => "deep_nested_value1",
7979
"deep_nested_key2" => "deep_nested_value2"
8080
)
8181
)
8282
)
8383

84-
TEST_DICT_DIFFERENT_KEY = JETLS.ConfigDict(
84+
TEST_DICT_DIFFERENT_KEY = JETLS.UntypedConfigDict(
8585
"diffname_1" => "test_value1",
86-
"test_key2" => JETLS.ConfigDict(
86+
"test_key2" => JETLS.UntypedConfigDict(
8787
"nested_key1" => "nested_value1",
88-
"diffname_2" => JETLS.ConfigDict(
88+
"diffname_2" => JETLS.UntypedConfigDict(
8989
"deep_nested_key1" => "deep_nested_value1",
9090
"diffname_3" => "deep_nested_value2"
9191
)
@@ -102,9 +102,9 @@ end
102102

103103
@test isempty(JETLS.collect_unmatched_keys(TEST_DICT, TEST_DICT))
104104

105-
# single-arg version should use DEFAULT_CONFIG_DICT
105+
# single-arg version should use DEFAULT_UNTYPED_CONFIG_DICT
106106
@test JETLS.collect_unmatched_keys(TEST_DICT_DIFFERENT_KEY) ==
107-
JETLS.collect_unmatched_keys(TEST_DICT_DIFFERENT_KEY, JETLS.DEFAULT_CONFIG_DICT)
107+
JETLS.collect_unmatched_keys(TEST_DICT_DIFFERENT_KEY, JETLS.DEFAULT_UNTYPED_CONFIG_DICT)
108108
end
109109
end
110110

0 commit comments

Comments
 (0)