275.2 KB、9584行 生 Blame 履歴
1// TextEditor - A syntax highlighting text editor for Dear ImGui.
2// Copyright (c) 2024-2026 Johan A. Goossens. All rights reserved.
3//
4// This work is licensed under the terms of the MIT license.
5// For a copy, see <https://opensource.org/licenses/MIT>.
6
7
8//
9// Include files
10//
11
12#include <cmath>
13#include <limits>
14
15#ifndef IMGUI_DEFINE_MATH_OPERATORS
16#define IMGUI_DEFINE_MATH_OPERATORS
17#endif
18
19#include "imgui.h"
20#include "imgui_internal.h"
21
22#include "TextEditor.h"
23
24
25//
26// TextEditor::TextEditor
27//
28
29TextEditor::TextEditor() {
30 SetPalette(defaultPalette);
31}
32
33
34//
35// TextEditor::setText
36//
37
38void TextEditor::setText(const std::string_view &text) {
39 // load text into document and reset subsystems
40 document.setText(text);
41 transactions.reset();
42 bracketeer.reset();
43 colorizer.updateEntireDocument(document, language);
44 cursors.clearAll();
45 clearMarkers();
46 makeCursorVisible();
47
48 showMatchingBracketsChanged = false;
49 languageChanged = false;
50}
51
52
53//
54// TextEditor::render
55//
56
57void TextEditor::render(const char* title, const ImVec2& size, bool border) {
58 // get current transaction version
59 auto transActionVersion = transactions.getVersion();
60
61 // update color palette (if required)
62 if (paletteAlpha != ImGui::GetStyle().Alpha) {
63 updatePalette();
64 }
65
66 // get font information and determine horizontal offsets for line numbers, decorations and text
67 font = ImGui::GetFont();
68 fontSize = ImGui::GetFontSize();
69 glyphSize = ImVec2(ImGui::CalcTextSize("#").x, ImGui::GetTextLineHeightWithSpacing() * lineSpacing);
70 lineNumberLeftOffset = leftMargin * glyphSize.x;
71
72 if (showLineNumbers) {
73 int digits = static_cast<int>(std::log10(document.lineCount() + 1) + 1.0f);
74 lineNumberRightOffset = lineNumberLeftOffset + digits * glyphSize.x;
75 decorationOffset = lineNumberRightOffset + decorationMargin * glyphSize.x;
76
77 } else {
78 lineNumberRightOffset = lineNumberLeftOffset;
79 decorationOffset = lineNumberLeftOffset;
80 }
81
82 if (decoratorWidth > 0.0f) {
83 textOffset = decorationOffset + decoratorWidth + decorationMargin * glyphSize.x;
84
85 } else if (decoratorWidth < 0.0f) {
86 textOffset = decorationOffset + (-decoratorWidth + decorationMargin) * glyphSize.x;
87
88 } else {
89 textOffset = decorationOffset + textMargin * glyphSize.x;
90 }
91
92 // get current position and total/visible editor size
93 auto pos = ImGui::GetCursorScreenPos();
94 auto totalSize = ImVec2(textOffset + document.getMaxColumn() * glyphSize.x + cursorWidth, document.size() * glyphSize.y);
95 auto region = ImGui::GetContentRegionAvail();
96 auto visibleSize = ImGui::CalcItemSize(size, region.x, region.y); // messing with Dear ImGui internals
97
98 // see if we have scrollbars
99 float scrollbarSize = ImGui::GetStyle().ScrollbarSize;
100 verticalScrollBarSize = (totalSize.y > visibleSize.y) ? scrollbarSize : 0.0f;
101 horizontalScrollBarSize = (totalSize.x > visibleSize.x) ? scrollbarSize : 0.0f;
102
103 // determine visible lines and columns
104 visibleWidth = visibleSize.x - textOffset - verticalScrollBarSize;
105 visibleColumns = std::max(static_cast<int>(std::ceil(visibleWidth / glyphSize.x)), 0);
106 visibleHeight = visibleSize.y - horizontalScrollBarSize;
107 visibleLines = std::max(static_cast<int>(std::ceil(visibleHeight / glyphSize.y)), 0);
108
109 // determine scrolling requirements
110 float scrollX = -1.0f;
111 float scrollY = -1.0f;
112
113 // ensure cursor is visible (if requested)
114 if (ensureCursorIsVisible) {
115 auto cursor = cursors.getCurrent().getInteractiveEnd();
116
117 if (cursor.line <= firstVisibleLine + 1) {
118 scrollY = std::max(0.0f, (cursor.line - 2.0f) * glyphSize.y);
119
120 } else if (cursor.line >= lastVisibleLine - 1) {
121 scrollY = std::max(0.0f, (cursor.line + 2.0f) * glyphSize.y - visibleHeight);
122 }
123
124 if (cursor.column <= firstVisibleColumn + 1) {
125 scrollX = std::max(0.0f, (cursor.column - 2.0f) * glyphSize.x);
126
127 } else if (cursor.column >= lastVisibleColumn - 1) {
128 scrollX = std::max(0.0f, (cursor.column + 2.0f) * glyphSize.x - visibleWidth);
129 }
130
131 ensureCursorIsVisible = false;
132 }
133
134 // scroll to specified line (if required)
135 if (scrollToLineNumber >= 0) {
136 scrollToLineNumber = std::min(scrollToLineNumber, document.lineCount());
137 scrollX = 0.0f;
138
139 switch (scrollToAlignment) {
140 case Scroll::alignTop:
141 scrollY = std::max(0.0f, static_cast<float>(scrollToLineNumber) * glyphSize.y);
142 break;
143
144 case Scroll::alignMiddle:
145 scrollY = std::max(0.0f, static_cast<float>(scrollToLineNumber - visibleLines / 2) * glyphSize.y);
146 break;
147
148 case Scroll::alignBottom:
149 scrollY = std::max(0.0f, static_cast<float>(scrollToLineNumber - (visibleLines - 1)) * glyphSize.y);
150 break;
151 }
152
153 scrollToLineNumber = -1;
154 }
155
156 // set scroll (if required)
157 if (scrollX >= 0.0f || scrollY >= 0.0f) {
158 ImGui::SetNextWindowScroll(ImVec2(scrollX, scrollY));
159 }
160
161 // ensure editor has focus (if required)
162 if (focusOnEditor) {
163 ImGui::SetNextWindowFocus();
164 focusOnEditor = false;
165 }
166
167 // start a new child window
168 // this must be done before we handle keyboard and mouse interactions to ensure correct Dear ImGui context
169 ImGui::SetNextWindowContentSize(totalSize);
170 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 0.0f));
171 ImGui::PushStyleColor(ImGuiCol_ChildBg, ImGui::ColorConvertU32ToFloat4(palette.get(Color::background)));
172 ImGui::BeginChild(title, size, border, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_HorizontalScrollbar | ImGuiWindowFlags_NoNavInputs);
173 lastRenderOrigin = ImGui::GetCursorScreenPos();
174
175 // handle keyboard and mouse inputs
176 handleKeyboardInputs();
177 handleMouseInteractions();
178
179 // ensure cursors are up to date (sort and merge if required)
180 if (cursors.anyHasUpdate()) {
181 cursors.update();
182 }
183
184 // recolorize entire document and reset brackets (if required)
185 if (showMatchingBracketsChanged || languageChanged) {
186 colorizer.updateEntireDocument(document, language);
187 bracketeer.reset();
188 }
189
190 // was document changed during this frame?
191 auto documentChanged = document.isUpdated();
192
193 if (language) {
194 if (documentChanged) {
195 // recolorize updated lines
196 colorizer.updateChangedLines(document, language);
197 }
198
199 if (showMatchingBrackets && (documentChanged || showMatchingBracketsChanged || languageChanged)) {
200 // rebuild bracket list
201 bracketeer.update(document);
202 }
203 }
204
205 // reset changed states
206 showMatchingBracketsChanged = false;
207 languageChanged = false;
208
209 // determine view parameters
210 firstVisibleColumn = std::max(static_cast<int>(std::floor(ImGui::GetScrollX() / glyphSize.x)), 0);
211 lastVisibleColumn = static_cast<int>(std::floor((ImGui::GetScrollX() + visibleWidth) / glyphSize.x));
212 firstVisibleLine = std::max(static_cast<int>(std::floor(ImGui::GetScrollY() / glyphSize.y)), 0);
213 lastVisibleLine = std::min(static_cast<int>(std::floor((ImGui::GetScrollY() + visibleHeight) / glyphSize.y)), document.lineCount() - 1);
214
215 // render editor parts
216 renderSelections();
217 renderMarkers();
218 renderMatchingBrackets();
219 renderText();
220 renderCursors();
221 renderMargin();
222 renderLineNumbers();
223 renderDecorations();
224 renderScrollbarMiniMap();
225 renderPanScrollIndicator();
226
227 if (ImGui::BeginPopup("LineNumberContextMenu")) {
228 lineNumberContextMenuCallback(contextMenuLine);
229 ImGui::EndPopup();
230 }
231
232 if (ImGui::BeginPopup("TextContextMenu")) {
233 textContextMenuCallback(contextMenuLine, contextMenuColumn);
234 ImGui::EndPopup();
235 }
236
237 // render find/replace popup
238 renderFindReplace(pos, visibleSize.x - verticalScrollBarSize);
239
240 // render autocomplete popup
241 if (autocomplete.render(document, cursors, language, textOffset, glyphSize)) {
242 // user picked a suggestion so insert it
243 auto start = autocomplete.getStart();
244 auto end = document.findWordEnd(start, true);
245 auto replacement = autocomplete.getReplacement();
246 replaceSectionText(start, end, replacement);
247 }
248
249 // handle change tracking if there is a change callback in place
250 if (delayedChangeCallback) {
251 if (delayedChangeDetected) {
252 if (std::chrono::system_clock::now() > delayedChangeReportTime) {
253 delayedChangeCallback();
254 delayedChangeDetected = false;
255 }
256
257 } else if (transactions.getVersion() != transActionVersion) {
258 delayedChangeDetected = true;
259 delayedChangeReportTime = std::chrono::system_clock::now() + delayedChangeDelay;
260 }
261 }
262
263 ImGui::EndChild();
264 ImGui::PopStyleColor();
265 ImGui::PopStyleVar();
266}
267
268
269//
270// TextEditor::renderSelections
271//
272
273void TextEditor::renderSelections() {
274 auto drawList = ImGui::GetWindowDrawList();
275 ImVec2 cursorScreenPos = ImGui::GetCursorScreenPos();
276
277 // draw background for selections
278 for (auto& cursor : cursors) {
279 if (cursor.hasSelection()) {
280 auto start = cursor.getSelectionStart();
281 auto end = cursor.getSelectionEnd();
282
283 if (end.line >= firstVisibleLine && start.line <= lastVisibleLine) {
284 auto first = std::max(start.line, firstVisibleLine);
285 auto last = std::min(end.line, lastVisibleLine);
286
287 for (auto line = first; line <= last; line++) {
288 auto x = cursorScreenPos.x + textOffset;
289 auto left = x + (line == first ? start.column : 0) * glyphSize.x;
290 auto right = x + (line == last ? end.column : document[line].maxColumn) * glyphSize.x;
291 auto y = cursorScreenPos.y + line * glyphSize.y;
292 drawList->AddRectFilled(ImVec2(left, y), ImVec2(right, y + glyphSize.y), palette.get(Color::selection));
293 }
294 }
295 }
296 }
297}
298
299
300//
301// TextEditor::renderMarkers
302//
303
304void TextEditor::renderMarkers() {
305 if (markers.size()) {
306 auto drawList = ImGui::GetWindowDrawList();
307 ImVec2 cursorScreenPos = ImGui::GetCursorScreenPos();
308
309 for (int line = firstVisibleLine; line <= lastVisibleLine; line++) {
310 if (document[line].marker) {
311 auto& marker = markers[document[line].marker - 1];
312 auto y = cursorScreenPos.y + line * glyphSize.y;
313
314 if (((marker.lineNumberColor >> IM_COL32_A_SHIFT) & 0xFF) != 0) {
315 auto left = cursorScreenPos.x + lineNumberLeftOffset;
316 auto right = cursorScreenPos.x + lineNumberRightOffset;
317 auto start = ImVec2(left, y);
318 auto end = ImVec2(right, y + glyphSize.y);
319 drawList->AddRectFilled(start, end, marker.lineNumberColor);
320
321 if (marker.lineNumberTooltip.size() && ImGui::IsMouseHoveringRect(start, end)) {
322 ImGui::PushStyleColor(ImGuiCol_PopupBg, marker.lineNumberColor);
323 ImGui::BeginTooltip();
324 ImGui::TextUnformatted(marker.lineNumberTooltip.c_str());
325 ImGui::EndTooltip();
326 ImGui::PopStyleColor();
327 }
328 }
329
330 if (((marker.textColor >> IM_COL32_A_SHIFT) & 0xFF) != 0) {
331 auto left = cursorScreenPos.x + textOffset;
332 auto right = left + lastVisibleColumn * glyphSize.x;
333 auto start = ImVec2(left, y);
334 auto end = ImVec2(right, y + glyphSize.y);
335 drawList->AddRectFilled(start, end, marker.textColor);
336
337 if (marker.textTooltip.size() && ImGui::IsMouseHoveringRect(start, end)) {
338 ImGui::PushStyleColor(ImGuiCol_PopupBg, marker.textColor);
339 ImGui::BeginTooltip();
340 ImGui::TextUnformatted(marker.textTooltip.c_str());
341 ImGui::EndTooltip();
342 ImGui::PopStyleColor();
343 }
344 }
345 }
346 }
347 }
348}
349
350
351//
352// TextEditor::renderMatchingBrackets
353//
354
355void TextEditor::renderMatchingBrackets() {
356 if (showMatchingBrackets) {
357 if (bracketeer.size()) {
358 auto drawList = ImGui::GetWindowDrawList();
359 ImVec2 cursorScreenPos = ImGui::GetCursorScreenPos();
360
361 // render bracket pair lines
362 for (auto& bracket : bracketeer) {
363 if ((bracket.end.line - bracket.start.line) > 1 &&
364 bracket.start.line <= lastVisibleLine &&
365 bracket.end.line > firstVisibleLine) {
366
367 auto lineX = cursorScreenPos.x + textOffset + std::min(bracket.start.column, bracket.end.column) * glyphSize.x;
368 auto startY = cursorScreenPos.y + (bracket.start.line + 1) * glyphSize.y;
369 auto endY = cursorScreenPos.y + bracket.end.line * glyphSize.y;
370 drawList->AddLine(ImVec2(lineX, startY), ImVec2(lineX, endY), palette.get(Color::whitespace), 1.0f);
371 }
372 }
373
374 // render active bracket pair
375 auto active = bracketeer.getEnclosingBrackets(cursors.getMain().getInteractiveEnd());
376
377 if (active != bracketeer.end() &&
378 active->start.line <= lastVisibleLine &&
379 active->end.line > firstVisibleLine) {
380
381 auto x1 = cursorScreenPos.x + textOffset + active->start.column * glyphSize.x;
382 auto y1 = cursorScreenPos.y + active->start.line * glyphSize.y;
383 drawList->AddRectFilled(ImVec2(x1, y1), ImVec2(x1 + glyphSize.x, y1 + glyphSize.y), palette.get(Color::matchingBracketBackground));
384
385 auto x2 = cursorScreenPos.x + textOffset + active->end.column * glyphSize.x;
386 auto y2 = cursorScreenPos.y + active->end.line * glyphSize.y;
387 drawList->AddRectFilled(ImVec2(x2, y2), ImVec2(x2 + glyphSize.x, y2 + glyphSize.y), palette.get(Color::matchingBracketBackground));
388
389 if (active->end.line - active->start.line > 1) {
390 auto lineX = std::min(x1, x2);
391 drawList->AddLine(ImVec2(lineX, y1 + glyphSize.y), ImVec2(lineX, y2), palette.get(Color::matchingBracketActive), 1.0f);
392 }
393 }
394 }
395 }
396}
397
398
399//
400// TextEditor::renderText
401//
402
403void TextEditor::renderText() {
404 auto drawList = ImGui::GetWindowDrawList();
405 ImVec2 cursorScreenPos = ImGui::GetCursorScreenPos();
406 ImVec2 lineScreenPos = cursorScreenPos + ImVec2(textOffset, firstVisibleLine * glyphSize.y);
407 auto tabSize = document.getTabSize();
408 auto firstRenderableColumn = (firstVisibleColumn / tabSize) * tabSize;
409
410 for (int i = firstVisibleLine; i <= lastVisibleLine; i++) {
411 auto& line = document[i];
412
413 // draw colored glyphs for current line
414 auto column = firstRenderableColumn;
415 auto index = document.getIndex(line, column);
416 auto lineSize = line.size();
417
418 while (index < lineSize && column <= lastVisibleColumn) {
419 auto& glyph = line[index];
420 auto codepoint = glyph.codepoint;
421 ImVec2 glyphPos{lineScreenPos.x + column * glyphSize.x, lineScreenPos.y};
422
423 if (codepoint == '\t') {
424 if (showTabs) {
425 const auto x1 = glyphPos.x + glyphSize.x * 0.3f;
426 const auto y = glyphPos.y + fontSize * 0.5f;
427 const auto x2 = glyphPos.x + glyphSize.x;
428
429 ImVec2 p1, p2, p3, p4;
430 p1 = ImVec2(x1, y);
431 p2 = ImVec2(x2, y);
432 p3 = ImVec2(x2 - fontSize * 0.16f, y - fontSize * 0.16f);
433 p4 = ImVec2(x2 - fontSize * 0.16f, y + fontSize * 0.16f);
434
435 drawList->AddLine(p1, p2, palette.get(Color::whitespace));
436 drawList->AddLine(p2, p3, palette.get(Color::whitespace));
437 drawList->AddLine(p2, p4, palette.get(Color::whitespace));
438 }
439
440 } else if (codepoint == ' ') {
441 if (showSpaces) {
442 const auto x = glyphPos.x + glyphSize.x * 0.5f;
443 const auto y = glyphPos.y + fontSize * 0.5f;
444 drawList->AddCircleFilled(ImVec2(x, y), 1.5f, palette.get(Color::whitespace), 4);
445 }
446
447 } else {
448 font->RenderChar(drawList, fontSize, glyphPos, palette.get(glyph.color), codepoint);
449 }
450
451 index++;
452 column += (codepoint == '\t') ? tabSize - (column % tabSize) : 1;
453 }
454
455 lineScreenPos.y += glyphSize.y;
456 }
457}
458
459
460//
461// TextEditor::renderCursors
462//
463
464void TextEditor::renderCursors() {
465 // update cursor animation timer
466 cursorAnimationTimer = std::fmod(cursorAnimationTimer + ImGui::GetIO().DeltaTime, 1.0f);
467
468 if (ImGui::IsWindowFocused()) {
469 ImVec2 cursorScreenPos = ImGui::GetCursorScreenPos();
470
471 if (!ImGui::GetIO().ConfigInputTextCursorBlink || cursorAnimationTimer < 0.5f) {
472 auto drawList = ImGui::GetWindowDrawList();
473
474 for (auto& cursor : cursors) {
475 auto pos = cursor.getInteractiveEnd();
476
477 if (pos.line >= firstVisibleLine && pos.line <= lastVisibleLine) {
478 auto x = cursorScreenPos.x + textOffset + pos.column * glyphSize.x - 1;
479 auto y = cursorScreenPos.y + pos.line * glyphSize.y;
480 drawList->AddRectFilled(ImVec2(x, y), ImVec2(x + cursorWidth, y + glyphSize.y), palette.get(Color::cursor));
481 }
482 }
483 }
484
485 // notify OS of text input position for advanced Input Method Editor (IME)
486 // this is required for the SDL3 backend as it will not report text input events unless we do this
487 // see https://github.com/ocornut/imgui/issues/8584 for details
488 if (!readOnly) {
489 auto context = ImGui::GetCurrentContext();
490 context->PlatformImeData.WantVisible = true;
491 context->PlatformImeData.WantTextInput = true;
492 context->PlatformImeData.InputPos = ImVec2(cursorScreenPos.x - 1.0f, cursorScreenPos.y - context->FontSize);
493 context->PlatformImeData.InputLineHeight = context->FontSize;
494 context->PlatformImeData.ViewportId = ImGui::GetCurrentWindow()->Viewport->ID;
495 }
496 }
497}
498
499
500//
501// TextEditor::renderMargin
502//
503
504void TextEditor::renderMargin() {
505 if ((decoratorWidth != 0.0f && decoratorCallback) || showLineNumbers) {
506 // erase background in case we are scrolling horizontally
507 if (ImGui::GetScrollX() > 0.0f) {
508 ImGui::GetWindowDrawList()->AddRectFilled(
509 ImGui::GetWindowPos(),
510 ImGui::GetWindowPos() + ImVec2(textOffset, ImGui::GetWindowSize().y),
511 palette.get(Color::background));
512 }
513 }
514}
515
516
517//
518// TextEditor::renderLineNumbers
519//
520
521void TextEditor::renderLineNumbers() {
522 if (showLineNumbers) {
523 auto drawList = ImGui::GetWindowDrawList();
524 auto cursorScreenPos = ImGui::GetCursorScreenPos();
525 auto curserLine = cursors.getCurrent().getInteractiveEnd().line;
526 auto position = ImVec2(ImGui::GetWindowPos().x + lineNumberRightOffset, cursorScreenPos.y);
527
528 for (int i = firstVisibleLine; i <= lastVisibleLine; i++) {
529 auto width = static_cast<int>(std::log10(i + 1) + 1.0f) * glyphSize.x;
530 auto foreground = (i == curserLine) ? Color::currentLineNumber : Color::lineNumber;
531 auto number = std::to_string(i + 1);
532 drawList->AddText(position + ImVec2(-width, i * glyphSize.y), palette.get(foreground), number.c_str());
533 }
534 }
535}
536
537
538//
539// TextEditor::renderDecorations
540//
541
542void TextEditor::renderDecorations() {
543 if (decoratorWidth != 0.0f && decoratorCallback) {
544 auto cursorScreenPos = ImGui::GetCursorScreenPos();
545 auto position = ImVec2(ImGui::GetWindowPos().x + decorationOffset, cursorScreenPos.y + glyphSize.y * firstVisibleLine);
546 auto widthInPixels = (decoratorWidth < 0.0f) ? -decoratorWidth * glyphSize.x: decoratorWidth;
547 Decorator decorator{0, widthInPixels, glyphSize.y, glyphSize, nullptr};
548
549 for (int i = firstVisibleLine; i <= lastVisibleLine; i++) {
550 decorator.line = i;
551 decorator.userData = document.getUserData(i);
552 ImGui::SetCursorScreenPos(position);
553 ImGui::PushID(i);
554 decoratorCallback(decorator);
555 ImGui::PopID();
556 position.y += glyphSize.y;
557 }
558
559 ImGui::SetCursorScreenPos(cursorScreenPos);
560 }
561}
562
563
564//
565// TextEditor::renderScrollbarMiniMap
566//
567
568void TextEditor::renderScrollbarMiniMap() {
569 // based on https://github.com/ocornut/imgui/issues/3114
570 // messing with Dear ImGui internals
571 if (showScrollbarMiniMap) {
572 auto window = ImGui::GetCurrentWindow();
573
574 if (window->ScrollbarY) {
575 auto drawList = ImGui::GetWindowDrawList();
576 auto rect = ImGui::GetWindowScrollbarRect(window, ImGuiAxis_Y);
577 auto lineHeight = rect.GetHeight() / static_cast<float>(document.size());
578 auto offset = (rect.Max.x - rect.Min.x) * 0.3f;
579 auto left = rect.Min.x + offset;
580 auto right = rect.Max.x - offset;
581
582 drawList->PushClipRect(rect.Min, rect.Max, false);
583
584 // render cursor locations
585 for (auto& cursor : cursors) {
586 auto begin = cursor.getSelectionStart();
587 auto end = cursor.getSelectionEnd();
588
589 auto ly1 = std::round(rect.Min.y + begin.line * lineHeight);
590 auto ly2 = std::round(rect.Min.y + (end.line + 1) * lineHeight);
591
592 drawList->AddRectFilled(ImVec2(left, ly1), ImVec2(right, ly2), palette.get(Color::selection));
593 }
594
595 // render marker locations
596 if (markers.size()) {
597 for (size_t line = 0; line < document.size(); line++) {
598 if (document[line].marker) {
599 auto color = markers[document[line].marker - 1].textColor;
600
601 if (!color) {
602 color = markers[document[line].marker - 1].lineNumberColor;
603 }
604
605 auto ly = std::round(rect.Min.y + line * lineHeight);
606 drawList->AddRectFilled(ImVec2(left, ly), ImVec2(right, ly + lineHeight), color);
607 }
608 }
609 }
610
611 drawList->PopClipRect();
612 }
613 }
614}
615
616
617//
618// TextEditor::renderPanScrollIndicator
619//
620
621void TextEditor::renderPanScrollIndicator() {
622 if (showPanScrollIndicator && (panning || scrolling)) {
623 auto drawList = ImGui::GetWindowDrawList();
624 auto center =ImGui::GetWindowPos() + ImGui::GetWindowSize() / 2.0f;
625 static constexpr int alpha = 160;
626 drawList->AddCircleFilled(center, 20.0f, IM_COL32(255, 255, 255, alpha));
627 drawList->AddCircle(center, 5.0f, IM_COL32(0, 0, 0, alpha), 0, 2.0f);
628
629 drawList->AddTriangle(
630 ImVec2(center.x - 15.0f, center.y),
631 ImVec2(center.x - 8.0f, center.y - 4.0f),
632 ImVec2(center.x - 8.0f, center.y + 4.0f),
633 IM_COL32(0, 0, 0, alpha),
634 2.0f);
635
636 drawList->AddTriangle(
637 ImVec2(center.x + 15.0f, center.y),
638 ImVec2(center.x + 8.0f, center.y - 4.0f),
639 ImVec2(center.x + 8.0f, center.y + 4.0f),
640 IM_COL32(0, 0, 0, alpha),
641 2.0f);
642
643 drawList->AddTriangle(
644 ImVec2(center.x, center.y - 15.0f),
645 ImVec2(center.x - 4.0f, center.y - 8.0f),
646 ImVec2(center.x + 4.0f, center.y - 8.0f),
647 IM_COL32(0, 0, 0, alpha),
648 2.0f);
649
650 drawList->AddTriangle(
651 ImVec2(center.x, center.y + 15.0f),
652 ImVec2(center.x - 4.0f, center.y + 8.0f),
653 ImVec2(center.x + 4.0f, center.y + 8.0f),
654 IM_COL32(0, 0, 0, alpha),
655 2.0f);
656 }
657}
658
659
660//
661// TextEditor::handleKeyboardInputs
662//
663
664void TextEditor::handleKeyboardInputs() {
665 if (ImGui::IsWindowFocused()) {
666 auto& io = ImGui::GetIO();
667 io.WantCaptureKeyboard = true;
668 io.WantTextInput = true;
669
670 // get state of modifier keys
671 auto shift = ImGui::IsKeyDown(ImGuiMod_Shift);
672 auto ctrl = ImGui::IsKeyDown(ImGuiMod_Ctrl);
673 auto alt = ImGui::IsKeyDown(ImGuiMod_Alt);
674
675 auto isNoModifiers = !ctrl && !shift && !alt;
676 auto isShortcut = ctrl && !shift && !alt;
677 auto isShiftShortcut = ctrl && shift && !alt;
678 auto isOptionalShiftShortcut = ctrl && !alt;
679 auto isAltOnly = !ctrl && !shift && alt;
680 auto isShiftOnly = !ctrl && shift && !alt;
681 auto isOptionalShift = !ctrl && !alt;
682 auto isOptionalAlt = !ctrl && !shift;
683
684 // Dear ImGui switches the Cmd(Super) and Ctrl keys on MacOS
685 auto super = ImGui::IsKeyDown(ImGuiMod_Super);
686 auto meta = ImGui::GetIO().ConfigMacOSXBehaviors ? alt : ctrl;
687 auto isMetaShift = ImGui::GetIO().ConfigMacOSXBehaviors ? !ctrl && shift && !alt && super : !ctrl && shift && alt;
688 auto isOptionalMetaShift = ImGui::GetIO().ConfigMacOSXBehaviors ? !ctrl : !alt;
689
690 // ignore specific keys when autocomplete is active, they will be handled later
691 if (autocomplete.isActive() && autocomplete.isSpecialKeyPressed()) {
692 if (autocomplete.hasSuggestions()) {
693 return;
694
695 } else {
696 // this is the exception, cancel autocomplete when special keys are used without any suggestions
697 autocomplete.cancel();
698 }
699 }
700
701 // cursor movements and selections
702 if (isOptionalShift && ImGui::IsKeyPressed(ImGuiKey_UpArrow)) { moveUp(1, shift); }
703 else if (isOptionalShift && ImGui::IsKeyPressed(ImGuiKey_DownArrow)) { moveDown(1, shift); }
704
705 else if (isMetaShift && ImGui::IsKeyPressed(ImGuiKey_LeftArrow)) { shrinkSelectionsToCurlyBrackets(); }
706 else if (isMetaShift && ImGui::IsKeyPressed(ImGuiKey_RightArrow)) { growSelectionsToCurlyBrackets(); }
707 else if (isOptionalMetaShift && ImGui::IsKeyPressed(ImGuiKey_LeftArrow)) { moveLeft(shift, meta); }
708 else if (isOptionalMetaShift && ImGui::IsKeyPressed(ImGuiKey_RightArrow)) { moveRight(shift, meta); }
709
710 else if (isOptionalShift && ImGui::IsKeyPressed(ImGuiKey_PageUp)) { moveUp(visibleLines - 2, shift); }
711 else if (isOptionalShift && ImGui::IsKeyPressed(ImGuiKey_PageDown)) { moveDown(visibleLines - 2, shift); }
712 else if (isOptionalShiftShortcut && ImGui::IsKeyPressed(ImGuiKey_UpArrow)) { moveToTop(shift); }
713 else if (isOptionalShiftShortcut && ImGui::IsKeyPressed(ImGuiKey_Home)) { moveToTop(shift); }
714 else if (isOptionalShiftShortcut && ImGui::IsKeyPressed(ImGuiKey_DownArrow)) { moveToBottom(shift); }
715 else if (isOptionalShiftShortcut && ImGui::IsKeyPressed(ImGuiKey_End)) { moveToBottom(shift); }
716 else if (isOptionalShift && ImGui::IsKeyPressed(ImGuiKey_Home)) { moveToStartOfLine(shift); }
717 else if (isOptionalShift && ImGui::IsKeyPressed(ImGuiKey_End)) { moveToEndOfLine(shift); }
718 else if (isShortcut && ImGui::IsKeyPressed(ImGuiKey_A)) { selectAll(); }
719 else if (isShortcut && ImGui::IsKeyPressed(ImGuiKey_D) && cursors.currentCursorHasSelection()) { addNextOccurrence(); }
720
721 // clipboard operations
722 else if (isShortcut && ImGui::IsKeyPressed(ImGuiKey_X)) { cut(); }
723 else if (isShiftOnly && ImGui::IsKeyPressed(ImGuiKey_Delete)) { cut(); }
724 else if (isShortcut && ImGui::IsKeyPressed(ImGuiKey_C)) { copy() ;}
725 else if (isShortcut && ImGui::IsKeyPressed(ImGuiKey_Insert)) { copy(); }
726
727 else if (!readOnly && isShortcut && ImGui::IsKeyPressed(ImGuiKey_V)) { paste(); }
728 else if (!readOnly && isShiftOnly && ImGui::IsKeyPressed(ImGuiKey_Insert)) { paste(); }
729 else if (!readOnly && isShortcut && ImGui::IsKeyPressed(ImGuiKey_Z)) { undo(); }
730 else if (!readOnly && isShiftShortcut && ImGui::IsKeyPressed(ImGuiKey_Z)) { redo(); }
731 else if (!readOnly && isShortcut && ImGui::IsKeyPressed(ImGuiKey_Y)) { redo(); }
732
733 // remove text
734 else if (!readOnly && isOptionalAlt && ImGui::IsKeyPressed(ImGuiKey_Delete)) { handleDelete(alt); }
735 else if (!readOnly && isOptionalAlt && ImGui::IsKeyPressed(ImGuiKey_Backspace)) { handleBackspace(alt); }
736 else if (!readOnly && isShiftShortcut && ImGui::IsKeyPressed(ImGuiKey_K)) { removeSelectedLines(); }
737
738 // text manipulation
739 else if (!readOnly && isShortcut && ImGui::IsKeyPressed(ImGuiKey_LeftBracket)) { deindentLines(); }
740 else if (!readOnly && isShortcut && ImGui::IsKeyPressed(ImGuiKey_RightBracket)) { indentLines(); }
741 else if (!readOnly && isAltOnly && ImGui::IsKeyPressed(ImGuiKey_UpArrow)) { moveUpLines(); }
742 else if (!readOnly && isAltOnly && ImGui::IsKeyPressed(ImGuiKey_DownArrow)) { moveDownLines(); }
743 else if (!readOnly && language && isShortcut && ImGui::IsKeyPressed(ImGuiKey_Slash)) { toggleComments(); }
744
745 // find/replace support
746 else if (isShortcut && ImGui::IsKeyPressed(ImGuiKey_F)) {
747 if (autocomplete.isActive()) {
748 autocomplete.cancel();
749 findCancelledAutocomplete = true;
750 }
751
752 openFindReplace();
753 }
754
755 else if (isShiftShortcut && ImGui::IsKeyPressed(ImGuiKey_F)) { findAll(); }
756 else if (isShortcut && ImGui::IsKeyPressed(ImGuiKey_G)) { findNext(); }
757
758 // autocomplete support
759 else if (!readOnly && ImGui::IsKeyChordPressed(autocomplete.getTriggerShortcut())) {
760 // don't activate if we have multiple cursors active
761 if (cursors.hasMultiple()) {
762 // TODO: inform user
763
764 } else {
765 if (autocomplete.startShortcut(cursors)) {
766 makeCursorVisible();
767 }
768 }
769 }
770
771 // change insert mode
772 else if (isNoModifiers && ImGui::IsKeyPressed(ImGuiKey_Insert)) { overwrite = !overwrite; }
773
774 // handle new line
775 else if (!readOnly && isNoModifiers && (ImGui::IsKeyPressed(ImGuiKey_Enter) || ImGui::IsKeyPressed(ImGuiKey_KeypadEnter))) { handleCharacter('\n'); }
776 else if (!readOnly && isShortcut && (ImGui::IsKeyPressed(ImGuiKey_Enter) || ImGui::IsKeyPressed(ImGuiKey_KeypadEnter))) { insertLineBelow(); }
777 else if (!readOnly && isShiftShortcut && (ImGui::IsKeyPressed(ImGuiKey_Enter) || ImGui::IsKeyPressed(ImGuiKey_KeypadEnter))) { insertLineAbove(); }
778
779 // handle tabs
780 else if (!readOnly && isOptionalShift && ImGui::IsKeyPressed(ImGuiKey_Tab)) {
781 if (cursors.anyHasSelection()) {
782 if (shift) {
783 deindentLines();
784
785 } else {
786 indentLines();
787 }
788
789 } else {
790 handleCharacter('\t');
791 }
792 }
793
794 // handle escape key
795 else if (ImGui::IsKeyPressed(ImGuiKey_Escape)) {
796 if (autocomplete.isActive()) {
797 autocomplete.cancel();
798
799 } else if (findReplaceVisible) {
800 closeFindReplace();
801
802 } else if (cursors.hasMultiple()) {
803 cursors.clearAdditional();
804 }
805 }
806
807 // handle regular text
808 if (!io.InputQueueCharacters.empty()) {
809 // ignore Ctrl inputs, but need to allow Alt+Ctrl as some keyboards (e.g. German) use AltGR (which is Alt+Ctrl) to input certain characters
810 if (!(io.KeyCtrl && !io.KeyAlt) && !readOnly) {
811 for (auto i = 0; i < io.InputQueueCharacters.size(); i++) {
812 auto character = io.InputQueueCharacters[i];
813
814 if (character == '\n' || character >= 32) {
815 handleCharacter(character);
816 }
817 }
818 }
819
820 io.InputQueueCharacters.resize(0);
821 }
822 }
823}
824
825
826//
827// TextEditor::handleMouseInteractions
828//
829
830void TextEditor::handleMouseInteractions() {
831 // handle middle mouse button modes
832 panning &= panMode && ImGui::IsMouseDown(ImGuiMouseButton_Middle);
833 auto absoluteMousePos = ImGui::GetMousePos() - ImGui::GetWindowPos();
834
835 if (panning && ImGui::IsMouseDragging(ImGuiMouseButton_Middle)) {
836 // handle middle mouse button panning
837 auto windowSize = ImGui::GetWindowSize();
838 auto mouseDelta = ImGui::GetMouseDragDelta(ImGuiMouseButton_Middle);
839 float dragFactor = ImGui::GetIO().DeltaTime * 15.0f;
840 ImVec2 autoPanMargin(glyphSize.x * 4.0f, glyphSize.y * 2.0f);
841
842 if (absoluteMousePos.x < textOffset + autoPanMargin.x) {
843 mouseDelta.x = (absoluteMousePos.x - (textOffset + autoPanMargin.x)) * dragFactor;
844
845 } else if (absoluteMousePos.x > windowSize.x - verticalScrollBarSize - autoPanMargin.x) {
846 mouseDelta.x = (absoluteMousePos.x - (windowSize.x - verticalScrollBarSize - autoPanMargin.x)) * dragFactor;
847 }
848
849 if (absoluteMousePos.y < autoPanMargin.y) {
850 mouseDelta.y = (absoluteMousePos.y - autoPanMargin.y) * dragFactor;
851
852 } else if (absoluteMousePos.y > windowSize.y - horizontalScrollBarSize - autoPanMargin.y) {
853 mouseDelta.y = (absoluteMousePos.y - (windowSize.y - horizontalScrollBarSize - autoPanMargin.y)) * dragFactor;
854 }
855
856 ImGui::SetScrollX(ImGui::GetScrollX() - mouseDelta.x);
857 ImGui::SetScrollY(ImGui::GetScrollY() - mouseDelta.y);
858 ImGui::ResetMouseDragDelta(ImGuiMouseButton_Middle);
859
860 } else if (scrolling) {
861 // handle middle mouse button scrolling
862 float deadzone = glyphSize.x;
863 auto offset = scrollStart - absoluteMousePos;
864 offset.x = (offset.x < 0.0f) ? std::min(offset.x + deadzone, 0.0f) : std::max(offset.x - deadzone, 0.0f);
865 offset.y = (offset.y < 0.0f) ? std::min(offset.y + deadzone, 0.0f) : std::max(offset.y - deadzone, 0.0f);
866
867 float scrollFactor = ImGui::GetIO().DeltaTime * 5.0f;
868 offset *= scrollFactor;
869
870 ImGui::SetScrollX(ImGui::GetScrollX() - offset.x);
871 ImGui::SetScrollY(ImGui::GetScrollY() - offset.y);
872
873 if (ImGui::IsMouseClicked(ImGuiMouseButton_Left) ||
874 ImGui::IsMouseClicked(ImGuiMouseButton_Middle) ||
875 ImGui::IsMouseClicked(ImGuiMouseButton_Right)) {
876
877 scrolling = false;
878 }
879
880 // ignore other interactions when the editor is not hovered
881 } else if (ImGui::IsWindowHovered()) {
882 auto io = ImGui::GetIO();
883 auto mousePos = ImGui::GetMousePos() - ImGui::GetCursorScreenPos();
884 bool overLineNumbers = showLineNumbers && (absoluteMousePos.x > lineNumberLeftOffset) && (absoluteMousePos.x < lineNumberRightOffset);
885 bool overText = mousePos.x - ImGui::GetScrollX() > textOffset;
886
887 Coordinate glyphCoordinate;
888 Coordinate cursorCoordinate;
889
890 document.normalizeCoordinate(
891 mousePos.y / glyphSize.y,
892 (mousePos.x - textOffset) / glyphSize.x,
893 glyphCoordinate,
894 cursorCoordinate);
895
896 // show text cursor if required
897 if (ImGui::IsWindowFocused() && overText) {
898 ImGui::SetMouseCursor(ImGuiMouseCursor_TextInput);
899 }
900
901 if (ImGui::IsMouseDragging(ImGuiMouseButton_Left)) {
902 // update selection with dragging left mouse button
903 io.WantCaptureMouse = true;
904
905 if (overLineNumbers) {
906 auto& cursor = cursors.getCurrent();
907 auto start = Coordinate(cursorCoordinate.line, 0);
908 auto end = document.getDown(start);
909 cursor.update(cursor.getInteractiveEnd() < cursor.getInteractiveStart() ? start : end);
910
911 } else {
912 cursors.updateCurrentCursor(cursorCoordinate);
913 }
914
915 makeCursorVisible();
916
917 } else if (ImGui::IsMouseClicked(ImGuiMouseButton_Middle)) {
918 // start panning/scrolling mode on middle mouse click
919 if (panMode) {
920 panning = true;
921
922 } else {
923 scrolling = true;
924 scrollStart = absoluteMousePos;
925 }
926
927 } else if (ImGui::IsMouseClicked(ImGuiMouseButton_Right)) {
928 // handle right clicks by setting up context menu (if required)
929 if (overLineNumbers && lineNumberContextMenuCallback) {
930 contextMenuLine = glyphCoordinate.line;
931 ImGui::OpenPopup("LineNumberContextMenu");
932
933 } else if (overText && textContextMenuCallback) {
934 contextMenuLine = glyphCoordinate.line;
935 contextMenuColumn = glyphCoordinate.column;
936 ImGui::OpenPopup("TextContextMenu");
937 }
938
939 } else if (ImGui::IsMouseClicked(ImGuiMouseButton_Left)) {
940 // handle left mouse button actions
941 auto click = ImGui::IsMouseClicked(ImGuiMouseButton_Left);
942 auto doubleClick = ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left);
943 auto now = static_cast<float>(ImGui::GetTime());
944 auto tripleClick = click && !doubleClick && (lastClickTime != -1.0f && (now - lastClickTime) < io.MouseDoubleClickTime);
945
946 if (click || doubleClick || tripleClick) {
947 lastClickTime = tripleClick ? -1.0f : now;
948 }
949
950 if (tripleClick) {
951 // left mouse button triple click
952 if (overText) {
953 auto start = document.getStartOfLine(cursorCoordinate);
954 auto end = document.getDown(start);
955 cursors.updateCurrentCursor(start, end);
956 }
957
958 } else if (doubleClick) {
959 // left mouse button double click
960 if (overText) {
961 auto codepoint = document.getCodePoint(glyphCoordinate);
962 bool handled = false;
963
964 // select bracketed section (if required)
965 if (CodePoint::isBracketOpener(codepoint)) {
966 auto brackets = bracketeer.getEnclosingBrackets(document.getRight(glyphCoordinate));
967
968 if (brackets != bracketeer.end()) {
969 if (ImGui::IsKeyDown(ImGuiMod_Shift)) {
970 cursors.setCursor(brackets->start, document.getRight(brackets->end));
971
972 } else {
973 cursors.setCursor(document.getRight(brackets->start), brackets->end);
974 }
975
976 handled = true;
977 }
978
979 } else if (CodePoint::isBracketCloser(codepoint)) {
980 auto brackets = bracketeer.getEnclosingBrackets(glyphCoordinate);
981
982 if (brackets != bracketeer.end()) {
983 cursors.setCursor(brackets->start, document.getRight(brackets->end));
984 handled = true;
985 }
986 }
987
988 // select "word" if it wasn't a bracketed section
989 // includes whitespace and operator sequences as well
990 if (!handled && !document.isEndOfLine(glyphCoordinate)) {
991 auto start = document.findWordStart(glyphCoordinate);
992 auto end = document.findWordEnd(glyphCoordinate);
993 cursors.updateCurrentCursor(start, end);
994 }
995 }
996
997 } else if (click) {
998 // left mouse button single click
999 auto extendCursor = ImGui::IsKeyDown(ImGuiMod_Shift);
1000
1001 auto addCursor = ImGui::GetIO().ConfigMacOSXBehaviors
1002 ? ImGui::IsKeyDown(ImGuiMod_Alt) :
1003 ImGui::IsKeyDown(ImGuiMod_Ctrl);
1004
1005 if (overLineNumbers) {
1006 // handle line number clicks
1007 auto start = Coordinate(cursorCoordinate.line, 0);
1008 auto end = document.getDown(start);
1009
1010 if (extendCursor) {
1011 auto& cursor = cursors.getCurrent();
1012 cursor.update(cursor.getInteractiveEnd() < cursor.getInteractiveStart() ? start : end);
1013 autocomplete.cancel();
1014
1015 } else if (addCursor) {
1016 cursors.addCursor(start, end);
1017 autocomplete.cancel();
1018
1019 } else {
1020 cursors.setCursor(start, end);
1021 }
1022
1023 makeCursorVisible();
1024
1025 } else if (overText) {
1026 // handle mouse clicks in text
1027 if (extendCursor) {
1028 cursors.updateCurrentCursor(cursorCoordinate);
1029 autocomplete.cancel();
1030
1031 } else if (addCursor) {
1032 cursors.addCursor(cursorCoordinate);
1033 autocomplete.cancel();
1034
1035 } else {
1036 cursors.setCursor(cursorCoordinate);
1037 }
1038
1039 makeCursorVisible();
1040 }
1041 }
1042 }
1043 }
1044}
1045
1046
1047//
1048// TextEditor::selectAll
1049//
1050
1051void TextEditor::selectAll() {
1052 moveToTop(false);
1053 moveToBottom(true);
1054}
1055
1056
1057//
1058// TextEditor::selectLine
1059//
1060
1061void TextEditor::selectLine(int line) {
1062 Coordinate start{line, 0};
1063 moveTo(start, false);
1064 moveTo(document.getDown(start), true);
1065}
1066
1067
1068//
1069// TextEditor::selectLines
1070//
1071
1072void TextEditor::selectLines(int startLine, int endLine) {
1073 Coordinate start{startLine, 0};
1074 moveTo(start, false);
1075 moveTo(document.getDown(start, endLine - startLine + 1), true);
1076}
1077
1078
1079//
1080// TextEditor::selectRegion
1081//
1082
1083void TextEditor::selectRegion(int startLine, int startColumn, int endLine, int endColumn) {
1084 auto start = document.normalizeCoordinate(Coordinate(startLine, startColumn));
1085 auto end = document.normalizeCoordinate(Coordinate(endLine, endColumn));
1086
1087 if (end < start) {
1088 std::swap(start, end);
1089 }
1090
1091 cursors.setCursor(start, end);
1092}
1093
1094
1095//
1096// TextEditor::selectToBrackets
1097//
1098
1099void TextEditor::selectToBrackets(bool includeBrackets) {
1100 if (!showMatchingBrackets) {
1101 bracketeer.update(document);
1102 }
1103
1104 for (auto& cursor : cursors) {
1105 auto bracket = bracketeer.getEnclosingBrackets(cursor.getSelectionStart());
1106
1107 if (bracket != bracketeer.end()) {
1108 if (includeBrackets) {
1109 cursor.update(bracket->start, document.getRight(bracket->end));
1110
1111 } else {
1112 cursor.update(document.getRight(bracket->start), bracket->end);
1113 }
1114 }
1115 }
1116}
1117
1118
1119//
1120// TextEditor::growSelectionsToCurlyBrackets
1121//
1122
1123void TextEditor::growSelectionsToCurlyBrackets() {
1124 if (!showMatchingBrackets) {
1125 bracketeer.update(document);
1126 }
1127
1128 for (auto& cursor : cursors) {
1129 auto start = cursor.getSelectionStart();
1130 auto end = cursor.getSelectionEnd();
1131 auto startCodePoint = document.getCodePoint(document.getLeft(start));
1132 auto endCodePoint = document.getCodePoint(end);
1133
1134 if (startCodePoint == CodePoint::openCurlyBracket && endCodePoint == CodePoint::closeCurlyBracket) {
1135 cursor.update(document.getLeft(start),document.getRight(end));
1136
1137 } else {
1138 auto bracket = bracketeer.getEnclosingCurlyBrackets(start, end);
1139
1140 if (bracket != bracketeer.end()) {
1141 cursor.update(document.getRight(bracket->start), bracket->end);
1142 }
1143 }
1144 }
1145}
1146
1147
1148//
1149// TextEditor::shrinkSelectionsToCurlyBrackets
1150//
1151
1152void TextEditor::shrinkSelectionsToCurlyBrackets() {
1153 if (!showMatchingBrackets) {
1154 bracketeer.update(document);
1155 }
1156
1157 for (auto& cursor : cursors) {
1158 if (cursor.hasSelection()){
1159 auto start = cursor.getSelectionStart();
1160 auto end = cursor.getSelectionEnd();
1161 auto startCodePoint = document.getCodePoint(start);
1162 auto endCodePoint = document.getCodePoint(document.getLeft(end));
1163
1164 if (startCodePoint == CodePoint::openCurlyBracket && endCodePoint == CodePoint::closeCurlyBracket) {
1165 cursor.update(document.getRight(start),document.getLeft(end));
1166
1167 } else {
1168 auto bracket = bracketeer.getInnerCurlyBrackets(start, end);
1169
1170 if (bracket != bracketeer.end()) {
1171 cursor.update(bracket->start, document.getRight(bracket->end));
1172 }
1173 }
1174 }
1175 }
1176}
1177
1178
1179//
1180// TextEditor::cut
1181//
1182
1183void TextEditor::cut() {
1184 // copy selections to clipboard and remove them
1185 copy();
1186 auto transaction = startTransaction();
1187 deleteTextFromAllCursors(transaction);
1188 cursors.getCurrent().resetToStart();
1189 endTransaction(transaction);
1190}
1191
1192
1193//
1194// TextEditor::copy
1195//
1196
1197void TextEditor::copy() const {
1198 // copy all selections and put them on the clipboard
1199 // empty cursors copy the entire line
1200 std::string text;
1201
1202 if (cursors.anyHasSelection()) {
1203 for (auto& cursor : cursors) {
1204 if (text.size()) {
1205 text += "\n";
1206 }
1207
1208 if (cursor.hasSelection()) {
1209 text += document.getSectionText(cursor.getSelectionStart(), cursor.getSelectionEnd());
1210
1211 } else {
1212 text += document.getLineText(cursor.getSelectionStart().line);
1213 }
1214 }
1215
1216 } else {
1217 for (auto& cursor : cursors) {
1218 text += document.getLineText(cursor.getSelectionStart().line) + "\n";
1219 }
1220 }
1221
1222 ImGui::SetClipboardText(text.c_str());
1223}
1224
1225
1226//
1227// TextEditor::paste
1228//
1229
1230void TextEditor::paste() {
1231 // ignore non-text clipboard content
1232 auto clipboard = ImGui::GetClipboardText();
1233
1234 if (clipboard) {
1235 auto transaction = startTransaction();
1236 insertTextIntoAllCursors(transaction, clipboard);
1237 endTransaction(transaction);
1238 }
1239}
1240
1241
1242//
1243// TextEditor::undo
1244//
1245
1246void TextEditor::undo() {
1247 if (transactions.canUndo()) {
1248 transactions.undo(document, cursors);
1249 makeCursorVisible();
1250 }
1251}
1252
1253
1254//
1255// TextEditor::redo
1256//
1257
1258void TextEditor::redo() {
1259 if (transactions.canRedo()) {
1260 transactions.redo(document, cursors);
1261 makeCursorVisible();
1262 }
1263}
1264
1265
1266//
1267// TextEditor::getCursor
1268//
1269
1270void TextEditor::getCursor(int& line, int& column, size_t cursor) const {
1271 cursor = std::min(cursor, cursors.size() - 1);
1272 auto pos = cursors[cursor].getInteractiveEnd();
1273 line = pos.line;
1274 column = pos.column;
1275}
1276
1277
1278//
1279// TextEditor::getCursor
1280//
1281
1282void TextEditor::getCursor(int& startLine, int& startColumn, int& endLine, int& endColumn, size_t cursor) const {
1283 cursor = std::min(cursor, cursors.size() - 1);
1284 auto start = cursors[cursor].getSelectionStart();
1285 auto end = cursors[cursor].getSelectionEnd();
1286 startLine = start.line;
1287 startColumn = start.column;
1288 endLine = end.line;
1289 endColumn = end.column;
1290}
1291
1292
1293//
1294// TextEditor::getCursorText
1295//
1296
1297std::string TextEditor::getCursorText(size_t cursor) const {
1298 cursor = std::min(cursor, cursors.size() - 1);
1299 return document.getSectionText(cursors[cursor].getSelectionStart(), cursors[cursor].getSelectionEnd());
1300}
1301
1302
1303//
1304// TextEditor::GetWordAtScreenPos
1305//
1306
1307std::string TextEditor::GetWordAtScreenPos(const ImVec2& screenPos) const {
1308 // convert screen position to local coordinates using the origin saved during last Render()
1309 auto local = screenPos - lastRenderOrigin;
1310
1311 // convert to text coordinates
1312 Coordinate glyphCoordinate;
1313 Coordinate cursorCoordinate;
1314 document.normalizeCoordinate(local.y / glyphSize.y, (local.x - textOffset) / glyphSize.x, glyphCoordinate, cursorCoordinate);
1315
1316 // Find word boundaries and extract text
1317 auto start = document.findWordStart(glyphCoordinate);
1318 auto end = document.findWordEnd(glyphCoordinate);
1319 return document.getSectionText(start, end);
1320}
1321
1322
1323//
1324// TextEditor::makeCursorVisible
1325//
1326
1327void TextEditor::makeCursorVisible() {
1328 ensureCursorIsVisible = true;
1329 scrollToLineNumber = -1;
1330}
1331
1332
1333//
1334// TextEditor::scrollToLine
1335//
1336
1337void TextEditor::scrollToLine(int line, Scroll alignment) {
1338 ensureCursorIsVisible = false;
1339 scrollToLineNumber = line;
1340 scrollToAlignment = alignment;
1341}
1342
1343
1344//
1345// TextEditor::addMarker
1346//
1347
1348void TextEditor::addMarker(int line, ImU32 lineNumberColor, ImU32 textColor, const std::string_view& lineNumberTooltip, const std::string_view& textTooltip) {
1349 if (line >= 0 && line < document.lineCount()) {
1350 markers.emplace_back(lineNumberColor, textColor, lineNumberTooltip, textTooltip);
1351 document[line].marker = markers.size();
1352 }
1353}
1354
1355
1356//
1357// TextEditor::clearMarkers
1358//
1359
1360void TextEditor::clearMarkers() {
1361 for (auto& line : document) {
1362 line.marker = 0;
1363 }
1364
1365 markers.clear();
1366}
1367
1368
1369//
1370// TextEditor::moveUp
1371//
1372
1373void TextEditor::moveUp(int lines, bool select) {
1374 for (auto& cursor : cursors) {
1375 cursor.update(document.getUp(cursor.getInteractiveEnd(), lines), select);
1376 }
1377
1378 makeCursorVisible();
1379}
1380
1381
1382//
1383// TextEditor::moveDown
1384//
1385
1386void TextEditor::moveDown(int lines, bool select) {
1387 for (auto& cursor : cursors) {
1388 cursor.update(document.getDown(cursor.getInteractiveEnd(), lines), select);
1389 }
1390
1391 makeCursorVisible();
1392}
1393
1394
1395//
1396// TextEditor::moveLeft
1397//
1398
1399void TextEditor::moveLeft(bool select, bool wordMode) {
1400 for (auto& cursor : cursors) {
1401 if (cursor.hasSelection() && !select && !wordMode) {
1402 cursor.resetToStart();
1403
1404 } else {
1405 cursor.update(document.getLeft(cursor.getInteractiveEnd(), wordMode), select);
1406 }
1407 }
1408
1409 makeCursorVisible();
1410}
1411
1412
1413//
1414// TextEditor::moveRight
1415//
1416
1417void TextEditor::moveRight(bool select, bool wordMode) {
1418 for (auto& cursor : cursors) {
1419 if (cursor.hasSelection() && !select && !wordMode) {
1420 cursor.resetToEnd();
1421
1422 } else {
1423 cursor.update(document.getRight(cursor.getInteractiveEnd(), wordMode), select);
1424 }
1425 }
1426
1427 makeCursorVisible();
1428}
1429
1430
1431//
1432// TextEditor::moveToTop
1433//
1434
1435void TextEditor::moveToTop(bool select) {
1436 cursors.clearAdditional();
1437 cursors.updateCurrentCursor(document.getTop(), select);
1438 makeCursorVisible();
1439}
1440
1441
1442//
1443// TextEditor::moveToBottom
1444//
1445
1446void TextEditor::moveToBottom(bool select) {
1447 cursors.clearAdditional();
1448 cursors.updateCurrentCursor(document.getBottom(), select);
1449 makeCursorVisible();
1450}
1451
1452
1453//
1454// TextEditor::moveToStartOfLine
1455//
1456
1457void TextEditor::moveToStartOfLine(bool select) {
1458 cursors.clearAdditional();
1459 cursors.updateCurrentCursor(document.getStartOfLine(cursors.getCurrent().getInteractiveEnd()), select);
1460 makeCursorVisible();
1461}
1462
1463
1464//
1465// TextEditor::moveToEndOfLine
1466//
1467
1468void TextEditor::moveToEndOfLine(bool select) {
1469 cursors.clearAdditional();
1470 cursors.updateCurrentCursor(document.getEndOfLine(cursors.getCurrent().getInteractiveEnd()), select);
1471 makeCursorVisible();
1472}
1473
1474
1475//
1476// TextEditor::moveTo
1477//
1478
1479void TextEditor::moveTo(Coordinate coordinate, bool select) {
1480 cursors.clearAdditional();
1481 cursors.updateCurrentCursor(coordinate, select);
1482 makeCursorVisible();
1483}
1484
1485
1486//
1487// TextEditor::handleCharacter
1488//
1489
1490void TextEditor::handleCharacter(ImWchar character) {
1491 auto transaction = startTransaction(false);
1492
1493 auto opener = character;
1494 auto isPaired = !overwrite && completePairedGlyphs && CodePoint::isPairOpener(opener);
1495 auto closer = CodePoint::toPairCloser(opener);
1496
1497 // ignore input if it was the closing character for a pair that was automatically inserted
1498 if (completePairCloser) {
1499 if (completePairCloser == character && completePairLocation == cursors.getCurrent().getSelectionEnd()) {
1500 completePairCloser = 0;
1501 moveRight(false, false);
1502 return;
1503 }
1504
1505 completePairCloser = 0;
1506 }
1507
1508 if (cursors.anyHasSelection() && isPaired) {
1509 // encapsulate the current selections with the requested pairs
1510 for (auto cursor = cursors.begin(); cursor < cursors.end(); cursor++) {
1511 if (cursor->hasSelection()) {
1512 auto start = cursor->getSelectionStart();
1513 auto end = cursor->getSelectionEnd();
1514
1515 // insert the closing glyph
1516 char utf8[4];
1517 auto end1 = insertText(transaction, end, std::string_view(utf8, CodePoint::write(utf8, closer)));
1518 cursors.adjustForInsert(cursor, start, end1);
1519
1520 // insert the opening glyph
1521 auto end2 = insertText(transaction, start, std::string_view(utf8, CodePoint::write(utf8, opener)));
1522 cursors.adjustForInsert(cursor, start, end2);
1523
1524 // update old selection
1525 cursor->update(Coordinate(start.line, start.column + 1), Coordinate(end.line, end.column + 1));
1526 }
1527 }
1528
1529 } else if (isPaired) {
1530 // insert the requested pair
1531 char utf8[8];
1532 auto size = CodePoint::write(utf8, opener);
1533 size += CodePoint::write(utf8 + size, closer);
1534 std::string_view pair(utf8, size);
1535
1536 for (auto cursor = cursors.begin(); cursor < cursors.end(); cursor++) {
1537 auto start = cursor->getSelectionStart();
1538 auto end = insertText(transaction, start, pair);
1539 cursors.adjustForInsert(cursor, start, end);
1540 cursor->update(Coordinate(start.line, start.column + 1), false);
1541 }
1542
1543 // remember the closer
1544 completePairCloser = closer;
1545 completePairLocation = cursors.getCurrent().getSelectionEnd();
1546
1547 } else if (!overwrite && autoIndent && character == '\n') {
1548 // handle auto indent case
1549 autoIndentAllCursors(transaction);
1550
1551 } else {
1552 // handle overwrite by deleting next glyph before insert
1553 if (overwrite) {
1554 for (auto cursor = cursors.begin(); cursor < cursors.end(); cursor++) {
1555 if (!cursor->hasSelection()) {
1556 auto start = cursor->getSelectionStart();
1557
1558 if (start != document.getEndOfLine(start)) {
1559 auto end = document.getRight(start);
1560 deleteText(transaction, start, end);
1561 cursors.adjustForDelete(cursor, start, end);
1562 }
1563 }
1564 }
1565 }
1566
1567 // just insert a regular character
1568 char utf8[4];
1569 insertTextIntoAllCursors(transaction, std::string_view(utf8, CodePoint::write(utf8, character)));
1570 }
1571
1572 endTransaction(transaction);
1573
1574 if (CodePoint::isWord(character)) {
1575 if (autocomplete.startTyping(cursors)) {
1576 makeCursorVisible();
1577 }
1578 }
1579}
1580
1581
1582//
1583// TextEditor::handleBackspace
1584//
1585
1586void TextEditor::handleBackspace(bool wordMode) {
1587 auto transaction = startTransaction(false);
1588
1589 // remove selections or characters to the left of the cursor
1590 for (auto cursor = cursors.begin(); cursor < cursors.end(); cursor++) {
1591 auto start = cursor->hasSelection() ? cursor->getSelectionStart() : document.getLeft(cursor->getSelectionStart(), wordMode);
1592 auto end = cursor->getSelectionEnd();
1593 deleteText(transaction, start, end);
1594 cursor->update(start, false);
1595 cursors.adjustForDelete(cursor, start, end);
1596 }
1597
1598 endTransaction(transaction);
1599}
1600
1601
1602//
1603// TextEditor::handleDelete
1604//
1605
1606void TextEditor::handleDelete(bool wordMode) {
1607 auto transaction = startTransaction(false);
1608
1609 // remove selections or characters to the right of the cursor
1610 for (auto cursor = cursors.begin(); cursor < cursors.end(); cursor++) {
1611 auto start = cursor->getSelectionStart();
1612 auto end = cursor->hasSelection() ? cursor->getSelectionEnd() : document.getRight(cursor->getSelectionEnd(), wordMode);
1613 deleteText(transaction, start, end);
1614 cursor->update(start, false);
1615 cursors.adjustForDelete(cursor, start, end);
1616 }
1617
1618 endTransaction(transaction);
1619}
1620
1621
1622//
1623// TextEditor::removeSelectedLines
1624//
1625
1626void TextEditor::removeSelectedLines() {
1627 auto transaction = startTransaction();
1628
1629 for (auto cursor = cursors.begin(); cursor < cursors.end(); cursor++) {
1630 auto start = document.getStartOfLine(cursor->getSelectionStart());
1631 auto end = cursor->getSelectionEnd();
1632 end = (end.column == 0) ? end : document.getNextLine(end);
1633 deleteText(transaction, start, end);
1634 cursor->update(start, false);
1635 cursors.adjustForDelete(cursor, start, end);
1636 }
1637
1638 endTransaction(transaction);
1639}
1640
1641
1642//
1643// TextEditor::insertLineAbove
1644//
1645
1646void TextEditor::insertLineAbove() {
1647 auto transaction = startTransaction();
1648
1649 for (auto cursor = cursors.begin(); cursor < cursors.end(); cursor++) {
1650 auto start = document.getStartOfLine(cursor->getSelectionStart());
1651 auto end = insertText(transaction, start, "\n");
1652 cursor->update(start, false);
1653 cursors.adjustForInsert(cursor, start, end);
1654 }
1655
1656 endTransaction(transaction);
1657}
1658
1659
1660//
1661// TextEditor::insertLineBelow
1662//
1663
1664void TextEditor::insertLineBelow() {
1665 auto transaction = startTransaction();
1666
1667 for (auto cursor = cursors.begin(); cursor < cursors.end(); cursor++) {
1668 auto start = cursor->getSelectionEnd();
1669 start = (start.column == 0) ? start : document.getNextLine(start);
1670 auto end = insertText(transaction, start, "\n");
1671 cursor->update(start, false);
1672 cursors.adjustForInsert(cursor, start, end);
1673 }
1674
1675 endTransaction(transaction);
1676}
1677
1678
1679//
1680// TextEditor::indentLines
1681//
1682
1683void TextEditor::indentLines() {
1684 auto transaction = startTransaction();
1685
1686 // process all cursors
1687 for (auto cursor = cursors.begin(); cursor < cursors.end(); cursor++) {
1688 auto cursorStart = cursor->getSelectionStart();
1689 auto cursorEnd = cursor->getSelectionEnd();
1690
1691 // process all lines in this cursor
1692 for (auto line = cursorStart.line; line <= cursorEnd.line; line++) {
1693 if (Coordinate(line, 0) != cursorEnd && document[line].size()) {
1694 auto insertStart = Coordinate(line, 0);
1695 auto insertEnd = insertText(transaction, insertStart, "\t");
1696 cursors.adjustForInsert(cursor, insertStart, insertEnd);
1697 }
1698 }
1699
1700 auto tabSize = document.getTabSize();
1701 cursorStart.column += cursorStart.column ? tabSize : 0;
1702 cursorEnd.column += cursorEnd.column ? tabSize : 0;
1703 cursor->update(cursorStart, cursorEnd);
1704 }
1705
1706 endTransaction(transaction);
1707}
1708
1709
1710//
1711// TextEditor::deindentLines
1712//
1713
1714void TextEditor::deindentLines() {
1715 auto transaction = startTransaction();
1716
1717 // process all cursors
1718 for (auto cursor = cursors.begin(); cursor < cursors.end(); cursor++) {
1719 auto cursorStart = cursor->getSelectionStart();
1720 auto cursorEnd = cursor->getSelectionEnd();
1721 auto tabSize = document.getTabSize();
1722
1723 for (auto line = cursorStart.line; line <= cursorEnd.line; line++) {
1724 // determine how many whitespaces are available at the start with a max of 4 columns
1725 int column = 0;
1726 size_t index = 0;
1727
1728 while (column < 4 && index < document[line].size() && std::isblank(document[line][index].codepoint)) {
1729 column += document[line][index].codepoint == '\t' ? tabSize - (column % tabSize) : 1;
1730 index++;
1731 }
1732
1733 // delete that whitespace (if required)
1734 Coordinate deleteStart{line, 0};
1735 Coordinate deleteEnd{line, document.getColumn(line, index)};
1736
1737 if (deleteEnd != deleteStart) {
1738 deleteText(transaction, deleteStart, deleteEnd);
1739 cursors.adjustForDelete(cursor, deleteStart, deleteEnd);
1740 }
1741 }
1742 }
1743
1744 endTransaction(transaction);
1745}
1746
1747
1748//
1749// Widget::moveUpLines
1750//
1751
1752void TextEditor::moveUpLines() {
1753 // don't move up if first line is in one of the cursors
1754 if (cursors[0].getSelectionStart().line != 0) {
1755 auto transaction = startTransaction();
1756
1757 for (auto cursor = cursors.begin(); cursor < cursors.end(); cursor++) {
1758 auto start = cursor->getSelectionStart();
1759 auto end = cursor->getSelectionEnd();
1760
1761 // delete existing lines
1762 auto deleteStart = document.getStartOfLine(start);
1763 auto deleteEnd = (end.column == 0) ? end : document.getNextLine(end);
1764 auto text = document.getSectionText(deleteStart, deleteEnd);
1765 deleteText(transaction, deleteStart, deleteEnd);
1766 cursors.adjustForDelete(cursor, deleteStart, deleteEnd);
1767
1768 // insert text one line up
1769 auto insertStart = document.getUp(deleteStart);
1770 auto insertEnd = insertText(transaction, insertStart, text);
1771 cursors.adjustForInsert(cursor, insertStart, insertEnd);
1772
1773 // update cursor
1774 cursor->update(start - Coordinate(1, 0), end - Coordinate(1, 0));
1775 }
1776
1777 endTransaction(transaction);
1778 }
1779}
1780
1781
1782//
1783// TextEditor::moveDownLines
1784//
1785
1786void TextEditor::moveDownLines() {
1787 // don't move up if last line is in one of the cursors
1788 if (!document.isLastLine(cursors[cursors.size() - 1].getSelectionStart().line)) {
1789 auto transaction = startTransaction();
1790
1791 for (auto cursor = cursors.begin(); cursor < cursors.end(); cursor++) {
1792 auto start = cursor->getSelectionStart();
1793 auto end = cursor->getSelectionEnd();
1794
1795 // delete existing lines
1796 auto deleteStart = document.getStartOfLine(start);
1797 auto deleteEnd = (end.column == 0) ? end : document.getNextLine(end);
1798 auto text = document.getSectionText(deleteStart, deleteEnd);
1799 deleteText(transaction, deleteStart, deleteEnd);
1800 cursors.adjustForDelete(cursor, deleteStart, deleteEnd);
1801
1802 // insert text one line down
1803 auto insertStart = document.getDown(deleteStart);
1804 auto insertEnd = insertText(transaction, insertStart, text);
1805 cursors.adjustForInsert(cursor, insertStart, insertEnd);
1806
1807 // update cursor
1808 cursor->update(start + Coordinate(1, 0), end + Coordinate(1, 0));
1809 }
1810
1811 endTransaction(transaction);
1812 }
1813}
1814
1815
1816//
1817// TextEditor::toggleComments
1818//
1819
1820void TextEditor::toggleComments() {
1821 auto transaction = startTransaction();
1822 auto comment = language->singleLineComment;
1823
1824 // process all cursors
1825 for (auto cursor = cursors.begin(); cursor < cursors.end(); cursor++) {
1826 auto cursorStart = cursor->getSelectionStart();
1827 auto cursorEnd = cursor->getSelectionEnd();
1828
1829 // process all lines in this cursor
1830 for (auto line = cursorStart.line; line <= cursorEnd.line; line++) {
1831 if (Coordinate(line, 0) != cursorEnd && document[line].size()) {
1832 // see if line starts with a comment (after possible leading whitespaces)
1833 size_t start = 0;
1834 size_t i = 0;
1835
1836 while (start < document[line].size() && CodePoint::isWhiteSpace(document[line][start].codepoint)) {
1837 start++;
1838 }
1839
1840 while (start + i < document[line].size() && i < comment.size() && document[line][start + i].codepoint == comment[i]) {
1841 i++;
1842 }
1843
1844 if (i == comment.size()) {
1845 auto deleteStart = Coordinate(line, document.getColumn(line, start));
1846 auto deleteEnd = Coordinate(line, document.getColumn(line, start + static_cast<int>(comment.size()) + 1));
1847 deleteText(transaction, deleteStart, deleteEnd);
1848 cursors.adjustForDelete(cursor, deleteStart, deleteEnd);
1849
1850 } else {
1851 auto insertStart = Coordinate(line, document.getColumn(line, start));
1852 auto insertEnd = insertText(transaction, insertStart, comment + " ");
1853 cursors.adjustForInsert(cursor, insertStart, insertEnd);
1854 }
1855 }
1856 }
1857 }
1858
1859 endTransaction(transaction);
1860}
1861
1862
1863//
1864// TextEditor::filterSelections
1865//
1866
1867void TextEditor::filterSelections(std::function<std::string(std::string_view)> filter) {
1868 auto transaction = startTransaction();
1869
1870 // process all cursors
1871 for (auto cursor = cursors.begin(); cursor < cursors.end(); cursor++) {
1872 auto start = cursor->getSelectionStart();
1873 auto end = cursor->getSelectionEnd();
1874
1875 // process all lines in this cursor
1876 for (auto line = start.line; line <= end.line; line++) {
1877 if (Coordinate(line, 0) != end && document[line].size()) {
1878 // get original text and run it through filter
1879 auto before = document.getSectionText(start, end);
1880 std::string after = filter(before);
1881
1882 // update selection if anything changed
1883 if (after != before) {
1884 deleteText(transaction, start, end);
1885 cursors.adjustForDelete(cursor, start, end);
1886 auto newEnd = insertText(transaction, start, after);
1887 cursor->update(start, newEnd);
1888 cursors.adjustForInsert(cursor, start, newEnd);
1889 }
1890 }
1891 }
1892 }
1893
1894 endTransaction(transaction);
1895}
1896
1897
1898//
1899// TextEditor::selectionToLowerCase
1900//
1901
1902void TextEditor::selectionToLowerCase() {
1903 FilterSelections([](const std::string_view& text) {
1904 std::string result;
1905 auto end = text.end();
1906 auto i = text.begin();
1907 char utf8[4];
1908
1909 while (i < end) {
1910 ImWchar codepoint;
1911 i = CodePoint::read(i, end, &codepoint);
1912 result.append(utf8, CodePoint::write(utf8, CodePoint::toLower(codepoint)));
1913 }
1914
1915 return result;
1916 });
1917}
1918
1919
1920//
1921// TextEditor::selectionToUpperCase
1922//
1923
1924void TextEditor::selectionToUpperCase() {
1925 FilterSelections([](const std::string_view& text) {
1926 std::string result;
1927 auto end = text.end();
1928 auto i = text.begin();
1929 char utf8[4];
1930
1931 while (i < end) {
1932 ImWchar codepoint;
1933 i = CodePoint::read(i, end, &codepoint);
1934 result.append(utf8, CodePoint::write(utf8, CodePoint::toUpper(codepoint)));
1935 }
1936
1937 return result;
1938 });
1939}
1940
1941
1942//
1943// TextEditor::stripTrailingWhitespaces
1944//
1945
1946void TextEditor::stripTrailingWhitespaces() {
1947 auto transaction = startTransaction();
1948
1949 // process all the lines
1950 for (int i = 0; i < document.lineCount(); i++) {
1951 auto& line = document[i];
1952 size_t lineSize = line.size();
1953 size_t whitespace = std::numeric_limits<std::size_t>::max();
1954 bool done = false;
1955
1956 // look for first non-whitespace glyph at the end of the line
1957 if (lineSize) {
1958 for (auto index = lineSize - 1; !done; index--) {
1959 if (CodePoint::isWhiteSpace(line[index].codepoint)) {
1960 whitespace = index;
1961
1962 if (index == 0) {
1963 done = true;
1964 }
1965
1966 } else {
1967 done = true;
1968 }
1969 }
1970 }
1971
1972 // remove whitespaces (if required)
1973 if (whitespace != std::numeric_limits<std::size_t>::max()) {
1974 auto start = Coordinate(i, document.getColumn(line, whitespace));
1975 auto end = Coordinate(i, document.getColumn(line, lineSize));
1976 deleteText(transaction, start, end);
1977 }
1978 }
1979
1980 // update cursor if transaction wasn't empty
1981 if (endTransaction(transaction)) {
1982 cursors.setCursor(document.normalizeCoordinate(cursors.getCurrent().getSelectionEnd()));
1983 }
1984}
1985
1986
1987//
1988// TextEditor::filterLines
1989//
1990
1991void TextEditor::filterLines(std::function<std::string(std::string_view)> filter) {
1992 auto transaction = startTransaction();
1993
1994 // process all the lines
1995 for (int i = 0; i < document.lineCount(); i++) {
1996 // get original text and run it through filter
1997 auto before = document.getLineText(i);
1998 std::string after = filter(before);
1999
2000 // update line if anything changed
2001 if (after != before) {
2002 auto start = Coordinate(i, 0);
2003 auto end = document.getEndOfLine(start);
2004 deleteText(transaction, start, end);
2005 insertText(transaction, start, after);
2006 }
2007 }
2008
2009 // update cursor if transaction wasn't empty
2010 if (endTransaction(transaction)) {
2011 cursors.setCursor(document.normalizeCoordinate(cursors.getCurrent().getSelectionEnd()));
2012 }
2013}
2014
2015
2016//
2017// TextEditor::tabsToSpaces
2018//
2019
2020void TextEditor::tabsToSpaces() {
2021 filterLines([this](const std::string_view& input) {
2022 auto tabSize = static_cast<size_t>(document.getTabSize());
2023 std::string output;
2024 auto end = input.end();
2025 auto i = input.begin();
2026 size_t pos = 0;
2027
2028 while (i < end) {
2029 char utf8[4];
2030 ImWchar codepoint;
2031 i = CodePoint::read(i, end, &codepoint);
2032
2033 if (codepoint == '\t') {
2034 auto spaces = tabSize - (pos % tabSize);
2035 output.append(spaces, ' ');
2036 pos += spaces;
2037
2038 } else {
2039 output.append(utf8, CodePoint::write(utf8, codepoint));
2040 pos++;
2041 }
2042 }
2043
2044 return output;
2045 });
2046}
2047
2048
2049//
2050// TextEditor::spacesToTabs
2051//
2052
2053void TextEditor::spacesToTabs() {
2054 FilterLines([this](const std::string_view& input) {
2055 auto tabSize = static_cast<size_t>(document.getTabSize());
2056 std::string output;
2057 auto end = input.end();
2058 auto i = input.begin();
2059 size_t pos = 0;
2060 size_t spaces = 0;
2061
2062 while (i < end) {
2063 char utf8[4];
2064 ImWchar codepoint;
2065 i = CodePoint::read(i, end, &codepoint);
2066
2067 if (codepoint == ' ') {
2068 spaces++;
2069
2070 } else {
2071 while (spaces) {
2072 auto spacesUntilNextTab = tabSize - (pos % tabSize);
2073
2074 if (spacesUntilNextTab == 1) {
2075 output += ' ';
2076 pos++;
2077 spaces--;
2078
2079 } else if (spaces >= spacesUntilNextTab) {
2080 output += '\t';
2081 pos += spacesUntilNextTab;
2082 spaces -= spacesUntilNextTab;
2083
2084 } else if (codepoint != '\t')
2085 while (spaces) {
2086 output += ' ';
2087 pos++;
2088 spaces--;
2089 }
2090
2091 else {
2092 spaces = 0;
2093 }
2094 }
2095
2096 if (codepoint == '\t') {
2097 output += '\t';
2098 pos += tabSize - (pos % tabSize);
2099
2100 } else {
2101 output.append(utf8, CodePoint::write(utf8, codepoint));
2102 pos++;
2103 }
2104 }
2105 }
2106
2107 return output;
2108 });
2109}
2110
2111
2112//
2113// TextEditor::startTransaction
2114//
2115
2116std::shared_ptr<TextEditor::Transaction> TextEditor::startTransaction(bool cancelsAutoComplete) {
2117 if (cancelsAutoComplete) {
2118 autocomplete.cancel();
2119 }
2120
2121 std::shared_ptr<Transaction> transaction = Transactions::create();
2122 transaction->setBeforeState(cursors);
2123 return transaction;
2124}
2125
2126
2127//
2128// TextEditor::endTransaction
2129//
2130
2131bool TextEditor::endTransaction(std::shared_ptr<Transaction> transaction) {
2132 if (transaction->actions() > 0) {
2133 cursors.update();
2134 transaction->setAfterState(cursors);
2135 transactions.add(transaction);
2136 std::vector<Change> changes;
2137
2138 if (transactionCallback) {
2139 for (auto& action : *transaction) {
2140 auto& change = changes.emplace_back();
2141 change.insert = action.type == Action::Type::insertText;
2142
2143 change.startLine = static_cast<int>(action.start.line);
2144 change.startColumn = static_cast<int>(action.start.column);
2145 change.startIndex = static_cast<int>(document.getIndex(action.start));
2146
2147 change.startLine = static_cast<int>(action.end.line);
2148 change.startColumn = static_cast<int>(action.end.column);
2149 change.startIndex = static_cast<int>(document.getIndex(action.end));
2150
2151 change.text = action.text;
2152 }
2153
2154 transactionCallback(changes);
2155 }
2156
2157 return true;
2158
2159 } else {
2160 return false;
2161 }
2162}
2163
2164
2165//
2166// TextEditor::insertTextIntoAllCursors
2167//
2168
2169void TextEditor::insertTextIntoAllCursors(std::shared_ptr<Transaction> transaction, const std::string_view& text) {
2170 // delete any selection content first
2171 deleteTextFromAllCursors(transaction);
2172
2173 // insert the text
2174 for (auto cursor = cursors.begin(); cursor < cursors.end(); cursor++) {
2175 auto start = cursor->getSelectionStart();
2176 auto end = insertText(transaction, start, text);
2177 cursor->update(end, false);
2178 cursors.adjustForInsert(cursor, start, end);
2179 }
2180}
2181
2182
2183//
2184// TextEditor::deleteTextFromAllCursors
2185//
2186
2187void TextEditor::deleteTextFromAllCursors(std::shared_ptr<Transaction> transaction) {
2188 for (auto cursor = cursors.begin(); cursor < cursors.end(); cursor++) {
2189 if (cursor->hasSelection()) {
2190 auto start = cursor->getSelectionStart();
2191 auto end = cursor->getSelectionEnd();
2192 deleteText(transaction, start, end);
2193 cursor->update(start, false);
2194 cursors.adjustForDelete(cursor, start, end);
2195 }
2196 }
2197}
2198
2199
2200//
2201// TextEditor::autoIndentAllCursors
2202//
2203
2204void TextEditor::autoIndentAllCursors(std::shared_ptr<Transaction> transaction) {
2205 for (auto cursor = cursors.begin(); cursor < cursors.end(); cursor++) {
2206 auto start = cursor->getSelectionStart();
2207
2208 // delete any selections
2209 if (cursor->hasSelection()) {
2210 auto end = cursor->getSelectionEnd();
2211 deleteText(transaction, start, end);
2212 cursors.adjustForDelete(cursor, start, end);
2213 }
2214
2215 // get previous and next character
2216 auto index = document.getIndex(start);
2217 auto& line = document[start.line];
2218 ImWchar previousChar = index > 0 ? line[index - 1].codepoint : 0;
2219 ImWchar nextChar = index < line.size() ? line[index].codepoint : 0;
2220
2221 // remove extra whitespaces if required
2222 if (CodePoint::isWhiteSpace(nextChar)) {
2223 while (index < line.size() && CodePoint::isWhiteSpace(line[index].codepoint)) {
2224 index++;
2225 }
2226
2227 auto end = Coordinate(start.line, document.getColumn(start.line, index));
2228 deleteText(transaction, start, end);
2229 cursors.adjustForDelete(cursor, start, end);
2230 }
2231
2232 // determine whitespace at start of current line
2233 std::string whitespace;
2234
2235 for (size_t i = 0; i < line.size() && CodePoint::isWhiteSpace(line[i].codepoint); i++) {
2236 char utf8[4];
2237 whitespace.append(utf8, CodePoint::write(utf8, line[i].codepoint));
2238 }
2239
2240 // determine text to insert
2241 std::string insert = "\n" + whitespace;
2242 auto newCursorIndex = static_cast<int>(whitespace.size());
2243
2244 // handle special cases
2245 if (previousChar == CodePoint::openCurlyBracket || previousChar == CodePoint::openSquareBracket) {
2246 // add to an existing block
2247 insert += "\t";
2248 newCursorIndex++;
2249
2250 if ((previousChar == CodePoint::openCurlyBracket && nextChar == CodePoint::closeCurlyBracket) ||
2251 (previousChar == CodePoint::openSquareBracket && nextChar == CodePoint::closeSquareBracket)) {
2252
2253 // open a new block
2254 insert += "\n" + whitespace;
2255 }
2256 }
2257
2258 // insert new text
2259 auto end = insertText(transaction, start, insert);
2260 cursors.adjustForInsert(cursor, start, end);
2261
2262 // set new cursor location
2263 cursor->update(Coordinate(start.line + 1, document.getColumn(start.line + 1, newCursorIndex)), false);
2264 }
2265}
2266
2267
2268//
2269// TextEditor::insertText
2270//
2271
2272TextEditor::Coordinate TextEditor::insertText(std::shared_ptr<Transaction> transaction, Coordinate start, const std::string_view& text) {
2273 // update document, add transaction and return coordinate of end of insert
2274 // this function does not touch the cursors
2275 auto end = document.insertText(start, text);
2276 transaction->addInsert(start, end, text);
2277 makeCursorVisible();
2278 return end;
2279}
2280
2281
2282//
2283// TextEditor::deleteText
2284//
2285
2286void TextEditor::deleteText(std::shared_ptr<Transaction> transaction, Coordinate start, Coordinate end) {
2287 // update document and add transaction
2288 // this function does not touch the cursors
2289 auto text = document.getSectionText(start, end);
2290 document.deleteText(start, end);
2291 transaction->addDelete(start, end, text);
2292 makeCursorVisible();
2293}
2294
2295
2296//
2297// TextEditor::updatePalette
2298//
2299
2300void TextEditor::updatePalette() {
2301 // Update palette with the current alpha from style
2302 paletteAlpha = ImGui::GetStyle().Alpha;
2303
2304 for (size_t i = 0; i < static_cast<size_t>(Color::count); i++) {
2305 auto color = ImGui::ColorConvertU32ToFloat4(paletteBase[i]);
2306 color.w *= paletteAlpha;
2307 palette[i] = ImGui::ColorConvertFloat4ToU32(color);
2308 }
2309}
2310
2311
2312//
2313// Color palettes
2314//
2315
2316const TextEditor::Palette& TextEditor::GetDarkPalette() {
2317 const static Palette p = {{
2318 IM_COL32(224, 224, 224, 255), // text
2319 IM_COL32(197, 134, 192, 255), // keyword
2320 IM_COL32( 90, 179, 155, 255), // declaration
2321 IM_COL32(181, 206, 168, 255), // number
2322 IM_COL32(206, 145, 120, 255), // string
2323 IM_COL32(255, 255, 153, 255), // punctuation
2324 IM_COL32( 64, 192, 128, 255), // preprocessor
2325 IM_COL32(156, 220, 254, 255), // identifier
2326 IM_COL32( 79, 193, 255, 255), // known identifier
2327 IM_COL32(106, 153, 85, 255), // comment
2328 IM_COL32( 30, 30, 30, 255), // background
2329 IM_COL32(224, 224, 224, 255), // cursor
2330 IM_COL32( 32, 96, 160, 255), // selection
2331 IM_COL32( 80, 80, 80, 255), // whitespace
2332 IM_COL32( 70, 70, 70, 255), // matchingBracketBackground
2333 IM_COL32(140, 140, 140, 255), // matchingBracketActive
2334 IM_COL32(246, 222, 36, 255), // matchingBracketLevel1
2335 IM_COL32( 66, 120, 198, 255), // matchingBracketLevel2
2336 IM_COL32(213, 96, 213, 255), // matchingBracketLevel3
2337 IM_COL32(198, 8, 32, 255), // matchingBracketError
2338 IM_COL32(128, 128, 144, 255), // line number
2339 IM_COL32(224, 224, 240, 255), // current line number
2340 }};
2341
2342 return p;
2343}
2344
2345const TextEditor::Palette& TextEditor::GetLightPalette()
2346{
2347 const static Palette p = {{
2348 IM_COL32( 64, 64, 64, 255), // text
2349 IM_COL32( 170, 0, 220, 255), // keyword
2350 IM_COL32( 65, 0, 255, 255), // declaration
2351 IM_COL32( 40, 140, 90, 255), // number
2352 IM_COL32(160, 32, 32, 255), // string
2353 IM_COL32( 0, 0, 0, 255), // punctuation
2354 IM_COL32( 96, 96, 64, 255), // preprocessor
2355 IM_COL32( 64, 64, 64, 255), // identifier
2356 IM_COL32( 16, 96, 96, 255), // known identifier
2357 IM_COL32( 35, 135, 5, 255), // comment
2358 IM_COL32(255, 255, 255, 255), // background
2359 IM_COL32( 0, 0, 0, 255), // cursor
2360 IM_COL32( 0, 0, 96, 64), // selection
2361 IM_COL32(144, 144, 144, 144), // whitespace
2362 IM_COL32(180, 180, 180, 144), // matchingBracketBackground
2363 IM_COL32( 72, 72, 72, 255), // matchingBracketActive
2364 IM_COL32( 70, 0, 250, 255), // matchingBracketLevel1
2365 IM_COL32( 80, 160, 70, 255), // matchingBracketLevel2
2366 IM_COL32(120, 60, 25, 255), // matchingBracketLevel3
2367 IM_COL32(198, 8, 32, 255), // matchingBracketError
2368 IM_COL32( 0, 80, 80, 255), // line number
2369 IM_COL32( 0, 0, 0, 255), // current line number
2370 }};
2371
2372 return p;
2373}
2374
2375TextEditor::Palette TextEditor::defaultPalette = TextEditor::GetDarkPalette();
2376
2377
2378//
2379// TextEditor::Cursor::adjustCoordinateForInsert
2380//
2381
2382TextEditor::Coordinate TextEditor::Cursor::adjustCoordinateForInsert(Coordinate coordinate, Coordinate insertStart, Coordinate insertEnd) {
2383 if (coordinate.line == insertStart.line) {
2384 coordinate.column += insertEnd.column - insertStart.column;
2385 }
2386
2387 coordinate.line += insertEnd.line - insertStart.line;
2388 return coordinate;
2389}
2390
2391
2392//
2393// TextEditor::Cursor::adjustForInsert
2394//
2395
2396void TextEditor::Cursor::adjustForInsert(Coordinate insertStart, Coordinate insertEnd) {
2397 start = adjustCoordinateForInsert(start, insertStart, insertEnd);
2398 end = adjustCoordinateForInsert(end, insertStart, insertEnd);
2399}
2400
2401
2402//
2403// TextEditor::Cursor::adjustCoordinateForDelete
2404//
2405
2406TextEditor::Coordinate TextEditor::Cursor::adjustCoordinateForDelete(Coordinate coordinate, Coordinate deleteStart, Coordinate deleteEnd) {
2407 if (deleteStart.line == deleteEnd.line) {
2408 if (coordinate.line == deleteEnd.line) {
2409 coordinate.column -= deleteEnd.column - deleteStart.column;
2410 }
2411
2412 } else {
2413 coordinate.line -= deleteEnd.line - deleteStart.line;
2414
2415 if (coordinate.line == deleteEnd.line) {
2416 coordinate.column -= deleteEnd.column;
2417 }
2418 }
2419
2420 return coordinate;
2421}
2422
2423
2424//
2425// TextEditor::Cursor::adjustForDelete
2426//
2427
2428void TextEditor::Cursor::adjustForDelete(Coordinate deleteStart, Coordinate deleteEnd) {
2429 start = adjustCoordinateForDelete(start, deleteStart, deleteEnd);
2430 end = adjustCoordinateForDelete(end, deleteStart, deleteEnd);
2431}
2432
2433
2434//
2435// TextEditor::Cursors::reset
2436//
2437
2438void TextEditor::Cursors::reset() {
2439 clear();
2440 main = 0;
2441 current = 0;
2442}
2443
2444
2445//
2446// TextEditor::Cursors::setCursor
2447//
2448
2449void TextEditor::Cursors::setCursor(Coordinate cursorStart, Coordinate cursorEnd) {
2450 reset();
2451 emplace_back(cursorStart, cursorEnd);
2452 front().setMain(true);
2453 front().setCurrent(true);
2454}
2455
2456
2457//
2458// TextEditor::Cursors::addCursor
2459//
2460
2461void TextEditor::Cursors::addCursor(Coordinate start, Coordinate end) {
2462 at(current).setCurrent(false);
2463 emplace_back(start, end);
2464 back().setCurrent(true);
2465 current = size() - 1;
2466}
2467
2468
2469//
2470// TextEditor::Cursors::anyHasSelection
2471//
2472
2473bool TextEditor::Cursors::anyHasSelection() const {
2474 for (auto cursor = begin(); cursor < end(); cursor++) {
2475 if (cursor->hasSelection()) {
2476 return true;
2477 }
2478 }
2479
2480 return false;
2481}
2482
2483
2484//
2485// TextEditor::Cursors::allHaveSelection
2486//
2487
2488bool TextEditor::Cursors::allHaveSelection() const {
2489 for (auto cursor = begin(); cursor < end(); cursor++) {
2490 if (!cursor->hasSelection()) {
2491 return false;
2492 }
2493 }
2494
2495 return true;
2496}
2497
2498
2499//
2500// TextEditor::Cursors::anyHasUpdate
2501//
2502
2503bool TextEditor::Cursors::anyHasUpdate() const {
2504 for (auto cursor = begin(); cursor < end(); cursor++) {
2505 if (cursor->isUpdated()) {
2506 return true;
2507 }
2508 }
2509
2510 return false;
2511}
2512
2513
2514//
2515// TextEditor::Cursors::clearAll
2516//
2517
2518void TextEditor::Cursors::clearAll() {
2519 reset();
2520 emplace_back(Coordinate(0, 0));
2521 front().setMain(true);
2522 front().setCurrent(true);
2523}
2524
2525
2526//
2527// TextEditor::Cursors::clearAdditional
2528//
2529
2530void TextEditor::Cursors::clearAdditional(bool reset) {
2531 for (auto cursor = begin(); cursor < end();) {
2532 if (cursor->isMain()) {
2533 cursor++;
2534
2535 } else {
2536 cursor = erase(cursor);
2537 }
2538 }
2539
2540 main = 0;
2541 current = 0;
2542 front().setCurrent(true);
2543
2544 if (reset) {
2545 front().resetToEnd();
2546 }
2547}
2548
2549
2550//
2551// TextEditor::Cursors::clearUpdated
2552//
2553
2554void TextEditor::Cursors::clearUpdated() {
2555 for (auto cursor = begin(); cursor < end(); cursor++) {
2556 cursor->setUpdated(false);
2557 }
2558}
2559
2560
2561//
2562// TextEditor::Cursors::update
2563//
2564
2565void TextEditor::Cursors::update() {
2566 // reset update flags
2567 clearUpdated();
2568
2569 // only sort and potential merge when we have multiple cursors
2570 if (hasMultiple()) {
2571 // sort cursors
2572 std::sort(begin(), end(), [](Cursor& a, Cursor& b) {
2573 return a.getSelectionStart() < b.getSelectionStart();
2574 });
2575
2576 // merge cursors
2577 for (auto cursor = rbegin(); cursor < rend() - 1;) {
2578 auto previous = cursor + 1;
2579
2580 if (previous->getSelectionEnd() >= cursor->getSelectionEnd()) {
2581 if (cursor->isMain()) {
2582 previous->setMain(true);
2583 }
2584
2585 if (cursor->isCurrent()) {
2586 previous->setCurrent(true);
2587 }
2588
2589 erase((++cursor).base());
2590
2591 } else if (previous->getSelectionEnd() > cursor->getSelectionStart()) {
2592 if (cursor->getInteractiveEnd() < cursor->getInteractiveStart()) {
2593 previous->update(cursor->getSelectionEnd(), previous->getSelectionStart());
2594
2595 } else {
2596 previous->update(previous->getSelectionStart(), cursor->getSelectionEnd());
2597 }
2598
2599 if (cursor->isMain()) {
2600 previous->setMain(true);
2601 }
2602
2603 if (cursor->isCurrent()) {
2604 previous->setCurrent(true);
2605 }
2606
2607 erase((++cursor).base());
2608
2609 } else {
2610 cursor++;
2611 }
2612 }
2613
2614 // find main and current cursor
2615 main = 0;
2616 current = 0;
2617
2618 for (size_t c = 0; c < size(); c++) {
2619 if (at(c).isMain()) {
2620 main = c;
2621
2622 } else if (at(c).isCurrent()) {
2623 current = c;
2624 }
2625 }
2626 }
2627}
2628
2629
2630//
2631// TextEditor::Cursors::adjustForInsert
2632//
2633
2634void TextEditor::Cursors::adjustForInsert(iterator start, Coordinate insertStart, Coordinate insertEnd) {
2635 for (auto cursor = start + 1; cursor < end(); cursor++) {
2636 cursor->adjustForInsert(insertStart, insertEnd);
2637 }
2638}
2639
2640
2641//
2642// TextEditor::Cursors::adjustForDelete
2643//
2644
2645void TextEditor::Cursors::adjustForDelete(iterator start, Coordinate deleteStart, Coordinate deleteEnd) {
2646 for (auto cursor = start + 1; cursor < end(); cursor++) {
2647 cursor->adjustForDelete(deleteStart, deleteEnd);
2648 }
2649}
2650
2651
2652//
2653// TextEditor::Document::setText
2654//
2655
2656void TextEditor::Document::setText(const std::string_view& text) {
2657 // reset document
2658 clearDocument();
2659 appendLine();
2660 updated = true;
2661
2662 // process UTF-8 and generate lines of glyphs
2663 auto end = text.end();
2664 auto i = CodePoint::skipBOM(text.begin(), end);
2665
2666 while (i < end) {
2667 ImWchar character;
2668 i = CodePoint::read(i, end, &character);
2669
2670 if (character == '\n') {
2671 appendLine();
2672
2673 } else if (insertSpacesOnTabs && character == '\t') {
2674 auto spaces = ((back().size() / tabSize) + 1) * tabSize - back().size();
2675
2676 for (size_t s = 0; s < spaces; s++) {
2677 back().emplace_back(Glyph(' ', Color::text));
2678 }
2679
2680 } else if (character != '\r') {
2681 back().emplace_back(Glyph(character, Color::text));
2682 }
2683 }
2684
2685 // update maximum column counts
2686 updateMaximumColumn(0, lineCount() - 1);
2687}
2688
2689
2690//
2691// TextEditor::Document::setText
2692//
2693
2694void TextEditor::Document::setText(const std::vector<std::string_view>& text) {
2695 // reset document
2696 clearDocument();
2697 updated = true;
2698
2699 if (text.size()) {
2700 // process input UTF-8 and generate lines of glyphs
2701 for (auto& line : text) {
2702 appendLine();
2703 auto i = line.begin();
2704 auto end = line.end();
2705
2706 while (i < end) {
2707 ImWchar character;
2708 i = CodePoint::read(i, end, &character);
2709
2710 if (insertSpacesOnTabs && character == '\t') {
2711 auto spaces = ((back().size() / tabSize) + 1) * tabSize - back().size();
2712
2713 for (size_t s = 0; s < spaces; s++) {
2714 back().emplace_back(Glyph(' ', Color::text));
2715 }
2716
2717 } else if (character != '\r') {
2718 back().emplace_back(Glyph(character, Color::text));
2719 }
2720 }
2721 }
2722
2723 } else {
2724 appendLine();
2725 }
2726
2727 // update maximum column counts
2728 updateMaximumColumn(0, lineCount() - 1);
2729}
2730
2731
2732//
2733// TextEditor::Document::insertText
2734//
2735
2736TextEditor::Coordinate TextEditor::Document::insertText(Coordinate start, const std::string_view& text) {
2737 auto line = begin() + start.line;
2738 auto index = getIndex(start);
2739 auto lineNo = start.line;
2740
2741 // process input as UTF-8
2742 auto endOfText = text.end();
2743 auto i = text.begin();
2744
2745 // process all codepoints
2746 while (i < endOfText) {
2747 ImWchar character;
2748 i = CodePoint::read(i, endOfText, &character);
2749
2750 if (character == '\n') {
2751 // split line
2752 insertLine(lineNo + 1);
2753 line = begin() + lineNo;
2754 auto nextLine = begin() + ++lineNo;
2755
2756 for (auto j = line->begin() + index; j < line->end(); j++) {
2757 nextLine->push_back(*j);
2758 }
2759
2760 line->erase(line->begin() + index, line->end());
2761 line = nextLine;
2762 index = 0;
2763
2764 } else if (insertSpacesOnTabs && character == '\t') {
2765 auto spaces = ((index / tabSize) + 1) * tabSize - index;
2766
2767 for (size_t s = 0; s < spaces; s++) {
2768 line->insert(line->begin() + (index++), Glyph(' ', Color::text));
2769 }
2770
2771 } else if (character != '\r') {
2772 // insert next glyph
2773 line->insert(line->begin() + (index++), Glyph(character, Color::text));
2774 }
2775 }
2776
2777 // determine end of insert
2778 auto end = Coordinate(lineNo, getColumn(static_cast<int>(line - begin()), index));
2779
2780 // mark affected lines for colorization
2781 for (auto j = start.line; j <= end.line; j++) {
2782 at(j).colorize = true;
2783 }
2784
2785 // update maximum column counts
2786 updateMaximumColumn(start.line, end.line);
2787
2788 updated = true;
2789 return end;
2790}
2791
2792
2793//
2794// TextEditor::Document::deleteText
2795//
2796
2797void TextEditor::Document::deleteText(Coordinate start, Coordinate end) {
2798 auto& startLine = at(start.line);
2799 auto& endLine = at(end.line);
2800 auto startIndex = getIndex(start);
2801 auto endIndex = getIndex(end);
2802
2803 // see if start and end are on the same line
2804 if (start.line == end.line) {
2805 startLine.erase(startLine.begin() + startIndex, startLine.begin() + endIndex);
2806
2807 // start and end are on different lines
2808 } else {
2809 // remove end of first line
2810 startLine.erase(startLine.begin() + startIndex, startLine.end());
2811
2812 // remove start of last line
2813 endLine.erase(endLine.begin(), endLine.begin() + endIndex);
2814
2815 // join lines
2816 startLine.insert(startLine.end(), endLine.begin(), endLine.end());
2817
2818 // delete lines
2819 deleteLines(start.line + 1, end.line);
2820 }
2821
2822 // remove marker
2823 startLine.marker = 0;
2824
2825 // mark line and document as changed
2826 at(start.line).colorize = true;
2827 updated = true;
2828
2829 // update maximum column counts
2830 updateMaximumColumn(start.line, start.line);
2831}
2832
2833
2834//
2835// TextEditor::Document::getText
2836//
2837
2838std::string TextEditor::Document::getText() const {
2839 // process all glyphs and generate UTF-8 output
2840 std::string text;
2841 char utf8[4];
2842
2843 for (auto line = begin(); line < end(); line++) {
2844 for (auto glyph = line->begin(); glyph < line->end(); glyph++) {
2845 text.append(std::string_view(utf8, CodePoint::write(utf8, glyph->codepoint)));
2846 }
2847
2848 if (line < end() - 1) {
2849 text += "\n";
2850 }
2851 }
2852
2853 return text;
2854}
2855
2856
2857//
2858// TextEditor::Document::getLineText
2859//
2860
2861std::string TextEditor::Document::getLineText(int line) const {
2862 return getSectionText(Coordinate(line, 0), Coordinate(line, at(line).maxColumn));
2863}
2864
2865
2866//
2867// TextEditor::Document::getSectionText
2868//
2869
2870std::string TextEditor::Document::getSectionText(Coordinate start, Coordinate end) const {
2871 std::string section;
2872
2873 auto lineNo = start.line;
2874 auto index = getIndex(start);
2875 auto endIndex = getIndex(end);
2876 char utf8[4];
2877
2878 while (lineNo < end.line || index < endIndex) {
2879 auto& line = at(lineNo);
2880
2881 if (index < line.size()) {
2882 section.append(std::string_view(utf8, CodePoint::write(utf8, line[index].codepoint)));
2883 index++;
2884
2885 } else {
2886 section += '\n';
2887 lineNo++;
2888 index = 0;
2889 }
2890 }
2891
2892 return section;
2893}
2894
2895
2896//
2897// TextEditor::Document::getCodePoint
2898//
2899
2900ImWchar TextEditor::Document::getCodePoint(Coordinate location) const {
2901 auto index = getIndex(location);
2902
2903 if (index < at(location.line).size()) {
2904 return at(location.line)[index].codepoint;
2905
2906 } else {
2907 return IM_UNICODE_CODEPOINT_INVALID;
2908 }
2909}
2910
2911//
2912// TextEditor::Document::getColor
2913//
2914
2915TextEditor::Color TextEditor::Document::getColor(Coordinate location) const {
2916 auto index = getIndex(location);
2917
2918 if (index < at(location.line).size()) {
2919 return at(location.line)[index].color;
2920
2921 } else {
2922 return Color::text;
2923 }
2924}
2925
2926
2927//
2928// TextEditor::Document::updateMaximumColumn
2929//
2930
2931void TextEditor::Document::updateMaximumColumn(int first, int last) {
2932 // process specified lines
2933 for (auto line = begin() + first; line <= begin() + last; line++) {
2934 // determine the maximum column number for this line
2935 int column = 0;
2936
2937 for (auto glyph = line->begin(); glyph < line->end(); glyph++) {
2938 column = (glyph->codepoint == '\t') ? ((column / tabSize) + 1) * tabSize : column + 1;
2939 }
2940
2941 line->maxColumn = column;
2942 }
2943
2944 // determine maximum column number in document
2945 maxColumn = 0;
2946
2947 for (auto line = begin(); line < end(); line++) {
2948 maxColumn = std::max(maxColumn, line->maxColumn);
2949 }
2950}
2951
2952
2953//
2954// TextEditor::Document::getIndex
2955//
2956
2957size_t TextEditor::Document::getIndex(const Line& line, int column) const {
2958 // convert a column reference to a glyph index for a specified line (taking tabs into account)
2959 auto end = line.end();
2960 size_t index = 0;
2961 auto leftCol = 0;
2962 auto rightCol = 0;
2963
2964 for (auto glyph = line.begin(); rightCol < column && glyph < end; glyph++) {
2965 leftCol = rightCol;
2966 rightCol = (glyph->codepoint == '\t') ? ((rightCol / tabSize) + 1) * tabSize : rightCol + 1;
2967 index++;
2968 }
2969
2970 if (rightCol - leftCol <= 1) {
2971 return index;
2972
2973 } else {
2974 auto leftDiff = column - leftCol;
2975 auto rightDiff = rightCol - column;
2976 return leftDiff <= rightDiff ? index - 1 : index;
2977 }
2978}
2979
2980
2981//
2982// TextEditor::Document::getColumn
2983//
2984
2985int TextEditor::Document::getColumn(const Line& line, size_t index) const {
2986 // convert a glyph index to a column reference for the specified line (taking tabs into account)
2987 auto end = line.begin() + index;
2988 int column = 0;
2989
2990 for (auto glyph = line.begin(); glyph < end; glyph++) {
2991 column = (glyph->codepoint == '\t') ? ((column / tabSize) + 1) * tabSize : column + 1;
2992 }
2993
2994 return column;
2995}
2996
2997
2998//
2999// TextEditor::Document::getUp
3000//
3001
3002TextEditor::Coordinate TextEditor::Document::getUp(Coordinate from, int lines) const {
3003 return normalizeCoordinate(Coordinate(from.line - lines, from.column));
3004}
3005
3006
3007//
3008// TextEditor::Document::getDown
3009//
3010
3011TextEditor::Coordinate TextEditor::Document::getDown(Coordinate from, int lines) const {
3012 return normalizeCoordinate(Coordinate(from.line + lines, from.column));
3013}
3014
3015
3016//
3017// TextEditor::Document::getLeft
3018//
3019
3020TextEditor::Coordinate TextEditor::Document::getLeft(Coordinate from, bool wordMode) const {
3021 if (wordMode) {
3022 // first move left by one glyph
3023 from = getLeft(from);
3024
3025 // now skip all whitespaces
3026 from = findPreviousNonWhiteSpace(from, false);
3027
3028 // find the start of the current word
3029 return findWordStart(from);
3030
3031 } else {
3032 // calculate coordinate of previous glyph (could be on previous line)
3033 auto index = getIndex(from);
3034
3035 if (index == 0) {
3036 return (from.line > 0) ? Coordinate(from.line - 1, at(from.line - 1).maxColumn) : from;
3037
3038 } else {
3039 return Coordinate(from.line, getColumn(from.line, index - 1));
3040 }
3041 }
3042}
3043
3044
3045//
3046// TextEditor::Document::getRight
3047//
3048
3049TextEditor::Coordinate TextEditor::Document::getRight(Coordinate from, bool wordMode) const {
3050 if (wordMode) {
3051 // first move right by one glyph
3052 from = getRight(from);
3053
3054 // now skip all whitespaces
3055 from = findNextNonWhiteSpace(from, false);
3056
3057 // find the end of the current word
3058 auto index = getIndex(from);
3059 return findWordEnd(Coordinate(from.line, getColumn(from.line, index)));
3060
3061 } else {
3062 // calculate coordinate of next glyph (could be on next line)
3063 auto index = getIndex(from);
3064
3065 if (index == at(from.line).size()) {
3066 return (from.line < lineCount() - 1) ? Coordinate(from.line + 1, 0) : from;
3067
3068 } else {
3069 return Coordinate(from.line, getColumn(from.line, index + 1));
3070 }
3071 }
3072}
3073
3074
3075//
3076// TextEditor::Document::getTop
3077//
3078
3079TextEditor::Coordinate TextEditor::Document::getTop() const {
3080 return Coordinate(0, 0);
3081}
3082
3083
3084//
3085// TextEditor::Document::getBottom
3086//
3087
3088TextEditor::Coordinate TextEditor::Document::getBottom() const {
3089 auto lastLine = lineCount() - 1;
3090 return Coordinate(lastLine, at(lastLine).maxColumn);
3091}
3092
3093
3094//
3095// TextEditor::Document::getStartOfLine
3096//
3097
3098TextEditor::Coordinate TextEditor::Document::getStartOfLine(Coordinate from) const {
3099 return Coordinate(from.line, 0);
3100}
3101
3102
3103//
3104// TextEditor::Document::getEndOfLine
3105//
3106
3107TextEditor::Coordinate TextEditor::Document::getEndOfLine(Coordinate from) const {
3108 return Coordinate(from.line, at(from.line).maxColumn);
3109}
3110
3111
3112//
3113// TextEditor::Document::findWordStart
3114//
3115
3116TextEditor::Coordinate TextEditor::Document::findWordStart(Coordinate from, bool wordOnly) const {
3117 auto& line = at(from.line);
3118 auto lineSize = line.size();
3119
3120 if (from.column == 0 || lineSize == 0) {
3121 return from;
3122
3123 } else {
3124 auto index = getIndex(from);
3125 auto firstCharacter = line[index - 1].codepoint;
3126
3127 if (!wordOnly && CodePoint::isWhiteSpace(firstCharacter)) {
3128 while (index > 0 && CodePoint::isWhiteSpace(line[index - 1].codepoint)) {
3129 index--;
3130 }
3131
3132 } else if (CodePoint::isWord(firstCharacter)) {
3133 while (index > 0 && CodePoint::isWord(line[index - 1].codepoint)) {
3134 index--;
3135 }
3136
3137 } else {
3138 while (!wordOnly && index > 0 && !CodePoint::isWord(line[index - 1].codepoint) && !CodePoint::isWhiteSpace(line[index - 1].codepoint)) {
3139 index--;
3140 }
3141 }
3142
3143 return Coordinate(from.line, getColumn(line, index));
3144 }
3145}
3146
3147
3148//
3149// TextEditor::Document::findWordEnd
3150//
3151
3152TextEditor::Coordinate TextEditor::Document::findWordEnd(Coordinate from, bool wordOnly) const {
3153 auto& line = at(from.line);
3154 auto index = getIndex(from);
3155 auto size = line.size();
3156
3157 if (index >= size) {
3158 return from;
3159
3160 } else {
3161 auto firstCharacter = line[index].codepoint;
3162
3163 if (!wordOnly && CodePoint::isWhiteSpace(firstCharacter)) {
3164 while (index < size && CodePoint::isWhiteSpace(line[index].codepoint)) {
3165 index++;
3166 }
3167
3168 } else if (CodePoint::isWord(firstCharacter)) {
3169 while (index < size && CodePoint::isWord(line[index].codepoint)) {
3170 index++;
3171 }
3172
3173 } else {
3174 while (!wordOnly && index < size && !CodePoint::isWord(line[index].codepoint) && !CodePoint::isWhiteSpace(line[index].codepoint)) {
3175 index++;
3176 }
3177 }
3178 }
3179
3180 return Coordinate(from.line, getColumn(line, index));
3181}
3182
3183
3184//
3185// TextEditor::Document::findText
3186//
3187
3188bool TextEditor::Document::findText(Coordinate from, const std::string_view& text, bool caseSensitive, bool wholeWord, Coordinate& start, Coordinate& end) const {
3189 // convert input string to vector of codepoints
3190 std::vector<ImWchar> search;
3191 auto endOfText = text.end();
3192 auto i = text.begin();
3193
3194 while (i < endOfText) {
3195 ImWchar character;
3196 i = CodePoint::read(i, endOfText, &character);
3197 search.emplace_back(caseSensitive ? character : CodePoint::toLower(character));
3198 }
3199
3200 // search document
3201 auto startLine = from.line;
3202 auto startIndex = getIndex(from);
3203 auto searchLine = startLine;
3204 auto searchIndex = startIndex;
3205
3206 do {
3207 auto line = searchLine;
3208 auto index = searchIndex;
3209 auto lineSize = at(line).size();
3210 bool done = false;
3211 size_t j = 0;
3212
3213 while (!done && j < search.size()) {
3214 if (search[j] == '\n') {
3215 if (index == lineSize) {
3216 if (line == lineCount() - 1) {
3217 done = true;
3218
3219 } else {
3220 line++;
3221 index = 0;
3222 lineSize = at(line).size();
3223 j++;
3224 }
3225
3226 } else {
3227 done = true;
3228 }
3229
3230 } else {
3231 if (index == lineSize) {
3232 done = true;
3233
3234 } else {
3235 auto ch = at(line)[index].codepoint;
3236
3237 if (!caseSensitive) {
3238 ch = CodePoint::toLower(ch);
3239 }
3240
3241 if (ch == search[j]) {
3242 index++;
3243 j++;
3244
3245 } else {
3246 done = true;
3247 }
3248 }
3249 }
3250 }
3251
3252 if (j == search.size()) {
3253 start = Coordinate(searchLine, getColumn(searchLine, searchIndex));
3254 end = Coordinate(line, getColumn(line, index));
3255
3256 if (!wholeWord || isWholeWord(start, end)) {
3257 return true;
3258 }
3259 }
3260
3261 if (searchIndex == at(searchLine).size()) {
3262 searchLine = (searchLine == lineCount() - 1) ? 0 : searchLine + 1;
3263 searchIndex = 0;
3264
3265 } else {
3266 searchIndex++;
3267 }
3268
3269 } while (searchLine != startLine || searchIndex != startIndex);
3270
3271 return false;
3272}
3273
3274
3275//
3276// TextEditor::Document::setUserData
3277//
3278
3279void TextEditor::Document::setUserData(int line, void* data) {
3280 if (line >= 0 && line < lineCount()) {
3281 at(static_cast<size_t>(line)).userData = data;
3282 }
3283}
3284
3285
3286//
3287// TextEditor::Document::getUserData
3288//
3289
3290void* TextEditor::Document::getUserData(int line) const {
3291 if (line >= 0 && line < lineCount()) {
3292 return at(static_cast<size_t>(line)).userData;
3293
3294 } else {
3295 return nullptr;
3296 }
3297}
3298
3299//
3300// TextEditor::Document::iterateUserData
3301//
3302
3303void TextEditor::Document::iterateUserData(std::function<void(int line, void* data)> callback) const {
3304 for (size_t i = 0; i < size(); i++) {
3305 callback(static_cast<int>(i), at(i).userData);
3306 }
3307}
3308
3309
3310//
3311// TextEditor::Document::iterateIdentifiers
3312//
3313
3314static inline bool isIdentifier(TextEditor::Color color) {
3315 return
3316 color == TextEditor::Color::identifier ||
3317 color == TextEditor::Color::knownIdentifier;
3318}
3319
3320void TextEditor::Document::iterateIdentifiers(std::function<void(const std::string&)> callback) const {
3321 for (size_t i = 0; i < size(); i++) {
3322 auto p = at(i).begin();
3323 auto end = at(i).end();
3324 char utf8[4];
3325
3326 while (p < end) {
3327 if (isIdentifier(p->color)) {
3328 std::string identifier;
3329
3330 while (p < end && isIdentifier(p->color)) {
3331 identifier.append(std::string_view(utf8, CodePoint::write(utf8, p->codepoint)));
3332 p++;
3333 }
3334
3335 callback(identifier);
3336
3337 } else {
3338 p++;
3339 }
3340 }
3341 }
3342}
3343
3344
3345//
3346// TextEditor::Document::isWholeWord
3347//
3348
3349bool TextEditor::Document::isWholeWord(Coordinate start, Coordinate end) const {
3350 if (start.line != end.line || end.column - start.column < 1) {
3351 return false;
3352
3353 } else {
3354 auto wordStart = findWordStart(Coordinate(start.line, start.column + 1));
3355 auto wordEnd = findWordEnd(Coordinate(end.line, end.column - 1));
3356 return start == wordStart && end == wordEnd;
3357 }
3358}
3359
3360
3361//
3362// TextEditor::Document::findPreviousNonWhiteSpace
3363//
3364
3365TextEditor::Coordinate TextEditor::Document::findPreviousNonWhiteSpace(Coordinate from, bool includeEndOfLine) const {
3366 bool done = false;
3367
3368 while (!done) {
3369 auto& line = at(from.line);
3370 auto index = getIndex(from);
3371
3372 while (!done && index > 0) {
3373 index--;
3374
3375 if (!CodePoint::isWhiteSpace(line[index].codepoint)) {
3376 from.column = getColumn(line, index);
3377 done = true;
3378 }
3379 }
3380
3381 if (!done) {
3382 if (from.line == 0 || !includeEndOfLine) {
3383 from.column = 0;
3384 done = true;
3385
3386 } else {
3387 from.line--;
3388 from.column = at(from.line).maxColumn;
3389 }
3390 }
3391 }
3392
3393 return from;
3394}
3395
3396
3397//
3398// TextEditor::Document::findNextNonWhiteSpace
3399//
3400
3401TextEditor::Coordinate TextEditor::Document::findNextNonWhiteSpace(Coordinate from, bool includeEndOfLine) const {
3402 bool done = false;
3403
3404 while (!done) {
3405 auto& line = at(from.line);
3406 auto index = getIndex(from);
3407
3408 while (!done && index < line.size()) {
3409 if (CodePoint::isWhiteSpace(line[index].codepoint)) {
3410 index++;
3411
3412 } else {
3413 from.column = getColumn(line, index);
3414 done = true;
3415 }
3416 }
3417
3418 if (!done) {
3419 if (from.line == lineCount() || !includeEndOfLine) {
3420 from.column = line.maxColumn;
3421 done = true;
3422
3423 } else {
3424 from.line++;
3425 from.column = 0;
3426 }
3427 }
3428 }
3429
3430 return from;
3431}
3432
3433
3434//
3435// TextEditor::Document::normalizeCoordinate
3436//
3437
3438TextEditor::Coordinate TextEditor::Document::normalizeCoordinate(Coordinate coordinate) const {
3439 if (coordinate.line < 0) {
3440 return Coordinate(0, 0);
3441
3442 } else if (coordinate.line >= lineCount()) {
3443 return Coordinate(lineCount() - 1, at(size() - 1).maxColumn);
3444
3445 } else if (coordinate.column < 0) {
3446 return Coordinate(coordinate.line, 0);
3447
3448 } else if (coordinate.column > at(coordinate.line).maxColumn) {
3449 return Coordinate(coordinate.line, at(coordinate.line).maxColumn);
3450
3451 } else {
3452 // determine column numbers left and right of provided coordinate
3453 auto& line = at(coordinate.line);
3454 auto end = line.end();
3455 auto leftCol = 0;
3456 auto rightCol = 0;
3457
3458 for (auto glyph = line.begin(); rightCol < coordinate.column && glyph < end; glyph++) {
3459 leftCol = rightCol;
3460 rightCol = (glyph->codepoint == '\t') ? ((rightCol / tabSize) + 1) * tabSize : rightCol + 1;
3461 }
3462
3463 auto leftDiff = coordinate.column - leftCol;
3464 auto rightDiff = rightCol - coordinate.column;
3465 return Coordinate(coordinate.line, leftDiff <= rightDiff ? leftCol : rightCol);
3466 }
3467}
3468
3469
3470//
3471// TextEditor::Document::normalizeCoordinate
3472//
3473
3474void TextEditor::Document::normalizeCoordinate(float line, float column, Coordinate& glyphCoordinate, Coordinate& cursorCoordinate) const {
3475 // normalize coordinates by clamping them to the document and line range
3476 // the returned glyphCoordinate addresses the glyph pointed to by the line and column parameters
3477 // the returned cursorCoordinate returns the closest cursor position (which can be at the start or the end of the glyph)
3478 if (line < 0.0f) {
3479 glyphCoordinate = Coordinate(0, 0);
3480 cursorCoordinate = glyphCoordinate;
3481
3482 } else if (line >= static_cast<float>(lineCount())) {
3483 glyphCoordinate = Coordinate(lineCount() - 1, at(lineCount() - 1).maxColumn);
3484 cursorCoordinate = glyphCoordinate;
3485
3486 } else {
3487 auto lineNo = static_cast<int>(line);
3488
3489 if (column < 0.0f) {
3490 glyphCoordinate = Coordinate(lineNo, 0);
3491 cursorCoordinate = glyphCoordinate;
3492
3493 } else if (column >= static_cast<float>(at(lineNo).maxColumn)) {
3494 glyphCoordinate = Coordinate(lineNo, at(lineNo).maxColumn);
3495 cursorCoordinate = glyphCoordinate;
3496
3497 } else {
3498 // determine column numbers left and right of provided coordinate
3499 auto leftCol = 0;
3500 auto rightCol = 0;
3501 auto end = at(lineNo).end();
3502
3503 for (auto glyph = at(lineNo).begin(); rightCol < column && glyph < end; glyph++) {
3504 leftCol = rightCol;
3505 rightCol = (glyph->codepoint == '\t') ? ((rightCol / tabSize) + 1) * tabSize : rightCol + 1;
3506 }
3507
3508 auto leftDiff = column - static_cast<float>(leftCol);
3509 auto rightDiff = static_cast<float>(rightCol) - column;
3510
3511 glyphCoordinate = Coordinate(lineNo, leftCol);
3512 cursorCoordinate = Coordinate(lineNo, leftDiff <= rightDiff ? leftCol : rightCol);
3513 }
3514 }
3515}
3516
3517
3518//
3519// TextEditor::Document::appendLine
3520//
3521
3522void TextEditor::Document::appendLine() {
3523 auto& line = emplace_back();
3524
3525 if (insertor) {
3526 line.userData = insertor(static_cast<int>(size() - 1));
3527 }
3528}
3529
3530
3531//
3532// TextEditor::Document::insertLine
3533//
3534
3535void TextEditor::Document::insertLine(int offsset) {
3536 auto line = insert(begin() + offsset, Line());
3537
3538 if (insertor) {
3539 line->userData = insertor(offsset);
3540 }
3541}
3542
3543
3544//
3545// TextEditor::Document::deleteLines
3546//
3547
3548void TextEditor::Document::deleteLines(int start, int end) {
3549 if (deletor) {
3550 for (auto i = start; i <= end; i++) {
3551 deletor(i, at(i).userData);
3552 }
3553 }
3554
3555 erase(begin() + start, begin() + end + 1);
3556}
3557
3558
3559//
3560// TextEditor::Document::clearDocument
3561//
3562
3563void TextEditor::Document::clearDocument() {
3564 if (deletor) {
3565 for (auto i = 0; i <= lineCount(); i++) {
3566 deletor(i, at(i).userData);
3567 }
3568 }
3569
3570 clear();
3571}
3572
3573
3574//
3575// TextEditor::Transactions::reset
3576//
3577
3578void TextEditor::Transactions::reset() {
3579 clear();
3580 undoIndex = 0;
3581 version = 0;
3582}
3583
3584
3585//
3586// TextEditor::Transactions::add
3587//
3588
3589void TextEditor::Transactions::add(std::shared_ptr<Transaction> transaction) {
3590 resize(undoIndex);
3591 push_back(transaction);
3592 undoIndex++;
3593 version++;
3594}
3595
3596
3597//
3598// TextEditor::Transactions::undo
3599//
3600
3601void TextEditor::Transactions::undo(Document& document, Cursors& cursors) {
3602 auto transaction = at(--undoIndex);
3603
3604 for (auto action = transaction->rbegin(); action < transaction->rend(); action++) {
3605 if (action->type == Action::Type::insertText) {
3606 document.deleteText(action->start, action->end);
3607
3608 } else {
3609 document.insertText(action->start, action->text);
3610 }
3611 }
3612
3613 cursors = transaction->getBeforeState();
3614 version++;
3615}
3616
3617
3618//
3619// TextEditor::Transactions::redo
3620//
3621
3622void TextEditor::Transactions::redo(Document& document, Cursors& cursors) {
3623 auto transaction = at(undoIndex++);
3624
3625 for (auto action = transaction->begin(); action < transaction->end(); action++) {
3626 if (action->type == Action::Type::insertText) {
3627 document.insertText(action->start, action->text);
3628
3629 } else {
3630 document.deleteText(action->start, action->end);
3631 }
3632 }
3633
3634 cursors = transaction->getAfterState();
3635 version++;
3636}
3637
3638
3639//
3640// TextEditor::Colorizer::update
3641//
3642
3643TextEditor::State TextEditor::Colorizer::update(Line& line, const Language* language) {
3644 auto state = line.state;
3645
3646 // process all glyphs on this line
3647 auto nonWhiteSpace = false;
3648 auto glyph = line.begin();
3649
3650 while (glyph < line.end()) {
3651 if (state == State::inText) {
3652 // special handling for preprocessor lines
3653 if (!nonWhiteSpace && language->preprocess && glyph->codepoint != language->preprocess && !CodePoint::isWhiteSpace(glyph->codepoint)) {
3654 nonWhiteSpace = true;
3655 }
3656
3657 // start parsing glyphs
3658 auto start = glyph;
3659
3660 // mark whitespace characters
3661 if (CodePoint::isWhiteSpace(glyph->codepoint)) {
3662 (glyph++)->color = Color::whitespace;
3663
3664 // handle single line comments
3665 } else if (language->singleLineComment.size() && matches(glyph, line.end(), language->singleLineComment)) {
3666 setColor(glyph, line.end(), Color::comment);
3667 glyph = line.end();
3668
3669 } else if (language->singleLineCommentAlt.size() && matches(glyph, line.end(), language->singleLineCommentAlt)) {
3670 setColor(glyph, line.end(), Color::comment);
3671 glyph = line.end();
3672
3673 // are we starting a multiline comment
3674 } else if (language->commentStart.size() && matches(glyph, line.end(), language->commentStart)) {
3675 state = State::inComment;
3676 auto size = language->commentEnd.size();
3677 setColor(glyph, glyph + size, Color::comment);
3678 glyph += size;
3679
3680 // are we starting a special string
3681 } else if (language->otherStringStart.size() && matches(glyph, line.end(), language->otherStringStart)) {
3682 state = State::inOtherString;
3683 auto size = language->otherStringStart.size();
3684 setColor(glyph, glyph + size, Color::string);
3685 glyph += size;
3686
3687 } else if (language->otherStringAltStart.size() && matches(glyph, line.end(), language->otherStringAltStart)) {
3688 state = State::inOtherStringAlt;
3689 auto size = language->otherStringAltStart.size();
3690 setColor(glyph, glyph + size, Color::string);
3691 glyph += size;
3692
3693 // are we starting a single quoted string
3694 } else if (language->hasSingleQuotedStrings && glyph->codepoint == CodePoint::singleQuote) {
3695 state = State::inSingleQuotedString;
3696 (glyph++)->color = Color::string;
3697
3698 // are we starting a double quoted string
3699 } else if (language->hasDoubleQuotedStrings && glyph->codepoint == CodePoint::doubleQuote) {
3700 state = State::inDoubleQuotedString;
3701 (glyph++)->color = Color::string;
3702
3703 // is this a preprocessor line
3704 } else if (language->preprocess && !nonWhiteSpace && glyph->codepoint == language->preprocess) {
3705 setColor(line.begin(), line.end(), Color::preprocessor);
3706 glyph = line.end();
3707
3708 // handle custom tokenizer (if we have one)
3709 } else if (language->customTokenizer) {
3710 Color color;
3711 Iterator tokenStart(&*glyph);
3712 Iterator lineEnd(line.data() + line.size());
3713 Iterator tokenEnd = language->customTokenizer(tokenStart, lineEnd, color);
3714
3715 if (tokenEnd != tokenStart) {
3716 auto size = tokenEnd - tokenStart;
3717 setColor(glyph, glyph + size, color);
3718 glyph += size;
3719 }
3720 }
3721
3722 if (glyph == start) {
3723 // nothing worked so far so it's time to do some tokenizing
3724 Color color;
3725 Iterator lineEnd(line.data() + line.size());
3726 Iterator tokenStart(&*glyph);
3727 Iterator tokenEnd;
3728
3729 // do we have an identifier
3730 if (language->getIdentifier && (tokenEnd = language->getIdentifier(tokenStart, lineEnd)) != tokenStart) {
3731 // determine identifier text and color color
3732 auto size = tokenEnd - tokenStart;
3733 std::string identifier;
3734 color = Color::identifier;
3735
3736 for (auto i = tokenStart; i < tokenEnd; i++) {
3737 ImWchar codepoint = *i;
3738
3739 if (!language->caseSensitive) {
3740 codepoint = CodePoint::toLower(codepoint);
3741 }
3742
3743 char utf8[4];
3744 identifier.append(utf8, CodePoint::write(utf8, codepoint));
3745 }
3746
3747 if (language->keywords.find(identifier) != language->keywords.end()) {
3748 color = Color::keyword;
3749
3750 } else if (language->declarations.find(identifier) != language->declarations.end()) {
3751 color = Color::declaration;
3752
3753 } else if (language->identifiers.find(identifier) != language->identifiers.end()) {
3754 color = Color::knownIdentifier;
3755 }
3756
3757 // colorize identifier and move on
3758 setColor(glyph, glyph + size, color);
3759 glyph += size;
3760
3761 // do we have a number
3762 } else if (language->getNumber && (tokenEnd = language->getNumber(tokenStart, lineEnd)) != tokenStart) {
3763 auto size = tokenEnd - tokenStart;
3764 setColor(glyph, glyph + size, Color::number);
3765 glyph += size;
3766
3767 // is this punctuation
3768 } else if (language->isPunctuation && language->isPunctuation(glyph->codepoint)) {
3769 (glyph++)->color = Color::punctuation;
3770
3771 } else {
3772 // I guess we don't know what this character is
3773 (glyph++)->color = Color::text;
3774 }
3775 }
3776
3777 } else if (state == State::inComment) {
3778 // stay in comment state until we see the end sequence
3779 if (matches(glyph, line.end(), language->commentEnd)) {
3780 auto size = language->commentEnd.size();
3781 setColor(glyph, glyph + size, Color::comment);
3782 glyph += size;
3783 state = State::inText;
3784
3785 } else {
3786 (glyph++)->color = Color::comment;
3787 }
3788
3789 } else if (state == State::inOtherString) {
3790 // stay in otherString state until we see the end sequence
3791 // skip escaped characters
3792 if (glyph->codepoint == language->stringEscape) {
3793 (glyph++)->color = Color::string;
3794
3795 if (glyph < line.end()) {
3796 (glyph++)->color = Color::string;
3797 }
3798
3799 } else if (matches(glyph, line.end(), language->otherStringEnd)) {
3800 auto size = language->otherStringEnd.size();
3801 setColor(glyph, glyph + size, Color::string);
3802 glyph += size;
3803 state = State::inText;
3804
3805 } else {
3806 (glyph++)->color = Color::comment;
3807 }
3808
3809 } else if (state == State::inOtherStringAlt) {
3810 // stay in otherStringAlt state until we see the end sequence
3811 // skip escaped characters
3812 if (glyph->codepoint == language->stringEscape) {
3813 (glyph++)->color = Color::string;
3814
3815 if (glyph < line.end()) {
3816 (glyph++)->color = Color::string;
3817 }
3818
3819 } else if (matches(glyph, line.end(), language->otherStringAltEnd)) {
3820 auto size = language->otherStringAltEnd.size();
3821 setColor(glyph, glyph + size, Color::string);
3822 glyph += size;
3823 state = State::inText;
3824
3825 } else {
3826 (glyph++)->color = Color::comment;
3827 }
3828
3829 } else if (state == State::inSingleQuotedString) {
3830 // stay in single quote state until we see an end
3831 // skip escaped characters
3832 if (glyph->codepoint == language->stringEscape) {
3833 (glyph++)->color = Color::string;
3834
3835 if (glyph < line.end()) {
3836 (glyph++)->color = Color::string;
3837 }
3838
3839 } else if (glyph->codepoint == CodePoint::singleQuote) {
3840 (glyph++)->color = Color::string;
3841 state = State::inText;
3842
3843 } else {
3844 (glyph++)->color = Color::string;
3845 }
3846
3847 } else if (state == State::inDoubleQuotedString) {
3848 // stay in double quote state until we see an end
3849 // skip escaped characters
3850 if (glyph->codepoint == language->stringEscape) {
3851 (glyph++)->color = Color::string;
3852
3853 if (glyph < line.end()) {
3854 (glyph++)->color = Color::string;
3855 }
3856
3857 } else if (glyph->codepoint == CodePoint::doubleQuote) {
3858 (glyph++)->color = Color::string;
3859 state = State::inText;
3860
3861 } else {
3862 (glyph++)->color = Color::string;
3863 }
3864 }
3865 }
3866
3867 line.colorize = false;
3868 return state;
3869}
3870
3871
3872//
3873// TextEditor::Colorizer::updateEntireDocument
3874//
3875
3876void TextEditor::Colorizer::updateEntireDocument(Document& document, const Language* language) {
3877 if (language) {
3878 for (auto line = document.begin(); line < document.end(); line++) {
3879 auto state = update(*line, language);
3880 auto next = line + 1;
3881
3882 if (next < document.end()) {
3883 next->state = state;
3884 }
3885 }
3886
3887 } else {
3888 for (auto line = document.begin(); line < document.end(); line++) {
3889 for (auto glyph = line->begin(); glyph < line->end(); glyph++) {
3890 glyph->color = Color::text;
3891 }
3892
3893 line->state = State::inText;
3894 line->colorize = false;
3895 }
3896 }
3897}
3898
3899
3900//
3901// TextEditor::Colorizer::updateChangedLines
3902//
3903
3904void TextEditor::Colorizer::updateChangedLines(Document& document, const Language* language) {
3905 for (auto line = document.begin(); line < document.end(); line++) {
3906 if (line->colorize) {
3907 auto state = update(*line, language);
3908 auto next = line + 1;
3909
3910 if (next < document.end() && next->state != state) {
3911 next->state = state;
3912 next->colorize = true;
3913 }
3914 }
3915 }
3916}
3917
3918
3919//
3920// TextEditor::Colorizer::matches
3921//
3922
3923bool TextEditor::Colorizer::matches(Line::iterator start, Line::iterator end, const std::string_view& text) {
3924 // see if text at iterators matches provided UTF-8 string
3925 auto i = text.begin();
3926
3927 while (i < text.end()) {
3928 if (start == end) {
3929 return false;
3930 }
3931
3932 ImWchar codepoint;
3933 i = CodePoint::read(i, text.end(), &codepoint);
3934
3935 if ((start++)->codepoint != codepoint) {
3936 return false;
3937 }
3938 }
3939
3940 return true;
3941}
3942
3943
3944//
3945// TextEditor::Bracketeer::reset
3946//
3947
3948void TextEditor::Bracketeer::reset() {
3949 clear();
3950}
3951
3952
3953//
3954// TextEditor::Bracketeer::update
3955//
3956
3957void TextEditor::Bracketeer::update(Document& document) {
3958 Color bracketColors[] = {
3959 Color::matchingBracketLevel1,
3960 Color::matchingBracketLevel2,
3961 Color::matchingBracketLevel3
3962 };
3963
3964 reset();
3965 std::vector<size_t> levels;
3966 int level = 0;
3967
3968 // process all the glyphs
3969 for (int line = 0; line < document.lineCount(); line++) {
3970 for (size_t index = 0; index < document[line].size(); index++) {
3971 auto& glyph = document[line][index];
3972
3973 // handle a "bracket opener" that is not in a comment, string or preprocessor statement
3974 if (isBracketCandidate(glyph) && CodePoint::isBracketOpener(glyph.codepoint)) {
3975 // start a new level
3976 levels.emplace_back(size());
3977 emplace_back(glyph.codepoint, Coordinate(line, document.getColumn(line, index)), static_cast<ImWchar>(0), Coordinate::invalid(), level);
3978 glyph.color = bracketColors[level % 3];
3979 level++;
3980
3981 // handle a "bracket closer" that is not in a comment, string or preprocessor statement
3982 } else if (isBracketCandidate(glyph) && CodePoint::isBracketCloser(glyph.codepoint)) {
3983 if (levels.size()) {
3984 auto& lastBracket = at(levels.back());
3985 levels.pop_back();
3986 level--;
3987
3988 if (lastBracket.startChar == CodePoint::toPairOpener(glyph.codepoint)) {
3989 // handle matching bracket
3990 glyph.color = bracketColors[level % 3];
3991 lastBracket.endChar = glyph.codepoint;
3992 lastBracket.end = Coordinate(line, document.getColumn(line, index));
3993
3994 } else {
3995 // no matching bracket, mark brackets as errors
3996 glyph.color = Color::matchingBracketError;
3997 document[lastBracket.start.line][document.getIndex(lastBracket.start)].color = Color::matchingBracketError;
3998 pop_back();
3999 }
4000
4001 // this is a closer without an opener
4002 } else {
4003 glyph.color = Color::matchingBracketError;
4004 }
4005 }
4006 }
4007 }
4008
4009 // handle levels left open and mark them as errors
4010 if (levels.size()) {
4011 for (auto i = levels.rbegin(); i < levels.rend(); i++) {
4012 auto& start = at(*i).start;
4013 document[start.line][document.getIndex(start)].color = Color::matchingBracketError;
4014 erase(begin() + *i);
4015 }
4016 }
4017}
4018
4019
4020//
4021// TextEditor::Bracketeer::getEnclosingBrackets
4022//
4023
4024TextEditor::Bracketeer::iterator TextEditor::Bracketeer::getEnclosingBrackets(Coordinate location) {
4025 iterator brackets = end();
4026 bool done = false;
4027
4028 for (auto i = begin(); !done && i < end(); i++) {
4029 // brackets are sorted so no need to go past specified location
4030 if (i->isAfter(location)) {
4031 done = true;
4032 }
4033
4034 else if (i->isAround(location)) {
4035 // this could be what we're looking for
4036 brackets = i;
4037 }
4038 }
4039
4040 return brackets;
4041}
4042
4043
4044//
4045// TextEditor::Bracketeer::getEnclosingCurlyBrackets
4046//
4047
4048TextEditor::Bracketeer::iterator TextEditor::Bracketeer::getEnclosingCurlyBrackets(Coordinate first, Coordinate last) {
4049 iterator brackets = end();
4050 bool done = false;
4051
4052 for (auto i = begin(); !done && i < end(); i++) {
4053 // brackets are sorted so no need to go past specified location
4054 if (i->isAfter(first)) {
4055 done = true;
4056 }
4057
4058 else if (i->isAround(first) && i->isAround(last) && i->startChar == CodePoint::openCurlyBracket) {
4059 // this could be what we're looking for
4060 brackets = i;
4061 }
4062 }
4063
4064 return brackets;
4065}
4066
4067
4068//
4069// TextEditor::Bracketeer::getInnerCurlyBrackets
4070//
4071
4072TextEditor::Bracketeer::iterator TextEditor::Bracketeer::getInnerCurlyBrackets(Coordinate first, Coordinate last) {
4073 iterator brackets = end();
4074 auto outer = getEnclosingCurlyBrackets(first, last);
4075
4076 if (outer != end()) {
4077 bool done = false;
4078
4079 for (auto i = outer + 1; i < end() && !done; i++) {
4080 if (i->level <= outer->level) {
4081 done = true;
4082
4083 } else if (
4084 i->level == outer->level + 1 &&
4085 i->startChar == CodePoint::openCurlyBracket &&
4086 i->start > first &&
4087 i->end < last) {
4088
4089 brackets = i;
4090 done = true;
4091 }
4092 }
4093 }
4094
4095 return brackets;
4096}
4097
4098
4099//
4100// latchButton
4101//
4102
4103static bool latchButton(const char* label, bool* value, const ImVec2& size) {
4104 auto changed = false;
4105 ImVec4* colors = ImGui::GetStyle().Colors;
4106
4107 if (*value) {
4108 ImGui::PushStyleColor(ImGuiCol_Button, colors[ImGuiCol_ButtonActive]);
4109 ImGui::PushStyleColor(ImGuiCol_ButtonHovered, colors[ImGuiCol_ButtonActive]);
4110 ImGui::PushStyleColor(ImGuiCol_ButtonActive, colors[ImGuiCol_TableBorderLight]);
4111
4112 } else {
4113 ImGui::PushStyleColor(ImGuiCol_Button, colors[ImGuiCol_TableBorderLight]);
4114 ImGui::PushStyleColor(ImGuiCol_ButtonHovered, colors[ImGuiCol_TableBorderLight]);
4115 ImGui::PushStyleColor(ImGuiCol_ButtonActive, colors[ImGuiCol_ButtonActive]);
4116 }
4117
4118 ImGui::Button(label, size);
4119
4120 if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) {
4121 *value = !*value;
4122 changed = true;
4123 }
4124
4125 ImGui::PopStyleColor(3);
4126 return changed;
4127}
4128
4129
4130//
4131// inputString
4132//
4133
4134static bool inputString(const char* label, std::string* value, ImGuiInputTextFlags flags=ImGuiInputTextFlags_None) {
4135 flags |=
4136 ImGuiInputTextFlags_NoUndoRedo |
4137 ImGuiInputTextFlags_CallbackResize;
4138
4139 return ImGui::InputText(label, (char*) value->c_str(), value->capacity() + 1, flags, [](ImGuiInputTextCallbackData* data) {
4140 if (data->EventFlag == ImGuiInputTextFlags_CallbackResize) {
4141 std::string* value = (std::string*) data->UserData;
4142 value->resize(data->BufTextLen);
4143 data->Buf = (char*) value->c_str();
4144 }
4145
4146 return 0;
4147 }, value);
4148}
4149
4150
4151//
4152// TextEditor::renderFindReplace
4153//
4154
4155void TextEditor::renderFindReplace(ImVec2 pos, float width) {
4156 // render find/replace window (if required)
4157 if (findReplaceVisible) {
4158 // save current screen position
4159 auto currentScreenPosition = ImGui::GetCursorScreenPos();
4160
4161 // calculate sizes
4162 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(6.0f, 4.0f));
4163 auto& style = ImGui::GetStyle();
4164 auto fieldWidth = 250.0f;
4165
4166 auto button1Width = ImGui::CalcTextSize(findButtonLabel.c_str()).x + style.ItemSpacing.x * 2.0f;
4167 auto button2Width = ImGui::CalcTextSize(findAllButtonLabel.c_str()).x + style.ItemSpacing.x * 2.0f;
4168 auto optionWidth = ImGui::CalcTextSize("Aa").x + style.ItemSpacing.x * 2.0f;
4169
4170 if (!readOnly) {
4171 button1Width = std::max(button1Width, ImGui::CalcTextSize(replaceButtonLabel.c_str()).x + style.ItemSpacing.x * 2.0f);
4172 button2Width = std::max(button2Width, ImGui::CalcTextSize(replaceAllButtonLabel.c_str()).x + style.ItemSpacing.x * 2.0f);
4173 }
4174
4175 auto windowHeight =
4176 style.ChildBorderSize * 2.0f +
4177 style.WindowPadding.y * 2.0f +
4178 ImGui::GetFrameHeight() +
4179 (readOnly ? 0.0f : (style.ItemSpacing.y + ImGui::GetFrameHeight()));
4180
4181 auto windowWidth =
4182 style.ChildBorderSize * 2.0f +
4183 style.WindowPadding.x * 2.0f +
4184 fieldWidth + style.ItemSpacing.x +
4185 button1Width + style.ItemSpacing.x +
4186 button2Width + style.ItemSpacing.x +
4187 optionWidth * 3.0f + style.ItemSpacing.x * 2.0f;
4188
4189 // create window
4190 ImGui::SetNextWindowPos(ImVec2(
4191 pos.x + width - windowWidth - style.ItemSpacing.x,
4192 pos.y + style.ItemSpacing.y * 2.0f));
4193
4194 ImGui::SetNextWindowSize(ImVec2(windowWidth, windowHeight));
4195 ImGui::SetNextWindowBgAlpha(0.75f);
4196
4197 ImGui::BeginChild("find-replace", ImVec2(windowWidth, windowHeight), ImGuiChildFlags_Borders);
4198 ImGui::SetNextItemWidth(fieldWidth);
4199
4200 if (focusOnFind) {
4201 ImGui::SetKeyboardFocusHere();
4202 focusOnFind = false;
4203
4204 } else if (findCancelledAutocomplete) {
4205 ImGui::SetKeyboardFocusHere();
4206 findCancelledAutocomplete = false;
4207 }
4208
4209 if (inputString("###find", &findText, ImGuiInputTextFlags_AutoSelectAll)) {
4210 if (findText.size()) {
4211 selectFirstOccurrenceOf(findText, caseSensitiveFind, wholeWordFind);
4212
4213 } else {
4214 cursors.clearAll();
4215 }
4216 }
4217
4218 if (ImGui::IsItemDeactivated()) {
4219 if (ImGui::IsKeyPressed(ImGuiKey_Escape)) {
4220 closeFindReplace();
4221
4222 } else if (ImGui::IsKeyPressed(ImGuiKey_Enter) || ImGui::IsKeyPressed(ImGuiKey_KeypadEnter)) {
4223 focusOnEditor = true;
4224 focusOnFind = false;
4225 }
4226 }
4227
4228 bool disableFindButtons = !findText.size();
4229
4230 if (disableFindButtons) {
4231 ImGui::BeginDisabled();
4232 }
4233
4234 ImGui::SameLine();
4235
4236 if (ImGui::Button(findButtonLabel.c_str(), ImVec2(button1Width, 0.0f))) {
4237 find();
4238 }
4239
4240 ImGui::SameLine();
4241
4242 if (ImGui::Button(findAllButtonLabel.c_str(), ImVec2(button2Width, 0.0f))) {
4243 findAll();
4244 }
4245
4246 if (disableFindButtons) {
4247 ImGui::EndDisabled();
4248 }
4249
4250 ImGui::SameLine();
4251
4252 if (latchButton("Aa", &caseSensitiveFind, ImVec2(optionWidth, 0.0f))) {
4253 find();
4254 }
4255
4256 ImGui::SameLine();
4257
4258 if (latchButton("[]", &wholeWordFind, ImVec2(optionWidth, 0.0f))) {
4259 find();
4260 }
4261
4262 ImGui::SameLine();
4263
4264 if (ImGui::Button("x", ImVec2(optionWidth, 0.0f))) {
4265 closeFindReplace();
4266 }
4267
4268 if (!readOnly) {
4269 ImGui::SetNextItemWidth(fieldWidth);
4270 inputString("###replace", &replaceText);
4271 ImGui::SameLine();
4272
4273 bool disableReplaceButtons = !findText.size() || !replaceText.size();
4274
4275 if (disableReplaceButtons) {
4276 ImGui::BeginDisabled();
4277 }
4278
4279 if (ImGui::Button(replaceButtonLabel.c_str(), ImVec2(button1Width, 0.0f))) {
4280 replace();
4281 }
4282
4283 ImGui::SameLine();
4284
4285 if (ImGui::Button(replaceAllButtonLabel.c_str(), ImVec2(button2Width, 0.0f))) {
4286 replaceAll();
4287 }
4288
4289 if (disableReplaceButtons) {
4290 ImGui::EndDisabled();
4291 }
4292 }
4293
4294 ImGui::EndChild();
4295 ImGui::PopStyleVar();
4296 ImGui::SetCursorScreenPos(currentScreenPosition);
4297 }
4298}
4299
4300
4301//
4302// TextEditor::selectFirstOccurrenceOf
4303//
4304
4305void TextEditor::selectFirstOccurrenceOf(const std::string_view& text, bool caseSensitive, bool wholeWord) {
4306 Coordinate start, end;
4307
4308 if (document.findText(Coordinate(0, 0), text, caseSensitive, wholeWord, start, end)) {
4309 cursors.setCursor(start, end);
4310 makeCursorVisible();
4311
4312 } else {
4313 cursors.clearAdditional(true);
4314 }
4315}
4316
4317
4318//
4319// TextEditor::selectNextOccurrenceOf
4320//
4321
4322void TextEditor::selectNextOccurrenceOf(const std::string_view& text, bool caseSensitive, bool wholeWord) {
4323 Coordinate start, end;
4324
4325 if (document.findText(cursors.getCurrent().getSelectionEnd(), text, caseSensitive, wholeWord, start, end)) {
4326 cursors.setCursor(start, end);
4327 makeCursorVisible();
4328
4329 } else {
4330 cursors.clearAdditional(true);
4331 }
4332}
4333
4334
4335//
4336// TextEditor::selectAllOccurrencesOf
4337//
4338
4339void TextEditor::selectAllOccurrencesOf(const std::string_view& text, bool caseSensitive, bool wholeWord) {
4340 Coordinate start, end;
4341
4342 if (document.findText(Coordinate(0, 0), text, caseSensitive, wholeWord, start, end)) {
4343 cursors.setCursor(start, end);
4344 bool done = false;
4345
4346 while (!done) {
4347 Coordinate nextStart, nextEnd;
4348 document.findText(cursors.getCurrent().getSelectionEnd(), text, caseSensitive, wholeWord, nextStart, nextEnd);
4349
4350 if (nextStart == start && nextEnd == end) {
4351 done = true;
4352
4353 } else {
4354 cursors.addCursor(nextStart, nextEnd);
4355 }
4356 }
4357
4358 makeCursorVisible();
4359
4360 } else {
4361 cursors.clearAdditional(true);
4362 }
4363}
4364
4365
4366//
4367// TextEditor::addNextOccurrence
4368//
4369
4370void TextEditor::addNextOccurrence() {
4371
4372 auto cursor = cursors.getCurrent();
4373 auto text = document.getSectionText(cursor.getSelectionStart(), cursor.getSelectionEnd());
4374 Coordinate start, end;
4375
4376 if (document.findText(cursor.getSelectionEnd(), text, true, false, start, end)) {
4377 cursors.addCursor(start, end);
4378 }
4379}
4380
4381
4382//
4383// TextEditor::addNextOccurrences
4384//
4385
4386void TextEditor::selectAllOccurrences() {
4387 auto cursor = cursors.getCurrent();
4388 auto text = document.getSectionText(cursor.getSelectionStart(), cursor.getSelectionEnd());
4389 selectAllOccurrencesOf(text, true, false);
4390}
4391
4392
4393//
4394// TextEditor::replaceTextInCurrentCursor
4395//
4396
4397void TextEditor::replaceTextInCurrentCursor(const std::string_view& text) {
4398 auto transaction = startTransaction();
4399
4400 // first delete old text
4401 auto cursor = cursors.getCurrentAsIterator();
4402 auto start = cursor->getSelectionStart();
4403 auto end = cursor->getSelectionEnd();
4404 deleteText(transaction, start, end);
4405 cursors.adjustForDelete(cursor, start, end);
4406
4407 // now insert new text
4408 Coordinate newEnd = insertText(transaction, start, text);
4409 cursor->update(newEnd, false);
4410 cursors.adjustForInsert(cursor, start, newEnd);
4411
4412 endTransaction(transaction);
4413}
4414
4415
4416//
4417// TextEditor::replaceTextInAllCursors
4418//
4419
4420void TextEditor::replaceTextInAllCursors(const std::string_view& text) {
4421 auto transaction = startTransaction();
4422 insertTextIntoAllCursors(transaction, text);
4423 endTransaction(transaction);
4424}
4425
4426
4427//
4428// TextEditor::replaceSectionText
4429//
4430
4431void TextEditor::replaceSectionText(const Coordinate& start, const Coordinate& end, const std::string_view& text) {
4432 auto transaction = startTransaction();
4433 deleteText(transaction, start, end);
4434 auto newEnd = insertText(transaction, start, text);
4435 cursors.clearAdditional();
4436 cursors.getMain().update(newEnd, newEnd);
4437 endTransaction(transaction);
4438}
4439
4440
4441//
4442// TextEditor::openFindReplace
4443//
4444
4445void TextEditor::openFindReplace() {
4446 // get main cursor location
4447 auto cursor = cursors.getMain();
4448
4449 // see if we have a current selection that's on one line
4450 if (cursor.hasSelection()) {
4451 if (cursor.getSelectionStart().line == cursor.getSelectionEnd().line) {
4452 // use it as the default search
4453 findText = document.getSectionText(cursor.getSelectionStart(), cursor.getSelectionEnd());
4454 }
4455
4456 } else {
4457 // if cursor is inside "real" word, use that as the default
4458 auto start = document.findWordStart(cursor.getSelectionStart(), true);
4459 auto end = document.findWordEnd(cursor.getSelectionStart(), true);
4460
4461 if (start != end) {
4462 findText = document.getSectionText(start, end);
4463 }
4464 }
4465
4466 findReplaceVisible = true;
4467 focusOnFind = true;
4468}
4469
4470
4471//
4472// TextEditor::closeFindReplace
4473//
4474
4475void TextEditor::closeFindReplace() {
4476 findReplaceVisible = false;
4477 focusOnEditor = true;
4478 focusOnFind = false;
4479}
4480
4481
4482//
4483// TextEditor::find
4484//
4485
4486void TextEditor::find() {
4487 if (findText.size()) {
4488 selectNextOccurrenceOf(findText, caseSensitiveFind, wholeWordFind);
4489 focusOnEditor = true;
4490 focusOnFind = false;
4491 }
4492}
4493
4494
4495//
4496// TextEditor::findNext
4497//
4498
4499void TextEditor::findNext() {
4500 if (findText.size()) {
4501 selectNextOccurrenceOf(findText, caseSensitiveFind, wholeWordFind);
4502 focusOnEditor = true;
4503 focusOnFind = false;
4504 }
4505}
4506
4507
4508//
4509// TextEditor::findAll
4510//
4511
4512void TextEditor::findAll() {
4513 if (findText.size()) {
4514 selectAllOccurrencesOf(findText, caseSensitiveFind, wholeWordFind);
4515 focusOnEditor = true;
4516 focusOnFind = false;
4517 }
4518}
4519
4520
4521//
4522// TextEditor::replace
4523//
4524
4525void TextEditor::replace() {
4526 if (findText.size()) {
4527 if (!cursors.anyHasSelection()) {
4528 selectNextOccurrenceOf(findText, caseSensitiveFind, wholeWordFind);
4529 }
4530
4531 replaceTextInCurrentCursor(replaceText);
4532 selectNextOccurrenceOf(findText, caseSensitiveFind, wholeWordFind);
4533 focusOnEditor = true;
4534 focusOnFind = false;
4535 }
4536}
4537
4538
4539//
4540// TextEditor::replaceAll
4541//
4542
4543void TextEditor::replaceAll() {
4544 if (findText.size()) {
4545 selectAllOccurrencesOf(findText, caseSensitiveFind, wholeWordFind);
4546 replaceTextInAllCursors(replaceText);
4547 focusOnEditor = true;
4548 focusOnFind = false;
4549 }
4550}
4551
4552
4553
4554//
4555// TextEditor::setAutoCompleteConfig
4556//
4557
4558
4559void TextEditor::Autocomplete::setConfig(const AutoCompleteConfig* config) {
4560 if (config) {
4561 configuration = *config;
4562 configured = true;
4563
4564 } else {
4565 configured = false;
4566 }
4567
4568 active = false;
4569}
4570
4571
4572//
4573// TextEditor::Autocomplete::startTyping
4574//
4575
4576bool TextEditor::Autocomplete::startTyping(Cursors& cursors) {
4577 if (!active && !requestActivation && configured && configuration.triggerOnTyping) {
4578 triggeredManually = false;
4579 start(cursors);
4580 return true;
4581
4582 } else {
4583 return false;
4584 }
4585}
4586
4587
4588//
4589// TextEditor::Autocomplete::startShortcut
4590//
4591
4592bool TextEditor::Autocomplete::startShortcut(Cursors& cursors) {
4593 if (!active && !requestActivation && configured && configuration.triggerOnShortcut) {
4594 triggeredManually = true;
4595 start(cursors);
4596 return true;
4597
4598 } else {
4599 return false;
4600 }
4601}
4602
4603
4604//
4605// TextEditor::Autocomplete::cancel
4606//
4607
4608void TextEditor::Autocomplete::cancel() {
4609 if (active) {
4610 requestDeactivation = true;
4611 }
4612}
4613
4614
4615//
4616// renderSuggestion
4617//
4618
4619static bool renderSuggestion(const std::string_view& suggestion, const std::string_view& searchTerm, float width, bool selected) {
4620 // custom widget to render an autocomplete suggestion in the style of Visual Studio Code
4621 auto glyphPos = ImGui::GetCursorScreenPos();
4622 auto size = ImVec2(width, ImGui::GetFrameHeightWithSpacing());
4623 auto clicked = ImGui::InvisibleButton("suggestion", size);
4624
4625 auto drawList = ImGui::GetWindowDrawList();
4626 auto font = ImGui::GetFont();
4627 auto fontSize = ImGui::GetFontSize();
4628 auto glyphWidth = ImGui::CalcTextSize("#").x;
4629
4630 // highlight selected item
4631 if (selected) {
4632 drawList->AddRectFilled(glyphPos, glyphPos + size, ImGui::GetColorU32(ImGuiCol_Header));
4633 }
4634
4635 // process all UTF-8 glyphs in suggestion
4636 glyphPos += ImGui::GetStyle().FramePadding;
4637 auto suggestionEnd = suggestion.end();
4638 auto searchTermEnd = searchTerm.end();
4639 auto i = TextEditor::CodePoint::skipBOM(suggestion.begin(), suggestionEnd);
4640 auto j = TextEditor::CodePoint::skipBOM(searchTerm.begin(), searchTermEnd);
4641
4642 while (i < suggestionEnd) {
4643 // get next glyph from suggestion
4644 ImWchar codepoint;
4645 i = TextEditor::CodePoint::read(i, suggestionEnd, &codepoint);
4646
4647 // highlight glyph in suggestion that match search term
4648 auto color = ImGui::GetColorU32(ImGuiCol_Text);
4649
4650 if (j < searchTermEnd) {
4651 ImWchar searchCodePoint;
4652 auto next = TextEditor::CodePoint::read(j, searchTermEnd, &searchCodePoint);
4653
4654 if (TextEditor::CodePoint::toLower(searchCodePoint) == TextEditor::CodePoint::toLower(codepoint)) {
4655 color = ImGui::GetColorU32(ImGuiCol_TextLink);
4656 j = next;
4657 }
4658 }
4659
4660 // render the glyph
4661 font->RenderChar(drawList, fontSize, glyphPos, color, codepoint);
4662 glyphPos.x += glyphWidth;
4663 }
4664
4665 return clicked;
4666}
4667
4668
4669//
4670// TextEditor::Autocomplete::render
4671//
4672
4673bool TextEditor::Autocomplete::render(Document& document, Cursors& cursors, const Language* language, float textOffset, ImVec2 glyphSize) {
4674 // see if we need to activate autocomplete mode
4675 if (requestActivation) {
4676 // apply popup delay
4677 if (std::chrono::system_clock::now() > activationTime) {
4678 // reset activation flag
4679 requestActivation = false;
4680
4681 // capture locations
4682 startLocation = document.findWordStart(currentLocation, true);
4683
4684 // update the autocomplete state
4685 updateState(document, language);
4686
4687 // handle cases where autocomplete request is ignored
4688 if(state.inComment && !configuration.triggerInComments) {
4689 return false;
4690 }
4691
4692 if(state.inString && !configuration.triggerInStrings) {
4693 return false;
4694 }
4695
4696 // get initial list of suggestions from the app
4697 refreshSuggestions();
4698
4699 // show autocomplete popup window
4700 ImGui::OpenPopup("AutoCompleteContextMenu");
4701 active = true;
4702 }
4703 }
4704
4705 // only continue if autocomplete is active
4706 if (!active) {
4707 return false;
4708 }
4709
4710 // see if cursor moved since last time
4711 auto newLocation = cursors.getMain().getSelectionEnd();
4712
4713 if (newLocation != currentLocation) {
4714 // see if we need to deactivate autocomplete because cursor is on new line
4715 if (newLocation.line != currentLocation.line) {
4716 requestDeactivation = true;
4717
4718 } else {
4719 // see if cursor moved away from current word
4720 auto newStart = document.findWordStart(newLocation, true);
4721
4722 if (newStart == startLocation) {
4723 currentLocation = newLocation;
4724
4725 // we deactivate autocomplete if the current location is the start
4726 if (currentLocation == startLocation) {
4727 requestDeactivation = true;
4728
4729 } else {
4730 updateState(document, language);
4731 refreshSuggestions();
4732 }
4733
4734 } else {
4735 requestDeactivation = true;
4736 }
4737 }
4738 }
4739
4740 // open popup window
4741 bool result = false;
4742 auto cursorScreenPos = ImGui::GetCursorScreenPos();
4743
4744 ImGui::SetNextWindowPos(ImVec2(
4745 cursorScreenPos.x + textOffset + currentLocation.column * glyphSize.x,
4746 cursorScreenPos.y + (currentLocation.line + 1) * glyphSize.y));
4747
4748 auto suggestions = state.suggestions.size();
4749 auto visibleSuggestions = (suggestions == 0) ? 1 : std::min(static_cast<size_t>(10), suggestions);
4750 auto& style = ImGui::GetStyle();
4751 auto height = ImGui::GetFrameHeightWithSpacing() * visibleSuggestions + style.WindowPadding.y * 2.0f;
4752 ImGui::SetNextWindowSize(ImVec2(suggestionWidth, height));
4753
4754 ImGuiWindowFlags flags =
4755 ImGuiWindowFlags_NoFocusOnAppearing |
4756 ImGuiWindowFlags_NoNav;
4757
4758 if (ImGui::BeginPopup("AutoCompleteContextMenu", flags)) {
4759 if (ImGui::IsWindowAppearing()) {
4760 ImGui::BringWindowToDisplayFront(ImGui::GetCurrentWindow());
4761 }
4762
4763 // deactivate popup (if requested)
4764 if (requestDeactivation) {
4765 ImGui::CloseCurrentPopup();
4766 requestDeactivation = false;
4767 active = false;
4768
4769 } else {
4770 // do we have any suggestions
4771 if (suggestions) {
4772 auto items = state.suggestions.size();
4773
4774 // apply arrow keys to selected suggestion
4775 if (ImGui::IsKeyPressed(ImGuiKey_UpArrow)) {
4776 if (currentSelection == 0) {
4777 currentSelection = items - 1;
4778}
4779 else {
4780 currentSelection--;
4781 }
4782
4783 } else if (ImGui::IsKeyPressed(ImGuiKey_DownArrow)) {
4784 if (currentSelection == items - 1) {
4785 currentSelection = 0;
4786
4787 } else {
4788 currentSelection++;
4789 }
4790
4791 // use selected suggestion if user hit tab of return
4792 } else if (ImGui::IsKeyPressed(ImGuiKey_Tab) || ImGui::IsKeyPressed(ImGuiKey_Enter) || ImGui::IsKeyPressed(ImGuiKey_KeypadEnter)) {
4793 requestDeactivation = true;
4794 result = true;
4795
4796 } else if (configuration.autoInsertSingleSuggestions && triggeredManually && state.suggestions.size() == 1) {
4797 requestDeactivation = true;
4798 result = true;
4799 }
4800
4801 // render suggestions
4802 for (size_t i = 0; i < items; i++) {
4803 // ensure unique ID
4804 ImGui::PushID(static_cast<int>(i));
4805
4806 // scroll list to selected item (if required)
4807 auto selected = i == currentSelection;
4808
4809 if (selected) {
4810 ImGui::SetScrollHereY(1.0f);
4811 }
4812
4813 if (renderSuggestion(state.suggestions[i].c_str(), state.searchTerm, ImGui::GetContentRegionAvail().x, selected)) {
4814 // user clicked on a suggestion, use it
4815 currentSelection = i;
4816 requestDeactivation = true;
4817 result = true;
4818 }
4819
4820 ImGui::PopID();
4821 }
4822
4823 } else {
4824 ImGui::TextUnformatted(configuration.noSuggestionsLabel.c_str());
4825 }
4826 }
4827
4828 ImGui::EndPopup();
4829
4830 } else {
4831 requestDeactivation = false;
4832 active = false;
4833 }
4834
4835 return result;
4836}
4837
4838
4839//
4840// TextEditor::Autocomplete::setSuggestions
4841//
4842
4843void TextEditor::Autocomplete::setSuggestions(const std::vector<std::string>& suggestions) {
4844 state.suggestions = suggestions;
4845 currentSelection = 0;
4846}
4847
4848
4849//
4850// TextEditor::Autocomplete::isSpecialKeyPressed
4851//
4852
4853bool TextEditor::Autocomplete::isSpecialKeyPressed() const {
4854 for (auto key : {ImGuiKey_Tab, ImGuiKey_Enter, ImGuiKey_KeypadEnter, ImGuiKey_UpArrow, ImGuiKey_DownArrow}) {
4855 if (ImGui::IsKeyPressed(key)) {
4856 return true;
4857 }
4858 }
4859
4860 return false;
4861}
4862
4863
4864//
4865// TextEditor::Autocomplete::start
4866//
4867
4868void TextEditor::Autocomplete::start(Cursors& cursors) {
4869 // request start of autocomplete mode (can't be done here as the Dear ImGui context might not be right)
4870 requestActivation = true;
4871 currentLocation = cursors.getMain().getSelectionEnd();
4872 activationTime = std::chrono::system_clock::now() + configuration.triggerDelay;
4873}
4874
4875
4876//
4877// TextEditor::Autocomplete::updateState
4878//
4879
4880void TextEditor::Autocomplete::updateState(Document& document, const Language* language) {
4881 state.searchTerm = document.getSectionText(startLocation, currentLocation);
4882
4883 if (currentLocation.column == 0) {
4884 state.inIdentifier = false;
4885 state.inNumber = false;
4886
4887 auto lineState = document[currentLocation.line].state;
4888 state.inComment = lineState == State::inComment;
4889
4890 state.inString =
4891 lineState == State::inDoubleQuotedString ||
4892 lineState == State::inSingleQuotedString||
4893 lineState == State::inOtherString ||
4894 lineState == State::inOtherStringAlt;
4895
4896 } else {
4897 auto color = document.getColor(Coordinate(currentLocation.line, currentLocation.column - 1));
4898 state.inIdentifier = color == Color::identifier || color == Color::knownIdentifier;
4899 state.inNumber = color == Color::number;
4900 state.inComment = color == Color::comment;
4901 state.inString = color == Color::string;
4902 }
4903
4904 state.line = currentLocation.line;
4905 state.searchTermStartColumn = startLocation.column;
4906 state.searchTermStartIndex = document.getIndex(startLocation);
4907 state.searchTermEndColumn = currentLocation.column;
4908 state.searchTermEndIndex= document.getIndex(currentLocation);
4909
4910 state.language = language;
4911 state.userData = configuration.userData;
4912}
4913
4914
4915//
4916// TextEditor::Autocomplete::refreshSuggestions
4917//
4918
4919void TextEditor::Autocomplete::refreshSuggestions() {
4920 // populate suggestion list through callback (or clear it if there is none)
4921 if (configuration.callback) {
4922 configuration.callback(state);
4923
4924 } else {
4925 state.suggestions.clear();
4926 }
4927
4928 currentSelection = 0;
4929}
4930
4931
4932//
4933// TextEditor::Trie::insert
4934//
4935
4936void TextEditor::Trie::insert(const std::string_view& word) {
4937 auto node = root.get();
4938 auto end = word.end();
4939 auto i = TextEditor::CodePoint::skipBOM(word.begin(), end);
4940
4941 while (i < end) {
4942 ImWchar codepoint;
4943 i = TextEditor::CodePoint::read(i, end, &codepoint);
4944
4945 if (node->children.find(codepoint) == node->children.end()) {
4946 node->children[codepoint] = std::make_unique<Node>();
4947 }
4948
4949 node = node->children[codepoint].get();
4950 }
4951
4952 node->word = word;
4953}
4954
4955
4956//
4957// TextEditor::Trie::findSuggestions
4958//
4959
4960void TextEditor::Trie::findSuggestions(std::vector<std::string>& suggestions, const std::string_view& searchTerm, size_t limit, size_t maxSkippedLetters) {
4961 // clear result vector
4962 maxSkip = maxSkippedLetters;
4963 suggestions.clear();
4964
4965 // don't even try if search term is empty
4966 if (searchTerm.size() != 0) {
4967 // convert search term into vector of code blocks
4968 searchCodepoints.clear();
4969 auto end = searchTerm.end();
4970 auto i = TextEditor::CodePoint::skipBOM(searchTerm.begin(), end);
4971
4972 while (i < end) {
4973 ImWchar codepoint;
4974 i = TextEditor::CodePoint::read(i, end, &codepoint);
4975 searchCodepoints.emplace_back(codepoint);
4976 }
4977
4978 // recursively evaluate nodes
4979 candidates.clear();
4980 evaluateNode(root.get(), 0, 0, maxSkip);
4981
4982 // did we find anything?
4983 if (candidates.size()) {
4984 // sort candidates by cost
4985 std::sort(candidates.begin(), candidates.end());
4986
4987 // remove duplicates which are caused by mutiple paths based on skips
4988 auto last = std::unique(candidates.begin(), candidates.end());
4989 candidates.erase(last, candidates.end());
4990
4991 // populate suggestions (applying limit)
4992 auto size = std::min(static_cast<size_t>(limit), candidates.size());
4993
4994 for (size_t j = 0; j < size; j++) {
4995 suggestions.emplace_back(candidates[j].node->word);
4996 }
4997 }
4998 }
4999}
5000
5001
5002//
5003// TextEditor::Trie::evaluateNode
5004//
5005
5006void TextEditor::Trie::evaluateNode(const Node* node, size_t index, size_t cost, size_t skip) {
5007 // see if that is one of our children (check both lower and uppercase matches)
5008 ImWchar codepointLower = TextEditor::CodePoint::toLower(searchCodepoints[index]);
5009 Node* childLower = nullptr;
5010
5011 if (node->children.find(codepointLower) != node->children.end()) {
5012 // codepoint found, is this the last one in our searchTerm?
5013 childLower = node->children.at(codepointLower).get();
5014
5015 if (index == searchCodepoints.size() - 1) {
5016 // yes, add candidate words to results
5017 addCandidates(childLower, cost);
5018
5019 } else {
5020 // no, try to find the rest
5021 evaluateNode(childLower, index + 1, cost, maxSkip);
5022 }
5023 }
5024
5025 ImWchar codepointUpper = TextEditor::CodePoint::toUpper(searchCodepoints[index]);
5026 Node* childUpper = nullptr;
5027
5028 if (node->children.find(codepointUpper) != node->children.end()) {
5029 // codepoint found, is this the last one in our searchTerm?
5030 childUpper = node->children.at(codepointUpper).get();
5031
5032 if (index == searchCodepoints.size() - 1) {
5033 // yes, add candidate words to results
5034 addCandidates(childUpper, cost);
5035
5036 } else {
5037 // no, try to find the rest
5038 evaluateNode(childUpper, index + 1, cost, maxSkip);
5039 }
5040 }
5041
5042 // also try children to support detection of missing letters (if we haven't skipped too many entries yet)
5043 if (skip) {
5044 for (auto const& [key, value] : node->children) {
5045 auto next = value.get();
5046
5047 if (next != childLower && next != childUpper) {
5048 evaluateNode(next, index, cost + 1, skip - 1);
5049 }
5050 }
5051 }
5052}
5053
5054
5055//
5056// TextEditor::Trie::addCandidates
5057//
5058
5059void TextEditor::Trie::addCandidates(const Node* node, size_t cost) {
5060 if (node->word.size()) {
5061 candidates.emplace_back(node, cost);
5062 }
5063
5064 for (auto const& [key, value] : node->children) {
5065 addCandidates(value.get(), cost + 1);
5066 }
5067}
5068
5069
5070//
5071// Range table types
5072//
5073
5074template <typename T>
5075struct Range {
5076 T low;
5077 T high;
5078 T stride;
5079};
5080
5081using Range16 = Range<ImWchar16>;
5082using Range32 = Range<ImWchar32>;
5083
5084template <typename T>
5085struct CaseRange {
5086 T low;
5087 T high;
5088 int32_t toUpper;
5089 int32_t toLower;
5090};
5091
5092using CaseRange16 = CaseRange<char16_t>;
5093using CaseRange32 = CaseRange<char32_t>;
5094
5095
5096//
5097// letters16
5098//
5099
5100static Range16 letters16[] = {
5101 {0x0041, 0x005a, 0x0001}, {0x0061, 0x007a, 0x0001}, {0x00aa, 0x00b5, 0x000b}, {0x00ba, 0x00c0, 0x0006},
5102 {0x00c1, 0x00d6, 0x0001}, {0x00d8, 0x00f6, 0x0001}, {0x00f8, 0x02c1, 0x0001}, {0x02c6, 0x02d1, 0x0001},
5103 {0x02e0, 0x02e4, 0x0001}, {0x02ec, 0x02ee, 0x0002}, {0x0370, 0x0374, 0x0001}, {0x0376, 0x0377, 0x0001},
5104 {0x037a, 0x037d, 0x0001}, {0x037f, 0x0386, 0x0007}, {0x0388, 0x038a, 0x0001}, {0x038c, 0x038e, 0x0002},
5105 {0x038f, 0x03a1, 0x0001}, {0x03a3, 0x03f5, 0x0001}, {0x03f7, 0x0481, 0x0001}, {0x048a, 0x052f, 0x0001},
5106 {0x0531, 0x0556, 0x0001}, {0x0559, 0x0560, 0x0007}, {0x0561, 0x0588, 0x0001}, {0x05d0, 0x05ea, 0x0001},
5107 {0x05ef, 0x05f2, 0x0001}, {0x0620, 0x064a, 0x0001}, {0x066e, 0x066f, 0x0001}, {0x0671, 0x06d3, 0x0001},
5108 {0x06d5, 0x06e5, 0x0010}, {0x06e6, 0x06ee, 0x0008}, {0x06ef, 0x06fa, 0x000b}, {0x06fb, 0x06fc, 0x0001},
5109 {0x06ff, 0x0710, 0x0011}, {0x0712, 0x072f, 0x0001}, {0x074d, 0x07a5, 0x0001}, {0x07b1, 0x07ca, 0x0019},
5110 {0x07cb, 0x07ea, 0x0001}, {0x07f4, 0x07f5, 0x0001}, {0x07fa, 0x0800, 0x0006}, {0x0801, 0x0815, 0x0001},
5111 {0x081a, 0x0824, 0x000a}, {0x0828, 0x0840, 0x0018}, {0x0841, 0x0858, 0x0001}, {0x0860, 0x086a, 0x0001},
5112 {0x0870, 0x0887, 0x0001}, {0x0889, 0x088f, 0x0001}, {0x08a0, 0x08c9, 0x0001}, {0x0904, 0x0939, 0x0001},
5113 {0x093d, 0x0950, 0x0013}, {0x0958, 0x0961, 0x0001}, {0x0971, 0x0980, 0x0001}, {0x0985, 0x098c, 0x0001},
5114 {0x098f, 0x0990, 0x0001}, {0x0993, 0x09a8, 0x0001}, {0x09aa, 0x09b0, 0x0001}, {0x09b2, 0x09b6, 0x0004},
5115 {0x09b7, 0x09b9, 0x0001}, {0x09bd, 0x09ce, 0x0011}, {0x09dc, 0x09dd, 0x0001}, {0x09df, 0x09e1, 0x0001},
5116 {0x09f0, 0x09f1, 0x0001}, {0x09fc, 0x0a05, 0x0009}, {0x0a06, 0x0a0a, 0x0001}, {0x0a0f, 0x0a10, 0x0001},
5117 {0x0a13, 0x0a28, 0x0001}, {0x0a2a, 0x0a30, 0x0001}, {0x0a32, 0x0a33, 0x0001}, {0x0a35, 0x0a36, 0x0001},
5118 {0x0a38, 0x0a39, 0x0001}, {0x0a59, 0x0a5c, 0x0001}, {0x0a5e, 0x0a72, 0x0014}, {0x0a73, 0x0a74, 0x0001},
5119 {0x0a85, 0x0a8d, 0x0001}, {0x0a8f, 0x0a91, 0x0001}, {0x0a93, 0x0aa8, 0x0001}, {0x0aaa, 0x0ab0, 0x0001},
5120 {0x0ab2, 0x0ab3, 0x0001}, {0x0ab5, 0x0ab9, 0x0001}, {0x0abd, 0x0ad0, 0x0013}, {0x0ae0, 0x0ae1, 0x0001},
5121 {0x0af9, 0x0b05, 0x000c}, {0x0b06, 0x0b0c, 0x0001}, {0x0b0f, 0x0b10, 0x0001}, {0x0b13, 0x0b28, 0x0001},
5122 {0x0b2a, 0x0b30, 0x0001}, {0x0b32, 0x0b33, 0x0001}, {0x0b35, 0x0b39, 0x0001}, {0x0b3d, 0x0b5c, 0x001f},
5123 {0x0b5d, 0x0b5f, 0x0002}, {0x0b60, 0x0b61, 0x0001}, {0x0b71, 0x0b83, 0x0012}, {0x0b85, 0x0b8a, 0x0001},
5124 {0x0b8e, 0x0b90, 0x0001}, {0x0b92, 0x0b95, 0x0001}, {0x0b99, 0x0b9a, 0x0001}, {0x0b9c, 0x0b9e, 0x0002},
5125 {0x0b9f, 0x0ba3, 0x0004}, {0x0ba4, 0x0ba8, 0x0004}, {0x0ba9, 0x0baa, 0x0001}, {0x0bae, 0x0bb9, 0x0001},
5126 {0x0bd0, 0x0c05, 0x0035}, {0x0c06, 0x0c0c, 0x0001}, {0x0c0e, 0x0c10, 0x0001}, {0x0c12, 0x0c28, 0x0001},
5127 {0x0c2a, 0x0c39, 0x0001}, {0x0c3d, 0x0c58, 0x001b}, {0x0c59, 0x0c5a, 0x0001}, {0x0c5c, 0x0c5d, 0x0001},
5128 {0x0c60, 0x0c61, 0x0001}, {0x0c80, 0x0c85, 0x0005}, {0x0c86, 0x0c8c, 0x0001}, {0x0c8e, 0x0c90, 0x0001},
5129 {0x0c92, 0x0ca8, 0x0001}, {0x0caa, 0x0cb3, 0x0001}, {0x0cb5, 0x0cb9, 0x0001}, {0x0cbd, 0x0cdc, 0x001f},
5130 {0x0cdd, 0x0cde, 0x0001}, {0x0ce0, 0x0ce1, 0x0001}, {0x0cf1, 0x0cf2, 0x0001}, {0x0d04, 0x0d0c, 0x0001},
5131 {0x0d0e, 0x0d10, 0x0001}, {0x0d12, 0x0d3a, 0x0001}, {0x0d3d, 0x0d4e, 0x0011}, {0x0d54, 0x0d56, 0x0001},
5132 {0x0d5f, 0x0d61, 0x0001}, {0x0d7a, 0x0d7f, 0x0001}, {0x0d85, 0x0d96, 0x0001}, {0x0d9a, 0x0db1, 0x0001},
5133 {0x0db3, 0x0dbb, 0x0001}, {0x0dbd, 0x0dc0, 0x0003}, {0x0dc1, 0x0dc6, 0x0001}, {0x0e01, 0x0e30, 0x0001},
5134 {0x0e32, 0x0e33, 0x0001}, {0x0e40, 0x0e46, 0x0001}, {0x0e81, 0x0e82, 0x0001}, {0x0e84, 0x0e86, 0x0002},
5135 {0x0e87, 0x0e8a, 0x0001}, {0x0e8c, 0x0ea3, 0x0001}, {0x0ea5, 0x0ea7, 0x0002}, {0x0ea8, 0x0eb0, 0x0001},
5136 {0x0eb2, 0x0eb3, 0x0001}, {0x0ebd, 0x0ec0, 0x0003}, {0x0ec1, 0x0ec4, 0x0001}, {0x0ec6, 0x0edc, 0x0016},
5137 {0x0edd, 0x0edf, 0x0001}, {0x0f00, 0x0f40, 0x0040}, {0x0f41, 0x0f47, 0x0001}, {0x0f49, 0x0f6c, 0x0001},
5138 {0x0f88, 0x0f8c, 0x0001}, {0x1000, 0x102a, 0x0001}, {0x103f, 0x1050, 0x0011}, {0x1051, 0x1055, 0x0001},
5139 {0x105a, 0x105d, 0x0001}, {0x1061, 0x1065, 0x0004}, {0x1066, 0x106e, 0x0008}, {0x106f, 0x1070, 0x0001},
5140 {0x1075, 0x1081, 0x0001}, {0x108e, 0x10a0, 0x0012}, {0x10a1, 0x10c5, 0x0001}, {0x10c7, 0x10cd, 0x0006},
5141 {0x10d0, 0x10fa, 0x0001}, {0x10fc, 0x1248, 0x0001}, {0x124a, 0x124d, 0x0001}, {0x1250, 0x1256, 0x0001},
5142 {0x1258, 0x125a, 0x0002}, {0x125b, 0x125d, 0x0001}, {0x1260, 0x1288, 0x0001}, {0x128a, 0x128d, 0x0001},
5143 {0x1290, 0x12b0, 0x0001}, {0x12b2, 0x12b5, 0x0001}, {0x12b8, 0x12be, 0x0001}, {0x12c0, 0x12c2, 0x0002},
5144 {0x12c3, 0x12c5, 0x0001}, {0x12c8, 0x12d6, 0x0001}, {0x12d8, 0x1310, 0x0001}, {0x1312, 0x1315, 0x0001},
5145 {0x1318, 0x135a, 0x0001}, {0x1380, 0x138f, 0x0001}, {0x13a0, 0x13f5, 0x0001}, {0x13f8, 0x13fd, 0x0001},
5146 {0x1401, 0x166c, 0x0001}, {0x166f, 0x167f, 0x0001}, {0x1681, 0x169a, 0x0001}, {0x16a0, 0x16ea, 0x0001},
5147 {0x16f1, 0x16f8, 0x0001}, {0x1700, 0x1711, 0x0001}, {0x171f, 0x1731, 0x0001}, {0x1740, 0x1751, 0x0001},
5148 {0x1760, 0x176c, 0x0001}, {0x176e, 0x1770, 0x0001}, {0x1780, 0x17b3, 0x0001}, {0x17d7, 0x17dc, 0x0005},
5149 {0x1820, 0x1878, 0x0001}, {0x1880, 0x1884, 0x0001}, {0x1887, 0x18a8, 0x0001}, {0x18aa, 0x18b0, 0x0006},
5150 {0x18b1, 0x18f5, 0x0001}, {0x1900, 0x191e, 0x0001}, {0x1950, 0x196d, 0x0001}, {0x1970, 0x1974, 0x0001},
5151 {0x1980, 0x19ab, 0x0001}, {0x19b0, 0x19c9, 0x0001}, {0x1a00, 0x1a16, 0x0001}, {0x1a20, 0x1a54, 0x0001},
5152 {0x1aa7, 0x1b05, 0x005e}, {0x1b06, 0x1b33, 0x0001}, {0x1b45, 0x1b4c, 0x0001}, {0x1b83, 0x1ba0, 0x0001},
5153 {0x1bae, 0x1baf, 0x0001}, {0x1bba, 0x1be5, 0x0001}, {0x1c00, 0x1c23, 0x0001}, {0x1c4d, 0x1c4f, 0x0001},
5154 {0x1c5a, 0x1c7d, 0x0001}, {0x1c80, 0x1c8a, 0x0001}, {0x1c90, 0x1cba, 0x0001}, {0x1cbd, 0x1cbf, 0x0001},
5155 {0x1ce9, 0x1cec, 0x0001}, {0x1cee, 0x1cf3, 0x0001}, {0x1cf5, 0x1cf6, 0x0001}, {0x1cfa, 0x1d00, 0x0006},
5156 {0x1d01, 0x1dbf, 0x0001}, {0x1e00, 0x1f15, 0x0001}, {0x1f18, 0x1f1d, 0x0001}, {0x1f20, 0x1f45, 0x0001},
5157 {0x1f48, 0x1f4d, 0x0001}, {0x1f50, 0x1f57, 0x0001}, {0x1f59, 0x1f5f, 0x0002}, {0x1f60, 0x1f7d, 0x0001},
5158 {0x1f80, 0x1fb4, 0x0001}, {0x1fb6, 0x1fbc, 0x0001}, {0x1fbe, 0x1fc2, 0x0004}, {0x1fc3, 0x1fc4, 0x0001},
5159 {0x1fc6, 0x1fcc, 0x0001}, {0x1fd0, 0x1fd3, 0x0001}, {0x1fd6, 0x1fdb, 0x0001}, {0x1fe0, 0x1fec, 0x0001},
5160 {0x1ff2, 0x1ff4, 0x0001}, {0x1ff6, 0x1ffc, 0x0001}, {0x2071, 0x207f, 0x000e}, {0x2090, 0x209c, 0x0001},
5161 {0x2102, 0x2107, 0x0005}, {0x210a, 0x2113, 0x0001}, {0x2115, 0x2119, 0x0004}, {0x211a, 0x211d, 0x0001},
5162 {0x2124, 0x212a, 0x0002}, {0x212b, 0x212d, 0x0001}, {0x212f, 0x2139, 0x0001}, {0x213c, 0x213f, 0x0001},
5163 {0x2145, 0x2149, 0x0001}, {0x214e, 0x2183, 0x0035}, {0x2184, 0x2c00, 0x0a7c}, {0x2c01, 0x2ce4, 0x0001},
5164 {0x2ceb, 0x2cee, 0x0001}, {0x2cf2, 0x2cf3, 0x0001}, {0x2d00, 0x2d25, 0x0001}, {0x2d27, 0x2d2d, 0x0006},
5165 {0x2d30, 0x2d67, 0x0001}, {0x2d6f, 0x2d80, 0x0011}, {0x2d81, 0x2d96, 0x0001}, {0x2da0, 0x2da6, 0x0001},
5166 {0x2da8, 0x2dae, 0x0001}, {0x2db0, 0x2db6, 0x0001}, {0x2db8, 0x2dbe, 0x0001}, {0x2dc0, 0x2dc6, 0x0001},
5167 {0x2dc8, 0x2dce, 0x0001}, {0x2dd0, 0x2dd6, 0x0001}, {0x2dd8, 0x2dde, 0x0001}, {0x2e2f, 0x3005, 0x01d6},
5168 {0x3006, 0x3031, 0x002b}, {0x3032, 0x3035, 0x0001}, {0x303b, 0x303c, 0x0001}, {0x3041, 0x3096, 0x0001},
5169 {0x309d, 0x309f, 0x0001}, {0x30a1, 0x30fa, 0x0001}, {0x30fc, 0x30ff, 0x0001}, {0x3105, 0x312f, 0x0001},
5170 {0x3131, 0x318e, 0x0001}, {0x31a0, 0x31bf, 0x0001}, {0x31f0, 0x31ff, 0x0001}, {0x3400, 0x4dbf, 0x19bf},
5171 {0x4e00, 0x9fff, 0x51ff}, {0xa000, 0xa48c, 0x0001}, {0xa4d0, 0xa4fd, 0x0001}, {0xa500, 0xa60c, 0x0001},
5172 {0xa610, 0xa61f, 0x0001}, {0xa62a, 0xa62b, 0x0001}, {0xa640, 0xa66e, 0x0001}, {0xa67f, 0xa69d, 0x0001},
5173 {0xa6a0, 0xa6e5, 0x0001}, {0xa717, 0xa71f, 0x0001}, {0xa722, 0xa788, 0x0001}, {0xa78b, 0xa7dc, 0x0001},
5174 {0xa7f1, 0xa801, 0x0001}, {0xa803, 0xa805, 0x0001}, {0xa807, 0xa80a, 0x0001}, {0xa80c, 0xa822, 0x0001},
5175 {0xa840, 0xa873, 0x0001}, {0xa882, 0xa8b3, 0x0001}, {0xa8f2, 0xa8f7, 0x0001}, {0xa8fb, 0xa8fd, 0x0002},
5176 {0xa8fe, 0xa90a, 0x000c}, {0xa90b, 0xa925, 0x0001}, {0xa930, 0xa946, 0x0001}, {0xa960, 0xa97c, 0x0001},
5177 {0xa984, 0xa9b2, 0x0001}, {0xa9cf, 0xa9e0, 0x0011}, {0xa9e1, 0xa9e4, 0x0001}, {0xa9e6, 0xa9ef, 0x0001},
5178 {0xa9fa, 0xa9fe, 0x0001}, {0xaa00, 0xaa28, 0x0001}, {0xaa40, 0xaa42, 0x0001}, {0xaa44, 0xaa4b, 0x0001},
5179 {0xaa60, 0xaa76, 0x0001}, {0xaa7a, 0xaa7e, 0x0004}, {0xaa7f, 0xaaaf, 0x0001}, {0xaab1, 0xaab5, 0x0004},
5180 {0xaab6, 0xaab9, 0x0003}, {0xaaba, 0xaabd, 0x0001}, {0xaac0, 0xaac2, 0x0002}, {0xaadb, 0xaadd, 0x0001},
5181 {0xaae0, 0xaaea, 0x0001}, {0xaaf2, 0xaaf4, 0x0001}, {0xab01, 0xab06, 0x0001}, {0xab09, 0xab0e, 0x0001},
5182 {0xab11, 0xab16, 0x0001}, {0xab20, 0xab26, 0x0001}, {0xab28, 0xab2e, 0x0001}, {0xab30, 0xab5a, 0x0001},
5183 {0xab5c, 0xab69, 0x0001}, {0xab70, 0xabe2, 0x0001}, {0xac00, 0xd7a3, 0x2ba3}, {0xd7b0, 0xd7c6, 0x0001},
5184 {0xd7cb, 0xd7fb, 0x0001}, {0xf900, 0xfa6d, 0x0001}, {0xfa70, 0xfad9, 0x0001}, {0xfb00, 0xfb06, 0x0001},
5185 {0xfb13, 0xfb17, 0x0001}, {0xfb1d, 0xfb1f, 0x0002}, {0xfb20, 0xfb28, 0x0001}, {0xfb2a, 0xfb36, 0x0001},
5186 {0xfb38, 0xfb3c, 0x0001}, {0xfb3e, 0xfb40, 0x0002}, {0xfb41, 0xfb43, 0x0002}, {0xfb44, 0xfb46, 0x0002},
5187 {0xfb47, 0xfbb1, 0x0001}, {0xfbd3, 0xfd3d, 0x0001}, {0xfd50, 0xfd8f, 0x0001}, {0xfd92, 0xfdc7, 0x0001},
5188 {0xfdf0, 0xfdfb, 0x0001}, {0xfe70, 0xfe74, 0x0001}, {0xfe76, 0xfefc, 0x0001}, {0xff21, 0xff3a, 0x0001},
5189 {0xff41, 0xff5a, 0x0001}, {0xff66, 0xffbe, 0x0001}, {0xffc2, 0xffc7, 0x0001}, {0xffca, 0xffcf, 0x0001},
5190 {0xffd2, 0xffd7, 0x0001}, {0xffda, 0xffdc, 0x0001}
5191};
5192
5193
5194//
5195// letters32
5196//
5197
5198#if defined(IMGUI_USE_WCHAR32)
5199
5200static Range32 letters32[] = {
5201 {0x10000, 0x1000b, 0x0001}, {0x1000d, 0x10026, 0x0001}, {0x10028, 0x1003a, 0x0001}, {0x1003c, 0x1003d, 0x0001},
5202 {0x1003f, 0x1004d, 0x0001}, {0x10050, 0x1005d, 0x0001}, {0x10080, 0x100fa, 0x0001}, {0x10280, 0x1029c, 0x0001},
5203 {0x102a0, 0x102d0, 0x0001}, {0x10300, 0x1031f, 0x0001}, {0x1032d, 0x10340, 0x0001}, {0x10342, 0x10349, 0x0001},
5204 {0x10350, 0x10375, 0x0001}, {0x10380, 0x1039d, 0x0001}, {0x103a0, 0x103c3, 0x0001}, {0x103c8, 0x103cf, 0x0001},
5205 {0x10400, 0x1049d, 0x0001}, {0x104b0, 0x104d3, 0x0001}, {0x104d8, 0x104fb, 0x0001}, {0x10500, 0x10527, 0x0001},
5206 {0x10530, 0x10563, 0x0001}, {0x10570, 0x1057a, 0x0001}, {0x1057c, 0x1058a, 0x0001}, {0x1058c, 0x10592, 0x0001},
5207 {0x10594, 0x10595, 0x0001}, {0x10597, 0x105a1, 0x0001}, {0x105a3, 0x105b1, 0x0001}, {0x105b3, 0x105b9, 0x0001},
5208 {0x105bb, 0x105bc, 0x0001}, {0x105c0, 0x105f3, 0x0001}, {0x10600, 0x10736, 0x0001}, {0x10740, 0x10755, 0x0001},
5209 {0x10760, 0x10767, 0x0001}, {0x10780, 0x10785, 0x0001}, {0x10787, 0x107b0, 0x0001}, {0x107b2, 0x107ba, 0x0001},
5210 {0x10800, 0x10805, 0x0001}, {0x10808, 0x1080a, 0x0002}, {0x1080b, 0x10835, 0x0001}, {0x10837, 0x10838, 0x0001},
5211 {0x1083c, 0x1083f, 0x0003}, {0x10840, 0x10855, 0x0001}, {0x10860, 0x10876, 0x0001}, {0x10880, 0x1089e, 0x0001},
5212 {0x108e0, 0x108f2, 0x0001}, {0x108f4, 0x108f5, 0x0001}, {0x10900, 0x10915, 0x0001}, {0x10920, 0x10939, 0x0001},
5213 {0x10940, 0x10959, 0x0001}, {0x10980, 0x109b7, 0x0001}, {0x109be, 0x109bf, 0x0001}, {0x10a00, 0x10a10, 0x0010},
5214 {0x10a11, 0x10a13, 0x0001}, {0x10a15, 0x10a17, 0x0001}, {0x10a19, 0x10a35, 0x0001}, {0x10a60, 0x10a7c, 0x0001},
5215 {0x10a80, 0x10a9c, 0x0001}, {0x10ac0, 0x10ac7, 0x0001}, {0x10ac9, 0x10ae4, 0x0001}, {0x10b00, 0x10b35, 0x0001},
5216 {0x10b40, 0x10b55, 0x0001}, {0x10b60, 0x10b72, 0x0001}, {0x10b80, 0x10b91, 0x0001}, {0x10c00, 0x10c48, 0x0001},
5217 {0x10c80, 0x10cb2, 0x0001}, {0x10cc0, 0x10cf2, 0x0001}, {0x10d00, 0x10d23, 0x0001}, {0x10d4a, 0x10d65, 0x0001},
5218 {0x10d6f, 0x10d85, 0x0001}, {0x10e80, 0x10ea9, 0x0001}, {0x10eb0, 0x10eb1, 0x0001}, {0x10ec2, 0x10ec7, 0x0001},
5219 {0x10f00, 0x10f1c, 0x0001}, {0x10f27, 0x10f30, 0x0009}, {0x10f31, 0x10f45, 0x0001}, {0x10f70, 0x10f81, 0x0001},
5220 {0x10fb0, 0x10fc4, 0x0001}, {0x10fe0, 0x10ff6, 0x0001}, {0x11003, 0x11037, 0x0001}, {0x11071, 0x11072, 0x0001},
5221 {0x11075, 0x11083, 0x000e}, {0x11084, 0x110af, 0x0001}, {0x110d0, 0x110e8, 0x0001}, {0x11103, 0x11126, 0x0001},
5222 {0x11144, 0x11147, 0x0003}, {0x11150, 0x11172, 0x0001}, {0x11176, 0x11183, 0x000d}, {0x11184, 0x111b2, 0x0001},
5223 {0x111c1, 0x111c4, 0x0001}, {0x111da, 0x111dc, 0x0002}, {0x11200, 0x11211, 0x0001}, {0x11213, 0x1122b, 0x0001},
5224 {0x1123f, 0x11240, 0x0001}, {0x11280, 0x11286, 0x0001}, {0x11288, 0x1128a, 0x0002}, {0x1128b, 0x1128d, 0x0001},
5225 {0x1128f, 0x1129d, 0x0001}, {0x1129f, 0x112a8, 0x0001}, {0x112b0, 0x112de, 0x0001}, {0x11305, 0x1130c, 0x0001},
5226 {0x1130f, 0x11310, 0x0001}, {0x11313, 0x11328, 0x0001}, {0x1132a, 0x11330, 0x0001}, {0x11332, 0x11333, 0x0001},
5227 {0x11335, 0x11339, 0x0001}, {0x1133d, 0x11350, 0x0013}, {0x1135d, 0x11361, 0x0001}, {0x11380, 0x11389, 0x0001},
5228 {0x1138b, 0x1138e, 0x0003}, {0x11390, 0x113b5, 0x0001}, {0x113b7, 0x113d1, 0x001a}, {0x113d3, 0x11400, 0x002d},
5229 {0x11401, 0x11434, 0x0001}, {0x11447, 0x1144a, 0x0001}, {0x1145f, 0x11461, 0x0001}, {0x11480, 0x114af, 0x0001},
5230 {0x114c4, 0x114c5, 0x0001}, {0x114c7, 0x11580, 0x00b9}, {0x11581, 0x115ae, 0x0001}, {0x115d8, 0x115db, 0x0001},
5231 {0x11600, 0x1162f, 0x0001}, {0x11644, 0x11680, 0x003c}, {0x11681, 0x116aa, 0x0001}, {0x116b8, 0x11700, 0x0048},
5232 {0x11701, 0x1171a, 0x0001}, {0x11740, 0x11746, 0x0001}, {0x11800, 0x1182b, 0x0001}, {0x118a0, 0x118df, 0x0001},
5233 {0x118ff, 0x11906, 0x0001}, {0x11909, 0x1190c, 0x0003}, {0x1190d, 0x11913, 0x0001}, {0x11915, 0x11916, 0x0001},
5234 {0x11918, 0x1192f, 0x0001}, {0x1193f, 0x11941, 0x0002}, {0x119a0, 0x119a7, 0x0001}, {0x119aa, 0x119d0, 0x0001},
5235 {0x119e1, 0x119e3, 0x0002}, {0x11a00, 0x11a0b, 0x000b}, {0x11a0c, 0x11a32, 0x0001}, {0x11a3a, 0x11a50, 0x0016},
5236 {0x11a5c, 0x11a89, 0x0001}, {0x11a9d, 0x11ab0, 0x0013}, {0x11ab1, 0x11af8, 0x0001}, {0x11bc0, 0x11be0, 0x0001},
5237 {0x11c00, 0x11c08, 0x0001}, {0x11c0a, 0x11c2e, 0x0001}, {0x11c40, 0x11c72, 0x0032}, {0x11c73, 0x11c8f, 0x0001},
5238 {0x11d00, 0x11d06, 0x0001}, {0x11d08, 0x11d09, 0x0001}, {0x11d0b, 0x11d30, 0x0001}, {0x11d46, 0x11d60, 0x001a},
5239 {0x11d61, 0x11d65, 0x0001}, {0x11d67, 0x11d68, 0x0001}, {0x11d6a, 0x11d89, 0x0001}, {0x11d98, 0x11db0, 0x0018},
5240 {0x11db1, 0x11ddb, 0x0001}, {0x11ee0, 0x11ef2, 0x0001}, {0x11f02, 0x11f04, 0x0002}, {0x11f05, 0x11f10, 0x0001},
5241 {0x11f12, 0x11f33, 0x0001}, {0x11fb0, 0x12000, 0x0050}, {0x12001, 0x12399, 0x0001}, {0x12480, 0x12543, 0x0001},
5242 {0x12f90, 0x12ff0, 0x0001}, {0x13000, 0x1342f, 0x0001}, {0x13441, 0x13446, 0x0001}, {0x13460, 0x143fa, 0x0001},
5243 {0x14400, 0x14646, 0x0001}, {0x16100, 0x1611d, 0x0001}, {0x16800, 0x16a38, 0x0001}, {0x16a40, 0x16a5e, 0x0001},
5244 {0x16a70, 0x16abe, 0x0001}, {0x16ad0, 0x16aed, 0x0001}, {0x16b00, 0x16b2f, 0x0001}, {0x16b40, 0x16b43, 0x0001},
5245 {0x16b63, 0x16b77, 0x0001}, {0x16b7d, 0x16b8f, 0x0001}, {0x16d40, 0x16d6c, 0x0001}, {0x16e40, 0x16e7f, 0x0001},
5246 {0x16ea0, 0x16eb8, 0x0001}, {0x16ebb, 0x16ed3, 0x0001}, {0x16f00, 0x16f4a, 0x0001}, {0x16f50, 0x16f93, 0x0043},
5247 {0x16f94, 0x16f9f, 0x0001}, {0x16fe0, 0x16fe1, 0x0001}, {0x16fe3, 0x16ff2, 0x000f}, {0x16ff3, 0x17000, 0x000d},
5248 {0x187ff, 0x18cd5, 0x0001}, {0x18cff, 0x18d00, 0x0001}, {0x18d1e, 0x18d80, 0x0062}, {0x18d81, 0x18df2, 0x0001},
5249 {0x1aff0, 0x1aff3, 0x0001}, {0x1aff5, 0x1affb, 0x0001}, {0x1affd, 0x1affe, 0x0001}, {0x1b000, 0x1b122, 0x0001},
5250 {0x1b132, 0x1b150, 0x001e}, {0x1b151, 0x1b152, 0x0001}, {0x1b155, 0x1b164, 0x000f}, {0x1b165, 0x1b167, 0x0001},
5251 {0x1b170, 0x1b2fb, 0x0001}, {0x1bc00, 0x1bc6a, 0x0001}, {0x1bc70, 0x1bc7c, 0x0001}, {0x1bc80, 0x1bc88, 0x0001},
5252 {0x1bc90, 0x1bc99, 0x0001}, {0x1d400, 0x1d454, 0x0001}, {0x1d456, 0x1d49c, 0x0001}, {0x1d49e, 0x1d49f, 0x0001},
5253 {0x1d4a2, 0x1d4a5, 0x0003}, {0x1d4a6, 0x1d4a9, 0x0003}, {0x1d4aa, 0x1d4ac, 0x0001}, {0x1d4ae, 0x1d4b9, 0x0001},
5254 {0x1d4bb, 0x1d4bd, 0x0002}, {0x1d4be, 0x1d4c3, 0x0001}, {0x1d4c5, 0x1d505, 0x0001}, {0x1d507, 0x1d50a, 0x0001},
5255 {0x1d50d, 0x1d514, 0x0001}, {0x1d516, 0x1d51c, 0x0001}, {0x1d51e, 0x1d539, 0x0001}, {0x1d53b, 0x1d53e, 0x0001},
5256 {0x1d540, 0x1d544, 0x0001}, {0x1d546, 0x1d54a, 0x0004}, {0x1d54b, 0x1d550, 0x0001}, {0x1d552, 0x1d6a5, 0x0001},
5257 {0x1d6a8, 0x1d6c0, 0x0001}, {0x1d6c2, 0x1d6da, 0x0001}, {0x1d6dc, 0x1d6fa, 0x0001}, {0x1d6fc, 0x1d714, 0x0001},
5258 {0x1d716, 0x1d734, 0x0001}, {0x1d736, 0x1d74e, 0x0001}, {0x1d750, 0x1d76e, 0x0001}, {0x1d770, 0x1d788, 0x0001},
5259 {0x1d78a, 0x1d7a8, 0x0001}, {0x1d7aa, 0x1d7c2, 0x0001}, {0x1d7c4, 0x1d7cb, 0x0001}, {0x1df00, 0x1df1e, 0x0001},
5260 {0x1df25, 0x1df2a, 0x0001}, {0x1e030, 0x1e06d, 0x0001}, {0x1e100, 0x1e12c, 0x0001}, {0x1e137, 0x1e13d, 0x0001},
5261 {0x1e14e, 0x1e290, 0x0142}, {0x1e291, 0x1e2ad, 0x0001}, {0x1e2c0, 0x1e2eb, 0x0001}, {0x1e4d0, 0x1e4eb, 0x0001},
5262 {0x1e5d0, 0x1e5ed, 0x0001}, {0x1e5f0, 0x1e6c0, 0x00d0}, {0x1e6c1, 0x1e6de, 0x0001}, {0x1e6e0, 0x1e6e2, 0x0001},
5263 {0x1e6e4, 0x1e6e5, 0x0001}, {0x1e6e7, 0x1e6ed, 0x0001}, {0x1e6f0, 0x1e6f4, 0x0001}, {0x1e6fe, 0x1e6ff, 0x0001},
5264 {0x1e7e0, 0x1e7e6, 0x0001}, {0x1e7e8, 0x1e7eb, 0x0001}, {0x1e7ed, 0x1e7ee, 0x0001}, {0x1e7f0, 0x1e7fe, 0x0001},
5265 {0x1e800, 0x1e8c4, 0x0001}, {0x1e900, 0x1e943, 0x0001}, {0x1e94b, 0x1ee00, 0x04b5}, {0x1ee01, 0x1ee03, 0x0001},
5266 {0x1ee05, 0x1ee1f, 0x0001}, {0x1ee21, 0x1ee22, 0x0001}, {0x1ee24, 0x1ee27, 0x0003}, {0x1ee29, 0x1ee32, 0x0001},
5267 {0x1ee34, 0x1ee37, 0x0001}, {0x1ee39, 0x1ee3b, 0x0002}, {0x1ee42, 0x1ee47, 0x0005}, {0x1ee49, 0x1ee4d, 0x0002},
5268 {0x1ee4e, 0x1ee4f, 0x0001}, {0x1ee51, 0x1ee52, 0x0001}, {0x1ee54, 0x1ee57, 0x0003}, {0x1ee59, 0x1ee61, 0x0002},
5269 {0x1ee62, 0x1ee64, 0x0002}, {0x1ee67, 0x1ee6a, 0x0001}, {0x1ee6c, 0x1ee72, 0x0001}, {0x1ee74, 0x1ee77, 0x0001},
5270 {0x1ee79, 0x1ee7c, 0x0001}, {0x1ee7e, 0x1ee80, 0x0002}, {0x1ee81, 0x1ee89, 0x0001}, {0x1ee8b, 0x1ee9b, 0x0001},
5271 {0x1eea1, 0x1eea3, 0x0001}, {0x1eea5, 0x1eea9, 0x0001}, {0x1eeab, 0x1eebb, 0x0001}, {0x20000, 0x2a6df, 0xa6df},
5272 {0x2a700, 0x2b73f, 0x103f}, {0x2b740, 0x2b81d, 0x00dd}, {0x2b820, 0x2cead, 0x168d}, {0x2ceb0, 0x2ebe0, 0x1d30},
5273 {0x2ebf0, 0x2ee5d, 0x026d}, {0x2f800, 0x2fa1d, 0x0001}, {0x30000, 0x3134a, 0x134a}, {0x31350, 0x323af, 0x105f},
5274 {0x323b0, 0x33479, 0x10c9}
5275};
5276
5277#endif
5278
5279
5280//
5281// lower16
5282//
5283
5284static Range16 lower16[] = {
5285 {0x0061, 0x007a, 0x0001}, {0x00b5, 0x00df, 0x002a}, {0x00e0, 0x00f6, 0x0001}, {0x00f8, 0x00ff, 0x0001},
5286 {0x0101, 0x0137, 0x0002}, {0x0138, 0x0148, 0x0002}, {0x0149, 0x0177, 0x0002}, {0x017a, 0x017e, 0x0002},
5287 {0x017f, 0x0180, 0x0001}, {0x0183, 0x0185, 0x0002}, {0x0188, 0x018c, 0x0004}, {0x018d, 0x0192, 0x0005},
5288 {0x0195, 0x0199, 0x0004}, {0x019a, 0x019b, 0x0001}, {0x019e, 0x01a1, 0x0003}, {0x01a3, 0x01a5, 0x0002},
5289 {0x01a8, 0x01aa, 0x0002}, {0x01ab, 0x01ad, 0x0002}, {0x01b0, 0x01b4, 0x0004}, {0x01b6, 0x01b9, 0x0003},
5290 {0x01ba, 0x01bd, 0x0003}, {0x01be, 0x01bf, 0x0001}, {0x01c6, 0x01cc, 0x0003}, {0x01ce, 0x01dc, 0x0002},
5291 {0x01dd, 0x01ef, 0x0002}, {0x01f0, 0x01f3, 0x0003}, {0x01f5, 0x01f9, 0x0004}, {0x01fb, 0x0233, 0x0002},
5292 {0x0234, 0x0239, 0x0001}, {0x023c, 0x023f, 0x0003}, {0x0240, 0x0242, 0x0002}, {0x0247, 0x024f, 0x0002},
5293 {0x0250, 0x0293, 0x0001}, {0x0296, 0x02af, 0x0001}, {0x0371, 0x0373, 0x0002}, {0x0377, 0x037b, 0x0004},
5294 {0x037c, 0x037d, 0x0001}, {0x0390, 0x03ac, 0x001c}, {0x03ad, 0x03ce, 0x0001}, {0x03d0, 0x03d1, 0x0001},
5295 {0x03d5, 0x03d7, 0x0001}, {0x03d9, 0x03ef, 0x0002}, {0x03f0, 0x03f3, 0x0001}, {0x03f5, 0x03fb, 0x0003},
5296 {0x03fc, 0x0430, 0x0034}, {0x0431, 0x045f, 0x0001}, {0x0461, 0x0481, 0x0002}, {0x048b, 0x04bf, 0x0002},
5297 {0x04c2, 0x04ce, 0x0002}, {0x04cf, 0x052f, 0x0002}, {0x0560, 0x0588, 0x0001}, {0x10d0, 0x10fa, 0x0001},
5298 {0x10fd, 0x10ff, 0x0001}, {0x13f8, 0x13fd, 0x0001}, {0x1c80, 0x1c88, 0x0001}, {0x1c8a, 0x1d00, 0x0076},
5299 {0x1d01, 0x1d2b, 0x0001}, {0x1d6b, 0x1d77, 0x0001}, {0x1d79, 0x1d9a, 0x0001}, {0x1e01, 0x1e95, 0x0002},
5300 {0x1e96, 0x1e9d, 0x0001}, {0x1e9f, 0x1eff, 0x0002}, {0x1f00, 0x1f07, 0x0001}, {0x1f10, 0x1f15, 0x0001},
5301 {0x1f20, 0x1f27, 0x0001}, {0x1f30, 0x1f37, 0x0001}, {0x1f40, 0x1f45, 0x0001}, {0x1f50, 0x1f57, 0x0001},
5302 {0x1f60, 0x1f67, 0x0001}, {0x1f70, 0x1f7d, 0x0001}, {0x1f80, 0x1f87, 0x0001}, {0x1f90, 0x1f97, 0x0001},
5303 {0x1fa0, 0x1fa7, 0x0001}, {0x1fb0, 0x1fb4, 0x0001}, {0x1fb6, 0x1fb7, 0x0001}, {0x1fbe, 0x1fc2, 0x0004},
5304 {0x1fc3, 0x1fc4, 0x0001}, {0x1fc6, 0x1fc7, 0x0001}, {0x1fd0, 0x1fd3, 0x0001}, {0x1fd6, 0x1fd7, 0x0001},
5305 {0x1fe0, 0x1fe7, 0x0001}, {0x1ff2, 0x1ff4, 0x0001}, {0x1ff6, 0x1ff7, 0x0001}, {0x210a, 0x210e, 0x0004},
5306 {0x210f, 0x2113, 0x0004}, {0x212f, 0x2139, 0x0005}, {0x213c, 0x213d, 0x0001}, {0x2146, 0x2149, 0x0001},
5307 {0x214e, 0x2184, 0x0036}, {0x2c30, 0x2c5f, 0x0001}, {0x2c61, 0x2c65, 0x0004}, {0x2c66, 0x2c6c, 0x0002},
5308 {0x2c71, 0x2c73, 0x0002}, {0x2c74, 0x2c76, 0x0002}, {0x2c77, 0x2c7b, 0x0001}, {0x2c81, 0x2ce3, 0x0002},
5309 {0x2ce4, 0x2cec, 0x0008}, {0x2cee, 0x2cf3, 0x0005}, {0x2d00, 0x2d25, 0x0001}, {0x2d27, 0x2d2d, 0x0006},
5310 {0xa641, 0xa66d, 0x0002}, {0xa681, 0xa69b, 0x0002}, {0xa723, 0xa72f, 0x0002}, {0xa730, 0xa731, 0x0001},
5311 {0xa733, 0xa771, 0x0002}, {0xa772, 0xa778, 0x0001}, {0xa77a, 0xa77c, 0x0002}, {0xa77f, 0xa787, 0x0002},
5312 {0xa78c, 0xa78e, 0x0002}, {0xa791, 0xa793, 0x0002}, {0xa794, 0xa795, 0x0001}, {0xa797, 0xa7a9, 0x0002},
5313 {0xa7af, 0xa7b5, 0x0006}, {0xa7b7, 0xa7c3, 0x0002}, {0xa7c8, 0xa7ca, 0x0002}, {0xa7cd, 0xa7db, 0x0002},
5314 {0xa7f6, 0xa7fa, 0x0004}, {0xab30, 0xab5a, 0x0001}, {0xab60, 0xab68, 0x0001}, {0xab70, 0xabbf, 0x0001},
5315 {0xfb00, 0xfb06, 0x0001}, {0xfb13, 0xfb17, 0x0001}, {0xff41, 0xff5a, 0x0001}
5316};
5317
5318
5319//
5320// lower32
5321//
5322
5323#if defined(IMGUI_USE_WCHAR32)
5324
5325static Range32 lower32[] = {
5326 {0x10428, 0x1044f, 0x0001}, {0x104d8, 0x104fb, 0x0001}, {0x10597, 0x105a1, 0x0001}, {0x105a3, 0x105b1, 0x0001},
5327 {0x105b3, 0x105b9, 0x0001}, {0x105bb, 0x105bc, 0x0001}, {0x10cc0, 0x10cf2, 0x0001}, {0x10d70, 0x10d85, 0x0001},
5328 {0x118c0, 0x118df, 0x0001}, {0x16e60, 0x16e7f, 0x0001}, {0x16ebb, 0x16ed3, 0x0001}, {0x1d41a, 0x1d433, 0x0001},
5329 {0x1d44e, 0x1d454, 0x0001}, {0x1d456, 0x1d467, 0x0001}, {0x1d482, 0x1d49b, 0x0001}, {0x1d4b6, 0x1d4b9, 0x0001},
5330 {0x1d4bb, 0x1d4bd, 0x0002}, {0x1d4be, 0x1d4c3, 0x0001}, {0x1d4c5, 0x1d4cf, 0x0001}, {0x1d4ea, 0x1d503, 0x0001},
5331 {0x1d51e, 0x1d537, 0x0001}, {0x1d552, 0x1d56b, 0x0001}, {0x1d586, 0x1d59f, 0x0001}, {0x1d5ba, 0x1d5d3, 0x0001},
5332 {0x1d5ee, 0x1d607, 0x0001}, {0x1d622, 0x1d63b, 0x0001}, {0x1d656, 0x1d66f, 0x0001}, {0x1d68a, 0x1d6a5, 0x0001},
5333 {0x1d6c2, 0x1d6da, 0x0001}, {0x1d6dc, 0x1d6e1, 0x0001}, {0x1d6fc, 0x1d714, 0x0001}, {0x1d716, 0x1d71b, 0x0001},
5334 {0x1d736, 0x1d74e, 0x0001}, {0x1d750, 0x1d755, 0x0001}, {0x1d770, 0x1d788, 0x0001}, {0x1d78a, 0x1d78f, 0x0001},
5335 {0x1d7aa, 0x1d7c2, 0x0001}, {0x1d7c4, 0x1d7c9, 0x0001}, {0x1d7cb, 0x1df00, 0x0735}, {0x1df01, 0x1df09, 0x0001},
5336 {0x1df0b, 0x1df1e, 0x0001}, {0x1df25, 0x1df2a, 0x0001}, {0x1e922, 0x1e943, 0x0001}
5337};
5338
5339#endif
5340
5341
5342//
5343// upper16
5344//
5345
5346static Range16 upper16[] = {
5347 {0x0041, 0x005a, 0x0001}, {0x00c0, 0x00d6, 0x0001}, {0x00d8, 0x00de, 0x0001}, {0x0100, 0x0136, 0x0002},
5348 {0x0139, 0x0147, 0x0002}, {0x014a, 0x0178, 0x0002}, {0x0179, 0x017d, 0x0002}, {0x0181, 0x0182, 0x0001},
5349 {0x0184, 0x0186, 0x0002}, {0x0187, 0x0189, 0x0002}, {0x018a, 0x018b, 0x0001}, {0x018e, 0x0191, 0x0001},
5350 {0x0193, 0x0194, 0x0001}, {0x0196, 0x0198, 0x0001}, {0x019c, 0x019d, 0x0001}, {0x019f, 0x01a0, 0x0001},
5351 {0x01a2, 0x01a6, 0x0002}, {0x01a7, 0x01a9, 0x0002}, {0x01ac, 0x01ae, 0x0002}, {0x01af, 0x01b1, 0x0002},
5352 {0x01b2, 0x01b3, 0x0001}, {0x01b5, 0x01b7, 0x0002}, {0x01b8, 0x01bc, 0x0004}, {0x01c4, 0x01cd, 0x0003},
5353 {0x01cf, 0x01db, 0x0002}, {0x01de, 0x01ee, 0x0002}, {0x01f1, 0x01f4, 0x0003}, {0x01f6, 0x01f8, 0x0001},
5354 {0x01fa, 0x0232, 0x0002}, {0x023a, 0x023b, 0x0001}, {0x023d, 0x023e, 0x0001}, {0x0241, 0x0243, 0x0002},
5355 {0x0244, 0x0246, 0x0001}, {0x0248, 0x024e, 0x0002}, {0x0370, 0x0372, 0x0002}, {0x0376, 0x037f, 0x0009},
5356 {0x0386, 0x0388, 0x0002}, {0x0389, 0x038a, 0x0001}, {0x038c, 0x038e, 0x0002}, {0x038f, 0x0391, 0x0002},
5357 {0x0392, 0x03a1, 0x0001}, {0x03a3, 0x03ab, 0x0001}, {0x03cf, 0x03d2, 0x0003}, {0x03d3, 0x03d4, 0x0001},
5358 {0x03d8, 0x03ee, 0x0002}, {0x03f4, 0x03f7, 0x0003}, {0x03f9, 0x03fa, 0x0001}, {0x03fd, 0x042f, 0x0001},
5359 {0x0460, 0x0480, 0x0002}, {0x048a, 0x04c0, 0x0002}, {0x04c1, 0x04cd, 0x0002}, {0x04d0, 0x052e, 0x0002},
5360 {0x0531, 0x0556, 0x0001}, {0x10a0, 0x10c5, 0x0001}, {0x10c7, 0x10cd, 0x0006}, {0x13a0, 0x13f5, 0x0001},
5361 {0x1c89, 0x1c90, 0x0007}, {0x1c91, 0x1cba, 0x0001}, {0x1cbd, 0x1cbf, 0x0001}, {0x1e00, 0x1e94, 0x0002},
5362 {0x1e9e, 0x1efe, 0x0002}, {0x1f08, 0x1f0f, 0x0001}, {0x1f18, 0x1f1d, 0x0001}, {0x1f28, 0x1f2f, 0x0001},
5363 {0x1f38, 0x1f3f, 0x0001}, {0x1f48, 0x1f4d, 0x0001}, {0x1f59, 0x1f5f, 0x0002}, {0x1f68, 0x1f6f, 0x0001},
5364 {0x1fb8, 0x1fbb, 0x0001}, {0x1fc8, 0x1fcb, 0x0001}, {0x1fd8, 0x1fdb, 0x0001}, {0x1fe8, 0x1fec, 0x0001},
5365 {0x1ff8, 0x1ffb, 0x0001}, {0x2102, 0x2107, 0x0005}, {0x210b, 0x210d, 0x0001}, {0x2110, 0x2112, 0x0001},
5366 {0x2115, 0x2119, 0x0004}, {0x211a, 0x211d, 0x0001}, {0x2124, 0x212a, 0x0002}, {0x212b, 0x212d, 0x0001},
5367 {0x2130, 0x2133, 0x0001}, {0x213e, 0x213f, 0x0001}, {0x2145, 0x2183, 0x003e}, {0x2c00, 0x2c2f, 0x0001},
5368 {0x2c60, 0x2c62, 0x0002}, {0x2c63, 0x2c64, 0x0001}, {0x2c67, 0x2c6d, 0x0002}, {0x2c6e, 0x2c70, 0x0001},
5369 {0x2c72, 0x2c75, 0x0003}, {0x2c7e, 0x2c80, 0x0001}, {0x2c82, 0x2ce2, 0x0002}, {0x2ceb, 0x2ced, 0x0002},
5370 {0x2cf2, 0xa640, 0x794e}, {0xa642, 0xa66c, 0x0002}, {0xa680, 0xa69a, 0x0002}, {0xa722, 0xa72e, 0x0002},
5371 {0xa732, 0xa76e, 0x0002}, {0xa779, 0xa77d, 0x0002}, {0xa77e, 0xa786, 0x0002}, {0xa78b, 0xa78d, 0x0002},
5372 {0xa790, 0xa792, 0x0002}, {0xa796, 0xa7aa, 0x0002}, {0xa7ab, 0xa7ae, 0x0001}, {0xa7b0, 0xa7b4, 0x0001},
5373 {0xa7b6, 0xa7c4, 0x0002}, {0xa7c5, 0xa7c7, 0x0001}, {0xa7c9, 0xa7cb, 0x0002}, {0xa7cc, 0xa7dc, 0x0002},
5374 {0xa7f5, 0xff21, 0x572c}, {0xff22, 0xff3a, 0x0001}
5375};
5376
5377
5378//
5379// upper32
5380//
5381
5382#if defined(IMGUI_USE_WCHAR32)
5383
5384static Range32 upper32[] = {
5385 {0x10400, 0x10427, 0x0001}, {0x104b0, 0x104d3, 0x0001}, {0x10570, 0x1057a, 0x0001}, {0x1057c, 0x1058a, 0x0001},
5386 {0x1058c, 0x10592, 0x0001}, {0x10594, 0x10595, 0x0001}, {0x10c80, 0x10cb2, 0x0001}, {0x10d50, 0x10d65, 0x0001},
5387 {0x118a0, 0x118bf, 0x0001}, {0x16e40, 0x16e5f, 0x0001}, {0x16ea0, 0x16eb8, 0x0001}, {0x1d400, 0x1d419, 0x0001},
5388 {0x1d434, 0x1d44d, 0x0001}, {0x1d468, 0x1d481, 0x0001}, {0x1d49c, 0x1d49e, 0x0002}, {0x1d49f, 0x1d4a5, 0x0003},
5389 {0x1d4a6, 0x1d4a9, 0x0003}, {0x1d4aa, 0x1d4ac, 0x0001}, {0x1d4ae, 0x1d4b5, 0x0001}, {0x1d4d0, 0x1d4e9, 0x0001},
5390 {0x1d504, 0x1d505, 0x0001}, {0x1d507, 0x1d50a, 0x0001}, {0x1d50d, 0x1d514, 0x0001}, {0x1d516, 0x1d51c, 0x0001},
5391 {0x1d538, 0x1d539, 0x0001}, {0x1d53b, 0x1d53e, 0x0001}, {0x1d540, 0x1d544, 0x0001}, {0x1d546, 0x1d54a, 0x0004},
5392 {0x1d54b, 0x1d550, 0x0001}, {0x1d56c, 0x1d585, 0x0001}, {0x1d5a0, 0x1d5b9, 0x0001}, {0x1d5d4, 0x1d5ed, 0x0001},
5393 {0x1d608, 0x1d621, 0x0001}, {0x1d63c, 0x1d655, 0x0001}, {0x1d670, 0x1d689, 0x0001}, {0x1d6a8, 0x1d6c0, 0x0001},
5394 {0x1d6e2, 0x1d6fa, 0x0001}, {0x1d71c, 0x1d734, 0x0001}, {0x1d756, 0x1d76e, 0x0001}, {0x1d790, 0x1d7a8, 0x0001},
5395 {0x1d7ca, 0x1e900, 0x1136}, {0x1e901, 0x1e921, 0x0001}
5396};
5397
5398#endif
5399
5400
5401//
5402// numbers16
5403//
5404
5405static Range16 numbers16[] = {
5406 {0x0030, 0x0039, 0x0001}, {0x0660, 0x0669, 0x0001}, {0x06f0, 0x06f9, 0x0001}, {0x07c0, 0x07c9, 0x0001},
5407 {0x0966, 0x096f, 0x0001}, {0x09e6, 0x09ef, 0x0001}, {0x0a66, 0x0a6f, 0x0001}, {0x0ae6, 0x0aef, 0x0001},
5408 {0x0b66, 0x0b6f, 0x0001}, {0x0be6, 0x0bef, 0x0001}, {0x0c66, 0x0c6f, 0x0001}, {0x0ce6, 0x0cef, 0x0001},
5409 {0x0d66, 0x0d6f, 0x0001}, {0x0de6, 0x0def, 0x0001}, {0x0e50, 0x0e59, 0x0001}, {0x0ed0, 0x0ed9, 0x0001},
5410 {0x0f20, 0x0f29, 0x0001}, {0x1040, 0x1049, 0x0001}, {0x1090, 0x1099, 0x0001}, {0x17e0, 0x17e9, 0x0001},
5411 {0x1810, 0x1819, 0x0001}, {0x1946, 0x194f, 0x0001}, {0x19d0, 0x19d9, 0x0001}, {0x1a80, 0x1a89, 0x0001},
5412 {0x1a90, 0x1a99, 0x0001}, {0x1b50, 0x1b59, 0x0001}, {0x1bb0, 0x1bb9, 0x0001}, {0x1c40, 0x1c49, 0x0001},
5413 {0x1c50, 0x1c59, 0x0001}, {0xa620, 0xa629, 0x0001}, {0xa8d0, 0xa8d9, 0x0001}, {0xa900, 0xa909, 0x0001},
5414 {0xa9d0, 0xa9d9, 0x0001}, {0xa9f0, 0xa9f9, 0x0001}, {0xaa50, 0xaa59, 0x0001}, {0xabf0, 0xabf9, 0x0001},
5415 {0xff10, 0xff19, 0x0001}
5416};
5417
5418
5419//
5420// numbers32
5421//
5422
5423#if defined(IMGUI_USE_WCHAR32)
5424
5425static Range32 numbers32[] = {
5426 {0x104a0, 0x104a9, 0x0001}, {0x10d30, 0x10d39, 0x0001}, {0x10d40, 0x10d49, 0x0001}, {0x11066, 0x1106f, 0x0001},
5427 {0x110f0, 0x110f9, 0x0001}, {0x11136, 0x1113f, 0x0001}, {0x111d0, 0x111d9, 0x0001}, {0x112f0, 0x112f9, 0x0001},
5428 {0x11450, 0x11459, 0x0001}, {0x114d0, 0x114d9, 0x0001}, {0x11650, 0x11659, 0x0001}, {0x116c0, 0x116c9, 0x0001},
5429 {0x116d0, 0x116e3, 0x0001}, {0x11730, 0x11739, 0x0001}, {0x118e0, 0x118e9, 0x0001}, {0x11950, 0x11959, 0x0001},
5430 {0x11bf0, 0x11bf9, 0x0001}, {0x11c50, 0x11c59, 0x0001}, {0x11d50, 0x11d59, 0x0001}, {0x11da0, 0x11da9, 0x0001},
5431 {0x11de0, 0x11de9, 0x0001}, {0x11f50, 0x11f59, 0x0001}, {0x16130, 0x16139, 0x0001}, {0x16a60, 0x16a69, 0x0001},
5432 {0x16ac0, 0x16ac9, 0x0001}, {0x16b50, 0x16b59, 0x0001}, {0x16d70, 0x16d79, 0x0001}, {0x1ccf0, 0x1ccf9, 0x0001},
5433 {0x1d7ce, 0x1d7ff, 0x0001}, {0x1e140, 0x1e149, 0x0001}, {0x1e2f0, 0x1e2f9, 0x0001}, {0x1e4f0, 0x1e4f9, 0x0001},
5434 {0x1e5f1, 0x1e5fa, 0x0001}, {0x1e950, 0x1e959, 0x0001}, {0x1fbf0, 0x1fbf9, 0x0001}
5435};
5436
5437#endif
5438
5439
5440//
5441// whitespace16
5442//
5443
5444static Range16 whitespace16[] = {
5445 {0x0009, 0x000d, 0x0001}, {0x0020, 0x0085, 0x0065}, {0x00a0, 0x1680, 0x15e0}, {0x2000, 0x200a, 0x0001},
5446 {0x2028, 0x2029, 0x0001}, {0x202f, 0x205f, 0x0030}, {0x3000, 0x3000, 0x0001}
5447};
5448
5449
5450//
5451// xidStart16
5452//
5453
5454static Range16 xidStart16[] = {
5455 {0x0041, 0x005a, 0x0001}, {0x0061, 0x007a, 0x0001}, {0x00aa, 0x00b5, 0x000b}, {0x00ba, 0x00c0, 0x0006},
5456 {0x00c1, 0x00d6, 0x0001}, {0x00d8, 0x00f6, 0x0001}, {0x00f8, 0x02c1, 0x0001}, {0x02c6, 0x02d1, 0x0001},
5457 {0x02e0, 0x02e4, 0x0001}, {0x02ec, 0x02ee, 0x0002}, {0x0370, 0x0374, 0x0001}, {0x0376, 0x0377, 0x0001},
5458 {0x037b, 0x037d, 0x0001}, {0x037f, 0x0386, 0x0007}, {0x0388, 0x038a, 0x0001}, {0x038c, 0x038e, 0x0002},
5459 {0x038f, 0x03a1, 0x0001}, {0x03a3, 0x03f5, 0x0001}, {0x03f7, 0x0481, 0x0001}, {0x048a, 0x052f, 0x0001},
5460 {0x0531, 0x0556, 0x0001}, {0x0559, 0x0560, 0x0007}, {0x0561, 0x0588, 0x0001}, {0x05d0, 0x05ea, 0x0001},
5461 {0x05ef, 0x05f2, 0x0001}, {0x0620, 0x064a, 0x0001}, {0x066e, 0x066f, 0x0001}, {0x0671, 0x06d3, 0x0001},
5462 {0x06d5, 0x06e5, 0x0010}, {0x06e6, 0x06ee, 0x0008}, {0x06ef, 0x06fa, 0x000b}, {0x06fb, 0x06fc, 0x0001},
5463 {0x06ff, 0x0710, 0x0011}, {0x0712, 0x072f, 0x0001}, {0x074d, 0x07a5, 0x0001}, {0x07b1, 0x07ca, 0x0019},
5464 {0x07cb, 0x07ea, 0x0001}, {0x07f4, 0x07f5, 0x0001}, {0x07fa, 0x0800, 0x0006}, {0x0801, 0x0815, 0x0001},
5465 {0x081a, 0x0824, 0x000a}, {0x0828, 0x0840, 0x0018}, {0x0841, 0x0858, 0x0001}, {0x0860, 0x086a, 0x0001},
5466 {0x0870, 0x0887, 0x0001}, {0x0889, 0x088f, 0x0001}, {0x08a0, 0x08c9, 0x0001}, {0x0904, 0x0939, 0x0001},
5467 {0x093d, 0x0950, 0x0013}, {0x0958, 0x0961, 0x0001}, {0x0971, 0x0980, 0x0001}, {0x0985, 0x098c, 0x0001},
5468 {0x098f, 0x0990, 0x0001}, {0x0993, 0x09a8, 0x0001}, {0x09aa, 0x09b0, 0x0001}, {0x09b2, 0x09b6, 0x0004},
5469 {0x09b7, 0x09b9, 0x0001}, {0x09bd, 0x09ce, 0x0011}, {0x09dc, 0x09dd, 0x0001}, {0x09df, 0x09e1, 0x0001},
5470 {0x09f0, 0x09f1, 0x0001}, {0x09fc, 0x0a05, 0x0009}, {0x0a06, 0x0a0a, 0x0001}, {0x0a0f, 0x0a10, 0x0001},
5471 {0x0a13, 0x0a28, 0x0001}, {0x0a2a, 0x0a30, 0x0001}, {0x0a32, 0x0a33, 0x0001}, {0x0a35, 0x0a36, 0x0001},
5472 {0x0a38, 0x0a39, 0x0001}, {0x0a59, 0x0a5c, 0x0001}, {0x0a5e, 0x0a72, 0x0014}, {0x0a73, 0x0a74, 0x0001},
5473 {0x0a85, 0x0a8d, 0x0001}, {0x0a8f, 0x0a91, 0x0001}, {0x0a93, 0x0aa8, 0x0001}, {0x0aaa, 0x0ab0, 0x0001},
5474 {0x0ab2, 0x0ab3, 0x0001}, {0x0ab5, 0x0ab9, 0x0001}, {0x0abd, 0x0ad0, 0x0013}, {0x0ae0, 0x0ae1, 0x0001},
5475 {0x0af9, 0x0b05, 0x000c}, {0x0b06, 0x0b0c, 0x0001}, {0x0b0f, 0x0b10, 0x0001}, {0x0b13, 0x0b28, 0x0001},
5476 {0x0b2a, 0x0b30, 0x0001}, {0x0b32, 0x0b33, 0x0001}, {0x0b35, 0x0b39, 0x0001}, {0x0b3d, 0x0b5c, 0x001f},
5477 {0x0b5d, 0x0b5f, 0x0002}, {0x0b60, 0x0b61, 0x0001}, {0x0b71, 0x0b83, 0x0012}, {0x0b85, 0x0b8a, 0x0001},
5478 {0x0b8e, 0x0b90, 0x0001}, {0x0b92, 0x0b95, 0x0001}, {0x0b99, 0x0b9a, 0x0001}, {0x0b9c, 0x0b9e, 0x0002},
5479 {0x0b9f, 0x0ba3, 0x0004}, {0x0ba4, 0x0ba8, 0x0004}, {0x0ba9, 0x0baa, 0x0001}, {0x0bae, 0x0bb9, 0x0001},
5480 {0x0bd0, 0x0c05, 0x0035}, {0x0c06, 0x0c0c, 0x0001}, {0x0c0e, 0x0c10, 0x0001}, {0x0c12, 0x0c28, 0x0001},
5481 {0x0c2a, 0x0c39, 0x0001}, {0x0c3d, 0x0c58, 0x001b}, {0x0c59, 0x0c5a, 0x0001}, {0x0c5c, 0x0c5d, 0x0001},
5482 {0x0c60, 0x0c61, 0x0001}, {0x0c80, 0x0c85, 0x0005}, {0x0c86, 0x0c8c, 0x0001}, {0x0c8e, 0x0c90, 0x0001},
5483 {0x0c92, 0x0ca8, 0x0001}, {0x0caa, 0x0cb3, 0x0001}, {0x0cb5, 0x0cb9, 0x0001}, {0x0cbd, 0x0cdc, 0x001f},
5484 {0x0cdd, 0x0cde, 0x0001}, {0x0ce0, 0x0ce1, 0x0001}, {0x0cf1, 0x0cf2, 0x0001}, {0x0d04, 0x0d0c, 0x0001},
5485 {0x0d0e, 0x0d10, 0x0001}, {0x0d12, 0x0d3a, 0x0001}, {0x0d3d, 0x0d4e, 0x0011}, {0x0d54, 0x0d56, 0x0001},
5486 {0x0d5f, 0x0d61, 0x0001}, {0x0d7a, 0x0d7f, 0x0001}, {0x0d85, 0x0d96, 0x0001}, {0x0d9a, 0x0db1, 0x0001},
5487 {0x0db3, 0x0dbb, 0x0001}, {0x0dbd, 0x0dc0, 0x0003}, {0x0dc1, 0x0dc6, 0x0001}, {0x0e01, 0x0e30, 0x0001},
5488 {0x0e32, 0x0e40, 0x000e}, {0x0e41, 0x0e46, 0x0001}, {0x0e81, 0x0e82, 0x0001}, {0x0e84, 0x0e86, 0x0002},
5489 {0x0e87, 0x0e8a, 0x0001}, {0x0e8c, 0x0ea3, 0x0001}, {0x0ea5, 0x0ea7, 0x0002}, {0x0ea8, 0x0eb0, 0x0001},
5490 {0x0eb2, 0x0ebd, 0x000b}, {0x0ec0, 0x0ec4, 0x0001}, {0x0ec6, 0x0edc, 0x0016}, {0x0edd, 0x0edf, 0x0001},
5491 {0x0f00, 0x0f40, 0x0040}, {0x0f41, 0x0f47, 0x0001}, {0x0f49, 0x0f6c, 0x0001}, {0x0f88, 0x0f8c, 0x0001},
5492 {0x1000, 0x102a, 0x0001}, {0x103f, 0x1050, 0x0011}, {0x1051, 0x1055, 0x0001}, {0x105a, 0x105d, 0x0001},
5493 {0x1061, 0x1065, 0x0004}, {0x1066, 0x106e, 0x0008}, {0x106f, 0x1070, 0x0001}, {0x1075, 0x1081, 0x0001},
5494 {0x108e, 0x10a0, 0x0012}, {0x10a1, 0x10c5, 0x0001}, {0x10c7, 0x10cd, 0x0006}, {0x10d0, 0x10fa, 0x0001},
5495 {0x10fc, 0x1248, 0x0001}, {0x124a, 0x124d, 0x0001}, {0x1250, 0x1256, 0x0001}, {0x1258, 0x125a, 0x0002},
5496 {0x125b, 0x125d, 0x0001}, {0x1260, 0x1288, 0x0001}, {0x128a, 0x128d, 0x0001}, {0x1290, 0x12b0, 0x0001},
5497 {0x12b2, 0x12b5, 0x0001}, {0x12b8, 0x12be, 0x0001}, {0x12c0, 0x12c2, 0x0002}, {0x12c3, 0x12c5, 0x0001},
5498 {0x12c8, 0x12d6, 0x0001}, {0x12d8, 0x1310, 0x0001}, {0x1312, 0x1315, 0x0001}, {0x1318, 0x135a, 0x0001},
5499 {0x1380, 0x138f, 0x0001}, {0x13a0, 0x13f5, 0x0001}, {0x13f8, 0x13fd, 0x0001}, {0x1401, 0x166c, 0x0001},
5500 {0x166f, 0x167f, 0x0001}, {0x1681, 0x169a, 0x0001}, {0x16a0, 0x16ea, 0x0001}, {0x16ee, 0x16f8, 0x0001},
5501 {0x1700, 0x1711, 0x0001}, {0x171f, 0x1731, 0x0001}, {0x1740, 0x1751, 0x0001}, {0x1760, 0x176c, 0x0001},
5502 {0x176e, 0x1770, 0x0001}, {0x1780, 0x17b3, 0x0001}, {0x17d7, 0x17dc, 0x0005}, {0x1820, 0x1878, 0x0001},
5503 {0x1880, 0x18a8, 0x0001}, {0x18aa, 0x18b0, 0x0006}, {0x18b1, 0x18f5, 0x0001}, {0x1900, 0x191e, 0x0001},
5504 {0x1950, 0x196d, 0x0001}, {0x1970, 0x1974, 0x0001}, {0x1980, 0x19ab, 0x0001}, {0x19b0, 0x19c9, 0x0001},
5505 {0x1a00, 0x1a16, 0x0001}, {0x1a20, 0x1a54, 0x0001}, {0x1aa7, 0x1b05, 0x005e}, {0x1b06, 0x1b33, 0x0001},
5506 {0x1b45, 0x1b4c, 0x0001}, {0x1b83, 0x1ba0, 0x0001}, {0x1bae, 0x1baf, 0x0001}, {0x1bba, 0x1be5, 0x0001},
5507 {0x1c00, 0x1c23, 0x0001}, {0x1c4d, 0x1c4f, 0x0001}, {0x1c5a, 0x1c7d, 0x0001}, {0x1c80, 0x1c8a, 0x0001},
5508 {0x1c90, 0x1cba, 0x0001}, {0x1cbd, 0x1cbf, 0x0001}, {0x1ce9, 0x1cec, 0x0001}, {0x1cee, 0x1cf3, 0x0001},
5509 {0x1cf5, 0x1cf6, 0x0001}, {0x1cfa, 0x1d00, 0x0006}, {0x1d01, 0x1dbf, 0x0001}, {0x1e00, 0x1f15, 0x0001},
5510 {0x1f18, 0x1f1d, 0x0001}, {0x1f20, 0x1f45, 0x0001}, {0x1f48, 0x1f4d, 0x0001}, {0x1f50, 0x1f57, 0x0001},
5511 {0x1f59, 0x1f5f, 0x0002}, {0x1f60, 0x1f7d, 0x0001}, {0x1f80, 0x1fb4, 0x0001}, {0x1fb6, 0x1fbc, 0x0001},
5512 {0x1fbe, 0x1fc2, 0x0004}, {0x1fc3, 0x1fc4, 0x0001}, {0x1fc6, 0x1fcc, 0x0001}, {0x1fd0, 0x1fd3, 0x0001},
5513 {0x1fd6, 0x1fdb, 0x0001}, {0x1fe0, 0x1fec, 0x0001}, {0x1ff2, 0x1ff4, 0x0001}, {0x1ff6, 0x1ffc, 0x0001},
5514 {0x2071, 0x207f, 0x000e}, {0x2090, 0x209c, 0x0001}, {0x2102, 0x2107, 0x0005}, {0x210a, 0x2113, 0x0001},
5515 {0x2115, 0x2118, 0x0003}, {0x2119, 0x211d, 0x0001}, {0x2124, 0x212a, 0x0002}, {0x212b, 0x2139, 0x0001},
5516 {0x213c, 0x213f, 0x0001}, {0x2145, 0x2149, 0x0001}, {0x214e, 0x2160, 0x0012}, {0x2161, 0x2188, 0x0001},
5517 {0x2c00, 0x2ce4, 0x0001}, {0x2ceb, 0x2cee, 0x0001}, {0x2cf2, 0x2cf3, 0x0001}, {0x2d00, 0x2d25, 0x0001},
5518 {0x2d27, 0x2d2d, 0x0006}, {0x2d30, 0x2d67, 0x0001}, {0x2d6f, 0x2d80, 0x0011}, {0x2d81, 0x2d96, 0x0001},
5519 {0x2da0, 0x2da6, 0x0001}, {0x2da8, 0x2dae, 0x0001}, {0x2db0, 0x2db6, 0x0001}, {0x2db8, 0x2dbe, 0x0001},
5520 {0x2dc0, 0x2dc6, 0x0001}, {0x2dc8, 0x2dce, 0x0001}, {0x2dd0, 0x2dd6, 0x0001}, {0x2dd8, 0x2dde, 0x0001},
5521 {0x3005, 0x3007, 0x0001}, {0x3021, 0x3029, 0x0001}, {0x3031, 0x3035, 0x0001}, {0x3038, 0x303c, 0x0001},
5522 {0x3041, 0x3096, 0x0001}, {0x309d, 0x309f, 0x0001}, {0x30a1, 0x30fa, 0x0001}, {0x30fc, 0x30ff, 0x0001},
5523 {0x3105, 0x312f, 0x0001}, {0x3131, 0x318e, 0x0001}, {0x31a0, 0x31bf, 0x0001}, {0x31f0, 0x31ff, 0x0001},
5524 {0x3400, 0x4dbf, 0x0001}, {0x4e00, 0xa48c, 0x0001}, {0xa4d0, 0xa4fd, 0x0001}, {0xa500, 0xa60c, 0x0001},
5525 {0xa610, 0xa61f, 0x0001}, {0xa62a, 0xa62b, 0x0001}, {0xa640, 0xa66e, 0x0001}, {0xa67f, 0xa69d, 0x0001},
5526 {0xa6a0, 0xa6ef, 0x0001}, {0xa717, 0xa71f, 0x0001}, {0xa722, 0xa788, 0x0001}, {0xa78b, 0xa7dc, 0x0001},
5527 {0xa7f1, 0xa801, 0x0001}, {0xa803, 0xa805, 0x0001}, {0xa807, 0xa80a, 0x0001}, {0xa80c, 0xa822, 0x0001},
5528 {0xa840, 0xa873, 0x0001}, {0xa882, 0xa8b3, 0x0001}, {0xa8f2, 0xa8f7, 0x0001}, {0xa8fb, 0xa8fd, 0x0002},
5529 {0xa8fe, 0xa90a, 0x000c}, {0xa90b, 0xa925, 0x0001}, {0xa930, 0xa946, 0x0001}, {0xa960, 0xa97c, 0x0001},
5530 {0xa984, 0xa9b2, 0x0001}, {0xa9cf, 0xa9e0, 0x0011}, {0xa9e1, 0xa9e4, 0x0001}, {0xa9e6, 0xa9ef, 0x0001},
5531 {0xa9fa, 0xa9fe, 0x0001}, {0xaa00, 0xaa28, 0x0001}, {0xaa40, 0xaa42, 0x0001}, {0xaa44, 0xaa4b, 0x0001},
5532 {0xaa60, 0xaa76, 0x0001}, {0xaa7a, 0xaa7e, 0x0004}, {0xaa7f, 0xaaaf, 0x0001}, {0xaab1, 0xaab5, 0x0004},
5533 {0xaab6, 0xaab9, 0x0003}, {0xaaba, 0xaabd, 0x0001}, {0xaac0, 0xaac2, 0x0002}, {0xaadb, 0xaadd, 0x0001},
5534 {0xaae0, 0xaaea, 0x0001}, {0xaaf2, 0xaaf4, 0x0001}, {0xab01, 0xab06, 0x0001}, {0xab09, 0xab0e, 0x0001},
5535 {0xab11, 0xab16, 0x0001}, {0xab20, 0xab26, 0x0001}, {0xab28, 0xab2e, 0x0001}, {0xab30, 0xab5a, 0x0001},
5536 {0xab5c, 0xab69, 0x0001}, {0xab70, 0xabe2, 0x0001}, {0xac00, 0xd7a3, 0x0001}, {0xd7b0, 0xd7c6, 0x0001},
5537 {0xd7cb, 0xd7fb, 0x0001}, {0xf900, 0xfa6d, 0x0001}, {0xfa70, 0xfad9, 0x0001}, {0xfb00, 0xfb06, 0x0001},
5538 {0xfb13, 0xfb17, 0x0001}, {0xfb1d, 0xfb1f, 0x0002}, {0xfb20, 0xfb28, 0x0001}, {0xfb2a, 0xfb36, 0x0001},
5539 {0xfb38, 0xfb3c, 0x0001}, {0xfb3e, 0xfb40, 0x0002}, {0xfb41, 0xfb43, 0x0002}, {0xfb44, 0xfb46, 0x0002},
5540 {0xfb47, 0xfbb1, 0x0001}, {0xfbd3, 0xfc5d, 0x0001}, {0xfc64, 0xfd3d, 0x0001}, {0xfd50, 0xfd8f, 0x0001},
5541 {0xfd92, 0xfdc7, 0x0001}, {0xfdf0, 0xfdf9, 0x0001}, {0xfe71, 0xfe73, 0x0002}, {0xfe77, 0xfe7f, 0x0002},
5542 {0xfe80, 0xfefc, 0x0001}, {0xff21, 0xff3a, 0x0001}, {0xff41, 0xff5a, 0x0001}, {0xff66, 0xff9d, 0x0001},
5543 {0xffa0, 0xffbe, 0x0001}, {0xffc2, 0xffc7, 0x0001}, {0xffca, 0xffcf, 0x0001}, {0xffd2, 0xffd7, 0x0001},
5544 {0xffda, 0xffdc, 0x0001}
5545};
5546
5547
5548//
5549// xidStart32
5550//
5551
5552#if defined(IMGUI_USE_WCHAR32)
5553
5554static Range32 xidStart32[] = {
5555 {0x10000, 0x1000b, 0x0001}, {0x1000d, 0x10026, 0x0001}, {0x10028, 0x1003a, 0x0001}, {0x1003c, 0x1003d, 0x0001},
5556 {0x1003f, 0x1004d, 0x0001}, {0x10050, 0x1005d, 0x0001}, {0x10080, 0x100fa, 0x0001}, {0x10140, 0x10174, 0x0001},
5557 {0x10280, 0x1029c, 0x0001}, {0x102a0, 0x102d0, 0x0001}, {0x10300, 0x1031f, 0x0001}, {0x1032d, 0x1034a, 0x0001},
5558 {0x10350, 0x10375, 0x0001}, {0x10380, 0x1039d, 0x0001}, {0x103a0, 0x103c3, 0x0001}, {0x103c8, 0x103cf, 0x0001},
5559 {0x103d1, 0x103d5, 0x0001}, {0x10400, 0x1049d, 0x0001}, {0x104b0, 0x104d3, 0x0001}, {0x104d8, 0x104fb, 0x0001},
5560 {0x10500, 0x10527, 0x0001}, {0x10530, 0x10563, 0x0001}, {0x10570, 0x1057a, 0x0001}, {0x1057c, 0x1058a, 0x0001},
5561 {0x1058c, 0x10592, 0x0001}, {0x10594, 0x10595, 0x0001}, {0x10597, 0x105a1, 0x0001}, {0x105a3, 0x105b1, 0x0001},
5562 {0x105b3, 0x105b9, 0x0001}, {0x105bb, 0x105bc, 0x0001}, {0x105c0, 0x105f3, 0x0001}, {0x10600, 0x10736, 0x0001},
5563 {0x10740, 0x10755, 0x0001}, {0x10760, 0x10767, 0x0001}, {0x10780, 0x10785, 0x0001}, {0x10787, 0x107b0, 0x0001},
5564 {0x107b2, 0x107ba, 0x0001}, {0x10800, 0x10805, 0x0001}, {0x10808, 0x1080a, 0x0002}, {0x1080b, 0x10835, 0x0001},
5565 {0x10837, 0x10838, 0x0001}, {0x1083c, 0x1083f, 0x0003}, {0x10840, 0x10855, 0x0001}, {0x10860, 0x10876, 0x0001},
5566 {0x10880, 0x1089e, 0x0001}, {0x108e0, 0x108f2, 0x0001}, {0x108f4, 0x108f5, 0x0001}, {0x10900, 0x10915, 0x0001},
5567 {0x10920, 0x10939, 0x0001}, {0x10940, 0x10959, 0x0001}, {0x10980, 0x109b7, 0x0001}, {0x109be, 0x109bf, 0x0001},
5568 {0x10a00, 0x10a10, 0x0010}, {0x10a11, 0x10a13, 0x0001}, {0x10a15, 0x10a17, 0x0001}, {0x10a19, 0x10a35, 0x0001},
5569 {0x10a60, 0x10a7c, 0x0001}, {0x10a80, 0x10a9c, 0x0001}, {0x10ac0, 0x10ac7, 0x0001}, {0x10ac9, 0x10ae4, 0x0001},
5570 {0x10b00, 0x10b35, 0x0001}, {0x10b40, 0x10b55, 0x0001}, {0x10b60, 0x10b72, 0x0001}, {0x10b80, 0x10b91, 0x0001},
5571 {0x10c00, 0x10c48, 0x0001}, {0x10c80, 0x10cb2, 0x0001}, {0x10cc0, 0x10cf2, 0x0001}, {0x10d00, 0x10d23, 0x0001},
5572 {0x10d4a, 0x10d65, 0x0001}, {0x10d6f, 0x10d85, 0x0001}, {0x10e80, 0x10ea9, 0x0001}, {0x10eb0, 0x10eb1, 0x0001},
5573 {0x10ec2, 0x10ec7, 0x0001}, {0x10f00, 0x10f1c, 0x0001}, {0x10f27, 0x10f30, 0x0009}, {0x10f31, 0x10f45, 0x0001},
5574 {0x10f70, 0x10f81, 0x0001}, {0x10fb0, 0x10fc4, 0x0001}, {0x10fe0, 0x10ff6, 0x0001}, {0x11003, 0x11037, 0x0001},
5575 {0x11071, 0x11072, 0x0001}, {0x11075, 0x11083, 0x000e}, {0x11084, 0x110af, 0x0001}, {0x110d0, 0x110e8, 0x0001},
5576 {0x11103, 0x11126, 0x0001}, {0x11144, 0x11147, 0x0003}, {0x11150, 0x11172, 0x0001}, {0x11176, 0x11183, 0x000d},
5577 {0x11184, 0x111b2, 0x0001}, {0x111c1, 0x111c4, 0x0001}, {0x111da, 0x111dc, 0x0002}, {0x11200, 0x11211, 0x0001},
5578 {0x11213, 0x1122b, 0x0001}, {0x1123f, 0x11240, 0x0001}, {0x11280, 0x11286, 0x0001}, {0x11288, 0x1128a, 0x0002},
5579 {0x1128b, 0x1128d, 0x0001}, {0x1128f, 0x1129d, 0x0001}, {0x1129f, 0x112a8, 0x0001}, {0x112b0, 0x112de, 0x0001},
5580 {0x11305, 0x1130c, 0x0001}, {0x1130f, 0x11310, 0x0001}, {0x11313, 0x11328, 0x0001}, {0x1132a, 0x11330, 0x0001},
5581 {0x11332, 0x11333, 0x0001}, {0x11335, 0x11339, 0x0001}, {0x1133d, 0x11350, 0x0013}, {0x1135d, 0x11361, 0x0001},
5582 {0x11380, 0x11389, 0x0001}, {0x1138b, 0x1138e, 0x0003}, {0x11390, 0x113b5, 0x0001}, {0x113b7, 0x113d1, 0x001a},
5583 {0x113d3, 0x11400, 0x002d}, {0x11401, 0x11434, 0x0001}, {0x11447, 0x1144a, 0x0001}, {0x1145f, 0x11461, 0x0001},
5584 {0x11480, 0x114af, 0x0001}, {0x114c4, 0x114c5, 0x0001}, {0x114c7, 0x11580, 0x00b9}, {0x11581, 0x115ae, 0x0001},
5585 {0x115d8, 0x115db, 0x0001}, {0x11600, 0x1162f, 0x0001}, {0x11644, 0x11680, 0x003c}, {0x11681, 0x116aa, 0x0001},
5586 {0x116b8, 0x11700, 0x0048}, {0x11701, 0x1171a, 0x0001}, {0x11740, 0x11746, 0x0001}, {0x11800, 0x1182b, 0x0001},
5587 {0x118a0, 0x118df, 0x0001}, {0x118ff, 0x11906, 0x0001}, {0x11909, 0x1190c, 0x0003}, {0x1190d, 0x11913, 0x0001},
5588 {0x11915, 0x11916, 0x0001}, {0x11918, 0x1192f, 0x0001}, {0x1193f, 0x11941, 0x0002}, {0x119a0, 0x119a7, 0x0001},
5589 {0x119aa, 0x119d0, 0x0001}, {0x119e1, 0x119e3, 0x0002}, {0x11a00, 0x11a0b, 0x000b}, {0x11a0c, 0x11a32, 0x0001},
5590 {0x11a3a, 0x11a50, 0x0016}, {0x11a5c, 0x11a89, 0x0001}, {0x11a9d, 0x11ab0, 0x0013}, {0x11ab1, 0x11af8, 0x0001},
5591 {0x11bc0, 0x11be0, 0x0001}, {0x11c00, 0x11c08, 0x0001}, {0x11c0a, 0x11c2e, 0x0001}, {0x11c40, 0x11c72, 0x0032},
5592 {0x11c73, 0x11c8f, 0x0001}, {0x11d00, 0x11d06, 0x0001}, {0x11d08, 0x11d09, 0x0001}, {0x11d0b, 0x11d30, 0x0001},
5593 {0x11d46, 0x11d60, 0x001a}, {0x11d61, 0x11d65, 0x0001}, {0x11d67, 0x11d68, 0x0001}, {0x11d6a, 0x11d89, 0x0001},
5594 {0x11d98, 0x11db0, 0x0018}, {0x11db1, 0x11ddb, 0x0001}, {0x11ee0, 0x11ef2, 0x0001}, {0x11f02, 0x11f04, 0x0002},
5595 {0x11f05, 0x11f10, 0x0001}, {0x11f12, 0x11f33, 0x0001}, {0x11fb0, 0x12000, 0x0050}, {0x12001, 0x12399, 0x0001},
5596 {0x12400, 0x1246e, 0x0001}, {0x12480, 0x12543, 0x0001}, {0x12f90, 0x12ff0, 0x0001}, {0x13000, 0x1342f, 0x0001},
5597 {0x13441, 0x13446, 0x0001}, {0x13460, 0x143fa, 0x0001}, {0x14400, 0x14646, 0x0001}, {0x16100, 0x1611d, 0x0001},
5598 {0x16800, 0x16a38, 0x0001}, {0x16a40, 0x16a5e, 0x0001}, {0x16a70, 0x16abe, 0x0001}, {0x16ad0, 0x16aed, 0x0001},
5599 {0x16b00, 0x16b2f, 0x0001}, {0x16b40, 0x16b43, 0x0001}, {0x16b63, 0x16b77, 0x0001}, {0x16b7d, 0x16b8f, 0x0001},
5600 {0x16d40, 0x16d6c, 0x0001}, {0x16e40, 0x16e7f, 0x0001}, {0x16ea0, 0x16eb8, 0x0001}, {0x16ebb, 0x16ed3, 0x0001},
5601 {0x16f00, 0x16f4a, 0x0001}, {0x16f50, 0x16f93, 0x0043}, {0x16f94, 0x16f9f, 0x0001}, {0x16fe0, 0x16fe1, 0x0001},
5602 {0x16fe3, 0x16ff2, 0x000f}, {0x16ff3, 0x16ff6, 0x0001}, {0x17000, 0x18cd5, 0x0001}, {0x18cff, 0x18d1e, 0x0001},
5603 {0x18d80, 0x18df2, 0x0001}, {0x1aff0, 0x1aff3, 0x0001}, {0x1aff5, 0x1affb, 0x0001}, {0x1affd, 0x1affe, 0x0001},
5604 {0x1b000, 0x1b122, 0x0001}, {0x1b132, 0x1b150, 0x001e}, {0x1b151, 0x1b152, 0x0001}, {0x1b155, 0x1b164, 0x000f},
5605 {0x1b165, 0x1b167, 0x0001}, {0x1b170, 0x1b2fb, 0x0001}, {0x1bc00, 0x1bc6a, 0x0001}, {0x1bc70, 0x1bc7c, 0x0001},
5606 {0x1bc80, 0x1bc88, 0x0001}, {0x1bc90, 0x1bc99, 0x0001}, {0x1d400, 0x1d454, 0x0001}, {0x1d456, 0x1d49c, 0x0001},
5607 {0x1d49e, 0x1d49f, 0x0001}, {0x1d4a2, 0x1d4a5, 0x0003}, {0x1d4a6, 0x1d4a9, 0x0003}, {0x1d4aa, 0x1d4ac, 0x0001},
5608 {0x1d4ae, 0x1d4b9, 0x0001}, {0x1d4bb, 0x1d4bd, 0x0002}, {0x1d4be, 0x1d4c3, 0x0001}, {0x1d4c5, 0x1d505, 0x0001},
5609 {0x1d507, 0x1d50a, 0x0001}, {0x1d50d, 0x1d514, 0x0001}, {0x1d516, 0x1d51c, 0x0001}, {0x1d51e, 0x1d539, 0x0001},
5610 {0x1d53b, 0x1d53e, 0x0001}, {0x1d540, 0x1d544, 0x0001}, {0x1d546, 0x1d54a, 0x0004}, {0x1d54b, 0x1d550, 0x0001},
5611 {0x1d552, 0x1d6a5, 0x0001}, {0x1d6a8, 0x1d6c0, 0x0001}, {0x1d6c2, 0x1d6da, 0x0001}, {0x1d6dc, 0x1d6fa, 0x0001},
5612 {0x1d6fc, 0x1d714, 0x0001}, {0x1d716, 0x1d734, 0x0001}, {0x1d736, 0x1d74e, 0x0001}, {0x1d750, 0x1d76e, 0x0001},
5613 {0x1d770, 0x1d788, 0x0001}, {0x1d78a, 0x1d7a8, 0x0001}, {0x1d7aa, 0x1d7c2, 0x0001}, {0x1d7c4, 0x1d7cb, 0x0001},
5614 {0x1df00, 0x1df1e, 0x0001}, {0x1df25, 0x1df2a, 0x0001}, {0x1e030, 0x1e06d, 0x0001}, {0x1e100, 0x1e12c, 0x0001},
5615 {0x1e137, 0x1e13d, 0x0001}, {0x1e14e, 0x1e290, 0x0142}, {0x1e291, 0x1e2ad, 0x0001}, {0x1e2c0, 0x1e2eb, 0x0001},
5616 {0x1e4d0, 0x1e4eb, 0x0001}, {0x1e5d0, 0x1e5ed, 0x0001}, {0x1e5f0, 0x1e6c0, 0x00d0}, {0x1e6c1, 0x1e6de, 0x0001},
5617 {0x1e6e0, 0x1e6e2, 0x0001}, {0x1e6e4, 0x1e6e5, 0x0001}, {0x1e6e7, 0x1e6ed, 0x0001}, {0x1e6f0, 0x1e6f4, 0x0001},
5618 {0x1e6fe, 0x1e6ff, 0x0001}, {0x1e7e0, 0x1e7e6, 0x0001}, {0x1e7e8, 0x1e7eb, 0x0001}, {0x1e7ed, 0x1e7ee, 0x0001},
5619 {0x1e7f0, 0x1e7fe, 0x0001}, {0x1e800, 0x1e8c4, 0x0001}, {0x1e900, 0x1e943, 0x0001}, {0x1e94b, 0x1ee00, 0x04b5},
5620 {0x1ee01, 0x1ee03, 0x0001}, {0x1ee05, 0x1ee1f, 0x0001}, {0x1ee21, 0x1ee22, 0x0001}, {0x1ee24, 0x1ee27, 0x0003},
5621 {0x1ee29, 0x1ee32, 0x0001}, {0x1ee34, 0x1ee37, 0x0001}, {0x1ee39, 0x1ee3b, 0x0002}, {0x1ee42, 0x1ee47, 0x0005},
5622 {0x1ee49, 0x1ee4d, 0x0002}, {0x1ee4e, 0x1ee4f, 0x0001}, {0x1ee51, 0x1ee52, 0x0001}, {0x1ee54, 0x1ee57, 0x0003},
5623 {0x1ee59, 0x1ee61, 0x0002}, {0x1ee62, 0x1ee64, 0x0002}, {0x1ee67, 0x1ee6a, 0x0001}, {0x1ee6c, 0x1ee72, 0x0001},
5624 {0x1ee74, 0x1ee77, 0x0001}, {0x1ee79, 0x1ee7c, 0x0001}, {0x1ee7e, 0x1ee80, 0x0002}, {0x1ee81, 0x1ee89, 0x0001},
5625 {0x1ee8b, 0x1ee9b, 0x0001}, {0x1eea1, 0x1eea3, 0x0001}, {0x1eea5, 0x1eea9, 0x0001}, {0x1eeab, 0x1eebb, 0x0001},
5626 {0x20000, 0x2a6df, 0x0001}, {0x2a700, 0x2b81d, 0x0001}, {0x2b820, 0x2cead, 0x0001}, {0x2ceb0, 0x2ebe0, 0x0001},
5627 {0x2ebf0, 0x2ee5d, 0x0001}, {0x2f800, 0x2fa1d, 0x0001}, {0x30000, 0x3134a, 0x0001}, {0x31350, 0x33479, 0x0001}
5628};
5629
5630#endif
5631
5632
5633//
5634// xidContinue16
5635//
5636
5637static Range16 xidContinue16[] = {
5638 {0x0030, 0x0039, 0x0001}, {0x0041, 0x005a, 0x0001}, {0x005f, 0x0061, 0x0002}, {0x0062, 0x007a, 0x0001},
5639 {0x00aa, 0x00b5, 0x000b}, {0x00b7, 0x00ba, 0x0003}, {0x00c0, 0x00d6, 0x0001}, {0x00d8, 0x00f6, 0x0001},
5640 {0x00f8, 0x02c1, 0x0001}, {0x02c6, 0x02d1, 0x0001}, {0x02e0, 0x02e4, 0x0001}, {0x02ec, 0x02ee, 0x0002},
5641 {0x0300, 0x0374, 0x0001}, {0x0376, 0x0377, 0x0001}, {0x037b, 0x037d, 0x0001}, {0x037f, 0x0386, 0x0007},
5642 {0x0387, 0x038a, 0x0001}, {0x038c, 0x038e, 0x0002}, {0x038f, 0x03a1, 0x0001}, {0x03a3, 0x03f5, 0x0001},
5643 {0x03f7, 0x0481, 0x0001}, {0x0483, 0x0487, 0x0001}, {0x048a, 0x052f, 0x0001}, {0x0531, 0x0556, 0x0001},
5644 {0x0559, 0x0560, 0x0007}, {0x0561, 0x0588, 0x0001}, {0x0591, 0x05bd, 0x0001}, {0x05bf, 0x05c1, 0x0002},
5645 {0x05c2, 0x05c4, 0x0002}, {0x05c5, 0x05c7, 0x0002}, {0x05d0, 0x05ea, 0x0001}, {0x05ef, 0x05f2, 0x0001},
5646 {0x0610, 0x061a, 0x0001}, {0x0620, 0x0669, 0x0001}, {0x066e, 0x06d3, 0x0001}, {0x06d5, 0x06dc, 0x0001},
5647 {0x06df, 0x06e8, 0x0001}, {0x06ea, 0x06fc, 0x0001}, {0x06ff, 0x0710, 0x0011}, {0x0711, 0x074a, 0x0001},
5648 {0x074d, 0x07b1, 0x0001}, {0x07c0, 0x07f5, 0x0001}, {0x07fa, 0x0800, 0x0003}, {0x0801, 0x082d, 0x0001},
5649 {0x0840, 0x085b, 0x0001}, {0x0860, 0x086a, 0x0001}, {0x0870, 0x0887, 0x0001}, {0x0889, 0x088f, 0x0001},
5650 {0x0897, 0x08e1, 0x0001}, {0x08e3, 0x0963, 0x0001}, {0x0966, 0x096f, 0x0001}, {0x0971, 0x0983, 0x0001},
5651 {0x0985, 0x098c, 0x0001}, {0x098f, 0x0990, 0x0001}, {0x0993, 0x09a8, 0x0001}, {0x09aa, 0x09b0, 0x0001},
5652 {0x09b2, 0x09b6, 0x0004}, {0x09b7, 0x09b9, 0x0001}, {0x09bc, 0x09c4, 0x0001}, {0x09c7, 0x09c8, 0x0001},
5653 {0x09cb, 0x09ce, 0x0001}, {0x09d7, 0x09dc, 0x0005}, {0x09dd, 0x09df, 0x0002}, {0x09e0, 0x09e3, 0x0001},
5654 {0x09e6, 0x09f1, 0x0001}, {0x09fc, 0x09fe, 0x0002}, {0x0a01, 0x0a03, 0x0001}, {0x0a05, 0x0a0a, 0x0001},
5655 {0x0a0f, 0x0a10, 0x0001}, {0x0a13, 0x0a28, 0x0001}, {0x0a2a, 0x0a30, 0x0001}, {0x0a32, 0x0a33, 0x0001},
5656 {0x0a35, 0x0a36, 0x0001}, {0x0a38, 0x0a39, 0x0001}, {0x0a3c, 0x0a3e, 0x0002}, {0x0a3f, 0x0a42, 0x0001},
5657 {0x0a47, 0x0a48, 0x0001}, {0x0a4b, 0x0a4d, 0x0001}, {0x0a51, 0x0a59, 0x0008}, {0x0a5a, 0x0a5c, 0x0001},
5658 {0x0a5e, 0x0a66, 0x0008}, {0x0a67, 0x0a75, 0x0001}, {0x0a81, 0x0a83, 0x0001}, {0x0a85, 0x0a8d, 0x0001},
5659 {0x0a8f, 0x0a91, 0x0001}, {0x0a93, 0x0aa8, 0x0001}, {0x0aaa, 0x0ab0, 0x0001}, {0x0ab2, 0x0ab3, 0x0001},
5660 {0x0ab5, 0x0ab9, 0x0001}, {0x0abc, 0x0ac5, 0x0001}, {0x0ac7, 0x0ac9, 0x0001}, {0x0acb, 0x0acd, 0x0001},
5661 {0x0ad0, 0x0ae0, 0x0010}, {0x0ae1, 0x0ae3, 0x0001}, {0x0ae6, 0x0aef, 0x0001}, {0x0af9, 0x0aff, 0x0001},
5662 {0x0b01, 0x0b03, 0x0001}, {0x0b05, 0x0b0c, 0x0001}, {0x0b0f, 0x0b10, 0x0001}, {0x0b13, 0x0b28, 0x0001},
5663 {0x0b2a, 0x0b30, 0x0001}, {0x0b32, 0x0b33, 0x0001}, {0x0b35, 0x0b39, 0x0001}, {0x0b3c, 0x0b44, 0x0001},
5664 {0x0b47, 0x0b48, 0x0001}, {0x0b4b, 0x0b4d, 0x0001}, {0x0b55, 0x0b57, 0x0001}, {0x0b5c, 0x0b5d, 0x0001},
5665 {0x0b5f, 0x0b63, 0x0001}, {0x0b66, 0x0b6f, 0x0001}, {0x0b71, 0x0b82, 0x0011}, {0x0b83, 0x0b85, 0x0002},
5666 {0x0b86, 0x0b8a, 0x0001}, {0x0b8e, 0x0b90, 0x0001}, {0x0b92, 0x0b95, 0x0001}, {0x0b99, 0x0b9a, 0x0001},
5667 {0x0b9c, 0x0b9e, 0x0002}, {0x0b9f, 0x0ba3, 0x0004}, {0x0ba4, 0x0ba8, 0x0004}, {0x0ba9, 0x0baa, 0x0001},
5668 {0x0bae, 0x0bb9, 0x0001}, {0x0bbe, 0x0bc2, 0x0001}, {0x0bc6, 0x0bc8, 0x0001}, {0x0bca, 0x0bcd, 0x0001},
5669 {0x0bd0, 0x0bd7, 0x0007}, {0x0be6, 0x0bef, 0x0001}, {0x0c00, 0x0c0c, 0x0001}, {0x0c0e, 0x0c10, 0x0001},
5670 {0x0c12, 0x0c28, 0x0001}, {0x0c2a, 0x0c39, 0x0001}, {0x0c3c, 0x0c44, 0x0001}, {0x0c46, 0x0c48, 0x0001},
5671 {0x0c4a, 0x0c4d, 0x0001}, {0x0c55, 0x0c56, 0x0001}, {0x0c58, 0x0c5a, 0x0001}, {0x0c5c, 0x0c5d, 0x0001},
5672 {0x0c60, 0x0c63, 0x0001}, {0x0c66, 0x0c6f, 0x0001}, {0x0c80, 0x0c83, 0x0001}, {0x0c85, 0x0c8c, 0x0001},
5673 {0x0c8e, 0x0c90, 0x0001}, {0x0c92, 0x0ca8, 0x0001}, {0x0caa, 0x0cb3, 0x0001}, {0x0cb5, 0x0cb9, 0x0001},
5674 {0x0cbc, 0x0cc4, 0x0001}, {0x0cc6, 0x0cc8, 0x0001}, {0x0cca, 0x0ccd, 0x0001}, {0x0cd5, 0x0cd6, 0x0001},
5675 {0x0cdc, 0x0cde, 0x0001}, {0x0ce0, 0x0ce3, 0x0001}, {0x0ce6, 0x0cef, 0x0001}, {0x0cf1, 0x0cf3, 0x0001},
5676 {0x0d00, 0x0d0c, 0x0001}, {0x0d0e, 0x0d10, 0x0001}, {0x0d12, 0x0d44, 0x0001}, {0x0d46, 0x0d48, 0x0001},
5677 {0x0d4a, 0x0d4e, 0x0001}, {0x0d54, 0x0d57, 0x0001}, {0x0d5f, 0x0d63, 0x0001}, {0x0d66, 0x0d6f, 0x0001},
5678 {0x0d7a, 0x0d7f, 0x0001}, {0x0d81, 0x0d83, 0x0001}, {0x0d85, 0x0d96, 0x0001}, {0x0d9a, 0x0db1, 0x0001},
5679 {0x0db3, 0x0dbb, 0x0001}, {0x0dbd, 0x0dc0, 0x0003}, {0x0dc1, 0x0dc6, 0x0001}, {0x0dca, 0x0dcf, 0x0005},
5680 {0x0dd0, 0x0dd4, 0x0001}, {0x0dd6, 0x0dd8, 0x0002}, {0x0dd9, 0x0ddf, 0x0001}, {0x0de6, 0x0def, 0x0001},
5681 {0x0df2, 0x0df3, 0x0001}, {0x0e01, 0x0e3a, 0x0001}, {0x0e40, 0x0e4e, 0x0001}, {0x0e50, 0x0e59, 0x0001},
5682 {0x0e81, 0x0e82, 0x0001}, {0x0e84, 0x0e86, 0x0002}, {0x0e87, 0x0e8a, 0x0001}, {0x0e8c, 0x0ea3, 0x0001},
5683 {0x0ea5, 0x0ea7, 0x0002}, {0x0ea8, 0x0ebd, 0x0001}, {0x0ec0, 0x0ec4, 0x0001}, {0x0ec6, 0x0ec8, 0x0002},
5684 {0x0ec9, 0x0ece, 0x0001}, {0x0ed0, 0x0ed9, 0x0001}, {0x0edc, 0x0edf, 0x0001}, {0x0f00, 0x0f18, 0x0018},
5685 {0x0f19, 0x0f20, 0x0007}, {0x0f21, 0x0f29, 0x0001}, {0x0f35, 0x0f39, 0x0002}, {0x0f3e, 0x0f47, 0x0001},
5686 {0x0f49, 0x0f6c, 0x0001}, {0x0f71, 0x0f84, 0x0001}, {0x0f86, 0x0f97, 0x0001}, {0x0f99, 0x0fbc, 0x0001},
5687 {0x0fc6, 0x1000, 0x003a}, {0x1001, 0x1049, 0x0001}, {0x1050, 0x109d, 0x0001}, {0x10a0, 0x10c5, 0x0001},
5688 {0x10c7, 0x10cd, 0x0006}, {0x10d0, 0x10fa, 0x0001}, {0x10fc, 0x1248, 0x0001}, {0x124a, 0x124d, 0x0001},
5689 {0x1250, 0x1256, 0x0001}, {0x1258, 0x125a, 0x0002}, {0x125b, 0x125d, 0x0001}, {0x1260, 0x1288, 0x0001},
5690 {0x128a, 0x128d, 0x0001}, {0x1290, 0x12b0, 0x0001}, {0x12b2, 0x12b5, 0x0001}, {0x12b8, 0x12be, 0x0001},
5691 {0x12c0, 0x12c2, 0x0002}, {0x12c3, 0x12c5, 0x0001}, {0x12c8, 0x12d6, 0x0001}, {0x12d8, 0x1310, 0x0001},
5692 {0x1312, 0x1315, 0x0001}, {0x1318, 0x135a, 0x0001}, {0x135d, 0x135f, 0x0001}, {0x1369, 0x1371, 0x0001},
5693 {0x1380, 0x138f, 0x0001}, {0x13a0, 0x13f5, 0x0001}, {0x13f8, 0x13fd, 0x0001}, {0x1401, 0x166c, 0x0001},
5694 {0x166f, 0x167f, 0x0001}, {0x1681, 0x169a, 0x0001}, {0x16a0, 0x16ea, 0x0001}, {0x16ee, 0x16f8, 0x0001},
5695 {0x1700, 0x1715, 0x0001}, {0x171f, 0x1734, 0x0001}, {0x1740, 0x1753, 0x0001}, {0x1760, 0x176c, 0x0001},
5696 {0x176e, 0x1770, 0x0001}, {0x1772, 0x1773, 0x0001}, {0x1780, 0x17d3, 0x0001}, {0x17d7, 0x17dc, 0x0005},
5697 {0x17dd, 0x17e0, 0x0003}, {0x17e1, 0x17e9, 0x0001}, {0x180b, 0x180d, 0x0001}, {0x180f, 0x1819, 0x0001},
5698 {0x1820, 0x1878, 0x0001}, {0x1880, 0x18aa, 0x0001}, {0x18b0, 0x18f5, 0x0001}, {0x1900, 0x191e, 0x0001},
5699 {0x1920, 0x192b, 0x0001}, {0x1930, 0x193b, 0x0001}, {0x1946, 0x196d, 0x0001}, {0x1970, 0x1974, 0x0001},
5700 {0x1980, 0x19ab, 0x0001}, {0x19b0, 0x19c9, 0x0001}, {0x19d0, 0x19da, 0x0001}, {0x1a00, 0x1a1b, 0x0001},
5701 {0x1a20, 0x1a5e, 0x0001}, {0x1a60, 0x1a7c, 0x0001}, {0x1a7f, 0x1a89, 0x0001}, {0x1a90, 0x1a99, 0x0001},
5702 {0x1aa7, 0x1ab0, 0x0009}, {0x1ab1, 0x1abd, 0x0001}, {0x1abf, 0x1add, 0x0001}, {0x1ae0, 0x1aeb, 0x0001},
5703 {0x1b00, 0x1b4c, 0x0001}, {0x1b50, 0x1b59, 0x0001}, {0x1b6b, 0x1b73, 0x0001}, {0x1b80, 0x1bf3, 0x0001},
5704 {0x1c00, 0x1c37, 0x0001}, {0x1c40, 0x1c49, 0x0001}, {0x1c4d, 0x1c7d, 0x0001}, {0x1c80, 0x1c8a, 0x0001},
5705 {0x1c90, 0x1cba, 0x0001}, {0x1cbd, 0x1cbf, 0x0001}, {0x1cd0, 0x1cd2, 0x0001}, {0x1cd4, 0x1cfa, 0x0001},
5706 {0x1d00, 0x1f15, 0x0001}, {0x1f18, 0x1f1d, 0x0001}, {0x1f20, 0x1f45, 0x0001}, {0x1f48, 0x1f4d, 0x0001},
5707 {0x1f50, 0x1f57, 0x0001}, {0x1f59, 0x1f5f, 0x0002}, {0x1f60, 0x1f7d, 0x0001}, {0x1f80, 0x1fb4, 0x0001},
5708 {0x1fb6, 0x1fbc, 0x0001}, {0x1fbe, 0x1fc2, 0x0004}, {0x1fc3, 0x1fc4, 0x0001}, {0x1fc6, 0x1fcc, 0x0001},
5709 {0x1fd0, 0x1fd3, 0x0001}, {0x1fd6, 0x1fdb, 0x0001}, {0x1fe0, 0x1fec, 0x0001}, {0x1ff2, 0x1ff4, 0x0001},
5710 {0x1ff6, 0x1ffc, 0x0001}, {0x200c, 0x200d, 0x0001}, {0x203f, 0x2040, 0x0001}, {0x2054, 0x2071, 0x001d},
5711 {0x207f, 0x2090, 0x0011}, {0x2091, 0x209c, 0x0001}, {0x20d0, 0x20dc, 0x0001}, {0x20e1, 0x20e5, 0x0004},
5712 {0x20e6, 0x20f0, 0x0001}, {0x2102, 0x2107, 0x0005}, {0x210a, 0x2113, 0x0001}, {0x2115, 0x2118, 0x0003},
5713 {0x2119, 0x211d, 0x0001}, {0x2124, 0x212a, 0x0002}, {0x212b, 0x2139, 0x0001}, {0x213c, 0x213f, 0x0001},
5714 {0x2145, 0x2149, 0x0001}, {0x214e, 0x2160, 0x0012}, {0x2161, 0x2188, 0x0001}, {0x2c00, 0x2ce4, 0x0001},
5715 {0x2ceb, 0x2cf3, 0x0001}, {0x2d00, 0x2d25, 0x0001}, {0x2d27, 0x2d2d, 0x0006}, {0x2d30, 0x2d67, 0x0001},
5716 {0x2d6f, 0x2d7f, 0x0010}, {0x2d80, 0x2d96, 0x0001}, {0x2da0, 0x2da6, 0x0001}, {0x2da8, 0x2dae, 0x0001},
5717 {0x2db0, 0x2db6, 0x0001}, {0x2db8, 0x2dbe, 0x0001}, {0x2dc0, 0x2dc6, 0x0001}, {0x2dc8, 0x2dce, 0x0001},
5718 {0x2dd0, 0x2dd6, 0x0001}, {0x2dd8, 0x2dde, 0x0001}, {0x2de0, 0x2dff, 0x0001}, {0x3005, 0x3007, 0x0001},
5719 {0x3021, 0x302f, 0x0001}, {0x3031, 0x3035, 0x0001}, {0x3038, 0x303c, 0x0001}, {0x3041, 0x3096, 0x0001},
5720 {0x3099, 0x309a, 0x0001}, {0x309d, 0x309f, 0x0001}, {0x30a1, 0x30ff, 0x0001}, {0x3105, 0x312f, 0x0001},
5721 {0x3131, 0x318e, 0x0001}, {0x31a0, 0x31bf, 0x0001}, {0x31f0, 0x31ff, 0x0001}, {0x3400, 0x4dbf, 0x0001},
5722 {0x4e00, 0xa48c, 0x0001}, {0xa4d0, 0xa4fd, 0x0001}, {0xa500, 0xa60c, 0x0001}, {0xa610, 0xa62b, 0x0001},
5723 {0xa640, 0xa66f, 0x0001}, {0xa674, 0xa67d, 0x0001}, {0xa67f, 0xa6f1, 0x0001}, {0xa717, 0xa71f, 0x0001},
5724 {0xa722, 0xa788, 0x0001}, {0xa78b, 0xa7dc, 0x0001}, {0xa7f1, 0xa827, 0x0001}, {0xa82c, 0xa840, 0x0014},
5725 {0xa841, 0xa873, 0x0001}, {0xa880, 0xa8c5, 0x0001}, {0xa8d0, 0xa8d9, 0x0001}, {0xa8e0, 0xa8f7, 0x0001},
5726 {0xa8fb, 0xa8fd, 0x0002}, {0xa8fe, 0xa92d, 0x0001}, {0xa930, 0xa953, 0x0001}, {0xa960, 0xa97c, 0x0001},
5727 {0xa980, 0xa9c0, 0x0001}, {0xa9cf, 0xa9d9, 0x0001}, {0xa9e0, 0xa9fe, 0x0001}, {0xaa00, 0xaa36, 0x0001},
5728 {0xaa40, 0xaa4d, 0x0001}, {0xaa50, 0xaa59, 0x0001}, {0xaa60, 0xaa76, 0x0001}, {0xaa7a, 0xaac2, 0x0001},
5729 {0xaadb, 0xaadd, 0x0001}, {0xaae0, 0xaaef, 0x0001}, {0xaaf2, 0xaaf6, 0x0001}, {0xab01, 0xab06, 0x0001},
5730 {0xab09, 0xab0e, 0x0001}, {0xab11, 0xab16, 0x0001}, {0xab20, 0xab26, 0x0001}, {0xab28, 0xab2e, 0x0001},
5731 {0xab30, 0xab5a, 0x0001}, {0xab5c, 0xab69, 0x0001}, {0xab70, 0xabea, 0x0001}, {0xabec, 0xabed, 0x0001},
5732 {0xabf0, 0xabf9, 0x0001}, {0xac00, 0xd7a3, 0x0001}, {0xd7b0, 0xd7c6, 0x0001}, {0xd7cb, 0xd7fb, 0x0001},
5733 {0xf900, 0xfa6d, 0x0001}, {0xfa70, 0xfad9, 0x0001}, {0xfb00, 0xfb06, 0x0001}, {0xfb13, 0xfb17, 0x0001},
5734 {0xfb1d, 0xfb28, 0x0001}, {0xfb2a, 0xfb36, 0x0001}, {0xfb38, 0xfb3c, 0x0001}, {0xfb3e, 0xfb40, 0x0002},
5735 {0xfb41, 0xfb43, 0x0002}, {0xfb44, 0xfb46, 0x0002}, {0xfb47, 0xfbb1, 0x0001}, {0xfbd3, 0xfc5d, 0x0001},
5736 {0xfc64, 0xfd3d, 0x0001}, {0xfd50, 0xfd8f, 0x0001}, {0xfd92, 0xfdc7, 0x0001}, {0xfdf0, 0xfdf9, 0x0001},
5737 {0xfe00, 0xfe0f, 0x0001}, {0xfe20, 0xfe2f, 0x0001}, {0xfe33, 0xfe34, 0x0001}, {0xfe4d, 0xfe4f, 0x0001},
5738 {0xfe71, 0xfe73, 0x0002}, {0xfe77, 0xfe7f, 0x0002}, {0xfe80, 0xfefc, 0x0001}, {0xff10, 0xff19, 0x0001},
5739 {0xff21, 0xff3a, 0x0001}, {0xff3f, 0xff41, 0x0002}, {0xff42, 0xff5a, 0x0001}, {0xff65, 0xffbe, 0x0001},
5740 {0xffc2, 0xffc7, 0x0001}, {0xffca, 0xffcf, 0x0001}, {0xffd2, 0xffd7, 0x0001}, {0xffda, 0xffdc, 0x0001}
5741};
5742
5743
5744//
5745// xidContinue32
5746//
5747
5748#if defined(IMGUI_USE_WCHAR32)
5749
5750static Range32 xidContinue32[] = {
5751 {0x10000, 0x1000b, 0x0001}, {0x1000d, 0x10026, 0x0001}, {0x10028, 0x1003a, 0x0001}, {0x1003c, 0x1003d, 0x0001},
5752 {0x1003f, 0x1004d, 0x0001}, {0x10050, 0x1005d, 0x0001}, {0x10080, 0x100fa, 0x0001}, {0x10140, 0x10174, 0x0001},
5753 {0x101fd, 0x10280, 0x0083}, {0x10281, 0x1029c, 0x0001}, {0x102a0, 0x102d0, 0x0001}, {0x102e0, 0x10300, 0x0020},
5754 {0x10301, 0x1031f, 0x0001}, {0x1032d, 0x1034a, 0x0001}, {0x10350, 0x1037a, 0x0001}, {0x10380, 0x1039d, 0x0001},
5755 {0x103a0, 0x103c3, 0x0001}, {0x103c8, 0x103cf, 0x0001}, {0x103d1, 0x103d5, 0x0001}, {0x10400, 0x1049d, 0x0001},
5756 {0x104a0, 0x104a9, 0x0001}, {0x104b0, 0x104d3, 0x0001}, {0x104d8, 0x104fb, 0x0001}, {0x10500, 0x10527, 0x0001},
5757 {0x10530, 0x10563, 0x0001}, {0x10570, 0x1057a, 0x0001}, {0x1057c, 0x1058a, 0x0001}, {0x1058c, 0x10592, 0x0001},
5758 {0x10594, 0x10595, 0x0001}, {0x10597, 0x105a1, 0x0001}, {0x105a3, 0x105b1, 0x0001}, {0x105b3, 0x105b9, 0x0001},
5759 {0x105bb, 0x105bc, 0x0001}, {0x105c0, 0x105f3, 0x0001}, {0x10600, 0x10736, 0x0001}, {0x10740, 0x10755, 0x0001},
5760 {0x10760, 0x10767, 0x0001}, {0x10780, 0x10785, 0x0001}, {0x10787, 0x107b0, 0x0001}, {0x107b2, 0x107ba, 0x0001},
5761 {0x10800, 0x10805, 0x0001}, {0x10808, 0x1080a, 0x0002}, {0x1080b, 0x10835, 0x0001}, {0x10837, 0x10838, 0x0001},
5762 {0x1083c, 0x1083f, 0x0003}, {0x10840, 0x10855, 0x0001}, {0x10860, 0x10876, 0x0001}, {0x10880, 0x1089e, 0x0001},
5763 {0x108e0, 0x108f2, 0x0001}, {0x108f4, 0x108f5, 0x0001}, {0x10900, 0x10915, 0x0001}, {0x10920, 0x10939, 0x0001},
5764 {0x10940, 0x10959, 0x0001}, {0x10980, 0x109b7, 0x0001}, {0x109be, 0x109bf, 0x0001}, {0x10a00, 0x10a03, 0x0001},
5765 {0x10a05, 0x10a06, 0x0001}, {0x10a0c, 0x10a13, 0x0001}, {0x10a15, 0x10a17, 0x0001}, {0x10a19, 0x10a35, 0x0001},
5766 {0x10a38, 0x10a3a, 0x0001}, {0x10a3f, 0x10a60, 0x0021}, {0x10a61, 0x10a7c, 0x0001}, {0x10a80, 0x10a9c, 0x0001},
5767 {0x10ac0, 0x10ac7, 0x0001}, {0x10ac9, 0x10ae6, 0x0001}, {0x10b00, 0x10b35, 0x0001}, {0x10b40, 0x10b55, 0x0001},
5768 {0x10b60, 0x10b72, 0x0001}, {0x10b80, 0x10b91, 0x0001}, {0x10c00, 0x10c48, 0x0001}, {0x10c80, 0x10cb2, 0x0001},
5769 {0x10cc0, 0x10cf2, 0x0001}, {0x10d00, 0x10d27, 0x0001}, {0x10d30, 0x10d39, 0x0001}, {0x10d40, 0x10d65, 0x0001},
5770 {0x10d69, 0x10d6d, 0x0001}, {0x10d6f, 0x10d85, 0x0001}, {0x10e80, 0x10ea9, 0x0001}, {0x10eab, 0x10eac, 0x0001},
5771 {0x10eb0, 0x10eb1, 0x0001}, {0x10ec2, 0x10ec7, 0x0001}, {0x10efa, 0x10f1c, 0x0001}, {0x10f27, 0x10f30, 0x0009},
5772 {0x10f31, 0x10f50, 0x0001}, {0x10f70, 0x10f85, 0x0001}, {0x10fb0, 0x10fc4, 0x0001}, {0x10fe0, 0x10ff6, 0x0001},
5773 {0x11000, 0x11046, 0x0001}, {0x11066, 0x11075, 0x0001}, {0x1107f, 0x110ba, 0x0001}, {0x110c2, 0x110d0, 0x000e},
5774 {0x110d1, 0x110e8, 0x0001}, {0x110f0, 0x110f9, 0x0001}, {0x11100, 0x11134, 0x0001}, {0x11136, 0x1113f, 0x0001},
5775 {0x11144, 0x11147, 0x0001}, {0x11150, 0x11173, 0x0001}, {0x11176, 0x11180, 0x000a}, {0x11181, 0x111c4, 0x0001},
5776 {0x111c9, 0x111cc, 0x0001}, {0x111ce, 0x111da, 0x0001}, {0x111dc, 0x11200, 0x0024}, {0x11201, 0x11211, 0x0001},
5777 {0x11213, 0x11237, 0x0001}, {0x1123e, 0x11241, 0x0001}, {0x11280, 0x11286, 0x0001}, {0x11288, 0x1128a, 0x0002},
5778 {0x1128b, 0x1128d, 0x0001}, {0x1128f, 0x1129d, 0x0001}, {0x1129f, 0x112a8, 0x0001}, {0x112b0, 0x112ea, 0x0001},
5779 {0x112f0, 0x112f9, 0x0001}, {0x11300, 0x11303, 0x0001}, {0x11305, 0x1130c, 0x0001}, {0x1130f, 0x11310, 0x0001},
5780 {0x11313, 0x11328, 0x0001}, {0x1132a, 0x11330, 0x0001}, {0x11332, 0x11333, 0x0001}, {0x11335, 0x11339, 0x0001},
5781 {0x1133b, 0x11344, 0x0001}, {0x11347, 0x11348, 0x0001}, {0x1134b, 0x1134d, 0x0001}, {0x11350, 0x11357, 0x0007},
5782 {0x1135d, 0x11363, 0x0001}, {0x11366, 0x1136c, 0x0001}, {0x11370, 0x11374, 0x0001}, {0x11380, 0x11389, 0x0001},
5783 {0x1138b, 0x1138e, 0x0003}, {0x11390, 0x113b5, 0x0001}, {0x113b7, 0x113c0, 0x0001}, {0x113c2, 0x113c5, 0x0003},
5784 {0x113c7, 0x113ca, 0x0001}, {0x113cc, 0x113d3, 0x0001}, {0x113e1, 0x113e2, 0x0001}, {0x11400, 0x1144a, 0x0001},
5785 {0x11450, 0x11459, 0x0001}, {0x1145e, 0x11461, 0x0001}, {0x11480, 0x114c5, 0x0001}, {0x114c7, 0x114d0, 0x0009},
5786 {0x114d1, 0x114d9, 0x0001}, {0x11580, 0x115b5, 0x0001}, {0x115b8, 0x115c0, 0x0001}, {0x115d8, 0x115dd, 0x0001},
5787 {0x11600, 0x11640, 0x0001}, {0x11644, 0x11650, 0x000c}, {0x11651, 0x11659, 0x0001}, {0x11680, 0x116b8, 0x0001},
5788 {0x116c0, 0x116c9, 0x0001}, {0x116d0, 0x116e3, 0x0001}, {0x11700, 0x1171a, 0x0001}, {0x1171d, 0x1172b, 0x0001},
5789 {0x11730, 0x11739, 0x0001}, {0x11740, 0x11746, 0x0001}, {0x11800, 0x1183a, 0x0001}, {0x118a0, 0x118e9, 0x0001},
5790 {0x118ff, 0x11906, 0x0001}, {0x11909, 0x1190c, 0x0003}, {0x1190d, 0x11913, 0x0001}, {0x11915, 0x11916, 0x0001},
5791 {0x11918, 0x11935, 0x0001}, {0x11937, 0x11938, 0x0001}, {0x1193b, 0x11943, 0x0001}, {0x11950, 0x11959, 0x0001},
5792 {0x119a0, 0x119a7, 0x0001}, {0x119aa, 0x119d7, 0x0001}, {0x119da, 0x119e1, 0x0001}, {0x119e3, 0x119e4, 0x0001},
5793 {0x11a00, 0x11a3e, 0x0001}, {0x11a47, 0x11a50, 0x0009}, {0x11a51, 0x11a99, 0x0001}, {0x11a9d, 0x11ab0, 0x0013},
5794 {0x11ab1, 0x11af8, 0x0001}, {0x11b60, 0x11b67, 0x0001}, {0x11bc0, 0x11be0, 0x0001}, {0x11bf0, 0x11bf9, 0x0001},
5795 {0x11c00, 0x11c08, 0x0001}, {0x11c0a, 0x11c36, 0x0001}, {0x11c38, 0x11c40, 0x0001}, {0x11c50, 0x11c59, 0x0001},
5796 {0x11c72, 0x11c8f, 0x0001}, {0x11c92, 0x11ca7, 0x0001}, {0x11ca9, 0x11cb6, 0x0001}, {0x11d00, 0x11d06, 0x0001},
5797 {0x11d08, 0x11d09, 0x0001}, {0x11d0b, 0x11d36, 0x0001}, {0x11d3a, 0x11d3c, 0x0002}, {0x11d3d, 0x11d3f, 0x0002},
5798 {0x11d40, 0x11d47, 0x0001}, {0x11d50, 0x11d59, 0x0001}, {0x11d60, 0x11d65, 0x0001}, {0x11d67, 0x11d68, 0x0001},
5799 {0x11d6a, 0x11d8e, 0x0001}, {0x11d90, 0x11d91, 0x0001}, {0x11d93, 0x11d98, 0x0001}, {0x11da0, 0x11da9, 0x0001},
5800 {0x11db0, 0x11ddb, 0x0001}, {0x11de0, 0x11de9, 0x0001}, {0x11ee0, 0x11ef6, 0x0001}, {0x11f00, 0x11f10, 0x0001},
5801 {0x11f12, 0x11f3a, 0x0001}, {0x11f3e, 0x11f42, 0x0001}, {0x11f50, 0x11f5a, 0x0001}, {0x11fb0, 0x12000, 0x0050},
5802 {0x12001, 0x12399, 0x0001}, {0x12400, 0x1246e, 0x0001}, {0x12480, 0x12543, 0x0001}, {0x12f90, 0x12ff0, 0x0001},
5803 {0x13000, 0x1342f, 0x0001}, {0x13440, 0x13455, 0x0001}, {0x13460, 0x143fa, 0x0001}, {0x14400, 0x14646, 0x0001},
5804 {0x16100, 0x16139, 0x0001}, {0x16800, 0x16a38, 0x0001}, {0x16a40, 0x16a5e, 0x0001}, {0x16a60, 0x16a69, 0x0001},
5805 {0x16a70, 0x16abe, 0x0001}, {0x16ac0, 0x16ac9, 0x0001}, {0x16ad0, 0x16aed, 0x0001}, {0x16af0, 0x16af4, 0x0001},
5806 {0x16b00, 0x16b36, 0x0001}, {0x16b40, 0x16b43, 0x0001}, {0x16b50, 0x16b59, 0x0001}, {0x16b63, 0x16b77, 0x0001},
5807 {0x16b7d, 0x16b8f, 0x0001}, {0x16d40, 0x16d6c, 0x0001}, {0x16d70, 0x16d79, 0x0001}, {0x16e40, 0x16e7f, 0x0001},
5808 {0x16ea0, 0x16eb8, 0x0001}, {0x16ebb, 0x16ed3, 0x0001}, {0x16f00, 0x16f4a, 0x0001}, {0x16f4f, 0x16f87, 0x0001},
5809 {0x16f8f, 0x16f9f, 0x0001}, {0x16fe0, 0x16fe1, 0x0001}, {0x16fe3, 0x16fe4, 0x0001}, {0x16ff0, 0x16ff6, 0x0001},
5810 {0x17000, 0x18cd5, 0x0001}, {0x18cff, 0x18d1e, 0x0001}, {0x18d80, 0x18df2, 0x0001}, {0x1aff0, 0x1aff3, 0x0001},
5811 {0x1aff5, 0x1affb, 0x0001}, {0x1affd, 0x1affe, 0x0001}, {0x1b000, 0x1b122, 0x0001}, {0x1b132, 0x1b150, 0x001e},
5812 {0x1b151, 0x1b152, 0x0001}, {0x1b155, 0x1b164, 0x000f}, {0x1b165, 0x1b167, 0x0001}, {0x1b170, 0x1b2fb, 0x0001},
5813 {0x1bc00, 0x1bc6a, 0x0001}, {0x1bc70, 0x1bc7c, 0x0001}, {0x1bc80, 0x1bc88, 0x0001}, {0x1bc90, 0x1bc99, 0x0001},
5814 {0x1bc9d, 0x1bc9e, 0x0001}, {0x1ccf0, 0x1ccf9, 0x0001}, {0x1cf00, 0x1cf2d, 0x0001}, {0x1cf30, 0x1cf46, 0x0001},
5815 {0x1d165, 0x1d169, 0x0001}, {0x1d16d, 0x1d172, 0x0001}, {0x1d17b, 0x1d182, 0x0001}, {0x1d185, 0x1d18b, 0x0001},
5816 {0x1d1aa, 0x1d1ad, 0x0001}, {0x1d242, 0x1d244, 0x0001}, {0x1d400, 0x1d454, 0x0001}, {0x1d456, 0x1d49c, 0x0001},
5817 {0x1d49e, 0x1d49f, 0x0001}, {0x1d4a2, 0x1d4a5, 0x0003}, {0x1d4a6, 0x1d4a9, 0x0003}, {0x1d4aa, 0x1d4ac, 0x0001},
5818 {0x1d4ae, 0x1d4b9, 0x0001}, {0x1d4bb, 0x1d4bd, 0x0002}, {0x1d4be, 0x1d4c3, 0x0001}, {0x1d4c5, 0x1d505, 0x0001},
5819 {0x1d507, 0x1d50a, 0x0001}, {0x1d50d, 0x1d514, 0x0001}, {0x1d516, 0x1d51c, 0x0001}, {0x1d51e, 0x1d539, 0x0001},
5820 {0x1d53b, 0x1d53e, 0x0001}, {0x1d540, 0x1d544, 0x0001}, {0x1d546, 0x1d54a, 0x0004}, {0x1d54b, 0x1d550, 0x0001},
5821 {0x1d552, 0x1d6a5, 0x0001}, {0x1d6a8, 0x1d6c0, 0x0001}, {0x1d6c2, 0x1d6da, 0x0001}, {0x1d6dc, 0x1d6fa, 0x0001},
5822 {0x1d6fc, 0x1d714, 0x0001}, {0x1d716, 0x1d734, 0x0001}, {0x1d736, 0x1d74e, 0x0001}, {0x1d750, 0x1d76e, 0x0001},
5823 {0x1d770, 0x1d788, 0x0001}, {0x1d78a, 0x1d7a8, 0x0001}, {0x1d7aa, 0x1d7c2, 0x0001}, {0x1d7c4, 0x1d7cb, 0x0001},
5824 {0x1d7ce, 0x1d7ff, 0x0001}, {0x1da00, 0x1da36, 0x0001}, {0x1da3b, 0x1da6c, 0x0001}, {0x1da75, 0x1da84, 0x000f},
5825 {0x1da9b, 0x1da9f, 0x0001}, {0x1daa1, 0x1daaf, 0x0001}, {0x1df00, 0x1df1e, 0x0001}, {0x1df25, 0x1df2a, 0x0001},
5826 {0x1e000, 0x1e006, 0x0001}, {0x1e008, 0x1e018, 0x0001}, {0x1e01b, 0x1e021, 0x0001}, {0x1e023, 0x1e024, 0x0001},
5827 {0x1e026, 0x1e02a, 0x0001}, {0x1e030, 0x1e06d, 0x0001}, {0x1e08f, 0x1e100, 0x0071}, {0x1e101, 0x1e12c, 0x0001},
5828 {0x1e130, 0x1e13d, 0x0001}, {0x1e140, 0x1e149, 0x0001}, {0x1e14e, 0x1e290, 0x0142}, {0x1e291, 0x1e2ae, 0x0001},
5829 {0x1e2c0, 0x1e2f9, 0x0001}, {0x1e4d0, 0x1e4f9, 0x0001}, {0x1e5d0, 0x1e5fa, 0x0001}, {0x1e6c0, 0x1e6de, 0x0001},
5830 {0x1e6e0, 0x1e6f5, 0x0001}, {0x1e6fe, 0x1e6ff, 0x0001}, {0x1e7e0, 0x1e7e6, 0x0001}, {0x1e7e8, 0x1e7eb, 0x0001},
5831 {0x1e7ed, 0x1e7ee, 0x0001}, {0x1e7f0, 0x1e7fe, 0x0001}, {0x1e800, 0x1e8c4, 0x0001}, {0x1e8d0, 0x1e8d6, 0x0001},
5832 {0x1e900, 0x1e94b, 0x0001}, {0x1e950, 0x1e959, 0x0001}, {0x1ee00, 0x1ee03, 0x0001}, {0x1ee05, 0x1ee1f, 0x0001},
5833 {0x1ee21, 0x1ee22, 0x0001}, {0x1ee24, 0x1ee27, 0x0003}, {0x1ee29, 0x1ee32, 0x0001}, {0x1ee34, 0x1ee37, 0x0001},
5834 {0x1ee39, 0x1ee3b, 0x0002}, {0x1ee42, 0x1ee47, 0x0005}, {0x1ee49, 0x1ee4d, 0x0002}, {0x1ee4e, 0x1ee4f, 0x0001},
5835 {0x1ee51, 0x1ee52, 0x0001}, {0x1ee54, 0x1ee57, 0x0003}, {0x1ee59, 0x1ee61, 0x0002}, {0x1ee62, 0x1ee64, 0x0002},
5836 {0x1ee67, 0x1ee6a, 0x0001}, {0x1ee6c, 0x1ee72, 0x0001}, {0x1ee74, 0x1ee77, 0x0001}, {0x1ee79, 0x1ee7c, 0x0001},
5837 {0x1ee7e, 0x1ee80, 0x0002}, {0x1ee81, 0x1ee89, 0x0001}, {0x1ee8b, 0x1ee9b, 0x0001}, {0x1eea1, 0x1eea3, 0x0001},
5838 {0x1eea5, 0x1eea9, 0x0001}, {0x1eeab, 0x1eebb, 0x0001}, {0x1fbf0, 0x1fbf9, 0x0001}, {0x20000, 0x2a6df, 0x0001},
5839 {0x2a700, 0x2b81d, 0x0001}, {0x2b820, 0x2cead, 0x0001}, {0x2ceb0, 0x2ebe0, 0x0001}, {0x2ebf0, 0x2ee5d, 0x0001},
5840 {0x2f800, 0x2fa1d, 0x0001}, {0x30000, 0x3134a, 0x0001}, {0x31350, 0x33479, 0x0001}, {0xe0100, 0xe01ef, 0x0001}
5841};
5842
5843#endif
5844
5845
5846//
5847// case16
5848//
5849
5850static CaseRange16 case16[] = {
5851 {0x0041, 0x005a, 0, 32}, {0x0061, 0x007a, -32, 0}, {0x00b5, 0x00b5, 743, 0},
5852 {0x00c0, 0x00d6, 0, 32}, {0x00d8, 0x00de, 0, 32}, {0x00e0, 0x00f6, -32, 0},
5853 {0x00f8, 0x00fe, -32, 0}, {0x00ff, 0x00ff, 121, 0}, {0x0100, 0x012f, 65535, 65535},
5854 {0x0130, 0x0130, 0, -199}, {0x0131, 0x0131, -232, 0}, {0x0132, 0x0177, 65535, 65535},
5855 {0x0178, 0x0178, 0, -121}, {0x0179, 0x017e, 65535, 65535}, {0x017f, 0x017f, -300, 0},
5856 {0x0180, 0x0180, 195, 0}, {0x0181, 0x0181, 0, 210}, {0x0182, 0x0185, 65535, 65535},
5857 {0x0186, 0x0186, 0, 206}, {0x0187, 0x0188, 65535, 65535}, {0x0189, 0x018a, 0, 205},
5858 {0x018b, 0x018c, 65535, 65535}, {0x018e, 0x018e, 0, 79}, {0x018f, 0x018f, 0, 202},
5859 {0x0190, 0x0190, 0, 203}, {0x0191, 0x0192, 65535, 65535}, {0x0193, 0x0193, 0, 205},
5860 {0x0194, 0x0194, 0, 207}, {0x0195, 0x0195, 97, 0}, {0x0196, 0x0196, 0, 211},
5861 {0x0197, 0x0197, 0, 209}, {0x0198, 0x0199, 65535, 65535}, {0x019a, 0x019a, 163, 0},
5862 {0x019b, 0x019b, 42561, 0}, {0x019c, 0x019c, 0, 211}, {0x019d, 0x019d, 0, 213},
5863 {0x019e, 0x019e, 130, 0}, {0x019f, 0x019f, 0, 214}, {0x01a0, 0x01a5, 65535, 65535},
5864 {0x01a6, 0x01a6, 0, 218}, {0x01a7, 0x01a8, 65535, 65535}, {0x01a9, 0x01a9, 0, 218},
5865 {0x01ac, 0x01ad, 65535, 65535}, {0x01ae, 0x01ae, 0, 218}, {0x01af, 0x01b0, 65535, 65535},
5866 {0x01b1, 0x01b2, 0, 217}, {0x01b3, 0x01b6, 65535, 65535}, {0x01b7, 0x01b7, 0, 219},
5867 {0x01b8, 0x01bd, 65535, 65535}, {0x01bf, 0x01bf, 56, 0}, {0x01c4, 0x01c4, 0, 2},
5868 {0x01c6, 0x01c6, -2, 0}, {0x01c7, 0x01c7, 0, 2}, {0x01c9, 0x01c9, -2, 0},
5869 {0x01ca, 0x01ca, 0, 2}, {0x01cc, 0x01cc, -2, 0}, {0x01cd, 0x01dc, 65535, 65535},
5870 {0x01dd, 0x01dd, -79, 0}, {0x01de, 0x01ef, 65535, 65535}, {0x01f1, 0x01f1, 0, 2},
5871 {0x01f3, 0x01f3, -2, 0}, {0x01f4, 0x01f5, 65535, 65535}, {0x01f6, 0x01f6, 0, -97},
5872 {0x01f7, 0x01f7, 0, -56}, {0x01f8, 0x021f, 65535, 65535}, {0x0220, 0x0220, 0, -130},
5873 {0x0222, 0x0233, 65535, 65535}, {0x023a, 0x023a, 0, 10795}, {0x023b, 0x023c, 65535, 65535},
5874 {0x023d, 0x023d, 0, -163}, {0x023e, 0x023e, 0, 10792}, {0x023f, 0x0240, 10815, 0},
5875 {0x0241, 0x0242, 65535, 65535}, {0x0243, 0x0243, 0, -195}, {0x0244, 0x0244, 0, 69},
5876 {0x0245, 0x0245, 0, 71}, {0x0246, 0x024f, 65535, 65535}, {0x0250, 0x0250, 10783, 0},
5877 {0x0251, 0x0251, 10780, 0}, {0x0252, 0x0252, 10782, 0}, {0x0253, 0x0253, -210, 0},
5878 {0x0254, 0x0254, -206, 0}, {0x0256, 0x0257, -205, 0}, {0x0259, 0x0259, -202, 0},
5879 {0x025b, 0x025b, -203, 0}, {0x025c, 0x025c, 42319, 0}, {0x0260, 0x0260, -205, 0},
5880 {0x0261, 0x0261, 42315, 0}, {0x0263, 0x0263, -207, 0}, {0x0264, 0x0264, 42343, 0},
5881 {0x0265, 0x0265, 42280, 0}, {0x0266, 0x0266, 42308, 0}, {0x0268, 0x0268, -209, 0},
5882 {0x0269, 0x0269, -211, 0}, {0x026a, 0x026a, 42308, 0}, {0x026b, 0x026b, 10743, 0},
5883 {0x026c, 0x026c, 42305, 0}, {0x026f, 0x026f, -211, 0}, {0x0271, 0x0271, 10749, 0},
5884 {0x0272, 0x0272, -213, 0}, {0x0275, 0x0275, -214, 0}, {0x027d, 0x027d, 10727, 0},
5885 {0x0280, 0x0280, -218, 0}, {0x0282, 0x0282, 42307, 0}, {0x0283, 0x0283, -218, 0},
5886 {0x0287, 0x0287, 42282, 0}, {0x0288, 0x0288, -218, 0}, {0x0289, 0x0289, -69, 0},
5887 {0x028a, 0x028b, -217, 0}, {0x028c, 0x028c, -71, 0}, {0x0292, 0x0292, -219, 0},
5888 {0x029d, 0x029d, 42261, 0}, {0x029e, 0x029e, 42258, 0}, {0x0370, 0x0377, 65535, 65535},
5889 {0x037b, 0x037d, 130, 0}, {0x037f, 0x037f, 0, 116}, {0x0386, 0x0386, 0, 38},
5890 {0x0388, 0x038a, 0, 37}, {0x038c, 0x038c, 0, 64}, {0x038e, 0x038f, 0, 63},
5891 {0x0391, 0x03a1, 0, 32}, {0x03a3, 0x03ab, 0, 32}, {0x03ac, 0x03ac, -38, 0},
5892 {0x03ad, 0x03af, -37, 0}, {0x03b1, 0x03c1, -32, 0}, {0x03c2, 0x03c2, -31, 0},
5893 {0x03c3, 0x03cb, -32, 0}, {0x03cc, 0x03cc, -64, 0}, {0x03cd, 0x03ce, -63, 0},
5894 {0x03cf, 0x03cf, 0, 8}, {0x03d0, 0x03d0, -62, 0}, {0x03d1, 0x03d1, -57, 0},
5895 {0x03d5, 0x03d5, -47, 0}, {0x03d6, 0x03d6, -54, 0}, {0x03d7, 0x03d7, -8, 0},
5896 {0x03d8, 0x03ef, 65535, 65535}, {0x03f0, 0x03f0, -86, 0}, {0x03f1, 0x03f1, -80, 0},
5897 {0x03f2, 0x03f2, 7, 0}, {0x03f3, 0x03f3, -116, 0}, {0x03f4, 0x03f4, 0, -60},
5898 {0x03f5, 0x03f5, -96, 0}, {0x03f7, 0x03f8, 65535, 65535}, {0x03f9, 0x03f9, 0, -7},
5899 {0x03fa, 0x03fb, 65535, 65535}, {0x03fd, 0x03ff, 0, -130}, {0x0400, 0x040f, 0, 80},
5900 {0x0410, 0x042f, 0, 32}, {0x0430, 0x044f, -32, 0}, {0x0450, 0x045f, -80, 0},
5901 {0x0460, 0x04bf, 65535, 65535}, {0x04c0, 0x04c0, 0, 15}, {0x04c1, 0x04ce, 65535, 65535},
5902 {0x04cf, 0x04cf, -15, 0}, {0x04d0, 0x052f, 65535, 65535}, {0x0531, 0x0556, 0, 48},
5903 {0x0561, 0x0586, -48, 0}, {0x10a0, 0x10c5, 0, 7264}, {0x10c7, 0x10c7, 0, 7264},
5904 {0x10cd, 0x10cd, 0, 7264}, {0x10d0, 0x10fa, 3008, 0}, {0x10fd, 0x10ff, 3008, 0},
5905 {0x13a0, 0x13ef, 0, 38864}, {0x13f0, 0x13f5, 0, 8}, {0x13f8, 0x13fd, -8, 0},
5906 {0x1c80, 0x1c80, -6254, 0}, {0x1c81, 0x1c81, -6253, 0}, {0x1c82, 0x1c82, -6244, 0},
5907 {0x1c83, 0x1c84, -6242, 0}, {0x1c85, 0x1c85, -6243, 0}, {0x1c86, 0x1c86, -6236, 0},
5908 {0x1c87, 0x1c87, -6181, 0}, {0x1c88, 0x1c88, 35266, 0}, {0x1c89, 0x1c8a, 65535, 65535},
5909 {0x1c90, 0x1cba, 0, -3008}, {0x1cbd, 0x1cbf, 0, -3008}, {0x1d79, 0x1d79, 35332, 0},
5910 {0x1d7d, 0x1d7d, 3814, 0}, {0x1d8e, 0x1d8e, 35384, 0}, {0x1e00, 0x1e95, 65535, 65535},
5911 {0x1e9b, 0x1e9b, -59, 0}, {0x1e9e, 0x1e9e, 0, -7615}, {0x1ea0, 0x1eff, 65535, 65535},
5912 {0x1f00, 0x1f07, 8, 0}, {0x1f08, 0x1f0f, 0, -8}, {0x1f10, 0x1f15, 8, 0},
5913 {0x1f18, 0x1f1d, 0, -8}, {0x1f20, 0x1f27, 8, 0}, {0x1f28, 0x1f2f, 0, -8},
5914 {0x1f30, 0x1f37, 8, 0}, {0x1f38, 0x1f3f, 0, -8}, {0x1f40, 0x1f45, 8, 0},
5915 {0x1f48, 0x1f4d, 0, -8}, {0x1f51, 0x1f51, 8, 0}, {0x1f53, 0x1f53, 8, 0},
5916 {0x1f55, 0x1f55, 8, 0}, {0x1f57, 0x1f57, 8, 0}, {0x1f59, 0x1f59, 0, -8},
5917 {0x1f5b, 0x1f5b, 0, -8}, {0x1f5d, 0x1f5d, 0, -8}, {0x1f5f, 0x1f5f, 0, -8},
5918 {0x1f60, 0x1f67, 8, 0}, {0x1f68, 0x1f6f, 0, -8}, {0x1f70, 0x1f71, 74, 0},
5919 {0x1f72, 0x1f75, 86, 0}, {0x1f76, 0x1f77, 100, 0}, {0x1f78, 0x1f79, 128, 0},
5920 {0x1f7a, 0x1f7b, 112, 0}, {0x1f7c, 0x1f7d, 126, 0}, {0x1f80, 0x1f87, 8, 0},
5921 {0x1f90, 0x1f97, 8, 0}, {0x1fa0, 0x1fa7, 8, 0}, {0x1fb0, 0x1fb1, 8, 0},
5922 {0x1fb3, 0x1fb3, 9, 0}, {0x1fb8, 0x1fb9, 0, -8}, {0x1fba, 0x1fbb, 0, -74},
5923 {0x1fbe, 0x1fbe, -7205, 0}, {0x1fc3, 0x1fc3, 9, 0}, {0x1fc8, 0x1fcb, 0, -86},
5924 {0x1fd0, 0x1fd1, 8, 0}, {0x1fd8, 0x1fd9, 0, -8}, {0x1fda, 0x1fdb, 0, -100},
5925 {0x1fe0, 0x1fe1, 8, 0}, {0x1fe5, 0x1fe5, 7, 0}, {0x1fe8, 0x1fe9, 0, -8},
5926 {0x1fea, 0x1feb, 0, -112}, {0x1fec, 0x1fec, 0, -7}, {0x1ff3, 0x1ff3, 9, 0},
5927 {0x1ff8, 0x1ff9, 0, -128}, {0x1ffa, 0x1ffb, 0, -126}, {0x2126, 0x2126, 0, -7517},
5928 {0x212a, 0x212a, 0, -8383}, {0x212b, 0x212b, 0, -8262}, {0x2132, 0x2132, 0, 28},
5929 {0x214e, 0x214e, -28, 0}, {0x2183, 0x2184, 65535, 65535}, {0x2c00, 0x2c2f, 0, 48},
5930 {0x2c30, 0x2c5f, -48, 0}, {0x2c60, 0x2c61, 65535, 65535}, {0x2c62, 0x2c62, 0, -10743},
5931 {0x2c63, 0x2c63, 0, -3814}, {0x2c64, 0x2c64, 0, -10727}, {0x2c65, 0x2c65, -10795, 0},
5932 {0x2c66, 0x2c66, -10792, 0}, {0x2c67, 0x2c6c, 65535, 65535}, {0x2c6d, 0x2c6d, 0, -10780},
5933 {0x2c6e, 0x2c6e, 0, -10749}, {0x2c6f, 0x2c6f, 0, -10783}, {0x2c70, 0x2c70, 0, -10782},
5934 {0x2c72, 0x2c76, 65535, 65535}, {0x2c7e, 0x2c7f, 0, -10815}, {0x2c80, 0x2cf3, 65535, 65535},
5935 {0x2d00, 0x2d25, -7264, 0}, {0x2d27, 0x2d27, -7264, 0}, {0x2d2d, 0x2d2d, -7264, 0},
5936 {0xa640, 0xa77c, 65535, 65535}, {0xa77d, 0xa77d, 0, -35332}, {0xa77e, 0xa78c, 65535, 65535},
5937 {0xa78d, 0xa78d, 0, -42280}, {0xa790, 0xa793, 65535, 65535}, {0xa794, 0xa794, 48, 0},
5938 {0xa796, 0xa7a9, 65535, 65535}, {0xa7aa, 0xa7aa, 0, -42308}, {0xa7ab, 0xa7ab, 0, -42319},
5939 {0xa7ac, 0xa7ac, 0, -42315}, {0xa7ad, 0xa7ad, 0, -42305}, {0xa7ae, 0xa7ae, 0, -42308},
5940 {0xa7b0, 0xa7b0, 0, -42258}, {0xa7b1, 0xa7b1, 0, -42282}, {0xa7b2, 0xa7b2, 0, -42261},
5941 {0xa7b3, 0xa7b3, 0, 928}, {0xa7b4, 0xa7c3, 65535, 65535}, {0xa7c4, 0xa7c4, 0, -48},
5942 {0xa7c5, 0xa7c5, 0, -42307}, {0xa7c6, 0xa7c6, 0, -35384}, {0xa7c7, 0xa7ca, 65535, 65535},
5943 {0xa7cb, 0xa7cb, 0, -42343}, {0xa7cc, 0xa7db, 65535, 65535}, {0xa7dc, 0xa7dc, 0, -42561},
5944 {0xa7f5, 0xa7f6, 65535, 65535}, {0xab53, 0xab53, -928, 0}, {0xab70, 0xabbf, -38864, 0},
5945 {0xff21, 0xff3a, 0, 32}, {0xff41, 0xff5a, -32, 0}
5946};
5947
5948
5949//
5950// case32
5951//
5952
5953#if defined(IMGUI_USE_WCHAR32)
5954
5955static CaseRange32 case32[] = {
5956 {0x10400, 0x10427, 0, 40}, {0x10428, 0x1044f, -40, 0}, {0x104b0, 0x104d3, 0, 40}, {0x104d8, 0x104fb, -40, 0},
5957 {0x10570, 0x1057a, 0, 39}, {0x1057c, 0x1058a, 0, 39}, {0x1058c, 0x10592, 0, 39}, {0x10594, 0x10595, 0, 39},
5958 {0x10597, 0x105a1, -39, 0}, {0x105a3, 0x105b1, -39, 0}, {0x105b3, 0x105b9, -39, 0}, {0x105bb, 0x105bc, -39, 0},
5959 {0x10c80, 0x10cb2, 0, 64}, {0x10cc0, 0x10cf2, -64, 0}, {0x10d50, 0x10d65, 0, 32}, {0x10d70, 0x10d85, -32, 0},
5960 {0x118a0, 0x118bf, 0, 32}, {0x118c0, 0x118df, -32, 0}, {0x16e40, 0x16e5f, 0, 32}, {0x16e60, 0x16e7f, -32, 0},
5961 {0x16ea0, 0x16eb8, 0, 27}, {0x16ebb, 0x16ed3, -27, 0}, {0x1e900, 0x1e921, 0, 34}, {0x1e922, 0x1e943, -34, 0}
5962};
5963
5964#endif
5965
5966
5967//
5968// rangeContains
5969//
5970
5971template <typename T, typename C>
5972bool rangeContains(const T& table, C codepoint) {
5973 auto low = std::begin(table);
5974 auto high = std::end(table);
5975
5976 while (low <= high) {
5977 auto mid = low + (high - low) / 2;
5978
5979 if (codepoint >= mid->low && codepoint <= mid->high) {
5980 return (mid->stride == 1) || ((codepoint - mid->low) % mid->stride == 0);
5981
5982 } else if (codepoint < mid->low) {
5983 high = mid - 1;
5984
5985 } else {
5986 low = mid + 1;
5987 }
5988 }
5989
5990 return false;
5991}
5992
5993
5994//
5995// caseRangeFind
5996//
5997
5998template <typename T, typename C>
5999const CaseRange<C>* caseRangeFind(const T& table, C codepoint) {
6000 auto low = std::begin(table);
6001 auto high = std::end(table);
6002
6003 while (low <= high) {
6004 auto mid = low + (high - low) / 2;
6005
6006 if (codepoint >= mid->low && codepoint <= mid->high) {
6007 return mid;
6008
6009 } else if (codepoint < mid->low) {
6010 high = mid - 1;
6011
6012 } else {
6013 low = mid + 1;
6014 }
6015 }
6016
6017 return nullptr;
6018}
6019
6020
6021//
6022// caseRangeToUpper
6023//
6024
6025template <typename T, typename C>
6026C caseRangeToUpper(const T& table, C codepoint) {
6027 auto caseRange = caseRangeFind(table, codepoint);
6028
6029 if (!caseRange || caseRange->toUpper == 0) {
6030 return codepoint;
6031
6032 } else if (caseRange->toUpper == 0xffff) {
6033 return codepoint & ~0x1;
6034 }
6035
6036 else {
6037 return static_cast<C>(static_cast<int32_t>(codepoint) + caseRange->toUpper);
6038 }
6039}
6040
6041
6042//
6043// caseRangeToLower
6044//
6045
6046template <typename T, typename C>
6047C caseRangeToLower(const T& table, C codepoint) {
6048 auto caseRange = caseRangeFind(table, codepoint);
6049
6050 if (!caseRange || caseRange->toLower == 0) {
6051 return codepoint;
6052
6053 } else if (caseRange->toLower == 0xffff) {
6054 return codepoint | 0x1;
6055 }
6056
6057 else {
6058 return static_cast<C>(static_cast<int32_t>(codepoint) + caseRange->toLower);
6059 }
6060}
6061
6062
6063//
6064// Internal type conversions because "char" is signed
6065//
6066
6067static inline ImWchar uch(char c) {
6068 return static_cast<ImWchar>(c);
6069}
6070
6071static inline char sch(ImWchar i) {
6072 return static_cast<char>(i);
6073}
6074
6075
6076//
6077// skipBOM
6078//
6079
6080std::string_view::const_iterator TextEditor::CodePoint::skipBOM(std::string_view::const_iterator i, std::string_view::const_iterator end) {
6081 // skip Byte Order Mark (BOM) just in case there is one
6082
6083 // Note: the standard states that:
6084 // Use of a BOM is neither required nor recommended for UTF-8
6085 static constexpr char bom1 = static_cast<char>(0xEF);
6086 static constexpr char bom2 = static_cast<char>(0xBB);
6087 static constexpr char bom3 = static_cast<char>(0xBF);
6088 return ((end - i) >= 3 && i[0] == bom1 && i[1] == bom2 && i[2] == bom3) ? i + 3 : i;
6089}
6090
6091
6092//
6093// TextEditor::CodePoint::read
6094//
6095
6096std::string_view::const_iterator TextEditor::CodePoint::read(std::string_view::const_iterator i, std::string_view::const_iterator end, ImWchar *codepoint) {
6097 // parse a UTF-8 sequence into a unicode codepoint
6098 if (i < end && (uch(*i) & 0x80) == 0) {
6099 *codepoint = uch(*i);
6100 i++;
6101
6102 } else if (i + 1 < end && (uch(*i) & 0xE0) == 0xC0) {
6103 *codepoint = ((uch(*i) & 0x1f) << 6) | (uch(*(i + 1)) & 0x3f);
6104 i += 2;
6105
6106 } else if (i + 2 < end && (uch(*i) & 0xF0) == 0xE0) {
6107 *codepoint = ((uch(*i) & 0x0f) << 12) | ((uch(*(i + 1)) & 0x3f) << 6) | (uch(*(i + 2)) & 0x3f);
6108 i += 3;
6109
6110 } else if (i + 3 < end && (uch(*i) & 0xF8) == 0xF0) {
6111#if defined(IMGUI_USE_WCHAR32)
6112 *codepoint = ((uch(*i) & 0x07) << 18) | ((uch(*(i + 1)) & 0x3f) << 12) | ((uch(*(i + 2)) & 0x3f) << 6) | (uch(*(i + 3)) & 0x3f);
6113#else
6114 *codepoint = IM_UNICODE_CODEPOINT_INVALID;
6115#endif
6116 i += 4;
6117
6118 } else {
6119 *codepoint = IM_UNICODE_CODEPOINT_INVALID;
6120 i++;
6121 }
6122
6123 return i;
6124}
6125
6126
6127//
6128// TextEditor::CodePoint::write
6129//
6130
6131size_t TextEditor::CodePoint::write(char* start, ImWchar codepoint) {
6132 // generate UTF-8 sequence from a unicode codepoint
6133 auto i = start;
6134
6135 if (codepoint < 0x80) {
6136 *i++ = sch(codepoint);
6137
6138 } else if (codepoint < 0x800) {
6139 *i++ = sch(0xc0 | ((codepoint >> 6) & 0x1f));
6140 *i++ = sch(0x80 | (codepoint & 0x3f));
6141
6142#if defined(IMGUI_USE_WCHAR32)
6143 } else if (codepoint < 0x10000) {
6144 *i++ = sch(0xe0 | ((codepoint >> 12) & 0x0f));
6145 *i++ = sch(0x80 | ((codepoint >> 6) & 0x3f));
6146 *i++ = sch(0x80 | (codepoint & 0x3f));
6147
6148 } else if (codepoint >= 0x110000) {
6149 codepoint = IM_UNICODE_CODEPOINT_INVALID;
6150 *i++ = sch(0xe0 | ((codepoint >> 12) & 0x0f));
6151 *i++ = sch(0x80 | ((codepoint >> 6) & 0x3f));
6152 *i++ = sch(0x80 | (codepoint & 0x3f));
6153
6154 } else {
6155 *i++ = sch(0xf0 | ((codepoint >> 18) & 0x07));
6156 *i++ = sch(0x80 | ((codepoint >> 12) & 0x3f));
6157 *i++ = sch(0x80 | ((codepoint >> 6) & 0x3f));
6158 *i++ = sch(0x80 | (codepoint & 0x3f));
6159
6160#else
6161 } else {
6162 *i++ = sch(0xe0 | ((codepoint >> 12) & 0x0f));
6163 *i++ = sch(0x80 | ((codepoint >> 6) & 0x3f));
6164 *i++ = sch(0x80 | (codepoint & 0x3f));
6165#endif
6166 }
6167
6168 return i - start;
6169}
6170
6171
6172//
6173// TextEditor::CodePoint::isLetter
6174//
6175
6176bool TextEditor::CodePoint::isLetter(ImWchar codepoint) {
6177 if (codepoint < 0x7f) {
6178 return static_cast<unsigned>((codepoint | 32) - 'a') < 26;
6179
6180#if defined(IMGUI_USE_WCHAR32)
6181 } else if (codepoint >= 0x10000) {
6182 return rangeContains(letters32, static_cast<ImWchar32>(codepoint));
6183#endif
6184
6185 } else {
6186 return rangeContains(letters16, static_cast<ImWchar16>(codepoint));
6187 }
6188}
6189
6190
6191//
6192// TextEditor::CodePoint::isNumber
6193//
6194
6195bool TextEditor::CodePoint::isNumber(ImWchar codepoint) {
6196 if (codepoint < 0x7f) {
6197 return static_cast<unsigned>(codepoint - '0') < 10;
6198
6199#if defined(IMGUI_USE_WCHAR32)
6200 } else if (codepoint >= 0x10000) {
6201 return rangeContains(numbers32, static_cast<ImWchar32>(codepoint));
6202#endif
6203
6204 } else {
6205 return rangeContains(numbers16, static_cast<ImWchar16>(codepoint));
6206 }
6207}
6208
6209
6210//
6211// TextEditor::CodePoint::isXidStart
6212//
6213
6214bool TextEditor::CodePoint::isXidStart(ImWchar codepoint) {
6215 if (codepoint < 0x7f) {
6216 return codepoint == '_' || static_cast<unsigned>((codepoint | 32) - 'a') < 26;
6217
6218#if defined(IMGUI_USE_WCHAR32)
6219 } else if (codepoint >= 0x10000) {
6220 return rangeContains(xidStart32, static_cast<ImWchar32>(codepoint));
6221#endif
6222
6223 } else {
6224 return rangeContains(xidStart16, static_cast<ImWchar16>(codepoint));
6225 }
6226}
6227
6228
6229//
6230// TextEditor::CodePoint::isWhiteSpace
6231//
6232
6233bool TextEditor::CodePoint::isWhiteSpace(ImWchar codepoint) {
6234 if (codepoint < 0x7f) {
6235 return codepoint == ' ' || static_cast<unsigned>(codepoint - '\t') < 5;
6236
6237#if defined(IMGUI_USE_WCHAR32)
6238 } else if (codepoint >= 0x10000) {
6239 return false;
6240#endif
6241
6242 } else {
6243 return rangeContains(whitespace16, static_cast<ImWchar16>(codepoint));
6244 }
6245}
6246
6247
6248//
6249// TextEditor::CodePoint::isWord
6250//
6251
6252bool TextEditor::CodePoint::isWord(ImWchar codepoint) {
6253 if (codepoint < 0x7f) {
6254 return
6255 (static_cast<unsigned>((codepoint | 32) - 'a') < 26) ||
6256 (static_cast<unsigned>(codepoint - '0') < 10) ||
6257 codepoint == '_';
6258
6259#if defined(IMGUI_USE_WCHAR32)
6260 } else if (codepoint >= 0x10000) {
6261 return
6262 rangeContains(letters32, static_cast<ImWchar32>(codepoint)) ||
6263 rangeContains(numbers32, static_cast<ImWchar32>(codepoint)) ||
6264 codepoint == '_';
6265#endif
6266
6267 } else {
6268 return
6269 rangeContains(letters16, static_cast<ImWchar16>(codepoint)) ||
6270 rangeContains(numbers16, static_cast<ImWchar16>(codepoint)) ||
6271 codepoint == '_';
6272 }
6273}
6274
6275
6276//
6277// TextEditor::CodePoint::isXidContinue
6278//
6279
6280bool TextEditor::CodePoint::isXidContinue(ImWchar codepoint) {
6281 if (codepoint < 0x7f) {
6282 return codepoint == '_' || (static_cast<unsigned>((codepoint | 32) - 'a') < 26) || (static_cast<unsigned>(codepoint - '0') < 10);
6283
6284#if defined(IMGUI_USE_WCHAR32)
6285 } else if (codepoint >= 0x10000) {
6286 return rangeContains(xidContinue32, static_cast<ImWchar16>(codepoint));
6287#endif
6288
6289 } else {
6290 return rangeContains(xidContinue16, static_cast<ImWchar16>(codepoint));
6291 }
6292}
6293
6294
6295//
6296// TextEditor::CodePoint::isLower
6297//
6298
6299bool TextEditor::CodePoint::isLower(ImWchar codepoint) {
6300 if (codepoint < 0x7f) {
6301 return static_cast<unsigned>(codepoint - 'a') < 26;
6302
6303#if defined(IMGUI_USE_WCHAR32)
6304 } else if (codepoint >= 0x10000) {
6305 return rangeContains(lower32, static_cast<ImWchar32>(codepoint));
6306#endif
6307
6308 } else {
6309 return rangeContains(lower16, static_cast<ImWchar16>(codepoint));
6310 }
6311}
6312
6313
6314//
6315// TextEditor::CodePoint::isUpper
6316//
6317
6318bool TextEditor::CodePoint::isUpper(ImWchar codepoint) {
6319 if (codepoint < 0x7f) {
6320 return static_cast<unsigned>(codepoint - 'A') < 26;
6321
6322#if defined(IMGUI_USE_WCHAR32)
6323 } else if (codepoint >= 0x10000) {
6324 return rangeContains(upper32, static_cast<ImWchar32>(codepoint));
6325#endif
6326
6327 } else {
6328 return rangeContains(upper16, static_cast<ImWchar16>(codepoint));
6329 }
6330}
6331
6332
6333//
6334// TextEditor::CodePoint::toUpper
6335//
6336
6337ImWchar TextEditor::CodePoint::toUpper(ImWchar codepoint) {
6338 if (codepoint < 0x7f) {
6339 return (static_cast<unsigned>(codepoint - 'a') < 26) ? codepoint & 0x5f : codepoint;
6340
6341#if defined(IMGUI_USE_WCHAR32)
6342 } else if (codepoint >= 0x10000) {
6343 return caseRangeToUpper(case32, static_cast<char32_t>(codepoint));
6344#endif
6345
6346 } else {
6347 return caseRangeToUpper(case16, static_cast<char16_t>(codepoint));
6348 }
6349}
6350
6351
6352//
6353// TextEditor::CodePoint::toLower
6354//
6355
6356ImWchar TextEditor::CodePoint::toLower(ImWchar codepoint) {
6357 if (codepoint < 0x7f) {
6358 return (static_cast<unsigned>(codepoint - 'A') < 26) ? codepoint | 32 : codepoint;
6359
6360#if defined(IMGUI_USE_WCHAR32)
6361 } else if (codepoint >= 0x10000) {
6362 return caseRangeToLower(case32, static_cast<char32_t>(codepoint));
6363#endif
6364
6365 } else {
6366 return caseRangeToLower(case16, static_cast<char16_t>(codepoint));
6367 }
6368}
6369
6370
6371//
6372// getCStyleIdentifier
6373//
6374
6375static TextEditor::Iterator getCStyleIdentifier(TextEditor::Iterator start, TextEditor::Iterator end) {
6376 if (start < end && TextEditor::CodePoint::isXidStart(*start)) {
6377 start++;
6378
6379 while (start < end && TextEditor::CodePoint::isXidContinue(*start)) {
6380 start++;
6381 }
6382 }
6383
6384 return start;
6385}
6386
6387
6388//
6389// getCStyleNumber
6390//
6391
6392static TextEditor::Iterator getCStyleNumber(TextEditor::Iterator start, TextEditor::Iterator end) {
6393 TextEditor::Iterator i = start;
6394 TextEditor::Iterator marker;
6395
6396
6397{
6398 ImWchar yych;
6399 unsigned int yyaccept = 0;
6400 yych = i < end ? *i : 0;
6401 switch (yych) {
6402 case '.': goto yy3;
6403 case '0': goto yy4;
6404 case '1':
6405 case '2':
6406 case '3':
6407 case '4':
6408 case '5':
6409 case '6':
6410 case '7':
6411 case '8':
6412 case '9': goto yy6;
6413 default:
6414 if (i >= end) goto yy82;
6415 goto yy1;
6416 }
6417yy1:
6418 ++i;
6419yy2:
6420 { return start; }
6421yy3:
6422 ++i;
6423 yych = i < end ? *i : 0;
6424 switch (yych) {
6425 case '0':
6426 case '1':
6427 case '2':
6428 case '3':
6429 case '4':
6430 case '5':
6431 case '6':
6432 case '7':
6433 case '8':
6434 case '9': goto yy8;
6435 default: goto yy2;
6436 }
6437yy4:
6438 yyaccept = 0;
6439 ++i;
6440 marker = i;
6441 yych = i < end ? *i : 0;
6442 switch (yych) {
6443 case 0x00: goto yy5;
6444 case 'B':
6445 case 'b': goto yy16;
6446 case 'X':
6447 case 'x': goto yy20;
6448 default: goto yy13;
6449 }
6450yy5:
6451 { return i; }
6452yy6:
6453 yyaccept = 1;
6454 ++i;
6455 marker = i;
6456 yych = i < end ? *i : 0;
6457 switch (yych) {
6458 case '.': goto yy10;
6459 case '0':
6460 case '1':
6461 case '2':
6462 case '3':
6463 case '4':
6464 case '5':
6465 case '6':
6466 case '7':
6467 case '8':
6468 case '9': goto yy6;
6469 case 'E':
6470 case 'e': goto yy17;
6471 case 'L': goto yy22;
6472 case 'U':
6473 case 'u': goto yy23;
6474 case 'l': goto yy24;
6475 default: goto yy7;
6476 }
6477yy7:
6478 { return i; }
6479yy8:
6480 yyaccept = 2;
6481 ++i;
6482 marker = i;
6483 yych = i < end ? *i : 0;
6484 switch (yych) {
6485 case '0':
6486 case '1':
6487 case '2':
6488 case '3':
6489 case '4':
6490 case '5':
6491 case '6':
6492 case '7':
6493 case '8':
6494 case '9': goto yy8;
6495 case 'E':
6496 case 'e': goto yy25;
6497 case 'F':
6498 case 'L':
6499 case 'f':
6500 case 'l': goto yy26;
6501 default: goto yy9;
6502 }
6503yy9:
6504 { return i; }
6505yy10:
6506 yyaccept = 3;
6507 ++i;
6508 marker = i;
6509 yych = i < end ? *i : 0;
6510 switch (yych) {
6511 case '0':
6512 case '1':
6513 case '2':
6514 case '3':
6515 case '4':
6516 case '5':
6517 case '6':
6518 case '7':
6519 case '8':
6520 case '9': goto yy8;
6521 case 'E':
6522 case 'e': goto yy27;
6523 case 'F':
6524 case 'L':
6525 case 'f':
6526 case 'l': goto yy28;
6527 default: goto yy11;
6528 }
6529yy11:
6530 { return i; }
6531yy12:
6532 yyaccept = 0;
6533 ++i;
6534 marker = i;
6535 yych = i < end ? *i : 0;
6536yy13:
6537 switch (yych) {
6538 case '.': goto yy10;
6539 case '0':
6540 case '1':
6541 case '2':
6542 case '3':
6543 case '4':
6544 case '5':
6545 case '6':
6546 case '7': goto yy12;
6547 case '8':
6548 case '9': goto yy14;
6549 case 'E':
6550 case 'e': goto yy17;
6551 case 'L': goto yy18;
6552 case 'U':
6553 case 'u': goto yy19;
6554 case 'l': goto yy21;
6555 default: goto yy5;
6556 }
6557yy14:
6558 ++i;
6559 yych = i < end ? *i : 0;
6560 switch (yych) {
6561 case '.': goto yy10;
6562 case '0':
6563 case '1':
6564 case '2':
6565 case '3':
6566 case '4':
6567 case '5':
6568 case '6':
6569 case '7':
6570 case '8':
6571 case '9': goto yy14;
6572 case 'E':
6573 case 'e': goto yy17;
6574 default: goto yy15;
6575 }
6576yy15:
6577 i = marker;
6578 switch (yyaccept) {
6579 case 0: goto yy5;
6580 case 1: goto yy7;
6581 case 2: goto yy9;
6582 case 3: goto yy11;
6583 default: goto yy40;
6584 }
6585yy16:
6586 ++i;
6587 yych = i < end ? *i : 0;
6588 switch (yych) {
6589 case '0':
6590 case '1': goto yy29;
6591 default: goto yy15;
6592 }
6593yy17:
6594 ++i;
6595 yych = i < end ? *i : 0;
6596 switch (yych) {
6597 case '+':
6598 case '-': goto yy31;
6599 case '0':
6600 case '1':
6601 case '2':
6602 case '3':
6603 case '4':
6604 case '5':
6605 case '6':
6606 case '7':
6607 case '8':
6608 case '9': goto yy32;
6609 default: goto yy15;
6610 }
6611yy18:
6612 ++i;
6613 yych = i < end ? *i : 0;
6614 switch (yych) {
6615 case 'L': goto yy34;
6616 case 'U':
6617 case 'u': goto yy35;
6618 default: goto yy5;
6619 }
6620yy19:
6621 ++i;
6622 yych = i < end ? *i : 0;
6623 switch (yych) {
6624 case 'L': goto yy36;
6625 case 'l': goto yy37;
6626 default: goto yy5;
6627 }
6628yy20:
6629 ++i;
6630 yych = i < end ? *i : 0;
6631 switch (yych) {
6632 case '.': goto yy38;
6633 case '0':
6634 case '1':
6635 case '2':
6636 case '3':
6637 case '4':
6638 case '5':
6639 case '6':
6640 case '7':
6641 case '8':
6642 case '9':
6643 case 'A':
6644 case 'B':
6645 case 'C':
6646 case 'D':
6647 case 'E':
6648 case 'F':
6649 case 'a':
6650 case 'b':
6651 case 'c':
6652 case 'd':
6653 case 'e':
6654 case 'f': goto yy39;
6655 default: goto yy15;
6656 }
6657yy21:
6658 ++i;
6659 yych = i < end ? *i : 0;
6660 switch (yych) {
6661 case 'U':
6662 case 'u': goto yy35;
6663 case 'l': goto yy34;
6664 default: goto yy5;
6665 }
6666yy22:
6667 ++i;
6668 yych = i < end ? *i : 0;
6669 switch (yych) {
6670 case 'L': goto yy41;
6671 case 'U':
6672 case 'u': goto yy42;
6673 default: goto yy7;
6674 }
6675yy23:
6676 ++i;
6677 yych = i < end ? *i : 0;
6678 switch (yych) {
6679 case 'L': goto yy43;
6680 case 'l': goto yy44;
6681 default: goto yy7;
6682 }
6683yy24:
6684 ++i;
6685 yych = i < end ? *i : 0;
6686 switch (yych) {
6687 case 'U':
6688 case 'u': goto yy42;
6689 case 'l': goto yy41;
6690 default: goto yy7;
6691 }
6692yy25:
6693 ++i;
6694 yych = i < end ? *i : 0;
6695 switch (yych) {
6696 case '+':
6697 case '-': goto yy45;
6698 case '0':
6699 case '1':
6700 case '2':
6701 case '3':
6702 case '4':
6703 case '5':
6704 case '6':
6705 case '7':
6706 case '8':
6707 case '9': goto yy46;
6708 default: goto yy15;
6709 }
6710yy26:
6711 ++i;
6712 goto yy9;
6713yy27:
6714 ++i;
6715 yych = i < end ? *i : 0;
6716 switch (yych) {
6717 case '+':
6718 case '-': goto yy47;
6719 case '0':
6720 case '1':
6721 case '2':
6722 case '3':
6723 case '4':
6724 case '5':
6725 case '6':
6726 case '7':
6727 case '8':
6728 case '9': goto yy48;
6729 default: goto yy15;
6730 }
6731yy28:
6732 ++i;
6733 goto yy11;
6734yy29:
6735 ++i;
6736 yych = i < end ? *i : 0;
6737 switch (yych) {
6738 case '0':
6739 case '1': goto yy29;
6740 case 'L': goto yy49;
6741 case 'U':
6742 case 'u': goto yy50;
6743 case 'l': goto yy51;
6744 default: goto yy30;
6745 }
6746yy30:
6747 { return i; }
6748yy31:
6749 ++i;
6750 yych = i < end ? *i : 0;
6751 switch (yych) {
6752 case '0':
6753 case '1':
6754 case '2':
6755 case '3':
6756 case '4':
6757 case '5':
6758 case '6':
6759 case '7':
6760 case '8':
6761 case '9': goto yy32;
6762 default: goto yy15;
6763 }
6764yy32:
6765 ++i;
6766 yych = i < end ? *i : 0;
6767 switch (yych) {
6768 case '0':
6769 case '1':
6770 case '2':
6771 case '3':
6772 case '4':
6773 case '5':
6774 case '6':
6775 case '7':
6776 case '8':
6777 case '9': goto yy32;
6778 case 'F':
6779 case 'L':
6780 case 'f':
6781 case 'l': goto yy52;
6782 default: goto yy33;
6783 }
6784yy33:
6785 { return i; }
6786yy34:
6787 ++i;
6788 yych = i < end ? *i : 0;
6789 switch (yych) {
6790 case 'U':
6791 case 'u': goto yy35;
6792 default: goto yy5;
6793 }
6794yy35:
6795 ++i;
6796 goto yy5;
6797yy36:
6798 ++i;
6799 yych = i < end ? *i : 0;
6800 switch (yych) {
6801 case 'L': goto yy35;
6802 default: goto yy5;
6803 }
6804yy37:
6805 ++i;
6806 yych = i < end ? *i : 0;
6807 switch (yych) {
6808 case 'l': goto yy35;
6809 default: goto yy5;
6810 }
6811yy38:
6812 ++i;
6813 yych = i < end ? *i : 0;
6814 switch (yych) {
6815 case 0x00:
6816 case 'P':
6817 case 'p': goto yy15;
6818 default: goto yy54;
6819 }
6820yy39:
6821 yyaccept = 4;
6822 ++i;
6823 marker = i;
6824 yych = i < end ? *i : 0;
6825 switch (yych) {
6826 case '.': goto yy55;
6827 case '0':
6828 case '1':
6829 case '2':
6830 case '3':
6831 case '4':
6832 case '5':
6833 case '6':
6834 case '7':
6835 case '8':
6836 case '9':
6837 case 'A':
6838 case 'B':
6839 case 'C':
6840 case 'D':
6841 case 'E':
6842 case 'F':
6843 case 'a':
6844 case 'b':
6845 case 'c':
6846 case 'd':
6847 case 'e':
6848 case 'f': goto yy39;
6849 case 'L': goto yy56;
6850 case 'P':
6851 case 'p': goto yy57;
6852 case 'U':
6853 case 'u': goto yy58;
6854 case 'l': goto yy59;
6855 default: goto yy40;
6856 }
6857yy40:
6858 { return i; }
6859yy41:
6860 ++i;
6861 yych = i < end ? *i : 0;
6862 switch (yych) {
6863 case 'U':
6864 case 'u': goto yy42;
6865 default: goto yy7;
6866 }
6867yy42:
6868 ++i;
6869 goto yy7;
6870yy43:
6871 ++i;
6872 yych = i < end ? *i : 0;
6873 switch (yych) {
6874 case 'L': goto yy42;
6875 default: goto yy7;
6876 }
6877yy44:
6878 ++i;
6879 yych = i < end ? *i : 0;
6880 switch (yych) {
6881 case 'l': goto yy42;
6882 default: goto yy7;
6883 }
6884yy45:
6885 ++i;
6886 yych = i < end ? *i : 0;
6887 switch (yych) {
6888 case '0':
6889 case '1':
6890 case '2':
6891 case '3':
6892 case '4':
6893 case '5':
6894 case '6':
6895 case '7':
6896 case '8':
6897 case '9': goto yy46;
6898 default: goto yy15;
6899 }
6900yy46:
6901 ++i;
6902 yych = i < end ? *i : 0;
6903 switch (yych) {
6904 case '0':
6905 case '1':
6906 case '2':
6907 case '3':
6908 case '4':
6909 case '5':
6910 case '6':
6911 case '7':
6912 case '8':
6913 case '9': goto yy46;
6914 case 'F':
6915 case 'L':
6916 case 'f':
6917 case 'l': goto yy26;
6918 default: goto yy9;
6919 }
6920yy47:
6921 ++i;
6922 yych = i < end ? *i : 0;
6923 switch (yych) {
6924 case '0':
6925 case '1':
6926 case '2':
6927 case '3':
6928 case '4':
6929 case '5':
6930 case '6':
6931 case '7':
6932 case '8':
6933 case '9': goto yy48;
6934 default: goto yy15;
6935 }
6936yy48:
6937 ++i;
6938 yych = i < end ? *i : 0;
6939 switch (yych) {
6940 case '0':
6941 case '1':
6942 case '2':
6943 case '3':
6944 case '4':
6945 case '5':
6946 case '6':
6947 case '7':
6948 case '8':
6949 case '9': goto yy48;
6950 case 'F':
6951 case 'L':
6952 case 'f':
6953 case 'l': goto yy28;
6954 default: goto yy11;
6955 }
6956yy49:
6957 ++i;
6958 yych = i < end ? *i : 0;
6959 switch (yych) {
6960 case 'L': goto yy60;
6961 case 'U':
6962 case 'u': goto yy61;
6963 default: goto yy30;
6964 }
6965yy50:
6966 ++i;
6967 yych = i < end ? *i : 0;
6968 switch (yych) {
6969 case 'L': goto yy62;
6970 case 'l': goto yy63;
6971 default: goto yy30;
6972 }
6973yy51:
6974 ++i;
6975 yych = i < end ? *i : 0;
6976 switch (yych) {
6977 case 'U':
6978 case 'u': goto yy61;
6979 case 'l': goto yy60;
6980 default: goto yy30;
6981 }
6982yy52:
6983 ++i;
6984 goto yy33;
6985yy53:
6986 ++i;
6987 yych = i < end ? *i : 0;
6988yy54:
6989 switch (yych) {
6990 case '0':
6991 case '1':
6992 case '2':
6993 case '3':
6994 case '4':
6995 case '5':
6996 case '6':
6997 case '7':
6998 case '8':
6999 case '9':
7000 case 'A':
7001 case 'B':
7002 case 'C':
7003 case 'D':
7004 case 'E':
7005 case 'F':
7006 case 'a':
7007 case 'b':
7008 case 'c':
7009 case 'd':
7010 case 'e':
7011 case 'f': goto yy53;
7012 case 'P':
7013 case 'p': goto yy64;
7014 default: goto yy15;
7015 }
7016yy55:
7017 ++i;
7018 yych = i < end ? *i : 0;
7019 switch (yych) {
7020 case 0x00: goto yy15;
7021 case 'P':
7022 case 'p': goto yy65;
7023 default: goto yy54;
7024 }
7025yy56:
7026 ++i;
7027 yych = i < end ? *i : 0;
7028 switch (yych) {
7029 case 'L': goto yy66;
7030 case 'U':
7031 case 'u': goto yy67;
7032 default: goto yy40;
7033 }
7034yy57:
7035 ++i;
7036 yych = i < end ? *i : 0;
7037 switch (yych) {
7038 case '+':
7039 case '-': goto yy68;
7040 case '0':
7041 case '1':
7042 case '2':
7043 case '3':
7044 case '4':
7045 case '5':
7046 case '6':
7047 case '7':
7048 case '8':
7049 case '9': goto yy69;
7050 default: goto yy15;
7051 }
7052yy58:
7053 ++i;
7054 yych = i < end ? *i : 0;
7055 switch (yych) {
7056 case 'L': goto yy71;
7057 case 'l': goto yy72;
7058 default: goto yy40;
7059 }
7060yy59:
7061 ++i;
7062 yych = i < end ? *i : 0;
7063 switch (yych) {
7064 case 'U':
7065 case 'u': goto yy67;
7066 case 'l': goto yy66;
7067 default: goto yy40;
7068 }
7069yy60:
7070 ++i;
7071 yych = i < end ? *i : 0;
7072 switch (yych) {
7073 case 'U':
7074 case 'u': goto yy61;
7075 default: goto yy30;
7076 }
7077yy61:
7078 ++i;
7079 goto yy30;
7080yy62:
7081 ++i;
7082 yych = i < end ? *i : 0;
7083 switch (yych) {
7084 case 'L': goto yy61;
7085 default: goto yy30;
7086 }
7087yy63:
7088 ++i;
7089 yych = i < end ? *i : 0;
7090 switch (yych) {
7091 case 'l': goto yy61;
7092 default: goto yy30;
7093 }
7094yy64:
7095 ++i;
7096 yych = i < end ? *i : 0;
7097 switch (yych) {
7098 case '+':
7099 case '-': goto yy73;
7100 case '0':
7101 case '1':
7102 case '2':
7103 case '3':
7104 case '4':
7105 case '5':
7106 case '6':
7107 case '7':
7108 case '8':
7109 case '9': goto yy74;
7110 default: goto yy15;
7111 }
7112yy65:
7113 ++i;
7114 yych = i < end ? *i : 0;
7115 switch (yych) {
7116 case '+':
7117 case '-': goto yy76;
7118 case '0':
7119 case '1':
7120 case '2':
7121 case '3':
7122 case '4':
7123 case '5':
7124 case '6':
7125 case '7':
7126 case '8':
7127 case '9': goto yy77;
7128 default: goto yy15;
7129 }
7130yy66:
7131 ++i;
7132 yych = i < end ? *i : 0;
7133 switch (yych) {
7134 case 'U':
7135 case 'u': goto yy67;
7136 default: goto yy40;
7137 }
7138yy67:
7139 ++i;
7140 goto yy40;
7141yy68:
7142 ++i;
7143 yych = i < end ? *i : 0;
7144 switch (yych) {
7145 case '0':
7146 case '1':
7147 case '2':
7148 case '3':
7149 case '4':
7150 case '5':
7151 case '6':
7152 case '7':
7153 case '8':
7154 case '9': goto yy69;
7155 default: goto yy15;
7156 }
7157yy69:
7158 ++i;
7159 yych = i < end ? *i : 0;
7160 switch (yych) {
7161 case '0':
7162 case '1':
7163 case '2':
7164 case '3':
7165 case '4':
7166 case '5':
7167 case '6':
7168 case '7':
7169 case '8':
7170 case '9': goto yy69;
7171 case 'F':
7172 case 'L':
7173 case 'f':
7174 case 'l': goto yy79;
7175 default: goto yy70;
7176 }
7177yy70:
7178 { return i; }
7179yy71:
7180 ++i;
7181 yych = i < end ? *i : 0;
7182 switch (yych) {
7183 case 'L': goto yy67;
7184 default: goto yy40;
7185 }
7186yy72:
7187 ++i;
7188 yych = i < end ? *i : 0;
7189 switch (yych) {
7190 case 'l': goto yy67;
7191 default: goto yy40;
7192 }
7193yy73:
7194 ++i;
7195 yych = i < end ? *i : 0;
7196 switch (yych) {
7197 case '0':
7198 case '1':
7199 case '2':
7200 case '3':
7201 case '4':
7202 case '5':
7203 case '6':
7204 case '7':
7205 case '8':
7206 case '9': goto yy74;
7207 default: goto yy15;
7208 }
7209yy74:
7210 ++i;
7211 yych = i < end ? *i : 0;
7212 switch (yych) {
7213 case '0':
7214 case '1':
7215 case '2':
7216 case '3':
7217 case '4':
7218 case '5':
7219 case '6':
7220 case '7':
7221 case '8':
7222 case '9': goto yy74;
7223 case 'F':
7224 case 'L':
7225 case 'f':
7226 case 'l': goto yy80;
7227 default: goto yy75;
7228 }
7229yy75:
7230 { return i; }
7231yy76:
7232 ++i;
7233 yych = i < end ? *i : 0;
7234 switch (yych) {
7235 case '0':
7236 case '1':
7237 case '2':
7238 case '3':
7239 case '4':
7240 case '5':
7241 case '6':
7242 case '7':
7243 case '8':
7244 case '9': goto yy77;
7245 default: goto yy15;
7246 }
7247yy77:
7248 ++i;
7249 yych = i < end ? *i : 0;
7250 switch (yych) {
7251 case '0':
7252 case '1':
7253 case '2':
7254 case '3':
7255 case '4':
7256 case '5':
7257 case '6':
7258 case '7':
7259 case '8':
7260 case '9': goto yy77;
7261 case 'F':
7262 case 'L':
7263 case 'f':
7264 case 'l': goto yy81;
7265 default: goto yy78;
7266 }
7267yy78:
7268 { return i; }
7269yy79:
7270 ++i;
7271 goto yy70;
7272yy80:
7273 ++i;
7274 goto yy75;
7275yy81:
7276 ++i;
7277 goto yy78;
7278yy82:
7279 { return start; }
7280}
7281
7282}
7283
7284
7285//
7286// isCStylePunctuation
7287//
7288
7289static bool isCStylePunctuation(ImWchar character) {
7290 static bool punctuation[128] = {
7291 false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false,
7292 false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false,
7293 false, true, false, false, false, true, true, false, true, true, true, true, true, true, true, true,
7294 false, false, false, false, false, false, false, false, false, false, true, true, true, true, true, true,
7295 false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false,
7296 false, false, false, false, false, false, false, false, false, false, false, true, false, true, true, false,
7297 false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false,
7298 false, false, false, false, false, false, false, false, false, false, false, true, true, true, true, false,
7299 };
7300
7301 return character < 127 ? punctuation[character] : false;
7302}
7303
7304
7305//
7306// TextEditor::Language::C
7307//
7308
7309const TextEditor::Language* TextEditor::Language::C() {
7310 static bool initialized = false;
7311 static TextEditor::Language language;
7312
7313 if (!initialized) {
7314 language.name = "C";
7315 language.preprocess = '#';
7316 language.singleLineComment = "//";
7317 language.commentStart = "/*";
7318 language.commentEnd = "*/";
7319 language.hasSingleQuotedStrings = true;
7320 language.hasDoubleQuotedStrings = true;
7321 language.stringEscape = '\\';
7322
7323 static const char* const keywords[] = {
7324 "break", "case", "continue", "default", "do", "else", "for", "goto", "if", "return", "sizeof",
7325 "switch", "while", "_Alignas", "_Alignof", "_Atomic", "_Bool", "_Complex", "_Generic",
7326 "_Imaginary", "_Noreturn", "_Static_assert", "_Thread_local"
7327 };
7328
7329 static const char* const declarations[] = {
7330 "auto", "char", "const", "double", "enum", "extern", "float", "inline", "int", "long", "register",
7331 "restrict", "short", "signed", "static", "struct", "typedef", "union", "unsigned", "void", "volatile"
7332 };
7333
7334 for (auto& keyword : keywords) { language.keywords.insert(keyword); }
7335 for (auto& declaration : declarations) { language.declarations.insert(declaration); }
7336
7337 language.isPunctuation = isCStylePunctuation;
7338 language.getIdentifier = getCStyleIdentifier;
7339 language.getNumber = getCStyleNumber;
7340 initialized = true;
7341 }
7342
7343 return &language;
7344}
7345
7346
7347//
7348// TextEditor::Language::Cpp
7349//
7350
7351const TextEditor::Language* TextEditor::Language::Cpp() {
7352 static bool initialized = false;
7353 static TextEditor::Language language;
7354
7355 if (!initialized) {
7356 language.name = "C++";
7357 language.preprocess = '#';
7358 language.singleLineComment = "//";
7359 language.commentStart = "/*";
7360 language.commentEnd = "*/";
7361 language.hasSingleQuotedStrings = true;
7362 language.hasDoubleQuotedStrings = true;
7363 language.stringEscape = '\\';
7364
7365 static const char* const keywords[] = {
7366 "alignas", "alignof", "and", "and_eq", "asm", "atomic_cancel", "atomic_commit", "atomic_noexcept",
7367 "bitand", "bitor", "break", "case", "catch", "compl", "const_cast", "continue", "default", "delete",
7368 "do", "dynamic_cast", "else", "explicit", "export", "extern", "false", "for", "goto", "if", "import",
7369 "new", "noexcept", "not", "not_eq", "nullptr", "operator", "or", "or_eq", "reinterpret_cast", "requires",
7370 "return", "sizeof", "static_assert", "static_cast", "switch", "synchronized", "this", "thread_local",
7371 "throw", "true", "try", "while", "xor", "xor_eq"
7372 };
7373
7374 static const char* const declarations[] = {
7375 "auto", "bool", "char", "char16_t", "char32_t", "class", "concept", "const", "constexpr", "decltype",
7376 "double", "explicit", "export", "extern", "enum", "extern", "float", "friend", "inline", "int", "long",
7377 "module", "mutable", "namespace", "private", "protected", "public", "register", "restrict", "short",
7378 "signed", "static", "struct", "template", "typedef", "typeid", "typename", "union", "using", "unsigned",
7379 "virtual", "void", "volatile", "wchar_t"
7380 };
7381
7382 for (auto& keyword : keywords) { language.keywords.insert(keyword); }
7383 for (auto& declaration : declarations) { language.declarations.insert(declaration); }
7384
7385 language.isPunctuation = isCStylePunctuation;
7386 language.getIdentifier = getCStyleIdentifier;
7387 language.getNumber = getCStyleNumber;
7388 initialized = true;
7389 }
7390
7391 return &language;
7392}
7393
7394
7395//
7396// getCsStyleNumber
7397//
7398
7399static TextEditor::Iterator getCsStyleNumber(TextEditor::Iterator start, TextEditor::Iterator end) {
7400 TextEditor::Iterator i = start;
7401 TextEditor::Iterator marker;
7402
7403
7404{
7405 ImWchar yych;
7406 unsigned int yyaccept = 0;
7407 yych = i < end ? *i : 0;
7408 switch (yych) {
7409 case '.': goto yy3;
7410 case '0': goto yy4;
7411 case '1':
7412 case '2':
7413 case '3':
7414 case '4':
7415 case '5':
7416 case '6':
7417 case '7':
7418 case '8':
7419 case '9': goto yy6;
7420 default:
7421 if (i >= end) goto yy49;
7422 goto yy1;
7423 }
7424yy1:
7425 ++i;
7426yy2:
7427 { return start; }
7428yy3:
7429 ++i;
7430 yych = i < end ? *i : 0;
7431 switch (yych) {
7432 case '0':
7433 case '1':
7434 case '2':
7435 case '3':
7436 case '4':
7437 case '5':
7438 case '6':
7439 case '7':
7440 case '8':
7441 case '9': goto yy8;
7442 default: goto yy2;
7443 }
7444yy4:
7445 yyaccept = 0;
7446 ++i;
7447 marker = i;
7448 yych = i < end ? *i : 0;
7449 switch (yych) {
7450 case 0x00: goto yy5;
7451 case 'B':
7452 case 'b': goto yy12;
7453 case 'X':
7454 case 'x': goto yy15;
7455 default: goto yy7;
7456 }
7457yy5:
7458 { return i; }
7459yy6:
7460 yyaccept = 0;
7461 ++i;
7462 marker = i;
7463 yych = i < end ? *i : 0;
7464yy7:
7465 switch (yych) {
7466 case '.': goto yy10;
7467 case '0':
7468 case '1':
7469 case '2':
7470 case '3':
7471 case '4':
7472 case '5':
7473 case '6':
7474 case '7':
7475 case '8':
7476 case '9':
7477 case '_': goto yy6;
7478 case 'L': goto yy13;
7479 case 'U':
7480 case 'u': goto yy14;
7481 case 'l': goto yy16;
7482 default: goto yy5;
7483 }
7484yy8:
7485 yyaccept = 1;
7486 ++i;
7487 marker = i;
7488 yych = i < end ? *i : 0;
7489 switch (yych) {
7490 case '0':
7491 case '1':
7492 case '2':
7493 case '3':
7494 case '4':
7495 case '5':
7496 case '6':
7497 case '7':
7498 case '8':
7499 case '9':
7500 case '_': goto yy8;
7501 case 'E':
7502 case 'e': goto yy17;
7503 case 'F':
7504 case 'L':
7505 case 'f':
7506 case 'l': goto yy18;
7507 default: goto yy9;
7508 }
7509yy9:
7510 { return i; }
7511yy10:
7512 ++i;
7513 yych = i < end ? *i : 0;
7514 switch (yych) {
7515 case '0':
7516 case '1':
7517 case '2':
7518 case '3':
7519 case '4':
7520 case '5':
7521 case '6':
7522 case '7':
7523 case '8':
7524 case '9': goto yy19;
7525 default: goto yy11;
7526 }
7527yy11:
7528 i = marker;
7529 switch (yyaccept) {
7530 case 0: goto yy5;
7531 case 1: goto yy9;
7532 default: goto yy20;
7533 }
7534yy12:
7535 ++i;
7536 yych = i < end ? *i : 0;
7537 switch (yych) {
7538 case '0':
7539 case '1': goto yy21;
7540 default: goto yy11;
7541 }
7542yy13:
7543 ++i;
7544 yych = i < end ? *i : 0;
7545 switch (yych) {
7546 case 'L': goto yy23;
7547 case 'U':
7548 case 'u': goto yy24;
7549 default: goto yy5;
7550 }
7551yy14:
7552 ++i;
7553 yych = i < end ? *i : 0;
7554 switch (yych) {
7555 case 'L': goto yy25;
7556 case 'l': goto yy26;
7557 default: goto yy5;
7558 }
7559yy15:
7560 ++i;
7561 yych = i < end ? *i : 0;
7562 switch (yych) {
7563 case '0':
7564 case '1':
7565 case '2':
7566 case '3':
7567 case '4':
7568 case '5':
7569 case '6':
7570 case '7':
7571 case '8':
7572 case '9':
7573 case 'A':
7574 case 'B':
7575 case 'C':
7576 case 'D':
7577 case 'E':
7578 case 'F':
7579 case 'a':
7580 case 'b':
7581 case 'c':
7582 case 'd':
7583 case 'e':
7584 case 'f': goto yy27;
7585 default: goto yy11;
7586 }
7587yy16:
7588 ++i;
7589 yych = i < end ? *i : 0;
7590 switch (yych) {
7591 case 'U':
7592 case 'u': goto yy24;
7593 case 'l': goto yy23;
7594 default: goto yy5;
7595 }
7596yy17:
7597 ++i;
7598 yych = i < end ? *i : 0;
7599 switch (yych) {
7600 case '+':
7601 case '-': goto yy29;
7602 case '0':
7603 case '1':
7604 case '2':
7605 case '3':
7606 case '4':
7607 case '5':
7608 case '6':
7609 case '7':
7610 case '8':
7611 case '9':
7612 case '_': goto yy30;
7613 default: goto yy11;
7614 }
7615yy18:
7616 ++i;
7617 goto yy9;
7618yy19:
7619 yyaccept = 2;
7620 ++i;
7621 marker = i;
7622 yych = i < end ? *i : 0;
7623 switch (yych) {
7624 case '0':
7625 case '1':
7626 case '2':
7627 case '3':
7628 case '4':
7629 case '5':
7630 case '6':
7631 case '7':
7632 case '8':
7633 case '9':
7634 case '_': goto yy19;
7635 case 'E':
7636 case 'e': goto yy31;
7637 case 'F':
7638 case 'L':
7639 case 'f':
7640 case 'l': goto yy32;
7641 default: goto yy20;
7642 }
7643yy20:
7644 { return i; }
7645yy21:
7646 ++i;
7647 yych = i < end ? *i : 0;
7648 switch (yych) {
7649 case '0':
7650 case '1':
7651 case '_': goto yy21;
7652 case 'L': goto yy33;
7653 case 'U':
7654 case 'u': goto yy34;
7655 case 'l': goto yy35;
7656 default: goto yy22;
7657 }
7658yy22:
7659 { return i; }
7660yy23:
7661 ++i;
7662 yych = i < end ? *i : 0;
7663 switch (yych) {
7664 case 'U':
7665 case 'u': goto yy24;
7666 default: goto yy5;
7667 }
7668yy24:
7669 ++i;
7670 goto yy5;
7671yy25:
7672 ++i;
7673 yych = i < end ? *i : 0;
7674 switch (yych) {
7675 case 'L': goto yy24;
7676 default: goto yy5;
7677 }
7678yy26:
7679 ++i;
7680 yych = i < end ? *i : 0;
7681 switch (yych) {
7682 case 'l': goto yy24;
7683 default: goto yy5;
7684 }
7685yy27:
7686 ++i;
7687 yych = i < end ? *i : 0;
7688 switch (yych) {
7689 case '0':
7690 case '1':
7691 case '2':
7692 case '3':
7693 case '4':
7694 case '5':
7695 case '6':
7696 case '7':
7697 case '8':
7698 case '9':
7699 case 'A':
7700 case 'B':
7701 case 'C':
7702 case 'D':
7703 case 'E':
7704 case 'F':
7705 case '_':
7706 case 'a':
7707 case 'b':
7708 case 'c':
7709 case 'd':
7710 case 'e':
7711 case 'f': goto yy27;
7712 case 'L': goto yy36;
7713 case 'U':
7714 case 'u': goto yy37;
7715 case 'l': goto yy38;
7716 default: goto yy28;
7717 }
7718yy28:
7719 { return i; }
7720yy29:
7721 ++i;
7722 yych = i < end ? *i : 0;
7723 switch (yych) {
7724 case '0':
7725 case '1':
7726 case '2':
7727 case '3':
7728 case '4':
7729 case '5':
7730 case '6':
7731 case '7':
7732 case '8':
7733 case '9':
7734 case '_': goto yy30;
7735 default: goto yy11;
7736 }
7737yy30:
7738 ++i;
7739 yych = i < end ? *i : 0;
7740 switch (yych) {
7741 case '0':
7742 case '1':
7743 case '2':
7744 case '3':
7745 case '4':
7746 case '5':
7747 case '6':
7748 case '7':
7749 case '8':
7750 case '9':
7751 case '_': goto yy30;
7752 case 'F':
7753 case 'L':
7754 case 'f':
7755 case 'l': goto yy18;
7756 default: goto yy9;
7757 }
7758yy31:
7759 ++i;
7760 yych = i < end ? *i : 0;
7761 switch (yych) {
7762 case '+':
7763 case '-': goto yy39;
7764 case '0':
7765 case '1':
7766 case '2':
7767 case '3':
7768 case '4':
7769 case '5':
7770 case '6':
7771 case '7':
7772 case '8':
7773 case '9':
7774 case '_': goto yy40;
7775 default: goto yy11;
7776 }
7777yy32:
7778 ++i;
7779 goto yy20;
7780yy33:
7781 ++i;
7782 yych = i < end ? *i : 0;
7783 switch (yych) {
7784 case 'L': goto yy41;
7785 case 'U':
7786 case 'u': goto yy42;
7787 default: goto yy22;
7788 }
7789yy34:
7790 ++i;
7791 yych = i < end ? *i : 0;
7792 switch (yych) {
7793 case 'L': goto yy43;
7794 case 'l': goto yy44;
7795 default: goto yy22;
7796 }
7797yy35:
7798 ++i;
7799 yych = i < end ? *i : 0;
7800 switch (yych) {
7801 case 'U':
7802 case 'u': goto yy42;
7803 case 'l': goto yy41;
7804 default: goto yy22;
7805 }
7806yy36:
7807 ++i;
7808 yych = i < end ? *i : 0;
7809 switch (yych) {
7810 case 'L': goto yy45;
7811 case 'U':
7812 case 'u': goto yy46;
7813 default: goto yy28;
7814 }
7815yy37:
7816 ++i;
7817 yych = i < end ? *i : 0;
7818 switch (yych) {
7819 case 'L': goto yy47;
7820 case 'l': goto yy48;
7821 default: goto yy28;
7822 }
7823yy38:
7824 ++i;
7825 yych = i < end ? *i : 0;
7826 switch (yych) {
7827 case 'U':
7828 case 'u': goto yy46;
7829 case 'l': goto yy45;
7830 default: goto yy28;
7831 }
7832yy39:
7833 ++i;
7834 yych = i < end ? *i : 0;
7835 switch (yych) {
7836 case '0':
7837 case '1':
7838 case '2':
7839 case '3':
7840 case '4':
7841 case '5':
7842 case '6':
7843 case '7':
7844 case '8':
7845 case '9':
7846 case '_': goto yy40;
7847 default: goto yy11;
7848 }
7849yy40:
7850 ++i;
7851 yych = i < end ? *i : 0;
7852 switch (yych) {
7853 case '0':
7854 case '1':
7855 case '2':
7856 case '3':
7857 case '4':
7858 case '5':
7859 case '6':
7860 case '7':
7861 case '8':
7862 case '9':
7863 case '_': goto yy40;
7864 case 'F':
7865 case 'L':
7866 case 'f':
7867 case 'l': goto yy32;
7868 default: goto yy20;
7869 }
7870yy41:
7871 ++i;
7872 yych = i < end ? *i : 0;
7873 switch (yych) {
7874 case 'U':
7875 case 'u': goto yy42;
7876 default: goto yy22;
7877 }
7878yy42:
7879 ++i;
7880 goto yy22;
7881yy43:
7882 ++i;
7883 yych = i < end ? *i : 0;
7884 switch (yych) {
7885 case 'L': goto yy42;
7886 default: goto yy22;
7887 }
7888yy44:
7889 ++i;
7890 yych = i < end ? *i : 0;
7891 switch (yych) {
7892 case 'l': goto yy42;
7893 default: goto yy22;
7894 }
7895yy45:
7896 ++i;
7897 yych = i < end ? *i : 0;
7898 switch (yych) {
7899 case 'U':
7900 case 'u': goto yy46;
7901 default: goto yy28;
7902 }
7903yy46:
7904 ++i;
7905 goto yy28;
7906yy47:
7907 ++i;
7908 yych = i < end ? *i : 0;
7909 switch (yych) {
7910 case 'L': goto yy46;
7911 default: goto yy28;
7912 }
7913yy48:
7914 ++i;
7915 yych = i < end ? *i : 0;
7916 switch (yych) {
7917 case 'l': goto yy46;
7918 default: goto yy28;
7919 }
7920yy49:
7921 { return start; }
7922}
7923
7924}
7925
7926
7927//
7928// TextEditor::Language::Cs
7929//
7930
7931const TextEditor::Language* TextEditor::Language::Cs() {
7932 static bool initialized = false;
7933 static TextEditor::Language language;
7934
7935 if (!initialized) {
7936 language.name = "C#";
7937 language.preprocess = '#';
7938 language.singleLineComment = "//";
7939 language.commentStart = "/*";
7940 language.commentEnd = "*/";
7941 language.hasSingleQuotedStrings = true;
7942 language.hasDoubleQuotedStrings = true;
7943 language.stringEscape = '\\';
7944
7945 static const char* const keywords[] = {
7946 "abstract", "as", "base", "bool", "break", "byte", "case", "catch", "char", "checked", "class", "const", "continue",
7947 "decimal", "default", "delegate", "do", "double", "else", "enum", "event", "explicit", "extern", "false", "finally",
7948 "fixed", "float", "for", "foreach", "goto", "if", "implicit", "in", "in (generic modifier)", "int", "interface",
7949 "internal", "is", "lock", "long", "namespace", "new", "null", "object", "operator", "out", "override", "params",
7950 "private", "protected", "public", "readonly", "ref", "return", "sbyte", "sealed", "short", "sizeof", "stackalloc",
7951 "static", "string", "struct", "switch", "this", "throw", "true", "try", "typeof", "uint", "ulong", "unchecked",
7952 "unsafe", "ushort", "using", "using static", "void", "volatile", "while"
7953 };
7954
7955 for (auto& keyword : keywords) { language.keywords.insert(keyword); }
7956
7957 language.isPunctuation = isCStylePunctuation;
7958 language.getIdentifier = getCStyleIdentifier;
7959 language.getNumber = getCsStyleNumber;
7960 initialized = true;
7961 }
7962
7963 return &language;
7964}
7965
7966
7967//
7968// TextEditor::Language::AngelScript
7969//
7970
7971const TextEditor::Language* TextEditor::Language::AngelScript() {
7972 static bool initialized = false;
7973 static TextEditor::Language language;
7974
7975 if (!initialized) {
7976 language.name = "AngelScript";
7977 language.preprocess = '#';
7978 language.singleLineComment = "//";
7979 language.commentStart = "/*";
7980 language.commentEnd = "*/";
7981 language.hasSingleQuotedStrings = true;
7982 language.hasDoubleQuotedStrings = true;
7983 language.stringEscape = '\\';
7984
7985 static const char* const keywords[] = {
7986 "and", "abstract", "auto", "bool", "break", "case", "cast", "class", "const", "continue", "default",
7987 "do", "double", "else", "enum", "false", "final", "float", "for", "from", "funcdef", "function", "get",
7988 "if", "import", "in", "inout", "int", "interface", "int8", "int16", "int32", "int64", "is", "mixin",
7989 "namespace", "not", "null", "or", "out", "override", "private", "protected", "return", "set", "shared",
7990 "super", "switch", "this ", "true", "typedef", "uint", "uint8", "uint16", "uint32", "uint64", "void",
7991 "while", "xor"
7992 };
7993
7994 for (auto& keyword : keywords) { language.keywords.insert(keyword); }
7995
7996 language.isPunctuation = isCStylePunctuation;
7997 language.getIdentifier = getCStyleIdentifier;
7998 language.getNumber = getCStyleNumber;
7999 initialized = true;
8000 }
8001
8002 return &language;
8003}
8004
8005
8006//
8007// getLuaStyleNumber
8008//
8009
8010static TextEditor::Iterator getLuaStyleNumber(TextEditor::Iterator start, TextEditor::Iterator end) {
8011 TextEditor::Iterator i = start;
8012 TextEditor::Iterator marker;
8013
8014
8015{
8016 ImWchar yych;
8017 yych = i < end ? *i : 0;
8018 switch (yych) {
8019 case '.': goto yy3;
8020 case '0': goto yy5;
8021 case '1':
8022 case '2':
8023 case '3':
8024 case '4':
8025 case '5':
8026 case '6':
8027 case '7':
8028 case '8':
8029 case '9': goto yy6;
8030 case 'E':
8031 case 'e': goto yy8;
8032 default:
8033 if (i >= end) goto yy1;
8034 goto yy2;
8035 }
8036yy1:
8037 { return i; }
8038yy2:
8039 ++i;
8040 { return start; }
8041yy3:
8042 ++i;
8043 yych = i < end ? *i : 0;
8044 switch (yych) {
8045 case '0':
8046 case '1':
8047 case '2':
8048 case '3':
8049 case '4':
8050 case '5':
8051 case '6':
8052 case '7':
8053 case '8':
8054 case '9': goto yy3;
8055 case 'E':
8056 case 'e': goto yy8;
8057 default: goto yy4;
8058 }
8059yy4:
8060 { return i; }
8061yy5:
8062 ++i;
8063 marker = i;
8064 yych = i < end ? *i : 0;
8065 switch (yych) {
8066 case 0x00: goto yy1;
8067 case 'X':
8068 case 'x': goto yy9;
8069 default: goto yy7;
8070 }
8071yy6:
8072 ++i;
8073 yych = i < end ? *i : 0;
8074yy7:
8075 switch (yych) {
8076 case '.': goto yy3;
8077 case '0':
8078 case '1':
8079 case '2':
8080 case '3':
8081 case '4':
8082 case '5':
8083 case '6':
8084 case '7':
8085 case '8':
8086 case '9': goto yy6;
8087 case 'E':
8088 case 'e': goto yy8;
8089 default: goto yy1;
8090 }
8091yy8:
8092 ++i;
8093 yych = i < end ? *i : 0;
8094 switch (yych) {
8095 case 0x00: goto yy4;
8096 case '+':
8097 case '-': goto yy11;
8098 default: goto yy12;
8099 }
8100yy9:
8101 ++i;
8102 yych = i < end ? *i : 0;
8103 switch (yych) {
8104 case '0':
8105 case '1':
8106 case '2':
8107 case '3':
8108 case '4':
8109 case '5':
8110 case '6':
8111 case '7':
8112 case '8':
8113 case '9':
8114 case 'A':
8115 case 'B':
8116 case 'C':
8117 case 'D':
8118 case 'E':
8119 case 'F':
8120 case 'a':
8121 case 'b':
8122 case 'c':
8123 case 'd':
8124 case 'e':
8125 case 'f': goto yy13;
8126 default: goto yy10;
8127 }
8128yy10:
8129 i = marker;
8130 goto yy1;
8131yy11:
8132 ++i;
8133 yych = i < end ? *i : 0;
8134yy12:
8135 switch (yych) {
8136 case '0':
8137 case '1':
8138 case '2':
8139 case '3':
8140 case '4':
8141 case '5':
8142 case '6':
8143 case '7':
8144 case '8':
8145 case '9': goto yy11;
8146 default: goto yy4;
8147 }
8148yy13:
8149 ++i;
8150 yych = i < end ? *i : 0;
8151 switch (yych) {
8152 case '.': goto yy15;
8153 case '0':
8154 case '1':
8155 case '2':
8156 case '3':
8157 case '4':
8158 case '5':
8159 case '6':
8160 case '7':
8161 case '8':
8162 case '9':
8163 case 'A':
8164 case 'B':
8165 case 'C':
8166 case 'D':
8167 case 'E':
8168 case 'F':
8169 case 'a':
8170 case 'b':
8171 case 'c':
8172 case 'd':
8173 case 'e':
8174 case 'f': goto yy13;
8175 case 'P':
8176 case 'p': goto yy16;
8177 default: goto yy14;
8178 }
8179yy14:
8180 { return i; }
8181yy15:
8182 ++i;
8183 yych = i < end ? *i : 0;
8184 switch (yych) {
8185 case '0':
8186 case '1':
8187 case '2':
8188 case '3':
8189 case '4':
8190 case '5':
8191 case '6':
8192 case '7':
8193 case '8':
8194 case '9':
8195 case 'A':
8196 case 'B':
8197 case 'C':
8198 case 'D':
8199 case 'E':
8200 case 'F':
8201 case 'a':
8202 case 'b':
8203 case 'c':
8204 case 'd':
8205 case 'e':
8206 case 'f': goto yy15;
8207 case 'P':
8208 case 'p': goto yy16;
8209 default: goto yy14;
8210 }
8211yy16:
8212 ++i;
8213 yych = i < end ? *i : 0;
8214 switch (yych) {
8215 case 0x00: goto yy14;
8216 case '+':
8217 case '-': goto yy17;
8218 default: goto yy18;
8219 }
8220yy17:
8221 ++i;
8222 yych = i < end ? *i : 0;
8223yy18:
8224 switch (yych) {
8225 case '0':
8226 case '1':
8227 case '2':
8228 case '3':
8229 case '4':
8230 case '5':
8231 case '6':
8232 case '7':
8233 case '8':
8234 case '9':
8235 case 'A':
8236 case 'B':
8237 case 'C':
8238 case 'D':
8239 case 'E':
8240 case 'F':
8241 case 'a':
8242 case 'b':
8243 case 'c':
8244 case 'd':
8245 case 'e':
8246 case 'f': goto yy17;
8247 default: goto yy14;
8248 }
8249}
8250
8251}
8252
8253
8254//
8255// isLuaStylePunctuation
8256// []{}!%#^&*()-+=~|<>?:/;,.
8257//
8258
8259static bool isLuaStylePunctuation(ImWchar character) {
8260 static bool punctuation[128] = {
8261 false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false,
8262 false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false,
8263 false, true, false, true, false, true, true, false, true, true, true, true, true, true, true, true,
8264 false, false, false, false, false, false, false, false, false, false, true, true, true, true, true, true,
8265 false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false,
8266 false, false, false, false, false, false, false, false, false, false, false, true, false, true, true, false,
8267 false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false,
8268 false, false, false, false, false, false, false, false, false, false, false, true, true, true, true, false,
8269 };
8270
8271 return character < 127 ? punctuation[character] : false;
8272}
8273
8274
8275//
8276// TextEditor::Language::Lua
8277//
8278
8279const TextEditor::Language* TextEditor::Language::Lua() {
8280 static bool initialized = false;
8281 static TextEditor::Language language;
8282
8283 if (!initialized) {
8284 language.name = "Lua";
8285 language.singleLineComment = "--";
8286 language.commentStart = "--[[";
8287 language.commentEnd = "]]";
8288 language.hasSingleQuotedStrings = true;
8289 language.hasDoubleQuotedStrings = true;
8290 language.otherStringStart = "[[";
8291 language.otherStringEnd = "]]";
8292 language.stringEscape = '\\';
8293
8294 static const char* const keywords[] = {
8295 "and", "break", "do", "else", "elseif", "end", "false", "for", "function", "goto", "if", "in", "local", "nil",
8296 "not", "or", "repeat", "return", "then", "true", "until", "while"
8297 };
8298
8299 for (auto& keyword : keywords) { language.keywords.insert(keyword); }
8300
8301 language.isPunctuation = isLuaStylePunctuation;
8302 language.getIdentifier = getCStyleIdentifier;
8303 language.getNumber = getLuaStyleNumber;
8304 initialized = true;
8305 }
8306
8307 return &language;
8308}
8309
8310
8311//
8312// getPythonStyleNumber
8313//
8314
8315static TextEditor::Iterator getPythonStyleNumber(TextEditor::Iterator start, TextEditor::Iterator end) {
8316 TextEditor::Iterator i = start;
8317 TextEditor::Iterator marker;
8318
8319
8320{
8321 ImWchar yych;
8322 yych = i < end ? *i : 0;
8323 switch (yych) {
8324 case '0': goto yy2;
8325 case '1':
8326 case '2':
8327 case '3':
8328 case '4':
8329 case '5':
8330 case '6':
8331 case '7':
8332 case '8':
8333 case '9': goto yy4;
8334 default:
8335 if (i >= end) goto yy18;
8336 goto yy1;
8337 }
8338yy1:
8339 ++i;
8340 { return start; }
8341yy2:
8342 ++i;
8343 marker = i;
8344 yych = i < end ? *i : 0;
8345 switch (yych) {
8346 case 0x00: goto yy3;
8347 case 'B':
8348 case 'b': goto yy9;
8349 case 'O':
8350 case 'o': goto yy11;
8351 case 'X':
8352 case 'x': goto yy12;
8353 default: goto yy5;
8354 }
8355yy3:
8356 {
8357 return i;
8358 }
8359yy4:
8360 ++i;
8361 marker = i;
8362 yych = i < end ? *i : 0;
8363yy5:
8364 switch (yych) {
8365 case '+':
8366 case '-':
8367 case 'E':
8368 case 'e': goto yy6;
8369 case '.': goto yy8;
8370 case '0':
8371 case '1':
8372 case '2':
8373 case '3':
8374 case '4':
8375 case '5':
8376 case '6':
8377 case '7':
8378 case '8':
8379 case '9':
8380 case '_': goto yy4;
8381 case 'J':
8382 case 'j': goto yy10;
8383 default: goto yy3;
8384 }
8385yy6:
8386 ++i;
8387 yych = i < end ? *i : 0;
8388 switch (yych) {
8389 case '0':
8390 case '1':
8391 case '2':
8392 case '3':
8393 case '4':
8394 case '5':
8395 case '6':
8396 case '7':
8397 case '8':
8398 case '9': goto yy13;
8399 default: goto yy7;
8400 }
8401yy7:
8402 i = marker;
8403 goto yy3;
8404yy8:
8405 ++i;
8406 yych = i < end ? *i : 0;
8407 switch (yych) {
8408 case '0':
8409 case '1':
8410 case '2':
8411 case '3':
8412 case '4':
8413 case '5':
8414 case '6':
8415 case '7':
8416 case '8':
8417 case '9': goto yy14;
8418 default: goto yy7;
8419 }
8420yy9:
8421 ++i;
8422 yych = i < end ? *i : 0;
8423 switch (yych) {
8424 case '0':
8425 case '1':
8426 case '_': goto yy15;
8427 default: goto yy7;
8428 }
8429yy10:
8430 ++i;
8431 goto yy3;
8432yy11:
8433 ++i;
8434 yych = i < end ? *i : 0;
8435 switch (yych) {
8436 case '0':
8437 case '1':
8438 case '2':
8439 case '3':
8440 case '4':
8441 case '5':
8442 case '6':
8443 case '7':
8444 case '_': goto yy16;
8445 default: goto yy7;
8446 }
8447yy12:
8448 ++i;
8449 yych = i < end ? *i : 0;
8450 switch (yych) {
8451 case '0':
8452 case '1':
8453 case '2':
8454 case '3':
8455 case '4':
8456 case '5':
8457 case '6':
8458 case '7':
8459 case '8':
8460 case '9':
8461 case 'A':
8462 case 'B':
8463 case 'C':
8464 case 'D':
8465 case 'E':
8466 case 'F':
8467 case '_':
8468 case 'a':
8469 case 'b':
8470 case 'c':
8471 case 'd':
8472 case 'e':
8473 case 'f': goto yy17;
8474 default: goto yy7;
8475 }
8476yy13:
8477 ++i;
8478 yych = i < end ? *i : 0;
8479 switch (yych) {
8480 case '0':
8481 case '1':
8482 case '2':
8483 case '3':
8484 case '4':
8485 case '5':
8486 case '6':
8487 case '7':
8488 case '8':
8489 case '9':
8490 case '_': goto yy13;
8491 case 'J':
8492 case 'j': goto yy10;
8493 default: goto yy3;
8494 }
8495yy14:
8496 ++i;
8497 marker = i;
8498 yych = i < end ? *i : 0;
8499 switch (yych) {
8500 case '+':
8501 case '-':
8502 case 'E':
8503 case 'e': goto yy6;
8504 case '0':
8505 case '1':
8506 case '2':
8507 case '3':
8508 case '4':
8509 case '5':
8510 case '6':
8511 case '7':
8512 case '8':
8513 case '9':
8514 case '_': goto yy14;
8515 case 'J':
8516 case 'j': goto yy10;
8517 default: goto yy3;
8518 }
8519yy15:
8520 ++i;
8521 yych = i < end ? *i : 0;
8522 switch (yych) {
8523 case '0':
8524 case '1':
8525 case '_': goto yy15;
8526 default: goto yy3;
8527 }
8528yy16:
8529 ++i;
8530 yych = i < end ? *i : 0;
8531 switch (yych) {
8532 case '0':
8533 case '1':
8534 case '2':
8535 case '3':
8536 case '4':
8537 case '5':
8538 case '6':
8539 case '7':
8540 case '_': goto yy16;
8541 default: goto yy3;
8542 }
8543yy17:
8544 ++i;
8545 yych = i < end ? *i : 0;
8546 switch (yych) {
8547 case '0':
8548 case '1':
8549 case '2':
8550 case '3':
8551 case '4':
8552 case '5':
8553 case '6':
8554 case '7':
8555 case '8':
8556 case '9':
8557 case 'A':
8558 case 'B':
8559 case 'C':
8560 case 'D':
8561 case 'E':
8562 case 'F':
8563 case '_':
8564 case 'a':
8565 case 'b':
8566 case 'c':
8567 case 'd':
8568 case 'e':
8569 case 'f': goto yy17;
8570 default: goto yy3;
8571 }
8572yy18:
8573 { return start; }
8574}
8575
8576}
8577
8578
8579//
8580// TextEditor::Language::Python
8581//
8582
8583const TextEditor::Language* TextEditor::Language::Python() {
8584 static bool initialized = false;
8585 static TextEditor::Language language;
8586
8587 if (!initialized) {
8588 language.name = "Python";
8589 language.singleLineComment = "#";
8590 language.hasSingleQuotedStrings = true;
8591 language.hasDoubleQuotedStrings = true;
8592 language.otherStringStart = "\"\"\"";
8593 language.otherStringEnd = "\"\"\"";
8594 language.otherStringAltStart = "'''";
8595 language.otherStringAltEnd = "'''";
8596 language.stringEscape = '\\';
8597
8598 static const char* const keywords[] = {
8599 "False", "await", "else", "import", "pass", "None", "break", "except", "in", "raise", "True",
8600 "class", "finally", "is", "return", "and", "continue", "for", "lambda", "try", "as", "def",
8601 "from", "nonlocal", "while", "assert", "del", "global", "not", "with", "async", "elif",
8602 "if", "or", "yield"
8603 };
8604
8605 for (auto& keyword : keywords) { language.keywords.insert(keyword); }
8606
8607 language.isPunctuation = isCStylePunctuation;
8608 language.getIdentifier = getCStyleIdentifier;
8609 language.getNumber = getPythonStyleNumber;
8610 initialized = true;
8611 }
8612
8613 return &language;
8614}
8615
8616
8617//
8618// TextEditor::Language::Glsl
8619//
8620
8621const TextEditor::Language* TextEditor::Language::Glsl() {
8622 static bool initialized = false;
8623 static TextEditor::Language language;
8624
8625 if (!initialized) {
8626 language.name = "GLSL";
8627 language.preprocess = '#';
8628 language.singleLineComment = "//";
8629 language.commentStart = "/*";
8630 language.commentEnd = "*/";
8631 language.hasSingleQuotedStrings = true;
8632 language.hasDoubleQuotedStrings = true;
8633 language.stringEscape = '\\';
8634
8635 // source: https://registry.khronos.org/OpenGL/specs/gl/GLSLangSpec.4.60.html
8636 static const char* const keywords[] = {
8637 "atomic_uint", "attribute", "bool", "break", "buffer", "bvec2", "bvec3", "bvec4", "case", "centroid",
8638 "coherent", "const", "continue", "default", "discard", "dmat2", "dmat2x2", "dmat2x3", "dmat2x4", "dmat3",
8639 "dmat3x2", "dmat3x3", "dmat3x4", "dmat4", "dmat4x2", "dmat4x3", "dmat4x4", "do", "double", "dvec2", "dvec3",
8640 "dvec4", "else", "false", "flat", "float", "for", "highp", "if", "iimage1D", "iimage1DArray", "iimage2D",
8641 "iimage2DArray", "iimage2DMS", "iimage2DMSArray", "iimage2DRect", "iimage3D", "iimageBuffer", "iimageCube",
8642 "iimageCubeArray", "image1D", "image1DArray", "image2D", "image2DArray", "image2DMS", "image2DMSArray",
8643 "image2DRect", "image3D", "imageBuffer", "imageCube", "imageCubeArray", "in", "inout", "int", "invariant",
8644 "isampler1D", "isampler1DArray", "isampler2D", "isampler2DArray", "isampler2DMS", "isampler2DMSArray",
8645 "isampler2DRect", "isampler3D", "isamplerBuffer", "isamplerCube", "isamplerCubeArray", "ivec2", "ivec3",
8646 "ivec4", "layout", "lowp", "mat2", "mat2x2", "mat2x3", "mat2x4", "mat3", "mat3x2", "mat3x3", "mat3x4",
8647 "mat4", "mat4x2", "mat4x3", "mat4x4", "mediump", "noperspective", "out", "patch", "precise", "precision",
8648 "readonly", "restrict", "return", "sample", "sampler1D", "sampler1DArray", "sampler1DArrayShadow",
8649 "sampler1DShadow", "sampler2D", "sampler2DArray", "sampler2DArrayShadow", "sampler2DMS", "sampler2DMSArray",
8650 "sampler2DRect", "sampler2DRectShadow", "sampler2DShadow", "sampler3D", "samplerBuffer", "samplerCube",
8651 "samplerCubeArray", "samplerCubeArrayShadow", "samplerCubeShadow", "shared", "smooth", "struct", "subroutine",
8652 "switch", "true", "uimage1D", "uimage1DArray", "uimage2D", "uimage2DArray", "uimage2DMS", "uimage2DMSArray",
8653 "uimage2DRect", "uimage3D", "uimageBuffer", "uimageCube", "uimageCubeArray", "uint", "uniform", "usampler1D",
8654 "usampler1DArray", "usampler2D", "usampler2DArray", "usampler2DMS", "usampler2DMSArray", "usampler2DRect",
8655 "usampler3D", "usamplerBuffer", "usamplerCube", "usamplerCubeArray", "uvec2", "uvec3", "uvec4", "varying",
8656 "vec2", "vec3", "vec4", "void", "volatile", "while", "writeonly"
8657 };
8658
8659 for (auto& keyword : keywords) { language.keywords.insert(keyword); }
8660
8661 language.isPunctuation = isCStylePunctuation;
8662 language.getIdentifier = getCStyleIdentifier;
8663 language.getNumber = getCStyleNumber;
8664 initialized = true;
8665 }
8666
8667 return &language;
8668}
8669
8670
8671//
8672// TextEditor::Language::Hlsl
8673//
8674
8675const TextEditor::Language* TextEditor::Language::Hlsl() {
8676 static bool initialized = false;
8677 static TextEditor::Language language;
8678
8679 if (!initialized) {
8680 language.name = "HLSL";
8681 language.preprocess = '#';
8682 language.singleLineComment = "//";
8683 language.commentStart = "/*";
8684 language.commentEnd = "*/";
8685 language.hasSingleQuotedStrings = true;
8686 language.hasDoubleQuotedStrings = true;
8687 language.stringEscape = '\\';
8688
8689 static const char* const keywords[] = {
8690 "AppendStructuredBuffer", "asm", "asm_fragment", "BlendState", "bool", "break", "Buffer",
8691 "ByteAddressBuffer", "case", "cbuffer", "centroid", "class", "column_major", "compile",
8692 "compile_fragment", "CompileShader", "const", "continue", "ComputeShader", "ConsumeStructuredBuffer",
8693 "default", "DepthStencilState", "DepthStencilView", "discard", "do", "double", "DomainShader", "dword",
8694 "else", "export", "extern", "false", "float", "for", "fxgroup", "GeometryShader", "groupshared", "half",
8695 "Hullshader", "if", "in", "inline", "inout", "InputPatch", "int", "interface", "line", "lineadj",
8696 "linear", "LineStream", "matrix", "min16float", "min10float", "min16int", "min12int", "min16uint",
8697 "namespace", "nointerpolation", "noperspective", "NULL", "out", "OutputPatch", "packoffset",
8698 "pass", "pixelfragment", "PixelShader", "point", "PointStream", "precise", "RasterizerState",
8699 "RenderTargetView", "return", "register", "row_major", "RWBuffer", "RWByteAddressBuffer",
8700 "RWStructuredBuffer", "RWTexture1D", "RWTexture1DArray", "RWTexture2D", "RWTexture2DArray",
8701 "RWTexture3D", "sample", "sampler", "SamplerState", "SamplerComparisonState", "shared",
8702 "snorm", "stateblock", "stateblock_state", "static", "string", "struct", "switch", "StructuredBuffer",
8703 "tbuffer", "technique", "technique10", "technique11", "texture", "Texture1D", "Texture1DArray",
8704 "Texture2D", "Texture2DArray", "Texture2DMS", "Texture2DMSArray", "Texture3D", "TextureCube",
8705 "TextureCubeArray", "true", "typedef", "triangle", "triangleadj", "TriangleStream", "uint",
8706 "uniform", "unorm", "unsigned", "vector", "vertexfragment", "VertexShader", "void", "volatile", "while",
8707 "bool1", "bool2", "bool3", "bool4", "double1", "double2", "double3", "double4", "float1", "float2",
8708 "float3", "float4", "int1", "int2", "int3", "int4", "in", "out", "inout", "uint1", "uint2", "uint3",
8709 "uint4", "dword1", "dword2", "dword3", "dword4", "half1", "half2", "half3", "half4", "float1x1",
8710 "float2x1", "float3x1", "float4x1", "float1x2", "float2x2", "float3x2", "float4x2",
8711 "float1x3", "float2x3", "float3x3", "float4x3", "float1x4", "float2x4", "float3x4", "float4x4",
8712 "half1x1", "half2x1", "half3x1", "half4x1", "half1x2", "half2x2", "half3x2", "half4x2",
8713 "half1x3", "half2x3", "half3x3", "half4x3", "half1x4", "half2x4", "half3x4", "half4x4",
8714 };
8715
8716 for (auto& keyword : keywords) { language.keywords.insert(keyword); }
8717
8718 language.isPunctuation = isCStylePunctuation;
8719 language.getIdentifier = getCStyleIdentifier;
8720 language.getNumber = getCStyleNumber;
8721 initialized = true;
8722 }
8723
8724 return &language;
8725}
8726// tokenizeJson
8727//
8728
8729static TextEditor::Iterator tokenizeJson(TextEditor::Iterator start, TextEditor::Iterator end, TextEditor::Color& color) {
8730 TextEditor::Iterator i = start;
8731 TextEditor::Iterator marker;
8732
8733
8734{
8735 ImWchar yych;
8736 unsigned int yyaccept = 0;
8737 yych = i < end ? *i : 0;
8738 switch (yych) {
8739 case '"': goto yy3;
8740 case ',':
8741 case '[':
8742 case ']':
8743 case '{':
8744 case '}': goto yy4;
8745 case '-': goto yy5;
8746 case '0': goto yy6;
8747 case '1':
8748 case '2':
8749 case '3':
8750 case '4':
8751 case '5':
8752 case '6':
8753 case '7':
8754 case '8':
8755 case '9': goto yy8;
8756 case 'f': goto yy9;
8757 case 'n': goto yy10;
8758 case 't': goto yy11;
8759 default:
8760 if (i >= end) goto yy31;
8761 goto yy1;
8762 }
8763yy1:
8764 ++i;
8765yy2:
8766 { return start; }
8767yy3:
8768 yyaccept = 0;
8769 ++i;
8770 marker = i;
8771 yych = i < end ? *i : 0;
8772 if (yych <= 0x00) {
8773 if (i >= end) goto yy2;
8774 goto yy12;
8775 }
8776 goto yy13;
8777yy4:
8778 ++i;
8779 {
8780 color = TextEditor::Color::punctuation;
8781 return i;
8782 }
8783yy5:
8784 ++i;
8785 yych = i < end ? *i : 0;
8786 switch (yych) {
8787 case '0': goto yy6;
8788 case '1':
8789 case '2':
8790 case '3':
8791 case '4':
8792 case '5':
8793 case '6':
8794 case '7':
8795 case '8':
8796 case '9': goto yy8;
8797 default: goto yy2;
8798 }
8799yy6:
8800 yyaccept = 1;
8801 ++i;
8802 marker = i;
8803 yych = i < end ? *i : 0;
8804 switch (yych) {
8805 case '.': goto yy16;
8806 case 'E':
8807 case 'e': goto yy18;
8808 default: goto yy7;
8809 }
8810yy7:
8811 {
8812 color = TextEditor::Color::number;
8813 return i;
8814 }
8815yy8:
8816 yyaccept = 1;
8817 ++i;
8818 marker = i;
8819 yych = i < end ? *i : 0;
8820 switch (yych) {
8821 case '.': goto yy16;
8822 case '0':
8823 case '1':
8824 case '2':
8825 case '3':
8826 case '4':
8827 case '5':
8828 case '6':
8829 case '7':
8830 case '8':
8831 case '9': goto yy8;
8832 case 'E':
8833 case 'e': goto yy18;
8834 default: goto yy7;
8835 }
8836yy9:
8837 yyaccept = 0;
8838 ++i;
8839 marker = i;
8840 yych = i < end ? *i : 0;
8841 switch (yych) {
8842 case 'a': goto yy19;
8843 default: goto yy2;
8844 }
8845yy10:
8846 yyaccept = 0;
8847 ++i;
8848 marker = i;
8849 yych = i < end ? *i : 0;
8850 switch (yych) {
8851 case 'u': goto yy20;
8852 default: goto yy2;
8853 }
8854yy11:
8855 yyaccept = 0;
8856 ++i;
8857 marker = i;
8858 yych = i < end ? *i : 0;
8859 switch (yych) {
8860 case 'r': goto yy21;
8861 default: goto yy2;
8862 }
8863yy12:
8864 ++i;
8865 yych = i < end ? *i : 0;
8866yy13:
8867 switch (yych) {
8868 case '"': goto yy14;
8869 default:
8870 if (i >= end) goto yy17;
8871 goto yy12;
8872 }
8873yy14:
8874 yyaccept = 2;
8875 ++i;
8876 marker = i;
8877 yych = i < end ? *i : 0;
8878 switch (yych) {
8879 case 0x08:
8880 case '\t':
8881 case '\v':
8882 case '\f':
8883 case ' ': goto yy22;
8884 case ':': goto yy23;
8885 default: goto yy15;
8886 }
8887yy15:
8888 {
8889 color = TextEditor::Color::string;
8890 return i;
8891 }
8892yy16:
8893 ++i;
8894 yych = i < end ? *i : 0;
8895 switch (yych) {
8896 case '0':
8897 case '1':
8898 case '2':
8899 case '3':
8900 case '4':
8901 case '5':
8902 case '6':
8903 case '7':
8904 case '8':
8905 case '9': goto yy24;
8906 default: goto yy17;
8907 }
8908yy17:
8909 i = marker;
8910 switch (yyaccept) {
8911 case 0: goto yy2;
8912 case 1: goto yy7;
8913 default: goto yy15;
8914 }
8915yy18:
8916 ++i;
8917 yych = i < end ? *i : 0;
8918 switch (yych) {
8919 case '+':
8920 case '-': goto yy25;
8921 case '0':
8922 case '1':
8923 case '2':
8924 case '3':
8925 case '4':
8926 case '5':
8927 case '6':
8928 case '7':
8929 case '8':
8930 case '9': goto yy26;
8931 default: goto yy17;
8932 }
8933yy19:
8934 ++i;
8935 yych = i < end ? *i : 0;
8936 switch (yych) {
8937 case 'l': goto yy27;
8938 default: goto yy17;
8939 }
8940yy20:
8941 ++i;
8942 yych = i < end ? *i : 0;
8943 switch (yych) {
8944 case 'l': goto yy28;
8945 default: goto yy17;
8946 }
8947yy21:
8948 ++i;
8949 yych = i < end ? *i : 0;
8950 switch (yych) {
8951 case 'u': goto yy29;
8952 default: goto yy17;
8953 }
8954yy22:
8955 ++i;
8956 yych = i < end ? *i : 0;
8957 switch (yych) {
8958 case 0x08:
8959 case '\t':
8960 case '\v':
8961 case '\f':
8962 case ' ': goto yy22;
8963 case ':': goto yy23;
8964 default: goto yy17;
8965 }
8966yy23:
8967 ++i;
8968 {
8969 color = TextEditor::Color::identifier;
8970 return i;
8971 }
8972yy24:
8973 yyaccept = 1;
8974 ++i;
8975 marker = i;
8976 yych = i < end ? *i : 0;
8977 switch (yych) {
8978 case '0':
8979 case '1':
8980 case '2':
8981 case '3':
8982 case '4':
8983 case '5':
8984 case '6':
8985 case '7':
8986 case '8':
8987 case '9': goto yy24;
8988 case 'E':
8989 case 'e': goto yy18;
8990 default: goto yy7;
8991 }
8992yy25:
8993 ++i;
8994 yych = i < end ? *i : 0;
8995 switch (yych) {
8996 case '0':
8997 case '1':
8998 case '2':
8999 case '3':
9000 case '4':
9001 case '5':
9002 case '6':
9003 case '7':
9004 case '8':
9005 case '9': goto yy26;
9006 default: goto yy17;
9007 }
9008yy26:
9009 ++i;
9010 yych = i < end ? *i : 0;
9011 switch (yych) {
9012 case '0':
9013 case '1':
9014 case '2':
9015 case '3':
9016 case '4':
9017 case '5':
9018 case '6':
9019 case '7':
9020 case '8':
9021 case '9': goto yy26;
9022 default: goto yy7;
9023 }
9024yy27:
9025 ++i;
9026 yych = i < end ? *i : 0;
9027 switch (yych) {
9028 case 's': goto yy29;
9029 default: goto yy17;
9030 }
9031yy28:
9032 ++i;
9033 yych = i < end ? *i : 0;
9034 switch (yych) {
9035 case 'l': goto yy30;
9036 default: goto yy17;
9037 }
9038yy29:
9039 ++i;
9040 yych = i < end ? *i : 0;
9041 switch (yych) {
9042 case 'e': goto yy30;
9043 default: goto yy17;
9044 }
9045yy30:
9046 ++i;
9047 {
9048 color = TextEditor::Color::knownIdentifier;
9049 return i;
9050 }
9051yy31:
9052 { return start; }
9053}
9054
9055}
9056
9057
9058//
9059// TextEditor::Language::Json
9060//
9061
9062const TextEditor::Language* TextEditor::Language::Json() {
9063 static bool initialized = false;
9064 static TextEditor::Language language;
9065
9066 if (!initialized) {
9067 language.name = "JSON";
9068
9069 static const char* const keywords[] = {
9070 "false", "null", "true"
9071 };
9072
9073 for (auto& keyword : keywords) { language.keywords.insert(keyword); }
9074
9075 language.customTokenizer = tokenizeJson;
9076 initialized = true;
9077 }
9078
9079 return &language;
9080}
9081
9082
9083//
9084// tokenizeMarkdown
9085//
9086
9087static TextEditor::Iterator tokenizeMarkdown(TextEditor::Iterator start, TextEditor::Iterator end, TextEditor::Color& color) {
9088 TextEditor::Iterator i = start;
9089 TextEditor::Iterator marker;
9090
9091
9092{
9093 ImWchar yych;
9094 yych = i < end ? *i : 0;
9095 switch (yych) {
9096 case '!': goto yy3;
9097 case '#': goto yy4;
9098 case '*': goto yy6;
9099 case '+': goto yy7;
9100 case '-': goto yy8;
9101 case '0':
9102 case '1':
9103 case '2':
9104 case '3':
9105 case '4':
9106 case '5':
9107 case '6':
9108 case '7':
9109 case '8':
9110 case '9': goto yy10;
9111 case ':':
9112 case '|': goto yy11;
9113 case '<': goto yy12;
9114 case '[': goto yy13;
9115 case '`': goto yy14;
9116 case '~': goto yy15;
9117 default:
9118 if (i >= end) goto yy37;
9119 goto yy1;
9120 }
9121yy1:
9122 ++i;
9123yy2:
9124 { return start; }
9125yy3:
9126 ++i;
9127 marker = i;
9128 yych = i < end ? *i : 0;
9129 switch (yych) {
9130 case '[': goto yy16;
9131 default: goto yy2;
9132 }
9133yy4:
9134 ++i;
9135 yych = i < end ? *i : 0;
9136 switch (yych) {
9137 case '\n': goto yy5;
9138 default:
9139 if (i >= end) goto yy5;
9140 goto yy4;
9141 }
9142yy5:
9143 {
9144 color = TextEditor::Color::declaration;
9145 return i;
9146 }
9147yy6:
9148 ++i;
9149 marker = i;
9150 yych = i < end ? *i : 0;
9151 switch (yych) {
9152 case ' ': goto yy11;
9153 case '*': goto yy20;
9154 default:
9155 if (i >= end) goto yy2;
9156 goto yy18;
9157 }
9158yy7:
9159 ++i;
9160 yych = i < end ? *i : 0;
9161 switch (yych) {
9162 case ' ': goto yy11;
9163 default: goto yy2;
9164 }
9165yy8:
9166 ++i;
9167 yych = i < end ? *i : 0;
9168 switch (yych) {
9169 case ' ': goto yy11;
9170 default: goto yy9;
9171 }
9172yy9:
9173 {
9174 color = TextEditor::Color::punctuation;
9175 return i;
9176 }
9177yy10:
9178 ++i;
9179 marker = i;
9180 yych = i < end ? *i : 0;
9181 switch (yych) {
9182 case '.': goto yy21;
9183 case '0':
9184 case '1':
9185 case '2':
9186 case '3':
9187 case '4':
9188 case '5':
9189 case '6':
9190 case '7':
9191 case '8':
9192 case '9': goto yy22;
9193 default: goto yy2;
9194 }
9195yy11:
9196 ++i;
9197 goto yy9;
9198yy12:
9199 ++i;
9200 marker = i;
9201 yych = i < end ? *i : 0;
9202 switch (yych) {
9203 case 'A':
9204 case 'B':
9205 case 'C':
9206 case 'D':
9207 case 'E':
9208 case 'F':
9209 case 'G':
9210 case 'H':
9211 case 'I':
9212 case 'J':
9213 case 'K':
9214 case 'L':
9215 case 'M':
9216 case 'N':
9217 case 'O':
9218 case 'P':
9219 case 'Q':
9220 case 'R':
9221 case 'S':
9222 case 'T':
9223 case 'U':
9224 case 'V':
9225 case 'W':
9226 case 'X':
9227 case 'Y':
9228 case 'Z':
9229 case 'a':
9230 case 'b':
9231 case 'c':
9232 case 'd':
9233 case 'e':
9234 case 'f':
9235 case 'g':
9236 case 'h':
9237 case 'i':
9238 case 'j':
9239 case 'k':
9240 case 'l':
9241 case 'm':
9242 case 'n':
9243 case 'o':
9244 case 'p':
9245 case 'q':
9246 case 'r':
9247 case 's':
9248 case 't':
9249 case 'u':
9250 case 'v':
9251 case 'w':
9252 case 'x':
9253 case 'y':
9254 case 'z': goto yy23;
9255 default: goto yy2;
9256 }
9257yy13:
9258 ++i;
9259 marker = i;
9260 yych = i < end ? *i : 0;
9261 if (yych <= 0x00) {
9262 if (i >= end) goto yy2;
9263 goto yy16;
9264 }
9265 goto yy17;
9266yy14:
9267 ++i;
9268 marker = i;
9269 yych = i < end ? *i : 0;
9270 if (yych <= 0x00) {
9271 if (i >= end) goto yy2;
9272 goto yy25;
9273 }
9274 goto yy26;
9275yy15:
9276 ++i;
9277 marker = i;
9278 yych = i < end ? *i : 0;
9279 switch (yych) {
9280 case '~': goto yy28;
9281 default: goto yy2;
9282 }
9283yy16:
9284 ++i;
9285 yych = i < end ? *i : 0;
9286yy17:
9287 switch (yych) {
9288 case ']': goto yy24;
9289 default:
9290 if (i >= end) goto yy19;
9291 goto yy16;
9292 }
9293yy18:
9294 ++i;
9295 yych = i < end ? *i : 0;
9296 switch (yych) {
9297 case ' ': goto yy19;
9298 case '*': goto yy29;
9299 default:
9300 if (i >= end) goto yy19;
9301 goto yy18;
9302 }
9303yy19:
9304 i = marker;
9305 goto yy2;
9306yy20:
9307 ++i;
9308 yych = i < end ? *i : 0;
9309 switch (yych) {
9310 case '*': goto yy19;
9311 default:
9312 if (i >= end) goto yy19;
9313 goto yy30;
9314 }
9315yy21:
9316 ++i;
9317 yych = i < end ? *i : 0;
9318 switch (yych) {
9319 case ' ': goto yy11;
9320 default: goto yy19;
9321 }
9322yy22:
9323 ++i;
9324 yych = i < end ? *i : 0;
9325 switch (yych) {
9326 case '.': goto yy21;
9327 case '0':
9328 case '1':
9329 case '2':
9330 case '3':
9331 case '4':
9332 case '5':
9333 case '6':
9334 case '7':
9335 case '8':
9336 case '9': goto yy22;
9337 default: goto yy19;
9338 }
9339yy23:
9340 ++i;
9341 yych = i < end ? *i : 0;
9342 switch (yych) {
9343 case '>': goto yy31;
9344 case 'A':
9345 case 'B':
9346 case 'C':
9347 case 'D':
9348 case 'E':
9349 case 'F':
9350 case 'G':
9351 case 'H':
9352 case 'I':
9353 case 'J':
9354 case 'K':
9355 case 'L':
9356 case 'M':
9357 case 'N':
9358 case 'O':
9359 case 'P':
9360 case 'Q':
9361 case 'R':
9362 case 'S':
9363 case 'T':
9364 case 'U':
9365 case 'V':
9366 case 'W':
9367 case 'X':
9368 case 'Y':
9369 case 'Z':
9370 case 'a':
9371 case 'b':
9372 case 'c':
9373 case 'd':
9374 case 'e':
9375 case 'f':
9376 case 'g':
9377 case 'h':
9378 case 'i':
9379 case 'j':
9380 case 'k':
9381 case 'l':
9382 case 'm':
9383 case 'n':
9384 case 'o':
9385 case 'p':
9386 case 'q':
9387 case 'r':
9388 case 's':
9389 case 't':
9390 case 'u':
9391 case 'v':
9392 case 'w':
9393 case 'x':
9394 case 'y':
9395 case 'z': goto yy23;
9396 default: goto yy19;
9397 }
9398yy24:
9399 ++i;
9400 yych = i < end ? *i : 0;
9401 switch (yych) {
9402 case '(': goto yy32;
9403 default: goto yy19;
9404 }
9405yy25:
9406 ++i;
9407 yych = i < end ? *i : 0;
9408yy26:
9409 switch (yych) {
9410 case '`': goto yy27;
9411 default:
9412 if (i >= end) goto yy19;
9413 goto yy25;
9414 }
9415yy27:
9416 ++i;
9417 {
9418 color = TextEditor::Color::string;
9419 return i;
9420 }
9421yy28:
9422 ++i;
9423 yych = i < end ? *i : 0;
9424 switch (yych) {
9425 case '~': goto yy19;
9426 default:
9427 if (i >= end) goto yy19;
9428 goto yy33;
9429 }
9430yy29:
9431 ++i;
9432 {
9433 color = TextEditor::Color::number;
9434 return i;
9435 }
9436yy30:
9437 ++i;
9438 yych = i < end ? *i : 0;
9439 switch (yych) {
9440 case '*': goto yy34;
9441 default:
9442 if (i >= end) goto yy19;
9443 goto yy30;
9444 }
9445yy31:
9446 ++i;
9447 {
9448 color = TextEditor::Color::keyword;
9449 return i;
9450 }
9451yy32:
9452 ++i;
9453 yych = i < end ? *i : 0;
9454 switch (yych) {
9455 case ')': goto yy35;
9456 default:
9457 if (i >= end) goto yy19;
9458 goto yy32;
9459 }
9460yy33:
9461 ++i;
9462 yych = i < end ? *i : 0;
9463 switch (yych) {
9464 case '~': goto yy36;
9465 default:
9466 if (i >= end) goto yy19;
9467 goto yy33;
9468 }
9469yy34:
9470 ++i;
9471 yych = i < end ? *i : 0;
9472 switch (yych) {
9473 case '*': goto yy29;
9474 default: goto yy19;
9475 }
9476yy35:
9477 ++i;
9478 {
9479 color = TextEditor::Color::identifier;
9480 return i;
9481 }
9482yy36:
9483 ++i;
9484 yych = i < end ? *i : 0;
9485 switch (yych) {
9486 case '~': goto yy29;
9487 default: goto yy19;
9488 }
9489yy37:
9490 { return start; }
9491}
9492
9493}
9494
9495
9496//
9497// TextEditor::Language::Markdown
9498//
9499
9500const TextEditor::Language* TextEditor::Language::Markdown() {
9501 static bool initialized = false;
9502 static TextEditor::Language language;
9503
9504 if (!initialized) {
9505 language.name = "Markdown";
9506 language.commentStart = "<!--";
9507 language.commentEnd = "-->";
9508
9509 language.customTokenizer = tokenizeMarkdown;
9510 initialized = true;
9511 }
9512
9513 return &language;
9514}
9515
9516
9517//
9518// TextEditor::Language::Sql
9519//
9520
9521const TextEditor::Language* TextEditor::Language::Sql() {
9522 static bool initialized = false;
9523 static TextEditor::Language language;
9524
9525 if (!initialized) {
9526 language.name = "SQL";
9527 language.caseSensitive = false;
9528 language.singleLineComment = "--";
9529 language.commentStart = "/*";
9530 language.commentEnd = "*/";
9531 language.hasSingleQuotedStrings = true;
9532 language.hasDoubleQuotedStrings = true;
9533 language.stringEscape = '\\';
9534
9535 static const char* const keywords[] = {
9536 "abs", "absent", "acos", "all", "allocate", "alter", "and", "any", "any_value", "are", "array", "array_agg",
9537 "array_max_cardinality", "as", "asensitive", "asin", "asymmetric", "at", "atan", "atomic", "authorization",
9538 "avg", "begin", "begin_frame", "begin_partition", "between", "bigint", "binary", "blob", "boolean", "both",
9539 "btrim", "by", "call", "called", "cardinality", "cascaded", "case", "cast", "ceil", "ceiling", "char",
9540 "character", "character_length", "char_length", "check", "classifier", "clob", "close", "coalesce", "collate",
9541 "collect", "column", "commit", "condition", "connect", "constraint", "contains", "convert", "copy", "corr",
9542 "corresponding", "cos", "cosh", "count", "covar_pop", "covar_samp", "create", "cross", "cube", "cume_dist",
9543 "current", "current_catalog", "current_date", "current_default_transform_group", "current_path", "current_role",
9544 "current_row", "current_schema", "current_time", "current_timestamp", "current_transform_group_for_type",
9545 "current_user", "cursor", "cycle", "date", "day", "deallocate", "dec", "decfloat", "decimal", "declare",
9546 "default", "define", "delete", "dense_rank", "deref", "describe", "deterministic", "disconnect", "distinct",
9547 "double", "drop", "dynamic", "each", "element", "else", "empty", "end", "end-exec", "end_frame", "end_partition",
9548 "equals", "escape", "every", "except", "exec", "execute", "exists", "exp", "external", "extract", "false", "fetch",
9549 "filter", "first_value", "float", "floor", "for", "foreign", "frame_row", "free", "from", "full", "function",
9550 "fusion", "get", "global", "grant", "greatest", "group", "grouping", "groups", "having", "hold", "hour",
9551 "identity", "in", "indicator", "initial", "inner", "inout", "insensitive", "insert", "int", "integer",
9552 "intersect", "intersection", "interval", "into", "is", "join", "json", "json_array", "json_arrayagg",
9553 "json_exists", "json_object", "json_objectagg", "json_query", "json_scalar", "json_serialize", "json_table",
9554 "json_table_primitive", "json_value", "lag", "language", "large", "last_value", "lateral", "lead", "leading",
9555 "least", "left", "like", "like_regex", "limit", "listagg", "ln", "local", "localtime", "localtimestamp", "log", "log10",
9556 "lower", "lpad", "ltrim", "match", "matches", "match_number", "match_recognize", "max", "member", "merge", "method",
9557 "min", "minute", "mod", "modifies", "module", "month", "multiset", "national", "natural", "nchar", "nclob", "new",
9558 "no", "none", "normalize", "not", "nth_value", "ntile", "null", "nullif", "numeric", "occurrences_regex",
9559 "octet_length", "of", "offset", "old", "omit", "on", "one", "only", "open", "or", "order", "out", "outer", "over",
9560 "overlaps", "overlay", "parameter", "partition", "pattern", "per", "percent", "percentile_cont", "percentile_disc",
9561 "percent_rank", "period", "portion", "position", "position_regex", "power", "precedes", "precision", "prepare", "primary",
9562 "procedure", "ptf", "range", "rank", "reads", "real", "recursive", "ref", "references", "referencing", "regr_avgx",
9563 "regr_avgy", "regr_count", "regr_intercept", "regr_r2", "regr_slope", "regr_sxx", "regr_sxy", "regr_syy", "release",
9564 "result", "return", "returns", "revoke", "right", "rollback", "rollup", "row", "rows", "row_number", "rpad", "running",
9565 "savepoint", "scope", "scroll", "search", "second", "seek", "select", "sensitive", "session_user", "set", "show", "similar",
9566 "sin", "sinh", "skip", "smallint", "some", "specific", "specifictype", "sql", "sqlexception", "sqlstate", "sqlwarning", "sqrt",
9567 "start", "static", "stddev_pop", "stddev_samp", "submultiset", "subset", "substring", "substring_regex", "succeeds",
9568 "sum", "symmetric", "system", "system_time", "system_user", "table", "tablesample", "tan", "tanh", "then", "time",
9569 "timestamp", "timezone_hour", "timezone_minute", "to", "trailing", "translate", "translate_regex", "translation",
9570 "treat", "trigger", "trim", "trim_array", "true", "truncate", "uescape", "union", "unique", "unknown", "unnest",
9571 "update", "upper", "user", "using", "value", "values", "value_of", "varbinary", "varchar", "varying", "var_pop",
9572 "var_samp", "versioning", "when", "whenever", "where", "width_bucket", "window", "with", "within", "without", "year"
9573 };
9574
9575 for (auto& keyword : keywords) { language.keywords.insert(keyword); }
9576
9577 language.isPunctuation = isCStylePunctuation;
9578 language.getIdentifier = getCStyleIdentifier;
9579 language.getNumber = getCStyleNumber;
9580 initialized = true;
9581 }
9582
9583 return &language;
9584}