1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-30 22:08:12 +00:00

TextEditor: Add button to match regular expression during search

This commit is contained in:
Emanuel Sprung 2020-04-23 20:29:38 +02:00 committed by Andreas Kling
parent 4a630d4b63
commit 3b7884ee8a
8 changed files with 176 additions and 18 deletions

View file

@ -30,6 +30,7 @@
#include <LibCore/Timer.h>
#include <LibGUI/TextDocument.h>
#include <LibGUI/TextEditor.h>
#include <LibRegex/Regex.h>
#include <ctype.h>
namespace GUI {
@ -272,6 +273,8 @@ void TextDocument::notify_did_change()
for (auto* client : m_clients)
client->document_did_change();
}
m_regex_needs_update = true;
}
void TextDocument::set_all_cursors(const TextPosition& position)
@ -350,11 +353,78 @@ TextPosition TextDocument::previous_position_before(const TextPosition& position
return { position.line(), position.column() - 1 };
}
TextRange TextDocument::find_next(const StringView& needle, const TextPosition& start, SearchShouldWrap should_wrap) const
void TextDocument::update_regex_matches(const StringView& needle)
{
if (m_regex_needs_update || needle != m_regex_needle) {
Regex<PosixExtended> re(needle);
Vector<RegexStringView> views;
for (size_t line = 0; line < m_lines.size(); ++line) {
views.append(m_lines.at(line).view());
}
re.search(views, m_regex_result);
m_regex_needs_update = false;
m_regex_needle = String { needle };
m_regex_result_match_index = -1;
m_regex_result_match_capture_group_index = -1;
}
}
TextRange TextDocument::find_next(const StringView& needle, const TextPosition& start, SearchShouldWrap should_wrap, bool regmatch)
{
if (needle.is_empty())
return {};
if (regmatch) {
if (!m_regex_result.matches.size())
return {};
regex::Match match;
bool use_whole_match { false };
auto next_match = [&] {
m_regex_result_match_capture_group_index = 0;
if (m_regex_result_match_index == m_regex_result.matches.size() - 1) {
if (should_wrap == SearchShouldWrap::Yes)
m_regex_result_match_index = 0;
else
++m_regex_result_match_index;
} else
++m_regex_result_match_index;
};
if (m_regex_result.n_capture_groups) {
if (m_regex_result_match_index >= m_regex_result.capture_group_matches.size())
next_match();
else {
// check if last capture group has been reached
if (m_regex_result_match_capture_group_index >= m_regex_result.capture_group_matches.at(m_regex_result_match_index).size()) {
next_match();
} else {
// get to the next capture group item
++m_regex_result_match_capture_group_index;
}
}
// use whole match, if there is no capture group for current index
if (m_regex_result_match_index >= m_regex_result.capture_group_matches.size())
use_whole_match = true;
else if (m_regex_result_match_capture_group_index >= m_regex_result.capture_group_matches.at(m_regex_result_match_index).size())
next_match();
} else {
next_match();
}
if (use_whole_match || !m_regex_result.capture_group_matches.at(m_regex_result_match_index).size())
match = m_regex_result.matches.at(m_regex_result_match_index);
else
match = m_regex_result.capture_group_matches.at(m_regex_result_match_index).at(m_regex_result_match_capture_group_index);
return TextRange { { match.line, match.column }, { match.line, match.column + match.view.length() } };
}
TextPosition position = start.is_valid() ? start : TextPosition(0, 0);
TextPosition original_position = position;
@ -381,11 +451,61 @@ TextRange TextDocument::find_next(const StringView& needle, const TextPosition&
return {};
}
TextRange TextDocument::find_previous(const StringView& needle, const TextPosition& start, SearchShouldWrap should_wrap) const
TextRange TextDocument::find_previous(const StringView& needle, const TextPosition& start, SearchShouldWrap should_wrap, bool regmatch)
{
if (needle.is_empty())
return {};
if (regmatch) {
if (!m_regex_result.matches.size())
return {};
regex::Match match;
bool use_whole_match { false };
auto next_match = [&] {
if (m_regex_result_match_index == 0) {
if (should_wrap == SearchShouldWrap::Yes)
m_regex_result_match_index = m_regex_result.matches.size() - 1;
else
--m_regex_result_match_index;
} else
--m_regex_result_match_index;
m_regex_result_match_capture_group_index = m_regex_result.capture_group_matches.at(m_regex_result_match_index).size() - 1;
};
if (m_regex_result.n_capture_groups) {
if (m_regex_result_match_index >= m_regex_result.capture_group_matches.size())
next_match();
else {
// check if last capture group has been reached
if (m_regex_result_match_capture_group_index >= m_regex_result.capture_group_matches.at(m_regex_result_match_index).size()) {
next_match();
} else {
// get to the next capture group item
--m_regex_result_match_capture_group_index;
}
}
// use whole match, if there is no capture group for current index
if (m_regex_result_match_index >= m_regex_result.capture_group_matches.size())
use_whole_match = true;
else if (m_regex_result_match_capture_group_index >= m_regex_result.capture_group_matches.at(m_regex_result_match_index).size())
next_match();
} else {
next_match();
}
if (use_whole_match || !m_regex_result.capture_group_matches.at(m_regex_result_match_index).size())
match = m_regex_result.matches.at(m_regex_result_match_index);
else
match = m_regex_result.capture_group_matches.at(m_regex_result_match_index).at(m_regex_result_match_capture_group_index);
return TextRange { { match.line, match.column }, { match.line, match.column + match.view.length() } };
}
TextPosition position = start.is_valid() ? start : TextPosition(0, 0);
position = previous_position_before(position, should_wrap);
TextPosition original_position = position;
@ -413,13 +533,13 @@ TextRange TextDocument::find_previous(const StringView& needle, const TextPositi
return {};
}
Vector<TextRange> TextDocument::find_all(const StringView& needle) const
Vector<TextRange> TextDocument::find_all(const StringView& needle, bool regmatch)
{
Vector<TextRange> ranges;
TextPosition position;
for (;;) {
auto range = find_next(needle, position, SearchShouldWrap::No);
auto range = find_next(needle, position, SearchShouldWrap::No, regmatch);
if (!range.is_valid())
break;
ranges.append(range);