aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile6
-rw-r--r--go.mod1
-rw-r--r--go.sum3
-rw-r--r--golings/cmd/print.go72
-rw-r--r--golings/cmd/root.go1
-rw-r--r--golings/cmd/run.go34
-rw-r--r--golings/cmd/watch.go96
7 files changed, 199 insertions, 14 deletions
diff --git a/Makefile b/Makefile
index 020bc08..5202e86 100644
--- a/Makefile
+++ b/Makefile
@@ -1,2 +1,8 @@
test:
@cd golings && go test -coverprofile=coverage.out -v $$(go list ./... | grep -v fixtures/error1)
+
+watch:
+ @go run golings/golings.go watch
+
+run:
+ @go run golings/golings.go run \ No newline at end of file
diff --git a/go.mod b/go.mod
index 8eb942f..631f5d9 100644
--- a/go.mod
+++ b/go.mod
@@ -4,6 +4,7 @@ go 1.19
require (
github.com/fatih/color v1.13.0
+ github.com/fsnotify/fsnotify v1.6.0
github.com/jedib0t/go-pretty/v6 v6.4.0
github.com/onsi/ginkgo/v2 v2.5.0
github.com/onsi/gomega v1.24.0
diff --git a/go.sum b/go.sum
index 34fa4e5..0a43d31 100644
--- a/go.sum
+++ b/go.sum
@@ -4,6 +4,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
+github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
+github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
@@ -59,6 +61,7 @@ golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.1.0 h1:g6Z6vPFA9dYBAF7DWcH6sCcOntplXsDKcliusYijMlw=
diff --git a/golings/cmd/print.go b/golings/cmd/print.go
new file mode 100644
index 0000000..c5565c7
--- /dev/null
+++ b/golings/cmd/print.go
@@ -0,0 +1,72 @@
+package cmd
+
+import (
+ "os"
+ "os/exec"
+ "runtime"
+
+ "github.com/fatih/color"
+ "github.com/mauricioabreu/golings/golings/exercises"
+ "github.com/mauricioabreu/golings/golings/ui"
+)
+
+func PrintHint(infoFile string) {
+ ClearScreen()
+ exercise, err := exercises.NextPending(infoFile)
+ if err != nil {
+ color.Red("Failed to find next exercises")
+ }
+ color.Yellow(exercise.Hint)
+}
+
+func PrintList(infoFile string) {
+ ClearScreen()
+ exs, err := exercises.List(infoFile)
+ if err != nil {
+ color.Red("Failed to list exercises")
+ }
+ ui.PrintList(os.Stdout, exs)
+}
+
+func RunNextExercise(infoFile string) {
+ ClearScreen()
+ exercise, err := exercises.NextPending(infoFile)
+ if err != nil {
+ color.Red("Failed to find next exercises")
+ }
+
+ result, err := exercise.Run()
+ if err != nil {
+ color.Cyan("Failed to compile the exercise %s\n\n", result.Exercise.Path)
+ color.White("Check the output below: \n\n")
+ color.Red(result.Err)
+ color.Red(result.Out)
+ color.Yellow("If you feel stuck, ask a hint by executing `golings hint %s`", result.Exercise.Name)
+ } else {
+ color.Green("Congratulations!\n\n")
+ color.Green("Here is the output of your program:\n\n")
+ color.Cyan(result.Out)
+ if result.Exercise.State() == exercises.Pending {
+ color.White("Remove the 'I AM NOT DONE' from the file to keep going\n")
+ color.Red("exercise is still pending")
+ }
+ }
+}
+
+func ClearScreen() {
+ if runtime.GOOS == "windows" {
+ cmd := exec.Command("cmd", "/c", "cls")
+ cmd.Stdout = os.Stdout
+ err := cmd.Run()
+ if err != nil {
+ color.Red("Clear terminal command error")
+ }
+ } else {
+ cmd := exec.Command("clear")
+ cmd.Stdout = os.Stdout
+ err := cmd.Run()
+ if err != nil {
+ color.Red("Clear terminal command error")
+ }
+ }
+}
diff --git a/golings/cmd/root.go b/golings/cmd/root.go
index 4f79311..23b4583 100644
--- a/golings/cmd/root.go
+++ b/golings/cmd/root.go
@@ -19,6 +19,7 @@ func NewRootCmd(version string) *cobra.Command {
rootCmd.AddCommand(ListCmd("info.toml"))
rootCmd.AddCommand(RunCmd("info.toml"))
rootCmd.AddCommand(VerifyCmd("info.toml"))
+ rootCmd.AddCommand(WatchCmd("info.toml"))
return rootCmd
}
diff --git a/golings/cmd/run.go b/golings/cmd/run.go
index 552c234..7d5fef8 100644
--- a/golings/cmd/run.go
+++ b/golings/cmd/run.go
@@ -27,20 +27,7 @@ func RunCmd(infoFile string) *cobra.Command {
exercise, err = exercises.Find(args[0], infoFile)
}
- spinner := progressbar.NewOptions(
- -1, // a negative number makes turns the progress bar into a spinner
- progressbar.OptionEnableColorCodes(true),
- progressbar.OptionSetDescription(color.WhiteString("Running exercise: %s", exercise.Name)),
- progressbar.OptionOnCompletion(func() {
- color.White("\nRunning complete!\n\n")
- }),
- )
- go func() {
- for x := 0; x < 100; x++ {
- spinner.Add(1) // nolint
- time.Sleep(250 * time.Millisecond)
- }
- }()
+ spinner := RunSpinner(exercise.Name)
if errors.Is(err, exercises.ErrExerciseNotFound) {
color.White("No exercise found for '%s'", args[0])
@@ -71,3 +58,22 @@ func RunCmd(infoFile string) *cobra.Command {
},
}
}
+
+func RunSpinner(exercise string) *progressbar.ProgressBar {
+ spinner := progressbar.NewOptions(
+ -1, // a negative number makes turns the progress bar into a spinner
+ progressbar.OptionEnableColorCodes(true),
+ progressbar.OptionSetDescription(color.WhiteString("Running exercise: %s", exercise)),
+ progressbar.OptionOnCompletion(func() {
+ color.White("\nRunning complete!\n\n")
+ }),
+ )
+ go func() {
+ for x := 0; x < 100; x++ {
+ spinner.Add(1) // nolint
+ time.Sleep(250 * time.Millisecond)
+ }
+ }()
+
+ return spinner
+}
diff --git a/golings/cmd/watch.go b/golings/cmd/watch.go
new file mode 100644
index 0000000..4693e3f
--- /dev/null
+++ b/golings/cmd/watch.go
@@ -0,0 +1,96 @@
+package cmd
+
+import (
+ "bufio"
+ "fmt"
+ "io/fs"
+ "log"
+ "os"
+ "path/filepath"
+ "strings"
+
+ "github.com/fatih/color"
+ "github.com/fsnotify/fsnotify"
+ "github.com/spf13/cobra"
+)
+
+func WatchCmd(infoFile string) *cobra.Command {
+ return &cobra.Command{
+ Use: "watch",
+ Short: "Run a single exercise",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ RunNextExercise(infoFile)
+ reader := bufio.NewReader(os.Stdin)
+ update := make(chan string)
+
+ go WatchEvents(update)
+
+ for {
+ go func() {
+ for range update {
+ RunNextExercise(infoFile)
+ }
+ }()
+
+ cmdString, err := reader.ReadString('\n')
+ if err != nil {
+ fmt.Fprintln(os.Stderr, err)
+ }
+ cmdStr := strings.TrimSuffix(cmdString, "\n")
+
+ switch cmdStr {
+ case "list":
+ PrintList(infoFile)
+ case "hint":
+ PrintHint(infoFile)
+ case "quit":
+ color.Green("Bye by golings o/")
+ os.Exit(0)
+ case "q":
+ color.Green("Bye by golings o/")
+ os.Exit(0)
+ case "exit":
+ color.Green("Bye by golings o/")
+ os.Exit(0)
+ default:
+ color.Yellow("only list or hint command are avaliable")
+ }
+ }
+ },
+ }
+}
+
+func WatchEvents(updateF chan<- string) {
+ watcher, err := fsnotify.NewWatcher()
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ path, _ := os.Getwd()
+ directories := fmt.Sprintf("%s/exercises", path)
+
+ err = filepath.WalkDir(directories, func(path_dir string, d fs.DirEntry, err error) error {
+ if err != nil {
+ log.Fatal(err)
+ return err
+ }
+ if d.IsDir() {
+ err = watcher.Add(path_dir)
+
+ if err != nil {
+ log.Fatal(err)
+ }
+ }
+ return nil
+ })
+
+ if err != nil {
+ log.Fatal("Error in file path:", err.Error())
+ }
+
+ for event := range watcher.Events {
+ if event.Has(fsnotify.Write) {
+ updateF <- event.Name
+ }
+ }
+}