Added -t
This commit is contained in:
parent
0d80fcf494
commit
a233c26e00
17
tt.go
17
tt.go
@ -9,6 +9,7 @@ import (
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gdamore/tcell"
|
||||
"github.com/mattn/go-isatty"
|
||||
@ -57,10 +58,10 @@ func exit() {
|
||||
}
|
||||
|
||||
func showReport(scr tcell.Screen, cpm, wpm int, accuracy float64) {
|
||||
report := fmt.Sprintf("WPM: %d\nCPM: %d\nAccuracy: %.2f%%\n", wpm, cpm, accuracy)
|
||||
report := fmt.Sprintf("WPM: %d\nCPM: %d\nAccuracy: %.2f%%", wpm, cpm, accuracy)
|
||||
|
||||
scr.Clear()
|
||||
drawCellsAtCenter(scr, stringToCells(report), -1)
|
||||
drawStringAtCenter(scr, report, tcell.StyleDefault)
|
||||
scr.HideCursor()
|
||||
scr.Show()
|
||||
|
||||
@ -79,15 +80,17 @@ func main() {
|
||||
var oneShotMode bool
|
||||
var wrapSz int
|
||||
var noSkip bool
|
||||
var timeout int
|
||||
var err error
|
||||
|
||||
flag.IntVar(&n, "n", 50, "The number of random words which constitute the test.")
|
||||
flag.IntVar(&wrapSz, "w", 80, "Wraps the input text at the given number of columns (ignored if -raw is present)")
|
||||
flag.IntVar(&wrapSz, "w", 80, "Wraps the input text at the given number of columns (ignored if -raw is present).")
|
||||
flag.IntVar(&timeout, "t", -1, "Terminate the test after the given number of seconds.")
|
||||
|
||||
flag.BoolVar(&noSkip, "noskip", false, "Disable word skipping when space is pressed.")
|
||||
flag.BoolVar(&csvMode, "csv", false, "Print the test results to stdout in the form <wpm>,<cpm>,<accuracy>.")
|
||||
flag.BoolVar(&rawMode, "raw", false, "Don't reflow text or show one paragraph at a time.")
|
||||
flag.BoolVar(&oneShotMode, "o", false, "Automatically exit after a single run.")
|
||||
flag.BoolVar(&oneShotMode, "o", false, "Automatically exit after a single run (useful for scripts).")
|
||||
|
||||
flag.Usage = func() {
|
||||
fmt.Println(`Usage: tt [options]
|
||||
@ -177,10 +180,12 @@ Options:`)
|
||||
if noSkip {
|
||||
typer.SkipWord = false
|
||||
}
|
||||
if timeout != -1 {
|
||||
timeout *= 1E9
|
||||
}
|
||||
|
||||
for {
|
||||
scr.Clear()
|
||||
nerrs, ncorrect, t, exitKey := typer.Start(contentFn())
|
||||
nerrs, ncorrect, t, exitKey := typer.Start(contentFn(), time.Duration(timeout))
|
||||
|
||||
switch exitKey {
|
||||
case 0:
|
||||
|
118
typer.go
118
typer.go
@ -2,6 +2,7 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/gdamore/tcell"
|
||||
@ -51,39 +52,49 @@ func (t *typer) highlight(text []cell, idx int, currentWordStyle, nextWordStyle
|
||||
}
|
||||
}
|
||||
|
||||
func (t *typer) Start(text []string) (nerrs, ncorrect int, tim time.Duration, exitKey tcell.Key) {
|
||||
var startTime time.Time
|
||||
func (t *typer) Start(text []string, timeout time.Duration) (nerrs, ncorrect int, duration time.Duration, exitKey tcell.Key) {
|
||||
timeLeft := timeout
|
||||
|
||||
for i, p := range text {
|
||||
startImmediately := true
|
||||
var d time.Duration
|
||||
var e, c int
|
||||
var fn func() = nil
|
||||
|
||||
if i == 0 {
|
||||
fn = func() {
|
||||
startTime = time.Now()
|
||||
}
|
||||
startImmediately = false
|
||||
}
|
||||
|
||||
e, c, exitKey = t.start(p, fn)
|
||||
e, c, exitKey, d = t.start(p, timeLeft, startImmediately)
|
||||
|
||||
nerrs += e
|
||||
ncorrect += c
|
||||
duration += d
|
||||
|
||||
if timeout != -1 {
|
||||
timeLeft -= d
|
||||
if timeLeft <= 0 {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if exitKey != 0 {
|
||||
tim = time.Now().Sub(startTime)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
tim = time.Now().Sub(startTime)
|
||||
exitKey = 0
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (t *typer) start(s string, onStart func()) (nerrs int, ncorrect int, exitKey tcell.Key) {
|
||||
started := false
|
||||
func (t *typer) start(s string, timeLimit time.Duration, startImmediately bool) (nerrs int, ncorrect int, exitKey tcell.Key, duration time.Duration) {
|
||||
|
||||
var startTime time.Time
|
||||
text := stringToCells(s)
|
||||
|
||||
nc, nr := calcStringDimensions(s)
|
||||
sw, sh := scr.Size()
|
||||
x := (sw - nc) / 2
|
||||
y := (sh - nr) / 2
|
||||
|
||||
for i, _ := range text {
|
||||
text[i].style = t.backgroundStyle
|
||||
}
|
||||
@ -98,11 +109,33 @@ func (t *typer) start(s string, onStart func()) (nerrs int, ncorrect int, exitKe
|
||||
idx := 0
|
||||
|
||||
redraw := func() {
|
||||
if timeLimit != -1 && !startTime.IsZero() {
|
||||
remaining := timeLimit - time.Now().Sub(startTime)
|
||||
drawString(t.Scr, x+nc/2, y+nr+1, strconv.Itoa(int(remaining/1E9)), -1, t.backgroundStyle)
|
||||
}
|
||||
|
||||
//Potentially inefficient, but seems to be good enough
|
||||
drawCellsAtCenter(t.Scr, text, idx)
|
||||
drawCells(t.Scr, x, y, text, idx)
|
||||
|
||||
t.Scr.Show()
|
||||
}
|
||||
|
||||
calcStats := func() {
|
||||
nerrs = 0
|
||||
ncorrect = 0
|
||||
|
||||
for _, c := range text {
|
||||
if c.style == t.incorrectStyle || c.style == t.incorrectSpaceStyle {
|
||||
nerrs++
|
||||
} else if c.style == t.correctStyle {
|
||||
ncorrect++
|
||||
}
|
||||
}
|
||||
|
||||
exitKey = 0
|
||||
duration = time.Now().Sub(startTime)
|
||||
}
|
||||
|
||||
deleteWord := func() {
|
||||
t.highlight(text, idx, t.backgroundStyle, t.backgroundStyle)
|
||||
|
||||
@ -129,6 +162,30 @@ func (t *typer) start(s string, onStart func()) (nerrs int, ncorrect int, exitKe
|
||||
t.highlight(text, idx, t.currentWordStyle, t.nextWordStyle)
|
||||
}
|
||||
|
||||
tickerCloser := make(chan bool)
|
||||
|
||||
//Inject nil events into the main event loop at regular invervals to force an update
|
||||
ticker := func() {
|
||||
for {
|
||||
select {
|
||||
case <-tickerCloser:
|
||||
return
|
||||
default:
|
||||
}
|
||||
|
||||
time.Sleep(time.Duration(1E8))
|
||||
t.Scr.PostEventWait(nil)
|
||||
}
|
||||
}
|
||||
|
||||
go ticker()
|
||||
defer close(tickerCloser)
|
||||
|
||||
if startImmediately {
|
||||
startTime = time.Now()
|
||||
}
|
||||
|
||||
t.Scr.Clear()
|
||||
for {
|
||||
t.highlight(text, idx, t.currentWordStyle, t.nextWordStyle)
|
||||
redraw()
|
||||
@ -139,13 +196,14 @@ func (t *typer) start(s string, onStart func()) (nerrs int, ncorrect int, exitKe
|
||||
case *tcell.EventResize:
|
||||
t.Scr.Sync()
|
||||
t.Scr.Clear()
|
||||
case *tcell.EventKey:
|
||||
if !started {
|
||||
if onStart != nil {
|
||||
onStart()
|
||||
}
|
||||
|
||||
started = true
|
||||
nc, nr = calcStringDimensions(s)
|
||||
sw, sh = scr.Size()
|
||||
x = (sw - nc) / 2
|
||||
y = (sh - nr) / 2
|
||||
case *tcell.EventKey:
|
||||
if startTime.IsZero() {
|
||||
startTime = time.Now()
|
||||
}
|
||||
|
||||
switch key := ev.Key(); key {
|
||||
@ -218,21 +276,17 @@ func (t *typer) start(s string, onStart func()) (nerrs int, ncorrect int, exitKe
|
||||
}
|
||||
|
||||
if idx == len(text) {
|
||||
nerrs = 0
|
||||
|
||||
for _, c := range text {
|
||||
if c.style == t.incorrectStyle || c.style == t.incorrectSpaceStyle {
|
||||
nerrs++
|
||||
}
|
||||
}
|
||||
|
||||
ncorrect = len(text) - nerrs
|
||||
exitKey = 0
|
||||
|
||||
t.Scr.Clear()
|
||||
calcStats()
|
||||
return
|
||||
}
|
||||
}
|
||||
default: //tick
|
||||
if timeLimit != -1 && !startTime.IsZero() && timeLimit <= time.Now().Sub(startTime) {
|
||||
calcStats()
|
||||
return
|
||||
}
|
||||
|
||||
redraw()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
56
util.go
56
util.go
@ -280,6 +280,28 @@ func stringToCells(s string) []cell {
|
||||
return a[:len]
|
||||
}
|
||||
|
||||
func drawString(scr tcell.Screen, x, y int, s string, cursorIdx int, style tcell.Style) {
|
||||
sx := x
|
||||
|
||||
for i, c := range s {
|
||||
if c == '\n' {
|
||||
y++
|
||||
x = sx
|
||||
} else {
|
||||
scr.SetContent(x, y, c, nil, style)
|
||||
if i == cursorIdx {
|
||||
scr.ShowCursor(x, y)
|
||||
}
|
||||
|
||||
x++
|
||||
}
|
||||
}
|
||||
|
||||
if cursorIdx == len(s) {
|
||||
scr.ShowCursor(x, y)
|
||||
}
|
||||
}
|
||||
|
||||
func drawCells(scr tcell.Screen, x, y int, s []cell, cursorIdx int) {
|
||||
sx := x
|
||||
|
||||
@ -302,16 +324,24 @@ func drawCells(scr tcell.Screen, x, y int, s []cell, cursorIdx int) {
|
||||
}
|
||||
}
|
||||
|
||||
func drawCellsAtCenter(scr tcell.Screen, s []cell, cursorIdx int) {
|
||||
rows := 0
|
||||
cols := 0
|
||||
func drawStringAtCenter(scr tcell.Screen, s string, style tcell.Style) {
|
||||
nc, nr := calcStringDimensions(s)
|
||||
sw, sh := scr.Size()
|
||||
|
||||
x := (sw - nc) / 2
|
||||
y := (sh - nr) / 2
|
||||
|
||||
drawString(scr, x, y, s, -1, style)
|
||||
}
|
||||
|
||||
func calcStringDimensions(s string) (nc, nr int) {
|
||||
c := 0
|
||||
|
||||
for _, x := range s {
|
||||
if x.c == '\n' {
|
||||
rows++
|
||||
if c > cols {
|
||||
cols = c
|
||||
if x == '\n' {
|
||||
nr++
|
||||
if c > nc {
|
||||
nc = c
|
||||
}
|
||||
c = 0
|
||||
} else {
|
||||
@ -319,16 +349,12 @@ func drawCellsAtCenter(scr tcell.Screen, s []cell, cursorIdx int) {
|
||||
}
|
||||
}
|
||||
|
||||
rows++
|
||||
if c > cols {
|
||||
cols = c
|
||||
nr++
|
||||
if c > nc {
|
||||
nc = c
|
||||
}
|
||||
|
||||
w, h := scr.Size()
|
||||
x := (w - cols) / 2
|
||||
y := (h - rows) / 2
|
||||
|
||||
drawCells(scr, x, y, s, cursorIdx)
|
||||
return
|
||||
}
|
||||
|
||||
func newTcellColor(s string) tcell.Color {
|
||||
|
Loading…
x
Reference in New Issue
Block a user