@promptctl/rich-js 0.23.0 → 0.24.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/THIRD-PARTY-NOTICES +29 -1
- package/dist/core/animation.d.ts +78 -0
- package/dist/core/animation.js +107 -0
- package/dist/core/cell-widths.d.ts +9 -0
- package/dist/core/cell-widths.js +140 -0
- package/dist/core/cells.d.ts +17 -11
- package/dist/core/cells.js +100 -25
- package/dist/core/clock.d.ts +9 -1
- package/dist/core/clock.js +22 -2
- package/dist/core/color.d.ts +10 -0
- package/dist/core/color.js +36 -1
- package/dist/core/console.js +5 -5
- package/dist/core/easing.d.ts +138 -7
- package/dist/core/easing.js +355 -17
- package/dist/core/json.js +2 -1
- package/dist/core/measure.js +2 -2
- package/dist/core/place.js +2 -1
- package/dist/core/pretty.js +2 -2
- package/dist/core/protocol.d.ts +73 -19
- package/dist/core/protocol.js +56 -15
- package/dist/core/render.js +2 -1
- package/dist/core/segment.d.ts +28 -1
- package/dist/core/segment.js +60 -44
- package/dist/core/strip.d.ts +107 -29
- package/dist/core/strip.js +242 -131
- package/dist/core/style.d.ts +18 -1
- package/dist/core/style.js +49 -9
- package/dist/core/text.js +26 -15
- package/dist/core/timeline.d.ts +84 -0
- package/dist/core/timeline.js +144 -0
- package/dist/core/tween.d.ts +49 -0
- package/dist/core/tween.js +69 -0
- package/dist/host/app.js +4 -6
- package/dist/host/index.d.ts +1 -1
- package/dist/host/input.d.ts +37 -13
- package/dist/host/input.js +146 -56
- package/dist/host/terminal-host.d.ts +16 -0
- package/dist/host/terminal-host.js +1 -0
- package/dist/index.d.ts +16 -11
- package/dist/index.js +15 -5
- package/dist/node/terminal-host.d.ts +8 -1
- package/dist/node/terminal-host.js +2 -0
- package/dist/renderables/align.d.ts +3 -2
- package/dist/renderables/align.js +3 -0
- package/dist/renderables/columns.d.ts +3 -2
- package/dist/renderables/columns.js +7 -2
- package/dist/renderables/constrain.d.ts +3 -2
- package/dist/renderables/constrain.js +5 -1
- package/dist/renderables/effect.d.ts +83 -30
- package/dist/renderables/effect.js +155 -57
- package/dist/renderables/effects.d.ts +88 -39
- package/dist/renderables/effects.js +444 -105
- package/dist/renderables/embed.d.ts +10 -0
- package/dist/renderables/embed.js +18 -9
- package/dist/renderables/flexStrip.d.ts +3 -2
- package/dist/renderables/flexStrip.js +6 -1
- package/dist/renderables/frames.d.ts +116 -0
- package/dist/renderables/frames.js +133 -0
- package/dist/renderables/group.d.ts +3 -2
- package/dist/renderables/group.js +5 -2
- package/dist/renderables/html-entities.d.ts +8 -0
- package/dist/renderables/html-entities.js +386 -0
- package/dist/renderables/layout.d.ts +3 -2
- package/dist/renderables/layout.js +15 -2
- package/dist/renderables/list-view.d.ts +3 -2
- package/dist/renderables/list-view.js +12 -5
- package/dist/renderables/live.d.ts +23 -7
- package/dist/renderables/live.js +69 -35
- package/dist/renderables/markdown-parse.d.ts +109 -0
- package/dist/renderables/markdown-parse.js +1421 -0
- package/dist/renderables/markdown-url.d.ts +19 -0
- package/dist/renderables/markdown-url.js +314 -0
- package/dist/renderables/markdown.d.ts +7 -6
- package/dist/renderables/markdown.js +363 -499
- package/dist/renderables/padding.d.ts +8 -20
- package/dist/renderables/padding.js +32 -50
- package/dist/renderables/panel.d.ts +26 -26
- package/dist/renderables/panel.js +67 -103
- package/dist/renderables/progress.d.ts +5 -3
- package/dist/renderables/progress.js +14 -3
- package/dist/renderables/progressBar.js +4 -4
- package/dist/renderables/python-space.d.ts +13 -0
- package/dist/renderables/python-space.js +24 -0
- package/dist/renderables/spinner.d.ts +73 -27
- package/dist/renderables/spinner.js +110 -51
- package/dist/renderables/status.d.ts +8 -3
- package/dist/renderables/status.js +8 -5
- package/dist/renderables/syntax.js +2 -1
- package/dist/renderables/table.d.ts +19 -11
- package/dist/renderables/table.js +140 -156
- package/dist/renderables/traceback.d.ts +1 -1
- package/dist/renderables/traceback.js +6 -5
- package/dist/renderables/tree.d.ts +6 -5
- package/dist/renderables/tree.js +11 -7
- package/dist/renderables/viewport.d.ts +13 -5
- package/dist/renderables/viewport.js +41 -20
- package/dist/template-bindings/animation-funcs.d.ts +37 -0
- package/dist/template-bindings/animation-funcs.js +83 -0
- package/dist/template-bindings/color-funcs.d.ts +13 -0
- package/dist/template-bindings/color-funcs.js +1 -1
- package/dist/template-bindings/helpers.d.ts +6 -0
- package/dist/template-bindings/helpers.js +12 -3
- package/dist/template-bindings/index.d.ts +6 -2
- package/dist/template-bindings/index.js +8 -3
- package/dist/themes/ramp.d.ts +18 -3
- package/dist/themes/ramp.js +23 -2
- package/dist/widgets/focus-manager.d.ts +21 -14
- package/dist/widgets/focus-manager.js +28 -29
- package/dist/widgets/index.d.ts +1 -1
- package/dist/widgets/static-item.d.ts +4 -3
- package/dist/widgets/static-item.js +9 -7
- package/dist/widgets/text-input.d.ts +28 -18
- package/dist/widgets/text-input.js +144 -101
- package/dist/widgets/widget-app.d.ts +19 -3
- package/dist/widgets/widget-app.js +39 -21
- package/dist/widgets/widget-base.js +0 -3
- package/package.json +2 -5
package/THIRD-PARTY-NOTICES
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Third-party notices for @promptctl/rich-js
|
|
2
2
|
|
|
3
|
-
This package contains material from the
|
|
3
|
+
This package contains material from the four projects below. All are
|
|
4
4
|
distributed under the MIT License, which requires their copyright and
|
|
5
5
|
permission notices to travel with every copy; they are reproduced here
|
|
6
6
|
unchanged. The license for rich-js itself is in LICENSE.
|
|
@@ -79,3 +79,31 @@ The above copyright notice and this permission notice shall be included in all c
|
|
|
79
79
|
|
|
80
80
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
81
81
|
|
|
82
|
+
-------------------------------------------------------------------------------
|
|
83
|
+
wcwidth
|
|
84
|
+
https://github.com/jquast/wcwidth
|
|
85
|
+
|
|
86
|
+
The cell width of each code point is Rich's table, which Rich generates from
|
|
87
|
+
wcwidth's data.
|
|
88
|
+
|
|
89
|
+
The MIT License (MIT)
|
|
90
|
+
|
|
91
|
+
Copyright (c) 2014 Jeff Quast <contact@jeffquast.com>
|
|
92
|
+
|
|
93
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
94
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
95
|
+
in the Software without restriction, including without limitation the rights
|
|
96
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
97
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
98
|
+
furnished to do so, subject to the following conditions:
|
|
99
|
+
|
|
100
|
+
The above copyright notice and this permission notice shall be included in all
|
|
101
|
+
copies or substantial portions of the Software.
|
|
102
|
+
|
|
103
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
104
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
105
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
106
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
107
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
108
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
109
|
+
SOFTWARE.
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Animation — a value for a time, and when it next changes: the one type
|
|
3
|
+
* anything in rich-js that changes with time is an instance of.
|
|
4
|
+
*
|
|
5
|
+
* `at(t)` is the value at `t` seconds. `nextChange(t)` is the first moment,
|
|
6
|
+
* on `t`'s own timeline, at which the value may stop being `at(t)`: never
|
|
7
|
+
* before `t`. A later time says the value is held until then, `Infinity`
|
|
8
|
+
* that it never changes again, and `t` itself that it is moving at `t` — it
|
|
9
|
+
* changes every frame, however close together they are drawn. An early
|
|
10
|
+
* answer costs a host a frame that draws what the last one did; a late one
|
|
11
|
+
* skips a change. So an animation that cannot say answers `t`, as
|
|
12
|
+
* `continuous` does. A value drawn as cells carries this answer on every
|
|
13
|
+
* cell (`Style.nextChange`), so a host holding the composed frame reads it
|
|
14
|
+
* there (`Segment.nextChange`); a value that is not drawn — a number, a
|
|
15
|
+
* colour — has `nextChange` as its only way to say when to look again.
|
|
16
|
+
*
|
|
17
|
+
* `lastChange(t)` is the other end of the same hold: the last moment, never
|
|
18
|
+
* after `t`, at which the value may have become `at(t)` — `-Infinity` if it
|
|
19
|
+
* always was, `t` while it moves. Together they bound the hold, `[lastChange(t),
|
|
20
|
+
* nextChange(t))`, and the answer may be narrower than the truth and never
|
|
21
|
+
* wider. It is what a host running the animation backwards reads
|
|
22
|
+
* (`./timeline.ts`): run down the timeline, the value next changes where it
|
|
23
|
+
* began. An animation that cannot say answers `t` here too.
|
|
24
|
+
*
|
|
25
|
+
* The instances already in the tree: a `Beat` is an animation of which hold
|
|
26
|
+
* is in progress (`./easing.ts`), a `FrameSequence` of the frame shown and a
|
|
27
|
+
* `Spinner` of the spinner drawn (`../renderables/`), and an `Effect` is, for
|
|
28
|
+
* what an element draws in a frame, an animation of how its cells' colours
|
|
29
|
+
* move (`../renderables/effect.ts`). Every kind of motion is one more.
|
|
30
|
+
*
|
|
31
|
+
* [LAW:no-ambient-temporal-coupling] Pure: `t` is an argument and never a
|
|
32
|
+
* clock read (`./clock.ts`), the same `t` gives the same value, nothing is
|
|
33
|
+
* kept between calls, and a call costs the same at `t = 0` and `t = 10⁶`, so
|
|
34
|
+
* a host sampling once a second and one sampling sixty times see the same
|
|
35
|
+
* value at every `t` they share.
|
|
36
|
+
*
|
|
37
|
+
* [LAW:one-type-per-behavior] The combinators here are the ones every kind
|
|
38
|
+
* of motion is built from — a constant, a value moving every moment, a map
|
|
39
|
+
* over the value, several at once, and one animation after another — and each says how
|
|
40
|
+
* `nextChange` composes, so an animation built from them answers it without
|
|
41
|
+
* its author doing anything.
|
|
42
|
+
*/
|
|
43
|
+
/** A value of `T` at a time in seconds, and the first moment that value may change. */
|
|
44
|
+
export interface Animation<T> {
|
|
45
|
+
/** The value at `t` seconds. */
|
|
46
|
+
at(t: number): T;
|
|
47
|
+
/** The first moment, never before `t`, at which the value may stop being `at(t)`: `t` while it moves, `Infinity` once it never will. */
|
|
48
|
+
nextChange(t: number): number;
|
|
49
|
+
/** The last moment, never after `t`, at which the value may have become `at(t)`: `t` while it moves, `-Infinity` if it always was. */
|
|
50
|
+
lastChange(t: number): number;
|
|
51
|
+
}
|
|
52
|
+
export declare const Animation: {
|
|
53
|
+
/** `value` at every time, never changing. */
|
|
54
|
+
constant<T>(value: T): Animation<T>;
|
|
55
|
+
/**
|
|
56
|
+
* The value `at` gives, taken to move at every moment: what an animation
|
|
57
|
+
* that cannot say when it holds still is, so a host draws it every frame.
|
|
58
|
+
*/
|
|
59
|
+
continuous<T>(at: (t: number) => T): Animation<T>;
|
|
60
|
+
/**
|
|
61
|
+
* `animation`'s value through `f`, changing when it does. Two values `f`
|
|
62
|
+
* maps alike make an early answer, which the contract allows.
|
|
63
|
+
*/
|
|
64
|
+
map<T, U>(animation: Animation<T>, f: (value: T) => U): Animation<U>;
|
|
65
|
+
/**
|
|
66
|
+
* Every one of `animations` at once, their values in order, changing when
|
|
67
|
+
* the soonest of them does — so a stack of effects drawn together holds
|
|
68
|
+
* still exactly while each of them does. None never changes.
|
|
69
|
+
*/
|
|
70
|
+
all<T>(animations: readonly Animation<T>[]): Animation<T[]>;
|
|
71
|
+
/**
|
|
72
|
+
* `first` until `seconds`, then `then`, handed the time since it began —
|
|
73
|
+
* each part on its own clock from 0, as every effect is. Before the switch
|
|
74
|
+
* the value next changes when `first`'s does or at the switch, whichever is
|
|
75
|
+
* sooner; after it, when `then`'s does, carried back onto this timeline.
|
|
76
|
+
*/
|
|
77
|
+
sequence<T>(first: Animation<T>, seconds: number, then: Animation<T>): Animation<T>;
|
|
78
|
+
};
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Animation — a value for a time, and when it next changes: the one type
|
|
3
|
+
* anything in rich-js that changes with time is an instance of.
|
|
4
|
+
*
|
|
5
|
+
* `at(t)` is the value at `t` seconds. `nextChange(t)` is the first moment,
|
|
6
|
+
* on `t`'s own timeline, at which the value may stop being `at(t)`: never
|
|
7
|
+
* before `t`. A later time says the value is held until then, `Infinity`
|
|
8
|
+
* that it never changes again, and `t` itself that it is moving at `t` — it
|
|
9
|
+
* changes every frame, however close together they are drawn. An early
|
|
10
|
+
* answer costs a host a frame that draws what the last one did; a late one
|
|
11
|
+
* skips a change. So an animation that cannot say answers `t`, as
|
|
12
|
+
* `continuous` does. A value drawn as cells carries this answer on every
|
|
13
|
+
* cell (`Style.nextChange`), so a host holding the composed frame reads it
|
|
14
|
+
* there (`Segment.nextChange`); a value that is not drawn — a number, a
|
|
15
|
+
* colour — has `nextChange` as its only way to say when to look again.
|
|
16
|
+
*
|
|
17
|
+
* `lastChange(t)` is the other end of the same hold: the last moment, never
|
|
18
|
+
* after `t`, at which the value may have become `at(t)` — `-Infinity` if it
|
|
19
|
+
* always was, `t` while it moves. Together they bound the hold, `[lastChange(t),
|
|
20
|
+
* nextChange(t))`, and the answer may be narrower than the truth and never
|
|
21
|
+
* wider. It is what a host running the animation backwards reads
|
|
22
|
+
* (`./timeline.ts`): run down the timeline, the value next changes where it
|
|
23
|
+
* began. An animation that cannot say answers `t` here too.
|
|
24
|
+
*
|
|
25
|
+
* The instances already in the tree: a `Beat` is an animation of which hold
|
|
26
|
+
* is in progress (`./easing.ts`), a `FrameSequence` of the frame shown and a
|
|
27
|
+
* `Spinner` of the spinner drawn (`../renderables/`), and an `Effect` is, for
|
|
28
|
+
* what an element draws in a frame, an animation of how its cells' colours
|
|
29
|
+
* move (`../renderables/effect.ts`). Every kind of motion is one more.
|
|
30
|
+
*
|
|
31
|
+
* [LAW:no-ambient-temporal-coupling] Pure: `t` is an argument and never a
|
|
32
|
+
* clock read (`./clock.ts`), the same `t` gives the same value, nothing is
|
|
33
|
+
* kept between calls, and a call costs the same at `t = 0` and `t = 10⁶`, so
|
|
34
|
+
* a host sampling once a second and one sampling sixty times see the same
|
|
35
|
+
* value at every `t` they share.
|
|
36
|
+
*
|
|
37
|
+
* [LAW:one-type-per-behavior] The combinators here are the ones every kind
|
|
38
|
+
* of motion is built from — a constant, a value moving every moment, a map
|
|
39
|
+
* over the value, several at once, and one animation after another — and each says how
|
|
40
|
+
* `nextChange` composes, so an animation built from them answers it without
|
|
41
|
+
* its author doing anything.
|
|
42
|
+
*/
|
|
43
|
+
import { firstReaching, positiveSeconds } from "./easing.js";
|
|
44
|
+
export const Animation = {
|
|
45
|
+
/** `value` at every time, never changing. */
|
|
46
|
+
constant(value) {
|
|
47
|
+
return { at: () => value, nextChange: () => Number.POSITIVE_INFINITY, lastChange: () => Number.NEGATIVE_INFINITY };
|
|
48
|
+
},
|
|
49
|
+
/**
|
|
50
|
+
* The value `at` gives, taken to move at every moment: what an animation
|
|
51
|
+
* that cannot say when it holds still is, so a host draws it every frame.
|
|
52
|
+
*/
|
|
53
|
+
continuous(at) {
|
|
54
|
+
return { at, nextChange: (t) => t, lastChange: (t) => t };
|
|
55
|
+
},
|
|
56
|
+
/**
|
|
57
|
+
* `animation`'s value through `f`, changing when it does. Two values `f`
|
|
58
|
+
* maps alike make an early answer, which the contract allows.
|
|
59
|
+
*/
|
|
60
|
+
map(animation, f) {
|
|
61
|
+
return { at: (t) => f(animation.at(t)), nextChange: (t) => animation.nextChange(t), lastChange: (t) => animation.lastChange(t) };
|
|
62
|
+
},
|
|
63
|
+
/**
|
|
64
|
+
* Every one of `animations` at once, their values in order, changing when
|
|
65
|
+
* the soonest of them does — so a stack of effects drawn together holds
|
|
66
|
+
* still exactly while each of them does. None never changes.
|
|
67
|
+
*/
|
|
68
|
+
all(animations) {
|
|
69
|
+
return {
|
|
70
|
+
at: (t) => animations.map((animation) => animation.at(t)),
|
|
71
|
+
nextChange: (t) => Math.min(...animations.map((animation) => animation.nextChange(t))),
|
|
72
|
+
lastChange: (t) => Math.max(...animations.map((animation) => animation.lastChange(t))),
|
|
73
|
+
};
|
|
74
|
+
},
|
|
75
|
+
/**
|
|
76
|
+
* `first` until `seconds`, then `then`, handed the time since it began —
|
|
77
|
+
* each part on its own clock from 0, as every effect is. Before the switch
|
|
78
|
+
* the value next changes when `first`'s does or at the switch, whichever is
|
|
79
|
+
* sooner; after it, when `then`'s does, carried back onto this timeline.
|
|
80
|
+
*/
|
|
81
|
+
sequence(first, seconds, then) {
|
|
82
|
+
positiveSeconds("Animation.sequence seconds", seconds);
|
|
83
|
+
// `then`'s moment `local`, on its own clock, carried back onto this
|
|
84
|
+
// timeline: the first moment whose time since the switch reaches
|
|
85
|
+
// `local`, which the sum `local + seconds` can round to either side of —
|
|
86
|
+
// under it, where `at` still shows the old value, or over it, a float
|
|
87
|
+
// after the change showed.
|
|
88
|
+
const carried = (local) => (Number.isFinite(local) ? firstReaching(local + seconds, (x) => x - seconds >= local) : local);
|
|
89
|
+
return {
|
|
90
|
+
at: (t) => (t - seconds >= 0 ? then.at(t - seconds) : first.at(t)),
|
|
91
|
+
nextChange(t) {
|
|
92
|
+
const into = t - seconds;
|
|
93
|
+
if (into < 0)
|
|
94
|
+
return Math.min(first.nextChange(t), seconds);
|
|
95
|
+
return Math.max(t, carried(then.nextChange(into)));
|
|
96
|
+
},
|
|
97
|
+
// After the switch the value became what it is at the switch or when
|
|
98
|
+
// `then`'s did since, whichever is later; before it, when `first`'s did.
|
|
99
|
+
lastChange(t) {
|
|
100
|
+
const into = t - seconds;
|
|
101
|
+
if (into < 0)
|
|
102
|
+
return first.lastChange(t);
|
|
103
|
+
return Math.min(t, Math.max(seconds, carried(then.lastChange(into))));
|
|
104
|
+
},
|
|
105
|
+
};
|
|
106
|
+
},
|
|
107
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The cells Rich's `cell_len` gives each code point, and the code points VS16
|
|
3
|
+
* widens. Generated by scripts/cell-widths.py from Rich 15.0.0's Unicode 17.0.0
|
|
4
|
+
* table, which Rich builds from wcwidth's data; regenerate rather than edit.
|
|
5
|
+
*/
|
|
6
|
+
/** The cells Rich gives `codePoint` on its own: none for a C0 or C1 control. */
|
|
7
|
+
export declare function codePointWidth(codePoint: number): 0 | 1 | 2;
|
|
8
|
+
/** Whether VS16 after `codePoint` widens it from one cell to two. */
|
|
9
|
+
export declare function widensToEmoji(codePoint: number): boolean;
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The cells Rich's `cell_len` gives each code point, and the code points VS16
|
|
3
|
+
* widens. Generated by scripts/cell-widths.py from Rich 15.0.0's Unicode 17.0.0
|
|
4
|
+
* table, which Rich builds from wcwidth's data; regenerate rather than edit.
|
|
5
|
+
*/
|
|
6
|
+
// Every range of code points that does not take one cell, as [first, last,
|
|
7
|
+
// cells]: ascending, disjoint, adjacent ranges of one width merged.
|
|
8
|
+
const RANGES = [
|
|
9
|
+
[0x0, 0x0, 0], [0x300, 0x36f, 0], [0x483, 0x489, 0], [0x591, 0x5bd, 0], [0x5bf, 0x5bf, 0], [0x5c1, 0x5c2, 0],
|
|
10
|
+
[0x5c4, 0x5c5, 0], [0x5c7, 0x5c7, 0], [0x610, 0x61a, 0], [0x61c, 0x61c, 0], [0x64b, 0x65f, 0], [0x670, 0x670, 0],
|
|
11
|
+
[0x6d6, 0x6dc, 0], [0x6df, 0x6e4, 0], [0x6e7, 0x6e8, 0], [0x6ea, 0x6ed, 0], [0x711, 0x711, 0], [0x730, 0x74a, 0],
|
|
12
|
+
[0x7a6, 0x7b0, 0], [0x7eb, 0x7f3, 0], [0x7fd, 0x7fd, 0], [0x816, 0x819, 0], [0x81b, 0x823, 0], [0x825, 0x827, 0],
|
|
13
|
+
[0x829, 0x82d, 0], [0x859, 0x85b, 0], [0x897, 0x89f, 0], [0x8ca, 0x8e1, 0], [0x8e3, 0x903, 0], [0x93a, 0x93c, 0],
|
|
14
|
+
[0x93e, 0x94f, 0], [0x951, 0x957, 0], [0x962, 0x963, 0], [0x981, 0x983, 0], [0x9bc, 0x9bc, 0], [0x9be, 0x9c4, 0],
|
|
15
|
+
[0x9c7, 0x9c8, 0], [0x9cb, 0x9cd, 0], [0x9d7, 0x9d7, 0], [0x9e2, 0x9e3, 0], [0x9fe, 0x9fe, 0], [0xa01, 0xa03, 0],
|
|
16
|
+
[0xa3c, 0xa3c, 0], [0xa3e, 0xa42, 0], [0xa47, 0xa48, 0], [0xa4b, 0xa4d, 0], [0xa51, 0xa51, 0], [0xa70, 0xa71, 0],
|
|
17
|
+
[0xa75, 0xa75, 0], [0xa81, 0xa83, 0], [0xabc, 0xabc, 0], [0xabe, 0xac5, 0], [0xac7, 0xac9, 0], [0xacb, 0xacd, 0],
|
|
18
|
+
[0xae2, 0xae3, 0], [0xafa, 0xaff, 0], [0xb01, 0xb03, 0], [0xb3c, 0xb3c, 0], [0xb3e, 0xb44, 0], [0xb47, 0xb48, 0],
|
|
19
|
+
[0xb4b, 0xb4d, 0], [0xb55, 0xb57, 0], [0xb62, 0xb63, 0], [0xb82, 0xb82, 0], [0xbbe, 0xbc2, 0], [0xbc6, 0xbc8, 0],
|
|
20
|
+
[0xbca, 0xbcd, 0], [0xbd7, 0xbd7, 0], [0xc00, 0xc04, 0], [0xc3c, 0xc3c, 0], [0xc3e, 0xc44, 0], [0xc46, 0xc48, 0],
|
|
21
|
+
[0xc4a, 0xc4d, 0], [0xc55, 0xc56, 0], [0xc62, 0xc63, 0], [0xc81, 0xc83, 0], [0xcbc, 0xcbc, 0], [0xcbe, 0xcc4, 0],
|
|
22
|
+
[0xcc6, 0xcc8, 0], [0xcca, 0xccd, 0], [0xcd5, 0xcd6, 0], [0xce2, 0xce3, 0], [0xcf3, 0xcf3, 0], [0xd00, 0xd03, 0],
|
|
23
|
+
[0xd3b, 0xd3c, 0], [0xd3e, 0xd44, 0], [0xd46, 0xd48, 0], [0xd4a, 0xd4d, 0], [0xd57, 0xd57, 0], [0xd62, 0xd63, 0],
|
|
24
|
+
[0xd81, 0xd83, 0], [0xdca, 0xdca, 0], [0xdcf, 0xdd4, 0], [0xdd6, 0xdd6, 0], [0xdd8, 0xddf, 0], [0xdf2, 0xdf3, 0],
|
|
25
|
+
[0xe31, 0xe31, 0], [0xe34, 0xe3a, 0], [0xe47, 0xe4e, 0], [0xeb1, 0xeb1, 0], [0xeb4, 0xebc, 0], [0xec8, 0xece, 0],
|
|
26
|
+
[0xf18, 0xf19, 0], [0xf35, 0xf35, 0], [0xf37, 0xf37, 0], [0xf39, 0xf39, 0], [0xf3e, 0xf3f, 0], [0xf71, 0xf84, 0],
|
|
27
|
+
[0xf86, 0xf87, 0], [0xf8d, 0xf97, 0], [0xf99, 0xfbc, 0], [0xfc6, 0xfc6, 0], [0x102b, 0x103e, 0], [0x1056, 0x1059, 0],
|
|
28
|
+
[0x105e, 0x1060, 0], [0x1062, 0x1064, 0], [0x1067, 0x106d, 0], [0x1071, 0x1074, 0], [0x1082, 0x108d, 0],
|
|
29
|
+
[0x108f, 0x108f, 0], [0x109a, 0x109d, 0], [0x1100, 0x115f, 2], [0x1160, 0x11ff, 0], [0x135d, 0x135f, 0],
|
|
30
|
+
[0x1712, 0x1715, 0], [0x1732, 0x1734, 0], [0x1752, 0x1753, 0], [0x1772, 0x1773, 0], [0x17b4, 0x17d3, 0],
|
|
31
|
+
[0x17dd, 0x17dd, 0], [0x180b, 0x180f, 0], [0x1885, 0x1886, 0], [0x18a9, 0x18a9, 0], [0x1920, 0x192b, 0],
|
|
32
|
+
[0x1930, 0x193b, 0], [0x1a17, 0x1a1b, 0], [0x1a55, 0x1a5e, 0], [0x1a60, 0x1a7c, 0], [0x1a7f, 0x1a7f, 0],
|
|
33
|
+
[0x1ab0, 0x1add, 0], [0x1ae0, 0x1aeb, 0], [0x1b00, 0x1b04, 0], [0x1b34, 0x1b44, 0], [0x1b6b, 0x1b73, 0],
|
|
34
|
+
[0x1b80, 0x1b82, 0], [0x1ba1, 0x1bad, 0], [0x1be6, 0x1bf3, 0], [0x1c24, 0x1c37, 0], [0x1cd0, 0x1cd2, 0],
|
|
35
|
+
[0x1cd4, 0x1ce8, 0], [0x1ced, 0x1ced, 0], [0x1cf4, 0x1cf4, 0], [0x1cf7, 0x1cf9, 0], [0x1dc0, 0x1dff, 0],
|
|
36
|
+
[0x200b, 0x200f, 0], [0x2028, 0x202e, 0], [0x2060, 0x206f, 0], [0x20d0, 0x20f0, 0], [0x231a, 0x231b, 2],
|
|
37
|
+
[0x2329, 0x232a, 2], [0x23e9, 0x23ec, 2], [0x23f0, 0x23f0, 2], [0x23f3, 0x23f3, 2], [0x25fd, 0x25fe, 2],
|
|
38
|
+
[0x2614, 0x2615, 2], [0x2630, 0x2637, 2], [0x2648, 0x2653, 2], [0x267f, 0x267f, 2], [0x268a, 0x268f, 2],
|
|
39
|
+
[0x2693, 0x2693, 2], [0x26a1, 0x26a1, 2], [0x26aa, 0x26ab, 2], [0x26bd, 0x26be, 2], [0x26c4, 0x26c5, 2],
|
|
40
|
+
[0x26ce, 0x26ce, 2], [0x26d4, 0x26d4, 2], [0x26ea, 0x26ea, 2], [0x26f2, 0x26f3, 2], [0x26f5, 0x26f5, 2],
|
|
41
|
+
[0x26fa, 0x26fa, 2], [0x26fd, 0x26fd, 2], [0x2705, 0x2705, 2], [0x270a, 0x270b, 2], [0x2728, 0x2728, 2],
|
|
42
|
+
[0x274c, 0x274c, 2], [0x274e, 0x274e, 2], [0x2753, 0x2755, 2], [0x2757, 0x2757, 2], [0x2795, 0x2797, 2],
|
|
43
|
+
[0x27b0, 0x27b0, 2], [0x27bf, 0x27bf, 2], [0x2b1b, 0x2b1c, 2], [0x2b50, 0x2b50, 2], [0x2b55, 0x2b55, 2],
|
|
44
|
+
[0x2cef, 0x2cf1, 0], [0x2d7f, 0x2d7f, 0], [0x2de0, 0x2dff, 0], [0x2e80, 0x2e99, 2], [0x2e9b, 0x2ef3, 2],
|
|
45
|
+
[0x2f00, 0x2fd5, 2], [0x2ff0, 0x3029, 2], [0x302a, 0x302f, 0], [0x3030, 0x303e, 2], [0x3041, 0x3096, 2],
|
|
46
|
+
[0x3099, 0x309a, 0], [0x309b, 0x30ff, 2], [0x3105, 0x312f, 2], [0x3131, 0x3163, 2], [0x3164, 0x3164, 0],
|
|
47
|
+
[0x3165, 0x318e, 2], [0x3190, 0x31e5, 2], [0x31ef, 0x321e, 2], [0x3220, 0x3247, 2], [0x3250, 0xa48c, 2],
|
|
48
|
+
[0xa490, 0xa4c6, 2], [0xa66f, 0xa672, 0], [0xa674, 0xa67d, 0], [0xa69e, 0xa69f, 0], [0xa6f0, 0xa6f1, 0],
|
|
49
|
+
[0xa802, 0xa802, 0], [0xa806, 0xa806, 0], [0xa80b, 0xa80b, 0], [0xa823, 0xa827, 0], [0xa82c, 0xa82c, 0],
|
|
50
|
+
[0xa880, 0xa881, 0], [0xa8b4, 0xa8c5, 0], [0xa8e0, 0xa8f1, 0], [0xa8ff, 0xa8ff, 0], [0xa926, 0xa92d, 0],
|
|
51
|
+
[0xa947, 0xa953, 0], [0xa960, 0xa97c, 2], [0xa980, 0xa983, 0], [0xa9b3, 0xa9c0, 0], [0xa9e5, 0xa9e5, 0],
|
|
52
|
+
[0xaa29, 0xaa36, 0], [0xaa43, 0xaa43, 0], [0xaa4c, 0xaa4d, 0], [0xaa7b, 0xaa7d, 0], [0xaab0, 0xaab0, 0],
|
|
53
|
+
[0xaab2, 0xaab4, 0], [0xaab7, 0xaab8, 0], [0xaabe, 0xaabf, 0], [0xaac1, 0xaac1, 0], [0xaaeb, 0xaaef, 0],
|
|
54
|
+
[0xaaf5, 0xaaf6, 0], [0xabe3, 0xabea, 0], [0xabec, 0xabed, 0], [0xac00, 0xd7a3, 2], [0xd7b0, 0xd7ff, 0],
|
|
55
|
+
[0xf900, 0xfaff, 2], [0xfb1e, 0xfb1e, 0], [0xfe00, 0xfe0f, 0], [0xfe10, 0xfe19, 2], [0xfe20, 0xfe2f, 0],
|
|
56
|
+
[0xfe30, 0xfe52, 2], [0xfe54, 0xfe66, 2], [0xfe68, 0xfe6b, 2], [0xfeff, 0xfeff, 0], [0xff01, 0xff60, 2],
|
|
57
|
+
[0xffa0, 0xffa0, 0], [0xffe0, 0xffe6, 2], [0xfff0, 0xfffb, 0], [0x101fd, 0x101fd, 0], [0x102e0, 0x102e0, 0],
|
|
58
|
+
[0x10376, 0x1037a, 0], [0x10a01, 0x10a03, 0], [0x10a05, 0x10a06, 0], [0x10a0c, 0x10a0f, 0], [0x10a38, 0x10a3a, 0],
|
|
59
|
+
[0x10a3f, 0x10a3f, 0], [0x10ae5, 0x10ae6, 0], [0x10d24, 0x10d27, 0], [0x10d69, 0x10d6d, 0], [0x10eab, 0x10eac, 0],
|
|
60
|
+
[0x10efa, 0x10eff, 0], [0x10f46, 0x10f50, 0], [0x10f82, 0x10f85, 0], [0x11000, 0x11002, 0], [0x11038, 0x11046, 0],
|
|
61
|
+
[0x11070, 0x11070, 0], [0x11073, 0x11074, 0], [0x1107f, 0x11082, 0], [0x110b0, 0x110ba, 0], [0x110c2, 0x110c2, 0],
|
|
62
|
+
[0x11100, 0x11102, 0], [0x11127, 0x11134, 0], [0x11145, 0x11146, 0], [0x11173, 0x11173, 0], [0x11180, 0x11182, 0],
|
|
63
|
+
[0x111b3, 0x111c0, 0], [0x111c9, 0x111cc, 0], [0x111ce, 0x111cf, 0], [0x1122c, 0x11237, 0], [0x1123e, 0x1123e, 0],
|
|
64
|
+
[0x11241, 0x11241, 0], [0x112df, 0x112ea, 0], [0x11300, 0x11303, 0], [0x1133b, 0x1133c, 0], [0x1133e, 0x11344, 0],
|
|
65
|
+
[0x11347, 0x11348, 0], [0x1134b, 0x1134d, 0], [0x11357, 0x11357, 0], [0x11362, 0x11363, 0], [0x11366, 0x1136c, 0],
|
|
66
|
+
[0x11370, 0x11374, 0], [0x113b8, 0x113c0, 0], [0x113c2, 0x113c2, 0], [0x113c5, 0x113c5, 0], [0x113c7, 0x113ca, 0],
|
|
67
|
+
[0x113cc, 0x113d0, 0], [0x113d2, 0x113d2, 0], [0x113e1, 0x113e2, 0], [0x11435, 0x11446, 0], [0x1145e, 0x1145e, 0],
|
|
68
|
+
[0x114b0, 0x114c3, 0], [0x115af, 0x115b5, 0], [0x115b8, 0x115c0, 0], [0x115dc, 0x115dd, 0], [0x11630, 0x11640, 0],
|
|
69
|
+
[0x116ab, 0x116b7, 0], [0x1171d, 0x1172b, 0], [0x1182c, 0x1183a, 0], [0x11930, 0x11935, 0], [0x11937, 0x11938, 0],
|
|
70
|
+
[0x1193b, 0x1193e, 0], [0x11940, 0x11940, 0], [0x11942, 0x11943, 0], [0x119d1, 0x119d7, 0], [0x119da, 0x119e0, 0],
|
|
71
|
+
[0x119e4, 0x119e4, 0], [0x11a01, 0x11a0a, 0], [0x11a33, 0x11a39, 0], [0x11a3b, 0x11a3e, 0], [0x11a47, 0x11a47, 0],
|
|
72
|
+
[0x11a51, 0x11a5b, 0], [0x11a8a, 0x11a99, 0], [0x11b60, 0x11b67, 0], [0x11c2f, 0x11c36, 0], [0x11c38, 0x11c3f, 0],
|
|
73
|
+
[0x11c92, 0x11ca7, 0], [0x11ca9, 0x11cb6, 0], [0x11d31, 0x11d36, 0], [0x11d3a, 0x11d3a, 0], [0x11d3c, 0x11d3d, 0],
|
|
74
|
+
[0x11d3f, 0x11d45, 0], [0x11d47, 0x11d47, 0], [0x11d8a, 0x11d8e, 0], [0x11d90, 0x11d91, 0], [0x11d93, 0x11d97, 0],
|
|
75
|
+
[0x11ef3, 0x11ef6, 0], [0x11f00, 0x11f01, 0], [0x11f03, 0x11f03, 0], [0x11f34, 0x11f3a, 0], [0x11f3e, 0x11f42, 0],
|
|
76
|
+
[0x11f5a, 0x11f5a, 0], [0x13430, 0x13440, 0], [0x13447, 0x13455, 0], [0x1611e, 0x1612f, 0], [0x16af0, 0x16af4, 0],
|
|
77
|
+
[0x16b30, 0x16b36, 0], [0x16f4f, 0x16f4f, 0], [0x16f51, 0x16f87, 0], [0x16f8f, 0x16f92, 0], [0x16fe0, 0x16fe3, 2],
|
|
78
|
+
[0x16fe4, 0x16fe4, 0], [0x16ff0, 0x16ff1, 0], [0x16ff2, 0x16ff6, 2], [0x17000, 0x18cd5, 2], [0x18cff, 0x18d1e, 2],
|
|
79
|
+
[0x18d80, 0x18df2, 2], [0x1aff0, 0x1aff3, 2], [0x1aff5, 0x1affb, 2], [0x1affd, 0x1affe, 2], [0x1b000, 0x1b122, 2],
|
|
80
|
+
[0x1b132, 0x1b132, 2], [0x1b150, 0x1b152, 2], [0x1b155, 0x1b155, 2], [0x1b164, 0x1b167, 2], [0x1b170, 0x1b2fb, 2],
|
|
81
|
+
[0x1bc9d, 0x1bc9e, 0], [0x1bca0, 0x1bca3, 0], [0x1cf00, 0x1cf2d, 0], [0x1cf30, 0x1cf46, 0], [0x1d165, 0x1d169, 0],
|
|
82
|
+
[0x1d16d, 0x1d182, 0], [0x1d185, 0x1d18b, 0], [0x1d1aa, 0x1d1ad, 0], [0x1d242, 0x1d244, 0], [0x1d300, 0x1d356, 2],
|
|
83
|
+
[0x1d360, 0x1d376, 2], [0x1da00, 0x1da36, 0], [0x1da3b, 0x1da6c, 0], [0x1da75, 0x1da75, 0], [0x1da84, 0x1da84, 0],
|
|
84
|
+
[0x1da9b, 0x1da9f, 0], [0x1daa1, 0x1daaf, 0], [0x1e000, 0x1e006, 0], [0x1e008, 0x1e018, 0], [0x1e01b, 0x1e021, 0],
|
|
85
|
+
[0x1e023, 0x1e024, 0], [0x1e026, 0x1e02a, 0], [0x1e08f, 0x1e08f, 0], [0x1e130, 0x1e136, 0], [0x1e2ae, 0x1e2ae, 0],
|
|
86
|
+
[0x1e2ec, 0x1e2ef, 0], [0x1e4ec, 0x1e4ef, 0], [0x1e5ee, 0x1e5ef, 0], [0x1e6e3, 0x1e6e3, 0], [0x1e6e6, 0x1e6e6, 0],
|
|
87
|
+
[0x1e6ee, 0x1e6ef, 0], [0x1e6f5, 0x1e6f5, 0], [0x1e8d0, 0x1e8d6, 0], [0x1e944, 0x1e94a, 0], [0x1f004, 0x1f004, 2],
|
|
88
|
+
[0x1f0cf, 0x1f0cf, 2], [0x1f18e, 0x1f18e, 2], [0x1f191, 0x1f19a, 2], [0x1f200, 0x1f202, 2], [0x1f210, 0x1f23b, 2],
|
|
89
|
+
[0x1f240, 0x1f248, 2], [0x1f250, 0x1f251, 2], [0x1f260, 0x1f265, 2], [0x1f300, 0x1f320, 2], [0x1f32d, 0x1f335, 2],
|
|
90
|
+
[0x1f337, 0x1f37c, 2], [0x1f37e, 0x1f393, 2], [0x1f3a0, 0x1f3ca, 2], [0x1f3cf, 0x1f3d3, 2], [0x1f3e0, 0x1f3f0, 2],
|
|
91
|
+
[0x1f3f4, 0x1f3f4, 2], [0x1f3f8, 0x1f3fa, 2], [0x1f3fb, 0x1f3ff, 0], [0x1f400, 0x1f43e, 2], [0x1f440, 0x1f440, 2],
|
|
92
|
+
[0x1f442, 0x1f4fc, 2], [0x1f4ff, 0x1f53d, 2], [0x1f54b, 0x1f54e, 2], [0x1f550, 0x1f567, 2], [0x1f57a, 0x1f57a, 2],
|
|
93
|
+
[0x1f595, 0x1f596, 2], [0x1f5a4, 0x1f5a4, 2], [0x1f5fb, 0x1f64f, 2], [0x1f680, 0x1f6c5, 2], [0x1f6cc, 0x1f6cc, 2],
|
|
94
|
+
[0x1f6d0, 0x1f6d2, 2], [0x1f6d5, 0x1f6d8, 2], [0x1f6dc, 0x1f6df, 2], [0x1f6eb, 0x1f6ec, 2], [0x1f6f4, 0x1f6fc, 2],
|
|
95
|
+
[0x1f7e0, 0x1f7eb, 2], [0x1f7f0, 0x1f7f0, 2], [0x1f90c, 0x1f93a, 2], [0x1f93c, 0x1f945, 2], [0x1f947, 0x1f9ff, 2],
|
|
96
|
+
[0x1fa70, 0x1fa7c, 2], [0x1fa80, 0x1fa8a, 2], [0x1fa8e, 0x1fac6, 2], [0x1fac8, 0x1fac8, 2], [0x1facd, 0x1fadc, 2],
|
|
97
|
+
[0x1fadf, 0x1faea, 2], [0x1faef, 0x1faf8, 2], [0x20000, 0x2fffd, 2], [0x30000, 0x3fffd, 2], [0xe0000, 0xe0fff, 0],
|
|
98
|
+
];
|
|
99
|
+
// The code points one cell wide on their own and two when VARIATION SELECTOR-16
|
|
100
|
+
// asks for emoji presentation.
|
|
101
|
+
const NARROW_TO_WIDE = new Set([
|
|
102
|
+
0x23, 0x2a, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0xa9, 0xae, 0x203c, 0x2049, 0x2122, 0x2139,
|
|
103
|
+
0x2194, 0x2195, 0x2196, 0x2197, 0x2198, 0x2199, 0x21a9, 0x21aa, 0x2328, 0x23cf, 0x23ed, 0x23ee, 0x23ef, 0x23f1,
|
|
104
|
+
0x23f2, 0x23f8, 0x23f9, 0x23fa, 0x24c2, 0x25aa, 0x25ab, 0x25b6, 0x25c0, 0x25fb, 0x25fc, 0x2600, 0x2601, 0x2602,
|
|
105
|
+
0x2603, 0x2604, 0x260e, 0x2611, 0x2618, 0x261d, 0x2620, 0x2622, 0x2623, 0x2626, 0x262a, 0x262e, 0x262f, 0x2638,
|
|
106
|
+
0x2639, 0x263a, 0x2640, 0x2642, 0x265f, 0x2660, 0x2663, 0x2665, 0x2666, 0x2668, 0x267b, 0x267e, 0x2692, 0x2694,
|
|
107
|
+
0x2695, 0x2696, 0x2697, 0x2699, 0x269b, 0x269c, 0x26a0, 0x26a7, 0x26b0, 0x26b1, 0x26c8, 0x26cf, 0x26d1, 0x26d3,
|
|
108
|
+
0x26e9, 0x26f0, 0x26f1, 0x26f4, 0x26f7, 0x26f8, 0x26f9, 0x2702, 0x2708, 0x2709, 0x270c, 0x270d, 0x270f, 0x2712,
|
|
109
|
+
0x2714, 0x2716, 0x271d, 0x2721, 0x2733, 0x2734, 0x2744, 0x2747, 0x2763, 0x2764, 0x27a1, 0x2934, 0x2935, 0x2b05,
|
|
110
|
+
0x2b06, 0x2b07, 0x1f170, 0x1f171, 0x1f17e, 0x1f17f, 0x1f321, 0x1f324, 0x1f325, 0x1f326, 0x1f327, 0x1f328, 0x1f329,
|
|
111
|
+
0x1f32a, 0x1f32b, 0x1f32c, 0x1f336, 0x1f37d, 0x1f396, 0x1f397, 0x1f399, 0x1f39a, 0x1f39b, 0x1f39e, 0x1f39f, 0x1f3cb,
|
|
112
|
+
0x1f3cc, 0x1f3cd, 0x1f3ce, 0x1f3d4, 0x1f3d5, 0x1f3d6, 0x1f3d7, 0x1f3d8, 0x1f3d9, 0x1f3da, 0x1f3db, 0x1f3dc, 0x1f3dd,
|
|
113
|
+
0x1f3de, 0x1f3df, 0x1f3f3, 0x1f3f5, 0x1f3f7, 0x1f43f, 0x1f441, 0x1f4fd, 0x1f549, 0x1f54a, 0x1f56f, 0x1f570, 0x1f573,
|
|
114
|
+
0x1f574, 0x1f575, 0x1f576, 0x1f577, 0x1f578, 0x1f579, 0x1f587, 0x1f58a, 0x1f58b, 0x1f58c, 0x1f58d, 0x1f590, 0x1f5a5,
|
|
115
|
+
0x1f5a8, 0x1f5b1, 0x1f5b2, 0x1f5bc, 0x1f5c2, 0x1f5c3, 0x1f5c4, 0x1f5d1, 0x1f5d2, 0x1f5d3, 0x1f5dc, 0x1f5dd, 0x1f5de,
|
|
116
|
+
0x1f5e1, 0x1f5e3, 0x1f5e8, 0x1f5ef, 0x1f5f3, 0x1f5fa, 0x1f6cb, 0x1f6cd, 0x1f6ce, 0x1f6cf, 0x1f6e0, 0x1f6e1, 0x1f6e2,
|
|
117
|
+
0x1f6e3, 0x1f6e4, 0x1f6e5, 0x1f6e9, 0x1f6f0, 0x1f6f3,
|
|
118
|
+
]);
|
|
119
|
+
/** The cells Rich gives `codePoint` on its own: none for a C0 or C1 control. */
|
|
120
|
+
export function codePointWidth(codePoint) {
|
|
121
|
+
if (codePoint < 0x20 || (codePoint >= 0x7f && codePoint < 0xa0))
|
|
122
|
+
return 0;
|
|
123
|
+
let low = 0;
|
|
124
|
+
let high = RANGES.length - 1;
|
|
125
|
+
while (low <= high) {
|
|
126
|
+
const mid = (low + high) >> 1;
|
|
127
|
+
const [first, last, cells] = RANGES[mid];
|
|
128
|
+
if (codePoint < first)
|
|
129
|
+
high = mid - 1;
|
|
130
|
+
else if (codePoint > last)
|
|
131
|
+
low = mid + 1;
|
|
132
|
+
else
|
|
133
|
+
return cells;
|
|
134
|
+
}
|
|
135
|
+
return 1;
|
|
136
|
+
}
|
|
137
|
+
/** Whether VS16 after `codePoint` widens it from one cell to two. */
|
|
138
|
+
export function widensToEmoji(codePoint) {
|
|
139
|
+
return NARROW_TO_WIDE.has(codePoint);
|
|
140
|
+
}
|
package/dist/core/cells.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Terminal cell width calculation.
|
|
3
|
-
* Handles ASCII, CJK (double-width), and emoji characters.
|
|
2
|
+
* Terminal cell width calculation: Rich's `cell_len`, ported.
|
|
4
3
|
*/
|
|
5
4
|
/**
|
|
6
5
|
* Returns the terminal cell width of a string.
|
|
@@ -72,13 +71,20 @@ export declare function setCellSize(text: string, totalWidth: CellCol): string;
|
|
|
72
71
|
*/
|
|
73
72
|
export declare function splitText(text: string, position: CellCol): [string, string];
|
|
74
73
|
/**
|
|
75
|
-
* Cuts `text`
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
*
|
|
74
|
+
* Cuts `text` at each of `positions`, as the reference's `Segment.split_cells`
|
|
75
|
+
* cuts at one: a wide glyph a cut goes through fits neither side, so it leaves
|
|
76
|
+
* a space in each of its cells, where `splitText` keeps it whole on the right.
|
|
77
|
+
* Every other character lands in exactly one piece, so each piece is exactly
|
|
78
|
+
* as wide as the distance between its cuts. `positions` are non-decreasing and
|
|
79
|
+
* fall inside `text`: from 0 to one short of its width.
|
|
80
|
+
*
|
|
81
|
+
* One walk over `text` however many positions there are, ending at the last
|
|
82
|
+
* of them: cutting what is left again at every position re-measures and copies
|
|
83
|
+
* the rest each time, which is quadratic in a long enough string, and walking
|
|
84
|
+
* past the last position makes one cut near the start of a long string pay for
|
|
85
|
+
* all of it.
|
|
80
86
|
*/
|
|
81
|
-
export declare function cutCells(text: string,
|
|
87
|
+
export declare function cutCells(text: string, positions: readonly CellCol[]): string[];
|
|
82
88
|
/**
|
|
83
89
|
* Wraps text into lines of at most `maxWidth` cells, preserving every code
|
|
84
90
|
* point: `chopCells(t, w).join("") === t`. Unlike `splitText` this never pads,
|
|
@@ -97,9 +103,9 @@ export declare function chopCells(text: string, maxWidth: CellCol): string[];
|
|
|
97
103
|
*/
|
|
98
104
|
export declare function splitAtCells(line: string, cuts: readonly CellCol[]): string[];
|
|
99
105
|
/**
|
|
100
|
-
* The grapheme clusters of `text`, in order: the unit `
|
|
101
|
-
*
|
|
102
|
-
*
|
|
106
|
+
* The grapheme clusters of `text`, in order: the unit `cellLen` of a whole
|
|
107
|
+
* string is the sum of. Summing `cellLen` over code points instead disagrees
|
|
108
|
+
* with it on every glyph built from several:
|
|
103
109
|
* `❤️` is 1 + 0 by code point and 2 as a cluster, `👨👩👧` is 6 and 2, and a cut
|
|
104
110
|
* between two of its code points leaves half a glyph.
|
|
105
111
|
*/
|
package/dist/core/cells.js
CHANGED
|
@@ -1,11 +1,57 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Terminal cell width calculation.
|
|
3
|
-
* Handles ASCII, CJK (double-width), and emoji characters.
|
|
2
|
+
* Terminal cell width calculation: Rich's `cell_len`, ported.
|
|
4
3
|
*/
|
|
5
|
-
import
|
|
4
|
+
import { codePointWidth, widensToEmoji } from "./cell-widths.js";
|
|
6
5
|
import { Memo } from "./memo.js";
|
|
7
|
-
// [LAW:one-source-of-truth] string-width is the single authority for cell width
|
|
8
6
|
const cellLenMemo = new Memo();
|
|
7
|
+
const ZWJ = 0x200d;
|
|
8
|
+
const VS16 = 0xfe0f;
|
|
9
|
+
const JOINERS = /[\u200d\ufe0f]/;
|
|
10
|
+
const PRINTABLE_ASCII = /^[ -~]*$/;
|
|
11
|
+
// Rich's `cell_len` over a run of text: each code point the cells Rich's table
|
|
12
|
+
// gives it, but that a ZWJ takes the code point after it into the glyph before
|
|
13
|
+
// so neither adds a cell, and VS16 widens the last code point measured to two
|
|
14
|
+
// cells when the table lists it as one that emoji presentation widens.
|
|
15
|
+
function richCells(text) {
|
|
16
|
+
let cells = 0;
|
|
17
|
+
let widenable = false;
|
|
18
|
+
let joined = false;
|
|
19
|
+
for (const ch of text) {
|
|
20
|
+
const codePoint = ch.codePointAt(0);
|
|
21
|
+
if (joined) {
|
|
22
|
+
joined = false;
|
|
23
|
+
}
|
|
24
|
+
else if (codePoint === ZWJ) {
|
|
25
|
+
joined = true;
|
|
26
|
+
}
|
|
27
|
+
else if (codePoint === VS16) {
|
|
28
|
+
cells += widenable ? 1 : 0;
|
|
29
|
+
widenable = false;
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
const width = codePointWidth(codePoint);
|
|
33
|
+
cells += width;
|
|
34
|
+
widenable = width > 0 ? widensToEmoji(codePoint) : widenable;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return cells;
|
|
38
|
+
}
|
|
39
|
+
// [LAW:one-source-of-truth] the single authority for cell width. A string is
|
|
40
|
+
// the sum of its grapheme clusters, each measured as Rich measures it, so a cut
|
|
41
|
+
// between clusters splits the width exactly; the two part only where a ZWJ or
|
|
42
|
+
// VS16 reaches across a cluster boundary, as in `a` ZWJ `b`, which Rich counts
|
|
43
|
+
// as one cell and two clusters count as two. Without either, every code point
|
|
44
|
+
// counts alone and no segmentation is needed.
|
|
45
|
+
function measure(text) {
|
|
46
|
+
if (PRINTABLE_ASCII.test(text))
|
|
47
|
+
return text.length;
|
|
48
|
+
if (!JOINERS.test(text))
|
|
49
|
+
return richCells(text);
|
|
50
|
+
let cells = 0;
|
|
51
|
+
for (const { segment } of graphemeSegmenter().segment(text))
|
|
52
|
+
cells += richCells(segment);
|
|
53
|
+
return cells;
|
|
54
|
+
}
|
|
9
55
|
/**
|
|
10
56
|
* Returns the terminal cell width of a string.
|
|
11
57
|
*/
|
|
@@ -13,7 +59,7 @@ export function cellLen(text) {
|
|
|
13
59
|
if (text.length === 0)
|
|
14
60
|
return 0;
|
|
15
61
|
// Short strings recur (words, cells, labels); a long one is rarely measured twice.
|
|
16
|
-
return text.length <= 64 ? cellLenMemo.get(text,
|
|
62
|
+
return text.length <= 64 ? cellLenMemo.get(text, measure) : measure(text);
|
|
17
63
|
}
|
|
18
64
|
/** Brand a raw number as a CellCol. Use only at trust boundaries. */
|
|
19
65
|
export function asCellCol(n) { return n; }
|
|
@@ -82,22 +128,49 @@ export function splitText(text, position) {
|
|
|
82
128
|
return [left + " ".repeat(position - cellLen(left)), text.slice(left.length)];
|
|
83
129
|
}
|
|
84
130
|
/**
|
|
85
|
-
* Cuts `text`
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
*
|
|
89
|
-
*
|
|
131
|
+
* Cuts `text` at each of `positions`, as the reference's `Segment.split_cells`
|
|
132
|
+
* cuts at one: a wide glyph a cut goes through fits neither side, so it leaves
|
|
133
|
+
* a space in each of its cells, where `splitText` keeps it whole on the right.
|
|
134
|
+
* Every other character lands in exactly one piece, so each piece is exactly
|
|
135
|
+
* as wide as the distance between its cuts. `positions` are non-decreasing and
|
|
136
|
+
* fall inside `text`: from 0 to one short of its width.
|
|
137
|
+
*
|
|
138
|
+
* One walk over `text` however many positions there are, ending at the last
|
|
139
|
+
* of them: cutting what is left again at every position re-measures and copies
|
|
140
|
+
* the rest each time, which is quadratic in a long enough string, and walking
|
|
141
|
+
* past the last position makes one cut near the start of a long string pay for
|
|
142
|
+
* all of it.
|
|
90
143
|
*/
|
|
91
|
-
export function cutCells(text,
|
|
92
|
-
const
|
|
93
|
-
//
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
144
|
+
export function cutCells(text, positions) {
|
|
145
|
+
const pieces = [];
|
|
146
|
+
// The current piece is `lead` blank cells, then `text` from `start` to `at`.
|
|
147
|
+
let start = 0;
|
|
148
|
+
let lead = 0;
|
|
149
|
+
let at = 0;
|
|
150
|
+
let col = 0;
|
|
151
|
+
let next = 0;
|
|
152
|
+
for (const glyph of clustersFrom(text, asCodePoint(0))) {
|
|
153
|
+
if (next === positions.length)
|
|
154
|
+
break;
|
|
155
|
+
const end = col + cellLen(glyph);
|
|
156
|
+
// The first cell of this glyph no piece has taken yet.
|
|
157
|
+
let from = col;
|
|
158
|
+
for (; next < positions.length && positions[next] < end; next++) {
|
|
159
|
+
const cut = positions[next];
|
|
160
|
+
pieces.push(" ".repeat(lead) + text.slice(start, at) + " ".repeat(cut - from));
|
|
161
|
+
lead = 0;
|
|
162
|
+
// A cut between glyphs leaves this one to the next piece; a cut through
|
|
163
|
+
// it blanks it, and the pieces after the cut start past it.
|
|
164
|
+
start = cut === col ? at : at + glyph.length;
|
|
165
|
+
from = cut;
|
|
166
|
+
}
|
|
167
|
+
if (from > col)
|
|
168
|
+
lead = end - from;
|
|
169
|
+
at += glyph.length;
|
|
170
|
+
col = end;
|
|
171
|
+
}
|
|
172
|
+
pieces.push(" ".repeat(lead) + text.slice(start));
|
|
173
|
+
return pieces;
|
|
101
174
|
}
|
|
102
175
|
/**
|
|
103
176
|
* Wraps text into lines of at most `maxWidth` cells, preserving every code
|
|
@@ -146,18 +219,20 @@ export function splitAtCells(line, cuts) {
|
|
|
146
219
|
// stepping along one string does not re-segment the whole of it every step.
|
|
147
220
|
let segmenter;
|
|
148
221
|
let lastSegmented;
|
|
222
|
+
function graphemeSegmenter() {
|
|
223
|
+
return (segmenter ??= new Intl.Segmenter(undefined, { granularity: "grapheme" }));
|
|
224
|
+
}
|
|
149
225
|
/** The grapheme segmentation of `text`, reusing the last one when it is the same string. */
|
|
150
226
|
function segmentsOf(text) {
|
|
151
227
|
if (lastSegmented?.text !== text) {
|
|
152
|
-
|
|
153
|
-
lastSegmented = { text, segments: segmenter.segment(text) };
|
|
228
|
+
lastSegmented = { text, segments: graphemeSegmenter().segment(text) };
|
|
154
229
|
}
|
|
155
230
|
return lastSegmented.segments;
|
|
156
231
|
}
|
|
157
232
|
/**
|
|
158
|
-
* The grapheme clusters of `text`, in order: the unit `
|
|
159
|
-
*
|
|
160
|
-
*
|
|
233
|
+
* The grapheme clusters of `text`, in order: the unit `cellLen` of a whole
|
|
234
|
+
* string is the sum of. Summing `cellLen` over code points instead disagrees
|
|
235
|
+
* with it on every glyph built from several:
|
|
161
236
|
* `❤️` is 1 + 0 by code point and 2 as a cluster, `👨👩👧` is 6 and 2, and a cut
|
|
162
237
|
* between two of its code points leaves half a glyph.
|
|
163
238
|
*/
|
package/dist/core/clock.d.ts
CHANGED
|
@@ -42,7 +42,15 @@ export interface Clock {
|
|
|
42
42
|
now(): number;
|
|
43
43
|
/** Call `tick` once a frame at `rate` until the returned function is called. */
|
|
44
44
|
every(rate: FrameRate, tick: () => void): Unsubscribe;
|
|
45
|
+
/**
|
|
46
|
+
* Call `tick` once, when this clock reads `time` — as soon as it can for a
|
|
47
|
+
* time already past — unless the returned function is called first. What
|
|
48
|
+
* a host that knows when its frame next changes (`Segment.nextChange`)
|
|
49
|
+
* waits on. A `time` further off than a timer can wait, about 24.8 days,
|
|
50
|
+
* throws, as `frameRate` refuses the rate.
|
|
51
|
+
*/
|
|
52
|
+
at(time: number, tick: () => void): Unsubscribe;
|
|
45
53
|
}
|
|
46
|
-
/** The platform's monotonic clock and its
|
|
54
|
+
/** The platform's monotonic clock and its timers. */
|
|
47
55
|
export declare function systemClock(): Clock;
|
|
48
56
|
export {};
|
package/dist/core/clock.js
CHANGED
|
@@ -30,13 +30,33 @@ export function frameRate(perSecond) {
|
|
|
30
30
|
}
|
|
31
31
|
return { perSecond, interval: 1 / perSecond };
|
|
32
32
|
}
|
|
33
|
-
/** The platform's monotonic clock and its
|
|
33
|
+
/** The platform's monotonic clock and its timers. */
|
|
34
34
|
export function systemClock() {
|
|
35
|
+
const now = () => performance.now() / 1000;
|
|
35
36
|
return {
|
|
36
|
-
now
|
|
37
|
+
now,
|
|
37
38
|
every: (rate, tick) => {
|
|
38
39
|
const timer = setInterval(tick, rate.interval * 1000);
|
|
39
40
|
return () => clearInterval(timer);
|
|
40
41
|
},
|
|
42
|
+
at: (time, tick) => {
|
|
43
|
+
if (!(time - now() <= LONGEST_INTERVAL)) {
|
|
44
|
+
throw new RangeError(`a clock waits at most ${LONGEST_INTERVAL} s, not until ${time} s from ${now()} s`);
|
|
45
|
+
}
|
|
46
|
+
// [LAW:single-enforcer] A platform timer is due by a whole millisecond
|
|
47
|
+
// of the event loop's own time, truncated, so it can run while this
|
|
48
|
+
// clock still reads under `time` — by most of a millisecond. The
|
|
49
|
+
// contract is the clock's reading, and it is held here, once, for every
|
|
50
|
+
// host: the wait is rounded up, and a timer that runs early is armed
|
|
51
|
+
// again for what remains, so `tick` runs when `now()` has reached
|
|
52
|
+
// `time` and not before. A host re-drawing at a frame's end would
|
|
53
|
+
// otherwise draw the old frame again and wait again, every boundary.
|
|
54
|
+
let timer;
|
|
55
|
+
const arm = () => {
|
|
56
|
+
timer = setTimeout(() => (now() < time ? arm() : tick()), Math.ceil(Math.max(0, time - now()) * 1000));
|
|
57
|
+
};
|
|
58
|
+
arm();
|
|
59
|
+
return () => clearTimeout(timer);
|
|
60
|
+
},
|
|
41
61
|
};
|
|
42
62
|
}
|