114 lines
3.0 KiB
C++
Executable File
114 lines
3.0 KiB
C++
Executable File
#include "editor/decl.h"
|
|
#include "io/knot.h"
|
|
#include "io/sysio.h"
|
|
#include "utils/utils.h"
|
|
|
|
struct GraphemeIterator {
|
|
char *line{nullptr};
|
|
uint32_t len{0};
|
|
|
|
GraphemeIterator(char *line, uint32_t len) : line(line), len(len) {}
|
|
|
|
char *next(uint32_t *o_len, uint32_t *o_width) {
|
|
if (!line || len == 0)
|
|
return nullptr;
|
|
char *cur = line;
|
|
uint32_t g = grapheme_next_character_break_utf8(cur, len);
|
|
if (o_width)
|
|
*o_width = display_width(cur, g);
|
|
if (o_len)
|
|
*o_len = g;
|
|
line += g;
|
|
len -= g;
|
|
return cur;
|
|
}
|
|
};
|
|
|
|
struct VisualIterator {
|
|
LineIterator *it{nullptr};
|
|
uint32_t line_index{UINT32_MAX};
|
|
uint32_t offset{0};
|
|
uint32_t len{0};
|
|
bool first{true};
|
|
char *line{nullptr};
|
|
uint32_t render_width{io::cols};
|
|
std::stack<std::pair<Coord, Coord>> prev_stack;
|
|
|
|
VisualIterator(Knot *root, Coord pos, uint32_t width)
|
|
: it(begin_l_iter(root, pos.row)), line_index(pos.row - 1),
|
|
offset(pos.col), render_width(width) {}
|
|
|
|
std::pair<Coord, Coord> prev() {
|
|
if (!it)
|
|
return {{UINT32_MAX, UINT32_MAX}, {UINT32_MAX, UINT32_MAX}};
|
|
if (prev_stack.empty())
|
|
return _prev();
|
|
auto ret = prev_stack.top();
|
|
offset = ret.first.col;
|
|
prev_stack.pop();
|
|
return ret;
|
|
}
|
|
|
|
std::pair<Coord, Coord> _prev() {
|
|
if (!it)
|
|
return {{UINT32_MAX, UINT32_MAX}, {UINT32_MAX, UINT32_MAX}};
|
|
line_index--;
|
|
line = prev_line(it, &len);
|
|
if (!line)
|
|
return {{UINT32_MAX, UINT32_MAX}, {UINT32_MAX, UINT32_MAX}};
|
|
if (len > 0 && line[len - 1] == '\n')
|
|
len--;
|
|
offset = first ? offset : 0;
|
|
first = false;
|
|
GraphemeIterator g(line + offset, len - offset);
|
|
uint32_t o_len, o_width, rendered = 0, advance = 0;
|
|
while (g.next(&o_len, &o_width)) {
|
|
if (rendered + o_width > render_width) {
|
|
prev_stack.push({{line_index, offset}, {line_index, offset + advance}});
|
|
offset += advance;
|
|
rendered = 0;
|
|
advance = 0;
|
|
}
|
|
advance += o_len;
|
|
rendered += o_width;
|
|
}
|
|
return {{line_index, offset}, {line_index, offset + advance}};
|
|
}
|
|
|
|
std::pair<Coord, Coord> next() {
|
|
if (!it)
|
|
return {{UINT32_MAX, UINT32_MAX}, {UINT32_MAX, UINT32_MAX}};
|
|
if (!line) {
|
|
line_index++;
|
|
line = next_line(it, &len);
|
|
if (!line)
|
|
return {{UINT32_MAX, UINT32_MAX}, {UINT32_MAX, UINT32_MAX}};
|
|
if (len > 0 && line[len - 1] == '\n')
|
|
len--;
|
|
offset = first ? offset : 0;
|
|
first = false;
|
|
}
|
|
GraphemeIterator g(line + offset, len - offset);
|
|
uint32_t o_len, o_width, rendered = 0, advance = 0;
|
|
while (g.next(&o_len, &o_width)) {
|
|
if (rendered + o_width > render_width) {
|
|
offset += advance;
|
|
return {{line_index, offset - advance}, {line_index, offset}};
|
|
}
|
|
advance += o_len;
|
|
rendered += o_width;
|
|
}
|
|
offset += advance;
|
|
if (offset >= len)
|
|
line = nullptr;
|
|
return {{line_index, offset}, {line_index, offset + advance}};
|
|
}
|
|
|
|
~VisualIterator() {
|
|
if (!it)
|
|
return;
|
|
free(it->buffer);
|
|
free(it);
|
|
}
|
|
};
|