Skip to content

Commit 1f458b1

Browse files
committedJun 6, 2024·
Storing regex match data
1 parent f8f5742 commit 1f458b1

File tree

4 files changed

+95
-11
lines changed

4 files changed

+95
-11
lines changed
 

‎Typoon/match/trigger_tree.cpp

+49-3
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,12 @@ std::strong_ordering Letter::operator<=>(const Letter& other) const
7979
}
8080

8181

82+
RegexPattern::~RegexPattern()
83+
{
84+
pcre2_code_free(mPattern);
85+
}
86+
87+
8288
TriggerTree::TriggerTree(std::filesystem::path matchFile, std::vector<std::filesystem::path> includes, std::vector<std::filesystem::path> excludes)
8389
: mMatchFile(std::move(matchFile))
8490
, mIncludes(std::move(includes))
@@ -166,7 +172,10 @@ void TriggerTree::Reconstruct(std::string_view matchesString, std::function<void
166172
};
167173
// TODO: Warn about empty triggers or replaces
168174

175+
mRegexMatches.clear();
176+
169177
/// First iteration. Construct the tree, preprocessing the data to be easy to use.
178+
/// Regex matches will be fully processed here.
170179
TempNode root;
171180
std::vector<std::pair<const Match*, const std::wstring*>> triggersOverwritten;
172181
for (const Match& match : matchesFiltered)
@@ -293,14 +302,14 @@ void TriggerTree::Reconstruct(std::string_view matchesString, std::function<void
293302
logger.Log(ELogLevel::ERROR, std::format(L"Regex compilation failed: {}\n"
294303
"File: {}, Original Trigger: {}, After Preprocess: {}, Error Offset: {}",
295304
errMsg, mMatchFile.generic_wstring(), regexTrigger, triggerStr, errOffset));
296-
305+
// TODO: Notification
297306
pcre2_code_free(pattern);
298307
continue;
299308
}
300309

301310
pcre2_jit_compile(pattern, PCRE2_JIT_COMPLETE); // Don't care if it failed or not. It'll automatically fallback to non-jit if so.
302311

303-
// TODO: Store
312+
mRegexMatches.emplace_back(pattern, doNeedFullComposite, replaceType, replaceStr, doKeepComposite);
304313

305314
STOP
306315
continue;
@@ -479,6 +488,7 @@ void TriggerTree::Reconstruct(std::string_view matchesString, std::function<void
479488
STOP
480489
}
481490

491+
mHasRegexMatches = !mRegexMatches.empty();
482492
mTreeHeight = height;
483493
mIsConstructingTriggerTree.store(false);
484494
if (onFinish && !didCallOnFinish)
@@ -545,6 +555,11 @@ void TriggerTree::OnInput(const InputMessage(&inputs)[MAX_INPUT_COUNT], int leng
545555
mAgents.reserve(mTreeHeight);
546556
mNextIterationAgents.reserve(mTreeHeight);
547557
mStroke.resize(std::max(mTreeHeight, 1U), 0);
558+
if (mHasRegexMatches)
559+
{
560+
mStrokeForRegex.clear();
561+
mStrokeForRegex.resize(std::max(get_config().maxStrokeLengthForRegex, 1), 0);
562+
}
548563
mRootAgent = { &mTree.front(), static_cast<int>(mTreeHeight) };
549564
}
550565

@@ -562,6 +577,7 @@ void TriggerTree::OnInput(const InputMessage(&inputs)[MAX_INPUT_COUNT], int leng
562577
if (length >= 0 && inputs[0].letter == L'\b')
563578
{
564579
std::ranges::shift_right(mStroke, 1);
580+
std::ranges::shift_right(mStrokeForRegex, 1);
565581

566582
// The input size is bigger than 1 only if letters are composed in the imm simulator.
567583
// But a backspace can't be used to finish composing(other than clearing one completely),
@@ -645,6 +661,15 @@ void TriggerTree::OnInput(const InputMessage(&inputs)[MAX_INPUT_COUNT], int leng
645661
return false;
646662
};
647663

664+
const auto lambdaCheckRegexMatches = [this, length, inputs](wchar_t inputLetter, bool isBeingComposed, int inputIndex)
665+
{
666+
for (const auto& [pattern, doNeedFullComposite, replaceType, replaceStr, doKeepComposite] : mRegexMatches)
667+
{
668+
}
669+
670+
return false;
671+
};
672+
648673
for (int i = 0; i < length; i++)
649674
{
650675
const auto [inputLetter, isBeingComposed] = inputs[i];
@@ -653,6 +678,22 @@ void TriggerTree::OnInput(const InputMessage(&inputs)[MAX_INPUT_COUNT], int leng
653678
{
654679
std::ranges::shift_left(mStroke, 1);
655680
mStroke.back() = inputLetter;
681+
682+
if (mHasRegexMatches)
683+
{
684+
if (L'' <= inputLetter && inputLetter <= L'')
685+
{
686+
std::wstring normalized = Letter::COMPOSITE_ENCLOSURE + normalize_hangeul(std::wstring_view{ &inputLetter, 1 }) + Letter::COMPOSITE_ENCLOSURE;
687+
const size_t size = normalized.size();
688+
std::ranges::shift_left(mStrokeForRegex, size);
689+
normalized.copy(&*(mStrokeForRegex.end() - size), size);
690+
}
691+
else
692+
{
693+
std::ranges::shift_left(mStrokeForRegex, 1);
694+
mStrokeForRegex.back() = inputLetter;
695+
}
696+
}
656697
}
657698

658699
// Check for triggers in the root node first.
@@ -669,6 +710,11 @@ void TriggerTree::OnInput(const InputMessage(&inputs)[MAX_INPUT_COUNT], int leng
669710
}
670711
}
671712

713+
if (!isTriggerFound)
714+
{
715+
isTriggerFound = lambdaCheckRegexMatches(inputLetter, isBeingComposed, i);
716+
}
717+
672718
if (isTriggerFound)
673719
{
674720
mNextIterationAgents.clear();
@@ -692,7 +738,7 @@ void TriggerTree::OnInput(const InputMessage(&inputs)[MAX_INPUT_COUNT], int leng
692738
void TriggerTree::replaceString(const Ending& ending, const Agent& agent, std::wstring_view stroke,
693739
const InputMessage(&inputs)[MAX_INPUT_COUNT], int inputLength, int inputIndex, bool doNeedFullComposite)
694740
{
695-
const auto& [replaceStringIndex, replaceType, replaceStringLength, backspaceCount, cursorMoveCount,
741+
const auto& [replaceType, replaceStringIndex, replaceStringLength, backspaceCount, cursorMoveCount,
696742
propagateCase, uppercaseStyle, keepComposite] = ending;
697743

698744
const std::wstring_view originalReplaceString{ mReplaceStrings.data() + replaceStringIndex, replaceStringLength };

‎Typoon/match/trigger_tree.h

+42-7
Original file line numberDiff line numberDiff line change
@@ -70,17 +70,48 @@ struct Ending
7070
COMMAND,
7171
};
7272

73-
int replaceStringIndex = -1;
7473
EReplaceType type = EReplaceType::TEXT;
74+
int replaceStringIndex = -1;
7575
unsigned int replaceStringLength = 0;
76-
unsigned int backspaceCount = 0; // If it's a regex match, need to calculate this after substitution.
77-
unsigned int cursorMoveCount = 0; // If it's a regex match, need to calculate this after substitution.
76+
unsigned int backspaceCount = 0;
77+
unsigned int cursorMoveCount = 0;
7878
bool propagateCase = false; // Won't be true if the first letter is not cased.
7979
Match::EUppercaseStyle uppercaseStyle = Match::EUppercaseStyle::FIRST_LETTER; // Only used if `propagateCase` is true.
8080
bool keepComposite = false; // Won't be true if the letter is not Korean or need full composite.
8181
};
8282

8383

84+
class pcre2_real_code_16;
85+
86+
class RegexPattern
87+
{
88+
public:
89+
RegexPattern(pcre2_real_code_16* pattern) : mPattern(pattern) {}
90+
~RegexPattern();
91+
RegexPattern(const RegexPattern& other) = default;
92+
RegexPattern(RegexPattern&& other) noexcept = default;
93+
RegexPattern& operator=(const RegexPattern& other) = default;
94+
RegexPattern& operator=(RegexPattern&& other) noexcept = default;
95+
96+
operator pcre2_real_code_16* () const noexcept { return mPattern; }
97+
98+
99+
private:
100+
pcre2_real_code_16* mPattern = nullptr;
101+
};
102+
103+
104+
struct RegexMatch
105+
{
106+
RegexPattern pattern = nullptr;
107+
bool needFullComposite = false;
108+
109+
Ending::EReplaceType type = Ending::EReplaceType::TEXT;
110+
std::wstring replaceString;
111+
bool keepComposite = false;
112+
};
113+
114+
84115
// The agents for tracking the current possible triggers.
85116
struct Agent
86117
{
@@ -131,13 +162,17 @@ class TriggerTree
131162
std::vector<Ending> mEndings;
132163
std::wstring mReplaceStrings;
133164

134-
std::vector<Agent> mAgents{};
135-
std::vector<Agent> mNextIterationAgents{};
136-
std::deque<DeadAgent> mDeadAgents{};
137-
std::wstring mStroke{};
165+
std::vector<Agent> mAgents;
166+
std::vector<Agent> mNextIterationAgents;
167+
std::deque<DeadAgent> mDeadAgents;
168+
std::wstring mStroke;
138169
bool mShouldResetAgents = false;
139170
Agent mRootAgent;
140171

172+
bool mHasRegexMatches = false;
173+
std::vector<RegexMatch> mRegexMatches;
174+
std::wstring mStrokeForRegex;
175+
141176
std::atomic<bool> mIsTriggerTreeOutdated = true;
142177
std::atomic<bool> mIsConstructingTriggerTree = false;
143178

‎Typoon/utils/config.cpp

+3-1
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ struct ConfigForParse
6868
std::string cursor_placeholder = "|_|";
6969
std::string regex_composite_start = ">>";
7070
std::string regex_composite_end = "<<";
71+
int max_stroke_length_for_regex = 50;
7172

7273
bool notify_config_load = true;
7374
bool notify_match_load = true;
@@ -86,6 +87,7 @@ struct ConfigForParse
8687
{ cursor_placeholder.begin(), cursor_placeholder.end() },
8788
{ regex_composite_start.begin(), regex_composite_start.end() },
8889
{ regex_composite_end.begin(), regex_composite_end.end() },
90+
max_stroke_length_for_regex,
8991
notify_config_load,
9092
notify_match_load,
9193
notify_on_off,
@@ -104,7 +106,7 @@ struct ConfigForParse
104106
};
105107

106108

107-
JSON5_CLASS(ConfigForParse, match_file_path, max_backspace_count, cursor_placeholder, regex_composite_start, regex_composite_end,
109+
JSON5_CLASS(ConfigForParse, match_file_path, max_backspace_count, cursor_placeholder, regex_composite_start, regex_composite_end, max_stroke_length_for_regex,
108110
notify_config_load, notify_match_load, notify_on_off, hotkey_toggle_on_off, hotkey_get_program_name, program_overrides)
109111

110112
Config config;

‎Typoon/utils/config.h

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ struct Config
2323
std::wstring cursorPlaceholder;
2424
std::wstring regexCompositeStart;
2525
std::wstring regexCompositeEnd;
26+
int maxStrokeLengthForRegex;
2627

2728
bool notifyConfigLoad;
2829
bool notifyMatchLoad;

0 commit comments

Comments
 (0)
Please sign in to comment.