#include "GapBuffer.h" #include "System.h" GapBuffer::GapBuffer(Encoding::Type encoding) { m_buffer = (uint8_t *)System::alloc_pages(1u); m_buffer_size = System::page_size; m_size = 0u; m_gap_position = 0u; m_encoding = encoding; tabstop = 4u; } GapBuffer::GapBuffer(uint8_t * buffer, size_t buffer_size, size_t size, Encoding::Type encoding) { m_buffer = buffer; m_buffer_size = buffer_size; m_size = size; m_gap_position = size; m_encoding = encoding; tabstop = 4u; } GapBuffer::~GapBuffer() { System::free_pages(m_buffer, m_buffer_size >> System::page_size_log); } std::shared_ptr GapBuffer::add_cursor() { std::shared_ptr cursor = std::make_shared(this); m_cursors.push_back(cursor); return cursor; } void GapBuffer::Iterator::forward() { if (valid()) { m_offset += Encoding::num_bytes_in_code_point(m_gap_buffer->m_encoding, address()); } } bool GapBuffer::Iterator::check_forward() { if (valid()) { Iterator i2 = *this; i2.forward(); if (i2.valid()) { m_offset = i2.m_offset; return true; } } return false; } void GapBuffer::Iterator::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_gap_buffer->m_encoding, a); m_offset -= ((a - beginning_of_code_point) + 1u); } } } bool GapBuffer::Iterator::check_back() { if (valid()) { Iterator i2 = *this; i2.back(); if (i2.valid()) { m_offset = i2.m_offset; return true; } } return false; } bool GapBuffer::Cursor::is_start_of_line() { Iterator i2 = m_iterator; if (!i2.check_back()) { /* Iterator cannot go backwards so it is at beginning of buffer. */ return true; } return *i2 == '\n'; } bool GapBuffer::Cursor::go_start_of_line() { bool moved = false; Iterator i2 = m_iterator; for (;;) { i2.back(); if (i2.valid() && (*i2 != '\n')) { moved = true; m_iterator = i2; } else { break; } } if (moved) { init_column(); } return moved; } bool GapBuffer::Cursor::go_end_of_line() { bool moved = false; if (go_right()) { moved = true; } while (go_right()) { ; } return moved; } bool GapBuffer::Cursor::go_left() { if (!is_start_of_line()) { uint32_t chr = *m_iterator; if (m_iterator.check_back()) { if (chr == '\t') { calculate_column(); } else { /* TODO: handle multi-column characters */ m_column--; } return true; } } return false; } bool GapBuffer::Cursor::go_right() { if (!is_end_of_line()) { if (m_iterator.check_forward()) { uint32_t chr = *m_iterator; if (chr == '\t') { uint8_t tabstop = m_iterator.gap_buffer()->tabstop; m_column += tabstop - (m_column + 1u) % tabstop; } else { /* TODO: handle multi-column characters */ m_column++; } return true; } } return false; } void GapBuffer::Cursor::init_column() { if (*m_iterator == '\t') { m_column = m_iterator.gap_buffer()->tabstop - 1u; } else { m_column = 0u; } } void GapBuffer::Cursor::calculate_column() { Cursor tmp_cursor = *this; tmp_cursor.go_start_of_line(); while (tmp_cursor < *this) { tmp_cursor.go_right(); } m_column = tmp_cursor.m_column; }