@oakoliver/lipgloss 1.0.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/LICENSE +24 -0
- package/README.md +259 -0
- package/dist/ansi.d.ts +82 -0
- package/dist/ansi.d.ts.map +1 -0
- package/dist/border.d.ts +54 -0
- package/dist/border.d.ts.map +1 -0
- package/dist/color.d.ts +86 -0
- package/dist/color.d.ts.map +1 -0
- package/dist/index.cjs +2408 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2309 -0
- package/dist/layout.d.ts +28 -0
- package/dist/layout.d.ts.map +1 -0
- package/dist/style.d.ts +247 -0
- package/dist/style.d.ts.map +1 -0
- package/package.json +70 -0
- package/src/ansi.ts +292 -0
- package/src/border.ts +168 -0
- package/src/color.ts +294 -0
- package/src/index.ts +44 -0
- package/src/layout.ts +206 -0
- package/src/style.ts +1131 -0
package/dist/layout.d.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Layout utilities: JoinHorizontal, JoinVertical, Place, PlaceHorizontal, PlaceVertical.
|
|
3
|
+
* Ported from charmbracelet/lipgloss join.go and position.go.
|
|
4
|
+
*/
|
|
5
|
+
import type { Position } from './style.js';
|
|
6
|
+
/**
|
|
7
|
+
* Horizontally join multi-line strings along a vertical axis.
|
|
8
|
+
* `pos` is the vertical alignment: 0 = top, 0.5 = center, 1 = bottom.
|
|
9
|
+
*/
|
|
10
|
+
export declare function joinHorizontal(pos: Position, ...strs: string[]): string;
|
|
11
|
+
/**
|
|
12
|
+
* Vertically join multi-line strings along a horizontal axis.
|
|
13
|
+
* `pos` is the horizontal alignment: 0 = left, 0.5 = center, 1 = right.
|
|
14
|
+
*/
|
|
15
|
+
export declare function joinVertical(pos: Position, ...strs: string[]): string;
|
|
16
|
+
/**
|
|
17
|
+
* Place a string in an unstyled box of given width and height.
|
|
18
|
+
*/
|
|
19
|
+
export declare function place(width: number, height: number, hPos: Position, vPos: Position, str: string): string;
|
|
20
|
+
/**
|
|
21
|
+
* Place a string horizontally in an unstyled block of given width.
|
|
22
|
+
*/
|
|
23
|
+
export declare function placeHorizontal(width: number, pos: Position, str: string): string;
|
|
24
|
+
/**
|
|
25
|
+
* Place a string vertically in an unstyled block of given height.
|
|
26
|
+
*/
|
|
27
|
+
export declare function placeVertical(height: number, pos: Position, str: string): string;
|
|
28
|
+
//# sourceMappingURL=layout.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"layout.d.ts","sourceRoot":"","sources":["../src/layout.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAO3C;;;GAGG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,QAAQ,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,CAuDvE;AAMD;;;GAGG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,QAAQ,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,CAwCrE;AAMD;;GAEG;AACH,wBAAgB,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAExG;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CA0BjF;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAmChF"}
|
package/dist/style.d.ts
ADDED
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Style — the core of lipgloss. Immutable fluent builder for terminal styling.
|
|
3
|
+
* Every setter returns a new Style instance (value-type semantics).
|
|
4
|
+
*/
|
|
5
|
+
import type { UnderlineStyle } from './ansi.js';
|
|
6
|
+
import type { Color } from './color.js';
|
|
7
|
+
import type { Border } from './border.js';
|
|
8
|
+
/** 0.0 = top/left, 0.5 = center, 1.0 = bottom/right */
|
|
9
|
+
export type Position = number;
|
|
10
|
+
export declare const Top: Position;
|
|
11
|
+
export declare const Bottom: Position;
|
|
12
|
+
export declare const Center: Position;
|
|
13
|
+
export declare const Left: Position;
|
|
14
|
+
export declare const Right: Position;
|
|
15
|
+
/** Split string into lines and find the widest line's visible width. */
|
|
16
|
+
export declare function getLines(s: string): {
|
|
17
|
+
lines: string[];
|
|
18
|
+
widest: number;
|
|
19
|
+
};
|
|
20
|
+
/** Get first character of a string as a string (for corners). */
|
|
21
|
+
export declare function getFirstRune(s: string): string;
|
|
22
|
+
export declare class Style {
|
|
23
|
+
private _set;
|
|
24
|
+
private _value;
|
|
25
|
+
private _bold;
|
|
26
|
+
private _italic;
|
|
27
|
+
private _strikethrough;
|
|
28
|
+
private _reverse;
|
|
29
|
+
private _blink;
|
|
30
|
+
private _faint;
|
|
31
|
+
private _underlineSpaces;
|
|
32
|
+
private _strikethroughSpaces;
|
|
33
|
+
private _colorWhitespace;
|
|
34
|
+
private _underlineStyle;
|
|
35
|
+
private _fg;
|
|
36
|
+
private _bg;
|
|
37
|
+
private _ulColor;
|
|
38
|
+
private _width;
|
|
39
|
+
private _height;
|
|
40
|
+
private _maxWidth;
|
|
41
|
+
private _maxHeight;
|
|
42
|
+
private _alignH;
|
|
43
|
+
private _alignV;
|
|
44
|
+
private _paddingTop;
|
|
45
|
+
private _paddingRight;
|
|
46
|
+
private _paddingBottom;
|
|
47
|
+
private _paddingLeft;
|
|
48
|
+
private _marginTop;
|
|
49
|
+
private _marginRight;
|
|
50
|
+
private _marginBottom;
|
|
51
|
+
private _marginLeft;
|
|
52
|
+
private _marginBg;
|
|
53
|
+
private _borderStyle;
|
|
54
|
+
private _borderTop;
|
|
55
|
+
private _borderRight;
|
|
56
|
+
private _borderBottom;
|
|
57
|
+
private _borderLeft;
|
|
58
|
+
private _borderTopFg;
|
|
59
|
+
private _borderRightFg;
|
|
60
|
+
private _borderBottomFg;
|
|
61
|
+
private _borderLeftFg;
|
|
62
|
+
private _borderTopBg;
|
|
63
|
+
private _borderRightBg;
|
|
64
|
+
private _borderBottomBg;
|
|
65
|
+
private _borderLeftBg;
|
|
66
|
+
private _inline;
|
|
67
|
+
private _tabWidth;
|
|
68
|
+
private _transform;
|
|
69
|
+
private _link;
|
|
70
|
+
private _linkParams;
|
|
71
|
+
private _paddingChar;
|
|
72
|
+
/** Clone this style into a new instance. */
|
|
73
|
+
private _clone;
|
|
74
|
+
setString(...strs: string[]): Style;
|
|
75
|
+
bold(v: boolean): Style;
|
|
76
|
+
italic(v: boolean): Style;
|
|
77
|
+
strikethrough(v: boolean): Style;
|
|
78
|
+
reverse(v: boolean): Style;
|
|
79
|
+
blink(v: boolean): Style;
|
|
80
|
+
faint(v: boolean): Style;
|
|
81
|
+
underline(v: boolean): Style;
|
|
82
|
+
underlineStyle(u: UnderlineStyle): Style;
|
|
83
|
+
foreground(c: Color): Style;
|
|
84
|
+
background(c: Color): Style;
|
|
85
|
+
underlineColor(c: Color): Style;
|
|
86
|
+
width(n: number): Style;
|
|
87
|
+
height(n: number): Style;
|
|
88
|
+
maxWidth(n: number): Style;
|
|
89
|
+
maxHeight(n: number): Style;
|
|
90
|
+
align(...pos: Position[]): Style;
|
|
91
|
+
alignHorizontal(p: Position): Style;
|
|
92
|
+
alignVertical(p: Position): Style;
|
|
93
|
+
padding(...args: number[]): Style;
|
|
94
|
+
paddingTop(n: number): Style;
|
|
95
|
+
paddingRight(n: number): Style;
|
|
96
|
+
paddingBottom(n: number): Style;
|
|
97
|
+
paddingLeft(n: number): Style;
|
|
98
|
+
margin(...args: number[]): Style;
|
|
99
|
+
marginTop(n: number): Style;
|
|
100
|
+
marginRight(n: number): Style;
|
|
101
|
+
marginBottom(n: number): Style;
|
|
102
|
+
marginLeft(n: number): Style;
|
|
103
|
+
marginBackground(c: Color): Style;
|
|
104
|
+
border(b: Border, ...sides: boolean[]): Style;
|
|
105
|
+
borderStyle(b: Border): Style;
|
|
106
|
+
borderTop(v: boolean): Style;
|
|
107
|
+
borderRight(v: boolean): Style;
|
|
108
|
+
borderBottom(v: boolean): Style;
|
|
109
|
+
borderLeft(v: boolean): Style;
|
|
110
|
+
borderForeground(...colors: Color[]): Style;
|
|
111
|
+
borderTopForeground(c: Color): Style;
|
|
112
|
+
borderRightForeground(c: Color): Style;
|
|
113
|
+
borderBottomForeground(c: Color): Style;
|
|
114
|
+
borderLeftForeground(c: Color): Style;
|
|
115
|
+
borderBackground(...colors: Color[]): Style;
|
|
116
|
+
borderTopBackground(c: Color): Style;
|
|
117
|
+
borderRightBackground(c: Color): Style;
|
|
118
|
+
borderBottomBackground(c: Color): Style;
|
|
119
|
+
borderLeftBackground(c: Color): Style;
|
|
120
|
+
inline(v: boolean): Style;
|
|
121
|
+
tabWidth(n: number): Style;
|
|
122
|
+
transform(fn: (s: string) => string): Style;
|
|
123
|
+
hyperlink(url: string, params?: string): Style;
|
|
124
|
+
underlineSpaces(v: boolean): Style;
|
|
125
|
+
strikethroughSpaces(v: boolean): Style;
|
|
126
|
+
colorWhitespace(v: boolean): Style;
|
|
127
|
+
paddingChar(ch: string): Style;
|
|
128
|
+
copy(): Style;
|
|
129
|
+
unsetBold(): Style;
|
|
130
|
+
unsetItalic(): Style;
|
|
131
|
+
unsetUnderline(): Style;
|
|
132
|
+
unsetUnderlineSpaces(): Style;
|
|
133
|
+
unsetStrikethrough(): Style;
|
|
134
|
+
unsetStrikethroughSpaces(): Style;
|
|
135
|
+
unsetReverse(): Style;
|
|
136
|
+
unsetBlink(): Style;
|
|
137
|
+
unsetFaint(): Style;
|
|
138
|
+
unsetInline(): Style;
|
|
139
|
+
unsetForeground(): Style;
|
|
140
|
+
unsetBackground(): Style;
|
|
141
|
+
unsetUnderlineColor(): Style;
|
|
142
|
+
unsetWidth(): Style;
|
|
143
|
+
unsetHeight(): Style;
|
|
144
|
+
unsetMaxWidth(): Style;
|
|
145
|
+
unsetMaxHeight(): Style;
|
|
146
|
+
unsetPaddingTop(): Style;
|
|
147
|
+
unsetPaddingRight(): Style;
|
|
148
|
+
unsetPaddingBottom(): Style;
|
|
149
|
+
unsetPaddingLeft(): Style;
|
|
150
|
+
unsetPaddingChar(): Style;
|
|
151
|
+
unsetMarginTop(): Style;
|
|
152
|
+
unsetMarginRight(): Style;
|
|
153
|
+
unsetMarginBottom(): Style;
|
|
154
|
+
unsetMarginLeft(): Style;
|
|
155
|
+
unsetBorderTop(): Style;
|
|
156
|
+
unsetBorderRight(): Style;
|
|
157
|
+
unsetBorderBottom(): Style;
|
|
158
|
+
unsetBorderLeft(): Style;
|
|
159
|
+
unsetBorderStyle(): Style;
|
|
160
|
+
unsetTabWidth(): Style;
|
|
161
|
+
unsetTransform(): Style;
|
|
162
|
+
unsetHyperlink(): Style;
|
|
163
|
+
unsetColorWhitespace(): Style;
|
|
164
|
+
getBold(): boolean;
|
|
165
|
+
getItalic(): boolean;
|
|
166
|
+
getUnderline(): boolean;
|
|
167
|
+
getUnderlineStyle(): UnderlineStyle;
|
|
168
|
+
getStrikethrough(): boolean;
|
|
169
|
+
getReverse(): boolean;
|
|
170
|
+
getBlink(): boolean;
|
|
171
|
+
getFaint(): boolean;
|
|
172
|
+
getForeground(): Color;
|
|
173
|
+
getBackground(): Color;
|
|
174
|
+
getUnderlineColor(): Color;
|
|
175
|
+
getWidth(): number;
|
|
176
|
+
getHeight(): number;
|
|
177
|
+
getMaxWidth(): number;
|
|
178
|
+
getMaxHeight(): number;
|
|
179
|
+
getAlignHorizontal(): Position;
|
|
180
|
+
getAlignVertical(): Position;
|
|
181
|
+
getInline(): boolean;
|
|
182
|
+
getTabWidth(): number;
|
|
183
|
+
getUnderlineSpaces(): boolean;
|
|
184
|
+
getStrikethroughSpaces(): boolean;
|
|
185
|
+
getColorWhitespace(): boolean;
|
|
186
|
+
getTransform(): ((s: string) => string) | null;
|
|
187
|
+
getPaddingChar(): string;
|
|
188
|
+
getHyperlink(): {
|
|
189
|
+
link: string;
|
|
190
|
+
params: string;
|
|
191
|
+
};
|
|
192
|
+
getPadding(): {
|
|
193
|
+
top: number;
|
|
194
|
+
right: number;
|
|
195
|
+
bottom: number;
|
|
196
|
+
left: number;
|
|
197
|
+
};
|
|
198
|
+
getPaddingTop(): number;
|
|
199
|
+
getPaddingRight(): number;
|
|
200
|
+
getPaddingBottom(): number;
|
|
201
|
+
getPaddingLeft(): number;
|
|
202
|
+
getHorizontalPadding(): number;
|
|
203
|
+
getVerticalPadding(): number;
|
|
204
|
+
getMargin(): {
|
|
205
|
+
top: number;
|
|
206
|
+
right: number;
|
|
207
|
+
bottom: number;
|
|
208
|
+
left: number;
|
|
209
|
+
};
|
|
210
|
+
getMarginTop(): number;
|
|
211
|
+
getMarginRight(): number;
|
|
212
|
+
getMarginBottom(): number;
|
|
213
|
+
getMarginLeft(): number;
|
|
214
|
+
getHorizontalMargins(): number;
|
|
215
|
+
getVerticalMargins(): number;
|
|
216
|
+
getBorderStyle(): Border;
|
|
217
|
+
getBorderTop(): boolean;
|
|
218
|
+
getBorderRight(): boolean;
|
|
219
|
+
getBorderBottom(): boolean;
|
|
220
|
+
getBorderLeft(): boolean;
|
|
221
|
+
/** True when border style is set but no individual side bools are set. */
|
|
222
|
+
private _isBorderStyleSetWithoutSides;
|
|
223
|
+
getBorderTopSize(): number;
|
|
224
|
+
getBorderRightSize(): number;
|
|
225
|
+
getBorderBottomSize(): number;
|
|
226
|
+
getBorderLeftSize(): number;
|
|
227
|
+
getHorizontalBorderSize(): number;
|
|
228
|
+
getVerticalBorderSize(): number;
|
|
229
|
+
getHorizontalFrameSize(): number;
|
|
230
|
+
getVerticalFrameSize(): number;
|
|
231
|
+
getFrameSize(): {
|
|
232
|
+
x: number;
|
|
233
|
+
y: number;
|
|
234
|
+
};
|
|
235
|
+
/** Copy explicitly-set values from `other` that are NOT set on this style. Margins/padding are not inherited. */
|
|
236
|
+
inherit(other: Style): Style;
|
|
237
|
+
private _keyToField;
|
|
238
|
+
/** Render the style applied to the given strings (joined with space). */
|
|
239
|
+
render(...strs: string[]): string;
|
|
240
|
+
private _maybeConvertTabs;
|
|
241
|
+
private _applyBorder;
|
|
242
|
+
private _applyMargins;
|
|
243
|
+
toString(): string;
|
|
244
|
+
}
|
|
245
|
+
/** Create a new empty Style. */
|
|
246
|
+
export declare function newStyle(): Style;
|
|
247
|
+
//# sourceMappingURL=style.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"style.d.ts","sourceRoot":"","sources":["../src/style.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@oakoliver/lipgloss",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "CSS-like terminal styling for JavaScript. Zero dependencies, multi-runtime (Node.js, Bun, Deno). Fluent API for colors, borders, padding, margins, alignment, and layout.",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"module": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"type": "module",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js",
|
|
13
|
+
"require": "./dist/index.cjs"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist",
|
|
18
|
+
"src"
|
|
19
|
+
],
|
|
20
|
+
"scripts": {
|
|
21
|
+
"build": "npm run build:esm && npm run build:cjs && npm run build:types",
|
|
22
|
+
"build:esm": "esbuild src/index.ts --bundle --format=esm --outfile=dist/index.js --platform=node",
|
|
23
|
+
"build:cjs": "esbuild src/index.ts --bundle --format=cjs --outfile=dist/index.cjs --platform=node",
|
|
24
|
+
"build:types": "tsc --declaration --emitDeclarationOnly --outDir dist",
|
|
25
|
+
"typecheck": "tsc --noEmit",
|
|
26
|
+
"test": "bun test",
|
|
27
|
+
"prepublishOnly": "npm run build"
|
|
28
|
+
},
|
|
29
|
+
"keywords": [
|
|
30
|
+
"lipgloss",
|
|
31
|
+
"terminal",
|
|
32
|
+
"styling",
|
|
33
|
+
"ansi",
|
|
34
|
+
"tui",
|
|
35
|
+
"css",
|
|
36
|
+
"colors",
|
|
37
|
+
"borders",
|
|
38
|
+
"padding",
|
|
39
|
+
"margins",
|
|
40
|
+
"layout",
|
|
41
|
+
"charmbracelet",
|
|
42
|
+
"nodejs",
|
|
43
|
+
"bun",
|
|
44
|
+
"deno",
|
|
45
|
+
"typescript",
|
|
46
|
+
"zero-dependencies",
|
|
47
|
+
"multi-runtime"
|
|
48
|
+
],
|
|
49
|
+
"author": "Antonio Oliveira <antonio@oakoliver.com> (https://oakoliver.com)",
|
|
50
|
+
"license": "MIT",
|
|
51
|
+
"repository": {
|
|
52
|
+
"type": "git",
|
|
53
|
+
"url": "git+https://github.com/oakoliver/lipgloss.git"
|
|
54
|
+
},
|
|
55
|
+
"homepage": "https://github.com/oakoliver/lipgloss#readme",
|
|
56
|
+
"bugs": {
|
|
57
|
+
"url": "https://github.com/oakoliver/lipgloss/issues"
|
|
58
|
+
},
|
|
59
|
+
"devDependencies": {
|
|
60
|
+
"@types/node": "^20.0.0",
|
|
61
|
+
"esbuild": "^0.27.4",
|
|
62
|
+
"typescript": "^5.0.0"
|
|
63
|
+
},
|
|
64
|
+
"peerDependencies": {
|
|
65
|
+
"typescript": "^5.0.0"
|
|
66
|
+
},
|
|
67
|
+
"engines": {
|
|
68
|
+
"node": ">=18.0.0"
|
|
69
|
+
}
|
|
70
|
+
}
|
package/src/ansi.ts
ADDED
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ANSI escape code utilities for terminal styling.
|
|
3
|
+
* Pure TypeScript implementation — no dependencies.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// CSI (Control Sequence Introducer)
|
|
7
|
+
const ESC = '\x1b';
|
|
8
|
+
const CSI = `${ESC}[`;
|
|
9
|
+
|
|
10
|
+
/** SGR (Select Graphic Rendition) codes */
|
|
11
|
+
export const SGR = {
|
|
12
|
+
reset: `${CSI}0m`,
|
|
13
|
+
|
|
14
|
+
bold: `${CSI}1m`,
|
|
15
|
+
faint: `${CSI}2m`,
|
|
16
|
+
italic: `${CSI}3m`,
|
|
17
|
+
underline: `${CSI}4m`,
|
|
18
|
+
blink: `${CSI}5m`,
|
|
19
|
+
reverse: `${CSI}7m`,
|
|
20
|
+
strikethrough: `${CSI}9m`,
|
|
21
|
+
|
|
22
|
+
// Underline styles (not universally supported)
|
|
23
|
+
underlineNone: `${CSI}24m`,
|
|
24
|
+
underlineSingle: `${CSI}4m`,
|
|
25
|
+
underlineDouble: `${CSI}4:2m`,
|
|
26
|
+
underlineCurly: `${CSI}4:3m`,
|
|
27
|
+
underlineDotted: `${CSI}4:4m`,
|
|
28
|
+
underlineDashed: `${CSI}4:5m`,
|
|
29
|
+
|
|
30
|
+
// Reset specific attributes
|
|
31
|
+
resetBold: `${CSI}22m`,
|
|
32
|
+
resetItalic: `${CSI}23m`,
|
|
33
|
+
resetUnderline: `${CSI}24m`,
|
|
34
|
+
resetBlink: `${CSI}25m`,
|
|
35
|
+
resetReverse: `${CSI}27m`,
|
|
36
|
+
resetStrikethrough: `${CSI}29m`,
|
|
37
|
+
} as const;
|
|
38
|
+
|
|
39
|
+
/** Set foreground color using ANSI basic (0-7), bright (8-15), 256, or RGB */
|
|
40
|
+
export function fgColor(r: number, g: number, b: number): string {
|
|
41
|
+
return `${CSI}38;2;${r};${g};${b}m`;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function fgAnsi256(n: number): string {
|
|
45
|
+
return `${CSI}38;5;${n}m`;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function fgBasic(n: number): string {
|
|
49
|
+
if (n < 8) return `${CSI}${30 + n}m`;
|
|
50
|
+
return `${CSI}${90 + (n - 8)}m`;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** Set background color using ANSI basic (0-7), bright (8-15), 256, or RGB */
|
|
54
|
+
export function bgColor(r: number, g: number, b: number): string {
|
|
55
|
+
return `${CSI}48;2;${r};${g};${b}m`;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function bgAnsi256(n: number): string {
|
|
59
|
+
return `${CSI}48;5;${n}m`;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function bgBasic(n: number): string {
|
|
63
|
+
if (n < 8) return `${CSI}${40 + n}m`;
|
|
64
|
+
return `${CSI}${100 + (n - 8)}m`;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** Set underline color (not universally supported) */
|
|
68
|
+
export function ulColor(r: number, g: number, b: number): string {
|
|
69
|
+
return `${CSI}58;2;${r};${g};${b}m`;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function ulAnsi256(n: number): string {
|
|
73
|
+
return `${CSI}58;5;${n}m`;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** OSC hyperlink escape sequences */
|
|
77
|
+
export function setHyperlink(url: string, params?: string): string {
|
|
78
|
+
const p = params ? params : '';
|
|
79
|
+
return `${ESC}]8;${p};${url}${ESC}\\`;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export function resetHyperlink(): string {
|
|
83
|
+
return `${ESC}]8;;${ESC}\\`;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Strip all ANSI escape sequences from a string.
|
|
88
|
+
*/
|
|
89
|
+
// eslint-disable-next-line no-control-regex
|
|
90
|
+
const ANSI_REGEX = /[\x1b\x9b][[()#;?]*(?:[0-9]{1,4}(?:[;:][0-9]{0,4})*)?[0-9A-ORZcf-nqry=><~]|\x1b\]8;[^\x1b]*\x1b\\/g;
|
|
91
|
+
|
|
92
|
+
export function stripAnsi(str: string): string {
|
|
93
|
+
return str.replace(ANSI_REGEX, '');
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Measure the visible (printable) width of a string, ignoring ANSI codes.
|
|
98
|
+
* This is a simplified implementation that handles common cases.
|
|
99
|
+
* For full Unicode width support, a proper East Asian Width implementation
|
|
100
|
+
* would be needed, but this covers the vast majority of use cases.
|
|
101
|
+
*/
|
|
102
|
+
export function stringWidth(str: string): number {
|
|
103
|
+
const stripped = stripAnsi(str);
|
|
104
|
+
let width = 0;
|
|
105
|
+
for (let i = 0; i < stripped.length; i++) {
|
|
106
|
+
const code = stripped.charCodeAt(i);
|
|
107
|
+
// Skip combining characters (rough heuristic)
|
|
108
|
+
if (code >= 0x0300 && code <= 0x036f) continue;
|
|
109
|
+
if (code >= 0x1ab0 && code <= 0x1aff) continue;
|
|
110
|
+
if (code >= 0x1dc0 && code <= 0x1dff) continue;
|
|
111
|
+
if (code >= 0x20d0 && code <= 0x20ff) continue;
|
|
112
|
+
if (code >= 0xfe20 && code <= 0xfe2f) continue;
|
|
113
|
+
|
|
114
|
+
// Handle surrogate pairs for full Unicode
|
|
115
|
+
if (code >= 0xd800 && code <= 0xdbff) {
|
|
116
|
+
const next = stripped.charCodeAt(i + 1);
|
|
117
|
+
if (next >= 0xdc00 && next <= 0xdfff) {
|
|
118
|
+
const cp = (code - 0xd800) * 0x400 + (next - 0xdc00) + 0x10000;
|
|
119
|
+
// CJK Unified Ideographs Extension B+
|
|
120
|
+
if (cp >= 0x20000 && cp <= 0x3ffff) {
|
|
121
|
+
width += 2;
|
|
122
|
+
} else {
|
|
123
|
+
width += 1;
|
|
124
|
+
}
|
|
125
|
+
i++; // skip low surrogate
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// East Asian Full-width and Wide characters
|
|
131
|
+
if (isFullWidth(code)) {
|
|
132
|
+
width += 2;
|
|
133
|
+
} else if (code === 0x09) {
|
|
134
|
+
// Tab — we handle this at a higher level
|
|
135
|
+
width += 4;
|
|
136
|
+
} else {
|
|
137
|
+
width += 1;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return width;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/** Check if a Unicode code point is full-width */
|
|
144
|
+
function isFullWidth(code: number): boolean {
|
|
145
|
+
return (
|
|
146
|
+
(code >= 0x1100 && code <= 0x115f) || // Hangul Jamo
|
|
147
|
+
(code >= 0x2e80 && code <= 0x303e) || // CJK Radicals, Kangxi, Ideographic Description
|
|
148
|
+
(code >= 0x3040 && code <= 0x33bf) || // Hiragana, Katakana, Bopomofo, etc.
|
|
149
|
+
(code >= 0x3400 && code <= 0x4dbf) || // CJK Unified Ideographs Extension A
|
|
150
|
+
(code >= 0x4e00 && code <= 0xa4cf) || // CJK Unified Ideographs, Yi
|
|
151
|
+
(code >= 0xac00 && code <= 0xd7a3) || // Hangul Syllables
|
|
152
|
+
(code >= 0xf900 && code <= 0xfaff) || // CJK Compatibility Ideographs
|
|
153
|
+
(code >= 0xfe30 && code <= 0xfe6f) || // CJK Compatibility Forms, Small Form Variants
|
|
154
|
+
(code >= 0xff01 && code <= 0xff60) || // Fullwidth Forms
|
|
155
|
+
(code >= 0xffe0 && code <= 0xffe6) // Fullwidth Signs
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Truncate a string to a maximum visible width, stripping ANSI codes as needed.
|
|
161
|
+
*/
|
|
162
|
+
export function truncate(str: string, maxWidth: number): string {
|
|
163
|
+
if (maxWidth <= 0) return '';
|
|
164
|
+
if (stringWidth(str) <= maxWidth) return str;
|
|
165
|
+
|
|
166
|
+
let width = 0;
|
|
167
|
+
let result = '';
|
|
168
|
+
let inEscape = false;
|
|
169
|
+
let escapeSeq = '';
|
|
170
|
+
|
|
171
|
+
for (let i = 0; i < str.length; i++) {
|
|
172
|
+
const ch = str[i];
|
|
173
|
+
|
|
174
|
+
if (inEscape) {
|
|
175
|
+
escapeSeq += ch;
|
|
176
|
+
// Check for end of escape sequence
|
|
177
|
+
if (/[A-Za-z~]/.test(ch) || (escapeSeq.startsWith('\x1b]') && ch === '\\' && escapeSeq[escapeSeq.length - 2] === '\x1b')) {
|
|
178
|
+
result += escapeSeq;
|
|
179
|
+
inEscape = false;
|
|
180
|
+
escapeSeq = '';
|
|
181
|
+
}
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
if (ch === '\x1b' || ch === '\x9b') {
|
|
186
|
+
inEscape = true;
|
|
187
|
+
escapeSeq = ch;
|
|
188
|
+
continue;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const code = ch.charCodeAt(0);
|
|
192
|
+
const charWidth = isFullWidth(code) ? 2 : 1;
|
|
193
|
+
|
|
194
|
+
if (width + charWidth > maxWidth) break;
|
|
195
|
+
width += charWidth;
|
|
196
|
+
result += ch;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
return result;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Build an ANSI styled string by wrapping content in SGR sequences.
|
|
204
|
+
*/
|
|
205
|
+
export interface AnsiStyleOptions {
|
|
206
|
+
bold?: boolean;
|
|
207
|
+
faint?: boolean;
|
|
208
|
+
italic?: boolean;
|
|
209
|
+
underline?: boolean;
|
|
210
|
+
underlineStyle?: UnderlineStyle;
|
|
211
|
+
blink?: boolean;
|
|
212
|
+
reverse?: boolean;
|
|
213
|
+
strikethrough?: boolean;
|
|
214
|
+
fg?: ColorValue | null;
|
|
215
|
+
bg?: ColorValue | null;
|
|
216
|
+
ul?: ColorValue | null;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
export type UnderlineStyle = 'none' | 'single' | 'double' | 'curly' | 'dotted' | 'dashed';
|
|
220
|
+
|
|
221
|
+
export interface ColorValue {
|
|
222
|
+
type: 'basic' | 'ansi256' | 'rgb';
|
|
223
|
+
value: number; // for basic (0-15) and ansi256 (0-255)
|
|
224
|
+
r?: number;
|
|
225
|
+
g?: number;
|
|
226
|
+
b?: number;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Apply ANSI styling to a string.
|
|
231
|
+
*/
|
|
232
|
+
export function styled(str: string, opts: AnsiStyleOptions): string {
|
|
233
|
+
let prefix = '';
|
|
234
|
+
let suffix = '';
|
|
235
|
+
|
|
236
|
+
if (opts.bold) { prefix += SGR.bold; }
|
|
237
|
+
if (opts.faint) { prefix += SGR.faint; }
|
|
238
|
+
if (opts.italic) { prefix += SGR.italic; }
|
|
239
|
+
if (opts.underline || (opts.underlineStyle && opts.underlineStyle !== 'none')) {
|
|
240
|
+
const style = opts.underlineStyle || 'single';
|
|
241
|
+
switch (style) {
|
|
242
|
+
case 'single': prefix += SGR.underlineSingle; break;
|
|
243
|
+
case 'double': prefix += SGR.underlineDouble; break;
|
|
244
|
+
case 'curly': prefix += SGR.underlineCurly; break;
|
|
245
|
+
case 'dotted': prefix += SGR.underlineDotted; break;
|
|
246
|
+
case 'dashed': prefix += SGR.underlineDashed; break;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
if (opts.blink) { prefix += SGR.blink; }
|
|
250
|
+
if (opts.reverse) { prefix += SGR.reverse; }
|
|
251
|
+
if (opts.strikethrough) { prefix += SGR.strikethrough; }
|
|
252
|
+
|
|
253
|
+
if (opts.fg) {
|
|
254
|
+
prefix += colorToFg(opts.fg);
|
|
255
|
+
}
|
|
256
|
+
if (opts.bg) {
|
|
257
|
+
prefix += colorToBg(opts.bg);
|
|
258
|
+
}
|
|
259
|
+
if (opts.ul) {
|
|
260
|
+
prefix += colorToUl(opts.ul);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
if (prefix) {
|
|
264
|
+
suffix = SGR.reset;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
return prefix + str + suffix;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
function colorToFg(c: ColorValue): string {
|
|
271
|
+
switch (c.type) {
|
|
272
|
+
case 'basic': return fgBasic(c.value);
|
|
273
|
+
case 'ansi256': return fgAnsi256(c.value);
|
|
274
|
+
case 'rgb': return fgColor(c.r!, c.g!, c.b!);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
function colorToBg(c: ColorValue): string {
|
|
279
|
+
switch (c.type) {
|
|
280
|
+
case 'basic': return bgBasic(c.value);
|
|
281
|
+
case 'ansi256': return bgAnsi256(c.value);
|
|
282
|
+
case 'rgb': return bgColor(c.r!, c.g!, c.b!);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
function colorToUl(c: ColorValue): string {
|
|
287
|
+
switch (c.type) {
|
|
288
|
+
case 'basic': return ulAnsi256(c.value); // underline color uses 256 encoding for basic too
|
|
289
|
+
case 'ansi256': return ulAnsi256(c.value);
|
|
290
|
+
case 'rgb': return ulColor(c.r!, c.g!, c.b!);
|
|
291
|
+
}
|
|
292
|
+
}
|