Skip to content

Commit

Permalink
start multilinebuffer
Browse files Browse the repository at this point in the history
  • Loading branch information
robinovitch61 committed Feb 1, 2025
1 parent 255fc83 commit d6d33b4
Show file tree
Hide file tree
Showing 7 changed files with 175 additions and 45 deletions.
17 changes: 11 additions & 6 deletions internal/model/entity.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,23 @@ type Entity struct {
State EntityState
}

func (e Entity) Render() linebuffer.LineBuffer {
func (e Entity) Render() linebuffer.LineBufferer {
if e.IsCluster {
return linebuffer.New(e.Prefix + e.Container.Cluster)
lb := linebuffer.New(e.Prefix + e.Container.Cluster)
return &lb
} else if e.IsNamespace {
return linebuffer.New(e.Prefix + e.Container.Namespace)
lb := linebuffer.New(e.Prefix + e.Container.Namespace)
return &lb
} else if e.IsPodOwner {
res := e.Prefix + e.Container.PodOwner
if e.Container.PodOwnerMetadata.OwnerType != "" {
res += " <" + e.Container.PodOwnerMetadata.OwnerType + ">"
}
return linebuffer.New(res)
lb := linebuffer.New(res)
return &lb
} else if e.IsPod {
return linebuffer.New(e.Prefix + e.Container.Pod)
lb := linebuffer.New(e.Prefix + e.Container.Pod)
return &lb
} else {
// for containers
res := e.Prefix + e.State.StatusIndicator() + " " + e.Container.Name + " (" + e.Container.Status.State.String()
Expand Down Expand Up @@ -66,7 +70,8 @@ func (e Entity) Render() linebuffer.LineBuffer {
}

res += ")"
return linebuffer.New(res)
lb := linebuffer.New(res)
return &lb
}
}

Expand Down
41 changes: 21 additions & 20 deletions internal/model/page_log.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,26 +34,27 @@ type PageLog struct {
Styles *style.Styles
}

func (l PageLog) Render() linebuffer.LineBuffer {
//ts := ""
//if l.CurrentTimestamp != "" {
// ts = l.Styles.Green.Render(l.CurrentTimestamp)
//}
//label := ""
//if l.CurrentName.ContainerName != "" {
// if ts != "" {
// label += " "
// }
// label += l.RenderName(l.CurrentName, true)
//}
//
//prefix := ts + label
//if len(prefix) > 0 {
// if l.Log.LineBuffer.Content != "" {
// prefix = prefix + " "
// }
//}
return l.Log.LineBuffer // TODO LEO: figure out how to combine prefix and linebuffer
func (l PageLog) Render() linebuffer.LineBufferer {
ts := ""
if l.CurrentTimestamp != "" {
ts = l.Styles.Green.Render(l.CurrentTimestamp)
}
label := ""
if l.CurrentName.ContainerName != "" {
if ts != "" {
label += " "
}
label += l.RenderName(l.CurrentName, true)
}

prefix := ts + label
if len(prefix) > 0 {
if l.Log.LineBuffer.Content() != "" {
prefix = prefix + " "
}
}
return linebuffer.NewMulti(linebuffer.New(prefix), l.Log.LineBuffer)
//return l.Log.LineBuffer // TODO LEO: figure out how to combine prefix and linebuffer
}

func (l PageLog) Equals(other interface{}) bool {
Expand Down
9 changes: 0 additions & 9 deletions internal/viewport/linebuffer/linebuffer.go
Original file line number Diff line number Diff line change
Expand Up @@ -665,12 +665,3 @@ func getLeftRuneIdx(w int, vals []uint32) int {

return left + 1
}

// TODO LEO: inline this where it's used
func ToLineBuffers(lines []string) []LineBuffer {
res := make([]LineBuffer, len(lines))
for i, line := range lines {
res[i] = New(line)
}
return res
}
123 changes: 123 additions & 0 deletions internal/viewport/linebuffer/multilinebuffer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
package linebuffer

import "github.com/charmbracelet/lipgloss/v2"

// MultiLineBuffer implements LineBufferer by wrapping multiple LineBuffers without extra memory allocation
type MultiLineBuffer struct {
buffers []LineBuffer
currentBufferIdx int // tracks which buffer we're currently reading from
totalWidth int // cached total width across all buffers
}

// type assertion that *MultiLineBuffer implements LineBufferer
var _ LineBufferer = (*MultiLineBuffer)(nil)

func NewMulti(buffers ...LineBuffer) *MultiLineBuffer {
if len(buffers) == 0 {
return &MultiLineBuffer{}
}

// calculate total width
totalWidth := 0
for _, buf := range buffers {
totalWidth += buf.Width()
}

return &MultiLineBuffer{
buffers: buffers,
totalWidth: totalWidth,
}
}

func (m *MultiLineBuffer) Width() int {
return m.totalWidth
}

// TODO LEO: don't use this for e.g. search, instead inject filter into a Matches() bool method here
func (m *MultiLineBuffer) Content() string {
totalLen := 0
for _, buf := range m.buffers {
totalLen += len(buf.Content())
}

result := make([]byte, 0, totalLen)
for _, buf := range m.buffers {
result = append(result, buf.Content()...)
}
return string(result)
}

func (m *MultiLineBuffer) SeekToWidth(width int) {
if width <= 0 {
m.currentBufferIdx = 0
if len(m.buffers) > 0 {
m.buffers[0].SeekToWidth(0)
}
return
}

// find which buffer contains the target width
remainingWidth := width
for i, buf := range m.buffers {
bufWidth := buf.Width()
if remainingWidth <= bufWidth {
// found the buffer containing our target
m.currentBufferIdx = i
m.buffers[i].SeekToWidth(remainingWidth)
return
}
remainingWidth -= bufWidth
}

// if we get here, we're seeking past the end
if len(m.buffers) > 0 {
m.currentBufferIdx = len(m.buffers) - 1
m.buffers[m.currentBufferIdx].SeekToWidth(m.buffers[m.currentBufferIdx].Width())
}
}

func (m *MultiLineBuffer) PopLeft(width int, continuation, toHighlight string, highlightStyle lipgloss.Style) string {
if len(m.buffers) == 0 || width == 0 {
return ""
}

// get content from current buffer
result := m.buffers[m.currentBufferIdx].PopLeft(width, continuation, toHighlight, highlightStyle)

// if we got less than requested width and have more buffers, move to next buffer
if resultWidth := lipgloss.Width(result); resultWidth < width && m.currentBufferIdx < len(m.buffers)-1 {
m.currentBufferIdx++
m.buffers[m.currentBufferIdx].SeekToWidth(0)
// get remaining content from next buffer
remainingWidth := width - resultWidth
nextResult := m.buffers[m.currentBufferIdx].PopLeft(remainingWidth, continuation, toHighlight, highlightStyle)
result += nextResult
}

return result
}

func (m *MultiLineBuffer) WrappedLines(width int, maxLinesEachEnd int, toHighlight string, toHighlightStyle lipgloss.Style) []string {
if width <= 0 {
return nil
}

// reset position
m.SeekToWidth(0)

var result []string
currentLine := m.PopLeft(width, "", toHighlight, toHighlightStyle)
for currentLine != "" {
result = append(result, currentLine)
currentLine = m.PopLeft(width, "", toHighlight, toHighlightStyle)
}

// handle maxLinesEachEnd if specified
if maxLinesEachEnd > 0 && len(result) > maxLinesEachEnd*2 {
firstN := result[:maxLinesEachEnd]
lastN := result[len(result)-maxLinesEachEnd:]
result = append(firstN, lastN...)
}

return result
}
6 changes: 3 additions & 3 deletions internal/viewport/renderable.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ package viewport
import "github.com/robinovitch61/kl/internal/viewport/linebuffer"

type RenderableComparable interface {
Render() linebuffer.LineBuffer
Render() linebuffer.LineBufferer
Equals(other interface{}) bool
}

type RenderableString struct {
LineBuffer linebuffer.LineBuffer
LineBuffer linebuffer.LineBufferer
}

func (r RenderableString) Render() linebuffer.LineBuffer {
func (r RenderableString) Render() linebuffer.LineBufferer {
return r.LineBuffer
}

Expand Down
3 changes: 2 additions & 1 deletion internal/viewport/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ func clampValMinMax(v, minimum, maximum int) int {
func setContent(vp *Model[RenderableString], content []string) {
renderableStrings := make([]RenderableString, len(content))
for i := range content {
renderableStrings[i] = RenderableString{LineBuffer: linebuffer.New(content[i])}
lb := linebuffer.New(content[i])
renderableStrings[i] = RenderableString{LineBuffer: &lb}
}
vp.SetContent(renderableStrings)
}
21 changes: 15 additions & 6 deletions internal/viewport/viewport.go
Original file line number Diff line number Diff line change
Expand Up @@ -672,7 +672,7 @@ func (m Model[T]) getVisibleHeaderLines() []string {

type visibleContentLinesResult struct {
// lines is the untruncated visible lines, each corresponding to one terminal row
lines []linebuffer.LineBuffer
lines []linebuffer.LineBufferer
// itemIndexes is the index of the item in allItems that corresponds to each line. len(itemIndexes) == len(lines)
itemIndexes []int
// showFooter is true if the footer should be shown due to the num visible lines exceeding the vertical space
Expand All @@ -689,17 +689,17 @@ func (m Model[T]) getVisibleContentLines() visibleContentLinesResult {
return visibleContentLinesResult{lines: nil, itemIndexes: nil, showFooter: false}
}

var contentLines []linebuffer.LineBuffer
var contentLines []linebuffer.LineBufferer
var itemIndexes []int

numLinesAfterHeader := max(0, m.height-len(m.getVisibleHeaderLines()))

addLine := func(l linebuffer.LineBuffer, itemIndex int) bool {
addLine := func(l linebuffer.LineBufferer, itemIndex int) bool {
contentLines = append(contentLines, l)
itemIndexes = append(itemIndexes, itemIndex)
return len(contentLines) == numLinesAfterHeader
}
addLines := func(ls []linebuffer.LineBuffer, itemIndex int) bool {
addLines := func(ls []linebuffer.LineBufferer, itemIndex int) bool {
for i := range ls {
if addLine(ls[i], itemIndex) {
return true
Expand All @@ -720,7 +720,7 @@ func (m Model[T]) getVisibleContentLines() visibleContentLinesResult {
lb := currItem.Render()
itemLines := lb.WrappedLines(m.width, m.height, m.stringToHighlight, m.highlightStyle(currItemIdx))
offsetLines := safeSliceFromIdx(itemLines, m.topItemLineOffset)
done = addLines(linebuffer.ToLineBuffers(offsetLines), currItemIdx)
done = addLines(toLineBuffers(offsetLines), currItemIdx)

for !done {
currItemIdx += 1
Expand All @@ -730,7 +730,7 @@ func (m Model[T]) getVisibleContentLines() visibleContentLinesResult {
currItem = m.allItems[currItemIdx]
lb = currItem.Render()
itemLines = lb.WrappedLines(m.width, m.height, m.stringToHighlight, m.highlightStyle(currItemIdx))
done = addLines(linebuffer.ToLineBuffers(itemLines), currItemIdx)
done = addLines(toLineBuffers(itemLines), currItemIdx)
}
}
} else {
Expand Down Expand Up @@ -924,3 +924,12 @@ func (m Model[T]) styleSelection(s string) string {
}
return builder.String()
}

func toLineBuffers(lines []string) []linebuffer.LineBufferer {
res := make([]linebuffer.LineBufferer, len(lines))
for i, line := range lines {
lb := linebuffer.New(line)
res[i] = &lb
}
return res
}

0 comments on commit d6d33b4

Please sign in to comment.