use std::fmt;
use super::{
Component, Components, ElemId, Element, Field, FieldsAsExt as _, Location, Path, PathSet,
};
impl<'buf> Element<'buf> {
pub(crate) fn find_field(&self, key: &str) -> Option<&Field<'buf>> {
let fields = self.as_object_fields()?;
fields.find_field(key)
}
}
impl Field<'_> {
pub(crate) fn id(&self) -> ElemId {
self.element.id()
}
}
impl From<usize> for ElemId {
fn from(value: usize) -> Self {
Self(value)
}
}
pub struct LineHighlighter {
json: String,
pos: Location,
}
impl LineHighlighter {
pub fn from_value(json: &serde_json::Value, pos: Location) -> Self {
let json = serde_json::to_string_pretty(json).unwrap();
Self { json, pos }
}
}
impl fmt::Display for LineHighlighter {
#[expect(
clippy::arithmetic_side_effects,
reason = "line count cannot realistically overflow usize"
)]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let Ok(target_line) = usize::try_from(self.pos.line) else {
return Ok(());
};
for (index, line) in self.json.lines().enumerate() {
let line_no = index + 1;
if index == target_line {
writeln!(f, "{line_no:3}| {line}")?;
} else {
writeln!(f, " | {line}")?;
}
}
Ok(())
}
}
impl PathSet<'_> {
pub(crate) fn filter_matches(&mut self, glob: &PathGlob) {
self.0.retain(|path| !glob.matches(path));
}
}
#[derive(Debug)]
pub(crate) struct PathGlob(String);
impl PathGlob {
pub(crate) fn matches(&self, path: &Path) -> bool {
let mut glob = Components::over(&self.0);
let mut actual = path.components();
loop {
match (glob.next(), actual.next()) {
(Some(glob_component), Some(component)) => {
let is_wildcard = matches!(glob_component, Component::Member("*"));
if !is_wildcard && glob_component != component {
return false;
}
}
(None, None) => return true,
(None, Some(_)) | (Some(_), None) => return false,
}
}
}
}
impl<'a> From<&'a str> for PathGlob {
fn from(s: &'a str) -> Self {
Self(s.into())
}
}
impl From<String> for PathGlob {
fn from(s: String) -> Self {
Self(s)
}
}
impl<'de> serde::Deserialize<'de> for PathGlob {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
let s = <String as ::serde::Deserialize>::deserialize(deserializer)?;
Ok(Self(s))
}
}