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) -> 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 super::*;
58
59 #[test]
60 fn get_diag_msg_or_skip_when_buf_path_not_matched_returns_skip() {
61 let filter = TestFilter {
62 source: "Test",
63 path_substring: Some("src/"),
64 };
65 let diag = dict! {
66 source: "Test",
67 message: "some message",
68 };
69 assert2::assert!(let Ok(result) = filter.get_diag_msg_or_skip("tests/main.rs", &diag));
70 pretty_assertions::assert_eq!(result, GetDiagMsgOutput::Skip);
71 }
72
73 #[test]
74 fn get_diag_msg_or_skip_when_buf_path_matched_but_source_none_returns_skip() {
75 let filter = TestFilter {
76 source: "Test",
77 path_substring: Some("src/"),
78 };
79 let diag = dict! {
80 message: "some message",
81 };
82 assert2::assert!(let Ok(result) = filter.get_diag_msg_or_skip("src/main.rs", &diag));
83 pretty_assertions::assert_eq!(result, GetDiagMsgOutput::Skip);
84 }
85
86 #[test]
87 fn get_diag_msg_or_skip_when_buf_path_matched_but_source_mismatch_returns_skip() {
88 let filter = TestFilter {
89 source: "Test",
90 path_substring: Some("src/"),
91 };
92 let diag = dict! {
93 source: "Other",
94 message: "some message",
95 };
96 assert2::assert!(let Ok(result) = filter.get_diag_msg_or_skip("src/main.rs", &diag));
97 pretty_assertions::assert_eq!(result, GetDiagMsgOutput::Skip);
98 }
99
100 #[test]
101 fn get_diag_msg_or_skip_when_buf_path_and_source_matches_returns_msg() {
102 let filter = TestFilter {
103 source: "Test",
104 path_substring: Some("src/"),
105 };
106 let diag = dict! {
107 source: "Test",
108 message: "some message",
109 };
110 assert2::assert!(let Ok(result) = filter.get_diag_msg_or_skip("src/main.rs", &diag));
111 pretty_assertions::assert_eq!(result, GetDiagMsgOutput::Msg("some message".to_string()));
112 }
113
114 #[test]
115 fn get_diag_msg_or_skip_when_no_buf_path_and_source_matches_returns_msg() {
116 let filter = TestFilter {
117 source: "Test",
118 path_substring: None,
119 };
120 let diag = dict! {
121 source: "Test",
122 message: "another message",
123 };
124 assert2::assert!(let Ok(result) = filter.get_diag_msg_or_skip("any/path.rs", &diag));
125 pretty_assertions::assert_eq!(result, GetDiagMsgOutput::Msg("another message".to_string()));
126 }
127
128 #[test]
129 fn get_diag_msg_or_skip_when_source_contains_filter_source_returns_msg() {
130 let filter = TestFilter {
131 source: "Test",
132 path_substring: None,
133 };
134 let diag = dict! {
135 source: "TestLSP",
136 message: "some message",
137 };
138 assert2::assert!(let Ok(result) = filter.get_diag_msg_or_skip("any/path.rs", &diag));
139 pretty_assertions::assert_eq!(result, GetDiagMsgOutput::Msg("some message".to_string()));
140 }
141
142 struct TestFilter {
143 source: &'static str,
144 path_substring: Option<&'static str>,
145 }
146
147 impl LspFilter for TestFilter {
148 fn path_substring(&self) -> Option<&str> {
149 self.path_substring
150 }
151
152 fn source(&self) -> &str {
153 self.source
154 }
155 }
156}