mirror of
https://github.com/zellij-org/zellij.git
synced 2024-11-30 09:55:29 +03:00
Merge pull request #625 from a-kenji/tab-layout
Add `tabs` to `layouts`
This commit is contained in:
commit
f802663067
87
example/layouts/multiple_tabs_layout.yaml
Normal file
87
example/layouts/multiple_tabs_layout.yaml
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
---
|
||||||
|
template:
|
||||||
|
direction: Horizontal
|
||||||
|
parts:
|
||||||
|
- direction: Vertical
|
||||||
|
split_size:
|
||||||
|
Fixed: 1
|
||||||
|
run:
|
||||||
|
plugin: tab-bar
|
||||||
|
borderless: true
|
||||||
|
- direction: Vertical
|
||||||
|
body: true
|
||||||
|
- direction: Vertical
|
||||||
|
split_size:
|
||||||
|
Fixed: 2
|
||||||
|
run:
|
||||||
|
plugin: status-bar
|
||||||
|
borderless: true
|
||||||
|
|
||||||
|
tabs:
|
||||||
|
- direction: Vertical
|
||||||
|
parts:
|
||||||
|
- direction: Vertical
|
||||||
|
split_size:
|
||||||
|
Percent: 50
|
||||||
|
- direction: Vertical
|
||||||
|
split_size:
|
||||||
|
Percent: 50
|
||||||
|
- direction: Vertical
|
||||||
|
- direction: Vertical
|
||||||
|
parts:
|
||||||
|
- direction: Vertical
|
||||||
|
split_size:
|
||||||
|
Percent: 50
|
||||||
|
- direction: Vertical
|
||||||
|
split_size:
|
||||||
|
Percent: 50
|
||||||
|
- direction: Vertical
|
||||||
|
parts:
|
||||||
|
- direction: Vertical
|
||||||
|
split_size:
|
||||||
|
Percent: 50
|
||||||
|
- direction: Horizontal
|
||||||
|
split_size:
|
||||||
|
Percent: 50
|
||||||
|
parts:
|
||||||
|
- direction: Vertical
|
||||||
|
split_size:
|
||||||
|
Percent: 50
|
||||||
|
- direction: Vertical
|
||||||
|
split_size:
|
||||||
|
Percent: 50
|
||||||
|
- direction: Vertical
|
||||||
|
- direction: Vertical
|
||||||
|
- direction: Vertical
|
||||||
|
- direction: Vertical
|
||||||
|
parts:
|
||||||
|
- direction: Vertical
|
||||||
|
split_size:
|
||||||
|
Percent: 20
|
||||||
|
run:
|
||||||
|
plugin: strider
|
||||||
|
- direction: Horizontal
|
||||||
|
split_size:
|
||||||
|
Percent: 80
|
||||||
|
parts:
|
||||||
|
- direction: Vertical
|
||||||
|
split_size:
|
||||||
|
Percent: 50
|
||||||
|
- direction: Vertical
|
||||||
|
split_size:
|
||||||
|
Percent: 50
|
||||||
|
- direction: Vertical
|
||||||
|
parts:
|
||||||
|
- direction: Vertical
|
||||||
|
split_size:
|
||||||
|
Percent: 40
|
||||||
|
- direction: Horizontal
|
||||||
|
split_size:
|
||||||
|
Percent: 60
|
||||||
|
parts:
|
||||||
|
- direction: Vertical
|
||||||
|
split_size:
|
||||||
|
Percent: 50
|
||||||
|
- direction: Vertical
|
||||||
|
split_size:
|
||||||
|
Percent: 50
|
90
example/layouts/multiple_tabs_layout_htop_command.yaml
Normal file
90
example/layouts/multiple_tabs_layout_htop_command.yaml
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
---
|
||||||
|
template:
|
||||||
|
direction: Horizontal
|
||||||
|
parts:
|
||||||
|
- direction: Vertical
|
||||||
|
split_size:
|
||||||
|
Fixed: 1
|
||||||
|
run:
|
||||||
|
plugin: tab-bar
|
||||||
|
borderless: true
|
||||||
|
- direction: Vertical
|
||||||
|
body: true
|
||||||
|
- direction: Vertical
|
||||||
|
split_size:
|
||||||
|
Fixed: 2
|
||||||
|
run:
|
||||||
|
plugin: status-bar
|
||||||
|
borderless: true
|
||||||
|
|
||||||
|
tabs:
|
||||||
|
- direction: Vertical
|
||||||
|
parts:
|
||||||
|
- direction: Vertical
|
||||||
|
split_size:
|
||||||
|
Percent: 50
|
||||||
|
run:
|
||||||
|
command: {cmd: htop}
|
||||||
|
- direction: Vertical
|
||||||
|
split_size:
|
||||||
|
Percent: 50
|
||||||
|
- direction: Vertical
|
||||||
|
parts:
|
||||||
|
- direction: Vertical
|
||||||
|
split_size:
|
||||||
|
Percent: 50
|
||||||
|
- direction: Vertical
|
||||||
|
split_size:
|
||||||
|
Percent: 50
|
||||||
|
- direction: Vertical
|
||||||
|
parts:
|
||||||
|
- direction: Vertical
|
||||||
|
split_size:
|
||||||
|
Percent: 50
|
||||||
|
- direction: Horizontal
|
||||||
|
split_size:
|
||||||
|
Percent: 50
|
||||||
|
parts:
|
||||||
|
- direction: Vertical
|
||||||
|
split_size:
|
||||||
|
Percent: 50
|
||||||
|
- direction: Vertical
|
||||||
|
split_size:
|
||||||
|
Percent: 50
|
||||||
|
- direction: Vertical
|
||||||
|
- direction: Vertical
|
||||||
|
run:
|
||||||
|
command: {cmd: htop, args: ["-C"]}
|
||||||
|
- direction: Vertical
|
||||||
|
- direction: Vertical
|
||||||
|
parts:
|
||||||
|
- direction: Vertical
|
||||||
|
split_size:
|
||||||
|
Percent: 20
|
||||||
|
run:
|
||||||
|
plugin: strider
|
||||||
|
- direction: Horizontal
|
||||||
|
split_size:
|
||||||
|
Percent: 80
|
||||||
|
parts:
|
||||||
|
- direction: Vertical
|
||||||
|
split_size:
|
||||||
|
Percent: 50
|
||||||
|
- direction: Vertical
|
||||||
|
split_size:
|
||||||
|
Percent: 50
|
||||||
|
- direction: Vertical
|
||||||
|
parts:
|
||||||
|
- direction: Vertical
|
||||||
|
split_size:
|
||||||
|
Percent: 40
|
||||||
|
- direction: Horizontal
|
||||||
|
split_size:
|
||||||
|
Percent: 60
|
||||||
|
parts:
|
||||||
|
- direction: Vertical
|
||||||
|
split_size:
|
||||||
|
Percent: 50
|
||||||
|
- direction: Vertical
|
||||||
|
split_size:
|
||||||
|
Percent: 50
|
21
example/layouts/run_htop_layout.yaml
Normal file
21
example/layouts/run_htop_layout.yaml
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
---
|
||||||
|
tabs:
|
||||||
|
- direction: Vertical
|
||||||
|
parts:
|
||||||
|
- direction: Horizontal
|
||||||
|
split_size:
|
||||||
|
Percent: 50
|
||||||
|
parts:
|
||||||
|
- direction: Vertical
|
||||||
|
split_size:
|
||||||
|
Percent: 50
|
||||||
|
- direction: Vertical
|
||||||
|
split_size:
|
||||||
|
Percent: 50
|
||||||
|
run:
|
||||||
|
command: {cmd: htop}
|
||||||
|
- direction: Horizontal
|
||||||
|
split_size:
|
||||||
|
Percent: 50
|
||||||
|
run:
|
||||||
|
command: {cmd: htop}
|
33
example/layouts/run_htop_layout_with_plugins.yaml
Normal file
33
example/layouts/run_htop_layout_with_plugins.yaml
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
---
|
||||||
|
tabs:
|
||||||
|
- direction: Horizontal
|
||||||
|
parts:
|
||||||
|
- direction: Vertical
|
||||||
|
split_size:
|
||||||
|
Fixed: 1
|
||||||
|
run:
|
||||||
|
plugin: tab-bar
|
||||||
|
borderless: true
|
||||||
|
- direction: Vertical
|
||||||
|
parts:
|
||||||
|
- direction: Vertical
|
||||||
|
parts:
|
||||||
|
- direction: Vertical
|
||||||
|
split_size:
|
||||||
|
Percent: 50
|
||||||
|
run:
|
||||||
|
command: {cmd: htop}
|
||||||
|
- direction: Vertical
|
||||||
|
split_size:
|
||||||
|
Percent: 50
|
||||||
|
run:
|
||||||
|
command: {cmd: htop, args: ["-C"]}
|
||||||
|
- direction: Vertical
|
||||||
|
split_size:
|
||||||
|
Fixed: 5
|
||||||
|
- direction: Vertical
|
||||||
|
split_size:
|
||||||
|
Fixed: 2
|
||||||
|
run:
|
||||||
|
plugin: status-bar
|
||||||
|
borderless: true
|
@ -1,20 +0,0 @@
|
|||||||
---
|
|
||||||
direction: Vertical
|
|
||||||
parts:
|
|
||||||
- direction: Horizontal
|
|
||||||
split_size:
|
|
||||||
Percent: 50
|
|
||||||
parts:
|
|
||||||
- direction: Vertical
|
|
||||||
split_size:
|
|
||||||
Percent: 50
|
|
||||||
- direction: Vertical
|
|
||||||
split_size:
|
|
||||||
Percent: 50
|
|
||||||
run:
|
|
||||||
command: {cmd: htop}
|
|
||||||
- direction: Horizontal
|
|
||||||
split_size:
|
|
||||||
Percent: 50
|
|
||||||
run:
|
|
||||||
command: {cmd: htop}
|
|
@ -1,30 +0,0 @@
|
|||||||
---
|
|
||||||
direction: Horizontal
|
|
||||||
parts:
|
|
||||||
- direction: Vertical
|
|
||||||
split_size:
|
|
||||||
Fixed: 1
|
|
||||||
run:
|
|
||||||
plugin: tab-bar
|
|
||||||
- direction: Vertical
|
|
||||||
parts:
|
|
||||||
- direction: Vertical
|
|
||||||
parts:
|
|
||||||
- direction: Vertical
|
|
||||||
split_size:
|
|
||||||
Percent: 50
|
|
||||||
run:
|
|
||||||
command: {cmd: htop}
|
|
||||||
- direction: Vertical
|
|
||||||
split_size:
|
|
||||||
Percent: 50
|
|
||||||
run:
|
|
||||||
command: {cmd: htop, args: ["-C"]}
|
|
||||||
- direction: Vertical
|
|
||||||
split_size:
|
|
||||||
Fixed: 5
|
|
||||||
- direction: Vertical
|
|
||||||
split_size:
|
|
||||||
Fixed: 2
|
|
||||||
run:
|
|
||||||
plugin: status-bar
|
|
24
src/main.rs
24
src/main.rs
@ -24,14 +24,6 @@ pub fn main() {
|
|||||||
list_sessions();
|
list_sessions();
|
||||||
}
|
}
|
||||||
|
|
||||||
let (config, layout, config_options) = match Setup::from_options(&opts) {
|
|
||||||
Ok(results) => results,
|
|
||||||
Err(e) => {
|
|
||||||
eprintln!("{}", e);
|
|
||||||
process::exit(1);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
atomic_create_dir(&*ZELLIJ_TMP_DIR).unwrap();
|
atomic_create_dir(&*ZELLIJ_TMP_DIR).unwrap();
|
||||||
atomic_create_dir(&*ZELLIJ_TMP_LOG_DIR).unwrap();
|
atomic_create_dir(&*ZELLIJ_TMP_LOG_DIR).unwrap();
|
||||||
if let Some(path) = opts.server {
|
if let Some(path) = opts.server {
|
||||||
@ -62,6 +54,14 @@ pub fn main() {
|
|||||||
session_name = Some(get_active_session());
|
session_name = Some(get_active_session());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let (config, _, config_options) = match Setup::from_options(&opts) {
|
||||||
|
Ok(results) => results,
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("{}", e);
|
||||||
|
process::exit(1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
start_client(
|
start_client(
|
||||||
Box::new(os_input),
|
Box::new(os_input),
|
||||||
opts,
|
opts,
|
||||||
@ -70,6 +70,14 @@ pub fn main() {
|
|||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
let (config, layout, _) = match Setup::from_options(&opts) {
|
||||||
|
Ok(results) => results,
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("{}", e);
|
||||||
|
process::exit(1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let session_name = opts
|
let session_name = opts
|
||||||
.session
|
.session
|
||||||
.clone()
|
.clone()
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
---
|
---
|
||||||
direction: Horizontal
|
tabs:
|
||||||
|
- direction: Horizontal
|
||||||
parts:
|
parts:
|
||||||
- direction: Vertical
|
- direction: Vertical
|
||||||
parts:
|
parts:
|
||||||
@ -9,6 +10,8 @@
|
|||||||
- direction: Horizontal
|
- direction: Horizontal
|
||||||
split_size:
|
split_size:
|
||||||
Percent: 50
|
Percent: 50
|
||||||
|
tabs:
|
||||||
|
- direction: Horizontal
|
||||||
split_size:
|
split_size:
|
||||||
Percent: 80
|
Percent: 80
|
||||||
- direction: Vertical
|
- direction: Vertical
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
---
|
---
|
||||||
direction: Horizontal
|
tabs:
|
||||||
|
- direction: Horizontal
|
||||||
parts:
|
parts:
|
||||||
- direction: Vertical
|
- direction: Vertical
|
||||||
parts:
|
parts:
|
||||||
@ -9,6 +10,9 @@
|
|||||||
- direction: Horizontal
|
- direction: Horizontal
|
||||||
split_size:
|
split_size:
|
||||||
Percent: 90
|
Percent: 90
|
||||||
|
- direction: Horizontal
|
||||||
|
tabs:
|
||||||
|
- direction: Horizontal
|
||||||
split_size:
|
split_size:
|
||||||
Percent: 80
|
Percent: 80
|
||||||
- direction: Vertical
|
- direction: Vertical
|
||||||
|
@ -1,16 +1,17 @@
|
|||||||
---
|
---
|
||||||
direction: Horizontal
|
tabs:
|
||||||
parts:
|
- direction: Horizontal
|
||||||
- direction: Vertical
|
|
||||||
parts:
|
parts:
|
||||||
- direction: Horizontal
|
- direction: Vertical
|
||||||
split_size:
|
parts:
|
||||||
Percent: 20
|
- direction: Horizontal
|
||||||
- direction: Horizontal
|
split_size:
|
||||||
|
Percent: 20
|
||||||
|
- direction: Horizontal
|
||||||
|
split_size:
|
||||||
|
Percent: 80
|
||||||
split_size:
|
split_size:
|
||||||
Percent: 80
|
Percent: 80
|
||||||
split_size:
|
- direction: Vertical
|
||||||
Percent: 80
|
split_size:
|
||||||
- direction: Vertical
|
Percent: 20
|
||||||
split_size:
|
|
||||||
Percent: 20
|
|
||||||
|
@ -185,7 +185,7 @@ impl InputHandler {
|
|||||||
}
|
}
|
||||||
Action::CloseFocus
|
Action::CloseFocus
|
||||||
| Action::NewPane(_)
|
| Action::NewPane(_)
|
||||||
| Action::NewTab
|
| Action::NewTab(_)
|
||||||
| Action::GoToNextTab
|
| Action::GoToNextTab
|
||||||
| Action::GoToPreviousTab
|
| Action::GoToPreviousTab
|
||||||
| Action::CloseTab
|
| Action::CloseTab
|
||||||
|
@ -14,14 +14,14 @@ use crate::{
|
|||||||
command_is_executing::CommandIsExecuting, input_handler::input_loop,
|
command_is_executing::CommandIsExecuting, input_handler::input_loop,
|
||||||
os_input_output::ClientOsApi,
|
os_input_output::ClientOsApi,
|
||||||
};
|
};
|
||||||
use zellij_utils::cli::CliArgs;
|
|
||||||
use zellij_utils::{
|
use zellij_utils::{
|
||||||
channels::{self, ChannelWithContext, SenderWithContext},
|
channels::{self, ChannelWithContext, SenderWithContext},
|
||||||
consts::{SESSION_NAME, ZELLIJ_IPC_PIPE},
|
consts::{SESSION_NAME, ZELLIJ_IPC_PIPE},
|
||||||
errors::{ClientContext, ContextType, ErrorInstruction},
|
errors::{ClientContext, ContextType, ErrorInstruction},
|
||||||
input::{actions::Action, config::Config, layout::Layout, options::Options},
|
input::{actions::Action, config::Config, options::Options},
|
||||||
ipc::{ClientAttributes, ClientToServerMsg, ExitReason, ServerToClientMsg},
|
ipc::{ClientAttributes, ClientToServerMsg, ExitReason, ServerToClientMsg},
|
||||||
};
|
};
|
||||||
|
use zellij_utils::{cli::CliArgs, input::layout::LayoutFromYaml};
|
||||||
|
|
||||||
/// Instructions related to the client-side application
|
/// Instructions related to the client-side application
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
@ -87,7 +87,7 @@ pub fn start_client(
|
|||||||
opts: CliArgs,
|
opts: CliArgs,
|
||||||
config: Config,
|
config: Config,
|
||||||
info: ClientInfo,
|
info: ClientInfo,
|
||||||
layout: Option<Layout>,
|
layout: Option<LayoutFromYaml>,
|
||||||
) {
|
) {
|
||||||
info!("Starting Zellij client!");
|
info!("Starting Zellij client!");
|
||||||
let clear_client_terminal_attributes = "\u{1b}[?1l\u{1b}=\u{1b}[r\u{1b}12l\u{1b}[?1000l\u{1b}[?1002l\u{1b}[?1003l\u{1b}[?1005l\u{1b}[?1006l\u{1b}[?12l";
|
let clear_client_terminal_attributes = "\u{1b}[?1l\u{1b}=\u{1b}[r\u{1b}12l\u{1b}[?1000l\u{1b}[?1002l\u{1b}[?1003l\u{1b}[?1005l\u{1b}[?1006l\u{1b}[?12l";
|
||||||
|
@ -11,11 +11,13 @@ mod ui;
|
|||||||
mod wasm_vm;
|
mod wasm_vm;
|
||||||
|
|
||||||
use log::info;
|
use log::info;
|
||||||
|
use std::{
|
||||||
|
path::PathBuf,
|
||||||
|
sync::{Arc, Mutex, RwLock},
|
||||||
|
thread,
|
||||||
|
};
|
||||||
use zellij_utils::zellij_tile;
|
use zellij_utils::zellij_tile;
|
||||||
|
|
||||||
use std::path::PathBuf;
|
|
||||||
use std::sync::{Arc, Mutex, RwLock};
|
|
||||||
use std::thread;
|
|
||||||
use wasmer::Store;
|
use wasmer::Store;
|
||||||
use zellij_tile::data::{Event, Palette, PluginCapabilities};
|
use zellij_tile::data::{Event, Palette, PluginCapabilities};
|
||||||
|
|
||||||
@ -34,7 +36,7 @@ use zellij_utils::{
|
|||||||
input::{
|
input::{
|
||||||
command::{RunCommand, TerminalAction},
|
command::{RunCommand, TerminalAction},
|
||||||
get_mode_info,
|
get_mode_info,
|
||||||
layout::Layout,
|
layout::LayoutFromYaml,
|
||||||
options::Options,
|
options::Options,
|
||||||
},
|
},
|
||||||
ipc::{ClientAttributes, ClientToServerMsg, ExitReason, ServerToClientMsg},
|
ipc::{ClientAttributes, ClientToServerMsg, ExitReason, ServerToClientMsg},
|
||||||
@ -44,7 +46,12 @@ use zellij_utils::{
|
|||||||
/// Instructions related to server-side application
|
/// Instructions related to server-side application
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub(crate) enum ServerInstruction {
|
pub(crate) enum ServerInstruction {
|
||||||
NewClient(ClientAttributes, Box<CliArgs>, Box<Options>, Option<Layout>),
|
NewClient(
|
||||||
|
ClientAttributes,
|
||||||
|
Box<CliArgs>,
|
||||||
|
Box<Options>,
|
||||||
|
Option<LayoutFromYaml>,
|
||||||
|
),
|
||||||
Render(Option<String>),
|
Render(Option<String>),
|
||||||
UnblockInputThread,
|
UnblockInputThread,
|
||||||
ClientExit,
|
ClientExit,
|
||||||
@ -207,7 +214,7 @@ pub fn start_server(os_input: Box<dyn ServerOsApi>, socket_path: PathBuf) {
|
|||||||
to_server.clone(),
|
to_server.clone(),
|
||||||
client_attributes,
|
client_attributes,
|
||||||
session_state.clone(),
|
session_state.clone(),
|
||||||
layout,
|
layout.clone(),
|
||||||
);
|
);
|
||||||
*session_data.write().unwrap() = Some(session);
|
*session_data.write().unwrap() = Some(session);
|
||||||
*session_state.write().unwrap() = SessionState::Attached;
|
*session_state.write().unwrap() = SessionState::Attached;
|
||||||
@ -219,14 +226,31 @@ pub fn start_server(os_input: Box<dyn ServerOsApi>, socket_path: PathBuf) {
|
|||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
session_data
|
let spawn_tabs = |tab_layout| {
|
||||||
.read()
|
session_data
|
||||||
.unwrap()
|
.read()
|
||||||
.as_ref()
|
.unwrap()
|
||||||
.unwrap()
|
.as_ref()
|
||||||
.senders
|
.unwrap()
|
||||||
.send_to_pty(PtyInstruction::NewTab(default_shell.clone()))
|
.senders
|
||||||
.unwrap();
|
.send_to_pty(PtyInstruction::NewTab(default_shell.clone(), tab_layout))
|
||||||
|
.unwrap()
|
||||||
|
};
|
||||||
|
|
||||||
|
match layout {
|
||||||
|
None => {
|
||||||
|
spawn_tabs(None);
|
||||||
|
}
|
||||||
|
Some(layout) => {
|
||||||
|
if !&layout.tabs.is_empty() {
|
||||||
|
for tab_layout in layout.tabs {
|
||||||
|
spawn_tabs(Some(tab_layout.clone()));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
spawn_tabs(None);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ServerInstruction::AttachClient(attrs, _, options) => {
|
ServerInstruction::AttachClient(attrs, _, options) => {
|
||||||
*session_state.write().unwrap() = SessionState::Attached;
|
*session_state.write().unwrap() = SessionState::Attached;
|
||||||
@ -302,7 +326,7 @@ fn init_session(
|
|||||||
to_server: SenderWithContext<ServerInstruction>,
|
to_server: SenderWithContext<ServerInstruction>,
|
||||||
client_attributes: ClientAttributes,
|
client_attributes: ClientAttributes,
|
||||||
session_state: Arc<RwLock<SessionState>>,
|
session_state: Arc<RwLock<SessionState>>,
|
||||||
layout: Option<Layout>,
|
layout: Option<LayoutFromYaml>,
|
||||||
) -> SessionMetaData {
|
) -> SessionMetaData {
|
||||||
let (to_screen, screen_receiver): ChannelWithContext<ScreenInstruction> = channels::unbounded();
|
let (to_screen, screen_receiver): ChannelWithContext<ScreenInstruction> = channels::unbounded();
|
||||||
let to_screen = SenderWithContext::new(to_screen);
|
let to_screen = SenderWithContext::new(to_screen);
|
||||||
|
@ -20,7 +20,7 @@ use zellij_utils::{
|
|||||||
errors::{get_current_ctx, ContextType, PtyContext},
|
errors::{get_current_ctx, ContextType, PtyContext},
|
||||||
input::{
|
input::{
|
||||||
command::TerminalAction,
|
command::TerminalAction,
|
||||||
layout::{Layout, Run},
|
layout::{Layout, LayoutFromYaml, Run, TabLayout},
|
||||||
},
|
},
|
||||||
logging::debug_to_file,
|
logging::debug_to_file,
|
||||||
};
|
};
|
||||||
@ -33,7 +33,7 @@ pub(crate) enum PtyInstruction {
|
|||||||
SpawnTerminal(Option<TerminalAction>),
|
SpawnTerminal(Option<TerminalAction>),
|
||||||
SpawnTerminalVertically(Option<TerminalAction>),
|
SpawnTerminalVertically(Option<TerminalAction>),
|
||||||
SpawnTerminalHorizontally(Option<TerminalAction>),
|
SpawnTerminalHorizontally(Option<TerminalAction>),
|
||||||
NewTab(Option<TerminalAction>),
|
NewTab(Option<TerminalAction>, Option<TabLayout>),
|
||||||
ClosePane(PaneId),
|
ClosePane(PaneId),
|
||||||
CloseTab(Vec<PaneId>),
|
CloseTab(Vec<PaneId>),
|
||||||
Exit,
|
Exit,
|
||||||
@ -47,7 +47,7 @@ impl From<&PtyInstruction> for PtyContext {
|
|||||||
PtyInstruction::SpawnTerminalHorizontally(_) => PtyContext::SpawnTerminalHorizontally,
|
PtyInstruction::SpawnTerminalHorizontally(_) => PtyContext::SpawnTerminalHorizontally,
|
||||||
PtyInstruction::ClosePane(_) => PtyContext::ClosePane,
|
PtyInstruction::ClosePane(_) => PtyContext::ClosePane,
|
||||||
PtyInstruction::CloseTab(_) => PtyContext::CloseTab,
|
PtyInstruction::CloseTab(_) => PtyContext::CloseTab,
|
||||||
PtyInstruction::NewTab(_) => PtyContext::NewTab,
|
PtyInstruction::NewTab(..) => PtyContext::NewTab,
|
||||||
PtyInstruction::Exit => PtyContext::Exit,
|
PtyInstruction::Exit => PtyContext::Exit,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -60,7 +60,7 @@ pub(crate) struct Pty {
|
|||||||
task_handles: HashMap<RawFd, JoinHandle<()>>,
|
task_handles: HashMap<RawFd, JoinHandle<()>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn pty_thread_main(mut pty: Pty, maybe_layout: Option<Layout>) {
|
pub(crate) fn pty_thread_main(mut pty: Pty, maybe_layout: Option<LayoutFromYaml>) {
|
||||||
loop {
|
loop {
|
||||||
let (event, mut err_ctx) = pty.bus.recv().expect("failed to receive event on channel");
|
let (event, mut err_ctx) = pty.bus.recv().expect("failed to receive event on channel");
|
||||||
err_ctx.add_call(ContextType::Pty((&event).into()));
|
err_ctx.add_call(ContextType::Pty((&event).into()));
|
||||||
@ -86,11 +86,12 @@ pub(crate) fn pty_thread_main(mut pty: Pty, maybe_layout: Option<Layout>) {
|
|||||||
.send_to_screen(ScreenInstruction::HorizontalSplit(PaneId::Terminal(pid)))
|
.send_to_screen(ScreenInstruction::HorizontalSplit(PaneId::Terminal(pid)))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
PtyInstruction::NewTab(terminal_action) => {
|
PtyInstruction::NewTab(terminal_action, tab_layout) => {
|
||||||
if let Some(layout) = maybe_layout.clone() {
|
if let Some(layout) = maybe_layout.clone() {
|
||||||
pty.spawn_terminals_for_layout(layout, terminal_action);
|
let merged_layout = layout.template.insert_tab_layout(tab_layout);
|
||||||
|
pty.spawn_terminals_for_layout(merged_layout.into(), terminal_action.clone());
|
||||||
} else {
|
} else {
|
||||||
let pid = pty.spawn_terminal(terminal_action);
|
let pid = pty.spawn_terminal(terminal_action.clone());
|
||||||
pty.bus
|
pty.bus
|
||||||
.senders
|
.senders
|
||||||
.send_to_screen(ScreenInstruction::NewTab(pid))
|
.send_to_screen(ScreenInstruction::NewTab(pid))
|
||||||
|
@ -197,11 +197,11 @@ fn route_action(
|
|||||||
.send_to_screen(ScreenInstruction::CloseFocusedPane)
|
.send_to_screen(ScreenInstruction::CloseFocusedPane)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
Action::NewTab => {
|
Action::NewTab(tab_layout) => {
|
||||||
let shell = session.default_shell.clone();
|
let shell = session.default_shell.clone();
|
||||||
session
|
session
|
||||||
.senders
|
.senders
|
||||||
.send_to_pty(PtyInstruction::NewTab(shell))
|
.send_to_pty(PtyInstruction::NewTab(shell, tab_layout))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
Action::GoToNextTab => {
|
Action::GoToNextTab => {
|
||||||
|
@ -136,7 +136,7 @@ keybinds:
|
|||||||
key: [ Char: 'h', Left, Up, Char: 'k',]
|
key: [ Char: 'h', Left, Up, Char: 'k',]
|
||||||
- action: [GoToNextTab,]
|
- action: [GoToNextTab,]
|
||||||
key: [ Char: 'l', Right,Down, Char: 'j']
|
key: [ Char: 'l', Right,Down, Char: 'j']
|
||||||
- action: [NewTab,]
|
- action: [NewTab: ,]
|
||||||
key: [ Char: 'n',]
|
key: [ Char: 'n',]
|
||||||
- action: [CloseTab,]
|
- action: [CloseTab,]
|
||||||
key: [ Char: 'x',]
|
key: [ Char: 'x',]
|
||||||
|
@ -1,16 +1,20 @@
|
|||||||
---
|
---
|
||||||
direction: Horizontal
|
template:
|
||||||
parts:
|
direction: Horizontal
|
||||||
|
parts:
|
||||||
|
- direction: Vertical
|
||||||
|
borderless: true
|
||||||
|
split_size:
|
||||||
|
Fixed: 1
|
||||||
|
run:
|
||||||
|
plugin: tab-bar
|
||||||
|
- direction: Vertical
|
||||||
|
body: true
|
||||||
|
- direction: Vertical
|
||||||
|
borderless: true
|
||||||
|
split_size:
|
||||||
|
Fixed: 2
|
||||||
|
run:
|
||||||
|
plugin: status-bar
|
||||||
|
tabs:
|
||||||
- direction: Vertical
|
- direction: Vertical
|
||||||
borderless: true
|
|
||||||
split_size:
|
|
||||||
Fixed: 1
|
|
||||||
run:
|
|
||||||
plugin: tab-bar
|
|
||||||
- direction: Vertical
|
|
||||||
- direction: Vertical
|
|
||||||
borderless: true
|
|
||||||
split_size:
|
|
||||||
Fixed: 2
|
|
||||||
run:
|
|
||||||
plugin: status-bar
|
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
---
|
---
|
||||||
direction: Horizontal
|
template:
|
||||||
parts:
|
direction: Horizontal
|
||||||
- direction: Vertical
|
parts:
|
||||||
borderless: true
|
- direction: Vertical
|
||||||
split_size:
|
borderless: true
|
||||||
Fixed: 1
|
split_size:
|
||||||
run:
|
Fixed: 1
|
||||||
plugin: tab-bar
|
run:
|
||||||
- direction: Vertical
|
plugin: tab-bar
|
||||||
|
- direction: Vertical
|
||||||
|
body: true
|
||||||
|
@ -1,12 +1,22 @@
|
|||||||
---
|
---
|
||||||
direction: Horizontal
|
template:
|
||||||
parts:
|
direction: Horizontal
|
||||||
- direction: Vertical
|
parts:
|
||||||
borderless: true
|
- direction: Vertical
|
||||||
split_size:
|
borderless: true
|
||||||
Fixed: 1
|
split_size:
|
||||||
run:
|
Fixed: 1
|
||||||
plugin: tab-bar
|
run:
|
||||||
|
plugin: tab-bar
|
||||||
|
- direction: Vertical
|
||||||
|
body: true
|
||||||
|
- direction: Vertical
|
||||||
|
borderless: true
|
||||||
|
split_size:
|
||||||
|
Fixed: 2
|
||||||
|
run:
|
||||||
|
plugin: status-bar
|
||||||
|
tabs:
|
||||||
- direction: Vertical
|
- direction: Vertical
|
||||||
parts:
|
parts:
|
||||||
- direction: Horizontal
|
- direction: Horizontal
|
||||||
@ -15,9 +25,3 @@ parts:
|
|||||||
run:
|
run:
|
||||||
plugin: strider
|
plugin: strider
|
||||||
- direction: Horizontal
|
- direction: Horizontal
|
||||||
- direction: Vertical
|
|
||||||
borderless: true
|
|
||||||
split_size:
|
|
||||||
Fixed: 2
|
|
||||||
run:
|
|
||||||
plugin: status-bar
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
//! Definition of the actions that can be bound to keys.
|
//! Definition of the actions that can be bound to keys.
|
||||||
|
|
||||||
use super::command::RunCommandAction;
|
use super::command::RunCommandAction;
|
||||||
|
use super::layout::TabLayout;
|
||||||
use crate::input::options::OnForceClose;
|
use crate::input::options::OnForceClose;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use zellij_tile::data::InputMode;
|
use zellij_tile::data::InputMode;
|
||||||
@ -19,7 +20,7 @@ pub enum Direction {
|
|||||||
// As these actions are bound to the default config, please
|
// As these actions are bound to the default config, please
|
||||||
// do take care when refactoring - or renaming.
|
// do take care when refactoring - or renaming.
|
||||||
// They might need to be adjusted in the default config
|
// They might need to be adjusted in the default config
|
||||||
// as well `../../../assets/config/default.yaml`
|
// as well `../../assets/config/default.yaml`
|
||||||
/// Actions that can be bound to keys.
|
/// Actions that can be bound to keys.
|
||||||
#[derive(Eq, Clone, Debug, PartialEq, Deserialize, Serialize)]
|
#[derive(Eq, Clone, Debug, PartialEq, Deserialize, Serialize)]
|
||||||
pub enum Action {
|
pub enum Action {
|
||||||
@ -65,8 +66,8 @@ pub enum Action {
|
|||||||
NewPane(Option<Direction>),
|
NewPane(Option<Direction>),
|
||||||
/// Close the focus pane.
|
/// Close the focus pane.
|
||||||
CloseFocus,
|
CloseFocus,
|
||||||
/// Create a new tab.
|
/// Create a new tab, optionally with a specified tab layout.
|
||||||
NewTab,
|
NewTab(Option<TabLayout>),
|
||||||
/// Do nothing.
|
/// Do nothing.
|
||||||
NoOp,
|
NoOp,
|
||||||
/// Go to the next tab.
|
/// Go to the next tab.
|
||||||
|
@ -45,6 +45,9 @@ pub enum ConfigError {
|
|||||||
IoPath(io::Error, PathBuf),
|
IoPath(io::Error, PathBuf),
|
||||||
// Internal Deserialization Error
|
// Internal Deserialization Error
|
||||||
FromUtf8(std::string::FromUtf8Error),
|
FromUtf8(std::string::FromUtf8Error),
|
||||||
|
// Missing the tab section in the layout.
|
||||||
|
Layout(LayoutMissingTabSectionError),
|
||||||
|
LayoutPartAndTab(LayoutPartAndTabError),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Config {
|
impl Default for Config {
|
||||||
@ -129,6 +132,75 @@ impl Config {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Split errors up into separate modules
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct LayoutMissingTabSectionError;
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct LayoutPartAndTabError;
|
||||||
|
|
||||||
|
impl fmt::Display for LayoutMissingTabSectionError {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"MissingTabSectionError:
|
||||||
|
There needs to be exactly one `tabs` section specified in the layout file, for example:
|
||||||
|
---
|
||||||
|
direction: Horizontal
|
||||||
|
parts:
|
||||||
|
- direction: Vertical
|
||||||
|
- direction: Vertical
|
||||||
|
tabs:
|
||||||
|
- direction: Vertical
|
||||||
|
- direction: Vertical
|
||||||
|
- direction: Vertical
|
||||||
|
"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::error::Error for LayoutMissingTabSectionError {
|
||||||
|
fn description(&self) -> &str {
|
||||||
|
"One tab must be specified per Layout."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for LayoutPartAndTabError {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"LayoutPartAndTabError:
|
||||||
|
The `tabs` and `parts` section should not be specified on the same level in the layout file, for example:
|
||||||
|
---
|
||||||
|
direction: Horizontal
|
||||||
|
parts:
|
||||||
|
- direction: Vertical
|
||||||
|
- direction: Vertical
|
||||||
|
tabs:
|
||||||
|
- direction: Vertical
|
||||||
|
- direction: Vertical
|
||||||
|
- direction: Vertical
|
||||||
|
|
||||||
|
should rather be specified as:
|
||||||
|
---
|
||||||
|
direction: Horizontal
|
||||||
|
parts:
|
||||||
|
- direction: Vertical
|
||||||
|
- direction: Vertical
|
||||||
|
tabs:
|
||||||
|
- direction: Vertical
|
||||||
|
- direction: Vertical
|
||||||
|
- direction: Vertical
|
||||||
|
"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::error::Error for LayoutPartAndTabError {
|
||||||
|
fn description(&self) -> &str {
|
||||||
|
"The `tabs` and parts section should not be specified on the same level."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Display for ConfigError {
|
impl Display for ConfigError {
|
||||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
@ -138,6 +210,12 @@ impl Display for ConfigError {
|
|||||||
}
|
}
|
||||||
ConfigError::Serde(ref err) => write!(formatter, "Deserialization error: {}", err),
|
ConfigError::Serde(ref err) => write!(formatter, "Deserialization error: {}", err),
|
||||||
ConfigError::FromUtf8(ref err) => write!(formatter, "FromUtf8Error: {}", err),
|
ConfigError::FromUtf8(ref err) => write!(formatter, "FromUtf8Error: {}", err),
|
||||||
|
ConfigError::Layout(ref err) => {
|
||||||
|
write!(formatter, "There was an error in the layout file, {}", err)
|
||||||
|
}
|
||||||
|
ConfigError::LayoutPartAndTab(ref err) => {
|
||||||
|
write!(formatter, "There was an error in the layout file, {}", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -149,6 +227,8 @@ impl std::error::Error for ConfigError {
|
|||||||
ConfigError::IoPath(ref err, _) => Some(err),
|
ConfigError::IoPath(ref err, _) => Some(err),
|
||||||
ConfigError::Serde(ref err) => Some(err),
|
ConfigError::Serde(ref err) => Some(err),
|
||||||
ConfigError::FromUtf8(ref err) => Some(err),
|
ConfigError::FromUtf8(ref err) => Some(err),
|
||||||
|
ConfigError::Layout(ref err) => Some(err),
|
||||||
|
ConfigError::LayoutPartAndTab(ref err) => Some(err),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -171,6 +251,18 @@ impl From<std::string::FromUtf8Error> for ConfigError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<LayoutMissingTabSectionError> for ConfigError {
|
||||||
|
fn from(err: LayoutMissingTabSectionError) -> ConfigError {
|
||||||
|
ConfigError::Layout(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<LayoutPartAndTabError> for ConfigError {
|
||||||
|
fn from(err: LayoutPartAndTabError) -> ConfigError {
|
||||||
|
ConfigError::LayoutPartAndTab(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// The unit test location.
|
// The unit test location.
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod config_test {
|
mod config_test {
|
||||||
|
@ -17,23 +17,24 @@ use crate::{serde, serde_yaml};
|
|||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
use std::vec::Vec;
|
||||||
use std::{fs::File, io::prelude::*};
|
use std::{fs::File, io::prelude::*};
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
|
||||||
#[serde(crate = "self::serde")]
|
#[serde(crate = "self::serde")]
|
||||||
pub enum Direction {
|
pub enum Direction {
|
||||||
Horizontal,
|
Horizontal,
|
||||||
Vertical,
|
Vertical,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone, Copy)]
|
#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq)]
|
||||||
#[serde(crate = "self::serde")]
|
#[serde(crate = "self::serde")]
|
||||||
pub enum SplitSize {
|
pub enum SplitSize {
|
||||||
Percent(u8), // 1 to 100
|
Percent(u8), // 1 to 100
|
||||||
Fixed(u16), // An absolute number of columns or rows
|
Fixed(u16), // An absolute number of columns or rows
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
|
||||||
#[serde(crate = "self::serde")]
|
#[serde(crate = "self::serde")]
|
||||||
pub enum Run {
|
pub enum Run {
|
||||||
#[serde(rename = "plugin")]
|
#[serde(rename = "plugin")]
|
||||||
@ -42,7 +43,8 @@ pub enum Run {
|
|||||||
Command(RunCommand),
|
Command(RunCommand),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
// The layout struct ultimately used to build the layouts.
|
||||||
|
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
|
||||||
#[serde(crate = "self::serde")]
|
#[serde(crate = "self::serde")]
|
||||||
pub struct Layout {
|
pub struct Layout {
|
||||||
pub direction: Direction,
|
pub direction: Direction,
|
||||||
@ -54,23 +56,38 @@ pub struct Layout {
|
|||||||
pub borderless: bool,
|
pub borderless: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
type LayoutResult = Result<Layout, ConfigError>;
|
// The struct that is used to deserialize the layout from
|
||||||
|
// a yaml configuration file
|
||||||
|
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
|
||||||
|
#[serde(crate = "self::serde")]
|
||||||
|
#[serde(default)]
|
||||||
|
pub struct LayoutFromYaml {
|
||||||
|
#[serde(default)]
|
||||||
|
pub template: LayoutTemplate,
|
||||||
|
#[serde(default)]
|
||||||
|
pub borderless: bool,
|
||||||
|
#[serde(default)]
|
||||||
|
pub tabs: Vec<TabLayout>,
|
||||||
|
}
|
||||||
|
|
||||||
impl Layout {
|
type LayoutFromYamlResult = Result<LayoutFromYaml, ConfigError>;
|
||||||
pub fn new(layout_path: &Path) -> LayoutResult {
|
|
||||||
|
impl LayoutFromYaml {
|
||||||
|
pub fn new(layout_path: &Path) -> LayoutFromYamlResult {
|
||||||
let mut layout_file = File::open(&layout_path)
|
let mut layout_file = File::open(&layout_path)
|
||||||
.or_else(|_| File::open(&layout_path.with_extension("yaml")))
|
.or_else(|_| File::open(&layout_path.with_extension("yaml")))
|
||||||
.map_err(|e| ConfigError::IoPath(e, layout_path.into()))?;
|
.map_err(|e| ConfigError::IoPath(e, layout_path.into()))?;
|
||||||
|
|
||||||
let mut layout = String::new();
|
let mut layout = String::new();
|
||||||
layout_file.read_to_string(&mut layout)?;
|
layout_file.read_to_string(&mut layout)?;
|
||||||
let layout: Layout = serde_yaml::from_str(&layout)?;
|
let layout: LayoutFromYaml = serde_yaml::from_str(&layout)?;
|
||||||
|
|
||||||
Ok(layout)
|
Ok(layout)
|
||||||
}
|
}
|
||||||
|
|
||||||
// It wants to use Path here, but that doesn't compile.
|
// It wants to use Path here, but that doesn't compile.
|
||||||
#[allow(clippy::ptr_arg)]
|
#[allow(clippy::ptr_arg)]
|
||||||
pub fn from_dir(layout: &PathBuf, layout_dir: Option<&PathBuf>) -> LayoutResult {
|
pub fn from_dir(layout: &PathBuf, layout_dir: Option<&PathBuf>) -> LayoutFromYamlResult {
|
||||||
match layout_dir {
|
match layout_dir {
|
||||||
Some(dir) => Self::new(&dir.join(layout))
|
Some(dir) => Self::new(&dir.join(layout))
|
||||||
.or_else(|_| Self::from_default_assets(layout.as_path())),
|
.or_else(|_| Self::from_default_assets(layout.as_path())),
|
||||||
@ -82,22 +99,21 @@ impl Layout {
|
|||||||
layout: Option<&PathBuf>,
|
layout: Option<&PathBuf>,
|
||||||
layout_path: Option<&PathBuf>,
|
layout_path: Option<&PathBuf>,
|
||||||
layout_dir: Option<PathBuf>,
|
layout_dir: Option<PathBuf>,
|
||||||
) -> Option<Result<Layout, ConfigError>> {
|
) -> Option<LayoutFromYamlResult> {
|
||||||
layout
|
layout
|
||||||
.map(|p| Layout::from_dir(p, layout_dir.as_ref()))
|
.map(|p| LayoutFromYaml::from_dir(p, layout_dir.as_ref()))
|
||||||
.or_else(|| layout_path.map(|p| Layout::new(p)))
|
.or_else(|| layout_path.map(|p| LayoutFromYaml::new(p)))
|
||||||
.or_else(|| {
|
.or_else(|| {
|
||||||
Some(Layout::from_dir(
|
Some(LayoutFromYaml::from_dir(
|
||||||
&std::path::PathBuf::from("default"),
|
&std::path::PathBuf::from("default"),
|
||||||
layout_dir.as_ref(),
|
layout_dir.as_ref(),
|
||||||
))
|
))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Currently still needed but on nightly
|
// Currently still needed but on nightly
|
||||||
// this is already possible:
|
// this is already possible:
|
||||||
// HashMap<&'static str, Vec<u8>>
|
// HashMap<&'static str, Vec<u8>>
|
||||||
pub fn from_default_assets(path: &Path) -> LayoutResult {
|
pub fn from_default_assets(path: &Path) -> LayoutFromYamlResult {
|
||||||
match path.to_str() {
|
match path.to_str() {
|
||||||
Some("default") => Self::default_from_assets(),
|
Some("default") => Self::default_from_assets(),
|
||||||
Some("strider") => Self::strider_from_assets(),
|
Some("strider") => Self::strider_from_assets(),
|
||||||
@ -111,24 +127,83 @@ impl Layout {
|
|||||||
|
|
||||||
// TODO Deserialize the assets from bytes &[u8],
|
// TODO Deserialize the assets from bytes &[u8],
|
||||||
// once serde-yaml supports zero-copy
|
// once serde-yaml supports zero-copy
|
||||||
pub fn default_from_assets() -> LayoutResult {
|
pub fn default_from_assets() -> LayoutFromYamlResult {
|
||||||
let layout: Layout =
|
let layout: LayoutFromYaml =
|
||||||
serde_yaml::from_str(String::from_utf8(setup::DEFAULT_LAYOUT.to_vec())?.as_str())?;
|
serde_yaml::from_str(String::from_utf8(setup::DEFAULT_LAYOUT.to_vec())?.as_str())?;
|
||||||
Ok(layout)
|
Ok(layout)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn strider_from_assets() -> LayoutResult {
|
pub fn strider_from_assets() -> LayoutFromYamlResult {
|
||||||
let layout: Layout =
|
let layout: LayoutFromYaml =
|
||||||
serde_yaml::from_str(String::from_utf8(setup::STRIDER_LAYOUT.to_vec())?.as_str())?;
|
serde_yaml::from_str(String::from_utf8(setup::STRIDER_LAYOUT.to_vec())?.as_str())?;
|
||||||
Ok(layout)
|
Ok(layout)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn disable_status_from_assets() -> LayoutResult {
|
pub fn disable_status_from_assets() -> LayoutFromYamlResult {
|
||||||
let layout: Layout =
|
let layout: LayoutFromYaml =
|
||||||
serde_yaml::from_str(String::from_utf8(setup::NO_STATUS_LAYOUT.to_vec())?.as_str())?;
|
serde_yaml::from_str(String::from_utf8(setup::NO_STATUS_LAYOUT.to_vec())?.as_str())?;
|
||||||
Ok(layout)
|
Ok(layout)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The struct that carries the information template that is used to
|
||||||
|
// construct the layout
|
||||||
|
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
|
||||||
|
#[serde(crate = "self::serde")]
|
||||||
|
pub struct LayoutTemplate {
|
||||||
|
pub direction: Direction,
|
||||||
|
#[serde(default)]
|
||||||
|
pub borderless: bool,
|
||||||
|
#[serde(default)]
|
||||||
|
pub parts: Vec<LayoutTemplate>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub body: bool,
|
||||||
|
pub split_size: Option<SplitSize>,
|
||||||
|
pub run: Option<Run>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LayoutTemplate {
|
||||||
|
// Insert an optional `[TabLayout]` at the correct postion
|
||||||
|
pub fn insert_tab_layout(mut self, tab_layout: Option<TabLayout>) -> Self {
|
||||||
|
if self.body {
|
||||||
|
return tab_layout.unwrap_or_default().into();
|
||||||
|
}
|
||||||
|
for (i, part) in self.parts.clone().iter().enumerate() {
|
||||||
|
if part.body {
|
||||||
|
self.parts.push(tab_layout.unwrap_or_default().into());
|
||||||
|
self.parts.swap_remove(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// recurse
|
||||||
|
let new_part = part.clone().insert_tab_layout(tab_layout.clone());
|
||||||
|
self.parts.push(new_part);
|
||||||
|
self.parts.swap_remove(i);
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_vec_tab_layout(tab_layout: Vec<TabLayout>) -> Vec<Self> {
|
||||||
|
tab_layout
|
||||||
|
.iter()
|
||||||
|
.map(|tab_layout| Self::from(tab_layout.to_owned()))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The tab-layout struct used to specify each individual tab.
|
||||||
|
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
|
||||||
|
#[serde(crate = "self::serde")]
|
||||||
|
pub struct TabLayout {
|
||||||
|
pub direction: Direction,
|
||||||
|
#[serde(default)]
|
||||||
|
pub borderless: bool,
|
||||||
|
#[serde(default)]
|
||||||
|
pub parts: Vec<TabLayout>,
|
||||||
|
pub split_size: Option<SplitSize>,
|
||||||
|
pub run: Option<Run>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Layout {
|
||||||
pub fn total_terminal_panes(&self) -> usize {
|
pub fn total_terminal_panes(&self) -> usize {
|
||||||
let mut total_panes = 0;
|
let mut total_panes = 0;
|
||||||
total_panes += self.parts.len();
|
total_panes += self.parts.len();
|
||||||
@ -169,6 +244,28 @@ impl Layout {
|
|||||||
) -> Vec<(Layout, PositionAndSize)> {
|
) -> Vec<(Layout, PositionAndSize)> {
|
||||||
split_space(space, self)
|
split_space(space, self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn merge_tab_layout(&mut self, tab: TabLayout) {
|
||||||
|
self.parts.push(tab.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn merge_layout_parts(&mut self, mut parts: Vec<Layout>) {
|
||||||
|
self.parts.append(&mut parts);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_vec_tab_layout(tab_layout: Vec<TabLayout>) -> Vec<Self> {
|
||||||
|
tab_layout
|
||||||
|
.iter()
|
||||||
|
.map(|tab_layout| Layout::from(tab_layout.to_owned()))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_vec_template_layout(layout_template: Vec<LayoutTemplate>) -> Vec<Self> {
|
||||||
|
layout_template
|
||||||
|
.iter()
|
||||||
|
.map(|layout_template| Layout::from(layout_template.to_owned()))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn split_space_to_parts_vertically(
|
fn split_space_to_parts_vertically(
|
||||||
@ -323,3 +420,87 @@ fn split_space(
|
|||||||
}
|
}
|
||||||
pane_positions
|
pane_positions
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<TabLayout> for Layout {
|
||||||
|
fn from(tab: TabLayout) -> Self {
|
||||||
|
Layout {
|
||||||
|
direction: tab.direction,
|
||||||
|
borderless: tab.borderless,
|
||||||
|
parts: Self::from_vec_tab_layout(tab.parts),
|
||||||
|
split_size: tab.split_size,
|
||||||
|
run: tab.run,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<TabLayout> for LayoutTemplate {
|
||||||
|
fn from(tab: TabLayout) -> Self {
|
||||||
|
Self {
|
||||||
|
direction: tab.direction,
|
||||||
|
borderless: tab.borderless,
|
||||||
|
parts: Self::from_vec_tab_layout(tab.parts),
|
||||||
|
body: false,
|
||||||
|
split_size: tab.split_size,
|
||||||
|
run: tab.run,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<LayoutTemplate> for Layout {
|
||||||
|
fn from(template: LayoutTemplate) -> Self {
|
||||||
|
Layout {
|
||||||
|
direction: template.direction,
|
||||||
|
borderless: template.borderless,
|
||||||
|
parts: Self::from_vec_template_layout(template.parts),
|
||||||
|
split_size: template.split_size,
|
||||||
|
run: template.run,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for TabLayout {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
direction: Direction::Horizontal,
|
||||||
|
borderless: false,
|
||||||
|
parts: vec![],
|
||||||
|
split_size: None,
|
||||||
|
run: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for LayoutTemplate {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
direction: Direction::Horizontal,
|
||||||
|
body: false,
|
||||||
|
borderless: false,
|
||||||
|
parts: vec![LayoutTemplate {
|
||||||
|
direction: Direction::Horizontal,
|
||||||
|
body: true,
|
||||||
|
borderless: false,
|
||||||
|
split_size: None,
|
||||||
|
run: None,
|
||||||
|
parts: vec![],
|
||||||
|
}],
|
||||||
|
split_size: None,
|
||||||
|
run: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for LayoutFromYaml {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
template: LayoutTemplate::default(),
|
||||||
|
borderless: false,
|
||||||
|
tabs: vec![],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The unit test location.
|
||||||
|
#[cfg(test)]
|
||||||
|
#[path = "./unit/layout_test.rs"]
|
||||||
|
mod layout_test;
|
||||||
|
@ -0,0 +1,41 @@
|
|||||||
|
---
|
||||||
|
template:
|
||||||
|
direction: Horizontal
|
||||||
|
parts:
|
||||||
|
- direction: Vertical
|
||||||
|
parts:
|
||||||
|
- direction: Horizontal
|
||||||
|
split_size:
|
||||||
|
Percent: 21
|
||||||
|
- direction: Vertical
|
||||||
|
split_size:
|
||||||
|
Percent: 79
|
||||||
|
parts:
|
||||||
|
- direction: Horizontal
|
||||||
|
split_size:
|
||||||
|
Percent: 22
|
||||||
|
- direction: Horizontal
|
||||||
|
split_size:
|
||||||
|
Percent: 78
|
||||||
|
parts:
|
||||||
|
- direction: Horizontal
|
||||||
|
split_size:
|
||||||
|
Percent: 23
|
||||||
|
- direction: Vertical
|
||||||
|
body: true
|
||||||
|
split_size:
|
||||||
|
Percent: 90
|
||||||
|
- direction: Vertical
|
||||||
|
split_size:
|
||||||
|
Percent: 15
|
||||||
|
- direction: Vertical
|
||||||
|
split_size:
|
||||||
|
Percent: 15
|
||||||
|
- direction: Vertical
|
||||||
|
split_size:
|
||||||
|
Percent: 15
|
||||||
|
|
||||||
|
tabs:
|
||||||
|
- direction: Horizontal
|
||||||
|
split_size:
|
||||||
|
Percent: 24
|
@ -0,0 +1,18 @@
|
|||||||
|
---
|
||||||
|
direction: Horizontal
|
||||||
|
parts:
|
||||||
|
- direction: Horizontal
|
||||||
|
parts:
|
||||||
|
- direction: Vertical
|
||||||
|
parts:
|
||||||
|
- direction: Horizontal
|
||||||
|
split_size:
|
||||||
|
Percent: 50
|
||||||
|
- direction: Horizontal
|
||||||
|
tabs:
|
||||||
|
- direction: Vertical
|
||||||
|
split_size:
|
||||||
|
Percent: 50
|
||||||
|
- direction: Vertical
|
||||||
|
split_size:
|
||||||
|
Percent: 50
|
@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
tabs:
|
||||||
|
- direction: Vertical
|
||||||
|
parts:
|
||||||
|
- direction: Horizontal
|
||||||
|
- direction: Horizontal
|
@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
template:
|
||||||
|
direction: Horizontal
|
||||||
|
parts:
|
||||||
|
- direction: Horizontal
|
||||||
|
body: true
|
@ -0,0 +1,35 @@
|
|||||||
|
---
|
||||||
|
template:
|
||||||
|
direction: Horizontal
|
||||||
|
parts:
|
||||||
|
- direction: Vertical
|
||||||
|
split_size:
|
||||||
|
Fixed: 1
|
||||||
|
run:
|
||||||
|
plugin: tab-bar
|
||||||
|
- direction: Horizontal
|
||||||
|
body: true
|
||||||
|
- direction: Vertical
|
||||||
|
split_size:
|
||||||
|
Fixed: 2
|
||||||
|
run:
|
||||||
|
plugin: status-bar
|
||||||
|
|
||||||
|
tabs:
|
||||||
|
- direction: Vertical
|
||||||
|
parts:
|
||||||
|
- direction: Horizontal
|
||||||
|
split_size:
|
||||||
|
Percent: 50
|
||||||
|
- direction: Horizontal
|
||||||
|
parts:
|
||||||
|
- direction: Vertical
|
||||||
|
split_size:
|
||||||
|
Percent: 50
|
||||||
|
run:
|
||||||
|
command: {cmd: htop}
|
||||||
|
- direction: Vertical
|
||||||
|
split_size:
|
||||||
|
Percent: 50
|
||||||
|
run:
|
||||||
|
command: {cmd: htop, args: ["-C"]}
|
@ -0,0 +1,31 @@
|
|||||||
|
---
|
||||||
|
template:
|
||||||
|
direction: Horizontal
|
||||||
|
parts:
|
||||||
|
- direction: Vertical
|
||||||
|
split_size:
|
||||||
|
Fixed: 1
|
||||||
|
run:
|
||||||
|
plugin: tab-bar
|
||||||
|
- direction: Horizontal
|
||||||
|
body: true
|
||||||
|
- direction: Vertical
|
||||||
|
split_size:
|
||||||
|
Fixed: 2
|
||||||
|
run:
|
||||||
|
plugin: status-bar
|
||||||
|
|
||||||
|
tabs:
|
||||||
|
- direction: Vertical
|
||||||
|
parts:
|
||||||
|
- direction: Horizontal
|
||||||
|
split_size:
|
||||||
|
Percent: 50
|
||||||
|
- direction: Horizontal
|
||||||
|
parts:
|
||||||
|
- direction: Vertical
|
||||||
|
split_size:
|
||||||
|
Percent: 50
|
||||||
|
- direction: Vertical
|
||||||
|
split_size:
|
||||||
|
Percent: 50
|
@ -0,0 +1,21 @@
|
|||||||
|
---
|
||||||
|
template:
|
||||||
|
direction: Horizontal
|
||||||
|
parts:
|
||||||
|
- direction: Horizontal
|
||||||
|
body: true
|
||||||
|
|
||||||
|
tabs:
|
||||||
|
- direction: Vertical
|
||||||
|
parts:
|
||||||
|
- direction: Horizontal
|
||||||
|
split_size:
|
||||||
|
Percent: 50
|
||||||
|
- direction: Horizontal
|
||||||
|
parts:
|
||||||
|
- direction: Vertical
|
||||||
|
split_size:
|
||||||
|
Percent: 50
|
||||||
|
- direction: Vertical
|
||||||
|
split_size:
|
||||||
|
Percent: 50
|
@ -0,0 +1,29 @@
|
|||||||
|
---
|
||||||
|
template:
|
||||||
|
direction: Vertical
|
||||||
|
parts:
|
||||||
|
- direction: Horizontal
|
||||||
|
body: true
|
||||||
|
- direction: Horizontal
|
||||||
|
|
||||||
|
|
||||||
|
tabs:
|
||||||
|
- direction: Horizontal
|
||||||
|
split_size:
|
||||||
|
Percent: 50
|
||||||
|
- direction: Horizontal
|
||||||
|
split_size:
|
||||||
|
Percent: 50
|
||||||
|
parts:
|
||||||
|
- direction: Horizontal
|
||||||
|
split_size:
|
||||||
|
Percent: 50
|
||||||
|
- direction: Horizontal
|
||||||
|
- direction: Vertical
|
||||||
|
split_size:
|
||||||
|
Percent: 50
|
||||||
|
parts:
|
||||||
|
- direction: Vertical
|
||||||
|
split_size:
|
||||||
|
Percent: 50
|
||||||
|
- direction: Horizontal
|
@ -150,7 +150,7 @@ fn no_unbind_unbinds_none() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn last_keybind_is_taken() {
|
fn last_keybind_is_taken() {
|
||||||
let actions_1 = vec![Action::NoOp, Action::NewTab];
|
let actions_1 = vec![Action::NoOp, Action::NewTab(None)];
|
||||||
let keyaction_1 = KeyActionFromYaml {
|
let keyaction_1 = KeyActionFromYaml {
|
||||||
action: actions_1.clone(),
|
action: actions_1.clone(),
|
||||||
key: vec![Key::F(1), Key::Backspace, Key::Char('t')],
|
key: vec![Key::F(1), Key::Backspace, Key::Char('t')],
|
||||||
@ -171,7 +171,7 @@ fn last_keybind_is_taken() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn last_keybind_overwrites() {
|
fn last_keybind_overwrites() {
|
||||||
let actions_1 = vec![Action::NoOp, Action::NewTab];
|
let actions_1 = vec![Action::NoOp, Action::NewTab(None)];
|
||||||
let keyaction_1 = KeyActionFromYaml {
|
let keyaction_1 = KeyActionFromYaml {
|
||||||
action: actions_1.clone(),
|
action: actions_1.clone(),
|
||||||
key: vec![Key::F(1), Key::Backspace, Key::Char('t')],
|
key: vec![Key::F(1), Key::Backspace, Key::Char('t')],
|
||||||
@ -764,7 +764,7 @@ fn unbind_single_toplevel_multiple_keys_multiple_modes() {
|
|||||||
fn uppercase_and_lowercase_are_distinct() {
|
fn uppercase_and_lowercase_are_distinct() {
|
||||||
let key_action_n = KeyActionFromYaml {
|
let key_action_n = KeyActionFromYaml {
|
||||||
key: vec![Key::Char('n')],
|
key: vec![Key::Char('n')],
|
||||||
action: vec![Action::NewTab],
|
action: vec![Action::NewTab(None)],
|
||||||
};
|
};
|
||||||
let key_action_large_n = KeyActionFromYaml {
|
let key_action_large_n = KeyActionFromYaml {
|
||||||
key: vec![Key::Char('N')],
|
key: vec![Key::Char('N')],
|
||||||
|
696
zellij-utils/src/input/unit/layout_test.rs
Normal file
696
zellij-utils/src/input/unit/layout_test.rs
Normal file
@ -0,0 +1,696 @@
|
|||||||
|
use super::super::layout::*;
|
||||||
|
|
||||||
|
fn layout_test_dir(layout: String) -> PathBuf {
|
||||||
|
let root = Path::new(env!("CARGO_MANIFEST_DIR"));
|
||||||
|
let layout_dir = root.join("src/input/unit/fixtures/layouts");
|
||||||
|
layout_dir.join(layout)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn default_layout_dir(layout: String) -> PathBuf {
|
||||||
|
let root = Path::new(env!("CARGO_MANIFEST_DIR"));
|
||||||
|
let layout_dir = root.join("assets/layouts");
|
||||||
|
layout_dir.join(layout)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn default_layout_is_ok() {
|
||||||
|
let path = default_layout_dir("default.yaml".into());
|
||||||
|
let layout = LayoutFromYaml::new(&path);
|
||||||
|
assert!(layout.is_ok());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn default_layout_has_one_tab() {
|
||||||
|
let path = default_layout_dir("default.yaml".into());
|
||||||
|
let layout = LayoutFromYaml::new(&path);
|
||||||
|
let layout_template = layout.as_ref().unwrap();
|
||||||
|
assert_eq!(layout_template.tabs.len(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn default_layout_merged_correctly() {
|
||||||
|
let path = default_layout_dir("default.yaml".into());
|
||||||
|
let layout_from_yaml = LayoutFromYaml::new(&path);
|
||||||
|
let layout_template = layout_from_yaml.as_ref().unwrap();
|
||||||
|
let tab_layout = layout_template
|
||||||
|
.template
|
||||||
|
.clone()
|
||||||
|
.insert_tab_layout(Some(layout_template.tabs[0].clone()));
|
||||||
|
let merged_layout = Layout {
|
||||||
|
direction: Direction::Horizontal,
|
||||||
|
borderless: false,
|
||||||
|
parts: vec![
|
||||||
|
Layout {
|
||||||
|
direction: Direction::Vertical,
|
||||||
|
borderless: true,
|
||||||
|
parts: vec![],
|
||||||
|
split_size: Some(SplitSize::Fixed(1)),
|
||||||
|
run: Some(Run::Plugin(Some("tab-bar".into()))),
|
||||||
|
},
|
||||||
|
Layout {
|
||||||
|
direction: Direction::Vertical,
|
||||||
|
borderless: false,
|
||||||
|
parts: vec![],
|
||||||
|
split_size: None,
|
||||||
|
run: None,
|
||||||
|
},
|
||||||
|
Layout {
|
||||||
|
direction: Direction::Vertical,
|
||||||
|
borderless: true,
|
||||||
|
parts: vec![],
|
||||||
|
split_size: Some(SplitSize::Fixed(2)),
|
||||||
|
run: Some(Run::Plugin(Some("status-bar".into()))),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
split_size: None,
|
||||||
|
run: None,
|
||||||
|
};
|
||||||
|
assert_eq!(merged_layout, tab_layout.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn default_layout_new_tab_correct() {
|
||||||
|
let path = default_layout_dir("default.yaml".into());
|
||||||
|
let layout_from_yaml = LayoutFromYaml::new(&path);
|
||||||
|
let layout_template = layout_from_yaml.as_ref().unwrap();
|
||||||
|
let tab_layout = layout_template.template.clone().insert_tab_layout(None);
|
||||||
|
let merged_layout = Layout {
|
||||||
|
direction: Direction::Horizontal,
|
||||||
|
borderless: false,
|
||||||
|
parts: vec![
|
||||||
|
Layout {
|
||||||
|
direction: Direction::Vertical,
|
||||||
|
borderless: true,
|
||||||
|
parts: vec![],
|
||||||
|
split_size: Some(SplitSize::Fixed(1)),
|
||||||
|
run: Some(Run::Plugin(Some("tab-bar".into()))),
|
||||||
|
},
|
||||||
|
Layout {
|
||||||
|
direction: Direction::Horizontal,
|
||||||
|
borderless: false,
|
||||||
|
parts: vec![],
|
||||||
|
split_size: None,
|
||||||
|
run: None,
|
||||||
|
},
|
||||||
|
Layout {
|
||||||
|
direction: Direction::Vertical,
|
||||||
|
borderless: true,
|
||||||
|
parts: vec![],
|
||||||
|
split_size: Some(SplitSize::Fixed(2)),
|
||||||
|
run: Some(Run::Plugin(Some("status-bar".into()))),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
split_size: None,
|
||||||
|
run: None,
|
||||||
|
};
|
||||||
|
assert_eq!(merged_layout, tab_layout.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn default_strider_layout_is_ok() {
|
||||||
|
let path = default_layout_dir("strider.yaml".into());
|
||||||
|
let layout_from_yaml = LayoutFromYaml::new(&path);
|
||||||
|
assert!(layout_from_yaml.is_ok());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn default_disable_status_layout_is_ok() {
|
||||||
|
let path = default_layout_dir("disable-status-bar.yaml".into());
|
||||||
|
let layout_from_yaml = LayoutFromYaml::new(&path);
|
||||||
|
assert!(layout_from_yaml.is_ok());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn default_disable_status_layout_has_no_tab() {
|
||||||
|
let path = default_layout_dir("disable-status-bar.yaml".into());
|
||||||
|
let layout_from_yaml = LayoutFromYaml::new(&path);
|
||||||
|
let layout_template = layout_from_yaml.as_ref().unwrap();
|
||||||
|
assert_eq!(layout_template.tabs.len(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn three_panes_with_tab_is_ok() {
|
||||||
|
let path = layout_test_dir("three-panes-with-tab.yaml".into());
|
||||||
|
let layout = LayoutFromYaml::new(&path);
|
||||||
|
assert!(layout.is_ok());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn three_panes_with_tab_has_one_tab() {
|
||||||
|
let path = layout_test_dir("three-panes-with-tab.yaml".into());
|
||||||
|
let layout = LayoutFromYaml::new(&path);
|
||||||
|
let layout_template = layout.unwrap();
|
||||||
|
assert_eq!(layout_template.tabs.len(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn three_panes_with_tab_merged_correctly() {
|
||||||
|
let path = layout_test_dir("three-panes-with-tab.yaml".into());
|
||||||
|
let layout = LayoutFromYaml::new(&path);
|
||||||
|
let layout_template = layout.as_ref().unwrap();
|
||||||
|
let tab_layout = layout_template
|
||||||
|
.template
|
||||||
|
.clone()
|
||||||
|
.insert_tab_layout(Some(layout_template.tabs[0].clone()));
|
||||||
|
let merged_layout = Layout {
|
||||||
|
direction: Direction::Horizontal,
|
||||||
|
borderless: false,
|
||||||
|
parts: vec![Layout {
|
||||||
|
direction: Direction::Vertical,
|
||||||
|
borderless: false,
|
||||||
|
parts: vec![
|
||||||
|
Layout {
|
||||||
|
direction: Direction::Horizontal,
|
||||||
|
borderless: false,
|
||||||
|
parts: vec![],
|
||||||
|
split_size: Some(SplitSize::Percent(50)),
|
||||||
|
run: None,
|
||||||
|
},
|
||||||
|
Layout {
|
||||||
|
direction: Direction::Horizontal,
|
||||||
|
borderless: false,
|
||||||
|
parts: vec![
|
||||||
|
Layout {
|
||||||
|
direction: Direction::Vertical,
|
||||||
|
borderless: false,
|
||||||
|
parts: vec![],
|
||||||
|
split_size: Some(SplitSize::Percent(50)),
|
||||||
|
run: None,
|
||||||
|
},
|
||||||
|
Layout {
|
||||||
|
direction: Direction::Vertical,
|
||||||
|
borderless: false,
|
||||||
|
parts: vec![],
|
||||||
|
split_size: Some(SplitSize::Percent(50)),
|
||||||
|
run: None,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
split_size: None,
|
||||||
|
run: None,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
split_size: None,
|
||||||
|
run: None,
|
||||||
|
}],
|
||||||
|
split_size: None,
|
||||||
|
run: None,
|
||||||
|
};
|
||||||
|
assert_eq!(merged_layout, tab_layout.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn three_panes_with_tab_new_tab_is_correct() {
|
||||||
|
let path = layout_test_dir("three-panes-with-tab.yaml".into());
|
||||||
|
let layout = LayoutFromYaml::new(&path);
|
||||||
|
let layout_template = layout.as_ref().unwrap();
|
||||||
|
let tab_layout = layout_template.template.clone().insert_tab_layout(None);
|
||||||
|
let merged_layout = Layout {
|
||||||
|
direction: Direction::Horizontal,
|
||||||
|
borderless: false,
|
||||||
|
parts: vec![Layout {
|
||||||
|
direction: Direction::Horizontal,
|
||||||
|
borderless: false,
|
||||||
|
parts: vec![],
|
||||||
|
split_size: None,
|
||||||
|
run: None,
|
||||||
|
}],
|
||||||
|
split_size: None,
|
||||||
|
run: None,
|
||||||
|
};
|
||||||
|
assert_eq!(merged_layout, tab_layout.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn three_panes_with_tab_and_default_plugins_is_ok() {
|
||||||
|
let path = layout_test_dir("three-panes-with-tab-and-default-plugins.yaml".into());
|
||||||
|
let layout = LayoutFromYaml::new(&path);
|
||||||
|
assert!(layout.is_ok());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn three_panes_with_tab_and_default_plugins_has_one_tab() {
|
||||||
|
let path = layout_test_dir("three-panes-with-tab-and-default-plugins.yaml".into());
|
||||||
|
let layout = LayoutFromYaml::new(&path);
|
||||||
|
let layout_template = layout.unwrap();
|
||||||
|
assert_eq!(layout_template.tabs.len(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn three_panes_with_tab_and_default_plugins_merged_correctly() {
|
||||||
|
let path = layout_test_dir("three-panes-with-tab-and-default-plugins.yaml".into());
|
||||||
|
let layout = LayoutFromYaml::new(&path);
|
||||||
|
let layout_template = layout.as_ref().unwrap();
|
||||||
|
let tab_layout = layout_template
|
||||||
|
.template
|
||||||
|
.clone()
|
||||||
|
.insert_tab_layout(Some(layout_template.tabs[0].clone()));
|
||||||
|
let merged_layout = Layout {
|
||||||
|
direction: Direction::Horizontal,
|
||||||
|
borderless: false,
|
||||||
|
parts: vec![
|
||||||
|
Layout {
|
||||||
|
direction: Direction::Vertical,
|
||||||
|
borderless: false,
|
||||||
|
parts: vec![],
|
||||||
|
split_size: Some(SplitSize::Fixed(1)),
|
||||||
|
run: Some(Run::Plugin(Some("tab-bar".into()))),
|
||||||
|
},
|
||||||
|
Layout {
|
||||||
|
direction: Direction::Vertical,
|
||||||
|
borderless: false,
|
||||||
|
parts: vec![
|
||||||
|
Layout {
|
||||||
|
direction: Direction::Horizontal,
|
||||||
|
borderless: false,
|
||||||
|
parts: vec![],
|
||||||
|
split_size: Some(SplitSize::Percent(50)),
|
||||||
|
run: None,
|
||||||
|
},
|
||||||
|
Layout {
|
||||||
|
direction: Direction::Horizontal,
|
||||||
|
borderless: false,
|
||||||
|
parts: vec![
|
||||||
|
Layout {
|
||||||
|
direction: Direction::Vertical,
|
||||||
|
borderless: false,
|
||||||
|
parts: vec![],
|
||||||
|
split_size: Some(SplitSize::Percent(50)),
|
||||||
|
run: None,
|
||||||
|
},
|
||||||
|
Layout {
|
||||||
|
direction: Direction::Vertical,
|
||||||
|
borderless: false,
|
||||||
|
parts: vec![],
|
||||||
|
split_size: Some(SplitSize::Percent(50)),
|
||||||
|
run: None,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
split_size: None,
|
||||||
|
run: None,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
split_size: None,
|
||||||
|
run: None,
|
||||||
|
},
|
||||||
|
Layout {
|
||||||
|
direction: Direction::Vertical,
|
||||||
|
borderless: false,
|
||||||
|
parts: vec![],
|
||||||
|
split_size: Some(SplitSize::Fixed(2)),
|
||||||
|
run: Some(Run::Plugin(Some("status-bar".into()))),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
split_size: None,
|
||||||
|
run: None,
|
||||||
|
};
|
||||||
|
assert_eq!(merged_layout, tab_layout.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn three_panes_with_tab_and_default_plugins_new_tab_is_correct() {
|
||||||
|
let path = layout_test_dir("three-panes-with-tab-and-default-plugins.yaml".into());
|
||||||
|
let layout = LayoutFromYaml::new(&path);
|
||||||
|
let layout_template = layout.as_ref().unwrap();
|
||||||
|
let tab_layout = layout_template.template.clone().insert_tab_layout(None);
|
||||||
|
let merged_layout = Layout {
|
||||||
|
direction: Direction::Horizontal,
|
||||||
|
borderless: false,
|
||||||
|
parts: vec![
|
||||||
|
Layout {
|
||||||
|
direction: Direction::Vertical,
|
||||||
|
borderless: false,
|
||||||
|
parts: vec![],
|
||||||
|
split_size: Some(SplitSize::Fixed(1)),
|
||||||
|
run: Some(Run::Plugin(Some("tab-bar".into()))),
|
||||||
|
},
|
||||||
|
Layout {
|
||||||
|
direction: Direction::Horizontal,
|
||||||
|
borderless: false,
|
||||||
|
parts: vec![],
|
||||||
|
split_size: None,
|
||||||
|
run: None,
|
||||||
|
},
|
||||||
|
Layout {
|
||||||
|
direction: Direction::Vertical,
|
||||||
|
borderless: false,
|
||||||
|
parts: vec![],
|
||||||
|
split_size: Some(SplitSize::Fixed(2)),
|
||||||
|
run: Some(Run::Plugin(Some("status-bar".into()))),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
split_size: None,
|
||||||
|
run: None,
|
||||||
|
};
|
||||||
|
assert_eq!(merged_layout, tab_layout.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn deeply_nested_tab_is_ok() {
|
||||||
|
let path = layout_test_dir("deeply-nested-tab-layout.yaml".into());
|
||||||
|
let layout = LayoutFromYaml::new(&path);
|
||||||
|
assert!(layout.is_ok());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn deeply_nested_tab_has_one_tab() {
|
||||||
|
let path = layout_test_dir("deeply-nested-tab-layout.yaml".into());
|
||||||
|
let layout = LayoutFromYaml::new(&path);
|
||||||
|
let layout_template = layout.unwrap();
|
||||||
|
assert_eq!(layout_template.tabs.len(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn deeply_nested_tab_merged_correctly() {
|
||||||
|
let path = layout_test_dir("deeply-nested-tab-layout.yaml".into());
|
||||||
|
let layout = LayoutFromYaml::new(&path);
|
||||||
|
let layout_template = layout.as_ref().unwrap();
|
||||||
|
let tab_layout = layout_template
|
||||||
|
.template
|
||||||
|
.clone()
|
||||||
|
.insert_tab_layout(Some(layout_template.tabs[0].clone()));
|
||||||
|
let merged_layout = Layout {
|
||||||
|
direction: Direction::Horizontal,
|
||||||
|
borderless: false,
|
||||||
|
parts: vec![
|
||||||
|
Layout {
|
||||||
|
direction: Direction::Vertical,
|
||||||
|
borderless: false,
|
||||||
|
parts: vec![
|
||||||
|
Layout {
|
||||||
|
direction: Direction::Horizontal,
|
||||||
|
borderless: false,
|
||||||
|
parts: vec![],
|
||||||
|
split_size: Some(SplitSize::Percent(21)),
|
||||||
|
run: None,
|
||||||
|
},
|
||||||
|
Layout {
|
||||||
|
direction: Direction::Vertical,
|
||||||
|
borderless: false,
|
||||||
|
parts: vec![
|
||||||
|
Layout {
|
||||||
|
direction: Direction::Horizontal,
|
||||||
|
borderless: false,
|
||||||
|
parts: vec![],
|
||||||
|
split_size: Some(SplitSize::Percent(22)),
|
||||||
|
run: None,
|
||||||
|
},
|
||||||
|
Layout {
|
||||||
|
direction: Direction::Horizontal,
|
||||||
|
borderless: false,
|
||||||
|
parts: vec![
|
||||||
|
Layout {
|
||||||
|
direction: Direction::Horizontal,
|
||||||
|
borderless: false,
|
||||||
|
parts: vec![],
|
||||||
|
split_size: Some(SplitSize::Percent(23)),
|
||||||
|
run: None,
|
||||||
|
},
|
||||||
|
Layout {
|
||||||
|
direction: Direction::Horizontal,
|
||||||
|
borderless: false,
|
||||||
|
parts: vec![],
|
||||||
|
split_size: Some(SplitSize::Percent(24)),
|
||||||
|
run: None,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
split_size: Some(SplitSize::Percent(78)),
|
||||||
|
run: None,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
split_size: Some(SplitSize::Percent(79)),
|
||||||
|
run: None,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
split_size: Some(SplitSize::Percent(90)),
|
||||||
|
run: None,
|
||||||
|
},
|
||||||
|
Layout {
|
||||||
|
direction: Direction::Vertical,
|
||||||
|
borderless: false,
|
||||||
|
parts: vec![],
|
||||||
|
split_size: Some(SplitSize::Percent(15)),
|
||||||
|
run: None,
|
||||||
|
},
|
||||||
|
Layout {
|
||||||
|
direction: Direction::Vertical,
|
||||||
|
borderless: false,
|
||||||
|
parts: vec![],
|
||||||
|
split_size: Some(SplitSize::Percent(15)),
|
||||||
|
run: None,
|
||||||
|
},
|
||||||
|
Layout {
|
||||||
|
direction: Direction::Vertical,
|
||||||
|
borderless: false,
|
||||||
|
parts: vec![],
|
||||||
|
split_size: Some(SplitSize::Percent(15)),
|
||||||
|
run: None,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
split_size: None,
|
||||||
|
run: None,
|
||||||
|
};
|
||||||
|
assert_eq!(merged_layout, tab_layout.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn three_tabs_is_ok() {
|
||||||
|
let path = layout_test_dir("three-tabs-merged-correctly.yaml".into());
|
||||||
|
let layout_from_yaml = LayoutFromYaml::new(&path);
|
||||||
|
assert!(layout_from_yaml.is_ok());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn three_tabs_has_three_tabs() {
|
||||||
|
let path = layout_test_dir("three-tabs-merged-correctly.yaml".into());
|
||||||
|
let layout_from_yaml = LayoutFromYaml::new(&path);
|
||||||
|
let layout_template = layout_from_yaml.unwrap();
|
||||||
|
assert_eq!(layout_template.tabs.len(), 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn three_tabs_tab_one_merged_correctly() {
|
||||||
|
let path = layout_test_dir("three-tabs-merged-correctly.yaml".into());
|
||||||
|
let layout_from_yaml = LayoutFromYaml::new(&path);
|
||||||
|
let layout_template = layout_from_yaml.as_ref().unwrap();
|
||||||
|
let tab_layout = layout_template
|
||||||
|
.template
|
||||||
|
.clone()
|
||||||
|
.insert_tab_layout(Some(layout_template.tabs[0].clone()));
|
||||||
|
let merged_layout = Layout {
|
||||||
|
direction: Direction::Vertical,
|
||||||
|
borderless: false,
|
||||||
|
parts: vec![
|
||||||
|
Layout {
|
||||||
|
direction: Direction::Horizontal,
|
||||||
|
borderless: false,
|
||||||
|
parts: vec![],
|
||||||
|
split_size: Some(SplitSize::Percent(50)),
|
||||||
|
run: None,
|
||||||
|
},
|
||||||
|
Layout {
|
||||||
|
direction: Direction::Horizontal,
|
||||||
|
borderless: false,
|
||||||
|
parts: vec![],
|
||||||
|
split_size: None,
|
||||||
|
run: None,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
split_size: None,
|
||||||
|
run: None,
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(merged_layout, tab_layout.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn three_tabs_tab_two_merged_correctly() {
|
||||||
|
let path = layout_test_dir("three-tabs-merged-correctly.yaml".into());
|
||||||
|
let layout_from_yaml = LayoutFromYaml::new(&path);
|
||||||
|
let layout_template = layout_from_yaml.as_ref().unwrap();
|
||||||
|
let tab_layout = layout_template
|
||||||
|
.template
|
||||||
|
.clone()
|
||||||
|
.insert_tab_layout(Some(layout_template.tabs[1].clone()));
|
||||||
|
let merged_layout = Layout {
|
||||||
|
direction: Direction::Vertical,
|
||||||
|
borderless: false,
|
||||||
|
parts: vec![
|
||||||
|
Layout {
|
||||||
|
direction: Direction::Horizontal,
|
||||||
|
borderless: false,
|
||||||
|
parts: vec![
|
||||||
|
Layout {
|
||||||
|
direction: Direction::Horizontal,
|
||||||
|
borderless: false,
|
||||||
|
parts: vec![],
|
||||||
|
split_size: Some(SplitSize::Percent(50)),
|
||||||
|
run: None,
|
||||||
|
},
|
||||||
|
Layout {
|
||||||
|
direction: Direction::Horizontal,
|
||||||
|
borderless: false,
|
||||||
|
parts: vec![],
|
||||||
|
split_size: None,
|
||||||
|
run: None,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
split_size: Some(SplitSize::Percent(50)),
|
||||||
|
run: None,
|
||||||
|
},
|
||||||
|
Layout {
|
||||||
|
direction: Direction::Horizontal,
|
||||||
|
borderless: false,
|
||||||
|
parts: vec![],
|
||||||
|
split_size: None,
|
||||||
|
run: None,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
split_size: None,
|
||||||
|
run: None,
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(merged_layout, tab_layout.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn three_tabs_tab_three_merged_correctly() {
|
||||||
|
let path = layout_test_dir("three-tabs-merged-correctly.yaml".into());
|
||||||
|
let layout = LayoutFromYaml::new(&path);
|
||||||
|
let layout_template = layout.as_ref().unwrap();
|
||||||
|
let tab_layout = layout_template
|
||||||
|
.template
|
||||||
|
.clone()
|
||||||
|
.insert_tab_layout(Some(layout_template.tabs[2].clone()));
|
||||||
|
let merged_layout = Layout {
|
||||||
|
direction: Direction::Vertical,
|
||||||
|
borderless: false,
|
||||||
|
parts: vec![
|
||||||
|
Layout {
|
||||||
|
direction: Direction::Vertical,
|
||||||
|
borderless: false,
|
||||||
|
parts: vec![
|
||||||
|
Layout {
|
||||||
|
direction: Direction::Vertical,
|
||||||
|
borderless: false,
|
||||||
|
parts: vec![],
|
||||||
|
split_size: Some(SplitSize::Percent(50)),
|
||||||
|
run: None,
|
||||||
|
},
|
||||||
|
Layout {
|
||||||
|
direction: Direction::Horizontal,
|
||||||
|
borderless: false,
|
||||||
|
parts: vec![],
|
||||||
|
split_size: None,
|
||||||
|
run: None,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
split_size: Some(SplitSize::Percent(50)),
|
||||||
|
run: None,
|
||||||
|
},
|
||||||
|
Layout {
|
||||||
|
direction: Direction::Horizontal,
|
||||||
|
borderless: false,
|
||||||
|
parts: vec![],
|
||||||
|
split_size: None,
|
||||||
|
run: None,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
split_size: None,
|
||||||
|
run: None,
|
||||||
|
};
|
||||||
|
assert_eq!(merged_layout, tab_layout.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn no_tabs_is_ok() {
|
||||||
|
let path = layout_test_dir("no-tab-section-specified.yaml".into());
|
||||||
|
let layout_from_yaml = LayoutFromYaml::new(&path);
|
||||||
|
assert!(layout_from_yaml.is_ok());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn no_tabs_has_no_tabs() {
|
||||||
|
let path = layout_test_dir("no-tab-section-specified.yaml".into());
|
||||||
|
let layout_from_yaml = LayoutFromYaml::new(&path);
|
||||||
|
let layout_template = layout_from_yaml.unwrap();
|
||||||
|
assert_eq!(layout_template.tabs.len(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn no_tabs_merged_correctly() {
|
||||||
|
let path = layout_test_dir("no-tab-section-specified.yaml".into());
|
||||||
|
let layout_from_yaml = LayoutFromYaml::new(&path);
|
||||||
|
let layout_template = layout_from_yaml.as_ref().unwrap();
|
||||||
|
let tab_layout = layout_template.template.clone().insert_tab_layout(None);
|
||||||
|
let merged_layout = Layout {
|
||||||
|
direction: Direction::Horizontal,
|
||||||
|
borderless: false,
|
||||||
|
parts: vec![Layout {
|
||||||
|
direction: Direction::Horizontal,
|
||||||
|
borderless: false,
|
||||||
|
parts: vec![],
|
||||||
|
split_size: None,
|
||||||
|
run: None,
|
||||||
|
}],
|
||||||
|
split_size: None,
|
||||||
|
run: None,
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(merged_layout, tab_layout.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn no_layout_template_specified_is_ok() {
|
||||||
|
let path = layout_test_dir("no-layout-template-specified.yaml".into());
|
||||||
|
let layout_from_yaml = LayoutFromYaml::new(&path);
|
||||||
|
assert!(layout_from_yaml.is_ok());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn no_layout_template_has_one_tab() {
|
||||||
|
let path = layout_test_dir("no-layout-template-specified.yaml".into());
|
||||||
|
let layout_from_yaml = LayoutFromYaml::new(&path);
|
||||||
|
let layout_template = layout_from_yaml.unwrap();
|
||||||
|
assert_eq!(layout_template.tabs.len(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn no_layout_template_merged_correctly() {
|
||||||
|
let path = layout_test_dir("no-layout-template-specified.yaml".into());
|
||||||
|
let layout_from_yaml = LayoutFromYaml::new(&path);
|
||||||
|
let layout_template = layout_from_yaml.as_ref().unwrap();
|
||||||
|
let tab_layout = layout_template
|
||||||
|
.template
|
||||||
|
.clone()
|
||||||
|
.insert_tab_layout(Some(layout_template.tabs[0].clone()));
|
||||||
|
let merged_layout = Layout {
|
||||||
|
direction: Direction::Horizontal,
|
||||||
|
parts: vec![Layout {
|
||||||
|
direction: Direction::Vertical,
|
||||||
|
parts: vec![
|
||||||
|
Layout {
|
||||||
|
direction: Direction::Horizontal,
|
||||||
|
parts: vec![],
|
||||||
|
split_size: None,
|
||||||
|
run: None,
|
||||||
|
borderless: false,
|
||||||
|
},
|
||||||
|
Layout {
|
||||||
|
direction: Direction::Horizontal,
|
||||||
|
parts: vec![],
|
||||||
|
split_size: None,
|
||||||
|
run: None,
|
||||||
|
borderless: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
split_size: None,
|
||||||
|
run: None,
|
||||||
|
borderless: false,
|
||||||
|
}],
|
||||||
|
split_size: None,
|
||||||
|
run: None,
|
||||||
|
borderless: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(merged_layout, tab_layout.into());
|
||||||
|
}
|
@ -1,18 +1,20 @@
|
|||||||
//! IPC stuff for starting to split things into a client and server model.
|
//! IPC stuff for starting to split things into a client and server model.
|
||||||
|
|
||||||
use crate::cli::CliArgs;
|
|
||||||
use crate::pane_size::PositionAndSize;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
cli::CliArgs,
|
||||||
errors::{get_current_ctx, ErrorContext},
|
errors::{get_current_ctx, ErrorContext},
|
||||||
input::{actions::Action, layout::Layout, options::Options},
|
input::{actions::Action, layout::LayoutFromYaml, options::Options},
|
||||||
|
pane_size::PositionAndSize,
|
||||||
};
|
};
|
||||||
use interprocess::local_socket::LocalSocketStream;
|
use interprocess::local_socket::LocalSocketStream;
|
||||||
use nix::unistd::dup;
|
use nix::unistd::dup;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::fmt::{Display, Error, Formatter};
|
use std::{
|
||||||
use std::io::{self, Write};
|
fmt::{Display, Error, Formatter},
|
||||||
use std::marker::PhantomData;
|
io::{self, Write},
|
||||||
use std::os::unix::io::{AsRawFd, FromRawFd};
|
marker::PhantomData,
|
||||||
|
os::unix::io::{AsRawFd, FromRawFd},
|
||||||
|
};
|
||||||
|
|
||||||
use zellij_tile::data::Palette;
|
use zellij_tile::data::Palette;
|
||||||
|
|
||||||
@ -56,7 +58,12 @@ pub enum ClientToServerMsg {
|
|||||||
// Disconnect from the session we're connected to
|
// Disconnect from the session we're connected to
|
||||||
DisconnectFromSession,*/
|
DisconnectFromSession,*/
|
||||||
TerminalResize(PositionAndSize),
|
TerminalResize(PositionAndSize),
|
||||||
NewClient(ClientAttributes, Box<CliArgs>, Box<Options>, Option<Layout>),
|
NewClient(
|
||||||
|
ClientAttributes,
|
||||||
|
Box<CliArgs>,
|
||||||
|
Box<Options>,
|
||||||
|
Option<LayoutFromYaml>,
|
||||||
|
),
|
||||||
AttachClient(ClientAttributes, bool, Options),
|
AttachClient(ClientAttributes, bool, Options),
|
||||||
Action(Action),
|
Action(Action),
|
||||||
ClientExited,
|
ClientExited,
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
use crate::consts::{
|
|
||||||
FEATURES, SYSTEM_DEFAULT_CONFIG_DIR, SYSTEM_DEFAULT_DATA_DIR_PREFIX, VERSION, ZELLIJ_PROJ_DIR,
|
|
||||||
};
|
|
||||||
use crate::input::options::Options;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
cli::{CliArgs, Command},
|
cli::{CliArgs, Command},
|
||||||
|
consts::{
|
||||||
|
FEATURES, SYSTEM_DEFAULT_CONFIG_DIR, SYSTEM_DEFAULT_DATA_DIR_PREFIX, VERSION,
|
||||||
|
ZELLIJ_PROJ_DIR,
|
||||||
|
},
|
||||||
input::{
|
input::{
|
||||||
config::{Config, ConfigError},
|
config::{Config, ConfigError},
|
||||||
layout::Layout,
|
layout::LayoutFromYaml,
|
||||||
|
options::Options,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use directories_next::BaseDirs;
|
use directories_next::BaseDirs;
|
||||||
@ -150,7 +151,9 @@ impl Setup {
|
|||||||
/// file options:
|
/// file options:
|
||||||
/// 1. command line options (`zellij options`)
|
/// 1. command line options (`zellij options`)
|
||||||
/// 2. config options (`config.yaml`)
|
/// 2. config options (`config.yaml`)
|
||||||
pub fn from_options(opts: &CliArgs) -> Result<(Config, Option<Layout>, Options), ConfigError> {
|
pub fn from_options(
|
||||||
|
opts: &CliArgs,
|
||||||
|
) -> Result<(Config, Option<LayoutFromYaml>, Options), ConfigError> {
|
||||||
let clean = match &opts.command {
|
let clean = match &opts.command {
|
||||||
Some(Command::Setup(ref setup)) => setup.clean,
|
Some(Command::Setup(ref setup)) => setup.clean,
|
||||||
_ => false,
|
_ => false,
|
||||||
@ -160,7 +163,6 @@ impl Setup {
|
|||||||
match Config::try_from(opts) {
|
match Config::try_from(opts) {
|
||||||
Ok(config) => config,
|
Ok(config) => config,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
eprintln!("There was an error in the config file:");
|
|
||||||
return Err(e);
|
return Err(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -174,7 +176,7 @@ impl Setup {
|
|||||||
.layout_dir
|
.layout_dir
|
||||||
.clone()
|
.clone()
|
||||||
.or_else(|| get_layout_dir(opts.config_dir.clone().or_else(find_default_config_dir)));
|
.or_else(|| get_layout_dir(opts.config_dir.clone().or_else(find_default_config_dir)));
|
||||||
let layout_result = crate::input::layout::Layout::from_path_or_default(
|
let layout_result = LayoutFromYaml::from_path_or_default(
|
||||||
opts.layout.as_ref(),
|
opts.layout.as_ref(),
|
||||||
opts.layout_path.as_ref(),
|
opts.layout_path.as_ref(),
|
||||||
layout_dir,
|
layout_dir,
|
||||||
@ -183,10 +185,10 @@ impl Setup {
|
|||||||
None => None,
|
None => None,
|
||||||
Some(Ok(layout)) => Some(layout),
|
Some(Ok(layout)) => Some(layout),
|
||||||
Some(Err(e)) => {
|
Some(Err(e)) => {
|
||||||
eprintln!("There was an error in the layout file:");
|
|
||||||
return Err(e);
|
return Err(e);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
//.map(|layout| layout.template);
|
||||||
|
|
||||||
if let Some(Command::Setup(ref setup)) = &opts.command {
|
if let Some(Command::Setup(ref setup)) = &opts.command {
|
||||||
setup.from_cli(opts, &config_options).map_or_else(
|
setup.from_cli(opts, &config_options).map_or_else(
|
||||||
|
Loading…
Reference in New Issue
Block a user