Skip to content

Commit 44bf335

Browse files
hajimehoshiclaude
andcommitted
basicwidget: clear dropped elements in reused buffers
A buffer reused across calls keeps its dropped elements in the backing array when truncated with s[:0], pinning every reference those elements hold. Replace such truncations with slices.Delete, which zeroes the removed range while keeping the capacity. The affected buffers: - PieceTable.history, in both the redo truncation and resetHistory. Each dropped historyItem owns a cloned items slice, so a discarded redo state, or a previous document's entire undo history, stayed alive. - Combobox.filteredItems, refilled on every keystroke while filtering, stranding the strings and content widgets of the items that a narrowed query no longer matches. - tmpLocales and prevLocales in resolveFace, as language.Tag embeds an interface. tmpLocales kept its whole contents live after the function returned. - tableRowWidget.textColumnLayouts, the only one of the three buffers reset together there that was not already cleared. appendVisualLinesFromCachedStarts had the same problem on its failure path: it returned dst[:base] after having appended, leaving those elements uncleared past the caller's length, out of reach of the caller's deferred clear. Drop the redundant re-truncation in Draw as well, which only ran when theVisualLinesBuffer was already empty. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent c3b2cc2 commit 44bf335

5 files changed

Lines changed: 7 additions & 7 deletions

File tree

basicwidget/combobox.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ func (c *Combobox) OnValueChanged(f func(context *guigui.Context, value string,
110110

111111
func (c *Combobox) updateFilteredItems() {
112112
input := strings.ToLower(c.textInput.Value())
113-
c.filteredItems = c.filteredItems[:0]
113+
c.filteredItems = slices.Delete(c.filteredItems, 0, len(c.filteredItems))
114114
for _, item := range c.items {
115115
if input == "" || strings.Contains(strings.ToLower(item), input) {
116116
c.filteredItems = append(c.filteredItems, PopupMenuItem[string]{

basicwidget/internal/font/font.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -270,8 +270,9 @@ func resolveFace(context *guigui.Context, fnt *Family, attributes Attributes) (t
270270
tmpLocales = context.AppendLocales(tmpLocales[:0])
271271
if !slices.Equal(prevLocales, tmpLocales) {
272272
clear(theFaceCache)
273-
prevLocales = append(prevLocales[:0], tmpLocales...)
273+
prevLocales = append(slices.Delete(prevLocales, 0, len(prevLocales)), tmpLocales...)
274274
}
275+
tmpLocales = slices.Delete(tmpLocales, 0, len(tmpLocales))
275276

276277
var familyID uint64
277278
if fnt != nil {

basicwidget/internal/piecetable/piecetable.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -344,7 +344,7 @@ func (p *PieceTable) ReadFrom(r io.Reader) (int64, error) {
344344
}
345345

346346
func (p *PieceTable) resetHistory() {
347-
p.history = p.history[:0]
347+
p.history = slices.Delete(p.history, 0, len(p.history))
348348
p.history = append(p.history, historyItem{
349349
items: []pieceTableItem{
350350
{
@@ -573,7 +573,7 @@ func (p *PieceTable) maybeAppendHistory(text string, start, end int, fromIME boo
573573
func (p *PieceTable) appendHistory(undoStart, undoEnd, redoStart, redoEnd int) {
574574
// Truncate the history.
575575
if p.historyIndex < len(p.history)-1 {
576-
p.history = p.history[:p.historyIndex+1]
576+
p.history = slices.Delete(p.history, p.historyIndex+1, len(p.history))
577577
}
578578

579579
// Append the current items (cloned) to the history.

basicwidget/internal/textutil/draw.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ func appendVisualLinesFromCachedStarts(dst []visualLine, str string, width int,
132132
line := str[pos:lineEnd]
133133
s, sok := cachedVisualLineStarts(width, line, wrapMode, face, tabWidth, keepTailingSpace)
134134
if !sok {
135-
return dst[:base], false
135+
return slices.Delete(dst, base, len(dst)), false
136136
}
137137
for i := range s {
138138
rs := pos + s[i]
@@ -184,7 +184,6 @@ func Draw(bounds image.Rectangle, dst *ebiten.Image, str string, options *DrawOp
184184
}
185185
}
186186
if !built {
187-
theVisualLinesBuffer = theVisualLinesBuffer[:0]
188187
for vl := range visualLines(layoutWidth, str, options.WrapMode, func(str string, indexInBytes int) float64 {
189188
return advance(str, indexInBytes, options.Face.TextFace(), options.TabWidth, options.KeepTailingSpace)
190189
}) {

basicwidget/table.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -365,7 +365,7 @@ func (t *tableRowWidget[T]) Build(context *guigui.Context, adder *guigui.ChildAd
365365

366366
func (t *tableRowWidget[T]) Layout(context *guigui.Context, widgetBounds *guigui.WidgetBounds, layouter *guigui.ChildLayouter) {
367367
t.linearLayoutItems = slices.Delete(t.linearLayoutItems, 0, len(t.linearLayoutItems))
368-
t.textColumnLayouts = t.textColumnLayouts[:0]
368+
t.textColumnLayouts = slices.Delete(t.textColumnLayouts, 0, len(t.textColumnLayouts))
369369
t.textColumnLayoutItems = slices.Delete(t.textColumnLayoutItems, 0, len(t.textColumnLayoutItems))
370370
for i := range t.table.columnWidthsInPixels {
371371
if i < len(t.row.Cells) && t.row.Cells[i].Content != nil {

0 commit comments

Comments
 (0)