Commit Graph
403 Commits
Author SHA1 Message Date
aiongg a453292729 Merge main into the integration batch 2026-10-24 09:20:03 +00:00
aiongg 2bbfe46d3e Integration: slides with two visible pictures get no layout ideas 2026-10-24 09:14:11 +00:00
aiongg 9dcb7bab03 Integration: the automatic-date test reads the clock before and after the command so a tick of the second cannot fail it 2026-10-24 09:13:29 +00:00
Dylan M. Taylor 6189fa8bf6 perf(engine): bound HTML entity semicolon scan window and formatting stack search (#1267) 2026-10-24 04:41:43 -04:00
Dylan M. TaylorandClaude Sonnet 5.5 d94790d97a refactor: replace redundant closures with method paths (SonarCloud S1612) (#1261)
Skipped where the receiver type is generic or not evident without a compiler (wrapping_neg, total_cmp, exists, to_vec, as_ref, split_first, Option::into_inner).

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-24 04:27:07 -04:00
aiongg 8957e193e9 Merge integration track r1-t02 (dialogs, view, text editing, panes, status bar, other)
ROADMAP.md, docs/gaps.md: union of both tracks' log rows.
2026-10-24 06:26:36 +00:00
aiongg abd8768b65 Merge PR #565: Files: save and open outlines as RTF
Conflicts:
crates/engine/src/cmd/file.rs: export spec keeps main's transparentBackground and adds rtf; probe_clips (main) and outline_text (PR) both kept
docs/file-format-parity.md: PR's outline row (RTF now read) with main's .md wording, main's PNG row
2026-10-24 06:18:03 +00:00
aiongg 5b5fd5eabe Merge PR #1109: Reuse Slides: choose which slides of the other file to insert
Conflicts: ROADMAP.md (union of both sides' rows)
2026-10-24 06:17:26 +00:00
aiongg 2693336155 Merge PR #809: Design: Browse for Themes brings a template's slide master and layouts (#807)
Conflicts: ROADMAP.md (union of both sides' rows)
2026-10-24 06:17:23 +00:00
aiongg f52c911959 Integration: #927 Header & Footer dialog sends dateFormat only when picked; set_date doc comment back above set_date
Without it, Apply rewrote every slide's existing date field to datetime1.
2026-10-24 06:17:19 +00:00
aiongg 0313e0128a Merge PR #850: Review: reject revisions after Compare, one or all
ROADMAP.md, docs/gaps.md: kept main's lines and the PR's single added line in each table.
2026-10-24 06:16:50 +00:00
aiongg 5880086522 Merge PR #927: Header & Footer: the automatic date takes a format 2026-10-24 06:16:45 +00:00
aiongg b7c505a389 Merge PR #1254: Reject invalid index in slide.hide and slide.layout
Conflicts: crates/engine/src/tests.rs (appended both sides' tests)
2026-10-24 06:16:45 +00:00
aiongg 987f49ac03 Merge PR #1252: Reject '+'-signed numeric character references in HTML paste 2026-10-24 06:16:43 +00:00
aiongg 92724e02bb Merge PR #1205: Design Ideas: no ideas for slides with diagrams, connectors or other graphics (#1200)
Conflicts: crates/engine/src/cmd/ideas.rs (test module: kept both sides' tests)
2026-10-24 06:16:39 +00:00
aiongg c480b74a3f Merge PR #833: Shapes: Edit Points — Straight/Curved Segment and Open/Close Path from the right-click menu
Conflicts: ROADMAP.md docs/gaps.md docs/ui-parity.md (union of both sides' rows)
2026-10-24 06:16:21 +00:00
aiongg 2fd32751cc Merge PR #1251: Fix arrange.distribute span to use the selection's full extent 2026-10-24 06:16:21 +00:00
aiongg 78afd2fc45 Merge PR #1245: Title: arrange.group: nest groups at most 32 deep 2026-10-24 06:16:18 +00:00
aiongg f2e2fcaba4 Merge PR #1015: Chart text can be coloured (chart.options textColor, format.color) and follows the theme by default
Conflicts: crates/engine/src/cmd/insert.rs (kept main's apply_bin_options / apply_subtotals_and_bars helpers and added the textColor assignment)
2026-10-24 06:15:53 +00:00
aiongg aed303e504 Integration: #956 chart.options dataLabels resets the series' own settings
Without it, turning Data Labels on did nothing for an imported chart whose series read showVal 0.
2026-10-24 06:15:41 +00:00
aiongg 7fd34fb359 Merge PR #813: engine: a hostile text selection can't drive paragraph commands past the body 2026-10-24 06:15:03 +00:00
aiongg 5827d3b4c1 Merge PR #904: Clamp text.selectParagraph paragraph index to avoid overflow 2026-10-24 06:15:03 +00:00
5fadda5ecf chore: resolve SonarCloud maintainability issues (#1255)
* chore: resolve SonarCloud maintainability issues

* fix: address shellcheck SC2059 and fix generic cast ambiguity

* style: apply rustfmt formatting

* fix: restore compile and behaviour in Sonar refactors

- fonts: char::is_alphanumeric takes &self, so filter needs a closure
- h264: keep the mvd accumulator as i32 (prefix is usize)
- model: annotate the non-stacked range accumulators as f64
- engine: chart.options still clears the raw chart XML for upDownBars
  and quartiles; smartart goes back to the glob import (cmd! macro)
- web: keep the original viewport meta (behaviour change)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Assign positional parameters to locals in sha256 verification

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Dylan Taylor <dylan@craftmaker.dev>
2026-10-23 23:28:09 -04:00
NetterSilverandClaude Haiku 5.5 6d7b32351f Reject invalid index in slide.hide and slide.layout
Found while testing crates/engine/src/cmd/slide.rs:376 (hide); same pattern at slide.rs:445

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-24 02:16:19 +00:00
NetterSilverandClaude Haiku 5.5 fc914a059c Reject '+'-signed numeric character references in HTML paste
Found while testing crates/engine/src/cmd/richclip.rs:301-304 (numeric_char, used by decode_text)

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-24 01:23:11 +00:00
NetterSilverandClaude Haiku 5.5 18e8bb0ded Fix arrange.distribute span to use the selection's full extent
Found while testing crates/engine/src/cmd/arrange.rs:325-327 (distribute)

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-24 01:07:34 +00:00
Zach BerryandClaude Fable 5.1 0c510426af Chart text without a colour of its own takes PowerPoint's default grey
The theme's bare text colour made chart text black on a light theme,
where it used to be 595959. PowerPoint's default is `tx1` at lumMod 65000
and lumOff 35000: 595959 on a light theme, a light grey on a dark one, so
the dark-theme fix stays. The render test now checks the light-theme title
is dark but not black; the chart.options doc says what null gives.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-23 19:57:50 -05:00
Zach BerryandClaude Fable 5.1 1b03ae95de format.color on a selected chart colours the chart's text
Font Color with a chart selected answered and changed nothing: a chart
has no text runs to colour. It now sets the chart's text colour (title,
axes, legend and data labels), the same thing chart.options {textColor}
sets; a mixed selection still colours the other shapes' runs.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-23 19:57:50 -05:00
Zach BerryandClaude Fable 5.1 a48a2d706a chart.options takes textColor so a chart's text can be coloured
On a dark theme a chart's title, axis labels, legend and data labels
render in a fixed grey and nothing could change them, though the model
already carries `text_color`. `chart.options {textColor}` now sets it
(#RRGGBB, accent1…accent6, tx1…, or null for the default) and refuses a
string that isn't a colour. docs/mcp.md mentions it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-23 19:57:50 -05:00
aiongg 9aef21e627 Media: a clip opened from a .pptx gets its length and size from its headers (#1241) (#1250) 2026-10-23 19:56:24 -04:00
KataccandClaude Opus 5.5 8117d5b710 arrange.group: nest groups at most 32 deep
Grouping a group again and again had no limit, but a .deckcraft saved
with 39 or more nested groups could not be opened again (the JSON
reader's recursion limit), and past 64 levels shape walks such as
format.languageAll stop. arrange.group now refuses to nest past 32,
the depth the PPTX reader reads and the renderer draws, and leaves the
slide unchanged. The test builds the deepest allowed deck (a table at
the bottom) and checks it saves and reopens.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 01:02:21 +03:00
Brandon Thomas 7871ff3d62 Merge pull request #1076 from fchinu/format_text 2026-10-23 17:22:14 -04:00
Brandon Thomas 8b912c106e Merge pull request #1002 from Silvertree2010/fix/h2821-find-replace-ignores-line-breaks 2026-10-23 17:22:13 -04:00
Brandon ThomasandClaude Opus 5.5 a5ca7d04b0 Format Painter: walk only the paragraphs a text selection has
An unclamped hostile selection end (text.select caret [1e18, 0]) made
covered_paragraphs iterate for effectively forever.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 17:13:32 -04:00
Brandon Thomas 8f81cdc380 Merge pull request #1026 from Silvertree2010/fix/1020-bug-report-deckcraft-gifs-stop-p
# Conflicts:
#	crates/ui-egui/src/media.rs
2026-10-23 17:11:03 -04:00
Brandon Thomas a0aca7f36b Merge pull request #1187 from samirhvbr/fix/group-shape-appearance 2026-10-23 17:10:42 -04:00
Brandon Thomas b2017dcb47 Merge pull request #1233 from marcoarnulfo/fix/set-transparent-color-pick 2026-10-23 17:10:41 -04:00
Brandon Thomas 8485b10356 Merge pull request #1207 from xc4pr/fix/1201-ideas-band-reset 2026-10-23 17:10:11 -04:00
Brandon Thomas e8e36be177 Merge pull request #894 from kk376/fix/apply-to-all-master-background 2026-10-23 17:09:50 -04:00
Brandon Thomas 998429fb9e Merge pull request #820 from Silvertree2010/fix/h1617-paste-from-html-a-newline-inside 2026-10-23 17:09:49 -04:00
Brandon Thomas e128a09caa Merge pull request #988 from Zetenypapp/fix/smart-duplicate-966
# Conflicts:
#	crates/engine/src/tests.rs
2026-10-23 17:09:38 -04:00
Brandon Thomas 86f6b365f3 Merge pull request #1145 from pick2510/fix/table-text-other-style 2026-10-23 17:09:24 -04:00
Marco Arnulfo 070cee617e Set Transparent Color: take the pixel of the topmost selected picture, not the first one selected 2026-10-23 21:17:27 +02:00
midasmatterhorn 077682ed4c engine: merge main and cover direct hostile paragraph selections 2026-10-23 21:22:14 +03:00
xc4pr ebf67f8a9a Design Ideas: switching ideas also removes a band saved by earlier versions (#1201) 2026-10-23 19:26:08 +02:00
Marco Arnulfo b7ea777be7 Set Transparent Color: map the click through the picture's 3-D camera and find grouped pictures that keep no box of their own 2026-10-23 19:16:09 +02:00
xc4pr 8a61586585 Design Ideas: store the Full-bleed band's opacity as PPTX does, so switching ideas still removes it after a save (#1201) 2026-10-23 19:08:09 +02:00
xc4pr 49f296cca1 Design Ideas: Full-bleed puts the band on the visible title, not a hidden one (#1201) 2026-10-23 18:25:46 +02:00
xc4pr e126fad9a7 Design Ideas: decide whether an empty box shows from its resolved fill and outline (#1200) 2026-10-23 18:17:39 +02:00
Dylan M. Taylor 0f4fffcf6c Use chrono instead of hand-rolled UTC conversion (#1116)
* Use chrono for UTC/calendar conversion instead of hand-rolled copies

Replaces the hand-rolled civil_from_days / civil copies and the hand-written
weekday / leap-year / days-in-month helpers with chrono. chrono is already a
workspace dependency (used by crates/text), so this reuses that entry and just
adds `chrono = { workspace = true }` to the engine and desktop app rather than
a second version.

- apps/deckcraft logging `timestamp` now formats through chrono (private
  civil_from_days deleted).
- engine cmd::design `civil` (days since 1970 -> date, used for comment
  timestamps in review.rs) uses chrono::NaiveDate.
- text datetime `DateTime::is_valid` / `weekday` use chrono::NaiveDate instead
  of a hand-rolled leap-year table and days-since-1970 weekday.

Output is byte-identical and pinned by the existing logging, design and
datetime-field tests; each converted helper keeps a proleptic-Gregorian
fallback for dates outside chrono's NaiveDate range.

Follow-up to storytold/cadcraft#1785

* text: make chrono available on wasm32

is_valid/weekday in crates/text/src/datetime.rs use chrono unconditionally,
but chrono was only declared under the non-wasm target, so the crate (and
engine/pdf/render/ui-egui depending on it) failed the wasm32-unknown-unknown
check in `cargo xtask ci`.

- crates/text: declare chrono unconditionally (wasm-safe `std` baseline),
  and keep `clock` in a separate cfg(not(target_arch="wasm32")) entry for
  now_local()'s local clock, which is already wasm-gated to return None.
- workspace: drop `clock` from the shared chrono entry so it is no longer
  forced onto wasm builds (engine uses chrono unconditionally too); `clock`
  is now requested per-crate only where the local clock is read.

* Never panic on a clock outside chrono's range; harden the civil fallback

logging.rs timestamp(): chrono's From<SystemTime> unwraps, so a clock past
year 262143 panicked inside the logger. Use the fallible DateTime::from_timestamp
and read an out-of-range or pre-epoch clock as the epoch, as the old saturating
code did. Years past 9999 are written with {:04} like before, because %Y adds a
'+'. Tests cover both cases.

cmd/design.rs civil_fallback(): make the hand-rolled fallback's year arithmetic
saturating so civil() cannot overflow or panic at i64::MAX/MIN (the engine rule
forbids crashes and unchecked arithmetic). Behaviour is unchanged for every real
input; a test exercises both extremes. The output year is formatted with {y:04}
by review.rs, so no %Y prefix issue.

crates/text/src/datetime.rs: checked after review; is_valid already limited the
year to 1..=9999 before this PR, weekday() is only reached for valid dates, and
all its arithmetic is checked/euclidean, so no change is needed.

* Don't build an unrepresentable SystemTime in the far-future test

UNIX_EPOCH + Duration::from_secs(u64::MAX / 2) overflows Windows'
SystemTime and panicked before timestamp() ran, failing the Windows
test job. Build it with checked_add and only assert where it exists.

* Make civil() exact for every i64 instead of saturating

The out-of-range fallback saturated z + 719_468, so civil(i64::MAX)
returned a date 719,468 days early. civil() now has chrono convert the day
within its 400-year Gregorian cycle and adds whole cycles back as years
(i128 for the extremes), so the hand-rolled fallback is gone. Exact results
for i64::MAX/MIN and both sides of chrono's range are tested against Hinnant's formula.

* time: preserve out-of-range years in the log timestamp instead of the epoch

`DateTime::from_timestamp(..).unwrap_or_default()` changed the existing output: a
clock set far ahead (an input the old hand-rolled civil-from-days converted)
collapsed to `1970-01-01`. Restore the old conversion domain with a cycle-based
helper: reduce by whole 400-year Gregorian cycles (146_097 days), convert the
in-range remainder with chrono, and carry the year back as i128. Only the year
leaves chrono's range; month/day/time stay exact. Pre-1970 still clamps to the
epoch as before. chrono stays the only calendar logic (no new features).

apps/deckcraft logging.rs `timestamp` (SystemTime, u64 secs), pinned via a
platform-safe `UNIX_EPOCH.checked_add`:
  u64::MAX/2 s → "292277026596-12-04T15:30:07.000Z" (was "1970-01-01..."),
  10e12 s → "318857-05-20T17:46:40.000Z", 253_402_300_800 s → "10000-01-01...".

* Name the 400-year range extension as the one exception to the time rule

The rule said never to hand-roll calendar math, but the range fix
(shifting by whole 400-year Gregorian cycles so dates past chrono's year
range keep their old output) is cycle arithmetic, so the rule and the code
disagreed. The rule now names that exception: the library still computes
month, day and time, and only whole cycles are carried in the year.

* Say the library computes month and day; time-of-day is plain arithmetic

Narrows the range-extension wording: the date library computes the
calendar fields, and splitting seconds into hours, minutes and seconds
is ordinary arithmetic, which is what the code does.
2026-10-23 11:20:42 -04:00