agy-powerline 1.3.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 +39 -1
- package/README.fr.md +81 -28
- package/README.ja.md +81 -28
- package/README.md +81 -28
- package/README.zh-CN.md +81 -28
- package/package.json +3 -1
- package/src/cli/configure.js +62 -28
- package/src/index.js +2 -1
- package/src/lib/colors.js +17 -14
- package/src/lib/config.js +69 -20
- package/src/lib/git.js +14 -5
- package/src/lib/layouts/lines.js +39 -11
- package/src/lib/layouts/pills.js +72 -22
- package/src/lib/shared.js +2 -1
- package/src/lib/widget-style.js +12 -6
package/src/lib/layouts/lines.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
const {
|
|
4
4
|
rgb,
|
|
5
5
|
fg,
|
|
6
|
+
mix,
|
|
6
7
|
RESET,
|
|
7
8
|
DIM,
|
|
8
9
|
BOLD,
|
|
@@ -143,27 +144,41 @@ function renderDotMeter(
|
|
|
143
144
|
: colorForUsedPct(pct, palette, options));
|
|
144
145
|
|
|
145
146
|
const marker = paceIndex(options.elapsedPct, width);
|
|
146
|
-
const [full, blank] = METER_STYLES[options.style] || METER_STYLES.dots;
|
|
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;
|
|
147
164
|
|
|
148
|
-
if (marker < 0) {
|
|
165
|
+
if (marker < 0 && !ramp) {
|
|
149
166
|
if (ascii) {
|
|
150
167
|
return fg(color) + "#".repeat(filled) + DIM + "-".repeat(empty) + RESET;
|
|
151
168
|
}
|
|
152
|
-
const trackColor = palette.track || rgb(60, 65, 75);
|
|
153
169
|
return fg(color) + full.repeat(filled) + fg(trackColor) + blank.repeat(empty) + RESET;
|
|
154
170
|
}
|
|
155
171
|
|
|
156
172
|
// The marker replaces the dot where the quota window currently is.
|
|
157
|
-
const
|
|
158
|
-
const markerColor = palette.text || LINES.white;
|
|
173
|
+
const markGlyph = ascii ? paceGlyph(true) : classic ? "│" : pace || paceGlyph(false);
|
|
159
174
|
// ASCII empties are dim; NORMAL ends that without dropping a blink.
|
|
160
175
|
const undim = ascii ? NORMAL : "";
|
|
161
176
|
let out = "";
|
|
162
177
|
for (let i = 0; i < width; i++) {
|
|
163
178
|
if (i === marker) {
|
|
164
|
-
out += undim + fg(markerColor) +
|
|
179
|
+
out += undim + fg(markerColor) + markGlyph;
|
|
165
180
|
} else if (i < filled) {
|
|
166
|
-
out += undim + fg(
|
|
181
|
+
out += undim + fg(fillColor(i)) + (ascii ? "#" : full);
|
|
167
182
|
} else {
|
|
168
183
|
out += ascii ? DIM + "-" : fg(trackColor) + blank;
|
|
169
184
|
}
|
|
@@ -171,16 +186,27 @@ function renderDotMeter(
|
|
|
171
186
|
return out + RESET;
|
|
172
187
|
}
|
|
173
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
|
+
|
|
174
197
|
function buildLinesSegment(id, session, palette, emojis, ascii = false, widget = {}, config = {}) {
|
|
175
198
|
// Raw widgets keep only their value: no icon, no label.
|
|
176
199
|
const raw = isRaw(widget, config);
|
|
177
200
|
const tag = (icon) => widgetTag(id, { emojis, raw, icon });
|
|
178
|
-
// 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";
|
|
179
204
|
const dots = widget?.compact ? 12 : 25;
|
|
180
|
-
const style = meterStyle(widget, config, "lines");
|
|
205
|
+
const style = meterStyle(widget, config, classic ? "classic" : "lines");
|
|
181
206
|
const pace = (quota, thresh) => ({
|
|
182
207
|
...thresh,
|
|
183
208
|
style,
|
|
209
|
+
classic,
|
|
184
210
|
elapsedPct: isPaced(widget, config) ? quota.elapsedPct : null,
|
|
185
211
|
});
|
|
186
212
|
const over200k = session.exceeds200k ? " >200k" : "";
|
|
@@ -328,6 +354,7 @@ function buildLinesSegment(id, session, palette, emojis, ascii = false, widget =
|
|
|
328
354
|
...thresh,
|
|
329
355
|
color,
|
|
330
356
|
style,
|
|
357
|
+
classic,
|
|
331
358
|
}) +
|
|
332
359
|
" " +
|
|
333
360
|
fg(color) +
|
|
@@ -707,7 +734,7 @@ function renderLinesLayout(session, emojis, ascii = false, colors, config) {
|
|
|
707
734
|
return RESET;
|
|
708
735
|
}
|
|
709
736
|
|
|
710
|
-
const pipe = ` ${DIM}${ascii ? "|" : "│"}${RESET} `;
|
|
737
|
+
const pipe = ` ${DIM}${ascii || config.layout === "classic" ? "|" : "│"}${RESET} `;
|
|
711
738
|
|
|
712
739
|
return (
|
|
713
740
|
rows
|
|
@@ -715,7 +742,8 @@ function renderLinesLayout(session, emojis, ascii = false, colors, config) {
|
|
|
715
742
|
const parts = groups.map((group) => group.join(pipe));
|
|
716
743
|
return joinFlex(parts, session.terminalWidth);
|
|
717
744
|
})
|
|
718
|
-
|
|
745
|
+
// rowGap: a line holding a space, as in Pills, so a host keeps it.
|
|
746
|
+
.join(config.rowGap === true ? "\n \n" : "\n") + RESET
|
|
719
747
|
);
|
|
720
748
|
}
|
|
721
749
|
|
package/src/lib/layouts/pills.js
CHANGED
|
@@ -67,7 +67,12 @@ function fillMeter(pct, width, fillColor, emptyColor, segmentColor, pace = {}) {
|
|
|
67
67
|
const ratio = Math.max(0, Math.min(100, Number(pct))) / 100;
|
|
68
68
|
const used = Math.round(ratio * width);
|
|
69
69
|
const marker = paceIndex(pace.elapsedPct, width);
|
|
70
|
-
|
|
70
|
+
// pips, the default, needs a Unicode font: ASCII mode keeps the cells.
|
|
71
|
+
const pips = pace.style === "pips";
|
|
72
|
+
if (pips && !pace.ascii && getActiveDepth() !== "none") {
|
|
73
|
+
return pipMeter(used, marker, width, fillColor, emptyColor) + bg(segmentColor);
|
|
74
|
+
}
|
|
75
|
+
if (METER_STYLES[pace.style] && !(pips && pace.ascii)) {
|
|
71
76
|
return glyphMeter(used, marker, width, METER_STYLES[pace.style], pace);
|
|
72
77
|
}
|
|
73
78
|
// The fill is a background color; without color it is drawn with glyphs.
|
|
@@ -87,10 +92,30 @@ function fillMeter(pct, width, fillColor, emptyColor, segmentColor, pace = {}) {
|
|
|
87
92
|
return meter + bg(segmentColor);
|
|
88
93
|
}
|
|
89
94
|
|
|
95
|
+
// Small dots on the pill's own color: the filled ones in the light fill color,
|
|
96
|
+
// the rest in the dark track color, the same pair cells use. The pace marker
|
|
97
|
+
// is a larger dot in the other color, so nothing in the meter is a line.
|
|
98
|
+
function pipMeter(used, marker, width, fillColor, emptyColor) {
|
|
99
|
+
let meter = "";
|
|
100
|
+
let color = null;
|
|
101
|
+
|
|
102
|
+
for (let i = 0; i < width; i++) {
|
|
103
|
+
const filled = i < used;
|
|
104
|
+
const next = i === marker ? (filled ? emptyColor : fillColor) : filled ? fillColor : emptyColor;
|
|
105
|
+
if (next !== color) {
|
|
106
|
+
meter += fg(next);
|
|
107
|
+
color = next;
|
|
108
|
+
}
|
|
109
|
+
meter += i === marker ? METER_STYLES.pips[2] : METER_STYLES.pips[0];
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return meter;
|
|
113
|
+
}
|
|
114
|
+
|
|
90
115
|
// A glyph style draws on the pill's own color, with no cells: filled glyphs in
|
|
91
116
|
// the pill's text color (readable on the pill, gradients included), empty
|
|
92
117
|
// ones in the same color dimmed. ASCII mode keeps # and -.
|
|
93
|
-
function glyphMeter(used, marker, width, [full, empty], { ascii, textColor }) {
|
|
118
|
+
function glyphMeter(used, marker, width, [full, empty, pace], { ascii, textColor }) {
|
|
94
119
|
let meter = fg(textColor);
|
|
95
120
|
let dim = false;
|
|
96
121
|
|
|
@@ -101,7 +126,7 @@ function glyphMeter(used, marker, width, [full, empty], { ascii, textColor }) {
|
|
|
101
126
|
dim = blank;
|
|
102
127
|
}
|
|
103
128
|
if (i === marker) {
|
|
104
|
-
meter += paceGlyph(ascii);
|
|
129
|
+
meter += (!ascii && pace) || paceGlyph(ascii);
|
|
105
130
|
} else if (ascii) {
|
|
106
131
|
meter += blank ? "-" : "#";
|
|
107
132
|
} else {
|
|
@@ -686,7 +711,6 @@ function buildRows(session, config, colors) {
|
|
|
686
711
|
// The widgets shown in the current row, so a gradient can be spread over
|
|
687
712
|
// exactly those once the row is complete.
|
|
688
713
|
let placed = [];
|
|
689
|
-
const splitEveryWidget = !config.powerline.enabled;
|
|
690
714
|
const gradient = gradientStops(config.gradient);
|
|
691
715
|
|
|
692
716
|
function styledSegment(widget, ownColors) {
|
|
@@ -767,13 +791,8 @@ function buildRows(session, config, colors) {
|
|
|
767
791
|
continue;
|
|
768
792
|
}
|
|
769
793
|
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
group.push(segment);
|
|
773
|
-
|
|
774
|
-
if (splitEveryWidget) {
|
|
775
|
-
groups.push(group);
|
|
776
|
-
}
|
|
794
|
+
placed.push({ widget, group: current, index: current.length });
|
|
795
|
+
current.push(segment);
|
|
777
796
|
}
|
|
778
797
|
|
|
779
798
|
flushRow();
|
|
@@ -794,20 +813,36 @@ function rightCap(color, terminal, glyph) {
|
|
|
794
813
|
return glyph ? fg(color) + capBackground(terminal) + glyph : "";
|
|
795
814
|
}
|
|
796
815
|
|
|
816
|
+
// Compared as the terminal will draw them: at 256 colors two different colors
|
|
817
|
+
// can land on the same code, and without color everything is the same.
|
|
797
818
|
function sameColor(a, b) {
|
|
798
|
-
return
|
|
819
|
+
return bg(a) === bg(b);
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
// Each solid Powerline glyph (U+E0B0 to U+E0BE, even code points) has a thin
|
|
823
|
+
// outline twin at the next code point. The round twins are drawn shorter than
|
|
824
|
+
// the cell in many Nerd Fonts, so round joins use a box-drawing line, which
|
|
825
|
+
// spans the full height.
|
|
826
|
+
function thinGlyph(glyph) {
|
|
827
|
+
const code = glyph.codePointAt(0);
|
|
828
|
+
if (glyph.length !== 1 || code < 0xe0b0 || code > 0xe0be || code % 2 !== 0) {
|
|
829
|
+
return glyph;
|
|
830
|
+
}
|
|
831
|
+
return code === 0xe0b4 || code === 0xe0b6 ? "│" : String.fromCodePoint(code + 1);
|
|
799
832
|
}
|
|
800
833
|
|
|
801
834
|
// A separator between two widgets of the same color would vanish, so it is
|
|
802
|
-
// drawn in the text color instead
|
|
835
|
+
// drawn as its thin outline in the text color instead, the way Powerline
|
|
836
|
+
// divides one color. ASCII joins are characters, not shapes, so they take the
|
|
837
|
+
// text color too, which reads on any pill. Inverted separators (meant for
|
|
803
838
|
// left-pointing glyphs) take the next widget's color on the previous one's.
|
|
804
|
-
function joinSegments(previous, next, glyph, invert, textColor) {
|
|
839
|
+
function joinSegments(previous, next, glyph, invert, textColor, ascii = false) {
|
|
805
840
|
if (!glyph) {
|
|
806
841
|
return "";
|
|
807
842
|
}
|
|
808
843
|
|
|
809
|
-
if (sameColor(previous.color, next.color)) {
|
|
810
|
-
return fg(next.textColor || textColor) + bg(next.color) + glyph;
|
|
844
|
+
if (ascii || sameColor(previous.color, next.color)) {
|
|
845
|
+
return fg(next.textColor || textColor) + bg(next.color) + thinGlyph(glyph);
|
|
811
846
|
}
|
|
812
847
|
|
|
813
848
|
return invert
|
|
@@ -846,13 +881,19 @@ function renderMeterSegment(segment, colors, ascii = false) {
|
|
|
846
881
|
|
|
847
882
|
// Caps cycle per pill and separators per join, counted across the whole
|
|
848
883
|
// statusline, so lists with several glyphs alternate from left to right.
|
|
884
|
+
// Glyphs are drawn without bold, which some fonts draw wider or shifted, and
|
|
885
|
+
// the pill ends on the terminal's background so the padding after it stays
|
|
886
|
+
// clear even without an end cap. Without color, solid caps would be blobs of
|
|
887
|
+
// text color, so only ASCII brackets are kept.
|
|
849
888
|
function renderGroup(group, colors, config, counters = { pill: 0, separator: 0 }) {
|
|
850
889
|
const { powerline } = config;
|
|
851
890
|
const ascii = config.ascii === true;
|
|
852
891
|
const terminal = colors.terminal;
|
|
853
892
|
const pillIndex = counters.pill++;
|
|
854
|
-
const
|
|
855
|
-
const
|
|
893
|
+
const caps = ascii || getActiveDepth() !== "none";
|
|
894
|
+
const cap = (list, slot) => (caps ? glyphChar(pickGlyph(list, pillIndex), slot, ascii) : "");
|
|
895
|
+
const startCap = cap(powerline.startCaps, "startCap");
|
|
896
|
+
const endCap = cap(powerline.endCaps, "endCap");
|
|
856
897
|
|
|
857
898
|
let out = leftCap(group[0].color, terminal, startCap);
|
|
858
899
|
|
|
@@ -873,13 +914,22 @@ function renderGroup(group, colors, config, counters = { pill: 0, separator: 0 }
|
|
|
873
914
|
const slot = counters.separator++;
|
|
874
915
|
const glyph = glyphChar(pickGlyph(powerline.separators, slot), "separator", ascii);
|
|
875
916
|
const invert = powerline.separatorInvert[slot % (powerline.separators.length || 1)];
|
|
876
|
-
out +=
|
|
917
|
+
out +=
|
|
918
|
+
NORMAL + joinSegments(segment, group[i + 1], glyph, invert === true, colors.text, ascii);
|
|
877
919
|
}
|
|
878
920
|
}
|
|
879
921
|
|
|
880
|
-
|
|
922
|
+
const last = group[group.length - 1].color;
|
|
923
|
+
return out + NORMAL + (endCap ? rightCap(last, terminal, endCap) : capBackground(terminal));
|
|
924
|
+
}
|
|
881
925
|
|
|
882
|
-
|
|
926
|
+
// With joins off every widget is a pill of its own, one space from the next;
|
|
927
|
+
// the Flex Separator still decides where the row opens up.
|
|
928
|
+
function renderPills(group, colors, config, counters) {
|
|
929
|
+
if (config.powerline.enabled) {
|
|
930
|
+
return renderGroup(group, colors, config, counters);
|
|
931
|
+
}
|
|
932
|
+
return group.map((segment) => renderGroup([segment], colors, config, counters)).join(" ");
|
|
883
933
|
}
|
|
884
934
|
|
|
885
935
|
function joinFlex(parts, terminalWidth) {
|
|
@@ -917,7 +967,7 @@ function renderPillRows(rows, session, colors, config) {
|
|
|
917
967
|
return rows
|
|
918
968
|
.map((row) =>
|
|
919
969
|
joinFlex(
|
|
920
|
-
row.map((group) =>
|
|
970
|
+
row.map((group) => renderPills(group, colors, config, counters)),
|
|
921
971
|
session.terminalWidth
|
|
922
972
|
)
|
|
923
973
|
)
|
package/src/lib/shared.js
CHANGED
|
@@ -139,7 +139,8 @@ function renderBar(data, config, overrides) {
|
|
|
139
139
|
}
|
|
140
140
|
|
|
141
141
|
function renderLayout(session, config, emojis, ascii, colors) {
|
|
142
|
-
|
|
142
|
+
// Classic is Lines with block meters and | dividers.
|
|
143
|
+
if (config.layout === "lines" || config.layout === "classic") {
|
|
143
144
|
return renderLinesLayout(session, emojis, ascii, colors, config);
|
|
144
145
|
}
|
|
145
146
|
|
package/src/lib/widget-style.js
CHANGED
|
@@ -139,10 +139,12 @@ function widgetTag(id, { emojis = true, raw = false, icon } = {}) {
|
|
|
139
139
|
return `${icon ?? tag.icon} ${tag.iconOnly ? "" : named}`;
|
|
140
140
|
}
|
|
141
141
|
|
|
142
|
-
// Meter styles: [filled, empty] glyphs
|
|
143
|
-
//
|
|
144
|
-
//
|
|
142
|
+
// Meter styles: [filled, empty] glyphs, and a pace marker for a style that
|
|
143
|
+
// has its own. cells has none: Pills draws it with background colors. Every
|
|
144
|
+
// glyph is one column wide for visibleWidth(); a two-column glyph would
|
|
145
|
+
// overflow the meter and throw fitting off.
|
|
145
146
|
const METER_STYLES = {
|
|
147
|
+
pips: ["•", "•", "●"],
|
|
146
148
|
cells: null,
|
|
147
149
|
dots: ["●", "●"],
|
|
148
150
|
blocks: ["█", "░"],
|
|
@@ -152,6 +154,8 @@ const METER_STYLES = {
|
|
|
152
154
|
squares: ["■", "□"],
|
|
153
155
|
braille: ["⣿", "⣀"],
|
|
154
156
|
bars: ["▮", "▯"],
|
|
157
|
+
rings: ["●", "○"],
|
|
158
|
+
ramp: ["█", "░"],
|
|
155
159
|
};
|
|
156
160
|
const METER_STYLE_IDS = Object.keys(METER_STYLES);
|
|
157
161
|
|
|
@@ -160,11 +164,13 @@ function isMeterStyle(value) {
|
|
|
160
164
|
}
|
|
161
165
|
|
|
162
166
|
// The widget's "meter", else the global "meterStyle", else the layout's own;
|
|
163
|
-
// cells exists only in Pills, so
|
|
167
|
+
// cells exists only in Pills, so the text layouts draw their own instead.
|
|
168
|
+
const OWN_METER = { pills: "pips", lines: "dots", classic: "blocks" };
|
|
169
|
+
|
|
164
170
|
function meterStyle(widget, config, layout) {
|
|
165
|
-
const own = layout
|
|
171
|
+
const own = OWN_METER[layout] ?? OWN_METER.pills;
|
|
166
172
|
const id = [widget?.meter, config?.meterStyle].find(isMeterStyle) ?? own;
|
|
167
|
-
return id === "cells" ? own : id;
|
|
173
|
+
return id === "cells" && layout !== "pills" ? own : id;
|
|
168
174
|
}
|
|
169
175
|
|
|
170
176
|
// Longest conversation title shown, in terminal columns.
|