~ghost08/wt

4d750268a619a3f8fa319cc118f275777cfaa9e2 — Vladimír Magyar 7 months ago b069041 master
chore: update dependencies
7 files changed, 146 insertions(+), 59 deletions(-)

M entries.go
M go.mod
M go.sum
M lexer.go
M main.go
M report.go
M send_report.go
M entries.go => entries.go +3 -3
@@ 18,9 18,9 @@ type Entry struct {
	End         time.Time
}

//Compare returns -1 if f is before e
//0 if f overlaps e
//1 if f is after e
// Compare returns -1 if f is before e
// 0 if f overlaps e
// 1 if f is after e
func (e Entry) Compare(f Entry) int {
	if f.Start.Before(e.Start) && f.End.Before(e.Start) {
		return -1

M go.mod => go.mod +16 -8
@@ 1,25 1,33 @@
module git.sr.ht/~ghost08/wt

go 1.18
go 1.20

require (
	github.com/360EntSecGroup-Skylar/excelize v1.4.1
	github.com/alecthomas/kong v0.5.0
	github.com/emersion/go-message v0.15.0
	github.com/emersion/go-sasl v0.0.0-20211008083017-0b9dcfb154ac
	github.com/emersion/go-smtp v0.15.0
	github.com/gookit/color v1.5.0
	github.com/alecthomas/kong v0.7.1
	github.com/charmbracelet/lipgloss v0.6.0
	github.com/emersion/go-message v0.16.0
	github.com/emersion/go-sasl v0.0.0-20220912192320-0145f2c60ead
	github.com/emersion/go-smtp v0.16.0
	github.com/gookit/color v1.5.2
	github.com/posener/complete/v2 v2.0.1-alpha.13
	github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966
)

require (
	github.com/aymanbagabas/go-osc52 v1.2.1 // indirect
	github.com/emersion/go-textwrapper v0.0.0-20200911093747-65d896831594 // indirect
	github.com/hashicorp/errwrap v1.1.0 // indirect
	github.com/hashicorp/go-multierror v1.1.1 // indirect
	github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
	github.com/mattn/go-isatty v0.0.17 // indirect
	github.com/mattn/go-runewidth v0.0.14 // indirect
	github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
	github.com/muesli/reflow v0.3.0 // indirect
	github.com/muesli/termenv v0.13.0 // indirect
	github.com/pkg/errors v0.9.1 // indirect
	github.com/posener/script v1.1.5 // indirect
	github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect
	golang.org/x/sys v0.0.0-20220406163625-3f8b81556e12 // indirect
	github.com/rivo/uniseg v0.4.3 // indirect
	github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
	golang.org/x/sys v0.4.0 // indirect
)

M go.sum => go.sum +54 -0
@@ 4,30 4,68 @@ github.com/alecthomas/kong v0.3.0 h1:qOLFzu0dGPNz8z5TiXGzgW3gb3RXfWVJKeAxcghVW88
github.com/alecthomas/kong v0.3.0/go.mod h1:uzxf/HUh0tj43x1AyJROl3JT7SgsZ5m+icOv1csRhc0=
github.com/alecthomas/kong v0.5.0 h1:u8Kdw+eeml93qtMZ04iei0CFYve/WPcA5IFh+9wSskE=
github.com/alecthomas/kong v0.5.0/go.mod h1:uzxf/HUh0tj43x1AyJROl3JT7SgsZ5m+icOv1csRhc0=
github.com/alecthomas/kong v0.7.1 h1:azoTh0IOfwlAX3qN9sHWTxACE2oV8Bg2gAwBsMwDQY4=
github.com/alecthomas/kong v0.7.1/go.mod h1:n1iCIO2xS46oE8ZfYCNDqdR0b0wZNrXAIAqro/2132U=
github.com/alecthomas/repr v0.0.0-20210801044451-80ca428c5142 h1:8Uy0oSf5co/NZXje7U1z8Mpep++QJOldL2hs/sBQf48=
github.com/alecthomas/repr v0.0.0-20210801044451-80ca428c5142/go.mod h1:2kn6fqh/zIyPLmm3ugklbEi5hg5wS435eygvNfaDQL8=
github.com/aymanbagabas/go-osc52 v1.0.3/go.mod h1:zT8H+Rk4VSabYN90pWyugflM3ZhpTZNC7cASDfUCdT4=
github.com/aymanbagabas/go-osc52 v1.2.1 h1:q2sWUyDcozPLcLabEMd+a+7Ea2DitxZVN9hTxab9L4E=
github.com/aymanbagabas/go-osc52 v1.2.1/go.mod h1:zT8H+Rk4VSabYN90pWyugflM3ZhpTZNC7cASDfUCdT4=
github.com/charmbracelet/lipgloss v0.5.0 h1:lulQHuVeodSgDez+3rGiuxlPVXSnhth442DATR2/8t8=
github.com/charmbracelet/lipgloss v0.5.0/go.mod h1:EZLha/HbzEt7cYqdFPovlqy5FZPj0xFhg5SaqxScmgs=
github.com/charmbracelet/lipgloss v0.6.0 h1:1StyZB9vBSOyuZxQUcUwGr17JmojPNm87inij9N3wJY=
github.com/charmbracelet/lipgloss v0.6.0/go.mod h1:tHh2wr34xcHjC2HCXIlGSG1jaDF0S0atAUvBMP6Ppuk=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
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/emersion/go-message v0.15.0 h1:urgKGqt2JAc9NFJcgncQcohHdiYb803YTH9OQwHBHIY=
github.com/emersion/go-message v0.15.0/go.mod h1:wQUEfE+38+7EW8p8aZ96ptg6bAb1iwdgej19uXASlE4=
github.com/emersion/go-message v0.16.0 h1:uZLz8ClLv3V5fSFF/fFdW9jXjrZkXIpE1Fn8fKx7pO4=
github.com/emersion/go-message v0.16.0/go.mod h1:pDJDgf/xeUIF+eicT6B/hPX/ZbEorKkUMPOxrPVG2eQ=
github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21/go.mod h1:iL2twTeMvZnrg54ZoPDNfJaJaqy0xIQFuBdrLsmspwQ=
github.com/emersion/go-sasl v0.0.0-20211008083017-0b9dcfb154ac h1:tn/OQ2PmwQ0XFVgAHfjlLyqMewry25Rz7jWnVoh4Ggs=
github.com/emersion/go-sasl v0.0.0-20211008083017-0b9dcfb154ac/go.mod h1:iL2twTeMvZnrg54ZoPDNfJaJaqy0xIQFuBdrLsmspwQ=
github.com/emersion/go-sasl v0.0.0-20220912192320-0145f2c60ead h1:fI1Jck0vUrXT8bnphprS1EoVRe2Q5CKCX8iDlpqjQ/Y=
github.com/emersion/go-sasl v0.0.0-20220912192320-0145f2c60ead/go.mod h1:iL2twTeMvZnrg54ZoPDNfJaJaqy0xIQFuBdrLsmspwQ=
github.com/emersion/go-smtp v0.15.0 h1:3+hMGMGrqP/lqd7qoxZc1hTU8LY8gHV9RFGWlqSDmP8=
github.com/emersion/go-smtp v0.15.0/go.mod h1:qm27SGYgoIPRot6ubfQ/GpiPy/g3PaZAVRxiO/sDUgQ=
github.com/emersion/go-smtp v0.16.0 h1:eB9CY9527WdEZSs5sWisTmilDX7gG+Q/2IdRcmubpa8=
github.com/emersion/go-smtp v0.16.0/go.mod h1:qm27SGYgoIPRot6ubfQ/GpiPy/g3PaZAVRxiO/sDUgQ=
github.com/emersion/go-textwrapper v0.0.0-20200911093747-65d896831594 h1:IbFBtwoTQyw0fIM5xv1HF+Y+3ZijDR839WMulgxCcUY=
github.com/emersion/go-textwrapper v0.0.0-20200911093747-65d896831594/go.mod h1:aqO8z8wPrjkscevZJFVE1wXJrLpC5LtJG7fqLOsPb2U=
github.com/gookit/color v1.5.0 h1:1Opow3+BWDwqor78DcJkJCIwnkviFi+rrOANki9BUFw=
github.com/gookit/color v1.5.0/go.mod h1:43aQb+Zerm/BWh2GnrgOQm7ffz7tvQXEKV6BFMl7wAo=
github.com/gookit/color v1.5.2 h1:uLnfXcaFjlrDnQDT+NCBcfhrXqYTx/rcCa6xn01Y8yI=
github.com/gookit/color v1.5.2/go.mod h1:w8h4bGiHeeBpvQVePTutdbERIUf3oJE5lZ8HM0UgXyg=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU=
github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw=
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
github.com/muesli/reflow v0.2.1-0.20210115123740-9e1d0d53df68 h1:y1p/ycavWjGT9FnmSjdbWUlLGvcxrY0Rw3ATltrxOhk=
github.com/muesli/reflow v0.2.1-0.20210115123740-9e1d0d53df68/go.mod h1:Xk+z4oIWdQqJzsxyjgl3P22oYZnHdZ8FFTHAQQt5BMQ=
github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s=
github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8=
github.com/muesli/termenv v0.11.1-0.20220204035834-5ac8409525e0 h1:STjmj0uFfRryL9fzRA/OupNppeAID6QJYPMavTL7jtY=
github.com/muesli/termenv v0.11.1-0.20220204035834-5ac8409525e0/go.mod h1:Bd5NYQ7pd+SrtBSrSNoBBmXlcY8+Xj4BMJgh8qcZrvs=
github.com/muesli/termenv v0.13.0 h1:wK20DRpJdDX8b7Ek2QfhvqhRQFZ237RGRO0RQ/Iqdy0=
github.com/muesli/termenv v0.13.0/go.mod h1:sP1+uffeLaEYpyOTb8pLCUctGcGLnoFjSn4YJK5e2bc=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=


@@ 38,26 76,42 @@ github.com/posener/complete/v2 v2.0.1-alpha.13 h1:xmeDzuCWM0E+hSq6hv4gZQBmiw+uz0
github.com/posener/complete/v2 v2.0.1-alpha.13/go.mod h1:+ndzg+QjkR+oKXdpgsPCdZTg67phWqV1atTotlxuyDg=
github.com/posener/script v1.1.5 h1:su+9YHNlevT+Hlq2Xul5skh5kYDIBE+x4xu+5mLDT9o=
github.com/posener/script v1.1.5/go.mod h1:Rg3ijooqulo05aGLyGsHoLmIOUzHUVK19WVgrYBPU/E=
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.3 h1:utMvzDsuh3suAEnhH0RdHmoPbU648o6CvXxTx4SBMOw=
github.com/rivo/uniseg v0.4.3/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 h1:JIAuq3EEf9cgbU6AtGPK4CTG3Zf6CKMNqf0MHTggAUA=
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/testify v1.2.3-0.20181224173747-660f15d67dbb/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 h1:QldyIu/L63oPpyvQmHgvgickp1Yw510KJOqX7H24mg8=
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs=
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220111092808-5a964db01320 h1:0jf+tOCoZ3LyutmCOWpVni1chK4VfFLhRsDK7MhqGRY=
golang.org/x/sys v0.0.0-20220111092808-5a964db01320/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220315194320-039c03cc5b86 h1:A9i04dxx7Cribqbs8jf3FQLogkL/CV2YN7hj9KWJCkc=
golang.org/x/sys v0.0.0-20220315194320-039c03cc5b86/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220406163625-3f8b81556e12 h1:QyVthZKMsyaQwBTJE04jdNN0Pp5Fn9Qga0mrgxyERQM=
golang.org/x/sys v0.0.0-20220406163625-3f8b81556e12/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18=
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

M lexer.go => lexer.go +11 -12
@@ 8,14 8,14 @@ import (
	"unicode"
)

//itemType identifies the type of lex items.
// itemType identifies the type of lex items.
type itemType int

const (
	itemError itemType = iota // error occurred; value is text of error
	itemEOF

	//basic items
	// basic items
	itemDate
	itemProject
	itemDescription


@@ 41,13 41,13 @@ var (
	eof = rune(0)
)

//stateFn represents the state of the scanner as a function that returns the next state.
// stateFn represents the state of the scanner as a function that returns the next state.
type stateFn func(*lexer) stateFn

// lexer holds the state of the scanner.
type lexer struct {
	input              *bufio.Reader   // the data being scanned.
	buf                strings.Builder //the data already scanned
	buf                strings.Builder // the data already scanned
	line, pos, prevpos int
	items              chan item // channel of scanned items.
}


@@ 56,7 56,7 @@ func (l *lexer) posString() string {
	return fmt.Sprintf("line: %d, pos: %d", l.line, l.pos)
}

//run lexes the input by executing state functions until the state is nil.
// run lexes the input by executing state functions until the state is nil.
func (l *lexer) run() {
	for state := lexStart; state != nil; {
		state = state(l)


@@ 66,7 66,6 @@ func (l *lexer) run() {

// emit passes an item back to the client.
func (l *lexer) emit(t itemType) {
	//log.Printf("EMIT %d '%s'", t, l.buf.String())
	l.items <- item{t, l.buf.String()}
	l.buf.Reset()
}


@@ 108,14 107,14 @@ func (l *lexer) unread() {
	}
}

//peek returns but does not consume the next rune in the input.
// peek returns but does not consume the next rune in the input.
func (l *lexer) peek() rune {
	r := l.read()
	l.unread()
	return r
}

//readDigits reads all runes that are letters
// readDigits reads all runes that are letters
func (l *lexer) readDigits() string {
	for {
		if ch := l.read(); ch == eof {


@@ 199,16 198,16 @@ func (l *lexer) acceptToTab() {
	}
}

//acceptRun consumes a run of runes from the valid set.
// acceptRun consumes a run of runes from the valid set.
func (l *lexer) accept(valid string) {
	for strings.ContainsRune(valid, l.read()) {
	}
	l.unread()
}

//errorf returns an error token and terminates the scan
//by passing back a nil pointer that will be the next
//state, terminating l.run.
// errorf returns an error token and terminates the scan
// by passing back a nil pointer that will be the next
// state, terminating l.run.
func (l *lexer) errorf(format string, args ...interface{}) stateFn {
	l.items <- item{
		itemError,

M main.go => main.go +53 -26
@@ 10,6 10,7 @@ import (
	"time"

	"github.com/alecthomas/kong"
	"github.com/charmbracelet/lipgloss"
	"github.com/gookit/color"
	"github.com/posener/complete/v2"
	"github.com/posener/complete/v2/install"


@@ 176,7 177,7 @@ func start() error {
	}
	if len(es) != 0 {
		last := &es[0]
		//if the first entry is from yesterday and isn't ended
		// if the first entry is from yesterday and isn't ended
		fy, fm, fd := last.Date.Date()
		if (y > fy || m > fm || d > fd) && last.End == zeroTime {
			return fmt.Errorf("last entry is from previous day and isn't ended (%s)", last.String())


@@ 232,24 233,47 @@ func end() error {
	return nil
}

var (
	box = lipgloss.NewStyle().
		PaddingTop(1).
		PaddingBottom(1).
		PaddingLeft(5).
		PaddingRight(5).
		Background(lipgloss.Color("237"))
	project = lipgloss.NewStyle().
		Foreground(lipgloss.Color("6"))
	label = lipgloss.NewStyle().
		Foreground(lipgloss.Color("229")).
		Bold(true)
	duration = lipgloss.NewStyle().
			Foreground(lipgloss.Color("13"))
)

func status() error {
	var col1, col2 strings.Builder
	es, err := loadEntries()
	if err != nil {
		return fmt.Errorf("loading entries: %w", err)
	}
	if len(es) == 0 || es[0].End != zeroTime {
		fmt.Println("\n    no running entries")
		col1.WriteString("no running entries")
	} else {
		last := &es[0]
		fmt.Printf(
			"\n    %s\t\t%s\n    %s: %s\t%s: %s\n",
			color.FgCyan.Render(last.Project),
			color.FgLightWhite.Render(last.Description),
			color.Style{color.FgLightWhite, color.OpBold}.Render("start"),
			last.Start.Format("15:04:05"),
			color.Style{color.FgLightWhite, color.OpBold}.Render("duration"),
			color.FgMagenta.Sprint(time.Since(last.Start)),
		)
		col1.WriteString(project.Render(last.Project))
		col1.WriteRune('\n')
		col1.WriteString(label.Render("start:"))
		col1.WriteRune(' ')
		col1.WriteString(last.Start.Format("15:04:05"))
		col1.WriteRune('\n')
		col1.WriteRune('\n')

		col2.WriteString(last.Description)
		col2.WriteRune('\n')
		col2.WriteString(label.Render("duration:"))
		col2.WriteRune(' ')
		col2.WriteString(duration.Render(time.Since(last.Start).String()))
		col2.WriteRune('\n')
		col2.WriteRune('\n')
	}
	y, m, d := time.Now().Date()
	var todayWorked time.Duration


@@ 263,11 287,10 @@ func status() error {
		}
		todayWorked += end.Sub(e.Start)
	}
	fmt.Printf(
		"\n    %s:\t%s\n",
		color.Style{color.FgLightWhite, color.OpBold}.Render("today worked"),
		color.FgMagenta.Sprint(todayWorked),
	)
	col1.WriteString(label.Render("today worked:"))
	col1.WriteRune('\n')
	col2.WriteString(duration.Render(todayWorked.String()))
	col2.WriteRune('\n')
	for _, e := range es {
		if ey, em, ed := e.Date.Date(); ey != y || em != m || ed != d {
			break


@@ 276,12 299,10 @@ func status() error {
		if end == zeroTime {
			end = time.Now()
		}
		fmt.Printf(
			"    %s\t\t%s %s\n",
			color.FgCyan.Render(e.Project),
			color.FgLightWhite.Render(e.Description),
			color.FgMagenta.Sprint(end.Sub(e.Start)),
		)
		col1.WriteString(project.Render(e.Project))
		col1.WriteRune(' ')
		col1.WriteString(e.Description)
		col1.WriteString(end.Sub(e.Start).String())
	}
	var thisMonthWorked time.Duration
	for _, e := range es {


@@ 294,10 315,16 @@ func status() error {
		}
		thisMonthWorked += end.Sub(e.Start)
	}
	fmt.Printf(
		"    %s:\t\t%s\n\n",
		color.Style{color.FgLightWhite, color.OpBold}.Render("this month"),
		color.FgMagenta.Render(thisMonthWorked),
	col1.WriteString(label.Render("this month:"))
	col2.WriteString(duration.Render(thisMonthWorked.String()))
	fmt.Println(
		box.Render(
			lipgloss.JoinHorizontal(
				lipgloss.Top,
				col1.String(),
				lipgloss.NewStyle().PaddingLeft(4).Render(col2.String()),
			),
		),
	)
	return nil
}

M report.go => report.go +9 -9
@@ 67,7 67,7 @@ func createReport(month string) (*excelize.File, string, error) {
	}

	xlsx := excelize.NewFile()
	//styles
	// styles
	centerStyle, err := xlsx.NewStyle(`{"alignment":{"horizontal":"center"}}`)
	if err != nil {
		panic(err)


@@ 89,7 89,7 @@ func createReport(month string) (*excelize.File, string, error) {
		panic(err)
	}

	//detail sheet
	// detail sheet
	detailSheet := "Detail"
	xlsx.SetSheetName("Sheet1", detailSheet)
	xlsx.SetCellValue(detailSheet, "A1", "Client")


@@ 108,7 108,7 @@ func createReport(month string) (*excelize.File, string, error) {
		xlsx.SetCellValue(detailSheet, fmt.Sprintf("E%d", i+2), e.End.Sub(e.Start))
	}

	// sumary sheet
	// summary sheet
	e := entries[0]
	sheetName := e.Start.Format("January 2006")
	index := xlsx.NewSheet(sheetName)


@@ 158,7 158,7 @@ func createReport(month string) (*excelize.File, string, error) {
	xlsx.SetCellStyle(sheetName, fmt.Sprintf("E%d", row), fmt.Sprintf("E%d", row), durationStyle)
	xlsx.SetCellFormula(sheetName, fmt.Sprintf("E%d", row), fmt.Sprintf("=SUM(E7:E%d)", row-1))

	//projects pivot table
	// projects pivot table
	row += 4
	xlsx.SetCellStyle(sheetName, fmt.Sprintf("A%d", row), fmt.Sprintf("F%d", row), centerBoldStyle)
	xlsx.SetCellValue(sheetName, fmt.Sprintf("A%d", row), "Projekt")


@@ 226,15 226,15 @@ func groupEntries(es Entries) (ees Entries) {
	return
}

//PivotTable used to sum up the duration by category and get the sorted data
// PivotTable used to sum up the duration by category and get the sorted data
type PivotTable map[string]time.Duration

//Add adds new duration to the PivotTable
// Add adds new duration to the PivotTable
func (pt PivotTable) Add(category string, duration time.Duration) {
	pt[category] += duration
}

//Sorted returns an sorted list of key-value pairs
// Sorted returns an sorted list of key-value pairs
func (pt PivotTable) Sorted() PairList {
	pl := make(PairList, len(pt))
	i := 0


@@ 246,13 246,13 @@ func (pt PivotTable) Sorted() PairList {
	return pl
}

//Pair represents a kev-value pair
// Pair represents a kev-value pair
type Pair struct {
	Key   string
	Value time.Duration
}

//PairList is a sortable list of key-value pairs
// PairList is a sortable list of key-value pairs
type PairList []Pair

func (p PairList) Len() int           { return len(p) }

M send_report.go => send_report.go +0 -1
@@ 92,7 92,6 @@ func sendreport() error {
				"",
				CLI.SendReport.SmtpUser,
				pass,
				//CLI.SendReport.SmtpServer,
			)
		case "LOGIN":
			auth = sasl.NewLoginClient(CLI.SendReport.SmtpUser, pass)