automatic layout for vscode

This commit is contained in:
Alex Janka 2024-07-29 12:01:42 +10:00
parent b6bc571b52
commit 761405e7ce
6 changed files with 100 additions and 4 deletions

2
Cargo.lock generated
View file

@ -653,7 +653,7 @@ dependencies = [
[[package]] [[package]]
name = "sway-flash-indicator" name = "sway-flash-indicator"
version = "0.2.1" version = "0.3.0"
dependencies = [ dependencies = [
"directories", "directories",
"futures-util", "futures-util",

View file

@ -1,6 +1,6 @@
[package] [package]
name = "sway-flash-indicator" name = "sway-flash-indicator"
version = "0.2.1" version = "0.3.0"
edition = "2021" edition = "2021"
[dependencies] [dependencies]

View file

@ -1,7 +1,7 @@
# Maintainer: Alex Janka <alex@alexjanka.com> # Maintainer: Alex Janka <alex@alexjanka.com>
pkgname=sway-flash-indicator pkgname=sway-flash-indicator
pkgver=0.2.1 pkgver=0.3.0
pkgrel=1 pkgrel=1
pkgdesc="flashes sway indicator border rather than always showing it" pkgdesc="flashes sway indicator border rather than always showing it"
arch=('x86_64' 'aarch64') arch=('x86_64' 'aarch64')

View file

@ -12,6 +12,7 @@ pub struct Config {
pub flash_colour: Lab, pub flash_colour: Lab,
pub autosplit_enabled: bool, pub autosplit_enabled: bool,
pub autosplit_ratio: f64, pub autosplit_ratio: f64,
pub output_blocklist: Vec<String>,
} }
pub fn parse_config() -> Res<()> { pub fn parse_config() -> Res<()> {
@ -55,6 +56,7 @@ impl Default for Config {
}, },
autosplit_enabled: true, autosplit_enabled: true,
autosplit_ratio: 1.0, autosplit_ratio: 1.0,
output_blocklist: Vec::new(),
} }
} }
} }

View file

@ -14,6 +14,8 @@ pub enum Error {
TomlDe(#[from] toml::de::Error), TomlDe(#[from] toml::de::Error),
#[error(transparent)] #[error(transparent)]
TomlSer(#[from] toml::ser::Error), TomlSer(#[from] toml::ser::Error),
#[error("node not found")]
NodeNotFound,
} }
impl<T> From<tokio::sync::SetError<T>> for Error { impl<T> From<tokio::sync::SetError<T>> for Error {

View file

@ -43,6 +43,7 @@ async fn main() -> Res<()> {
.await?; .await?;
let mut fut: Option<tokio::task::JoinHandle<()>> = None; let mut fut: Option<tokio::task::JoinHandle<()>> = None;
let mut recent_code = None;
while let Some(event) = events.next().await { while let Some(event) = events.next().await {
if let Ok(event) = event { if let Ok(event) = event {
@ -62,9 +63,37 @@ async fn main() -> Res<()> {
swayipc_async::Event::Window(window) swayipc_async::Event::Window(window)
if window.change != swayipc_async::WindowChange::Mark => if window.change != swayipc_async::WindowChange::Mark =>
{ {
let node = window.container;
if window.change == swayipc_async::WindowChange::New
&& node.app_id == Some(String::from("code-url-handler"))
{
recent_code = Some((std::time::Instant::now(), node.id));
} else if recent_code.is_some_and(|(t, _)| {
std::time::Instant::now().duration_since(t)
> std::time::Duration::from_millis(200)
}) {
recent_code = None;
}
if let Some((_, id)) = recent_code {
if id == node.id && window.change == swayipc_async::WindowChange::Focus {
recent_code = None;
log::info!("focused the window we want with id {id}");
if let Err(e) = code_trigger(
&mut autosplit_connection,
id,
&CONFIG.get().unwrap().output_blocklist,
)
.await
{
log::error!("error {e:?} fixing vscode window");
}
}
}
// TODO: also change on window closed - // TODO: also change on window closed -
// the node we're given is the one that closes // the node we're given is the one that closes
let node = window.container;
if node.node_type == swayipc_async::NodeType::Con { if node.node_type == swayipc_async::NodeType::Con {
let (width, height) = (node.window_rect.width, node.window_rect.height); let (width, height) = (node.window_rect.width, node.window_rect.height);
if width == 0 || height == 0 { if width == 0 || height == 0 {
@ -90,6 +119,69 @@ async fn main() -> Res<()> {
Ok(()) Ok(())
} }
async fn code_trigger<T: AsRef<str> + std::cmp::PartialEq<str>>(
connection: &mut swayipc_async::Connection,
id: i64,
output_blocklist: &[T],
) -> Res<()> {
let tree = connection.get_tree().await?;
for workspace in connection.get_workspaces().await? {
let width = workspace.rect.width;
if workspace.focused {
let mut workspace = get_with_id(&tree, workspace.id)?;
if workspace
.output
.as_ref()
.is_some_and(|output| output_blocklist.iter().any(|s| s == output.as_str()))
{
return Ok(());
}
while workspace.focus.len() == 1 {
workspace = get_with_id(workspace, workspace.focus[0])?;
}
if workspace.layout == swayipc_async::NodeLayout::SplitH && workspace.focus.len() == 2 {
let (code, other) = {
let a = get_with_id(&tree, workspace.focus[0])?;
let b = get_with_id(&tree, workspace.focus[1])?;
if contains_child(a, id) {
(a, b)
} else {
(b, a)
}
};
if code.focus.len() > 1 {
log::info!("more than one thing in vscode focus tree");
return Ok(());
}
let (code_rect, other_rect) = (code.rect, other.rect);
if code_rect.x > other_rect.x {
log::info!("focused window is to the right");
connection
.run_command(format!("swap container with con_id {}", other.id))
.await?;
}
connection
.run_command(format!("resize set width {}px", width - 1220))
.await?;
}
}
}
Ok(())
}
fn get_with_id(node: &swayipc_async::Node, id: i64) -> Res<&swayipc_async::Node> {
node.find_as_ref(|n| n.id == id).ok_or(Error::NodeNotFound)
}
fn contains_child(node: &swayipc_async::Node, id: i64) -> bool {
node.find_as_ref(|n| n.id == id).is_some()
}
async fn get_sway_config(connection: &mut swayipc_async::Connection) -> Res<()> { async fn get_sway_config(connection: &mut swayipc_async::Connection) -> Res<()> {
let config = connection.get_config().await?; let config = connection.get_config().await?;
let default_colours = config let default_colours = config