diff options
author | Aram Drevekenin <aram@poor.dev> | 2021-08-24 10:58:36 +0200 |
---|---|---|
committer | Aram Drevekenin <aram@poor.dev> | 2021-08-24 10:58:36 +0200 |
commit | 618c2c376bb4edca8693ea4b871279bc04501559 (patch) | |
tree | b4d4426b353955e8af1ed8ad6531f95860eda5f6 | |
parent | 7a2f86db1b34b027ca03be73ec7bc4681f33fbdf (diff) | |
parent | 88b4063879845cf53397f60201473ce386280cfe (diff) |
Merge branch 'tab-layout' of https://github.com/a-kenji/zellij into a-kenji-tab-layout
28 files changed, 1572 insertions, 128 deletions
diff --git a/example/multiple_tabs_layout.yaml b/example/multiple_tabs_layout.yaml new file mode 100644 index 000000000..6c4d15980 --- /dev/null +++ b/example/multiple_tabs_layout.yaml @@ -0,0 +1,82 @@ +--- +direction: Horizontal +parts: + - direction: Vertical + split_size: + Fixed: 1 + run: + plugin: tab-bar + - direction: Vertical + 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 + - direction: Vertical + split_size: + Fixed: 2 + run: + plugin: status-bar diff --git a/example/multiple_tabs_layout_htop_command.yaml b/example/multiple_tabs_layout_htop_command.yaml new file mode 100644 index 000000000..6739eba8f --- /dev/null +++ b/example/multiple_tabs_layout_htop_command.yaml @@ -0,0 +1,85 @@ +--- +direction: Horizontal +parts: + - direction: Vertical + split_size: + Fixed: 1 + run: + plugin: tab-bar + - direction: Vertical + 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 + - direction: Vertical + split_size: + Fixed: 2 + run: + plugin: status-bar diff --git a/src/main.rs b/src/main.rs index 1a3a16ed6..f0d00f77a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -24,14 +24,6 @@ pub fn main() { 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_LOG_DIR).unwrap(); if let Some(path) = opts.server { @@ -62,6 +54,14 @@ pub fn main() { 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( Box::new(os_input), opts, @@ -70,6 +70,14 @@ pub fn main() { None, ); } else { + let (config, layout, _) = match Setup::from_options(&opts) { + Ok(results) => results, + Err(e) => { + eprintln!("{}", e); + process::exit(1); + } + }; + let session_name = opts .session .clone() diff --git a/src/tests/fixtures/layouts/parts-total-less-than-100-percent.yaml b/src/tests/fixtures/layouts/parts-total-less-than-100-percent.yaml index e1a1a6071..f0f66a323 100644 --- a/src/tests/fixtures/layouts/parts-total-less-than-100-percent.yaml +++ b/src/tests/fixtures/layouts/parts-total-less-than-100-percent.yaml @@ -9,6 +9,8 @@ - direction: Horizontal split_size: Percent: 50 + tabs: + - direction: Horizontal split_size: Percent: 80 - direction: Vertical diff --git a/src/tests/fixtures/layouts/parts-total-more-than-100-percent.yaml b/src/tests/fixtures/layouts/parts-total-more-than-100-percent.yaml index 33d942253..2b55547d4 100644 --- a/src/tests/fixtures/layouts/parts-total-more-than-100-percent.yaml +++ b/src/tests/fixtures/layouts/parts-total-more-than-100-percent.yaml @@ -9,6 +9,9 @@ - direction: Horizontal split_size: Percent: 90 + - direction: Horizontal + tabs: + - direction: Horizontal split_size: Percent: 80 - direction: Vertical diff --git a/src/tests/fixtures/layouts/three-panes-with-nesting.yaml b/src/tests/fixtures/layouts/three-panes-with-nesting.yaml index f1e0dd7e5..20a647f3d 100644 --- a/src/tests/fixtures/layouts/three-panes-with-nesting.yaml +++ b/src/tests/fixtures/layouts/three-panes-with-nesting.yaml @@ -1,16 +1,18 @@ --- direction: Horizontal -parts: - - direction: Vertical +tabs: + - direction: Horizontal parts: - - direction: Horizontal - split_size: - Percent: 20 - - direction: Horizontal + - direction: Vertical + parts: + - direction: Horizontal + split_size: + Percent: 20 + - direction: Horizontal + split_size: + Percent: 80 split_size: Percent: 80 - split_size: - Percent: 80 - - direction: Vertical - split_size: - Percent: 20 + - direction: Vertical + split_size: + Percent: 20 diff --git a/zellij-client/src/input_handler.rs b/zellij-client/src/input_handler.rs index 03d223b2e..217b10f97 100644 --- a/zellij-client/src/input_handler.rs +++ b/zellij-client/src/input_handler.rs @@ -185,7 +185,7 @@ impl InputHandler { } Action::CloseFocus | Action::NewPane(_) - | Action::NewTab + | Action::NewTab(_) | Action::GoToNextTab | Action::GoToPreviousTab | Action::CloseTab diff --git a/zellij-client/src/lib.rs b/zellij-client/src/lib.rs index 5c832e860..f74a74ddf 100644 --- a/zellij-client/src/lib.rs +++ b/zellij-client/src/lib.rs @@ -19,7 +19,7 @@ use zellij_utils::{ channels::{self, ChannelWithContext, SenderWithContext}, consts::{SESSION_NAME, ZELLIJ_IPC_PIPE}, errors::{ClientContext, ContextType, ErrorInstruction}, - input::{actions::Action, config::Config, layout::Layout, options::Options}, + input::{actions::Action, config::Config, layout::LayoutTemplate, options::Options}, ipc::{ClientAttributes, ClientToServerMsg, ExitReason, ServerToClientMsg}, }; @@ -87,7 +87,7 @@ pub fn start_client( opts: CliArgs, config: Config, info: ClientInfo, - layout: Option<Layout>, + layout: Option<LayoutTemplate>, ) { 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"; diff --git a/zellij-server/src/lib.rs b/zellij-server/src/lib.rs index 690304bb5..d0b3b5d27 100644 --- a/zellij-server/src/lib.rs +++ b/zellij-server/src/lib.rs @@ -11,11 +11,13 @@ mod ui; mod wasm_vm; use log::info; +use std::{ + path::PathBuf, + sync::{Arc, Mutex, RwLock}, + thread, +}; use zellij_utils::zellij_tile; -use std::path::PathBuf; -use std::sync::{Arc, Mutex, RwLock}; -use std::thread; use wasmer::Store; use zellij_tile::data::{Event, Palette, PluginCapabilities}; @@ -34,7 +36,7 @@ use zellij_utils::{ input::{ command::{RunCommand, TerminalAction}, get_mode_info, - layout::Layout, + layout::LayoutTemplate, options::Options, }, ipc::{ClientAttributes, ClientToServerMsg, ExitReason, ServerToClientMsg}, @@ -44,7 +46,12 @@ use zellij_utils::{ /// Instructions related to server-side application #[derive(Debug, Clone)] pub(crate) enum ServerInstruction { - NewClient(ClientAttributes, Box<CliArgs>, Box<Options>, Option<Layout>), + NewClient( + ClientAttributes, + Box<CliArgs>, + Box<Options>, + Option<LayoutTemplate>, + ), Render(Option<String>), UnblockInputThread, ClientExit, @@ -207,7 +214,7 @@ pub fn start_server(os_input: Box<dyn ServerOsApi>, socket_path: PathBuf) { to_server.clone(), client_attributes, session_state.clone(), - layout, + layout.clone(), ); *session_data.write().unwrap() = Some(session); *session_state.write().unwrap() = SessionState::Attached; @@ -219,14 +226,34 @@ pub fn start_server(os_input: Box<dyn ServerOsApi>, socket_path: PathBuf) { }) }); - session_data - .read() - .unwrap() - .as_ref() - .unwrap() - .senders - .send_to_pty(PtyInstruction::NewTab(default_shell.clone())) - .unwrap(); + let spawn_tabs = |tab_layout| { + session_data + .read() + .unwrap() + .as_ref() + .unwrap() + .senders + .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())); + // Spawning tabs in too quick succession might mess up the layout + // TODO: investigate why + thread::sleep(std::time::Duration::from_millis(250)); + } + } else { + spawn_tabs(None); + } + } + } } ServerInstruction::AttachClient(attrs, _, options) => { *session_state.write().unwrap() = SessionState::Attached; @@ -302,7 +329,7 @@ fn init_session( to_server: SenderWithContext<ServerInstruction>, client_attributes: ClientAttributes, session_state: Arc<RwLock<SessionState>>, - layout: Option<Layout>, + layout: Option<LayoutTemplate>, ) -> SessionMetaData { let (to_screen, screen_receiver): ChannelWithContext<ScreenInstruction> = channels::unbounded(); let to_screen = SenderWithContext::new(to_screen); diff --git a/zellij-server/src/pty.rs b/zellij-server/src/pty.rs index 5ef3b3217..5c0e4a269 100644 --- a/zellij-server/src/pty.rs +++ b/zellij-server/src/pty.rs @@ -20,7 +20,7 @@ use zellij_utils::{ errors::{get_current_ctx, ContextType, PtyContext}, input::{ command::TerminalAction, - layout::{Layout, Run}, + layout::{Layout, LayoutTemplate, Run, TabLayout}, }, logging::debug_to_file, }; @@ -33,7 +33,7 @@ pub(crate) enum PtyInstruction { SpawnTerminal(Option<TerminalAction>), SpawnTerminalVertically(Option<TerminalAction>), SpawnTerminalHorizontally(Option<TerminalAction>), - NewTab(Option<TerminalAction>), + NewTab(Option<TerminalAction>, Option<TabLayout>), ClosePane(PaneId), CloseTab(Vec<PaneId>), Exit, @@ -47,7 +47,7 @@ impl From<&PtyInstruction> for PtyContext { PtyInstruction::SpawnTerminalHorizontally(_) => PtyContext::SpawnTerminalHorizontally, PtyInstruction::ClosePane(_) => PtyContext::ClosePane, PtyInstruction::CloseTab(_) => PtyContext::CloseTab, - PtyInstruction::NewTab(_) => PtyContext::NewTab, + PtyInstruction::NewTab(..) => PtyContext::NewTab, PtyInstruction::Exit => PtyContext::Exit, } } @@ -60,7 +60,7 @@ pub(crate) struct Pty { 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<LayoutTemplate>) { loop { let (event, mut err_ctx) = pty.bus.recv().expect("failed to receive event on channel"); 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))) .unwrap(); } - PtyInstruction::NewTab(terminal_action) => { + PtyInstruction::NewTab(terminal_action, tab_layout) => { if let Some(layout) = maybe_layout.clone() { - pty.spawn_terminals_for_layout(layout, terminal_action); + let merged_layout = layout.construct_tab_layout(tab_layout); + pty.spawn_terminals_for_layout(merged_layout, terminal_action.clone()); } else { - let pid = pty.spawn_terminal(terminal_action); + let pid = pty.spawn_terminal(terminal_action.clone()); pty.bus .senders .send_to_screen(ScreenInstruction::NewTab(pid)) diff --git a/zellij-server/src/route.rs b/zellij-server/src/route.rs index 54ddfe1b1..a88d04b09 100644 --- a/zellij-server/src/route.rs +++ b/zellij-server/src/route.rs @@ -197,11 +197,11 @@ fn route_action( .send_to_screen(ScreenInstruction::CloseFocusedPane) .unwrap(); } - Action::NewTab => { + Action::NewTab(tab_layout) => { let shell = session.default_shell.clone(); session .senders - .send_to_pty(PtyInstruction::NewTab(shell)) + .send_to_pty(PtyInstruction::NewTab(shell, tab_layout)) .unwrap(); } Action::GoToNextTab => { diff --git a/zellij-utils/assets/config/default.yaml b/zellij-utils/assets/config/default.yaml index 94f12f33c..42f2287b7 100644 --- a/zellij-utils/assets/config/default.yaml +++ b/zellij-utils/assets/config/default.yaml @@ -136,7 +136,7 @@ keybinds: key: [ Char: 'h', Left, Up, Char: 'k',] - action: [GoToNextTab,] key: [ Char: 'l', Right,Down, Char: 'j'] - - action: [NewTab,] + - action: [NewTab: ,] key: [ Char: 'n',] - action: [CloseTab,] key: [ Char: 'x',] diff --git a/zellij-utils/assets/layouts/default.yaml b/zellij-utils/assets/layouts/default.yaml index b163821de..e0a28da12 100644 --- a/zellij-utils/assets/layouts/default.yaml +++ b/ |