Move folder
This commit is contained in:
113
include/editor/visual.h
Executable file
113
include/editor/visual.h
Executable file
@@ -0,0 +1,113 @@
|
||||
#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)), offset(pos.col),
|
||||
line_index(pos.row - 1), 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);
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user