1use std::fmt;
2use std::path::PathBuf;
3
4#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
5pub enum Severity {
6 Error,
7 Warning,
8}
9
10impl fmt::Display for Severity {
11 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
12 f.write_str(match self {
13 Self::Error => "error",
14 Self::Warning => "warning",
15 })
16 }
17}
18
19#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
20pub struct Location {
21 pub file: PathBuf,
22 pub line: u32,
23 pub column: u32,
24}
25
26impl fmt::Display for Location {
27 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
28 write!(f, "{}:{}:{}", self.file.display(), self.line, self.column)
29 }
30}
31
32#[derive(Clone, Debug, PartialEq, Eq, Hash)]
33pub struct Diagnostic {
34 pub file: PathBuf,
35 pub line: u32,
36 pub column: u32,
37 pub end_line: u32,
38 pub end_column: u32,
39 pub severity: Severity,
40 pub code: &'static str,
41 pub key: String,
42 pub message: String,
43 pub related: Vec<Location>,
44}
45
46impl Diagnostic {
47 pub fn is_error(&self) -> bool {
48 self.severity == Severity::Error
49 }
50
51 pub fn location(&self) -> Location {
52 Location {
53 file: self.file.clone(),
54 line: self.line,
55 column: self.column,
56 }
57 }
58}
59
60impl fmt::Display for Diagnostic {
61 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
62 write!(
63 f,
64 "{}:{}:{}: {} [{}]",
65 self.file.display(),
66 self.line,
67 self.column,
68 self.severity,
69 self.code
70 )?;
71 if !self.key.is_empty() {
72 write!(f, " {}:", self.key)?;
73 }
74 write!(f, " {}", self.message)?;
75 for related in &self.related {
76 write!(f, " (see {related})")?;
77 }
78 Ok(())
79 }
80}
81
82impl std::error::Error for Diagnostic {}
83
84pub mod code {
85 pub const SYNTAX: &str = "syntax";
86 pub const UNREADABLE: &str = "unreadable";
87 pub const NOT_UTF8: &str = "not-utf8";
88 pub const UNKNOWN_KEY: &str = "unknown-key";
89 pub const MISSING_KEY: &str = "missing-key";
90 pub const BAD_TYPE: &str = "bad-type";
91 pub const BAD_VALUE: &str = "bad-value";
92 pub const BAD_ID: &str = "bad-id";
93 pub const MISSING_ID: &str = "missing-id";
94 pub const DUPLICATE_ID: &str = "duplicate-id";
95 pub const BAD_NAME: &str = "bad-name";
96 pub const DUPLICATE_NAME: &str = "duplicate-name";
97 pub const BAD_REFERENCE: &str = "bad-reference";
98 pub const AMBIGUOUS_REFERENCE: &str = "ambiguous-reference";
99 pub const BAD_PATH: &str = "bad-path";
100 pub const OUTSIDE_ROOT: &str = "outside-root";
101 pub const MISSING_FILE: &str = "missing-file";
102 pub const PATH_CASE: &str = "path-case";
103 pub const INCLUDE_CYCLE: &str = "include-cycle";
104 pub const PREFAB_CYCLE: &str = "prefab-cycle";
105 pub const INCLUDE_DEPTH: &str = "include-depth";
106 pub const PREFAB_DEPTH: &str = "prefab-depth";
107 pub const PARENT_CYCLE: &str = "parent-cycle";
108 pub const HELD_TWICE: &str = "held-twice";
109 pub const BAD_OVERRIDE: &str = "bad-override";
110 pub const PLACEMENT_KEY: &str = "placement-key";
111 pub const OLD_FORMAT: &str = "old-format";
112 pub const NEWER_FORMAT: &str = "newer-format";
113 pub const MIGRATION: &str = "migration";
114
115 pub const ALL: &[&str] = &[
116 SYNTAX,
117 UNREADABLE,
118 NOT_UTF8,
119 UNKNOWN_KEY,
120 MISSING_KEY,
121 BAD_TYPE,
122 BAD_VALUE,
123 BAD_ID,
124 MISSING_ID,
125 DUPLICATE_ID,
126 BAD_NAME,
127 DUPLICATE_NAME,
128 BAD_REFERENCE,
129 AMBIGUOUS_REFERENCE,
130 BAD_PATH,
131 OUTSIDE_ROOT,
132 MISSING_FILE,
133 PATH_CASE,
134 INCLUDE_CYCLE,
135 PREFAB_CYCLE,
136 INCLUDE_DEPTH,
137 PREFAB_DEPTH,
138 PARENT_CYCLE,
139 HELD_TWICE,
140 BAD_OVERRIDE,
141 PLACEMENT_KEY,
142 OLD_FORMAT,
143 NEWER_FORMAT,
144 MIGRATION,
145 ];
146}