effective-progress 0.7.0 → 0.8.1
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/README.md +8 -7
- package/dist/index.mjs +649 -737
- package/package.json +2 -1
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { Brand, Cause, Clock, Context, Effect, Exit, FiberRef, Layer, Option, Schema } from "effect";
|
|
1
|
+
import { Brand, Cause, Clock, Context, Data, Effect, Exit, FiberRef, Hash, Layer, Option, Schema } from "effect";
|
|
2
2
|
import { dual } from "effect/Function";
|
|
3
3
|
import { Box, Text, render } from "ink";
|
|
4
|
-
import { useEffect, useState, useSyncExternalStore } from "react";
|
|
4
|
+
import { useEffect, useRef, useState, useSyncExternalStore } from "react";
|
|
5
5
|
import stringWidth from "fast-string-width";
|
|
6
6
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
7
7
|
|
|
@@ -113,14 +113,13 @@ const toRenderSnapshot = (store) => {
|
|
|
113
113
|
//#endregion
|
|
114
114
|
//#region src/ink-renderer/store.ts
|
|
115
115
|
const hasExplicitTotal = (options) => Object.prototype.hasOwnProperty.call(options, "total");
|
|
116
|
-
const DEFAULT_TOTAL = 100;
|
|
117
116
|
const sanitizeTotalOnAdd = (total) => {
|
|
118
117
|
if (total === void 0) return;
|
|
119
|
-
return total < 0 ?
|
|
118
|
+
return total < 0 ? void 0 : total;
|
|
120
119
|
};
|
|
121
|
-
const sanitizeTotalOnUpdate = (
|
|
120
|
+
const sanitizeTotalOnUpdate = (nextTotal) => {
|
|
122
121
|
if (nextTotal === void 0) return;
|
|
123
|
-
return nextTotal < 0 ?
|
|
122
|
+
return nextTotal < 0 ? void 0 : nextTotal;
|
|
124
123
|
};
|
|
125
124
|
const normalizeUnits = (counts) => {
|
|
126
125
|
const succeeded = Math.max(0, counts.succeeded);
|
|
@@ -141,7 +140,7 @@ const updatedSnapshot = (snapshot, options) => {
|
|
|
141
140
|
const units = options.succeeded === void 0 && options.failed === void 0 && options.total === void 0 && !hasExplicitTotal(options) ? currentUnits : normalizeUnits({
|
|
142
141
|
succeeded: options.succeeded ?? currentUnits.succeeded,
|
|
143
142
|
failed: options.failed ?? currentUnits.failed,
|
|
144
|
-
total: hasExplicitTotal(options) ? sanitizeTotalOnUpdate(
|
|
143
|
+
total: hasExplicitTotal(options) ? sanitizeTotalOnUpdate(options.total) : currentUnits.total
|
|
145
144
|
});
|
|
146
145
|
return new TaskSnapshot({
|
|
147
146
|
id: snapshot.id,
|
|
@@ -448,6 +447,33 @@ const makeProgressRenderStore = () => {
|
|
|
448
447
|
};
|
|
449
448
|
};
|
|
450
449
|
|
|
450
|
+
//#endregion
|
|
451
|
+
//#region src/ink-renderer/columns/frame.ts
|
|
452
|
+
const createRenderFrame = (rows, now, tick, stickyWidths) => {
|
|
453
|
+
const tasks = /* @__PURE__ */ new Map();
|
|
454
|
+
const trees = /* @__PURE__ */ new Map();
|
|
455
|
+
for (const row of rows) {
|
|
456
|
+
tasks.set(row.task.id, row.task);
|
|
457
|
+
trees.set(row.task.id, row.tree);
|
|
458
|
+
}
|
|
459
|
+
return {
|
|
460
|
+
taskIds: rows.map((row) => row.task.id),
|
|
461
|
+
now,
|
|
462
|
+
tick,
|
|
463
|
+
stickyWidths,
|
|
464
|
+
getTask: (taskId) => {
|
|
465
|
+
const task = tasks.get(taskId);
|
|
466
|
+
if (task === void 0) throw new Error(`Unknown task id: ${taskId}`);
|
|
467
|
+
return task;
|
|
468
|
+
},
|
|
469
|
+
getTree: (taskId) => {
|
|
470
|
+
const tree = trees.get(taskId);
|
|
471
|
+
if (tree === void 0) throw new Error(`Unknown task tree: ${taskId}`);
|
|
472
|
+
return tree;
|
|
473
|
+
}
|
|
474
|
+
};
|
|
475
|
+
};
|
|
476
|
+
|
|
451
477
|
//#endregion
|
|
452
478
|
//#region src/ink-renderer/format.ts
|
|
453
479
|
const SPINNER_FRAMES = [
|
|
@@ -530,6 +556,16 @@ const formatDeterminateAmountParts = (task) => {
|
|
|
530
556
|
total: totalText
|
|
531
557
|
};
|
|
532
558
|
};
|
|
559
|
+
const getDeterminateProcessedColor = (task) => {
|
|
560
|
+
if (!isDeterminate$1(task)) return "whiteBright";
|
|
561
|
+
const { succeeded, failed, processed, total } = task.units;
|
|
562
|
+
if (task.status === "failed" && processed < total) return "red";
|
|
563
|
+
if (processed >= total && failed === 0) return "green";
|
|
564
|
+
if (processed >= total && failed > 0 && succeeded === 0) return "red";
|
|
565
|
+
if (succeeded > 0 && failed > 0) return "yellow";
|
|
566
|
+
if (failed > 0 && succeeded === 0) return "red";
|
|
567
|
+
return "whiteBright";
|
|
568
|
+
};
|
|
533
569
|
const formatAmount = (task, _tick) => {
|
|
534
570
|
if (isDeterminate$1(task)) {
|
|
535
571
|
const parts = formatDeterminateAmountParts(task);
|
|
@@ -546,12 +582,49 @@ const formatAmount = (task, _tick) => {
|
|
|
546
582
|
};
|
|
547
583
|
|
|
548
584
|
//#endregion
|
|
549
|
-
//#region src/ink-renderer/columns/
|
|
550
|
-
const
|
|
551
|
-
|
|
585
|
+
//#region src/ink-renderer/columns/node.ts
|
|
586
|
+
const createColumnDefinition = (config, create) => {
|
|
587
|
+
return {
|
|
588
|
+
id: Hash.hash(Data.struct(config)).toString(36),
|
|
589
|
+
build: (frame) => create(frame, config)
|
|
590
|
+
};
|
|
591
|
+
};
|
|
552
592
|
|
|
553
593
|
//#endregion
|
|
554
|
-
//#region src/ink-renderer/columns/
|
|
594
|
+
//#region src/ink-renderer/columns/sticky-width.ts
|
|
595
|
+
const applyStickyWidth = ({ key, measure, stickyWidths }) => {
|
|
596
|
+
const preferred = Math.max(measure.preferred, stickyWidths.get(key) ?? 0);
|
|
597
|
+
const max = measure.max === void 0 ? void 0 : Math.max(measure.max, preferred);
|
|
598
|
+
return {
|
|
599
|
+
...measure,
|
|
600
|
+
preferred,
|
|
601
|
+
max
|
|
602
|
+
};
|
|
603
|
+
};
|
|
604
|
+
const commitStickyWidth = ({ key, measure, stickyWidths }) => {
|
|
605
|
+
stickyWidths.set(key, measure.preferred);
|
|
606
|
+
};
|
|
607
|
+
const createStickyColumn = ({ frame, measure: baseMeasure, render, stickyKey }) => {
|
|
608
|
+
const measure = stickyKey === void 0 ? baseMeasure : applyStickyWidth({
|
|
609
|
+
key: stickyKey,
|
|
610
|
+
measure: baseMeasure,
|
|
611
|
+
stickyWidths: frame.stickyWidths
|
|
612
|
+
});
|
|
613
|
+
return {
|
|
614
|
+
measure,
|
|
615
|
+
commitStickyWidth: stickyKey === void 0 ? void 0 : () => {
|
|
616
|
+
commitStickyWidth({
|
|
617
|
+
key: stickyKey,
|
|
618
|
+
measure,
|
|
619
|
+
stickyWidths: frame.stickyWidths
|
|
620
|
+
});
|
|
621
|
+
},
|
|
622
|
+
render
|
|
623
|
+
};
|
|
624
|
+
};
|
|
625
|
+
|
|
626
|
+
//#endregion
|
|
627
|
+
//#region src/ink-renderer/columns/text-width.ts
|
|
555
628
|
const WIDTH_CACHE_LIMIT = 4096;
|
|
556
629
|
const widthCache = /* @__PURE__ */ new Map();
|
|
557
630
|
const textWidth = (text) => {
|
|
@@ -562,140 +635,187 @@ const textWidth = (text) => {
|
|
|
562
635
|
widthCache.set(text, width);
|
|
563
636
|
return width;
|
|
564
637
|
};
|
|
565
|
-
const resolveColumnSpec = (spec, resistance) => ({
|
|
566
|
-
id: spec.id,
|
|
567
|
-
grow: spec.grow,
|
|
568
|
-
canHide: spec.canHide,
|
|
569
|
-
variants: spec.variants.map((variant) => ({
|
|
570
|
-
id: variant.id,
|
|
571
|
-
minWidth: variant.minWidth,
|
|
572
|
-
idealWidth: variant.idealWidth,
|
|
573
|
-
maxWidth: variant.maxWidth,
|
|
574
|
-
shrinkResistance: resistance.shrink(spec.id, variant.id),
|
|
575
|
-
demoteResistance: resistance.demote(spec.id, variant.id),
|
|
576
|
-
hideResistance: resistance.hide(spec.id, variant.id),
|
|
577
|
-
renderCell: variant.renderCell
|
|
578
|
-
}))
|
|
579
|
-
});
|
|
580
|
-
const resolveColumnSpecs = (specs, resistance) => specs.flatMap((spec) => spec.variants.length > 0 ? [resolveColumnSpec(spec, resistance)] : []);
|
|
581
638
|
|
|
582
639
|
//#endregion
|
|
583
|
-
//#region src/ink-renderer/columns/
|
|
584
|
-
const
|
|
585
|
-
const
|
|
586
|
-
const
|
|
587
|
-
const
|
|
588
|
-
const
|
|
589
|
-
const
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
640
|
+
//#region src/ink-renderer/columns/description-column.tsx
|
|
641
|
+
const MIN_PLAIN_DESCRIPTION_WIDTH = 8;
|
|
642
|
+
const MIN_COMPACT_DESCRIPTION_WIDTH = 3;
|
|
643
|
+
const MIN_SPINNER_WIDTH = 1;
|
|
644
|
+
const MIN_TREE_DESCRIPTION_TEXT_WIDTH = 6;
|
|
645
|
+
const DESCRIPTION_TREE_STICKY_KEY = Symbol("description.tree");
|
|
646
|
+
const DESCRIPTION_PLAIN_STICKY_KEY = Symbol("description.plain");
|
|
647
|
+
const DESCRIPTION_COMPACT_STICKY_KEY = Symbol("description.compact");
|
|
648
|
+
const treeAncestorPrefix = (tree) => tree.ancestorHasNextSibling.slice(1).map((hasNext) => hasNext ? "│ " : " ").join("");
|
|
649
|
+
const renderTreePrefix = (tree) => {
|
|
650
|
+
if (tree.depth <= 0) return "";
|
|
651
|
+
return `${treeAncestorPrefix(tree)}${tree.hasNextSibling ? "├─ " : "└─ "}`;
|
|
652
|
+
};
|
|
653
|
+
const maxDescriptionWidth = (frame, showTree) => frame.taskIds.reduce((max, taskId) => {
|
|
654
|
+
const treePrefix = showTree ? renderTreePrefix(frame.getTree(taskId)) : "";
|
|
655
|
+
return Math.max(max, textWidth(`${treePrefix}${frame.getTask(taskId).description}`) + 2);
|
|
656
|
+
}, MIN_PLAIN_DESCRIPTION_WIDTH);
|
|
657
|
+
const minTreeDescriptionWidth = (frame) => frame.taskIds.reduce((max, taskId) => {
|
|
658
|
+
const treePrefixWidth = textWidth(renderTreePrefix(frame.getTree(taskId)));
|
|
659
|
+
return Math.max(max, treePrefixWidth + 2 + MIN_TREE_DESCRIPTION_TEXT_WIDTH);
|
|
660
|
+
}, MIN_PLAIN_DESCRIPTION_WIDTH);
|
|
661
|
+
const DescriptionColumn = (frame, config = {}) => {
|
|
662
|
+
const variant = config.variant ?? "plain";
|
|
663
|
+
const showTree = variant === "tree";
|
|
664
|
+
const stickyKey = variant === "tree" ? DESCRIPTION_TREE_STICKY_KEY : variant === "plain" ? DESCRIPTION_PLAIN_STICKY_KEY : variant === "compact" ? DESCRIPTION_COMPACT_STICKY_KEY : void 0;
|
|
665
|
+
const min = variant === "spinner" ? MIN_SPINNER_WIDTH : variant === "compact" ? MIN_COMPACT_DESCRIPTION_WIDTH : variant === "tree" ? minTreeDescriptionWidth(frame) : MIN_PLAIN_DESCRIPTION_WIDTH;
|
|
666
|
+
const preferred = variant === "spinner" ? MIN_SPINNER_WIDTH : Math.max(min, maxDescriptionWidth(frame, showTree));
|
|
667
|
+
return createStickyColumn({
|
|
668
|
+
frame,
|
|
669
|
+
measure: {
|
|
670
|
+
min,
|
|
671
|
+
preferred,
|
|
672
|
+
max: preferred
|
|
673
|
+
},
|
|
674
|
+
stickyKey,
|
|
675
|
+
render: (taskId) => {
|
|
676
|
+
const task = frame.getTask(taskId);
|
|
677
|
+
const tree = frame.getTree(taskId);
|
|
678
|
+
const treePrefix = showTree ? renderTreePrefix(tree) : "";
|
|
679
|
+
const indicator = getTaskIndicator(task, frame.tick);
|
|
680
|
+
if (variant === "spinner") return /* @__PURE__ */ jsx(Text, {
|
|
681
|
+
color: indicator.color,
|
|
682
|
+
children: indicator.symbol
|
|
683
|
+
});
|
|
684
|
+
return /* @__PURE__ */ jsxs(Text, {
|
|
685
|
+
wrap: "truncate-end",
|
|
686
|
+
children: [
|
|
687
|
+
treePrefix,
|
|
688
|
+
/* @__PURE__ */ jsx(Text, {
|
|
689
|
+
color: indicator.color,
|
|
690
|
+
children: indicator.symbol
|
|
691
|
+
}),
|
|
692
|
+
` ${task.description}`
|
|
693
|
+
]
|
|
694
|
+
});
|
|
695
|
+
}
|
|
596
696
|
});
|
|
597
697
|
};
|
|
598
|
-
const
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
698
|
+
const createDescriptionRootColumn = (variant) => createColumnDefinition({
|
|
699
|
+
_tag: "description",
|
|
700
|
+
variant
|
|
701
|
+
}, (frame, config) => DescriptionColumn(frame, config));
|
|
702
|
+
const DescriptionTreeRootColumn = createDescriptionRootColumn("tree");
|
|
703
|
+
const DescriptionPlainRootColumn = createDescriptionRootColumn("plain");
|
|
704
|
+
const DescriptionCompactRootColumn = createDescriptionRootColumn("compact");
|
|
705
|
+
const DescriptionSpinnerRootColumn = createDescriptionRootColumn("spinner");
|
|
706
|
+
|
|
707
|
+
//#endregion
|
|
708
|
+
//#region src/ink-renderer/columns/elapsed-column.tsx
|
|
709
|
+
const MIN_ELAPSED_WIDTH = Array.from("10s").length;
|
|
710
|
+
const ELAPSED_STICKY_KEY = Symbol("elapsed");
|
|
711
|
+
const maxElapsedWidth = (frame) => frame.taskIds.reduce((max, taskId) => Math.max(max, textWidth(formatElapsed(frame.getTask(taskId), frame.now))), MIN_ELAPSED_WIDTH);
|
|
712
|
+
const ElapsedColumn = (frame) => {
|
|
713
|
+
const elapsedContentWidth = maxElapsedWidth(frame);
|
|
714
|
+
return createStickyColumn({
|
|
715
|
+
frame,
|
|
716
|
+
stickyKey: ELAPSED_STICKY_KEY,
|
|
717
|
+
measure: {
|
|
718
|
+
min: MIN_ELAPSED_WIDTH,
|
|
719
|
+
preferred: elapsedContentWidth,
|
|
720
|
+
max: elapsedContentWidth
|
|
721
|
+
},
|
|
722
|
+
render: (taskId, width) => {
|
|
723
|
+
const formatted = formatElapsed(frame.getTask(taskId), frame.now);
|
|
724
|
+
return /* @__PURE__ */ jsx(Box, {
|
|
725
|
+
width,
|
|
726
|
+
justifyContent: "flex-end",
|
|
727
|
+
children: /* @__PURE__ */ jsx(Text, {
|
|
728
|
+
color: "gray",
|
|
729
|
+
children: textWidth(formatted) <= width ? formatted : formatted.slice(0, width)
|
|
730
|
+
})
|
|
731
|
+
});
|
|
732
|
+
}
|
|
605
733
|
});
|
|
606
734
|
};
|
|
607
|
-
const
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
735
|
+
const ElapsedRootColumn = createColumnDefinition({ _tag: "elapsed" }, (frame) => ElapsedColumn(frame));
|
|
736
|
+
|
|
737
|
+
//#endregion
|
|
738
|
+
//#region src/ink-renderer/columns/determinate.ts
|
|
739
|
+
const isDeterminate = (task) => task.units.total !== void 0;
|
|
740
|
+
|
|
741
|
+
//#endregion
|
|
742
|
+
//#region src/ink-renderer/columns/eta-column.tsx
|
|
743
|
+
const primaryUnit = (duration) => duration.split(" ")[0] ?? duration;
|
|
744
|
+
const ETA_STICKY_KEY = Symbol("eta");
|
|
745
|
+
const etaDurationText = (task, now) => {
|
|
746
|
+
if (task.status !== "running" || !isDeterminate(task)) return;
|
|
747
|
+
const eta = formatEta(task, now);
|
|
748
|
+
return eta.length > 0 ? eta : "--";
|
|
611
749
|
};
|
|
612
|
-
const
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
if (task.status === "running") return /* @__PURE__ */ jsx(Text, {
|
|
620
|
-
color: "yellow",
|
|
621
|
-
children: symbol
|
|
622
|
-
});
|
|
623
|
-
return /* @__PURE__ */ jsx(Text, { children: symbol });
|
|
750
|
+
const renderEtaText = (task, now, width) => {
|
|
751
|
+
const duration = etaDurationText(task, now);
|
|
752
|
+
if (duration === void 0) return "";
|
|
753
|
+
const prefixed = `ETA: ${duration}`;
|
|
754
|
+
if (width >= textWidth(prefixed)) return prefixed;
|
|
755
|
+
if (width >= textWidth(duration)) return duration;
|
|
756
|
+
return primaryUnit(duration);
|
|
624
757
|
};
|
|
625
|
-
const
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
758
|
+
const RESERVED_ETA_WIDTH_UP_TO_ONE_HOUR = Array.from("ETA: 59m 59s").length;
|
|
759
|
+
const computeEtaMetrics = (frame) => {
|
|
760
|
+
let hasEta = false;
|
|
761
|
+
let prefixedWidth = 0;
|
|
762
|
+
let durationWidth = 0;
|
|
763
|
+
let primaryUnitWidth = 0;
|
|
764
|
+
for (const taskId of frame.taskIds) {
|
|
765
|
+
const duration = etaDurationText(frame.getTask(taskId), frame.now);
|
|
766
|
+
if (duration === void 0) continue;
|
|
767
|
+
hasEta = true;
|
|
768
|
+
const prefixed = `ETA: ${duration}`;
|
|
769
|
+
prefixedWidth = Math.max(prefixedWidth, textWidth(prefixed));
|
|
770
|
+
durationWidth = Math.max(durationWidth, textWidth(duration));
|
|
771
|
+
primaryUnitWidth = Math.max(primaryUnitWidth, textWidth(primaryUnit(duration)));
|
|
772
|
+
}
|
|
773
|
+
return {
|
|
774
|
+
hasEta,
|
|
775
|
+
prefixedWidth,
|
|
776
|
+
durationWidth: Math.max(2, durationWidth),
|
|
777
|
+
primaryUnitWidth: Math.max(2, primaryUnitWidth)
|
|
778
|
+
};
|
|
629
779
|
};
|
|
630
|
-
const
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
});
|
|
643
|
-
return /* @__PURE__ */ jsx(Text, {
|
|
780
|
+
const EtaColumn = (frame) => {
|
|
781
|
+
const metrics = computeEtaMetrics(frame);
|
|
782
|
+
if (!metrics.hasEta) return;
|
|
783
|
+
return createStickyColumn({
|
|
784
|
+
frame,
|
|
785
|
+
stickyKey: ETA_STICKY_KEY,
|
|
786
|
+
measure: {
|
|
787
|
+
min: metrics.primaryUnitWidth,
|
|
788
|
+
preferred: Math.max(metrics.prefixedWidth, RESERVED_ETA_WIDTH_UP_TO_ONE_HOUR),
|
|
789
|
+
max: Math.max(metrics.prefixedWidth, RESERVED_ETA_WIDTH_UP_TO_ONE_HOUR)
|
|
790
|
+
},
|
|
791
|
+
render: (taskId, width) => /* @__PURE__ */ jsx(Text, {
|
|
644
792
|
wrap: "truncate-end",
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
if (layout.kind === "processed") return /* @__PURE__ */ jsxs(Box, {
|
|
649
|
-
flexDirection: "row",
|
|
650
|
-
children: [
|
|
651
|
-
/* @__PURE__ */ jsx(ProcessedCountColumn, {
|
|
652
|
-
task,
|
|
653
|
-
width: layout.processedWidth
|
|
654
|
-
}),
|
|
655
|
-
/* @__PURE__ */ jsx(AmountSeparatorColumn, {
|
|
656
|
-
task,
|
|
657
|
-
tick
|
|
658
|
-
}),
|
|
659
|
-
/* @__PURE__ */ jsx(TotalCountColumn, {
|
|
660
|
-
task,
|
|
661
|
-
width: layout.totalWidth
|
|
662
|
-
})
|
|
663
|
-
]
|
|
664
|
-
});
|
|
665
|
-
return /* @__PURE__ */ jsxs(Box, {
|
|
666
|
-
flexDirection: "row",
|
|
667
|
-
children: [
|
|
668
|
-
layout.succeededWidth > 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(SucceededCountColumn, {
|
|
669
|
-
task,
|
|
670
|
-
width: layout.succeededWidth
|
|
671
|
-
}), /* @__PURE__ */ jsx(Text, { children: ` ` })] }) : null,
|
|
672
|
-
layout.failedWidth > 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(FailedCountColumn, {
|
|
673
|
-
task,
|
|
674
|
-
width: layout.failedWidth
|
|
675
|
-
}), /* @__PURE__ */ jsx(Text, { children: ` ` })] }) : null,
|
|
676
|
-
/* @__PURE__ */ jsx(ProcessedCountColumn, {
|
|
677
|
-
task,
|
|
678
|
-
width: layout.processedWidth
|
|
679
|
-
}),
|
|
680
|
-
/* @__PURE__ */ jsx(AmountSeparatorColumn, {
|
|
681
|
-
task,
|
|
682
|
-
tick
|
|
683
|
-
}),
|
|
684
|
-
/* @__PURE__ */ jsx(TotalCountColumn, {
|
|
685
|
-
task,
|
|
686
|
-
width: layout.totalWidth
|
|
687
|
-
})
|
|
688
|
-
]
|
|
793
|
+
color: "gray",
|
|
794
|
+
children: renderEtaText(frame.getTask(taskId), frame.now, width)
|
|
795
|
+
})
|
|
689
796
|
});
|
|
690
797
|
};
|
|
691
|
-
const
|
|
798
|
+
const EtaRootColumn = createColumnDefinition({ _tag: "eta" }, (frame) => EtaColumn(frame));
|
|
799
|
+
|
|
800
|
+
//#endregion
|
|
801
|
+
//#region src/ink-renderer/columns/progress/shared.ts
|
|
802
|
+
const DEFAULT_BAR_WIDTH = 30;
|
|
803
|
+
const PERCENT_FALLBACK_WIDTH = 10;
|
|
804
|
+
const padLeft = (value, width) => value.padStart(Math.max(0, width), " ");
|
|
805
|
+
const padRight = (value, width) => value.padEnd(Math.max(0, width), " ");
|
|
806
|
+
const blank = (width) => " ".repeat(Math.max(0, width));
|
|
807
|
+
const shouldShowCountAmount = (task) => task.units.total !== void 0 || task.units.processed > 0;
|
|
808
|
+
const shouldShowDetailedCounts = (task) => shouldShowCountAmount(task) && task.countDisplay === "detailed";
|
|
809
|
+
const computeProgressMetrics = (frame) => {
|
|
692
810
|
let hasStructuredCounts = false;
|
|
693
811
|
let hasDetailed = false;
|
|
812
|
+
let hasDeterminate = false;
|
|
694
813
|
let countDigits = 0;
|
|
695
814
|
let totalWidth = 0;
|
|
696
815
|
let simpleTextWidth = 0;
|
|
697
|
-
for (const
|
|
698
|
-
const
|
|
816
|
+
for (const taskId of frame.taskIds) {
|
|
817
|
+
const task = frame.getTask(taskId);
|
|
818
|
+
hasDeterminate ||= isDeterminate(task);
|
|
699
819
|
if (shouldShowCountAmount(task)) {
|
|
700
820
|
hasStructuredCounts = true;
|
|
701
821
|
countDigits = Math.max(countDigits, textWidth(`${task.units.succeeded}`), textWidth(`${task.units.failed}`), textWidth(`${task.units.processed}`));
|
|
@@ -703,85 +823,124 @@ const computeAmountMetrics = (rows, tick) => {
|
|
|
703
823
|
if (task.countDisplay === "detailed") hasDetailed = true;
|
|
704
824
|
continue;
|
|
705
825
|
}
|
|
706
|
-
simpleTextWidth = Math.max(simpleTextWidth, textWidth(formatAmount(task, tick)));
|
|
826
|
+
simpleTextWidth = Math.max(simpleTextWidth, textWidth(formatAmount(task, frame.tick)));
|
|
707
827
|
}
|
|
708
828
|
return {
|
|
709
829
|
hasStructuredCounts,
|
|
710
830
|
hasDetailed,
|
|
831
|
+
hasDeterminate,
|
|
711
832
|
countDigits: Math.max(1, countDigits),
|
|
712
833
|
totalWidth: Math.max(1, totalWidth),
|
|
713
834
|
simpleTextWidth
|
|
714
835
|
};
|
|
715
836
|
};
|
|
716
|
-
const detailedAmountLayout = (metrics) => ({
|
|
717
|
-
kind: "detailed",
|
|
718
|
-
succeededWidth: metrics.hasDetailed ? metrics.countDigits : 0,
|
|
719
|
-
failedWidth: metrics.hasDetailed ? metrics.countDigits : 0,
|
|
720
|
-
processedWidth: metrics.countDigits,
|
|
721
|
-
totalWidth: metrics.totalWidth
|
|
722
|
-
});
|
|
723
|
-
const processedAmountLayout = (metrics) => ({
|
|
724
|
-
kind: "processed",
|
|
725
|
-
processedWidth: metrics.countDigits,
|
|
726
|
-
totalWidth: metrics.totalWidth
|
|
727
|
-
});
|
|
728
|
-
const detailedAmountWidth = (metrics) => metrics.countDigits + 1 + metrics.totalWidth + (metrics.hasDetailed ? metrics.countDigits + 1 + metrics.countDigits + 1 : 0);
|
|
729
837
|
const processedAmountWidth = (metrics) => metrics.countDigits + 1 + metrics.totalWidth;
|
|
730
|
-
const
|
|
731
|
-
|
|
732
|
-
if (!
|
|
733
|
-
|
|
734
|
-
const
|
|
838
|
+
const detailedAmountWidth = (metrics) => metrics.countDigits + 1 + metrics.totalWidth + (metrics.hasDetailed ? metrics.countDigits + 1 + metrics.countDigits + 1 : 0);
|
|
839
|
+
const percentText = (task) => {
|
|
840
|
+
if (!isDeterminate(task)) return formatAmount(task, 0);
|
|
841
|
+
if (task.units.total === 0) return "100%";
|
|
842
|
+
const displayTotal = Math.max(task.units.total, task.units.processed);
|
|
843
|
+
return `${Math.max(0, Math.min(100, Math.round(task.units.processed / displayTotal * 100)))}%`;
|
|
844
|
+
};
|
|
845
|
+
|
|
846
|
+
//#endregion
|
|
847
|
+
//#region src/ink-renderer/columns/progress/amount-column.tsx
|
|
848
|
+
const succeededCount = (task, width) => {
|
|
849
|
+
if (width <= 0 || !shouldShowCountAmount(task) || !shouldShowDetailedCounts(task)) return /* @__PURE__ */ jsx(Text, { children: blank(width) });
|
|
850
|
+
return /* @__PURE__ */ jsx(Text, {
|
|
851
|
+
color: "green",
|
|
852
|
+
children: padLeft(`${task.units.succeeded}`, width)
|
|
853
|
+
});
|
|
854
|
+
};
|
|
855
|
+
const failedCount = (task, width) => {
|
|
856
|
+
if (width <= 0 || !shouldShowCountAmount(task) || !shouldShowDetailedCounts(task)) return /* @__PURE__ */ jsx(Text, { children: blank(width) });
|
|
857
|
+
return /* @__PURE__ */ jsx(Text, {
|
|
858
|
+
color: "red",
|
|
859
|
+
children: padLeft(`${task.units.failed}`, width)
|
|
860
|
+
});
|
|
861
|
+
};
|
|
862
|
+
const processedCount = (task, width) => {
|
|
863
|
+
if (width <= 0 || !shouldShowCountAmount(task)) return /* @__PURE__ */ jsx(Text, { children: blank(width) });
|
|
864
|
+
return /* @__PURE__ */ jsx(Text, { children: padLeft(`${task.units.processed}`, width) });
|
|
865
|
+
};
|
|
866
|
+
const totalCount = (task, width) => {
|
|
867
|
+
if (width <= 0 || !shouldShowCountAmount(task)) return /* @__PURE__ */ jsx(Text, { children: blank(width) });
|
|
868
|
+
return /* @__PURE__ */ jsx(Text, { children: padRight(isDeterminate(task) ? `${task.units.total}` : "?", width) });
|
|
869
|
+
};
|
|
870
|
+
const structuredAmount = (task, tick, width, layout) => {
|
|
871
|
+
if (!shouldShowCountAmount(task)) return /* @__PURE__ */ jsx(Text, {
|
|
872
|
+
wrap: "truncate-end",
|
|
873
|
+
children: formatAmount(task, tick)
|
|
874
|
+
});
|
|
875
|
+
if (layout.kind === "processed") return /* @__PURE__ */ jsxs(Box, {
|
|
876
|
+
flexDirection: "row",
|
|
877
|
+
width,
|
|
878
|
+
children: [
|
|
879
|
+
processedCount(task, layout.processedWidth),
|
|
880
|
+
/* @__PURE__ */ jsx(Text, { children: "/" }),
|
|
881
|
+
totalCount(task, layout.totalWidth)
|
|
882
|
+
]
|
|
883
|
+
});
|
|
884
|
+
return /* @__PURE__ */ jsxs(Box, {
|
|
885
|
+
flexDirection: "row",
|
|
886
|
+
width,
|
|
887
|
+
children: [
|
|
888
|
+
layout.succeededWidth > 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [succeededCount(task, layout.succeededWidth), /* @__PURE__ */ jsx(Text, { children: ` ` })] }) : null,
|
|
889
|
+
layout.failedWidth > 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [failedCount(task, layout.failedWidth), /* @__PURE__ */ jsx(Text, { children: ` ` })] }) : null,
|
|
890
|
+
processedCount(task, layout.processedWidth),
|
|
891
|
+
/* @__PURE__ */ jsx(Text, { children: "/" }),
|
|
892
|
+
totalCount(task, layout.totalWidth)
|
|
893
|
+
]
|
|
894
|
+
});
|
|
895
|
+
};
|
|
896
|
+
const AmountColumn = (frame, config) => {
|
|
897
|
+
const metrics = config.metrics ?? computeProgressMetrics(frame);
|
|
735
898
|
const detailedWidth = detailedAmountWidth(metrics);
|
|
736
899
|
const processedWidth = processedAmountWidth(metrics);
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
layout: detailedLayout
|
|
749
|
-
})
|
|
750
|
-
}, {
|
|
751
|
-
id: "processed",
|
|
752
|
-
minWidth: processedWidth,
|
|
753
|
-
idealWidth: processedWidth,
|
|
754
|
-
renderCell: (row) => /* @__PURE__ */ jsx(AmountColumn, {
|
|
755
|
-
task: row.task,
|
|
756
|
-
tick: context.tick,
|
|
757
|
-
layout: processedLayout
|
|
758
|
-
})
|
|
759
|
-
}] : metrics.hasStructuredCounts ? [{
|
|
760
|
-
id: "processed",
|
|
761
|
-
minWidth: processedWidth,
|
|
762
|
-
idealWidth: processedWidth,
|
|
763
|
-
renderCell: (row) => /* @__PURE__ */ jsx(AmountColumn, {
|
|
764
|
-
task: row.task,
|
|
765
|
-
tick: context.tick,
|
|
766
|
-
layout: processedLayout
|
|
767
|
-
})
|
|
768
|
-
}] : [{
|
|
769
|
-
id: "text",
|
|
770
|
-
minWidth: 0,
|
|
771
|
-
idealWidth: metrics.simpleTextWidth,
|
|
772
|
-
renderCell: (row) => /* @__PURE__ */ jsx(AmountColumn, {
|
|
773
|
-
task: row.task,
|
|
774
|
-
tick: context.tick,
|
|
775
|
-
layout: { kind: "text" }
|
|
776
|
-
})
|
|
777
|
-
}]
|
|
900
|
+
const preferredWidth = metrics.hasStructuredCounts ? metrics.hasDetailed ? detailedWidth : processedWidth : Math.max(1, metrics.simpleTextWidth);
|
|
901
|
+
const minWidth = metrics.hasStructuredCounts ? processedWidth : Math.max(1, metrics.simpleTextWidth);
|
|
902
|
+
const summary = {
|
|
903
|
+
hasDetailed: metrics.hasDetailed,
|
|
904
|
+
countDigits: metrics.countDigits,
|
|
905
|
+
totalWidth: metrics.totalWidth,
|
|
906
|
+
detailedWidth,
|
|
907
|
+
processedWidth,
|
|
908
|
+
preferredWidth,
|
|
909
|
+
minWidth,
|
|
910
|
+
simpleTextWidth: Math.max(1, metrics.simpleTextWidth)
|
|
778
911
|
};
|
|
912
|
+
return createStickyColumn({
|
|
913
|
+
frame,
|
|
914
|
+
measure: {
|
|
915
|
+
min: summary.minWidth,
|
|
916
|
+
preferred: summary.preferredWidth,
|
|
917
|
+
max: summary.preferredWidth
|
|
918
|
+
},
|
|
919
|
+
stickyKey: config.stickyWidth === true ? config.key : void 0,
|
|
920
|
+
render: (taskId, width) => {
|
|
921
|
+
const task = frame.getTask(taskId);
|
|
922
|
+
if (!shouldShowCountAmount(task)) return /* @__PURE__ */ jsx(Text, {
|
|
923
|
+
wrap: "truncate-end",
|
|
924
|
+
children: formatAmount(task, frame.tick)
|
|
925
|
+
});
|
|
926
|
+
if (summary.hasDetailed && width >= summary.detailedWidth) return structuredAmount(task, frame.tick, width, {
|
|
927
|
+
kind: "detailed",
|
|
928
|
+
succeededWidth: summary.countDigits,
|
|
929
|
+
failedWidth: summary.countDigits,
|
|
930
|
+
processedWidth: summary.countDigits,
|
|
931
|
+
totalWidth: summary.totalWidth
|
|
932
|
+
});
|
|
933
|
+
return structuredAmount(task, frame.tick, width, {
|
|
934
|
+
kind: "processed",
|
|
935
|
+
processedWidth: summary.countDigits,
|
|
936
|
+
totalWidth: summary.totalWidth
|
|
937
|
+
});
|
|
938
|
+
}
|
|
939
|
+
});
|
|
779
940
|
};
|
|
780
941
|
|
|
781
942
|
//#endregion
|
|
782
|
-
//#region src/ink-renderer/columns/bar-column.tsx
|
|
783
|
-
const DEFAULT_BAR_WIDTH = 30;
|
|
784
|
-
const MIN_BAR_WIDTH = 8;
|
|
943
|
+
//#region src/ink-renderer/columns/progress/bar-column.tsx
|
|
785
944
|
const segmentLengths = (width, total, succeeded, failed) => {
|
|
786
945
|
if (total === 0) return {
|
|
787
946
|
succeeded: width,
|
|
@@ -799,576 +958,335 @@ const segmentLengths = (width, total, succeeded, failed) => {
|
|
|
799
958
|
remaining: Math.max(0, width - succeededLength - failedLength)
|
|
800
959
|
};
|
|
801
960
|
};
|
|
802
|
-
const BarColumn = (
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
961
|
+
const BarColumn = (frame, config) => {
|
|
962
|
+
return createStickyColumn({
|
|
963
|
+
frame,
|
|
964
|
+
measure: {
|
|
965
|
+
min: 4,
|
|
966
|
+
preferred: DEFAULT_BAR_WIDTH,
|
|
967
|
+
max: config.fullWidth ? void 0 : DEFAULT_BAR_WIDTH
|
|
968
|
+
},
|
|
969
|
+
stickyKey: config.stickyWidth === true ? config.key : void 0,
|
|
970
|
+
render: (taskId, width) => {
|
|
971
|
+
const task = frame.getTask(taskId);
|
|
972
|
+
if (!isDeterminate(task)) return /* @__PURE__ */ jsx(Text, { children: blank(width) });
|
|
973
|
+
const lengths = segmentLengths(Math.max(1, Math.floor(width)), task.units.total, task.units.succeeded, task.units.failed);
|
|
974
|
+
return /* @__PURE__ */ jsxs(Text, {
|
|
975
|
+
wrap: "truncate-end",
|
|
976
|
+
children: [
|
|
977
|
+
/* @__PURE__ */ jsx(Text, {
|
|
978
|
+
color: "green",
|
|
979
|
+
children: "━".repeat(lengths.succeeded)
|
|
980
|
+
}),
|
|
981
|
+
/* @__PURE__ */ jsx(Text, {
|
|
982
|
+
color: "red",
|
|
983
|
+
children: "━".repeat(lengths.failed)
|
|
984
|
+
}),
|
|
985
|
+
/* @__PURE__ */ jsx(Text, {
|
|
986
|
+
color: "gray",
|
|
987
|
+
children: "─".repeat(lengths.remaining)
|
|
988
|
+
})
|
|
989
|
+
]
|
|
990
|
+
});
|
|
991
|
+
}
|
|
821
992
|
});
|
|
822
993
|
};
|
|
823
|
-
const createBarColumnSpec = (context, isTTY) => {
|
|
824
|
-
if (!hasDeterminateRows(context.rows)) return;
|
|
825
|
-
return {
|
|
826
|
-
id: "bar",
|
|
827
|
-
grow: 0,
|
|
828
|
-
canHide: true,
|
|
829
|
-
variants: [{
|
|
830
|
-
id: "full",
|
|
831
|
-
minWidth: MIN_BAR_WIDTH,
|
|
832
|
-
idealWidth: DEFAULT_BAR_WIDTH,
|
|
833
|
-
maxWidth: DEFAULT_BAR_WIDTH,
|
|
834
|
-
renderCell: (row, width) => /* @__PURE__ */ jsx(BarColumn, {
|
|
835
|
-
task: row.task,
|
|
836
|
-
tree: row.tree,
|
|
837
|
-
now: context.now,
|
|
838
|
-
tick: context.tick,
|
|
839
|
-
isTTY,
|
|
840
|
-
width: Math.max(1, Math.min(width, DEFAULT_BAR_WIDTH))
|
|
841
|
-
})
|
|
842
|
-
}, {
|
|
843
|
-
id: "compact",
|
|
844
|
-
minWidth: 1,
|
|
845
|
-
idealWidth: MIN_BAR_WIDTH,
|
|
846
|
-
maxWidth: MIN_BAR_WIDTH,
|
|
847
|
-
renderCell: (row, width) => /* @__PURE__ */ jsx(BarColumn, {
|
|
848
|
-
task: row.task,
|
|
849
|
-
tree: row.tree,
|
|
850
|
-
now: context.now,
|
|
851
|
-
tick: context.tick,
|
|
852
|
-
isTTY,
|
|
853
|
-
width: Math.max(1, width)
|
|
854
|
-
})
|
|
855
|
-
}]
|
|
856
|
-
};
|
|
857
|
-
};
|
|
858
994
|
|
|
859
995
|
//#endregion
|
|
860
|
-
//#region src/ink-renderer/
|
|
861
|
-
const
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
996
|
+
//#region src/ink-renderer/columns/progress/percent-column.tsx
|
|
997
|
+
const PercentColumn = (frame) => ({
|
|
998
|
+
measure: {
|
|
999
|
+
min: 4,
|
|
1000
|
+
preferred: 4,
|
|
1001
|
+
max: 4
|
|
1002
|
+
},
|
|
1003
|
+
render: (taskId, _width) => {
|
|
1004
|
+
const task = frame.getTask(taskId);
|
|
1005
|
+
const determinateColor = isDeterminate(task) ? getDeterminateProcessedColor(task) : void 0;
|
|
1006
|
+
return /* @__PURE__ */ jsx(Text, {
|
|
1007
|
+
wrap: "truncate-end",
|
|
1008
|
+
color: determinateColor === "green" || determinateColor === "yellow" || determinateColor === "red" ? determinateColor : void 0,
|
|
1009
|
+
children: percentText(task)
|
|
1010
|
+
});
|
|
1011
|
+
}
|
|
1012
|
+
});
|
|
866
1013
|
|
|
867
1014
|
//#endregion
|
|
868
|
-
//#region src/ink-renderer/columns/
|
|
869
|
-
const
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
color: indicator.color,
|
|
878
|
-
children: indicator.symbol
|
|
879
|
-
}),
|
|
880
|
-
` ${task.description}`
|
|
881
|
-
]
|
|
882
|
-
});
|
|
883
|
-
};
|
|
884
|
-
const MIN_DESCRIPTION_WIDTH = 8;
|
|
885
|
-
const MIN_DESCRIPTION_WITH_TREE_WIDTH = 20;
|
|
886
|
-
const DESCRIPTION_PADDING_GROWTH_LIMIT = 20;
|
|
887
|
-
const maxDescriptionWidth = (rows, showTree) => rows.reduce((max, row) => {
|
|
888
|
-
const treePrefix = showTree ? renderTreePrefix(row.tree) : "";
|
|
889
|
-
return Math.max(max, textWidth(`${treePrefix}${row.task.description}`) + 2);
|
|
890
|
-
}, MIN_DESCRIPTION_WIDTH);
|
|
891
|
-
const createDescriptionColumnSpec = (context, isTTY) => {
|
|
892
|
-
const treeIdeal = maxDescriptionWidth(context.rows, true);
|
|
893
|
-
const plainIdeal = maxDescriptionWidth(context.rows, false);
|
|
894
|
-
const treeVariantIdeal = Math.max(MIN_DESCRIPTION_WITH_TREE_WIDTH, treeIdeal);
|
|
895
|
-
const plainVariantIdeal = Math.max(MIN_DESCRIPTION_WIDTH, plainIdeal);
|
|
896
|
-
return {
|
|
897
|
-
id: "description",
|
|
898
|
-
grow: 1,
|
|
899
|
-
canHide: false,
|
|
900
|
-
variants: [{
|
|
901
|
-
id: "tree",
|
|
902
|
-
minWidth: MIN_DESCRIPTION_WITH_TREE_WIDTH,
|
|
903
|
-
idealWidth: treeVariantIdeal,
|
|
904
|
-
maxWidth: Math.max(DESCRIPTION_PADDING_GROWTH_LIMIT, treeVariantIdeal),
|
|
905
|
-
renderCell: (row) => /* @__PURE__ */ jsx(DescriptionColumn, {
|
|
906
|
-
task: row.task,
|
|
907
|
-
tree: row.tree,
|
|
908
|
-
now: context.now,
|
|
909
|
-
tick: context.tick,
|
|
910
|
-
isTTY,
|
|
911
|
-
showTree: true
|
|
912
|
-
})
|
|
913
|
-
}, {
|
|
914
|
-
id: "plain",
|
|
915
|
-
minWidth: MIN_DESCRIPTION_WIDTH,
|
|
916
|
-
idealWidth: plainVariantIdeal,
|
|
917
|
-
maxWidth: Math.max(DESCRIPTION_PADDING_GROWTH_LIMIT, plainVariantIdeal),
|
|
918
|
-
renderCell: (row) => /* @__PURE__ */ jsx(DescriptionColumn, {
|
|
919
|
-
task: row.task,
|
|
920
|
-
tree: row.tree,
|
|
921
|
-
now: context.now,
|
|
922
|
-
tick: context.tick,
|
|
923
|
-
isTTY,
|
|
924
|
-
showTree: false
|
|
925
|
-
})
|
|
926
|
-
}]
|
|
1015
|
+
//#region src/ink-renderer/columns/progress-metrics-column.tsx
|
|
1016
|
+
const PROGRESS_BAR_STICKY_KEY = Symbol("progress.bar");
|
|
1017
|
+
const PROGRESS_AMOUNT_STICKY_KEY = Symbol("progress.amount");
|
|
1018
|
+
const createProgressColumnModel = (frame, mode) => {
|
|
1019
|
+
const metrics = computeProgressMetrics(frame);
|
|
1020
|
+
const percent = PercentColumn(frame);
|
|
1021
|
+
if (mode === "percent" && metrics.hasDeterminate) return {
|
|
1022
|
+
metrics,
|
|
1023
|
+
percent
|
|
927
1024
|
};
|
|
928
|
-
};
|
|
929
|
-
|
|
930
|
-
//#endregion
|
|
931
|
-
//#region src/ink-renderer/columns/elapsed-column.tsx
|
|
932
|
-
const ElapsedColumn = ({ task, now }) => /* @__PURE__ */ jsx(Text, {
|
|
933
|
-
wrap: "truncate-end",
|
|
934
|
-
color: "gray",
|
|
935
|
-
children: formatElapsed(task, now)
|
|
936
|
-
});
|
|
937
|
-
const MIN_ELAPSED_WIDTH = 2;
|
|
938
|
-
const RESERVED_ELAPSED_WIDTH_UP_TO_ONE_HOUR = Array.from("59m 59s").length;
|
|
939
|
-
const maxElapsedWidth = (rows, now) => rows.reduce((max, row) => Math.max(max, textWidth(formatElapsed(row.task, now))), MIN_ELAPSED_WIDTH);
|
|
940
|
-
const createElapsedColumnSpec = (context, isTTY) => {
|
|
941
|
-
const elapsedContentWidth = maxElapsedWidth(context.rows, context.now);
|
|
942
1025
|
return {
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
isTTY
|
|
956
|
-
})
|
|
957
|
-
}, {
|
|
958
|
-
id: "compact",
|
|
959
|
-
minWidth: MIN_ELAPSED_WIDTH,
|
|
960
|
-
idealWidth: elapsedContentWidth,
|
|
961
|
-
renderCell: (row) => /* @__PURE__ */ jsx(ElapsedColumn, {
|
|
962
|
-
task: row.task,
|
|
963
|
-
tree: row.tree,
|
|
964
|
-
now: context.now,
|
|
965
|
-
tick: context.tick,
|
|
966
|
-
isTTY
|
|
967
|
-
})
|
|
968
|
-
}]
|
|
1026
|
+
metrics,
|
|
1027
|
+
percent,
|
|
1028
|
+
amount: AmountColumn(frame, {
|
|
1029
|
+
key: PROGRESS_AMOUNT_STICKY_KEY,
|
|
1030
|
+
metrics,
|
|
1031
|
+
stickyWidth: true
|
|
1032
|
+
}),
|
|
1033
|
+
bar: metrics.hasDeterminate ? BarColumn(frame, {
|
|
1034
|
+
key: PROGRESS_BAR_STICKY_KEY,
|
|
1035
|
+
fullWidth: false,
|
|
1036
|
+
stickyWidth: true
|
|
1037
|
+
}) : void 0
|
|
969
1038
|
};
|
|
970
1039
|
};
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
const
|
|
978
|
-
return eta.length > 0 ? eta : "--";
|
|
979
|
-
};
|
|
980
|
-
const EtaColumn = ({ task, now, mode }) => {
|
|
981
|
-
const duration = etaDurationText(task, now);
|
|
982
|
-
if (duration === void 0) return /* @__PURE__ */ jsx(Text, {});
|
|
983
|
-
return /* @__PURE__ */ jsx(Text, {
|
|
984
|
-
wrap: "truncate-end",
|
|
985
|
-
color: "gray",
|
|
986
|
-
children: mode === "prefixed" ? `ETA: ${duration}` : mode === "primary" ? primaryUnit(duration) : duration
|
|
987
|
-
});
|
|
988
|
-
};
|
|
989
|
-
const RESERVED_ETA_WIDTH_UP_TO_ONE_HOUR = Array.from("ETA: 59m 59s").length;
|
|
990
|
-
const computeEtaMetrics = (rows, now) => {
|
|
991
|
-
let hasEta = false;
|
|
992
|
-
let prefixedWidth = 0;
|
|
993
|
-
let durationWidth = 0;
|
|
994
|
-
let primaryUnitWidth = 0;
|
|
995
|
-
for (const row of rows) {
|
|
996
|
-
const duration = etaDurationText(row.task, now);
|
|
997
|
-
if (duration === void 0) continue;
|
|
998
|
-
hasEta = true;
|
|
999
|
-
const prefixed = `ETA: ${duration}`;
|
|
1000
|
-
prefixedWidth = Math.max(prefixedWidth, textWidth(prefixed));
|
|
1001
|
-
durationWidth = Math.max(durationWidth, textWidth(duration));
|
|
1002
|
-
primaryUnitWidth = Math.max(primaryUnitWidth, textWidth(primaryUnit(duration)));
|
|
1003
|
-
}
|
|
1040
|
+
const layoutForWidth = (width, model) => {
|
|
1041
|
+
if (!model.metrics.hasDeterminate || model.amount === void 0) return { kind: "amount-only" };
|
|
1042
|
+
const bar = model.bar;
|
|
1043
|
+
if (bar === void 0) return { kind: "percent" };
|
|
1044
|
+
if (width < bar.measure.min + 1 + model.amount.measure.min || width < PERCENT_FALLBACK_WIDTH) return { kind: "percent" };
|
|
1045
|
+
const available = Math.max(0, width - 1);
|
|
1046
|
+
const amountWidth = Math.min(model.amount.measure.preferred, Math.max(model.amount.measure.min, available - bar.measure.min));
|
|
1004
1047
|
return {
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1048
|
+
kind: "bar-amount",
|
|
1049
|
+
bar,
|
|
1050
|
+
barWidth: Math.max(bar.measure.min, available - amountWidth),
|
|
1051
|
+
amountWidth
|
|
1009
1052
|
};
|
|
1010
1053
|
};
|
|
1011
|
-
const
|
|
1012
|
-
const
|
|
1013
|
-
|
|
1054
|
+
const ProgressMetricsColumn = (frame, config = {}) => {
|
|
1055
|
+
const mode = config.mode ?? "full";
|
|
1056
|
+
const model = createProgressColumnModel(frame, mode);
|
|
1057
|
+
if (!model.metrics.hasStructuredCounts && !model.metrics.hasDeterminate) return;
|
|
1058
|
+
if (mode === "percent" && model.metrics.hasDeterminate) return model.percent;
|
|
1059
|
+
const amount = model.amount;
|
|
1060
|
+
if (amount === void 0) return;
|
|
1061
|
+
const preferred = model.metrics.hasDeterminate && model.bar !== void 0 ? model.bar.measure.preferred + 1 + amount.measure.preferred : amount.measure.preferred;
|
|
1062
|
+
const fullMin = model.metrics.hasDeterminate && model.bar !== void 0 ? model.bar.measure.min + 1 + amount.measure.min : amount.measure.min;
|
|
1063
|
+
const max = !model.metrics.hasDeterminate || model.bar === void 0 || model.bar.measure.max === void 0 ? amount.measure.max : model.bar.measure.max + 1 + amount.measure.preferred;
|
|
1014
1064
|
return {
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
},
|
|
1045
|
-
{
|
|
1046
|
-
id: "primary",
|
|
1047
|
-
minWidth: metrics.primaryUnitWidth,
|
|
1048
|
-
idealWidth: metrics.primaryUnitWidth,
|
|
1049
|
-
renderCell: (row) => /* @__PURE__ */ jsx(EtaColumn, {
|
|
1050
|
-
task: row.task,
|
|
1051
|
-
tree: row.tree,
|
|
1052
|
-
now: context.now,
|
|
1053
|
-
tick: context.tick,
|
|
1054
|
-
isTTY,
|
|
1055
|
-
mode: "primary"
|
|
1056
|
-
})
|
|
1057
|
-
}
|
|
1058
|
-
]
|
|
1065
|
+
measure: {
|
|
1066
|
+
min: !model.metrics.hasDeterminate ? amount.measure.min : fullMin,
|
|
1067
|
+
preferred,
|
|
1068
|
+
max
|
|
1069
|
+
},
|
|
1070
|
+
commitStickyWidth: () => {
|
|
1071
|
+
model.bar?.commitStickyWidth?.();
|
|
1072
|
+
amount.commitStickyWidth?.();
|
|
1073
|
+
},
|
|
1074
|
+
render: (taskId, width) => {
|
|
1075
|
+
const layout = layoutForWidth(width, model);
|
|
1076
|
+
if (layout.kind === "percent") return model.percent.render(taskId, width);
|
|
1077
|
+
if (layout.kind === "amount-only") return amount.render(taskId, width);
|
|
1078
|
+
return /* @__PURE__ */ jsxs(Box, {
|
|
1079
|
+
flexDirection: "row",
|
|
1080
|
+
width,
|
|
1081
|
+
children: [
|
|
1082
|
+
/* @__PURE__ */ jsx(Box, {
|
|
1083
|
+
width: layout.barWidth,
|
|
1084
|
+
children: layout.bar.render(taskId, layout.barWidth)
|
|
1085
|
+
}),
|
|
1086
|
+
/* @__PURE__ */ jsx(Box, { marginRight: 1 }),
|
|
1087
|
+
/* @__PURE__ */ jsx(Box, {
|
|
1088
|
+
width: layout.amountWidth,
|
|
1089
|
+
children: amount.render(taskId, layout.amountWidth)
|
|
1090
|
+
})
|
|
1091
|
+
]
|
|
1092
|
+
});
|
|
1093
|
+
}
|
|
1059
1094
|
};
|
|
1060
1095
|
};
|
|
1096
|
+
const createProgressRootColumn = (mode) => createColumnDefinition({
|
|
1097
|
+
_tag: "progress",
|
|
1098
|
+
mode
|
|
1099
|
+
}, (frame, config) => ProgressMetricsColumn(frame, config));
|
|
1100
|
+
const ProgressRootColumn = createProgressRootColumn("full");
|
|
1101
|
+
const ProgressPercentRootColumn = createProgressRootColumn("percent");
|
|
1061
1102
|
|
|
1062
1103
|
//#endregion
|
|
1063
|
-
//#region src/ink-renderer/columns/
|
|
1064
|
-
const
|
|
1065
|
-
const
|
|
1066
|
-
const
|
|
1067
|
-
|
|
1068
|
-
const totalWidth = (columns) => visibleColumns(columns).reduce((sum, column) => sum + column.width, 0) + visibleGapWidth(columns);
|
|
1069
|
-
const currentVariant = (column) => column.variants[column.variantIndex];
|
|
1070
|
-
const variantMaxWidth = (column) => {
|
|
1071
|
-
const variant = currentVariant(column);
|
|
1072
|
-
return variant.maxWidth === void 0 ? Number.POSITIVE_INFINITY : Math.max(variant.minWidth, variant.maxWidth);
|
|
1104
|
+
//#region src/ink-renderer/columns/root-column.tsx
|
|
1105
|
+
const ROOT_GAP = 1;
|
|
1106
|
+
const visibleWidth = (widths, gap) => {
|
|
1107
|
+
const visible = widths.filter((width) => width > 0);
|
|
1108
|
+
return visible.reduce((sum, width) => sum + width, 0) + Math.max(0, visible.length - 1) * gap;
|
|
1073
1109
|
};
|
|
1074
|
-
const
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1110
|
+
const ROOT_LAYOUTS = [
|
|
1111
|
+
[
|
|
1112
|
+
DescriptionTreeRootColumn,
|
|
1113
|
+
ProgressRootColumn,
|
|
1114
|
+
ElapsedRootColumn,
|
|
1115
|
+
EtaRootColumn
|
|
1116
|
+
],
|
|
1117
|
+
[
|
|
1118
|
+
DescriptionPlainRootColumn,
|
|
1119
|
+
ProgressRootColumn,
|
|
1120
|
+
ElapsedRootColumn,
|
|
1121
|
+
EtaRootColumn
|
|
1122
|
+
],
|
|
1123
|
+
[
|
|
1124
|
+
DescriptionPlainRootColumn,
|
|
1125
|
+
ProgressPercentRootColumn,
|
|
1126
|
+
ElapsedRootColumn,
|
|
1127
|
+
EtaRootColumn
|
|
1128
|
+
],
|
|
1129
|
+
[
|
|
1130
|
+
DescriptionPlainRootColumn,
|
|
1131
|
+
ProgressPercentRootColumn,
|
|
1132
|
+
ElapsedRootColumn
|
|
1133
|
+
],
|
|
1134
|
+
[DescriptionPlainRootColumn, ProgressPercentRootColumn],
|
|
1135
|
+
[DescriptionCompactRootColumn, ProgressPercentRootColumn],
|
|
1136
|
+
[DescriptionCompactRootColumn],
|
|
1137
|
+
[DescriptionSpinnerRootColumn]
|
|
1138
|
+
];
|
|
1139
|
+
const ROOT_COLUMNS = [...new Map(ROOT_LAYOUTS.flat().map((column) => [column.id, column])).values()];
|
|
1140
|
+
const measureColumns = (frame) => new Map(ROOT_COLUMNS.flatMap((definition) => {
|
|
1141
|
+
const column = definition.build(frame);
|
|
1142
|
+
if (column === void 0) return [];
|
|
1143
|
+
const measure = column.measure;
|
|
1144
|
+
return [[definition.id, {
|
|
1145
|
+
definition,
|
|
1146
|
+
id: definition.id,
|
|
1147
|
+
measure,
|
|
1148
|
+
preferredWidth: measure.preferred,
|
|
1149
|
+
commitStickyWidth: column.commitStickyWidth,
|
|
1150
|
+
render: column.render
|
|
1151
|
+
}]];
|
|
1152
|
+
}));
|
|
1153
|
+
const candidateRootLayouts = (columnsById) => {
|
|
1154
|
+
const hasProgress = columnsById.has(ProgressRootColumn.id);
|
|
1155
|
+
const hasPercentProgress = columnsById.has(ProgressPercentRootColumn.id);
|
|
1156
|
+
const hasEta = columnsById.has(EtaRootColumn.id);
|
|
1157
|
+
return [
|
|
1158
|
+
...hasProgress && hasEta ? [[
|
|
1159
|
+
DescriptionTreeRootColumn,
|
|
1160
|
+
ProgressRootColumn,
|
|
1161
|
+
ElapsedRootColumn,
|
|
1162
|
+
EtaRootColumn
|
|
1163
|
+
], [
|
|
1164
|
+
DescriptionPlainRootColumn,
|
|
1165
|
+
ProgressRootColumn,
|
|
1166
|
+
ElapsedRootColumn,
|
|
1167
|
+
EtaRootColumn
|
|
1168
|
+
]] : [],
|
|
1169
|
+
...hasProgress && !hasEta ? [[
|
|
1170
|
+
DescriptionTreeRootColumn,
|
|
1171
|
+
ProgressRootColumn,
|
|
1172
|
+
ElapsedRootColumn
|
|
1173
|
+
], [
|
|
1174
|
+
DescriptionPlainRootColumn,
|
|
1175
|
+
ProgressRootColumn,
|
|
1176
|
+
ElapsedRootColumn
|
|
1177
|
+
]] : [],
|
|
1178
|
+
...hasPercentProgress && hasEta ? [[
|
|
1179
|
+
DescriptionPlainRootColumn,
|
|
1180
|
+
ProgressPercentRootColumn,
|
|
1181
|
+
ElapsedRootColumn,
|
|
1182
|
+
EtaRootColumn
|
|
1183
|
+
]] : [],
|
|
1184
|
+
...hasPercentProgress ? [
|
|
1185
|
+
[
|
|
1186
|
+
DescriptionPlainRootColumn,
|
|
1187
|
+
ProgressPercentRootColumn,
|
|
1188
|
+
ElapsedRootColumn
|
|
1189
|
+
],
|
|
1190
|
+
[DescriptionPlainRootColumn, ProgressPercentRootColumn],
|
|
1191
|
+
[DescriptionCompactRootColumn, ProgressPercentRootColumn]
|
|
1192
|
+
] : [],
|
|
1193
|
+
...!hasProgress && !hasPercentProgress ? [
|
|
1194
|
+
[DescriptionTreeRootColumn, ElapsedRootColumn],
|
|
1195
|
+
[DescriptionPlainRootColumn, ElapsedRootColumn],
|
|
1196
|
+
[DescriptionPlainRootColumn]
|
|
1197
|
+
] : [],
|
|
1198
|
+
[DescriptionCompactRootColumn],
|
|
1199
|
+
[DescriptionSpinnerRootColumn]
|
|
1200
|
+
];
|
|
1087
1201
|
};
|
|
1088
|
-
const
|
|
1089
|
-
const
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1202
|
+
const resolveRootLayouts = (columnsById) => {
|
|
1203
|
+
const resolveLayout = (definitions) => {
|
|
1204
|
+
const columns = [];
|
|
1205
|
+
for (const definition of definitions) {
|
|
1206
|
+
const column = columnsById.get(definition.id);
|
|
1207
|
+
if (column === void 0) return;
|
|
1208
|
+
columns.push(column);
|
|
1209
|
+
}
|
|
1210
|
+
return columns;
|
|
1211
|
+
};
|
|
1212
|
+
return candidateRootLayouts(columnsById).map(resolveLayout).filter((columns) => columns !== void 0);
|
|
1094
1213
|
};
|
|
1095
|
-
const
|
|
1096
|
-
const
|
|
1097
|
-
|
|
1098
|
-
|
|
1214
|
+
const minimumWidthForSet = (columns) => visibleWidth(columns.map((column) => column.measure.min), ROOT_GAP);
|
|
1215
|
+
const selectColumnSet = (columnSets, terminalColumns) => {
|
|
1216
|
+
if (columnSets.length === 0) return [];
|
|
1217
|
+
if (terminalColumns === void 0) return columnSets[0] ?? [];
|
|
1218
|
+
return columnSets.find((columns) => minimumWidthForSet(columns) <= terminalColumns) ?? columnSets.at(-1) ?? [];
|
|
1099
1219
|
};
|
|
1100
|
-
const
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
if (distributed === 0) {
|
|
1120
|
-
for (const column of candidates) {
|
|
1121
|
-
if (remaining <= 0) break;
|
|
1122
|
-
if (Math.max(0, variantMaxWidth(column) - column.width) <= 0) continue;
|
|
1123
|
-
column.width += 1;
|
|
1124
|
-
distributed += 1;
|
|
1125
|
-
remaining -= 1;
|
|
1126
|
-
}
|
|
1127
|
-
if (distributed === 0) break;
|
|
1220
|
+
const preferredWidthsForSet = (columns) => columns.map((column) => Math.max(column.measure.min, column.preferredWidth));
|
|
1221
|
+
const nextDistinctWidth = (entries, widest) => entries.find((entry) => entry.width < widest)?.width;
|
|
1222
|
+
const reduceOverflowRichStyle = (widths, minimums, targetWidth) => {
|
|
1223
|
+
let overflow = visibleWidth(widths, ROOT_GAP) - targetWidth;
|
|
1224
|
+
while (overflow > 0) {
|
|
1225
|
+
const shrinkable = widths.map((width, index) => ({
|
|
1226
|
+
width,
|
|
1227
|
+
index,
|
|
1228
|
+
minimum: minimums[index] ?? width
|
|
1229
|
+
})).filter(({ width, minimum }) => width > minimum).sort((left, right) => right.width - left.width || left.index - right.index);
|
|
1230
|
+
if (shrinkable.length === 0) break;
|
|
1231
|
+
const widest = shrinkable[0].width;
|
|
1232
|
+
const cohort = shrinkable.filter(({ width }) => width === widest);
|
|
1233
|
+
const nextWidth = nextDistinctWidth(shrinkable, widest);
|
|
1234
|
+
const maxUniformDrop = widest - Math.max(nextWidth ?? 0, ...cohort.map(({ minimum }) => minimum));
|
|
1235
|
+
const uniformDrop = Math.min(maxUniformDrop, Math.floor(overflow / cohort.length));
|
|
1236
|
+
if (uniformDrop > 0) {
|
|
1237
|
+
for (const { index } of cohort) widths[index] = widths[index] - uniformDrop;
|
|
1238
|
+
overflow -= uniformDrop * cohort.length;
|
|
1128
1239
|
continue;
|
|
1129
1240
|
}
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
};
|
|
1133
|
-
const planColumns = ({ context, baselineWidth, columns }) => {
|
|
1134
|
-
const mutable = columns.flatMap((column) => {
|
|
1135
|
-
if (column.variants.length === 0) return [];
|
|
1136
|
-
const first = column.variants[0];
|
|
1137
|
-
return [{
|
|
1138
|
-
spec: column,
|
|
1139
|
-
variants: column.variants,
|
|
1140
|
-
variantIndex: 0,
|
|
1141
|
-
width: Math.max(first.minWidth, Math.min(first.idealWidth, first.maxWidth === void 0 ? Number.POSITIVE_INFINITY : Math.max(first.minWidth, first.maxWidth))),
|
|
1142
|
-
hidden: false
|
|
1143
|
-
}];
|
|
1144
|
-
});
|
|
1145
|
-
if (mutable.length === 0) return {
|
|
1146
|
-
rowWidth: 0,
|
|
1147
|
-
columns: []
|
|
1148
|
-
};
|
|
1149
|
-
const naturalWidth = totalWidth(mutable);
|
|
1150
|
-
const clampedTerminal = context.terminalColumns === void 0 ? void 0 : clampInt(context.terminalColumns, 1, Number.POSITIVE_INFINITY);
|
|
1151
|
-
const baselineTarget = Math.max(1, Math.max(baselineWidth, naturalWidth));
|
|
1152
|
-
const target = clampedTerminal === void 0 ? baselineTarget : Math.min(baselineTarget, clampedTerminal);
|
|
1153
|
-
if (naturalWidth < target) distributeGrowth(mutable, target - naturalWidth);
|
|
1154
|
-
else if (naturalWidth > target) {
|
|
1155
|
-
let overflow = naturalWidth - target;
|
|
1156
|
-
let progressed = true;
|
|
1157
|
-
while (overflow > 0 && progressed) {
|
|
1158
|
-
const before = overflow;
|
|
1159
|
-
overflow = reduceOverflowByShrink(mutable, overflow);
|
|
1241
|
+
let changed = false;
|
|
1242
|
+
for (const { index, minimum } of cohort) {
|
|
1160
1243
|
if (overflow <= 0) break;
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
continue;
|
|
1166
|
-
}
|
|
1167
|
-
if ((demoteCandidate === void 0 ? Number.POSITIVE_INFINITY : currentVariant(demoteCandidate).demoteResistance) <= (hideCandidate === void 0 ? Number.POSITIVE_INFINITY : currentVariant(hideCandidate).hideResistance) && demoteCandidate !== void 0) applyDemote(demoteCandidate);
|
|
1168
|
-
else if (hideCandidate !== void 0) applyHide(hideCandidate);
|
|
1169
|
-
overflow = Math.max(0, totalWidth(mutable) - target);
|
|
1170
|
-
progressed = true;
|
|
1244
|
+
if (widths[index] <= minimum) continue;
|
|
1245
|
+
widths[index] = widths[index] - 1;
|
|
1246
|
+
overflow -= 1;
|
|
1247
|
+
changed = true;
|
|
1171
1248
|
}
|
|
1172
|
-
|
|
1173
|
-
if (compactedWidth < target) distributeGrowth(mutable, target - compactedWidth);
|
|
1249
|
+
if (!changed) break;
|
|
1174
1250
|
}
|
|
1175
|
-
|
|
1176
|
-
return {
|
|
1177
|
-
rowWidth: totalWidth(mutable),
|
|
1178
|
-
columns: visible.map((column) => {
|
|
1179
|
-
const variant = currentVariant(column);
|
|
1180
|
-
return {
|
|
1181
|
-
id: column.spec.id,
|
|
1182
|
-
variantId: variant.id,
|
|
1183
|
-
width: column.width,
|
|
1184
|
-
renderCell: variant.renderCell
|
|
1185
|
-
};
|
|
1186
|
-
})
|
|
1187
|
-
};
|
|
1251
|
+
return widths;
|
|
1188
1252
|
};
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
* 2. Apply shared resistance rules (shrink / demote / hide) to those variants.
|
|
1197
|
-
* 3. Feed resolved columns into `planColumns`.
|
|
1198
|
-
* 4. `planColumns` shrinks, demotes, and hides until the row fits target width.
|
|
1199
|
-
* 5. Render rows with the selected variant and width for each visible column.
|
|
1200
|
-
*/
|
|
1201
|
-
const BASELINE_ROW_WIDTH = 150;
|
|
1202
|
-
const DEFAULT_RESISTANCE = 1e3;
|
|
1203
|
-
const variantOrderKey = ({ columnId, variantId }) => `${columnId}:${variantId}`;
|
|
1204
|
-
const SHRINK_ORDER = [
|
|
1205
|
-
{
|
|
1206
|
-
columnId: "eta",
|
|
1207
|
-
variantId: "prefixed"
|
|
1208
|
-
},
|
|
1209
|
-
{
|
|
1210
|
-
columnId: "elapsed",
|
|
1211
|
-
variantId: "stable"
|
|
1212
|
-
},
|
|
1213
|
-
{
|
|
1214
|
-
columnId: "eta",
|
|
1215
|
-
variantId: "duration"
|
|
1216
|
-
},
|
|
1217
|
-
{
|
|
1218
|
-
columnId: "eta",
|
|
1219
|
-
variantId: "primary"
|
|
1220
|
-
},
|
|
1221
|
-
{
|
|
1222
|
-
columnId: "bar",
|
|
1223
|
-
variantId: "compact"
|
|
1224
|
-
},
|
|
1225
|
-
{
|
|
1226
|
-
columnId: "bar",
|
|
1227
|
-
variantId: "full"
|
|
1228
|
-
},
|
|
1229
|
-
{
|
|
1230
|
-
columnId: "amount",
|
|
1231
|
-
variantId: "text"
|
|
1232
|
-
},
|
|
1233
|
-
{
|
|
1234
|
-
columnId: "elapsed",
|
|
1235
|
-
variantId: "compact"
|
|
1236
|
-
},
|
|
1237
|
-
{
|
|
1238
|
-
columnId: "description",
|
|
1239
|
-
variantId: "tree"
|
|
1240
|
-
},
|
|
1241
|
-
{
|
|
1242
|
-
columnId: "amount",
|
|
1243
|
-
variantId: "detailed"
|
|
1244
|
-
},
|
|
1245
|
-
{
|
|
1246
|
-
columnId: "amount",
|
|
1247
|
-
variantId: "processed"
|
|
1248
|
-
},
|
|
1249
|
-
{
|
|
1250
|
-
columnId: "description",
|
|
1251
|
-
variantId: "plain"
|
|
1252
|
-
}
|
|
1253
|
-
];
|
|
1254
|
-
const DEMOTE_ORDER = [
|
|
1255
|
-
{
|
|
1256
|
-
columnId: "description",
|
|
1257
|
-
variantId: "tree"
|
|
1258
|
-
},
|
|
1259
|
-
{
|
|
1260
|
-
columnId: "eta",
|
|
1261
|
-
variantId: "prefixed"
|
|
1262
|
-
},
|
|
1263
|
-
{
|
|
1264
|
-
columnId: "eta",
|
|
1265
|
-
variantId: "duration"
|
|
1266
|
-
},
|
|
1267
|
-
{
|
|
1268
|
-
columnId: "elapsed",
|
|
1269
|
-
variantId: "stable"
|
|
1270
|
-
},
|
|
1271
|
-
{
|
|
1272
|
-
columnId: "bar",
|
|
1273
|
-
variantId: "full"
|
|
1274
|
-
},
|
|
1275
|
-
{
|
|
1276
|
-
columnId: "amount",
|
|
1277
|
-
variantId: "detailed"
|
|
1278
|
-
}
|
|
1279
|
-
];
|
|
1280
|
-
const HIDE_ORDER = [
|
|
1281
|
-
{
|
|
1282
|
-
columnId: "eta",
|
|
1283
|
-
variantId: "primary"
|
|
1284
|
-
},
|
|
1285
|
-
{
|
|
1286
|
-
columnId: "eta",
|
|
1287
|
-
variantId: "prefixed"
|
|
1288
|
-
},
|
|
1289
|
-
{
|
|
1290
|
-
columnId: "eta",
|
|
1291
|
-
variantId: "duration"
|
|
1292
|
-
},
|
|
1293
|
-
{
|
|
1294
|
-
columnId: "bar",
|
|
1295
|
-
variantId: "full"
|
|
1296
|
-
},
|
|
1297
|
-
{
|
|
1298
|
-
columnId: "bar",
|
|
1299
|
-
variantId: "compact"
|
|
1300
|
-
},
|
|
1301
|
-
{
|
|
1302
|
-
columnId: "amount",
|
|
1303
|
-
variantId: "text"
|
|
1304
|
-
},
|
|
1305
|
-
{
|
|
1306
|
-
columnId: "amount",
|
|
1307
|
-
variantId: "detailed"
|
|
1308
|
-
},
|
|
1309
|
-
{
|
|
1310
|
-
columnId: "amount",
|
|
1311
|
-
variantId: "processed"
|
|
1312
|
-
}
|
|
1313
|
-
];
|
|
1314
|
-
const toResistanceLookup = (order) => new Map(order.map((item, index) => [variantOrderKey(item), index + 1]));
|
|
1315
|
-
const shrinkResistanceLookup = toResistanceLookup(SHRINK_ORDER);
|
|
1316
|
-
const demoteResistanceLookup = toResistanceLookup(DEMOTE_ORDER);
|
|
1317
|
-
const hideResistanceLookup = toResistanceLookup(HIDE_ORDER);
|
|
1318
|
-
const resistanceFor = (lookup, columnId, variantId) => lookup.get(`${columnId}:${variantId}`) ?? DEFAULT_RESISTANCE;
|
|
1319
|
-
const buildColumns = (context, isTTY) => {
|
|
1320
|
-
return resolveColumnSpecs([
|
|
1321
|
-
createDescriptionColumnSpec(context, isTTY),
|
|
1322
|
-
createBarColumnSpec(context, isTTY),
|
|
1323
|
-
createAmountColumnSpec(context),
|
|
1324
|
-
createElapsedColumnSpec(context, isTTY),
|
|
1325
|
-
createEtaColumnSpec(context, isTTY)
|
|
1326
|
-
].filter((spec) => spec !== void 0), {
|
|
1327
|
-
shrink: (columnId, variantId) => resistanceFor(shrinkResistanceLookup, columnId, variantId),
|
|
1328
|
-
demote: (columnId, variantId) => resistanceFor(demoteResistanceLookup, columnId, variantId),
|
|
1329
|
-
hide: (columnId, variantId) => resistanceFor(hideResistanceLookup, columnId, variantId)
|
|
1330
|
-
});
|
|
1253
|
+
const widthForSelectedSet = (columns, targetWidth) => {
|
|
1254
|
+
if (columns.length === 0) return [];
|
|
1255
|
+
if (targetWidth === void 0) return preferredWidthsForSet(columns);
|
|
1256
|
+
const minimums = columns.map((column) => column.measure.min);
|
|
1257
|
+
const widths = preferredWidthsForSet(columns);
|
|
1258
|
+
if (visibleWidth(widths, ROOT_GAP) <= targetWidth) return widths;
|
|
1259
|
+
return reduceOverflowRichStyle(widths, minimums, targetWidth);
|
|
1331
1260
|
};
|
|
1332
|
-
const
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
now,
|
|
1336
|
-
tick,
|
|
1337
|
-
terminalColumns
|
|
1338
|
-
};
|
|
1339
|
-
return planColumns({
|
|
1340
|
-
context,
|
|
1341
|
-
columns: buildColumns(context, isTTY),
|
|
1342
|
-
baselineWidth: hasDeterminateRows(rows) ? BASELINE_ROW_WIDTH : 1
|
|
1343
|
-
});
|
|
1261
|
+
const emptyRootColumn = (stickyWidths) => {
|
|
1262
|
+
stickyWidths.clear();
|
|
1263
|
+
return { render: () => null };
|
|
1344
1264
|
};
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1265
|
+
const RootColumn = (rows, now, tick, terminalColumns, stickyWidths = /* @__PURE__ */ new Map()) => {
|
|
1266
|
+
if (rows.length === 0) return emptyRootColumn(stickyWidths);
|
|
1267
|
+
const selectedColumns = selectColumnSet(resolveRootLayouts(measureColumns(createRenderFrame(rows, now, tick, stickyWidths))), terminalColumns);
|
|
1268
|
+
for (const column of selectedColumns) column.commitStickyWidth?.();
|
|
1269
|
+
const columns = widthForSelectedSet(selectedColumns, terminalColumns === void 0 ? visibleWidth(selectedColumns.map((column) => column.preferredWidth), ROOT_GAP) : terminalColumns).map((width, index) => ({
|
|
1270
|
+
id: selectedColumns[index].id,
|
|
1271
|
+
width,
|
|
1272
|
+
render: selectedColumns[index].render
|
|
1273
|
+
})).filter((column) => column.width > 0);
|
|
1274
|
+
const taskIds = rows.map((row) => row.task.id);
|
|
1275
|
+
const rowWidth = visibleWidth(columns.map((column) => column.width), ROOT_GAP);
|
|
1276
|
+
return { render: () => /* @__PURE__ */ jsx(Box, {
|
|
1350
1277
|
flexDirection: "row",
|
|
1351
|
-
minWidth:
|
|
1352
|
-
children:
|
|
1278
|
+
minWidth: rowWidth,
|
|
1279
|
+
children: columns.map((column, index) => /* @__PURE__ */ jsx(Box, {
|
|
1280
|
+
flexDirection: "column",
|
|
1353
1281
|
width: column.width,
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1282
|
+
marginRight: index < columns.length - 1 ? ROOT_GAP : 0,
|
|
1283
|
+
children: taskIds.map((taskId) => /* @__PURE__ */ jsx(Box, {
|
|
1284
|
+
width: column.width,
|
|
1285
|
+
height: 1,
|
|
1286
|
+
children: column.render(taskId, column.width)
|
|
1287
|
+
}, taskId))
|
|
1357
1288
|
}, column.id))
|
|
1358
|
-
});
|
|
1359
|
-
};
|
|
1360
|
-
|
|
1361
|
-
//#endregion
|
|
1362
|
-
//#region src/ink-renderer/view/progress-view.tsx
|
|
1363
|
-
const ProgressView = ({ rows, now, tick, isTTY, terminalColumns }) => {
|
|
1364
|
-
const layout = computeFrameLayout(rows, now, tick, terminalColumns, isTTY);
|
|
1365
|
-
return /* @__PURE__ */ jsx(Box, {
|
|
1366
|
-
flexDirection: "column",
|
|
1367
|
-
children: rows.map((row) => /* @__PURE__ */ jsx(TaskRow, {
|
|
1368
|
-
row,
|
|
1369
|
-
layout
|
|
1370
|
-
}, row.task.id))
|
|
1371
|
-
});
|
|
1289
|
+
}) };
|
|
1372
1290
|
};
|
|
1373
1291
|
|
|
1374
1292
|
//#endregion
|
|
@@ -1408,17 +1326,12 @@ const useSpinnerClock = (active, intervalMillis) => {
|
|
|
1408
1326
|
//#region src/ink-renderer/view/render-root.tsx
|
|
1409
1327
|
const SPINNER_INTERVAL_MILLIS = 100;
|
|
1410
1328
|
const NOW_INTERVAL_MILLIS = 1e3;
|
|
1411
|
-
const ProgressRoot = ({ store,
|
|
1329
|
+
const ProgressRoot = ({ store, getTerminalColumns }) => {
|
|
1412
1330
|
const snapshot = useSyncExternalStore(store.subscribe, store.getSnapshot, store.getSnapshot);
|
|
1413
1331
|
const tick = useSpinnerClock(snapshot.hasRunningTasks, SPINNER_INTERVAL_MILLIS);
|
|
1414
1332
|
const now = useNowClock(snapshot.hasRunningTasks, NOW_INTERVAL_MILLIS);
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
now,
|
|
1418
|
-
tick,
|
|
1419
|
-
isTTY,
|
|
1420
|
-
terminalColumns: getTerminalColumns()
|
|
1421
|
-
});
|
|
1333
|
+
const stickyWidths = useRef(/* @__PURE__ */ new Map());
|
|
1334
|
+
return RootColumn(snapshot.rows, now, tick, getTerminalColumns(), stickyWidths.current).render();
|
|
1422
1335
|
};
|
|
1423
1336
|
|
|
1424
1337
|
//#endregion
|
|
@@ -1426,7 +1339,6 @@ const ProgressRoot = ({ store, isTTY, getTerminalColumns }) => {
|
|
|
1426
1339
|
const MAX_FPS = 12;
|
|
1427
1340
|
const makeDefaultInkRenderer = () => ({ run: (store, stdio, isTTY) => Effect.sync(() => render(/* @__PURE__ */ jsx(ProgressRoot, {
|
|
1428
1341
|
store,
|
|
1429
|
-
isTTY,
|
|
1430
1342
|
getTerminalColumns: () => isTTY ? stdio.stderr.columns : void 0
|
|
1431
1343
|
}), {
|
|
1432
1344
|
stdout: stdio.stdout,
|