mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 12:48:10 +00:00
LibGUI: Add MoveLineUpOrDownCommand
This allows lines moved by Ctrl+Shift+[Up, Down] to be registered as a command, i.e. cancellable by Ctrl+Z. This patch also introduces the usage of TextDocument::[take, insert]_line. Those functions forward changes to the visual lines and then avoid some data mismatch. Co-authored-by: Jorropo <jorropo.pgm@gmail.com>
This commit is contained in:
parent
cf693136e2
commit
7a8104e79b
3 changed files with 145 additions and 55 deletions
|
@ -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,55 +378,6 @@ void EditingEngine::get_selection_line_boundaries(size_t& first_line, size_t& la
|
|||
last_line -= 1;
|
||||
}
|
||||
|
||||
void EditingEngine::move_selected_lines_up()
|
||||
{
|
||||
if (!m_editor->is_editable())
|
||||
return;
|
||||
size_t first_line;
|
||||
size_t last_line;
|
||||
get_selection_line_boundaries(first_line, last_line);
|
||||
|
||||
if (first_line == 0)
|
||||
return;
|
||||
|
||||
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() });
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
m_editor->did_change();
|
||||
m_editor->update();
|
||||
}
|
||||
|
||||
void EditingEngine::move_selected_lines_down()
|
||||
{
|
||||
if (!m_editor->is_editable())
|
||||
return;
|
||||
size_t first_line;
|
||||
size_t last_line;
|
||||
get_selection_line_boundaries(first_line, last_line);
|
||||
|
||||
auto& lines = m_editor->document().lines();
|
||||
VERIFY(lines.size() != 0);
|
||||
if (last_line >= lines.size() - 1)
|
||||
return;
|
||||
|
||||
lines.insert((int)first_line, lines.take((int)last_line + 1));
|
||||
m_editor->set_cursor({ m_editor->cursor().line() + 1, m_editor->cursor().column() });
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
m_editor->did_change();
|
||||
m_editor->update();
|
||||
}
|
||||
|
||||
void EditingEngine::delete_char()
|
||||
{
|
||||
if (!m_editor->is_editable())
|
||||
|
@ -430,4 +392,105 @@ void EditingEngine::delete_line()
|
|||
m_editor->delete_current_line();
|
||||
};
|
||||
|
||||
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())
|
||||
{
|
||||
}
|
||||
|
||||
void MoveLineUpOrDownCommand::redo()
|
||||
{
|
||||
move_lines(m_direction);
|
||||
}
|
||||
|
||||
void MoveLineUpOrDownCommand::undo()
|
||||
{
|
||||
move_lines(!m_direction);
|
||||
}
|
||||
|
||||
bool MoveLineUpOrDownCommand::merge_with(GUI::Command const&)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
String MoveLineUpOrDownCommand::action_text() const
|
||||
{
|
||||
return "Move a line";
|
||||
}
|
||||
|
||||
bool MoveLineUpOrDownCommand::valid_operation(EditingEngine& engine, VerticalDirection direction)
|
||||
{
|
||||
|
||||
VERIFY(engine.editor().line_count() != 0);
|
||||
|
||||
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);
|
||||
|
||||
if ((direction == VerticalDirection::Up && first_line == 0) || (direction == VerticalDirection::Down && last_line >= engine.editor().line_count() - 1))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
TextRange MoveLineUpOrDownCommand::retrieve_selection(VerticalDirection direction)
|
||||
{
|
||||
if (direction == m_direction)
|
||||
return m_selection;
|
||||
|
||||
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_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;
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue