Skip to content

Commit 4ff0840

Browse files
Fix stale selector fragments left by a renderer regression
* bug: switch to altscreen to address bubbletea regression * chore: version bump
1 parent bf03673 commit 4ff0840

9 files changed

Lines changed: 242 additions & 185 deletions

File tree

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
v1.1.0
1+
v1.1.1

cmd/book/collection.go

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package cmd
22

33
import (
4-
tea "charm.land/bubbletea/v2"
54
"github.com/polymorcodeus/book/internal/book"
65
"github.com/polymorcodeus/book/internal/model"
76
)
@@ -20,13 +19,11 @@ func collections(bs *book.BookShelves, shelfName string, format string, config *
2019
return book.PrintCatalog(names, format)
2120
}
2221

23-
_, err := tea.NewProgram(collectionRootScreen(bs, "list", config)).Run()
24-
return err
22+
return runProgram(collectionRootScreen(bs, "list", config))
2523
}
2624

2725
func addCollection(bs *book.BookShelves, config *book.Config) error {
28-
_, err := tea.NewProgram(collectionRootScreen(bs, "add", config)).Run()
29-
return err
26+
return runProgram(collectionRootScreen(bs, "add", config))
3027
}
3128

3229
func collectionRootScreen(bs *book.BookShelves, action string, config *book.Config) model.RootScreen {

cmd/book/main.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"os"
1111
"path/filepath"
1212

13+
tea "charm.land/bubbletea/v2"
1314
"github.com/polymorcodeus/gofiglet"
1415
altsrc "github.com/urfave/cli-altsrc/v3"
1516
alttoml "github.com/urfave/cli-altsrc/v3/toml"
@@ -18,6 +19,7 @@ import (
1819

1920
"github.com/polymorcodeus/book/internal/book"
2021
"github.com/polymorcodeus/book/internal/catalog"
22+
"github.com/polymorcodeus/book/internal/model"
2123
)
2224

2325
var (
@@ -533,3 +535,20 @@ func Main() {
533535
log.Fatal(err)
534536
}
535537
}
538+
539+
// runProgram runs a RootScreen TUI and prints its completion output after the
540+
// program exits. The interactive form renders in the alternate screen buffer
541+
// and is discarded on exit, so the caller prints the result below the banner
542+
// instead of leaving selector fragments behind.
543+
func runProgram(screen model.RootScreen) error {
544+
m, err := tea.NewProgram(screen).Run()
545+
if err != nil {
546+
return err
547+
}
548+
if rp, ok := m.(model.ResultProvider); ok {
549+
if v := rp.ResultView(); v != "" {
550+
fmt.Print(v)
551+
}
552+
}
553+
return nil
554+
}

cmd/book/mark.go

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,14 @@ import (
66
"net/url"
77
"strings"
88

9-
tea "charm.land/bubbletea/v2"
109
"github.com/polymorcodeus/book/internal/book"
1110
"github.com/polymorcodeus/book/internal/catalog"
1211
"github.com/polymorcodeus/book/internal/model"
1312
"github.com/polymorcodeus/book/internal/web"
1413
)
1514

1615
func mark(bs *book.BookShelves, config *book.Config) error {
17-
_, err := tea.NewProgram(markRootScreen(bs, &book.Mark{}, "get", config)).Run()
18-
return err
16+
return runProgram(markRootScreen(bs, &book.Mark{}, "get", config))
1917
}
2018

2119
func marks(bs *book.BookShelves, shelfName string, collectionName string, format string, config *book.Config) error {
@@ -31,13 +29,11 @@ func marks(bs *book.BookShelves, shelfName string, collectionName string, format
3129
}
3230
return book.PrintCatalog(collection, format)
3331
}
34-
_, err := tea.NewProgram(markRootScreen(bs, &book.Mark{}, "list", config)).Run()
35-
return err
32+
return runProgram(markRootScreen(bs, &book.Mark{}, "list", config))
3633
}
3734

3835
func editMark(bs *book.BookShelves, config *book.Config) error {
39-
_, err := tea.NewProgram(markRootScreen(bs, &book.Mark{}, "edit", config)).Run()
40-
return err
36+
return runProgram(markRootScreen(bs, &book.Mark{}, "edit", config))
4137
}
4238

4339
func searchMarks(query string, tags string, shelfName string, collectionName string, format string, config *book.Config) error {
@@ -139,13 +135,11 @@ func addMark(bs *book.BookShelves, URL string, tags string, shelfName string, co
139135
return nil
140136
}
141137

142-
_, err := tea.NewProgram(markRootScreen(bs, &mark, "add", config)).Run()
143-
return err
138+
return runProgram(markRootScreen(bs, &mark, "add", config))
144139
}
145140

146141
func removeMark(bs *book.BookShelves, config *book.Config) error {
147-
_, err := tea.NewProgram(markRootScreen(bs, &book.Mark{}, "delete", config)).Run()
148-
return err
142+
return runProgram(markRootScreen(bs, &book.Mark{}, "delete", config))
149143
}
150144

151145
func markRootScreen(bs *book.BookShelves, mark *book.Mark, action string, config *book.Config) model.RootScreen {

cmd/book/shelf.go

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package cmd
22

33
import (
4-
tea "charm.land/bubbletea/v2"
54
"github.com/polymorcodeus/book/internal/book"
65
"github.com/polymorcodeus/book/internal/model"
76
)
@@ -19,13 +18,11 @@ func shelves(bs *book.BookShelves, format string, config *book.Config) error {
1918
return book.PrintCatalog(names, format)
2019
}
2120

22-
_, err := tea.NewProgram(shelfRootScreen(bs, "list", config)).Run()
23-
return err
21+
return runProgram(shelfRootScreen(bs, "list", config))
2422
}
2523

2624
func addShelf(bs *book.BookShelves, config *book.Config) error {
27-
_, err := tea.NewProgram(shelfRootScreen(bs, "add", config)).Run()
28-
return err
25+
return runProgram(shelfRootScreen(bs, "add", config))
2926
}
3027

3128
func shelfRootScreen(bs *book.BookShelves, action string, config *book.Config) model.RootScreen {

internal/model/collection_model.go

Lines changed: 60 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -75,13 +75,12 @@ func (m getCollectionModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
7575
}
7676

7777
func (m getCollectionModel) View() tea.View {
78-
s := m.get.book.styles
79-
t := m.get.book.tmpls
80-
81-
if m.action == "list" && m.get.book.form.State == huh.StateCompleted {
82-
return renderCompletedView(s, t, "collection-list", m.get.shelf)
78+
if m.get.book.form.State == huh.StateCompleted || m.get.book.width <= 0 {
79+
return altScreenView("")
8380
}
8481

82+
s := m.get.book.styles
83+
8584
// Form (left side)
8685
v := strings.TrimSuffix(m.get.book.form.View(), "\n\n")
8786
form := s.Form.Render(v)
@@ -100,13 +99,7 @@ func (m getCollectionModel) View() tea.View {
10099

101100
currentShelf = lipglossDimmer(s.StatusHeader, "Picked Shelf", displayShelf)
102101

103-
const statusWidth = 68
104-
statusMarginLeft := m.get.book.width - statusWidth - lipgloss.Width(form) - s.Status.GetMarginRight()
105-
status = s.Status.
106-
Height(10).
107-
Width(statusWidth).
108-
MarginLeft(statusMarginLeft).
109-
Render(currentShelf)
102+
status = m.get.book.statusPanel(form, currentShelf, 10)
110103
}
111104

112105
errors := m.get.book.form.Errors()
@@ -120,12 +113,21 @@ func (m getCollectionModel) View() tea.View {
120113
if len(errors) > 0 {
121114
footer = m.get.book.appErrorBoundaryView("")
122115
}
123-
return tea.NewView(s.Base.Render(header + "\n" + body + "\n\n" + footer))
116+
return altScreenView(s.Base.Render(header + "\n" + body + "\n\n" + footer))
117+
}
118+
119+
// ResultView returns the completion output for the caller to print after the
120+
// program exits.
121+
func (m getCollectionModel) ResultView() string {
122+
if m.get.book.form.State != huh.StateCompleted || m.action != "list" {
123+
return ""
124+
}
125+
return renderCompletedView(m.get.book.styles, m.get.book.tmpls, "collection-list", m.get.shelf).Content
124126
}
125127

126128
// GetCollectionForm to be used for editing descriptions/names in future
127129
func GetCollectionForm(bs *book.BookShelves, config *book.Config, action string) getCollectionModel {
128-
m := collectionModel{book: &Book{width: maxWidth}}
130+
m := collectionModel{book: &Book{width: 0}}
129131
m.book.styles = NewStyles(config)
130132
m.book.tmpls = config.Templates
131133
m.book.shelves = bs
@@ -240,56 +242,57 @@ func (m editCollectionModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
240242
}
241243

242244
func (m editCollectionModel) View() tea.View {
245+
if m.editor.book.form.State == huh.StateCompleted || m.editor.book.width <= 0 {
246+
return altScreenView("")
247+
}
248+
243249
s := m.editor.book.styles
244-
t := m.editor.book.tmpls
245-
246-
switch m.editor.book.form.State {
247-
case huh.StateCompleted:
248-
return renderCompletedView(s, t, "collection-add", m.editor.collection)
249-
default:
250-
// Form (left side)
251-
v := strings.TrimSuffix(m.editor.book.form.View(), "\n\n")
252-
form := s.Form.Render(v)
253-
254-
// Status (right side)
255-
var status string
256-
{
257-
var (
258-
editShelfName string
259-
editCollectionName string
260-
editCollectionDesc string
261-
)
262-
263-
editShelfName = s.StatusHeader.Render("Picked Shelf") + "\n" + m.editor.shelf.Name + "\n\n"
264-
editCollectionName = lipglossDimmer(s.StatusHeader, "Collection Name", m.editor.collection.Name)
265-
editCollectionDesc = lipglossDimmer(s.StatusHeader, "Collection Description", m.editor.collection.Description)
266-
267-
const statusWidth = 68
268-
statusMarginLeft := m.editor.book.width - statusWidth - lipgloss.Width(form) - s.Status.GetMarginRight()
269-
status = s.Status.
270-
Height(10).
271-
Width(statusWidth).
272-
MarginLeft(statusMarginLeft).
273-
Render(editShelfName + editCollectionName + editCollectionDesc)
274-
}
275250

276-
errors := m.editor.book.form.Errors()
277-
header := m.editor.book.appBoundaryView("book collection editing system")
278-
if len(errors) > 0 {
279-
header = m.editor.book.appErrorBoundaryView(m.editor.book.errorView())
280-
}
281-
body := lipgloss.JoinHorizontal(lipgloss.Left, form, status)
251+
// Form (left side)
252+
v := strings.TrimSuffix(m.editor.book.form.View(), "\n\n")
253+
form := s.Form.Render(v)
282254

283-
footer := m.editor.book.appBoundaryView(m.editor.book.form.Help().ShortHelpView(m.editor.book.form.KeyBinds()))
284-
if len(errors) > 0 {
285-
footer = m.editor.book.appErrorBoundaryView("")
286-
}
287-
return tea.NewView(s.Base.Render(header + "\n" + body + "\n\n" + footer))
255+
// Status (right side)
256+
var status string
257+
{
258+
var (
259+
editShelfName string
260+
editCollectionName string
261+
editCollectionDesc string
262+
)
263+
264+
editShelfName = s.StatusHeader.Render("Picked Shelf") + "\n" + m.editor.shelf.Name + "\n\n"
265+
editCollectionName = lipglossDimmer(s.StatusHeader, "Collection Name", m.editor.collection.Name)
266+
editCollectionDesc = lipglossDimmer(s.StatusHeader, "Collection Description", m.editor.collection.Description)
267+
268+
status = m.editor.book.statusPanel(form, editShelfName+editCollectionName+editCollectionDesc, 10)
269+
}
270+
271+
errors := m.editor.book.form.Errors()
272+
header := m.editor.book.appBoundaryView("book collection editing system")
273+
if len(errors) > 0 {
274+
header = m.editor.book.appErrorBoundaryView(m.editor.book.errorView())
275+
}
276+
body := lipgloss.JoinHorizontal(lipgloss.Left, form, status)
277+
278+
footer := m.editor.book.appBoundaryView(m.editor.book.form.Help().ShortHelpView(m.editor.book.form.KeyBinds()))
279+
if len(errors) > 0 {
280+
footer = m.editor.book.appErrorBoundaryView("")
281+
}
282+
return altScreenView(s.Base.Render(header + "\n" + body + "\n\n" + footer))
283+
}
284+
285+
// ResultView returns the completion output for the caller to print after the
286+
// program exits.
287+
func (m editCollectionModel) ResultView() string {
288+
if m.editor.book.form.State != huh.StateCompleted {
289+
return ""
288290
}
291+
return renderCompletedView(m.editor.book.styles, m.editor.book.tmpls, "collection-add", m.editor.collection).Content
289292
}
290293

291294
func editCollectionForm(bs *book.BookShelves, shelf *book.Shelf, config *book.Config, action string) editCollectionModel {
292-
m := collectionModel{book: &Book{width: maxWidth}}
295+
m := collectionModel{book: &Book{width: 0}}
293296
m.book.styles = NewStyles(config)
294297
m.book.tmpls = config.Templates
295298
m.book.shelves = bs

0 commit comments

Comments
 (0)