@vincemakes/kiso-tui-cells 0.10.0 → 0.12.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/dist/approval-panel.d.ts +167 -16
- package/dist/approval-panel.js +283 -75
- package/dist/components.d.ts +48 -2
- package/dist/components.js +61 -19
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/md.d.ts +137 -0
- package/dist/md.js +720 -0
- package/dist/render.d.ts +10 -0
- package/dist/render.js +2 -2
- package/dist/strings.d.ts +22 -22
- package/dist/strings.js +26 -24
- package/dist/width.d.ts +14 -0
- package/dist/width.js +74 -27
- package/package.json +1 -1
package/dist/components.d.ts
CHANGED
|
@@ -18,6 +18,8 @@
|
|
|
18
18
|
* tint, fold wording).
|
|
19
19
|
*/
|
|
20
20
|
import { foldThinking, foldResult, renderToolSummary, type ResumeMeta } from "./render.js";
|
|
21
|
+
import { type MdBlock } from "./md.js";
|
|
22
|
+
export { MdStream, renderBlock, renderMarkdown, type MdBlock, type MdKind } from "./md.js";
|
|
21
23
|
/** The spinner glyphs, cycled by the compositor's on-demand tick. */
|
|
22
24
|
export declare const SPINNER: string[];
|
|
23
25
|
/** The frame context the compositor passes down — the pieces of time
|
|
@@ -43,8 +45,12 @@ export type RenderLine = string;
|
|
|
43
45
|
*/
|
|
44
46
|
export declare function foldLine(line: string, W: number): string[];
|
|
45
47
|
/** The visible width of a rendered line (SGR stripped — the invariant
|
|
46
|
-
* the compositor enforces on every emitted line).
|
|
47
|
-
|
|
48
|
+
* the compositor enforces on every emitted line). TUI2-MD ⑤: the body
|
|
49
|
+
* moved to width.ts (the width authority's own home) so the markdown
|
|
50
|
+
* renderer can measure without importing this module back — the
|
|
51
|
+
* re-export is verbatim, so every existing importer and the barrel see
|
|
52
|
+
* exactly what they saw. */
|
|
53
|
+
export { visibleWidth } from "./width.js";
|
|
48
54
|
/** A component: render the display lines for one piece of state. */
|
|
49
55
|
export interface Component {
|
|
50
56
|
render(width: number, ctx: FrameCtx): string[];
|
|
@@ -145,6 +151,18 @@ export type BodyCell = {
|
|
|
145
151
|
kind: "text";
|
|
146
152
|
text: string;
|
|
147
153
|
done: boolean;
|
|
154
|
+
}
|
|
155
|
+
/** TUI2-MD ⑤ — ONE markdown block of assistant body text. The cell is
|
|
156
|
+
* the commit unit the compositor already had, so block-freeze needs
|
|
157
|
+
* no new commit machinery: a CLOSED block is a DONE cell and the
|
|
158
|
+
* natural loop freezes it; the OPEN tail block is the one cell left
|
|
159
|
+
* live. `block` carries the block's SOURCE (never rendered rows), so
|
|
160
|
+
* a resize re-renders it at the new width exactly as every other
|
|
161
|
+
* cell does. */
|
|
162
|
+
| {
|
|
163
|
+
kind: "md";
|
|
164
|
+
block: MdBlock;
|
|
165
|
+
done: boolean;
|
|
148
166
|
} | {
|
|
149
167
|
kind: "notice";
|
|
150
168
|
text: string;
|
|
@@ -332,6 +350,34 @@ export declare function statusLine(status: string, tail: string, W: number, hint
|
|
|
332
350
|
/** The display-width prefix of a plain (SGR-free) text. W21: exported
|
|
333
351
|
* for the approval panel's option-2 rule-name cut. */
|
|
334
352
|
export declare function widthCut(text: string, max: number): string;
|
|
353
|
+
/**
|
|
354
|
+
* TUI2-R3v2 ① — THE selection bar. One engine, every selection surface.
|
|
355
|
+
*
|
|
356
|
+
* The R1.5 ⑧ ruling settled the shape (a full-row reverse bar, not a
|
|
357
|
+
* two-cell marker you have to hunt for in eighty columns) and the @
|
|
358
|
+
* picker, the user chip and the R2 session picker each grew their own
|
|
359
|
+
* copy of the composition. The approval panel would have been the
|
|
360
|
+
* fourth, so the composition moves HERE and the surfaces call it.
|
|
361
|
+
*
|
|
362
|
+
* Two details are the whole reason this is a function and not four
|
|
363
|
+
* inlined string templates:
|
|
364
|
+
*
|
|
365
|
+
* - the inner `reset`s are rewritten to reset-then-reverse. A plain SGR
|
|
366
|
+
* 0 inside the bar punches a hole in it: the row goes back to normal
|
|
367
|
+
* video mid-span and the bar reads as two bars with a gap. The close
|
|
368
|
+
* is SGR 27 (rvEnd), never SGR 0, for the same reason — the bar
|
|
369
|
+
* composes INSIDE whatever span surrounds it.
|
|
370
|
+
* - the pad is computed from the caller's measured VISIBLE width, never
|
|
371
|
+
* from the styled string's length. A bar that stops short is not a
|
|
372
|
+
* bar, and one that runs past W crashes the compositor's invariant ①
|
|
373
|
+
* rather than truncating quietly — so the arithmetic is stated once,
|
|
374
|
+
* here, and proven once, in the sweep gates.
|
|
375
|
+
*
|
|
376
|
+
* The bar spends one cell of frame at each end, so callers build their
|
|
377
|
+
* spans against W−2 whether the row is selected or not — which is what
|
|
378
|
+
* keeps the columns from moving as the bar walks the list.
|
|
379
|
+
*/
|
|
380
|
+
export declare function selectionBar(styled: string, visible: number, W: number): string;
|
|
335
381
|
/** W6 — the box: the chrome's top rail. The two ╌ dotted rows become
|
|
336
382
|
* a rounded box (the box already says "input lives here"); the rails
|
|
337
383
|
* stay dim, the width is still the full W (the box is a rail with
|
package/dist/components.js
CHANGED
|
@@ -17,12 +17,18 @@
|
|
|
17
17
|
* (untouched); render.ts supplies the original text (palette, escape,
|
|
18
18
|
* tint, fold wording).
|
|
19
19
|
*/
|
|
20
|
-
import { displayWidth } from "./width.js";
|
|
20
|
+
import { displayWidth, visibleWidth } from "./width.js";
|
|
21
21
|
// TUI2-R2pre ④: the ONE display-verb table (strings.ts, beside
|
|
22
22
|
// KEY_BINDINGS). strings.js imports only render/width here, so this edge
|
|
23
23
|
// adds no cycle.
|
|
24
24
|
import { displayVerb } from "./strings.js";
|
|
25
25
|
import { bannerLines, escapeTerminal, foldThinking, foldResult, colorInlineCode, renderTerminalGap, renderToolSummary, toolTarget, kUnit, palette, } from "./render.js";
|
|
26
|
+
// TUI2-MD: the markdown renderer's surface reaches the tui through this
|
|
27
|
+
// module (the tui's components shim re-exports it) — one import edge,
|
|
28
|
+
// and it points one way: md.ts measures with the width authority, never
|
|
29
|
+
// back through here.
|
|
30
|
+
import { renderBlock } from "./md.js";
|
|
31
|
+
export { MdStream, renderBlock, renderMarkdown } from "./md.js";
|
|
26
32
|
/** The spinner glyphs, cycled by the compositor's on-demand tick. */
|
|
27
33
|
export const SPINNER = ["▖", "▘", "▝", "▗"];
|
|
28
34
|
/**
|
|
@@ -94,24 +100,12 @@ export function foldLine(line, W) {
|
|
|
94
100
|
return out;
|
|
95
101
|
}
|
|
96
102
|
/** The visible width of a rendered line (SGR stripped — the invariant
|
|
97
|
-
* the compositor enforces on every emitted line).
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
if (m !== null) {
|
|
104
|
-
i += m[0].length;
|
|
105
|
-
continue;
|
|
106
|
-
}
|
|
107
|
-
i += 1;
|
|
108
|
-
continue;
|
|
109
|
-
}
|
|
110
|
-
w += displayWidth(line[i]);
|
|
111
|
-
i += 1;
|
|
112
|
-
}
|
|
113
|
-
return w;
|
|
114
|
-
}
|
|
103
|
+
* the compositor enforces on every emitted line). TUI2-MD ⑤: the body
|
|
104
|
+
* moved to width.ts (the width authority's own home) so the markdown
|
|
105
|
+
* renderer can measure without importing this module back — the
|
|
106
|
+
* re-export is verbatim, so every existing importer and the barrel see
|
|
107
|
+
* exactly what they saw. */
|
|
108
|
+
export { visibleWidth } from "./width.js";
|
|
115
109
|
/** The W11 spacing formula — "a row gets one blank line above it when
|
|
116
110
|
* the row is itself a block, or when the previous sibling was taller
|
|
117
111
|
* than one row". One-row siblings pack tight; anything multi-row
|
|
@@ -160,6 +154,8 @@ export function cellComponent(cell) {
|
|
|
160
154
|
return new ToolExecution(cell);
|
|
161
155
|
case "text":
|
|
162
156
|
return new AssistantMessage(cell);
|
|
157
|
+
case "md":
|
|
158
|
+
return new MarkdownBlock(cell);
|
|
163
159
|
case "notice":
|
|
164
160
|
return new ErrorLine(cell);
|
|
165
161
|
case "banner":
|
|
@@ -1190,6 +1186,20 @@ class AssistantMessage {
|
|
|
1190
1186
|
return wrapped.length > 0 ? wrapped.map((l) => colorInlineCode(l)) : [""];
|
|
1191
1187
|
}
|
|
1192
1188
|
}
|
|
1189
|
+
/** TUI2-MD ⑤ — one markdown block. Pure in (block, W): the same source
|
|
1190
|
+
* and the same width give the same bytes, which is the freeze property
|
|
1191
|
+
* the commit path relies on. The block carries its own leading blank
|
|
1192
|
+
* (the style table's rhythm), so the compositor's W11 join formula
|
|
1193
|
+
* steps aside between two of these. */
|
|
1194
|
+
class MarkdownBlock {
|
|
1195
|
+
cell;
|
|
1196
|
+
constructor(cell) {
|
|
1197
|
+
this.cell = cell;
|
|
1198
|
+
}
|
|
1199
|
+
render(W, _ctx) {
|
|
1200
|
+
return renderBlock(this.cell.block, W);
|
|
1201
|
+
}
|
|
1202
|
+
}
|
|
1193
1203
|
/** The ⚠ / notice lines — the error surface. */
|
|
1194
1204
|
class ErrorLine {
|
|
1195
1205
|
cell;
|
|
@@ -1401,6 +1411,38 @@ export function widthCut(text, max) {
|
|
|
1401
1411
|
}
|
|
1402
1412
|
return text.slice(0, i);
|
|
1403
1413
|
}
|
|
1414
|
+
/**
|
|
1415
|
+
* TUI2-R3v2 ① — THE selection bar. One engine, every selection surface.
|
|
1416
|
+
*
|
|
1417
|
+
* The R1.5 ⑧ ruling settled the shape (a full-row reverse bar, not a
|
|
1418
|
+
* two-cell marker you have to hunt for in eighty columns) and the @
|
|
1419
|
+
* picker, the user chip and the R2 session picker each grew their own
|
|
1420
|
+
* copy of the composition. The approval panel would have been the
|
|
1421
|
+
* fourth, so the composition moves HERE and the surfaces call it.
|
|
1422
|
+
*
|
|
1423
|
+
* Two details are the whole reason this is a function and not four
|
|
1424
|
+
* inlined string templates:
|
|
1425
|
+
*
|
|
1426
|
+
* - the inner `reset`s are rewritten to reset-then-reverse. A plain SGR
|
|
1427
|
+
* 0 inside the bar punches a hole in it: the row goes back to normal
|
|
1428
|
+
* video mid-span and the bar reads as two bars with a gap. The close
|
|
1429
|
+
* is SGR 27 (rvEnd), never SGR 0, for the same reason — the bar
|
|
1430
|
+
* composes INSIDE whatever span surrounds it.
|
|
1431
|
+
* - the pad is computed from the caller's measured VISIBLE width, never
|
|
1432
|
+
* from the styled string's length. A bar that stops short is not a
|
|
1433
|
+
* bar, and one that runs past W crashes the compositor's invariant ①
|
|
1434
|
+
* rather than truncating quietly — so the arithmetic is stated once,
|
|
1435
|
+
* here, and proven once, in the sweep gates.
|
|
1436
|
+
*
|
|
1437
|
+
* The bar spends one cell of frame at each end, so callers build their
|
|
1438
|
+
* spans against W−2 whether the row is selected or not — which is what
|
|
1439
|
+
* keeps the columns from moving as the bar walks the list.
|
|
1440
|
+
*/
|
|
1441
|
+
export function selectionBar(styled, visible, W) {
|
|
1442
|
+
const p = palette();
|
|
1443
|
+
const inner = styled.replaceAll(p.reset, `${p.reset}${p.rv}`);
|
|
1444
|
+
return `${p.rv} ${inner}${" ".repeat(Math.max(0, W - visible - 2))} ${p.rvEnd}`;
|
|
1445
|
+
}
|
|
1404
1446
|
/** W6 — the box: the chrome's top rail. The two ╌ dotted rows become
|
|
1405
1447
|
* a rounded box (the box already says "input lives here"); the rails
|
|
1406
1448
|
* stay dim, the width is still the full W (the box is a rail with
|
package/dist/index.d.ts
CHANGED
|
@@ -10,7 +10,7 @@ export { SPINNER, foldLine, foldWords, visibleWidth, bodySpacing, Container, cel
|
|
|
10
10
|
export { editFileDiff, truncateDiff, writeFileDiff, type DiffLine, type DiffResult } from "./diff.js";
|
|
11
11
|
export { pendingQueueRows } from "./components.js";
|
|
12
12
|
export { charWidth, displayWidth, leadWidth, widthOf } from "./width.js";
|
|
13
|
-
export { panelAffordance, panelBlockRows, panelLead, panelLeadPlain, panelLeadWidth, panelStatus, type PanelArgs, type PanelFlavor, type PanelPhase, type
|
|
13
|
+
export { panelAffordance, panelBlockRows, panelLead, panelLeadPlain, panelLeadWidth, panelStatus, type PanelArgs, type PanelFlavor, type PanelPhase, deletionRiskHint, SAFER_BACK, SAFER_DEGRADED, type SaferOption, type SaferRuntime, panelOptions, type PanelOption, type PanelOptionKind, type PanelState, type PanelVerdict, type PanelView, type AskAnswer, type AskOption, type AskQuestion, type AskResult, type AskRuntime, type AskSpec, } from "./approval-panel.js";
|
|
14
14
|
export { interactivePrompt, projectTrustRows, projectTrustView, projectUntrustedNote, uncertainView, type TrustArtifact, } from "./strings.js";
|
|
15
15
|
export { extensionsBannerText, helpRows, unansweredAskView, type BannerExtension } from "./strings.js";
|
|
16
16
|
export { displayVerb } from "./strings.js";
|
package/dist/index.js
CHANGED
|
@@ -17,7 +17,7 @@ export { charWidth, displayWidth, leadWidth, widthOf } from "./width.js";
|
|
|
17
17
|
// that replaces the running tool's live window while a human-chain
|
|
18
18
|
// approval is pending. Types + the row/lead/status renderers; the
|
|
19
19
|
// verdict mapping lives in the cli, never here.
|
|
20
|
-
export { panelAffordance, panelBlockRows, panelLead, panelLeadPlain, panelLeadWidth, panelStatus, } from "./approval-panel.js";
|
|
20
|
+
export { panelAffordance, panelBlockRows, panelLead, panelLeadPlain, panelLeadWidth, panelStatus, deletionRiskHint, SAFER_BACK, SAFER_DEGRADED, panelOptions, } from "./approval-panel.js";
|
|
21
21
|
// KC3 slice 1 (the extraction): the human-facing strings the CLI's
|
|
22
22
|
// trust-ui.ts used to build inline — the prompt, the project-trust
|
|
23
23
|
// listing/view/note, the uncertain execution's view. The flow stays in
|
package/dist/md.d.ts
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TUI2-MD — the markdown renderer. Hand-rolled, zero dependencies, and
|
|
3
|
+
* deliberately a SUBSET: the constructs assistant prose actually uses,
|
|
4
|
+
* rendered under the mono discipline (attributes over colours, zero
|
|
5
|
+
* syntax highlighting).
|
|
6
|
+
*
|
|
7
|
+
* THE BLOCK-FREEZE DISCIPLINE. kiso's committed bytes are never
|
|
8
|
+
* re-emitted (ADR-0046) — the terminal's own scrollback is the
|
|
9
|
+
* transcript. A renderer that re-lexes the whole message per delta (the
|
|
10
|
+
* shape a whole-text parser forces on you) can therefore not be used
|
|
11
|
+
* here at all: it would need to repaint lines that have already left
|
|
12
|
+
* the live region. So the scanner below IS the streaming state machine.
|
|
13
|
+
* It consumes appended text and yields two things:
|
|
14
|
+
*
|
|
15
|
+
* - CLOSED blocks: their source is final, so their render is final;
|
|
16
|
+
* the compositor commits them through the path it already had.
|
|
17
|
+
* - the OPEN TAIL block: the live region's occupant, re-rendered in
|
|
18
|
+
* place per delta, bounded by construction (one block).
|
|
19
|
+
*
|
|
20
|
+
* The freeze property — a closed block's rendered lines never change as
|
|
21
|
+
* more text arrives — is earned by ONE rule: block boundaries are
|
|
22
|
+
* decided only on COMPLETE lines. A trailing partial line renders
|
|
23
|
+
* eagerly but can never close anything, because a decision taken on an
|
|
24
|
+
* incomplete line can be wrong ("#" is a heading until it becomes
|
|
25
|
+
* "#hashtag") and a wrong decision here is a wrong commit.
|
|
26
|
+
*
|
|
27
|
+
* Everything else follows: an unclosed `**` renders literal and flips
|
|
28
|
+
* when it closes, but only ever inside the open block; a fence body
|
|
29
|
+
* line is line-local (no highlighting means no cross-line lexer state),
|
|
30
|
+
* so it closes the instant its newline arrives and long code blocks
|
|
31
|
+
* never bloat the live region; a table re-layouts as rows stream, and
|
|
32
|
+
* only inside the tail.
|
|
33
|
+
*
|
|
34
|
+
* The style table is the round's normative one (the owner's circled
|
|
35
|
+
* group D): the BLOCK half is `blockBody` below, the INLINE half is
|
|
36
|
+
* `inlineSpans`, and every entry is pinned by a fixture rather than
|
|
37
|
+
* described twice.
|
|
38
|
+
*/
|
|
39
|
+
/** The block kinds. `fence-open`/`fence-line` are separate kinds on
|
|
40
|
+
* purpose: a fence's rows must be able to freeze ONE AT A TIME. */
|
|
41
|
+
export type MdKind = "para" | "heading" | "list" | "table" | "quote" | "rule" | "fence-open" | "fence-line";
|
|
42
|
+
/** One block: its SOURCE lines, never a rendered form. The render is a
|
|
43
|
+
* pure function of (block, width), which is what makes the freeze
|
|
44
|
+
* property a property of the scanner alone. */
|
|
45
|
+
export interface MdBlock {
|
|
46
|
+
readonly kind: MdKind;
|
|
47
|
+
readonly lines: readonly string[];
|
|
48
|
+
/** a blank row precedes this block — the markdown rhythm, owned here
|
|
49
|
+
* rather than by the compositor's W11 join formula (which reads row
|
|
50
|
+
* COUNTS and so cannot express "no blank between two rows of one
|
|
51
|
+
* fence"). */
|
|
52
|
+
readonly gap: boolean;
|
|
53
|
+
/** the fence's language tag; "" everywhere else. */
|
|
54
|
+
readonly lang: string;
|
|
55
|
+
}
|
|
56
|
+
export declare class MdStream {
|
|
57
|
+
#private;
|
|
58
|
+
/** Append streamed text. Only COMPLETE lines reach the state machine. */
|
|
59
|
+
push(text: string): void;
|
|
60
|
+
/** The message ended: the trailing partial line is a complete line
|
|
61
|
+
* after all, and the open block closes. */
|
|
62
|
+
end(): void;
|
|
63
|
+
/** Every block so far: `closed()` of them are FINAL, and at most one
|
|
64
|
+
* open tail follows. Fresh objects — a closed block's source can
|
|
65
|
+
* never be reached through this. */
|
|
66
|
+
blocks(): readonly MdBlock[];
|
|
67
|
+
/** How many leading blocks are CLOSED — the commit-eligible count. */
|
|
68
|
+
closed(): number;
|
|
69
|
+
}
|
|
70
|
+
/** The whole message at once — the freeze property's oracle, and the
|
|
71
|
+
* path a non-streaming caller takes. */
|
|
72
|
+
export declare function renderMarkdown(text: string, W: number): string[];
|
|
73
|
+
/** One block's screen rows. Pure in (block, W) — this is the whole
|
|
74
|
+
* freeze guarantee: same source, same width, same bytes, forever. */
|
|
75
|
+
export declare function renderBlock(b: MdBlock, W: number): string[];
|
|
76
|
+
/**
|
|
77
|
+
* The inline pass — the mono style table applied to one block's text.
|
|
78
|
+
*
|
|
79
|
+
* Scoped to `**bold**`, `*italic*`, `` `code` ``, `[text](url)` and the
|
|
80
|
+
* backslash escape, with two rules that matter more than coverage:
|
|
81
|
+
*
|
|
82
|
+
* RAW UNTIL CLOSED — an opener with no closer in this text stays
|
|
83
|
+
* literal. That is what lets a half-streamed `**` show its asterisks
|
|
84
|
+
* and flip the instant the closer lands, inside the live block and
|
|
85
|
+
* nowhere else.
|
|
86
|
+
*
|
|
87
|
+
* CLOSE BACK TO `base` — the block's own style (a heading's bold, a
|
|
88
|
+
* quote's dim) is passed in, and every span reopens it on the way
|
|
89
|
+
* out, so a nested span can never strand it. Italic is the one span
|
|
90
|
+
* that closes surgically (SGR 23), because it can.
|
|
91
|
+
*
|
|
92
|
+
* Documented deviations from CommonMark: `_` never emphasizes (it is a
|
|
93
|
+
* character in identifiers far more often than a marker in prose);
|
|
94
|
+
* emphasis does not nest across a code span; `~~` is not a construct at
|
|
95
|
+
* all — the markers are content (the strict tokenizer both reference
|
|
96
|
+
* implementations converged on, taken to its honest conclusion, since
|
|
97
|
+
* SGR 9's terminal support is too fragmented to promise).
|
|
98
|
+
*/
|
|
99
|
+
export declare function inlineSpans(text: string, base: string): string;
|
|
100
|
+
/** Split a table line into cells. The `|` walls are found on the RAW
|
|
101
|
+
* line, but a pipe INSIDE a code span is content — two independent
|
|
102
|
+
* reference implementations both patched exactly this, because a
|
|
103
|
+
* command in a cell (`grep a | wc`) is common and splitting it puts
|
|
104
|
+
* the human's own text in the wrong column. A backslash-escaped pipe
|
|
105
|
+
* is content too. */
|
|
106
|
+
export declare function splitCells(line: string): string[];
|
|
107
|
+
export type MdAlign = "left" | "center" | "right";
|
|
108
|
+
export interface MdTable {
|
|
109
|
+
readonly header: readonly string[];
|
|
110
|
+
readonly align: readonly MdAlign[];
|
|
111
|
+
readonly rows: readonly (readonly string[])[];
|
|
112
|
+
}
|
|
113
|
+
/** The table shape, or null when these lines are NOT a table.
|
|
114
|
+
*
|
|
115
|
+
* Two rejections, both borrowed: a second line that is not a delimiter
|
|
116
|
+
* row means this is prose that contains pipes; and a body row carrying
|
|
117
|
+
* MORE columns than the header is malformed — rendering it would have
|
|
118
|
+
* to guess where the extra content belongs, and a guess printed into
|
|
119
|
+
* scrollback is indistinguishable from a fact. Rejected tables fall
|
|
120
|
+
* back to their own source bytes, which are still valid markdown. */
|
|
121
|
+
export declare function tableShape(lines: readonly string[]): MdTable | null;
|
|
122
|
+
/**
|
|
123
|
+
* Wrap styled text into rows of at most W columns, with a HANGING
|
|
124
|
+
* INDENT: `first` prefixes the first row, `hang` every later one, and
|
|
125
|
+
* the text column is what continuations align to.
|
|
126
|
+
*
|
|
127
|
+
* The SGR spans open at a break are closed at the row's end and
|
|
128
|
+
* reopened at the next row's start, so no style leaks into the padding
|
|
129
|
+
* and none is lost across the break. Italic's own close (23) is
|
|
130
|
+
* understood, so `\x1b[3m…\x1b[23m` inside a bold heading tracks
|
|
131
|
+
* correctly.
|
|
132
|
+
*
|
|
133
|
+
* Every emitted row measures ≤ W through the SAME width authority the
|
|
134
|
+
* compositor's invariant ① measures with — which is the only way the
|
|
135
|
+
* two can agree.
|
|
136
|
+
*/
|
|
137
|
+
export declare function mdWrap(text: string, W: number, first: string, hang: string): string[];
|