gap: single selected cell's border drags in its row only

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
Dmitrii Khlapov
2026-10-18 17:43:28 +02:00
co-authored by Claude Sonnet 5.5
parent a7abd346e7
commit da99deb3aa
2 changed files with 91 additions and 1 deletions
+21 -1
View File
@@ -378,8 +378,28 @@ fn select_sentence(s: &mut Session, _: &Value) -> CmdResult {
select_unit(s, Unit::Sentence)
}
/// A triple-click on the only paragraph of a table cell selects the cell (Word takes its end
/// mark too, which shades it), so its borders then move on their own (`table.resizeDrag`).
fn select_paragraph(s: &mut Session, _: &Value) -> CmdResult {
select_unit(s, Unit::Paragraph)
let r = select_unit(s, Unit::Paragraph);
let (a, b) = (s.sel.anchor.clone(), s.sel.focus.clone());
let n = a.path.0.len();
if a.story == b.story
&& a.path.0.len() == b.path.0.len()
&& let Some(tp) = a.path.0.get(..n.saturating_sub(3))
&& !tp.is_empty()
&& a.path.0.get(..n.saturating_sub(1)) == b.path.0.get(..n.saturating_sub(1))
&& let (Some(&row), Some(&cell)) = (a.path.0.get(n.saturating_sub(3)), a.path.0.get(n.saturating_sub(2)))
{
let tp = wordcraft_doc::Path(tp.to_vec());
let (row, cell) = (row as usize, cell as usize);
let only = s.doc.table(a.story, &tp).and_then(|t| t.rows.get(row)?.cells.get(cell)).is_some_and(|c| c.blocks.len() == 1);
let grid = s.doc.table(a.story, &tp).map(|t| super::table::grid_cols(t, row, cell));
if let (true, Some(cols)) = (only, grid) {
return super::table::select_range(s, a.story, &tp, (row, row), cols);
}
}
r
}
/// A click in the selection bar (#856): the whole line at `pos` (default: the caret's), its
+70
View File
@@ -1016,4 +1016,74 @@ mod tests {
assert_eq!(first_table(&s).grid.len(), 3, "no new grid line");
assert!((cell_rect(&mut s, 0, 2).x - (c.x + 20.0)).abs() < 1.0, "the first row follows");
}
/// Selects the cell at (row, cell) one of the ways Word does: Select Cell, the left-edge
/// arrow, or a triple-click on its text.
fn select_one_cell(s: &mut Session, how: &str, r: usize, c: usize) {
let b = cell_rect(s, r, c);
let y = b.y + b.h / 2.0;
match how {
"arrow" => {
s.run("table.selectAt", &json!({"page": 0, "x": b.x + 4.5, "y": y})).unwrap();
}
"triple" => {
s.run("caret.set", &json!({"page": 0, "x": b.x + b.w / 2.0, "y": y})).unwrap();
s.run("select.paragraph", &json!({})).unwrap();
}
_ => {
s.run("caret.set", &json!({"page": 0, "x": b.x + b.w / 2.0, "y": y})).unwrap();
s.run("table.selectCell", &json!({})).unwrap();
}
}
}
/// Each way of selecting one cell makes its right and its left border move in its row
/// only; the neighbour on that side gives up or gains the room and the row keeps its width.
#[test]
fn a_single_selected_cells_borders_move_only_in_its_row() {
for how in ["cell", "arrow", "triple"] {
for left in [false, true] {
let mut s = table_session(3, 3);
let (a, b, c) = (cell_rect(&mut s, 1, 0), cell_rect(&mut s, 1, 1), cell_rect(&mut s, 1, 2));
let y = b.y + b.h / 2.0;
select_one_cell(&mut s, how, 1, 1);
let start = first_table(&s);
let x = if left { b.x } else { b.right() };
s.run("table.resizeDrag", &json!({"page": 0, "x": x, "y": y, "toX": x + 30.0, "toY": y})).unwrap();
let (a1, b1, c1) = (cell_rect(&mut s, 1, 0), cell_rect(&mut s, 1, 1), cell_rect(&mut s, 1, 2));
if left {
assert!((b1.w - (b.w - 30.0)).abs() < 1.0 && (a1.w - (a.w + 30.0)).abs() < 1.0, "{how} left: {a1:?} {b1:?}");
assert!((c1.w - c.w).abs() < 0.5, "{how} left");
} else {
assert!((b1.w - (b.w + 30.0)).abs() < 1.0 && (c1.w - (c.w - 30.0)).abs() < 1.0, "{how} right: {b1:?} {c1:?}");
assert!((a1.w - a.w).abs() < 0.5, "{how} right");
}
assert!((c1.right() - c.right()).abs() < 0.5, "{how}: the row keeps its width");
for r in [0, 2] {
assert!(
(cell_rect(&mut s, r, 1).x - b.x).abs() < 0.5 && (cell_rect(&mut s, r, 1).right() - b.right()).abs() < 0.5,
"{how}: row {r} unchanged"
);
}
s.run("edit.undo", &json!({})).unwrap();
assert_eq!(first_table(&s), start, "{how}: one undo step");
}
}
}
/// A caret, a part of a cell's text, or another cell's border with a cell selected: the
/// whole column moves.
#[test]
fn without_that_cell_selected_the_whole_column_moves() {
let mut s = table_session(3, 3);
let b = cell_rect(&mut s, 1, 1);
let y = b.y + b.h / 2.0;
s.run("caret.set", &json!({"page": 0, "x": b.x + b.w / 2.0, "y": y})).unwrap();
s.run("table.resizeDrag", &json!({"page": 0, "x": b.right(), "y": y, "toX": b.right() + 30.0, "toY": y})).unwrap();
assert!((cell_rect(&mut s, 0, 1).w - (b.w + 30.0)).abs() < 1.0, "caret only");
s.run("edit.undo", &json!({})).unwrap();
select_one_cell(&mut s, "arrow", 2, 2);
s.run("table.resizeDrag", &json!({"page": 0, "x": b.right(), "y": y, "toX": b.right() + 30.0, "toY": y})).unwrap();
assert!((cell_rect(&mut s, 0, 1).w - (b.w + 30.0)).abs() < 1.0, "another cell selected");
}
}