typetui 0.2.1

A terminal-based typing test.
Documentation
#module_parameters (DEBUG := false, MAX_SIZE := 1024);

#if DEBUG {
    debug_print :: (fmt: string, args: ..Any) {
        print("[DEBUG] ");
        print(fmt, ..args);
    }
} else {
    debug_print :: (fmt: string, args: ..Any) {
    }
}

main :: () {
    print("Module parameters: DEBUG=%, MAX_SIZE=%\n", DEBUG, MAX_SIZE);
    
    debug_print("This only prints in debug mode\n");
    
    #assert(MAX_SIZE > 0, "MAX_SIZE must be positive");
    
    print("\n=== String Utilities ===\n");
    string_utils_demo();
    
    print("\n=== File I/O ===\n");
    file_io_demo();
    
    print("\n=== Time and Date ===\n");
    time_demo();
    
    print("\n=== Command Line ===\n");
    cli_demo();
    
    print("\n=== Math Utilities ===\n");
    math_demo();
    
    print("\n=== Random Numbers ===\n");
    random_demo();
    
    print("\n=== Hashing ===\n");
    hash_demo();
}

string_utils_demo :: () {
    str := "Hello, World!";
    
    print("Original: %\n", str);
    print("Length: %\n", str.count);
    
    sub := slice(str, 7, 5);
    print("Substring: %\n", sub);
    
    pos := find_index_from_left(str, "World");
    print("'World' at index: %\n", pos);
    
    replaced := replace(str, "World", "Jai");
    defer free(replaced);
    print("Replaced: %\n", replaced);
    
    csv := "one,two,three,four";
    parts := split(csv, ",");
    defer array_reset(*parts);
    print("Split: %\n", parts);
    
    joined := join(parts, " | ");
    defer free(joined);
    print("Joined: %\n", joined);
    
    spaced := "  spaces  ";
    trimmed := trim(spaced);
    print("Trimmed: '%'\n", trimmed);
    
    lower := copy_string(str);
    defer free(lower);
    for lower {
        if it >= #char "A" && it <= #char "Z" {
            lower[it_index] = it + 32;
        }
    }
    print("Lowercase: %\n", lower);
}

file_io_demo :: () {
    filename := "test_file.txt";
    content := "Hello from Jai!\nThis is a test file.\n";
    
    success := write_entire_file(filename, content);
    print("Write success: %\n", success);
    
    read_content := read_entire_file(filename);
    defer free(read_content);
    print("Read content:\n%", read_content);
    
    exists := file_exists(filename);
    print("File exists: %\n", exists);
    
    if exists {
        file_size, ok := file_get_size(filename);
        if ok print("File size: % bytes\n", file_size);
    }
    
    delete_file(filename);
    print("File deleted\n");
    
    dir := "test_dir";
    make_directory_if_it_does_not_exist(dir);
    print("Directory created: %\n", dir);
    
    files := file_list(dir);
    defer array_reset(*files);
    print("Files in directory: %\n", files);
    
    delete_directory(dir);
    print("Directory deleted\n");
}

time_demo :: () {
    now := current_time_monotonic();
    print("Monotonic time: % seconds\n", to_float64_seconds(now));
    
    wall_now := current_time_consensus();
    print("Wall clock: %\n", to_calendar(wall_now, .LOCAL));
    
    start := current_time_monotonic();
    
    sum := 0;
    for 0..1000000 sum += it;
    
    end := current_time_monotonic();
    elapsed := to_float64_seconds(end - start);
    print("Elapsed: % ms\n", elapsed * 1000);
    
    print("Sleeping for 100ms...\n");
    sleep_milliseconds(100);
    print("Done sleeping\n");
}

cli_demo :: () {
    args := get_command_line_arguments();
    print("Command: %\n", args[0]);
    print("Arguments (%):\n", args.count - 1);
    
    for 1..args.count-1 {
        print("  [%]: %\n", it, args[it]);
    }
    
    i := 1;
    while i < args.count {
        arg := args[i];
        if arg == "-h" || arg == "--help" {
            print("Usage: program [options]\n");
        } else if arg == "-v" || arg == "--verbose" {
            print("Verbose mode enabled\n");
        } else if starts_with(arg, "--size=") {
            size_str := slice(arg, 7, arg.count - 7);
            size := string_to_int(size_str);
            print("Size set to: %\n", size);
        } else {
            print("Unknown argument: %\n", arg);
        }
        i += 1;
    }
}

math_demo :: () {
    print("PI: %\n", PI);
    print("E: %\n", E);
    
    angle := PI / 4;
    print("sin(45°): %\n", sin(angle));
    print("cos(45°): %\n", cos(angle));
    
    print("exp(1): %\n", exp(1));
    print("log(e): %\n", log(E));
    print("log10(100): %\n", log10(100));
    
    print("pow(2, 10): %\n", pow(2, 10));
    print("sqrt(16): %\n", sqrt(16));
    
    print("floor(3.7): %\n", floor(3.7));
    print("ceil(3.2): %\n", ceil(3.2));
    print("round(3.5): %\n", round(3.5));
    
    print("min(5, 3): %\n", min(5, 3));
    print("max(5, 3): %\n", max(5, 3));
    print("clamp(15, 0, 10): %\n", clamp(15, 0, 10));
    
    print("abs(-42): %\n", abs(-42));
    
    v1 := Vector2.{3, 4};
    v2 := Vector2.{1, 2};
    
    print("\nv1: %\n", v1);
    print("v2: %\n", v2);
    print("v1 length: %\n", length(v1));
    print("v1 + v2: %\n", add(v1, v2));
    print("v1 dot v2: %\n", dot(v1, v2));
}

random_demo :: () {
    r := random_get();
    print("Random float: %\n", r);
    
    dice := random_int(1, 6);
    print("Dice roll: %\n", dice);
    
    temperature := random_float(20.0, 30.0);
    print("Random temperature: %\n", temperature);
    
    arr: [..]int;
    for 1..10 array_add(*arr, it);
    
    print("Before shuffle: %\n", arr);
    shuffle(*arr);
    print("After shuffle: %\n", arr);
    
    choices := string.["apple", "banana", "cherry"];
    choice := choices[random_int(0, choices.count - 1)];
    print("Random choice: %\n", choice);
}

hash_demo :: () {
    str := "Hello, World!";
    
    h := hash(str);
    print("Hash of '%': %\n", str, h);
    
    fnv_hash := fnv1a(str);
    print("FNV-1a hash: %\n", fnv_hash);
}

Vector2 :: struct {
    x: float;
    y: float;
}

length :: (v: Vector2) -> float {
    return sqrt(v.x * v.x + v.y * v.y);
}

add :: (a: Vector2, b: Vector2) -> Vector2 {
    return .{a.x + b.x, a.y + b.y};
}

dot :: (a: Vector2, b: Vector2) -> float {
    return a.x * b.x + a.y * b.y;
}

hash :: (s: string) -> u64 {
    h: u64 = 14695981039346656037;
    for s {
        h = h * 1099511628211;
        h = h ^ cast(u64) it;
    }
    return h;
}

fnv1a :: (s: string) -> u32 {
    h: u32 = 2166136261;
    for s {
        h = h ^ cast(u32) it;
        h = h * 16777619;
    }
    return h;
}

PI :: 3.14159265358979323846;
E :: 2.71828182845904523536;

#import "Basic";
#import "String";
#import "File";
#import "Thread";