* Open Word documents with WordCraft from the system (#295)
Register WordCraft for Word, RTF and ODT files on Windows and Linux without
taking over anyone's defaults, and add File > Options > General > "Make
WordCraft the default for Word documents..." where the system allows it.
- Windows MSI: a ProgId per type (.docx .docm .dotx .dotm .doc .dot .rtf
.odt, plus .md and .txt as Open With candidates only) with the app icon
and `"wordcraft.exe" "%1"`, OpenWithProgids, Applications\wordcraft.exe
SupportedTypes, and Capabilities + RegisteredApplications so WordCraft
shows in Settings > Default apps. New component with its own GUID.
- Linux: the desktop entry declares the macro-enabled, template and legacy
Word types and text/rtf; AppStream lists the media types. deb, rpm,
AppImage and both Flatpak manifests use this same file.
- macOS: Info.plist also lists legacy .doc.
- The Options button runs `ui.makeDefaultApp` through a new
Services::make_default_app hook: Windows opens
ms-settings:defaultapps on WordCraft's page; Linux and BSD run
`xdg-mime default ai.storyteller.wordcraft.desktop <types>` (refused
inside Flatpak or without an installed desktop entry); macOS shows the
Finder Get Info hint; the web shows nothing. The status bar reports the
outcome. Strings translated in every catalog.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Review fixes for #304: keep Make default out of programmatic dispatch
ui.makeDefaultApp is refused when run programmatically (control channel, MCP, macros,
scripts); only a click on File > Options > General > Make WordCraft the default… reaches
the host's hook, so no agent can change the user's system default apps or open system
settings. Test: programmatic_calls_cannot_change_the_default_apps.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Default-app strings in the newer catalogs; the button's test looks for a General-pane label
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
- release.yml: new `linux-riscv64` job ported from GridCraft. Cross-compiles
wordcraft and wordcraft-cli on ubuntu-24.04 with riscv64 libs from
ports.ubuntu.com (riscv64 variants of the Linux job's -dev packages),
packages a tar.gz, and smoke-tests the CLI under QEMU. The draft-release
job needs it, so its tar.gz is uploaded and covered by SHA256SUMS.
- packaging/linux/package.sh: CROSS_ARCH/CROSS_TARGET/CROSS_COMPILE/EMULATOR
support (as in GridCraft).
- README and docs/releasing.md list the riscv64 tarball.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
The MSI had no UI, so Windows Installer showed only its basic progress box and closed
without saying the install had worked. It now uses WiX's standard WixUI_Minimal dialogs:
a welcome page with the license (MIT or Apache-2.0, built at packaging time from
LICENSE-MIT and LICENSE-APACHE), progress, and a finish page with an optional
"Launch WordCraft" checkbox. The release and Windows ARM64 workflows install the WiX
UI and Util extensions the build now needs. UpgradeCode and component GUIDs are unchanged.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* LaTeX (.tex) import and export (#7)
Open and save LaTeX source as a document format, next to Markdown and
HTML. Export writes a standalone article (fontenc, ulem, xcolor,
multirow, amsmath, hyperref, loaded only when used): unnumbered sections,
itemize/enumerate, quote, center/flushright, verbatim, tabular with the
document's column widths and merged cells, equations as $..$ / \[..\],
character formatting, colours and links; metadata goes to \hypersetup.
Import reads the everyday subset: preamble \title/\author, sectioning
(\part/\chapter shift levels), paragraphs, lists with labels, quote,
alignment environments, verbatim-like environments, tabular with
\multicolumn/\multirow/\cellcolor and p{} widths, inline and display
math, formatting commands and declarations, colours, links, refs,
citations, footnotes, accents, TeX ligatures and special characters.
Unknown commands keep their arguments' text; layout and definition
commands are dropped with their arguments. Nesting is depth-limited and
input is capped, so hostile files can't overflow the stack.
The flow model gains an Equation inline so equations survive LaTeX round
trips; the other text formats write their linear text as before.
Wired into open/save dispatch, the file dialog filter, Backstage Export,
the web app, CLI/MCP help, docs and the Linux desktop entry.
Fixes#7.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019FczntrDNYd6DupyBdpbL5
* #7: bound LaTeX column specs and equation export (review)
- spec_widths: `*{n}{…}` repeats recurse with a depth argument and stop at
MAX_NEST, so a deeply nested column spec no longer overflows the stack or
exhausts memory. Column counts saturate and widths stop at MAX_COLS.
- Column specs read from the source are capped at MAX_SPEC (4096) chars.
- balanced() looks groups up in a table of closers built in one stack pass,
so linear_to_latex no longer rescans to the end of the string for every
unmatched `(` (quadratic: 50k took seconds). spec_widths uses it too.
- env_name restores the position when `\begin{` / `\end{` has no `}`
within 64 chars, so the `{` is no longer lost.
- Regression tests: the 100k-deep `*{1}{` spec and a 200k-`(` equation in
deep_nesting_is_bounded; unclosed_begin_keeps_its_brace and
spec_widths_repeats_are_bounded.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LyVbT6Vv4BwWZ4hY8973qD
* #7: linear-time labels, brackets and \begin{; no commands from the document in exports
Applies @HaringIbon's review suggestions:
1. Parser::anchor keeps at most MAX_ANCHOR_RUN (64) bookmarks in a row with
no text between them; text() looked back past every one, so a file of
labels imported in quadratic time. Labels separated by text are all kept.
2. linear_to_latex_at checks for the `/` of a fraction before copying the
group out, so deeply nested matched brackets export in linear time.
3. env_name searches only the next 65 bytes for `}`, so a run of unclosed
`\begin{` imports in linear time.
4. An equation's `\name` is written as a command only when it is a known
symbol, function or font/spacing command (MATH_COMMANDS); anything else
becomes `\backslash name`. Two carets are never written side by side in
equations or anchor names, since TeX reads `^^5c` as a backslash. Compiling
an export can no longer `\input` files or `\write18` named by the document.
Regression tests: three cases added to deep_nesting_is_bounded, plus
latex_export_carries_no_commands_from_the_document and
latex_labels_in_a_row_are_read_in_linear_time.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LyVbT6Vv4BwWZ4hY8973qD
* Merge follow-ups: FTable.borderless (from #102) in the LaTeX importer; rustfmt
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
The web build always starts eframe's wgpu runner; only `?webgl` changes
the backend. `?cpu` selected the same renderer as no flag, so drop it
from the renderer table (and the HOSTING.md shipped in the web archive).
Fixes#126.
Co-authored-by: lloyd <lloyd@stackworx.io>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
The DMG opened as a plain Finder window. It now shows the app icon's figure on
the WordCraft colour, with WordCraft.app and the Applications link side by side.
Same approach as PhotoCraft's and VectorCraft's (storytold/photocraft#1201,
storytold/vectorcraft#493).
- packaging/macos/dmg/: background.svg (source; text outlined, no paper grain,
the figure an <image> of assets/app-icon), background.tiff (1x + 2x HiDPI,
16-colour palette, Deflate, sRGB; ~23 KB)
and dmg-layout.DS_Store (Finder view settings: window, icon size 128,
positions, background).
- generate.py writes the TIFF and the layout on any OS, byte-for-byte
reproducible, with nothing from the machine that ran it (no paths, users,
disk names or volume UUIDs).
- package.sh copies them into the staging folder; the image is still built with
hdiutil makehybrid. Nothing extra runs in the signing job.
- The volume name drops the version: the layout finds the background through
an alias that includes the volume name. The DMG file name keeps the version.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
wordcraft.wxs shipped with DesignCraft's UpgradeCode and app component
GUID. Windows Installer treats packages that share an UpgradeCode as one
product, so with DesignCraft 0.2.1 installed the WordCraft 0.1.0 MSI was a
"downgrade" and refused to install ("A newer version of WordCraft is
already installed"), and installing DesignCraft after WordCraft would have
removed WordCraft.
Give WordCraft fresh GUIDs, drop the header comment copied from PhotoCraft,
and make packaging-lint fail if the .wxs reuses a sibling Craft app's
UpgradeCode/component GUID or repeats a GUID.
Fixes#4.
Claude-Session: https://claude.ai/code/session_019FczntrDNYd6DupyBdpbL5
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Also fix the .deb/.rpm description in packaging/linux/nfpm.yaml, which still described PhotoCraft.
Co-authored-by: Brandon Thomas <shared2@storyteller.ai>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
- packaging/linux/package.sh: embed gh-releases-zsync update information in each AppImage
(appimagetool -u) and write the .zsync beside it; the Linux job installs zsync and checks both.
- New flatpak job (x86_64 on ubuntu-24.04, aarch64 on ubuntu-24.04-arm) repackages the Linux
tarball with packaging/linux/flatpak-bundle.sh and ai.storyteller.wordcraft.bundle.yml; no Rust
build, no release environment. The release job needs it.
- version, Linux and web jobs drop `environment: release` (they sign nothing), so a branch
workflow_dispatch dry-runs every unsigned job; the release job still needs the signed jobs.
- FreeBSD release build embeds craft-fonts like the other desktop builds and ships its licences.
- Flathub manifest: same finish-args as the bundle (adds xdg-documents), builds the CLI too;
packaging-lint checks both manifests agree.
- README: Downloads section; docs/releasing.md updated.
Co-authored-by: Brandon Thomas <shared2@storyteller.ai>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>