use std::collections::BTreeSet;
use std::path::Path;
use yog_data::Path as At;
use yog_ids::Format;
use crate::content::CONTENT_DIR;
use crate::diagnostics::Diagnostic;
use crate::yres;
pub(in crate::content) struct Ctx<'a> {
pub(in crate::content) root: &'a Path,
pub(in crate::content) refs: &'a yres::Refs,
pub(in crate::content) file: String,
pub(in crate::content) ns: String,
pub(in crate::content) errors: &'a mut Vec<Diagnostic>,
pub(in crate::content) warnings: &'a mut Vec<Diagnostic>,
pub(in crate::content) own_textures: &'a BTreeSet<String>,
pub(in crate::content) inventories: &'a mut Vec<(String, usize, String)>,
pub(in crate::content) deferred: &'a mut Vec<Deferred>,
}
pub(in crate::content) enum Wanted {
Ref(yog_data::Ref),
Tag { kinds: Vec<String>, id: String },
}
pub(in crate::content) struct Deferred {
pub(in crate::content) file: String,
pub(in crate::content) line: usize,
pub(in crate::content) path: String,
pub(in crate::content) wanted: Wanted,
}
pub(in crate::content) struct Shared<'a> {
pub(in crate::content) root: &'a Path,
pub(in crate::content) refs: &'a yres::Refs,
pub(in crate::content) ns: &'a str,
pub(in crate::content) own_textures: &'a BTreeSet<String>,
}
impl Shared<'_> {
pub(in crate::content) fn content_id(&self, path: &Path) -> String {
let rel = path
.strip_prefix(self.root.join(CONTENT_DIR))
.unwrap_or(path)
.with_extension("");
yog_ids::join(self.ns, &crate::slash_path(&rel))
}
}
#[derive(Default)]
pub(in crate::content) struct Sink {
pub(in crate::content) errors: Vec<Diagnostic>,
pub(in crate::content) warnings: Vec<Diagnostic>,
pub(in crate::content) inventories: Vec<(String, usize, String)>,
pub(in crate::content) deferred: Vec<Deferred>,
}
impl Sink {
pub(in crate::content) fn cx<'s>(&'s mut self, shared: &Shared<'s>, file: &str) -> Ctx<'s> {
Ctx {
root: shared.root,
refs: shared.refs,
file: file.to_string(),
ns: shared.ns.to_string(),
errors: &mut self.errors,
warnings: &mut self.warnings,
own_textures: shared.own_textures,
inventories: &mut self.inventories,
deferred: &mut self.deferred,
}
}
}
impl Ctx<'_> {
pub(in crate::content) fn err(&mut self, line: usize, msg: impl std::fmt::Display) {
self.errors
.push(problem(msg).in_file(&self.file).at_line(line));
}
pub(in crate::content) fn defer(&mut self, line: usize, path: &At, wanted: Wanted) {
self.deferred.push(Deferred {
file: self.file.clone(),
line,
path: path.to_string(),
wanted,
});
}
pub(in crate::content) fn warn(&mut self, line: usize, msg: impl std::fmt::Display) {
self.warnings
.push(caveat(msg).in_file(&self.file).at_line(line));
}
pub(in crate::content) fn err_at(&mut self, loc: Loc, path: &At, msg: impl std::fmt::Display) {
let found = problem(msg).in_file(&self.file).at_line(loc(path));
self.errors.push(found.at_path(path.clone()));
}
pub(in crate::content) fn warn_at(&mut self, loc: Loc, path: &At, msg: impl std::fmt::Display) {
let found = caveat(msg).in_file(&self.file).at_line(loc(path));
self.warnings.push(found.at_path(path.clone()));
}
pub(in crate::content) fn schema_errors(&mut self, errors: yog_data::Errors) {
for e in errors.0 {
self.errors.push(e.in_file(&self.file));
}
}
pub(in crate::content) fn texture(
&mut self,
loc: Loc,
path: &At,
t: &yog_formats::content::Texture,
) -> Option<String> {
use yog_formats::content::{SLOT_MARK, Texture};
match t {
Texture::Slot(slot) => Some(format!("{SLOT_MARK}{slot}")),
Texture::Ref(id) => {
let (ns, tex) = yog_ids::split(id);
if ns == self.ns && !self.own_textures.contains(id) {
self.err_at(
loc,
path,
format!(
"`{}{id}`: no {}/{tex}.{}",
yog_ids::reference::TEXTURE,
yres::RESOURCES_DIR,
Format::Texture.ext()
),
);
return None;
}
Some(id.clone())
}
}
}
}
pub(in crate::content) type Loc<'a> = &'a dyn Fn(&At) -> usize;
pub(in crate::content) fn problem(msg: impl std::fmt::Display) -> Diagnostic {
Diagnostic::error(yog_ids::build_problem::CONTENT, msg)
}
pub(in crate::content) fn caveat(msg: impl std::fmt::Display) -> Diagnostic {
Diagnostic::warning(yog_ids::build_problem::CONTENT, msg)
}