BufferView: add functions to move cursor up/down by screen row
This commit is contained in:
parent
fcd198b691
commit
84759d0a36
@ -17,7 +17,9 @@ BufferView::BufferView(std::shared_ptr<Buffer> buffer,
|
|||||||
m_cursor_screen_column = 0;
|
m_cursor_screen_column = 0;
|
||||||
m_cursor_virtual_column = 0;
|
m_cursor_virtual_column = 0;
|
||||||
m_cursor_row_offset = 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;
|
m_update_target_column = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,7 +45,7 @@ void BufferView::update()
|
|||||||
* and cursor column values. */
|
* and cursor column values. */
|
||||||
auto start_of_line = std::make_shared<Buffer::Iterator>(*m_iterator);
|
auto start_of_line = std::make_shared<Buffer::Iterator>(*m_iterator);
|
||||||
start_of_line->go_start_of_line();
|
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,
|
/* Limit the cursor screen row taking into account view dimensions,
|
||||||
* available buffer contents above and below the current line, and scroll
|
* 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;
|
std::list<std::pair<int, std::shared_ptr<Buffer::Iterator>>> backward_lines;
|
||||||
int so = effective_scroll_offset();
|
int so = effective_scroll_offset();
|
||||||
int rows_above = screen_rows_above_line(start_of_line, backward_lines) + m_cursor_row_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_above = std::min(rows_above, so);
|
||||||
int min_rows_to_leave_below = std::min(rows_below, 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);
|
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;
|
break;
|
||||||
case CursorMovement::SOL:
|
case CursorMovement::SOL:
|
||||||
moved = m_iterator->go_start_of_line();
|
moved = m_iterator->go_start_of_line();
|
||||||
m_target_column = 0;
|
m_target_screen_column = 0;
|
||||||
|
m_target_virtual_column = 0;
|
||||||
break;
|
break;
|
||||||
case CursorMovement::EOL:
|
case CursorMovement::EOL:
|
||||||
moved = m_iterator->go_end_of_line(allow_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;
|
break;
|
||||||
case CursorMovement::FIRST_LINE:
|
case CursorMovement::FIRST_LINE:
|
||||||
{
|
{
|
||||||
@ -135,7 +139,8 @@ bool BufferView::cursor_move(CursorMovement which, bool allow_eol)
|
|||||||
moved = true;
|
moved = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_target_column = 0;
|
m_target_screen_column = 0;
|
||||||
|
m_target_virtual_column = 0;
|
||||||
break;
|
break;
|
||||||
case CursorMovement::LAST_LINE:
|
case CursorMovement::LAST_LINE:
|
||||||
{
|
{
|
||||||
@ -148,19 +153,14 @@ bool BufferView::cursor_move(CursorMovement which, bool allow_eol)
|
|||||||
moved = true;
|
moved = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_target_column = 0;
|
m_target_screen_column = 0;
|
||||||
|
m_target_virtual_column = 0;
|
||||||
break;
|
break;
|
||||||
case CursorMovement::SCREEN_ROW_UP:
|
case CursorMovement::SCREEN_ROW_UP:
|
||||||
/* TODO */
|
moved = move_cursor_screen_row_up(allow_eol);
|
||||||
#if 0
|
|
||||||
moved = move_cursor_screen_row_up();
|
|
||||||
#endif
|
|
||||||
break;
|
break;
|
||||||
case CursorMovement::SCREEN_ROW_DOWN:
|
case CursorMovement::SCREEN_ROW_DOWN:
|
||||||
/* TODO */
|
moved = move_cursor_screen_row_down(allow_eol);
|
||||||
#if 0
|
|
||||||
moved = move_cursor_screen_row_down();
|
|
||||||
#endif
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (moved)
|
if (moved)
|
||||||
@ -173,7 +173,7 @@ bool BufferView::cursor_move(CursorMovement which, bool allow_eol)
|
|||||||
break;
|
break;
|
||||||
case CursorMovement::UP:
|
case CursorMovement::UP:
|
||||||
case CursorMovement::DOWN:
|
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();
|
determine_new_cursor_screen_row();
|
||||||
break;
|
break;
|
||||||
case CursorMovement::SOL:
|
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();
|
m_cursor_screen_column = it.screen_column();
|
||||||
if (m_update_target_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();
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -104,7 +104,9 @@ protected:
|
|||||||
int m_cursor_screen_column;
|
int m_cursor_screen_column;
|
||||||
int m_cursor_virtual_column;
|
int m_cursor_virtual_column;
|
||||||
int m_cursor_row_offset;
|
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;
|
bool m_update_target_column;
|
||||||
|
|
||||||
int effective_scroll_offset()
|
int effective_scroll_offset()
|
||||||
@ -119,6 +121,11 @@ protected:
|
|||||||
std::shared_ptr<Buffer::Iterator> line,
|
std::shared_ptr<Buffer::Iterator> line,
|
||||||
std::list<std::pair<int, std::shared_ptr<Buffer::Iterator>>> & backward_lines);
|
std::list<std::pair<int, std::shared_ptr<Buffer::Iterator>>> & backward_lines);
|
||||||
void move_forward_to_column(int to_column, bool allow_eol);
|
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
|
#endif
|
||||||
|
@ -467,3 +467,56 @@ TEST(BufferViewTest, sets_target_column_when_traversing_left_and_right)
|
|||||||
EXPECT_EQ(1, LineNumber(iterator));
|
EXPECT_EQ(1, LineNumber(iterator));
|
||||||
EXPECT_EQ(C('a'), **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));
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user