1
+ /**
2
+ * @typedef {import('../src/UiString').UiCharStartPos } UiCharStartPos
3
+ */
1
4
import Blessed from "@farjs/blessed" ;
2
5
import assert from "node:assert/strict" ;
3
6
import UiString from "../src/UiString.mjs" ;
@@ -32,6 +35,60 @@ describe("UiString.test.mjs", () => {
32
35
assert . deepEqual ( UiString ( str ) . toString ( ) , str ) ;
33
36
} ) ;
34
37
38
+ it ( "should return left/right char widths and start pos when charStartPos" , ( ) => {
39
+ /**
40
+ * @param {string } str
41
+ * @param {number } pos
42
+ * @param {UiCharStartPos } expected
43
+ */
44
+ function check ( str , pos , expected ) {
45
+ assert . deepEqual ( UiString ( str ) . charStartPos ( pos ) , expected ) ;
46
+ }
47
+
48
+ //when & then
49
+ check ( "" , 0 , { lcw : 0 , pos : 0 , rcw : 0 } ) ;
50
+ check ( "abc" , - 1 , { lcw : 0 , pos : 0 , rcw : 1 } ) ;
51
+ check ( "abc" , 0 , { lcw : 0 , pos : 0 , rcw : 1 } ) ;
52
+ check ( "abc" , 1 , { lcw : 1 , pos : 1 , rcw : 1 } ) ;
53
+ check ( "abc" , 2 , { lcw : 1 , pos : 2 , rcw : 1 } ) ;
54
+ check ( "abc" , 3 , { lcw : 1 , pos : 3 , rcw : 0 } ) ;
55
+ check ( "abc" , 4 , { lcw : 1 , pos : 3 , rcw : 0 } ) ;
56
+ check ( "й" , 0 , { lcw : 0 , pos : 0 , rcw : 1 } ) ;
57
+ check ( "й" , 1 , { lcw : 1 , pos : 1 , rcw : 0 } ) ;
58
+ check ( "й" , 2 , { lcw : 1 , pos : 1 , rcw : 0 } ) ;
59
+ check ( "aй" , 0 , { lcw : 0 , pos : 0 , rcw : 1 } ) ;
60
+ check ( "aй" , 1 , { lcw : 1 , pos : 1 , rcw : 1 } ) ;
61
+ check ( "aй" , 2 , { lcw : 1 , pos : 2 , rcw : 0 } ) ;
62
+ check ( "йa" , 0 , { lcw : 0 , pos : 0 , rcw : 1 } ) ;
63
+ check ( "йa" , 1 , { lcw : 1 , pos : 1 , rcw : 1 } ) ;
64
+ check ( "йa" , 2 , { lcw : 1 , pos : 2 , rcw : 0 } ) ;
65
+ check ( "\uD83C\uDF31" , 0 , { lcw : 0 , pos : 0 , rcw : 2 } ) ;
66
+ check ( "\uD83C\uDF31" , 1 , { lcw : 2 , pos : 2 , rcw : 0 } ) ;
67
+ check ( "\uD83C\uDF31" , 2 , { lcw : 2 , pos : 2 , rcw : 0 } ) ;
68
+ check ( "a\uD83C\uDF31" , 0 , { lcw : 0 , pos : 0 , rcw : 1 } ) ;
69
+ check ( "a\uD83C\uDF31" , 1 , { lcw : 1 , pos : 1 , rcw : 2 } ) ;
70
+ check ( "a\uD83C\uDF31" , 2 , { lcw : 2 , pos : 3 , rcw : 0 } ) ;
71
+ check ( "a\uD83C\uDF31" , 3 , { lcw : 2 , pos : 3 , rcw : 0 } ) ;
72
+ check ( "\uff01" , 0 , { lcw : 0 , pos : 0 , rcw : 2 } ) ;
73
+ check ( "\uff01" , 1 , { lcw : 2 , pos : 2 , rcw : 0 } ) ;
74
+ check ( "\uff01" , 2 , { lcw : 2 , pos : 2 , rcw : 0 } ) ;
75
+ check ( "a\uff01b" , 0 , { lcw : 0 , pos : 0 , rcw : 1 } ) ;
76
+ check ( "a\uff01b" , 1 , { lcw : 1 , pos : 1 , rcw : 2 } ) ;
77
+ check ( "a\uff01b" , 2 , { lcw : 2 , pos : 3 , rcw : 1 } ) ;
78
+ check ( "a\uff01b" , 3 , { lcw : 2 , pos : 3 , rcw : 1 } ) ;
79
+ check ( "a\uff01b" , 4 , { lcw : 1 , pos : 4 , rcw : 0 } ) ;
80
+ check ( "\u200D" , 0 , { lcw : 0 , pos : 0 , rcw : 0 } ) ;
81
+ check ( "\u200Dй" , 0 , { lcw : 0 , pos : 0 , rcw : 1 } ) ;
82
+ check ( "\u200Dй" , 1 , { lcw : 1 , pos : 1 , rcw : 0 } ) ;
83
+ check ( "\u200Dй" , 2 , { lcw : 1 , pos : 1 , rcw : 0 } ) ;
84
+ check ( "\u200Dй\u200Dй" , 0 , { lcw : 0 , pos : 0 , rcw : 1 } ) ;
85
+ check ( "\u200Dй\u200Dй" , 1 , { lcw : 1 , pos : 1 , rcw : 1 } ) ;
86
+ check ( "\u200Dй\u200Dй" , 2 , { lcw : 1 , pos : 2 , rcw : 0 } ) ;
87
+ check ( "double 🉐" , 4 , { lcw : 1 , pos : 4 , rcw : 1 } ) ;
88
+ check ( "double 🉐" , 7 , { lcw : 1 , pos : 7 , rcw : 2 } ) ;
89
+ check ( "double 🉐" , 8 , { lcw : 2 , pos : 9 , rcw : 0 } ) ;
90
+ } ) ;
91
+
35
92
it ( "should return part of str when slice" , ( ) => {
36
93
//given
37
94
const str = "abcd" ;
@@ -54,6 +111,8 @@ describe("UiString.test.mjs", () => {
54
111
55
112
it ( "should handle combining chars when slice" , ( ) => {
56
113
//given
114
+ assert . deepEqual ( unicode . isCombining ( "\u200D" , 0 ) , true ) ;
115
+ assert . deepEqual ( unicode . charWidth ( "\u200D" , 0 ) , 0 ) ;
57
116
assert . deepEqual ( unicode . isCombining ( "й" , 0 ) , false ) ;
58
117
assert . deepEqual ( unicode . isCombining ( "й" , 1 ) , true ) ;
59
118
assert . deepEqual ( unicode . strWidth ( "й" ) , 1 ) ;
@@ -63,14 +122,37 @@ describe("UiString.test.mjs", () => {
63
122
assert . deepEqual ( UiString ( "Валютный" ) . slice ( 6 , 7 ) , "ы" ) ;
64
123
assert . deepEqual ( UiString ( "Валютный" ) . slice ( 7 , 8 ) , "й" ) ;
65
124
assert . deepEqual ( UiString ( "й" ) . slice ( 0 , 1 ) , "й" ) ;
125
+ assert . deepEqual ( UiString ( "й\u200D" ) . slice ( 0 , 1 ) , "й\u200D" ) ;
126
+ assert . deepEqual ( UiString ( "й\u200D\u200Db" ) . slice ( 0 , 1 ) , "й\u200D\u200D" ) ;
127
+ assert . deepEqual ( UiString ( "й\u200D\u200Db" ) . slice ( 1 , 2 ) , "b" ) ;
66
128
assert . deepEqual ( UiString ( "1й" ) . slice ( 0 , 1 ) , "1" ) ;
67
129
assert . deepEqual ( UiString ( "1й" ) . slice ( 0 , 2 ) , "1й" ) ;
68
130
assert . deepEqual ( UiString ( "й2" ) . slice ( 0 , 2 ) , "й2" ) ;
69
131
assert . deepEqual ( UiString ( "й2" ) . slice ( 0 , 1 ) , "й" ) ;
70
132
assert . deepEqual ( UiString ( "й2" ) . slice ( 1 , 2 ) , "2" ) ;
71
133
} ) ;
72
134
73
- it ( "should handle surrogate chars when slice" , ( ) => {
135
+ it ( "should handle high/low surrogate chars when slice" , ( ) => {
136
+ //given
137
+ assert . deepEqual ( unicode . isSurrogate ( "\uD83C" , 0 ) , false ) ;
138
+ assert . deepEqual ( unicode . isSurrogate ( "\uD83Ca" , 0 ) , false ) ;
139
+ assert . deepEqual ( unicode . isSurrogate ( "\uD83C\uDF31" , 0 ) , true ) ;
140
+ assert . deepEqual ( unicode . isSurrogate ( "\uD83C\uDF31" , 1 ) , false ) ;
141
+ assert . deepEqual ( unicode . charWidth ( "\uD800" , 0 ) , 0 ) ;
142
+ assert . deepEqual ( unicode . charWidth ( "\uD83C" , 0 ) , 0 ) ;
143
+ assert . deepEqual ( unicode . charWidth ( "\uDBFF" , 0 ) , 0 ) ;
144
+ assert . deepEqual ( unicode . charWidth ( "\uDC00" , 0 ) , 0 ) ;
145
+ assert . deepEqual ( unicode . charWidth ( "\uDFFF" , 0 ) , 0 ) ;
146
+ assert . deepEqual ( unicode . isCombining ( "\uD83C" , 0 ) , false ) ;
147
+
148
+ //when & then
149
+ assert . deepEqual ( UiString ( "\uD83C" ) . slice ( 0 , 1 ) , "\uD83C" ) ;
150
+ assert . deepEqual ( UiString ( "a\uD83C" ) . slice ( 0 , 1 ) , "a\uD83C" ) ;
151
+ assert . deepEqual ( UiString ( "a\uD83C\uD800b" ) . slice ( 0 , 1 ) , "a\uD83C\uD800" ) ;
152
+ assert . deepEqual ( UiString ( "a\uD83C\uD800b" ) . slice ( 1 , 2 ) , "b" ) ;
153
+ } ) ;
154
+
155
+ it ( "should handle surrogate pairs when slice" , ( ) => {
74
156
//given
75
157
assert . deepEqual ( unicode . isSurrogate ( "\uD83C\uDF31" , 0 ) , true ) ;
76
158
assert . deepEqual ( unicode . isSurrogate ( "\uD83C\uDF31" , 1 ) , false ) ;
0 commit comments