///|
pub(all) enum ConflictKind {
DuplicateAssignment
RedundantAssignment
OverlappingSections
ConflictingSections
} derive(Debug, Eq)
///|
pub(all) struct ConfigConflict {
kind : ConflictKind
key : String
first_pattern : String
second_pattern : String
first_value : String
second_value : String
witness_path : String?
first_line : Int
second_line : Int
message : String
} derive(Debug, Eq)
///|
fn same_scope_conflicts(
section : Section,
conflicts : Array[ConfigConflict],
) -> Unit {
for index, property in section.properties {
for previous in 0.. Unit {
guard glob_overlap_witness(first.pattern, second.pattern) is Some(witness) else {
return
}
for left in first.properties {
for right in second.properties {
if left.key == right.key {
let same = lower_ascii(left.value) == lower_ascii(right.value)
conflicts.push({
kind: if same {
OverlappingSections
} else {
ConflictingSections
},
key: left.key,
first_pattern: first.pattern,
second_pattern: second.pattern,
first_value: left.value,
second_value: right.value,
witness_path: Some(witness),
first_line: left.source.line,
second_line: right.source.line,
message: if same {
"两个可能重叠的配置节设置了相同值,可考虑集中通用配置。"
} else {
"两个可能重叠的配置节设置了不同值;后出现的节会覆盖前一节。"
},
})
}
}
}
}
///|
/// Find duplicate assignments and concrete cross-section overlap witnesses.
/// Overlap analysis is deliberately conservative: it reports only when a
/// generated path matches both patterns and never claims patterns are disjoint.
pub fn analyze_conflicts(config : EditorConfig) -> Array[ConfigConflict] {
let conflicts : Array[ConfigConflict] = []
for section in config.sections {
same_scope_conflicts(section, conflicts)
}
for index, section in config.sections {
for previous in 0.. String {
let location = "第 " +
self.first_line.to_string() +
"、" +
self.second_line.to_string() +
" 行"
let witness = match self.witness_path {
Some(path) => ";示例路径:" + path
None => ""
}
location + ":属性 `" + self.key + "`," + self.message + witness
}
///|
pub fn conflict_count_by_kind(
conflicts : Array[ConfigConflict],
kind : ConflictKind,
) -> Int {
conflicts.fold(init=0, (count, conflict) => {
count + (if conflict.kind == kind { 1 } else { 0 })
})
}