-
-
Notifications
You must be signed in to change notification settings - Fork 0
Description
Goal
Create a Language Server Protocol implementation for LUMOS to enable IDE features (auto-completion, diagnostics, hover info) across multiple editors.
Phase: 5.2 IDE Integration
Foundation Issue: Enables multi-editor support
Problem
Currently:
- ❌ IDE features only in VSCode extension (limited to one editor)
- ❌ Duplicated logic needed for each editor plugin
- ❌ No standardized way to provide language intelligence
- ❌ Other editors (IntelliJ, Neovim, Emacs) have no LUMOS support
Solution
Implement LSP server that provides language features to any LSP-compatible editor.
What is LSP?
Language Server Protocol standardizes communication between editors and language tooling:
- One LSP server → Works with all editors
- Developed by Microsoft, industry standard
- Supported by VS Code, IntelliJ, Neovim, Emacs, Sublime, etc.
Features to Implement
1. Diagnostics (Errors & Warnings)
- Syntax errors (red squiggles)
- Undefined type references
- Invalid attribute usage
- Version format errors
2. Auto-Completion
- Solana types (
PublicKey,Signature) - Primitive types (
u8-u128,i8-i128,bool) - Complex types (
Vec,Option) - Attributes (
#[solana],#[account],#[version])
3. Hover Information
- Type definitions
- Field documentation
- Attribute explanations
4. Go to Definition
- Jump to struct/enum definition
- Jump to field type definition
5. Code Actions (Quick Fixes)
- Add missing
#[solana]attribute - Fix undefined type references
- Convert between
Vecand arrays
6. Document Symbols
- Outline view (list of structs/enums)
- Symbol search
7. Formatting
- Auto-format on save
- Consistent indentation
Implementation
Technology Stack
Rust crates:
tower-lsp- LSP server frameworktokio- Async runtimeserde_json- JSON-RPC communication
Architecture
Editor (VS Code, Neovim, etc.)
↕ JSON-RPC (LSP)
LUMOS Language Server
↓
LUMOS Parser (existing)
↓
AST Analysis
Project Structure
packages/
└── lsp/
├── Cargo.toml
├── src/
│ ├── main.rs # Binary entry point
│ ├── server.rs # LSP server implementation
│ ├── handlers/
│ │ ├── diagnostics.rs
│ │ ├── completion.rs
│ │ ├── hover.rs
│ │ └── formatting.rs
│ └── utils.rs
└── tests/
Core Server Implementation
Location: packages/lsp/src/server.rs
use tower_lsp::jsonrpc::Result;
use tower_lsp::lsp_types::*;
use tower_lsp::{Client, LanguageServer, LspService, Server};
#[derive(Debug)]
struct LumosLanguageServer {
client: Client,
}
#[tower_lsp::async_trait]
impl LanguageServer for LumosLanguageServer {
async fn initialize(&self, _: InitializeParams) -> Result<InitializeResult> {
Ok(InitializeResult {
capabilities: ServerCapabilities {
text_document_sync: Some(TextDocumentSyncCapability::Kind(
TextDocumentSyncKind::FULL,
)),
completion_provider: Some(CompletionOptions::default()),
hover_provider: Some(HoverProviderCapability::Simple(true)),
diagnostic_provider: Some(DiagnosticServerCapabilities::Options(
DiagnosticOptions::default(),
)),
// ... more capabilities
..Default::default()
},
..Default::default()
})
}
async fn initialized(&self, _: InitializedParams) {
self.client
.log_message(MessageType::INFO, "LUMOS Language Server initialized")
.await;
}
async fn shutdown(&self) -> Result<()> {
Ok(())
}
async fn did_open(&self, params: DidOpenTextDocumentParams) {
self.on_change(params.text_document).await;
}
async fn did_change(&self, params: DidChangeTextDocumentParams) {
self.on_change(params.text_document).await;
}
async fn completion(&self, params: CompletionParams) -> Result<Option<CompletionResponse>> {
// Implementation
}
async fn hover(&self, params: HoverParams) -> Result<Option<Hover>> {
// Implementation
}
}LSP Features Implementation
1. Diagnostics
async fn on_change(&self, text_document: TextDocumentItem) {
let uri = text_document.uri;
let text = text_document.text;
// Parse LUMOS schema
match parse_schema(&text) {
Ok(_) => {
// Clear diagnostics
self.client.publish_diagnostics(uri, vec\![], None).await;
}
Err(errors) => {
let diagnostics: Vec<Diagnostic> = errors.iter().map(|e| {
Diagnostic {
range: e.span.to_lsp_range(),
severity: Some(DiagnosticSeverity::ERROR),
message: e.message.clone(),
source: Some("lumos".to_string()),
..Default::default()
}
}).collect();
self.client.publish_diagnostics(uri, diagnostics, None).await;
}
}
}2. Auto-Completion
async fn completion(&self, params: CompletionParams) -> Result<Option<CompletionResponse>> {
let items = vec\![
CompletionItem {
label: "PublicKey".to_string(),
kind: Some(CompletionItemKind::STRUCT),
detail: Some("Solana public key (32 bytes)".to_string()),
..Default::default()
},
CompletionItem {
label: "u64".to_string(),
kind: Some(CompletionItemKind::KEYWORD),
detail: Some("64-bit unsigned integer".to_string()),
..Default::default()
},
// ... more items
];
Ok(Some(CompletionResponse::Array(items)))
}3. Hover Information
async fn hover(&self, params: HoverParams) -> Result<Option<Hover>> {
// Get word at cursor position
let word = get_word_at_position(params.text_document_position_params);
let hover_text = match word.as_str() {
"PublicKey" => "Solana public key (32 bytes)\nUsed for account addresses",
"u64" => "64-bit unsigned integer\nRange: 0 to 18,446,744,073,709,551,615",
// ... more cases
_ => return Ok(None),
};
Ok(Some(Hover {
contents: HoverContents::Scalar(MarkedString::String(hover_text.to_string())),
range: None,
}))
}Binary Distribution
Install as CLI
cargo install lumos-lspUsage
Start server (typically called by editor):
lumos-lspWith custom options:
lumos-lsp --stdio --log-level debugEditor Configuration
VS Code
Update existing extension to use LSP:
{
"contributes": {
"configuration": {
"properties": {
"lumos.lsp.path": {
"type": "string",
"default": "lumos-lsp",
"description": "Path to LUMOS language server"
}
}
}
}
}Neovim (nvim-lspconfig)
require'lspconfig'.lumos.setup{
cmd = {"lumos-lsp"},
filetypes = {"lumos"},
root_dir = require'lspconfig'.util.root_pattern(".git"),
}Emacs (lsp-mode)
(add-to-list 'lsp-language-id-configuration '(lumos-mode . "lumos"))
(lsp-register-client
(make-lsp-client :new-connection (lsp-stdio-connection "lumos-lsp")
:major-modes '(lumos-mode)
:server-id 'lumos-lsp))Testing
Unit Tests
#[tokio::test]
async fn test_diagnostics_on_syntax_error() {
let server = create_test_server();
let text = "struct Player { invalid syntax }";
let diagnostics = server.analyze(text).await;
assert\!(\!diagnostics.is_empty());
}
#[tokio::test]
async fn test_completion_includes_solana_types() {
let server = create_test_server();
let completions = server.get_completions(Position::new(0, 0)).await;
assert\!(completions.iter().any(|c| c.label == "PublicKey"));
}Integration Tests
- Start LSP server
- Send LSP requests (via JSON-RPC)
- Verify responses match LSP spec
- Test all features (diagnostics, completion, hover)
Success Criteria
- LSP server binary compiles and runs
- Implements core LSP features (diagnostics, completion, hover)
- Works with VS Code
- Works with Neovim
- Works with at least one more editor (Emacs or IntelliJ)
- Real-time diagnostics on file changes
- Auto-completion for Solana and primitive types
- Hover information for types and attributes
- Published as
lumos-lspon crates.io - All tests passing
- Documentation for editor setup
Documentation
Create New Files
-
packages/lsp/README.md- LSP server documentation -
docs/editors/setup.md- Editor configuration guide -
docs/editors/vscode.md- VS Code setup -
docs/editors/neovim.md- Neovim setup -
docs/editors/emacs.md- Emacs setup
Update Files
-
README.md- Add LSP installation instructions -
CHANGELOG.md- Document LSP release
Benefits
✅ Universal Support: One server, all editors
✅ Maintainability: Single codebase for language features
✅ Consistency: Same features across editors
✅ Scalability: Easy to add new editors
✅ Standard Protocol: Industry-standard LSP
Related
- Enables: Implement Language Server Protocol (LSP) for LUMOS #45 (IntelliJ plugin), Create IntelliJ IDEA / Rust Rover plugin for LUMOS #46 (Neovim), Create Neovim plugin with Tree-sitter grammar for LUMOS #47 (Emacs), Create Emacs mode for LUMOS #48 (Sublime)
- ROADMAP.md Phase 5.2 - IDE Integration
Priority: High (foundation for IDE support)
Complexity: High
Timeline: 7-10 days
Blocks: All other Phase 5.2 features