Skip to content

Commit 22ea8be

Browse files
committed
Add comprehensive codebase documentation
Generate structured documentation in .agents/summary/ with architecture, components, interfaces, data models, workflows, and dependencies. Update AGENTS.md with consolidated project context for AI assistants.
1 parent b759f7c commit 22ea8be

10 files changed

Lines changed: 1239 additions & 64 deletions

File tree

.agents/summary/architecture.md

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
# Architecture
2+
<!-- metadata: type=architecture, audience=ai-agents, scope=system-design -->
3+
4+
## Overview
5+
6+
Mecalin follows the standard GNOME application architecture using GTK4 with the Adwaita design system. It uses the GTK subclassing pattern where each UI component is a GObject subclass with a corresponding XML composite template.
7+
8+
## High-Level Architecture
9+
10+
```mermaid
11+
graph TB
12+
subgraph Entry["Application Entry"]
13+
main["main.rs"]
14+
app["MecalinApplication"]
15+
end
16+
17+
subgraph Navigation["Navigation Layer"]
18+
window["MecalinWindow<br/>(NavigationView hub)"]
19+
end
20+
21+
subgraph Views["Feature Views"]
22+
lesson["LessonView<br/>(Structured lessons)"]
23+
speed["SpeedTestView<br/>(Timed typing tests)"]
24+
falling["FallingKeysGame<br/>(Falling keys game)"]
25+
scrolling["ScrollingLanesGame<br/>(Scrolling lanes game)"]
26+
prefs["PreferencesView"]
27+
about["AboutView"]
28+
completion["CourseCompletionView"]
29+
end
30+
31+
subgraph Widgets["Reusable Widgets"]
32+
typing["TypingRow<br/>(Text input)"]
33+
keyboard["KeyboardWidget<br/>(Visual keyboard)"]
34+
hand["HandWidget<br/>(Hand position guide)"]
35+
stv["SpeedTestTextView<br/>(Rich text display)"]
36+
results["SpeedTestResultsView"]
37+
end
38+
39+
subgraph Data["Data & Utilities"]
40+
course["Course / Lesson / LessonStep"]
41+
textgen["text_generation<br/>(Random text)"]
42+
textutil["text_utils<br/>(Validation, WPM)"]
43+
testutil["typing_test_utils<br/>(Test config/summary)"]
44+
utils["utils<br/>(Locale, decomposition)"]
45+
end
46+
47+
subgraph Resources["Embedded Resources"]
48+
ui["11 XML UI templates"]
49+
css["style.css"]
50+
lessons["7 lesson JSON files"]
51+
layouts["7 keyboard layout JSONs"]
52+
words["40+ word list files"]
53+
icons["SVG icons"]
54+
end
55+
56+
main --> app
57+
app --> window
58+
window --> lesson & speed & falling & scrolling & prefs & about
59+
lesson --> typing & keyboard & hand & completion
60+
lesson --> course
61+
speed --> stv & results
62+
falling --> keyboard
63+
scrolling --> keyboard
64+
stv --> textutil
65+
speed --> testutil
66+
textgen --> words
67+
course --> lessons
68+
keyboard --> layouts
69+
typing --> textutil
70+
utils --> course & keyboard & lesson
71+
```
72+
73+
## Design Patterns
74+
75+
### GTK4 Subclassing Pattern
76+
77+
Every UI component follows this structure:
78+
79+
```mermaid
80+
classDiagram
81+
class Component {
82+
+mod imp (private implementation)
83+
+glib::wrapper! macro
84+
+public API methods
85+
}
86+
class imp_Module {
87+
+struct ComponentName (fields)
88+
+ObjectSubclass impl
89+
+ObjectImpl::constructed()
90+
+WidgetImpl overrides
91+
+CompositeTemplate derive
92+
}
93+
class XML_Template {
94+
+Widget hierarchy
95+
+template_child bindings
96+
+Signal connections
97+
}
98+
Component --> imp_Module : contains
99+
imp_Module --> XML_Template : loads via GResource
100+
```
101+
102+
Each component:
103+
1. Defines a private `imp` module with the actual struct and trait implementations
104+
2. Uses `#[derive(gtk::CompositeTemplate)]` to bind to an XML UI template
105+
3. Exposes a public wrapper type via `glib::wrapper!`
106+
4. Initializes in `ObjectImpl::constructed()` — setting up signals, loading data, binding settings
107+
108+
### Navigation Architecture
109+
110+
`MecalinWindow` uses `adw::NavigationView` as a stack-based navigation hub. Each feature is an `adw::NavigationPage` pushed by tag:
111+
112+
```mermaid
113+
graph LR
114+
Home["Home Menu"] -->|"push by tag"| lessons["lessons"]
115+
Home -->|"push by tag"| speed_test["speed_test"]
116+
Home -->|"push by tag"| game["game (Falling Keys)"]
117+
Home -->|"push by tag"| lanes_game["lanes_game"]
118+
Home -->|"push by tag"| preferences["preferences"]
119+
Home -->|"push by tag"| about["about"]
120+
```
121+
122+
### State Management
123+
124+
- **GSettings** (`io.github.nacho.mecalin`): Persists user preferences (current lesson/step, widget visibility, finger colors, test duration)
125+
- **Window state** (`io.github.nacho.mecalin.state.window`): Persists window size and maximized state
126+
- **In-memory state**: Component-local `Cell`/`RefCell` fields in `imp` structs
127+
128+
### Resource Embedding
129+
130+
All UI templates, CSS, and icons are compiled into the binary via GResource (`resources.gresource.xml`). Lesson data, keyboard layouts, and word lists are embedded via `include_str!` and `include_dir!` macros at compile time.
131+
132+
### Build-Time Code Generation
133+
134+
`build.rs` performs two tasks:
135+
1. **Config generation**: Processes `src/config.rs.in` template, replacing `@VARIABLE@` placeholders with environment variables (VERSION, APPLICATION_ID, GETTEXT_PACKAGE, DATADIR)
136+
2. **Resource compilation**: Compiles `resources.gresource.xml` into a binary resource bundle
137+
138+
### Internationalization
139+
140+
- UI strings: gettext via `gettext-rs` and `i18n-format` crates
141+
- Lesson content: Separate JSON files per language, selected by locale detection (`utils::language_from_locale()`)
142+
- Keyboard layouts: Separate JSON files per language
143+
- Word lists: Separate text files per language, embedded at compile time

.agents/summary/codebase_info.md

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# Codebase Information
2+
<!-- metadata: type=overview, audience=ai-agents, scope=project-wide -->
3+
4+
## Project Identity
5+
6+
- **Name**: Mecalin
7+
- **Application ID**: `io.github.nacho.mecalin`
8+
- **Version**: 1.0.2
9+
- **License**: GPL-3.0-or-later
10+
- **Category**: Education (Typing Tutor)
11+
- **Distribution**: [Flathub](https://flathub.org/apps/io.github.nacho.mecalin)
12+
- **Heritage**: Based on [Mecawin](https://archive.org/details/mecawin), a classic Windows typing tutor
13+
14+
## Technology Stack
15+
16+
| Layer | Technology | Version Requirement |
17+
|-------|-----------|-------------------|
18+
| Language | Rust | Edition 2024 |
19+
| UI Framework | GTK4 | ≥ 4.14 (Cargo), ≥ 4.10 (Meson) |
20+
| Design System | libadwaita | ≥ 1.5 |
21+
| Build (dev) | Cargo | stable toolchain |
22+
| Build (prod) | Meson | ≥ 0.59.0 |
23+
| Packaging | Flatpak | GNOME Platform 46 |
24+
| i18n | gettext | via `gettext-rs` crate |
25+
| CI | GitHub Actions | ubuntu-latest |
26+
27+
## Language Breakdown
28+
29+
| Language | Files | Purpose |
30+
|----------|-------|---------|
31+
| Rust | 20 `.rs` files | Application logic |
32+
| XML | 11 `.ui` files | GTK Builder UI templates |
33+
| JSON | 7 lesson + 7 keyboard layout files | Localized content |
34+
| Text | 40+ `.txt` files | Word lists for text generation |
35+
| CSS | 1 `style.css` | Custom styling |
36+
| XML | 1 `.gresource.xml` | Resource manifest |
37+
| XML | 1 `.gschema.xml` | GSettings schema |
38+
| YAML | 1 `ci.yml` + 1 Flatpak manifest | CI/CD and packaging |
39+
40+
## Supported Languages (UI Translation)
41+
42+
Spanish (es), French (fr), Galician (gl), Italian (it), Polish (pl), Portuguese (pt)
43+
44+
## Supported Keyboard Layouts
45+
46+
US, Spanish, French, Galician, Italian, Polish, Portuguese
47+
48+
## Word Lists for Text Generation
49+
50+
40+ languages including: Arabic, Bengali, Bulgarian, Catalan, Czech, Danish, Dutch, English, Estonian, Finnish, French, Galician, German, Greek, Hebrew, Hindi, Hungarian, Indonesian, Italian, Kabyle, Kinyarwanda, Korean, Nepali, Norwegian (Bokmål/Nynorsk), Occitan, Persian, Polish, Portuguese, Romanian, Russian, Slovak, Swahili, Swedish, Turkish, Ukrainian, Vietnamese

.agents/summary/components.md

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
# Components
2+
<!-- metadata: type=components, audience=ai-agents, scope=all-modules -->
3+
4+
## Application Core
5+
6+
### MecalinApplication (`src/application.rs`)
7+
- **Parent**: `adw::Application`
8+
- **Role**: Application entry point. Registers GResource base path, loads CSS, sets keyboard shortcuts (`Ctrl+Q` quit, `Ctrl+W` close), creates the main window on activation.
9+
- **Key behavior**: `startup()` loads global CSS provider; `activate()` creates and presents `MecalinWindow`.
10+
11+
### MecalinWindow (`src/window.rs`)
12+
- **Parent**: `adw::ApplicationWindow`
13+
- **Role**: Main window and navigation hub. Contains `adw::NavigationView` with `ActionRow` entries for each feature.
14+
- **Template children**: `header_bar`, `window_title`, `navigation_view`, plus rows for lessons, speed test, falling keys, scrolling lanes, preferences, about.
15+
- **Key behavior**: Each row's `activated` signal pushes the corresponding navigation page by tag. Persists window size/maximized state via GSettings.
16+
17+
## Feature Views
18+
19+
### LessonView (`src/lesson_view.rs`)
20+
- **Parent**: `adw::NavigationPage`
21+
- **Role**: Structured typing lessons with step-by-step progression. The most complex view.
22+
- **Contains**: `TypingRow`, `KeyboardWidget`, `HandWidget`
23+
- **Key behavior**: Loads a `Course` based on locale, tracks current lesson/step/repetition via GSettings, highlights relevant keys on the keyboard, shows hand position guidance, advances through steps on completion, shows `CourseCompletionView` when all lessons are done.
24+
- **Properties**: `current_lesson` (boxed), `current_step_index` (u32)
25+
26+
### SpeedTestView (`src/speed_test_view.rs`)
27+
- **Parent**: `adw::NavigationPage`
28+
- **Role**: Timed typing speed tests with configurable duration.
29+
- **Contains**: `SpeedTestTextView`, `SpeedTestResultsView`
30+
- **Key behavior**: Generates random text via `text_generation`, starts a timer, tracks progress, shows results (WPM, accuracy, duration) on completion or timeout.
31+
32+
### FallingKeysGame (`src/falling_keys_game.rs`)
33+
- **Parent**: `adw::NavigationPage`
34+
- **Role**: Gamified typing practice where keys fall from the top of the screen.
35+
- **Contains**: `FallingKeysWidget` (custom painted widget), `KeyboardWidget`
36+
- **Key behavior**: Game loop spawns falling key characters, player must type them before they reach the bottom. Tracks score and lives. Uses `glib::timeout_add_local` for the game loop.
37+
- **Inner types**: `FallingKey` (position, character, speed), `FallingKeysWidget` (custom snapshot rendering)
38+
39+
### ScrollingLanesGame (`src/scrolling_lanes_game.rs`)
40+
- **Parent**: `adw::NavigationPage`
41+
- **Role**: Gamified typing practice with text scrolling across lanes.
42+
- **Contains**: `LaneWidget` (custom painted widget), `KeyboardWidget`
43+
- **Key behavior**: Multiple lanes with scrolling text that must be typed. Uses `glib::timeout_add_local` for animation. Tracks score and lives.
44+
- **Inner types**: `ScrollingText` (text, position, lane), `LaneWidget` (custom snapshot rendering)
45+
46+
### PreferencesView (`src/preferences_view.rs`)
47+
- **Parent**: `adw::NavigationPage`
48+
- **Role**: User settings for hand widget visibility, keyboard widget visibility, finger colors, and lesson selection.
49+
- **Key behavior**: Binds `adw::SwitchRow` widgets directly to GSettings keys. Populates lesson combo from `Course` data.
50+
51+
### AboutView (`src/about_view.rs`)
52+
- **Parent**: `adw::NavigationPage`
53+
- **Role**: Application information, credits, and links.
54+
55+
### CourseCompletionView (`src/course_completion_view.rs`)
56+
- **Parent**: `adw::NavigationPage`
57+
- **Role**: Congratulatory view shown when all lessons in a course are completed.
58+
59+
## Reusable Widgets
60+
61+
### TypingRow (`src/typing_row.rs`)
62+
- **Parent**: `adw::PreferencesRow`
63+
- **Role**: Core text input widget used in `LessonView`. Shows target text, captures typed input, validates character-by-character.
64+
- **Signals**: `mistake-made(bool)`, `step-completed`, `next-char-changed(String)`, `dead-key-started`
65+
- **Key behavior**: Locks cursor to end position, validates each keystroke against target text, draws custom cursor overlay, detects dead key input (for accented characters).
66+
67+
### KeyboardWidget (`src/keyboard_widget.rs`)
68+
- **Parent**: `gtk::Widget`
69+
- **Role**: Visual on-screen keyboard that highlights the current key to press and shows finger assignments.
70+
- **Key behavior**: Loads keyboard layout from JSON, custom `snapshot()` rendering of keys with color-coded fingers, supports dead key sequences (accent → base char), handles modifier keys (Shift, AltGr).
71+
- **Inner types**: `KeyboardLayout`, `KeyInfo`, `Finger`, `ModifierKey`
72+
73+
### HandWidget (`src/hand_widget.rs`)
74+
- **Parent**: `gtk::Widget`
75+
- **Role**: Visual hand position guide showing which finger to use.
76+
- **Key behavior**: Custom `snapshot()` rendering of left/right hands with highlighted current finger. Caches theme colors and responds to dark/light mode changes.
77+
78+
### SpeedTestTextView (`src/speed_test_text_view.rs`)
79+
- **Parent**: `adw::Bin` (composite template)
80+
- **Role**: Rich text display for speed tests with color-coded correct/incorrect characters, animated caret, and scrolling.
81+
- **Sub-modules**: `accessibility.rs`, `caret.rs`, `colors.rs`, `input.rs`, `scrolling.rs`
82+
- **Key behavior**: Manages original vs typed text comparison, renders colored text via GTK TextBuffer tags, animates caret position, handles IME input, auto-scrolls as user types.
83+
- **Signals**: `typed-text-changed`, `push-original-text`, `set-original-text`
84+
85+
### SpeedTestResultsView (`src/speed_test_results_view.rs`)
86+
- **Parent**: `adw::NavigationPage`
87+
- **Role**: Displays speed test results (WPM, accuracy, duration).
88+
- **Signals**: `retry-clicked`
89+
90+
## Data & Utility Modules
91+
92+
### Course (`src/course.rs`)
93+
- **Role**: Data model for structured typing lessons. Loads lesson JSON files based on language.
94+
- **Types**: `Course`, `Lesson`, `LessonStep`, `LessonsData`
95+
- **Key behavior**: `new_with_language()` loads embedded JSON via `include_str!`. Falls back to US English for unknown languages.
96+
97+
### text_generation (`src/text_generation.rs`)
98+
- **Role**: Generates random typing text from embedded word lists.
99+
- **Types**: `Language` (enum with 30+ variants), `Punctuation`
100+
- **Key behavior**: Loads word lists via `include_dir!`, generates text with configurable difficulty (simple/advanced), supports punctuation insertion, uppercase, and wrapping.
101+
102+
### text_utils (`src/text_utils.rs`)
103+
- **Role**: Text validation, WPM calculation, and character comparison utilities.
104+
- **Types**: `GraphemeState` (Correct/Unfinished/Mistake)
105+
- **Key behavior**: Grapheme-level validation with Unicode support, handles character aliases (æ→ae, guillemets→quotes, non-breaking spaces), calculates WPM from correct graphemes.
106+
107+
### typing_test_utils (`src/typing_test_utils.rs`)
108+
- **Role**: Speed test configuration and result summary types.
109+
- **Types**: `TestConfig`, `TestDuration`, `TestSummary`, `GeneratedTestDifficulty`
110+
111+
### utils (`src/utils.rs`)
112+
- **Role**: Locale detection, Unicode decomposition, and key extraction utilities.
113+
- **Key functions**: `language_from_locale()` (maps LANG env var to language code), `decompose_with_spacing_accent()` (for dead key handling), `extract_keys()` (unique characters from text).

0 commit comments

Comments
 (0)