agy-powerline 1.2.0 → 1.3.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/CHANGELOG.md +34 -0
- package/README.fr.md +190 -0
- package/README.ja.md +68 -26
- package/README.md +84 -29
- package/README.zh-CN.md +80 -38
- package/package.json +3 -2
- package/src/cli/caps.js +2 -0
- package/src/cli/configure.js +8 -144
- package/src/cli/doctor.js +12 -0
- package/src/cli/export.js +82 -0
- package/src/cli/gradient.js +121 -0
- package/src/cli/import.js +273 -0
- package/src/cli/init.js +186 -7
- package/src/cli/layout.js +2 -0
- package/src/cli/preset.js +2 -0
- package/src/cli/repo-url.js +7 -0
- package/src/cli/theme.js +2 -0
- package/src/cli/uninstall.js +6 -2
- package/src/index.js +51 -0
- package/src/lib/catalog.js +54 -2
- package/src/lib/colors.js +127 -0
- package/src/lib/config-check.js +74 -0
- package/src/lib/config.js +20 -1
- package/src/lib/exec.js +140 -21
- package/src/lib/fit.js +7 -0
- package/src/lib/formatters.js +67 -0
- package/src/lib/git.js +374 -2
- package/src/lib/layouts/lines.js +139 -20
- package/src/lib/layouts/pills.js +167 -18
- package/src/lib/paths.js +73 -13
- package/src/lib/prompt.js +30 -0
- package/src/lib/run.js +2 -0
- package/src/lib/session.js +17 -3
- package/src/lib/shared.js +11 -1
- package/src/lib/themes.js +79 -5
- package/src/lib/usage.js +524 -0
- package/src/lib/widget-options.js +194 -0
- package/src/lib/widget-style.js +39 -0
- package/src/runtime/statusline.js +15 -1
package/src/lib/layouts/lines.js
CHANGED
|
@@ -1,6 +1,17 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
const {
|
|
3
|
+
const {
|
|
4
|
+
rgb,
|
|
5
|
+
fg,
|
|
6
|
+
RESET,
|
|
7
|
+
DIM,
|
|
8
|
+
BOLD,
|
|
9
|
+
NORMAL,
|
|
10
|
+
BLINK,
|
|
11
|
+
gradientColors,
|
|
12
|
+
withContrast,
|
|
13
|
+
} = require("../colors");
|
|
14
|
+
const { gradientStops, terminalBackground } = require("../themes");
|
|
4
15
|
const {
|
|
5
16
|
basenameOf,
|
|
6
17
|
homePath,
|
|
@@ -8,6 +19,9 @@ const {
|
|
|
8
19
|
paceIndex,
|
|
9
20
|
paceGlyph,
|
|
10
21
|
formatGitSync,
|
|
22
|
+
formatGitOperation,
|
|
23
|
+
gitChangeParts,
|
|
24
|
+
gitFileParts,
|
|
11
25
|
formatTasks,
|
|
12
26
|
formatMode,
|
|
13
27
|
clipText,
|
|
@@ -15,12 +29,13 @@ const {
|
|
|
15
29
|
formatContextTokens,
|
|
16
30
|
shortModelName,
|
|
17
31
|
formatTokenSplit,
|
|
32
|
+
formatUsage,
|
|
18
33
|
resolveQuotaThresholds,
|
|
19
34
|
resolveContextThresholds,
|
|
20
35
|
shouldBlink,
|
|
21
36
|
} = require("../formatters");
|
|
22
37
|
const { joinFlex } = require("./pills");
|
|
23
|
-
const { execWidgetOutput } = require("../exec");
|
|
38
|
+
const { execWidgetOutput, restoreAfterReset } = require("../exec");
|
|
24
39
|
const {
|
|
25
40
|
NAMED_COLORS,
|
|
26
41
|
resolveColor,
|
|
@@ -28,6 +43,8 @@ const {
|
|
|
28
43
|
widgetTag,
|
|
29
44
|
isRaw,
|
|
30
45
|
isPaced,
|
|
46
|
+
METER_STYLES,
|
|
47
|
+
meterStyle,
|
|
31
48
|
hasNoData,
|
|
32
49
|
RAM_CAUTION,
|
|
33
50
|
RAM_DANGER,
|
|
@@ -126,13 +143,14 @@ function renderDotMeter(
|
|
|
126
143
|
: colorForUsedPct(pct, palette, options));
|
|
127
144
|
|
|
128
145
|
const marker = paceIndex(options.elapsedPct, width);
|
|
146
|
+
const [full, blank] = METER_STYLES[options.style] || METER_STYLES.dots;
|
|
129
147
|
|
|
130
148
|
if (marker < 0) {
|
|
131
149
|
if (ascii) {
|
|
132
150
|
return fg(color) + "#".repeat(filled) + DIM + "-".repeat(empty) + RESET;
|
|
133
151
|
}
|
|
134
152
|
const trackColor = palette.track || rgb(60, 65, 75);
|
|
135
|
-
return fg(color) +
|
|
153
|
+
return fg(color) + full.repeat(filled) + fg(trackColor) + blank.repeat(empty) + RESET;
|
|
136
154
|
}
|
|
137
155
|
|
|
138
156
|
// The marker replaces the dot where the quota window currently is.
|
|
@@ -145,9 +163,9 @@ function renderDotMeter(
|
|
|
145
163
|
if (i === marker) {
|
|
146
164
|
out += undim + fg(markerColor) + paceGlyph(ascii);
|
|
147
165
|
} else if (i < filled) {
|
|
148
|
-
out += undim + fg(color) + (ascii ? "#" :
|
|
166
|
+
out += undim + fg(color) + (ascii ? "#" : full);
|
|
149
167
|
} else {
|
|
150
|
-
out += ascii ? DIM + "-" : fg(trackColor) +
|
|
168
|
+
out += ascii ? DIM + "-" : fg(trackColor) + blank;
|
|
151
169
|
}
|
|
152
170
|
}
|
|
153
171
|
return out + RESET;
|
|
@@ -159,8 +177,10 @@ function buildLinesSegment(id, session, palette, emojis, ascii = false, widget =
|
|
|
159
177
|
const tag = (icon) => widgetTag(id, { emojis, raw, icon });
|
|
160
178
|
// Meters: 25 dots, or 12 when the bar is fitted to a narrow terminal.
|
|
161
179
|
const dots = widget?.compact ? 12 : 25;
|
|
180
|
+
const style = meterStyle(widget, config, "lines");
|
|
162
181
|
const pace = (quota, thresh) => ({
|
|
163
182
|
...thresh,
|
|
183
|
+
style,
|
|
164
184
|
elapsedPct: isPaced(widget, config) ? quota.elapsedPct : null,
|
|
165
185
|
});
|
|
166
186
|
const over200k = session.exceeds200k ? " >200k" : "";
|
|
@@ -304,7 +324,11 @@ function buildLinesSegment(id, session, palette, emojis, ascii = false, widget =
|
|
|
304
324
|
blinkSeq +
|
|
305
325
|
fg(palette.text) +
|
|
306
326
|
tag() +
|
|
307
|
-
renderDotMeter(session.contextPct, dots, ascii, palette, false, {
|
|
327
|
+
renderDotMeter(session.contextPct, dots, ascii, palette, false, {
|
|
328
|
+
...thresh,
|
|
329
|
+
color,
|
|
330
|
+
style,
|
|
331
|
+
}) +
|
|
308
332
|
" " +
|
|
309
333
|
fg(color) +
|
|
310
334
|
`${formatContextTokens(session.usedTokens, session.contextSize)} ` +
|
|
@@ -357,6 +381,7 @@ function buildLinesSegment(id, session, palette, emojis, ascii = false, widget =
|
|
|
357
381
|
if (!session.git || !session.git.branch) {
|
|
358
382
|
return null;
|
|
359
383
|
}
|
|
384
|
+
const opStr = widget.operation === false ? "" : formatGitOperation(session.git.operation);
|
|
360
385
|
const syncStr = formatGitSync(session.git.ahead, session.git.behind, ascii);
|
|
361
386
|
const syncPart = syncStr ? ` ${syncStr}` : "";
|
|
362
387
|
return (
|
|
@@ -365,6 +390,7 @@ function buildLinesSegment(id, session, palette, emojis, ascii = false, widget =
|
|
|
365
390
|
"(" +
|
|
366
391
|
session.git.branch +
|
|
367
392
|
(session.git.dirty ? `${fg(palette.gitDirty)}*` : "") +
|
|
393
|
+
(opStr ? `${fg(palette.gitDirty)} ${opStr}` : "") +
|
|
368
394
|
(syncPart ? `${fg(palette.git)}${syncPart}` : "") +
|
|
369
395
|
fg(palette.git) +
|
|
370
396
|
")" +
|
|
@@ -372,6 +398,52 @@ function buildLinesSegment(id, session, palette, emojis, ascii = false, widget =
|
|
|
372
398
|
);
|
|
373
399
|
}
|
|
374
400
|
|
|
401
|
+
case "gitChanges": {
|
|
402
|
+
const parts = gitChangeParts(session.gitDetails?.changes, ascii);
|
|
403
|
+
if (!parts.length) {
|
|
404
|
+
return null;
|
|
405
|
+
}
|
|
406
|
+
const shade = { added: palette.quotaLow, removed: palette.quotaCrit };
|
|
407
|
+
return (
|
|
408
|
+
fg(palette.git) +
|
|
409
|
+
tag() +
|
|
410
|
+
parts.map((part) => fg(shade[part.kind]) + part.text).join(" ") +
|
|
411
|
+
RESET
|
|
412
|
+
);
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
case "gitFiles": {
|
|
416
|
+
const parts = gitFileParts(session.gitDetails?.files, ascii);
|
|
417
|
+
if (!parts.length) {
|
|
418
|
+
return null;
|
|
419
|
+
}
|
|
420
|
+
const shade = (kind) => (kind === "conflicts" ? palette.quotaCrit : palette.git);
|
|
421
|
+
return (
|
|
422
|
+
fg(palette.git) +
|
|
423
|
+
tag() +
|
|
424
|
+
parts.map((part) => fg(shade(part.kind)) + part.text).join(" ") +
|
|
425
|
+
RESET
|
|
426
|
+
);
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
case "gitSha":
|
|
430
|
+
if (!session.gitDetails?.sha) {
|
|
431
|
+
return null;
|
|
432
|
+
}
|
|
433
|
+
return fg(palette.git) + tag() + session.gitDetails.sha + RESET;
|
|
434
|
+
|
|
435
|
+
case "gitStash":
|
|
436
|
+
if (!(session.gitDetails?.stash > 0)) {
|
|
437
|
+
return null;
|
|
438
|
+
}
|
|
439
|
+
return fg(palette.git) + tag() + session.gitDetails.stash + RESET;
|
|
440
|
+
|
|
441
|
+
case "gitWorktree":
|
|
442
|
+
if (!session.gitDetails?.worktree) {
|
|
443
|
+
return null;
|
|
444
|
+
}
|
|
445
|
+
return fg(palette.git) + tag() + session.gitDetails.worktree + RESET;
|
|
446
|
+
|
|
375
447
|
case "plan":
|
|
376
448
|
if (!session.plan) {
|
|
377
449
|
return null;
|
|
@@ -474,6 +546,32 @@ function buildLinesSegment(id, session, palette, emojis, ascii = false, widget =
|
|
|
474
546
|
RESET
|
|
475
547
|
);
|
|
476
548
|
|
|
549
|
+
case "tokensToday":
|
|
550
|
+
case "tokensWeek": {
|
|
551
|
+
const usage = formatUsage(
|
|
552
|
+
session.usage?.[id === "tokensToday" ? "today" : "week"],
|
|
553
|
+
widget,
|
|
554
|
+
ascii
|
|
555
|
+
);
|
|
556
|
+
if (!usage) {
|
|
557
|
+
return null;
|
|
558
|
+
}
|
|
559
|
+
// A budget alerts like the context widgets: caution, then danger.
|
|
560
|
+
const thresh = resolveContextThresholds(widget, config);
|
|
561
|
+
const level =
|
|
562
|
+
usage.pct === null
|
|
563
|
+
? "normal"
|
|
564
|
+
: usage.pct >= thresh.crit
|
|
565
|
+
? "crit"
|
|
566
|
+
: usage.pct >= thresh.warn
|
|
567
|
+
? "warn"
|
|
568
|
+
: "normal";
|
|
569
|
+
const color =
|
|
570
|
+
level === "crit" ? palette.quotaCrit : level === "warn" ? palette.quotaHigh : palette.text;
|
|
571
|
+
const blinkSeq = !ascii && shouldBlink(level, thresh.blink) ? BLINK : "";
|
|
572
|
+
return blinkSeq + fg(palette.text) + tag() + fg(color) + usage.text + RESET;
|
|
573
|
+
}
|
|
574
|
+
|
|
477
575
|
case "customText": {
|
|
478
576
|
if (!widget?.text) {
|
|
479
577
|
return null;
|
|
@@ -491,7 +589,7 @@ function buildLinesSegment(id, session, palette, emojis, ascii = false, widget =
|
|
|
491
589
|
// buildLinesRows already swapped the widget's color into the palette.
|
|
492
590
|
const col = palette.location;
|
|
493
591
|
const iconPart = emojis && icon && !raw ? `${icon} ` : "";
|
|
494
|
-
return fg(col) + iconPart + named + output + RESET;
|
|
592
|
+
return fg(col) + iconPart + named + restoreAfterReset(output, fg(col)) + RESET;
|
|
495
593
|
}
|
|
496
594
|
|
|
497
595
|
default:
|
|
@@ -530,10 +628,22 @@ function buildLinesRows(session, config, palette, emojis, ascii = false, colors
|
|
|
530
628
|
rowDefs.push(currentRowDef);
|
|
531
629
|
|
|
532
630
|
const rows = [];
|
|
631
|
+
const gradient = colors ? gradientStops(config?.gradient) : null;
|
|
632
|
+
const background = terminalBackground(colors);
|
|
633
|
+
|
|
634
|
+
function renderItem(widget, widgetPal) {
|
|
635
|
+
const item = buildLinesSegment(widget.id, session, widgetPal, emojis, ascii, widget, config);
|
|
636
|
+
// Bold has to survive the resets inside the segment.
|
|
637
|
+
return item && widget.bold === true
|
|
638
|
+
? BOLD + item.split(RESET).join(RESET + BOLD) + RESET
|
|
639
|
+
: item;
|
|
640
|
+
}
|
|
533
641
|
|
|
534
642
|
for (const def of rowDefs) {
|
|
535
643
|
const groups = [];
|
|
536
644
|
let currentGroup = [];
|
|
645
|
+
// The widgets shown in this row, so a gradient spreads over exactly those.
|
|
646
|
+
const placed = [];
|
|
537
647
|
|
|
538
648
|
function flushGroup() {
|
|
539
649
|
if (currentGroup.length) {
|
|
@@ -552,26 +662,35 @@ function buildLinesRows(session, config, palette, emojis, ascii = false, colors
|
|
|
552
662
|
continue;
|
|
553
663
|
}
|
|
554
664
|
|
|
555
|
-
const item =
|
|
556
|
-
widget.id,
|
|
557
|
-
session,
|
|
558
|
-
widgetPalette(widget, palette, colors),
|
|
559
|
-
emojis,
|
|
560
|
-
ascii,
|
|
561
|
-
widget,
|
|
562
|
-
config
|
|
563
|
-
);
|
|
665
|
+
const item = renderItem(widget, widgetPalette(widget, palette, colors));
|
|
564
666
|
|
|
565
667
|
if (item) {
|
|
566
|
-
|
|
567
|
-
currentGroup.push(
|
|
568
|
-
widget.bold === true ? BOLD + item.split(RESET).join(RESET + BOLD) + RESET : item
|
|
569
|
-
);
|
|
668
|
+
placed.push({ widget, group: currentGroup, index: currentGroup.length });
|
|
669
|
+
currentGroup.push(item);
|
|
570
670
|
}
|
|
571
671
|
}
|
|
572
672
|
|
|
573
673
|
flushGroup();
|
|
574
674
|
|
|
675
|
+
// Each widget's text takes its step of the gradient, made readable on the
|
|
676
|
+
// terminal background; alert colors and a widget's own color stay.
|
|
677
|
+
if (gradient && placed.length) {
|
|
678
|
+
const shades = gradientColors(gradient, placed.length);
|
|
679
|
+
placed.forEach(({ widget, group, index }, i) => {
|
|
680
|
+
if (resolveColor(widget.color, colors)) {
|
|
681
|
+
return;
|
|
682
|
+
}
|
|
683
|
+
const shade = withContrast(shades[i], background);
|
|
684
|
+
const item = renderItem(
|
|
685
|
+
widget,
|
|
686
|
+
widgetPalette({ ...widget, color: shade }, palette, colors)
|
|
687
|
+
);
|
|
688
|
+
if (item) {
|
|
689
|
+
group[index] = item;
|
|
690
|
+
}
|
|
691
|
+
});
|
|
692
|
+
}
|
|
693
|
+
|
|
575
694
|
if (groups.length) {
|
|
576
695
|
rows.push(groups);
|
|
577
696
|
}
|
package/src/lib/layouts/pills.js
CHANGED
|
@@ -7,11 +7,15 @@ const {
|
|
|
7
7
|
bgDefault,
|
|
8
8
|
fg,
|
|
9
9
|
BOLD,
|
|
10
|
+
DIM,
|
|
10
11
|
NORMAL,
|
|
11
12
|
BLINK,
|
|
12
13
|
BLINK_OFF,
|
|
13
14
|
getActiveDepth,
|
|
15
|
+
gradientColors,
|
|
16
|
+
readableText,
|
|
14
17
|
} = require("../colors");
|
|
18
|
+
const { gradientStops } = require("../themes");
|
|
15
19
|
const { pickGlyph, glyphChar } = require("../powerline");
|
|
16
20
|
const {
|
|
17
21
|
quotaColor,
|
|
@@ -23,7 +27,11 @@ const {
|
|
|
23
27
|
formatContextTokens,
|
|
24
28
|
shortModelName,
|
|
25
29
|
formatTokenSplit,
|
|
30
|
+
formatUsage,
|
|
26
31
|
formatGitSync,
|
|
32
|
+
formatGitOperation,
|
|
33
|
+
gitChangeParts,
|
|
34
|
+
gitFileParts,
|
|
27
35
|
formatTasks,
|
|
28
36
|
formatMode,
|
|
29
37
|
clipText,
|
|
@@ -35,12 +43,15 @@ const {
|
|
|
35
43
|
paceIndex,
|
|
36
44
|
paceGlyph,
|
|
37
45
|
} = require("../formatters");
|
|
38
|
-
const { execWidgetOutput } = require("../exec");
|
|
46
|
+
const { execWidgetOutput, restoreAfterReset } = require("../exec");
|
|
39
47
|
const {
|
|
48
|
+
resolveColor,
|
|
40
49
|
widgetColors,
|
|
41
50
|
widgetTag,
|
|
42
51
|
isRaw,
|
|
43
52
|
isPaced,
|
|
53
|
+
METER_STYLES,
|
|
54
|
+
meterStyle,
|
|
44
55
|
hasNoData,
|
|
45
56
|
RAM_CAUTION,
|
|
46
57
|
RAM_DANGER,
|
|
@@ -56,6 +67,9 @@ function fillMeter(pct, width, fillColor, emptyColor, segmentColor, pace = {}) {
|
|
|
56
67
|
const ratio = Math.max(0, Math.min(100, Number(pct))) / 100;
|
|
57
68
|
const used = Math.round(ratio * width);
|
|
58
69
|
const marker = paceIndex(pace.elapsedPct, width);
|
|
70
|
+
if (METER_STYLES[pace.style]) {
|
|
71
|
+
return glyphMeter(used, marker, width, METER_STYLES[pace.style], pace);
|
|
72
|
+
}
|
|
59
73
|
// The fill is a background color; without color it is drawn with glyphs.
|
|
60
74
|
const plain = getActiveDepth() === "none";
|
|
61
75
|
const glyph = (filled) => (!plain ? " " : pace.ascii ? (filled ? "#" : "-") : filled ? "█" : "░");
|
|
@@ -73,6 +87,31 @@ function fillMeter(pct, width, fillColor, emptyColor, segmentColor, pace = {}) {
|
|
|
73
87
|
return meter + bg(segmentColor);
|
|
74
88
|
}
|
|
75
89
|
|
|
90
|
+
// A glyph style draws on the pill's own color, with no cells: filled glyphs in
|
|
91
|
+
// the pill's text color (readable on the pill, gradients included), empty
|
|
92
|
+
// ones in the same color dimmed. ASCII mode keeps # and -.
|
|
93
|
+
function glyphMeter(used, marker, width, [full, empty], { ascii, textColor }) {
|
|
94
|
+
let meter = fg(textColor);
|
|
95
|
+
let dim = false;
|
|
96
|
+
|
|
97
|
+
for (let i = 0; i < width; i++) {
|
|
98
|
+
const blank = i !== marker && i >= used;
|
|
99
|
+
if (blank !== dim) {
|
|
100
|
+
meter += blank ? DIM : NORMAL;
|
|
101
|
+
dim = blank;
|
|
102
|
+
}
|
|
103
|
+
if (i === marker) {
|
|
104
|
+
meter += paceGlyph(ascii);
|
|
105
|
+
} else if (ascii) {
|
|
106
|
+
meter += blank ? "-" : "#";
|
|
107
|
+
} else {
|
|
108
|
+
meter += blank ? empty : full;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return dim ? meter + NORMAL : meter;
|
|
113
|
+
}
|
|
114
|
+
|
|
76
115
|
function meterSegment(
|
|
77
116
|
color,
|
|
78
117
|
pct,
|
|
@@ -437,14 +476,52 @@ function buildSegment(id, session, colors, emojis, ascii = false, widget = {}, c
|
|
|
437
476
|
return null;
|
|
438
477
|
}
|
|
439
478
|
const mark = session.git.dirty ? `${ascii ? "* " : "● "}` : "";
|
|
479
|
+
const opStr = widget.operation === false ? "" : formatGitOperation(session.git.operation);
|
|
480
|
+
const opPart = opStr ? `|${opStr}` : "";
|
|
440
481
|
const syncStr = formatGitSync(session.git.ahead, session.git.behind, ascii);
|
|
441
482
|
const syncPart = syncStr ? ` ${syncStr}` : "";
|
|
442
483
|
return pill(
|
|
443
484
|
session.git.dirty ? colors.gitDirty : colors.git,
|
|
444
|
-
lbl(`${mark}${session.git.branch}${syncPart}`)
|
|
485
|
+
lbl(`${mark}${session.git.branch}${opPart}${syncPart}`)
|
|
445
486
|
);
|
|
446
487
|
}
|
|
447
488
|
|
|
489
|
+
case "gitChanges": {
|
|
490
|
+
const parts = gitChangeParts(session.gitDetails?.changes, ascii);
|
|
491
|
+
if (!parts.length) {
|
|
492
|
+
return null;
|
|
493
|
+
}
|
|
494
|
+
return pill(colors.git, lbl(parts.map((part) => part.text).join(" ")));
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
case "gitFiles": {
|
|
498
|
+
const files = session.gitDetails?.files;
|
|
499
|
+
const parts = gitFileParts(files, ascii);
|
|
500
|
+
if (!parts.length) {
|
|
501
|
+
return null;
|
|
502
|
+
}
|
|
503
|
+
const color = files.conflicts > 0 ? colors.gitDirty : colors.git;
|
|
504
|
+
return pill(color, lbl(parts.map((part) => part.text).join(" ")));
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
case "gitSha":
|
|
508
|
+
if (!session.gitDetails?.sha) {
|
|
509
|
+
return null;
|
|
510
|
+
}
|
|
511
|
+
return pill(colors.git, lbl(session.gitDetails.sha));
|
|
512
|
+
|
|
513
|
+
case "gitStash":
|
|
514
|
+
if (!(session.gitDetails?.stash > 0)) {
|
|
515
|
+
return null;
|
|
516
|
+
}
|
|
517
|
+
return pill(colors.git, lbl(String(session.gitDetails.stash)));
|
|
518
|
+
|
|
519
|
+
case "gitWorktree":
|
|
520
|
+
if (!session.gitDetails?.worktree) {
|
|
521
|
+
return null;
|
|
522
|
+
}
|
|
523
|
+
return pill(colors.git, lbl(session.gitDetails.worktree));
|
|
524
|
+
|
|
448
525
|
case "plan":
|
|
449
526
|
if (!session.plan) {
|
|
450
527
|
return null;
|
|
@@ -547,6 +624,32 @@ function buildSegment(id, session, colors, emojis, ascii = false, widget = {}, c
|
|
|
547
624
|
)
|
|
548
625
|
);
|
|
549
626
|
|
|
627
|
+
case "tokensToday":
|
|
628
|
+
case "tokensWeek": {
|
|
629
|
+
const usage = formatUsage(
|
|
630
|
+
session.usage?.[id === "tokensToday" ? "today" : "week"],
|
|
631
|
+
widget,
|
|
632
|
+
ascii
|
|
633
|
+
);
|
|
634
|
+
if (!usage) {
|
|
635
|
+
return null;
|
|
636
|
+
}
|
|
637
|
+
if (usage.pct === null) {
|
|
638
|
+
return pill(colors.meta, lbl(usage.text));
|
|
639
|
+
}
|
|
640
|
+
// A budget alerts like the context widgets: caution, then danger.
|
|
641
|
+
const thresh = resolveContextThresholds(widget, config);
|
|
642
|
+
const level =
|
|
643
|
+
usage.pct >= thresh.crit ? "crit" : usage.pct >= thresh.warn ? "warn" : "normal";
|
|
644
|
+
const color = contextColor(usage.pct, colors.meta, false, {
|
|
645
|
+
crit: thresh.crit,
|
|
646
|
+
warn: thresh.warn,
|
|
647
|
+
critColor: colors.warn,
|
|
648
|
+
warnColor: colors.caution,
|
|
649
|
+
});
|
|
650
|
+
return pill(color, lbl(usage.text), !ascii && shouldBlink(level, thresh.blink));
|
|
651
|
+
}
|
|
652
|
+
|
|
550
653
|
case "customText": {
|
|
551
654
|
if (!widget?.text) {
|
|
552
655
|
return null;
|
|
@@ -573,11 +676,58 @@ function buildSegment(id, session, colors, emojis, ascii = false, widget = {}, c
|
|
|
573
676
|
}
|
|
574
677
|
}
|
|
575
678
|
|
|
679
|
+
// Pill text on a gradient color that the theme's text doesn't read on.
|
|
680
|
+
const READABLE_TEXT = [[22, 22, 28], WHITE, [0, 0, 0]];
|
|
681
|
+
|
|
576
682
|
function buildRows(session, config, colors) {
|
|
577
683
|
const rows = [];
|
|
578
684
|
let groups = [];
|
|
579
685
|
let current = [];
|
|
686
|
+
// The widgets shown in the current row, so a gradient can be spread over
|
|
687
|
+
// exactly those once the row is complete.
|
|
688
|
+
let placed = [];
|
|
580
689
|
const splitEveryWidget = !config.powerline.enabled;
|
|
690
|
+
const gradient = gradientStops(config.gradient);
|
|
691
|
+
|
|
692
|
+
function styledSegment(widget, ownColors) {
|
|
693
|
+
const segment = buildSegment(
|
|
694
|
+
widget.id,
|
|
695
|
+
session,
|
|
696
|
+
ownColors,
|
|
697
|
+
config.emojis,
|
|
698
|
+
config.ascii === true,
|
|
699
|
+
widget,
|
|
700
|
+
config
|
|
701
|
+
);
|
|
702
|
+
if (segment) {
|
|
703
|
+
segment.textColor = ownColors.text;
|
|
704
|
+
segment.bold = widget.bold !== false;
|
|
705
|
+
if (segment.meter) {
|
|
706
|
+
segment.style = meterStyle(widget, config, "pills");
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
return segment;
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
// Each widget takes its step of the gradient in place of its identity
|
|
713
|
+
// color; alert colors and a widget's own color stay as they are.
|
|
714
|
+
function applyGradient() {
|
|
715
|
+
const shades = gradientColors(gradient, placed.length);
|
|
716
|
+
placed.forEach(({ widget, group, index }, i) => {
|
|
717
|
+
if (resolveColor(widget.color, colors)) {
|
|
718
|
+
return;
|
|
719
|
+
}
|
|
720
|
+
const ownColors = widgetColors({ ...widget, color: shades[i] }, colors);
|
|
721
|
+
const segment = styledSegment(widget, ownColors);
|
|
722
|
+
if (!segment) {
|
|
723
|
+
return;
|
|
724
|
+
}
|
|
725
|
+
if (!resolveColor(widget.textColor, colors)) {
|
|
726
|
+
segment.textColor = readableText(segment.color, ownColors.text, READABLE_TEXT);
|
|
727
|
+
}
|
|
728
|
+
group[index] = segment;
|
|
729
|
+
});
|
|
730
|
+
}
|
|
581
731
|
|
|
582
732
|
function flushGroup() {
|
|
583
733
|
if (current.length) {
|
|
@@ -589,6 +739,11 @@ function buildRows(session, config, colors) {
|
|
|
589
739
|
function flushRow() {
|
|
590
740
|
flushGroup();
|
|
591
741
|
|
|
742
|
+
if (gradient && placed.length) {
|
|
743
|
+
applyGradient();
|
|
744
|
+
}
|
|
745
|
+
placed = [];
|
|
746
|
+
|
|
592
747
|
if (groups.length) {
|
|
593
748
|
rows.push(groups);
|
|
594
749
|
groups = [];
|
|
@@ -606,28 +761,18 @@ function buildRows(session, config, colors) {
|
|
|
606
761
|
continue;
|
|
607
762
|
}
|
|
608
763
|
|
|
609
|
-
const
|
|
610
|
-
const segment = buildSegment(
|
|
611
|
-
widget.id,
|
|
612
|
-
session,
|
|
613
|
-
ownColors,
|
|
614
|
-
config.emojis,
|
|
615
|
-
config.ascii === true,
|
|
616
|
-
widget,
|
|
617
|
-
config
|
|
618
|
-
);
|
|
764
|
+
const segment = styledSegment(widget, widgetColors(widget, colors));
|
|
619
765
|
|
|
620
766
|
if (!segment) {
|
|
621
767
|
continue;
|
|
622
768
|
}
|
|
623
769
|
|
|
624
|
-
|
|
625
|
-
|
|
770
|
+
const group = splitEveryWidget ? [] : current;
|
|
771
|
+
placed.push({ widget, group, index: group.length });
|
|
772
|
+
group.push(segment);
|
|
626
773
|
|
|
627
774
|
if (splitEveryWidget) {
|
|
628
|
-
groups.push(
|
|
629
|
-
} else {
|
|
630
|
-
current.push(segment);
|
|
775
|
+
groups.push(group);
|
|
631
776
|
}
|
|
632
777
|
}
|
|
633
778
|
|
|
@@ -674,7 +819,9 @@ function segmentContent(text, color, textColor, blink = false, bold = true) {
|
|
|
674
819
|
const blinkSeq = blink ? BLINK : "";
|
|
675
820
|
const blinkOff = blink ? BLINK_OFF : "";
|
|
676
821
|
// NORMAL clears bold left over from a previous widget.
|
|
677
|
-
|
|
822
|
+
const style = bg(color) + fg(textColor) + blinkSeq + (bold ? BOLD : NORMAL);
|
|
823
|
+
// Only exec output with "colors": true still holds escapes here.
|
|
824
|
+
return style + (text.includes("\x1b") ? restoreAfterReset(text, style) : text) + blinkOff;
|
|
678
825
|
}
|
|
679
826
|
|
|
680
827
|
function renderMeterSegment(segment, colors, ascii = false) {
|
|
@@ -685,6 +832,8 @@ function renderMeterSegment(segment, colors, ascii = false) {
|
|
|
685
832
|
const meter = fillMeter(displayPct, 12, segment.fill, segment.empty, segment.color, {
|
|
686
833
|
elapsedPct: segment.elapsedPct,
|
|
687
834
|
ascii,
|
|
835
|
+
style: segment.style,
|
|
836
|
+
textColor,
|
|
688
837
|
});
|
|
689
838
|
const bold = segment.bold !== false;
|
|
690
839
|
|