@promptctl/rich-js 0.15.0 → 0.16.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.
@@ -67,7 +67,7 @@ export declare class Strip<T extends StyledRenderable = StyledRenderable> implem
67
67
  */
68
68
  export declare const SEAM_MIN_DELTA_E = 0.04;
69
69
  export interface PowerlineJoinerOptions {
70
- /** Glyph used for every join. */
70
+ /** Glyph for every join between two coloured items. */
71
71
  glyph: string;
72
72
  /**
73
73
  * Glyph drawn between neighbours whose backgrounds the eye cannot tell apart,
@@ -75,12 +75,30 @@ export interface PowerlineJoinerOptions {
75
75
  * shared background.
76
76
  */
77
77
  divider: string;
78
+ /**
79
+ * Glyph for every join a coloured item is entered from nothing — the strip's
80
+ * start, or a colourless left neighbour — painted in the right item's
81
+ * background. `""` begins a coloured run flat.
82
+ */
83
+ lead: string;
84
+ /**
85
+ * Glyph for every join a coloured item leaves into nothing — the strip's end,
86
+ * or a colourless right neighbour — painted in the left item's background.
87
+ * `""` ends a coloured run flat.
88
+ */
89
+ tail: string;
78
90
  }
79
- /** The powerline pair: U+E0B0 (right-arrow) divided by U+E0B1 (thin right-arrow). */
91
+ /**
92
+ * The powerline set: U+E0B0 (right-arrow) divided by U+E0B1 (thin right-arrow),
93
+ * led by U+E0B2 (left-arrow) and tailed by the arrow itself — so a strip's two
94
+ * ends are one shape.
95
+ */
80
96
  export declare const POWERLINE_JOINER_GLYPHS: Readonly<PowerlineJoinerOptions>;
81
97
  export declare class PowerlineJoiner<T extends StyledRenderable = StyledRenderable> implements Joiner<T> {
82
98
  private readonly _glyph;
83
99
  private readonly _divider;
100
+ private readonly _lead;
101
+ private readonly _tail;
84
102
  constructor(options?: PowerlineJoinerOptions);
85
103
  join(left: T | null, right: T | null): Renderable;
86
104
  }
@@ -101,6 +101,18 @@ function bgAsFg(edge) {
101
101
  function paintableBg(bg) {
102
102
  return bg !== undefined && !bg.isDefault ? bg : undefined;
103
103
  }
104
+ // A cap or arrow is its cell continuing: that cell's ground as the writer draws
105
+ // it, so a translucent ground is not composited a second time over whatever it
106
+ // enters.
107
+ function drawnGround(bg) {
108
+ return new Style({ bgcolor: bg }).drawnColors().bgcolor;
109
+ }
110
+ // A cap is its glyph in its cell's ground, and "" is a flat end: no glyph, so
111
+ // no segment — the same output as a join with nothing to paint.
112
+ function* cap(glyph, bg) {
113
+ if (glyph !== "")
114
+ yield new Segment(glyph, new Style({ color: drawnGround(bg) }));
115
+ }
104
116
  // --- PowerlineJoiner ---
105
117
  /**
106
118
  * The least ΔE_OK two neighbouring backgrounds must differ by for the powerline
@@ -130,27 +142,42 @@ function vanishes(arrow, colorSystem) {
130
142
  ? Oklch.fromRgba(av).deltaE(Oklch.fromRgba(bv)) < SEAM_MIN_DELTA_E
131
143
  : color.number === bgcolor.number;
132
144
  }
133
- /** The powerline pair: U+E0B0 (right-arrow) divided by U+E0B1 (thin right-arrow). */
134
- export const POWERLINE_JOINER_GLYPHS = Object.freeze({ glyph: "\ue0b0", divider: "\ue0b1" });
145
+ /**
146
+ * The powerline set: U+E0B0 (right-arrow) divided by U+E0B1 (thin right-arrow),
147
+ * led by U+E0B2 (left-arrow) and tailed by the arrow itself — so a strip's two
148
+ * ends are one shape.
149
+ */
150
+ export const POWERLINE_JOINER_GLYPHS = Object.freeze({
151
+ glyph: "\ue0b0",
152
+ divider: "\ue0b1",
153
+ lead: "\ue0b2",
154
+ tail: "\ue0b0",
155
+ });
135
156
  export class PowerlineJoiner {
136
157
  _glyph;
137
158
  _divider;
159
+ _lead;
160
+ _tail;
138
161
  constructor(options = POWERLINE_JOINER_GLYPHS) {
139
162
  this._glyph = options.glyph;
140
163
  this._divider = options.divider;
164
+ this._lead = options.lead;
165
+ this._tail = options.tail;
141
166
  }
142
167
  join(left, right) {
143
- // [LAW:dataflow-not-control-flow] One expression for all three positions
144
- // (start cap, mid-join, end cap). The powerline separator is painted in the
145
- // LEFT edge's bg — the colour bleeding rightward — over the RIGHT edge's bg.
146
- // The endpoints are not control-flow special cases; they are the DATA cases
168
+ // [LAW:dataflow-not-control-flow] One table for all three positions (start
169
+ // cap, mid-join, end cap), read off which side has a colour to paint. The
170
+ // endpoints are not control-flow special cases; they are the DATA cases
147
171
  // where a neighbour (hence its bg) is absent:
148
- // • no left bg — the start cap, OR a left item with no background — has no
149
- // colour to bleed, so there is no separator to paint and the join
150
- // yields nothing. (This matches vim-airline / tmux-powerline: a
151
- // colourless arrow is not drawn.)
152
- // • no right bg — the end cap — bleeds the left colour out over the
153
- // terminal background (fg = left bg, no bg).
172
+ // • both bgs — the arrow in the LEFT bg (the colour bleeding rightward)
173
+ // over the RIGHT bg.
174
+ // • left bg only — the end cap, OR a coloured item before a colourless
175
+ // one — the tail bleeds the left colour out over the terminal
176
+ // background (fg = left bg, no bg).
177
+ // • right bg only — the start cap, OR a colourless item before a coloured
178
+ // one — the lead: the right colour reaching back over the terminal
179
+ // background (fg = right bg, no bg).
180
+ // • neither — nothing to paint, so the join yields nothing.
154
181
  // Equal REAL bgs still emit: a same-bg seam between two distinct items is a
155
182
  // structural boundary, never suppressed. The arrow would be drawn in its own
156
183
  // background colour there and vanish, so the seam is the DIVIDER instead, in
@@ -165,17 +192,22 @@ export class PowerlineJoiner {
165
192
  // both to undefined so an explicit `… on default` cannot smuggle a separator.
166
193
  const glyph = this._glyph;
167
194
  const divider = this._divider;
195
+ const lead = this._lead;
196
+ const tail = this._tail;
168
197
  return deferred(function* (options) {
169
198
  const leftEdge = left?.edgeStyle("right", options);
170
199
  const leftBg = paintableBg(leftEdge?.bgcolor);
171
- if (leftBg === undefined)
172
- return;
173
200
  const rightBg = paintableBg(right?.edgeStyle("left", options).bgcolor);
174
- // The arrow is the left cell continuing: its ground as the writer draws
175
- // it, so a translucent ground is not composited a second time over the
176
- // right one.
177
- const leftDrawn = new Style({ bgcolor: leftBg }).drawnColors().bgcolor;
178
- const arrow = new Style({ color: leftDrawn, bgcolor: rightBg });
201
+ if (leftBg === undefined) {
202
+ if (rightBg !== undefined)
203
+ yield* cap(lead, rightBg);
204
+ return;
205
+ }
206
+ if (rightBg === undefined) {
207
+ yield* cap(tail, leftBg);
208
+ return;
209
+ }
210
+ const arrow = new Style({ color: drawnGround(leftBg), bgcolor: rightBg });
179
211
  // The divider is the left item's text on the left item's own ground,
180
212
  // so it reads exactly as well as that item's text does, at any depth.
181
213
  yield vanishes(arrow, options.colorSystem)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@promptctl/rich-js",
3
- "version": "0.15.0",
3
+ "version": "0.16.0",
4
4
  "description": "Rich text and beautiful formatting in the terminal — a TypeScript port of Python's Rich",
5
5
  "type": "module",
6
6
  "sideEffects": false,