move character iteration logic from BufferView to BufferLineWalker

This commit is contained in:
Josh Holtrop 2017-08-24 20:52:33 -04:00
parent 65df0c2320
commit 3d4e8230fe
4 changed files with 130 additions and 58 deletions

View File

@ -0,0 +1,101 @@
#include "BufferLineWalker.h"
/**
* Construct a BufferLineWalker.
*/
BufferLineWalker::BufferLineWalker(
std::shared_ptr<Buffer> buffer,
CharacterWidthDeterminer & character_width_determiner)
: m_buffer(buffer),
m_character_width_determiner(character_width_determiner)
{
m_width = 1;
}
/**
* Set the view width.
*
* @param width View width.
*/
void BufferLineWalker::set_width(int width)
{
m_width = std::max(1, width);
}
/**
* Invoke the callback for each character in the buffer line, wrapping to the
* next screen line and taking into account multi-column characters.
*
* Callback parameters:
* - row_offset
* - screen column
* - virtual column
* - character width
* - buffer iterator
* If the callback function returns true, iteration continues. Otherwise
* iteration is terminated.
*
* @param start_of_line Buffer iterator pointing to the beginning of the buffer line.
* @param callback Function to call for each character in the line.
*/
void BufferLineWalker::walk_line(
const Buffer::Iterator & start_of_line,
std::function<bool(int, int, int, int, const Buffer::Iterator &)> callback)
{
int row_offset = 0;
int screen_column = 0;
int virtual_column = 0;
Buffer::Iterator i = start_of_line;
for (;;)
{
uint32_t code_point = *i;
if ((code_point == '\n') || (!i.valid()))
{
callback(row_offset, screen_column, virtual_column, 0, i);
break;
}
int c_width;
if (code_point == '\t')
{
uint8_t tabstop = m_buffer->tabstop();
c_width = tabstop - virtual_column % tabstop;
}
else
{
c_width = m_character_width_determiner(code_point);
if (((screen_column + c_width) > m_width) &&
(screen_column > 0))
{
row_offset++;
screen_column = 0;
}
}
if (!callback(row_offset, screen_column, virtual_column, c_width, i))
{
break;
}
virtual_column += c_width;
if (code_point == '\t')
{
screen_column += c_width;
while (screen_column >= m_width)
{
screen_column -= m_width;
row_offset++;
}
}
else
{
if ((screen_column + c_width) >= m_width)
{
row_offset++;
screen_column = 0;
}
else
{
screen_column += c_width;
}
}
i.go_forward();
}
}

View File

@ -0,0 +1,29 @@
#ifndef BUFFERLINEWALKER_H
#define BUFFERLINEWALKER_H
#include "Buffer.h"
#include "CharacterWidthDeterminer.h"
#include <functional>
/**
* Provides functionality to walk a line of a buffer taking into account the
* view width and multi-column characters.
*/
class BufferLineWalker
{
public:
BufferLineWalker(
std::shared_ptr<Buffer> buffer,
CharacterWidthDeterminer & character_width_determiner);
void set_width(int width);
void walk_line(
const Buffer::Iterator & start_of_line,
std::function<bool(int, int, int, int, const Buffer::Iterator &)> callback);
protected:
std::shared_ptr<Buffer> m_buffer;
CharacterWidthDeterminer & m_character_width_determiner;
int m_width;
};
#endif

View File

@ -23,60 +23,3 @@ void BufferView::set_scroll_offset(int scroll_offset)
{ {
m_scroll_offset = std::max(0, scroll_offset); m_scroll_offset = std::max(0, scroll_offset);
} }
void BufferView::iter_cols(const Buffer::Iterator & start_of_line, std::function<void(int, int, int, int, const Buffer::Iterator &)> callback)
{
int row_offset = 0;
int screen_column = 0;
int virtual_column = 0;
Buffer::Iterator i = start_of_line;
for (;;)
{
uint32_t code_point = *i;
if ((code_point == '\n') || (!i.valid()))
{
callback(row_offset, screen_column, virtual_column, 0, i);
break;
}
int c_width;
if (code_point == '\t')
{
uint8_t tabstop = m_buffer->tabstop();
c_width = tabstop - virtual_column % tabstop;
}
else
{
c_width = m_character_width_determiner(code_point);
if (((screen_column + c_width) > m_width) &&
(screen_column > 0))
{
row_offset++;
screen_column = 0;
}
}
callback(row_offset, screen_column, virtual_column, c_width, i);
virtual_column += c_width;
if (code_point == '\t')
{
screen_column += c_width;
while (screen_column >= m_width)
{
screen_column -= m_width;
row_offset++;
}
}
else
{
if ((screen_column + c_width) >= m_width)
{
row_offset++;
screen_column = 0;
}
else
{
screen_column += c_width;
}
}
i.go_forward();
}
}

View File

@ -18,7 +18,6 @@ public:
void resize(int width, int height); void resize(int width, int height);
void set_scroll_offset(int scroll_offset); void set_scroll_offset(int scroll_offset);
void iter_lines(std::function<bool(const Buffer::Iterator &)> callback); void iter_lines(std::function<bool(const Buffer::Iterator &)> callback);
void iter_cols(const Buffer::Iterator & start_of_line, std::function<void(int, int, int, int, const Buffer::Iterator &)> callback);
protected: protected:
std::shared_ptr<Buffer> m_buffer; std::shared_ptr<Buffer> m_buffer;