use super::*;
use crate::anyhow_expr;
use crate::bail_expr;
use crate::bail_span;
use crate::err_expr;
pub(crate) fn filter_platform_specific_cfg(
top_levels: Vec<TopLevel>,
deflocalkeys_variant_to_apply: &str,
_lsp_hints: &mut lsp_hints::LspHints,
) -> Result<Vec<TopLevel>> {
let valid_platform_names = DEFLOCALKEYS_VARIANTS
.iter()
.map(|dfl| dfl.trim_start_matches("deflocalkeys-"))
.collect::<Vec<_>>();
let current_platform = deflocalkeys_variant_to_apply.trim_start_matches("deflocalkeys-");
top_levels
.into_iter()
.try_fold(vec![], |mut tles, tle| -> Result<Vec<TopLevel>> {
if !matches!(tle.t.first().and_then(|m| m.atom(None)), Some("platform")) {
tles.push(tle);
return Ok(tles);
}
if tle.t.len() != 3 {
bail_span!(
&tle,
"platform requires exactly two parameters:\n\
applicable-platforms, configuration-item"
);
}
let configuration = tle.t[2]
.span_list(None)
.ok_or_else(|| anyhow_expr!(&tle.t[2], "configuration-item must be a list"))?;
let applicable_platforms = tle.t[1]
.list(None)
.ok_or_else(|| anyhow_expr!(&tle.t[1], "applicable-platforms must be a list"))
.and_then(|pf_list| {
pf_list.iter().try_fold(vec![], |mut pfs, pf_expr| {
let good_pf = pf_expr
.atom(None)
.ok_or_else(|| anyhow_expr!(pf_expr, "platform must be a string"))
.and_then(|pf| {
if valid_platform_names.contains(&pf) {
Ok(pf)
} else {
err_expr!(
pf_expr,
"Unknown platform. Valid platforms:\n{}",
valid_platform_names.join(" ")
)
}
})?;
pfs.push(good_pf);
Ok(pfs)
})
})?;
if applicable_platforms.contains(¤t_platform) {
tles.push(configuration.clone());
} else {
#[cfg(feature = "lsp")]
_lsp_hints.inactive_code.push(lsp_hints::InactiveCode {
span: tle.span.clone(),
reason: format!(
"Current platform \"{current_platform}\" doesn't match any of: {}",
applicable_platforms.join(" ")
),
})
}
Ok(tles)
})
}
pub(crate) fn filter_env_specific_cfg(
top_levels: Vec<TopLevel>,
env: &EnvVars,
_lsp_hints: &mut lsp_hints::LspHints,
) -> Result<Vec<TopLevel>> {
top_levels
.into_iter()
.try_fold(vec![], |mut tles, tle| -> Result<Vec<TopLevel>> {
if !matches!(
tle.t.first().and_then(|m| m.atom(None)),
Some("environment")
) {
tles.push(tle);
return Ok(tles);
}
let env = match env.as_ref() {
Ok(v) => v,
Err(e) => Err(anyhow!("{e}"))?,
};
if tle.t.len() != 3 {
bail_span!(
&tle,
"environment requires exactly two parameters:\n\
varname-varvalue, configuration-item"
);
}
let configuration = tle.t[2]
.span_list(None)
.ok_or_else(|| anyhow_expr!(&tle.t[2], "configuration-item must be a list"))?;
let (env_var_name, env_var_val) = tle.t[1]
.list(None)
.ok_or_else(|| anyhow_expr!(&tle.t[1], "varname-varvalue must be a list"))
.and_then(|varnameval| {
if varnameval.len() != 2 {
bail_expr!(
&tle.t[1],
"varname-varvalue must be a list of two elements:\n\
varname, varvalue"
);
}
Ok((
varnameval[0].atom(None).ok_or_else(|| {
anyhow_expr!(&varnameval[0], "varname must be a string")
})?,
varnameval[1].atom(None).ok_or_else(|| {
anyhow_expr!(&varnameval[1], "varvalue must be a string")
})?,
))
})?;
let env_var_val = env_var_val.trim_atom_quotes();
match (
env.iter().find_map(|(name, val)| {
if name == env_var_name {
Some(val)
} else {
None
}
}),
env_var_val.is_empty(),
) {
(None, false) => {
#[cfg(feature = "lsp")]
_lsp_hints.inactive_code.push(lsp_hints::InactiveCode {
span: tle.span.clone(),
reason: format!(
"Active if env var {env_var_name} is {env_var_val}. It is unset."
),
});
}
(None, true) => {
tles.push(configuration.clone());
}
(Some(val), true) if val.is_empty() => {
tles.push(configuration.clone());
}
(Some(_val), true) => {
#[cfg(feature = "lsp")]
_lsp_hints.inactive_code.push(lsp_hints::InactiveCode {
span: tle.span.clone(),
reason: format!(
"Active if {env_var_name} is empty or unset. It has value {_val}"
),
});
}
(Some(val), false) => {
if val == env_var_val {
tles.push(configuration.clone());
} else {
#[cfg(feature = "lsp")]
_lsp_hints.inactive_code.push(lsp_hints::InactiveCode {
span: tle.span.clone(),
reason: format!(
"Active if {env_var_name} is {env_var_val}. It has value {val}"
),
})
}
}
}
Ok(tles)
})
}