mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-24 09:46:59 -06:00
Merge pull request #3433 from dotCooCoo/fix/tabs-ruler-sets-whole-points
Tabs: a stop placed or moved on the ruler lands on a whole point
This commit is contained in:
+6
-3
@@ -25,8 +25,9 @@ vectorcraft-doc = { path = "crates/doc" }
|
||||
vectorcraft-pathops = { path = "crates/pathops" }
|
||||
vectorcraft-brush = { path = "crates/brush" }
|
||||
vectorcraft-trace = { path = "crates/trace" }
|
||||
# Without its default `bundled-fonts`: the engine turns them on (its own default feature), so a
|
||||
# library crate never forces them on an embedder that supplies its fonts at run time.
|
||||
# Without its default `bundled-fonts`: a crate that wants the fonts asks for them (the apps and
|
||||
# vectorcraft-testkit through the engine's `bundled-fonts`), so a library crate never forces them on
|
||||
# an embedder that supplies its fonts at run time.
|
||||
vectorcraft-text = { path = "crates/text", default-features = false }
|
||||
vectorcraft-effects = { path = "crates/effects" }
|
||||
vectorcraft-three-d = { path = "crates/three-d" }
|
||||
@@ -35,7 +36,9 @@ vectorcraft-svg = { path = "crates/svg" }
|
||||
vectorcraft-pdf = { path = "crates/pdf" }
|
||||
vectorcraft-format = { path = "crates/format" }
|
||||
vectorcraft-tools = { path = "crates/tools" }
|
||||
vectorcraft-engine = { path = "crates/engine" }
|
||||
# Without its default `bundled-fonts`, as vectorcraft-text: each crate that wants the fonts asks for
|
||||
# them, so an embedder can build without them (docs/development.md › Leaving out the bundled fonts).
|
||||
vectorcraft-engine = { path = "crates/engine", default-features = false }
|
||||
vectorcraft-ui-egui = { path = "crates/ui-egui" }
|
||||
vectorcraft-mcp = { path = "crates/mcp" }
|
||||
vectorcraft-testkit = { path = "crates/testkit" }
|
||||
|
||||
@@ -16,7 +16,7 @@ workspace = true
|
||||
[dependencies]
|
||||
vectorcraft-color = { workspace = true }
|
||||
vectorcraft-doc = { workspace = true }
|
||||
vectorcraft-engine = { workspace = true }
|
||||
vectorcraft-engine = { workspace = true, features = ["bundled-fonts"] }
|
||||
vectorcraft-format = { workspace = true }
|
||||
vectorcraft-geom = { workspace = true }
|
||||
vectorcraft-svg = { workspace = true }
|
||||
|
||||
@@ -14,7 +14,7 @@ name = "vectorcraft-web"
|
||||
path = "src/main.rs"
|
||||
|
||||
[dependencies]
|
||||
vectorcraft-engine = { workspace = true }
|
||||
vectorcraft-engine = { workspace = true, features = ["bundled-fonts"] }
|
||||
vectorcraft-ui-egui = { workspace = true }
|
||||
vectorcraft-format = { workspace = true }
|
||||
vectorcraft-text = { workspace = true }
|
||||
|
||||
@@ -17,7 +17,7 @@ accessibility = ["eframe/accesskit"]
|
||||
windows7 = ["eframe/glow"]
|
||||
|
||||
[dependencies]
|
||||
vectorcraft-engine = { workspace = true }
|
||||
vectorcraft-engine = { workspace = true, features = ["bundled-fonts"] }
|
||||
vectorcraft-ui-egui = { workspace = true }
|
||||
vectorcraft-text = { workspace = true }
|
||||
# Shared across the Craft suite: decides who draws the window frame per desktop (compositor vs app)
|
||||
|
||||
@@ -8,6 +8,12 @@ description = "VectorCraft MCP server: JSON-RPC 2.0 over stdio, driving a runnin
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[features]
|
||||
default = ["bundled-fonts"]
|
||||
# The fonts vectorcraft-text bundles for documents, through the engine's `bundled-fonts`, as
|
||||
# vectorcraft-ui-egui's. Off, for an embedder that supplies every document font at run time.
|
||||
bundled-fonts = ["vectorcraft-engine/bundled-fonts"]
|
||||
|
||||
[dependencies]
|
||||
vectorcraft-engine = { workspace = true }
|
||||
vectorcraft-render = { workspace = true }
|
||||
|
||||
@@ -13,7 +13,7 @@ workspace = true
|
||||
vectorcraft-geom = { workspace = true }
|
||||
vectorcraft-color = { workspace = true }
|
||||
vectorcraft-doc = { workspace = true }
|
||||
vectorcraft-engine = { workspace = true }
|
||||
vectorcraft-engine = { workspace = true, features = ["bundled-fonts"] }
|
||||
vectorcraft-render = { workspace = true }
|
||||
vectorcraft-format = { workspace = true }
|
||||
vectorcraft-svg = { workspace = true }
|
||||
|
||||
@@ -37,7 +37,8 @@ default = ["bundled-fonts"]
|
||||
# The OFL fonts of `assets/fonts` (Source Sans 3, Source Serif 4, Inter, JetBrains Mono) compiled
|
||||
# in: 3.4 MB of the binary. Off, the font database starts without them (craft-fonts and system
|
||||
# fonts are unaffected), for an embedder that adds its own with `FontDb::add_font` and would ship
|
||||
# these twice. vectorcraft-engine turns it on by default (its `bundled-fonts` feature).
|
||||
# these twice. vectorcraft-engine turns it on by default (its `bundled-fonts` feature), and
|
||||
# vectorcraft-ui-egui and vectorcraft-mcp by default through the engine.
|
||||
bundled-fonts = []
|
||||
# `vectorcraft_text::test_fonts` for other crates' tests (dev-dependencies only).
|
||||
test-fonts = ["dep:write-fonts"]
|
||||
|
||||
@@ -8,6 +8,13 @@ description = "VectorCraft egui frontend (menus, panels, tools and canvas); swap
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[features]
|
||||
default = ["bundled-fonts"]
|
||||
# The fonts vectorcraft-text bundles for documents, through the engine's `bundled-fonts`. Off, for
|
||||
# an embedder that supplies every document font at run time (`vectorcraft_text::FontDb::add_font`);
|
||||
# the interface's own faces are separate copies in theme.rs and stay either way.
|
||||
bundled-fonts = ["vectorcraft-engine/bundled-fonts"]
|
||||
|
||||
[dependencies]
|
||||
craft-ui = { workspace = true }
|
||||
vectorcraft-geom = { workspace = true }
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//! Tabs panel: tab-stop alignment, X position (Y in vertical type), leader and "align on", and a
|
||||
//! ruler numbered in the General unit on which a click adds a stop, dragging moves one and dragging
|
||||
//! it off the ruler deletes it. With Snap to Unit on, or Shift held, a stop placed or dragged on the
|
||||
//! ruler lands on the ruler's nearest tick.
|
||||
//! it off the ruler deletes it. A stop placed or dragged on the ruler lands on the nearest whole
|
||||
//! point. With Snap to Unit on, or Shift held, it lands on the ruler's nearest tick.
|
||||
|
||||
use egui::{Sense, Stroke, Ui, vec2};
|
||||
use serde_json::{Value, json};
|
||||
@@ -225,9 +225,10 @@ pub fn show(app: &mut VectorcraftApp, ui: &mut Ui) {
|
||||
);
|
||||
}
|
||||
}
|
||||
// Snap to Unit, or Shift held: a stop placed or dragged on the ruler lands on its nearest tick.
|
||||
// A stop placed or dragged on the ruler lands on the nearest whole point. With Snap to Unit on,
|
||||
// or Shift held, it lands on the ruler's nearest tick, which can be a fraction of a point.
|
||||
let snap = pstate::<bool>(ui.ctx(), "tabs-snap") || ui.input(|i| i.modifiers.shift);
|
||||
let place = |x: f32| if snap { unit.snap_to_ruler_tick(to_pt(x), scale).max(0.0) } else { to_pt(x) };
|
||||
let place = |x: f32| if snap { unit.snap_to_ruler_tick(to_pt(x), scale).max(0.0) } else { to_pt(x).round() };
|
||||
for (i, s) in stops.iter().enumerate() {
|
||||
let x = to_x(s.position);
|
||||
let c = if i == sel { t.accent } else { t.text };
|
||||
@@ -278,7 +279,8 @@ pub fn show(app: &mut VectorcraftApp, ui: &mut Ui) {
|
||||
Some(i) => set_pstate(ui.ctx(), "tabs-sel", i),
|
||||
None => {
|
||||
let position = place(pos.x);
|
||||
// A snapped click onto a stop's tick selects that stop and records no undo step.
|
||||
// A click that lands on a stop's whole point or tick selects that stop and records no
|
||||
// undo step.
|
||||
let added = !stops.iter().any(|s| s.position == position);
|
||||
if added {
|
||||
stops.push(TabStop { position, align: ALIGNS[align_idx.min(3)].0, leader: String::new(), align_on: '.' });
|
||||
@@ -617,15 +619,15 @@ mod tests {
|
||||
drag_on_ruler(&ctx, &mut app, 33.4, 33.4, false);
|
||||
assert_eq!(positions(&app), [15.0, 35.0]);
|
||||
assert_eq!(row(&mut app).0, "✓ Snap to Unit");
|
||||
// Chosen again, Snap to Unit turns off and the stop stays where it is dropped.
|
||||
// Chosen again, Snap to Unit turns off and the stop lands on the whole point nearest where it
|
||||
// is dropped.
|
||||
let at = row(&mut app).1.center();
|
||||
let button = |pressed| egui::Event::PointerButton { pos: at, button: egui::PointerButton::Primary, pressed, modifiers: Default::default() };
|
||||
menu_frame(&ctx, &mut app, vec![egui::Event::PointerMoved(at), button(true)]);
|
||||
menu_frame(&ctx, &mut app, vec![button(false)]);
|
||||
assert_eq!(row(&mut app).0.trim_start(), "Snap to Unit");
|
||||
drag_on_ruler(&ctx, &mut app, 35.0, 23.4, false);
|
||||
let p = positions(&app);
|
||||
assert!((p[1] - 23.4).abs() < 1.0 && p[1] != 25.0, "{p:?}");
|
||||
assert_eq!(positions(&app), [15.0, 23.0]);
|
||||
}
|
||||
|
||||
/// A snapped click more than 5 px from a stop, nearest to the tick that stop is on, selects the
|
||||
@@ -710,6 +712,38 @@ mod tests {
|
||||
assert!(texts.iter().any(|(t, _)| *t == shown), "{shown} in {texts:?}");
|
||||
}
|
||||
|
||||
/// A stop placed by a click on the ruler or dragged on it lands on the nearest whole point, and
|
||||
/// the moved stop stays selected. A position typed in the X field keeps its hundredths of a point.
|
||||
#[test]
|
||||
fn the_ruler_places_and_moves_stops_on_whole_points() {
|
||||
let mut app = VectorcraftApp::new(Session::new(), Default::default());
|
||||
app.session.execute("file.new", &json!({})).unwrap();
|
||||
app.session.execute("text.create", &json!({"x": 10, "y": 20, "text": "a b", "area": {"width": 300, "height": 100}})).unwrap();
|
||||
app.session.execute("text.tabs.set", &json!({"stops": [{"position": 50}]})).unwrap();
|
||||
let ctx = egui::Context::default();
|
||||
let positions = |app: &VectorcraftApp| current(app).unwrap().1.iter().map(|s| s.position).collect::<Vec<_>>();
|
||||
// A click at 33.4 pt adds a stop at 33 pt and selects it.
|
||||
drag_on_ruler(&ctx, &mut app, 33.4, 33.4, false);
|
||||
assert_eq!(positions(&app), [33.0, 50.0]);
|
||||
assert_eq!(pstate::<usize>(&ctx, "tabs-sel"), 0);
|
||||
// The stop at 50 pt dragged to 13.6 pt lands on 14 pt, left of the stop at 33 pt, and stays selected.
|
||||
drag_on_ruler(&ctx, &mut app, 50.0, 13.6, false);
|
||||
assert_eq!(positions(&app), [14.0, 33.0]);
|
||||
assert_eq!(pstate::<usize>(&ctx, "tabs-sel"), 0);
|
||||
// 13.47 typed in the X field keeps its hundredths.
|
||||
let texts = panel_frame(&ctx, &mut app, vec![]);
|
||||
let at = texts.iter().find(|(t, _)| t == "14 pt").unwrap_or_else(|| panic!("14 pt in {texts:?}")).1.center();
|
||||
let button = |pressed| egui::Event::PointerButton { pos: at, button: egui::PointerButton::Primary, pressed, modifiers: Default::default() };
|
||||
let key = |key, modifiers| egui::Event::Key { key, physical_key: None, pressed: true, repeat: false, modifiers };
|
||||
panel_frame(&ctx, &mut app, vec![egui::Event::PointerMoved(at), button(true)]);
|
||||
panel_frame(&ctx, &mut app, vec![button(false)]);
|
||||
panel_frame(&ctx, &mut app, vec![key(egui::Key::A, egui::Modifiers::COMMAND)]);
|
||||
panel_frame(&ctx, &mut app, vec![egui::Event::Text("13.47".into())]);
|
||||
panel_frame(&ctx, &mut app, vec![key(egui::Key::Enter, egui::Modifiers::NONE)]);
|
||||
assert_eq!(positions(&app), [13.47, 33.0]);
|
||||
assert_eq!(pstate::<usize>(&ctx, "tabs-sel"), 0);
|
||||
}
|
||||
|
||||
/// An X typed past the next stop keeps the stop selected once the stops are sorted. An X the
|
||||
/// stops cannot take (past 100,000 pt) leaves the stops and the selection as they were.
|
||||
#[test]
|
||||
|
||||
+19
-4
@@ -1,5 +1,6 @@
|
||||
# Development
|
||||
|
||||
> **Last updated:** 2026-10-21 · **Change:** leaving out the bundled fonts with the egui panels (vectorcraft-ui-egui's and vectorcraft-mcp's `bundled-fonts` features).
|
||||
> **Last updated:** 2026-10-14 · **Change:** leaving out the bundled fonts (`bundled-fonts` feature).
|
||||
> **Last updated:** 2026-10-14 · **Change:** document-font registration for all explicitly supplied faces.
|
||||
|
||||
@@ -160,15 +161,28 @@ CRAFT_FONTS_DIR="$PWD/../craft-fonts" cargo xtask ci # also runs the Japanese-
|
||||
|
||||
The Latin fonts in `assets/fonts/` are compiled into `vectorcraft-text` by its `bundled-fonts`
|
||||
feature (3.4 MB of the binary). It is on by default, and `vectorcraft-engine`'s default
|
||||
`bundled-fonts` feature turns it on, so the apps and anything built on the engine have them. An
|
||||
`bundled-fonts` feature turns it on, so the apps and anything built on the engine with its default
|
||||
features have them. An
|
||||
embedder that brings every font itself at run time (`FontDb::add_font`, say a web app serving its
|
||||
own font catalogue) depends on the engine with `default-features = false` and doesn't ship them
|
||||
twice. Its font database starts without them: on the web and without craft-fonts it starts empty,
|
||||
and text has no glyphs until a font is added.
|
||||
|
||||
- The workspace declares `vectorcraft-text` without default features, so no library crate turns the
|
||||
fonts back on; a crate whose tests lay type out asks for `bundled-fonts` in its
|
||||
dev-dependencies (or gets it through `vectorcraft-testkit`, which uses the engine).
|
||||
An embedder that also hosts the egui panels depends on `vectorcraft-ui-egui` with
|
||||
`default-features = false` as well: its own `bundled-fonts` feature, on by default, turns the
|
||||
engine's on; `vectorcraft-mcp` has the same feature. The panels' interface faces (Source Sans 3
|
||||
Regular and Semibold, Inter Regular and SemiBold, JetBrains Mono) are separate copies in
|
||||
`theme.rs` and stay either way.
|
||||
|
||||
- The workspace declares `vectorcraft-text` and `vectorcraft-engine` without default features, so
|
||||
each crate that wants the fonts asks for them (the apps, and `vectorcraft-testkit` for tests);
|
||||
a crate whose tests lay type out asks for `bundled-fonts` in its dev-dependencies (or gets it
|
||||
through `vectorcraft-testkit`).
|
||||
- `cargo xtask ci`'s `no-bundled-fonts` step also checks that `vectorcraft-ui-egui` and
|
||||
`vectorcraft-mcp` without their default features turn them on nowhere, for any target
|
||||
(`cargo tree -p vectorcraft-ui-egui --no-default-features --target all -e features,normal -i
|
||||
vectorcraft-text`, and the same for `vectorcraft-mcp`), and with them do; a test of either can't
|
||||
see that configuration, since their dev-dependencies turn the fonts on.
|
||||
- `cargo test -p vectorcraft-text --no-default-features --test without_bundled_fonts` checks the
|
||||
configuration without them.
|
||||
|
||||
@@ -375,6 +389,7 @@ do not replace expected hashes automatically in response to a download mismatch.
|
||||
|
||||
| Date | Change | Summary |
|
||||
|---|---|---|
|
||||
| 2026-10-21 | minor | Fonts › Leaving out the bundled fonts: vectorcraft-ui-egui's and vectorcraft-mcp's `bundled-fonts` features, and the engine declared without default features. |
|
||||
| 2026-10-14 | minor | Document the `bundled-fonts` feature of vectorcraft-text and vectorcraft-engine (Fonts › Leaving out the bundled fonts). |
|
||||
| 2026-10-14 | minor | Document registration of every explicitly supplied craft-fonts face after the existing script-specific prefix; empty input and web selection remain unchanged. |
|
||||
| 2026-10-13 | minor | Document pinned PngSuite files, integrity checks and download budgets (#1729). |
|
||||
|
||||
@@ -681,6 +681,7 @@ Moved from the ROADMAP's "Shipped so far" on 2026-10-10. Update it when a featur
|
||||
The Paragraph panel's Insert Kashidas (with the Indic options; `text.setFormat {kashida}`) lengthens each Arabic word of a justified horizontal area type line with a kashida, a tatweel between its last pair of joined letters, before the word spaces widen: Short, Medium and Long kashidas are at most a quarter, half and a whole em long, Stylistic ones are whole tatweels up to an em, and None (the default) leaves the line as before; paragraph styles and the native file keep the setting.
|
||||
In vertical type, the Tabs panel names its alignment buttons Top-Justified Tab, Center-Justified Tab, Bottom-Justified Tab and Decimal-Justified Tab, in their tool tips and for screen readers, and labels the position field Y. In horizontal type the buttons keep the names Left-Justified Tab and Right-Justified Tab, and the field keeps the label X.
|
||||
The Tabs panel's ruler is numbered in the General unit with the canvas rulers' label steps and a tick every tenth of a step. With the panel menu's Snap to Unit on, or Shift held, a tab stop placed by a click on the ruler or dragged on it lands on the nearest tick (`text.tabs.set`).
|
||||
With Snap to Unit off and Shift not held, a tab stop placed by a click on the Tabs panel's ruler or dragged on it lands on the nearest whole point. A position typed in the X or Y field keeps its hundredths of a point.
|
||||
When a drag on the Tabs panel's ruler or a value typed in its X field moves a tab stop past another stop, the moved stop stays selected.
|
||||
The Tabs panel menu's Clear All Tabs (`text.tabs.clear`), Delete Tab and Repeat Tab (`text.tabs.set`) can be chosen while the panel's ruler shows tab stops. Delete Tab removes the stop selected on the ruler. Repeat Tab replaces the stops after the selected stop with up to 20 copies of it. The copies are spaced by the selected stop's distance from the stop before it, or from the paragraph's left indent when it is the first stop, and no copy is placed at 2,000 pt or beyond. Clear All Tabs removes every stop, so the default stops every ½ inch apply again.
|
||||
- **Interface languages, vertical type:** Preferences ▸ User Interface (or VectorCraft ▸ Language on macOS) picks Automatic (the system locale) or a registered language, persisted as `interfaceLanguage`. Translations come from per-language catalogs (`i18n/*.tsv`): Traditional and Simplified Chinese, Japanese, German (every `de-*` locale), Spanish (neutral international Spanish, for every `es-*` locale), French (every `fr-*` locale), Italian (every `it-*` locale) Russian (every `ru-*` locale) and Ukrainian (every `uk-*` locale) cover the whole interface, Czech every menu label; Czech, German, Greek, Spanish, French, Hungarian, Italian, Japanese, Korean, Vietnamese, Polish, Brazilian Portuguese, Russian, Simplified Chinese, Traditional Chinese, Swedish, Ukrainian and Finnish also translate status-bar and error messages as they are shown (`@msg` templates, every message literal tested; the messages themselves stay English for agents); untranslated text stays English. Japanese and Chinese glyphs come from the craft-fonts build input (release builds) or the installed fonts, Czech, German, Spanish, French, Italian, Russian and Ukrainian ones from the bundled UI fonts. The web app follows the browser's languages (or `?lang=`). The Basic toolbar's Type button holds Vertical Type in its flyout. Vertical Type, Vertical Area Type and Vertical Type on a Path create vertical text (columns right to left, upright CJK glyphs and marks with `vert` alternates, Latin and longer numbers on their side, two- and three-digit numbers set as tate-chu-yoko in one em of the column (kept whole when justified), upright glyphs centred on the column (tracked or justified too), point type's anchor on the first column's centre line); kinsoku applies to horizontal and vertical Japanese (Paragraph panel › Kinsoku Set, `text.setFormat {kinsoku}`: Hard, the default, keeps closing marks, iteration marks, the prolonged sound mark and small kana off the line start and opening brackets off its end; Soft lets 々, ー and small kana start a line as JLREQ's level 3 rules do; None turns it off), and justified Japanese lines spread their room between characters (not inside Latin words); Paragraph panel › Mojikumi Set (shown with Preferences › Type › Show East Asian Options, `text.setFormat {mojikumi}`): None or Line-end Punctuation Half Width (new type's default, as in Illustrator; older documents and imported text keep None) shares one half-em space between consecutive punctuation, sets a closing mark ending a line half width and an opening bracket starting a line flush with its start (a paragraph's first line at its first-line indent, JIS X 4051's principle in JLREQ 3.1.5), and puts a quarter em between Japanese and Latin letters or digits; Paragraph panel menu › Top-to-Top / Bottom-to-Bottom Leading measures leading from em box top to top (area type's first line touches the frame) or from baseline to baseline (new type in a Japanese interface starts top to top, with em box centre character alignment, #432); Paragraph panel menu › Burasagari None / Regular / Force (`text.setFormat {burasagari: "none"|"standard"|"forced"}`) hangs an East Asian comma or full stop (、。,.、。) ending an area type line outside it, Regular (new type's default) when it doesn't fit and Force always (the rest of the line then fills the measure; closing brackets and Latin punctuation don't hang); Character panel menu › Character Alignment (with the East Asian options; `text.setFormat` or `text.setRangeStyle {charAlign}`) lines characters smaller than the largest on their line up on the Roman baseline, the em box top/right, centre or bottom/left, or the ICF (ideographic character face) top/right or bottom/left, from the font's BASE table or, without one, the average ink box of some ideographs and kana; Proportional Metrics (the same menu; `{proportionalMetrics}`) sets full-width glyphs on the font's proportional widths (OpenType `palt`) in horizontal type and upright glyphs on its proportional heights (`vpal`, shaped top to bottom; fonts without vertical metrics keep their cells) in vertical type, and Line-end Punctuation Half Width takes nothing more off the punctuation they re-spaced; Type ▸ Type Orientation switches existing text; caret, selection, hit testing and arrow keys follow the writing direction. Vertical text exports to PDF as real text and to SVG as outlines. The interface is available in Polish (`pl`): menus, panels, dialogs and messages, with one/few/many plurals; AI-drafted, native review pending (#1498).
|
||||
|
||||
+38
-1
@@ -105,6 +105,40 @@ fn run(mut cmd: Command, what: &str) -> Result<(), String> {
|
||||
if status.success() { Ok(()) } else { Err(format!("{what}: exited with {status}")) }
|
||||
}
|
||||
|
||||
/// `vectorcraft-ui-egui` and `vectorcraft-mcp` without their default features leave
|
||||
/// vectorcraft-text's bundled fonts out: no crate they depend on turns them on (docs/development.md
|
||||
/// › Leaving out the bundled fonts). The same tree with the default features must show them, so a
|
||||
/// change in cargo tree's output can't make the check pass by finding nothing.
|
||||
fn libraries_without_bundled_fonts() -> Result<(), String> {
|
||||
["vectorcraft-ui-egui", "vectorcraft-mcp"].into_iter().try_for_each(without_bundled_fonts)
|
||||
}
|
||||
|
||||
fn without_bundled_fonts(package: &str) -> Result<(), String> {
|
||||
const FEATURE: &str = "vectorcraft-text feature \"bundled-fonts\"";
|
||||
let tree = |defaults: bool| -> Result<String, String> {
|
||||
let mut args = vec!["tree", "-p", package, "--target", "all", "-e", "features,normal", "-i", "vectorcraft-text"];
|
||||
if !defaults {
|
||||
args.insert(3, "--no-default-features");
|
||||
}
|
||||
let what = format!("cargo {}", args.join(" "));
|
||||
eprintln!("$ {what}");
|
||||
let out = cargo().args(&args).output().map_err(|e| format!("{what}: failed to spawn: {e}"))?;
|
||||
if !out.status.success() {
|
||||
return Err(format!("{what}: exited with {}:\n{}", out.status, String::from_utf8_lossy(&out.stderr)));
|
||||
}
|
||||
Ok(String::from_utf8_lossy(&out.stdout).into_owned())
|
||||
};
|
||||
let with = tree(true)?;
|
||||
if !with.contains(FEATURE) {
|
||||
return Err(format!("{package} with its default features shows no {FEATURE} (has cargo tree's output changed?):\n{with}"));
|
||||
}
|
||||
let without = tree(false)?;
|
||||
if without.contains(FEATURE) {
|
||||
return Err(format!("{package} without default features still bundles the fonts:\n{without}"));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn metadata() -> Result<serde_json::Value, String> {
|
||||
let out = cargo().args(["metadata", "--format-version", "1", "--no-deps"]).output().map_err(|e| format!("cargo metadata: {e}"))?;
|
||||
if !out.status.success() {
|
||||
@@ -212,7 +246,10 @@ fn cmd_ci() -> Result<(), String> {
|
||||
// vectorcraft-text as embedders that bring their own fonts build it.
|
||||
let mut c = cargo();
|
||||
c.args(["test", "-p", "vectorcraft-text", "--no-default-features", "--test", "without_bundled_fonts"]);
|
||||
run(c, "cargo test -p vectorcraft-text --no-default-features --test without_bundled_fonts")
|
||||
run(c, "cargo test -p vectorcraft-text --no-default-features --test without_bundled_fonts")?;
|
||||
// The egui panels and the MCP server as such an embedder builds them: nothing turns
|
||||
// the fonts back on.
|
||||
libraries_without_bundled_fonts()
|
||||
}),
|
||||
),
|
||||
("pdf-deps", Box::new(|| pdf_deps::run(&root()))),
|
||||
|
||||
Reference in New Issue
Block a user