Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ tree-sitter-cpp = "0.23"
tree-sitter-haskell = "0.23"
tree-sitter-dart = "0.0.4"
tree-sitter-scala = "0.24"
tree-sitter-zig = "1.0"
crossterm = "0.29"
ratatui = "0.29"
rusqlite = { version = "0.37", features = ["bundled"] }
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

## Features ✨

- 🦀🐍⚡🐹💎🍎🎯☕🐘#️⃣🔧➕🎭🎯 **Multi-language**: Rust, TypeScript, JavaScript, Python, Go, Ruby, Swift, Kotlin, Java, PHP, C#, C, C++, Haskell, Dart, Scala (more languages incoming!)
- 🦀🐍⚡🐹💎🍎🎯☕🐘#️⃣🔧➕🎭🎯 **Multi-language**: Rust, TypeScript, JavaScript, Python, Go, Ruby, Swift, Kotlin, Java, PHP, C#, C, C++, Haskell, Dart, Scala, Zig (more languages incoming!)
- 📊 **Real-time metrics**: Live WPM, accuracy, and consistency tracking as you type
- 🏆 **Ranking system**: Unlock developer titles from "Hello World Newbie" to "Quantum Computer" with ASCII art
- 🎮 **Multiple game modes**: Normal, Time Attack, and custom difficulty levels (Easy to Zen)
Expand Down
1 change: 1 addition & 0 deletions assets/languages/lang_ascii.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,6 @@
"lang_scala": "red",
"lang_haskell": "magenta",
"lang_dart": "cyan",
"lang_zig": "yellow",
"lang_default": "white"
}
1 change: 1 addition & 0 deletions assets/languages/lang_dark.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,6 @@
"lang_scala": {"r": 220, "g": 50, "b": 47},
"lang_haskell": {"r": 94, "g": 80, "b": 134},
"lang_dart": {"r": 0, "g": 180, "b": 240},
"lang_zig": {"r": 249, "g": 169, "b": 60},
"lang_default": {"r": 255, "g": 255, "b": 255}
}
1 change: 1 addition & 0 deletions assets/languages/lang_light.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,6 @@
"lang_scala": {"r": 220, "g": 50, "b": 47},
"lang_haskell": {"r": 94, "g": 80, "b": 134},
"lang_dart": {"r": 0, "g": 120, "b": 180},
"lang_zig": {"r": 189, "g": 99, "b": 0},
"lang_default": {"r": 64, "g": 64, "b": 64}
}
159 changes: 133 additions & 26 deletions docs/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -293,45 +293,152 @@ pub fn extract_chunks(
tree-sitter-newlang = "0.20"
```

2. **Create language-specific extractor:**
2. **Create language definition:**
```rust
// src/extractor/languages/newlang.rs
use tree_sitter::Language;

extern "C" {
fn tree_sitter_newlang() -> Language;
// src/domain/models/languages/newlang.rs
use crate::domain::models::Language;
use crate::presentation::ui::Colors;
use std::hash::Hash;

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct NewLang;

impl Language for NewLang {
fn name(&self) -> &'static str {
"newlang"
}
fn extensions(&self) -> Vec<&'static str> {
vec!["nl"]
}
fn color(&self) -> ratatui::style::Color {
Colors::lang_newlang()
}
fn display_name(&self) -> &'static str {
"NewLang"
}
fn is_valid_comment_node(&self, node: tree_sitter::Node) -> bool {
node.kind() == "comment"
}
}

pub fn language() -> Language {
unsafe { tree_sitter_newlang() }
```

3. **Create language-specific extractor:**
```rust
// src/domain/services/source_code_parser/parsers/newlang.rs
use super::LanguageExtractor;
use crate::domain::models::ChunkType;
use crate::{GitTypeError, Result};
use tree_sitter::{Node, Parser};

pub struct NewLangExtractor;

impl LanguageExtractor for NewLangExtractor {
fn tree_sitter_language(&self) -> tree_sitter::Language {
tree_sitter_newlang::LANGUAGE.into()
}

fn query_patterns(&self) -> &str {
"(function_declaration name: (identifier) @name) @function"
}

fn comment_query(&self) -> &str {
"(comment) @comment"
}

fn capture_name_to_chunk_type(&self, capture_name: &str) -> Option<ChunkType> {
match capture_name {
"function" => Some(ChunkType::Function),
_ => None,
}
}

fn extract_name(&self, node: Node, source_code: &str, _capture_name: &str) -> Option<String> {
// Extract identifier name from AST node
None
}

fn middle_implementation_query(&self) -> &str {
"" // Optional: for extracting code blocks within functions
}

fn middle_capture_name_to_chunk_type(&self, _capture_name: &str) -> Option<ChunkType> {
None
}
}

impl NewLangExtractor {
pub fn create_parser() -> Result<Parser> {
let mut parser = Parser::new();
parser.set_language(&tree_sitter_newlang::LANGUAGE.into())
.map_err(|e| GitTypeError::ExtractionFailed(format!("Failed to set NewLang language: {}", e)))?;
Ok(parser)
}
}

pub const QUERY: &str = r#"
(function_definition
name: (identifier) @function.name) @function.definition
"#;
```

3. **Update the main extractor:**
4. **Register the language:**
```rust
// src/extractor/mod.rs
match language {
Language::NewLang => languages::newlang::create_extractor(),
// ... other languages
// In src/domain/models/languages/mod.rs
pub mod newlang;
pub use newlang::NewLang;

// In src/domain/models/language.rs
pub fn all_languages() -> Vec<Box<dyn Language>> {
vec![
// ... other languages
Box::new(NewLang),
]
}

// In src/domain/services/source_code_parser/parsers/mod.rs
pub mod newlang;
register_language!(NewLang, newlang, NewLangExtractor);
```

5. **Add color scheme support:**
```rust
// In src/domain/models/color_scheme.rs - add field:
pub lang_newlang: SerializableColor,

// In src/presentation/ui/colors.rs - add method:
pub fn lang_newlang() -> Color {
Self::get_color_scheme().lang_newlang.into()
}

// Add to theme JSON files:
// assets/languages/lang_dark.json
// assets/languages/lang_light.json
// assets/languages/lang_ascii.json
"lang_newlang": {"r": 123, "g": 45, "b": 67}
```

4. **Add tests:**
6. **Add tests:**
```rust
#[test]
fn test_newlang_extraction() {
// Test with sample code
// tests/integration/languages/newlang/extractor.rs
use crate::integration::languages::extractor::test_language_extractor;

test_language_extractor! {
name: test_newlang_function_extraction,
language: "newlang",
extension: "nl",
source: r#"
function hello() {
print("Hello")
}
"#,
total_chunks: 2,
chunk_counts: {
File: 1,
Function: 1,
}
}
```

5. **Update documentation:**
- Add to supported languages list in README.md
- Include examples if needed
7. **Update documentation:**
- Add to `README.md` supported languages list
- Add to `docs/supported-languages.md` with extraction features
- Update CLI help in `src/presentation/cli/args.rs`
- Add example code if needed

### Query Writing Guidelines

Expand Down
9 changes: 8 additions & 1 deletion docs/supported-languages.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
| Scala | `.sc`, `.scala` | `sc` | `tree_sitter_scala` |
| Swift | `.swift` | - | `tree_sitter_swift` |
| TypeScript | `.ts`, `.tsx` | `ts` | `tree_sitter_typescript` (TSX) |
| Zig | `.zig` | - | `tree_sitter_zig` |

## Extraction Features

Expand Down Expand Up @@ -157,6 +158,12 @@
- **Namespaces** (`internal_module`) - Namespace declarations
- **JSX Elements** (`jsx_element`, `jsx_self_closing_element`) - React components

### Zig
- **Functions** (`function_declaration`) - Function definitions
- **Structs** (`variable_declaration` with `struct_declaration`) - Struct type definitions
- **Enums** (`variable_declaration` with `enum_declaration`) - Enum type definitions
- **Unions** (`variable_declaration` with `union_declaration`) - Union type definitions

## Language-Specific Options

### Filtering by Language
Expand All @@ -173,7 +180,7 @@ gittype --langs rust,typescript,javascript,python

```toml
[default]
langs = ["rust", "typescript", "javascript", "python", "go", "ruby", "swift", "kotlin", "java", "php", "csharp", "c", "cpp", "haskell", "dart", "scala"]
langs = ["rust", "typescript", "javascript", "python", "go", "ruby", "swift", "kotlin", "java", "php", "csharp", "c", "cpp", "haskell", "dart", "scala", "zig"]
```

## Code Extraction Quality
Expand Down
2 changes: 1 addition & 1 deletion docs/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ Discover and practice typing with trending GitHub repositories. Repositories are
| `--period` | Time period for trending (daily, weekly, monthly) | `daily` |

#### Supported Languages:
- C, C#, C++, Dart, Go, Haskell, Java, JavaScript, Kotlin, PHP, Python, Ruby, Rust, Scala, Swift, TypeScript
- C, C#, C++, Dart, Go, Haskell, Java, JavaScript, Kotlin, PHP, Python, Ruby, Rust, Scala, Swift, TypeScript, Zig

#### Examples:
```bash
Expand Down
5 changes: 5 additions & 0 deletions src/domain/models/color_scheme.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ pub struct ColorScheme {
pub lang_scala: SerializableColor,
pub lang_haskell: SerializableColor,
pub lang_dart: SerializableColor,
pub lang_zig: SerializableColor,
pub lang_default: SerializableColor,
}

Expand Down Expand Up @@ -320,6 +321,10 @@ impl ColorScheme {
.get("lang_dart")
.cloned()
.unwrap_or(SerializableColor::Name("blue".to_string())),
lang_zig: lang_colors
.get("lang_zig")
.cloned()
.unwrap_or(SerializableColor::Name("yellow".to_string())),
lang_default: lang_colors
.get("lang_default")
.cloned()
Expand Down
3 changes: 2 additions & 1 deletion src/domain/models/language.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::domain::models::languages::{
CSharp, Cpp, Dart, Go, Haskell, Java, JavaScript, Kotlin, Php, Python, Ruby, Rust, Scala,
Swift, TypeScript, C,
Swift, TypeScript, Zig, C,
};
use crate::presentation::ui::Colors;
use std::hash::{Hash, Hasher};
Expand Down Expand Up @@ -72,6 +72,7 @@ impl Languages {
Box::new(Haskell),
Box::new(Dart),
Box::new(Scala),
Box::new(Zig),
]
}

Expand Down
2 changes: 2 additions & 0 deletions src/domain/models/languages/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ pub mod rust;
pub mod scala;
pub mod swift;
pub mod typescript;
pub mod zig;

pub use c::C;
pub use cpp::Cpp;
Expand All @@ -31,3 +32,4 @@ pub use rust::Rust;
pub use scala::Scala;
pub use swift::Swift;
pub use typescript::TypeScript;
pub use zig::Zig;
28 changes: 28 additions & 0 deletions src/domain/models/languages/zig.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
use crate::domain::models::Language;
use crate::presentation::ui::Colors;
use std::hash::Hash;

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Zig;

impl Language for Zig {
fn name(&self) -> &'static str {
"zig"
}
fn extensions(&self) -> Vec<&'static str> {
vec!["zig"]
}

fn color(&self) -> ratatui::style::Color {
Colors::lang_zig()
}

fn display_name(&self) -> &'static str {
"Zig"
}

fn is_valid_comment_node(&self, node: tree_sitter::Node) -> bool {
let node_kind = node.kind();
node_kind == "comment"
}
}
4 changes: 3 additions & 1 deletion src/domain/services/source_code_parser/parsers/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::domain::models::languages::{
CSharp, Cpp, Dart, Go, Haskell, Java, JavaScript, Kotlin, Php, Python, Ruby, Rust, Scala,
Swift, TypeScript, C,
Swift, TypeScript, Zig, C,
};
use crate::domain::models::ChunkType;
use crate::domain::models::Language;
Expand All @@ -26,6 +26,7 @@ pub mod rust;
pub mod scala;
pub mod swift;
pub mod typescript;
pub mod zig;

pub trait LanguageExtractor {
fn tree_sitter_language(&self) -> tree_sitter::Language;
Expand Down Expand Up @@ -82,6 +83,7 @@ impl ParserRegistry {
register_language!(Rust, rust, RustExtractor);
register_language!(Scala, scala, ScalaExtractor);
register_language!(Swift, swift, SwiftExtractor);
register_language!(Zig, zig, ZigExtractor);

registry
}
Expand Down
Loading