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
This commit is contained in:
parent
368c852e57
commit
c75bcbd937
21 changed files with 233 additions and 22 deletions
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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()),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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()));
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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()),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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']
|
||||
|
|
|
|||
|
|
@ -251,6 +251,7 @@ pub enum ScreenContext {
|
|||
SetFixedHeight,
|
||||
SetFixedWidth,
|
||||
ClosePane,
|
||||
UpdatePaneName,
|
||||
NewTab,
|
||||
SwitchTabNext,
|
||||
SwitchTabPrev,
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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())],
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ pub enum ClientToServerMsg {
|
|||
ClientAttributes,
|
||||
Box<CliArgs>,
|
||||
Box<Options>,
|
||||
LayoutFromYaml,
|
||||
Box<LayoutFromYaml>,
|
||||
Option<PluginsConfig>,
|
||||
),
|
||||
AttachClient(ClientAttributes, Options),
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue