Floating panes in layouts (#2047)
* work * tests passing * tests: floating panes in layouts * panes(plugins): floating plugins working * refactor(tab): layout applier * style(comment): remove outdated * style(fmt): rustfmt
This commit is contained in:
parent
17205793e4
commit
799fa5de8d
68 changed files with 2051 additions and 576 deletions
|
|
@ -179,7 +179,7 @@ fn get_keys_and_hints(mi: &ModeInfo) -> Vec<(String, String, Vec<Key>)> {
|
|||
|
||||
vec![
|
||||
(s("Move focus"), s("Move"), focus_keys),
|
||||
(s("New"), s("New"), action_key(&km, &[A::NewTab(None, None), TO_NORMAL])),
|
||||
(s("New"), s("New"), action_key(&km, &[A::NewTab(None, vec![], None), TO_NORMAL])),
|
||||
(s("Close"), s("Close"), action_key(&km, &[A::CloseTab, TO_NORMAL])),
|
||||
(s("Rename"), s("Rename"),
|
||||
action_key(&km, &[A::SwitchToMode(IM::RenameTab), A::TabNameInput(vec![0])])),
|
||||
|
|
@ -253,7 +253,7 @@ fn get_keys_and_hints(mi: &ModeInfo) -> Vec<(String, String, Vec<Key>)> {
|
|||
(s("Split down"), s("Down"), action_key(&km, &[A::NewPane(Some(Dir::Down), None), TO_NORMAL])),
|
||||
(s("Split right"), s("Right"), action_key(&km, &[A::NewPane(Some(Dir::Right), None), TO_NORMAL])),
|
||||
(s("Fullscreen"), s("Fullscreen"), action_key(&km, &[A::ToggleFocusFullscreen, TO_NORMAL])),
|
||||
(s("New tab"), s("New"), action_key(&km, &[A::NewTab(None, None), TO_NORMAL])),
|
||||
(s("New tab"), s("New"), action_key(&km, &[A::NewTab(None, vec![], None), TO_NORMAL])),
|
||||
(s("Rename tab"), s("Rename"),
|
||||
action_key(&km, &[A::SwitchToMode(IM::RenameTab), A::TabNameInput(vec![0])])),
|
||||
(s("Previous Tab"), s("Previous"), action_key(&km, &[A::GoToPreviousTab, TO_NORMAL])),
|
||||
|
|
|
|||
|
|
@ -332,7 +332,7 @@ pub fn start_server(mut os_input: Box<dyn ServerOsApi>, socket_path: PathBuf) {
|
|||
})
|
||||
});
|
||||
|
||||
let spawn_tabs = |tab_layout, tab_name| {
|
||||
let spawn_tabs = |tab_layout, floating_panes_layout, tab_name| {
|
||||
session_data
|
||||
.read()
|
||||
.unwrap()
|
||||
|
|
@ -342,6 +342,7 @@ pub fn start_server(mut os_input: Box<dyn ServerOsApi>, socket_path: PathBuf) {
|
|||
.send_to_screen(ScreenInstruction::NewTab(
|
||||
default_shell.clone(),
|
||||
tab_layout,
|
||||
floating_panes_layout,
|
||||
tab_name,
|
||||
client_id,
|
||||
))
|
||||
|
|
@ -349,8 +350,12 @@ pub fn start_server(mut os_input: Box<dyn ServerOsApi>, socket_path: PathBuf) {
|
|||
};
|
||||
|
||||
if layout.has_tabs() {
|
||||
for (tab_name, tab_layout) in layout.tabs() {
|
||||
spawn_tabs(Some(tab_layout.clone()), tab_name);
|
||||
for (tab_name, tab_layout, floating_panes_layout) in layout.tabs() {
|
||||
spawn_tabs(
|
||||
Some(tab_layout.clone()),
|
||||
floating_panes_layout.clone(),
|
||||
tab_name,
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(focused_tab_index) = layout.focused_tab_index() {
|
||||
|
|
@ -367,7 +372,7 @@ pub fn start_server(mut os_input: Box<dyn ServerOsApi>, socket_path: PathBuf) {
|
|||
.unwrap();
|
||||
}
|
||||
} else {
|
||||
spawn_tabs(None, None);
|
||||
spawn_tabs(None, layout.floating_panes_template.clone(), None);
|
||||
}
|
||||
session_data
|
||||
.read()
|
||||
|
|
|
|||
|
|
@ -25,7 +25,8 @@ use zellij_utils::{
|
|||
data::{ModeInfo, Style},
|
||||
errors::prelude::*,
|
||||
input::command::RunCommand,
|
||||
pane_size::{Offset, PaneGeom, Size, Viewport},
|
||||
input::layout::FloatingPanesLayout,
|
||||
pane_size::{Dimension, Offset, PaneGeom, Size, Viewport},
|
||||
};
|
||||
|
||||
const RESIZE_INCREMENT_WIDTH: usize = 5;
|
||||
|
|
@ -224,9 +225,55 @@ impl FloatingPanes {
|
|||
);
|
||||
floating_pane_grid.find_room_for_new_pane()
|
||||
}
|
||||
pub fn position_floating_pane_layout(
|
||||
&mut self,
|
||||
floating_pane_layout: &FloatingPanesLayout,
|
||||
) -> PaneGeom {
|
||||
let display_area = *self.display_area.borrow();
|
||||
let viewport = *self.viewport.borrow();
|
||||
let floating_pane_grid = FloatingPaneGrid::new(
|
||||
&mut self.panes,
|
||||
&mut self.desired_pane_positions,
|
||||
display_area,
|
||||
viewport,
|
||||
);
|
||||
let mut position = floating_pane_grid.find_room_for_new_pane().unwrap(); // TODO: no unwrap
|
||||
if let Some(x) = &floating_pane_layout.x {
|
||||
position.x = x.to_position(display_area.cols);
|
||||
}
|
||||
if let Some(y) = &floating_pane_layout.y {
|
||||
position.y = y.to_position(display_area.rows);
|
||||
}
|
||||
if let Some(width) = &floating_pane_layout.width {
|
||||
position.cols = Dimension::fixed(width.to_position(display_area.cols));
|
||||
}
|
||||
if let Some(height) = &floating_pane_layout.height {
|
||||
position.rows = Dimension::fixed(height.to_position(display_area.rows));
|
||||
}
|
||||
if position.cols.as_usize() > display_area.cols {
|
||||
position.cols = Dimension::fixed(display_area.cols);
|
||||
}
|
||||
if position.rows.as_usize() > display_area.rows {
|
||||
position.rows = Dimension::fixed(display_area.rows);
|
||||
}
|
||||
if position.x + position.cols.as_usize() > display_area.cols {
|
||||
position.x = position
|
||||
.x
|
||||
.saturating_sub((position.x + position.cols.as_usize()) - display_area.cols);
|
||||
}
|
||||
if position.y + position.rows.as_usize() > display_area.rows {
|
||||
position.y = position
|
||||
.y
|
||||
.saturating_sub((position.y + position.rows.as_usize()) - display_area.rows);
|
||||
}
|
||||
position
|
||||
}
|
||||
pub fn first_floating_pane_id(&self) -> Option<PaneId> {
|
||||
self.panes.keys().next().copied()
|
||||
}
|
||||
pub fn last_floating_pane_id(&self) -> Option<PaneId> {
|
||||
self.panes.keys().last().copied()
|
||||
}
|
||||
pub fn first_active_floating_pane_id(&self) -> Option<PaneId> {
|
||||
self.active_panes.values().next().copied()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -539,10 +539,13 @@ impl TiledPanes {
|
|||
viewport.cols = (viewport.cols as isize + column_difference) as usize;
|
||||
display_area.cols = cols;
|
||||
},
|
||||
Err(e) => {
|
||||
Err::<(), _>(anyError::msg(e))
|
||||
.context("failed to resize tab horizontally")
|
||||
.non_fatal();
|
||||
Err(e) => match e.downcast_ref::<ZellijError>() {
|
||||
Some(ZellijError::PaneSizeUnchanged) => {}, // ignore unchanged layout
|
||||
_ => {
|
||||
Err::<(), _>(anyError::msg(e))
|
||||
.context("failed to resize tab horizontally")
|
||||
.non_fatal();
|
||||
},
|
||||
},
|
||||
};
|
||||
match pane_grid.layout(SplitDirection::Vertical, rows) {
|
||||
|
|
@ -551,10 +554,13 @@ impl TiledPanes {
|
|||
viewport.rows = (viewport.rows as isize + row_difference) as usize;
|
||||
display_area.rows = rows;
|
||||
},
|
||||
Err(e) => {
|
||||
Err::<(), _>(anyError::msg(e))
|
||||
.context("failed to resize tab vertically")
|
||||
.non_fatal();
|
||||
Err(e) => match e.downcast_ref::<ZellijError>() {
|
||||
Some(ZellijError::PaneSizeUnchanged) => {}, // ignore unchanged layout
|
||||
_ => {
|
||||
Err::<(), _>(anyError::msg(e))
|
||||
.context("failed to resize tab vertically")
|
||||
.non_fatal();
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ use zellij_utils::{
|
|||
errors::{prelude::*, ContextType, PluginContext},
|
||||
input::{
|
||||
command::TerminalAction,
|
||||
layout::{Layout, PaneLayout, Run, RunPlugin, RunPluginLocation},
|
||||
layout::{FloatingPanesLayout, Layout, PaneLayout, Run, RunPlugin, RunPluginLocation},
|
||||
plugins::PluginsConfig,
|
||||
},
|
||||
pane_size::Size,
|
||||
|
|
@ -29,6 +29,7 @@ pub enum PluginInstruction {
|
|||
NewTab(
|
||||
Option<TerminalAction>,
|
||||
Option<PaneLayout>,
|
||||
Vec<FloatingPanesLayout>,
|
||||
Option<String>, // tab name
|
||||
usize, // tab_index
|
||||
ClientId,
|
||||
|
|
@ -69,7 +70,6 @@ pub(crate) fn plugin_thread_main(
|
|||
let (event, mut err_ctx) = bus.recv().expect("failed to receive event on channel");
|
||||
err_ctx.add_call(ContextType::Plugin((&event).into()));
|
||||
match event {
|
||||
// TODO: remove pid_tx from here
|
||||
PluginInstruction::Load(run, tab_index, client_id, size) => {
|
||||
wasm_bridge.load_plugin(&run, tab_index, size, client_id)?;
|
||||
},
|
||||
|
|
@ -91,16 +91,22 @@ pub(crate) fn plugin_thread_main(
|
|||
PluginInstruction::NewTab(
|
||||
terminal_action,
|
||||
tab_layout,
|
||||
floating_panes_layout,
|
||||
tab_name,
|
||||
tab_index,
|
||||
client_id,
|
||||
) => {
|
||||
let mut plugin_ids: HashMap<RunPluginLocation, Vec<u32>> = HashMap::new();
|
||||
let extracted_run_instructions = tab_layout
|
||||
let mut extracted_run_instructions = tab_layout
|
||||
.clone()
|
||||
.unwrap_or_else(|| layout.new_tab())
|
||||
.unwrap_or_else(|| layout.new_tab().0)
|
||||
.extract_run_instructions();
|
||||
let size = Size::default(); // TODO: is this bad?
|
||||
let size = Size::default();
|
||||
let mut extracted_floating_plugins: Vec<Option<Run>> = floating_panes_layout
|
||||
.iter()
|
||||
.map(|f| f.run.clone())
|
||||
.collect();
|
||||
extracted_run_instructions.append(&mut extracted_floating_plugins);
|
||||
for run_instruction in extracted_run_instructions {
|
||||
if let Some(Run::Plugin(run)) = run_instruction {
|
||||
let plugin_id =
|
||||
|
|
@ -111,6 +117,7 @@ pub(crate) fn plugin_thread_main(
|
|||
drop(bus.senders.send_to_pty(PtyInstruction::NewTab(
|
||||
terminal_action,
|
||||
tab_layout,
|
||||
floating_panes_layout,
|
||||
tab_name,
|
||||
tab_index,
|
||||
plugin_ids,
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ use zellij_utils::{
|
|||
errors::{ContextType, PtyContext},
|
||||
input::{
|
||||
command::{RunCommand, TerminalAction},
|
||||
layout::{Layout, PaneLayout, Run, RunPluginLocation},
|
||||
layout::{FloatingPanesLayout, Layout, PaneLayout, Run, RunPluginLocation},
|
||||
},
|
||||
};
|
||||
|
||||
|
|
@ -50,6 +50,7 @@ pub enum PtyInstruction {
|
|||
NewTab(
|
||||
Option<TerminalAction>,
|
||||
Option<PaneLayout>,
|
||||
Vec<FloatingPanesLayout>,
|
||||
Option<String>,
|
||||
usize, // tab_index
|
||||
HashMap<RunPluginLocation, Vec<u32>>, // plugin_ids
|
||||
|
|
@ -335,6 +336,7 @@ pub(crate) fn pty_thread_main(mut pty: Pty, layout: Box<Layout>) -> Result<()> {
|
|||
PtyInstruction::NewTab(
|
||||
terminal_action,
|
||||
tab_layout,
|
||||
floating_panes_layout,
|
||||
tab_name,
|
||||
tab_index,
|
||||
plugin_ids,
|
||||
|
|
@ -342,8 +344,14 @@ pub(crate) fn pty_thread_main(mut pty: Pty, layout: Box<Layout>) -> Result<()> {
|
|||
) => {
|
||||
let err_context = || format!("failed to open new tab for client {}", client_id);
|
||||
|
||||
let floating_panes_layout = if floating_panes_layout.is_empty() {
|
||||
layout.new_tab().1
|
||||
} else {
|
||||
floating_panes_layout
|
||||
};
|
||||
pty.spawn_terminals_for_layout(
|
||||
tab_layout.unwrap_or_else(|| layout.new_tab()),
|
||||
tab_layout.unwrap_or_else(|| layout.new_tab().0),
|
||||
floating_panes_layout,
|
||||
terminal_action.clone(),
|
||||
plugin_ids,
|
||||
tab_index,
|
||||
|
|
@ -562,6 +570,7 @@ impl Pty {
|
|||
pub fn spawn_terminals_for_layout(
|
||||
&mut self,
|
||||
layout: PaneLayout,
|
||||
floating_panes_layout: Vec<FloatingPanesLayout>,
|
||||
default_shell: Option<TerminalAction>,
|
||||
plugin_ids: HashMap<RunPluginLocation, Vec<u32>>,
|
||||
tab_index: usize,
|
||||
|
|
@ -572,176 +581,28 @@ impl Pty {
|
|||
let mut default_shell = default_shell.unwrap_or_else(|| self.get_default_terminal(None));
|
||||
self.fill_cwd(&mut default_shell, client_id);
|
||||
let extracted_run_instructions = layout.extract_run_instructions();
|
||||
let extracted_floating_run_instructions =
|
||||
floating_panes_layout.iter().map(|f| f.run.clone());
|
||||
let mut new_pane_pids: Vec<(u32, bool, Option<RunCommand>, Result<RawFd>)> = vec![]; // (terminal_id,
|
||||
// starts_held,
|
||||
// run_command,
|
||||
// file_descriptor)
|
||||
let mut new_floating_panes_pids: Vec<(u32, bool, Option<RunCommand>, Result<RawFd>)> =
|
||||
vec![]; // same
|
||||
// as
|
||||
// new_pane_pids
|
||||
for run_instruction in extracted_run_instructions {
|
||||
let quit_cb = Box::new({
|
||||
let senders = self.bus.senders.clone();
|
||||
move |pane_id, _exit_status, _command| {
|
||||
let _ = senders.send_to_screen(ScreenInstruction::ClosePane(pane_id, None));
|
||||
}
|
||||
});
|
||||
match run_instruction {
|
||||
Some(Run::Command(command)) => {
|
||||
let starts_held = command.hold_on_start;
|
||||
let hold_on_close = command.hold_on_close;
|
||||
let quit_cb = Box::new({
|
||||
let senders = self.bus.senders.clone();
|
||||
move |pane_id, exit_status, command| {
|
||||
if hold_on_close {
|
||||
let _ = senders.send_to_screen(ScreenInstruction::HoldPane(
|
||||
pane_id,
|
||||
exit_status,
|
||||
command,
|
||||
None,
|
||||
));
|
||||
} else {
|
||||
let _ = senders
|
||||
.send_to_screen(ScreenInstruction::ClosePane(pane_id, None));
|
||||
}
|
||||
}
|
||||
});
|
||||
let cmd = TerminalAction::RunCommand(command.clone());
|
||||
if starts_held {
|
||||
// we don't actually open a terminal in this case, just wait for the user to run it
|
||||
match self
|
||||
.bus
|
||||
.os_input
|
||||
.as_mut()
|
||||
.context("no OS I/O interface found")
|
||||
.with_context(err_context)?
|
||||
.reserve_terminal_id()
|
||||
{
|
||||
Ok(terminal_id) => {
|
||||
new_pane_pids.push((
|
||||
terminal_id,
|
||||
starts_held,
|
||||
Some(command.clone()),
|
||||
Ok(terminal_id as i32), // this is not actually correct but gets
|
||||
// stripped later
|
||||
));
|
||||
},
|
||||
Err(e) => Err::<(), _>(e).with_context(err_context).non_fatal(),
|
||||
}
|
||||
} else {
|
||||
match self
|
||||
.bus
|
||||
.os_input
|
||||
.as_mut()
|
||||
.context("no OS I/O interface found")
|
||||
.with_context(err_context)?
|
||||
.spawn_terminal(cmd, quit_cb, self.default_editor.clone())
|
||||
.with_context(err_context)
|
||||
{
|
||||
Ok((terminal_id, pid_primary, child_fd)) => {
|
||||
self.id_to_child_pid.insert(terminal_id, child_fd);
|
||||
new_pane_pids.push((
|
||||
terminal_id,
|
||||
starts_held,
|
||||
Some(command.clone()),
|
||||
Ok(pid_primary),
|
||||
));
|
||||
},
|
||||
Err(err) => match err.downcast_ref::<ZellijError>() {
|
||||
Some(ZellijError::CommandNotFound { terminal_id, .. }) => {
|
||||
new_pane_pids.push((
|
||||
*terminal_id,
|
||||
starts_held,
|
||||
Some(command.clone()),
|
||||
Err(err),
|
||||
));
|
||||
},
|
||||
_ => {
|
||||
Err::<(), _>(err).non_fatal();
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
Some(Run::Cwd(cwd)) => {
|
||||
let starts_held = false; // we do not hold Cwd panes
|
||||
let shell = self.get_default_terminal(Some(cwd));
|
||||
match self
|
||||
.bus
|
||||
.os_input
|
||||
.as_mut()
|
||||
.context("no OS I/O interface found")
|
||||
.with_context(err_context)?
|
||||
.spawn_terminal(shell, quit_cb, self.default_editor.clone())
|
||||
.with_context(err_context)
|
||||
{
|
||||
Ok((terminal_id, pid_primary, child_fd)) => {
|
||||
self.id_to_child_pid.insert(terminal_id, child_fd);
|
||||
new_pane_pids.push((terminal_id, starts_held, None, Ok(pid_primary)));
|
||||
},
|
||||
Err(err) => match err.downcast_ref::<ZellijError>() {
|
||||
Some(ZellijError::CommandNotFound { terminal_id, .. }) => {
|
||||
new_pane_pids.push((*terminal_id, starts_held, None, Err(err)));
|
||||
},
|
||||
_ => {
|
||||
Err::<(), _>(err).non_fatal();
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
Some(Run::EditFile(path_to_file, line_number)) => {
|
||||
let starts_held = false; // we do not hold edit panes (for now?)
|
||||
match self
|
||||
.bus
|
||||
.os_input
|
||||
.as_mut()
|
||||
.context("no OS I/O interface found")
|
||||
.with_context(err_context)?
|
||||
.spawn_terminal(
|
||||
TerminalAction::OpenFile(path_to_file, line_number),
|
||||
quit_cb,
|
||||
self.default_editor.clone(),
|
||||
)
|
||||
.with_context(err_context)
|
||||
{
|
||||
Ok((terminal_id, pid_primary, child_fd)) => {
|
||||
self.id_to_child_pid.insert(terminal_id, child_fd);
|
||||
new_pane_pids.push((terminal_id, starts_held, None, Ok(pid_primary)));
|
||||
},
|
||||
Err(err) => match err.downcast_ref::<ZellijError>() {
|
||||
Some(ZellijError::CommandNotFound { terminal_id, .. }) => {
|
||||
new_pane_pids.push((*terminal_id, starts_held, None, Err(err)));
|
||||
},
|
||||
_ => {
|
||||
Err::<(), _>(err).non_fatal();
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
None => {
|
||||
let starts_held = false;
|
||||
match self
|
||||
.bus
|
||||
.os_input
|
||||
.as_mut()
|
||||
.context("no OS I/O interface found")
|
||||
.with_context(err_context)?
|
||||
.spawn_terminal(default_shell.clone(), quit_cb, self.default_editor.clone())
|
||||
.with_context(err_context)
|
||||
{
|
||||
Ok((terminal_id, pid_primary, child_fd)) => {
|
||||
self.id_to_child_pid.insert(terminal_id, child_fd);
|
||||
new_pane_pids.push((terminal_id, starts_held, None, Ok(pid_primary)));
|
||||
},
|
||||
Err(err) => match err.downcast_ref::<ZellijError>() {
|
||||
Some(ZellijError::CommandNotFound { terminal_id, .. }) => {
|
||||
new_pane_pids.push((*terminal_id, starts_held, None, Err(err)));
|
||||
},
|
||||
_ => {
|
||||
Err::<(), _>(err).non_fatal();
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
// Investigate moving plugin loading to here.
|
||||
Some(Run::Plugin(_)) => {},
|
||||
if let Some(new_pane_data) =
|
||||
self.apply_run_instruction(run_instruction, default_shell.clone())?
|
||||
{
|
||||
new_pane_pids.push(new_pane_data);
|
||||
}
|
||||
}
|
||||
for run_instruction in extracted_floating_run_instructions {
|
||||
if let Some(new_pane_data) =
|
||||
self.apply_run_instruction(run_instruction, default_shell.clone())?
|
||||
{
|
||||
new_floating_panes_pids.push(new_pane_data);
|
||||
}
|
||||
}
|
||||
// Option<RunCommand> should only be Some if the pane starts held
|
||||
|
|
@ -755,17 +616,32 @@ impl Pty {
|
|||
}
|
||||
})
|
||||
.collect();
|
||||
let new_tab_floating_pane_ids: Vec<(u32, Option<RunCommand>)> = new_floating_panes_pids
|
||||
.iter()
|
||||
.map(|(terminal_id, starts_held, run_command, _)| {
|
||||
if *starts_held {
|
||||
(*terminal_id, run_command.clone())
|
||||
} else {
|
||||
(*terminal_id, None)
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
self.bus
|
||||
.senders
|
||||
.send_to_screen(ScreenInstruction::ApplyLayout(
|
||||
layout,
|
||||
floating_panes_layout,
|
||||
new_tab_pane_ids,
|
||||
new_tab_floating_pane_ids,
|
||||
plugin_ids,
|
||||
tab_index,
|
||||
client_id,
|
||||
))
|
||||
.with_context(err_context)?;
|
||||
for (terminal_id, starts_held, run_command, pid_primary) in new_pane_pids {
|
||||
let mut terminals_to_start = vec![];
|
||||
terminals_to_start.append(&mut new_pane_pids);
|
||||
terminals_to_start.append(&mut new_floating_panes_pids);
|
||||
for (terminal_id, starts_held, run_command, pid_primary) in terminals_to_start {
|
||||
if starts_held {
|
||||
// we do not run a command or start listening for bytes on held panes
|
||||
continue;
|
||||
|
|
@ -820,6 +696,172 @@ impl Pty {
|
|||
}
|
||||
Ok(())
|
||||
}
|
||||
fn apply_run_instruction(
|
||||
&mut self,
|
||||
run_instruction: Option<Run>,
|
||||
default_shell: TerminalAction,
|
||||
) -> Result<Option<(u32, bool, Option<RunCommand>, Result<i32>)>> {
|
||||
// terminal_id,
|
||||
// starts_held,
|
||||
// command
|
||||
// successfully opened
|
||||
let err_context = || format!("failed to apply run instruction");
|
||||
let quit_cb = Box::new({
|
||||
let senders = self.bus.senders.clone();
|
||||
move |pane_id, _exit_status, _command| {
|
||||
let _ = senders.send_to_screen(ScreenInstruction::ClosePane(pane_id, None));
|
||||
}
|
||||
});
|
||||
match run_instruction {
|
||||
Some(Run::Command(command)) => {
|
||||
let starts_held = command.hold_on_start;
|
||||
let hold_on_close = command.hold_on_close;
|
||||
let quit_cb = Box::new({
|
||||
let senders = self.bus.senders.clone();
|
||||
move |pane_id, exit_status, command| {
|
||||
if hold_on_close {
|
||||
let _ = senders.send_to_screen(ScreenInstruction::HoldPane(
|
||||
pane_id,
|
||||
exit_status,
|
||||
command,
|
||||
None,
|
||||
));
|
||||
} else {
|
||||
let _ =
|
||||
senders.send_to_screen(ScreenInstruction::ClosePane(pane_id, None));
|
||||
}
|
||||
}
|
||||
});
|
||||
let cmd = TerminalAction::RunCommand(command.clone());
|
||||
if starts_held {
|
||||
// we don't actually open a terminal in this case, just wait for the user to run it
|
||||
match self
|
||||
.bus
|
||||
.os_input
|
||||
.as_mut()
|
||||
.context("no OS I/O interface found")
|
||||
.with_context(err_context)?
|
||||
.reserve_terminal_id()
|
||||
{
|
||||
Ok(terminal_id) => {
|
||||
Ok(Some((
|
||||
terminal_id,
|
||||
starts_held,
|
||||
Some(command.clone()),
|
||||
Ok(terminal_id as i32), // this is not actually correct but gets
|
||||
// stripped later
|
||||
)))
|
||||
},
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
} else {
|
||||
match self
|
||||
.bus
|
||||
.os_input
|
||||
.as_mut()
|
||||
.context("no OS I/O interface found")
|
||||
.with_context(err_context)?
|
||||
.spawn_terminal(cmd, quit_cb, self.default_editor.clone())
|
||||
.with_context(err_context)
|
||||
{
|
||||
Ok((terminal_id, pid_primary, child_fd)) => {
|
||||
self.id_to_child_pid.insert(terminal_id, child_fd);
|
||||
Ok(Some((
|
||||
terminal_id,
|
||||
starts_held,
|
||||
Some(command.clone()),
|
||||
Ok(pid_primary),
|
||||
)))
|
||||
},
|
||||
Err(err) => {
|
||||
match err.downcast_ref::<ZellijError>() {
|
||||
Some(ZellijError::CommandNotFound { terminal_id, .. }) => Ok(Some(
|
||||
(*terminal_id, starts_held, Some(command.clone()), Err(err)),
|
||||
)),
|
||||
_ => Err(err),
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
Some(Run::Cwd(cwd)) => {
|
||||
let starts_held = false; // we do not hold Cwd panes
|
||||
let shell = self.get_default_terminal(Some(cwd));
|
||||
match self
|
||||
.bus
|
||||
.os_input
|
||||
.as_mut()
|
||||
.context("no OS I/O interface found")
|
||||
.with_context(err_context)?
|
||||
.spawn_terminal(shell, quit_cb, self.default_editor.clone())
|
||||
.with_context(err_context)
|
||||
{
|
||||
Ok((terminal_id, pid_primary, child_fd)) => {
|
||||
self.id_to_child_pid.insert(terminal_id, child_fd);
|
||||
Ok(Some((terminal_id, starts_held, None, Ok(pid_primary))))
|
||||
},
|
||||
Err(err) => match err.downcast_ref::<ZellijError>() {
|
||||
Some(ZellijError::CommandNotFound { terminal_id, .. }) => {
|
||||
Ok(Some((*terminal_id, starts_held, None, Err(err))))
|
||||
},
|
||||
_ => Err(err),
|
||||
},
|
||||
}
|
||||
},
|
||||
Some(Run::EditFile(path_to_file, line_number)) => {
|
||||
let starts_held = false; // we do not hold edit panes (for now?)
|
||||
match self
|
||||
.bus
|
||||
.os_input
|
||||
.as_mut()
|
||||
.context("no OS I/O interface found")
|
||||
.with_context(err_context)?
|
||||
.spawn_terminal(
|
||||
TerminalAction::OpenFile(path_to_file, line_number),
|
||||
quit_cb,
|
||||
self.default_editor.clone(),
|
||||
)
|
||||
.with_context(err_context)
|
||||
{
|
||||
Ok((terminal_id, pid_primary, child_fd)) => {
|
||||
self.id_to_child_pid.insert(terminal_id, child_fd);
|
||||
Ok(Some((terminal_id, starts_held, None, Ok(pid_primary))))
|
||||
},
|
||||
Err(err) => match err.downcast_ref::<ZellijError>() {
|
||||
Some(ZellijError::CommandNotFound { terminal_id, .. }) => {
|
||||
Ok(Some((*terminal_id, starts_held, None, Err(err))))
|
||||
},
|
||||
_ => Err(err),
|
||||
},
|
||||
}
|
||||
},
|
||||
None => {
|
||||
let starts_held = false;
|
||||
match self
|
||||
.bus
|
||||
.os_input
|
||||
.as_mut()
|
||||
.context("no OS I/O interface found")
|
||||
.with_context(err_context)?
|
||||
.spawn_terminal(default_shell.clone(), quit_cb, self.default_editor.clone())
|
||||
.with_context(err_context)
|
||||
{
|
||||
Ok((terminal_id, pid_primary, child_fd)) => {
|
||||
self.id_to_child_pid.insert(terminal_id, child_fd);
|
||||
Ok(Some((terminal_id, starts_held, None, Ok(pid_primary))))
|
||||
},
|
||||
Err(err) => match err.downcast_ref::<ZellijError>() {
|
||||
Some(ZellijError::CommandNotFound { terminal_id, .. }) => {
|
||||
Ok(Some((*terminal_id, starts_held, None, Err(err))))
|
||||
},
|
||||
_ => Err(err),
|
||||
},
|
||||
}
|
||||
},
|
||||
// Investigate moving plugin loading to here.
|
||||
Some(Run::Plugin(_)) => Ok(None),
|
||||
}
|
||||
}
|
||||
pub fn close_pane(&mut self, id: PaneId) -> Result<()> {
|
||||
let err_context = || format!("failed to close for pane {id:?}");
|
||||
match id {
|
||||
|
|
|
|||
|
|
@ -430,12 +430,16 @@ pub(crate) fn route_action(
|
|||
.send_to_screen(ScreenInstruction::CloseFocusedPane(client_id))
|
||||
.with_context(err_context)?;
|
||||
},
|
||||
Action::NewTab(tab_layout, tab_name) => {
|
||||
Action::NewTab(tab_layout, floating_panes_layout, tab_name) => {
|
||||
let shell = session.default_shell.clone();
|
||||
session
|
||||
.senders
|
||||
.send_to_screen(ScreenInstruction::NewTab(
|
||||
shell, tab_layout, tab_name, client_id,
|
||||
shell,
|
||||
tab_layout,
|
||||
floating_panes_layout,
|
||||
tab_name,
|
||||
client_id,
|
||||
))
|
||||
.with_context(err_context)?;
|
||||
},
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ use zellij_utils::input::options::Clipboard;
|
|||
use zellij_utils::pane_size::{Size, SizeInPixels};
|
||||
use zellij_utils::{
|
||||
input::command::TerminalAction,
|
||||
input::layout::{PaneLayout, RunPluginLocation},
|
||||
input::layout::{FloatingPanesLayout, PaneLayout, RunPluginLocation},
|
||||
position::Position,
|
||||
};
|
||||
|
||||
|
|
@ -177,12 +177,15 @@ pub enum ScreenInstruction {
|
|||
NewTab(
|
||||
Option<TerminalAction>,
|
||||
Option<PaneLayout>,
|
||||
Vec<FloatingPanesLayout>,
|
||||
Option<String>,
|
||||
ClientId,
|
||||
),
|
||||
ApplyLayout(
|
||||
PaneLayout,
|
||||
Vec<(u32, HoldForCommand)>,
|
||||
Vec<FloatingPanesLayout>,
|
||||
Vec<(u32, HoldForCommand)>, // new pane pids
|
||||
Vec<(u32, HoldForCommand)>, // new floating pane pids
|
||||
HashMap<RunPluginLocation, Vec<u32>>,
|
||||
usize, // tab_index
|
||||
ClientId,
|
||||
|
|
@ -920,7 +923,9 @@ impl Screen {
|
|||
pub fn apply_layout(
|
||||
&mut self,
|
||||
layout: PaneLayout,
|
||||
floating_panes_layout: Vec<FloatingPanesLayout>,
|
||||
new_terminal_ids: Vec<(u32, HoldForCommand)>,
|
||||
new_floating_terminal_ids: Vec<(u32, HoldForCommand)>,
|
||||
new_plugin_ids: HashMap<RunPluginLocation, Vec<u32>>,
|
||||
tab_index: usize,
|
||||
client_id: ClientId,
|
||||
|
|
@ -968,9 +973,10 @@ impl Screen {
|
|||
let tab = self.tabs.get_mut(&tab_index).unwrap(); // TODO: no unwrap
|
||||
tab.apply_layout(
|
||||
layout,
|
||||
floating_panes_layout,
|
||||
new_terminal_ids,
|
||||
new_floating_terminal_ids,
|
||||
new_plugin_ids,
|
||||
tab_index,
|
||||
client_id,
|
||||
)
|
||||
.with_context(err_context)?;
|
||||
|
|
@ -1878,7 +1884,13 @@ pub(crate) fn screen_thread_main(
|
|||
screen.unblock_input()?;
|
||||
screen.render()?;
|
||||
},
|
||||
ScreenInstruction::NewTab(default_shell, layout, tab_name, client_id) => {
|
||||
ScreenInstruction::NewTab(
|
||||
default_shell,
|
||||
layout,
|
||||
floating_panes_layout,
|
||||
tab_name,
|
||||
client_id,
|
||||
) => {
|
||||
let tab_index = screen.get_new_tab_index();
|
||||
screen.new_tab(tab_index, client_id)?;
|
||||
screen
|
||||
|
|
@ -1887,6 +1899,7 @@ pub(crate) fn screen_thread_main(
|
|||
.send_to_plugin(PluginInstruction::NewTab(
|
||||
default_shell,
|
||||
layout,
|
||||
floating_panes_layout,
|
||||
tab_name,
|
||||
tab_index,
|
||||
client_id,
|
||||
|
|
@ -1894,12 +1907,22 @@ pub(crate) fn screen_thread_main(
|
|||
},
|
||||
ScreenInstruction::ApplyLayout(
|
||||
layout,
|
||||
floating_panes_layout,
|
||||
new_pane_pids,
|
||||
new_floating_pane_pids,
|
||||
new_plugin_ids,
|
||||
tab_index,
|
||||
client_id,
|
||||
) => {
|
||||
screen.apply_layout(layout, new_pane_pids, new_plugin_ids, tab_index, client_id)?;
|
||||
screen.apply_layout(
|
||||
layout,
|
||||
floating_panes_layout,
|
||||
new_pane_pids,
|
||||
new_floating_pane_pids,
|
||||
new_plugin_ids,
|
||||
tab_index,
|
||||
client_id,
|
||||
)?;
|
||||
screen.unblock_input()?;
|
||||
screen.render()?;
|
||||
},
|
||||
|
|
|
|||
376
zellij-server/src/tab/layout_applier.rs
Normal file
376
zellij-server/src/tab/layout_applier.rs
Normal file
|
|
@ -0,0 +1,376 @@
|
|||
use zellij_utils::errors::prelude::*;
|
||||
|
||||
use crate::resize_pty;
|
||||
use crate::tab::{get_next_terminal_position, HoldForCommand, Pane};
|
||||
|
||||
use crate::{
|
||||
os_input_output::ServerOsApi,
|
||||
panes::sixel::SixelImageStore,
|
||||
panes::{FloatingPanes, TiledPanes},
|
||||
panes::{LinkHandler, PaneId, PluginPane, TerminalPane},
|
||||
plugins::PluginInstruction,
|
||||
pty::PtyInstruction,
|
||||
thread_bus::ThreadSenders,
|
||||
ClientId,
|
||||
};
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
use std::rc::Rc;
|
||||
use zellij_utils::{
|
||||
data::{Palette, Style},
|
||||
input::layout::{FloatingPanesLayout, PaneLayout, Run, RunPluginLocation},
|
||||
pane_size::{Offset, PaneGeom, Size, SizeInPixels, Viewport},
|
||||
};
|
||||
|
||||
pub struct LayoutApplier<'a> {
|
||||
viewport: Rc<RefCell<Viewport>>, // includes all non-UI panes
|
||||
senders: ThreadSenders,
|
||||
sixel_image_store: Rc<RefCell<SixelImageStore>>,
|
||||
link_handler: Rc<RefCell<LinkHandler>>,
|
||||
terminal_emulator_colors: Rc<RefCell<Palette>>,
|
||||
terminal_emulator_color_codes: Rc<RefCell<HashMap<usize, String>>>,
|
||||
character_cell_size: Rc<RefCell<Option<SizeInPixels>>>,
|
||||
style: Style,
|
||||
display_area: Rc<RefCell<Size>>, // includes all panes (including eg. the status bar and tab bar in the default layout)
|
||||
tiled_panes: &'a mut TiledPanes,
|
||||
floating_panes: &'a mut FloatingPanes,
|
||||
draw_pane_frames: bool,
|
||||
focus_pane_id: &'a mut Option<PaneId>,
|
||||
os_api: Box<dyn ServerOsApi>,
|
||||
}
|
||||
|
||||
impl<'a> LayoutApplier<'a> {
|
||||
pub fn new(
|
||||
viewport: &Rc<RefCell<Viewport>>,
|
||||
senders: &ThreadSenders,
|
||||
sixel_image_store: &Rc<RefCell<SixelImageStore>>,
|
||||
link_handler: &Rc<RefCell<LinkHandler>>,
|
||||
terminal_emulator_colors: &Rc<RefCell<Palette>>,
|
||||
terminal_emulator_color_codes: &Rc<RefCell<HashMap<usize, String>>>,
|
||||
character_cell_size: &Rc<RefCell<Option<SizeInPixels>>>,
|
||||
style: &Style,
|
||||
display_area: &Rc<RefCell<Size>>, // includes all panes (including eg. the status bar and tab bar in the default layout)
|
||||
tiled_panes: &'a mut TiledPanes,
|
||||
floating_panes: &'a mut FloatingPanes,
|
||||
draw_pane_frames: bool,
|
||||
focus_pane_id: &'a mut Option<PaneId>,
|
||||
os_api: &Box<dyn ServerOsApi>,
|
||||
) -> Self {
|
||||
let viewport = viewport.clone();
|
||||
let senders = senders.clone();
|
||||
let sixel_image_store = sixel_image_store.clone();
|
||||
let link_handler = link_handler.clone();
|
||||
let terminal_emulator_colors = terminal_emulator_colors.clone();
|
||||
let terminal_emulator_color_codes = terminal_emulator_color_codes.clone();
|
||||
let character_cell_size = character_cell_size.clone();
|
||||
let style = style.clone();
|
||||
let display_area = display_area.clone();
|
||||
let os_api = os_api.clone();
|
||||
LayoutApplier {
|
||||
viewport,
|
||||
senders,
|
||||
sixel_image_store,
|
||||
link_handler,
|
||||
terminal_emulator_colors,
|
||||
terminal_emulator_color_codes,
|
||||
character_cell_size,
|
||||
style,
|
||||
display_area,
|
||||
tiled_panes,
|
||||
floating_panes,
|
||||
draw_pane_frames,
|
||||
focus_pane_id,
|
||||
os_api,
|
||||
}
|
||||
}
|
||||
pub fn apply_layout(
|
||||
&mut self,
|
||||
layout: PaneLayout,
|
||||
floating_panes_layout: Vec<FloatingPanesLayout>,
|
||||
new_terminal_ids: Vec<(u32, HoldForCommand)>,
|
||||
new_floating_terminal_ids: Vec<(u32, HoldForCommand)>,
|
||||
mut new_plugin_ids: HashMap<RunPluginLocation, Vec<u32>>,
|
||||
client_id: ClientId,
|
||||
) -> Result<bool> {
|
||||
// true => layout has floating panes
|
||||
let layout_name = layout.name.clone();
|
||||
self.apply_tiled_panes_layout(layout, new_terminal_ids, &mut new_plugin_ids, client_id)?;
|
||||
let layout_has_floating_panes = self.apply_floating_panes_layout(
|
||||
floating_panes_layout,
|
||||
new_floating_terminal_ids,
|
||||
&mut new_plugin_ids,
|
||||
layout_name,
|
||||
)?;
|
||||
return Ok(layout_has_floating_panes);
|
||||
}
|
||||
fn apply_tiled_panes_layout(
|
||||
&mut self,
|
||||
layout: PaneLayout,
|
||||
new_terminal_ids: Vec<(u32, HoldForCommand)>,
|
||||
new_plugin_ids: &mut HashMap<RunPluginLocation, Vec<u32>>,
|
||||
client_id: ClientId,
|
||||
) -> Result<()> {
|
||||
let err_context = || format!("failed to apply tiled panes layout");
|
||||
let (viewport_cols, viewport_rows) = {
|
||||
let viewport = self.viewport.borrow();
|
||||
(viewport.cols, viewport.rows)
|
||||
};
|
||||
let mut free_space = PaneGeom::default();
|
||||
free_space.cols.set_inner(viewport_cols);
|
||||
free_space.rows.set_inner(viewport_rows);
|
||||
match layout.position_panes_in_space(&free_space) {
|
||||
Ok(positions_in_layout) => {
|
||||
let positions_and_size = positions_in_layout.iter();
|
||||
let mut new_terminal_ids = new_terminal_ids.iter();
|
||||
|
||||
let mut focus_pane_id: Option<PaneId> = None;
|
||||
let mut set_focus_pane_id = |layout: &PaneLayout, pane_id: PaneId| {
|
||||
if layout.focus.unwrap_or(false) && focus_pane_id.is_none() {
|
||||
focus_pane_id = Some(pane_id);
|
||||
}
|
||||
};
|
||||
|
||||
for (layout, position_and_size) in positions_and_size {
|
||||
// A plugin pane
|
||||
if let Some(Run::Plugin(run)) = layout.run.clone() {
|
||||
let pane_title = run.location.to_string();
|
||||
let pid = new_plugin_ids
|
||||
.get_mut(&run.location)
|
||||
.and_then(|ids| ids.pop())
|
||||
.with_context(err_context)?;
|
||||
let mut new_plugin = PluginPane::new(
|
||||
pid,
|
||||
*position_and_size,
|
||||
self.senders
|
||||
.to_plugin
|
||||
.as_ref()
|
||||
.with_context(err_context)?
|
||||
.clone(),
|
||||
pane_title,
|
||||
layout.name.clone().unwrap_or_default(),
|
||||
self.sixel_image_store.clone(),
|
||||
self.terminal_emulator_colors.clone(),
|
||||
self.terminal_emulator_color_codes.clone(),
|
||||
self.link_handler.clone(),
|
||||
self.character_cell_size.clone(),
|
||||
self.style,
|
||||
);
|
||||
new_plugin.set_borderless(layout.borderless);
|
||||
self.tiled_panes
|
||||
.add_pane_with_existing_geom(PaneId::Plugin(pid), Box::new(new_plugin));
|
||||
set_focus_pane_id(layout, PaneId::Plugin(pid));
|
||||
} else {
|
||||
// there are still panes left to fill, use the pids we received in this method
|
||||
if let Some((pid, hold_for_command)) = new_terminal_ids.next() {
|
||||
let next_terminal_position =
|
||||
get_next_terminal_position(&self.tiled_panes, &self.floating_panes);
|
||||
let initial_title = match &layout.run {
|
||||
Some(Run::Command(run_command)) => Some(run_command.to_string()),
|
||||
_ => None,
|
||||
};
|
||||
let mut new_pane = TerminalPane::new(
|
||||
*pid,
|
||||
*position_and_size,
|
||||
self.style,
|
||||
next_terminal_position,
|
||||
layout.name.clone().unwrap_or_default(),
|
||||
self.link_handler.clone(),
|
||||
self.character_cell_size.clone(),
|
||||
self.sixel_image_store.clone(),
|
||||
self.terminal_emulator_colors.clone(),
|
||||
self.terminal_emulator_color_codes.clone(),
|
||||
initial_title,
|
||||
);
|
||||
new_pane.set_borderless(layout.borderless);
|
||||
if let Some(held_command) = hold_for_command {
|
||||
new_pane.hold(None, true, held_command.clone());
|
||||
}
|
||||
self.tiled_panes.add_pane_with_existing_geom(
|
||||
PaneId::Terminal(*pid),
|
||||
Box::new(new_pane),
|
||||
);
|
||||
set_focus_pane_id(layout, PaneId::Terminal(*pid));
|
||||
}
|
||||
}
|
||||
}
|
||||
for (unused_pid, _) in new_terminal_ids {
|
||||
self.senders
|
||||
.send_to_pty(PtyInstruction::ClosePane(PaneId::Terminal(*unused_pid)))
|
||||
.with_context(err_context)?;
|
||||
}
|
||||
self.adjust_viewport();
|
||||
self.set_focused_tiled_pane(focus_pane_id, client_id);
|
||||
},
|
||||
Err(e) => {
|
||||
for (unused_pid, _) in new_terminal_ids {
|
||||
self.senders
|
||||
.send_to_pty(PtyInstruction::ClosePane(PaneId::Terminal(unused_pid)))
|
||||
.with_context(err_context)?;
|
||||
}
|
||||
Err::<(), _>(anyError::msg(e))
|
||||
.with_context(err_context)
|
||||
.non_fatal(); // TODO: propagate this to the user
|
||||
},
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
fn apply_floating_panes_layout(
|
||||
&mut self,
|
||||
floating_panes_layout: Vec<FloatingPanesLayout>,
|
||||
new_floating_terminal_ids: Vec<(u32, HoldForCommand)>,
|
||||
new_plugin_ids: &mut HashMap<RunPluginLocation, Vec<u32>>,
|
||||
layout_name: Option<String>,
|
||||
) -> Result<bool> {
|
||||
// true => has floating panes
|
||||
let err_context = || format!("Failed to apply_floating_panes_layout");
|
||||
let mut layout_has_floating_panes = false;
|
||||
let floating_panes_layout = floating_panes_layout.iter();
|
||||
let mut focused_floating_pane = None;
|
||||
let mut new_floating_terminal_ids = new_floating_terminal_ids.iter();
|
||||
for floating_pane_layout in floating_panes_layout {
|
||||
layout_has_floating_panes = true;
|
||||
if let Some(Run::Plugin(run)) = floating_pane_layout.run.clone() {
|
||||
let position_and_size = self
|
||||
.floating_panes
|
||||
.position_floating_pane_layout(&floating_pane_layout);
|
||||
let pane_title = run.location.to_string();
|
||||
let pid = new_plugin_ids
|
||||
.get_mut(&run.location)
|
||||
.and_then(|ids| ids.pop())
|
||||
.with_context(err_context)?;
|
||||
let mut new_pane = PluginPane::new(
|
||||
pid,
|
||||
position_and_size,
|
||||
self.senders
|
||||
.to_plugin
|
||||
.as_ref()
|
||||
.with_context(err_context)?
|
||||
.clone(),
|
||||
pane_title,
|
||||
layout_name.clone().unwrap_or_default(),
|
||||
self.sixel_image_store.clone(),
|
||||
self.terminal_emulator_colors.clone(),
|
||||
self.terminal_emulator_color_codes.clone(),
|
||||
self.link_handler.clone(),
|
||||
self.character_cell_size.clone(),
|
||||
self.style,
|
||||
);
|
||||
new_pane.set_borderless(false);
|
||||
new_pane.set_content_offset(Offset::frame(1));
|
||||
resize_pty!(new_pane, self.os_api, self.senders)?;
|
||||
self.floating_panes
|
||||
.add_pane(PaneId::Plugin(pid), Box::new(new_pane));
|
||||
if floating_pane_layout.focus.unwrap_or(false) {
|
||||
focused_floating_pane = Some(PaneId::Plugin(pid));
|
||||
}
|
||||
} else if let Some((pid, hold_for_command)) = new_floating_terminal_ids.next() {
|
||||
let position_and_size = self
|
||||
.floating_panes
|
||||
.position_floating_pane_layout(&floating_pane_layout);
|
||||
let next_terminal_position =
|
||||
get_next_terminal_position(&self.tiled_panes, &self.floating_panes);
|
||||
let initial_title = match &floating_pane_layout.run {
|
||||
Some(Run::Command(run_command)) => Some(run_command.to_string()),
|
||||
_ => None,
|
||||
};
|
||||
let mut new_pane = TerminalPane::new(
|
||||
*pid,
|
||||
position_and_size,
|
||||
self.style,
|
||||
next_terminal_position,
|
||||
floating_pane_layout.name.clone().unwrap_or_default(),
|
||||
self.link_handler.clone(),
|
||||
self.character_cell_size.clone(),
|
||||
self.sixel_image_store.clone(),
|
||||
self.terminal_emulator_colors.clone(),
|
||||
self.terminal_emulator_color_codes.clone(),
|
||||
initial_title,
|
||||
);
|
||||
new_pane.set_borderless(false);
|
||||
new_pane.set_content_offset(Offset::frame(1));
|
||||
if let Some(held_command) = hold_for_command {
|
||||
new_pane.hold(None, true, held_command.clone());
|
||||
}
|
||||
resize_pty!(new_pane, self.os_api, self.senders)?;
|
||||
self.floating_panes
|
||||
.add_pane(PaneId::Terminal(*pid), Box::new(new_pane));
|
||||
if floating_pane_layout.focus.unwrap_or(false) {
|
||||
focused_floating_pane = Some(PaneId::Terminal(*pid));
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(focused_floating_pane) = focused_floating_pane {
|
||||
self.floating_panes
|
||||
.focus_pane_for_all_clients(focused_floating_pane);
|
||||
}
|
||||
if layout_has_floating_panes {
|
||||
Ok(true)
|
||||
} else {
|
||||
Ok(false)
|
||||
}
|
||||
}
|
||||
fn resize_whole_tab(&mut self, new_screen_size: Size) {
|
||||
self.floating_panes.resize(new_screen_size);
|
||||
self.floating_panes
|
||||
.resize_pty_all_panes(&mut self.os_api)
|
||||
.unwrap(); // we need to do this explicitly because floating_panes.resize does not do this
|
||||
self.tiled_panes.resize(new_screen_size);
|
||||
}
|
||||
fn offset_viewport(&mut self, position_and_size: &Viewport) {
|
||||
let mut viewport = self.viewport.borrow_mut();
|
||||
if position_and_size.x == viewport.x
|
||||
&& position_and_size.x + position_and_size.cols == viewport.x + viewport.cols
|
||||
{
|
||||
if position_and_size.y == viewport.y {
|
||||
viewport.y += position_and_size.rows;
|
||||
viewport.rows -= position_and_size.rows;
|
||||
} else if position_and_size.y + position_and_size.rows == viewport.y + viewport.rows {
|
||||
viewport.rows -= position_and_size.rows;
|
||||
}
|
||||
}
|
||||
if position_and_size.y == viewport.y
|
||||
&& position_and_size.y + position_and_size.rows == viewport.y + viewport.rows
|
||||
{
|
||||
if position_and_size.x == viewport.x {
|
||||
viewport.x += position_and_size.cols;
|
||||
viewport.cols -= position_and_size.cols;
|
||||
} else if position_and_size.x + position_and_size.cols == viewport.x + viewport.cols {
|
||||
viewport.cols -= position_and_size.cols;
|
||||
}
|
||||
}
|
||||
}
|
||||
fn adjust_viewport(&mut self) {
|
||||
// here we offset the viewport after applying a tiled panes layout
|
||||
// from borderless panes that are on the edges of the
|
||||
// screen, this is so that when we don't have pane boundaries (eg. when they were
|
||||
// disabled by the user) boundaries won't be drawn around these panes
|
||||
// geometrically, we can only do this with panes that are on the edges of the
|
||||
// screen - so it's mostly a best-effort thing
|
||||
let display_area = {
|
||||
let display_area = self.display_area.borrow();
|
||||
*display_area
|
||||
};
|
||||
self.resize_whole_tab(display_area);
|
||||
let boundary_geoms = self.tiled_panes.borderless_pane_geoms();
|
||||
for geom in boundary_geoms {
|
||||
self.offset_viewport(&geom)
|
||||
}
|
||||
self.tiled_panes.set_pane_frames(self.draw_pane_frames);
|
||||
}
|
||||
fn set_focused_tiled_pane(&mut self, focus_pane_id: Option<PaneId>, client_id: ClientId) {
|
||||
if let Some(pane_id) = focus_pane_id {
|
||||
*self.focus_pane_id = Some(pane_id);
|
||||
self.tiled_panes.focus_pane(pane_id, client_id);
|
||||
} else {
|
||||
let next_selectable_pane_id = self.tiled_panes.first_selectable_pane_id();
|
||||
match next_selectable_pane_id {
|
||||
Some(active_pane_id) => {
|
||||
self.tiled_panes.focus_pane(active_pane_id, client_id);
|
||||
},
|
||||
None => {
|
||||
self.tiled_panes.clear_active_panes();
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
mod clipboard;
|
||||
mod copy_command;
|
||||
mod layout_applier;
|
||||
|
||||
use copy_command::CopyCommand;
|
||||
use std::env::temp_dir;
|
||||
|
|
@ -17,6 +18,7 @@ use crate::background_jobs::BackgroundJob;
|
|||
use crate::pty_writer::PtyWriteInstruction;
|
||||
use crate::screen::CopyOptions;
|
||||
use crate::ui::pane_boundaries_frame::FrameParams;
|
||||
use layout_applier::LayoutApplier;
|
||||
|
||||
use self::clipboard::ClipboardProvider;
|
||||
use crate::{
|
||||
|
|
@ -24,7 +26,7 @@ use crate::{
|
|||
output::{CharacterChunk, Output, SixelImageChunk},
|
||||
panes::sixel::SixelImageStore,
|
||||
panes::{FloatingPanes, TiledPanes},
|
||||
panes::{LinkHandler, PaneId, PluginPane, TerminalPane},
|
||||
panes::{LinkHandler, PaneId, TerminalPane},
|
||||
plugins::PluginInstruction,
|
||||
pty::{ClientOrTabIndex, PtyInstruction, VteBytes},
|
||||
thread_bus::ThreadSenders,
|
||||
|
|
@ -42,7 +44,7 @@ use zellij_utils::{
|
|||
data::{Event, InputMode, ModeInfo, Palette, PaletteColor, Style},
|
||||
input::{
|
||||
command::TerminalAction,
|
||||
layout::{PaneLayout, Run, RunPluginLocation},
|
||||
layout::{FloatingPanesLayout, PaneLayout, RunPluginLocation},
|
||||
parse_keys,
|
||||
},
|
||||
pane_size::{Offset, PaneGeom, Size, SizeInPixels, Viewport},
|
||||
|
|
@ -398,6 +400,26 @@ pub enum AdjustedInput {
|
|||
ReRunCommandInThisPane(RunCommand),
|
||||
CloseThisPane,
|
||||
}
|
||||
pub fn get_next_terminal_position(
|
||||
tiled_panes: &TiledPanes,
|
||||
floating_panes: &FloatingPanes,
|
||||
) -> usize {
|
||||
let tiled_panes_count = tiled_panes
|
||||
.get_panes()
|
||||
.filter(|(k, _)| match k {
|
||||
PaneId::Plugin(_) => false,
|
||||
PaneId::Terminal(_) => true,
|
||||
})
|
||||
.count();
|
||||
let floating_panes_count = floating_panes
|
||||
.get_panes()
|
||||
.filter(|(k, _)| match k {
|
||||
PaneId::Plugin(_) => false,
|
||||
PaneId::Terminal(_) => true,
|
||||
})
|
||||
.count();
|
||||
tiled_panes_count + floating_panes_count + 1
|
||||
}
|
||||
|
||||
impl Tab {
|
||||
// FIXME: Still too many arguments for clippy to be happy...
|
||||
|
|
@ -509,170 +531,45 @@ impl Tab {
|
|||
pub fn apply_layout(
|
||||
&mut self,
|
||||
layout: PaneLayout,
|
||||
floating_panes_layout: Vec<FloatingPanesLayout>,
|
||||
new_terminal_ids: Vec<(u32, HoldForCommand)>,
|
||||
mut new_plugin_ids: HashMap<RunPluginLocation, Vec<u32>>,
|
||||
tab_index: usize,
|
||||
new_floating_terminal_ids: Vec<(u32, HoldForCommand)>,
|
||||
new_plugin_ids: HashMap<RunPluginLocation, Vec<u32>>,
|
||||
client_id: ClientId,
|
||||
) -> Result<()> {
|
||||
let err_context = || {
|
||||
format!(
|
||||
"failed to apply layout {layout:#?} in tab {tab_index} for client id {client_id}"
|
||||
)
|
||||
};
|
||||
|
||||
if self.tiled_panes.has_panes() {
|
||||
Err::<(), _>(anyhow!(
|
||||
"Applying a layout to a tab with existing panes - this is not yet supported!"
|
||||
))
|
||||
.with_context(err_context)
|
||||
.non_fatal();
|
||||
}
|
||||
let (viewport_cols, viewport_rows) = {
|
||||
let viewport = self.viewport.borrow();
|
||||
(viewport.cols, viewport.rows)
|
||||
};
|
||||
let mut free_space = PaneGeom::default();
|
||||
free_space.cols.set_inner(viewport_cols);
|
||||
free_space.rows.set_inner(viewport_rows);
|
||||
|
||||
match layout.position_panes_in_space(&free_space) {
|
||||
Ok(positions_in_layout) => {
|
||||
let positions_and_size = positions_in_layout.iter();
|
||||
let mut new_terminal_ids = new_terminal_ids.iter();
|
||||
|
||||
let mut focus_pane_id: Option<PaneId> = None;
|
||||
let mut set_focus_pane_id = |layout: &PaneLayout, pane_id: PaneId| {
|
||||
if layout.focus.unwrap_or(false) && focus_pane_id.is_none() {
|
||||
focus_pane_id = Some(pane_id);
|
||||
}
|
||||
};
|
||||
|
||||
for (layout, position_and_size) in positions_and_size {
|
||||
// A plugin pane
|
||||
if let Some(Run::Plugin(run)) = layout.run.clone() {
|
||||
// let (pid_tx, pid_rx) = channel();
|
||||
let pane_title = run.location.to_string();
|
||||
let pid = new_plugin_ids
|
||||
.get_mut(&run.location)
|
||||
.unwrap()
|
||||
.pop()
|
||||
.unwrap(); // TODO:
|
||||
// err_context
|
||||
// and
|
||||
// stuff
|
||||
let mut new_plugin = PluginPane::new(
|
||||
pid,
|
||||
*position_and_size,
|
||||
self.senders
|
||||
.to_plugin
|
||||
.as_ref()
|
||||
.with_context(err_context)?
|
||||
.clone(),
|
||||
pane_title,
|
||||
layout.name.clone().unwrap_or_default(),
|
||||
self.sixel_image_store.clone(),
|
||||
self.terminal_emulator_colors.clone(),
|
||||
self.terminal_emulator_color_codes.clone(),
|
||||
self.link_handler.clone(),
|
||||
self.character_cell_size.clone(),
|
||||
self.style,
|
||||
);
|
||||
new_plugin.set_borderless(layout.borderless);
|
||||
self.tiled_panes
|
||||
.add_pane_with_existing_geom(PaneId::Plugin(pid), Box::new(new_plugin));
|
||||
set_focus_pane_id(layout, PaneId::Plugin(pid));
|
||||
} else {
|
||||
// there are still panes left to fill, use the pids we received in this method
|
||||
if let Some((pid, hold_for_command)) = new_terminal_ids.next() {
|
||||
let next_terminal_position = self.get_next_terminal_position();
|
||||
let initial_title = match &layout.run {
|
||||
Some(Run::Command(run_command)) => Some(run_command.to_string()),
|
||||
_ => None,
|
||||
};
|
||||
let mut new_pane = TerminalPane::new(
|
||||
*pid,
|
||||
*position_and_size,
|
||||
self.style,
|
||||
next_terminal_position,
|
||||
layout.name.clone().unwrap_or_default(),
|
||||
self.link_handler.clone(),
|
||||
self.character_cell_size.clone(),
|
||||
self.sixel_image_store.clone(),
|
||||
self.terminal_emulator_colors.clone(),
|
||||
self.terminal_emulator_color_codes.clone(),
|
||||
initial_title,
|
||||
);
|
||||
new_pane.set_borderless(layout.borderless);
|
||||
if let Some(held_command) = hold_for_command {
|
||||
new_pane.hold(None, true, held_command.clone());
|
||||
}
|
||||
self.tiled_panes.add_pane_with_existing_geom(
|
||||
PaneId::Terminal(*pid),
|
||||
Box::new(new_pane),
|
||||
);
|
||||
set_focus_pane_id(layout, PaneId::Terminal(*pid));
|
||||
}
|
||||
}
|
||||
}
|
||||
for (unused_pid, _) in new_terminal_ids {
|
||||
// this is a bit of a hack and happens because we don't have any central location that
|
||||
// can query the screen as to how many panes it needs to create a layout
|
||||
// fixing this will require a bit of an architecture change
|
||||
self.senders
|
||||
.send_to_pty(PtyInstruction::ClosePane(PaneId::Terminal(*unused_pid)))
|
||||
.with_context(err_context)?;
|
||||
}
|
||||
|
||||
// here we offset the viewport from borderless panes that are on the edges of the
|
||||
// screen, this is so that when we don't have pane boundaries (eg. when they were
|
||||
// disabled by the user) boundaries won't be drawn around these panes
|
||||
// geometrically, we can only do this with panes that are on the edges of the
|
||||
// screen - so it's mostly a best-effort thing
|
||||
let display_area = {
|
||||
let display_area = self.display_area.borrow();
|
||||
*display_area
|
||||
};
|
||||
self.resize_whole_tab(display_area);
|
||||
let boundary_geoms = self.tiled_panes.borderless_pane_geoms();
|
||||
for geom in boundary_geoms {
|
||||
self.offset_viewport(&geom)
|
||||
}
|
||||
self.tiled_panes.set_pane_frames(self.draw_pane_frames);
|
||||
self.should_clear_display_before_rendering = true;
|
||||
|
||||
if let Some(pane_id) = focus_pane_id {
|
||||
self.focus_pane_id = Some(pane_id);
|
||||
self.tiled_panes.focus_pane(pane_id, client_id);
|
||||
} else {
|
||||
// This is the end of the nasty viewport hack...
|
||||
let next_selectable_pane_id = self.tiled_panes.first_selectable_pane_id();
|
||||
match next_selectable_pane_id {
|
||||
Some(active_pane_id) => {
|
||||
self.tiled_panes.focus_pane(active_pane_id, client_id);
|
||||
},
|
||||
None => {
|
||||
// this is very likely a configuration error (layout with no selectable panes)
|
||||
self.tiled_panes.clear_active_panes();
|
||||
},
|
||||
}
|
||||
}
|
||||
self.is_pending = false;
|
||||
self.apply_buffered_instructions()?;
|
||||
Ok(())
|
||||
},
|
||||
Err(e) => {
|
||||
for (unused_pid, _) in new_terminal_ids {
|
||||
self.senders
|
||||
.send_to_pty(PtyInstruction::ClosePane(PaneId::Terminal(unused_pid)))
|
||||
.with_context(err_context)?;
|
||||
}
|
||||
self.is_pending = false;
|
||||
Err::<(), _>(anyError::msg(e))
|
||||
.with_context(err_context)
|
||||
.non_fatal(); // TODO: propagate this to the user
|
||||
Ok(())
|
||||
},
|
||||
let layout_has_floating_panes = LayoutApplier::new(
|
||||
&self.viewport,
|
||||
&self.senders,
|
||||
&self.sixel_image_store,
|
||||
&self.link_handler,
|
||||
&self.terminal_emulator_colors,
|
||||
&self.terminal_emulator_color_codes,
|
||||
&self.character_cell_size,
|
||||
&self.style,
|
||||
&self.display_area,
|
||||
&mut self.tiled_panes,
|
||||
&mut self.floating_panes,
|
||||
self.draw_pane_frames,
|
||||
&mut self.focus_pane_id,
|
||||
&self.os_api,
|
||||
)
|
||||
.apply_layout(
|
||||
layout,
|
||||
floating_panes_layout,
|
||||
new_terminal_ids,
|
||||
new_floating_terminal_ids,
|
||||
new_plugin_ids,
|
||||
client_id,
|
||||
)?;
|
||||
if layout_has_floating_panes {
|
||||
if !self.floating_panes.panes_are_visible() {
|
||||
self.toggle_floating_panes(client_id, None)?;
|
||||
}
|
||||
}
|
||||
self.tiled_panes.set_pane_frames(self.draw_pane_frames);
|
||||
self.is_pending = false;
|
||||
self.apply_buffered_instructions()?;
|
||||
Ok(())
|
||||
}
|
||||
pub fn apply_buffered_instructions(&mut self) -> Result<()> {
|
||||
let buffered_instructions: Vec<BufferedTabInstruction> =
|
||||
|
|
@ -852,7 +749,7 @@ impl Tab {
|
|||
self.set_force_render();
|
||||
} else {
|
||||
self.show_floating_panes();
|
||||
match self.floating_panes.first_floating_pane_id() {
|
||||
match self.floating_panes.last_floating_pane_id() {
|
||||
Some(first_floating_pane_id) => {
|
||||
if !self.floating_panes.active_panes_contain(&client_id) {
|
||||
self.floating_panes
|
||||
|
|
@ -2708,30 +2605,6 @@ impl Tab {
|
|||
|
||||
Ok(())
|
||||
}
|
||||
fn offset_viewport(&mut self, position_and_size: &Viewport) {
|
||||
let mut viewport = self.viewport.borrow_mut();
|
||||
if position_and_size.x == viewport.x
|
||||
&& position_and_size.x + position_and_size.cols == viewport.x + viewport.cols
|
||||
{
|
||||
if position_and_size.y == viewport.y {
|
||||
viewport.y += position_and_size.rows;
|
||||
viewport.rows -= position_and_size.rows;
|
||||
} else if position_and_size.y + position_and_size.rows == viewport.y + viewport.rows {
|
||||
viewport.rows -= position_and_size.rows;
|
||||
}
|
||||
}
|
||||
if position_and_size.y == viewport.y
|
||||
&& position_and_size.y + position_and_size.rows == viewport.y + viewport.rows
|
||||
{
|
||||
if position_and_size.x == viewport.x {
|
||||
viewport.x += position_and_size.cols;
|
||||
viewport.cols -= position_and_size.cols;
|
||||
} else if position_and_size.x + position_and_size.cols == viewport.x + viewport.cols {
|
||||
viewport.cols -= position_and_size.cols;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn visible(&self, visible: bool) -> Result<()> {
|
||||
let pids_in_this_tab = self.tiled_panes.pane_ids().filter_map(|p| match p {
|
||||
PaneId::Plugin(pid) => Some(pid),
|
||||
|
|
|
|||
|
|
@ -0,0 +1,26 @@
|
|||
---
|
||||
source: zellij-server/src/tab/./unit/tab_integration_tests.rs
|
||||
assertion_line: 2560
|
||||
expression: snapshot
|
||||
---
|
||||
00 (C): ┌ Pane #1 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||||
01 (C): │ │
|
||||
02 (C): │ │
|
||||
03 (C): │ │
|
||||
04 (C): │ │
|
||||
05 (C): │ ┌ Pane #2 ─────────────────────────────────────────────────┐ │
|
||||
06 (C): │ │ │ │
|
||||
07 (C): │ │ ┌ Pane #3 ─────────────────────────────────────────────────┐ │
|
||||
08 (C): │ │ │ │ │
|
||||
09 (C): │ │ │ │ │
|
||||
10 (C): │ │ │ │ │
|
||||
11 (C): │ │ │ │ │
|
||||
12 (C): │ │ │ │ │
|
||||
13 (C): │ │ │ │ │
|
||||
14 (C): │ └─│ │ │
|
||||
15 (C): │ │ │ │
|
||||
16 (C): │ └──────────────────────────────────────────────────────────┘ │
|
||||
17 (C): │ │
|
||||
18 (C): │ │
|
||||
19 (C): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
|
|
@ -229,9 +229,10 @@ fn create_new_tab(size: Size, default_mode: ModeInfo) -> Tab {
|
|||
);
|
||||
tab.apply_layout(
|
||||
PaneLayout::default(),
|
||||
vec![],
|
||||
vec![(1, None)],
|
||||
vec![],
|
||||
HashMap::new(),
|
||||
index,
|
||||
client_id,
|
||||
)
|
||||
.unwrap();
|
||||
|
|
@ -285,9 +286,10 @@ fn create_new_tab_with_os_api(
|
|||
);
|
||||
tab.apply_layout(
|
||||
PaneLayout::default(),
|
||||
vec![],
|
||||
vec![(1, None)],
|
||||
vec![],
|
||||
HashMap::new(),
|
||||
index,
|
||||
client_id,
|
||||
)
|
||||
.unwrap();
|
||||
|
|
@ -316,7 +318,7 @@ fn create_new_tab_with_layout(size: Size, default_mode: ModeInfo, layout: &str)
|
|||
let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
|
||||
let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
|
||||
let layout = Layout::from_str(layout, "layout_file_name".into(), None).unwrap();
|
||||
let tab_layout = layout.new_tab();
|
||||
let (tab_layout, floating_panes_layout) = layout.new_tab();
|
||||
let mut tab = Tab::new(
|
||||
index,
|
||||
position,
|
||||
|
|
@ -343,8 +345,20 @@ fn create_new_tab_with_layout(size: Size, default_mode: ModeInfo, layout: &str)
|
|||
.enumerate()
|
||||
.map(|(i, _)| (i as u32, None))
|
||||
.collect();
|
||||
tab.apply_layout(tab_layout, pane_ids, HashMap::new(), index, client_id)
|
||||
.unwrap();
|
||||
let floating_pane_ids = floating_panes_layout
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, _)| (i as u32, None))
|
||||
.collect();
|
||||
tab.apply_layout(
|
||||
tab_layout,
|
||||
floating_panes_layout,
|
||||
pane_ids,
|
||||
floating_pane_ids,
|
||||
HashMap::new(),
|
||||
client_id,
|
||||
)
|
||||
.unwrap();
|
||||
tab
|
||||
}
|
||||
|
||||
|
|
@ -396,9 +410,10 @@ fn create_new_tab_with_mock_pty_writer(
|
|||
);
|
||||
tab.apply_layout(
|
||||
PaneLayout::default(),
|
||||
vec![],
|
||||
vec![(1, None)],
|
||||
vec![],
|
||||
HashMap::new(),
|
||||
index,
|
||||
client_id,
|
||||
)
|
||||
.unwrap();
|
||||
|
|
@ -455,9 +470,10 @@ fn create_new_tab_with_sixel_support(
|
|||
);
|
||||
tab.apply_layout(
|
||||
PaneLayout::default(),
|
||||
vec![],
|
||||
vec![(1, None)],
|
||||
vec![],
|
||||
HashMap::new(),
|
||||
index,
|
||||
client_id,
|
||||
)
|
||||
.unwrap();
|
||||
|
|
@ -2519,6 +2535,34 @@ fn tab_with_basic_layout() {
|
|||
assert_snapshot!(snapshot);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tab_with_layout_that_has_floating_panes() {
|
||||
let layout = r#"
|
||||
layout {
|
||||
pane
|
||||
floating_panes {
|
||||
pane
|
||||
pane
|
||||
}
|
||||
}
|
||||
"#;
|
||||
let size = Size {
|
||||
cols: 121,
|
||||
rows: 20,
|
||||
};
|
||||
let client_id = 1;
|
||||
let mut tab = create_new_tab_with_layout(size, ModeInfo::default(), layout);
|
||||
let mut output = Output::default();
|
||||
tab.render(&mut output, None).unwrap();
|
||||
let snapshot = take_snapshot(
|
||||
output.serialize().unwrap().get(&client_id).unwrap(),
|
||||
size.rows,
|
||||
size.cols,
|
||||
Palette::default(),
|
||||
);
|
||||
assert_snapshot!(snapshot);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tab_with_nested_layout() {
|
||||
let layout = r#"
|
||||
|
|
|
|||
|
|
@ -178,9 +178,10 @@ fn create_new_tab(size: Size) -> Tab {
|
|||
);
|
||||
tab.apply_layout(
|
||||
PaneLayout::default(),
|
||||
vec![],
|
||||
vec![(1, None)],
|
||||
vec![],
|
||||
HashMap::new(),
|
||||
index,
|
||||
client_id,
|
||||
)
|
||||
.unwrap();
|
||||
|
|
@ -231,8 +232,15 @@ fn create_new_tab_with_layout(size: Size, layout: PaneLayout) -> Tab {
|
|||
for i in 0..layout.extract_run_instructions().len() {
|
||||
new_terminal_ids.push((i as u32, None));
|
||||
}
|
||||
tab.apply_layout(layout, new_terminal_ids, HashMap::new(), index, client_id)
|
||||
.unwrap();
|
||||
tab.apply_layout(
|
||||
layout,
|
||||
vec![],
|
||||
new_terminal_ids,
|
||||
vec![],
|
||||
HashMap::new(),
|
||||
client_id,
|
||||
)
|
||||
.unwrap();
|
||||
tab
|
||||
}
|
||||
|
||||
|
|
@ -280,9 +288,10 @@ fn create_new_tab_with_cell_size(
|
|||
);
|
||||
tab.apply_layout(
|
||||
PaneLayout::default(),
|
||||
vec![],
|
||||
vec![(1, None)],
|
||||
vec![],
|
||||
HashMap::new(),
|
||||
index,
|
||||
client_id,
|
||||
)
|
||||
.unwrap();
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ use zellij_utils::data::Resize;
|
|||
use zellij_utils::errors::{prelude::*, ErrorContext};
|
||||
use zellij_utils::input::actions::Action;
|
||||
use zellij_utils::input::command::{RunCommand, TerminalAction};
|
||||
use zellij_utils::input::layout::{PaneLayout, SplitDirection, SplitSize};
|
||||
use zellij_utils::input::layout::{PaneLayout, SplitDirection};
|
||||
use zellij_utils::input::options::Options;
|
||||
use zellij_utils::ipc::IpcReceiverWithContext;
|
||||
use zellij_utils::pane_size::{Size, SizeInPixels};
|
||||
|
|
@ -297,12 +297,15 @@ impl MockScreen {
|
|||
let _ = self.to_screen.send(ScreenInstruction::NewTab(
|
||||
default_shell,
|
||||
Some(pane_layout.clone()),
|
||||
vec![], // floating_panes_layout
|
||||
tab_name,
|
||||
self.main_client_id,
|
||||
));
|
||||
let _ = self.to_screen.send(ScreenInstruction::ApplyLayout(
|
||||
pane_layout,
|
||||
vec![], // floating panes layout
|
||||
pane_ids,
|
||||
vec![], // floating pane ids
|
||||
plugin_ids,
|
||||
tab_index,
|
||||
self.main_client_id,
|
||||
|
|
@ -323,12 +326,15 @@ impl MockScreen {
|
|||
let _ = self.to_screen.send(ScreenInstruction::NewTab(
|
||||
default_shell,
|
||||
Some(tab_layout.clone()),
|
||||
vec![], // floating_panes_layout
|
||||
tab_name,
|
||||
self.main_client_id,
|
||||
));
|
||||
let _ = self.to_screen.send(ScreenInstruction::ApplyLayout(
|
||||
tab_layout,
|
||||
vec![], // floating_panes_layout
|
||||
pane_ids,
|
||||
vec![], // floating panes ids
|
||||
plugin_ids,
|
||||
0,
|
||||
self.main_client_id,
|
||||
|
|
@ -472,7 +478,9 @@ fn new_tab(screen: &mut Screen, pid: u32, tab_index: usize) {
|
|||
screen
|
||||
.apply_layout(
|
||||
PaneLayout::default(),
|
||||
vec![], // floating panes layout
|
||||
new_terminal_ids,
|
||||
vec![], // new floating terminal ids
|
||||
new_plugin_ids,
|
||||
tab_index,
|
||||
client_id,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
source: zellij-server/src/./unit/screen_tests.rs
|
||||
assertion_line: 2272
|
||||
assertion_line: 2300
|
||||
expression: "format!(\"{:#?}\", new_tab_action)"
|
||||
---
|
||||
Some(
|
||||
|
|
@ -39,6 +39,7 @@ Some(
|
|||
external_children_index: None,
|
||||
},
|
||||
),
|
||||
[],
|
||||
None,
|
||||
0,
|
||||
1,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
source: zellij-server/src/./unit/screen_tests.rs
|
||||
assertion_line: 2322
|
||||
assertion_line: 2350
|
||||
expression: "format!(\"{:#?}\", new_tab_instruction)"
|
||||
---
|
||||
NewTab(
|
||||
|
|
@ -60,6 +60,7 @@ NewTab(
|
|||
external_children_index: None,
|
||||
},
|
||||
),
|
||||
[],
|
||||
Some(
|
||||
"my-awesome-tab-name",
|
||||
),
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
source: zellij-server/src/./unit/screen_tests.rs
|
||||
assertion_line: 2511
|
||||
assertion_line: 2534
|
||||
expression: "format!(\"{:#?}\", * received_plugin_instructions.lock().unwrap())"
|
||||
---
|
||||
[
|
||||
|
|
@ -61,6 +61,7 @@ expression: "format!(\"{:#?}\", * received_plugin_instructions.lock().unwrap())"
|
|||
external_children_index: None,
|
||||
},
|
||||
),
|
||||
[],
|
||||
None,
|
||||
0,
|
||||
1,
|
||||
|
|
@ -207,6 +208,7 @@ expression: "format!(\"{:#?}\", * received_plugin_instructions.lock().unwrap())"
|
|||
external_children_index: None,
|
||||
},
|
||||
),
|
||||
[],
|
||||
None,
|
||||
1,
|
||||
1,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
source: zellij-server/src/./unit/screen_tests.rs
|
||||
assertion_line: 2554
|
||||
assertion_line: 2577
|
||||
expression: "format!(\"{:#?}\", * received_plugin_instructions.lock().unwrap())"
|
||||
---
|
||||
[
|
||||
|
|
@ -61,6 +61,7 @@ expression: "format!(\"{:#?}\", * received_plugin_instructions.lock().unwrap())"
|
|||
external_children_index: None,
|
||||
},
|
||||
),
|
||||
[],
|
||||
None,
|
||||
0,
|
||||
1,
|
||||
|
|
@ -207,6 +208,7 @@ expression: "format!(\"{:#?}\", * received_plugin_instructions.lock().unwrap())"
|
|||
external_children_index: None,
|
||||
},
|
||||
),
|
||||
[],
|
||||
None,
|
||||
1,
|
||||
1,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
//! Definition of the actions that can be bound to keys.
|
||||
|
||||
use super::command::RunCommandAction;
|
||||
use super::layout::{Layout, PaneLayout};
|
||||
use super::layout::{FloatingPanesLayout, Layout, PaneLayout};
|
||||
use crate::cli::CliAction;
|
||||
use crate::data::InputMode;
|
||||
use crate::data::{Direction, Resize};
|
||||
|
|
@ -162,7 +162,7 @@ pub enum Action {
|
|||
PaneNameInput(Vec<u8>),
|
||||
UndoRenamePane,
|
||||
/// Create a new tab, optionally with a specified tab layout.
|
||||
NewTab(Option<PaneLayout>, Option<String>), // the String is the tab name
|
||||
NewTab(Option<PaneLayout>, Vec<FloatingPanesLayout>, Option<String>), // the String is the tab name
|
||||
/// Do nothing.
|
||||
NoOp,
|
||||
/// Go to the next tab.
|
||||
|
|
@ -368,15 +368,24 @@ impl Action {
|
|||
if tabs.len() > 1 {
|
||||
return Err(format!("Tab layout cannot itself have tabs"));
|
||||
} else if !tabs.is_empty() {
|
||||
let (tab_name, layout) = tabs.drain(..).next().unwrap();
|
||||
let (tab_name, layout, floating_panes_layout) =
|
||||
tabs.drain(..).next().unwrap();
|
||||
let name = tab_name.or(name);
|
||||
Ok(vec![Action::NewTab(Some(layout), name)])
|
||||
Ok(vec![Action::NewTab(
|
||||
Some(layout),
|
||||
floating_panes_layout,
|
||||
name,
|
||||
)])
|
||||
} else {
|
||||
let layout = layout.new_tab();
|
||||
Ok(vec![Action::NewTab(Some(layout), name)])
|
||||
let (layout, floating_panes_layout) = layout.new_tab();
|
||||
Ok(vec![Action::NewTab(
|
||||
Some(layout),
|
||||
floating_panes_layout,
|
||||
name,
|
||||
)])
|
||||
}
|
||||
} else {
|
||||
Ok(vec![Action::NewTab(None, name)])
|
||||
Ok(vec![Action::NewTab(None, vec![], name)])
|
||||
}
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -213,9 +213,94 @@ impl fmt::Display for RunPluginLocation {
|
|||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Default)]
|
||||
pub struct Layout {
|
||||
pub tabs: Vec<(Option<String>, PaneLayout)>,
|
||||
pub tabs: Vec<(Option<String>, PaneLayout, Vec<FloatingPanesLayout>)>,
|
||||
pub focused_tab_index: Option<usize>,
|
||||
pub template: Option<PaneLayout>,
|
||||
pub floating_panes_template: Vec<FloatingPanesLayout>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
|
||||
pub enum PercentOrFixed {
|
||||
Percent(usize), // 1 to 100
|
||||
Fixed(usize), // An absolute number of columns or rows
|
||||
}
|
||||
|
||||
impl PercentOrFixed {
|
||||
pub fn to_position(&self, whole: usize) -> usize {
|
||||
match self {
|
||||
PercentOrFixed::Percent(percent) => {
|
||||
(whole as f64 / 100.0 * *percent as f64).ceil() as usize
|
||||
},
|
||||
PercentOrFixed::Fixed(fixed) => {
|
||||
if *fixed > whole {
|
||||
whole
|
||||
} else {
|
||||
*fixed
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PercentOrFixed {
|
||||
pub fn is_zero(&self) -> bool {
|
||||
match self {
|
||||
PercentOrFixed::Percent(percent) => *percent == 0,
|
||||
PercentOrFixed::Fixed(fixed) => *fixed == 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for PercentOrFixed {
|
||||
type Err = Box<dyn std::error::Error>;
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
if s.chars().last() == Some('%') {
|
||||
let char_count = s.chars().count();
|
||||
let percent_size = usize::from_str_radix(&s[..char_count.saturating_sub(1)], 10)?;
|
||||
if percent_size <= 100 {
|
||||
Ok(PercentOrFixed::Percent(percent_size))
|
||||
} else {
|
||||
Err("Percent must be between 0 and 100".into())
|
||||
}
|
||||
} else {
|
||||
let fixed_size = usize::from_str_radix(s, 10)?;
|
||||
Ok(PercentOrFixed::Fixed(fixed_size))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Default)]
|
||||
pub struct FloatingPanesLayout {
|
||||
// TODO: change name to singular
|
||||
pub name: Option<String>,
|
||||
pub height: Option<PercentOrFixed>,
|
||||
pub width: Option<PercentOrFixed>,
|
||||
pub x: Option<PercentOrFixed>,
|
||||
pub y: Option<PercentOrFixed>,
|
||||
pub run: Option<Run>,
|
||||
pub focus: Option<bool>,
|
||||
}
|
||||
|
||||
impl FloatingPanesLayout {
|
||||
pub fn add_cwd_to_layout(&mut self, cwd: &PathBuf) {
|
||||
match self.run.as_mut() {
|
||||
Some(run) => run.add_cwd(cwd),
|
||||
None => {
|
||||
self.run = Some(Run::Cwd(cwd.clone()));
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&PaneLayout> for FloatingPanesLayout {
|
||||
fn from(pane_layout: &PaneLayout) -> Self {
|
||||
FloatingPanesLayout {
|
||||
name: pane_layout.name.clone(),
|
||||
run: pane_layout.run.clone(),
|
||||
focus: pane_layout.focus,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Default)]
|
||||
|
|
@ -276,6 +361,8 @@ impl PaneLayout {
|
|||
Ok(layouts)
|
||||
}
|
||||
pub fn extract_run_instructions(&self) -> Vec<Option<Run>> {
|
||||
// the order of these run instructions is significant and needs to be the same
|
||||
// as the order of the "flattened" layout panes received from eg. position_panes_in_space
|
||||
let mut run_instructions = vec![];
|
||||
if self.children.is_empty() {
|
||||
run_instructions.push(self.run.clone());
|
||||
|
|
@ -452,11 +539,12 @@ impl Layout {
|
|||
Ok(String::from_utf8(setup::COMPACT_BAR_LAYOUT.to_vec())?)
|
||||
}
|
||||
|
||||
pub fn new_tab(&self) -> PaneLayout {
|
||||
match &self.template {
|
||||
pub fn new_tab(&self) -> (PaneLayout, Vec<FloatingPanesLayout>) {
|
||||
let template = match &self.template {
|
||||
Some(template) => template.clone(),
|
||||
None => PaneLayout::default(),
|
||||
}
|
||||
};
|
||||
(template, self.floating_panes_template.clone())
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
|
|
@ -467,7 +555,7 @@ impl Layout {
|
|||
!self.tabs.is_empty()
|
||||
}
|
||||
|
||||
pub fn tabs(&self) -> Vec<(Option<String>, PaneLayout)> {
|
||||
pub fn tabs(&self) -> Vec<(Option<String>, PaneLayout, Vec<FloatingPanesLayout>)> {
|
||||
// String is the tab name
|
||||
self.tabs.clone()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -89,6 +89,175 @@ fn layout_with_nested_panes() {
|
|||
assert_eq!(layout, expected_layout);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn layout_with_floating_panes() {
|
||||
let kdl_layout = r#"
|
||||
layout {
|
||||
floating_panes {
|
||||
pane
|
||||
pane {
|
||||
x 10
|
||||
y "10%"
|
||||
width 10
|
||||
height "10%"
|
||||
}
|
||||
pane x=10 y="10%"
|
||||
pane command="htop"
|
||||
}
|
||||
}
|
||||
"#;
|
||||
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
|
||||
let expected_layout = Layout {
|
||||
template: Some(PaneLayout::default()),
|
||||
floating_panes_template: vec![
|
||||
FloatingPanesLayout::default(),
|
||||
FloatingPanesLayout {
|
||||
x: Some(PercentOrFixed::Fixed(10)),
|
||||
y: Some(PercentOrFixed::Percent(10)),
|
||||
width: Some(PercentOrFixed::Fixed(10)),
|
||||
height: Some(PercentOrFixed::Percent(10)),
|
||||
..Default::default()
|
||||
},
|
||||
FloatingPanesLayout {
|
||||
x: Some(PercentOrFixed::Fixed(10)),
|
||||
y: Some(PercentOrFixed::Percent(10)),
|
||||
..Default::default()
|
||||
},
|
||||
FloatingPanesLayout {
|
||||
run: Some(Run::Command(RunCommand {
|
||||
command: PathBuf::from("htop"),
|
||||
hold_on_close: true,
|
||||
..Default::default()
|
||||
})),
|
||||
..Default::default()
|
||||
},
|
||||
],
|
||||
..Default::default()
|
||||
};
|
||||
assert_eq!(layout, expected_layout);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn layout_with_mixed_panes_and_floating_panes() {
|
||||
let kdl_layout = r#"
|
||||
layout {
|
||||
pane
|
||||
pane
|
||||
floating_panes {
|
||||
pane
|
||||
}
|
||||
}
|
||||
"#;
|
||||
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
|
||||
let expected_layout = Layout {
|
||||
template: Some(PaneLayout {
|
||||
children: vec![PaneLayout::default(), PaneLayout::default()],
|
||||
..Default::default()
|
||||
}),
|
||||
floating_panes_template: vec![FloatingPanesLayout::default()],
|
||||
..Default::default()
|
||||
};
|
||||
assert_eq!(layout, expected_layout);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn layout_with_floating_panes_template() {
|
||||
let kdl_layout = r#"
|
||||
layout {
|
||||
pane_template name="my_cool_template" {
|
||||
x 10
|
||||
y "10%"
|
||||
}
|
||||
pane
|
||||
floating_panes {
|
||||
pane
|
||||
my_cool_template
|
||||
}
|
||||
}
|
||||
"#;
|
||||
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
|
||||
let expected_layout = Layout {
|
||||
template: Some(PaneLayout {
|
||||
children: vec![PaneLayout::default()],
|
||||
..Default::default()
|
||||
}),
|
||||
floating_panes_template: vec![
|
||||
FloatingPanesLayout::default(),
|
||||
FloatingPanesLayout {
|
||||
x: Some(PercentOrFixed::Fixed(10)),
|
||||
y: Some(PercentOrFixed::Percent(10)),
|
||||
..Default::default()
|
||||
},
|
||||
],
|
||||
..Default::default()
|
||||
};
|
||||
assert_eq!(layout, expected_layout);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn layout_with_shared_tiled_and_floating_panes_template() {
|
||||
let kdl_layout = r#"
|
||||
layout {
|
||||
pane_template name="htop" {
|
||||
command "htop"
|
||||
}
|
||||
htop
|
||||
floating_panes {
|
||||
pane
|
||||
htop
|
||||
}
|
||||
}
|
||||
"#;
|
||||
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
|
||||
let expected_layout = Layout {
|
||||
template: Some(PaneLayout {
|
||||
children: vec![PaneLayout {
|
||||
run: Some(Run::Command(RunCommand {
|
||||
command: PathBuf::from("htop"),
|
||||
hold_on_close: true,
|
||||
..Default::default()
|
||||
})),
|
||||
..Default::default()
|
||||
}],
|
||||
..Default::default()
|
||||
}),
|
||||
floating_panes_template: vec![
|
||||
FloatingPanesLayout::default(),
|
||||
FloatingPanesLayout {
|
||||
run: Some(Run::Command(RunCommand {
|
||||
command: PathBuf::from("htop"),
|
||||
hold_on_close: true,
|
||||
..Default::default()
|
||||
})),
|
||||
..Default::default()
|
||||
},
|
||||
],
|
||||
..Default::default()
|
||||
};
|
||||
assert_eq!(layout, expected_layout);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn layout_with_tabs_and_floating_panes() {
|
||||
let kdl_layout = r#"
|
||||
layout {
|
||||
tab {
|
||||
floating_panes {
|
||||
pane
|
||||
}
|
||||
}
|
||||
tab {
|
||||
floating_panes {
|
||||
pane
|
||||
pane
|
||||
}
|
||||
}
|
||||
}
|
||||
"#;
|
||||
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
|
||||
assert_snapshot!(format!("{:#?}", layout));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn layout_with_tabs() {
|
||||
let kdl_layout = r#"
|
||||
|
|
@ -98,7 +267,7 @@ fn layout_with_tabs() {
|
|||
"#;
|
||||
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
|
||||
let expected_layout = Layout {
|
||||
tabs: vec![(None, PaneLayout::default())],
|
||||
tabs: vec![(None, PaneLayout::default(), vec![])],
|
||||
template: Some(PaneLayout::default()),
|
||||
..Default::default()
|
||||
};
|
||||
|
|
@ -134,6 +303,7 @@ fn layout_with_nested_differing_tabs() {
|
|||
],
|
||||
..Default::default()
|
||||
},
|
||||
vec![], // floating panes
|
||||
),
|
||||
(
|
||||
None,
|
||||
|
|
@ -142,6 +312,7 @@ fn layout_with_nested_differing_tabs() {
|
|||
children: vec![PaneLayout::default(), PaneLayout::default()],
|
||||
..Default::default()
|
||||
},
|
||||
vec![], // floating panes
|
||||
),
|
||||
],
|
||||
template: Some(PaneLayout::default()),
|
||||
|
|
@ -412,6 +583,7 @@ fn layout_with_tab_names() {
|
|||
children: vec![],
|
||||
..Default::default()
|
||||
},
|
||||
vec![], // floating panes
|
||||
),
|
||||
(
|
||||
Some("my cool tab name 2".into()),
|
||||
|
|
@ -419,6 +591,7 @@ fn layout_with_tab_names() {
|
|||
children: vec![],
|
||||
..Default::default()
|
||||
},
|
||||
vec![], // floating panes
|
||||
),
|
||||
],
|
||||
template: Some(PaneLayout::default()),
|
||||
|
|
@ -439,9 +612,9 @@ fn layout_with_focused_tab() {
|
|||
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
|
||||
let expected_layout = Layout {
|
||||
tabs: vec![
|
||||
(None, PaneLayout::default()),
|
||||
(None, PaneLayout::default()),
|
||||
(None, PaneLayout::default()),
|
||||
(None, PaneLayout::default(), vec![]),
|
||||
(None, PaneLayout::default(), vec![]),
|
||||
(None, PaneLayout::default(), vec![]),
|
||||
],
|
||||
template: Some(PaneLayout::default()),
|
||||
focused_tab_index: Some(1),
|
||||
|
|
@ -488,6 +661,7 @@ fn layout_with_tab_templates() {
|
|||
],
|
||||
..Default::default()
|
||||
},
|
||||
vec![], // floating panes
|
||||
),
|
||||
(
|
||||
Some("my second tab".into()),
|
||||
|
|
@ -504,6 +678,7 @@ fn layout_with_tab_templates() {
|
|||
],
|
||||
..Default::default()
|
||||
},
|
||||
vec![], // floating panes
|
||||
),
|
||||
(
|
||||
None,
|
||||
|
|
@ -516,6 +691,7 @@ fn layout_with_tab_templates() {
|
|||
],
|
||||
..Default::default()
|
||||
},
|
||||
vec![], // floating panes
|
||||
),
|
||||
],
|
||||
template: Some(PaneLayout::default()),
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
source: zellij-utils/src/input/./unit/layout_test.rs
|
||||
assertion_line: 1081
|
||||
assertion_line: 1101
|
||||
expression: "format!(\"{:#?}\", layout)"
|
||||
---
|
||||
Layout {
|
||||
|
|
@ -62,4 +62,5 @@ Layout {
|
|||
external_children_index: None,
|
||||
},
|
||||
),
|
||||
floating_panes_template: [],
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
source: zellij-utils/src/input/./unit/layout_test.rs
|
||||
assertion_line: 1046
|
||||
assertion_line: 1066
|
||||
expression: "format!(\"{:#?}\", layout)"
|
||||
---
|
||||
Layout {
|
||||
|
|
@ -65,4 +65,5 @@ Layout {
|
|||
external_children_index: None,
|
||||
},
|
||||
),
|
||||
floating_panes_template: [],
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
source: zellij-utils/src/input/./unit/layout_test.rs
|
||||
assertion_line: 711
|
||||
assertion_line: 744
|
||||
expression: "format!(\"{:#?}\", layout)"
|
||||
---
|
||||
Layout {
|
||||
|
|
@ -138,4 +138,5 @@ Layout {
|
|||
external_children_index: None,
|
||||
},
|
||||
),
|
||||
floating_panes_template: [],
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
source: zellij-utils/src/input/./unit/layout_test.rs
|
||||
assertion_line: 801
|
||||
assertion_line: 696
|
||||
expression: "format!(\"{:#?}\", layout)"
|
||||
---
|
||||
Layout {
|
||||
|
|
@ -82,6 +82,7 @@ Layout {
|
|||
focus: None,
|
||||
external_children_index: None,
|
||||
},
|
||||
[],
|
||||
),
|
||||
(
|
||||
None,
|
||||
|
|
@ -129,6 +130,7 @@ Layout {
|
|||
focus: None,
|
||||
external_children_index: None,
|
||||
},
|
||||
[],
|
||||
),
|
||||
],
|
||||
focused_tab_index: None,
|
||||
|
|
@ -144,4 +146,5 @@ Layout {
|
|||
external_children_index: None,
|
||||
},
|
||||
),
|
||||
floating_panes_template: [],
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
source: zellij-utils/src/input/./unit/layout_test.rs
|
||||
assertion_line: 1098
|
||||
assertion_line: 1118
|
||||
expression: "format!(\"{:#?}\", layout)"
|
||||
---
|
||||
Layout {
|
||||
|
|
@ -59,4 +59,5 @@ Layout {
|
|||
external_children_index: None,
|
||||
},
|
||||
),
|
||||
floating_panes_template: [],
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
source: zellij-utils/src/input/./unit/layout_test.rs
|
||||
assertion_line: 1064
|
||||
assertion_line: 1084
|
||||
expression: "format!(\"{:#?}\", layout)"
|
||||
---
|
||||
Layout {
|
||||
|
|
@ -59,4 +59,5 @@ Layout {
|
|||
external_children_index: None,
|
||||
},
|
||||
),
|
||||
floating_panes_template: [],
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
source: zellij-utils/src/input/./unit/layout_test.rs
|
||||
assertion_line: 899
|
||||
assertion_line: 796
|
||||
expression: "format!(\"{:#?}\", layout)"
|
||||
---
|
||||
Layout {
|
||||
|
|
@ -105,6 +105,7 @@ Layout {
|
|||
focus: None,
|
||||
external_children_index: None,
|
||||
},
|
||||
[],
|
||||
),
|
||||
(
|
||||
None,
|
||||
|
|
@ -183,6 +184,7 @@ Layout {
|
|||
focus: None,
|
||||
external_children_index: None,
|
||||
},
|
||||
[],
|
||||
),
|
||||
],
|
||||
focused_tab_index: None,
|
||||
|
|
@ -198,4 +200,5 @@ Layout {
|
|||
external_children_index: None,
|
||||
},
|
||||
),
|
||||
floating_panes_template: [],
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
source: zellij-utils/src/input/./unit/layout_test.rs
|
||||
assertion_line: 1133
|
||||
assertion_line: 1153
|
||||
expression: "format!(\"{:#?}\", layout)"
|
||||
---
|
||||
Layout {
|
||||
|
|
@ -61,4 +61,5 @@ Layout {
|
|||
external_children_index: None,
|
||||
},
|
||||
),
|
||||
floating_panes_template: [],
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
source: zellij-utils/src/input/./unit/layout_test.rs
|
||||
assertion_line: 1116
|
||||
assertion_line: 1136
|
||||
expression: "format!(\"{:#?}\", layout)"
|
||||
---
|
||||
Layout {
|
||||
|
|
@ -63,4 +63,5 @@ Layout {
|
|||
external_children_index: None,
|
||||
},
|
||||
),
|
||||
floating_panes_template: [],
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
source: zellij-utils/src/input/./unit/layout_test.rs
|
||||
assertion_line: 1516
|
||||
assertion_line: 1536
|
||||
expression: "format!(\"{:#?}\", layout)"
|
||||
---
|
||||
Layout {
|
||||
|
|
@ -58,6 +58,7 @@ Layout {
|
|||
focus: None,
|
||||
external_children_index: None,
|
||||
},
|
||||
[],
|
||||
),
|
||||
],
|
||||
focused_tab_index: None,
|
||||
|
|
@ -73,4 +74,5 @@ Layout {
|
|||
external_children_index: None,
|
||||
},
|
||||
),
|
||||
floating_panes_template: [],
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
source: zellij-utils/src/input/./unit/layout_test.rs
|
||||
assertion_line: 1537
|
||||
assertion_line: 1557
|
||||
expression: "format!(\"{:#?}\", layout)"
|
||||
---
|
||||
Layout {
|
||||
|
|
@ -102,6 +102,7 @@ Layout {
|
|||
focus: None,
|
||||
external_children_index: None,
|
||||
},
|
||||
[],
|
||||
),
|
||||
],
|
||||
focused_tab_index: None,
|
||||
|
|
@ -117,4 +118,5 @@ Layout {
|
|||
external_children_index: None,
|
||||
},
|
||||
),
|
||||
floating_panes_template: [],
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
source: zellij-utils/src/input/./unit/layout_test.rs
|
||||
assertion_line: 1556
|
||||
assertion_line: 1576
|
||||
expression: "format!(\"{:#?}\", layout)"
|
||||
---
|
||||
Layout {
|
||||
|
|
@ -87,6 +87,7 @@ Layout {
|
|||
focus: None,
|
||||
external_children_index: None,
|
||||
},
|
||||
[],
|
||||
),
|
||||
],
|
||||
focused_tab_index: None,
|
||||
|
|
@ -102,4 +103,5 @@ Layout {
|
|||
external_children_index: None,
|
||||
},
|
||||
),
|
||||
floating_panes_template: [],
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
source: zellij-utils/src/input/./unit/layout_test.rs
|
||||
assertion_line: 1403
|
||||
assertion_line: 1423
|
||||
expression: "format!(\"{:#?}\", layout)"
|
||||
---
|
||||
Layout {
|
||||
|
|
@ -55,4 +55,5 @@ Layout {
|
|||
external_children_index: None,
|
||||
},
|
||||
),
|
||||
floating_panes_template: [],
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
source: zellij-utils/src/input/./unit/layout_test.rs
|
||||
assertion_line: 1435
|
||||
assertion_line: 1455
|
||||
expression: "format!(\"{:#?}\", layout)"
|
||||
---
|
||||
Layout {
|
||||
|
|
@ -55,4 +55,5 @@ Layout {
|
|||
external_children_index: None,
|
||||
},
|
||||
),
|
||||
floating_panes_template: [],
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
source: zellij-utils/src/input/./unit/layout_test.rs
|
||||
assertion_line: 1455
|
||||
assertion_line: 1475
|
||||
expression: "format!(\"{:#?}\", layout)"
|
||||
---
|
||||
Layout {
|
||||
|
|
@ -55,4 +55,5 @@ Layout {
|
|||
external_children_index: None,
|
||||
},
|
||||
),
|
||||
floating_panes_template: [],
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
source: zellij-utils/src/input/./unit/layout_test.rs
|
||||
assertion_line: 1416
|
||||
assertion_line: 1436
|
||||
expression: "format!(\"{:#?}\", layout)"
|
||||
---
|
||||
Layout {
|
||||
|
|
@ -55,4 +55,5 @@ Layout {
|
|||
external_children_index: None,
|
||||
},
|
||||
),
|
||||
floating_panes_template: [],
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
source: zellij-utils/src/input/./unit/layout_test.rs
|
||||
assertion_line: 1471
|
||||
assertion_line: 1491
|
||||
expression: "format!(\"{:#?}\", layout)"
|
||||
---
|
||||
Layout {
|
||||
|
|
@ -58,6 +58,7 @@ Layout {
|
|||
focus: None,
|
||||
external_children_index: None,
|
||||
},
|
||||
[],
|
||||
),
|
||||
],
|
||||
focused_tab_index: None,
|
||||
|
|
@ -73,4 +74,5 @@ Layout {
|
|||
external_children_index: None,
|
||||
},
|
||||
),
|
||||
floating_panes_template: [],
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
source: zellij-utils/src/input/./unit/layout_test.rs
|
||||
assertion_line: 281
|
||||
assertion_line: 283
|
||||
expression: "format!(\"{:#?}\", layout)"
|
||||
---
|
||||
Layout {
|
||||
|
|
@ -39,4 +39,5 @@ Layout {
|
|||
external_children_index: None,
|
||||
},
|
||||
),
|
||||
floating_panes_template: [],
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
source: zellij-utils/src/input/./unit/layout_test.rs
|
||||
assertion_line: 294
|
||||
assertion_line: 296
|
||||
expression: "format!(\"{:#?}\", layout)"
|
||||
---
|
||||
Layout {
|
||||
|
|
@ -39,4 +39,5 @@ Layout {
|
|||
external_children_index: None,
|
||||
},
|
||||
),
|
||||
floating_panes_template: [],
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
source: zellij-utils/src/input/./unit/layout_test.rs
|
||||
assertion_line: 549
|
||||
assertion_line: 555
|
||||
expression: "format!(\"{:#?}\", layout)"
|
||||
---
|
||||
Layout {
|
||||
|
|
@ -71,6 +71,7 @@ Layout {
|
|||
focus: None,
|
||||
external_children_index: None,
|
||||
},
|
||||
[],
|
||||
),
|
||||
(
|
||||
Some(
|
||||
|
|
@ -138,6 +139,7 @@ Layout {
|
|||
focus: None,
|
||||
external_children_index: None,
|
||||
},
|
||||
[],
|
||||
),
|
||||
(
|
||||
None,
|
||||
|
|
@ -182,6 +184,7 @@ Layout {
|
|||
focus: None,
|
||||
external_children_index: None,
|
||||
},
|
||||
[],
|
||||
),
|
||||
],
|
||||
focused_tab_index: None,
|
||||
|
|
@ -228,4 +231,5 @@ Layout {
|
|||
external_children_index: None,
|
||||
},
|
||||
),
|
||||
floating_panes_template: [],
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
source: zellij-utils/src/input/./unit/layout_test.rs
|
||||
assertion_line: 756
|
||||
assertion_line: 650
|
||||
expression: "format!(\"{:#?}\", layout)"
|
||||
---
|
||||
Layout {
|
||||
|
|
@ -122,4 +122,5 @@ Layout {
|
|||
external_children_index: None,
|
||||
},
|
||||
),
|
||||
floating_panes_template: [],
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
source: zellij-utils/src/input/./unit/layout_test.rs
|
||||
assertion_line: 729
|
||||
assertion_line: 624
|
||||
expression: "format!(\"{:#?}\", layout)"
|
||||
---
|
||||
Layout {
|
||||
|
|
@ -91,4 +91,5 @@ Layout {
|
|||
external_children_index: None,
|
||||
},
|
||||
),
|
||||
floating_panes_template: [],
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
source: zellij-utils/src/input/./unit/layout_test.rs
|
||||
assertion_line: 626
|
||||
assertion_line: 582
|
||||
expression: "format!(\"{:#?}\", layout)"
|
||||
---
|
||||
Layout {
|
||||
|
|
@ -236,4 +236,5 @@ Layout {
|
|||
external_children_index: None,
|
||||
},
|
||||
),
|
||||
floating_panes_template: [],
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
source: zellij-utils/src/input/./unit/layout_test.rs
|
||||
assertion_line: 583
|
||||
assertion_line: 603
|
||||
expression: "format!(\"{:#?}\", layout)"
|
||||
---
|
||||
Layout {
|
||||
|
|
@ -80,6 +80,7 @@ Layout {
|
|||
focus: None,
|
||||
external_children_index: None,
|
||||
},
|
||||
[],
|
||||
),
|
||||
],
|
||||
focused_tab_index: None,
|
||||
|
|
@ -95,4 +96,5 @@ Layout {
|
|||
external_children_index: None,
|
||||
},
|
||||
),
|
||||
floating_panes_template: [],
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,102 @@
|
|||
---
|
||||
source: zellij-utils/src/input/./unit/layout_test.rs
|
||||
assertion_line: 263
|
||||
expression: "format!(\"{:#?}\", layout)"
|
||||
---
|
||||
Layout {
|
||||
tabs: [
|
||||
(
|
||||
None,
|
||||
PaneLayout {
|
||||
children_split_direction: Horizontal,
|
||||
name: None,
|
||||
children: [
|
||||
PaneLayout {
|
||||
children_split_direction: Horizontal,
|
||||
name: None,
|
||||
children: [],
|
||||
split_size: None,
|
||||
run: None,
|
||||
borderless: false,
|
||||
focus: None,
|
||||
external_children_index: None,
|
||||
},
|
||||
],
|
||||
split_size: None,
|
||||
run: None,
|
||||
borderless: false,
|
||||
focus: None,
|
||||
external_children_index: None,
|
||||
},
|
||||
[
|
||||
FloatingPanesLayout {
|
||||
name: None,
|
||||
height: None,
|
||||
width: None,
|
||||
x: None,
|
||||
y: None,
|
||||
run: None,
|
||||
focus: None,
|
||||
},
|
||||
],
|
||||
),
|
||||
(
|
||||
None,
|
||||
PaneLayout {
|
||||
children_split_direction: Horizontal,
|
||||
name: None,
|
||||
children: [
|
||||
PaneLayout {
|
||||
children_split_direction: Horizontal,
|
||||
name: None,
|
||||
children: [],
|
||||
split_size: None,
|
||||
run: None,
|
||||
borderless: false,
|
||||
focus: None,
|
||||
external_children_index: None,
|
||||
},
|
||||
],
|
||||
split_size: None,
|
||||
run: None,
|
||||
borderless: false,
|
||||
focus: None,
|
||||
external_children_index: None,
|
||||
},
|
||||
[
|
||||
FloatingPanesLayout {
|
||||
name: None,
|
||||
height: None,
|
||||
width: None,
|
||||
x: None,
|
||||
y: None,
|
||||
run: None,
|
||||
focus: None,
|
||||
},
|
||||
FloatingPanesLayout {
|
||||
name: None,
|
||||
height: None,
|
||||
width: None,
|
||||
x: None,
|
||||
y: None,
|
||||
run: None,
|
||||
focus: None,
|
||||
},
|
||||
],
|
||||
),
|
||||
],
|
||||
focused_tab_index: None,
|
||||
template: Some(
|
||||
PaneLayout {
|
||||
children_split_direction: Horizontal,
|
||||
name: None,
|
||||
children: [],
|
||||
split_size: None,
|
||||
run: None,
|
||||
borderless: false,
|
||||
focus: None,
|
||||
external_children_index: None,
|
||||
},
|
||||
),
|
||||
floating_panes_template: [],
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
source: zellij-utils/src/input/./unit/layout_test.rs
|
||||
assertion_line: 1287
|
||||
assertion_line: 1307
|
||||
expression: "format!(\"{:#?}\", layout)"
|
||||
---
|
||||
Layout {
|
||||
|
|
@ -41,4 +41,5 @@ Layout {
|
|||
external_children_index: None,
|
||||
},
|
||||
),
|
||||
floating_panes_template: [],
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
source: zellij-utils/src/input/./unit/layout_test.rs
|
||||
assertion_line: 1233
|
||||
assertion_line: 1253
|
||||
expression: "format!(\"{:#?}\", layout)"
|
||||
---
|
||||
Layout {
|
||||
|
|
@ -41,4 +41,5 @@ Layout {
|
|||
external_children_index: None,
|
||||
},
|
||||
),
|
||||
floating_panes_template: [],
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
source: zellij-utils/src/input/./unit/layout_test.rs
|
||||
assertion_line: 1250
|
||||
assertion_line: 1270
|
||||
expression: "format!(\"{:#?}\", layout)"
|
||||
---
|
||||
Layout {
|
||||
|
|
@ -41,4 +41,5 @@ Layout {
|
|||
external_children_index: None,
|
||||
},
|
||||
),
|
||||
floating_panes_template: [],
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
source: zellij-utils/src/input/./unit/layout_test.rs
|
||||
assertion_line: 1268
|
||||
assertion_line: 1288
|
||||
expression: "format!(\"{:#?}\", layout)"
|
||||
---
|
||||
Layout {
|
||||
|
|
@ -41,4 +41,5 @@ Layout {
|
|||
external_children_index: None,
|
||||
},
|
||||
),
|
||||
floating_panes_template: [],
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
source: zellij-utils/src/input/./unit/layout_test.rs
|
||||
assertion_line: 1305
|
||||
assertion_line: 1325
|
||||
expression: "format!(\"{:#?}\", layout)"
|
||||
---
|
||||
Layout {
|
||||
|
|
@ -41,4 +41,5 @@ Layout {
|
|||
external_children_index: None,
|
||||
},
|
||||
),
|
||||
floating_panes_template: [],
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
source: zellij-utils/src/input/./unit/layout_test.rs
|
||||
assertion_line: 1235
|
||||
assertion_line: 1343
|
||||
expression: "format!(\"{:#?}\", layout)"
|
||||
---
|
||||
Layout {
|
||||
|
|
@ -33,4 +33,5 @@ Layout {
|
|||
external_children_index: None,
|
||||
},
|
||||
),
|
||||
floating_panes_template: [],
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
source: zellij-utils/src/input/./unit/layout_test.rs
|
||||
assertion_line: 1357
|
||||
assertion_line: 1377
|
||||
expression: "format!(\"{:#?}\", layout)"
|
||||
---
|
||||
Layout {
|
||||
|
|
@ -41,4 +41,5 @@ Layout {
|
|||
external_children_index: None,
|
||||
},
|
||||
),
|
||||
floating_panes_template: [],
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
source: zellij-utils/src/input/./unit/layout_test.rs
|
||||
assertion_line: 1339
|
||||
assertion_line: 1359
|
||||
expression: "format!(\"{:#?}\", layout)"
|
||||
---
|
||||
Layout {
|
||||
|
|
@ -41,4 +41,5 @@ Layout {
|
|||
external_children_index: None,
|
||||
},
|
||||
),
|
||||
floating_panes_template: [],
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
source: zellij-utils/src/input/./unit/layout_test.rs
|
||||
assertion_line: 1298
|
||||
assertion_line: 1393
|
||||
expression: "format!(\"{:#?}\", layout)"
|
||||
---
|
||||
Layout {
|
||||
|
|
@ -34,4 +34,5 @@ Layout {
|
|||
external_children_index: None,
|
||||
},
|
||||
),
|
||||
floating_panes_template: [],
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
source: zellij-utils/src/input/./unit/layout_test.rs
|
||||
assertion_line: 1314
|
||||
assertion_line: 1409
|
||||
expression: "format!(\"{:#?}\", layout)"
|
||||
---
|
||||
Layout {
|
||||
|
|
@ -34,4 +34,5 @@ Layout {
|
|||
external_children_index: None,
|
||||
},
|
||||
),
|
||||
floating_panes_template: [],
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
source: zellij-utils/src/input/./unit/layout_test.rs
|
||||
assertion_line: 1486
|
||||
assertion_line: 1506
|
||||
expression: "format!(\"{:#?}\", layout)"
|
||||
---
|
||||
Layout {
|
||||
|
|
@ -58,6 +58,7 @@ Layout {
|
|||
focus: None,
|
||||
external_children_index: None,
|
||||
},
|
||||
[],
|
||||
),
|
||||
],
|
||||
focused_tab_index: None,
|
||||
|
|
@ -73,4 +74,5 @@ Layout {
|
|||
external_children_index: None,
|
||||
},
|
||||
),
|
||||
floating_panes_template: [],
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
source: zellij-utils/src/input/./unit/layout_test.rs
|
||||
assertion_line: 1501
|
||||
assertion_line: 1521
|
||||
expression: "format!(\"{:#?}\", layout)"
|
||||
---
|
||||
Layout {
|
||||
|
|
@ -58,6 +58,7 @@ Layout {
|
|||
focus: None,
|
||||
external_children_index: None,
|
||||
},
|
||||
[],
|
||||
),
|
||||
],
|
||||
focused_tab_index: None,
|
||||
|
|
@ -73,4 +74,5 @@ Layout {
|
|||
external_children_index: None,
|
||||
},
|
||||
),
|
||||
floating_panes_template: [],
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -738,7 +738,7 @@ impl TryFrom<&KdlNode> for Action {
|
|||
"PaneNameInput" => {
|
||||
parse_kdl_action_u8_arguments!(action_name, action_arguments, kdl_action)
|
||||
},
|
||||
"NewTab" => Ok(Action::NewTab(None, None)),
|
||||
"NewTab" => Ok(Action::NewTab(None, vec![], None)),
|
||||
"GoToTab" => parse_kdl_action_u8_arguments!(action_name, action_arguments, kdl_action),
|
||||
"TabNameInput" => {
|
||||
parse_kdl_action_u8_arguments!(action_name, action_arguments, kdl_action)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
source: zellij-utils/src/setup.rs
|
||||
assertion_line: 509
|
||||
assertion_line: 626
|
||||
expression: "format!(\"{:#?}\", layout)"
|
||||
---
|
||||
Layout {
|
||||
|
|
@ -18,4 +18,5 @@ Layout {
|
|||
external_children_index: None,
|
||||
},
|
||||
),
|
||||
floating_panes_template: [],
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
source: zellij-utils/src/setup.rs
|
||||
assertion_line: 492
|
||||
assertion_line: 583
|
||||
expression: "format!(\"{:#?}\", layout)"
|
||||
---
|
||||
Layout {
|
||||
|
|
@ -79,4 +79,5 @@ Layout {
|
|||
external_children_index: None,
|
||||
},
|
||||
),
|
||||
floating_panes_template: [],
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
---
|
||||
source: zellij-utils/src/setup.rs
|
||||
assertion_line: 582
|
||||
expression: "format!(\"{:#?}\", config)"
|
||||
---
|
||||
Config {
|
||||
|
|
@ -975,6 +976,7 @@ Config {
|
|||
): [
|
||||
NewTab(
|
||||
None,
|
||||
[],
|
||||
None,
|
||||
),
|
||||
SwitchToMode(
|
||||
|
|
@ -3049,6 +3051,7 @@ Config {
|
|||
): [
|
||||
NewTab(
|
||||
None,
|
||||
[],
|
||||
None,
|
||||
),
|
||||
SwitchToMode(
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
---
|
||||
source: zellij-utils/src/setup.rs
|
||||
assertion_line: 640
|
||||
expression: "format!(\"{:#?}\", config)"
|
||||
---
|
||||
Config {
|
||||
|
|
@ -975,6 +976,7 @@ Config {
|
|||
): [
|
||||
NewTab(
|
||||
None,
|
||||
[],
|
||||
None,
|
||||
),
|
||||
SwitchToMode(
|
||||
|
|
@ -3049,6 +3051,7 @@ Config {
|
|||
): [
|
||||
NewTab(
|
||||
None,
|
||||
[],
|
||||
None,
|
||||
),
|
||||
SwitchToMode(
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
source: zellij-utils/src/setup.rs
|
||||
assertion_line: 492
|
||||
assertion_line: 608
|
||||
expression: "format!(\"{:#?}\", layout)"
|
||||
---
|
||||
Layout {
|
||||
|
|
@ -18,4 +18,5 @@ Layout {
|
|||
external_children_index: None,
|
||||
},
|
||||
),
|
||||
floating_panes_template: [],
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
---
|
||||
source: zellij-utils/src/setup.rs
|
||||
assertion_line: 668
|
||||
expression: "format!(\"{:#?}\", config)"
|
||||
---
|
||||
Config {
|
||||
|
|
@ -975,6 +976,7 @@ Config {
|
|||
): [
|
||||
NewTab(
|
||||
None,
|
||||
[],
|
||||
None,
|
||||
),
|
||||
SwitchToMode(
|
||||
|
|
@ -3049,6 +3051,7 @@ Config {
|
|||
): [
|
||||
NewTab(
|
||||
None,
|
||||
[],
|
||||
None,
|
||||
),
|
||||
SwitchToMode(
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
---
|
||||
source: zellij-utils/src/setup.rs
|
||||
assertion_line: 682
|
||||
expression: "format!(\"{:#?}\", config)"
|
||||
---
|
||||
Config {
|
||||
|
|
@ -975,6 +976,7 @@ Config {
|
|||
): [
|
||||
NewTab(
|
||||
None,
|
||||
[],
|
||||
None,
|
||||
),
|
||||
SwitchToMode(
|
||||
|
|
@ -3049,6 +3051,7 @@ Config {
|
|||
): [
|
||||
NewTab(
|
||||
None,
|
||||
[],
|
||||
None,
|
||||
),
|
||||
SwitchToMode(
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
---
|
||||
source: zellij-utils/src/setup.rs
|
||||
assertion_line: 654
|
||||
expression: "format!(\"{:#?}\", config)"
|
||||
---
|
||||
Config {
|
||||
|
|
@ -975,6 +976,7 @@ Config {
|
|||
): [
|
||||
NewTab(
|
||||
None,
|
||||
[],
|
||||
None,
|
||||
),
|
||||
SwitchToMode(
|
||||
|
|
@ -3049,6 +3051,7 @@ Config {
|
|||
): [
|
||||
NewTab(
|
||||
None,
|
||||
[],
|
||||
None,
|
||||
),
|
||||
SwitchToMode(
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue