-
-
Notifications
You must be signed in to change notification settings - Fork 577
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
FEAT: Support custom TOML themes #286
FEAT: Support custom TOML themes #286
Conversation
`iced::Color` doesn't implement `serde::Deserialize` nor `serde::Serialize`. I need `Deserialize` so that custom color schemes can be deserialized into the palette type used in Sniffnet. I implemented ser/de to deserialize from a hex string into the float colors used by `iced`. My reasoning is that hexadecimal colors are easier for color scheme artists. Anecdotally, I've also noticed hex colors are the most prevalent for color schemes. Some schemes also provide RGB, but I haven't encountered float colors yet. For example: * [Catppuccin](https://github.com/catppuccin/catppuccin) * [Dracula](https://draculatheme.com/contribute) * [gruvbox](https://github.com/morhetz/gruvbox) * [Nord](https://github.com/nordtheme/nord) * [Tokyo Night](https://github.com/folke/tokyonight.nvim)
Merge branch 'main' of github.com:joshuamegnauth54/sniffnet into add_themes
Previously, I implemented a remote type to serialize and deserialize `iced::Color`. That implementation caused some problems when writing the unit tests because `serde_test` expected the `iced::Color` struct. I didn't want to overhaul the tests from their concise and more direct implementations - especially considering I don't really understand the problem. Anyway, using `deserialize_with` and `serialize_with` is cleaner than remote derive so this is overall a win. I implemented `PartialEq` for the custom style's palette's to account for floating point's imprecision. I also fixed an incorrectly copied number that caused the unit tests to fail. With that, deserializing custom styles from TOML seems to work and all unit tests pass.
- Add support for descriptions in other languages. - Use the latest `toml` crate because `confy`'s version had a bug that my code is hitting. Deserializing the `Language` enum in a TOML table failed with an error that claimed that the enum isn't a key. Upgrading the `toml` crate solved that problem. - Clean up TOML theme spec.
Primarily to keep parity with the types that derived Hash before these patches.
`StyleType` is no longer `Copy` because the enum holds `CustomStyle`.
Iced doesn't provide a file dialog to use because that should be handled natively or something. See [iced-rs/iced#347].
(Also, remove a debug line).
Hey, thanks for all the work! The problemsWhile I appreciate your effort, I feel that specifying colors through an external file adds an unneeded complexity which goes against Sniffnet's aim to be comfortable to use. The solutionWhat we could do, instead, is providing a more extended set of palettes personally curated by us.
What I suggest is changing the least possible in the app logic, providing new palettes which could be divided by day/night/other criteria. |
Hello again and thank you for your time! I should clarify my intent with this patch. I apologize for the confusion. I don't intend for users to pick colors one by one for their color schemes. Instead, the purpose of this patch is to allow end users to use common themes that are created by groups such as:
Those groups release themes for programs with easily modifiable styles. For a few examples, I'll refer to alacritty (terminal emulator), bat (a So, if an alacritty user wants to use the Dracula theme, they can head on over to the Dracula repository and download a small YAML with the theme. The process is similar for bat. A user who wants to use the Catppuccin theme only has to download the theme file from the Catppuccin repository just like alacritty's. And of course it's the same for zellij as well as many other programs. Dracula releases its theme for many programs such as kitty, fish, zsh, neovim/vim, Alacritty, VSCode, Steam, zellij, exa, Sway, et cetera. Catppuccin and other themes support a similar number of software. Thus, my intention is for this patch to provide a commensurate experience with Sniffnet - groups that create themes can easily publish a theme, like Catppuccin, for Sniffnet so that end users can use it easily if they wish. DependenciesI completely agree with you on the dependencies issue! However, I should clarify the two dependencies because the situation is not what it seems.
The crux of this patch is adding an extra variant to the I hope that clarifies some of your concerns! Thank you for your time whether or not you want this feature.😄 I'm simplifying the code even more in the meantime. |
I previously wrote PartialEq implementations for `Color` and structs that used it, but deriving it seems to work fine now.
Thanks for the clarifications and for your time as well.
You pointed out a really interesting topic and at this point I'm interested in having Catpuccin and other well-established themes for Sniffnet. Next stepsSince I'm planning to include this kind of feature in v1.3 (which will land not before some months) I think we should have time to obtain enough themes from those groups.
|
I'll have to look into the process of obtaining themes from those groups. As for your other concern, you can definitely distribute those themes with Sniffnet to make it easier for end users. For example, Pygments includes more than 20 built in styles including Dracula and Monokai. Zellij has a page that notes that the maintainers accept theme contributions. The built in themes are located in the zellij repository. Bat also distributes built in themes in a similar manner. I think your ideas are awesome and very useful. Sniffnet will have (as you said) both the original built in themes as well as a set of common themes. It will also have the ability to load themes that aren't distributed with Sniffnet. We can still split the additional schemes by Day and Night too. As for the next steps, I'll definitely stick around to maintain and improve this feature. I'll start working on the improvements listed soon. |
Thanks so much for your ideas and help! |
`StyleType` should serialize as a TOML table to account for `StyleType::Custom` taking a value. I added two attributes to `StyleType` to hint that the `toml` crate should serialize it as a table instead of a simple key = value.
This is just to inform you that I already solved the problem of generating palettes manually instead of using SVGs. Oh, I also removed the |
Thank you! I'll merge this in and get back to working on it within a day or two. |
This adds a unit test to ensure that every built in custom theme successfully deserializes.
Hey! Sorry for disappearing for a few weeks. I had to repair my aging computer, but I'm back now to work on this. I added a scrollbar to the theme picker. Custom themes are loaded from the I wrote a few example themes using Catppuccin and Dracula's specs as examples to show that it works. Should I remove the text box I originally added to load themes? Edit: To clarify, the original themes are at the top of the scrollbar. Extra themes are added below those. I made sure that it works with an odd number of extra themes too. |
Hey! Don't worry at all about delays! I think it'd be better to open a separate PR from a different branch if we want to add some of the new themes in a reasonable amount of time. As I've anticipated, I'd prefer avoiding the management of external files until a proper file dialog is supported. Consequently, the idea of a new branch and a separate PR to not waste anyway the job you did so far. Ideally, we should include in the new PR only the following parts:
Again, thanks a lot for all the work! |
src/gui/styles/types/custom_style.rs
Outdated
use super::palette::{Palette, PaletteExtension}; | ||
use crate::Language; | ||
|
||
/// Custom color scheme data including the palette, name, and location of the toml. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good! I have a question before I start. I implemented a CustomStyle
struct that holds the name of the style, the translated descriptions, and the Palette
plus the extra yellow color.
This struct made it easier to define themes without having to extend functions like get_colors
for each theme.
Original:
pub fn get_colors(style: StyleType) -> Palette {
match style {
StyleType::Night => NIGHT_STYLE,
StyleType::Day => DAY_STYLE,
StyleType::DeepSea => DEEP_SEA_STYLE,
StyleType::MonAmour => MON_AMOUR_STYLE,
}
}
How it looks in my PR:
pub fn get_colors(style: &StyleType) -> &Palette {
match style {
StyleType::Night => &NIGHT_STYLE,
StyleType::Day => &DAY_STYLE,
StyleType::DeepSea => &DEEP_SEA_STYLE,
StyleType::MonAmour => &MON_AMOUR_STYLE,
StyleType::Custom(style) => &style.palette.base,
}
}
Another example.
Original:
pub fn get_starred_color(style: StyleType) -> Color {
match style {
StyleType::Night | StyleType::DeepSea => Color {
r: 245.0 / 255.0,
g: 193.0 / 255.0,
b: 39.0 / 255.0,
a: 0.5,
},
StyleType::Day | StyleType::MonAmour => Color {
r: 245.0 / 255.0,
g: 193.0 / 255.0,
b: 39.0 / 255.0,
a: 0.8,
},
}
}
How it looks in my PR:
pub fn get_starred_color(style: &StyleType) -> Color {
match style {
StyleType::Night | StyleType::DeepSea => Color {
r: 245.0 / 255.0,
g: 193.0 / 255.0,
b: 39.0 / 255.0,
a: 0.5,
},
StyleType::Day | StyleType::MonAmour => Color {
r: 245.0 / 255.0,
g: 193.0 / 255.0,
b: 39.0 / 255.0,
a: 0.8,
},
StyleType::Custom(style) => style.palette.extension.starred,
}
}
In other words, the struct encapsulates the palette plus the metadata for the theme. Functions take &Arc<StyleType>
or &StyleType
instead of StyleType
.
Should I port that over to the new PR or just extend the match
es with new themes as in the original code?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The Arc
should not be needed for the moment.
You can also forget about the palettes' descriptions since I'd like to include them just for the original themes, to not make complex getting all the translations from native speaker and because I'll display the additional palettes in a more condensed form.
The palette name is enough.
And we don't even need the path at this point.
I think the best thing to do is not keeping CustomStyle
, but only keeping CustomPalette
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, I know that's a lot limited with respect to all the work you did, but I think it's a good compromise given the simplicity of this solution and the fact that without a file dialog is not comfortable to include external palettes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought I responded to this. 😅
It's no problem! A minimal, working custom styles implementation is best for now. Plus, I learned a lot anyway. I mostly finished the patch so I'll open a PR now.
The newer implementation is much simpler, so only some of the code needs to be ported over. This is a WIP. The old tests don't work yet.
The least invasive way of supporting custom TOML themes is to add a new variant to `ExtraStyles`. I implemented `Hash` for `CustomPalette` because it's not derivable for `Palette`. Finally, indicating whether a style is nightly must be stored in the palette extensions struct because I can't hard code it (the old solution for the built in extra styles).
(Message not implemented yet)
- The custom theme text box is highlighted in red if the path doesn't exist or if it doesn't have a `.toml` extension. - The last set theme takes prescedence instead of custom themes always clobbering the set theme. - Fix all old TOML themes.
I'm mostly finished porting over the old code from this PR. Custom themes work, so you can test it if you want. 😺 I have to remove some unused functions and fix my old unit tests, but you can let me know what else I should do with the code committed so far. |
Tyvm! I'll let you know as soon as I have time to check your PR 👍 |
I've fixed some aspects and I think we are finally ready to merge this. Most notably, I didn't like that the input box for the custom style was emptied when selecting one of the default themes. Other than that I just changed minor aspects. I really liked your implementation. |
Feature: Support custom GUI themes defined in TOML.
Rationale
Many programs support custom themes that are defined in simple file formats, such as TOML. This patch adds a similar feature to Sniffnet by working within its preexisting style and palette infrastructure. Theme designers, such as the individuals who contribute to Catppuccin or Dracula.
Usage
I added a text box to the theme picker to load a custom theme from a TOML file. Iced doesn't have a file dialog yet. The text input box is an imperfect solution but works for now.
A custom theme should be defined in TOML with the following schema:
All colors are hexadecimal RGB. Descriptions are multilingual but currently unused in the UI at the moment. The format is really simple and similar to other programs.
Examples of theme files in other open source programs (non-exhaustive)
The example above is located in
resources\themes\catppuccin_mocha.toml
and uses colors from Catppuccin.Implementation details
CustomStyle
,CustomPalette
, andPaletteExtension
I added a new variant to
StyleType
that holds aCustomStyle
struct.I implemented three new types for custom styles.
CustomStyle
contains metadata on the theme such as its name and description(s) as well as the palette.CustomPalette
contains the colors themselves. I used Sniffnet's pre-existingPalette
type as well as an extension type,PaletteExtension
, to hold extra colors such as the favorites star.Palette
andPaletteExtension
are flattened upon deserialization for ergonomics. A future patch can simplify Sniffnet's styles by unifying both types without affecting any existing themes at all.Split deserialization
CustomStyle
is serialized to and deserialized from a file path. In other words, Sniffnet's config file saves the path to a custom theme to reload it on start rather than serializing the colors.I implemented a deserializer for
iced::Color
that constructs it from a hex string.Two new dependencies (sort of)
I added the toml crate as a dependency and serde-test as a dev-dependency.
The
toml
crate is already used by confy by default.confy
is already used by Sniffnet which means thattoml
is a transitive dependency.serde-test
is only used in unit tests as a dev-dependency (i.e. it's only compiled and used in tests).StyleType
borrowsStyleType
is no longer copyable becauseCustomStyle
isn'tCopy
.StyleType
is wrapped into anArc
which is passed around or cloned as necessary. This is a fairly simple change that doesn't affect Sniffnet itself.Future work
Let me know what you think for now!