diff --git a/Userland/DevTools/Playground/main.cpp b/Userland/DevTools/Playground/main.cpp index f7a2781684..2be6b6f020 100644 --- a/Userland/DevTools/Playground/main.cpp +++ b/Userland/DevTools/Playground/main.cpp @@ -227,7 +227,7 @@ ErrorOr serenity_main(Main::Arguments arguments) TRY(edit_menu->try_add_action(GUI::Action::create("&Format GML", { Mod_Ctrl | Mod_Shift, Key_I }, [&](auto&) { auto formatted_gml_or_error = GUI::GML::format_gml(editor->text()); if (!formatted_gml_or_error.is_error()) { - editor->set_text(formatted_gml_or_error.release_value()); + editor->replace_all_text_while_keeping_undo_stack(formatted_gml_or_error.release_value()); } else { GUI::MessageBox::show( window, diff --git a/Userland/Libraries/LibGUI/TextDocument.cpp b/Userland/Libraries/LibGUI/TextDocument.cpp index 6ffe48be38..2d2a465986 100644 --- a/Userland/Libraries/LibGUI/TextDocument.cpp +++ b/Userland/Libraries/LibGUI/TextDocument.cpp @@ -884,6 +884,40 @@ void RemoveTextCommand::undo() m_document.set_all_cursors(new_cursor); } +ReplaceAllTextCommand::ReplaceAllTextCommand(GUI::TextDocument& document, String const& text, GUI::TextRange const& range) + : TextDocumentUndoCommand(document) + , m_text(text) + , m_range(range) +{ +} + +void ReplaceAllTextCommand::redo() +{ + m_document.remove(m_range); + m_document.set_all_cursors(m_range.start()); + auto new_cursor = m_document.insert_at(m_range.start(), m_text, m_client); + m_range.set_end(new_cursor); + m_document.set_all_cursors(new_cursor); +} + +void ReplaceAllTextCommand::undo() +{ + m_document.remove(m_range); + m_document.set_all_cursors(m_range.start()); + auto new_cursor = m_document.insert_at(m_range.start(), m_text); + m_document.set_all_cursors(new_cursor); +} + +bool ReplaceAllTextCommand::merge_with(GUI::Command const&) +{ + return false; +} + +String ReplaceAllTextCommand::action_text() const +{ + return "Playground format text"; +} + TextPosition TextDocument::insert_at(TextPosition const& position, StringView text, Client const* client) { TextPosition cursor = position; diff --git a/Userland/Libraries/LibGUI/TextDocument.h b/Userland/Libraries/LibGUI/TextDocument.h index afef884465..48f569cac9 100644 --- a/Userland/Libraries/LibGUI/TextDocument.h +++ b/Userland/Libraries/LibGUI/TextDocument.h @@ -236,4 +236,20 @@ private: TextRange m_range; }; +class ReplaceAllTextCommand : public GUI::TextDocumentUndoCommand { + +public: + ReplaceAllTextCommand(GUI::TextDocument& document, String const& text, GUI::TextRange const& range); + void redo() override; + void undo() override; + bool merge_with(GUI::Command const&) override; + String action_text() const override; + String const& text() const { return m_text; } + TextRange const& range() const { return m_range; } + +private: + String m_text; + GUI::TextRange m_range; +}; + } diff --git a/Userland/Libraries/LibGUI/TextEditor.cpp b/Userland/Libraries/LibGUI/TextEditor.cpp index 6d104a0437..0ea96cc616 100644 --- a/Userland/Libraries/LibGUI/TextEditor.cpp +++ b/Userland/Libraries/LibGUI/TextEditor.cpp @@ -1446,6 +1446,19 @@ void TextEditor::insert_at_cursor_or_replace_selection(StringView text) } } +void TextEditor::replace_all_text_while_keeping_undo_stack(StringView text) +{ + auto start = GUI::TextPosition(0, 0); + auto last_line_index = line_count() - 1; + auto end = GUI::TextPosition(last_line_index, line(last_line_index).length()); + auto range = GUI::TextRange(start, end); + auto normalized_range = range.normalized(); + execute(text, range); + did_change(); + set_cursor(normalized_range.start()); + update(); +} + void TextEditor::cut() { if (!is_editable()) diff --git a/Userland/Libraries/LibGUI/TextEditor.h b/Userland/Libraries/LibGUI/TextEditor.h index ac3d536126..cb4d2f58ff 100644 --- a/Userland/Libraries/LibGUI/TextEditor.h +++ b/Userland/Libraries/LibGUI/TextEditor.h @@ -123,6 +123,7 @@ public: TextRange normalized_selection() const { return m_selection.normalized(); } void insert_at_cursor_or_replace_selection(StringView); + void replace_all_text_while_keeping_undo_stack(StringView text); bool write_to_file(String const& path); bool write_to_file(Core::File&); bool has_selection() const { return m_selection.is_valid(); }