lattice_config/
diagnostics_options.rs1use crate::option_type::{EnumeratedValue, OptionType};
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
16pub enum DiagnosticsInline {
17 Off,
20 #[default]
24 CursorLine,
25 All,
27}
28
29impl DiagnosticsInline {
30 pub fn label(&self) -> &'static str {
33 match self {
34 DiagnosticsInline::Off => "off",
35 DiagnosticsInline::CursorLine => "cursor-line",
36 DiagnosticsInline::All => "all",
37 }
38 }
39
40 pub fn doc(&self) -> &'static str {
43 match self {
44 DiagnosticsInline::Off => "No inline summary (gutter + underline only)",
45 DiagnosticsInline::CursorLine => "End-of-line summary on the cursor line, idle-gated",
46 DiagnosticsInline::All => "End-of-line summary on every viewport line",
47 }
48 }
49
50 pub fn all() -> [DiagnosticsInline; 3] {
52 [
53 DiagnosticsInline::Off,
54 DiagnosticsInline::CursorLine,
55 DiagnosticsInline::All,
56 ]
57 }
58
59 pub fn parse_label(s: &str) -> Result<Self, String> {
75 match s {
76 "off" => Ok(DiagnosticsInline::Off),
77 "cursor-line" => Ok(DiagnosticsInline::CursorLine),
78 "all" => Ok(DiagnosticsInline::All),
79 other => Err(format!(
80 "ui.diagnostics.inline: expected `off`, `cursor-line`, or `all`, got `{other}`"
81 )),
82 }
83 }
84}
85
86impl OptionType for DiagnosticsInline {
87 fn parse(s: &str) -> Result<Self, String> {
88 DiagnosticsInline::parse_label(s)
89 }
90 fn format(&self) -> String {
91 self.label().to_string()
92 }
93 fn type_label() -> &'static str {
94 "diagnostics-inline"
95 }
96 fn enumerate() -> Option<Vec<&'static str>> {
97 Some(DiagnosticsInline::all().iter().map(|v| v.label()).collect())
98 }
99
100 fn enumerate_is_exhaustive() -> bool {
103 true
104 }
105 fn enumerate_with_docs() -> Option<Vec<EnumeratedValue>> {
106 Some(
107 DiagnosticsInline::all()
108 .iter()
109 .map(|v| EnumeratedValue {
110 form: v.label(),
111 doc: v.doc(),
112 })
113 .collect(),
114 )
115 }
116}
117
118#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
123pub enum DiagnosticsSeverity {
124 Error,
126 Warning,
128 Info,
130 #[default]
132 Hint,
133}
134
135impl DiagnosticsSeverity {
136 pub fn rank(&self) -> u8 {
140 match self {
141 DiagnosticsSeverity::Error => 0,
142 DiagnosticsSeverity::Warning => 1,
143 DiagnosticsSeverity::Info => 2,
144 DiagnosticsSeverity::Hint => 3,
145 }
146 }
147
148 pub fn label(&self) -> &'static str {
151 match self {
152 DiagnosticsSeverity::Error => "error",
153 DiagnosticsSeverity::Warning => "warning",
154 DiagnosticsSeverity::Info => "info",
155 DiagnosticsSeverity::Hint => "hint",
156 }
157 }
158
159 pub fn doc(&self) -> &'static str {
162 match self {
163 DiagnosticsSeverity::Error => "Errors only",
164 DiagnosticsSeverity::Warning => "Warnings and errors",
165 DiagnosticsSeverity::Info => "Info, warnings, and errors",
166 DiagnosticsSeverity::Hint => "All diagnostics (hints and up)",
167 }
168 }
169
170 pub fn all() -> [DiagnosticsSeverity; 4] {
172 [
173 DiagnosticsSeverity::Error,
174 DiagnosticsSeverity::Warning,
175 DiagnosticsSeverity::Info,
176 DiagnosticsSeverity::Hint,
177 ]
178 }
179
180 pub fn parse_label(s: &str) -> Result<Self, String> {
194 match s {
195 "error" => Ok(DiagnosticsSeverity::Error),
196 "warning" => Ok(DiagnosticsSeverity::Warning),
197 "info" => Ok(DiagnosticsSeverity::Info),
198 "hint" => Ok(DiagnosticsSeverity::Hint),
199 other => Err(format!(
200 "ui.diagnostics.inline-min-severity: expected `error`, `warning`, `info`, or `hint`, got `{other}`"
201 )),
202 }
203 }
204}
205
206impl OptionType for DiagnosticsSeverity {
207 fn parse(s: &str) -> Result<Self, String> {
208 DiagnosticsSeverity::parse_label(s)
209 }
210 fn format(&self) -> String {
211 self.label().to_string()
212 }
213 fn type_label() -> &'static str {
214 "diagnostics-severity"
215 }
216 fn enumerate() -> Option<Vec<&'static str>> {
217 Some(
218 DiagnosticsSeverity::all()
219 .iter()
220 .map(|v| v.label())
221 .collect(),
222 )
223 }
224
225 fn enumerate_is_exhaustive() -> bool {
228 true
229 }
230 fn enumerate_with_docs() -> Option<Vec<EnumeratedValue>> {
231 Some(
232 DiagnosticsSeverity::all()
233 .iter()
234 .map(|v| EnumeratedValue {
235 form: v.label(),
236 doc: v.doc(),
237 })
238 .collect(),
239 )
240 }
241}
242
243#[cfg(test)]
244mod tests {
245 #![allow(clippy::unwrap_used, clippy::panic)]
246 use super::*;
247
248 #[test]
249 fn inline_round_trips_and_default_is_cursor_line() {
250 assert_eq!(DiagnosticsInline::default(), DiagnosticsInline::CursorLine);
251 for v in DiagnosticsInline::all() {
252 assert_eq!(DiagnosticsInline::parse(&v.format()).unwrap(), v);
253 }
254 assert!(DiagnosticsInline::parse("nope").is_err());
255 }
256
257 #[test]
258 fn severity_round_trips_and_rank_orders_error_lowest() {
259 assert_eq!(DiagnosticsSeverity::default(), DiagnosticsSeverity::Hint);
260 for v in DiagnosticsSeverity::all() {
261 assert_eq!(DiagnosticsSeverity::parse(&v.format()).unwrap(), v);
262 }
263 assert!(DiagnosticsSeverity::Error.rank() < DiagnosticsSeverity::Warning.rank());
264 assert!(DiagnosticsSeverity::Warning.rank() < DiagnosticsSeverity::Info.rank());
265 assert!(DiagnosticsSeverity::Info.rank() < DiagnosticsSeverity::Hint.rank());
266 assert!(DiagnosticsSeverity::parse("fatal").is_err());
267 }
268
269 #[test]
270 fn enumerate_with_docs_covers_every_variant() {
271 assert_eq!(DiagnosticsInline::enumerate_with_docs().unwrap().len(), 3);
272 assert_eq!(DiagnosticsSeverity::enumerate_with_docs().unwrap().len(), 4);
273 }
274}