@bastra-recall/statusline 0.9.2 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.build-revision +2 -0
- package/dist/browser.d.ts +100 -102
- package/dist/browser.js +3 -3
- package/dist/index.mjs +14 -14
- package/package.json +4 -4
- package/src/config/defaults.ts +5 -1
- package/src/powerline-layout.ts +174 -0
- package/src/powerline-segments.ts +374 -0
- package/src/powerline-theme.ts +323 -0
- package/src/powerline.ts +53 -835
- package/src/segments/git.ts +3 -3
- package/src/segments/pricing.ts +78 -1
- package/src/segments/renderer-bars.ts +83 -0
- package/src/segments/renderer-format.ts +89 -0
- package/src/segments/renderer-types.ts +171 -0
- package/src/segments/renderer.ts +80 -328
- package/src/segments/session.ts +29 -5
- package/src/segments/today.ts +11 -13
- package/src/tui/sections-bars.ts +215 -0
- package/src/tui/sections-parts.ts +604 -0
- package/src/tui/sections-shared.ts +23 -0
- package/src/tui/sections.ts +67 -819
- package/src/utils/budget.ts +1 -1
- package/src/utils/claude.ts +55 -16
- package/src/utils/formatters.ts +12 -5
- package/src/utils/terminal.ts +5 -5
package/src/powerline.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import type
|
|
2
|
-
import type { PowerlineColors, ColorTheme } from "./themes";
|
|
1
|
+
import { dropUnreadableRateLimits, type ClaudeHookData } from "./utils/claude";
|
|
3
2
|
import type { PowerlineConfig, LineConfig } from "./config/loader";
|
|
4
3
|
import type {
|
|
5
4
|
UsageInfo,
|
|
@@ -7,191 +6,73 @@ import type {
|
|
|
7
6
|
MetricsInfo,
|
|
8
7
|
PowerlineSymbols,
|
|
9
8
|
AnySegmentConfig,
|
|
10
|
-
DirectorySegmentConfig,
|
|
11
|
-
GitSegmentConfig,
|
|
12
|
-
UsageSegmentConfig,
|
|
13
9
|
ContextSegmentConfig,
|
|
14
|
-
MetricsSegmentConfig,
|
|
15
|
-
BlockSegmentConfig,
|
|
16
|
-
TodaySegmentConfig,
|
|
17
|
-
VersionSegmentConfig,
|
|
18
|
-
SessionIdSegmentConfig,
|
|
19
|
-
EnvSegmentConfig,
|
|
20
|
-
WeeklySegmentConfig,
|
|
21
|
-
AgentSegmentConfig,
|
|
22
|
-
ThinkingSegmentConfig,
|
|
23
|
-
CacheTimerSegmentConfig,
|
|
24
10
|
} from "./segments";
|
|
25
11
|
import type { BlockInfo } from "./segments/block";
|
|
26
12
|
import type { TodayInfo } from "./segments/today";
|
|
27
13
|
import type { CacheTimerInfo } from "./segments/cacheTimer";
|
|
28
14
|
import type { TuiData } from "./tui";
|
|
15
|
+
import type { RenderedSegment } from "./powerline-layout";
|
|
29
16
|
|
|
30
|
-
import {
|
|
31
|
-
hexToAnsi,
|
|
32
|
-
extractBgToFg,
|
|
33
|
-
hexToBasicAnsi,
|
|
34
|
-
hexTo256Ansi,
|
|
35
|
-
hexColorDistance,
|
|
36
|
-
} from "./utils/colors";
|
|
37
|
-
import { getColorSupport } from "./utils/color-support";
|
|
38
|
-
import { getTheme } from "./themes";
|
|
39
|
-
import {
|
|
40
|
-
UsageProvider,
|
|
41
|
-
ContextProvider,
|
|
42
|
-
GitService,
|
|
43
|
-
TmuxService,
|
|
44
|
-
MetricsProvider,
|
|
45
|
-
SegmentRenderer,
|
|
46
|
-
} from "./segments";
|
|
47
|
-
import { BlockProvider } from "./segments/block";
|
|
48
|
-
import { TodayProvider } from "./segments/today";
|
|
49
|
-
import { CacheTimerProvider } from "./segments/cacheTimer";
|
|
50
|
-
import { BastraProvider } from "./segments/bastra";
|
|
51
|
-
import type { BastraSegmentConfig } from "./segments/renderer";
|
|
52
|
-
import {
|
|
53
|
-
SYMBOLS,
|
|
54
|
-
TEXT_SYMBOLS,
|
|
55
|
-
RESET_CODE,
|
|
56
|
-
BOX_CHARS,
|
|
57
|
-
BOX_CHARS_TEXT,
|
|
58
|
-
} from "./utils/constants";
|
|
59
|
-
import { visibleLength } from "./utils/terminal";
|
|
17
|
+
import { BOX_CHARS, BOX_CHARS_TEXT } from "./utils/constants";
|
|
60
18
|
import { getTerminalWidth, getRawTerminalWidth } from "./utils/terminal-width";
|
|
61
19
|
import { renderTuiPanel } from "./tui";
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
20
|
+
import { PowerlineTheme } from "./powerline-theme";
|
|
21
|
+
import { PowerlineSegments } from "./powerline-segments";
|
|
22
|
+
import { PowerlineLayout } from "./powerline-layout";
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Renders the statusline for one hook tick. Since #1039 the work is split
|
|
26
|
+
* over three collaborators: PowerlineTheme (glyphs, colours), PowerlineSegments
|
|
27
|
+
* (data providers, per-segment dispatch) and PowerlineLayout (measuring,
|
|
28
|
+
* wrapping, ANSI line assembly). This class keeps the flow: which data to
|
|
29
|
+
* fetch, which lines to render, and the TUI hand-over.
|
|
30
|
+
*/
|
|
71
31
|
export class PowerlineRenderer {
|
|
72
32
|
private readonly symbols: PowerlineSymbols;
|
|
73
|
-
private
|
|
74
|
-
private
|
|
75
|
-
private
|
|
76
|
-
private _contextProvider?: ContextProvider;
|
|
77
|
-
private _gitService?: GitService;
|
|
78
|
-
private _tmuxService?: TmuxService;
|
|
79
|
-
private _metricsProvider?: MetricsProvider;
|
|
80
|
-
private _cacheTimerProvider?: CacheTimerProvider;
|
|
81
|
-
private _bastraProvider?: BastraProvider;
|
|
82
|
-
private _segmentRenderer?: SegmentRenderer;
|
|
33
|
+
private readonly theme: PowerlineTheme;
|
|
34
|
+
private readonly segments: PowerlineSegments;
|
|
35
|
+
private readonly layout: PowerlineLayout;
|
|
83
36
|
|
|
84
37
|
constructor(private readonly config: PowerlineConfig) {
|
|
85
|
-
this.
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
if (!this._usageProvider) {
|
|
90
|
-
this._usageProvider = new UsageProvider();
|
|
91
|
-
}
|
|
92
|
-
return this._usageProvider;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
private get blockProvider(): BlockProvider {
|
|
96
|
-
if (!this._blockProvider) {
|
|
97
|
-
this._blockProvider = new BlockProvider();
|
|
98
|
-
}
|
|
99
|
-
return this._blockProvider;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
private get todayProvider(): TodayProvider {
|
|
103
|
-
if (!this._todayProvider) {
|
|
104
|
-
this._todayProvider = new TodayProvider();
|
|
105
|
-
}
|
|
106
|
-
return this._todayProvider;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
private get contextProvider(): ContextProvider {
|
|
110
|
-
if (!this._contextProvider) {
|
|
111
|
-
this._contextProvider = new ContextProvider(this.config);
|
|
112
|
-
}
|
|
113
|
-
return this._contextProvider;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
private get gitService(): GitService {
|
|
117
|
-
if (!this._gitService) {
|
|
118
|
-
this._gitService = new GitService();
|
|
119
|
-
}
|
|
120
|
-
return this._gitService;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
private get tmuxService(): TmuxService {
|
|
124
|
-
if (!this._tmuxService) {
|
|
125
|
-
this._tmuxService = new TmuxService();
|
|
126
|
-
}
|
|
127
|
-
return this._tmuxService;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
private get metricsProvider(): MetricsProvider {
|
|
131
|
-
if (!this._metricsProvider) {
|
|
132
|
-
this._metricsProvider = new MetricsProvider();
|
|
133
|
-
}
|
|
134
|
-
return this._metricsProvider;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
private get cacheTimerProvider(): CacheTimerProvider {
|
|
138
|
-
if (!this._cacheTimerProvider) {
|
|
139
|
-
this._cacheTimerProvider = new CacheTimerProvider();
|
|
140
|
-
}
|
|
141
|
-
return this._cacheTimerProvider;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
private get bastraProvider(): BastraProvider {
|
|
145
|
-
if (!this._bastraProvider) {
|
|
146
|
-
this._bastraProvider = new BastraProvider();
|
|
147
|
-
}
|
|
148
|
-
return this._bastraProvider;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
private get segmentRenderer(): SegmentRenderer {
|
|
152
|
-
if (!this._segmentRenderer) {
|
|
153
|
-
this._segmentRenderer = new SegmentRenderer(this.config, this.symbols);
|
|
154
|
-
}
|
|
155
|
-
return this._segmentRenderer;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
private needsSegmentInfo(segmentType: keyof LineConfig["segments"]): boolean {
|
|
159
|
-
return this.config.display.lines.some(
|
|
160
|
-
(line) => line.segments[segmentType]?.enabled,
|
|
161
|
-
);
|
|
38
|
+
this.theme = new PowerlineTheme(config);
|
|
39
|
+
this.symbols = this.theme.initializeSymbols();
|
|
40
|
+
this.segments = new PowerlineSegments(config, this.symbols);
|
|
41
|
+
this.layout = new PowerlineLayout(config, this.symbols, this.theme);
|
|
162
42
|
}
|
|
163
43
|
|
|
164
|
-
async generateStatusline(
|
|
44
|
+
async generateStatusline(rawHookData: ClaudeHookData): Promise<string> {
|
|
45
|
+
const hookData = dropUnreadableRateLimits(rawHookData);
|
|
165
46
|
if (this.config.display.style === "tui") {
|
|
166
47
|
return this.generateTuiStatusline(hookData);
|
|
167
48
|
}
|
|
168
49
|
|
|
169
|
-
const usageInfo = this.needsSegmentInfo("session")
|
|
170
|
-
? await this.usageProvider.getUsageInfo(hookData.session_id, hookData)
|
|
50
|
+
const usageInfo = this.segments.needsSegmentInfo("session")
|
|
51
|
+
? await this.segments.usageProvider.getUsageInfo(hookData.session_id, hookData)
|
|
171
52
|
: null;
|
|
172
53
|
|
|
173
|
-
const blockInfo = this.needsSegmentInfo("block")
|
|
174
|
-
? await this.blockProvider.getActiveBlockInfo(hookData)
|
|
54
|
+
const blockInfo = this.segments.needsSegmentInfo("block")
|
|
55
|
+
? await this.segments.blockProvider.getActiveBlockInfo(hookData)
|
|
175
56
|
: null;
|
|
176
57
|
|
|
177
|
-
const todayInfo = this.needsSegmentInfo("today")
|
|
178
|
-
? await this.todayProvider.getTodayInfo()
|
|
58
|
+
const todayInfo = this.segments.needsSegmentInfo("today")
|
|
59
|
+
? await this.segments.todayProvider.getTodayInfo()
|
|
179
60
|
: null;
|
|
180
61
|
|
|
181
62
|
const contextSegmentConfig = this.config.display.lines
|
|
182
63
|
.map((line) => line.segments.context)
|
|
183
64
|
.find((c) => c?.enabled) as ContextSegmentConfig | undefined;
|
|
184
65
|
const autocompactBuffer = contextSegmentConfig?.autocompactBuffer ?? 33000;
|
|
185
|
-
const contextInfo = this.needsSegmentInfo("context")
|
|
186
|
-
? await this.contextProvider.getContextInfo(hookData, autocompactBuffer)
|
|
66
|
+
const contextInfo = this.segments.needsSegmentInfo("context")
|
|
67
|
+
? await this.segments.contextProvider.getContextInfo(hookData, autocompactBuffer)
|
|
187
68
|
: null;
|
|
188
69
|
|
|
189
|
-
const metricsInfo = this.needsSegmentInfo("metrics")
|
|
190
|
-
? await this.metricsProvider.getMetricsInfo(hookData.session_id, hookData)
|
|
70
|
+
const metricsInfo = this.segments.needsSegmentInfo("metrics")
|
|
71
|
+
? await this.segments.metricsProvider.getMetricsInfo(hookData.session_id, hookData)
|
|
191
72
|
: null;
|
|
192
73
|
|
|
193
|
-
const cacheTimerInfo = this.needsSegmentInfo("cacheTimer")
|
|
194
|
-
? await this.cacheTimerProvider.getCacheTimerInfo(hookData)
|
|
74
|
+
const cacheTimerInfo = this.segments.needsSegmentInfo("cacheTimer")
|
|
75
|
+
? await this.segments.cacheTimerProvider.getCacheTimerInfo(hookData)
|
|
195
76
|
: null;
|
|
196
77
|
|
|
197
78
|
if (this.config.display.autoWrap) {
|
|
@@ -233,7 +114,7 @@ export class PowerlineRenderer {
|
|
|
233
114
|
metricsInfo: MetricsInfo | null,
|
|
234
115
|
cacheTimerInfo: CacheTimerInfo | null,
|
|
235
116
|
): Promise<string> {
|
|
236
|
-
const colors = this.getThemeColors();
|
|
117
|
+
const colors = this.theme.getThemeColors();
|
|
237
118
|
const currentDir = hookData.workspace?.current_dir || hookData.cwd || "/";
|
|
238
119
|
const terminalWidth = getTerminalWidth();
|
|
239
120
|
|
|
@@ -252,7 +133,7 @@ export class PowerlineRenderer {
|
|
|
252
133
|
|
|
253
134
|
const renderedSegments: RenderedSegment[] = [];
|
|
254
135
|
for (const segment of segments) {
|
|
255
|
-
const segmentData = await this.renderSegment(
|
|
136
|
+
const segmentData = await this.segments.renderSegment(
|
|
256
137
|
segment,
|
|
257
138
|
hookData,
|
|
258
139
|
usageInfo,
|
|
@@ -278,40 +159,9 @@ export class PowerlineRenderer {
|
|
|
278
159
|
|
|
279
160
|
if (renderedSegments.length === 0) continue;
|
|
280
161
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
let currentLineSegments: RenderedSegment[] = [];
|
|
287
|
-
let currentLineWidth = 0;
|
|
288
|
-
|
|
289
|
-
for (const segment of renderedSegments) {
|
|
290
|
-
const segmentWidth = this.calculateSegmentWidth(
|
|
291
|
-
segment,
|
|
292
|
-
currentLineSegments.length === 0,
|
|
293
|
-
);
|
|
294
|
-
|
|
295
|
-
if (
|
|
296
|
-
currentLineSegments.length > 0 &&
|
|
297
|
-
currentLineWidth + segmentWidth > terminalWidth
|
|
298
|
-
) {
|
|
299
|
-
outputLines.push(
|
|
300
|
-
this.buildLineFromSegments(currentLineSegments, colors),
|
|
301
|
-
);
|
|
302
|
-
currentLineSegments = [];
|
|
303
|
-
currentLineWidth = 0;
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
currentLineSegments.push(segment);
|
|
307
|
-
currentLineWidth += segmentWidth;
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
if (currentLineSegments.length > 0) {
|
|
311
|
-
outputLines.push(
|
|
312
|
-
this.buildLineFromSegments(currentLineSegments, colors),
|
|
313
|
-
);
|
|
314
|
-
}
|
|
162
|
+
outputLines.push(
|
|
163
|
+
...this.layout.wrapSegments(renderedSegments, terminalWidth, colors),
|
|
164
|
+
);
|
|
315
165
|
}
|
|
316
166
|
|
|
317
167
|
return outputLines.join("\n");
|
|
@@ -320,7 +170,7 @@ export class PowerlineRenderer {
|
|
|
320
170
|
private async generateTuiStatusline(
|
|
321
171
|
hookData: ClaudeHookData,
|
|
322
172
|
): Promise<string> {
|
|
323
|
-
const colors = this.getThemeColors();
|
|
173
|
+
const colors = this.theme.getThemeColors();
|
|
324
174
|
const terminalWidth = getTerminalWidth();
|
|
325
175
|
const currentDir = hookData.workspace?.current_dir || hookData.cwd || "/";
|
|
326
176
|
const charset = this.config.display.charset || "unicode";
|
|
@@ -331,12 +181,12 @@ export class PowerlineRenderer {
|
|
|
331
181
|
const autocompactBuffer = contextSegmentConfig?.autocompactBuffer ?? 33000;
|
|
332
182
|
|
|
333
183
|
const results = await Promise.allSettled([
|
|
334
|
-
this.usageProvider.getUsageInfo(hookData.session_id, hookData),
|
|
335
|
-
this.blockProvider.getActiveBlockInfo(hookData),
|
|
336
|
-
this.todayProvider.getTodayInfo(),
|
|
337
|
-
this.contextProvider.getContextInfo(hookData, autocompactBuffer),
|
|
338
|
-
this.metricsProvider.getMetricsInfo(hookData.session_id, hookData),
|
|
339
|
-
this.gitService.getGitInfo(
|
|
184
|
+
this.segments.usageProvider.getUsageInfo(hookData.session_id, hookData),
|
|
185
|
+
this.segments.blockProvider.getActiveBlockInfo(hookData),
|
|
186
|
+
this.segments.todayProvider.getTodayInfo(),
|
|
187
|
+
this.segments.contextProvider.getContextInfo(hookData, autocompactBuffer),
|
|
188
|
+
this.segments.metricsProvider.getMetricsInfo(hookData.session_id, hookData),
|
|
189
|
+
this.segments.gitService.getGitInfo(
|
|
340
190
|
currentDir,
|
|
341
191
|
{
|
|
342
192
|
showSha: false,
|
|
@@ -350,8 +200,8 @@ export class PowerlineRenderer {
|
|
|
350
200
|
},
|
|
351
201
|
hookData.workspace?.project_dir,
|
|
352
202
|
),
|
|
353
|
-
this.tmuxService.getSessionId(),
|
|
354
|
-
this.cacheTimerProvider.getCacheTimerInfo(hookData),
|
|
203
|
+
this.segments.tmuxService.getSessionId(),
|
|
204
|
+
this.segments.cacheTimerProvider.getCacheTimerInfo(hookData),
|
|
355
205
|
]);
|
|
356
206
|
const val = <T>(r: PromiseSettledResult<T>) =>
|
|
357
207
|
r.status === "fulfilled" ? r.value : null;
|
|
@@ -384,7 +234,7 @@ export class PowerlineRenderer {
|
|
|
384
234
|
metricsInfo,
|
|
385
235
|
gitInfo,
|
|
386
236
|
cacheTimerInfo,
|
|
387
|
-
bastraInfo: this.bastraProvider.getBastraInfo(), // #53: TUI parity
|
|
237
|
+
bastraInfo: this.segments.bastraProvider.getBastraInfo(), // #53: TUI parity
|
|
388
238
|
tmuxSessionId,
|
|
389
239
|
colors,
|
|
390
240
|
};
|
|
@@ -399,58 +249,6 @@ export class PowerlineRenderer {
|
|
|
399
249
|
);
|
|
400
250
|
}
|
|
401
251
|
|
|
402
|
-
private calculateSegmentWidth(
|
|
403
|
-
segment: RenderedSegment,
|
|
404
|
-
isFirst: boolean,
|
|
405
|
-
): number {
|
|
406
|
-
const isCapsuleStyle = this.config.display.style === "capsule";
|
|
407
|
-
const textWidth = visibleLength(segment.text);
|
|
408
|
-
const padding = this.config.display.padding ?? 1;
|
|
409
|
-
const paddingWidth = padding * 2;
|
|
410
|
-
|
|
411
|
-
if (isCapsuleStyle) {
|
|
412
|
-
const capsuleOverhead = 2 + paddingWidth + (isFirst ? 0 : 1);
|
|
413
|
-
return textWidth + capsuleOverhead;
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
const powerlineOverhead = 1 + paddingWidth;
|
|
417
|
-
return textWidth + powerlineOverhead;
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
private buildLineFromSegments(
|
|
421
|
-
segments: RenderedSegment[],
|
|
422
|
-
colors: PowerlineColors,
|
|
423
|
-
): string {
|
|
424
|
-
const isCapsuleStyle = this.config.display.style === "capsule";
|
|
425
|
-
let line = colors.reset;
|
|
426
|
-
|
|
427
|
-
for (let i = 0; i < segments.length; i++) {
|
|
428
|
-
const segment = segments[i];
|
|
429
|
-
if (!segment) continue;
|
|
430
|
-
|
|
431
|
-
const isFirst = i === 0;
|
|
432
|
-
const isLast = i === segments.length - 1;
|
|
433
|
-
const nextSegment = !isLast ? segments[i + 1] : null;
|
|
434
|
-
|
|
435
|
-
if (isCapsuleStyle && !isFirst) {
|
|
436
|
-
line += " ";
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
const bold =
|
|
440
|
-
segment.bold ?? this.getSegmentBoldFlag(segment.type, colors);
|
|
441
|
-
|
|
442
|
-
line += this.formatSegment(
|
|
443
|
-
segment.bgColor,
|
|
444
|
-
segment.fgColor,
|
|
445
|
-
segment.text,
|
|
446
|
-
nextSegment?.bgColor,
|
|
447
|
-
colors,
|
|
448
|
-
bold,
|
|
449
|
-
);
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
return line;
|
|
453
|
-
}
|
|
454
252
|
|
|
455
253
|
private async renderLine(
|
|
456
254
|
lineConfig: LineConfig,
|
|
@@ -462,7 +260,7 @@ export class PowerlineRenderer {
|
|
|
462
260
|
metricsInfo: MetricsInfo | null,
|
|
463
261
|
cacheTimerInfo: CacheTimerInfo | null,
|
|
464
262
|
): Promise<string> {
|
|
465
|
-
const colors = this.getThemeColors();
|
|
263
|
+
const colors = this.theme.getThemeColors();
|
|
466
264
|
const currentDir = hookData.workspace?.current_dir || hookData.cwd || "/";
|
|
467
265
|
|
|
468
266
|
const segments = Object.entries(lineConfig.segments)
|
|
@@ -474,7 +272,7 @@ export class PowerlineRenderer {
|
|
|
474
272
|
|
|
475
273
|
const renderedSegments: RenderedSegment[] = [];
|
|
476
274
|
for (const segment of segments) {
|
|
477
|
-
const segmentData = await this.renderSegment(
|
|
275
|
+
const segmentData = await this.segments.renderSegment(
|
|
478
276
|
segment,
|
|
479
277
|
hookData,
|
|
480
278
|
usageInfo,
|
|
@@ -498,586 +296,6 @@ export class PowerlineRenderer {
|
|
|
498
296
|
}
|
|
499
297
|
}
|
|
500
298
|
|
|
501
|
-
return this.buildLineFromSegments(renderedSegments, colors);
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
private async renderSegment(
|
|
505
|
-
segment: { type: string; config: AnySegmentConfig },
|
|
506
|
-
hookData: ClaudeHookData,
|
|
507
|
-
usageInfo: UsageInfo | null,
|
|
508
|
-
blockInfo: BlockInfo | null,
|
|
509
|
-
todayInfo: TodayInfo | null,
|
|
510
|
-
contextInfo: ContextInfo | null,
|
|
511
|
-
metricsInfo: MetricsInfo | null,
|
|
512
|
-
cacheTimerInfo: CacheTimerInfo | null,
|
|
513
|
-
colors: PowerlineColors,
|
|
514
|
-
currentDir: string,
|
|
515
|
-
) {
|
|
516
|
-
if (segment.type === "directory") {
|
|
517
|
-
return this.segmentRenderer.renderDirectory(
|
|
518
|
-
hookData,
|
|
519
|
-
colors,
|
|
520
|
-
segment.config as DirectorySegmentConfig,
|
|
521
|
-
);
|
|
522
|
-
}
|
|
523
|
-
if (segment.type === "model") {
|
|
524
|
-
return this.segmentRenderer.renderModel(hookData, colors, segment.config);
|
|
525
|
-
}
|
|
526
|
-
|
|
527
|
-
if (segment.type === "git") {
|
|
528
|
-
return await this.renderGitSegment(
|
|
529
|
-
segment.config as GitSegmentConfig,
|
|
530
|
-
hookData,
|
|
531
|
-
colors,
|
|
532
|
-
currentDir,
|
|
533
|
-
);
|
|
534
|
-
}
|
|
535
|
-
|
|
536
|
-
if (segment.type === "session") {
|
|
537
|
-
return this.renderSessionSegment(
|
|
538
|
-
segment.config as UsageSegmentConfig,
|
|
539
|
-
usageInfo,
|
|
540
|
-
colors,
|
|
541
|
-
);
|
|
542
|
-
}
|
|
543
|
-
|
|
544
|
-
if (segment.type === "sessionId") {
|
|
545
|
-
return hookData.session_id
|
|
546
|
-
? this.segmentRenderer.renderSessionId(
|
|
547
|
-
hookData.session_id,
|
|
548
|
-
colors,
|
|
549
|
-
segment.config as SessionIdSegmentConfig,
|
|
550
|
-
)
|
|
551
|
-
: null;
|
|
552
|
-
}
|
|
553
|
-
|
|
554
|
-
if (segment.type === "tmux") {
|
|
555
|
-
return await this.renderTmuxSegment(colors);
|
|
556
|
-
}
|
|
557
|
-
|
|
558
|
-
if (segment.type === "context") {
|
|
559
|
-
return this.renderContextSegment(
|
|
560
|
-
segment.config as ContextSegmentConfig,
|
|
561
|
-
contextInfo,
|
|
562
|
-
colors,
|
|
563
|
-
);
|
|
564
|
-
}
|
|
565
|
-
|
|
566
|
-
if (segment.type === "metrics") {
|
|
567
|
-
return this.renderMetricsSegment(
|
|
568
|
-
segment.config as MetricsSegmentConfig,
|
|
569
|
-
metricsInfo,
|
|
570
|
-
blockInfo,
|
|
571
|
-
colors,
|
|
572
|
-
);
|
|
573
|
-
}
|
|
574
|
-
|
|
575
|
-
if (segment.type === "block") {
|
|
576
|
-
return this.renderBlockSegment(
|
|
577
|
-
segment.config as BlockSegmentConfig,
|
|
578
|
-
blockInfo,
|
|
579
|
-
colors,
|
|
580
|
-
);
|
|
581
|
-
}
|
|
582
|
-
|
|
583
|
-
if (segment.type === "today") {
|
|
584
|
-
return this.renderTodaySegment(
|
|
585
|
-
segment.config as TodaySegmentConfig,
|
|
586
|
-
todayInfo,
|
|
587
|
-
colors,
|
|
588
|
-
);
|
|
589
|
-
}
|
|
590
|
-
|
|
591
|
-
if (segment.type === "version") {
|
|
592
|
-
return this.renderVersionSegment(
|
|
593
|
-
segment.config as VersionSegmentConfig,
|
|
594
|
-
hookData,
|
|
595
|
-
colors,
|
|
596
|
-
);
|
|
597
|
-
}
|
|
598
|
-
|
|
599
|
-
if (segment.type === "env") {
|
|
600
|
-
return this.segmentRenderer.renderEnv(
|
|
601
|
-
colors,
|
|
602
|
-
segment.config as EnvSegmentConfig,
|
|
603
|
-
);
|
|
604
|
-
}
|
|
605
|
-
|
|
606
|
-
if (segment.type === "weekly") {
|
|
607
|
-
return this.segmentRenderer.renderWeekly(
|
|
608
|
-
hookData,
|
|
609
|
-
colors,
|
|
610
|
-
segment.config as WeeklySegmentConfig,
|
|
611
|
-
);
|
|
612
|
-
}
|
|
613
|
-
|
|
614
|
-
if (segment.type === "agent") {
|
|
615
|
-
return this.segmentRenderer.renderAgent(
|
|
616
|
-
hookData,
|
|
617
|
-
colors,
|
|
618
|
-
segment.config as AgentSegmentConfig,
|
|
619
|
-
);
|
|
620
|
-
}
|
|
621
|
-
|
|
622
|
-
if (segment.type === "thinking") {
|
|
623
|
-
return this.segmentRenderer.renderThinking(
|
|
624
|
-
hookData,
|
|
625
|
-
colors,
|
|
626
|
-
segment.config as ThinkingSegmentConfig,
|
|
627
|
-
);
|
|
628
|
-
}
|
|
629
|
-
|
|
630
|
-
if (segment.type === "cacheTimer") {
|
|
631
|
-
if (!cacheTimerInfo) return null;
|
|
632
|
-
return this.segmentRenderer.renderCacheTimer(
|
|
633
|
-
cacheTimerInfo,
|
|
634
|
-
colors,
|
|
635
|
-
segment.config as CacheTimerSegmentConfig,
|
|
636
|
-
);
|
|
637
|
-
}
|
|
638
|
-
|
|
639
|
-
if (segment.type === "bastra") {
|
|
640
|
-
const info = this.bastraProvider.getBastraInfo();
|
|
641
|
-
return this.segmentRenderer.renderBastra(
|
|
642
|
-
info,
|
|
643
|
-
colors,
|
|
644
|
-
segment.config as BastraSegmentConfig,
|
|
645
|
-
);
|
|
646
|
-
}
|
|
647
|
-
|
|
648
|
-
return null;
|
|
649
|
-
}
|
|
650
|
-
|
|
651
|
-
private async renderGitSegment(
|
|
652
|
-
config: GitSegmentConfig,
|
|
653
|
-
hookData: ClaudeHookData,
|
|
654
|
-
colors: PowerlineColors,
|
|
655
|
-
currentDir: string,
|
|
656
|
-
) {
|
|
657
|
-
if (!this.needsSegmentInfo("git")) return null;
|
|
658
|
-
|
|
659
|
-
const gitInfo = await this.gitService.getGitInfo(
|
|
660
|
-
currentDir,
|
|
661
|
-
{
|
|
662
|
-
showSha: config?.showSha,
|
|
663
|
-
showWorkingTree: config?.showWorkingTree,
|
|
664
|
-
showOperation: config?.showOperation,
|
|
665
|
-
showTag: config?.showTag,
|
|
666
|
-
showTimeSinceCommit: config?.showTimeSinceCommit,
|
|
667
|
-
showStashCount: config?.showStashCount,
|
|
668
|
-
showUpstream: config?.showUpstream,
|
|
669
|
-
showRepoName: config?.showRepoName,
|
|
670
|
-
},
|
|
671
|
-
hookData.workspace?.project_dir,
|
|
672
|
-
);
|
|
673
|
-
|
|
674
|
-
return gitInfo
|
|
675
|
-
? this.segmentRenderer.renderGit(gitInfo, colors, config)
|
|
676
|
-
: null;
|
|
677
|
-
}
|
|
678
|
-
|
|
679
|
-
private renderSessionSegment(
|
|
680
|
-
config: UsageSegmentConfig,
|
|
681
|
-
usageInfo: UsageInfo | null,
|
|
682
|
-
colors: PowerlineColors,
|
|
683
|
-
) {
|
|
684
|
-
if (!usageInfo) return null;
|
|
685
|
-
return this.segmentRenderer.renderSession(usageInfo, colors, config);
|
|
686
|
-
}
|
|
687
|
-
|
|
688
|
-
private async renderTmuxSegment(colors: PowerlineColors) {
|
|
689
|
-
if (!this.needsSegmentInfo("tmux")) return null;
|
|
690
|
-
const tmuxSessionId = await this.tmuxService.getSessionId();
|
|
691
|
-
return this.segmentRenderer.renderTmux(tmuxSessionId, colors);
|
|
692
|
-
}
|
|
693
|
-
|
|
694
|
-
private renderContextSegment(
|
|
695
|
-
config: ContextSegmentConfig,
|
|
696
|
-
contextInfo: ContextInfo | null,
|
|
697
|
-
colors: PowerlineColors,
|
|
698
|
-
) {
|
|
699
|
-
if (!this.needsSegmentInfo("context")) return null;
|
|
700
|
-
return this.segmentRenderer.renderContext(contextInfo, colors, config);
|
|
701
|
-
}
|
|
702
|
-
|
|
703
|
-
private renderMetricsSegment(
|
|
704
|
-
config: MetricsSegmentConfig,
|
|
705
|
-
metricsInfo: MetricsInfo | null,
|
|
706
|
-
_blockInfo: BlockInfo | null,
|
|
707
|
-
colors: PowerlineColors,
|
|
708
|
-
) {
|
|
709
|
-
return this.segmentRenderer.renderMetrics(metricsInfo, colors, config);
|
|
710
|
-
}
|
|
711
|
-
|
|
712
|
-
private renderBlockSegment(
|
|
713
|
-
config: BlockSegmentConfig,
|
|
714
|
-
blockInfo: BlockInfo | null,
|
|
715
|
-
colors: PowerlineColors,
|
|
716
|
-
) {
|
|
717
|
-
if (!blockInfo) return null;
|
|
718
|
-
return this.segmentRenderer.renderBlock(blockInfo, colors, config);
|
|
719
|
-
}
|
|
720
|
-
|
|
721
|
-
private renderTodaySegment(
|
|
722
|
-
config: TodaySegmentConfig,
|
|
723
|
-
todayInfo: TodayInfo | null,
|
|
724
|
-
colors: PowerlineColors,
|
|
725
|
-
) {
|
|
726
|
-
if (!todayInfo) return null;
|
|
727
|
-
return this.segmentRenderer.renderToday(todayInfo, colors, config);
|
|
728
|
-
}
|
|
729
|
-
|
|
730
|
-
private renderVersionSegment(
|
|
731
|
-
config: VersionSegmentConfig,
|
|
732
|
-
hookData: ClaudeHookData,
|
|
733
|
-
colors: PowerlineColors,
|
|
734
|
-
) {
|
|
735
|
-
return this.segmentRenderer.renderVersion(hookData, colors, config);
|
|
736
|
-
}
|
|
737
|
-
|
|
738
|
-
private initializeSymbols(): PowerlineSymbols {
|
|
739
|
-
const style = this.config.display.style;
|
|
740
|
-
const charset = this.config.display.charset || "unicode";
|
|
741
|
-
const isMinimalStyle = style === "minimal";
|
|
742
|
-
const isCapsuleStyle = style === "capsule";
|
|
743
|
-
const symbolSet = charset === "text" ? TEXT_SYMBOLS : SYMBOLS;
|
|
744
|
-
|
|
745
|
-
return {
|
|
746
|
-
right: isMinimalStyle
|
|
747
|
-
? ""
|
|
748
|
-
: isCapsuleStyle
|
|
749
|
-
? symbolSet.right_rounded
|
|
750
|
-
: symbolSet.right,
|
|
751
|
-
left: isCapsuleStyle ? symbolSet.left_rounded : "",
|
|
752
|
-
branch: symbolSet.branch,
|
|
753
|
-
model: symbolSet.model,
|
|
754
|
-
git_clean: symbolSet.git_clean,
|
|
755
|
-
git_dirty: symbolSet.git_dirty,
|
|
756
|
-
git_conflicts: symbolSet.git_conflicts,
|
|
757
|
-
git_ahead: symbolSet.git_ahead,
|
|
758
|
-
git_behind: symbolSet.git_behind,
|
|
759
|
-
git_worktree: symbolSet.git_worktree,
|
|
760
|
-
git_tag: symbolSet.git_tag,
|
|
761
|
-
git_sha: symbolSet.git_sha,
|
|
762
|
-
git_upstream: symbolSet.git_upstream,
|
|
763
|
-
git_stash: symbolSet.git_stash,
|
|
764
|
-
git_time: symbolSet.git_time,
|
|
765
|
-
session_cost: symbolSet.session_cost,
|
|
766
|
-
block_cost: symbolSet.block_cost,
|
|
767
|
-
today_cost: symbolSet.today_cost,
|
|
768
|
-
context_time: symbolSet.context_time,
|
|
769
|
-
metrics_response: symbolSet.metrics_response,
|
|
770
|
-
metrics_last_response: symbolSet.metrics_last_response,
|
|
771
|
-
metrics_duration: symbolSet.metrics_duration,
|
|
772
|
-
metrics_messages: symbolSet.metrics_messages,
|
|
773
|
-
metrics_lines_added: symbolSet.metrics_lines_added,
|
|
774
|
-
metrics_lines_removed: symbolSet.metrics_lines_removed,
|
|
775
|
-
metrics_burn: symbolSet.metrics_burn,
|
|
776
|
-
version: symbolSet.version,
|
|
777
|
-
bar_filled: symbolSet.bar_filled,
|
|
778
|
-
bar_empty: symbolSet.bar_empty,
|
|
779
|
-
env: symbolSet.env,
|
|
780
|
-
session_id: symbolSet.session_id,
|
|
781
|
-
weekly_cost: symbolSet.weekly_cost,
|
|
782
|
-
agent: symbolSet.agent,
|
|
783
|
-
thinking: symbolSet.thinking,
|
|
784
|
-
cache_timer: symbolSet.cache_timer,
|
|
785
|
-
bastra: symbolSet.bastra,
|
|
786
|
-
};
|
|
787
|
-
}
|
|
788
|
-
|
|
789
|
-
private getThemeColors(): PowerlineColors {
|
|
790
|
-
const theme = this.config.theme;
|
|
791
|
-
let colorTheme;
|
|
792
|
-
|
|
793
|
-
const colorMode = this.config.display.colorCompatibility || "auto";
|
|
794
|
-
const colorSupport = colorMode === "auto" ? getColorSupport() : colorMode;
|
|
795
|
-
|
|
796
|
-
if (theme === "custom") {
|
|
797
|
-
colorTheme = this.config.colors?.custom;
|
|
798
|
-
if (!colorTheme) {
|
|
799
|
-
throw new Error(
|
|
800
|
-
"Custom theme selected but no colors provided in configuration",
|
|
801
|
-
);
|
|
802
|
-
}
|
|
803
|
-
} else {
|
|
804
|
-
colorTheme = getTheme(theme, colorSupport);
|
|
805
|
-
if (!colorTheme) {
|
|
806
|
-
console.warn(
|
|
807
|
-
`Built-in theme '${theme}' not found, falling back to 'dark' theme`,
|
|
808
|
-
);
|
|
809
|
-
colorTheme = getTheme("dark", colorSupport)!;
|
|
810
|
-
}
|
|
811
|
-
}
|
|
812
|
-
|
|
813
|
-
const convertHex = (hex: string, isBg: boolean): string => {
|
|
814
|
-
if (colorSupport === "none") return "";
|
|
815
|
-
if (colorSupport === "ansi") return hexToBasicAnsi(hex, isBg);
|
|
816
|
-
if (colorSupport === "ansi256") return hexTo256Ansi(hex, isBg);
|
|
817
|
-
return hexToAnsi(hex, isBg);
|
|
818
|
-
};
|
|
819
|
-
|
|
820
|
-
const fallbackTheme = getTheme("dark", colorSupport)!;
|
|
821
|
-
|
|
822
|
-
const isTui = this.config.display.style === "tui";
|
|
823
|
-
const isLightTheme = theme === "light";
|
|
824
|
-
const terminalRef = isLightTheme ? "#f0f0f0" : "#1e1e1e";
|
|
825
|
-
|
|
826
|
-
const getSegmentColors = (segment: Exclude<keyof ColorTheme, "tui">) => {
|
|
827
|
-
const fallback = fallbackTheme[segment];
|
|
828
|
-
const custom = colorTheme[segment];
|
|
829
|
-
const colors = {
|
|
830
|
-
fg: custom?.fg || fallback.fg,
|
|
831
|
-
bg: custom?.bg || fallback.bg,
|
|
832
|
-
};
|
|
833
|
-
|
|
834
|
-
let fgHex = colors.fg;
|
|
835
|
-
if (isTui && hexColorDistance(fgHex, terminalRef) < 60) {
|
|
836
|
-
fgHex = colors.bg;
|
|
837
|
-
}
|
|
838
|
-
|
|
839
|
-
const bold =
|
|
840
|
-
colorSupport !== "none" && Boolean(custom?.bold ?? fallback.bold);
|
|
841
|
-
|
|
842
|
-
return {
|
|
843
|
-
bg: convertHex(colors.bg, true),
|
|
844
|
-
fg: convertHex(fgHex, false),
|
|
845
|
-
bold,
|
|
846
|
-
};
|
|
847
|
-
};
|
|
848
|
-
|
|
849
|
-
const directory = getSegmentColors("directory");
|
|
850
|
-
const git = getSegmentColors("git");
|
|
851
|
-
const model = getSegmentColors("model");
|
|
852
|
-
const session = getSegmentColors("session");
|
|
853
|
-
const block = getSegmentColors("block");
|
|
854
|
-
const today = getSegmentColors("today");
|
|
855
|
-
const tmux = getSegmentColors("tmux");
|
|
856
|
-
const context = getSegmentColors("context");
|
|
857
|
-
const contextWarning = getSegmentColors("contextWarning");
|
|
858
|
-
const contextCritical = getSegmentColors("contextCritical");
|
|
859
|
-
const metrics = getSegmentColors("metrics");
|
|
860
|
-
const version = getSegmentColors("version");
|
|
861
|
-
const env = getSegmentColors("env");
|
|
862
|
-
const weekly = getSegmentColors("weekly");
|
|
863
|
-
const agent = getSegmentColors("agent");
|
|
864
|
-
const thinking = getSegmentColors("thinking");
|
|
865
|
-
const cacheTimer = getSegmentColors("cacheTimer");
|
|
866
|
-
|
|
867
|
-
// bastra brand color — fixed across all themes (not theme-derived), so
|
|
868
|
-
// the bastra segment is always recognizable. White fg on bastra purple.
|
|
869
|
-
const bastra = {
|
|
870
|
-
bg: convertHex("#7c3aed", true),
|
|
871
|
-
fg: convertHex("#ffffff", false),
|
|
872
|
-
bold: colorSupport !== "none",
|
|
873
|
-
};
|
|
874
|
-
|
|
875
|
-
return {
|
|
876
|
-
reset: colorSupport === "none" ? "" : RESET_CODE,
|
|
877
|
-
modeBg: directory.bg,
|
|
878
|
-
modeFg: directory.fg,
|
|
879
|
-
modeBold: directory.bold,
|
|
880
|
-
gitBg: git.bg,
|
|
881
|
-
gitFg: git.fg,
|
|
882
|
-
gitBold: git.bold,
|
|
883
|
-
modelBg: model.bg,
|
|
884
|
-
modelFg: model.fg,
|
|
885
|
-
modelBold: model.bold,
|
|
886
|
-
sessionBg: session.bg,
|
|
887
|
-
sessionFg: session.fg,
|
|
888
|
-
sessionBold: session.bold,
|
|
889
|
-
blockBg: block.bg,
|
|
890
|
-
blockFg: block.fg,
|
|
891
|
-
blockBold: block.bold,
|
|
892
|
-
todayBg: today.bg,
|
|
893
|
-
todayFg: today.fg,
|
|
894
|
-
todayBold: today.bold,
|
|
895
|
-
tmuxBg: tmux.bg,
|
|
896
|
-
tmuxFg: tmux.fg,
|
|
897
|
-
tmuxBold: tmux.bold,
|
|
898
|
-
contextBg: context.bg,
|
|
899
|
-
contextFg: context.fg,
|
|
900
|
-
contextBold: context.bold,
|
|
901
|
-
contextWarningBg: contextWarning.bg,
|
|
902
|
-
contextWarningFg: contextWarning.fg,
|
|
903
|
-
contextWarningBold: contextWarning.bold,
|
|
904
|
-
contextCriticalBg: contextCritical.bg,
|
|
905
|
-
contextCriticalFg: contextCritical.fg,
|
|
906
|
-
contextCriticalBold: contextCritical.bold,
|
|
907
|
-
metricsBg: metrics.bg,
|
|
908
|
-
metricsFg: metrics.fg,
|
|
909
|
-
metricsBold: metrics.bold,
|
|
910
|
-
versionBg: version.bg,
|
|
911
|
-
versionFg: version.fg,
|
|
912
|
-
versionBold: version.bold,
|
|
913
|
-
envBg: env.bg,
|
|
914
|
-
envFg: env.fg,
|
|
915
|
-
envBold: env.bold,
|
|
916
|
-
weeklyBg: weekly.bg,
|
|
917
|
-
weeklyFg: weekly.fg,
|
|
918
|
-
weeklyBold: weekly.bold,
|
|
919
|
-
agentBg: agent.bg,
|
|
920
|
-
agentFg: agent.fg,
|
|
921
|
-
agentBold: agent.bold,
|
|
922
|
-
thinkingBg: thinking.bg,
|
|
923
|
-
thinkingFg: thinking.fg,
|
|
924
|
-
thinkingBold: thinking.bold,
|
|
925
|
-
cacheTimerBg: cacheTimer.bg,
|
|
926
|
-
cacheTimerFg: cacheTimer.fg,
|
|
927
|
-
cacheTimerBold: cacheTimer.bold,
|
|
928
|
-
bastraBg: bastra.bg,
|
|
929
|
-
bastraFg: bastra.fg,
|
|
930
|
-
bastraBold: bastra.bold,
|
|
931
|
-
partFg: theme === "custom" ? this.resolvePartColors(convertHex) : {},
|
|
932
|
-
};
|
|
933
|
-
}
|
|
934
|
-
|
|
935
|
-
private resolvePartColors(
|
|
936
|
-
convertHex: (hex: string, isBg: boolean) => string,
|
|
937
|
-
): Record<string, string> {
|
|
938
|
-
const custom = this.config.colors?.custom as
|
|
939
|
-
| Record<string, { fg?: string }>
|
|
940
|
-
| undefined;
|
|
941
|
-
if (!custom) return {};
|
|
942
|
-
|
|
943
|
-
const result: Record<string, string> = {};
|
|
944
|
-
for (const key of Object.keys(custom)) {
|
|
945
|
-
const entry = custom[key];
|
|
946
|
-
if (!entry?.fg) continue;
|
|
947
|
-
result[key] = convertHex(entry.fg, false);
|
|
948
|
-
}
|
|
949
|
-
return result;
|
|
950
|
-
}
|
|
951
|
-
|
|
952
|
-
private getSegmentBgColor(
|
|
953
|
-
segmentType: string,
|
|
954
|
-
colors: PowerlineColors,
|
|
955
|
-
): string {
|
|
956
|
-
switch (segmentType) {
|
|
957
|
-
case "directory":
|
|
958
|
-
return colors.modeBg;
|
|
959
|
-
case "git":
|
|
960
|
-
return colors.gitBg;
|
|
961
|
-
case "model":
|
|
962
|
-
return colors.modelBg;
|
|
963
|
-
case "session":
|
|
964
|
-
case "sessionId":
|
|
965
|
-
return colors.sessionBg;
|
|
966
|
-
case "block":
|
|
967
|
-
return colors.blockBg;
|
|
968
|
-
case "today":
|
|
969
|
-
return colors.todayBg;
|
|
970
|
-
case "tmux":
|
|
971
|
-
return colors.tmuxBg;
|
|
972
|
-
case "context":
|
|
973
|
-
return colors.contextBg;
|
|
974
|
-
case "metrics":
|
|
975
|
-
return colors.metricsBg;
|
|
976
|
-
case "version":
|
|
977
|
-
return colors.versionBg;
|
|
978
|
-
case "env":
|
|
979
|
-
return colors.envBg;
|
|
980
|
-
case "weekly":
|
|
981
|
-
return colors.weeklyBg;
|
|
982
|
-
case "agent":
|
|
983
|
-
return colors.agentBg;
|
|
984
|
-
case "thinking":
|
|
985
|
-
return colors.thinkingBg;
|
|
986
|
-
case "cacheTimer":
|
|
987
|
-
return colors.cacheTimerBg;
|
|
988
|
-
case "bastra":
|
|
989
|
-
return colors.bastraBg;
|
|
990
|
-
default:
|
|
991
|
-
return colors.modeBg;
|
|
992
|
-
}
|
|
993
|
-
}
|
|
994
|
-
|
|
995
|
-
private getSegmentBoldFlag(
|
|
996
|
-
segmentType: string,
|
|
997
|
-
colors: PowerlineColors,
|
|
998
|
-
): boolean {
|
|
999
|
-
switch (segmentType) {
|
|
1000
|
-
case "directory":
|
|
1001
|
-
return colors.modeBold;
|
|
1002
|
-
case "git":
|
|
1003
|
-
return colors.gitBold;
|
|
1004
|
-
case "model":
|
|
1005
|
-
return colors.modelBold;
|
|
1006
|
-
case "session":
|
|
1007
|
-
case "sessionId":
|
|
1008
|
-
return colors.sessionBold;
|
|
1009
|
-
case "block":
|
|
1010
|
-
return colors.blockBold;
|
|
1011
|
-
case "today":
|
|
1012
|
-
return colors.todayBold;
|
|
1013
|
-
case "tmux":
|
|
1014
|
-
return colors.tmuxBold;
|
|
1015
|
-
case "context":
|
|
1016
|
-
return colors.contextBold;
|
|
1017
|
-
case "metrics":
|
|
1018
|
-
return colors.metricsBold;
|
|
1019
|
-
case "version":
|
|
1020
|
-
return colors.versionBold;
|
|
1021
|
-
case "env":
|
|
1022
|
-
return colors.envBold;
|
|
1023
|
-
case "weekly":
|
|
1024
|
-
return colors.weeklyBold;
|
|
1025
|
-
case "agent":
|
|
1026
|
-
return colors.agentBold;
|
|
1027
|
-
case "thinking":
|
|
1028
|
-
return colors.thinkingBold;
|
|
1029
|
-
case "cacheTimer":
|
|
1030
|
-
return colors.cacheTimerBold;
|
|
1031
|
-
case "bastra":
|
|
1032
|
-
return colors.bastraBold;
|
|
1033
|
-
default:
|
|
1034
|
-
return colors.modeBold;
|
|
1035
|
-
}
|
|
1036
|
-
}
|
|
1037
|
-
|
|
1038
|
-
private formatSegment(
|
|
1039
|
-
bgColor: string,
|
|
1040
|
-
fgColor: string,
|
|
1041
|
-
text: string,
|
|
1042
|
-
nextBgColor: string | undefined,
|
|
1043
|
-
colors: PowerlineColors,
|
|
1044
|
-
bold: boolean,
|
|
1045
|
-
): string {
|
|
1046
|
-
const isCapsuleStyle = this.config.display.style === "capsule";
|
|
1047
|
-
const padding = " ".repeat(this.config.display.padding ?? 1);
|
|
1048
|
-
const useBold = bold && colors.reset !== "";
|
|
1049
|
-
const boldOn = useBold ? "\x1b[1m" : "";
|
|
1050
|
-
const boldOff = useBold ? "\x1b[22m" : "";
|
|
1051
|
-
|
|
1052
|
-
if (isCapsuleStyle) {
|
|
1053
|
-
const colorMode = this.config.display.colorCompatibility || "auto";
|
|
1054
|
-
const colorSupport = colorMode === "auto" ? getColorSupport() : colorMode;
|
|
1055
|
-
const isBasicMode = colorSupport === "ansi";
|
|
1056
|
-
|
|
1057
|
-
const capFgColor = extractBgToFg(bgColor, isBasicMode);
|
|
1058
|
-
|
|
1059
|
-
const leftCap = `${capFgColor}${this.symbols.left}${colors.reset}`;
|
|
1060
|
-
|
|
1061
|
-
const content = `${bgColor}${fgColor}${boldOn}${padding}${text}${padding}${boldOff}${colors.reset}`;
|
|
1062
|
-
|
|
1063
|
-
const rightCap = `${capFgColor}${this.symbols.right}${colors.reset}`;
|
|
1064
|
-
|
|
1065
|
-
return `${leftCap}${content}${rightCap}`;
|
|
1066
|
-
}
|
|
1067
|
-
|
|
1068
|
-
let output = `${bgColor}${fgColor}${boldOn}${padding}${text}${padding}${boldOff}`;
|
|
1069
|
-
|
|
1070
|
-
const colorMode = this.config.display.colorCompatibility || "auto";
|
|
1071
|
-
const colorSupport = colorMode === "auto" ? getColorSupport() : colorMode;
|
|
1072
|
-
const isBasicMode = colorSupport === "ansi";
|
|
1073
|
-
|
|
1074
|
-
if (nextBgColor) {
|
|
1075
|
-
const arrowFgColor = extractBgToFg(bgColor, isBasicMode);
|
|
1076
|
-
output += `${colors.reset}${nextBgColor}${arrowFgColor}${this.symbols.right}`;
|
|
1077
|
-
} else {
|
|
1078
|
-
output += `${colors.reset}${extractBgToFg(bgColor, isBasicMode)}${this.symbols.right}${colors.reset}`;
|
|
1079
|
-
}
|
|
1080
|
-
|
|
1081
|
-
return output;
|
|
299
|
+
return this.layout.buildLineFromSegments(renderedSegments, colors);
|
|
1082
300
|
}
|
|
1083
301
|
}
|