Commit Graph
1933 Commits
Author SHA1 Message Date
aiongg 9a51627cc2 Merge 178 open PRs (backlog round 1) (storytold/wordcraft#3555)
Integrates the backlog round's ready set from aiongg:next.
2026-10-22 00:24:38 -04:00
aiongg 0712924629 Merge PR storytold/wordcraft#1761: Hyphenation: German text follows the German patterns
crates/proof/src/lang.rs: main's English-dialect helpers kept; code() doc lists `de`.
crates/proof/src/lib.rs: hostile-input test loops over main's languages plus De.
crates/ui-egui/src/options.rs: language_name maps EnGb/EnCa and De to no dictionary name.
ROADMAP.md: main's status lines; both progress-log and revision rows kept.
docs/gaps.md: main's status line; gap 8 row is main's with German hyphenation added; revision rows unioned.
docs/layout-parity.md: main's status line, Tabs and Drop caps rows; the PR's Hyphenation row; revision rows unioned.
docs/localization-parity.md: main's status line; revision rows unioned.
2026-10-22 01:20:31 +00:00
aiongg 2c1ac35c64 Merge PR storytold/wordcraft#3252: Russian and Czech dictionaries are reported, not just checked (storytold/wordcraft#3226) 2026-10-22 01:19:47 +00:00
aiongg 27d89300a6 Merge PR storytold/wordcraft#2164: proof: emoji flags followed by U+FE0F load (RLA-ES Spanish) 2026-10-22 01:19:47 +00:00
Dylan M. Taylor 1b9cf1973a ci: pin GitHub Actions to full commit SHA (SonarCloud githubactions:S7637) (#228)
Pin third-party actions to full-length commit SHAs (with version comments)
instead of mutable tags/branches to prevent supply-chain tampering via
retagged releases. Resolves SonarCloud rule githubactions:S7637.
2026-10-21 20:14:01 -04:00
0034538d4d storytold/wordcraft#1281: English dialects in proofing — en-GB, en-CA, en-AU… flag each other's spellings (storytold/wordcraft#1045) (storytold/wordcraft#2632)
* storytold/wordcraft#1281: English dialects in proofing — en-GB, en-CA, en-AU… flag each other's spellings (storytold/wordcraft#1045)

English was one proofing language: en-GB, en-CA and en-AU all proofed like
US English, and US documents accepted British spellings. Now ProofLang has
three Englishes, picked by the tag's region:

- En (en-US, other regions, no language): British spellings flagged
  (colour → color).
- EnGb (en-GB, en-AU, en-NZ, en-IE, en-ZA, en-IN…): American spellings
  flagged (color → colour, center → centre, analyze → analyse); -ize and
  -ise both right (Oxford spelling).
- EnCa (en-CA): British -our/-re/-ence, American -ize, tire, program.

Data: assets/spelling/en-variants.txt, our own ~280 American/British
pairs with a policy per English (MIT OR Apache-2.0, ATTRIBUTION.md row).
Inflections by rule (crates/proof/src/en_variants.rs). A dialect's form
is right when the shared list knows it or its other spelling, so
"realisation" is right in en-GB. No system dictionary needed.

Suggestions put the dialect's own form first. Review › Language lists
English (Australia) and (Canada); the Language dialog adds India,
Ireland, New Zealand and South Africa (names in every catalog, not
native-reviewed). An English interface on an en-GB/en-CA/en-AU… region
writes new documents in that English. Options › Language shows the
document's language instead of a fixed "English (United States)".

Tests: per-dialect accept/flag/suggest, tag mapping, no-panic proptests,
engine end to end through review.language, DOCX w:lang round trip,
region-based editing language, language menu.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P8veLveuUsJJm6UEcQPEuW

* storytold/wordcraft#1281: review — pin the storytold/wordcraft#40 words (judgement, defence, licence, programme, catalogue) in en-GB and en-US

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012WEhZXSxzS8orX7f9J3qpr

* storytold/wordcraft#1281: review — harness picks every proofing language in Review › Language and checks it is ticked

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012WEhZXSxzS8orX7f9J3qpr

* storytold/wordcraft#1281: review — pin more British spellings in en-GB (goitre, sceptre, enrol, fulfil, instalment, skilful, wilful, encyclopaedia…)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012WEhZXSxzS8orX7f9J3qpr

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-authored-by: aiongg <aiongtaigi@gmail.com>
2026-10-21 19:52:57 -04:00
dmim2502-commitsandClaude Opus 5.5 08d69d5fd0 proof: drop U+FE0F from FORBIDDENWORD and NOSUGGEST flags too
Review follow-up: the directives that name one flag read the same emoji
form, so they now skip the variation selector like PFX/SFX and stem flags.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 16:21:24 -05:00
Dylan M. Taylor e25b6ec6e6 security: validate CLI paths/args in dev tools (SonarCloud S2083/S8707/S8705/S7044)
Resolve and validate command-line path arguments before use, enforce HTTPS at
download sinks, and confirm path containment. Hardens local codegen/fetch tools
against path-traversal and command-argument-injection findings.
2026-10-21 17:12:54 -04:00
Dylan M. Taylor ce89625521 ci: add sonar-project.properties for CI-based analysis
Marks the project ineligible for SonarCloud Automatic Analysis, resolving the
CI-vs-automatic-analysis conflict so the SonarCloud workflow succeeds.
2026-10-21 16:00:28 -04:00
Dylan M. Taylor 20b2c1a1eb ci: add SonarCloud scan via shared reusable workflow
Calls storytold/craft-common-actions/.github/workflows/sonarcloud.yml@main
with secrets: inherit. Adds SonarCloud badge to README where missing and
removes the redundant sonar-project.properties (config now passed by the
reusable workflow).
2026-10-21 15:46:51 -04:00
aiongg b43a39df65 keymap ui: the failed-change test sets the import's truncated count 2026-10-21 18:14:58 +00:00
aiongg 3c8c3309a0 Merge branch 'craft-keymap' into keymap-ui 2026-10-21 18:14:23 +00:00
aiongg 8ce872938f keymap: a failed import change keeps its shortcuts when a later change frees room
The cleanup after an import could remove a chord from a command whose own change had failed, once a later change freed an overrides entry. That command now keeps its bindings, and the change that would have taken its chord is dropped and reported, as when the removal itself fails.
2026-10-21 18:14:21 +00:00
aiongg 315af428c7 keymap: a key whose Latin layout character is no letter runs no letter binding
The suite's egui reports, per key pressed, the character it types on the
Latin layout shortcuts follow (InputState::latin_layout_char). A letter
makes the press that letter; any other character means the key has no
Latin letter, so egui's position fallback no longer turns it into one: on
Dvorak + Russian the key that types й is Dvorak's ', not Ctrl+Q. Without a
report (crates.io egui) the key's position still decides.
2026-10-21 18:05:18 +00:00
aiongg 971127f61f craft-fonts-build: document fonts are a named list (Embed::documents); Embed::new leaves out the interface faces' sources
Embed::documents embeds only the families an app names, whole, and an
unknown name is Error::UnknownFamilies listing the manifest's families.
Embed::embedded_elsewhere lets check_text and the catalog check count
faces another table embeds. EmbeddedFace::is_cjk. The embed() shorthand,
which embedded every face, is gone.
2026-10-21 17:53:15 +00:00
dmim2502-commitsandClaude Opus 5.5 11a455cf24 proof: emoji flags followed by U+FE0F load (RLA-ES Spanish)
RLA-ES, the Spanish Hunspell dictionaries in LibreOffice and most Linux
distributions, writes one flag as U+260E followed by U+FE0F, in the rules
(PFX ☎️ Y 3) and on stems (banco/S☎️). parse_aff rejected it as "not one
character", so the whole dictionary failed to load. The variation selector
is now dropped wherever flags are read, with a regression test.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 12:27:06 -05:00
aiongg cec769a889 keymap: on layouts that are not Latin, take the letter the toolkit reports
The suite's egui-winit reports a letter key on a layout that is not Latin
as the Latin layout's letter, so on Dvorak + Russian the с key is
Dvorak's J. resolve takes that letter before the key's position; with
crates.io egui the letter is the position, as before.
2026-10-21 17:23:16 +00:00
aiongg 7143c25157 i18n: contain values that carry bidi controls
A value with an embedding, override, isolate or mark (LRE RLE PDF LRO
RLO LRI RLI FSI PDI LRM RLM ALM) makes fmt isolate, even in text with no
right-to-left letter, so an ASCII file name with an RLO can't reorder
the sentence. Embeddings, overrides and isolates a value opens are
closed inside its isolate, and stray PDF and PDI are dropped.
2026-10-21 17:20:34 +00:00
aiongg 958c5ada58 docking: the Frame profile's drop hint says undock, as its menus do 2026-10-21 16:46:50 +00:00
aiongg 7d786e5108 docking: the Frame profile drop preview says which key floats
While a drag offers a docking target, a hint under the pointer reads
"Hold Ctrl to float" ("Hold ⌘ to float" on macOS), from the
localizable float_hint_label (key dock.floatHint).
2026-10-21 16:45:29 +00:00
aiongg 899807ff19 docking: a split beside a fixed-size frame keeps that frame's size
A side split replaced the anchor frame in place, so a split beside a
fixed-width frame such as a tool strip took the frame's fixed slot:
the two frames shared its width, and the parent's divider resized both.
The frame now keeps its size: on its outer side the new split wraps the
parent, on its inner side it halves the parent's other child. The drop
preview shows the half the new frame takes.
2026-10-21 16:44:06 +00:00
aiongg 40c59bb577 docking: narrow frames keep usable side drop zones, and seams split
A side zone is a quarter of the frame deep, at least 32 pt and at most
half the frame, so a 64 pt tool strip offers its left and right edges
past the outer edge band. A pointer in the gap between frames resolves
to the nearest frame's edge instead of floating.
2026-10-21 16:40:59 +00:00
aiongg 2fa4ad79d7 docking: floating windows stay inside the app's float bounds
DockArea::float_bounds sets where floating windows, flyouts and drag ghosts may go; the default is the whole viewport. An app with its own title bar under a transparent macOS title bar passes the viewport below it, so a floating window can't be dropped, dragged or restored where pressing it moves the app window.
2026-10-21 16:19:25 +00:00
aiongg a414736c67 craft-fonts-build: subset_to cuts the role ui faces to the catalogs' characters at build time
The interface faces in craft-fonts are full Regular TrueType sources. With the
subset feature (build-dependencies only), Embed::subset_to cuts each one with
skera to the catalogs' characters from U+2E80 up plus CJK punctuation, kana and
full-width forms, keeping every layout feature, and embeds the cut from OUT_DIR.
for_ui without catalogs leaves the interface faces out with a warning; a CFF
interface face is an error. check_text and the catalogs warn only about
characters no embedded face covers.
2026-10-21 13:31:26 +00:00
aiongg 1a8573d523 craft-fonts-build: for_ui embeds CJK faces as their UI subsets; check_text warns about characters no face covers
The manifest's optional ninth field, role, marks the UI subsets (ui). check_text reads
the selected faces' cmaps (formats 4 and 12) with a small reader, so the crate keeps
no dependencies.
2026-10-21 12:45:51 +00:00
Dylan M. Taylor 1f805378d4 feat(window): shared craft-window crate for consistent window decorations (#217)
* feat(window): shared crate deciding who draws the window frame

Add craft-window, which decides whether the desktop or the app draws the
window frame (titlebar, borders, window buttons) and applies it to an
egui ViewportBuilder. This fixes the drift where some Craft apps drew
their own titlebar on KDE while others kept KWin's.

The rule: macOS, Windows and X11 keep the desktop frame; a Wayland
compositor with zxdg_decoration_manager_v1 (KDE, Sway, Hyprland, COSMIC)
keeps its frame; one without it (GNOME) leaves the frame to the app.
<PREFIX>_TITLEBAR=app|system|desktop overrides. When the app draws the
frame, the decision carries the window-button Layout from GNOME's
button-layout so the app's header bar matches the desktop's order.

Decision logic only; drawing the buttons stays in each app. Extracted and
generalized from pdfcraft's decorations.rs. forbid(unsafe_code); default
build has no egui dependency (egui feature adds decorate()).

* style(window): rustfmt the Wayland probe and Dispatch impl

cargo fmt --check failed CI: collapse the thread-spawn builder chain and
the Dispatch::event signature onto the lines rustfmt wants (verified with
rustfmt 1.98 against the workspace rustfmt.toml).

* fix(window): address review — WAYLAND_SOCKET, bounded gsettings, checkout creds

- Skip the Wayland probe when WAYLAND_SOCKET is set: connect_to_env would
  take ownership of the inherited fd and unset the variable, closing the
  descriptor winit needs. Keep the desktop frame instead.
- Run the gsettings button-layout lookup behind the same 500 ms bounded
  worker as the Wayland probe, so a stalled gsettings can't block startup.
  Factored the worker into a shared bounded() helper.
- window.yml: set persist-credentials: false on checkout so the token
  isn't left in .git/config while cargo runs dependency build scripts.
- README: document the socket guard and the bounded gsettings lookup.

Verified with rustfmt 1.98 and clippy -D warnings (both feature sets).

* fix(window): reap the gsettings child on timeout; document probe tradeoffs

Follow-up to review: the button-layout lookup now spawns gsettings with
piped output, reads it on a worker, and kills+reaps the child whether it
finishes or times out — so a stalled gsettings leaves neither a blocked
process nor a parked worker (it is a one-shot startup call).

Also document, on the Wayland probe, that an inherited WAYLAND_SOCKET
(rare; normal launches get WAYLAND_DISPLAY) deliberately falls back to the
desktop frame to protect winit's connection — the same frame an app that
doesn't probe would get, a safe default rather than a regression.

Verified: rustfmt 1.98 clean, clippy -D warnings clean (default + egui),
tests pass.
2026-10-21 05:35:20 -04:00
aiongg cdc3b45496 keymap: take whether the layout is Latin from egui when it reports it
The suite's egui reports it from egui-winit on Linux. A report sets the
layout's Latin-ness; frames without one keep learning from typing. On
crates.io egui a private fallback trait reports nothing.
2026-10-21 06:57:03 +00:00
aiongg ed0f6f611c craft-fonts-build: CRAFT_FONTS_REQUIRED applies only when it is exactly 1 2026-10-21 06:18:24 +00:00
aiongg aaec0e1e5f i18n: Format::number_ungrouped for pixel sizes and years 2026-10-21 06:18:21 +00:00
aiongg b37040cb93 Add craft-fonts-build: embed craft-fonts faces from an app's build.rs 2026-10-21 06:16:08 +00:00
aiongg 2ff3f11654 i18n: base_direction of a paragraph from its first strong character 2026-10-21 06:13:49 +00:00
aiongg 1a0e7e7bbf keymap: learn nothing from presses while right Alt is held
egui-winit reports AltGr with neither Ctrl nor Alt, so AltGr text read as plain
typing: German AltGr+M (µ) marked the layout as not Latin and Ctrl+Z resolved
by position as Ctrl+Y. µ, ª and º no longer count as a sign of another script.
2026-10-21 06:08:30 +00:00
aiongg 365f7672b5 i18n: don't match part of a Hangul syllable 2026-10-21 06:07:40 +00:00
aiongg 61db8b71b5 i18n: break collation ties by code point 2026-10-21 06:07:40 +00:00
aiongg 188c313c69 Merge remote-tracking branch 'origin/i18n-format' into i18n-parse-number 2026-10-21 06:07:18 +00:00
aiongg 540dafb9c3 i18n: generate.sh keeps locales.rs when locales.py fails 2026-10-21 06:07:07 +00:00
aiongg 9b4c4350b6 Merge remote-tracking branch 'origin/i18n-region' into i18n-format 2026-10-21 06:07:02 +00:00
aiongg c9013e08c7 i18n: Hani and yue-Hant pick Han forms by region; usual scripts for kk, ky, tg, ku, ms, ug 2026-10-21 06:06:51 +00:00
aiongg 31b5f953ee i18n: plain wording for where Region separators come from 2026-10-21 06:06:44 +00:00
aiongg b7d5394802 i18n: a grouping dot stays grouping beside a system decimal mark 2026-10-21 06:06:29 +00:00
aiongg 56bbf840a7 i18n: strip every isolate mark in fmt_plain 2026-10-21 06:06:08 +00:00
aiongg 502f799716 i18n: han and catalog matching follow region-implied scripts
han(zh-US), zh-AU and the other regions CLDR writes in Traditional
characters give Traditional, and pa-PK picks a pa-arab catalog, never
Gurmukhi pa, as pa-Arab-PK does.
2026-10-21 05:54:12 +00:00
aiongg b010389df2 i18n: Format::parse on the format's own marks; lone decimal marks
Format::parse reads what a Format writes: its digits, its decimal and
grouping separators (the system's included) and the locale's Latin
marks in an Arabic-Indic format, plus every digit set. parse_number is
Format::from_tag(locale).parse, so the decimal marks come from CLDR's
data alone and the hand-made table is gone.

A lone . in a comma locale is the decimal mark when it can't be
grouping (1.5, 0.250, 1234.5, .5); 1.234 and 1.234.567 stay grouped in
German. The same holds for , in a point locale. Percent signs and units
are documented as the caller's to strip.
2026-10-21 05:54:08 +00:00
aiongg 217f108ee0 Merge remote-tracking branch 'origin/i18n-format' into i18n-parse-number
# Conflicts:
#	crates/i18n/src/lib.rs
2026-10-21 05:54:08 +00:00
aiongg 9d636cf6cb Merge remote-tracking branch 'origin/i18n-file-size' into i18n-format
# Conflicts:
#	crates/i18n/src/size.rs
2026-10-21 05:50:09 +00:00
aiongg a89bf84e58 Merge remote-tracking branch 'origin/i18n-region' into i18n-format 2026-10-21 05:49:51 +00:00
aiongg f2ab6dc7f3 i18n: rewrap the Region README paragraph 2026-10-21 05:49:46 +00:00
aiongg 9c75eda598 keymap: block the position fallback only at positions seen typing something else
AZERTY's Ctrl+Shift+E works before an e has been typed.
2026-10-21 05:49:41 +00:00
aiongg 233e0b7aa0 i18n: plural rules by language, CLDR data for every locale, trn_plain
Plural rules are looked up by language alone: CLDR's parent of sr-Latn
and zh-Hant is the root, whose only category is other, so sr-latn rows
were rejected. The baked data covers every CLDR locale (10 KB): plural
rules for he, ro, nb, ca, sk, th, ms and the rest, and decimal symbols
for nb-NO, sk-SK, bn-BD, ar-MA and English in Europe. Format applies a
Region's separators only where the system set them, and an empty
grouping separator writes none.

trn_plain writes counts in 0-9 without grouping, for documents and file
names. reset_format goes back to the system region. trn_decimal and
Format write infinities and NaN as CLDR does and take the other form.
Tests that don't set a format use en-US, not the machine's region. The
ICU4X crates are pinned to ~2.3, the minor version the data is for.
2026-10-21 05:49:38 +00:00
aiongg d0acf36588 keymap: Shift presses egui reports as their position run nothing on moved layouts
Dvorak's ⇧, types <, which egui has no key for, so egui reports the
press as W and Ctrl+Shift+, ran Ctrl+Shift+W. Once typing shows the
layout's letters are not on QWERTY positions, such a press resolves to
nothing unless the position is known to type its own letter.
2026-10-21 05:47:51 +00:00