@@ -16,16 +16,45 @@ import (
1616 "github.com/charmbracelet/bubbles/key"
1717 "github.com/charmbracelet/bubbles/progress"
1818 tea "github.com/charmbracelet/bubbletea"
19+ "tiny-timer/status"
1920)
2021
22+ var version = "dev"
23+
2124func main () {
22- // Parse CLI flags
25+ title , countUp , clean , debug := parseFlags ()
26+
27+ configureLogging (debug )
28+
29+ if clean {
30+ handleCleanFlag ()
31+ return
32+ }
33+
34+ if err := initDB (); err != nil {
35+ fmt .Println ("Error initializing database:" , err )
36+ os .Exit (1 )
37+ }
38+
39+ defer closeDBConnection ()
40+
41+ targetDuration := calculateTargetDuration (countUp )
42+ keys := createKeyBindings ()
43+ m := createModel (title , countUp , targetDuration , keys )
44+
45+ if _ , err := tea .NewProgram (m ).Run (); err != nil {
46+ fmt .Println ("Oh no!" , err )
47+ os .Exit (1 )
48+ }
49+ }
50+
51+ func parseFlags () (title string , countUp bool , clean bool , debug bool ) {
2352 titleFlag := flag .String ("title" , "" , "Optional title for the timer session" )
2453 countUpFlag := flag .Bool ("count-up" , false , "Enable count-up mode (logs task time after completion)" )
2554 cleanFlag := flag .Bool ("clean" , false , "Delete the database and exit" )
2655 debugFlag := flag .Bool ("debug" , false , "Enable debug logging to debug.log" )
56+ versionFlag := flag .Bool ("version" , false , "Print version and exit" )
2757
28- // Customize usage to include positional argument
2958 flag .Usage = func () {
3059 fmt .Fprintf (os .Stderr , "Usage: %s [minutes] [flags]\n \n " , os .Args [0 ])
3160 fmt .Fprintf (os .Stderr , "Positional arguments:\n " )
@@ -35,64 +64,62 @@ func main() {
3564 flag .PrintDefaults ()
3665 }
3766
38- // Pre-process arguments to allow positional argument (minutes) before flags
39- // flag.Parse() stops at the first non-flag argument.
40- // We check if the first argument is a number and move it to the end if so.
67+ preprocessArgs ()
68+ flag .Parse ()
69+
70+ if * versionFlag {
71+ fmt .Println ("tiny-timer version" , version )
72+ os .Exit (0 )
73+ }
74+
75+ return * titleFlag , * countUpFlag , * cleanFlag , * debugFlag
76+ }
77+
78+ func preprocessArgs () {
4179 args := os .Args [1 :]
4280 if len (args ) > 0 {
4381 if _ , err := strconv .ParseInt (args [0 ], 10 , 64 ); err == nil {
44- // First arg is a number, move it to the end so flag.Parse() can see the flags
4582 minutes := args [0 ]
4683 newArgs := append (args [1 :], minutes )
4784 os .Args = append ([]string {os .Args [0 ]}, newArgs ... )
4885 }
4986 }
87+ }
5088
51- flag .Parse ()
52-
53- // Enable debug logging if flag is set
54- // tea.LogToFile configures the standard log package to write to debug.log
55- // All log.Printf() calls throughout the codebase will write to this file
56- if * debugFlag {
89+ func configureLogging (debug bool ) {
90+ if debug {
5791 f , err := tea .LogToFile ("debug.log" , "debug" )
5892 if err != nil {
5993 fmt .Fprintf (os .Stderr , "Warning: Failed to enable debug logging: %v\n " , err )
6094 } else {
6195 defer f .Close ()
6296 }
6397 } else {
64- // Silence all log output in normal mode
6598 log .SetOutput (io .Discard )
6699 }
100+ }
67101
68- if * cleanFlag {
69- dbPath , err := getDBPath ()
70- if err != nil {
71- fmt .Println ("Error getting database path:" , err )
72- os .Exit (1 )
73- }
74- if _ , err := os .Stat (dbPath ); err == nil {
75- if err := os .Remove (dbPath ); err != nil {
76- fmt .Println ("Error deleting database:" , err )
77- os .Exit (1 )
78- }
79- fmt .Println ("Database deleted successfully." )
80- } else if os .IsNotExist (err ) {
81- fmt .Println ("Database does not exist." )
82- } else {
83- fmt .Println ("Error checking database:" , err )
102+ func handleCleanFlag () {
103+ dbPath , err := getDBPath ()
104+ if err != nil {
105+ fmt .Println ("Error getting database path:" , err )
106+ os .Exit (1 )
107+ }
108+ if _ , err := os .Stat (dbPath ); err == nil {
109+ if err := os .Remove (dbPath ); err != nil {
110+ fmt .Println ("Error deleting database:" , err )
84111 os .Exit (1 )
85112 }
86- os .Exit (0 )
87- }
88-
89- // Initialize database on launch
90- if err := initDB (); err != nil {
91- fmt .Println ("Error initializing database:" , err )
113+ fmt .Println ("Database deleted successfully." )
114+ } else if os .IsNotExist (err ) {
115+ fmt .Println ("Database does not exist." )
116+ } else {
117+ fmt .Println ("Error checking database:" , err )
92118 os .Exit (1 )
93119 }
120+ }
94121
95- // Read positional arg for duration, or use default
122+ func calculateTargetDuration ( countUp bool ) int64 {
96123 var targetDurationInMinutes int64 = defaultDurationInMinutes
97124 if flag .NArg () > 0 {
98125 if arg , err := strconv .ParseInt (flag .Arg (0 ), 10 , 64 ); err == nil && arg > 0 {
@@ -101,11 +128,15 @@ func main() {
101128 }
102129
103130 targetDuration := targetDurationInMinutes * 60
104- if * countUpFlag && flag .NArg () == 0 {
131+ if countUp && flag .NArg () == 0 {
105132 targetDuration = defaultCountUpDuration
106133 }
107134
108- keys := keyMap {
135+ return targetDuration
136+ }
137+
138+ func createKeyBindings () keyMap {
139+ return keyMap {
109140 Done : key .NewBinding (
110141 key .WithKeys ("d" ),
111142 key .WithHelp ("d" , "done" ),
@@ -143,22 +174,27 @@ func main() {
143174 key .WithHelp ("backspace" , "delete" ),
144175 ),
145176 }
177+ }
178+
179+ func createModel (title string , countUp bool , targetDuration int64 , keys keyMap ) model {
180+ prog := progress .New (progress .WithGradient (colorMontezumaGold , colorCream ), progress .WithoutPercentage ())
181+ if countUp {
182+ prog .SetPercent (0 )
183+ } else {
184+ prog .SetPercent (1.0 )
185+ }
186+
187+ statusCmp := status .NewStatusCmp ()
188+ statusCmp .SetKeyMap (keys )
146189
147- m := model {
148- progress : progress . New ( progress . WithGradient ( colorMontezumaGold , colorCream ), progress . WithoutPercentage ()) ,
190+ return model {
191+ progress : prog ,
149192 startTime : time .Now ().Unix (),
150193 targetDuration : targetDuration ,
151- title : * titleFlag ,
152- countUpMode : * countUpFlag ,
194+ title : title ,
195+ countUpMode : countUp ,
153196 help : newHelpModel (),
154197 keys : keys ,
155- }
156-
157- // Ensure database connection is closed on exit
158- defer closeDBConnection ()
159-
160- if _ , err := tea .NewProgram (m ).Run (); err != nil {
161- fmt .Println ("Oh no!" , err )
162- os .Exit (1 )
198+ status : statusCmp ,
163199 }
164200}
0 commit comments