use std::collections::HashMap;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DiagnosticSeverity {
Error,
Warning,
Info,
Hint,
}
impl DiagnosticSeverity {
pub fn from_lsp(severity: Option<u32>) -> Self {
match severity.unwrap_or(1) {
1 => DiagnosticSeverity::Error,
2 => DiagnosticSeverity::Warning,
3 => DiagnosticSeverity::Info,
4 => DiagnosticSeverity::Hint,
_ => DiagnosticSeverity::Error,
}
}
}
#[derive(Debug, Clone)]
pub struct LspRange {
pub start: LspPosition,
pub end: LspPosition,
}
#[derive(Debug, Clone)]
pub struct LspPosition {
pub line: u32,
pub character: u32,
}
#[derive(Debug, Clone)]
pub struct LspDiagnostic {
pub message: String,
pub severity: Option<u32>,
pub range: LspRange,
pub source: Option<String>,
pub code: Option<String>,
}
#[derive(Debug, Clone)]
pub struct PublishDiagnosticsParams {
pub uri: String,
pub diagnostics: Vec<LspDiagnostic>,
}
#[derive(Debug, Clone)]
pub struct DiagnosticFile {
pub uri: String,
pub diagnostics: Vec<FormattedDiagnostic>,
}
#[derive(Debug, Clone)]
pub struct FormattedDiagnostic {
pub message: String,
pub severity: String,
pub range: DiagnosticRange,
pub source: Option<String>,
pub code: Option<String>,
}
#[derive(Debug, Clone)]
pub struct DiagnosticRange {
pub start: DiagnosticPosition,
pub end: DiagnosticPosition,
}
#[derive(Debug, Clone)]
pub struct DiagnosticPosition {
pub line: u32,
pub character: u32,
}
pub fn map_lsp_severity_to_string(severity: Option<u32>) -> String {
match DiagnosticSeverity::from_lsp(severity) {
DiagnosticSeverity::Error => "Error".to_string(),
DiagnosticSeverity::Warning => "Warning".to_string(),
DiagnosticSeverity::Info => "Info".to_string(),
DiagnosticSeverity::Hint => "Hint".to_string(),
}
}
pub fn uri_to_file_path(uri: &str) -> String {
if uri.starts_with("file://") {
if let Ok(path) = url::Url::parse(uri) {
if let Ok(file_path) = path.to_file_path() {
return file_path.to_string_lossy().to_string();
}
}
}
uri.to_string()
}
pub fn format_diagnostics_for_attachment(params: PublishDiagnosticsParams) -> Vec<DiagnosticFile> {
let uri = uri_to_file_path(¶ms.uri);
let diagnostics: Vec<FormattedDiagnostic> = params
.diagnostics
.into_iter()
.map(|diag| FormattedDiagnostic {
message: diag.message,
severity: map_lsp_severity_to_string(diag.severity),
range: DiagnosticRange {
start: DiagnosticPosition {
line: diag.range.start.line,
character: diag.range.start.character,
},
end: DiagnosticPosition {
line: diag.range.end.line,
character: diag.range.end.character,
},
},
source: diag.source,
code: diag.code,
})
.collect();
vec![DiagnosticFile { uri, diagnostics }]
}
#[derive(Debug, Clone)]
pub struct HandlerRegistrationResult {
pub total_servers: usize,
pub success_count: usize,
pub registration_errors: Vec<RegistrationError>,
pub diagnostic_failures: HashMap<String, FailureInfo>,
}
#[derive(Debug, Clone)]
pub struct RegistrationError {
pub server_name: String,
pub error: String,
}
#[derive(Debug, Clone)]
pub struct FailureInfo {
pub count: u32,
pub last_error: String,
}
pub fn register_lsp_notification_handlers(
_manager: &dyn LspServerManagerTrait,
) -> HandlerRegistrationResult {
HandlerRegistrationResult {
total_servers: 0,
success_count: 0,
registration_errors: Vec::new(),
diagnostic_failures: HashMap::new(),
}
}
pub trait LspServerManagerTrait {
fn get_all_servers(&self) -> HashMap<String, Box<dyn LspServerInstance>>;
}
pub trait LspServerInstance: Send + Sync {
fn on_notification(&self, method: &str, handler: Box<dyn Fn(serde_json::Value) + Send + Sync>);
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_map_lsp_severity_error() {
assert_eq!(map_lsp_severity_to_string(Some(1)), "Error");
}
#[test]
fn test_map_lsp_severity_warning() {
assert_eq!(map_lsp_severity_to_string(Some(2)), "Warning");
}
#[test]
fn test_map_lsp_severity_info() {
assert_eq!(map_lsp_severity_to_string(Some(3)), "Info");
}
#[test]
fn test_map_lsp_severity_hint() {
assert_eq!(map_lsp_severity_to_string(Some(4)), "Hint");
}
#[test]
fn test_map_lsp_severity_default() {
assert_eq!(map_lsp_severity_to_string(None), "Error");
assert_eq!(map_lsp_severity_to_string(Some(999)), "Error");
}
#[test]
fn test_uri_to_file_path_plain() {
assert_eq!(uri_to_file_path("/some/path/file.rs"), "/some/path/file.rs");
}
}