use strop_core::Buffer;
pub(crate) fn is_word(b: u8) -> bool {
b.is_ascii_alphanumeric() || b == b'_'
}
pub(crate) fn class_of(b: u8, big: bool) -> u8 {
if big {
u8::from(!b.is_ascii_whitespace())
} else {
u8::from(is_word(b))
}
}
pub(crate) fn class_at(buf: &Buffer, pos: usize, big: bool) -> u8 {
let b = buf.byte(pos);
if b.is_ascii() {
return class_of(b, big);
}
let character = buf.text().char(buf.text().byte_to_char(pos));
if big {
u8::from(!character.is_whitespace())
} else {
u8::from(character.is_alphanumeric() || character == '_')
}
}
pub(crate) fn word_forward(buf: &Buffer, mut pos: usize, big: bool) -> usize {
let n = buf.len_bytes();
if pos >= n {
return n;
}
let start_class = class_at(buf, pos, big);
while pos < n && class_at(buf, pos, big) == start_class && !buf.byte(pos).is_ascii_whitespace()
{
pos += 1;
}
while pos < n && (buf.byte(pos).is_ascii_whitespace()) {
pos += 1;
}
pos
}
pub(crate) fn word_backward(buf: &Buffer, mut pos: usize, big: bool) -> usize {
if pos == 0 {
return 0;
}
pos -= 1;
while pos > 0 && buf.byte(pos).is_ascii_whitespace() {
pos -= 1;
}
let class = class_at(buf, pos, big);
while pos > 0
&& !buf.byte(pos - 1).is_ascii_whitespace()
&& class_at(buf, pos - 1, big) == class
{
pos -= 1;
}
pos
}
pub(crate) fn word_end(buf: &Buffer, mut pos: usize, big: bool) -> usize {
let n = buf.len_bytes();
if pos + 1 >= n {
return n.saturating_sub(1);
}
pos += 1;
while pos < n && buf.byte(pos).is_ascii_whitespace() {
pos += 1;
}
let class = class_at(buf, pos, big);
while pos + 1 < n
&& !buf.byte(pos + 1).is_ascii_whitespace()
&& class_at(buf, pos + 1, big) == class
{
pos += 1;
}
pos
}
pub(crate) fn word_end_backward(buf: &Buffer, pos: usize, big: bool) -> usize {
if pos == 0 {
return 0;
}
let mut p = pos;
if !buf.byte(p).is_ascii_whitespace() {
let class = class_at(buf, p, big);
while p > 0 && !buf.byte(p - 1).is_ascii_whitespace() && class_at(buf, p - 1, big) == class
{
p -= 1;
}
}
if p == 0 {
return 0;
}
p -= 1;
while p > 0 && buf.byte(p).is_ascii_whitespace() {
p -= 1;
}
p
}
pub(crate) fn line_blank(buf: &Buffer, line: usize) -> bool {
let (s, e) = (buf.line_start(line), buf.line_end(line));
(s..e).all(|p| buf.byte(p).is_ascii_whitespace())
}
pub(crate) fn change_word_end(buf: &Buffer, pos: usize, big: bool) -> usize {
let n = buf.len_bytes();
if pos >= n || buf.byte(pos).is_ascii_whitespace() {
return word_end(buf, pos, big);
}
let class = class_at(buf, pos, big);
let mut end = pos;
while end + 1 < n
&& !buf.byte(end + 1).is_ascii_whitespace()
&& class_at(buf, end + 1, big) == class
{
end += 1;
}
end
}