@timurproko/a1 0.2.7-dev.1255 → 0.2.7-dev.1264
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/app/session-shell/prompt-submission.d.ts +1 -1
- package/dist/app/session-shell/prompt-submission.js +9 -9
- package/dist/app/session-shell/resource-labels.d.ts +2 -0
- package/dist/app/session-shell/resource-labels.js +158 -0
- package/dist/app/session-shell/session-prompt-history.d.ts +29 -0
- package/dist/app/session-shell/session-prompt-history.js +80 -0
- package/dist/app/session-shell/session-selectors.d.ts +46 -0
- package/dist/app/session-shell/session-selectors.js +269 -0
- package/dist/app/session-shell/session-shell-root.d.ts +6 -28
- package/dist/app/session-shell/session-shell-root.js +26 -220
- package/dist/app/session-shell/session-shell.d.ts +3 -23
- package/dist/app/session-shell/session-shell.js +54 -365
- package/dist/app/session-shell/session-viewport-controller.d.ts +2 -10
- package/dist/app/session-shell/session-viewport-controller.js +40 -318
- package/dist/app/session-shell/settings-bindings.d.ts +1 -1
- package/dist/app/session-shell/settings-bindings.js +2 -2
- package/dist/app/session-shell/viewport-pointer.d.ts +83 -0
- package/dist/app/session-shell/viewport-pointer.js +361 -0
- package/dist/composition/owned-ui.js +63 -59
- package/dist/contracts/owned-ui/index.d.ts +1 -1
- package/dist/contracts/owned-ui/index.js +1 -1
- package/dist/contracts/owned-ui/validation.d.ts +1 -11
- package/dist/contracts/owned-ui/validation.js +8 -104
- package/dist/contracts/presentation/index.d.ts +1 -1
- package/dist/contracts/presentation/terminal.d.ts +0 -6
- package/dist/features/owned-ui/settings-app.js +13 -208
- package/dist/features/owned-ui/settings-model-dialog.d.ts +41 -0
- package/dist/features/owned-ui/settings-model-dialog.js +194 -0
- package/dist/foundation/release/automatic-update.js +1 -8
- package/dist/foundation/release/dependency-layer.js +3 -3
- package/dist/foundation/release/latest-release.js +1 -1
- package/dist/foundation/release/managed-path.d.ts +10 -0
- package/dist/foundation/release/managed-path.js +26 -0
- package/dist/foundation/release/release-gc.js +6 -8
- package/dist/foundation/release/restart-certification.js +3 -4
- package/dist/foundation/release/update-activation.js +1 -1
- package/dist/foundation/release/update-execution-lease.js +1 -7
- package/dist/foundation/release/update-installer.d.ts +45 -0
- package/dist/foundation/release/update-installer.js +57 -0
- package/dist/foundation/release/update-recovery.js +2 -9
- package/dist/foundation/release/update.d.ts +4 -23
- package/dist/foundation/release/update.js +160 -179
- package/dist/integrations/pi/components/bracketed-paste.d.ts +33 -0
- package/dist/integrations/pi/components/bracketed-paste.js +123 -0
- package/dist/integrations/pi/components/owned-editor-ux.js +46 -140
- package/dist/integrations/pi/engine/adapter.d.ts +1 -8
- package/dist/integrations/pi/engine/adapter.js +6 -49
- package/dist/integrations/pi/engine/host.js +1 -1
- package/dist/integrations/pi/engine/repository-metadata.d.ts +49 -0
- package/dist/integrations/pi/engine/repository-metadata.js +189 -0
- package/dist/integrations/pi/engine/session-runtime.d.ts +6 -12
- package/dist/integrations/pi/engine/session-runtime.js +21 -178
- package/dist/integrations/pi/engine/view-state.d.ts +21 -2
- package/dist/integrations/pi/engine/view-state.js +129 -1
- package/dist/integrations/pi/engine/workflow-runner.d.ts +0 -1
- package/dist/integrations/pi/engine/workflow-runner.js +254 -365
- package/dist/integrations/pi/engine/workflow-share.d.ts +9 -0
- package/dist/integrations/pi/engine/workflow-share.js +168 -0
- package/dist/integrations/pi/engine/workflow-support.d.ts +0 -14
- package/dist/integrations/pi/engine/workflow-support.js +0 -47
- package/dist/integrations/pi/tui-runtime/adapter.d.ts +9 -19
- package/dist/integrations/pi/tui-runtime/adapter.js +35 -144
- package/dist/integrations/pi/tui-runtime/damage-aware-terminal.d.ts +4 -4
- package/dist/integrations/pi/tui-runtime/index.d.ts +0 -1
- package/dist/integrations/pi/tui-runtime/overlay-geometry.d.ts +2 -2
- package/dist/integrations/pi/tui-runtime/presentation-adapter.d.ts +2 -2
- package/dist/ui/components/transcript-viewport-frame.d.ts +120 -0
- package/dist/ui/components/transcript-viewport-frame.js +314 -0
- package/dist/ui/components/transcript-viewport-types.d.ts +147 -0
- package/dist/ui/components/transcript-viewport.d.ts +2 -147
- package/dist/ui/components/transcript-viewport.js +87 -315
- package/package.json +3 -3
- package/dist/integrations/pi/engine/diagnostics-state.d.ts +0 -9
- package/dist/integrations/pi/engine/diagnostics-state.js +0 -34
- package/dist/integrations/pi/engine/usage-view.d.ts +0 -4
- package/dist/integrations/pi/engine/usage-view.js +0 -56
- package/dist/integrations/pi/tui-runtime/contracts.d.ts +0 -22
- /package/dist/{integrations/pi/tui-runtime/contracts.js → ui/components/transcript-viewport-types.js} +0 -0
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
import { samePointerSurfaces } from "../../contracts/presentation/index.js";
|
|
2
2
|
import { TranscriptViewport } from "../../ui/components/transcript-viewport.js";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { scrollForTrackPage, scrollForThumbRow, scrollbarSelectionRows, scrollbarWheelRows } from "../../ui/components/scrollbar.js";
|
|
6
|
-
function withinTailControl(region, column, row) {
|
|
7
|
-
return row >= region.rowStart && row <= region.rowEnd && column >= region.columnStart && column <= region.columnEnd;
|
|
8
|
-
}
|
|
3
|
+
import { scrollbarSelectionRows } from "../../ui/components/scrollbar.js";
|
|
4
|
+
import { ViewportPointerGestures, withinTailControl } from "./viewport-pointer.js";
|
|
9
5
|
/**
|
|
10
6
|
* Owns the stateful interaction policy of the bare-A1 session viewport. The
|
|
11
7
|
* shell root supplies semantic rows and dock geometry; this controller owns
|
|
@@ -26,27 +22,16 @@ export class SessionViewportController {
|
|
|
26
22
|
scrollbarStyle: "thin",
|
|
27
23
|
scrollbarSpeed: "normal",
|
|
28
24
|
};
|
|
29
|
-
#dragGrabOffset = null;
|
|
30
25
|
#inputSurface;
|
|
31
26
|
#inputSurfacePending = false;
|
|
32
27
|
#overlays = [];
|
|
33
|
-
#pointerOwner;
|
|
34
|
-
// Invariant: a right-click editor gesture remains owned by the dock.
|
|
35
|
-
#dockPointerSuppressed = false;
|
|
36
|
-
// Invariant: a gesture begun on an explicit control remains owned by that control.
|
|
37
|
-
#tailPointerSuppressed = false;
|
|
38
|
-
// Invariant: editor selection remains true only while its left button is held.
|
|
39
|
-
#editorPointerSelecting = false;
|
|
40
|
-
// Invariant: no-drag editor presses replay on release; distinct motion promotes frame selection.
|
|
41
|
-
#pendingEditorClick;
|
|
42
28
|
// Invariant: pointer routing uses the most recently composed editor rows.
|
|
43
29
|
#editorPointerFrame;
|
|
44
30
|
// Invariant: one clickable region in the viewport tail, located by the most recent composition.
|
|
45
31
|
#tailControl;
|
|
46
32
|
#selectionAutoScrollTimer;
|
|
47
33
|
#selectionAutoScrollPointer;
|
|
48
|
-
#
|
|
49
|
-
#hoveredHyperlinkKey;
|
|
34
|
+
#gestures;
|
|
50
35
|
#lastRequestedSelectionRevision = -1;
|
|
51
36
|
#presentationRevision = 0;
|
|
52
37
|
#copyOnSelect = true;
|
|
@@ -62,12 +47,32 @@ export class SessionViewportController {
|
|
|
62
47
|
this.#requestHyperlinkCleanup = options.requestHyperlinkCleanup ?? (() => { });
|
|
63
48
|
this.#pasteDiagnostics = options.pasteDiagnostics;
|
|
64
49
|
this.#nextPasteDiagnosticRequest = options.nextPasteDiagnosticRequest ?? (() => --this.#pasteDiagnosticRequest);
|
|
50
|
+
this.#gestures = new ViewportPointerGestures({
|
|
51
|
+
viewport: this.#viewport,
|
|
52
|
+
editor: this.#editor,
|
|
53
|
+
config: () => this.#config,
|
|
54
|
+
copyOnSelect: () => this.#copyOnSelect,
|
|
55
|
+
inputGeometryReady: () => this.inputGeometryReady,
|
|
56
|
+
modalAt: (column, row) => this.#modalAt(column, row),
|
|
57
|
+
editorFrame: () => this.#editorPointerFrame,
|
|
58
|
+
tailControl: () => this.#tailControl,
|
|
59
|
+
clearTailControl: () => { this.#tailControl = undefined; },
|
|
60
|
+
requestRender: () => { this.#requestRender(); },
|
|
61
|
+
requestHyperlinkCleanup: rows => { this.#requestHyperlinkCleanup(rows); },
|
|
62
|
+
updateSelectionAutoScroll: (column, row, viewportHeight, frameHeight) => { this.#updateSelectionAutoScroll(column, row, viewportHeight, frameHeight); },
|
|
63
|
+
stopSelectionAutoScroll: () => { this.#stopSelectionAutoScroll(); },
|
|
64
|
+
pasteFromPointer: () => {
|
|
65
|
+
const request = this.#nextPasteDiagnosticRequest();
|
|
66
|
+
if (this.#editor.pasteClipboard())
|
|
67
|
+
this.#emitPasteRoute(request, "pointer-admitted");
|
|
68
|
+
},
|
|
69
|
+
});
|
|
65
70
|
}
|
|
66
71
|
get config() {
|
|
67
72
|
return this.#config;
|
|
68
73
|
}
|
|
69
74
|
get editorPointerSelecting() {
|
|
70
|
-
return this.#
|
|
75
|
+
return this.#gestures.editorSelecting;
|
|
71
76
|
}
|
|
72
77
|
get transcriptPointerSelecting() {
|
|
73
78
|
return this.#viewport.selectionActive;
|
|
@@ -83,7 +88,7 @@ export class SessionViewportController {
|
|
|
83
88
|
}
|
|
84
89
|
/** Latest reported coordinates; exposed without rendering for frame provenance and evidence. */
|
|
85
90
|
get pointerPosition() {
|
|
86
|
-
return this.#
|
|
91
|
+
return this.#gestures.position;
|
|
87
92
|
}
|
|
88
93
|
setCopyOnSelect(enabled) {
|
|
89
94
|
this.#copyOnSelect = enabled;
|
|
@@ -100,7 +105,7 @@ export class SessionViewportController {
|
|
|
100
105
|
}
|
|
101
106
|
/** Whether the pointer currently rests on the tail control; drives its hover paint. */
|
|
102
107
|
tailControlHovered(target) {
|
|
103
|
-
const pointer = this.#
|
|
108
|
+
const pointer = this.#gestures.position;
|
|
104
109
|
return target !== undefined && pointer !== undefined && withinTailControl(target, pointer.column, pointer.row);
|
|
105
110
|
}
|
|
106
111
|
/** Replacement input changed before its new bounds have been painted. */
|
|
@@ -143,7 +148,7 @@ export class SessionViewportController {
|
|
|
143
148
|
})));
|
|
144
149
|
const frame = this.#viewport.compose({
|
|
145
150
|
...input,
|
|
146
|
-
...(this.#
|
|
151
|
+
...(this.#gestures.position === undefined ? {} : { pointerPosition: this.#gestures.position }),
|
|
147
152
|
...(coveredCells.length === 0 ? {} : { coveredCells }),
|
|
148
153
|
});
|
|
149
154
|
// Concurrency: if selection changed during composition, this frame truthfully carries
|
|
@@ -153,16 +158,7 @@ export class SessionViewportController {
|
|
|
153
158
|
this.#lastRequestedSelectionRevision = this.#viewport.selectionRevision;
|
|
154
159
|
this.#requestRender();
|
|
155
160
|
}
|
|
156
|
-
|
|
157
|
-
const next = this.#hyperlinkKeyAt(frame, this.#pointerPosition.column, this.#pointerPosition.row);
|
|
158
|
-
if (this.#hoveredHyperlinkKey !== undefined && next !== this.#hoveredHyperlinkKey) {
|
|
159
|
-
// Platform: Windows Terminal can leave its solid native-hover underline behind
|
|
160
|
-
// when a following viewport moves the link away from a stationary pointer.
|
|
161
|
-
this.#requestHyperlinkCleanup([this.#pointerPosition.row]);
|
|
162
|
-
this.#requestRender();
|
|
163
|
-
}
|
|
164
|
-
this.#hoveredHyperlinkKey = next;
|
|
165
|
-
}
|
|
161
|
+
this.#gestures.refreshHover(frame);
|
|
166
162
|
return frame;
|
|
167
163
|
}
|
|
168
164
|
composeDockOnly(dockRows, width, height, copyableDockRows = []) {
|
|
@@ -196,32 +192,18 @@ export class SessionViewportController {
|
|
|
196
192
|
this.#presentationRevision += 1;
|
|
197
193
|
this.#clearActivityTimer();
|
|
198
194
|
this.#stopSelectionAutoScroll();
|
|
199
|
-
this.#
|
|
200
|
-
this.#pendingEditorClick = undefined;
|
|
195
|
+
this.#gestures.clear();
|
|
201
196
|
this.#editorPointerFrame = undefined;
|
|
202
|
-
this.#pointerPosition = undefined;
|
|
203
|
-
this.#hoveredHyperlinkKey = undefined;
|
|
204
197
|
this.#viewport.reset();
|
|
205
|
-
this.#pointerOwner = undefined;
|
|
206
|
-
this.#dragGrabOffset = null;
|
|
207
|
-
this.#dockPointerSuppressed = false;
|
|
208
|
-
this.#tailPointerSuppressed = false;
|
|
209
198
|
}
|
|
210
199
|
clearPointerState() {
|
|
211
200
|
this.#presentationRevision += 1;
|
|
212
201
|
this.#clearActivityTimer();
|
|
213
|
-
this.#
|
|
214
|
-
this.#dockPointerSuppressed = false;
|
|
215
|
-
this.#tailPointerSuppressed = false;
|
|
216
|
-
this.#editorPointerSelecting = false;
|
|
217
|
-
this.#pendingEditorClick = undefined;
|
|
202
|
+
this.#gestures.clear();
|
|
218
203
|
this.#editorPointerFrame = undefined;
|
|
219
|
-
this.#pointerPosition = undefined;
|
|
220
|
-
this.#hoveredHyperlinkKey = undefined;
|
|
221
204
|
this.#stopSelectionAutoScroll();
|
|
222
205
|
this.#viewport.clearSelection();
|
|
223
206
|
this.#viewport.clearTransient();
|
|
224
|
-
this.#pointerOwner = undefined;
|
|
225
207
|
}
|
|
226
208
|
#emitPasteRoute(request, phase) {
|
|
227
209
|
try {
|
|
@@ -230,15 +212,15 @@ export class SessionViewportController {
|
|
|
230
212
|
catch { /* Invariant: payload-free diagnostics cannot interfere with input routing. */ }
|
|
231
213
|
}
|
|
232
214
|
#cancelGesture() {
|
|
233
|
-
const held = this.#
|
|
215
|
+
const held = this.#gestures.held;
|
|
234
216
|
const repaint = this.#viewport.hasSelection || held;
|
|
235
|
-
if (!repaint && this.#
|
|
217
|
+
if (!repaint && this.#gestures.idle)
|
|
236
218
|
return;
|
|
237
219
|
const editorFrame = this.#editorPointerFrame;
|
|
238
220
|
this.clearPointerState();
|
|
239
221
|
this.#editorPointerFrame = editorFrame;
|
|
240
222
|
if (held)
|
|
241
|
-
this.#
|
|
223
|
+
this.#gestures.drain();
|
|
242
224
|
if (repaint)
|
|
243
225
|
this.#requestRender();
|
|
244
226
|
}
|
|
@@ -291,16 +273,8 @@ export class SessionViewportController {
|
|
|
291
273
|
if (data === "\u0018" && editorActive && !this.#viewport.hasSelection && !this.#editor.hasSelection()) {
|
|
292
274
|
return { data: "", consumed: true, copyLastMessage: true };
|
|
293
275
|
}
|
|
294
|
-
if (this.#viewport.frame === null)
|
|
295
|
-
|
|
296
|
-
return routeMouseInput(data, event => {
|
|
297
|
-
if (event.kind === "press" && event.button === 0)
|
|
298
|
-
this.#tailPointerSuppressed = true;
|
|
299
|
-
if (event.kind === "release")
|
|
300
|
-
this.#tailPointerSuppressed = false;
|
|
301
|
-
return event.kind === "motion" || event.kind === "release" || (event.kind === "press" && event.button === 0);
|
|
302
|
-
});
|
|
303
|
-
}
|
|
276
|
+
if (this.#viewport.frame === null)
|
|
277
|
+
return this.#gestures.routeUnpainted(data);
|
|
304
278
|
if ((data === "\u0003" || data === "\u0018") && this.#viewport.hasSelection) {
|
|
305
279
|
// Invariant: the newest frame selection wins over an older editor selection.
|
|
306
280
|
const copySelection = this.#viewport.captureSelectedText();
|
|
@@ -325,259 +299,14 @@ export class SessionViewportController {
|
|
|
325
299
|
if (!data.includes("\u001b[<") && data !== "\u0003" && this.#viewport.clearSelection()) {
|
|
326
300
|
this.#requestRender();
|
|
327
301
|
}
|
|
328
|
-
const
|
|
329
|
-
|
|
330
|
-
let forceRepaint = false;
|
|
331
|
-
let activity = false;
|
|
332
|
-
let completedCopy;
|
|
333
|
-
const routed = routeMouseInput(data, (event, report) => {
|
|
334
|
-
const hits = frame.hits;
|
|
335
|
-
const overModal = this.#modalAt(event.column, event.row);
|
|
336
|
-
const wheel = event.kind === "wheel-up" || event.kind === "wheel-down";
|
|
337
|
-
// Invariant: latch each gesture to one surface.
|
|
338
|
-
if (this.#pointerOwner === "drain" || !this.inputGeometryReady) {
|
|
339
|
-
if (event.kind === "release")
|
|
340
|
-
this.#pointerOwner = undefined;
|
|
341
|
-
else if (event.kind === "press")
|
|
342
|
-
this.#pointerOwner = "drain";
|
|
343
|
-
return true;
|
|
344
|
-
}
|
|
345
|
-
const owner = !wheel && this.#pointerOwner !== undefined ? this.#pointerOwner : overModal;
|
|
346
|
-
if (owner !== undefined && owner !== "viewport") {
|
|
347
|
-
if (event.kind === "press")
|
|
348
|
-
this.#pointerOwner = owner;
|
|
349
|
-
if (event.kind === "release")
|
|
350
|
-
this.#pointerOwner = undefined;
|
|
351
|
-
if (event.kind === "press" && this.#viewport.clearSelection())
|
|
352
|
-
repaint = true;
|
|
353
|
-
this.#viewport.setRailHovered(false);
|
|
354
|
-
this.#viewport.setStickyHovered(false);
|
|
355
|
-
this.#pointerPosition = undefined;
|
|
356
|
-
owner.component.handleInput?.(report);
|
|
357
|
-
repaint = true;
|
|
358
|
-
return true;
|
|
359
|
-
}
|
|
360
|
-
if (event.kind === "press")
|
|
361
|
-
this.#pointerOwner = "viewport";
|
|
362
|
-
if (event.kind === "release")
|
|
363
|
-
this.#pointerOwner = undefined;
|
|
364
|
-
const overRail = overModal === undefined && hits.rail !== null
|
|
365
|
-
&& event.column === hits.rail.column
|
|
366
|
-
&& event.row >= hits.rail.rowStart
|
|
367
|
-
&& event.row < hits.rail.rowStart + hits.rail.trackHeight;
|
|
368
|
-
const overSticky = overModal === undefined && hits.sticky !== null && event.row === hits.sticky.row && event.column <= hits.sticky.width;
|
|
369
|
-
const overBottom = overModal === undefined && hits.bottom !== null && event.row === hits.bottom.row
|
|
370
|
-
&& event.column >= hits.bottom.columnStart && event.column <= hits.bottom.columnEnd;
|
|
371
|
-
const tailControl = this.#tailControl;
|
|
372
|
-
const overTailControl = overModal === undefined && tailControl !== undefined
|
|
373
|
-
&& withinTailControl(tailControl, event.column, event.row);
|
|
374
|
-
const previousPointer = this.#pointerPosition;
|
|
375
|
-
const wasOverBottom = hits.bottom !== null && previousPointer !== undefined
|
|
376
|
-
&& previousPointer.row === hits.bottom.row
|
|
377
|
-
&& previousPointer.column >= hits.bottom.columnStart && previousPointer.column <= hits.bottom.columnEnd;
|
|
378
|
-
// Invariant: every report updates the pointer position.
|
|
379
|
-
this.#pointerPosition = { column: event.column, row: event.row };
|
|
380
|
-
repaint ||= wasOverBottom !== overBottom;
|
|
381
|
-
const wasOverTailControl = tailControl !== undefined && previousPointer !== undefined
|
|
382
|
-
&& withinTailControl(tailControl, previousPointer.column, previousPointer.row);
|
|
383
|
-
repaint ||= wasOverTailControl !== overTailControl;
|
|
384
|
-
if (!this.#viewport.selectionActive && !this.#editorPointerSelecting) {
|
|
385
|
-
const nextHyperlink = this.#hyperlinkKeyAt(frame, event.column, event.row);
|
|
386
|
-
if (this.#hoveredHyperlinkKey !== undefined && nextHyperlink !== this.#hoveredHyperlinkKey) {
|
|
387
|
-
// Platform: overwrite Windows Terminal's cached native-hover underline exactly once.
|
|
388
|
-
this.#requestHyperlinkCleanup(previousPointer === undefined ? undefined : [previousPointer.row]);
|
|
389
|
-
repaint = true;
|
|
390
|
-
}
|
|
391
|
-
this.#hoveredHyperlinkKey = nextHyperlink;
|
|
392
|
-
}
|
|
393
|
-
if (event.kind === "motion") {
|
|
394
|
-
this.#viewport.setRailHovered(overRail);
|
|
395
|
-
this.#viewport.setStickyHovered(overSticky);
|
|
396
|
-
repaint = true;
|
|
397
|
-
if (editorActive && this.#editorPointerSelecting && this.#editorPointerFrame !== undefined) {
|
|
398
|
-
this.#editor.handlePointer({
|
|
399
|
-
kind: "motion",
|
|
400
|
-
button: event.button,
|
|
401
|
-
column: event.column,
|
|
402
|
-
row: event.row - this.#editorPointerFrame.rowStart + 1,
|
|
403
|
-
});
|
|
404
|
-
return true;
|
|
405
|
-
}
|
|
406
|
-
if (this.#dockPointerSuppressed || this.#tailPointerSuppressed)
|
|
407
|
-
return true;
|
|
408
|
-
const pendingEditorClick = this.#pendingEditorClick;
|
|
409
|
-
if (pendingEditorClick !== undefined) {
|
|
410
|
-
if (event.column === pendingEditorClick.column && event.row === pendingEditorClick.row)
|
|
411
|
-
return true;
|
|
412
|
-
this.#pendingEditorClick = undefined;
|
|
413
|
-
const editorFrame = editorActive ? this.#editorPointerFrame : undefined;
|
|
414
|
-
if (editorFrame !== undefined && this.#editor.handlePointer({ kind: "press", button: 0, column: pendingEditorClick.column, row: pendingEditorClick.row - editorFrame.rowStart + 1 })) {
|
|
415
|
-
this.#editorPointerSelecting = true;
|
|
416
|
-
this.#editor.handlePointer({ kind: "motion", button: event.button, column: event.column, row: event.row - editorFrame.rowStart + 1 });
|
|
417
|
-
return true;
|
|
418
|
-
}
|
|
419
|
-
this.#viewport.pressSelection(pendingEditorClick.column, pendingEditorClick.row, now, { continueMultiClick: false });
|
|
420
|
-
this.#viewport.extendSelection(event.column, event.row, now, false);
|
|
421
|
-
this.#updateSelectionAutoScroll(event.column, event.row, hits.viewportHeight, frame.rows.length);
|
|
422
|
-
activity = true;
|
|
423
|
-
return true;
|
|
424
|
-
}
|
|
425
|
-
if (this.#viewport.selectionActive) {
|
|
426
|
-
this.#viewport.extendSelection(event.column, event.row, now, false);
|
|
427
|
-
this.#updateSelectionAutoScroll(event.column, event.row, hits.viewportHeight, frame.rows.length);
|
|
428
|
-
activity = true;
|
|
429
|
-
return true;
|
|
430
|
-
}
|
|
431
|
-
if (this.#dragGrabOffset !== null && hits.rail !== null) {
|
|
432
|
-
const target = scrollForThumbRow(hits.rail.geometry, event.row - hits.rail.rowStart - this.#dragGrabOffset);
|
|
433
|
-
this.#viewport.scrollTo(target, now);
|
|
434
|
-
activity = true;
|
|
435
|
-
return true;
|
|
436
|
-
}
|
|
437
|
-
return overRail || overSticky || overBottom || overTailControl;
|
|
438
|
-
}
|
|
439
|
-
if (event.kind === "wheel-up" || event.kind === "wheel-down") {
|
|
440
|
-
if (!allowWheel || event.row < 1 || event.row > hits.viewportHeight)
|
|
441
|
-
return false;
|
|
442
|
-
const distance = scrollbarWheelRows(this.#config.scrollbarSpeed);
|
|
443
|
-
this.#viewport.scrollBy(event.kind === "wheel-up" ? -distance : distance, now);
|
|
444
|
-
activity = true;
|
|
445
|
-
repaint = true;
|
|
446
|
-
forceRepaint = true;
|
|
447
|
-
return true;
|
|
448
|
-
}
|
|
449
|
-
if (event.kind === "press") {
|
|
450
|
-
const editorFrame = editorActive ? this.#editorPointerFrame : undefined;
|
|
451
|
-
if (event.button === 2 && editorFrame !== undefined
|
|
452
|
-
&& event.row >= editorFrame.rowStart && event.row <= editorFrame.rowEnd) {
|
|
453
|
-
this.#stopSelectionAutoScroll();
|
|
454
|
-
if (this.#viewport.clearSelection())
|
|
455
|
-
repaint = true;
|
|
456
|
-
const request = this.#nextPasteDiagnosticRequest();
|
|
457
|
-
if (this.#editor.pasteClipboard())
|
|
458
|
-
this.#emitPasteRoute(request, "pointer-admitted");
|
|
459
|
-
this.#dockPointerSuppressed = true;
|
|
460
|
-
repaint = true;
|
|
461
|
-
return true;
|
|
462
|
-
}
|
|
463
|
-
if (event.button !== 0)
|
|
464
|
-
return false;
|
|
465
|
-
this.#dockPointerSuppressed = false;
|
|
466
|
-
this.#tailPointerSuppressed = false;
|
|
467
|
-
this.#pendingEditorClick = undefined;
|
|
468
|
-
this.#stopSelectionAutoScroll();
|
|
469
|
-
if (this.#viewport.clearSelection())
|
|
470
|
-
repaint = true;
|
|
471
|
-
if (overTailControl) {
|
|
472
|
-
this.#tailControl = undefined;
|
|
473
|
-
tailControl.activate();
|
|
474
|
-
this.#tailPointerSuppressed = true;
|
|
475
|
-
repaint = true;
|
|
476
|
-
return true;
|
|
477
|
-
}
|
|
478
|
-
if (overBottom) {
|
|
479
|
-
this.#viewport.scrollToEnd(now);
|
|
480
|
-
this.#tailPointerSuppressed = true;
|
|
481
|
-
activity = true;
|
|
482
|
-
repaint = true;
|
|
483
|
-
return true;
|
|
484
|
-
}
|
|
485
|
-
if (overSticky && hits.sticky !== null) {
|
|
486
|
-
this.#viewport.scrollTo(hits.sticky.target, now);
|
|
487
|
-
this.#tailPointerSuppressed = true;
|
|
488
|
-
activity = true;
|
|
489
|
-
repaint = true;
|
|
490
|
-
return true;
|
|
491
|
-
}
|
|
492
|
-
if (overRail && hits.rail !== null) {
|
|
493
|
-
const trackRow = event.row - hits.rail.rowStart;
|
|
494
|
-
const geometry = hits.rail.geometry;
|
|
495
|
-
if (trackRow >= geometry.thumbTop && trackRow < geometry.thumbTop + geometry.thumbHeight) {
|
|
496
|
-
this.#dragGrabOffset = trackRow - geometry.thumbTop;
|
|
497
|
-
this.#viewport.setRailDragging(true);
|
|
498
|
-
}
|
|
499
|
-
else {
|
|
500
|
-
this.#viewport.scrollTo(scrollForTrackPage(geometry, trackRow, frame.scrollTop, hits.viewportHeight), now);
|
|
501
|
-
this.#tailPointerSuppressed = true;
|
|
502
|
-
}
|
|
503
|
-
activity = true;
|
|
504
|
-
repaint = true;
|
|
505
|
-
return true;
|
|
506
|
-
}
|
|
507
|
-
if (event.row >= 1 && event.row <= frame.rows.length && event.column <= frame.descriptor.width) {
|
|
508
|
-
if (editorFrame !== undefined && event.row >= editorFrame.rowStart && event.row <= editorFrame.rowEnd) {
|
|
509
|
-
// Invariant: no-drag clicks remain editor-owned; first motion latches an editor drag.
|
|
510
|
-
this.#pendingEditorClick = { column: event.column, row: event.row };
|
|
511
|
-
}
|
|
512
|
-
else {
|
|
513
|
-
this.#viewport.pressSelection(event.column, event.row, now);
|
|
514
|
-
}
|
|
515
|
-
repaint = true;
|
|
516
|
-
return true;
|
|
517
|
-
}
|
|
518
|
-
this.#tailPointerSuppressed = true;
|
|
519
|
-
return true;
|
|
520
|
-
}
|
|
521
|
-
if (event.kind === "release") {
|
|
522
|
-
if (editorActive && this.#editorPointerSelecting && this.#editorPointerFrame !== undefined) {
|
|
523
|
-
const wasEditorSelecting = this.#editorPointerSelecting;
|
|
524
|
-
this.#editor.handlePointer({
|
|
525
|
-
kind: "release",
|
|
526
|
-
button: event.button,
|
|
527
|
-
column: event.column,
|
|
528
|
-
row: event.row - this.#editorPointerFrame.rowStart + 1,
|
|
529
|
-
});
|
|
530
|
-
this.#editorPointerSelecting = false;
|
|
531
|
-
forceRepaint ||= wasEditorSelecting;
|
|
532
|
-
repaint = true;
|
|
533
|
-
return true;
|
|
534
|
-
}
|
|
535
|
-
const pendingEditorClick = this.#pendingEditorClick;
|
|
536
|
-
if (pendingEditorClick !== undefined) {
|
|
537
|
-
this.#pendingEditorClick = undefined;
|
|
538
|
-
if (this.#editorPointerFrame !== undefined) {
|
|
539
|
-
const editorRow = pendingEditorClick.row - this.#editorPointerFrame.rowStart + 1;
|
|
540
|
-
this.#editor.handlePointer({ kind: "press", button: 0, column: pendingEditorClick.column, row: editorRow });
|
|
541
|
-
this.#editor.handlePointer({ kind: "release", button: 0, column: pendingEditorClick.column, row: editorRow });
|
|
542
|
-
}
|
|
543
|
-
forceRepaint = true;
|
|
544
|
-
repaint = true;
|
|
545
|
-
return true;
|
|
546
|
-
}
|
|
547
|
-
if (this.#viewport.releaseSelection()) {
|
|
548
|
-
this.#stopSelectionAutoScroll();
|
|
549
|
-
if (this.#copyOnSelect)
|
|
550
|
-
completedCopy = this.#viewport.captureSelectedText() ?? undefined;
|
|
551
|
-
// Platform: restore OSC 8 links only after the held-button selection paint has
|
|
552
|
-
// ended, then overwrite any terminal-cached hover cells immediately.
|
|
553
|
-
forceRepaint = true;
|
|
554
|
-
repaint = true;
|
|
555
|
-
return true;
|
|
556
|
-
}
|
|
557
|
-
if (this.#dragGrabOffset !== null) {
|
|
558
|
-
this.#dragGrabOffset = null;
|
|
559
|
-
this.#viewport.setRailDragging(false);
|
|
560
|
-
repaint = true;
|
|
561
|
-
return true;
|
|
562
|
-
}
|
|
563
|
-
if (this.#dockPointerSuppressed) {
|
|
564
|
-
this.#dockPointerSuppressed = false;
|
|
565
|
-
return true;
|
|
566
|
-
}
|
|
567
|
-
if (this.#tailPointerSuppressed) {
|
|
568
|
-
this.#tailPointerSuppressed = false;
|
|
569
|
-
return true;
|
|
570
|
-
}
|
|
571
|
-
}
|
|
572
|
-
return false;
|
|
573
|
-
});
|
|
574
|
-
if (activity)
|
|
302
|
+
const { routed, outcome } = this.#gestures.route(data, this.#viewport.frame, { allowWheel, now, editorActive });
|
|
303
|
+
if (outcome.activity)
|
|
575
304
|
this.#scheduleActivityExpiry();
|
|
576
|
-
if (repaint) {
|
|
305
|
+
if (outcome.repaint) {
|
|
577
306
|
this.#lastRequestedSelectionRevision = this.#viewport.selectionRevision;
|
|
578
|
-
this.#requestRender(forceRepaint);
|
|
307
|
+
this.#requestRender(outcome.forceRepaint);
|
|
579
308
|
}
|
|
580
|
-
return completedCopy === undefined ? routed : { ...routed, copySelection: completedCopy };
|
|
309
|
+
return outcome.completedCopy === undefined ? routed : { ...routed, copySelection: outcome.completedCopy };
|
|
581
310
|
}
|
|
582
311
|
#modalAt(column, row) {
|
|
583
312
|
const contains = (surface) => column >= surface.columnStart && column <= surface.columnEnd
|
|
@@ -585,13 +314,6 @@ export class SessionViewportController {
|
|
|
585
314
|
const overlay = this.#overlays?.findLast(contains);
|
|
586
315
|
return overlay ?? (this.#inputSurface !== undefined && contains(this.#inputSurface) ? this.#inputSurface : undefined);
|
|
587
316
|
}
|
|
588
|
-
#hyperlinkKeyAt(frame, column, row) {
|
|
589
|
-
if (row < 1 || row > frame.rows.length || column < 1)
|
|
590
|
-
return undefined;
|
|
591
|
-
const range = readVisibleHyperlinks(frame.rows[row - 1] ?? "").ranges
|
|
592
|
-
.find(candidate => column - 1 >= candidate.from && column - 1 < candidate.to);
|
|
593
|
-
return range === undefined ? undefined : JSON.stringify([row, range]);
|
|
594
|
-
}
|
|
595
317
|
#updateSelectionAutoScroll(column, row, viewportHeight, frameHeight) {
|
|
596
318
|
// Invariant: the last content row stays selectable; only the pointer below it scrolls,
|
|
597
319
|
// unless no row exists below. The top row scrolls because nothing lies above it. A
|
|
@@ -4,7 +4,7 @@ import type { OwnedUiSessionShellRoot } from "./session-shell-root.js";
|
|
|
4
4
|
/** What the session's live setting effects reach: terminal modes, root presentation, and the presenter's progress flag. */
|
|
5
5
|
interface SessionSettingsTargets {
|
|
6
6
|
readonly terminal: Pick<OwnedUiPresenterTerminal, "setHardwareCursor" | "setClearOnShrink" | "setWheelScrollLines">;
|
|
7
|
-
readonly root: Pick<OwnedUiSessionShellRoot, "setEditorPaddingX" | "setAutocompleteMaxVisible" | "setOutputPad" | "setHideThinkingBlock" | "setMermaidRenderingMode" | "setImagePresentation" | "
|
|
7
|
+
readonly root: Pick<OwnedUiSessionShellRoot, "setEditorPaddingX" | "setAutocompleteMaxVisible" | "setOutputPad" | "setHideThinkingBlock" | "setMermaidRenderingMode" | "setImagePresentation" | "viewport">;
|
|
8
8
|
setTerminalProgress(enabled: boolean): void;
|
|
9
9
|
}
|
|
10
10
|
/**
|
|
@@ -49,13 +49,13 @@ function settingBindings(targets, snapshot, customViewport, bare) {
|
|
|
49
49
|
{ owner: null, key: "imageWidthCells", live: () => { }, seed: presentImages },
|
|
50
50
|
// Invariant: the custom viewport owns copy-on-select; the pinned comparison profile keeps Pi's wheel distance.
|
|
51
51
|
customViewport
|
|
52
|
-
? setting("shell", "fullscreenCopyOnSelect", "Fullscreen copy-on-select setting is invalid", isBoolean, value => root.
|
|
52
|
+
? setting("shell", "fullscreenCopyOnSelect", "Fullscreen copy-on-select setting is invalid", isBoolean, value => root.viewport.setCopyOnSelect(value))
|
|
53
53
|
: setting("shell", "fullscreenWheelScrollLines", "Fullscreen wheel-scroll distance is invalid", isWheelDistance, value => terminal.setWheelScrollLines(value), false),
|
|
54
54
|
...(customViewport ? [] : [{
|
|
55
55
|
owner: null,
|
|
56
56
|
key: "fullscreenCopyOnSelect",
|
|
57
57
|
live: () => { },
|
|
58
|
-
seed: (initial) => root.
|
|
58
|
+
seed: (initial) => root.viewport.setCopyOnSelect(initial.fullscreenCopyOnSelect),
|
|
59
59
|
}]),
|
|
60
60
|
];
|
|
61
61
|
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import type { OwnedUiShellEditorPort, OwnedUiViewportSettings } from "../../contracts/owned-ui/index.js";
|
|
2
|
+
import type { TerminalPointerSurface } from "../../contracts/presentation/index.js";
|
|
3
|
+
import { type RoutedMouseInput } from "../../ui/components/mouse.js";
|
|
4
|
+
import type { SelectionCopySnapshot } from "../../ui/components/selection-copy.js";
|
|
5
|
+
import type { TranscriptViewport, TranscriptViewportFrame } from "../../ui/components/transcript-viewport.js";
|
|
6
|
+
/** One-based, inclusive terminal cells of a clickable viewport-tail control. */
|
|
7
|
+
export interface TailControlRegion {
|
|
8
|
+
readonly rowStart: number;
|
|
9
|
+
readonly rowEnd: number;
|
|
10
|
+
readonly columnStart: number;
|
|
11
|
+
readonly columnEnd: number;
|
|
12
|
+
}
|
|
13
|
+
export type TailControl = TailControlRegion & {
|
|
14
|
+
readonly activate: () => void;
|
|
15
|
+
};
|
|
16
|
+
export declare function withinTailControl(region: TailControlRegion, column: number, row: number): boolean;
|
|
17
|
+
export interface ViewportPointerPorts {
|
|
18
|
+
readonly viewport: TranscriptViewport;
|
|
19
|
+
readonly editor: OwnedUiShellEditorPort;
|
|
20
|
+
config(): OwnedUiViewportSettings;
|
|
21
|
+
copyOnSelect(): boolean;
|
|
22
|
+
/** False while replacement input or overlay bounds have not been painted yet. */
|
|
23
|
+
inputGeometryReady(): boolean;
|
|
24
|
+
/** The topmost overlay or input surface under a cell. */
|
|
25
|
+
modalAt(column: number, row: number): TerminalPointerSurface | undefined;
|
|
26
|
+
/** The editor rows of the most recent composition. */
|
|
27
|
+
editorFrame(): {
|
|
28
|
+
readonly rowStart: number;
|
|
29
|
+
readonly rowEnd: number;
|
|
30
|
+
} | undefined;
|
|
31
|
+
tailControl(): TailControl | undefined;
|
|
32
|
+
clearTailControl(): void;
|
|
33
|
+
requestRender(): void;
|
|
34
|
+
requestHyperlinkCleanup(rows?: readonly number[]): void;
|
|
35
|
+
updateSelectionAutoScroll(column: number, row: number, viewportHeight: number, frameHeight: number): void;
|
|
36
|
+
stopSelectionAutoScroll(): void;
|
|
37
|
+
/** A right-click on the editor pastes the clipboard. */
|
|
38
|
+
pasteFromPointer(): void;
|
|
39
|
+
}
|
|
40
|
+
/** How one input chunk's mouse reports changed the viewport. */
|
|
41
|
+
export interface ViewportPointerOutcome {
|
|
42
|
+
repaint: boolean;
|
|
43
|
+
forceRepaint: boolean;
|
|
44
|
+
activity: boolean;
|
|
45
|
+
completedCopy: SelectionCopySnapshot | undefined;
|
|
46
|
+
}
|
|
47
|
+
interface PointerCall {
|
|
48
|
+
readonly allowWheel: boolean;
|
|
49
|
+
readonly now: number;
|
|
50
|
+
readonly editorActive: boolean;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* The pointer gestures of the session viewport: which surface a gesture is latched to, the
|
|
54
|
+
* suppression of a gesture begun on the dock or a control, the editor click that waits for drag
|
|
55
|
+
* or release, the rail drag offset, the pointer position and the hovered link. Each report is
|
|
56
|
+
* routed in the same order of checks, and its effect is reported as an outcome.
|
|
57
|
+
*/
|
|
58
|
+
export declare class ViewportPointerGestures {
|
|
59
|
+
#private;
|
|
60
|
+
constructor(ports: ViewportPointerPorts);
|
|
61
|
+
get position(): {
|
|
62
|
+
readonly column: number;
|
|
63
|
+
readonly row: number;
|
|
64
|
+
} | undefined;
|
|
65
|
+
get editorSelecting(): boolean;
|
|
66
|
+
/** A gesture is latched to a surface or a selection is being dragged. */
|
|
67
|
+
get held(): boolean;
|
|
68
|
+
/** No pointer position or hovered link is remembered. */
|
|
69
|
+
get idle(): boolean;
|
|
70
|
+
/** Forget every latch. */
|
|
71
|
+
clear(): void;
|
|
72
|
+
/** Swallow the rest of a held gesture until its release. */
|
|
73
|
+
drain(): void;
|
|
74
|
+
/** Before the first paint, a left press and its motion and release belong to no surface. */
|
|
75
|
+
routeUnpainted(data: string): RoutedMouseInput;
|
|
76
|
+
route(data: string, frame: TranscriptViewportFrame, call: PointerCall): {
|
|
77
|
+
readonly routed: RoutedMouseInput;
|
|
78
|
+
readonly outcome: ViewportPointerOutcome;
|
|
79
|
+
};
|
|
80
|
+
/** A newly composed frame may move a link away from a stationary pointer. */
|
|
81
|
+
refreshHover(frame: TranscriptViewportFrame): void;
|
|
82
|
+
}
|
|
83
|
+
export {};
|