coderlib 0.1.0

A Rust library for AI-powered code assistance and agentic system
Documentation
//! LSP types and error definitions

use std::path::PathBuf;
use serde::{Deserialize, Serialize};

/// LSP-specific errors
#[derive(Debug, thiserror::Error)]
pub enum LspError {
    #[error("LSP server not found for file type: {0}")]
    ServerNotFound(String),
    
    #[error("LSP server failed to start: {0}")]
    ServerStartFailed(String),
    
    #[error("LSP communication error: {0}")]
    CommunicationError(String),
    
    #[error("LSP server timeout: {0}")]
    Timeout(String),
    
    #[error("LSP server not initialized")]
    NotInitialized,
    
    #[error("Invalid LSP response: {0}")]
    InvalidResponse(String),
    
    #[error("IO error: {0}")]
    Io(#[from] std::io::Error),
    
    #[error("JSON error: {0}")]
    Json(#[from] serde_json::Error),
    
    #[error("Tower LSP error: {0}")]
    TowerLsp(String),

    #[error("File not open: {0}")]
    FileNotOpen(PathBuf),
}

/// Simplified diagnostic information from LSP
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LspDiagnostic {
    /// File path
    pub file_path: PathBuf,
    
    /// Line number (0-based)
    pub line: u32,
    
    /// Column number (0-based)
    pub column: u32,
    
    /// End line (0-based)
    pub end_line: u32,
    
    /// End column (0-based)
    pub end_column: u32,
    
    /// Diagnostic message
    pub message: String,
    
    /// Severity level
    pub severity: DiagnosticSeverity,
    
    /// Diagnostic source (e.g., "rust-analyzer", "gopls")
    pub source: Option<String>,
    
    /// Error code if available
    pub code: Option<String>,
}

/// Diagnostic severity levels
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum DiagnosticSeverity {
    Error,
    Warning,
    Information,
    Hint,
}

impl std::fmt::Display for DiagnosticSeverity {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            DiagnosticSeverity::Error => write!(f, "ERROR"),
            DiagnosticSeverity::Warning => write!(f, "WARNING"),
            DiagnosticSeverity::Information => write!(f, "INFO"),
            DiagnosticSeverity::Hint => write!(f, "HINT"),
        }
    }
}

impl From<lsp_types::DiagnosticSeverity> for DiagnosticSeverity {
    fn from(severity: lsp_types::DiagnosticSeverity) -> Self {
        match severity {
            lsp_types::DiagnosticSeverity::ERROR => DiagnosticSeverity::Error,
            lsp_types::DiagnosticSeverity::WARNING => DiagnosticSeverity::Warning,
            lsp_types::DiagnosticSeverity::INFORMATION => DiagnosticSeverity::Information,
            lsp_types::DiagnosticSeverity::HINT => DiagnosticSeverity::Hint,
            _ => DiagnosticSeverity::Error, // Default to error for unknown severities
        }
    }
}

/// Position in a text document
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub struct Position {
    pub line: u32,
    pub character: u32,
}

/// Range in a text document
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub struct Range {
    pub start: Position,
    pub end: Position,
}

/// Location in a text document
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Location {
    pub file_path: PathBuf,
    pub range: Range,
}

/// Completion item from LSP
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CompletionItem {
    pub label: String,
    pub kind: Option<CompletionItemKind>,
    pub detail: Option<String>,
    pub documentation: Option<String>,
    pub insert_text: Option<String>,
    pub filter_text: Option<String>,
    pub sort_text: Option<String>,
}

/// Completion item kind
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum CompletionItemKind {
    Text,
    Method,
    Function,
    Constructor,
    Field,
    Variable,
    Class,
    Interface,
    Module,
    Property,
    Unit,
    Value,
    Enum,
    Keyword,
    Snippet,
    Color,
    File,
    Reference,
    Folder,
    EnumMember,
    Constant,
    Struct,
    Event,
    Operator,
    TypeParameter,
}

/// Hover information
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Hover {
    pub contents: String,
    pub range: Option<Range>,
}

/// Code action from LSP
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CodeAction {
    pub title: String,
    pub kind: Option<String>,
    pub diagnostics: Vec<LspDiagnostic>,
    pub is_preferred: bool,
    pub disabled: Option<String>,
}

/// Symbol information
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SymbolInformation {
    pub name: String,
    pub kind: SymbolKind,
    pub location: Location,
    pub container_name: Option<String>,
}

/// Symbol kind
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum SymbolKind {
    File,
    Module,
    Namespace,
    Package,
    Class,
    Method,
    Property,
    Field,
    Constructor,
    Enum,
    Interface,
    Function,
    Variable,
    Constant,
    String,
    Number,
    Boolean,
    Array,
    Object,
    Key,
    Null,
    EnumMember,
    Struct,
    Event,
    Operator,
    TypeParameter,
}

// Conversion implementations
impl From<lsp_types::Position> for Position {
    fn from(pos: lsp_types::Position) -> Self {
        Self {
            line: pos.line,
            character: pos.character,
        }
    }
}

impl From<Position> for lsp_types::Position {
    fn from(pos: Position) -> Self {
        Self {
            line: pos.line,
            character: pos.character,
        }
    }
}

impl From<lsp_types::Range> for Range {
    fn from(range: lsp_types::Range) -> Self {
        Self {
            start: range.start.into(),
            end: range.end.into(),
        }
    }
}

impl From<Range> for lsp_types::Range {
    fn from(range: Range) -> Self {
        Self {
            start: range.start.into(),
            end: range.end.into(),
        }
    }
}

impl From<lsp_types::CompletionItemKind> for CompletionItemKind {
    fn from(kind: lsp_types::CompletionItemKind) -> Self {
        match kind {
            lsp_types::CompletionItemKind::TEXT => CompletionItemKind::Text,
            lsp_types::CompletionItemKind::METHOD => CompletionItemKind::Method,
            lsp_types::CompletionItemKind::FUNCTION => CompletionItemKind::Function,
            lsp_types::CompletionItemKind::CONSTRUCTOR => CompletionItemKind::Constructor,
            lsp_types::CompletionItemKind::FIELD => CompletionItemKind::Field,
            lsp_types::CompletionItemKind::VARIABLE => CompletionItemKind::Variable,
            lsp_types::CompletionItemKind::CLASS => CompletionItemKind::Class,
            lsp_types::CompletionItemKind::INTERFACE => CompletionItemKind::Interface,
            lsp_types::CompletionItemKind::MODULE => CompletionItemKind::Module,
            lsp_types::CompletionItemKind::PROPERTY => CompletionItemKind::Property,
            lsp_types::CompletionItemKind::UNIT => CompletionItemKind::Unit,
            lsp_types::CompletionItemKind::VALUE => CompletionItemKind::Value,
            lsp_types::CompletionItemKind::ENUM => CompletionItemKind::Enum,
            lsp_types::CompletionItemKind::KEYWORD => CompletionItemKind::Keyword,
            lsp_types::CompletionItemKind::SNIPPET => CompletionItemKind::Snippet,
            lsp_types::CompletionItemKind::COLOR => CompletionItemKind::Color,
            lsp_types::CompletionItemKind::FILE => CompletionItemKind::File,
            lsp_types::CompletionItemKind::REFERENCE => CompletionItemKind::Reference,
            lsp_types::CompletionItemKind::FOLDER => CompletionItemKind::Folder,
            lsp_types::CompletionItemKind::ENUM_MEMBER => CompletionItemKind::EnumMember,
            lsp_types::CompletionItemKind::CONSTANT => CompletionItemKind::Constant,
            lsp_types::CompletionItemKind::STRUCT => CompletionItemKind::Struct,
            lsp_types::CompletionItemKind::EVENT => CompletionItemKind::Event,
            lsp_types::CompletionItemKind::OPERATOR => CompletionItemKind::Operator,
            lsp_types::CompletionItemKind::TYPE_PARAMETER => CompletionItemKind::TypeParameter,
            _ => CompletionItemKind::Text, // Default fallback
        }
    }
}

impl From<lsp_types::SymbolKind> for SymbolKind {
    fn from(kind: lsp_types::SymbolKind) -> Self {
        match kind {
            lsp_types::SymbolKind::FILE => SymbolKind::File,
            lsp_types::SymbolKind::MODULE => SymbolKind::Module,
            lsp_types::SymbolKind::NAMESPACE => SymbolKind::Namespace,
            lsp_types::SymbolKind::PACKAGE => SymbolKind::Package,
            lsp_types::SymbolKind::CLASS => SymbolKind::Class,
            lsp_types::SymbolKind::METHOD => SymbolKind::Method,
            lsp_types::SymbolKind::PROPERTY => SymbolKind::Property,
            lsp_types::SymbolKind::FIELD => SymbolKind::Field,
            lsp_types::SymbolKind::CONSTRUCTOR => SymbolKind::Constructor,
            lsp_types::SymbolKind::ENUM => SymbolKind::Enum,
            lsp_types::SymbolKind::INTERFACE => SymbolKind::Interface,
            lsp_types::SymbolKind::FUNCTION => SymbolKind::Function,
            lsp_types::SymbolKind::VARIABLE => SymbolKind::Variable,
            lsp_types::SymbolKind::CONSTANT => SymbolKind::Constant,
            lsp_types::SymbolKind::STRING => SymbolKind::String,
            lsp_types::SymbolKind::NUMBER => SymbolKind::Number,
            lsp_types::SymbolKind::BOOLEAN => SymbolKind::Boolean,
            lsp_types::SymbolKind::ARRAY => SymbolKind::Array,
            lsp_types::SymbolKind::OBJECT => SymbolKind::Object,
            lsp_types::SymbolKind::KEY => SymbolKind::Key,
            lsp_types::SymbolKind::NULL => SymbolKind::Null,
            lsp_types::SymbolKind::ENUM_MEMBER => SymbolKind::EnumMember,
            lsp_types::SymbolKind::STRUCT => SymbolKind::Struct,
            lsp_types::SymbolKind::EVENT => SymbolKind::Event,
            lsp_types::SymbolKind::OPERATOR => SymbolKind::Operator,
            lsp_types::SymbolKind::TYPE_PARAMETER => SymbolKind::TypeParameter,
            _ => SymbolKind::File, // Default fallback
        }
    }
}

impl From<lsp_types::Diagnostic> for LspDiagnostic {
    fn from(diagnostic: lsp_types::Diagnostic) -> Self {
        Self {
            file_path: PathBuf::new(), // Will be set by caller
            line: diagnostic.range.start.line,
            column: diagnostic.range.start.character,
            end_line: diagnostic.range.end.line,
            end_column: diagnostic.range.end.character,
            message: diagnostic.message,
            severity: diagnostic.severity
                .map(DiagnosticSeverity::from)
                .unwrap_or(DiagnosticSeverity::Error),
            source: diagnostic.source,
            code: diagnostic.code.and_then(|c| match c {
                lsp_types::NumberOrString::Number(n) => Some(n.to_string()),
                lsp_types::NumberOrString::String(s) => Some(s),
            }),
        }
    }
}

impl LspDiagnostic {
    /// Format diagnostic for display
    pub fn format(&self) -> String {
        let severity_str = match self.severity {
            DiagnosticSeverity::Error => "ERROR",
            DiagnosticSeverity::Warning => "WARNING",
            DiagnosticSeverity::Information => "INFO",
            DiagnosticSeverity::Hint => "HINT",
        };
        
        let location = format!("{}:{}:{}", 
            self.file_path.display(), 
            self.line + 1, 
            self.column + 1
        );
        
        let source_info = self.source.as_ref()
            .map(|s| format!(" [{}]", s))
            .unwrap_or_default();
        
        format!("{} {}{}: {}", severity_str, location, source_info, self.message)
    }
    
    /// Check if this is an error-level diagnostic
    pub fn is_error(&self) -> bool {
        self.severity == DiagnosticSeverity::Error
    }
    
    /// Check if this is a warning-level diagnostic
    pub fn is_warning(&self) -> bool {
        self.severity == DiagnosticSeverity::Warning
    }
}