Columns on selected text go in their own section (#2024) (#2071)

With text selected, Layout > Columns used to change the whole section. As in
Word (observed black-box), a continuous section break now goes where the
selection starts and one where it ends, splitting a paragraph there, unless that
end already meets a section boundary (the document's start or end, or an
existing break); the columns go on the section between, in one undo step.
`layout.columns` gains `apply: "selection"`, its default when text is selected
in the main text. More Columns... offers "Selected text" and picks it then.

Co-authored-by: Brandon Thomas <echelon@gmail.com>
This commit is contained in:
Alik
2026-10-18 03:59:01 -04:00
committed by GitHub
co-authored by Brandon Thomas
parent 7f94643154
commit d8b11c69d3
26 changed files with 190 additions and 7 deletions
+3 -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-18 · **Change:** trivial (progress log: legacy outline, shadow, emboss and imprint text effects drawn, #2534; previously trivial: progress log: Indonesian proofing, #498; previously trivial: progress log: DOCX glossary documents (building blocks); previously trivial: progress log: Read Mode keeps the keyboard and shows whole, unobscured columns, #1772); previously trivial: progress log: font list entries of tall-ascent fonts no longer cut off, #2570); previously trivial: progress log: Split Cells and Convert Text to Table dialogs follow the Word check, #2592; previously 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: progress log: Different First Page headers reachable from page 1, #2826; 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-18 · **Change:** trivial (progress log: Columns on selected text, #2024; previously trivial: progress log: legacy outline, shadow, emboss and imprint text effects drawn, #2534; previously trivial: progress log: Indonesian proofing, #498; previously trivial: progress log: DOCX glossary documents (building blocks); previously trivial: progress log: Read Mode keeps the keyboard and shows whole, unobscured columns, #1772); previously trivial: progress log: font list entries of tall-ascent fonts no longer cut off, #2570); previously trivial: progress log: Split Cells and Convert Text to Table dialogs follow the Word check, #2592; previously 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: progress log: Different First Page headers reachable from page 1, #2826; 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 (progress log: pasted blockquotes are indented paragraphs, #1270; previously trivial: progress log: print-area strings translated in every catalog; previously trivial: progress log: comments readable in the dark theme, #2045; 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.
@@ -149,6 +149,7 @@ Ranked, to beta (detail and remaining milestones in [docs/roadmap.md](docs/roadm
| 2026-10-16 | Indonesian proofing (#498): id-ID spelling reads the installed Hunspell `id_ID` dictionary (`hunspell-id` on Debian/Ubuntu, LibreOffice's `dict-id`, or the Dictionaries folder), suggestions use its MAP/REP/TRY/KEY tables, generic repeated-word (offering `anak-anak`) and spacing checks explain in Indonesian; Review › Language, Set Proofing Language and File › Options › Proofing offer Indonesian. No dictionary data bundled; hyphenation keeps the English fallback; parity estimates unchanged |
| 2026-10-17 | A table inserted in a right-to-left paragraph is a right-to-left table, like Word, so Tab moves right to left through its cells (#2634) |
| 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-15 | Layout › Columns with text selected puts only that text in columns, as in Word (#2024): a continuous section break goes where the selection starts and one where it ends (splitting a paragraph there; none at the document's start or end, or where a section already begins or ends), and the columns go on the section between, one undo step; More Columns… offers "Selected text" and picks it. Before, the whole section took the columns |
| 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 | Table formulas: cell references and ranges (`=B2+B3`, `=SUM(B2:C3)`), arithmetic and comparisons, IF, AND, OR, NOT, TRUE, FALSE, DEFINED and the `\#` number format; ABOVE and LEFT sum the run of numbers next to the cell as Word does; an unknown function or a syntax error is an error instead of a sum; Update Field (F9) recalculates formula fields |
| 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 |
@@ -432,6 +433,7 @@ Ranked, to beta (detail and remaining milestones in [docs/roadmap.md](docs/roadm
| 2026-10-16 | trivial | Progress log: comments readable in the dark theme (#2045) |
| 2026-10-16 | trivial | Progress log: Indonesian proofing (#498) |
| 2026-10-16 | trivial | Progress log: legacy outline, shadow, emboss and imprint text effects drawn (#2534) |
| 2026-10-15 | trivial | Progress log: Columns on selected text (#2024) |
| 2026-10-14 | trivial | Progress log: row table border exceptions |
| 2026-10-12 | minor | Czech proofing review: short-word splits rank after deletion, NOSUGGEST excludes suggestions while accepting typed forms, affix comments apply only to headers, ratios keep spaces and repeated-word messages use Czech quotes; synthetic engine end-to-end and latency checks |
| 2026-10-12 | minor | Czech spelling from the installed Hunspell dictionary, runtime-table suggestions and generic checks; Czech interface writes cs-CZ documents; no Czech hyphenation patterns bundled; estimates unchanged |
+134 -3
View File
@@ -27,7 +27,7 @@ pub fn specs() -> Vec<CommandSpec> {
CommandSpec::new("layout.size", "Size", "Layout › Page Setup", size).params(r#"{"name"?: "Letter|Legal|A4|…", "width"?: pt, "height"?: pt} (each side clamped to 7.2–1584 pt, 0.1–22 in; the section keeps its orientation)"#),
CommandSpec::new("layout.columns", "Columns", "Layout › Page Setup", columns)
.params(
r#"{"count": 1-12, "space"?: pt, "separator"?: bool, "preset"?: "left|right", "widths"?: [[width pt, space after pt], …] (unequal columns; sets the count), "apply"?: "section|document|forward"}"#,
r#"{"count": 1-12, "space"?: pt, "separator"?: bool, "preset"?: "left|right", "widths"?: [[width pt, space after pt], …] (unequal columns; sets the count), "apply"?: "section|document|forward|selection"} (default: selection when text is selected in the main text — section breaks around it — else section)"#,
),
CommandSpec::new("layout.break", "Breaks", "Layout › Page Setup", breaks)
.params(r#"{"kind": "page|column|textWrapping|nextPage|continuous|evenPage|oddPage"}"#),
@@ -569,7 +569,9 @@ fn columns(s: &mut Session, v: &Value) -> CmdResult {
// Equal columns keep one spacing; unequal ones remember the first gap for a later switch back.
let space = widths.first().map(|w| w.1).unwrap_or(space);
let cols = Columns { count: count as u32, space, separator: sep, widths };
match p::str(v, "apply").unwrap_or("section") {
// With text selected the gallery works on that text, as in Word (#2024).
let default = if selection_sectionable(s) { "selection" } else { "section" };
match p::str(v, "apply").unwrap_or(default) {
"section" => with_sect(s, |x| x.columns = cols.clone()),
"document" => {
let ends: Vec<usize> = s.doc.sections().iter().map(|(e, _)| *e).collect();
@@ -585,10 +587,61 @@ fn columns(s: &mut Session, v: &Value) -> CmdResult {
breaks(s, &json!({"kind": "continuous"}))?;
with_sect(s, |x| x.columns = cols.clone())
}
x => Err(CmdError::Params(format!("unknown apply `{x}` (section, document or forward)"))),
"selection" => {
selection_to_sections(s)?;
with_sect(s, |x| x.columns = cols.clone())
}
x => Err(CmdError::Params(format!("unknown apply `{x}` (section, document, forward or selection)"))),
}
}
/// Whether the selection can become sections of its own: text selected in the main text, outside
/// tables.
pub fn selection_sectionable(s: &Session) -> bool {
let (a, b) = s.sel.ordered();
!s.sel.is_collapsed() && [a, b].iter().all(|p| p.story == StoryRef::Body && p.path.depth() == 0)
}
/// Columns for the selected text (#2024), as Word does it: a continuous section break where the
/// selection starts and one where it ends, splitting paragraphs there, unless that end already
/// meets a section boundary (the document's start or end, or a section break). The selection keeps
/// its text, which is then the section(s) between.
fn selection_to_sections(s: &mut Session) -> Result<(), CmdError> {
if !selection_sectionable(s) {
return Err(CmdError::Params("selected text in the main text, outside tables, is needed".into()));
}
let old = s.sel.clone();
let (a, mut b) = old.ordered();
let block = |p: &Pos| p.path.0.first().copied().unwrap_or(0) as usize;
let len = |s: &Session, p: &Pos| s.doc.para_at(p).map(|q| q.len()).unwrap_or(0);
let ends: Vec<usize> = s.doc.sections().iter().map(|(e, _)| *e).collect();
let after_break = |i: usize| i.checked_sub(1).is_some_and(|j| ends.contains(&j));
// A selection that took a section break with it ends before that break.
if b.off == 0 && block(&b) > block(&a) && after_break(block(&b)) {
let prev = Pos { path: wordcraft_doc::Path::top(block(&b) - 1), off: 0, ..b.clone() };
b = Pos { off: len(s, &prev), ..prev };
}
let last_block = s.doc.body.len().saturating_sub(1);
let end_break = !(b.off == len(s, &b) && (ends.contains(&block(&b)) || block(&b) == last_block));
let start_break = !(a.off == 0 && (block(&a) == 0 || after_break(block(&a))));
// The end first: the start's position doesn't move.
if end_break {
s.sel = Selection::caret(b.clone());
breaks(s, &json!({"kind": "continuous"}))?;
}
let (first, last) = if start_break {
s.sel = Selection::caret(a.clone());
breaks(s, &json!({"kind": "continuous"}))?;
let first = s.sel.focus.clone();
let last = shifted_by_split(&b, &a, &first);
(first, last)
} else {
(a, b)
};
s.sel = if old.anchor <= old.focus { Selection { anchor: first, focus: last } } else { Selection { anchor: last, focus: first } };
Ok(())
}
/// `[[width, space after], …]` in points: 1–12 columns, each at least 0.25", that fit the text
/// width (`tw`).
fn column_widths(v: &Value, tw: f32) -> Result<Vec<(f32, f32)>, CmdError> {
@@ -956,6 +1009,84 @@ mod tests {
assert!(s.run("layout.columns", &json!({"count": 2, "apply": "elsewhere"})).is_err());
}
/// Each section's paragraphs (a section break's own paragraph shows as "") and column count.
fn sections_of(s: &Session) -> Vec<(Vec<String>, u32)> {
let mut from = 0;
let mut out = Vec::new();
for (end, x) in s.doc.sections() {
let paras = (from..=end).map(|i| s.doc.para_at(&Pos::body(i, 0)).map(|p| p.text.clone()).unwrap_or_default()).collect();
out.push((paras, x.columns.count));
from = end + 1;
}
out
}
fn select(s: &mut Session, from: (usize, usize), to: (usize, usize)) {
s.sel = Selection { anchor: Pos::body(from.0, from.1), focus: Pos::body(to.0, to.1) };
}
fn strs(v: &[&str]) -> Vec<String> {
v.iter().map(|x| x.to_string()).collect()
}
/// Columns on selected text (#2024), as observed in Word: a continuous section break before
/// and after the selection, the columns on the section between, the rest left alone.
#[test]
fn columns_apply_to_the_selected_text() {
let five = || Session::new(wordcraft_doc::Document::from_text("p1\np2\nalpha beta gamma\np4\np5"));
// A whole paragraph (a triple-click takes its mark): each break gets a paragraph of its own.
let mut s = five();
select(&mut s, (2, 0), (3, 0));
let whole = s.selected_text();
s.run("layout.columns", &json!({"count": 2})).unwrap();
assert_eq!(sections_of(&s), vec![(strs(&["p1", "p2", ""]), 1), (strs(&["alpha beta gamma", ""]), 2), (strs(&["p4", "p5"]), 1)]);
assert!(s.doc.sections().iter().skip(1).all(|(_, x)| x.start == SectionStart::Continuous));
assert_eq!(s.selected_text(), whole, "the paragraph stays selected");
// The same paragraph again: its section changes, no new breaks.
select(&mut s, (3, 0), (4, 0));
s.run("layout.columns", &json!({"count": 3})).unwrap();
assert_eq!(sections_of(&s).iter().map(|(_, n)| *n).collect::<Vec<_>>(), vec![1, 3, 1]);
// Taking the section break along changes nothing more.
select(&mut s, (3, 0), (5, 0));
s.run("layout.columns", &json!({"count": 2})).unwrap();
assert_eq!(sections_of(&s).iter().map(|(_, n)| *n).collect::<Vec<_>>(), vec![1, 2, 1]);
// One undo step takes the breaks and the columns away.
let mut s = five();
select(&mut s, (2, 0), (3, 0));
s.run("layout.columns", &json!({"count": 2})).unwrap();
s.run("edit.undo", &json!({})).unwrap();
assert_eq!(sections_of(&s), vec![(strs(&["p1", "p2", "alpha beta gamma", "p4", "p5"]), 1)]);
// Words inside a paragraph: the breaks split it there.
let mut s = five();
select(&mut s, (2, 10), (2, 6));
s.run("layout.columns", &json!({"count": 2})).unwrap();
assert_eq!(sections_of(&s), vec![(strs(&["p1", "p2", "alpha "]), 1), (strs(&["beta"]), 2), (strs(&[" gamma", "p4", "p5"]), 1)]);
assert_eq!(s.selected_text(), "beta");
assert!(s.sel.anchor > s.sel.focus, "a backward selection stays backward");
// At the document's start no break goes before it, at its end none after.
let mut s = five();
select(&mut s, (0, 0), (1, 0));
s.run("layout.columns", &json!({"count": 2})).unwrap();
assert_eq!(sections_of(&s), vec![(strs(&["p1", ""]), 2), (strs(&["p2", "alpha beta gamma", "p4", "p5"]), 1)]);
let mut s = five();
select(&mut s, (4, 0), (4, 2));
s.run("layout.columns", &json!({"count": 2})).unwrap();
assert_eq!(sections_of(&s), vec![(strs(&["p1", "p2", "alpha beta gamma", "p4", ""]), 1), (strs(&["p5"]), 2)]);
// Select All: the whole document, no breaks.
let mut s = five();
s.run("select.all", &json!({})).unwrap();
s.run("layout.columns", &json!({"count": 2})).unwrap();
assert_eq!(sections_of(&s), vec![(strs(&["p1", "p2", "alpha beta gamma", "p4", "p5"]), 2)]);
// Without a selection the caret's section changes; "selection" then needs one.
let mut s = five();
s.run("layout.columns", &json!({"count": 2})).unwrap();
assert_eq!(sections_of(&s).len(), 1);
assert!(s.run("layout.columns", &json!({"count": 2, "apply": "selection"})).is_err());
}
/// #407 Line Numbers options: start, count by, distance and restart; options alone keep the
/// restart mode, `none` turns numbering off.
#[test]
+29 -2
View File
@@ -112,12 +112,14 @@ pub struct ColumnsForm {
pub cols: Vec<(f32, f32)>,
/// Line between columns.
pub separator: bool,
/// `section`, `document` or `forward` (this point forward).
/// `section`, `document`, `forward` (this point forward) or `selection` (selected text).
pub apply: String,
/// The section's text width, in the interface unit.
pub text_width: f32,
/// The document has more than one section (offer "This section").
pub sections: bool,
/// Text is selected that can take columns of its own (offer "Selected text", #2024).
pub selection: bool,
}
impl ColumnsForm {
@@ -131,14 +133,21 @@ impl ColumnsForm {
let c = &sp.columns;
let count = c.count.clamp(1, 12);
let sections = app.session.doc.sections().len() > 1;
let selection = wordcraft_engine::cmd::page::selection_sectionable(&app.session);
let apply = match (selection, sections) {
(true, _) => "selection",
(false, true) => "section",
(false, false) => "document",
};
let mut f = ColumnsForm {
count,
equal: true,
cols: Vec::new(),
separator: c.separator,
apply: if sections { "section" } else { "document" }.into(),
apply: apply.into(),
text_width: sp.text_width() / k,
sections,
selection,
};
if c.widths.len() == count as usize && count > 1 {
f.equal = false;
@@ -438,6 +447,9 @@ fn columns_ui(app: &mut WordApp, ui: &mut Ui, f: &mut ColumnsForm) -> bool {
if f.sections {
options.insert(0, ("section", "This section"));
}
if f.selection {
options.push(("selection", "Selected text"));
}
let shown = options.iter().find(|(k, _)| *k == f.apply).map(|(_, l)| *l).unwrap_or("This section");
egui::ComboBox::from_id_salt("columns_apply").selected_text(tl!(shown)).width(180.0).show_ui(ui, |ui| {
for (k, l) in &options {
@@ -1357,6 +1369,21 @@ mod tests {
assert_eq!(wordcraft_engine::cmd::page::sect(&a.session).columns.count, 1);
}
/// With text selected, More Columns applies to the selected text by default, as in Word
/// (#2024): the other paragraphs keep one column.
#[test]
fn columns_dialog_applies_to_the_selected_text() {
let mut a = app();
assert!(!ColumnsForm::read(&a).selection, "no selection, no Selected text");
a.run("select.paragraph", json!({})).unwrap();
let mut f = ColumnsForm::read(&a);
assert_eq!((f.selection, f.apply.as_str()), (true, "selection"));
f.preset("two");
a.run("layout.columns", f.params()).unwrap();
let counts: Vec<u32> = a.session.doc.sections().iter().map(|(_, x)| x.columns.count).collect();
assert_eq!(counts, vec![2, 1]);
}
/// The Symbol dialog inserts in the chosen font and remembers the symbol.
#[test]
fn symbol_dialog_inserts_with_its_font() {
+1
View File
@@ -147,6 +147,7 @@
Apply to: Прилагане към:
Whole document Целия документ
This section Този раздел
Selected text Избрания текст
Fill Запълване
Setting: Настройка:
3-D 3-D
Can't render this file because it contains an unexpected character in line 7 and column 25.
+1
View File
@@ -1242,6 +1242,7 @@
This font has no characters to show. Toto písmo neobsahuje žádné znaky k zobrazení.
This point forward Od tohoto místa dále
This section Tento oddíl
Selected text Vybraný text
Three Tři
Tight Těsné
Title from the document properties Název z vlastností dokumentu
Can't render this file because it contains an unexpected character in line 7 and column 25.
+1
View File
@@ -159,6 +159,7 @@
Apply to: Übernehmen für:
Whole document Gesamtes Dokument
This section Dieser Abschnitt
Selected text Markierter Text
Fill Füllung
Setting: Einstellung:
3-D 3D
Can't render this file because it contains an unexpected character in line 6 and column 25.
+1
View File
@@ -198,6 +198,7 @@
Use the Insert key to switch overtype on and off Usar la tecla Insert para activar y desactivar la sobrescritura
Whole document Todo el documento
This section Esta sección
Selected text Texto seleccionado
Fill Relleno de color
Setting: Valor:
3-D 3D
Can't render this file because it contains an unexpected character in line 6 and column 25.
+1
View File
@@ -1331,6 +1331,7 @@
Apply to: Rakenda:
Whole document Kogu dokument
This section See jaotis
Selected text Valitud tekst
Fill Täide
Setting: Säte:
3-D Ruumiline
Can't render this file because it contains an unexpected character in line 841 and column 23.
+1
View File
@@ -145,6 +145,7 @@
Apply to: Appliquer à :
Whole document Tout le document
This section Cette section
Selected text Texte sélectionné
Fill Remplissage
Setting: Type :
3-D 3-D
Can't render this file because it contains an unexpected character in line 7 and column 25.
+1
View File
@@ -2257,6 +2257,7 @@ template Letter Pismo
This password type isn't supported. Ova vrsta lozinke nije podržana.
This point forward Od ove točke nadalje
This section Ovaj odjeljak
Selected text Odabrani tekst
Three Tri
Through Kroz
Tight Usko
Can't render this file because it contains an unexpected character in line 6 and column 25.
+1
View File
@@ -1642,6 +1642,7 @@
Apply to: Alkalmazás erre:
Whole document Teljes dokumentum
This section Ez a szakasz
Selected text Kijelölt szöveg
Fill Kitöltés
Setting: Beállítás:
3-D Térhatású
Can't render this file because it contains an unexpected character in line 6 and column 25.
+1
View File
@@ -144,6 +144,7 @@
Apply to: Applica a:
Whole document Tutto il documento
This section Questa sezione
Selected text Testo selezionato
Fill Riempimento
Setting: Impostazione:
3-D 3D
Can't render this file because it contains an unexpected character in line 6 and column 25.
+1
View File
@@ -213,6 +213,7 @@
Use the Insert key to switch overtype on and off Insert キーで上書きのオンとオフを切り替える
Whole document 文書全体
This section このセクション
Selected text 選択したテキスト
Fill 塗りつぶし
Setting: 種類:
3-D 立体
1 # Japanese (ja) interface catalog. Same format and clean-room rules as zh-hans.tsv.
213
214
215
216
217
218
219
+1
View File
@@ -176,6 +176,7 @@
Use the Insert key to switch overtype on and off Insert 키를 눌러 겹쳐쓰기 켜기/끄기
Whole document 문서 전체
This section 이 구역
Selected text 선택한 텍스트
Fill 채우기
Setting: 설정:
3-D 3차원
1 # Korean (ko) interface catalog. Same format and clean-room rules as zh-hans.tsv.
176
177
178
179
180
181
182
+1
View File
@@ -1329,6 +1329,7 @@
This font has no characters to show. Ta czcionka nie zawiera znaków do pokazania.
This point forward Od tego miejsca
This section Ta sekcja
Selected text Zaznaczony tekst
Title from the document properties Tytuł z właściwości dokumentu
Total Razem
Track Changes Options Opcje śledzenia zmian
Can't render this file because it contains an unexpected character in line 6 and column 25.
+1
View File
@@ -193,6 +193,7 @@
Use the Insert key to switch overtype on and off Usar a tecla Insert para ativar e desativar a sobrescrita
Whole document Documento inteiro
This section Esta seção
Selected text Texto selecionado
Fill Cor de fundo
Setting: Tipo:
3-D 3D
Can't render this file because it contains an unexpected character in line 6 and column 25.
+1
View File
@@ -1620,6 +1620,7 @@ preview Title Пример
Apply to: Применить к:
Whole document Ко всему документу
This section К этому разделу
Selected text К выделенному тексту
Fill Заливка
Setting: Тип:
3-D Объёмная
Can't render this file because it contains an unexpected character in line 7 and column 25.
+1
View File
@@ -270,6 +270,7 @@
Use the Insert key to switch overtype on and off Taster Insert uključuje i isključuje prepisivanje
Whole document Ceo dokument
This section Ovaj odeljak
Selected text Izabrani tekst
Fill Ispuna
Setting: Vrsta:
3-D 3D
Can't render this file because it contains an unexpected character in line 6 and column 25.
+1
View File
@@ -274,6 +274,7 @@
Use the Insert key to switch overtype on and off Тастер Insert укључује и искључује преписивање
Whole document Цео документ
This section Овај одељак
Selected text Изабрани текст
Fill Испуна
Setting: Врста:
3-D 3D
Can't render this file because it contains an unexpected character in line 11 and column 25.
+1
View File
@@ -191,6 +191,7 @@
Use the Insert key to switch overtype on and off Använd Insert-tangenten för att slå på och av överskrivning
Whole document Hela dokumentet
This section Det här avsnittet
Selected text Markerad text
Fill Fyllning
Setting: Inställning:
3-D 3D
Can't render this file because it contains an unexpected character in line 7 and column 25.
+1
View File
@@ -1619,6 +1619,7 @@ preview Title Örnek
Apply to: Uygula:
Whole document Tüm belge
This section Bu bölüm
Selected text Seçili metin
Fill Dolgu
Setting: Ayar:
3-D 3B
Can't render this file because it contains an unexpected character in line 793 and column 23.
+1
View File
@@ -195,6 +195,7 @@
Use the Insert key to switch overtype on and off Клавіша Insert вмикає та вимикає режим заміни
Whole document Увесь документ
This section Цей розділ
Selected text До виділеного тексту
Fill Колір заливки
Setting: Тип:
3-D Об'ємна
Can't render this file because it contains an unexpected character in line 6 and column 31.
+1
View File
@@ -141,6 +141,7 @@
Apply to: Áp dụng cho:
Whole document Toàn bộ tài liệu
This section Phần này
Selected text Văn bản đã chọn
Fill Tô nền
Setting: Thiết lập:
3-D 3-D
Can't render this file because it contains an unexpected character in line 7 and column 25.
+1
View File
@@ -225,6 +225,7 @@
Use the Insert key to switch overtype on and off 用 Insert 键切换改写模式
Whole document 整篇文档
This section 本节
Selected text 所选文字
Fill 填充
Setting: 设置:
3-D 三维
Can't render this file because it contains an unexpected character in line 7 and column 25.
+1
View File
@@ -214,6 +214,7 @@
Use the Insert key to switch overtype on and off 使用 Insert 鍵切換取代模式
Whole document 整份文件
This section 本節
Selected text 選取的文字
Fill 填滿
Setting: 設定:
3-D 立體
1 # Traditional Chinese (zh-hant, Taiwan vocabulary) interface catalog. Same format and clean-room
214
215
216
217
218
219
220
+2 -1
View File
@@ -1,6 +1,6 @@
# UI parity with Microsoft Word
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-18 · **Change:** trivial (Different First Page headers reachable from page 1, #2826; previously trivial: a copied equation also goes in the clipboard's MathML formats, #1297; previously trivial: Read Mode keeps the keyboard, shows whole columns and keeps text clear of the page-turn bar, #1772); previously trivial: font list entries of tall-ascent fonts sit in their row, not cut off, #2570); previously trivial: Split Cells and Convert Text to Table dialogs follow Word's merged-cell limits and Initial column width, #2592; previously 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: comment balloons readable in the dark theme, #2045; 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-18 · **Change:** trivial (Columns on selected text, #2024; previously trivial: Different First Page headers reachable from page 1, #2826; previously trivial: a copied equation also goes in the clipboard's MathML formats, #1297; previously trivial: Read Mode keeps the keyboard, shows whole columns and keeps text clear of the page-turn bar, #1772); previously trivial: font list entries of tall-ascent fonts sit in their row, not cut off, #2570); previously trivial: Split Cells and Convert Text to Table dialogs follow Word's merged-cell limits and Initial column width, #2592; previously 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: comment balloons readable in the dark theme, #2045; 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
@@ -71,6 +71,7 @@ The Language dialog reads effective character formatting, including document def
| 2026-10-16 | trivial | Font list: each entry's capitals are centred in its row, so a font with a very tall ascent (Amiri, Amiri Quran) no longer sits low or is cut in half, and the list reads as one even list (#2570) |
| 2026-10-16 | trivial | Read Mode keeps the keyboard on entering, shows only whole columns, centred, and ends them above the page-turn bar (#1772) |
| 2026-10-16 | trivial | Comment and revision balloons are readable in the dark theme: the card, the markup area, the author stripes and the leader lines come from theme tokens, and the text reaches 4.5:1 (#2045) |
| 2026-10-15 | trivial | Layout › Columns works on the selected text, as in Word: section breaks around it, the rest of the document unchanged; More Columns… adds "Selected text" to Apply to and picks it when text is selected (#2024) |
| 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) |