aboutsummaryrefslogtreecommitdiffstats
path: root/src/common/screen.rs
diff options
context:
space:
mode:
authora-kenji <aks.kenji@protonmail.com>2021-05-10 20:54:39 +0200
committera-kenji <aks.kenji@protonmail.com>2021-05-10 20:54:39 +0200
commit85a4e476f2011dc0491a15bcce3b0052ebb15adb (patch)
treeeb5d120250c5c3b0d74314a42129a857bf6b1afe /src/common/screen.rs
parentfixup! Add Option for Simplified Layout (diff)
parentMerge pull request #480 from a-kenji/dump-config-exit (diff)
downloadsl0ppij-85a4e476f2011dc0491a15bcce3b0052ebb15adb.tar.gz
sl0ppij-85a4e476f2011dc0491a15bcce3b0052ebb15adb.tar.xz
sl0ppij-85a4e476f2011dc0491a15bcce3b0052ebb15adb.zip
fixup! Merge branch 'main' of https://github.com/zellij-org/zellij into simple-font-ui
Diffstat (limited to 'src/common/screen.rs')
-rw-r--r--src/common/screen.rs344
1 files changed, 301 insertions, 43 deletions
diff --git a/src/common/screen.rs b/src/common/screen.rs
index 62d87b51..82f63537 100644
--- a/src/common/screen.rs
+++ b/src/common/screen.rs
@@ -3,18 +3,20 @@
use std::collections::BTreeMap;
use std::os::unix::io::RawFd;
use std::str;
-use std::sync::mpsc::Receiver;
-use crate::common::SenderWithContext;
-use crate::os_input_output::ServerOsApi;
+use crate::common::pty::{PtyInstruction, VteBytes};
+use crate::common::thread_bus::Bus;
+use crate::common::input::options::Options;
+use crate::cli::ConfigCli;
+use crate::errors::{ContextType, ScreenContext};
+use crate::layout::Layout;
+use crate::panes::PaneId;
use crate::panes::PositionAndSize;
-use crate::pty_bus::{PtyInstruction, VteBytes};
use crate::server::ServerInstruction;
use crate::tab::Tab;
-use crate::{errors::ErrorContext, wasm_vm::PluginInstruction};
-use crate::{layout::Layout, panes::PaneId};
+use crate::wasm_vm::PluginInstruction;
-use zellij_tile::data::{Event, InputMode, ModeInfo, Palette, TabInfo};
+use zellij_tile::data::{Event, InputMode, ModeInfo, Palette, TabInfo, PluginCapabilities};
/// Instructions that can be sent to the [`Screen`].
#[derive(Debug, Clone)]
@@ -33,9 +35,11 @@ pub enum ScreenInstruction {
FocusNextPane,
FocusPreviousPane,
MoveFocusLeft,
+ MoveFocusLeftOrPreviousTab,
MoveFocusDown,
MoveFocusUp,
MoveFocusRight,
+ MoveFocusRightOrNextTab,
Exit,
ScrollUp,
ScrollDown,
@@ -63,55 +67,37 @@ pub enum ScreenInstruction {
/// A [`Screen`] holds multiple [`Tab`]s, each one holding multiple [`panes`](crate::client::panes).
/// It only directly controls which tab is active, delegating the rest to the individual `Tab`.
pub struct Screen {
- /// A [`ScreenInstruction`] and [`ErrorContext`] receiver.
- pub receiver: Receiver<(ScreenInstruction, ErrorContext)>,
+ /// A Bus for sending and receiving messages with the other threads.
+ pub bus: Bus<ScreenInstruction>,
/// An optional maximal amount of panes allowed per [`Tab`] in this [`Screen`] instance.
max_panes: Option<usize>,
/// A map between this [`Screen`]'s tabs and their ID/key.
tabs: BTreeMap<usize, Tab>,
- /// A [`PluginInstruction`] and [`ErrorContext`] sender.
- pub send_plugin_instructions: SenderWithContext<PluginInstruction>,
- /// An [`PtyInstruction`] and [`ErrorContext`] sender.
- pub send_pty_instructions: SenderWithContext<PtyInstruction>,
- /// An [`ServerInstruction`] and [`ErrorContext`] sender.
- pub send_server_instructions: SenderWithContext<ServerInstruction>,
/// The full size of this [`Screen`].
full_screen_ws: PositionAndSize,
/// The index of this [`Screen`]'s active [`Tab`].
active_tab_index: Option<usize>,
- /// The [`ServerOsApi`] this [`Screen`] uses.
- os_api: Box<dyn ServerOsApi>,
mode_info: ModeInfo,
input_mode: InputMode,
colors: Palette,
}
impl Screen {
- // FIXME: This lint needs actual fixing! Maybe by bundling the Senders
/// Creates and returns a new [`Screen`].
- #[allow(clippy::too_many_arguments)]
pub fn new(
- receive_screen_instructions: Receiver<(ScreenInstruction, ErrorContext)>,
- send_plugin_instructions: SenderWithContext<PluginInstruction>,
- send_pty_instructions: SenderWithContext<PtyInstruction>,
- send_server_instructions: SenderWithContext<ServerInstruction>,
+ bus: Bus<ScreenInstruction>,
full_screen_ws: &PositionAndSize,
- os_api: Box<dyn ServerOsApi>,
max_panes: Option<usize>,
mode_info: ModeInfo,
input_mode: InputMode,
colors: Palette,
) -> Self {
Screen {
- receiver: receive_screen_instructions,
+ bus,
max_panes,
- send_plugin_instructions,
- send_pty_instructions,
- send_server_instructions,
full_screen_ws: *full_screen_ws,
active_tab_index: None,
tabs: BTreeMap::new(),
- os_api,
mode_info,
input_mode,
colors,
@@ -128,10 +114,8 @@ impl Screen {
position,
String::new(),
&self.full_screen_ws,
- self.os_api.clone(),
- self.send_plugin_instructions.clone(),
- self.send_pty_instructions.clone(),
- self.send_server_instructions.clone(),
+ self.bus.os_input.as_ref().unwrap().clone(),
+ self.bus.senders.clone(),
self.max_panes,
Some(PaneId::Terminal(pane_id)),
self.mode_info.clone(),
@@ -215,13 +199,15 @@ impl Screen {
// below we don't check the result of sending the CloseTab instruction to the pty thread
// because this might be happening when the app is closing, at which point the pty thread
// has already closed and this would result in an error
- self.send_pty_instructions
- .send(PtyInstruction::CloseTab(pane_ids))
+ self.bus
+ .senders
+ .send_to_pty(PtyInstruction::CloseTab(pane_ids))
.unwrap();
if self.tabs.is_empty() {
self.active_tab_index = None;
- self.send_server_instructions
- .send(ServerInstruction::Render(None))
+ self.bus
+ .senders
+ .send_to_server(ServerInstruction::Render(None))
.unwrap();
} else {
for t in self.tabs.values_mut() {
@@ -284,10 +270,8 @@ impl Screen {
position,
String::new(),
&self.full_screen_ws,
- self.os_api.clone(),
- self.send_plugin_instructions.clone(),
- self.send_pty_instructions.clone(),
- self.send_server_instructions.clone(),
+ self.bus.os_input.as_ref().unwrap().clone(),
+ self.bus.senders.clone(),
self.max_panes,
None,
self.mode_info.clone(),
@@ -311,8 +295,9 @@ impl Screen {
is_sync_panes_active: tab.is_sync_panes_active(),
});
}
- self.send_plugin_instructions
- .send(PluginInstruction::Update(None, Event::TabUpdate(tab_data)))
+ self.bus
+ .senders
+ .send_to_plugin(PluginInstruction::Update(None, Event::TabUpdate(tab_data)))
.unwrap();
}
@@ -340,3 +325,276 @@ impl Screen {
}
}
}
+
+pub fn screen_thread_main(
+ bus: Bus<ScreenInstruction>,
+ max_panes: Option<usize>,
+ full_screen_ws: PositionAndSize,
+ options: Option<ConfigCli>,
+ config_options: Options,
+) {
+ let colors = bus.os_input.as_ref().unwrap().load_palette();
+ let capabilities = if let Some(ConfigCli::Options(options)) = options {
+ options.simplified_ui
+ } else {
+ config_options.simplified_ui
+ };
+ let mut screen = Screen::new(
+ bus,
+ &full_screen_ws,
+ max_panes,
+ ModeInfo {
+ palette: colors,
+ capabilities: PluginCapabilities {
+ arrow_fonts: capabilities,
+ },
+ ..ModeInfo::default()
+ },
+ InputMode::Normal,
+ colors,
+ );
+ loop {
+ let (event, mut err_ctx) = screen
+ .bus
+ .recv()
+ .expect("failed to receive event on channel");
+ err_ctx.add_call(ContextType::Screen(ScreenContext::from(&event)));
+ match event {
+ ScreenInstruction::PtyBytes(pid, vte_bytes) => {
+ let active_tab = screen.get_active_tab_mut().unwrap();
+ if active_tab.has_terminal_pid(pid) {
+ // it's most likely that this event is directed at the active tab
+ // look there first
+ active_tab.handle_pty_bytes(pid, vte_bytes);
+ } else {
+ // if this event wasn't directed at the active tab, start looking
+ // in other tabs
+ let all_tabs = screen.get_tabs_mut();
+ for tab in all_tabs.values_mut() {
+ if tab.has_terminal_pid(pid) {
+ tab.handle_pty_bytes(pid, vte_bytes);
+ break;
+ }
+ }
+ }
+ }
+ ScreenInstruction::Render => {
+ screen.render();
+ }
+ ScreenInstruction::NewPane(pid) => {
+ screen.get_active_tab_mut().unwrap().new_pane(pid);
+ screen
+ .bus
+ .senders
+ .send_to_server(ServerInstruction::UnblockInputThread)
+ .unwrap();
+ }
+ ScreenInstruction::HorizontalSplit(pid) => {
+ screen.get_active_tab_mut().unwrap().horizontal_split(pid);
+ screen
+ .bus
+ .senders
+ .send_to_server(ServerInstruction::UnblockInputThread)
+ .unwrap();
+ }
+ ScreenInstruction::VerticalSplit(pid) => {
+ screen.get_active_tab_mut().unwrap().vertical_split(pid);
+ screen
+ .bus
+ .senders
+ .send_to_server(ServerInstruction::UnblockInputThread)
+ .unwrap();
+ }
+ ScreenInstruction::WriteCharacter(bytes) => {
+ let active_tab = screen.get_active_tab_mut().unwrap();
+ match active_tab.is_sync_panes_active() {
+ true => active_tab.write_to_terminals_on_current_tab(bytes),
+ false => active_tab.write_to_active_terminal(bytes),
+ }
+ }
+ ScreenInstruction::ResizeLeft => {
+ screen.get_active_tab_mut().unwrap().resize_left();
+ }
+ ScreenInstruction::ResizeRight => {
+ screen.get_active_tab_mut().unwrap().resize_right();
+ }
+ ScreenInstruction::ResizeDown => {
+ screen.get_active_tab_mut().unwrap().resize_down();
+ }
+ ScreenInstruction::ResizeUp => {
+ screen.get_active_tab_mut().unwrap().resize_up();
+ }
+ ScreenInstruction::SwitchFocus => {
+ screen.get_active_tab_mut().unwrap().move_focus();
+ }
+ ScreenInstruction::FocusNextPane => {
+ screen.get_active_tab_mut().unwrap().focus_next_pane();
+ }
+ ScreenInstruction::FocusPreviousPane => {
+ screen.get_active_tab_mut().unwrap().focus_previous_pane();
+ }
+ ScreenInstruction::MoveFocusLeft => {
+ screen.get_active_tab_mut().unwrap().move_focus_left();
+ }
+ ScreenInstruction::MoveFocusLeftOrPreviousTab => {
+ if !screen.get_active_tab_mut().unwrap().move_focus_left() {
+ screen.switch_tab_prev();
+ }
+ screen
+ .bus
+ .senders
+ .send_to_server(ServerInstruction::UnblockInputThread)
+ .unwrap();
+ }
+ ScreenInstruction::MoveFocusDown => {
+ screen.get_active_tab_mut().unwrap().move_focus_down();
+ }
+ ScreenInstruction::MoveFocusRight => {
+ screen.get_active_tab_mut().unwrap().move_focus_right();
+ }
+ ScreenInstruction::MoveFocusRightOrNextTab => {
+ if !screen.get_active_tab_mut().unwrap().move_focus_right() {
+ screen.switch_tab_next();
+ }
+ screen
+ .bus
+ .senders
+ .send_to_server(ServerInstruction::UnblockInputThread)
+ .unwrap();
+ }
+ ScreenInstruction::MoveFocusUp => {
+ screen.get_active_tab_mut().unwrap().move_focus_up();
+ }
+ ScreenInstruction::ScrollUp => {
+ screen
+ .get_active_tab_mut()
+ .unwrap()
+ .scroll_active_terminal_up();
+ }
+ ScreenInstruction::ScrollDown => {
+ screen
+ .get_active_tab_mut()
+ .unwrap()
+ .scroll_active_terminal_down();
+ }
+ ScreenInstruction::PageScrollUp => {
+ screen
+ .get_active_tab_mut()
+ .unwrap()
+ .scroll_active_terminal_up_page();
+ }
+ ScreenInstruction::PageScrollDown => {
+ screen
+ .get_active_tab_mut()
+ .unwrap()
+ .scroll_active_terminal_down_page();
+ }
+ ScreenInstruction::ClearScroll => {
+ screen
+ .get_active_tab_mut()
+ .unwrap()
+ .clear_active_terminal_scroll();
+ }
+ ScreenInstruction::CloseFocusedPane => {
+ screen.get_active_tab_mut().unwrap().close_focused_pane();
+ screen.render();
+ }
+ ScreenInstruction::SetSelectable(id, selectable) => {
+ screen
+ .get_active_tab_mut()
+ .unwrap()
+ .set_pane_selectable(id, selectable);
+ }
+ ScreenInstruction::SetMaxHeight(id, max_height) => {
+ screen
+ .get_active_tab_mut()
+ .unwrap()
+ .set_pane_max_height(id, max_height);
+ }
+ ScreenInstruction::SetInvisibleBorders(id, invisible_borders) => {
+ screen
+ .get_active_tab_mut()
+ .unwrap()
+ .set_pane_invisible_borders(id, invisible_borders);
+ screen.render();
+ }
+ ScreenInstruction::ClosePane(id) => {
+ screen.get_active_tab_mut().unwrap().close_pane(id);
+ screen.render();
+ }
+ ScreenInstruction::ToggleActiveTerminalFullscreen => {
+ screen
+ .get_active_tab_mut()
+ .unwrap()
+ .toggle_active_pane_fullscreen();
+ }
+ ScreenInstruction::NewTab(pane_id) => {
+ screen.new_tab(pane_id);
+ screen
+ .bus
+ .senders
+ .send_to_server(ServerInstruction::UnblockInputThread)
+ .unwrap();
+ }
+ ScreenInstruction::SwitchTabNext => {
+ screen.switch_tab_next();
+ screen
+ .bus
+ .senders
+ .send_to_server(ServerInstruction::UnblockInputThread)
+ .unwrap();
+ }
+ ScreenInstruction::SwitchTabPrev => {
+ screen.switch_tab_prev();
+ screen
+ .bus
+ .senders
+ .send_to_server(ServerInstruction::UnblockInputThread)
+ .unwrap();
+ }
+ ScreenInstruction::CloseTab => {
+ screen.close_tab();
+ screen
+ .bus
+ .senders
+ .send_to_server(ServerInstruction::UnblockInputThread)
+ .unwrap();
+ }
+ ScreenInstruction::ApplyLayout(layout, new_pane_pids) => {
+ screen.apply_layout(layout, new_pane_pids);
+ screen
+ .bus
+ .senders
+ .send_to_server(ServerInstruction::UnblockInputThread)
+ .unwrap();
+ }
+ ScreenInstruction::GoToTab(tab_index) => {
+ screen.go_to_tab(tab_index as usize);
+ screen
+ .bus
+ .senders
+ .send_to_server(ServerInstruction::UnblockInputThread)
+ .unwrap();
+ }
+ ScreenInstruction::UpdateTabName(c) => {
+ screen.update_active_tab_name(c);
+ }
+ ScreenInstruction::TerminalResize(new_size) => {
+ screen.resize_to_screen(new_size);
+ }
+ ScreenInstruction::ChangeMode(mode_info) => {
+ screen.change_mode(mode_info);
+ }
+ ScreenInstruction::ToggleActiveSyncTab => {
+ screen
+ .get_active_tab_mut()
+ .unwrap()
+ .toggle_sync_panes_is_active();
+ screen.update_tabs();
+ }
+ ScreenInstruction::Exit => {
+ break;
+ }
+ }
+ }
+}