use std::cmp::min;
use ropey::RopeSlice;
use crate::buffer::TextBuffer;
impl TextBuffer {
#[inline]
pub fn len_lines(&self) -> usize {
self.rope.len_lines()
}
#[inline]
pub fn clamp_line(&self, line: usize) -> usize {
let last = self.len_lines().saturating_sub(1);
min(line, last)
}
#[inline]
pub fn line_to_char(&self, line: usize) -> usize {
let line = self.clamp_line(line);
self.rope.line_to_char(line)
}
#[inline]
pub fn char_to_line(&self, char_idx: usize) -> usize {
let c = min(char_idx, self.len_chars());
self.rope.char_to_line(c)
}
pub fn line_len_chars(&self, line: usize) -> usize {
let line = self.clamp_line(line);
let slice = self.rope.line(line);
let mut len = slice.len_chars();
if len > 0 && slice.char(len - 1) == '\n' {
len -= 1;
}
len
}
pub fn line_first_non_whitespace_col(&self, line: usize) -> usize {
let line = self.clamp_line(line);
let slice = self.line_slice(line);
for (idx, ch) in slice.chars().enumerate() {
if !ch.is_whitespace() {
return idx;
}
}
self.line_len_chars(line)
}
pub fn line_string(&self, line: usize) -> String {
self.line_slice(line).to_string()
}
pub fn line_slice(&self, line: usize) -> RopeSlice<'_> {
let line = self.clamp_line(line);
let range = self.line_char_range(line);
self.rope.slice(range)
}
pub fn line_char_range(&self, line: usize) -> std::ops::Range<usize> {
let line = self.clamp_line(line);
let start = self.rope.line_to_char(line);
let end_including_newline = start + self.rope.line(line).len_chars();
let end =
if end_including_newline > start && self.rope.char(end_including_newline - 1) == '\n' {
end_including_newline - 1
} else {
end_including_newline
};
start..end
}
pub fn line_full_end_char(&self, line: usize) -> usize {
let line = self.clamp_line(line);
if line + 1 < self.len_lines() {
self.rope.line_to_char(line + 1)
} else {
self.rope.line_to_char(line) + self.line_len_chars(line)
}
}
}