Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions packages/wm-common/src/app_command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,10 @@ pub enum InvokeCommand {
},
SetMinimized,
SetTiling,
FocusWindow {
#[clap(required = true, trailing_var_arg = true)]
title: Vec<String>,
},
SetTitleBarVisibility {
#[clap(required = true, value_enum)]
visibility: TitleBarVisibility,
Expand Down
1 change: 1 addition & 0 deletions packages/wm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ clap = { workspace = true }
enum-as-inner = "0.6"
futures-util = { workspace = true }
home = { workspace = true }
regex = "1.10.2"
serde = { workspace = true }
serde_json = { workspace = true }
serde_yaml = "0.9"
Expand Down
67 changes: 67 additions & 0 deletions packages/wm/src/commands/general/focus_window.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
use anyhow;
use regex::Regex;
use tracing::info;

use crate::{
commands::{
container::set_focused_descendant,
workspace::focus_workspace,
},
models::WorkspaceTarget,
traits::{WindowGetters, CommonGetters},
wm_state::WmState,
user_config::UserConfig,
};

/// Focus a window where the title matches a given regex pattern.
///
/// If the window is in a different workspace, it will switch to that workspace first.
/// Does nothing if no matching window is found.
pub fn focus_window(
title_regex: &Vec<String>,
state: &mut WmState,
config: &UserConfig,
) -> anyhow::Result<()> {
let pattern_str = title_regex.join(" ");
// Compile the regex pattern
let pattern = Regex::new(&pattern_str)
.map_err(|e| anyhow::anyhow!("Invalid regex pattern: {}", e))?;

// Get all windows and find the first one with a matching title
let windows = state.windows();

for window in windows {
let title = window.native().title()?;

if pattern.is_match(&title) {
info!("Focusing window with title matching pattern '{}': '{}'", pattern_str, title);

// Get the window's workspace
let window_workspace = window.workspace()
.ok_or_else(|| anyhow::anyhow!("Window has no workspace"))?;

// Get the current workspace
let current_workspace = state.focused_container()
.and_then(|focused| focused.workspace())
.ok_or_else(|| anyhow::anyhow!("No workspace is currently focused"))?;

// If the window is in a different workspace, switch to that workspace first
if window_workspace.id() != current_workspace.id() {
focus_workspace(
WorkspaceTarget::Name(window_workspace.config().name.clone()),
state,
config
)?;
}

// Set the matching window as focused
set_focused_descendant(&window.clone().into(), None);
state.pending_sync.queue_focus_change().queue_cursor_jump();

return Ok(());
}
}

info!("No window found with title matching pattern: '{}'", pattern_str);
Ok(())
}
2 changes: 2 additions & 0 deletions packages/wm/src/commands/general/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
mod cycle_focus;
mod disable_binding_mode;
mod enable_binding_mode;
mod focus_window;
mod platform_sync;
mod reload_config;
mod shell_exec;
Expand All @@ -9,6 +10,7 @@ mod toggle_pause;
pub use cycle_focus::*;
pub use disable_binding_mode::*;
pub use enable_binding_mode::*;
pub use focus_window::*;
pub use platform_sync::*;
pub use reload_config::*;
pub use shell_exec::*;
Expand Down
6 changes: 5 additions & 1 deletion packages/wm/src/wm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use crate::{
},
general::{
cycle_focus, disable_binding_mode, enable_binding_mode,
platform_sync, reload_config, shell_exec, toggle_pause,
platform_sync, reload_config, shell_exec, toggle_pause, focus_window,
},
monitor::focus_monitor,
window::{
Expand Down Expand Up @@ -578,6 +578,10 @@ impl WindowManager {
_ => Ok(()),
}
}
InvokeCommand::FocusWindow { title } => {
focus_window(title, state, config)?;
Ok(())
}
InvokeCommand::ShellExec {
hide_window,
command,
Expand Down