///|
fn find_property_index(
properties : Array[ResolvedProperty],
key : String,
) -> Int? {
for index, property in properties {
if property.key == key {
return Some(index)
}
}
None
}
///|
fn append_step(
existing : ResolvedProperty,
step : PropertyStep,
replacement : Property,
) -> ResolvedProperty {
let history = existing.history.copy()
history.push(step)
{
key: replacement.key,
value: replacement.value,
source: replacement.source,
pattern: step.pattern,
config_path: step.config_path,
history,
}
}
///|
fn apply_property(
properties : Array[ResolvedProperty],
property : Property,
config_path : String,
pattern : String,
) -> Unit {
let normalized_value = lower_ascii(property.value)
let step : PropertyStep = {
key: property.key,
value: property.value,
config_path,
pattern,
line: property.source.line,
action: if normalized_value == "unset" {
"unset"
} else {
"set"
},
}
match find_property_index(properties, property.key) {
Some(index) =>
if normalized_value == "unset" {
ignore(properties.remove(index))
} else {
properties[index] = append_step(properties[index], step, property)
}
None =>
if normalized_value != "unset" {
properties.push({
key: property.key,
value: property.value,
source: property.source,
pattern,
config_path,
history: [step],
})
}
}
}
///|
fn apply_derived_properties(properties : Array[ResolvedProperty]) -> Unit {
let indent_index = find_property_index(properties, "indent_size")
let tab_index = find_property_index(properties, "tab_width")
match (indent_index, tab_index) {
(Some(indent), None) if lower_ascii(properties[indent].value) != "tab" => {
let source = properties[indent]
properties.push({
key: "tab_width",
value: source.value,
source: source.source,
pattern: source.pattern,
config_path: source.config_path,
history: [
{
key: "tab_width",
value: source.value,
config_path: source.config_path,
pattern: source.pattern,
line: source.source.line,
action: "derived from indent_size",
},
],
})
}
(Some(indent), Some(tab)) if lower_ascii(properties[indent].value) == "tab" => {
let source = properties[tab]
properties[indent] = {
key: "indent_size",
value: source.value,
source: source.source,
pattern: source.pattern,
config_path: source.config_path,
history: properties[indent].history,
}
}
_ => ()
}
}
///|
fn sorted_layers(layers : Array[ConfigLayer]) -> Array[ConfigLayer] {
let result = layers.copy()
result.sort_by((left, right) => {
path_depth(left.directory) - path_depth(right.directory)
})
let mut last_root = -1
for index, layer in result {
if layer.config.root {
last_root = index
}
}
if last_root > 0 {
let scoped : Array[ConfigLayer] = []
for index in last_root.. Resolution {
let properties : Array[ResolvedProperty] = []
let traces : Array[SectionTrace] = []
let diagnostics : Array[Diagnostic] = []
for layer in sorted_layers(layers) {
for diagnostic in validate(layer.config) {
diagnostics.push(diagnostic)
}
match relative_path(layer.directory, target) {
None =>
diagnostics.push(
make_diagnostic(
layer.path,
1,
1,
1,
0,
Warning,
"EC3001",
"目标文件不在配置目录内",
"检查配置层的 directory 字段。",
),
)
Some(relative) =>
for section in layer.config.sections {
let matched = glob_matches(section.pattern, relative)
traces.push({
config_path: layer.path,
pattern: section.pattern,
matched,
relative_path: relative,
line: section.source.line,
reason: explain_glob(section.pattern, relative),
})
if matched {
for property in section.properties {
apply_property(properties, property, layer.path, section.pattern)
}
}
}
}
}
apply_derived_properties(properties)
{ target: normalize_path(target), properties, sections: traces, diagnostics }
}
///|
/// Compatibility helper for resolving one already parsed document.
pub fn resolve(config : EditorConfig, path : String) -> Array[ResolvedProperty] {
let properties : Array[ResolvedProperty] = []
for section in config.sections {
if glob_matches(section.pattern, path) {
for property in section.properties {
apply_property(properties, property, config.path, section.pattern)
}
}
}
properties
}
///|
pub fn Resolution::get(self : Resolution, key : String) -> ResolvedProperty? {
let normalized = lower_ascii(key)
for property in self.properties {
if property.key == normalized {
return Some(property)
}
}
None
}