nvrim/diagnostics/
formatter.rs1use serde::Deserialize;
7
8#[expect(
10 clippy::needless_pass_by_value,
11 reason = "nvim function binding requires owned Lua-converted arguments"
12)]
13pub fn format(diagnostic: Diagnostic) -> Option<String> {
14 let Some(msg) = get_msg(&diagnostic).map(|s| s.trim_end_matches('.').to_string()) else {
15 ytil_noxi::notify::error(format!("error missing diagnostic message | diagnostic={diagnostic:#?}"));
16 return None;
17 };
18
19 let Some(src) = get_src(&diagnostic).map(str::to_string) else {
20 ytil_noxi::notify::error(format!("error missing diagnostic source | diagnostic={diagnostic:#?}"));
21 return None;
22 };
23
24 let src_and_code = get_code(&diagnostic).map_or_else(|| src.clone(), |c| format!("{src}: {c}"));
25
26 Some(format!("▶ {msg} [{src_and_code}]"))
27}
28
29#[derive(Debug, Deserialize)]
31pub struct Diagnostic {
32 code: Option<String>,
34 message: Option<String>,
36 source: Option<String>,
38 user_data: Option<UserData>,
40}
41
42ytil_noxi::impl_nvim_deserializable!(Diagnostic);
43
44#[derive(Debug, Deserialize)]
46pub struct UserData {
47 lsp: Option<Lsp>,
49}
50
51#[derive(Debug, Deserialize)]
53pub struct Lsp {
54 code: Option<String>,
56 data: Option<LspData>,
58 message: Option<String>,
60 source: Option<String>,
62}
63
64#[derive(Debug, Deserialize)]
66pub struct LspData {
67 rendered: Option<String>,
68}
69
70fn get_msg(diag: &Diagnostic) -> Option<&str> {
72 diag.user_data
73 .as_ref()
74 .and_then(|user_data| {
75 user_data
76 .lsp
77 .as_ref()
78 .and_then(|lsp| {
79 lsp.data
80 .as_ref()
81 .and_then(|lsp_data| lsp_data.rendered.as_deref())
82 .or(lsp.message.as_deref())
83 })
84 .or(diag.message.as_deref())
85 })
86 .or(diag.message.as_deref())
87}
88
89fn get_src(diag: &Diagnostic) -> Option<&str> {
91 diag.user_data
92 .as_ref()
93 .and_then(|user_data| user_data.lsp.as_ref().and_then(|lsp| lsp.source.as_deref()))
94 .or(diag.source.as_deref())
95}
96
97fn get_code(diag: &Diagnostic) -> Option<&str> {
99 diag.user_data
100 .as_ref()
101 .and_then(|user_data| user_data.lsp.as_ref().and_then(|lsp| lsp.code.as_deref()))
102 .or(diag.code.as_deref())
103}