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