diff options
Diffstat (limited to 'Userland')
-rw-r--r-- | Userland/Libraries/LibGUI/EditingEngine.cpp | 153 | ||||
-rw-r--r-- | Userland/Libraries/LibGUI/EditingEngine.h | 25 | ||||
-rw-r--r-- | Userland/Libraries/LibGUI/TextEditor.h | 6 |
3 files changed, 137 insertions, 47 deletions
diff --git a/Userland/Libraries/LibGUI/EditingEngine.cpp b/Userland/Libraries/LibGUI/EditingEngine.cpp index 5f2d6cfc0d..028a7bb24e 100644 --- a/Userland/Libraries/LibGUI/EditingEngine.cpp +++ b/Userland/Libraries/LibGUI/EditingEngine.cpp @@ -259,8 +259,11 @@ EditingEngine::DidMoveALine EditingEngine::move_one_up(KeyEvent const& event) { if (m_editor->cursor().line() > 0 || m_editor->is_wrapping_enabled()) { if (event.ctrl() && event.shift()) { - move_selected_lines_up(); - return DidMoveALine::Yes; + if (MoveLineUpOrDownCommand::valid_operation(*this, VerticalDirection::Up)) { + m_editor->execute<MoveLineUpOrDownCommand>(Badge<EditingEngine> {}, event, *this); + return DidMoveALine::Yes; + } + return DidMoveALine::No; } TextPosition new_cursor; if (m_editor->is_wrapping_enabled()) { @@ -280,8 +283,11 @@ EditingEngine::DidMoveALine EditingEngine::move_one_down(KeyEvent const& event) { if (m_editor->cursor().line() < (m_editor->line_count() - 1) || m_editor->is_wrapping_enabled()) { if (event.ctrl() && event.shift()) { - move_selected_lines_down(); - return DidMoveALine::Yes; + if (MoveLineUpOrDownCommand::valid_operation(*this, VerticalDirection::Down)) { + m_editor->execute<MoveLineUpOrDownCommand>(Badge<EditingEngine> {}, event, *this); + return DidMoveALine::Yes; + } + return DidMoveALine::No; } TextPosition new_cursor; if (m_editor->is_wrapping_enabled()) { @@ -353,6 +359,11 @@ void EditingEngine::move_to_last_line() m_editor->set_cursor(m_editor->line_count() - 1, m_editor->lines()[m_editor->line_count() - 1].length()); }; +void EditingEngine::get_selection_line_boundaries(Badge<MoveLineUpOrDownCommand>, size_t& first_line, size_t& last_line) +{ + get_selection_line_boundaries(first_line, last_line); +} + void EditingEngine::get_selection_line_boundaries(size_t& first_line, size_t& last_line) { auto selection = m_editor->normalized_selection(); @@ -367,67 +378,119 @@ void EditingEngine::get_selection_line_boundaries(size_t& first_line, size_t& la last_line -= 1; } -void EditingEngine::move_selected_lines_up() +void EditingEngine::delete_char() { if (!m_editor->is_editable()) return; - size_t first_line; - size_t last_line; - get_selection_line_boundaries(first_line, last_line); + m_editor->do_delete(); +}; - if (first_line == 0) +void EditingEngine::delete_line() +{ + if (!m_editor->is_editable()) return; + m_editor->delete_current_line(); +}; - auto& lines = m_editor->document().lines(); - lines.insert((int)last_line, lines.take((int)first_line - 1)); - m_editor->set_cursor({ m_editor->cursor().line() - 1, m_editor->cursor().column() }); +MoveLineUpOrDownCommand::MoveLineUpOrDownCommand(TextDocument& document, KeyEvent event, EditingEngine& engine) + : TextDocumentUndoCommand(document) + , m_event(move(event)) + , m_direction(key_code_to_vertical_direction(m_event.key())) + , m_engine(engine) + , m_selection(m_engine.editor().selection()) + , m_cursor(m_engine.editor().cursor()) +{ +} - if (m_editor->has_selection()) { - m_editor->selection().start().set_line(m_editor->selection().start().line() - 1); - m_editor->selection().end().set_line(m_editor->selection().end().line() - 1); - } +void MoveLineUpOrDownCommand::redo() +{ + move_lines(m_direction); +} - m_editor->did_change(); - m_editor->update(); +void MoveLineUpOrDownCommand::undo() +{ + move_lines(!m_direction); } -void EditingEngine::move_selected_lines_down() +bool MoveLineUpOrDownCommand::merge_with(GUI::Command const&) { - if (!m_editor->is_editable()) - return; - size_t first_line; - size_t last_line; - get_selection_line_boundaries(first_line, last_line); + return false; +} - auto& lines = m_editor->document().lines(); - VERIFY(lines.size() != 0); - if (last_line >= lines.size() - 1) - return; +String MoveLineUpOrDownCommand::action_text() const +{ + return "Move a line"; +} + +bool MoveLineUpOrDownCommand::valid_operation(EditingEngine& engine, VerticalDirection direction) +{ - lines.insert((int)first_line, lines.take((int)last_line + 1)); - m_editor->set_cursor({ m_editor->cursor().line() + 1, m_editor->cursor().column() }); + VERIFY(engine.editor().line_count() != 0); - if (m_editor->has_selection()) { - m_editor->selection().start().set_line(m_editor->selection().start().line() + 1); - m_editor->selection().end().set_line(m_editor->selection().end().line() + 1); - } + auto const& selection = engine.editor().selection().normalized(); + if (selection.is_valid()) { + if ((direction == VerticalDirection::Up && selection.start().line() == 0) || (direction == VerticalDirection::Down && selection.end().line() >= engine.editor().line_count() - 1)) + return false; + } else { + size_t first_line; + size_t last_line; + engine.get_selection_line_boundaries(Badge<MoveLineUpOrDownCommand> {}, first_line, last_line); - m_editor->did_change(); - m_editor->update(); + if ((direction == VerticalDirection::Up && first_line == 0) || (direction == VerticalDirection::Down && last_line >= engine.editor().line_count() - 1)) + return false; + } + return true; } -void EditingEngine::delete_char() +TextRange MoveLineUpOrDownCommand::retrieve_selection(VerticalDirection direction) { - if (!m_editor->is_editable()) - return; - m_editor->do_delete(); -}; + if (direction == m_direction) + return m_selection; -void EditingEngine::delete_line() + auto const offset_selection = [this](auto const offset) { + auto tmp = m_selection; + tmp.start().set_line(tmp.start().line() + offset); + tmp.end().set_line(tmp.end().line() + offset); + + return tmp; + }; + + if (direction == VerticalDirection::Up) + return offset_selection(1); + if (direction == VerticalDirection::Down) + return offset_selection(-1); + VERIFY_NOT_REACHED(); +} + +void MoveLineUpOrDownCommand::move_lines(VerticalDirection direction) { - if (!m_editor->is_editable()) + if (m_event.shift() && m_selection.is_valid()) { + m_engine.editor().set_selection(retrieve_selection(direction)); + m_engine.editor().did_update_selection(); + } + + if (!m_engine.editor().is_editable()) return; - m_editor->delete_current_line(); -}; + + size_t first_line; + size_t last_line; + m_engine.get_selection_line_boundaries(Badge<MoveLineUpOrDownCommand> {}, first_line, last_line); + + auto const offset = direction == VerticalDirection::Up ? -1 : 1; + auto const insertion_index = direction == VerticalDirection::Up ? last_line : first_line; + auto const moved_line_index = offset + (direction != VerticalDirection::Up ? last_line : first_line); + + auto moved_line = m_document.take_line(moved_line_index); + m_document.insert_line(insertion_index, move(moved_line)); + + m_engine.editor().set_cursor({ m_engine.editor().cursor().line() + offset, m_engine.editor().cursor().column() }); + if (m_engine.editor().has_selection()) { + m_engine.editor().selection().start().set_line(m_engine.editor().selection().start().line() + offset); + m_engine.editor().selection().end().set_line(m_engine.editor().selection().end().line() + offset); + } + + m_engine.editor().did_change(); + m_engine.editor().update(); +} } diff --git a/Userland/Libraries/LibGUI/EditingEngine.h b/Userland/Libraries/LibGUI/EditingEngine.h index 13c71a3dca..d6dacb1205 100644 --- a/Userland/Libraries/LibGUI/EditingEngine.h +++ b/Userland/Libraries/LibGUI/EditingEngine.h @@ -22,6 +22,8 @@ enum EngineType { Vim, }; +class MoveLineUpOrDownCommand; + class EditingEngine { AK_MAKE_NONCOPYABLE(EditingEngine); AK_MAKE_NONMOVABLE(EditingEngine); @@ -45,6 +47,8 @@ public: bool is_regular() const { return engine_type() == EngineType::Regular; } bool is_vim() const { return engine_type() == EngineType::Vim; } + void get_selection_line_boundaries(Badge<MoveLineUpOrDownCommand>, size_t& first_line, size_t& last_line); + protected: EditingEngine() = default; @@ -80,10 +84,27 @@ protected: void delete_char(); virtual EngineType engine_type() const = 0; +}; + +class MoveLineUpOrDownCommand : public TextDocumentUndoCommand { +public: + MoveLineUpOrDownCommand(TextDocument&, KeyEvent event, EditingEngine&); + virtual void undo() override; + virtual void redo() override; + bool merge_with(GUI::Command const&) override; + String action_text() const override; + + static bool valid_operation(EditingEngine& engine, VerticalDirection direction); private: - void move_selected_lines_up(); - void move_selected_lines_down(); + void move_lines(VerticalDirection); + TextRange retrieve_selection(VerticalDirection); + + KeyEvent m_event; + VerticalDirection m_direction; + EditingEngine& m_engine; + TextRange m_selection; + TextPosition m_cursor; }; } diff --git a/Userland/Libraries/LibGUI/TextEditor.h b/Userland/Libraries/LibGUI/TextEditor.h index b5b8dd374f..547ac759a3 100644 --- a/Userland/Libraries/LibGUI/TextEditor.h +++ b/Userland/Libraries/LibGUI/TextEditor.h @@ -229,6 +229,12 @@ public: virtual Optional<UISize> calculated_min_size() const override; + template<class T, class... Args> + inline void execute(Badge<EditingEngine>, Args&&... args) + { + execute<T>(forward<Args>(args)...); + } + protected: explicit TextEditor(Type = Type::MultiLine); |