mirror of
https://github.com/storytold/designcraft.git
synced 2026-11-11 16:30:16 -06: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:
co-authored by
Claude Opus 5.5
parent
0014243ac2
commit
2e44b19096
@@ -438,7 +438,9 @@ fn in_table_or_ids(s: &Session) -> std::result::Result<(), String> {
|
|||||||
|
|
||||||
fn in_cell(s: &Session) -> std::result::Result<(), String> {
|
fn in_cell(s: &Session) -> std::result::Result<(), String> {
|
||||||
has_doc(s)?;
|
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.
|
/// 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";
|
const ID: &str = "table.toggleSelection";
|
||||||
let st = s.doc_mut()?;
|
let st = s.doc_mut()?;
|
||||||
let t = st.selection.text.ok_or_else(|| bad(ID, "no caret"))?;
|
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 {
|
let cells = match st.selection.cells {
|
||||||
Some(cs) => {
|
Some(cs) => {
|
||||||
// A merged cell's text belongs to the cell at its top left.
|
// 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
|
/// 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.
|
/// selects that cell, and selected cells select the first one's text; Shift+Tab goes back a cell.
|
||||||
#[test]
|
#[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, 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::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!({})));
|
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));
|
// Out of a table, and in footnote text (addressed as a cell too).
|
||||||
let cx = ctx(&d, &s, &c, &l);
|
for cell in [None, Some(designcraft_doc::CellAddr::footnote(1))] {
|
||||||
assert_eq!(t.key(&cx, ToolKey::Tab, shift), exec("text.insert", serde_json::json!({"text": "\t"})));
|
let s = Selection::text(designcraft_doc::TextSel { cell, ..designcraft_doc::TextSel::caret(sid, 0) });
|
||||||
assert!(matches!(t.key(&cx, ToolKey::Escape, Mods::default()).first(), Some(Action::SwitchTool(_))));
|
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]
|
#[test]
|
||||||
|
|||||||
@@ -364,7 +364,8 @@ impl Tool for TypeTool {
|
|||||||
let steps = if mods.cmd || mods.ctrl { 5.0 } else { 1.0 };
|
let steps = if mods.cmd || mods.ctrl { 5.0 } else { 1.0 };
|
||||||
vec![Action::Exec("type.kernStep".into(), json!({"steps": sign * steps}))]
|
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 {
|
match key {
|
||||||
ToolKey::Left if mods.alt && !mods.shift => kern(-1.0),
|
ToolKey::Left if mods.alt && !mods.shift => kern(-1.0),
|
||||||
ToolKey::Right 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