refactor(komorebic): gen more clap boilerplate

Following on from the last commit, I jumped on the Rust Community
Discord and @danielhenrymantilla was kind enough to show me a working
example of how an optional macro argument can be used together with
cfg_attr to conditionally add a doc comment.

I took his example and reworked it a little, in the process refactoring
all the macros in the komorebic crate to give them a sense of internal
consistency.
This commit is contained in:
LGUG2Z
2021-08-16 15:20:55 -07:00
parent 9c55545600
commit 4dff452c1f
+81 -65
View File
@@ -9,6 +9,7 @@ use clap::ArgEnum;
use clap::Clap; use clap::Clap;
use color_eyre::eyre::ContextCompat; use color_eyre::eyre::ContextCompat;
use color_eyre::Result; use color_eyre::Result;
use paste::paste;
use uds_windows::UnixListener; use uds_windows::UnixListener;
use uds_windows::UnixStream; use uds_windows::UnixStream;
@@ -39,38 +40,84 @@ impl From<BooleanState> for bool {
} }
} }
macro_rules! gen_enum_subcommand { macro_rules! gen_enum_subcommand_args {
($name:ident, $element:ty) => { // SubCommand Pattern: Enum Type
paste::paste! { ( $( $name:ident: $element:ty ),+ ) => {
#[derive(clap::Clap)] $(
pub struct $name { paste! {
#[clap(arg_enum)] #[derive(clap::Clap)]
[<$element:snake>]: $element pub struct $name {
#[clap(arg_enum)]
[<$element:snake>]: $element
}
} }
} )+
}; };
} }
gen_enum_subcommand!(Focus, OperationDirection); gen_enum_subcommand_args! {
gen_enum_subcommand!(Move, OperationDirection); Focus: OperationDirection,
gen_enum_subcommand!(Stack, OperationDirection); Move: OperationDirection,
gen_enum_subcommand!(CycleStack, CycleDirection); Stack: OperationDirection,
gen_enum_subcommand!(WatchConfiguration, BooleanState); CycleStack: CycleDirection,
gen_enum_subcommand!(FlipLayout, LayoutFlip); FlipLayout: LayoutFlip,
gen_enum_subcommand!(FocusFollowsMouse, BooleanState); WatchConfiguration: BooleanState,
FocusFollowsMouse: BooleanState
}
macro_rules! gen_target_subcommands { macro_rules! gen_target_subcommand_args {
// SubCommand Pattern
( $( $name:ident ),+ ) => { ( $( $name:ident ),+ ) => {
$( $(
#[derive(clap::Clap)] #[derive(clap::Clap)]
pub struct $name { pub struct $name {
/// Target index (zero-indexed)
target: usize, target: usize,
} }
)+ )+
}; };
} }
gen_target_subcommands!(MoveToMonitor, MoveToWorkspace, FocusMonitor, FocusWorkspace); gen_target_subcommand_args! {
MoveToMonitor,
MoveToWorkspace,
FocusMonitor,
FocusWorkspace
}
// Thanks to @danielhenrymantilla for showing me how to use cfr_attr with an optional argument like
// this on the Rust Programming Language Community Discord Server
macro_rules! gen_workspace_subcommand_args {
// Workspace Property: #[enum] Value Enum (if the value is an Enum)
// Workspace Property: Value Type (if the value is anything else)
( $( $name:ident: $(#[enum] $(@$arg_enum:tt)?)? $value:ty ),+ ) => (
paste! {
$(
#[derive(clap::Clap)]
pub struct [<Workspace $name>] {
/// Monitor index (zero-indexed)
monitor: usize,
/// Workspace index on the specified monitor (zero-indexed)
workspace: usize,
$(#[clap(arg_enum)] $($arg_enum)?)?
#[cfg_attr(
all($(FALSE $($arg_enum)?)?),
doc = ""$name" of the workspace as a "$value""
)]
value: $value,
}
)+
}
)
}
gen_workspace_subcommand_args! {
Name: String,
Layout: #[enum] Layout,
Tiling: #[enum] BooleanState
}
#[derive(Clap)] #[derive(Clap)]
struct Resize { struct Resize {
@@ -82,60 +129,22 @@ struct Resize {
#[derive(Clap)] #[derive(Clap)]
struct EnsureWorkspaces { struct EnsureWorkspaces {
/// Monitor index (zero-indexed, ie. the primary/first monitor is 0) /// Monitor index (zero-indexed)
monitor: usize, monitor: usize,
/// Number of desired workspaces /// Number of desired workspaces
workspace_count: usize, workspace_count: usize,
} }
#[derive(Clap)] #[derive(Clap)]
struct SizeForMonitorWorkspace { struct Padding {
/// Monitor index (zero-indexed, ie. the primary/first monitor is 0) /// Monitor index (zero-indexed)
monitor: usize, monitor: usize,
/// Workspace index on the specified monitor (zero-indexed, ie. the first workspace is 0) /// Workspace index on the specified monitor (zero-indexed)
workspace: usize, workspace: usize,
/// Pixels to pad with as an integer /// Pixels to pad with as an integer
size: i32, 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)] #[derive(Clap)]
struct PaddingAdjustment { struct PaddingAdjustment {
#[clap(arg_enum)] #[clap(arg_enum)]
@@ -144,6 +153,14 @@ struct PaddingAdjustment {
adjustment: i32, adjustment: i32,
} }
#[derive(Clap)]
struct ApplicationTarget {
#[clap(arg_enum)]
identifier: ApplicationIdentifier,
/// Identifier as a string
id: String,
}
#[derive(Clap)] #[derive(Clap)]
#[clap(version = "0.1.0", author = "Jade Iqbal <jadeiqbal@fastmail.com>")] #[clap(version = "0.1.0", author = "Jade Iqbal <jadeiqbal@fastmail.com>")]
#[clap(setting = AppSettings::DeriveDisplayOrder)] #[clap(setting = AppSettings::DeriveDisplayOrder)]
@@ -208,10 +225,10 @@ enum SubCommand {
EnsureWorkspaces(EnsureWorkspaces), EnsureWorkspaces(EnsureWorkspaces),
/// Set the container padding for the specified workspace /// Set the container padding for the specified workspace
#[clap(setting = AppSettings::ArgRequiredElseHelp)] #[clap(setting = AppSettings::ArgRequiredElseHelp)]
ContainerPadding(SizeForMonitorWorkspace), ContainerPadding(Padding),
/// Set the workspace padding for the specified workspace /// Set the workspace padding for the specified workspace
#[clap(setting = AppSettings::ArgRequiredElseHelp)] #[clap(setting = AppSettings::ArgRequiredElseHelp)]
WorkspacePadding(SizeForMonitorWorkspace), WorkspacePadding(Padding),
/// Set the layout for the specified workspace /// Set the layout for the specified workspace
#[clap(setting = AppSettings::ArgRequiredElseHelp)] #[clap(setting = AppSettings::ArgRequiredElseHelp)]
WorkspaceLayout(WorkspaceLayout), WorkspaceLayout(WorkspaceLayout),
@@ -313,19 +330,18 @@ fn main() -> Result<()> {
} }
SubCommand::WorkspaceLayout(arg) => { SubCommand::WorkspaceLayout(arg) => {
send_message( send_message(
&*SocketMessage::WorkspaceLayout(arg.monitor, arg.workspace, arg.layout) &*SocketMessage::WorkspaceLayout(arg.monitor, arg.workspace, arg.value)
.as_bytes()?, .as_bytes()?,
)?; )?;
} }
SubCommand::WorkspaceTiling(arg) => { SubCommand::WorkspaceTiling(arg) => {
send_message( send_message(
&*SocketMessage::WorkspaceTiling(arg.monitor, arg.workspace, arg.tile.into()) &*SocketMessage::WorkspaceTiling(arg.monitor, arg.workspace, arg.value.into())
.as_bytes()?, .as_bytes()?,
)?; )?;
} }
SubCommand::Start => { SubCommand::Start => {
let script = r#"Start-Process komorebi -WindowStyle hidden"#; match powershell_script::run("Start-Process komorebi -WindowStyle hidden", true) {
match powershell_script::run(script, true) {
Ok(output) => { Ok(output) => {
println!("{}", output); println!("{}", output);
} }