Skip to content

Remove input from fontc::Args, rename as Options; restore Box<dyn Source> support#1797

Merged
rsheeter merged 5 commits intono_pathfrom
no_path_2
Dec 4, 2025
Merged

Remove input from fontc::Args, rename as Options; restore Box<dyn Source> support#1797
rsheeter merged 5 commits intono_pathfrom
no_path_2

Conversation

@anthrotype
Copy link
Copy Markdown
Member

Refactor the compile arguments API to:

  • Rename fontc::Args to fontc::Options for clarity (avoids confusion with the clap-based CLI args::Args)
  • Remove input field from Options - source is now passed separately
  • Update generate_font() to accept Box<dyn Source> + Options
  • Update run() to accept Input + Options

This restores the ability to pass custom Box<dyn Source> implementations that was added in #1684, which library users need for generating their own IR programmatically.

Also:

  • Add Default derive to Options for ergonomic in-memory/WASM usage
  • Rename cli_args.rs back to args.rs and delete compile_args.rs (Options inlined in lib.rs since it's short enough)

…rce> support

Refactor the compile arguments API to:
- Rename `fontc::Args` to `fontc::Options` for clarity (avoids confusion
  with CLI `args::Args`)
- Remove `input` field from Options - source is now passed separately
- Update `generate_font()` to accept `Box<dyn Source>` + `Options`
- Update `run()` to accept `Input` + `Options`

This restores the ability to pass custom `Box<dyn Source>` implementations
that was added in #1684, which library users need for generating their own
IR programmatically.

Also:
- Add `Default` derive to `Options` for ergonomic in-memory/WASM usage
- Rename `cli_args.rs` back to `args.rs` and delete `compile_args.rs` (Options inlined in lib.rs since it's short enough)
@anthrotype
Copy link
Copy Markdown
Member Author

anthrotype commented Dec 4, 2025

before y'all start bikeshedding, here's why I think the name Options beats Args.

It's more semantically accured: Args is "what I was given" and close to CLI terminology; Options is "how to behave" and closer to configuration terminology. After removing the input from the old Args, we're left with how to compile, not what, and that sounds more like options.
Plus we don't need two structs both confusingly named "Args", one in cli_args and the other in compile_args module.
I can go on...
Library users don't usually pass "arguments", they configure options. If someone creates Options programmatically (not from CLI), calling it "Args" is awkward.

let args = Args { flags, skip_features: true, ... };
generate_font(source, args)  // args to a function that's not main()?

@anthrotype
Copy link
Copy Markdown
Member Author

there are precendents in the rust ecosystem e.g. https://doc.rust-lang.org/std/fs/struct.OpenOptions.html

Change require_dir() to use fs::create_dir_all() instead of
fs::create_dir() so that nested paths like /tmp/deep/nested/build
are created correctly.
…used

When both --emit-ir and --output-file are used, the font is first
written to {ir_dir}/font.ttf by the persistence mechanism. If output_file
differs, we move (rename) the font to the custom output path rather than
leaving it in the IR directory.

We rename (instead of fs::write or fs::copy) as this matches the current
behavior on `main` whereby the font ends up at output_file only and is not
duplicated in the IR directory.
@anthrotype
Copy link
Copy Markdown
Member Author

@simoncozens does this work for your use case?

@simoncozens
Copy link
Copy Markdown
Contributor

Yes, this works perfectly, thank you!

Copy link
Copy Markdown
Member

@cmyr cmyr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One note inline but overall I think the Args/Options distinction is useful, and this looks good :)

Comment thread fontc/src/lib.rs
Comment on lines +109 to +112
pub fn run(input: Input, options: Options, mut timer: JobTimer) -> Result<(), Error> {
if options.output_file.is_none() {
return Err(Error::NoOutputFile);
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couldn't this be just a required field on the Args struct, and then Args::parse() will fail immediately?

Copy link
Copy Markdown
Member Author

@anthrotype anthrotype Dec 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the check exists because Options.output_file must be Option<PathBuf> for library/WASM users who don't want file output. Our own main.rs always sets it because it uses Args::try_into() which fills it with .or_else(|| Some(build_dir.join("font.ttf"))), so you may argue it's redundant. However the run() function is pub and someone might call it directly with hand-built Options so the check is a safety net for that case.

Copy link
Copy Markdown
Member Author

@anthrotype anthrotype Dec 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

--output-file has an implicit default ("{build_dir}/font.ttf") and the NoOutputFile error only guards against direct run() callers, not CLI users. And we want fontc source.glyphs to continue working as before, without requiring to pass --output-file.

@anthrotype
Copy link
Copy Markdown
Member Author

thanks for reviewing. I'll let @rsheeter merge this since this goes into his own PR branch, not main

@rsheeter
Copy link
Copy Markdown
Contributor

rsheeter commented Dec 4, 2025

It would have been nice to rename separate of the other changes because it's so noisy but lgtm

@rsheeter rsheeter merged commit 5dfa9da into no_path Dec 4, 2025
12 checks passed
@rsheeter rsheeter deleted the no_path_2 branch December 4, 2025 17:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants