mirror of
https://github.com/zellij-org/zellij.git
synced 2024-11-27 06:25:42 +03:00
Getting back to where we started... (Buggy Resizing)
This commit is contained in:
parent
fe299325eb
commit
f2c5ee44f7
7
Cargo.lock
generated
7
Cargo.lock
generated
@ -271,6 +271,12 @@ version = "1.1.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "631ae5198c9be5e753e5cc215e1bd73c2b466a3565173db433f52bb9d3e66dba"
|
checksum = "631ae5198c9be5e753e5cc215e1bd73c2b466a3565173db433f52bb9d3e66dba"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cassowary"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.0.67"
|
version = "1.0.67"
|
||||||
@ -2345,6 +2351,7 @@ version = "0.13.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"ansi_term 0.12.1",
|
"ansi_term 0.12.1",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
|
"cassowary",
|
||||||
"daemonize",
|
"daemonize",
|
||||||
"insta",
|
"insta",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
@ -135,7 +135,7 @@ impl ZellijPlugin for State {
|
|||||||
fn load(&mut self) {
|
fn load(&mut self) {
|
||||||
set_selectable(false);
|
set_selectable(false);
|
||||||
set_invisible_borders(true);
|
set_invisible_borders(true);
|
||||||
set_max_height(2);
|
set_fixed_height(2);
|
||||||
subscribe(&[EventType::ModeUpdate]);
|
subscribe(&[EventType::ModeUpdate]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ impl ZellijPlugin for State {
|
|||||||
fn load(&mut self) {
|
fn load(&mut self) {
|
||||||
set_selectable(false);
|
set_selectable(false);
|
||||||
set_invisible_borders(true);
|
set_invisible_borders(true);
|
||||||
set_max_height(1);
|
set_fixed_height(1);
|
||||||
subscribe(&[EventType::TabUpdate, EventType::ModeUpdate]);
|
subscribe(&[EventType::TabUpdate, EventType::ModeUpdate]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@ serde_json = "1.0"
|
|||||||
unicode-width = "0.1.8"
|
unicode-width = "0.1.8"
|
||||||
wasmer = "1.0.0"
|
wasmer = "1.0.0"
|
||||||
wasmer-wasi = "1.0.0"
|
wasmer-wasi = "1.0.0"
|
||||||
|
cassowary = "0.3.0"
|
||||||
zellij-utils = { path = "../zellij-utils/", version = "0.13.0" }
|
zellij-utils = { path = "../zellij-utils/", version = "0.13.0" }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
@ -112,6 +112,8 @@ pub fn start_server(os_input: Box<dyn ServerOsApi>, socket_path: PathBuf) {
|
|||||||
daemonize::Daemonize::new()
|
daemonize::Daemonize::new()
|
||||||
.working_directory(std::env::current_dir().unwrap())
|
.working_directory(std::env::current_dir().unwrap())
|
||||||
.umask(0o077)
|
.umask(0o077)
|
||||||
|
// FIXME: My cherished `dbg!` was broken, so this is a hack to bring it back
|
||||||
|
.stderr(std::fs::File::create("dbg.log").unwrap())
|
||||||
.start()
|
.start()
|
||||||
.expect("could not daemonize the server process");
|
.expect("could not daemonize the server process");
|
||||||
|
|
||||||
|
@ -16,8 +16,6 @@ pub(crate) struct PluginPane {
|
|||||||
pub position_and_size: PositionAndSize,
|
pub position_and_size: PositionAndSize,
|
||||||
pub position_and_size_override: Option<PositionAndSize>,
|
pub position_and_size_override: Option<PositionAndSize>,
|
||||||
pub send_plugin_instructions: SenderWithContext<PluginInstruction>,
|
pub send_plugin_instructions: SenderWithContext<PluginInstruction>,
|
||||||
pub max_height: Option<usize>,
|
|
||||||
pub max_width: Option<usize>,
|
|
||||||
pub active_at: Instant,
|
pub active_at: Instant,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -35,8 +33,6 @@ impl PluginPane {
|
|||||||
position_and_size,
|
position_and_size,
|
||||||
position_and_size_override: None,
|
position_and_size_override: None,
|
||||||
send_plugin_instructions,
|
send_plugin_instructions,
|
||||||
max_height: None,
|
|
||||||
max_width: None,
|
|
||||||
active_at: Instant::now(),
|
active_at: Instant::now(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -95,7 +91,9 @@ impl Pane for PluginPane {
|
|||||||
fn adjust_input_to_terminal(&self, _input_bytes: Vec<u8>) -> Vec<u8> {
|
fn adjust_input_to_terminal(&self, _input_bytes: Vec<u8>) -> Vec<u8> {
|
||||||
unimplemented!() // FIXME: Shouldn't need this implmented?
|
unimplemented!() // FIXME: Shouldn't need this implmented?
|
||||||
}
|
}
|
||||||
|
fn position_and_size(&self) -> PositionAndSize {
|
||||||
|
self.position_and_size
|
||||||
|
}
|
||||||
fn position_and_size_override(&self) -> Option<PositionAndSize> {
|
fn position_and_size_override(&self) -> Option<PositionAndSize> {
|
||||||
self.position_and_size_override
|
self.position_and_size_override
|
||||||
}
|
}
|
||||||
@ -114,11 +112,13 @@ impl Pane for PluginPane {
|
|||||||
fn set_invisible_borders(&mut self, invisible_borders: bool) {
|
fn set_invisible_borders(&mut self, invisible_borders: bool) {
|
||||||
self.invisible_borders = invisible_borders;
|
self.invisible_borders = invisible_borders;
|
||||||
}
|
}
|
||||||
fn set_max_height(&mut self, max_height: usize) {
|
fn set_fixed_height(&mut self, fixed_height: usize) {
|
||||||
self.max_height = Some(max_height);
|
self.position_and_size.rows = fixed_height;
|
||||||
|
self.position_and_size.rows_fixed = true;
|
||||||
}
|
}
|
||||||
fn set_max_width(&mut self, max_width: usize) {
|
fn set_fixed_width(&mut self, fixed_width: usize) {
|
||||||
self.max_width = Some(max_width);
|
self.position_and_size.columns = fixed_width;
|
||||||
|
self.position_and_size.cols_fixed = true;
|
||||||
}
|
}
|
||||||
fn render(&mut self) -> Option<String> {
|
fn render(&mut self) -> Option<String> {
|
||||||
// if self.should_render {
|
// if self.should_render {
|
||||||
@ -204,11 +204,21 @@ impl Pane for PluginPane {
|
|||||||
fn clear_scroll(&mut self) {
|
fn clear_scroll(&mut self) {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
// FIXME: This need to be reevaluated and deleted if possible.
|
||||||
|
// `max` doesn't make sense when things are fixed...
|
||||||
fn max_height(&self) -> Option<usize> {
|
fn max_height(&self) -> Option<usize> {
|
||||||
self.max_height
|
if self.position_and_size.rows_fixed {
|
||||||
|
Some(self.position_and_size.rows)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
fn max_width(&self) -> Option<usize> {
|
fn max_width(&self) -> Option<usize> {
|
||||||
self.max_width
|
if self.position_and_size.cols_fixed {
|
||||||
|
Some(self.position_and_size.columns)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
fn invisible_borders(&self) -> bool {
|
fn invisible_borders(&self) -> bool {
|
||||||
self.invisible_borders
|
self.invisible_borders
|
||||||
|
@ -27,8 +27,6 @@ pub struct TerminalPane {
|
|||||||
pub selectable: bool,
|
pub selectable: bool,
|
||||||
pub position_and_size: PositionAndSize,
|
pub position_and_size: PositionAndSize,
|
||||||
pub position_and_size_override: Option<PositionAndSize>,
|
pub position_and_size_override: Option<PositionAndSize>,
|
||||||
pub max_height: Option<usize>,
|
|
||||||
pub max_width: Option<usize>,
|
|
||||||
pub active_at: Instant,
|
pub active_at: Instant,
|
||||||
pub colors: Palette,
|
pub colors: Palette,
|
||||||
vte_parser: vte::Parser,
|
vte_parser: vte::Parser,
|
||||||
@ -52,8 +50,7 @@ impl Pane for TerminalPane {
|
|||||||
self.reflow_lines();
|
self.reflow_lines();
|
||||||
}
|
}
|
||||||
fn change_pos_and_size(&mut self, position_and_size: &PositionAndSize) {
|
fn change_pos_and_size(&mut self, position_and_size: &PositionAndSize) {
|
||||||
self.position_and_size.columns = position_and_size.columns;
|
self.position_and_size = *position_and_size;
|
||||||
self.position_and_size.rows = position_and_size.rows;
|
|
||||||
self.reflow_lines();
|
self.reflow_lines();
|
||||||
}
|
}
|
||||||
fn override_size_and_position(&mut self, x: usize, y: usize, size: &PositionAndSize) {
|
fn override_size_and_position(&mut self, x: usize, y: usize, size: &PositionAndSize) {
|
||||||
@ -119,7 +116,9 @@ impl Pane for TerminalPane {
|
|||||||
};
|
};
|
||||||
input_bytes
|
input_bytes
|
||||||
}
|
}
|
||||||
|
fn position_and_size(&self) -> PositionAndSize {
|
||||||
|
self.position_and_size
|
||||||
|
}
|
||||||
fn position_and_size_override(&self) -> Option<PositionAndSize> {
|
fn position_and_size_override(&self) -> Option<PositionAndSize> {
|
||||||
self.position_and_size_override
|
self.position_and_size_override
|
||||||
}
|
}
|
||||||
@ -135,21 +134,17 @@ impl Pane for TerminalPane {
|
|||||||
fn set_selectable(&mut self, selectable: bool) {
|
fn set_selectable(&mut self, selectable: bool) {
|
||||||
self.selectable = selectable;
|
self.selectable = selectable;
|
||||||
}
|
}
|
||||||
fn set_max_height(&mut self, max_height: usize) {
|
fn set_fixed_height(&mut self, fixed_height: usize) {
|
||||||
self.max_height = Some(max_height);
|
self.position_and_size.rows = fixed_height;
|
||||||
|
self.position_and_size.rows_fixed = true;
|
||||||
}
|
}
|
||||||
fn set_max_width(&mut self, max_width: usize) {
|
fn set_fixed_width(&mut self, fixed_width: usize) {
|
||||||
self.max_width = Some(max_width);
|
self.position_and_size.columns = fixed_width;
|
||||||
|
self.position_and_size.cols_fixed = true;
|
||||||
}
|
}
|
||||||
fn set_invisible_borders(&mut self, _invisible_borders: bool) {
|
fn set_invisible_borders(&mut self, _invisible_borders: bool) {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
fn max_height(&self) -> Option<usize> {
|
|
||||||
self.max_height
|
|
||||||
}
|
|
||||||
fn max_width(&self) -> Option<usize> {
|
|
||||||
self.max_width
|
|
||||||
}
|
|
||||||
fn render(&mut self) -> Option<String> {
|
fn render(&mut self) -> Option<String> {
|
||||||
if self.should_render() {
|
if self.should_render() {
|
||||||
let mut vte_output = String::new();
|
let mut vte_output = String::new();
|
||||||
@ -294,8 +289,6 @@ impl TerminalPane {
|
|||||||
selectable: true,
|
selectable: true,
|
||||||
position_and_size,
|
position_and_size,
|
||||||
position_and_size_override: None,
|
position_and_size_override: None,
|
||||||
max_height: None,
|
|
||||||
max_width: None,
|
|
||||||
vte_parser: vte::Parser::new(),
|
vte_parser: vte::Parser::new(),
|
||||||
active_at: Instant::now(),
|
active_at: Instant::now(),
|
||||||
colors: palette,
|
colors: palette,
|
||||||
|
@ -55,7 +55,8 @@ pub(crate) enum ScreenInstruction {
|
|||||||
CloseFocusedPane,
|
CloseFocusedPane,
|
||||||
ToggleActiveTerminalFullscreen,
|
ToggleActiveTerminalFullscreen,
|
||||||
SetSelectable(PaneId, bool),
|
SetSelectable(PaneId, bool),
|
||||||
SetMaxHeight(PaneId, usize),
|
SetFixedHeight(PaneId, usize),
|
||||||
|
SetFixedWidth(PaneId, usize),
|
||||||
SetInvisibleBorders(PaneId, bool),
|
SetInvisibleBorders(PaneId, bool),
|
||||||
ClosePane(PaneId),
|
ClosePane(PaneId),
|
||||||
ApplyLayout(Layout, Vec<RawFd>),
|
ApplyLayout(Layout, Vec<RawFd>),
|
||||||
@ -106,7 +107,8 @@ impl From<&ScreenInstruction> for ScreenContext {
|
|||||||
}
|
}
|
||||||
ScreenInstruction::SetSelectable(..) => ScreenContext::SetSelectable,
|
ScreenInstruction::SetSelectable(..) => ScreenContext::SetSelectable,
|
||||||
ScreenInstruction::SetInvisibleBorders(..) => ScreenContext::SetInvisibleBorders,
|
ScreenInstruction::SetInvisibleBorders(..) => ScreenContext::SetInvisibleBorders,
|
||||||
ScreenInstruction::SetMaxHeight(..) => ScreenContext::SetMaxHeight,
|
ScreenInstruction::SetFixedHeight(..) => ScreenContext::SetFixedHeight,
|
||||||
|
ScreenInstruction::SetFixedWidth(..) => ScreenContext::SetFixedWidth,
|
||||||
ScreenInstruction::ClosePane(_) => ScreenContext::ClosePane,
|
ScreenInstruction::ClosePane(_) => ScreenContext::ClosePane,
|
||||||
ScreenInstruction::ApplyLayout(..) => ScreenContext::ApplyLayout,
|
ScreenInstruction::ApplyLayout(..) => ScreenContext::ApplyLayout,
|
||||||
ScreenInstruction::NewTab(_) => ScreenContext::NewTab,
|
ScreenInstruction::NewTab(_) => ScreenContext::NewTab,
|
||||||
@ -574,11 +576,17 @@ pub(crate) fn screen_thread_main(
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.set_pane_selectable(id, selectable);
|
.set_pane_selectable(id, selectable);
|
||||||
}
|
}
|
||||||
ScreenInstruction::SetMaxHeight(id, max_height) => {
|
ScreenInstruction::SetFixedHeight(id, fixed_height) => {
|
||||||
screen
|
screen
|
||||||
.get_active_tab_mut()
|
.get_active_tab_mut()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.set_pane_max_height(id, max_height);
|
.set_pane_fixed_height(id, fixed_height);
|
||||||
|
}
|
||||||
|
ScreenInstruction::SetFixedWidth(id, fixed_width) => {
|
||||||
|
screen
|
||||||
|
.get_active_tab_mut()
|
||||||
|
.unwrap()
|
||||||
|
.set_pane_fixed_width(id, fixed_width);
|
||||||
}
|
}
|
||||||
ScreenInstruction::SetInvisibleBorders(id, invisible_borders) => {
|
ScreenInstruction::SetInvisibleBorders(id, invisible_borders) => {
|
||||||
screen
|
screen
|
||||||
|
@ -104,15 +104,15 @@ pub trait Pane {
|
|||||||
fn handle_pty_bytes(&mut self, bytes: VteBytes);
|
fn handle_pty_bytes(&mut self, bytes: VteBytes);
|
||||||
fn cursor_coordinates(&self) -> Option<(usize, usize)>;
|
fn cursor_coordinates(&self) -> Option<(usize, usize)>;
|
||||||
fn adjust_input_to_terminal(&self, input_bytes: Vec<u8>) -> Vec<u8>;
|
fn adjust_input_to_terminal(&self, input_bytes: Vec<u8>) -> Vec<u8>;
|
||||||
|
fn position_and_size(&self) -> PositionAndSize;
|
||||||
fn position_and_size_override(&self) -> Option<PositionAndSize>;
|
fn position_and_size_override(&self) -> Option<PositionAndSize>;
|
||||||
fn should_render(&self) -> bool;
|
fn should_render(&self) -> bool;
|
||||||
fn set_should_render(&mut self, should_render: bool);
|
fn set_should_render(&mut self, should_render: bool);
|
||||||
fn selectable(&self) -> bool;
|
fn selectable(&self) -> bool;
|
||||||
fn set_selectable(&mut self, selectable: bool);
|
fn set_selectable(&mut self, selectable: bool);
|
||||||
fn set_invisible_borders(&mut self, invisible_borders: bool);
|
fn set_invisible_borders(&mut self, invisible_borders: bool);
|
||||||
fn set_max_height(&mut self, max_height: usize);
|
fn set_fixed_height(&mut self, fixed_height: usize);
|
||||||
fn set_max_width(&mut self, max_width: usize);
|
fn set_fixed_width(&mut self, fixed_width: usize);
|
||||||
fn render(&mut self) -> Option<String>;
|
fn render(&mut self) -> Option<String>;
|
||||||
fn pid(&self) -> PaneId;
|
fn pid(&self) -> PaneId;
|
||||||
fn reduce_height_down(&mut self, count: usize);
|
fn reduce_height_down(&mut self, count: usize);
|
||||||
@ -178,15 +178,6 @@ pub trait Pane {
|
|||||||
std::cmp::min(self.x() + self.columns(), other.x() + other.columns())
|
std::cmp::min(self.x() + self.columns(), other.x() + other.columns())
|
||||||
- std::cmp::max(self.x(), other.x())
|
- std::cmp::max(self.x(), other.x())
|
||||||
}
|
}
|
||||||
fn position_and_size(&self) -> PositionAndSize {
|
|
||||||
PositionAndSize {
|
|
||||||
x: self.x(),
|
|
||||||
y: self.y(),
|
|
||||||
columns: self.columns(),
|
|
||||||
rows: self.rows(),
|
|
||||||
..Default::default()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn can_increase_height_by(&self, increase_by: usize) -> bool {
|
fn can_increase_height_by(&self, increase_by: usize) -> bool {
|
||||||
self.max_height()
|
self.max_height()
|
||||||
.map(|max_height| self.rows() + increase_by <= max_height)
|
.map(|max_height| self.rows() + increase_by <= max_height)
|
||||||
@ -294,12 +285,6 @@ impl Tab {
|
|||||||
match positions_and_size.next() {
|
match positions_and_size.next() {
|
||||||
Some((_, position_and_size)) => {
|
Some((_, position_and_size)) => {
|
||||||
terminal_pane.reset_size_and_position_override();
|
terminal_pane.reset_size_and_position_override();
|
||||||
if let Some(max_rows) = position_and_size.max_rows {
|
|
||||||
terminal_pane.set_max_height(max_rows);
|
|
||||||
}
|
|
||||||
if let Some(max_columns) = position_and_size.max_columns {
|
|
||||||
terminal_pane.set_max_width(max_columns);
|
|
||||||
}
|
|
||||||
terminal_pane.change_pos_and_size(&position_and_size);
|
terminal_pane.change_pos_and_size(&position_and_size);
|
||||||
self.os_api.set_terminal_size_using_fd(
|
self.os_api.set_terminal_size_using_fd(
|
||||||
*pid,
|
*pid,
|
||||||
@ -317,24 +302,18 @@ impl Tab {
|
|||||||
}
|
}
|
||||||
let mut new_pids = new_pids.iter();
|
let mut new_pids = new_pids.iter();
|
||||||
for (layout, position_and_size) in positions_and_size {
|
for (layout, position_and_size) in positions_and_size {
|
||||||
// Just a regular terminal
|
// A plugin pane
|
||||||
if let Some(plugin) = &layout.plugin {
|
if let Some(plugin) = &layout.plugin {
|
||||||
let (pid_tx, pid_rx) = channel();
|
let (pid_tx, pid_rx) = channel();
|
||||||
self.senders
|
self.senders
|
||||||
.send_to_plugin(PluginInstruction::Load(pid_tx, plugin.clone()))
|
.send_to_plugin(PluginInstruction::Load(pid_tx, plugin.clone()))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let pid = pid_rx.recv().unwrap();
|
let pid = pid_rx.recv().unwrap();
|
||||||
let mut new_plugin = PluginPane::new(
|
let new_plugin = PluginPane::new(
|
||||||
pid,
|
pid,
|
||||||
*position_and_size,
|
*position_and_size,
|
||||||
self.senders.to_plugin.as_ref().unwrap().clone(),
|
self.senders.to_plugin.as_ref().unwrap().clone(),
|
||||||
);
|
);
|
||||||
if let Some(max_rows) = position_and_size.max_rows {
|
|
||||||
new_plugin.set_max_height(max_rows);
|
|
||||||
}
|
|
||||||
if let Some(max_columns) = position_and_size.max_columns {
|
|
||||||
new_plugin.set_max_width(max_columns);
|
|
||||||
}
|
|
||||||
self.panes.insert(PaneId::Plugin(pid), Box::new(new_plugin));
|
self.panes.insert(PaneId::Plugin(pid), Box::new(new_plugin));
|
||||||
// Send an initial mode update to the newly loaded plugin only!
|
// Send an initial mode update to the newly loaded plugin only!
|
||||||
self.senders
|
self.senders
|
||||||
@ -2121,9 +2100,14 @@ impl Tab {
|
|||||||
pane.set_invisible_borders(invisible_borders);
|
pane.set_invisible_borders(invisible_borders);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn set_pane_max_height(&mut self, id: PaneId, max_height: usize) {
|
pub fn set_pane_fixed_height(&mut self, id: PaneId, fixed_height: usize) {
|
||||||
if let Some(pane) = self.panes.get_mut(&id) {
|
if let Some(pane) = self.panes.get_mut(&id) {
|
||||||
pane.set_max_height(max_height);
|
pane.set_fixed_height(fixed_height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn set_pane_fixed_width(&mut self, id: PaneId, fixed_width: usize) {
|
||||||
|
if let Some(pane) = self.panes.get_mut(&id) {
|
||||||
|
pane.set_fixed_width(fixed_width);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn close_pane(&mut self, id: PaneId) {
|
pub fn close_pane(&mut self, id: PaneId) {
|
||||||
|
@ -19,17 +19,14 @@ fn split_space_to_parts_vertically(
|
|||||||
|
|
||||||
// First fit in the parameterized sizes
|
// First fit in the parameterized sizes
|
||||||
for size in sizes {
|
for size in sizes {
|
||||||
let (columns, max_columns) = match size {
|
let columns = match size {
|
||||||
Some(SplitSize::Percent(percent)) => {
|
Some(SplitSize::Percent(percent)) => {
|
||||||
((max_width as f32 * (percent as f32 / 100.0)) as usize, None)
|
(max_width as f32 * (percent as f32 / 100.0)) as usize
|
||||||
} // TODO: round properly
|
} // TODO: round properly
|
||||||
Some(SplitSize::Fixed(size)) => (size as usize, Some(size as usize)),
|
Some(SplitSize::Fixed(size)) => size as usize,
|
||||||
None => {
|
None => {
|
||||||
parts_to_grow.push(current_x_position);
|
parts_to_grow.push(current_x_position);
|
||||||
(
|
1 // This is grown later on
|
||||||
1, // This is grown later on
|
|
||||||
None,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
split_parts.push(PositionAndSize {
|
split_parts.push(PositionAndSize {
|
||||||
@ -37,7 +34,6 @@ fn split_space_to_parts_vertically(
|
|||||||
y: space_to_split.y,
|
y: space_to_split.y,
|
||||||
columns,
|
columns,
|
||||||
rows: space_to_split.rows,
|
rows: space_to_split.rows,
|
||||||
max_columns,
|
|
||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
current_width += columns;
|
current_width += columns;
|
||||||
@ -87,18 +83,14 @@ fn split_space_to_parts_horizontally(
|
|||||||
let mut parts_to_grow = Vec::new();
|
let mut parts_to_grow = Vec::new();
|
||||||
|
|
||||||
for size in sizes {
|
for size in sizes {
|
||||||
let (rows, max_rows) = match size {
|
let rows = match size {
|
||||||
Some(SplitSize::Percent(percent)) => (
|
Some(SplitSize::Percent(percent)) => {
|
||||||
(max_height as f32 * (percent as f32 / 100.0)) as usize,
|
(max_height as f32 * (percent as f32 / 100.0)) as usize
|
||||||
None,
|
} // TODO: round properly
|
||||||
), // TODO: round properly
|
Some(SplitSize::Fixed(size)) => size as usize,
|
||||||
Some(SplitSize::Fixed(size)) => (size as usize, Some(size as usize)),
|
|
||||||
None => {
|
None => {
|
||||||
parts_to_grow.push(current_y_position);
|
parts_to_grow.push(current_y_position);
|
||||||
(
|
1 // This is grown later on
|
||||||
1, // This is grown later on
|
|
||||||
None,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
split_parts.push(PositionAndSize {
|
split_parts.push(PositionAndSize {
|
||||||
@ -106,7 +98,6 @@ fn split_space_to_parts_horizontally(
|
|||||||
y: current_y_position,
|
y: current_y_position,
|
||||||
columns: space_to_split.columns,
|
columns: space_to_split.columns,
|
||||||
rows,
|
rows,
|
||||||
max_rows,
|
|
||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
current_height += rows;
|
current_height += rows;
|
||||||
|
@ -1,531 +1,247 @@
|
|||||||
use crate::{os_input_output::ServerOsApi, panes::PaneId, tab::Pane};
|
use crate::{os_input_output::ServerOsApi, panes::PaneId, tab::Pane};
|
||||||
|
use cassowary::{
|
||||||
|
strength::{REQUIRED, STRONG},
|
||||||
|
Constraint, Solver, Variable,
|
||||||
|
WeightedRelation::*,
|
||||||
|
};
|
||||||
use std::{
|
use std::{
|
||||||
cmp::Ordering,
|
|
||||||
collections::{BTreeMap, HashSet},
|
collections::{BTreeMap, HashSet},
|
||||||
|
ops::Not,
|
||||||
};
|
};
|
||||||
use zellij_utils::pane_size::PositionAndSize;
|
use zellij_utils::pane_size::PositionAndSize;
|
||||||
|
|
||||||
pub(crate) struct PaneResizer<'a> {
|
const GAP_SIZE: usize = 1; // Panes are separated by this number of rows / columns
|
||||||
|
|
||||||
|
pub struct PaneResizer<'a> {
|
||||||
panes: &'a mut BTreeMap<PaneId, Box<dyn Pane>>,
|
panes: &'a mut BTreeMap<PaneId, Box<dyn Pane>>,
|
||||||
|
vars: BTreeMap<PaneId, (Variable, Variable)>,
|
||||||
|
solver: Solver,
|
||||||
os_api: &'a mut Box<dyn ServerOsApi>,
|
os_api: &'a mut Box<dyn ServerOsApi>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
enum Direction {
|
||||||
|
Horizontal,
|
||||||
|
Vertical,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Not for Direction {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn not(self) -> Self::Output {
|
||||||
|
match self {
|
||||||
|
Direction::Horizontal => Direction::Vertical,
|
||||||
|
Direction::Vertical => Direction::Horizontal,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
struct Span {
|
||||||
|
pid: PaneId,
|
||||||
|
direction: Direction,
|
||||||
|
fixed: bool,
|
||||||
|
pos: usize,
|
||||||
|
size: usize,
|
||||||
|
pos_var: Variable,
|
||||||
|
size_var: Variable,
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: currently there are some functions here duplicated with Tab
|
// TODO: currently there are some functions here duplicated with Tab
|
||||||
// all resizing functions should move here
|
// all resizing functions should move here
|
||||||
|
|
||||||
|
// FIXME:
|
||||||
|
// 1. Rounding causes a loss of ratios, I need to store an internal f64 for
|
||||||
|
// each pane as well as the displayed usize and add custom rounding logic.
|
||||||
|
// 2. Vertical resizing doesn't seem to respect the space consumed by the tab
|
||||||
|
// and status bars?
|
||||||
|
// 3. A 2x2 layout and simultaneous vertical + horizontal resizing sometimes
|
||||||
|
// leads to unsolvable constraints? Maybe related to 2 (and possibly 1).
|
||||||
|
// I should sanity-check the `spans_in_boundary()` here!
|
||||||
|
|
||||||
impl<'a> PaneResizer<'a> {
|
impl<'a> PaneResizer<'a> {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
panes: &'a mut BTreeMap<PaneId, Box<dyn Pane>>,
|
panes: &'a mut BTreeMap<PaneId, Box<dyn Pane>>,
|
||||||
os_api: &'a mut Box<dyn ServerOsApi>,
|
os_api: &'a mut Box<dyn ServerOsApi>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
PaneResizer { panes, os_api }
|
let mut vars = BTreeMap::new();
|
||||||
|
for &k in panes.keys() {
|
||||||
|
vars.insert(k, (Variable::new(), Variable::new()));
|
||||||
|
}
|
||||||
|
PaneResizer {
|
||||||
|
panes,
|
||||||
|
vars,
|
||||||
|
solver: Solver::new(),
|
||||||
|
os_api,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resize(
|
pub fn resize(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut current_size: PositionAndSize,
|
current_size: PositionAndSize,
|
||||||
new_size: PositionAndSize,
|
new_size: PositionAndSize,
|
||||||
) -> Option<(isize, isize)> {
|
) -> Option<(isize, isize)> {
|
||||||
// (column_difference, row_difference)
|
let col_delta = new_size.columns as isize - current_size.columns as isize;
|
||||||
let mut successfully_resized = false;
|
let row_delta = new_size.rows as isize - current_size.rows as isize;
|
||||||
let mut column_difference: isize = 0;
|
if col_delta != 0 {
|
||||||
let mut row_difference: isize = 0;
|
let spans = self.solve_direction(Direction::Horizontal, new_size.columns)?;
|
||||||
match new_size.columns.cmp(¤t_size.columns) {
|
self.collapse_spans(&spans);
|
||||||
Ordering::Greater => {
|
|
||||||
let increase_by = new_size.columns - current_size.columns;
|
|
||||||
if let Some(panes_to_resize) = find_increasable_vertical_chain(
|
|
||||||
&self.panes,
|
|
||||||
increase_by,
|
|
||||||
current_size.columns,
|
|
||||||
current_size.rows,
|
|
||||||
) {
|
|
||||||
self.increase_panes_right_and_push_adjacents_right(
|
|
||||||
panes_to_resize,
|
|
||||||
increase_by,
|
|
||||||
);
|
|
||||||
column_difference = new_size.columns as isize - current_size.columns as isize;
|
|
||||||
current_size.columns =
|
|
||||||
(current_size.columns as isize + column_difference) as usize;
|
|
||||||
successfully_resized = true;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
Ordering::Less => {
|
|
||||||
let reduce_by = current_size.columns - new_size.columns;
|
|
||||||
if let Some(panes_to_resize) = find_reducible_vertical_chain(
|
|
||||||
&self.panes,
|
|
||||||
reduce_by,
|
|
||||||
current_size.columns,
|
|
||||||
current_size.rows,
|
|
||||||
) {
|
|
||||||
self.reduce_panes_left_and_pull_adjacents_left(panes_to_resize, reduce_by);
|
|
||||||
column_difference = new_size.columns as isize - current_size.columns as isize;
|
|
||||||
current_size.columns =
|
|
||||||
(current_size.columns as isize + column_difference) as usize;
|
|
||||||
successfully_resized = true;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
Ordering::Equal => (),
|
|
||||||
}
|
}
|
||||||
match new_size.rows.cmp(¤t_size.rows) {
|
self.solver.reset();
|
||||||
Ordering::Greater => {
|
if row_delta != 0 {
|
||||||
let increase_by = new_size.rows - current_size.rows;
|
let spans = self.solve_direction(Direction::Vertical, new_size.rows)?;
|
||||||
if let Some(panes_to_resize) = find_increasable_horizontal_chain(
|
self.collapse_spans(&spans);
|
||||||
&self.panes,
|
|
||||||
increase_by,
|
|
||||||
current_size.columns,
|
|
||||||
current_size.rows,
|
|
||||||
) {
|
|
||||||
self.increase_panes_down_and_push_down_adjacents(panes_to_resize, increase_by);
|
|
||||||
row_difference = new_size.rows as isize - current_size.rows as isize;
|
|
||||||
current_size.rows = (current_size.rows as isize + row_difference) as usize;
|
|
||||||
successfully_resized = true;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
Ordering::Less => {
|
|
||||||
let reduce_by = current_size.rows - new_size.rows;
|
|
||||||
if let Some(panes_to_resize) = find_reducible_horizontal_chain(
|
|
||||||
&self.panes,
|
|
||||||
reduce_by,
|
|
||||||
current_size.columns,
|
|
||||||
current_size.rows,
|
|
||||||
) {
|
|
||||||
self.reduce_panes_up_and_pull_adjacents_up(panes_to_resize, reduce_by);
|
|
||||||
row_difference = new_size.rows as isize - current_size.rows as isize;
|
|
||||||
current_size.rows = (current_size.rows as isize + row_difference) as usize;
|
|
||||||
successfully_resized = true;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
Ordering::Equal => (),
|
|
||||||
}
|
}
|
||||||
if successfully_resized {
|
Some((col_delta, row_delta))
|
||||||
Some((column_difference, row_difference))
|
}
|
||||||
|
|
||||||
|
fn solve_direction(&mut self, direction: Direction, space: usize) -> Option<Vec<Span>> {
|
||||||
|
let mut grid = Vec::new();
|
||||||
|
for boundary in self.grid_boundaries(direction) {
|
||||||
|
grid.push(self.spans_in_boundary(direction, boundary));
|
||||||
|
}
|
||||||
|
|
||||||
|
let constraints: Vec<_> = grid
|
||||||
|
.iter()
|
||||||
|
.flat_map(|s| constrain_spans(space, s))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
// FIXME: This line needs to be restored before merging!
|
||||||
|
//self.solver.add_constraints(&constraints).ok()?;
|
||||||
|
self.solver.add_constraints(&constraints).unwrap();
|
||||||
|
Some(grid.into_iter().flatten().collect())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn grid_boundaries(&self, direction: Direction) -> Vec<(usize, usize)> {
|
||||||
|
// Select the spans running *perpendicular* to the direction of resize
|
||||||
|
let spans: Vec<Span> = self
|
||||||
|
.panes
|
||||||
|
.values()
|
||||||
|
.map(|p| self.get_span(!direction, p.as_ref()))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let mut last_edge = 0;
|
||||||
|
let mut bounds = Vec::new();
|
||||||
|
loop {
|
||||||
|
let mut spans_on_edge: Vec<&Span> =
|
||||||
|
spans.iter().filter(|p| p.pos == last_edge).collect();
|
||||||
|
spans_on_edge.sort_unstable_by_key(|s| s.size);
|
||||||
|
if let Some(next) = spans_on_edge.first() {
|
||||||
|
let next_edge = last_edge + next.size;
|
||||||
|
bounds.push((last_edge, next_edge));
|
||||||
|
last_edge = next_edge + GAP_SIZE;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bounds
|
||||||
|
}
|
||||||
|
|
||||||
|
fn spans_in_boundary(&self, direction: Direction, boundary: (usize, usize)) -> Vec<Span> {
|
||||||
|
let (start, end) = boundary;
|
||||||
|
let bwn = |v| start <= v && v < end;
|
||||||
|
let mut spans: Vec<_> = self
|
||||||
|
.panes
|
||||||
|
.values()
|
||||||
|
.filter(|p| {
|
||||||
|
let s = self.get_span(!direction, p.as_ref());
|
||||||
|
bwn(s.pos) || bwn(s.pos + s.size)
|
||||||
|
})
|
||||||
|
.map(|p| self.get_span(direction, p.as_ref()))
|
||||||
|
.collect();
|
||||||
|
spans.sort_unstable_by_key(|s| s.pos);
|
||||||
|
spans
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_span(&self, direction: Direction, pane: &dyn Pane) -> Span {
|
||||||
|
let pas = pane.position_and_size();
|
||||||
|
let (pos_var, size_var) = self.vars[&pane.pid()];
|
||||||
|
match direction {
|
||||||
|
Direction::Horizontal => Span {
|
||||||
|
pid: pane.pid(),
|
||||||
|
direction,
|
||||||
|
fixed: pas.cols_fixed,
|
||||||
|
pos: pas.x,
|
||||||
|
size: pas.columns,
|
||||||
|
pos_var,
|
||||||
|
size_var,
|
||||||
|
},
|
||||||
|
Direction::Vertical => Span {
|
||||||
|
pid: pane.pid(),
|
||||||
|
direction,
|
||||||
|
fixed: pas.rows_fixed,
|
||||||
|
pos: pas.y,
|
||||||
|
size: pas.rows,
|
||||||
|
pos_var,
|
||||||
|
size_var,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn collapse_spans(&mut self, spans: &[Span]) {
|
||||||
|
for span in spans {
|
||||||
|
let solver = &self.solver; // Hand-holding the borrow-checker
|
||||||
|
let pane = self.panes.get_mut(&span.pid).unwrap();
|
||||||
|
let fetch_usize = |v| solver.get_value(v).round() as usize;
|
||||||
|
match span.direction {
|
||||||
|
Direction::Horizontal => pane.change_pos_and_size(&PositionAndSize {
|
||||||
|
x: fetch_usize(span.pos_var),
|
||||||
|
columns: fetch_usize(span.size_var),
|
||||||
|
..pane.position_and_size()
|
||||||
|
}),
|
||||||
|
Direction::Vertical => pane.change_pos_and_size(&PositionAndSize {
|
||||||
|
y: fetch_usize(span.pos_var),
|
||||||
|
rows: fetch_usize(span.size_var),
|
||||||
|
..pane.position_and_size()
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
if let PaneId::Terminal(pid) = pane.pid() {
|
||||||
|
self.os_api.set_terminal_size_using_fd(
|
||||||
|
pid,
|
||||||
|
pane.columns() as u16,
|
||||||
|
pane.rows() as u16,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn constrain_spans(space: usize, spans: &[Span]) -> HashSet<Constraint> {
|
||||||
|
let mut constraints = HashSet::new();
|
||||||
|
|
||||||
|
// The first span needs to start at 0
|
||||||
|
constraints.insert(spans[0].pos_var | EQ(REQUIRED) | 0.0);
|
||||||
|
|
||||||
|
// Calculating "flexible" space (space not consumed by fixed-size spans)
|
||||||
|
let gap_space = GAP_SIZE * (spans.len() - 1);
|
||||||
|
let old_flex_space = spans
|
||||||
|
.iter()
|
||||||
|
.fold(0, |a, s| if !s.fixed { a + s.size } else { a });
|
||||||
|
let new_flex_space = spans.iter().fold(
|
||||||
|
space - gap_space,
|
||||||
|
|a, s| if s.fixed { a - s.size } else { a },
|
||||||
|
);
|
||||||
|
|
||||||
|
// Keep spans stuck together
|
||||||
|
for pair in spans.windows(2) {
|
||||||
|
let (ls, rs) = (pair[0], pair[1]);
|
||||||
|
constraints
|
||||||
|
.insert((ls.pos_var + ls.size_var + GAP_SIZE as f64) | EQ(REQUIRED) | rs.pos_var);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to maintain ratios and lock non-flexible sizes
|
||||||
|
for span in spans {
|
||||||
|
if span.fixed {
|
||||||
|
constraints.insert(span.size_var | EQ(REQUIRED) | span.size as f64);
|
||||||
} else {
|
} else {
|
||||||
None
|
let ratio = span.size as f64 / old_flex_space as f64;
|
||||||
}
|
constraints.insert((span.size_var / new_flex_space as f64) | EQ(STRONG) | ratio);
|
||||||
}
|
|
||||||
fn reduce_panes_left_and_pull_adjacents_left(
|
|
||||||
&mut self,
|
|
||||||
panes_to_reduce: Vec<PaneId>,
|
|
||||||
reduce_by: usize,
|
|
||||||
) {
|
|
||||||
let mut pulled_panes: HashSet<PaneId> = HashSet::new();
|
|
||||||
for pane_id in panes_to_reduce {
|
|
||||||
let (pane_x, pane_y, pane_columns, pane_rows) = {
|
|
||||||
let pane = self.panes.get(&pane_id).unwrap();
|
|
||||||
(pane.x(), pane.y(), pane.columns(), pane.rows())
|
|
||||||
};
|
|
||||||
let panes_to_pull = self.panes.values_mut().filter(|p| {
|
|
||||||
p.x() > pane_x + pane_columns
|
|
||||||
&& (p.y() <= pane_y && p.y() + p.rows() >= pane_y
|
|
||||||
|| p.y() >= pane_y && p.y() + p.rows() <= pane_y + pane_rows)
|
|
||||||
});
|
|
||||||
for pane in panes_to_pull {
|
|
||||||
if !pulled_panes.contains(&pane.pid()) {
|
|
||||||
pane.pull_left(reduce_by);
|
|
||||||
pulled_panes.insert(pane.pid());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.reduce_pane_width_left(&pane_id, reduce_by);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn reduce_panes_up_and_pull_adjacents_up(
|
|
||||||
&mut self,
|
|
||||||
panes_to_reduce: Vec<PaneId>,
|
|
||||||
reduce_by: usize,
|
|
||||||
) {
|
|
||||||
let mut pulled_panes: HashSet<PaneId> = HashSet::new();
|
|
||||||
for pane_id in panes_to_reduce {
|
|
||||||
let (pane_x, pane_y, pane_columns, pane_rows) = {
|
|
||||||
let pane = self.panes.get(&pane_id).unwrap();
|
|
||||||
(pane.x(), pane.y(), pane.columns(), pane.rows())
|
|
||||||
};
|
|
||||||
let panes_to_pull = self.panes.values_mut().filter(|p| {
|
|
||||||
p.y() > pane_y + pane_rows
|
|
||||||
&& (p.x() <= pane_x && p.x() + p.columns() >= pane_x
|
|
||||||
|| p.x() >= pane_x && p.x() + p.columns() <= pane_x + pane_columns)
|
|
||||||
});
|
|
||||||
for pane in panes_to_pull {
|
|
||||||
if !pulled_panes.contains(&pane.pid()) {
|
|
||||||
pane.pull_up(reduce_by);
|
|
||||||
pulled_panes.insert(pane.pid());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.reduce_pane_height_up(&pane_id, reduce_by);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn increase_panes_down_and_push_down_adjacents(
|
|
||||||
&mut self,
|
|
||||||
panes_to_increase: Vec<PaneId>,
|
|
||||||
increase_by: usize,
|
|
||||||
) {
|
|
||||||
let mut pushed_panes: HashSet<PaneId> = HashSet::new();
|
|
||||||
for pane_id in panes_to_increase {
|
|
||||||
let (pane_x, pane_y, pane_columns, pane_rows) = {
|
|
||||||
let pane = self.panes.get(&pane_id).unwrap();
|
|
||||||
(pane.x(), pane.y(), pane.columns(), pane.rows())
|
|
||||||
};
|
|
||||||
let panes_to_push = self.panes.values_mut().filter(|p| {
|
|
||||||
p.y() > pane_y + pane_rows
|
|
||||||
&& (p.x() <= pane_x && p.x() + p.columns() >= pane_x
|
|
||||||
|| p.x() >= pane_x && p.x() + p.columns() <= pane_x + pane_columns)
|
|
||||||
});
|
|
||||||
for pane in panes_to_push {
|
|
||||||
if !pushed_panes.contains(&pane.pid()) {
|
|
||||||
pane.push_down(increase_by);
|
|
||||||
pushed_panes.insert(pane.pid());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.increase_pane_height_down(&pane_id, increase_by);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn increase_panes_right_and_push_adjacents_right(
|
|
||||||
&mut self,
|
|
||||||
panes_to_increase: Vec<PaneId>,
|
|
||||||
increase_by: usize,
|
|
||||||
) {
|
|
||||||
let mut pushed_panes: HashSet<PaneId> = HashSet::new();
|
|
||||||
for pane_id in panes_to_increase {
|
|
||||||
let (pane_x, pane_y, pane_columns, pane_rows) = {
|
|
||||||
let pane = self.panes.get(&pane_id).unwrap();
|
|
||||||
(pane.x(), pane.y(), pane.columns(), pane.rows())
|
|
||||||
};
|
|
||||||
let panes_to_push = self.panes.values_mut().filter(|p| {
|
|
||||||
p.x() > pane_x + pane_columns
|
|
||||||
&& (p.y() <= pane_y && p.y() + p.rows() >= pane_y
|
|
||||||
|| p.y() >= pane_y && p.y() + p.rows() <= pane_y + pane_rows)
|
|
||||||
});
|
|
||||||
for pane in panes_to_push {
|
|
||||||
if !pushed_panes.contains(&pane.pid()) {
|
|
||||||
pane.push_right(increase_by);
|
|
||||||
pushed_panes.insert(pane.pid());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.increase_pane_width_right(&pane_id, increase_by);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn reduce_pane_height_up(&mut self, id: &PaneId, count: usize) {
|
|
||||||
let pane = self.panes.get_mut(id).unwrap();
|
|
||||||
pane.reduce_height_up(count);
|
|
||||||
if let PaneId::Terminal(pid) = id {
|
|
||||||
self.os_api
|
|
||||||
.set_terminal_size_using_fd(*pid, pane.columns() as u16, pane.rows() as u16);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn increase_pane_height_down(&mut self, id: &PaneId, count: usize) {
|
|
||||||
let pane = self.panes.get_mut(id).unwrap();
|
|
||||||
pane.increase_height_down(count);
|
|
||||||
if let PaneId::Terminal(pid) = pane.pid() {
|
|
||||||
self.os_api
|
|
||||||
.set_terminal_size_using_fd(pid, pane.columns() as u16, pane.rows() as u16);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn increase_pane_width_right(&mut self, id: &PaneId, count: usize) {
|
|
||||||
let pane = self.panes.get_mut(id).unwrap();
|
|
||||||
pane.increase_width_right(count);
|
|
||||||
if let PaneId::Terminal(pid) = pane.pid() {
|
|
||||||
self.os_api
|
|
||||||
.set_terminal_size_using_fd(pid, pane.columns() as u16, pane.rows() as u16);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn reduce_pane_width_left(&mut self, id: &PaneId, count: usize) {
|
|
||||||
let pane = self.panes.get_mut(id).unwrap();
|
|
||||||
pane.reduce_width_left(count);
|
|
||||||
if let PaneId::Terminal(pid) = pane.pid() {
|
|
||||||
self.os_api
|
|
||||||
.set_terminal_size_using_fd(pid, pane.columns() as u16, pane.rows() as u16);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn find_next_increasable_horizontal_pane(
|
|
||||||
panes: &BTreeMap<PaneId, Box<dyn Pane>>,
|
|
||||||
right_of: &dyn Pane,
|
|
||||||
increase_by: usize,
|
|
||||||
) -> Option<PaneId> {
|
|
||||||
let next_pane_candidates = panes.values().filter(
|
|
||||||
|p| {
|
|
||||||
p.x() == right_of.x() + right_of.columns() + 1 && p.horizontally_overlaps_with(right_of)
|
|
||||||
}, // TODO: the name here is wrong, it should be vertically_overlaps_with
|
|
||||||
);
|
|
||||||
let resizable_candidates =
|
|
||||||
next_pane_candidates.filter(|p| p.can_increase_height_by(increase_by));
|
|
||||||
resizable_candidates.fold(None, |next_pane_id, p| match next_pane_id {
|
|
||||||
Some(next_pane) => {
|
|
||||||
let next_pane = panes.get(&next_pane).unwrap();
|
|
||||||
if next_pane.y() < p.y() {
|
|
||||||
next_pane_id
|
|
||||||
} else {
|
|
||||||
Some(p.pid())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => Some(p.pid()),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn find_next_increasable_vertical_pane(
|
|
||||||
panes: &BTreeMap<PaneId, Box<dyn Pane>>,
|
|
||||||
below: &dyn Pane,
|
|
||||||
increase_by: usize,
|
|
||||||
) -> Option<PaneId> {
|
|
||||||
let next_pane_candidates = panes.values().filter(
|
|
||||||
|p| p.y() == below.y() + below.rows() + 1 && p.vertically_overlaps_with(below), // TODO: the name here is wrong, it should be horizontally_overlaps_with
|
|
||||||
);
|
|
||||||
let resizable_candidates =
|
|
||||||
next_pane_candidates.filter(|p| p.can_increase_width_by(increase_by));
|
|
||||||
resizable_candidates.fold(None, |next_pane_id, p| match next_pane_id {
|
|
||||||
Some(next_pane) => {
|
|
||||||
let next_pane = panes.get(&next_pane).unwrap();
|
|
||||||
if next_pane.x() < p.x() {
|
|
||||||
next_pane_id
|
|
||||||
} else {
|
|
||||||
Some(p.pid())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => Some(p.pid()),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn find_next_reducible_vertical_pane(
|
|
||||||
panes: &BTreeMap<PaneId, Box<dyn Pane>>,
|
|
||||||
below: &dyn Pane,
|
|
||||||
reduce_by: usize,
|
|
||||||
) -> Option<PaneId> {
|
|
||||||
let next_pane_candidates = panes.values().filter(
|
|
||||||
|p| p.y() == below.y() + below.rows() + 1 && p.vertically_overlaps_with(below), // TODO: the name here is wrong, it should be horizontally_overlaps_with
|
|
||||||
);
|
|
||||||
let resizable_candidates = next_pane_candidates.filter(|p| p.can_reduce_width_by(reduce_by));
|
|
||||||
resizable_candidates.fold(None, |next_pane_id, p| match next_pane_id {
|
|
||||||
Some(next_pane) => {
|
|
||||||
let next_pane = panes.get(&next_pane).unwrap();
|
|
||||||
if next_pane.x() < p.x() {
|
|
||||||
next_pane_id
|
|
||||||
} else {
|
|
||||||
Some(p.pid())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => Some(p.pid()),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn find_next_reducible_horizontal_pane(
|
|
||||||
panes: &BTreeMap<PaneId, Box<dyn Pane>>,
|
|
||||||
right_of: &dyn Pane,
|
|
||||||
reduce_by: usize,
|
|
||||||
) -> Option<PaneId> {
|
|
||||||
let next_pane_candidates = panes.values().filter(
|
|
||||||
|p| {
|
|
||||||
p.x() == right_of.x() + right_of.columns() + 1 && p.horizontally_overlaps_with(right_of)
|
|
||||||
}, // TODO: the name here is wrong, it should be vertically_overlaps_with
|
|
||||||
);
|
|
||||||
let resizable_candidates = next_pane_candidates.filter(|p| p.can_reduce_height_by(reduce_by));
|
|
||||||
resizable_candidates.fold(None, |next_pane_id, p| match next_pane_id {
|
|
||||||
Some(next_pane) => {
|
|
||||||
let next_pane = panes.get(&next_pane).unwrap();
|
|
||||||
if next_pane.y() < p.y() {
|
|
||||||
next_pane_id
|
|
||||||
} else {
|
|
||||||
Some(p.pid())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => Some(p.pid()),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn find_increasable_horizontal_chain(
|
|
||||||
panes: &BTreeMap<PaneId, Box<dyn Pane>>,
|
|
||||||
increase_by: usize,
|
|
||||||
screen_width: usize,
|
|
||||||
screen_height: usize, // TODO: this is the previous size (make this clearer)
|
|
||||||
) -> Option<Vec<PaneId>> {
|
|
||||||
let mut horizontal_coordinate = 0;
|
|
||||||
loop {
|
|
||||||
if horizontal_coordinate == screen_height {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
match panes
|
|
||||||
.values()
|
|
||||||
.find(|p| p.x() == 0 && p.y() == horizontal_coordinate)
|
|
||||||
{
|
|
||||||
Some(leftmost_pane) => {
|
|
||||||
if !leftmost_pane.can_increase_height_by(increase_by) {
|
|
||||||
horizontal_coordinate = leftmost_pane.y() + leftmost_pane.rows() + 1;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
let mut panes_to_resize = vec![];
|
|
||||||
let mut current_pane = leftmost_pane;
|
|
||||||
loop {
|
|
||||||
panes_to_resize.push(current_pane.pid());
|
|
||||||
if current_pane.x() + current_pane.columns() == screen_width {
|
|
||||||
return Some(panes_to_resize);
|
|
||||||
}
|
|
||||||
match find_next_increasable_horizontal_pane(
|
|
||||||
panes,
|
|
||||||
current_pane.as_ref(),
|
|
||||||
increase_by,
|
|
||||||
) {
|
|
||||||
Some(next_pane_id) => {
|
|
||||||
current_pane = panes.get(&next_pane_id).unwrap();
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
horizontal_coordinate = leftmost_pane.y() + leftmost_pane.rows() + 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn find_increasable_vertical_chain(
|
|
||||||
panes: &BTreeMap<PaneId, Box<dyn Pane>>,
|
|
||||||
increase_by: usize,
|
|
||||||
screen_width: usize,
|
|
||||||
screen_height: usize, // TODO: this is the previous size (make this clearer)
|
|
||||||
) -> Option<Vec<PaneId>> {
|
|
||||||
let mut vertical_coordinate = 0;
|
|
||||||
loop {
|
|
||||||
if vertical_coordinate == screen_width {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
match panes
|
|
||||||
.values()
|
|
||||||
.find(|p| p.y() == 0 && p.x() == vertical_coordinate)
|
|
||||||
{
|
|
||||||
Some(topmost_pane) => {
|
|
||||||
if !topmost_pane.can_increase_width_by(increase_by) {
|
|
||||||
vertical_coordinate = topmost_pane.x() + topmost_pane.columns() + 1;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
let mut panes_to_resize = vec![];
|
|
||||||
let mut current_pane = topmost_pane;
|
|
||||||
loop {
|
|
||||||
panes_to_resize.push(current_pane.pid());
|
|
||||||
if current_pane.y() + current_pane.rows() == screen_height {
|
|
||||||
return Some(panes_to_resize);
|
|
||||||
}
|
|
||||||
match find_next_increasable_vertical_pane(
|
|
||||||
panes,
|
|
||||||
current_pane.as_ref(),
|
|
||||||
increase_by,
|
|
||||||
) {
|
|
||||||
Some(next_pane_id) => {
|
|
||||||
current_pane = panes.get(&next_pane_id).unwrap();
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
vertical_coordinate = topmost_pane.x() + topmost_pane.columns() + 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn find_reducible_horizontal_chain(
|
|
||||||
panes: &BTreeMap<PaneId, Box<dyn Pane>>,
|
|
||||||
reduce_by: usize,
|
|
||||||
screen_width: usize,
|
|
||||||
screen_height: usize, // TODO: this is the previous size (make this clearer)
|
|
||||||
) -> Option<Vec<PaneId>> {
|
|
||||||
let mut horizontal_coordinate = 0;
|
|
||||||
loop {
|
|
||||||
if horizontal_coordinate == screen_height {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
match panes
|
|
||||||
.values()
|
|
||||||
.find(|p| p.x() == 0 && p.y() == horizontal_coordinate)
|
|
||||||
{
|
|
||||||
Some(leftmost_pane) => {
|
|
||||||
if !leftmost_pane.can_reduce_height_by(reduce_by) {
|
|
||||||
horizontal_coordinate = leftmost_pane.y() + leftmost_pane.rows() + 1;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
let mut panes_to_resize = vec![];
|
|
||||||
let mut current_pane = leftmost_pane;
|
|
||||||
loop {
|
|
||||||
panes_to_resize.push(current_pane.pid());
|
|
||||||
if current_pane.x() + current_pane.columns() == screen_width {
|
|
||||||
return Some(panes_to_resize);
|
|
||||||
}
|
|
||||||
match find_next_reducible_horizontal_pane(
|
|
||||||
panes,
|
|
||||||
current_pane.as_ref(),
|
|
||||||
reduce_by,
|
|
||||||
) {
|
|
||||||
Some(next_pane_id) => {
|
|
||||||
current_pane = panes.get(&next_pane_id).unwrap();
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
horizontal_coordinate = leftmost_pane.y() + leftmost_pane.rows() + 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn find_reducible_vertical_chain(
|
|
||||||
panes: &BTreeMap<PaneId, Box<dyn Pane>>,
|
|
||||||
increase_by: usize,
|
|
||||||
screen_width: usize,
|
|
||||||
screen_height: usize, // TODO: this is the previous size (make this clearer)
|
|
||||||
) -> Option<Vec<PaneId>> {
|
|
||||||
let mut vertical_coordinate = 0;
|
|
||||||
loop {
|
|
||||||
if vertical_coordinate == screen_width {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
match panes
|
|
||||||
.values()
|
|
||||||
.find(|p| p.y() == 0 && p.x() == vertical_coordinate)
|
|
||||||
{
|
|
||||||
Some(topmost_pane) => {
|
|
||||||
if !topmost_pane.can_reduce_width_by(increase_by) {
|
|
||||||
vertical_coordinate = topmost_pane.x() + topmost_pane.columns() + 1;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
let mut panes_to_resize = vec![];
|
|
||||||
let mut current_pane = topmost_pane;
|
|
||||||
loop {
|
|
||||||
panes_to_resize.push(current_pane.pid());
|
|
||||||
if current_pane.y() + current_pane.rows() == screen_height {
|
|
||||||
return Some(panes_to_resize);
|
|
||||||
}
|
|
||||||
match find_next_reducible_vertical_pane(
|
|
||||||
panes,
|
|
||||||
current_pane.as_ref(),
|
|
||||||
increase_by,
|
|
||||||
) {
|
|
||||||
Some(next_pane_id) => {
|
|
||||||
current_pane = panes.get(&next_pane_id).unwrap();
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
vertical_coordinate = topmost_pane.x() + topmost_pane.columns() + 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The last pane needs to end at the end of the space
|
||||||
|
let last = spans.last().unwrap();
|
||||||
|
constraints.insert((last.pos_var + last.size_var) | EQ(REQUIRED) | space as f64);
|
||||||
|
|
||||||
|
constraints
|
||||||
}
|
}
|
||||||
|
@ -158,7 +158,8 @@ pub(crate) fn zellij_exports(store: &Store, plugin_env: &PluginEnv) -> ImportObj
|
|||||||
host_subscribe,
|
host_subscribe,
|
||||||
host_unsubscribe,
|
host_unsubscribe,
|
||||||
host_set_invisible_borders,
|
host_set_invisible_borders,
|
||||||
host_set_max_height,
|
host_set_fixed_height,
|
||||||
|
host_set_fixed_width,
|
||||||
host_set_selectable,
|
host_set_selectable,
|
||||||
host_get_plugin_ids,
|
host_get_plugin_ids,
|
||||||
host_open_file,
|
host_open_file,
|
||||||
@ -189,13 +190,24 @@ fn host_set_selectable(plugin_env: &PluginEnv, selectable: i32) {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn host_set_max_height(plugin_env: &PluginEnv, max_height: i32) {
|
fn host_set_fixed_height(plugin_env: &PluginEnv, fixed_height: i32) {
|
||||||
let max_height = max_height as usize;
|
let fixed_height = fixed_height as usize;
|
||||||
plugin_env
|
plugin_env
|
||||||
.senders
|
.senders
|
||||||
.send_to_screen(ScreenInstruction::SetMaxHeight(
|
.send_to_screen(ScreenInstruction::SetFixedHeight(
|
||||||
PaneId::Plugin(plugin_env.plugin_id),
|
PaneId::Plugin(plugin_env.plugin_id),
|
||||||
max_height,
|
fixed_height,
|
||||||
|
))
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn host_set_fixed_width(plugin_env: &PluginEnv, fixed_width: i32) {
|
||||||
|
let fixed_width = fixed_width as usize;
|
||||||
|
plugin_env
|
||||||
|
.senders
|
||||||
|
.send_to_screen(ScreenInstruction::SetFixedWidth(
|
||||||
|
PaneId::Plugin(plugin_env.plugin_id),
|
||||||
|
fixed_width,
|
||||||
))
|
))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
@ -17,8 +17,12 @@ pub fn unsubscribe(event_types: &[EventType]) {
|
|||||||
|
|
||||||
// Plugin Settings
|
// Plugin Settings
|
||||||
|
|
||||||
pub fn set_max_height(max_height: i32) {
|
pub fn set_fixed_height(fixed_height: i32) {
|
||||||
unsafe { host_set_max_height(max_height) };
|
unsafe { host_set_fixed_height(fixed_height) };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_fixed_width(fixed_width: i32) {
|
||||||
|
unsafe { host_set_fixed_width(fixed_width) };
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_selectable(selectable: bool) {
|
pub fn set_selectable(selectable: bool) {
|
||||||
@ -64,7 +68,8 @@ pub fn object_to_stdout(object: &impl Serialize) {
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
fn host_subscribe();
|
fn host_subscribe();
|
||||||
fn host_unsubscribe();
|
fn host_unsubscribe();
|
||||||
fn host_set_max_height(max_height: i32);
|
fn host_set_fixed_height(fixed_height: i32);
|
||||||
|
fn host_set_fixed_width(fixed_width: i32);
|
||||||
fn host_set_selectable(selectable: i32);
|
fn host_set_selectable(selectable: i32);
|
||||||
fn host_set_invisible_borders(invisible_borders: i32);
|
fn host_set_invisible_borders(invisible_borders: i32);
|
||||||
fn host_get_plugin_ids();
|
fn host_get_plugin_ids();
|
||||||
|
@ -207,7 +207,8 @@ pub enum ScreenContext {
|
|||||||
ToggleActiveTerminalFullscreen,
|
ToggleActiveTerminalFullscreen,
|
||||||
SetSelectable,
|
SetSelectable,
|
||||||
SetInvisibleBorders,
|
SetInvisibleBorders,
|
||||||
SetMaxHeight,
|
SetFixedHeight,
|
||||||
|
SetFixedWidth,
|
||||||
ClosePane,
|
ClosePane,
|
||||||
ApplyLayout,
|
ApplyLayout,
|
||||||
NewTab,
|
NewTab,
|
||||||
|
@ -9,8 +9,11 @@ pub struct PositionAndSize {
|
|||||||
pub y: usize,
|
pub y: usize,
|
||||||
pub rows: usize,
|
pub rows: usize,
|
||||||
pub columns: usize,
|
pub columns: usize,
|
||||||
pub max_rows: Option<usize>,
|
// FIXME: Honestly, these shouldn't exist and rows / columns should be enums like:
|
||||||
pub max_columns: Option<usize>,
|
// Dimension::Flex(usize) / Dimension::Fixed(usize), but 400+ compiler errors is more than
|
||||||
|
// I'm in the mood for right now...
|
||||||
|
pub rows_fixed: bool,
|
||||||
|
pub cols_fixed: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Winsize> for PositionAndSize {
|
impl From<Winsize> for PositionAndSize {
|
||||||
|
Loading…
Reference in New Issue
Block a user