nvrim/diagnostics/filters/
lsps.rs1use nvim_oxi::Dictionary;
7use ytil_noxi::dict::DictionaryExt;
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) -> rootcause::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_or(|diag_source| !diag_source.contains(self.source())) {
49 return Ok(GetDiagMsgOutput::Skip);
50 }
51 Ok(GetDiagMsgOutput::Msg(lsp_diag.get_t::<nvim_oxi::String>("message")?))
52 }
53}
54
55#[cfg(test)]
56mod tests {
57 use test_that::prelude::*;
58
59 use super::*;
60
61 #[test]
62 fn test_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 assert_that!(
72 filter.get_diag_msg_or_skip("tests/main.rs", &diag),
73 ok(eq(GetDiagMsgOutput::Skip))
74 );
75 }
76
77 #[test]
78 fn test_get_diag_msg_or_skip_when_buf_path_matched_but_source_none_returns_skip() {
79 let filter = TestFilter {
80 source: "Test",
81 path_substring: Some("src/"),
82 };
83 let diag = dict! {
84 message: "some message",
85 };
86 assert_that!(
87 filter.get_diag_msg_or_skip("src/main.rs", &diag),
88 ok(eq(GetDiagMsgOutput::Skip))
89 );
90 }
91
92 #[test]
93 fn test_get_diag_msg_or_skip_when_buf_path_matched_but_source_mismatch_returns_skip() {
94 let filter = TestFilter {
95 source: "Test",
96 path_substring: Some("src/"),
97 };
98 let diag = dict! {
99 source: "Other",
100 message: "some message",
101 };
102 assert_that!(
103 filter.get_diag_msg_or_skip("src/main.rs", &diag),
104 ok(eq(GetDiagMsgOutput::Skip))
105 );
106 }
107
108 #[test]
109 fn test_get_diag_msg_or_skip_when_buf_path_and_source_matches_returns_msg() {
110 let filter = TestFilter {
111 source: "Test",
112 path_substring: Some("src/"),
113 };
114 let diag = dict! {
115 source: "Test",
116 message: "some message",
117 };
118 assert_that!(
119 filter.get_diag_msg_or_skip("src/main.rs", &diag),
120 ok(eq(GetDiagMsgOutput::Msg("some message".to_string())))
121 );
122 }
123
124 #[test]
125 fn test_get_diag_msg_or_skip_when_no_buf_path_and_source_matches_returns_msg() {
126 let filter = TestFilter {
127 source: "Test",
128 path_substring: None,
129 };
130 let diag = dict! {
131 source: "Test",
132 message: "another message",
133 };
134 assert_that!(
135 filter.get_diag_msg_or_skip("any/path.rs", &diag),
136 ok(eq(GetDiagMsgOutput::Msg("another message".to_string())))
137 );
138 }
139
140 #[test]
141 fn test_get_diag_msg_or_skip_when_source_contains_filter_source_returns_msg() {
142 let filter = TestFilter {
143 source: "Test",
144 path_substring: None,
145 };
146 let diag = dict! {
147 source: "TestLSP",
148 message: "some message",
149 };
150 assert_that!(
151 filter.get_diag_msg_or_skip("any/path.rs", &diag),
152 ok(eq(GetDiagMsgOutput::Msg("some message".to_string())))
153 );
154 }
155
156 struct TestFilter {
157 source: &'static str,
158 path_substring: Option<&'static str>,
159 }
160
161 impl LspFilter for TestFilter {
162 fn path_substring(&self) -> Option<&str> {
163 self.path_substring
164 }
165
166 fn source(&self) -> &str {
167 self.source
168 }
169 }
170}