Skip to content

Commit 99e516d

Browse files
authored
Merge pull request #4 from termkit/support-tea-interface-for-instant-initialize
Change return type to make possible use as tea.Model
2 parents 84cba4f + c77f2b8 commit 99e516d

File tree

4 files changed

+48
-129
lines changed

4 files changed

+48
-129
lines changed

README.md

Lines changed: 23 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -53,19 +53,27 @@ import (
5353
tea "github.com/charmbracelet/bubbletea"
5454
)
5555

56+
// -----------------------------------------------------------------------------
57+
// Tiny Model
58+
// The Tiny Model is a sub-model for the tabs. It's a simple model that just shows the title of the tab.
59+
60+
// tinyModel is a sub-model for the tabs
5661
type tinyModel struct {
5762
skeleton *skeleton.Skeleton
5863
title string
5964
}
6065

66+
// newTinyModel returns a new tinyModel
6167
func newTinyModel(skeleton *skeleton.Skeleton, title string) *tinyModel {
6268
return &tinyModel{
6369
skeleton: skeleton,
6470
title: title,
6571
}
6672
}
6773

68-
func (m tinyModel) Init() tea.Cmd { return nil }
74+
func (m tinyModel) Init() tea.Cmd {
75+
return nil
76+
}
6977
func (m tinyModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
7078
return m, nil
7179
}
@@ -76,74 +84,44 @@ func (m tinyModel) View() string {
7684
}
7785
````
7886

79-
#### 2. Create the Main Model
80-
81-
Next, define the main model that will handle the overall application state and interact with Skeleton:
82-
83-
````go
84-
type mainModel struct {
85-
skeleton *skeleton.Skeleton
86-
}
87-
88-
func (m *mainModel) Init() tea.Cmd {
89-
return tea.Batch(
90-
tea.EnterAltScreen,
91-
tea.SetWindowTitle("Basic Tab Example"),
92-
m.skeleton.Init(), // Initialize the skeleton
93-
)
94-
}
95-
96-
func (m *mainModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
97-
var cmd tea.Cmd
98-
m.skeleton, cmd = m.skeleton.Update(msg)
99-
return m, cmd
100-
}
101-
102-
func (m *mainModel) View() string {
103-
return m.skeleton.View()
104-
}
105-
````
106-
107-
#### 3. Set Up the Application
87+
#### 2. Set Up the Application
10888

10989
Initialize Skeleton, add pages, and configure widgets:
11090

11191
````go
92+
// -----------------------------------------------------------------------------
93+
// Main Program
11294
func main() {
113-
skel := skeleton.NewSkeleton()
95+
s := skeleton.NewSkeleton()
11496

11597
// Add tabs (pages)
116-
skel.AddPage("first", "First Tab", newTinyModel(skel, "First"))
117-
skel.AddPage("second", "Second Tab", newTinyModel(skel, "Second"))
118-
skel.AddPage("third", "Third Tab", newTinyModel(skel, "Third"))
98+
s.AddPage("first", "First Tab", newTinyModel(s, "First"))
99+
s.AddPage("second", "Second Tab", newTinyModel(s, "Second"))
100+
s.AddPage("third", "Third Tab", newTinyModel(s, "Third"))
119101

120102
// Set up key bindings ( Optional | Defaults: ctrl+left, ctrl+right )
121103
//To switch next page
122-
skel.KeyMap.SwitchTabRight = key.NewBinding(
104+
s.KeyMap.SwitchTabRight = key.NewBinding(
123105
key.WithKeys("shift+right"))
124106

125107
// To switch previous page
126-
skel.KeyMap.SwitchTabLeft = key.NewBinding(
108+
s.KeyMap.SwitchTabLeft = key.NewBinding(
127109
key.WithKeys("shift+left"))
128110

129111
// Add a widget to entire screen
130-
skel.AddWidget("battery", "Battery %92")
131-
skel.AddWidget("time", time.Now().Format("15:04:05"))
112+
s.AddWidget("battery", "Battery %92")
113+
s.AddWidget("time", time.Now().Format("15:04:05"))
132114

133115
// Update the time widget every second
134116
go func() {
135117
time.Sleep(time.Second)
136118
for {
137-
skel.UpdateWidgetValue("time", time.Now().Format("15:04:05"))
119+
s.UpdateWidgetValue("time", time.Now().Format("15:04:05"))
138120
time.Sleep(time.Second)
139121
}
140122
}()
141123

142-
model := &mainModel{
143-
skeleton: skel,
144-
}
145-
146-
p := tea.NewProgram(model)
124+
p := tea.NewProgram(s)
147125
if err := p.Start(); err != nil {
148126
panic(err)
149127
}
@@ -154,9 +132,7 @@ func main() {
154132

155133
1. **Model Definition**: `tinyModel` represents the content of each tab. It uses the Skeleton instance to query terminal dimensions and display information.
156134

157-
2. **Main Model**: `mainModel` integrates Skeleton and handles application state updates and rendering.
158-
159-
3. **Application Setup**: The `main` function initializes Skeleton, adds pages, and sets up widgets. The time widget updates every second to reflect the current time.
135+
2. **Application Setup**: The `main` function initializes Skeleton, adds pages, and sets up widgets. The time widget updates every second to reflect the current time.
160136

161137
## Skeleton in the Wild
162138
Some programs that use Skeleton in production:

examples/file-reader/main.go

Lines changed: 1 addition & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -6,28 +6,6 @@ import (
66
"github.com/termkit/skeleton"
77
)
88

9-
type mainModel struct {
10-
skeleton *skeleton.Skeleton
11-
}
12-
13-
func (m *mainModel) Init() tea.Cmd {
14-
return tea.Batch(
15-
tea.EnterAltScreen,
16-
tea.SetWindowTitle("File Reader"),
17-
m.skeleton.Init(),
18-
)
19-
}
20-
21-
func (m *mainModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
22-
var cmd tea.Cmd
23-
m.skeleton, cmd = m.skeleton.Update(msg)
24-
return m, cmd
25-
}
26-
27-
func (m *mainModel) View() string {
28-
return m.skeleton.View()
29-
}
30-
319
func main() {
3210
s := skeleton.NewSkeleton()
3311
s.SetPagePosition(lipgloss.Left)
@@ -37,9 +15,7 @@ func main() {
3715

3816
s.AddPage("explorer", "Explorer", newExplorer(s))
3917

40-
m := &mainModel{skeleton: s}
41-
42-
if err := tea.NewProgram(m).Start(); err != nil {
18+
if err := tea.NewProgram(s).Start(); err != nil {
4319
panic(err)
4420
}
4521
}

examples/fundamental-skeleton/main.go

Lines changed: 15 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@ func newTinyModel(skeleton *skeleton.Skeleton, title string) *tinyModel {
2828
}
2929
}
3030

31-
func (m tinyModel) Init() tea.Cmd { return nil }
31+
func (m tinyModel) Init() tea.Cmd {
32+
return nil
33+
}
3234
func (m tinyModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
3335
return m, nil
3436
}
@@ -40,60 +42,32 @@ func (m tinyModel) View() string {
4042
}
4143

4244
// -----------------------------------------------------------------------------
43-
// Main Model
44-
// The Main Model is the main model for the program. It contains the skeleton and the tab models.
45-
46-
type mainModel struct {
47-
skeleton *skeleton.Skeleton
48-
}
49-
50-
func (m *mainModel) Init() tea.Cmd {
51-
return tea.Batch(
52-
tea.EnterAltScreen,
53-
tea.SetWindowTitle("Basic Tab Example"),
54-
m.skeleton.Init(),
55-
)
56-
}
57-
58-
func (m *mainModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
59-
var cmd tea.Cmd
60-
m.skeleton, cmd = m.skeleton.Update(msg)
61-
return m, cmd
62-
}
63-
64-
func (m *mainModel) View() string {
65-
return m.skeleton.View()
66-
}
67-
45+
// Main Program
6846
func main() {
69-
skel := skeleton.NewSkeleton()
47+
s := skeleton.NewSkeleton()
7048

7149
// Add tabs (pages)
72-
skel.AddPage("first", "First Tab", newTinyModel(skel, "First"))
73-
skel.AddPage("second", "Second Tab", newTinyModel(skel, "Second"))
74-
skel.AddPage("third", "Third Tab", newTinyModel(skel, "Third"))
50+
s.AddPage("first", "First Tab", newTinyModel(s, "First"))
51+
s.AddPage("second", "Second Tab", newTinyModel(s, "Second"))
52+
s.AddPage("third", "Third Tab", newTinyModel(s, "Third"))
7553

76-
// Add a widget to entire screen
54+
// Add a widget to entire screen ( Optional )
7755
// Battery level is hardcoded. You can use a library to get the battery level of your system.
78-
skel.AddWidget("battery", "Battery %92") // Add a widget to entire screen
56+
s.AddWidget("battery", "Battery %92") // Add a widget to entire screen
7957

80-
// Add current time
81-
skel.AddWidget("time", time.Now().Format("15:04:05"))
58+
// Add current time ( Optional )
59+
s.AddWidget("time", time.Now().Format("15:04:05"))
8260

83-
// Update the time widget every second
61+
// Update the time widget every second ( Optional )
8462
go func() {
8563
time.Sleep(time.Second)
8664
for {
87-
skel.UpdateWidgetValue("time", time.Now().Format("15:04:05"))
65+
s.UpdateWidgetValue("time", time.Now().Format("15:04:05"))
8866
time.Sleep(time.Second)
8967
}
9068
}()
9169

92-
model := &mainModel{
93-
skeleton: skel,
94-
}
95-
96-
p := tea.NewProgram(model)
70+
p := tea.NewProgram(s)
9771
if err := p.Start(); err != nil {
9872
panic(err)
9973
}

skeleton.go

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -354,21 +354,6 @@ func (s *Skeleton) GetActivePage() string {
354354
return s.header.headers[s.currentTab].key
355355
}
356356

357-
func (s *Skeleton) Init() tea.Cmd {
358-
if len(s.pages) == 0 {
359-
panic("skeleton: no pages added, please add at least one page")
360-
}
361-
362-
inits := make([]tea.Cmd, 3) // 3 for (self, header, Value)
363-
364-
// and init self, header and Value
365-
inits[0] = s.Listen()
366-
inits[1] = s.header.Init()
367-
inits[2] = s.widget.Init()
368-
369-
return tea.Batch(inits...)
370-
}
371-
372357
// IAMActivePage is a message to trigger the update of the active page.
373358
type IAMActivePage struct{}
374359

@@ -379,7 +364,15 @@ func (s *Skeleton) IAMActivePageCmd() tea.Cmd {
379364
}
380365
}
381366

382-
func (s *Skeleton) Update(msg tea.Msg) (*Skeleton, tea.Cmd) {
367+
func (s *Skeleton) Init() tea.Cmd {
368+
if len(s.pages) == 0 {
369+
panic("skeleton: no pages added, please add at least one page")
370+
}
371+
372+
return tea.Batch(s.Listen(), s.header.Init(), s.widget.Init())
373+
}
374+
375+
func (s *Skeleton) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
383376
var cmds []tea.Cmd
384377
var cmd tea.Cmd
385378

0 commit comments

Comments
 (0)