diff --git a/Cargo.lock b/Cargo.lock index 3820d61d..d4430d43 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -67,9 +67,9 @@ dependencies = [ [[package]] name = "bitflags" -version = "1.3.1" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2da1976d75adbe5fbc88130ecd119529cf1cc6a93ae1546d8696ee66f0d21af1" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "cc" @@ -104,9 +104,9 @@ dependencies = [ [[package]] name = "clap" -version = "3.0.0-beta.2" +version = "3.0.0-beta.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bd1061998a501ee7d4b6d449020df3266ca3124b941ec56cf2005c3779ca142" +checksum = "fcd70aa5597dbc42f7217a543f9ef2768b2ef823ba29036072d30e1d88e98406" dependencies = [ "atty", "bitflags", @@ -117,15 +117,14 @@ dependencies = [ "strsim", "termcolor", "textwrap", - "unicode-width", "vec_map", ] [[package]] name = "clap_derive" -version = "3.0.0-beta.2" +version = "3.0.0-beta.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "370f715b81112975b1b69db93e0b56ea4cd4e5002ac43b2da8474106a54096a1" +checksum = "0b5bb0d655624a0b8770d1c178fb8ffcb1f91cc722cb08f451e3dc72465421ac" dependencies = [ "heck", "proc-macro-error", @@ -490,6 +489,7 @@ dependencies = [ "color-eyre", "dirs", "komorebi-core", + "paste", "powershell_script", "serde", "serde_json", @@ -706,9 +706,9 @@ checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" [[package]] name = "os_str_bytes" -version = "2.4.0" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afb2e1c3ee07430c2cf76151675e583e0f19985fa6efae47d6848a3e2c824f85" +checksum = "6acbef58a60fe69ab50510a55bc8cdd4d6cf2283d27ad338f54cb52747a9cf2d" [[package]] name = "owo-colors" @@ -1089,9 +1089,9 @@ dependencies = [ [[package]] name = "textwrap" -version = "0.12.1" +version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "203008d98caf094106cfaba70acfed15e18ed3ddb7d94e49baec153a2b462789" +checksum = "0066c8d12af8b5acd21e00547c3797fde4e8677254a7ee429176ccebbe93dd80" dependencies = [ "unicode-width", ] diff --git a/README.md b/README.md index 7884076f..14bd7a88 100644 --- a/README.md +++ b/README.md @@ -88,9 +88,9 @@ If you have AutoHotKey installed and a `komorebi.ahk` file in your home director PowerShell prompt to find your home directory), `komorebi` will automatically try to load it when starting. If you are experiencing behaviour where -[closing a window leaves a blank tile, but minimizing the same window does not](https://github.com/LGUG2Z/komorebi/issues/6), -you have probably enabled a 'close/minimize to tray' option for that application. You can tell _komorebi_ to handle this -application appropriately by identifying it via the executable name or the window class: +[closing a window leaves a blank tile, but minimizing the same window does not](https://github.com/LGUG2Z/komorebi/issues/6) +, you have probably enabled a 'close/minimize to tray' option for that application. You can tell _komorebi_ to handle +this application appropriately by identifying it via the executable name or the window class: ```powershell komorebic.exe identify-tray-application exe Discord.exe @@ -103,6 +103,10 @@ As previously mentioned, this project does not handle anything related to keybin personally use AutoHotKey to manage my window management shortcuts, and have provided a sample [komorebi.ahk](komorebi.sample.ahk) AHK script that you can use as a starting point for your own. +You can run `komorebic.exe` to get a full list of the commands that you can use to customise `komorebi` and create +keybindings with. You can run `komorebic.exe --help` to get a full explanation of the arguments required for +each command. + ## Features - [x] Multi-monitor diff --git a/bindings/build.rs b/bindings/build.rs index 80b65a0b..3c98669a 100644 --- a/bindings/build.rs +++ b/bindings/build.rs @@ -18,7 +18,8 @@ fn main() { Windows::Win32::System::Threading::AttachThreadInput, Windows::Win32::System::Threading::GetCurrentProcessId, Windows::Win32::UI::KeyboardAndMouseInput::SetFocus, - Windows::Win32::UI::Accessibility::{SetWinEventHook, HWINEVENTHOOK}, + Windows::Win32::UI::Accessibility::SetWinEventHook, + Windows::Win32::UI::Accessibility::HWINEVENTHOOK, // error: `Windows.Win32.UI.WindowsAndMessaging.GWL_EXSTYLE` not found in metadata Windows::Win32::UI::WindowsAndMessaging::*, ); diff --git a/komorebi-core/Cargo.toml b/komorebi-core/Cargo.toml index 83210cc4..d95c40a0 100644 --- a/komorebi-core/Cargo.toml +++ b/komorebi-core/Cargo.toml @@ -8,7 +8,7 @@ edition = "2018" [dependencies] bindings = { package = "bindings", path = "../bindings" } -clap = "3.0.0-beta.2" +clap = "3.0.0-beta.4" color-eyre = "0.5" serde = { version = "1", features = ["derive"] } serde_json = "1" diff --git a/komorebi-core/src/cycle_direction.rs b/komorebi-core/src/cycle_direction.rs index fd11664b..521c804d 100644 --- a/komorebi-core/src/cycle_direction.rs +++ b/komorebi-core/src/cycle_direction.rs @@ -1,12 +1,11 @@ -use clap::Clap; +use clap::ArgEnum; use serde::Deserialize; use serde::Serialize; use strum::Display; use strum::EnumString; -#[derive(Clone, Copy, Debug, Serialize, Deserialize, Display, EnumString)] +#[derive(Clone, Copy, Debug, Serialize, Deserialize, Display, EnumString, ArgEnum)] #[strum(serialize_all = "snake_case")] -#[derive(Clap)] pub enum CycleDirection { Previous, Next, diff --git a/komorebi-core/src/layout.rs b/komorebi-core/src/layout.rs index 7dc401ab..a5960fca 100644 --- a/komorebi-core/src/layout.rs +++ b/komorebi-core/src/layout.rs @@ -1,6 +1,6 @@ use std::num::NonZeroUsize; -use clap::Clap; +use clap::ArgEnum; use serde::Deserialize; use serde::Serialize; use strum::Display; @@ -10,18 +10,16 @@ use crate::OperationDirection; use crate::Rect; use crate::Sizing; -#[derive(Clone, Copy, Debug, Serialize, Deserialize, Display, EnumString)] +#[derive(Clone, Copy, Debug, Serialize, Deserialize, Display, EnumString, ArgEnum)] #[strum(serialize_all = "snake_case")] -#[derive(Clap)] pub enum Layout { BSP, Columns, Rows, } -#[derive(Clone, Copy, Debug, Serialize, Deserialize, Display, EnumString)] +#[derive(Clone, Copy, Debug, Serialize, Deserialize, Display, EnumString, ArgEnum)] #[strum(serialize_all = "snake_case")] -#[derive(Clap)] pub enum LayoutFlip { Horizontal, Vertical, diff --git a/komorebi-core/src/lib.rs b/komorebi-core/src/lib.rs index 27621c6e..631b7407 100644 --- a/komorebi-core/src/lib.rs +++ b/komorebi-core/src/lib.rs @@ -1,6 +1,6 @@ use std::str::FromStr; -use clap::Clap; +use clap::ArgEnum; use color_eyre::Result; use serde::Deserialize; use serde::Serialize; @@ -80,16 +80,16 @@ impl FromStr for SocketMessage { } } -#[derive(Clone, Debug, Serialize, Deserialize, Display, EnumString)] +#[derive(Clone, Debug, Serialize, Deserialize, Display, EnumString, ArgEnum)] #[strum(serialize_all = "snake_case")] pub enum ApplicationIdentifier { Exe, Class, + Title, } -#[derive(Clone, Copy, Debug, Serialize, Deserialize, Display, EnumString)] +#[derive(Clone, Copy, Debug, Serialize, Deserialize, Display, EnumString, ArgEnum)] #[strum(serialize_all = "snake_case")] -#[derive(Clap)] pub enum Sizing { Increase, Decrease, diff --git a/komorebi-core/src/operation_direction.rs b/komorebi-core/src/operation_direction.rs index 4913e24f..4e19281f 100644 --- a/komorebi-core/src/operation_direction.rs +++ b/komorebi-core/src/operation_direction.rs @@ -1,4 +1,4 @@ -use clap::Clap; +use clap::ArgEnum; use serde::Deserialize; use serde::Serialize; use strum::Display; @@ -7,9 +7,8 @@ use strum::EnumString; use crate::Layout; use crate::LayoutFlip; -#[derive(Clone, Copy, Debug, Serialize, Deserialize, Display, EnumString)] +#[derive(Clone, Copy, Debug, Serialize, Deserialize, Display, EnumString, ArgEnum)] #[strum(serialize_all = "snake_case")] -#[derive(Clap)] pub enum OperationDirection { Left, Right, diff --git a/komorebi.sample.ahk b/komorebi.sample.ahk index 9f4918b7..4dea28f6 100644 --- a/komorebi.sample.ahk +++ b/komorebi.sample.ahk @@ -1,50 +1,49 @@ #SingleInstance Force ; Enable hot reloading of changes to this file -Run, komorebic.exe watch-configuration enable +Run, komorebic.exe watch-configuration enable, , Hide ; Enable focus follows mouse -Run, komorebic.exe focus-follows-mouse enable +Run, komorebic.exe focus-follows-mouse enable, , Hide ; Ensure there are 3 workspaces created on monitor 0 -Run, komorebic.exe ensure-workspaces 0 5 +Run, komorebic.exe ensure-workspaces 0 5, , Hide ; Give the workspaces some optional names -Run, komorebic.exe workspace-name 0 0 bsp -Run, komorebic.exe workspace-name 0 1 columns -Run, komorebic.exe workspace-name 0 2 thicc -Run, komorebic.exe workspace-name 0 3 matrix -Run, komorebic.exe workspace-name 0 4 floaty +Run, komorebic.exe workspace-name 0 0 bsp, , Hide +Run, komorebic.exe workspace-name 0 1 columns, , Hide +Run, komorebic.exe workspace-name 0 2 thicc, , Hide +Run, komorebic.exe workspace-name 0 3 matrix, , Hide +Run, komorebic.exe workspace-name 0 4 floaty, , Hide ; Set the padding of the different workspaces -Run, komorebic.exe workspace-padding 0 1 30 -Run, komorebic.exe container-padding 0 1 30 -Run, komorebic.exe workspace-padding 0 2 200 -Run, komorebic.exe workspace-padding 0 3 0 -Run, komorebic.exe container-padding 0 3 0 +Run, komorebic.exe workspace-padding 0 1 30, , Hide +Run, komorebic.exe container-padding 0 1 30, , Hide +Run, komorebic.exe workspace-padding 0 2 200, , Hide +Run, komorebic.exe workspace-padding 0 3 0, , Hide +Run, komorebic.exe container-padding 0 3 0, , Hide ; Set the layouts of different workspaces -Run, komorebic.exe workspace-layout 0 1 columns +Run, komorebic.exe workspace-layout 0 1 columns, , Hide ; Set the floaty layout to not tile any windows -Run, komorebic.exe workspace-tiling 0 4 off +Run, komorebic.exe workspace-tiling 0 4 disable, , Hide ; Always float IntelliJ popups, matching on class -Run, komorebic.exe float-class SunAwtDialog, , Hide +Run, komorebic.exe float-rule class SunAwtDialog, , Hide ; Always float Control Panel, matching on title -Run, komorebic.exe float-title "Control Panel", , Hide +Run, komorebic.exe float-rule title "Control Panel", , Hide ; Always float Task Manager, matching on class -Run, komorebic.exe float-class TaskManagerWindow, , Hide +Run, komorebic.exe float-rule class TaskManagerWindow, , Hide ; Always float Wally, matching on executable name -Run, komorebic.exe float-exe Wally.exe, , Hide -Run, komorebic.exe float-exe wincompose.exe, , Hide +Run, komorebic.exe float-rule exe Wally.exe, , Hide +Run, komorebic.exe float-rule exe wincompose.exe, , Hide ; Always float Calculator app, matching on window title -Run, komorebic.exe float-title Calculator, , Hide -Run, komorebic.exe float-exe 1Password.exe, , Hide +Run, komorebic.exe float-rule title Calculator, , Hide +Run, komorebic.exe float-rule exe 1Password.exe, , Hide ; Identify applications that close to the tray Run, komorebic.exe identify-tray-application exe Discord.exe, , Hide -Run, komorebic.exe identify-tray-application exe Telegram.exe, , Hide ; Change the focused window, Alt + Vim direction keys !h:: @@ -65,36 +64,36 @@ return ; Move the focused window in a given direction, Alt + Shift + Vim direction keys !+h:: -Run, komorebic.exe move left, Hide +Run, komorebic.exe move left, , Hide return !+j:: -Run, komorebic.exe move down, Hide +Run, komorebic.exe move down, , Hide return !+k:: -Run, komorebic.exe move up, Hide +Run, komorebic.exe move up, , Hide return !+l:: -Run, komorebic.exe move right, Hide +Run, komorebic.exe move right, , Hide return ; Stack the focused window in a given direction, Alt + Shift + direction keys !+Left:: -Run, komorebic.exe stack left, Hide +Run, komorebic.exe stack left, , Hide return !+Down:: -Run, komorebic.exe stack down, Hide +Run, komorebic.exe stack down, , Hide return !+Up:: -Run, komorebic.exe stack up, Hide +Run, komorebic.exe stack up, , Hide return !+Right:: -Run, komorebic.exe stack right, Hide +Run, komorebic.exe stack right, , Hide return !]:: @@ -107,102 +106,102 @@ return ; Unstack the focused window, Alt + Shift + D !+d:: -Run, komorebic.exe unstack, Hide +Run, komorebic.exe unstack, , Hide return ; Promote the focused window to the top of the tree, Alt + Shift + Enter !+Enter:: -Run, komorebic.exe promote, Hide +Run, komorebic.exe promote, , Hide return ; Switch to an equal-width, max-height column layout on the main workspace, Alt + Shift + C !+c:: -Run, komorebic.exe workspace-layout 0 0 columns, Hide +Run, komorebic.exe workspace-layout 0 0 columns, , Hide return ; Switch to the default bsp tiling layout on the main workspace, Alt + Shift + T !+t:: -Run, komorebic.exe workspace-layout 0 0 bsp, Hide +Run, komorebic.exe workspace-layout 0 0 bsp, , Hide return ; Toggle the Monocle layout for the focused window, Alt + Shift + F !+f:: -Run, komorebic.exe toggle-monocle, Hide +Run, komorebic.exe toggle-monocle, , Hide return ; Flip horizontally, Alt + X !x:: -Run, komorebic.exe flip-layout horizontal, Hide +Run, komorebic.exe flip-layout horizontal, , Hide return ; Flip vertically, Alt + Y !y:: -Run, komorebic.exe flip-layout vertical, Hide +Run, komorebic.exe flip-layout vertical, , Hide return ; Force a retile if things get janky, Alt + Shift + R !+r:: -Run, komorebic.exe retile, Hide +Run, komorebic.exe retile, , Hide return ; Float the focused window, Alt + T !t:: -Run, komorebic.exe toggle-float, Hide +Run, komorebic.exe toggle-float, , Hide return ; Reload ~/komorebi.ahk, Alt + O !o:: -Run, komorebic.exe reload-configuration, Hide +Run, komorebic.exe reload-configuration, , Hide return ; Pause responding to any window events or komorebic commands, Alt + P !p:: -Run, komorebic.exe toggle-pause, Hide +Run, komorebic.exe toggle-pause, , Hide return ; Switch to workspace !1:: Send ! -Run, komorebic.exe focus-workspace 0, Hide +Run, komorebic.exe focus-workspace 0, , Hide return !2:: Send ! -Run, komorebic.exe focus-workspace 1, Hide +Run, komorebic.exe focus-workspace 1, , Hide return !3:: Send ! -Run, komorebic.exe focus-workspace 2, Hide +Run, komorebic.exe focus-workspace 2, , Hide return !4:: Send ! -Run, komorebic.exe focus-workspace 3, Hide +Run, komorebic.exe focus-workspace 3, , Hide return !5:: Send ! -Run, komorebic.exe focus-workspace 4, Hide +Run, komorebic.exe focus-workspace 4, , Hide return ; Move window to workspace !+1:: -Run, komorebic.exe move-to-workspace 0, Hide +Run, komorebic.exe move-to-workspace 0, , Hide return !+2:: -Run, komorebic.exe move-to-workspace 1, Hide +Run, komorebic.exe move-to-workspace 1, , Hide return !+3:: -Run, komorebic.exe move-to-workspace 2, Hide +Run, komorebic.exe move-to-workspace 2, , Hide return !+4:: -Run, komorebic.exe move-to-workspace 3, Hide +Run, komorebic.exe move-to-workspace 3, , Hide return !+5:: -Run, komorebic.exe move-to-workspace 4, Hide +Run, komorebic.exe move-to-workspace 4, , Hide return diff --git a/komorebi/src/process_command.rs b/komorebi/src/process_command.rs index 4ce3d65f..9fa9fda7 100644 --- a/komorebi/src/process_command.rs +++ b/komorebi/src/process_command.rs @@ -193,6 +193,7 @@ impl WindowManager { classes.push(id); } } + ApplicationIdentifier::Title => {} }, } diff --git a/komorebic/Cargo.toml b/komorebic/Cargo.toml index b460c1a4..5f505687 100644 --- a/komorebic/Cargo.toml +++ b/komorebic/Cargo.toml @@ -9,9 +9,10 @@ edition = "2018" bindings = { package = "bindings", path = "../bindings" } komorebi-core = { path = "../komorebi-core" } -clap = "3.0.0-beta.2" +clap = "3.0.0-beta.4" color-eyre = "0.5" dirs = "3" +paste = "1" powershell_script = "0.2" serde = { version = "1", features = ["derive"] } serde_json = "1" diff --git a/komorebic/src/main.rs b/komorebic/src/main.rs index 65ce1c9e..19f0f099 100644 --- a/komorebic/src/main.rs +++ b/komorebic/src/main.rs @@ -4,6 +4,8 @@ use std::io::BufReader; use std::io::ErrorKind; use std::io::Write; +use clap::AppSettings; +use clap::ArgEnum; use clap::Clap; use color_eyre::eyre::ContextCompat; use color_eyre::Result; @@ -22,8 +24,129 @@ use komorebi_core::OperationDirection; use komorebi_core::Sizing; use komorebi_core::SocketMessage; +#[derive(ArgEnum)] +enum BooleanState { + Enable, + Disable, +} + +impl From for bool { + fn from(b: BooleanState) -> Self { + match b { + BooleanState::Enable => true, + BooleanState::Disable => false, + } + } +} + +macro_rules! gen_enum_subcommand { + ($name:ident, $element:ty) => { + paste::paste! { + #[derive(clap::Clap)] + pub struct $name { + #[clap(arg_enum)] + [<$element:snake>]: $element + } + } + }; +} + +gen_enum_subcommand!(Focus, OperationDirection); +gen_enum_subcommand!(Move, OperationDirection); +gen_enum_subcommand!(Stack, OperationDirection); +gen_enum_subcommand!(CycleStack, CycleDirection); +gen_enum_subcommand!(WatchConfiguration, BooleanState); +gen_enum_subcommand!(FlipLayout, LayoutFlip); +gen_enum_subcommand!(FocusFollowsMouse, BooleanState); + +macro_rules! gen_target_subcommands { + ( $( $name:ident ),+ ) => { + $( + #[derive(clap::Clap)] + pub struct $name { + target: usize, + } + )+ + }; +} + +gen_target_subcommands!(MoveToMonitor, MoveToWorkspace, FocusMonitor, FocusWorkspace); + #[derive(Clap)] -#[clap(version = "1.0", author = "Jade Iqbal ")] +struct Resize { + #[clap(arg_enum)] + edge: OperationDirection, + #[clap(arg_enum)] + sizing: Sizing, +} + +#[derive(Clap)] +struct EnsureWorkspaces { + /// Monitor index (zero-indexed, ie. the primary/first monitor is 0) + monitor: usize, + /// Number of desired workspaces + workspace_count: usize, +} + +#[derive(Clap)] +struct SizeForMonitorWorkspace { + /// Monitor index (zero-indexed, ie. the primary/first monitor is 0) + monitor: usize, + /// Workspace index on the specified monitor (zero-indexed, ie. the first workspace is 0) + workspace: usize, + /// Pixels to pad with as an integer + size: i32, +} + +#[derive(Clap)] +struct WorkspaceName { + /// Monitor index (zero-indexed, ie. the primary/first monitor is 0) + monitor: usize, + /// Workspace index on the specified monitor (zero-indexed, ie. the first workspace is 0) + workspace: usize, + /// Name of the workspace as a string + value: String, +} + +#[derive(Clap)] +struct WorkspaceLayout { + /// Monitor index (zero-indexed, ie. the primary/first monitor is 0) + monitor: usize, + /// Workspace index on the specified monitor (zero-indexed, ie. the first workspace is 0) + workspace: usize, + #[clap(arg_enum)] + layout: Layout, +} + +#[derive(Clap)] +struct WorkspaceTiling { + /// Monitor index (zero-indexed, ie. the primary/first monitor is 0) + monitor: usize, + /// Workspace index on the specified monitor (zero-indexed, ie. the first workspace is 0) + workspace: usize, + #[clap(arg_enum)] + tile: BooleanState, +} + +#[derive(Clap)] +struct ApplicationTarget { + #[clap(arg_enum)] + identifier: ApplicationIdentifier, + /// Identifier as a string + id: String, +} + +#[derive(Clap)] +struct PaddingAdjustment { + #[clap(arg_enum)] + sizing: Sizing, + /// Pixels to adjust by as an integer + adjustment: i32, +} + +#[derive(Clap)] +#[clap(version = "0.1.0", author = "Jade Iqbal ")] +#[clap(setting = AppSettings::DeriveDisplayOrder)] struct Opts { #[clap(subcommand)] subcmd: SubCommand, @@ -31,123 +154,96 @@ struct Opts { #[derive(Clap)] enum SubCommand { - Focus(OperationDirection), - Move(OperationDirection), - Stack(OperationDirection), - Resize(Resize), - Unstack, - CycleStack(CycleDirection), - MoveToMonitor(Target), - MoveToWorkspace(Target), - FocusMonitor(Target), - FocusWorkspace(Target), - NewWorkspace, - Promote, - EnsureWorkspaces(WorkspaceCountForMonitor), - Retile, - ContainerPadding(SizeForMonitorWorkspace), - WorkspacePadding(SizeForMonitorWorkspace), - WorkspaceLayout(LayoutForMonitorWorkspace), - WorkspaceTiling(TilingForMonitorWorkspace), - WorkspaceName(NameForMonitorWorkspace), - ToggleTiling, - ToggleFloat, - TogglePause, - ToggleMonocle, - RestoreWindows, - ReloadConfiguration, - WatchConfiguration(BooleanState), - State, + /// Start komorebi.exe as a background process Start, + /// Stop the komorebi.exe process and restore all hidden windows Stop, - FloatClass(FloatTarget), - FloatExe(FloatTarget), - FloatTitle(FloatTarget), + /// Show a JSON representation of the current window manager state + State, + /// Change focus to the window in the specified direction + #[clap(setting = AppSettings::ArgRequiredElseHelp)] + Focus(Focus), + /// Move the focused window in the specified direction + #[clap(setting = AppSettings::ArgRequiredElseHelp)] + Move(Move), + /// Stack the focused window in the specified direction + #[clap(setting = AppSettings::ArgRequiredElseHelp)] + Stack(Stack), + /// Resize the focused window in the specified direction + #[clap(setting = AppSettings::ArgRequiredElseHelp)] + Resize(Resize), + /// Unstack the focused window + Unstack, + /// Cycle the focused stack in the specified cycle direction + #[clap(setting = AppSettings::ArgRequiredElseHelp)] + CycleStack(CycleStack), + /// Move the focused window to the specified monitor + #[clap(setting = AppSettings::ArgRequiredElseHelp)] + MoveToMonitor(MoveToMonitor), + /// Move the focused window to the specified workspace + #[clap(setting = AppSettings::ArgRequiredElseHelp)] + MoveToWorkspace(MoveToWorkspace), + /// Focus the specified monitor + #[clap(setting = AppSettings::ArgRequiredElseHelp)] + FocusMonitor(FocusMonitor), + /// Focus the specified workspace on the focused monitor + #[clap(setting = AppSettings::ArgRequiredElseHelp)] + FocusWorkspace(FocusWorkspace), + /// Create and append a new workspace on the focused monitor + NewWorkspace, + /// Adjust container padding on the focused workspace + #[clap(setting = AppSettings::ArgRequiredElseHelp)] + AdjustContainerPadding(PaddingAdjustment), + /// Adjust workspace padding on the focused workspace + #[clap(setting = AppSettings::ArgRequiredElseHelp)] + AdjustWorkspacePadding(PaddingAdjustment), + /// Flip the layout on the focused workspace (BSP only) + FlipLayout(FlipLayout), + /// Promote the focused window to the top of the tree + Promote, + /// Force the retiling of all managed windows + Retile, + /// Create at least this many workspaces for the specified monitor + #[clap(setting = AppSettings::ArgRequiredElseHelp)] + EnsureWorkspaces(EnsureWorkspaces), + /// Set the container padding for the specified workspace + #[clap(setting = AppSettings::ArgRequiredElseHelp)] + ContainerPadding(SizeForMonitorWorkspace), + /// Set the workspace padding for the specified workspace + #[clap(setting = AppSettings::ArgRequiredElseHelp)] + WorkspacePadding(SizeForMonitorWorkspace), + /// Set the layout for the specified workspace + #[clap(setting = AppSettings::ArgRequiredElseHelp)] + WorkspaceLayout(WorkspaceLayout), + /// Enable or disable window tiling for the specified workspace + #[clap(setting = AppSettings::ArgRequiredElseHelp)] + WorkspaceTiling(WorkspaceTiling), + /// Set the workspace name for the specified workspace + #[clap(setting = AppSettings::ArgRequiredElseHelp)] + WorkspaceName(WorkspaceName), + /// Toggle the window manager on and off across all monitors + TogglePause, + /// Toggle window tiling on the focused workspace + ToggleTiling, + /// Toggle floating mode for the focused window + ToggleFloat, + /// Toggle monocle mode for the focused container + ToggleMonocle, + /// Restore all hidden windows (debugging command) + RestoreWindows, + /// Reload ~/komorebi.ahk (if it exists) + ReloadConfiguration, + /// Toggle the automatic reloading of ~/komorebi.ahk (if it exists) + #[clap(setting = AppSettings::ArgRequiredElseHelp)] + WatchConfiguration(WatchConfiguration), + /// Add a rule to always float the specified application + #[clap(setting = AppSettings::ArgRequiredElseHelp)] + FloatRule(ApplicationTarget), + /// Identify an application that closes to the system tray + #[clap(setting = AppSettings::ArgRequiredElseHelp)] IdentifyTrayApplication(ApplicationTarget), - AdjustContainerPadding(SizingAdjustment), - AdjustWorkspacePadding(SizingAdjustment), - FlipLayout(LayoutFlip), - FocusFollowsMouse(BooleanState), -} - -#[derive(Clap)] -struct WorkspaceCountForMonitor { - monitor: usize, - workspace_count: usize, -} - -#[derive(Clap)] -struct SizeForMonitorWorkspace { - monitor: usize, - workspace: usize, - size: i32, -} - -#[derive(Clap)] -struct NameForMonitorWorkspace { - monitor: usize, - workspace: usize, - value: String, -} - -#[derive(Clap)] -struct LayoutForMonitorWorkspace { - monitor: usize, - workspace: usize, - layout: Layout, -} - -fn on_or_off(s: &str) -> Result { - match s { - "enable" => Ok(true), - "disable" => Ok(false), - // in order to not break backwards compat for mouse follows focus - "on" => Ok(true), - "off" => Ok(false), - _ => Err("expected `enable` or `disable`"), - } -} - -#[derive(Clap)] -struct TilingForMonitorWorkspace { - monitor: usize, - workspace: usize, - #[clap(parse(try_from_str = on_or_off))] - tile: bool, -} - -#[derive(Clap)] -struct Target { - number: usize, -} - -#[derive(Clap)] -struct SizingAdjustment { - sizing: Sizing, - adjustment: i32, -} - -#[derive(Clap)] -struct FloatTarget { - id: String, -} - -#[derive(Clap)] -struct ApplicationTarget { - identifier: ApplicationIdentifier, - id: String, -} - -#[derive(Clap)] -struct Resize { - edge: OperationDirection, - sizing: Sizing, -} - -#[derive(Clap)] -enum BooleanState { - Enable, - Disable, + /// Enable or disable focus follows mouse for the operating system + FocusFollowsMouse(FocusFollowsMouse), } pub fn send_message(bytes: &[u8]) -> Result<()> { @@ -163,8 +259,8 @@ fn main() -> Result<()> { let opts: Opts = Opts::parse(); match opts.subcmd { - SubCommand::Focus(direction) => { - send_message(&*SocketMessage::FocusWindow(direction).as_bytes()?)?; + SubCommand::Focus(arg) => { + send_message(&*SocketMessage::FocusWindow(arg.operation_direction).as_bytes()?)?; } SubCommand::Promote => { send_message(&*SocketMessage::Promote.as_bytes()?)?; @@ -175,47 +271,35 @@ fn main() -> Result<()> { SubCommand::Retile => { send_message(&*SocketMessage::Retile.as_bytes()?)?; } - SubCommand::Move(direction) => { - send_message(&*SocketMessage::MoveWindow(direction).as_bytes()?)?; + SubCommand::Move(arg) => { + send_message(&*SocketMessage::MoveWindow(arg.operation_direction).as_bytes()?)?; } - SubCommand::MoveToMonitor(display) => { - send_message( - &*SocketMessage::MoveContainerToMonitorNumber(display.number).as_bytes()?, - )?; + SubCommand::MoveToMonitor(arg) => { + send_message(&*SocketMessage::MoveContainerToMonitorNumber(arg.target).as_bytes()?)?; } - SubCommand::MoveToWorkspace(workspace) => { - send_message( - &*SocketMessage::MoveContainerToWorkspaceNumber(workspace.number).as_bytes()?, - )?; + SubCommand::MoveToWorkspace(arg) => { + send_message(&*SocketMessage::MoveContainerToWorkspaceNumber(arg.target).as_bytes()?)?; } - SubCommand::ContainerPadding(gap) => { + SubCommand::ContainerPadding(arg) => { send_message( - &*SocketMessage::ContainerPadding(gap.monitor, gap.workspace, gap.size) + &*SocketMessage::ContainerPadding(arg.monitor, arg.workspace, arg.size) .as_bytes()?, )?; } - SubCommand::WorkspacePadding(gap) => { + SubCommand::WorkspacePadding(arg) => { send_message( - &*SocketMessage::WorkspacePadding(gap.monitor, gap.workspace, gap.size) + &*SocketMessage::WorkspacePadding(arg.monitor, arg.workspace, arg.size) .as_bytes()?, )?; } - SubCommand::AdjustWorkspacePadding(sizing_adjustment) => { + SubCommand::AdjustWorkspacePadding(arg) => { send_message( - &*SocketMessage::AdjustWorkspacePadding( - sizing_adjustment.sizing, - sizing_adjustment.adjustment, - ) - .as_bytes()?, + &*SocketMessage::AdjustWorkspacePadding(arg.sizing, arg.adjustment).as_bytes()?, )?; } - SubCommand::AdjustContainerPadding(sizing_adjustment) => { + SubCommand::AdjustContainerPadding(arg) => { send_message( - &*SocketMessage::AdjustContainerPadding( - sizing_adjustment.sizing, - sizing_adjustment.adjustment, - ) - .as_bytes()?, + &*SocketMessage::AdjustContainerPadding(arg.sizing, arg.adjustment).as_bytes()?, )?; } SubCommand::ToggleTiling => { @@ -227,15 +311,15 @@ fn main() -> Result<()> { SubCommand::ToggleMonocle => { send_message(&*SocketMessage::ToggleMonocle.as_bytes()?)?; } - SubCommand::WorkspaceLayout(layout) => { + SubCommand::WorkspaceLayout(arg) => { send_message( - &*SocketMessage::WorkspaceLayout(layout.monitor, layout.workspace, layout.layout) + &*SocketMessage::WorkspaceLayout(arg.monitor, arg.workspace, arg.layout) .as_bytes()?, )?; } - SubCommand::WorkspaceTiling(layout) => { + SubCommand::WorkspaceTiling(arg) => { send_message( - &*SocketMessage::WorkspaceTiling(layout.monitor, layout.workspace, layout.tile) + &*SocketMessage::WorkspaceTiling(arg.monitor, arg.workspace, arg.tile.into()) .as_bytes()?, )?; } @@ -253,32 +337,34 @@ fn main() -> Result<()> { SubCommand::Stop => { send_message(&*SocketMessage::Stop.as_bytes()?)?; } - SubCommand::FloatClass(target) => { - send_message(&*SocketMessage::FloatClass(target.id).as_bytes()?)?; - } - SubCommand::FloatExe(target) => { - send_message(&*SocketMessage::FloatExe(target.id).as_bytes()?)?; - } - SubCommand::FloatTitle(target) => { - send_message(&*SocketMessage::FloatTitle(target.id).as_bytes()?)?; - } - SubCommand::Stack(direction) => { - send_message(&*SocketMessage::StackWindow(direction).as_bytes()?)?; + SubCommand::FloatRule(arg) => match arg.identifier { + ApplicationIdentifier::Exe => { + send_message(&*SocketMessage::FloatExe(arg.id).as_bytes()?)?; + } + ApplicationIdentifier::Class => { + send_message(&*SocketMessage::FloatClass(arg.id).as_bytes()?)?; + } + ApplicationIdentifier::Title => { + send_message(&*SocketMessage::FloatTitle(arg.id).as_bytes()?)?; + } + }, + SubCommand::Stack(arg) => { + send_message(&*SocketMessage::StackWindow(arg.operation_direction).as_bytes()?)?; } SubCommand::Unstack => { send_message(&*SocketMessage::UnstackWindow.as_bytes()?)?; } - SubCommand::CycleStack(direction) => { - send_message(&*SocketMessage::CycleStack(direction).as_bytes()?)?; + SubCommand::CycleStack(arg) => { + send_message(&*SocketMessage::CycleStack(arg.cycle_direction).as_bytes()?)?; } - SubCommand::FlipLayout(flip) => { - send_message(&*SocketMessage::FlipLayout(flip).as_bytes()?)?; + SubCommand::FlipLayout(arg) => { + send_message(&*SocketMessage::FlipLayout(arg.layout_flip).as_bytes()?)?; } - SubCommand::FocusMonitor(target) => { - send_message(&*SocketMessage::FocusMonitorNumber(target.number).as_bytes()?)?; + SubCommand::FocusMonitor(arg) => { + send_message(&*SocketMessage::FocusMonitorNumber(arg.target).as_bytes()?)?; } - SubCommand::FocusWorkspace(target) => { - send_message(&*SocketMessage::FocusWorkspaceNumber(target.number).as_bytes()?)?; + SubCommand::FocusWorkspace(arg) => { + send_message(&*SocketMessage::FocusWorkspaceNumber(arg.target).as_bytes()?)?; } SubCommand::NewWorkspace => { send_message(&*SocketMessage::NewWorkspace.as_bytes()?)?; @@ -344,8 +430,8 @@ fn main() -> Result<()> { SubCommand::Resize(resize) => { send_message(&*SocketMessage::ResizeWindow(resize.edge, resize.sizing).as_bytes()?)?; } - SubCommand::FocusFollowsMouse(enable) => { - let enable = match enable { + SubCommand::FocusFollowsMouse(arg) => { + let enable = match arg.boolean_state { BooleanState::Enable => true, BooleanState::Disable => false, }; @@ -355,8 +441,8 @@ fn main() -> Result<()> { SubCommand::ReloadConfiguration => { send_message(&*SocketMessage::ReloadConfiguration.as_bytes()?)?; } - SubCommand::WatchConfiguration(enable) => { - let enable = match enable { + SubCommand::WatchConfiguration(arg) => { + let enable = match arg.boolean_state { BooleanState::Enable => true, BooleanState::Disable => false, };