дзеркало
https://github.com/l0ng-ai/openidea.git
синхронізовано 2026-11-09 19:25:54 +02:00
fix(editor): restore an evicted tab's exact scroll offset (#2324)
Цей коміт міститься в:
1 джерело
5a48beab07
коміт
2955cdcf9c
2 files changed
+31
-3
No files matched your search
@@ -347,6 +347,28 @@ describe("DocumentManager + slots", () => {
|
||||
for (const slot of slots) slot.dispose();
|
||||
manager.stop();
|
||||
});
|
||||
|
||||
it("restores a destroyed kept view at its exact scroll offset, not its top line", async () => {
|
||||
const { manager } = setup({ "/p/a.txt": "line\n".repeat(500) });
|
||||
const model = await manager.acquire("/p/a.txt");
|
||||
const slot = new EditorSlot(model, "t0", host);
|
||||
const view = slot.mount(document.body);
|
||||
Object.defineProperty(view.scrollDOM, "scrollTop", { value: 137, configurable: true });
|
||||
view.scrollDOM.dispatchEvent(new Event("scroll"));
|
||||
slot.unmount();
|
||||
const expected = view.scrollSnapshot().value as { range: unknown; yMargin: number; isSnapshot: boolean };
|
||||
const others = Array.from({ length: 8 }, (_, i) => new EditorSlot(model, `t${i + 1}`, host));
|
||||
for (const other of others) {
|
||||
other.mount(document.body);
|
||||
other.unmount();
|
||||
}
|
||||
const restored = (slot as unknown as { scroll: { value: typeof expected } }).scroll.value;
|
||||
expect(restored.isSnapshot).toBe(true);
|
||||
expect(restored.range).toEqual(expected.range);
|
||||
expect(restored.yMargin).toBe(expected.yMargin);
|
||||
for (const s of [slot, ...others]) s.dispose();
|
||||
manager.stop();
|
||||
});
|
||||
});
|
||||
|
||||
describe("save cleanup", () => {
|
||||
|
||||
@@ -242,9 +242,8 @@ export class EditorSlot {
|
||||
this.kept = null;
|
||||
const i = keptSlots.indexOf(this);
|
||||
if (i >= 0) keptSlots.splice(i, 1);
|
||||
const top = topLineAt(view, this.scrollPos.top);
|
||||
this.savedTopLine = top;
|
||||
this.scroll = EditorView.scrollIntoView(view.state.doc.line(top + 1).from, { y: "start" });
|
||||
this.savedTopLine = topLineAt(view, this.scrollPos.top);
|
||||
this.scroll = scrollSnapshotAt(view, this.scrollPos);
|
||||
this.stored = view.state;
|
||||
view.destroy();
|
||||
}
|
||||
@@ -399,6 +398,13 @@ function topLineOf(view: EditorView): number {
|
||||
return topLineAt(view, view.scrollDOM.scrollTop);
|
||||
}
|
||||
|
||||
/** `view.scrollSnapshot()` at a tracked offset: a detached view's scrollDOM reports 0. */
|
||||
function scrollSnapshotAt(view: EditorView, pos: { top: number; left: number }): StateEffect<unknown> {
|
||||
const atPos = Object.create(view) as EditorView;
|
||||
Object.defineProperty(atPos, "scrollDOM", { value: { scrollTop: pos.top, scrollLeft: pos.left } });
|
||||
return atPos.scrollSnapshot();
|
||||
}
|
||||
|
||||
function topLineAt(view: EditorView, scrollTop: number): number {
|
||||
const block = view.lineBlockAtHeight(Math.max(0, scrollTop));
|
||||
return view.state.doc.lineAt(block.from).number - 1;
|
||||
|
||||
Reference in new issue
Заблокувати користувача