typetui 0.2.0

A terminal-based typing test.
Documentation
package main

import (
    "context"
    "fmt"
    "time"
)

func BufferedChannelExample() {
    ch := make(chan int, 3)
    ch <- 1
    ch <- 2
    ch <- 3

    fmt.Println(<-ch)
    fmt.Println(<-ch)
    fmt.Println(<-ch)
}

func CloseChannelExample() {
    ch := make(chan int, 5)
    go func() {
        for i := 0; i < 5; i++ {
            ch <- i
        }
        close(ch)
    }()

    for val := range ch {
        fmt.Println("Received:", val)
    }
}

func SelectExample() {
    ch1 := make(chan string)
    ch2 := make(chan string)

    go func() {
        time.Sleep(100 * time.Millisecond)
        ch1 <- "message from channel 1"
    }()

    go func() {
        time.Sleep(200 * time.Millisecond)
        ch2 <- "message from channel 2"
    }()

    select {
    case msg := <-ch1:
        fmt.Println(msg)
    case msg := <-ch2:
        fmt.Println(msg)
    case <-time.After(150 * time.Millisecond):
        fmt.Println("timeout")
    }
}

func FanOutFanIn() {
    input := make(chan int)
    output1 := make(chan int)
    output2 := make(chan int)

    go func() {
        for i := 0; i < 10; i++ {
            input <- i
        }
        close(input)
    }()

    worker := func(in <-chan int, out chan<- int, factor int) {
        for val := range in {
            out <- val * factor
        }
        close(out)
    }

    go worker(input, output1, 2)
    go worker(input, output2, 3)

    for val := range output1 {
        fmt.Println("Worker 1:", val)
    }
}

func PipelinePattern() {
    generator := func(nums ...int) <-chan int {
        out := make(chan int)
        go func() {
            for _, n := range nums {
                out <- n
            }
            close(out)
        }()
        return out
    }

    square := func(in <-chan int) <-chan int {
        out := make(chan int)
        go func() {
            for n := range in {
                out <- n * n
            }
            close(out)
        }()
        return out
    }

    printer := func(in <-chan int) {
        for n := range in {
            fmt.Println(n)
        }
    }

    nums := generator(2, 3, 4, 5)
    squared := square(nums)
    printer(squared)
}

func ContextCancellation() {
    ctx, cancel := context.WithCancel(context.Background())

    go func() {
        time.Sleep(2 * time.Second)
        cancel()
    }()

    select {
    case <-ctx.Done():
        fmt.Println("Cancelled:", ctx.Err())
    case <-time.After(3 * time.Second):
        fmt.Println("Completed normally")
    }
}

func ContextTimeout() {
    ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
    defer cancel()

    select {
    case <-time.After(2 * time.Second):
        fmt.Println("Slow operation completed")
    case <-ctx.Done():
        fmt.Println("Timed out:", ctx.Err())
    }
}

func ContextWithValue() {
    type key string
    ctx := context.WithValue(context.Background(), key("userID"), "12345")

    if val := ctx.Value(key("userID")); val != nil {
        fmt.Println("User ID:", val)
    }
}

func NonBlockingSend(ch chan<- int, val int) bool {
    select {
    case ch <- val:
        return true
    default:
        return false
    }
}

func NonBlockingRecv(ch <-chan int) (int, bool) {
    select {
    case val := <-ch:
        return val, true
    default:
        return 0, false
    }
}

func TickerExample() {
    ticker := time.NewTicker(500 * time.Millisecond)
    defer ticker.Stop()

    done := make(chan bool)
    go func() {
        time.Sleep(2 * time.Second)
        done <- true
    }()

    for {
        select {
        case <-done:
            fmt.Println("Done!")
            return
        case t := <-ticker.C:
            fmt.Println("Tick at", t)
        }
    }
}

func Debounce(input <-chan string, duration time.Duration) <-chan string {
    output := make(chan string)
    go func() {
        var timer *time.Timer
        var last string
        for msg := range input {
            last = msg
            if timer != nil {
                timer.Stop()
            }
            timer = time.AfterFunc(duration, func() {
                output <- last
            })
        }
        close(output)
    }()
    return output
}

func main() {
    BufferedChannelExample()
    CloseChannelExample()
    SelectExample()
}