Skip to content

Commit b4d24b3

Browse files
Merge pull request #178 from unhappychoice/feature/history-tui-screen
feat: Add History screen and comprehensive development tooling
2 parents fcdc25e + 37472c3 commit b4d24b3

27 files changed

+3196
-443
lines changed

examples/README.md

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# Development Tools
2+
3+
This directory contains development tools and utilities for GitType.
4+
5+
## Seed Database
6+
7+
Populate the database with sample data for development and testing.
8+
9+
### Usage
10+
11+
```bash
12+
# Generate default dataset (10 repos, 1000 sessions, 3000 stages)
13+
cargo run --example seed_database -- --clear
14+
15+
# Generate custom dataset
16+
cargo run --example seed_database -- --clear --repos 5 --sessions 100 --stages 500
17+
18+
# Small dataset for quick testing
19+
cargo run --example seed_database -- --clear --repos 2 --sessions 20 --stages 50
20+
```
21+
22+
### Options
23+
24+
- `--clear`: Clear existing data before seeding
25+
- `--repos <N>`: Number of repositories to generate (default: 10)
26+
- `--sessions <N>`: Number of sessions to generate (default: 1000)
27+
- `--stages <N>`: Number of stages to generate (default: 3000)
28+
29+
### Generated Data
30+
31+
The tool generates realistic sample data including:
32+
33+
- **Repositories**: Various programming languages and project types
34+
- **Sessions**: Mix of completed and incomplete typing sessions
35+
- **Challenges**: Real code snippets in multiple languages
36+
- **Stages**: Individual typing challenges with timing data
37+
- **Results**: Performance metrics, rankings, and statistics
38+
39+
This data is useful for:
40+
- Testing UI components with realistic data volumes
41+
- Performance testing with large datasets
42+
- Developing analytics and reporting features
43+
- Manual testing of different user scenarios

examples/seed_database.rs

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
use clap::Parser;
2+
use gittype::{
3+
storage::{seeders::DatabaseSeeder, Database},
4+
Result,
5+
};
6+
use std::sync::{Arc, Mutex};
7+
8+
#[derive(Parser)]
9+
#[command(name = "seed_database")]
10+
#[command(about = "Populate database with seed data for development")]
11+
struct Args {
12+
/// Clear existing data before seeding
13+
#[arg(long)]
14+
clear: bool,
15+
/// Number of repositories to generate
16+
#[arg(long, default_value = "10")]
17+
repos: usize,
18+
/// Number of sessions to generate
19+
#[arg(long, default_value = "1000")]
20+
sessions: usize,
21+
/// Number of stages to generate
22+
#[arg(long, default_value = "3000")]
23+
stages: usize,
24+
}
25+
26+
fn main() -> Result<()> {
27+
let args = Args::parse();
28+
29+
println!("🌱 Starting database seeding...");
30+
31+
let database = Arc::new(Mutex::new(Database::new()?));
32+
33+
// Initialize database tables if needed
34+
{
35+
let db = database.lock().unwrap();
36+
db.init()?;
37+
}
38+
39+
if args.clear {
40+
println!("🧹 Clearing existing data...");
41+
clear_database(&database)?;
42+
}
43+
44+
println!(
45+
"📊 Generating {} repositories, {} sessions, {} stages...",
46+
args.repos, args.sessions, args.stages
47+
);
48+
49+
let seeder = DatabaseSeeder::new(database);
50+
seeder.seed_with_counts(args.repos, args.sessions, args.stages)?;
51+
52+
println!("✅ Seed data has been successfully loaded!");
53+
println!("💡 You can now use the application with sample data for development and testing.");
54+
55+
Ok(())
56+
}
57+
58+
fn clear_database(database: &Arc<Mutex<Database>>) -> Result<()> {
59+
let db = database.lock().unwrap();
60+
let conn = db.get_connection();
61+
62+
// Disable foreign key checks temporarily
63+
conn.execute("PRAGMA foreign_keys = OFF", [])?;
64+
65+
let tables = vec![
66+
"stage_results",
67+
"session_results",
68+
"stages",
69+
"challenges",
70+
"sessions",
71+
"repositories",
72+
];
73+
74+
for table in tables {
75+
conn.execute(&format!("DELETE FROM {}", table), [])?;
76+
}
77+
78+
// Re-enable foreign key checks
79+
conn.execute("PRAGMA foreign_keys = ON", [])?;
80+
81+
Ok(())
82+
}

src/cli/commands/game.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,9 @@ pub fn run_game_session(cli: Cli) -> Result<()> {
102102
}
103103

104104
fn handle_game_error(e: GitTypeError) -> Result<()> {
105+
// Log the error details for debugging before handling user-friendly output
106+
crate::logging::log_error_to_file(&e);
107+
105108
match e {
106109
GitTypeError::NoSupportedFiles => {
107110
eprintln!("❌ No code chunks found in the repository");

src/cli/runner.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::cli::args::{Cli, Commands};
22
use crate::cli::commands::{run_export, run_game_session, run_history, run_stats};
33
use crate::game::stage_manager::{cleanup_terminal, show_session_summary_on_interrupt};
4-
use crate::logging::{setup_console_logging, setup_logging};
4+
use crate::logging::{log_panic_to_file, setup_console_logging, setup_logging};
55
use crate::Result;
66

77
pub fn run_cli(cli: Cli) -> Result<()> {
@@ -27,6 +27,9 @@ pub fn setup_signal_handlers() {
2727
std::panic::set_hook(Box::new(|panic_info| {
2828
use std::io::{stderr, Write};
2929

30+
// Log panic information to file
31+
log_panic_to_file(panic_info);
32+
3033
// Ensure panic message is displayed before terminal cleanup
3134
let _ = writeln!(stderr(), "Error: {}", panic_info);
3235
let _ = stderr().flush();
@@ -35,6 +38,7 @@ pub fn setup_signal_handlers() {
3538

3639
// Display panic info again after cleanup to ensure visibility
3740
eprintln!("Application encountered a panic: {}", panic_info);
41+
eprintln!("💡 Panic details have been logged to the log file for debugging.");
3842
}));
3943

4044
ctrlc::set_handler(move || {

src/game/screens/cancel_screen.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ impl CancelScreen {
1616
pub fn show_session_summary_cancel_mode(
1717
total_stages: usize,
1818
completed_stages: usize,
19-
stage_engines: &[(String, StageTracker)],
19+
stage_trackers: &[(String, StageTracker)],
2020
_repo_info: &Option<GitRepository>,
2121
) -> Result<ResultAction> {
2222
let mut stdout = stdout();
@@ -53,9 +53,9 @@ impl CancelScreen {
5353
execute!(stdout, Print(stage_text))?;
5454

5555
// Show basic metrics if available (centered, white)
56-
if !stage_engines.is_empty() {
57-
let (_last_stage_name, last_engine) = stage_engines.last().unwrap();
58-
let metrics = crate::scoring::StageCalculator::calculate(last_engine, false, false);
56+
if !stage_trackers.is_empty() {
57+
let (_last_stage_name, last_tracker) = stage_trackers.last().unwrap();
58+
let metrics = crate::scoring::StageCalculator::calculate(last_tracker);
5959

6060
let metrics_text = format!(
6161
"CPM: {:.0} | WPM: {:.0} | Accuracy: {:.0}%",

src/game/screens/failure_screen.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ impl FailureScreen {
1616
pub fn show_session_summary_fail_mode(
1717
total_stages: usize,
1818
completed_stages: usize,
19-
stage_engines: &[(String, StageTracker)],
19+
stage_trackers: &[(String, StageTracker)],
2020
_repo_info: &Option<GitRepository>,
2121
) -> Result<ResultAction> {
2222
let mut stdout = stdout();
@@ -53,9 +53,12 @@ impl FailureScreen {
5353
execute!(stdout, Print(stage_text))?;
5454

5555
// Show basic metrics if available (centered, white)
56-
if !stage_engines.is_empty() {
57-
let (_last_stage_name, last_engine) = stage_engines.last().unwrap();
58-
let metrics = crate::scoring::StageCalculator::calculate(last_engine, false, true);
56+
if !stage_trackers.is_empty() {
57+
let (_last_stage_name, last_tracker) = stage_trackers.last().unwrap();
58+
// Mark as failed first, then calculate
59+
let mut tracker = last_tracker.clone();
60+
tracker.record(crate::scoring::StageInput::Fail);
61+
let metrics = crate::scoring::StageCalculator::calculate(&tracker);
5962

6063
let metrics_text = format!(
6164
"CPM: {:.0} | WPM: {:.0} | Accuracy: {:.0}%",

0 commit comments

Comments
 (0)