25 bool insertMode =
true;
40 bool hasPartialGrapheme =
false;
44 text(), _shapedText(), currentStyle(style)
55 if (ssize(text) == 0) {
58 text_.emplace_back(
Grapheme(
'\n'), text_.back().style, 0);
61 _shapedText =
ShapedText(text_, width, Alignment::TopLeft,
false);
64 [[nodiscard]]
ShapedText shapedText() const noexcept {
68 void setWidth(
float _width)
noexcept {
73 void setCurrentStyle(TextStyle style)
noexcept {
74 this->currentStyle = style;
80 setCurrentStyle(style);
87 size_t size() const noexcept {
94 tt_assume(index >= 0);
96 tt_assume(index < ssize(text));
98 return text.
begin() + index;
104 tt_assume(index >= 0);
106 tt_assume(index <= ssize(text));
108 return text.
cbegin() + index;
111 decltype(
auto)
it(
ssize_t index)
const noexcept {
118 if (hasPartialGrapheme) {
119 tt_assume(cursorIndex != 0);
136 if (selectionIndex < cursorIndex) {
138 }
else if (selectionIndex > cursorIndex) {
149 if (selectionIndex < cursorIndex) {
151 cursorIndex = selectionIndex;
153 }
else if (selectionIndex > cursorIndex) {
155 selectionIndex = cursorIndex;
164 void setCursorAtCoordinate(
vec coordinate)
noexcept {
166 selectionIndex = cursorIndex = *newCursorPosition;
167 tt_assume(selectionIndex >= 0);
168 tt_assume(selectionIndex <= ssize(text));
172 void selectWordAtCoordinate(
vec coordinate)
noexcept {
175 tt_assume(selectionIndex >= 0);
176 tt_assume(selectionIndex <= ssize(text));
177 tt_assume(cursorIndex >= 0);
178 tt_assume(cursorIndex <= ssize(text));
182 void selectParagraphAtCoordinate(vec coordinate)
noexcept {
185 tt_assume(selectionIndex >= 0);
186 tt_assume(selectionIndex <= ssize(text));
187 tt_assume(cursorIndex >= 0);
188 tt_assume(cursorIndex <= ssize(text));
192 void dragCursorAtCoordinate(vec coordinate)
noexcept {
194 cursorIndex = *newCursorPosition;
195 tt_assume(cursorIndex >= 0);
196 tt_assume(cursorIndex <= ssize(text));
200 void dragWordAtCoordinate(vec coordinate)
noexcept {
202 ttlet [a, b] = _shapedText.
indicesOfWord(*newCursorPosition);
204 if (selectionIndex <= cursorIndex) {
205 if (a < selectionIndex) {
207 selectionIndex = cursorIndex;
213 if (b > selectionIndex) {
215 selectionIndex = cursorIndex;
222 tt_assume(selectionIndex >= 0);
223 tt_assume(selectionIndex <= ssize(text));
224 tt_assume(cursorIndex >= 0);
225 tt_assume(cursorIndex <= ssize(text));
229 void dragParagraphAtCoordinate(vec coordinate)
noexcept {
233 if (selectionIndex <= cursorIndex) {
234 if (a < selectionIndex) {
236 selectionIndex = cursorIndex;
242 if (b > selectionIndex) {
244 selectionIndex = cursorIndex;
251 tt_assume(selectionIndex >= 0);
252 tt_assume(selectionIndex <= ssize(text));
253 tt_assume(cursorIndex >= 0);
254 tt_assume(cursorIndex <= ssize(text));
258 void cancelPartialGrapheme() noexcept {
259 if (hasPartialGrapheme) {
260 tt_assume(cursorIndex >= 1);
262 selectionIndex = --cursorIndex;
263 tt_assume(selectionIndex >= 0);
264 tt_assume(selectionIndex <= ssize(text));
265 tt_assume(cursorIndex >= 0);
266 tt_assume(cursorIndex <= ssize(text));
269 hasPartialGrapheme =
false;
281 cancelPartialGrapheme();
284 text.
emplace(
cit(cursorIndex), character, currentStyle);
285 selectionIndex = ++cursorIndex;
286 tt_assume(selectionIndex >= 0);
287 tt_assume(selectionIndex <= ssize(text));
288 tt_assume(cursorIndex >= 0);
289 tt_assume(cursorIndex <= ssize(text));
291 hasPartialGrapheme =
true;
299 cancelPartialGrapheme();
303 handleCommand(
"text.delete.char.next"_ltag);
305 text.
emplace(
cit(cursorIndex), character, currentStyle);
306 selectionIndex = ++cursorIndex;
307 tt_assume(selectionIndex >= 0);
308 tt_assume(selectionIndex <= ssize(text));
309 tt_assume(cursorIndex >= 0);
310 tt_assume(cursorIndex <= ssize(text));
316 cancelPartialGrapheme();
319 gstring gstr = to_gstring(str);
323 for (ttlet &g: gstr) {
324 str_attr.emplace_back(g, currentStyle);
327 text.
insert(
cit(cursorIndex), str_attr.cbegin(), str_attr.cend());
328 selectionIndex = cursorIndex += ssize(str_attr);
329 tt_assume(selectionIndex >= 0);
330 tt_assume(selectionIndex <= ssize(text));
331 tt_assume(cursorIndex >= 0);
332 tt_assume(cursorIndex <= ssize(text));
340 if (selectionIndex < cursorIndex) {
341 r.
reserve(cursorIndex - selectionIndex);
342 for (
auto i =
cit(selectionIndex); i !=
cit(cursorIndex); ++i) {
345 }
else if (selectionIndex > cursorIndex) {
346 r.reserve(selectionIndex - cursorIndex);
347 for (
auto i =
cit(cursorIndex); i !=
cit(selectionIndex); ++i) {
355 auto r = handleCopy();
356 cancelPartialGrapheme();
361 void handleCommand(string_ltag command)
noexcept {
362 tt_assume(cursorIndex <= ssize(text));
363 cancelPartialGrapheme();
365 if (command ==
"text.cursor.char.left"_ltag) {
368 selectionIndex = cursorIndex = *newCursorPosition;
370 }
else if (command ==
"text.cursor.char.right"_ltag) {
372 selectionIndex = cursorIndex = *newCursorPosition;
374 }
else if (command ==
"text.cursor.word.left"_ltag) {
376 selectionIndex = cursorIndex = *newCursorPosition;
378 }
else if (command ==
"text.cursor.word.right"_ltag) {
380 selectionIndex = cursorIndex = *newCursorPosition;
382 }
else if (command ==
"text.cursor.word.right"_ltag) {
384 selectionIndex = cursorIndex = *newCursorPosition;
386 }
else if (command ==
"text.cursor.line.end"_ltag) {
387 selectionIndex = cursorIndex = size() - 1;
388 }
else if (command ==
"text.cursor.line.begin"_ltag) {
389 selectionIndex = cursorIndex = 0;
390 }
else if (command ==
"text.select.char.left"_ltag) {
392 cursorIndex = *newCursorPosition;
394 }
else if (command ==
"text.select.char.right"_ltag) {
396 cursorIndex = *newCursorPosition;
398 }
else if (command ==
"text.select.word.left"_ltag) {
400 cursorIndex = *newCursorPosition;
402 }
else if (command ==
"text.select.word.right"_ltag) {
404 cursorIndex = *newCursorPosition;
406 }
else if (command ==
"text.select.word"_ltag) {
408 }
else if (command ==
"text.select.line.end"_ltag) {
409 cursorIndex = size() - 1;
410 }
else if (command ==
"text.select.line.begin"_ltag) {
412 }
else if (command ==
"text.select.document"_ltag) {
414 cursorIndex = size() - 1;
415 }
else if (command ==
"text.mode.insert"_ltag) {
416 insertMode = !insertMode;
417 }
else if (command ==
"text.delete.char.prev"_ltag) {
418 if (cursorIndex != selectionIndex) {
421 }
else if (cursorIndex >= 1) {
422 selectionIndex = --cursorIndex;
426 }
else if (command ==
"text.delete.char.next"_ltag) {
427 if (cursorIndex != selectionIndex) {
430 }
else if (cursorIndex < (ssize(text) - 1)) {
437 tt_assume(selectionIndex >= 0);
438 tt_assume(selectionIndex <= ssize(text));
439 tt_assume(cursorIndex >= 0);
440 tt_assume(cursorIndex <= ssize(text));