From 8c054e17bacf60fbcfb963ab7768fdf56ced42ac Mon Sep 17 00:00:00 2001 From: Seaotatop Date: Wed, 21 Jun 2023 17:36:51 -0500 Subject: [PATCH] Add quit function to api, update README and example_config --- README.md | 18 +---- api/lua/example_config.lua | 16 ++-- api/lua/input.lua | 4 +- api/lua/pinnacle.lua | 6 +- src/api.rs | 1 - src/api/msg.rs | 4 + src/input.rs | 48 +++--------- src/state.rs | 155 ++++++++++++++++++++----------------- 8 files changed, 121 insertions(+), 131 deletions(-) diff --git a/README.md b/README.md index c38f2a8..1a29006 100644 --- a/README.md +++ b/README.md @@ -77,7 +77,7 @@ It is *highly* recommended to use the [Lua language server](https://github.com/L Install the [Lua](https://marketplace.visualstudio.com/items?itemName=sumneko.lua) plugin, then go into its settings and add the absolute(?) path to the [`api/lua`](api/lua) directory to Workspace: Library. #### For Neovim: -Pass +Pass this table into your Lua language server settings: ```lua Lua = { workspace = { @@ -87,28 +87,18 @@ Lua = { } } ``` -into your Lua language server settings. Doc website soon:tm: ## Controls The following controls are currently hardcoded: - - `Esc`: Stop Pinnacle - `Ctrl + Left Mouse`: Move a window - `Ctrl + Right Mouse`: Resize a window -The following controls are set in the [`example_config`](api/lua/example_config.lua): - - `Ctrl + Alt + C`: Close the currently focused window - - `Ctrl + Alt + Space`: Toggle "floating" for the currently focused window - - `Ctrl + Return`: Open Alacritty - - `Ctrl + 1`: Open Kitty - - `Ctrl + 2`: Open Foot - - `Ctrl + 3`: Open Nautilus - -"Floating" is in quotes because while windows do currently tile themselves, tiled ones can still be moved just like a floating window. Toggling to and from floating will retile all tiled windows. - -The only layout currently is a master stack with the master on the left side. +You can find the rest of the controls in the [`example_config`](api/lua/example_config.lua). ## A Small Note This is currently just a summer project I'm working on, but I hope that I can work on it enough that it becomes somewhat usable! If development slows down during the rest of the year, it's because :star:university:star:. + +Also the only layout is kinda wonk right now if you close all but one window diff --git a/api/lua/example_config.lua b/api/lua/example_config.lua index 7331547..343fcf1 100644 --- a/api/lua/example_config.lua +++ b/api/lua/example_config.lua @@ -1,10 +1,16 @@ require("pinnacle").setup(function(pinnacle) - local input = pinnacle.input - local client = pinnacle.client - local keys = pinnacle.keys - local process = pinnacle.process + local input = pinnacle.input --Key and mouse binds + local client = pinnacle.client --Window management + local process = pinnacle.process -- Process spawning - input.keybind({ "Alt", "Ctrl" }, keys.c, client.close_window) + -- Every key supported by xkbcommon. + -- Support for just putting in a string of a key is intended. + local keys = input.keys + + -- Keybinds ---------------------------------------------------------------------- + input.keybind({ "Ctrl", "Alt" }, keys.c, client.close_window) + + -- NOTE: In tiled mode you can still move stuff around as if it's floating. Actual tiling is TODO input.keybind({ "Ctrl", "Alt" }, keys.space, client.toggle_floating) input.keybind({ "Ctrl" }, keys.Return, function() diff --git a/api/lua/input.lua b/api/lua/input.lua index 0687172..a9cbb3f 100644 --- a/api/lua/input.lua +++ b/api/lua/input.lua @@ -1,4 +1,6 @@ -local M = {} +local M = { + keys = require("keys"), +} ---Set a keybind. If called on an already existing keybind, it gets replaced. ---@param key Keys The key for the keybind. NOTE: uppercase and lowercase characters are considered different. diff --git a/api/lua/pinnacle.lua b/api/lua/pinnacle.lua index 9937ef5..91bb76c 100644 --- a/api/lua/pinnacle.lua +++ b/api/lua/pinnacle.lua @@ -43,10 +43,14 @@ end local pinnacle = { input = require("input"), client = require("client"), - keys = require("keys"), process = require("process"), } +---Quit Pinnacle. +function pinnacle.quit() + SendMsg("Quit") +end + ---Configure Pinnacle. You should put mostly eveything into the config_func to avoid invalid state. ---The function takes one argument: the Pinnacle table, which is how you'll access all of the available config options. ---@param config_func fun(pinnacle: Pinnacle) diff --git a/src/api.rs b/src/api.rs index 1bbeead..3a0f2eb 100644 --- a/src/api.rs +++ b/src/api.rs @@ -66,7 +66,6 @@ impl PinnacleSocketSource { } } -#[must_use] pub fn send_to_client( stream: &mut UnixStream, msg: &OutgoingMsg, diff --git a/src/api/msg.rs b/src/api/msg.rs index d120542..ce15cc1 100644 --- a/src/api/msg.rs +++ b/src/api/msg.rs @@ -41,6 +41,10 @@ pub enum Msg { #[serde(default)] callback_id: Option, }, + + // Pinnacle management + /// Quit the compositor. + Quit, } #[derive(Debug, PartialEq, Eq, Copy, Clone, serde::Serialize, serde::Deserialize)] diff --git a/src/input.rs b/src/input.rs index 5eb0713..cc6745d 100644 --- a/src/input.rs +++ b/src/input.rs @@ -228,17 +228,6 @@ impl State { { return FilterResult::Intercept(*callback_id); } - match keysym.modified_sym() { - keysyms::KEY_L => return FilterResult::Intercept(100), - keysyms::KEY_K => return FilterResult::Intercept(200), - keysyms::KEY_J => return FilterResult::Intercept(300), - keysyms::KEY_H => return FilterResult::Intercept(400), - keysyms::KEY_Escape => { - state.loop_signal.stop(); - return FilterResult::Intercept(0); - } - _ => {} - } } if keysym.modified_sym() == keysyms::KEY_Control_L { @@ -259,34 +248,19 @@ impl State { self.move_mode = move_mode; - let program = match action { - Some(100) => "alacritty", - Some(200) => "nautilus", - Some(300) => "kitty", - Some(400) => "foot", - Some(callback_id) => { - if let Some(stream) = self.api_state.stream.as_mut() { - if let Err(err) = crate::api::send_to_client( - &mut self.api_state.stream.as_ref().unwrap().lock().unwrap(), - &OutgoingMsg::CallCallback { - callback_id: CallbackId(callback_id), - args: None, - }, - ) { - // TODO: print error - } + if let Some(callback_id) = action { + if let Some(stream) = self.api_state.stream.as_ref() { + if let Err(err) = crate::api::send_to_client( + &mut stream.lock().unwrap(), + &OutgoingMsg::CallCallback { + callback_id: CallbackId(callback_id), + args: None, + }, + ) { + // TODO: print error } - - return; } - None => return, - }; - - tracing::info!("Spawning {}", program); - std::process::Command::new(program) - .env("WAYLAND_DISPLAY", self.socket_name.clone()) - .spawn() - .unwrap(); + } } } diff --git a/src/state.rs b/src/state.rs index 66bf1e0..ba93cff 100644 --- a/src/state.rs +++ b/src/state.rs @@ -118,6 +118,7 @@ impl State { let (tx_channel, rx_channel) = calloop::channel::channel::(); loop_handle.insert_source(rx_channel, |msg, _, data| match msg { Event::Msg(msg) => { + // TODO: move this into its own function match msg { Msg::SetKeybind { key, @@ -162,6 +163,8 @@ impl State { .stdin(if callback_id.is_some() { Stdio::piped() } else { + // piping to null because foot won't open without a callback_id + // otherwise Stdio::null() }) .stdout(if callback_id.is_some() { @@ -180,81 +183,84 @@ impl State { // TODO: find a way to make this hellish code look better, deal with unwraps if let Some(callback_id) = callback_id { - let stdout = child.stdout.take().unwrap(); - let stderr = child.stderr.take().unwrap(); - let stream = data.state.api_state.stream.as_ref().unwrap().clone(); - // data.state - // .api_state - // .stream - // .replace(stream.try_clone().unwrap()); - let stream2 = stream.clone(); - let stream3 = stream.clone(); - std::thread::spawn(move || { - // TODO: maybe make this not a thread? - let mut reader = BufReader::new(stdout); - loop { - let mut buf = String::new(); - match reader.read_line(&mut buf) { - Ok(0) => break, // EOF - Ok(_) => { - let mut stream = stream.lock().unwrap(); - crate::api::send_to_client( - &mut stream, - &OutgoingMsg::CallCallback { - callback_id, - args: Some(Args::Spawn { - stdout: Some( - buf.trim_end_matches('\n').to_string(), - ), - stderr: None, - exit_code: None, - exit_msg: None, - }), - }, - ) - .unwrap(); - } - Err(err) => { - tracing::error!("child read err: {err}"); - break; + let stdout = child.stdout.take(); + let stderr = child.stderr.take(); + let stream_out = data.state.api_state.stream.as_ref().unwrap().clone(); + let stream_err = stream_out.clone(); + let stream_exit = stream_out.clone(); + + if let Some(stdout) = stdout { + std::thread::spawn(move || { + // TODO: maybe find a way to make this async? + let mut reader = BufReader::new(stdout); + loop { + let mut buf = String::new(); + match reader.read_line(&mut buf) { + Ok(0) => break, // stream closed + Ok(_) => { + let mut stream = stream_out.lock().unwrap(); + crate::api::send_to_client( + &mut stream, + &OutgoingMsg::CallCallback { + callback_id, + args: Some(Args::Spawn { + stdout: Some( + buf.trim_end_matches('\n') + .to_string(), + ), + stderr: None, + exit_code: None, + exit_msg: None, + }), + }, + ) + .unwrap(); + } + Err(err) => { + tracing::error!("child read err: {err}"); + break; + } } } - } - }); - std::thread::spawn(move || { - let mut reader = BufReader::new(stderr); - loop { - let mut buf = String::new(); - match reader.read_line(&mut buf) { - Ok(0) => break, // EOF - Ok(_) => { - let mut stream = stream2.lock().unwrap(); - crate::api::send_to_client( - &mut stream, - &OutgoingMsg::CallCallback { - callback_id, - args: Some(Args::Spawn { - stdout: None, - stderr: Some( - buf.trim_end_matches('\n').to_string(), - ), - exit_code: None, - exit_msg: None, - }), - }, - ) - .unwrap(); - } - Err(err) => { - tracing::error!("child read err: {err}"); - break; + }); + } + if let Some(stderr) = stderr { + std::thread::spawn(move || { + let mut reader = BufReader::new(stderr); + loop { + let mut buf = String::new(); + match reader.read_line(&mut buf) { + Ok(0) => break, // stream closed + Ok(_) => { + let mut stream = stream_err.lock().unwrap(); + crate::api::send_to_client( + &mut stream, + &OutgoingMsg::CallCallback { + callback_id, + args: Some(Args::Spawn { + stdout: None, + stderr: Some( + buf.trim_end_matches('\n') + .to_string(), + ), + exit_code: None, + exit_msg: None, + }), + }, + ) + .unwrap(); + } + Err(err) => { + tracing::error!("child read err: {err}"); + break; + } } } - } - }); + }); + } std::thread::spawn(move || match child.wait() { Ok(exit_status) => { - let mut stream = stream3.lock().unwrap(); + let mut stream = stream_exit.lock().unwrap(); crate::api::send_to_client( &mut stream, &OutgoingMsg::CallCallback { @@ -275,9 +281,14 @@ impl State { }); } } - - // TODO: add the rest - _ => (), + Msg::SpawnShell { + shell, + command, + callback_id, + } => todo!(), + Msg::Quit => { + data.state.loop_signal.stop(); + } }; } Event::Closed => todo!(),