egui/crates/egui_extras
Matt Keeter f11a3510ba
Support custom syntect settings in syntax highlighter (#7084)
<!--
Please read the "Making a PR" section of
[`CONTRIBUTING.md`](https://github.com/emilk/egui/blob/main/CONTRIBUTING.md)
before opening a Pull Request!

* Keep your PR:s small and focused.
* The PR title is what ends up in the changelog, so make it descriptive!
* If applicable, add a screenshot or gif.
* If it is a non-trivial addition, consider adding a demo for it to
`egui_demo_lib`, or a new example.
* Do NOT open PR:s from your `master` branch, as that makes it hard for
maintainers to test and add commits to your PR.
* Remember to run `cargo fmt` and `cargo clippy`.
* Open the PR as a draft until you have self-reviewed it and run
`./scripts/check.sh`.
* When you have addressed a PR comment, mark it as resolved.

Please be patient! I will review your PR, but my time is limited!
-->

* Closes <https://github.com/emilk/egui/issues/3964>
* [X] I have followed the instructions in the PR template

This PR adds support for syntax highlighting with custom
`syntect::parsing::SyntaxSet` and `syntect::highlighting::ThemeSet`. It
adds a new `egui_extras::highlight_with` function (enabled with `feature
= "syntect"`), which takes a new public`struct SyntectSettings`
containing the syntax and theme sets.

```rust
let mut builder = SyntaxSetBuilder::new();
builder.add_from_folder("syntax", true).unwrap();
let ps = builder.build();
let ts = syntect::highlighting::ThemeSet::load_defaults();
let syntax =
    egui_extras::syntax_highlighting::SyntectSettings { ps, ts };

// ...elsewhere
egui_extras::syntax_highlighting::highlight_with(
    ui.ctx(),
    ui.style(),
    &theme,
    buf,
    "rhai",
    &syntax,
);
```

There's a little bit of architectural complexity, but it all emerges
naturally from the problem's constraints.

Previously, the `Highlighter` both contained the `syntect` settings
_and_ implemented `egui::cache::ComputerMut` to highlight a string; the
settings would never change. After this change, the `syntect` settings
have become part of the cache key, so we should redo highlighting if
they change. The `Highlighter` becomes an empty `struct` which just
serves to implement `ComputerMut`.

`SyntaxSet` and `ThemeSet` are not hasheable themselves, so can't be
used as cache keys direction. Instead, we can use the *address* of the
`&SyntectSettings` as the key. This requires an object with a custom
`Hash` implementation, so I added a new `HighlightSettings(&'a
SyntectSettings)`, implementing `Hash` using `std::ptr::hash` on the
reference. I think using the address is reasonable – it would be _weird_
for a user to be constantly moving around their `SyntectSettings`, and
there's a warning in the docstring to this effect.

To work _without_ custom settings, `SyntectSettings::default` preserves
the same behavior as before, using `SyntaxSet::load_defaults_newlines`
and `ThemeSet::load_defaults`. If the user doesn't provide custom
settings, then we instantiate a singleton `SyntectSettings` in `data`
and use it; this will only be constructed once.

Finally, in cases where the `syntect` feature is disabled,
`SyntectSettings` are replaced with a unit `()`. This adds a _tiny_
amount of overhead – one singleton `Arc<()>` allocation and a lookup in
`data` per `highlight` – but I think that's better than dramatically
different implementations. If this is an issue, I can refactor to make
it zero-cost when the feature is disabled.
2025-06-24 15:09:29 +02:00
..
src Support custom syntect settings in syntax highlighter (#7084) 2025-06-24 15:09:29 +02:00
CHANGELOG.md Release 0.31.1 - text_edit and kittest fixes 2025-03-05 08:37:34 +01:00
Cargo.toml Include test windows in `egui_demo_lib` snapshot tests (#7070) 2025-05-21 17:44:27 +02:00
README.md Update `image` crate to 0.25 (#4160) 2024-05-13 13:35:15 +02:00

README.md

egui_extras

Latest version Documentation unsafe forbidden MIT Apache

This is a crate that adds some features on top top of egui. This crate is for experimental features, and features that require big dependencies that do not belong in egui.

Images

One thing egui_extras is commonly used for is to install image loaders for egui:

egui_extras = { version = "*", features = ["all_loaders"] }
image = { version = "0.25", features = ["jpeg", "png"] } # Add the types you want support for
egui_extras::install_image_loaders(egui_ctx);