Files
crib/src/editor/boundaries.cc

119 lines
3.1 KiB
C++

#include "editor/editor.h"
uint32_t scan_left(const char *line, uint32_t len, uint32_t off) {
if (off > len)
off = len;
uint32_t i = off;
while (i > 0) {
unsigned char c = (unsigned char)line[i - 1];
if ((c & 0x80) != 0)
break;
if (!((c == '_') || (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') ||
(c >= 'a' && c <= 'z')))
break;
--i;
}
return i;
}
uint32_t scan_right(const char *line, uint32_t len, uint32_t off) {
if (off > len)
off = len;
uint32_t i = off;
while (i < len) {
unsigned char c = (unsigned char)line[i];
if ((c & 0x80) != 0)
break;
if (!((c == '_') || (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') ||
(c >= 'a' && c <= 'z')))
break;
++i;
}
return i;
}
void word_boundaries_exclusive(Editor *editor, Coord coord, uint32_t *prev_col,
uint32_t *next_col) {
if (!editor)
return;
std::shared_lock lock(editor->knot_mtx);
LineIterator *it = begin_l_iter(editor->root, coord.row);
if (!it)
return;
uint32_t line_len;
char *line = next_line(it, &line_len);
if (!line) {
free(it->buffer);
free(it);
return;
}
if (line_len && line[line_len - 1] == '\n')
line_len--;
uint32_t col = coord.col;
if (col > line_len)
col = line_len;
uint32_t left = scan_left(line, line_len, col);
uint32_t right = scan_right(line, line_len, col);
if (prev_col)
*prev_col = left;
if (next_col)
*next_col = right;
free(it->buffer);
free(it);
}
uint32_t word_jump_right(const char *line, size_t len, uint32_t pos) {
if (pos >= len)
return len;
size_t next = grapheme_next_word_break_utf8(line + pos, len - pos);
return static_cast<uint32_t>(pos + next);
}
uint32_t word_jump_left(const char *line, size_t len, uint32_t col) {
if (col == 0)
return 0;
size_t pos = 0;
size_t last = 0;
size_t cursor = col;
while (pos < len) {
size_t next = pos + grapheme_next_word_break_utf8(line + pos, len - pos);
if (next >= cursor)
break;
last = next;
pos = next;
}
return static_cast<uint32_t>(last);
}
void word_boundaries(Editor *editor, Coord coord, uint32_t *prev_col,
uint32_t *next_col, uint32_t *prev_clusters,
uint32_t *next_clusters) {
if (!editor)
return;
std::shared_lock lock(editor->knot_mtx);
LineIterator *it = begin_l_iter(editor->root, coord.row);
if (!it)
return;
uint32_t line_len;
char *line = next_line(it, &line_len);
if (!line)
return;
if (line_len && line[line_len - 1] == '\n')
line_len--;
size_t col = coord.col;
if (col > line_len)
col = line_len;
size_t left = word_jump_left(line, line_len, col);
size_t right = word_jump_right(line, line_len, col);
if (prev_col)
*prev_col = static_cast<uint32_t>(left);
if (next_col)
*next_col = static_cast<uint32_t>(right);
if (prev_clusters)
*prev_clusters = count_clusters(line, line_len, left, col);
if (next_clusters)
*next_clusters = count_clusters(line, line_len, col, right);
free(it->buffer);
free(it);
}