mirror of
https://github.com/storytold/designcraft.git
synced 2026-10-31 07:39:17 +00:00
Table keys and cell commands: footnote text isn't a table cell
The caret in a footnote has a CellAddr too (FOOTNOTE_TABLE). Shift+Tab and Esc there now act as outside a table, and table.nextCell, table.prevCell and table.toggleSelection refuse it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
0014243ac2
commit
2e44b19096
4 files changed
+28
-7
No files matched your search
@@ -438,7 +438,9 @@ fn in_table_or_ids(s: &Session) -> std::result::Result<(), String> {
|
||||
|
||||
fn in_cell(s: &Session) -> std::result::Result<(), String> {
|
||||
has_doc(s)?;
|
||||
if s.active().is_some_and(|d| d.selection.text.is_some_and(|t| t.cell.is_some())) { Ok(()) } else { Err("not in a table cell".into()) }
|
||||
// Footnote text is addressed as a cell too, but isn't in a table.
|
||||
let in_table = |c: CellAddr| c.footnote_id().is_none();
|
||||
if s.active().is_some_and(|d| d.selection.text.is_some_and(|t| t.cell.is_some_and(in_table))) { Ok(()) } else { Err("not in a table cell".into()) }
|
||||
}
|
||||
|
||||
/// The table a command acts on and its target cell range.
|
||||
@@ -1594,7 +1596,7 @@ fn toggle_selection(s: &mut Session) -> Result<Value> {
|
||||
const ID: &str = "table.toggleSelection";
|
||||
let st = s.doc_mut()?;
|
||||
let t = st.selection.text.ok_or_else(|| bad(ID, "no caret"))?;
|
||||
let c = t.cell.ok_or_else(|| bad(ID, "not in a cell"))?;
|
||||
let c = t.cell.filter(|c| c.footnote_id().is_none()).ok_or_else(|| bad(ID, "not in a cell"))?;
|
||||
let cells = match st.selection.cells {
|
||||
Some(cs) => {
|
||||
// A merged cell's text belongs to the cell at its top left.
|
||||
|
||||
@@ -127,6 +127,21 @@ fn table_edit_after_anchor_removal_floors_parent_caret() {
|
||||
}
|
||||
}
|
||||
|
||||
/// Footnote text is addressed as a cell, but the table commands don't take it for one.
|
||||
#[test]
|
||||
fn the_cell_commands_refuse_footnote_text() {
|
||||
let (mut s, sid, _) = session_with_frame();
|
||||
s.execute("story.setText", &json!({"story": sid, "text": "Hello"})).unwrap();
|
||||
s.execute("text.select", &json!({"story": sid, "anchor": 5, "focus": 5})).unwrap();
|
||||
s.execute("footnote.insert", &json!({"text": "Note"})).unwrap();
|
||||
let before = s.doc().unwrap().selection.clone();
|
||||
assert!(before.text.and_then(|t| t.cell).and_then(|c| c.footnote_id()).is_some(), "the caret is in the footnote");
|
||||
for cmd in ["table.toggleSelection", "table.prevCell", "table.nextCell"] {
|
||||
assert!(s.execute(cmd, &json!({})).is_err(), "{cmd}");
|
||||
}
|
||||
assert_eq!(s.doc().unwrap().selection, before);
|
||||
}
|
||||
|
||||
/// Esc in a table toggles between the text and the cell (InDesign's Esc): the caret in a cell
|
||||
/// selects that cell, and selected cells select the first one's text; Shift+Tab goes back a cell.
|
||||
#[test]
|
||||
|
||||
@@ -1469,10 +1469,13 @@ fn type_tool_keys_in_a_table_cell() {
|
||||
assert_eq!(t.key(&cx, ToolKey::Tab, shift), exec("table.prevCell", serde_json::json!({})));
|
||||
assert_eq!(t.key(&cx, ToolKey::Tab, Mods::default()), exec("text.insert", serde_json::json!({"text": "\t"})));
|
||||
assert_eq!(t.key(&cx, ToolKey::Escape, Mods::default()), exec("table.toggleSelection", serde_json::json!({})));
|
||||
let s = Selection::text(designcraft_doc::TextSel::caret(sid, 0));
|
||||
let cx = ctx(&d, &s, &c, &l);
|
||||
assert_eq!(t.key(&cx, ToolKey::Tab, shift), exec("text.insert", serde_json::json!({"text": "\t"})));
|
||||
assert!(matches!(t.key(&cx, ToolKey::Escape, Mods::default()).first(), Some(Action::SwitchTool(_))));
|
||||
// Out of a table, and in footnote text (addressed as a cell too).
|
||||
for cell in [None, Some(designcraft_doc::CellAddr::footnote(1))] {
|
||||
let s = Selection::text(designcraft_doc::TextSel { cell, ..designcraft_doc::TextSel::caret(sid, 0) });
|
||||
let cx = ctx(&d, &s, &c, &l);
|
||||
assert_eq!(t.key(&cx, ToolKey::Tab, shift), exec("text.insert", serde_json::json!({"text": "\t"})), "{cell:?}");
|
||||
assert!(matches!(t.key(&cx, ToolKey::Escape, Mods::default()).first(), Some(Action::SwitchTool(_))), "{cell:?}");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -364,7 +364,8 @@ impl Tool for TypeTool {
|
||||
let steps = if mods.cmd || mods.ctrl { 5.0 } else { 1.0 };
|
||||
vec![Action::Exec("type.kernStep".into(), json!({"steps": sign * steps}))]
|
||||
};
|
||||
let in_cell = cx.selection.text.is_some_and(|t| t.cell.is_some());
|
||||
// A table cell's text, not a footnote's (which is addressed as a cell too).
|
||||
let in_cell = cx.selection.text.is_some_and(|t| t.cell.is_some_and(|c| c.footnote_id().is_none()));
|
||||
match key {
|
||||
ToolKey::Left if mods.alt && !mods.shift => kern(-1.0),
|
||||
ToolKey::Right if mods.alt && !mods.shift => kern(1.0),
|
||||
|
||||
Reference in new issue
Block a user