Commit 0eccfe1

Karn Wong <[email protected]>
2025-07-28 03:54:54
refactor(timer): move to internal
1 parent 835e92f
Changed files (2)
cmd
internal
cmd/timer.go
@@ -1,143 +1,15 @@
-// modified from <https://github.com/maaslalani/pom/blob/main/main.go>
 package cmd
 
 import (
-	"fmt"
-	"os"
-	"strings"
-	"time"
-
-	"github.com/charmbracelet/bubbles/progress"
-	"github.com/charmbracelet/lipgloss"
-	"github.com/rs/zerolog/log"
-
-	tea "github.com/charmbracelet/bubbletea"
+	"github.com/kahnwong/swissknife/internal/timer"
 	"github.com/spf13/cobra"
 )
 
-// init
-const (
-	titleColor   = "#2EF8BB"
-	tickInterval = time.Second / 2
-)
-
-var (
-	currentTime    = time.Now().Format("15:04PM")
-	startTimeStyle = lipgloss.NewStyle().Foreground(lipgloss.Color(titleColor)).MarginRight(1).SetString(currentTime)
-	helpStyle      = lipgloss.NewStyle().Foreground(lipgloss.Color("240")).MarginTop(2)
-	baseTimerStyle = lipgloss.NewStyle().Padding(1, 2)
-)
-
-type tickMsg time.Time
-
-// model
-type Model struct {
-	quitting  bool
-	startTime time.Time
-	duration  time.Duration
-	progress  progress.Model
-}
-
-// bubbletea
-func (m Model) Init() tea.Cmd {
-	return tea.Tick(tickInterval, tickCmd)
-}
-
-func tickCmd(t time.Time) tea.Msg {
-	return tickMsg(t)
-}
-
-func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
-	var cmds []tea.Cmd
-
-	switch msg := msg.(type) {
-	case tickMsg:
-		cmds = append(cmds, tea.Tick(tickInterval, tickCmd))
-	case tea.KeyMsg:
-		switch msg.String() {
-		case "q":
-			m.startTime = time.Now()
-
-			m.quitting = true
-			return m, tea.Quit
-		case "ctrl+c":
-			m.quitting = true
-			return m, tea.Quit
-		default:
-			m.startTime = time.Now()
-		}
-	}
-
-	// Update timer
-	if m.startTime.IsZero() {
-		m.startTime = time.Now()
-		cmds = append(cmds, tea.Tick(tickInterval, tickCmd))
-	}
-
-	if time.Since(m.startTime) > m.duration {
-		m.startTime = time.Now()
-
-		m.quitting = true
-		return m, tea.Quit
-	}
-
-	return m, tea.Batch(cmds...)
-}
-
-func (m Model) View() string {
-	if m.quitting {
-		return ""
-	}
-
-	var s strings.Builder
-
-	elapsed := time.Since(m.startTime)
-	timeLeft := m.duration - elapsed
-
-	percent := float64(elapsed) / float64(m.duration)
-	s.WriteString(startTimeStyle.String())
-	s.WriteString("- " + timeLeft.Round(time.Second).String())
-	s.WriteString("\n\n")
-	s.WriteString(m.progress.ViewAs(percent))
-	s.WriteString(helpStyle.Render("Press 'q' to quit"))
-
-	return baseTimerStyle.Render(s.String())
-}
-
-func NewModel() Model {
-	progressBar := progress.New()
-	progressBar.FullColor = titleColor
-	progressBar.SetSpringOptions(1, 1)
-
-	return Model{
-		progress: progressBar,
-	}
-}
-
-// main
 var TimerCmd = &cobra.Command{
 	Use:   "timer",
 	Short: "Create a timer",
 	Run: func(cmd *cobra.Command, args []string) {
-		// check if input exists
-		if len(args) == 0 {
-			fmt.Println("Please provide a duration")
-			os.Exit(1)
-		}
-		// parse input
-		duration, err := time.ParseDuration(args[0])
-		if err != nil {
-			log.Fatal().Msg("Error parsing duration")
-		}
-
-		// timer
-		m := NewModel()
-		m.duration = duration
-
-		_, err = tea.NewProgram(&m).Run()
-		if err != nil {
-			log.Fatal().Err(err)
-		}
+		timer.Timer(args)
 	},
 }
 
internal/timer/timer.go
@@ -0,0 +1,136 @@
+// modified from <https://github.com/maaslalani/pom/blob/main/main.go>
+package timer
+
+import (
+	"fmt"
+	"os"
+	"strings"
+	"time"
+
+	"github.com/charmbracelet/bubbles/progress"
+	"github.com/charmbracelet/lipgloss"
+	"github.com/rs/zerolog/log"
+
+	tea "github.com/charmbracelet/bubbletea"
+)
+
+// init
+const (
+	titleColor   = "#2EF8BB"
+	tickInterval = time.Second / 2
+)
+
+var (
+	currentTime    = time.Now().Format("15:04PM")
+	startTimeStyle = lipgloss.NewStyle().Foreground(lipgloss.Color(titleColor)).MarginRight(1).SetString(currentTime)
+	helpStyle      = lipgloss.NewStyle().Foreground(lipgloss.Color("240")).MarginTop(2)
+	baseTimerStyle = lipgloss.NewStyle().Padding(1, 2)
+)
+
+type tickMsg time.Time
+
+// model
+type Model struct {
+	quitting  bool
+	startTime time.Time
+	duration  time.Duration
+	progress  progress.Model
+}
+
+// bubbletea
+func (m Model) Init() tea.Cmd {
+	return tea.Tick(tickInterval, tickCmd)
+}
+
+func tickCmd(t time.Time) tea.Msg {
+	return tickMsg(t)
+}
+
+func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
+	var cmds []tea.Cmd
+
+	switch msg := msg.(type) {
+	case tickMsg:
+		cmds = append(cmds, tea.Tick(tickInterval, tickCmd))
+	case tea.KeyMsg:
+		switch msg.String() {
+		case "q":
+			m.startTime = time.Now()
+
+			m.quitting = true
+			return m, tea.Quit
+		case "ctrl+c":
+			m.quitting = true
+			return m, tea.Quit
+		default:
+			m.startTime = time.Now()
+		}
+	}
+
+	// Update timer
+	if m.startTime.IsZero() {
+		m.startTime = time.Now()
+		cmds = append(cmds, tea.Tick(tickInterval, tickCmd))
+	}
+
+	if time.Since(m.startTime) > m.duration {
+		m.startTime = time.Now()
+
+		m.quitting = true
+		return m, tea.Quit
+	}
+
+	return m, tea.Batch(cmds...)
+}
+
+func (m Model) View() string {
+	if m.quitting {
+		return ""
+	}
+
+	var s strings.Builder
+
+	elapsed := time.Since(m.startTime)
+	timeLeft := m.duration - elapsed
+
+	percent := float64(elapsed) / float64(m.duration)
+	s.WriteString(startTimeStyle.String())
+	s.WriteString("- " + timeLeft.Round(time.Second).String())
+	s.WriteString("\n\n")
+	s.WriteString(m.progress.ViewAs(percent))
+	s.WriteString(helpStyle.Render("Press 'q' to quit"))
+
+	return baseTimerStyle.Render(s.String())
+}
+
+func NewModel() Model {
+	progressBar := progress.New()
+	progressBar.FullColor = titleColor
+	progressBar.SetSpringOptions(1, 1)
+
+	return Model{
+		progress: progressBar,
+	}
+}
+
+func Timer(args []string) {
+	// check if input exists
+	if len(args) == 0 {
+		fmt.Println("Please provide a duration")
+		os.Exit(1)
+	}
+	// parse input
+	duration, err := time.ParseDuration(args[0])
+	if err != nil {
+		log.Fatal().Msg("Error parsing duration")
+	}
+
+	// timer
+	m := NewModel()
+	m.duration = duration
+
+	_, err = tea.NewProgram(&m).Run()
+	if err != nil {
+		log.Fatal().Err(err)
+	}
+}