gosuri / uilive

uilive is a go library for updating terminal output in realtime
MIT License
1.7k stars 87 forks source link

Outputting to multiple lines #14

Closed g3kk0 closed 5 years ago

g3kk0 commented 7 years ago

This is more a question than an issue.

I'd like to output and update the status of a list of tasks:

e.g.

Task1... Done
Task2... Done
Task3... Running
Task4... 

I've attempted to do this using multiple Fprintf statements as follows:

w := uilive.New()
w.Start()

for i := 0; i <= 60; i++ {
  var t1, t2, t3, t4 string

  if i > 2 {
    t1 = "Done     "
    t2 = "Running"
  }
  if i > 5 {
    t1 = "Done     "
    t2 = "Done     "
    t3 = "Running"
  }
  if i > 7 {
    t1 = "Done     "
    t2 = "Done     "
    t3 = "Done     "
    t4 = "Running"
  }
  if i > 9 {
    t1 = "Done     "
    t2 = "Done     "
    t3 = "Done     "
    t4 = "Done     "
  }

  fmt.Fprintf(w, "Task1...  %s\n", t1)
  fmt.Fprintf(w, "Task2...  %s\n", t2)
  fmt.Fprintf(w, "Task3...  %s\n", t3)
  fmt.Fprintf(w, "Task4...  %s\n", t4)
  time.Sleep(time.Second)
}

w.Stop()

This initially appears to work fine however on some iterations various tasks disappear and then reappear.

e.g.

# I get this
Task3...  Done
Task4...  Done

# instead of
Task1...  Done
Task2...  Done
Task3...  Done
Task4...  Done

Am I using this incorrectly or could this possibly be a bug?

g3kk0 commented 7 years ago

For some reason adding this seems to help:

w.RefreshInterval = 1000

Could this be related to gosuri/uilive#9

g3kk0 commented 7 years ago

The solution to this was to only use a single call to the writer:

for i := 0; i <= 60; i++ {
  fmt.Fprintf(writer,
    "Task1...  %s\n"+
    "Task2...  %s\n"+
    "Task3...  %s\n"+
    "Task4...  %s\n",
    t1, t2, t3, t4, t5, t6)
  time.Sleep(time.Second)
}
asahasrabuddhe commented 5 years ago

Hello @g3kk0 ,

I have managed to implement this feature back on my fork. I will be doing a PR soon for @gosuri to review and merge. Until that time, you can feel free to use my fork :)

Here's the code that I am using:

    //start listening for updates and render
    writer.Start()

    for i := 0; i <= 100; i++ {
        var t1, t2, t3, t4 string

        t1 = "Running"

        if i > 20 {
            t1 = "Done"
            t2 = "Running"
        }
        if i > 50 {
            t1 = "Done"
            t2 = "Done"
            t3 = "Running"
        }
        if i > 70 {
            t1 = "Done"
            t2 = "Done"
            t3 = "Done"
            t4 = "Running"
        }
        if i > 90 {
            t1 = "Done"
            t2 = "Done"
            t3 = "Done"
            t4 = "Done"
        }

        _, _ = fmt.Fprintf(writer, "Task1...  %s\n", t1)
        _, _ = fmt.Fprintf(writer.Newline(), "Task2...  %s\n", t2)
        _, _ = fmt.Fprintf(writer.Newline(), "Task3...  %s\n", t3)
        _, _ = fmt.Fprintf(writer.Newline(), "Task4...  %s\n", t4)
        time.Sleep(time.Millisecond * 100)
    }
    _, _ = fmt.Fprintln(writer, "Finished")
    writer.Stop() // flush and stop rendering

and this is the output for the same

render1554955255840-min