A new source's Tag follows Word's format; editing keeps the Tag (#2094) (#2571)

Co-authored-by: Dmitrii Khlapov <19991457+dkhlapov@users.noreply.github.com>
Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
This commit is contained in:
Dmitrii Khlapov
2026-10-18 03:20:56 -04:00
committed by GitHub
co-authored by Dmitrii Khlapov Claude Sonnet 5.5 Brandon Thomas
parent 16622f0853
commit 8c1a39ba95
3 changed files with 68 additions and 10 deletions
+2 -1
View File
@@ -2,7 +2,7 @@
**Stage: alpha** · next: beta, ~15 points (60% → 75% ready for real work) and ~150–230 h away
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-17 · **Change:** trivial (Web Layout fills the window width, #1876; previously trivial: Language dialog keeps inherited proofing language and no-proof choices (#2717)); previously trivial (table style editor formats every part, #714); previously trivial: VML freeforms read and kept on save; previously trivial: progress log: consistent preferred cell widths; previously trivial: multi-paragraph field instructions no longer add blank lines; previously trivial: page-break-only list paragraphs hide their labels; previously trivial: progress log: grouped `flowChartOr` shapes draw their circle and crossing spokes; previously trivial: progress log: copies keep their formatting in other programs, #1523; previously trivial: progress log: privacy options on save, #1062; previously trivial: progress log: equation pictures in theme colours on Windows, #1002; previously trivial: symbol fonts, #776; previously trivial: the save prompt answers from the keyboard, #861; previously trivial: table column and row markers on the rulers, #700; previously trivial: table borders and the resize handle drag on the page, #217; previously trivial: formatting revisions landed, #41; previously trivial: Draw tab ink, #307, and Draw Table and Eraser, #303, landed: catalog 402/434; previously minor: readiness table with hours per audience; full number back to the additive weighted sum, 60%; mainstream and essentials numbers added; alpha gate checked; previously major: full re-measure against Word for Mac 16.113.4; restructured to the craftrules progress-docs standard) · **Target:** Microsoft Word (Microsoft 365) for Mac 16.113.4
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-17 · **Change:** trivial (a new source's Tag is made like Word's, three letters of the author and two digits of the year with a number added when taken, and an edit keeps the Tag, #2094; previously trivial: Web Layout fills the window width, #1876; previously trivial: Language dialog keeps inherited proofing language and no-proof choices (#2717)); previously trivial (table style editor formats every part, #714); previously trivial: VML freeforms read and kept on save; previously trivial: progress log: consistent preferred cell widths; previously trivial: multi-paragraph field instructions no longer add blank lines; previously trivial: page-break-only list paragraphs hide their labels; previously trivial: progress log: grouped `flowChartOr` shapes draw their circle and crossing spokes; previously trivial: progress log: copies keep their formatting in other programs, #1523; previously trivial: progress log: privacy options on save, #1062; previously trivial: progress log: equation pictures in theme colours on Windows, #1002; previously trivial: symbol fonts, #776; previously trivial: the save prompt answers from the keyboard, #861; previously trivial: table column and row markers on the rulers, #700; previously trivial: table borders and the resize handle drag on the page, #217; previously trivial: formatting revisions landed, #41; previously trivial: Draw tab ink, #307, and Draw Table and Eraser, #303, landed: catalog 402/434; previously minor: readiness table with hours per audience; full number back to the additive weighted sum, 60%; mainstream and essentials numbers added; alpha gate checked; previously major: full re-measure against Word for Mac 16.113.4; restructured to the craftrules progress-docs standard) · **Target:** Microsoft Word (Microsoft 365) for Mac 16.113.4
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-14 · **Change:** trivial (progress log: print-area strings translated in every catalog; previously trivial: progress log: ODT sections, #1379; previously trivial: progress log: table deletes, Change Case and Unlink Fields respect Track Changes and locked content controls, #1329; previously trivial: progress log: rounded rectangle corners, #1476; previously trivial: progress log: Save As type list, #1399; previously trivial: progress log: privacy options on save, #1062; previously trivial: progress log: equation pictures in theme colours on Windows, #1002; previously trivial: symbol fonts, #776; previously trivial: the save prompt answers from the keyboard, #861; previously trivial: table column and row markers on the rulers, #700; previously trivial: table borders and the resize handle drag on the page, #217; previously trivial: formatting revisions landed, #41; previously trivial: Draw tab ink, #307, and Draw Table and Eraser, #303, landed: catalog 402/434; previously minor: readiness table with hours per audience; full number back to the additive weighted sum, 60%; mainstream and essentials numbers added; alpha gate checked; previously major: full re-measure against Word for Mac 16.113.4; restructured to the craftrules progress-docs standard) · **Target:** Microsoft Word (Microsoft 365) for Mac 16.113.4
> **Printing update:** 2026-10-12 · direct desktop printing through craft-print; details below.
@@ -136,6 +136,7 @@ Ranked, to beta (detail and remaining milestones in [docs/roadmap.md](docs/roadm
| Date | What landed |
| 2026-10-16 | Web Layout text fills the window width and re-wraps once a resize settles, or at once on a zoom, instead of a fixed 800 pt column; Draft and Outline keep their 800 pt column (#1876). |
| 2026-10-16 | Create Source: the automatic Tag is three letters of the first author and the last two digits of the year (`Smi20`), with 1, 2… added when taken, as Word for Mac 16.113.4 does (user-checked). Editing Author or Year keeps the Tag, as in Word, and the citations in the text show the new author and year (#2094; the reporter expected the Tag to follow). |
| 2026-10-14 | DOCX row table border exceptions render and survive saving. Explicit cell borders win; a row exception does not change other rows. |
| 2026-10-14 | Tab stops edited on the ruler: the corner selector picks Left/Center/Right/Decimal/Bar, a click sets a stop (Alt skips the snap), dragging moves it with a guide line and position tooltip, dragging off the ruler clears it; markers draw per kind and mirror for RTL; one `para.tabs` call and one undo step per gesture |
| 2026-10-12 | Fields keep `w:dirty` through DOCX saves (#877): a begin marker flagged by a generator that couldn't compute a result (pandoc-style TOC placeholders) keeps the flag on open/save — as a buffered field or a range field — so Word still refreshes it on open; computing a result (Update Field, Update Table) clears it, like Word's F9 |
+64 -8
View File
@@ -519,18 +519,28 @@ pub fn entry(src: &Source, style_name: &str, n: usize) -> String {
render(if src.journal.is_empty() { st.book } else { st.article }, &field)
}
/// The tag a new source gets, as Word makes it: the first three letters of the first author's
/// name and the last two digits of the year (`Smi20`), with `1`, `2`… added while it is taken.
fn auto_tag(doc: &Document, src: &Source) -> String {
let name: String =
authors(&src.author).first().map(|x| x.0.clone()).unwrap_or_default().chars().filter(|c| c.is_alphanumeric()).take(3).collect();
let name = if name.is_empty() { "Src".to_string() } else { name };
let digits: Vec<char> = src.year.chars().filter(char::is_ascii_digit).collect();
let year: String = digits.get(digits.len().saturating_sub(2)..).unwrap_or_default().iter().collect();
let base = format!("{name}{year}");
let taken = |t: &str| doc.sources.iter().any(|x| x.tag == t);
if !taken(&base) {
return base;
}
(1u32..).map(|n| format!("{base}{n}")).find(|t| !taken(t)).unwrap_or(base)
}
fn sources(s: &mut Session, v: &Value) -> CmdResult {
if let Some(a) = v.get("add") {
let mut src: Source = serde_json::from_value(a.clone()).map_err(|e| CmdError::Params(e.to_string()))?;
// A new source's tag is made from its author and year; an edit keeps the tag it has.
if src.tag.is_empty() {
let base: String = authors(&src.author)
.first()
.map(|x| x.0.clone())
.unwrap_or_else(|| "Source".into())
.chars()
.filter(|c| c.is_alphanumeric())
.collect();
src.tag = format!("{base}{}", src.year);
src.tag = auto_tag(&s.doc, &src);
}
// Edit Source keeps the source's place in the list and refreshes its citations.
match s.doc.sources.iter().position(|x| x.tag == src.tag) {
@@ -1185,6 +1195,52 @@ mod tests {
assert_eq!(crate::cmd::references::bookmark_text(&s.doc, &name).as_deref(), Some("Kilns"));
}
fn src_of(author: &str, year: &str) -> Value {
json!({"author": author, "year": year, "title": "T"})
}
#[test]
fn editing_author_and_year_keeps_the_tag_and_updates_the_citation_text() {
let mut s = Session::new(wordcraft_doc::Document::new());
s.run("references.sources", &json!({"add": src_of("Smith, Ann", "2020")})).unwrap();
assert_eq!(s.doc.sources[0].tag, "Smi20");
s.run("references.citation", &json!({"tag": "Smi20"})).unwrap();
// What the Edit Source dialog sends: the unchanged tag with the new author and year.
let mut edited = src_of("Jones, Bo", "2021");
edited["tag"] = json!("Smi20");
s.run("references.sources", &json!({"add": edited})).unwrap();
assert_eq!(s.doc.sources.len(), 1);
assert_eq!(s.doc.sources[0].tag, "Smi20");
let f = fields(&s);
assert_eq!(f[0].0, "CITATION Smi20");
assert!(f[0].1.contains("Jones") && f[0].1.contains("2021"), "{:?}", f[0].1);
}
#[test]
fn a_new_sources_tag_is_three_letters_and_two_year_digits() {
let mut s = Session::new(wordcraft_doc::Document::new());
for (a, y) in [
("Kim", "2000"),
("Kim", "2000"),
("Kim", "2000"),
("Lee", "2019"),
("Li", "1999"),
("", ""),
("", ""),
("Ünal, Ece", "7"),
("O'Neil", "20x5"),
] {
s.run("references.sources", &json!({"add": src_of(a, y)})).unwrap();
}
let tags: Vec<_> = s.doc.sources.iter().map(|x| x.tag.as_str()).collect();
assert_eq!(tags, ["Kim00", "Kim001", "Kim002", "Lee19", "Li99", "Src", "Src1", "Üna7", "ONe05"]);
let mut s = Session::new(wordcraft_doc::Document::new());
let mut a = src_of("Lee", "2019");
a["tag"] = json!("MyTag");
s.run("references.sources", &json!({"add": a})).unwrap();
assert_eq!(s.doc.sources[0].tag, "MyTag");
}
fn two_sources(s: &mut Session, a_title: &str) {
let a = json!({"tag": "A", "author": "Rivera, Alex; Chen, Mei", "title": a_title, "year": "2021", "publisher": "Harbor Books", "city": "Portland"});
let b = json!({"tag": "B", "author": "Okafor, Ngozi", "title": "Kilns and Clay", "year": "2019", "journal": "Studio Quarterly", "volume": "4", "pages": "10-20"});
+2 -1
View File
@@ -1,6 +1,6 @@
# UI parity with Microsoft Word
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-17 · **Change:** trivial (Web Layout text fills the window width, #1876; previously trivial: Language dialog keeps inherited proofing language and no-proof choices (#2717)); previously trivial (Modify Table Style formats every table style part, #714); previously trivial: a click on the ribbon chrome hands the keyboard to the page in the same frame, #1093 follow-up; previously trivial: Page Setup vertical alignment, #1320; previously trivial: the app opens on the Home tab every launch, as in Word; previously trivial: no document behind the Start screen, #1129; previously trivial: equation pictures share a few textures, #1002; previously trivial: selection bar in the left margin, #856; previously trivial: table column and row markers on the rulers, #700; previously trivial: table borders and the resize handle drag on the page, #217; previously major: first version; ribbon, dialogs, shortcuts and on-canvas interaction measured from `crates/ui-egui` and the command registry) · **Target:** Microsoft Word (Microsoft 365) for Mac 16.113.4
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-17 · **Change:** trivial (a new source's Tag is made like Word's, three letters of the author and two digits of the year with a number added when taken, and an edit keeps the Tag, #2094; previously trivial: Web Layout text fills the window width, #1876; previously trivial: Language dialog keeps inherited proofing language and no-proof choices (#2717)); previously trivial (Modify Table Style formats every table style part, #714); previously trivial: a click on the ribbon chrome hands the keyboard to the page in the same frame, #1093 follow-up; previously trivial: Page Setup vertical alignment, #1320; previously trivial: the app opens on the Home tab every launch, as in Word; previously trivial: no document behind the Start screen, #1129; previously trivial: equation pictures share a few textures, #1002; previously trivial: selection bar in the left margin, #856; previously trivial: table column and row markers on the rulers, #700; previously trivial: table borders and the resize handle drag on the page, #217; previously major: first version; ribbon, dialogs, shortcuts and on-canvas interaction measured from `crates/ui-egui` and the command registry) · **Target:** Microsoft Word (Microsoft 365) for Mac 16.113.4
How WordCraft looks and feels next to Word: ribbon, dialogs, panes, keyboard, mouse and touch.
Typing behaviour has its own checklist ([`typing-parity.md`](typing-parity.md)). All assets are our
@@ -64,6 +64,7 @@ The Language dialog reads effective character formatting, including document def
|---|---|---|
| 2026-10-16 | trivial | Web Layout text fills the window width and re-wraps once a resize settles or at once on a zoom, instead of a fixed 800 pt column; Draft and Outline keep their 800 pt column (#1876) |
| 2026-10-17 | trivial | Language dialog keeps inherited proofing language and no-proof choices (#2717); readiness estimates unchanged |
| 2026-10-16 | trivial | Create Source: automatic Tag like Word's (`Smi20`, `Kim001`); Edit Source keeps the Tag and citations show the new Author and Year (#2094; Word for Mac 16.113.4, user-checked) |
| 2026-10-13 | trivial | New/Modify Table Style: No Border on a part that inherits its lines hides them; emptying the font box makes the part's font inherited again (#1288) |
| 2026-10-14 | trivial | Tab stops edited on the ruler: corner kind selector, click to set, drag to move or off to clear, per-kind markers mirrored for RTL; each gesture one `para.tabs` call and one undo step; Rulers 85% → 90% |
| 2026-10-12 | trivial | Tables on the page: one selected cell (Select Cell, or a click along its left edge) is a cell selection when its border is dragged: the border moves in its row only (#962) |