Skip to content

Instantly share code, notes, and snippets.

@ezr
Last active October 3, 2022 20:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ezr/6c7a9d4d880b5ea489d726b693cf28bd to your computer and use it in GitHub Desktop.
Save ezr/6c7a9d4d880b5ea489d726b693cf28bd to your computer and use it in GitHub Desktop.
A CLI stopwatch
package main
import (
"fmt"
"os"
"time"
"github.com/gdamore/tcell/v2"
"github.com/ltcsuite/lnd/ticker"
"github.com/mattn/go-runewidth"
)
func emitStr(s tcell.Screen, x, y int, style tcell.Style, str string) {
for _, c := range str {
var comb []rune
w := runewidth.RuneWidth(c)
if w == 0 {
comb = []rune{c}
c = ' '
w = 1
}
s.SetContent(x, y, c, comb, style)
x += w
}
}
func displayTime(time string, s tcell.Screen) {
w, h := s.Size()
s.Clear()
style := tcell.StyleDefault
emitStr(s, w/2-7, h/2, style, time)
emitStr(s, w/2-9, h/2+2, style, "Press ENTER to toggle pause.")
emitStr(s, w/2-9, h/2+3, style, "Press ESC to exit.")
s.Show()
}
func formatSecs(i int) string {
// takes a number of seconds and returns it formatted as hh:mm:ss
// after 100 hours it will start to be like: hhh:mm:ss
hours := i / 3600
hoursRemainder := i % 3600
minutes := hoursRemainder / 60
seconds := hoursRemainder % 60
return fmt.Sprintf("%02d:%02d:%02d", hours, minutes, seconds)
}
func main() {
tcell.SetEncodingFallback(tcell.EncodingFallbackASCII)
s, e := tcell.NewScreen()
if e != nil {
fmt.Fprintf(os.Stderr, "%v\n", e)
os.Exit(1)
}
if e = s.Init(); e != nil {
fmt.Fprintf(os.Stderr, "%v\n", e)
os.Exit(1)
}
s.Clear()
quit := make(chan struct{})
pause := make(chan bool)
ispaused := false
go func() {
for {
ev := s.PollEvent()
switch ev := ev.(type) {
case *tcell.EventKey:
if (ev.Key() == tcell.KeyEscape) || (ev.Rune() == 'q') {
if ispaused {
// we need to unpause first, otherwise the program will lock up
pause <- false
}
close(quit)
return
} else if ev.Key() == tcell.KeyCtrlL {
s.Sync()
} else if (ev.Key() == tcell.KeyEnter) || (ev.Rune() == ' ') {
ispaused = !ispaused
pause <- ispaused
}
case *tcell.EventResize:
s.Sync()
}
}
}()
var i = 0
var ts = formatSecs(0)
displayTime(ts, s)
var timeTicker = ticker.New(time.Second)
timeTicker.Resume() // newly created variable is paused
loop:
for {
select {
case <-quit:
break loop
case <-pause:
timeTicker.Pause()
// block until we get another message in the pause channel
<-pause
timeTicker.Resume()
case <-timeTicker.Ticks():
i++
ts = formatSecs(i)
displayTime(ts, s)
}
}
s.Fini()
fmt.Println(ts)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment