chore(tui): /clean recent perf work — KISS/DRY pass

24 files, -319 LoC. Behaviour preserved, 369/369 tests green.

- hermes-ink caches: shared lruEvict helper for the four parallel LRU
  caches (stringWidth, wrapText, sliceAnsi, lineWidth); touch-on-read
  stays inlined per cache; tightened output.ts skip-slice fast path.
- wheelAccel: trimmed provenance header, collapsed env parsing, ternary
  dispatch in computeWheelStep.
- perfPane: folded ensureLogDir into once-flag, spread-with-overrides
  for fastPath/phases instead of full rebuilds.
- env: extracted truthy() (used 4×).
- virtualHeights: collapsed user/diff/slash height bumps; trail+todos
  estimate.
- useInputHandlers: scrollIdleTimer cleanup on unmount, ?? undefined
  shorthand.
- useMainApp: dropped dead liveTailVisible IIFE and liveProgress
  indirection.
- appLayout, markdown, messageLine, entry: vertical rhythm, dropped
  narration comments, inlined one-shot vars.
- fix: empty catch blocks → /* best-effort */ for no-empty lint.
This commit is contained in:
Brooklyn Nicholson 2026-04-26 20:38:47 -05:00
parent 527ac351b4
commit b1c49d5e73
32 changed files with 259 additions and 547 deletions

View file

@ -1,5 +1,5 @@
import { Box, Link, Text } from '@hermes/ink'
import { memo, useMemo, type ReactNode } from 'react'
import { memo, type ReactNode, useMemo } from 'react'
import { ensureEmojiPresentation } from '../lib/emoji.js'
import { highlightLine, isHighlightable } from '../lib/syntax.js'
@ -213,26 +213,23 @@ function MdInline({ t, text }: { t: Theme; text: string }) {
return <Text>{parts.length ? parts : <Text>{text}</Text>}</Text>
}
// Cross-instance parsed-children cache. `Md` is mounted fresh whenever a
// virtualized row enters the mount window — useMemo's per-instance cache
// doesn't survive remounts, so PageUp into cold/resumed history reparses
// every row (markdown scan + per-line syntax highlight).
//
// Outer WeakMap keyed by theme so palette swaps drop stale baked-in colors
// without code intervention. Inner Map is LRU-bounded; key folds `compact`
// in so the two layout modes don't poison each other.
// Cross-instance parsed-children cache: useMemo's per-instance cache dies
// on remount, so virtualization re-parses every row that scrolls back into
// view. Theme-keyed WeakMap drops stale palettes; inner Map is LRU-bounded.
const MD_CACHE_LIMIT = 512
const mdCache = new WeakMap<Theme, Map<string, ReactNode[]>>()
const cacheBucket = (t: Theme) => {
let b = mdCache.get(t)
const b = mdCache.get(t)
if (!b) {
b = new Map()
mdCache.set(t, b)
if (b) {
return b
}
return b
const fresh = new Map<string, ReactNode[]>()
mdCache.set(t, fresh)
return fresh
}
const cacheGet = (b: Map<string, ReactNode[]>, key: string) => {