From b6fc87901a8a2a4c2f02e188b237ee6fb3cb2709 Mon Sep 17 00:00:00 2001 From: Tassilo Horn Date: Thu, 25 Nov 2021 21:19:39 +0100 Subject: [PATCH] New switch-output command --- NEWS.md | 3 +++ src/cmds.rs | 15 +++++++++++++++ src/config.rs | 24 +++++++++++++++++++----- src/tree.rs | 9 ++++++--- 4 files changed, 43 insertions(+), 8 deletions(-) diff --git a/NEWS.md b/NEWS.md index 33fcf6f..6c3b82f 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,6 +1,9 @@ swayr v0.11.0 ============= +- New command: `switch-output` shows all outputs in the menu and focuses the + selected one. Since outputs must now be printable in the menu program, + there's a new `format.output_format` spec. - New command: `configure-outputs` lets you repeatedly issue output commands until you abort the menu program. - Formats can now include a `{output_name}` placeholder which is replaced by diff --git a/src/cmds.rs b/src/cmds.rs index fa82e5e..6da737c 100644 --- a/src/cmds.rs +++ b/src/cmds.rs @@ -71,6 +71,8 @@ pub enum SwayrCommand { SwitchWindow, /// Switch to the selected workspace. SwitchWorkspace, + /// Switch to the selected workspace. + SwitchOutput, /// Switch to the selected workspace or focus the selected window. SwitchWorkspaceOrWindow, /// Switch to the selected workspace or focus the selected container, or @@ -241,6 +243,7 @@ pub fn exec_swayr_cmd(args: ExecSwayrCmdArgs) { SwayrCommand::SwitchWorkspace => { switch_workspace(&*props.read().unwrap()) } + SwayrCommand::SwitchOutput => switch_output(&*props.read().unwrap()), SwayrCommand::SwitchWorkspaceOrWindow => { switch_workspace_or_window(&*props.read().unwrap()) } @@ -370,6 +373,7 @@ pub fn exec_swayr_cmd(args: ExecSwayrCmdArgs) { SwayrCommand::QuitWorkspaceOrWindow, SwayrCommand::SwitchWindow, SwayrCommand::SwitchWorkspace, + SwayrCommand::SwitchOutput, SwayrCommand::SwitchWorkspaceOrWindow, SwayrCommand::SwitchToUrgentOrLRUWindow, SwayrCommand::ConfigureOutputs, @@ -515,6 +519,11 @@ fn handle_non_matching_input(input: &str) { fn select_and_focus(prompt: &str, choices: &[t::DisplayNode]) { match util::select_from_menu(prompt, choices) { Ok(tn) => match tn.node.get_type() { + t::Type::Output => { + if !tn.node.is_scratchpad() { + run_sway_command(&["focus output", tn.node.get_name()]); + } + } t::Type::Workspace => { if !tn.node.is_scratchpad() { run_sway_command(&["workspace", tn.node.get_name()]); @@ -545,6 +554,12 @@ pub fn switch_workspace(extra_props: &HashMap) { select_and_focus("Select workspace", &tree.get_workspaces()); } +pub fn switch_output(extra_props: &HashMap) { + let root = get_tree(false); + let tree = t::get_tree(&root, extra_props); + select_and_focus("Select output", &tree.get_outputs()); +} + pub fn switch_workspace_or_window(extra_props: &HashMap) { let root = get_tree(true); let tree = t::get_tree(&root, extra_props); diff --git a/src/config.rs b/src/config.rs index d350987..a176642 100644 --- a/src/config.rs +++ b/src/config.rs @@ -63,12 +63,12 @@ impl Config { .expect("No menu.args defined.") } - pub fn get_format_window_format(&self) -> String { + pub fn get_format_output_format(&self) -> String { self.format .as_ref() - .and_then(|f| f.window_format.clone()) - .or_else(|| Format::default().window_format) - .expect("No format.window_format defined.") + .and_then(|f| f.output_format.clone()) + .or_else(|| Format::default().output_format) + .expect("No format.output_format defined.") } pub fn get_format_workspace_format(&self) -> String { @@ -87,6 +87,14 @@ impl Config { .expect("No format.container_format defined.") } + pub fn get_format_window_format(&self) -> String { + self.format + .as_ref() + .and_then(|f| f.window_format.clone()) + .or_else(|| Format::default().window_format) + .expect("No format.window_format defined.") + } + pub fn get_format_indent(&self) -> String { self.format .as_ref() @@ -161,9 +169,10 @@ pub struct Menu { #[derive(Debug, Serialize, Deserialize)] pub struct Format { - window_format: Option, + output_format: Option, workspace_format: Option, container_format: Option, + window_format: Option, indent: Option, urgency_start: Option, urgency_end: Option, @@ -215,6 +224,11 @@ impl Default for Menu { impl Default for Format { fn default() -> Self { Format { + output_format: Some( + "{indent}Output {name} \ + ({id})" + .to_string(), + ), workspace_format: Some( "{indent}Workspace {name} [{layout}] \ on output {output_name} \ diff --git a/src/tree.rs b/src/tree.rs index bbe7e00..cd7a4e0 100644 --- a/src/tree.rs +++ b/src/tree.rs @@ -257,8 +257,11 @@ impl<'a> Tree<'a> { } pub fn get_outputs(&self) -> Vec { - let outputs: Vec<&s::Node> = - self.root.iter().filter(|n| !n.is_scratchpad()).collect(); + let outputs: Vec<&s::Node> = self + .root + .iter() + .filter(|n| n.get_type() == Type::Output && !n.is_scratchpad()) + .collect(); self.as_display_nodes(&outputs, IndentLevel::Fixed(0)) } @@ -450,7 +453,7 @@ impl DisplayFormat for DisplayNode<'_> { let fmt = match self.node.get_type() { Type::Root => String::from("Cannot format Root"), - Type::Output => String::from("Cannot format Output"), + Type::Output => cfg.get_format_output_format(), Type::Workspace => cfg.get_format_workspace_format(), Type::Container => cfg.get_format_container_format(), Type::Window => cfg.get_format_window_format(),