complete cursor movement routines taking Encoding and tabs into account

This commit is contained in:
Josh Holtrop 2016-08-27 16:53:55 -04:00
parent b478d17e16
commit 33a190c495
3 changed files with 74 additions and 48 deletions

View File

@ -116,25 +116,11 @@ void PieceTable::Iterator::go_prev_piece()
} }
} }
#if 0 PieceTable::Cursor::Cursor(PieceTable * pt) : iterator(pt)
uint32_t PieceTable::Cursor::column() const
{ {
/* TODO: support tabs */ line = iterator.valid() ? 1u : 0u;
Cursor sol = *this; init_column();
sol.go_start_of_line();
if (sol.piece->eol() && sol.piece->length == 0u)
{
return 0u;
}
uint32_t c = 1u;
while ((sol.piece != piece) || (sol.offset < offset))
{
sol.go_right();
c++;
}
return c;
} }
#endif
void PieceTable::Cursor::go_start_of_line() void PieceTable::Cursor::go_start_of_line()
{ {
@ -142,6 +128,7 @@ void PieceTable::Cursor::go_start_of_line()
{ {
iterator.go_prev_piece(); iterator.go_prev_piece();
} }
init_column();
} }
void PieceTable::Cursor::go_end_of_line() void PieceTable::Cursor::go_end_of_line()
@ -151,9 +138,10 @@ void PieceTable::Cursor::go_end_of_line()
iterator.go_next_piece(); iterator.go_next_piece();
} }
iterator.go_end_of_piece(); iterator.go_end_of_piece();
calculate_column();
} }
bool PieceTable::Cursor::go_up(int n) bool PieceTable::Cursor::go_up(int n, uint32_t desired_column)
{ {
Piece * p = prev_line(); Piece * p = prev_line();
if (p == nullptr) if (p == nullptr)
@ -162,14 +150,13 @@ bool PieceTable::Cursor::go_up(int n)
} }
iterator.piece = p; iterator.piece = p;
iterator.offset = 0u; iterator.offset = 0u;
#if 0 line--;
uint32_t current_column = column(); init_column();
forward_to_column(current_column); forward_to_column(desired_column);
#endif
return true; return true;
} }
bool PieceTable::Cursor::go_down(int n) bool PieceTable::Cursor::go_down(int n, uint32_t desired_column)
{ {
Piece * p = next_line(); Piece * p = next_line();
if (p == nullptr) if (p == nullptr)
@ -178,10 +165,9 @@ bool PieceTable::Cursor::go_down(int n)
} }
iterator.piece = p; iterator.piece = p;
iterator.offset = 0u; iterator.offset = 0u;
#if 0 line++;
uint32_t current_column = column(); init_column();
forward_to_column(current_column); forward_to_column(desired_column);
#endif
return true; return true;
} }
@ -191,7 +177,17 @@ bool PieceTable::Cursor::go_left(int n)
{ {
return false; return false;
} }
uint32_t chr = *iterator;
iterator.go_prev_position(); iterator.go_prev_position();
if (chr == '\t')
{
calculate_column();
}
else
{
/* TODO: handle multi-column characters */
column--;
}
return true; return true;
} }
@ -202,6 +198,17 @@ bool PieceTable::Cursor::go_right(int n)
return false; return false;
} }
iterator.go_next_position(); iterator.go_next_position();
uint32_t chr = *iterator;
if (chr == '\t')
{
column += iterator.piece_table->tabstop;
column -= column % iterator.piece_table->tabstop;
}
else
{
/* TODO: handle multi-column characters */
column++;
}
return true; return true;
} }
@ -257,23 +264,36 @@ PieceTable::Piece * PieceTable::Cursor::next_line() const
return p; return p;
} }
#if 0 void PieceTable::Cursor::init_column()
{
uint32_t chr = *iterator;
/* TODO: handle multi-column characters */
column = (chr == 0xFFFFFFFFu) ? 0u : (chr == '\t') ? iterator.piece_table->tabstop : 1u;
}
void PieceTable::Cursor::calculate_column()
{
Cursor tmp_cursor = *this;
tmp_cursor.go_start_of_line();
while ((tmp_cursor.iterator.piece != iterator.piece) ||
(tmp_cursor.iterator.offset < iterator.offset))
{
tmp_cursor.go_right(1);
}
column = tmp_cursor.column;
}
void PieceTable::Cursor::forward_to_column(uint32_t c) void PieceTable::Cursor::forward_to_column(uint32_t c)
{ {
uint32_t current_column = column(); int32_t diff = abs((int32_t)(c - column));
/* TODO: support tabs */ while (go_right(1))
/* TODO: Use Encoding */
int32_t diff = abs((int32_t)(c - current_column));
while (go_right())
{ {
current_column++; int32_t new_diff = abs((int32_t)(c - column));
int32_t new_diff = abs((int32_t)(c - current_column));
if (new_diff > diff) if (new_diff > diff)
{ {
go_left(); go_left(1);
return; return;
} }
diff = new_diff; diff = new_diff;
} }
} }
#endif

View File

@ -98,26 +98,32 @@ public:
{ {
Iterator iterator; Iterator iterator;
uint32_t line;
uint32_t column;
/** Get the character pointed to by the cursor. */ /** Get the character pointed to by the cursor. */
uint32_t operator*() const uint32_t operator*() const
{ {
return *iterator; return *iterator;
} }
Cursor(PieceTable * pt) : iterator(pt) {} Cursor(PieceTable * pt);
void go_start_of_line(); void go_start_of_line();
void go_end_of_line(); void go_end_of_line();
bool go_up(int n = 1); bool go_up(int n, uint32_t desired_column);
bool go_down(int n = 1); bool go_down(int n, uint32_t desired_column);
bool go_left(int n = 1); bool go_left(int n);
bool go_right(int n = 1); bool go_right(int n);
protected: protected:
bool is_start_of_line(); bool is_start_of_line();
bool is_end_of_line(); bool is_end_of_line();
Piece * prev_line() const; Piece * prev_line() const;
Piece * next_line() const; Piece * next_line() const;
void init_column();
void calculate_column();
void forward_to_column(uint32_t c); void forward_to_column(uint32_t c);
}; };

View File

@ -28,16 +28,16 @@ TEST(BufferTest, allows_navigating_using_cursors)
ASSERT_TRUE(b.load_from_file("test/files/line_endings/lf_format.txt")); ASSERT_TRUE(b.load_from_file("test/files/line_endings/lf_format.txt"));
std::shared_ptr<PieceTable::Cursor> cursor = b.piece_table->add_cursor(); std::shared_ptr<PieceTable::Cursor> cursor = b.piece_table->add_cursor();
ASSERT_EQ((uint32_t)'H', **cursor); ASSERT_EQ((uint32_t)'H', **cursor);
cursor->go_up(); cursor->go_up(1, cursor->column);
ASSERT_EQ((uint32_t)'H', **cursor); ASSERT_EQ((uint32_t)'H', **cursor);
cursor->go_right(); cursor->go_right(1);
ASSERT_EQ((uint32_t)'e', **cursor); ASSERT_EQ((uint32_t)'e', **cursor);
cursor->go_down(); cursor->go_down(1, cursor->column);
ASSERT_EQ((uint32_t)'h', **cursor); ASSERT_EQ((uint32_t)'h', **cursor);
cursor->go_left(); cursor->go_left(1);
ASSERT_EQ((uint32_t)'T', **cursor); ASSERT_EQ((uint32_t)'T', **cursor);
cursor->go_left(); cursor->go_left(1);
ASSERT_EQ((uint32_t)'T', **cursor); ASSERT_EQ((uint32_t)'T', **cursor);
cursor->go_down(); cursor->go_down(1, cursor->column);
ASSERT_EQ((uint32_t)'T', **cursor); ASSERT_EQ((uint32_t)'T', **cursor);
} }