aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/cru/common/StringUtil.hpp19
-rw-r--r--src/common/StringUtil.cpp55
-rw-r--r--src/ui/controls/TextHostControlService.cpp16
3 files changed, 89 insertions, 1 deletions
diff --git a/include/cru/common/StringUtil.hpp b/include/cru/common/StringUtil.hpp
index 276048f5..62999d53 100644
--- a/include/cru/common/StringUtil.hpp
+++ b/include/cru/common/StringUtil.hpp
@@ -1,7 +1,10 @@
#pragma once
-#include <string>
#include "Base.hpp"
+#include <functional>
+#include <string>
+#include <string_view>
+
namespace cru {
using CodePoint = std::int32_t;
constexpr CodePoint k_invalid_code_point = -1;
@@ -128,4 +131,18 @@ std::u16string ToUtf16(std::string_view s);
// If given s is not a valid utf16 string, return value is UD.
bool Utf16IsValidInsertPosition(std::u16string_view s, gsl::index position);
+
+// Return position after the character making predicate returns true or 0 if no
+// character doing so.
+gsl::index Utf16BackwardUntil(std::u16string_view str, gsl::index position,
+ const std::function<bool(CodePoint)>& predicate);
+// Return position before the character making predicate returns true or
+// str.size() if no character doing so.
+gsl::index Utf16ForwardUntil(std::u16string_view str, gsl::index position,
+ const std::function<bool(CodePoint)>& predicate);
+
+gsl::index Utf16PreviousWord(std::u16string_view str, gsl::index position,
+ bool* is_space = nullptr);
+gsl::index Utf16NextWord(std::u16string_view str, gsl::index position,
+ bool* is_space = nullptr);
} // namespace cru
diff --git a/src/common/StringUtil.cpp b/src/common/StringUtil.cpp
index 3c312d49..b13c0193 100644
--- a/src/common/StringUtil.cpp
+++ b/src/common/StringUtil.cpp
@@ -1,4 +1,5 @@
#include "cru/common/StringUtil.hpp"
+#include "cru/common/Base.hpp"
#include "gsl/gsl_util"
namespace cru {
@@ -229,4 +230,58 @@ bool Utf16IsValidInsertPosition(std::u16string_view s, gsl::index position) {
if (position == static_cast<gsl::index>(s.size())) return true;
return !IsUtf16SurrogatePairTrailing(s[position]);
}
+
+gsl::index Utf16BackwardUntil(std::u16string_view str, gsl::index position,
+ const std::function<bool(CodePoint)>& predicate) {
+ if (position <= 0) return position;
+ while (true) {
+ gsl::index p = position;
+ auto c = Utf16PreviousCodePoint(str, p, &position);
+ if (predicate(c)) return p;
+ if (c == k_invalid_code_point) return p;
+ }
+ UnreachableCode();
+}
+
+gsl::index Utf16ForwardUntil(std::u16string_view str, gsl::index position,
+ const std::function<bool(CodePoint)>& predicate) {
+ if (position >= static_cast<gsl::index>(str.size())) return position;
+ while (true) {
+ gsl::index p = position;
+ auto c = Utf16NextCodePoint(str, p, &position);
+ if (predicate(c)) return p;
+ if (c == k_invalid_code_point) return p;
+ }
+ UnreachableCode();
+}
+
+inline bool IsSpace(CodePoint c) { return c == 0x20; }
+
+gsl::index Utf16PreviousWord(std::u16string_view str, gsl::index position,
+ bool* is_space) {
+ if (position <= 0) return position;
+ auto c = Utf16PreviousCodePoint(str, position, nullptr);
+ if (IsSpace(c)) { // TODO: Currently only test against 0x20(space).
+ if (is_space) *is_space = true;
+ return Utf16BackwardUntil(str, position,
+ [](CodePoint c) { return !IsSpace(c); });
+ } else {
+ if (is_space) *is_space = false;
+ return Utf16BackwardUntil(str, position, IsSpace);
+ }
+}
+
+gsl::index Utf16NextWord(std::u16string_view str, gsl::index position,
+ bool* is_space) {
+ if (position >= static_cast<gsl::index>(str.size())) return position;
+ auto c = Utf16NextCodePoint(str, position, nullptr);
+ if (IsSpace(c)) { // TODO: Currently only test against 0x20(space).
+ if (is_space) *is_space = true;
+ return Utf16ForwardUntil(str, position,
+ [](CodePoint c) { return !IsSpace(c); });
+ } else {
+ if (is_space) *is_space = false;
+ return Utf16ForwardUntil(str, position, IsSpace);
+ }
+}
} // namespace cru
diff --git a/src/ui/controls/TextHostControlService.cpp b/src/ui/controls/TextHostControlService.cpp
index 91ec53ff..4bfd6715 100644
--- a/src/ui/controls/TextHostControlService.cpp
+++ b/src/ui/controls/TextHostControlService.cpp
@@ -419,6 +419,14 @@ void TextHostControlService::SetUpShortcuts() {
return true;
});
+ shortcut_hub_.RegisterShortcut(
+ u"CtrlLeft", {KeyCode::Left, KeyModifiers::ctrl}, [this] {
+ auto text = this->GetTextView();
+ auto caret = this->GetCaretPosition();
+ this->SetSelection(Utf16PreviousWord(text, caret));
+ return true;
+ });
+
shortcut_hub_.RegisterShortcut(u"Right", KeyCode::Right, [this] {
auto text = this->GetTextView();
const auto caret = this->GetCaretPosition();
@@ -438,5 +446,13 @@ void TextHostControlService::SetUpShortcuts() {
this->SetSelection(selection);
return true;
});
+
+ shortcut_hub_.RegisterShortcut(
+ u"CtrlRight", {KeyCode::Right, KeyModifiers::ctrl}, [this] {
+ auto text = this->GetTextView();
+ auto caret = this->GetCaretPosition();
+ this->SetSelection(Utf16NextWord(text, caret));
+ return true;
+ });
}
} // namespace cru::ui::controls