Skip to content

Commit afb04d9

Browse files
author
Kilian Drechsler
committed
changed creation of the line and wrap prefix
to be performater created befor entering the loop
1 parent a117398 commit afb04d9

File tree

1 file changed

+79
-54
lines changed

1 file changed

+79
-54
lines changed

list/list.go

+79-54
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
tea "github.com/charmbracelet/bubbletea"
88
runewidth "github.com/mattn/go-runewidth"
99
"github.com/muesli/reflow/wordwrap"
10+
"github.com/muesli/reflow/ansi"
1011
"github.com/muesli/termenv"
1112
"sort"
1213
"strings"
@@ -27,12 +28,13 @@ type Model struct {
2728
Viewport viewport.Model
2829
Wrap bool
2930

31+
SelectedPrefix string
3032
Seperator string
3133
SeperatorWrap string
32-
SeperatorCurrent string
33-
SelectedPrefix string
34-
RelativeNumber bool
35-
AbsoluteNumber bool
34+
CurrentMarker string
35+
36+
Number bool
37+
NumberRelative bool
3638

3739
LineForeGroundStyle termenv.Style
3840
LineBackGroundStyle termenv.Style
@@ -74,31 +76,21 @@ func View(model tea.Model) string {
7476
panic("Can't display with zero width or hight of Viewport")
7577
}
7678

77-
// if there is something to pad
78-
var relWidth, absWidth, padWidth int
7979

80-
if m.RelativeNumber {
81-
relWidth = len(fmt.Sprintf("%d", height))
82-
}
80+
// Get max seperator width
81+
widthItem := ansi.PrintableRuneWidth(m.Seperator)
82+
widthWrap := ansi.PrintableRuneWidth(m.SeperatorWrap)
8383

84-
if m.AbsoluteNumber {
85-
absWidth = len(fmt.Sprintf("%d", len(m.listItems)))
86-
}
8784

88-
// get widest number to pad
89-
padWidth = relWidth
90-
if padWidth < absWidth {
91-
padWidth = absWidth
85+
// Find max width
86+
sepWidth := widthItem
87+
if widthWrap > sepWidth {
88+
sepWidth = widthWrap
9289
}
9390

94-
// Get max seperator width
95-
sepWidth := maxRuneWidth(m.Seperator, m.SeperatorWrap, m.SeperatorCurrent) + runewidth.StringWidth(m.SelectedPrefix)
96-
97-
//Get hole Width
98-
holeWidth := sepWidth + padWidth
99-
10091
// Get actual content width
101-
contentWidth := width - (holeWidth + 1)
92+
numWidth := len(m.listItems)
93+
contentWidth := width - (numWidth + sepWidth)
10294

10395
// Check if there is space for the content left
10496
if contentWidth <= 0 {
@@ -111,6 +103,19 @@ func View(model tea.Model) string {
111103

112104
}
113105

106+
107+
// pad all prefixes to the same width for easy exchange
108+
prefix := m.SelectedPrefix
109+
prepad := strings.Repeat(" ", ansi.PrintableRuneWidth(m.SelectedPrefix))
110+
111+
// pad all seperators to the same width for easy exchange
112+
sepItem := strings.Repeat(" ", sepWidth-widthItem)+m.Seperator
113+
sepWrap := strings.Repeat(" ", sepWidth-widthWrap)+m.SeperatorWrap
114+
115+
// pad right of prefix, with lenght of current pointer
116+
suffix := m.CurrentMarker
117+
sufpad := strings.Repeat(" ", ansi.PrintableRuneWidth(suffix))
118+
114119
var visLines int
115120
var holeString bytes.Buffer
116121
out:
@@ -121,49 +126,59 @@ out:
121126
}
122127

123128
item := m.listItems[index]
129+
if item.wrapedLenght == 0 {
130+
panic("cant display item with no visible content")
131+
}
124132

125-
sepString := m.Seperator
126-
wrapString := m.SeperatorWrap
127133

128-
// handel highlighting and prefixing of selected lines
129-
style := termenv.String()
134+
var linePrefix, wrapPrefix string
135+
136+
// if a number is set, prepend firstline with number and both with enough spaceses
137+
firstPad := strings.Repeat(" ", numWidth)
138+
var wrapPad string
139+
if m.Number {
140+
lineNum := lineNumber(m.NumberRelative, m.curIndex, m.visibleOffset+index)
141+
number := fmt.Sprintf("%d", lineNum)
142+
// since diggets are only singel bytes len is sufficent:
143+
firstPad = strings.Repeat(" ", numWidth-len(number)) + number
144+
// pad wraped lines
145+
wrapPad = strings.Repeat(" ", numWidth)
146+
}
147+
148+
149+
// Selecting: handel highlighting and prefixing of selected lines
150+
selString := prepad // assume not selected
151+
style := termenv.String() // create empty style
152+
130153
if item.selected {
131-
style = m.SelectedBackGroundStyle
132-
sepString = m.SelectedPrefix + sepString
133-
wrapString = m.SelectedPrefix + wrapString
154+
style = m.SelectedBackGroundStyle // fill style
155+
selString = prefix // change if selected
134156
}
135157

136-
// handel highlighting of current line
158+
159+
// Current: handel highlighting of current item/first-line
160+
curPad := sufpad
137161
if index+m.visibleOffset == m.curIndex {
138162
style = style.Reverse()
139-
sepString = m.SeperatorCurrent
163+
curPad = suffix
140164
}
141165

142-
// if set, prepend firstline with enough space for linenumber and seperator
143-
// This while first create a string like: "%3d%4s"
144-
// Which will be than filled with linenumber and seperator string
145-
var firstPad string
146-
if m.AbsoluteNumber || m.RelativeNumber {
147-
lineOffset := m.visibleOffset + index
148-
firstPad = fmt.Sprintf("%"+fmt.Sprint(padWidth)+"d%"+fmt.Sprint(sepWidth)+"s", lineOffset, sepString)
149-
}
166+
// join all prefixes
167+
linePrefix = strings.Join([]string{firstPad, linePrefix, selString, sepItem, curPad}, "")
168+
wrapPrefix = strings.Join([]string{wrapPad, linePrefix, selString, sepWrap, sufpad}, "")
150169

151-
if item.wrapedLenght == 0 {
152-
panic("cant display item with no visible content")
153-
}
154170

155-
lineContent := item.wrapedLines[0]
156-
// join pad and line content
171+
// join pad and first line content
157172
// NOTE linebreak is not added here because it would mess with the highlighting
158-
line := fmt.Sprintf("%s%s", firstPad, lineContent)
173+
line := fmt.Sprintf("%s%s", linePrefix, item.wrapedLines[0])
159174

160175
// Highlight and write first line
161176
holeString.WriteString(style.Styled(line))
162177
holeString.WriteString("\n")
163178
visLines++
164179

165180
// Dont write wraped lines if not set
166-
if !m.Wrap || item.wrapedLenght < 1 {
181+
if !m.Wrap || item.wrapedLenght <= 1 {
167182
continue
168183
}
169184

@@ -175,10 +190,8 @@ out:
175190
// Write wraped lines
176191
for _, line := range item.wrapedLines[1:] {
177192
// Pad left of line
178-
// TODO performance: do stringlength and prepending befor loop
179-
pad := strings.Repeat(" ", holeWidth-runewidth.StringWidth(wrapString)) + wrapString
180193
// NOTE linebreak is not added here because it would mess with the highlighting
181-
padLine := fmt.Sprintf("%s%s", pad, line)
194+
padLine := fmt.Sprintf("%s%s", wrapPrefix, line)
182195

183196
// Highlight and write wraped line
184197
holeString.WriteString(style.Styled(padLine))
@@ -307,11 +320,11 @@ func NewModel() Model {
307320

308321
Wrap: true,
309322

310-
Seperator: "",
311-
SeperatorWrap: "",
312-
SeperatorCurrent: ">",
323+
Seperator: "",
324+
SeperatorWrap: "",
325+
CurrentMarker: ">",
313326
SelectedPrefix: "*",
314-
AbsoluteNumber: true,
327+
Number: true,
315328
less: func(k, l string) bool {
316329
return k < l
317330
},
@@ -392,3 +405,15 @@ func (m *Model) SetLess(less func(string, string) bool) {
392405
func (m *Model) Sort() {
393406
sort.Sort(m)
394407
}
408+
409+
func lineNumber(relativ bool, curser, current int) int {
410+
if !relativ || curser == current {
411+
return current
412+
}
413+
414+
diff := curser - current
415+
if diff < 0 {
416+
diff *= -1
417+
}
418+
return diff
419+
}

0 commit comments

Comments
 (0)