From d8a13a37f0715d3063f947f60533ae29c260104c Mon Sep 17 00:00:00 2001 From: S-H-GAMELINKS Date: Tue, 30 Dec 2025 13:19:46 +0900 Subject: [PATCH] Introduce Kanayago LSP that provides real-time Ruby syntax checking Kanayago is a Ruby Language Server Protocol (LSP) implementation that provides: - Real-time Ruby syntax checking based on parse.y AST - AST-based Ruby code analysis - A lightweight LSP implementation written entirely in Ruby Users need to have the `kanayago` command available in their PATH: ```bash gem install kanayago ``` --- extension.toml | 4 +++ src/language_servers/kanayago.rs | 43 ++++++++++++++++++++++++++++++++ src/language_servers/mod.rs | 2 ++ src/ruby.rs | 7 +++++- 4 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 src/language_servers/kanayago.rs diff --git a/extension.toml b/extension.toml index 9c21154..cb94210 100644 --- a/extension.toml +++ b/extension.toml @@ -38,6 +38,10 @@ languages = ["Ruby"] name = "Herb" languages = ["HTML+ERB"] +[language_servers.kanayago] +name = "Kanayago" +languages = ["Ruby"] + [grammars.ruby] repository = "https://github.com/tree-sitter/tree-sitter-ruby" commit = "71bd32fb7607035768799732addba884a37a6210" diff --git a/src/language_servers/kanayago.rs b/src/language_servers/kanayago.rs new file mode 100644 index 0000000..a4a2071 --- /dev/null +++ b/src/language_servers/kanayago.rs @@ -0,0 +1,43 @@ +use super::{language_server::WorktreeLike, LanguageServer}; + +pub struct Kanayago {} + + +impl LanguageServer for Kanayago { + const SERVER_ID: &str = "kanayago"; + const EXECUTABLE_NAME: &str = "kanayago"; + const GEM_NAME: &str = "kanayago"; + + fn get_executable_args(&self, _worktree: &T) -> Vec { + vec!["--lsp".to_string()] + } +} + +impl Kanayago { + pub fn new() -> Self { + Self {} + } +} + +#[cfg(test)] +mod tests { + use crate::language_servers::{language_server::FakeWorktree, LanguageServer, Kanayago}; + + #[test] + fn test_server_id() { + assert_eq!(Kanayago::SERVER_ID, "kanayago"); + } + + #[test] + fn test_executable_name() { + assert_eq!(Kanayago::EXECUTABLE_NAME, "kanayago"); + } + + #[test] + fn test_executable_args() { + let kanayago = Kanayago::new(); + let mock_worktree = FakeWorktree::new("/path/to/project".to_string()); + + assert_eq!(kanayago.get_executable_args(&mock_worktree), vec!["--lsp"]); + } +} diff --git a/src/language_servers/mod.rs b/src/language_servers/mod.rs index 57d7184..7f13ddd 100644 --- a/src/language_servers/mod.rs +++ b/src/language_servers/mod.rs @@ -1,3 +1,4 @@ +mod kanayago; mod herb; mod language_server; mod rubocop; @@ -6,6 +7,7 @@ mod solargraph; mod sorbet; mod steep; +pub use kanayago::Kanayago; pub use herb::Herb; pub use language_server::LanguageServer; pub use rubocop::Rubocop; diff --git a/src/ruby.rs b/src/ruby.rs index e1b1a70..bc48b69 100644 --- a/src/ruby.rs +++ b/src/ruby.rs @@ -8,7 +8,7 @@ use std::{collections::HashMap, path::PathBuf}; use bundler::Bundler; use command_executor::RealCommandExecutor; use gemset::Gemset; -use language_servers::{Herb, LanguageServer, Rubocop, RubyLsp, Solargraph, Sorbet, Steep}; +use language_servers::{Kanayago, Herb, LanguageServer, Rubocop, RubyLsp, Solargraph, Sorbet, Steep}; use serde::{Deserialize, Serialize}; use zed_extension_api::{ self as zed, resolve_tcp_template, DebugAdapterBinary, DebugConfig, DebugRequest, @@ -24,6 +24,7 @@ struct RubyExtension { sorbet: Option, steep: Option, herb: Option, + kanayago: Option, } #[derive(Serialize, Deserialize)] @@ -73,6 +74,10 @@ impl zed::Extension for RubyExtension { let herb = self.herb.get_or_insert_with(Herb::new); herb.language_server_command(language_server_id, worktree) } + Kanayago::SERVER_ID => { + let kanayago = self.kanayago.get_or_insert_with(Kanayago::new); + kanayago.language_server_command(language_server_id, worktree) + } language_server_id => Err(format!("unknown language server: {language_server_id}")), } }