diff options
| -rw-r--r-- | .gitignore | 1 | ||||
| -rw-r--r-- | Makefile | 21 | ||||
| -rw-r--r-- | README.md | 0 | ||||
| -rw-r--r-- | cmd/clock.go | 203 | ||||
| -rw-r--r-- | cmd/root.go | 18 | ||||
| -rw-r--r-- | go.mod | 20 | ||||
| -rw-r--r-- | go.sum | 27 | ||||
| -rw-r--r-- | main.go | 16 |
8 files changed, 306 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fb4efc6 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/term-clock diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..b390a3c --- /dev/null +++ b/Makefile @@ -0,0 +1,21 @@ +BIN := term-clock + +all: build + +.PHONY: run +run: build + ./$(BIN) + +.PHONY: build +build: $(BIN) + +$(BIN): main.go + go build -o $(BIN) + +.PHONY: fmt +fmt: + go fmt + +.PHONY: clean +clean: + go clean diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/README.md diff --git a/cmd/clock.go b/cmd/clock.go new file mode 100644 index 0000000..69c125d --- /dev/null +++ b/cmd/clock.go @@ -0,0 +1,203 @@ +package cmd + +import ( + "log" + "time" + + "github.com/gdamore/tcell/v2" + "github.com/spf13/cobra" +) + +func drawSquare(scr tcell.Screen, xOffset, yOffset, w, h int, style tcell.Style) { + for dx := 0; dx < w; dx++ { + x := xOffset + dx + for dy := 0; dy < h; dy++ { + y := yOffset + dy + scr.SetContent(x, y, ' ', nil, style) + } + } +} + +func drawNumber(scr tcell.Screen, n, xOffset, yOffset, squareW, squareH int, style tcell.Style) { + defs := [...][15]bool{ + { + true, true, true, + true, false, true, + true, false, true, + true, false, true, + true, true, true, + }, + { + false, false, true, + false, false, true, + false, false, true, + false, false, true, + false, false, true, + }, + { + true, true, true, + false, false, true, + true, true, true, + true, false, false, + true, true, true, + }, + { + true, true, true, + false, false, true, + true, true, true, + false, false, true, + true, true, true, + }, + { + true, false, true, + true, false, true, + true, true, true, + false, false, true, + false, false, true, + }, + { + true, true, true, + true, false, false, + true, true, true, + false, false, true, + true, true, true, + }, + { + true, true, true, + true, false, false, + true, true, true, + true, false, true, + true, true, true, + }, + { + true, true, true, + false, false, true, + false, false, true, + false, false, true, + false, false, true, + }, + { + true, true, true, + true, false, true, + true, true, true, + true, false, true, + true, true, true, + }, + { + true, true, true, + true, false, true, + true, true, true, + false, false, true, + true, true, true, + }, + } + + squares := defs[n] + for i, draw := range squares { + if !draw { + continue + } + x := i % 3 + y := i / 3 + drawSquare(scr, xOffset+squareW*x, yOffset+squareH*y, squareW, squareH, style) + } +} + +func drawClock(scr tcell.Screen, now time.Time, bgStyle, clockStyle tcell.Style) { + // Clear the entire screen. + scr.SetStyle(bgStyle) + scr.Clear() + + // Calculate square width/height and offset. + scrW, scrH := scr.Size() + // 17 + // <---------------> + // ### ### ### ### ^ + // # # # # # # # # # | + // # # # # # # # # | 5 + // # # # # # # # # # | + // ### ### ### ### v + squareW := scrW / (17 + 2) + squareH := scrH / (5 + 2) + if squareH > squareW { + squareH = squareW + } + if squareW > squareH*3/2 { + squareW = squareH * 3 / 2 + } + xOffset := (scrW - squareW*17) / 2 + yOffset := (scrH - squareH*5) / 2 + + // Hour + hour := now.Hour() + drawNumber(scr, hour/10, xOffset+squareW*0, yOffset, squareW, squareH, clockStyle) + drawNumber(scr, hour%10, xOffset+squareW*4, yOffset, squareW, squareH, clockStyle) + + // Colon + drawSquare(scr, xOffset+squareW*8, yOffset+squareH*1, squareW, squareH, clockStyle) + drawSquare(scr, xOffset+squareW*8, yOffset+squareH*3, squareW, squareH, clockStyle) + + // Minute + minute := now.Minute() + drawNumber(scr, minute/10, xOffset+squareW*10, yOffset, squareW, squareH, clockStyle) + drawNumber(scr, minute%10, xOffset+squareW*14, yOffset, squareW, squareH, clockStyle) +} + +func cmdClock(cmd *cobra.Command, args []string) { + bgStyle := tcell.StyleDefault.Background(tcell.ColorReset).Foreground(tcell.ColorReset) + clockStyle := tcell.StyleDefault.Foreground(tcell.ColorWhite).Background(tcell.ColorOlive) + + scr, err := tcell.NewScreen() + if err != nil { + log.Fatalf("%+v", err) + } + if err := scr.Init(); err != nil { + log.Fatalf("%+v", err) + } + defer scr.Fini() + + drawClock(scr, time.Now(), bgStyle, clockStyle) + + quitC := make(chan struct{}) + + go func() { + for { + scr.Show() + + ev := scr.PollEvent() + switch ev := ev.(type) { + case *tcell.EventResize: + drawClock(scr, time.Now(), bgStyle, clockStyle) + scr.Sync() + case *tcell.EventKey: + if ev.Key() == tcell.KeyEscape || ev.Key() == tcell.KeyCtrlC || ev.Rune() == 'q' { + close(quitC) + return + } + } + } + }() + + t := time.NewTicker(1 * time.Second) + defer t.Stop() + + prev := time.Now() + for { + select { + case <-quitC: + return + case now := <-t.C: + if now.Minute() != prev.Minute() { + drawClock(scr, now, bgStyle, clockStyle) + scr.Show() + prev = now + } + } + } +} + +var clockCmd =&cobra.Command{ + Use: "clock", + Short: "Clock mode", + Run: cmdClock, +} diff --git a/cmd/root.go b/cmd/root.go new file mode 100644 index 0000000..d0f9713 --- /dev/null +++ b/cmd/root.go @@ -0,0 +1,18 @@ +package cmd + +import ( + "github.com/spf13/cobra" +) + +var rootCmd = &cobra.Command{ + Use: "term-clock", + Short: "A clock on your terminal", +} + +func init() { + rootCmd.AddCommand(clockCmd) +} + +func Execute() error { + return rootCmd.Execute() +} @@ -0,0 +1,20 @@ +module github.com/nsfisis/term-clock + +go 1.18 + +require ( + github.com/gdamore/tcell/v2 v2.4.0 + github.com/spf13/cobra v1.6.1 +) + +require ( + github.com/gdamore/encoding v1.0.0 // indirect + github.com/inconshreveable/mousetrap v1.0.1 // indirect + github.com/lucasb-eyer/go-colorful v1.0.3 // indirect + github.com/mattn/go-runewidth v0.0.10 // indirect + github.com/rivo/uniseg v0.1.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect + golang.org/x/sys v0.0.0-20220422013727-9388b58f7150 // indirect + golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf // indirect + golang.org/x/text v0.3.0 // indirect +) @@ -0,0 +1,27 @@ +github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko= +github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg= +github.com/gdamore/tcell/v2 v2.4.0 h1:W6dxJEmaxYvhICFoTY3WrLLEXsQ11SaFnKGVEXW57KM= +github.com/gdamore/tcell/v2 v2.4.0/go.mod h1:cTTuF84Dlj/RqmaCIV5p4w8uG1zWdk0SF6oBpwHp4fU= +github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc= +github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/lucasb-eyer/go-colorful v1.0.3 h1:QIbQXiugsb+q10B+MI+7DI1oQLdmnep86tWFlaaUAac= +github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= +github.com/mattn/go-runewidth v0.0.10 h1:CoZ3S2P7pvtP45xOtBw+/mDL2z0RKI576gSkzRRpdGg= +github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= +github.com/rivo/uniseg v0.1.0 h1:+2KBaVoUmb9XzDsrx/Ct0W/EYOSFf/nWTauy++DprtY= +github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA= +github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20220422013727-9388b58f7150 h1:xHms4gcpe1YE7A3yIllJXP16CMAGuqwO2lX1mTyyRRc= +golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf h1:MZ2shdL+ZM/XzY3ZGOnh4Nlpnxz5GSOhOmtHo3iPU6M= +golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= @@ -0,0 +1,16 @@ +package main + +import ( + "fmt" + "os" + + "github.com/nsfisis/term-clock/cmd" +) + +func main() { + err := cmd.Execute() + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } +} |
