use text_document::{FlowElementSnapshot, MoveMode, SelectionKind, TextDocument};
fn doc_with_table() -> TextDocument {
let doc = TextDocument::new();
doc.set_markdown("Before\n\n| A | B |\n|---|---|\n| c | d |\n\nAfter")
.unwrap()
.wait()
.unwrap();
doc
}
fn first_table_cell_position(doc: &TextDocument) -> usize {
let snap = doc.snapshot_flow();
for el in &snap.elements {
if let FlowElementSnapshot::Table(ts) = el {
for cell in &ts.cells {
if cell.row == 0
&& cell.column == 0
&& let Some(b) = cell.blocks.first()
{
return b.position;
}
}
}
}
panic!("no table cell (0,0) found");
}
fn after_block_position(doc: &TextDocument) -> usize {
let snap = doc.snapshot_flow();
let mut found_table = false;
for el in &snap.elements {
match el {
FlowElementSnapshot::Table(_) => found_table = true,
FlowElementSnapshot::Block(bs) if found_table => return bs.position,
_ => {}
}
}
panic!("no block found after table");
}
fn before_block_info(doc: &TextDocument) -> (usize, usize) {
let snap = doc.snapshot_flow();
for el in &snap.elements {
if let FlowElementSnapshot::Block(bs) = el {
return (bs.position, bs.length);
}
}
panic!("no block found before table");
}
#[test]
fn trap_snap_forward_position_lands_at_after_block() {
let doc = doc_with_table();
let cell_pos = first_table_cell_position(&doc);
let after_pos = after_block_position(&doc);
let cursor = doc.cursor_at(2);
cursor.set_position(cell_pos, MoveMode::KeepAnchor);
assert_eq!(
cursor.position(),
after_pos,
"position should snap to start of block after table"
);
assert_eq!(cursor.anchor(), 2, "anchor should not move");
}
#[test]
fn trap_snap_forward_selection_kind_is_mixed() {
let doc = doc_with_table();
let cell_pos = first_table_cell_position(&doc);
let cursor = doc.cursor_at(2);
cursor.set_position(cell_pos, MoveMode::KeepAnchor);
match cursor.selection_kind() {
SelectionKind::Mixed {
text_before,
text_after,
..
} => {
assert!(text_before, "should have text before table");
assert!(text_after, "should have text after table");
}
other => panic!("expected Mixed, got {:?}", other),
}
}
#[test]
fn trap_snap_forward_selected_cells_covers_all() {
let doc = doc_with_table();
let cell_pos = first_table_cell_position(&doc);
let cursor = doc.cursor_at(0);
cursor.set_position(cell_pos, MoveMode::KeepAnchor);
let cells = cursor.selected_cells();
assert_eq!(cells.len(), 4, "2x2 table should have all 4 cells selected");
}
#[test]
fn trap_snap_reverse_position_lands_at_before_block_end() {
let doc = doc_with_table();
let cell_pos = first_table_cell_position(&doc);
let (before_pos, before_len) = before_block_info(&doc);
let before_end = before_pos + before_len;
let after_pos = after_block_position(&doc);
let cursor = doc.cursor_at(after_pos + 3);
cursor.set_position(cell_pos, MoveMode::KeepAnchor);
assert_eq!(
cursor.position(),
before_end,
"position should snap to end of block before table"
);
}
#[test]
fn trap_snap_reverse_selection_kind_is_mixed() {
let doc = doc_with_table();
let cell_pos = first_table_cell_position(&doc);
let after_pos = after_block_position(&doc);
let cursor = doc.cursor_at(after_pos + 3);
cursor.set_position(cell_pos, MoveMode::KeepAnchor);
match cursor.selection_kind() {
SelectionKind::Mixed { .. } => {}
other => panic!("expected Mixed, got {:?}", other),
}
}
#[test]
fn no_snap_when_table_is_first() {
let doc = TextDocument::new();
let cursor0 = doc.cursor();
cursor0.insert_table(2, 2).unwrap();
let end = doc.character_count();
let cursor_end = doc.cursor_at(end);
cursor_end.insert_block().unwrap();
cursor_end.insert_text("After").unwrap();
let cell_pos = first_table_cell_position(&doc);
let after_pos = after_block_position(&doc);
let cursor = doc.cursor_at(after_pos + 2);
cursor.set_position(cell_pos, MoveMode::KeepAnchor);
let pos = cursor.position();
assert!(
pos <= cell_pos,
"no snap should happen when table is first: position {} should be <= cell_pos {}",
pos,
cell_pos
);
}
#[test]
fn move_anchor_no_snap() {
let doc = doc_with_table();
let cell_pos = first_table_cell_position(&doc);
let cursor = doc.cursor_at(0);
cursor.set_position(cell_pos, MoveMode::MoveAnchor);
assert_eq!(
cursor.position(),
cell_pos,
"MoveAnchor should place cursor inside table without snapping"
);
assert_eq!(cursor.anchor(), cell_pos);
}
#[test]
fn move_position_keep_anchor_triggers_snap() {
let doc = doc_with_table();
let (before_pos, before_len) = before_block_info(&doc);
let before_end = before_pos + before_len;
let cursor = doc.cursor_at(before_end);
let after_pos = after_block_position(&doc);
cursor.set_position(before_end + 1, MoveMode::KeepAnchor);
assert_eq!(
cursor.position(),
after_pos,
"shift-right from end of block before table should snap to start of block after"
);
}