use super::{Pane, Selection};
use arreliny_terminal::Screen;
pub(super) fn bounds(selection: Selection) -> ((usize, usize), (usize, usize)) {
if selection.start <= selection.end {
(selection.start, selection.end)
} else {
(selection.end, selection.start)
}
}
pub(super) fn contains(selection: Selection, line: usize, column: usize) -> bool {
let (start, end) = bounds(selection);
(line, column) >= start && (line, column) <= end
}
pub(super) fn word(screen: &Screen, line: usize, column: usize) -> Selection {
let mut column = column;
while column > 0 && screen.line_cell(line, column).width == 0 {
column -= 1;
}
let class = word_class(screen.line_cell(line, column).character);
let mut start = column;
while start > 0 {
let mut previous = start - 1;
while previous > 0 && screen.line_cell(line, previous).width == 0 {
previous -= 1;
}
if word_class(screen.line_cell(line, previous).character) != class {
break;
}
start = previous;
}
let width = screen.line_cell(line, column).width.max(1) as usize;
let mut end = (column + width - 1).min(screen.columns() - 1);
let mut next = column + width;
while next < screen.columns() {
let cell = screen.line_cell(line, next);
if word_class(cell.character) != class {
break;
}
end = (next + cell.width.max(1) as usize - 1).min(screen.columns() - 1);
next += cell.width.max(1) as usize;
}
Selection {
start: (line, start),
end: (line, end),
}
}
pub(super) fn text(pane: &Pane, trim_selection: bool) -> Option<String> {
let selection = pane.selection?;
let (start, end) = bounds(selection);
let screen = pane.terminal.screen();
let mut result = String::new();
for line in start.0..=end.0 {
let first = if line == start.0 { start.1 } else { 0 };
let last = if line == end.0 {
end.1
} else {
screen.columns().saturating_sub(1)
};
for column in first..=last {
let cell = screen.line_cell(line, column);
if cell.width != 0 {
result.push_str(&cell.text());
}
}
if trim_selection {
let trimmed = result.trim_end_matches(' ').len();
result.truncate(trimmed);
}
if line != end.0 {
result.push('\n');
}
}
Some(result)
}
fn word_class(character: char) -> u8 {
if character.is_whitespace() {
0
} else if character.is_alphanumeric() || character == '_' {
1
} else {
2
}
}