nvrim/diagnostics/filters/
lsps.rs1use nvim_oxi::Dictionary;
7use ytil_noxi::dict::DictionaryExt as _;
8
9pub mod harper_ls;
10pub mod typos_lsp;
11
12#[cfg_attr(test, derive(Debug, Eq, PartialEq))]
14pub enum GetDiagMsgOutput {
15 Msg(String),
17 Skip,
19}
20
21pub trait LspFilter {
25 fn path_substring(&self) -> Option<&str>;
29
30 fn source(&self) -> &str;
32
33 fn get_diag_msg_or_skip(&self, buf_path: &str, lsp_diag: &Dictionary) -> color_eyre::Result<GetDiagMsgOutput> {
41 if self
42 .path_substring()
43 .is_some_and(|path_substring| !buf_path.contains(path_substring))
44 {
45 return Ok(GetDiagMsgOutput::Skip);
46 }
47 let maybe_diag_source = lsp_diag.get_opt_t::<nvim_oxi::String>("source")?;
48 if maybe_diag_source.is_none()
49 || maybe_diag_source.is_some_and(|diag_source| !diag_source.contains(self.source()))
50 {
51 return Ok(GetDiagMsgOutput::Skip);
52 }
53 Ok(GetDiagMsgOutput::Msg(lsp_diag.get_t::<nvim_oxi::String>("message")?))
54 }
55}
56
57#[cfg(test)]
58mod tests {
59 use super::*;
60
61 #[test]
62 fn get_diag_msg_or_skip_when_buf_path_not_matched_returns_skip() {
63 let filter = TestFilter {
64 source: "Test",
65 path_substring: Some("src/"),
66 };
67 let diag = dict! {
68 source: "Test",
69 message: "some message",
70 };
71 assert2::let_assert!(Ok(result) = filter.get_diag_msg_or_skip("tests/main.rs", &diag));
72 pretty_assertions::assert_eq!(result, GetDiagMsgOutput::Skip);
73 }
74
75 #[test]
76 fn get_diag_msg_or_skip_when_buf_path_matched_but_source_none_returns_skip() {
77 let filter = TestFilter {
78 source: "Test",
79 path_substring: Some("src/"),
80 };
81 let diag = dict! {
82 message: "some message",
83 };
84 assert2::let_assert!(Ok(result) = filter.get_diag_msg_or_skip("src/main.rs", &diag));
85 pretty_assertions::assert_eq!(result, GetDiagMsgOutput::Skip);
86 }
87
88 #[test]
89 fn get_diag_msg_or_skip_when_buf_path_matched_but_source_mismatch_returns_skip() {
90 let filter = TestFilter {
91 source: "Test",
92 path_substring: Some("src/"),
93 };
94 let diag = dict! {
95 source: "Other",
96 message: "some message",
97 };
98 assert2::let_assert!(Ok(result) = filter.get_diag_msg_or_skip("src/main.rs", &diag));
99 pretty_assertions::assert_eq!(result, GetDiagMsgOutput::Skip);
100 }
101
102 #[test]
103 fn get_diag_msg_or_skip_when_buf_path_and_source_matches_returns_msg() {
104 let filter = TestFilter {
105 source: "Test",
106 path_substring: Some("src/"),
107 };
108 let diag = dict! {
109 source: "Test",
110 message: "some message",
111 };
112 assert2::let_assert!(Ok(result) = filter.get_diag_msg_or_skip("src/main.rs", &diag));
113 pretty_assertions::assert_eq!(result, GetDiagMsgOutput::Msg("some message".to_string()));
114 }
115
116 #[test]
117 fn get_diag_msg_or_skip_when_no_buf_path_and_source_matches_returns_msg() {
118 let filter = TestFilter {
119 source: "Test",
120 path_substring: None,
121 };
122 let diag = dict! {
123 source: "Test",
124 message: "another message",
125 };
126 assert2::let_assert!(Ok(result) = filter.get_diag_msg_or_skip("any/path.rs", &diag));
127 pretty_assertions::assert_eq!(result, GetDiagMsgOutput::Msg("another message".to_string()));
128 }
129
130 #[test]
131 fn get_diag_msg_or_skip_when_source_contains_filter_source_returns_msg() {
132 let filter = TestFilter {
133 source: "Test",
134 path_substring: None,
135 };
136 let diag = dict! {
137 source: "TestLSP",
138 message: "some message",
139 };
140 assert2::let_assert!(Ok(result) = filter.get_diag_msg_or_skip("any/path.rs", &diag));
141 pretty_assertions::assert_eq!(result, GetDiagMsgOutput::Msg("some message".to_string()));
142 }
143
144 struct TestFilter {
145 source: &'static str,
146 path_substring: Option<&'static str>,
147 }
148
149 impl LspFilter for TestFilter {
150 fn path_substring(&self) -> Option<&str> {
151 self.path_substring
152 }
153
154 fn source(&self) -> &str {
155 self.source
156 }
157 }
158}