init claude-code
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
import type { Diff } from './frame.js'
|
||||
|
||||
/**
|
||||
* Optimize a diff by applying all optimization rules in a single pass.
|
||||
* This reduces the number of patches that need to be written to the terminal.
|
||||
*
|
||||
* Rules applied:
|
||||
* - Remove empty stdout patches
|
||||
* - Merge consecutive cursorMove patches
|
||||
* - Remove no-op cursorMove (0,0) patches
|
||||
* - Concat adjacent style patches (transition diffs — can't drop either)
|
||||
* - Dedupe consecutive hyperlinks with same URI
|
||||
* - Cancel cursor hide/show pairs
|
||||
* - Remove clear patches with count 0
|
||||
*/
|
||||
export function optimize(diff: Diff): Diff {
|
||||
if (diff.length <= 1) {
|
||||
return diff
|
||||
}
|
||||
|
||||
const result: Diff = []
|
||||
let len = 0
|
||||
|
||||
for (const patch of diff) {
|
||||
const type = patch.type
|
||||
|
||||
// Skip no-ops
|
||||
if (type === 'stdout') {
|
||||
if (patch.content === '') continue
|
||||
} else if (type === 'cursorMove') {
|
||||
if (patch.x === 0 && patch.y === 0) continue
|
||||
} else if (type === 'clear') {
|
||||
if (patch.count === 0) continue
|
||||
}
|
||||
|
||||
// Try to merge with previous patch
|
||||
if (len > 0) {
|
||||
const lastIdx = len - 1
|
||||
const last = result[lastIdx]!
|
||||
const lastType = last.type
|
||||
|
||||
// Merge consecutive cursorMove
|
||||
if (type === 'cursorMove' && lastType === 'cursorMove') {
|
||||
result[lastIdx] = {
|
||||
type: 'cursorMove',
|
||||
x: last.x + patch.x,
|
||||
y: last.y + patch.y,
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// Collapse consecutive cursorTo (only the last one matters)
|
||||
if (type === 'cursorTo' && lastType === 'cursorTo') {
|
||||
result[lastIdx] = patch
|
||||
continue
|
||||
}
|
||||
|
||||
// Concat adjacent style patches. styleStr is a transition diff
|
||||
// (computed by diffAnsiCodes(from, to)), not a setter — dropping
|
||||
// the first is only sound if its undo-codes are a subset of the
|
||||
// second's, which is NOT guaranteed. e.g. [\e[49m, \e[2m]: dropping
|
||||
// the bg reset leaks it into the next \e[2J/\e[2K via BCE.
|
||||
if (type === 'styleStr' && lastType === 'styleStr') {
|
||||
result[lastIdx] = { type: 'styleStr', str: last.str + patch.str }
|
||||
continue
|
||||
}
|
||||
|
||||
// Dedupe hyperlinks
|
||||
if (
|
||||
type === 'hyperlink' &&
|
||||
lastType === 'hyperlink' &&
|
||||
patch.uri === last.uri
|
||||
) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Cancel cursor hide/show pairs
|
||||
if (
|
||||
(type === 'cursorShow' && lastType === 'cursorHide') ||
|
||||
(type === 'cursorHide' && lastType === 'cursorShow')
|
||||
) {
|
||||
result.pop()
|
||||
len--
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
result.push(patch)
|
||||
len++
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
Reference in New Issue
Block a user