Add quit function to api, update README and example_config

This commit is contained in:
Seaotatop 2023-06-21 17:36:51 -05:00
parent c46159c77a
commit 8c054e17ba
8 changed files with 121 additions and 131 deletions

View file

@ -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

View file

@ -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()

View file

@ -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.

View file

@ -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)

View file

@ -66,7 +66,6 @@ impl PinnacleSocketSource {
}
}
#[must_use]
pub fn send_to_client(
stream: &mut UnixStream,
msg: &OutgoingMsg,

View file

@ -41,6 +41,10 @@ pub enum Msg {
#[serde(default)]
callback_id: Option<CallbackId>,
},
// Pinnacle management
/// Quit the compositor.
Quit,
}
#[derive(Debug, PartialEq, Eq, Copy, Clone, serde::Serialize, serde::Deserialize)]

View file

@ -228,17 +228,6 @@ impl<B: Backend> State<B> {
{
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<B: Backend> State<B> {
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();
}
}
}

View file

@ -118,6 +118,7 @@ impl<B: Backend> State<B> {
let (tx_channel, rx_channel) = calloop::channel::channel::<Msg>();
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<B: Backend> State<B> {
.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<B: Backend> State<B> {
// 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<B: Backend> State<B> {
});
}
}
// TODO: add the rest
_ => (),
Msg::SpawnShell {
shell,
command,
callback_id,
} => todo!(),
Msg::Quit => {
data.state.loop_signal.stop();
}
};
}
Event::Closed => todo!(),