#include "Cursor.h" void Iterator::go_forward() { if (valid()) { m_offset += Encoding::num_bytes_in_code_point(m_encoding, address()); } } bool Iterator::check_go_forward() { if (valid()) { Iterator i2 = *this; i2.go_forward(); if (i2.valid()) { m_offset = i2.m_offset; return true; } } return false; } void Iterator::go_back() { if (valid()) { if (m_offset == 0u) { m_offset = 0xFFFFFFFFu; } else { const uint8_t * a = m_gap_buffer->address(m_offset - 1u); const uint8_t * beginning_of_code_point = Encoding::beginning_of_code_point(m_encoding, a); m_offset -= ((a - beginning_of_code_point) + 1u); } } } bool Iterator::check_go_back() { if (valid()) { Iterator i2 = *this; i2.go_back(); if (i2.valid()) { m_offset = i2.m_offset; return true; } } return false; } bool Cursor::is_start_of_line() { Iterator i2 = m_iterator; if (!i2.check_go_back()) { /* Iterator cannot go backwards so it is at beginning of buffer. */ return true; } return *i2 == '\n'; } bool Cursor::is_end_of_line(bool allow_eol) { if (*m_iterator == '\n') { return true; } if (!allow_eol) { Iterator i2 = m_iterator; i2.go_forward(); if (*i2 == '\n') { return true; } } return false; } bool Cursor::go_start_of_line() { bool moved = false; Iterator i2 = m_iterator; for (;;) { i2.go_back(); if (i2.valid() && (*i2 != '\n')) { moved = true; m_iterator = i2; } else { break; } } if (moved) { init_column(); } return moved; } bool Cursor::go_end_of_line(bool allow_eol) { bool moved = false; if (go_right(allow_eol)) { moved = true; } while (go_right(allow_eol)) { ; } return moved; } bool Cursor::go_left() { if (!is_start_of_line()) { uint32_t chr = *m_iterator; if (m_iterator.check_go_back()) { if (chr == '\t') { calculate_column(); } else { /* TODO: handle multi-column characters */ m_column--; } return true; } } return false; } bool Cursor::go_right(bool allow_eol) { if (!is_end_of_line(allow_eol)) { if (m_iterator.check_go_forward()) { uint32_t chr = *m_iterator; if (chr == '\t') { m_column += m_tabstop - (m_column + 1u) % m_tabstop; } else { /* TODO: handle multi-column characters */ m_column++; } return true; } } return false; } bool Cursor::go_up(size_t target_column) { Cursor c2 = *this; c2.go_start_of_line(); if (!c2.m_iterator.check_go_back()) { return false; } c2.go_start_of_line(); *this = c2; m_line--; m_column = 0u; forward_to_column(target_column); return true; } bool Cursor::go_down(size_t target_column) { Cursor c2 = *this; c2.go_end_of_line(true); if (!c2.m_iterator.check_go_forward()) { return false; } *this = c2; m_line++; m_column = 0u; forward_to_column(target_column); return true; } void Cursor::init_column() { if (*m_iterator == '\t') { m_column = m_tabstop - 1u; } else { m_column = 0u; } } void Cursor::calculate_column() { Cursor tmp_cursor = *this; tmp_cursor.go_start_of_line(); while (tmp_cursor < *this) { tmp_cursor.go_right(true); } m_column = tmp_cursor.m_column; } void Cursor::forward_to_column(size_t target_column) { int32_t diff = abs((int32_t)(target_column - m_column)); if (diff == 0) return; while (go_right(false)) { int32_t new_diff = abs((int32_t)(target_column - m_column)); if (new_diff > diff) { go_left(); return; } diff = new_diff; } }