From f4b47333be1f68b1a0475aadf8c0bfae2bf987ac Mon Sep 17 00:00:00 2001
From: Arthur Sonzogni <sonzogniarthur@gmail.com>
Date: Thu, 6 Oct 2022 21:16:55 +0200
Subject: [PATCH] Featre: Support ctrl+arrow in input. (#494)

CTRL+LEFT: Move the cursor to the beginning of the word.
CTRL+RIGHT: Move the cursor to the beginning of the word.

This was requested by:
https://github.com/ArthurSonzogni/FTXUI/issues/490
---
 CHANGELOG.md                       |    1 +
 include/ftxui/component/event.hpp  |    5 +
 include/ftxui/screen/string.hpp    |   27 +
 src/ftxui/component/event.cpp      |   44 +-
 src/ftxui/component/input.cpp      |   75 +-
 src/ftxui/component/input_test.cpp |  118 ++
 src/ftxui/screen/string.cpp        | 1740 ++++++++++++++++++++++++----
 src/ftxui/screen/string_test.cpp   |   16 +
 8 files changed, 1776 insertions(+), 250 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index eb1378e1..1c725796 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -20,6 +20,7 @@ current (development)
     - multiple directions.
     - multiple colors.
     - various values (value, min, max, increment).
+- Feature: `Input` supports CTRL+Left and CTRL+Right
 - Improvement: The `Menu` keeps the focus when an entry is selected with the
   mouse.
 - Bug: Add implementation of `ButtonOption::Border()`. It was missing.
diff --git a/include/ftxui/component/event.hpp b/include/ftxui/component/event.hpp
index d226c9c8..6de33b46 100644
--- a/include/ftxui/component/event.hpp
+++ b/include/ftxui/component/event.hpp
@@ -38,6 +38,11 @@ struct Event {
   static const Event ArrowUp;
   static const Event ArrowDown;
 
+  static const Event ArrowLeftCtrl;
+  static const Event ArrowRightCtrl;
+  static const Event ArrowUpCtrl;
+  static const Event ArrowDownCtrl;
+
   // --- Other ---
   static const Event Backspace;
   static const Event Delete;
diff --git a/include/ftxui/screen/string.hpp b/include/ftxui/screen/string.hpp
index cfc37710..e1a20d5b 100644
--- a/include/ftxui/screen/string.hpp
+++ b/include/ftxui/screen/string.hpp
@@ -26,6 +26,33 @@ int GlyphPosition(const std::string& input,
 // Returns the number of glyphs in |input|.
 int GlyphCount(const std::string& input);
 
+// Properties from:
+// https://www.unicode.org/Public/UCD/latest/ucd/auxiliary/WordBreakProperty.txt
+enum class WordBreakProperty {
+  ALetter,
+  CR,
+  Double_Quote,
+  Extend,
+  ExtendNumLet,
+  Format,
+  Hebrew_Letter,
+  Katakana,
+  LF,
+  MidLetter,
+  MidNum,
+  MidNumLet,
+  Newline,
+  Numeric,
+  Regional_Indicator,
+  Single_Quote,
+  WSegSpace,
+  ZWJ,
+};
+std::vector<WordBreakProperty> Utf8ToWordBreakProperty(
+    const std::string& input);
+
+bool IsWordBreakingCharacter(const std::string& input, size_t glyph_index);
+
 // Map every cells drawn by |input| to their corresponding Glyphs. Half-size
 // Glyphs takes one cell, full-size Glyphs take two cells.
 std::vector<int> CellToGlyphIndex(const std::string& input);
diff --git a/src/ftxui/component/event.cpp b/src/ftxui/component/event.cpp
index 81a3629c..57d746af 100644
--- a/src/ftxui/component/event.cpp
+++ b/src/ftxui/component/event.cpp
@@ -51,26 +51,30 @@ Event Event::CursorReporting(std::string input, int x, int y) {
 }
 
 // --- Arrow ---
-const Event Event::ArrowLeft = Event::Special("\x1B[D");       // NOLINT
-const Event Event::ArrowRight = Event::Special("\x1B[C");      // NOLINT
-const Event Event::ArrowUp = Event::Special("\x1B[A");         // NOLINT
-const Event Event::ArrowDown = Event::Special("\x1B[B");       // NOLINT
-const Event Event::Backspace = Event::Special({127});          // NOLINT
-const Event Event::Delete = Event::Special("\x1B[3~");         // NOLINT
-const Event Event::Escape = Event::Special("\x1B");            // NOLINT
-const Event Event::Return = Event::Special({10});              // NOLINT
-const Event Event::Tab = Event::Special({9});                  // NOLINT
-const Event Event::TabReverse = Event::Special({27, 91, 90});  // NOLINT
-const Event Event::F1 = Event::Special("\x1B[OP");             // NOLINT
-const Event Event::F2 = Event::Special("\x1B[OQ");             // NOLINT
-const Event Event::F3 = Event::Special("\x1B[OR");             // NOLINT
-const Event Event::F4 = Event::Special("\x1B[OS");             // NOLINT
-const Event Event::F5 = Event::Special("\x1B[15~");            // NOLINT
-const Event Event::F6 = Event::Special("\x1B[17~");            // NOLINT
-const Event Event::F7 = Event::Special("\x1B[18~");            // NOLINT
-const Event Event::F8 = Event::Special("\x1B[19~");            // NOLINT
-const Event Event::F9 = Event::Special("\x1B[20~");            // NOLINT
-const Event Event::F10 = Event::Special("\x1B[21~");           // NOLINT
+const Event Event::ArrowLeft = Event::Special("\x1B[D");          // NOLINT
+const Event Event::ArrowRight = Event::Special("\x1B[C");         // NOLINT
+const Event Event::ArrowUp = Event::Special("\x1B[A");            // NOLINT
+const Event Event::ArrowDown = Event::Special("\x1B[B");          // NOLINT
+const Event Event::ArrowLeftCtrl = Event::Special("\x1B[1;5D");   // NOLINT
+const Event Event::ArrowRightCtrl = Event::Special("\x1B[1;5C");  // NOLINT
+const Event Event::ArrowUpCtrl = Event::Special("\x1B[1;5A");     // NOLINT
+const Event Event::ArrowDownCtrl = Event::Special("\x1B[1;5B");   // NOLINT
+const Event Event::Backspace = Event::Special({127});             // NOLINT
+const Event Event::Delete = Event::Special("\x1B[3~");            // NOLINT
+const Event Event::Escape = Event::Special("\x1B");               // NOLINT
+const Event Event::Return = Event::Special({10});                 // NOLINT
+const Event Event::Tab = Event::Special({9});                     // NOLINT
+const Event Event::TabReverse = Event::Special({27, 91, 90});     // NOLINT
+const Event Event::F1 = Event::Special("\x1B[OP");                // NOLINT
+const Event Event::F2 = Event::Special("\x1B[OQ");                // NOLINT
+const Event Event::F3 = Event::Special("\x1B[OR");                // NOLINT
+const Event Event::F4 = Event::Special("\x1B[OS");                // NOLINT
+const Event Event::F5 = Event::Special("\x1B[15~");               // NOLINT
+const Event Event::F6 = Event::Special("\x1B[17~");               // NOLINT
+const Event Event::F7 = Event::Special("\x1B[18~");               // NOLINT
+const Event Event::F8 = Event::Special("\x1B[19~");               // NOLINT
+const Event Event::F9 = Event::Special("\x1B[20~");               // NOLINT
+const Event Event::F10 = Event::Special("\x1B[21~");              // NOLINT
 const Event Event::F11 = Event::Special("\x1B[21~");  // Doesn't exist // NOLINT
 const Event Event::F12 = Event::Special("\x1B[24~");  // NOLINT
 const Event Event::Home = Event::Special({27, 91, 72});           // NOLINT
diff --git a/src/ftxui/component/input.cpp b/src/ftxui/component/input.cpp
index 307cb6ca..cbd47836 100644
--- a/src/ftxui/component/input.cpp
+++ b/src/ftxui/component/input.cpp
@@ -22,6 +22,36 @@ namespace ftxui {
 
 namespace {
 
+// Group together several propertiej so they appear to form a similar group.
+// For instance, letters are grouped with number and form a single word.
+bool IsWordCharacter(WordBreakProperty property) {
+  switch (property) {
+    case WordBreakProperty::ALetter:
+    case WordBreakProperty::Hebrew_Letter:
+    case WordBreakProperty::Katakana:
+    case WordBreakProperty::Numeric:
+      return true;
+
+    case WordBreakProperty::CR:
+    case WordBreakProperty::Double_Quote:
+    case WordBreakProperty::LF:
+    case WordBreakProperty::MidLetter:
+    case WordBreakProperty::MidNum:
+    case WordBreakProperty::MidNumLet:
+    case WordBreakProperty::Newline:
+    case WordBreakProperty::Single_Quote:
+    case WordBreakProperty::WSegSpace:
+    // Unsure:
+    case WordBreakProperty::Extend:
+    case WordBreakProperty::ExtendNumLet:
+    case WordBreakProperty::Format:
+    case WordBreakProperty::Regional_Indicator:
+    case WordBreakProperty::ZWJ:
+      return false;
+  };
+  return true; // NOT_REACHED();
+};
+
 std::string PasswordField(size_t size) {
   std::string out;
   out.reserve(2 * size);
@@ -111,7 +141,6 @@ class InputBase : public ComponentBase {
     if (event.is_mouse()) {
       return OnMouseEvent(event);
     }
-
     std::string c;
 
     // Backspace.
@@ -149,6 +178,7 @@ class InputBase : public ComponentBase {
       return false;
     }
 
+    // Arrow
     if (event == Event::ArrowLeft && cursor_position() > 0) {
       cursor_position()--;
       return true;
@@ -160,6 +190,16 @@ class InputBase : public ComponentBase {
       return true;
     }
 
+    // CTRL + Arrow:
+    if (event == Event::ArrowLeftCtrl) {
+      HandleLeftCtrl();
+      return true;
+    }
+    if (event == Event::ArrowRightCtrl) {
+      HandleRightCtrl();
+      return true;
+    }
+
     if (event == Event::Home) {
       cursor_position() = 0;
       return true;
@@ -182,6 +222,39 @@ class InputBase : public ComponentBase {
   }
 
  private:
+  void HandleLeftCtrl() {
+    auto properties = Utf8ToWordBreakProperty(*content_);
+
+    // Move left, as long as left is not a word character.
+    while (cursor_position() > 0 &&
+           !IsWordCharacter(properties[cursor_position() - 1])) {
+      cursor_position()--;
+    }
+
+    // Move left, as long as left is a word character:
+    while (cursor_position() > 0 &&
+           IsWordCharacter(properties[cursor_position() - 1])) {
+      cursor_position()--;
+    }
+  }
+
+  void HandleRightCtrl() {
+    auto properties = Utf8ToWordBreakProperty(*content_);
+    int max = (int)properties.size();
+
+    // Move right, as long as right is not a word character.
+    while (cursor_position() < max &&
+           !IsWordCharacter(properties[cursor_position()])) {
+      cursor_position()++;
+    }
+
+    // Move right, as long as right is a word character:
+    while (cursor_position() < max &&
+           IsWordCharacter(properties[cursor_position()])) {
+      cursor_position()++;
+    }
+  }
+
   bool OnMouseEvent(Event event) {
     hovered_ =
         box_.Contain(event.mouse().x, event.mouse().y) && CaptureMouse(event);
diff --git a/src/ftxui/component/input_test.cpp b/src/ftxui/component/input_test.cpp
index 21d8fddf..1ccc3d55 100644
--- a/src/ftxui/component/input_test.cpp
+++ b/src/ftxui/component/input_test.cpp
@@ -369,6 +369,124 @@ TEST(InputTest, MouseClickComplex) {
   EXPECT_EQ(option.cursor_position(), 4u);
 }
 
+TEST(InputTest, CtrlArrowLeft) {
+  std::string content = "word word 测ord wo测d word";
+  //                     0    5    10    15    20
+  std::string placeholder;
+  auto option = InputOption();
+  option.cursor_position = 22;
+  auto input = Input(&content, &placeholder, &option);
+
+  // Use CTRL+Left several time
+  EXPECT_TRUE(input->OnEvent(Event::ArrowLeftCtrl));
+  EXPECT_EQ(option.cursor_position(), 20u);
+
+  EXPECT_TRUE(input->OnEvent(Event::ArrowLeftCtrl));
+  EXPECT_EQ(option.cursor_position(), 15u);
+
+  EXPECT_TRUE(input->OnEvent(Event::ArrowLeftCtrl));
+  EXPECT_EQ(option.cursor_position(), 10u);
+
+  EXPECT_TRUE(input->OnEvent(Event::ArrowLeftCtrl));
+  EXPECT_EQ(option.cursor_position(), 5u);
+
+  EXPECT_TRUE(input->OnEvent(Event::ArrowLeftCtrl));
+  EXPECT_EQ(option.cursor_position(), 0u);
+
+  EXPECT_TRUE(input->OnEvent(Event::ArrowLeftCtrl));
+  EXPECT_EQ(option.cursor_position(), 0u);
+}
+
+TEST(InputTest, CtrlArrowLeft2) {
+  std::string content = "   word  word  测ord  wo测d  word   ";
+  //                     0  3  6  9 12  15  18 21  24 27 30 33
+  std::string placeholder;
+  auto option = InputOption();
+  option.cursor_position = 33;
+  auto input = Input(&content, &placeholder, &option);
+
+  // Use CTRL+Left several time
+  EXPECT_TRUE(input->OnEvent(Event::ArrowLeftCtrl));
+  EXPECT_EQ(option.cursor_position(), 27u);
+
+  EXPECT_TRUE(input->OnEvent(Event::ArrowLeftCtrl));
+  EXPECT_EQ(option.cursor_position(), 21u);
+
+  EXPECT_TRUE(input->OnEvent(Event::ArrowLeftCtrl));
+  EXPECT_EQ(option.cursor_position(), 15u);
+
+  EXPECT_TRUE(input->OnEvent(Event::ArrowLeftCtrl));
+  EXPECT_EQ(option.cursor_position(), 9u);
+
+  EXPECT_TRUE(input->OnEvent(Event::ArrowLeftCtrl));
+  EXPECT_EQ(option.cursor_position(), 3u);
+
+  EXPECT_TRUE(input->OnEvent(Event::ArrowLeftCtrl));
+  EXPECT_EQ(option.cursor_position(), 0u);
+
+  EXPECT_TRUE(input->OnEvent(Event::ArrowLeftCtrl));
+  EXPECT_EQ(option.cursor_position(), 0u);
+}
+
+TEST(InputTest, CtrlArrowRight) {
+  std::string content = "word word 测ord wo测d word";
+  //                     0    5    10    15    20
+  std::string placeholder;
+  auto option = InputOption();
+  option.cursor_position = 2;
+  auto input = Input(&content, &placeholder, &option);
+
+  // Use CTRL+Left several time
+  EXPECT_TRUE(input->OnEvent(Event::ArrowRightCtrl));
+  EXPECT_EQ(option.cursor_position(), 4);
+
+  EXPECT_TRUE(input->OnEvent(Event::ArrowRightCtrl));
+  EXPECT_EQ(option.cursor_position(), 9);
+
+  EXPECT_TRUE(input->OnEvent(Event::ArrowRightCtrl));
+  EXPECT_EQ(option.cursor_position(), 14u);
+
+  EXPECT_TRUE(input->OnEvent(Event::ArrowRightCtrl));
+  EXPECT_EQ(option.cursor_position(), 19u);
+
+  EXPECT_TRUE(input->OnEvent(Event::ArrowRightCtrl));
+  EXPECT_EQ(option.cursor_position(), 24u);
+
+  EXPECT_TRUE(input->OnEvent(Event::ArrowRightCtrl));
+  EXPECT_EQ(option.cursor_position(), 24u);
+}
+
+TEST(InputTest, CtrlArrowRight2) {
+  std::string content = "   word  word  测ord  wo测d  word   ";
+  //                     0  3  6  9 12  15  18 21  24 27 30 33
+  std::string placeholder;
+  auto option = InputOption();
+  option.cursor_position = 0;
+  auto input = Input(&content, &placeholder, &option);
+
+  // Use CTRL+Left several time
+  EXPECT_TRUE(input->OnEvent(Event::ArrowRightCtrl));
+  EXPECT_EQ(option.cursor_position(), 7u);
+
+  EXPECT_TRUE(input->OnEvent(Event::ArrowRightCtrl));
+  EXPECT_EQ(option.cursor_position(), 13u);
+
+  EXPECT_TRUE(input->OnEvent(Event::ArrowRightCtrl));
+  EXPECT_EQ(option.cursor_position(), 19u);
+
+  EXPECT_TRUE(input->OnEvent(Event::ArrowRightCtrl));
+  EXPECT_EQ(option.cursor_position(), 25u);
+
+  EXPECT_TRUE(input->OnEvent(Event::ArrowRightCtrl));
+  EXPECT_EQ(option.cursor_position(), 31u);
+
+  EXPECT_TRUE(input->OnEvent(Event::ArrowRightCtrl));
+  EXPECT_EQ(option.cursor_position(), 34u);
+
+  EXPECT_TRUE(input->OnEvent(Event::ArrowRightCtrl));
+  EXPECT_EQ(option.cursor_position(), 34u);
+}
+
 }  // namespace ftxui
 
 // Copyright 2021 Arthur Sonzogni. All rights reserved.
diff --git a/src/ftxui/screen/string.cpp b/src/ftxui/screen/string.cpp
index 37ed3cf9..faba9344 100644
--- a/src/ftxui/screen/string.cpp
+++ b/src/ftxui/screen/string.cpp
@@ -25,240 +25,1492 @@ struct Interval {
 // Sorted list of non-overlapping intervals of non-spacing characters
 // generated by "uniset +cat=Me +cat=Mn +cat=Cf -00AD +1160-11FF +200B c"
 // As of Unicode 13.0.0
-const std::array<Interval, 324> g_combining_characters = {
-    Interval{0x00300, 0x0036f}, Interval{0x00483, 0x00489},
-    Interval{0x00591, 0x005bd}, Interval{0x005bf, 0x005bf},
-    Interval{0x005c1, 0x005c2}, Interval{0x005c4, 0x005c5},
-    Interval{0x005c7, 0x005c7}, Interval{0x00610, 0x0061a},
-    Interval{0x0064b, 0x0065f}, Interval{0x00670, 0x00670},
-    Interval{0x006d6, 0x006dc}, Interval{0x006df, 0x006e4},
-    Interval{0x006e7, 0x006e8}, Interval{0x006ea, 0x006ed},
-    Interval{0x00711, 0x00711}, Interval{0x00730, 0x0074a},
-    Interval{0x007a6, 0x007b0}, Interval{0x007eb, 0x007f3},
-    Interval{0x007fd, 0x007fd}, Interval{0x00816, 0x00819},
-    Interval{0x0081b, 0x00823}, Interval{0x00825, 0x00827},
-    Interval{0x00829, 0x0082d}, Interval{0x00859, 0x0085b},
-    Interval{0x008d3, 0x008e1}, Interval{0x008e3, 0x00902},
-    Interval{0x0093a, 0x0093a}, Interval{0x0093c, 0x0093c},
-    Interval{0x00941, 0x00948}, Interval{0x0094d, 0x0094d},
-    Interval{0x00951, 0x00957}, Interval{0x00962, 0x00963},
-    Interval{0x00981, 0x00981}, Interval{0x009bc, 0x009bc},
-    Interval{0x009c1, 0x009c4}, Interval{0x009cd, 0x009cd},
-    Interval{0x009e2, 0x009e3}, Interval{0x009fe, 0x009fe},
-    Interval{0x00a01, 0x00a02}, Interval{0x00a3c, 0x00a3c},
-    Interval{0x00a41, 0x00a42}, Interval{0x00a47, 0x00a48},
-    Interval{0x00a4b, 0x00a4d}, Interval{0x00a51, 0x00a51},
-    Interval{0x00a70, 0x00a71}, Interval{0x00a75, 0x00a75},
-    Interval{0x00a81, 0x00a82}, Interval{0x00abc, 0x00abc},
-    Interval{0x00ac1, 0x00ac5}, Interval{0x00ac7, 0x00ac8},
-    Interval{0x00acd, 0x00acd}, Interval{0x00ae2, 0x00ae3},
-    Interval{0x00afa, 0x00aff}, Interval{0x00b01, 0x00b01},
-    Interval{0x00b3c, 0x00b3c}, Interval{0x00b3f, 0x00b3f},
-    Interval{0x00b41, 0x00b44}, Interval{0x00b4d, 0x00b4d},
-    Interval{0x00b55, 0x00b56}, Interval{0x00b62, 0x00b63},
-    Interval{0x00b82, 0x00b82}, Interval{0x00bc0, 0x00bc0},
-    Interval{0x00bcd, 0x00bcd}, Interval{0x00c00, 0x00c00},
-    Interval{0x00c04, 0x00c04}, Interval{0x00c3e, 0x00c40},
-    Interval{0x00c46, 0x00c48}, Interval{0x00c4a, 0x00c4d},
-    Interval{0x00c55, 0x00c56}, Interval{0x00c62, 0x00c63},
-    Interval{0x00c81, 0x00c81}, Interval{0x00cbc, 0x00cbc},
-    Interval{0x00cbf, 0x00cbf}, Interval{0x00cc6, 0x00cc6},
-    Interval{0x00ccc, 0x00ccd}, Interval{0x00ce2, 0x00ce3},
-    Interval{0x00d00, 0x00d01}, Interval{0x00d3b, 0x00d3c},
-    Interval{0x00d41, 0x00d44}, Interval{0x00d4d, 0x00d4d},
-    Interval{0x00d62, 0x00d63}, Interval{0x00d81, 0x00d81},
-    Interval{0x00dca, 0x00dca}, Interval{0x00dd2, 0x00dd4},
-    Interval{0x00dd6, 0x00dd6}, Interval{0x00e31, 0x00e31},
-    Interval{0x00e34, 0x00e3a}, Interval{0x00e47, 0x00e4e},
-    Interval{0x00eb1, 0x00eb1}, Interval{0x00eb4, 0x00ebc},
-    Interval{0x00ec8, 0x00ecd}, Interval{0x00f18, 0x00f19},
-    Interval{0x00f35, 0x00f35}, Interval{0x00f37, 0x00f37},
-    Interval{0x00f39, 0x00f39}, Interval{0x00f71, 0x00f7e},
-    Interval{0x00f80, 0x00f84}, Interval{0x00f86, 0x00f87},
-    Interval{0x00f8d, 0x00f97}, Interval{0x00f99, 0x00fbc},
-    Interval{0x00fc6, 0x00fc6}, Interval{0x0102d, 0x01030},
-    Interval{0x01032, 0x01037}, Interval{0x01039, 0x0103a},
-    Interval{0x0103d, 0x0103e}, Interval{0x01058, 0x01059},
-    Interval{0x0105e, 0x01060}, Interval{0x01071, 0x01074},
-    Interval{0x01082, 0x01082}, Interval{0x01085, 0x01086},
-    Interval{0x0108d, 0x0108d}, Interval{0x0109d, 0x0109d},
-    Interval{0x0135d, 0x0135f}, Interval{0x01712, 0x01714},
-    Interval{0x01732, 0x01734}, Interval{0x01752, 0x01753},
-    Interval{0x01772, 0x01773}, Interval{0x017b4, 0x017b5},
-    Interval{0x017b7, 0x017bd}, Interval{0x017c6, 0x017c6},
-    Interval{0x017c9, 0x017d3}, Interval{0x017dd, 0x017dd},
-    Interval{0x0180b, 0x0180d}, Interval{0x01885, 0x01886},
-    Interval{0x018a9, 0x018a9}, Interval{0x01920, 0x01922},
-    Interval{0x01927, 0x01928}, Interval{0x01932, 0x01932},
-    Interval{0x01939, 0x0193b}, Interval{0x01a17, 0x01a18},
-    Interval{0x01a1b, 0x01a1b}, Interval{0x01a56, 0x01a56},
-    Interval{0x01a58, 0x01a5e}, Interval{0x01a60, 0x01a60},
-    Interval{0x01a62, 0x01a62}, Interval{0x01a65, 0x01a6c},
-    Interval{0x01a73, 0x01a7c}, Interval{0x01a7f, 0x01a7f},
-    Interval{0x01ab0, 0x01ac0}, Interval{0x01b00, 0x01b03},
-    Interval{0x01b34, 0x01b34}, Interval{0x01b36, 0x01b3a},
-    Interval{0x01b3c, 0x01b3c}, Interval{0x01b42, 0x01b42},
-    Interval{0x01b6b, 0x01b73}, Interval{0x01b80, 0x01b81},
-    Interval{0x01ba2, 0x01ba5}, Interval{0x01ba8, 0x01ba9},
-    Interval{0x01bab, 0x01bad}, Interval{0x01be6, 0x01be6},
-    Interval{0x01be8, 0x01be9}, Interval{0x01bed, 0x01bed},
-    Interval{0x01bef, 0x01bf1}, Interval{0x01c2c, 0x01c33},
-    Interval{0x01c36, 0x01c37}, Interval{0x01cd0, 0x01cd2},
-    Interval{0x01cd4, 0x01ce0}, Interval{0x01ce2, 0x01ce8},
-    Interval{0x01ced, 0x01ced}, Interval{0x01cf4, 0x01cf4},
-    Interval{0x01cf8, 0x01cf9}, Interval{0x01dc0, 0x01df9},
-    Interval{0x01dfb, 0x01dff}, Interval{0x020d0, 0x020f0},
-    Interval{0x02cef, 0x02cf1}, Interval{0x02d7f, 0x02d7f},
-    Interval{0x02de0, 0x02dff}, Interval{0x0302a, 0x0302d},
-    Interval{0x03099, 0x0309a}, Interval{0x0a66f, 0x0a672},
-    Interval{0x0a674, 0x0a67d}, Interval{0x0a69e, 0x0a69f},
-    Interval{0x0a6f0, 0x0a6f1}, Interval{0x0a802, 0x0a802},
-    Interval{0x0a806, 0x0a806}, Interval{0x0a80b, 0x0a80b},
-    Interval{0x0a825, 0x0a826}, Interval{0x0a82c, 0x0a82c},
-    Interval{0x0a8c4, 0x0a8c5}, Interval{0x0a8e0, 0x0a8f1},
-    Interval{0x0a8ff, 0x0a8ff}, Interval{0x0a926, 0x0a92d},
-    Interval{0x0a947, 0x0a951}, Interval{0x0a980, 0x0a982},
-    Interval{0x0a9b3, 0x0a9b3}, Interval{0x0a9b6, 0x0a9b9},
-    Interval{0x0a9bc, 0x0a9bd}, Interval{0x0a9e5, 0x0a9e5},
-    Interval{0x0aa29, 0x0aa2e}, Interval{0x0aa31, 0x0aa32},
-    Interval{0x0aa35, 0x0aa36}, Interval{0x0aa43, 0x0aa43},
-    Interval{0x0aa4c, 0x0aa4c}, Interval{0x0aa7c, 0x0aa7c},
-    Interval{0x0aab0, 0x0aab0}, Interval{0x0aab2, 0x0aab4},
-    Interval{0x0aab7, 0x0aab8}, Interval{0x0aabe, 0x0aabf},
-    Interval{0x0aac1, 0x0aac1}, Interval{0x0aaec, 0x0aaed},
-    Interval{0x0aaf6, 0x0aaf6}, Interval{0x0abe5, 0x0abe5},
-    Interval{0x0abe8, 0x0abe8}, Interval{0x0abed, 0x0abed},
-    Interval{0x0fb1e, 0x0fb1e}, Interval{0x0fe00, 0x0fe0f},
-    Interval{0x0fe20, 0x0fe2f}, Interval{0x101fd, 0x101fd},
-    Interval{0x102e0, 0x102e0}, Interval{0x10376, 0x1037a},
-    Interval{0x10a01, 0x10a03}, Interval{0x10a05, 0x10a06},
-    Interval{0x10a0c, 0x10a0f}, Interval{0x10a38, 0x10a3a},
-    Interval{0x10a3f, 0x10a3f}, Interval{0x10ae5, 0x10ae6},
-    Interval{0x10d24, 0x10d27}, Interval{0x10eab, 0x10eac},
-    Interval{0x10f46, 0x10f50}, Interval{0x11001, 0x11001},
-    Interval{0x11038, 0x11046}, Interval{0x1107f, 0x11081},
-    Interval{0x110b3, 0x110b6}, Interval{0x110b9, 0x110ba},
-    Interval{0x11100, 0x11102}, Interval{0x11127, 0x1112b},
-    Interval{0x1112d, 0x11134}, Interval{0x11173, 0x11173},
-    Interval{0x11180, 0x11181}, Interval{0x111b6, 0x111be},
-    Interval{0x111c9, 0x111cc}, Interval{0x111cf, 0x111cf},
-    Interval{0x1122f, 0x11231}, Interval{0x11234, 0x11234},
-    Interval{0x11236, 0x11237}, Interval{0x1123e, 0x1123e},
-    Interval{0x112df, 0x112df}, Interval{0x112e3, 0x112ea},
-    Interval{0x11300, 0x11301}, Interval{0x1133b, 0x1133c},
-    Interval{0x11340, 0x11340}, Interval{0x11366, 0x1136c},
-    Interval{0x11370, 0x11374}, Interval{0x11438, 0x1143f},
-    Interval{0x11442, 0x11444}, Interval{0x11446, 0x11446},
-    Interval{0x1145e, 0x1145e}, Interval{0x114b3, 0x114b8},
-    Interval{0x114ba, 0x114ba}, Interval{0x114bf, 0x114c0},
-    Interval{0x114c2, 0x114c3}, Interval{0x115b2, 0x115b5},
-    Interval{0x115bc, 0x115bd}, Interval{0x115bf, 0x115c0},
-    Interval{0x115dc, 0x115dd}, Interval{0x11633, 0x1163a},
-    Interval{0x1163d, 0x1163d}, Interval{0x1163f, 0x11640},
-    Interval{0x116ab, 0x116ab}, Interval{0x116ad, 0x116ad},
-    Interval{0x116b0, 0x116b5}, Interval{0x116b7, 0x116b7},
-    Interval{0x1171d, 0x1171f}, Interval{0x11722, 0x11725},
-    Interval{0x11727, 0x1172b}, Interval{0x1182f, 0x11837},
-    Interval{0x11839, 0x1183a}, Interval{0x1193b, 0x1193c},
-    Interval{0x1193e, 0x1193e}, Interval{0x11943, 0x11943},
-    Interval{0x119d4, 0x119d7}, Interval{0x119da, 0x119db},
-    Interval{0x119e0, 0x119e0}, Interval{0x11a01, 0x11a0a},
-    Interval{0x11a33, 0x11a38}, Interval{0x11a3b, 0x11a3e},
-    Interval{0x11a47, 0x11a47}, Interval{0x11a51, 0x11a56},
-    Interval{0x11a59, 0x11a5b}, Interval{0x11a8a, 0x11a96},
-    Interval{0x11a98, 0x11a99}, Interval{0x11c30, 0x11c36},
-    Interval{0x11c38, 0x11c3d}, Interval{0x11c3f, 0x11c3f},
-    Interval{0x11c92, 0x11ca7}, Interval{0x11caa, 0x11cb0},
-    Interval{0x11cb2, 0x11cb3}, Interval{0x11cb5, 0x11cb6},
-    Interval{0x11d31, 0x11d36}, Interval{0x11d3a, 0x11d3a},
-    Interval{0x11d3c, 0x11d3d}, Interval{0x11d3f, 0x11d45},
-    Interval{0x11d47, 0x11d47}, Interval{0x11d90, 0x11d91},
-    Interval{0x11d95, 0x11d95}, Interval{0x11d97, 0x11d97},
-    Interval{0x11ef3, 0x11ef4}, Interval{0x16af0, 0x16af4},
-    Interval{0x16b30, 0x16b36}, Interval{0x16f4f, 0x16f4f},
-    Interval{0x16f8f, 0x16f92}, Interval{0x16fe4, 0x16fe4},
-    Interval{0x1bc9d, 0x1bc9e}, Interval{0x1d167, 0x1d169},
-    Interval{0x1d17b, 0x1d182}, Interval{0x1d185, 0x1d18b},
-    Interval{0x1d1aa, 0x1d1ad}, Interval{0x1d242, 0x1d244},
-    Interval{0x1da00, 0x1da36}, Interval{0x1da3b, 0x1da6c},
-    Interval{0x1da75, 0x1da75}, Interval{0x1da84, 0x1da84},
-    Interval{0x1da9b, 0x1da9f}, Interval{0x1daa1, 0x1daaf},
-    Interval{0x1e000, 0x1e006}, Interval{0x1e008, 0x1e018},
-    Interval{0x1e01b, 0x1e021}, Interval{0x1e023, 0x1e024},
-    Interval{0x1e026, 0x1e02a}, Interval{0x1e130, 0x1e136},
-    Interval{0x1e2ec, 0x1e2ef}, Interval{0x1e8d0, 0x1e8d6},
-    Interval{0x1e944, 0x1e94a}, Interval{0xe0100, 0xe01ef},
-};
+const std::array<Interval, 324> g_combining_characters = {{
+    {0x00300, 0x0036f}, {0x00483, 0x00489}, {0x00591, 0x005bd},
+    {0x005bf, 0x005bf}, {0x005c1, 0x005c2}, {0x005c4, 0x005c5},
+    {0x005c7, 0x005c7}, {0x00610, 0x0061a}, {0x0064b, 0x0065f},
+    {0x00670, 0x00670}, {0x006d6, 0x006dc}, {0x006df, 0x006e4},
+    {0x006e7, 0x006e8}, {0x006ea, 0x006ed}, {0x00711, 0x00711},
+    {0x00730, 0x0074a}, {0x007a6, 0x007b0}, {0x007eb, 0x007f3},
+    {0x007fd, 0x007fd}, {0x00816, 0x00819}, {0x0081b, 0x00823},
+    {0x00825, 0x00827}, {0x00829, 0x0082d}, {0x00859, 0x0085b},
+    {0x008d3, 0x008e1}, {0x008e3, 0x00902}, {0x0093a, 0x0093a},
+    {0x0093c, 0x0093c}, {0x00941, 0x00948}, {0x0094d, 0x0094d},
+    {0x00951, 0x00957}, {0x00962, 0x00963}, {0x00981, 0x00981},
+    {0x009bc, 0x009bc}, {0x009c1, 0x009c4}, {0x009cd, 0x009cd},
+    {0x009e2, 0x009e3}, {0x009fe, 0x009fe}, {0x00a01, 0x00a02},
+    {0x00a3c, 0x00a3c}, {0x00a41, 0x00a42}, {0x00a47, 0x00a48},
+    {0x00a4b, 0x00a4d}, {0x00a51, 0x00a51}, {0x00a70, 0x00a71},
+    {0x00a75, 0x00a75}, {0x00a81, 0x00a82}, {0x00abc, 0x00abc},
+    {0x00ac1, 0x00ac5}, {0x00ac7, 0x00ac8}, {0x00acd, 0x00acd},
+    {0x00ae2, 0x00ae3}, {0x00afa, 0x00aff}, {0x00b01, 0x00b01},
+    {0x00b3c, 0x00b3c}, {0x00b3f, 0x00b3f}, {0x00b41, 0x00b44},
+    {0x00b4d, 0x00b4d}, {0x00b55, 0x00b56}, {0x00b62, 0x00b63},
+    {0x00b82, 0x00b82}, {0x00bc0, 0x00bc0}, {0x00bcd, 0x00bcd},
+    {0x00c00, 0x00c00}, {0x00c04, 0x00c04}, {0x00c3e, 0x00c40},
+    {0x00c46, 0x00c48}, {0x00c4a, 0x00c4d}, {0x00c55, 0x00c56},
+    {0x00c62, 0x00c63}, {0x00c81, 0x00c81}, {0x00cbc, 0x00cbc},
+    {0x00cbf, 0x00cbf}, {0x00cc6, 0x00cc6}, {0x00ccc, 0x00ccd},
+    {0x00ce2, 0x00ce3}, {0x00d00, 0x00d01}, {0x00d3b, 0x00d3c},
+    {0x00d41, 0x00d44}, {0x00d4d, 0x00d4d}, {0x00d62, 0x00d63},
+    {0x00d81, 0x00d81}, {0x00dca, 0x00dca}, {0x00dd2, 0x00dd4},
+    {0x00dd6, 0x00dd6}, {0x00e31, 0x00e31}, {0x00e34, 0x00e3a},
+    {0x00e47, 0x00e4e}, {0x00eb1, 0x00eb1}, {0x00eb4, 0x00ebc},
+    {0x00ec8, 0x00ecd}, {0x00f18, 0x00f19}, {0x00f35, 0x00f35},
+    {0x00f37, 0x00f37}, {0x00f39, 0x00f39}, {0x00f71, 0x00f7e},
+    {0x00f80, 0x00f84}, {0x00f86, 0x00f87}, {0x00f8d, 0x00f97},
+    {0x00f99, 0x00fbc}, {0x00fc6, 0x00fc6}, {0x0102d, 0x01030},
+    {0x01032, 0x01037}, {0x01039, 0x0103a}, {0x0103d, 0x0103e},
+    {0x01058, 0x01059}, {0x0105e, 0x01060}, {0x01071, 0x01074},
+    {0x01082, 0x01082}, {0x01085, 0x01086}, {0x0108d, 0x0108d},
+    {0x0109d, 0x0109d}, {0x0135d, 0x0135f}, {0x01712, 0x01714},
+    {0x01732, 0x01734}, {0x01752, 0x01753}, {0x01772, 0x01773},
+    {0x017b4, 0x017b5}, {0x017b7, 0x017bd}, {0x017c6, 0x017c6},
+    {0x017c9, 0x017d3}, {0x017dd, 0x017dd}, {0x0180b, 0x0180d},
+    {0x01885, 0x01886}, {0x018a9, 0x018a9}, {0x01920, 0x01922},
+    {0x01927, 0x01928}, {0x01932, 0x01932}, {0x01939, 0x0193b},
+    {0x01a17, 0x01a18}, {0x01a1b, 0x01a1b}, {0x01a56, 0x01a56},
+    {0x01a58, 0x01a5e}, {0x01a60, 0x01a60}, {0x01a62, 0x01a62},
+    {0x01a65, 0x01a6c}, {0x01a73, 0x01a7c}, {0x01a7f, 0x01a7f},
+    {0x01ab0, 0x01ac0}, {0x01b00, 0x01b03}, {0x01b34, 0x01b34},
+    {0x01b36, 0x01b3a}, {0x01b3c, 0x01b3c}, {0x01b42, 0x01b42},
+    {0x01b6b, 0x01b73}, {0x01b80, 0x01b81}, {0x01ba2, 0x01ba5},
+    {0x01ba8, 0x01ba9}, {0x01bab, 0x01bad}, {0x01be6, 0x01be6},
+    {0x01be8, 0x01be9}, {0x01bed, 0x01bed}, {0x01bef, 0x01bf1},
+    {0x01c2c, 0x01c33}, {0x01c36, 0x01c37}, {0x01cd0, 0x01cd2},
+    {0x01cd4, 0x01ce0}, {0x01ce2, 0x01ce8}, {0x01ced, 0x01ced},
+    {0x01cf4, 0x01cf4}, {0x01cf8, 0x01cf9}, {0x01dc0, 0x01df9},
+    {0x01dfb, 0x01dff}, {0x020d0, 0x020f0}, {0x02cef, 0x02cf1},
+    {0x02d7f, 0x02d7f}, {0x02de0, 0x02dff}, {0x0302a, 0x0302d},
+    {0x03099, 0x0309a}, {0x0a66f, 0x0a672}, {0x0a674, 0x0a67d},
+    {0x0a69e, 0x0a69f}, {0x0a6f0, 0x0a6f1}, {0x0a802, 0x0a802},
+    {0x0a806, 0x0a806}, {0x0a80b, 0x0a80b}, {0x0a825, 0x0a826},
+    {0x0a82c, 0x0a82c}, {0x0a8c4, 0x0a8c5}, {0x0a8e0, 0x0a8f1},
+    {0x0a8ff, 0x0a8ff}, {0x0a926, 0x0a92d}, {0x0a947, 0x0a951},
+    {0x0a980, 0x0a982}, {0x0a9b3, 0x0a9b3}, {0x0a9b6, 0x0a9b9},
+    {0x0a9bc, 0x0a9bd}, {0x0a9e5, 0x0a9e5}, {0x0aa29, 0x0aa2e},
+    {0x0aa31, 0x0aa32}, {0x0aa35, 0x0aa36}, {0x0aa43, 0x0aa43},
+    {0x0aa4c, 0x0aa4c}, {0x0aa7c, 0x0aa7c}, {0x0aab0, 0x0aab0},
+    {0x0aab2, 0x0aab4}, {0x0aab7, 0x0aab8}, {0x0aabe, 0x0aabf},
+    {0x0aac1, 0x0aac1}, {0x0aaec, 0x0aaed}, {0x0aaf6, 0x0aaf6},
+    {0x0abe5, 0x0abe5}, {0x0abe8, 0x0abe8}, {0x0abed, 0x0abed},
+    {0x0fb1e, 0x0fb1e}, {0x0fe00, 0x0fe0f}, {0x0fe20, 0x0fe2f},
+    {0x101fd, 0x101fd}, {0x102e0, 0x102e0}, {0x10376, 0x1037a},
+    {0x10a01, 0x10a03}, {0x10a05, 0x10a06}, {0x10a0c, 0x10a0f},
+    {0x10a38, 0x10a3a}, {0x10a3f, 0x10a3f}, {0x10ae5, 0x10ae6},
+    {0x10d24, 0x10d27}, {0x10eab, 0x10eac}, {0x10f46, 0x10f50},
+    {0x11001, 0x11001}, {0x11038, 0x11046}, {0x1107f, 0x11081},
+    {0x110b3, 0x110b6}, {0x110b9, 0x110ba}, {0x11100, 0x11102},
+    {0x11127, 0x1112b}, {0x1112d, 0x11134}, {0x11173, 0x11173},
+    {0x11180, 0x11181}, {0x111b6, 0x111be}, {0x111c9, 0x111cc},
+    {0x111cf, 0x111cf}, {0x1122f, 0x11231}, {0x11234, 0x11234},
+    {0x11236, 0x11237}, {0x1123e, 0x1123e}, {0x112df, 0x112df},
+    {0x112e3, 0x112ea}, {0x11300, 0x11301}, {0x1133b, 0x1133c},
+    {0x11340, 0x11340}, {0x11366, 0x1136c}, {0x11370, 0x11374},
+    {0x11438, 0x1143f}, {0x11442, 0x11444}, {0x11446, 0x11446},
+    {0x1145e, 0x1145e}, {0x114b3, 0x114b8}, {0x114ba, 0x114ba},
+    {0x114bf, 0x114c0}, {0x114c2, 0x114c3}, {0x115b2, 0x115b5},
+    {0x115bc, 0x115bd}, {0x115bf, 0x115c0}, {0x115dc, 0x115dd},
+    {0x11633, 0x1163a}, {0x1163d, 0x1163d}, {0x1163f, 0x11640},
+    {0x116ab, 0x116ab}, {0x116ad, 0x116ad}, {0x116b0, 0x116b5},
+    {0x116b7, 0x116b7}, {0x1171d, 0x1171f}, {0x11722, 0x11725},
+    {0x11727, 0x1172b}, {0x1182f, 0x11837}, {0x11839, 0x1183a},
+    {0x1193b, 0x1193c}, {0x1193e, 0x1193e}, {0x11943, 0x11943},
+    {0x119d4, 0x119d7}, {0x119da, 0x119db}, {0x119e0, 0x119e0},
+    {0x11a01, 0x11a0a}, {0x11a33, 0x11a38}, {0x11a3b, 0x11a3e},
+    {0x11a47, 0x11a47}, {0x11a51, 0x11a56}, {0x11a59, 0x11a5b},
+    {0x11a8a, 0x11a96}, {0x11a98, 0x11a99}, {0x11c30, 0x11c36},
+    {0x11c38, 0x11c3d}, {0x11c3f, 0x11c3f}, {0x11c92, 0x11ca7},
+    {0x11caa, 0x11cb0}, {0x11cb2, 0x11cb3}, {0x11cb5, 0x11cb6},
+    {0x11d31, 0x11d36}, {0x11d3a, 0x11d3a}, {0x11d3c, 0x11d3d},
+    {0x11d3f, 0x11d45}, {0x11d47, 0x11d47}, {0x11d90, 0x11d91},
+    {0x11d95, 0x11d95}, {0x11d97, 0x11d97}, {0x11ef3, 0x11ef4},
+    {0x16af0, 0x16af4}, {0x16b30, 0x16b36}, {0x16f4f, 0x16f4f},
+    {0x16f8f, 0x16f92}, {0x16fe4, 0x16fe4}, {0x1bc9d, 0x1bc9e},
+    {0x1d167, 0x1d169}, {0x1d17b, 0x1d182}, {0x1d185, 0x1d18b},
+    {0x1d1aa, 0x1d1ad}, {0x1d242, 0x1d244}, {0x1da00, 0x1da36},
+    {0x1da3b, 0x1da6c}, {0x1da75, 0x1da75}, {0x1da84, 0x1da84},
+    {0x1da9b, 0x1da9f}, {0x1daa1, 0x1daaf}, {0x1e000, 0x1e006},
+    {0x1e008, 0x1e018}, {0x1e01b, 0x1e021}, {0x1e023, 0x1e024},
+    {0x1e026, 0x1e02a}, {0x1e130, 0x1e136}, {0x1e2ec, 0x1e2ef},
+    {0x1e8d0, 0x1e8d6}, {0x1e944, 0x1e94a}, {0xe0100, 0xe01ef},
+}};
 
 // As of Unicode 13.0.0
-const std::array<Interval, 116> g_full_width_characters = {
-    Interval{0x01100, 0x0115f}, Interval{0x0231a, 0x0231b},
-    Interval{0x02329, 0x0232a}, Interval{0x023e9, 0x023ec},
-    Interval{0x023f0, 0x023f0}, Interval{0x023f3, 0x023f3},
-    Interval{0x025fd, 0x025fe}, Interval{0x02614, 0x02615},
-    Interval{0x02648, 0x02653}, Interval{0x0267f, 0x0267f},
-    Interval{0x02693, 0x02693}, Interval{0x026a1, 0x026a1},
-    Interval{0x026aa, 0x026ab}, Interval{0x026bd, 0x026be},
-    Interval{0x026c4, 0x026c5}, Interval{0x026ce, 0x026ce},
-    Interval{0x026d4, 0x026d4}, Interval{0x026ea, 0x026ea},
-    Interval{0x026f2, 0x026f3}, Interval{0x026f5, 0x026f5},
-    Interval{0x026fa, 0x026fa}, Interval{0x026fd, 0x026fd},
-    Interval{0x02705, 0x02705}, Interval{0x0270a, 0x0270b},
-    Interval{0x02728, 0x02728}, Interval{0x0274c, 0x0274c},
-    Interval{0x0274e, 0x0274e}, Interval{0x02753, 0x02755},
-    Interval{0x02757, 0x02757}, Interval{0x02795, 0x02797},
-    Interval{0x027b0, 0x027b0}, Interval{0x027bf, 0x027bf},
-    Interval{0x02b1b, 0x02b1c}, Interval{0x02b50, 0x02b50},
-    Interval{0x02b55, 0x02b55}, Interval{0x02e80, 0x02e99},
-    Interval{0x02e9b, 0x02ef3}, Interval{0x02f00, 0x02fd5},
-    Interval{0x02ff0, 0x02ffb}, Interval{0x03000, 0x0303e},
-    Interval{0x03041, 0x03096}, Interval{0x03099, 0x030ff},
-    Interval{0x03105, 0x0312f}, Interval{0x03131, 0x0318e},
-    Interval{0x03190, 0x031e3}, Interval{0x031f0, 0x0321e},
-    Interval{0x03220, 0x03247}, Interval{0x03250, 0x04dbf},
-    Interval{0x04e00, 0x0a48c}, Interval{0x0a490, 0x0a4c6},
-    Interval{0x0a960, 0x0a97c}, Interval{0x0ac00, 0x0d7a3},
-    Interval{0x0f900, 0x0faff}, Interval{0x0fe10, 0x0fe19},
-    Interval{0x0fe30, 0x0fe52}, Interval{0x0fe54, 0x0fe66},
-    Interval{0x0fe68, 0x0fe6b}, Interval{0x0ff01, 0x0ff60},
-    Interval{0x0ffe0, 0x0ffe6}, Interval{0x16fe0, 0x16fe4},
-    Interval{0x16ff0, 0x16ff1}, Interval{0x17000, 0x187f7},
-    Interval{0x18800, 0x18cd5}, Interval{0x18d00, 0x18d08},
-    Interval{0x1b000, 0x1b11e}, Interval{0x1b150, 0x1b152},
-    Interval{0x1b164, 0x1b167}, Interval{0x1b170, 0x1b2fb},
-    Interval{0x1f004, 0x1f004}, Interval{0x1f0cf, 0x1f0cf},
-    Interval{0x1f18e, 0x1f18e}, Interval{0x1f191, 0x1f19a},
-    Interval{0x1f200, 0x1f202}, Interval{0x1f210, 0x1f23b},
-    Interval{0x1f240, 0x1f248}, Interval{0x1f250, 0x1f251},
-    Interval{0x1f260, 0x1f265}, Interval{0x1f300, 0x1f320},
-    Interval{0x1f32d, 0x1f335}, Interval{0x1f337, 0x1f37c},
-    Interval{0x1f37e, 0x1f393}, Interval{0x1f3a0, 0x1f3ca},
-    Interval{0x1f3cf, 0x1f3d3}, Interval{0x1f3e0, 0x1f3f0},
-    Interval{0x1f3f4, 0x1f3f4}, Interval{0x1f3f8, 0x1f43e},
-    Interval{0x1f440, 0x1f440}, Interval{0x1f442, 0x1f4fc},
-    Interval{0x1f4ff, 0x1f53d}, Interval{0x1f54b, 0x1f54e},
-    Interval{0x1f550, 0x1f567}, Interval{0x1f57a, 0x1f57a},
-    Interval{0x1f595, 0x1f596}, Interval{0x1f5a4, 0x1f5a4},
-    Interval{0x1f5fb, 0x1f64f}, Interval{0x1f680, 0x1f6c5},
-    Interval{0x1f6cc, 0x1f6cc}, Interval{0x1f6d0, 0x1f6d2},
-    Interval{0x1f6d5, 0x1f6d7}, Interval{0x1f6eb, 0x1f6ec},
-    Interval{0x1f6f4, 0x1f6fc}, Interval{0x1f7e0, 0x1f7eb},
-    Interval{0x1f90c, 0x1f93a}, Interval{0x1f93c, 0x1f945},
-    Interval{0x1f947, 0x1f978}, Interval{0x1f97a, 0x1f9cb},
-    Interval{0x1f9cd, 0x1f9ff}, Interval{0x1fa70, 0x1fa74},
-    Interval{0x1fa78, 0x1fa7a}, Interval{0x1fa80, 0x1fa86},
-    Interval{0x1fa90, 0x1faa8}, Interval{0x1fab0, 0x1fab6},
-    Interval{0x1fac0, 0x1fac2}, Interval{0x1fad0, 0x1fad6},
-    Interval{0x20000, 0x2fffd}, Interval{0x30000, 0x3fffd},
+const std::array<Interval, 116> g_full_width_characters = {{
+    {0x01100, 0x0115f}, {0x0231a, 0x0231b}, {0x02329, 0x0232a},
+    {0x023e9, 0x023ec}, {0x023f0, 0x023f0}, {0x023f3, 0x023f3},
+    {0x025fd, 0x025fe}, {0x02614, 0x02615}, {0x02648, 0x02653},
+    {0x0267f, 0x0267f}, {0x02693, 0x02693}, {0x026a1, 0x026a1},
+    {0x026aa, 0x026ab}, {0x026bd, 0x026be}, {0x026c4, 0x026c5},
+    {0x026ce, 0x026ce}, {0x026d4, 0x026d4}, {0x026ea, 0x026ea},
+    {0x026f2, 0x026f3}, {0x026f5, 0x026f5}, {0x026fa, 0x026fa},
+    {0x026fd, 0x026fd}, {0x02705, 0x02705}, {0x0270a, 0x0270b},
+    {0x02728, 0x02728}, {0x0274c, 0x0274c}, {0x0274e, 0x0274e},
+    {0x02753, 0x02755}, {0x02757, 0x02757}, {0x02795, 0x02797},
+    {0x027b0, 0x027b0}, {0x027bf, 0x027bf}, {0x02b1b, 0x02b1c},
+    {0x02b50, 0x02b50}, {0x02b55, 0x02b55}, {0x02e80, 0x02e99},
+    {0x02e9b, 0x02ef3}, {0x02f00, 0x02fd5}, {0x02ff0, 0x02ffb},
+    {0x03000, 0x0303e}, {0x03041, 0x03096}, {0x03099, 0x030ff},
+    {0x03105, 0x0312f}, {0x03131, 0x0318e}, {0x03190, 0x031e3},
+    {0x031f0, 0x0321e}, {0x03220, 0x03247}, {0x03250, 0x04dbf},
+    {0x04e00, 0x0a48c}, {0x0a490, 0x0a4c6}, {0x0a960, 0x0a97c},
+    {0x0ac00, 0x0d7a3}, {0x0f900, 0x0faff}, {0x0fe10, 0x0fe19},
+    {0x0fe30, 0x0fe52}, {0x0fe54, 0x0fe66}, {0x0fe68, 0x0fe6b},
+    {0x0ff01, 0x0ff60}, {0x0ffe0, 0x0ffe6}, {0x16fe0, 0x16fe4},
+    {0x16ff0, 0x16ff1}, {0x17000, 0x187f7}, {0x18800, 0x18cd5},
+    {0x18d00, 0x18d08}, {0x1b000, 0x1b11e}, {0x1b150, 0x1b152},
+    {0x1b164, 0x1b167}, {0x1b170, 0x1b2fb}, {0x1f004, 0x1f004},
+    {0x1f0cf, 0x1f0cf}, {0x1f18e, 0x1f18e}, {0x1f191, 0x1f19a},
+    {0x1f200, 0x1f202}, {0x1f210, 0x1f23b}, {0x1f240, 0x1f248},
+    {0x1f250, 0x1f251}, {0x1f260, 0x1f265}, {0x1f300, 0x1f320},
+    {0x1f32d, 0x1f335}, {0x1f337, 0x1f37c}, {0x1f37e, 0x1f393},
+    {0x1f3a0, 0x1f3ca}, {0x1f3cf, 0x1f3d3}, {0x1f3e0, 0x1f3f0},
+    {0x1f3f4, 0x1f3f4}, {0x1f3f8, 0x1f43e}, {0x1f440, 0x1f440},
+    {0x1f442, 0x1f4fc}, {0x1f4ff, 0x1f53d}, {0x1f54b, 0x1f54e},
+    {0x1f550, 0x1f567}, {0x1f57a, 0x1f57a}, {0x1f595, 0x1f596},
+    {0x1f5a4, 0x1f5a4}, {0x1f5fb, 0x1f64f}, {0x1f680, 0x1f6c5},
+    {0x1f6cc, 0x1f6cc}, {0x1f6d0, 0x1f6d2}, {0x1f6d5, 0x1f6d7},
+    {0x1f6eb, 0x1f6ec}, {0x1f6f4, 0x1f6fc}, {0x1f7e0, 0x1f7eb},
+    {0x1f90c, 0x1f93a}, {0x1f93c, 0x1f945}, {0x1f947, 0x1f978},
+    {0x1f97a, 0x1f9cb}, {0x1f9cd, 0x1f9ff}, {0x1fa70, 0x1fa74},
+    {0x1fa78, 0x1fa7a}, {0x1fa80, 0x1fa86}, {0x1fa90, 0x1faa8},
+    {0x1fab0, 0x1fab6}, {0x1fac0, 0x1fac2}, {0x1fad0, 0x1fad6},
+    {0x20000, 0x2fffd}, {0x30000, 0x3fffd},
+}};
+
+using WBP = ftxui::WordBreakProperty;
+struct WordBreakPropertyInterval {
+  uint32_t first;
+  uint32_t last;
+  WBP property;
 };
 
+// Properties from:
+// https://www.unicode.org/Public/UCD/latest/ucd/auxiliary/WordBreakProperty.txt
+const std::array<WordBreakPropertyInterval, 1288> g_word_break_intervals = {{
+    {0x0000A, 0x0000A, WBP::LF},
+    {0x0000B, 0x0000C, WBP::Newline},
+    {0x0000D, 0x0000D, WBP::CR},
+    {0x00020, 0x00020, WBP::WSegSpace},
+    {0x00022, 0x00022, WBP::Double_Quote},
+    {0x00027, 0x00027, WBP::Single_Quote},
+    {0x0002C, 0x0002C, WBP::MidNum},
+    {0x0002E, 0x0002E, WBP::MidNumLet},
+    {0x00030, 0x00039, WBP::Numeric},
+    {0x0003A, 0x0003A, WBP::MidLetter},
+    {0x0003B, 0x0003B, WBP::MidNum},
+    {0x00041, 0x0005A, WBP::ALetter},
+    {0x0005F, 0x0005F, WBP::ExtendNumLet},
+    {0x00061, 0x0007A, WBP::ALetter},
+    {0x00085, 0x00085, WBP::Newline},
+    {0x000AA, 0x000AA, WBP::ALetter},
+    {0x000AD, 0x000AD, WBP::Format},
+    {0x000B5, 0x000B5, WBP::ALetter},
+    {0x000B7, 0x000B7, WBP::MidLetter},
+    {0x000BA, 0x000BA, WBP::ALetter},
+    {0x000C0, 0x000D6, WBP::ALetter},
+    {0x000D8, 0x000F6, WBP::ALetter},
+    {0x000F8, 0x001BA, WBP::ALetter},
+    {0x001BB, 0x001BB, WBP::ALetter},
+    {0x001BC, 0x001BF, WBP::ALetter},
+    {0x001C0, 0x001C3, WBP::ALetter},
+    {0x001C4, 0x00293, WBP::ALetter},
+    {0x00294, 0x00294, WBP::ALetter},
+    {0x00295, 0x002AF, WBP::ALetter},
+    {0x002B0, 0x002C1, WBP::ALetter},
+    {0x002C2, 0x002C5, WBP::ALetter},
+    {0x002C6, 0x002D1, WBP::ALetter},
+    {0x002D2, 0x002D7, WBP::ALetter},
+    {0x002DE, 0x002DF, WBP::ALetter},
+    {0x002E0, 0x002E4, WBP::ALetter},
+    {0x002E5, 0x002EB, WBP::ALetter},
+    {0x002EC, 0x002EC, WBP::ALetter},
+    {0x002ED, 0x002ED, WBP::ALetter},
+    {0x002EE, 0x002EE, WBP::ALetter},
+    {0x002EF, 0x002FF, WBP::ALetter},
+    {0x00300, 0x0036F, WBP::Extend},
+    {0x00370, 0x00373, WBP::ALetter},
+    {0x00374, 0x00374, WBP::ALetter},
+    {0x00376, 0x00377, WBP::ALetter},
+    {0x0037A, 0x0037A, WBP::ALetter},
+    {0x0037B, 0x0037D, WBP::ALetter},
+    {0x0037E, 0x0037E, WBP::MidNum},
+    {0x0037F, 0x0037F, WBP::ALetter},
+    {0x00386, 0x00386, WBP::ALetter},
+    {0x00387, 0x00387, WBP::MidLetter},
+    {0x00388, 0x0038A, WBP::ALetter},
+    {0x0038C, 0x0038C, WBP::ALetter},
+    {0x0038E, 0x003A1, WBP::ALetter},
+    {0x003A3, 0x003F5, WBP::ALetter},
+    {0x003F7, 0x00481, WBP::ALetter},
+    {0x00483, 0x00487, WBP::Extend},
+    {0x00488, 0x00489, WBP::Extend},
+    {0x0048A, 0x0052F, WBP::ALetter},
+    {0x00531, 0x00556, WBP::ALetter},
+    {0x00559, 0x00559, WBP::ALetter},
+    {0x0055A, 0x0055C, WBP::ALetter},
+    {0x0055E, 0x0055E, WBP::ALetter},
+    {0x0055F, 0x0055F, WBP::MidLetter},
+    {0x00560, 0x00588, WBP::ALetter},
+    {0x00589, 0x00589, WBP::MidNum},
+    {0x0058A, 0x0058A, WBP::ALetter},
+    {0x00591, 0x005BD, WBP::Extend},
+    {0x005BF, 0x005BF, WBP::Extend},
+    {0x005C1, 0x005C2, WBP::Extend},
+    {0x005C4, 0x005C5, WBP::Extend},
+    {0x005C7, 0x005C7, WBP::Extend},
+    {0x005D0, 0x005EA, WBP::Hebrew_Letter},
+    {0x005EF, 0x005F2, WBP::Hebrew_Letter},
+    {0x005F3, 0x005F3, WBP::ALetter},
+    {0x005F4, 0x005F4, WBP::MidLetter},
+    {0x00600, 0x00605, WBP::Format},
+    {0x0060C, 0x0060D, WBP::MidNum},
+    {0x00610, 0x0061A, WBP::Extend},
+    {0x0061C, 0x0061C, WBP::Format},
+    {0x00620, 0x0063F, WBP::ALetter},
+    {0x00640, 0x00640, WBP::ALetter},
+    {0x00641, 0x0064A, WBP::ALetter},
+    {0x0064B, 0x0065F, WBP::Extend},
+    {0x00660, 0x00669, WBP::Numeric},
+    {0x0066B, 0x0066B, WBP::Numeric},
+    {0x0066C, 0x0066C, WBP::MidNum},
+    {0x0066E, 0x0066F, WBP::ALetter},
+    {0x00670, 0x00670, WBP::Extend},
+    {0x00671, 0x006D3, WBP::ALetter},
+    {0x006D5, 0x006D5, WBP::ALetter},
+    {0x006D6, 0x006DC, WBP::Extend},
+    {0x006DD, 0x006DD, WBP::Format},
+    {0x006DF, 0x006E4, WBP::Extend},
+    {0x006E5, 0x006E6, WBP::ALetter},
+    {0x006E7, 0x006E8, WBP::Extend},
+    {0x006EA, 0x006ED, WBP::Extend},
+    {0x006EE, 0x006EF, WBP::ALetter},
+    {0x006F0, 0x006F9, WBP::Numeric},
+    {0x006FA, 0x006FC, WBP::ALetter},
+    {0x006FF, 0x006FF, WBP::ALetter},
+    {0x0070F, 0x0070F, WBP::Format},
+    {0x00710, 0x00710, WBP::ALetter},
+    {0x00711, 0x00711, WBP::Extend},
+    {0x00712, 0x0072F, WBP::ALetter},
+    {0x00730, 0x0074A, WBP::Extend},
+    {0x0074D, 0x007A5, WBP::ALetter},
+    {0x007A6, 0x007B0, WBP::Extend},
+    {0x007B1, 0x007B1, WBP::ALetter},
+    {0x007C0, 0x007C9, WBP::Numeric},
+    {0x007CA, 0x007EA, WBP::ALetter},
+    {0x007EB, 0x007F3, WBP::Extend},
+    {0x007F4, 0x007F5, WBP::ALetter},
+    {0x007F8, 0x007F8, WBP::MidNum},
+    {0x007FA, 0x007FA, WBP::ALetter},
+    {0x007FD, 0x007FD, WBP::Extend},
+    {0x00800, 0x00815, WBP::ALetter},
+    {0x00816, 0x00819, WBP::Extend},
+    {0x0081A, 0x0081A, WBP::ALetter},
+    {0x0081B, 0x00823, WBP::Extend},
+    {0x00824, 0x00824, WBP::ALetter},
+    {0x00825, 0x00827, WBP::Extend},
+    {0x00828, 0x00828, WBP::ALetter},
+    {0x00829, 0x0082D, WBP::Extend},
+    {0x00840, 0x00858, WBP::ALetter},
+    {0x00859, 0x0085B, WBP::Extend},
+    {0x00860, 0x0086A, WBP::ALetter},
+    {0x008A0, 0x008B4, WBP::ALetter},
+    {0x008B6, 0x008C7, WBP::ALetter},
+    {0x008D3, 0x008E1, WBP::Extend},
+    {0x008E2, 0x008E2, WBP::Format},
+    {0x008E3, 0x00902, WBP::Extend},
+    {0x00903, 0x00903, WBP::Extend},
+    {0x00904, 0x00939, WBP::ALetter},
+    {0x0093A, 0x0093A, WBP::Extend},
+    {0x0093B, 0x0093B, WBP::Extend},
+    {0x0093C, 0x0093C, WBP::Extend},
+    {0x0093D, 0x0093D, WBP::ALetter},
+    {0x0093E, 0x00940, WBP::Extend},
+    {0x00941, 0x00948, WBP::Extend},
+    {0x00949, 0x0094C, WBP::Extend},
+    {0x0094D, 0x0094D, WBP::Extend},
+    {0x0094E, 0x0094F, WBP::Extend},
+    {0x00950, 0x00950, WBP::ALetter},
+    {0x00951, 0x00957, WBP::Extend},
+    {0x00958, 0x00961, WBP::ALetter},
+    {0x00962, 0x00963, WBP::Extend},
+    {0x00966, 0x0096F, WBP::Numeric},
+    {0x00971, 0x00971, WBP::ALetter},
+    {0x00972, 0x00980, WBP::ALetter},
+    {0x00981, 0x00981, WBP::Extend},
+    {0x00982, 0x00983, WBP::Extend},
+    {0x00985, 0x0098C, WBP::ALetter},
+    {0x0098F, 0x00990, WBP::ALetter},
+    {0x00993, 0x009A8, WBP::ALetter},
+    {0x009AA, 0x009B0, WBP::ALetter},
+    {0x009B2, 0x009B2, WBP::ALetter},
+    {0x009B6, 0x009B9, WBP::ALetter},
+    {0x009BC, 0x009BC, WBP::Extend},
+    {0x009BD, 0x009BD, WBP::ALetter},
+    {0x009BE, 0x009C0, WBP::Extend},
+    {0x009C1, 0x009C4, WBP::Extend},
+    {0x009C7, 0x009C8, WBP::Extend},
+    {0x009CB, 0x009CC, WBP::Extend},
+    {0x009CD, 0x009CD, WBP::Extend},
+    {0x009CE, 0x009CE, WBP::ALetter},
+    {0x009D7, 0x009D7, WBP::Extend},
+    {0x009DC, 0x009DD, WBP::ALetter},
+    {0x009DF, 0x009E1, WBP::ALetter},
+    {0x009E2, 0x009E3, WBP::Extend},
+    {0x009E6, 0x009EF, WBP::Numeric},
+    {0x009F0, 0x009F1, WBP::ALetter},
+    {0x009FC, 0x009FC, WBP::ALetter},
+    {0x009FE, 0x009FE, WBP::Extend},
+    {0x00A01, 0x00A02, WBP::Extend},
+    {0x00A03, 0x00A03, WBP::Extend},
+    {0x00A05, 0x00A0A, WBP::ALetter},
+    {0x00A0F, 0x00A10, WBP::ALetter},
+    {0x00A13, 0x00A28, WBP::ALetter},
+    {0x00A2A, 0x00A30, WBP::ALetter},
+    {0x00A32, 0x00A33, WBP::ALetter},
+    {0x00A35, 0x00A36, WBP::ALetter},
+    {0x00A38, 0x00A39, WBP::ALetter},
+    {0x00A3C, 0x00A3C, WBP::Extend},
+    {0x00A3E, 0x00A40, WBP::Extend},
+    {0x00A41, 0x00A42, WBP::Extend},
+    {0x00A47, 0x00A48, WBP::Extend},
+    {0x00A4B, 0x00A4D, WBP::Extend},
+    {0x00A51, 0x00A51, WBP::Extend},
+    {0x00A59, 0x00A5C, WBP::ALetter},
+    {0x00A5E, 0x00A5E, WBP::ALetter},
+    {0x00A66, 0x00A6F, WBP::Numeric},
+    {0x00A70, 0x00A71, WBP::Extend},
+    {0x00A72, 0x00A74, WBP::ALetter},
+    {0x00A75, 0x00A75, WBP::Extend},
+    {0x00A81, 0x00A82, WBP::Extend},
+    {0x00A83, 0x00A83, WBP::Extend},
+    {0x00A85, 0x00A8D, WBP::ALetter},
+    {0x00A8F, 0x00A91, WBP::ALetter},
+    {0x00A93, 0x00AA8, WBP::ALetter},
+    {0x00AAA, 0x00AB0, WBP::ALetter},
+    {0x00AB2, 0x00AB3, WBP::ALetter},
+    {0x00AB5, 0x00AB9, WBP::ALetter},
+    {0x00ABC, 0x00ABC, WBP::Extend},
+    {0x00ABD, 0x00ABD, WBP::ALetter},
+    {0x00ABE, 0x00AC0, WBP::Extend},
+    {0x00AC1, 0x00AC5, WBP::Extend},
+    {0x00AC7, 0x00AC8, WBP::Extend},
+    {0x00AC9, 0x00AC9, WBP::Extend},
+    {0x00ACB, 0x00ACC, WBP::Extend},
+    {0x00ACD, 0x00ACD, WBP::Extend},
+    {0x00AD0, 0x00AD0, WBP::ALetter},
+    {0x00AE0, 0x00AE1, WBP::ALetter},
+    {0x00AE2, 0x00AE3, WBP::Extend},
+    {0x00AE6, 0x00AEF, WBP::Numeric},
+    {0x00AF9, 0x00AF9, WBP::ALetter},
+    {0x00AFA, 0x00AFF, WBP::Extend},
+    {0x00B01, 0x00B01, WBP::Extend},
+    {0x00B02, 0x00B03, WBP::Extend},
+    {0x00B05, 0x00B0C, WBP::ALetter},
+    {0x00B0F, 0x00B10, WBP::ALetter},
+    {0x00B13, 0x00B28, WBP::ALetter},
+    {0x00B2A, 0x00B30, WBP::ALetter},
+    {0x00B32, 0x00B33, WBP::ALetter},
+    {0x00B35, 0x00B39, WBP::ALetter},
+    {0x00B3C, 0x00B3C, WBP::Extend},
+    {0x00B3D, 0x00B3D, WBP::ALetter},
+    {0x00B3E, 0x00B3E, WBP::Extend},
+    {0x00B3F, 0x00B3F, WBP::Extend},
+    {0x00B40, 0x00B40, WBP::Extend},
+    {0x00B41, 0x00B44, WBP::Extend},
+    {0x00B47, 0x00B48, WBP::Extend},
+    {0x00B4B, 0x00B4C, WBP::Extend},
+    {0x00B4D, 0x00B4D, WBP::Extend},
+    {0x00B55, 0x00B56, WBP::Extend},
+    {0x00B57, 0x00B57, WBP::Extend},
+    {0x00B5C, 0x00B5D, WBP::ALetter},
+    {0x00B5F, 0x00B61, WBP::ALetter},
+    {0x00B62, 0x00B63, WBP::Extend},
+    {0x00B66, 0x00B6F, WBP::Numeric},
+    {0x00B71, 0x00B71, WBP::ALetter},
+    {0x00B82, 0x00B82, WBP::Extend},
+    {0x00B83, 0x00B83, WBP::ALetter},
+    {0x00B85, 0x00B8A, WBP::ALetter},
+    {0x00B8E, 0x00B90, WBP::ALetter},
+    {0x00B92, 0x00B95, WBP::ALetter},
+    {0x00B99, 0x00B9A, WBP::ALetter},
+    {0x00B9C, 0x00B9C, WBP::ALetter},
+    {0x00B9E, 0x00B9F, WBP::ALetter},
+    {0x00BA3, 0x00BA4, WBP::ALetter},
+    {0x00BA8, 0x00BAA, WBP::ALetter},
+    {0x00BAE, 0x00BB9, WBP::ALetter},
+    {0x00BBE, 0x00BBF, WBP::Extend},
+    {0x00BC0, 0x00BC0, WBP::Extend},
+    {0x00BC1, 0x00BC2, WBP::Extend},
+    {0x00BC6, 0x00BC8, WBP::Extend},
+    {0x00BCA, 0x00BCC, WBP::Extend},
+    {0x00BCD, 0x00BCD, WBP::Extend},
+    {0x00BD0, 0x00BD0, WBP::ALetter},
+    {0x00BD7, 0x00BD7, WBP::Extend},
+    {0x00BE6, 0x00BEF, WBP::Numeric},
+    {0x00C00, 0x00C00, WBP::Extend},
+    {0x00C01, 0x00C03, WBP::Extend},
+    {0x00C04, 0x00C04, WBP::Extend},
+    {0x00C05, 0x00C0C, WBP::ALetter},
+    {0x00C0E, 0x00C10, WBP::ALetter},
+    {0x00C12, 0x00C28, WBP::ALetter},
+    {0x00C2A, 0x00C39, WBP::ALetter},
+    {0x00C3D, 0x00C3D, WBP::ALetter},
+    {0x00C3E, 0x00C40, WBP::Extend},
+    {0x00C41, 0x00C44, WBP::Extend},
+    {0x00C46, 0x00C48, WBP::Extend},
+    {0x00C4A, 0x00C4D, WBP::Extend},
+    {0x00C55, 0x00C56, WBP::Extend},
+    {0x00C58, 0x00C5A, WBP::ALetter},
+    {0x00C60, 0x00C61, WBP::ALetter},
+    {0x00C62, 0x00C63, WBP::Extend},
+    {0x00C66, 0x00C6F, WBP::Numeric},
+    {0x00C80, 0x00C80, WBP::ALetter},
+    {0x00C81, 0x00C81, WBP::Extend},
+    {0x00C82, 0x00C83, WBP::Extend},
+    {0x00C85, 0x00C8C, WBP::ALetter},
+    {0x00C8E, 0x00C90, WBP::ALetter},
+    {0x00C92, 0x00CA8, WBP::ALetter},
+    {0x00CAA, 0x00CB3, WBP::ALetter},
+    {0x00CB5, 0x00CB9, WBP::ALetter},
+    {0x00CBC, 0x00CBC, WBP::Extend},
+    {0x00CBD, 0x00CBD, WBP::ALetter},
+    {0x00CBE, 0x00CBE, WBP::Extend},
+    {0x00CBF, 0x00CBF, WBP::Extend},
+    {0x00CC0, 0x00CC4, WBP::Extend},
+    {0x00CC6, 0x00CC6, WBP::Extend},
+    {0x00CC7, 0x00CC8, WBP::Extend},
+    {0x00CCA, 0x00CCB, WBP::Extend},
+    {0x00CCC, 0x00CCD, WBP::Extend},
+    {0x00CD5, 0x00CD6, WBP::Extend},
+    {0x00CDE, 0x00CDE, WBP::ALetter},
+    {0x00CE0, 0x00CE1, WBP::ALetter},
+    {0x00CE2, 0x00CE3, WBP::Extend},
+    {0x00CE6, 0x00CEF, WBP::Numeric},
+    {0x00CF1, 0x00CF2, WBP::ALetter},
+    {0x00D00, 0x00D01, WBP::Extend},
+    {0x00D02, 0x00D03, WBP::Extend},
+    {0x00D04, 0x00D0C, WBP::ALetter},
+    {0x00D0E, 0x00D10, WBP::ALetter},
+    {0x00D12, 0x00D3A, WBP::ALetter},
+    {0x00D3B, 0x00D3C, WBP::Extend},
+    {0x00D3D, 0x00D3D, WBP::ALetter},
+    {0x00D3E, 0x00D40, WBP::Extend},
+    {0x00D41, 0x00D44, WBP::Extend},
+    {0x00D46, 0x00D48, WBP::Extend},
+    {0x00D4A, 0x00D4C, WBP::Extend},
+    {0x00D4D, 0x00D4D, WBP::Extend},
+    {0x00D4E, 0x00D4E, WBP::ALetter},
+    {0x00D54, 0x00D56, WBP::ALetter},
+    {0x00D57, 0x00D57, WBP::Extend},
+    {0x00D5F, 0x00D61, WBP::ALetter},
+    {0x00D62, 0x00D63, WBP::Extend},
+    {0x00D66, 0x00D6F, WBP::Numeric},
+    {0x00D7A, 0x00D7F, WBP::ALetter},
+    {0x00D81, 0x00D81, WBP::Extend},
+    {0x00D82, 0x00D83, WBP::Extend},
+    {0x00D85, 0x00D96, WBP::ALetter},
+    {0x00D9A, 0x00DB1, WBP::ALetter},
+    {0x00DB3, 0x00DBB, WBP::ALetter},
+    {0x00DBD, 0x00DBD, WBP::ALetter},
+    {0x00DC0, 0x00DC6, WBP::ALetter},
+    {0x00DCA, 0x00DCA, WBP::Extend},
+    {0x00DCF, 0x00DD1, WBP::Extend},
+    {0x00DD2, 0x00DD4, WBP::Extend},
+    {0x00DD6, 0x00DD6, WBP::Extend},
+    {0x00DD8, 0x00DDF, WBP::Extend},
+    {0x00DE6, 0x00DEF, WBP::Numeric},
+    {0x00DF2, 0x00DF3, WBP::Extend},
+    {0x00E31, 0x00E31, WBP::Extend},
+    {0x00E34, 0x00E3A, WBP::Extend},
+    {0x00E47, 0x00E4E, WBP::Extend},
+    {0x00E50, 0x00E59, WBP::Numeric},
+    {0x00EB1, 0x00EB1, WBP::Extend},
+    {0x00EB4, 0x00EBC, WBP::Extend},
+    {0x00EC8, 0x00ECD, WBP::Extend},
+    {0x00ED0, 0x00ED9, WBP::Numeric},
+    {0x00F00, 0x00F00, WBP::ALetter},
+    {0x00F18, 0x00F19, WBP::Extend},
+    {0x00F20, 0x00F29, WBP::Numeric},
+    {0x00F35, 0x00F35, WBP::Extend},
+    {0x00F37, 0x00F37, WBP::Extend},
+    {0x00F39, 0x00F39, WBP::Extend},
+    {0x00F3E, 0x00F3F, WBP::Extend},
+    {0x00F40, 0x00F47, WBP::ALetter},
+    {0x00F49, 0x00F6C, WBP::ALetter},
+    {0x00F71, 0x00F7E, WBP::Extend},
+    {0x00F7F, 0x00F7F, WBP::Extend},
+    {0x00F80, 0x00F84, WBP::Extend},
+    {0x00F86, 0x00F87, WBP::Extend},
+    {0x00F88, 0x00F8C, WBP::ALetter},
+    {0x00F8D, 0x00F97, WBP::Extend},
+    {0x00F99, 0x00FBC, WBP::Extend},
+    {0x00FC6, 0x00FC6, WBP::Extend},
+    {0x0102B, 0x0102C, WBP::Extend},
+    {0x0102D, 0x01030, WBP::Extend},
+    {0x01031, 0x01031, WBP::Extend},
+    {0x01032, 0x01037, WBP::Extend},
+    {0x01038, 0x01038, WBP::Extend},
+    {0x01039, 0x0103A, WBP::Extend},
+    {0x0103B, 0x0103C, WBP::Extend},
+    {0x0103D, 0x0103E, WBP::Extend},
+    {0x01040, 0x01049, WBP::Numeric},
+    {0x01056, 0x01057, WBP::Extend},
+    {0x01058, 0x01059, WBP::Extend},
+    {0x0105E, 0x01060, WBP::Extend},
+    {0x01062, 0x01064, WBP::Extend},
+    {0x01067, 0x0106D, WBP::Extend},
+    {0x01071, 0x01074, WBP::Extend},
+    {0x01082, 0x01082, WBP::Extend},
+    {0x01083, 0x01084, WBP::Extend},
+    {0x01085, 0x01086, WBP::Extend},
+    {0x01087, 0x0108C, WBP::Extend},
+    {0x0108D, 0x0108D, WBP::Extend},
+    {0x0108F, 0x0108F, WBP::Extend},
+    {0x01090, 0x01099, WBP::Numeric},
+    {0x0109A, 0x0109C, WBP::Extend},
+    {0x0109D, 0x0109D, WBP::Extend},
+    {0x010A0, 0x010C5, WBP::ALetter},
+    {0x010C7, 0x010C7, WBP::ALetter},
+    {0x010CD, 0x010CD, WBP::ALetter},
+    {0x010D0, 0x010FA, WBP::ALetter},
+    {0x010FC, 0x010FC, WBP::ALetter},
+    {0x010FD, 0x010FF, WBP::ALetter},
+    {0x01100, 0x01248, WBP::ALetter},
+    {0x0124A, 0x0124D, WBP::ALetter},
+    {0x01250, 0x01256, WBP::ALetter},
+    {0x01258, 0x01258, WBP::ALetter},
+    {0x0125A, 0x0125D, WBP::ALetter},
+    {0x01260, 0x01288, WBP::ALetter},
+    {0x0128A, 0x0128D, WBP::ALetter},
+    {0x01290, 0x012B0, WBP::ALetter},
+    {0x012B2, 0x012B5, WBP::ALetter},
+    {0x012B8, 0x012BE, WBP::ALetter},
+    {0x012C0, 0x012C0, WBP::ALetter},
+    {0x012C2, 0x012C5, WBP::ALetter},
+    {0x012C8, 0x012D6, WBP::ALetter},
+    {0x012D8, 0x01310, WBP::ALetter},
+    {0x01312, 0x01315, WBP::ALetter},
+    {0x01318, 0x0135A, WBP::ALetter},
+    {0x0135D, 0x0135F, WBP::Extend},
+    {0x01380, 0x0138F, WBP::ALetter},
+    {0x013A0, 0x013F5, WBP::ALetter},
+    {0x013F8, 0x013FD, WBP::ALetter},
+    {0x01401, 0x0166C, WBP::ALetter},
+    {0x0166F, 0x0167F, WBP::ALetter},
+    {0x01680, 0x01680, WBP::WSegSpace},
+    {0x01681, 0x0169A, WBP::ALetter},
+    {0x016A0, 0x016EA, WBP::ALetter},
+    {0x016EE, 0x016F0, WBP::ALetter},
+    {0x016F1, 0x016F8, WBP::ALetter},
+    {0x01700, 0x0170C, WBP::ALetter},
+    {0x0170E, 0x01711, WBP::ALetter},
+    {0x01712, 0x01714, WBP::Extend},
+    {0x01720, 0x01731, WBP::ALetter},
+    {0x01732, 0x01734, WBP::Extend},
+    {0x01740, 0x01751, WBP::ALetter},
+    {0x01752, 0x01753, WBP::Extend},
+    {0x01760, 0x0176C, WBP::ALetter},
+    {0x0176E, 0x01770, WBP::ALetter},
+    {0x01772, 0x01773, WBP::Extend},
+    {0x017B4, 0x017B5, WBP::Extend},
+    {0x017B6, 0x017B6, WBP::Extend},
+    {0x017B7, 0x017BD, WBP::Extend},
+    {0x017BE, 0x017C5, WBP::Extend},
+    {0x017C6, 0x017C6, WBP::Extend},
+    {0x017C7, 0x017C8, WBP::Extend},
+    {0x017C9, 0x017D3, WBP::Extend},
+    {0x017DD, 0x017DD, WBP::Extend},
+    {0x017E0, 0x017E9, WBP::Numeric},
+    {0x0180B, 0x0180D, WBP::Extend},
+    {0x0180E, 0x0180E, WBP::Format},
+    {0x01810, 0x01819, WBP::Numeric},
+    {0x01820, 0x01842, WBP::ALetter},
+    {0x01843, 0x01843, WBP::ALetter},
+    {0x01844, 0x01878, WBP::ALetter},
+    {0x01880, 0x01884, WBP::ALetter},
+    {0x01885, 0x01886, WBP::Extend},
+    {0x01887, 0x018A8, WBP::ALetter},
+    {0x018A9, 0x018A9, WBP::Extend},
+    {0x018AA, 0x018AA, WBP::ALetter},
+    {0x018B0, 0x018F5, WBP::ALetter},
+    {0x01900, 0x0191E, WBP::ALetter},
+    {0x01920, 0x01922, WBP::Extend},
+    {0x01923, 0x01926, WBP::Extend},
+    {0x01927, 0x01928, WBP::Extend},
+    {0x01929, 0x0192B, WBP::Extend},
+    {0x01930, 0x01931, WBP::Extend},
+    {0x01932, 0x01932, WBP::Extend},
+    {0x01933, 0x01938, WBP::Extend},
+    {0x01939, 0x0193B, WBP::Extend},
+    {0x01946, 0x0194F, WBP::Numeric},
+    {0x019D0, 0x019D9, WBP::Numeric},
+    {0x01A00, 0x01A16, WBP::ALetter},
+    {0x01A17, 0x01A18, WBP::Extend},
+    {0x01A19, 0x01A1A, WBP::Extend},
+    {0x01A1B, 0x01A1B, WBP::Extend},
+    {0x01A55, 0x01A55, WBP::Extend},
+    {0x01A56, 0x01A56, WBP::Extend},
+    {0x01A57, 0x01A57, WBP::Extend},
+    {0x01A58, 0x01A5E, WBP::Extend},
+    {0x01A60, 0x01A60, WBP::Extend},
+    {0x01A61, 0x01A61, WBP::Extend},
+    {0x01A62, 0x01A62, WBP::Extend},
+    {0x01A63, 0x01A64, WBP::Extend},
+    {0x01A65, 0x01A6C, WBP::Extend},
+    {0x01A6D, 0x01A72, WBP::Extend},
+    {0x01A73, 0x01A7C, WBP::Extend},
+    {0x01A7F, 0x01A7F, WBP::Extend},
+    {0x01A80, 0x01A89, WBP::Numeric},
+    {0x01A90, 0x01A99, WBP::Numeric},
+    {0x01AB0, 0x01ABD, WBP::Extend},
+    {0x01ABE, 0x01ABE, WBP::Extend},
+    {0x01ABF, 0x01AC0, WBP::Extend},
+    {0x01B00, 0x01B03, WBP::Extend},
+    {0x01B04, 0x01B04, WBP::Extend},
+    {0x01B05, 0x01B33, WBP::ALetter},
+    {0x01B34, 0x01B34, WBP::Extend},
+    {0x01B35, 0x01B35, WBP::Extend},
+    {0x01B36, 0x01B3A, WBP::Extend},
+    {0x01B3B, 0x01B3B, WBP::Extend},
+    {0x01B3C, 0x01B3C, WBP::Extend},
+    {0x01B3D, 0x01B41, WBP::Extend},
+    {0x01B42, 0x01B42, WBP::Extend},
+    {0x01B43, 0x01B44, WBP::Extend},
+    {0x01B45, 0x01B4B, WBP::ALetter},
+    {0x01B50, 0x01B59, WBP::Numeric},
+    {0x01B6B, 0x01B73, WBP::Extend},
+    {0x01B80, 0x01B81, WBP::Extend},
+    {0x01B82, 0x01B82, WBP::Extend},
+    {0x01B83, 0x01BA0, WBP::ALetter},
+    {0x01BA1, 0x01BA1, WBP::Extend},
+    {0x01BA2, 0x01BA5, WBP::Extend},
+    {0x01BA6, 0x01BA7, WBP::Extend},
+    {0x01BA8, 0x01BA9, WBP::Extend},
+    {0x01BAA, 0x01BAA, WBP::Extend},
+    {0x01BAB, 0x01BAD, WBP::Extend},
+    {0x01BAE, 0x01BAF, WBP::ALetter},
+    {0x01BB0, 0x01BB9, WBP::Numeric},
+    {0x01BBA, 0x01BE5, WBP::ALetter},
+    {0x01BE6, 0x01BE6, WBP::Extend},
+    {0x01BE7, 0x01BE7, WBP::Extend},
+    {0x01BE8, 0x01BE9, WBP::Extend},
+    {0x01BEA, 0x01BEC, WBP::Extend},
+    {0x01BED, 0x01BED, WBP::Extend},
+    {0x01BEE, 0x01BEE, WBP::Extend},
+    {0x01BEF, 0x01BF1, WBP::Extend},
+    {0x01BF2, 0x01BF3, WBP::Extend},
+    {0x01C00, 0x01C23, WBP::ALetter},
+    {0x01C24, 0x01C2B, WBP::Extend},
+    {0x01C2C, 0x01C33, WBP::Extend},
+    {0x01C34, 0x01C35, WBP::Extend},
+    {0x01C36, 0x01C37, WBP::Extend},
+    {0x01C40, 0x01C49, WBP::Numeric},
+    {0x01C4D, 0x01C4F, WBP::ALetter},
+    {0x01C50, 0x01C59, WBP::Numeric},
+    {0x01C5A, 0x01C77, WBP::ALetter},
+    {0x01C78, 0x01C7D, WBP::ALetter},
+    {0x01C80, 0x01C88, WBP::ALetter},
+    {0x01C90, 0x01CBA, WBP::ALetter},
+    {0x01CBD, 0x01CBF, WBP::ALetter},
+    {0x01CD0, 0x01CD2, WBP::Extend},
+    {0x01CD4, 0x01CE0, WBP::Extend},
+    {0x01CE1, 0x01CE1, WBP::Extend},
+    {0x01CE2, 0x01CE8, WBP::Extend},
+    {0x01CE9, 0x01CEC, WBP::ALetter},
+    {0x01CED, 0x01CED, WBP::Extend},
+    {0x01CEE, 0x01CF3, WBP::ALetter},
+    {0x01CF4, 0x01CF4, WBP::Extend},
+    {0x01CF5, 0x01CF6, WBP::ALetter},
+    {0x01CF7, 0x01CF7, WBP::Extend},
+    {0x01CF8, 0x01CF9, WBP::Extend},
+    {0x01CFA, 0x01CFA, WBP::ALetter},
+    {0x01D00, 0x01D2B, WBP::ALetter},
+    {0x01D2C, 0x01D6A, WBP::ALetter},
+    {0x01D6B, 0x01D77, WBP::ALetter},
+    {0x01D78, 0x01D78, WBP::ALetter},
+    {0x01D79, 0x01D9A, WBP::ALetter},
+    {0x01D9B, 0x01DBF, WBP::ALetter},
+    {0x01DC0, 0x01DF9, WBP::Extend},
+    {0x01DFB, 0x01DFF, WBP::Extend},
+    {0x01E00, 0x01F15, WBP::ALetter},
+    {0x01F18, 0x01F1D, WBP::ALetter},
+    {0x01F20, 0x01F45, WBP::ALetter},
+    {0x01F48, 0x01F4D, WBP::ALetter},
+    {0x01F50, 0x01F57, WBP::ALetter},
+    {0x01F59, 0x01F59, WBP::ALetter},
+    {0x01F5B, 0x01F5B, WBP::ALetter},
+    {0x01F5D, 0x01F5D, WBP::ALetter},
+    {0x01F5F, 0x01F7D, WBP::ALetter},
+    {0x01F80, 0x01FB4, WBP::ALetter},
+    {0x01FB6, 0x01FBC, WBP::ALetter},
+    {0x01FBE, 0x01FBE, WBP::ALetter},
+    {0x01FC2, 0x01FC4, WBP::ALetter},
+    {0x01FC6, 0x01FCC, WBP::ALetter},
+    {0x01FD0, 0x01FD3, WBP::ALetter},
+    {0x01FD6, 0x01FDB, WBP::ALetter},
+    {0x01FE0, 0x01FEC, WBP::ALetter},
+    {0x01FF2, 0x01FF4, WBP::ALetter},
+    {0x01FF6, 0x01FFC, WBP::ALetter},
+    {0x02000, 0x02006, WBP::WSegSpace},
+    {0x02008, 0x0200A, WBP::WSegSpace},
+    {0x0200C, 0x0200C, WBP::Extend},
+    {0x0200D, 0x0200D, WBP::ZWJ},
+    {0x0200E, 0x0200F, WBP::Format},
+    {0x02018, 0x02018, WBP::MidNumLet},
+    {0x02019, 0x02019, WBP::MidNumLet},
+    {0x02024, 0x02024, WBP::MidNumLet},
+    {0x02027, 0x02027, WBP::MidLetter},
+    {0x02028, 0x02028, WBP::Newline},
+    {0x02029, 0x02029, WBP::Newline},
+    {0x0202A, 0x0202E, WBP::Format},
+    {0x0202F, 0x0202F, WBP::ExtendNumLet},
+    {0x0203F, 0x02040, WBP::ExtendNumLet},
+    {0x02044, 0x02044, WBP::MidNum},
+    {0x02054, 0x02054, WBP::ExtendNumLet},
+    {0x0205F, 0x0205F, WBP::WSegSpace},
+    {0x02060, 0x02064, WBP::Format},
+    {0x02066, 0x0206F, WBP::Format},
+    {0x02071, 0x02071, WBP::ALetter},
+    {0x0207F, 0x0207F, WBP::ALetter},
+    {0x02090, 0x0209C, WBP::ALetter},
+    {0x020D0, 0x020DC, WBP::Extend},
+    {0x020DD, 0x020E0, WBP::Extend},
+    {0x020E1, 0x020E1, WBP::Extend},
+    {0x020E2, 0x020E4, WBP::Extend},
+    {0x020E5, 0x020F0, WBP::Extend},
+    {0x02102, 0x02102, WBP::ALetter},
+    {0x02107, 0x02107, WBP::ALetter},
+    {0x0210A, 0x02113, WBP::ALetter},
+    {0x02115, 0x02115, WBP::ALetter},
+    {0x02119, 0x0211D, WBP::ALetter},
+    {0x02124, 0x02124, WBP::ALetter},
+    {0x02126, 0x02126, WBP::ALetter},
+    {0x02128, 0x02128, WBP::ALetter},
+    {0x0212A, 0x0212D, WBP::ALetter},
+    {0x0212F, 0x02134, WBP::ALetter},
+    {0x02135, 0x02138, WBP::ALetter},
+    {0x02139, 0x02139, WBP::ALetter},
+    {0x0213C, 0x0213F, WBP::ALetter},
+    {0x02145, 0x02149, WBP::ALetter},
+    {0x0214E, 0x0214E, WBP::ALetter},
+    {0x02160, 0x02182, WBP::ALetter},
+    {0x02183, 0x02184, WBP::ALetter},
+    {0x02185, 0x02188, WBP::ALetter},
+    {0x024B6, 0x024E9, WBP::ALetter},
+    {0x02C00, 0x02C2E, WBP::ALetter},
+    {0x02C30, 0x02C5E, WBP::ALetter},
+    {0x02C60, 0x02C7B, WBP::ALetter},
+    {0x02C7C, 0x02C7D, WBP::ALetter},
+    {0x02C7E, 0x02CE4, WBP::ALetter},
+    {0x02CEB, 0x02CEE, WBP::ALetter},
+    {0x02CEF, 0x02CF1, WBP::Extend},
+    {0x02CF2, 0x02CF3, WBP::ALetter},
+    {0x02D00, 0x02D25, WBP::ALetter},
+    {0x02D27, 0x02D27, WBP::ALetter},
+    {0x02D2D, 0x02D2D, WBP::ALetter},
+    {0x02D30, 0x02D67, WBP::ALetter},
+    {0x02D6F, 0x02D6F, WBP::ALetter},
+    {0x02D7F, 0x02D7F, WBP::Extend},
+    {0x02D80, 0x02D96, WBP::ALetter},
+    {0x02DA0, 0x02DA6, WBP::ALetter},
+    {0x02DA8, 0x02DAE, WBP::ALetter},
+    {0x02DB0, 0x02DB6, WBP::ALetter},
+    {0x02DB8, 0x02DBE, WBP::ALetter},
+    {0x02DC0, 0x02DC6, WBP::ALetter},
+    {0x02DC8, 0x02DCE, WBP::ALetter},
+    {0x02DD0, 0x02DD6, WBP::ALetter},
+    {0x02DD8, 0x02DDE, WBP::ALetter},
+    {0x02DE0, 0x02DFF, WBP::Extend},
+    {0x02E2F, 0x02E2F, WBP::ALetter},
+    {0x03000, 0x03000, WBP::WSegSpace},
+    {0x03005, 0x03005, WBP::ALetter},
+    {0x0302A, 0x0302D, WBP::Extend},
+    {0x0302E, 0x0302F, WBP::Extend},
+    {0x03031, 0x03035, WBP::Katakana},
+    {0x0303B, 0x0303B, WBP::ALetter},
+    {0x0303C, 0x0303C, WBP::ALetter},
+    {0x03099, 0x0309A, WBP::Extend},
+    {0x0309B, 0x0309C, WBP::Katakana},
+    {0x030A0, 0x030A0, WBP::Katakana},
+    {0x030A1, 0x030FA, WBP::Katakana},
+    {0x030FC, 0x030FE, WBP::Katakana},
+    {0x030FF, 0x030FF, WBP::Katakana},
+    {0x03105, 0x0312F, WBP::ALetter},
+    {0x03131, 0x0318E, WBP::ALetter},
+    {0x031A0, 0x031BF, WBP::ALetter},
+    {0x031F0, 0x031FF, WBP::Katakana},
+    {0x032D0, 0x032FE, WBP::Katakana},
+    {0x03300, 0x03357, WBP::Katakana},
+    {0x0A000, 0x0A014, WBP::ALetter},
+    {0x0A015, 0x0A015, WBP::ALetter},
+    {0x0A016, 0x0A48C, WBP::ALetter},
+    {0x0A4D0, 0x0A4F7, WBP::ALetter},
+    {0x0A4F8, 0x0A4FD, WBP::ALetter},
+    {0x0A500, 0x0A60B, WBP::ALetter},
+    {0x0A60C, 0x0A60C, WBP::ALetter},
+    {0x0A610, 0x0A61F, WBP::ALetter},
+    {0x0A620, 0x0A629, WBP::Numeric},
+    {0x0A62A, 0x0A62B, WBP::ALetter},
+    {0x0A640, 0x0A66D, WBP::ALetter},
+    {0x0A66E, 0x0A66E, WBP::ALetter},
+    {0x0A66F, 0x0A66F, WBP::Extend},
+    {0x0A670, 0x0A672, WBP::Extend},
+    {0x0A674, 0x0A67D, WBP::Extend},
+    {0x0A67F, 0x0A67F, WBP::ALetter},
+    {0x0A680, 0x0A69B, WBP::ALetter},
+    {0x0A69C, 0x0A69D, WBP::ALetter},
+    {0x0A69E, 0x0A69F, WBP::Extend},
+    {0x0A6A0, 0x0A6E5, WBP::ALetter},
+    {0x0A6E6, 0x0A6EF, WBP::ALetter},
+    {0x0A6F0, 0x0A6F1, WBP::Extend},
+    {0x0A708, 0x0A716, WBP::ALetter},
+    {0x0A717, 0x0A71F, WBP::ALetter},
+    {0x0A720, 0x0A721, WBP::ALetter},
+    {0x0A722, 0x0A76F, WBP::ALetter},
+    {0x0A770, 0x0A770, WBP::ALetter},
+    {0x0A771, 0x0A787, WBP::ALetter},
+    {0x0A788, 0x0A788, WBP::ALetter},
+    {0x0A789, 0x0A78A, WBP::ALetter},
+    {0x0A78B, 0x0A78E, WBP::ALetter},
+    {0x0A78F, 0x0A78F, WBP::ALetter},
+    {0x0A790, 0x0A7BF, WBP::ALetter},
+    {0x0A7C2, 0x0A7CA, WBP::ALetter},
+    {0x0A7F5, 0x0A7F6, WBP::ALetter},
+    {0x0A7F7, 0x0A7F7, WBP::ALetter},
+    {0x0A7F8, 0x0A7F9, WBP::ALetter},
+    {0x0A7FA, 0x0A7FA, WBP::ALetter},
+    {0x0A7FB, 0x0A801, WBP::ALetter},
+    {0x0A802, 0x0A802, WBP::Extend},
+    {0x0A803, 0x0A805, WBP::ALetter},
+    {0x0A806, 0x0A806, WBP::Extend},
+    {0x0A807, 0x0A80A, WBP::ALetter},
+    {0x0A80B, 0x0A80B, WBP::Extend},
+    {0x0A80C, 0x0A822, WBP::ALetter},
+    {0x0A823, 0x0A824, WBP::Extend},
+    {0x0A825, 0x0A826, WBP::Extend},
+    {0x0A827, 0x0A827, WBP::Extend},
+    {0x0A82C, 0x0A82C, WBP::Extend},
+    {0x0A840, 0x0A873, WBP::ALetter},
+    {0x0A880, 0x0A881, WBP::Extend},
+    {0x0A882, 0x0A8B3, WBP::ALetter},
+    {0x0A8B4, 0x0A8C3, WBP::Extend},
+    {0x0A8C4, 0x0A8C5, WBP::Extend},
+    {0x0A8D0, 0x0A8D9, WBP::Numeric},
+    {0x0A8E0, 0x0A8F1, WBP::Extend},
+    {0x0A8F2, 0x0A8F7, WBP::ALetter},
+    {0x0A8FB, 0x0A8FB, WBP::ALetter},
+    {0x0A8FD, 0x0A8FE, WBP::ALetter},
+    {0x0A8FF, 0x0A8FF, WBP::Extend},
+    {0x0A900, 0x0A909, WBP::Numeric},
+    {0x0A90A, 0x0A925, WBP::ALetter},
+    {0x0A926, 0x0A92D, WBP::Extend},
+    {0x0A930, 0x0A946, WBP::ALetter},
+    {0x0A947, 0x0A951, WBP::Extend},
+    {0x0A952, 0x0A953, WBP::Extend},
+    {0x0A960, 0x0A97C, WBP::ALetter},
+    {0x0A980, 0x0A982, WBP::Extend},
+    {0x0A983, 0x0A983, WBP::Extend},
+    {0x0A984, 0x0A9B2, WBP::ALetter},
+    {0x0A9B3, 0x0A9B3, WBP::Extend},
+    {0x0A9B4, 0x0A9B5, WBP::Extend},
+    {0x0A9B6, 0x0A9B9, WBP::Extend},
+    {0x0A9BA, 0x0A9BB, WBP::Extend},
+    {0x0A9BC, 0x0A9BD, WBP::Extend},
+    {0x0A9BE, 0x0A9C0, WBP::Extend},
+    {0x0A9CF, 0x0A9CF, WBP::ALetter},
+    {0x0A9D0, 0x0A9D9, WBP::Numeric},
+    {0x0A9E5, 0x0A9E5, WBP::Extend},
+    {0x0A9F0, 0x0A9F9, WBP::Numeric},
+    {0x0AA00, 0x0AA28, WBP::ALetter},
+    {0x0AA29, 0x0AA2E, WBP::Extend},
+    {0x0AA2F, 0x0AA30, WBP::Extend},
+    {0x0AA31, 0x0AA32, WBP::Extend},
+    {0x0AA33, 0x0AA34, WBP::Extend},
+    {0x0AA35, 0x0AA36, WBP::Extend},
+    {0x0AA40, 0x0AA42, WBP::ALetter},
+    {0x0AA43, 0x0AA43, WBP::Extend},
+    {0x0AA44, 0x0AA4B, WBP::ALetter},
+    {0x0AA4C, 0x0AA4C, WBP::Extend},
+    {0x0AA4D, 0x0AA4D, WBP::Extend},
+    {0x0AA50, 0x0AA59, WBP::Numeric},
+    {0x0AA7B, 0x0AA7B, WBP::Extend},
+    {0x0AA7C, 0x0AA7C, WBP::Extend},
+    {0x0AA7D, 0x0AA7D, WBP::Extend},
+    {0x0AAB0, 0x0AAB0, WBP::Extend},
+    {0x0AAB2, 0x0AAB4, WBP::Extend},
+    {0x0AAB7, 0x0AAB8, WBP::Extend},
+    {0x0AABE, 0x0AABF, WBP::Extend},
+    {0x0AAC1, 0x0AAC1, WBP::Extend},
+    {0x0AAE0, 0x0AAEA, WBP::ALetter},
+    {0x0AAEB, 0x0AAEB, WBP::Extend},
+    {0x0AAEC, 0x0AAED, WBP::Extend},
+    {0x0AAEE, 0x0AAEF, WBP::Extend},
+    {0x0AAF2, 0x0AAF2, WBP::ALetter},
+    {0x0AAF3, 0x0AAF4, WBP::ALetter},
+    {0x0AAF5, 0x0AAF5, WBP::Extend},
+    {0x0AAF6, 0x0AAF6, WBP::Extend},
+    {0x0AB01, 0x0AB06, WBP::ALetter},
+    {0x0AB09, 0x0AB0E, WBP::ALetter},
+    {0x0AB11, 0x0AB16, WBP::ALetter},
+    {0x0AB20, 0x0AB26, WBP::ALetter},
+    {0x0AB28, 0x0AB2E, WBP::ALetter},
+    {0x0AB30, 0x0AB5A, WBP::ALetter},
+    {0x0AB5B, 0x0AB5B, WBP::ALetter},
+    {0x0AB5C, 0x0AB5F, WBP::ALetter},
+    {0x0AB60, 0x0AB68, WBP::ALetter},
+    {0x0AB69, 0x0AB69, WBP::ALetter},
+    {0x0AB70, 0x0ABBF, WBP::ALetter},
+    {0x0ABC0, 0x0ABE2, WBP::ALetter},
+    {0x0ABE3, 0x0ABE4, WBP::Extend},
+    {0x0ABE5, 0x0ABE5, WBP::Extend},
+    {0x0ABE6, 0x0ABE7, WBP::Extend},
+    {0x0ABE8, 0x0ABE8, WBP::Extend},
+    {0x0ABE9, 0x0ABEA, WBP::Extend},
+    {0x0ABEC, 0x0ABEC, WBP::Extend},
+    {0x0ABED, 0x0ABED, WBP::Extend},
+    {0x0ABF0, 0x0ABF9, WBP::Numeric},
+    {0x0AC00, 0x0D7A3, WBP::ALetter},
+    {0x0D7B0, 0x0D7C6, WBP::ALetter},
+    {0x0D7CB, 0x0D7FB, WBP::ALetter},
+    {0x0FB00, 0x0FB06, WBP::ALetter},
+    {0x0FB13, 0x0FB17, WBP::ALetter},
+    {0x0FB1D, 0x0FB1D, WBP::Hebrew_Letter},
+    {0x0FB1E, 0x0FB1E, WBP::Extend},
+    {0x0FB1F, 0x0FB28, WBP::Hebrew_Letter},
+    {0x0FB2A, 0x0FB36, WBP::Hebrew_Letter},
+    {0x0FB38, 0x0FB3C, WBP::Hebrew_Letter},
+    {0x0FB3E, 0x0FB3E, WBP::Hebrew_Letter},
+    {0x0FB40, 0x0FB41, WBP::Hebrew_Letter},
+    {0x0FB43, 0x0FB44, WBP::Hebrew_Letter},
+    {0x0FB46, 0x0FB4F, WBP::Hebrew_Letter},
+    {0x0FB50, 0x0FBB1, WBP::ALetter},
+    {0x0FBD3, 0x0FD3D, WBP::ALetter},
+    {0x0FD50, 0x0FD8F, WBP::ALetter},
+    {0x0FD92, 0x0FDC7, WBP::ALetter},
+    {0x0FDF0, 0x0FDFB, WBP::ALetter},
+    {0x0FE00, 0x0FE0F, WBP::Extend},
+    {0x0FE10, 0x0FE10, WBP::MidNum},
+    {0x0FE13, 0x0FE13, WBP::MidLetter},
+    {0x0FE14, 0x0FE14, WBP::MidNum},
+    {0x0FE20, 0x0FE2F, WBP::Extend},
+    {0x0FE33, 0x0FE34, WBP::ExtendNumLet},
+    {0x0FE4D, 0x0FE4F, WBP::ExtendNumLet},
+    {0x0FE50, 0x0FE50, WBP::MidNum},
+    {0x0FE52, 0x0FE52, WBP::MidNumLet},
+    {0x0FE54, 0x0FE54, WBP::MidNum},
+    {0x0FE55, 0x0FE55, WBP::MidLetter},
+    {0x0FE70, 0x0FE74, WBP::ALetter},
+    {0x0FE76, 0x0FEFC, WBP::ALetter},
+    {0x0FEFF, 0x0FEFF, WBP::Format},
+    {0x0FF07, 0x0FF07, WBP::MidNumLet},
+    {0x0FF0C, 0x0FF0C, WBP::MidNum},
+    {0x0FF0E, 0x0FF0E, WBP::MidNumLet},
+    {0x0FF10, 0x0FF19, WBP::Numeric},
+    {0x0FF1A, 0x0FF1A, WBP::MidLetter},
+    {0x0FF1B, 0x0FF1B, WBP::MidNum},
+    {0x0FF21, 0x0FF3A, WBP::ALetter},
+    {0x0FF3F, 0x0FF3F, WBP::ExtendNumLet},
+    {0x0FF41, 0x0FF5A, WBP::ALetter},
+    {0x0FF66, 0x0FF6F, WBP::Katakana},
+    {0x0FF70, 0x0FF70, WBP::Katakana},
+    {0x0FF71, 0x0FF9D, WBP::Katakana},
+    {0x0FF9E, 0x0FF9F, WBP::Extend},
+    {0x0FFA0, 0x0FFBE, WBP::ALetter},
+    {0x0FFC2, 0x0FFC7, WBP::ALetter},
+    {0x0FFCA, 0x0FFCF, WBP::ALetter},
+    {0x0FFD2, 0x0FFD7, WBP::ALetter},
+    {0x0FFDA, 0x0FFDC, WBP::ALetter},
+    {0x0FFF9, 0x0FFFB, WBP::Format},
+    {0x10000, 0x1000B, WBP::ALetter},
+    {0x1000D, 0x10026, WBP::ALetter},
+    {0x10028, 0x1003A, WBP::ALetter},
+    {0x1003C, 0x1003D, WBP::ALetter},
+    {0x1003F, 0x1004D, WBP::ALetter},
+    {0x10050, 0x1005D, WBP::ALetter},
+    {0x10080, 0x100FA, WBP::ALetter},
+    {0x10140, 0x10174, WBP::ALetter},
+    {0x101FD, 0x101FD, WBP::Extend},
+    {0x10280, 0x1029C, WBP::ALetter},
+    {0x102A0, 0x102D0, WBP::ALetter},
+    {0x102E0, 0x102E0, WBP::Extend},
+    {0x10300, 0x1031F, WBP::ALetter},
+    {0x1032D, 0x10340, WBP::ALetter},
+    {0x10341, 0x10341, WBP::ALetter},
+    {0x10342, 0x10349, WBP::ALetter},
+    {0x1034A, 0x1034A, WBP::ALetter},
+    {0x10350, 0x10375, WBP::ALetter},
+    {0x10376, 0x1037A, WBP::Extend},
+    {0x10380, 0x1039D, WBP::ALetter},
+    {0x103A0, 0x103C3, WBP::ALetter},
+    {0x103C8, 0x103CF, WBP::ALetter},
+    {0x103D1, 0x103D5, WBP::ALetter},
+    {0x10400, 0x1044F, WBP::ALetter},
+    {0x10450, 0x1049D, WBP::ALetter},
+    {0x104A0, 0x104A9, WBP::Numeric},
+    {0x104B0, 0x104D3, WBP::ALetter},
+    {0x104D8, 0x104FB, WBP::ALetter},
+    {0x10500, 0x10527, WBP::ALetter},
+    {0x10530, 0x10563, WBP::ALetter},
+    {0x10600, 0x10736, WBP::ALetter},
+    {0x10740, 0x10755, WBP::ALetter},
+    {0x10760, 0x10767, WBP::ALetter},
+    {0x10800, 0x10805, WBP::ALetter},
+    {0x10808, 0x10808, WBP::ALetter},
+    {0x1080A, 0x10835, WBP::ALetter},
+    {0x10837, 0x10838, WBP::ALetter},
+    {0x1083C, 0x1083C, WBP::ALetter},
+    {0x1083F, 0x10855, WBP::ALetter},
+    {0x10860, 0x10876, WBP::ALetter},
+    {0x10880, 0x1089E, WBP::ALetter},
+    {0x108E0, 0x108F2, WBP::ALetter},
+    {0x108F4, 0x108F5, WBP::ALetter},
+    {0x10900, 0x10915, WBP::ALetter},
+    {0x10920, 0x10939, WBP::ALetter},
+    {0x10980, 0x109B7, WBP::ALetter},
+    {0x109BE, 0x109BF, WBP::ALetter},
+    {0x10A00, 0x10A00, WBP::ALetter},
+    {0x10A01, 0x10A03, WBP::Extend},
+    {0x10A05, 0x10A06, WBP::Extend},
+    {0x10A0C, 0x10A0F, WBP::Extend},
+    {0x10A10, 0x10A13, WBP::ALetter},
+    {0x10A15, 0x10A17, WBP::ALetter},
+    {0x10A19, 0x10A35, WBP::ALetter},
+    {0x10A38, 0x10A3A, WBP::Extend},
+    {0x10A3F, 0x10A3F, WBP::Extend},
+    {0x10A60, 0x10A7C, WBP::ALetter},
+    {0x10A80, 0x10A9C, WBP::ALetter},
+    {0x10AC0, 0x10AC7, WBP::ALetter},
+    {0x10AC9, 0x10AE4, WBP::ALetter},
+    {0x10AE5, 0x10AE6, WBP::Extend},
+    {0x10B00, 0x10B35, WBP::ALetter},
+    {0x10B40, 0x10B55, WBP::ALetter},
+    {0x10B60, 0x10B72, WBP::ALetter},
+    {0x10B80, 0x10B91, WBP::ALetter},
+    {0x10C00, 0x10C48, WBP::ALetter},
+    {0x10C80, 0x10CB2, WBP::ALetter},
+    {0x10CC0, 0x10CF2, WBP::ALetter},
+    {0x10D00, 0x10D23, WBP::ALetter},
+    {0x10D24, 0x10D27, WBP::Extend},
+    {0x10D30, 0x10D39, WBP::Numeric},
+    {0x10E80, 0x10EA9, WBP::ALetter},
+    {0x10EAB, 0x10EAC, WBP::Extend},
+    {0x10EB0, 0x10EB1, WBP::ALetter},
+    {0x10F00, 0x10F1C, WBP::ALetter},
+    {0x10F27, 0x10F27, WBP::ALetter},
+    {0x10F30, 0x10F45, WBP::ALetter},
+    {0x10F46, 0x10F50, WBP::Extend},
+    {0x10FB0, 0x10FC4, WBP::ALetter},
+    {0x10FE0, 0x10FF6, WBP::ALetter},
+    {0x11000, 0x11000, WBP::Extend},
+    {0x11001, 0x11001, WBP::Extend},
+    {0x11002, 0x11002, WBP::Extend},
+    {0x11003, 0x11037, WBP::ALetter},
+    {0x11038, 0x11046, WBP::Extend},
+    {0x11066, 0x1106F, WBP::Numeric},
+    {0x1107F, 0x11081, WBP::Extend},
+    {0x11082, 0x11082, WBP::Extend},
+    {0x11083, 0x110AF, WBP::ALetter},
+    {0x110B0, 0x110B2, WBP::Extend},
+    {0x110B3, 0x110B6, WBP::Extend},
+    {0x110B7, 0x110B8, WBP::Extend},
+    {0x110B9, 0x110BA, WBP::Extend},
+    {0x110BD, 0x110BD, WBP::Format},
+    {0x110CD, 0x110CD, WBP::Format},
+    {0x110D0, 0x110E8, WBP::ALetter},
+    {0x110F0, 0x110F9, WBP::Numeric},
+    {0x11100, 0x11102, WBP::Extend},
+    {0x11103, 0x11126, WBP::ALetter},
+    {0x11127, 0x1112B, WBP::Extend},
+    {0x1112C, 0x1112C, WBP::Extend},
+    {0x1112D, 0x11134, WBP::Extend},
+    {0x11136, 0x1113F, WBP::Numeric},
+    {0x11144, 0x11144, WBP::ALetter},
+    {0x11145, 0x11146, WBP::Extend},
+    {0x11147, 0x11147, WBP::ALetter},
+    {0x11150, 0x11172, WBP::ALetter},
+    {0x11173, 0x11173, WBP::Extend},
+    {0x11176, 0x11176, WBP::ALetter},
+    {0x11180, 0x11181, WBP::Extend},
+    {0x11182, 0x11182, WBP::Extend},
+    {0x11183, 0x111B2, WBP::ALetter},
+    {0x111B3, 0x111B5, WBP::Extend},
+    {0x111B6, 0x111BE, WBP::Extend},
+    {0x111BF, 0x111C0, WBP::Extend},
+    {0x111C1, 0x111C4, WBP::ALetter},
+    {0x111C9, 0x111CC, WBP::Extend},
+    {0x111CE, 0x111CE, WBP::Extend},
+    {0x111CF, 0x111CF, WBP::Extend},
+    {0x111D0, 0x111D9, WBP::Numeric},
+    {0x111DA, 0x111DA, WBP::ALetter},
+    {0x111DC, 0x111DC, WBP::ALetter},
+    {0x11200, 0x11211, WBP::ALetter},
+    {0x11213, 0x1122B, WBP::ALetter},
+    {0x1122C, 0x1122E, WBP::Extend},
+    {0x1122F, 0x11231, WBP::Extend},
+    {0x11232, 0x11233, WBP::Extend},
+    {0x11234, 0x11234, WBP::Extend},
+    {0x11235, 0x11235, WBP::Extend},
+    {0x11236, 0x11237, WBP::Extend},
+    {0x1123E, 0x1123E, WBP::Extend},
+    {0x11280, 0x11286, WBP::ALetter},
+    {0x11288, 0x11288, WBP::ALetter},
+    {0x1128A, 0x1128D, WBP::ALetter},
+    {0x1128F, 0x1129D, WBP::ALetter},
+    {0x1129F, 0x112A8, WBP::ALetter},
+    {0x112B0, 0x112DE, WBP::ALetter},
+    {0x112DF, 0x112DF, WBP::Extend},
+    {0x112E0, 0x112E2, WBP::Extend},
+    {0x112E3, 0x112EA, WBP::Extend},
+    {0x112F0, 0x112F9, WBP::Numeric},
+    {0x11300, 0x11301, WBP::Extend},
+    {0x11302, 0x11303, WBP::Extend},
+    {0x11305, 0x1130C, WBP::ALetter},
+    {0x1130F, 0x11310, WBP::ALetter},
+    {0x11313, 0x11328, WBP::ALetter},
+    {0x1132A, 0x11330, WBP::ALetter},
+    {0x11332, 0x11333, WBP::ALetter},
+    {0x11335, 0x11339, WBP::ALetter},
+    {0x1133B, 0x1133C, WBP::Extend},
+    {0x1133D, 0x1133D, WBP::ALetter},
+    {0x1133E, 0x1133F, WBP::Extend},
+    {0x11340, 0x11340, WBP::Extend},
+    {0x11341, 0x11344, WBP::Extend},
+    {0x11347, 0x11348, WBP::Extend},
+    {0x1134B, 0x1134D, WBP::Extend},
+    {0x11350, 0x11350, WBP::ALetter},
+    {0x11357, 0x11357, WBP::Extend},
+    {0x1135D, 0x11361, WBP::ALetter},
+    {0x11362, 0x11363, WBP::Extend},
+    {0x11366, 0x1136C, WBP::Extend},
+    {0x11370, 0x11374, WBP::Extend},
+    {0x11400, 0x11434, WBP::ALetter},
+    {0x11435, 0x11437, WBP::Extend},
+    {0x11438, 0x1143F, WBP::Extend},
+    {0x11440, 0x11441, WBP::Extend},
+    {0x11442, 0x11444, WBP::Extend},
+    {0x11445, 0x11445, WBP::Extend},
+    {0x11446, 0x11446, WBP::Extend},
+    {0x11447, 0x1144A, WBP::ALetter},
+    {0x11450, 0x11459, WBP::Numeric},
+    {0x1145E, 0x1145E, WBP::Extend},
+    {0x1145F, 0x11461, WBP::ALetter},
+    {0x11480, 0x114AF, WBP::ALetter},
+    {0x114B0, 0x114B2, WBP::Extend},
+    {0x114B3, 0x114B8, WBP::Extend},
+    {0x114B9, 0x114B9, WBP::Extend},
+    {0x114BA, 0x114BA, WBP::Extend},
+    {0x114BB, 0x114BE, WBP::Extend},
+    {0x114BF, 0x114C0, WBP::Extend},
+    {0x114C1, 0x114C1, WBP::Extend},
+    {0x114C2, 0x114C3, WBP::Extend},
+    {0x114C4, 0x114C5, WBP::ALetter},
+    {0x114C7, 0x114C7, WBP::ALetter},
+    {0x114D0, 0x114D9, WBP::Numeric},
+    {0x11580, 0x115AE, WBP::ALetter},
+    {0x115AF, 0x115B1, WBP::Extend},
+    {0x115B2, 0x115B5, WBP::Extend},
+    {0x115B8, 0x115BB, WBP::Extend},
+    {0x115BC, 0x115BD, WBP::Extend},
+    {0x115BE, 0x115BE, WBP::Extend},
+    {0x115BF, 0x115C0, WBP::Extend},
+    {0x115D8, 0x115DB, WBP::ALetter},
+    {0x115DC, 0x115DD, WBP::Extend},
+    {0x11600, 0x1162F, WBP::ALetter},
+    {0x11630, 0x11632, WBP::Extend},
+    {0x11633, 0x1163A, WBP::Extend},
+    {0x1163B, 0x1163C, WBP::Extend},
+    {0x1163D, 0x1163D, WBP::Extend},
+    {0x1163E, 0x1163E, WBP::Extend},
+    {0x1163F, 0x11640, WBP::Extend},
+    {0x11644, 0x11644, WBP::ALetter},
+    {0x11650, 0x11659, WBP::Numeric},
+    {0x11680, 0x116AA, WBP::ALetter},
+    {0x116AB, 0x116AB, WBP::Extend},
+    {0x116AC, 0x116AC, WBP::Extend},
+    {0x116AD, 0x116AD, WBP::Extend},
+    {0x116AE, 0x116AF, WBP::Extend},
+    {0x116B0, 0x116B5, WBP::Extend},
+    {0x116B6, 0x116B6, WBP::Extend},
+    {0x116B7, 0x116B7, WBP::Extend},
+    {0x116B8, 0x116B8, WBP::ALetter},
+    {0x116C0, 0x116C9, WBP::Numeric},
+    {0x1171D, 0x1171F, WBP::Extend},
+    {0x11720, 0x11721, WBP::Extend},
+    {0x11722, 0x11725, WBP::Extend},
+    {0x11726, 0x11726, WBP::Extend},
+    {0x11727, 0x1172B, WBP::Extend},
+    {0x11730, 0x11739, WBP::Numeric},
+    {0x11800, 0x1182B, WBP::ALetter},
+    {0x1182C, 0x1182E, WBP::Extend},
+    {0x1182F, 0x11837, WBP::Extend},
+    {0x11838, 0x11838, WBP::Extend},
+    {0x11839, 0x1183A, WBP::Extend},
+    {0x118A0, 0x118DF, WBP::ALetter},
+    {0x118E0, 0x118E9, WBP::Numeric},
+    {0x118FF, 0x11906, WBP::ALetter},
+    {0x11909, 0x11909, WBP::ALetter},
+    {0x1190C, 0x11913, WBP::ALetter},
+    {0x11915, 0x11916, WBP::ALetter},
+    {0x11918, 0x1192F, WBP::ALetter},
+    {0x11930, 0x11935, WBP::Extend},
+    {0x11937, 0x11938, WBP::Extend},
+    {0x1193B, 0x1193C, WBP::Extend},
+    {0x1193D, 0x1193D, WBP::Extend},
+    {0x1193E, 0x1193E, WBP::Extend},
+    {0x1193F, 0x1193F, WBP::ALetter},
+    {0x11940, 0x11940, WBP::Extend},
+    {0x11941, 0x11941, WBP::ALetter},
+    {0x11942, 0x11942, WBP::Extend},
+    {0x11943, 0x11943, WBP::Extend},
+    {0x11950, 0x11959, WBP::Numeric},
+    {0x119A0, 0x119A7, WBP::ALetter},
+    {0x119AA, 0x119D0, WBP::ALetter},
+    {0x119D1, 0x119D3, WBP::Extend},
+    {0x119D4, 0x119D7, WBP::Extend},
+    {0x119DA, 0x119DB, WBP::Extend},
+    {0x119DC, 0x119DF, WBP::Extend},
+    {0x119E0, 0x119E0, WBP::Extend},
+    {0x119E1, 0x119E1, WBP::ALetter},
+    {0x119E3, 0x119E3, WBP::ALetter},
+    {0x119E4, 0x119E4, WBP::Extend},
+    {0x11A00, 0x11A00, WBP::ALetter},
+    {0x11A01, 0x11A0A, WBP::Extend},
+    {0x11A0B, 0x11A32, WBP::ALetter},
+    {0x11A33, 0x11A38, WBP::Extend},
+    {0x11A39, 0x11A39, WBP::Extend},
+    {0x11A3A, 0x11A3A, WBP::ALetter},
+    {0x11A3B, 0x11A3E, WBP::Extend},
+    {0x11A47, 0x11A47, WBP::Extend},
+    {0x11A50, 0x11A50, WBP::ALetter},
+    {0x11A51, 0x11A56, WBP::Extend},
+    {0x11A57, 0x11A58, WBP::Extend},
+    {0x11A59, 0x11A5B, WBP::Extend},
+    {0x11A5C, 0x11A89, WBP::ALetter},
+    {0x11A8A, 0x11A96, WBP::Extend},
+    {0x11A97, 0x11A97, WBP::Extend},
+    {0x11A98, 0x11A99, WBP::Extend},
+    {0x11A9D, 0x11A9D, WBP::ALetter},
+    {0x11AC0, 0x11AF8, WBP::ALetter},
+    {0x11C00, 0x11C08, WBP::ALetter},
+    {0x11C0A, 0x11C2E, WBP::ALetter},
+    {0x11C2F, 0x11C2F, WBP::Extend},
+    {0x11C30, 0x11C36, WBP::Extend},
+    {0x11C38, 0x11C3D, WBP::Extend},
+    {0x11C3E, 0x11C3E, WBP::Extend},
+    {0x11C3F, 0x11C3F, WBP::Extend},
+    {0x11C40, 0x11C40, WBP::ALetter},
+    {0x11C50, 0x11C59, WBP::Numeric},
+    {0x11C72, 0x11C8F, WBP::ALetter},
+    {0x11C92, 0x11CA7, WBP::Extend},
+    {0x11CA9, 0x11CA9, WBP::Extend},
+    {0x11CAA, 0x11CB0, WBP::Extend},
+    {0x11CB1, 0x11CB1, WBP::Extend},
+    {0x11CB2, 0x11CB3, WBP::Extend},
+    {0x11CB4, 0x11CB4, WBP::Extend},
+    {0x11CB5, 0x11CB6, WBP::Extend},
+    {0x11D00, 0x11D06, WBP::ALetter},
+    {0x11D08, 0x11D09, WBP::ALetter},
+    {0x11D0B, 0x11D30, WBP::ALetter},
+    {0x11D31, 0x11D36, WBP::Extend},
+    {0x11D3A, 0x11D3A, WBP::Extend},
+    {0x11D3C, 0x11D3D, WBP::Extend},
+    {0x11D3F, 0x11D45, WBP::Extend},
+    {0x11D46, 0x11D46, WBP::ALetter},
+    {0x11D47, 0x11D47, WBP::Extend},
+    {0x11D50, 0x11D59, WBP::Numeric},
+    {0x11D60, 0x11D65, WBP::ALetter},
+    {0x11D67, 0x11D68, WBP::ALetter},
+    {0x11D6A, 0x11D89, WBP::ALetter},
+    {0x11D8A, 0x11D8E, WBP::Extend},
+    {0x11D90, 0x11D91, WBP::Extend},
+    {0x11D93, 0x11D94, WBP::Extend},
+    {0x11D95, 0x11D95, WBP::Extend},
+    {0x11D96, 0x11D96, WBP::Extend},
+    {0x11D97, 0x11D97, WBP::Extend},
+    {0x11D98, 0x11D98, WBP::ALetter},
+    {0x11DA0, 0x11DA9, WBP::Numeric},
+    {0x11EE0, 0x11EF2, WBP::ALetter},
+    {0x11EF3, 0x11EF4, WBP::Extend},
+    {0x11EF5, 0x11EF6, WBP::Extend},
+    {0x11FB0, 0x11FB0, WBP::ALetter},
+    {0x12000, 0x12399, WBP::ALetter},
+    {0x12400, 0x1246E, WBP::ALetter},
+    {0x12480, 0x12543, WBP::ALetter},
+    {0x13000, 0x1342E, WBP::ALetter},
+    {0x13430, 0x13438, WBP::Format},
+    {0x14400, 0x14646, WBP::ALetter},
+    {0x16800, 0x16A38, WBP::ALetter},
+    {0x16A40, 0x16A5E, WBP::ALetter},
+    {0x16A60, 0x16A69, WBP::Numeric},
+    {0x16AD0, 0x16AED, WBP::ALetter},
+    {0x16AF0, 0x16AF4, WBP::Extend},
+    {0x16B00, 0x16B2F, WBP::ALetter},
+    {0x16B30, 0x16B36, WBP::Extend},
+    {0x16B40, 0x16B43, WBP::ALetter},
+    {0x16B50, 0x16B59, WBP::Numeric},
+    {0x16B63, 0x16B77, WBP::ALetter},
+    {0x16B7D, 0x16B8F, WBP::ALetter},
+    {0x16E40, 0x16E7F, WBP::ALetter},
+    {0x16F00, 0x16F4A, WBP::ALetter},
+    {0x16F4F, 0x16F4F, WBP::Extend},
+    {0x16F50, 0x16F50, WBP::ALetter},
+    {0x16F51, 0x16F87, WBP::Extend},
+    {0x16F8F, 0x16F92, WBP::Extend},
+    {0x16F93, 0x16F9F, WBP::ALetter},
+    {0x16FE0, 0x16FE1, WBP::ALetter},
+    {0x16FE3, 0x16FE3, WBP::ALetter},
+    {0x16FE4, 0x16FE4, WBP::Extend},
+    {0x16FF0, 0x16FF1, WBP::Extend},
+    {0x1B000, 0x1B000, WBP::Katakana},
+    {0x1B164, 0x1B167, WBP::Katakana},
+    {0x1BC00, 0x1BC6A, WBP::ALetter},
+    {0x1BC70, 0x1BC7C, WBP::ALetter},
+    {0x1BC80, 0x1BC88, WBP::ALetter},
+    {0x1BC90, 0x1BC99, WBP::ALetter},
+    {0x1BC9D, 0x1BC9E, WBP::Extend},
+    {0x1BCA0, 0x1BCA3, WBP::Format},
+    {0x1D165, 0x1D166, WBP::Extend},
+    {0x1D167, 0x1D169, WBP::Extend},
+    {0x1D16D, 0x1D172, WBP::Extend},
+    {0x1D173, 0x1D17A, WBP::Format},
+    {0x1D17B, 0x1D182, WBP::Extend},
+    {0x1D185, 0x1D18B, WBP::Extend},
+    {0x1D1AA, 0x1D1AD, WBP::Extend},
+    {0x1D242, 0x1D244, WBP::Extend},
+    {0x1D400, 0x1D454, WBP::ALetter},
+    {0x1D456, 0x1D49C, WBP::ALetter},
+    {0x1D49E, 0x1D49F, WBP::ALetter},
+    {0x1D4A2, 0x1D4A2, WBP::ALetter},
+    {0x1D4A5, 0x1D4A6, WBP::ALetter},
+    {0x1D4A9, 0x1D4AC, WBP::ALetter},
+    {0x1D4AE, 0x1D4B9, WBP::ALetter},
+    {0x1D4BB, 0x1D4BB, WBP::ALetter},
+    {0x1D4BD, 0x1D4C3, WBP::ALetter},
+    {0x1D4C5, 0x1D505, WBP::ALetter},
+    {0x1D507, 0x1D50A, WBP::ALetter},
+    {0x1D50D, 0x1D514, WBP::ALetter},
+    {0x1D516, 0x1D51C, WBP::ALetter},
+    {0x1D51E, 0x1D539, WBP::ALetter},
+    {0x1D53B, 0x1D53E, WBP::ALetter},
+    {0x1D540, 0x1D544, WBP::ALetter},
+    {0x1D546, 0x1D546, WBP::ALetter},
+    {0x1D54A, 0x1D550, WBP::ALetter},
+    {0x1D552, 0x1D6A5, WBP::ALetter},
+    {0x1D6A8, 0x1D6C0, WBP::ALetter},
+    {0x1D6C2, 0x1D6DA, WBP::ALetter},
+    {0x1D6DC, 0x1D6FA, WBP::ALetter},
+    {0x1D6FC, 0x1D714, WBP::ALetter},
+    {0x1D716, 0x1D734, WBP::ALetter},
+    {0x1D736, 0x1D74E, WBP::ALetter},
+    {0x1D750, 0x1D76E, WBP::ALetter},
+    {0x1D770, 0x1D788, WBP::ALetter},
+    {0x1D78A, 0x1D7A8, WBP::ALetter},
+    {0x1D7AA, 0x1D7C2, WBP::ALetter},
+    {0x1D7C4, 0x1D7CB, WBP::ALetter},
+    {0x1D7CE, 0x1D7FF, WBP::Numeric},
+    {0x1DA00, 0x1DA36, WBP::Extend},
+    {0x1DA3B, 0x1DA6C, WBP::Extend},
+    {0x1DA75, 0x1DA75, WBP::Extend},
+    {0x1DA84, 0x1DA84, WBP::Extend},
+    {0x1DA9B, 0x1DA9F, WBP::Extend},
+    {0x1DAA1, 0x1DAAF, WBP::Extend},
+    {0x1E000, 0x1E006, WBP::Extend},
+    {0x1E008, 0x1E018, WBP::Extend},
+    {0x1E01B, 0x1E021, WBP::Extend},
+    {0x1E023, 0x1E024, WBP::Extend},
+    {0x1E026, 0x1E02A, WBP::Extend},
+    {0x1E100, 0x1E12C, WBP::ALetter},
+    {0x1E130, 0x1E136, WBP::Extend},
+    {0x1E137, 0x1E13D, WBP::ALetter},
+    {0x1E140, 0x1E149, WBP::Numeric},
+    {0x1E14E, 0x1E14E, WBP::ALetter},
+    {0x1E2C0, 0x1E2EB, WBP::ALetter},
+    {0x1E2EC, 0x1E2EF, WBP::Extend},
+    {0x1E2F0, 0x1E2F9, WBP::Numeric},
+    {0x1E800, 0x1E8C4, WBP::ALetter},
+    {0x1E8D0, 0x1E8D6, WBP::Extend},
+    {0x1E900, 0x1E943, WBP::ALetter},
+    {0x1E944, 0x1E94A, WBP::Extend},
+    {0x1E94B, 0x1E94B, WBP::ALetter},
+    {0x1E950, 0x1E959, WBP::Numeric},
+    {0x1EE00, 0x1EE03, WBP::ALetter},
+    {0x1EE05, 0x1EE1F, WBP::ALetter},
+    {0x1EE21, 0x1EE22, WBP::ALetter},
+    {0x1EE24, 0x1EE24, WBP::ALetter},
+    {0x1EE27, 0x1EE27, WBP::ALetter},
+    {0x1EE29, 0x1EE32, WBP::ALetter},
+    {0x1EE34, 0x1EE37, WBP::ALetter},
+    {0x1EE39, 0x1EE39, WBP::ALetter},
+    {0x1EE3B, 0x1EE3B, WBP::ALetter},
+    {0x1EE42, 0x1EE42, WBP::ALetter},
+    {0x1EE47, 0x1EE47, WBP::ALetter},
+    {0x1EE49, 0x1EE49, WBP::ALetter},
+    {0x1EE4B, 0x1EE4B, WBP::ALetter},
+    {0x1EE4D, 0x1EE4F, WBP::ALetter},
+    {0x1EE51, 0x1EE52, WBP::ALetter},
+    {0x1EE54, 0x1EE54, WBP::ALetter},
+    {0x1EE57, 0x1EE57, WBP::ALetter},
+    {0x1EE59, 0x1EE59, WBP::ALetter},
+    {0x1EE5B, 0x1EE5B, WBP::ALetter},
+    {0x1EE5D, 0x1EE5D, WBP::ALetter},
+    {0x1EE5F, 0x1EE5F, WBP::ALetter},
+    {0x1EE61, 0x1EE62, WBP::ALetter},
+    {0x1EE64, 0x1EE64, WBP::ALetter},
+    {0x1EE67, 0x1EE6A, WBP::ALetter},
+    {0x1EE6C, 0x1EE72, WBP::ALetter},
+    {0x1EE74, 0x1EE77, WBP::ALetter},
+    {0x1EE79, 0x1EE7C, WBP::ALetter},
+    {0x1EE7E, 0x1EE7E, WBP::ALetter},
+    {0x1EE80, 0x1EE89, WBP::ALetter},
+    {0x1EE8B, 0x1EE9B, WBP::ALetter},
+    {0x1EEA1, 0x1EEA3, WBP::ALetter},
+    {0x1EEA5, 0x1EEA9, WBP::ALetter},
+    {0x1EEAB, 0x1EEBB, WBP::ALetter},
+    {0x1F130, 0x1F149, WBP::ALetter},
+    {0x1F150, 0x1F169, WBP::ALetter},
+    {0x1F170, 0x1F189, WBP::ALetter},
+    {0x1F1E6, 0x1F1FF, WBP::Regional_Indicator},
+    {0x1F3FB, 0x1F3FF, WBP::Extend},
+    {0x1FBF0, 0x1FBF9, WBP::Numeric},
+    {0xE0001, 0xE0001, WBP::Format},
+    {0xE0020, 0xE007F, WBP::Extend},
+    {0xE0100, 0xE01EF, WBP::Extend},
+}};
+
 // Find a codepoint inside a sorted list of Interval.
-bool Bisearch(uint32_t ucs, const Interval* table, int max) {
-  if (ucs < table[0].first || ucs > table[max].last) {  // NOLINT
+template <size_t N>
+bool Bisearch(uint32_t ucs, const std::array<Interval, N> table) {
+  if (ucs < table.front().first || ucs > table.back().last) {  // NOLINT
+    return false;
+  }
+
+  int min = 0;
+  int max = N - 1;
+  while (max >= min) {
+    int mid = (min + max) / 2;
+    if (ucs > table[mid].last) {  // NOLINT
+      min = mid + 1;
+    } else if (ucs < table[mid].first) {  // NOLINT
+      max = mid - 1;
+    } else {
+      return true;
+    }
+  }
+
+  return false;
+}
+
+// Find a value inside a sorted list of Interval + property.
+template <class C, size_t N>
+bool Bisearch(uint32_t ucs, const std::array<C, N> table, C* out) {
+  if (ucs < table.front().first || ucs > table.back().last) {  // NOLINT
     return false;
   }
 
   int min = 0;
+  int max = N - 1;
   while (max >= min) {
     int mid = (min + max) / 2;
     if (ucs > table[mid].last) {  // NOLINT
@@ -266,6 +1518,7 @@ bool Bisearch(uint32_t ucs, const Interval* table, int max) {
     } else if (ucs < table[mid].first) {  // NOLINT
       max = mid - 1;
     } else {
+      *out = table[mid];  // NOLINT
       return true;
     }
   }
@@ -274,16 +1527,14 @@ bool Bisearch(uint32_t ucs, const Interval* table, int max) {
 }
 
 bool IsCombining(uint32_t ucs) {
-  return Bisearch(ucs, g_combining_characters.data(),
-                  g_combining_characters.size() - 1);
+  return Bisearch(ucs, g_combining_characters);
 }
 
 bool IsFullWidth(uint32_t ucs) {
   if (ucs < 0x0300)  // Quick path: // NOLINT
     return false;
 
-  return Bisearch(ucs, g_full_width_characters.data(),
-                  g_full_width_characters.size() - 1);
+  return Bisearch(ucs, g_full_width_characters);
 }
 
 bool IsControl(uint32_t ucs) {
@@ -572,6 +1823,37 @@ int GlyphCount(const std::string& input) {
   return size;
 }
 
+std::vector<WordBreakProperty> Utf8ToWordBreakProperty(
+    const std::string& input) {
+  std::vector<WordBreakProperty> out;
+  out.reserve(input.size());
+  size_t start = 0;
+  size_t end = 0;
+  while (start < input.size()) {
+    uint32_t codepoint = 0;
+    if (!EatCodePoint(input, start, &end, &codepoint)) {
+      start = end;
+      continue;
+    }
+    start = end;
+
+    // Ignore control characters.
+    if (IsControl(codepoint)) {
+      continue;
+    }
+
+    // Ignore combining characters.
+    if (IsCombining(codepoint)) {
+      continue;
+    }
+
+    WordBreakPropertyInterval interval = {0, 0, WBP::ALetter};
+    std::ignore = Bisearch(codepoint, g_word_break_intervals, &interval);
+    out.push_back(interval.property);
+  }
+  return out;
+}
+
 #ifdef _MSC_VER
 #pragma warning(push)
 #pragma warning(disable : 4996)  // codecvt_utf8_utf16 is deprecated
diff --git a/src/ftxui/screen/string_test.cpp b/src/ftxui/screen/string_test.cpp
index 9452970c..fd1a2222 100644
--- a/src/ftxui/screen/string_test.cpp
+++ b/src/ftxui/screen/string_test.cpp
@@ -122,6 +122,22 @@ TEST(StringTest, CellToGlyphIndex) {
   EXPECT_EQ(combining[2], 2);
 }
 
+TEST(StringTest, Utf8ToWordBreakProperty) {
+  using T = std::vector<WordBreakProperty>;
+  using P = WordBreakProperty;
+  EXPECT_EQ(Utf8ToWordBreakProperty("a"), T({P::ALetter}));
+  EXPECT_EQ(Utf8ToWordBreakProperty("0"), T({P::Numeric}));
+  EXPECT_EQ(Utf8ToWordBreakProperty("א"), T({P::Hebrew_Letter}));
+  EXPECT_EQ(Utf8ToWordBreakProperty("ㇰ"), T({P::Katakana}));
+  EXPECT_EQ(Utf8ToWordBreakProperty(" "), T({P::WSegSpace}));
+  EXPECT_EQ(Utf8ToWordBreakProperty("\""), T({P::Double_Quote}));
+  EXPECT_EQ(Utf8ToWordBreakProperty("'"), T({P::Single_Quote}));
+  EXPECT_EQ(Utf8ToWordBreakProperty(":"), T({P::MidLetter}));
+  EXPECT_EQ(Utf8ToWordBreakProperty("."), T({P::MidNumLet}));
+  EXPECT_EQ(Utf8ToWordBreakProperty("\r"), T({})); // FIXME
+  EXPECT_EQ(Utf8ToWordBreakProperty("\n"), T({})); // FIXME
+}
+
 }  // namespace ftxui
 // Copyright 2020 Arthur Sonzogni. All rights reserved.
 // Use of this source code is governed by the MIT license that can be found in
-- 
GitLab