From 36d724f148ed8ebe84cbb3c3e25cd4a361d94e66 Mon Sep 17 00:00:00 2001 From: Jake Stanger Date: Fri, 10 May 2024 22:40:00 +0100 Subject: [PATCH] feat(config): json schema support This PR includes the necessary code changes, CI changes and documentation to generate and deploy a full JSON schema for each release and the master branch, which can be used within config files for autocomplete and type checking. --- .github/workflows/deploy.yml | 60 +++++++++++++++++++++++++------ .github/workflows/schema.yml | 41 +++++++++++++++++++++ Cargo.lock | 42 ++++++++++++++++++++++ Cargo.toml | 5 +++ docs/Compiling.md | 3 ++ docs/Configuration guide.md | 9 ++++- examples/config.json | 1 + examples/config.yaml | 1 + src/cli.rs | 6 ++++ src/config/common.rs | 3 ++ src/config/mod.rs | 9 +++++ src/config/truncate.rs | 2 ++ src/dynamic_value/dynamic_bool.rs | 1 + src/main.rs | 7 ++++ src/modules/cairo.rs | 1 + src/modules/clipboard.rs | 1 + src/modules/clock.rs | 1 + src/modules/custom/box.rs | 1 + src/modules/custom/button.rs | 1 + src/modules/custom/image.rs | 1 + src/modules/custom/label.rs | 1 + src/modules/custom/mod.rs | 4 +++ src/modules/custom/progress.rs | 1 + src/modules/custom/slider.rs | 1 + src/modules/focused.rs | 1 + src/modules/label.rs | 1 + src/modules/launcher/mod.rs | 1 + src/modules/music/config.rs | 3 ++ src/modules/notifications.rs | 2 ++ src/modules/script.rs | 1 + src/modules/sysinfo.rs | 3 ++ src/modules/tray/mod.rs | 21 +++++++++-- src/modules/upower.rs | 1 + src/modules/volume.rs | 2 ++ src/modules/workspaces.rs | 3 ++ src/script.rs | 3 ++ 36 files changed, 230 insertions(+), 15 deletions(-) create mode 100644 .github/workflows/schema.yml diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index f8f68a1..bb86387 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -6,20 +6,13 @@ on: - v[0-9]+.[0-9]+.[0-9]+ jobs: - deploy: + release: + name: 'Create Release' runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - uses: actions-rs/toolchain@v1 - with: - toolchain: stable - override: true - - - name: Install build deps - run: ./.github/scripts/ubuntu_setup.sh - - name: Update CHANGELOG id: changelog uses: Requarks/changelog-action@v1 @@ -41,9 +34,54 @@ jobs: uses: stefanzweifel/git-auto-commit-action@v4 with: branch: master - commit_message: 'docs: update CHANGELOG.md for ${{ github.ref_name }} [skip ci]' + commit_message: 'chore: update CHANGELOG.md for ${{ github.ref_name }} [skip ci]' file_pattern: CHANGELOG.md - - uses: katyo/publish-crates@v1 + + publish-crate: + name: 'Publish Crate' + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + + - uses: actions-rs/toolchain@v1 + with: + toolchain: stable + override: true + + - name: Install build deps + run: ./.github/scripts/ubuntu_setup.sh + + - name: Publish crate + uses: katyo/publish-crates@v1 with: registry-token: ${{ secrets.CARGO_REGISTRY_TOKEN }} + + + publish-schema: + name: 'Publish Schema' + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + + - uses: Swatinem/rust-cache@v2 + name: Cache dependencies + + - name: Install build deps + run: ./.github/scripts/ubuntu_setup.sh + + - name: Build schema + run: cargo build --features schema -- --print-schema > target/schema-${{ github.ref_name }}.json + + - name: Copy file via SSH + uses: appleboy/scp-action@v0.1.7 + with: + host: ${{ secrets.SSH_HOST }} + port: ${{ secrets.SSH_PORT }} + username: ${{ secrets.SSH_USERNAME }} + key: ${{ secrets.SSH_PRIVATE_KEY }} + source: "target/schema-${{ github.ref_name }}.json" + target: /storage/Public/github/ironbar + strip_components: 1 \ No newline at end of file diff --git a/.github/workflows/schema.yml b/.github/workflows/schema.yml new file mode 100644 index 0000000..be79ca2 --- /dev/null +++ b/.github/workflows/schema.yml @@ -0,0 +1,41 @@ +name: Publish Schema + +on: + workflow_dispatch: + push: + branches: [ "master" ] + +env: + CARGO_TERM_COLOR: always + RUSTFLAGS: '-Dwarnings' + +jobs: + publish-schema: + name: 'Publish Schema' + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + + - uses: Swatinem/rust-cache@v2 + name: Cache dependencies + + - name: Install build deps + run: ./.github/scripts/ubuntu_setup.sh + + - name: Build + run: cargo build --features schema + + - name: Print schema + run: cargo run --features schema -- --print-schema > target/schema.json + + - name: Copy file via SSH + uses: appleboy/scp-action@v0.1.7 + with: + host: ${{ secrets.SSH_HOST }} + port: ${{ secrets.SSH_PORT }} + username: ${{ secrets.SSH_USERNAME }} + key: ${{ secrets.SSH_PRIVATE_KEY }} + source: "target/schema.json" + target: /storage/Public/github/ironbar + strip_components: 1 \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 01e7cb6..a79ba4a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -755,6 +755,12 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" +[[package]] +name = "dyn-clone" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" + [[package]] name = "either" version = "1.8.1" @@ -1606,6 +1612,7 @@ dependencies = [ "notify", "regex", "reqwest", + "schemars", "serde", "serde_json", "smithay-client-toolkit", @@ -2637,6 +2644,30 @@ dependencies = [ "windows-sys 0.42.0", ] +[[package]] +name = "schemars" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc6e7ed6919cb46507fb01ff1654309219f62b4d603822501b0b80d42f6f21ef" +dependencies = [ + "dyn-clone", + "schemars_derive", + "serde", + "serde_json", +] + +[[package]] +name = "schemars_derive" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "185f2b7aa7e02d418e453790dde16890256bbd2bcd04b7dc5348811052b53f49" +dependencies = [ + "proc-macro2", + "quote 1.0.35", + "serde_derive_internals", + "syn 2.0.48", +] + [[package]] name = "scoped-tls" version = "1.0.1" @@ -2698,6 +2729,17 @@ dependencies = [ "syn 2.0.48", ] +[[package]] +name = "serde_derive_internals" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "330f01ce65a3a5fe59a60c82f3c9a024b573b8a6e875bd233fe5f934e71d54e3" +dependencies = [ + "proc-macro2", + "quote 1.0.35", + "syn 2.0.48", +] + [[package]] name = "serde_json" version = "1.0.117" diff --git a/Cargo.toml b/Cargo.toml index 23fa7fc..91be339 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -76,6 +76,8 @@ workspaces = ["futures-lite"] "workspaces+sway" = ["workspaces", "swayipc-async"] "workspaces+hyprland" = ["workspaces", "hyprland"] +schema = ["dep:schemars"] + [dependencies] # core gtk = "0.18.1" @@ -157,3 +159,6 @@ regex = { version = "1.10.4", default-features = false, features = [ "std", ], optional = true } # music, sys_info zbus = { version = "3.15.2", default-features = false, features = ["tokio"], optional = true } # notifications, upower + +# schema +schemars = { version = "0.8.19", optional = true } diff --git a/docs/Compiling.md b/docs/Compiling.md index 6b1c9a7..6112885 100644 --- a/docs/Compiling.md +++ b/docs/Compiling.md @@ -101,6 +101,9 @@ cargo build --release --no-default-features \ | workspaces+all | Enables the `workspaces` module with support for all compositors. | | workspaces+sway | Enables the `workspaces` module with support for Sway. | | workspaces+hyprland | Enables the `workspaces` module with support for Hyprland. | +| **Other** | | +| schema | Enables JSON schema support and the CLI `--print-schema` flag. | + ## Speeding up compiling diff --git a/docs/Configuration guide.md b/docs/Configuration guide.md index 5edf0b1..b52c2e2 100644 --- a/docs/Configuration guide.md +++ b/docs/Configuration guide.md @@ -20,11 +20,18 @@ Ironbar supports a range of configuration formats, so you can pick your favourit - `config.json` - `config.toml` - `config.yaml` -- `config.corn` (Experimental, includes variable support for re-using blocks. +- `config.corn` (Includes variable support for re-using blocks. See [here](https://github.com/jakestanger/corn) for info) You can also override the default config path using the `IRONBAR_CONFIG` environment variable. +A hosted schema is available for the latest Git version ~~and each versioned release~~. +JSON and YAML both support schema checking by adding the `$schema` key +to the top level of your config. + +- master: `https://f.jstanger.dev/github/ironbar/schema.json` +- ~~release: `https://f.jstanger.dev/github/ironbar/schema-v0.16.0.json`~~ *(Not released yet)* + ## 2. Pick your use-case Ironbar gives you a few ways to configure the bar to suit your needs. diff --git a/examples/config.json b/examples/config.json index a54dd12..b85a4ff 100644 --- a/examples/config.json +++ b/examples/config.json @@ -1,4 +1,5 @@ { + "$schema": "https://f.jstanger.dev/github/ironbar/schema.json", "anchor_to_edges": true, "position": "bottom", "icon_theme": "Paper", diff --git a/examples/config.yaml b/examples/config.yaml index e05c4a1..86cb83d 100644 --- a/examples/config.yaml +++ b/examples/config.yaml @@ -1,3 +1,4 @@ +$schema: https://f.jstanger.dev/github/ironbar/schema.json anchor_to_edges: true position: bottom icon_theme: Paper diff --git a/src/cli.rs b/src/cli.rs index d0f05f1..0938753 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -9,6 +9,12 @@ pub struct Args { #[command(subcommand)] pub command: Option, + /// Prints the config JSON schema to `stdout` + /// and exits. + #[cfg(feature = "schema")] + #[arg(long("print-schema"))] + pub print_schema: bool, + /// `bar_id` argument passed by `swaybar_command`. /// Not used. #[arg(short('b'), hide(true))] diff --git a/src/config/common.rs b/src/config/common.rs index d1446e2..f1bc3c7 100644 --- a/src/config/common.rs +++ b/src/config/common.rs @@ -16,6 +16,7 @@ use tracing::trace; /// see [here](script). /// For information on styling, please see the [styling guide](styling-guide). #[derive(Debug, Default, Deserialize, Clone)] +#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] pub struct CommonConfig { /// Sets the unique widget name, /// allowing you to target it in CSS using `#name`. @@ -160,6 +161,7 @@ pub struct CommonConfig { #[derive(Debug, Deserialize, Clone)] #[serde(rename_all = "snake_case")] +#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] pub enum TransitionType { None, Crossfade, @@ -169,6 +171,7 @@ pub enum TransitionType { #[derive(Debug, Default, Deserialize, Clone, Copy)] #[serde(rename_all = "snake_case")] +#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] pub enum ModuleOrientation { #[default] #[serde(alias = "h")] diff --git a/src/config/mod.rs b/src/config/mod.rs index e906a40..f5f4c88 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -36,11 +36,15 @@ use color_eyre::Result; use serde::Deserialize; use std::collections::HashMap; +#[cfg(feature = "schema")] +use schemars::JsonSchema; + pub use self::common::{CommonConfig, ModuleOrientation, TransitionType}; pub use self::truncate::TruncateMode; #[derive(Debug, Deserialize, Clone)] #[serde(tag = "type", rename_all = "snake_case")] +#[cfg_attr(feature = "schema", derive(JsonSchema))] pub enum ModuleConfig { #[cfg(feature = "cairo")] Cairo(Box), @@ -117,6 +121,7 @@ impl ModuleConfig { } #[derive(Debug, Clone)] +#[cfg_attr(feature = "schema", derive(JsonSchema))] pub enum MonitorConfig { Single(BarConfig), Multiple(Vec), @@ -124,6 +129,7 @@ pub enum MonitorConfig { #[derive(Debug, Deserialize, Copy, Clone, PartialEq, Eq)] #[serde(rename_all = "snake_case")] +#[cfg_attr(feature = "schema", derive(JsonSchema))] pub enum BarPosition { Top, Bottom, @@ -138,6 +144,7 @@ impl Default for BarPosition { } #[derive(Debug, Default, Deserialize, Copy, Clone, PartialEq, Eq)] +#[cfg_attr(feature = "schema", derive(JsonSchema))] pub struct MarginConfig { #[serde(default)] pub bottom: i32, @@ -156,6 +163,7 @@ pub struct MarginConfig { /// depending on your [use-case](#2-pick-your-use-case). /// #[derive(Debug, Deserialize, Clone)] +#[cfg_attr(feature = "schema", derive(JsonSchema))] pub struct BarConfig { /// A unique identifier for the bar, used for controlling it over IPC. /// If not set, uses a generated integer suffix. @@ -292,6 +300,7 @@ impl Default for BarConfig { } #[derive(Debug, Deserialize, Clone, Default)] +#[cfg_attr(feature = "schema", derive(JsonSchema))] pub struct Config { /// A map of [ironvar](ironvar) keys and values /// to initialize Ironbar with on startup. diff --git a/src/config/truncate.rs b/src/config/truncate.rs index 87451e4..09966cd 100644 --- a/src/config/truncate.rs +++ b/src/config/truncate.rs @@ -4,6 +4,7 @@ use serde::Deserialize; #[derive(Debug, Deserialize, Clone, Copy)] #[serde(rename_all = "snake_case")] +#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] pub enum EllipsizeMode { Start, Middle, @@ -28,6 +29,7 @@ impl From for GtkEllipsizeMode { /// #[derive(Debug, Deserialize, Clone, Copy)] #[serde(untagged)] +#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] pub enum TruncateMode { /// Auto mode lets GTK decide when to ellipsize. /// diff --git a/src/dynamic_value/dynamic_bool.rs b/src/dynamic_value/dynamic_bool.rs index df75758..c2162fc 100644 --- a/src/dynamic_value/dynamic_bool.rs +++ b/src/dynamic_value/dynamic_bool.rs @@ -8,6 +8,7 @@ use tokio::sync::mpsc; #[derive(Debug, Deserialize, Clone)] #[serde(untagged)] +#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] pub enum DynamicBool { /// Either a script or variable, to be determined. Unknown(String), diff --git a/src/main.rs b/src/main.rs index 441c0e3..551a25b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -76,6 +76,13 @@ fn main() { fn run_with_args() { let args = cli::Args::parse(); + #[cfg(feature = "schema")] + if args.print_schema { + let schema = schemars::schema_for!(Config); + println!("{}", serde_json::to_string_pretty(&schema).unwrap()); + return; + } + match args.command { Some(command) => { let rt = create_runtime(); diff --git a/src/modules/cairo.rs b/src/modules/cairo.rs index 3ce42bb..bb0290b 100644 --- a/src/modules/cairo.rs +++ b/src/modules/cairo.rs @@ -18,6 +18,7 @@ use tokio::time::sleep; use tracing::{debug, error}; #[derive(Debug, Clone, Deserialize)] +#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] pub struct CairoModule { /// The path to the Lua script to load. /// This can be absolute, or relative to the working directory. diff --git a/src/modules/clipboard.rs b/src/modules/clipboard.rs index 6365088..751c115 100644 --- a/src/modules/clipboard.rs +++ b/src/modules/clipboard.rs @@ -17,6 +17,7 @@ use tokio::sync::{broadcast, mpsc}; use tracing::{debug, error}; #[derive(Debug, Deserialize, Clone)] +#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] pub struct ClipboardModule { /// The icon to show on the bar widget button. /// Supports [image](images) icons. diff --git a/src/modules/clock.rs b/src/modules/clock.rs index a5be924..6af5e88 100644 --- a/src/modules/clock.rs +++ b/src/modules/clock.rs @@ -16,6 +16,7 @@ use crate::modules::{ use crate::{glib_recv, module_impl, send_async, spawn, try_send}; #[derive(Debug, Deserialize, Clone)] +#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] pub struct ClockModule { /// The format string to use for the date/time shown on the bar. /// Pango markup is supported. diff --git a/src/modules/custom/box.rs b/src/modules/custom/box.rs index 7e448f4..2c4275f 100644 --- a/src/modules/custom/box.rs +++ b/src/modules/custom/box.rs @@ -6,6 +6,7 @@ use gtk::prelude::*; use serde::Deserialize; #[derive(Debug, Deserialize, Clone)] +#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] pub struct BoxWidget { /// Widget name. /// diff --git a/src/modules/custom/button.rs b/src/modules/custom/button.rs index 9382da2..98476e8 100644 --- a/src/modules/custom/button.rs +++ b/src/modules/custom/button.rs @@ -10,6 +10,7 @@ use crate::{build, try_send}; use super::{CustomWidget, CustomWidgetContext, ExecEvent, WidgetConfig}; #[derive(Debug, Deserialize, Clone)] +#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] pub struct ButtonWidget { /// Widget name. /// diff --git a/src/modules/custom/image.rs b/src/modules/custom/image.rs index fffac2d..cb4a33f 100644 --- a/src/modules/custom/image.rs +++ b/src/modules/custom/image.rs @@ -9,6 +9,7 @@ use crate::image::ImageProvider; use super::{CustomWidget, CustomWidgetContext}; #[derive(Debug, Deserialize, Clone)] +#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] pub struct ImageWidget { /// Widget name. /// diff --git a/src/modules/custom/label.rs b/src/modules/custom/label.rs index 65f303b..55d2507 100644 --- a/src/modules/custom/label.rs +++ b/src/modules/custom/label.rs @@ -9,6 +9,7 @@ use crate::dynamic_value::dynamic_string; use super::{CustomWidget, CustomWidgetContext}; #[derive(Debug, Deserialize, Clone)] +#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] pub struct LabelWidget { /// Widget name. /// diff --git a/src/modules/custom/mod.rs b/src/modules/custom/mod.rs index 5cffb00..9ef32eb 100644 --- a/src/modules/custom/mod.rs +++ b/src/modules/custom/mod.rs @@ -28,6 +28,7 @@ use tokio::sync::{broadcast, mpsc}; use tracing::{debug, error}; #[derive(Debug, Deserialize, Clone)] +#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] pub struct CustomModule { /// Modules and widgets to add to the bar container. /// @@ -45,6 +46,7 @@ pub struct CustomModule { } #[derive(Debug, Deserialize, Clone)] +#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] pub struct WidgetConfig { /// One of a custom module native Ironbar module. #[serde(flatten)] @@ -57,6 +59,7 @@ pub struct WidgetConfig { #[derive(Debug, Deserialize, Clone)] #[serde(untagged)] +#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] pub enum WidgetOrModule { /// A custom-module specific basic widget Widget(Widget), @@ -67,6 +70,7 @@ pub enum WidgetOrModule { #[derive(Debug, Deserialize, Clone)] #[serde(tag = "type", rename_all = "snake_case")] +#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] pub enum Widget { /// A container to place nested widgets inside. Box(BoxWidget), diff --git a/src/modules/custom/progress.rs b/src/modules/custom/progress.rs index 199ea8c..1d9f40e 100644 --- a/src/modules/custom/progress.rs +++ b/src/modules/custom/progress.rs @@ -13,6 +13,7 @@ use crate::{build, glib_recv_mpsc, spawn, try_send}; use super::{CustomWidget, CustomWidgetContext}; #[derive(Debug, Deserialize, Clone)] +#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] pub struct ProgressWidget { /// Widget name. /// diff --git a/src/modules/custom/slider.rs b/src/modules/custom/slider.rs index c533719..bc5ea7f 100644 --- a/src/modules/custom/slider.rs +++ b/src/modules/custom/slider.rs @@ -16,6 +16,7 @@ use crate::{build, glib_recv_mpsc, spawn, try_send}; use super::{CustomWidget, CustomWidgetContext, ExecEvent}; #[derive(Debug, Deserialize, Clone)] +#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] pub struct SliderWidget { /// Widget name. /// diff --git a/src/modules/focused.rs b/src/modules/focused.rs index 9fb43d2..989293f 100644 --- a/src/modules/focused.rs +++ b/src/modules/focused.rs @@ -12,6 +12,7 @@ use tokio::sync::mpsc; use tracing::debug; #[derive(Debug, Deserialize, Clone)] +#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] pub struct FocusedModule { /// Whether to show icon on the bar. /// diff --git a/src/modules/label.rs b/src/modules/label.rs index 2a8a20c..0004ad9 100644 --- a/src/modules/label.rs +++ b/src/modules/label.rs @@ -9,6 +9,7 @@ use serde::Deserialize; use tokio::sync::mpsc; #[derive(Debug, Deserialize, Clone)] +#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] pub struct LabelModule { /// The text to show on the label. /// This is a [Dynamic String](dynamic-values#dynamic-string). diff --git a/src/modules/launcher/mod.rs b/src/modules/launcher/mod.rs index bb48cd9..70e4b56 100644 --- a/src/modules/launcher/mod.rs +++ b/src/modules/launcher/mod.rs @@ -19,6 +19,7 @@ use tokio::sync::{broadcast, mpsc}; use tracing::{debug, error, trace}; #[derive(Debug, Deserialize, Clone)] +#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] pub struct LauncherModule { /// List of app IDs (or classes) to always show regardless of open state, /// in the order specified. diff --git a/src/modules/music/config.rs b/src/modules/music/config.rs index 6d3de79..cfedb8f 100644 --- a/src/modules/music/config.rs +++ b/src/modules/music/config.rs @@ -4,6 +4,7 @@ use serde::Deserialize; use std::path::PathBuf; #[derive(Debug, Deserialize, Clone)] +#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] pub struct Icons { /// Icon to display when playing. /// @@ -71,6 +72,7 @@ impl Default for Icons { #[derive(Debug, Deserialize, Clone, Copy)] #[serde(rename_all = "snake_case")] +#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] pub enum PlayerType { Mpd, Mpris, @@ -83,6 +85,7 @@ impl Default for PlayerType { } #[derive(Debug, Deserialize, Clone)] +#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] pub struct MusicModule { /// Type of player to connect to #[serde(default)] diff --git a/src/modules/notifications.rs b/src/modules/notifications.rs index 18e5c2a..b76a368 100644 --- a/src/modules/notifications.rs +++ b/src/modules/notifications.rs @@ -10,6 +10,7 @@ use tokio::sync::mpsc::Receiver; use tracing::error; #[derive(Debug, Deserialize, Clone)] +#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] pub struct NotificationsModule { /// Whether to show the current notification count. /// @@ -29,6 +30,7 @@ pub struct NotificationsModule { } #[derive(Debug, Deserialize, Clone)] +#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] struct Icons { /// Icon to show when the panel is closed, with no notifications. /// diff --git a/src/modules/script.rs b/src/modules/script.rs index cd96142..83a0748 100644 --- a/src/modules/script.rs +++ b/src/modules/script.rs @@ -10,6 +10,7 @@ use tokio::sync::mpsc; use tracing::error; #[derive(Debug, Deserialize, Clone)] +#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] pub struct ScriptModule { /// Path to script to execute. /// diff --git a/src/modules/sysinfo.rs b/src/modules/sysinfo.rs index 026cbf2..2568ff2 100644 --- a/src/modules/sysinfo.rs +++ b/src/modules/sysinfo.rs @@ -14,6 +14,7 @@ use tokio::sync::mpsc; use tokio::time::sleep; #[derive(Debug, Deserialize, Clone)] +#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] pub struct SysInfoModule { /// List of strings including formatting tokens. /// For available tokens, see [below](#formatting-tokens). @@ -51,6 +52,7 @@ pub struct SysInfoModule { } #[derive(Debug, Deserialize, Copy, Clone)] +#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] pub struct Intervals { /// The number of seconds between refreshing memory data. /// @@ -91,6 +93,7 @@ pub struct Intervals { #[derive(Debug, Deserialize, Copy, Clone)] #[serde(untagged)] +#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] pub enum Interval { All(u64), Individual(Intervals), diff --git a/src/modules/tray/mod.rs b/src/modules/tray/mod.rs index 23c4bee..faba589 100644 --- a/src/modules/tray/mod.rs +++ b/src/modules/tray/mod.rs @@ -19,6 +19,7 @@ use tokio::sync::mpsc; use tracing::{debug, error, warn}; #[derive(Debug, Deserialize, Clone)] +#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] pub struct TrayModule { /// Requests that icons from the theme be used over the item-provided item. /// Most items only provide one or the other so this will have no effect in most circumstances. @@ -38,7 +39,8 @@ pub struct TrayModule { /// **Valid options**: `top_to_bottom`, `bottom_to_top`, `left_to_right`, `right_to_left` ///
/// **Default**: `left_to_right` if bar is horizontal, `top_to_bottom` if bar is vertical - #[serde(default, deserialize_with = "deserialize_orientation")] + #[serde(default, deserialize_with = "deserialize_pack_direction")] + #[cfg_attr(feature = "schema", schemars(schema_with = "schema_pack_direction"))] direction: Option, /// See [common options](module-level-options#common-options). @@ -50,7 +52,7 @@ const fn default_icon_size() -> u32 { 16 } -fn deserialize_orientation<'de, D>(deserializer: D) -> Result, D::Error> +fn deserialize_pack_direction<'de, D>(deserializer: D) -> Result, D::Error> where D: serde::Deserializer<'de>, { @@ -61,11 +63,24 @@ where "right_to_left" => Ok(PackDirection::Rtl), "top_to_bottom" => Ok(PackDirection::Ttb), "bottom_to_top" => Ok(PackDirection::Btt), - _ => Err(serde::de::Error::custom("invalid value for orientation")), + _ => Err(serde::de::Error::custom("invalid value for direction")), }) .transpose() } +#[cfg(feature = "schema")] +fn schema_pack_direction(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema { + use schemars::JsonSchema; + let mut schema: schemars::schema::SchemaObject = ::json_schema(gen).into(); + schema.enum_values = Some(vec![ + "top_to_bottom".into(), + "bottom_to_top".into(), + "left_to_right".into(), + "right_to_left".into(), + ]); + schema.into() +} + impl Module for TrayModule { type SendMessage = Event; type ReceiveMessage = ActivateRequest; diff --git a/src/modules/upower.rs b/src/modules/upower.rs index 34baf27..d461cc3 100644 --- a/src/modules/upower.rs +++ b/src/modules/upower.rs @@ -22,6 +22,7 @@ const HOUR: i64 = 60 * 60; const MINUTE: i64 = 60; #[derive(Debug, Deserialize, Clone)] +#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] pub struct UpowerModule { /// The format string to use for the widget button label. /// For available tokens, see [below](#formatting-tokens). diff --git a/src/modules/volume.rs b/src/modules/volume.rs index 221d327..172b562 100644 --- a/src/modules/volume.rs +++ b/src/modules/volume.rs @@ -14,6 +14,7 @@ use std::collections::HashMap; use tokio::sync::mpsc; #[derive(Debug, Clone, Deserialize)] +#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] pub struct VolumeModule { /// The format string to use for the widget button label. /// For available tokens, see [below](#formatting-tokens). @@ -45,6 +46,7 @@ fn default_format() -> String { } #[derive(Debug, Clone, Deserialize)] +#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] pub struct Icons { /// Icon to show for high volume levels. /// diff --git a/src/modules/workspaces.rs b/src/modules/workspaces.rs index 91d0cd6..d9f41dd 100644 --- a/src/modules/workspaces.rs +++ b/src/modules/workspaces.rs @@ -15,6 +15,7 @@ use tracing::{debug, trace, warn}; #[derive(Debug, Deserialize, Clone, Copy, Eq, PartialEq)] #[serde(rename_all = "snake_case")] +#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] pub enum SortOrder { /// Shows workspaces in the order they're added Added, @@ -31,6 +32,7 @@ impl Default for SortOrder { #[derive(Debug, Deserialize, Clone)] #[serde(untagged)] +#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] pub enum Favorites { ByMonitor(HashMap>), Global(Vec), @@ -43,6 +45,7 @@ impl Default for Favorites { } #[derive(Debug, Deserialize, Clone)] +#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] pub struct WorkspacesModule { /// Map of actual workspace names to custom names. /// diff --git a/src/script.rs b/src/script.rs index 71f0dc4..29fe2c4 100644 --- a/src/script.rs +++ b/src/script.rs @@ -14,6 +14,7 @@ use tracing::{debug, error, trace, warn}; #[derive(Debug, Deserialize, Clone)] #[serde(untagged)] +#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] pub enum ScriptInput { String(String), Struct(Script), @@ -21,6 +22,7 @@ pub enum ScriptInput { #[derive(Debug, Deserialize, Clone, Copy, Eq, PartialEq)] #[serde(rename_all = "snake_case")] +#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] pub enum ScriptMode { Poll, Watch, @@ -75,6 +77,7 @@ impl ScriptMode { } #[derive(Debug, Deserialize, Clone)] +#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] pub struct Script { #[serde(default = "ScriptMode::default")] pub(crate) mode: ScriptMode,