mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 10:12:45 +00:00 
			
		
		
		
	TextEditor: Add button to match regular expression during search
This commit is contained in:
		
							parent
							
								
									4a630d4b63
								
							
						
					
					
						commit
						3b7884ee8a
					
				
					 8 changed files with 176 additions and 18 deletions
				
			
		|  | @ -7,4 +7,4 @@ set(SOURCES | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| serenity_bin(TextEditor) | serenity_bin(TextEditor) | ||||||
| target_link_libraries(TextEditor LibWeb LibMarkdown LibGUI LibShell LibDesktop) | target_link_libraries(TextEditor LibWeb LibMarkdown LibGUI LibShell LibRegex LibDesktop) | ||||||
|  |  | ||||||
|  | @ -117,8 +117,12 @@ TextEditorWidget::TextEditorWidget() | ||||||
|             dbgln("find_next(\"\")"); |             dbgln("find_next(\"\")"); | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|         auto found_range = m_editor->document().find_next(needle, m_editor->normalized_selection().end()); | 
 | ||||||
|         dbgln("find_next(\"{}\") returned {}", needle, found_range); |         if (m_find_use_regex) | ||||||
|  |             m_editor->document().update_regex_matches(needle); | ||||||
|  | 
 | ||||||
|  |         auto found_range = m_editor->document().find_next(needle, m_editor->normalized_selection().end(), GUI::TextDocument::SearchShouldWrap::Yes, m_find_use_regex); | ||||||
|  |         dbg() << "find_next(\"" << needle << "\") returned " << found_range; | ||||||
|         if (found_range.is_valid()) { |         if (found_range.is_valid()) { | ||||||
|             m_editor->set_selection(found_range); |             m_editor->set_selection(found_range); | ||||||
|         } else { |         } else { | ||||||
|  | @ -129,7 +133,12 @@ TextEditorWidget::TextEditorWidget() | ||||||
|         } |         } | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|     m_find_previous_action = GUI::Action::create("Find previous", { Mod_Ctrl | Mod_Shift, Key_G }, Gfx::Bitmap::load_from_file("/res/icons/16x16/find-previous.png"), [&](auto&) { |     m_find_regex_action = GUI::Action::create("Find regex", { Mod_Ctrl, Key_R }, [&](auto&) { | ||||||
|  |         m_find_regex_button->set_checked(!m_find_regex_button->is_checked()); | ||||||
|  |         m_find_use_regex = m_find_regex_button->is_checked(); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     m_find_previous_action = GUI::Action::create("Find previous", { Mod_Ctrl | Mod_Shift, Key_G }, [&](auto&) { | ||||||
|         auto needle = m_find_textbox->text(); |         auto needle = m_find_textbox->text(); | ||||||
|         if (needle.is_empty()) { |         if (needle.is_empty()) { | ||||||
|             dbgln("find_prev(\"\")"); |             dbgln("find_prev(\"\")"); | ||||||
|  | @ -140,7 +149,10 @@ TextEditorWidget::TextEditorWidget() | ||||||
|         if (!selection_start.is_valid()) |         if (!selection_start.is_valid()) | ||||||
|             selection_start = m_editor->normalized_selection().end(); |             selection_start = m_editor->normalized_selection().end(); | ||||||
| 
 | 
 | ||||||
|         auto found_range = m_editor->document().find_previous(needle, selection_start); |         if (m_find_use_regex) | ||||||
|  |             m_editor->document().update_regex_matches(needle); | ||||||
|  | 
 | ||||||
|  |         auto found_range = m_editor->document().find_previous(needle, selection_start, GUI::TextDocument::SearchShouldWrap::Yes, m_find_use_regex); | ||||||
| 
 | 
 | ||||||
|         dbgln("find_prev(\"{}\") returned {}", needle, found_range); |         dbgln("find_prev(\"{}\") returned {}", needle, found_range); | ||||||
|         if (found_range.is_valid()) { |         if (found_range.is_valid()) { | ||||||
|  | @ -164,7 +176,10 @@ TextEditorWidget::TextEditorWidget() | ||||||
|         if (!selection_start.is_valid()) |         if (!selection_start.is_valid()) | ||||||
|             selection_start = m_editor->normalized_selection().start(); |             selection_start = m_editor->normalized_selection().start(); | ||||||
| 
 | 
 | ||||||
|         auto found_range = m_editor->document().find_next(needle, selection_start); |         if (m_find_use_regex) | ||||||
|  |             m_editor->document().update_regex_matches(needle); | ||||||
|  | 
 | ||||||
|  |         auto found_range = m_editor->document().find_next(needle, selection_start, GUI::TextDocument::SearchShouldWrap::Yes, m_find_use_regex); | ||||||
| 
 | 
 | ||||||
|         if (found_range.is_valid()) { |         if (found_range.is_valid()) { | ||||||
|             m_editor->set_selection(found_range); |             m_editor->set_selection(found_range); | ||||||
|  | @ -187,6 +202,9 @@ TextEditorWidget::TextEditorWidget() | ||||||
|         if (!selection_start.is_valid()) |         if (!selection_start.is_valid()) | ||||||
|             selection_start = m_editor->normalized_selection().start(); |             selection_start = m_editor->normalized_selection().start(); | ||||||
| 
 | 
 | ||||||
|  |         if (m_find_use_regex) | ||||||
|  |             m_editor->document().update_regex_matches(needle); | ||||||
|  | 
 | ||||||
|         auto found_range = m_editor->document().find_previous(needle, selection_start); |         auto found_range = m_editor->document().find_previous(needle, selection_start); | ||||||
| 
 | 
 | ||||||
|         if (found_range.is_valid()) { |         if (found_range.is_valid()) { | ||||||
|  | @ -205,12 +223,14 @@ TextEditorWidget::TextEditorWidget() | ||||||
|         auto substitute = m_replace_textbox->text(); |         auto substitute = m_replace_textbox->text(); | ||||||
|         if (needle.is_empty()) |         if (needle.is_empty()) | ||||||
|             return; |             return; | ||||||
|  |         if (m_find_use_regex) | ||||||
|  |             m_editor->document().update_regex_matches(needle); | ||||||
| 
 | 
 | ||||||
|         auto found_range = m_editor->document().find_next(needle); |         auto found_range = m_editor->document().find_next(needle, {}, GUI::TextDocument::SearchShouldWrap::Yes, m_find_use_regex); | ||||||
|         while (found_range.is_valid()) { |         while (found_range.is_valid()) { | ||||||
|             m_editor->set_selection(found_range); |             m_editor->set_selection(found_range); | ||||||
|             m_editor->insert_at_cursor_or_replace_selection(substitute); |             m_editor->insert_at_cursor_or_replace_selection(substitute); | ||||||
|             found_range = m_editor->document().find_next(needle); |             found_range = m_editor->document().find_next(needle, {}, GUI::TextDocument::SearchShouldWrap::Yes, m_find_use_regex); | ||||||
|         } |         } | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|  | @ -224,6 +244,11 @@ TextEditorWidget::TextEditorWidget() | ||||||
|         m_find_next_button->click(); |         m_find_next_button->click(); | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|  |     m_find_regex_button = m_find_widget->add<GUI::Button>(".*"); | ||||||
|  |     m_find_regex_button->set_size_policy(GUI::SizePolicy::Fixed, GUI::SizePolicy::Fill); | ||||||
|  |     m_find_regex_button->set_preferred_size(20, 0); | ||||||
|  |     m_find_regex_button->set_action(*m_find_regex_action); | ||||||
|  | 
 | ||||||
|     m_find_textbox->on_escape_pressed = [this] { |     m_find_textbox->on_escape_pressed = [this] { | ||||||
|         m_find_replace_widget->set_visible(false); |         m_find_replace_widget->set_visible(false); | ||||||
|         m_editor->set_focus(true); |         m_editor->set_focus(true); | ||||||
|  | @ -358,6 +383,7 @@ TextEditorWidget::TextEditorWidget() | ||||||
|     edit_menu.add_separator(); |     edit_menu.add_separator(); | ||||||
|     edit_menu.add_action(*m_find_replace_action); |     edit_menu.add_action(*m_find_replace_action); | ||||||
|     edit_menu.add_action(*m_find_next_action); |     edit_menu.add_action(*m_find_next_action); | ||||||
|  |     edit_menu.add_action(*m_find_regex_action); | ||||||
|     edit_menu.add_action(*m_find_previous_action); |     edit_menu.add_action(*m_find_previous_action); | ||||||
|     edit_menu.add_action(*m_replace_next_action); |     edit_menu.add_action(*m_replace_next_action); | ||||||
|     edit_menu.add_action(*m_replace_previous_action); |     edit_menu.add_action(*m_replace_previous_action); | ||||||
|  |  | ||||||
|  | @ -77,6 +77,7 @@ private: | ||||||
|     RefPtr<GUI::Action> m_line_wrapping_setting_action; |     RefPtr<GUI::Action> m_line_wrapping_setting_action; | ||||||
| 
 | 
 | ||||||
|     RefPtr<GUI::Action> m_find_next_action; |     RefPtr<GUI::Action> m_find_next_action; | ||||||
|  |     RefPtr<GUI::Action> m_find_regex_action; | ||||||
|     RefPtr<GUI::Action> m_find_previous_action; |     RefPtr<GUI::Action> m_find_previous_action; | ||||||
|     RefPtr<GUI::Action> m_replace_next_action; |     RefPtr<GUI::Action> m_replace_next_action; | ||||||
|     RefPtr<GUI::Action> m_replace_previous_action; |     RefPtr<GUI::Action> m_replace_previous_action; | ||||||
|  | @ -93,6 +94,7 @@ private: | ||||||
|     RefPtr<GUI::TextBox> m_replace_textbox; |     RefPtr<GUI::TextBox> m_replace_textbox; | ||||||
|     RefPtr<GUI::Button> m_find_previous_button; |     RefPtr<GUI::Button> m_find_previous_button; | ||||||
|     RefPtr<GUI::Button> m_find_next_button; |     RefPtr<GUI::Button> m_find_next_button; | ||||||
|  |     RefPtr<GUI::Button> m_find_regex_button; | ||||||
|     RefPtr<GUI::Button> m_replace_previous_button; |     RefPtr<GUI::Button> m_replace_previous_button; | ||||||
|     RefPtr<GUI::Button> m_replace_next_button; |     RefPtr<GUI::Button> m_replace_next_button; | ||||||
|     RefPtr<GUI::Button> m_replace_all_button; |     RefPtr<GUI::Button> m_replace_all_button; | ||||||
|  | @ -114,6 +116,7 @@ private: | ||||||
|     bool m_document_dirty { false }; |     bool m_document_dirty { false }; | ||||||
|     bool m_document_opening { false }; |     bool m_document_opening { false }; | ||||||
|     bool m_auto_detect_preview_mode { false }; |     bool m_auto_detect_preview_mode { false }; | ||||||
|  |     bool m_find_use_regex { false }; | ||||||
| 
 | 
 | ||||||
|     PreviewMode m_preview_mode { PreviewMode::None }; |     PreviewMode m_preview_mode { PreviewMode::None }; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | @ -35,7 +35,7 @@ ProjectFile::ProjectFile(const String& name) | ||||||
| { | { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| const GUI::TextDocument& ProjectFile::document() const | GUI::TextDocument& ProjectFile::document() const | ||||||
| { | { | ||||||
|     if (!m_document) { |     if (!m_document) { | ||||||
|         m_document = CodeDocument::create(LexicalPath(m_name)); |         m_document = CodeDocument::create(LexicalPath(m_name)); | ||||||
|  |  | ||||||
|  | @ -43,7 +43,7 @@ public: | ||||||
| 
 | 
 | ||||||
|     const String& name() const { return m_name; } |     const String& name() const { return m_name; } | ||||||
| 
 | 
 | ||||||
|     const GUI::TextDocument& document() const; |     GUI::TextDocument& document() const; | ||||||
| 
 | 
 | ||||||
|     int vertical_scroll_value() const; |     int vertical_scroll_value() const; | ||||||
|     void vertical_scroll_value(int); |     void vertical_scroll_value(int); | ||||||
|  |  | ||||||
|  | @ -94,4 +94,4 @@ set(GENERATED_SOURCES | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| serenity_lib(LibGUI gui) | serenity_lib(LibGUI gui) | ||||||
| target_link_libraries(LibGUI LibCore LibGfx LibIPC LibThread LibCpp) | target_link_libraries(LibGUI LibCore LibGfx LibIPC LibThread LibCpp LibRegex) | ||||||
|  |  | ||||||
|  | @ -30,6 +30,7 @@ | ||||||
| #include <LibCore/Timer.h> | #include <LibCore/Timer.h> | ||||||
| #include <LibGUI/TextDocument.h> | #include <LibGUI/TextDocument.h> | ||||||
| #include <LibGUI/TextEditor.h> | #include <LibGUI/TextEditor.h> | ||||||
|  | #include <LibRegex/Regex.h> | ||||||
| #include <ctype.h> | #include <ctype.h> | ||||||
| 
 | 
 | ||||||
| namespace GUI { | namespace GUI { | ||||||
|  | @ -272,6 +273,8 @@ void TextDocument::notify_did_change() | ||||||
|         for (auto* client : m_clients) |         for (auto* client : m_clients) | ||||||
|             client->document_did_change(); |             client->document_did_change(); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     m_regex_needs_update = true; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void TextDocument::set_all_cursors(const TextPosition& position) | 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 }; |     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()) |     if (needle.is_empty()) | ||||||
|         return {}; |         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 position = start.is_valid() ? start : TextPosition(0, 0); | ||||||
|     TextPosition original_position = position; |     TextPosition original_position = position; | ||||||
| 
 | 
 | ||||||
|  | @ -381,11 +451,61 @@ TextRange TextDocument::find_next(const StringView& needle, const TextPosition& | ||||||
|     return {}; |     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()) |     if (needle.is_empty()) | ||||||
|         return {}; |         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); |     TextPosition position = start.is_valid() ? start : TextPosition(0, 0); | ||||||
|     position = previous_position_before(position, should_wrap); |     position = previous_position_before(position, should_wrap); | ||||||
|     TextPosition original_position = position; |     TextPosition original_position = position; | ||||||
|  | @ -413,13 +533,13 @@ TextRange TextDocument::find_previous(const StringView& needle, const TextPositi | ||||||
|     return {}; |     return {}; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| Vector<TextRange> TextDocument::find_all(const StringView& needle) const | Vector<TextRange> TextDocument::find_all(const StringView& needle, bool regmatch) | ||||||
| { | { | ||||||
|     Vector<TextRange> ranges; |     Vector<TextRange> ranges; | ||||||
| 
 | 
 | ||||||
|     TextPosition position; |     TextPosition position; | ||||||
|     for (;;) { |     for (;;) { | ||||||
|         auto range = find_next(needle, position, SearchShouldWrap::No); |         auto range = find_next(needle, position, SearchShouldWrap::No, regmatch); | ||||||
|         if (!range.is_valid()) |         if (!range.is_valid()) | ||||||
|             break; |             break; | ||||||
|         ranges.append(range); |         ranges.append(range); | ||||||
|  |  | ||||||
|  | @ -39,6 +39,7 @@ | ||||||
| #include <LibGUI/UndoStack.h> | #include <LibGUI/UndoStack.h> | ||||||
| #include <LibGfx/Color.h> | #include <LibGfx/Color.h> | ||||||
| #include <LibGfx/Forward.h> | #include <LibGfx/Forward.h> | ||||||
|  | #include <LibRegex/Regex.h> | ||||||
| 
 | 
 | ||||||
| namespace GUI { | namespace GUI { | ||||||
| 
 | 
 | ||||||
|  | @ -108,10 +109,11 @@ public: | ||||||
|     String text() const; |     String text() const; | ||||||
|     String text_in_range(const TextRange&) const; |     String text_in_range(const TextRange&) const; | ||||||
| 
 | 
 | ||||||
|     Vector<TextRange> find_all(const StringView& needle) const; |     Vector<TextRange> find_all(const StringView& needle, bool regmatch = false); | ||||||
| 
 | 
 | ||||||
|     TextRange find_next(const StringView&, const TextPosition& start = {}, SearchShouldWrap = SearchShouldWrap::Yes) const; |     void update_regex_matches(const StringView&); | ||||||
|     TextRange find_previous(const StringView&, const TextPosition& start = {}, SearchShouldWrap = SearchShouldWrap::Yes) const; |     TextRange find_next(const StringView&, const TextPosition& start = {}, SearchShouldWrap = SearchShouldWrap::Yes, bool regmatch = false); | ||||||
|  |     TextRange find_previous(const StringView&, const TextPosition& start = {}, SearchShouldWrap = SearchShouldWrap::Yes, bool regmatch = false); | ||||||
| 
 | 
 | ||||||
|     TextPosition next_position_after(const TextPosition&, SearchShouldWrap = SearchShouldWrap::Yes) const; |     TextPosition next_position_after(const TextPosition&, SearchShouldWrap = SearchShouldWrap::Yes) const; | ||||||
|     TextPosition previous_position_before(const TextPosition&, SearchShouldWrap = SearchShouldWrap::Yes) const; |     TextPosition previous_position_before(const TextPosition&, SearchShouldWrap = SearchShouldWrap::Yes) const; | ||||||
|  | @ -158,6 +160,13 @@ private: | ||||||
| 
 | 
 | ||||||
|     UndoStack m_undo_stack; |     UndoStack m_undo_stack; | ||||||
|     RefPtr<Core::Timer> m_undo_timer; |     RefPtr<Core::Timer> m_undo_timer; | ||||||
|  | 
 | ||||||
|  |     RegexResult m_regex_result; | ||||||
|  |     size_t m_regex_result_match_index { 0 }; | ||||||
|  |     size_t m_regex_result_match_capture_group_index { 0 }; | ||||||
|  | 
 | ||||||
|  |     bool m_regex_needs_update { true }; | ||||||
|  |     String m_regex_needle; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| class TextDocumentLine { | class TextDocumentLine { | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Emanuel Sprung
						Emanuel Sprung