ricecoder-lsp

Crates.ioricecoder-lsp
lib.rsricecoder-lsp
version0.1.71
created_at2025-12-09 19:07:46.151742+00
updated_at2025-12-09 19:07:46.151742+00
descriptionLanguage Server Protocol integration for RiceCoder
homepagehttps://github.com/moabualruz/ricecoder
repositoryhttps://github.com/moabualruz/ricecoder
max_upload_size
id1976042
size496,088
Moh'd Khier Abualruz (moabualruz)

documentation

https://github.com/moabualruz/ricecoder/wiki

README

RiceCoder LSP Integration

Language Server Protocol (LSP) integration for RiceCoder, providing semantic code analysis, diagnostics, code actions, and hover information across multiple programming languages.

Overview

The ricecoder-lsp crate implements a Language Server Protocol server that enables semantic understanding of code. It provides:

  • Semantic Analysis: Parse and analyze code structure for Rust, TypeScript, and Python
  • Diagnostics: Generate errors, warnings, and hints for code issues
  • Code Actions: Suggest fixes and refactorings for identified issues
  • Hover Information: Display type information and documentation on hover
  • Multi-Language Support: Extensible architecture for adding new languages
  • Performance Optimization: Caching and performance tracking for efficient analysis

Features

Supported Languages

  • Rust: Full semantic analysis with tree-sitter
  • TypeScript: Full semantic analysis with tree-sitter
  • Python: Full semantic analysis with tree-sitter
  • Unknown Languages: Graceful degradation with basic analysis

Core Capabilities

  • Symbol Extraction: Extract functions, types, variables, classes, and other symbols
  • Import Tracking: Track dependencies and imports
  • Diagnostic Generation: Identify syntax errors, style issues, and potential bugs
  • Code Actions: Suggest fixes for common issues
  • Hover Information: Display type information and documentation
  • Caching: Cache parsed ASTs and symbol indexes for performance
  • Performance Tracking: Monitor analysis time and resource usage

Architecture

┌─────────────────────────────────────────────────────────────┐
│                    LSP Client (IDE)                         │
└────────────────────────┬────────────────────────────────────┘
                         │ LSP Protocol (JSON-RPC)
                         │
┌────────────────────────▼────────────────────────────────────┐
│                  LSP Server (ricecoder-lsp)                 │
│  ┌──────────────────────────────────────────────────────┐  │
│  │              LSP Protocol Handler                     │  │
│  │  - Initialize/Shutdown                               │  │
│  │  - Document Synchronization                          │  │
│  │  - Request Routing                                   │  │
│  └──────────────────────────────────────────────────────┘  │
│  ┌──────────────────────────────────────────────────────┐  │
│  │           Semantic Analysis Engine                    │  │
│  │  ┌────────────────┐  ┌────────────────┐              │  │
│  │  │  AST Parser    │  │  Symbol Index  │              │  │
│  │  │  - Rust        │  │  - Lookup      │              │  │
│  │  │  - TypeScript  │  │  - References  │              │  │
│  │  │  - Python      │  │  - Definitions │              │  │
│  │  └────────────────┘  └────────────────┘              │  │
│  └──────────────────────────────────────────────────────┘  │
│  ┌──────────────────────────────────────────────────────┐  │
│  │           Diagnostics & Code Actions                 │  │
│  │  - Issue Detection                                   │  │
│  │  - Fix Suggestions                                   │  │
│  │  - Code Transformations                              │  │
│  └──────────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────────┘

API Documentation

LSP Server Interface

The main entry point for LSP functionality is the LspServer struct:

use ricecoder_lsp::LspServer;

// Create a new LSP server
let mut server = LspServer::new();

// Run the server (handles stdio communication)
server.run().await?;

Key Methods:

  • new(): Create a new LSP server instance
  • run(): Start the server and handle client requests
  • state(): Get the current server state (Initializing, Running, Shutdown)

Server Capabilities:

  • Text document synchronization (full sync)
  • Hover information
  • Code actions
  • Diagnostics

Semantic Analyzer Interface

The SemanticAnalyzer trait provides language-agnostic semantic analysis:

use ricecoder_lsp::semantic::{SemanticAnalyzer, RustAnalyzer};
use ricecoder_lsp::types::Language;

// Create a Rust analyzer
let analyzer = RustAnalyzer::new();

// Analyze code
let semantic_info = analyzer.analyze(code)?;

// Extract symbols
let symbols = analyzer.extract_symbols(code)?;

// Get hover information
let hover = analyzer.get_hover_info(code, position)?;

Supported Analyzers:

  • RustAnalyzer: Rust code analysis
  • TypeScriptAnalyzer: TypeScript code analysis
  • PythonAnalyzer: Python code analysis
  • FallbackAnalyzer: Fallback for unknown languages

Key Methods:

  • analyze(code: &str): Analyze code and extract semantic information
  • extract_symbols(code: &str): Extract all symbols from code
  • get_hover_info(code: &str, position: Position): Get hover information at a position
  • language(): Get the supported language

Diagnostics Engine Interface

The DiagnosticsEngine trait generates diagnostics for code issues:

use ricecoder_lsp::diagnostics::{DiagnosticsEngine, DefaultDiagnosticsEngine};
use ricecoder_lsp::types::Language;

// Create a diagnostics engine
let engine = DefaultDiagnosticsEngine::new();

// Generate diagnostics
let diagnostics = engine.generate_diagnostics(code, Language::Rust)?;

// Generate diagnostics for a specific range
let range_diagnostics = engine.generate_diagnostics_for_range(
    code,
    Language::Rust,
    range,
)?;

Key Methods:

  • generate_diagnostics(code: &str, language: Language): Generate all diagnostics
  • generate_diagnostics_for_range(code: &str, language: Language, range: Range): Generate diagnostics for a specific range

Diagnostic Severity Levels:

  • Error: Critical issues that prevent compilation
  • Warning: Potential issues that should be addressed
  • Hint: Style suggestions and improvements

Code Actions Engine Interface

The CodeActionsEngine trait suggests fixes for identified issues:

use ricecoder_lsp::code_actions::{CodeActionsEngine, DefaultCodeActionsEngine};

// Create a code actions engine
let engine = DefaultCodeActionsEngine::new();

// Get code actions for a diagnostic
let actions = engine.code_actions_for_diagnostic(diagnostic)?;

// Apply a code action
let fixed_code = engine.apply_code_action(code, action)?;

Key Methods:

  • code_actions_for_diagnostic(diagnostic: &Diagnostic): Get applicable code actions
  • apply_code_action(code: &str, action: &CodeAction): Apply a code action to code

Hover Provider Interface

The HoverProvider trait provides hover information:

use ricecoder_lsp::hover::HoverProvider;
use ricecoder_lsp::types::Position;

// Create a hover provider
let provider = HoverProvider::new();

// Get hover information
let hover = provider.hover_at(code, position)?;

Key Methods:

  • hover_at(code: &str, position: Position): Get hover information at a position

Usage Examples

Example 1: Basic Semantic Analysis

use ricecoder_lsp::semantic::{SemanticAnalyzer, RustAnalyzer};

let code = r#"
fn hello(name: &str) {
    println!("Hello, {}", name);
}
"#;

let analyzer = RustAnalyzer::new();
let semantic_info = analyzer.analyze(code)?;

println!("Symbols: {:?}", semantic_info.symbols);
println!("Imports: {:?}", semantic_info.imports);

Example 2: Generating Diagnostics

use ricecoder_lsp::diagnostics::DefaultDiagnosticsEngine;
use ricecoder_lsp::types::Language;

let code = r#"
fn unused_function() {
    let unused_var = 42;
}
"#;

let engine = DefaultDiagnosticsEngine::new();
let diagnostics = engine.generate_diagnostics(code, Language::Rust)?;

for diagnostic in diagnostics {
    println!("{}: {}", diagnostic.severity, diagnostic.message);
}

Example 3: Getting Hover Information

use ricecoder_lsp::hover::HoverProvider;
use ricecoder_lsp::types::Position;

let code = r#"
let x: i32 = 42;
"#;

let provider = HoverProvider::new();
let hover = provider.hover_at(code, Position { line: 0, character: 4 })?;

if let Some(info) = hover {
    println!("Type: {}", info.contents);
}

Example 4: Applying Code Actions

use ricecoder_lsp::code_actions::DefaultCodeActionsEngine;
use ricecoder_lsp::diagnostics::DefaultDiagnosticsEngine;
use ricecoder_lsp::types::Language;

let code = r#"
use std::collections::HashMap;

fn main() {
    println!("Hello");
}
"#;

let diagnostics_engine = DefaultDiagnosticsEngine::new();
let diagnostics = diagnostics_engine.generate_diagnostics(code, Language::Rust)?;

let actions_engine = DefaultCodeActionsEngine::new();
for diagnostic in diagnostics {
    let actions = actions_engine.code_actions_for_diagnostic(&diagnostic)?;
    for action in actions {
        let fixed = actions_engine.apply_code_action(code, &action)?;
        println!("Fixed code:\n{}", fixed);
    }
}

Configuration

The LSP server can be configured via environment variables:

  • RICECODER_LSP_LOG_LEVEL: Set logging level (trace, debug, info, warn, error)
  • RICECODER_LSP_CACHE_SIZE: Set cache size in MB (default: 100)
  • RICECODER_LSP_TIMEOUT_MS: Set analysis timeout in milliseconds (default: 5000)

Performance

The LSP server is optimized for performance:

  • Caching: Parsed ASTs and symbol indexes are cached for unchanged documents
  • Incremental Analysis: Only re-analyze changed portions of code
  • Performance Targets:
    • < 500ms for files < 10KB
    • < 2s for files < 100KB
    • < 100ms for cached results

Error Handling

All operations return explicit error types:

use ricecoder_lsp::semantic::SemanticError;

match analyzer.analyze(code) {
    Ok(info) => println!("Analysis successful"),
    Err(SemanticError::ParseError(msg)) => eprintln!("Parse error: {}", msg),
    Err(SemanticError::UnsupportedLanguage(lang)) => eprintln!("Unsupported: {:?}", lang),
    Err(e) => eprintln!("Error: {}", e),
}

Testing

The crate includes comprehensive tests:

  • Unit Tests: Test individual components (analyzers, engines, providers)
  • Integration Tests: Test end-to-end LSP workflows
  • Property Tests: Verify correctness properties across all inputs

Run tests with:

cargo test --lib
cargo test --test '*'
cargo test --test '*properties*'

Troubleshooting

Issue: Analysis is slow

Solution: Check cache hit rates and increase cache size if needed.

RICECODER_LSP_CACHE_SIZE=200 cargo run

Issue: Unsupported language errors

Solution: The crate gracefully degrades for unsupported languages. Check logs for details.

RICECODER_LSP_LOG_LEVEL=debug cargo run

Issue: Diagnostics are missing

Solution: Ensure the language is correctly detected. Check language-specific rules.

let language = Language::from_extension(path);
println!("Detected language: {:?}", language);

Contributing

When adding new features:

  1. Add language-specific analyzers in src/semantic/
  2. Add diagnostic rules in src/diagnostics/
  3. Add code actions in src/code_actions/
  4. Add tests in tests/
  5. Update this README with examples

Related Documentation

License

Part of the RiceCoder project. See LICENSE for details.

Commit count: 0

cargo fmt