BufferView: add functions to move cursor up/down by screen row

This commit is contained in:
Josh Holtrop 2017-09-11 22:43:38 -04:00
parent fcd198b691
commit 84759d0a36
3 changed files with 141 additions and 18 deletions

View File

@ -17,7 +17,9 @@ BufferView::BufferView(std::shared_ptr<Buffer> buffer,
m_cursor_screen_column = 0;
m_cursor_virtual_column = 0;
m_cursor_row_offset = 0;
m_target_column = 0;
m_rows_in_cursor_line = 0;
m_target_screen_column = 0;
m_target_virtual_column = 0;
m_update_target_column = false;
}
@ -43,7 +45,7 @@ void BufferView::update()
* and cursor column values. */
auto start_of_line = std::make_shared<Buffer::Iterator>(*m_iterator);
start_of_line->go_start_of_line();
int rows_in_cursor_line = calculate_rows_in_cursor_line(start_of_line);
m_rows_in_cursor_line = calculate_rows_in_cursor_line(start_of_line);
/* Limit the cursor screen row taking into account view dimensions,
* available buffer contents above and below the current line, and scroll
@ -51,7 +53,7 @@ void BufferView::update()
std::list<std::pair<int, std::shared_ptr<Buffer::Iterator>>> backward_lines;
int so = effective_scroll_offset();
int rows_above = screen_rows_above_line(start_of_line, backward_lines) + m_cursor_row_offset;
int rows_below = screen_rows_below_line(start_of_line) + std::max(0, rows_in_cursor_line - m_cursor_row_offset - 1);
int rows_below = screen_rows_below_line(start_of_line) + std::max(0, m_rows_in_cursor_line - m_cursor_row_offset - 1);
int min_rows_to_leave_above = std::min(rows_above, so);
int min_rows_to_leave_below = std::min(rows_below, so);
m_cursor_screen_row = std::min(m_height - min_rows_to_leave_below - 1, m_cursor_screen_row);
@ -120,11 +122,13 @@ bool BufferView::cursor_move(CursorMovement which, bool allow_eol)
break;
case CursorMovement::SOL:
moved = m_iterator->go_start_of_line();
m_target_column = 0;
m_target_screen_column = 0;
m_target_virtual_column = 0;
break;
case CursorMovement::EOL:
moved = m_iterator->go_end_of_line(allow_eol);
m_target_column = INT_MAX;
m_target_screen_column = INT_MAX;
m_target_virtual_column = INT_MAX;
break;
case CursorMovement::FIRST_LINE:
{
@ -135,7 +139,8 @@ bool BufferView::cursor_move(CursorMovement which, bool allow_eol)
moved = true;
}
}
m_target_column = 0;
m_target_screen_column = 0;
m_target_virtual_column = 0;
break;
case CursorMovement::LAST_LINE:
{
@ -148,19 +153,14 @@ bool BufferView::cursor_move(CursorMovement which, bool allow_eol)
moved = true;
}
}
m_target_column = 0;
m_target_screen_column = 0;
m_target_virtual_column = 0;
break;
case CursorMovement::SCREEN_ROW_UP:
/* TODO */
#if 0
moved = move_cursor_screen_row_up();
#endif
moved = move_cursor_screen_row_up(allow_eol);
break;
case CursorMovement::SCREEN_ROW_DOWN:
/* TODO */
#if 0
moved = move_cursor_screen_row_down();
#endif
moved = move_cursor_screen_row_down(allow_eol);
break;
}
if (moved)
@ -173,7 +173,7 @@ bool BufferView::cursor_move(CursorMovement which, bool allow_eol)
break;
case CursorMovement::UP:
case CursorMovement::DOWN:
move_forward_to_column(m_target_column, allow_eol);
move_forward_to_column(m_target_virtual_column, allow_eol);
determine_new_cursor_screen_row();
break;
case CursorMovement::SOL:
@ -249,7 +249,8 @@ int BufferView::calculate_rows_in_cursor_line(std::shared_ptr<Buffer::Iterator>
m_cursor_screen_column = it.screen_column();
if (m_update_target_column)
{
m_target_column = m_cursor_virtual_column;
m_target_screen_column = m_cursor_screen_column;
m_target_virtual_column = m_cursor_virtual_column;
}
m_cursor_row_offset = it.row_offset();
}
@ -311,3 +312,65 @@ void BufferView::move_forward_to_column(int to_column, bool allow_eol)
}
}
}
bool BufferView::move_cursor_screen_row_up(bool allow_eol)
{
if (m_cursor_row_offset > 0)
{
/* There are screen rows above the current in the current line. */
auto start_of_line = std::make_shared<Buffer::Iterator>(*m_iterator);
start_of_line->go_start_of_line();
move_forward_to_screen_position(start_of_line, m_cursor_row_offset - 1, allow_eol);
}
else
{
auto previous_line = std::make_shared<Buffer::Iterator>(*m_iterator);
if (!previous_line->go_previous_line())
{
return false;
}
int target_row_offset = calculate_rows_in_line(previous_line) - 1;
move_forward_to_screen_position(previous_line, target_row_offset, allow_eol);
}
return true;
}
bool BufferView::move_cursor_screen_row_down(bool allow_eol)
{
if (m_rows_in_cursor_line > (m_cursor_row_offset + 1))
{
/* There are screen rows below the current in the current line. */
auto start_of_line = std::make_shared<Buffer::Iterator>(*m_iterator);
start_of_line->go_start_of_line();
move_forward_to_screen_position(start_of_line, m_cursor_row_offset + 1, allow_eol);
}
else
{
auto next_line = std::make_shared<Buffer::Iterator>(*m_iterator);
if (!next_line->go_next_line())
{
return false;
}
move_forward_to_screen_position(next_line, 0, allow_eol);
}
return true;
}
void BufferView::move_forward_to_screen_position(
std::shared_ptr<Buffer::Iterator> line, int target_row_offset,
bool allow_eol)
{
for (auto it = horiz_iter(line); it.is_valid(); it++)
{
if ((allow_eol || (!it.is_eol())) &&
((it.row_offset() < target_row_offset) ||
(it.screen_column() <= m_target_screen_column)))
{
*m_iterator = *it.iterator();
}
else
{
break;
}
}
}

View File

@ -104,7 +104,9 @@ protected:
int m_cursor_screen_column;
int m_cursor_virtual_column;
int m_cursor_row_offset;
int m_target_column;
int m_rows_in_cursor_line;
int m_target_screen_column;
int m_target_virtual_column;
bool m_update_target_column;
int effective_scroll_offset()
@ -119,6 +121,11 @@ protected:
std::shared_ptr<Buffer::Iterator> line,
std::list<std::pair<int, std::shared_ptr<Buffer::Iterator>>> & backward_lines);
void move_forward_to_column(int to_column, bool allow_eol);
bool move_cursor_screen_row_up(bool allow_eol);
bool move_cursor_screen_row_down(bool allow_eol);
void move_forward_to_screen_position(
std::shared_ptr<Buffer::Iterator> line, int target_row_offset,
bool allow_eol);
};
#endif

View File

@ -467,3 +467,56 @@ TEST(BufferViewTest, sets_target_column_when_traversing_left_and_right)
EXPECT_EQ(1, LineNumber(iterator));
EXPECT_EQ(C('a'), **iterator);
}
TEST(BufferViewTest, moves_cursor_by_screen_row)
{
auto b = buffer1();
auto iterator = b->add_iterator();
BufferView bv(b, iterator, Cwd);
bv.resize(4, 4);
for (int i = 0; i < 6; i++)
{
EXPECT_TRUE(bv.cursor_move(BufferView::CursorMovement::SCREEN_ROW_DOWN, false));
bv.update();
EXPECT_EQ(1 + i, LineNumber(iterator));
}
EXPECT_EQ(C('6'), **iterator);
EXPECT_TRUE(bv.cursor_move(BufferView::CursorMovement::SCREEN_ROW_DOWN, false));
bv.update();
EXPECT_EQ(6, LineNumber(iterator));
EXPECT_EQ(C('d'), **iterator);
EXPECT_TRUE(bv.cursor_move(BufferView::CursorMovement::RIGHT, false));
bv.update();
EXPECT_TRUE(bv.cursor_move(BufferView::CursorMovement::RIGHT, false));
bv.update();
EXPECT_EQ(C('f'), **iterator);
EXPECT_TRUE(bv.cursor_move(BufferView::CursorMovement::SCREEN_ROW_DOWN, false));
bv.update();
EXPECT_EQ(C('7'), **iterator);
EXPECT_TRUE(bv.cursor_move(BufferView::CursorMovement::SCREEN_ROW_UP, false));
bv.update();
EXPECT_EQ(C('f'), **iterator);
EXPECT_TRUE(bv.cursor_move(BufferView::CursorMovement::SCREEN_ROW_UP, false));
bv.update();
EXPECT_EQ(C('b'), **iterator);
EXPECT_TRUE(bv.cursor_move(BufferView::CursorMovement::SCREEN_ROW_UP, false));
bv.update();
EXPECT_EQ(C('5'), **iterator);
}
TEST(BufferViewTest, cursor_move_screen_row_up_and_down_returns_false_at_top_and_bottom)
{
auto b = buffer1();
auto iterator = b->add_iterator();
BufferView bv(b, iterator, Cwd);
bv.resize(4, 4);
EXPECT_FALSE(bv.cursor_move(BufferView::CursorMovement::SCREEN_ROW_UP, false));
bv.update();
EXPECT_EQ(0, LineNumber(iterator));
for (int i = 0; i < 16; i++)
{
EXPECT_TRUE(bv.cursor_move(BufferView::CursorMovement::SCREEN_ROW_DOWN, false));
bv.update();
}
EXPECT_FALSE(bv.cursor_move(BufferView::CursorMovement::SCREEN_ROW_DOWN, false));
}