@ 261105.1

261022.4 · acf267d89712449124fa5e7bf14a80cfa3ce48e5

perf(cell): reuse the drawn width when putting back the same text

reading declarations

cell.go

@@ -23,6 +23,7 @@ type cell struct { 	lastStyle Style 	width     int 	lock      bool+	lastWidth int8 // width of lastStr, or 0 when lastStr marks a redraw }  func (c *cell) setDirty(dirty bool) {@@ -36,12 +37,14 @@ func (c *cell) setDirty(dirty bool) { 		} else { 			c.lastStr = "" 		}+		c.lastWidth = 0 	} else { 		if c.currStr == "" { 			c.currStr = " " 		} 		c.lastStr = c.currStr 		c.lastStyle = c.currStyle+		c.lastWidth = int8(c.width) 	} } @@ -82,6 +85,10 @@ func (cb *CellBuffer) put(x int, y int, str string, style Style) (string, int) { 			// Printable ASCII followed by ASCII cannot be part of a larger 			// grapheme cluster, so avoid constructing a grapheme iterator. 			cl, width, str = str[:1], 1, str[1:]+		} else if str == c.lastStr && c.lastWidth > 0 {+			// Putting back what is on screen, as after a Clear: reuse the+			// width measured when it was drawn.+			cl, width, str = str, int(c.lastWidth), "" 		} else { 			g := textWidthOptions.StringGraphemes(str) 			for width == 0 && g.Next() {

cell_test.go

@@ -349,3 +349,33 @@ func TestCellBufferFillAreaColorNone(t *testing.T) { 		t.Fatalf("ColorNone should preserve existing colors, got %v", style) 	} }++func TestCellBufferRePutAfterClear(t *testing.T) {+	cb := &CellBuffer{}+	cb.Resize(4, 1)+	for _, str := range []string{"宽", "🎉", "👩‍👩‍👧‍👦", "e\u0301"} {+		_, want := cb.Put(0, 0, str, StyleDefault)+		cb.SetDirty(0, 0, false) // drawn++		// Putting back what is on screen after a Clear reuses the width+		// measured when it was drawn.+		cb.Put(0, 0, " ", StyleDefault) // what Clear leaves+		if rest, width := cb.Put(0, 0, str, StyleDefault); rest != "" || width != want {+			t.Errorf("%q: got %q, %d after clearing, want \"\", %d", str, rest, width, want)+		}+	}+}++func TestCellBufferRePutAfterRedrawMarker(t *testing.T) {+	cb := &CellBuffer{}+	cb.Resize(4, 1)+	cb.Put(0, 0, "宽", StyleDefault)+	cb.SetDirty(0, 0, false) // drawn, two columns wide++	// Marking the cell for redraw sets lastStr to "", which must not keep+	// the width of what was drawn.+	cb.SetDirty(0, 0, true)+	if _, width := cb.Put(0, 0, "", StyleDefault); width != 0 {+		t.Fatalf("empty string width %d, want 0", width)+	}+}