agy-powerline 1.2.0 → 1.4.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 +72 -0
- package/README.fr.md +243 -0
- package/README.ja.md +144 -49
- package/README.md +160 -52
- package/README.zh-CN.md +144 -49
- package/package.json +5 -2
- package/src/cli/caps.js +2 -0
- package/src/cli/configure.js +70 -172
- 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 +53 -1
- package/src/lib/catalog.js +54 -2
- package/src/lib/colors.js +144 -14
- package/src/lib/config-check.js +74 -0
- package/src/lib/config.js +89 -21
- 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 +385 -4
- package/src/lib/layouts/lines.js +175 -28
- package/src/lib/layouts/pills.js +232 -33
- 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 +13 -2
- 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 +45 -0
- package/src/runtime/statusline.js +15 -1
package/src/lib/layouts/lines.js
CHANGED
|
@@ -1,6 +1,18 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
const {
|
|
3
|
+
const {
|
|
4
|
+
rgb,
|
|
5
|
+
fg,
|
|
6
|
+
mix,
|
|
7
|
+
RESET,
|
|
8
|
+
DIM,
|
|
9
|
+
BOLD,
|
|
10
|
+
NORMAL,
|
|
11
|
+
BLINK,
|
|
12
|
+
gradientColors,
|
|
13
|
+
withContrast,
|
|
14
|
+
} = require("../colors");
|
|
15
|
+
const { gradientStops, terminalBackground } = require("../themes");
|
|
4
16
|
const {
|
|
5
17
|
basenameOf,
|
|
6
18
|
homePath,
|
|
@@ -8,6 +20,9 @@ const {
|
|
|
8
20
|
paceIndex,
|
|
9
21
|
paceGlyph,
|
|
10
22
|
formatGitSync,
|
|
23
|
+
formatGitOperation,
|
|
24
|
+
gitChangeParts,
|
|
25
|
+
gitFileParts,
|
|
11
26
|
formatTasks,
|
|
12
27
|
formatMode,
|
|
13
28
|
clipText,
|
|
@@ -15,12 +30,13 @@ const {
|
|
|
15
30
|
formatContextTokens,
|
|
16
31
|
shortModelName,
|
|
17
32
|
formatTokenSplit,
|
|
33
|
+
formatUsage,
|
|
18
34
|
resolveQuotaThresholds,
|
|
19
35
|
resolveContextThresholds,
|
|
20
36
|
shouldBlink,
|
|
21
37
|
} = require("../formatters");
|
|
22
38
|
const { joinFlex } = require("./pills");
|
|
23
|
-
const { execWidgetOutput } = require("../exec");
|
|
39
|
+
const { execWidgetOutput, restoreAfterReset } = require("../exec");
|
|
24
40
|
const {
|
|
25
41
|
NAMED_COLORS,
|
|
26
42
|
resolveColor,
|
|
@@ -28,6 +44,8 @@ const {
|
|
|
28
44
|
widgetTag,
|
|
29
45
|
isRaw,
|
|
30
46
|
isPaced,
|
|
47
|
+
METER_STYLES,
|
|
48
|
+
meterStyle,
|
|
31
49
|
hasNoData,
|
|
32
50
|
RAM_CAUTION,
|
|
33
51
|
RAM_DANGER,
|
|
@@ -126,41 +144,69 @@ function renderDotMeter(
|
|
|
126
144
|
: colorForUsedPct(pct, palette, options));
|
|
127
145
|
|
|
128
146
|
const marker = paceIndex(options.elapsedPct, width);
|
|
147
|
+
const [full, blank, pace] = METER_STYLES[options.style] || METER_STYLES.dots;
|
|
148
|
+
// A Classic meter is one color: the empty glyph's own texture (░) sets it
|
|
149
|
+
// apart, and the pace marker is a thin line.
|
|
150
|
+
const classic = options.classic === true;
|
|
151
|
+
const track = palette.track || rgb(60, 65, 75);
|
|
152
|
+
// ramp shades each filled cell by its place, from the theme's ok color to
|
|
153
|
+
// caution to danger, over the track; rings keeps the fill's color, faded.
|
|
154
|
+
const ramp = options.style === "ramp";
|
|
155
|
+
const trackColor = ramp
|
|
156
|
+
? track
|
|
157
|
+
: options.style === "rings"
|
|
158
|
+
? mix(color, track, 0.5)
|
|
159
|
+
: classic
|
|
160
|
+
? color
|
|
161
|
+
: track;
|
|
162
|
+
const fillColor = (i) => (ramp ? rampColor(width > 1 ? i / (width - 1) : 0, palette) : color);
|
|
163
|
+
const markerColor = palette.text || LINES.white;
|
|
129
164
|
|
|
130
|
-
if (marker < 0) {
|
|
165
|
+
if (marker < 0 && !ramp) {
|
|
131
166
|
if (ascii) {
|
|
132
167
|
return fg(color) + "#".repeat(filled) + DIM + "-".repeat(empty) + RESET;
|
|
133
168
|
}
|
|
134
|
-
|
|
135
|
-
return fg(color) + "●".repeat(filled) + fg(trackColor) + "●".repeat(empty) + RESET;
|
|
169
|
+
return fg(color) + full.repeat(filled) + fg(trackColor) + blank.repeat(empty) + RESET;
|
|
136
170
|
}
|
|
137
171
|
|
|
138
172
|
// The marker replaces the dot where the quota window currently is.
|
|
139
|
-
const
|
|
140
|
-
const markerColor = palette.text || LINES.white;
|
|
173
|
+
const markGlyph = ascii ? paceGlyph(true) : classic ? "│" : pace || paceGlyph(false);
|
|
141
174
|
// ASCII empties are dim; NORMAL ends that without dropping a blink.
|
|
142
175
|
const undim = ascii ? NORMAL : "";
|
|
143
176
|
let out = "";
|
|
144
177
|
for (let i = 0; i < width; i++) {
|
|
145
178
|
if (i === marker) {
|
|
146
|
-
out += undim + fg(markerColor) +
|
|
179
|
+
out += undim + fg(markerColor) + markGlyph;
|
|
147
180
|
} else if (i < filled) {
|
|
148
|
-
out += undim + fg(
|
|
181
|
+
out += undim + fg(fillColor(i)) + (ascii ? "#" : full);
|
|
149
182
|
} else {
|
|
150
|
-
out += ascii ? DIM + "-" : fg(trackColor) +
|
|
183
|
+
out += ascii ? DIM + "-" : fg(trackColor) + blank;
|
|
151
184
|
}
|
|
152
185
|
}
|
|
153
186
|
return out + RESET;
|
|
154
187
|
}
|
|
155
188
|
|
|
189
|
+
// A point along the meter, 0 to 1, as a color between ok, caution and danger.
|
|
190
|
+
function rampColor(at, palette) {
|
|
191
|
+
const ok = palette.quotaLow || LINES.green;
|
|
192
|
+
const caution = palette.quotaHigh || LINES.yellow;
|
|
193
|
+
const danger = palette.quotaCrit || LINES.red;
|
|
194
|
+
return at <= 0.5 ? mix(ok, caution, at * 2) : mix(caution, danger, (at - 0.5) * 2);
|
|
195
|
+
}
|
|
196
|
+
|
|
156
197
|
function buildLinesSegment(id, session, palette, emojis, ascii = false, widget = {}, config = {}) {
|
|
157
198
|
// Raw widgets keep only their value: no icon, no label.
|
|
158
199
|
const raw = isRaw(widget, config);
|
|
159
200
|
const tag = (icon) => widgetTag(id, { emojis, raw, icon });
|
|
160
|
-
// Meters: 25
|
|
201
|
+
// Meters: 25 cells, or 12 when the bar is fitted to a narrow terminal;
|
|
202
|
+
// Classic draws the same cells as blocks.
|
|
203
|
+
const classic = config.layout === "classic";
|
|
161
204
|
const dots = widget?.compact ? 12 : 25;
|
|
205
|
+
const style = meterStyle(widget, config, classic ? "classic" : "lines");
|
|
162
206
|
const pace = (quota, thresh) => ({
|
|
163
207
|
...thresh,
|
|
208
|
+
style,
|
|
209
|
+
classic,
|
|
164
210
|
elapsedPct: isPaced(widget, config) ? quota.elapsedPct : null,
|
|
165
211
|
});
|
|
166
212
|
const over200k = session.exceeds200k ? " >200k" : "";
|
|
@@ -304,7 +350,12 @@ function buildLinesSegment(id, session, palette, emojis, ascii = false, widget =
|
|
|
304
350
|
blinkSeq +
|
|
305
351
|
fg(palette.text) +
|
|
306
352
|
tag() +
|
|
307
|
-
renderDotMeter(session.contextPct, dots, ascii, palette, false, {
|
|
353
|
+
renderDotMeter(session.contextPct, dots, ascii, palette, false, {
|
|
354
|
+
...thresh,
|
|
355
|
+
color,
|
|
356
|
+
style,
|
|
357
|
+
classic,
|
|
358
|
+
}) +
|
|
308
359
|
" " +
|
|
309
360
|
fg(color) +
|
|
310
361
|
`${formatContextTokens(session.usedTokens, session.contextSize)} ` +
|
|
@@ -357,6 +408,7 @@ function buildLinesSegment(id, session, palette, emojis, ascii = false, widget =
|
|
|
357
408
|
if (!session.git || !session.git.branch) {
|
|
358
409
|
return null;
|
|
359
410
|
}
|
|
411
|
+
const opStr = widget.operation === false ? "" : formatGitOperation(session.git.operation);
|
|
360
412
|
const syncStr = formatGitSync(session.git.ahead, session.git.behind, ascii);
|
|
361
413
|
const syncPart = syncStr ? ` ${syncStr}` : "";
|
|
362
414
|
return (
|
|
@@ -365,6 +417,7 @@ function buildLinesSegment(id, session, palette, emojis, ascii = false, widget =
|
|
|
365
417
|
"(" +
|
|
366
418
|
session.git.branch +
|
|
367
419
|
(session.git.dirty ? `${fg(palette.gitDirty)}*` : "") +
|
|
420
|
+
(opStr ? `${fg(palette.gitDirty)} ${opStr}` : "") +
|
|
368
421
|
(syncPart ? `${fg(palette.git)}${syncPart}` : "") +
|
|
369
422
|
fg(palette.git) +
|
|
370
423
|
")" +
|
|
@@ -372,6 +425,52 @@ function buildLinesSegment(id, session, palette, emojis, ascii = false, widget =
|
|
|
372
425
|
);
|
|
373
426
|
}
|
|
374
427
|
|
|
428
|
+
case "gitChanges": {
|
|
429
|
+
const parts = gitChangeParts(session.gitDetails?.changes, ascii);
|
|
430
|
+
if (!parts.length) {
|
|
431
|
+
return null;
|
|
432
|
+
}
|
|
433
|
+
const shade = { added: palette.quotaLow, removed: palette.quotaCrit };
|
|
434
|
+
return (
|
|
435
|
+
fg(palette.git) +
|
|
436
|
+
tag() +
|
|
437
|
+
parts.map((part) => fg(shade[part.kind]) + part.text).join(" ") +
|
|
438
|
+
RESET
|
|
439
|
+
);
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
case "gitFiles": {
|
|
443
|
+
const parts = gitFileParts(session.gitDetails?.files, ascii);
|
|
444
|
+
if (!parts.length) {
|
|
445
|
+
return null;
|
|
446
|
+
}
|
|
447
|
+
const shade = (kind) => (kind === "conflicts" ? palette.quotaCrit : palette.git);
|
|
448
|
+
return (
|
|
449
|
+
fg(palette.git) +
|
|
450
|
+
tag() +
|
|
451
|
+
parts.map((part) => fg(shade(part.kind)) + part.text).join(" ") +
|
|
452
|
+
RESET
|
|
453
|
+
);
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
case "gitSha":
|
|
457
|
+
if (!session.gitDetails?.sha) {
|
|
458
|
+
return null;
|
|
459
|
+
}
|
|
460
|
+
return fg(palette.git) + tag() + session.gitDetails.sha + RESET;
|
|
461
|
+
|
|
462
|
+
case "gitStash":
|
|
463
|
+
if (!(session.gitDetails?.stash > 0)) {
|
|
464
|
+
return null;
|
|
465
|
+
}
|
|
466
|
+
return fg(palette.git) + tag() + session.gitDetails.stash + RESET;
|
|
467
|
+
|
|
468
|
+
case "gitWorktree":
|
|
469
|
+
if (!session.gitDetails?.worktree) {
|
|
470
|
+
return null;
|
|
471
|
+
}
|
|
472
|
+
return fg(palette.git) + tag() + session.gitDetails.worktree + RESET;
|
|
473
|
+
|
|
375
474
|
case "plan":
|
|
376
475
|
if (!session.plan) {
|
|
377
476
|
return null;
|
|
@@ -474,6 +573,32 @@ function buildLinesSegment(id, session, palette, emojis, ascii = false, widget =
|
|
|
474
573
|
RESET
|
|
475
574
|
);
|
|
476
575
|
|
|
576
|
+
case "tokensToday":
|
|
577
|
+
case "tokensWeek": {
|
|
578
|
+
const usage = formatUsage(
|
|
579
|
+
session.usage?.[id === "tokensToday" ? "today" : "week"],
|
|
580
|
+
widget,
|
|
581
|
+
ascii
|
|
582
|
+
);
|
|
583
|
+
if (!usage) {
|
|
584
|
+
return null;
|
|
585
|
+
}
|
|
586
|
+
// A budget alerts like the context widgets: caution, then danger.
|
|
587
|
+
const thresh = resolveContextThresholds(widget, config);
|
|
588
|
+
const level =
|
|
589
|
+
usage.pct === null
|
|
590
|
+
? "normal"
|
|
591
|
+
: usage.pct >= thresh.crit
|
|
592
|
+
? "crit"
|
|
593
|
+
: usage.pct >= thresh.warn
|
|
594
|
+
? "warn"
|
|
595
|
+
: "normal";
|
|
596
|
+
const color =
|
|
597
|
+
level === "crit" ? palette.quotaCrit : level === "warn" ? palette.quotaHigh : palette.text;
|
|
598
|
+
const blinkSeq = !ascii && shouldBlink(level, thresh.blink) ? BLINK : "";
|
|
599
|
+
return blinkSeq + fg(palette.text) + tag() + fg(color) + usage.text + RESET;
|
|
600
|
+
}
|
|
601
|
+
|
|
477
602
|
case "customText": {
|
|
478
603
|
if (!widget?.text) {
|
|
479
604
|
return null;
|
|
@@ -491,7 +616,7 @@ function buildLinesSegment(id, session, palette, emojis, ascii = false, widget =
|
|
|
491
616
|
// buildLinesRows already swapped the widget's color into the palette.
|
|
492
617
|
const col = palette.location;
|
|
493
618
|
const iconPart = emojis && icon && !raw ? `${icon} ` : "";
|
|
494
|
-
return fg(col) + iconPart + named + output + RESET;
|
|
619
|
+
return fg(col) + iconPart + named + restoreAfterReset(output, fg(col)) + RESET;
|
|
495
620
|
}
|
|
496
621
|
|
|
497
622
|
default:
|
|
@@ -530,10 +655,22 @@ function buildLinesRows(session, config, palette, emojis, ascii = false, colors
|
|
|
530
655
|
rowDefs.push(currentRowDef);
|
|
531
656
|
|
|
532
657
|
const rows = [];
|
|
658
|
+
const gradient = colors ? gradientStops(config?.gradient) : null;
|
|
659
|
+
const background = terminalBackground(colors);
|
|
660
|
+
|
|
661
|
+
function renderItem(widget, widgetPal) {
|
|
662
|
+
const item = buildLinesSegment(widget.id, session, widgetPal, emojis, ascii, widget, config);
|
|
663
|
+
// Bold has to survive the resets inside the segment.
|
|
664
|
+
return item && widget.bold === true
|
|
665
|
+
? BOLD + item.split(RESET).join(RESET + BOLD) + RESET
|
|
666
|
+
: item;
|
|
667
|
+
}
|
|
533
668
|
|
|
534
669
|
for (const def of rowDefs) {
|
|
535
670
|
const groups = [];
|
|
536
671
|
let currentGroup = [];
|
|
672
|
+
// The widgets shown in this row, so a gradient spreads over exactly those.
|
|
673
|
+
const placed = [];
|
|
537
674
|
|
|
538
675
|
function flushGroup() {
|
|
539
676
|
if (currentGroup.length) {
|
|
@@ -552,26 +689,35 @@ function buildLinesRows(session, config, palette, emojis, ascii = false, colors
|
|
|
552
689
|
continue;
|
|
553
690
|
}
|
|
554
691
|
|
|
555
|
-
const item =
|
|
556
|
-
widget.id,
|
|
557
|
-
session,
|
|
558
|
-
widgetPalette(widget, palette, colors),
|
|
559
|
-
emojis,
|
|
560
|
-
ascii,
|
|
561
|
-
widget,
|
|
562
|
-
config
|
|
563
|
-
);
|
|
692
|
+
const item = renderItem(widget, widgetPalette(widget, palette, colors));
|
|
564
693
|
|
|
565
694
|
if (item) {
|
|
566
|
-
|
|
567
|
-
currentGroup.push(
|
|
568
|
-
widget.bold === true ? BOLD + item.split(RESET).join(RESET + BOLD) + RESET : item
|
|
569
|
-
);
|
|
695
|
+
placed.push({ widget, group: currentGroup, index: currentGroup.length });
|
|
696
|
+
currentGroup.push(item);
|
|
570
697
|
}
|
|
571
698
|
}
|
|
572
699
|
|
|
573
700
|
flushGroup();
|
|
574
701
|
|
|
702
|
+
// Each widget's text takes its step of the gradient, made readable on the
|
|
703
|
+
// terminal background; alert colors and a widget's own color stay.
|
|
704
|
+
if (gradient && placed.length) {
|
|
705
|
+
const shades = gradientColors(gradient, placed.length);
|
|
706
|
+
placed.forEach(({ widget, group, index }, i) => {
|
|
707
|
+
if (resolveColor(widget.color, colors)) {
|
|
708
|
+
return;
|
|
709
|
+
}
|
|
710
|
+
const shade = withContrast(shades[i], background);
|
|
711
|
+
const item = renderItem(
|
|
712
|
+
widget,
|
|
713
|
+
widgetPalette({ ...widget, color: shade }, palette, colors)
|
|
714
|
+
);
|
|
715
|
+
if (item) {
|
|
716
|
+
group[index] = item;
|
|
717
|
+
}
|
|
718
|
+
});
|
|
719
|
+
}
|
|
720
|
+
|
|
575
721
|
if (groups.length) {
|
|
576
722
|
rows.push(groups);
|
|
577
723
|
}
|
|
@@ -588,7 +734,7 @@ function renderLinesLayout(session, emojis, ascii = false, colors, config) {
|
|
|
588
734
|
return RESET;
|
|
589
735
|
}
|
|
590
736
|
|
|
591
|
-
const pipe = ` ${DIM}${ascii ? "|" : "│"}${RESET} `;
|
|
737
|
+
const pipe = ` ${DIM}${ascii || config.layout === "classic" ? "|" : "│"}${RESET} `;
|
|
592
738
|
|
|
593
739
|
return (
|
|
594
740
|
rows
|
|
@@ -596,7 +742,8 @@ function renderLinesLayout(session, emojis, ascii = false, colors, config) {
|
|
|
596
742
|
const parts = groups.map((group) => group.join(pipe));
|
|
597
743
|
return joinFlex(parts, session.terminalWidth);
|
|
598
744
|
})
|
|
599
|
-
|
|
745
|
+
// rowGap: a line holding a space, as in Pills, so a host keeps it.
|
|
746
|
+
.join(config.rowGap === true ? "\n \n" : "\n") + RESET
|
|
600
747
|
);
|
|
601
748
|
}
|
|
602
749
|
|