Speed up cold diffs and wrapped text measurement (#4676)

* perf(app): optimize wrapped measurements and checkpoint native layout experiment

Compute full grapheme geometry only for final wrap fragments. Preserve shaped-text search behavior while bounding additive wrap probes. Keep the Android background layout experiment isolated from the normal diff renderer; native renderer integration and iOS bindings remain unfinished.

* perf(server): reduce cold diff generation work

Keep active diff reads owned across invalidation and wait for the initial watcher inventory before cold generation. Batch patch and blob reads while preserving per-file size isolation, bounded output, and daemon responsiveness. Avoid constructing fallback tokens when full-file highlighting already covers both sides.

* test(server): exercise oversized highlighted diff rejection

The single-line fixture now bypasses highlighting under the long-line guard, so it no longer reaches the structured payload limit. Use short dense lines to keep testing oversized rejection and continued socket usability.

* fix(server): queue fresh diffs for forced reads

A forced request following a repository mutation must not reuse an older active build. Invalidate that result and coalesce waiting callers onto one subsequent build. Give the cache a named object input and completed-value type.

* test(server): share deferred diff loader setup

* test(server): name completed diff cache setup

* refactor(server): use aliases for new diff imports

* fix(server): keep shipped diff imports resolvable by Node

The TypeScript build preserves path aliases without a runtime resolver. Restore relative imports for shipped code and declarations, and correct the server import guideline that prompted the regression.
This commit is contained in:
Mohamed Boudra
2026-09-11 08:07:01 +02:00
committed by GitHub
parent 16d932651c
commit 33a52d0ae7
32 changed files with 1409 additions and 186 deletions
@@ -71,6 +71,78 @@ function input(overrides: Partial<BuildDiffDocumentModelInput> = {}): BuildDiffD
}
describe("diff document model", () => {
it("preserves shaped wrap breaks when joining makes a longer prefix narrower", () => {
const measure = (text: string) => {
if (text === "لا") return 30;
if (text === "لام") return 15;
return text.length * 10;
};
const fragments = measureFragments({
text: "لام",
availableWidth: 20,
wrapLines: true,
lineHeight: 18,
measureText: { measure, measureWidth: (graphemes) => measure(graphemes.join("")) },
});
expect(fragments.map((fragment) => fragment.text)).toEqual(["ل", "ام"]);
expect(fragments.map((fragment) => fragment.width)).toEqual([10, 20]);
});
it("does not search wrap boundaries when the remaining text already fits", () => {
let widthQueries = 0;
const fragments = measureFragments({
text: "const answer = value + 1;",
availableWidth: 300,
wrapLines: true,
lineHeight: 18,
measureText: {
measure: measurer.measure,
measureWidth(graphemes) {
widthQueries++;
return graphemes.length * 10;
},
},
});
expect(fragments).toHaveLength(1);
expect(fragments[0]?.width).toBe(250);
expect(widthQueries).toBe(1);
});
it("builds character geometry only for displayed wrapped fragments", () => {
let advancedGraphemes = 0;
const measureWidth = (graphemes: readonly string[]) => graphemes.length * 10;
const measureText = {
// Whole-string widths need not match the chunked advance contract.
measure: () => 999,
measureWidth,
measureAdvances(graphemes: readonly string[]) {
advancedGraphemes += graphemes.length;
return graphemes.map((_, index) => (index + 1) * 10);
},
};
const text = "const next = (value) => value + 1;".repeat(4);
const fragments = measureFragments({
text,
availableWidth: 80,
wrapLines: true,
lineHeight: 18,
measureText,
});
expect(fragments.map((fragment) => fragment.text).join("")).toBe(text);
expect(fragments.every((fragment) => fragment.width <= 80)).toBe(true);
expect(fragments).toEqual(
measureFragments({
text,
availableWidth: 80,
wrapLines: true,
lineHeight: 18,
measureText: { measure: measurer.measure },
}),
);
expect(advancedGraphemes).toBe(text.length);
});
it("materializes only visible rows of a large file while preserving full horizontal extent", () => {
const source = file("large.ts");
source.hunks[0]!.lines = Array.from({ length: 1000 }, (_, index) => ({