mirror of
https://github.com/storytold/wordcraft.git
synced 2026-10-24 10:27:44 -06:00
Co-authored-by: Brandon Thomas <echelon@gmail.com>
This commit is contained in:
co-authored by
Brandon Thomas
parent
1e48e6710f
commit
196f828f3f
+3
-1
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
**Stage: alpha** · next: beta, ~15 points (60% → 75% ready for real work) and ~150–230 h away
|
**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-12 · **Change:** trivial (direct run-level native InkML content parts survive DOCX saves; previously trivial: progress log: 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-12 · **Change:** trivial (sample-text formulas on Enter, #1067; previously trivial: direct run-level native InkML content parts survive DOCX saves; previously trivial: progress log: 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.
|
> **Printing update:** 2026-10-12 · direct desktop printing through craft-print; details below.
|
||||||
|
|
||||||
@@ -135,6 +135,7 @@ Ranked, to beta (detail and remaining milestones in [docs/roadmap.md](docs/roadm
|
|||||||
|
|
||||||
| Date | What landed |
|
| Date | What landed |
|
||||||
|---|---|
|
|---|---|
|
||||||
|
| 2026-10-12 | Sample-text formulas on Enter (#1067): `=rand()` and `=lorem()`, optional paragraph/sentence counts, 5/3 defaults, original English and one-step undo |
|
||||||
| 2026-10-12 | File › Export › Word 2003 XML Document (#1081): documents save as WordprocessingML 2003 (`format: "wordml2003"` on the save commands, `wordcraft-cli convert --format wordml2003`); shapes, text boxes, charts and SmartArt don't survive, and it hasn't been opened in Word yet |
|
| 2026-10-12 | File › Export › Word 2003 XML Document (#1081): documents save as WordprocessingML 2003 (`format: "wordml2003"` on the save commands, `wordcraft-cli convert --format wordml2003`); shapes, text boxes, charts and SmartArt don't survive, and it hasn't been opened in Word yet |
|
||||||
| 2026-10-12 | Direct run-level native InkML (`w:contentPart`) now survives DOCX edits and repeated saves with its relationship, content type and bytes intact. Native InkML rendering/editing and ink nested in groups or canvases remain missing |
|
| 2026-10-12 | Direct run-level native InkML (`w:contentPart`) now survives DOCX edits and repeated saves with its relationship, content type and bytes intact. Native InkML rendering/editing and ink nested in groups or canvases remain missing |
|
||||||
| 2026-10-12 | RTF import now uses the RTF spec's defaults where a file names none (#902): no space before or after paragraphs, single line spacing, and the `\deff` default font, instead of WordCraft's Normal style; RTF files that relied on the old defaults open tighter, like in Word |
|
| 2026-10-12 | RTF import now uses the RTF spec's defaults where a file names none (#902): no space before or after paragraphs, single line spacing, and the `\deff` default font, instead of WordCraft's Normal style; RTF files that relied on the old defaults open tighter, like in Word |
|
||||||
@@ -275,6 +276,7 @@ Ranked, to beta (detail and remaining milestones in [docs/roadmap.md](docs/roadm
|
|||||||
|
|
||||||
| Date | Change | Summary |
|
| Date | Change | Summary |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
|
| 2026-10-12 | trivial | Progress log: sample-text formulas on Enter (#1067) |
|
||||||
| 2026-10-12 | trivial | Progress log: direct run-level native InkML content parts survive DOCX edits and repeated saves |
|
| 2026-10-12 | trivial | Progress log: direct run-level native InkML content parts survive DOCX edits and repeated saves |
|
||||||
| 2026-10-12 | trivial | Progress log: Accept All and Reject All keep the right paragraph marks (#864) |
|
| 2026-10-12 | trivial | Progress log: Accept All and Reject All keep the right paragraph marks (#864) |
|
||||||
| 2026-10-11 | trivial | Progress log: Ctrl, Alt, left-edge and selected-cells table border drags (#711) |
|
| 2026-10-11 | trivial | Progress log: Ctrl, Alt, left-edge and selected-cells table border drags (#711) |
|
||||||
|
|||||||
@@ -17,6 +17,9 @@
|
|||||||
# To remove your names, delete your entry (or set fields empty) in a PR. The next
|
# To remove your names, delete your entry (or set fields empty) in a PR. The next
|
||||||
# contributors.py run, and the next build, drop them.
|
# contributors.py run, and the next build, drop them.
|
||||||
|
|
||||||
|
[people.lokinmodar]
|
||||||
|
sync_github_name = true
|
||||||
|
|
||||||
[people.echelon]
|
[people.echelon]
|
||||||
real_name = "Brandon Thomas"
|
real_name = "Brandon Thomas"
|
||||||
display_name = "Brandon Thomas"
|
display_name = "Brandon Thomas"
|
||||||
|
|||||||
@@ -385,12 +385,70 @@ fn ins_char(s: &mut Session, c: char) -> CmdResult {
|
|||||||
sel_result(s)
|
sel_result(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Exact sample-text formulas; bounded counts keep typed input from allocating without limit.
|
||||||
|
fn sample_text(s: &Session) -> Option<String> {
|
||||||
|
let at = &s.sel.focus;
|
||||||
|
let para = s.doc.para_at(at)?;
|
||||||
|
if !s.sel.is_collapsed() || at.off != para.len() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let (args, sentences) = if let Some(args) = para.text.strip_prefix("=rand(") {
|
||||||
|
(
|
||||||
|
args,
|
||||||
|
[
|
||||||
|
"A blank page leaves room for a new idea.",
|
||||||
|
"The morning light falls across a notebook on the desk.",
|
||||||
|
"Small changes in spacing can give a story a different rhythm.",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
(
|
||||||
|
para.text.strip_prefix("=lorem(")?,
|
||||||
|
[
|
||||||
|
"Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
|
||||||
|
"Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
|
||||||
|
"Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
};
|
||||||
|
let args = args.strip_suffix(')')?;
|
||||||
|
if args.contains(['(', ')']) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let count = |arg: &str| arg.parse::<usize>().ok().filter(|n| (1..=200).contains(n));
|
||||||
|
let counts = if args.is_empty() {
|
||||||
|
Some((5, 3))
|
||||||
|
} else if let Some((p, s)) = args.split_once(',') {
|
||||||
|
count(p).zip(count(s))
|
||||||
|
} else {
|
||||||
|
count(args).map(|p| (p, 3))
|
||||||
|
};
|
||||||
|
let (paragraphs, lines) = counts.unwrap_or((5, 3));
|
||||||
|
let mut text = String::new();
|
||||||
|
for _ in 0..paragraphs {
|
||||||
|
for sentence in sentences.iter().cycle().take(lines) {
|
||||||
|
if !text.is_empty() && !text.ends_with('\r') {
|
||||||
|
text.push(' ');
|
||||||
|
}
|
||||||
|
text.push_str(sentence);
|
||||||
|
}
|
||||||
|
text.push('\r');
|
||||||
|
}
|
||||||
|
Some(text)
|
||||||
|
}
|
||||||
|
|
||||||
fn new_paragraph(s: &mut Session, _: &Value) -> CmdResult {
|
fn new_paragraph(s: &mut Session, _: &Value) -> CmdResult {
|
||||||
// Enter in a one-line plain text control (or a check box or list) does nothing, as in Word.
|
// Enter in a one-line plain text control (or a check box or list) does nothing, as in Word.
|
||||||
if super::controls::refuses_paragraph(s) {
|
if super::controls::refuses_paragraph(s) {
|
||||||
return sel_result(s);
|
return sel_result(s);
|
||||||
}
|
}
|
||||||
super::controls::prepare_edit(s)?;
|
super::controls::prepare_edit(s)?;
|
||||||
|
if let Some(text) = sample_text(s) {
|
||||||
|
let end = s.sel.focus.clone();
|
||||||
|
s.sel = Selection { anchor: Pos { off: 0, ..end.clone() }, focus: end };
|
||||||
|
type_text(s, &text)?;
|
||||||
|
return sel_result(s);
|
||||||
|
}
|
||||||
let mut at = delete_selection(s)?;
|
let mut at = delete_selection(s)?;
|
||||||
let auto = border_line(s, &at).map(EnterAutoFormat::Border).or_else(|| table_line(s, &at).map(EnterAutoFormat::Table));
|
let auto = border_line(s, &at).map(EnterAutoFormat::Border).or_else(|| table_line(s, &at).map(EnterAutoFormat::Table));
|
||||||
if let Some(auto) = auto {
|
if let Some(auto) = auto {
|
||||||
|
|||||||
@@ -49,6 +49,84 @@ fn typed(keys: &str) -> Session {
|
|||||||
s
|
s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn sample_text_formulas_expand_on_enter() {
|
||||||
|
for name in ["rand", "lorem"] {
|
||||||
|
for (args, paragraphs, sentences) in [("", 5, 3), ("2", 2, 3), ("2,4", 2, 4), ("1,1", 1, 1), ("200,1", 200, 1), ("1,200", 1, 200)] {
|
||||||
|
let mut s = typed(&format!("={name}({args})"));
|
||||||
|
let depth = s.undo_depth();
|
||||||
|
typ(&mut s, "\n");
|
||||||
|
let generated: Vec<_> = paras(&s).into_iter().map(|p| p.0).collect();
|
||||||
|
assert_eq!(generated.len(), paragraphs + 1, "{name}({args})");
|
||||||
|
for text in generated.iter().take(paragraphs) {
|
||||||
|
assert_eq!(text.matches('.').count(), sentences);
|
||||||
|
assert!(text.starts_with(if name == "lorem" { "Lorem ipsum" } else { "A blank page" }), "{name}({args}): {text:?}");
|
||||||
|
}
|
||||||
|
assert_eq!(generated.last().unwrap(), "");
|
||||||
|
assert_eq!(s.sel.focus, Pos::body(paragraphs, 0));
|
||||||
|
assert_eq!(s.undo_depth(), depth + 1);
|
||||||
|
let expanded = s.doc.clone();
|
||||||
|
run(&mut s, "edit.undo", json!({}));
|
||||||
|
assert_eq!(texts(&s), [format!("={name}({args})")]);
|
||||||
|
run(&mut s, "edit.redo", json!({}));
|
||||||
|
assert_eq!(s.doc, expanded);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn sample_text_invalid_parameters_use_defaults() {
|
||||||
|
for name in ["rand", "lorem"] {
|
||||||
|
for args in ["0", "-1", "201", "abc", "1.5", "99999999999999999999999999999", "2,0", "0,4", "2,201", "2,no", "2,", ",4", "1,2,3"] {
|
||||||
|
let s = typed(&format!("={name}({args})\n"));
|
||||||
|
let texts = texts(&s);
|
||||||
|
assert_eq!(texts.len(), 6, "{name}({args})");
|
||||||
|
assert!(texts.iter().take(5).all(|text| text.matches('.').count() == 3));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn sample_text_requires_an_exact_paragraph_and_caret_at_end() {
|
||||||
|
for formula in [" =rand()", "=rand() ", "prefix =rand()", "=lorem() suffix", "=other()", "=rand(", "=rand(())"] {
|
||||||
|
assert_eq!(texts(&typed(&format!("{formula}\n"))), [formula, ""]);
|
||||||
|
}
|
||||||
|
let mut s = typed("=rand()");
|
||||||
|
run(&mut s, "caret.home", json!({}));
|
||||||
|
typ(&mut s, "\n");
|
||||||
|
assert_eq!(texts(&s), ["", "=rand()"]);
|
||||||
|
let mut s = typed("=rand()suffix");
|
||||||
|
s.sel = crate::Selection { anchor: Pos::body(0, 7), focus: Pos::body(0, 13) };
|
||||||
|
typ(&mut s, "\n");
|
||||||
|
assert_eq!(texts(&s), ["=rand()", ""]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn sample_text_preserves_typing_and_paragraph_formatting() {
|
||||||
|
let mut s = s();
|
||||||
|
run(&mut s, "format.bold", json!({}));
|
||||||
|
run(&mut s, "para.alignCenter", json!({}));
|
||||||
|
typ(&mut s, "=rand(2,1)\n");
|
||||||
|
for p in s.doc.body.iter().filter_map(|b| b.as_para()).take(2) {
|
||||||
|
assert_eq!(p.props.align, Some(wordcraft_doc::props::Align::Center));
|
||||||
|
assert_eq!(p.props_at(0).bold, Some(true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn sample_text_replacement_tracks_changes() {
|
||||||
|
let mut s = typed("=lorem(2,1)");
|
||||||
|
run(&mut s, "review.trackChanges", json!({}));
|
||||||
|
typ(&mut s, "\n");
|
||||||
|
assert!(s.doc.body.iter().filter_map(|b| b.as_para()).flat_map(|p| &p.runs).any(|r| r.props.ins.is_some()));
|
||||||
|
run(&mut s, "review.rejectAll", json!({}));
|
||||||
|
assert_eq!(texts(&s), ["=lorem(2,1)"]);
|
||||||
|
run(&mut s, "edit.undo", json!({}));
|
||||||
|
run(&mut s, "review.acceptAll", json!({}));
|
||||||
|
assert_eq!(texts(&s).len(), 3);
|
||||||
|
assert!(!s.doc.plain_text(StoryRef::Body).contains("=lorem"));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn enter_twice_after_a_list_item_ends_the_list() {
|
fn enter_twice_after_a_list_item_ends_the_list() {
|
||||||
let s = typed("* item\n\ntext");
|
let s = typed("* item\n\ntext");
|
||||||
|
|||||||
+6
-1
@@ -1,6 +1,6 @@
|
|||||||
# Where WordCraft falls short of Word
|
# Where WordCraft falls short of Word
|
||||||
|
|
||||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-12 · **Change:** trivial (radar, stock and other undrawn chart types show a placeholder instead of blank space, #998; previously trivial: saving Word 2003 XML, #1081; previously trivial: direct run-level native InkML content parts now survive DOCX saves; previously trivial: the Font list no longer keeps every previewed font in memory, #848; 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 Table and Eraser landed, #303; previously minor: beta distance restated: ~15 points, ~150–230 h; previously: first version; every known shortfall from the 2026-10-10 re-measure, ranked) · **Target:** Microsoft Word (Microsoft 365) for Mac 16.113.4
|
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-12 · **Change:** trivial (sample-text formulas on Enter, #1067; previously trivial: radar, stock and other undrawn chart types show a placeholder instead of blank space, #998; previously trivial: saving Word 2003 XML, #1081; previously trivial: direct run-level native InkML content parts now survive DOCX saves; previously trivial: the Font list no longer keeps every previewed font in memory, #848; 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 Table and Eraser landed, #303; previously minor: beta distance restated: ~15 points, ~150–230 h; previously: first version; every known shortfall from the 2026-10-10 re-measure, ranked) · **Target:** Microsoft Word (Microsoft 365) for Mac 16.113.4
|
||||||
|
|
||||||
> **Printing update:** 2026-10-12 · direct desktop printing through craft-print; details below.
|
> **Printing update:** 2026-10-12 · direct desktop printing through craft-print; details below.
|
||||||
|
|
||||||
@@ -51,6 +51,10 @@ full number from ~60% to ~75%. Everything else is depth on the way to full parit
|
|||||||
|
|
||||||
## By kind
|
## By kind
|
||||||
|
|
||||||
|
Sample-text formulas on Enter (#1067) are implemented: `=rand()` and `=lorem()`,
|
||||||
|
optional paragraph/sentence counts and one-step undo. See [typing-parity.md](typing-parity.md)
|
||||||
|
for the accepted parameter range and validation limits; readiness numbers are unchanged.
|
||||||
|
|
||||||
The same gaps grouped the way the parity documents are, for agents working in one area.
|
The same gaps grouped the way the parity documents are, for agents working in one area.
|
||||||
|
|
||||||
- **Feature gaps:** #2 (preserve), #5, #10, #12, #13, #15, #17, #21, #25, #27, #28, #29; Clipboard
|
- **Feature gaps:** #2 (preserve), #5, #10, #12, #13, #15, #17, #21, #25, #27, #28, #29; Clipboard
|
||||||
@@ -73,6 +77,7 @@ The same gaps grouped the way the parity documents are, for agents working in on
|
|||||||
|
|
||||||
| Date | Change | Summary |
|
| Date | Change | Summary |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
|
| 2026-10-12 | trivial | Sample-text formulas on Enter (#1067) implemented; numerical limits not compared in Word |
|
||||||
| 2026-10-12 | minor | Italian proofing landed (it-IT spelling from the installed Hunspell dictionary, accent-first suggestions, conservative grammar); gap #8 narrowed to the remaining languages |
|
| 2026-10-12 | minor | Italian proofing landed (it-IT spelling from the installed Hunspell dictionary, accent-first suggestions, conservative grammar); gap #8 narrowed to the remaining languages |
|
||||||
| 2026-10-12 | trivial | #2 narrowed: direct run-level `w:contentPart` InkML survives DOCX edits and repeated saves; nested group/canvas ink and native rendering remain |
|
| 2026-10-12 | trivial | #2 narrowed: direct run-level `w:contentPart` InkML survives DOCX edits and repeated saves; nested group/canvas ink and native rendering remain |
|
||||||
| 2026-10-11 | trivial | Table column and row markers on the rulers landed (#700): the ruler's column markers are off the UI/UX gaps |
|
| 2026-10-11 | trivial | Table column and row markers on the rulers landed (#700): the ruler's column markers are off the UI/UX gaps |
|
||||||
|
|||||||
+18
-1
@@ -1,6 +1,6 @@
|
|||||||
# Typing parity with Word
|
# Typing parity with Word
|
||||||
|
|
||||||
> **Last reviewed:** 2026-10-11 · **Last updated:** 2026-10-12 · **Change:** trivial (Track Changes: Accept All after a tracked delete from a paragraph end keeps the next paragraph; Reject All after typing into an empty paragraph keeps it (#864); previously minor: Correct TWo INitial CApitals, cAPS LOCK and table-cell capitals, #544; previously trivial: complex-script caret and Backspace, #604; Move Paragraph Up/Down, Promote/Demote, Go Back and Alt+X keys, #343) · **Target:** Microsoft Word (Microsoft 365) for Mac 16.113.4
|
> **Last reviewed:** 2026-10-11 · **Last updated:** 2026-10-12 · **Change:** trivial (sample-text formulas on Enter, #1067; previously trivial: Track Changes: Accept All after a tracked delete from a paragraph end keeps the next paragraph; Reject All after typing into an empty paragraph keeps it (#864); previously minor: Correct TWo INitial CApitals, cAPS LOCK and table-cell capitals, #544; previously trivial: complex-script caret and Backspace, #604; Move Paragraph Up/Down, Promote/Demote, Go Back and Alt+X keys, #343) · **Target:** Microsoft Word (Microsoft 365) for Mac 16.113.4
|
||||||
|
|
||||||
What Word does when you type, observed black-box (same keystrokes typed into Word and
|
What Word does when you type, observed black-box (same keystrokes typed into Word and
|
||||||
WordCraft, results read back paragraph by paragraph) and pinned by tests in
|
WordCraft, results read back paragraph by paragraph) and pinned by tests in
|
||||||
@@ -8,6 +8,22 @@ WordCraft, results read back paragraph by paragraph) and pinned by tests in
|
|||||||
tests together. Line breaking and pagination are in [`layout-parity.md`](layout-parity.md); the
|
tests together. Line breaking and pagination are in [`layout-parity.md`](layout-parity.md); the
|
||||||
overall picture is in [`target-app-parity.md`](target-app-parity.md).
|
overall picture is in [`target-app-parity.md`](target-app-parity.md).
|
||||||
|
|
||||||
|
## Sample text (#1067)
|
||||||
|
|
||||||
|
Enter at the end of a paragraph containing exactly `=rand()` or `=lorem()` replaces
|
||||||
|
the formula with five paragraphs of three sentences and leaves the caret in a following
|
||||||
|
empty paragraph. `=rand(p)` / `=lorem(p)` set the paragraph count; `(p,s)` sets both
|
||||||
|
counts. WordCraft accepts integers from 1 to 200 for each count; if either parameter
|
||||||
|
is invalid or outside that range, both revert to 5/3. Other text, a selection or Enter
|
||||||
|
inside the formula follows ordinary Enter behaviour. The English text is original to
|
||||||
|
WordCraft; lorem ipsum uses traditional pseudo-Latin. This implements the issue's
|
||||||
|
requested defaults; the exact numerical limits have not been compared in Word.
|
||||||
|
|
||||||
|
The replacement and its paragraph breaks are one undo step. Typing and paragraph
|
||||||
|
formatting use the existing editing primitives. Tests: `sample_text_formulas_expand_on_enter`,
|
||||||
|
`sample_text_invalid_parameters_use_defaults`, `sample_text_requires_an_exact_paragraph_and_caret_at_end`,
|
||||||
|
`sample_text_preserves_typing_and_paragraph_formatting`, `sample_text_replacement_tracks_changes`.
|
||||||
|
|
||||||
## Lists
|
## Lists
|
||||||
|
|
||||||
| Keys | Word's result | Test |
|
| Keys | Word's result | Test |
|
||||||
@@ -168,6 +184,7 @@ Word.
|
|||||||
|
|
||||||
| Date | Change | Summary |
|
| Date | Change | Summary |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
|
| 2026-10-12 | trivial | Sample-text formulas on Enter (#1067), exact matching, bounded parameters, original English and one-step undo |
|
||||||
| 2026-10-12 | trivial | Track Changes: Accept All after a tracked delete from a paragraph end keeps the next paragraph; Reject All after typing into an empty paragraph keeps it (#864) |
|
| 2026-10-12 | trivial | Track Changes: Accept All after a tracked delete from a paragraph end keeps the next paragraph; Reject All after typing into an empty paragraph keeps it (#864) |
|
||||||
| 2026-10-12 | minor | AutoCorrect: Correct TWo INitial CApitals, accidental cAPS LOCK, capitalize first letter of table cells (#544) |
|
| 2026-10-12 | minor | AutoCorrect: Correct TWo INitial CApitals, accidental cAPS LOCK, capitalize first letter of table cells (#544) |
|
||||||
| 2026-10-11 | minor | Text direction: right-to-left letters typed into an empty paragraph make it right-to-left; existing paragraphs keep theirs (#713) |
|
| 2026-10-11 | minor | Text direction: right-to-left letters typed into an empty paragraph make it right-to-left; existing paragraphs keep theirs (#713) |
|
||||||
|
|||||||
Reference in New Issue
Block a user