Flashcard CLI app in Golang This is a simple flashcard app. With flags to control the sides of the flashcards and the number of flashcards in the session.

All the flashcards without any input at the prompt, are deleted from the map. And ones with an input, remain. The idea is that, the user marks the flashcard that they want to revise in case they had forgotten it, later in the session.

The outer loop, loops until the length of the map is &gt;= 1

package main

import (
    "encoding/csv"
    "flag"
    "fmt"
    "log"
    "math/rand"
    "os"
    "os/exec"
    "runtime"
    "time"

    "github.com/fatih/color"
)

var (
    flagNoColor = flag.Bool("no-color", false, "disable color output")
    csvPath = flag.String("src", "src.csv", "source")
    side = flag.Int("s", -1, "side")
    num = flag.Int("n", -1, "number")
)

var clear map[string]func()

func init() {
    clear = make(map[string]func())
        clear["linux"] = func() {
        cmd := exec.Command("clear")
        cmd.Stdout = os.Stdout
        cmd.Run()
    }
    clear["windows"] = func() {
        cmd := exec.Command("cmd", "/c", "cls")
        cmd.Stdout = os.Stdout
        cmd.Run()
    }
}

func CallClear() {
    value, ok := clear[runtime.GOOS]
    if ok {
        value()
    } else {
        panic("Panic!")
    }
}

func random(min int, max int) int {
    return rand.Intn((max-min) + 1) + min
}

func main() {

    flag.Parse()

    file, err := os.Open(*csvPath)
    if err != nil {
        log.Println(err)
        return
    }
    defer file.Close()

    csvReader := csv.NewReader(file)

    csvData, err := csvReader.ReadAll()
    if err != nil {
        log.Println(err)
        return
    }

    qaRaw := make(map[string]string, len(csvData))
    for _, data := range csvData {
        qaRaw[data[0]] = data[1]
    }

    qaPair := make(map[string]string)

    if *num != -1 {
        i := 1
        for one, two := range qaRaw {
            if i &lt;= *num {
                qaPair[one] = two
            }
            i++
        }
    } else {
        for one, two := range qaRaw {
            qaPair[one] = two
        }
    }

    done := make(chan bool)

    go func() {
        if *flagNoColor {
            color.NoColor = true
        }
        white := color.New(color.FgWhite)
        boldWhite := white.Add(color.Bold)

        qNum := 0

        for len(qaPair) &gt;= 1 {
            for one, two := range qaPair {
                rand.Seed(time.Now().UnixNano())
                randomNum := random(1, 2)
                if *side != -1 {
                    randomNum = *side
                }
                var userInput string
                CallClear()
                boldWhite.Printf("\n #\t%d / %d\n", qNum+1, qNum+len(qaPair))
                qNum++
                if randomNum == 1 {
                    boldWhite.Printf("\n Q\t%s", one)
                    fmt.Scanln(&amp;userInput)
                    boldWhite.Printf("\n A\t%s", two)
                    fmt.Scanln(&amp;userInput)
                    if len(userInput) == 0 {
                        delete(qaPair, one)
                    }
                } else if randomNum == 2 {
                    boldWhite.Printf("\n Q\t%s", two)
                    fmt.Scanln(&amp;userInput)
                    boldWhite.Printf("\n A\t%s", one)
                    fmt.Scanln(&amp;userInput)
                    if len(userInput) == 0 {
                        delete(qaPair, one)
                    }
                }
                CallClear()
            }
        }
        done &lt;- true
    }()

    select {
        case &lt;-done:
            fmt.Println("blah blah blah")
    }

}


Flashcards example data (.csv file)

"hola","hi"
"sí","yes"
"¿qué pasa?","what's up?"
"¡vamos!","let's go!"
"¡salud!","cheers!; bless you!"
"no","no"
"por favor","please"
"lo siento","I'm sorry"
"buenos días","good morning"
"buenas noches","good night"
"gracias","thank you"
"vale","okay"
"hasta luego","see you later"
"adiós","goodbye"
"cómo","how (questions)"
var clear map[string]func()

To handle OS specific implementations you may consider using Golang tags feature. See it in action:

flashcard_windows.go

// +build windows

package main

import(
    "os"
    "os/exec"
)

func Clear() {
    cmd := exec.Command("cmd", "/c", "cls")
    cmd.Stdout = os.Stdout
    cmd.Run()
}


flashcard_unix.go

// +build linux

package main

import(
    "os"
    "os/exec"
)

func Clear() {
    cmd := exec.Command("clear")
    cmd.Stdout = os.Stdout
    cmd.Run()
}


To build run go build with -tags windows or -tags linux arguments.

Now there is no need call panic(). go build will exit if implementation of Clear function is missing.

See this for more information.