Stop the clipboard picker freezing on huge pastes (#6568)

Every keystroke in the search box scanned, lowercased, and split the
full text of every history entry, and the preview pane laid out the
entire selection with WrapAnywhere. A single 1.6MB paste (or a large
file selection) turned that into hundreds of megabytes of work on the
shell thread and stalled the render thread — freezing the whole
desktop.

Cap each entry once as it enters the display, so searching, previewing,
and rendering all work on a bounded prefix. Pasting reads the full entry
back from history by index, so nothing is actually lost. The cut lands
on a line break, keeping a file:// URI from truncating into a bogus path.

Co-authored-by: markbusking <marcosbustos.dev@gmail.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
markbus-ai
2026-08-09 14:01:37 +02:00
committed by GitHub
co-authored by markbusking Claude Opus 5
parent dd61d4a75b
commit c4dda58ba2
2 changed files with 41 additions and 1 deletions
+15 -1
View File
@@ -157,6 +157,20 @@ function fullText(entry) {
return String(entry.text || "")
}
// The picker only ever searches and renders a prefix of an entry, so scan and
// render just that much. A single huge paste otherwise costs hundreds of
// megabytes of string work on every keystroke and stalls the whole shell.
// Pasting reads the full entry back from history by index, so nothing is lost.
var displayTextLimit = 8192
function cappedEntry(entry) {
if (!entry || entry.type !== "text" || entry.text.length <= displayTextLimit) return entry
// Cut on a line break so a file:// URI never truncates into a bogus path.
var cut = entry.text.lastIndexOf("\n", displayTextLimit)
return { type: "text", text: entry.text.slice(0, cut > 0 ? cut : displayTextLimit) }
}
function displayRows(history, query, limit) {
var values = Array.isArray(history) ? history : []
var needle = String(query || "").trim().toLowerCase()
@@ -168,7 +182,7 @@ function displayRows(history, query, limit) {
var rows = []
for (var i = 0; i < values.length; i++) {
var entry = normalizeEntry(values[i])
var entry = cappedEntry(normalizeEntry(values[i]))
if (!entry) continue
if (needle && searchableText(entry).toLowerCase().indexOf(needle) < 0) continue