From 7666a09162bf774368097a93294cd10ec82f49c0 Mon Sep 17 00:00:00 2001 From: Clement Tsang <34804052+ClementTsang@users.noreply.github.com> Date: Sun, 16 Jun 2024 19:28:24 -0400 Subject: [PATCH] feat: add way to automatically generate new json schemas (#1482) --- Cargo.lock | 42 ++ Cargo.toml | 8 +- schema/nightly/bottom.json | 1046 +++++++++++++++++++---------- schema/v1.0/bottom.json | 6 +- src/main.rs | 19 + src/options.rs | 2 +- src/options/args.rs | 4 + src/options/colours.rs | 1 + src/options/config.rs | 7 + src/options/config/cpu.rs | 2 + src/options/config/disk.rs | 1 + src/options/config/ignore_list.rs | 1 + src/options/config/layout.rs | 3 + src/options/config/network.rs | 1 + src/options/config/process.rs | 1 + src/options/config/temperature.rs | 1 + src/widgets/process_table.rs | 1 + 17 files changed, 789 insertions(+), 357 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 15d246f6..1d72c7e8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -181,6 +181,7 @@ dependencies = [ "ratatui", "regex", "rustix", + "schemars", "serde", "serde_json", "starship-battery", @@ -515,6 +516,12 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" +[[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.11.0" @@ -1152,6 +1159,30 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "schemars" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09c024468a378b7e36765cd36702b7a90cc3cba11654f6685c8f233408e89e92" +dependencies = [ + "dyn-clone", + "schemars_derive", + "serde", + "serde_json", +] + +[[package]] +name = "schemars_derive" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1eee588578aff73f856ab961cd2f79e36bc45d7ded33a7562adba4667aecc0e" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn", +] + [[package]] name = "scopeguard" version = "1.2.0" @@ -1178,6 +1209,17 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_derive_internals" +version = "0.29.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "serde_json" version = "1.0.117" diff --git a/Cargo.toml b/Cargo.toml index 97eda9f9..0edfa260 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,11 +15,13 @@ build = "build.rs" exclude = [ ".cargo-husky/", ".github/", + ".vscode/", "assets/", "desktop/", "docs/", + "flamegraphs/", "sample_configs/", - "schema", + "schema/", "scripts/", "wix/", ".all-contributorsrc", @@ -70,6 +72,7 @@ nvidia = ["nvml-wrapper"] gpu = ["nvidia"] zfs = [] logging = ["fern", "log", "time/local-offset"] +generate_schema = ["schemars", "serde_json"] deploy = ["battery", "gpu", "zfs"] default = ["deploy"] @@ -91,7 +94,9 @@ itertools = "0.13.0" log = { version = "0.4.21", optional = true } nvml-wrapper = { version = "0.10.0", optional = true, features = ["legacy-functions"] } regex = "1.10.4" +schemars = { version = "0.8.21", optional = true } serde = { version = "1.0.203", features = ["derive"] } +serde_json = { version = "1.0.117", optional = true } starship-battery = { version = "0.8.3", optional = true } sysinfo = "=0.30.12" thiserror = "1.0.61" @@ -143,7 +148,6 @@ clap_complete_nushell = "4.5.1" clap_complete_fig = "4.5.0" clap_mangen = "0.2.20" indoc = "2.0.5" -# schemars = "0.8.21" [package.metadata.deb] section = "utility" diff --git a/schema/nightly/bottom.json b/schema/nightly/bottom.json index b1debe2f..ac3ec53f 100644 --- a/schema/nightly/bottom.json +++ b/schema/nightly/bottom.json @@ -1,50 +1,590 @@ { "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "https://github.com/ClementTsang/bottom/tree/main/schema/nightly/schema.json", - "$comment": "https://clementtsang.github.io/bottom/nightly/configuration/config-file", + "$id": "https://github.com/ClementTsang/bottom/blob/main/schema/nightly/bottom.json", "title": "Schema for bottom's configs (nightly)", + "description": "https://clementtsang.github.io/bottom/nightly/configuration/config-file", "type": "object", - "definitions": { - "row": { - "items": { - "properties": { - "ratio": { - "default": 1, - "type": "integer" - }, - "type": { - "enum": ["cpu", "mem", "proc", "net", "temp", "disk", "empty"], - "type": "string" - }, - "default": { - "default": true, - "type": "boolean" - } + "properties": { + "colors": { + "anyOf": [ + { + "$ref": "#/definitions/ColoursConfig" }, - "patternProperties": { - "row(.child)+": { - "$ref": "#/definitions/row" - } - }, - "type": "object" - }, - "type": "array" + { + "type": "null" + } + ] }, - "filter": { - "description": "hide specific temperature sensors, network interfaces, and disks using filters", + "cpu": { + "anyOf": [ + { + "$ref": "#/definitions/CpuConfig" + }, + { + "type": "null" + } + ] + }, + "disk": { + "anyOf": [ + { + "$ref": "#/definitions/DiskConfig" + }, + { + "type": "null" + } + ] + }, + "flags": { + "anyOf": [ + { + "$ref": "#/definitions/FlagConfig" + }, + { + "type": "null" + } + ] + }, + "network": { + "anyOf": [ + { + "$ref": "#/definitions/NetworkConfig" + }, + { + "type": "null" + } + ] + }, + "processes": { + "anyOf": [ + { + "$ref": "#/definitions/ProcessesConfig" + }, + { + "type": "null" + } + ] + }, + "row": { + "type": [ + "array", + "null" + ], + "items": { + "$ref": "#/definitions/row" + } + }, + "temperature": { + "anyOf": [ + { + "$ref": "#/definitions/TempConfig" + }, + { + "type": "null" + } + ] + } + }, + "definitions": { + "ColoursConfig": { + "type": "object", "properties": { + "all_cpu_color": { + "type": [ + "string", + "null" + ] + }, + "arc_color": { + "type": [ + "string", + "null" + ] + }, + "avg_cpu_color": { + "type": [ + "string", + "null" + ] + }, + "border_color": { + "type": [ + "string", + "null" + ] + }, + "cache_color": { + "type": [ + "string", + "null" + ] + }, + "cpu_core_colors": { + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + } + }, + "disabled_text_color": { + "type": [ + "string", + "null" + ] + }, + "gpu_core_colors": { + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + } + }, + "graph_color": { + "type": [ + "string", + "null" + ] + }, + "high_battery_color": { + "type": [ + "string", + "null" + ] + }, + "highlighted_border_color": { + "type": [ + "string", + "null" + ] + }, + "low_battery_color": { + "type": [ + "string", + "null" + ] + }, + "medium_battery_color": { + "type": [ + "string", + "null" + ] + }, + "ram_color": { + "type": [ + "string", + "null" + ] + }, + "rx_color": { + "type": [ + "string", + "null" + ] + }, + "rx_total_color": { + "type": [ + "string", + "null" + ] + }, + "selected_bg_color": { + "type": [ + "string", + "null" + ] + }, + "selected_text_color": { + "type": [ + "string", + "null" + ] + }, + "swap_color": { + "type": [ + "string", + "null" + ] + }, + "table_header_color": { + "type": [ + "string", + "null" + ] + }, + "text_color": { + "type": [ + "string", + "null" + ] + }, + "tx_color": { + "type": [ + "string", + "null" + ] + }, + "tx_total_color": { + "type": [ + "string", + "null" + ] + }, + "widget_title_color": { + "type": [ + "string", + "null" + ] + } + } + }, + "CpuConfig": { + "description": "Process column settings.", + "type": "object", + "properties": { + "default": { + "$ref": "#/definitions/CpuDefault" + } + } + }, + "CpuDefault": { + "description": "The default selection of the CPU widget. If the given selection is invalid, we will fall back to all.", + "type": "string", + "enum": [ + "all", + "average" + ] + }, + "DiskConfig": { + "description": "Disk configuration.", + "type": "object", + "properties": { + "mount_filter": { + "description": "A filter over the mount names.", + "anyOf": [ + { + "$ref": "#/definitions/IgnoreList" + }, + { + "type": "null" + } + ] + }, + "name_filter": { + "description": "A filter over the disk names.", + "anyOf": [ + { + "$ref": "#/definitions/IgnoreList" + }, + { + "type": "null" + } + ] + } + } + }, + "FinalWidget": { + "description": "Represents a widget.", + "type": "object", + "required": [ + "type" + ], + "properties": { + "default": { + "type": [ + "boolean", + "null" + ] + }, + "ratio": { + "type": [ + "integer", + "null" + ], + "format": "uint32", + "minimum": 0.0 + }, + "type": { + "type": "string" + } + } + }, + "FlagConfig": { + "type": "object", + "properties": { + "autohide_time": { + "type": [ + "boolean", + "null" + ] + }, + "basic": { + "type": [ + "boolean", + "null" + ] + }, + "battery": { + "type": [ + "boolean", + "null" + ] + }, + "case_sensitive": { + "type": [ + "boolean", + "null" + ] + }, + "color": { + "description": "For built-in colour palettes.", + "type": [ + "string", + "null" + ] + }, + "cpu_left_legend": { + "type": [ + "boolean", + "null" + ] + }, + "current_usage": { + "type": [ + "boolean", + "null" + ] + }, + "default_time_value": { + "anyOf": [ + { + "$ref": "#/definitions/StringOrNum" + }, + { + "type": "null" + } + ] + }, + "default_widget_count": { + "type": [ + "integer", + "null" + ], + "format": "uint64", + "minimum": 0.0 + }, + "default_widget_type": { + "type": [ + "string", + "null" + ] + }, + "disable_advanced_kill": { + "type": [ + "boolean", + "null" + ] + }, + "disable_click": { + "type": [ + "boolean", + "null" + ] + }, + "dot_marker": { + "type": [ + "boolean", + "null" + ] + }, + "enable_cache_memory": { + "type": [ + "boolean", + "null" + ] + }, + "enable_gpu": { + "type": [ + "boolean", + "null" + ] + }, + "expanded": { + "type": [ + "boolean", + "null" + ] + }, + "group_processes": { + "type": [ + "boolean", + "null" + ] + }, + "hide_avg_cpu": { + "type": [ + "boolean", + "null" + ] + }, + "hide_table_gap": { + "type": [ + "boolean", + "null" + ] + }, + "hide_time": { + "type": [ + "boolean", + "null" + ] + }, + "memory_legend": { + "type": [ + "string", + "null" + ] + }, + "network_legend": { + "type": [ + "string", + "null" + ] + }, + "network_use_binary_prefix": { + "type": [ + "boolean", + "null" + ] + }, + "network_use_bytes": { + "type": [ + "boolean", + "null" + ] + }, + "network_use_log": { + "type": [ + "boolean", + "null" + ] + }, + "no_write": { + "type": [ + "boolean", + "null" + ] + }, + "process_command": { + "type": [ + "boolean", + "null" + ] + }, + "process_memory_as_value": { + "type": [ + "boolean", + "null" + ] + }, + "rate": { + "anyOf": [ + { + "$ref": "#/definitions/StringOrNum" + }, + { + "type": "null" + } + ] + }, + "regex": { + "type": [ + "boolean", + "null" + ] + }, + "retention": { + "anyOf": [ + { + "$ref": "#/definitions/StringOrNum" + }, + { + "type": "null" + } + ] + }, + "show_table_scroll_position": { + "type": [ + "boolean", + "null" + ] + }, + "temperature_type": { + "type": [ + "string", + "null" + ] + }, + "time_delta": { + "anyOf": [ + { + "$ref": "#/definitions/StringOrNum" + }, + { + "type": "null" + } + ] + }, + "tree": { + "type": [ + "boolean", + "null" + ] + }, + "unnormalized_cpu": { + "type": [ + "boolean", + "null" + ] + }, + "use_old_network_legend": { + "type": [ + "boolean", + "null" + ] + }, + "whole_word": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "IgnoreList": { + "type": "object", + "required": [ + "list" + ], + "properties": { + "case_sensitive": { + "default": false, + "type": "boolean" + }, "is_list_ignored": { "default": true, "type": "boolean" }, "list": { - "type": "array" + "type": "array", + "items": { + "type": "string" + } }, "regex": { - "default": true, - "type": "boolean" - }, - "case_sensitive": { "default": false, "type": "boolean" }, @@ -52,334 +592,138 @@ "default": false, "type": "boolean" } - }, - "type": "object" - } - }, - "properties": { - "flags": { - "description": "This group of options represents a command-line flag/option. Flags explicitly added when running (ie: btm -a) will override this config file if an option is also set here", - "properties": { - "hide_avg_cpu": { - "default": false, - "description": "Whether to hide the average cpu entry", - "type": "boolean" - }, - "dot_marker": { - "default": false, - "description": "Whether to use dot markers rather than braille", - "type": "boolean" - }, - "rate": { - "default": 1000, - "description": "The update rate of the application", - "type": "integer" - }, - "cpu_left_legend": { - "default": false, - "description": "Whether to put the CPU legend to the left", - "type": "boolean" - }, - "current_usage": { - "default": false, - "description": "Whether to set CPU% on a process to be based on the total CPU or just current usage", - "type": "boolean" - }, - "unnormalized_cpu": { - "default": false, - "description": "Whether to set CPU% on a process to be based on the total CPU or per-core CPU% (not divided by the number of cpus)", - "type": "boolean" - }, - "group_processes": { - "default": false, - "description": "Whether to group processes with the same name together by default", - "type": "boolean" - }, - "case_sensitive": { - "default": false, - "description": "Whether to make process searching case sensitive by default", - "type": "boolean" - }, - "whole_word": { - "default": false, - "description": "Whether to make process searching look for matching the entire word by default", - "type": "boolean" - }, - "regex": { - "default": false, - "description": "Whether to make process searching use regex by default", - "type": "boolean" - }, - "temperature_type": { - "default": "k", - "enum": ["k", "f", "c", "kelvin", "fahrenheit", "celsius"], - "description": "Defaults to Celsius", - "type": "string" - }, - "default_time_value": { - "default": 60000, - "description": "The default time interval in milliseconds", - "type": "integer" - }, - "time_delta": { - "default": 15000, - "description": "The time delta on each zoom in/out action in milliseconds", - "type": "integer" - }, - "hide_time": { - "default": false, - "description": "Hides the time scale", - "type": "boolean" - }, - "default_widget_type": { - "default": "proc", - "description": "Override layout default widget", - "type": "string" - }, - "default_widget_count": { - "default": 1, - "description": "Override layout default widget", - "type": "integer" - }, - "expanded": { - "default": true, - "description": "Expand selected widget upon starting the app", - "type": "boolean" - }, - "basic": { - "default": false, - "description": "Use basic mode", - "type": "boolean" - }, - "use_old_network_legend": { - "default": false, - "description": "Use the old network legend style", - "type": "boolean" - }, - "hide_table_gap": { - "default": false, - "description": "Remove space in tables", - "type": "boolean" - }, - "battery": { - "default": false, - "description": "Show the battery widgets", - "type": "boolean" - }, - "disable_click": { - "default": false, - "description": "Disable mouse clicks", - "type": "boolean" - }, - "color": { - "default": "default", - "enum": [ - "default", - "default-light", - "gruvbox", - "gruvbox-light", - "nord", - "nord-light" - ], - "description": "Built-in themes", - "type": "string" - }, - "mem_as_value": { - "default": false, - "description": "Show memory values in the processes widget as values by default", - "type": "boolean" - }, - "tree": { - "default": false, - "description": "Show tree mode by default in the processes widget", - "type": "boolean" - }, - "show_table_scroll_position": { - "default": false, - "description": "Shows an indicator in table widgets tracking where in the list you are", - "type": "boolean" - }, - "process_command": { - "default": false, - "description": "Show processes as their commands by default in the process widget", - "type": "boolean" - }, - "network_use_binary_prefix": { - "default": false, - "description": "Displays the network widget with binary prefixes", - "type": "boolean" - }, - "network_use_bytes": { - "default": false, - "description": "Displays the network widget using bytes", - "type": "boolean" - }, - "network_use_log": { - "default": false, - "description": "Displays the network widget with a log scale", - "type": "boolean" - }, - "disable_advanced_kill": { - "default": false, - "description": "Hides advanced options to stop a process on Unix-like systems", - "type": "boolean" - }, - "enable_gpu_memory": { - "default": false, - "description": "Shows GPU(s) memory", - "type": "boolean" - }, - "retention": { - "default": "10m", - "description": "How much data is stored at once in terms of time", - "type": "string" - } - }, - "type": "object" + } }, - "colors": { - "description": "These are all the components that support custom theming. Note that colour support will depend on terminal support", + "NetworkConfig": { + "description": "Network configuration.", + "type": "object", "properties": { - "table_header_color": { - "default": "LightBlue", - "description": "Represents the colour of table headers (processes, CPU, disks, temperature)", - "type": "string" - }, - "widget_title_color": { - "default": "Gray", - "description": "Represents the colour of the label each widget has", - "type": "string" - }, - "avg_cpu_color": { - "default": "Red", - "description": "Represents the average CPU color", - "type": "string" - }, - "cpu_core_colors": { + "interface_filter": { + "description": "A filter over the network interface names.", + "anyOf": [ + { + "$ref": "#/definitions/IgnoreList" + }, + { + "type": "null" + } + ] + } + } + }, + "ProcWidgetColumn": { + "description": "A hacky workaround for now.", + "type": "string", + "enum": [ + "PidOrCount", + "ProcNameOrCommand", + "Cpu", + "Mem", + "ReadPerSecond", + "WritePerSecond", + "TotalRead", + "TotalWrite", + "User", + "State", + "Time", + "GpuMem", + "GpuUtil" + ] + }, + "ProcessesConfig": { + "description": "Process configuration.", + "type": "object", + "properties": { + "columns": { + "description": "A list of process widget columns.", + "type": "array", "items": { - "uniqueItems": true, - "minItems": 1, - "type": "string" - }, - "default": [ - "LightMagenta", - "LightYellow", - "LightCyan", - "LightGreen", - "LightBlue", - "LightRed", - "Cyan", - "Green", - "Blue", - "Red" + "$ref": "#/definitions/ProcWidgetColumn" + } + } + } + }, + "RowChildren": { + "description": "Represents a child of a Row - either a Col (column) or a FinalWidget.\n\nA Col can also have an optional length and children. We only allow columns to have FinalWidgets as children, lest we get some amount of mutual recursion between Row and Col.", + "anyOf": [ + { + "$ref": "#/definitions/FinalWidget" + }, + { + "type": "object", + "required": [ + "child" ], - "description": "Represents the colour the core will use in the CPU legend and graph", - "type": "array" - }, - "ram_color": { - "default": "LightMagenta", - "description": "Represents the colour RAM will use in the memory legend and graph", + "properties": { + "child": { + "type": "array", + "items": { + "$ref": "#/definitions/FinalWidget" + } + }, + "ratio": { + "type": [ + "integer", + "null" + ], + "format": "uint32", + "minimum": 0.0 + } + } + } + ] + }, + "StringOrNum": { + "anyOf": [ + { "type": "string" }, - "swap_color": { - "default": "LightYellow", - "description": "Represents the colour SWAP will use in the memory legend and graph", - "type": "string" - }, - "arc_color": { - "default": "LightCyan", - "description": "Represents the colour ARC will use in the memory legend and graph", - "type": "string" - }, - "gpu_core_colors": { - "items": { - "uniqueItems": true, - "minItems": 1, - "type": "string" - }, - "default": [ - "LightGreen", - "LightBlue", - "LightRed", - "Cyan", - "Green", - "Blue", - "Red" - ], - "description": "Represents the colour the GPU will use in the memory legend and graph", - "type": "array" - }, - "rx_color": { - "default": "LightCyan", - "description": "Represents the colour rx will use in the network legend and graph", - "type": "string" - }, - "tx_color": { - "default": "LightGreen", - "description": "Represents the colour tx will use in the network legend and graph", - "type": "string" - }, - "border_color": { - "default": "Gray", - "description": "Represents the colour of the border of unselected widgets", - "type": "string" - }, - "highlighted_border_color": { - "default": "LightBlue", - "description": "Represents the colour of the border of selected widgets", - "type": "string" - }, - "text_color": { - "default": "Gray", - "description": "Represents the colour of most text", - "type": "string" - }, - "selected_text_color": { - "default": "Black", - "description": "Represents the colour of text that is selected", - "type": "string" - }, - "selected_bg_color": { - "default": "LightBlue", - "description": "Represents the background colour of text that is selected", - "type": "string" - }, - "graph_color": { - "default": "Gray", - "description": "Represents the colour of the lines and text of the graph", - "type": "string" - }, - "high_battery_color": { - "default": "green", - "description": "Represents the colours of the battery based on charge", - "type": "string" - }, - "medium_battery_color": { - "default": "yellow", - "description": "Represents the colours of the battery based on charge", - "type": "string" - }, - "low_battery_color": { - "default": "red", - "description": "Represents the colours of the battery based on charge", - "type": "string" + { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + ] + }, + "TempConfig": { + "description": "Temperature configuration.", + "type": "object", + "properties": { + "sensor_filter": { + "description": "A filter over the sensor names.", + "anyOf": [ + { + "$ref": "#/definitions/IgnoreList" + }, + { + "type": "null" + } + ] } } }, "row": { - "$ref": "#/definitions/row" - }, - "disk_filter": { - "$ref": "#/definitions/filter" - }, - "mount_filter": { - "$ref": "#/definitions/filter" - }, - "temp_filter": { - "$ref": "#/definitions/filter" - }, - "net_filter": { - "$ref": "#/definitions/filter" + "description": "Represents a row. This has a length of some sort (optional) and a vector of children.", + "type": "object", + "properties": { + "child": { + "type": [ + "array", + "null" + ], + "items": { + "$ref": "#/definitions/RowChildren" + } + }, + "ratio": { + "type": [ + "integer", + "null" + ], + "format": "uint32", + "minimum": 0.0 + } + } } } } diff --git a/schema/v1.0/bottom.json b/schema/v1.0/bottom.json index adfb8b7f..892405d2 100644 --- a/schema/v1.0/bottom.json +++ b/schema/v1.0/bottom.json @@ -1,8 +1,8 @@ { "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "https://github.com/ClementTsang/bottom/tree/main/schema/nightly/schema.json", - "$comment": "https://clementtsang.github.io/bottom/nightly/configuration/config-file", - "title": "Schema for bottom's configs (v1)", + "$id": "https://github.com/ClementTsang/bottom/blob/main/schema/v1.0/bottom.json", + "$comment": "https://clementtsang.github.io/bottom/0.9.6/configuration/config-file", + "title": "Schema for bottom's configs (v1.0)", "type": "object", "definitions": { "row": { diff --git a/src/main.rs b/src/main.rs index d22e62a7..4f6e4c9f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -283,6 +283,25 @@ fn main() -> anyhow::Result<()> { let args = args::get_args(); + #[cfg(feature = "generate_schema")] + { + if args.other.generate_schema { + let mut schema = schemars::schema_for!(crate::options::config::ConfigV1); + let metadata = schema.schema.metadata.as_mut().unwrap(); + metadata.id = Some( + "https://github.com/ClementTsang/bottom/blob/main/schema/nightly/bottom.json" + .to_string(), + ); + metadata.description = Some( + "https://clementtsang.github.io/bottom/nightly/configuration/config-file" + .to_string(), + ); + println!("{}", serde_json::to_string_pretty(&schema).unwrap()); + + return Ok(()); + } + } + #[cfg(feature = "logging")] { if let Err(err) = init_logger( diff --git a/src/options.rs b/src/options.rs index 345981bd..f45699d1 100644 --- a/src/options.rs +++ b/src/options.rs @@ -1105,7 +1105,7 @@ mod test { // Skip battery since it's tricky to test depending on the platform/features // we're testing with. - let skip = ["help", "version", "celsius", "battery"]; + let skip = ["help", "version", "celsius", "battery", "generate_schema"]; for arg in app.get_arguments().collect::>() { let arg_name = arg diff --git a/src/options/args.rs b/src/options/args.rs index 27c773d7..d8d44f15 100644 --- a/src/options/args.rs +++ b/src/options/args.rs @@ -567,6 +567,10 @@ pub struct OtherArgs { #[arg(short = 'V', long, action = ArgAction::Version, help = "Prints version information.")] version: (), + + #[cfg(feature = "generate_schema")] + #[arg(long, action = ArgAction::SetTrue)] + pub generate_schema: bool, } /// Returns a [`BottomArgs`]. diff --git a/src/options/colours.rs b/src/options/colours.rs index e01e2ed0..1a30dfab 100644 --- a/src/options/colours.rs +++ b/src/options/colours.rs @@ -3,6 +3,7 @@ use std::borrow::Cow; use serde::{Deserialize, Serialize}; #[derive(Clone, Debug, Default, Deserialize, Serialize)] +#[cfg_attr(feature = "generate_schema", derive(schemars::JsonSchema))] pub struct ColoursConfig { pub table_header_color: Option>, pub all_cpu_color: Option>, diff --git a/src/options/config.rs b/src/options/config.rs index 659563bf..da01636d 100644 --- a/src/options/config.rs +++ b/src/options/config.rs @@ -16,6 +16,11 @@ use self::{cpu::CpuConfig, layout::Row, process::ProcessesConfig}; use super::ColoursConfig; #[derive(Clone, Debug, Default, Deserialize)] +#[cfg_attr( + feature = "generate_schema", + derive(schemars::JsonSchema), + schemars(title = "Schema for bottom's configs (nightly)") +)] pub struct ConfigV1 { pub(crate) flags: Option, pub(crate) colors: Option, @@ -29,6 +34,7 @@ pub struct ConfigV1 { #[derive(Clone, Debug, Deserialize, Serialize)] #[serde(untagged)] +#[cfg_attr(feature = "generate_schema", derive(schemars::JsonSchema))] pub(crate) enum StringOrNum { String(String), Num(u64), @@ -47,6 +53,7 @@ impl From for StringOrNum { } #[derive(Clone, Debug, Default, Deserialize, Serialize)] +#[cfg_attr(feature = "generate_schema", derive(schemars::JsonSchema))] pub(crate) struct FlagConfig { pub(crate) hide_avg_cpu: Option, pub(crate) dot_marker: Option, diff --git a/src/options/config/cpu.rs b/src/options/config/cpu.rs index c5af891d..240b070d 100644 --- a/src/options/config/cpu.rs +++ b/src/options/config/cpu.rs @@ -3,6 +3,7 @@ use serde::Deserialize; /// The default selection of the CPU widget. If the given selection is invalid, /// we will fall back to all. #[derive(Clone, Copy, Debug, Default, Deserialize)] +#[cfg_attr(feature = "generate_schema", derive(schemars::JsonSchema))] #[serde(rename_all = "lowercase")] pub enum CpuDefault { #[default] @@ -13,6 +14,7 @@ pub enum CpuDefault { /// Process column settings. #[derive(Clone, Debug, Default, Deserialize)] +#[cfg_attr(feature = "generate_schema", derive(schemars::JsonSchema))] pub struct CpuConfig { #[serde(default)] pub default: CpuDefault, diff --git a/src/options/config/disk.rs b/src/options/config/disk.rs index 355416bc..cc9f3319 100644 --- a/src/options/config/disk.rs +++ b/src/options/config/disk.rs @@ -4,6 +4,7 @@ use super::IgnoreList; /// Disk configuration. #[derive(Clone, Debug, Default, Deserialize)] +#[cfg_attr(feature = "generate_schema", derive(schemars::JsonSchema))] pub struct DiskConfig { /// A filter over the disk names. pub name_filter: Option, diff --git a/src/options/config/ignore_list.rs b/src/options/config/ignore_list.rs index f0d5325b..839d8c49 100644 --- a/src/options/config/ignore_list.rs +++ b/src/options/config/ignore_list.rs @@ -6,6 +6,7 @@ fn default_as_true() -> bool { } #[derive(Clone, Debug, Default, Deserialize, Serialize)] +#[cfg_attr(feature = "generate_schema", derive(schemars::JsonSchema))] pub struct IgnoreList { #[serde(default = "default_as_true")] // TODO: Deprecate and/or rename, current name sounds awful. diff --git a/src/options/config/layout.rs b/src/options/config/layout.rs index b88448fa..8baa3711 100644 --- a/src/options/config/layout.rs +++ b/src/options/config/layout.rs @@ -5,6 +5,7 @@ use crate::{app::layout_manager::*, error::Result}; /// Represents a row. This has a length of some sort (optional) and a vector /// of children. #[derive(Clone, Deserialize, Debug, Serialize)] +#[cfg_attr(feature = "generate_schema", derive(schemars::JsonSchema))] #[serde(rename = "row")] pub struct Row { pub ratio: Option, @@ -214,6 +215,7 @@ impl Row { /// to have FinalWidgets as children, lest we get some amount of mutual /// recursion between Row and Col. #[derive(Clone, Deserialize, Debug, Serialize)] +#[cfg_attr(feature = "generate_schema", derive(schemars::JsonSchema))] #[serde(untagged)] pub enum RowChildren { Widget(FinalWidget), @@ -225,6 +227,7 @@ pub enum RowChildren { /// Represents a widget. #[derive(Clone, Deserialize, Debug, Serialize)] +#[cfg_attr(feature = "generate_schema", derive(schemars::JsonSchema))] pub struct FinalWidget { pub ratio: Option, #[serde(rename = "type")] diff --git a/src/options/config/network.rs b/src/options/config/network.rs index 7e75fdd4..bd52b63d 100644 --- a/src/options/config/network.rs +++ b/src/options/config/network.rs @@ -4,6 +4,7 @@ use super::IgnoreList; /// Network configuration. #[derive(Clone, Debug, Default, Deserialize)] +#[cfg_attr(feature = "generate_schema", derive(schemars::JsonSchema))] pub struct NetworkConfig { /// A filter over the network interface names. pub interface_filter: Option, diff --git a/src/options/config/process.rs b/src/options/config/process.rs index f8bbe866..3a98a912 100644 --- a/src/options/config/process.rs +++ b/src/options/config/process.rs @@ -4,6 +4,7 @@ use crate::widgets::ProcWidgetColumn; /// Process configuration. #[derive(Clone, Debug, Default, Deserialize)] +#[cfg_attr(feature = "generate_schema", derive(schemars::JsonSchema))] pub struct ProcessesConfig { /// A list of process widget columns. #[serde(default)] diff --git a/src/options/config/temperature.rs b/src/options/config/temperature.rs index 266d7406..9423242d 100644 --- a/src/options/config/temperature.rs +++ b/src/options/config/temperature.rs @@ -4,6 +4,7 @@ use super::IgnoreList; /// Temperature configuration. #[derive(Clone, Debug, Default, Deserialize)] +#[cfg_attr(feature = "generate_schema", derive(schemars::JsonSchema))] pub struct TempConfig { /// A filter over the sensor names. pub sensor_filter: Option, diff --git a/src/widgets/process_table.rs b/src/widgets/process_table.rs index 873a8d8a..1b07274b 100644 --- a/src/widgets/process_table.rs +++ b/src/widgets/process_table.rs @@ -111,6 +111,7 @@ pub struct ProcTableConfig { /// A hacky workaround for now. #[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)] +#[cfg_attr(feature = "generate_schema", derive(schemars::JsonSchema))] pub enum ProcWidgetColumn { PidOrCount, ProcNameOrCommand,