Commit a17bc21

Karn Wong <[email protected]>
2025-07-28 03:56:46
refactor(stopwatch): move to internal
1 parent 0eccfe1
Changed files (2)
cmd
internal
stopwatch
cmd/stopwatch.go
@@ -1,112 +1,15 @@
-// from <https://github.com/charmbracelet/bubbletea/blob/master/examples/stopwatch/main.go>
 package cmd
 
 import (
-	"fmt"
-	"os"
-	"time"
-
-	"github.com/charmbracelet/bubbles/help"
-	"github.com/charmbracelet/bubbles/key"
+	"github.com/kahnwong/swissknife/internal/stopwatch"
 	"github.com/spf13/cobra"
-
-	"github.com/charmbracelet/bubbles/stopwatch"
-	tea "github.com/charmbracelet/bubbletea"
 )
 
-type model struct {
-	stopwatch stopwatch.Model
-	keymap    keymap
-	help      help.Model
-	quitting  bool
-}
-
-type keymap struct {
-	start key.Binding
-	stop  key.Binding
-	reset key.Binding
-	quit  key.Binding
-}
-
-func (m model) Init() tea.Cmd {
-	return m.stopwatch.Init()
-}
-
-func (m model) View() string {
-	// Note: you could further customize the time output by getting the
-	// duration from m.stopwatch.Elapsed(), which returns a time.Duration, and
-	// skip m.stopwatch.View() altogether.
-	s := m.stopwatch.View() + "\n"
-	if !m.quitting {
-		s = "Elapsed: " + s
-		s += m.helpView()
-	}
-	return s
-}
-
-func (m model) helpView() string {
-	return "\n" + m.help.ShortHelpView([]key.Binding{
-		m.keymap.start,
-		m.keymap.stop,
-		m.keymap.reset,
-		m.keymap.quit,
-	})
-}
-
-func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
-	switch msg := msg.(type) {
-	case tea.KeyMsg:
-		switch {
-		case key.Matches(msg, m.keymap.quit):
-			m.quitting = true
-			return m, tea.Quit
-		case key.Matches(msg, m.keymap.reset):
-			return m, m.stopwatch.Reset()
-		case key.Matches(msg, m.keymap.start, m.keymap.stop):
-			m.keymap.stop.SetEnabled(!m.stopwatch.Running())
-			m.keymap.start.SetEnabled(m.stopwatch.Running())
-			return m, m.stopwatch.Toggle()
-		}
-	}
-	var cmd tea.Cmd
-	m.stopwatch, cmd = m.stopwatch.Update(msg)
-	return m, cmd
-}
-
-// main
 var StopwatchCmd = &cobra.Command{
 	Use:   "stopwatch",
 	Short: "Create a stopwatch",
 	Run: func(cmd *cobra.Command, args []string) {
-		m := model{
-			stopwatch: stopwatch.NewWithInterval(time.Millisecond),
-			keymap: keymap{
-				start: key.NewBinding(
-					key.WithKeys("s"),
-					key.WithHelp("s", "start"),
-				),
-				stop: key.NewBinding(
-					key.WithKeys("s"),
-					key.WithHelp("s", "stop"),
-				),
-				reset: key.NewBinding(
-					key.WithKeys("r"),
-					key.WithHelp("r", "reset"),
-				),
-				quit: key.NewBinding(
-					key.WithKeys("ctrl+c", "q"),
-					key.WithHelp("q", "quit"),
-				),
-			},
-			help: help.New(),
-		}
-
-		m.keymap.start.SetEnabled(false)
-
-		if _, err := tea.NewProgram(m).Run(); err != nil {
-			fmt.Println("Oh no, it didn't work:", err)
-			os.Exit(1)
-		}
+		stopwatch.Stopwatch()
 	},
 }
 
internal/stopwatch/stopwatch.go
@@ -0,0 +1,104 @@
+// from <https://github.com/charmbracelet/bubbletea/blob/master/examples/stopwatch/main.go>
+package stopwatch
+
+import (
+	"fmt"
+	"os"
+	"time"
+
+	"github.com/charmbracelet/bubbles/help"
+	"github.com/charmbracelet/bubbles/key"
+	"github.com/charmbracelet/bubbles/stopwatch"
+	tea "github.com/charmbracelet/bubbletea"
+)
+
+type model struct {
+	stopwatch stopwatch.Model
+	keymap    keymap
+	help      help.Model
+	quitting  bool
+}
+
+type keymap struct {
+	start key.Binding
+	stop  key.Binding
+	reset key.Binding
+	quit  key.Binding
+}
+
+func (m model) Init() tea.Cmd {
+	return m.stopwatch.Init()
+}
+
+func (m model) View() string {
+	// Note: you could further customize the time output by getting the
+	// duration from m.stopwatch.Elapsed(), which returns a time.Duration, and
+	// skip m.stopwatch.View() altogether.
+	s := m.stopwatch.View() + "\n"
+	if !m.quitting {
+		s = "Elapsed: " + s
+		s += m.helpView()
+	}
+	return s
+}
+
+func (m model) helpView() string {
+	return "\n" + m.help.ShortHelpView([]key.Binding{
+		m.keymap.start,
+		m.keymap.stop,
+		m.keymap.reset,
+		m.keymap.quit,
+	})
+}
+
+func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
+	switch msg := msg.(type) {
+	case tea.KeyMsg:
+		switch {
+		case key.Matches(msg, m.keymap.quit):
+			m.quitting = true
+			return m, tea.Quit
+		case key.Matches(msg, m.keymap.reset):
+			return m, m.stopwatch.Reset()
+		case key.Matches(msg, m.keymap.start, m.keymap.stop):
+			m.keymap.stop.SetEnabled(!m.stopwatch.Running())
+			m.keymap.start.SetEnabled(m.stopwatch.Running())
+			return m, m.stopwatch.Toggle()
+		}
+	}
+	var cmd tea.Cmd
+	m.stopwatch, cmd = m.stopwatch.Update(msg)
+	return m, cmd
+}
+
+func Stopwatch() {
+	m := model{
+		stopwatch: stopwatch.NewWithInterval(time.Millisecond),
+		keymap: keymap{
+			start: key.NewBinding(
+				key.WithKeys("s"),
+				key.WithHelp("s", "start"),
+			),
+			stop: key.NewBinding(
+				key.WithKeys("s"),
+				key.WithHelp("s", "stop"),
+			),
+			reset: key.NewBinding(
+				key.WithKeys("r"),
+				key.WithHelp("r", "reset"),
+			),
+			quit: key.NewBinding(
+				key.WithKeys("ctrl+c", "q"),
+				key.WithHelp("q", "quit"),
+			),
+		},
+		help: help.New(),
+	}
+
+	m.keymap.start.SetEnabled(false)
+
+	if _, err := tea.NewProgram(m).Run(); err != nil {
+		fmt.Println("Oh no, it didn't work:", err)
+		os.Exit(1)
+	}
+}