nvrim/diagnostics/
formatter.rs1use nvim_oxi::Object;
7use nvim_oxi::conversion::FromObject;
8use nvim_oxi::lua::Poppable;
9use nvim_oxi::lua::ffi::State;
10use nvim_oxi::serde::Deserializer;
11use serde::Deserialize;
12
13#[allow(clippy::needless_pass_by_value)]
15pub fn format(diagnostic: Diagnostic) -> Option<String> {
16 let Some(msg) = get_msg(&diagnostic).map(|s| s.trim_end_matches('.').to_string()) else {
17 ytil_noxi::notify::error(format!("error missing diagnostic message | diagnostic={diagnostic:#?}"));
18 return None;
19 };
20
21 let Some(src) = get_src(&diagnostic).map(str::to_string) else {
22 ytil_noxi::notify::error(format!("error missing diagnostic source | diagnostic={diagnostic:#?}"));
23 return None;
24 };
25
26 let src_and_code = get_code(&diagnostic).map_or_else(|| src.clone(), |c| format!("{src}: {c}"));
27
28 Some(format!("▶ {msg} [{src_and_code}]"))
29}
30
31fn get_msg(diag: &Diagnostic) -> Option<&str> {
33 diag.user_data
34 .as_ref()
35 .and_then(|user_data| {
36 user_data
37 .lsp
38 .as_ref()
39 .and_then(|lsp| {
40 lsp.data
41 .as_ref()
42 .and_then(|lsp_data| lsp_data.rendered.as_deref())
43 .or(lsp.message.as_deref())
44 })
45 .or(diag.message.as_deref())
46 })
47 .or(diag.message.as_deref())
48}
49
50fn get_src(diag: &Diagnostic) -> Option<&str> {
52 diag.user_data
53 .as_ref()
54 .and_then(|user_data| user_data.lsp.as_ref().and_then(|lsp| lsp.source.as_deref()))
55 .or(diag.source.as_deref())
56}
57
58fn get_code(diag: &Diagnostic) -> Option<&str> {
60 diag.user_data
61 .as_ref()
62 .and_then(|user_data| user_data.lsp.as_ref().and_then(|lsp| lsp.code.as_deref()))
63 .or(diag.code.as_deref())
64}
65
66#[derive(Debug, Deserialize)]
68pub struct Diagnostic {
69 code: Option<String>,
71 message: Option<String>,
73 source: Option<String>,
75 user_data: Option<UserData>,
77}
78
79impl FromObject for Diagnostic {
81 fn from_object(obj: Object) -> Result<Self, nvim_oxi::conversion::Error> {
82 Self::deserialize(Deserializer::new(obj)).map_err(Into::into)
83 }
84}
85
86impl Poppable for Diagnostic {
88 unsafe fn pop(lstate: *mut State) -> Result<Self, nvim_oxi::lua::Error> {
89 unsafe {
90 let obj = Object::pop(lstate)?;
91 Self::from_object(obj).map_err(nvim_oxi::lua::Error::pop_error_from_err::<Self, _>)
92 }
93 }
94}
95
96#[derive(Debug, Deserialize)]
98pub struct UserData {
99 lsp: Option<Lsp>,
101}
102
103#[derive(Debug, Deserialize)]
105pub struct Lsp {
106 code: Option<String>,
108 data: Option<LspData>,
110 message: Option<String>,
112 source: Option<String>,
114}
115
116#[derive(Debug, Deserialize)]
118pub struct LspData {
119 rendered: Option<String>,
120}