nvrim/diagnostics/filters/
related_info.rs1use std::collections::HashSet;
7
8use nvim_oxi::Array;
9use nvim_oxi::Dictionary;
10use nvim_oxi::ObjectKind;
11use nvim_oxi::conversion::FromObject;
12use rootcause::prelude::ResultExt;
13use ytil_noxi::dict::DictionaryExt;
14
15use crate::diagnostics::filters::BufferWithPath;
16use crate::diagnostics::filters::DiagnosticsFilter;
17
18pub struct RelatedInfoFilter {
21 rel_infos: HashSet<RelatedInfo>,
25}
26
27impl RelatedInfoFilter {
28 pub fn new(lsp_diags: &[Dictionary]) -> rootcause::Result<Self> {
33 Ok(Self {
34 rel_infos: Self::get_related_infos(lsp_diags)?,
35 })
36 }
37
38 fn get_related_infos(lsp_diags: &[Dictionary]) -> rootcause::Result<HashSet<RelatedInfo>> {
43 let mut out = HashSet::with_capacity(lsp_diags.len().saturating_mul(2));
45 for lsp_diag in lsp_diags {
46 let Some(lsp) = lsp_diag.get_dict(&["user_data", "lsp"])? else {
48 continue;
49 };
50 let rel_infos_key = "relatedInformation";
51 let Some(rel_infos) = lsp.get(rel_infos_key) else {
52 continue;
53 };
54
55 let rel_infos = Array::from_object(rel_infos.clone())
56 .context("unexpected object kind")
57 .attach_with(|| {
58 ytil_noxi::extract::unexpected_kind_error_msg(rel_infos, rel_infos_key, &lsp, ObjectKind::Array)
59 })?;
60 for rel_info in rel_infos {
61 let rel_info = Dictionary::try_from(rel_info)?;
62 out.insert(RelatedInfo::from_related_info(&rel_info)?);
63 }
64 }
65 Ok(out)
66 }
67}
68
69impl DiagnosticsFilter for RelatedInfoFilter {
70 fn skip_diagnostic(&self, _buf: &BufferWithPath, lsp_diag: &Dictionary) -> rootcause::Result<bool> {
75 if self.rel_infos.is_empty() {
76 return Ok(false);
77 }
78 let rel_info = RelatedInfo::from_lsp_diagnostic(lsp_diag)?;
80 if self.rel_infos.contains(&rel_info) {
81 return Ok(true);
82 }
83 Ok(false)
84 }
85}
86
87#[derive(Eq, Hash, PartialEq)]
89struct RelatedInfo {
90 col: i64,
92 end_col: i64,
94 end_lnum: i64,
96 lnum: i64,
98 message: String,
100}
101
102impl RelatedInfo {
103 fn from_lsp_diagnostic(lsp_diagnostic: &Dictionary) -> rootcause::Result<Self> {
108 Ok(Self {
109 message: lsp_diagnostic.get_t::<nvim_oxi::String>("message")?,
110 lnum: lsp_diagnostic.get_t::<nvim_oxi::Integer>("lnum")?,
111 col: lsp_diagnostic.get_t::<nvim_oxi::Integer>("col")?,
112 end_lnum: lsp_diagnostic.get_t::<nvim_oxi::Integer>("end_lnum")?,
113 end_col: lsp_diagnostic.get_t::<nvim_oxi::Integer>("end_col")?,
114 })
115 }
116
117 fn from_related_info(rel_info: &Dictionary) -> rootcause::Result<Self> {
122 let (start, end) = {
123 let range_query = ["location", "range"];
124 let range = rel_info.get_required_dict(&range_query)?;
125
126 let start_query = ["start"];
127 let end_query = ["end"];
128 (
129 range.get_required_dict(&start_query)?,
130 range.get_required_dict(&end_query)?,
131 )
132 };
133
134 Ok(Self {
135 message: rel_info.get_t::<nvim_oxi::String>("message")?,
136 lnum: start.get_t::<nvim_oxi::Integer>("line")?,
137 col: start.get_t::<nvim_oxi::Integer>("character")?,
138 end_lnum: end.get_t::<nvim_oxi::Integer>("line")?,
139 end_col: end.get_t::<nvim_oxi::Integer>("character")?,
140 })
141 }
142}