diff --git a/Cargo.lock b/Cargo.lock index 79d6e345..a1ed6da9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1051,6 +1051,15 @@ dependencies = [ "terminal_size", ] +[[package]] +name = "clap_complete" +version = "4.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "037e2a1a92236d0aff7e845093f64661d6df4c02c9fcc61a60e9e1d736fa392f" +dependencies = [ + "clap", +] + [[package]] name = "clap_derive" version = "4.6.7" @@ -3576,6 +3585,7 @@ name = "komorebic-core" version = "0.1.42" dependencies = [ "clap", + "clap_complete", "komorebi-layouts", "komorebi-protocol", ] diff --git a/crates/komorebic-core/Cargo.toml b/crates/komorebic-core/Cargo.toml index fa8e653e..2901be3e 100644 --- a/crates/komorebic-core/Cargo.toml +++ b/crates/komorebic-core/Cargo.toml @@ -6,5 +6,6 @@ edition = "2024" [dependencies] clap = { workspace = true } +clap_complete = "4" komorebi-layouts = { path = "../../komorebi-layouts" } komorebi-protocol = { path = "../komorebi-protocol", default-features = false } diff --git a/crates/komorebic-core/examples/docgen-all.rs b/crates/komorebic-core/examples/docgen-all.rs new file mode 100644 index 00000000..042021d9 --- /dev/null +++ b/crates/komorebic-core/examples/docgen-all.rs @@ -0,0 +1,35 @@ +//! Write the pages of `docs/cli` of the platforms that live in this crate, on any host: +//! `cargo run -p komorebic-core --example docgen-all -- OUTDIR [windows|macos]...` +//! writes `OUTDIR//.md` for each platform named (all of them by default). +//! The pages are the ones `komorebic docgen` writes on that platform. + +use komorebic_core::cli::Meta; +use komorebic_core::cli::command; +use komorebic_core::docgen::DocFormat; +use komorebic_core::docgen::write; +use std::path::PathBuf; + +const META: Meta = Meta { + name: "komorebic", + about: "", + author: "", + version: "", +}; + +fn main() -> std::io::Result<()> { + let mut args = std::env::args().skip(1); + let out = PathBuf::from(args.next().expect("usage: docgen-all OUTDIR [platform]...")); + let mut platforms: Vec = args.collect(); + if platforms.is_empty() { + platforms = ["macos"].map(String::from).to_vec(); + } + for platform in platforms { + let cli = match platform.as_str() { + "macos" => command::(&META), + other => panic!("no platform {other} in this crate"), + }; + let pages = write(cli, &DocFormat::PLAIN, &out.join(&platform))?; + println!("{platform}: {} pages", pages.len()); + } + Ok(()) +} diff --git a/crates/komorebic-core/src/lib.rs b/crates/komorebic-core/src/lib.rs index 5355ce5c..d6d0be92 100644 --- a/crates/komorebic-core/src/lib.rs +++ b/crates/komorebic-core/src/lib.rs @@ -6,9 +6,11 @@ //! - [`args`] has the argument blocks the subcommands are built from. //! - [`cli`] has [`cli::Opts`], the command line of a platform, generic over its own subcommands. //! - [`messages`] has the subcommands that are one message to the daemon. +//! - [`platform`] has the subcommands of each platform that are not in [`messages`]. //! - [`docgen`] renders the pages of `docs/cli`. pub mod args; pub mod cli; pub mod docgen; pub mod messages; +pub mod platform; diff --git a/crates/komorebic-core/src/platform/macos.rs b/crates/komorebic-core/src/platform/macos.rs new file mode 100644 index 00000000..f6157902 --- /dev/null +++ b/crates/komorebic-core/src/platform/macos.rs @@ -0,0 +1,428 @@ +//! The subcommands of komorebic for Macos that are not a message to the daemon in every `komorebic`. + +use crate::args::*; +use clap::Parser; +use clap::Subcommand; +use komorebi_layouts::*; +use komorebi_protocol::animation::prefix::AnimationPrefix; +use komorebi_protocol::pathext::replace_env_in_path; +use komorebi_protocol::types::*; +use std::num::NonZeroUsize; +use std::path::PathBuf; + +#[derive(Parser)] +pub struct MonocleFocusBehaviour { + /// Desired monocle focus behaviour + #[clap(value_enum)] + pub behaviour: komorebi_protocol::types::MonocleFocusBehaviour, +} + +#[derive(Parser)] +#[allow(clippy::struct_excessive_bools)] +pub struct Start { + /// Path to a static configuration JSON file + #[clap(short, long)] + #[clap(value_parser = replace_env_in_path)] + pub config: Option, + /// Start komorebi-bar in a background process + #[clap(long)] + pub bar: bool, + // /// Do not attempt to auto-apply a dumped state temp file from a previously running instance of komorebi + // #[clap(long)] + // clean_state: bool, +} + +#[derive(Parser)] +pub struct Stop { + /// Do not restore windows after stopping komorebi + #[clap(long, hide = true)] + pub ignore_restore: bool, + /// Stop komorebi-bar if it is running as a background process + #[clap(long)] + pub bar: bool, +} + +#[derive(Parser)] +pub struct EnableAutostart { + /// Path to a static configuration JSON file + #[clap(action, short, long)] + #[clap(value_parser = replace_env_in_path)] + pub config: Option, + /// Enable autostart of komorebi-bar + #[clap(long)] + pub bar: bool, +} + +#[derive(Parser)] +pub struct EagerFocus { + /// Case-sensitive exe identifier + pub exe: String, +} + +#[derive(Parser)] +pub struct ScrollingLayoutColumns { + /// Number of columns that fit across the screen + pub count: NonZeroUsize, +} + +#[derive(Parser)] +pub struct Pan { + /// The way that the view goes + #[clap( + value_enum, + required_unless_present = "stream", + conflicts_with = "stream" + )] + pub direction: Option, + /// Read the gestures of fingers on a touchpad from standard input, in the gesture stream that + /// whkd writes for a swipe of three or four fingers, and pan with them + #[clap(long)] + pub stream: bool, + /// What the distances of a gesture are multiplied by, which is 1 if it is left out, with + /// --stream + #[clap(long)] + pub sensitivity: Option, + /// Go the other way to the fingers, with --stream + #[clap(long)] + pub reversed: bool, + /// Take a step for every two centimetres that the fingers go, and not move the view with + /// them, with --stream + #[clap(long)] + pub paging: bool, +} + +#[derive(Parser)] +pub struct LayoutRatios { + /// Column width ratios (space-separated values between 0.1 and 0.9) + #[clap(short, long, num_args = 1..)] + pub columns: Option>, + /// Row height ratios (space-separated values between 0.1 and 0.9) + #[clap(short, long, num_args = 1..)] + pub rows: Option>, +} + +#[derive(Parser)] +pub struct BorderColour { + #[clap(value_enum, short, long, default_value = "single")] + pub window_kind: WindowKind, + /// Red + pub r: u32, + /// Green + pub g: u32, + /// Blue + pub b: u32, +} + +#[derive(Parser)] +pub struct Animation { + #[clap(value_enum)] + pub boolean_state: BooleanState, + /// Animation type to apply the state to. If not specified, sets global state + #[clap(value_enum, short, long)] + pub animation_type: Option, +} + +#[derive(Parser)] +pub struct AnimationDuration { + /// Desired animation durations in ms + pub duration: u64, + /// Animation type to apply the duration to. If not specified, sets global duration + #[clap(value_enum, short, long)] + pub animation_type: Option, +} + +#[derive(Parser)] +pub struct AnimationStyle { + /// Desired ease function for animation + #[clap(value_enum, short, long, default_value = "linear")] + pub style: komorebi_protocol::animation::AnimationStyle, + /// Animation type to apply the style to. If not specified, sets global style + #[clap(value_enum, short, long)] + pub animation_type: Option, +} + +#[derive(Parser)] +pub struct Docgen { + /// Output directory for generated documentation files + #[clap(short, long)] + pub output: Option, +} + +#[derive(Parser)] +pub struct Completions { + #[clap(value_enum)] + pub shell: clap_complete::Shell, +} + +#[derive(Parser)] +pub struct License { + /// Email address associated with an Individual Commercial Use License + pub email: String, +} + +#[derive(Parser)] +pub struct Splash { + pub mdm_server: Option, +} + +#[derive(Subcommand)] +pub enum MacosCommands { + #[clap(hide = true)] + Docgen(Docgen), + #[clap(hide = true)] + Splash(Splash), + /// Generate komorebic CLI completions for the target shell + #[clap(arg_required_else_help = true)] + Completions(Completions), + /// Show the System Settings permissions dialogs required by komorebi + Permissions, + /// Gather example configurations for a new-user quickstart + Quickstart, + /// Specify an email associated with an Individual Commercial Use License + #[clap(arg_required_else_help = true)] + License(License), + /// Start komorebi as a background process + Start(Start), + /// Stop the komorebi process and restore all hidden windows + Stop(Stop), + // /// Kill background processes started by komorebic + // Kill(Kill), + // /// Check komorebi configuration and related files for common errors + // Check(Check), + /// Show the path to komorebi.json + #[clap(alias = "config")] + Configuration, + // /// Show the path to komorebi.bar.json + // #[clap(alias = "bar-config")] + // #[clap(alias = "bconfig")] + // BarConfiguration, + // /// Show the path to whkdrc + // #[clap(alias = "whkd")] + // Whkdrc, + /// Show the path to komorebi's data directory in $HOME/Library/Application Support + #[clap(alias = "datadir")] + DataDirectory, + // /// Launch the komorebi-gui debugging tool + // Gui, + // /// Toggle the komorebi-shortcuts helper + // ToggleShortcuts, + // /// Subscribe to komorebi events using a Named Pipe + // #[clap(arg_required_else_help = true)] + // #[clap(alias = "subscribe")] + // SubscribePipe(SubscribePipe), + // /// Unsubscribe from komorebi events + // #[clap(arg_required_else_help = true)] + // #[clap(alias = "unsubscribe")] + // UnsubscribePipe(UnsubscribePipe), + /// Tail komorebi's process logs (cancel with Ctrl-C) + Log, + // /// Forcibly focus the window at the cursor with a left mouse click + // ForceFocus, + /// Focus the first managed window matching the given executable + #[clap(arg_required_else_help = true)] + EagerFocus(EagerFocus), + // /// Set the invisible border dimensions around each window + // #[clap(arg_required_else_help = true)] + // InvisibleBorders(InvisibleBorders), + /// Set how many columns fit across the Scrolling layout on the focused workspace + #[clap(arg_required_else_help = true)] + ScrollingLayoutColumns(ScrollingLayoutColumns), + /// Make the focused column of the Scrolling layout as wide as the screen, or put it back + ScrollingLayoutFullWidth, + /// Scroll the Scrolling layout so that the focused column is in the middle of the screen, once + /// + /// Only the Scrolling layout scrolls, so this does nothing in the other layouts. + CenterFocus, + /// Take the window on one side into the focused column + /// + /// Left takes the last window of the column on the left to the top of the focused column, and + /// right takes the first window of the column on the right to the bottom of it. Up and down do + /// nothing. Only the Scrolling layout has columns of several windows, so this does nothing in + /// the other layouts. + #[clap(arg_required_else_help = true)] + Consume(OneEnum), + /// Take the focused window out of its column and into a column of its own + /// + /// Only the Scrolling layout has columns of several windows, so this does nothing in the other + /// layouts. + Expel, + /// Stack the windows of the focused column, or spread a stack out into a column + /// + /// A column of several windows becomes one stack of all of them, which takes the height of the + /// column and shows one window at a time, and the usual stack commands work on it. A stack + /// becomes a column with a window in each slot, in the order of its tabs. Only the Scrolling + /// layout has columns of several windows, so this does nothing in the other layouts. + ToggleColumnStack, + /// Move the view of the Scrolling layout a column to the left or the right, or with the + /// fingers on a touchpad + /// + /// The strip of columns moves by the width of a new column and comes to rest with a column + /// against an edge of the screen. Focus stays on the column that has it if that is still fully + /// in view, and otherwise goes to the nearest column that is. Only the Scrolling layout has a + /// strip to move, so this does nothing in the other layouts. + /// + /// With --stream the strip follows the fingers as they go, 10 centimetres of travel being the + /// width of the screen, until they lift, and then comes to rest in the column that the speed + /// that they lifted at takes it to. Standard input is the gesture stream that whkd writes on + /// Windows, one message to a line: `begin`, `move dx= t=`, `end` and `cancel`. A + /// gesture that is not finished when standard input closes is given up, and the strip goes back + /// to where it was. + #[clap(arg_required_else_help = true)] + Pan(Pan), + /// Set the layout column and row ratios for the focused workspace + LayoutRatios(LayoutRatios), + // /// Load a custom layout from file for the focused workspace + // #[clap(hide = true)] + // #[clap(arg_required_else_help = true)] + // LoadCustomLayout(LoadCustomLayout), + /// Promote the user focus to the largest window container + PromoteFocus, + /// Force the retiling of all managed windows + /// + /// Every column of a workspace in the Scrolling layout goes back to the width that + /// scrolling-layout-columns gives, and every window in a column of several goes back to an + /// equal share of its height. + Retile, + // /// Set the monitor index preference for a monitor identified using its size + // #[clap(arg_required_else_help = true)] + // MonitorIndexPreference(MonitorIndexPreference), + // /// Set a custom layout for the specified workspace + // #[clap(hide = true)] + // #[clap(arg_required_else_help = true)] + // WorkspaceCustomLayout(WorkspaceCustomLayout), + // /// Set a custom layout for the specified workspace + // #[clap(hide = true)] + // #[clap(arg_required_else_help = true)] + // NamedWorkspaceCustomLayout(NamedWorkspaceCustomLayout), + // /// Add a dynamic custom layout for the specified workspace + // #[clap(hide = true)] + // #[clap(arg_required_else_help = true)] + // WorkspaceCustomLayoutRule(WorkspaceCustomLayoutRule), + // /// Add a dynamic custom layout for the specified workspace + // #[clap(hide = true)] + // #[clap(arg_required_else_help = true)] + // NamedWorkspaceCustomLayoutRule(NamedWorkspaceCustomLayoutRule), + /// Toggle the behaviour for new windows (stacking or dynamic tiling) + ToggleWindowContainerBehaviour, + /// Toggle the behaviour for new windows (stacking or dynamic tiling) for currently focused + /// workspace. If there was no behaviour set for the workspace previously it takes the opposite + /// of the global value. + ToggleWorkspaceWindowContainerBehaviour, + // /// Toggle native maximization for the focused window + // ToggleMaximize, + // /// Restore all hidden windows (debugging command) + // RestoreWindows, + // /// Reload legacy komorebi.ahk or komorebi.ps1 configurations (if they exist) + // ReloadConfiguration, + // /// Enable or disable watching of legacy komorebi.ahk or komorebi.ps1 configurations (if they exist) + // #[clap(arg_required_else_help = true)] + // WatchConfiguration(WatchConfiguration), + // /// For legacy komorebi.ahk or komorebi.ps1 configurations, signal that the final configuration option has been sent + // CompleteConfiguration, + // /// DEPRECATED since v0.1.22 + // #[clap(arg_required_else_help = true)] + // #[clap(hide = true)] + // AltFocusHack(AltFocusHack), + // /// Set the window behaviour when switching workspaces / cycling stacks + // #[clap(arg_required_else_help = true)] + // WindowHidingBehaviour(WindowHidingBehaviour), + /// Set the behaviour when focusing in a direction while a monocle container is active + #[clap(arg_required_else_help = true)] + MonocleFocusBehaviour(MonocleFocusBehaviour), + /// Toggle the behaviour when focusing in a direction while a monocle container is active + ToggleMonocleFocusBehaviour, + /// Set the operation behaviour when the focused window is not managed + #[clap(arg_required_else_help = true)] + UnmanagedWindowOperationBehaviour(OneEnum), + // /// Identify an application that sends EVENT_OBJECT_NAMECHANGE on launch + // #[clap(arg_required_else_help = true)] + // IdentifyObjectNameChangeApplication(IdentifyObjectNameChangeApplication), + // /// Identify an application that closes to the system tray + // #[clap(arg_required_else_help = true)] + // IdentifyTrayApplication(IdentifyTrayApplication), + // /// Identify an application that has WS_EX_LAYERED, but should still be managed + // #[clap(arg_required_else_help = true)] + // IdentifyLayeredApplication(IdentifyLayeredApplication), + // /// Whitelist an application for title bar removal + // #[clap(arg_required_else_help = true)] + // RemoveTitleBar(RemoveTitleBar), + // /// Toggle title bars for whitelisted applications + // ToggleTitleBars, + // /// Identify an application that has overflowing borders + // #[clap(hide = true)] + // #[clap(alias = "identify-border-overflow")] + // IdentifyBorderOverflowApplication(IdentifyBorderOverflowApplication), + /// Set the colour for a window border kind + #[clap(arg_required_else_help = true)] + #[clap(alias = "active-window-border-colour")] + BorderColour(BorderColour), + // /// Set the border style + // #[clap(arg_required_else_help = true)] + // BorderStyle(BorderStyle), + // /// Set the border implementation + // #[clap(arg_required_else_help = true)] + // BorderImplementation(BorderImplementation), + // /// Set the stackbar mode + // #[clap(arg_required_else_help = true)] + // StackbarMode(StackbarMode), + // /// Enable or disable transparency for unfocused windows + // #[clap(arg_required_else_help = true)] + // Transparency(Transparency), + // /// Set the alpha value for unfocused window transparency + // #[clap(arg_required_else_help = true)] + // TransparencyAlpha(TransparencyAlpha), + // /// Toggle transparency for unfocused windows + // ToggleTransparency, + /// Enable or disable movement animations + #[clap(arg_required_else_help = true)] + Animation(Animation), + /// Set the duration for movement animations in ms + #[clap(arg_required_else_help = true)] + AnimationDuration(AnimationDuration), + /// Set the ease function for movement animations + #[clap(arg_required_else_help = true)] + AnimationStyle(AnimationStyle), + // /// Enable or disable focus follows mouse for the operating system + // #[clap(hide = true)] + // #[clap(arg_required_else_help = true)] + // FocusFollowsMouse(FocusFollowsMouse), + // /// Toggle focus follows mouse for the operating system + // #[clap(hide = true)] + // #[clap(arg_required_else_help = true)] + // ToggleFocusFollowsMouse(ToggleFocusFollowsMouse), + // /// Generate common app-specific configurations and fixes to use in komorebi.ahk + // #[clap(arg_required_else_help = true)] + // #[clap(alias = "ahk-asc")] + // AhkAppSpecificConfiguration(AhkAppSpecificConfiguration), + // /// Generate common app-specific configurations and fixes in a PowerShell script + // #[clap(arg_required_else_help = true)] + // #[clap(alias = "pwsh-asc")] + // PwshAppSpecificConfiguration(PwshAppSpecificConfiguration), + // /// Convert a v1 ASC YAML file to a v2 ASC JSON file + // #[clap(arg_required_else_help = true)] + // #[clap(alias = "convert-asc")] + // ConvertAppSpecificConfiguration(ConvertAppSpecificConfiguration), + // /// Format a YAML file for use with the 'app-specific-configuration' command + // #[clap(arg_required_else_help = true)] + // #[clap(alias = "fmt-asc")] + // #[clap(hide = true)] + // FormatAppSpecificConfiguration(FormatAppSpecificConfiguration), + /// Fetch the latest version of applications.json from komorebi-application-specific-configuration + #[clap(alias = "fetch-asc")] + FetchAppSpecificConfiguration, + /// Generate a JSON Schema for applications.json + #[clap(alias = "asc-schema")] + ApplicationSpecificConfigurationSchema, + /// Generate a JSON Schema of subscription notifications + NotificationSchema, + /// Generate a JSON Schema of socket messages + SocketSchema, + /// Generate a JSON Schema of the static configuration file + StaticConfigSchema, + /// Generates a static configuration JSON file based on the current window manager state + GenerateStaticConfig, + /// Generates and loads the com.lgug2z.komorebi.plist file in $HOME/Library/LaunchAgents + EnableAutostart(EnableAutostart), + /// Unloads and deletes the com.lgug2z.komorebi.plist file in $HOME/Library/LaunchAgents + DisableAutostart, +} diff --git a/crates/komorebic-core/src/platform/mod.rs b/crates/komorebic-core/src/platform/mod.rs new file mode 100644 index 00000000..242eabdc --- /dev/null +++ b/crates/komorebic-core/src/platform/mod.rs @@ -0,0 +1,3 @@ +//! The subcommands that a platform has and the others do not, or has differently. + +pub mod macos; diff --git a/komorebi-for-kde/Cargo.lock b/komorebi-for-kde/Cargo.lock index 181c47ac..c953b928 100644 --- a/komorebi-for-kde/Cargo.lock +++ b/komorebi-for-kde/Cargo.lock @@ -2639,6 +2639,7 @@ name = "komorebic-core" version = "0.1.42" dependencies = [ "clap", + "clap_complete", "komorebi-layouts", "komorebi-protocol", ] diff --git a/komorebi-for-mac/Cargo.lock b/komorebi-for-mac/Cargo.lock index 6387320a..0bd36ecd 100644 --- a/komorebi-for-mac/Cargo.lock +++ b/komorebi-for-mac/Cargo.lock @@ -3343,6 +3343,7 @@ name = "komorebic-core" version = "0.1.42" dependencies = [ "clap", + "clap_complete", "komorebi-layouts", "komorebi-protocol", ] diff --git a/komorebi-for-mac/komorebic/src/main.rs b/komorebi-for-mac/komorebic/src/main.rs index 96444dd5..3dff61e8 100644 --- a/komorebi-for-mac/komorebic/src/main.rs +++ b/komorebi-for-mac/komorebic/src/main.rs @@ -1,28 +1,20 @@ #![warn(clippy::all)] use chrono::Utc; -use clap::Parser; -use clap::Subcommand; use color_eyre::eyre; use fs_tail::TailedFile; -use komorebi_client::OperationBehaviour; -use komorebi_client::OperationDirection; -use komorebi_client::PanDirection; use komorebi_client::PathExt; use komorebi_client::SocketMessage; -use komorebi_client::WindowKind; -use komorebi_client::replace_env_in_path; use komorebi_client::send_message; use komorebi_client::send_query; use komorebi_client::splash; use komorebi_client::splash::ValidationFeedback; -use komorebic_core::args::BooleanState; -use komorebic_core::args::OneEnum; use komorebic_core::cli::Cmd; use komorebic_core::cli::Meta; use komorebic_core::cli::command; use komorebic_core::docgen::DocFormat; use komorebic_core::messages::Messages; +use komorebic_core::platform::macos::*; use lazy_static::lazy_static; use std::fs::File; use std::fs::OpenOptions; @@ -30,7 +22,6 @@ use std::io; use std::io::BufRead; use std::io::BufReader; use std::io::Write; -use std::num::NonZeroUsize; use std::path::PathBuf; use std::process::Command; use std::process::Stdio; @@ -64,423 +55,6 @@ lazy_static! { .join("komorebi"); } -#[derive(Parser)] -struct MonocleFocusBehaviour { - /// Desired monocle focus behaviour - #[clap(value_enum)] - behaviour: komorebi_client::MonocleFocusBehaviour, -} - -#[derive(Parser)] -#[allow(clippy::struct_excessive_bools)] -struct Start { - /// Path to a static configuration JSON file - #[clap(short, long)] - #[clap(value_parser = replace_env_in_path)] - config: Option, - /// Start komorebi-bar in a background process - #[clap(long)] - bar: bool, - // /// Do not attempt to auto-apply a dumped state temp file from a previously running instance of komorebi - // #[clap(long)] - // clean_state: bool, -} - -#[derive(Parser)] -struct Stop { - /// Do not restore windows after stopping komorebi - #[clap(long, hide = true)] - ignore_restore: bool, - /// Stop komorebi-bar if it is running as a background process - #[clap(long)] - bar: bool, -} - -#[derive(Parser)] -struct EnableAutostart { - /// Path to a static configuration JSON file - #[clap(action, short, long)] - #[clap(value_parser = replace_env_in_path)] - config: Option, - /// Enable autostart of komorebi-bar - #[clap(long)] - bar: bool, -} - -#[derive(Parser)] -struct EagerFocus { - /// Case-sensitive exe identifier - exe: String, -} - -#[derive(Parser)] -struct ScrollingLayoutColumns { - /// Number of columns that fit across the screen - count: NonZeroUsize, -} - -#[derive(Parser)] -struct Pan { - /// The way that the view goes - #[clap( - value_enum, - required_unless_present = "stream", - conflicts_with = "stream" - )] - direction: Option, - /// Read the gestures of fingers on a touchpad from standard input, in the gesture stream that - /// whkd writes for a swipe of three or four fingers, and pan with them - #[clap(long)] - stream: bool, - /// What the distances of a gesture are multiplied by, which is 1 if it is left out, with - /// --stream - #[clap(long)] - sensitivity: Option, - /// Go the other way to the fingers, with --stream - #[clap(long)] - reversed: bool, - /// Take a step for every two centimetres that the fingers go, and not move the view with - /// them, with --stream - #[clap(long)] - paging: bool, -} - -#[derive(Parser)] -struct LayoutRatios { - /// Column width ratios (space-separated values between 0.1 and 0.9) - #[clap(short, long, num_args = 1..)] - columns: Option>, - /// Row height ratios (space-separated values between 0.1 and 0.9) - #[clap(short, long, num_args = 1..)] - rows: Option>, -} - -#[derive(Parser)] -struct BorderColour { - #[clap(value_enum, short, long, default_value = "single")] - window_kind: WindowKind, - /// Red - r: u32, - /// Green - g: u32, - /// Blue - b: u32, -} - -#[derive(Parser)] -struct Animation { - #[clap(value_enum)] - boolean_state: BooleanState, - /// Animation type to apply the state to. If not specified, sets global state - #[clap(value_enum, short, long)] - animation_type: Option, -} - -#[derive(Parser)] -struct AnimationDuration { - /// Desired animation durations in ms - duration: u64, - /// Animation type to apply the duration to. If not specified, sets global duration - #[clap(value_enum, short, long)] - animation_type: Option, -} - -#[derive(Parser)] -struct AnimationStyle { - /// Desired ease function for animation - #[clap(value_enum, short, long, default_value = "linear")] - style: komorebi_client::AnimationStyle, - /// Animation type to apply the style to. If not specified, sets global style - #[clap(value_enum, short, long)] - animation_type: Option, -} - -#[derive(Parser)] -struct Docgen { - /// Output directory for generated documentation files - #[clap(short, long)] - output: Option, -} - -#[derive(Parser)] -struct Completions { - #[clap(value_enum)] - shell: clap_complete::Shell, -} - -#[derive(Parser)] -struct License { - /// Email address associated with an Individual Commercial Use License - email: String, -} - -#[derive(Parser)] -struct Splash { - mdm_server: Option, -} - -#[derive(Subcommand)] -enum MacosCommands { - #[clap(hide = true)] - Docgen(Docgen), - #[clap(hide = true)] - Splash(Splash), - /// Generate komorebic CLI completions for the target shell - #[clap(arg_required_else_help = true)] - Completions(Completions), - /// Show the System Settings permissions dialogs required by komorebi - Permissions, - /// Gather example configurations for a new-user quickstart - Quickstart, - /// Specify an email associated with an Individual Commercial Use License - #[clap(arg_required_else_help = true)] - License(License), - /// Start komorebi as a background process - Start(Start), - /// Stop the komorebi process and restore all hidden windows - Stop(Stop), - // /// Kill background processes started by komorebic - // Kill(Kill), - // /// Check komorebi configuration and related files for common errors - // Check(Check), - /// Show the path to komorebi.json - #[clap(alias = "config")] - Configuration, - // /// Show the path to komorebi.bar.json - // #[clap(alias = "bar-config")] - // #[clap(alias = "bconfig")] - // BarConfiguration, - // /// Show the path to whkdrc - // #[clap(alias = "whkd")] - // Whkdrc, - /// Show the path to komorebi's data directory in $HOME/Library/Application Support - #[clap(alias = "datadir")] - DataDirectory, - // /// Launch the komorebi-gui debugging tool - // Gui, - // /// Toggle the komorebi-shortcuts helper - // ToggleShortcuts, - // /// Subscribe to komorebi events using a Named Pipe - // #[clap(arg_required_else_help = true)] - // #[clap(alias = "subscribe")] - // SubscribePipe(SubscribePipe), - // /// Unsubscribe from komorebi events - // #[clap(arg_required_else_help = true)] - // #[clap(alias = "unsubscribe")] - // UnsubscribePipe(UnsubscribePipe), - /// Tail komorebi's process logs (cancel with Ctrl-C) - Log, - // /// Forcibly focus the window at the cursor with a left mouse click - // ForceFocus, - /// Focus the first managed window matching the given executable - #[clap(arg_required_else_help = true)] - EagerFocus(EagerFocus), - // /// Set the invisible border dimensions around each window - // #[clap(arg_required_else_help = true)] - // InvisibleBorders(InvisibleBorders), - /// Set how many columns fit across the Scrolling layout on the focused workspace - #[clap(arg_required_else_help = true)] - ScrollingLayoutColumns(ScrollingLayoutColumns), - /// Make the focused column of the Scrolling layout as wide as the screen, or put it back - ScrollingLayoutFullWidth, - /// Scroll the Scrolling layout so that the focused column is in the middle of the screen, once - /// - /// Only the Scrolling layout scrolls, so this does nothing in the other layouts. - CenterFocus, - /// Take the window on one side into the focused column - /// - /// Left takes the last window of the column on the left to the top of the focused column, and - /// right takes the first window of the column on the right to the bottom of it. Up and down do - /// nothing. Only the Scrolling layout has columns of several windows, so this does nothing in - /// the other layouts. - #[clap(arg_required_else_help = true)] - Consume(OneEnum), - /// Take the focused window out of its column and into a column of its own - /// - /// Only the Scrolling layout has columns of several windows, so this does nothing in the other - /// layouts. - Expel, - /// Stack the windows of the focused column, or spread a stack out into a column - /// - /// A column of several windows becomes one stack of all of them, which takes the height of the - /// column and shows one window at a time, and the usual stack commands work on it. A stack - /// becomes a column with a window in each slot, in the order of its tabs. Only the Scrolling - /// layout has columns of several windows, so this does nothing in the other layouts. - ToggleColumnStack, - /// Move the view of the Scrolling layout a column to the left or the right, or with the - /// fingers on a touchpad - /// - /// The strip of columns moves by the width of a new column and comes to rest with a column - /// against an edge of the screen. Focus stays on the column that has it if that is still fully - /// in view, and otherwise goes to the nearest column that is. Only the Scrolling layout has a - /// strip to move, so this does nothing in the other layouts. - /// - /// With --stream the strip follows the fingers as they go, 10 centimetres of travel being the - /// width of the screen, until they lift, and then comes to rest in the column that the speed - /// that they lifted at takes it to. Standard input is the gesture stream that whkd writes on - /// Windows, one message to a line: `begin`, `move dx= t=`, `end` and `cancel`. A - /// gesture that is not finished when standard input closes is given up, and the strip goes back - /// to where it was. - #[clap(arg_required_else_help = true)] - Pan(Pan), - /// Set the layout column and row ratios for the focused workspace - LayoutRatios(LayoutRatios), - // /// Load a custom layout from file for the focused workspace - // #[clap(hide = true)] - // #[clap(arg_required_else_help = true)] - // LoadCustomLayout(LoadCustomLayout), - /// Promote the user focus to the largest window container - PromoteFocus, - /// Force the retiling of all managed windows - /// - /// Every column of a workspace in the Scrolling layout goes back to the width that - /// scrolling-layout-columns gives, and every window in a column of several goes back to an - /// equal share of its height. - Retile, - // /// Set the monitor index preference for a monitor identified using its size - // #[clap(arg_required_else_help = true)] - // MonitorIndexPreference(MonitorIndexPreference), - // /// Set a custom layout for the specified workspace - // #[clap(hide = true)] - // #[clap(arg_required_else_help = true)] - // WorkspaceCustomLayout(WorkspaceCustomLayout), - // /// Set a custom layout for the specified workspace - // #[clap(hide = true)] - // #[clap(arg_required_else_help = true)] - // NamedWorkspaceCustomLayout(NamedWorkspaceCustomLayout), - // /// Add a dynamic custom layout for the specified workspace - // #[clap(hide = true)] - // #[clap(arg_required_else_help = true)] - // WorkspaceCustomLayoutRule(WorkspaceCustomLayoutRule), - // /// Add a dynamic custom layout for the specified workspace - // #[clap(hide = true)] - // #[clap(arg_required_else_help = true)] - // NamedWorkspaceCustomLayoutRule(NamedWorkspaceCustomLayoutRule), - /// Toggle the behaviour for new windows (stacking or dynamic tiling) - ToggleWindowContainerBehaviour, - /// Toggle the behaviour for new windows (stacking or dynamic tiling) for currently focused - /// workspace. If there was no behaviour set for the workspace previously it takes the opposite - /// of the global value. - ToggleWorkspaceWindowContainerBehaviour, - // /// Toggle native maximization for the focused window - // ToggleMaximize, - // /// Restore all hidden windows (debugging command) - // RestoreWindows, - // /// Reload legacy komorebi.ahk or komorebi.ps1 configurations (if they exist) - // ReloadConfiguration, - // /// Enable or disable watching of legacy komorebi.ahk or komorebi.ps1 configurations (if they exist) - // #[clap(arg_required_else_help = true)] - // WatchConfiguration(WatchConfiguration), - // /// For legacy komorebi.ahk or komorebi.ps1 configurations, signal that the final configuration option has been sent - // CompleteConfiguration, - // /// DEPRECATED since v0.1.22 - // #[clap(arg_required_else_help = true)] - // #[clap(hide = true)] - // AltFocusHack(AltFocusHack), - // /// Set the window behaviour when switching workspaces / cycling stacks - // #[clap(arg_required_else_help = true)] - // WindowHidingBehaviour(WindowHidingBehaviour), - /// Set the behaviour when focusing in a direction while a monocle container is active - #[clap(arg_required_else_help = true)] - MonocleFocusBehaviour(MonocleFocusBehaviour), - /// Toggle the behaviour when focusing in a direction while a monocle container is active - ToggleMonocleFocusBehaviour, - /// Set the operation behaviour when the focused window is not managed - #[clap(arg_required_else_help = true)] - UnmanagedWindowOperationBehaviour(OneEnum), - // /// Identify an application that sends EVENT_OBJECT_NAMECHANGE on launch - // #[clap(arg_required_else_help = true)] - // IdentifyObjectNameChangeApplication(IdentifyObjectNameChangeApplication), - // /// Identify an application that closes to the system tray - // #[clap(arg_required_else_help = true)] - // IdentifyTrayApplication(IdentifyTrayApplication), - // /// Identify an application that has WS_EX_LAYERED, but should still be managed - // #[clap(arg_required_else_help = true)] - // IdentifyLayeredApplication(IdentifyLayeredApplication), - // /// Whitelist an application for title bar removal - // #[clap(arg_required_else_help = true)] - // RemoveTitleBar(RemoveTitleBar), - // /// Toggle title bars for whitelisted applications - // ToggleTitleBars, - // /// Identify an application that has overflowing borders - // #[clap(hide = true)] - // #[clap(alias = "identify-border-overflow")] - // IdentifyBorderOverflowApplication(IdentifyBorderOverflowApplication), - /// Set the colour for a window border kind - #[clap(arg_required_else_help = true)] - #[clap(alias = "active-window-border-colour")] - BorderColour(BorderColour), - // /// Set the border style - // #[clap(arg_required_else_help = true)] - // BorderStyle(BorderStyle), - // /// Set the border implementation - // #[clap(arg_required_else_help = true)] - // BorderImplementation(BorderImplementation), - // /// Set the stackbar mode - // #[clap(arg_required_else_help = true)] - // StackbarMode(StackbarMode), - // /// Enable or disable transparency for unfocused windows - // #[clap(arg_required_else_help = true)] - // Transparency(Transparency), - // /// Set the alpha value for unfocused window transparency - // #[clap(arg_required_else_help = true)] - // TransparencyAlpha(TransparencyAlpha), - // /// Toggle transparency for unfocused windows - // ToggleTransparency, - /// Enable or disable movement animations - #[clap(arg_required_else_help = true)] - Animation(Animation), - /// Set the duration for movement animations in ms - #[clap(arg_required_else_help = true)] - AnimationDuration(AnimationDuration), - /// Set the ease function for movement animations - #[clap(arg_required_else_help = true)] - AnimationStyle(AnimationStyle), - // /// Enable or disable focus follows mouse for the operating system - // #[clap(hide = true)] - // #[clap(arg_required_else_help = true)] - // FocusFollowsMouse(FocusFollowsMouse), - // /// Toggle focus follows mouse for the operating system - // #[clap(hide = true)] - // #[clap(arg_required_else_help = true)] - // ToggleFocusFollowsMouse(ToggleFocusFollowsMouse), - // /// Generate common app-specific configurations and fixes to use in komorebi.ahk - // #[clap(arg_required_else_help = true)] - // #[clap(alias = "ahk-asc")] - // AhkAppSpecificConfiguration(AhkAppSpecificConfiguration), - // /// Generate common app-specific configurations and fixes in a PowerShell script - // #[clap(arg_required_else_help = true)] - // #[clap(alias = "pwsh-asc")] - // PwshAppSpecificConfiguration(PwshAppSpecificConfiguration), - // /// Convert a v1 ASC YAML file to a v2 ASC JSON file - // #[clap(arg_required_else_help = true)] - // #[clap(alias = "convert-asc")] - // ConvertAppSpecificConfiguration(ConvertAppSpecificConfiguration), - // /// Format a YAML file for use with the 'app-specific-configuration' command - // #[clap(arg_required_else_help = true)] - // #[clap(alias = "fmt-asc")] - // #[clap(hide = true)] - // FormatAppSpecificConfiguration(FormatAppSpecificConfiguration), - /// Fetch the latest version of applications.json from komorebi-application-specific-configuration - #[clap(alias = "fetch-asc")] - FetchAppSpecificConfiguration, - /// Generate a JSON Schema for applications.json - #[clap(alias = "asc-schema")] - ApplicationSpecificConfigurationSchema, - /// Generate a JSON Schema of subscription notifications - NotificationSchema, - /// Generate a JSON Schema of socket messages - SocketSchema, - /// Generate a JSON Schema of the static configuration file - StaticConfigSchema, - /// Generates a static configuration JSON file based on the current window manager state - GenerateStaticConfig, - /// Generates and loads the com.lgug2z.komorebi.plist file in $HOME/Library/LaunchAgents - EnableAutostart(EnableAutostart), - /// Unloads and deletes the com.lgug2z.komorebi.plist file in $HOME/Library/LaunchAgents - DisableAutostart, -} - fn print_query(message: &SocketMessage) { match send_query(message) { Ok(response) => println!("{response}"),