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

View File

@@ -9,6 +9,7 @@ use clap::ArgEnum;
use clap::Clap;
use color_eyre::eyre::ContextCompat;
use color_eyre::Result;
use paste::paste;
use uds_windows::UnixListener;
use uds_windows::UnixStream;
@@ -39,38 +40,84 @@ impl From<BooleanState> for bool {
}
}
macro_rules! gen_enum_subcommand {
($name:ident, $element:ty) => {
paste::paste! {
#[derive(clap::Clap)]
pub struct $name {
#[clap(arg_enum)]
[<$element:snake>]: $element
macro_rules! gen_enum_subcommand_args {
// SubCommand Pattern: Enum Type
( $( $name:ident: $element:ty ),+ ) => {
$(
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);
gen_enum_subcommand_args! {
Focus: OperationDirection,
Move: OperationDirection,
Stack: OperationDirection,
CycleStack: CycleDirection,
FlipLayout: LayoutFlip,
WatchConfiguration: BooleanState,
FocusFollowsMouse: BooleanState
}
macro_rules! gen_target_subcommands {
macro_rules! gen_target_subcommand_args {
// SubCommand Pattern
( $( $name:ident ),+ ) => {
$(
#[derive(clap::Clap)]
pub struct $name {
/// Target index (zero-indexed)
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)]
struct Resize {
@@ -82,60 +129,22 @@ struct Resize {
#[derive(Clap)]
struct EnsureWorkspaces {
/// Monitor index (zero-indexed, ie. the primary/first monitor is 0)
/// Monitor index (zero-indexed)
monitor: usize,
/// Number of desired workspaces
workspace_count: usize,
}
#[derive(Clap)]
struct SizeForMonitorWorkspace {
/// Monitor index (zero-indexed, ie. the primary/first monitor is 0)
struct Padding {
/// Monitor index (zero-indexed)
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,
/// 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)]
@@ -144,6 +153,14 @@ struct PaddingAdjustment {
adjustment: i32,
}
#[derive(Clap)]
struct ApplicationTarget {
#[clap(arg_enum)]
identifier: ApplicationIdentifier,
/// Identifier as a string
id: String,
}
#[derive(Clap)]
#[clap(version = "0.1.0", author = "Jade Iqbal <jadeiqbal@fastmail.com>")]
#[clap(setting = AppSettings::DeriveDisplayOrder)]
@@ -208,10 +225,10 @@ enum SubCommand {
EnsureWorkspaces(EnsureWorkspaces),
/// Set the container padding for the specified workspace
#[clap(setting = AppSettings::ArgRequiredElseHelp)]
ContainerPadding(SizeForMonitorWorkspace),
ContainerPadding(Padding),
/// Set the workspace padding for the specified workspace
#[clap(setting = AppSettings::ArgRequiredElseHelp)]
WorkspacePadding(SizeForMonitorWorkspace),
WorkspacePadding(Padding),
/// Set the layout for the specified workspace
#[clap(setting = AppSettings::ArgRequiredElseHelp)]
WorkspaceLayout(WorkspaceLayout),
@@ -313,19 +330,18 @@ fn main() -> Result<()> {
}
SubCommand::WorkspaceLayout(arg) => {
send_message(
&*SocketMessage::WorkspaceLayout(arg.monitor, arg.workspace, arg.layout)
&*SocketMessage::WorkspaceLayout(arg.monitor, arg.workspace, arg.value)
.as_bytes()?,
)?;
}
SubCommand::WorkspaceTiling(arg) => {
send_message(
&*SocketMessage::WorkspaceTiling(arg.monitor, arg.workspace, arg.tile.into())
&*SocketMessage::WorkspaceTiling(arg.monitor, arg.workspace, arg.value.into())
.as_bytes()?,
)?;
}
SubCommand::Start => {
let script = r#"Start-Process komorebi -WindowStyle hidden"#;
match powershell_script::run(script, true) {
match powershell_script::run("Start-Process komorebi -WindowStyle hidden", true) {
Ok(output) => {
println!("{}", output);
}