mirror of
https://github.com/storytold/deckcraft.git
synced 2026-10-31 15:48:18 +00:00
[CC3] table.cellAlign takes a horizontal align
align: left|center|right|justify sets every paragraph of the target cells; anchor stays the vertical alignment and is optional when align is given. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
55e5ee56b4
commit
f58ec39968
2 files changed
+56
-8
No files matched your search
@@ -108,7 +108,7 @@ pub fn specs() -> Vec<CommandSpec> {
|
||||
"Align Cell Text",
|
||||
["Table Layout", "Alignment"],
|
||||
None,
|
||||
"{anchor: top|middle|bottom, cells?, id?}",
|
||||
"{anchor?: top|middle|bottom (vertical; top when neither anchor nor align is given), align?: left|center|right|justify (horizontal, applied to every paragraph of the cells), cells?, id?}",
|
||||
has_selection,
|
||||
cell_align
|
||||
),
|
||||
@@ -535,18 +535,43 @@ fn cell_margins(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
}
|
||||
|
||||
fn cell_align(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
use deckcraft_model::text::Anchor;
|
||||
let a = match str_param(p, "anchor").unwrap_or("top") {
|
||||
"middle" | "center" | "ctr" => Anchor::Middle,
|
||||
"bottom" | "b" => Anchor::Bottom,
|
||||
"top" | "t" => Anchor::Top,
|
||||
o => return Err(bad("table.cellAlign", format!("unknown anchor {o:?}; one of top, middle, bottom"))),
|
||||
use deckcraft_model::text::{Align, Anchor};
|
||||
// A value that is not a string is refused, not taken as absent.
|
||||
for k in ["align", "anchor"] {
|
||||
if p.get(k).is_some_and(|v| !v.is_null() && !v.is_string()) {
|
||||
return Err(bad("table.cellAlign", format!("`{k}` is a name such as {}", if k == "align" { "left or center" } else { "top or middle" })));
|
||||
}
|
||||
}
|
||||
// Without `align`, the vertical anchor is the whole command (top when not given).
|
||||
let align = match str_param(p, "align") {
|
||||
None => None,
|
||||
Some("left" | "l") => Some(Align::Left),
|
||||
Some("center" | "centre" | "ctr") => Some(Align::Center),
|
||||
Some("right" | "r") => Some(Align::Right),
|
||||
Some("justify" | "just") => Some(Align::Justify),
|
||||
Some(o) => return Err(bad("table.cellAlign", format!("unknown align {o:?}; one of left, center, right, justify"))),
|
||||
};
|
||||
let anchor = match (str_param(p, "anchor"), align) {
|
||||
(None, Some(_)) => None,
|
||||
(a, _) => Some(match a.unwrap_or("top") {
|
||||
"middle" | "center" | "ctr" => Anchor::Middle,
|
||||
"bottom" | "b" => Anchor::Bottom,
|
||||
"top" | "t" => Anchor::Top,
|
||||
o => return Err(bad("table.cellAlign", format!("unknown anchor {o:?}; one of top, middle, bottom"))),
|
||||
}),
|
||||
};
|
||||
let targets = target_cells(s, p)?;
|
||||
with_table(s, p, "table.cellAlign", move |t| {
|
||||
for (r, c) in targets(t) {
|
||||
if let Some(cell) = t.cell_mut(r, c) {
|
||||
cell.anchor = Some(a);
|
||||
if anchor.is_some() {
|
||||
cell.anchor = anchor;
|
||||
}
|
||||
if let Some(a) = align {
|
||||
for para in &mut cell.text.paragraphs {
|
||||
para.props.align = Some(a);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
|
||||
@@ -5646,3 +5646,26 @@ fn invalid_ids_array_never_falls_back_to_the_selection() {
|
||||
assert!(s.doc().unwrap().shape(deckcraft_model::ShapeId(a as u32)).is_some(), "shape deleted for {ids}");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn table_cell_align_sets_the_horizontal_alignment() {
|
||||
use deckcraft_model::text::{Align, Anchor};
|
||||
let mut s = session();
|
||||
let id = table_at(&mut s, &[100.0, 100.0], json!([["a", "b"], ["c", "d"]]));
|
||||
s.execute("table.cellAlign", &json!({"id": id.0, "align": "center", "cells": [[0, 0], [1, 0]]})).unwrap();
|
||||
s.execute("table.cellAlign", &json!({"id": id.0, "align": "right", "anchor": "bottom", "cells": [[0, 1]]})).unwrap();
|
||||
let t = table_of(&s, id);
|
||||
let al = |r, c| t.cell(r, c).unwrap().text.paragraphs.iter().map(|p| p.props.align).collect::<Vec<_>>();
|
||||
assert_eq!(al(0, 0), vec![Some(Align::Center)]);
|
||||
assert_eq!(al(1, 0), vec![Some(Align::Center)]);
|
||||
assert_eq!(al(0, 1), vec![Some(Align::Right)]);
|
||||
assert_eq!(al(1, 1), vec![None], "other cells are untouched");
|
||||
assert_eq!(t.cell(0, 1).unwrap().anchor, Some(Anchor::Bottom));
|
||||
assert_eq!(t.cell(0, 0).unwrap().anchor, None, "align alone leaves the vertical anchor");
|
||||
assert!(s.execute("table.cellAlign", &json!({"id": id.0, "align": "diagonal"})).is_err());
|
||||
// A value that is not a name is refused, not read as absent (which would set the anchor to top).
|
||||
let rev = s.doc().unwrap().revision;
|
||||
assert!(s.execute("table.cellAlign", &json!({"id": id.0, "align": 1})).is_err());
|
||||
assert!(s.execute("table.cellAlign", &json!({"id": id.0, "align": "left", "anchor": true})).is_err());
|
||||
assert_eq!(s.doc().unwrap().revision, rev);
|
||||
}
|
||||
Reference in new issue
Block a user