Skip to content

Commit 827c624

Browse files
Changed Pre/suffixer interface, implemented suffixer support
- added example suffixer to example now when a suffixer is provided to the list model the resulting string should have a fixed Printable Width. As long as the Init-Prefixer and Suffixer return correct the number of the Prinatbale width used by all there processed lines.
1 parent 0e7b9d7 commit 827c624

File tree

2 files changed

+44
-16
lines changed

2 files changed

+44
-16
lines changed

list/example/main.go

+22
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@ import (
55
"fmt"
66
"github.com/charmbracelet/bubbles/list"
77
tea "github.com/charmbracelet/bubbletea"
8+
"github.com/muesli/reflow/ansi"
89
"os"
910
"strconv"
11+
"strings"
1012
)
1113

1214
type model struct {
@@ -44,6 +46,7 @@ func main() {
4446
endResult := make(chan string, 1)
4547
list := list.NewModel()
4648
list.AddItems(stringerList)
49+
list.SuffixGen = &exampleSuffixer{currentMarker: "<"}
4750

4851
// Since in this example we only use UNIQUE string items we can use a String Comparison for the equals methode
4952
// but be aware that different items in your case can have the same string -> false-positiv
@@ -201,3 +204,22 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
201204
}
202205
return m, nil
203206
}
207+
208+
type exampleSuffixer struct {
209+
viewPos list.ViewPos
210+
currentMarker string
211+
markerLenght int
212+
}
213+
214+
func (e *exampleSuffixer) InitSuffixer(viewPos list.ViewPos, screen list.ScreenInfo) int {
215+
e.viewPos = viewPos
216+
e.markerLenght = ansi.PrintableRuneWidth(e.currentMarker)
217+
return e.markerLenght
218+
}
219+
220+
func (e *exampleSuffixer) Suffix(item, line int, selected bool) string {
221+
if item == e.viewPos.Cursor && line == 0 {
222+
return e.currentMarker
223+
}
224+
return strings.Repeat(" ", e.markerLenght)
225+
}

list/list.go

+22-16
Original file line numberDiff line numberDiff line change
@@ -44,15 +44,15 @@ type ScreenInfo struct {
4444
// and then Prefix ones, per line to draw, to generate according prefixes.
4545
type Prefixer interface {
4646
InitPrefixer(ViewPos, ScreenInfo) int
47-
Prefix(currentItem, currentLine int, selected, lastLine bool) string
47+
Prefix(currentItem, currentLine int, selected bool) string
4848
}
4949

5050
// Suffixer is used to suffix all visible Lines.
5151
// InitSuffixer gets called ones on the beginning of the Lines methode
5252
// and then Suffix ones, per line to draw, to generate according suffixes.
5353
type Suffixer interface {
5454
InitSuffixer(ViewPos, ScreenInfo) int
55-
Suffix(currentItem, currentLine int, selected, lastLine bool) string
55+
Suffix(currentItem, currentLine int, selected bool) string
5656
}
5757

5858
// Model is a bubbletea List of strings
@@ -74,8 +74,8 @@ type Model struct {
7474

7575
Wrap bool
7676

77-
// PrefixFunc func(position ViewPos, height int) (func(currentIndex int, selected bool, wrapedIndex int) string, int)
7877
PrefixGen Prefixer
78+
SuffixGen Suffixer
7979

8080
LineStyle termenv.Style
8181
SelectedStyle termenv.Style
@@ -126,28 +126,31 @@ func (m Model) View() string {
126126
// used to display the current user interface
127127
func (m *Model) Lines() []string {
128128
// get public variables as locals so they can't change while using
129+
129130
// check visible area
130131
height := m.Height
131132
width := m.Width
132133
if height*width <= 0 {
133134
panic("Can't display with zero width or hight of Viewport")
134135
}
135136

136-
// This is only used if the Lines methode is called befor the Update methode is called the first time
137-
var holePrefixWidth int
137+
// Get the Width of each suf/prefix
138+
var prefixWidth, suffixWidth int
138139
if m.PrefixGen != nil {
139-
holePrefixWidth = m.PrefixGen.InitPrefixer(m.viewPos, ScreenInfo{Height: m.Height, Width: m.Width, Profile: termenv.ColorProfile()})
140+
prefixWidth = m.PrefixGen.InitPrefixer(m.viewPos, ScreenInfo{Height: m.Height, Width: m.Width, Profile: termenv.ColorProfile()})
141+
}
142+
if m.SuffixGen != nil {
143+
suffixWidth = m.SuffixGen.InitSuffixer(m.viewPos, ScreenInfo{Height: m.Height, Width: m.Width, Profile: termenv.ColorProfile()})
140144
}
141145

142146
// Get actual content width
143-
contentWidth := width - holePrefixWidth
147+
contentWidth := width - prefixWidth - suffixWidth
144148

145149
// Check if there is space for the content left
146150
if contentWidth <= 0 {
147151
panic("Can't display with zero width for content")
148152
}
149153

150-
// If set
151154
wrap := m.Wrap
152155
if wrap {
153156
// renew wrap of all items
@@ -188,16 +191,19 @@ out:
188191
// TODO hard limit the string length
189192
}
190193

191-
var linePrefix string
194+
// Surrounding content
195+
var linePrefix, lineSuffix string
192196
if m.PrefixGen != nil {
193-
linePrefix = m.PrefixGen.Prefix(index, 0, item.selected, item.wrapedLenght == 0)
197+
linePrefix = m.PrefixGen.Prefix(index, 0, item.selected)
198+
}
199+
if m.SuffixGen != nil {
200+
lineSuffix = fmt.Sprintf("%s%s", strings.Repeat(" ", contentWidth-ansi.PrintableRuneWidth(content)), m.SuffixGen.Suffix(index, 0, item.selected))
194201
}
195202

196-
// join pad and first line content
197-
// NOTE line break is not added here because it would mess with the highlighting
198-
line := fmt.Sprintf("%s%s", linePrefix, content)
203+
// Join all
204+
line := fmt.Sprintf("%s%s%s", linePrefix, content, lineSuffix)
199205

200-
// Selecting: handle highlighting of selected and current lines
206+
// Highlighting of selected and current lines
201207
style := m.LineStyle
202208
if item.selected {
203209
style = m.SelectedStyle
@@ -238,7 +244,7 @@ out:
238244
// NOTE line break is not added here because it would mess with the highlighting
239245
var wrapPrefix string
240246
if m.PrefixGen != nil {
241-
wrapPrefix = m.PrefixGen.Prefix(index, i+1, item.selected, i == item.wrapedLenght-2)
247+
wrapPrefix = m.PrefixGen.Prefix(index, i+1, item.selected)
242248
}
243249
padLine := fmt.Sprintf("%s%s", wrapPrefix, line)
244250

@@ -915,7 +921,7 @@ func (d *DefaultPrefixer) InitPrefixer(position ViewPos, screen ScreenInfo) int
915921
}
916922

917923
// Prefix prefixes a given line
918-
func (d *DefaultPrefixer) Prefix(currentIndex int, wrapIndex int, selected, lastLine bool) string {
924+
func (d *DefaultPrefixer) Prefix(currentIndex int, wrapIndex int, selected bool) string {
919925
// if a number is set, prepend first line with number and both with enough spaces
920926
firstPad := strings.Repeat(" ", d.numWidth)
921927
var wrapPad string

0 commit comments

Comments
 (0)