aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKunal Mohan <44079328+kunalmohan@users.noreply.github.com>2021-12-09 23:30:40 +0530
committerGitHub <noreply@github.com>2021-12-09 23:30:40 +0530
commitc75bcbd9370249f23031edcd69f6724805c1e034 (patch)
treea45dab48eb4a0eea8f008db2278ea68c8166b044
parentdocs(changelog): distinct tips in `status-bar` (diff)
downloadsl0ppij-c75bcbd9370249f23031edcd69f6724805c1e034.tar.gz
sl0ppij-c75bcbd9370249f23031edcd69f6724805c1e034.tar.xz
sl0ppij-c75bcbd9370249f23031edcd69f6724805c1e034.zip
Feature: Add pane names (#928)
* Read pane name from layout * Update pane name at runtime * Fix tests * prefer and render pane name over pane title * fix clippy errors * fix after rebase
-rw-r--r--default-plugins/status-bar/src/first_line.rs2
-rw-r--r--src/tests/e2e/remote_runner.rs3
-rw-r--r--zellij-client/src/lib.rs2
-rw-r--r--zellij-server/src/lib.rs4
-rw-r--r--zellij-server/src/panes/plugin_pane.rs38
-rw-r--r--zellij-server/src/panes/terminal_pane.rs44
-rw-r--r--zellij-server/src/panes/unit/terminal_pane_tests.rs2
-rw-r--r--zellij-server/src/pty.rs2
-rw-r--r--zellij-server/src/route.rs6
-rw-r--r--zellij-server/src/screen.rs10
-rw-r--r--zellij-server/src/tab.rs36
-rw-r--r--zellij-server/src/ui/pane_contents_and_ui.rs2
-rw-r--r--zellij-tile/src/data.rs5
-rw-r--r--zellij-utils/assets/config/default.yaml23
-rw-r--r--zellij-utils/src/errors.rs1
-rw-r--r--zellij-utils/src/input/actions.rs1
-rw-r--r--zellij-utils/src/input/keybinds.rs1
-rw-r--r--zellij-utils/src/input/layout.rs11
-rw-r--r--zellij-utils/src/input/mod.rs2
-rw-r--r--zellij-utils/src/input/unit/layout_test.rs58
-rw-r--r--zellij-utils/src/ipc.rs2
21 files changed, 233 insertions, 22 deletions
diff --git a/default-plugins/status-bar/src/first_line.rs b/default-plugins/status-bar/src/first_line.rs
index 5bc51086..cdb1dece 100644
--- a/default-plugins/status-bar/src/first_line.rs
+++ b/default-plugins/status-bar/src/first_line.rs
@@ -279,7 +279,7 @@ pub fn ctrl_keys(help: &ModeInfo, max_len: usize, separator: &str) -> LinePart {
colored_elements,
separator,
),
- InputMode::Pane => key_indicators(
+ InputMode::Pane | InputMode::RenamePane => key_indicators(
max_len,
&[
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Lock),
diff --git a/src/tests/e2e/remote_runner.rs b/src/tests/e2e/remote_runner.rs
index e27e9fc2..205710f1 100644
--- a/src/tests/e2e/remote_runner.rs
+++ b/src/tests/e2e/remote_runner.rs
@@ -131,7 +131,8 @@ fn read_from_channel(
let last_snapshot = last_snapshot.clone();
let cursor_coordinates = cursor_coordinates.clone();
let mut vte_parser = vte::Parser::new();
- let mut terminal_output = TerminalPane::new(0, *pane_geom, Palette::default(), 0); // 0 is the pane index
+ let mut terminal_output =
+ TerminalPane::new(0, *pane_geom, Palette::default(), 0, String::new()); // 0 is the pane index
let mut retries_left = 3;
move || {
let mut should_sleep = false;
diff --git a/zellij-client/src/lib.rs b/zellij-client/src/lib.rs
index 38ab3021..9bc8828a 100644
--- a/zellij-client/src/lib.rs
+++ b/zellij-client/src/lib.rs
@@ -160,7 +160,7 @@ pub fn start_client(
client_attributes,
Box::new(opts),
Box::new(config_options.clone()),
- layout.unwrap(),
+ Box::new(layout.unwrap()),
Some(config.plugins.clone()),
)
}
diff --git a/zellij-server/src/lib.rs b/zellij-server/src/lib.rs
index 6a94742c..c1f238ed 100644
--- a/zellij-server/src/lib.rs
+++ b/zellij-server/src/lib.rs
@@ -58,7 +58,7 @@ pub enum ServerInstruction {
ClientAttributes,
Box<CliArgs>,
Box<Options>,
- LayoutFromYaml,
+ Box<LayoutFromYaml>,
ClientId,
Option<PluginsConfig>,
),
@@ -531,7 +531,7 @@ pub fn start_server(mut os_input: Box<dyn ServerOsApi>, socket_path: PathBuf) {
pub struct SessionOptions {
pub opts: Box<CliArgs>,
pub config_options: Box<Options>,
- pub layout: LayoutFromYaml,
+ pub layout: Box<LayoutFromYaml>,
pub plugins: Option<PluginsConfig>,
}
diff --git a/zellij-server/src/panes/plugin_pane.rs b/zellij-server/src/panes/plugin_pane.rs
index a9d5d3e5..46c5ed7a 100644
--- a/zellij-server/src/panes/plugin_pane.rs
+++ b/zellij-server/src/panes/plugin_pane.rs
@@ -12,7 +12,7 @@ use crate::ClientId;
use zellij_utils::pane_size::Offset;
use zellij_utils::position::Position;
use zellij_utils::shared::ansi_len;
-use zellij_utils::zellij_tile::prelude::{Event, Mouse, PaletteColor};
+use zellij_utils::zellij_tile::prelude::{Event, InputMode, Mouse, PaletteColor};
use zellij_utils::{
channels::SenderWithContext,
pane_size::{Dimension, PaneGeom},
@@ -28,6 +28,7 @@ pub(crate) struct PluginPane {
pub send_plugin_instructions: SenderWithContext<PluginInstruction>,
pub active_at: Instant,
pub pane_title: String,
+ pub pane_name: String,
frame: bool,
borderless: bool,
}
@@ -38,6 +39,7 @@ impl PluginPane {
position_and_size: PaneGeom,
send_plugin_instructions: SenderWithContext<PluginInstruction>,
title: String,
+ pane_name: String,
) -> Self {
Self {
pid,
@@ -51,6 +53,7 @@ impl PluginPane {
content_offset: Offset::default(),
pane_title: title,
borderless: false,
+ pane_name,
}
}
}
@@ -209,14 +212,29 @@ impl Pane for PluginPane {
None
}
}
- fn render_frame(&mut self, _client_id: ClientId, frame_params: FrameParams) -> Option<String> {
+ fn render_frame(
+ &mut self,
+ _client_id: ClientId,
+ frame_params: FrameParams,
+ input_mode: InputMode,
+ ) -> Option<String> {
// FIXME: This is a hack that assumes all fixed-size panes are borderless. This
// will eventually need fixing!
if self.frame && !(self.geom.rows.is_fixed() || self.geom.cols.is_fixed()) {
+ let pane_title = if self.pane_name.is_empty()
+ && input_mode == InputMode::RenamePane
+ && frame_params.is_main_client
+ {
+ String::from("Enter name...")
+ } else if self.pane_name.is_empty() {
+ self.pane_title.clone()
+ } else {
+ self.pane_name.clone()
+ };
let frame = PaneFrame::new(
self.current_geom().into(),
(0, 0), // scroll position
- self.pane_title.clone(),
+ pane_title,
frame_params,
);
Some(frame.render())
@@ -231,6 +249,20 @@ impl Pane for PluginPane {
) -> Option<String> {
None
}
+ fn update_name(&mut self, name: &str) {
+ match name {
+ "\0" => {
+ self.pane_name = String::new();
+ }
+ "\u{007F}" | "\u{0008}" => {
+ //delete and backspace keys
+ self.pane_name.pop();
+ }
+ c => {
+ self.pane_name.push_str(c);
+ }
+ }
+ }
fn pid(&self) -> PaneId {
PaneId::Plugin(self.pid)
}
diff --git a/zellij-server/src/panes/terminal_pane.rs b/zellij-server/src/panes/terminal_pane.rs
index a6da7670..284d6fe9 100644
--- a/zellij-server/src/panes/terminal_pane.rs
+++ b/zellij-server/src/panes/terminal_pane.rs
@@ -17,7 +17,7 @@ use zellij_utils::{
pane_size::{Dimension, PaneGeom},
position::Position,
vte,
- zellij_tile::data::{Palette, PaletteColor},
+ zellij_tile::data::{InputMode, Palette, PaletteColor},
};
pub const SELECTION_SCROLL_INTERVAL_MS: u64 = 10;
@@ -44,6 +44,7 @@ pub struct TerminalPane {
selection_scrolled_at: time::Instant,
content_offset: Offset,
pane_title: String,
+ pane_name: String,
frame: HashMap<ClientId, PaneFrame>,
borderless: bool,
fake_cursor_locations: HashSet<(usize, usize)>, // (x, y) - these hold a record of previous fake cursors which we need to clear on render
@@ -278,16 +279,31 @@ impl Pane for TerminalPane {
None
}
}
- fn render_frame(&mut self, client_id: ClientId, frame_params: FrameParams) -> Option<String> {
+ fn render_frame(
+ &mut self,
+ client_id: ClientId,
+ frame_params: FrameParams,
+ input_mode: InputMode,
+ ) -> Option<String> {
// TODO: remove the cursor stuff from here
let mut vte_output = None;
- let frame = PaneFrame::new(
- self.current_geom().into(),
- self.grid.scrollback_position_and_length(),
+ let pane_title = if self.pane_name.is_empty()
+ && input_mode == InputMode::RenamePane
+ && frame_params.is_main_client
+ {
+ String::from("Enter name...")
+ } else if self.pane_name.is_empty() {
self.grid
.title
.clone()
- .unwrap_or_else(|| self.pane_title.clone()),
+ .unwrap_or_else(|| self.pane_title.clone())
+ } else {
+ self.pane_name.clone()
+ };
+ let frame = PaneFrame::new(
+ self.current_geom().into(),
+ self.grid.scrollback_position_and_length(),
+ pane_title,
frame_params,
);
match self.frame.get(&client_id) {
@@ -336,6 +352,20 @@ impl Pane for TerminalPane {
}
vte_output
}
+ fn update_name(&mut self, name: &str) {
+ match name {
+ "\0" => {
+ self.pane_name = String::new();
+ }
+ "\u{007F}" | "\u{0008}" => {
+ //delete and backspace keys
+ self.pane_name.pop();
+ }
+ c => {
+ self.pane_name.push_str(c);
+ }
+ }
+ }
fn pid(&self) -> PaneId {
PaneId::Terminal(self.pid)
}
@@ -475,6 +505,7 @@ impl TerminalPane {
position_and_size: PaneGeom,
palette: Palette,
pane_index: usize,
+ pane_name: String,
) -> TerminalPane {
let initial_pane_title = format!("Pane #{}", pane_index);
let grid = Grid::new(
@@ -495,6 +526,7 @@ impl TerminalPane {
colors: palette,
selection_scrolled_at: time::Instant::now(),
pane_title: initial_pane_title,
+ pane_name,
borderless: false,
fake_cursor_locations: HashSet::new(),
}
diff --git a/zellij-server/src/panes/unit/terminal_pane_tests.rs b/zellij-server/src/panes/unit/terminal_pane_tests.rs
index ef24a77f..56ec2cf9 100644
--- a/zellij-server/src/panes/unit/terminal_pane_tests.rs
+++ b/zellij-server/src/panes/unit/terminal_pane_tests.rs
@@ -14,7 +14,7 @@ pub fn scrolling_inside_a_pane() {
let pid = 1;
let palette = Palette::default();
- let mut terminal_pane = TerminalPane::new(pid, fake_win_size, palette, 0); // 0 is the pane index
+ let mut terminal_pane = TerminalPane::new(pid, fake_win_size, palette, 0, String::new()); // 0 is the pane index
let mut text_to_fill_pane = String::new();
for i in 0..30 {
writeln!(&mut text_to_fill_pane, "\rline {}", i + 1).unwrap();
diff --git a/zellij-server/src/pty.rs b/zellij-server/src/pty.rs
index d7e2ad47..99f7e375 100644
--- a/zellij-server/src/pty.rs
+++ b/zellij-server/src/pty.rs
@@ -74,7 +74,7 @@ pub(crate) struct Pty {
use std::convert::TryFrom;
-pub(crate) fn pty_thread_main(mut pty: Pty, layout: LayoutFromYaml) {
+pub(crate) fn pty_thread_main(mut pty: Pty, layout: Box<LayoutFromYaml>) {
loop {
let (event, mut err_ctx) = pty.bus.recv().expect("failed to receive event on channel");
err_ctx.add_call(ContextType::Pty((&event).into()));
diff --git a/zellij-server/src/route.rs b/zellij-server/src/route.rs
index e24d2d4f..4626bc5f 100644
--- a/zellij-server/src/route.rs
+++ b/zellij-server/src/route.rs
@@ -226,6 +226,12 @@ fn route_action(
};
session.senders.send_to_pty(pty_instr).unwrap();
}
+ Action::PaneNameInput(c) => {
+ session
+ .senders
+ .send_to_screen(ScreenInstruction::UpdatePaneName(c, client_id))
+ .unwrap();
+ }
Action::Run(command) => {
let run_cmd = Some(TerminalAction::RunCommand(command.clone().into()));
let pty_instr = match command.direction {
diff --git a/zellij-server/src/screen.rs b/zellij-server/src/screen.rs
index 1400235e..f5beade5 100644
--- a/zellij-server/src/screen.rs
+++ b/zellij-server/src/screen.rs
@@ -68,6 +68,7 @@ pub enum ScreenInstruction {
TogglePaneFrames,
SetSelectable(PaneId, bool, usize),
ClosePane(PaneId, Option<ClientId>),
+ UpdatePaneName(Vec<u8>, ClientId),
NewTab(Layout, Vec<RawFd>, ClientId),
SwitchTabNext(ClientId),
SwitchTabPrev(ClientId),
@@ -140,6 +141,7 @@ impl From<&ScreenInstruction> for ScreenContext {
ScreenInstruction::TogglePaneFrames => ScreenContext::TogglePaneFrames,
ScreenInstruction::SetSelectable(..) => ScreenContext::SetSelectable,
ScreenInstruction::ClosePane(..) => ScreenContext::ClosePane,
+ ScreenInstruction::UpdatePaneName(..) => ScreenContext::UpdatePaneName,
ScreenInstruction::NewTab(..) => ScreenContext::NewTab,
ScreenInstruction::SwitchTabNext(..) => ScreenContext::SwitchTabNext,
ScreenInstruction::SwitchTabPrev(..) => ScreenContext::SwitchTabPrev,
@@ -975,6 +977,14 @@ pub(crate) fn screen_thread_main(
}
screen.update_tabs();
}
+ ScreenInstruction::UpdatePaneName(c, client_id) => {
+ screen
+ .get_active_tab_mut(client_id)
+ .unwrap()
+ .update_active_pane_name(c, client_id);
+
+ screen.render();
+ }
ScreenInstruction::ToggleActiveTerminalFullscreen(client_id) => {
screen
.get_active_tab_mut(client_id)
diff --git a/zellij-server/src/tab.rs b/zellij-server/src/tab.rs
index f684b996..a0386a45 100644
--- a/zellij-server/src/tab.rs
+++ b/zellij-server/src/tab.rs
@@ -23,8 +23,9 @@ use std::time::Instant;
use std::{
cmp::Reverse,
collections::{BTreeMap, HashMap, HashSet},
+ str,
};
-use zellij_tile::data::{Event, ModeInfo, Palette, PaletteColor};
+use zellij_tile::data::{Event, InputMode, ModeInfo, Palette, PaletteColor};
use zellij_utils::{
input::{
layout::{Direction, Layout, Run},
@@ -181,12 +182,18 @@ pub trait Pane {
fn selectable(&self) -> bool;
fn set_selectable(&mut self, selectable: bool);
fn render(&mut self, client_id: Option<ClientId>) -> Option<String>;
- fn render_frame(&mut self, client_id: ClientId, frame_params: FrameParams) -> Option<String>;
+ fn render_frame(
+ &mut self,
+ client_id: ClientId,
+ frame_params: FrameParams,
+ input_mode: InputMode,
+ ) -> Option<String>;
fn render_fake_cursor(
&mut self,
cursor_color: PaletteColor,
text_color: PaletteColor,
) -> Option<String>;
+ fn update_name(&mut self, name: &str);
fn pid(&self) -> PaneId;
fn reduce_height(&mut self, percent: f64);
fn increase_height(&mut self, percent: f64);
@@ -400,6 +407,7 @@ impl Tab {
*position_and_size,
self.senders.to_plugin.as_ref().unwrap().clone(),
pane_title,
+ layout.pane_name.clone().unwrap_or_default(),
);
new_plugin.set_borderless(layout.borderless);
self.panes.insert(PaneId::Plugin(pid), Box::new(new_plugin));
@@ -412,6 +420,7 @@ impl Tab {
*position_and_size,
self.colors,
next_terminal_position,
+ layout.pane_name.clone().unwrap_or_default(),
);
new_pane.set_borderless(layout.borderless);
self.panes
@@ -588,6 +597,7 @@ impl Tab {
bottom_winsize,
self.colors,
next_terminal_position,
+ String::new(),
);
terminal_to_split.set_geom(top_winsize);
self.panes.insert(pid, Box::new(new_terminal));
@@ -604,6 +614,7 @@ impl Tab {
right_winsize,
self.colors,
next_terminal_position,
+ String::new(),
);
terminal_to_split.set_geom(left_winsize);
self.panes.insert(pid, Box::new(new_terminal));
@@ -647,6 +658,7 @@ impl Tab {
bottom_winsize,
self.colors,
next_terminal_position,
+ String::new(),
);
active_pane.set_geom(top_winsize);
self.panes.insert(pid, Box::new(new_terminal));
@@ -684,8 +696,13 @@ impl Tab {
}
let terminal_ws = active_pane.position_and_size();
if let Some((left_winsize, right_winsize)) = split(Direction::Vertical, &terminal_ws) {
- let new_terminal =
- TerminalPane::new(term_pid, right_winsize, self.colors, next_terminal_position);
+ let new_terminal = TerminalPane::new(
+ term_pid,
+ right_winsize,
+ self.colors,
+ next_terminal_position,
+ String::new(),
+ );
active_pane.set_geom(left_winsize);
self.panes.insert(pid, Box::new(new_terminal));
}
@@ -3451,6 +3468,17 @@ impl Tab {
.unwrap();
}
}
+
+ pub fn update_active_pane_name(&mut self, buf: Vec<u8>, client_id: ClientId) {
+ if let Some(active_terminal_id) = self.get_active_terminal_id(client_id) {
+ let s = str::from_utf8(&buf).unwrap();
+ let active_terminal = self
+ .panes
+ .get_mut(&PaneId::Terminal(active_terminal_id))
+ .unwrap();
+ active_terminal.update_name(s);
+ }
+ }
}
#[allow(clippy::borrowed_box)]
diff --git a/zellij-server/src/ui/pane_contents_and_ui.rs b/zellij-server/src/ui/pane_contents_and_ui.rs
index f2742f17..25550fe9 100644
--- a/zellij-server/src/ui/pane_contents_and_ui.rs
+++ b/zellij-server/src/ui/pane_contents_and_ui.rs
@@ -132,7 +132,7 @@ impl<'a> PaneContentsAndUi<'a> {
other_cursors_exist_in_session: self.multiple_users_exist_in_session,
}
};
- if let Some(vte_output) = self.pane.render_frame(client_id, frame_params) {
+ if let Some(vte_output) = self.pane.render_frame(client_id, frame_params, client_mode) {
// FIXME: Use Termion for cursor and style clearing?
self.output.push_to_client(
client_id,
diff --git a/zellij-tile/src/data.rs b/zellij-tile/src/data.rs
index e43049a5..3e269af3 100644
--- a/zellij-tile/src/data.rs
+++ b/zellij-tile/src/data.rs
@@ -77,8 +77,12 @@ pub enum InputMode {
/// `Scroll` mode allows scrolling up and down within a pane.
#[serde(alias = "scroll")]
Scroll,
+ /// `RenameTab` mode allows assigning a new name to a tab.
#[serde(alias = "renametab")]
RenameTab,
+ /// `RenamePane` mode allows assigning a new name to a pane.
+ #[serde(alias = "renamepane")]
+ RenamePane,
/// `Session` mode allows detaching sessions
#[serde(alias = "session")]
Session,
@@ -133,6 +137,7 @@ impl FromStr for InputMode {
"session" => Ok(InputMode::Session),
"move" => Ok(InputMode::Move),
"prompt" => Ok(InputMode::Prompt),
+ "renamepane" => Ok(InputMode::RenamePane),
e => Err(e.to_string().into()),
}
}
diff --git a/zellij-utils/assets/config/default.yaml b/zellij-utils/assets/config/default.yaml
index 0c06485a..4de2a92e 100644
--- a/zellij-utils/assets/config/default.yaml
+++ b/zellij-utils/assets/config/default.yaml
@@ -135,6 +135,8 @@ keybinds:
key: [ Alt: '[',]
- action: [FocusNextPane,]
key: [ Alt: ']',]
+ - action: [SwitchToMode: RenamePane, PaneNameInput: [0],]
+ key: [Char: 'c']
move:
- action: [SwitchToMode: Locked,]
key: [Ctrl: 'g']
@@ -304,6 +306,27 @@ keybinds:
key: [ Alt: '[',]
- action: [FocusNextPane,]
key: [ Alt: ']',]
+ renamepane:
+ - action: [SwitchToMode: Normal,]
+ key: [Ctrl: 'c', Ctrl: 's', Char: ' ',]
+ - action: [SwitchToMode: Pane,]
+ key: [Char: "\n",]
+ - action: [PaneNameInput: [27] , SwitchToMode: Pane,]
+ key: [Esc,]
+ - action: [NewPane: ,]
+ key: [ Alt: 'n',]
+ - action: [MoveFocus: Left,]
+ key: [ Alt: 'h',]
+ - action: [MoveFocus: Right,]
+ key: [ Alt: 'l',]
+ - action: [MoveFocus: Down,]
+ key: [ Alt: 'j',]
+ - action: [MoveFocus: Up,]
+ key: [ Alt: 'k',]
+ - action: [FocusPreviousPane,]
+ key: [ Alt: '[',]
+ - action: [FocusNextPane,]
+ key: [ Alt: ']',]
session:
- action: [SwitchToMode: Locked,]
key: [Ctrl: 'g']
diff --git a/zellij-utils/src/errors.rs b/zellij-utils/src/errors.rs
index f8b8def9..a546e6cc 100644
--- a/zellij-utils/src/errors.rs
+++ b/zellij-utils/src/errors.rs
@@ -251,6 +251,7 @@ pub enum ScreenContext {
SetFixedHeight,
SetFixedWidth,
ClosePane,
+ UpdatePaneName,
NewTab,
SwitchTabNext,
SwitchTabPrev,
diff --git a/zellij-utils/src/input/actions.rs b/zellij-utils/src/input/actions.rs
index c84ad285..d29799fb 100644
--- a/zellij-utils/src/input/actions.rs
+++ b/zellij-utils/src/input/actions.rs
@@ -83,6 +83,7 @@ pub enum Action {
NewPane(Option<Direction>),
/// Close the focus pane.
CloseFocus,
+ PaneNameInput(Vec<u8>),
/// Create a new tab, optionally with a specified tab layout.
NewTab(Option<TabLayout>),
/// Do nothing.
diff --git a/zellij-utils/src/input/keybinds.rs b/zellij-utils/src/input/keybinds.rs
index fcc2e4a8..47b7fc3e 100644
--- a/zellij-utils/src/input/keybinds.rs
+++ b/zellij-utils/src/input/keybinds.rs
@@ -209,6 +209,7 @@ impl Keybinds {
mode_keybind_or_action(Action::Write(raw_bytes))
}
InputMode::RenameTab => mode_keybind_or_action(Action::TabNameInput(raw_bytes)),
+ InputMode::RenamePane => mode_keybind_or_action(Action::PaneNameInput(raw_bytes)),
_ => mode_keybind_or_action(Action::NoOp),
}
}
diff --git a/zellij-utils/src/input/layout.rs b/zellij-utils/src/input/layout.rs
index 29b8de00..9fa6709c 100644
--- a/zellij-utils/src/input/layout.rs
+++ b/zellij-utils/src/input/layout.rs
@@ -133,6 +133,8 @@ impl fmt::Display for RunPluginLocation {
pub struct Layout {
pub direction: Direction,
#[serde(default)]
+ pub pane_name: Option<String>,
+ #[serde(default)]
pub parts: Vec<Layout>,
pub split_size: Option<SplitSize>,
pub run: Option<Run>,
@@ -411,6 +413,8 @@ fn default_as_some_true() -> Option<bool> {
pub struct LayoutTemplate {
pub direction: Direction,
#[serde(default)]
+ pub pane_name: Option<String>,
+ #[serde(default)]
pub borderless: bool,
#[serde(default)]
pub parts: Vec<LayoutTemplate>,
@@ -454,6 +458,7 @@ impl LayoutTemplate {
pub struct TabLayout {
#[serde(default)]
pub direction: Direction,
+ pub pane_name: Option<String>,
#[serde(default)]
pub borderless: bool,
#[serde(default)]
@@ -703,6 +708,7 @@ impl TryFrom<TabLayout> for Layout {
fn try_from(tab: TabLayout) -> Result<Self, Self::Error> {
Ok(Layout {
direction: tab.direction,
+ pane_name: tab.pane_name,
borderless: tab.borderless,
parts: Self::from_vec_tab_layout(tab.parts)?,
split_size: tab.split_size,
@@ -715,6 +721,7 @@ impl From<TabLayout> for LayoutTemplate {
fn from(tab: TabLayout) -> Self {
Self {
direction: tab.direction,
+ pane_name: tab.pane_name,
borderless: tab.borderless,
parts: Self::from_vec_tab_layout(tab.parts),
body: false,
@@ -730,6 +737,7 @@ impl TryFrom<LayoutTemplate> for Layout {
fn try_from(template: LayoutTemplate) -> Result<Self, Self::Error> {
Ok(Layout {
direction: template.direction,
+ pane_name: template.pane_name,
borderless: template.borderless,
parts: Self::from_vec_template_layout(template.parts)?,
split_size: template.split_size,
@@ -752,6 +760,7 @@ impl Default for TabLayout {
split_size: None,
run: None,
name: String::new(),
+ pane_name: None,
}
}
}
@@ -760,10 +769,12 @@ impl Default for LayoutTemplate {
fn default() -> Self {
Self {
direction: Direction::Horizontal,
+ pane_name: None,
body: false,
borderless: false,
parts: vec![LayoutTemplate {
direction: Direction::Horizontal,
+ pane_name: None,
body: true,
borderless: false,
split_size: None,
diff --git a/zellij-utils/src/input/mod.rs b/zellij-utils/src/input/mod.rs
index a10ffa2c..34572ba7 100644
--- a/zellij-utils/src/input/mod.rs
+++ b/zellij-utils/src/input/mod.rs
@@ -40,6 +40,7 @@ pub fn get_mode_info(
("x".to_string(), "Close".to_string()),
("f".to_string(), "Fullscreen".to_string()),
("z".to_string(), "Frames".to_string()),
+ ("c".to_string(), "Rename".to_string()),
],
InputMode::Tab => vec![
("←↓↑→".to_string(), "Move focus".to_string()),
@@ -55,6 +56,7 @@ pub fn get_mode_info(
("u/d".to_string(), "Scroll Half Page".to_string()),
],
InputMode::RenameTab => vec![("Enter".to_string(), "when done".to_string())],
+ InputMode::RenamePane => vec![("Enter".to_string(), "when done".to_string())],
InputMode::Session => vec![("d".to_string(), "Detach".to_string())],
};
diff --git a/zellij-utils/src/input/unit/layout_test.rs b/zellij-utils/src/input/unit/layout_test.rs
index 2ec66a2a..aec34c45 100644
--- a/zellij-utils/src/input/unit/layout_test.rs
+++ b/zellij-utils/src/input/unit/layout_test.rs
@@ -40,10 +40,12 @@ fn default_layout_merged_correctly() {
let merged_layout = Layout {
direction: Direction::Horizontal,
borderless: false,
+ pane_name: None,
parts: vec![
Layout {
direction: Direction::Vertical,
borderless: true,
+ pane_name: None,
parts: vec![],
split_size: Some(SplitSize::Fixed(1)),
run: Some(Run::Plugin(RunPlugin {
@@ -54,6 +56,7 @@ fn default_layout_merged_correctly() {
Layout {
direction: Direction::Vertical,
borderless: false,
+ pane_name: None,
parts: vec![],
split_size: None,
run: None,
@@ -61,6 +64,7 @@ fn default_layout_merged_correctly() {
Layout {
direction: Direction::Vertical,
borderless: true,
+ pane_name: None,
parts: vec![],
split_size: Some(SplitSize::Fixed(2)),
run: Some(Run::Plugin(RunPlugin {
@@ -84,10 +88,12 @@ fn default_layout_new_tab_correct() {
let merged_layout = Layout {
direction: Direction::Horizontal,
borderless: false,
+ pane_name: None,
parts: vec![
Layout {
direction: Direction::Vertical,
borderless: true,
+ pane_name: None,
parts: vec![],
split_size: Some(SplitSize::Fixed(1)),
run: Some(Run::Plugin(RunPlugin {
@@ -98,6 +104,7 @@ fn default_layout_new_tab_correct() {
Layout {
direction: Direction::Horizontal,
borderless: false,
+ pane_name: None,
parts: vec![],
split_size: None,
run: None,
@@ -105,6 +112,7 @@ fn default_layout_new_tab_correct() {
Layout {
direction: Direction::Vertical,
borderless: true,
+ pane_name: None,
parts: vec![],
split_size: Some(SplitSize::Fixed(2)),
run: Some(Run::Plugin(RunPlugin {
@@ -168,13 +176,16 @@ fn three_panes_with_tab_merged_correctly() {
let merged_layout = Layout {
direction: Direction::Horizontal,
borderless: false,
+ pane_name: None,
parts: vec![Layout {
direction: Direction::Vertical,
borderless: false,
+ pane_name: None,
parts: vec![
Layout {
direction: Direction::Horizontal,
borderless: false,
+ pane_name: None,
parts: vec![],
split_size: Some(SplitSize::Percent(50.0)),
run: None,
@@ -182,10 +193,12 @@ fn three_panes_with_tab_merged_correctly() {
Layout {
direction: Direction::Horizontal,
borderless: false,
+ pane_name: None,
parts: vec![
Layout {
direction: Direction::Vertical,
borderless: false,
+ pane_name: None,
parts: vec![],
split_size: Some(SplitSize::Percent(50.0)),
run: None,
@@ -193,6 +206,7 @@ fn three_panes_with_tab_merged_correctly() {
Layout {
direction: Direction::Vertical,
borderless: false,
+ pane_name: None,
parts: vec![],
split_size: Some(SplitSize::Percent(50.0)),
run: None,
@@ -220,9 +234,11 @@ fn three_panes_with_tab_new_tab_is_correct() {
let merged_layout = Layout {
direction: Direction::Horizontal,
borderless: false,
+ pane_name: None,
parts: vec![Layout {
direction: Direction::Horizontal,
borderless: false,
+ pane_name: None,
parts: vec![],
split_size: None,
run: None,
@@ -260,10 +276,12 @@ fn three_panes_with_tab_and_default_plugins_merged_correctly() {
let merged_layout = Layout {
direction: Direction::Horizontal,
borderless: false,
+ pane_name: None,
parts: vec![
Layout {
direction: Direction::Vertical,
borderless: false,
+ pane_name: None,
parts: vec![],
split_size: Some(SplitSize::Fixed(1)),
run: Some(Run::Plugin(RunPlugin {
@@ -274,10 +292,12 @@ fn three_panes_with_tab_and_default_plugins_merged_correctly() {
Layout {
direction: Direction::Vertical,
borderless: false,
+ pane_name: None,
parts: vec![
Layout {
direction: Direction::Horizontal,
borderless: false,
+ pane_name: None,
parts: vec![],
split_size: Some(SplitSize::Percent(50.0)),
run: None,
@@ -285,10 +305,12 @@ fn three_panes_with_tab_and_default_plugins_merged_correctly() {
Layout {
direction: Direction::Horizontal,
borderless: false,
+ pane_name: None,
parts: vec![
Layout {
direction: Direction::Vertical,
borderless: false,
+ pane_name: None,
parts: vec![],
split_size: Some(SplitSize::Percent(50.0)),
run: None,
@@ -296,6 +318,7 @@ fn three_panes_with_tab_and_default_plugins_merged_correctly() {
Layout {
direction: Direction::Vertical,
borderless: false,
+ pane_name: None,
parts: vec![],
split_size: Some(SplitSize::Percent(50.0)),
run: None,
@@ -311,6 +334,7 @@ fn three_panes_with_tab_and_default_plugins_merged_correctly() {
Layout {
direction: Direction::Vertical,
borderless: false,
+ pane_name: None,
parts: vec![],
split_size: Some(SplitSize::Fixed(2)),
run: Some(Run::Plugin(RunPlugin {
@@ -334,10 +358,12 @@ fn three_panes_with_tab_and_default_plugins_new_tab_is_correct() {
let merged_layout = Layout {
direction: Direction::Horizontal,
borderless: false,
+ pane_name: None,
parts: vec![
Layout {
direction: Direction::Vertical,
borderless: false,
+ pane_name: None,
parts: vec![],
split_size: Some(SplitSize::Fixed(1)),
run: Some(Run::Plugin(RunPlugin {
@@ -348,6 +374,7 @@ fn three_panes_with_tab_and_default_plugins_new_tab_is_correct() {
Layout {
direction: Direction::Horizontal,
borderless: false,
+ pane_name: None,
parts: vec![],
split_size: None,
run: None,
@@ -355,6 +382,7 @@ fn three_panes_with_tab_and_default_plugins_new_tab_is_correct() {
Layout {
direction: Direction::Vertical,
borderless: false,
+ pane_name: None,
parts: vec![],
split_size: Some(SplitSize::Fixed(2)),
run: Some(Run::Plugin(RunPlugin {
@@ -396,14 +424,17 @@ fn deeply_nested_tab_merged_correctly() {
let merged_layout = Layout {
direction: Direction::Horizontal,
borderless: false,
+ pane_name: None,
parts: vec![
Layout {
direction: Direction::Vertical,
borderless: false,
+ pane_name: None,
parts: vec![
Layout {
direction: Direction::Horizontal,
borderless: false,
+ pane_name: None,
parts: vec![],
split_size: Some(SplitSize::Percent(21.0)),
run: None,
@@ -411,10 +442,12 @@ fn deeply_nested_tab_merged_correctly() {
Layout {
direction: Direction::Vertical,
borderless: false,
+ pane_name: None,
parts: vec![
Layout {
direction: Direction::Horizontal,
borderless: false,
+ pane_name: None,
parts: vec![],
split_size: Some(SplitSize::Percent(22.0)),
run: None,
@@ -422,10 +455,12 @@ fn deeply_nested_tab_merged_correctly() {
Layout {
direction: Direction::Horizontal,
borderless: false,
+ pane_name: None,
parts: vec![
Layout {
direction: Direction::Horizontal,
borderless: false,
+ pane_name: None,
parts: vec![],
split_size: Some(SplitSize::Percent(23.0)),
run: None,
@@ -433,6 +468,7 @@ fn deeply_nested_tab_merged_correctly() {
Layout {
direction: Direction::Horizontal,
borderless: false,
+ pane_name: None,
parts: vec![],
split_size: Some(SplitSize::Percent(24.0)),
run: None,
@@ -452,6 +488,7 @@ fn deeply_nested_tab_merged_correctly() {
Layout {
direction: Direction::Vertical,
borderless: false,
+ pane_name: None,
parts: vec![],
split_size: Some(SplitSize::Percent(15.0)),
run: None,
@@ -459,6 +496,7 @@ fn deeply_nested_tab_merged_correctly() {
Layout {
direction: Direction::Vertical,
borderless: false,
+ pane_name: None,
parts: vec![],
split_size: Some(SplitSize::Percent(15.0)),
run: None,
@@ -466,6 +504,7 @@ fn deeply_nested_tab_merged_correctly() {
Layout {
direction: Direction::Vertical,
borderless: false,
+ pane_name: None,
parts: vec![],
split_size: Some(SplitSize::Percent(15.0)),
run: None,
@@ -504,10 +543,12 @@ fn three_tabs_tab_one_merged_correctly() {
let merged_layout = Layout {
direction: Direction::Vertical,
borderless: false,
+ pane_name: None,
parts: vec![
Layout {
direction: Direction::Horizontal,
borderless: false,
+ pane_name: None,
parts: vec![],
split_size: Some(SplitSize::Percent(50.0)),
run: None,
@@ -515,6 +556,7 @@ fn three_tabs_tab_one_merged_correctly() {
Layout {
direction: Direction::Horizontal,
borderless: false,
+ pane_name: None,
parts: vec![],
split_size: None,
run: None,
@@ -539,14 +581,17 @@ fn three_tabs_tab_two_merged_correctly() {
let merged_layout = Layout {
direction: Direction::Vertical,
borderless: false,
+ pane_name: None,
parts: vec![
Layout {
direction: Direction::Horizontal,
borderless: false,
+ pane_name: None,
parts: vec![
Layout {
direction: Direction::Horizontal,
borderless: false,
+ pane_name: None,
parts: vec![],
split_size: Some(SplitSize::Percent(50.0)),
run: None,
@@ -554,6 +599,7 @@ fn three_tabs_tab_two_merged_correctly() {
Layout {
direction: Direction::Horizontal,
borderless: false,
+ pane_name: None,
parts: vec![],
split_size: None,
run: None,
@@ -565,6 +611,7 @@ fn three_tabs_tab_two_merged_correctly() {
Layout {
direction: Direction::Horizontal,
borderless: false,
+ pane_name: None,
parts: vec![],
split_size: None,
run: None,
@@ -589,14 +636,17 @@ fn three_tabs_tab_three_merged_correctly() {
let merged_layout = Layout {
direction: Direction::Vertical,
borderless: false,
+ pane_name: None,
parts: vec![
Layout {
direction: Direction::Vertical,
borderless: false,
+ pane_name: None,
parts: vec![
Layout {
direction: Direction::Vertical,
borderless: false,
+ pane_name: None,
parts: vec![],
split_size: Some(SplitSize::Percent(50.0)),
run: None,
@@ -604,6 +654,7 @@ fn three_tabs_tab_three_merged_correctly() {
Layout {
direction: Direction::Horizontal,
borderless: false,
+ pane_name: None,
parts: vec![],
split_size: None,
run: None,
@@ -615,6 +666,7 @@ fn three_tabs_tab_three_merged_correctly() {
Layout {
direction: Direction::Horizontal,
borderless: false,
+ pane_name: None,
parts: vec![],
split_size: None,
run: None,
@@ -650,9 +702,11 @@ fn no_tabs_merged_correctly() {
let merged_layout = Layout {
direction: Direction::Horizontal,
borderless: false,
+ pane_name: None,
parts: vec![Layout {
direction: Direction::Horizontal,
borderless: false,
+ pane_name: None,
parts: vec![],
split_size: None,
run: None,
@@ -699,6 +753,7 @@ fn no_layout_template_merged_correctly() {
split_size: None,
run: None,
borderless: false,
+ pane_name: None,
},
Layout {
direction: Direction::Horizontal,
@@ -706,15 +761,18 @@ fn no_layout_template_merged_correctly() {
split_size: None,
run: None,
borderless: false,
+ pane_name: None,
},
],
split_size: None,
run: None,
borderless: false,
+ pane_name: None,
}],
split_size: None,
run: None,
borderless: false,
+ pane_name: None,
};
assert_eq!(merged_layout, tab_layout.try_into().unwrap());
diff --git a/zellij-utils/src/ipc.rs b/zellij-utils/src/ipc.rs
index b27a097a..2716dd3c 100644
--- a/zellij-utils/src/ipc.rs
+++ b/zellij-utils/src/ipc.rs
@@ -62,7 +62,7 @@ pub enum ClientToServerMsg {
ClientAttributes,
Box<CliArgs>,
Box<Options>,
- LayoutFromYaml,
+ Box<LayoutFromYaml>,
Option<PluginsConfig>,
),
AttachClient(ClientAttributes, Options),