@teammates/consolonia 0.6.1 → 0.6.3
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.d.ts +6 -0
- package/dist/app.js +11 -0
- package/dist/widgets/chat-view.d.ts +5 -3
- package/dist/widgets/chat-view.js +37 -22
- package/package.json +1 -1
package/dist/app.d.ts
CHANGED
|
@@ -44,6 +44,12 @@ export declare class App {
|
|
|
44
44
|
stop(): void;
|
|
45
45
|
/** Force a full re-render. */
|
|
46
46
|
refresh(): void;
|
|
47
|
+
/**
|
|
48
|
+
* Schedule a coalesced render pass. Multiple calls within the same tick
|
|
49
|
+
* collapse into a single render, avoiding redundant full-screen redraws
|
|
50
|
+
* when many rapid updates occur (e.g. progress spinner + concurrent task output).
|
|
51
|
+
*/
|
|
52
|
+
scheduleRefresh(): void;
|
|
47
53
|
private _setup;
|
|
48
54
|
private _prepareTerminal;
|
|
49
55
|
private _restoreTerminal;
|
package/dist/app.js
CHANGED
|
@@ -74,6 +74,17 @@ export class App {
|
|
|
74
74
|
return;
|
|
75
75
|
this._fullRender();
|
|
76
76
|
}
|
|
77
|
+
/**
|
|
78
|
+
* Schedule a coalesced render pass. Multiple calls within the same tick
|
|
79
|
+
* collapse into a single render, avoiding redundant full-screen redraws
|
|
80
|
+
* when many rapid updates occur (e.g. progress spinner + concurrent task output).
|
|
81
|
+
*/
|
|
82
|
+
scheduleRefresh() {
|
|
83
|
+
if (!this._running)
|
|
84
|
+
return;
|
|
85
|
+
this.root.invalidate();
|
|
86
|
+
this._scheduleRender();
|
|
87
|
+
}
|
|
77
88
|
// ── Setup ────────────────────────────────────────────────────────
|
|
78
89
|
_setup() {
|
|
79
90
|
const stdout = process.stdout;
|
|
@@ -33,7 +33,7 @@ import type { DrawingContext, TextStyle } from "../drawing/context.js";
|
|
|
33
33
|
import type { InputEvent } from "../input/events.js";
|
|
34
34
|
import { Control } from "../layout/control.js";
|
|
35
35
|
import type { Constraint, Rect, Size } from "../layout/types.js";
|
|
36
|
-
import {
|
|
36
|
+
import type { StyledSpan } from "../styled.js";
|
|
37
37
|
import { type StyledLine } from "./styled-text.js";
|
|
38
38
|
import { type DeleteSizer, type InputColorizer, TextInput } from "./text-input.js";
|
|
39
39
|
export interface DropdownItem {
|
|
@@ -133,6 +133,10 @@ export declare class ChatView extends Control {
|
|
|
133
133
|
private _feedScrollOffset;
|
|
134
134
|
private _feedX;
|
|
135
135
|
private _contentWidth;
|
|
136
|
+
/** Cached measured height per feed line index. Invalidated on width change. */
|
|
137
|
+
private _feedHeightCache;
|
|
138
|
+
/** The content width used for the last height cache pass. */
|
|
139
|
+
private _feedHeightCacheWidth;
|
|
136
140
|
/** Cached from last render for hit-testing. */
|
|
137
141
|
private _scrollbarX;
|
|
138
142
|
private _feedY;
|
|
@@ -236,8 +240,6 @@ export declare class ChatView extends Control {
|
|
|
236
240
|
handleInput(event: InputEvent): boolean;
|
|
237
241
|
/** Extract the plain text content of a feed line. */
|
|
238
242
|
private _extractFeedLineText;
|
|
239
|
-
/** Find the URL at the given character offset, if any. */
|
|
240
|
-
private _findUrlAtOffset;
|
|
241
243
|
/** Resolve which action item the mouse x-position falls on. */
|
|
242
244
|
private _resolveActionItem;
|
|
243
245
|
/** Build a hover line: highlight only the target item, keep others normal. */
|
|
@@ -73,6 +73,11 @@ export class ChatView extends Control {
|
|
|
73
73
|
// ── Feed geometry (cached from last render for hit-testing) ──
|
|
74
74
|
_feedX = 0;
|
|
75
75
|
_contentWidth = 0;
|
|
76
|
+
// ── Feed line height cache ───────────────────────────────────
|
|
77
|
+
/** Cached measured height per feed line index. Invalidated on width change. */
|
|
78
|
+
_feedHeightCache = [];
|
|
79
|
+
/** The content width used for the last height cache pass. */
|
|
80
|
+
_feedHeightCacheWidth = -1;
|
|
76
81
|
// ── Scrollbar state ───────────────────────────────────────────
|
|
77
82
|
/** Cached from last render for hit-testing. */
|
|
78
83
|
_scrollbarX = -1;
|
|
@@ -321,6 +326,7 @@ export class ChatView extends Control {
|
|
|
321
326
|
/** Clear everything between the banner and the input box. */
|
|
322
327
|
clear() {
|
|
323
328
|
this._feedLines = [];
|
|
329
|
+
this._feedHeightCache = [];
|
|
324
330
|
this._feedActions.clear();
|
|
325
331
|
this._hoveredAction = -1;
|
|
326
332
|
this._feedScrollOffset = 0;
|
|
@@ -335,6 +341,8 @@ export class ChatView extends Control {
|
|
|
335
341
|
if (index < 0 || index >= this._feedLines.length)
|
|
336
342
|
return;
|
|
337
343
|
this._feedLines[index].lines = [content];
|
|
344
|
+
// Invalidate cached height — content changed, may wrap differently
|
|
345
|
+
delete this._feedHeightCache[index];
|
|
338
346
|
this._feedActions.delete(index);
|
|
339
347
|
if (this._hoveredAction === index)
|
|
340
348
|
this._hoveredAction = -1;
|
|
@@ -600,8 +608,16 @@ export class ChatView extends Control {
|
|
|
600
608
|
const urls = [...text.matchAll(URL_REGEX)];
|
|
601
609
|
const paths = [...text.matchAll(FILE_PATH_REGEX)];
|
|
602
610
|
const allTargets = [
|
|
603
|
-
...urls.map((m) => ({
|
|
604
|
-
|
|
611
|
+
...urls.map((m) => ({
|
|
612
|
+
index: m.index,
|
|
613
|
+
text: m[0],
|
|
614
|
+
type: "link",
|
|
615
|
+
})),
|
|
616
|
+
...paths.map((m) => ({
|
|
617
|
+
index: m.index,
|
|
618
|
+
text: m[0],
|
|
619
|
+
type: "file",
|
|
620
|
+
})),
|
|
605
621
|
].sort((a, b) => a.index - b.index);
|
|
606
622
|
if (allTargets.length === 1) {
|
|
607
623
|
this.emit(allTargets[0].type, allTargets[0].text);
|
|
@@ -678,12 +694,14 @@ export class ChatView extends Control {
|
|
|
678
694
|
const prev = this._feedActions.get(this._hoveredAction);
|
|
679
695
|
if (prev) {
|
|
680
696
|
this._feedLines[this._hoveredAction].lines = [prev.normalStyle];
|
|
697
|
+
delete this._feedHeightCache[this._hoveredAction];
|
|
681
698
|
}
|
|
682
699
|
}
|
|
683
700
|
if (entry && newHover >= 0) {
|
|
684
701
|
const hitItem = this._resolveActionItem(entry, me.x);
|
|
685
702
|
const hoverLine = this._buildHoverLine(entry, hitItem);
|
|
686
703
|
this._feedLines[newHover].lines = [hoverLine];
|
|
704
|
+
delete this._feedHeightCache[newHover];
|
|
687
705
|
}
|
|
688
706
|
this._hoveredAction = newHover;
|
|
689
707
|
this.invalidate();
|
|
@@ -716,18 +734,6 @@ export class ChatView extends Control {
|
|
|
716
734
|
})
|
|
717
735
|
.join("\n");
|
|
718
736
|
}
|
|
719
|
-
/** Find the URL at the given character offset, if any. */
|
|
720
|
-
_findUrlAtOffset(text, charOffset) {
|
|
721
|
-
URL_REGEX.lastIndex = 0;
|
|
722
|
-
let match;
|
|
723
|
-
while ((match = URL_REGEX.exec(text)) !== null) {
|
|
724
|
-
if (charOffset >= match.index &&
|
|
725
|
-
charOffset < match.index + match[0].length) {
|
|
726
|
-
return match[0];
|
|
727
|
-
}
|
|
728
|
-
}
|
|
729
|
-
return null;
|
|
730
|
-
}
|
|
731
737
|
/** Resolve which action item the mouse x-position falls on. */
|
|
732
738
|
_resolveActionItem(entry, x) {
|
|
733
739
|
if (entry.items.length === 1)
|
|
@@ -968,16 +974,25 @@ export class ChatView extends Control {
|
|
|
968
974
|
},
|
|
969
975
|
});
|
|
970
976
|
}
|
|
971
|
-
// Feed lines
|
|
977
|
+
// Feed lines — use cached heights to avoid re-measuring every line each frame.
|
|
978
|
+
// Cache is invalidated when content width changes (e.g. terminal resize).
|
|
979
|
+
if (contentWidth !== this._feedHeightCacheWidth) {
|
|
980
|
+
this._feedHeightCache = [];
|
|
981
|
+
this._feedHeightCacheWidth = contentWidth;
|
|
982
|
+
}
|
|
972
983
|
for (let fi = 0; fi < this._feedLines.length; fi++) {
|
|
973
984
|
const line = this._feedLines[fi];
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
985
|
+
let h = this._feedHeightCache[fi];
|
|
986
|
+
if (h === undefined) {
|
|
987
|
+
const lineSize = line.measure({
|
|
988
|
+
minWidth: 0,
|
|
989
|
+
maxWidth: contentWidth,
|
|
990
|
+
minHeight: 0,
|
|
991
|
+
maxHeight: Infinity,
|
|
992
|
+
});
|
|
993
|
+
h = Math.max(1, lineSize.height);
|
|
994
|
+
this._feedHeightCache[fi] = h;
|
|
995
|
+
}
|
|
981
996
|
items.push({
|
|
982
997
|
height: h,
|
|
983
998
|
feedLineIdx: fi,
|
package/package.json
CHANGED