mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 05:52:46 +00:00 
			
		
		
		
	TextEditor+LibGUI: Add case matching and wrap around optionality
Adds simple ASCII case matching and wrap around toggles to TextEditor's find/replace widget and reorganizes its layout
This commit is contained in:
		
							parent
							
								
									b4c0314f1d
								
							
						
					
					
						commit
						3e987eba2b
					
				
					 5 changed files with 98 additions and 106 deletions
				
			
		|  | @ -40,9 +40,11 @@ | ||||||
| #include <LibGUI/ActionGroup.h> | #include <LibGUI/ActionGroup.h> | ||||||
| #include <LibGUI/BoxLayout.h> | #include <LibGUI/BoxLayout.h> | ||||||
| #include <LibGUI/Button.h> | #include <LibGUI/Button.h> | ||||||
|  | #include <LibGUI/CheckBox.h> | ||||||
| #include <LibGUI/FilePicker.h> | #include <LibGUI/FilePicker.h> | ||||||
| #include <LibGUI/FontPicker.h> | #include <LibGUI/FontPicker.h> | ||||||
| #include <LibGUI/GMLSyntaxHighlighter.h> | #include <LibGUI/GMLSyntaxHighlighter.h> | ||||||
|  | #include <LibGUI/GroupBox.h> | ||||||
| #include <LibGUI/INISyntaxHighlighter.h> | #include <LibGUI/INISyntaxHighlighter.h> | ||||||
| #include <LibGUI/Menu.h> | #include <LibGUI/Menu.h> | ||||||
| #include <LibGUI/MenuBar.h> | #include <LibGUI/MenuBar.h> | ||||||
|  | @ -60,7 +62,6 @@ | ||||||
| #include <LibMarkdown/Document.h> | #include <LibMarkdown/Document.h> | ||||||
| #include <LibWeb/OutOfProcessWebView.h> | #include <LibWeb/OutOfProcessWebView.h> | ||||||
| #include <Shell/SyntaxHighlighter.h> | #include <Shell/SyntaxHighlighter.h> | ||||||
| #include <string.h> |  | ||||||
| 
 | 
 | ||||||
| TextEditorWidget::TextEditorWidget() | TextEditorWidget::TextEditorWidget() | ||||||
| { | { | ||||||
|  | @ -108,26 +109,42 @@ TextEditorWidget::TextEditorWidget() | ||||||
|         } |         } | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     m_find_replace_widget = *find_descendant_of_type_named<GUI::Widget>("find_replace_widget"); |     m_find_replace_widget = *find_descendant_of_type_named<GUI::GroupBox>("find_replace_widget"); | ||||||
| 
 |  | ||||||
|     m_find_widget = *find_descendant_of_type_named<GUI::Widget>("find_widget"); |     m_find_widget = *find_descendant_of_type_named<GUI::Widget>("find_widget"); | ||||||
| 
 |  | ||||||
|     m_replace_widget = *find_descendant_of_type_named<GUI::Widget>("replace_widget"); |     m_replace_widget = *find_descendant_of_type_named<GUI::Widget>("replace_widget"); | ||||||
| 
 | 
 | ||||||
|     m_find_textbox = m_find_widget->add<GUI::TextBox>(); |     m_find_textbox = *find_descendant_of_type_named<GUI::TextBox>("find_textbox"); | ||||||
|     m_replace_textbox = m_replace_widget->add<GUI::TextBox>(); |     m_find_textbox->set_placeholder("Find"); | ||||||
|  | 
 | ||||||
|  |     m_replace_textbox = *find_descendant_of_type_named<GUI::TextBox>("replace_textbox"); | ||||||
|  |     m_replace_textbox->set_placeholder("Replace"); | ||||||
|  | 
 | ||||||
|  |     m_match_case_checkbox = *find_descendant_of_type_named<GUI::CheckBox>("match_case_checkbox"); | ||||||
|  |     m_match_case_checkbox->on_checked = [this] { | ||||||
|  |         m_match_case = m_match_case_checkbox->is_checked(); | ||||||
|  |     }; | ||||||
|  |     m_match_case_checkbox->set_checked(true); | ||||||
|  | 
 | ||||||
|  |     m_regex_checkbox = *find_descendant_of_type_named<GUI::CheckBox>("regex_checkbox"); | ||||||
|  |     m_regex_checkbox->on_checked = [this] { | ||||||
|  |         m_use_regex = m_regex_checkbox->is_checked(); | ||||||
|  |     }; | ||||||
|  |     m_regex_checkbox->set_checked(false); | ||||||
|  | 
 | ||||||
|  |     m_wrap_around_checkbox = *find_descendant_of_type_named<GUI::CheckBox>("wrap_around_checkbox"); | ||||||
|  |     m_wrap_around_checkbox->on_checked = [this] { | ||||||
|  |         m_should_wrap = m_wrap_around_checkbox->is_checked(); | ||||||
|  |     }; | ||||||
|  |     m_wrap_around_checkbox->set_checked(true); | ||||||
| 
 | 
 | ||||||
|     m_find_next_action = GUI::Action::create("Find next", { Mod_Ctrl, Key_G }, Gfx::Bitmap::load_from_file("/res/icons/16x16/find-next.png"), [&](auto&) { |     m_find_next_action = GUI::Action::create("Find next", { Mod_Ctrl, Key_G }, Gfx::Bitmap::load_from_file("/res/icons/16x16/find-next.png"), [&](auto&) { | ||||||
|         auto needle = m_find_textbox->text(); |         auto needle = m_find_textbox->text(); | ||||||
|         if (needle.is_empty()) { |         if (needle.is_empty()) | ||||||
|             dbgln("find_next(\"\")"); |  | ||||||
|             return; |             return; | ||||||
|         } |         if (m_use_regex) | ||||||
| 
 |  | ||||||
|         if (m_find_use_regex) |  | ||||||
|             m_editor->document().update_regex_matches(needle); |             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); |         auto found_range = m_editor->document().find_next(needle, m_editor->normalized_selection().end(), m_should_wrap ? GUI::TextDocument::SearchShouldWrap::Yes : GUI::TextDocument::SearchShouldWrap::No, m_use_regex, m_match_case); | ||||||
|         dbgln("find_next('{}') returned {}", needle, found_range); |         dbgln("find_next('{}') returned {}", needle, found_range); | ||||||
|         if (found_range.is_valid()) { |         if (found_range.is_valid()) { | ||||||
|             m_editor->set_selection(found_range); |             m_editor->set_selection(found_range); | ||||||
|  | @ -139,27 +156,18 @@ TextEditorWidget::TextEditorWidget() | ||||||
|         } |         } | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|     m_find_regex_action = GUI::Action::create("Find regex", { Mod_Ctrl | Mod_Shift, Key_R }, [&](auto&) { |     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_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(\"\")"); |  | ||||||
|             return; |             return; | ||||||
|         } |         if (m_use_regex) | ||||||
|  |             m_editor->document().update_regex_matches(needle); | ||||||
| 
 | 
 | ||||||
|         auto selection_start = m_editor->normalized_selection().start(); |         auto selection_start = m_editor->normalized_selection().start(); | ||||||
|         if (!selection_start.is_valid()) |         if (!selection_start.is_valid()) | ||||||
|             selection_start = m_editor->normalized_selection().end(); |             selection_start = m_editor->normalized_selection().end(); | ||||||
| 
 | 
 | ||||||
|         if (m_find_use_regex) |         auto found_range = m_editor->document().find_previous(needle, selection_start, m_should_wrap ? GUI::TextDocument::SearchShouldWrap::Yes : GUI::TextDocument::SearchShouldWrap::No, m_use_regex, m_match_case); | ||||||
|             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()) { | ||||||
|             m_editor->set_selection(found_range); |             m_editor->set_selection(found_range); | ||||||
|  | @ -171,48 +179,15 @@ TextEditorWidget::TextEditorWidget() | ||||||
|         } |         } | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|     m_replace_next_action = GUI::Action::create("Replace next", { Mod_Ctrl, Key_F1 }, [&](auto&) { |     m_replace_action = GUI::Action::create("Replace", { Mod_Ctrl, Key_F1 }, [&](auto&) { | ||||||
|         auto needle = m_find_textbox->text(); |  | ||||||
|         auto substitute = m_replace_textbox->text(); |  | ||||||
| 
 |  | ||||||
|         if (needle.is_empty()) |  | ||||||
|             return; |  | ||||||
| 
 |  | ||||||
|         auto selection_start = m_editor->normalized_selection().start(); |  | ||||||
|         if (!selection_start.is_valid()) |  | ||||||
|             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_next(needle, selection_start, GUI::TextDocument::SearchShouldWrap::Yes, m_find_use_regex); |  | ||||||
| 
 |  | ||||||
|         if (found_range.is_valid()) { |  | ||||||
|             m_editor->set_selection(found_range); |  | ||||||
|             m_editor->insert_at_cursor_or_replace_selection(substitute); |  | ||||||
|         } else { |  | ||||||
|             GUI::MessageBox::show(window(), |  | ||||||
|                 String::formatted("Not found: \"{}\"", needle), |  | ||||||
|                 "Not found", |  | ||||||
|                 GUI::MessageBox::Type::Information); |  | ||||||
|         } |  | ||||||
|     }); |  | ||||||
| 
 |  | ||||||
|     m_replace_previous_action = GUI::Action::create("Replace previous", { Mod_Ctrl | Mod_Shift, Key_F1 }, [&](auto&) { |  | ||||||
|         auto needle = m_find_textbox->text(); |         auto needle = m_find_textbox->text(); | ||||||
|         auto substitute = m_replace_textbox->text(); |         auto substitute = m_replace_textbox->text(); | ||||||
|         if (needle.is_empty()) |         if (needle.is_empty()) | ||||||
|             return; |             return; | ||||||
| 
 |         if (m_use_regex) | ||||||
|         auto selection_start = m_editor->normalized_selection().start(); |  | ||||||
|         if (!selection_start.is_valid()) |  | ||||||
|             selection_start = m_editor->normalized_selection().start(); |  | ||||||
| 
 |  | ||||||
|         if (m_find_use_regex) |  | ||||||
|             m_editor->document().update_regex_matches(needle); |             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_next(needle, m_editor->normalized_selection().start(), m_should_wrap ? GUI::TextDocument::SearchShouldWrap::Yes : GUI::TextDocument::SearchShouldWrap::No, m_use_regex, m_match_case); | ||||||
| 
 |  | ||||||
|         if (found_range.is_valid()) { |         if (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); | ||||||
|  | @ -229,47 +204,42 @@ 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) |         if (m_use_regex) | ||||||
|             m_editor->document().update_regex_matches(needle); |             m_editor->document().update_regex_matches(needle); | ||||||
| 
 | 
 | ||||||
|         auto found_range = m_editor->document().find_next(needle, {}, GUI::TextDocument::SearchShouldWrap::Yes, m_find_use_regex); |         auto found_range = m_editor->document().find_next(needle, {}, GUI::TextDocument::SearchShouldWrap::Yes, m_use_regex, m_match_case); | ||||||
|         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, {}, GUI::TextDocument::SearchShouldWrap::Yes, m_find_use_regex); |             found_range = m_editor->document().find_next(needle, {}, GUI::TextDocument::SearchShouldWrap::Yes, m_use_regex, m_match_case); | ||||||
|         } |         } | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|     m_find_previous_button = *find_descendant_of_type_named<GUI::Button>("find_previous_button"); |     m_find_previous_button = *find_descendant_of_type_named<GUI::Button>("find_previous_button"); | ||||||
|     m_find_previous_button->set_action(*m_find_previous_action); |     m_find_previous_button->set_action(*m_find_previous_action); | ||||||
|  |     m_find_previous_button->set_icon(Gfx::Bitmap::load_from_file("/res/icons/16x16/find-previous.png")); | ||||||
| 
 | 
 | ||||||
|     m_find_next_button = *find_descendant_of_type_named<GUI::Button>("find_next_button"); |     m_find_next_button = *find_descendant_of_type_named<GUI::Button>("find_next_button"); | ||||||
|     m_find_next_button->set_action(*m_find_next_action); |     m_find_next_button->set_action(*m_find_next_action); | ||||||
|  |     m_find_next_button->set_icon(Gfx::Bitmap::load_from_file("/res/icons/16x16/find-next.png")); | ||||||
| 
 | 
 | ||||||
|     m_find_textbox->on_return_pressed = [this] { |     m_find_textbox->on_return_pressed = [this] { | ||||||
|         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_fixed_width(20); |  | ||||||
|     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); | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     m_replace_previous_button = *find_descendant_of_type_named<GUI::Button>("replace_previous_button"); |     m_replace_button = *find_descendant_of_type_named<GUI::Button>("replace_button"); | ||||||
|     m_replace_previous_button->set_action(*m_replace_previous_action); |     m_replace_button->set_action(*m_replace_action); | ||||||
| 
 |  | ||||||
|     m_replace_next_button = *find_descendant_of_type_named<GUI::Button>("replace_next_button"); |  | ||||||
|     m_replace_next_button->set_action(*m_replace_next_action); |  | ||||||
| 
 | 
 | ||||||
|     m_replace_all_button = *find_descendant_of_type_named<GUI::Button>("replace_all_button"); |     m_replace_all_button = *find_descendant_of_type_named<GUI::Button>("replace_all_button"); | ||||||
|     m_replace_all_button->set_action(*m_replace_all_action); |     m_replace_all_button->set_action(*m_replace_all_action); | ||||||
| 
 | 
 | ||||||
|     m_replace_textbox->on_return_pressed = [this] { |     m_replace_textbox->on_return_pressed = [this] { | ||||||
|         m_replace_next_button->click(); |         m_replace_button->click(); | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     m_replace_textbox->on_escape_pressed = [this] { |     m_replace_textbox->on_escape_pressed = [this] { | ||||||
|  | @ -393,10 +363,8 @@ 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_action); | ||||||
|     edit_menu.add_action(*m_replace_previous_action); |  | ||||||
|     edit_menu.add_action(*m_replace_all_action); |     edit_menu.add_action(*m_replace_all_action); | ||||||
| 
 | 
 | ||||||
|     m_no_preview_action = GUI::Action::create_checkable( |     m_no_preview_action = GUI::Action::create_checkable( | ||||||
|  |  | ||||||
|  | @ -78,10 +78,8 @@ private: | ||||||
|     RefPtr<GUI::Action> m_vim_emulation_setting_action; |     RefPtr<GUI::Action> m_vim_emulation_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_action; | ||||||
|     RefPtr<GUI::Action> m_replace_previous_action; |  | ||||||
|     RefPtr<GUI::Action> m_replace_all_action; |     RefPtr<GUI::Action> m_replace_all_action; | ||||||
| 
 | 
 | ||||||
|     RefPtr<GUI::Action> m_layout_toolbar_action; |     RefPtr<GUI::Action> m_layout_toolbar_action; | ||||||
|  | @ -99,13 +97,14 @@ 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_button; | ||||||
|     RefPtr<GUI::Button> m_replace_previous_button; |  | ||||||
|     RefPtr<GUI::Button> m_replace_next_button; |  | ||||||
|     RefPtr<GUI::Button> m_replace_all_button; |     RefPtr<GUI::Button> m_replace_all_button; | ||||||
|     RefPtr<GUI::Widget> m_find_replace_widget; |     RefPtr<GUI::Widget> m_find_replace_widget; | ||||||
|     RefPtr<GUI::Widget> m_find_widget; |     RefPtr<GUI::Widget> m_find_widget; | ||||||
|     RefPtr<GUI::Widget> m_replace_widget; |     RefPtr<GUI::Widget> m_replace_widget; | ||||||
|  |     RefPtr<GUI::CheckBox> m_regex_checkbox; | ||||||
|  |     RefPtr<GUI::CheckBox> m_match_case_checkbox; | ||||||
|  |     RefPtr<GUI::CheckBox> m_wrap_around_checkbox; | ||||||
| 
 | 
 | ||||||
|     GUI::ActionGroup m_wrapping_mode_actions; |     GUI::ActionGroup m_wrapping_mode_actions; | ||||||
|     RefPtr<GUI::Action> m_no_wrapping_action; |     RefPtr<GUI::Action> m_no_wrapping_action; | ||||||
|  | @ -126,7 +125,9 @@ 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 }; |     bool m_use_regex { false }; | ||||||
|  |     bool m_match_case { true }; | ||||||
|  |     bool m_should_wrap { true }; | ||||||
| 
 | 
 | ||||||
|     PreviewMode m_preview_mode { PreviewMode::None }; |     PreviewMode m_preview_mode { PreviewMode::None }; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | @ -25,14 +25,15 @@ | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @GUI::Widget { |     @GUI::GroupBox { | ||||||
|         name: "find_replace_widget" |         name: "find_replace_widget" | ||||||
|         visible: false |         visible: false | ||||||
|         fill_with_background_color: true |         fill_with_background_color: true | ||||||
|         fixed_height: 48 |         fixed_height: 56 | ||||||
| 
 | 
 | ||||||
|         layout: @GUI::VerticalBoxLayout { |         layout: @GUI::VerticalBoxLayout { | ||||||
|             margins: [2, 2, 2, 4] |             spacing: 2 | ||||||
|  |             margins: [5, 5, 5, 5] | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         @GUI::Widget { |         @GUI::Widget { | ||||||
|  | @ -41,18 +42,33 @@ | ||||||
|             fixed_height: 22 |             fixed_height: 22 | ||||||
| 
 | 
 | ||||||
|             layout: @GUI::HorizontalBoxLayout { |             layout: @GUI::HorizontalBoxLayout { | ||||||
|  |                 spacing: 4 | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             @GUI::Button { |             @GUI::Button { | ||||||
|                 name: "find_previous_button" |                 name: "find_previous_button" | ||||||
|                 text: "Find previous" |                 fixed_width: 38 | ||||||
|                 fixed_width: 150 |  | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             @GUI::Button { |             @GUI::Button { | ||||||
|                 name: "find_next_button" |                 name: "find_next_button" | ||||||
|                 text: "Find next" |                 fixed_width: 38 | ||||||
|                 fixed_width: 150 |             } | ||||||
|  | 
 | ||||||
|  |             @GUI::TextBox { | ||||||
|  |                 name: "find_textbox" | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             @GUI::CheckBox { | ||||||
|  |                 name: "regex_checkbox" | ||||||
|  |                 text: "Use RegEx" | ||||||
|  |                 fixed_width: 80 | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             @GUI::CheckBox { | ||||||
|  |                 name: "match_case_checkbox" | ||||||
|  |                 text: "Match case" | ||||||
|  |                 fixed_width: 85 | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | @ -62,24 +78,29 @@ | ||||||
|             fixed_height: 22 |             fixed_height: 22 | ||||||
| 
 | 
 | ||||||
|             layout: @GUI::HorizontalBoxLayout { |             layout: @GUI::HorizontalBoxLayout { | ||||||
|  |                 spacing: 4 | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             @GUI::Button { |             @GUI::Button { | ||||||
|                 name: "replace_previous_button" |                 name: "replace_button" | ||||||
|                 text: "Replace previous" |                 text: "Replace" | ||||||
|                 fixed_width: 100 |                 fixed_width: 80 | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             @GUI::Button { |             @GUI::TextBox { | ||||||
|                 name: "replace_next_button" |                 name: "replace_textbox" | ||||||
|                 text: "Replace next" |  | ||||||
|                 fixed_width: 100 |  | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             @GUI::Button { |             @GUI::Button { | ||||||
|                 name: "replace_all_button" |                 name: "replace_all_button" | ||||||
|                 text: "Replace all" |                 text: "Replace all" | ||||||
|                 fixed_width: 100 |                 fixed_width: 80 | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             @GUI::CheckBox { | ||||||
|  |                 name: "wrap_around_checkbox" | ||||||
|  |                 text: "Wrap around" | ||||||
|  |                 fixed_width: 85 | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -387,7 +387,7 @@ void TextDocument::update_regex_matches(const StringView& needle) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| TextRange TextDocument::find_next(const StringView& needle, const TextPosition& start, SearchShouldWrap should_wrap, bool regmatch) | TextRange TextDocument::find_next(const StringView& needle, const TextPosition& start, SearchShouldWrap should_wrap, bool regmatch, bool match_case) | ||||||
| { | { | ||||||
|     if (needle.is_empty()) |     if (needle.is_empty()) | ||||||
|         return {}; |         return {}; | ||||||
|  | @ -450,7 +450,7 @@ TextRange TextDocument::find_next(const StringView& needle, const TextPosition& | ||||||
|     do { |     do { | ||||||
|         auto ch = code_point_at(position); |         auto ch = code_point_at(position); | ||||||
|         // FIXME: This is not the right way to use a Unicode needle!
 |         // FIXME: This is not the right way to use a Unicode needle!
 | ||||||
|         if (ch == (u32)needle[needle_index]) { |         if (match_case ? ch == (u32)needle[needle_index] : tolower(ch) == tolower((u32)needle[needle_index])) { | ||||||
|             if (needle_index == 0) |             if (needle_index == 0) | ||||||
|                 start_of_potential_match = position; |                 start_of_potential_match = position; | ||||||
|             ++needle_index; |             ++needle_index; | ||||||
|  | @ -467,7 +467,7 @@ TextRange TextDocument::find_next(const StringView& needle, const TextPosition& | ||||||
|     return {}; |     return {}; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| TextRange TextDocument::find_previous(const StringView& needle, const TextPosition& start, SearchShouldWrap should_wrap, bool regmatch) | TextRange TextDocument::find_previous(const StringView& needle, const TextPosition& start, SearchShouldWrap should_wrap, bool regmatch, bool match_case) | ||||||
| { | { | ||||||
|     if (needle.is_empty()) |     if (needle.is_empty()) | ||||||
|         return {}; |         return {}; | ||||||
|  | @ -524,6 +524,8 @@ TextRange TextDocument::find_previous(const StringView& needle, const TextPositi | ||||||
| 
 | 
 | ||||||
|     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); | ||||||
|  |     if (position.line() >= line_count()) | ||||||
|  |         return {}; | ||||||
|     TextPosition original_position = position; |     TextPosition original_position = position; | ||||||
| 
 | 
 | ||||||
|     TextPosition end_of_potential_match; |     TextPosition end_of_potential_match; | ||||||
|  | @ -532,7 +534,7 @@ TextRange TextDocument::find_previous(const StringView& needle, const TextPositi | ||||||
|     do { |     do { | ||||||
|         auto ch = code_point_at(position); |         auto ch = code_point_at(position); | ||||||
|         // FIXME: This is not the right way to use a Unicode needle!
 |         // FIXME: This is not the right way to use a Unicode needle!
 | ||||||
|         if (ch == (u32)needle[needle_index]) { |         if (match_case ? ch == (u32)needle[needle_index] : tolower(ch) == tolower((u32)needle[needle_index])) { | ||||||
|             if (needle_index == needle.length() - 1) |             if (needle_index == needle.length() - 1) | ||||||
|                 end_of_potential_match = position; |                 end_of_potential_match = position; | ||||||
|             if (needle_index == 0) |             if (needle_index == 0) | ||||||
|  |  | ||||||
|  | @ -109,8 +109,8 @@ public: | ||||||
|     Vector<TextRange> find_all(const StringView& needle, bool regmatch = false); |     Vector<TextRange> find_all(const StringView& needle, bool regmatch = false); | ||||||
| 
 | 
 | ||||||
|     void update_regex_matches(const StringView&); |     void update_regex_matches(const StringView&); | ||||||
|     TextRange find_next(const StringView&, const TextPosition& start = {}, SearchShouldWrap = SearchShouldWrap::Yes, bool regmatch = false); |     TextRange find_next(const StringView&, const TextPosition& start = {}, SearchShouldWrap = SearchShouldWrap::Yes, bool regmatch = false, bool match_case = true); | ||||||
|     TextRange find_previous(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, bool match_case = true); | ||||||
| 
 | 
 | ||||||
|     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; | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 thankyouverycool
						thankyouverycool