From 151b8c4658b6b3d72c7b26b560427f056d2361c8 Mon Sep 17 00:00:00 2001 From: "Dhanji R. Prasanna" Date: Tue, 13 Jan 2026 18:44:59 +0530 Subject: [PATCH] Add Racket tree-sitter support, remove Kotlin - Add tree-sitter-racket dependency (v0.24) - Initialize Racket parser in code search - Add .rkt, .rktl, .rktd file extensions - Add test_racket_search test - Remove Kotlin from supported languages (was disabled) - Clean up duplicate test files Supported languages: Rust, Python, JavaScript, TypeScript, Go, Java, C, C++, Racket --- Cargo.lock | 11 ++++++++ crates/g3-core/Cargo.toml | 1 + crates/g3-core/examples/test_code/Example.kt | 24 ------------------ crates/g3-core/src/code_search/searcher.rs | 25 ++++++++++--------- crates/g3-core/src/tool_definitions.rs | 4 +-- crates/g3-core/tests/code_search_test.rs | 23 +++++++++++------ .../test_code/example.rkt | 0 7 files changed, 42 insertions(+), 46 deletions(-) delete mode 100644 crates/g3-core/examples/test_code/Example.kt rename {crates/g3-core/examples => examples}/test_code/example.rkt (100%) diff --git a/Cargo.lock b/Cargo.lock index 3231ec8..038b855 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1453,6 +1453,7 @@ dependencies = [ "tree-sitter-java", "tree-sitter-javascript", "tree-sitter-python", + "tree-sitter-racket", "tree-sitter-rust", "tree-sitter-scheme", "tree-sitter-typescript", @@ -3946,6 +3947,16 @@ dependencies = [ "tree-sitter-language", ] +[[package]] +name = "tree-sitter-racket" +version = "0.24.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8395b6a054e6264c67e1ef915f239c4f86575b7d7c69638bdbf3c336c58f128" +dependencies = [ + "cc", + "tree-sitter-language", +] + [[package]] name = "tree-sitter-rust" version = "0.23.3" diff --git a/crates/g3-core/Cargo.toml b/crates/g3-core/Cargo.toml index ed812c3..63f7272 100644 --- a/crates/g3-core/Cargo.toml +++ b/crates/g3-core/Cargo.toml @@ -40,6 +40,7 @@ tree-sitter-cpp = "0.23" # tree-sitter-kotlin = "0.3" # Temporarily disabled - incompatible with tree-sitter 0.24 tree-sitter-haskell = { git = "https://github.com/tree-sitter/tree-sitter-haskell" } tree-sitter-scheme = "0.24" +tree-sitter-racket = "0.24" streaming-iterator = "0.1" walkdir = "2.4" diff --git a/crates/g3-core/examples/test_code/Example.kt b/crates/g3-core/examples/test_code/Example.kt deleted file mode 100644 index eaae013..0000000 --- a/crates/g3-core/examples/test_code/Example.kt +++ /dev/null @@ -1,24 +0,0 @@ -package com.example - -class Person(val name: String, val age: Int) { - fun greet() { - println("Hello, I'm $name") - } - - fun getAge(): Int { - return age - } -} - -interface Greeter { - fun sayHello() -} - -fun main() { - val person = Person("Alice", 30) - person.greet() -} - -fun add(a: Int, b: Int): Int { - return a + b -} diff --git a/crates/g3-core/src/code_search/searcher.rs b/crates/g3-core/src/code_search/searcher.rs index b38cd72..a7a4e92 100644 --- a/crates/g3-core/src/code_search/searcher.rs +++ b/crates/g3-core/src/code_search/searcher.rs @@ -121,17 +121,6 @@ impl TreeSitterSearcher { languages.insert("cpp".to_string(), language); } - // // Initialize Kotlin - Temporarily disabled due to tree-sitter version incompatibility - // { - // let mut parser = Parser::new(); - // let language: Language = tree_sitter_kotlin::language(); - // parser - // .set_language(&language) - // .map_err(|e| anyhow!("Failed to set Kotlin language: {}", e))?; - // parsers.insert("kotlin".to_string(), parser); - // languages.insert("kotlin".to_string(), language); - // } - // Initialize Haskell { let mut parser = Parser::new(); @@ -154,6 +143,17 @@ impl TreeSitterSearcher { languages.insert("scheme".to_string(), language); } + // Initialize Racket + { + let mut parser = Parser::new(); + let language: Language = tree_sitter_racket::LANGUAGE.into(); + parser + .set_language(&language) + .map_err(|e| anyhow!("Failed to set Racket language: {}", e))?; + parsers.insert("racket".to_string(), parser); + languages.insert("racket".to_string(), language); + } + if parsers.is_empty() { return Err(anyhow!( "No language parsers available. Enable at least one language feature." @@ -335,9 +335,10 @@ impl TreeSitterSearcher { ("java", Some("java")) => true, ("c", Some("c" | "h")) => true, ("cpp", Some("cpp" | "cc" | "cxx" | "hpp" | "hxx" | "h")) => true, - ("kotlin", Some("kt" | "kts")) => true, + ("haskell", Some("hs" | "lhs")) => true, ("scheme", Some("scm" | "ss" | "sld" | "sls")) => true, + ("racket", Some("rkt" | "rktl" | "rktd")) => true, _ => false, } } diff --git a/crates/g3-core/src/tool_definitions.rs b/crates/g3-core/src/tool_definitions.rs index 7c24a97..db716ed 100644 --- a/crates/g3-core/src/tool_definitions.rs +++ b/crates/g3-core/src/tool_definitions.rs @@ -227,7 +227,7 @@ fn create_core_tools(exclude_research: bool) -> Vec { }, Tool { name: "code_search".to_string(), - description: "Syntax-aware code search that understands code structure, not just text. Finds actual functions, classes, methods, and other code constructs - ignores matches in comments and strings. Much more accurate than grep for code searches. Supports batch searches (up to 20 parallel) with structured results and context lines. Languages: Rust, Python, JavaScript, TypeScript, Go, Java, C, C++, Kotlin. Uses tree-sitter query syntax.".to_string(), + description: "Syntax-aware code search that understands code structure, not just text. Finds actual functions, classes, methods, and other code constructs - ignores matches in comments and strings. Much more accurate than grep for code searches. Supports batch searches (up to 20 parallel) with structured results and context lines. Languages: Rust, Python, JavaScript, TypeScript, Go, Java, C, C++, Racket. Uses tree-sitter query syntax.".to_string(), input_schema: json!({ "type": "object", "properties": { @@ -239,7 +239,7 @@ fn create_core_tools(exclude_research: bool) -> Vec { "properties": { "name": { "type": "string", "description": "Label for this search." }, "query": { "type": "string", "description": "tree-sitter query in S-expression format (e.g., \"(function_item name: (identifier) @name)\")" }, - "language": { "type": "string", "enum": ["rust", "python", "javascript", "typescript", "go", "java", "c", "cpp", "kotlin"], "description": "Programming language to search." }, + "language": { "type": "string", "enum": ["rust", "python", "javascript", "typescript", "go", "java", "c", "cpp", "racket"], "description": "Programming language to search." }, "paths": { "type": "array", "items": { "type": "string" }, "description": "Paths/dirs to search. Defaults to current dir if empty." }, "context_lines": { "type": "integer", "minimum": 0, "maximum": 20, "default": 0, "description": "Lines of context to include around each match." } }, diff --git a/crates/g3-core/tests/code_search_test.rs b/crates/g3-core/tests/code_search_test.rs index c42dad6..992ad34 100644 --- a/crates/g3-core/tests/code_search_test.rs +++ b/crates/g3-core/tests/code_search_test.rs @@ -580,14 +580,21 @@ async fn test_cpp_search() { } #[tokio::test] -#[ignore] -async fn test_kotlin_search() { +async fn test_racket_search() { + // Get the workspace root (where Cargo.toml is) + let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap(); + let workspace_root = std::path::Path::new(&manifest_dir) + .parent() + .and_then(|p| p.parent()) + .unwrap(); + let test_code_path = workspace_root.join("examples/test_code"); + let request = CodeSearchRequest { searches: vec![SearchSpec { - name: "kotlin_classes".to_string(), - query: "(class_declaration (type_identifier) @name)".to_string(), - language: "kotlin".to_string(), - paths: vec!["examples/test_code".to_string()], + name: "racket_functions".to_string(), + query: r#"(list . (symbol) @kw (#eq? @kw "define") . (list . (symbol) @name))"#.to_string(), + language: "racket".to_string(), + paths: vec![test_code_path.to_string_lossy().to_string()], context_lines: 0, }], max_concurrency: 4, @@ -598,11 +605,11 @@ async fn test_kotlin_search() { assert_eq!(response.searches.len(), 1); assert!(response.searches[0].matches.len() > 0); - // Should find Person class + // Should find greet, add, factorial functions let names: Vec<&str> = response.searches[0] .matches .iter() .filter_map(|m| m.captures.get("name").map(|s| s.as_str())) .collect(); - assert!(names.contains(&"Person")); + assert!(names.contains(&"greet")); } diff --git a/crates/g3-core/examples/test_code/example.rkt b/examples/test_code/example.rkt similarity index 100% rename from crates/g3-core/examples/test_code/example.rkt rename to examples/test_code/example.rkt