guise/editor/
diagnostic.rs1use std::ops::Range;
9
10use gpui::{Hsla, SharedString};
11
12use crate::theme::Theme;
13
14#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
16pub enum Severity {
17 Hint,
18 Info,
19 Warning,
20 Error,
21}
22
23impl Severity {
24 pub fn color(self, t: &Theme) -> Hsla {
26 match self {
27 Severity::Error => t.danger().hsla(),
28 Severity::Warning => t.warning().hsla(),
29 Severity::Info => t.info().hsla(),
30 Severity::Hint => t.dimmed().hsla(),
31 }
32 }
33}
34
35#[derive(Debug, Clone)]
37pub struct Diagnostic {
38 pub line: usize,
40 pub cols: Range<usize>,
42 pub severity: Severity,
43 pub message: SharedString,
44}
45
46impl Diagnostic {
47 pub fn new(
48 line: usize,
49 cols: Range<usize>,
50 severity: Severity,
51 message: impl Into<SharedString>,
52 ) -> Self {
53 Diagnostic {
54 line,
55 cols,
56 severity,
57 message: message.into(),
58 }
59 }
60
61 pub fn line_wide(line: usize, severity: Severity, message: impl Into<SharedString>) -> Self {
63 Diagnostic::new(line, 0..0, severity, message)
64 }
65}
66
67pub(crate) fn line_severity(diagnostics: &[Diagnostic], line: usize) -> Option<Severity> {
70 diagnostics
71 .iter()
72 .filter(|d| d.line == line)
73 .map(|d| d.severity)
74 .max()
75}
76
77pub(crate) fn line_message(diagnostics: &[Diagnostic], line: usize) -> Option<&Diagnostic> {
79 diagnostics
80 .iter()
81 .filter(|d| d.line == line)
82 .max_by_key(|d| d.severity)
83}
84
85#[cfg(test)]
86mod tests {
87 use super::*;
88
89 #[test]
90 fn severity_orders_worst_last() {
91 assert!(Severity::Error > Severity::Warning);
92 assert!(Severity::Warning > Severity::Info);
93 assert!(Severity::Info > Severity::Hint);
94 }
95
96 #[test]
97 fn line_lookups_pick_the_worst() {
98 let diags = vec![
99 Diagnostic::new(2, 0..4, Severity::Warning, "unused"),
100 Diagnostic::new(2, 6..9, Severity::Error, "type mismatch"),
101 Diagnostic::line_wide(5, Severity::Hint, "style"),
102 ];
103 assert_eq!(line_severity(&diags, 2), Some(Severity::Error));
104 assert_eq!(line_severity(&diags, 5), Some(Severity::Hint));
105 assert_eq!(line_severity(&diags, 0), None);
106 assert_eq!(
107 line_message(&diags, 2).unwrap().message.as_ref(),
108 "type mismatch"
109 );
110 }
111
112 #[test]
113 fn line_wide_uses_an_empty_range() {
114 let d = Diagnostic::line_wide(3, Severity::Error, "boom");
115 assert!(d.cols.is_empty());
116 assert_eq!(d.line, 3);
117 }
118}