use crate::{col, row, ColIndex, ColWidth, EditorBuffer, RowHeight, RowIndex};
#[derive(Clone, Eq, PartialEq, Debug)]
pub enum CaretColLocationInLine {
AtStart,
AtEnd,
InMiddle,
}
#[derive(Clone, Eq, PartialEq, Debug)]
pub enum CaretRowLocationInBuffer {
AtTop,
AtBottom,
InMiddle,
}
#[must_use]
pub fn locate_col(editor_buffer: &EditorBuffer) -> CaretColLocationInLine {
if col_is_at_start_of_line(editor_buffer) {
CaretColLocationInLine::AtStart
} else if col_is_at_end_of_line(editor_buffer) {
CaretColLocationInLine::AtEnd
} else {
CaretColLocationInLine::InMiddle
}
}
fn col_is_at_start_of_line(buffer: &EditorBuffer) -> bool {
if buffer.line_at_caret_scr_adj().is_some() {
buffer.get_caret_scr_adj().col_index == col(0)
} else {
false
}
}
fn col_is_at_end_of_line(buffer: &EditorBuffer) -> bool {
if buffer.line_at_caret_scr_adj().is_some() {
let line_display_width = buffer.get_line_display_width_at_caret_scr_adj();
buffer.get_caret_scr_adj().col_index
== caret_scroll_index::col_index_for_width(line_display_width)
} else {
false
}
}
#[must_use]
pub fn locate_row(buffer: &EditorBuffer) -> CaretRowLocationInBuffer {
if row_is_at_top_of_buffer(buffer) {
CaretRowLocationInBuffer::AtTop
} else if row_is_at_bottom_of_buffer(buffer) {
CaretRowLocationInBuffer::AtBottom
} else {
CaretRowLocationInBuffer::InMiddle
}
}
fn row_is_at_top_of_buffer(buffer: &EditorBuffer) -> bool {
buffer.get_caret_scr_adj().row_index == row(0)
}
fn row_is_at_bottom_of_buffer(buffer: &EditorBuffer) -> bool {
if buffer.is_empty() || buffer.get_lines().len() == 1 {
false
} else {
let max_row_index = buffer.get_max_row_index();
buffer.get_caret_scr_adj().row_index == max_row_index
}
}
pub mod caret_scroll_index {
use super::{col, row, ColIndex, ColWidth, RowHeight, RowIndex};
#[must_use]
pub fn col_index_for_width(col_amt: ColWidth) -> ColIndex {
col_amt.convert_to_col_index() + col(1)
}
#[must_use]
pub fn row_index_for_height(row_amt: RowHeight) -> RowIndex {
row_amt.convert_to_row_index() + row(1)
}
#[test]
fn test_scroll_col_index_for_width() {
use crate::width;
let width = width(5);
let scroll_col_index = col_index_for_width(width);
assert_eq!(*scroll_col_index, *width);
}
#[test]
fn test_scroll_row_index_for_height() {
use crate::height;
let height = height(5);
let scroll_row_index = row_index_for_height(height);
assert_eq!(*scroll_row_index, *height);
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{assert_eq2, EditorEngine, EditorEngineConfig};
#[test]
fn test_locate_col_at_start() {
let mut buffer = EditorBuffer::new_empty(None, None);
buffer.init_with(vec!["Hello World"]);
let engine = EditorEngine::new(EditorEngineConfig::default());
{
let buffer_mut = buffer.get_mut(engine.viewport());
buffer_mut.inner.caret_raw.row_index = row(0);
buffer_mut.inner.caret_raw.col_index = col(0);
}
let location = locate_col(&buffer);
assert_eq2!(location, CaretColLocationInLine::AtStart);
}
#[test]
fn test_locate_col_at_end() {
let mut buffer = EditorBuffer::new_empty(None, None);
buffer.init_with(vec!["Hello World"]);
let engine = EditorEngine::new(EditorEngineConfig::default());
let line_width = buffer.get_lines()[0].display_width;
{
let buffer_mut = buffer.get_mut(engine.viewport());
buffer_mut.inner.caret_raw.row_index = row(0);
buffer_mut.inner.caret_raw.col_index = caret_scroll_index::col_index_for_width(line_width);
}
let location = locate_col(&buffer);
assert_eq2!(location, CaretColLocationInLine::AtEnd);
}
#[test]
fn test_locate_col_in_middle() {
let mut buffer = EditorBuffer::new_empty(None, None);
buffer.init_with(vec!["Hello World"]);
let engine = EditorEngine::new(EditorEngineConfig::default());
{
let buffer_mut = buffer.get_mut(engine.viewport());
buffer_mut.inner.caret_raw.row_index = row(0);
buffer_mut.inner.caret_raw.col_index = col(5);
}
let location = locate_col(&buffer);
assert_eq2!(location, CaretColLocationInLine::InMiddle);
}
#[test]
fn test_locate_col_empty_line() {
let mut buffer = EditorBuffer::new_empty(None, None);
buffer.init_with(vec![""]);
let engine = EditorEngine::new(EditorEngineConfig::default());
{
let buffer_mut = buffer.get_mut(engine.viewport());
buffer_mut.inner.caret_raw.row_index = row(0);
buffer_mut.inner.caret_raw.col_index = col(0);
}
let location = locate_col(&buffer);
assert_eq2!(location, CaretColLocationInLine::AtStart);
}
#[test]
fn test_locate_col_with_unicode() {
let mut buffer = EditorBuffer::new_empty(None, None);
buffer.init_with(vec!["Hello 😄 World"]);
let engine = EditorEngine::new(EditorEngineConfig::default());
{
let buffer_mut = buffer.get_mut(engine.viewport());
buffer_mut.inner.caret_raw.row_index = row(0);
buffer_mut.inner.caret_raw.col_index = col(6); }
let location = locate_col(&buffer);
assert_eq2!(location, CaretColLocationInLine::InMiddle);
let line_width = buffer.get_lines()[0].display_width;
{
let buffer_mut = buffer.get_mut(engine.viewport());
buffer_mut.inner.caret_raw.row_index = row(0);
buffer_mut.inner.caret_raw.col_index = caret_scroll_index::col_index_for_width(line_width);
}
let location = locate_col(&buffer);
assert_eq2!(location, CaretColLocationInLine::AtEnd);
}
#[test]
fn test_locate_row_at_top() {
let mut buffer = EditorBuffer::new_empty(None, None);
buffer.init_with(vec!["Line 1", "Line 2", "Line 3"]);
let engine = EditorEngine::new(EditorEngineConfig::default());
{
let buffer_mut = buffer.get_mut(engine.viewport());
buffer_mut.inner.caret_raw.row_index = row(0);
buffer_mut.inner.caret_raw.col_index = col(0);
}
let location = locate_row(&buffer);
assert_eq2!(location, CaretRowLocationInBuffer::AtTop);
}
#[test]
fn test_locate_row_at_bottom() {
let mut buffer = EditorBuffer::new_empty(None, None);
buffer.init_with(vec!["Line 1", "Line 2", "Line 3"]);
let engine = EditorEngine::new(EditorEngineConfig::default());
{
let buffer_mut = buffer.get_mut(engine.viewport());
buffer_mut.inner.caret_raw.row_index = row(2);
buffer_mut.inner.caret_raw.col_index = col(0);
}
let location = locate_row(&buffer);
assert_eq2!(location, CaretRowLocationInBuffer::AtBottom);
}
#[test]
fn test_locate_row_in_middle() {
let mut buffer = EditorBuffer::new_empty(None, None);
buffer.init_with(vec!["Line 1", "Line 2", "Line 3"]);
let engine = EditorEngine::new(EditorEngineConfig::default());
{
let buffer_mut = buffer.get_mut(engine.viewport());
buffer_mut.inner.caret_raw.row_index = row(1);
buffer_mut.inner.caret_raw.col_index = col(0);
}
let location = locate_row(&buffer);
assert_eq2!(location, CaretRowLocationInBuffer::InMiddle);
}
#[test]
fn test_locate_row_single_line() {
let mut buffer = EditorBuffer::new_empty(None, None);
buffer.init_with(vec!["Only line"]);
let engine = EditorEngine::new(EditorEngineConfig::default());
{
let buffer_mut = buffer.get_mut(engine.viewport());
buffer_mut.inner.caret_raw.row_index = row(0);
buffer_mut.inner.caret_raw.col_index = col(0);
}
let location = locate_row(&buffer);
assert_eq2!(location, CaretRowLocationInBuffer::AtTop);
}
#[test]
fn test_locate_row_empty_buffer() {
let buffer = EditorBuffer::new_empty(None, None);
let location = locate_row(&buffer);
assert_eq2!(location, CaretRowLocationInBuffer::AtTop);
}
#[test]
fn test_col_is_at_start_of_line() {
let mut buffer = EditorBuffer::new_empty(None, None);
buffer.init_with(vec!["Test line"]);
let engine = EditorEngine::new(EditorEngineConfig::default());
{
let buffer_mut = buffer.get_mut(engine.viewport());
buffer_mut.inner.caret_raw.row_index = row(0);
buffer_mut.inner.caret_raw.col_index = col(0);
}
let location = locate_col(&buffer);
assert_eq2!(location, CaretColLocationInLine::AtStart);
{
let buffer_mut = buffer.get_mut(engine.viewport());
buffer_mut.inner.caret_raw.row_index = row(0);
buffer_mut.inner.caret_raw.col_index = col(5);
}
let location = locate_col(&buffer);
assert_eq2!(location, CaretColLocationInLine::InMiddle);
}
#[test]
fn test_col_is_at_end_of_line() {
let mut buffer = EditorBuffer::new_empty(None, None);
buffer.init_with(vec!["Test"]);
let engine = EditorEngine::new(EditorEngineConfig::default());
let line_width = buffer.get_lines()[0].display_width;
{
let buffer_mut = buffer.get_mut(engine.viewport());
buffer_mut.inner.caret_raw.row_index = row(0);
buffer_mut.inner.caret_raw.col_index = caret_scroll_index::col_index_for_width(line_width);
}
let location = locate_col(&buffer);
assert_eq2!(location, CaretColLocationInLine::AtEnd);
{
let buffer_mut = buffer.get_mut(engine.viewport());
buffer_mut.inner.caret_raw.row_index = row(0);
buffer_mut.inner.caret_raw.col_index = col(2);
}
let location = locate_col(&buffer);
assert_eq2!(location, CaretColLocationInLine::InMiddle);
}
#[test]
fn test_row_is_at_top_of_buffer() {
let mut buffer = EditorBuffer::new_empty(None, None);
buffer.init_with(vec!["Line 1", "Line 2", "Line 3"]);
let engine = EditorEngine::new(EditorEngineConfig::default());
{
let buffer_mut = buffer.get_mut(engine.viewport());
buffer_mut.inner.caret_raw.row_index = row(0);
buffer_mut.inner.caret_raw.col_index = col(0);
}
let location = locate_row(&buffer);
assert_eq2!(location, CaretRowLocationInBuffer::AtTop);
{
let buffer_mut = buffer.get_mut(engine.viewport());
buffer_mut.inner.caret_raw.row_index = row(1);
buffer_mut.inner.caret_raw.col_index = col(0);
}
let location = locate_row(&buffer);
assert_eq2!(location, CaretRowLocationInBuffer::InMiddle);
}
#[test]
fn test_row_is_at_bottom_of_buffer() {
let mut buffer = EditorBuffer::new_empty(None, None);
buffer.init_with(vec!["Line 1", "Line 2", "Line 3"]);
let engine = EditorEngine::new(EditorEngineConfig::default());
{
let buffer_mut = buffer.get_mut(engine.viewport());
buffer_mut.inner.caret_raw.row_index = row(2);
buffer_mut.inner.caret_raw.col_index = col(0);
}
let location = locate_row(&buffer);
assert_eq2!(location, CaretRowLocationInBuffer::AtBottom);
{
let buffer_mut = buffer.get_mut(engine.viewport());
buffer_mut.inner.caret_raw.row_index = row(1);
buffer_mut.inner.caret_raw.col_index = col(0);
}
let location = locate_row(&buffer);
assert_eq2!(location, CaretRowLocationInBuffer::InMiddle);
let mut single_line_buffer = EditorBuffer::new_empty(None, None);
single_line_buffer.init_with(vec!["Only line"]);
{
let buffer_mut = single_line_buffer.get_mut(engine.viewport());
buffer_mut.inner.caret_raw.row_index = row(0);
buffer_mut.inner.caret_raw.col_index = col(0);
}
let location = locate_row(&single_line_buffer);
assert_eq2!(location, CaretRowLocationInBuffer::AtTop); }
#[test]
fn test_locate_functions_with_scroll_offset() {
let mut buffer = EditorBuffer::new_empty(None, None);
buffer.init_with(vec!["Very long line with many characters"]);
let engine = EditorEngine::new(EditorEngineConfig::default());
{
let buffer_mut = buffer.get_mut(engine.viewport());
buffer_mut.inner.scr_ofs.row_index = row(0);
buffer_mut.inner.scr_ofs.col_index = col(5);
buffer_mut.inner.caret_raw.row_index = row(0);
buffer_mut.inner.caret_raw.col_index = col(0);
}
let location = locate_col(&buffer);
assert_eq2!(location, CaretColLocationInLine::InMiddle);
}
}